9189999119aa19701578753b1972a1c08e227d9b
[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             /*
698              * Talk about DUMB!  It turns out that there is a bug in
699              * pr_Initialize -- even if you give a different cell name
700              * to it, it still uses a connection to a previous AFS server
701              * if one exists.  The way to fix this is to change the
702              * _filename_ argument to pr_Initialize - that forces it to
703              * re-initialize the connection.  We do this by adding and
704              * removing a "/" on the end of the configuration directory name.
705              */
706
707             if (lastcell[0] != '\0' && (strcmp(lastcell, aserver.cell) != 0)) {
708                 int i = strlen(confname);
709                 if (confname[i - 1] == '/') {
710                     confname[i - 1] = '\0';
711                 } else {
712                     confname[i] = '/';
713                     confname[i + 1] = '\0';
714                 }
715             }
716
717             strcpy(lastcell, aserver.cell);
718
719             if (!pr_Initialize (0, confname, aserver.cell, 0))
720                     status = pr_SNameToId (username, &viceId);
721             
722             if (dflag) {
723                 if (status) 
724                     sprintf(msgbuf, "Error %d\n", status);
725                 else
726                     sprintf(msgbuf, "Id %d\n", (int) viceId);
727                 params.pstdout(msgbuf);
728             }
729             
730                 /*
731                  * This is a crock, but it is Transarc's crock, so
732                  * we have to play along in order to get the
733                  * functionality.  The way the afs id is stored is
734                  * as a string in the username field of the token.
735                  * Contrary to what you may think by looking at
736                  * the code for tokens, this hack (AFS ID %d) will
737                  * not work if you change %d to something else.
738                  */
739
740                 /*
741                  * This code is taken from cklog -- it lets people
742                  * automatically register with the ptserver in foreign cells
743                  */
744
745 #ifdef ALLOW_REGISTER
746         if (status == 0) {
747             if (viceId != ANONYMOUSID) {
748 #else /* ALLOW_REGISTER */
749             if ((status == 0) && (viceId != ANONYMOUSID))
750 #endif /* ALLOW_REGISTER */
751                 sprintf (username, "AFS ID %d", (int) viceId);
752 #ifdef ALLOW_REGISTER
753             } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
754                 if (dflag) {
755                     sprintf(msgbuf, "doing first-time registration of %s "
756                             "at %s\n", username, cell_to_use);
757                     params.pstdout(msgbuf);
758                 }
759                 id = 0;
760                 strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
761                 strcpy(aclient.instance, "");
762                 strncpy(aclient.cell, c.realm, MAXKTCREALMLEN - 1);
763                 if ((status = ktc_SetToken(&aserver, &atoken, &aclient, 0))) {
764                     sprintf(msgbuf, "%s: unable to obtain tokens for cell %s "
765                             "(status: %d).\n", progname, cell_to_use, status);
766                     params.pstderr(msgbuf);
767                     status = AKLOG_TOKEN;
768                 }
769
770                 /*
771                  * In case you're wondering, we don't need to change the
772                  * filename here because we're still connecting to the
773                  * same cell -- we're just using a different authentication
774                  * level
775                  */
776
777                 if ((status = pr_Initialize(1L, confname, aserver.cell, 0))) {
778                     sprintf(msgbuf, "Error %d\n", status);
779                     params.pstdout(msgbuf);
780                 }
781
782                 if ((status = pr_CreateUser(username, &id))) {
783                     sprintf(msgbuf, "%s: %s so unable to create remote PTS "
784                             "user %s in cell %s (status: %d).\n", progname,
785                             error_message(status), username, cell_to_use,
786                             status);
787                     params.pstdout(msgbuf);
788                 } else {
789                     sprintf(msgbuf, "created cross-cell entry for %s at %s\n",
790                             username, cell_to_use);
791                     params.pstdout(msgbuf);
792                     sprintf(username, "AFS ID %d", (int) id);
793                 }
794             }
795         }
796 #endif /* ALLOW_REGISTER */
797
798         }
799 #endif /* !WINDOWS */
800
801         if (dflag) {
802             sprintf(msgbuf, "Set username to %s\n", username);
803             params.pstdout(msgbuf);
804         }
805
806         /* Reset the "aclient" structure before we call ktc_SetToken.
807          * This structure was first set by the ktc_GetToken call when
808          * we were comparing whether identical tokens already existed.
809          */
810         strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
811         strcpy(aclient.instance, "");
812         strncpy(aclient.cell, c.realm, MAXKTCREALMLEN - 1);
813
814         if (dflag) {
815             sprintf(msgbuf, "Setting tokens. %s / %s @ %s \n",
816                         aclient.name, aclient.instance, aclient.cell );
817             params.pstdout(msgbuf);
818         }
819         /* on AIX 4.1.4 with AFS 3.4a+ if a write is not done before 
820          * this routine, it will not add the token. It is not clear what 
821          * is going on here! So we will do the following operation
822          */
823         write(2,"",0); /* dummy write */
824 #ifndef WINDOWS
825         if ((status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag))) {
826             sprintf(msgbuf, 
827                     "%s: unable to obtain tokens for cell %s (status: %d).\n",
828                     progname, cell_to_use, status);
829             params.pstderr(msgbuf);
830             status = AKLOG_TOKEN;
831         }
832 #else /* WINDOWS */
833         /* Note switched 2nd and 3rd args */
834 #ifdef PRE_AFS35
835         if ((status = ktc_SetToken(&aserver, &aclient, &atoken, afssetpag))) {
836 #else
837         if ((status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag))) {
838 #endif
839             switch(status) {
840             case KTC_INVAL:
841                 sprintf(msgbuf, "%s: Bad ticket length", progname);
842                 break;
843             case KTC_PIOCTLFAIL:
844                 sprintf(msgbuf, "%s: Unknown error contacting AFS service",
845                         progname);
846                 break;
847             case KTC_NOCELL:
848                 sprintf(msgbuf, "%s: Cell name (%s) not recognized by AFS service",
849                         progname, realm_of_cell);
850                 break;
851             case KTC_NOCM:
852                 sprintf(msgbuf, "%s: AFS service is unavailable", progname);
853                 break;
854             default:
855                 sprintf(msgbuf, "%s: Undocumented error (%d) contacting AFS service", progname, status);
856                 break;  
857             }
858             params.pstderr(msgbuf);
859             status = AKLOG_TOKEN;           
860         }
861 #endif /* !WINDOWS */
862     }
863     else
864         if (dflag) {
865             sprintf(msgbuf, "Noauth mode; not authenticating.\n");
866             params.pstdout(msgbuf);
867         }
868         
869     return(status);
870 }
871
872 #ifndef WINDOWS /* struct ViceIoctl missing */
873
874 #ifdef __STDC__
875 static int get_afs_mountpoint(char *file, char *mountpoint, int size)
876 #else
877 static int get_afs_mountpoint(file, mountpoint, size)
878   char *file;
879   char *mountpoint;
880   int size;
881 #endif /* __STDC__ */
882 {
883 #ifdef AFS_SUN_ENV
884         char V ='V'; /* AFS has problem on Sun with pioctl */
885 #endif
886     char our_file[MAXPATHLEN + 1];
887     char *parent_dir;
888     char *last_component;
889     struct ViceIoctl vio;
890     char cellname[BUFSIZ];
891
892     memset(our_file, 0, sizeof(our_file));
893     strcpy(our_file, file);
894
895     if ((last_component = strrchr(our_file, DIR))) {
896         *last_component++ = 0;
897         parent_dir = our_file;
898     }
899     else {
900         last_component = our_file;
901         parent_dir = ".";
902     }    
903     
904     memset(cellname, 0, sizeof(cellname));
905
906     vio.in = last_component;
907     vio.in_size = strlen(last_component)+1;
908     vio.out_size = size;
909     vio.out = mountpoint;
910
911     if (!pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, &vio, 0)) {
912         if (strchr(mountpoint, VOLMARKER) == NULL) {
913             vio.in = file;
914             vio.in_size = strlen(file) + 1;
915             vio.out_size = sizeof(cellname);
916             vio.out = cellname;
917             
918             if (!pioctl(file, VIOC_FILE_CELL_NAME, &vio, 1)) {
919                 strcat(cellname, VOLMARKERSTRING);
920                 strcat(cellname, mountpoint + 1);
921                 memset(mountpoint + 1, 0, size - 1);
922                 strcpy(mountpoint + 1, cellname);
923             }
924         }
925         return(TRUE);
926     }
927     else
928         return(FALSE);
929 }
930
931 /* 
932  * This routine each time it is called returns the next directory 
933  * down a pathname.  It resolves all symbolic links.  The first time
934  * it is called, it should be called with the name of the path
935  * to be descended.  After that, it should be called with the arguemnt
936  * NULL.
937  */
938 #ifdef __STDC__
939 static char *next_path(char *origpath)
940 #else
941 static char *next_path(origpath)
942   char *origpath;
943 #endif /* __STDC__ */
944 {
945     static char path[MAXPATHLEN + 1];
946     static char pathtocheck[MAXPATHLEN + 1];
947
948     int link = FALSE;           /* Is this a symbolic link? */
949     char linkbuf[MAXPATHLEN + 1];
950     char tmpbuf[MAXPATHLEN + 1];
951
952     static char *last_comp;     /* last component of directory name */
953     static char *elast_comp;    /* End of last component */
954     char *t;
955     int len;
956     
957     static int symlinkcount = 0; /* We can't exceed MAXSYMLINKS */
958     
959     /* If we are given something for origpath, we are initializing only. */
960     if (origpath) {
961         memset(path, 0, sizeof(path));
962         memset(pathtocheck, 0, sizeof(pathtocheck));
963         strcpy(path, origpath);
964         last_comp = path;
965         symlinkcount = 0;
966         return(NULL);
967     }
968
969     /* We were not given origpath; find then next path to check */
970     
971     /* If we've gotten all the way through already, return NULL */
972     if (last_comp == NULL)
973         return(NULL);
974
975     do {
976         while (*last_comp == DIR)
977             strncat(pathtocheck, last_comp++, 1);
978         len = (elast_comp = strchr(last_comp, DIR)) 
979             ? elast_comp - last_comp : strlen(last_comp);
980         strncat(pathtocheck, last_comp, len);
981         memset(linkbuf, 0, sizeof(linkbuf));
982         if ((link = (params.readlink(pathtocheck, linkbuf, 
983                                     sizeof(linkbuf)) > 0))) {
984             if (++symlinkcount > MAXSYMLINKS) {
985                 sprintf(msgbuf, "%s: %s\n", progname, strerror(ELOOP));
986                 params.pstderr(msgbuf);
987                 params.exitprog(AKLOG_BADPATH);
988             }
989             memset(tmpbuf, 0, sizeof(tmpbuf));
990             if (elast_comp)
991                 strcpy(tmpbuf, elast_comp);
992             if (linkbuf[0] == DIR) {
993                 /* 
994                  * If this is a symbolic link to an absolute path, 
995                  * replace what we have by the absolute path.
996                  */
997                 memset(path, 0, strlen(path));
998                 memcpy(path, linkbuf, sizeof(linkbuf));
999                 strcat(path, tmpbuf);
1000                 last_comp = path;
1001                 elast_comp = NULL;
1002                 memset(pathtocheck, 0, sizeof(pathtocheck));
1003             }
1004             else {
1005                 /* 
1006                  * If this is a symbolic link to a relative path, 
1007                  * replace only the last component with the link name.
1008                  */
1009                 strncpy(last_comp, linkbuf, strlen(linkbuf) + 1);
1010                 strcat(path, tmpbuf);
1011                 elast_comp = NULL;
1012                 if ((t = strrchr(pathtocheck, DIR))) {
1013                     t++;
1014                     memset(t, 0, strlen(t));
1015                 }
1016                 else
1017                     memset(pathtocheck, 0, sizeof(pathtocheck));
1018             }
1019         }
1020         else
1021             last_comp = elast_comp;
1022     }
1023     while(link);
1024
1025     return(pathtocheck);
1026 }
1027
1028 #endif /* WINDOWS */
1029
1030 #if 0
1031 /*****************************************/
1032 int dee_gettokens()
1033 {
1034 #ifdef AFS_SUN_ENV
1035         char V = 'V'; /* AFS has problem on SunOS */
1036 #endif
1037    struct ViceIoctl vio;
1038    char outbuf[BUFSIZ];
1039    long ind;
1040    int fd;
1041
1042    memset(outbuf, 0, sizeof(outbuf));
1043
1044    vio.out_size = sizeof(outbuf);
1045    vio.in_size = sizeof(ind);
1046    vio.out = outbuf;
1047    vio.in = &ind;
1048
1049    ind = 0;
1050    fd = open("dee.tok",O_WRONLY);
1051    while(!pioctl(0,VIOCGETTOK,&vio,0)) {
1052         write(fd,&outbuf,sizeof(outbuf)); 
1053        ind++;
1054    }
1055    close(fd);
1056 }
1057 /*****************************************/
1058 #endif
1059
1060 #ifndef WINDOWS /* struct ViceIoctl missing */
1061
1062 #ifdef __STDC__
1063 static void add_hosts(char *file)
1064 #else
1065 static void add_hosts(file)
1066   char *file;
1067 #endif /* __STDC__ */
1068 {
1069 #ifdef AFS_SUN_ENV
1070         char V = 'V'; /* AFS has problem on SunOS */
1071 #endif
1072     struct ViceIoctl vio;
1073     char outbuf[BUFSIZ];
1074     long *phosts;
1075     int i;
1076     struct hostent *hp;
1077     struct in_addr in;
1078     
1079     memset(outbuf, 0, sizeof(outbuf));
1080
1081     vio.out_size = sizeof(outbuf);
1082     vio.in_size = 0;
1083     vio.out = outbuf;
1084
1085     if (dflag) {
1086         sprintf(msgbuf, "Getting list of hosts for %s\n", file);
1087         params.pstdout(msgbuf);
1088     }
1089     /* Don't worry about errors. */
1090     if (!pioctl(file, VIOCWHEREIS, &vio, 1)) {
1091         phosts = (long *) outbuf;
1092
1093         /*
1094          * Lists hosts that we care about.  If ALLHOSTS is defined,
1095          * then all hosts that you ever may possible go through are
1096          * included in this list.  If not, then only hosts that are
1097          * the only ones appear.  That is, if a volume you must use
1098          * is replaced on only one server, that server is included.
1099          * If it is replicated on many servers, then none are included.
1100          * This is not perfect, but the result is that people don't
1101          * get subscribed to a lot of instances of FILSRV that they
1102          * probably won't need which reduces the instances of 
1103          * people getting messages that don't apply to them.
1104          */
1105 #ifndef ALLHOSTS
1106         if (phosts[1] != '\0')
1107             return;
1108 #endif
1109         for (i = 0; phosts[i]; i++) {
1110             if (hosts) {
1111                 in.s_addr = phosts[i];
1112                 if (dflag) {
1113                     sprintf(msgbuf, "Got host %s\n", inet_ntoa(in));
1114                     params.pstdout(msgbuf);
1115                 }
1116                 ll_string(&hostlist, ll_s_add, (char *)inet_ntoa(in));
1117             }
1118             if (zsubs && (hp=gethostbyaddr((char *) &phosts[i],sizeof(long),AF_INET))) {
1119                 if (dflag) {
1120                     sprintf(msgbuf, "Got host %s\n", hp->h_name);
1121                     params.pstdout(msgbuf);
1122                 }
1123                 ll_string(&zsublist, ll_s_add, hp->h_name);
1124             }
1125         }
1126     }
1127 }
1128
1129 #endif /* WINDOWS */
1130
1131 #ifndef WINDOWS /* next_path(), get_afs_mountpoint() */
1132
1133 /*
1134  * This routine descends through a path to a directory, logging to 
1135  * every cell it encounters along the way.
1136  */
1137 #ifdef __STDC__
1138 static int auth_to_path(krb5_context context, char *path)
1139 #else
1140 static int auth_to_path(context, path)
1141   krb5_context context;
1142   char *path;                   /* The path to which we try to authenticate */
1143 #endif /* __STDC__ */
1144 {
1145     int status = AKLOG_SUCCESS;
1146     int auth_to_cell_status = AKLOG_SUCCESS;
1147
1148     char *nextpath;
1149     char pathtocheck[MAXPATHLEN + 1];
1150     char mountpoint[MAXPATHLEN + 1];
1151
1152     char *cell;
1153     char *endofcell;
1154
1155     u_char isdir;
1156
1157     /* Initialize */
1158     if (path[0] == DIR)
1159         strcpy(pathtocheck, path);
1160     else {
1161         if (params.getwd(pathtocheck) == NULL) {
1162             sprintf(msgbuf, "Unable to find current working directory:\n");
1163             params.pstderr(msgbuf);
1164             sprintf(msgbuf, "%s\n", pathtocheck);
1165             params.pstderr(msgbuf);
1166             sprintf(msgbuf, "Try an absolute pathname.\n");
1167             params.pstderr(msgbuf);
1168             params.exitprog(AKLOG_BADPATH);
1169         }
1170         else {
1171             strcat(pathtocheck, DIRSTRING);
1172             strcat(pathtocheck, path);
1173         }
1174     }
1175     next_path(pathtocheck);
1176
1177     /* Go on to the next level down the path */
1178     while ((nextpath = next_path(NULL))) {
1179         strcpy(pathtocheck, nextpath);
1180         if (dflag) {
1181             sprintf(msgbuf, "Checking directory %s\n", pathtocheck);
1182             params.pstdout(msgbuf);
1183         }
1184         /* 
1185          * If this is an afs mountpoint, determine what cell from 
1186          * the mountpoint name which is of the form 
1187          * #cellname:volumename or %cellname:volumename.
1188          */
1189         if (get_afs_mountpoint(pathtocheck, mountpoint, sizeof(mountpoint))) {
1190             /* skip over the '#' or '%' */
1191             cell = mountpoint + 1;
1192             /* Add this (cell:volumename) to the list of zsubs */
1193             if (zsubs)
1194                 ll_string(&zsublist, ll_s_add, cell);
1195             if (zsubs || hosts)
1196                 add_hosts(pathtocheck);
1197             if ((endofcell = strchr(mountpoint, VOLMARKER))) {
1198                 *endofcell = '\0';
1199                 if ((auth_to_cell_status = auth_to_cell(context, cell, NULL))) {
1200                     if (status == AKLOG_SUCCESS)
1201                         status = auth_to_cell_status;
1202                     else if (status != auth_to_cell_status)
1203                         status = AKLOG_SOMETHINGSWRONG;
1204                 }
1205             }
1206         }
1207         else {
1208             if (params.isdir(pathtocheck, &isdir) < 0) {
1209                 /*
1210                  * If we've logged and still can't stat, there's
1211                  * a problem... 
1212                  */
1213                 sprintf(msgbuf, "%s: stat(%s): %s\n", progname, 
1214                         pathtocheck, strerror(errno));
1215                 params.pstderr(msgbuf);
1216                 return(AKLOG_BADPATH);
1217             }
1218             else if (! isdir) {
1219                 /* Allow only directories */
1220                 sprintf(msgbuf, "%s: %s: %s\n", progname, pathtocheck,
1221                         strerror(ENOTDIR));
1222                 params.pstderr(msgbuf);
1223                 return(AKLOG_BADPATH);
1224             }
1225         }
1226     }
1227     
1228
1229     return(status);
1230 }
1231
1232 #endif /* WINDOWS */
1233
1234
1235 /* Print usage message and exit */
1236 #ifdef __STDC__
1237 static void usage(void)
1238 #else
1239 static void usage()
1240 #endif /* __STDC__ */
1241 {
1242     sprintf(msgbuf, "\nUsage: %s %s%s%s\n", progname,
1243             "[-d] [[-cell | -c] cell [-k krb_realm]] ",
1244             "[[-p | -path] pathname]\n",
1245             "    [-zsubs] [-hosts] [-noauth] [-noprdb] [-force] [-setpag] [-linked]\n");
1246     params.pstderr(msgbuf);
1247     sprintf(msgbuf, "    -d gives debugging information.\n");
1248     params.pstderr(msgbuf);
1249     sprintf(msgbuf, "    krb_realm is the kerberos realm of a cell.\n");
1250     params.pstderr(msgbuf);
1251     sprintf(msgbuf, "    pathname is the name of a directory to which ");
1252     params.pstderr(msgbuf);
1253     sprintf(msgbuf, "you wish to authenticate.\n");
1254     params.pstderr(msgbuf);
1255     sprintf(msgbuf, "    -zsubs gives zephyr subscription information.\n");
1256     params.pstderr(msgbuf);
1257     sprintf(msgbuf, "    -hosts gives host address information.\n");
1258     params.pstderr(msgbuf);
1259     sprintf(msgbuf, "    -noauth does not attempt to get tokens.\n");
1260     params.pstderr(msgbuf);
1261     sprintf(msgbuf, "    -noprdb means don't try to determine AFS ID.\n");
1262     params.pstderr(msgbuf);
1263     sprintf(msgbuf, "    -force means replace identical tickets. \n");
1264     params.pstderr(msgbuf);
1265     sprintf(msgbuf, "    -linked means if AFS node is linked, try both. \n");
1266     params.pstderr(msgbuf);
1267     sprintf(msgbuf, "    -setpag set the AFS process authentication group.\n");
1268     params.pstderr(msgbuf);
1269     sprintf(msgbuf, "    No commandline arguments means ");
1270     params.pstderr(msgbuf);
1271     sprintf(msgbuf, "authenticate to the local cell.\n");
1272     params.pstderr(msgbuf);
1273     sprintf(msgbuf, "\n");
1274     params.pstderr(msgbuf);
1275     params.exitprog(AKLOG_USAGE);
1276 }
1277
1278 #ifdef __STDC__
1279 void aklog(int argc, char *argv[], aklog_params *a_params)
1280 #else
1281 void aklog(argc, argv, a_params)
1282   int argc;
1283   char *argv[];
1284   aklog_params *a_params;
1285 #endif /* __STDC__ */
1286 {
1287         krb5_context context;
1288     int status = AKLOG_SUCCESS;
1289     int i;
1290     int somethingswrong = FALSE;
1291
1292     cellinfo_t cellinfo;
1293
1294     extern char *progname;      /* Name of this program */
1295
1296     extern int dflag;           /* Debug mode */
1297
1298     int cmode = FALSE;          /* Cellname mode */
1299     int pmode = FALSE;          /* Path name mode */
1300
1301     char realm[REALM_SZ];       /* Kerberos realm of afs server */
1302     char cell[BUFSIZ];          /* Cell to which we are authenticating */
1303     char path[MAXPATHLEN + 1];          /* Path length for path mode */
1304
1305     linked_list cells;          /* List of cells to log to */
1306     linked_list paths;          /* List of paths to log to */
1307     ll_node *cur_node;
1308
1309     memset(&cellinfo, 0, sizeof(cellinfo));
1310
1311     memset(realm, 0, sizeof(realm));
1312     memset(cell, 0, sizeof(cell));
1313     memset(path, 0, sizeof(path));
1314
1315     ll_init(&cells);
1316     ll_init(&paths);
1317
1318     ll_init(&zsublist);
1319     ll_init(&hostlist);
1320
1321     /* Store the program name here for error messages */
1322     if ((progname = strrchr(argv[0], DIR)))
1323         progname++;
1324     else
1325         progname = argv[0];
1326
1327     krb5_init_context(&context);
1328 #ifndef WINDOWS
1329         initialize_ktc_error_table ();
1330 #endif
1331
1332     memcpy((char *)&params, (char *)a_params, sizeof(aklog_params));
1333
1334     /* Initialize list of cells to which we have authenticated */
1335     (void)ll_init(&authedcells);
1336
1337     /* Parse commandline arguments and make list of what to do. */
1338     for (i = 1; i < argc; i++) {
1339         if (strcmp(argv[i], "-d") == 0)
1340             dflag++;
1341         else if (strcmp(argv[i], "-noauth") == 0) 
1342             noauth++;
1343         else if (strcmp(argv[i], "-zsubs") == 0)
1344             zsubs++;
1345         else if (strcmp(argv[i], "-hosts") == 0)
1346             hosts++;
1347         else if (strcmp(argv[i], "-noprdb") == 0)
1348             noprdb++;
1349         else if (strcmp(argv[i], "-linked") == 0)
1350                 linked++;
1351         else if (strcmp(argv[i], "-force") == 0)
1352             force++;
1353     else if (strcmp(argv[i], "-setpag") == 0)
1354             afssetpag++;
1355         else if (((strcmp(argv[i], "-cell") == 0) ||
1356                   (strcmp(argv[i], "-c") == 0)) && !pmode)
1357             if (++i < argc) {
1358                 cmode++;
1359                 strcpy(cell, argv[i]);
1360             }
1361             else
1362                 usage();
1363         else if (((strcmp(argv[i], "-path") == 0) ||
1364                   (strcmp(argv[i], "-p") == 0)) && !cmode)
1365 #ifndef WINDOWS
1366             if (++i < argc) {
1367                 pmode++;
1368                 strcpy(path, argv[i]);
1369             }
1370             else
1371                 usage();
1372 #else /* WINDOWS */
1373         {
1374             sprintf(msgbuf, "%s: path mode not supported.\n", progname);
1375             params.pstderr(msgbuf);
1376             params.exitprog(AKLOG_MISC);
1377         }
1378 #endif /* WINDOWS */
1379             
1380         else if (argv[i][0] == '-')
1381             usage();
1382         else if (!pmode && !cmode) {
1383             if (strchr(argv[i], DIR) || (strcmp(argv[i], ".") == 0) ||
1384                 (strcmp(argv[i], "..") == 0)) {
1385 #ifndef WINDOWS
1386                 pmode++;
1387                 strcpy(path, argv[i]);
1388 #else /* WINDOWS */
1389                 sprintf(msgbuf, "%s: path mode not supported.\n", progname);
1390                 params.pstderr(msgbuf);
1391                 params.exitprog(AKLOG_MISC);
1392 #endif /* WINDOWS */
1393             }
1394             else { 
1395                 cmode++;
1396                 strcpy(cell, argv[i]);
1397             }
1398         }
1399         else
1400             usage();
1401
1402         if (cmode) {
1403             if (((i + 1) < argc) && (strcmp(argv[i + 1], "-k") == 0)) {
1404                 i+=2;
1405                 if (i < argc)
1406                     strcpy(realm, argv[i]);
1407                 else
1408                     usage();
1409             }
1410             /* Add this cell to list of cells */
1411             strcpy(cellinfo.cell, cell);
1412             strcpy(cellinfo.realm, realm);
1413             if ((cur_node = ll_add_node(&cells, ll_tail))) {
1414                 char *new_cellinfo;
1415                 if ((new_cellinfo = copy_cellinfo(&cellinfo)))
1416                     ll_add_data(cur_node, new_cellinfo);
1417                 else {
1418                     sprintf(msgbuf, 
1419                             "%s: failure copying cellinfo.\n", progname);
1420                     params.pstderr(msgbuf);
1421                     params.exitprog(AKLOG_MISC);
1422                 }
1423             }
1424             else {
1425                 sprintf(msgbuf, "%s: failure adding cell to cells list.\n",
1426                         progname);
1427                 params.pstderr(msgbuf);
1428                 params.exitprog(AKLOG_MISC);
1429             }
1430             memset(&cellinfo, 0, sizeof(cellinfo));
1431             cmode = FALSE;
1432             memset(cell, 0, sizeof(cell));
1433             memset(realm, 0, sizeof(realm));
1434         }
1435 #ifndef WINDOWS
1436         else if (pmode) {
1437             /* Add this path to list of paths */
1438             if ((cur_node = ll_add_node(&paths, ll_tail))) {
1439                 char *new_path; 
1440                 if ((new_path = copy_string(path)))
1441                     ll_add_data(cur_node, new_path);
1442                 else {
1443                     sprintf(msgbuf, "%s: failure copying path name.\n",
1444                             progname);
1445                     params.pstderr(msgbuf);
1446                     params.exitprog(AKLOG_MISC);
1447                 }
1448             }
1449             else {
1450                 sprintf(msgbuf, "%s: failure adding path to paths list.\n",
1451                         progname);
1452                 params.pstderr(msgbuf);
1453                 params.exitprog(AKLOG_MISC);
1454             }
1455             pmode = FALSE;
1456             memset(path, 0, sizeof(path));
1457         }
1458 #endif /* WINDOWS */
1459     }
1460
1461     /*
1462      * The code that _used_ to be here called setpag().  When you think
1463      * about this, doing this makes no sense!  setpag() allocates a PAG
1464      * only for the current process, so the token installed would have
1465      * not be usable in the parent!  Since ktc_SetToken() now takes a
1466      * 4th argument to control whether or not we're going to allocate
1467      * a PAG (and since when you do it _that_ way, it modifies the cred
1468      * structure of your parent)), why don't we use that instead?
1469      */
1470
1471 #if 0
1472     if (afssetpag) {
1473            status = setpag();
1474            if (dflag) { 
1475              int i,j;
1476                  int gidsetlen = 50;
1477          int gidset[50];
1478
1479                  printf("setpag %d\n",status);
1480              j = getgroups(gidsetlen,gidset);
1481          printf("Groups(%d):",j);
1482          for (i = 0; i<j; i++) {
1483            printf("%d",gidset[i]);
1484            if((i+1)<j) printf(",");
1485          }
1486          printf("\n");
1487            }
1488         }
1489 #endif
1490     /* If nothing was given, log to the local cell. */
1491     if ((cells.nelements + paths.nelements) == 0) {
1492                 struct passwd *pwd;
1493
1494                 status = auth_to_cell(context, NULL, NULL);
1495         
1496                 /* If this cell is linked to a DCE cell, and user 
1497                  * requested -linked, get tokens for both 
1498                  * This is very usefull when the AFS cell is linked to a DFS 
1499                  * cell and this system does not also have DFS. 
1500                  */
1501
1502                 if (!status && linked && linkedcell[0]) {
1503                                 strncpy(linkedcell2,linkedcell,MAXCELLCHARS);
1504                             if (dflag) {
1505                                 sprintf(msgbuf, "Linked cell: %s\n",
1506                                     linkedcell);
1507                                 params.pstdout(msgbuf);
1508                             }
1509                                 status = auth_to_cell(context, linkedcell2, NULL);
1510                 }
1511
1512 #ifndef WINDOWS
1513                 /*
1514                  * Local hack - if the person has a file in their home
1515                  * directory called ".xlog", read that for a list of
1516                  * extra cells to authenticate to
1517                  */
1518
1519                 if ((pwd = getpwuid(getuid())) != NULL) {
1520                     struct stat sbuf;
1521                     FILE *f;
1522                     char fcell[100], xlog_path[512];
1523
1524                     strcpy(xlog_path, pwd->pw_dir);
1525                     strcat(xlog_path, "/.xlog");
1526
1527                     if ((stat(xlog_path, &sbuf) == 0) &&
1528                         ((f = fopen(xlog_path, "r")) != NULL)) {
1529
1530                         if (dflag) {
1531                             sprintf(msgbuf, "Reading %s for cells to "
1532                                     "authenticate to.\n", xlog_path);
1533                             params.pstdout(msgbuf);
1534                         }
1535
1536                         while (fgets(fcell, 100, f) != NULL) {
1537                             int auth_status;
1538
1539                             fcell[strlen(fcell) - 1] = '\0';
1540
1541                             if (dflag) {
1542                                 sprintf(msgbuf, "Found cell %s in %s.\n",
1543                                         fcell, xlog_path);
1544                                 params.pstdout(msgbuf);
1545                             }
1546
1547                             auth_status = auth_to_cell(context, fcell, NULL);
1548                             if (status == AKLOG_SUCCESS)
1549                                 status = auth_status;
1550                             else
1551                                 status = AKLOG_SOMETHINGSWRONG;
1552                         }
1553                     }
1554                 }
1555 #endif /* WINDOWS */
1556         }
1557     else {
1558         /* Log to all cells in the cells list first */
1559         for (cur_node = cells.first; cur_node; cur_node = cur_node->next) {
1560             memcpy((char *)&cellinfo, cur_node->data, sizeof(cellinfo));
1561             if ((status = auth_to_cell(context, cellinfo.cell, cellinfo.realm)))
1562                 somethingswrong++;
1563                 else {
1564                         if (linked && linkedcell[0]) {
1565                                 strncpy(linkedcell2,linkedcell,MAXCELLCHARS);
1566                 if (dflag) {
1567                     sprintf(msgbuf, "Linked cell: %s\n",
1568                         linkedcell);
1569                     params.pstdout(msgbuf);
1570                 }
1571                                 if ((status = auth_to_cell(context,linkedcell2,
1572                                                          cellinfo.realm)))
1573                                 somethingswrong++;
1574                         }
1575                 }
1576         }
1577         
1578 #ifndef WINDOWS
1579         /* Then, log to all paths in the paths list */
1580         for (cur_node = paths.first; cur_node; cur_node = cur_node->next) {
1581             if ((status = auth_to_path(context, cur_node->data)))
1582                 somethingswrong++;
1583         }
1584 #endif /* WINDOWS */
1585         
1586         /* 
1587          * If only one thing was logged to, we'll return the status 
1588          * of the single call.  Otherwise, we'll return a generic
1589          * something failed status.
1590          */
1591         if (somethingswrong && ((cells.nelements + paths.nelements) > 1))
1592             status = AKLOG_SOMETHINGSWRONG;
1593     }
1594
1595     /* If we are keeping track of zephyr subscriptions, print them. */
1596     if (zsubs) 
1597         for (cur_node = zsublist.first; cur_node; cur_node = cur_node->next) {
1598             sprintf(msgbuf, "zsub: %s\n", cur_node->data);
1599             params.pstdout(msgbuf);
1600         }
1601
1602     /* If we are keeping track of host information, print it. */
1603     if (hosts)
1604         for (cur_node = hostlist.first; cur_node; cur_node = cur_node->next) {
1605             sprintf(msgbuf, "host: %s\n", cur_node->data);
1606             params.pstdout(msgbuf);
1607         }
1608
1609     params.exitprog(status);
1610 }