pr_init-fix-20050623
[openafs.git] / src / aklog / aklog_main.c
1 /* 
2  * $Id$
3  *
4  * Copyright 1990,1991 by the Massachusetts Institute of Technology
5  * For distribution and copying rights, see the file "mit-copyright.h"
6  */
7
8 #if !defined(lint) && !defined(SABER)
9 static char *rcsid =
10         "$Id$";
11 #endif /* lint || SABER */
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <sys/types.h>
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #ifdef HAVE_STDLIB_H
21 #include <stdlib.h>
22 #endif
23 #ifdef HAVE_MEMORY_H
24 #include <memory.h>
25 #endif
26 #include <errno.h>
27
28 #include <sys/stat.h>
29 #include <fcntl.h>
30
31 #ifndef WINDOWS
32 #include <sys/param.h>
33 #include <sys/errno.h>
34 #include <netdb.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <pwd.h>
39 #endif /* WINDOWS */
40
41 /* on AIX AFS has an unresolved reference to osi_audit. We will define
42  * it here as extern. It also trys to call the ntohl and htonl routines
43  * as routines rather then macros. We need a real routine here. 
44  * We do this before the ntohl and htonl macros are defined in net/in.h
45  */
46 int osi_audit()
47     { return(0);}
48
49 #if 0
50 #ifdef _AIX
51 u_long htonl(u_long x)
52     { return(x);}
53
54 u_long ntohl(u_long x)
55     { return(x);}
56 #endif
57
58 #include <netinet/in.h>
59 /* #include <krb.h> */
60 #endif /* 0 */
61
62 #include <krb5.h>
63
64 #ifdef WINDOWS
65
66 #ifdef PRE_AFS35
67 #include "afs_tokens.h"
68 #include "rxkad.h"
69 #else /* !PRE_AFS35 */
70 #include <afs/stds.h>
71 #include <afs/auth.h>
72 #include <rx/rxkad.h>
73 #include <afs/dirpath.h>
74 #endif /* PRE_AFS35 */
75
76 #else /* !WINDOWS */
77 #include <afs/stds.h>
78 #include <afs/com_err.h>
79
80 #include <afs/param.h>
81 #ifdef AFS_SUN5_ENV
82 #include <sys/ioccom.h>
83 #endif
84 #include <afs/auth.h>
85 #include <afs/cellconfig.h>
86 #include <afs/vice.h>
87 #include <afs/venus.h>
88 #include <afs/ptserver.h>
89 #include <afs/dirpath.h>
90 #endif /* WINDOWS */
91
92 #include "aklog.h"
93 #include "linked_list.h"
94
95 #define AFSKEY "afs"
96 #define AFSINST ""
97
98 #ifndef AFS_TRY_FULL_PRINC
99 #define AFS_TRY_FULL_PRINC 0
100 #endif /* AFS_TRY_FULL_PRINC */
101
102 #define AKLOG_SUCCESS 0
103 #define AKLOG_USAGE 1
104 #define AKLOG_SOMETHINGSWRONG 2
105 #define AKLOG_AFS 3
106 #define AKLOG_KERBEROS 4
107 #define AKLOG_TOKEN 5
108 #define AKLOG_BADPATH 6
109 #define AKLOG_MISC 7
110
111 #ifndef NULL
112 #define NULL 0
113 #endif
114
115 #ifndef TRUE
116 #define TRUE 1
117 #endif
118
119 #ifndef FALSE
120 #define FALSE 0
121 #endif
122
123 #ifndef MAXSYMLINKS
124 /* RedHat 4.x doesn't seem to define this */
125 #define MAXSYMLINKS     5
126 #endif
127
128 #define DIR '/'                 /* Character that divides directories */
129 #define DIRSTRING "/"           /* String form of above */
130 #define VOLMARKER ':'           /* Character separating cellname from mntpt */
131 #define VOLMARKERSTRING ":"     /* String form of above */
132
133 typedef struct {
134     char cell[BUFSIZ];
135     char realm[REALM_SZ];
136 } cellinfo_t;
137
138 struct afsconf_cell ak_cellconfig; /* General information about the cell */
139 static char linkedcell[MAXCELLCHARS+1];
140 static char linkedcell2[MAXCELLCHARS+1];
141
142 #ifdef WINDOWS
143
144 /* libafsconf.dll */
145 extern long cm_GetRootCellName();
146 extern long cm_SearchCellFile();
147
148 static long cm_SearchCellFile_CallBack();
149
150 #else /* !WINDOWS */
151
152 /*
153  * Why doesn't AFS provide these prototypes?
154  */
155
156 #ifdef AFS_INT32
157 typedef afs_int32 int32 ;
158 #endif
159
160 extern int afsconf_GetLocalCell(struct afsconf_dir *, char *, afs_int32);
161 extern int afsconf_GetCellInfo(struct afsconf_dir *, char *, char *,
162                                struct afsconf_cell *);
163 extern int afsconf_Close(struct afsconf_dir *);
164 extern int ktc_GetToken(struct ktc_principal *, struct ktc_token *, int,
165                         struct ktc_principal *);
166 extern int ktc_SetToken(struct ktc_principal *, struct ktc_token *,
167                         struct ktc_principal *, int);
168 extern afs_int32 pr_Initialize(afs_int32, char *, char *, afs_int32);
169 extern int pr_SNameToId(char *, afs_int32 *);
170 extern int pr_CreateUser(char *, afs_int32 *);
171 extern int pr_End();
172 extern int pioctl(char *, afs_int32, struct ViceIoctl *, afs_int32);
173
174 /*
175  * Other prototypes
176  */
177
178 extern char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
179
180 #endif /* WINDOWS */
181
182 /*
183  * Provide a replacement for strerror if we don't have it
184  */
185
186 #ifndef HAVE_STRERROR
187 extern char *sys_errlist[];
188 #define strerror(x) sys_errlist[x]
189 #endif /* HAVE_STRERROR */
190
191 static aklog_params params;     /* Various aklog functions */
192 static char msgbuf[BUFSIZ];     /* String for constructing error messages */
193 static char *progname = NULL;   /* Name of this program */
194 static int dflag = FALSE;       /* Give debugging information */
195 static int noauth = FALSE;      /* If true, don't try to get tokens */
196 static int zsubs = FALSE;       /* Are we keeping track of zephyr subs? */
197 static int hosts = FALSE;       /* Are we keeping track of hosts? */
198 static int noprdb = FALSE;      /* Skip resolving name to id? */
199 static int linked = FALSE;  /* try for both AFS nodes */
200 static int afssetpag = FALSE; /* setpag for AFS */
201 static int force = FALSE;       /* Bash identical tokens? */
202 static linked_list zsublist;    /* List of zephyr subscriptions */
203 static linked_list hostlist;    /* List of host addresses */
204 static linked_list authedcells; /* List of cells already logged to */
205
206 /* ANL - CMU lifetime convert routine */
207 /* for K5.4.1 don't use this for now. Need to see if it is needed */
208 /* maybe needed in the krb524d module as well */
209 /* extern unsigned long krb_life_to_time(); */
210
211 #ifdef __STDC__
212 static char *copy_cellinfo(cellinfo_t *cellinfo)
213 #else
214 static char *copy_cellinfo(cellinfo)
215   cellinfo_t *cellinfo;
216 #endif /* __STDC__ */
217 {
218     cellinfo_t *new_cellinfo;
219
220     if ((new_cellinfo = (cellinfo_t *)malloc(sizeof(cellinfo_t))))
221         memcpy(new_cellinfo, cellinfo, sizeof(cellinfo_t));
222     
223     return ((char *)new_cellinfo);
224 }
225
226
227 #ifdef __STDC__
228 static char *copy_string(char *string)    
229 #else
230 static char *copy_string(string)
231   char *string;
232 #endif /* __STDC__ */
233 {
234     char *new_string;
235
236     if ((new_string = (char *)calloc(strlen(string) + 1, sizeof(char))))
237         (void) strcpy(new_string, string);
238
239     return (new_string);
240 }
241
242
243 #ifdef __STDC__
244 static int get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell, char *linkedcell)
245 #else
246 static int get_cellconfig(cell, cellconfig, local_cell, linkedcell)
247     char *cell;
248     struct afsconf_cell *cellconfig;
249     char *local_cell;
250         char *linkedcell;
251 #endif /* __STDC__ */
252 {
253     int status = AKLOG_SUCCESS;
254     struct afsconf_dir *configdir;
255 #ifndef PRE_AFS35
256     char *dirpath;
257 #endif /* ! PRE_AFS35 */
258
259     memset(local_cell, 0, sizeof(local_cell));
260     memset((char *)cellconfig, 0, sizeof(*cellconfig));
261
262 #ifndef WINDOWS
263
264     if (!(configdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
265         sprintf(msgbuf, 
266                 "%s: can't get afs configuration (afsconf_Open(%s))\n",
267                 progname, AFSDIR_CLIENT_ETC_DIRPATH);
268         params.pstderr(msgbuf);
269         params.exitprog(AKLOG_AFS);
270     }
271
272     if (afsconf_GetLocalCell(configdir, local_cell, MAXCELLCHARS)) {
273         sprintf(msgbuf, "%s: can't determine local cell.\n", progname);
274         params.pstderr(msgbuf);
275         params.exitprog(AKLOG_AFS);
276     }
277
278     if ((cell == NULL) || (cell[0] == 0))
279         cell = local_cell;
280
281         linkedcell[0] = '\0';
282     if (afsconf_GetCellInfo(configdir, cell, NULL, cellconfig)) {
283         sprintf(msgbuf, "%s: Can't get information about cell %s.\n",
284                 progname, cell);
285         params.pstderr(msgbuf);
286         status = AKLOG_AFS;
287     }
288         if (cellconfig->linkedCell) 
289                 strncpy(linkedcell,cellconfig->linkedCell,MAXCELLCHARS);
290
291     (void) afsconf_Close(configdir);
292
293 #else /* WINDOWS */
294     /*
295      * We'll try to mimic the GetCellInfo call here and fill in as much
296      * of the afsconf_cell structure as we can.
297      */
298     if (cm_GetRootCellName(local_cell)) {
299         sprintf(msgbuf, "%s: can't get local cellname\n", progname);
300         params.pstderr(msgbuf);
301         params.exitprog(AKLOG_AFS);
302     }
303
304     if ((cell == NULL) || (cell[0] == 0))
305         cell = local_cell;
306
307     strcpy(cellconfig->name, cell);
308
309     /* No way of figuring this out as far as I can tell */
310     linkedcell[0] = '\0';
311
312     /* Initialize server info */
313     cellconfig->numServers = 0;
314     cellconfig->hostName[0][0] = "\0";
315
316     /*
317      * Get servers of cell. cm_SearchCellFile_CallBack() gets call with
318      * each server.
319      */
320 #ifdef PRE_AFS35
321     status = (int) cm_SearchCellFile(cell, &cm_SearchCellFile_CallBack,
322 #else
323     status = (int) cm_SearchCellFile(cell, NULL, &cm_SearchCellFile_CallBack,
324 #endif
325                                      cellconfig /* rock */);
326
327     switch(status) {
328     case 0:
329         break;
330
331     case -1:
332         sprintf(msgbuf, "%s: GetWindowsDirectory() failed.\n", progname);
333         break;
334
335     case -2:
336         sprintf(msgbuf, "%s: Couldn't open afsdcells.ini for reading\n",
337                 progname);
338         break;
339
340     case -3:
341         sprintf(msgbuf, "%s: Couldn't find any servers for cell %s\n",
342                 progname, cell);
343         break;
344
345     case -4:
346         sprintf(msgbuf, "%s: Badly formatted line in afsdcells.ini (does not begin with a \">\" or contain \"#\"\n",
347                 progname);
348         break;
349
350     default:
351         sprintf(msgbuf, "%s cm_SearchCellFile returned unknown error %d\n",
352                 status);
353     }
354
355     if (status) {
356         params.pstderr(msgbuf);
357         params.exitprog(AKLOG_AFS);
358     }
359
360     status = AKLOG_SUCCESS;
361
362     
363 #endif /* WINDOWS */
364
365     return(status);
366 }
367
368
369 #ifdef WINDOWS
370 /*
371  * Callback function for cm_SearchCellFile() in get_cellconfig() above.
372  * This function gets called once for each server that is found for the cell.
373  */
374 static long
375 cm_SearchCellFile_CallBack(void *rock /* cellconfig */,
376                            struct sockaddr_in *addr, /* Not used */
377                            char *server)
378 {
379     struct afsconf_cell *cellconfig = rock;
380
381
382     /*
383      * Save server name and increment count of servers
384      */
385     strcpy(cellconfig->hostName[cellconfig->numServers++], server);
386     
387     return (long) 0;
388 }
389
390     
391 #endif /* WINDOWS */
392
393
394 /* 
395  * Log to a cell.  If the cell has already been logged to, return without
396  * doing anything.  Otherwise, log to it and mark that it has been logged
397  * to.
398  */
399 #ifdef __STDC__
400 static int auth_to_cell(krb5_context context, char *cell, char *realm)
401 #else
402 static int auth_to_cell(context, cell, realm)
403
404   krb5_context context;
405   char *cell;
406   char *realm;
407 #endif /* __STDC__ */
408 {
409     int status = AKLOG_SUCCESS;
410     char username[BUFSIZ];      /* To hold client username structure */
411     long viceId;                /* AFS uid of user */
412
413     char name[ANAME_SZ];        /* Name of afs key */
414     char primary_instance[INST_SZ];     /* Instance of afs key */
415     char secondary_instance[INST_SZ];   /* Backup instance to try */
416     int try_secondary = 0;              /* Flag to indicate if we try second */
417     char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
418     char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
419     char local_cell[MAXCELLCHARS+1];
420     char cell_to_use[MAXCELLCHARS+1]; /* Cell to authenticate to */
421     static char lastcell[MAXCELLCHARS+1] = { 0 };
422 #ifndef WINDOWS
423     static char confname[512] = { 0 };
424 #endif
425     krb5_creds *v5cred = NULL;
426     CREDENTIALS c;
427     struct ktc_principal aserver;
428     struct ktc_principal aclient;
429     struct ktc_token atoken, btoken;
430
431 #ifdef ALLOW_REGISTER
432     afs_int32 id;
433 #endif /* ALLOW_REGISTER */
434
435     memset(name, 0, sizeof(name));
436     memset(primary_instance, 0, sizeof(primary_instance));
437     memset(secondary_instance, 0, sizeof(secondary_instance));
438     memset(realm_of_user, 0, sizeof(realm_of_user));
439     memset(realm_of_cell, 0, sizeof(realm_of_cell));
440
441 #ifndef WINDOWS
442     if (confname[0] == '\0') {
443         strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
444         confname[sizeof(confname) - 2] = '\0';
445     }
446 #endif /* WINDOWS */
447
448     /* NULL or empty cell returns information on local cell */
449     if ((status = get_cellconfig(cell, &ak_cellconfig,
450                          local_cell, linkedcell)))
451         return(status);
452
453     strncpy(cell_to_use, ak_cellconfig.name, MAXCELLCHARS);
454     cell_to_use[MAXCELLCHARS] = 0;
455
456     if (ll_string(&authedcells, ll_s_check, cell_to_use)) {
457         if (dflag) {
458             sprintf(msgbuf, "Already authenticated to %s (or tried to)\n", 
459                     cell_to_use);
460             params.pstdout(msgbuf);
461         }
462         return(AKLOG_SUCCESS);
463     }
464
465     /* 
466      * Record that we have attempted to log to this cell.  We do this
467      * before we try rather than after so that we will not try
468      * and fail repeatedly for one cell.
469      */
470     (void)ll_string(&authedcells, ll_s_add, cell_to_use);
471
472     /* 
473      * Record this cell in the list of zephyr subscriptions.  We may
474      * want zephyr subscriptions even if authentication fails.
475      * If this is done after we attempt to get tokens, aklog -zsubs
476      * can return something different depending on whether or not we
477      * are in -noauth mode.
478      */
479     if (ll_string(&zsublist, ll_s_add, cell_to_use) == LL_FAILURE) {
480         sprintf(msgbuf, 
481                 "%s: failure adding cell %s to zephyr subscriptions list.\n",
482                 progname, cell_to_use);
483         params.pstderr(msgbuf);
484         params.exitprog(AKLOG_MISC);
485     }
486     if (ll_string(&zsublist, ll_s_add, local_cell) == LL_FAILURE) {
487         sprintf(msgbuf, 
488                 "%s: failure adding cell %s to zephyr subscriptions list.\n",
489                 progname, local_cell);
490         params.pstderr(msgbuf);
491         params.exitprog(AKLOG_MISC);
492     }
493
494     if (!noauth) {
495         if (dflag) {
496             sprintf(msgbuf, "Authenticating to cell %s (server %s).\n",
497                     cell_to_use, ak_cellconfig.hostName[0]);
498             params.pstdout(msgbuf);
499         }
500
501         /*
502          * Find out which realm we're supposed to authenticate to.  If one
503          * is not included, use the kerberos realm found in the credentials
504          * cache.
505          */
506
507         if (realm && realm[0]) {
508             strcpy(realm_of_cell, realm);
509             if (dflag) {
510                 sprintf(msgbuf, "We were told to authenticate to realm %s.\n",
511                         realm);
512                 params.pstdout(msgbuf);
513             }
514         }
515         else {
516             char *realm = afs_realm_of_cell(context, &ak_cellconfig);
517
518             if (!realm) {
519                 sprintf(msgbuf, 
520                         "%s: Couldn't figure out realm for cell %s.\n",
521                         progname, cell_to_use);
522                 params.pstderr(msgbuf);
523                 params.exitprog(AKLOG_MISC);
524             }
525
526             strcpy(realm_of_cell, realm);
527
528             if (dflag) {
529                 sprintf(msgbuf, "We've deduced that we need to authenticate to"
530                         " realm %s.\n", realm_of_cell);
531                 params.pstdout(msgbuf);
532             }
533         }
534
535         /* We use the afs.<cellname> convention here... 
536          *
537          * Doug Engert's original code had principals of the form:
538          *
539          * "afsx/cell@realm"
540          *
541          * in the KDC, so the name wouldn't conflict with DFS.  Since we're
542          * not using DFS, I changed it just to look for the following
543          * principals:
544          *
545          * afs/<cell>@<realm>
546          * afs@<realm>
547          *
548          * Because people are transitioning from afs@realm to afs/cell,
549          * we configure things so that if the first one isn't found, we
550          * try the second one.  You can select which one you prefer with
551          * a configure option.
552          */
553
554         strcpy(name, AFSKEY);
555
556         if (AFS_TRY_FULL_PRINC || strcasecmp(cell_to_use, realm_of_cell) != 0) {
557             strncpy(primary_instance, cell_to_use, sizeof(primary_instance));
558             primary_instance[sizeof(primary_instance)-1] = '\0';
559             if (strcasecmp(cell_to_use, realm_of_cell) == 0) {
560                 try_secondary = 1;
561                 secondary_instance[0] = '\0';
562             }
563         } else {
564             primary_instance[0] = '\0';
565             try_secondary = 1;
566             strncpy(secondary_instance, cell_to_use,
567                     sizeof(secondary_instance));
568             secondary_instance[sizeof(secondary_instance)-1] = '\0';
569         }
570
571         /* 
572          * Extract the session key from the ticket file and hand-frob an
573          * afs style authenticator.
574          */
575
576         /*
577          * Try to obtain AFS tickets.  Because there are two valid service
578          * names, we will try both, but trying the more specific first.
579          *
580          *      afs/<cell>@<realm> i.e. allow for single name with "."
581          *      afs@<realm>
582          */
583 #if 0
584         if (dflag) {
585                 dee_gettokens(); /* DEBUG */
586         }
587 #endif
588
589         if (dflag) {
590             sprintf(msgbuf, "Getting tickets: %s/%s@%s\n", name,
591                     primary_instance, realm_of_cell);
592             params.pstdout(msgbuf);
593         }
594
595         status = params.get_cred(context, name, primary_instance, realm_of_cell,
596                          &c, &v5cred);
597
598         if (status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
599             if (try_secondary) {
600                 if (dflag) {
601                     sprintf(msgbuf, "Principal not found, trying alternate "
602                             "service name: %s/%s@%s\n", name,
603                             secondary_instance, realm_of_cell);
604                     params.pstdout(msgbuf);
605                 }
606                 status = params.get_cred(context, name, secondary_instance,
607                                          realm_of_cell, &c, &v5cred);
608             }
609         }
610
611         if (status != KSUCCESS) {
612             if (dflag) {
613                 sprintf(msgbuf, 
614                         "Kerberos error code returned by get_cred: %d\n",
615                         status);
616                 params.pstdout(msgbuf);
617             }
618             sprintf(msgbuf, "%s: Couldn't get %s AFS tickets:\n",
619                     progname, cell_to_use);
620             params.pstderr(msgbuf);
621                 com_err(progname, status, "while getting AFS tickets");
622             return(AKLOG_KERBEROS);
623         }
624
625         strncpy(aserver.name, AFSKEY, MAXKTCNAMELEN - 1);
626         strncpy(aserver.instance, AFSINST, MAXKTCNAMELEN - 1);
627         strncpy(aserver.cell, cell_to_use, MAXKTCREALMLEN - 1);
628
629         strcpy (username, c.pname);
630         if (c.pinst[0]) {
631             strcat (username, ".");
632             strcat (username, c.pinst);
633         }
634
635         atoken.kvno = c.kvno;
636         atoken.startTime = c.issue_date;
637         /*
638          * It seems silly to go through a bunch of contortions to
639          * extract the expiration time, when the v5 credentials already
640          * has the exact time!  Let's use that instead.
641          *
642          * Note that this isn't a security hole, as the expiration time
643          * is also contained in the encrypted token
644          */
645         atoken.endTime = v5cred->times.endtime;
646         memcpy(&atoken.sessionKey, c.session, 8);
647         atoken.ticketLen = c.ticket_st.length;
648         memcpy(atoken.ticket, c.ticket_st.dat, atoken.ticketLen);
649         
650         if (!force &&
651             !ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient) &&
652             atoken.kvno == btoken.kvno &&
653             atoken.ticketLen == btoken.ticketLen &&
654             !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
655             !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
656
657             if (dflag) {
658                 sprintf(msgbuf, "Identical tokens already exist; skipping.\n");
659                 params.pstdout(msgbuf);
660             }
661             return 0;
662         }
663
664 #ifdef FORCE_NOPRDB
665         noprdb = 1;
666 #endif
667
668 #ifndef WINDOWS
669         if (noprdb) {
670 #endif
671             if (dflag) {
672                 sprintf(msgbuf, "Not resolving name %s to id (-noprdb set)\n",
673                         username);
674                 params.pstdout(msgbuf);
675             }
676 #ifndef WINDOWS
677         }
678         else {
679             if ((status = params.get_user_realm(context, realm_of_user)) != KSUCCESS) {
680                 sprintf(msgbuf, "%s: Couldn't determine realm of user:)",
681                         progname);
682                 params.pstderr(msgbuf);
683                 com_err(progname, status, " while getting realm");
684                 return(AKLOG_KERBEROS);
685             }
686             if (strcmp(realm_of_user, realm_of_cell)) {
687                 strcat(username, "@");
688                 strcat(username, realm_of_user);
689             }
690
691             if (dflag) {
692                 sprintf(msgbuf, "About to resolve name %s to id in cell %s.\n", 
693                         username, aserver.cell);
694                 params.pstdout(msgbuf);
695             }
696
697             strcpy(lastcell, aserver.cell);
698
699             if (!pr_Initialize (0, confname, aserver.cell, 0))
700                     status = pr_SNameToId (username, &viceId);
701             
702             if (dflag) {
703                 if (status) 
704                     sprintf(msgbuf, "Error %d\n", status);
705                 else
706                     sprintf(msgbuf, "Id %d\n", (int) viceId);
707                 params.pstdout(msgbuf);
708             }
709             
710                 /*
711                  * This is a crock, but it is Transarc's crock, so
712                  * we have to play along in order to get the
713                  * functionality.  The way the afs id is stored is
714                  * as a string in the username field of the token.
715                  * Contrary to what you may think by looking at
716                  * the code for tokens, this hack (AFS ID %d) will
717                  * not work if you change %d to something else.
718                  */
719
720                 /*
721                  * This code is taken from cklog -- it lets people
722                  * automatically register with the ptserver in foreign cells
723                  */
724
725 #ifdef ALLOW_REGISTER
726         if (status == 0) {
727             if (viceId != ANONYMOUSID) {
728 #else /* ALLOW_REGISTER */
729             if ((status == 0) && (viceId != ANONYMOUSID))
730 #endif /* ALLOW_REGISTER */
731                 sprintf (username, "AFS ID %d", (int) viceId);
732 #ifdef ALLOW_REGISTER
733             } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
734                 if (dflag) {
735                     sprintf(msgbuf, "doing first-time registration of %s "
736                             "at %s\n", username, cell_to_use);
737                     params.pstdout(msgbuf);
738                 }
739                 id = 0;
740                 strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
741                 strcpy(aclient.instance, "");
742                 strncpy(aclient.cell, c.realm, MAXKTCREALMLEN - 1);
743                 if ((status = ktc_SetToken(&aserver, &atoken, &aclient, 0))) {
744                     sprintf(msgbuf, "%s: unable to obtain tokens for cell %s "
745                             "(status: %d).\n", progname, cell_to_use, status);
746                     params.pstderr(msgbuf);
747                     status = AKLOG_TOKEN;
748                 }
749
750                 /*
751                  * In case you're wondering, we don't need to change the
752                  * filename here because we're still connecting to the
753                  * same cell -- we're just using a different authentication
754                  * level
755                  */
756
757                 if ((status = pr_Initialize(1L, confname, aserver.cell, 0))) {
758                     sprintf(msgbuf, "Error %d\n", status);
759                     params.pstdout(msgbuf);
760                 }
761
762                 if ((status = pr_CreateUser(username, &id))) {
763                     sprintf(msgbuf, "%s: %s so unable to create remote PTS "
764                             "user %s in cell %s (status: %d).\n", progname,
765                             error_message(status), username, cell_to_use,
766                             status);
767                     params.pstdout(msgbuf);
768                 } else {
769                     sprintf(msgbuf, "created cross-cell entry for %s at %s\n",
770                             username, cell_to_use);
771                     params.pstdout(msgbuf);
772                     sprintf(username, "AFS ID %d", (int) id);
773                 }
774             }
775         }
776 #endif /* ALLOW_REGISTER */
777
778         }
779 #endif /* !WINDOWS */
780
781         if (dflag) {
782             sprintf(msgbuf, "Set username to %s\n", username);
783             params.pstdout(msgbuf);
784         }
785
786         /* Reset the "aclient" structure before we call ktc_SetToken.
787          * This structure was first set by the ktc_GetToken call when
788          * we were comparing whether identical tokens already existed.
789          */
790         strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
791         strcpy(aclient.instance, "");
792         strncpy(aclient.cell, c.realm, MAXKTCREALMLEN - 1);
793
794         if (dflag) {
795             sprintf(msgbuf, "Setting tokens. %s / %s @ %s \n",
796                         aclient.name, aclient.instance, aclient.cell );
797             params.pstdout(msgbuf);
798         }
799         /* on AIX 4.1.4 with AFS 3.4a+ if a write is not done before 
800          * this routine, it will not add the token. It is not clear what 
801          * is going on here! So we will do the following operation
802          */
803         write(2,"",0); /* dummy write */
804 #ifndef WINDOWS
805         if ((status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag))) {
806             sprintf(msgbuf, 
807                     "%s: unable to obtain tokens for cell %s (status: %d).\n",
808                     progname, cell_to_use, status);
809             params.pstderr(msgbuf);
810             status = AKLOG_TOKEN;
811         }
812 #else /* WINDOWS */
813         /* Note switched 2nd and 3rd args */
814 #ifdef PRE_AFS35
815         if ((status = ktc_SetToken(&aserver, &aclient, &atoken, afssetpag))) {
816 #else
817         if ((status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag))) {
818 #endif
819             switch(status) {
820             case KTC_INVAL:
821                 sprintf(msgbuf, "%s: Bad ticket length", progname);
822                 break;
823             case KTC_PIOCTLFAIL:
824                 sprintf(msgbuf, "%s: Unknown error contacting AFS service",
825                         progname);
826                 break;
827             case KTC_NOCELL:
828                 sprintf(msgbuf, "%s: Cell name (%s) not recognized by AFS service",
829                         progname, realm_of_cell);
830                 break;
831             case KTC_NOCM:
832                 sprintf(msgbuf, "%s: AFS service is unavailable", progname);
833                 break;
834             default:
835                 sprintf(msgbuf, "%s: Undocumented error (%d) contacting AFS service", progname, status);
836                 break;  
837             }
838             params.pstderr(msgbuf);
839             status = AKLOG_TOKEN;           
840         }
841 #endif /* !WINDOWS */
842     }
843     else
844         if (dflag) {
845             sprintf(msgbuf, "Noauth mode; not authenticating.\n");
846             params.pstdout(msgbuf);
847         }
848         
849     return(status);
850 }
851
852 #ifndef WINDOWS /* struct ViceIoctl missing */
853
854 #ifdef __STDC__
855 static int get_afs_mountpoint(char *file, char *mountpoint, int size)
856 #else
857 static int get_afs_mountpoint(file, mountpoint, size)
858   char *file;
859   char *mountpoint;
860   int size;
861 #endif /* __STDC__ */
862 {
863 #ifdef AFS_SUN_ENV
864         char V ='V'; /* AFS has problem on Sun with pioctl */
865 #endif
866     char our_file[MAXPATHLEN + 1];
867     char *parent_dir;
868     char *last_component;
869     struct ViceIoctl vio;
870     char cellname[BUFSIZ];
871
872     memset(our_file, 0, sizeof(our_file));
873     strcpy(our_file, file);
874
875     if ((last_component = strrchr(our_file, DIR))) {
876         *last_component++ = 0;
877         parent_dir = our_file;
878     }
879     else {
880         last_component = our_file;
881         parent_dir = ".";
882     }    
883     
884     memset(cellname, 0, sizeof(cellname));
885
886     vio.in = last_component;
887     vio.in_size = strlen(last_component)+1;
888     vio.out_size = size;
889     vio.out = mountpoint;
890
891     if (!pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &vio, 0)) {
892         if (strchr(mountpoint, VOLMARKER) == NULL) {
893             vio.in = file;
894             vio.in_size = strlen(file) + 1;
895             vio.out_size = sizeof(cellname);
896             vio.out = cellname;
897             
898             if (!pioctl(file, VIOC_FILE_CELL_NAME, &vio, 1)) {
899                 strcat(cellname, VOLMARKERSTRING);
900                 strcat(cellname, mountpoint + 1);
901                 memset(mountpoint + 1, 0, size - 1);
902                 strcpy(mountpoint + 1, cellname);
903             }
904         }
905         return(TRUE);
906     }
907     else
908         return(FALSE);
909 }
910
911 /* 
912  * This routine each time it is called returns the next directory 
913  * down a pathname.  It resolves all symbolic links.  The first time
914  * it is called, it should be called with the name of the path
915  * to be descended.  After that, it should be called with the arguemnt
916  * NULL.
917  */
918 #ifdef __STDC__
919 static char *next_path(char *origpath)
920 #else
921 static char *next_path(origpath)
922   char *origpath;
923 #endif /* __STDC__ */
924 {
925     static char path[MAXPATHLEN + 1];
926     static char pathtocheck[MAXPATHLEN + 1];
927
928     int link = FALSE;           /* Is this a symbolic link? */
929     char linkbuf[MAXPATHLEN + 1];
930     char tmpbuf[MAXPATHLEN + 1];
931
932     static char *last_comp;     /* last component of directory name */
933     static char *elast_comp;    /* End of last component */
934     char *t;
935     int len;
936     
937     static int symlinkcount = 0; /* We can't exceed MAXSYMLINKS */
938     
939     /* If we are given something for origpath, we are initializing only. */
940     if (origpath) {
941         memset(path, 0, sizeof(path));
942         memset(pathtocheck, 0, sizeof(pathtocheck));
943         strcpy(path, origpath);
944         last_comp = path;
945         symlinkcount = 0;
946         return(NULL);
947     }
948
949     /* We were not given origpath; find then next path to check */
950     
951     /* If we've gotten all the way through already, return NULL */
952     if (last_comp == NULL)
953         return(NULL);
954
955     do {
956         while (*last_comp == DIR)
957             strncat(pathtocheck, last_comp++, 1);
958         len = (elast_comp = strchr(last_comp, DIR)) 
959             ? elast_comp - last_comp : strlen(last_comp);
960         strncat(pathtocheck, last_comp, len);
961         memset(linkbuf, 0, sizeof(linkbuf));
962         if ((link = (params.readlink(pathtocheck, linkbuf, 
963                                     sizeof(linkbuf)) > 0))) {
964             if (++symlinkcount > MAXSYMLINKS) {
965                 sprintf(msgbuf, "%s: %s\n", progname, strerror(ELOOP));
966                 params.pstderr(msgbuf);
967                 params.exitprog(AKLOG_BADPATH);
968             }
969             memset(tmpbuf, 0, sizeof(tmpbuf));
970             if (elast_comp)
971                 strcpy(tmpbuf, elast_comp);
972             if (linkbuf[0] == DIR) {
973                 /* 
974                  * If this is a symbolic link to an absolute path, 
975                  * replace what we have by the absolute path.
976                  */
977                 memset(path, 0, strlen(path));
978                 memcpy(path, linkbuf, sizeof(linkbuf));
979                 strcat(path, tmpbuf);
980                 last_comp = path;
981                 elast_comp = NULL;
982                 memset(pathtocheck, 0, sizeof(pathtocheck));
983             }
984             else {
985                 /* 
986                  * If this is a symbolic link to a relative path, 
987                  * replace only the last component with the link name.
988                  */
989                 strncpy(last_comp, linkbuf, strlen(linkbuf) + 1);
990                 strcat(path, tmpbuf);
991                 elast_comp = NULL;
992                 if ((t = strrchr(pathtocheck, DIR))) {
993                     t++;
994                     memset(t, 0, strlen(t));
995                 }
996                 else
997                     memset(pathtocheck, 0, sizeof(pathtocheck));
998             }
999         }
1000         else
1001             last_comp = elast_comp;
1002     }
1003     while(link);
1004
1005     return(pathtocheck);
1006 }
1007
1008 #endif /* WINDOWS */
1009
1010 #if 0
1011 /*****************************************/
1012 int dee_gettokens()
1013 {
1014 #ifdef AFS_SUN_ENV
1015         char V = 'V'; /* AFS has problem on SunOS */
1016 #endif
1017    struct ViceIoctl vio;
1018    char outbuf[BUFSIZ];
1019    long ind;
1020    int fd;
1021
1022    memset(outbuf, 0, sizeof(outbuf));
1023
1024    vio.out_size = sizeof(outbuf);
1025    vio.in_size = sizeof(ind);
1026    vio.out = outbuf;
1027    vio.in = &ind;
1028
1029    ind = 0;
1030    fd = open("dee.tok",O_WRONLY);
1031    while(!pioctl(0,VIOCGETTOK,&vio,0)) {
1032         write(fd,&outbuf,sizeof(outbuf)); 
1033        ind++;
1034    }
1035    close(fd);
1036 }
1037 /*****************************************/
1038 #endif
1039
1040 #ifndef WINDOWS /* struct ViceIoctl missing */
1041
1042 #ifdef __STDC__
1043 static void add_hosts(char *file)
1044 #else
1045 static void add_hosts(file)
1046   char *file;
1047 #endif /* __STDC__ */
1048 {
1049 #ifdef AFS_SUN_ENV
1050         char V = 'V'; /* AFS has problem on SunOS */
1051 #endif
1052     struct ViceIoctl vio;
1053     char outbuf[BUFSIZ];
1054     long *phosts;
1055     int i;
1056     struct hostent *hp;
1057     struct in_addr in;
1058     
1059     memset(outbuf, 0, sizeof(outbuf));
1060
1061     vio.out_size = sizeof(outbuf);
1062     vio.in_size = 0;
1063     vio.out = outbuf;
1064
1065     if (dflag) {
1066         sprintf(msgbuf, "Getting list of hosts for %s\n", file);
1067         params.pstdout(msgbuf);
1068     }
1069     /* Don't worry about errors. */
1070     if (!pioctl(file, VIOCWHEREIS, &vio, 1)) {
1071         phosts = (long *) outbuf;
1072
1073         /*
1074          * Lists hosts that we care about.  If ALLHOSTS is defined,
1075          * then all hosts that you ever may possible go through are
1076          * included in this list.  If not, then only hosts that are
1077          * the only ones appear.  That is, if a volume you must use
1078          * is replaced on only one server, that server is included.
1079          * If it is replicated on many servers, then none are included.
1080          * This is not perfect, but the result is that people don't
1081          * get subscribed to a lot of instances of FILSRV that they
1082          * probably won't need which reduces the instances of 
1083          * people getting messages that don't apply to them.
1084          */
1085 #ifndef ALLHOSTS
1086         if (phosts[1] != '\0')
1087             return;
1088 #endif
1089         for (i = 0; phosts[i]; i++) {
1090             if (hosts) {
1091                 in.s_addr = phosts[i];
1092                 if (dflag) {
1093                     sprintf(msgbuf, "Got host %s\n", inet_ntoa(in));
1094                     params.pstdout(msgbuf);
1095                 }
1096                 ll_string(&hostlist, ll_s_add, (char *)inet_ntoa(in));
1097             }
1098             if (zsubs && (hp=gethostbyaddr((char *) &phosts[i],sizeof(long),AF_INET))) {
1099                 if (dflag) {
1100                     sprintf(msgbuf, "Got host %s\n", hp->h_name);
1101                     params.pstdout(msgbuf);
1102                 }
1103                 ll_string(&zsublist, ll_s_add, hp->h_name);
1104             }
1105         }
1106     }
1107 }
1108
1109 #endif /* WINDOWS */
1110
1111 #ifndef WINDOWS /* next_path(), get_afs_mountpoint() */
1112
1113 /*
1114  * This routine descends through a path to a directory, logging to 
1115  * every cell it encounters along the way.
1116  */
1117 #ifdef __STDC__
1118 static int auth_to_path(krb5_context context, char *path)
1119 #else
1120 static int auth_to_path(context, path)
1121   krb5_context context;
1122   char *path;                   /* The path to which we try to authenticate */
1123 #endif /* __STDC__ */
1124 {
1125     int status = AKLOG_SUCCESS;
1126     int auth_to_cell_status = AKLOG_SUCCESS;
1127
1128     char *nextpath;
1129     char pathtocheck[MAXPATHLEN + 1];
1130     char mountpoint[MAXPATHLEN + 1];
1131
1132     char *cell;
1133     char *endofcell;
1134
1135     u_char isdir;
1136
1137     /* Initialize */
1138     if (path[0] == DIR)
1139         strcpy(pathtocheck, path);
1140     else {
1141         if (params.getwd(pathtocheck) == NULL) {
1142             sprintf(msgbuf, "Unable to find current working directory:\n");
1143             params.pstderr(msgbuf);
1144             sprintf(msgbuf, "%s\n", pathtocheck);
1145             params.pstderr(msgbuf);
1146             sprintf(msgbuf, "Try an absolute pathname.\n");
1147             params.pstderr(msgbuf);
1148             params.exitprog(AKLOG_BADPATH);
1149         }
1150         else {
1151             strcat(pathtocheck, DIRSTRING);
1152             strcat(pathtocheck, path);
1153         }
1154     }
1155     next_path(pathtocheck);
1156
1157     /* Go on to the next level down the path */
1158     while ((nextpath = next_path(NULL))) {
1159         strcpy(pathtocheck, nextpath);
1160         if (dflag) {
1161             sprintf(msgbuf, "Checking directory %s\n", pathtocheck);
1162             params.pstdout(msgbuf);
1163         }
1164         /* 
1165          * If this is an afs mountpoint, determine what cell from 
1166          * the mountpoint name which is of the form 
1167          * #cellname:volumename or %cellname:volumename.
1168          */
1169         if (get_afs_mountpoint(pathtocheck, mountpoint, sizeof(mountpoint))) {
1170             /* skip over the '#' or '%' */
1171             cell = mountpoint + 1;
1172             /* Add this (cell:volumename) to the list of zsubs */
1173             if (zsubs)
1174                 ll_string(&zsublist, ll_s_add, cell);
1175             if (zsubs || hosts)
1176                 add_hosts(pathtocheck);
1177             if ((endofcell = strchr(mountpoint, VOLMARKER))) {
1178                 *endofcell = '\0';
1179                 if ((auth_to_cell_status = auth_to_cell(context, cell, NULL))) {
1180                     if (status == AKLOG_SUCCESS)
1181                         status = auth_to_cell_status;
1182                     else if (status != auth_to_cell_status)
1183                         status = AKLOG_SOMETHINGSWRONG;
1184                 }
1185             }
1186         }
1187         else {
1188             if (params.isdir(pathtocheck, &isdir) < 0) {
1189                 /*
1190                  * If we've logged and still can't stat, there's
1191                  * a problem... 
1192                  */
1193                 sprintf(msgbuf, "%s: stat(%s): %s\n", progname, 
1194                         pathtocheck, strerror(errno));
1195                 params.pstderr(msgbuf);
1196                 return(AKLOG_BADPATH);
1197             }
1198             else if (! isdir) {
1199                 /* Allow only directories */
1200                 sprintf(msgbuf, "%s: %s: %s\n", progname, pathtocheck,
1201                         strerror(ENOTDIR));
1202                 params.pstderr(msgbuf);
1203                 return(AKLOG_BADPATH);
1204             }
1205         }
1206     }
1207     
1208
1209     return(status);
1210 }
1211
1212 #endif /* WINDOWS */
1213
1214
1215 /* Print usage message and exit */
1216 #ifdef __STDC__
1217 static void usage(void)
1218 #else
1219 static void usage()
1220 #endif /* __STDC__ */
1221 {
1222     sprintf(msgbuf, "\nUsage: %s %s%s%s\n", progname,
1223             "[-d] [[-cell | -c] cell [-k krb_realm]] ",
1224             "[[-p | -path] pathname]\n",
1225             "    [-zsubs] [-hosts] [-noauth] [-noprdb] [-force] [-setpag] [-linked]\n");
1226     params.pstderr(msgbuf);
1227     sprintf(msgbuf, "    -d gives debugging information.\n");
1228     params.pstderr(msgbuf);
1229     sprintf(msgbuf, "    krb_realm is the kerberos realm of a cell.\n");
1230     params.pstderr(msgbuf);
1231     sprintf(msgbuf, "    pathname is the name of a directory to which ");
1232     params.pstderr(msgbuf);
1233     sprintf(msgbuf, "you wish to authenticate.\n");
1234     params.pstderr(msgbuf);
1235     sprintf(msgbuf, "    -zsubs gives zephyr subscription information.\n");
1236     params.pstderr(msgbuf);
1237     sprintf(msgbuf, "    -hosts gives host address information.\n");
1238     params.pstderr(msgbuf);
1239     sprintf(msgbuf, "    -noauth does not attempt to get tokens.\n");
1240     params.pstderr(msgbuf);
1241     sprintf(msgbuf, "    -noprdb means don't try to determine AFS ID.\n");
1242     params.pstderr(msgbuf);
1243     sprintf(msgbuf, "    -force means replace identical tickets. \n");
1244     params.pstderr(msgbuf);
1245     sprintf(msgbuf, "    -linked means if AFS node is linked, try both. \n");
1246     params.pstderr(msgbuf);
1247     sprintf(msgbuf, "    -setpag set the AFS process authentication group.\n");
1248     params.pstderr(msgbuf);
1249     sprintf(msgbuf, "    No commandline arguments means ");
1250     params.pstderr(msgbuf);
1251     sprintf(msgbuf, "authenticate to the local cell.\n");
1252     params.pstderr(msgbuf);
1253     sprintf(msgbuf, "\n");
1254     params.pstderr(msgbuf);
1255     params.exitprog(AKLOG_USAGE);
1256 }
1257
1258 #ifdef __STDC__
1259 void aklog(int argc, char *argv[], aklog_params *a_params)
1260 #else
1261 void aklog(argc, argv, a_params)
1262   int argc;
1263   char *argv[];
1264   aklog_params *a_params;
1265 #endif /* __STDC__ */
1266 {
1267         krb5_context context;
1268     int status = AKLOG_SUCCESS;
1269     int i;
1270     int somethingswrong = FALSE;
1271
1272     cellinfo_t cellinfo;
1273
1274     extern char *progname;      /* Name of this program */
1275
1276     extern int dflag;           /* Debug mode */
1277
1278     int cmode = FALSE;          /* Cellname mode */
1279     int pmode = FALSE;          /* Path name mode */
1280
1281     char realm[REALM_SZ];       /* Kerberos realm of afs server */
1282     char cell[BUFSIZ];          /* Cell to which we are authenticating */
1283     char path[MAXPATHLEN + 1];          /* Path length for path mode */
1284
1285     linked_list cells;          /* List of cells to log to */
1286     linked_list paths;          /* List of paths to log to */
1287     ll_node *cur_node;
1288
1289     memset(&cellinfo, 0, sizeof(cellinfo));
1290
1291     memset(realm, 0, sizeof(realm));
1292     memset(cell, 0, sizeof(cell));
1293     memset(path, 0, sizeof(path));
1294
1295     ll_init(&cells);
1296     ll_init(&paths);
1297
1298     ll_init(&zsublist);
1299     ll_init(&hostlist);
1300
1301     /* Store the program name here for error messages */
1302     if ((progname = strrchr(argv[0], DIR)))
1303         progname++;
1304     else
1305         progname = argv[0];
1306
1307     krb5_init_context(&context);
1308 #ifndef WINDOWS
1309         initialize_ktc_error_table ();
1310 #endif
1311
1312     memcpy((char *)&params, (char *)a_params, sizeof(aklog_params));
1313
1314     /* Initialize list of cells to which we have authenticated */
1315     (void)ll_init(&authedcells);
1316
1317     /* Parse commandline arguments and make list of what to do. */
1318     for (i = 1; i < argc; i++) {
1319         if (strcmp(argv[i], "-d") == 0)
1320             dflag++;
1321         else if (strcmp(argv[i], "-noauth") == 0) 
1322             noauth++;
1323         else if (strcmp(argv[i], "-zsubs") == 0)
1324             zsubs++;
1325         else if (strcmp(argv[i], "-hosts") == 0)
1326             hosts++;
1327         else if (strcmp(argv[i], "-noprdb") == 0)
1328             noprdb++;
1329         else if (strcmp(argv[i], "-linked") == 0)
1330                 linked++;
1331         else if (strcmp(argv[i], "-force") == 0)
1332             force++;
1333     else if (strcmp(argv[i], "-setpag") == 0)
1334             afssetpag++;
1335         else if (((strcmp(argv[i], "-cell") == 0) ||
1336                   (strcmp(argv[i], "-c") == 0)) && !pmode)
1337             if (++i < argc) {
1338                 cmode++;
1339                 strcpy(cell, argv[i]);
1340             }
1341             else
1342                 usage();
1343         else if (((strcmp(argv[i], "-path") == 0) ||
1344                   (strcmp(argv[i], "-p") == 0)) && !cmode)
1345 #ifndef WINDOWS
1346             if (++i < argc) {
1347                 pmode++;
1348                 strcpy(path, argv[i]);
1349             }
1350             else
1351                 usage();
1352 #else /* WINDOWS */
1353         {
1354             sprintf(msgbuf, "%s: path mode not supported.\n", progname);
1355             params.pstderr(msgbuf);
1356             params.exitprog(AKLOG_MISC);
1357         }
1358 #endif /* WINDOWS */
1359             
1360         else if (argv[i][0] == '-')
1361             usage();
1362         else if (!pmode && !cmode) {
1363             if (strchr(argv[i], DIR) || (strcmp(argv[i], ".") == 0) ||
1364                 (strcmp(argv[i], "..") == 0)) {
1365 #ifndef WINDOWS
1366                 pmode++;
1367                 strcpy(path, argv[i]);
1368 #else /* WINDOWS */
1369                 sprintf(msgbuf, "%s: path mode not supported.\n", progname);
1370                 params.pstderr(msgbuf);
1371                 params.exitprog(AKLOG_MISC);
1372 #endif /* WINDOWS */
1373             }
1374             else { 
1375                 cmode++;
1376                 strcpy(cell, argv[i]);
1377             }
1378         }
1379         else
1380             usage();
1381
1382         if (cmode) {
1383             if (((i + 1) < argc) && (strcmp(argv[i + 1], "-k") == 0)) {
1384                 i+=2;
1385                 if (i < argc)
1386                     strcpy(realm, argv[i]);
1387                 else
1388                     usage();
1389             }
1390             /* Add this cell to list of cells */
1391             strcpy(cellinfo.cell, cell);
1392             strcpy(cellinfo.realm, realm);
1393             if ((cur_node = ll_add_node(&cells, ll_tail))) {
1394                 char *new_cellinfo;
1395                 if ((new_cellinfo = copy_cellinfo(&cellinfo)))
1396                     ll_add_data(cur_node, new_cellinfo);
1397                 else {
1398                     sprintf(msgbuf, 
1399                             "%s: failure copying cellinfo.\n", progname);
1400                     params.pstderr(msgbuf);
1401                     params.exitprog(AKLOG_MISC);
1402                 }
1403             }
1404             else {
1405                 sprintf(msgbuf, "%s: failure adding cell to cells list.\n",
1406                         progname);
1407                 params.pstderr(msgbuf);
1408                 params.exitprog(AKLOG_MISC);
1409             }
1410             memset(&cellinfo, 0, sizeof(cellinfo));
1411             cmode = FALSE;
1412             memset(cell, 0, sizeof(cell));
1413             memset(realm, 0, sizeof(realm));
1414         }
1415 #ifndef WINDOWS
1416         else if (pmode) {
1417             /* Add this path to list of paths */
1418             if ((cur_node = ll_add_node(&paths, ll_tail))) {
1419                 char *new_path; 
1420                 if ((new_path = copy_string(path)))
1421                     ll_add_data(cur_node, new_path);
1422                 else {
1423                     sprintf(msgbuf, "%s: failure copying path name.\n",
1424                             progname);
1425                     params.pstderr(msgbuf);
1426                     params.exitprog(AKLOG_MISC);
1427                 }
1428             }
1429             else {
1430                 sprintf(msgbuf, "%s: failure adding path to paths list.\n",
1431                         progname);
1432                 params.pstderr(msgbuf);
1433                 params.exitprog(AKLOG_MISC);
1434             }
1435             pmode = FALSE;
1436             memset(path, 0, sizeof(path));
1437         }
1438 #endif /* WINDOWS */
1439     }
1440
1441     /*
1442      * The code that _used_ to be here called setpag().  When you think
1443      * about this, doing this makes no sense!  setpag() allocates a PAG
1444      * only for the current process, so the token installed would have
1445      * not be usable in the parent!  Since ktc_SetToken() now takes a
1446      * 4th argument to control whether or not we're going to allocate
1447      * a PAG (and since when you do it _that_ way, it modifies the cred
1448      * structure of your parent)), why don't we use that instead?
1449      */
1450
1451 #if 0
1452     if (afssetpag) {
1453            status = setpag();
1454            if (dflag) { 
1455              int i,j;
1456                  int gidsetlen = 50;
1457          int gidset[50];
1458
1459                  printf("setpag %d\n",status);
1460              j = getgroups(gidsetlen,gidset);
1461          printf("Groups(%d):",j);
1462          for (i = 0; i<j; i++) {
1463            printf("%d",gidset[i]);
1464            if((i+1)<j) printf(",");
1465          }
1466          printf("\n");
1467            }
1468         }
1469 #endif
1470     /* If nothing was given, log to the local cell. */
1471     if ((cells.nelements + paths.nelements) == 0) {
1472                 struct passwd *pwd;
1473
1474                 status = auth_to_cell(context, NULL, NULL);
1475         
1476                 /* If this cell is linked to a DCE cell, and user 
1477                  * requested -linked, get tokens for both 
1478                  * This is very usefull when the AFS cell is linked to a DFS 
1479                  * cell and this system does not also have DFS. 
1480                  */
1481
1482                 if (!status && linked && linkedcell[0]) {
1483                                 strncpy(linkedcell2,linkedcell,MAXCELLCHARS);
1484                             if (dflag) {
1485                                 sprintf(msgbuf, "Linked cell: %s\n",
1486                                     linkedcell);
1487                                 params.pstdout(msgbuf);
1488                             }
1489                                 status = auth_to_cell(context, linkedcell2, NULL);
1490                 }
1491
1492 #ifndef WINDOWS
1493                 /*
1494                  * Local hack - if the person has a file in their home
1495                  * directory called ".xlog", read that for a list of
1496                  * extra cells to authenticate to
1497                  */
1498
1499                 if ((pwd = getpwuid(getuid())) != NULL) {
1500                     struct stat sbuf;
1501                     FILE *f;
1502                     char fcell[100], xlog_path[512];
1503
1504                     strcpy(xlog_path, pwd->pw_dir);
1505                     strcat(xlog_path, "/.xlog");
1506
1507                     if ((stat(xlog_path, &sbuf) == 0) &&
1508                         ((f = fopen(xlog_path, "r")) != NULL)) {
1509
1510                         if (dflag) {
1511                             sprintf(msgbuf, "Reading %s for cells to "
1512                                     "authenticate to.\n", xlog_path);
1513                             params.pstdout(msgbuf);
1514                         }
1515
1516                         while (fgets(fcell, 100, f) != NULL) {
1517                             int auth_status;
1518
1519                             fcell[strlen(fcell) - 1] = '\0';
1520
1521                             if (dflag) {
1522                                 sprintf(msgbuf, "Found cell %s in %s.\n",
1523                                         fcell, xlog_path);
1524                                 params.pstdout(msgbuf);
1525                             }
1526
1527                             auth_status = auth_to_cell(context, fcell, NULL);
1528                             if (status == AKLOG_SUCCESS)
1529                                 status = auth_status;
1530                             else
1531                                 status = AKLOG_SOMETHINGSWRONG;
1532                         }
1533                     }
1534                 }
1535 #endif /* WINDOWS */
1536         }
1537     else {
1538         /* Log to all cells in the cells list first */
1539         for (cur_node = cells.first; cur_node; cur_node = cur_node->next) {
1540             memcpy((char *)&cellinfo, cur_node->data, sizeof(cellinfo));
1541             if ((status = auth_to_cell(context, cellinfo.cell, cellinfo.realm)))
1542                 somethingswrong++;
1543                 else {
1544                         if (linked && linkedcell[0]) {
1545                                 strncpy(linkedcell2,linkedcell,MAXCELLCHARS);
1546                 if (dflag) {
1547                     sprintf(msgbuf, "Linked cell: %s\n",
1548                         linkedcell);
1549                     params.pstdout(msgbuf);
1550                 }
1551                                 if ((status = auth_to_cell(context,linkedcell2,
1552                                                          cellinfo.realm)))
1553                                 somethingswrong++;
1554                         }
1555                 }
1556         }
1557         
1558 #ifndef WINDOWS
1559         /* Then, log to all paths in the paths list */
1560         for (cur_node = paths.first; cur_node; cur_node = cur_node->next) {
1561             if ((status = auth_to_path(context, cur_node->data)))
1562                 somethingswrong++;
1563         }
1564 #endif /* WINDOWS */
1565         
1566         /* 
1567          * If only one thing was logged to, we'll return the status 
1568          * of the single call.  Otherwise, we'll return a generic
1569          * something failed status.
1570          */
1571         if (somethingswrong && ((cells.nelements + paths.nelements) > 1))
1572             status = AKLOG_SOMETHINGSWRONG;
1573     }
1574
1575     /* If we are keeping track of zephyr subscriptions, print them. */
1576     if (zsubs) 
1577         for (cur_node = zsublist.first; cur_node; cur_node = cur_node->next) {
1578             sprintf(msgbuf, "zsub: %s\n", cur_node->data);
1579             params.pstdout(msgbuf);
1580         }
1581
1582     /* If we are keeping track of host information, print it. */
1583     if (hosts)
1584         for (cur_node = hostlist.first; cur_node; cur_node = cur_node->next) {
1585             sprintf(msgbuf, "host: %s\n", cur_node->data);
1586             params.pstdout(msgbuf);
1587         }
1588
1589     params.exitprog(status);
1590 }
1591
1592 #ifndef HAVE_ADD_TO_ERROR_TABLE
1593 #include <afs/error_table.h>
1594
1595 void add_error_table (const struct error_table *);
1596
1597 void
1598 add_to_error_table(struct et_list *new_table)
1599 {
1600         add_error_table(new_table->table);
1601 }
1602 #endif /* HAVE_ADD_TO_ERROR_TABLE */