auth: Force correct evenness on rxkad tokens
[openafs.git] / src / tsm41 / aix_aklog.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/com_err.h>
13
14
15 #if defined(AFS_AIX51_ENV)
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <stdio.h>
19 #include <locale.h>
20 #include <nl_types.h>
21 #include <pwd.h>
22 #include <netdb.h>
23 #include <sys/socket.h>
24 #include <sys/file.h>
25 #ifdef HAVE_SYS_PAG_H
26 #include <sys/pag.h>
27 #endif
28 #include <errno.h>
29 #include <usersec.h>
30 #include <syslog.h>
31
32 #include <krb5.h>
33
34 #include <afs/cellconfig.h>
35 #include <afs/dirpath.h>
36 #include <rx/rxkad.h>
37 #include <afs/auth.h>
38 #include <afs/ktc.h>
39 #include <afs/token.h>
40 #include <afs/ptserver.h>
41 #include "aix_auth_prototypes.h"
42
43 static int uidpag = 0;
44 static int localuid = 0;
45 struct afsconf_cell ak_cellconfig; /* General information about the cell */
46 static char linkedcell[MAXCELLCHARS+1];
47 static krb5_ccache  _krb425_ccache = NULL;
48
49 #define AFSKEY "afs"
50 #define AFSINST ""
51
52 #ifndef ANAME_SZ
53 #define ANAME_SZ 40
54 #endif /* ANAME_SZ */
55 #ifndef REALM_SZ
56 #define REALM_SZ 40
57 #endif /* REALM_SZ */
58 #ifndef SNAME_SZ
59 #define SNAME_SZ 40
60 #endif /* SNAME_SZ */
61 #ifndef INST_SZ
62 #define INST_SZ 40
63 #endif /* INST_SZ */
64
65 /*
66  * Why doesn't AFS provide these prototypes?
67  */
68
69 extern int pioctl(char *, afs_int32, struct ViceIoctl *, afs_int32);
70
71 /*
72  * Other prototypes
73  */
74
75 static krb5_error_code get_credv5(krb5_context context, char *, char *, char *,
76                                   char *, krb5_creds **);
77 static int get_user_realm(krb5_context, char *);
78
79 #if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
80
81 #define get_princ_str(c, p, n) krb5_princ_component(c, p, n)->data
82 #define get_princ_len(c, p, n) krb5_princ_component(c, p, n)->length
83 #define second_comp(c, p) (krb5_princ_size(c, p) > 1)
84 #define realm_data(c, p) krb5_princ_realm(c, p)->data
85 #define realm_len(c, p) krb5_princ_realm(c, p)->length
86
87 #elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
88
89 #define get_princ_str(c, p, n) krb5_principal_get_comp_string(c, p, n)
90 #define get_princ_len(c, p, n) strlen(krb5_principal_get_comp_string(c, p, n))
91 #define second_comp(c, p) (krb5_principal_get_comp_string(c, p, 1) != NULL)
92 #define realm_data(c, p) krb5_realm_data(krb5_principal_get_realm(c, p))
93 #define realm_len(c, p) krb5_realm_length(krb5_principal_get_realm(c, p))
94
95 #else
96 #error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
97 #endif
98
99 #if defined(HAVE_KRB5_CREDS_KEYBLOCK)
100
101 #define get_cred_keydata(c) c->keyblock.contents
102 #define get_cred_keylen(c) c->keyblock.length
103 #define get_creds_enctype(c) c->keyblock.enctype
104
105 #elif defined(HAVE_KRB5_CREDS_SESSION)
106
107 #define get_cred_keydata(c) c->session.keyvalue.data
108 #define get_cred_keylen(c) c->session.keyvalue.length
109 #define get_creds_enctype(c) c->session.keytype
110
111 #else
112 #error "Must have either keyblock or session member of krb5_creds"
113 #endif
114
115 char *
116 afs_realm_of_cell(krb5_context context, struct afsconf_cell *cellconfig, int fallback)
117 {
118     static char krbrlm[REALM_SZ+1];
119     char **hrealms = 0;
120     krb5_error_code retval;
121
122     if (!cellconfig)
123         return 0;
124
125     if (fallback) {
126         char * p;
127         p = strchr(cellconfig->hostName[0], '.');
128         if (p++)
129             strcpy(krbrlm, p);
130         else
131             strcpy(krbrlm, cellconfig->name);
132         for (p=krbrlm; *p; p++) {
133             if (islower(*p))
134                 *p = toupper(*p);
135         }
136     } else {
137         if (retval = krb5_get_host_realm(context,
138                                          cellconfig->hostName[0], &hrealms))
139             return 0;
140         if(!hrealms[0]) return 0;
141         strcpy(krbrlm, hrealms[0]);
142
143         if (hrealms) krb5_free_host_realm(context, hrealms);
144     }
145     return krbrlm;
146 }
147
148 int
149 aklog_authenticate(char *userName, char *response, int *reenter, char **message)
150 {
151     char *reason, *pword, prompt[256];
152     struct passwd *pwd;
153     int code, unixauthneeded, password_expires = -1;
154     int status;
155     krb5_context context;
156
157     syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: uidpag %s localuid %s",
158                                uidpag ? "yes" : "no",
159                                localuid ? "yes" : "no");
160
161     krb5_init_context(&context);
162     *reenter = 0;
163     *message = (char *)0;
164
165     status = auth_to_cell(context, userName, NULL, NULL);
166
167     if (status) {
168         char *str = afs_error_message(status);
169         *message = (char *)malloc(1024);
170 #ifdef HAVE_KRB5_SVC_GET_MSG
171         if (strncmp(str, "unknown", strlen("unknown")) == 0) {
172             krb5_svc_get_msg(status,&str);
173             sprintf(*message, "Unable to obtain AFS tokens: %s.\n",
174                     str);
175             krb5_free_string(context, str);
176         } else
177 #endif
178             sprintf(*message, "Unable to obtain AFS tokens: %s.\n",
179                     str);
180         return AUTH_FAILURE; /* NOTFOUND? */
181     }
182
183 #if 0
184     /*
185      * Local hack - if the person has a file in their home
186      * directory called ".xlog", read that for a list of
187      * extra cells to authenticate to
188      */
189
190     if ((pwd = getpwuid(getuid())) != NULL) {
191         struct stat sbuf;
192         FILE *f;
193         char fcell[100], xlog_path[512];
194
195         strcpy(xlog_path, pwd->pw_dir);
196         strcat(xlog_path, "/.xlog");
197
198         if ((stat(xlog_path, &sbuf) == 0) &&
199             ((f = fopen(xlog_path, "r")) != NULL)) {
200
201             while (fgets(fcell, 100, f) != NULL) {
202                 int auth_status;
203
204                 fcell[strlen(fcell) - 1] = '\0';
205
206                 auth_status = auth_to_cell(context, userName, fcell, NULL);
207                 if (status == AKLOG_SUCCESS)
208                     status = auth_status;
209                 else
210                     status = AKLOG_SOMETHINGSWRONG;
211             }
212         }
213     }
214 #endif
215     return AUTH_SUCCESS;
216 }
217
218 static krb5_error_code
219 get_credv5(krb5_context context, char *user,
220            char *name, char *inst, char *realm,
221            krb5_creds **creds)
222 {
223     krb5_creds increds;
224     krb5_error_code r;
225     static krb5_principal client_principal = 0;
226     char *str;
227
228     memset(&increds, 0, sizeof(increds));
229     /* instance may be ptr to a null string. Pass null then */
230     if ((r = krb5_build_principal(context, &increds.server,
231                                   strlen(realm), realm,
232                                   name,
233                                   (inst && strlen(inst)) ? inst : (void *) NULL,
234                                   (void *) NULL))) {
235         return r;
236     }
237     r = krb5_cc_default(context, &_krb425_ccache);
238     if (r) {
239         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: krb5_cc_default returns %d", r);
240         return r;
241     }
242     r = krb5_cc_get_principal(context, _krb425_ccache, &client_principal);
243     if (r) {
244         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: krb5_cc_get_principal returns %d", r);
245         return r;
246     }
247     increds.client = client_principal;
248     increds.times.endtime = 0;
249     /* Ask for DES since that is what V4 understands */
250     get_creds_enctype((&increds)) = ENCTYPE_DES_CBC_CRC;
251
252     r = krb5_get_credentials(context, 0, _krb425_ccache, &increds, creds);
253
254     return r;
255 }
256
257
258 static int
259 get_user_realm(krb5_context context, char *realm)
260 {
261     static krb5_principal client_principal = 0;
262     int i;
263
264     if (!_krb425_ccache)
265         krb5_cc_default(context, &_krb425_ccache);
266     if (!client_principal)
267         krb5_cc_get_principal(context, _krb425_ccache, &client_principal);
268
269     i = realm_len(context, client_principal);
270     if (i > REALM_SZ-1) i = REALM_SZ-1;
271     strncpy(realm,realm_data(context, client_principal), i);
272     realm[i] = 0;
273
274     return 0;
275 }
276
277 int
278 aklog_chpass(char *userName, char *oldPasswd, char *newPasswd, char **message)
279 {
280     return AUTH_SUCCESS;
281 }
282
283 int
284 aklog_passwdexpired(char *userName, char **message)
285 {
286     return AUTH_SUCCESS;
287 }
288
289 int
290 aklog_passwdrestrictions(char *userName, char *newPasswd, char *oldPasswd,
291                          char **message)
292 {
293     return AUTH_SUCCESS;
294 }
295
296 char *
297 aklog_getpasswd(char * userName)
298 {
299     errno = ENOSYS;
300     return NULL;
301 }
302
303 static void *
304 aklog_open(char *name, char *domain, int mode, char *options)
305 {
306     char *opt;
307
308     /* I can't find this documented anywhere, but it looks like the "options"
309      * string is NUL-delimited (so NULs replace commas in the configuration
310      * file), and the end of the list is marked by an extra NUL. */
311
312     for (opt = options; opt && *opt; opt += strlen(opt) + 1) {
313         if (strcasecmp(opt, "uidpag") == 0) {
314             uidpag = 1;
315         }
316         if (strcasecmp(opt, "localuid") == 0) {
317             localuid = 1;
318         }
319     }
320     return NULL;
321 }
322
323 static int
324 get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell, char *linkedcell)
325 {
326     int status = 0;
327     struct afsconf_dir *configdir;
328
329     memset(local_cell, 0, sizeof(local_cell));
330     memset(cellconfig, 0, sizeof(*cellconfig));
331
332     if (!(configdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
333         return AFSCONF_NODB;
334     }
335
336     if (afsconf_GetLocalCell(configdir, local_cell, MAXCELLCHARS)) {
337         return AFSCONF_FAILURE;
338     }
339
340     if ((cell == NULL) || (cell[0] == 0))
341         cell = local_cell;
342
343     linkedcell[0] = '\0';
344     if (afsconf_GetCellInfo(configdir, cell, NULL, cellconfig)) {
345         status = AFSCONF_NOTFOUND;
346     }
347     if (cellconfig->linkedCell)
348         strncpy(linkedcell,cellconfig->linkedCell,MAXCELLCHARS);
349
350     (void) afsconf_Close(configdir);
351
352     return(status);
353 }
354
355 /*
356  * Log to a cell.  If the cell has already been logged to, return without
357  * doing anything.  Otherwise, log to it and mark that it has been logged
358  * to.
359  */
360 static int
361 auth_to_cell(krb5_context context, char *user, char *cell, char *realm)
362 {
363     int status = 0;
364     char username[BUFSIZ];      /* To hold client username structure */
365     afs_int32 viceId;           /* AFS uid of user */
366
367     char name[ANAME_SZ];        /* Name of afs key */
368     char primary_instance[INST_SZ];     /* Instance of afs key */
369     char secondary_instance[INST_SZ];   /* Backup instance to try */
370     int try_secondary = 0;              /* Flag to indicate if we try second */
371     char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
372     char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
373     char local_cell[MAXCELLCHARS+1];
374     char cell_to_use[MAXCELLCHARS+1]; /* Cell to authenticate to */
375     static char confname[512] = { 0 };
376     krb5_creds *v5cred = NULL;
377     struct ktc_principal aserver;
378     int afssetpag = 0, uid = -1;
379     struct passwd *pwd = NULL;
380     struct ktc_setTokenData *token = NULL;
381     struct ktc_tokenUnion *rxkadToken = NULL;
382
383     memset(name, 0, sizeof(name));
384     memset(primary_instance, 0, sizeof(primary_instance));
385     memset(secondary_instance, 0, sizeof(secondary_instance));
386     memset(realm_of_user, 0, sizeof(realm_of_user));
387     memset(realm_of_cell, 0, sizeof(realm_of_cell));
388     syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog starting: user %s uid %d", user, getuid());
389     if (confname[0] == '\0') {
390         strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
391         confname[sizeof(confname) - 2] = '\0';
392     }
393
394     /* NULL or empty cell returns information on local cell */
395     if ((status = get_cellconfig(cell, &ak_cellconfig,
396                                  local_cell, linkedcell))) {
397         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_cellconfig returns %d", status);
398         return(status);
399     }
400
401     strncpy(cell_to_use, ak_cellconfig.name, MAXCELLCHARS);
402     cell_to_use[MAXCELLCHARS] = 0;
403
404     /*
405      * Find out which realm we're supposed to authenticate to.  If one
406      * is not included, use the kerberos realm found in the credentials
407      * cache.
408      */
409
410     if (realm && realm[0]) {
411         strcpy(realm_of_cell, realm);
412     }
413     else {
414         char *afs_realm = afs_realm_of_cell(context, &ak_cellconfig, FALSE);
415
416         if (!afs_realm) {
417             syslog(LOG_AUTH|LOG_ERR, "LAM aklog: afs_realm_of_cell returns %d", status);
418             return AFSCONF_FAILURE;
419         }
420
421         strcpy(realm_of_cell, afs_realm);
422     }
423
424     /* We use the afs.<cellname> convention here...
425      *
426      * Doug Engert's original code had principals of the form:
427      *
428      * "afsx/cell@realm"
429      *
430      * in the KDC, so the name wouldn't conflict with DFS.  Since we're
431      * not using DFS, I changed it just to look for the following
432      * principals:
433      *
434      * afs/<cell>@<realm>
435      * afs@<realm>
436      *
437      * Because people are transitioning from afs@realm to afs/cell,
438      * we configure things so that if the first one isn't found, we
439      * try the second one.  You can select which one you prefer with
440      * a configure option.
441      */
442
443     strcpy(name, AFSKEY);
444
445     if (1 || strcasecmp(cell_to_use, realm_of_cell) != 0) {
446         strncpy(primary_instance, cell_to_use, sizeof(primary_instance));
447         primary_instance[sizeof(primary_instance)-1] = '\0';
448         if (strcasecmp(cell_to_use, realm_of_cell) == 0) {
449             try_secondary = 1;
450             secondary_instance[0] = '\0';
451         }
452     } else {
453         primary_instance[0] = '\0';
454         try_secondary = 1;
455         strncpy(secondary_instance, cell_to_use,
456                 sizeof(secondary_instance));
457         secondary_instance[sizeof(secondary_instance)-1] = '\0';
458     }
459
460     token = token_buildTokenJar(ak_cellconfig.name);
461     if (!token) {
462         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: token_buildTokenJar returns NULL");
463         return ENOMEM;
464     }
465
466     /*
467      * Extract the session key from the ticket file and hand-frob an
468      * afs style authenticator.
469      */
470
471     /*
472      * Try to obtain AFS tickets.  Because there are two valid service
473      * names, we will try both, but trying the more specific first.
474      *
475      *  afs/<cell>@<realm> i.e. allow for single name with "."
476      *  afs@<realm>
477      */
478
479     status = get_credv5(context, user, name, primary_instance, realm_of_cell,
480                         &v5cred);
481
482     if ((status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
483          status == KRB5KRB_ERR_GENERIC) && !realm_of_cell[0]) {
484         char *afs_realm = afs_realm_of_cell(context, &ak_cellconfig, TRUE);
485
486         if (!afs_realm) {
487             syslog(LOG_AUTH|LOG_ERR, "LAM aklog: afs_realm_of_cell returns %d", status);
488             status = AFSCONF_FAILURE;
489             goto done;
490         }
491
492         strcpy(realm_of_cell, afs_realm);
493
494         if (strcasecmp(cell_to_use, realm_of_cell) == 0) {
495             try_secondary = 1;
496             secondary_instance[0] = '\0';
497         }
498
499         status = get_credv5(context, user, name, primary_instance,
500                             realm_of_cell, &v5cred);
501     }
502     if (status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
503         status == KRB5KRB_ERR_GENERIC) {
504         if (try_secondary)
505             status = get_credv5(context, user, name, secondary_instance,
506                                 realm_of_cell, &v5cred);
507     }
508
509     if (status) {
510         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_credv5 returns %d", status);
511         goto done;
512     }
513
514     strncpy(aserver.name, AFSKEY, MAXKTCNAMELEN - 1);
515     strncpy(aserver.instance, AFSINST, MAXKTCNAMELEN - 1);
516     strncpy(aserver.cell, cell_to_use, MAXKTCREALMLEN - 1);
517
518     /*
519      * The default is to use rxkad2b, which means we put in a full
520      * V5 ticket.  If the user specifies -524, we talk to the
521      * 524 ticket converter.
522      */
523
524     {
525         char *p;
526         int len;
527         struct ktc_token atoken;
528
529         len = min(get_princ_len(context, v5cred->client, 0),
530                   second_comp(context, v5cred->client) ?
531                   MAXKTCNAMELEN - 2 : MAXKTCNAMELEN - 1);
532         strncpy(username, get_princ_str(context, v5cred->client, 0), len);
533         username[len] = '\0';
534
535         if (second_comp(context, v5cred->client)) {
536             strcat(username, ".");
537             p = username + strlen(username);
538             len = min(get_princ_len(context, v5cred->client, 1),
539                       MAXKTCNAMELEN - strlen(username) - 1);
540             strncpy(p, get_princ_str(context, v5cred->client, 1), len);
541             p[len] = '\0';
542         }
543
544         memset(&atoken, 0, sizeof(atoken));
545         atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
546         atoken.startTime = v5cred->times.starttime;;
547         atoken.endTime = v5cred->times.endtime;
548         memcpy(&atoken.sessionKey, get_cred_keydata(v5cred),
549                get_cred_keylen(v5cred));
550         atoken.ticketLen = v5cred->ticket.length;
551         memcpy(atoken.ticket, v5cred->ticket.data, atoken.ticketLen);
552
553         status = token_importRxkadViceId(&rxkadToken, &atoken, 0);
554         if (status) {
555             syslog(LOG_AUTH|LOG_ERR, "LAM aklog: importRxkad failed with %d", status);
556             goto done;
557         }
558     }
559
560     status = token_addToken(token, rxkadToken);
561     if (status) {
562         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: addToken failed with %d", status);
563         goto done;
564     }
565
566     if ((status = get_user_realm(context, realm_of_user))) {
567         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_user_realm returns %d", status);
568         status = KRB5_REALM_UNKNOWN;
569         goto done;
570     }
571     if (strcmp(realm_of_user, realm_of_cell)) {
572         strcat(username, "@");
573         strcat(username, realm_of_user);
574     }
575
576     uid = getuid();
577     if (uid == 0) {
578         pwd = getpwnam(user);
579         if (!pwd) {
580             syslog(LOG_AUTH|LOG_ERR, "LAM aklog: getpwnam %s failed", user);
581             status = AUTH_FAILURE;
582             goto done;
583         }
584     }
585
586     viceId = ANONYMOUSID;
587
588     if (!localuid) {
589         /* This actually crashes long-running daemons */
590         if (!pr_Initialize (0, confname, aserver.cell))
591             status = pr_SNameToId (username, &viceId);
592         if (status)
593             viceId = ANONYMOUSID;
594     } else {
595         /*
596          * This actually only works assuming that your uid and pts space match
597          * and probably this works only for the local cell anyway.
598          */
599
600         if (uid == 0) {
601             viceId = pwd->pw_uid;
602         } else {
603             viceId = uid;
604         }
605     }
606
607     /* Don't do first-time registration. Handle only the simple case */
608     if ((status == 0) && (viceId != ANONYMOUSID)) {
609         status = token_setRxkadViceId(rxkadToken, viceId);
610         if (status) {
611             syslog(LOG_AUTH|LOG_ERR, "LAM aklog: Error %d setting rxkad ViceId", status);
612             status = 0;
613         } else {
614             token_replaceToken(token, &rxkadToken);
615             syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: setting tokens for ViceId %d\n",
616                    (int)viceId);
617         }
618     }
619
620 #ifndef AFS_AIX51_ENV
621     /* on AIX 4.1.4 with AFS 3.4a+ if a write is not done before
622      * this routine, it will not add the token. It is not clear what
623      * is going on here! So we will do the following operation.
624      * On AIX 5 this kills our parent. So we won't.
625      */
626     write(2,"",0); /* dummy write */
627 #endif
628
629     /* If uidpag is set, we want to use UID-based PAGs, and not real PAGs, so
630      * don't create a new PAG if we're not in a PAG. But if uidpag is _not_
631      * set, just always create a new PAG. */
632     if (uidpag) {
633         afssetpag = (getpagvalue("afs") > 0) ? 1 : 0;
634         if (afssetpag) {
635             /* we can't set a UID PAG if we're already in a real PAG. Whine */
636             syslog(LOG_AUTH|LOG_ERR, "LAM aklog: uidpag is set, but we are "
637                                      "already in a PAG; this cannot work! "
638                                      "Attempting to continue by creating a "
639                                      "a new PAG");
640         }
641     } else {
642         afssetpag = 1;
643     }
644     token_setPag(token, afssetpag);
645
646     if (uid == 0 && uidpag) {
647         /* We are root, and we want to use UID-based PAGs. So, fork a child
648          * and setuid before setting tokens, so we set the tokens for the
649          * target user. */
650         struct sigaction newAction, origAction;
651         pid_t cid, pcid;
652         int wstatus;
653
654         sigemptyset(&newAction.sa_mask);
655         newAction.sa_handler = SIG_DFL;
656         newAction.sa_flags = 0;
657         status = sigaction(SIGCHLD, &newAction, &origAction);
658         if (status) {
659             syslog(LOG_AUTH|LOG_ERR, "LAM aklog: sigaction returned %d", status);
660             status = AUTH_FAILURE;
661             goto done;
662         }
663         syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: in daemon? forking to set tokens");
664         cid = fork();
665         if (cid <= 0) {
666             syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog child: setting tokens");
667             setuid(pwd->pw_uid);
668             status = ktc_SetTokenEx(token);
669             if (status != 0)
670                 syslog(LOG_AUTH|LOG_ERR, "LAM aklog child: set tokens, returning %d", status);
671             exit((status == 0)?0:255);
672         } else {
673             do {
674                 pcid = waitpid(cid, &wstatus, 0);
675             } while ((pcid == -1) && (errno == EINTR));
676             if ((pcid == cid) && WIFEXITED(wstatus))
677                 status = WEXITSTATUS(wstatus);
678             else
679                 status = -1;
680         }
681         syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: collected child status %d", status);
682         sigaction(SIGCHLD, &origAction, NULL);
683     } else {
684         status = ktc_SetTokenEx(token);
685     }
686     if (status != 0)
687         syslog(LOG_AUTH|LOG_ERR, "LAM aklog: set tokens returned %d", status);
688     else
689         syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: set tokens, pag %d", getpagvalue("afs"));
690
691  done:
692     if (rxkadToken) {
693         token_freeToken(&rxkadToken);
694     }
695     token_FreeSet(&token);
696     return(status);
697 }
698
699 int
700 aklog_initialize(struct secmethod_table *meths)
701 {
702     memset(meths, 0, sizeof(struct secmethod_table));
703     syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog loaded: uid %d pag %d", getuid(), getpagvalue("afs"));
704     /*
705      * Initialize the exported interface routines.
706      * Aside from method_authenticate and method_open, these are just no-ops.
707      */
708     meths->method_chpass = aklog_chpass;
709     meths->method_authenticate = aklog_authenticate;
710     meths->method_passwdexpired = aklog_passwdexpired;
711     meths->method_passwdrestrictions = aklog_passwdrestrictions;
712     meths->method_getpasswd = aklog_getpasswd;
713     meths->method_open = aklog_open;
714
715     return (0);
716 }
717 #endif /* AFS_AIX51_ENV */