2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * Implementation of basic procedures for the AFS user account
16 * --------------------- Required definitions ---------------------
18 #include <afsconfig.h>
19 #include <afs/param.h>
24 #include "uss_kauth.h" /*Module interface */
25 #include "uss_common.h" /*Common defs & operations */
37 #include <afs/com_err.h>
38 #include <afs/kautils.h> /*MAXKTCREALMLEN*/
39 #include <afs/kaport.h> /* pack_long */
40 #define uss_kauth_MAX_SIZE 2048
43 * ---------------------- Exported variables ----------------------
45 struct ubik_client *uconn_kauthP; /*Ubik connections
49 * ------------------------ Private globals -----------------------
51 static int initDone = 0; /*Module initialized? */
52 static char CreatorInstance[MAXKTCNAMELEN]; /*Instance string */
53 static char UserPrincipal[MAXKTCNAMELEN]; /*Parsed user principal */
54 static char UserInstance[MAXKTCNAMELEN]; /*Parsed user instance */
55 static char UserCell[MAXKTCREALMLEN]; /*Parsed user cell */
58 /*-----------------------------------------------------------------------
59 * EXPORTED uss_kauth_InitAccountCreator
62 * The command line must have been parsed.
66 *-----------------------------------------------------------------------*/
69 uss_kauth_InitAccountCreator()
70 { /*uss_kauth_InitAccountCreator */
77 * Set up the identity of the principal performing the account
78 * creation (uss_AccountCreator). It's either the administrator
79 * name provided at the call or the identity of the caller as
80 * gleaned from the password info.
82 if (uss_Administrator[0] != '\0') {
83 name = uss_Administrator;
84 } else { /* Administrator name not passed in */
85 pw = getpwuid(getuid());
88 "%s: Can't figure out your name from your user id.\n",
95 /* Break the *name into principal and instance */
96 dotPosition = strcspn(name, ".");
97 if (dotPosition >= MAXKTCNAMELEN) {
98 fprintf(stderr, "Admin principal name too long.\n");
101 strncpy(uss_AccountCreator, name, dotPosition);
102 uss_AccountCreator[dotPosition] = '\0';
105 if (name[0] == '.') {
107 if (strlen(name) >= MAXKTCNAMELEN) {
108 fprintf(stderr, "Admin instance name too long.\n");
111 strcpy(CreatorInstance, name);
113 CreatorInstance[0] = '\0';
116 #ifdef USS_KAUTH_DB_INSTANCE
117 fprintf(stderr, "%s: Starting CreatorInstance is '%s', %d bytes\n",
118 uss_whoami, CreatorInstance, strlen(CreatorInstance));
119 #endif /* USS_KAUTH_DB_INSTANCE */
124 /*-----------------------------------------------------------------------
125 * static InitThisModule
128 * Set up this module, namely set up all the client state for
129 * dealing with the Volume Location Server(s), including
130 * network connections.
133 * a_noAuthFlag : Do we need authentication?
134 * a_confDir : Configuration directory to use.
135 * a_cellName : Cell we want to talk to.
138 * 0 if everything went fine, or
139 * lower-level error code otherwise.
142 * This routine will only be called once.
146 *------------------------------------------------------------------------*/
152 static char gpbuf[BUFSIZ];
153 /* read a password from stdin, stop on \n or eof */
155 memset(gpbuf, 0, sizeof(gpbuf));
156 for (i = 0; i < (sizeof(gpbuf) - 1); i++) {
158 if (tc == '\n' || tc == EOF)
168 { /*InitThisModule */
170 static char rn[] = "uss_kauth:InitThisModule";
171 register afs_int32 code;
172 char *name, prompt[2 * MAXKTCNAMELEN + 20];
173 char *reasonString, longPassBuff[1024], shortPassBuff[9];
174 struct ktc_encryptionKey key;
175 struct ktc_token token, tok;
176 struct ktc_principal Name;
179 * Only call this routine once.
186 * Pull out the caller's administrator token if they have one.
189 ka_GetAdminToken(0, 0, uss_Cell, 0, 10 * 60 * 60, &token,
193 strncpy(longPassBuff, getpipepass(), sizeof(longPassBuff));
196 * Nope, no admin tokens available. Get the key based on the
197 * full password and try again.
199 sprintf(prompt, "Password for '%s", uss_AccountCreator);
200 if (CreatorInstance[0])
201 sprintf(prompt + strlen(prompt), ".%s", CreatorInstance);
202 strcat(prompt, "': ");
203 code = ka_UserReadPassword(prompt, /*Prompt to use */
204 longPassBuff, /*Long pwd buffer */
205 sizeof(longPassBuff), /*Size of above */
208 afs_com_err(uss_whoami, code, "while getting password ");
210 printf("%s: Error code from ka_UserReadPassword(): %d\n", rn,
212 #endif /* USS_KAUTH_DB */
216 ka_StringToKey(longPassBuff, uss_Cell, &key);
218 ka_GetAdminToken(uss_AccountCreator, CreatorInstance, uss_Cell,
219 &key, 24 * 60 * 60, &token, 0 /*new */ );
221 if ((code == KABADREQUEST) && (strlen(longPassBuff) > 8)) {
223 * The key we provided just doesn't work, yet we
224 * suspect that since the password is greater than 8
225 * chars, it might be the case that we really need
226 * to truncate the password to generate the appropriate
229 afs_com_err(uss_whoami, code,
230 "while getting administrator token (trying shortened password next...)");
232 printf("%s: Error code from ka_GetAdminToken: %d\n", rn,
234 #endif /* USS_KAUTH_DB */
235 strncpy(shortPassBuff, longPassBuff, 8);
236 shortPassBuff[8] = 0;
237 ka_StringToKey(shortPassBuff, uss_Cell, &key);
239 ka_GetAdminToken(uss_AccountCreator, CreatorInstance,
240 uss_Cell, &key, 24 * 60 * 60, &token,
243 afs_com_err(uss_whoami, code,
244 "while getting administrator token (possibly wrong password, or not an administrative account)");
246 printf("%s: Error code from ka_GetAdminToken: %d\n", rn,
248 #endif /* USS_KAUTH_DB */
252 * The silly administrator has a long password! Tell
253 * him or her off in a polite way.
256 ("%s: Shortened password accepted by the Authentication Server\n",
259 } /*Try a shorter password */
262 * We failed to get an admin token, but the password is
263 * of a reasonable length, so we're just hosed.
265 afs_com_err(uss_whoami, code,
266 "while getting administrator token (possibly wrong password, or not an administrative account)");
268 printf("%s: Error code from ka_GetAdminToken: %d\n", rn,
270 #endif /* USS_KAUTH_DB */
272 } /*Even the shorter password didn't work */
273 } /*Key from given password didn't work */
276 /*First attempt to get admin token failed */
278 * At this point, we have acquired an administrator token. Let's
279 * proceed to set up a connection to the AuthServer.
281 #ifdef USS_KAUTH_DB_INSTANCE
283 "%s: CreatorInstance after ka_GetAdminToken(): '%s', %d bytes\n",
284 rn, CreatorInstance, strlen(CreatorInstance));
285 #endif /* USS_KAUTH_DB_INSTANCE */
288 * Set up the connection to the AuthServer read/write site.
291 ka_AuthServerConn(uss_Cell, KA_MAINTENANCE_SERVICE, &token,
294 afs_com_err(uss_whoami, code,
295 "while establishing Authentication Server connection");
297 printf("%s: Error code from ka_AuthServerConn: %d\n", rn, code);
298 #endif /* USS_KAUTH_DB */
302 if (uss_Administrator[0]) {
304 * We must check to see if we have local tokens for admin since he'll may do
305 * various pioctl or calls to protection server that require tokens. Remember
306 * to remove this tokens at the end of the program...
308 strcpy(Name.name, "afs");
309 Name.instance[0] = '\0';
310 strncpy(Name.cell, uss_Cell, sizeof(Name.cell));
312 ktc_GetToken(&Name, &token, sizeof(struct ktc_token), &tok)) {
314 ka_UserAuthenticateLife(0, uss_AccountCreator,
315 CreatorInstance, uss_Cell,
316 longPassBuff, 10 * 60 * 60,
324 * Declare our success.
329 } /*InitThisModule */
332 /*-----------------------------------------------------------------------
333 * EXPORTED uss_kauth_AddUser
336 * The uconn_kauthP variable may already be set to an AuthServer
341 *------------------------------------------------------------------------*/
344 uss_kauth_AddUser(a_user, a_passwd)
348 { /*uss_kauth_AddUser */
350 static char rn[] = "uss_kauth_AddUser"; /*Routine name */
351 struct ktc_encryptionKey key;
354 if (uss_SkipKaserver) {
356 * Don't talk to the kaserver; assume calls succeded and simply return.
357 * Amasingly people want to update it (most likely kerberos) themselves...
361 ("[Skip Kaserver option - Adding of user %s in Authentication DB not done]\n",
368 * Make sure the module has been initialized before we start trying
369 * to talk to AuthServers.
372 code = InitThisModule();
378 * Given the (unencrypted) password and cell, generate a key to
379 * pass to the AuthServer.
381 ka_StringToKey(a_passwd, uss_Cell, &key);
385 fprintf(stderr, "Adding user '%s' to the Authentication DB\n",
388 #ifdef USS_KAUTH_DB_INSTANCE
390 "%s: KAM_CreateUser: user='%s', CreatorInstance='%s', %d bytes\n",
391 rn, a_user, CreatorInstance, strlen(CreatorInstance));
392 #endif /* USS_KAUTH_DB_INSTANCE */
393 code = ubik_Call(KAM_CreateUser, uconn_kauthP, 0, a_user, UserInstance, /*set by CheckUsername() */
396 if (code == KAEXIST) {
399 "%s: Warning: User '%s' already in Authentication DB\n",
402 afs_com_err(uss_whoami, code,
403 "while adding user '%s' to Authentication DB",
406 printf("%s: Error code from KAM_CreateUser: %d\n", rn, code);
407 #endif /* USS_KAUTH_DB */
410 } /*KAM_CreateUser failed */
414 "\t[Dry run - user '%s' NOT added to Authentication DB]\n",
419 } /*uss_kauth_AddUser */
422 /*-----------------------------------------------------------------------
423 * EXPORTED uss_kauth_DelUser
426 * The uconn_kauthP variable may already be set to an AuthServer
431 *------------------------------------------------------------------------*/
434 uss_kauth_DelUser(a_user)
437 { /*uss_kauth_DelUser */
439 static char rn[] = "uss_kauth_DelUser"; /*Routine name */
440 register afs_int32 code; /*Return code */
442 if (uss_SkipKaserver) {
444 * Don't talk to the kaserver; assume calls succeded and simply return.
445 * Amasingly people want to update it (most likely kerberos) themselves...
449 ("[Skip Kaserver option - Deleting of user %s in Authentication DB not done]\n",
455 * Make sure the module has been initialized before we start trying
456 * to talk to AuthServers.
459 code = InitThisModule();
465 #ifdef USS_KAUTH_DB_INSTANCE
466 printf("%s: KAM_DeleteUser: user='%s', CreatorInstance='%s'\n",
467 uss_whoami, a_user, CreatorInstance);
468 #endif /* USS_KAUTH_DB_INSTANCE */
470 printf("Deleting user '%s' from Authentication DB\n", a_user);
471 code = ubik_Call(KAM_DeleteUser, /*Procedure to call */
472 uconn_kauthP, /*Ubik client connection struct */
474 a_user, /*User name to delete */
475 UserInstance); /*set in CheckUserName() */
477 if (code == KANOENT) {
480 ("%s: No entry for user '%s' in Authentication DB\n",
484 afs_com_err(uss_whoami, code,
485 "while deleting entry in Authentication DB\n");
487 printf("%s: Error code from KAM_DeleteUser: %d\n", rn, code);
488 #endif /* USS_KAUTH_DB */
491 } /*KAM_DeleteUser failed */
494 printf("\t[Dry run - user '%s' NOT deleted from Authentication DB]\n",
499 } /*uss_kauth_DelUser */
502 /*-----------------------------------------------------------------------
503 * EXPORTED uss_kauth_CheckUserName
506 * The user name has already been parsed and placed into
511 *------------------------------------------------------------------------*/
514 uss_kauth_CheckUserName()
515 { /*uss_kauth_CheckUserName */
517 static char rn[] = "uss_kauth_CheckUserName"; /*Routine name */
518 register afs_int32 code; /*Return code */
520 if (uss_SkipKaserver) {
522 * Don't talk to the kaserver; assume calls succeded and simply return.
523 * Amasingly people want to update it (most likely kerberos) themselves...
527 ("[Skip Kaserver option - Checking of user name in Authentication DB not done]\n");
532 * Make sure the module has been initialized before we start trying
533 * to talk to AuthServers.
536 code = InitThisModule();
542 * Use the AuthServer's own routine to decide if the parsed user name
543 * is legal. Specifically, it can't have any weird characters or
544 * embedded instance or cell names.
546 code = ka_ParseLoginName(uss_User, UserPrincipal, UserInstance, UserCell);
547 if (strlen(UserInstance) > 0) {
549 "%s: User name can't have an instance string ('%s')\n",
550 uss_whoami, UserInstance);
553 if (strlen(UserCell) > 0) {
554 fprintf(stderr, "%s: User name can't have a cell string ('%s')\n",
555 uss_whoami, UserCell);
558 if (strchr(UserPrincipal, ':') != NULL) {
559 fprintf(stderr, "%s: User name '%s' can't have a colon\n", uss_whoami,
563 if (strlen(UserPrincipal) > 8) {
565 "%s: User name '%s' must have 8 or fewer characters\n",
566 uss_whoami, UserPrincipal);
571 * The name's OK in my book. Replace the user name with the parsed
574 strcpy(uss_User, UserPrincipal);
577 } /*uss_kauth_CheckUserName */
581 * EXPORTED uss_kauth_SetFields
584 * The uconn_kauthP variable may already be set to an AuthServer
592 uss_kauth_SetFields(username, expirestring, reuse, failures, lockout)
599 static char rn[] = "uss_kauth_SetFields";
601 char misc_auth_bytes[4];
605 afs_int32 lifetime = 0;
606 afs_int32 maxAssociates = -1;
607 afs_int32 was_spare = 0;
608 char instance = '\0';
610 int nfailures, locktime, hrs, mins;
612 if (strlen(username) > uss_UserLen) {
614 "%s: * User field in add cmd too long (max is %d chars; truncated value is '%s')\n",
615 uss_whoami, uss_UserLen, uss_User);
619 strcpy(uss_User, username);
620 code = uss_kauth_CheckUserName();
624 /* no point in doing this any sooner than necessary */
625 for (i = 0; i < 4; misc_auth_bytes[i++] = 0);
627 pwexpiry = atoi(expirestring);
628 if (pwexpiry < 0 || pwexpiry > 254) {
629 fprintf(stderr, "Password lifetime range must be [0..254] days.\n");
630 fprintf(stderr, "Zero represents an unlimited lifetime.\n");
632 "Continuing with default lifetime == 0 for user %s.\n",
636 misc_auth_bytes[0] = pwexpiry + 1;
638 if (!strcmp(reuse, "noreuse")) {
639 misc_auth_bytes[1] = KA_NOREUSEPW;
641 misc_auth_bytes[1] = KA_REUSEPW;
642 if (strcmp(reuse, "reuse"))
643 fprintf(stderr, "must specify \"reuse\" or \"noreuse\": \"reuse\" assumed\n");
646 nfailures = atoi(failures);
647 if (nfailures < 0 || nfailures > 254) {
648 fprintf(stderr, "Failure limit must be in [0..254].\n");
649 fprintf(stderr, "Zero represents unlimited login attempts.\n");
650 fprintf(stderr, "Continuing with limit == 254 for user %s.\n",
652 misc_auth_bytes[2] = 255;
654 misc_auth_bytes[2] = nfailures + 1;
657 if (strchr(lockout, ':'))
658 sscanf(lockout, "%d:%d", &hrs, &mins);
660 sscanf(lockout, "%d", &mins);
662 locktime = hrs*60 + mins;
663 if (hrs < 0 || hrs > 36 || mins < 0) {
664 fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
665 fprintf(stderr,"Lockout times must be less than 36 hours.\n");
667 } else if (locktime > 36*60) {
668 fprintf(stderr, "Lockout times must be either minutes or hh:mm.\n");
669 fprintf(stderr, "Lockout times must be less than 36 hours.\n");
670 fprintf(stderr, "Continuing with lock time == forever for user %s.\n",
672 misc_auth_bytes[3] = 1;
674 locktime = (locktime * 60 + 511) >> 9; /* ceil(l*60/512) */
675 misc_auth_bytes[3] = locktime + 1;
678 if (uss_SkipKaserver) {
680 printf("[Skipping Kaserver as requested]\n");
685 * Make sure the module has been initialized before we start trying
686 * to talk to AuthServers.
689 code = InitThisModule();
696 fprintf(stderr, "Setting options for '%s' in database.\n",
699 was_spare = pack_long(misc_auth_bytes);
701 if (was_spare || flags || expiration || lifetime
702 || (maxAssociates >= 0)) {
705 expiration = uss_Expires;
707 ubik_Call(KAM_SetFields, uconn_kauthP, 0, username, &instance,
708 flags, expiration, lifetime, maxAssociates,
709 was_spare, /* spare */ 0);
712 "Must specify one of the optional parameters. Continuing...\n");
715 afs_com_err(uss_whoami, code, "calling KAM_SetFields for %s.%s",
722 fprintf(stderr, "\t[Dry run - user '%s' NOT changed.]\n", username);
726 } /*uss_kauth_SetFields */