"Fossies" - the Fresh Open Source Software Archive

Member "mod_ntlm2-0.1/mod_ntlm.c" (23 Feb 2003, 28621 Bytes) of package /linux/www/apache_httpd_modules/old/mod_ntlm2-0.1.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* 
    2  * mod_ntlm.c: NTLM authentication module for Apache/Unix
    3  * Version 0.1
    4  * 
    5  *     "This product includes software developed by the Apache Group
    6  *     for use in the Apache HTTP server project (http://www.apache.org/)."
    7  * 
    8  * Based on 
    9  * mod_ntlm.c for Win32 by Tim Costello <tim.costello@bigfoot.com>
   10  * pam_smb by Dave Airlie <Dave.Airlie@ul.ie>
   11  *
   12  * This code is copyright 2000 Andreas Gal <agal@uwsp.edu>.
   13  * Visit http://modntlm.sourceforge.net/ for code updates.
   14  * 
   15  * THIS SOFTWARE IS PROVIDED ``AS IS`` AND ANY EXPRESSED OR IMPLIED
   16  * WARRANTIES ARE DISCLAIMED. 
   17  * 
   18  * This code may be freely distributed, as long the above notices are
   19  * reproduced.
   20  *
   21  *  $Id: mod_ntlm.c,v 1.3.4.2 2003/02/23 15:58:02 casz Exp $
   22  *
   23  */
   24 
   25 #define VERSION "mod_ntlm2-0.1"
   26 
   27 #define USE_APACHE_PROVIDED_UU_FUNCTIONS
   28 #define myLOG_ERROR
   29 
   30 #ifdef myLOG_ERROR
   31 #define DEBUG(x) ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r, x " %u %u", (unsigned) r->connection, (unsigned) getpid())
   32 #else
   33 #define DEBUG(x)
   34 #endif /*myLOG_ERROR*/
   35 
   36 #include "mod_ntlm.h"
   37 
   38 #ifdef myLOG_ERROR
   39 #define LOG
   40 
   41 #include <stdarg.h>
   42 static void
   43 log(const request_rec * r, const char *format,...)
   44 {
   45     va_list ap;
   46     char *s;
   47 
   48     if ((s = (char *) malloc(2048)) == NULL)
   49         return;
   50     va_start(ap, format);
   51     vsprintf(s, format, ap);
   52     va_end(ap);
   53     ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_NOTICE, 0, r, s);
   54     free(s);
   55 }
   56 static void
   57 flog(const char *format,...)
   58 {
   59     va_list ap;
   60     char *s;
   61     FILE *f;
   62 
   63     if ((s = (char *) malloc(2048)) == NULL)
   64         return;
   65     va_start(ap, format);
   66     vsprintf(s, format, ap);
   67     va_end(ap);
   68     if ((f = fopen("/tmp/mod_ntlm.log", "a")) != NULL) {
   69         fputs(s, f);
   70         fputs("\n", f);
   71         fclose(f);
   72     }
   73     free(s);
   74 }
   75 #else
   76 #undef LOG
   77 #endif /*myLOG_ERROR*/
   78 
   79 /* +csz */
   80 #include <ctype.h>
   81 #include <sys/socket.h>
   82 #include <netinet/in.h>
   83 #include <arpa/inet.h>
   84 /* -csz */
   85 
   86 #include "ntlmssp.inc.c"
   87 
   88 #include "smbval/byteorder.h"
   89 #include "smbval/std-defines.h"
   90 #include "smbval/std-includes.h"
   91 #include "smbval/smblib-common.h"
   92 #include "smbval/smblib-priv.h"
   93 #include "smbval/rfcnb-common.h"
   94 #include "smbval/rfcnb-error.h"
   95 #include "smbval/rfcnb-priv.h"
   96 #include "smbval/rfcnb-util.h"
   97 #include "smbval/rfcnb-io.h"
   98 #include "smbval/rfcnb.h"
   99 #include "smbval/valid.h"
  100 
  101 #include "smbval/rfcnb-io.inc.c"
  102 #include "smbval/rfcnb-util.inc.c"
  103 #include "smbval/session.inc.c"
  104 #include "smbval/smbdes.inc.c"
  105 #include "smbval/smbencrypt.inc.c"
  106 #include "smbval/smblib-util.inc.c"
  107 #include "smbval/smblib.inc.c"
  108 #include "smbval/valid.inc.c"
  109 
  110 static const command_rec ntlm_cmds[] = {
  111     AP_INIT_FLAG
  112     ( "NTLMAuth",  ap_set_flag_slot,
  113       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_on),
  114       OR_AUTHCFG,
  115       "set to 'on' to activate NTLM authentication here" ),
  116 
  117     AP_INIT_TAKE1
  118     ("AuthNTGroups", ap_set_string_slot,
  119       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_grpfile),
  120       OR_AUTHCFG,
  121        "text file containing (NT) group names and member user IDs"),
  122 
  123     AP_INIT_FLAG
  124     ( "NTLMBasicAuth", ap_set_flag_slot,
  125       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_basic_on),
  126       OR_AUTHCFG,
  127       "set to 'on' to allov Basic authentication too" ),
  128 
  129     AP_INIT_TAKE1
  130     ( "NTLMBasicRealm", ap_set_string_slot,
  131       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_basic_realm),
  132       OR_AUTHCFG,
  133       "realm to use for Basic authentication" ),
  134 
  135     AP_INIT_FLAG
  136     ( "NTLMAuthoritative", ap_set_flag_slot,
  137       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_authoritative),
  138       OR_AUTHCFG,
  139       "set to 'off' to allow access control to be passed along to lower "
  140       "modules if the UserID is not known to this module" ),
  141 
  142     AP_INIT_TAKE1
  143     ( "NTLMDomain", ap_set_string_slot,
  144       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_domain),
  145       OR_AUTHCFG,
  146       "set to the domain you want users authenticated against for cleartext "
  147       "authentication - if not specified, the local machine, then all trusted "
  148       " domains are checked" ),
  149 
  150     AP_INIT_TAKE1
  151     ( "NTLMServer", ap_set_string_slot,
  152       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_server),
  153       OR_AUTHCFG,
  154       "set to the NT server to contact to authenticate users" ),
  155 
  156     AP_INIT_TAKE1
  157     ( "NTLMBackup", ap_set_string_slot,
  158       (void *)APR_OFFSETOF(ntlm_config_rec, ntlm_backup),
  159       OR_AUTHCFG,
  160       "set to the alternate NT server to contact to authenticate users" ),
  161 
  162     { NULL }
  163 };
  164 
  165 static ntlm_connection_rec *ntlm_connection = NULL;
  166 
  167 static void * 
  168 create_ntlm_dir_config( apr_pool_t *p, char *d)
  169 {
  170     ntlm_config_rec *crec
  171         = (ntlm_config_rec *) apr_pcalloc(p, sizeof(ntlm_config_rec));
  172 
  173     /* Set the defaults. */
  174     crec->ntlm_authoritative = 1;
  175     crec->ntlm_on = 0;
  176     crec->ntlm_basic_on = 0;
  177     crec->ntlm_basic_realm = "REALM";
  178     crec->ntlm_server = "SERVER";
  179     crec->ntlm_backup = "";
  180     crec->ntlm_domain = "DOMAIN";
  181     crec->ntlm_grpfile = NULL; /* rit, group file added */
  182 
  183     return crec;
  184 }
  185 
  186 #ifdef USE_APACHE_PROVIDED_UU_FUNCTIONS
  187 
  188 static void *
  189 uudecode_binary(apr_pool_t *p, const char *bufcoded, int *nbytesdecoded)
  190 {
  191     char *decoded;
  192 
  193     decoded = (char *) apr_palloc(p, 1 + apr_base64_decode_len(bufcoded));
  194     *nbytesdecoded = apr_base64_decode(decoded, bufcoded);
  195     decoded[*nbytesdecoded] = '\0'; /* make binary sequence into string */
  196 
  197     return decoded;
  198 }
  199 
  200 static char *
  201 uuencode_binary(apr_pool_t *p, unsigned char *string, int len)
  202 {
  203     char *encoded;
  204 
  205     encoded = (char *) apr_palloc(p, 1 + apr_base64_encode_len(len));
  206     len = apr_base64_encode(encoded, string, len);
  207     encoded[len] = '\0'; /* make binary sequence into string */
  208 
  209     return encoded;
  210 }
  211 
  212 #else
  213 /* UUENCODE / DECODE TABLES */
  214 
  215 static const unsigned char pr2six[256] =
  216 {
  217     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  218     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  219     64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54,
  220     55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3,
  221     4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
  222     22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32,
  223     33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
  224     50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  225     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  226     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  227     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  228     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  229     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  230     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
  231     64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
  232 };
  233 
  234 static const char basis_64[]
  235     = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  236 
  237 /* 
  238  * UUENCODE / DECODE routines below taken from apache source code
  239  */
  240 static void *
  241 uudecode_binary(apr_pool_t * p, const char *bufcoded, int *nbytesdecoded)
  242 {
  243     register const unsigned char *bufin;
  244     register char *bufplain;
  245     register unsigned char *bufout;
  246     register int nprbytes;
  247 
  248     /* Strip leading whitespace. */
  249 
  250     while (*bufcoded == ' ' || *bufcoded == '\t')
  251         bufcoded++;
  252 
  253     /* Figure out how many characters are in the input buffer.
  254      * Allocate this many from the per-transaction pool for the
  255      * result. */
  256 #ifndef CHARSET_EBCDIC
  257     bufin = (const unsigned char *) bufcoded;
  258     while (pr2six[*(bufin++)] <= 63) ;
  259     nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  260     *nbytesdecoded = ((nprbytes + 3) / 4) * 3;
  261 
  262     bufplain = apr_palloc(p, *nbytesdecoded + 1);
  263     bufout = (unsigned char *) bufplain;
  264 
  265     bufin = (const unsigned char *) bufcoded;
  266 
  267     while (nprbytes > 0) {
  268         *(bufout++) =
  269             (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  270         *(bufout++) =
  271             (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  272         *(bufout++) =
  273             (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  274         bufin += 4;
  275         nprbytes -= 4;
  276     }
  277 
  278     if (nprbytes & 03) {
  279         if (pr2six[bufin[-2]] > 63)
  280             *nbytesdecoded -= 2;
  281         else
  282             *nbytesdecoded -= 1;
  283     }
  284     bufplain[*nbytesdecoded] = '\0';
  285 #else /* CHARSET_EBCDIC */
  286     bufin = (const unsigned char *) bufcoded;
  287     while (pr2six[os_toascii[(unsigned char) *(bufin++)]] <= 63) ;
  288     nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
  289     *nbytesdecoded = ((nprbytes + 3) / 4) * 3;
  290 
  291     bufplain = apr_palloc(p, *nbytesdecoded + 1);
  292     bufout = (unsigned char *) bufplain;
  293 
  294     bufin = (const unsigned char *) bufcoded;
  295 
  296     while (nprbytes > 0) {
  297         *(bufout++)
  298             = os_toebcdic[(unsigned char) (pr2six[os_toascii[*bufin]]
  299                                            << 2 | pr2six[os_toascii[bufin[1]]]
  300                                            >> 4)];
  301         *(bufout++)
  302             = os_toebcdic[(unsigned char) (pr2six[os_toascii[bufin[1]]]
  303                                            << 4 | pr2six[os_toascii[bufin[2]]]
  304                                            >> 2)];
  305         *(bufout++)
  306             = os_toebcdic[(unsigned char) (pr2six[os_toascii[bufin[2]]]
  307                                          << 6 | pr2six[os_toascii[bufin[3]]])];
  308         bufin += 4;
  309         nprbytes -= 4;
  310     }
  311 
  312     if (nprbytes & 03) {
  313         if (pr2six[os_toascii[bufin[-2]]] > 63)
  314             *nbytesdecoded -= 2;
  315         else
  316             *nbytesdecoded -= 1;
  317     }
  318     bufplain[*nbytesdecoded] = '\0';
  319 #endif /* CHARSET_EBCDIC */
  320     return bufplain;
  321 }
  322 
  323 static char *
  324 uuencode_binary(apr_pool_t *a, unsigned char *string, int len)
  325 {
  326     int i;
  327     char *p;
  328     char *encoded = (char *) apr_palloc(a, ((len + 2) / 3 * 4) + 1);
  329 
  330     p = encoded;
  331 #ifndef CHARSET_EBCDIC
  332     for (i = 0; i < len - 2; i += 3) {
  333         *p++ = basis_64[(string[i] >> 2) & 0x3F];
  334         *p++ = basis_64[((string[i] & 0x3) << 4)
  335                        | ((int) (string[i + 1] & 0xF0) >> 4)];
  336         *p++ = basis_64[((string[i + 1] & 0xF) << 2)
  337                        | ((int) (string[i + 2] & 0xC0) >> 6)];
  338         *p++ = basis_64[string[i + 2] & 0x3F];
  339     }
  340     if (i < len) {
  341         *p++ = basis_64[(string[i] >> 2) & 0x3F];
  342         *p++ = basis_64[((string[i] & 0x3) << 4)
  343                        | ((int) (string[i + 1] & 0xF0) >> 4)];
  344         if (i == (len - 2))
  345             *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
  346         else
  347             *p++ = '=';
  348         *p++ = '=';
  349     }
  350 #else /* CHARSET_EBCDIC */
  351     for (i = 0; i < len - 2; i += 3) {
  352         *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F];
  353         *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4)
  354                        | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)];
  355         *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2)
  356                        | ((int) (os_toascii[string[i + 2]] & 0xC0) >> 6)];
  357         *p++ = basis_64[os_toascii[string[i + 2]] & 0x3F];
  358     }
  359     if (i < len) {
  360         *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F];
  361         *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4)
  362                        | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)];
  363         if (i == (len - 2))
  364             *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2)];
  365         else
  366             *p++ = '=';
  367         *p++ = '=';
  368     }
  369 #endif /* CHARSET_EBCDIC */
  370 
  371     *p = '\0';
  372     return encoded;
  373 }
  374 #endif /* USE_APACHE_PROVIDED_UU_FUNCTIONS */
  375 
  376 static apr_status_t 
  377 cleanup_ntlm_connection(void *unused)
  378 {
  379     if (ntlm_connection->handle) {
  380         NTLM_Disconnect(ntlm_connection->handle);
  381         ntlm_connection->handle = NULL;
  382     }
  383     ntlm_connection = NULL; /* will be freed with r->connection's context */
  384     return APR_SUCCESS; // csz
  385 }
  386 
  387 static void 
  388 note_ntlm_auth_failure(request_rec * r)
  389 {
  390     ntlm_config_rec *crec
  391         = (ntlm_config_rec *) ap_get_module_config(r->per_dir_config,
  392                                                    &ntlm_module);
  393     unsigned char *line;
  394 
  395     line = apr_pstrdup(r->pool, NTLM_AUTH_NAME);
  396 
  397     apr_table_setn(r->err_headers_out,
  398                   r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
  399                   line);
  400     if (crec->ntlm_basic_on) {
  401         line = apr_pstrcat(r->pool,
  402                           "Basic realm=\"", crec->ntlm_basic_realm, "\"",
  403                           NULL);
  404         apr_table_addn(r->err_headers_out,
  405                       r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
  406                       line);
  407     }
  408 }
  409 
  410 static void 
  411 log_ntlm_logon_denied(request_rec * r)
  412 {
  413     ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
  414                   "NTLM/SMB user \"%s\": authentication failure for \"%s\"",
  415                   ntlm_connection->user, r->uri);
  416 }
  417 
  418 
  419 ntlmssp_info_rec *
  420 get_ntlm_header(request_rec * r, ntlm_config_rec * crec)
  421 {
  422     const char *auth_line = apr_table_get(r->headers_in,
  423                                          r->proxyreq ? "Proxy-Authorization"
  424                                          : "Authorization");
  425     unsigned char *msg;
  426     int len, foo;
  427     unsigned ntlmssp_flags=0;
  428     ntlmssp_info_rec *ntlmssp;
  429 
  430     /* fhz 16-10-01: take care of unicode strings */
  431     if (ntlm_connection->ntlmssp_flags)
  432             ntlmssp_flags=ntlm_connection->ntlmssp_flags;
  433 
  434     if (!auth_line) {
  435         DEBUG("no auth_line");
  436         return NULL;
  437     }
  438     if (strcmp(ap_getword_white(r->pool, &auth_line), NTLM_AUTH_NAME)) {
  439         DEBUG("ap_getword_white failed");
  440         return NULL;
  441     }
  442 #ifdef LOG
  443     log(r, "got auth_line \"%s\"",auth_line);
  444 #endif
  445     msg = uudecode_binary(r->connection->pool, auth_line, &len);
  446     ntlmssp = apr_pcalloc(r->pool, sizeof(ntlmssp_info_rec));
  447     if ((foo = ntlm_decode_msg(r, ntlmssp, msg, len,&ntlmssp_flags)) != 0) {
  448         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
  449                       "ntlm_decode_msg failed: type: %d, host: \"%s\", "
  450                       "user: \"%s\", domain: \"%s\", error: %d",
  451                       ntlmssp->msg_type,
  452                       ntlmssp->host, ntlmssp->user, ntlmssp->domain,
  453                       foo);
  454         return NULL;
  455     }
  456 
  457     /* fhz 16-10-01: take care of unicode strings */
  458     if (ntlmssp_flags)
  459         ntlm_connection->ntlmssp_flags=ntlmssp_flags;
  460 #ifdef LOG
  461     log(r, "got header with host \"%s\", domain \"%s\"",
  462         ntlmssp->host, ntlmssp->domain);
  463 #endif
  464     return ntlmssp;
  465 }
  466 
  467 
  468 
  469 static int 
  470 send_ntlm_challenge(request_rec * r, ntlm_config_rec * crec, int win9x)
  471 {
  472     struct ntlm_msg2 msg;
  473     struct ntlm_msg2_win9x msg_win9x;
  474     unsigned char *challenge;
  475     unsigned int l;
  476 
  477     DEBUG("received msg1");
  478 
  479     if (ntlm_connection->handle == NULL) {
  480         ntlm_connection->nonce = apr_pcalloc(r->connection->pool, NONCE_LEN);
  481         ntlm_connection->handle = NTLM_Connect(crec->ntlm_server,
  482               crec->ntlm_backup, crec->ntlm_domain, ntlm_connection->nonce);
  483 
  484         if (!ntlm_connection->handle) {
  485         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
  486             "send_ntlm_challenge: no conn. handle...trouble communicating with PDC/BDC? returning internal server error");
  487             return HTTP_INTERNAL_SERVER_ERROR;
  488         }
  489     }
  490     if (win9x==0) {
  491         ntlm_encode_msg2(ntlm_connection->nonce, &msg);
  492         challenge = uuencode_binary(r->pool, (unsigned char *) &msg, sizeof(msg));
  493     }
  494     else    {
  495         l=ntlm_encode_msg2_win9x(ntlm_connection->nonce, &msg_win9x,
  496                 crec->ntlm_domain,ntlm_connection->ntlmssp_flags);
  497         challenge = uuencode_binary(r->pool, (unsigned char *)&msg_win9x,l);
  498     }
  499 
  500     apr_table_setn(r->err_headers_out,
  501                   r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
  502                   apr_psprintf(r->pool, "%s %s", NTLM_AUTH_NAME, challenge));
  503 #ifdef LOG
  504     log(r, "send %s \"%s %s\"",r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate", NTLM_AUTH_NAME, challenge);
  505 #endif
  506 
  507     return HTTP_UNAUTHORIZED;
  508 }
  509 
  510 static int 
  511 ntlm_check_response(request_rec * r, ntlm_config_rec * crec,
  512                     ntlmssp_info_rec * ntlmssp)
  513 {
  514     DEBUG("received msg3");
  515 
  516     if (ntlm_connection->auth_ok && ntlm_connection->user) {
  517         /* user has already valid credentials */
  518         if ((!strcmp(ntlm_connection->user, ntlmssp->user))
  519             && (!strcmp(ntlm_connection->domain, ntlmssp->domain))
  520             && (!memcmp(ntlm_connection->password, ntlmssp->nt, RESP_LEN))) {
  521             DEBUG("silent reauthentication");
  522             /* silently accept login with same credentials */
  523             r->user = apr_pstrdup(r->connection->pool,
  524                                   ntlm_connection->user);
  525             r->ap_auth_type = apr_pstrdup(r->connection->pool,
  526                                           NTLM_AUTH_NAME);
  527             return OK;
  528         }
  529     }
  530     if (!ntlm_connection->handle) {
  531         DEBUG("PDC connection already closed");
  532         note_ntlm_auth_failure(r);
  533         return HTTP_UNAUTHORIZED;
  534     }
  535     if (!*ntlmssp->user)
  536         return HTTP_BAD_REQUEST;
  537     ntlm_connection->user = apr_pstrdup(r->connection->pool, ntlmssp->user);
  538     ntlm_connection->domain = (*ntlmssp->domain)
  539         ? apr_pstrdup(r->connection->pool, ntlmssp->domain)
  540         : crec->ntlm_domain;
  541     ntlm_connection->password = apr_pcalloc(r->connection->pool, RESP_LEN);
  542     memcpy(ntlm_connection->password, ntlmssp->nt, RESP_LEN);
  543 
  544     DEBUG("authenticating user against DC");
  545 
  546     if (NTLM_Auth(ntlm_connection->handle,
  547                   ntlm_connection->user,
  548                   ntlm_connection->password, 1) == NTV_LOGON_ERROR) {
  549         log_ntlm_logon_denied(r);
  550         note_ntlm_auth_failure(r);
  551         ntlm_connection->auth_ok = 0;
  552         return HTTP_UNAUTHORIZED;
  553     }
  554     ntlm_connection->auth_ok = 1;
  555     DEBUG("authentication OK!");
  556     /* NTLM_Disconnect(ntlm_connection->handle); ntlm_connection->handle = 
  557      * NULL; */
  558     r->user = apr_pstrdup(r->connection->pool,
  559                           ntlm_connection->user);
  560     r->ap_auth_type = apr_pstrdup(r->connection->pool,
  561                                   NTLM_AUTH_NAME);
  562 
  563 #ifdef LOG
  564     log(r, "NTLM/SMB user: \"%s\\%s\": authentication OK.",
  565         ntlm_connection->domain, ntlm_connection->user);
  566 #endif
  567 
  568     return OK;
  569 }
  570 
  571 
  572 /* rit, 9.10.00 
  573 *       code from mod_auth.c 
  574 */
  575 static apr_table_t *groups_for_user(apr_pool_t *p, char *user, char *grpfile)
  576 {
  577     ap_configfile_t *f;
  578     apr_table_t *grps = apr_table_make(p, 15);
  579     apr_pool_t *sp;
  580     char l[MAX_STRING_LEN];
  581     const char *group_name, *ll, *w;
  582     apr_status_t status;
  583 
  584     if ((status = ap_pcfg_openfile(&f, p, grpfile)) != APR_SUCCESS ) {
  585         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, NULL,
  586                       "Could not open group file: %s", grpfile);
  587         return NULL;
  588     }
  589 
  590     apr_pool_sub_make(&sp,p,NULL);
  591 
  592     while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
  593         if ((l[0] == '#') || (!l[0]))
  594             continue;
  595         ll = l;
  596         apr_pool_clear(sp);
  597 
  598         group_name = ap_getword(sp, &ll, ':');
  599 
  600         while (ll[0]) {
  601             w = ap_getword_conf(sp, &ll);
  602             if (!strcmp(w, user)) {
  603                 apr_table_setn(grps, apr_pstrdup(p, group_name), "in");
  604                 break;
  605             }
  606         }
  607     }
  608     ap_cfg_closefile(f);
  609     apr_pool_destroy(sp);
  610     return grps;
  611 }
  612 
  613 /* SHH 2000-05-10: added the following method by copying from several
  614  * places (this file and apache sources).  very little is my own work.
  615  * *sigh*; i've become a thief on my older days. */
  616 static int 
  617 authenticate_basic_user(request_rec * r, ntlm_config_rec * crec,
  618                         const char *auth_line_after_Basic)
  619 {
  620     char *sent_user, *sent_pw, *sent_domain = "", *s;
  621 
  622     while (*auth_line_after_Basic == ' ' || *auth_line_after_Basic == '\t')
  623         auth_line_after_Basic++;
  624 
  625     sent_user = ap_pbase64decode(r->pool, auth_line_after_Basic);
  626     if (sent_user != NULL) {
  627         if ((sent_pw = strchr(sent_user, ':')) != NULL) {
  628             *sent_pw = '\0';
  629             ++sent_pw;
  630         } else
  631             sent_pw = "";
  632         if ((s = strchr(sent_user, '\\')) != NULL
  633             || (s = strchr(sent_user, '/')) != NULL) {
  634             /* domain supplied as part of the user name. */
  635             *s = '\0';
  636             sent_domain = sent_user;
  637             sent_user = s + 1;
  638             /* check that we are willing to serve this domain. */
  639             if (strcasecmp(sent_domain, crec->ntlm_domain) != 0) {
  640                 /* domain mismatch. */
  641                 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
  642                               "Basic/SMB user \"%s\\%s\": "
  643                               "authentication failure; "
  644                               "domain not \"%s\".",
  645                               sent_domain, sent_user, crec->ntlm_domain);
  646                 return HTTP_UNAUTHORIZED;
  647             }
  648         }
  649     } else
  650         sent_user = sent_pw = "";
  651 
  652     if (Valid_User(sent_user, sent_pw,
  653                    crec->ntlm_server, crec->ntlm_backup,
  654                    crec->ntlm_domain) != NTV_NO_ERROR) {
  655         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
  656                       "Basic/SMB user \"%s\\%s\": "
  657                       "authentication failure for \"%s\"",
  658                       sent_domain, sent_user, r->uri);
  659         ap_note_basic_auth_failure(r);
  660         return HTTP_UNAUTHORIZED;
  661     }
  662     /* Note that this allocation has to be made from
  663      * r->connection->pool because it has the lifetime of the
  664      * connection.  The other allocations are temporary and can be
  665      * tossed away any time. */
  666     r->user = apr_pstrcat(r->connection->pool, sent_user, NULL);
  667     r->ap_auth_type = "Basic";
  668 
  669 #ifdef LOG
  670     log(r, "Basic/SMB user: \"%s\\%s\": authentication OK.",
  671         sent_domain, sent_user);
  672 #endif
  673 
  674     return OK;
  675 }
  676 
  677 static int 
  678 authenticate_ntlm_user(request_rec * r, ntlm_config_rec * crec)
  679 {
  680     ntlmssp_info_rec *ntlmssp;
  681     int win9x=0;
  682 
  683     /* If this is the first request with this connection, then create
  684      * a ntlm_connection entry for it. It will be cleaned up when the
  685      * connection is dropped */
  686     if (ntlm_connection == NULL) {
  687         DEBUG("creating new ntlm_connection");
  688         ntlm_connection = apr_pcalloc(r->connection->pool,
  689                                      sizeof(ntlm_connection_rec));
  690         ntlm_connection->auth_ok = 0;
  691         ntlm_connection->ntlmssp_flags = 0;
  692         apr_pool_cleanup_register(r->connection->pool, 0, cleanup_ntlm_connection,
  693                             apr_pool_cleanup_null);
  694     }
  695     if ((ntlmssp = get_ntlm_header(r, crec)) == NULL) {
  696         note_ntlm_auth_failure(r);
  697         DEBUG("missing/corrupt NTLM header");
  698         return HTTP_UNAUTHORIZED;
  699     }
  700     switch (ntlmssp->msg_type) {
  701       case 1:
  702      /* Win9x: in msg1, host and domain never sent */
  703      if ((strcmp(ntlmssp->host,"")==0) && (strcmp(ntlmssp->domain,"")==0))
  704         win9x=1;
  705           return send_ntlm_challenge(r, crec,win9x);
  706       case 3:
  707           return ntlm_check_response(r, crec, ntlmssp);
  708     }
  709     DEBUG("authenticate_ntlm_user: bad request");
  710     return HTTP_BAD_REQUEST;
  711 }
  712 
  713 static int 
  714 authenticate_user(request_rec * r)
  715 {
  716     ntlm_config_rec *crec =
  717     (ntlm_config_rec *) ap_get_module_config(r->per_dir_config,
  718                                              &ntlm_module);
  719     const char *auth_line = apr_table_get(r->headers_in,
  720                                          r->proxyreq ? "Proxy-Authorization"
  721                                          : "Authorization");
  722 
  723     if (!crec->ntlm_on) {
  724         return DECLINED;
  725     }
  726 
  727     if (!auth_line) {
  728         note_ntlm_auth_failure(r);
  729         return HTTP_UNAUTHORIZED;
  730     }
  731     if (crec->ntlm_basic_on
  732         && strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic") == 0) {
  733         return authenticate_basic_user(r, crec, auth_line);
  734     }
  735 
  736     return authenticate_ntlm_user(r, crec);
  737 
  738 }
  739 
  740 static int 
  741 check_user_access(request_rec * r)
  742 {
  743     ntlm_config_rec *crec =
  744         (ntlm_config_rec *) ap_get_module_config(r->per_dir_config,
  745                                                  &ntlm_module);
  746     char *user = r->user;
  747     int m = r->method_number;
  748     int method_restricted = 0;
  749     register int x;
  750     const char *t, *w;
  751     apr_table_t *grpstatus; /* rit */
  752     apr_table_t *e = r->subprocess_env; /* rit */
  753     const apr_array_header_t *reqs_arr = ap_requires(r);
  754     require_line *reqs;
  755 
  756     /* 
  757      * If the switch isn't on, don't bother. 
  758      */
  759     if (!crec->ntlm_on) {
  760         return DECLINED;
  761     }
  762     if (!reqs_arr) {
  763         return OK;
  764     }
  765 
  766 
  767     reqs = (require_line *) reqs_arr->elts;
  768 
  769     /* 
  770      * Did we authenticate this user?
  771      * If not, we don't want to do user/group checking.
  772      */
  773     if (strcmp(r->ap_auth_type, NTLM_AUTH_NAME) == 0
  774         && (!ntlm_connection || !ntlm_connection->auth_ok)) {
  775         return DECLINED;
  776     }
  777     /* rit, get groups for user */
  778     if (crec->ntlm_grpfile)
  779         grpstatus = groups_for_user(r->pool, user, crec->ntlm_grpfile);
  780     else
  781         grpstatus = NULL;
  782 
  783     for (x = 0; x < reqs_arr->nelts; x++) {
  784         if (!(reqs[x].method_mask & (1 << m)))
  785             continue;
  786 
  787         method_restricted = 1;
  788 
  789         t = reqs[x].requirement;
  790         w = ap_getword_white(r->pool, &t);
  791         if (!strcmp(w, "valid-user"))
  792             return OK;
  793         if (!strcmp(w, "user")) {
  794             while (t[0]) {
  795                 w = ap_getword_conf(r->pool, &t);
  796                 if (!strcmp(user, w))
  797                     return OK;
  798             }
  799         }
  800 /* rit, 9.10.00: coding aus mod_auth.c */
  801         else if (!strcmp(w, "group")) {
  802             if (!grpstatus) {
  803                 return DECLINED; /* DBM group?  Something else? */
  804             }
  805             while (t[0]) {
  806                 w = ap_getword_conf(r->pool, &t);
  807                 if (apr_table_get(grpstatus, w)) {
  808                     apr_table_setn(e, "REMOTE_NTGROUP", w);
  809                     return OK;
  810                 }
  811             }
  812 /* rit, finish group testng */
  813         } else if (crec->ntlm_authoritative) {
  814             /* if we aren't authoritative, any require directive could
  815              * be valid even if we don't grok it.  However, if we are
  816              * authoritative, we can warn the user they did something
  817              * wrong. That something could be a missing
  818              * "AuthAuthoritative off", but more likely is a typo in
  819              * the require directive. */
  820             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
  821                           "access to \"%s\" failed, reason: "
  822                           "unknown require directive:"
  823                           "\"%s\"",
  824                           r->uri, reqs[x].requirement);
  825         }
  826     }
  827 
  828     if (!method_restricted) {
  829         return OK;
  830     }
  831     if (!(crec->ntlm_authoritative)) {
  832         return DECLINED;
  833     }
  834     ap_log_rerror(APLOG_MARK, APLOG_NOERRNO | APLOG_ERR, 0, r,
  835                   "access to \"%s\" failed, reason: "
  836                   "user \"%s\" not allowed access.",
  837                   r->uri, user);
  838 
  839     note_ntlm_auth_failure(r);
  840     /* 
  841      * We return HTTP_UNAUTHORIZED (401) because the client may wish
  842      * to authenticate using a different scheme, or a different
  843      * username. If this works, they can be granted access. If we
  844      * returned HTTP_FORBIDDEN (403) then they don't get a second
  845      * chance.
  846      */
  847     return HTTP_UNAUTHORIZED;
  848 }
  849 
  850 /*
  851  * This function is a callback and it declares what other functions
  852  * should be called for request processing and configuration requests.
  853  * This callback function declares the Handlers for other events.
  854  */
  855 static void modntlm_register_hooks (apr_pool_t *p)
  856 {
  857     // I think this is the call to make to register a handler 
  858         // for method calls (GET PUT et. al.).
  859     // We will ask to be last so that the comment has a higher tendency to
  860     // go at the end.
  861 
  862     ap_hook_check_user_id(authenticate_user,
  863                               NULL,NULL,APR_HOOK_MIDDLE);
  864 
  865     ap_hook_auth_checker(check_user_access,
  866                               NULL,NULL,APR_HOOK_MIDDLE);
  867 
  868 }
  869 
  870 
  871 
  872 module AP_MODULE_DECLARE_DATA ntlm_module = {
  873     STANDARD20_MODULE_STUFF,
  874     create_ntlm_dir_config, /* create per-directory config structures */
  875     NULL, /* merge per-directory config structures  */
  876     NULL, /* create per-server config structures    */
  877     NULL, /* merge per-server config structures     */
  878     ntlm_cmds, /* command handlers */
  879     modntlm_register_hooks, /* register hooks */
  880 };