From 3da5d7dec29ad16c745a2eb36c4f9601f833db3e Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 13 May 2019 16:55:49 +0200 Subject: [PATCH 01/10] s3:smbspool: Add the 'lp' group to the users groups This is required to access files in /var/spool/cups which have been temporarily created in there by CUPS. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit 6086efb6808089c431e7307fa239924bfda1185b) --- source3/client/smbspool_krb5_wrapper.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/source3/client/smbspool_krb5_wrapper.c b/source3/client/smbspool_krb5_wrapper.c index 5c4da33238b..e6684fc0d0c 100644 --- a/source3/client/smbspool_krb5_wrapper.c +++ b/source3/client/smbspool_krb5_wrapper.c @@ -82,6 +82,7 @@ int main(int argc, char *argv[]) { char smbspool_cmd[PATH_MAX] = {0}; struct passwd *pwd; + struct group *g = NULL; char gen_cc[PATH_MAX] = {0}; struct stat sb; char *env = NULL; @@ -89,6 +90,7 @@ int main(int argc, char *argv[]) char device_uri[4096] = {0}; uid_t uid = (uid_t)-1; gid_t gid = (gid_t)-1; + gid_t groups[1] = { (gid_t)-1 }; unsigned long tmp; int cmp; int rc; @@ -176,6 +178,26 @@ int main(int argc, char *argv[]) return CUPS_BACKEND_FAILED; } + /* + * We need the primary group of the 'lp' user. This is needed to access + * temporary files in /var/spool/cups/. + */ + g = getgrnam("lp"); + if (g == NULL) { + CUPS_SMB_ERROR("Failed to find user 'lp' - %s", + strerror(errno)); + return CUPS_BACKEND_FAILED; + } + + CUPS_SMB_DEBUG("Adding group 'lp' (%u)", g->gr_gid); + groups[0] = g->gr_gid; + rc = setgroups(sizeof(groups), groups); + if (rc != 0) { + CUPS_SMB_ERROR("Failed to set groups for 'lp' - %s", + strerror(errno)); + return CUPS_BACKEND_FAILED; + } + CUPS_SMB_DEBUG("Switching to gid=%d", gid); rc = setgid(gid); if (rc != 0) { -- 2.21.0 From 41c822a47a1a67cb14b14eac4a9f5eb034b8896f Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 16 May 2019 13:41:02 +0200 Subject: [PATCH 02/10] s3:smbspool: Print the principal we use to authenticate with BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit 42492d547661cb7a98c237b32d42ee93de35aba5) --- source3/client/smbspool.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c index c404b3a3f69..78c13b9ebdb 100644 --- a/source3/client/smbspool.c +++ b/source3/client/smbspool.c @@ -612,6 +612,7 @@ static bool kerberos_ccache_is_valid(void) { return false; } else { krb5_principal default_princ = NULL; + char *princ_name = NULL; code = krb5_cc_get_principal(ctx, ccache, @@ -621,6 +622,16 @@ static bool kerberos_ccache_is_valid(void) { krb5_free_context(ctx); return false; } + + code = krb5_unparse_name(ctx, + default_princ, + &princ_name); + if (code == 0) { + fprintf(stderr, + "DEBUG: Try to authenticate as %s\n", + princ_name); + krb5_free_unparsed_name(ctx, princ_name); + } krb5_free_principal(ctx, default_princ); } krb5_cc_close(ctx, ccache); -- 2.21.0 From 8d3f5baef114c3f0afd072a5ef9860b51a178f2b Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 16 May 2019 14:25:00 +0200 Subject: [PATCH 03/10] s3:smbspool: Add debug for finding KRB5CCNAME BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit 3632bfef25e471075886eb7aecddd4cc260db8ba) --- source3/client/smbspool_krb5_wrapper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/client/smbspool_krb5_wrapper.c b/source3/client/smbspool_krb5_wrapper.c index e6684fc0d0c..2cdcd372ec6 100644 --- a/source3/client/smbspool_krb5_wrapper.c +++ b/source3/client/smbspool_krb5_wrapper.c @@ -219,10 +219,14 @@ int main(int argc, char *argv[]) env = getenv("KRB5CCNAME"); if (env != NULL && env[0] != 0) { snprintf(gen_cc, sizeof(gen_cc), "%s", env); + CUPS_SMB_DEBUG("User already set KRB5CCNAME [%s] as ccache", + gen_cc); goto create_env; } + CUPS_SMB_DEBUG("Trying to guess KRB5CCNAME (FILE, DIR, KEYRING)"); + snprintf(gen_cc, sizeof(gen_cc), "/tmp/krb5cc_%d", uid); rc = lstat(gen_cc, &sb); -- 2.21.0 From 108f599143c81fa63f85a3c33c458c78e6a9265b Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 16 May 2019 17:10:57 +0200 Subject: [PATCH 04/10] s3:smbspool: Use %u format specifier to print uid BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit be596ce3d2455bd49a8ebd311d8c764c37852858) --- source3/client/smbspool_krb5_wrapper.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/client/smbspool_krb5_wrapper.c b/source3/client/smbspool_krb5_wrapper.c index 2cdcd372ec6..3266b90ec1a 100644 --- a/source3/client/smbspool_krb5_wrapper.c +++ b/source3/client/smbspool_krb5_wrapper.c @@ -227,13 +227,13 @@ int main(int argc, char *argv[]) CUPS_SMB_DEBUG("Trying to guess KRB5CCNAME (FILE, DIR, KEYRING)"); - snprintf(gen_cc, sizeof(gen_cc), "/tmp/krb5cc_%d", uid); + snprintf(gen_cc, sizeof(gen_cc), "/tmp/krb5cc_%u", uid); rc = lstat(gen_cc, &sb); if (rc == 0) { - snprintf(gen_cc, sizeof(gen_cc), "FILE:/tmp/krb5cc_%d", uid); + snprintf(gen_cc, sizeof(gen_cc), "FILE:/tmp/krb5cc_%u", uid); } else { - snprintf(gen_cc, sizeof(gen_cc), "/run/user/%d/krb5cc", uid); + snprintf(gen_cc, sizeof(gen_cc), "/run/user/%u/krb5cc", uid); rc = lstat(gen_cc, &sb); if (rc == 0 && S_ISDIR(sb.st_mode)) { -- 2.21.0 From 731ec2aba6ddfef24bf36727a19fe670afe4315c Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 16 May 2019 17:40:43 +0200 Subject: [PATCH 05/10] s3:smbspool: Fallback to default ccache if KRB5CCNAME is not set This could also support the new KCM credential cache storage. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit 6bbdf69e406916107400e2cabdbc831e2a2bbee3) --- source3/client/smbspool_krb5_wrapper.c | 79 ++++++++++++++++++-------- source3/wscript_build | 1 + 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/source3/client/smbspool_krb5_wrapper.c b/source3/client/smbspool_krb5_wrapper.c index 3266b90ec1a..bff1df417e8 100644 --- a/source3/client/smbspool_krb5_wrapper.c +++ b/source3/client/smbspool_krb5_wrapper.c @@ -21,6 +21,7 @@ #include "includes.h" #include "system/filesys.h" +#include "system/kerberos.h" #include "system/passwd.h" #include @@ -68,6 +69,50 @@ static void cups_smb_debug(enum cups_smb_dbglvl_e lvl, const char *format, ...) buffer); } +static bool kerberos_get_default_ccache(char *ccache_buf, size_t len) +{ + krb5_context ctx; + const char *ccache_name = NULL; + char *full_ccache_name = NULL; + krb5_ccache ccache = NULL; + krb5_error_code code; + + code = krb5_init_context(&ctx); + if (code != 0) { + return false; + } + + ccache_name = krb5_cc_default_name(ctx); + if (ccache_name == NULL) { + krb5_free_context(ctx); + return false; + } + + code = krb5_cc_resolve(ctx, ccache_name, &ccache); + if (code != 0) { + krb5_free_context(ctx); + return false; + } + + code = krb5_cc_get_full_name(ctx, ccache, &full_ccache_name); + krb5_cc_close(ctx, ccache); + if (code != 0) { + krb5_free_context(ctx); + return false; + } + + snprintf(ccache_buf, len, "%s", full_ccache_name); + +#ifdef SAMBA4_USES_HEIMDAL + free(full_ccache_name); +#else + krb5_free_string(ctx, full_ccache_name); +#endif + krb5_free_context(ctx); + + return true; +} + /* * This is a helper binary to execute smbspool. * @@ -84,7 +129,6 @@ int main(int argc, char *argv[]) struct passwd *pwd; struct group *g = NULL; char gen_cc[PATH_MAX] = {0}; - struct stat sb; char *env = NULL; char auth_info_required[256] = {0}; char device_uri[4096] = {0}; @@ -92,6 +136,7 @@ int main(int argc, char *argv[]) gid_t gid = (gid_t)-1; gid_t groups[1] = { (gid_t)-1 }; unsigned long tmp; + bool ok; int cmp; int rc; @@ -225,32 +270,16 @@ int main(int argc, char *argv[]) goto create_env; } - CUPS_SMB_DEBUG("Trying to guess KRB5CCNAME (FILE, DIR, KEYRING)"); - - snprintf(gen_cc, sizeof(gen_cc), "/tmp/krb5cc_%u", uid); - - rc = lstat(gen_cc, &sb); - if (rc == 0) { - snprintf(gen_cc, sizeof(gen_cc), "FILE:/tmp/krb5cc_%u", uid); - } else { - snprintf(gen_cc, sizeof(gen_cc), "/run/user/%u/krb5cc", uid); - - rc = lstat(gen_cc, &sb); - if (rc == 0 && S_ISDIR(sb.st_mode)) { - snprintf(gen_cc, - sizeof(gen_cc), - "DIR:/run/user/%d/krb5cc", - uid); - } else { -#if defined(__linux__) - snprintf(gen_cc, - sizeof(gen_cc), - "KEYRING:persistent:%d", - uid); -#endif - } + ok = kerberos_get_default_ccache(gen_cc, sizeof(gen_cc)); + if (ok) { + CUPS_SMB_DEBUG("Use default KRB5CCNAME [%s]", + gen_cc); + goto create_env; } + /* Fallback to a FILE ccache */ + snprintf(gen_cc, sizeof(gen_cc), "FILE:/tmp/krb5cc_%u", uid); + create_env: /* * Make sure we do not have LD_PRELOAD or other security relevant diff --git a/source3/wscript_build b/source3/wscript_build index 6be87ba8139..04701eb3026 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1136,6 +1136,7 @@ bld.SAMBA3_BINARY('smbspool_krb5_wrapper', deps=''' DYNCONFIG cups + krb5 ''', install_path='${LIBEXECDIR}/samba', enabled=bld.CONFIG_SET('HAVE_CUPS')) -- 2.21.0 From 379a1d8d6037b75294855a5c75f93bb6b47450ae Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 13 May 2019 16:48:31 +0200 Subject: [PATCH 06/10] s3:smbspool: Print the filename we failed to open BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit 281274572bcc3125fe6026a01ef7bf7ef584a0dd) --- source3/client/smbspool.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c index 78c13b9ebdb..805ad88b88d 100644 --- a/source3/client/smbspool.c +++ b/source3/client/smbspool.c @@ -223,7 +223,9 @@ main(int argc, /* I - Number of command-line arguments */ fp = fopen(print_file, "rb"); if (fp == NULL) { - perror("ERROR: Unable to open print file"); + fprintf(stderr, + "ERROR: Unable to open print file: %s", + print_file); goto done; } -- 2.21.0 From 4e20fac95595e2bd2b84f5cd5d4e09aa365321f2 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 13 May 2019 18:54:02 +0200 Subject: [PATCH 07/10] s3:smbspool: Always try to authenticate using Kerberos If username and password is given, then fallback to NTLM. However try kinit first. Also we correctly handle NULL passwords in the meantime and this makes it easier to deal with issues. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit 3d719a1f85db8e423dc3a4116a2228961d5ac48d) --- source3/client/smbspool.c | 90 ++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c index 805ad88b88d..d336cd08209 100644 --- a/source3/client/smbspool.c +++ b/source3/client/smbspool.c @@ -87,8 +87,8 @@ main(int argc, /* I - Number of command-line arguments */ int port; /* Port number */ char uri[1024], /* URI */ *sep, /* Pointer to separator */ - *tmp, *tmp2, /* Temp pointers to do escaping */ - *password; /* Password */ + *tmp, *tmp2; /* Temp pointers to do escaping */ + const char *password = NULL; /* Password */ char *username, /* Username */ *server, /* Server name */ *printer;/* Printer name */ @@ -292,8 +292,6 @@ main(int argc, /* I - Number of command-line arguments */ if ((tmp2 = strchr_m(tmp, ':')) != NULL) { *tmp2++ = '\0'; password = uri_unescape_alloc(tmp2); - } else { - password = empty_str; } username = uri_unescape_alloc(tmp); } else { @@ -301,14 +299,15 @@ main(int argc, /* I - Number of command-line arguments */ username = empty_str; } - if ((password = getenv("AUTH_PASSWORD")) == NULL) { - password = empty_str; + env = getenv("AUTH_PASSWORD"); + if (env != NULL && strlen(env) > 0) { + password = env; } server = uri + 6; } - if (password != empty_str) { + if (password != NULL) { auth_info_required = "username,password"; } @@ -513,6 +512,7 @@ smb_complete_connection(const char *myname, NTSTATUS nt_status; struct cli_credentials *creds = NULL; bool use_kerberos = false; + bool fallback_after_kerberos = false; /* Start the SMB connection */ *need_auth = false; @@ -523,27 +523,21 @@ smb_complete_connection(const char *myname, return NULL; } - /* - * We pretty much guarantee password must be valid or a pointer to a - * 0 char. - */ - if (!password) { - *need_auth = true; - return NULL; - } - if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) { - auth_info_required = "negotiate"; use_kerberos = true; } + if (flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) { + fallback_after_kerberos = true; + } + creds = cli_session_creds_init(cli, username, workgroup, NULL, /* realm */ password, use_kerberos, - false, /* fallback_after_kerberos */ + fallback_after_kerberos, false, /* use_ccache */ false); /* password_is_nt_hash */ if (creds == NULL) { @@ -659,6 +653,10 @@ smb_connect(const char *workgroup, /* I - Workgroup */ struct cli_state *cli; /* 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; /* * Get the names and addresses of the client and server... @@ -668,42 +666,56 @@ smb_connect(const char *workgroup, /* I - Workgroup */ return NULL; } - /* - * See if we have a username first. This is for backwards compatible - * behavior with 3.0.14a - */ - if (username == NULL || username[0] == '\0') { - if (kerberos_ccache_is_valid()) { - goto kerberos_auth; + cmp = strcmp(auth_info_required, "negotiate"); + if (cmp == 0) { + if (!kerberos_ccache_is_valid()) { + return NULL; } + 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; + } + + /* Fallback to NTLM */ + flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; + + fprintf(stderr, + "DEBUG: Try to connect using username/password ...\n"); + } + + cmp = strcmp(auth_info_required, "none"); + if (cmp == 0) { + fprintf(stderr, + "DEBUG: This backend doesn't support none auth ...\n"); + return NULL; } cli = smb_complete_connection(myname, server, port, - username, + user, password, workgroup, share, - 0, + flags, need_auth); if (cli != NULL) { - fputs("DEBUG: Connected with username/password...\n", stderr); + fprintf(stderr, "DEBUG: SMB connection established.\n"); return (cli); } -kerberos_auth: - /* - * Try to use the user kerberos credentials (if any) to authenticate - */ - cli = smb_complete_connection(myname, server, port, jobusername, "", - workgroup, share, - CLI_FULL_CONNECTION_USE_KERBEROS, need_auth); - - if (cli) { - fputs("DEBUG: Connected using Kerberos...\n", stderr); - return (cli); + if (!use_kerberos) { + fprintf(stderr, "ERROR: SMB connection failed!\n"); + return NULL; } /* give a chance for a passwordless NTLMSSP session setup */ -- 2.21.0 From bded194f8d4b484d3f31818809b2cd1282ddebe2 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 16 May 2019 18:24:32 +0200 Subject: [PATCH 08/10] s3:smbspool: Add debug messages to kerberos_ccache_is_valid() BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Guenther Deschner (cherry picked from commit 93acd880801524c5e621df7b5bf5ad650f93cec3) --- source3/client/smbspool.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c index d336cd08209..221c50af196 100644 --- a/source3/client/smbspool.c +++ b/source3/client/smbspool.c @@ -599,11 +599,15 @@ static bool kerberos_ccache_is_valid(void) { ccache_name = krb5_cc_default_name(ctx); if (ccache_name == NULL) { + DBG_ERR("Failed to get default ccache name\n"); + krb5_free_context(ctx); return false; } code = krb5_cc_resolve(ctx, ccache_name, &ccache); if (code != 0) { + DBG_ERR("Failed to resolve ccache name: %s\n", + ccache_name); krb5_free_context(ctx); return false; } else { @@ -614,6 +618,9 @@ static bool kerberos_ccache_is_valid(void) { ccache, &default_princ); if (code != 0) { + DBG_ERR("Failed to get default principal from " + "ccache: %s\n", + ccache_name); krb5_cc_close(ctx, ccache); krb5_free_context(ctx); return false; -- 2.21.0 From 730c09ba2b3c7d48be011f62b975f0a27ddda4b7 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 14 May 2019 11:35:46 +0200 Subject: [PATCH 09/10] s3:smbspool: Use NTSTATUS return codes 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 Reviewed-by: Guenther Deschner (cherry picked from commit d9af3dc02e98a3eb22441dfbdeddbaca0af078ea) --- source3/client/smbspool.c | 250 ++++++++++++++++++++++---------------- 1 file changed, 145 insertions(+), 105 deletions(-) diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c index 221c50af196..5ab286cd3e9 100644 --- a/source3/client/smbspool.c +++ b/source3/client/smbspool.c @@ -60,12 +60,27 @@ * 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 @@ -89,16 +104,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; @@ -295,8 +309,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"); @@ -368,27 +383,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); @@ -435,10 +462,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 @@ -454,17 +480,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... @@ -497,16 +522,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; @@ -515,12 +540,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) { @@ -543,20 +567,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); @@ -564,13 +584,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. */ @@ -583,7 +599,8 @@ smb_complete_connection(const char *myname, } #endif - return cli; + *output_cli = cli; + return NT_STATUS_OK; } static bool kerberos_ccache_is_valid(void) { @@ -647,49 +664,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 */ @@ -697,59 +713,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; } @@ -795,7 +835,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); } /* @@ -813,7 +853,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", @@ -829,7 +869,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); } -- 2.21.0 From 6dcb3a69308732989e939798f6f29c50af3f2a98 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 18 Jun 2019 14:43:50 +0200 Subject: [PATCH 10/10] s3:client: Link smbspool_krb5_wrapper against krb5samba Heimdal doesn't provide krb5_free_unparsed_name(), so we need to use the function we provide in krb5samba. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13939 Signed-off-by: Andreas Schneider Reviewed-by: Ralph Boehme (cherry picked from commit 9268919e046190c7b423133de3f9d0edada3f1b8) --- source3/wscript_build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/wscript_build b/source3/wscript_build index 04701eb3026..8a0371611ab 100644 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -1136,7 +1136,7 @@ bld.SAMBA3_BINARY('smbspool_krb5_wrapper', deps=''' DYNCONFIG cups - krb5 + krb5samba ''', install_path='${LIBEXECDIR}/samba', enabled=bld.CONFIG_SET('HAVE_CUPS')) -- 2.21.0