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>
23 #include "uss_kauth.h" /*Module interface*/
24 #include "uss_common.h" /*Common defs & operations*/
27 #include <afs/com_err.h>
28 #include <afs/kautils.h> /*MAXKTCREALMLEN*/
29 #include <afs/kaport.h> /* pack_long */
33 #define uss_kauth_MAX_SIZE 2048
38 * ---------------------- Exported variables ----------------------
40 struct ubik_client *uconn_kauthP; /*Ubik connections
44 * ------------------------ Private globals -----------------------
46 static int initDone = 0; /*Module initialized?*/
47 static char CreatorInstance[MAXKTCNAMELEN]; /*Instance string*/
48 static char UserPrincipal[MAXKTCNAMELEN]; /*Parsed user principal*/
49 static char UserInstance[MAXKTCNAMELEN]; /*Parsed user instance*/
50 static char UserCell[MAXKTCREALMLEN]; /*Parsed user cell*/
53 /*-----------------------------------------------------------------------
54 * EXPORTED uss_kauth_InitAccountCreator
57 * The command line must have been parsed.
61 *-----------------------------------------------------------------------*/
63 afs_int32 uss_kauth_InitAccountCreator()
65 { /*uss_kauth_InitAccountCreator*/
72 * Set up the identity of the principal performing the account
73 * creation (uss_AccountCreator). It's either the administrator
74 * name provided at the call or the identity of the caller as
75 * gleaned from the password info.
77 if (uss_Administrator[0] != '\0') {
78 name = uss_Administrator;
80 else { /* Administrator name not passed in */
81 pw = getpwuid(getuid());
84 "%s: Can't figure out your name from your user id.\n",
91 /* Break the *name into principal and instance */
92 dotPosition = strcspn(name, ".");
93 if (dotPosition >= MAXKTCNAMELEN) {
94 fprintf(stderr, "Admin principal name too long.\n");
97 strncpy(uss_AccountCreator, name, dotPosition);
98 uss_AccountCreator[dotPosition] = '\0';
101 if (name[0] == '.') {
103 if (strlen(name) >= MAXKTCNAMELEN) {
104 fprintf(stderr, "Admin instance name too long.\n");
107 strcpy(CreatorInstance, name);
110 CreatorInstance[0] = '\0';
113 #ifdef USS_KAUTH_DB_INSTANCE
115 "%s: Starting CreatorInstance is '%s', %d bytes\n",
116 uss_whoami, CreatorInstance, strlen(CreatorInstance));
117 #endif /* USS_KAUTH_DB_INSTANCE */
122 /*-----------------------------------------------------------------------
123 * static InitThisModule
126 * Set up this module, namely set up all the client state for
127 * dealing with the Volume Location Server(s), including
128 * network connections.
131 * a_noAuthFlag : Do we need authentication?
132 * a_confDir : Configuration directory to use.
133 * a_cellName : Cell we want to talk to.
136 * 0 if everything went fine, or
137 * lower-level error code otherwise.
140 * This routine will only be called once.
144 *------------------------------------------------------------------------*/
147 static char *getpipepass() {
148 static char gpbuf[BUFSIZ];
149 /* read a password from stdin, stop on \n or eof */
151 memset(gpbuf, 0, sizeof(gpbuf));
152 for(i=0; i<(sizeof(gpbuf)-1); i++) {
154 if (tc == '\n' || tc == EOF) break;
161 afs_int32 InitThisModule()
165 static char rn[] = "uss_kauth:InitThisModule";
166 register afs_int32 code;
167 char *name, prompt[2*MAXKTCNAMELEN+20];
168 char *reasonString, longPassBuff[1024], shortPassBuff[9];
169 struct ktc_encryptionKey key;
170 struct ktc_token token, tok;
171 struct ktc_principal Name;
174 * Only call this routine once.
181 * Pull out the caller's administrator token if they have one.
183 code = ka_GetAdminToken(0, 0, uss_Cell, 0, 10*60*60, &token, 0/*new*/);
186 strncpy(longPassBuff, getpipepass(), sizeof(longPassBuff));
189 * Nope, no admin tokens available. Get the key based on the
190 * full password and try again.
192 sprintf(prompt, "Password for '%s", uss_AccountCreator);
193 if (CreatorInstance[0])
194 sprintf(prompt+strlen(prompt), ".%s", CreatorInstance);
195 strcat(prompt, "': ");
197 ka_UserReadPassword(prompt, /*Prompt to use*/
198 longPassBuff, /*Long pwd buffer*/
199 sizeof(longPassBuff), /*Size of above*/
202 com_err(uss_whoami, code, "while getting password ");
204 printf("%s: Error code from ka_UserReadPassword(): %d\n",
206 #endif /* USS_KAUTH_DB */
210 ka_StringToKey(longPassBuff, uss_Cell, &key);
211 code = ka_GetAdminToken(uss_AccountCreator,
219 if ((code == KABADREQUEST) && (strlen(longPassBuff) > 8)) {
221 * The key we provided just doesn't work, yet we
222 * suspect that since the password is greater than 8
223 * chars, it might be the case that we really need
224 * to truncate the password to generate the appropriate
227 com_err(uss_whoami, code,
228 "while getting administrator token (trying shortened password next...)");
230 printf("%s: Error code from ka_GetAdminToken: %d\n",
232 #endif /* USS_KAUTH_DB */
233 strncpy(shortPassBuff, longPassBuff, 8);
234 shortPassBuff[8] = 0;
235 ka_StringToKey(shortPassBuff, uss_Cell, &key);
236 code = ka_GetAdminToken(uss_AccountCreator,
244 com_err(uss_whoami, code,
245 "while getting administrator token (possibly wrong password, or not an administrative account)");
247 printf("%s: Error code from ka_GetAdminToken: %d\n",
249 #endif /* USS_KAUTH_DB */
254 * The silly administrator has a long password! Tell
255 * him or her off in a polite way.
257 printf("%s: Shortened password accepted by the Authentication Server\n", uss_whoami);
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 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",
270 #endif /* USS_KAUTH_DB */
272 } /*Even the shorter password didn't work*/
273 } /*Key from given password didn't work*/
274 } /*First attempt to get admin token failed*/
277 * At this point, we have acquired an administrator token. Let's
278 * proceed to set up a connection to the AuthServer.
280 #ifdef USS_KAUTH_DB_INSTANCE
282 "%s: CreatorInstance after ka_GetAdminToken(): '%s', %d bytes\n",
283 rn, CreatorInstance, strlen(CreatorInstance));
284 #endif /* USS_KAUTH_DB_INSTANCE */
287 * Set up the connection to the AuthServer read/write site.
289 code = ka_AuthServerConn(uss_Cell, KA_MAINTENANCE_SERVICE,
290 &token, &uconn_kauthP);
292 com_err(uss_whoami, code,
293 "while establishing Authentication Server connection");
295 printf("%s: Error code from ka_AuthServerConn: %d\n",
297 #endif /* USS_KAUTH_DB */
301 if (uss_Administrator[0]) {
303 * We must check to see if we have local tokens for admin since he'll may do
304 * various pioctl or calls to protection server that require tokens. Remember
305 * to remove this tokens at the end of the program...
307 strcpy (Name.name, "afs");
308 Name.instance[0] = '\0';
309 strncpy (Name.cell, uss_Cell, sizeof(Name.cell));
310 if (code = ktc_GetToken (&Name, &token, sizeof(struct ktc_token), &tok)) {
311 code = ka_UserAuthenticateLife (0, uss_AccountCreator, CreatorInstance,
312 uss_Cell,longPassBuff,10*60*60,&reasonString);
319 * Declare our success.
327 /*-----------------------------------------------------------------------
328 * EXPORTED uss_kauth_AddUser
331 * The uconn_kauthP variable may already be set to an AuthServer
336 *------------------------------------------------------------------------*/
338 afs_int32 uss_kauth_AddUser(a_user, a_passwd)
342 { /*uss_kauth_AddUser*/
344 static char rn[] = "uss_kauth_AddUser"; /*Routine name*/
345 struct ktc_encryptionKey key;
348 if (uss_SkipKaserver) {
350 * Don't talk to the kaserver; assume calls succeded and simply return.
351 * Amasingly people want to update it (most likely kerberos) themselves...
354 printf("[Skip Kaserver option - Adding of user %s in Authentication DB not done]\n",
361 * Make sure the module has been initialized before we start trying
362 * to talk to AuthServers.
365 code = InitThisModule();
371 * Given the (unencrypted) password and cell, generate a key to
372 * pass to the AuthServer.
374 ka_StringToKey(a_passwd, uss_Cell, &key);
378 fprintf(stderr, "Adding user '%s' to the Authentication DB\n",
381 #ifdef USS_KAUTH_DB_INSTANCE
383 "%s: KAM_CreateUser: user='%s', CreatorInstance='%s', %d bytes\n",
384 rn, a_user, CreatorInstance, strlen(CreatorInstance));
385 #endif /* USS_KAUTH_DB_INSTANCE */
386 code = ubik_Call(KAM_CreateUser,
390 UserInstance, /*set by CheckUsername()*/
393 if (code == KAEXIST){
396 "%s: Warning: User '%s' already in Authentication DB\n",
400 com_err(uss_whoami, code,
401 "while adding user '%s' to Authentication DB",
404 printf("%s: Error code from KAM_CreateUser: %d\n",
406 #endif /* USS_KAUTH_DB */
409 } /*KAM_CreateUser failed*/
413 "\t[Dry run - user '%s' NOT added to Authentication DB]\n",
418 } /*uss_kauth_AddUser*/
421 /*-----------------------------------------------------------------------
422 * EXPORTED uss_kauth_DelUser
425 * The uconn_kauthP variable may already be set to an AuthServer
430 *------------------------------------------------------------------------*/
432 afs_int32 uss_kauth_DelUser(a_user)
435 { /*uss_kauth_DelUser*/
437 static char rn[] = "uss_kauth_DelUser"; /*Routine name*/
438 register afs_int32 code; /*Return code*/
440 if (uss_SkipKaserver) {
442 * Don't talk to the kaserver; assume calls succeded and simply return.
443 * Amasingly people want to update it (most likely kerberos) themselves...
446 printf("[Skip Kaserver option - Deleting of user %s in Authentication DB not done]\n",
452 * Make sure the module has been initialized before we start trying
453 * to talk to AuthServers.
456 code = InitThisModule();
462 #ifdef USS_KAUTH_DB_INSTANCE
463 printf("%s: KAM_DeleteUser: user='%s', CreatorInstance='%s'\n",
464 uss_whoami, a_user, CreatorInstance);
465 #endif /* USS_KAUTH_DB_INSTANCE */
467 printf("Deleting user '%s' from Authentication DB\n",
469 code = ubik_Call(KAM_DeleteUser, /*Procedure to call*/
470 uconn_kauthP, /*Ubik client connection struct*/
472 a_user, /*User name to delete*/
473 UserInstance); /*set in CheckUserName()*/
475 if (code == KANOENT) {
477 printf("%s: No entry for user '%s' in Authentication DB\n",
482 com_err(uss_whoami, code,
483 "while deleting entry in Authentication DB\n");
485 printf("%s: Error code from KAM_DeleteUser: %d\n",
487 #endif /* USS_KAUTH_DB */
490 } /*KAM_DeleteUser failed*/
493 printf("\t[Dry run - user '%s' NOT deleted from Authentication DB]\n",
498 } /*uss_kauth_DelUser*/
501 /*-----------------------------------------------------------------------
502 * EXPORTED uss_kauth_CheckUserName
505 * The user name has already been parsed and placed into
510 *------------------------------------------------------------------------*/
512 afs_int32 uss_kauth_CheckUserName()
514 { /*uss_kauth_CheckUserName*/
516 static char rn[] = "uss_kauth_CheckUserName"; /*Routine name*/
517 register afs_int32 code; /*Return code*/
519 if (uss_SkipKaserver) {
521 * Don't talk to the kaserver; assume calls succeded and simply return.
522 * Amasingly people want to update it (most likely kerberos) themselves...
525 printf("[Skip Kaserver option - Checking of user name in Authentication DB not done]\n");
530 * Make sure the module has been initialized before we start trying
531 * to talk to AuthServers.
534 code = InitThisModule();
540 * Use the AuthServer's own routine to decide if the parsed user name
541 * is legal. Specifically, it can't have any weird characters or
542 * embedded instance or cell names.
544 code = ka_ParseLoginName(uss_User,
545 UserPrincipal, UserInstance, UserCell);
546 if (strlen(UserInstance) > 0) {
547 fprintf(stderr, "%s: User name can't have an instance string ('%s')\n",
548 uss_whoami, UserInstance);
551 if (strlen(UserCell) > 0) {
552 fprintf(stderr, "%s: User name can't have a cell string ('%s')\n",
553 uss_whoami, UserCell);
556 if (strchr(UserPrincipal, ':') != NULL) {
557 fprintf(stderr, "%s: User name '%s' can't have a colon\n",
558 uss_whoami, UserPrincipal);
561 if (strlen(UserPrincipal) > 8) {
563 "%s: User name '%s' must have 8 or fewer characters\n",
564 uss_whoami, UserPrincipal);
569 * The name's OK in my book. Replace the user name with the parsed
572 strcpy(uss_User, UserPrincipal);
575 } /*uss_kauth_CheckUserName*/
579 * EXPORTED uss_kauth_SetFields
582 * The uconn_kauthP variable may already be set to an AuthServer
589 afs_int32 uss_kauth_SetFields(username, expirestring, reuse, failures, lockout)
596 static char rn[] = "uss_kauth_SetFields";
598 char misc_auth_bytes[4];
602 afs_int32 lifetime = 0;
603 afs_int32 maxAssociates = -1;
604 afs_int32 was_spare = 0;
605 char instance = '\0';
607 int nfailures, locktime;
609 if (strlen (username) > uss_UserLen) {
611 "%s: * User field in add cmd too long (max is %d chars; truncated value is '%s')\n",
612 uss_whoami, uss_UserLen, uss_User);
616 strcpy (uss_User, username);
617 code = uss_kauth_CheckUserName();
621 /* no point in doing this any sooner than necessary */
622 for (i=0;i<4;misc_auth_bytes[i++] = 0);
624 pwexpiry = atoi(expirestring);
625 if (pwexpiry <0 || pwexpiry >254) {
626 fprintf(stderr,"Password lifetime range must be [0..254] days.\n");
627 fprintf(stderr,"Zero represents an unlimited lifetime.\n");
628 fprintf(stderr,"Continuing with default lifetime == 0 for user %s.\n",
632 misc_auth_bytes[0] = pwexpiry+1;
635 if (!strcmp(reuse, "reuse")) {
636 misc_auth_bytes[1] = KA_REUSEPW;
638 else if (!strcmp(reuse, "noreuse")) {
639 misc_auth_bytes[1] = KA_NOREUSEPW;
642 misc_auth_bytes[1] = KA_REUSEPW;
644 "must specify \"reuse\" or \"noreuse\": \"reuse\" assumed\n");
647 nfailures = atoi(failures);
648 if (nfailures <0 || nfailures >254) {
649 fprintf(stderr,"Failure limit must be in [0..254].\n");
650 fprintf(stderr,"Zero represents unlimited login attempts.\n");
651 fprintf(stderr,"Continuing with limit == 254 for user %s.\n",
653 misc_auth_bytes[2] = 255;
656 misc_auth_bytes[2] = nfailures+1;
658 locktime = ktime_Str2int32(lockout);
659 if (locktime < 0 || locktime > 36*60 ) {
660 fprintf(stderr,"Lockout times must be either minutes or hh:mm.\n");
661 fprintf(stderr,"Lockout times must be less than 36 hours.\n");
662 fprintf(stderr,"Continuing with lock time == forever for user %s.\n",
666 locktime = (locktime * 60) >> 9;
667 misc_auth_bytes[3] = locktime +1;
670 if (uss_SkipKaserver) {
672 printf("[Skipping Kaserver as requested]\n");
677 * Make sure the module has been initialized before we start trying
678 * to talk to AuthServers.
681 code = InitThisModule();
688 fprintf(stderr, "Setting options for '%s' in database.\n",
691 was_spare = pack_long(misc_auth_bytes);
693 if (was_spare || flags || expiration ||
694 lifetime || (maxAssociates >= 0)) {
697 expiration = uss_Expires;
698 code = ubik_Call( KAM_SetFields, uconn_kauthP, 0, username, &instance,
699 flags, expiration, lifetime, maxAssociates,
700 was_spare, /* spare */ 0);
702 else fprintf (stderr,
703 "Must specify one of the optional parameters. Continuing...\n");
706 com_err (uss_whoami, code,
707 "calling KAM_SetFields for %s.%s", username, instance);
714 "\t[Dry run - user '%s' NOT changed.]\n",
719 } /*uss_kauth_SetFields */