]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Kerberos fixes for Mac OS X (STR #2045).
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Mon, 23 Oct 2006 00:11:55 +0000 (00:11 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Mon, 23 Oct 2006 00:11:55 +0000 (00:11 +0000)
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

12 files changed:
cgi-bin/Makefile
config-scripts/cups-gssapi.m4
config.h.in
cups/auth.c
cups/http-support.c
cups/http.c
scheduler/Makefile
scheduler/auth.c
scheduler/conf.c
scheduler/conf.h
scheduler/ipp.c
scheduler/main.c

index 7fb8a24eba5c0e3067868d39980ed7f314c038b9..d7c5709c424ae490a5d60b58ae433a5485163cee 100644 (file)
@@ -139,7 +139,7 @@ printers.cgi:       printers.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a
 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)
 
 
 #
@@ -149,7 +149,7 @@ testcgi:    testcgi.o ../Makedefs libcgi.a ../cups/libcups.a
 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)
 
 
 #
@@ -159,7 +159,7 @@ testhi:     testhi.o ../Makedefs libcgi.a ../cups/libcups.a
 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)
 
 
 #
index 8a78ddbd462b64ea6dba4bfaaa5512640ac1e13c..07c52783639d59f2b103e7f33b152cde678db470 100644 (file)
@@ -82,7 +82,23 @@ if test x$enable_gssapi != xno; then
        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$".
index b5bb16e828565a0f393f1667ed9729cb7b4a599f..8fd160f5473d6cd2d3f15e6207946e0c40aeb9a1 100644 (file)
 #undef HAVE_HEIMDAL
 
 
+/*
+ * Default GSS service name...
+ */
+
+#define CUPS_DEFAULT_GSSSERVICENAME    ""
+
+
 #endif /* !_CUPS_CONFIG_H_ */
 
 /*
index 62231885107a6935a9ef2e94b18f24aa94adecbd..3ec00446b68ea5de5674c2b8f8b2694f98309086 100644 (file)
@@ -168,9 +168,49 @@ cupsDoAuthentication(http_t     *http,     /* I - HTTP connection to server */
                                        /* 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,
@@ -179,6 +219,9 @@ cupsDoAuthentication(http_t     *http,      /* I - HTTP connection to server */
                                         &input_token, &http->gssmech,
                                         &output_token, NULL, NULL);
 
+    if (input_token.value)
+      free(input_token.value);
+
     if (GSS_ERROR(major_status))
     {
 #  ifdef DEBUG
@@ -193,11 +236,16 @@ cupsDoAuthentication(http_t     *http,    /* I - HTTP connection to server */
       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...
@@ -310,18 +358,12 @@ cups_get_gss_creds(
           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
index 456800e791f9680a1e18b90f719ef9534797383c..0f9ef2e9e562c35d2e1b319fdcc0a609cba09f18 100644 (file)
@@ -595,8 +595,14 @@ httpEncode64_2(char       *out,            /* I - String to write to */
 
     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 --;
@@ -610,7 +616,12 @@ httpEncode64_2(char       *out,            /* I - String to write to */
     }
 
     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 --;
index f32eb36996e50823efac0f94c88a6763d1e5037d..222a4ba666d333f5c69a53821abc1ffb822bfe40 100644 (file)
@@ -248,6 +248,12 @@ httpClearFields(http_t *http)              /* I - HTTP connection */
 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)
@@ -272,6 +278,15 @@ httpClose(http_t *http)                    /* I - HTTP connection */
   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)
@@ -350,6 +365,11 @@ httpConnectEncrypt(
   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...
   */
@@ -2270,6 +2290,20 @@ http_send(http_t       *http,    /* I - HTTP connection */
   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);
 }
 
@@ -2504,6 +2538,7 @@ http_upgrade(http_t *http)                /* I - HTTP connection */
   */
 
   memcpy(&myhttp, http, sizeof(myhttp));
+  myhttp.field_authorization = NULL;
 
  /*
   * Send an OPTIONS request to the server, requiring SSL or TLS
index 20b281cc3a28acc4fe2a2dee7bf9c095c3d82b79..63e921dbf7370851b2c44dd82ac846ed7b7175ef 100644 (file)
@@ -261,7 +261,7 @@ testdirsvc: testdirsvc.o
 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)
 
 
 #
@@ -271,7 +271,7 @@ testlpd:    testlpd.o ../cups/libcups.a cups-lpd
 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)
 
 
 #
@@ -281,7 +281,7 @@ testmime:   testmime.o libmime.a ../cups/libcups.a
 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)
 
 
 #
@@ -291,7 +291,7 @@ testspeed:  testspeed.o ../cups/libcups.a
 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)
 
 
 #
index 80596eacf9e3f72b32390901a16affe9a1c44094..6caaae581bc335b2969564a3195223f62cf4aacd 100644 (file)
@@ -783,7 +783,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
     */
 
     authorization += 9;
-    while (*authorization && isspace(*authorization & 255))
+    while (isspace(*authorization & 255))
       authorization ++;
 
     if (!*authorization)
@@ -797,7 +797,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */
     * 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;  
@@ -836,6 +836,10 @@ cupsdAuthorize(cupsd_client_t *con)        /* I - Client connection */
       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;
     }
@@ -848,19 +852,22 @@ cupsdAuthorize(cupsd_client_t *con)       /* I - Client connection */
     {
       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);
@@ -1736,9 +1743,11 @@ cupsdIsAuthorized(cupsd_client_t *con,   /* I - Connection */
   * 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...");
@@ -2128,7 +2137,7 @@ get_gss_creds(const char *service_name)   /* I - Service name */
           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,
index 6aa0b916cee12bfc696e67b2df0b925cde2b461b..27399975d45b33c20b6c22f0b26bf0f3600e28a3 100644 (file)
@@ -117,7 +117,9 @@ static cupsd_var_t  variables[] =
   { "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 },
@@ -288,6 +290,9 @@ cupsdReadConfiguration(void)
   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;
@@ -1706,7 +1711,8 @@ parse_aaa(cupsd_location_t *loc,  /* I - Location */
        loc->level = AUTH_USER;
     }
 #ifdef HAVE_GSSAPI
-    else if (!strcasecmp(value, "kerberos"))
+    else if (!strcasecmp(value, "kerberos") ||
+            !strcasecmp(value, "gssapi"))
     {
       loc->type = AUTH_KERBEROS;
 
index 78e4da8c2f07d8e2f7a86cba2a629b610330ab46..d6b2f9250fe11ad8a4ffc86401ec8198772edfdb 100644 (file)
@@ -112,6 +112,8 @@ VAR char            *AccessLog              VALUE(NULL),
                        *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 */
index 2779758144000b787b221b1d335e310ae98d7daa..a711cbfb1c2bcc31c5725b563d4a7fa0d9d7de9f 100644 (file)
@@ -7576,6 +7576,7 @@ static void
 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 */
@@ -7616,6 +7617,7 @@ save_krb5_creds(cupsd_client_t *con,      /* I - Client connection */
   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 */
 
index c4d269a9a48a93fca5e20d28176a6f93a8049e82..066d6e102caa92619b2d8d05a8d69042650ce5ab 100644 (file)
@@ -357,8 +357,8 @@ main(int  argc,                             /* I - Number of command-line args */
 
   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;