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>
15 #ifdef IGNORE_SOME_GCC_WARNINGS
16 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
22 #include <sys/types.h>
25 #include <afs/afsutil.h>
27 #include <sys/resource.h>
33 #include <hcrypto/des.h>
44 #include <netinet/in.h>
47 #include <afs/cellconfig.h>
49 #include <afs/com_err.h>
55 #include "kauth_internal.h"
56 #include "afs/audit.h"
58 #include "kadatabase.h"
61 extern struct ubik_dbase *KA_dbase;
62 struct kaheader cheader;
63 Date cheaderReadTime; /* time cheader last read in */
64 extern struct afsconf_dir *KA_conf; /* for getting cell info */
68 char lrealm[MAXKTCREALMLEN];
70 #ifndef EXPIREPW /* password expiration default yes */
74 #ifndef AUTOCPWINTERVAL
75 #define AUTOCPWINTERVAL (24*3600)
77 #ifndef AUTOCPWUPDATES
78 #define AUTOCPWUPDATES 128
83 static afs_int32 autoCPWInterval;
84 static afs_int32 autoCPWUpdates;
86 static afs_int32 set_password(struct ubik_trans *tt, char *name,
88 struct ktc_encryptionKey *password,
89 afs_int32 kvno, afs_int32 caller);
90 static afs_int32 impose_reuse_limits(EncryptionKey *password,
91 struct kaentry *tentry);
92 static int create_user(struct ubik_trans *tt, char *name, char *instance,
93 struct ktc_encryptionKey *key, afs_int32 caller,
96 /* This routine is called whenever an RPC interface needs the time. It uses
97 the current time to randomize a 128 bit value that is used to change the
98 AuthServer Admin and TGS keys automatically. */
100 static Date nextAutoCPWTime = 0;
101 static afs_int32 totalUpdates = 0;
103 /* This routine is ostensibly to get the current time, but basically its job is
104 to periodically update a random number. It also periodically updates the
105 keys for the builtin servers. This is why it needs a transaction pointer
106 and returns an error code. If the caller is in a read transaction, the tt
107 ptr should be zero and the return code need not be checked. */
110 get_time(Date *timeP,
111 struct ubik_trans *tt, /* tt != 0: a write transaction */
112 int admin) /* the caller is an admin user */
114 /* random value used to change Admin & TGS keys, this is at risk during
115 * multi-threaded operation, but I think the consequences are fairly
117 static afs_uint32 random_value[4];
120 unsigned int bit, nbit;
124 gettimeofday(&time, 0);
125 bit = (random_value[3] >> 31) & 1; /* get high bit of high word */
126 for (i = 0; i < 4; i++) {
127 nbit = random_value[i] >> 31;
128 random_value[i] = (random_value[i] << 1) + bit;
131 /* get 60ths from usec. This is all the real randomness there is. */
132 random_value[0] += time.tv_usec / 16667;
134 if (nextAutoCPWTime == 0) { /* initialize things */
135 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
136 memcpy(&random_value[0], &time, 8);
137 memcpy(&random_value[2], &time, 8);
140 if ((++totalUpdates >= autoCPWUpdates) && tt && /* a write transaction */
141 ((admin && (time.tv_sec >= nextAutoCPWTime))
142 || (time.tv_sec >= nextAutoCPWTime + autoCPWInterval))) {
143 struct ktc_encryptionKey key;
144 char buf[4 * sizeof(key) + 1];
145 struct kaentry tentry;
147 char bob[KA_TIMESTR_LEN];
149 ka_timestr(time.tv_sec, bob, KA_TIMESTR_LEN);
150 es_Report("Auto CPW at %s\n", bob);
152 es_Report(" ... even though no ADMIN user\n");
154 code = FindBlock(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &to, &tentry);
157 if (to) { /* check if auto cpw is disabled */
158 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
159 memcpy(&key, &random_value[0], sizeof(key));
160 DES_set_odd_parity(ktc_to_cblock(&key));
162 set_password(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
165 DES_init_random_number_generator(ktc_to_cblock(&key));
166 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
168 es_Report("New Admin key is %s\n", buf);
171 ("in get_time: set_password failed because: %d\n",
178 code = FindBlock(tt, KA_TGS_NAME, lrealm, &to, &tentry);
181 if (to) { /* check if auto cpw is disabled */
182 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
183 memcpy(&key, &random_value[2], sizeof(key));
184 DES_set_odd_parity(ktc_to_cblock(&key));
185 code = set_password(tt, KA_TGS_NAME, lrealm, &key, 0, 0);
187 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
189 es_Report("New TGS key is %s\n", buf);
192 ("in get_time: set_password failed because: %s\n",
193 afs_error_message(code));
198 code = ka_FillKeyCache(tt); /* ensure in-core copy is uptodate */
202 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
206 *timeP = time.tv_sec;
210 static int noAuthenticationRequired; /* global state */
211 static int recheckNoAuth; /* global state */
213 /* kaprocsInited is sort of a lock: during a transaction only one process runs
214 while kaprocsInited is false. */
216 static int kaprocsInited = 0;
218 /* This variable is protected by the kaprocsInited flag. */
220 static int (*rebuildDatabase) (struct ubik_trans *);
222 /* This is called to initialize the database */
225 initialize_database(struct ubik_trans *tt)
227 struct ktc_encryptionKey key;
230 gettimeofday((struct timeval *)&key, 0); /* this is just a cheap seed key */
231 DES_set_odd_parity(ktc_to_cblock(&key));
232 DES_init_random_number_generator(ktc_to_cblock(&key));
233 if ((code = DES_new_random_key(ktc_to_cblock(&key)))
235 create_user(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
236 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
238 if ((code = DES_new_random_key(ktc_to_cblock(&key)))
240 create_user(tt, KA_TGS_NAME, lrealm, &key, 0,
241 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
246 /* This routine handles initialization required by this module. The initFlags
247 parameter passes some information about the command line arguments. */
250 init_kaprocs(const char *lclpath, int initFlags)
253 struct ubik_trans *tt;
254 struct ktc_encryptionKey key;
259 return KAINTERNALERROR;
261 return KAINTERNALERROR;
262 code = afsconf_GetLocalCell(KA_conf, lrealm, sizeof(lrealm));
264 printf("** Can't determine local cell name!\n");
267 ucstring(lrealm, lrealm, sizeof(lrealm));
271 noAuthenticationRequired = 1;
275 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
276 if (noAuthenticationRequired)
277 printf("Running server with security disabled\n");
280 autoCPWInterval = 10;
283 autoCPWInterval = AUTOCPWINTERVAL;
284 autoCPWUpdates = AUTOCPWUPDATES;
287 init_kadatabase(initFlags);
288 rebuildDatabase = initialize_database;
290 if ((code = InitAuthServ(&tt, LOCKREAD, 0))) {
291 printf("init_kaprocs: InitAuthServ failed: code = %d\n", code);
294 code = ka_LookupKey(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &kvno, &key);
298 ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n",
302 DES_init_random_number_generator(ktc_to_cblock(&key));
304 code = ubik_EndTrans(tt);
306 printf("init_kaprocs: ubik_EndTrans failed: code = %d\n", code);
310 kaux_opendb((char *)lclpath);/* aux database stores failure counters */
311 rebuildDatabase = 0; /* only do this during init */
316 /* These variable are for returning debugging info about the state of the
317 server. If they get trashed during multi-threaded operation it doesn't
320 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
321 char *lastOperation = 0; /* name of last operation */
322 static Date lastTrans; /* time of last transaction */
324 static char adminPrincipal[256];
325 static char authPrincipal[256];
326 static char tgsPrincipal[256];
327 static char tgsServerPrincipal[256];
330 save_principal(char *p, char *n, char *i, char *c)
340 if (i && strlen(i)) {
350 if (c && strlen(c)) {
362 check_auth(struct rx_call *call,
363 struct ubik_trans *at,
364 int admin, /* require caller to be ADMIN */
365 afs_int32 *acaller_id)
368 char name[MAXKTCNAMELEN];
369 char instance[MAXKTCNAMELEN];
370 char cell[MAXKTCREALMLEN];
372 Date expiration; /* checked by Security Module */
373 struct kaentry tentry;
380 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
382 si = rx_SecurityClassOf(rx_ConnectionOf(call));
383 if (si == RX_SCINDEX_VAB) {
384 printf("No support for VAB security module yet.\n");
386 } else if (si == RX_SCINDEX_NULL) {
389 } else if (si != RX_SCINDEX_KAD) {
390 es_Report("Unknown security index %d\n", si);
395 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration, name,
396 instance, cell, &kvno);
400 if (level != rxkad_crypt) {
401 es_Report("Incorrect security level = %d\n", level);
406 if (!name_instance_legal(name, instance))
410 ("Authorization rejected because we don't understand intercell stuff yet: ",
412 printf("@%s\n", cell);
416 code = FindBlock(at, name, instance, acaller_id, &tentry);
419 if (*acaller_id == 0) {
420 ka_PrintUserID("User ", name, instance, " unknown.\n");
423 save_principal(adminPrincipal, name, instance, 0);
426 if (!(ntohl(tentry.flags) & KAFADMIN)) {
427 if (noAuthenticationRequired) {
428 ka_PrintUserID("Authorization approved for ", name, instance,
429 " because there is no authentication required\n");
430 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR,
431 instance, AUD_STR, cell, AUD_END);
434 ka_PrintUserID("User ", name, instance, " is not ADMIN.\n");
437 osi_auditU(call, UseOfPrivilegeEvent, code, AUD_STR, name, AUD_STR,
438 instance, AUD_STR, cell, AUD_END);
443 if (noAuthenticationRequired) {
445 ("Caller w/o authorization approved no authentication required\n");
446 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR, instance,
447 AUD_STR, cell, AUD_END);
450 return code; /* no auth info */
454 AwaitInitialization(void)
457 while (!kaprocsInited) {
460 else if (time(0) - start > 5)
467 /* This is called by every RPC interface to create a Ubik transaction and read
468 the database header into core */
471 InitAuthServ(struct ubik_trans **tt,
472 int lock, /* indicate read/write transaction */
473 int *this_op) /* opcode of RPC proc, for COUNT_ABO */
476 afs_int32 start = 0; /* time started waiting for quorum */
477 float wait = 0.91; /* start waiting for 1 second */
479 /* Wait for server initialization to finish if not during init_kaprocs */
481 if ((code = AwaitInitialization()))
484 for (code = UNOQUORUM; code == UNOQUORUM;) {
485 if (lock == LOCKREAD)
486 code = ubik_BeginTransReadAny(KA_dbase, UBIK_READTRANS, tt);
488 code = ubik_BeginTrans(KA_dbase, UBIK_WRITETRANS, tt);
489 if (code == UNOQUORUM) { /* no quorum elected */
493 int delay = time(0) - start;
494 if (this_op) { /* punt quickly, if RPC call */
497 } else { /* more patient during init. */
502 printf("Waiting for quorum election.\n");
505 IOMGR_Sleep((int)wait);
510 if ((code = ubik_SetLock(*tt, 1, 1, lock))) {
513 ubik_AbortTrans(*tt);
516 /* check that dbase is initialized and setup cheader */
517 if (lock == LOCKREAD) {
518 /* init but don't fix because this is read only */
519 code = CheckInit(*tt, 0);
521 ubik_AbortTrans(*tt); /* abort, since probably I/O error */
522 /* we did the check under a ReadAny transaction, but now, after
523 * getting a write transaction (and thus some real guarantees
524 * about what databases are really out there), we will check again
525 * in CheckInit before nuking the database. Since this may now get
526 * a UNOQUORUM we'll just do this from the top.
528 if ((code = InitAuthServ(tt, LOCKWRITE, this_op)))
530 if ((code = ubik_EndTrans(*tt)))
533 /* now open the read transaction that was originally requested. */
534 return InitAuthServ(tt, lock, this_op);
537 if ((code = CheckInit(*tt, rebuildDatabase))) {
540 ubik_AbortTrans(*tt);
545 ka_FillKeyCache(*tt); /* ensure in-core copy is uptodate */
549 /* returns true if name is specially known by AuthServer */
552 special_name(char *name, char *instance)
555 return ((!strcmp(name, KA_TGS_NAME) && !strcmp(instance, lrealm))
556 || (strcmp(name, KA_ADMIN_NAME) == 0));
560 create_user(struct ubik_trans *tt, char *name, char *instance,
561 struct ktc_encryptionKey *key, afs_int32 caller,
566 struct kaentry tentry;
567 afs_int32 maxLifetime;
569 code = FindBlock(tt, name, instance, &to, &tentry);
573 return KAEXIST; /* name already exists, we fail */
575 to = AllocBlock(tt, &tentry);
579 /* otherwise we have a block */
580 strncpy(tentry.userID.name, name, sizeof(tentry.userID.name));
581 strncpy(tentry.userID.instance, instance, sizeof(tentry.userID.instance));
582 tentry.flags = htonl(flags);
583 if (special_name(name, instance)) { /* this overrides key & version */
584 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
585 tentry.key_version = htonl(-1); /* don't save this key */
586 if ((code = ka_NewKey(tt, to, &tentry, key)))
589 memcpy(&tentry.key, key, sizeof(tentry.key));
590 tentry.key_version = htonl(0);
592 tentry.user_expiration = htonl(NEVERDATE);
593 code = get_time(&tentry.modification_time, tt, 1);
597 /* time and addr of entry for guy changing this entry */
598 tentry.modification_time = htonl(tentry.modification_time);
599 tentry.modification_id = htonl(caller);
600 tentry.change_password_time = tentry.modification_time;
602 if (strcmp(name, KA_TGS_NAME) == 0)
603 maxLifetime = MAXKTCTICKETLIFETIME;
604 else if (strcmp(name, KA_ADMIN_NAME) == 0)
605 maxLifetime = 10 * 3600;
606 else if (strcmp(name, AUTH_SUPERUSER) == 0)
607 maxLifetime = 100 * 3600;
609 maxLifetime = 25 * 3600; /* regular users */
610 tentry.max_ticket_lifetime = htonl(maxLifetime);
612 code = ThreadBlock(tt, to, &tentry);
616 /* Put actual stub routines here */
619 SKAM_CreateUser(struct rx_call *call, char *aname, char *ainstance,
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(struct rx_call *call, char *aname, char *ainstance,
633 EncryptionKey ainitpw)
636 struct ubik_trans *tt;
637 afs_int32 caller; /* Disk offset of caller's entry */
639 COUNT_REQ(CreateUser);
640 if (!DES_check_key_parity(EncryptionKey_to_cblock(&ainitpw)) ||
641 DES_is_weak_key(EncryptionKey_to_cblock(&ainitpw)))
643 if (!name_instance_legal(aname, ainstance))
645 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
647 code = check_auth(call, tt, 1, &caller);
653 code = create_user(tt, aname, ainstance, EncryptionKey_to_ktc(&ainitpw), caller, KAFNORMAL);
659 code = ubik_EndTrans(tt);
660 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
666 SKAA_ChangePassword(struct rx_call *call, char *aname, char *ainstance,
667 ka_CBS *arequest, ka_BBS *oanswer)
671 code = ChangePassWord(call, aname, ainstance, arequest, oanswer);
672 osi_auditU(call, AFS_KAA_ChPswdEvent, code, AUD_STR, aname, AUD_STR,
678 ChangePassWord(struct rx_call *call, char *aname, char *ainstance,
679 ka_CBS *arequest, ka_BBS *oanswer)
682 struct ubik_trans *tt;
683 afs_int32 to; /* offset of block */
684 struct kaentry tentry;
685 struct ka_cpwRequest request; /* request after decryption */
686 char *answer; /* where answer is to be put */
687 int answer_len; /* length of answer packet */
688 afs_int32 kvno; /* requested key version number */
689 DES_key_schedule user_schedule; /* key schedule for user's key */
690 Date request_time; /* time request originated */
692 COUNT_REQ(ChangePassword);
693 if (!name_instance_legal(aname, ainstance))
695 if (strcmp(ainstance, KA_ADMIN_NAME) == 0)
697 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
700 code = FindBlock(tt, aname, ainstance, &to, &tentry);
704 if (to == 0) { /* no such user */
708 if (ntohl(tentry.flags) & KAFNOCPW) {
713 /* decrypt request w/ user password */
714 if ((code = DES_key_sched(ktc_to_cblock(&tentry.key), &user_schedule)))
715 es_Report("In KAChangePassword: key_sched returned %d\n", code);
716 DES_pcbc_encrypt(arequest->SeqBody, &request,
717 min(arequest->SeqLen, sizeof(request)), &user_schedule,
718 ktc_to_cblockptr(&tentry.key), DECRYPT);
720 /* validate the request */
721 request_time = ntohl(request.time); /* reorder date */
722 kvno = ntohl(request.kvno);
723 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 */
728 /* check to see if the new password was used before, or if there has
729 * not been sufficient time since the last password change
731 code = impose_reuse_limits(ktc_to_EncryptionKey(&request.newpw), &tentry);
736 /* Create the Answer Packet */
737 answer_len = sizeof(Date) + KA_LABELSIZE;
738 if (oanswer->MaxSeqLen < answer_len) {
739 code = KAANSWERTOOLONG;
742 oanswer->SeqLen = answer_len;
743 answer = oanswer->SeqBody;
744 request.time = htonl(request_time + 1);
745 memcpy(answer, (char *)&request.time, sizeof(Date));
746 answer += sizeof(Date);
747 memcpy(answer, KA_CPW_ANS_LABEL, KA_LABELSIZE);
749 DES_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, answer_len,
750 &user_schedule, ktc_to_cblockptr(&tentry.key), ENCRYPT);
752 code = set_password(tt, aname, ainstance, &request.newpw, kvno, 0);
758 cheader.stats.cpws = htonl(ntohl(cheader.stats.cpws) + 1);
760 kawrite(tt, DOFFSET(0, &cheader, &cheader.stats.cpws),
761 (char *)&cheader.stats.cpws, sizeof(afs_int32));
767 code = ubik_EndTrans(tt);
777 impose_reuse_limits(EncryptionKey *password, struct kaentry *tentry)
785 if (!tentry->pwsums[0] && npwSums > 1 && !tentry->pwsums[1])
786 return 0; /* password reuse limits not in effect */
788 code = get_time(&now, 0, 0);
792 if ((now - ntohl(tentry->change_password_time)) < MinHours * 60 * 60)
795 if (!memcmp(password, &(tentry->key), sizeof(EncryptionKey)))
798 code = ka_KeyCheckSum((char *)password, &newsum);
802 newsum = newsum & 0x000000ff;
803 for (i = 0; i < npwSums; i++) {
804 if (newsum == tentry->pwsums[i])
813 set_password(struct ubik_trans *tt, char *name, char *instance,
814 struct ktc_encryptionKey *password, afs_int32 kvno, afs_int32 caller)
817 afs_int32 to; /* offset of block */
818 struct kaentry tentry;
824 code = FindBlock(tt, name, instance, &to, &tentry);
828 return KANOENT; /* no such user */
830 /* if password reuse limits in effect, set the checksums, the hard way */
831 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
832 /* do nothing, no limits */ ;
834 code = ka_KeyCheckSum((char *)&(tentry.key), &newsum);
837 for (i = npwSums - 1; i; i--)
838 tentry.pwsums[i] = tentry.pwsums[i - 1];
839 tentry.pwsums[0] = newsum & 0x000000ff;
843 if (special_name(name, instance)) { /* set key over rides key_version */
844 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
845 if ((code = ka_NewKey(tt, to, &tentry, password)))
848 memcpy(&tentry.key, password, sizeof(tentry.key));
850 kvno = ntohl(tentry.key_version);
851 if ((kvno < 1) || (kvno >= MAXKAKVNO))
856 tentry.key_version = htonl((afs_int32) kvno); /* requested key version */
861 /* no-write prevents recursive call to set_password by AuthCPW code. */
862 code = get_time(&now, 0, 0);
866 tentry.modification_time = htonl(now);
867 tentry.modification_id = htonl(caller);
870 tentry.change_password_time = htonl(now);
872 if ((code = kawrite(tt, to, (char *) &tentry, sizeof(tentry))))
878 SKAM_SetPassword(struct rx_call *call, char *aname, char *ainstance,
879 afs_int32 akvno, EncryptionKey apassword)
883 code = kamSetPassword(call, aname, ainstance, akvno, apassword);
884 osi_auditU(call, AFS_KAM_SetPswdEvent, code, AUD_STR, aname, AUD_STR,
890 kamSetPassword(struct rx_call *call, char *aname, char *ainstance,
891 afs_int32 akvno, EncryptionKey apassword)
894 struct ubik_trans *tt;
895 afs_int32 caller; /* Disk offset of caller's entry */
896 struct kaentry tentry;
898 COUNT_REQ(SetPassword);
899 if (akvno > MAXKAKVNO)
900 return KABADARGUMENT;
901 if (!DES_check_key_parity(EncryptionKey_to_cblock(&apassword)) ||
902 DES_is_weak_key(EncryptionKey_to_cblock(&apassword)))
905 if (!name_instance_legal(aname, ainstance))
907 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
909 code = check_auth(call, tt, 0, &caller);
913 if ((code = karead(tt, caller, (char *)&tentry, sizeof(tentry)))) {
917 /* if the user is changing his own password or ADMIN then go ahead. */
918 if ((strcmp(tentry.userID.name, aname) == 0)
919 && (strcmp(tentry.userID.instance, ainstance) == 0)) {
920 if (ntohl(tentry.flags) & KAFNOCPW)
923 code = impose_reuse_limits(&apassword, &tentry);
926 set_password(tt, aname, ainstance, EncryptionKey_to_ktc(&apassword), akvno, 0);
928 } else if (ntohl(tentry.flags) & KAFADMIN) {
929 code = set_password(tt, aname, ainstance, EncryptionKey_to_ktc(&apassword), akvno, caller);
935 code = ubik_EndTrans(tt);
936 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
947 CoerseLifetime(Date start, Date end)
949 unsigned char kerberosV4Life;
950 kerberosV4Life = time_to_life(start, end);
951 end = life_to_time(start, kerberosV4Life);
956 GetEndTime(Date start, /* start time of ticket */
957 Date reqEnd, /* requested end time */
958 Date expiration, /* authorizing ticket's expiration */
959 struct kaentry *caller,
960 struct kaentry *server,
961 Date *endP) /* actual end time */
967 if (ntohl(caller->flags) & KAFNOTGS)
968 return KABADUSER; /* no new tickets for this user */
969 if (expiration && (ntohl(server->flags) & KAFNOSEAL))
970 return KABADSERVER; /* can't be target of GetTicket req */
972 expiration = NEVERDATE;
974 cExp = ntohl(caller->user_expiration);
975 sExp = ntohl(server->user_expiration);
980 cLife = start + ntohl(caller->max_ticket_lifetime);
981 sLife = start + ntohl(server->max_ticket_lifetime);
983 umin(umin(reqEnd, expiration),
984 umin(umin(cLife, sLife), umin(cExp, sExp)));
985 end = CoerseLifetime(start, end);
991 PrepareTicketAnswer(ka_BBS *oanswer, afs_int32 challenge, char *ticket,
992 afs_int32 ticketLen, struct ktc_encryptionKey *sessionKey,
993 Date start, Date end, struct kaentry *caller,
994 struct kaentry *server, char *cell, char *label)
997 struct ka_ticketAnswer *answer;
1000 code = KAANSWERTOOLONG;
1001 if (oanswer->MaxSeqLen <
1002 sizeof(struct ka_ticketAnswer) - 5 * MAXKTCNAMELEN - MAXKTCTICKETLEN +
1006 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
1007 answer->challenge = htonl(challenge);
1008 memcpy(&answer->sessionKey, sessionKey, sizeof(struct ktc_encryptionKey));
1009 answer->startTime = htonl(start);
1010 answer->endTime = htonl(end);
1011 answer->kvno = server->key_version;
1012 answer->ticketLen = htonl(ticketLen);
1015 char *ans = answer->name; /* pointer to variable part */
1016 int rem; /* space remaining */
1017 int len; /* macro temp. */
1019 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1021 #define putstr(str) len = strlen (str)+1;\
1022 if (rem < len) return code;\
1024 ans += len; rem -= len
1025 putstr(caller->userID.name);
1026 putstr(caller->userID.instance);
1028 putstr(server->userID.name);
1029 putstr(server->userID.instance);
1030 if (rem < ticketLen + KA_LABELSIZE)
1032 memcpy(ans, ticket, ticketLen);
1035 memcpy(ans, label, KA_LABELSIZE);
1037 memset(ans, 0, KA_LABELSIZE);
1038 ans += KA_LABELSIZE;
1039 oanswer->SeqLen = (ans - oanswer->SeqBody);
1042 answer->cksum = htonl(cksum);
1043 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1044 if (oanswer->SeqLen > oanswer->MaxSeqLen)
1049 /* This is used to get a ticket granting ticket or an admininstration ticket.
1050 These two specific, built-in servers are special cases, which require the
1051 client's key as an additional security precaution. The GetTicket operation
1052 is normally disabled for these two principals. */
1055 Authenticate(int version, struct rx_call *call, char *aname, char *ainstance,
1056 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1059 struct ubik_trans *tt;
1060 afs_int32 to; /* offset of block */
1062 struct kaentry server; /* entry for desired server */
1063 struct ka_gettgtRequest request; /* request after decryption */
1064 int tgt, adm; /* type of request */
1065 char *sname; /* principal of server */
1067 char ticket[MAXKTCTICKETLEN]; /* our copy of the ticket */
1069 struct ktc_encryptionKey sessionKey; /* we have to invent a session key */
1070 char *answer; /* where answer is to be put */
1071 int answer_len; /* length of answer packet */
1072 Date answer_time; /* 1+ request time in network order */
1073 afs_int32 temp; /* for htonl conversions */
1074 DES_key_schedule user_schedule; /* key schedule for user's key */
1075 afs_int32 tgskvno; /* key version of service key */
1076 struct ktc_encryptionKey tgskey; /* service key for encrypting ticket */
1078 afs_uint32 pwexpires;
1080 COUNT_REQ(Authenticate);
1081 if (!name_instance_legal(aname, ainstance))
1083 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1085 get_time(&now, 0, 0);
1087 sname = sinst = NULL;
1089 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1093 if (to == 0) { /* no such user */
1098 /* have to check for locked before verifying the password, otherwise all
1099 * KALOCKED means is "yup, you guessed the password all right, now wait a
1100 * few minutes and we'll let you in"
1103 (to, (u_int) tentry.misc_auth_bytes[ATTEMPTS],
1104 (afs_uint32) tentry.misc_auth_bytes[LOCKTIME] << 9)) {
1110 save_principal(authPrincipal, aname, ainstance, 0);
1112 /* decrypt request w/ user password */
1113 if ((code = DES_key_sched(ktc_to_cblock(&tentry.key), &user_schedule)))
1114 es_Report("In KAAuthenticate: key_sched returned %d\n", code);
1115 DES_pcbc_encrypt(arequest->SeqBody, &request,
1116 min(arequest->SeqLen, sizeof(request)), &user_schedule,
1117 ktc_to_cblockptr(&tentry.key), DECRYPT);
1119 request.time = ntohl(request.time); /* reorder date */
1120 tgt = !strncmp(request.label, KA_GETTGT_REQ_LABEL, sizeof(request.label));
1121 adm = !strncmp(request.label, KA_GETADM_REQ_LABEL, sizeof(request.label));
1122 if (!(tgt || adm)) {
1123 kaux_inc(to, ((unsigned char)tentry.misc_auth_bytes[LOCKTIME]) << 9);
1124 code = KABADREQUEST;
1127 kaux_write(to, 0, 0); /* reset counters */
1130 if (!tentry.misc_auth_bytes[EXPIRES]) {
1131 /* 0 in the database means never, but 0 on the network means today */
1132 /* 255 on the network means "long time, maybe never" */
1135 pwexpires = tentry.misc_auth_bytes[EXPIRES];
1138 ntohl(tentry.change_password_time) + 24 * 60 * 60 * pwexpires;
1139 if (adm) { /* provide a little slack for admin ticket */
1140 pwexpires += 30 * 24 * 60 * 60; /* 30 days */
1142 if (pwexpires < now) {
1146 pwexpires = (pwexpires - now) / (24 * 60 * 60);
1147 if (pwexpires > 255)
1151 #endif /* EXPIREPW */
1153 if (abs(request.time - now) > KTC_TIME_UNCERTAINTY) {
1155 if (oanswer->MaxSeqLen < sizeof(afs_int32))
1156 code = KAANSWERTOOLONG;
1157 else { /* return our time if possible */
1158 oanswer->SeqLen = sizeof(afs_int32);
1159 request.time = htonl(now);
1160 memcpy(oanswer->SeqBody, &request.time, sizeof(afs_int32));
1166 sname = (tgt ? KA_TGS_NAME : KA_ADMIN_NAME);
1167 sinst = (tgt ? lrealm : KA_ADMIN_INST);
1168 code = FindBlock(tt, sname, sinst, &to, &server);
1176 tgskvno = ntohl(server.key_version);
1177 memcpy(&tgskey, &server.key, sizeof(tgskey));
1179 code = DES_new_random_key(ktc_to_cblock(&sessionKey));
1185 code = GetEndTime(start, end, 0 /*!GetTicket */ , &tentry, &server, &end);
1190 tkt_MakeTicket(ticket, &ticketLen, &tgskey, aname, ainstance, "",
1191 start, end, &sessionKey,
1192 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), sname,
1200 ticketLen + sizeof(Date) + sizeof(struct ktc_encryptionKey) +
1201 2 * sizeof(afs_int32) + KA_LABELSIZE;
1202 answer_len = round_up_to_ebs(answer_len);
1203 if (answer_len > oanswer->MaxSeqLen) {
1204 code = KAANSWERTOOLONG;
1207 oanswer->SeqLen = answer_len;
1208 answer = oanswer->SeqBody;
1209 answer_time = htonl(request.time + 1);
1210 memcpy(answer, (char *)&answer_time, sizeof(Date));
1211 answer += sizeof(Date);
1212 memcpy(answer, (char *)&sessionKey, sizeof(struct ktc_encryptionKey));
1213 answer += sizeof(struct ktc_encryptionKey);
1214 temp = htonl(tgskvno);
1215 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1216 answer += sizeof(afs_int32);
1217 temp = htonl(ticketLen);
1218 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1219 answer += sizeof(afs_int32);
1220 memcpy(answer, ticket, ticketLen);
1221 answer += ticketLen;
1222 memcpy(answer, (tgt ? KA_GETTGT_ANS_LABEL : KA_GETADM_ANS_LABEL),
1228 PrepareTicketAnswer(oanswer, request.time + 1, ticket, ticketLen,
1229 &sessionKey, start, end, &tentry, &server, "",
1230 (tgt ? KA_GETTGT_ANS_LABEL :
1231 KA_GETADM_ANS_LABEL));
1236 && oanswer->SeqLen < oanswer->MaxSeqLen + sizeof(afs_int32)) {
1237 temp = pwexpires << 24; /* move it into the high byte */
1238 pwexpires = htonl(temp);
1240 memcpy((char *)oanswer->SeqBody + oanswer->SeqLen, &pwexpires,
1242 oanswer->SeqLen += sizeof(afs_int32);
1243 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1244 if (oanswer->SeqLen > oanswer->MaxSeqLen) {
1245 code = KAANSWERTOOLONG;
1249 #endif /* EXPIREPW */
1253 code = KAINTERNALERROR;
1256 DES_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1257 &user_schedule, ktc_to_cblockptr(&tentry.key), ENCRYPT);
1258 code = ubik_EndTrans(tt);
1259 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host,
1265 ubik_AbortTrans(tt);
1266 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host,
1272 SKAA_Authenticate_old(struct rx_call *call, char *aname, char *ainstance,
1273 Date start, Date end, ka_CBS *arequest,
1278 IOMGR_Sleep(1); /* discourage use of this mechanism */
1280 Authenticate(0, call, aname, ainstance, start, end, arequest,
1282 osi_auditU(call, AFS_KAA_AuthOEvent, code, AUD_STR, aname, AUD_STR,
1283 ainstance, AUD_END);
1289 SKAA_Authenticate(struct rx_call *call, char *aname, char *ainstance,
1290 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1295 Authenticate(1, call, aname, ainstance, start, end, arequest,
1297 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1298 ainstance, AUD_END);
1304 SKAA_AuthenticateV2(struct rx_call *call, char *aname, char *ainstance,
1305 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1310 Authenticate(2, call, aname, ainstance, start, end, arequest,
1312 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1313 ainstance, AUD_END);
1319 SKAM_SetFields(struct rx_call *call,
1324 afs_int32 alifetime,
1325 afs_int32 amaxAssociates,
1326 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1332 kamSetFields(call, aname, ainstance, aflags, aexpiration, alifetime,
1333 amaxAssociates, misc_auth_bytes, spare2);
1334 osi_auditU(call, AFS_KAM_SetFldEvent, code, AUD_STR, aname, AUD_STR,
1335 ainstance, AUD_LONG, aflags, AUD_DATE, aexpiration, AUD_LONG,
1336 alifetime, AUD_LONG, amaxAssociates, AUD_END);
1341 kamSetFields(struct rx_call *call,
1346 afs_int32 alifetime,
1347 afs_int32 amaxAssociates,
1348 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1353 struct ubik_trans *tt;
1355 afs_int32 tentry_offset; /* offset of entry */
1356 struct kaentry tentry;
1357 unsigned char newvals[4];
1359 COUNT_REQ(SetFields);
1362 return KABADARGUMENT; /* not supported yet... */
1364 /* make sure we're supposed to do something */
1365 if (!(aflags || aexpiration || alifetime || (amaxAssociates >= 0)
1367 || ((aflags & ~KAFNORMAL) & ~KAF_SETTABLE_FLAGS))
1368 return KABADARGUMENT; /* arguments no good */
1369 if (!name_instance_legal(aname, ainstance))
1371 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1373 code = check_auth(call, tt, 1, &caller);
1378 code = FindBlock(tt, aname, ainstance, &tentry_offset, &tentry);
1381 if (tentry_offset == 0) { /* no such user */
1385 if ((ntohl(tentry.flags) & KAFNORMAL) == 0)
1386 return KAINTERNALERROR;
1388 /* Keep track of the total number of admin accounts. This way we can
1389 * update database without any admin privilege initially */
1390 if ((aflags & KAFADMIN) != (ntohl(tentry.flags) & KAFADMIN)) {
1391 /* if admin state is changing */
1393 if (ntohl(tentry.flags) & KAFADMIN)
1397 if ((code = update_admin_count(tt, delta)))
1401 htonl((ntohl(tentry.flags) & ~KAF_SETTABLE_FLAGS) | aflags);
1403 if ((code = get_time(&now, tt, 1)))
1406 tentry.user_expiration = htonl(aexpiration);
1407 if (!ntohl(tentry.change_password_time)) {
1408 tentry.change_password_time = htonl(now);
1412 tentry.max_ticket_lifetime = htonl(alifetime);
1414 #ifndef NOPWCONTROLS
1416 * We've packed a bunch of bytes into a long for backward compatibility.
1417 * These include password expiration time, and some failed login limits
1418 * counters. Now let's unpack them and stick them into the
1419 * kaentry struct. All the bytes have values in the range
1420 * 1..255, else they were not specified in the interface, and are
1422 * In the case of password expiration times, 1 means password never
1423 * expires (==>0), 2 means password only lives for one day (==>1),
1426 if (misc_auth_bytes) {
1427 unpack_long(misc_auth_bytes, newvals);
1428 if (newvals[EXPIRES]) {
1429 tentry.misc_auth_bytes[EXPIRES] = newvals[EXPIRES] - 1;
1432 if (newvals[REUSEFLAGS]) {
1433 if (newvals[REUSEFLAGS] & KA_REUSEPW)
1434 memset(tentry.pwsums, 0, KA_NPWSUMS);
1435 else if ((newvals[REUSEFLAGS] & KA_NOREUSEPW)
1436 && !tentry.pwsums[0])
1437 tentry.pwsums[0] = 0xff;
1440 if (newvals[ATTEMPTS]) {
1441 tentry.misc_auth_bytes[ATTEMPTS] = newvals[ATTEMPTS] - 1;
1443 if (newvals[LOCKTIME]) {
1444 tentry.misc_auth_bytes[LOCKTIME] = newvals[LOCKTIME] - 1;
1447 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1450 #endif /* NOPWCONTROLS */
1452 if (amaxAssociates >= 0) {
1453 if ((ntohl(tentry.flags) & KAFASSOC)
1454 || (ntohl(tentry.flags) & KAFSPECIAL))
1456 if (((ntohl(tentry.flags) & KAFASSOCROOT) == 0) && (amaxAssociates > 0)) /* convert normal user to assoc root */
1457 tentry.flags = htonl(ntohl(tentry.flags) | KAFASSOCROOT);
1458 tentry.misc.assocRoot.maxAssociates = htonl(amaxAssociates);
1461 tentry.modification_time = htonl(now);
1462 tentry.modification_id = htonl(caller);
1463 code = kawrite(tt, tentry_offset, (char *) &tentry, sizeof(tentry));
1467 code = ubik_EndTrans(tt);
1468 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
1474 ubik_AbortTrans(tt);
1481 SKAM_DeleteUser(struct rx_call *call, char *aname, char *ainstance)
1485 code = kamDeleteUser(call, aname, ainstance);
1486 osi_auditU(call, AFS_KAM_DelUserEvent, code, AUD_STR, aname, AUD_STR,
1487 ainstance, AUD_END);
1492 kamDeleteUser(struct rx_call *call, char *aname, char *ainstance)
1495 struct ubik_trans *tt;
1498 struct kaentry tentry;
1499 unsigned int nfailures;
1500 afs_uint32 locktime;
1502 COUNT_REQ(DeleteUser);
1503 if (!name_instance_legal(aname, ainstance))
1505 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1507 code = check_auth(call, tt, 1, &caller);
1511 ubik_AbortTrans(tt);
1515 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1518 if (to == 0) { /* name not found */
1523 kaux_read(to, &nfailures, &locktime);
1524 if (nfailures || locktime)
1525 kaux_write(to, 0, 0); /* zero failure counters at this offset */
1527 /* track all AuthServer identities */
1528 if (special_name(aname, ainstance))
1529 if ((code = ka_DelKey(tt, to, &tentry)))
1532 if (ntohl(tentry.flags) & KAFADMIN) /* keep admin count up-to-date */
1533 if ((code = update_admin_count(tt, -1)))
1536 if ((code = UnthreadBlock(tt, &tentry)) || (code = FreeBlock(tt, to)) || (code = get_time(0, tt, 1)) /* update randomness */
1540 code = ubik_EndTrans(tt);
1541 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
1546 /* we set a bit in here which indicates that the user's limit of
1547 * authentication failures has been exceeded. If that bit is not set,
1548 * kas can take it on faith that the user ID is not locked. If that
1549 * bit is set, kas has to check all the servers to find one who will
1550 * report that the ID is not locked, or else to find out when the ID
1554 SKAM_GetEntry(struct rx_call *call,
1557 afs_int32 aversion, /* major version assumed by caller */
1558 kaentryinfo *aentry) /* entry data copied here */
1562 code = kamGetEntry(call, aname, ainstance, aversion, aentry);
1563 osi_auditU(call, AFS_KAM_GetEntEvent, code, AUD_STR, aname, AUD_STR,
1564 ainstance, AUD_END);
1569 kamGetEntry(struct rx_call *call,
1572 afs_int32 aversion, /* major version assumed by caller */
1573 kaentryinfo *aentry) /* entry data copied here */
1576 struct ubik_trans *tt;
1577 afs_int32 callerIndex;
1578 struct kaentry caller;
1581 struct kaentry tentry;
1582 rxkad_level enc_level = rxkad_clear;
1583 int callerIsAdmin = 0;
1585 COUNT_REQ(GetEntry);
1586 if (aversion != KAMAJORVERSION)
1587 return KAOLDINTERFACE;
1588 if (!name_instance_legal(aname, ainstance))
1590 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1592 code = check_auth(call, tt, 0, &callerIndex);
1596 if (noAuthenticationRequired) {
1597 } else if (!callerIndex) {
1601 if ((code = karead(tt, callerIndex, (char *)&caller, sizeof(caller)))) {
1605 /* if the user is checking his own entry or ADMIN then go ahead. */
1606 callerIsAdmin = (ntohl(caller.flags) & KAFADMIN);
1608 if (strcmp(caller.userID.name, aname) != 0 && !callerIsAdmin) {
1614 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1617 if (to == 0) { /* entry not found */
1622 get_time(0, 0, 0); /* generate random update */
1624 memset(aentry, 0, sizeof(*aentry));
1625 aentry->minor_version = KAMINORVERSION;
1626 aentry->flags = ntohl(tentry.flags);
1627 aentry->user_expiration = ntohl(tentry.user_expiration);
1628 aentry->modification_time = ntohl(tentry.modification_time);
1629 aentry->change_password_time = ntohl(tentry.change_password_time);
1630 aentry->max_ticket_lifetime = ntohl(tentry.max_ticket_lifetime);
1631 aentry->key_version = ntohl(tentry.key_version);
1633 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
1635 if (kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp))
1636 tentry.misc_auth_bytes[REUSEFLAGS] |= KA_ISLOCKED; /* saves an RPC */
1638 temp = pack_long(tentry.misc_auth_bytes);
1639 aentry->misc_auth_bytes = temp;
1641 * only return user's key if security disabled or if admin and
1642 * we have an encrypted connection to the user
1644 rxkad_GetServerInfo(call->conn, &enc_level, 0, 0, 0, 0, 0);
1645 if ((noAuthenticationRequired)
1646 || (callerIsAdmin && enc_level == rxkad_crypt))
1647 memcpy(&aentry->key, &tentry.key, sizeof(struct ktc_encryptionKey));
1649 memset(&aentry->key, 0, sizeof(aentry->key));
1650 code = ka_KeyCheckSum((char *)&tentry.key, &aentry->keyCheckSum);
1651 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
1652 aentry->reserved3 = 0x12340000;
1654 aentry->reserved3 = 0x12340001;
1657 /* Now get entry of user who last modified this entry */
1658 if (ntohl(tentry.modification_id)) {
1659 temp = ntohl(tentry.modification_id);
1660 code = karead(tt, temp, (char *)&tentry, sizeof(tentry));
1665 aentry->modification_user = tentry.userID;
1667 strcpy(aentry->modification_user.name, "<none>");
1668 strcpy(aentry->modification_user.instance, "\0");
1670 code = ubik_EndTrans(tt);
1675 ubik_AbortTrans(tt);
1680 SKAM_ListEntry(struct rx_call *call,
1681 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1682 afs_int32 *index, /* index of this entry */
1683 afs_int32 *count, /* total entries in database */
1684 kaident *name) /* name & instance of this entry */
1688 code = kamListEntry(call, previous_index, index, count, name);
1689 osi_auditU(call, AFS_KAM_LstEntEvent, code, AUD_LONG, *index, AUD_END);
1695 kamListEntry(struct rx_call *call,
1696 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1697 afs_int32 *index, /* index of this entry */
1698 afs_int32 *count, /* total entries in database */
1699 kaident *name) /* name & instance of this entry */
1702 struct ubik_trans *tt;
1704 struct kaentry tentry;
1706 COUNT_REQ(ListEntry);
1707 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1709 code = check_auth(call, tt, 1, &caller);
1714 *index = NextBlock(tt, previous_index, &tentry, count);
1720 if (*index) { /* return name & inst of this entry */
1721 strncpy(name->name, tentry.userID.name, sizeof(name->name));
1722 strncpy(name->instance, tentry.userID.instance,
1723 sizeof(name->instance));
1725 strcpy(name->name, "\0");
1726 strcpy(name->instance, "\0");
1728 code = ubik_EndTrans(tt);
1733 ubik_AbortTrans(tt);
1738 GetTicket(int version,
1739 struct rx_call *call,
1745 ka_CBS *atimes, /* encrypted start & end time */
1750 struct ubik_trans *tt;
1751 struct ktc_encryptionKey tgskey;
1752 DES_key_schedule schedule;
1754 char name[MAXKTCNAMELEN];
1755 char instance[MAXKTCNAMELEN];
1756 char cell[MAXKTCNAMELEN];
1758 struct kaentry caller;
1759 struct kaentry server;
1760 struct ktc_encryptionKey authSessionKey;
1761 struct ktc_encryptionKey sessionKey;
1763 char ticket[MAXKTCTICKETLEN];
1769 struct ka_getTicketTimes times;
1770 struct ka_getTicketAnswer *answer;
1772 COUNT_REQ(GetTicket);
1773 if (!name_instance_legal(sname, sinstance))
1775 if (atimes->SeqLen != sizeof(times))
1776 return KABADARGUMENT;
1777 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1780 export = import = 0;
1781 if ((strcmp(sname, KA_TGS_NAME) == 0) && (strcmp(sinstance, lrealm) != 0))
1783 if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0))
1786 if (strlen(authDomain) == 0)
1787 authDomain = lrealm;
1788 code = ka_LookupKvno(tt, KA_TGS_NAME, authDomain, kvno, &tgskey);
1793 tkt_DecodeTicket(aticket->SeqBody, aticket->SeqLen, &tgskey, name,
1794 instance, cell, &authSessionKey, &host, &start,
1800 save_principal(tgsPrincipal, name, instance, cell);
1802 if ((code = get_time(&now, 0, 0)))
1805 code = tkt_CheckTimes(start, expiration, now);
1808 code = RXKADEXPIRED;
1813 code = DES_key_sched(ktc_to_cblock(&authSessionKey), &schedule);
1818 celllen = strlen(cell);
1819 if (import && (celllen == 0)) {
1823 if (export && (celllen == 0))
1824 strcpy(cell, lrealm);
1826 if (!krb4_cross && celllen && strcmp(lrealm, cell) != 0) {
1831 DES_ecb_encrypt((DES_cblock *)atimes->SeqBody, (DES_cblock *)×, &schedule, DECRYPT);
1832 times.start = ntohl(times.start);
1833 times.end = ntohl(times.end);
1834 code = tkt_CheckTimes(times.start, times.end, now);
1836 code = KABADREQUEST;
1841 strcpy(caller.userID.name, name);
1842 strcpy(caller.userID.instance, instance);
1843 caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
1844 caller.flags = htonl(KAFNORMAL);
1845 caller.user_expiration = htonl(NEVERDATE);
1847 code = FindBlock(tt, name, instance, &to, &caller);
1851 ka_PrintUserID("GetTicket: User ", name, instance, " unknown.\n");
1857 /* get server's entry */
1858 code = FindBlock(tt, sname, sinstance, &to, &server);
1861 if (to == 0) { /* entry not found */
1862 ka_PrintUserID("GetTicket: Server ", sname, sinstance, " unknown.\n");
1866 save_principal(tgsServerPrincipal, sname, sinstance, 0);
1868 code = DES_new_random_key(ktc_to_cblock(&sessionKey));
1875 GetEndTime(times.start, times.end, expiration, &caller, &server,
1881 tkt_MakeTicket(ticket, &ticketLen, &server.key, caller.userID.name,
1882 caller.userID.instance, cell, times.start, end,
1884 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
1885 server.userID.name, server.userID.instance);
1891 code = KAANSWERTOOLONG;
1892 if (oanswer->MaxSeqLen <
1893 sizeof(struct ka_getTicketAnswer) - 5 * MAXKTCNAMELEN -
1894 MAXKTCTICKETLEN + ticketLen)
1897 answer = (struct ka_getTicketAnswer *)oanswer->SeqBody;
1898 memcpy(&answer->sessionKey, &sessionKey,
1899 sizeof(struct ktc_encryptionKey));
1900 answer->startTime = htonl(times.start);
1901 answer->endTime = htonl(end);
1902 answer->kvno = server.key_version;
1903 answer->ticketLen = htonl(ticketLen);
1906 char *ans = answer->name; /* ptr to variable part of answer */
1909 /* space remaining */
1910 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1912 #define putstr(str) len = strlen (str)+1;\
1913 if (rem < len) goto abort;\
1915 ans += len; rem -= len
1922 if (rem < ticketLen)
1924 memcpy(ans, ticket, ticketLen);
1925 oanswer->SeqLen = (ans - oanswer->SeqBody) + ticketLen;
1927 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1931 PrepareTicketAnswer(oanswer, /*challenge */ 0, ticket, ticketLen,
1932 &sessionKey, times.start, end, &caller,
1933 &server, cell, KA_GETTICKET_ANS_LABEL);
1938 code = KAINTERNALERROR;
1941 DES_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1942 &schedule, ktc_to_cblockptr(&authSessionKey), ENCRYPT);
1943 code = ubik_EndTrans(tt);
1944 KALOG(name, instance, sname, sinstance, (import ? authDomain : NULL),
1945 call->conn->peer->host, LOG_GETTICKET);
1950 ubik_AbortTrans(tt);
1955 SKAT_GetTicket_old(struct rx_call *call,
1961 ka_CBS *atimes, /* encrypted start & end time */
1966 sleep(1); /* strongly discourage this */
1968 GetTicket(0, call, kvno, authDomain, aticket, sname, sinstance,
1971 osi_auditU(call, AFS_KAT_GetTicketOEvent, code, AUD_STR, sname, AUD_STR,
1972 sinstance, AUD_END);
1977 SKAT_GetTicket(struct rx_call *call,
1983 ka_CBS *atimes, /* encrypted start & end time */
1989 GetTicket(1, call, kvno, authDomain, aticket, sname, sinstance,
1991 osi_auditU(call, AFS_KAT_GetTicketEvent, code, AUD_STR, sname, AUD_STR,
1992 sinstance, AUD_END);
1997 SKAM_GetStats(struct rx_call *call, afs_int32 version,
1998 afs_int32 *admin_accounts, kasstats *statics,
2003 code = kamGetStats(call, version, admin_accounts, statics, dynamics);
2004 osi_auditU(call, AFS_KAM_GetStatEvent, code, AUD_END);
2009 kamGetStats(struct rx_call *call, afs_int32 version,
2010 afs_int32 *admin_accounts, kasstats *statics,
2014 struct ubik_trans *tt;
2017 COUNT_REQ(GetStats);
2018 if (version != KAMAJORVERSION)
2019 return KAOLDINTERFACE;
2020 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2022 code = check_auth(call, tt, 1, &caller);
2025 ubik_AbortTrans(tt);
2029 *admin_accounts = ntohl(cheader.admin_accounts);
2030 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
2031 /* these are stored in network byte order and must be copied */
2032 statics->allocs = ntohl(cheader.stats.allocs);
2033 statics->frees = ntohl(cheader.stats.frees);
2034 statics->cpws = ntohl(cheader.stats.cpws);
2035 #if KADBVERSION != 5
2036 check that the statistics command copies all the fields
2038 memcpy((char *)dynamics, (char *)&dynamic_statistics, sizeof(kadstats));
2039 statics->minor_version = KAMINORVERSION;
2040 dynamics->minor_version = KAMINORVERSION;
2046 for (i = 0; i < HASHSIZE; i++)
2047 if (cheader.nameHash[i])
2049 dynamics->hashTableUtilization =
2050 (used * 10000 + HASHSIZE / 2) / HASHSIZE;
2053 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
2055 /* Unfortunately, although aix_22 has a minimal compatibility
2056 * method of getting to some rusage fields (i.e. stime &
2057 * utime), the version that we have doesn't even have the
2058 * related include files needed for the aix vtimes() call; so
2059 * ignore this for aix till v3.1... */
2060 getrusage(RUSAGE_SELF, &ru);
2061 #if (KAMAJORVERSION>5)
2062 memcpy(&dynamics->utime, &ru.ru_utime, sizeof(struct katimeval));
2063 memcpy(&dynamics->stime, &ru.ru_stime, sizeof(struct katimeval));
2064 dynamics->dataSize = ru.ru_idrss;
2065 dynamics->stackSize = ru.ru_isrss;
2066 dynamics->pageFailts = ru.ru_majflt;
2068 dynamics->string_checks =
2069 (afs_int32) (1000.0 *
2070 ((ru.ru_utime.tv_sec +
2071 ru.ru_utime.tv_usec / 1000000.0) +
2072 (ru.ru_stime.tv_sec +
2073 ru.ru_stime.tv_usec / 1000000.0)));
2075 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
2078 code = ubik_EndTrans(tt);
2083 SKAM_GetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2087 code = kamGetPassword(call, name, password);
2088 osi_auditU(call, AFS_KAM_GetPswdEvent, code, AUD_STR, name, AUD_END);
2093 kamGetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2095 int code = KANOAUTH;
2096 AFS_UNUSED COUNT_REQ(GetPassword);
2100 struct ubik_trans *tt;
2101 struct kaentry tentry;
2103 if (!name_instance_legal(name, ""))
2105 /* only requests from this host work */
2106 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))) !=
2107 htonl(INADDR_LOOPBACK))
2109 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2112 /* this isn't likely to be used because of string to key problems, so since
2113 * this is a temporary thing anyway, we'll use it here. */
2115 extern char udpAuthPrincipal[256];
2117 save_principal(udpAuthPrincipal, name, 0, 0);
2120 get_time(0, 0, 0); /* update random value */
2121 code = FindBlock(tt, name, "", &to, &tentry);
2128 ubik_AbortTrans(tt);
2132 memcpy(password, &tentry.key, sizeof(*password));
2133 code = ubik_EndTrans(tt);
2140 SKAM_GetRandomKey(struct rx_call *call, EncryptionKey *key)
2144 code = kamGetRandomKey(call, key);
2145 osi_auditU(call, AFS_KAM_GetRndKeyEvent, code, AUD_END);
2150 kamGetRandomKey(struct rx_call *call, EncryptionKey *key)
2154 AFS_UNUSED COUNT_REQ(GetRandomKey);
2155 if ((code = AwaitInitialization()))
2157 code = DES_new_random_key(EncryptionKey_to_cblock(key));
2164 SKAM_Debug(struct rx_call *call,
2166 int checkDB, /* start a transaction to examine DB */
2167 struct ka_debugInfo *info)
2171 code = kamDebug(call, version, checkDB, info);
2172 osi_auditU(call, AFS_KAM_DbgEvent, code, AUD_END);
2177 kamDebug(struct rx_call *call,
2179 int checkDB, /* start a transaction to examine DB */
2180 struct ka_debugInfo *info)
2182 /* COUNT_REQ (Debug); */
2183 if (sizeof(struct kaentry) != sizeof(struct kaOldKeys))
2184 return KAINTERNALERROR;
2185 if (sizeof(struct ka_cpwRequest) % 8)
2186 return KAINTERNALERROR;
2187 if (version != KAMAJORVERSION)
2188 return KAOLDINTERFACE;
2190 memset(info, 0, sizeof(*info));
2192 info->minorVersion = KAMINORVERSION;
2193 info->host = dynamic_statistics.host;
2194 info->startTime = dynamic_statistics.start_time;
2196 #if (KAMAJORVERSION>5)
2202 info->noAuth = noAuthenticationRequired;
2204 info->dbVersion = ntohl(cheader.version);
2205 info->dbFreePtr = ntohl(cheader.freePtr);
2206 info->dbEofPtr = ntohl(cheader.eofPtr);
2207 info->dbKvnoPtr = ntohl(cheader.kvnoPtr);
2208 info->dbSpecialKeysVersion = ntohl(cheader.specialKeysVersion);
2210 info->dbHeaderRead = cheaderReadTime;
2211 info->lastTrans = lastTrans;
2213 lastOperation = "(Not Available)";
2214 strncpy(info->lastOperation, lastOperation, sizeof(info->lastOperation));
2215 strncpy(info->lastAuth, authPrincipal, sizeof(info->lastAuth));
2216 strncpy(info->lastTGS, tgsPrincipal, sizeof(info->lastTGS));
2217 strncpy(info->lastAdmin, adminPrincipal, sizeof(info->lastAdmin));
2218 strncpy(info->lastTGSServer, tgsServerPrincipal,
2219 sizeof(info->lastTGSServer));
2221 extern char udpAuthPrincipal[256];
2222 extern char udptgsPrincipal[256];
2223 extern char udptgsServerPrincipal[256];
2225 strncpy(info->lastUAuth, udpAuthPrincipal, sizeof(info->lastUAuth));
2226 strncpy(info->lastUTGS, udptgsPrincipal, sizeof(info->lastUTGS));
2227 strncpy(info->lastUTGSServer, udptgsServerPrincipal,
2228 sizeof(info->lastUTGSServer));
2230 info->nextAutoCPW = nextAutoCPWTime;
2231 info->updatesRemaining = autoCPWUpdates - totalUpdates;
2232 ka_debugKeyCache(info);
2236 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2237 * a tacked-on-the-side data file.
2238 * prob'ly ought to check the noauth flag.
2240 #define ABORTIF(A) {if((code = A)){goto abort;}}
2242 SKAM_Unlock(struct rx_call *call,
2251 struct ubik_trans *tt;
2254 struct kaentry tentry;
2257 if (!name_instance_legal(aname, ainstance)) {
2261 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2264 ABORTIF(check_auth(call, tt, 1, &caller));
2265 ABORTIF(FindBlock(tt, aname, ainstance, &to, &tentry));
2266 ABORTIF((to == 0 ? KANOENT : 0));
2268 kaux_write(to, 0, 0); /* zero failure counters at this offset */
2270 code = ubik_EndTrans(tt);
2271 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
2277 ubik_AbortTrans(tt);
2280 osi_auditU(call, UnlockEvent, code, AUD_STR, aname, AUD_STR, ainstance,
2286 SKAM_LockStatus(struct rx_call *call,
2289 afs_int32 *lockeduntil,
2296 struct ubik_trans *tt;
2297 afs_int32 callerIndex;
2299 struct kaentry caller;
2300 struct kaentry tentry;
2303 COUNT_REQ(LockStatus);
2305 if (!name_instance_legal(aname, ainstance)) {
2309 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2312 if ((code = check_auth(call, tt, 0, &callerIndex)))
2315 if (!noAuthenticationRequired && callerIndex) {
2316 if (karead(tt, callerIndex, (char *)&caller, sizeof(caller))) {
2320 /* if the user is checking his own entry or ADMIN then go ahead. */
2321 if ((strcmp(caller.userID.name, aname) != 0)
2322 && !(ntohl(caller.flags) & KAFADMIN)) {
2328 if ((code = FindBlock(tt, aname, ainstance, &to, &tentry)))
2336 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
2339 kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp);
2341 code = ubik_EndTrans(tt);
2346 ubik_AbortTrans(tt);
2347 osi_auditU(call, LockStatusEvent, code, AUD_STR, aname, AUD_STR,
2348 ainstance, AUD_END);