config-scripts/cups-gssapi.m4:
config.h.in:
scheduler/conf.c:
scheduler/conf.h:
- Support configurable kerberos service name, default is "IPP".
cups/http.c:
- httpConnectEncrypt(): Initialize the gss context and name.
- httpClose(): Free the gss context and name.
- http_send(): Clear the kerberos authentication string since
it can only be sent once.
- http_upgrade(): Clear the copy of the field_authorization
pointer to avoid a double free later.
cups/http-support.c:
- httpEncode64_2(): Could reference a byte beyond the end of
the input string.
cups/auth.c:
- cupsDoAuthentication(): Support a configurable kerberos
service name, clear gsssec context to avoid kerberos
"request is a replay" errors, free allocated input_token
and output_token, fix token length, and don't memset
'token' since it's only a pointer.
scheduler/auth.c:
- cupsdAuthorize(): Support configurable kerberos service
name and free gss context and name in the right places.
- cupsdIsAuthorized(): Don't require TLS upgrade when using
Kerberos, and fix token length.
scheduler/ipp.c:
- save_krb5_creds(): Doesn't yet work on Mac OS X.
scheduler/main.c:
- main(): Limit MaxFDs to FD_SETSIZE (from 1.2 branch).
git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@6055
7a7537e8-13f0-0310-91df-
b6672ffda945
testcgi: testcgi.o ../Makedefs libcgi.a ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o $@ testcgi.o libcgi.a ../cups/libcups.a \
- $(COMMONLIBS) $(SSLLIBS) $(LIBZ)
+ $(COMMONLIBS) $(SSLLIBS) $(LIBZ) $(LIBGSSAPI)
#
testhi: testhi.o ../Makedefs libcgi.a ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o $@ testhi.o libcgi.a ../cups/libcups.a \
- $(COMMONLIBS) $(SSLLIBS) $(LIBZ)
+ $(COMMONLIBS) $(SSLLIBS) $(LIBZ) $(LIBGSSAPI)
#
testtemplate: testtemplate.o ../Makedefs libcgi.a ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o $@ testtemplate.o libcgi.a ../cups/libcups.a \
- $(COMMONLIBS) $(SSLLIBS) $(LIBZ)
+ $(COMMONLIBS) $(SSLLIBS) $(LIBZ) $(LIBGSSAPI)
#
fi
fi
+dnl Default GSS service name...
+AC_ARG_WITH(gssservicename, [ --with-gssservicename set default gss service name],
+ default_gssservicename="$withval",
+ default_gssservicename="default")
+
+if test x$default_gssservicename != xno; then
+ if test "x$default_gssservicename" = "xdefault"; then
+ CUPS_DEFAULT_GSSSERVICENAME="IPP"
+ else
+ CUPS_DEFAULT_GSSSERVICENAME="$default_gssservicename"
+ fi
+else
+ CUPS_DEFAULT_GSSSERVICENAME=""
+fi
+
AC_SUBST(LIBGSSAPI)
+AC_DEFINE_UNQUOTED(CUPS_DEFAULT_GSSSERVICENAME, "$CUPS_DEFAULT_GSSSERVICENAME")
dnl
dnl End of "$Id$".
#undef HAVE_HEIMDAL
+/*
+ * Default GSS service name...
+ */
+
+#define CUPS_DEFAULT_GSSSERVICENAME ""
+
+
#endif /* !_CUPS_CONFIG_H_ */
/*
/* Output token */
input_token = GSS_C_EMPTY_BUFFER;
/* Input token */
+ char *gss_service_name;
+ /* GSS service name */
+ const char *authorization;
+ /* Pointer into Authorization string */
- http->gssname = cups_get_gss_creds(http, "HTTP");
+ if (http->gssname == GSS_C_NO_NAME)
+ {
+ if ((gss_service_name = getenv("CUPS_GSSSERVICENAME")) == NULL)
+ gss_service_name = CUPS_DEFAULT_GSSSERVICENAME;
+ else
+ DEBUG_puts("cupsDoAuthentication: GSS service name set via environment");
+
+ http->gssname = cups_get_gss_creds(http, gss_service_name);
+ }
+
+ /*
+ * Find the start of the Kerberos input token...
+ */
+
+ authorization = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE);
+
+ authorization += 9;
+ while (*authorization && isspace(*authorization & 255))
+ authorization ++;
+
+ if (*authorization)
+ {
+ /*
+ * For SPNEGO, this is where we'll feed the server's authorization data
+ * back into gss via input_token...
+ */
+ }
+ else
+ {
+ if (http->gssctx != GSS_C_NO_CONTEXT)
+ {
+ major_status = gss_delete_sec_context(&minor_status, &http->gssctx,
+ GSS_C_NO_BUFFER);
+ http->gssctx = GSS_C_NO_CONTEXT;
+ }
+ }
+
major_status = gss_init_sec_context(&minor_status, GSS_C_NO_CREDENTIAL,
&http->gssctx,
http->gssname, http->gssmech,
&input_token, &http->gssmech,
&output_token, NULL, NULL);
+ if (input_token.value)
+ free(input_token.value);
+
if (GSS_ERROR(major_status))
{
# ifdef DEBUG
DEBUG_gss_printf(major_status, minor_status, "Continuation needed!");
# endif /* DEBUG */
- httpEncode64_2(encode, sizeof(encode), output_token.value,
- output_token.length);
+ if (output_token.length)
+ {
+ httpEncode64_2(encode, sizeof(encode), output_token.value,
+ output_token.length);
- http->authstring = malloc(strlen(encode) + 20);
- sprintf(http->authstring, "Negotiate %s", encode); /* Safe because allocated */
+ http->authstring = malloc(strlen(encode) + 11);
+ sprintf(http->authstring, "Negotiate %s", encode); /* Safe because allocated */
+
+ major_status = gss_release_buffer(&minor_status, &output_token);
+ }
/*
* Copy back what we can to _authstring for backwards compatibility...
httpGetHostname(http, fqdn, sizeof(fqdn)));
token.value = buf;
- token.length = strlen(buf) + 1;
+ token.length = strlen(buf);
server_name = GSS_C_NO_NAME;
major_status = gss_import_name(&minor_status, &token,
GSS_C_NT_HOSTBASED_SERVICE,
&server_name);
- /*
- * Clear the service token after we are done to avoid exposing information...
- */
-
- memset(&token, 0, sizeof(token));
-
if (GSS_ERROR(major_status))
{
# ifdef DEBUG
if (outptr < outend)
*outptr ++ = base64[(in[0] & 255) >> 2];
+
if (outptr < outend)
- *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
+ {
+ if (inlen > 1)
+ *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
+ else
+ *outptr ++ = base64[((in[0] & 255) << 4) & 63];
+ }
in ++;
inlen --;
}
if (outptr < outend)
- *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
+ {
+ if (inlen > 1)
+ *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
+ else
+ *outptr ++ = base64[((in[0] & 255) << 2) & 63];
+ }
in ++;
inlen --;
void
httpClose(http_t *http) /* I - HTTP connection */
{
+#ifdef HAVE_GSSAPI
+ OM_uint32 minor_status, /* Minor status code */
+ major_status; /* Major status code */
+#endif /* HAVE_GSSAPI */
+
+
DEBUG_printf(("httpClose(http=%p)\n", http));
if (!http)
close(http->fd);
#endif /* WIN32 */
+#ifdef HAVE_GSSAPI
+ if (http->gssctx != GSS_C_NO_CONTEXT)
+ major_status = gss_delete_sec_context(&minor_status, &http->gssctx,
+ GSS_C_NO_BUFFER);
+
+ if (http->gssname != GSS_C_NO_NAME)
+ major_status = gss_release_name(&minor_status, &http->gssname);
+#endif /* HAVE_GSSAPI */
+
httpClearFields(http);
if (http->authstring && http->authstring != http->_authstring)
http->activity = time(NULL);
http->fd = -1;
+#ifdef HAVE_GSSAPI
+ http->gssctx = GSS_C_NO_CONTEXT;
+ http->gssname = GSS_C_NO_NAME;
+#endif /* HAVE_GSSAPI */
+
/*
* Set the encryption status...
*/
httpGetLength2(http);
httpClearFields(http);
+ /*
+ * The Kerberos authentication string can only be used once...
+ */
+
+ if (http->authstring && !strncmp(http->authstring, "Negotiate", 9))
+ {
+ http->_authstring[0] = '\0';
+
+ if (http->authstring != http->_authstring)
+ free(http->authstring);
+
+ http->authstring = http->_authstring;
+ }
+
return (0);
}
*/
memcpy(&myhttp, http, sizeof(myhttp));
+ myhttp.field_authorization = NULL;
/*
* Send an OPTIONS request to the server, requiring SSL or TLS
testlpd: testlpd.o ../cups/libcups.a cups-lpd
echo Linking $@...
$(CC) $(LDFLAGS) -o testlpd testlpd.o ../cups/libcups.a \
- $(COMMONLIBS) $(LIBZ) $(SSLLIBS)
+ $(COMMONLIBS) $(LIBZ) $(SSLLIBS) $(LIBGSSAPI)
#
testmime: testmime.o libmime.a ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o $@ testmime.o libmime.a ../cups/libcups.a \
- $(COMMONLIBS) $(LIBZ) $(SSLLIBS)
+ $(COMMONLIBS) $(LIBZ) $(SSLLIBS) $(LIBGSSAPI)
#
testspeed: testspeed.o ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o testspeed testspeed.o ../cups/libcups.a \
- $(LIBGSSAPI) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI)
#
testsub: testsub.o ../cups/libcups.a
echo Linking $@...
$(CC) $(LDFLAGS) -o testsub testsub.o ../cups/libcups.a \
- $(LIBGSSAPI) $(SSLLIBS) $(COMMONLIBS) $(LIBZ)
+ $(SSLLIBS) $(COMMONLIBS) $(LIBZ) $(LIBGSSAPI)
#
*/
authorization += 9;
- while (*authorization && isspace(*authorization & 255))
+ while (isspace(*authorization & 255))
authorization ++;
if (!*authorization)
* Get the server credentials...
*/
- if ((server_creds = get_gss_creds("HTTP")) == NULL)
+ if ((server_creds = get_gss_creds(GSSServiceName)) == NULL)
{
con->no_negotiate = 1;
return;
cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
"cupsdAuthorize: Error accepting GSSAPI security "
"context");
+
+ if (context != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
+
con->no_negotiate = 1;
return;
}
{
major_status = gss_display_name(&minor_status, client_name,
&output_token, NULL);
- gss_release_name(&minor_status, &client_name);
if (GSS_ERROR(major_status))
{
cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
"cupsdAuthorize: Error getting username");
+ gss_release_name(&minor_status, &client_name);
+ gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
con->no_negotiate = 1;
return;
}
+ gss_release_name(&minor_status, &client_name);
strlcpy(username, output_token.value, sizeof(username));
gss_release_buffer(&minor_status, &output_token);
+ gss_delete_sec_context(&minor_status, &context, GSS_C_NO_BUFFER);
}
else
gss_release_name(&minor_status, &client_name);
* See if encryption is required...
*/
- if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
+ if ((best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls &&
strcasecmp(con->http.hostname, "localhost") &&
- best->satisfy == AUTH_SATISFY_ALL)
+ best->satisfy == AUTH_SATISFY_ALL) &&
+ !(best->type == AUTH_KERBEROS ||
+ (best->type == AUTH_NONE && DefaultAuthType == AUTH_KERBEROS)))
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdIsAuthorized: Need upgrade to TLS...");
httpGetHostname(NULL, fqdn, sizeof(fqdn)));
token.value = buf;
- token.length = strlen(buf) + 1;
+ token.length = strlen(buf);
server_name = GSS_C_NO_NAME;
major_status = gss_import_name(&minor_status, &token,
GSS_C_NT_HOSTBASED_SERVICE,
{ "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER },
{ "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER },
{ "FontPath", &FontPath, CUPSD_VARTYPE_STRING },
- { "HideImplicitMembers", &HideImplicitMembers, CUPSD_VARTYPE_BOOLEAN },
+#ifdef HAVE_GSSAPI
+ { "GSSServiceName", &GSSServiceName, CUPSD_VARTYPE_STRING },
+#endif /* HAVE_GSSAPI */
{ "ImplicitClasses", &ImplicitClasses, CUPSD_VARTYPE_BOOLEAN },
{ "ImplicitAnyClasses", &ImplicitAnyClasses, CUPSD_VARTYPE_BOOLEAN },
{ "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER },
cupsdSetString(&RemoteRoot, "remroot");
cupsdSetString(&ServerHeader, "CUPS/1.2");
cupsdSetString(&StateDir, CUPS_STATEDIR);
+#ifdef HAVE_GSSAPI
+ cupsdSetString(&GSSServiceName, CUPS_DEFAULT_GSSSERVICENAME);
+#endif /* HAVE_GSSAPI */
if (!strcmp(CUPS_DEFAULT_PRINTCAP, "/etc/printers.conf"))
PrintcapFormat = PRINTCAP_SOLARIS;
loc->level = AUTH_USER;
}
#ifdef HAVE_GSSAPI
- else if (!strcasecmp(value, "kerberos"))
+ else if (!strcasecmp(value, "kerberos") ||
+ !strcasecmp(value, "gssapi"))
{
loc->type = AUTH_KERBEROS;
*Classification VALUE(NULL);
/* Classification of system */
#ifdef HAVE_GSSAPI
+VAR char *GSSServiceName VALUE(NULL);
+ /* GSS service name */
VAR char *Krb5Keytab VALUE(NULL);
/* Kerberos Keytab */
#endif /* HAVE_GSSAPI */
save_krb5_creds(cupsd_client_t *con, /* I - Client connection */
cupsd_job_t *job) /* I - Job */
{
+# ifndef __APPLE__
krb5_context krb_context; /* Kerberos context */
krb5_ccache ccache; /* Credentials cache */
OM_uint32 major_status, /* Major status code */
cupsdSetStringf(&(job->ccname), "KRB5CCNAME=FILE:%s",
krb5_cc_get_name(krb_context, ccache));
krb5_cc_close(krb_context, ccache);
+# endif /* !__APPLE__
}
#endif /* HAVE_GSSAPI && HAVE_KRB5_H */
getrlimit(RLIMIT_NOFILE, &limit);
- if (limit.rlim_max > CUPS_MAX_FDS)
- MaxFDs = CUPS_MAX_FDS;
+ if (limit.rlim_max > FD_SETSIZE)
+ MaxFDs = FD_SETSIZE;
else
MaxFDs = limit.rlim_max;