]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3:smbspool: Use NTSTATUS return codes
authorAndreas Schneider <asn@samba.org>
Tue, 14 May 2019 09:35:46 +0000 (11:35 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 23 May 2019 09:41:17 +0000 (09:41 +0000)
This allows us to simplify some code and return better errors.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
source3/client/smbspool.c

index 79e210dd12e700f3935e69cc2dc32415051ce058..ad988eb0df944b9e9b1bd83305949901b2dfde73 100644 (file)
  * Local functions...
  */
 
-static int      get_exit_code(struct cli_state * cli, NTSTATUS nt_status);
+static int      get_exit_code(NTSTATUS nt_status);
 static void     list_devices(void);
-static struct cli_state *smb_complete_connection(const char *, const char *,
-       int, const char *, const char *, const char *, const char *, int, bool *need_auth);
-static struct cli_state *smb_connect(const char *, const char *, int, const
-       char *, const char *, const char *, const char *, bool *need_auth);
+static NTSTATUS
+smb_complete_connection(struct cli_state **output_cli,
+                       const char *myname,
+                       const char *server,
+                       int port,
+                       const char *username,
+                       const char *password,
+                       const char *workgroup,
+                       const char *share,
+                       int flags);
+static NTSTATUS
+smb_connect(struct cli_state **output_cli,
+           const char *workgroup,
+           const char *server,
+           const int port,
+           const char *share,
+           const char *username,
+           const char *password,
+           const char *jobusername);
 static int      smb_print(struct cli_state *, const char *, FILE *);
 static char    *uri_unescape_alloc(const char *);
 #if 0
@@ -90,16 +105,15 @@ main(int argc,                     /* I - Number of command-line arguments */
                       *sep,    /* Pointer to separator */
                       *tmp, *tmp2;     /* Temp pointers to do escaping */
        const char     *password = NULL;        /* Password */
-       char           *username,       /* Username */
-                      *server, /* Server name */
+       const char     *username = NULL;        /* Username */
+       char           *server, /* Server name */
                       *printer;/* Printer name */
        const char     *workgroup;      /* Workgroup */
        FILE           *fp;     /* File to print */
        int             status = 1;     /* Status of LPD job */
-       struct cli_state *cli;  /* SMB interface */
-       char            empty_str[] = "";
+       NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
+       struct cli_state *cli = NULL;   /* SMB interface */
        int             tries = 0;
-       bool            need_auth = true;
        const char     *dev_uri = NULL;
        const char     *env = NULL;
        const char     *config_file = NULL;
@@ -296,8 +310,9 @@ main(int argc,                      /* I - Number of command-line arguments */
                }
                username = uri_unescape_alloc(tmp);
        } else {
-               if ((username = getenv("AUTH_USERNAME")) == NULL) {
-                       username = empty_str;
+               env = getenv("AUTH_USERNAME");
+               if (env != NULL && strlen(env) > 0) {
+                       username = env;
                }
 
                env = getenv("AUTH_PASSWORD");
@@ -369,27 +384,39 @@ main(int argc,                    /* I - Number of command-line arguments */
        load_interfaces();
 
        do {
-               cli = smb_connect(workgroup,
-                                 server,
-                                 port,
-                                 printer,
-                                 username,
-                                 password,
-                                 print_user,
-                                 &need_auth);
-               if (cli == NULL) {
-                       if (need_auth) {
-                               exit(2);
+               nt_status = smb_connect(&cli,
+                                       workgroup,
+                                       server,
+                                       port,
+                                       printer,
+                                       username,
+                                       password,
+                                       print_user);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       status = get_exit_code(nt_status);
+                       if (status == 2) {
+                               fprintf(stderr,
+                                       "DEBUG: Unable to connect to CIFS "
+                                       "host: %s",
+                                       nt_errstr(nt_status));
+                               goto done;
                        } else if (getenv("CLASS") == NULL) {
-                               fprintf(stderr, "ERROR: Unable to connect to CIFS host, will retry in 60 seconds...\n");
+                               fprintf(stderr,
+                                       "ERROR: Unable to connect to CIFS "
+                                       "host: %s. Will retry in 60 "
+                                       "seconds...\n",
+                                       nt_errstr(nt_status));
                                sleep(60);
                                tries++;
                        } else {
-                               fprintf(stderr, "ERROR: Unable to connect to CIFS host, trying next printer...\n");
+                               fprintf(stderr,
+                                       "ERROR: Unable to connect to CIFS "
+                                       "host: %s. Trying next printer...\n",
+                                       nt_errstr(nt_status));
                                goto done;
                        }
                }
-       } while ((cli == NULL) && (tries < MAX_RETRY_CONNECT));
+       } while (!NT_STATUS_IS_OK(nt_status) && (tries < MAX_RETRY_CONNECT));
 
        if (cli == NULL) {
                fprintf(stderr, "ERROR: Unable to connect to CIFS host after (tried %d times)\n", tries);
@@ -436,10 +463,9 @@ done:
  */
 
 static int
-get_exit_code(struct cli_state * cli,
-             NTSTATUS nt_status)
+get_exit_code(NTSTATUS nt_status)
 {
-       int i;
+       size_t i;
 
        /* List of NTSTATUS errors that are considered
         * authentication errors
@@ -455,17 +481,16 @@ get_exit_code(struct cli_state * cli,
        };
 
 
-       fprintf(stderr, "DEBUG: get_exit_code(cli=%p, nt_status=%s [%x])\n",
-               cli, nt_errstr(nt_status), NT_STATUS_V(nt_status));
+       fprintf(stderr,
+               "DEBUG: get_exit_code(nt_status=%s [%x])\n",
+               nt_errstr(nt_status), NT_STATUS_V(nt_status));
 
        for (i = 0; i < ARRAY_SIZE(auth_errors); i++) {
                if (!NT_STATUS_EQUAL(nt_status, auth_errors[i])) {
                        continue;
                }
 
-               if (cli) {
-                       fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
-               }
+               fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required);
 
                /*
                 * 2 = authentication required...
@@ -498,16 +523,16 @@ list_devices(void)
 }
 
 
-static struct cli_state *
-smb_complete_connection(const char *myname,
+static NTSTATUS
+smb_complete_connection(struct cli_state **output_cli,
+                       const char *myname,
                        const char *server,
                        int port,
                        const char *username,
                        const char *password,
                        const char *workgroup,
                        const char *share,
-                       int flags,
-                       bool *need_auth)
+                       int flags)
 {
        struct cli_state *cli;  /* New connection */
        NTSTATUS        nt_status;
@@ -516,12 +541,11 @@ smb_complete_connection(const char *myname,
        bool fallback_after_kerberos = false;
 
        /* Start the SMB connection */
-       *need_auth = false;
        nt_status = cli_start_connection(&cli, myname, server, NULL, port,
                                         SMB_SIGNING_DEFAULT, flags);
        if (!NT_STATUS_IS_OK(nt_status)) {
                fprintf(stderr, "ERROR: Connection failed: %s\n", nt_errstr(nt_status));
-               return NULL;
+               return nt_status;
        }
 
        if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
@@ -544,20 +568,16 @@ smb_complete_connection(const char *myname,
        if (creds == NULL) {
                fprintf(stderr, "ERROR: cli_session_creds_init failed\n");
                cli_shutdown(cli);
-               return NULL;
+               return NT_STATUS_NO_MEMORY;
        }
 
        nt_status = cli_session_setup_creds(cli, creds);
        if (!NT_STATUS_IS_OK(nt_status)) {
                fprintf(stderr, "ERROR: Session setup failed: %s\n", nt_errstr(nt_status));
 
-               if (get_exit_code(cli, nt_status) == 2) {
-                       *need_auth = true;
-               }
-
                cli_shutdown(cli);
 
-               return NULL;
+               return nt_status;
        }
 
        nt_status = cli_tree_connect_creds(cli, share, "?????", creds);
@@ -565,13 +585,9 @@ smb_complete_connection(const char *myname,
                fprintf(stderr, "ERROR: Tree connect failed (%s)\n",
                        nt_errstr(nt_status));
 
-               if (get_exit_code(cli, nt_status) == 2) {
-                       *need_auth = true;
-               }
-
                cli_shutdown(cli);
 
-               return NULL;
+               return nt_status;
        }
 #if 0
        /* Need to work out how to specify this on the URL. */
@@ -584,7 +600,8 @@ smb_complete_connection(const char *myname,
        }
 #endif
 
-       return cli;
+       *output_cli = cli;
+       return NT_STATUS_OK;
 }
 
 static bool kerberos_ccache_is_valid(void) {
@@ -650,49 +667,48 @@ static bool kerberos_ccache_is_valid(void) {
  * 'smb_connect()' - Return a connection to a server.
  */
 
-static struct cli_state *      /* O - SMB connection */
-smb_connect(const char *workgroup,     /* I - Workgroup */
+static NTSTATUS
+smb_connect(struct cli_state **output_cli,
+           const char *workgroup,      /* I - Workgroup */
            const char *server, /* I - Server */
            const int port,     /* I - Port */
            const char *share,  /* I - Printer */
            const char *username,       /* I - Username */
            const char *password,       /* I - Password */
-           const char *jobusername,    /* I - User who issued the print job */
-           bool *need_auth)
-{                              /* O - Need authentication? */
-       struct cli_state *cli;  /* New connection */
+           const char *jobusername)    /* I - User who issued the print job */
+{
+       struct cli_state *cli = NULL;   /* New connection */
        char           *myname = NULL;  /* Client name */
        struct passwd  *pwd;
        int flags = CLI_FULL_CONNECTION_USE_KERBEROS;
        bool use_kerberos = false;
        const char *user = username;
-       int cmp;
+       NTSTATUS nt_status;
 
        /*
          * Get the names and addresses of the client and server...
          */
        myname = get_myname(talloc_tos());
        if (!myname) {
-               return NULL;
+               return NT_STATUS_NO_MEMORY;
        }
 
 
-       cmp = strcmp(auth_info_required, "negotiate");
-       if (cmp == 0) {
+       if (strcmp(auth_info_required, "negotiate") == 0) {
                if (!kerberos_ccache_is_valid()) {
-                       return NULL;
+                       fprintf(stderr,
+                               "ERROR: No valid Kerberos credential cache "
+                               "found!\n");
+                       return NT_STATUS_LOGON_FAILURE;
                }
                user = jobusername;
 
                use_kerberos = true;
                fprintf(stderr,
                        "DEBUG: Try to connect using Kerberos ...\n");
-       }
-
-       cmp = strcmp(auth_info_required, "username,password");
-       if (cmp == 0) {
-               if (username == NULL || username[0] == '\0') {
-                       return NULL;
+       } else if (strcmp(auth_info_required, "username,password") == 0) {
+               if (username == NULL) {
+                       return NT_STATUS_INVALID_ACCOUNT_NAME;
                }
 
                /* Fallback to NTLM */
@@ -700,59 +716,83 @@ smb_connect(const char *workgroup,        /* I - Workgroup */
 
                fprintf(stderr,
                        "DEBUG: Try to connect using username/password ...\n");
-       }
+       } else {
+               if (username != NULL) {
+                       flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
+               } else if (kerberos_ccache_is_valid()) {
+                       auth_info_required = "negotiate";
 
-       cmp = strcmp(auth_info_required, "none");
-       if (cmp == 0) {
-               fprintf(stderr,
-                       "DEBUG: This backend doesn't support none auth ...\n");
-               return NULL;
+                       user = jobusername;
+                       use_kerberos = true;
+               } else {
+                       fprintf(stderr,
+                               "DEBUG: This backend requires credentials!\n");
+                       return NT_STATUS_ACCESS_DENIED;
+               }
        }
 
-       cli = smb_complete_connection(myname,
-                                     server,
-                                     port,
-                                     user,
-                                     password,
-                                     workgroup,
-                                     share,
-                                     flags,
-                                     need_auth);
-       if (cli != NULL) {
+       nt_status = smb_complete_connection(&cli,
+                                           myname,
+                                           server,
+                                           port,
+                                           user,
+                                           password,
+                                           workgroup,
+                                           share,
+                                           flags);
+       if (NT_STATUS_IS_OK(nt_status)) {
                fprintf(stderr, "DEBUG: SMB connection established.\n");
-               return (cli);
+
+               *output_cli = cli;
+               return NT_STATUS_OK;
        }
 
        if (!use_kerberos) {
                fprintf(stderr, "ERROR: SMB connection failed!\n");
-               return NULL;
+               return nt_status;
        }
 
        /* give a chance for a passwordless NTLMSSP session setup */
        pwd = getpwuid(geteuid());
        if (pwd == NULL) {
-               return NULL;
-       }
-
-       cli = smb_complete_connection(myname, server, port, pwd->pw_name, "",
-                                     workgroup, share, 0, need_auth);
-
-       if (cli) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       nt_status = smb_complete_connection(&cli,
+                                           myname,
+                                           server,
+                                           port,
+                                           pwd->pw_name,
+                                           "",
+                                           workgroup,
+                                           share,
+                                           0);
+       if (NT_STATUS_IS_OK(nt_status)) {
                fputs("DEBUG: Connected with NTLMSSP...\n", stderr);
-               return (cli);
+
+               *output_cli = cli;
+               return NT_STATUS_OK;
        }
 
        /*
          * last try. Use anonymous authentication
          */
 
-       cli = smb_complete_connection(myname, server, port, "", "",
-                                     workgroup, share, 0, need_auth);
-       /*
-         * Return the new connection...
-         */
-
-       return (cli);
+       nt_status = smb_complete_connection(&cli,
+                                           myname,
+                                           server,
+                                           port,
+                                           "",
+                                           "",
+                                           workgroup,
+                                           share,
+                                           0);
+       if (NT_STATUS_IS_OK(nt_status)) {
+               *output_cli = cli;
+               return NT_STATUS_OK;
+       }
+
+       return nt_status;
 }
 
 
@@ -798,7 +838,7 @@ smb_print(struct cli_state * cli,   /* I - SMB connection */
        if (!NT_STATUS_IS_OK(nt_status)) {
                fprintf(stderr, "ERROR: %s opening remote spool %s\n",
                        nt_errstr(nt_status), title);
-               return get_exit_code(cli, nt_status);
+               return get_exit_code(nt_status);
        }
 
        /*
@@ -816,7 +856,7 @@ smb_print(struct cli_state * cli,   /* I - SMB connection */
                status = cli_writeall(cli, fnum, 0, (uint8_t *)buffer,
                                      tbytes, nbytes, NULL);
                if (!NT_STATUS_IS_OK(status)) {
-                       int ret = get_exit_code(cli, status);
+                       int ret = get_exit_code(status);
                        fprintf(stderr, "ERROR: Error writing spool: %s\n",
                                nt_errstr(status));
                        fprintf(stderr, "DEBUG: Returning status %d...\n",
@@ -832,7 +872,7 @@ smb_print(struct cli_state * cli,   /* I - SMB connection */
        if (!NT_STATUS_IS_OK(nt_status)) {
                fprintf(stderr, "ERROR: %s closing remote spool %s\n",
                        nt_errstr(nt_status), title);
-               return get_exit_code(cli, nt_status);
+               return get_exit_code(nt_status);
        } else {
                return (0);
        }