Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afsweb / apache_afs_client.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 /*
11 * Implements most of the client side web authentication protocol
12 */
13
14 /*
15 */
16
17 #include "apache_afs_utils.h"
18 #include "apache_afs_cache.h"
19
20 #include "AFS_component_version_number.c"
21 #include "apache_api.h"
22
23 #define afsassert(str) if(!(str)) { fprintf(stderr, "afs module: assertion failed:%s\t%d\n",__FILE__,__LINE__) ; return SERVER_ERROR; }
24
25 #define MAXBUFF 1024
26
27 #define APACHEAFS_MAX_PATH 1024 /* Maximum path length */
28 #define APACHEAFS_USERNAME_MAX 64 /* Maximum username length */
29 #define APACHEAFS_PASSWORD_MAX 64 /* Maximum password length */
30 #define APACHEAFS_CELLNAME_MAX 64 /* Maximum cellname length */
31 #define APACHEAFS_MOUNTPTLEN_MAX 64 /* Max mountpoint length */
32
33 #ifndef MAX
34 #define MAX(A,B) ((A)>(B)?(A):(B))
35 #endif /* !MAX */
36 #ifndef MIN
37 #define MIN(A,B) ((A)<(B)?(A):(B))
38 #endif /* !MAX */
39
40 /* */
41 static int setCellAuthHeader(request_rec * r);
42
43 /* Module name for logging stuff */
44 extern const char module_name[];
45
46 /* file descriptors for the pipes for communication with weblog */
47 extern int readPipe;
48 extern int writePipe;
49
50 #ifdef AIX
51 /* lock file descriptor */
52 extern int tempfd;
53 #endif
54
55 /* do we have an authentication field */
56 static int haveAuth = 0;
57
58 /* local cache stuff */
59 static int cache_initialized;
60
61 /* we need the defult cell in several places */
62 static char global_default_cell[APACHEAFS_CELLNAME_MAX];
63
64 /* buffers to keep track of the last authenticated user */
65 static char lastUser[APACHEAFS_USERNAME_MAX];
66 static char lastCell[APACHEAFS_CELLNAME_MAX];
67 static char lastCksum[SHA_HASH_BYTES];
68
69 /* do I have my own PAG */
70 static int doneSETPAG = 0;
71
72 /*
73 * Parse the authorization header for username and password
74 */
75 static int
76 parse_authhdr(request_rec * r, char *user, char *passwd, char *cell,
77 char *defaultCell)
78 {
79 int i;
80 char *p, *t;
81 const char *auth_line = TABLE_GET(r->headers_in, "Authorization");
82
83 if ((r == NULL) || (auth_line == NULL) || (user == NULL)
84 || (passwd == NULL) || (cell == NULL)) {
85 LOG_REASON("AFSAUTH_CLIENT: NULL request record, auth_line, cell,"
86 "user or passwd while parsing authentication header",
87 r->uri, r);
88 return SERVER_ERROR;
89 }
90
91 user[0] = '\0';
92 passwd[0] = '\0';
93 cell[0] = '\0';
94
95 /*
96 * check for basic authentication
97 */
98 if (strncasecmp
99 (GETWORD(r->pool, (const char **)&auth_line, ' '), "basic", 6) != 0) {
100 /* Client tried to authenticate using some other auth scheme */
101 LOG_REASON
102 ("AFSAUTH_CLIENT:client used other than Basic authentication"
103 "scheme", r->uri, r);
104 return SERVER_ERROR;
105 }
106
107 /*
108 * Username and password are base64 encoded
109 */
110 t = UUDECODE(r->pool, auth_line);
111
112 if (t == NULL) {
113 LOG_REASON("AFSAUTH_CLIENT:uudecode failed", r->uri, r);
114 return SERVER_ERROR;
115 }
116
117 /*
118 * Format is user@cell:passwd. The user, cell or passwd may be missing
119 */
120 r->connection->user = GETWORD_NULLS(r->pool, (const char **)&t, ':');
121 r->connection->auth_type = "Basic";
122 strcpy(passwd, t);
123
124 p = r->connection->user;
125
126 for (i = 0; *p != '@' && *p != '\0'; p++, i++) {
127 user[i] = *p;
128 }
129 user[i] = '\0';
130 if (*p == '@') {
131 for (i = 0, p++; *p != '\0'; p++, i++) {
132 cell[i] = *p;
133 }
134 cell[i] = '\0';
135 }
136
137 if (cell[0] == '\0') {
138 strcpy(cell, defaultCell);
139 }
140 return OK;
141 }
142
143 /*
144 * send a buffer to the weblog process over the pipe. Used for sending
145 * authentication credentials to weblog
146 */
147 static int
148 sendBuffer(char *buf, int len)
149 {
150 afsassert(buf);
151 if (write(writePipe, buf, len) != len) {
152 afslog(5,
153 ("%s: Error writing to pipe - %s", module_name,
154 strerror(errno)));
155 return -1;
156 }
157 return 0;
158 }
159
160 /*
161 * packs user credentials into a buffer seperated by newlines and
162 * sends them to weblog
163 */
164 static int
165 sendTo_afsAuthenticator(char *user, char *passwd, char *cell, char *type)
166 {
167 char buf[MAXBUFF];
168
169 afsassert(user);
170 afsassert(passwd);
171 afsassert(cell);
172 afsassert(type);
173
174 sprintf(buf, "%s\n%s\n%s\n%s", type, user, cell, passwd);
175 return sendBuffer(buf, strlen(buf));
176 }
177
178 /*
179 * reads the response from weblog over the pipe
180 */
181 static int
182 recvFrom_afsAuthenticator(char *buf)
183 {
184 int n;
185
186 afsassert(buf);
187 n = read(readPipe, buf, MAXBUFF);
188 if (n < 0) {
189 afslog(5,
190 ("%s: Error reading from pipe - %s", module_name,
191 strerror(errno)));
192 return -1;
193 }
194 return n;
195 }
196
197 #ifndef NO_AFSAPACHE_CACHE
198 /*
199 * check local cache for the token associated with user crds.
200 */
201 static int
202 check_Cache(char *user, char *passwd, char *cell, char *tokenBuf)
203 {
204 char cksum[SHA_HASH_BYTES]; /* for sha checksum for caching */
205
206 /* look up local cache - function in apache_afs_cach.c */
207 weblog_login_checksum(user, cell, passwd, cksum);
208 return weblog_login_lookup(user, cell, cksum, &tokenBuf[0]);
209 }
210
211 /*
212 * put the token and the user credentials in the local cache
213 */
214 static int
215 updateCache(char *user, char *passwd, char *cell, char *tokenBuf,
216 int cacheExpiration)
217 {
218 long expires = 0, testExpires = 0;
219 char cksum[SHA_HASH_BYTES]; /* for sha checksum for caching */
220
221 /* put the token in local cache with the expiration date */
222 expires = getExpiration(tokenBuf);
223 if (expires < 0) {
224 afslog(5,
225 ("%s: Error getting expiration time for cache. Expires %d",
226 module_name, expires));
227 return -1;
228 }
229
230 weblog_login_checksum(user, cell, passwd, cksum);
231
232 if (cacheExpiration == 0) {
233 weblog_login_store(user, cell, cksum, &tokenBuf[0], sizeof(tokenBuf),
234 expires);
235 } else {
236 testExpires = cacheExpiration + time(NULL);
237 weblog_login_store(user, cell, cksum, &tokenBuf[0], sizeof(tokenBuf),
238 MIN(expires, testExpires));
239 }
240 return 0;
241 }
242 #endif /* NO_APACHEAFS_CACHE */
243
244
245 /*
246 * locking routines to provide exclusive access to the pipes
247 */
248 static int
249 start_lock(int fd, int cmd, int type)
250 {
251 struct flock lock;
252 lock.l_type = type;
253 lock.l_start = 0;
254 lock.l_whence = SEEK_SET;
255 lock.l_len = 0;
256 return (fcntl(fd, cmd, &lock));
257 }
258
259 static int
260 test_lock(int fd, int type)
261 {
262 struct flock lock;
263 lock.l_type = type;
264 lock.l_start = 0;
265 lock.l_whence = SEEK_SET;
266 lock.l_len = 0;
267
268 if (fcntl(fd, F_GETLK, &lock) < 0) {
269 return -1;
270 }
271 if (lock.l_type == F_UNLCK) {
272 return 0; /* not locked */
273 }
274 return (lock.l_pid); /* return pid of locking process */
275 }
276
277
278 #define Read_lock(fd) \
279 start_lock(fd, F_SETLK, F_RDLCK)
280 #define Readw_lock(fd) \
281 start_lock(fd, F_SETLKW, F_RDLCK)
282 #define Write_lock(fd) \
283 start_lock(fd, F_SETLK, F_WRLCK)
284 #define Writew_lock(fd) \
285 start_lock(fd, F_SETLKW, F_WRLCK)
286 #define Unlock(fd) \
287 start_lock(fd, F_SETLK, F_UNLCK)
288 #define Is_readlock(fd) \
289 test_lock(fd, F_RDLCK)
290 #define Is_writelock(fd) \
291 test_lock(fd, F_WRLCK)
292
293 /*
294 * communication between this process and weblog - sends user credentials
295 * over a shared pipe (mutex provided using locks) and recieves either a
296 * token or an error message
297 */
298 static int
299 request_Authentication(char *user, char *passwd, char *cell, char *type,
300 char *tokenbuf, char *reason)
301 {
302 int len = 0;
303 int pid;
304 char *temp;
305 int lockfd = 0;
306
307 afsassert(user);
308 afsassert(passwd);
309 afsassert(cell);
310 afsassert(type);
311 afsassert(tokenbuf);
312
313 /*
314 * lock the pipe before beginning communication or in case of AIX it is an
315 * error to attempt to lock a pipe or FIFO (EINVAL) therefore we have to create
316 * a temporary file and use that fd instead
317 */
318 #ifdef AIX
319 lockfd = tempfd;
320 #else
321 lockfd = writePipe;
322 #endif
323
324 while ((pid = Is_writelock(lockfd)) != 0) {
325 if (pid < 0) {
326 afslog(5,
327 ("%s: pid:%d Error locking pipe - %s", module_name,
328 getpid(), strerror(errno)));
329 return -1;
330 }
331 afslog(40,
332 ("%s: pid %d waiting for lock held by pid %d", module_name,
333 getpid(), pid));
334 }
335
336 if (Write_lock(lockfd) == -1) {
337 afslog(5,
338 ("%s: pid:%d Error write lock - %s. Retrying with WriteW",
339 module_name, getpid(), strerror(errno)));
340 if (Writew_lock(lockfd) == -1) {
341 afslog(5,
342 ("%s: pid:%d Error write lock - %s", module_name, getpid(),
343 strerror(errno)));
344 return -1;
345 }
346 }
347
348 if (sendTo_afsAuthenticator(user, passwd, cell, type) == -1) {
349 Unlock(lockfd);
350 afslog(5, ("%s: Error sending authentication info", module_name));
351 return -1;
352 }
353
354 len = recvFrom_afsAuthenticator(tokenbuf);
355
356 /* release the lock */
357 if (Unlock(lockfd)) {
358 afslog(5, ("%s: pid:%d Error unlocking", module_name, getpid()));
359 return -1;
360 }
361
362 if (len > 0) {
363 if (strncmp(tokenbuf, "FAILURE", 7) == 0) {
364 temp = &tokenbuf[7];
365 strncpy(reason, temp, len);
366 return -2;
367 }
368 }
369 return len;
370 }
371
372 /*
373 * pioctl setting token
374 */
375 static int
376 setToken(char *tokenBuf, int tokenLen)
377 {
378 char *temp;
379 afs_int32 i = 0;
380
381 afsassert(tokenBuf);
382
383 /*
384 * set the primary flag only if we haven't done a SETPAG previoulsy
385 * by flipping this bit
386 */
387 if (!doneSETPAG) {
388 #ifdef OLDSETPAG
389 /* skip over the secret token */
390 temp = tokenBuf;
391 memcpy(&i, temp, sizeof(afs_int32));
392 temp += (i + sizeof(afs_int32));
393
394 /* skip over the clear token */
395 memcpy(&i, temp, sizeof(afs_int32));
396 temp += (i + sizeof(afs_int32));
397
398 doneSETPAG = 1;
399 memcpy(&i, temp, sizeof(afs_int32));
400 i |= 0x8000;
401 memcpy(temp, &i, sizeof(afs_int32));
402 temp += sizeof(afs_int32);
403 #endif
404
405 if (do_setpag()) {
406 return -1;
407 }
408 doneSETPAG = 1;
409 }
410 return do_pioctl(tokenBuf, tokenLen, tokenBuf, tokenLen, VIOCSETTOK, NULL,
411 0);
412 }
413
414 /*
415 * Get the token for the primary cell from the cache manager for this
416 * process. Primary cell is the cell at the first index (index 0)
417 */
418 static int
419 getToken(char *buf, int bufsize)
420 {
421 /* get just the ONE token for this PAG from cache manager */
422 afs_int32 i = 0;
423 memcpy((void *)buf, (void *)&i, sizeof(afs_int32));
424 return do_pioctl(buf, sizeof(afs_int32), buf, bufsize, VIOCGETTOK, NULL,
425 0);
426 }
427
428
429 /*
430 * discard all authentication information for this PAG ie. this process
431 */
432 int
433 unlog()
434 {
435 return do_pioctl(0, 0, 0, 0, VIOCUNPAG, NULL, 0);
436 }
437
438
439 /*
440 * Does the following things:
441 * Checks whether there is a Basic Authentication header - obtains creds.
442 * Checks local cache for the token associated with the user creds.
443 * - if no token in cache - obtains token from weblog using pipes
444 * - sets the token and returns appropriate return code
445 * Return values: OK, SERVER_ERROR, AUTH_REQUIRED, FORBIDDEN
446 */
447 int
448 authenticateUser(request_rec * r, char *defaultCell, int cacheExpiration,
449 char *type)
450 {
451 char user[APACHEAFS_USERNAME_MAX];
452 char passwd[APACHEAFS_PASSWORD_MAX];
453 char cell[APACHEAFS_CELLNAME_MAX];
454 char tokenbuf[MAXBUFF];
455 char cksum[SHA_HASH_BYTES];
456 int rc = 0;
457 int i = 0;
458 const char *auth_line;
459 char reason[MAXBUFF]; /* if authentication failed - this is why */
460 char err_msg[MAXBUFF];
461 int userChanged = 0;
462
463 afsassert(r);
464 afsassert(r->uri);
465 afsassert(defaultCell);
466 afsassert(type);
467
468 auth_line = TABLE_GET(r->headers_in, "Authorization");
469
470 if (strcmp(global_default_cell, defaultCell)) {
471 strcpy(global_default_cell, defaultCell);
472 }
473
474 memset(user, 0, APACHEAFS_USERNAME_MAX);
475 memset(passwd, 0, APACHEAFS_PASSWORD_MAX);
476 memset(cell, 0, APACHEAFS_CELLNAME_MAX);
477
478 if (auth_line == NULL) { /* No Authorization field - we don't do anything */
479 /*
480 * No Authorization field recieved - that's fine by us.
481 * go ahead and attempt to service the request and if we get
482 * back FORBIDDEN then we'll take care of it then
483 */
484 afslog(15, ("%s: No authline recieved", module_name));
485 haveAuth = 0;
486 userChanged = 1;
487 memset(lastUser, 0, APACHEAFS_USERNAME_MAX);
488 memset(lastCell, 0, APACHEAFS_CELLNAME_MAX);
489 memset(lastCksum, 0, SHA_HASH_BYTES);
490 rc = unlog();
491 afslog(25,
492 ("%s: pid:%d No Authorization field. Unlogging ...",
493 module_name, getpid()));
494 if (rc) {
495 sprintf(err_msg,
496 "%s: Error unlogging from AFS cell - rc: %d, errno:%d",
497 module_name, rc, errno);
498 LOG_REASON(err_msg, r->uri, r);
499 return SERVER_ERROR;
500 }
501 return OK;
502 }
503
504 /*
505 * We should get here only if there IS an Authorization field
506 */
507
508 if ((rc = parse_authhdr(r, user, passwd, cell, defaultCell)) != 0) {
509 sprintf(err_msg, "%s: Error parsing Authorization Header rc:%d",
510 module_name, rc);
511 LOG_REASON(err_msg, r->uri, r);
512 return rc; /* SERVER ERROR */
513 }
514
515 /*
516 * should get here only after obtaining the username and password and cell
517 * check to make sure anyway
518 */
519 if ((user[0] == '\0') || (cell[0] == '\0') || (passwd[0] == '\0')) {
520 afslog(15,
521 ("%s: pid:%d No username or password or cell. Unlogging.",
522 module_name, getpid()));
523 haveAuth = 0;
524 userChanged = 1;
525 memset(lastUser, 0, APACHEAFS_USERNAME_MAX);
526 memset(lastCell, 0, APACHEAFS_CELLNAME_MAX);
527 memset(lastCksum, 0, SHA_HASH_BYTES);
528 rc = unlog();
529 if (rc) {
530 sprintf(err_msg,
531 "%s: Error unlogging from AFS cell - rc: %d, errno:%d",
532 module_name, rc, errno);
533 LOG_REASON(err_msg, r->uri, r);
534 return SERVER_ERROR;
535 }
536 setCellAuthHeader(r);
537 return AUTH_REQUIRED;
538 }
539 #ifdef DEBUG
540 fprintf(stderr, "Cell:%s\tUser:%s\tPasswd:%s\n", cell, user, passwd);
541 #endif
542
543 /*
544 * compare with previous username/cell/cksum - update it
545 * unlog if required
546 */
547
548 weblog_login_checksum(user, cell, passwd, cksum);
549 if (!haveAuth) {
550 haveAuth = 1;
551 strcpy(lastUser, user);
552 strcpy(lastCksum, cksum);
553 strcpy(lastCell, cell);
554 }
555 if (strcmp(user, lastUser) || strcmp(cell, lastCell)
556 || strcmp(cksum, lastCksum)) {
557 /*
558 * unlog the old user from the cell if a new username/passwd is recievd
559 */
560
561 userChanged = 1;
562 afslog(25,
563 ("%s: pid:%d\tUnlogging user %s from cell%s", module_name,
564 getpid(), lastUser, lastCell));
565 afslog(25, ("%s:New user:%s\t New Cell:%s", module_name, user, cell));
566 afslog(25, ("%s:Trying to get URL:%s", module_name, r->uri));
567 afslog(25, ("%s: Unlogging ....", module_name));
568
569 if (unlog()) {
570 sprintf(err_msg,
571 "%s: Error unlogging from AFS cell - rc: %d, errno:%d",
572 module_name, rc, errno);
573 LOG_REASON(err_msg, r->uri, r);
574 return SERVER_ERROR;
575 }
576 /* change lastUser to this user */
577 strcpy(lastUser, user);
578 strcpy(lastCksum, cksum);
579 strcpy(lastCell, cell);
580 }
581
582 /* strcmp checksums - ie. did the user change */
583 #ifndef NO_AFSAPACHE_CACHE
584 if (!cache_initialized) {
585 token_cache_init();
586 cache_initialized = 1;
587 }
588
589 /* have to check local cache for this name/passwd */
590
591 rc = check_Cache(user, passwd, cell, tokenbuf);
592 if (rc) {
593 /* if found then just send the request without going through
594 * weblog - this means the user has already been authenticated
595 * once and we have a valid token just need to set it -
596 * only if it is different from the token already set. No need to
597 * even unlog because this token is set for the entire PAG which
598 * of course consists of just this child process
599 */
600 afslog(35,
601 ("%s: pid:%d found user %s's token (expires:%d) in cache",
602 module_name, getpid(), user,
603 (getExpiration(tokenbuf) - time(NULL))));
604
605 /* if the user changed then set this token else leave it since it should
606 * be set */
607 if (userChanged) {
608 /* set this token obtained from the local cache */
609 afslog(15,
610 ("%s:pid:%d\t Setting cached token", module_name,
611 getpid()));
612 if (setToken(tokenbuf, rc)) {
613 afslog(5,
614 ("%s: pid:%d Failed to set token obtained from cache."
615 "rc:%d errno:%d Token Expiration:%d", module_name,
616 getpid(), rc, errno,
617 (getExpiration(tokenbuf) - time(NULL))));
618 #ifdef DEBUG_CACHE
619 parseToken(tokenbuf);
620 #endif
621 /*
622 * BUG WORKAROUND: sometimes we fail while setting token
623 * with errno ESRCH indicating the named cell
624 * in the last field of the token is not recognized - but that's
625 * not quite true according to parseToken()!! Possibly corrupted
626 * tokens from the cache?
627 * Anyway we just get a new token from weblog
628 */
629 goto reqAuth;
630 }
631 } /* if userChanged */
632 else {
633 /* if this is a child process getting the request for the first time
634 * then there's no way this guy's got a token for us in which case
635 * getToken should fail with EDOM and that means we should set the token
636 * first and maybe set a static variable saying we have set a token?
637 */
638 char temp[MAXBUFF];
639 if (getToken(temp, sizeof(temp))) {
640 if (errno == EDOM) {
641 /* try setting the cached token */
642 if (setToken(tokenbuf, rc)) {
643 /*
644 * same bug workaround here. ie. go to weblog if setting
645 * the cached token fails.
646 */
647 sprintf(err_msg,
648 "%s: pid:%d Failed to set cached token."
649 "errno:%d rc:%d", module_name, getpid(),
650 errno, rc);
651 LOG_REASON(err_msg, r->uri, r);
652 goto reqAuth;
653 }
654 } else {
655 /* and again for any getToken failure other than EDOM */
656 sprintf(err_msg,
657 "%s: Failed to get token: errno:%d rc:%d",
658 module_name, errno, rc);
659 LOG_REASON(err_msg, r->uri, r);
660 goto reqAuth;
661 }
662 } /* so we already have a token set since the gettoken succeeded */
663 }
664
665 /* to set the REMOTE_USER environment variable */
666 strcpy(r->connection->user, user);
667 return OK;
668 }
669 /*
670 * else - request afs_Authenticator's for it and update local cache
671 * then go about serving the request URI
672 */
673 else {
674 reqAuth:
675 #endif /* NO_AFSAPACHE_CACHE */
676
677 rc = request_Authentication(user, passwd, cell, type, tokenbuf,
678 reason);
679 if (rc > 0) {
680 /* we got back a token from weblog */
681 /* set the token with setToken */
682 if (setToken(tokenbuf, rc)) {
683 sprintf(err_msg,
684 "%s: Failed to set token given by weblog. errno:%d",
685 module_name, errno);
686 LOG_REASON(err_msg, r->uri, r);
687 return SERVER_ERROR;
688 }
689 #ifdef DEBUG_TOKENS
690 system("/usr/afsws/bin/tokens");
691 #endif
692
693 #ifndef NO_AFSAPACHE_CACHE
694 /* update local cache */
695 if (updateCache(user, passwd, cell, tokenbuf, cacheExpiration)) {
696 sprintf(err_msg, "%s: Error updating cache", module_name);
697 LOG_REASON(err_msg, r->uri, r);
698 return SERVER_ERROR;
699 }
700 afslog(15,
701 ("%s: pid:%d\t put user:%s tokens in cache", module_name,
702 getpid(), user));
703 #endif /* NO_AFSAPACHE_CACHE */
704
705 /* now we've got a token, updated the cache and set it so we should
706 * have no problems accessing AFS files - however if we do then
707 * we handle it in afs_accessCheck() when the error comes back
708 */
709
710 /* to set the REMOTE_USER environment variable to the username */
711 strcpy(r->connection->user, user);
712 return OK;
713 } else if (rc == -2) {
714 sprintf(err_msg,
715 ":%s: AFS authentication failed for %s@%s because %s",
716 module_name, user, cell, reason);
717 LOG_REASON(err_msg, r->uri, r);
718 setCellAuthHeader(r);
719 return AUTH_REQUIRED;
720 } else if (rc == -1) {
721 sprintf(err_msg, "%s: Error readiong from pipe. errno:%d",
722 module_name, errno);
723 LOG_REASON(err_msg, r->uri, r);
724 return SERVER_ERROR;
725 }
726
727 else {
728 /*
729 * unknown error from weblog - this should not occur
730 * if afs_Authenticator can't authenticate you, then return FORBIDDEN
731 */
732 sprintf(err_msg,
733 "%s: AFS could not authenticate user %s in cell %s."
734 "Returning FORBIDDEN", module_name, user, cell);
735 LOG_REASON(err_msg, r->uri, r);
736 return FORBIDDEN;
737 }
738 #ifndef NO_AFSAPACHE_CACHE
739 }
740 #endif
741 /* should never get here */
742 LOG_REASON("AFS Authentication: WE SHOULD NEVER GET HERE", r->uri, r);
743 return SERVER_ERROR;
744 }
745
746
747 /*
748 * pioctl call to get the cell name hosting the object specified by path.
749 * returns 0 if successful -1 if failure. Assumes memory has been allocated
750 * for cell. Used to set the www-authenticate header.
751 */
752 static int
753 get_cellname_from_path(char *apath, char *cell)
754 {
755 int rc;
756
757 afsassert(apath);
758 afsassert(cell);
759
760 rc = do_pioctl(NULL, 0, cell, APACHEAFS_CELLNAME_MAX, VIOC_FILE_CELL_NAME,
761 apath, 1);
762 if (rc)
763 afslog(30,
764 ("%s: Error getting cell from path %s. errno:%d rc:%d",
765 module_name, apath, errno, rc));
766 else
767 afslog(30,
768 ("%s: Obtained cell %s from path %s", module_name, cell,
769 apath));
770
771 return rc;
772 }
773
774 /*
775 * obtains the path to the file requested and sets things up to
776 * call get_cell_by_name.
777 * TODO: These could well be combined into one single function.
778 */
779 static int
780 getcellname(request_rec * r, char *buf)
781 {
782 int rc = 0;
783
784 afsassert(r);
785 afsassert(buf);
786
787 if (r->filename) {
788 rc = get_cellname_from_path(r->filename, buf);
789 } else {
790 char path[1024];
791 sprintf(path, "%s/%s", DOCUMENT_ROOT(r), r->uri);
792 rc = get_cellname_from_path(path, buf);
793 }
794 return rc;
795 }
796
797 /*
798 * Returns a part of the url upto the second slash in the buf
799 */
800 static int
801 geturi(request_rec * r, char *buf)
802 {
803 int rc = 0;
804 char *pos;
805 char *end;
806 int i = 0;
807 int max = 2;
808
809 afsassert(r);
810 afsassert(buf);
811
812 memset(buf, 0, APACHEAFS_CELLNAME_MAX);
813 pos = strchr(r->uri, '/');
814 if (pos != NULL) {
815 pos++;
816 for (i = 0; i < max; i++) {
817 end = strchr(pos, '/');
818 if (end != NULL) {
819 int len = strlen(pos) - strlen(end);
820 strcat(buf, "/");
821 strncat(buf, pos, len);
822 afslog(35,
823 ("%s: Getting URI upto second slash buf:%s",
824 module_name, buf));
825 pos += (len + 1);
826 end = strchr(pos, '/');
827 if (end == NULL) {
828 break;
829 }
830 } else {
831 strcat(buf, pos);
832 break;
833 }
834 }
835 } else {
836 strcpy(buf, " ");
837 }
838 return rc;
839 }
840
841 /*
842 * This function recursively parses buf and places the output in msg
843 * Eg. <%c%uUnknown> gets translated to the cellname that the file
844 * resides in, failing which the first part of the uri failing which the
845 * string Unknown
846 */
847 static int
848 parseAuthName_int(request_rec * r, char *buf, char *msg)
849 {
850 char *pos;
851 char *end;
852 int len = 0;
853 int rc = 0;
854 char blank[APACHEAFS_CELLNAME_MAX];
855
856 afsassert(r);
857 afsassert(buf);
858 afsassert(msg);
859
860 memset(blank, 0, sizeof(blank));
861 afslog(50,
862 ("%s: Parsing Authorization Required reply. buf:%s", module_name,
863 buf));
864
865 pos = strchr(buf, '<');
866 if (pos) {
867 len = strlen(pos);
868 pos++;
869 end = strchr(pos, '>');
870 if (end == NULL) {
871 afslog(0,
872 ("%s:Parse error for AUTH_REQUIRED reply - mismatched <",
873 module_name));
874 fprintf(stderr, "Parse Error: mismatched <\n");
875 strncpy(msg, buf, strlen(buf) - len);
876 afslog(0, ("%s: msg:%s", msg));
877 return -1;
878 }
879 end++;
880 if (pos[0] == '%') {
881 pos++;
882 switch (pos[0]) {
883 case 'c':
884 rc = getcellname(r, blank);
885 if (!rc) {
886 strncpy(msg, buf, strlen(buf) - len);
887 strcat(msg, blank);
888 strcat(msg, end);
889 return 0;
890 }
891 break;
892
893 case 'u':
894 rc = geturi(r, blank);
895 if (!rc) {
896 strncpy(msg, buf, strlen(buf) - len);
897 strcat(msg, blank);
898 strcat(msg, end);
899 return 0;
900 }
901 break;
902
903 case 'd':
904 if (global_default_cell != NULL) {
905 strncpy(msg, buf, strlen(buf) - len);
906 strcat(msg, global_default_cell);
907 strcat(msg, end);
908 return 0;
909 }
910 break;
911 }
912 strncpy(msg, buf, strlen(buf) - len);
913 strcat(msg, "<");
914 pos++;
915 strcat(msg, pos);
916 strcpy(buf, msg);
917 memset(msg, 0, 1024);
918 parseAuthName_int(r, buf, msg);
919 return 0;
920 } else {
921 strncpy(msg, buf, strlen(buf) - len);
922 strncat(msg, pos, strlen(pos) - strlen(end) - 1);
923 strcat(msg, end);
924 return 0;
925 }
926 }
927 }
928
929 /*
930 * Parses the entire auth_name string - ie. takes care of multiple
931 * <%...> <%...>
932 */
933 static int
934 parseAuthName(request_rec * r, char *buf)
935 {
936 char *pos;
937 int rc;
938 char msg[1024];
939
940 afsassert(r);
941 afsassert(buf);
942
943 memset(msg, 0, sizeof(msg));
944
945 pos = strchr(buf, '<');
946 while (pos != NULL) {
947 rc = parseAuthName_int(r, buf, msg);
948 if (rc) {
949 strcpy(buf, msg);
950 afslog(35,
951 ("%s: Failed to parse Auth Name. buf:%s", module_name,
952 buf));
953 return -1;
954 }
955 strcpy(buf, msg);
956 memset(msg, 0, sizeof(msg));
957 pos = strchr(buf, '<');
958 }
959 afslog(50,
960 ("%s: Parsing WWW Auth required reply. final message:%s",
961 module_name, buf));
962 return 0;
963 }
964
965
966 /*
967 * Set the www-authenticate header - this is the login prompt the users see
968 */
969 static int
970 setCellAuthHeader(request_rec * r)
971 {
972 char *name;
973 char buf[1024];
974 int rc = 0;
975
976 afsassert(r);
977
978 name = (char *)get_afs_authprompt(r);
979 if (name != NULL) {
980 strcpy(buf, name);
981 rc = parseAuthName(r, buf);
982 } else {
983 strcpy(buf, " ");
984 }
985 TABLE_SET(r->err_headers_out, "WWW-Authenticate",
986 PSTRCAT(r->pool, "Basic realm=\"", buf, "\"", NULL));
987 return rc;
988 }
989
990
991 /*
992 * Checks if we have some authentication credentials, if we do returns
993 * FORBIDDEN and if we don't then returns AUTH_REQUIRED with the appropriate
994 * www-authenticate header. Should be called if we can't access a file because
995 * permission is denied.
996 */
997 int
998 forbToAuthReqd(request_rec * r)
999 {
1000 if (haveAuth) {
1001 return FORBIDDEN;
1002 } else {
1003 setCellAuthHeader(r);
1004 return AUTH_REQUIRED;
1005 }
1006 }