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(talloc_tos(),
548 : &cli,
549 : myname,
550 : server,
551 : NULL,
552 : port,
553 : SMB_SIGNING_DEFAULT,
554 : 0);
555 16 : if (!NT_STATUS_IS_OK(nt_status)) {
556 0 : fprintf(stderr, "ERROR: Connection failed: %s\n", nt_errstr(nt_status));
557 0 : return nt_status;
558 : }
559 :
560 16 : creds = cli_session_creds_init(cli,
561 : username,
562 : workgroup,
563 : NULL, /* realm */
564 : password,
565 : use_kerberos,
566 : fallback_after_kerberos,
567 : false, /* use_ccache */
568 : false); /* password_is_nt_hash */
569 16 : if (creds == NULL) {
570 0 : fprintf(stderr, "ERROR: cli_session_creds_init failed\n");
571 0 : cli_shutdown(cli);
572 0 : return NT_STATUS_NO_MEMORY;
573 : }
574 :
575 16 : nt_status = cli_session_setup_creds(cli, creds);
576 16 : if (!NT_STATUS_IS_OK(nt_status)) {
577 0 : fprintf(stderr, "ERROR: Session setup failed: %s\n", nt_errstr(nt_status));
578 :
579 0 : cli_shutdown(cli);
580 :
581 0 : return nt_status;
582 : }
583 :
584 16 : nt_status = cli_tree_connect_creds(cli, share, "?????", creds);
585 16 : if (!NT_STATUS_IS_OK(nt_status)) {
586 0 : fprintf(stderr, "ERROR: Tree connect failed (%s)\n",
587 : nt_errstr(nt_status));
588 :
589 0 : cli_shutdown(cli);
590 :
591 0 : return nt_status;
592 : }
593 :
594 16 : *output_cli = cli;
595 16 : return NT_STATUS_OK;
596 : }
597 :
598 0 : static bool kerberos_ccache_is_valid(void) {
599 : krb5_context ctx;
600 0 : const char *ccache_name = NULL;
601 0 : krb5_ccache ccache = NULL;
602 : krb5_error_code code;
603 :
604 0 : code = smb_krb5_init_context_common(&ctx);
605 0 : if (code != 0) {
606 0 : DBG_ERR("kerberos init context failed (%s)\n",
607 : error_message(code));
608 0 : return false;
609 : }
610 :
611 0 : ccache_name = smb_force_krb5_cc_default_name(ctx);
612 0 : if (ccache_name == NULL) {
613 0 : DBG_ERR("Failed to get default ccache name\n");
614 0 : krb5_free_context(ctx);
615 0 : return false;
616 : }
617 :
618 0 : code = krb5_cc_resolve(ctx, ccache_name, &ccache);
619 0 : if (code != 0) {
620 0 : DBG_ERR("Failed to resolve ccache name: %s\n",
621 : ccache_name);
622 0 : krb5_free_context(ctx);
623 0 : return false;
624 : } else {
625 0 : krb5_principal default_princ = NULL;
626 0 : char *princ_name = NULL;
627 :
628 0 : code = krb5_cc_get_principal(ctx,
629 : ccache,
630 : &default_princ);
631 0 : if (code != 0) {
632 0 : DBG_ERR("Failed to get default principal from "
633 : "ccache: %s\n",
634 : ccache_name);
635 0 : krb5_cc_close(ctx, ccache);
636 0 : krb5_free_context(ctx);
637 0 : return false;
638 : }
639 :
640 0 : code = krb5_unparse_name(ctx,
641 : default_princ,
642 : &princ_name);
643 0 : if (code == 0) {
644 0 : fprintf(stderr,
645 : "DEBUG: Try to authenticate as %s\n",
646 : princ_name);
647 0 : krb5_free_unparsed_name(ctx, princ_name);
648 : }
649 0 : krb5_free_principal(ctx, default_princ);
650 : }
651 0 : krb5_cc_close(ctx, ccache);
652 0 : krb5_free_context(ctx);
653 :
654 0 : return true;
655 : }
656 :
657 : /*
658 : * 'smb_connect()' - Return a connection to a server.
659 : */
660 :
661 : static NTSTATUS
662 18 : smb_connect(struct cli_state **output_cli,
663 : const char *workgroup, /* I - Workgroup */
664 : const char *server, /* I - Server */
665 : const int port, /* I - Port */
666 : const char *share, /* I - Printer */
667 : const char *username, /* I - Username */
668 : const char *password, /* I - Password */
669 : const char *jobusername) /* I - User who issued the print job */
670 : {
671 18 : struct cli_state *cli = NULL; /* New connection */
672 18 : char *myname = NULL; /* Client name */
673 : struct passwd *pwd;
674 18 : bool use_kerberos = false;
675 18 : bool fallback_after_kerberos = false;
676 18 : const char *user = username;
677 : NTSTATUS nt_status;
678 :
679 : /*
680 : * Get the names and addresses of the client and server...
681 : */
682 18 : myname = get_myname(talloc_tos());
683 18 : if (!myname) {
684 0 : return NT_STATUS_NO_MEMORY;
685 : }
686 :
687 :
688 18 : if (strcmp(auth_info_required, "negotiate") == 0) {
689 0 : if (!kerberos_ccache_is_valid()) {
690 0 : fprintf(stderr,
691 : "ERROR: No valid Kerberos credential cache found! "
692 : "Using smbspool_krb5_wrapper may help.\n");
693 0 : return NT_STATUS_LOGON_FAILURE;
694 : }
695 0 : user = jobusername;
696 :
697 0 : use_kerberos = true;
698 0 : fprintf(stderr,
699 : "DEBUG: Try to connect using Kerberos ...\n");
700 18 : } else if (strcmp(auth_info_required, "username,password") == 0) {
701 14 : if (username == NULL) {
702 0 : return NT_STATUS_INVALID_ACCOUNT_NAME;
703 : }
704 :
705 : /* Fallback to NTLM */
706 14 : fallback_after_kerberos = true;
707 :
708 14 : fprintf(stderr,
709 : "DEBUG: Try to connect using username/password ...\n");
710 4 : } else if (strcmp(auth_info_required, "none") == 0) {
711 2 : goto anonymous;
712 2 : } else if (strcmp(auth_info_required, "samba") == 0) {
713 0 : if (username != NULL) {
714 0 : fallback_after_kerberos = true;
715 0 : } else if (kerberos_ccache_is_valid()) {
716 0 : auth_info_required = "negotiate";
717 :
718 0 : user = jobusername;
719 0 : use_kerberos = true;
720 : } else {
721 0 : fprintf(stderr,
722 : "DEBUG: This backend requires credentials!\n");
723 0 : return NT_STATUS_ACCESS_DENIED;
724 : }
725 : } else {
726 2 : return NT_STATUS_ACCESS_DENIED;
727 : }
728 :
729 14 : nt_status = smb_complete_connection(&cli,
730 : myname,
731 : server,
732 : port,
733 : user,
734 : password,
735 : workgroup,
736 : share,
737 : true, /* try kerberos */
738 : fallback_after_kerberos);
739 14 : if (NT_STATUS_IS_OK(nt_status)) {
740 14 : fprintf(stderr, "DEBUG: SMB connection established.\n");
741 :
742 14 : *output_cli = cli;
743 14 : return NT_STATUS_OK;
744 : }
745 :
746 0 : if (!use_kerberos) {
747 0 : fprintf(stderr, "ERROR: SMB connection failed!\n");
748 0 : return nt_status;
749 : }
750 :
751 : /* give a chance for a passwordless NTLMSSP session setup */
752 0 : pwd = getpwuid(geteuid());
753 0 : if (pwd == NULL) {
754 0 : return NT_STATUS_ACCESS_DENIED;
755 : }
756 :
757 0 : nt_status = smb_complete_connection(&cli,
758 : myname,
759 : server,
760 : port,
761 0 : pwd->pw_name,
762 : "",
763 : workgroup,
764 : share,
765 : false, false);
766 0 : if (NT_STATUS_IS_OK(nt_status)) {
767 0 : fputs("DEBUG: Connected with NTLMSSP...\n", stderr);
768 :
769 0 : *output_cli = cli;
770 0 : return NT_STATUS_OK;
771 : }
772 :
773 : /*
774 : * last try. Use anonymous authentication
775 : */
776 :
777 0 : anonymous:
778 2 : nt_status = smb_complete_connection(&cli,
779 : myname,
780 : server,
781 : port,
782 : "",
783 : "",
784 : workgroup,
785 : share,
786 : false, false);
787 2 : if (NT_STATUS_IS_OK(nt_status)) {
788 2 : *output_cli = cli;
789 2 : return NT_STATUS_OK;
790 : }
791 :
792 0 : return nt_status;
793 : }
794 :
795 :
796 : /*
797 : * 'smb_print()' - Queue a job for printing using the SMB protocol.
798 : */
799 :
800 : static int /* O - 0 = success, non-0 = failure */
801 16 : smb_print(struct cli_state * cli, /* I - SMB connection */
802 : const char *print_title, /* I - Title/job name */
803 : FILE * fp)
804 : { /* I - File to print */
805 : uint16_t fnum; /* File number */
806 : int nbytes, /* Number of bytes read */
807 : tbytes; /* Total bytes read */
808 : char buffer[8192], /* Buffer for copy */
809 : *ptr; /* Pointer into title */
810 16 : char title[1024] = {0};
811 : int len;
812 : NTSTATUS nt_status;
813 :
814 :
815 : /*
816 : * Sanitize the title...
817 : */
818 16 : len = snprintf(title, sizeof(title), "%s", print_title);
819 16 : if (len != strlen(print_title)) {
820 0 : return 2;
821 : }
822 :
823 160 : for (ptr = title; *ptr; ptr++) {
824 144 : if (!isalnum((int) *ptr) && !isspace((int) *ptr)) {
825 0 : *ptr = '_';
826 : }
827 : }
828 :
829 : /*
830 : * Open the printer device...
831 : */
832 :
833 16 : nt_status = cli_open(cli, title, O_RDWR | O_CREAT | O_TRUNC, DENY_NONE,
834 : &fnum);
835 16 : if (!NT_STATUS_IS_OK(nt_status)) {
836 0 : fprintf(stderr, "ERROR: %s opening remote spool %s\n",
837 : nt_errstr(nt_status), title);
838 0 : return get_exit_code(nt_status);
839 : }
840 :
841 : /*
842 : * Copy the file to the printer...
843 : */
844 :
845 16 : if (fp != stdin)
846 10 : rewind(fp);
847 :
848 16 : tbytes = 0;
849 :
850 368 : while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
851 : NTSTATUS status;
852 :
853 352 : status = cli_writeall(cli, fnum, 0, (uint8_t *)buffer,
854 : tbytes, nbytes, NULL);
855 352 : if (!NT_STATUS_IS_OK(status)) {
856 0 : int ret = get_exit_code(status);
857 0 : fprintf(stderr, "ERROR: Error writing spool: %s\n",
858 : nt_errstr(status));
859 0 : fprintf(stderr, "DEBUG: Returning status %d...\n",
860 : ret);
861 0 : cli_close(cli, fnum);
862 :
863 0 : return (ret);
864 : }
865 352 : tbytes += nbytes;
866 : }
867 :
868 16 : nt_status = cli_close(cli, fnum);
869 16 : if (!NT_STATUS_IS_OK(nt_status)) {
870 0 : fprintf(stderr, "ERROR: %s closing remote spool %s\n",
871 : nt_errstr(nt_status), title);
872 0 : return get_exit_code(nt_status);
873 : } else {
874 16 : return (0);
875 : }
876 : }
877 :
878 : static char *
879 64 : uri_unescape_alloc(const char *uritok)
880 : {
881 : char *ret;
882 : char *end;
883 64 : ret = (char *) SMB_STRDUP(uritok);
884 64 : if (!ret) {
885 0 : return NULL;
886 : }
887 :
888 64 : end = rfc1738_unescape(ret);
889 64 : if (end == NULL) {
890 0 : free(ret);
891 0 : return NULL;
892 : }
893 64 : return ret;
894 : }
|