2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #if defined(AFS_AIX51_ENV)
17 #include <sys/types.h>
18 #include <sys/param.h>
24 #include <sys/socket.h>
33 #include <afs/cellconfig.h>
34 #include <afs/dirpath.h>
37 #include <afs/ptserver.h>
38 #include "aix_auth_prototypes.h"
40 struct afsconf_cell ak_cellconfig; /* General information about the cell */
41 static char linkedcell[MAXCELLCHARS+1];
42 static krb5_ccache _krb425_ccache = NULL;
61 * Why doesn't AFS provide these prototypes?
64 extern int pioctl(char *, afs_int32, struct ViceIoctl *, afs_int32);
70 static krb5_error_code get_credv5(krb5_context context, char *, char *, char *,
71 char *, krb5_creds **);
72 static int get_user_realm(krb5_context, char *);
74 #if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
76 #define get_princ_str(c, p, n) krb5_princ_component(c, p, n)->data
77 #define get_princ_len(c, p, n) krb5_princ_component(c, p, n)->length
78 #define second_comp(c, p) (krb5_princ_size(c, p) > 1)
79 #define realm_data(c, p) krb5_princ_realm(c, p)->data
80 #define realm_len(c, p) krb5_princ_realm(c, p)->length
82 #elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
84 #define get_princ_str(c, p, n) krb5_principal_get_comp_string(c, p, n)
85 #define get_princ_len(c, p, n) strlen(krb5_principal_get_comp_string(c, p, n))
86 #define second_comp(c, p) (krb5_principal_get_comp_string(c, p, 1) != NULL)
87 #define realm_data(c, p) krb5_realm_data(krb5_principal_get_realm(c, p))
88 #define realm_len(c, p) krb5_realm_length(krb5_principal_get_realm(c, p))
91 #error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
94 #if defined(HAVE_KRB5_CREDS_KEYBLOCK)
96 #define get_cred_keydata(c) c->keyblock.contents
97 #define get_cred_keylen(c) c->keyblock.length
98 #define get_creds_enctype(c) c->keyblock.enctype
100 #elif defined(HAVE_KRB5_CREDS_SESSION)
102 #define get_cred_keydata(c) c->session.keyvalue.data
103 #define get_cred_keylen(c) c->session.keyvalue.length
104 #define get_creds_enctype(c) c->session.keytype
107 #error "Must have either keyblock or session member of krb5_creds"
110 char *afs_realm_of_cell(krb5_context context, struct afsconf_cell *cellconfig, int fallback)
112 static char krbrlm[REALM_SZ+1];
114 krb5_error_code retval;
121 p = strchr(cellconfig->hostName[0], '.');
125 strcpy(krbrlm, cellconfig->name);
126 for (p=krbrlm; *p; p++) {
131 if (retval = krb5_get_host_realm(context,
132 cellconfig->hostName[0], &hrealms))
134 if(!hrealms[0]) return 0;
135 strcpy(krbrlm, hrealms[0]);
137 if (hrealms) krb5_free_host_realm(context, hrealms);
143 aklog_authenticate(char *userName, char *response, int *reenter, char **message)
145 char *reason, *pword, prompt[256];
147 int code, unixauthneeded, password_expires = -1;
149 krb5_context context;
151 krb5_init_context(&context);
153 *message = (char *)0;
155 status = auth_to_cell(context, userName, NULL, NULL);
158 *message = (char *)malloc(1024);
159 sprintf(*message, "Unable to obtain AFS tokens: %s.\n",
160 afs_error_message(status));
161 return AUTH_FAILURE; /* NOTFOUND? */
166 * Local hack - if the person has a file in their home
167 * directory called ".xlog", read that for a list of
168 * extra cells to authenticate to
171 if ((pwd = getpwuid(getuid())) != NULL) {
174 char fcell[100], xlog_path[512];
176 strcpy(xlog_path, pwd->pw_dir);
177 strcat(xlog_path, "/.xlog");
179 if ((stat(xlog_path, &sbuf) == 0) &&
180 ((f = fopen(xlog_path, "r")) != NULL)) {
182 while (fgets(fcell, 100, f) != NULL) {
185 fcell[strlen(fcell) - 1] = '\0';
187 auth_status = auth_to_cell(context, userName, fcell, NULL);
188 if (status == AKLOG_SUCCESS)
189 status = auth_status;
191 status = AKLOG_SOMETHINGSWRONG;
199 static krb5_error_code get_credv5(krb5_context context, char *user,
200 char *name, char *inst, char *realm,
205 static krb5_principal client_principal = 0;
208 memset((char *)&increds, 0, sizeof(increds));
209 /* instance may be ptr to a null string. Pass null then */
210 if ((r = krb5_build_principal(context, &increds.server,
211 strlen(realm), realm,
213 (inst && strlen(inst)) ? inst : (void *) NULL,
217 r = krb5_cc_default(context, &_krb425_ccache);
219 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: krb5_cc_default returns %d", r);
222 r = krb5_cc_get_principal(context, _krb425_ccache, &client_principal);
224 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: krb5_cc_get_principal returns %d", r);
227 increds.client = client_principal;
228 increds.times.endtime = 0;
229 /* Ask for DES since that is what V4 understands */
230 get_creds_enctype((&increds)) = ENCTYPE_DES_CBC_CRC;
232 r = krb5_get_credentials(context, 0, _krb425_ccache, &increds, creds);
238 static int get_user_realm(krb5_context context, char *realm)
240 static krb5_principal client_principal = 0;
244 krb5_cc_default(context, &_krb425_ccache);
245 if (!client_principal)
246 krb5_cc_get_principal(context, _krb425_ccache, &client_principal);
248 i = realm_len(context, client_principal);
249 if (i > REALM_SZ-1) i = REALM_SZ-1;
250 strncpy(realm,realm_data(context, client_principal), i);
257 aklog_chpass(char *userName, char *oldPasswd, char *newPasswd, char **message)
263 aklog_passwdexpired(char *userName, char **message)
269 aklog_passwdrestrictions(char *userName, char *newPasswd, char *oldPasswd,
276 aklog_getpasswd(char * userName)
283 static int get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell, char *linkedcell)
286 struct afsconf_dir *configdir;
288 memset(local_cell, 0, sizeof(local_cell));
289 memset((char *)cellconfig, 0, sizeof(*cellconfig));
291 if (!(configdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
295 if (afsconf_GetLocalCell(configdir, local_cell, MAXCELLCHARS)) {
296 return AFSCONF_FAILURE;
299 if ((cell == NULL) || (cell[0] == 0))
302 linkedcell[0] = '\0';
303 if (afsconf_GetCellInfo(configdir, cell, NULL, cellconfig)) {
304 status = AFSCONF_NOTFOUND;
306 if (cellconfig->linkedCell)
307 strncpy(linkedcell,cellconfig->linkedCell,MAXCELLCHARS);
309 (void) afsconf_Close(configdir);
315 * Log to a cell. If the cell has already been logged to, return without
316 * doing anything. Otherwise, log to it and mark that it has been logged
319 static int auth_to_cell(krb5_context context, char *user, char *cell, char *realm)
322 char username[BUFSIZ]; /* To hold client username structure */
323 afs_int32 viceId; /* AFS uid of user */
325 char name[ANAME_SZ]; /* Name of afs key */
326 char primary_instance[INST_SZ]; /* Instance of afs key */
327 char secondary_instance[INST_SZ]; /* Backup instance to try */
328 int try_secondary = 0; /* Flag to indicate if we try second */
329 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
330 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
331 char local_cell[MAXCELLCHARS+1];
332 char cell_to_use[MAXCELLCHARS+1]; /* Cell to authenticate to */
333 static char lastcell[MAXCELLCHARS+1] = { 0 };
334 static char confname[512] = { 0 };
335 krb5_creds *v5cred = NULL;
336 struct ktc_principal aserver;
337 struct ktc_principal aclient;
338 struct ktc_token atoken, btoken;
339 int afssetpag = 0, uid = -1;
342 memset(name, 0, sizeof(name));
343 memset(primary_instance, 0, sizeof(primary_instance));
344 memset(secondary_instance, 0, sizeof(secondary_instance));
345 memset(realm_of_user, 0, sizeof(realm_of_user));
346 memset(realm_of_cell, 0, sizeof(realm_of_cell));
347 syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog starting: user %s uid %d", user, getuid());
348 if (confname[0] == '\0') {
349 strncpy(confname, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confname));
350 confname[sizeof(confname) - 2] = '\0';
353 /* NULL or empty cell returns information on local cell */
354 if ((status = get_cellconfig(cell, &ak_cellconfig,
355 local_cell, linkedcell))) {
356 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_cellconfig returns %d", status);
360 strncpy(cell_to_use, ak_cellconfig.name, MAXCELLCHARS);
361 cell_to_use[MAXCELLCHARS] = 0;
364 * Find out which realm we're supposed to authenticate to. If one
365 * is not included, use the kerberos realm found in the credentials
369 if (realm && realm[0]) {
370 strcpy(realm_of_cell, realm);
373 char *afs_realm = afs_realm_of_cell(context, &ak_cellconfig, FALSE);
376 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: afs_realm_of_cell returns %d", status);
377 return AFSCONF_FAILURE;
380 strcpy(realm_of_cell, afs_realm);
383 /* We use the afs.<cellname> convention here...
385 * Doug Engert's original code had principals of the form:
389 * in the KDC, so the name wouldn't conflict with DFS. Since we're
390 * not using DFS, I changed it just to look for the following
396 * Because people are transitioning from afs@realm to afs/cell,
397 * we configure things so that if the first one isn't found, we
398 * try the second one. You can select which one you prefer with
399 * a configure option.
402 strcpy(name, AFSKEY);
404 if (1 || strcasecmp(cell_to_use, realm_of_cell) != 0) {
405 strncpy(primary_instance, cell_to_use, sizeof(primary_instance));
406 primary_instance[sizeof(primary_instance)-1] = '\0';
407 if (strcasecmp(cell_to_use, realm_of_cell) == 0) {
409 secondary_instance[0] = '\0';
412 primary_instance[0] = '\0';
414 strncpy(secondary_instance, cell_to_use,
415 sizeof(secondary_instance));
416 secondary_instance[sizeof(secondary_instance)-1] = '\0';
420 * Extract the session key from the ticket file and hand-frob an
421 * afs style authenticator.
425 * Try to obtain AFS tickets. Because there are two valid service
426 * names, we will try both, but trying the more specific first.
428 * afs/<cell>@<realm> i.e. allow for single name with "."
432 status = get_credv5(context, user, name, primary_instance, realm_of_cell,
435 if ((status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
436 status == KRB5KRB_ERR_GENERIC) && !realm_of_cell[0]) {
437 char *afs_realm = afs_realm_of_cell(context, &ak_cellconfig, TRUE);
440 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: afs_realm_of_cell returns %d", status);
441 return AFSCONF_FAILURE;
444 strcpy(realm_of_cell, afs_realm);
446 if (strcasecmp(cell_to_use, realm_of_cell) == 0) {
448 secondary_instance[0] = '\0';
451 status = get_credv5(context, user, name, primary_instance,
452 realm_of_cell, &v5cred);
454 if (status == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
455 status == KRB5KRB_ERR_GENERIC) {
457 status = get_credv5(context, user, name, secondary_instance,
458 realm_of_cell, &v5cred);
462 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_credv5 returns %d", status);
466 strncpy(aserver.name, AFSKEY, MAXKTCNAMELEN - 1);
467 strncpy(aserver.instance, AFSINST, MAXKTCNAMELEN - 1);
468 strncpy(aserver.cell, cell_to_use, MAXKTCREALMLEN - 1);
471 * The default is to use rxkad2b, which means we put in a full
472 * V5 ticket. If the user specifies -524, we talk to the
473 * 524 ticket converter.
480 len = min(get_princ_len(context, v5cred->client, 0),
481 second_comp(context, v5cred->client) ?
482 MAXKTCNAMELEN - 2 : MAXKTCNAMELEN - 1);
483 strncpy(username, get_princ_str(context, v5cred->client, 0), len);
484 username[len] = '\0';
486 if (second_comp(context, v5cred->client)) {
487 strcat(username, ".");
488 p = username + strlen(username);
489 len = min(get_princ_len(context, v5cred->client, 1),
490 MAXKTCNAMELEN - strlen(username) - 1);
491 strncpy(p, get_princ_str(context, v5cred->client, 1), len);
495 memset(&atoken, 0, sizeof(atoken));
496 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
497 atoken.startTime = v5cred->times.starttime;;
498 atoken.endTime = v5cred->times.endtime;
499 memcpy(&atoken.sessionKey, get_cred_keydata(v5cred),
500 get_cred_keylen(v5cred));
501 atoken.ticketLen = v5cred->ticket.length;
502 memcpy(atoken.ticket, v5cred->ticket.data, atoken.ticketLen);
505 if ((status = get_user_realm(context, realm_of_user))) {
506 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: get_user_realm returns %d", status);
507 return KRB5_REALM_UNKNOWN;
509 if (strcmp(realm_of_user, realm_of_cell)) {
510 strcat(username, "@");
511 strcat(username, realm_of_user);
514 strcpy(lastcell, aserver.cell);
517 * This is a crock, but it is Transarc's crock, so
518 * we have to play along in order to get the
519 * functionality. The way the afs id is stored is
520 * as a string in the username field of the token.
521 * Contrary to what you may think by looking at
522 * the code for tokens, this hack (AFS ID %d) will
523 * not work if you change %d to something else.
527 /* This actually crashes long-running daemons */
528 if (!pr_Initialize (0, confname, aserver.cell))
529 status = pr_SNameToId (username, &viceId);
530 if ((status == 0) && (viceId != ANONYMOUSID))
531 sprintf (username, "AFS ID %d", (int) viceId);
534 * This actually only works assuming that your uid and pts space match
535 * and probably this works only for the local cell anyway.
538 if ((uid = getuid()) == 0) {
539 if ((pwd = getpwnam(user)) == NULL) {
540 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: getpwnam %s failed", user);
545 /* Don't do first-time registration. Handle only the simple case */
546 if ((status == 0) && (viceId != ANONYMOUSID))
547 sprintf (username, "AFS ID %d", ((uid==0)?(int)pwd->pw_uid:(int)uid));
550 /* Reset the "aclient" structure before we call ktc_SetToken.
551 * This structure was first set by the ktc_GetToken call when
552 * we were comparing whether identical tokens already existed.
554 strncpy(aclient.name, username, MAXKTCNAMELEN - 1);
555 strcpy(aclient.instance, "");
556 strncpy(aclient.cell, realm_of_user, MAXKTCREALMLEN - 1);
558 #ifndef AFS_AIX51_ENV
559 /* on AIX 4.1.4 with AFS 3.4a+ if a write is not done before
560 * this routine, it will not add the token. It is not clear what
561 * is going on here! So we will do the following operation.
562 * On AIX 5 this kills our parent. So we won't.
564 write(2,"",0); /* dummy write */
566 afssetpag = (getpagvalue("afs") > 0) ? 1 : 0;
568 struct sigaction newAction, origAction;
572 sigemptyset(&newAction.sa_mask);
573 newAction.sa_handler = SIG_DFL;
574 newAction.sa_flags = 0;
575 status = sigaction(SIGCHLD, &newAction, &origAction);
577 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: sigaction returned %d", status);
580 syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: in daemon? forking to set tokens");
583 syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog child: setting tokens");
585 status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag);
587 syslog(LOG_AUTH|LOG_ERR, "LAM aklog child: set tokens, returning %d", status);
588 exit((status == 0)?0:255);
591 pcid = waitpid(cid, &wstatus, 0);
592 } while ((pcid == -1) && (errno == EINTR));
593 if ((pcid == cid) && WIFEXITED(wstatus))
594 status = WEXITSTATUS(wstatus);
598 syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: collected child status %d", status);
599 sigaction(SIGCHLD, &origAction, NULL);
601 status = ktc_SetToken(&aserver, &atoken, &aclient, afssetpag);
604 syslog(LOG_AUTH|LOG_ERR, "LAM aklog: set tokens returned %d", status);
606 syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog: set tokens, pag %d", getpagvalue("afs"));
611 aklog_initialize(struct secmethod_table *meths)
613 memset(meths, 0, sizeof(struct secmethod_table));
614 syslog(LOG_AUTH|LOG_DEBUG, "LAM aklog loaded: uid %d pag %d", getuid(), getpagvalue("afs"));
616 * Initialize the exported interface routines.
617 * Aside from method_authenticate, these are just no-ops.
619 meths->method_chpass = aklog_chpass;
620 meths->method_authenticate = aklog_authenticate;
621 meths->method_passwdexpired = aklog_passwdexpired;
622 meths->method_passwdrestrictions = aklog_passwdrestrictions;
623 meths->method_getpasswd = aklog_getpasswd;
627 #endif /* AFS_AIX51_ENV */