LCOV - code coverage report
Current view: top level - source3/client - smbspool.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 191 314 60.8 %
Date: 2024-05-31 13:13:24 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(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             : }

Generated by: LCOV version 1.14