LCOV - code coverage report
Current view: top level - source3/client - smbspool.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 191 314 60.8 %
Date: 2024-02-28 12:06:22 Functions: 7 8 87.5 %

          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             : }

Generated by: LCOV version 1.14