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>
17 #include <sys/types.h>
20 #include <afs/afsutil.h>
22 #include <sys/resource.h>
35 #include <netinet/in.h>
39 #include <des_prototypes.h>
40 #include <afs/cellconfig.h>
42 #include <afs/com_err.h>
47 #include "kauth_internal.h"
48 #include "afs/audit.h"
50 extern struct ubik_dbase *KA_dbase;
51 struct kaheader cheader;
52 Date cheaderReadTime; /* time cheader last read in */
53 extern struct afsconf_dir *KA_conf; /* for getting cell info */
55 afs_int32 kamCreateUser(struct rx_call *call, char *aname, char *ainstance,
56 EncryptionKey ainitpw);
57 afs_int32 ChangePassWord(struct rx_call *call, char *aname, char *ainstance,
58 ka_CBS *arequest, ka_BBS *oanswer);
59 afs_int32 kamSetPassword(struct rx_call *call, char *aname, char *ainstance,
60 afs_int32 akvno, EncryptionKey apassword);
61 afs_int32 kamSetFields(struct rx_call *call, char *aname, char *ainstance,
62 afs_int32 aflags, Date aexpiration,
63 afs_int32 alifetime, afs_int32 amaxAssociates,
64 afs_uint32 misc_auth_bytes, afs_int32 spare2);
65 afs_int32 kamDeleteUser(struct rx_call *call, char *aname, char *ainstance);
66 afs_int32 kamGetEntry(struct rx_call *call, char *aname, char *ainstance,
67 afs_int32 aversion, kaentryinfo *aentry);
68 afs_int32 kamListEntry(struct rx_call *call, afs_int32 previous_index,
69 afs_int32 *index, afs_int32 *count, kaident *name);
70 afs_int32 kamGetStats(struct rx_call *call, afs_int32 version,
71 afs_int32 *admin_accounts, kasstats *statics,
73 afs_int32 kamGetPassword(struct rx_call *call, char *name,
74 EncryptionKey *password);
75 afs_int32 kamGetRandomKey(struct rx_call *call, EncryptionKey *key);
76 afs_int32 kamDebug(struct rx_call *call, afs_int32 version,
77 int checkDB, struct ka_debugInfo *info);
79 char lrealm[MAXKTCREALMLEN];
81 #ifndef EXPIREPW /* password expiration default yes */
85 #ifndef AUTOCPWINTERVAL
86 #define AUTOCPWINTERVAL (24*3600)
88 #ifndef AUTOCPWUPDATES
89 #define AUTOCPWUPDATES 128
94 static afs_int32 autoCPWInterval;
95 static afs_int32 autoCPWUpdates;
97 static afs_int32 set_password(struct ubik_trans *tt, char *name,
98 char *instance, EncryptionKey *password,
99 afs_int32 kvno, afs_int32 caller);
101 extern afs_int32 InitAuthServ(struct ubik_trans **tt, int lock,
103 static afs_int32 impose_reuse_limits(EncryptionKey *password,
104 struct kaentry *tentry);
105 static int create_user(struct ubik_trans *tt, char *name, char *instance,
106 EncryptionKey *key, afs_int32 caller,
109 /* This routine is called whenever an RPC interface needs the time. It uses
110 the current time to randomize a 128 bit value that is used to change the
111 AuthServer Admin and TGS keys automatically. */
113 static Date nextAutoCPWTime = 0;
114 static afs_int32 totalUpdates = 0;
116 /* This routine is ostensibly to get the current time, but basically its job is
117 to periodically update a random number. It also periodically updates the
118 keys for the builtin servers. This is why it needs a transaction pointer
119 and returns an error code. If the caller is in a read transaction, the tt
120 ptr should be zero and the return code need not be checked. */
123 get_time(Date *timeP,
124 struct ubik_trans *tt, /* tt != 0: a write transaction */
125 int admin) /* the caller is an admin user */
127 /* random value used to change Admin & TGS keys, this is at risk during
128 * multi-threaded operation, but I think the consequences are fairly
130 static afs_uint32 random_value[4];
133 unsigned int bit, nbit;
137 gettimeofday(&time, 0);
138 bit = (random_value[3] >> 31) & 1; /* get high bit of high word */
139 for (i = 0; i < 4; i++) {
140 nbit = random_value[i] >> 31;
141 random_value[i] = (random_value[i] << 1) + bit;
144 /* get 60ths from usec. This is all the real randomness there is. */
145 random_value[0] += time.tv_usec / 16667;
147 if (nextAutoCPWTime == 0) { /* initialize things */
148 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
149 memcpy(&random_value[0], &time, 8);
150 memcpy(&random_value[2], &time, 8);
153 if ((++totalUpdates >= autoCPWUpdates) && tt && /* a write transaction */
154 ((admin && (time.tv_sec >= nextAutoCPWTime))
155 || (time.tv_sec >= nextAutoCPWTime + autoCPWInterval))) {
156 struct ktc_encryptionKey key;
157 char buf[4 * sizeof(key) + 1];
158 struct kaentry tentry;
160 char bob[KA_TIMESTR_LEN];
162 ka_timestr(time.tv_sec, bob, KA_TIMESTR_LEN);
163 es_Report("Auto CPW at %s\n", bob);
165 es_Report(" ... even though no ADMIN user\n");
167 code = FindBlock(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &to, &tentry);
170 if (to) { /* check if auto cpw is disabled */
171 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
172 memcpy(&key, &random_value[0], sizeof(key));
173 des_fixup_key_parity(&key);
175 set_password(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
178 des_init_random_number_generator(&key);
179 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
181 es_Report("New Admin key is %s\n", buf);
184 ("in get_time: set_password failed because: %d\n",
191 code = FindBlock(tt, KA_TGS_NAME, lrealm, &to, &tentry);
194 if (to) { /* check if auto cpw is disabled */
195 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
196 memcpy(&key, &random_value[2], sizeof(key));
197 des_fixup_key_parity(&key);
198 code = set_password(tt, KA_TGS_NAME, lrealm, &key, 0, 0);
200 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
202 es_Report("New TGS key is %s\n", buf);
205 ("in get_time: set_password failed because: %s\n",
206 afs_error_message(code));
211 code = ka_FillKeyCache(tt); /* ensure in-core copy is uptodate */
215 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
219 *timeP = time.tv_sec;
223 static int noAuthenticationRequired; /* global state */
224 static int recheckNoAuth; /* global state */
226 /* kaprocsInited is sort of a lock: during a transaction only one process runs
227 while kaprocsInited is false. */
229 static int kaprocsInited = 0;
231 /* This variable is protected by the kaprocsInited flag. */
233 static int (*rebuildDatabase) (struct ubik_trans *);
235 /* This is called to initialize the database */
238 initialize_database(struct ubik_trans *tt)
240 struct ktc_encryptionKey key;
243 gettimeofday((struct timeval *)&key, 0); /* this is just a cheap seed key */
244 des_fixup_key_parity(&key);
245 des_init_random_number_generator(&key);
246 if ((code = des_random_key(&key))
248 create_user(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
249 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
251 if ((code = des_random_key(&key))
253 create_user(tt, KA_TGS_NAME, lrealm, &key, 0,
254 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
259 /* This routine handles initialization required by this module. The initFlags
260 parameter passes some information about the command line arguments. */
263 init_kaprocs(char *lclpath, int initFlags)
266 struct ubik_trans *tt;
267 struct ktc_encryptionKey key;
272 return KAINTERNALERROR;
274 return KAINTERNALERROR;
275 code = afsconf_GetLocalCell(KA_conf, lrealm, sizeof(lrealm));
277 printf("** Can't determine local cell name!\n");
280 ucstring(lrealm, lrealm, sizeof(lrealm));
284 noAuthenticationRequired = 1;
288 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
289 if (noAuthenticationRequired)
290 printf("Running server with security disabled\n");
293 autoCPWInterval = 10;
296 autoCPWInterval = AUTOCPWINTERVAL;
297 autoCPWUpdates = AUTOCPWUPDATES;
300 init_kadatabase(initFlags);
301 rebuildDatabase = initialize_database;
303 if ((code = InitAuthServ(&tt, LOCKREAD, 0))) {
304 printf("init_kaprocs: InitAuthServ failed: code = %d\n", code);
307 code = ka_LookupKey(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &kvno, &key);
311 ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n",
315 des_init_random_number_generator(&key);
317 code = ubik_EndTrans(tt);
319 printf("init_kaprocs: ubik_EndTrans failed: code = %d\n", code);
323 kaux_opendb(lclpath); /* aux database stores failure counters */
324 rebuildDatabase = 0; /* only do this during init */
329 /* These variable are for returning debugging info about the state of the
330 server. If they get trashed during multi-threaded operation it doesn't
333 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
334 char *lastOperation = 0; /* name of last operation */
335 static Date lastTrans; /* time of last transaction */
337 static char adminPrincipal[256];
338 static char authPrincipal[256];
339 static char tgsPrincipal[256];
340 static char tgsServerPrincipal[256];
343 save_principal(char *p, char *n, char *i, char *c)
353 if (i && strlen(i)) {
363 if (c && strlen(c)) {
375 check_auth(struct rx_call *call,
376 struct ubik_trans *at,
377 int admin, /* require caller to be ADMIN */
378 afs_int32 *acaller_id)
381 char name[MAXKTCNAMELEN];
382 char instance[MAXKTCNAMELEN];
383 char cell[MAXKTCREALMLEN];
385 Date expiration; /* checked by Security Module */
386 struct kaentry tentry;
393 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
395 si = rx_SecurityClassOf(rx_ConnectionOf(call));
396 if (si == RX_SCINDEX_VAB) {
397 printf("No support for VAB security module yet.\n");
399 } else if (si == RX_SCINDEX_NULL) {
402 } else if (si != RX_SCINDEX_KAD) {
403 es_Report("Unknown security index %d\n", si);
408 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration, name,
409 instance, cell, &kvno);
413 if (level != rxkad_crypt) {
414 es_Report("Incorrect security level = %d\n", level);
419 if (!name_instance_legal(name, instance))
423 ("Authorization rejected because we don't understand intercell stuff yet: ",
425 printf("@%s\n", cell);
429 code = FindBlock(at, name, instance, acaller_id, &tentry);
432 if (*acaller_id == 0) {
433 ka_PrintUserID("User ", name, instance, " unknown.\n");
436 save_principal(adminPrincipal, name, instance, 0);
439 if (!(ntohl(tentry.flags) & KAFADMIN)) {
440 if (noAuthenticationRequired) {
441 ka_PrintUserID("Authorization approved for ", name, instance,
442 " because there is no authentication required\n");
443 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR,
444 instance, AUD_STR, cell, AUD_END);
447 ka_PrintUserID("User ", name, instance, " is not ADMIN.\n");
450 osi_auditU(call, UseOfPrivilegeEvent, code, AUD_STR, name, AUD_STR,
451 instance, AUD_STR, cell, AUD_END);
456 if (noAuthenticationRequired) {
458 ("Caller w/o authorization approved no authentication required\n");
459 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR, instance,
460 AUD_STR, cell, AUD_END);
463 return code; /* no auth info */
467 AwaitInitialization(void)
470 while (!kaprocsInited) {
473 else if (time(0) - start > 5)
480 /* This is called by every RPC interface to create a Ubik transaction and read
481 the database header into core */
484 InitAuthServ(struct ubik_trans **tt,
485 int lock, /* indicate read/write transaction */
486 int *this_op) /* opcode of RPC proc, for COUNT_ABO */
489 afs_int32 start = 0; /* time started waiting for quorum */
490 float wait = 0.91; /* start waiting for 1 second */
492 /* Wait for server initialization to finish if not during init_kaprocs */
494 if ((code = AwaitInitialization()))
497 for (code = UNOQUORUM; code == UNOQUORUM;) {
498 if (lock == LOCKREAD)
499 code = ubik_BeginTransReadAny(KA_dbase, UBIK_READTRANS, tt);
501 code = ubik_BeginTrans(KA_dbase, UBIK_WRITETRANS, tt);
502 if (code == UNOQUORUM) { /* no quorum elected */
506 int delay = time(0) - start;
507 if (this_op) { /* punt quickly, if RPC call */
510 } else { /* more patient during init. */
515 printf("Waiting for quorum election.\n");
518 IOMGR_Sleep((int)wait);
523 if ((code = ubik_SetLock(*tt, 1, 1, lock))) {
526 ubik_AbortTrans(*tt);
529 /* check that dbase is initialized and setup cheader */
530 if (lock == LOCKREAD) {
531 /* init but don't fix because this is read only */
532 code = CheckInit(*tt, 0);
534 ubik_AbortTrans(*tt); /* abort, since probably I/O error */
535 /* we did the check under a ReadAny transaction, but now, after
536 * getting a write transaction (and thus some real guarantees
537 * about what databases are really out there), we will check again
538 * in CheckInit before nuking the database. Since this may now get
539 * a UNOQUORUM we'll just do this from the top.
541 if ((code = InitAuthServ(tt, LOCKWRITE, this_op)))
543 if ((code = ubik_EndTrans(*tt)))
546 /* now open the read transaction that was originally requested. */
547 return InitAuthServ(tt, lock, this_op);
550 if ((code = CheckInit(*tt, rebuildDatabase))) {
553 ubik_AbortTrans(*tt);
558 ka_FillKeyCache(*tt); /* ensure in-core copy is uptodate */
562 /* returns true if name is specially known by AuthServer */
565 special_name(char *name, char *instance)
568 return ((!strcmp(name, KA_TGS_NAME) && !strcmp(instance, lrealm))
569 || (strcmp(name, KA_ADMIN_NAME) == 0));
573 create_user(struct ubik_trans *tt, char *name, char *instance,
574 EncryptionKey *key, afs_int32 caller, afs_int32 flags)
578 struct kaentry tentry;
579 afs_int32 maxLifetime;
581 code = FindBlock(tt, name, instance, &to, &tentry);
585 return KAEXIST; /* name already exists, we fail */
587 to = AllocBlock(tt, &tentry);
591 /* otherwise we have a block */
592 strncpy(tentry.userID.name, name, sizeof(tentry.userID.name));
593 strncpy(tentry.userID.instance, instance, sizeof(tentry.userID.instance));
594 tentry.flags = htonl(flags);
595 if (special_name(name, instance)) { /* this overrides key & version */
596 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
597 tentry.key_version = htonl(-1); /* don't save this key */
598 if ((code = ka_NewKey(tt, to, &tentry, key)))
601 memcpy(&tentry.key, key, sizeof(tentry.key));
602 tentry.key_version = htonl(0);
604 tentry.user_expiration = htonl(NEVERDATE);
605 code = get_time(&tentry.modification_time, tt, 1);
609 /* time and addr of entry for guy changing this entry */
610 tentry.modification_time = htonl(tentry.modification_time);
611 tentry.modification_id = htonl(caller);
612 tentry.change_password_time = tentry.modification_time;
614 if (strcmp(name, KA_TGS_NAME) == 0)
615 maxLifetime = MAXKTCTICKETLIFETIME;
616 else if (strcmp(name, KA_ADMIN_NAME) == 0)
617 maxLifetime = 10 * 3600;
618 else if (strcmp(name, AUTH_SUPERUSER) == 0)
619 maxLifetime = 100 * 3600;
621 maxLifetime = 25 * 3600; /* regular users */
622 tentry.max_ticket_lifetime = htonl(maxLifetime);
624 code = ThreadBlock(tt, to, &tentry);
628 /* Put actual stub routines here */
631 SKAM_CreateUser(struct rx_call *call, char *aname, char *ainstance,
632 EncryptionKey ainitpw)
636 code = kamCreateUser(call, aname, ainstance, ainitpw);
637 osi_auditU(call, AFS_KAM_CrUserEvent, code, AUD_STR, aname, AUD_STR,
644 kamCreateUser(struct rx_call *call, char *aname, char *ainstance,
645 EncryptionKey ainitpw)
648 struct ubik_trans *tt;
649 afs_int32 caller; /* Disk offset of caller's entry */
651 COUNT_REQ(CreateUser);
652 if (!des_check_key_parity(&ainitpw) || des_is_weak_key(&ainitpw))
654 if (!name_instance_legal(aname, ainstance))
656 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
658 code = check_auth(call, tt, 1, &caller);
664 code = create_user(tt, aname, ainstance, &ainitpw, caller, KAFNORMAL);
670 code = ubik_EndTrans(tt);
671 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
677 SKAA_ChangePassword(struct rx_call *call, char *aname, char *ainstance,
678 ka_CBS *arequest, ka_BBS *oanswer)
682 code = ChangePassWord(call, aname, ainstance, arequest, oanswer);
683 osi_auditU(call, AFS_KAA_ChPswdEvent, code, AUD_STR, aname, AUD_STR,
689 ChangePassWord(struct rx_call *call, char *aname, char *ainstance,
690 ka_CBS *arequest, ka_BBS *oanswer)
693 struct ubik_trans *tt;
694 afs_int32 to; /* offset of block */
695 struct kaentry tentry;
696 struct ka_cpwRequest request; /* request after decryption */
697 char *answer; /* where answer is to be put */
698 int answer_len; /* length of answer packet */
699 afs_int32 kvno; /* requested key version number */
700 des_key_schedule user_schedule; /* key schedule for user's key */
701 Date request_time; /* time request originated */
703 COUNT_REQ(ChangePassword);
704 if (!name_instance_legal(aname, ainstance))
706 if (strcmp(ainstance, KA_ADMIN_NAME) == 0)
708 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
711 code = FindBlock(tt, aname, ainstance, &to, &tentry);
715 if (to == 0) { /* no such user */
719 if (ntohl(tentry.flags) & KAFNOCPW) {
724 /* decrypt request w/ user password */
725 if ((code = des_key_sched(&tentry.key, user_schedule)))
726 es_Report("In KAChangePassword: key_sched returned %d\n", code);
727 des_pcbc_encrypt(arequest->SeqBody, &request,
728 min(arequest->SeqLen, sizeof(request)), user_schedule,
729 &tentry.key, DECRYPT);
731 /* validate the request */
732 request_time = ntohl(request.time); /* reorder date */
733 kvno = ntohl(request.kvno);
734 if ((abs(request_time - time(0)) > KTC_TIME_UNCERTAINTY) || strncmp(request.label, KA_CPW_REQ_LABEL, sizeof(request.label)) || (request.spare) || (kvno > MAXKAKVNO)) { /* these are reseved */
739 /* check to see if the new password was used before, or if there has
740 * not been sufficient time since the last password change
742 code = impose_reuse_limits(&request.newpw, &tentry);
747 /* Create the Answer Packet */
748 answer_len = sizeof(Date) + KA_LABELSIZE;
749 if (oanswer->MaxSeqLen < answer_len) {
750 code = KAANSWERTOOLONG;
753 oanswer->SeqLen = answer_len;
754 answer = oanswer->SeqBody;
755 request.time = htonl(request_time + 1);
756 memcpy(answer, (char *)&request.time, sizeof(Date));
757 answer += sizeof(Date);
758 memcpy(answer, KA_CPW_ANS_LABEL, KA_LABELSIZE);
760 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, answer_len,
761 user_schedule, &tentry.key, ENCRYPT);
763 code = set_password(tt, aname, ainstance, &request.newpw, kvno, 0);
769 cheader.stats.cpws = htonl(ntohl(cheader.stats.cpws) + 1);
771 kawrite(tt, DOFFSET(0, &cheader, &cheader.stats.cpws),
772 (char *)&cheader.stats.cpws, sizeof(afs_int32));
778 code = ubik_EndTrans(tt);
788 impose_reuse_limits(EncryptionKey *password, struct kaentry *tentry)
796 if (!tentry->pwsums[0] && npwSums > 1 && !tentry->pwsums[1])
797 return 0; /* password reuse limits not in effect */
799 code = get_time(&now, 0, 0);
803 if ((now - ntohl(tentry->change_password_time)) < MinHours * 60 * 60)
806 if (!memcmp(password, &(tentry->key), sizeof(EncryptionKey)))
809 code = ka_KeyCheckSum((char *)password, &newsum);
813 newsum = newsum & 0x000000ff;
814 for (i = 0; i < npwSums; i++) {
815 if (newsum == tentry->pwsums[i])
824 set_password(struct ubik_trans *tt, char *name, char *instance,
825 EncryptionKey *password, afs_int32 kvno, afs_int32 caller)
828 afs_int32 to; /* offset of block */
829 struct kaentry tentry;
835 code = FindBlock(tt, name, instance, &to, &tentry);
839 return KANOENT; /* no such user */
841 /* if password reuse limits in effect, set the checksums, the hard way */
842 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
843 /* do nothing, no limits */ ;
845 code = ka_KeyCheckSum((char *)&(tentry.key), &newsum);
848 for (i = npwSums - 1; i; i--)
849 tentry.pwsums[i] = tentry.pwsums[i - 1];
850 tentry.pwsums[0] = newsum & 0x000000ff;
854 if (special_name(name, instance)) { /* set key over rides key_version */
855 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
856 if ((code = ka_NewKey(tt, to, &tentry, password)))
859 memcpy(&tentry.key, password, sizeof(tentry.key));
861 kvno = ntohl(tentry.key_version);
862 if ((kvno < 1) || (kvno >= MAXKAKVNO))
867 tentry.key_version = htonl((afs_int32) kvno); /* requested key version */
872 /* no-write prevents recursive call to set_password by AuthCPW code. */
873 code = get_time(&now, 0, 0);
877 tentry.modification_time = htonl(now);
878 tentry.modification_id = htonl(caller);
881 tentry.change_password_time = htonl(now);
883 if (code = kawrite(tt, to, &tentry, sizeof(tentry)))
889 SKAM_SetPassword(struct rx_call *call, char *aname, char *ainstance,
890 afs_int32 akvno, EncryptionKey apassword)
894 code = kamSetPassword(call, aname, ainstance, akvno, apassword);
895 osi_auditU(call, AFS_KAM_SetPswdEvent, code, AUD_STR, aname, AUD_STR,
901 kamSetPassword(struct rx_call *call, char *aname, char *ainstance,
902 afs_int32 akvno, EncryptionKey apassword)
905 struct ubik_trans *tt;
906 afs_int32 caller; /* Disk offset of caller's entry */
907 struct kaentry tentry;
909 COUNT_REQ(SetPassword);
910 if (akvno > MAXKAKVNO)
911 return KABADARGUMENT;
912 if (!des_check_key_parity(&apassword) || des_is_weak_key(&apassword))
915 if (!name_instance_legal(aname, ainstance))
917 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
919 code = check_auth(call, tt, 0, &caller);
923 if ((code = karead(tt, caller, &tentry, sizeof(tentry)))) {
927 /* if the user is changing his own password or ADMIN then go ahead. */
928 if ((strcmp(tentry.userID.name, aname) == 0)
929 && (strcmp(tentry.userID.instance, ainstance) == 0)) {
930 if (ntohl(tentry.flags) & KAFNOCPW)
933 code = impose_reuse_limits(&apassword, &tentry);
936 set_password(tt, aname, ainstance, &apassword, akvno, 0);
938 } else if (ntohl(tentry.flags) & KAFADMIN) {
939 code = set_password(tt, aname, ainstance, &apassword, akvno, caller);
945 code = ubik_EndTrans(tt);
946 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
957 CoerseLifetime(Date start, Date end)
959 unsigned char kerberosV4Life;
960 kerberosV4Life = time_to_life(start, end);
961 end = life_to_time(start, kerberosV4Life);
966 GetEndTime(Date start, /* start time of ticket */
967 Date reqEnd, /* requested end time */
968 Date expiration, /* authorizing ticket's expiration */
969 struct kaentry *caller,
970 struct kaentry *server,
971 Date *endP) /* actual end time */
977 if (ntohl(caller->flags) & KAFNOTGS)
978 return KABADUSER; /* no new tickets for this user */
979 if (expiration && (ntohl(server->flags) & KAFNOSEAL))
980 return KABADSERVER; /* can't be target of GetTicket req */
982 expiration = NEVERDATE;
984 cExp = ntohl(caller->user_expiration);
985 sExp = ntohl(server->user_expiration);
990 cLife = start + ntohl(caller->max_ticket_lifetime);
991 sLife = start + ntohl(server->max_ticket_lifetime);
993 umin(umin(reqEnd, expiration),
994 umin(umin(cLife, sLife), umin(cExp, sExp)));
995 end = CoerseLifetime(start, end);
1001 PrepareTicketAnswer(ka_BBS *oanswer, afs_int32 challenge, char *ticket,
1002 afs_int32 ticketLen, struct ktc_encryptionKey *sessionKey,
1003 Date start, Date end, struct kaentry *caller,
1004 struct kaentry *server, char *cell, char *label)
1007 struct ka_ticketAnswer *answer;
1010 code = KAANSWERTOOLONG;
1011 if (oanswer->MaxSeqLen <
1012 sizeof(struct ka_ticketAnswer) - 5 * MAXKTCNAMELEN - MAXKTCTICKETLEN +
1016 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
1017 answer->challenge = htonl(challenge);
1018 memcpy(&answer->sessionKey, sessionKey, sizeof(struct ktc_encryptionKey));
1019 answer->startTime = htonl(start);
1020 answer->endTime = htonl(end);
1021 answer->kvno = server->key_version;
1022 answer->ticketLen = htonl(ticketLen);
1025 char *ans = answer->name; /* pointer to variable part */
1026 int rem; /* space remaining */
1027 int len; /* macro temp. */
1029 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1031 #define putstr(str) len = strlen (str)+1;\
1032 if (rem < len) return code;\
1034 ans += len; rem -= len
1035 putstr(caller->userID.name);
1036 putstr(caller->userID.instance);
1038 putstr(server->userID.name);
1039 putstr(server->userID.instance);
1040 if (rem < ticketLen + KA_LABELSIZE)
1042 memcpy(ans, ticket, ticketLen);
1045 memcpy(ans, label, KA_LABELSIZE);
1047 memset(ans, 0, KA_LABELSIZE);
1048 ans += KA_LABELSIZE;
1049 oanswer->SeqLen = (ans - oanswer->SeqBody);
1052 answer->cksum = htonl(cksum);
1053 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1054 if (oanswer->SeqLen > oanswer->MaxSeqLen)
1059 /* This is used to get a ticket granting ticket or an admininstration ticket.
1060 These two specific, built-in servers are special cases, which require the
1061 client's key as an additional security precaution. The GetTicket operation
1062 is normally disabled for these two principals. */
1065 Authenticate(int version, struct rx_call *call, char *aname, char *ainstance,
1066 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1069 struct ubik_trans *tt;
1070 afs_int32 to; /* offset of block */
1072 struct kaentry server; /* entry for desired server */
1073 struct ka_gettgtRequest request; /* request after decryption */
1074 int tgt, adm; /* type of request */
1075 char *sname; /* principal of server */
1077 char ticket[MAXKTCTICKETLEN]; /* our copy of the ticket */
1079 struct ktc_encryptionKey sessionKey; /* we have to invent a session key */
1080 char *answer; /* where answer is to be put */
1081 int answer_len; /* length of answer packet */
1082 Date answer_time; /* 1+ request time in network order */
1083 afs_int32 temp; /* for htonl conversions */
1084 des_key_schedule user_schedule; /* key schedule for user's key */
1085 afs_int32 tgskvno; /* key version of service key */
1086 struct ktc_encryptionKey tgskey; /* service key for encrypting ticket */
1088 afs_uint32 pwexpires;
1090 COUNT_REQ(Authenticate);
1091 if (!name_instance_legal(aname, ainstance))
1093 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1095 get_time(&now, 0, 0);
1097 sname = sinst = NULL;
1099 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1103 if (to == 0) { /* no such user */
1108 /* have to check for locked before verifying the password, otherwise all
1109 * KALOCKED means is "yup, you guessed the password all right, now wait a
1110 * few minutes and we'll let you in"
1113 (to, (u_int) tentry.misc_auth_bytes[ATTEMPTS],
1114 (afs_uint32) tentry.misc_auth_bytes[LOCKTIME] << 9)) {
1120 save_principal(authPrincipal, aname, ainstance, 0);
1122 /* decrypt request w/ user password */
1123 if ((code = des_key_sched(&tentry.key, user_schedule)))
1124 es_Report("In KAAuthenticate: key_sched returned %d\n", code);
1125 des_pcbc_encrypt(arequest->SeqBody, &request,
1126 min(arequest->SeqLen, sizeof(request)), user_schedule,
1127 &tentry.key, DECRYPT);
1129 request.time = ntohl(request.time); /* reorder date */
1130 tgt = !strncmp(request.label, KA_GETTGT_REQ_LABEL, sizeof(request.label));
1131 adm = !strncmp(request.label, KA_GETADM_REQ_LABEL, sizeof(request.label));
1132 if (!(tgt || adm)) {
1133 kaux_inc(to, ((unsigned char)tentry.misc_auth_bytes[LOCKTIME]) << 9);
1134 code = KABADREQUEST;
1137 kaux_write(to, 0, 0); /* reset counters */
1140 if (!tentry.misc_auth_bytes[EXPIRES]) {
1141 /* 0 in the database means never, but 0 on the network means today */
1142 /* 255 on the network means "long time, maybe never" */
1145 pwexpires = tentry.misc_auth_bytes[EXPIRES];
1148 ntohl(tentry.change_password_time) + 24 * 60 * 60 * pwexpires;
1149 if (adm) { /* provide a little slack for admin ticket */
1150 pwexpires += 30 * 24 * 60 * 60; /* 30 days */
1152 if (pwexpires < now) {
1156 pwexpires = (pwexpires - now) / (24 * 60 * 60);
1157 if (pwexpires > 255)
1161 #endif /* EXPIREPW */
1163 if (abs(request.time - now) > KTC_TIME_UNCERTAINTY) {
1165 if (oanswer->MaxSeqLen < sizeof(afs_int32))
1166 code = KAANSWERTOOLONG;
1167 else { /* return our time if possible */
1168 oanswer->SeqLen = sizeof(afs_int32);
1169 request.time = htonl(now);
1170 memcpy(oanswer->SeqBody, &request.time, sizeof(afs_int32));
1176 sname = (tgt ? KA_TGS_NAME : KA_ADMIN_NAME);
1177 sinst = (tgt ? lrealm : KA_ADMIN_INST);
1178 code = FindBlock(tt, sname, sinst, &to, &server);
1186 tgskvno = ntohl(server.key_version);
1187 memcpy(&tgskey, &server.key, sizeof(tgskey));
1189 code = des_random_key(&sessionKey);
1195 code = GetEndTime(start, end, 0 /*!GetTicket */ , &tentry, &server, &end);
1200 tkt_MakeTicket(ticket, &ticketLen, &tgskey, aname, ainstance, "",
1201 start, end, &sessionKey,
1202 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), sname,
1210 ticketLen + sizeof(Date) + sizeof(struct ktc_encryptionKey) +
1211 2 * sizeof(afs_int32) + KA_LABELSIZE;
1212 answer_len = round_up_to_ebs(answer_len);
1213 if (answer_len > oanswer->MaxSeqLen) {
1214 code = KAANSWERTOOLONG;
1217 oanswer->SeqLen = answer_len;
1218 answer = oanswer->SeqBody;
1219 answer_time = htonl(request.time + 1);
1220 memcpy(answer, (char *)&answer_time, sizeof(Date));
1221 answer += sizeof(Date);
1222 memcpy(answer, (char *)&sessionKey, sizeof(struct ktc_encryptionKey));
1223 answer += sizeof(struct ktc_encryptionKey);
1224 temp = htonl(tgskvno);
1225 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1226 answer += sizeof(afs_int32);
1227 temp = htonl(ticketLen);
1228 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1229 answer += sizeof(afs_int32);
1230 memcpy(answer, ticket, ticketLen);
1231 answer += ticketLen;
1232 memcpy(answer, (tgt ? KA_GETTGT_ANS_LABEL : KA_GETADM_ANS_LABEL),
1238 PrepareTicketAnswer(oanswer, request.time + 1, ticket, ticketLen,
1239 &sessionKey, start, end, &tentry, &server, "",
1240 (tgt ? KA_GETTGT_ANS_LABEL :
1241 KA_GETADM_ANS_LABEL));
1246 && oanswer->SeqLen < oanswer->MaxSeqLen + sizeof(afs_int32)) {
1247 temp = pwexpires << 24; /* move it into the high byte */
1248 pwexpires = htonl(temp);
1250 memcpy((char *)oanswer->SeqBody + oanswer->SeqLen, &pwexpires,
1252 oanswer->SeqLen += sizeof(afs_int32);
1253 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1254 if (oanswer->SeqLen > oanswer->MaxSeqLen) {
1255 code = KAANSWERTOOLONG;
1259 #endif /* EXPIREPW */
1263 code = KAINTERNALERROR;
1266 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1267 user_schedule, &tentry.key, ENCRYPT);
1268 code = ubik_EndTrans(tt);
1269 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host,
1275 ubik_AbortTrans(tt);
1276 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host,
1282 SKAA_Authenticate_old(struct rx_call *call, char *aname, char *ainstance,
1283 Date start, Date end, ka_CBS *arequest,
1288 IOMGR_Sleep(1); /* discourage use of this mechanism */
1290 Authenticate(0, call, aname, ainstance, start, end, arequest,
1292 osi_auditU(call, AFS_KAA_AuthOEvent, code, AUD_STR, aname, AUD_STR,
1293 ainstance, AUD_END);
1299 SKAA_Authenticate(struct rx_call *call, char *aname, char *ainstance,
1300 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1305 Authenticate(1, call, aname, ainstance, start, end, arequest,
1307 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1308 ainstance, AUD_END);
1314 SKAA_AuthenticateV2(struct rx_call *call, char *aname, char *ainstance,
1315 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1320 Authenticate(2, call, aname, ainstance, start, end, arequest,
1322 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1323 ainstance, AUD_END);
1329 SKAM_SetFields(struct rx_call *call,
1334 afs_int32 alifetime,
1335 afs_int32 amaxAssociates,
1336 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1342 kamSetFields(call, aname, ainstance, aflags, aexpiration, alifetime,
1343 amaxAssociates, misc_auth_bytes, spare2);
1344 osi_auditU(call, AFS_KAM_SetFldEvent, code, AUD_STR, aname, AUD_STR,
1345 ainstance, AUD_LONG, aflags, AUD_DATE, aexpiration, AUD_LONG,
1346 alifetime, AUD_LONG, amaxAssociates, AUD_END);
1351 kamSetFields(struct rx_call *call,
1356 afs_int32 alifetime,
1357 afs_int32 amaxAssociates,
1358 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1363 struct ubik_trans *tt;
1365 afs_int32 tentry_offset; /* offset of entry */
1366 struct kaentry tentry;
1367 unsigned char newvals[4];
1369 COUNT_REQ(SetFields);
1372 return KABADARGUMENT; /* not supported yet... */
1374 /* make sure we're supposed to do something */
1375 if (!(aflags || aexpiration || alifetime || (amaxAssociates >= 0)
1377 || ((aflags & ~KAFNORMAL) & ~KAF_SETTABLE_FLAGS))
1378 return KABADARGUMENT; /* arguments no good */
1379 if (!name_instance_legal(aname, ainstance))
1381 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1383 code = check_auth(call, tt, 1, &caller);
1388 code = FindBlock(tt, aname, ainstance, &tentry_offset, &tentry);
1391 if (tentry_offset == 0) { /* no such user */
1395 if ((ntohl(tentry.flags) & KAFNORMAL) == 0)
1396 return KAINTERNALERROR;
1398 /* Keep track of the total number of admin accounts. This way we can
1399 * update database without any admin privilege initially */
1400 if ((aflags & KAFADMIN) != (ntohl(tentry.flags) & KAFADMIN)) {
1401 /* if admin state is changing */
1403 if (ntohl(tentry.flags) & KAFADMIN)
1407 if ((code = update_admin_count(tt, delta)))
1411 htonl((ntohl(tentry.flags) & ~KAF_SETTABLE_FLAGS) | aflags);
1413 if ((code = get_time(&now, tt, 1)))
1416 tentry.user_expiration = htonl(aexpiration);
1417 if (!ntohl(tentry.change_password_time)) {
1418 tentry.change_password_time = htonl(now);
1422 tentry.max_ticket_lifetime = htonl(alifetime);
1424 #ifndef NOPWCONTROLS
1426 * We've packed a bunch of bytes into a long for backward compatibility.
1427 * These include password expiration time, and some failed login limits
1428 * counters. Now let's unpack them and stick them into the
1429 * kaentry struct. All the bytes have values in the range
1430 * 1..255, else they were not specified in the interface, and are
1432 * In the case of password expiration times, 1 means password never
1433 * expires (==>0), 2 means password only lives for one day (==>1),
1436 if (misc_auth_bytes) {
1437 unpack_long(misc_auth_bytes, newvals);
1438 if (newvals[EXPIRES]) {
1439 tentry.misc_auth_bytes[EXPIRES] = newvals[EXPIRES] - 1;
1442 if (newvals[REUSEFLAGS]) {
1443 if (newvals[REUSEFLAGS] & KA_REUSEPW)
1444 memset(tentry.pwsums, 0, KA_NPWSUMS);
1445 else if ((newvals[REUSEFLAGS] & KA_NOREUSEPW)
1446 && !tentry.pwsums[0])
1447 tentry.pwsums[0] = 0xff;
1450 if (newvals[ATTEMPTS]) {
1451 tentry.misc_auth_bytes[ATTEMPTS] = newvals[ATTEMPTS] - 1;
1453 if (newvals[LOCKTIME]) {
1454 tentry.misc_auth_bytes[LOCKTIME] = newvals[LOCKTIME] - 1;
1457 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1460 #endif /* NOPWCONTROLS */
1462 if (amaxAssociates >= 0) {
1463 if ((ntohl(tentry.flags) & KAFASSOC)
1464 || (ntohl(tentry.flags) & KAFSPECIAL))
1466 if (((ntohl(tentry.flags) & KAFASSOCROOT) == 0) && (amaxAssociates > 0)) /* convert normal user to assoc root */
1467 tentry.flags = htonl(ntohl(tentry.flags) | KAFASSOCROOT);
1468 tentry.misc.assocRoot.maxAssociates = htonl(amaxAssociates);
1471 tentry.modification_time = htonl(now);
1472 tentry.modification_id = htonl(caller);
1473 code = kawrite(tt, tentry_offset, &tentry, sizeof(tentry));
1477 code = ubik_EndTrans(tt);
1478 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
1484 ubik_AbortTrans(tt);
1491 SKAM_DeleteUser(struct rx_call *call, char *aname, char *ainstance)
1495 code = kamDeleteUser(call, aname, ainstance);
1496 osi_auditU(call, AFS_KAM_DelUserEvent, code, AUD_STR, aname, AUD_STR,
1497 ainstance, AUD_END);
1502 kamDeleteUser(struct rx_call *call, char *aname, char *ainstance)
1505 struct ubik_trans *tt;
1508 struct kaentry tentry;
1510 afs_uint32 locktime;
1512 COUNT_REQ(DeleteUser);
1513 if (!name_instance_legal(aname, ainstance))
1515 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1517 code = check_auth(call, tt, 1, &caller);
1521 ubik_AbortTrans(tt);
1525 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1528 if (to == 0) { /* name not found */
1533 kaux_read(to, &nfailures, &locktime);
1534 if (nfailures || locktime)
1535 kaux_write(to, 0, 0); /* zero failure counters at this offset */
1537 /* track all AuthServer identities */
1538 if (special_name(aname, ainstance))
1539 if ((code = ka_DelKey(tt, to, &tentry)))
1542 if (ntohl(tentry.flags) & KAFADMIN) /* keep admin count up-to-date */
1543 if ((code = update_admin_count(tt, -1)))
1546 if ((code = UnthreadBlock(tt, &tentry)) || (code = FreeBlock(tt, to)) || (code = get_time(0, tt, 1)) /* update randomness */
1550 code = ubik_EndTrans(tt);
1551 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
1556 /* we set a bit in here which indicates that the user's limit of
1557 * authentication failures has been exceeded. If that bit is not set,
1558 * kas can take it on faith that the user ID is not locked. If that
1559 * bit is set, kas has to check all the servers to find one who will
1560 * report that the ID is not locked, or else to find out when the ID
1564 SKAM_GetEntry(struct rx_call *call,
1567 afs_int32 aversion, /* major version assumed by caller */
1568 kaentryinfo *aentry) /* entry data copied here */
1572 code = kamGetEntry(call, aname, ainstance, aversion, aentry);
1573 osi_auditU(call, AFS_KAM_GetEntEvent, code, AUD_STR, aname, AUD_STR,
1574 ainstance, AUD_END);
1579 kamGetEntry(struct rx_call *call,
1582 afs_int32 aversion, /* major version assumed by caller */
1583 kaentryinfo *aentry) /* entry data copied here */
1585 register afs_int32 code;
1586 struct ubik_trans *tt;
1587 afs_int32 callerIndex;
1588 struct kaentry caller;
1591 struct kaentry tentry;
1592 rxkad_level enc_level = rxkad_clear;
1593 int callerIsAdmin = 0;
1595 COUNT_REQ(GetEntry);
1596 if (aversion != KAMAJORVERSION)
1597 return KAOLDINTERFACE;
1598 if (!name_instance_legal(aname, ainstance))
1600 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1602 code = check_auth(call, tt, 0, &callerIndex);
1606 if (noAuthenticationRequired) {
1607 } else if (!callerIndex) {
1611 if ((code = karead(tt, callerIndex, &caller, sizeof(caller)))) {
1615 /* if the user is checking his own entry or ADMIN then go ahead. */
1616 callerIsAdmin = (ntohl(caller.flags) & KAFADMIN);
1618 if (strcmp(caller.userID.name, aname) != 0 && !callerIsAdmin) {
1624 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1627 if (to == 0) { /* entry not found */
1632 get_time(0, 0, 0); /* generate random update */
1634 memset(aentry, 0, sizeof(*aentry));
1635 aentry->minor_version = KAMINORVERSION;
1636 aentry->flags = ntohl(tentry.flags);
1637 aentry->user_expiration = ntohl(tentry.user_expiration);
1638 aentry->modification_time = ntohl(tentry.modification_time);
1639 aentry->change_password_time = ntohl(tentry.change_password_time);
1640 aentry->max_ticket_lifetime = ntohl(tentry.max_ticket_lifetime);
1641 aentry->key_version = ntohl(tentry.key_version);
1643 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
1645 if (kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp))
1646 tentry.misc_auth_bytes[REUSEFLAGS] |= KA_ISLOCKED; /* saves an RPC */
1648 temp = pack_long(tentry.misc_auth_bytes);
1649 aentry->misc_auth_bytes = temp;
1651 * only return user's key if security disabled or if admin and
1652 * we have an encrypted connection to the user
1654 rxkad_GetServerInfo(call->conn, &enc_level, 0, 0, 0, 0, 0);
1655 if ((noAuthenticationRequired)
1656 || (callerIsAdmin && enc_level == rxkad_crypt))
1657 memcpy(&aentry->key, &tentry.key, sizeof(struct ktc_encryptionKey));
1659 memset(&aentry->key, 0, sizeof(aentry->key));
1660 code = ka_KeyCheckSum((char *)&tentry.key, &aentry->keyCheckSum);
1661 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
1662 aentry->reserved3 = 0x12340000;
1664 aentry->reserved3 = 0x12340001;
1667 /* Now get entry of user who last modified this entry */
1668 if (ntohl(tentry.modification_id)) {
1669 temp = ntohl(tentry.modification_id);
1670 code = karead(tt, temp, &tentry, sizeof(tentry));
1675 aentry->modification_user = tentry.userID;
1677 strcpy(aentry->modification_user.name, "<none>");
1678 strcpy(aentry->modification_user.instance, "\0");
1680 code = ubik_EndTrans(tt);
1685 ubik_AbortTrans(tt);
1690 SKAM_ListEntry(struct rx_call *call,
1691 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1692 afs_int32 *index, /* index of this entry */
1693 afs_int32 *count, /* total entries in database */
1694 kaident *name) /* name & instance of this entry */
1698 code = kamListEntry(call, previous_index, index, count, name);
1699 osi_auditU(call, AFS_KAM_LstEntEvent, code, AUD_LONG, *index, AUD_END);
1705 kamListEntry(struct rx_call *call,
1706 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1707 afs_int32 *index, /* index of this entry */
1708 afs_int32 *count, /* total entries in database */
1709 kaident *name) /* name & instance of this entry */
1712 struct ubik_trans *tt;
1714 struct kaentry tentry;
1716 COUNT_REQ(ListEntry);
1717 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1719 code = check_auth(call, tt, 1, &caller);
1724 *index = NextBlock(tt, previous_index, &tentry, count);
1730 if (*index) { /* return name & inst of this entry */
1731 strncpy(name->name, tentry.userID.name, sizeof(name->name));
1732 strncpy(name->instance, tentry.userID.instance,
1733 sizeof(name->instance));
1735 strcpy(name->name, "\0");
1736 strcpy(name->instance, "\0");
1738 code = ubik_EndTrans(tt);
1743 ubik_AbortTrans(tt);
1748 GetTicket(int version,
1749 struct rx_call *call,
1755 ka_CBS *atimes, /* encrypted start & end time */
1760 struct ubik_trans *tt;
1761 struct ktc_encryptionKey tgskey;
1762 des_key_schedule schedule;
1764 char name[MAXKTCNAMELEN];
1765 char instance[MAXKTCNAMELEN];
1766 char cell[MAXKTCNAMELEN];
1768 struct kaentry caller;
1769 struct kaentry server;
1770 struct ktc_encryptionKey authSessionKey;
1771 struct ktc_encryptionKey sessionKey;
1773 char ticket[MAXKTCTICKETLEN];
1779 struct ka_getTicketTimes times;
1780 struct ka_getTicketAnswer *answer;
1782 COUNT_REQ(GetTicket);
1783 if (!name_instance_legal(sname, sinstance))
1785 if (atimes->SeqLen != sizeof(times))
1786 return KABADARGUMENT;
1787 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1790 export = import = 0;
1791 if ((strcmp(sname, KA_TGS_NAME) == 0) && (strcmp(sinstance, lrealm) != 0))
1793 if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0))
1796 if (strlen(authDomain) == 0)
1797 authDomain = lrealm;
1798 code = ka_LookupKvno(tt, KA_TGS_NAME, authDomain, kvno, &tgskey);
1803 tkt_DecodeTicket(aticket->SeqBody, aticket->SeqLen, &tgskey, name,
1804 instance, cell, &authSessionKey, &host, &start,
1810 save_principal(tgsPrincipal, name, instance, cell);
1812 if ((code = get_time(&now, 0, 0)))
1815 code = tkt_CheckTimes(start, expiration, now);
1818 code = RXKADEXPIRED;
1823 code = des_key_sched(&authSessionKey, schedule);
1828 celllen = strlen(cell);
1829 if (import && (celllen == 0)) {
1833 if (export && (celllen == 0))
1834 strcpy(cell, lrealm);
1836 if (!krb4_cross && celllen && strcmp(lrealm, cell) != 0) {
1841 des_ecb_encrypt(atimes->SeqBody, ×, schedule, DECRYPT);
1842 times.start = ntohl(times.start);
1843 times.end = ntohl(times.end);
1844 code = tkt_CheckTimes(times.start, times.end, now);
1846 code = KABADREQUEST;
1851 strcpy(caller.userID.name, name);
1852 strcpy(caller.userID.instance, instance);
1853 caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
1854 caller.flags = htonl(KAFNORMAL);
1855 caller.user_expiration = htonl(NEVERDATE);
1857 code = FindBlock(tt, name, instance, &to, &caller);
1861 ka_PrintUserID("GetTicket: User ", name, instance, " unknown.\n");
1867 /* get server's entry */
1868 code = FindBlock(tt, sname, sinstance, &to, &server);
1871 if (to == 0) { /* entry not found */
1872 ka_PrintUserID("GetTicket: Server ", sname, sinstance, " unknown.\n");
1876 save_principal(tgsServerPrincipal, sname, sinstance, 0);
1878 code = des_random_key(&sessionKey);
1885 GetEndTime(times.start, times.end, expiration, &caller, &server,
1891 tkt_MakeTicket(ticket, &ticketLen, &server.key, caller.userID.name,
1892 caller.userID.instance, cell, times.start, end,
1894 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
1895 server.userID.name, server.userID.instance);
1901 code = KAANSWERTOOLONG;
1902 if (oanswer->MaxSeqLen <
1903 sizeof(struct ka_getTicketAnswer) - 5 * MAXKTCNAMELEN -
1904 MAXKTCTICKETLEN + ticketLen)
1907 answer = (struct ka_getTicketAnswer *)oanswer->SeqBody;
1908 memcpy(&answer->sessionKey, &sessionKey,
1909 sizeof(struct ktc_encryptionKey));
1910 answer->startTime = htonl(times.start);
1911 answer->endTime = htonl(end);
1912 answer->kvno = server.key_version;
1913 answer->ticketLen = htonl(ticketLen);
1916 char *ans = answer->name; /* ptr to variable part of answer */
1919 /* space remaining */
1920 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1922 #define putstr(str) len = strlen (str)+1;\
1923 if (rem < len) goto abort;\
1925 ans += len; rem -= len
1932 if (rem < ticketLen)
1934 memcpy(ans, ticket, ticketLen);
1935 oanswer->SeqLen = (ans - oanswer->SeqBody) + ticketLen;
1937 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1941 PrepareTicketAnswer(oanswer, /*challenge */ 0, ticket, ticketLen,
1942 &sessionKey, times.start, end, &caller,
1943 &server, cell, KA_GETTICKET_ANS_LABEL);
1948 code = KAINTERNALERROR;
1951 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1952 schedule, &authSessionKey, ENCRYPT);
1953 code = ubik_EndTrans(tt);
1954 KALOG(name, instance, sname, sinstance, (import ? authDomain : NULL),
1955 call->conn->peer->host, LOG_GETTICKET);
1960 ubik_AbortTrans(tt);
1965 SKAT_GetTicket_old(struct rx_call *call,
1971 ka_CBS *atimes, /* encrypted start & end time */
1976 sleep(1); /* strongly discourage this */
1978 GetTicket(0, call, kvno, authDomain, aticket, sname, sinstance,
1981 osi_auditU(call, AFS_KAT_GetTicketOEvent, code, AUD_STR, sname, AUD_STR,
1982 sinstance, AUD_END);
1987 SKAT_GetTicket(struct rx_call *call,
1993 ka_CBS *atimes, /* encrypted start & end time */
1999 GetTicket(1, call, kvno, authDomain, aticket, sname, sinstance,
2001 osi_auditU(call, AFS_KAT_GetTicketEvent, code, AUD_STR, sname, AUD_STR,
2002 sinstance, AUD_END);
2007 SKAM_GetStats(struct rx_call *call, afs_int32 version,
2008 afs_int32 *admin_accounts, kasstats *statics,
2013 code = kamGetStats(call, version, admin_accounts, statics, dynamics);
2014 osi_auditU(call, AFS_KAM_GetStatEvent, code, AUD_END);
2019 kamGetStats(struct rx_call *call, afs_int32 version,
2020 afs_int32 *admin_accounts, kasstats *statics,
2024 struct ubik_trans *tt;
2027 COUNT_REQ(GetStats);
2028 if (version != KAMAJORVERSION)
2029 return KAOLDINTERFACE;
2030 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2032 code = check_auth(call, tt, 1, &caller);
2035 ubik_AbortTrans(tt);
2039 *admin_accounts = ntohl(cheader.admin_accounts);
2040 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
2041 /* these are stored in network byte order and must be copied */
2042 statics->allocs = ntohl(cheader.stats.allocs);
2043 statics->frees = ntohl(cheader.stats.frees);
2044 statics->cpws = ntohl(cheader.stats.cpws);
2045 #if KADBVERSION != 5
2046 check that the statistics command copies all the fields
2048 memcpy((char *)dynamics, (char *)&dynamic_statistics, sizeof(kadstats));
2049 statics->minor_version = KAMINORVERSION;
2050 dynamics->minor_version = KAMINORVERSION;
2056 for (i = 0; i < HASHSIZE; i++)
2057 if (cheader.nameHash[i])
2059 dynamics->hashTableUtilization =
2060 (used * 10000 + HASHSIZE / 2) / HASHSIZE;
2063 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
2065 /* Unfortunately, although aix_22 has a minimal compatibility
2066 * method of getting to some rusage fields (i.e. stime &
2067 * utime), the version that we have doesn't even have the
2068 * related include files needed for the aix vtimes() call; so
2069 * ignore this for aix till v3.1... */
2070 getrusage(RUSAGE_SELF, &ru);
2071 #if (KAMAJORVERSION>5)
2072 memcpy(&dynamics->utime, &ru.ru_utime, sizeof(struct katimeval));
2073 memcpy(&dynamics->stime, &ru.ru_stime, sizeof(struct katimeval));
2074 dynamics->dataSize = ru.ru_idrss;
2075 dynamics->stackSize = ru.ru_isrss;
2076 dynamics->pageFailts = ru.ru_majflt;
2078 dynamics->string_checks =
2079 (afs_int32) (1000.0 *
2080 ((ru.ru_utime.tv_sec +
2081 ru.ru_utime.tv_usec / 1000000.0) +
2082 (ru.ru_stime.tv_sec +
2083 ru.ru_stime.tv_usec / 1000000.0)));
2085 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
2088 code = ubik_EndTrans(tt);
2093 SKAM_GetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2097 code = kamGetPassword(call, name, password);
2098 osi_auditU(call, AFS_KAM_GetPswdEvent, code, AUD_STR, name, AUD_END);
2103 kamGetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2105 int code = KANOAUTH;
2106 COUNT_REQ(GetPassword);
2111 struct ubik_trans *tt;
2112 struct kaentry tentry;
2114 if (!name_instance_legal(name, ""))
2116 /* only requests from this host work */
2117 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))) !=
2118 htonl(INADDR_LOOPBACK))
2120 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2123 /* this isn't likely to be used because of string to key problems, so since
2124 * this is a temporary thing anyway, we'll use it here. */
2126 extern char udpAuthPrincipal[256];
2128 save_principal(udpAuthPrincipal, name, 0, 0);
2131 get_time(0, 0, 0); /* update random value */
2132 code = FindBlock(tt, name, "", &to, &tentry);
2139 ubik_AbortTrans(tt);
2143 memcpy(password, &tentry.key, sizeof(*password));
2144 code = ubik_EndTrans(tt);
2151 SKAM_GetRandomKey(struct rx_call *call, EncryptionKey *key)
2155 code = kamGetRandomKey(call, key);
2156 osi_auditU(call, AFS_KAM_GetRndKeyEvent, code, AUD_END);
2161 kamGetRandomKey(struct rx_call *call, EncryptionKey *key)
2165 COUNT_REQ(GetRandomKey);
2166 if ((code = AwaitInitialization()))
2168 code = des_random_key(key);
2175 SKAM_Debug(struct rx_call *call,
2177 int checkDB, /* start a transaction to examine DB */
2178 struct ka_debugInfo *info)
2182 code = kamDebug(call, version, checkDB, info);
2183 osi_auditU(call, AFS_KAM_DbgEvent, code, AUD_END);
2188 kamDebug(struct rx_call *call,
2190 int checkDB, /* start a transaction to examine DB */
2191 struct ka_debugInfo *info)
2193 /* COUNT_REQ (Debug); */
2194 if (sizeof(struct kaentry) != sizeof(struct kaOldKeys))
2195 return KAINTERNALERROR;
2196 if (sizeof(struct ka_cpwRequest) % 8)
2197 return KAINTERNALERROR;
2198 if (version != KAMAJORVERSION)
2199 return KAOLDINTERFACE;
2201 memset(info, 0, sizeof(*info));
2203 info->minorVersion = KAMINORVERSION;
2204 info->host = dynamic_statistics.host;
2205 info->startTime = dynamic_statistics.start_time;
2207 #if (KAMAJORVERSION>5)
2213 info->noAuth = noAuthenticationRequired;
2215 info->dbVersion = ntohl(cheader.version);
2216 info->dbFreePtr = ntohl(cheader.freePtr);
2217 info->dbEofPtr = ntohl(cheader.eofPtr);
2218 info->dbKvnoPtr = ntohl(cheader.kvnoPtr);
2219 info->dbSpecialKeysVersion = ntohl(cheader.specialKeysVersion);
2221 info->dbHeaderRead = cheaderReadTime;
2222 info->lastTrans = lastTrans;
2224 lastOperation = "(Not Available)";
2225 strncpy(info->lastOperation, lastOperation, sizeof(info->lastOperation));
2226 strncpy(info->lastAuth, authPrincipal, sizeof(info->lastAuth));
2227 strncpy(info->lastTGS, tgsPrincipal, sizeof(info->lastTGS));
2228 strncpy(info->lastAdmin, adminPrincipal, sizeof(info->lastAdmin));
2229 strncpy(info->lastTGSServer, tgsServerPrincipal,
2230 sizeof(info->lastTGSServer));
2232 extern char udpAuthPrincipal[256];
2233 extern char udptgsPrincipal[256];
2234 extern char udptgsServerPrincipal[256];
2236 strncpy(info->lastUAuth, udpAuthPrincipal, sizeof(info->lastUAuth));
2237 strncpy(info->lastUTGS, udptgsPrincipal, sizeof(info->lastUTGS));
2238 strncpy(info->lastUTGSServer, udptgsServerPrincipal,
2239 sizeof(info->lastUTGSServer));
2241 info->nextAutoCPW = nextAutoCPWTime;
2242 info->updatesRemaining = autoCPWUpdates - totalUpdates;
2243 ka_debugKeyCache(info);
2247 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2248 * a tacked-on-the-side data file.
2249 * prob'ly ought to check the noauth flag.
2251 #define ABORTIF(A) {if((code = A)){goto abort;}}
2253 SKAM_Unlock(struct rx_call *call,
2262 struct ubik_trans *tt;
2265 struct kaentry tentry;
2268 if (!name_instance_legal(aname, ainstance)) {
2272 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2275 ABORTIF(check_auth(call, tt, 1, &caller));
2276 ABORTIF(FindBlock(tt, aname, ainstance, &to, &tentry));
2277 ABORTIF((to == 0 ? KANOENT : 0));
2279 kaux_write(to, 0, 0); /* zero failure counters at this offset */
2281 code = ubik_EndTrans(tt);
2282 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
2288 ubik_AbortTrans(tt);
2291 osi_auditU(call, UnlockEvent, code, AUD_STR, aname, AUD_STR, ainstance,
2297 SKAM_LockStatus(struct rx_call *call,
2300 afs_int32 *lockeduntil,
2307 struct ubik_trans *tt;
2308 afs_int32 callerIndex;
2310 struct kaentry caller;
2311 struct kaentry tentry;
2314 COUNT_REQ(LockStatus);
2316 if (!name_instance_legal(aname, ainstance)) {
2320 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2323 if ((code = check_auth(call, tt, 0, &callerIndex)))
2326 if (!noAuthenticationRequired && callerIndex) {
2327 if (karead(tt, callerIndex, &caller, sizeof(caller))) {
2331 /* if the user is checking his own entry or ADMIN then go ahead. */
2332 if ((strcmp(caller.userID.name, aname) != 0)
2333 && !(ntohl(caller.flags) & KAFADMIN)) {
2339 if ((code = FindBlock(tt, aname, ainstance, &to, &tentry)))
2347 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
2350 kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp);
2352 code = ubik_EndTrans(tt);
2357 ubik_AbortTrans(tt);
2358 osi_auditU(call, LockStatusEvent, code, AUD_STR, aname, AUD_STR,
2359 ainstance, AUD_END);