summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Sweet <msweet@apple.com>2008-04-21 09:16:01 -0700
committerJames Peach <jpeach@apple.com>2008-04-21 09:16:01 -0700
commit7e166858c3c2094372f90239adba25711c4739a5 (patch)
tree0dd66087e1de117e3c9bca978c85c0e66167dd30
parent154f4837b3169ddf6c61f87b9d28c257f69d35bf (diff)
downloadsamba-7e166858c3c2094372f90239adba25711c4739a5.tar.gz
samba-7e166858c3c2094372f90239adba25711c4739a5.tar.bz2
samba-7e166858c3c2094372f90239adba25711c4739a5.zip
smbspool: fix Kerberos support for CUPS 1.3.
To summarize the changes, the patches remove the old (probably non- working) Kerberos support code which is unnecessary with CUPS 1.3 and adds some checks on the NT status we get back to see whether the connection error is related to authentication. If so, we send the ATTR: message to tell CUPS we need a username and password and return exit code 2 so cupsd will do the right thing. AUTH_USERNAME, AUTH_PASSWORD, and KRB5CCNAME are set and supported by CUPS 1.3. The new exit code is supported by CUPS 1.2.x and 1.3, and it treated as a general failure in CUPS 1.1. The ATTR: message is only supported by CUPS 1.3, while CUPS 1.2 will assume the "username,password" value we are setting. The current code only uses the AUTH_* env vars if they are set. If not, we fall back to the previous behavior. I really can't tell whether the Kerberos code that was in there would work at all. It did not work for Mac OS X which is why I dropped it. (This used to be commit 8c12c5cea01d9b801fe80c2a87b8139c488a62a5)
-rw-r--r--source3/client/smbspool.c231
1 files changed, 87 insertions, 144 deletions
diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c
index e827df4b09..a57cf49c5f 100644
--- a/source3/client/smbspool.c
+++ b/source3/client/smbspool.c
@@ -22,12 +22,24 @@
#include "includes.h"
-#define TICKET_CC_DIR "/tmp"
-#define CC_PREFIX "krb5cc_" /* prefix of the ticket cache */
-#define CC_MAX_FILE_LEN 24
-#define CC_MAX_FILE_PATH_LEN (sizeof(TICKET_CC_DIR)-1)+ CC_MAX_FILE_LEN+2
-#define OVERWRITE 1
-#define KRB5CCNAME "KRB5CCNAME"
+/*
+ Starting with CUPS 1.3, Kerberos support is provided by cupsd including
+ the forwarding of user credentials via the authenticated session between
+ user and server and the KRB5CCNAME environment variable which will point
+ to a temporary file or an in-memory representation depending on the version
+ of Kerberos you use. As a result, all of the ticket code that used to
+ live here has been removed, and we depend on the user session (if you
+ run smbspool by hand) or cupsd to provide the necessary Kerberos info.
+
+ Also, the AUTH_USERNAME and AUTH_PASSWORD environment variables provide
+ for per-job authentication for non-Kerberized printing. We use those
+ if there is no username and password specified in the device URI.
+
+ Finally, if we have an authentication failure we return exit code 2
+ which tells CUPS to hold the job for authentication and bug the user
+ to get the necessary credentials.
+*/
+
#define MAX_RETRY_CONNECT 3
@@ -42,8 +54,8 @@
*/
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);
-static struct cli_state *smb_connect(const char *, const char *, int, const char *, const char *, const char *, const char *);
+static struct cli_state *smb_complete_connection(const char *, const char *,int , const char *, const char *, const char *, const char *, int, int *need_auth);
+static struct cli_state *smb_connect(const char *, const char *, int, const char *, const char *, const char *, const char *, int *need_auth);
static int smb_print(struct cli_state *, char *, FILE *);
static char * uri_unescape_alloc(const char *);
#if 0
@@ -177,9 +189,13 @@ static bool smb_encrypt;
}
else
{
- username = null_str;
- password = null_str;
- server = uri + 6;
+ if ((username = getenv("AUTH_USERNAME")) == NULL)
+ username = null_str;
+
+ if ((password = getenv("AUTH_PASSWORD")) == NULL)
+ password = null_str;
+
+ server = uri + 6;
}
tmp = server;
@@ -244,12 +260,17 @@ static bool smb_encrypt;
do
{
- if ((cli = smb_connect(workgroup, server, port, printer, username, password, argv[2])) == NULL)
+ if ((cli = smb_connect(workgroup, server, port, printer, username, password, argv[2], &need_auth)) == NULL)
{
- if (getenv("CLASS") == NULL)
+ if (need_auth)
+ {
+ fputs("ATTR: auth-info-required=username,password\n", stderr);
+ exit(2);
+ }
+ else if (getenv("CLASS") == NULL)
{
fprintf(stderr, "ERROR: Unable to connect to CIFS host, will retry in 60 seconds...\n");
- sleep (60); /* should just waiting and retrying fix authentication ??? */
+ sleep(60);
tries++;
}
else
@@ -312,68 +333,6 @@ list_devices(void)
}
-/*
- * get the name of the newest ticket cache for the uid user.
- * pam_krb5 defines a non default ticket cache for each user
- */
-static
-char * get_ticket_cache( uid_t uid )
-{
- char *ticket_file = NULL;
- SMB_STRUCT_DIR *tcdir; /* directory where ticket caches are stored */
- SMB_STRUCT_DIRENT *dirent; /* directory entry */
- char *filename = NULL; /* holds file names on the tmp directory */
- SMB_STRUCT_STAT buf;
- char user_cache_prefix[CC_MAX_FILE_LEN];
- char file_path[CC_MAX_FILE_PATH_LEN];
- time_t t = 0;
-
- snprintf(user_cache_prefix, CC_MAX_FILE_LEN, "%s%d", CC_PREFIX, uid );
- tcdir = sys_opendir( TICKET_CC_DIR );
- if ( tcdir == NULL )
- return NULL;
-
- while ( (dirent = sys_readdir( tcdir ) ) )
- {
- filename = dirent->d_name;
- snprintf(file_path, CC_MAX_FILE_PATH_LEN,"%s/%s", TICKET_CC_DIR, filename);
- if (sys_stat(file_path, &buf) == 0 )
- {
- if ( ( buf.st_uid == uid ) && ( S_ISREG(buf.st_mode) ) )
- {
- /*
- * check the user id of the file to prevent denial of
- * service attacks by creating fake ticket caches for the
- * user
- */
- if ( strstr( filename, user_cache_prefix ) )
- {
- if ( buf.st_mtime > t )
- {
- /*
- * a newer ticket cache found
- */
- free(ticket_file);
- ticket_file=SMB_STRDUP(file_path);
- t = buf.st_mtime;
- }
- }
- }
- }
- }
-
- sys_closedir(tcdir);
-
- if ( ticket_file == NULL )
- {
- /* no ticket cache found */
- fprintf(stderr, "ERROR: No ticket cache found for userid=%d\n", uid);
- return NULL;
- }
-
- return ticket_file;
-}
-
static struct cli_state
*smb_complete_connection(const char *myname,
const char *server,
@@ -382,81 +341,54 @@ static struct cli_state
const char *password,
const char *workgroup,
const char *share,
- int flags)
+ int flags,
+ int *need_auth)
{
struct cli_state *cli; /* New connection */
NTSTATUS nt_status;
-
+ int i;
+ static const NTSTATUS auth_errors[] =
+ { /* List of NTSTATUS errors that are considered authentication errors */
+ NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCESS_VIOLATION,
+ NT_STATUS_SHARING_VIOLATION, NT_STATUS_PRIVILEGE_NOT_HELD,
+ NT_STATUS_INVALID_ACCOUNT_NAME, NT_STATUS_NO_SUCH_USER,
+ NT_STATUS_WRONG_PASSWORD, NT_STATUS_LOGON_FAILURE,
+ NT_STATUS_ACCOUNT_RESTRICTION, NT_STATUS_INVALID_LOGON_HOURS,
+ NT_STATUS_PASSWORD_EXPIRED, NT_STATUS_ACCOUNT_DISABLED
+ };
+
/* Start the SMB connection */
+ *need_auth = 0;
nt_status = cli_start_connection( &cli, myname, server, NULL, port,
Undefined, flags, NULL);
if (!NT_STATUS_IS_OK(nt_status))
{
+ fprintf(stderr,"ERROR: Connection failed: %s\n", nt_errstr(nt_status));
return NULL;
}
/* We pretty much guarentee password must be valid or a pointer
to a 0 char. */
if (!password) {
+ *need_auth = 1;
return NULL;
}
- if ( (username) && (*username) &&
- (strlen(password) == 0 ) &&
- (cli->use_kerberos) )
+ nt_status = cli_session_setup(cli, username,
+ password, strlen(password)+1,
+ password, strlen(password)+1,
+ workgroup);
+ if (!NT_STATUS_IS_OK(nt_status))
{
- /* Use kerberos authentication */
- struct passwd *pw;
- char *cache_file;
-
-
- if ( !(pw = sys_getpwnam(username)) ) {
- fprintf(stderr,"ERROR Can not get %s uid\n", username);
- cli_shutdown(cli);
- return NULL;
- }
-
- /*
- * Get the ticket cache of the user to set KRB5CCNAME env
- * variable
- */
- cache_file = get_ticket_cache( pw->pw_uid );
- if ( cache_file == NULL )
- {
- fprintf(stderr, "ERROR: Can not get the ticket cache for %s\n", username);
- cli_shutdown(cli);
- return NULL;
- }
-
- if ( setenv(KRB5CCNAME, cache_file, OVERWRITE) < 0 )
- {
- fprintf(stderr, "ERROR: Can not add KRB5CCNAME to the environment");
- cli_shutdown(cli);
- free(cache_file);
- return NULL;
- }
- free(cache_file);
+ fprintf(stderr,"ERROR: Session setup failed: %s\n", nt_errstr(nt_status));
- /*
- * Change the UID of the process to be able to read the kerberos
- * ticket cache
- */
- setuid(pw->pw_uid);
+ for (i = 0; i < (int)(sizeof(auth_errors) / sizeof(auth_errors[0])); i ++)
+ if (NT_STATUS_V(nt_status) == NT_STATUS_V(auth_errors[i]))
+ {
+ *need_auth = 1;
+ break;
+ }
- }
-
-
- if (!NT_STATUS_IS_OK(cli_session_setup(cli, username,
- password, strlen(password)+1,
- password, strlen(password)+1,
- workgroup)))
- {
- fprintf(stderr,"ERROR: Session setup failed: %s\n", cli_errstr(cli));
- if (NT_STATUS_V(cli_nt_error(cli)) ==
- NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
- {
- fprintf(stderr, "did you forget to run kinit?\n");
- }
cli_shutdown(cli);
return NULL;
@@ -465,7 +397,17 @@ static struct cli_state
if (!cli_send_tconX(cli, share, "?????", password, strlen(password)+1))
{
fprintf(stderr, "ERROR: Tree connect failed (%s)\n", cli_errstr(cli));
+ nt_status = cli_nt_error(cli);
+
+ for (i = 0; i < (int)(sizeof(auth_errors) / sizeof(auth_errors[0])); i ++)
+ if (NT_STATUS_V(nt_status) == NT_STATUS_V(auth_errors[i]))
+ {
+ *need_auth = 1;
+ break;
+ }
+
cli_shutdown(cli);
+
return NULL;
}
@@ -493,14 +435,15 @@ static struct cli_state
* 'smb_connect()' - Return a connection to a server.
*/
-static struct cli_state * /* O - SMB connection */
-smb_connect(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 */
+static struct cli_state * /* O - SMB connection */
+smb_connect(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 */
+ int *need_auth) /* O - Need authentication? */
{
struct cli_state *cli; /* New connection */
char *myname = NULL; /* Client name */
@@ -518,10 +461,10 @@ smb_connect(const char *workgroup, /* I - Workgroup */
/* See if we have a username first. This is for backwards compatible
behavior with 3.0.14a */
- if ( username && *username )
+ if (username && *username && !getenv("KRB5CCNAME"))
{
cli = smb_complete_connection(myname, server, port, username,
- password, workgroup, share, 0 );
+ password, workgroup, share, 0, need_auth);
if (cli)
return cli;
}
@@ -531,7 +474,7 @@ smb_connect(const char *workgroup, /* I - Workgroup */
*/
cli = smb_complete_connection(myname, server, port, jobusername, "",
workgroup, share,
- CLI_FULL_CONNECTION_USE_KERBEROS );
+ CLI_FULL_CONNECTION_USE_KERBEROS, need_auth);
if (cli ) { return cli; }
@@ -543,7 +486,7 @@ smb_connect(const char *workgroup, /* I - Workgroup */
}
cli = smb_complete_connection(myname, server, port, pwd->pw_name, "",
- workgroup, share, 0);
+ workgroup, share, 0, need_auth);
if (cli) { return cli; }
@@ -552,7 +495,7 @@ smb_connect(const char *workgroup, /* I - Workgroup */
*/
cli = smb_complete_connection(myname, server, port, "", "",
- workgroup, share, 0);
+ workgroup, share, 0, need_auth);
/*
* Return the new connection...
*/