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>
18 #include <sys/types.h>
21 #include <afs/afsutil.h>
23 #include <sys/resource.h>
36 #include <netinet/in.h>
40 #include <afs/cellconfig.h>
46 #include "afs/audit.h"
48 extern struct ubik_dbase *KA_dbase;
49 struct kaheader cheader;
50 Date cheaderReadTime; /* time cheader last read in */
51 extern struct afsconf_dir *KA_conf; /* for getting cell info */
53 afs_int32 kamCreateUser(), ChangePassWord(), kamSetPassword(), kamSetFields(), kamDeleteUser();
54 afs_int32 kamGetEntry(), kamListEntry(), kamGetStats(), kamGetPassword(), kamGetRandomKey(), kamDebug();
55 char lrealm[MAXKTCREALMLEN];
57 #ifndef EXPIREPW /* password expiration default yes */
61 #ifndef AUTOCPWINTERVAL
62 #define AUTOCPWINTERVAL (24*3600)
64 #ifndef AUTOCPWUPDATES
65 #define AUTOCPWUPDATES 128
70 static afs_int32 autoCPWInterval;
71 static afs_int32 autoCPWUpdates;
73 static afs_int32 set_password (); /* forward */
74 extern afs_int32 InitAuthServ (); /* forward */
75 static afs_int32 impose_reuse_limits(); /* forward */
76 static int create_user(); /* forward */
78 /* This routine is called whenever an RPC interface needs the time. It uses
79 the current time to randomize a 128 bit value that is used to change the
80 AuthServer Admin and TGS keys automatically. */
82 static Date nextAutoCPWTime = 0;
83 static afs_int32 totalUpdates = 0;
85 /* This routine is ostensibly to get the current time, but basically its job is
86 to periodically update a random number. It also periodically updates the
87 keys for the builtin servers. This is why it needs a transaction pointer
88 and returns an error code. If the caller is in a read transaction, the tt
89 ptr should be zero and the return code need not be checked. */
91 static afs_int32 get_time (timeP, tt, admin)
93 struct ubik_trans *tt; /* tt != 0: a write transaction */
94 int admin; /* the caller is an admin user */
96 /* random value used to change Admin & TGS keys, this is at risk during
97 multi-threaded operation, but I think the consequences are fairly
99 static afs_uint32 random_value[4];
102 unsigned int bit, nbit;
106 gettimeofday (&time, 0);
107 bit = (random_value[3] >> 31) & 1; /* get high bit of high word */
108 for (i=0; i<4; i++) {
109 nbit = random_value[i] >> 31;
110 random_value[i] = (random_value[i] << 1) + bit;
113 /* get 60ths from usec. This is all the real randomness there is. */
114 random_value[0] += time.tv_usec / 16667;
116 if (nextAutoCPWTime == 0) { /* initialize things */
117 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
118 memcpy(&random_value[0], &time, 8);
119 memcpy(&random_value[2], &time, 8);
122 if ((++totalUpdates >= autoCPWUpdates) &&
123 tt && /* a write transaction */
124 ((admin && (time.tv_sec >= nextAutoCPWTime)) ||
125 (time.tv_sec >= nextAutoCPWTime + autoCPWInterval))) {
126 struct ktc_encryptionKey key;
127 char buf[4*sizeof(key)+1];
128 struct kaentry tentry;
130 char bob[KA_TIMESTR_LEN];
132 ka_timestr(time.tv_sec,bob,KA_TIMESTR_LEN);
133 es_Report ("Auto CPW at %s\n", bob);
134 if (!admin) es_Report (" ... even though no ADMIN user\n");
136 code = FindBlock (tt, KA_ADMIN_NAME, KA_ADMIN_INST, &to, &tentry);
137 if (code) return code;
138 if (to) { /* check if auto cpw is disabled */
139 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
140 memcpy(&key, &random_value[0], sizeof(key));
141 des_fixup_key_parity (&key);
142 code = set_password (tt, KA_ADMIN_NAME, KA_ADMIN_INST,
145 des_init_random_number_generator (&key);
146 ka_ConvertBytes (buf, sizeof(buf), (char *)&key,
148 es_Report ("New Admin key is %s\n", buf);
150 es_Report ("in get_time: set_password failed because: %d\n", code);
156 code = FindBlock(tt, KA_TGS_NAME, lrealm, &to, &tentry);
157 if (code) return code;
158 if (to) { /* check if auto cpw is disabled */
159 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
160 memcpy(&key, &random_value[2], sizeof(key));
161 des_fixup_key_parity (&key);
162 code = set_password (tt, KA_TGS_NAME, lrealm, &key, 0, 0);
164 ka_ConvertBytes (buf, sizeof(buf), (char *)&key,
166 es_Report ("New TGS key is %s\n", buf);
168 es_Report ("in get_time: set_password failed because: %s\n", error_message (code));
173 code = ka_FillKeyCache (tt); /* ensure in-core copy is uptodate */
174 if (code) return code;
176 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
179 if (timeP) *timeP = time.tv_sec;
183 static int noAuthenticationRequired; /* global state */
184 static int recheckNoAuth; /* global state */
186 /* kaprocsInited is sort of a lock: during a transaction only one process runs
187 while kaprocsInited is false. */
189 static int kaprocsInited = 0;
191 /* This variable is protected by the kaprocsInited flag. */
193 static int (*rebuildDatabase)();
195 /* This is called to initialize the database */
197 static int initialize_database (tt)
198 struct ubik_trans *tt;
199 { struct ktc_encryptionKey key;
202 gettimeofday((struct timeval *)&key, 0); /* this is just a cheap seed key */
203 des_fixup_key_parity (&key);
204 des_init_random_number_generator (&key);
205 if ((code = des_random_key (&key)) ||
206 (code = create_user (tt, KA_ADMIN_NAME, KA_ADMIN_INST,
207 &key, 0, KAFNORMAL|KAFNOSEAL|KAFNOTGS)))
209 if ((code = des_random_key (&key)) ||
210 (code = create_user (tt, KA_TGS_NAME, lrealm,
211 &key, 0, KAFNORMAL|KAFNOSEAL|KAFNOTGS)))
216 /* This routine handles initialization required by this module. The initFlags
217 parameter passes some information about the command line arguments. */
219 afs_int32 init_kaprocs(lclpath, initFlags)
223 struct ubik_trans *tt;
224 struct ktc_encryptionKey key;
228 if (myHost == 0) return KAINTERNALERROR;
229 if (KA_conf == 0) return KAINTERNALERROR;
230 code = afsconf_GetLocalCell (KA_conf, lrealm, sizeof(lrealm));
232 printf("** Can't determine local cell name!\n");
235 ucstring (lrealm, lrealm, sizeof(lrealm));
238 if (initFlags & 1) noAuthenticationRequired = 1;
239 if (initFlags & 2) recheckNoAuth = 0;
241 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
242 if (noAuthenticationRequired)
243 printf ("Running server with security disabled\n");
246 autoCPWInterval = 10;
249 autoCPWInterval = AUTOCPWINTERVAL;
250 autoCPWUpdates = AUTOCPWUPDATES;
253 init_kadatabase (initFlags);
254 rebuildDatabase = initialize_database;
256 if (code = InitAuthServ (&tt, LOCKREAD, 0)) {
257 printf ("init_kaprocs: InitAuthServ failed: code = %d\n", code);
260 code = ka_LookupKey (tt, KA_ADMIN_NAME, KA_ADMIN_INST, &kvno, &key);
263 printf ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n", code);
266 des_init_random_number_generator (&key);
268 code = ubik_EndTrans(tt);
270 printf ("init_kaprocs: ubik_EndTrans failed: code = %d\n", code);
274 kaux_opendb(lclpath); /* aux database stores failure counters */
275 rebuildDatabase = 0; /* only do this during init */
280 /* These variable are for returning debugging info about the state of the
281 server. If they get trashed during multi-threaded operation it doesn't
284 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
285 char *lastOperation = 0; /* name of last operation */
286 static Date lastTrans; /* time of last transaction */
288 static char adminPrincipal[256];
289 static char authPrincipal[256];
290 static char tgsPrincipal[256];
291 static char tgsServerPrincipal[256];
293 void save_principal (p, n, i, c)
302 if (i && strlen (i)) {
303 if (s-- <= 0) return;
310 if (c && strlen(c)) {
311 if (s-- <= 0) return;
319 static afs_int32 check_auth (call, at, admin, acaller_id)
320 struct rx_call *call;
321 struct ubik_trans *at;
322 int admin; /* require caller to be ADMIN */
323 afs_int32 *acaller_id;
325 char name[MAXKTCNAMELEN];
326 char instance[MAXKTCNAMELEN];
327 char cell[MAXKTCREALMLEN];
329 Date expiration; /* checked by Security Module */
330 struct kaentry tentry;
337 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
339 si = rx_SecurityClassOf(rx_ConnectionOf(call));
340 if (si == RX_SCINDEX_VAB) {
341 printf ("No support for VAB security module yet.\n");
343 } else if (si == RX_SCINDEX_NULL) {
346 } else if (si != RX_SCINDEX_KAD) {
347 es_Report ("Unknown security index %d\n", si);
351 code = rxkad_GetServerInfo (rx_ConnectionOf(call), &level, &expiration,
352 name, instance, cell, &kvno);
356 if (level != rxkad_crypt) {
357 es_Report ("Incorrect security level = %d\n", level);
362 if (!name_instance_legal (name, instance)) return KABADNAME;
364 ka_PrintUserID ("Authorization rejected because we don't understand intercell stuff yet: ",
366 printf ("@%s\n", cell);
370 code = FindBlock(at, name, instance, acaller_id, &tentry);
371 if (code) return code;
372 if (*acaller_id == 0) {
373 ka_PrintUserID ("User ", name, instance, " unknown.\n");
376 save_principal (adminPrincipal, name, instance, 0);
379 if (!(ntohl(tentry.flags) & KAFADMIN)) {
380 if (noAuthenticationRequired) {
381 ka_PrintUserID ("Authorization approved for ", name, instance,
382 " because there is no authentication required\n");
383 osi_auditU (call, UnAuthEvent, code, AUD_STR, name, AUD_STR, instance, AUD_STR, cell, AUD_END);
386 ka_PrintUserID ("User ", name, instance, " is not ADMIN.\n");
389 osi_auditU (call, UseOfPrivilegeEvent, code, AUD_STR,name, AUD_STR,instance, AUD_STR,cell, AUD_END);
394 if (noAuthenticationRequired) {
395 es_Report ("Caller w/o authorization approved no authentication required\n");
396 osi_auditU (call, UnAuthEvent, code, AUD_STR, name, AUD_STR, instance, AUD_STR, cell, AUD_END);
399 return code; /* no auth info */
402 afs_int32 AwaitInitialization ()
403 { afs_int32 start = 0;
404 while (!kaprocsInited) {
405 if (!start) start = time(0);
406 else if (time(0)-start > 5) return UNOQUORUM;
412 /* This is called by every RPC interface to create a Ubik transaction and read
413 the database header into core */
415 afs_int32 InitAuthServ (tt, lock, this_op)
416 struct ubik_trans **tt;
417 int lock; /* indicate read/write transaction */
418 int *this_op; /* opcode of RPC proc, for COUNT_ABO */
420 afs_int32 start = 0; /* time started waiting for quorum */
421 float wait = 0.91; /* start waiting for 1 second */
423 /* Wait for server initialization to finish if not during init_kaprocs */
424 if (this_op) if (code = AwaitInitialization()) return code;
426 for (code = UNOQUORUM; code == UNOQUORUM; ) {
427 if (lock == LOCKREAD)
428 code = ubik_BeginTransReadAny (KA_dbase, UBIK_READTRANS, tt);
429 else code = ubik_BeginTrans (KA_dbase, UBIK_WRITETRANS, tt);
430 if (code == UNOQUORUM) { /* no quorum elected */
431 if (!start) start = time(0);
433 int delay = time(0) - start;
434 if (this_op) { /* punt quickly, if RPC call */
435 if (delay > 5) return code;
436 } else { /* more patient during init. */
437 if (delay > 500) return code;
440 printf ("Waiting for quorum election.\n");
441 if (wait < 15.0) wait *= 1.1;
442 IOMGR_Sleep ((int)wait);
445 if (code) return code;
446 if (code = ubik_SetLock (*tt, 1, 1, lock)) {
447 if (this_op) COUNT_ABO;
448 ubik_AbortTrans (*tt);
451 /* check that dbase is initialized and setup cheader */
452 if (lock == LOCKREAD) {
453 /* init but don't fix because this is read only */
454 code = CheckInit(*tt, 0);
456 ubik_AbortTrans (*tt); /* abort, since probably I/O error */
457 /* we did the check under a ReadAny transaction, but now, after
458 * getting a write transaction (and thus some real guarantees
459 * about what databases are really out there), we will check again
460 * in CheckInit before nuking the database. Since this may now get
461 * a UNOQUORUM we'll just do this from the top.
463 if (code = InitAuthServ (tt, LOCKWRITE, this_op)) return code;
464 if (code = ubik_EndTrans(*tt)) return code;
466 /* now open the read transaction that was originally requested. */
467 return InitAuthServ (tt, lock, this_op);
471 if (code = CheckInit(*tt, rebuildDatabase)) {
472 if (this_op) COUNT_ABO;
473 ubik_AbortTrans(*tt);
478 ka_FillKeyCache (*tt); /* ensure in-core copy is uptodate */
482 /* returns true if name is specially known by AuthServer */
484 static int special_name (name, instance)
488 return ((!strcmp (name, KA_TGS_NAME) && !strcmp(instance, lrealm)) ||
489 (strcmp (name, KA_ADMIN_NAME) == 0));
492 static int create_user (tt, name, instance, key, caller, flags)
493 struct ubik_trans *tt;
501 struct kaentry tentry;
502 afs_int32 maxLifetime;
504 code = FindBlock(tt, name, instance, &to, &tentry);
505 if (code) return code;
506 if (to) return KAEXIST; /* name already exists, we fail */
508 to = AllocBlock(tt, &tentry);
509 if (to == 0) return KACREATEFAIL;
511 /* otherwise we have a block */
512 strncpy(tentry.userID.name, name, sizeof(tentry.userID.name));
513 strncpy(tentry.userID.instance, instance, sizeof(tentry.userID.instance));
514 tentry.flags = htonl(flags);
515 if (special_name (name, instance)) { /* this overrides key & version */
516 tentry.flags = htonl (ntohl(tentry.flags) | KAFSPECIAL);
517 tentry.key_version = htonl(-1); /* don't save this key */
518 if (code = ka_NewKey (tt, to, &tentry, key)) return code;
521 memcpy(&tentry.key, key, sizeof(tentry.key));
522 tentry.key_version = htonl(0);
524 tentry.user_expiration = htonl(NEVERDATE);
525 code = get_time (&tentry.modification_time, tt, 1);
526 if (code) return code;
528 /* time and addr of entry for guy changing this entry */
529 tentry.modification_time = htonl(tentry.modification_time);
530 tentry.modification_id = htonl(caller);
531 tentry.change_password_time = tentry.modification_time;
533 if (strcmp (name, KA_TGS_NAME) == 0) maxLifetime = MAXKTCTICKETLIFETIME;
534 else if (strcmp (name, KA_ADMIN_NAME) == 0) maxLifetime = 10*3600;
535 else if (strcmp (name, AUTH_SUPERUSER) == 0) maxLifetime = 100*3600;
536 else maxLifetime = 25*3600; /* regular users */
537 tentry.max_ticket_lifetime = htonl(maxLifetime);
539 code = ThreadBlock (tt, to, &tentry);
543 /* Put actual stub routines here */
545 afs_int32 KAM_CreateUser (call, aname, ainstance, ainitpw)
546 struct rx_call *call;
549 EncryptionKey ainitpw;
553 code = kamCreateUser (call, aname, ainstance, ainitpw);
554 osi_auditU (call, AFS_KAM_CrUserEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
559 afs_int32 kamCreateUser (call, aname, ainstance, ainitpw)
560 struct rx_call *call;
563 EncryptionKey ainitpw;
565 struct ubik_trans *tt;
566 afs_int32 caller; /* Disk offset of caller's entry */
568 COUNT_REQ (CreateUser);
569 if (!des_check_key_parity (&ainitpw) ||
570 des_is_weak_key (&ainitpw)) return KABADKEY;
571 if (!name_instance_legal (aname, ainstance)) return KABADNAME;
572 if (code = InitAuthServ( &tt, LOCKWRITE, this_op)) return code;
573 code = check_auth (call, tt, 1, &caller);
579 code = create_user (tt, aname, ainstance, &ainitpw, caller, KAFNORMAL);
585 code = ubik_EndTrans(tt);
586 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host, LOG_CRUSER);
590 afs_int32 KAA_ChangePassword (call, aname, ainstance, arequest, oanswer)
591 struct rx_call *call;
599 code = ChangePassWord (call, aname, ainstance, arequest, oanswer);
600 osi_auditU(call, AFS_KAA_ChPswdEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
604 afs_int32 ChangePassWord (call, aname, ainstance, arequest, oanswer)
605 struct rx_call *call;
611 struct ubik_trans *tt;
612 afs_int32 to; /* offset of block */
613 struct kaentry tentry;
614 struct ka_cpwRequest request; /* request after decryption */
615 char *answer; /* where answer is to be put */
616 int answer_len; /* length of answer packet */
617 afs_int32 kvno; /* requested key version number */
618 des_key_schedule user_schedule; /* key schedule for user's key */
619 Date request_time; /* time request originated */
621 COUNT_REQ (ChangePassword);
622 if (!name_instance_legal (aname, ainstance)) return KABADNAME;
623 if (strcmp (ainstance, KA_ADMIN_NAME) == 0) return KABADNAME;
624 if (code = InitAuthServ (&tt, LOCKWRITE, this_op)) return code;
626 code = FindBlock (tt, aname, ainstance, &to, &tentry);
630 if (to == 0) { /* no such user */
634 if (ntohl(tentry.flags) & KAFNOCPW)
635 { code = KABADCPW; goto abort; }
637 /* decrypt request w/ user password */
638 if (code = des_key_sched (&tentry.key, user_schedule))
639 es_Report ("In KAChangePassword: key_sched returned %d\n", code);
640 des_pcbc_encrypt (arequest->SeqBody, &request,
641 min (arequest->SeqLen, sizeof(request)),
642 user_schedule, &tentry.key, DECRYPT);
644 /* validate the request */
645 request_time = ntohl (request.time); /* reorder date */
646 kvno = ntohl(request.kvno);
647 if ((abs (request_time - time(0)) > KTC_TIME_UNCERTAINTY) ||
648 strncmp (request.label, KA_CPW_REQ_LABEL, sizeof(request.label)) ||
650 (kvno > MAXKAKVNO)) { /* these are reseved */
655 /* check to see if the new password was used before, or if there has
656 * not been sufficient time since the last password change
658 code = impose_reuse_limits(&request.newpw, &tentry);
663 /* Create the Answer Packet */
664 answer_len = sizeof(Date) + KA_LABELSIZE;
665 if (oanswer->MaxSeqLen < answer_len) {
666 code = KAANSWERTOOLONG;
669 oanswer->SeqLen = answer_len;
670 answer = oanswer->SeqBody;
671 request.time = htonl (request_time+1);
672 memcpy(answer, (char *)&request.time, sizeof(Date));
673 answer += sizeof(Date);
674 memcpy(answer, KA_CPW_ANS_LABEL, KA_LABELSIZE);
676 des_pcbc_encrypt (oanswer->SeqBody, oanswer->SeqBody, answer_len,
677 user_schedule, &tentry.key, ENCRYPT);
679 code = set_password (tt, aname, ainstance, &request.newpw, kvno, 0);
685 cheader.stats.cpws = htonl(ntohl(cheader.stats.cpws)+1);
686 code = kawrite(tt, DOFFSET(0, &cheader, &cheader.stats.cpws),
687 (char *) &cheader.stats.cpws, sizeof(afs_int32));
693 code = ubik_EndTrans(tt);
698 ubik_AbortTrans (tt);
703 impose_reuse_limits ( password, tentry )
704 EncryptionKey *password;
705 struct kaentry *tentry;
714 if (!tentry->pwsums[0] && npwSums > 1 && !tentry->pwsums[1])
715 return 0; /* password reuse limits not in effect */
717 code = get_time (&now,0,0);
718 if (code) return code;
720 if ((now - ntohl(tentry->change_password_time)) < MinHours*60*60)
723 if (!memcmp(password, &(tentry->key), sizeof(EncryptionKey)))
726 code = ka_KeyCheckSum ((char *)password, &newsum);
730 newsum = newsum & 0x000000ff;
731 for (i=0; i<npwSums; i++) {
732 if (newsum == tentry->pwsums[i])
741 set_password (tt, name, instance, password, kvno, caller)
742 struct ubik_trans *tt;
745 EncryptionKey *password;
749 afs_int32 to; /* offset of block */
750 struct kaentry tentry;
756 code = FindBlock (tt, name, instance, &to, &tentry);
757 if (code) return code;
758 if (to == 0) return KANOENT; /* no such user */
760 /* if password reuse limits in effect, set the checksums, the hard way */
761 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
762 /* do nothing, no limits */ ;
765 code = ka_KeyCheckSum ((char *)&(tentry.key), &newsum);
768 for (i=npwSums-1; i ; i--)
769 tentry.pwsums[i] = tentry.pwsums[i-1];
770 tentry.pwsums[0] = newsum & 0x000000ff;
774 if (special_name (name, instance)) { /* set key over rides key_version */
775 tentry.flags = htonl (ntohl(tentry.flags) | KAFSPECIAL);
776 if (code = ka_NewKey (tt, to, &tentry, password)) return(code);
779 memcpy(&tentry.key, password, sizeof(tentry.key));
781 kvno = ntohl(tentry.key_version);
782 if ((kvno < 1) || (kvno >= MAXKAKVNO))
787 tentry.key_version = htonl((afs_int32)kvno); /* requested key version */
792 /* no-write prevents recursive call to set_password by AuthCPW code. */
793 code = get_time (&now,0,0);
794 if (code) return code;
796 tentry.modification_time = htonl(now);
797 tentry.modification_id = htonl(caller);
800 tentry.change_password_time = htonl(now);
802 if (code = kawrite (tt, to, &tentry, sizeof(tentry))) return(KAIO);
806 afs_int32 KAM_SetPassword (call, aname, ainstance, akvno, apassword)
807 struct rx_call *call;
811 EncryptionKey apassword;
815 code = kamSetPassword (call, aname, ainstance, akvno, apassword);
816 osi_auditU (call, AFS_KAM_SetPswdEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
820 afs_int32 kamSetPassword (call, aname, ainstance, akvno, apassword)
821 struct rx_call *call;
825 EncryptionKey apassword;
827 struct ubik_trans *tt;
828 afs_int32 caller; /* Disk offset of caller's entry */
829 struct kaentry tentry;
831 COUNT_REQ (SetPassword);
832 if (akvno > MAXKAKVNO) return KABADARGUMENT;
833 if (!des_check_key_parity (&apassword) ||
834 des_is_weak_key (&apassword)) return KABADKEY;
836 if (!name_instance_legal (aname, ainstance)) return KABADNAME;
837 if (code = InitAuthServ (&tt, LOCKWRITE, this_op)) return code;
838 code = check_auth (call, tt, 0, &caller);
842 if (code = karead (tt, caller, &tentry, sizeof(tentry))) {
846 /* if the user is changing his own password or ADMIN then go ahead. */
847 if ((strcmp (tentry.userID.name, aname) == 0) &&
848 (strcmp (tentry.userID.instance, ainstance) == 0)) {
849 if (ntohl(tentry.flags) & KAFNOCPW)
852 code = impose_reuse_limits(&apassword, &tentry);
854 code = set_password (tt, aname, ainstance, &apassword, akvno, 0);
856 } else if (ntohl(tentry.flags) & KAFADMIN) {
857 code = set_password (tt, aname, ainstance, &apassword, akvno, caller);
859 else code = KANOAUTH;
860 if (code) goto abort;
862 code = ubik_EndTrans(tt);
863 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host, LOG_CHPASSWD);
872 static Date CoerseLifetime (start, end)
875 unsigned char kerberosV4Life;
876 kerberosV4Life = time_to_life (start, end);
877 end = life_to_time (start, kerberosV4Life);
881 static afs_int32 GetEndTime (start, reqEnd, expiration, caller, server, endP)
882 IN Date start; /* start time of ticket */
883 IN Date reqEnd; /* requested end time */
884 IN Date expiration; /* authorizing ticket's expiration */
885 IN struct kaentry *caller;
886 IN struct kaentry *server;
887 OUT Date *endP; /* actual end time */
893 if (ntohl(caller->flags) & KAFNOTGS)
894 return KABADUSER; /* no new tickets for this user */
895 if (expiration && (ntohl(server->flags) & KAFNOSEAL))
896 return KABADSERVER; /* can't be target of GetTicket req */
897 if (!expiration) expiration = NEVERDATE;
899 cExp = ntohl(caller->user_expiration);
900 sExp = ntohl(server->user_expiration);
901 if (cExp < start) return KAPWEXPIRED;
902 if (sExp < start) return KABADSERVER;
903 cLife = start + ntohl(caller->max_ticket_lifetime);
904 sLife = start + ntohl(server->max_ticket_lifetime);
905 end = umin (umin (reqEnd, expiration),
906 umin (umin (cLife,sLife),
908 end = CoerseLifetime (start, end);
915 (oanswer, challenge, ticket, ticketLen, sessionKey,
916 start, end, caller, server, cell, label)
921 struct ktc_encryptionKey *sessionKey;
923 struct kaentry *caller, *server;
928 struct ka_ticketAnswer *answer;
931 code = KAANSWERTOOLONG;
932 if (oanswer->MaxSeqLen < sizeof(struct ka_ticketAnswer) - 5*MAXKTCNAMELEN)
935 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
936 answer->challenge = htonl(challenge);
937 memcpy(&answer->sessionKey, sessionKey, sizeof(struct ktc_encryptionKey));
938 answer->startTime = htonl(start);
939 answer->endTime = htonl(end);
940 answer->kvno = server->key_version;
941 answer->ticketLen = htonl(ticketLen);
943 { char *ans = answer->name; /* pointer to variable part */
944 int rem; /* space remaining */
945 int len; /* macro temp. */
947 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
949 #define putstr(str) len = strlen (str)+1;\
950 if (rem < len) return code;\
952 ans += len; rem -= len
953 putstr (caller->userID.name);
954 putstr (caller->userID.instance);
956 putstr (server->userID.name);
957 putstr (server->userID.instance);
958 if (rem < ticketLen+KA_LABELSIZE) return code;
959 memcpy(ans, ticket, ticketLen);
961 if (label) memcpy(ans, label, KA_LABELSIZE);
962 else memset(ans, 0, KA_LABELSIZE);
964 oanswer->SeqLen = (ans - oanswer->SeqBody);
967 answer->cksum = htonl(cksum);
968 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
969 if (oanswer->SeqLen > oanswer->MaxSeqLen) return code;
973 /* This is used to get a ticket granting ticket or an admininstration ticket.
974 These two specific, built-in servers are special cases, which require the
975 client's key as an additional security precaution. The GetTicket operation
976 is normally disabled for these two principals. */
978 static afs_int32 Authenticate (version, call, aname, ainstance, start, end,
981 struct rx_call *call;
988 struct ubik_trans *tt;
989 afs_int32 to; /* offset of block */
991 struct kaentry server; /* entry for desired server */
992 struct ka_gettgtRequest request; /* request after decryption */
993 int tgt, adm; /* type of request */
994 char *sname; /* principal of server */
996 char ticket[MAXKTCTICKETLEN]; /* our copy of the ticket */
998 struct ktc_encryptionKey sessionKey; /* we have to invent a session key */
999 char *answer; /* where answer is to be put */
1000 int answer_len; /* length of answer packet */
1001 Date answer_time; /* 1+ request time in network order */
1002 afs_int32 temp; /* for htonl conversions */
1003 des_key_schedule user_schedule; /* key schedule for user's key */
1004 afs_int32 tgskvno; /* key version of service key */
1005 struct ktc_encryptionKey tgskey; /* service key for encrypting ticket */
1007 afs_uint32 pwexpires;
1008 afs_uint32 lasttime;
1010 COUNT_REQ (Authenticate);
1011 if (!name_instance_legal (aname, ainstance)) return KABADNAME;
1012 if (code = InitAuthServ (&tt, LOCKREAD, this_op)) return code;
1013 get_time(&now, 0, 0);
1015 sname = sinst = NULL;
1017 code = FindBlock (tt, aname, ainstance, &to, &tentry);
1021 if (to == 0) { /* no such user */
1027 /* have to check for locked before verifying the password, otherwise all
1028 * KALOCKED means is "yup, you guessed the password all right, now wait a
1029 * few minutes and we'll let you in"
1031 if (kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS],
1032 (afs_uint32) tentry.misc_auth_bytes[LOCKTIME] << 9)) {
1038 save_principal (authPrincipal, aname, ainstance, 0);
1040 /* decrypt request w/ user password */
1041 if (code = des_key_sched (&tentry.key, user_schedule))
1042 es_Report ("In KAAuthenticate: key_sched returned %d\n", code);
1043 des_pcbc_encrypt (arequest->SeqBody, &request,
1044 min (arequest->SeqLen, sizeof(request)),
1045 user_schedule, &tentry.key, DECRYPT);
1047 request.time = ntohl (request.time); /* reorder date */
1048 tgt = !strncmp (request.label, KA_GETTGT_REQ_LABEL, sizeof(request.label));
1049 adm = !strncmp (request.label, KA_GETADM_REQ_LABEL, sizeof(request.label));
1050 if (!(tgt || adm)) {
1051 kaux_inc(to,((unsigned char) tentry.misc_auth_bytes[LOCKTIME]) << 9);
1052 code = KABADREQUEST;
1055 else kaux_write(to, 0, 0); /* reset counters */
1058 if (! tentry.misc_auth_bytes[EXPIRES]) {
1059 /* 0 in the database means never, but 0 on the network means today */
1060 /* 255 on the network means "long time, maybe never" */
1064 pwexpires = tentry.misc_auth_bytes[EXPIRES];
1066 pwexpires = ntohl(tentry.change_password_time) + 24*60*60*pwexpires;
1067 if (adm) { /* provide a little slack for admin ticket */
1068 pwexpires += 30*24*60*60; /* 30 days */
1070 if ( pwexpires < now ) {
1075 pwexpires = (pwexpires - now)/ (24*60*60);
1076 if (pwexpires > 255)
1080 #endif /* EXPIREPW */
1082 if (abs (request.time - now) > KTC_TIME_UNCERTAINTY) {
1084 if (oanswer->MaxSeqLen < sizeof(afs_int32)) code = KAANSWERTOOLONG;
1085 else { /* return our time if possible */
1086 oanswer->SeqLen = sizeof(afs_int32);
1087 request.time = htonl(now);
1088 memcpy(oanswer->SeqBody, &request.time, sizeof(afs_int32));
1094 sname = (tgt ? KA_TGS_NAME : KA_ADMIN_NAME);
1095 sinst = (tgt ? lrealm : KA_ADMIN_INST);
1096 code = FindBlock (tt, sname, sinst, &to, &server);
1097 if (code) goto abort;
1098 if (to == 0) {code = KANOENT; goto abort; }
1100 tgskvno = ntohl(server.key_version);
1101 memcpy(&tgskey, &server.key, sizeof(tgskey));
1103 code = des_random_key (&sessionKey);
1109 code = GetEndTime (start, end, 0/*!GetTicket*/, &tentry, &server, &end);
1110 if (code) goto abort;
1112 code = tkt_MakeTicket (ticket, &ticketLen, &tgskey,
1113 aname, ainstance, "", start, end, &sessionKey,
1114 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
1116 if (code) goto abort;
1120 answer_len = ticketLen + sizeof(Date) +
1121 sizeof(struct ktc_encryptionKey) + 2*sizeof(afs_int32) + KA_LABELSIZE;
1122 answer_len = round_up_to_ebs(answer_len);
1123 if (answer_len > oanswer->MaxSeqLen) {
1124 code = KAANSWERTOOLONG;
1127 oanswer->SeqLen = answer_len;
1128 answer = oanswer->SeqBody;
1129 answer_time = htonl(request.time+1);
1130 memcpy(answer, (char *)&answer_time, sizeof(Date));
1131 answer += sizeof(Date);
1132 memcpy(answer, (char *)&sessionKey, sizeof(struct ktc_encryptionKey));
1133 answer += sizeof(struct ktc_encryptionKey);
1134 temp = htonl(tgskvno);
1135 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1136 answer += sizeof(afs_int32);
1137 temp = htonl(ticketLen);
1138 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1139 answer += sizeof(afs_int32);
1140 memcpy(answer, ticket, ticketLen);
1141 answer += ticketLen;
1142 memcpy(answer, (tgt ? KA_GETTGT_ANS_LABEL : KA_GETADM_ANS_LABEL), KA_LABELSIZE);
1146 code = PrepareTicketAnswer
1147 (oanswer, request.time+1, ticket, ticketLen, &sessionKey,
1148 start, end, &tentry, &server, "",
1149 (tgt ? KA_GETTGT_ANS_LABEL : KA_GETADM_ANS_LABEL));
1150 if (code) goto abort;
1152 if ((version == 2) && oanswer->SeqLen < oanswer->MaxSeqLen + sizeof(afs_int32)) {
1153 temp = pwexpires << 24; /* move it into the high byte */
1154 pwexpires = htonl(temp);
1156 memcpy((char * )oanswer->SeqBody + oanswer->SeqLen, &pwexpires, sizeof(afs_int32));
1157 oanswer->SeqLen += sizeof(afs_int32);
1158 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1159 if (oanswer->SeqLen > oanswer->MaxSeqLen) {
1160 code = KAANSWERTOOLONG;
1164 #endif /* EXPIREPW */
1168 code = KAINTERNALERROR;
1171 des_pcbc_encrypt (oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1172 user_schedule, &tentry.key, ENCRYPT);
1173 code = ubik_EndTrans(tt);
1174 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host, LOG_AUTHENTICATE);
1179 ubik_AbortTrans (tt);
1180 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host, LOG_AUTHFAILED);
1184 afs_int32 KAA_Authenticate_old (call, aname, ainstance, start, end,
1186 struct rx_call *call;
1195 IOMGR_Sleep (1); /* discourage use of this mechanism */
1196 code = Authenticate (0, call, aname, ainstance, start, end,
1198 osi_auditU(call, AFS_KAA_AuthOEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
1203 afs_int32 KAA_Authenticate (call, aname, ainstance, start, end, arequest, oanswer)
1204 struct rx_call *call;
1213 code = Authenticate (1, call, aname, ainstance, start, end,
1215 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
1220 afs_int32 KAA_AuthenticateV2 (call, aname, ainstance, start, end, arequest, oanswer)
1221 struct rx_call *call;
1230 code = Authenticate (2, call, aname, ainstance, start, end,
1232 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
1237 afs_int32 KAM_SetFields (call, aname, ainstance, aflags,
1238 aexpiration, alifetime, amaxAssociates, misc_auth_bytes, spare2)
1239 struct rx_call *call;
1244 afs_int32 alifetime;
1245 afs_int32 amaxAssociates;
1246 afs_uint32 misc_auth_bytes; /* 4 bytes, each 0 means unspecified*/
1251 code = kamSetFields (call, aname, ainstance, aflags,
1252 aexpiration, alifetime, amaxAssociates, misc_auth_bytes, spare2);
1253 osi_auditU (call, AFS_KAM_SetFldEvent, code, AUD_STR, aname,
1256 AUD_DATE, aexpiration,
1257 AUD_LONG, alifetime,
1258 AUD_LONG, amaxAssociates,
1263 afs_int32 kamSetFields (call, aname, ainstance, aflags,
1264 aexpiration, alifetime, amaxAssociates, misc_auth_bytes, spare2)
1265 struct rx_call *call;
1270 afs_int32 alifetime;
1271 afs_int32 amaxAssociates;
1272 afs_uint32 misc_auth_bytes; /* 4 bytes, each 0 means unspecified*/
1276 struct ubik_trans *tt;
1278 afs_int32 tentry_offset; /* offset of entry */
1279 struct kaentry tentry;
1280 unsigned char newvals[4], oldvals[4];
1283 COUNT_REQ (SetFields);
1286 return KABADARGUMENT; /* not supported yet... */
1288 /* make sure we're supposed to do something */
1289 if (!(aflags || aexpiration || alifetime || (amaxAssociates >= 0) ||
1290 misc_auth_bytes ) ||
1291 ((aflags & ~KAFNORMAL) & ~KAF_SETTABLE_FLAGS))
1292 return KABADARGUMENT; /* arguments no good */
1293 if (!name_instance_legal (aname, ainstance)) return KABADNAME;
1294 if (code = InitAuthServ (&tt, LOCKWRITE, this_op)) return code;
1295 code = check_auth (call, tt, 1, &caller);
1300 code = FindBlock (tt, aname, ainstance, &tentry_offset, &tentry);
1301 if (code) goto abort;
1302 if (tentry_offset == 0) { /* no such user */
1306 if ((ntohl(tentry.flags) & KAFNORMAL) == 0) return KAINTERNALERROR;
1308 /* Keep track of the total number of admin accounts. This way we can
1309 update database without any admin privilege initially */
1310 if ((aflags & KAFADMIN) != (ntohl(tentry.flags) & KAFADMIN)) {
1311 /* if admin state is changing */
1313 if (ntohl(tentry.flags) & KAFADMIN) delta = -1;
1315 if (code = update_admin_count (tt, delta)) goto abort;
1318 htonl((ntohl(tentry.flags) & ~KAF_SETTABLE_FLAGS) | aflags);
1320 if (code = get_time (&now, tt, 1)) goto abort;
1322 tentry.user_expiration = htonl(aexpiration);
1323 if (!ntohl(tentry.change_password_time)) {
1324 tentry.change_password_time = htonl(now);
1327 if (alifetime) tentry.max_ticket_lifetime = htonl(alifetime);
1329 #ifndef NOPWCONTROLS
1331 * We've packed a bunch of bytes into a long for backward compatibility.
1332 * These include password expiration time, and some failed login limits
1333 * counters. Now let's unpack them and stick them into the
1334 * kaentry struct. All the bytes have values in the range
1335 * 1..255, else they were not specified in the interface, and are
1337 * In the case of password expiration times, 1 means password never
1338 * expires (==>0), 2 means password only lives for one day (==>1),
1341 if (misc_auth_bytes) {
1342 unpack_long(misc_auth_bytes, newvals);
1343 if (newvals[EXPIRES]) {
1344 tentry.misc_auth_bytes[EXPIRES] = newvals[EXPIRES] - 1;
1347 if (newvals[REUSEFLAGS]) {
1348 if (newvals[REUSEFLAGS] & KA_REUSEPW)
1349 memset(tentry.pwsums, 0, KA_NPWSUMS);
1350 else if ((newvals[REUSEFLAGS] & KA_NOREUSEPW) && !tentry.pwsums[0])
1351 tentry.pwsums[0] = 0xff;
1354 if (newvals[ATTEMPTS]) {
1355 tentry.misc_auth_bytes[ATTEMPTS] = newvals[ATTEMPTS] - 1;
1357 if (newvals[LOCKTIME]) {
1358 tentry.misc_auth_bytes[LOCKTIME] = newvals[LOCKTIME] - 1;
1361 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1364 #endif /* NOPWCONTROLS */
1366 if (amaxAssociates >= 0) {
1367 if ((ntohl(tentry.flags) & KAFASSOC) ||
1368 (ntohl(tentry.flags) & KAFSPECIAL)) return KAASSOCUSER;
1369 if (((ntohl(tentry.flags) & KAFASSOCROOT) == 0) &&
1370 (amaxAssociates > 0)) /* convert normal user to assoc root */
1371 tentry.flags = htonl(ntohl(tentry.flags) | KAFASSOCROOT);
1372 tentry.misc.assocRoot.maxAssociates = htonl(amaxAssociates);
1375 tentry.modification_time = htonl(now);
1376 tentry.modification_id = htonl(caller);
1377 code = kawrite (tt, tentry_offset, &tentry, sizeof(tentry));
1378 if (code) goto abort;
1380 code = ubik_EndTrans(tt);
1381 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host, LOG_SETFIELDS);
1386 ubik_AbortTrans(tt);
1392 afs_int32 KAM_DeleteUser(call, aname, ainstance)
1393 struct rx_call *call;
1399 code = kamDeleteUser(call, aname, ainstance);
1400 osi_auditU (call, AFS_KAM_DelUserEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
1404 afs_int32 kamDeleteUser(call, aname, ainstance)
1405 struct rx_call *call;
1408 { register int code;
1409 struct ubik_trans *tt;
1412 struct kaentry tentry;
1414 afs_uint32 locktime;
1416 COUNT_REQ (DeleteUser);
1417 if (!name_instance_legal (aname, ainstance)) return KABADNAME;
1418 if (code = InitAuthServ (&tt, LOCKWRITE, this_op)) return code;
1419 code = check_auth (call, tt, 1, &caller);
1423 ubik_AbortTrans(tt);
1427 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1428 if (code) goto abort;
1429 if (to == 0) { /* name not found */
1434 kaux_read( to, &nfailures, &locktime );
1435 if (nfailures || locktime)
1436 kaux_write( to, 0, 0 ); /* zero failure counters at this offset */
1438 /* track all AuthServer identities */
1439 if (special_name (aname, ainstance))
1440 if (code = ka_DelKey (tt, to, &tentry)) goto abort;
1442 if (ntohl(tentry.flags) & KAFADMIN) /* keep admin count up-to-date */
1443 if (code = update_admin_count (tt, -1)) goto abort;
1445 if ((code = UnthreadBlock (tt, &tentry)) ||
1446 (code = FreeBlock (tt, to)) ||
1447 (code = get_time (0, tt, 1)) /* update randomness */
1450 code = ubik_EndTrans(tt);
1451 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host, LOG_DELUSER);
1455 /* we set a bit in here which indicates that the user's limit of
1456 * authentication failures has been exceeded. If that bit is not set,
1457 * kas can take it on faith that the user ID is not locked. If that
1458 * bit is set, kas has to check all the servers to find one who will
1459 * report that the ID is not locked, or else to find out when the ID
1462 afs_int32 KAM_GetEntry (call, aname, ainstance, aversion, aentry)
1463 struct rx_call *call;
1466 afs_int32 aversion; /* major version assumed by caller */
1467 kaentryinfo *aentry; /* entry data copied here */
1471 code = kamGetEntry (call, aname, ainstance, aversion, aentry);
1472 osi_auditU (call, AFS_KAM_GetEntEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
1476 afs_int32 kamGetEntry (call, aname, ainstance, aversion, aentry)
1477 struct rx_call *call;
1480 afs_int32 aversion; /* major version assumed by caller */
1481 kaentryinfo *aentry; /* entry data copied here */
1482 { register afs_int32 code;
1483 struct ubik_trans *tt;
1484 afs_int32 callerIndex;
1485 struct kaentry caller;
1488 struct kaentry tentry;
1489 rxkad_level enc_level = rxkad_clear;
1490 int callerIsAdmin = 0;
1492 COUNT_REQ (GetEntry);
1493 if (aversion != KAMAJORVERSION) return KAOLDINTERFACE;
1494 if (!name_instance_legal (aname, ainstance)) return KABADNAME;
1495 if (code = InitAuthServ (&tt, LOCKREAD, this_op)) return code;
1496 code = check_auth (call, tt, 0, &callerIndex);
1500 if (noAuthenticationRequired) {
1502 else if (!callerIndex) {
1507 if (code = karead (tt, callerIndex, &caller, sizeof(caller))) {
1511 /* if the user is checking his own entry or ADMIN then go ahead. */
1512 callerIsAdmin = (ntohl(caller.flags) & KAFADMIN);
1514 if (strcmp (caller.userID.name, aname) != 0 && !callerIsAdmin) {
1520 code = FindBlock (tt, aname, ainstance, &to, &tentry);
1521 if (code) goto abort;
1522 if (to == 0) { /* entry not found */
1527 get_time (0,0,0); /* generate random update */
1529 memset(aentry, 0, sizeof(*aentry));
1530 aentry->minor_version = KAMINORVERSION;
1531 aentry->flags = ntohl(tentry.flags);
1532 aentry->user_expiration = ntohl(tentry.user_expiration);
1533 aentry->modification_time = ntohl(tentry.modification_time);
1534 aentry->change_password_time = ntohl(tentry.change_password_time);
1535 aentry->max_ticket_lifetime = ntohl(tentry.max_ticket_lifetime);
1536 aentry->key_version = ntohl(tentry.key_version);
1538 temp = (unsigned char) tentry.misc_auth_bytes[LOCKTIME] ;
1540 if (kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp))
1541 tentry.misc_auth_bytes[REUSEFLAGS] |= KA_ISLOCKED; /* saves an RPC */
1543 temp = pack_long(tentry.misc_auth_bytes);
1544 aentry->misc_auth_bytes = temp;
1546 * only return user's key if security disabled or if admin and
1547 * we have an encrypted connection to the user
1549 rxkad_GetServerInfo(call->conn, &enc_level, 0, 0, 0, 0, 0);
1550 if ((noAuthenticationRequired) ||
1551 (callerIsAdmin && enc_level == rxkad_crypt))
1552 memcpy(&aentry->key, &tentry.key, sizeof(struct ktc_encryptionKey));
1553 else memset(&aentry->key, 0, sizeof(aentry->key));
1554 code = ka_KeyCheckSum ((char *)&tentry.key, &aentry->keyCheckSum);
1555 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
1556 aentry->reserved3 = 0x12340000;
1558 aentry->reserved3 = 0x12340001;
1561 /* Now get entry of user who last modified this entry */
1562 if (ntohl(tentry.modification_id)) {
1563 temp = ntohl (tentry.modification_id);
1564 code = karead (tt, temp, &tentry, sizeof(tentry));
1569 aentry->modification_user = tentry.userID;
1572 strcpy (aentry->modification_user.name, "<none>");
1573 strcpy (aentry->modification_user.instance, "\0");
1575 code = ubik_EndTrans (tt);
1580 ubik_AbortTrans(tt);
1584 afs_int32 KAM_ListEntry (call, previous_index, index, count, name)
1585 struct rx_call *call;
1586 afs_int32 previous_index; /* last entry ret'd or 0 for first */
1587 afs_int32 *index; /* index of this entry */
1588 afs_int32 *count; /* total entries in database */
1589 kaident *name; /* name & instance of this entry */
1593 code = kamListEntry (call, previous_index, index, count, name);
1594 osi_auditU (call, AFS_KAM_LstEntEvent, code, AUD_LONG, *index, AUD_END);
1599 afs_int32 kamListEntry (call, previous_index, index, count, name)
1600 struct rx_call *call;
1601 afs_int32 previous_index; /* last entry ret'd or 0 for first */
1602 afs_int32 *index; /* index of this entry */
1603 afs_int32 *count; /* total entries in database */
1604 kaident *name; /* name & instance of this entry */
1605 { register int code;
1606 struct ubik_trans *tt;
1608 struct kaentry tentry;
1610 COUNT_REQ (ListEntry);
1611 if (code = InitAuthServ (&tt, LOCKREAD, this_op)) return code;
1612 code = check_auth (call, tt, 1, &caller);
1617 *index = NextBlock (tt, previous_index, &tentry, count);
1623 if (*index) { /* return name & inst of this entry */
1624 strncpy (name->name, tentry.userID.name, sizeof(name->name));
1625 strncpy (name->instance, tentry.userID.instance,
1626 sizeof(name->instance));
1629 strcpy (name->name, "\0");
1630 strcpy (name->instance, "\0");
1632 code = ubik_EndTrans(tt);
1637 ubik_AbortTrans(tt);
1641 static afs_int32 GetTicket (version, call, kvno, authDomain, aticket,
1642 sname, sinstance, atimes, oanswer)
1644 struct rx_call *call;
1650 ka_CBS *atimes; /* encrypted start & end time */
1654 struct ubik_trans *tt;
1655 struct ktc_encryptionKey tgskey;
1656 des_key_schedule schedule;
1658 char name[MAXKTCNAMELEN];
1659 char instance[MAXKTCNAMELEN];
1660 char cell[MAXKTCNAMELEN];
1662 struct kaentry caller;
1663 struct kaentry server;
1664 struct ktc_encryptionKey authSessionKey;
1665 struct ktc_encryptionKey sessionKey;
1667 char ticket[MAXKTCTICKETLEN];
1673 struct ka_getTicketTimes times;
1674 struct ka_getTicketAnswer *answer;
1676 COUNT_REQ (GetTicket);
1677 if (!name_instance_legal (sname, sinstance)) return KABADNAME;
1678 if (atimes->SeqLen != sizeof(times)) return KABADARGUMENT;
1679 if (code = InitAuthServ (&tt, LOCKREAD, this_op)) return code;
1681 export = import = 0;
1682 if ((strcmp (sname, KA_TGS_NAME) == 0) && (strcmp(sinstance, lrealm) != 0))
1684 if ((strlen(authDomain) > 0) && (strcmp (authDomain, lrealm) != 0))
1687 if (strlen(authDomain) == 0) authDomain = lrealm;
1688 code = ka_LookupKvno (tt, KA_TGS_NAME, authDomain, kvno, &tgskey);
1692 code = tkt_DecodeTicket (aticket->SeqBody, aticket->SeqLen, &tgskey,
1693 name, instance, cell,
1694 &authSessionKey, &host, &start, &expiration);
1695 if (code) {code = KANOAUTH; goto abort;}
1696 save_principal (tgsPrincipal, name, instance, cell);
1698 if (code = get_time (&now, 0, 0)) goto abort;
1700 code = tkt_CheckTimes (start, expiration, now);
1702 if (code == -1) code = RXKADEXPIRED;
1703 else code = KANOAUTH;
1706 code = des_key_sched (&authSessionKey, schedule);
1707 if (code) {code = KANOAUTH; goto abort;}
1708 celllen = strlen (cell);
1709 if (import && (celllen == 0)) {code = KABADTICKET; goto abort;}
1710 if (export && (celllen == 0)) strcpy (cell, lrealm);
1712 des_ecb_encrypt (atimes->SeqBody, ×, schedule, DECRYPT);
1713 times.start = ntohl(times.start);
1714 times.end = ntohl(times.end);
1715 code = tkt_CheckTimes (times.start, times.end, now);
1716 if (code < 0) {code = KABADREQUEST; goto abort;}
1719 strcpy (caller.userID.name, name);
1720 strcpy (caller.userID.instance, instance);
1721 caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
1722 caller.flags = htonl(KAFNORMAL);
1723 caller.user_expiration = htonl(NEVERDATE);
1726 code = FindBlock(tt, name, instance, &to, &caller);
1727 if (code) goto abort;
1729 ka_PrintUserID ("GetTicket: User ", name, instance, " unknown.\n");
1735 /* get server's entry */
1736 code = FindBlock (tt, sname, sinstance, &to, &server);
1737 if (code) goto abort;
1738 if (to == 0) { /* entry not found */
1739 ka_PrintUserID ("GetTicket: Server ", sname, sinstance, " unknown.\n");
1743 save_principal (tgsServerPrincipal, sname, sinstance, 0);
1745 code = des_random_key (&sessionKey);
1746 if (code) {code = KANOKEYS; goto abort;}
1748 code = GetEndTime (times.start, times.end, expiration, &caller, &server,
1750 if (code) goto abort;
1752 code = tkt_MakeTicket (ticket, &ticketLen, &server.key,
1753 caller.userID.name, caller.userID.instance, cell,
1754 times.start, end, &sessionKey,
1755 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
1756 server.userID.name, server.userID.instance);
1757 if (code) goto abort;
1761 code = KAANSWERTOOLONG;
1762 if (oanswer->MaxSeqLen <
1763 sizeof(struct ka_getTicketAnswer) - 5*MAXKTCNAMELEN) goto abort;
1765 answer = (struct ka_getTicketAnswer *)oanswer->SeqBody;
1766 memcpy(&answer->sessionKey, &sessionKey, sizeof(struct ktc_encryptionKey));
1767 answer->startTime = htonl(times.start);
1768 answer->endTime = htonl(end);
1769 answer->kvno = server.key_version;
1770 answer->ticketLen = htonl(ticketLen);
1772 { char *ans = answer->name; /* ptr to variable part of answer */
1775 /* space remaining */
1776 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1778 #define putstr(str) len = strlen (str)+1;\
1779 if (rem < len) goto abort;\
1781 ans += len; rem -= len
1788 if (rem < ticketLen) goto abort;
1789 memcpy(ans, ticket, ticketLen);
1790 oanswer->SeqLen = (ans - oanswer->SeqBody) + ticketLen;
1792 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1795 code = PrepareTicketAnswer
1796 (oanswer, /*challenge*/0, ticket, ticketLen, &sessionKey,
1797 times.start, end, &caller, &server, cell,
1798 KA_GETTICKET_ANS_LABEL);
1799 if (code) goto abort;
1802 code = KAINTERNALERROR;
1805 des_pcbc_encrypt (oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1806 schedule, &authSessionKey, ENCRYPT);
1807 code = ubik_EndTrans (tt);
1808 KALOG(name, instance, sname, sinstance, (import ? authDomain : NULL), call->conn->peer->host, LOG_GETTICKET);
1813 ubik_AbortTrans(tt);
1817 afs_int32 KAT_GetTicket_old (call, kvno, authDomain, aticket,
1818 sname, sinstance, atimes, oanswer)
1819 struct rx_call *call;
1825 ka_CBS *atimes; /* encrypted start & end time */
1830 sleep(1); /* strongly discourage this */
1831 code = GetTicket (0, call, kvno, authDomain, aticket,
1832 sname, sinstance, atimes, oanswer);
1834 osi_auditU( call, AFS_KAT_GetTicketOEvent, code, AUD_STR, sname, AUD_STR, sinstance, AUD_END);
1838 afs_int32 KAT_GetTicket (call, kvno, authDomain, aticket,
1839 sname, sinstance, atimes, oanswer)
1840 struct rx_call *call;
1846 ka_CBS *atimes; /* encrypted start & end time */
1851 code = GetTicket (1, call, kvno, authDomain, aticket,
1852 sname, sinstance, atimes, oanswer);
1853 osi_auditU( call, AFS_KAT_GetTicketEvent, code, AUD_STR, sname, AUD_STR, sinstance, AUD_END);
1857 afs_int32 KAM_GetStats (call, version, admin_accounts, statics, dynamics)
1858 struct rx_call *call;
1860 afs_int32 *admin_accounts;
1866 code = kamGetStats (call, version, admin_accounts, statics, dynamics);
1867 osi_auditU (call, AFS_KAM_GetStatEvent, code, AUD_END);
1871 afs_int32 kamGetStats (call, version, admin_accounts, statics, dynamics)
1872 struct rx_call *call;
1874 afs_int32 *admin_accounts;
1878 struct ubik_trans *tt;
1881 COUNT_REQ (GetStats);
1882 if (version != KAMAJORVERSION) return KAOLDINTERFACE;
1883 if (code = InitAuthServ( &tt, LOCKREAD, this_op)) return code;
1884 code = check_auth (call, tt, 1, &caller);
1887 ubik_AbortTrans(tt);
1891 *admin_accounts = ntohl(cheader.admin_accounts);
1892 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
1893 /* these are stored in network byte order and must be copied */
1894 statics->allocs = ntohl(cheader.stats.allocs);
1895 statics->frees = ntohl(cheader.stats.frees);
1896 statics->cpws = ntohl(cheader.stats.cpws);
1897 #if KADBVERSION != 5
1898 check that the statistics command copies all the fields
1901 memcpy((char *)dynamics, (char *)&dynamic_statistics, sizeof(kadstats));
1902 statics->minor_version = KAMINORVERSION;
1903 dynamics->minor_version = KAMINORVERSION;
1908 for (i=0; i<HASHSIZE; i++)
1909 if (cheader.nameHash[i]) used++;
1910 dynamics->hashTableUtilization = (used*10000 + HASHSIZE/2)/HASHSIZE;
1913 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
1915 /* Unfortunately, although aix_22 has a minimal compatibility
1916 * method of getting to some rusage fields (i.e. stime &
1917 * utime), the version that we have doesn't even have the
1918 * related include files needed for the aix vtimes() call; so
1919 * ignore this for aix till v3.1... */
1920 getrusage(RUSAGE_SELF, &ru);
1921 #if (KAMAJORVERSION>5)
1922 memcpy(&dynamics->utime, &ru.ru_utime, sizeof(struct katimeval));
1923 memcpy(&dynamics->stime, &ru.ru_stime, sizeof(struct katimeval));
1924 dynamics->dataSize = ru.ru_idrss;
1925 dynamics->stackSize = ru.ru_isrss;
1926 dynamics->pageFailts = ru.ru_majflt;
1928 dynamics->string_checks =
1929 (afs_int32)(1000.0 *
1930 ((ru.ru_utime.tv_sec + ru.ru_utime.tv_usec / 1000000.0) +
1931 (ru.ru_stime.tv_sec + ru.ru_stime.tv_usec / 1000000.0)));
1933 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
1936 code = ubik_EndTrans (tt);
1940 afs_int32 KAM_GetPassword (call, name, password)
1941 struct rx_call *call;
1943 EncryptionKey *password;
1947 code = kamGetPassword (call, name, password);
1948 osi_auditU (call, AFS_KAM_GetPswdEvent, code, AUD_STR, name, AUD_END);
1952 afs_int32 kamGetPassword (call, name, password)
1953 struct rx_call *call;
1955 EncryptionKey *password;
1956 { int code = KANOAUTH;
1958 struct ubik_trans *tt;
1959 struct kaentry tentry;
1961 COUNT_REQ (GetPassword);
1963 if (!name_instance_legal (name, "")) return KABADNAME;
1964 /* only requests from this host work */
1965 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))) != htonl(INADDR_LOOPBACK))
1967 if (code = InitAuthServ (&tt, LOCKREAD, this_op)) return code;
1969 /* this isn't likely to be used because of string to key problems, so since
1970 this is a temporary thing anyway, we'll use it here. */
1971 { extern char udpAuthPrincipal[256];
1972 save_principal (udpAuthPrincipal, name, 0, 0);
1974 get_time (0,0,0); /* update random value */
1975 code = FindBlock(tt, name, "", &to, &tentry);
1976 if (code) goto abort;
1981 ubik_AbortTrans(tt);
1985 memcpy(password, &tentry.key, sizeof (*password));
1986 code = ubik_EndTrans (tt);
1991 afs_int32 KAM_GetRandomKey (call, key)
1992 struct rx_call *call;
1997 code = kamGetRandomKey (call, key);
1998 osi_auditU (call, AFS_KAM_GetRndKeyEvent, code, AUD_END);
2002 afs_int32 kamGetRandomKey (call, key)
2003 struct rx_call *call;
2007 COUNT_REQ (GetRandomKey);
2008 if (code = AwaitInitialization()) return code;
2009 code = des_random_key (key);
2010 if (code) return KANOKEYS;
2014 afs_int32 KAM_Debug (call, version, checkDB, info)
2015 struct rx_call *call;
2017 int checkDB; /* start a transaction to examine DB */
2018 struct ka_debugInfo *info;
2022 code = kamDebug (call, version, checkDB, info);
2023 osi_auditU (call, AFS_KAM_DbgEvent, code, AUD_END);
2027 afs_int32 kamDebug (call, version, checkDB, info)
2028 struct rx_call *call;
2030 int checkDB; /* start a transaction to examine DB */
2031 struct ka_debugInfo *info;
2033 /* COUNT_REQ (Debug); */
2034 if (sizeof(struct kaentry) != sizeof(struct kaOldKeys))
2035 return KAINTERNALERROR;
2036 if (sizeof(struct ka_cpwRequest) % 8) return KAINTERNALERROR;
2037 if (version != KAMAJORVERSION) return KAOLDINTERFACE;
2039 memset(info, 0, sizeof(*info));
2041 info->minorVersion = KAMINORVERSION;
2042 info->host = dynamic_statistics.host;
2043 info->startTime = dynamic_statistics.start_time;
2045 #if (KAMAJORVERSION>5)
2051 info->noAuth = noAuthenticationRequired;
2053 info->dbVersion = ntohl(cheader.version);
2054 info->dbFreePtr = ntohl(cheader.freePtr);
2055 info->dbEofPtr = ntohl(cheader.eofPtr);
2056 info->dbKvnoPtr = ntohl(cheader.kvnoPtr);
2057 info->dbSpecialKeysVersion = ntohl(cheader.specialKeysVersion);
2059 info->dbHeaderRead = cheaderReadTime;
2060 info->lastTrans = lastTrans;
2062 lastOperation = "(Not Available)";
2063 strncpy (info->lastOperation, lastOperation, sizeof(info->lastOperation));
2064 strncpy (info->lastAuth, authPrincipal, sizeof(info->lastAuth));
2065 strncpy (info->lastTGS, tgsPrincipal, sizeof(info->lastTGS));
2066 strncpy (info->lastAdmin, adminPrincipal, sizeof(info->lastAdmin));
2067 strncpy (info->lastTGSServer, tgsServerPrincipal,
2068 sizeof(info->lastTGSServer));
2069 { extern char udpAuthPrincipal[256];
2070 extern char udptgsPrincipal[256];
2071 extern char udptgsServerPrincipal[256];
2073 strncpy (info->lastUAuth, udpAuthPrincipal, sizeof(info->lastUAuth));
2074 strncpy (info->lastUTGS, udptgsPrincipal, sizeof(info->lastUTGS));
2075 strncpy (info->lastUTGSServer, udptgsServerPrincipal,
2076 sizeof(info->lastUTGSServer));
2078 info->nextAutoCPW = nextAutoCPWTime;
2079 info->updatesRemaining = autoCPWUpdates - totalUpdates;
2080 ka_debugKeyCache (info);
2084 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2085 * a tacked-on-the-side data file.
2086 * prob'ly ought to check the noauth flag.
2088 #define ABORTIF(A) {if(code= A){goto abort;}}
2089 afs_int32 KAM_Unlock (call, aname, ainstance, spare1, spare2, spare3, spare4)
2090 struct rx_call *call;
2093 afs_int32 spare1, spare2, spare3, spare4;
2096 struct ubik_trans *tt;
2099 struct kaentry tentry;
2102 if (!name_instance_legal (aname, ainstance)) {
2106 if (code = InitAuthServ (&tt, LOCKREAD, this_op))
2109 ABORTIF( check_auth (call, tt, 1, &caller) );
2110 ABORTIF( FindBlock(tt, aname, ainstance, &to, &tentry) );
2111 ABORTIF( (to == 0 ? KANOENT : 0) );
2113 kaux_write( to, 0, 0 ); /* zero failure counters at this offset */
2115 code = ubik_EndTrans(tt);
2116 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host, LOG_UNLOCK);
2121 ubik_AbortTrans(tt);
2124 osi_auditU(call, UnlockEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);
2128 afs_int32 KAM_LockStatus (call, aname, ainstance, lockeduntil, spare1, spare2, spare3, spare4)
2129 struct rx_call *call;
2132 afs_int32 *lockeduntil;
2133 afs_int32 spare1, spare2, spare3, spare4;
2136 struct ubik_trans *tt;
2137 afs_int32 callerIndex;
2139 struct kaentry caller;
2140 struct kaentry tentry;
2143 COUNT_REQ (LockStatus);
2145 if (!name_instance_legal (aname, ainstance)) {
2149 if (code = InitAuthServ (&tt, LOCKREAD, this_op))
2152 if (code = check_auth (call, tt, 0, &callerIndex) )
2155 if (!noAuthenticationRequired && callerIndex) {
2156 if (karead (tt, callerIndex, &caller, sizeof(caller))) {
2160 /* if the user is checking his own entry or ADMIN then go ahead. */
2161 if ((strcmp (caller.userID.name, aname) != 0) &&
2162 !(ntohl(caller.flags) & KAFADMIN)) {
2168 if (code = FindBlock(tt, aname, ainstance, &to, &tentry) )
2176 temp = (unsigned char) tentry.misc_auth_bytes[LOCKTIME] ;
2178 *lockeduntil = kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS],
2181 code = ubik_EndTrans(tt);
2186 ubik_AbortTrans(tt);
2187 osi_auditU(call, LockStatusEvent, code, AUD_STR, aname, AUD_STR, ainstance, AUD_END);