]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/auth/negotiate/kerberos/negotiate_kerberos_auth.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / auth / negotiate / kerberos / negotiate_kerberos_auth.cc
index 61775d2d81db3814594e8780e29a90d6d4c4f5c1..4cce9264f4dae84e6a6ae198ee86bb7698351255 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -54,7 +54,9 @@ typedef struct _krb5_kt_list {
     struct _krb5_kt_list *next;
     krb5_keytab_entry *entry;
 } *krb5_kt_list;
-krb5_kt_list ktlist = NULL;
+krb5_kt_list ktlist = nullptr;
+
+krb5_keytab memory_keytab;
 
 krb5_error_code krb5_free_kt_list(krb5_context context, krb5_kt_list kt_list);
 krb5_error_code krb5_write_keytab(krb5_context context,
@@ -92,7 +94,7 @@ gethost_name(void)
      * char hostname[sysconf(_SC_HOST_NAME_MAX)];
      */
     char hostname[1024];
-    struct addrinfo *hres = NULL, *hres_list;
+    struct addrinfo *hres = nullptr, *hres_list;
     int rc, count;
 
     rc = gethostname(hostname, sizeof(hostname)-1);
@@ -100,16 +102,16 @@ gethost_name(void)
         debug((char *) "%s| %s: ERROR: resolving hostname '%s' failed\n", LogTime(), PROGRAM, hostname);
         fprintf(stderr, "%s| %s: ERROR: resolving hostname '%s' failed\n",
                 LogTime(), PROGRAM, hostname);
-        return NULL;
+        return nullptr;
     }
-    rc = getaddrinfo(hostname, NULL, NULL, &hres);
-    if (rc != 0 || hres == NULL ) {
+    rc = getaddrinfo(hostname, nullptr, nullptr, &hres);
+    if (rc != 0 || hres == nullptr ) {
         debug((char *) "%s| %s: ERROR: resolving hostname with getaddrinfo: %s failed\n",
               LogTime(), PROGRAM, gai_strerror(rc));
         fprintf(stderr,
                 "%s| %s: ERROR: resolving hostname with getaddrinfo: %s failed\n",
                 LogTime(), PROGRAM, gai_strerror(rc));
-        return NULL;
+        return nullptr;
     }
     hres_list = hres;
     count = 0;
@@ -118,7 +120,7 @@ gethost_name(void)
         hres_list = hres_list->ai_next;
     }
     rc = getnameinfo(hres->ai_addr, hres->ai_addrlen, hostname,
-                     sizeof(hostname), NULL, 0, 0);
+                     sizeof(hostname), nullptr, 0, 0);
     if (rc != 0) {
         debug((char *) "%s| %s: ERROR: resolving ip address with getnameinfo: %s failed\n",
               LogTime(), PROGRAM, gai_strerror(rc));
@@ -126,7 +128,7 @@ gethost_name(void)
                 "%s| %s: ERROR: resolving ip address with getnameinfo: %s failed\n",
                 LogTime(), PROGRAM, gai_strerror(rc));
         freeaddrinfo(hres);
-        return NULL;
+        return nullptr;
     }
     freeaddrinfo(hres);
     hostname[sizeof(hostname)-1] = '\0';
@@ -217,7 +219,7 @@ krb5_error_code krb5_free_kt_list(krb5_context context, krb5_kt_list list)
  */
 krb5_error_code krb5_read_keytab(krb5_context context, char *name, krb5_kt_list *list)
 {
-    krb5_kt_list lp = NULL, tail = NULL, back = NULL;
+    krb5_kt_list lp = nullptr, tail = nullptr, back = nullptr;
     krb5_keytab kt;
     krb5_keytab_entry *entry;
     krb5_kt_cursor cursor;
@@ -273,7 +275,7 @@ krb5_error_code krb5_read_keytab(krb5_context context, char *name, krb5_kt_list
         }
         if (!tail)
             tail = lp;
-        lp->next = NULL;
+        lp->next = nullptr;
         lp->entry = entry;
     }
     xfree(entry);
@@ -282,9 +284,9 @@ krb5_error_code krb5_read_keytab(krb5_context context, char *name, krb5_kt_list
             retval = 0;
         else {
             krb5_free_kt_list(context, tail);
-            tail = NULL;
+            tail = nullptr;
             if (back)
-                back->next = NULL;
+                back->next = nullptr;
         }
     }
     if (!*list)
@@ -300,16 +302,15 @@ close_kt:
  */
 krb5_error_code krb5_write_keytab(krb5_context context, krb5_kt_list list, char *name)
 {
-    krb5_keytab kt;
     char ktname[MAXPATHLEN+sizeof("MEMORY:")+1];
     krb5_error_code retval = 0;
 
     snprintf(ktname, sizeof(ktname), "%s", name);
-    retval = krb5_kt_resolve(context, ktname, &kt);
+    retval = krb5_kt_resolve(context, ktname, &memory_keytab);
     if (retval)
         return retval;
     for (krb5_kt_list lp = list; lp; lp = lp->next) {
-        retval = krb5_kt_add_entry(context, kt, lp->entry);
+        retval = krb5_kt_add_entry(context, memory_keytab, lp->entry);
         if (retval)
             break;
     }
@@ -325,11 +326,11 @@ main(int argc, char *const argv[])
 {
     char buf[MAX_AUTHTOKEN_LEN];
     char *c, *p;
-    char *user = NULL;
-    char *rfc_user = NULL;
+    char *user = nullptr;
+    char *rfc_user = nullptr;
 #if HAVE_PAC_SUPPORT
     char ad_groups[MAX_PAC_GROUP_SIZE];
-    char *ag=NULL;
+    char *ag=nullptr;
     krb5_pac pac;
 #if USE_HEIMDAL_KRB5
     gss_buffer_desc data_set = GSS_C_EMPTY_BUFFER;
@@ -337,25 +338,26 @@ main(int argc, char *const argv[])
     gss_buffer_desc type_id = GSS_C_EMPTY_BUFFER;
 #endif
 #endif
-    krb5_context context = NULL;
+    krb5_context context = nullptr;
     krb5_error_code ret;
     long length = 0;
     static int err = 0;
     int opt, log = 0, norealm = 0;
     OM_uint32 ret_flags = 0, spnego_flag = 0;
-    char *service_name = (char *) "HTTP", *host_name = NULL;
-    char *token = NULL;
-    char *service_principal = NULL;
-    char *keytab_name = NULL;
-    char *keytab_name_env = NULL;
-    char default_keytab[MAXPATHLEN];
+    char *service_name = (char *) "HTTP", *host_name = nullptr;
+    char *token = nullptr;
+    char *service_principal = nullptr;
+    char *keytab_name = nullptr;
+    char *keytab_name_env = nullptr;
+    char default_keytab[MAXPATHLEN] = {};
 #if HAVE_KRB5_MEMORY_KEYTAB
-    char *memory_keytab_name = NULL;
+    char *memory_keytab_name = nullptr;
+    char *memory_keytab_name_env = nullptr;
 #endif
-    char *rcache_type = NULL;
-    char *rcache_type_env = NULL;
-    char *rcache_dir = NULL;
-    char *rcache_dir_env = NULL;
+    char *rcache_type = nullptr;
+    char *rcache_type_env = nullptr;
+    char *rcache_dir = nullptr;
+    char *rcache_dir_env = nullptr;
     OM_uint32 major_status, minor_status;
     gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
     gss_name_t client_name = GSS_C_NO_NAME;
@@ -364,12 +366,12 @@ main(int argc, char *const argv[])
     gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
     gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
-    const unsigned char *kerberosToken = NULL;
-    const unsigned char *spnegoToken = NULL;
+    const unsigned char *kerberosToken = nullptr;
+    const unsigned char *spnegoToken = nullptr;
     size_t spnegoTokenLength = 0;
 
-    setbuf(stdout, NULL);
-    setbuf(stdin, NULL);
+    setbuf(stdout, nullptr);
+    setbuf(stdin, nullptr);
 
     while (-1 != (opt = getopt(argc, argv, "dirs:k:c:t:"))) {
         switch (opt) {
@@ -391,7 +393,7 @@ main(int argc, char *const argv[])
                 keytab_name = xstrdup(optarg);
             else {
                 fprintf(stderr, "ERROR: keytab file not given\n");
-                exit(1);
+                exit(EXIT_FAILURE);
             }
             /*
              * Some sanity checks
@@ -406,16 +408,16 @@ main(int argc, char *const argv[])
                     fprintf(stderr, "ERROR: keytab file %s does not exist\n",keytab_name);
                 else
                     fprintf(stderr, "ERROR: Error %s during stat of keytab file %s\n",strerror(errno),keytab_name);
-                exit(1);
+                exit(EXIT_FAILURE);
             } else if (!S_ISREG(fstat.st_mode)) {
                 fprintf(stderr, "ERROR: keytab file %s is not a file\n",keytab_name);
-                exit(1);
+                exit(EXIT_FAILURE);
             }
 #endif
 #if HAVE_UNISTD_H
             if (access(ktp, R_OK)) {
                 fprintf(stderr, "ERROR: keytab file %s is not accessible\n",keytab_name);
-                exit(1);
+                exit(EXIT_FAILURE);
             }
 #endif
             break;
@@ -427,7 +429,7 @@ main(int argc, char *const argv[])
                 rcache_dir = xstrdup(optarg);
             else {
                 fprintf(stderr, "ERROR: replay cache directory not given\n");
-                exit(1);
+                exit(EXIT_FAILURE);
             }
             /*
              * Some sanity checks
@@ -438,16 +440,16 @@ main(int argc, char *const argv[])
                     fprintf(stderr, "ERROR: replay cache directory %s does not exist\n",rcache_dir);
                 else
                     fprintf(stderr, "ERROR: Error %s during stat of replay cache directory %s\n",strerror(errno),rcache_dir);
-                exit(1);
+                exit(EXIT_FAILURE);
             } else if (!S_ISDIR(dstat.st_mode)) {
                 fprintf(stderr, "ERROR: replay cache directory %s is not a directory\n",rcache_dir);
-                exit(1);
+                exit(EXIT_FAILURE);
             }
 #endif
 #if HAVE_UNISTD_H
             if (access(rcache_dir, W_OK)) {
                 fprintf(stderr, "ERROR: replay cache directory %s is not accessible\n",rcache_dir);
-                exit(1);
+                exit(EXIT_FAILURE);
             }
 #endif
             break;
@@ -456,7 +458,7 @@ main(int argc, char *const argv[])
                 rcache_type = xstrdup(optarg);
             else {
                 fprintf(stderr, "ERROR: replay cache type not given\n");
-                exit(1);
+                exit(EXIT_FAILURE);
             }
             break;
         case 's':
@@ -464,7 +466,7 @@ main(int argc, char *const argv[])
                 service_principal = xstrdup(optarg);
             else {
                 fprintf(stderr, "ERROR: service principal not given\n");
-                exit(1);
+                exit(EXIT_FAILURE);
             }
             break;
         default:
@@ -480,7 +482,7 @@ main(int argc, char *const argv[])
             fprintf(stderr,
                     "The SPN can be set to GSS_C_NO_NAME to allow any entry from keytab\n");
             fprintf(stderr, "default SPN is HTTP/fqdn@DEFAULT_REALM\n");
-            exit(0);
+            exit(EXIT_SUCCESS);
         }
     }
 
@@ -499,7 +501,7 @@ main(int argc, char *const argv[])
                     "%s| %s: FATAL: Local hostname could not be determined. Please specify the service principal\n",
                     LogTime(), PROGRAM);
             fprintf(stdout, "BH hostname error\n");
-            exit(-1);
+            exit(EXIT_FAILURE);
         }
         service.value = xmalloc(strlen(service_name) + strlen(host_name) + 2);
         snprintf((char *) service.value, strlen(service_name) + strlen(host_name) + 2,
@@ -560,10 +562,10 @@ main(int argc, char *const argv[])
                 debug((char *) "%s| %s: ERROR: Writing list into keytab %s\n",
                       LogTime(), PROGRAM, memory_keytab_name);
             } else {
-                keytab_name_env = (char *) xmalloc(strlen("KRB5_KTNAME=")+strlen(memory_keytab_name)+1);
-                strcpy(keytab_name_env, "KRB5_KTNAME=");
-                strcat(keytab_name_env, memory_keytab_name);
-                putenv(keytab_name_env);
+                memory_keytab_name_env = (char *) xmalloc(strlen("KRB5_KTNAME=")+strlen(memory_keytab_name)+1);
+                strcpy(memory_keytab_name_env, "KRB5_KTNAME=");
+                strcat(memory_keytab_name_env, memory_keytab_name);
+                putenv(memory_keytab_name_env);
                 xfree(keytab_name);
                 keytab_name = xstrdup(memory_keytab_name);
                 debug((char *) "%s| %s: INFO: Changed keytab to %s\n",
@@ -582,17 +584,17 @@ main(int argc, char *const argv[])
     gsskrb5_register_acceptor_identity(keytab_name);
 #endif
     while (1) {
-        if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
+        if (fgets(buf, sizeof(buf) - 1, stdin) == nullptr) {
             if (ferror(stdin)) {
                 debug((char *) "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n",
                       LogTime(), PROGRAM, ferror(stdin),
                       strerror(ferror(stdin)));
 
                 fprintf(stdout, "BH input error\n");
-                exit(1);    /* BIIG buffer */
+                exit(EXIT_FAILURE);    /* BIIG buffer */
             }
             fprintf(stdout, "BH input error\n");
-            exit(0);
+            exit(EXIT_SUCCESS);
         }
         c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
         if (c) {
@@ -629,7 +631,7 @@ main(int argc, char *const argv[])
             if (client_name)
                 gss_release_name(&minor_status, &client_name);
             if (gss_context != GSS_C_NO_CONTEXT)
-                gss_delete_sec_context(&minor_status, &gss_context, NULL);
+                gss_delete_sec_context(&minor_status, &gss_context, nullptr);
             if (kerberosToken) {
                 /* Allocated by parseNegTokenInit, but no matching free function exists.. */
                 if (!spnego_flag)
@@ -640,8 +642,20 @@ main(int argc, char *const argv[])
                 xfree(spnegoToken);
             }
             xfree(token);
+            xfree(rcache_type);
+            xfree(rcache_type_env);
+            xfree(rcache_dir);
+            xfree(rcache_dir_env);
+            xfree(keytab_name);
+            xfree(keytab_name_env);
+#if HAVE_KRB5_MEMORY_KEYTAB
+            krb5_kt_close(context, memory_keytab);
+            xfree(memory_keytab_name);
+            xfree(memory_keytab_name_env);
+#endif
+            xfree(rfc_user);
             fprintf(stdout, "BH quit command\n");
-            exit(0);
+            exit(EXIT_SUCCESS);
         }
         if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
             debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
@@ -650,7 +664,7 @@ main(int argc, char *const argv[])
         }
         if (!strncmp(buf, "YR", 2)) {
             if (gss_context != GSS_C_NO_CONTEXT)
-                gss_delete_sec_context(&minor_status, &gss_context, NULL);
+                gss_delete_sec_context(&minor_status, &gss_context, nullptr);
             gss_context = GSS_C_NO_CONTEXT;
         }
         if (strlen(buf) <= 3) {
@@ -658,7 +672,7 @@ main(int argc, char *const argv[])
             fprintf(stdout, "BH Invalid negotiate request\n");
             continue;
         }
-        const uint8_t *b64Token = reinterpret_cast<const uint8_t*>(buf+3);
+        const char *b64Token = buf+3;
         const size_t srcLen = strlen(buf+3);
         input_token.length = BASE64_DECODE_LENGTH(srcLen);
         debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length estimate: %d).\n",
@@ -707,7 +721,7 @@ main(int argc, char *const argv[])
 
         major_status =
             gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
-                             GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL);
+                             GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds, nullptr, nullptr);
         if (check_gss_err(major_status, minor_status, "gss_acquire_cred()", log, 1))
             goto cleanup;
 
@@ -716,46 +730,46 @@ main(int argc, char *const argv[])
                                               server_creds,
                                               &input_token,
                                               GSS_C_NO_CHANNEL_BINDINGS,
-                                              &client_name, NULL, &output_token, &ret_flags, NULL, NULL);
+                                              &client_name, nullptr, &output_token, &ret_flags, nullptr, nullptr);
 
         if (output_token.length) {
             spnegoToken = (const unsigned char *) output_token.value;
             spnegoTokenLength = output_token.length;
             token = (char *) xmalloc((size_t)base64_encode_len(spnegoTokenLength));
-            if (token == NULL) {
+            if (token == nullptr) {
                 debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
             struct base64_encode_ctx tokCtx;
             base64_encode_init(&tokCtx);
-            size_t blen = base64_encode_update(&tokCtx, reinterpret_cast<uint8_t*>(token), spnegoTokenLength, reinterpret_cast<const uint8_t*>(spnegoToken));
-            blen += base64_encode_final(&tokCtx, reinterpret_cast<uint8_t*>(token)+blen);
+            size_t blen = base64_encode_update(&tokCtx, token, spnegoTokenLength, reinterpret_cast<const uint8_t*>(spnegoToken));
+            blen += base64_encode_final(&tokCtx, token+blen);
             token[blen] = '\0';
 
             if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log, 1))
                 goto cleanup;
             if (major_status & GSS_S_CONTINUE_NEEDED) {
                 debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
-                fprintf(stdout, "TT %s\n", token);
+                fprintf(stdout, "TT token=%s\n", token);
                 goto cleanup;
             }
             gss_release_buffer(&minor_status, &output_token);
             major_status =
                 gss_display_name(&minor_status, client_name, &output_token,
-                                 NULL);
+                                 nullptr);
 
             if (check_gss_err(major_status, minor_status, "gss_display_name()", log, 1))
                 goto cleanup;
             user = (char *) xmalloc(output_token.length + 1);
-            if (user == NULL) {
+            if (user == nullptr) {
                 debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
             memcpy(user, output_token.value, output_token.length);
             user[output_token.length] = '\0';
-            if (norealm && (p = strchr(user, '@')) != NULL) {
+            if (norealm && (p = strchr(user, '@')) != nullptr) {
                 *p = '\0';
             }
 
@@ -794,11 +808,11 @@ main(int argc, char *const argv[])
 #endif
             rfc_user = rfc1738_escape(user);
 #if HAVE_PAC_SUPPORT
-            fprintf(stdout, "AF %s %s %s\n", token, rfc_user, ag?ag:"group=");
+            fprintf(stdout, "OK token=%s user=%s %s\n", token, rfc_user, ag?ag:"group=");
 #else
-            fprintf(stdout, "AF %s %s\n", token, rfc_user);
+            fprintf(stdout, "OK token=%s user=%s\n", token, rfc_user);
 #endif
-            debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token, rfc_user);
+            debug((char *) "%s| %s: DEBUG: OK token=%s user=%s\n", LogTime(), PROGRAM, token, rfc_user);
             if (log)
                 fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
                         PROGRAM, rfc_user);
@@ -808,13 +822,14 @@ main(int argc, char *const argv[])
                 goto cleanup;
             if (major_status & GSS_S_CONTINUE_NEEDED) {
                 debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
-                fprintf(stdout, "NA %s\n", token);
+                // XXX: where to get the server token for delivery to client? token is nullptr here.
+                fprintf(stdout, "ERR\n");
                 goto cleanup;
             }
             gss_release_buffer(&minor_status, &output_token);
             major_status =
                 gss_display_name(&minor_status, client_name, &output_token,
-                                 NULL);
+                                 nullptr);
 
             if (check_gss_err(major_status, minor_status, "gss_display_name()", log, 1))
                 goto cleanup;
@@ -822,23 +837,23 @@ main(int argc, char *const argv[])
              *  Return dummy token AA. May need an extra return tag then AF
              */
             user = (char *) xmalloc(output_token.length + 1);
-            if (user == NULL) {
+            if (user == nullptr) {
                 debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
             memcpy(user, output_token.value, output_token.length);
             user[output_token.length] = '\0';
-            if (norealm && (p = strchr(user, '@')) != NULL) {
+            if (norealm && (p = strchr(user, '@')) != nullptr) {
                 *p = '\0';
             }
             rfc_user = rfc1738_escape(user);
 #if HAVE_PAC_SUPPORT
-            fprintf(stdout, "AF %s %s %s\n", "AA==", rfc_user, ag?ag:"group=");
+            fprintf(stdout, "OK token=%s user=%s %s\n", "AA==", rfc_user, ag?ag:"group=");
 #else
-            fprintf(stdout, "AF %s %s\n", "AA==", rfc_user);
+            fprintf(stdout, "OK token=%s user=%s\n", "AA==", rfc_user);
 #endif
-            debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, "AA==", rfc_user);
+            debug((char *) "%s| %s: DEBUG: OK token=%s user=%s\n", LogTime(), PROGRAM, "AA==", rfc_user);
             if (log)
                 fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
                         PROGRAM, rfc_user);
@@ -864,6 +879,7 @@ cleanup:
         safe_free(user);
         continue;
     }
+    return EXIT_SUCCESS;
 }
 #else
 #include <cstdlib>
@@ -879,10 +895,11 @@ main(int argc, char *const argv[])
     while (1) {
         if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
             fprintf(stdout, "BH input error\n");
-            exit(0);
+            exit(EXIT_SUCCESS);
         }
         fprintf(stdout, "BH Kerberos authentication not supported\n");
     }
+    return EXIT_SUCCESS;
 }
 #endif /* HAVE_GSSAPI */