2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Implements the weblog binary which links with the AFS libraries and acts
12 * as the server for authenticating users for apache access to AFS. Code
13 * structure is based on klog.c. The communication with clients is done
14 * via pipes whose file descriptors are passed as command line arguments
15 * thus making it necessary for a common parent to start this process and
16 * the processes that will communicate with it for them to inherit the
17 * pipes. Also passed as a command line argument is a Silent flag (like klog)
18 * and a cache expiration flag which allows cache expiration times for
19 * tokens to be set for testing purposes
23 /* These two needed for rxgen output to work */
24 #include <afsconfig.h>
25 #include <afs/param.h>
31 #include <sys/types.h>
32 #include <sys/errno.h>
45 #include <afs/com_err.h>
47 #include <afs/cellconfig.h>
50 #include "weblog_errors.h"
53 #define MAX(A,B) ((A)>(B)?(A):(B))
56 #define MIN(A,B) ((A)<(B)?(A):(B))
59 #include "apache_afs_utils.h"
64 #include "apache_afs_cache.h"
66 /* the actual function that does all the work! */
70 static char **zero_argv;
72 /* pipes used for communicating with web server */
73 /* these are passed as command line args - defaults to stdin/stdout */
79 * now I know why this was necessary! - it's a hokie thing -
80 * the call to ka_UserAuthenticateGeneral doesn't compile otherwise
89 main(int argc, char **argv)
91 struct cmd_syndesc *ts;
96 * The following signal action for AIX is necessary so that in case of a
97 * crash (i.e. core is generated) we can include the user's data section
98 * in the core dump. Unfortunately, by default, only a partial core is
99 * generated which, in many cases, isn't too useful.
101 struct sigaction nsa;
103 sigemptyset(&nsa.sa_mask);
104 nsa.sa_handler = SIG_DFL;
105 nsa.sa_flags = SA_FULLDUMP;
106 sigaction(SIGABRT, &nsa, NULL);
107 sigaction(SIGSEGV, &nsa, NULL);
111 * we ignore SIGPIPE so that EPIPE is returned if there is no one reading
112 * data being written to the pipe
116 /* TODO - for AIX? */
119 sa.sa_handler = SIG_IGN;
120 sigaction(SIGPIPE, &sa, NULL);
126 ts = cmd_CreateSyntax(NULL, CommandProc, NULL,
127 "obtain Kerberos authentication for web servers");
129 /* define the command line arguments */
132 #define aCACHEEXPIRATION 2
133 #define aTOKENEXPIRATION 3
136 cmd_AddParm(ts, "-readPipe", CMD_SINGLE, CMD_OPTIONAL, "inPipefd");
137 cmd_AddParm(ts, "-writePipe", CMD_SINGLE, CMD_OPTIONAL, "outPipefd");
138 cmd_AddParm(ts, "-cacheExpiration", CMD_SINGLE, CMD_OPTIONAL,
139 "local cache expiration times for tokens");
140 cmd_AddParm(ts, "-tokenExpiration", CMD_SINGLE, CMD_OPTIONAL,
141 "cache manager expiration time for tokens");
142 cmd_AddParm(ts, "-silent", CMD_FLAG, CMD_OPTIONAL, "silent operation");
144 code = cmd_Dispatch(argc, argv);
151 * send a buffer over the pipe
154 sendToken(int len, void *buf)
157 WEBLOGEXIT(NULLARGSERROR);
159 if (write(writePipe, buf, len) != len) {
161 perror("weblog: write to pipe error");
170 * read the incoming buffer from the pipe
174 readFromClient(char *buf)
178 WEBLOGEXIT(NULLARGSERROR);
180 n = read(readPipe, buf, MAXBUFF);
183 perror("weblog: pipe read error");
189 perror("weblog: zero bytes read from pipe");
197 * copies the string spereated by the sep into retbuf and returns the position
198 * from the beginning of the string that this string ends at so you can call
199 * it againword seperated by the sep character and give that value as th start
200 * parameter - used to parse incoming buffer from clients over the pipe
203 * NOTE - the space seperated credentials failed for passwds with spaces, thus
204 * we use newline for seperators instead
207 getNullSepWord(char *buf, char sep, char *retBuf, int start)
210 int len = strlen(buf) - start;
213 if ((buf == NULL) || (retBuf == NULL) || (start < 0)) {
214 fprintf(stderr, "weblog (getWordSep):NULL args\n");
218 while ((buf[start] != sep) && (ret <= len)) {
219 retBuf[ret] = buf[start];
229 * parses the NEWLINE seperated buffer giving the username, passwd and cell
230 * coming over the pipe from the clients and sets the variables accordingly
233 parseBuf(char *buf, char *user, char *pass, char *cell, char *type)
236 int start = 0, ret = 0;
238 if ((buf == NULL) || (user == NULL) || (pass == NULL) || (cell == NULL)
241 fprintf(stderr, "afs_Authenticator:parseBuf-an arg was NULL\n");
245 if ((ret = getNullSepWord(buf, '\n', type, start)) < 0) {
249 if ((ret = getNullSepWord(buf, '\n', user, start)) < 0) {
253 if ((ret = getNullSepWord(buf, '\n', cell, start)) < 0) {
257 if ((ret = getNullSepWord(buf, '\n', pass, start)) < 0) {
265 * Discard any authentication information held in trust by the Cache Manager
266 * for the calling process and all other processes in the same PAG
271 return do_pioctl(NULL, 0, NULL, 0, VIOCUNPAG, NULL, 0);
275 /* we can obtain a PAG by calling this system call */
284 * The main procedure that waits in an infinite loop for data to
285 * arrive through a pipe from the httpds, authenticates the user and
286 * returns a token (or a failure message) over the pipe
289 CommandProc(struct cmd_syndesc *as, void *arock)
291 char name[MAXKTCNAMELEN];
292 char cell[MAXKTCREALMLEN];
294 /* All the constant sizes for these arrays are taken from the code for klog */
296 char cksum[SHA_HASH_BYTES]; /* for sha checksum for caching */
297 afs_int32 expires = 0; /* for cache expiration */
298 afs_int32 cacheExpiration = 0; /* configurable cmd line parameter */
299 afs_int32 testExpires = 0; /* cacheExpiration + current time */
301 int authtype = 0; /* AFS or AFS-DFS Authentication */
303 int shutdown = 0; /* on getting shutdown from the pipe we GO */
304 int gotToken = 0; /* did we get a token from the cache manager */
305 afs_int32 i = 0; /* for getting primary token held by CM */
306 int dosetpag = 1; /* not used */
307 Date lifetime; /* requested ticket lifetime */
308 char tbuffer[MAXBUFF]; /* for pioctl ops + pipe transfers */
309 static char rn[] = "weblog"; /* Routine name */
310 static int Silent = 0; /* Don't want error messages */
311 afs_int32 password_expires = -1;
312 char *reason; /* string describing errors */
313 char type[10]; /* authentication type AFS or DFS */
315 /* blow away command line arguments */
316 for (i = 1; i < zero_argc; i++)
317 memset(zero_argv[i], 0, strlen(zero_argv[i]));
320 /* first determine quiet flag based on -silent switch */
321 Silent = (as->parms[aSILENT].items ? 1 : 0);
326 fprintf(stderr, "%s:ka_Init FAILED\n", rn);
331 /* Parse our arguments. */
332 if (as->parms[aREADPIPE].items)
333 /* there is a file descriptor instead of stdin */
334 readPipe = atoi(as->parms[aREADPIPE].items->data);
338 if (as->parms[aWRITEPIPE].items)
339 /* there is a file descriptor instead of stdout */
340 writePipe = atoi(as->parms[aWRITEPIPE].items->data);
344 if (as->parms[aCACHEEXPIRATION].items)
345 /* set configurable cache expiration time */
346 cacheExpiration = atoi(as->parms[aCACHEEXPIRATION].items->data);
348 if (as->parms[aTOKENEXPIRATION].items)
349 /* set configurable token lifetime */
350 lifetime = atoi(as->parms[aTOKENEXPIRATION].items->data);
353 * Initialize the cache for tokens
358 * discard any tokens held for this PAG -
359 * should we create a seperate PAG for weblog first? makeNewPAG does that
362 fprintf(stderr, "%s:Before MAKENEWPAG\n", rn);
364 fprintf(stderr, "\nWEBLOG: before PAG:\t");
368 fprintf(stderr, "WEBLOG: MakeNewPAG failed\n");
371 fprintf(stderr, "weblog:AFTER do_setpag,PAG:\t");
373 fprintf(stderr, "%s:After MAKENEWPAG\n", rn);
379 fprintf(stderr, "WEBLOG: UNLOG FAILED\n");
385 code = readFromClient(tbuffer);
387 tbuffer[code] = '\0';
388 code = parseBuf(tbuffer, name, passwd, cell, type);
390 fprintf(stderr, "weblog: parseBuf FAILED\n");
391 WEBLOGEXIT(PARSEERROR);
395 fprintf(stderr, "%s: readFromClient FAILED:%d...exiting\n", rn,
398 WEBLOGEXIT(PIPEREADERROR);
401 if (strcasecmp(type, "AFS") == 0) {
409 reason = (char *)malloc(sizeof(tbuffer));
410 sprintf(reason, "weblog: Unknown Authentication type:%s.", type);
414 memset((void *)&tbuffer, 0, sizeof(tbuffer));
416 /* look up local cache */
417 weblog_login_checksum(name, cell, passwd, cksum);
418 code = weblog_login_lookup(name, cell, cksum, &tbuffer[0]);
420 if (!code) { /* local cache lookup failed */
421 /* authenticate user */
424 fprintf(stderr, "WEBLOG GROUPCHECK BEFORE KA_AUTH\n");
430 ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION + 0, name,
431 NULL, cell, passwd, lifetime,
432 &password_expires, 0, &reason);
439 "weblog:Unable to authenticate to AFS because "
447 "WEBLOG:After ka_UserAuthenticateGeneral GroupCheck\n");
450 /* get just the ONE token for this PAG from cache manager */
452 memcpy((void *)&tbuffer[0], (void *)&i, sizeof(afs_int32));
454 do_pioctl(tbuffer, sizeof(afs_int32), tbuffer,
455 sizeof(tbuffer), VIOCGETTOK, NULL, 0);
457 fprintf(stderr, "weblog: failed to get token:%d\n", code);
459 "FAILED TO GET TOKEN FROM CACHE MANAGER\n");
464 hexDump(tbuffer, sizeof(tbuffer));
468 /* put the token in local cache with the expiration date/time */
469 expires = getExpiration(tbuffer);
472 fprintf(stderr, "Error getting expiration time\n");
475 weblog_login_checksum(name, cell, passwd, cksum);
476 if (cacheExpiration == 0) {
477 weblog_login_store(name, cell, cksum, &tbuffer[0],
478 sizeof(tbuffer), expires);
480 testExpires = cacheExpiration + time(NULL);
481 weblog_login_store(name, cell, cksum, &tbuffer[0],
482 sizeof(tbuffer), MIN(expires,
489 /* cache lookup succesful */
491 fprintf(stderr, "WEBLOG: Cache lookup succesful\n");
496 /* prepare the reply buffer with this token */
500 /* respond with a reason why authentication failed */
501 sprintf(tbuffer, "FAILURE:%s", reason);
504 /* send response to client */
505 code = sendToken(sizeof(tbuffer), tbuffer);
508 fprintf(stderr, "sendToken FAILED\n");
510 WEBLOGEXIT(PIPESENDERROR);
512 /* unlog after every request unconditionally */
515 fprintf(stderr, "WEBLOG: UNLOG FAILED\n");