]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - helpers/negotiate_auth/kerberos/negotiate_kerberos_auth.cc
SourceFormat Enforcement
[thirdparty/squid.git] / helpers / negotiate_auth / kerberos / negotiate_kerberos_auth.cc
index 5f84ea41f8cd0d95cd8def8fadc3e23ebd3de2b9..511e862458950fb18f7f47a51b57d052268b1e5a 100644 (file)
 /*
  * Hosted at http://sourceforge.net/projects/squidkerbauth
  */
-#include "config.h"
+#include "squid.h"
 #include "compat/getaddrinfo.h"
 #include "compat/getnameinfo.h"
+#include "rfc1738.h"
 
 #if HAVE_GSSAPI
 
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_STDOI_H
-#include <stdio.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_TIME_H
-#include <time.h>
-#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#include "util.h"
-#include "base64.h"
-
-#if HAVE_GSSAPI_GSSAPI_H
-#include <gssapi/gssapi.h>
-#elif HAVE_GSSAPI_H
-#include <gssapi.h>
-#endif /* HAVE_GSSAPI_GSSAPI_H */
-#if HAVE_GSSAPI_GSSAPI_KRB5_H
-#include <gssapi/gssapi_krb5.h>
-#endif /* HAVE_GSSAPI_GSSAPI_KRB5_H */
-#if HAVE_GSSAPI_GSSAPI_GENERIC_H
-#include <gssapi/gssapi_generic.h>
-#endif /* HAVE_GSSAPI_GSSAPI_GENERIC_H */
-#ifndef gss_nt_service_name
-#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
-#endif
-
-#define PROGRAM "negotiate_kerberos_auth"
-
-#ifndef MAX_AUTHTOKEN_LEN
-#define MAX_AUTHTOKEN_LEN   65535
-#endif
-#ifndef SQUID_KERB_AUTH_VERSION
-#define SQUID_KERB_AUTH_VERSION "3.0.2sq"
-#endif
-
-int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
-                  const char *function, int debug, int log);
-char *gethost_name(void);
-static const char *LogTime(void);
-
-static const unsigned char ntlmProtocol[] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', 0 };
-
-static const char *
-LogTime()
-{
-    struct tm *tm;
-    struct timeval now;
-    static time_t last_t = 0;
-    static char buf[128];
-
-    gettimeofday(&now, NULL);
-    if (now.tv_sec != last_t) {
-        tm = localtime((time_t *) & now.tv_sec);
-        strftime(buf, 127, "%Y/%m/%d %H:%M:%S", tm);
-        last_t = now.tv_sec;
-    }
-    return buf;
-}
+#include "negotiate_kerberos.h"
 
 char *
 gethost_name(void)
 {
     /*
-        char hostname[sysconf(_SC_HOST_NAME_MAX)];
-    */
+     * char hostname[sysconf(_SC_HOST_NAME_MAX)];
+     */
     char hostname[1024];
     struct addrinfo *hres = NULL, *hres_list;
     int rc, count;
 
-    rc = gethostname(hostname, sysconf(_SC_HOST_NAME_MAX));
+    rc = gethostname(hostname, sizeof(hostname)-1);
     if (rc) {
         fprintf(stderr, "%s| %s: ERROR: resolving hostname '%s' failed\n",
                 LogTime(), PROGRAM, hostname);
@@ -134,7 +64,7 @@ gethost_name(void)
     hres_list = hres;
     count = 0;
     while (hres_list) {
-        count++;
+        ++count;
         hres_list = hres_list->ai_next;
     }
     rc = getnameinfo(hres->ai_addr, hres->ai_addrlen, hostname,
@@ -146,15 +76,14 @@ gethost_name(void)
         freeaddrinfo(hres);
         return NULL;
     }
-
     freeaddrinfo(hres);
-    hostname[sysconf(_SC_HOST_NAME_MAX) - 1] = '\0';
+    hostname[sizeof(hostname)-1] = '\0';
     return (xstrdup(hostname));
 }
 
 int
 check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
-              const char *function, int debug, int log)
+              const char *function, int log, int sout)
 {
     if (GSS_ERROR(major_status)) {
         OM_uint32 maj_stat, min_stat;
@@ -165,43 +94,40 @@ check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
 
         len = 0;
         msg_ctx = 0;
-        while (!msg_ctx) {
+        do {
             /* convert major status code (GSS-API error) to text */
             maj_stat = gss_display_status(&min_stat, major_status,
                                           GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
-            if (maj_stat == GSS_S_COMPLETE) {
+            if (maj_stat == GSS_S_COMPLETE && status_string.length > 0) {
                 if (sizeof(buf) > len + status_string.length + 1) {
-                    snprintf(buf + len, (sizeof(buf)-len), "%s", (char *) status_string.value);
+                    snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value);
                     len += status_string.length;
                 }
-                gss_release_buffer(&min_stat, &status_string);
-                break;
-            }
+            } else
+                msg_ctx = 0;
             gss_release_buffer(&min_stat, &status_string);
-        }
+        } while (msg_ctx);
         if (sizeof(buf) > len + 2) {
-            snprintf(buf + len, (sizeof(buf)-len), "%s", ". ");
+            snprintf(buf + len, (sizeof(buf) - len), "%s", ". ");
             len += 2;
         }
         msg_ctx = 0;
-        while (!msg_ctx) {
+        do {
             /* convert minor status code (underlying routine error) to text */
             maj_stat = gss_display_status(&min_stat, minor_status,
                                           GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string);
-            if (maj_stat == GSS_S_COMPLETE) {
+            if (maj_stat == GSS_S_COMPLETE && status_string.length > 0) {
                 if (sizeof(buf) > len + status_string.length) {
-                    snprintf(buf + len,(sizeof(buf)-len), "%s", (char *) status_string.value);
+                    snprintf(buf + len, (sizeof(buf) - len), "%s", (char *) status_string.value);
                     len += status_string.length;
                 }
-                gss_release_buffer(&min_stat, &status_string);
-                break;
-            }
+            } else
+                msg_ctx = 0;
             gss_release_buffer(&min_stat, &status_string);
-        }
-        if (debug)
-            fprintf(stderr, "%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM,
-                    function, buf);
-        fprintf(stdout, "BH %s failed: %s\n", function, buf);
+        } while (msg_ctx);
+        debug((char *) "%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM, function, buf);
+        if (sout)
+            fprintf(stdout, "BH %s failed: %s\n", function, buf);
         if (log)
             fprintf(stderr, "%s| %s: INFO: User not authenticated\n", LogTime(),
                     PROGRAM);
@@ -210,17 +136,28 @@ check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
     return (0);
 }
 
-
-
 int
 main(int argc, char *const argv[])
 {
     char buf[MAX_AUTHTOKEN_LEN];
     char *c, *p;
     char *user = NULL;
-    int length = 0;
+    char *rfc_user = NULL;
+#if HAVE_PAC_SUPPORT
+    char ad_groups[MAX_PAC_GROUP_SIZE];
+    char *ag=NULL;
+    krb5_context context = NULL;
+    krb5_error_code ret;
+    krb5_pac pac;
+#if HAVE_HEIMDAL_KERBEROS
+    gss_buffer_desc data_set = GSS_C_EMPTY_BUFFER;
+#else
+    gss_buffer_desc type_id = GSS_C_EMPTY_BUFFER;
+#endif
+#endif
+    long length = 0;
     static int err = 0;
-    int opt, debug = 0, log = 0, norealm = 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;
@@ -243,7 +180,7 @@ main(int argc, char *const argv[])
     while (-1 != (opt = getopt(argc, argv, "dirs:h"))) {
         switch (opt) {
         case 'd':
-            debug = 1;
+            debug_enabled = 1;
             break;
         case 'i':
             log = 1;
@@ -272,9 +209,7 @@ main(int argc, char *const argv[])
         }
     }
 
-    if (debug)
-        fprintf(stderr, "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM,
-                SQUID_KERB_AUTH_VERSION);
+    debug((char *) "%s| %s: INFO: Starting version %s\n", LogTime(), PROGRAM, SQUID_KERB_AUTH_VERSION);
     if (service_principal && strcasecmp(service_principal, "GSS_C_NO_NAME")) {
         service.value = service_principal;
         service.length = strlen((char *) service.value);
@@ -288,19 +223,18 @@ main(int argc, char *const argv[])
             exit(-1);
         }
         service.value = xmalloc(strlen(service_name) + strlen(host_name) + 2);
-        snprintf((char*)service.value, strlen(service_name) + strlen(host_name) + 2,
+        snprintf((char *) service.value, strlen(service_name) + strlen(host_name) + 2,
                  "%s@%s", service_name, host_name);
         service.length = strlen((char *) service.value);
+        xfree(host_name);
     }
 
     while (1) {
         if (fgets(buf, sizeof(buf) - 1, stdin) == NULL) {
             if (ferror(stdin)) {
-                if (debug)
-                    fprintf(stderr,
-                            "%s| %s: FATAL: fgets() failed! dying..... errno=%d (%s)\n",
-                            LogTime(), PROGRAM, ferror(stdin),
-                            strerror(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 */
@@ -308,8 +242,7 @@ main(int argc, char *const argv[])
             fprintf(stdout, "BH input error\n");
             exit(0);
         }
-
-        c = (char*)memchr(buf, '\n', sizeof(buf) - 1);
+        c = (char *) memchr(buf, '\n', sizeof(buf) - 1);
         if (c) {
             *c = '\0';
             length = c - buf;
@@ -317,34 +250,23 @@ main(int argc, char *const argv[])
             err = 1;
         }
         if (err) {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Oversized message\n", LogTime(),
-                        PROGRAM);
+            debug((char *) "%s| %s: ERROR: Oversized message\n", LogTime(), PROGRAM);
             fprintf(stdout, "BH Oversized message\n");
             err = 0;
             continue;
         }
-
-        if (debug)
-            fprintf(stderr, "%s| %s: DEBUG: Got '%s' from squid (length: %d).\n",
-                    LogTime(), PROGRAM, buf, length);
+        debug((char *) "%s| %s: DEBUG: Got '%s' from squid (length: %ld).\n", LogTime(), PROGRAM, buf, length);
 
         if (buf[0] == '\0') {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Invalid request\n", LogTime(),
-                        PROGRAM);
+            debug((char *) "%s| %s: ERROR: Invalid request\n", LogTime(), PROGRAM);
             fprintf(stdout, "BH Invalid request\n");
             continue;
         }
-
         if (strlen(buf) < 2) {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Invalid request [%s]\n", LogTime(),
-                        PROGRAM, buf);
+            debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
             fprintf(stdout, "BH Invalid request\n");
             continue;
         }
-
         if (!strncmp(buf, "QQ", 2)) {
             gss_release_buffer(&minor_status, &input_token);
             gss_release_buffer(&minor_status, &output_token);
@@ -359,31 +281,18 @@ main(int argc, char *const argv[])
             if (kerberosToken) {
                 /* Allocated by parseNegTokenInit, but no matching free function exists.. */
                 if (!spnego_flag)
-                    xfree((char *) kerberosToken);
-                kerberosToken = NULL;
+                    xfree(kerberosToken);
             }
             if (spnego_flag) {
                 /* Allocated by makeNegTokenTarg, but no matching free function exists.. */
-                if (spnegoToken)
-                    xfree((char *) spnegoToken);
-                spnegoToken = NULL;
-            }
-            if (token) {
-                xfree(token);
-                token = NULL;
-            }
-            if (host_name) {
-                xfree(host_name);
-                host_name = NULL;
+                xfree(spnegoToken);
             }
+            xfree(token);
             fprintf(stdout, "BH quit command\n");
             exit(0);
         }
-
         if (strncmp(buf, "YR", 2) && strncmp(buf, "KK", 2)) {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Invalid request [%s]\n", LogTime(),
-                        PROGRAM, buf);
+            debug((char *) "%s| %s: ERROR: Invalid request [%s]\n", LogTime(), PROGRAM, buf);
             fprintf(stdout, "BH Invalid request\n");
             continue;
         }
@@ -392,37 +301,29 @@ main(int argc, char *const argv[])
                 gss_delete_sec_context(&minor_status, &gss_context, NULL);
             gss_context = GSS_C_NO_CONTEXT;
         }
-
         if (strlen(buf) <= 3) {
-            if (debug)
-                fprintf(stderr, "%s| %s: ERROR: Invalid negotiate request [%s]\n",
-                        LogTime(), PROGRAM, buf);
+            debug((char *) "%s| %s: ERROR: Invalid negotiate request [%s]\n", LogTime(), PROGRAM, buf);
             fprintf(stdout, "BH Invalid negotiate request\n");
             continue;
         }
-
-        input_token.length = ska_base64_decode_len(buf + 3);
-        if (debug)
-            fprintf(stderr, "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
-                    LogTime(), PROGRAM, buf + 3, (int) input_token.length);
+        input_token.length = (size_t)base64_decode_len(buf+3);
+        debug((char *) "%s| %s: DEBUG: Decode '%s' (decoded length: %d).\n",
+              LogTime(), PROGRAM, buf + 3, (int) input_token.length);
         input_token.value = xmalloc(input_token.length);
 
-        ska_base64_decode((char*)input_token.value, buf + 3, input_token.length);
-
+        input_token.length = (size_t)base64_decode((char *) input_token.value, (unsigned int)input_token.length, buf+3);
 
         if ((input_token.length >= sizeof ntlmProtocol + 1) &&
                 (!memcmp(input_token.value, ntlmProtocol, sizeof ntlmProtocol))) {
-            if (debug)
-                fprintf(stderr, "%s| %s: WARNING: received type %d NTLM token\n",
-                        LogTime(), PROGRAM,
-                        (int) *((unsigned char *) input_token.value +
-                                sizeof ntlmProtocol));
+            debug((char *) "%s| %s: WARNING: received type %d NTLM token\n",
+                  LogTime(), PROGRAM,
+                  (int) *((unsigned char *) input_token.value +
+                          sizeof ntlmProtocol));
             fprintf(stdout, "BH received type %d NTLM token\n",
                     (int) *((unsigned char *) input_token.value +
                             sizeof ntlmProtocol));
             goto cleanup;
         }
-
         if (service_principal) {
             if (strcasecmp(service_principal, "GSS_C_NO_NAME")) {
                 major_status = gss_import_name(&minor_status, &service,
@@ -431,21 +332,20 @@ main(int argc, char *const argv[])
             } else {
                 server_name = GSS_C_NO_NAME;
                 major_status = GSS_S_COMPLETE;
+                minor_status = 0;
             }
         } else {
             major_status = gss_import_name(&minor_status, &service,
                                            gss_nt_service_name, &server_name);
         }
 
-        if (check_gss_err(major_status, minor_status, "gss_import_name()",
-                          debug, log))
+        if (check_gss_err(major_status, minor_status, "gss_import_name()", log, 1))
             goto cleanup;
 
         major_status =
             gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
                              GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_creds, NULL, NULL);
-        if (check_gss_err(major_status, minor_status, "gss_acquire_cred()",
-                          debug, log))
+        if (check_gss_err(major_status, minor_status, "gss_acquire_cred()", log, 1))
             goto cleanup;
 
         major_status = gss_accept_sec_context(&minor_status,
@@ -455,29 +355,22 @@ main(int argc, char *const argv[])
                                               GSS_C_NO_CHANNEL_BINDINGS,
                                               &client_name, NULL, &output_token, &ret_flags, NULL, NULL);
 
-
         if (output_token.length) {
-            spnegoToken = (const unsigned char*)output_token.value;
+            spnegoToken = (const unsigned char *) output_token.value;
             spnegoTokenLength = output_token.length;
-            token = (char*)xmalloc(ska_base64_encode_len(spnegoTokenLength));
+            token = (char *) xmalloc((size_t)base64_encode_len((int)spnegoTokenLength));
             if (token == NULL) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                            PROGRAM);
+                debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
+            base64_encode_str(token, base64_encode_len((int)spnegoTokenLength),
+                              (const char *) spnegoToken, (int)spnegoTokenLength);
 
-            ska_base64_encode(token, (const char *) spnegoToken,
-                              ska_base64_encode_len(spnegoTokenLength), spnegoTokenLength);
-
-            if (check_gss_err(major_status, minor_status,
-                              "gss_accept_sec_context()", debug, log))
+            if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log, 1))
                 goto cleanup;
             if (major_status & GSS_S_CONTINUE_NEEDED) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: INFO: continuation needed\n", LogTime(),
-                            PROGRAM);
+                debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
                 fprintf(stdout, "TT %s\n", token);
                 goto cleanup;
             }
@@ -486,14 +379,11 @@ main(int argc, char *const argv[])
                 gss_display_name(&minor_status, client_name, &output_token,
                                  NULL);
 
-            if (check_gss_err(major_status, minor_status, "gss_display_name()",
-                              debug, log))
+            if (check_gss_err(major_status, minor_status, "gss_display_name()", log, 1))
                 goto cleanup;
-            user = (char*)xmalloc(output_token.length + 1);
+            user = (char *) xmalloc(output_token.length + 1);
             if (user == NULL) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                            PROGRAM);
+                debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
@@ -502,22 +392,52 @@ main(int argc, char *const argv[])
             if (norealm && (p = strchr(user, '@')) != NULL) {
                 *p = '\0';
             }
+
+#if HAVE_PAC_SUPPORT
+            ret = krb5_init_context(&context);
+            if (!check_k5_err(context, "krb5_init_context", ret)) {
+#if HAVE_HEIMDAL_KERBEROS
+#define ADWIN2KPAC 128
+                major_status = gsskrb5_extract_authz_data_from_sec_context(&minor_status,
+                               gss_context, ADWIN2KPAC, &data_set);
+                if (!check_gss_err(major_status, minor_status,
+                                   "gsskrb5_extract_authz_data_from_sec_context()", log, 0)) {
+                    ret = krb5_pac_parse(context, data_set.value, data_set.length, &pac);
+                    gss_release_buffer(&minor_status, &data_set);
+                    if (!check_k5_err(context, "krb5_pac_parse", ret)) {
+                        ag = get_ad_groups((char *)&ad_groups, context, pac);
+                        krb5_pac_free(context, pac);
+                    }
+                    krb5_free_context(context);
+                }
+#else
+                type_id.value = (void *)"mspac";
+                type_id.length = strlen((char *)type_id.value);
+#define KRB5PACLOGONINFO        1
+                major_status = gss_map_name_to_any(&minor_status, client_name, KRB5PACLOGONINFO, &type_id, (gss_any_t *)&pac);
+                if (!check_gss_err(major_status, minor_status, "gss_map_name_to_any()", log, 0)) {
+                    ag = get_ad_groups((char *)&ad_groups,context, pac);
+                }
+                (void)gss_release_any_name_mapping(&minor_status, client_name, &type_id, (gss_any_t *)&pac);
+                krb5_free_context(context);
+#endif
+            }
+            if (ag) {
+                debug((char *) "%s| %s: DEBUG: Groups %s\n", LogTime(), PROGRAM, ag);
+            }
+#endif
             fprintf(stdout, "AF %s %s\n", token, user);
-            if (debug)
-                fprintf(stderr, "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token,
-                        user);
+            rfc_user = rfc1738_escape(user);
+            debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, token, rfc_user);
             if (log)
                 fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
-                        PROGRAM, user);
+                        PROGRAM, rfc1738_escape(user));
             goto cleanup;
         } else {
-            if (check_gss_err(major_status, minor_status,
-                              "gss_accept_sec_context()", debug, log))
+            if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log, 1))
                 goto cleanup;
             if (major_status & GSS_S_CONTINUE_NEEDED) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: INFO: continuation needed\n", LogTime(),
-                            PROGRAM);
+                debug((char *) "%s| %s: INFO: continuation needed\n", LogTime(), PROGRAM);
                 fprintf(stdout, "NA %s\n", token);
                 goto cleanup;
             }
@@ -526,17 +446,14 @@ main(int argc, char *const argv[])
                 gss_display_name(&minor_status, client_name, &output_token,
                                  NULL);
 
-            if (check_gss_err(major_status, minor_status, "gss_display_name()",
-                              debug, log))
+            if (check_gss_err(major_status, minor_status, "gss_display_name()", log, 1))
                 goto cleanup;
             /*
              *  Return dummy token AA. May need an extra return tag then AF
              */
-            user = (char*)xmalloc(output_token.length + 1);
+            user = (char *) xmalloc(output_token.length + 1);
             if (user == NULL) {
-                if (debug)
-                    fprintf(stderr, "%s| %s: ERROR: Not enough memory\n", LogTime(),
-                            PROGRAM);
+                debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
                 fprintf(stdout, "BH Not enough memory\n");
                 goto cleanup;
             }
@@ -546,12 +463,10 @@ main(int argc, char *const argv[])
                 *p = '\0';
             }
             fprintf(stdout, "AF %s %s\n", "AA==", user);
-            if (debug)
-                fprintf(stderr, "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM,
-                        "AA==", user);
+            debug((char *) "%s| %s: DEBUG: AF %s %s\n", LogTime(), PROGRAM, "AA==", rfc1738_escape(user));
             if (log)
                 fprintf(stderr, "%s| %s: INFO: User %s authenticated\n", LogTime(),
-                        PROGRAM, user);
+                        PROGRAM, rfc1738_escape(user));
 
         }
 cleanup:
@@ -565,23 +480,14 @@ cleanup:
         if (kerberosToken) {
             /* Allocated by parseNegTokenInit, but no matching free function exists.. */
             if (!spnego_flag)
-                xfree((char *) kerberosToken);
-            kerberosToken = NULL;
+                safe_free(kerberosToken);
         }
         if (spnego_flag) {
             /* Allocated by makeNegTokenTarg, but no matching free function exists.. */
-            if (spnegoToken)
-                xfree((char *) spnegoToken);
-            spnegoToken = NULL;
-        }
-        if (token) {
-            xfree(token);
-            token = NULL;
-        }
-        if (user) {
-            xfree(user);
-            user = NULL;
+            safe_free(spnegoToken);
         }
+        safe_free(token);
+        safe_free(user);
         continue;
     }
 }