Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB backend for the Common UNIX Printing System ("CUPS")
4 :
5 : Copyright (C) Michael R Sweet 1999
6 : Copyright (C) Andrew Tridgell 1994-1998
7 : Copyright (C) Andrew Bartlett 2002
8 : Copyright (C) Rodrigo Fernandez-Vizarra 2005
9 : Copyright (C) James Peach 2008
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "includes.h"
26 : #include "system/filesys.h"
27 : #include "system/passwd.h"
28 : #include "system/kerberos.h"
29 : #include "libsmb/libsmb.h"
30 : #include "lib/param/param.h"
31 : #include "lib/krb5_wrap/krb5_samba.h"
32 :
33 : /*
34 : * Starting with CUPS 1.3, Kerberos support is provided by cupsd including
35 : * the forwarding of user credentials via the authenticated session between
36 : * user and server and the KRB5CCNAME environment variable which will point
37 : * to a temporary file or an in-memory representation depending on the version
38 : * of Kerberos you use. As a result, all of the ticket code that used to
39 : * live here has been removed, and we depend on the user session (if you
40 : * run smbspool by hand) or cupsd to provide the necessary Kerberos info.
41 : *
42 : * Also, the AUTH_USERNAME and AUTH_PASSWORD environment variables provide
43 : * for per-job authentication for non-Kerberized printing. We use those
44 : * if there is no username and password specified in the device URI.
45 : *
46 : * Finally, if we have an authentication failure we return exit code 2
47 : * which tells CUPS to hold the job for authentication and bug the user
48 : * to get the necessary credentials.
49 : */
50 :
51 : #define MAX_RETRY_CONNECT 3
52 :
53 :
54 : /*
55 : * Globals...
56 : */
57 :
58 :
59 :
60 : /*
61 : * Local functions...
62 : */
63 :
64 : static int get_exit_code(NTSTATUS nt_status);
65 : static void list_devices(void);
66 : static NTSTATUS
67 : smb_connect(struct cli_state **output_cli,
68 : const char *workgroup,
69 : const char *server,
70 : const int port,
71 : const char *share,
72 : const char *username,
73 : const char *password,
74 : const char *jobusername);
75 : static int smb_print(struct cli_state *, const char *, FILE *);
76 : static char *uri_unescape_alloc(const char *);
77 : #if 0
78 : static bool smb_encrypt;
79 : #endif
80 :
81 : static const char *auth_info_required;
82 :
83 : /*
84 : * 'main()' - Main entry for SMB backend.
85 : */
86 :
87 : int /* O - Exit status */
88 22 : main(int argc, /* I - Number of command-line arguments */
89 : char *argv[])
90 : { /* I - Command-line arguments */
91 : int i; /* Looping var */
92 : int copies; /* Number of copies */
93 : int port; /* Port number */
94 : char uri[1024], /* URI */
95 : *sep, /* Pointer to separator */
96 : *tmp, *tmp2; /* Temp pointers to do escaping */
97 22 : const char *password = NULL; /* Password */
98 22 : const char *username = NULL; /* Username */
99 : char *server, /* Server name */
100 : *printer;/* Printer name */
101 : const char *workgroup; /* Workgroup */
102 : FILE *fp; /* File to print */
103 22 : int status = 1; /* Status of LPD job */
104 22 : NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
105 22 : struct cli_state *cli = NULL; /* SMB interface */
106 22 : int tries = 0;
107 22 : const char *dev_uri = NULL;
108 22 : const char *env = NULL;
109 22 : const char *config_file = NULL;
110 22 : TALLOC_CTX *frame = talloc_stackframe();
111 22 : const char *print_user = NULL;
112 22 : const char *print_title = NULL;
113 22 : const char *print_file = NULL;
114 22 : const char *print_copies = NULL;
115 : int cmp;
116 : int len;
117 :
118 22 : if (argc == 1) {
119 : /*
120 : * NEW! In CUPS 1.1 the backends are run with no arguments
121 : * to list the available devices. These can be devices
122 : * served by this backend or any other backends (i.e. you
123 : * can have an SNMP backend that is only used to enumerate
124 : * the available network printers... :)
125 : */
126 :
127 4 : list_devices();
128 4 : status = 0;
129 4 : goto done;
130 : }
131 :
132 : /*
133 : * We need at least 5 options if the DEVICE_URI is passed via an env
134 : * variable and printing data comes via stdin.
135 : * We don't accept more than 7 options in total, including optional.
136 : */
137 18 : if (argc < 5 || argc > 8) {
138 0 : fprintf(stderr,
139 : "Usage: %s [DEVICE_URI] job-id user title copies options [file]\n"
140 : " The DEVICE_URI environment variable can also contain the\n"
141 : " destination printer:\n"
142 : "\n"
143 : " smb://[username:password@][workgroup/]server[:port]/printer\n",
144 : argv[0]);
145 0 : goto done;
146 : }
147 :
148 : /*
149 : * Find out if we have the device_uri in the command line.
150 : *
151 : * If we are started as a CUPS backend argv[0] is normally the
152 : * device_uri!
153 : */
154 18 : if (argc == 8) {
155 : /*
156 : * smbspool <uri> <job> <user> <title> <copies> <options> <file>
157 : * 0 1 2 3 4 5 6 7
158 : */
159 :
160 8 : dev_uri = argv[1];
161 :
162 8 : print_user = argv[3];
163 8 : print_title = argv[4];
164 8 : print_copies = argv[5];
165 8 : print_file = argv[7];
166 10 : } else if (argc == 7) {
167 : int cmp1;
168 : int cmp2;
169 :
170 : /*
171 : * <uri> <job> <user> <title> <copies> <options> <file>
172 : * smbspool <uri> <job> <user> <title> <copies> <options>
173 : * smbspool <job> <user> <title> <copies> <options> <file> | DEVICE_URI
174 : */
175 6 : cmp1 = strncmp(argv[0], "smb://", 6);
176 6 : cmp2 = strncmp(argv[1], "smb://", 6);
177 :
178 6 : if (cmp1 == 0) {
179 : /*
180 : * <uri> <job> <user> <title> <copies> <options> <file>
181 : * 0 1 2 3 4 5 6
182 : */
183 2 : dev_uri = argv[0];
184 :
185 2 : print_user = argv[2];
186 2 : print_title = argv[3];
187 2 : print_copies = argv[4];
188 2 : print_file = argv[6];
189 4 : } else if (cmp2 == 0) {
190 : /*
191 : * smbspool <uri> <job> <user> <title> <copies> <options>
192 : * 0 1 2 3 4 5 6
193 : */
194 2 : dev_uri = argv[1];
195 :
196 2 : print_user = argv[3];
197 2 : print_title = argv[4];
198 2 : print_copies = argv[5];
199 2 : print_file = NULL;
200 : } else {
201 : /*
202 : * smbspool <job> <user> <title> <copies> <options> <file> | DEVICE_URI
203 : * 0 1 2 3 4 5 6
204 : */
205 2 : print_user = argv[2];
206 2 : print_title = argv[3];
207 2 : print_copies = argv[4];
208 2 : print_file = argv[6];
209 : }
210 4 : } else if (argc == 6) {
211 : /*
212 : * <uri> <job> <user> <title> <copies> <options>
213 : * smbspool <job> <user> <title> <copies> <options> | DEVICE_URI
214 : * 0 1 2 3 4 5
215 : */
216 4 : cmp = strncmp(argv[0], "smb://", 6);
217 4 : if (cmp == 0) {
218 2 : dev_uri = argv[0];
219 : }
220 :
221 4 : print_user = argv[2];
222 4 : print_title = argv[3];
223 4 : print_copies = argv[4];
224 : }
225 :
226 18 : if (print_file != NULL) {
227 : char *endp;
228 :
229 12 : fp = fopen(print_file, "rb");
230 12 : if (fp == NULL) {
231 0 : fprintf(stderr,
232 : "ERROR: Unable to open print file: %s",
233 : print_file);
234 0 : goto done;
235 : }
236 :
237 12 : copies = strtol(print_copies, &endp, 10);
238 12 : if (print_copies == endp) {
239 0 : perror("ERROR: Unable to determine number of copies");
240 0 : goto done;
241 : }
242 : } else {
243 6 : fp = stdin;
244 6 : copies = 1;
245 : }
246 :
247 : /*
248 : * Find the URI ...
249 : *
250 : * The URI in argv[0] is sanitized to remove username/password, so
251 : * use DEVICE_URI if available. Otherwise keep the URI already
252 : * discovered in argv.
253 : */
254 18 : env = getenv("DEVICE_URI");
255 18 : if (env != NULL && env[0] != '\0') {
256 8 : dev_uri = env;
257 : }
258 :
259 18 : if (dev_uri == NULL) {
260 0 : fprintf(stderr,
261 : "ERROR: No valid device URI has been specified\n");
262 0 : goto done;
263 : }
264 :
265 18 : cmp = strncmp(dev_uri, "smb://", 6);
266 18 : if (cmp != 0) {
267 0 : fprintf(stderr,
268 : "ERROR: No valid device URI has been specified\n");
269 0 : goto done;
270 : }
271 18 : len = snprintf(uri, sizeof(uri), "%s", dev_uri);
272 18 : if (len >= sizeof(uri)) {
273 0 : fprintf(stderr,
274 : "ERROR: The URI is too long.\n");
275 0 : goto done;
276 : }
277 :
278 18 : auth_info_required = getenv("AUTH_INFO_REQUIRED");
279 18 : if (auth_info_required == NULL) {
280 12 : auth_info_required = "samba";
281 : }
282 :
283 : /*
284 : * Extract the destination from the URI...
285 : */
286 :
287 18 : if ((sep = strrchr_m(uri, '@')) != NULL) {
288 14 : tmp = uri + 6;
289 14 : *sep++ = '\0';
290 :
291 : /* username is in tmp */
292 :
293 14 : server = sep;
294 :
295 : /*
296 : * Extract password as needed...
297 : */
298 :
299 14 : if ((tmp2 = strchr_m(tmp, ':')) != NULL) {
300 14 : *tmp2++ = '\0';
301 14 : password = uri_unescape_alloc(tmp2);
302 : }
303 14 : username = uri_unescape_alloc(tmp);
304 : } else {
305 4 : env = getenv("AUTH_USERNAME");
306 4 : if (env != NULL && strlen(env) > 0) {
307 0 : username = env;
308 : }
309 :
310 4 : env = getenv("AUTH_PASSWORD");
311 4 : if (env != NULL && strlen(env) > 0) {
312 0 : password = env;
313 : }
314 :
315 4 : server = uri + 6;
316 : }
317 :
318 18 : if (password != NULL) {
319 14 : auth_info_required = "username,password";
320 : }
321 :
322 18 : tmp = server;
323 :
324 18 : if ((sep = strchr_m(tmp, '/')) == NULL) {
325 0 : fputs("ERROR: Bad URI - need printer name!\n", stderr);
326 0 : goto done;
327 : }
328 :
329 18 : *sep++ = '\0';
330 18 : tmp2 = sep;
331 :
332 18 : if ((sep = strchr_m(tmp2, '/')) != NULL) {
333 : /*
334 : * Convert to smb://[username:password@]workgroup/server/printer...
335 : */
336 :
337 0 : *sep++ = '\0';
338 :
339 0 : workgroup = uri_unescape_alloc(tmp);
340 0 : server = uri_unescape_alloc(tmp2);
341 0 : printer = uri_unescape_alloc(sep);
342 : } else {
343 18 : workgroup = NULL;
344 18 : server = uri_unescape_alloc(tmp);
345 18 : printer = uri_unescape_alloc(tmp2);
346 : }
347 :
348 18 : if ((sep = strrchr_m(server, ':')) != NULL) {
349 0 : *sep++ = '\0';
350 :
351 0 : port = atoi(sep);
352 : } else {
353 18 : port = 0;
354 : }
355 :
356 : /*
357 : * Setup the SAMBA server state...
358 : */
359 :
360 18 : setup_logging("smbspool", DEBUG_STDERR);
361 :
362 18 : smb_init_locale();
363 :
364 18 : config_file = lp_default_path();
365 18 : if (!lp_load_client(config_file)) {
366 0 : fprintf(stderr,
367 : "ERROR: Can't load %s - run testparm to debug it\n",
368 : config_file);
369 0 : goto done;
370 : }
371 :
372 18 : if (workgroup == NULL) {
373 18 : workgroup = lp_workgroup();
374 : }
375 :
376 18 : load_interfaces();
377 :
378 : do {
379 18 : nt_status = smb_connect(&cli,
380 : workgroup,
381 : server,
382 : port,
383 : printer,
384 : username,
385 : password,
386 : print_user);
387 18 : if (!NT_STATUS_IS_OK(nt_status)) {
388 2 : status = get_exit_code(nt_status);
389 2 : if (status == 2) {
390 2 : fprintf(stderr,
391 : "DEBUG: Unable to connect to CIFS "
392 : "host: %s",
393 : nt_errstr(nt_status));
394 2 : goto done;
395 0 : } else if (getenv("CLASS") == NULL) {
396 0 : fprintf(stderr,
397 : "ERROR: Unable to connect to CIFS "
398 : "host: %s. Will retry in 60 "
399 : "seconds...\n",
400 : nt_errstr(nt_status));
401 0 : sleep(60);
402 0 : tries++;
403 : } else {
404 0 : fprintf(stderr,
405 : "ERROR: Unable to connect to CIFS "
406 : "host: %s. Trying next printer...\n",
407 : nt_errstr(nt_status));
408 0 : goto done;
409 : }
410 : }
411 16 : } while (!NT_STATUS_IS_OK(nt_status) && (tries < MAX_RETRY_CONNECT));
412 :
413 16 : if (cli == NULL) {
414 0 : fprintf(stderr, "ERROR: Unable to connect to CIFS host after (tried %d times)\n", tries);
415 0 : goto done;
416 : }
417 :
418 : /*
419 : * Now that we are connected to the server, ignore SIGTERM so that we
420 : * can finish out any page data the driver sends (e.g. to eject the
421 : * current page... Only ignore SIGTERM if we are printing data from
422 : * stdin (otherwise you can't cancel raw jobs...)
423 : */
424 :
425 16 : if (argc < 7) {
426 4 : CatchSignal(SIGTERM, SIG_IGN);
427 : }
428 :
429 : /*
430 : * Queue the job...
431 : */
432 :
433 32 : for (i = 0; i < copies; i++) {
434 16 : status = smb_print(cli, print_title, fp);
435 16 : if (status != 0) {
436 0 : break;
437 : }
438 : }
439 :
440 16 : cli_shutdown(cli);
441 :
442 : /*
443 : * Return the queue status...
444 : */
445 :
446 22 : done:
447 22 : gfree_all();
448 22 : TALLOC_FREE(frame);
449 22 : return (status);
450 : }
451 :
452 :
453 : /*
454 : * 'get_exit_code()' - Get the backend exit code based on the current error.
455 : */
456 :
457 : static int
458 2 : get_exit_code(NTSTATUS nt_status)
459 : {
460 : size_t i;
461 :
462 : /* List of NTSTATUS errors that are considered
463 : * authentication errors
464 : */
465 : static const NTSTATUS auth_errors[] =
466 : {
467 : NT_STATUS_ACCESS_DENIED,
468 : NT_STATUS_ACCESS_VIOLATION,
469 : NT_STATUS_ACCOUNT_DISABLED,
470 : NT_STATUS_ACCOUNT_LOCKED_OUT,
471 : NT_STATUS_ACCOUNT_RESTRICTION,
472 : NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND,
473 : NT_STATUS_INVALID_ACCOUNT_NAME,
474 : NT_STATUS_INVALID_COMPUTER_NAME,
475 : NT_STATUS_INVALID_LOGON_HOURS,
476 : NT_STATUS_INVALID_WORKSTATION,
477 : NT_STATUS_LOGON_FAILURE,
478 : NT_STATUS_NO_SUCH_USER,
479 : NT_STATUS_NO_SUCH_DOMAIN,
480 : NT_STATUS_NO_LOGON_SERVERS,
481 : NT_STATUS_PASSWORD_EXPIRED,
482 : NT_STATUS_PRIVILEGE_NOT_HELD,
483 : NT_STATUS_SHARING_VIOLATION,
484 : NT_STATUS_WRONG_PASSWORD,
485 : };
486 :
487 :
488 2 : fprintf(stderr,
489 : "DEBUG: get_exit_code(nt_status=%s [%x])\n",
490 : nt_errstr(nt_status), NT_STATUS_V(nt_status));
491 :
492 2 : for (i = 0; i < ARRAY_SIZE(auth_errors); i++) {
493 2 : if (!NT_STATUS_EQUAL(nt_status, auth_errors[i])) {
494 0 : continue;
495 : }
496 :
497 2 : fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
498 :
499 : /*
500 : * 2 = authentication required...
501 : */
502 :
503 2 : return (2);
504 :
505 : }
506 :
507 : /*
508 : * 1 = fail
509 : */
510 :
511 0 : return (1);
512 : }
513 :
514 :
515 : /*
516 : * 'list_devices()' - List the available printers seen on the network...
517 : */
518 :
519 : static void
520 4 : list_devices(void)
521 : {
522 : /*
523 : * Eventually, search the local workgroup for available hosts and printers.
524 : */
525 :
526 4 : puts("network smb \"Unknown\" \"Windows Printer via SAMBA\"");
527 4 : }
528 :
529 :
530 : static NTSTATUS
531 16 : smb_complete_connection(struct cli_state **output_cli,
532 : const char *myname,
533 : const char *server,
534 : int port,
535 : const char *username,
536 : const char *password,
537 : const char *workgroup,
538 : const char *share,
539 : bool use_kerberos,
540 : bool fallback_after_kerberos)
541 : {
542 : struct cli_state *cli; /* New connection */
543 : NTSTATUS nt_status;
544 16 : struct cli_credentials *creds = NULL;
545 :
546 : /* Start the SMB connection */
547 16 : nt_status = cli_start_connection(&cli, myname, server, NULL, port,
548 : SMB_SIGNING_DEFAULT, 0);
549 16 : if (!NT_STATUS_IS_OK(nt_status)) {
550 0 : fprintf(stderr, "ERROR: Connection failed: %s\n", nt_errstr(nt_status));
551 0 : return nt_status;
552 : }
553 :
554 16 : creds = cli_session_creds_init(cli,
555 : username,
556 : workgroup,
557 : NULL, /* realm */
558 : password,
559 : use_kerberos,
560 : fallback_after_kerberos,
561 : false, /* use_ccache */
562 : false); /* password_is_nt_hash */
563 16 : if (creds == NULL) {
564 0 : fprintf(stderr, "ERROR: cli_session_creds_init failed\n");
565 0 : cli_shutdown(cli);
566 0 : return NT_STATUS_NO_MEMORY;
567 : }
568 :
569 16 : nt_status = cli_session_setup_creds(cli, creds);
570 16 : if (!NT_STATUS_IS_OK(nt_status)) {
571 0 : fprintf(stderr, "ERROR: Session setup failed: %s\n", nt_errstr(nt_status));
572 :
573 0 : cli_shutdown(cli);
574 :
575 0 : return nt_status;
576 : }
577 :
578 16 : nt_status = cli_tree_connect_creds(cli, share, "?????", creds);
579 16 : if (!NT_STATUS_IS_OK(nt_status)) {
580 0 : fprintf(stderr, "ERROR: Tree connect failed (%s)\n",
581 : nt_errstr(nt_status));
582 :
583 0 : cli_shutdown(cli);
584 :
585 0 : return nt_status;
586 : }
587 :
588 16 : *output_cli = cli;
589 16 : return NT_STATUS_OK;
590 : }
591 :
592 0 : static bool kerberos_ccache_is_valid(void) {
593 : krb5_context ctx;
594 0 : const char *ccache_name = NULL;
595 0 : krb5_ccache ccache = NULL;
596 : krb5_error_code code;
597 :
598 0 : code = smb_krb5_init_context_common(&ctx);
599 0 : if (code != 0) {
600 0 : DBG_ERR("kerberos init context failed (%s)\n",
601 : error_message(code));
602 0 : return false;
603 : }
604 :
605 0 : ccache_name = krb5_cc_default_name(ctx);
606 0 : if (ccache_name == NULL) {
607 0 : DBG_ERR("Failed to get default ccache name\n");
608 0 : krb5_free_context(ctx);
609 0 : return false;
610 : }
611 :
612 0 : code = krb5_cc_resolve(ctx, ccache_name, &ccache);
613 0 : if (code != 0) {
614 0 : DBG_ERR("Failed to resolve ccache name: %s\n",
615 : ccache_name);
616 0 : krb5_free_context(ctx);
617 0 : return false;
618 : } else {
619 0 : krb5_principal default_princ = NULL;
620 0 : char *princ_name = NULL;
621 :
622 0 : code = krb5_cc_get_principal(ctx,
623 : ccache,
624 : &default_princ);
625 0 : if (code != 0) {
626 0 : DBG_ERR("Failed to get default principal from "
627 : "ccache: %s\n",
628 : ccache_name);
629 0 : krb5_cc_close(ctx, ccache);
630 0 : krb5_free_context(ctx);
631 0 : return false;
632 : }
633 :
634 0 : code = krb5_unparse_name(ctx,
635 : default_princ,
636 : &princ_name);
637 0 : if (code == 0) {
638 0 : fprintf(stderr,
639 : "DEBUG: Try to authenticate as %s\n",
640 : princ_name);
641 0 : krb5_free_unparsed_name(ctx, princ_name);
642 : }
643 0 : krb5_free_principal(ctx, default_princ);
644 : }
645 0 : krb5_cc_close(ctx, ccache);
646 0 : krb5_free_context(ctx);
647 :
648 0 : return true;
649 : }
650 :
651 : /*
652 : * 'smb_connect()' - Return a connection to a server.
653 : */
654 :
655 : static NTSTATUS
656 18 : smb_connect(struct cli_state **output_cli,
657 : const char *workgroup, /* I - Workgroup */
658 : const char *server, /* I - Server */
659 : const int port, /* I - Port */
660 : const char *share, /* I - Printer */
661 : const char *username, /* I - Username */
662 : const char *password, /* I - Password */
663 : const char *jobusername) /* I - User who issued the print job */
664 : {
665 18 : struct cli_state *cli = NULL; /* New connection */
666 18 : char *myname = NULL; /* Client name */
667 : struct passwd *pwd;
668 18 : bool use_kerberos = false;
669 18 : bool fallback_after_kerberos = false;
670 18 : const char *user = username;
671 : NTSTATUS nt_status;
672 :
673 : /*
674 : * Get the names and addresses of the client and server...
675 : */
676 18 : myname = get_myname(talloc_tos());
677 18 : if (!myname) {
678 0 : return NT_STATUS_NO_MEMORY;
679 : }
680 :
681 :
682 18 : if (strcmp(auth_info_required, "negotiate") == 0) {
683 0 : if (!kerberos_ccache_is_valid()) {
684 0 : fprintf(stderr,
685 : "ERROR: No valid Kerberos credential cache found! "
686 : "Using smbspool_krb5_wrapper may help.\n");
687 0 : return NT_STATUS_LOGON_FAILURE;
688 : }
689 0 : user = jobusername;
690 :
691 0 : use_kerberos = true;
692 0 : fprintf(stderr,
693 : "DEBUG: Try to connect using Kerberos ...\n");
694 18 : } else if (strcmp(auth_info_required, "username,password") == 0) {
695 14 : if (username == NULL) {
696 0 : return NT_STATUS_INVALID_ACCOUNT_NAME;
697 : }
698 :
699 : /* Fallback to NTLM */
700 14 : fallback_after_kerberos = true;
701 :
702 14 : fprintf(stderr,
703 : "DEBUG: Try to connect using username/password ...\n");
704 4 : } else if (strcmp(auth_info_required, "none") == 0) {
705 2 : goto anonymous;
706 2 : } else if (strcmp(auth_info_required, "samba") == 0) {
707 0 : if (username != NULL) {
708 0 : fallback_after_kerberos = true;
709 0 : } else if (kerberos_ccache_is_valid()) {
710 0 : auth_info_required = "negotiate";
711 :
712 0 : user = jobusername;
713 0 : use_kerberos = true;
714 : } else {
715 0 : fprintf(stderr,
716 : "DEBUG: This backend requires credentials!\n");
717 0 : return NT_STATUS_ACCESS_DENIED;
718 : }
719 : } else {
720 2 : return NT_STATUS_ACCESS_DENIED;
721 : }
722 :
723 14 : nt_status = smb_complete_connection(&cli,
724 : myname,
725 : server,
726 : port,
727 : user,
728 : password,
729 : workgroup,
730 : share,
731 : true, /* try kerberos */
732 : fallback_after_kerberos);
733 14 : if (NT_STATUS_IS_OK(nt_status)) {
734 14 : fprintf(stderr, "DEBUG: SMB connection established.\n");
735 :
736 14 : *output_cli = cli;
737 14 : return NT_STATUS_OK;
738 : }
739 :
740 0 : if (!use_kerberos) {
741 0 : fprintf(stderr, "ERROR: SMB connection failed!\n");
742 0 : return nt_status;
743 : }
744 :
745 : /* give a chance for a passwordless NTLMSSP session setup */
746 0 : pwd = getpwuid(geteuid());
747 0 : if (pwd == NULL) {
748 0 : return NT_STATUS_ACCESS_DENIED;
749 : }
750 :
751 0 : nt_status = smb_complete_connection(&cli,
752 : myname,
753 : server,
754 : port,
755 0 : pwd->pw_name,
756 : "",
757 : workgroup,
758 : share,
759 : false, false);
760 0 : if (NT_STATUS_IS_OK(nt_status)) {
761 0 : fputs("DEBUG: Connected with NTLMSSP...\n", stderr);
762 :
763 0 : *output_cli = cli;
764 0 : return NT_STATUS_OK;
765 : }
766 :
767 : /*
768 : * last try. Use anonymous authentication
769 : */
770 :
771 0 : anonymous:
772 2 : nt_status = smb_complete_connection(&cli,
773 : myname,
774 : server,
775 : port,
776 : "",
777 : "",
778 : workgroup,
779 : share,
780 : false, false);
781 2 : if (NT_STATUS_IS_OK(nt_status)) {
782 2 : *output_cli = cli;
783 2 : return NT_STATUS_OK;
784 : }
785 :
786 0 : return nt_status;
787 : }
788 :
789 :
790 : /*
791 : * 'smb_print()' - Queue a job for printing using the SMB protocol.
792 : */
793 :
794 : static int /* O - 0 = success, non-0 = failure */
795 16 : smb_print(struct cli_state * cli, /* I - SMB connection */
796 : const char *print_title, /* I - Title/job name */
797 : FILE * fp)
798 : { /* I - File to print */
799 : uint16_t fnum; /* File number */
800 : int nbytes, /* Number of bytes read */
801 : tbytes; /* Total bytes read */
802 : char buffer[8192], /* Buffer for copy */
803 : *ptr; /* Pointer into title */
804 16 : char title[1024] = {0};
805 : int len;
806 : NTSTATUS nt_status;
807 :
808 :
809 : /*
810 : * Sanitize the title...
811 : */
812 16 : len = snprintf(title, sizeof(title), "%s", print_title);
813 16 : if (len != strlen(print_title)) {
814 0 : return 2;
815 : }
816 :
817 160 : for (ptr = title; *ptr; ptr++) {
818 144 : if (!isalnum((int) *ptr) && !isspace((int) *ptr)) {
819 0 : *ptr = '_';
820 : }
821 : }
822 :
823 : /*
824 : * Open the printer device...
825 : */
826 :
827 16 : nt_status = cli_open(cli, title, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE,
828 : &fnum);
829 16 : if (!NT_STATUS_IS_OK(nt_status)) {
830 0 : fprintf(stderr, "ERROR: %s opening remote spool %s\n",
831 : nt_errstr(nt_status), title);
832 0 : return get_exit_code(nt_status);
833 : }
834 :
835 : /*
836 : * Copy the file to the printer...
837 : */
838 :
839 16 : if (fp != stdin)
840 10 : rewind(fp);
841 :
842 16 : tbytes = 0;
843 :
844 368 : while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
845 : NTSTATUS status;
846 :
847 352 : status = cli_writeall(cli, fnum, 0, (uint8_t *)buffer,
848 : tbytes, nbytes, NULL);
849 352 : if (!NT_STATUS_IS_OK(status)) {
850 0 : int ret = get_exit_code(status);
851 0 : fprintf(stderr, "ERROR: Error writing spool: %s\n",
852 : nt_errstr(status));
853 0 : fprintf(stderr, "DEBUG: Returning status %d...\n",
854 : ret);
855 0 : cli_close(cli, fnum);
856 :
857 0 : return (ret);
858 : }
859 352 : tbytes += nbytes;
860 : }
861 :
862 16 : nt_status = cli_close(cli, fnum);
863 16 : if (!NT_STATUS_IS_OK(nt_status)) {
864 0 : fprintf(stderr, "ERROR: %s closing remote spool %s\n",
865 : nt_errstr(nt_status), title);
866 0 : return get_exit_code(nt_status);
867 : } else {
868 16 : return (0);
869 : }
870 : }
871 :
872 : static char *
873 64 : uri_unescape_alloc(const char *uritok)
874 : {
875 : char *ret;
876 : char *end;
877 64 : ret = (char *) SMB_STRDUP(uritok);
878 64 : if (!ret) {
879 0 : return NULL;
880 : }
881 :
882 64 : end = rfc1738_unescape(ret);
883 64 : if (end == NULL) {
884 0 : free(ret);
885 0 : return NULL;
886 : }
887 64 : return ret;
888 : }
|