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>
19 #include <sys/types.h>
22 #include <afs/afsutil.h>
24 #include <sys/resource.h>
37 #include <netinet/in.h>
41 #include <afs/cellconfig.h>
47 #include "afs/audit.h"
49 extern struct ubik_dbase *KA_dbase;
50 struct kaheader cheader;
51 Date cheaderReadTime; /* time cheader last read in */
52 extern struct afsconf_dir *KA_conf; /* for getting cell info */
54 afs_int32 kamCreateUser(), ChangePassWord(), kamSetPassword(), kamSetFields(),
56 afs_int32 kamGetEntry(), kamListEntry(), kamGetStats(), kamGetPassword(),
57 kamGetRandomKey(), kamDebug();
58 char lrealm[MAXKTCREALMLEN];
60 #ifndef EXPIREPW /* password expiration default yes */
64 #ifndef AUTOCPWINTERVAL
65 #define AUTOCPWINTERVAL (24*3600)
67 #ifndef AUTOCPWUPDATES
68 #define AUTOCPWUPDATES 128
73 static afs_int32 autoCPWInterval;
74 static afs_int32 autoCPWUpdates;
76 static afs_int32 set_password(); /* forward */
77 extern afs_int32 InitAuthServ(); /* forward */
78 static afs_int32 impose_reuse_limits(); /* forward */
79 static int create_user(); /* forward */
81 /* This routine is called whenever an RPC interface needs the time. It uses
82 the current time to randomize a 128 bit value that is used to change the
83 AuthServer Admin and TGS keys automatically. */
85 static Date nextAutoCPWTime = 0;
86 static afs_int32 totalUpdates = 0;
88 /* This routine is ostensibly to get the current time, but basically its job is
89 to periodically update a random number. It also periodically updates the
90 keys for the builtin servers. This is why it needs a transaction pointer
91 and returns an error code. If the caller is in a read transaction, the tt
92 ptr should be zero and the return code need not be checked. */
95 get_time(timeP, tt, admin)
97 struct ubik_trans *tt; /* tt != 0: a write transaction */
98 int admin; /* the caller is an admin user */
100 /* random value used to change Admin & TGS keys, this is at risk during
101 * multi-threaded operation, but I think the consequences are fairly
103 static afs_uint32 random_value[4];
106 unsigned int bit, nbit;
110 gettimeofday(&time, 0);
111 bit = (random_value[3] >> 31) & 1; /* get high bit of high word */
112 for (i = 0; i < 4; i++) {
113 nbit = random_value[i] >> 31;
114 random_value[i] = (random_value[i] << 1) + bit;
117 /* get 60ths from usec. This is all the real randomness there is. */
118 random_value[0] += time.tv_usec / 16667;
120 if (nextAutoCPWTime == 0) { /* initialize things */
121 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
122 memcpy(&random_value[0], &time, 8);
123 memcpy(&random_value[2], &time, 8);
126 if ((++totalUpdates >= autoCPWUpdates) && tt && /* a write transaction */
127 ((admin && (time.tv_sec >= nextAutoCPWTime))
128 || (time.tv_sec >= nextAutoCPWTime + autoCPWInterval))) {
129 struct ktc_encryptionKey key;
130 char buf[4 * sizeof(key) + 1];
131 struct kaentry tentry;
133 char bob[KA_TIMESTR_LEN];
135 ka_timestr(time.tv_sec, bob, KA_TIMESTR_LEN);
136 es_Report("Auto CPW at %s\n", bob);
138 es_Report(" ... even though no ADMIN user\n");
140 code = FindBlock(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &to, &tentry);
143 if (to) { /* check if auto cpw is disabled */
144 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
145 memcpy(&key, &random_value[0], sizeof(key));
146 des_fixup_key_parity(&key);
148 set_password(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
151 des_init_random_number_generator(&key);
152 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
154 es_Report("New Admin key is %s\n", buf);
157 ("in get_time: set_password failed because: %d\n",
164 code = FindBlock(tt, KA_TGS_NAME, lrealm, &to, &tentry);
167 if (to) { /* check if auto cpw is disabled */
168 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
169 memcpy(&key, &random_value[2], sizeof(key));
170 des_fixup_key_parity(&key);
171 code = set_password(tt, KA_TGS_NAME, lrealm, &key, 0, 0);
173 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
175 es_Report("New TGS key is %s\n", buf);
178 ("in get_time: set_password failed because: %s\n",
179 error_message(code));
184 code = ka_FillKeyCache(tt); /* ensure in-core copy is uptodate */
188 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
192 *timeP = time.tv_sec;
196 static int noAuthenticationRequired; /* global state */
197 static int recheckNoAuth; /* global state */
199 /* kaprocsInited is sort of a lock: during a transaction only one process runs
200 while kaprocsInited is false. */
202 static int kaprocsInited = 0;
204 /* This variable is protected by the kaprocsInited flag. */
206 static int (*rebuildDatabase) ();
208 /* This is called to initialize the database */
211 initialize_database(tt)
212 struct ubik_trans *tt;
214 struct ktc_encryptionKey key;
217 gettimeofday((struct timeval *)&key, 0); /* this is just a cheap seed key */
218 des_fixup_key_parity(&key);
219 des_init_random_number_generator(&key);
220 if ((code = des_random_key(&key))
222 create_user(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
223 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
225 if ((code = des_random_key(&key))
227 create_user(tt, KA_TGS_NAME, lrealm, &key, 0,
228 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
233 /* This routine handles initialization required by this module. The initFlags
234 parameter passes some information about the command line arguments. */
237 init_kaprocs(lclpath, initFlags)
242 struct ubik_trans *tt;
243 struct ktc_encryptionKey key;
248 return KAINTERNALERROR;
250 return KAINTERNALERROR;
251 code = afsconf_GetLocalCell(KA_conf, lrealm, sizeof(lrealm));
253 printf("** Can't determine local cell name!\n");
256 ucstring(lrealm, lrealm, sizeof(lrealm));
260 noAuthenticationRequired = 1;
264 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
265 if (noAuthenticationRequired)
266 printf("Running server with security disabled\n");
269 autoCPWInterval = 10;
272 autoCPWInterval = AUTOCPWINTERVAL;
273 autoCPWUpdates = AUTOCPWUPDATES;
276 init_kadatabase(initFlags);
277 rebuildDatabase = initialize_database;
279 if (code = InitAuthServ(&tt, LOCKREAD, 0)) {
280 printf("init_kaprocs: InitAuthServ failed: code = %d\n", code);
283 code = ka_LookupKey(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &kvno, &key);
287 ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n",
291 des_init_random_number_generator(&key);
293 code = ubik_EndTrans(tt);
295 printf("init_kaprocs: ubik_EndTrans failed: code = %d\n", code);
299 kaux_opendb(lclpath); /* aux database stores failure counters */
300 rebuildDatabase = 0; /* only do this during init */
305 /* These variable are for returning debugging info about the state of the
306 server. If they get trashed during multi-threaded operation it doesn't
309 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
310 char *lastOperation = 0; /* name of last operation */
311 static Date lastTrans; /* time of last transaction */
313 static char adminPrincipal[256];
314 static char authPrincipal[256];
315 static char tgsPrincipal[256];
316 static char tgsServerPrincipal[256];
319 save_principal(p, n, i, c)
330 if (i && strlen(i)) {
340 if (c && strlen(c)) {
352 check_auth(call, at, admin, acaller_id)
353 struct rx_call *call;
354 struct ubik_trans *at;
355 int admin; /* require caller to be ADMIN */
356 afs_int32 *acaller_id;
359 char name[MAXKTCNAMELEN];
360 char instance[MAXKTCNAMELEN];
361 char cell[MAXKTCREALMLEN];
363 Date expiration; /* checked by Security Module */
364 struct kaentry tentry;
371 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
373 si = rx_SecurityClassOf(rx_ConnectionOf(call));
374 if (si == RX_SCINDEX_VAB) {
375 printf("No support for VAB security module yet.\n");
377 } else if (si == RX_SCINDEX_NULL) {
380 } else if (si != RX_SCINDEX_KAD) {
381 es_Report("Unknown security index %d\n", si);
386 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration, name,
387 instance, cell, &kvno);
391 if (level != rxkad_crypt) {
392 es_Report("Incorrect security level = %d\n", level);
397 if (!name_instance_legal(name, instance))
401 ("Authorization rejected because we don't understand intercell stuff yet: ",
403 printf("@%s\n", cell);
407 code = FindBlock(at, name, instance, acaller_id, &tentry);
410 if (*acaller_id == 0) {
411 ka_PrintUserID("User ", name, instance, " unknown.\n");
414 save_principal(adminPrincipal, name, instance, 0);
417 if (!(ntohl(tentry.flags) & KAFADMIN)) {
418 if (noAuthenticationRequired) {
419 ka_PrintUserID("Authorization approved for ", name, instance,
420 " because there is no authentication required\n");
421 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR,
422 instance, AUD_STR, cell, AUD_END);
425 ka_PrintUserID("User ", name, instance, " is not ADMIN.\n");
428 osi_auditU(call, UseOfPrivilegeEvent, code, AUD_STR, name, AUD_STR,
429 instance, AUD_STR, cell, AUD_END);
434 if (noAuthenticationRequired) {
436 ("Caller w/o authorization approved no authentication required\n");
437 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR, instance,
438 AUD_STR, cell, AUD_END);
441 return code; /* no auth info */
445 AwaitInitialization()
448 while (!kaprocsInited) {
451 else if (time(0) - start > 5)
458 /* This is called by every RPC interface to create a Ubik transaction and read
459 the database header into core */
462 InitAuthServ(tt, lock, this_op)
463 struct ubik_trans **tt;
464 int lock; /* indicate read/write transaction */
465 int *this_op; /* opcode of RPC proc, for COUNT_ABO */
468 afs_int32 start = 0; /* time started waiting for quorum */
469 float wait = 0.91; /* start waiting for 1 second */
471 /* Wait for server initialization to finish if not during init_kaprocs */
473 if (code = AwaitInitialization())
476 for (code = UNOQUORUM; code == UNOQUORUM;) {
477 if (lock == LOCKREAD)
478 code = ubik_BeginTransReadAny(KA_dbase, UBIK_READTRANS, tt);
480 code = ubik_BeginTrans(KA_dbase, UBIK_WRITETRANS, tt);
481 if (code == UNOQUORUM) { /* no quorum elected */
485 int delay = time(0) - start;
486 if (this_op) { /* punt quickly, if RPC call */
489 } else { /* more patient during init. */
494 printf("Waiting for quorum election.\n");
497 IOMGR_Sleep((int)wait);
502 if (code = ubik_SetLock(*tt, 1, 1, lock)) {
505 ubik_AbortTrans(*tt);
508 /* check that dbase is initialized and setup cheader */
509 if (lock == LOCKREAD) {
510 /* init but don't fix because this is read only */
511 code = CheckInit(*tt, 0);
513 ubik_AbortTrans(*tt); /* abort, since probably I/O error */
514 /* we did the check under a ReadAny transaction, but now, after
515 * getting a write transaction (and thus some real guarantees
516 * about what databases are really out there), we will check again
517 * in CheckInit before nuking the database. Since this may now get
518 * a UNOQUORUM we'll just do this from the top.
520 if (code = InitAuthServ(tt, LOCKWRITE, this_op))
522 if (code = ubik_EndTrans(*tt))
525 /* now open the read transaction that was originally requested. */
526 return InitAuthServ(tt, lock, this_op);
529 if (code = CheckInit(*tt, rebuildDatabase)) {
532 ubik_AbortTrans(*tt);
537 ka_FillKeyCache(*tt); /* ensure in-core copy is uptodate */
541 /* returns true if name is specially known by AuthServer */
544 special_name(name, instance)
548 return ((!strcmp(name, KA_TGS_NAME) && !strcmp(instance, lrealm))
549 || (strcmp(name, KA_ADMIN_NAME) == 0));
553 create_user(tt, name, instance, key, caller, flags)
554 struct ubik_trans *tt;
563 struct kaentry tentry;
564 afs_int32 maxLifetime;
566 code = FindBlock(tt, name, instance, &to, &tentry);
570 return KAEXIST; /* name already exists, we fail */
572 to = AllocBlock(tt, &tentry);
576 /* otherwise we have a block */
577 strncpy(tentry.userID.name, name, sizeof(tentry.userID.name));
578 strncpy(tentry.userID.instance, instance, sizeof(tentry.userID.instance));
579 tentry.flags = htonl(flags);
580 if (special_name(name, instance)) { /* this overrides key & version */
581 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
582 tentry.key_version = htonl(-1); /* don't save this key */
583 if (code = ka_NewKey(tt, to, &tentry, key))
586 memcpy(&tentry.key, key, sizeof(tentry.key));
587 tentry.key_version = htonl(0);
589 tentry.user_expiration = htonl(NEVERDATE);
590 code = get_time(&tentry.modification_time, tt, 1);
594 /* time and addr of entry for guy changing this entry */
595 tentry.modification_time = htonl(tentry.modification_time);
596 tentry.modification_id = htonl(caller);
597 tentry.change_password_time = tentry.modification_time;
599 if (strcmp(name, KA_TGS_NAME) == 0)
600 maxLifetime = MAXKTCTICKETLIFETIME;
601 else if (strcmp(name, KA_ADMIN_NAME) == 0)
602 maxLifetime = 10 * 3600;
603 else if (strcmp(name, AUTH_SUPERUSER) == 0)
604 maxLifetime = 100 * 3600;
606 maxLifetime = 25 * 3600; /* regular users */
607 tentry.max_ticket_lifetime = htonl(maxLifetime);
609 code = ThreadBlock(tt, to, &tentry);
613 /* Put actual stub routines here */
616 SKAM_CreateUser(call, aname, ainstance, ainitpw)
617 struct rx_call *call;
620 EncryptionKey ainitpw;
624 code = kamCreateUser(call, aname, ainstance, ainitpw);
625 osi_auditU(call, AFS_KAM_CrUserEvent, code, AUD_STR, aname, AUD_STR,
632 kamCreateUser(call, aname, ainstance, ainitpw)
633 struct rx_call *call;
636 EncryptionKey ainitpw;
639 struct ubik_trans *tt;
640 afs_int32 caller; /* Disk offset of caller's entry */
642 COUNT_REQ(CreateUser);
643 if (!des_check_key_parity(&ainitpw) || des_is_weak_key(&ainitpw))
645 if (!name_instance_legal(aname, ainstance))
647 if (code = InitAuthServ(&tt, LOCKWRITE, this_op))
649 code = check_auth(call, tt, 1, &caller);
655 code = create_user(tt, aname, ainstance, &ainitpw, caller, KAFNORMAL);
661 code = ubik_EndTrans(tt);
662 KALOG(aname, ainstance, NULL, NULL, NULL,
663 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
669 SKAA_ChangePassword(call, aname, ainstance, arequest, oanswer)
670 struct rx_call *call;
678 code = ChangePassWord(call, aname, ainstance, arequest, oanswer);
679 osi_auditU(call, AFS_KAA_ChPswdEvent, code, AUD_STR, aname, AUD_STR,
685 ChangePassWord(call, aname, ainstance, arequest, oanswer)
686 struct rx_call *call;
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(password, tentry)
789 EncryptionKey *password;
790 struct kaentry *tentry;
798 if (!tentry->pwsums[0] && npwSums > 1 && !tentry->pwsums[1])
799 return 0; /* password reuse limits not in effect */
801 code = get_time(&now, 0, 0);
805 if ((now - ntohl(tentry->change_password_time)) < MinHours * 60 * 60)
808 if (!memcmp(password, &(tentry->key), sizeof(EncryptionKey)))
811 code = ka_KeyCheckSum((char *)password, &newsum);
815 newsum = newsum & 0x000000ff;
816 for (i = 0; i < npwSums; i++) {
817 if (newsum == tentry->pwsums[i])
826 set_password(tt, name, instance, password, kvno, caller)
827 struct ubik_trans *tt;
830 EncryptionKey *password;
835 afs_int32 to; /* offset of block */
836 struct kaentry tentry;
842 code = FindBlock(tt, name, instance, &to, &tentry);
846 return KANOENT; /* no such user */
848 /* if password reuse limits in effect, set the checksums, the hard way */
849 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
850 /* do nothing, no limits */ ;
852 code = ka_KeyCheckSum((char *)&(tentry.key), &newsum);
855 for (i = npwSums - 1; i; i--)
856 tentry.pwsums[i] = tentry.pwsums[i - 1];
857 tentry.pwsums[0] = newsum & 0x000000ff;
861 if (special_name(name, instance)) { /* set key over rides key_version */
862 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
863 if (code = ka_NewKey(tt, to, &tentry, password))
866 memcpy(&tentry.key, password, sizeof(tentry.key));
868 kvno = ntohl(tentry.key_version);
869 if ((kvno < 1) || (kvno >= MAXKAKVNO))
874 tentry.key_version = htonl((afs_int32) kvno); /* requested key version */
879 /* no-write prevents recursive call to set_password by AuthCPW code. */
880 code = get_time(&now, 0, 0);
884 tentry.modification_time = htonl(now);
885 tentry.modification_id = htonl(caller);
888 tentry.change_password_time = htonl(now);
890 if (code = kawrite(tt, to, &tentry, sizeof(tentry)))
896 SKAM_SetPassword(call, aname, ainstance, akvno, apassword)
897 struct rx_call *call;
901 EncryptionKey apassword;
905 code = kamSetPassword(call, aname, ainstance, akvno, apassword);
906 osi_auditU(call, AFS_KAM_SetPswdEvent, code, AUD_STR, aname, AUD_STR,
912 kamSetPassword(call, aname, ainstance, akvno, apassword)
913 struct rx_call *call;
917 EncryptionKey apassword;
920 struct ubik_trans *tt;
921 afs_int32 caller; /* Disk offset of caller's entry */
922 struct kaentry tentry;
924 COUNT_REQ(SetPassword);
925 if (akvno > MAXKAKVNO)
926 return KABADARGUMENT;
927 if (!des_check_key_parity(&apassword) || des_is_weak_key(&apassword))
930 if (!name_instance_legal(aname, ainstance))
932 if (code = InitAuthServ(&tt, LOCKWRITE, this_op))
934 code = check_auth(call, tt, 0, &caller);
938 if (code = karead(tt, caller, &tentry, sizeof(tentry))) {
942 /* if the user is changing his own password or ADMIN then go ahead. */
943 if ((strcmp(tentry.userID.name, aname) == 0)
944 && (strcmp(tentry.userID.instance, ainstance) == 0)) {
945 if (ntohl(tentry.flags) & KAFNOCPW)
948 code = impose_reuse_limits(&apassword, &tentry);
951 set_password(tt, aname, ainstance, &apassword, akvno, 0);
953 } else if (ntohl(tentry.flags) & KAFADMIN) {
954 code = set_password(tt, aname, ainstance, &apassword, akvno, caller);
960 code = ubik_EndTrans(tt);
961 KALOG(aname, ainstance, NULL, NULL, NULL,
962 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_CHPASSWD);
972 CoerseLifetime(start, end)
975 unsigned char kerberosV4Life;
976 kerberosV4Life = time_to_life(start, end);
977 end = life_to_time(start, kerberosV4Life);
982 GetEndTime(start, reqEnd, expiration, caller, server, endP)
983 IN Date start; /* start time of ticket */
984 IN Date reqEnd; /* requested end time */
985 IN Date expiration; /* authorizing ticket's expiration */
986 IN struct kaentry *caller;
987 IN struct kaentry *server;
988 OUT Date *endP; /* actual end time */
994 if (ntohl(caller->flags) & KAFNOTGS)
995 return KABADUSER; /* no new tickets for this user */
996 if (expiration && (ntohl(server->flags) & KAFNOSEAL))
997 return KABADSERVER; /* can't be target of GetTicket req */
999 expiration = NEVERDATE;
1001 cExp = ntohl(caller->user_expiration);
1002 sExp = ntohl(server->user_expiration);
1007 cLife = start + ntohl(caller->max_ticket_lifetime);
1008 sLife = start + ntohl(server->max_ticket_lifetime);
1010 umin(umin(reqEnd, expiration),
1011 umin(umin(cLife, sLife), umin(cExp, sExp)));
1012 end = CoerseLifetime(start, end);
1018 PrepareTicketAnswer(oanswer, challenge, ticket, ticketLen, sessionKey, start,
1019 end, caller, server, cell, label)
1021 afs_int32 challenge;
1023 afs_int32 ticketLen;
1024 struct ktc_encryptionKey *sessionKey;
1026 struct kaentry *caller, *server;
1031 struct ka_ticketAnswer *answer;
1034 code = KAANSWERTOOLONG;
1035 if (oanswer->MaxSeqLen <
1036 sizeof(struct ka_ticketAnswer) - 5 * MAXKTCNAMELEN - MAXKTCTICKETLEN +
1040 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
1041 answer->challenge = htonl(challenge);
1042 memcpy(&answer->sessionKey, sessionKey, sizeof(struct ktc_encryptionKey));
1043 answer->startTime = htonl(start);
1044 answer->endTime = htonl(end);
1045 answer->kvno = server->key_version;
1046 answer->ticketLen = htonl(ticketLen);
1049 char *ans = answer->name; /* pointer to variable part */
1050 int rem; /* space remaining */
1051 int len; /* macro temp. */
1053 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1055 #define putstr(str) len = strlen (str)+1;\
1056 if (rem < len) return code;\
1058 ans += len; rem -= len
1059 putstr(caller->userID.name);
1060 putstr(caller->userID.instance);
1062 putstr(server->userID.name);
1063 putstr(server->userID.instance);
1064 if (rem < ticketLen + KA_LABELSIZE)
1066 memcpy(ans, ticket, ticketLen);
1069 memcpy(ans, label, KA_LABELSIZE);
1071 memset(ans, 0, KA_LABELSIZE);
1072 ans += KA_LABELSIZE;
1073 oanswer->SeqLen = (ans - oanswer->SeqBody);
1076 answer->cksum = htonl(cksum);
1077 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1078 if (oanswer->SeqLen > oanswer->MaxSeqLen)
1083 /* This is used to get a ticket granting ticket or an admininstration ticket.
1084 These two specific, built-in servers are special cases, which require the
1085 client's key as an additional security precaution. The GetTicket operation
1086 is normally disabled for these two principals. */
1089 Authenticate(version, call, aname, ainstance, start, end, arequest, oanswer)
1091 struct rx_call *call;
1099 struct ubik_trans *tt;
1100 afs_int32 to; /* offset of block */
1102 struct kaentry server; /* entry for desired server */
1103 struct ka_gettgtRequest request; /* request after decryption */
1104 int tgt, adm; /* type of request */
1105 char *sname; /* principal of server */
1107 char ticket[MAXKTCTICKETLEN]; /* our copy of the ticket */
1109 struct ktc_encryptionKey sessionKey; /* we have to invent a session key */
1110 char *answer; /* where answer is to be put */
1111 int answer_len; /* length of answer packet */
1112 Date answer_time; /* 1+ request time in network order */
1113 afs_int32 temp; /* for htonl conversions */
1114 des_key_schedule user_schedule; /* key schedule for user's key */
1115 afs_int32 tgskvno; /* key version of service key */
1116 struct ktc_encryptionKey tgskey; /* service key for encrypting ticket */
1118 afs_uint32 pwexpires;
1120 COUNT_REQ(Authenticate);
1121 if (!name_instance_legal(aname, ainstance))
1123 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
1125 get_time(&now, 0, 0);
1127 sname = sinst = NULL;
1129 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1133 if (to == 0) { /* no such user */
1138 /* have to check for locked before verifying the password, otherwise all
1139 * KALOCKED means is "yup, you guessed the password all right, now wait a
1140 * few minutes and we'll let you in"
1143 (to, (u_int) tentry.misc_auth_bytes[ATTEMPTS],
1144 (afs_uint32) tentry.misc_auth_bytes[LOCKTIME] << 9)) {
1150 save_principal(authPrincipal, aname, ainstance, 0);
1152 /* decrypt request w/ user password */
1153 if (code = des_key_sched(&tentry.key, user_schedule))
1154 es_Report("In KAAuthenticate: key_sched returned %d\n", code);
1155 des_pcbc_encrypt(arequest->SeqBody, &request,
1156 min(arequest->SeqLen, sizeof(request)), user_schedule,
1157 &tentry.key, DECRYPT);
1159 request.time = ntohl(request.time); /* reorder date */
1160 tgt = !strncmp(request.label, KA_GETTGT_REQ_LABEL, sizeof(request.label));
1161 adm = !strncmp(request.label, KA_GETADM_REQ_LABEL, sizeof(request.label));
1162 if (!(tgt || adm)) {
1163 kaux_inc(to, ((unsigned char)tentry.misc_auth_bytes[LOCKTIME]) << 9);
1164 code = KABADREQUEST;
1167 kaux_write(to, 0, 0); /* reset counters */
1170 if (!tentry.misc_auth_bytes[EXPIRES]) {
1171 /* 0 in the database means never, but 0 on the network means today */
1172 /* 255 on the network means "long time, maybe never" */
1175 pwexpires = tentry.misc_auth_bytes[EXPIRES];
1178 ntohl(tentry.change_password_time) + 24 * 60 * 60 * pwexpires;
1179 if (adm) { /* provide a little slack for admin ticket */
1180 pwexpires += 30 * 24 * 60 * 60; /* 30 days */
1182 if (pwexpires < now) {
1186 pwexpires = (pwexpires - now) / (24 * 60 * 60);
1187 if (pwexpires > 255)
1191 #endif /* EXPIREPW */
1193 if (abs(request.time - now) > KTC_TIME_UNCERTAINTY) {
1195 if (oanswer->MaxSeqLen < sizeof(afs_int32))
1196 code = KAANSWERTOOLONG;
1197 else { /* return our time if possible */
1198 oanswer->SeqLen = sizeof(afs_int32);
1199 request.time = htonl(now);
1200 memcpy(oanswer->SeqBody, &request.time, sizeof(afs_int32));
1206 sname = (tgt ? KA_TGS_NAME : KA_ADMIN_NAME);
1207 sinst = (tgt ? lrealm : KA_ADMIN_INST);
1208 code = FindBlock(tt, sname, sinst, &to, &server);
1216 tgskvno = ntohl(server.key_version);
1217 memcpy(&tgskey, &server.key, sizeof(tgskey));
1219 code = des_random_key(&sessionKey);
1225 code = GetEndTime(start, end, 0 /*!GetTicket */ , &tentry, &server, &end);
1230 tkt_MakeTicket(ticket, &ticketLen, &tgskey, aname, ainstance, "",
1231 start, end, &sessionKey,
1232 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), sname,
1240 ticketLen + sizeof(Date) + sizeof(struct ktc_encryptionKey) +
1241 2 * sizeof(afs_int32) + KA_LABELSIZE;
1242 answer_len = round_up_to_ebs(answer_len);
1243 if (answer_len > oanswer->MaxSeqLen) {
1244 code = KAANSWERTOOLONG;
1247 oanswer->SeqLen = answer_len;
1248 answer = oanswer->SeqBody;
1249 answer_time = htonl(request.time + 1);
1250 memcpy(answer, (char *)&answer_time, sizeof(Date));
1251 answer += sizeof(Date);
1252 memcpy(answer, (char *)&sessionKey, sizeof(struct ktc_encryptionKey));
1253 answer += sizeof(struct ktc_encryptionKey);
1254 temp = htonl(tgskvno);
1255 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1256 answer += sizeof(afs_int32);
1257 temp = htonl(ticketLen);
1258 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1259 answer += sizeof(afs_int32);
1260 memcpy(answer, ticket, ticketLen);
1261 answer += ticketLen;
1262 memcpy(answer, (tgt ? KA_GETTGT_ANS_LABEL : KA_GETADM_ANS_LABEL),
1268 PrepareTicketAnswer(oanswer, request.time + 1, ticket, ticketLen,
1269 &sessionKey, start, end, &tentry, &server, "",
1270 (tgt ? KA_GETTGT_ANS_LABEL :
1271 KA_GETADM_ANS_LABEL));
1276 && oanswer->SeqLen < oanswer->MaxSeqLen + sizeof(afs_int32)) {
1277 temp = pwexpires << 24; /* move it into the high byte */
1278 pwexpires = htonl(temp);
1280 memcpy((char *)oanswer->SeqBody + oanswer->SeqLen, &pwexpires,
1282 oanswer->SeqLen += sizeof(afs_int32);
1283 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1284 if (oanswer->SeqLen > oanswer->MaxSeqLen) {
1285 code = KAANSWERTOOLONG;
1289 #endif /* EXPIREPW */
1293 code = KAINTERNALERROR;
1296 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1297 user_schedule, &tentry.key, ENCRYPT);
1298 code = ubik_EndTrans(tt);
1299 KALOG(aname, ainstance, sname, sinst, NULL,
1300 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_AUTHENTICATE);
1305 ubik_AbortTrans(tt);
1306 KALOG(aname, ainstance, sname, sinst, NULL,
1307 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_AUTHFAILED);
1312 SKAA_Authenticate_old(call, aname, ainstance, start, end, arequest, oanswer)
1313 struct rx_call *call;
1322 IOMGR_Sleep(1); /* discourage use of this mechanism */
1324 Authenticate(0, call, aname, ainstance, start, end, arequest,
1326 osi_auditU(call, AFS_KAA_AuthOEvent, code, AUD_STR, aname, AUD_STR,
1327 ainstance, AUD_END);
1333 SKAA_Authenticate(call, aname, ainstance, start, end, arequest, oanswer)
1334 struct rx_call *call;
1344 Authenticate(1, call, aname, ainstance, start, end, arequest,
1346 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1347 ainstance, AUD_END);
1353 SKAA_AuthenticateV2(call, aname, ainstance, start, end, arequest, oanswer)
1354 struct rx_call *call;
1364 Authenticate(2, call, aname, ainstance, start, end, arequest,
1366 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1367 ainstance, AUD_END);
1373 SKAM_SetFields(call, aname, ainstance, aflags, aexpiration, alifetime,
1374 amaxAssociates, misc_auth_bytes, spare2)
1375 struct rx_call *call;
1380 afs_int32 alifetime;
1381 afs_int32 amaxAssociates;
1382 afs_uint32 misc_auth_bytes; /* 4 bytes, each 0 means unspecified */
1388 kamSetFields(call, aname, ainstance, aflags, aexpiration, alifetime,
1389 amaxAssociates, misc_auth_bytes, spare2);
1390 osi_auditU(call, AFS_KAM_SetFldEvent, code, AUD_STR, aname, AUD_STR,
1391 ainstance, AUD_LONG, aflags, AUD_DATE, aexpiration, AUD_LONG,
1392 alifetime, AUD_LONG, amaxAssociates, AUD_END);
1397 kamSetFields(call, aname, ainstance, aflags, aexpiration, alifetime,
1398 amaxAssociates, misc_auth_bytes, spare2)
1399 struct rx_call *call;
1404 afs_int32 alifetime;
1405 afs_int32 amaxAssociates;
1406 afs_uint32 misc_auth_bytes; /* 4 bytes, each 0 means unspecified */
1411 struct ubik_trans *tt;
1413 afs_int32 tentry_offset; /* offset of entry */
1414 struct kaentry tentry;
1415 unsigned char newvals[4];
1417 COUNT_REQ(SetFields);
1420 return KABADARGUMENT; /* not supported yet... */
1422 /* make sure we're supposed to do something */
1423 if (!(aflags || aexpiration || alifetime || (amaxAssociates >= 0)
1425 || ((aflags & ~KAFNORMAL) & ~KAF_SETTABLE_FLAGS))
1426 return KABADARGUMENT; /* arguments no good */
1427 if (!name_instance_legal(aname, ainstance))
1429 if (code = InitAuthServ(&tt, LOCKWRITE, this_op))
1431 code = check_auth(call, tt, 1, &caller);
1436 code = FindBlock(tt, aname, ainstance, &tentry_offset, &tentry);
1439 if (tentry_offset == 0) { /* no such user */
1443 if ((ntohl(tentry.flags) & KAFNORMAL) == 0)
1444 return KAINTERNALERROR;
1446 /* Keep track of the total number of admin accounts. This way we can
1447 * update database without any admin privilege initially */
1448 if ((aflags & KAFADMIN) != (ntohl(tentry.flags) & KAFADMIN)) {
1449 /* if admin state is changing */
1451 if (ntohl(tentry.flags) & KAFADMIN)
1455 if (code = update_admin_count(tt, delta))
1459 htonl((ntohl(tentry.flags) & ~KAF_SETTABLE_FLAGS) | aflags);
1461 if (code = get_time(&now, tt, 1))
1464 tentry.user_expiration = htonl(aexpiration);
1465 if (!ntohl(tentry.change_password_time)) {
1466 tentry.change_password_time = htonl(now);
1470 tentry.max_ticket_lifetime = htonl(alifetime);
1472 #ifndef NOPWCONTROLS
1474 * We've packed a bunch of bytes into a long for backward compatibility.
1475 * These include password expiration time, and some failed login limits
1476 * counters. Now let's unpack them and stick them into the
1477 * kaentry struct. All the bytes have values in the range
1478 * 1..255, else they were not specified in the interface, and are
1480 * In the case of password expiration times, 1 means password never
1481 * expires (==>0), 2 means password only lives for one day (==>1),
1484 if (misc_auth_bytes) {
1485 unpack_long(misc_auth_bytes, newvals);
1486 if (newvals[EXPIRES]) {
1487 tentry.misc_auth_bytes[EXPIRES] = newvals[EXPIRES] - 1;
1490 if (newvals[REUSEFLAGS]) {
1491 if (newvals[REUSEFLAGS] & KA_REUSEPW)
1492 memset(tentry.pwsums, 0, KA_NPWSUMS);
1493 else if ((newvals[REUSEFLAGS] & KA_NOREUSEPW)
1494 && !tentry.pwsums[0])
1495 tentry.pwsums[0] = 0xff;
1498 if (newvals[ATTEMPTS]) {
1499 tentry.misc_auth_bytes[ATTEMPTS] = newvals[ATTEMPTS] - 1;
1501 if (newvals[LOCKTIME]) {
1502 tentry.misc_auth_bytes[LOCKTIME] = newvals[LOCKTIME] - 1;
1505 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1508 #endif /* NOPWCONTROLS */
1510 if (amaxAssociates >= 0) {
1511 if ((ntohl(tentry.flags) & KAFASSOC)
1512 || (ntohl(tentry.flags) & KAFSPECIAL))
1514 if (((ntohl(tentry.flags) & KAFASSOCROOT) == 0) && (amaxAssociates > 0)) /* convert normal user to assoc root */
1515 tentry.flags = htonl(ntohl(tentry.flags) | KAFASSOCROOT);
1516 tentry.misc.assocRoot.maxAssociates = htonl(amaxAssociates);
1519 tentry.modification_time = htonl(now);
1520 tentry.modification_id = htonl(caller);
1521 code = kawrite(tt, tentry_offset, &tentry, sizeof(tentry));
1525 code = ubik_EndTrans(tt);
1526 KALOG(aname, ainstance, NULL, NULL, NULL,
1527 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_SETFIELDS);
1532 ubik_AbortTrans(tt);
1539 SKAM_DeleteUser(call, aname, ainstance)
1540 struct rx_call *call;
1546 code = kamDeleteUser(call, aname, ainstance);
1547 osi_auditU(call, AFS_KAM_DelUserEvent, code, AUD_STR, aname, AUD_STR,
1548 ainstance, AUD_END);
1553 kamDeleteUser(call, aname, ainstance)
1554 struct rx_call *call;
1559 struct ubik_trans *tt;
1562 struct kaentry tentry;
1564 afs_uint32 locktime;
1566 COUNT_REQ(DeleteUser);
1567 if (!name_instance_legal(aname, ainstance))
1569 if (code = InitAuthServ(&tt, LOCKWRITE, this_op))
1571 code = check_auth(call, tt, 1, &caller);
1575 ubik_AbortTrans(tt);
1579 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1582 if (to == 0) { /* name not found */
1587 kaux_read(to, &nfailures, &locktime);
1588 if (nfailures || locktime)
1589 kaux_write(to, 0, 0); /* zero failure counters at this offset */
1591 /* track all AuthServer identities */
1592 if (special_name(aname, ainstance))
1593 if (code = ka_DelKey(tt, to, &tentry))
1596 if (ntohl(tentry.flags) & KAFADMIN) /* keep admin count up-to-date */
1597 if (code = update_admin_count(tt, -1))
1600 if ((code = UnthreadBlock(tt, &tentry)) || (code = FreeBlock(tt, to)) || (code = get_time(0, tt, 1)) /* update randomness */
1604 code = ubik_EndTrans(tt);
1605 KALOG(aname, ainstance, NULL, NULL, NULL,
1606 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_DELUSER);
1610 /* we set a bit in here which indicates that the user's limit of
1611 * authentication failures has been exceeded. If that bit is not set,
1612 * kas can take it on faith that the user ID is not locked. If that
1613 * bit is set, kas has to check all the servers to find one who will
1614 * report that the ID is not locked, or else to find out when the ID
1618 SKAM_GetEntry(call, aname, ainstance, aversion, aentry)
1619 struct rx_call *call;
1622 afs_int32 aversion; /* major version assumed by caller */
1623 kaentryinfo *aentry; /* entry data copied here */
1627 code = kamGetEntry(call, aname, ainstance, aversion, aentry);
1628 osi_auditU(call, AFS_KAM_GetEntEvent, code, AUD_STR, aname, AUD_STR,
1629 ainstance, AUD_END);
1634 kamGetEntry(call, aname, ainstance, aversion, aentry)
1635 struct rx_call *call;
1638 afs_int32 aversion; /* major version assumed by caller */
1639 kaentryinfo *aentry; /* entry data copied here */
1641 register afs_int32 code;
1642 struct ubik_trans *tt;
1643 afs_int32 callerIndex;
1644 struct kaentry caller;
1647 struct kaentry tentry;
1648 rxkad_level enc_level = rxkad_clear;
1649 int callerIsAdmin = 0;
1651 COUNT_REQ(GetEntry);
1652 if (aversion != KAMAJORVERSION)
1653 return KAOLDINTERFACE;
1654 if (!name_instance_legal(aname, ainstance))
1656 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
1658 code = check_auth(call, tt, 0, &callerIndex);
1662 if (noAuthenticationRequired) {
1663 } else if (!callerIndex) {
1667 if (code = karead(tt, callerIndex, &caller, sizeof(caller))) {
1671 /* if the user is checking his own entry or ADMIN then go ahead. */
1672 callerIsAdmin = (ntohl(caller.flags) & KAFADMIN);
1674 if (strcmp(caller.userID.name, aname) != 0 && !callerIsAdmin) {
1680 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1683 if (to == 0) { /* entry not found */
1688 get_time(0, 0, 0); /* generate random update */
1690 memset(aentry, 0, sizeof(*aentry));
1691 aentry->minor_version = KAMINORVERSION;
1692 aentry->flags = ntohl(tentry.flags);
1693 aentry->user_expiration = ntohl(tentry.user_expiration);
1694 aentry->modification_time = ntohl(tentry.modification_time);
1695 aentry->change_password_time = ntohl(tentry.change_password_time);
1696 aentry->max_ticket_lifetime = ntohl(tentry.max_ticket_lifetime);
1697 aentry->key_version = ntohl(tentry.key_version);
1699 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
1701 if (kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp))
1702 tentry.misc_auth_bytes[REUSEFLAGS] |= KA_ISLOCKED; /* saves an RPC */
1704 temp = pack_long(tentry.misc_auth_bytes);
1705 aentry->misc_auth_bytes = temp;
1707 * only return user's key if security disabled or if admin and
1708 * we have an encrypted connection to the user
1710 rxkad_GetServerInfo(call->conn, &enc_level, 0, 0, 0, 0, 0);
1711 if ((noAuthenticationRequired)
1712 || (callerIsAdmin && enc_level == rxkad_crypt))
1713 memcpy(&aentry->key, &tentry.key, sizeof(struct ktc_encryptionKey));
1715 memset(&aentry->key, 0, sizeof(aentry->key));
1716 code = ka_KeyCheckSum((char *)&tentry.key, &aentry->keyCheckSum);
1717 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
1718 aentry->reserved3 = 0x12340000;
1720 aentry->reserved3 = 0x12340001;
1723 /* Now get entry of user who last modified this entry */
1724 if (ntohl(tentry.modification_id)) {
1725 temp = ntohl(tentry.modification_id);
1726 code = karead(tt, temp, &tentry, sizeof(tentry));
1731 aentry->modification_user = tentry.userID;
1733 strcpy(aentry->modification_user.name, "<none>");
1734 strcpy(aentry->modification_user.instance, "\0");
1736 code = ubik_EndTrans(tt);
1741 ubik_AbortTrans(tt);
1746 SKAM_ListEntry(call, previous_index, index, count, name)
1747 struct rx_call *call;
1748 afs_int32 previous_index; /* last entry ret'd or 0 for first */
1749 afs_int32 *index; /* index of this entry */
1750 afs_int32 *count; /* total entries in database */
1751 kaident *name; /* name & instance of this entry */
1755 code = kamListEntry(call, previous_index, index, count, name);
1756 osi_auditU(call, AFS_KAM_LstEntEvent, code, AUD_LONG, *index, AUD_END);
1762 kamListEntry(call, previous_index, index, count, name)
1763 struct rx_call *call;
1764 afs_int32 previous_index; /* last entry ret'd or 0 for first */
1765 afs_int32 *index; /* index of this entry */
1766 afs_int32 *count; /* total entries in database */
1767 kaident *name; /* name & instance of this entry */
1770 struct ubik_trans *tt;
1772 struct kaentry tentry;
1774 COUNT_REQ(ListEntry);
1775 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
1777 code = check_auth(call, tt, 1, &caller);
1782 *index = NextBlock(tt, previous_index, &tentry, count);
1788 if (*index) { /* return name & inst of this entry */
1789 strncpy(name->name, tentry.userID.name, sizeof(name->name));
1790 strncpy(name->instance, tentry.userID.instance,
1791 sizeof(name->instance));
1793 strcpy(name->name, "\0");
1794 strcpy(name->instance, "\0");
1796 code = ubik_EndTrans(tt);
1801 ubik_AbortTrans(tt);
1806 GetTicket(version, call, kvno, authDomain, aticket, sname, sinstance, atimes,
1809 struct rx_call *call;
1815 ka_CBS *atimes; /* encrypted start & end time */
1820 struct ubik_trans *tt;
1821 struct ktc_encryptionKey tgskey;
1822 des_key_schedule schedule;
1824 char name[MAXKTCNAMELEN];
1825 char instance[MAXKTCNAMELEN];
1826 char cell[MAXKTCNAMELEN];
1828 struct kaentry caller;
1829 struct kaentry server;
1830 struct ktc_encryptionKey authSessionKey;
1831 struct ktc_encryptionKey sessionKey;
1833 char ticket[MAXKTCTICKETLEN];
1839 struct ka_getTicketTimes times;
1840 struct ka_getTicketAnswer *answer;
1842 COUNT_REQ(GetTicket);
1843 if (!name_instance_legal(sname, sinstance))
1845 if (atimes->SeqLen != sizeof(times))
1846 return KABADARGUMENT;
1847 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
1850 export = import = 0;
1851 if ((strcmp(sname, KA_TGS_NAME) == 0) && (strcmp(sinstance, lrealm) != 0))
1853 if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0))
1856 if (strlen(authDomain) == 0)
1857 authDomain = lrealm;
1858 code = ka_LookupKvno(tt, KA_TGS_NAME, authDomain, kvno, &tgskey);
1863 tkt_DecodeTicket(aticket->SeqBody, aticket->SeqLen, &tgskey, name,
1864 instance, cell, &authSessionKey, &host, &start,
1870 save_principal(tgsPrincipal, name, instance, cell);
1872 if (code = get_time(&now, 0, 0))
1875 code = tkt_CheckTimes(start, expiration, now);
1878 code = RXKADEXPIRED;
1883 code = des_key_sched(&authSessionKey, schedule);
1888 celllen = strlen(cell);
1889 if (import && (celllen == 0)) {
1893 if (export && (celllen == 0))
1894 strcpy(cell, lrealm);
1896 if (!krb4_cross && celllen && strcmp(lrealm, cell) != 0) {
1901 des_ecb_encrypt(atimes->SeqBody, ×, schedule, DECRYPT);
1902 times.start = ntohl(times.start);
1903 times.end = ntohl(times.end);
1904 code = tkt_CheckTimes(times.start, times.end, now);
1906 code = KABADREQUEST;
1911 strcpy(caller.userID.name, name);
1912 strcpy(caller.userID.instance, instance);
1913 caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
1914 caller.flags = htonl(KAFNORMAL);
1915 caller.user_expiration = htonl(NEVERDATE);
1917 code = FindBlock(tt, name, instance, &to, &caller);
1921 ka_PrintUserID("GetTicket: User ", name, instance, " unknown.\n");
1927 /* get server's entry */
1928 code = FindBlock(tt, sname, sinstance, &to, &server);
1931 if (to == 0) { /* entry not found */
1932 ka_PrintUserID("GetTicket: Server ", sname, sinstance, " unknown.\n");
1936 save_principal(tgsServerPrincipal, sname, sinstance, 0);
1938 code = des_random_key(&sessionKey);
1945 GetEndTime(times.start, times.end, expiration, &caller, &server,
1951 tkt_MakeTicket(ticket, &ticketLen, &server.key, caller.userID.name,
1952 caller.userID.instance, cell, times.start, end,
1954 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
1955 server.userID.name, server.userID.instance);
1961 code = KAANSWERTOOLONG;
1962 if (oanswer->MaxSeqLen <
1963 sizeof(struct ka_getTicketAnswer) - 5 * MAXKTCNAMELEN -
1964 MAXKTCTICKETLEN + ticketLen)
1967 answer = (struct ka_getTicketAnswer *)oanswer->SeqBody;
1968 memcpy(&answer->sessionKey, &sessionKey,
1969 sizeof(struct ktc_encryptionKey));
1970 answer->startTime = htonl(times.start);
1971 answer->endTime = htonl(end);
1972 answer->kvno = server.key_version;
1973 answer->ticketLen = htonl(ticketLen);
1976 char *ans = answer->name; /* ptr to variable part of answer */
1979 /* space remaining */
1980 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1982 #define putstr(str) len = strlen (str)+1;\
1983 if (rem < len) goto abort;\
1985 ans += len; rem -= len
1992 if (rem < ticketLen)
1994 memcpy(ans, ticket, ticketLen);
1995 oanswer->SeqLen = (ans - oanswer->SeqBody) + ticketLen;
1997 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
2001 PrepareTicketAnswer(oanswer, /*challenge */ 0, ticket, ticketLen,
2002 &sessionKey, times.start, end, &caller,
2003 &server, cell, KA_GETTICKET_ANS_LABEL);
2008 code = KAINTERNALERROR;
2011 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
2012 schedule, &authSessionKey, ENCRYPT);
2013 code = ubik_EndTrans(tt);
2014 KALOG(name, instance, sname, sinstance, (import ? authDomain : NULL),
2015 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_GETTICKET);
2020 ubik_AbortTrans(tt);
2025 SKAT_GetTicket_old(call, kvno, authDomain, aticket, sname, sinstance, atimes,
2027 struct rx_call *call;
2033 ka_CBS *atimes; /* encrypted start & end time */
2038 sleep(1); /* strongly discourage this */
2040 GetTicket(0, call, kvno, authDomain, aticket, sname, sinstance,
2043 osi_auditU(call, AFS_KAT_GetTicketOEvent, code, AUD_STR, sname, AUD_STR,
2044 sinstance, AUD_END);
2049 SKAT_GetTicket(call, kvno, authDomain, aticket, sname, sinstance, atimes,
2051 struct rx_call *call;
2057 ka_CBS *atimes; /* encrypted start & end time */
2063 GetTicket(1, call, kvno, authDomain, aticket, sname, sinstance,
2065 osi_auditU(call, AFS_KAT_GetTicketEvent, code, AUD_STR, sname, AUD_STR,
2066 sinstance, AUD_END);
2071 SKAM_GetStats(call, version, admin_accounts, statics, dynamics)
2072 struct rx_call *call;
2074 afs_int32 *admin_accounts;
2080 code = kamGetStats(call, version, admin_accounts, statics, dynamics);
2081 osi_auditU(call, AFS_KAM_GetStatEvent, code, AUD_END);
2086 kamGetStats(call, version, admin_accounts, statics, dynamics)
2087 struct rx_call *call;
2089 afs_int32 *admin_accounts;
2094 struct ubik_trans *tt;
2097 COUNT_REQ(GetStats);
2098 if (version != KAMAJORVERSION)
2099 return KAOLDINTERFACE;
2100 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2102 code = check_auth(call, tt, 1, &caller);
2105 ubik_AbortTrans(tt);
2109 *admin_accounts = ntohl(cheader.admin_accounts);
2110 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
2111 /* these are stored in network byte order and must be copied */
2112 statics->allocs = ntohl(cheader.stats.allocs);
2113 statics->frees = ntohl(cheader.stats.frees);
2114 statics->cpws = ntohl(cheader.stats.cpws);
2115 #if KADBVERSION != 5
2116 check that the statistics command copies all the fields
2118 memcpy((char *)dynamics, (char *)&dynamic_statistics, sizeof(kadstats));
2119 statics->minor_version = KAMINORVERSION;
2120 dynamics->minor_version = KAMINORVERSION;
2126 for (i = 0; i < HASHSIZE; i++)
2127 if (cheader.nameHash[i])
2129 dynamics->hashTableUtilization =
2130 (used * 10000 + HASHSIZE / 2) / HASHSIZE;
2133 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
2135 /* Unfortunately, although aix_22 has a minimal compatibility
2136 * method of getting to some rusage fields (i.e. stime &
2137 * utime), the version that we have doesn't even have the
2138 * related include files needed for the aix vtimes() call; so
2139 * ignore this for aix till v3.1... */
2140 getrusage(RUSAGE_SELF, &ru);
2141 #if (KAMAJORVERSION>5)
2142 memcpy(&dynamics->utime, &ru.ru_utime, sizeof(struct katimeval));
2143 memcpy(&dynamics->stime, &ru.ru_stime, sizeof(struct katimeval));
2144 dynamics->dataSize = ru.ru_idrss;
2145 dynamics->stackSize = ru.ru_isrss;
2146 dynamics->pageFailts = ru.ru_majflt;
2148 dynamics->string_checks =
2149 (afs_int32) (1000.0 *
2150 ((ru.ru_utime.tv_sec +
2151 ru.ru_utime.tv_usec / 1000000.0) +
2152 (ru.ru_stime.tv_sec +
2153 ru.ru_stime.tv_usec / 1000000.0)));
2155 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
2158 code = ubik_EndTrans(tt);
2163 SKAM_GetPassword(call, name, password)
2164 struct rx_call *call;
2166 EncryptionKey *password;
2170 code = kamGetPassword(call, name, password);
2171 osi_auditU(call, AFS_KAM_GetPswdEvent, code, AUD_STR, name, AUD_END);
2176 kamGetPassword(call, name, password)
2177 struct rx_call *call;
2179 EncryptionKey *password;
2181 int code = KANOAUTH;
2182 COUNT_REQ(GetPassword);
2187 struct ubik_trans *tt;
2188 struct kaentry tentry;
2190 if (!name_instance_legal(name, ""))
2192 /* only requests from this host work */
2193 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))) !=
2194 htonl(INADDR_LOOPBACK))
2196 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2199 /* this isn't likely to be used because of string to key problems, so since
2200 * this is a temporary thing anyway, we'll use it here. */
2202 extern char udpAuthPrincipal[256];
2204 save_principal(udpAuthPrincipal, name, 0, 0);
2207 get_time(0, 0, 0); /* update random value */
2208 code = FindBlock(tt, name, "", &to, &tentry);
2215 ubik_AbortTrans(tt);
2219 memcpy(password, &tentry.key, sizeof(*password));
2220 code = ubik_EndTrans(tt);
2227 SKAM_GetRandomKey(call, key)
2228 struct rx_call *call;
2233 code = kamGetRandomKey(call, key);
2234 osi_auditU(call, AFS_KAM_GetRndKeyEvent, code, AUD_END);
2239 kamGetRandomKey(call, key)
2240 struct rx_call *call;
2245 COUNT_REQ(GetRandomKey);
2246 if (code = AwaitInitialization())
2248 code = des_random_key(key);
2255 SKAM_Debug(call, version, checkDB, info)
2256 struct rx_call *call;
2258 int checkDB; /* start a transaction to examine DB */
2259 struct ka_debugInfo *info;
2263 code = kamDebug(call, version, checkDB, info);
2264 osi_auditU(call, AFS_KAM_DbgEvent, code, AUD_END);
2269 kamDebug(call, version, checkDB, info)
2270 struct rx_call *call;
2272 int checkDB; /* start a transaction to examine DB */
2273 struct ka_debugInfo *info;
2275 /* COUNT_REQ (Debug); */
2276 if (sizeof(struct kaentry) != sizeof(struct kaOldKeys))
2277 return KAINTERNALERROR;
2278 if (sizeof(struct ka_cpwRequest) % 8)
2279 return KAINTERNALERROR;
2280 if (version != KAMAJORVERSION)
2281 return KAOLDINTERFACE;
2283 memset(info, 0, sizeof(*info));
2285 info->minorVersion = KAMINORVERSION;
2286 info->host = dynamic_statistics.host;
2287 info->startTime = dynamic_statistics.start_time;
2289 #if (KAMAJORVERSION>5)
2295 info->noAuth = noAuthenticationRequired;
2297 info->dbVersion = ntohl(cheader.version);
2298 info->dbFreePtr = ntohl(cheader.freePtr);
2299 info->dbEofPtr = ntohl(cheader.eofPtr);
2300 info->dbKvnoPtr = ntohl(cheader.kvnoPtr);
2301 info->dbSpecialKeysVersion = ntohl(cheader.specialKeysVersion);
2303 info->dbHeaderRead = cheaderReadTime;
2304 info->lastTrans = lastTrans;
2306 lastOperation = "(Not Available)";
2307 strncpy(info->lastOperation, lastOperation, sizeof(info->lastOperation));
2308 strncpy(info->lastAuth, authPrincipal, sizeof(info->lastAuth));
2309 strncpy(info->lastTGS, tgsPrincipal, sizeof(info->lastTGS));
2310 strncpy(info->lastAdmin, adminPrincipal, sizeof(info->lastAdmin));
2311 strncpy(info->lastTGSServer, tgsServerPrincipal,
2312 sizeof(info->lastTGSServer));
2314 extern char udpAuthPrincipal[256];
2315 extern char udptgsPrincipal[256];
2316 extern char udptgsServerPrincipal[256];
2318 strncpy(info->lastUAuth, udpAuthPrincipal, sizeof(info->lastUAuth));
2319 strncpy(info->lastUTGS, udptgsPrincipal, sizeof(info->lastUTGS));
2320 strncpy(info->lastUTGSServer, udptgsServerPrincipal,
2321 sizeof(info->lastUTGSServer));
2323 info->nextAutoCPW = nextAutoCPWTime;
2324 info->updatesRemaining = autoCPWUpdates - totalUpdates;
2325 ka_debugKeyCache(info);
2329 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2330 * a tacked-on-the-side data file.
2331 * prob'ly ought to check the noauth flag.
2333 #define ABORTIF(A) {if(code= A){goto abort;}}
2335 SKAM_Unlock(call, aname, ainstance, spare1, spare2, spare3, spare4)
2336 struct rx_call *call;
2339 afs_int32 spare1, spare2, spare3, spare4;
2342 struct ubik_trans *tt;
2345 struct kaentry tentry;
2348 if (!name_instance_legal(aname, ainstance)) {
2352 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2355 ABORTIF(check_auth(call, tt, 1, &caller));
2356 ABORTIF(FindBlock(tt, aname, ainstance, &to, &tentry));
2357 ABORTIF((to == 0 ? KANOENT : 0));
2359 kaux_write(to, 0, 0); /* zero failure counters at this offset */
2361 code = ubik_EndTrans(tt);
2362 KALOG(aname, ainstance, NULL, NULL, NULL,
2363 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_UNLOCK);
2368 ubik_AbortTrans(tt);
2371 osi_auditU(call, UnlockEvent, code, AUD_STR, aname, AUD_STR, ainstance,
2377 SKAM_LockStatus(call, aname, ainstance, lockeduntil, spare1, spare2, spare3,
2379 struct rx_call *call;
2382 afs_int32 *lockeduntil;
2383 afs_int32 spare1, spare2, spare3, spare4;
2386 struct ubik_trans *tt;
2387 afs_int32 callerIndex;
2389 struct kaentry caller;
2390 struct kaentry tentry;
2393 COUNT_REQ(LockStatus);
2395 if (!name_instance_legal(aname, ainstance)) {
2399 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2402 if (code = check_auth(call, tt, 0, &callerIndex))
2405 if (!noAuthenticationRequired && callerIndex) {
2406 if (karead(tt, callerIndex, &caller, sizeof(caller))) {
2410 /* if the user is checking his own entry or ADMIN then go ahead. */
2411 if ((strcmp(caller.userID.name, aname) != 0)
2412 && !(ntohl(caller.flags) & KAFADMIN)) {
2418 if (code = FindBlock(tt, aname, ainstance, &to, &tentry))
2426 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
2429 kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp);
2431 code = ubik_EndTrans(tt);
2436 ubik_AbortTrans(tt);
2437 osi_auditU(call, LockStatusEvent, code, AUD_STR, aname, AUD_STR,
2438 ainstance, AUD_END);