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 <afs/com_err.h>
24 #include <afs/kautils.h> /*MAXKTCREALMLEN*/
25 #include <afs/kaport.h> /* pack_long */
26 #include <afs/kauth.h>
28 #include "uss_kauth.h" /*Module interface */
29 #include "uss_common.h" /*Common defs & operations */
31 #define uss_kauth_MAX_SIZE 2048
34 * ---------------------- Exported variables ----------------------
36 struct ubik_client
*uconn_kauthP
; /*Ubik connections
40 * ------------------------ Private globals -----------------------
42 static int initDone
= 0; /*Module initialized? */
43 static char CreatorInstance
[MAXKTCNAMELEN
]; /*Instance string */
44 static char UserPrincipal
[MAXKTCNAMELEN
]; /*Parsed user principal */
45 static char UserInstance
[MAXKTCNAMELEN
]; /*Parsed user instance */
46 static char UserCell
[MAXKTCREALMLEN
]; /*Parsed user cell */
49 /*-----------------------------------------------------------------------
50 * EXPORTED uss_kauth_InitAccountCreator
53 * The command line must have been parsed.
57 *-----------------------------------------------------------------------*/
60 uss_kauth_InitAccountCreator(void)
61 { /*uss_kauth_InitAccountCreator */
68 * Set up the identity of the principal performing the account
69 * creation (uss_AccountCreator). It's either the administrator
70 * name provided at the call or the identity of the caller as
71 * gleaned from the password info.
73 if (uss_Administrator
[0] != '\0') {
74 name
= uss_Administrator
;
75 } else { /* Administrator name not passed in */
76 pw
= getpwuid(getuid());
79 "%s: Can't figure out your name from your user id.\n",
86 /* Break the *name into principal and instance */
87 dotPosition
= strcspn(name
, ".");
88 if (dotPosition
>= MAXKTCNAMELEN
) {
89 fprintf(stderr
, "Admin principal name too long.\n");
92 strncpy(uss_AccountCreator
, name
, dotPosition
);
93 uss_AccountCreator
[dotPosition
] = '\0';
98 if (strlen(name
) >= MAXKTCNAMELEN
) {
99 fprintf(stderr
, "Admin instance name too long.\n");
102 strcpy(CreatorInstance
, name
);
104 CreatorInstance
[0] = '\0';
107 #ifdef USS_KAUTH_DB_INSTANCE
108 fprintf(stderr
, "%s: Starting CreatorInstance is '%s', %d bytes\n",
109 uss_whoami
, CreatorInstance
, strlen(CreatorInstance
));
110 #endif /* USS_KAUTH_DB_INSTANCE */
115 /*-----------------------------------------------------------------------
116 * static InitThisModule
119 * Set up this module, namely set up all the client state for
120 * dealing with the Volume Location Server(s), including
121 * network connections.
124 * a_noAuthFlag : Do we need authentication?
125 * a_confDir : Configuration directory to use.
126 * a_cellName : Cell we want to talk to.
129 * 0 if everything went fine, or
130 * lower-level error code otherwise.
133 * This routine will only be called once.
137 *------------------------------------------------------------------------*/
143 static char gpbuf
[BUFSIZ
];
144 /* read a password from stdin, stop on \n or eof */
146 memset(gpbuf
, 0, sizeof(gpbuf
));
147 for (i
= 0; i
< (sizeof(gpbuf
) - 1); i
++) {
149 if (tc
== '\n' || tc
== EOF
)
159 { /*InitThisModule */
161 static char rn
[] = "uss_kauth:InitThisModule";
164 char prompt
[2 * MAXKTCNAMELEN
+ 20];
165 char *reasonString
, longPassBuff
[1024], shortPassBuff
[9];
166 struct ktc_encryptionKey key
;
167 struct ktc_token token
;
168 struct ktc_principal Name
, tok
;
171 * Only call this routine once.
178 * Pull out the caller's administrator token if they have one.
181 ka_GetAdminToken(0, 0, uss_Cell
, 0, 10 * 60 * 60, &token
,
185 strncpy(longPassBuff
, getpipepass(), sizeof(longPassBuff
));
188 * Nope, no admin tokens available. Get the key based on the
189 * full password and try again.
191 sprintf(prompt
, "Password for '%s", uss_AccountCreator
);
192 if (CreatorInstance
[0])
193 sprintf(prompt
+ strlen(prompt
), ".%s", CreatorInstance
);
194 strcat(prompt
, "': ");
195 code
= ka_UserReadPassword(prompt
, /*Prompt to use */
196 longPassBuff
, /*Long pwd buffer */
197 sizeof(longPassBuff
), /*Size of above */
200 afs_com_err(uss_whoami
, code
, "while getting password ");
202 printf("%s: Error code from ka_UserReadPassword(): %d\n", rn
,
204 #endif /* USS_KAUTH_DB */
208 ka_StringToKey(longPassBuff
, uss_Cell
, &key
);
210 ka_GetAdminToken(uss_AccountCreator
, CreatorInstance
, uss_Cell
,
211 &key
, 24 * 60 * 60, &token
, 0 /*new */ );
213 if ((code
== KABADREQUEST
) && (strlen(longPassBuff
) > 8)) {
215 * The key we provided just doesn't work, yet we
216 * suspect that since the password is greater than 8
217 * chars, it might be the case that we really need
218 * to truncate the password to generate the appropriate
221 afs_com_err(uss_whoami
, code
,
222 "while getting administrator token (trying shortened password next...)");
224 printf("%s: Error code from ka_GetAdminToken: %d\n", rn
,
226 #endif /* USS_KAUTH_DB */
227 strncpy(shortPassBuff
, longPassBuff
, 8);
228 shortPassBuff
[8] = 0;
229 ka_StringToKey(shortPassBuff
, uss_Cell
, &key
);
231 ka_GetAdminToken(uss_AccountCreator
, CreatorInstance
,
232 uss_Cell
, &key
, 24 * 60 * 60, &token
,
235 afs_com_err(uss_whoami
, code
,
236 "while getting administrator token (possibly wrong password, or not an administrative account)");
238 printf("%s: Error code from ka_GetAdminToken: %d\n", rn
,
240 #endif /* USS_KAUTH_DB */
244 * The silly administrator has a long password! Tell
245 * him or her off in a polite way.
248 ("%s: Shortened password accepted by the Authentication Server\n",
251 } /*Try a shorter password */
254 * We failed to get an admin token, but the password is
255 * of a reasonable length, so we're just hosed.
257 afs_com_err(uss_whoami
, code
,
258 "while getting administrator token (possibly wrong password, or not an administrative account)");
260 printf("%s: Error code from ka_GetAdminToken: %d\n", rn
,
262 #endif /* USS_KAUTH_DB */
264 } /*Even the shorter password didn't work */
265 } /*Key from given password didn't work */
268 /*First attempt to get admin token failed */
270 * At this point, we have acquired an administrator token. Let's
271 * proceed to set up a connection to the AuthServer.
273 #ifdef USS_KAUTH_DB_INSTANCE
275 "%s: CreatorInstance after ka_GetAdminToken(): '%s', %d bytes\n",
276 rn
, CreatorInstance
, strlen(CreatorInstance
));
277 #endif /* USS_KAUTH_DB_INSTANCE */
280 * Set up the connection to the AuthServer read/write site.
283 ka_AuthServerConn(uss_Cell
, KA_MAINTENANCE_SERVICE
, &token
,
286 afs_com_err(uss_whoami
, code
,
287 "while establishing Authentication Server connection");
289 printf("%s: Error code from ka_AuthServerConn: %d\n", rn
, code
);
290 #endif /* USS_KAUTH_DB */
294 if (uss_Administrator
[0]) {
296 * We must check to see if we have local tokens for admin since he'll may do
297 * various pioctl or calls to protection server that require tokens. Remember
298 * to remove this tokens at the end of the program...
300 strcpy(Name
.name
, "afs");
301 Name
.instance
[0] = '\0';
302 strncpy(Name
.cell
, uss_Cell
, sizeof(Name
.cell
));
304 ktc_GetToken(&Name
, &token
, sizeof(struct ktc_token
), &tok
))) {
306 ka_UserAuthenticateLife(0, uss_AccountCreator
,
307 CreatorInstance
, uss_Cell
,
308 longPassBuff
, 10 * 60 * 60,
316 * Declare our success.
321 } /*InitThisModule */
324 /*-----------------------------------------------------------------------
325 * EXPORTED uss_kauth_AddUser
328 * The uconn_kauthP variable may already be set to an AuthServer
333 *------------------------------------------------------------------------*/
336 uss_kauth_AddUser(char *a_user
, char *a_passwd
)
337 { /*uss_kauth_AddUser */
339 static char rn
[] = "uss_kauth_AddUser"; /*Routine name */
341 struct ktc_encryptionKey ktc_key
;
345 if (uss_SkipKaserver
) {
347 * Don't talk to the kaserver; assume calls succeded and simply return.
348 * Amasingly people want to update it (most likely kerberos) themselves...
352 ("[Skip Kaserver option - Adding of user %s in Authentication DB not done]\n",
359 * Make sure the module has been initialized before we start trying
360 * to talk to AuthServers.
363 code
= InitThisModule();
369 * Given the (unencrypted) password and cell, generate a key to
370 * pass to the AuthServer.
372 ka_StringToKey(a_passwd
, uss_Cell
, &ktc_key
);
374 memcpy(&key
, &ktc_key
, sizeof(key
)); /* XXX - we could just cast */
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_KAM_CreateUser(uconn_kauthP
, 0, a_user
,
387 UserInstance
, /*set by CheckUsername() */
390 if (code
== KAEXIST
) {
393 "%s: Warning: User '%s' already in Authentication DB\n",
396 afs_com_err(uss_whoami
, code
,
397 "while adding user '%s' to Authentication DB",
400 printf("%s: Error code from KAM_CreateUser: %d\n", rn
, code
);
401 #endif /* USS_KAUTH_DB */
404 } /*KAM_CreateUser failed */
408 "\t[Dry run - user '%s' NOT added to Authentication DB]\n",
413 } /*uss_kauth_AddUser */
416 /*-----------------------------------------------------------------------
417 * EXPORTED uss_kauth_DelUser
420 * The uconn_kauthP variable may already be set to an AuthServer
425 *------------------------------------------------------------------------*/
428 uss_kauth_DelUser(char *a_user
)
429 { /*uss_kauth_DelUser */
431 static char rn
[] = "uss_kauth_DelUser"; /*Routine name */
433 afs_int32 code
; /*Return code */
435 if (uss_SkipKaserver
) {
437 * Don't talk to the kaserver; assume calls succeded and simply return.
438 * Amasingly people want to update it (most likely kerberos) themselves...
442 ("[Skip Kaserver option - Deleting of user %s in Authentication DB not done]\n",
448 * Make sure the module has been initialized before we start trying
449 * to talk to AuthServers.
452 code
= InitThisModule();
458 #ifdef USS_KAUTH_DB_INSTANCE
459 printf("%s: KAM_DeleteUser: user='%s', CreatorInstance='%s'\n",
460 uss_whoami
, a_user
, CreatorInstance
);
461 #endif /* USS_KAUTH_DB_INSTANCE */
463 printf("Deleting user '%s' from Authentication DB\n", a_user
);
464 code
= ubik_KAM_DeleteUser(
465 uconn_kauthP
, /*Ubik client connection struct */
467 a_user
, /*User name to delete */
468 UserInstance
); /*set in CheckUserName() */
470 if (code
== KANOENT
) {
473 ("%s: No entry for user '%s' in Authentication DB\n",
477 afs_com_err(uss_whoami
, code
,
478 "while deleting entry in Authentication DB\n");
480 printf("%s: Error code from KAM_DeleteUser: %d\n", rn
, code
);
481 #endif /* USS_KAUTH_DB */
484 } /*KAM_DeleteUser failed */
487 printf("\t[Dry run - user '%s' NOT deleted from Authentication DB]\n",
492 } /*uss_kauth_DelUser */
495 /*-----------------------------------------------------------------------
496 * EXPORTED uss_kauth_CheckUserName
499 * The user name has already been parsed and placed into
504 *------------------------------------------------------------------------*/
507 uss_kauth_CheckUserName(void)
508 { /*uss_kauth_CheckUserName */
510 static char rn
[] = "uss_kauth_CheckUserName"; /*Routine name */
512 afs_int32 code
; /*Return code */
514 if (uss_SkipKaserver
) {
516 * Don't talk to the kaserver; assume calls succeded and simply return.
517 * Amasingly people want to update it (most likely kerberos) themselves...
521 ("[Skip Kaserver option - Checking of user name in Authentication DB not done]\n");
526 * Make sure the module has been initialized before we start trying
527 * to talk to AuthServers.
530 code
= InitThisModule();
536 * Use the AuthServer's own routine to decide if the parsed user name
537 * is legal. Specifically, it can't have any weird characters or
538 * embedded instance or cell names.
540 code
= ka_ParseLoginName(uss_User
, UserPrincipal
, UserInstance
, UserCell
);
541 if (strlen(UserInstance
) > 0) {
543 "%s: User name can't have an instance string ('%s')\n",
544 uss_whoami
, UserInstance
);
547 if (strlen(UserCell
) > 0) {
548 fprintf(stderr
, "%s: User name can't have a cell string ('%s')\n",
549 uss_whoami
, UserCell
);
552 if (strchr(UserPrincipal
, ':') != NULL
) {
553 fprintf(stderr
, "%s: User name '%s' can't have a colon\n", uss_whoami
,
557 if (strlen(UserPrincipal
) > 8) {
559 "%s: User name '%s' must have 8 or fewer characters\n",
560 uss_whoami
, UserPrincipal
);
565 * The name's OK in my book. Replace the user name with the parsed
568 strcpy(uss_User
, UserPrincipal
);
571 } /*uss_kauth_CheckUserName */
575 * EXPORTED uss_kauth_SetFields
578 * The uconn_kauthP variable may already be set to an AuthServer
586 uss_kauth_SetFields(char *username
, char *expirestring
, char *reuse
,
587 char *failures
, char *lockout
)
590 static char rn
[] = "uss_kauth_SetFields";
593 char misc_auth_bytes
[4];
597 afs_int32 lifetime
= 0;
598 afs_int32 maxAssociates
= -1;
599 afs_int32 was_spare
= 0;
600 char instance
= '\0';
602 int nfailures
, locktime
, hrs
, mins
;
604 if (strlen(username
) > uss_UserLen
) {
606 "%s: * User field in add cmd too long (max is %d chars; truncated value is '%s')\n",
607 uss_whoami
, uss_UserLen
, uss_User
);
611 strcpy(uss_User
, username
);
612 code
= uss_kauth_CheckUserName();
616 /* no point in doing this any sooner than necessary */
617 for (i
= 0; i
< 4; misc_auth_bytes
[i
++] = 0);
619 pwexpiry
= atoi(expirestring
);
620 if (pwexpiry
< 0 || pwexpiry
> 254) {
621 fprintf(stderr
, "Password lifetime range must be [0..254] days.\n");
622 fprintf(stderr
, "Zero represents an unlimited lifetime.\n");
624 "Continuing with default lifetime == 0 for user %s.\n",
628 misc_auth_bytes
[0] = pwexpiry
+ 1;
630 if (!strcmp(reuse
, "noreuse")) {
631 misc_auth_bytes
[1] = KA_NOREUSEPW
;
633 misc_auth_bytes
[1] = KA_REUSEPW
;
634 if (strcmp(reuse
, "reuse"))
635 fprintf(stderr
, "must specify \"reuse\" or \"noreuse\": \"reuse\" assumed\n");
638 nfailures
= atoi(failures
);
639 if (nfailures
< 0 || nfailures
> 254) {
640 fprintf(stderr
, "Failure limit must be in [0..254].\n");
641 fprintf(stderr
, "Zero represents unlimited login attempts.\n");
642 fprintf(stderr
, "Continuing with limit == 254 for user %s.\n",
644 misc_auth_bytes
[2] = 255;
646 misc_auth_bytes
[2] = nfailures
+ 1;
649 if (strchr(lockout
, ':'))
650 sscanf(lockout
, "%d:%d", &hrs
, &mins
);
652 sscanf(lockout
, "%d", &mins
);
654 locktime
= hrs
*60 + mins
;
655 if (hrs
< 0 || hrs
> 36 || mins
< 0) {
656 fprintf(stderr
,"Lockout times must be either minutes or hh:mm.\n");
657 fprintf(stderr
,"Lockout times must be less than 36 hours.\n");
659 } else if (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",
664 misc_auth_bytes
[3] = 1;
666 locktime
= (locktime
* 60 + 511) >> 9; /* ceil(l*60/512) */
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
|| lifetime
694 || (maxAssociates
>= 0)) {
697 expiration
= uss_Expires
;
699 ubik_KAM_SetFields(uconn_kauthP
, 0, username
, &instance
,
700 flags
, expiration
, lifetime
, maxAssociates
,
701 was_spare
, /* spare */ 0);
704 "Must specify one of the optional parameters. Continuing...\n");
707 afs_com_err(uss_whoami
, code
, "calling KAM_SetFields for %s",
714 fprintf(stderr
, "\t[Dry run - user '%s' NOT changed.]\n", username
);
718 } /*uss_kauth_SetFields */