Pull in patch that properly includes stdint.h
[pkg-k5-afs_openafs.git] / src / kauth / kaprocs.c
blobe2c058c6fbc3d54ab78c70e0c595e6645ff08524
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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
8 */
10 #include <afsconfig.h>
11 #include <afs/param.h>
14 #include <afs/stds.h>
15 #include <errno.h>
16 #include "kauth.h"
17 #include <sys/types.h>
18 #include <time.h>
19 #ifdef AFS_NT40_ENV
20 #include <afs/afsutil.h>
21 #else
22 #include <sys/resource.h>
23 #include <sys/file.h>
24 #endif
25 #include <stdio.h>
26 #include <lock.h>
27 #include <ubik.h>
28 #include <lwp.h>
29 #include <des.h>
30 #include <des_prototypes.h>
31 #include <rx/xdr.h>
32 #include <rx/rx.h>
33 #include <rx/rxkad.h>
34 #ifdef AFS_NT40_ENV
35 #include <winsock2.h>
36 #else
37 #include <netinet/in.h>
38 #endif
39 #include <string.h>
40 #include <afs/cellconfig.h>
41 #include <afs/auth.h>
42 #include <afs/com_err.h>
43 #include "kautils.h"
44 #include "kaserver.h"
45 #include "kalog.h"
46 #include "kaport.h"
47 #include "kauth_internal.h"
48 #include "afs/audit.h"
50 #include "kadatabase.h"
51 #include "kaprocs.h"
53 extern struct ubik_dbase *KA_dbase;
54 struct kaheader cheader;
55 Date cheaderReadTime; /* time cheader last read in */
56 extern struct afsconf_dir *KA_conf; /* for getting cell info */
60 char lrealm[MAXKTCREALMLEN];
62 #ifndef EXPIREPW /* password expiration default yes */
63 #define EXPIREPW
64 #endif
66 #ifndef AUTOCPWINTERVAL
67 #define AUTOCPWINTERVAL (24*3600)
68 #endif
69 #ifndef AUTOCPWUPDATES
70 #define AUTOCPWUPDATES 128
71 #endif
73 extern int npwSums;
75 static afs_int32 autoCPWInterval;
76 static afs_int32 autoCPWUpdates;
78 static afs_int32 set_password(struct ubik_trans *tt, char *name,
79 char *instance,
80 struct ktc_encryptionKey *password,
81 afs_int32 kvno, afs_int32 caller);
82 static afs_int32 impose_reuse_limits(EncryptionKey *password,
83 struct kaentry *tentry);
84 static int create_user(struct ubik_trans *tt, char *name, char *instance,
85 struct ktc_encryptionKey *key, afs_int32 caller,
86 afs_int32 flags);
88 /* This routine is called whenever an RPC interface needs the time. It uses
89 the current time to randomize a 128 bit value that is used to change the
90 AuthServer Admin and TGS keys automatically. */
92 static Date nextAutoCPWTime = 0;
93 static afs_int32 totalUpdates = 0;
95 /* This routine is ostensibly to get the current time, but basically its job is
96 to periodically update a random number. It also periodically updates the
97 keys for the builtin servers. This is why it needs a transaction pointer
98 and returns an error code. If the caller is in a read transaction, the tt
99 ptr should be zero and the return code need not be checked. */
101 static afs_int32
102 get_time(Date *timeP,
103 struct ubik_trans *tt, /* tt != 0: a write transaction */
104 int admin) /* the caller is an admin user */
106 /* random value used to change Admin & TGS keys, this is at risk during
107 * multi-threaded operation, but I think the consequences are fairly
108 * harmless. */
109 static afs_uint32 random_value[4];
111 struct timeval time;
112 unsigned int bit, nbit;
113 int i;
114 afs_int32 to;
116 gettimeofday(&time, 0);
117 bit = (random_value[3] >> 31) & 1; /* get high bit of high word */
118 for (i = 0; i < 4; i++) {
119 nbit = random_value[i] >> 31;
120 random_value[i] = (random_value[i] << 1) + bit;
121 bit = nbit & 1;
123 /* get 60ths from usec. This is all the real randomness there is. */
124 random_value[0] += time.tv_usec / 16667;
126 if (nextAutoCPWTime == 0) { /* initialize things */
127 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
128 memcpy(&random_value[0], &time, 8);
129 memcpy(&random_value[2], &time, 8);
132 if ((++totalUpdates >= autoCPWUpdates) && tt && /* a write transaction */
133 ((admin && (time.tv_sec >= nextAutoCPWTime))
134 || (time.tv_sec >= nextAutoCPWTime + autoCPWInterval))) {
135 struct ktc_encryptionKey key;
136 char buf[4 * sizeof(key) + 1];
137 struct kaentry tentry;
138 afs_int32 code;
139 char bob[KA_TIMESTR_LEN];
141 ka_timestr(time.tv_sec, bob, KA_TIMESTR_LEN);
142 es_Report("Auto CPW at %s\n", bob);
143 if (!admin)
144 es_Report(" ... even though no ADMIN user\n");
146 code = FindBlock(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &to, &tentry);
147 if (code)
148 return code;
149 if (to) { /* check if auto cpw is disabled */
150 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
151 memcpy(&key, &random_value[0], sizeof(key));
152 des_fixup_key_parity(ktc_to_cblock(&key));
153 code =
154 set_password(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
156 if (code == 0) {
157 des_init_random_number_generator(ktc_to_cblock(&key));
158 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
159 sizeof(key));
160 es_Report("New Admin key is %s\n", buf);
161 } else {
162 es_Report
163 ("in get_time: set_password failed because: %d\n",
164 code);
165 return code;
170 code = FindBlock(tt, KA_TGS_NAME, lrealm, &to, &tentry);
171 if (code)
172 return code;
173 if (to) { /* check if auto cpw is disabled */
174 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
175 memcpy(&key, &random_value[2], sizeof(key));
176 des_fixup_key_parity(ktc_to_cblock(&key));
177 code = set_password(tt, KA_TGS_NAME, lrealm, &key, 0, 0);
178 if (code == 0) {
179 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
180 sizeof(key));
181 es_Report("New TGS key is %s\n", buf);
182 } else {
183 es_Report
184 ("in get_time: set_password failed because: %s\n",
185 afs_error_message(code));
186 return code;
190 code = ka_FillKeyCache(tt); /* ensure in-core copy is uptodate */
191 if (code)
192 return code;
194 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
195 totalUpdates = 0;
197 if (timeP)
198 *timeP = time.tv_sec;
199 return 0;
202 static int noAuthenticationRequired; /* global state */
203 static int recheckNoAuth; /* global state */
205 /* kaprocsInited is sort of a lock: during a transaction only one process runs
206 while kaprocsInited is false. */
208 static int kaprocsInited = 0;
210 /* This variable is protected by the kaprocsInited flag. */
212 static int (*rebuildDatabase) (struct ubik_trans *);
214 /* This is called to initialize the database */
216 static int
217 initialize_database(struct ubik_trans *tt)
219 struct ktc_encryptionKey key;
220 int code;
222 gettimeofday((struct timeval *)&key, 0); /* this is just a cheap seed key */
223 des_fixup_key_parity(ktc_to_cblock(&key));
224 des_init_random_number_generator(ktc_to_cblock(&key));
225 if ((code = des_random_key(ktc_to_cblock(&key)))
226 || (code =
227 create_user(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
228 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
229 return code;
230 if ((code = des_random_key(ktc_to_cblock(&key)))
231 || (code =
232 create_user(tt, KA_TGS_NAME, lrealm, &key, 0,
233 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
234 return code;
235 return 0;
238 /* This routine handles initialization required by this module. The initFlags
239 parameter passes some information about the command line arguments. */
241 afs_int32
242 init_kaprocs(const char *lclpath, int initFlags)
244 int code;
245 struct ubik_trans *tt;
246 struct ktc_encryptionKey key;
247 afs_int32 kvno;
249 kaprocsInited = 0;
250 if (myHost == 0)
251 return KAINTERNALERROR;
252 if (KA_conf == 0)
253 return KAINTERNALERROR;
254 code = afsconf_GetLocalCell(KA_conf, lrealm, sizeof(lrealm));
255 if (code) {
256 printf("** Can't determine local cell name!\n");
257 return KANOCELLS;
259 ucstring(lrealm, lrealm, sizeof(lrealm));
261 recheckNoAuth = 1;
262 if (initFlags & 1)
263 noAuthenticationRequired = 1;
264 if (initFlags & 2)
265 recheckNoAuth = 0;
266 if (recheckNoAuth)
267 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
268 if (noAuthenticationRequired)
269 printf("Running server with security disabled\n");
271 if (initFlags & 4) {
272 autoCPWInterval = 10;
273 autoCPWUpdates = 10;
274 } else {
275 autoCPWInterval = AUTOCPWINTERVAL;
276 autoCPWUpdates = AUTOCPWUPDATES;
279 init_kadatabase(initFlags);
280 rebuildDatabase = initialize_database;
282 if ((code = InitAuthServ(&tt, LOCKREAD, 0))) {
283 printf("init_kaprocs: InitAuthServ failed: code = %d\n", code);
284 return code;
286 code = ka_LookupKey(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &kvno, &key);
287 if (code) {
288 ubik_AbortTrans(tt);
289 printf
290 ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n",
291 code);
292 return code;
294 des_init_random_number_generator(ktc_to_cblock(&key));
296 code = ubik_EndTrans(tt);
297 if (code) {
298 printf("init_kaprocs: ubik_EndTrans failed: code = %d\n", code);
299 return code;
302 kaux_opendb((char *)lclpath);/* aux database stores failure counters */
303 rebuildDatabase = 0; /* only do this during init */
304 kaprocsInited = 1;
305 return 0;
308 /* These variable are for returning debugging info about the state of the
309 server. If they get trashed during multi-threaded operation it doesn't
310 matter. */
312 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
313 char *lastOperation = 0; /* name of last operation */
314 static Date lastTrans; /* time of last transaction */
316 static char adminPrincipal[256];
317 static char authPrincipal[256];
318 static char tgsPrincipal[256];
319 static char tgsServerPrincipal[256];
321 void
322 save_principal(char *p, char *n, char *i, char *c)
324 int s = 255;
325 int l;
327 l = strlen(n);
328 if (l > s)
329 return;
330 strcpy(p, n);
331 s -= l;
332 if (i && strlen(i)) {
333 if (s-- <= 0)
334 return;
335 strcat(p, ".");
336 l = strlen(i);
337 if (l > s)
338 return;
339 strcat(p, i);
340 s -= l;
342 if (c && strlen(c)) {
343 if (s-- <= 0)
344 return;
345 strcat(p, "@");
346 l = strlen(c);
347 if (l > s)
348 return;
349 strcat(p, c);
353 static afs_int32
354 check_auth(struct rx_call *call,
355 struct ubik_trans *at,
356 int admin, /* require caller to be ADMIN */
357 afs_int32 *acaller_id)
359 rxkad_level level;
360 char name[MAXKTCNAMELEN];
361 char instance[MAXKTCNAMELEN];
362 char cell[MAXKTCREALMLEN];
363 afs_int32 kvno;
364 Date expiration; /* checked by Security Module */
365 struct kaentry tentry;
366 int code;
367 int si;
369 *acaller_id = 0;
371 if (recheckNoAuth)
372 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
374 si = rx_SecurityClassOf(rx_ConnectionOf(call));
375 if (si == RX_SCINDEX_VAB) {
376 printf("No support for VAB security module yet.\n");
377 return -1;
378 } else if (si == RX_SCINDEX_NULL) {
379 code = KANOAUTH;
380 goto no_auth;
381 } else if (si != RX_SCINDEX_KAD) {
382 es_Report("Unknown security index %d\n", si);
383 return -1;
386 code =
387 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration, name,
388 instance, cell, &kvno);
389 if (code) {
390 goto no_auth;
392 if (level != rxkad_crypt) {
393 es_Report("Incorrect security level = %d\n", level);
394 code = KANOAUTH;
395 goto no_auth;
398 if (!name_instance_legal(name, instance))
399 return KABADNAME;
400 if (strlen(cell)) {
401 ka_PrintUserID
402 ("Authorization rejected because we don't understand intercell stuff yet: ",
403 name, instance, "");
404 printf("@%s\n", cell);
405 return KANOAUTH;
408 code = FindBlock(at, name, instance, acaller_id, &tentry);
409 if (code)
410 return code;
411 if (*acaller_id == 0) {
412 ka_PrintUserID("User ", name, instance, " unknown.\n");
413 return KANOENT;
415 save_principal(adminPrincipal, name, instance, 0);
417 if (admin) {
418 if (!(ntohl(tentry.flags) & KAFADMIN)) {
419 if (noAuthenticationRequired) {
420 ka_PrintUserID("Authorization approved for ", name, instance,
421 " because there is no authentication required\n");
422 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR,
423 instance, AUD_STR, cell, AUD_END);
424 return 0;
426 ka_PrintUserID("User ", name, instance, " is not ADMIN.\n");
427 return KANOAUTH;
429 osi_auditU(call, UseOfPrivilegeEvent, code, AUD_STR, name, AUD_STR,
430 instance, AUD_STR, cell, AUD_END);
432 return 0;
434 no_auth:
435 if (noAuthenticationRequired) {
436 es_Report
437 ("Caller w/o authorization approved no authentication required\n");
438 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR, instance,
439 AUD_STR, cell, AUD_END);
440 return 0;
442 return code; /* no auth info */
445 afs_int32
446 AwaitInitialization(void)
448 afs_int32 start = 0;
449 while (!kaprocsInited) {
450 if (!start)
451 start = time(0);
452 else if (time(0) - start > 5)
453 return UNOQUORUM;
454 IOMGR_Sleep(1);
456 return 0;
459 /* This is called by every RPC interface to create a Ubik transaction and read
460 the database header into core */
462 afs_int32
463 InitAuthServ(struct ubik_trans **tt,
464 int lock, /* indicate read/write transaction */
465 int *this_op) /* opcode of RPC proc, for COUNT_ABO */
467 int code;
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 */
472 if (this_op)
473 if ((code = AwaitInitialization()))
474 return code;
476 for (code = UNOQUORUM; code == UNOQUORUM;) {
477 if (lock == LOCKREAD)
478 code = ubik_BeginTransReadAny(KA_dbase, UBIK_READTRANS, tt);
479 else
480 code = ubik_BeginTrans(KA_dbase, UBIK_WRITETRANS, tt);
481 if (code == UNOQUORUM) { /* no quorum elected */
482 if (!start)
483 start = time(0);
484 else {
485 int delay = time(0) - start;
486 if (this_op) { /* punt quickly, if RPC call */
487 if (delay > 5)
488 return code;
489 } else { /* more patient during init. */
490 if (delay > 500)
491 return code;
494 printf("Waiting for quorum election.\n");
495 if (wait < 15.0)
496 wait *= 1.1;
497 IOMGR_Sleep((int)wait);
500 if (code)
501 return code;
502 if ((code = ubik_SetLock(*tt, 1, 1, lock))) {
503 if (this_op)
504 COUNT_ABO;
505 ubik_AbortTrans(*tt);
506 return code;
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);
512 if (code) {
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)))
521 return code;
522 if ((code = ubik_EndTrans(*tt)))
523 return code;
525 /* now open the read transaction that was originally requested. */
526 return InitAuthServ(tt, lock, this_op);
528 } else {
529 if ((code = CheckInit(*tt, rebuildDatabase))) {
530 if (this_op)
531 COUNT_ABO;
532 ubik_AbortTrans(*tt);
533 return code;
536 lastTrans = time(0);
537 ka_FillKeyCache(*tt); /* ensure in-core copy is uptodate */
538 return 0;
541 /* returns true if name is specially known by AuthServer */
543 static int
544 special_name(char *name, char *instance)
547 return ((!strcmp(name, KA_TGS_NAME) && !strcmp(instance, lrealm))
548 || (strcmp(name, KA_ADMIN_NAME) == 0));
551 static int
552 create_user(struct ubik_trans *tt, char *name, char *instance,
553 struct ktc_encryptionKey *key, afs_int32 caller,
554 afs_int32 flags)
556 int code;
557 afs_int32 to;
558 struct kaentry tentry;
559 afs_int32 maxLifetime;
561 code = FindBlock(tt, name, instance, &to, &tentry);
562 if (code)
563 return code;
564 if (to)
565 return KAEXIST; /* name already exists, we fail */
567 to = AllocBlock(tt, &tentry);
568 if (to == 0)
569 return KACREATEFAIL;
571 /* otherwise we have a block */
572 strncpy(tentry.userID.name, name, sizeof(tentry.userID.name));
573 strncpy(tentry.userID.instance, instance, sizeof(tentry.userID.instance));
574 tentry.flags = htonl(flags);
575 if (special_name(name, instance)) { /* this overrides key & version */
576 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
577 tentry.key_version = htonl(-1); /* don't save this key */
578 if ((code = ka_NewKey(tt, to, &tentry, key)))
579 return code;
580 } else {
581 memcpy(&tentry.key, key, sizeof(tentry.key));
582 tentry.key_version = htonl(0);
584 tentry.user_expiration = htonl(NEVERDATE);
585 code = get_time(&tentry.modification_time, tt, 1);
586 if (code)
587 return code;
589 /* time and addr of entry for guy changing this entry */
590 tentry.modification_time = htonl(tentry.modification_time);
591 tentry.modification_id = htonl(caller);
592 tentry.change_password_time = tentry.modification_time;
594 if (strcmp(name, KA_TGS_NAME) == 0)
595 maxLifetime = MAXKTCTICKETLIFETIME;
596 else if (strcmp(name, KA_ADMIN_NAME) == 0)
597 maxLifetime = 10 * 3600;
598 else if (strcmp(name, AUTH_SUPERUSER) == 0)
599 maxLifetime = 100 * 3600;
600 else
601 maxLifetime = 25 * 3600; /* regular users */
602 tentry.max_ticket_lifetime = htonl(maxLifetime);
604 code = ThreadBlock(tt, to, &tentry);
605 return code;
608 /* Put actual stub routines here */
610 afs_int32
611 SKAM_CreateUser(struct rx_call *call, char *aname, char *ainstance,
612 EncryptionKey ainitpw)
614 afs_int32 code;
616 code = kamCreateUser(call, aname, ainstance, ainitpw);
617 osi_auditU(call, AFS_KAM_CrUserEvent, code, AUD_STR, aname, AUD_STR,
618 ainstance, AUD_END);
619 return code;
623 afs_int32
624 kamCreateUser(struct rx_call *call, char *aname, char *ainstance,
625 EncryptionKey ainitpw)
627 int code;
628 struct ubik_trans *tt;
629 afs_int32 caller; /* Disk offset of caller's entry */
631 COUNT_REQ(CreateUser);
632 if (!des_check_key_parity(EncryptionKey_to_cblock(&ainitpw)) || des_is_weak_key(EncryptionKey_to_cblock(&ainitpw)))
633 return KABADKEY;
634 if (!name_instance_legal(aname, ainstance))
635 return KABADNAME;
636 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
637 return code;
638 code = check_auth(call, tt, 1, &caller);
639 if (code) {
640 COUNT_ABO;
641 ubik_AbortTrans(tt);
642 return code;
644 code = create_user(tt, aname, ainstance, EncryptionKey_to_ktc(&ainitpw), caller, KAFNORMAL);
645 if (code) {
646 COUNT_ABO;
647 ubik_AbortTrans(tt);
648 return code;
650 code = ubik_EndTrans(tt);
651 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
652 LOG_CRUSER);
653 return code;
656 afs_int32
657 SKAA_ChangePassword(struct rx_call *call, char *aname, char *ainstance,
658 ka_CBS *arequest, ka_BBS *oanswer)
660 afs_int32 code;
662 code = ChangePassWord(call, aname, ainstance, arequest, oanswer);
663 osi_auditU(call, AFS_KAA_ChPswdEvent, code, AUD_STR, aname, AUD_STR,
664 ainstance, AUD_END);
665 return code;
668 afs_int32
669 ChangePassWord(struct rx_call *call, char *aname, char *ainstance,
670 ka_CBS *arequest, ka_BBS *oanswer)
672 int code;
673 struct ubik_trans *tt;
674 afs_int32 to; /* offset of block */
675 struct kaentry tentry;
676 struct ka_cpwRequest request; /* request after decryption */
677 char *answer; /* where answer is to be put */
678 int answer_len; /* length of answer packet */
679 afs_int32 kvno; /* requested key version number */
680 des_key_schedule user_schedule; /* key schedule for user's key */
681 Date request_time; /* time request originated */
683 COUNT_REQ(ChangePassword);
684 if (!name_instance_legal(aname, ainstance))
685 return KABADNAME;
686 if (strcmp(ainstance, KA_ADMIN_NAME) == 0)
687 return KABADNAME;
688 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
689 return code;
691 code = FindBlock(tt, aname, ainstance, &to, &tentry);
692 if (code) {
693 goto abort;
695 if (to == 0) { /* no such user */
696 code = KANOENT;
697 goto abort;
699 if (ntohl(tentry.flags) & KAFNOCPW) {
700 code = KABADCPW;
701 goto abort;
704 /* decrypt request w/ user password */
705 if ((code = des_key_sched(ktc_to_cblock(&tentry.key), user_schedule)))
706 es_Report("In KAChangePassword: key_sched returned %d\n", code);
707 des_pcbc_encrypt(arequest->SeqBody, &request,
708 min(arequest->SeqLen, sizeof(request)), user_schedule,
709 ktc_to_cblockptr(&tentry.key), DECRYPT);
711 /* validate the request */
712 request_time = ntohl(request.time); /* reorder date */
713 kvno = ntohl(request.kvno);
714 if (check_ka_skew(request_time, time(NULL), KTC_TIME_UNCERTAINTY) ||
715 strncmp(request.label, KA_CPW_REQ_LABEL, sizeof(request.label)) ||
716 request.spare || kvno > MAXKAKVNO) { /* these are reserved */
717 code = KABADREQUEST;
718 goto abort;
721 /* check to see if the new password was used before, or if there has
722 * not been sufficient time since the last password change
724 code = impose_reuse_limits(ktc_to_EncryptionKey(&request.newpw), &tentry);
725 if (code) {
726 goto abort;
729 /* Create the Answer Packet */
730 answer_len = sizeof(Date) + KA_LABELSIZE;
731 if (oanswer->MaxSeqLen < answer_len) {
732 code = KAANSWERTOOLONG;
733 goto abort;
735 oanswer->SeqLen = answer_len;
736 answer = oanswer->SeqBody;
737 request.time = htonl(request_time + 1);
738 memcpy(answer, (char *)&request.time, sizeof(Date));
739 answer += sizeof(Date);
740 memcpy(answer, KA_CPW_ANS_LABEL, KA_LABELSIZE);
742 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, answer_len,
743 user_schedule, ktc_to_cblockptr(&tentry.key), ENCRYPT);
745 code = set_password(tt, aname, ainstance, &request.newpw, kvno, 0);
746 if (code) {
747 code = KAIO;
748 goto abort;
751 cheader.stats.cpws = htonl(ntohl(cheader.stats.cpws) + 1);
752 code =
753 kawrite(tt, DOFFSET(0, &cheader, &cheader.stats.cpws),
754 (char *)&cheader.stats.cpws, sizeof(afs_int32));
755 if (code) {
756 code = KAIO;
757 goto abort;
760 code = ubik_EndTrans(tt);
761 return code;
763 abort:
764 COUNT_ABO;
765 ubik_AbortTrans(tt);
766 return code;
769 static afs_int32
770 impose_reuse_limits(EncryptionKey *password, struct kaentry *tentry)
772 int code;
773 Date now;
774 int i;
775 extern int MinHours;
776 afs_uint32 newsum;
778 if (!tentry->pwsums[0] && npwSums > 1 && !tentry->pwsums[1])
779 return 0; /* password reuse limits not in effect */
781 code = get_time(&now, 0, 0);
782 if (code)
783 return code;
785 if ((now - ntohl(tentry->change_password_time)) < MinHours * 60 * 60)
786 return KATOOSOON;
788 if (!memcmp(password, &(tentry->key), sizeof(EncryptionKey)))
789 return KAREUSED;
791 code = ka_KeyCheckSum((char *)password, &newsum);
792 if (code)
793 return code;
795 newsum = newsum & 0x000000ff;
796 for (i = 0; i < npwSums; i++) {
797 if (newsum == tentry->pwsums[i])
798 return KAREUSED;
801 return 0;
805 static afs_int32
806 set_password(struct ubik_trans *tt, char *name, char *instance,
807 struct ktc_encryptionKey *password, afs_int32 kvno, afs_int32 caller)
809 afs_int32 code;
810 afs_int32 to; /* offset of block */
811 struct kaentry tentry;
812 Date now;
813 int i;
814 extern int npwSums;
815 afs_uint32 newsum;
817 code = FindBlock(tt, name, instance, &to, &tentry);
818 if (code)
819 return code;
820 if (to == 0)
821 return KANOENT; /* no such user */
823 /* if password reuse limits in effect, set the checksums, the hard way */
824 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
825 /* do nothing, no limits */ ;
826 } else {
827 code = ka_KeyCheckSum((char *)&(tentry.key), &newsum);
828 if (code)
829 return code;
830 for (i = npwSums - 1; i; i--)
831 tentry.pwsums[i] = tentry.pwsums[i - 1];
832 tentry.pwsums[0] = newsum & 0x000000ff;
836 if (special_name(name, instance)) { /* set key over rides key_version */
837 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
838 if ((code = ka_NewKey(tt, to, &tentry, password)))
839 return (code);
840 } else {
841 memcpy(&tentry.key, password, sizeof(tentry.key));
842 if (!kvno) {
843 kvno = ntohl(tentry.key_version);
844 if ((kvno < 1) || (kvno >= MAXKAKVNO))
845 kvno = 1;
846 else
847 kvno++;
849 tentry.key_version = htonl((afs_int32) kvno); /* requested key version */
854 /* no-write prevents recursive call to set_password by AuthCPW code. */
855 code = get_time(&now, 0, 0);
856 if (code)
857 return code;
858 if (caller) {
859 tentry.modification_time = htonl(now);
860 tentry.modification_id = htonl(caller);
863 tentry.change_password_time = htonl(now);
865 if ((code = kawrite(tt, to, (char *) &tentry, sizeof(tentry))))
866 return (KAIO);
867 return (0);
870 afs_int32
871 SKAM_SetPassword(struct rx_call *call, char *aname, char *ainstance,
872 afs_int32 akvno, EncryptionKey apassword)
874 afs_int32 code;
876 code = kamSetPassword(call, aname, ainstance, akvno, apassword);
877 osi_auditU(call, AFS_KAM_SetPswdEvent, code, AUD_STR, aname, AUD_STR,
878 ainstance, AUD_END);
879 return code;
882 afs_int32
883 kamSetPassword(struct rx_call *call, char *aname, char *ainstance,
884 afs_int32 akvno, EncryptionKey apassword)
886 int code;
887 struct ubik_trans *tt;
888 afs_int32 caller; /* Disk offset of caller's entry */
889 struct kaentry tentry;
891 COUNT_REQ(SetPassword);
892 if (akvno > MAXKAKVNO)
893 return KABADARGUMENT;
894 if (!des_check_key_parity(EncryptionKey_to_cblock(&apassword)) || des_is_weak_key(EncryptionKey_to_cblock(&apassword)))
895 return KABADKEY;
897 if (!name_instance_legal(aname, ainstance))
898 return KABADNAME;
899 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
900 return code;
901 code = check_auth(call, tt, 0, &caller);
902 if (code) {
903 goto abort;
905 if ((code = karead(tt, caller, (char *)&tentry, sizeof(tentry)))) {
906 code = KAIO;
907 goto abort;
909 /* if the user is changing his own password or ADMIN then go ahead. */
910 if ((strcmp(tentry.userID.name, aname) == 0)
911 && (strcmp(tentry.userID.instance, ainstance) == 0)) {
912 if (ntohl(tentry.flags) & KAFNOCPW)
913 code = KABADCPW;
914 else {
915 code = impose_reuse_limits(&apassword, &tentry);
916 if (!code)
917 code =
918 set_password(tt, aname, ainstance, EncryptionKey_to_ktc(&apassword), akvno, 0);
920 } else if (ntohl(tentry.flags) & KAFADMIN) {
921 code = set_password(tt, aname, ainstance, EncryptionKey_to_ktc(&apassword), akvno, caller);
922 } else
923 code = KANOAUTH;
924 if (code)
925 goto abort;
927 code = ubik_EndTrans(tt);
928 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
929 LOG_CHPASSWD);
930 return code;
932 abort:
933 COUNT_ABO;
934 ubik_AbortTrans(tt);
935 return code;
938 static Date
939 CoerseLifetime(Date start, Date end)
941 unsigned char kerberosV4Life;
942 kerberosV4Life = time_to_life(start, end);
943 end = life_to_time(start, kerberosV4Life);
944 return end;
947 static afs_int32
948 GetEndTime(Date start, /* start time of ticket */
949 Date reqEnd, /* requested end time */
950 Date expiration, /* authorizing ticket's expiration */
951 struct kaentry *caller,
952 struct kaentry *server,
953 Date *endP) /* actual end time */
955 Date cExp, sExp;
956 Date cLife, sLife;
957 Date end;
959 if (ntohl(caller->flags) & KAFNOTGS)
960 return KABADUSER; /* no new tickets for this user */
961 if (expiration && (ntohl(server->flags) & KAFNOSEAL))
962 return KABADSERVER; /* can't be target of GetTicket req */
963 if (!expiration)
964 expiration = NEVERDATE;
966 cExp = ntohl(caller->user_expiration);
967 sExp = ntohl(server->user_expiration);
968 if (cExp < start)
969 return KAPWEXPIRED;
970 if (sExp < start)
971 return KABADSERVER;
972 cLife = start + ntohl(caller->max_ticket_lifetime);
973 sLife = start + ntohl(server->max_ticket_lifetime);
974 end =
975 umin(umin(reqEnd, expiration),
976 umin(umin(cLife, sLife), umin(cExp, sExp)));
977 end = CoerseLifetime(start, end);
978 *endP = end;
979 return 0;
982 static afs_int32
983 PrepareTicketAnswer(ka_BBS *oanswer, afs_int32 challenge, char *ticket,
984 afs_int32 ticketLen, struct ktc_encryptionKey *sessionKey,
985 Date start, Date end, struct kaentry *caller,
986 struct kaentry *server, char *cell, char *label)
988 afs_int32 code;
989 struct ka_ticketAnswer *answer;
990 afs_int32 cksum;
992 code = KAANSWERTOOLONG;
993 if (oanswer->MaxSeqLen <
994 sizeof(struct ka_ticketAnswer) - 5 * MAXKTCNAMELEN - MAXKTCTICKETLEN +
995 ticketLen)
996 return code;
998 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
999 answer->challenge = htonl(challenge);
1000 memcpy(&answer->sessionKey, sessionKey, sizeof(struct ktc_encryptionKey));
1001 answer->startTime = htonl(start);
1002 answer->endTime = htonl(end);
1003 answer->kvno = server->key_version;
1004 answer->ticketLen = htonl(ticketLen);
1007 char *ans = answer->name; /* pointer to variable part */
1008 int rem; /* space remaining */
1009 int len; /* macro temp. */
1011 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1012 #undef putstr
1013 #define putstr(str) len = strlen (str)+1;\
1014 if (rem < len) return code;\
1015 strcpy (ans, str);\
1016 ans += len; rem -= len
1017 putstr(caller->userID.name);
1018 putstr(caller->userID.instance);
1019 putstr(cell);
1020 putstr(server->userID.name);
1021 putstr(server->userID.instance);
1022 if (rem < ticketLen + KA_LABELSIZE)
1023 return code;
1024 memcpy(ans, ticket, ticketLen);
1025 ans += ticketLen;
1026 if (label)
1027 memcpy(ans, label, KA_LABELSIZE);
1028 else
1029 memset(ans, 0, KA_LABELSIZE);
1030 ans += KA_LABELSIZE;
1031 oanswer->SeqLen = (ans - oanswer->SeqBody);
1033 cksum = 0;
1034 answer->cksum = htonl(cksum);
1035 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1036 if (oanswer->SeqLen > oanswer->MaxSeqLen)
1037 return code;
1038 return 0;
1041 /* This is used to get a ticket granting ticket or an admininstration ticket.
1042 These two specific, built-in servers are special cases, which require the
1043 client's key as an additional security precaution. The GetTicket operation
1044 is normally disabled for these two principals. */
1046 static afs_int32
1047 Authenticate(int version, struct rx_call *call, char *aname, char *ainstance,
1048 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1050 int code;
1051 struct ubik_trans *tt;
1052 afs_int32 to; /* offset of block */
1053 kaentry tentry;
1054 struct kaentry server; /* entry for desired server */
1055 struct ka_gettgtRequest request; /* request after decryption */
1056 int tgt, adm; /* type of request */
1057 char *sname; /* principal of server */
1058 char *sinst;
1059 char ticket[MAXKTCTICKETLEN]; /* our copy of the ticket */
1060 int ticketLen;
1061 struct ktc_encryptionKey sessionKey; /* we have to invent a session key */
1062 char *answer; /* where answer is to be put */
1063 int answer_len; /* length of answer packet */
1064 Date answer_time; /* 1+ request time in network order */
1065 afs_int32 temp; /* for htonl conversions */
1066 des_key_schedule user_schedule; /* key schedule for user's key */
1067 afs_int32 tgskvno; /* key version of service key */
1068 struct ktc_encryptionKey tgskey; /* service key for encrypting ticket */
1069 Date now;
1070 afs_uint32 pwexpires;
1072 COUNT_REQ(Authenticate);
1073 if (!name_instance_legal(aname, ainstance))
1074 return KABADNAME;
1075 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1076 return code;
1077 get_time(&now, 0, 0);
1079 sname = sinst = NULL;
1081 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1082 if (code) {
1083 goto abort;
1085 if (to == 0) { /* no such user */
1086 code = KANOENT;
1087 goto abort;
1089 #ifdef LOCKPW
1090 /* have to check for locked before verifying the password, otherwise all
1091 * KALOCKED means is "yup, you guessed the password all right, now wait a
1092 * few minutes and we'll let you in"
1094 if (kaux_islocked
1095 (to, (u_int) tentry.misc_auth_bytes[ATTEMPTS],
1096 (afs_uint32) tentry.misc_auth_bytes[LOCKTIME] << 9)) {
1097 code = KALOCKED;
1098 goto abort;
1100 #endif /* LOCKPW */
1102 save_principal(authPrincipal, aname, ainstance, 0);
1104 /* decrypt request w/ user password */
1105 if ((code = des_key_sched(ktc_to_cblock(&tentry.key), user_schedule)))
1106 es_Report("In KAAuthenticate: key_sched returned %d\n", code);
1107 des_pcbc_encrypt(arequest->SeqBody, &request,
1108 min(arequest->SeqLen, sizeof(request)), user_schedule,
1109 ktc_to_cblockptr(&tentry.key), DECRYPT);
1111 request.time = ntohl(request.time); /* reorder date */
1112 tgt = !strncmp(request.label, KA_GETTGT_REQ_LABEL, sizeof(request.label));
1113 adm = !strncmp(request.label, KA_GETADM_REQ_LABEL, sizeof(request.label));
1114 if (!(tgt || adm)) {
1115 kaux_inc(to, ((unsigned char)tentry.misc_auth_bytes[LOCKTIME]) << 9);
1116 code = KABADREQUEST;
1117 goto abort;
1118 } else
1119 kaux_write(to, 0, 0); /* reset counters */
1121 #ifdef EXPIREPW
1122 if (!tentry.misc_auth_bytes[EXPIRES]) {
1123 /* 0 in the database means never, but 0 on the network means today */
1124 /* 255 on the network means "long time, maybe never" */
1125 pwexpires = 255;
1126 } else {
1127 pwexpires = tentry.misc_auth_bytes[EXPIRES];
1129 pwexpires =
1130 ntohl(tentry.change_password_time) + 24 * 60 * 60 * pwexpires;
1131 if (adm) { /* provide a little slack for admin ticket */
1132 pwexpires += 30 * 24 * 60 * 60; /* 30 days */
1134 if (pwexpires < now) {
1135 code = KAPWEXPIRED;
1136 goto abort;
1137 } else {
1138 pwexpires = (pwexpires - now) / (24 * 60 * 60);
1139 if (pwexpires > 255)
1140 pwexpires = 255;
1143 #endif /* EXPIREPW */
1145 if (check_ka_skew(request.time, now, KTC_TIME_UNCERTAINTY)) {
1146 #if 0
1147 if (oanswer->MaxSeqLen < sizeof(afs_int32))
1148 code = KAANSWERTOOLONG;
1149 else { /* return our time if possible */
1150 oanswer->SeqLen = sizeof(afs_int32);
1151 request.time = htonl(now);
1152 memcpy(oanswer->SeqBody, &request.time, sizeof(afs_int32));
1154 #endif
1155 code = KACLOCKSKEW;
1156 goto abort;
1158 sname = (tgt ? KA_TGS_NAME : KA_ADMIN_NAME);
1159 sinst = (tgt ? lrealm : KA_ADMIN_INST);
1160 code = FindBlock(tt, sname, sinst, &to, &server);
1161 if (code)
1162 goto abort;
1163 if (to == 0) {
1164 code = KANOENT;
1165 goto abort;
1168 tgskvno = ntohl(server.key_version);
1169 memcpy(&tgskey, &server.key, sizeof(tgskey));
1171 code = des_random_key(ktc_to_cblock(&sessionKey));
1172 if (code) {
1173 code = KANOKEYS;
1174 goto abort;
1177 code = GetEndTime(start, end, 0 /*!GetTicket */ , &tentry, &server, &end);
1178 if (code)
1179 goto abort;
1181 code =
1182 tkt_MakeTicket(ticket, &ticketLen, &tgskey, aname, ainstance, "",
1183 start, end, &sessionKey,
1184 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), sname,
1185 sinst);
1186 if (code)
1187 goto abort;
1189 switch (version) {
1190 case 0:
1191 answer_len =
1192 ticketLen + sizeof(Date) + sizeof(struct ktc_encryptionKey) +
1193 2 * sizeof(afs_int32) + KA_LABELSIZE;
1194 answer_len = round_up_to_ebs(answer_len);
1195 if (answer_len > oanswer->MaxSeqLen) {
1196 code = KAANSWERTOOLONG;
1197 goto abort;
1199 oanswer->SeqLen = answer_len;
1200 answer = oanswer->SeqBody;
1201 answer_time = htonl(request.time + 1);
1202 memcpy(answer, (char *)&answer_time, sizeof(Date));
1203 answer += sizeof(Date);
1204 memcpy(answer, (char *)&sessionKey, sizeof(struct ktc_encryptionKey));
1205 answer += sizeof(struct ktc_encryptionKey);
1206 temp = htonl(tgskvno);
1207 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1208 answer += sizeof(afs_int32);
1209 temp = htonl(ticketLen);
1210 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1211 answer += sizeof(afs_int32);
1212 memcpy(answer, ticket, ticketLen);
1213 answer += ticketLen;
1214 memcpy(answer, (tgt ? KA_GETTGT_ANS_LABEL : KA_GETADM_ANS_LABEL),
1215 KA_LABELSIZE);
1216 break;
1217 case 1:
1218 case 2:
1219 code =
1220 PrepareTicketAnswer(oanswer, request.time + 1, ticket, ticketLen,
1221 &sessionKey, start, end, &tentry, &server, "",
1222 (tgt ? KA_GETTGT_ANS_LABEL :
1223 KA_GETADM_ANS_LABEL));
1224 if (code)
1225 goto abort;
1226 #ifdef EXPIREPW
1227 if ((version == 2)
1228 && oanswer->SeqLen < oanswer->MaxSeqLen + sizeof(afs_int32)) {
1229 temp = pwexpires << 24; /* move it into the high byte */
1230 pwexpires = htonl(temp);
1232 memcpy((char *)oanswer->SeqBody + oanswer->SeqLen, &pwexpires,
1233 sizeof(afs_int32));
1234 oanswer->SeqLen += sizeof(afs_int32);
1235 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1236 if (oanswer->SeqLen > oanswer->MaxSeqLen) {
1237 code = KAANSWERTOOLONG;
1238 goto abort;
1241 #endif /* EXPIREPW */
1242 break;
1244 default:
1245 code = KAINTERNALERROR;
1246 goto abort;
1248 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1249 user_schedule, ktc_to_cblockptr(&tentry.key), ENCRYPT);
1250 code = ubik_EndTrans(tt);
1251 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host,
1252 LOG_AUTHENTICATE);
1253 return code;
1255 abort:
1256 COUNT_ABO;
1257 ubik_AbortTrans(tt);
1258 KALOG(aname, ainstance, sname, sinst, NULL, call->conn->peer->host,
1259 LOG_AUTHFAILED);
1260 return code;
1263 afs_int32
1264 SKAA_Authenticate_old(struct rx_call *call, char *aname, char *ainstance,
1265 Date start, Date end, ka_CBS *arequest,
1266 ka_BBS *oanswer)
1268 int code;
1270 IOMGR_Sleep(1); /* discourage use of this mechanism */
1271 code =
1272 Authenticate(0, call, aname, ainstance, start, end, arequest,
1273 oanswer);
1274 osi_auditU(call, AFS_KAA_AuthOEvent, code, AUD_STR, aname, AUD_STR,
1275 ainstance, AUD_END);
1277 return code;
1280 afs_int32
1281 SKAA_Authenticate(struct rx_call *call, char *aname, char *ainstance,
1282 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1284 int code;
1286 code =
1287 Authenticate(1, call, aname, ainstance, start, end, arequest,
1288 oanswer);
1289 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1290 ainstance, AUD_END);
1292 return code;
1295 afs_int32
1296 SKAA_AuthenticateV2(struct rx_call *call, char *aname, char *ainstance,
1297 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1299 int code;
1301 code =
1302 Authenticate(2, call, aname, ainstance, start, end, arequest,
1303 oanswer);
1304 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1305 ainstance, AUD_END);
1307 return code;
1310 afs_int32
1311 SKAM_SetFields(struct rx_call *call,
1312 char *aname,
1313 char *ainstance,
1314 afs_int32 aflags,
1315 Date aexpiration,
1316 afs_int32 alifetime,
1317 afs_int32 amaxAssociates,
1318 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1319 afs_int32 spare2)
1321 afs_int32 code;
1323 code =
1324 kamSetFields(call, aname, ainstance, aflags, aexpiration, alifetime,
1325 amaxAssociates, misc_auth_bytes, spare2);
1326 osi_auditU(call, AFS_KAM_SetFldEvent, code, AUD_STR, aname, AUD_STR,
1327 ainstance, AUD_LONG, aflags, AUD_DATE, aexpiration, AUD_LONG,
1328 alifetime, AUD_LONG, amaxAssociates, AUD_END);
1329 return code;
1332 afs_int32
1333 kamSetFields(struct rx_call *call,
1334 char *aname,
1335 char *ainstance,
1336 afs_int32 aflags,
1337 Date aexpiration,
1338 afs_int32 alifetime,
1339 afs_int32 amaxAssociates,
1340 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1341 afs_int32 spare2)
1343 afs_int32 code;
1344 Date now;
1345 struct ubik_trans *tt;
1346 afs_int32 caller;
1347 afs_int32 tentry_offset; /* offset of entry */
1348 struct kaentry tentry;
1349 unsigned char newvals[4];
1351 COUNT_REQ(SetFields);
1353 if (spare2)
1354 return KABADARGUMENT; /* not supported yet... */
1356 /* make sure we're supposed to do something */
1357 if (!(aflags || aexpiration || alifetime || (amaxAssociates >= 0)
1358 || misc_auth_bytes)
1359 || ((aflags & ~KAFNORMAL) & ~KAF_SETTABLE_FLAGS))
1360 return KABADARGUMENT; /* arguments no good */
1361 if (!name_instance_legal(aname, ainstance))
1362 return KABADNAME;
1363 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1364 return code;
1365 code = check_auth(call, tt, 1, &caller);
1366 if (code) {
1367 goto abort;
1370 code = FindBlock(tt, aname, ainstance, &tentry_offset, &tentry);
1371 if (code)
1372 goto abort;
1373 if (tentry_offset == 0) { /* no such user */
1374 code = KANOENT;
1375 goto abort;
1377 if ((ntohl(tentry.flags) & KAFNORMAL) == 0)
1378 return KAINTERNALERROR;
1379 if (aflags) {
1380 /* Keep track of the total number of admin accounts. This way we can
1381 * update database without any admin privilege initially */
1382 if ((aflags & KAFADMIN) != (ntohl(tentry.flags) & KAFADMIN)) {
1383 /* if admin state is changing */
1384 int delta;
1385 if (ntohl(tentry.flags) & KAFADMIN)
1386 delta = -1;
1387 else
1388 delta = 1;
1389 if ((code = update_admin_count(tt, delta)))
1390 goto abort;
1392 tentry.flags =
1393 htonl((ntohl(tentry.flags) & ~KAF_SETTABLE_FLAGS) | aflags);
1395 if ((code = get_time(&now, tt, 1)))
1396 goto abort;
1397 if (aexpiration) {
1398 tentry.user_expiration = htonl(aexpiration);
1399 if (!ntohl(tentry.change_password_time)) {
1400 tentry.change_password_time = htonl(now);
1403 if (alifetime)
1404 tentry.max_ticket_lifetime = htonl(alifetime);
1406 #ifndef NOPWCONTROLS
1408 * We've packed a bunch of bytes into a long for backward compatibility.
1409 * These include password expiration time, and some failed login limits
1410 * counters. Now let's unpack them and stick them into the
1411 * kaentry struct. All the bytes have values in the range
1412 * 1..255, else they were not specified in the interface, and are
1413 * set to zero.
1414 * In the case of password expiration times, 1 means password never
1415 * expires (==>0), 2 means password only lives for one day (==>1),
1416 * and so on.
1418 if (misc_auth_bytes) {
1419 unpack_long(misc_auth_bytes, newvals);
1420 if (newvals[EXPIRES]) {
1421 tentry.misc_auth_bytes[EXPIRES] = newvals[EXPIRES] - 1;
1424 if (newvals[REUSEFLAGS]) {
1425 if (newvals[REUSEFLAGS] & KA_REUSEPW)
1426 memset(tentry.pwsums, 0, KA_NPWSUMS);
1427 else if ((newvals[REUSEFLAGS] & KA_NOREUSEPW)
1428 && !tentry.pwsums[0])
1429 tentry.pwsums[0] = 0xff;
1432 if (newvals[ATTEMPTS]) {
1433 tentry.misc_auth_bytes[ATTEMPTS] = newvals[ATTEMPTS] - 1;
1435 if (newvals[LOCKTIME]) {
1436 tentry.misc_auth_bytes[LOCKTIME] = newvals[LOCKTIME] - 1;
1439 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1442 #endif /* NOPWCONTROLS */
1444 if (amaxAssociates >= 0) {
1445 if ((ntohl(tentry.flags) & KAFASSOC)
1446 || (ntohl(tentry.flags) & KAFSPECIAL))
1447 return KAASSOCUSER;
1448 if (((ntohl(tentry.flags) & KAFASSOCROOT) == 0) && (amaxAssociates > 0)) /* convert normal user to assoc root */
1449 tentry.flags = htonl(ntohl(tentry.flags) | KAFASSOCROOT);
1450 tentry.misc.assocRoot.maxAssociates = htonl(amaxAssociates);
1453 tentry.modification_time = htonl(now);
1454 tentry.modification_id = htonl(caller);
1455 code = kawrite(tt, tentry_offset, (char *) &tentry, sizeof(tentry));
1456 if (code)
1457 goto abort;
1459 code = ubik_EndTrans(tt);
1460 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
1461 LOG_SETFIELDS);
1462 return code;
1464 abort:
1465 COUNT_ABO;
1466 ubik_AbortTrans(tt);
1467 return code;
1470 /* delete a user */
1472 afs_int32
1473 SKAM_DeleteUser(struct rx_call *call, char *aname, char *ainstance)
1475 afs_int32 code;
1477 code = kamDeleteUser(call, aname, ainstance);
1478 osi_auditU(call, AFS_KAM_DelUserEvent, code, AUD_STR, aname, AUD_STR,
1479 ainstance, AUD_END);
1480 return code;
1483 afs_int32
1484 kamDeleteUser(struct rx_call *call, char *aname, char *ainstance)
1486 int code;
1487 struct ubik_trans *tt;
1488 afs_int32 caller;
1489 afs_int32 to;
1490 struct kaentry tentry;
1491 unsigned int nfailures;
1492 afs_uint32 locktime;
1494 COUNT_REQ(DeleteUser);
1495 if (!name_instance_legal(aname, ainstance))
1496 return KABADNAME;
1497 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1498 return code;
1499 code = check_auth(call, tt, 1, &caller);
1500 if (code) {
1501 abort:
1502 COUNT_ABO;
1503 ubik_AbortTrans(tt);
1504 return code;
1507 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1508 if (code)
1509 goto abort;
1510 if (to == 0) { /* name not found */
1511 code = KANOENT;
1512 goto abort;
1515 kaux_read(to, &nfailures, &locktime);
1516 if (nfailures || locktime)
1517 kaux_write(to, 0, 0); /* zero failure counters at this offset */
1519 /* track all AuthServer identities */
1520 if (special_name(aname, ainstance))
1521 if ((code = ka_DelKey(tt, to, &tentry)))
1522 goto abort;
1524 if (ntohl(tentry.flags) & KAFADMIN) /* keep admin count up-to-date */
1525 if ((code = update_admin_count(tt, -1)))
1526 goto abort;
1528 if ((code = UnthreadBlock(tt, &tentry)) || (code = FreeBlock(tt, to)) || (code = get_time(0, tt, 1)) /* update randomness */
1530 goto abort;
1532 code = ubik_EndTrans(tt);
1533 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
1534 LOG_DELUSER);
1535 return code;
1538 /* we set a bit in here which indicates that the user's limit of
1539 * authentication failures has been exceeded. If that bit is not set,
1540 * kas can take it on faith that the user ID is not locked. If that
1541 * bit is set, kas has to check all the servers to find one who will
1542 * report that the ID is not locked, or else to find out when the ID
1543 * will be unlocked.
1545 afs_int32
1546 SKAM_GetEntry(struct rx_call *call,
1547 char *aname,
1548 char *ainstance,
1549 afs_int32 aversion, /* major version assumed by caller */
1550 kaentryinfo *aentry) /* entry data copied here */
1552 afs_int32 code;
1554 code = kamGetEntry(call, aname, ainstance, aversion, aentry);
1555 osi_auditU(call, AFS_KAM_GetEntEvent, code, AUD_STR, aname, AUD_STR,
1556 ainstance, AUD_END);
1557 return code;
1560 afs_int32
1561 kamGetEntry(struct rx_call *call,
1562 char *aname,
1563 char *ainstance,
1564 afs_int32 aversion, /* major version assumed by caller */
1565 kaentryinfo *aentry) /* entry data copied here */
1567 afs_int32 code;
1568 struct ubik_trans *tt;
1569 afs_int32 callerIndex;
1570 struct kaentry caller;
1571 afs_int32 to;
1572 afs_uint32 temp;
1573 struct kaentry tentry;
1574 rxkad_level enc_level = rxkad_clear;
1575 int callerIsAdmin = 0;
1577 COUNT_REQ(GetEntry);
1578 if (aversion != KAMAJORVERSION)
1579 return KAOLDINTERFACE;
1580 if (!name_instance_legal(aname, ainstance))
1581 return KABADNAME;
1582 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1583 return code;
1584 code = check_auth(call, tt, 0, &callerIndex);
1585 if (code) {
1586 goto abort;
1588 if (noAuthenticationRequired) {
1589 } else if (!callerIndex) {
1590 code = KANOENT;
1591 goto abort;
1592 } else {
1593 if ((code = karead(tt, callerIndex, (char *)&caller, sizeof(caller)))) {
1594 code = KAIO;
1595 goto abort;
1597 /* if the user is checking his own entry or ADMIN then go ahead. */
1598 callerIsAdmin = (ntohl(caller.flags) & KAFADMIN);
1600 if (strcmp(caller.userID.name, aname) != 0 && !callerIsAdmin) {
1601 code = KANOAUTH;
1602 goto abort;
1606 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1607 if (code)
1608 goto abort;
1609 if (to == 0) { /* entry not found */
1610 code = KANOENT;
1611 goto abort;
1614 get_time(0, 0, 0); /* generate random update */
1616 memset(aentry, 0, sizeof(*aentry));
1617 aentry->minor_version = KAMINORVERSION;
1618 aentry->flags = ntohl(tentry.flags);
1619 aentry->user_expiration = ntohl(tentry.user_expiration);
1620 aentry->modification_time = ntohl(tentry.modification_time);
1621 aentry->change_password_time = ntohl(tentry.change_password_time);
1622 aentry->max_ticket_lifetime = ntohl(tentry.max_ticket_lifetime);
1623 aentry->key_version = ntohl(tentry.key_version);
1625 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
1626 temp = temp << 9;
1627 if (kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp))
1628 tentry.misc_auth_bytes[REUSEFLAGS] |= KA_ISLOCKED; /* saves an RPC */
1630 temp = pack_long(tentry.misc_auth_bytes);
1631 aentry->misc_auth_bytes = temp;
1633 * only return user's key if security disabled or if admin and
1634 * we have an encrypted connection to the user
1636 rxkad_GetServerInfo(call->conn, &enc_level, 0, 0, 0, 0, 0);
1637 if ((noAuthenticationRequired)
1638 || (callerIsAdmin && enc_level == rxkad_crypt))
1639 memcpy(&aentry->key, &tentry.key, sizeof(struct ktc_encryptionKey));
1640 else
1641 memset(&aentry->key, 0, sizeof(aentry->key));
1642 code = ka_KeyCheckSum((char *)&tentry.key, &aentry->keyCheckSum);
1643 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
1644 aentry->reserved3 = 0x12340000;
1645 } else {
1646 aentry->reserved3 = 0x12340001;
1649 /* Now get entry of user who last modified this entry */
1650 if (ntohl(tentry.modification_id)) {
1651 temp = ntohl(tentry.modification_id);
1652 code = karead(tt, temp, (char *)&tentry, sizeof(tentry));
1653 if (code) {
1654 code = KAIO;
1655 goto abort;
1657 aentry->modification_user = tentry.userID;
1658 } else {
1659 strcpy(aentry->modification_user.name, "<none>");
1660 strcpy(aentry->modification_user.instance, "\0");
1662 code = ubik_EndTrans(tt);
1663 return code;
1665 abort:
1666 COUNT_ABO;
1667 ubik_AbortTrans(tt);
1668 return code;
1671 afs_int32
1672 SKAM_ListEntry(struct rx_call *call,
1673 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1674 afs_int32 *index, /* index of this entry */
1675 afs_int32 *count, /* total entries in database */
1676 kaident *name) /* name & instance of this entry */
1678 afs_int32 code;
1680 code = kamListEntry(call, previous_index, index, count, name);
1681 osi_auditU(call, AFS_KAM_LstEntEvent, code, AUD_LONG, *index, AUD_END);
1682 return code;
1686 afs_int32
1687 kamListEntry(struct rx_call *call,
1688 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1689 afs_int32 *index, /* index of this entry */
1690 afs_int32 *count, /* total entries in database */
1691 kaident *name) /* name & instance of this entry */
1693 int code;
1694 struct ubik_trans *tt;
1695 afs_int32 caller;
1696 struct kaentry tentry;
1698 COUNT_REQ(ListEntry);
1699 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1700 return code;
1701 code = check_auth(call, tt, 1, &caller);
1702 if (code) {
1703 goto abort;
1706 *index = NextBlock(tt, previous_index, &tentry, count);
1707 if (*count < 0) {
1708 code = KAIO;
1709 goto abort;
1712 if (*index) { /* return name & inst of this entry */
1713 strncpy(name->name, tentry.userID.name, sizeof(name->name));
1714 strncpy(name->instance, tentry.userID.instance,
1715 sizeof(name->instance));
1716 } else {
1717 strcpy(name->name, "\0");
1718 strcpy(name->instance, "\0");
1720 code = ubik_EndTrans(tt);
1721 return code;
1723 abort:
1724 COUNT_ABO;
1725 ubik_AbortTrans(tt);
1726 return code;
1729 static afs_int32
1730 GetTicket(int version,
1731 struct rx_call *call,
1732 afs_int32 kvno,
1733 char *authDomain,
1734 ka_CBS *aticket,
1735 char *sname,
1736 char *sinstance,
1737 ka_CBS *atimes, /* encrypted start & end time */
1738 ka_BBS *oanswer)
1740 afs_int32 code;
1741 int import, export;
1742 struct ubik_trans *tt;
1743 struct ktc_encryptionKey tgskey;
1744 des_key_schedule schedule;
1745 afs_int32 to;
1746 char name[MAXKTCNAMELEN];
1747 char instance[MAXKTCNAMELEN];
1748 char cell[MAXKTCNAMELEN];
1749 int celllen;
1750 struct kaentry caller;
1751 struct kaentry server;
1752 struct ktc_encryptionKey authSessionKey;
1753 struct ktc_encryptionKey sessionKey;
1754 int ticketLen;
1755 char ticket[MAXKTCTICKETLEN];
1756 afs_int32 host;
1757 Date start;
1758 Date expiration;
1759 Date now;
1760 Date end;
1761 struct ka_getTicketTimes times;
1762 struct ka_getTicketAnswer *answer;
1764 COUNT_REQ(GetTicket);
1765 if (!name_instance_legal(sname, sinstance))
1766 return KABADNAME;
1767 if (atimes->SeqLen != sizeof(times))
1768 return KABADARGUMENT;
1769 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1770 return code;
1772 export = import = 0;
1773 if ((strcmp(sname, KA_TGS_NAME) == 0) && (strcmp(sinstance, lrealm) != 0))
1774 export = 1;
1775 if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0))
1776 import = 1;
1778 if (strlen(authDomain) == 0)
1779 authDomain = lrealm;
1780 code = ka_LookupKvno(tt, KA_TGS_NAME, authDomain, kvno, &tgskey);
1781 if (code) {
1782 goto abort;
1784 code =
1785 tkt_DecodeTicket(aticket->SeqBody, aticket->SeqLen, &tgskey, name,
1786 instance, cell, &authSessionKey, &host, &start,
1787 &expiration);
1788 if (code) {
1789 code = KANOAUTH;
1790 goto abort;
1792 save_principal(tgsPrincipal, name, instance, cell);
1794 if ((code = get_time(&now, 0, 0)))
1795 goto abort;
1797 code = tkt_CheckTimes(start, expiration, now);
1798 if (code <= 0) {
1799 if (code == -1)
1800 code = RXKADEXPIRED;
1801 else
1802 code = KANOAUTH;
1803 goto abort;
1805 code = des_key_sched(ktc_to_cblock(&authSessionKey), schedule);
1806 if (code) {
1807 code = KANOAUTH;
1808 goto abort;
1810 celllen = strlen(cell);
1811 if (import && (celllen == 0)) {
1812 code = KABADTICKET;
1813 goto abort;
1815 if (export && (celllen == 0))
1816 strcpy(cell, lrealm);
1818 if (!krb4_cross && celllen && strcmp(lrealm, cell) != 0) {
1819 code = KABADUSER;
1820 goto abort;
1823 des_ecb_encrypt(atimes->SeqBody, &times, schedule, DECRYPT);
1824 times.start = ntohl(times.start);
1825 times.end = ntohl(times.end);
1826 code = tkt_CheckTimes(times.start, times.end, now);
1827 if (code < 0) {
1828 code = KABADREQUEST;
1829 goto abort;
1832 if (import) {
1833 strcpy(caller.userID.name, name);
1834 strcpy(caller.userID.instance, instance);
1835 caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
1836 caller.flags = htonl(KAFNORMAL);
1837 caller.user_expiration = htonl(NEVERDATE);
1838 } else {
1839 code = FindBlock(tt, name, instance, &to, &caller);
1840 if (code)
1841 goto abort;
1842 if (to == 0) {
1843 ka_PrintUserID("GetTicket: User ", name, instance, " unknown.\n");
1844 code = KANOENT;
1845 goto abort;
1849 /* get server's entry */
1850 code = FindBlock(tt, sname, sinstance, &to, &server);
1851 if (code)
1852 goto abort;
1853 if (to == 0) { /* entry not found */
1854 ka_PrintUserID("GetTicket: Server ", sname, sinstance, " unknown.\n");
1855 code = KANOENT;
1856 goto abort;
1858 save_principal(tgsServerPrincipal, sname, sinstance, 0);
1860 code = des_random_key(ktc_to_cblock(&sessionKey));
1861 if (code) {
1862 code = KANOKEYS;
1863 goto abort;
1866 code =
1867 GetEndTime(times.start, times.end, expiration, &caller, &server,
1868 &end);
1869 if (code)
1870 goto abort;
1872 code =
1873 tkt_MakeTicket(ticket, &ticketLen, &server.key, caller.userID.name,
1874 caller.userID.instance, cell, times.start, end,
1875 &sessionKey,
1876 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
1877 server.userID.name, server.userID.instance);
1878 if (code)
1879 goto abort;
1881 switch (version) {
1882 case 0:
1883 code = KAANSWERTOOLONG;
1884 if (oanswer->MaxSeqLen <
1885 sizeof(struct ka_getTicketAnswer) - 5 * MAXKTCNAMELEN -
1886 MAXKTCTICKETLEN + ticketLen)
1887 goto abort;
1889 answer = (struct ka_getTicketAnswer *)oanswer->SeqBody;
1890 memcpy(&answer->sessionKey, &sessionKey,
1891 sizeof(struct ktc_encryptionKey));
1892 answer->startTime = htonl(times.start);
1893 answer->endTime = htonl(end);
1894 answer->kvno = server.key_version;
1895 answer->ticketLen = htonl(ticketLen);
1898 char *ans = answer->name; /* ptr to variable part of answer */
1899 int rem, len;
1901 /* space remaining */
1902 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1903 #undef putstr
1904 #define putstr(str) len = strlen (str)+1;\
1905 if (rem < len) goto abort;\
1906 strcpy (ans, str);\
1907 ans += len; rem -= len
1909 putstr(name);
1910 putstr(instance);
1911 putstr(cell);
1912 putstr(sname);
1913 putstr(sinstance);
1914 if (rem < ticketLen)
1915 goto abort;
1916 memcpy(ans, ticket, ticketLen);
1917 oanswer->SeqLen = (ans - oanswer->SeqBody) + ticketLen;
1919 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1920 break;
1921 case 1:
1922 code =
1923 PrepareTicketAnswer(oanswer, /*challenge */ 0, ticket, ticketLen,
1924 &sessionKey, times.start, end, &caller,
1925 &server, cell, KA_GETTICKET_ANS_LABEL);
1926 if (code)
1927 goto abort;
1928 break;
1929 default:
1930 code = KAINTERNALERROR;
1931 goto abort;
1933 des_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1934 schedule, ktc_to_cblockptr(&authSessionKey), ENCRYPT);
1935 code = ubik_EndTrans(tt);
1936 KALOG(name, instance, sname, sinstance, (import ? authDomain : NULL),
1937 call->conn->peer->host, LOG_GETTICKET);
1938 return code;
1940 abort:
1941 COUNT_ABO;
1942 ubik_AbortTrans(tt);
1943 return code;
1946 afs_int32
1947 SKAT_GetTicket_old(struct rx_call *call,
1948 afs_int32 kvno,
1949 char *authDomain,
1950 ka_CBS *aticket,
1951 char *sname,
1952 char *sinstance,
1953 ka_CBS *atimes, /* encrypted start & end time */
1954 ka_BBS *oanswer)
1956 int code;
1958 sleep(1); /* strongly discourage this */
1959 code =
1960 GetTicket(0, call, kvno, authDomain, aticket, sname, sinstance,
1961 atimes, oanswer);
1963 osi_auditU(call, AFS_KAT_GetTicketOEvent, code, AUD_STR, sname, AUD_STR,
1964 sinstance, AUD_END);
1965 return code;
1968 afs_int32
1969 SKAT_GetTicket(struct rx_call *call,
1970 afs_int32 kvno,
1971 char *authDomain,
1972 ka_CBS *aticket,
1973 char *sname,
1974 char *sinstance,
1975 ka_CBS *atimes, /* encrypted start & end time */
1976 ka_BBS *oanswer)
1978 int code;
1980 code =
1981 GetTicket(1, call, kvno, authDomain, aticket, sname, sinstance,
1982 atimes, oanswer);
1983 osi_auditU(call, AFS_KAT_GetTicketEvent, code, AUD_STR, sname, AUD_STR,
1984 sinstance, AUD_END);
1985 return code;
1988 afs_int32
1989 SKAM_GetStats(struct rx_call *call, afs_int32 version,
1990 afs_int32 *admin_accounts, kasstats *statics,
1991 kadstats *dynamics)
1993 afs_int32 code;
1995 code = kamGetStats(call, version, admin_accounts, statics, dynamics);
1996 osi_auditU(call, AFS_KAM_GetStatEvent, code, AUD_END);
1997 return code;
2000 afs_int32
2001 kamGetStats(struct rx_call *call, afs_int32 version,
2002 afs_int32 *admin_accounts, kasstats *statics,
2003 kadstats *dynamics)
2005 afs_int32 code;
2006 struct ubik_trans *tt;
2007 afs_int32 caller;
2009 COUNT_REQ(GetStats);
2010 if (version != KAMAJORVERSION)
2011 return KAOLDINTERFACE;
2012 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2013 return code;
2014 code = check_auth(call, tt, 1, &caller);
2015 if (code) {
2016 COUNT_ABO;
2017 ubik_AbortTrans(tt);
2018 return code;
2021 *admin_accounts = ntohl(cheader.admin_accounts);
2022 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
2023 /* these are stored in network byte order and must be copied */
2024 statics->allocs = ntohl(cheader.stats.allocs);
2025 statics->frees = ntohl(cheader.stats.frees);
2026 statics->cpws = ntohl(cheader.stats.cpws);
2027 #if KADBVERSION != 5
2028 check that the statistics command copies all the fields
2029 #endif
2030 memcpy((char *)dynamics, (char *)&dynamic_statistics, sizeof(kadstats));
2031 statics->minor_version = KAMINORVERSION;
2032 dynamics->minor_version = KAMINORVERSION;
2035 int used = 0;
2036 int i;
2038 for (i = 0; i < HASHSIZE; i++)
2039 if (cheader.nameHash[i])
2040 used++;
2041 dynamics->hashTableUtilization =
2042 (used * 10000 + HASHSIZE / 2) / HASHSIZE;
2045 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
2046 struct rusage ru;
2047 /* Unfortunately, although aix_22 has a minimal compatibility
2048 * method of getting to some rusage fields (i.e. stime &
2049 * utime), the version that we have doesn't even have the
2050 * related include files needed for the aix vtimes() call; so
2051 * ignore this for aix till v3.1... */
2052 getrusage(RUSAGE_SELF, &ru);
2053 #if (KAMAJORVERSION>5)
2054 memcpy(&dynamics->utime, &ru.ru_utime, sizeof(struct katimeval));
2055 memcpy(&dynamics->stime, &ru.ru_stime, sizeof(struct katimeval));
2056 dynamics->dataSize = ru.ru_idrss;
2057 dynamics->stackSize = ru.ru_isrss;
2058 dynamics->pageFailts = ru.ru_majflt;
2059 #else
2060 dynamics->string_checks =
2061 (afs_int32) (1000.0 *
2062 ((ru.ru_utime.tv_sec +
2063 ru.ru_utime.tv_usec / 1000000.0) +
2064 (ru.ru_stime.tv_sec +
2065 ru.ru_stime.tv_usec / 1000000.0)));
2066 #endif
2067 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
2070 code = ubik_EndTrans(tt);
2071 return code;
2074 afs_int32
2075 SKAM_GetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2077 afs_int32 code;
2079 code = kamGetPassword(call, name, password);
2080 osi_auditU(call, AFS_KAM_GetPswdEvent, code, AUD_STR, name, AUD_END);
2081 return code;
2084 afs_int32
2085 kamGetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2087 int code = KANOAUTH;
2088 AFS_UNUSED COUNT_REQ(GetPassword);
2089 #ifdef GETPASSWORD
2091 afs_int32 to;
2092 struct ubik_trans *tt;
2093 struct kaentry tentry;
2095 if (!name_instance_legal(name, ""))
2096 return KABADNAME;
2097 /* only requests from this host work */
2098 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))) !=
2099 htonl(INADDR_LOOPBACK))
2100 return KANOAUTH;
2101 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2102 return code;
2104 /* this isn't likely to be used because of string to key problems, so since
2105 * this is a temporary thing anyway, we'll use it here. */
2107 extern char udpAuthPrincipal[256];
2109 save_principal(udpAuthPrincipal, name, 0, 0);
2112 get_time(0, 0, 0); /* update random value */
2113 code = FindBlock(tt, name, "", &to, &tentry);
2114 if (code)
2115 goto abort;
2116 if (to == 0) {
2117 code = KANOENT;
2118 abort:
2119 COUNT_ABO;
2120 ubik_AbortTrans(tt);
2121 return code;
2124 memcpy(password, &tentry.key, sizeof(*password));
2125 code = ubik_EndTrans(tt);
2127 #endif
2128 return code;
2131 afs_int32
2132 SKAM_GetRandomKey(struct rx_call *call, EncryptionKey *key)
2134 afs_int32 code;
2136 code = kamGetRandomKey(call, key);
2137 osi_auditU(call, AFS_KAM_GetRndKeyEvent, code, AUD_END);
2138 return code;
2141 afs_int32
2142 kamGetRandomKey(struct rx_call *call, EncryptionKey *key)
2144 int code;
2146 AFS_UNUSED COUNT_REQ(GetRandomKey);
2147 if ((code = AwaitInitialization()))
2148 return code;
2149 code = des_random_key(EncryptionKey_to_cblock(key));
2150 if (code)
2151 return KANOKEYS;
2152 return 0;
2155 afs_int32
2156 SKAM_Debug(struct rx_call *call,
2157 afs_int32 version,
2158 int checkDB, /* start a transaction to examine DB */
2159 struct ka_debugInfo *info)
2161 afs_int32 code;
2163 code = kamDebug(call, version, checkDB, info);
2164 osi_auditU(call, AFS_KAM_DbgEvent, code, AUD_END);
2165 return code;
2168 afs_int32
2169 kamDebug(struct rx_call *call,
2170 afs_int32 version,
2171 int checkDB, /* start a transaction to examine DB */
2172 struct ka_debugInfo *info)
2174 /* COUNT_REQ (Debug); */
2175 if (sizeof(struct kaentry) != sizeof(struct kaOldKeys))
2176 return KAINTERNALERROR;
2177 if (sizeof(struct ka_cpwRequest) % 8)
2178 return KAINTERNALERROR;
2179 if (version != KAMAJORVERSION)
2180 return KAOLDINTERFACE;
2182 memset(info, 0, sizeof(*info));
2184 info->minorVersion = KAMINORVERSION;
2185 info->host = dynamic_statistics.host;
2186 info->startTime = dynamic_statistics.start_time;
2187 info->
2188 #if (KAMAJORVERSION>5)
2190 #else
2191 reserved1
2192 #endif
2193 = time(0);
2194 info->noAuth = noAuthenticationRequired;
2196 info->dbVersion = ntohl(cheader.version);
2197 info->dbFreePtr = ntohl(cheader.freePtr);
2198 info->dbEofPtr = ntohl(cheader.eofPtr);
2199 info->dbKvnoPtr = ntohl(cheader.kvnoPtr);
2200 info->dbSpecialKeysVersion = ntohl(cheader.specialKeysVersion);
2202 info->dbHeaderRead = cheaderReadTime;
2203 info->lastTrans = lastTrans;
2204 if (!lastOperation)
2205 lastOperation = "(Not Available)";
2206 strncpy(info->lastOperation, lastOperation, sizeof(info->lastOperation));
2207 strncpy(info->lastAuth, authPrincipal, sizeof(info->lastAuth));
2208 strncpy(info->lastTGS, tgsPrincipal, sizeof(info->lastTGS));
2209 strncpy(info->lastAdmin, adminPrincipal, sizeof(info->lastAdmin));
2210 strncpy(info->lastTGSServer, tgsServerPrincipal,
2211 sizeof(info->lastTGSServer));
2213 extern char udpAuthPrincipal[256];
2214 extern char udptgsPrincipal[256];
2215 extern char udptgsServerPrincipal[256];
2217 strncpy(info->lastUAuth, udpAuthPrincipal, sizeof(info->lastUAuth));
2218 strncpy(info->lastUTGS, udptgsPrincipal, sizeof(info->lastUTGS));
2219 strncpy(info->lastUTGSServer, udptgsServerPrincipal,
2220 sizeof(info->lastUTGSServer));
2222 info->nextAutoCPW = nextAutoCPWTime;
2223 info->updatesRemaining = autoCPWUpdates - totalUpdates;
2224 ka_debugKeyCache(info);
2225 return 0;
2228 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2229 * a tacked-on-the-side data file.
2230 * prob'ly ought to check the noauth flag.
2232 #define ABORTIF(A) {if((code = A)){goto abort;}}
2233 afs_int32
2234 SKAM_Unlock(struct rx_call *call,
2235 char *aname,
2236 char *ainstance,
2237 afs_int32 spare1,
2238 afs_int32 spare2,
2239 afs_int32 spare3,
2240 afs_int32 spare4)
2242 int code;
2243 struct ubik_trans *tt;
2244 afs_int32 caller;
2245 afs_int32 to;
2246 struct kaentry tentry;
2248 COUNT_REQ(Unlock);
2249 if (!name_instance_legal(aname, ainstance)) {
2250 code = KABADNAME;
2251 goto exit;
2253 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2254 goto exit;
2256 ABORTIF(check_auth(call, tt, 1, &caller));
2257 ABORTIF(FindBlock(tt, aname, ainstance, &to, &tentry));
2258 ABORTIF((to == 0 ? KANOENT : 0));
2260 kaux_write(to, 0, 0); /* zero failure counters at this offset */
2262 code = ubik_EndTrans(tt);
2263 KALOG(aname, ainstance, NULL, NULL, NULL, call->conn->peer->host,
2264 LOG_UNLOCK);
2265 goto exit;
2267 abort:
2268 COUNT_ABO;
2269 ubik_AbortTrans(tt);
2271 exit:
2272 osi_auditU(call, UnlockEvent, code, AUD_STR, aname, AUD_STR, ainstance,
2273 AUD_END);
2274 return code;
2277 afs_int32
2278 SKAM_LockStatus(struct rx_call *call,
2279 char *aname,
2280 char *ainstance,
2281 afs_int32 *lockeduntil,
2282 afs_int32 spare1,
2283 afs_int32 spare2,
2284 afs_int32 spare3,
2285 afs_int32 spare4)
2287 int code;
2288 struct ubik_trans *tt;
2289 afs_int32 callerIndex;
2290 afs_int32 to;
2291 struct kaentry caller;
2292 struct kaentry tentry;
2293 afs_uint32 temp;
2295 COUNT_REQ(LockStatus);
2297 if (!name_instance_legal(aname, ainstance)) {
2298 code = KABADNAME;
2299 goto exit;
2301 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2302 goto exit;
2304 if ((code = check_auth(call, tt, 0, &callerIndex)))
2305 goto abort;
2307 if (!noAuthenticationRequired && callerIndex) {
2308 if (karead(tt, callerIndex, (char *)&caller, sizeof(caller))) {
2309 code = KAIO;
2310 goto abort;
2312 /* if the user is checking his own entry or ADMIN then go ahead. */
2313 if ((strcmp(caller.userID.name, aname) != 0)
2314 && !(ntohl(caller.flags) & KAFADMIN)) {
2315 code = KANOAUTH;
2316 goto abort;
2320 if ((code = FindBlock(tt, aname, ainstance, &to, &tentry)))
2321 goto abort;
2323 if (to == 0) {
2324 code = KANOENT;
2325 goto abort;
2328 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
2329 temp = temp << 9;
2330 *lockeduntil =
2331 kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp);
2333 code = ubik_EndTrans(tt);
2334 goto exit;
2336 abort:
2337 COUNT_ABO;
2338 ubik_AbortTrans(tt);
2339 osi_auditU(call, LockStatusEvent, code, AUD_STR, aname, AUD_STR,
2340 ainstance, AUD_END);
2342 exit:
2343 return code;