/*
* 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_NETDB_H
-#include <netdb.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_TIME_H
-#include <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
-
-#if !HAVE_HEIMDAL_KERBEROS
-#if HAVE_GSSAPI_GSSAPI_KRB5_H
-#include <gssapi/gssapi_krb5.h>
-#endif
-#if HAVE_GSSAPI_GSSAPI_GENERIC_H
-#include <gssapi/gssapi_generic.h>
-#endif
-#if HAVE_GSSAPI_GSSAPI_EXT_H
-#include <gssapi/gssapi_ext.h>
-#endif
-#endif
-
-#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.4sq"
-#endif
-
-int check_gss_err(OM_uint32 major_status, OM_uint32 minor_status,
- const char *function, 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)
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);
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,
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 log)
+ const char *function, int log, int sout)
{
if (GSS_ERROR(major_status)) {
OM_uint32 maj_stat, min_stat;
gss_release_buffer(&min_stat, &status_string);
} while (msg_ctx);
debug((char *) "%s| %s: ERROR: %s failed: %s\n", LogTime(), PROGRAM, function, buf);
- fprintf(stdout, "BH %s failed: %s\n", 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);
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, log = 0, norealm = 0;
OM_uint32 ret_flags = 0, spnego_flag = 0;
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) {
err = 0;
continue;
}
- debug((char *) "%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') {
debug((char *) "%s| %s: ERROR: Invalid request\n", LogTime(), PROGRAM);
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);
}
fprintf(stdout, "BH Invalid negotiate request\n");
continue;
}
- input_token.length = ska_base64_decode_len(buf + 3);
+ 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))) {
} 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()", 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()", log))
+ if (check_gss_err(major_status, minor_status, "gss_acquire_cred()", log, 1))
goto cleanup;
major_status = gss_accept_sec_context(&minor_status,
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;
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) {
debug((char *) "%s| %s: ERROR: Not enough memory\n", LogTime(), PROGRAM);
fprintf(stdout, "BH Not enough memory\n");
goto cleanup;
}
- ska_base64_encode(token, (const char *) spnegoToken,
- ska_base64_encode_len(spnegoTokenLength), spnegoTokenLength);
+ base64_encode_str(token, base64_encode_len((int)spnegoTokenLength),
+ (const char *) spnegoToken, (int)spnegoTokenLength);
- if (check_gss_err(major_status, minor_status, "gss_accept_sec_context()", log))
+ 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);
gss_display_name(&minor_status, client_name, &output_token,
NULL);
- if (check_gss_err(major_status, minor_status, "gss_display_name()", log))
+ 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 (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);
- debug((char *) "%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()", log))
+ 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);
gss_display_name(&minor_status, client_name, &output_token,
NULL);
- if (check_gss_err(major_status, minor_status, "gss_display_name()", 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
*p = '\0';
}
fprintf(stdout, "AF %s %s\n", "AA==", user);
- debug((char *) "%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:
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;
}
}