"Fossies" - the Fresh Open Source Software Archive 
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 };