/* * mod_ntlm.c: NTLM authentication module for Apache/Unix * Version 0.1 * * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * Based on * mod_ntlm.c for Win32 by Tim Costello * pam_smb by Dave Airlie * * This code is copyright 2000 Andreas Gal . * Visit http://modntlm.sourceforge.net/ for code updates. * * THIS SOFTWARE IS PROVIDED ``AS IS`` AND ANY EXPRESSED OR IMPLIED * WARRANTIES ARE DISCLAIMED. * * This code may be freely distributed, as long the above notices are * reproduced. * * $Id: mod_ntlm.c,v 1.3 2003/02/21 01:55:13 casz Exp $ * */ #define VERSION "$Name: $" #define USE_APACHE_PROVIDED_UU_FUNCTIONS #define myLOG_ERROR #ifdef myLOG_ERROR #define DEBUG(x) ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, x " %u %u", (unsigned) r->connection, (unsigned) getpid()) #else #define DEBUG(x) #endif #include "mod_ntlm.h" #ifdef myLOG_ERROR #define LOG #include static void log(const request_rec * r, const char *format,...) { va_list ap; char *s; if ((s = (char *) malloc(2048)) == NULL) return; va_start(ap, format); vsprintf(s, format, ap); va_end(ap); ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_NOTICE, r, s); free(s); } static void flog(const char *format,...) { va_list ap; char *s; FILE *f; if ((s = (char *) malloc(2048)) == NULL) return; va_start(ap, format); vsprintf(s, format, ap); va_end(ap); if ((f = fopen("/tmp/mod_ntlm.log", "a")) != NULL) { fputs(s, f); fputs("\n", f); fclose(f); } free(s); } #else #undef LOG #endif #include "ntlmssp.inc.c" #include "smbval/byteorder.h" #include "smbval/std-defines.h" #include "smbval/std-includes.h" #include "smbval/smblib-common.h" #include "smbval/smblib-priv.h" #include "smbval/rfcnb-common.h" #include "smbval/rfcnb-error.h" #include "smbval/rfcnb-priv.h" #include "smbval/rfcnb-util.h" #include "smbval/rfcnb-io.h" #include "smbval/rfcnb.h" #include "smbval/valid.h" #include "smbval/rfcnb-io.inc.c" #include "smbval/rfcnb-util.inc.c" #include "smbval/session.inc.c" #include "smbval/smbdes.inc.c" #include "smbval/smbencrypt.inc.c" #include "smbval/smblib-util.inc.c" #include "smbval/smblib.inc.c" #include "smbval/valid.inc.c" static const command_rec ntlm_cmds[] = { { "NTLMAuth", ap_set_flag_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_on), OR_AUTHCFG, FLAG, "set to 'on' to activate NTLM authentication here" }, /* fhz, 03/30/02: use standard Apache API (ap_set_file_slot) instead our old buggy one :-) */ {"AuthNTGroups", ap_set_file_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_grpfile), OR_AUTHCFG, TAKE1, "text file containing (NT) group names and member user IDs"}, { "NTLMBasicAuth", ap_set_flag_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_basic_on), OR_AUTHCFG, FLAG, "set to 'on' to allov Basic authentication too" }, { "NTLMBasicRealm", ap_set_string_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_basic_realm), OR_AUTHCFG, TAKE1, "realm to use for Basic authentication" }, { "NTLMAuthoritative", ap_set_flag_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_authoritative), OR_AUTHCFG, FLAG, "set to 'off' to allow access control to be passed along to lower " "modules if the UserID is not known to this module" }, { "NTLMDomain", ap_set_string_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_domain), OR_AUTHCFG, TAKE1, "set to the domain you want users authenticated against for cleartext " "authentication - if not specified, the local machine, then all trusted " " domains are checked" }, { "NTLMServer", ap_set_string_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_server), OR_AUTHCFG, TAKE1, "set to the NT server to contact to authenticate users" }, { "NTLMBackup", ap_set_string_slot, (void *) XtOffsetOf(ntlm_config_rec, ntlm_backup), OR_AUTHCFG, TAKE1, "set to the alternate NT server to contact to authenticate users" }, { NULL } }; static ntlm_connection_rec *ntlm_connection = NULL; static void * create_ntlm_dir_config(pool * p, char *d) { ntlm_config_rec *crec = (ntlm_config_rec *) ap_pcalloc(p, sizeof(ntlm_config_rec)); /* Set the defaults. */ crec->ntlm_authoritative = 1; crec->ntlm_on = 0; crec->ntlm_basic_on = 0; crec->ntlm_basic_realm = "REALM"; crec->ntlm_server = "SERVER"; crec->ntlm_backup = ""; crec->ntlm_domain = "DOMAIN"; crec->ntlm_grpfile = NULL; /* rit, group file added */ return crec; } #ifdef USE_APACHE_PROVIDED_UU_FUNCTIONS static void * uudecode_binary(pool *p, const char *bufcoded, int *nbytesdecoded) { char *decoded; decoded = (char *) ap_palloc(p, 1 + ap_base64decode_len(bufcoded)); *nbytesdecoded = ap_base64decode(decoded, bufcoded); decoded[*nbytesdecoded] = '\0'; /* make binary sequence into string */ return decoded; } static char * uuencode_binary(pool *p, unsigned char *string, int len) { char *encoded; encoded = (char *) ap_palloc(p, 1 + ap_base64encode_len(len)); len = ap_base64encode(encoded, string, len); encoded[len] = '\0'; /* make binary sequence into string */ return encoded; } #else /* UUENCODE / DECODE TABLES */ static const unsigned char pr2six[256] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }; static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* * UUENCODE / DECODE routines below taken from apache source code */ static void * uudecode_binary(pool * p, const char *bufcoded, int *nbytesdecoded) { register const unsigned char *bufin; register char *bufplain; register unsigned char *bufout; register int nprbytes; /* Strip leading whitespace. */ while (*bufcoded == ' ' || *bufcoded == '\t') bufcoded++; /* Figure out how many characters are in the input buffer. * Allocate this many from the per-transaction pool for the * result. */ #ifndef CHARSET_EBCDIC bufin = (const unsigned char *) bufcoded; while (pr2six[*(bufin++)] <= 63) ; nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; *nbytesdecoded = ((nprbytes + 3) / 4) * 3; bufplain = ap_palloc(p, *nbytesdecoded + 1); bufout = (unsigned char *) bufplain; bufin = (const unsigned char *) bufcoded; while (nprbytes > 0) { *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); bufin += 4; nprbytes -= 4; } if (nprbytes & 03) { if (pr2six[bufin[-2]] > 63) *nbytesdecoded -= 2; else *nbytesdecoded -= 1; } bufplain[*nbytesdecoded] = '\0'; #else /* CHARSET_EBCDIC */ bufin = (const unsigned char *) bufcoded; while (pr2six[os_toascii[(unsigned char) *(bufin++)]] <= 63) ; nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; *nbytesdecoded = ((nprbytes + 3) / 4) * 3; bufplain = ap_palloc(p, *nbytesdecoded + 1); bufout = (unsigned char *) bufplain; bufin = (const unsigned char *) bufcoded; while (nprbytes > 0) { *(bufout++) = os_toebcdic[(unsigned char) (pr2six[os_toascii[*bufin]] << 2 | pr2six[os_toascii[bufin[1]]] >> 4)]; *(bufout++) = os_toebcdic[(unsigned char) (pr2six[os_toascii[bufin[1]]] << 4 | pr2six[os_toascii[bufin[2]]] >> 2)]; *(bufout++) = os_toebcdic[(unsigned char) (pr2six[os_toascii[bufin[2]]] << 6 | pr2six[os_toascii[bufin[3]]])]; bufin += 4; nprbytes -= 4; } if (nprbytes & 03) { if (pr2six[os_toascii[bufin[-2]]] > 63) *nbytesdecoded -= 2; else *nbytesdecoded -= 1; } bufplain[*nbytesdecoded] = '\0'; #endif /* CHARSET_EBCDIC */ return bufplain; } static char * uuencode_binary(pool *a, unsigned char *string, int len) { int i; char *p; char *encoded = (char *) ap_palloc(a, ((len + 2) / 3 * 4) + 1); p = encoded; #ifndef CHARSET_EBCDIC for (i = 0; i < len - 2; i += 3) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; *p++ = basis_64[string[i + 2] & 0x3F]; } if (i < len) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; if (i == (len - 2)) *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; else *p++ = '='; *p++ = '='; } #else /* CHARSET_EBCDIC */ for (i = 0; i < len - 2; i += 3) { *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2) | ((int) (os_toascii[string[i + 2]] & 0xC0) >> 6)]; *p++ = basis_64[os_toascii[string[i + 2]] & 0x3F]; } if (i < len) { *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; if (i == (len - 2)) *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2)]; else *p++ = '='; *p++ = '='; } #endif /* CHARSET_EBCDIC */ *p = '\0'; return encoded; } #endif /* USE_APACHE_PROVIDED_UU_FUNCTIONS */ static void cleanup_ntlm_connection(void *unused) { if (ntlm_connection->handle) { NTLM_Disconnect(ntlm_connection->handle); ntlm_connection->handle = NULL; } ntlm_connection = NULL; /* will be freed with r->connection's context */ } static void note_ntlm_auth_failure(request_rec * r) { ntlm_config_rec *crec = (ntlm_config_rec *) ap_get_module_config(r->per_dir_config, &ntlm_module); unsigned char *line; line = ap_pstrdup(r->pool, NTLM_AUTH_NAME); ap_table_setn(r->err_headers_out, r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", line); if (crec->ntlm_basic_on) { line = ap_pstrcat(r->pool, "Basic realm=\"", crec->ntlm_basic_realm, "\"", NULL); ap_table_addn(r->err_headers_out, r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", line); } } static void log_ntlm_logon_denied(request_rec * r) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "NTLM/SMB user \"%s\": authentication failure for \"%s\"", ntlm_connection->user, r->uri); } ntlmssp_info_rec * get_ntlm_header(request_rec * r, ntlm_config_rec * crec) { const char *auth_line = ap_table_get(r->headers_in, r->proxyreq ? "Proxy-Authorization" : "Authorization"); unsigned char *msg; int len, foo; unsigned ntlmssp_flags=0; ntlmssp_info_rec *ntlmssp; /* fhz 16-10-01: take care of unicode strings */ if (ntlm_connection->ntlmssp_flags) ntlmssp_flags=ntlm_connection->ntlmssp_flags; if (!auth_line) { DEBUG("no auth_line"); return NULL; } if (strcmp(ap_getword_white(r->pool, &auth_line), NTLM_AUTH_NAME)) { DEBUG("ap_getword_white failed"); return NULL; } #ifdef LOG log(r, "got auth_line \"%s\"",auth_line); #endif msg = uudecode_binary(r->connection->pool, auth_line, &len); ntlmssp = ap_pcalloc(r->pool, sizeof(ntlmssp_info_rec)); if ((foo = ntlm_decode_msg(r, ntlmssp, msg, len,&ntlmssp_flags)) != 0) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "ntlm_decode_msg failed: type: %d, host: \"%s\", " "user: \"%s\", domain: \"%s\", error: %d", ntlmssp->msg_type, ntlmssp->host, ntlmssp->user, ntlmssp->domain, foo); return NULL; } /* fhz 16-10-01: take care of unicode strings */ if (ntlmssp_flags) ntlm_connection->ntlmssp_flags=ntlmssp_flags; #ifdef LOG log(r, "got header with host \"%s\", domain \"%s\"", ntlmssp->host, ntlmssp->domain); #endif return ntlmssp; } static int send_ntlm_challenge(request_rec * r, ntlm_config_rec * crec, int win9x) { struct ntlm_msg2 msg; struct ntlm_msg2_win9x msg_win9x; unsigned char *challenge; unsigned int l; DEBUG("received msg1"); if (ntlm_connection->handle == NULL) { ntlm_connection->nonce = ap_pcalloc(r->connection->pool, NONCE_LEN); ntlm_connection->handle = NTLM_Connect(crec->ntlm_server, crec->ntlm_backup, crec->ntlm_domain, ntlm_connection->nonce); if (!ntlm_connection->handle) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "send_ntlm_challenge: no conn. handle...trouble communicating with PDC/BDC? returning internal server error"); return HTTP_INTERNAL_SERVER_ERROR; } } if (win9x==0) { ntlm_encode_msg2(ntlm_connection->nonce, &msg); challenge = uuencode_binary(r->pool, (unsigned char *) &msg, sizeof(msg)); } else { l=ntlm_encode_msg2_win9x(ntlm_connection->nonce, &msg_win9x, crec->ntlm_domain,ntlm_connection->ntlmssp_flags); challenge = uuencode_binary(r->pool, (unsigned char *)&msg_win9x,l); } ap_table_setn(r->err_headers_out, r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", ap_psprintf(r->pool, "%s %s", NTLM_AUTH_NAME, challenge)); #ifdef LOG log(r, "send WWW-Authenticate \"%s %s\"",NTLM_AUTH_NAME, challenge); #endif return HTTP_UNAUTHORIZED; } static int ntlm_check_response(request_rec * r, ntlm_config_rec * crec, ntlmssp_info_rec * ntlmssp) { DEBUG("received msg3"); if (ntlm_connection->auth_ok && ntlm_connection->user) { /* user has already valid credentials */ if ((!strcmp(ntlm_connection->user, ntlmssp->user)) && (!strcmp(ntlm_connection->domain, ntlmssp->domain)) && (!memcmp(ntlm_connection->password, ntlmssp->nt, RESP_LEN))) { DEBUG("silent reauthentication"); /* silently accept login with same credentials */ r->connection->user = ap_pstrdup(r->connection->pool, ntlm_connection->user); r->connection->ap_auth_type = ap_pstrdup(r->connection->pool, NTLM_AUTH_NAME); return OK; } } if (!ntlm_connection->handle) { DEBUG("PDC connection already closed"); note_ntlm_auth_failure(r); return HTTP_UNAUTHORIZED; } if (!*ntlmssp->user) return HTTP_BAD_REQUEST; ntlm_connection->user = ap_pstrdup(r->connection->pool, ntlmssp->user); ntlm_connection->domain = (*ntlmssp->domain) ? ap_pstrdup(r->connection->pool, ntlmssp->domain) : crec->ntlm_domain; ntlm_connection->password = ap_pcalloc(r->connection->pool, RESP_LEN); memcpy(ntlm_connection->password, ntlmssp->nt, RESP_LEN); DEBUG("authenticating user against DC"); if (NTLM_Auth(ntlm_connection->handle, ntlm_connection->user, ntlm_connection->password, 1) == NTV_LOGON_ERROR) { log_ntlm_logon_denied(r); note_ntlm_auth_failure(r); ntlm_connection->auth_ok = 0; return HTTP_UNAUTHORIZED; } ntlm_connection->auth_ok = 1; DEBUG("authentication OK!"); /* NTLM_Disconnect(ntlm_connection->handle); ntlm_connection->handle = * NULL; */ r->connection->user = ap_pstrdup(r->connection->pool, ntlm_connection->user); r->connection->ap_auth_type = ap_pstrdup(r->connection->pool, NTLM_AUTH_NAME); #ifdef LOG log(r, "NTLM/SMB user: \"%s\\%s\": authentication OK.", ntlm_connection->domain, ntlm_connection->user); #endif return OK; } /* rit, 9.10.00 * code from mod_auth.c */ static table *groups_for_user(pool *p, char *user, char *grpfile) { configfile_t *f; table *grps = ap_make_table(p, 15); pool *sp; char l[MAX_STRING_LEN]; const char *group_name, *ll, *w; if (!(f = ap_pcfg_openfile(p, grpfile))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, NULL, "Could not open group file: %s", grpfile); return NULL; } sp = ap_make_sub_pool(p); while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) { if ((l[0] == '#') || (!l[0])) continue; ll = l; ap_clear_pool(sp); group_name = ap_getword(sp, &ll, ':'); while (ll[0]) { w = ap_getword_conf(sp, &ll); if (!strcmp(w, user)) { ap_table_setn(grps, ap_pstrdup(p, group_name), "in"); break; } } } ap_cfg_closefile(f); ap_destroy_pool(sp); return grps; } /* SHH 2000-05-10: added the following method by copying from several * places (this file and apache sources). very little is my own work. * *sigh*; i've become a thief on my older days. */ static int authenticate_basic_user(request_rec * r, ntlm_config_rec * crec, const char *auth_line_after_Basic) { char *sent_user, *sent_pw, *sent_domain = "", *s; while (*auth_line_after_Basic == ' ' || *auth_line_after_Basic == '\t') auth_line_after_Basic++; sent_user = ap_pbase64decode(r->pool, auth_line_after_Basic); if (sent_user != NULL) { if ((sent_pw = strchr(sent_user, ':')) != NULL) { *sent_pw = '\0'; ++sent_pw; } else sent_pw = ""; if ((s = strchr(sent_user, '\\')) != NULL || (s = strchr(sent_user, '/')) != NULL) { /* domain supplied as part of the user name. */ *s = '\0'; sent_domain = sent_user; sent_user = s + 1; /* check that we are willing to serve this domain. */ if (strcasecmp(sent_domain, crec->ntlm_domain) != 0) { /* domain mismatch. */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "Basic/SMB user \"%s\\%s\": " "authentication failure; " "domain not \"%s\".", sent_domain, sent_user, crec->ntlm_domain); return AUTH_REQUIRED; } } } else sent_user = sent_pw = ""; if (Valid_User(sent_user, sent_pw, crec->ntlm_server, crec->ntlm_backup, crec->ntlm_domain) != NTV_NO_ERROR) { ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "Basic/SMB user \"%s\\%s\": " "authentication failure for \"%s\"", sent_domain, sent_user, r->uri); ap_note_basic_auth_failure(r); return AUTH_REQUIRED; } /* Note that this allocation has to be made from * r->connection->pool because it has the lifetime of the * connection. The other allocations are temporary and can be * tossed away any time. */ r->connection->user = ap_pstrcat(r->connection->pool, sent_user, NULL); r->connection->ap_auth_type = "Basic"; #ifdef LOG log(r, "Basic/SMB user: \"%s\\%s\": authentication OK.", sent_domain, sent_user); #endif return OK; } static int authenticate_ntlm_user(request_rec * r, ntlm_config_rec * crec) { ntlmssp_info_rec *ntlmssp; int win9x=0; /* If this is the first request with this connection, then create * a ntlm_connection entry for it. It will be cleaned up when the * connection is dropped */ if (ntlm_connection == NULL) { DEBUG("creating new ntlm_connection"); ntlm_connection = ap_pcalloc(r->connection->pool, sizeof(ntlm_connection_rec)); ntlm_connection->auth_ok = 0; ntlm_connection->ntlmssp_flags = 0; ap_register_cleanup(r->connection->pool, 0, cleanup_ntlm_connection, ap_null_cleanup); } if ((ntlmssp = get_ntlm_header(r, crec)) == NULL) { note_ntlm_auth_failure(r); DEBUG("missing/corrupt NTLM header"); return HTTP_UNAUTHORIZED; } switch (ntlmssp->msg_type) { case 1: /* Win9x: in msg1, host and domain never sent */ if ((strcmp(ntlmssp->host,"")==0) && (strcmp(ntlmssp->domain,"")==0)) win9x=1; return send_ntlm_challenge(r, crec,win9x); case 3: return ntlm_check_response(r, crec, ntlmssp); } DEBUG("authenticate_ntlm_user: bad request"); return HTTP_BAD_REQUEST; } static int authenticate_user(request_rec * r) { ntlm_config_rec *crec = (ntlm_config_rec *) ap_get_module_config(r->per_dir_config, &ntlm_module); const char *auth_line = ap_table_get(r->headers_in, r->proxyreq ? "Proxy-Authorization" : "Authorization"); if (!crec->ntlm_on) return DECLINED; if (!auth_line) { note_ntlm_auth_failure(r); return AUTH_REQUIRED; } if (crec->ntlm_basic_on && strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic") == 0) return authenticate_basic_user(r, crec, auth_line); return authenticate_ntlm_user(r, crec); } static int check_user_access(request_rec * r) { ntlm_config_rec *crec = (ntlm_config_rec *) ap_get_module_config(r->per_dir_config, &ntlm_module); char *user = r->connection->user; int m = r->method_number; int method_restricted = 0; register int x; const char *t, *w; table *grpstatus; /* rit */ table *e = r->subprocess_env; /* rit */ const array_header *reqs_arr = ap_requires(r); require_line *reqs; /* * If the switch isn't on, don't bother. */ if (!crec->ntlm_on) { return DECLINED; } if (!reqs_arr) { return OK; } reqs = (require_line *) reqs_arr->elts; /* * Did we authenticate this user? * If not, we don't want to do user/group checking. */ if (strcmp(r->connection->ap_auth_type, NTLM_AUTH_NAME) == 0 && (!ntlm_connection || !ntlm_connection->auth_ok)) { return DECLINED; } /* rit, get groups for user */ if (crec->ntlm_grpfile) grpstatus = groups_for_user(r->pool, user, crec->ntlm_grpfile); else grpstatus = NULL; for (x = 0; x < reqs_arr->nelts; x++) { if (!(reqs[x].method_mask & (1 << m))) continue; method_restricted = 1; t = reqs[x].requirement; w = ap_getword_white(r->pool, &t); if (!strcmp(w, "valid-user")) return OK; if (!strcmp(w, "user")) { while (t[0]) { w = ap_getword_conf(r->pool, &t); if (!strcmp(user, w)) return OK; } } /* rit, 9.10.00: coding aus mod_auth.c */ else if (!strcmp(w, "group")) { if (!grpstatus) { return DECLINED; /* DBM group? Something else? */ } while (t[0]) { w = ap_getword_conf(r->pool, &t); if (ap_table_get(grpstatus, w)) { ap_table_setn(e, "REMOTE_NTGROUP", w); return OK; } } /* rit, finish group testng */ } else if (crec->ntlm_authoritative) { /* if we aren't authoritative, any require directive could * be valid even if we don't grok it. However, if we are * authoritative, we can warn the user they did something * wrong. That something could be a missing * "AuthAuthoritative off", but more likely is a typo in * the require directive. */ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "access to \"%s\" failed, reason: " "unknown require directive:" "\"%s\"", r->uri, reqs[x].requirement); } } if (!method_restricted) { return OK; } if (!(crec->ntlm_authoritative)) { return DECLINED; } ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, r, "access to \"%s\" failed, reason: " "user \"%s\" not allowed access.", r->uri, user); note_ntlm_auth_failure(r); /* * We return HTTP_UNAUTHORIZED (401) because the client may wish * to authenticate using a different scheme, or a different * username. If this works, they can be granted access. If we * returned HTTP_FORBIDDEN (403) then they don't get a second * chance. */ return HTTP_UNAUTHORIZED; } module MODULE_VAR_EXPORT ntlm_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ create_ntlm_dir_config, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ ntlm_cmds, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ authenticate_user, /* check_user_id */ check_user_access, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ };