Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / kauth / kaprocs.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #ifdef HAVE_SYS_RESOURCE_H
18 # include <sys/resource.h>
19 #endif
20
21 #ifdef IGNORE_SOME_GCC_WARNINGS
22 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
23 #endif
24
25 #include "kauth.h"
26
27 #define HC_DEPRECATED
28 #include <hcrypto/des.h>
29
30 #include <lock.h>
31 #include <ubik.h>
32 #include <lwp.h>
33 #include <rx/xdr.h>
34 #include <rx/rx.h>
35 #include <rx/rxkad.h>
36 #include <rx/rxkad_convert.h>
37 #include <afs/cellconfig.h>
38 #include <afs/auth.h>
39 #include <afs/com_err.h>
40 #include <afs/afsutil.h>
41 #include <afs/audit.h>
42
43 #include "kautils.h"
44 #include "kaserver.h"
45 #include "kalog.h"
46 #include "kaport.h"
47 #include "kauth_internal.h"
48
49 #include "kadatabase.h"
50 #include "kaprocs.h"
51
52 extern struct ubik_dbase *KA_dbase;
53 struct kaheader cheader;
54 Date cheaderReadTime; /* time cheader last read in */
55 extern struct afsconf_dir *KA_conf; /* for getting cell info */
56
57
58
59 char lrealm[MAXKTCREALMLEN];
60
61 #ifndef EXPIREPW /* password expiration default yes */
62 #define EXPIREPW
63 #endif
64
65 #ifndef AUTOCPWINTERVAL
66 #define AUTOCPWINTERVAL (24*3600)
67 #endif
68 #ifndef AUTOCPWUPDATES
69 #define AUTOCPWUPDATES 128
70 #endif
71
72 extern int npwSums;
73
74 static afs_int32 autoCPWInterval;
75 static afs_int32 autoCPWUpdates;
76
77 static afs_int32 set_password(struct ubik_trans *tt, char *name,
78 char *instance,
79 struct ktc_encryptionKey *password,
80 afs_int32 kvno, afs_int32 caller);
81 static afs_int32 impose_reuse_limits(EncryptionKey *password,
82 struct kaentry *tentry);
83 static int create_user(struct ubik_trans *tt, char *name, char *instance,
84 struct ktc_encryptionKey *key, afs_int32 caller,
85 afs_int32 flags);
86
87 /* This routine is called whenever an RPC interface needs the time. It uses
88 the current time to randomize a 128 bit value that is used to change the
89 AuthServer Admin and TGS keys automatically. */
90
91 static Date nextAutoCPWTime = 0;
92 static afs_int32 totalUpdates = 0;
93
94 /* This routine is ostensibly to get the current time, but basically its job is
95 to periodically update a random number. It also periodically updates the
96 keys for the builtin servers. This is why it needs a transaction pointer
97 and returns an error code. If the caller is in a read transaction, the tt
98 ptr should be zero and the return code need not be checked. */
99
100 static afs_int32
101 get_time(Date *timeP,
102 struct ubik_trans *tt, /* tt != 0: a write transaction */
103 int admin) /* the caller is an admin user */
104 {
105 /* random value used to change Admin & TGS keys, this is at risk during
106 * multi-threaded operation, but I think the consequences are fairly
107 * harmless. */
108 static afs_uint32 random_value[4];
109
110 struct timeval time;
111 unsigned int bit, nbit;
112 int i;
113 afs_int32 to;
114
115 gettimeofday(&time, NULL);
116 bit = (random_value[3] >> 31) & 1; /* get high bit of high word */
117 for (i = 0; i < 4; i++) {
118 nbit = random_value[i] >> 31;
119 random_value[i] = (random_value[i] << 1) + bit;
120 bit = nbit & 1;
121 }
122 /* get 60ths from usec. This is all the real randomness there is. */
123 random_value[0] += time.tv_usec / 16667;
124
125 if (nextAutoCPWTime == 0) { /* initialize things */
126 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
127 memcpy(&random_value[0], &time, 8);
128 memcpy(&random_value[2], &time, 8);
129 }
130
131 if ((++totalUpdates >= autoCPWUpdates) && tt && /* a write transaction */
132 ((admin && (time.tv_sec >= nextAutoCPWTime))
133 || (time.tv_sec >= nextAutoCPWTime + autoCPWInterval))) {
134 struct ktc_encryptionKey key;
135 char buf[4 * sizeof(key) + 1];
136 struct kaentry tentry;
137 afs_int32 code;
138 char bob[KA_TIMESTR_LEN];
139
140 ka_timestr(time.tv_sec, bob, KA_TIMESTR_LEN);
141 es_Report("Auto CPW at %s\n", bob);
142 if (!admin)
143 es_Report(" ... even though no ADMIN user\n");
144
145 code = FindBlock(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &to, &tentry);
146 if (code)
147 return code;
148 if (to) { /* check if auto cpw is disabled */
149 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
150 memcpy(&key, &random_value[0], sizeof(key));
151 DES_set_odd_parity(ktc_to_cblock(&key));
152 code =
153 set_password(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
154 0);
155 if (code == 0) {
156 DES_init_random_number_generator(ktc_to_cblock(&key));
157 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
158 sizeof(key));
159 es_Report("New Admin key is %s\n", buf);
160 } else {
161 es_Report
162 ("in get_time: set_password failed because: %d\n",
163 code);
164 return code;
165 }
166 }
167 }
168
169 code = FindBlock(tt, KA_TGS_NAME, lrealm, &to, &tentry);
170 if (code)
171 return code;
172 if (to) { /* check if auto cpw is disabled */
173 if (!(ntohl(tentry.flags) & KAFNOCPW)) {
174 memcpy(&key, &random_value[2], sizeof(key));
175 DES_set_odd_parity(ktc_to_cblock(&key));
176 code = set_password(tt, KA_TGS_NAME, lrealm, &key, 0, 0);
177 if (code == 0) {
178 ka_ConvertBytes(buf, sizeof(buf), (char *)&key,
179 sizeof(key));
180 es_Report("New TGS key is %s\n", buf);
181 } else {
182 es_Report
183 ("in get_time: set_password failed because: %s\n",
184 afs_error_message(code));
185 return code;
186 }
187 }
188 }
189 code = ka_FillKeyCache(tt); /* ensure in-core copy is uptodate */
190 if (code)
191 return code;
192
193 nextAutoCPWTime = time.tv_sec + autoCPWInterval;
194 totalUpdates = 0;
195 }
196 if (timeP)
197 *timeP = time.tv_sec;
198 return 0;
199 }
200
201 static int noAuthenticationRequired; /* global state */
202 static int recheckNoAuth; /* global state */
203
204 /* kaprocsInited is sort of a lock: during a transaction only one process runs
205 while kaprocsInited is false. */
206
207 static int kaprocsInited = 0;
208
209 /* This variable is protected by the kaprocsInited flag. */
210
211 static int (*rebuildDatabase) (struct ubik_trans *);
212
213 /* This is called to initialize the database */
214
215 static int
216 initialize_database(struct ubik_trans *tt)
217 {
218 struct ktc_encryptionKey key;
219 int code;
220
221 gettimeofday((struct timeval *)&key, NULL); /* this is just a cheap seed key */
222 DES_set_odd_parity(ktc_to_cblock(&key));
223 DES_init_random_number_generator(ktc_to_cblock(&key));
224 if ((code = DES_new_random_key(ktc_to_cblock(&key)))
225 || (code =
226 create_user(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &key, 0,
227 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
228 return code;
229 if ((code = DES_new_random_key(ktc_to_cblock(&key)))
230 || (code =
231 create_user(tt, KA_TGS_NAME, lrealm, &key, 0,
232 KAFNORMAL | KAFNOSEAL | KAFNOTGS)))
233 return code;
234 return 0;
235 }
236
237 /* This routine handles initialization required by this module. The initFlags
238 parameter passes some information about the command line arguments. */
239
240 afs_int32
241 init_kaprocs(const char *lclpath, int initFlags)
242 {
243 int code;
244 struct ubik_trans *tt;
245 struct ktc_encryptionKey key;
246 afs_int32 kvno;
247
248 kaprocsInited = 0;
249 if (myHost == 0)
250 return KAINTERNALERROR;
251 if (KA_conf == 0)
252 return KAINTERNALERROR;
253 code = afsconf_GetLocalCell(KA_conf, lrealm, sizeof(lrealm));
254 if (code) {
255 printf("** Can't determine local cell name!\n");
256 return KANOCELLS;
257 }
258 ucstring(lrealm, lrealm, sizeof(lrealm));
259
260 recheckNoAuth = 1;
261 if (initFlags & 1)
262 noAuthenticationRequired = 1;
263 if (initFlags & 2)
264 recheckNoAuth = 0;
265 if (recheckNoAuth)
266 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
267 if (noAuthenticationRequired)
268 printf("Running server with security disabled\n");
269
270 if (initFlags & 4) {
271 autoCPWInterval = 10;
272 autoCPWUpdates = 10;
273 } else {
274 autoCPWInterval = AUTOCPWINTERVAL;
275 autoCPWUpdates = AUTOCPWUPDATES;
276 }
277
278 init_kadatabase(initFlags);
279 rebuildDatabase = initialize_database;
280
281 if ((code = InitAuthServ(&tt, LOCKREAD, 0))) {
282 printf("init_kaprocs: InitAuthServ failed: code = %d\n", code);
283 return code;
284 }
285 code = ka_LookupKey(tt, KA_ADMIN_NAME, KA_ADMIN_INST, &kvno, &key);
286 if (code) {
287 ubik_AbortTrans(tt);
288 printf
289 ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n",
290 code);
291 return code;
292 }
293 DES_init_random_number_generator(ktc_to_cblock(&key));
294
295 code = ubik_EndTrans(tt);
296 if (code) {
297 printf("init_kaprocs: ubik_EndTrans failed: code = %d\n", code);
298 return code;
299 }
300
301 kaux_opendb((char *)lclpath);/* aux database stores failure counters */
302 rebuildDatabase = 0; /* only do this during init */
303 kaprocsInited = 1;
304 return 0;
305 }
306
307 /* These variable are for returning debugging info about the state of the
308 server. If they get trashed during multi-threaded operation it doesn't
309 matter. */
310
311 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
312 char *lastOperation = 0; /* name of last operation */
313 static Date lastTrans; /* time of last transaction */
314
315 static char adminPrincipal[256];
316 static char authPrincipal[256];
317 static char tgsPrincipal[256];
318 static char tgsServerPrincipal[256];
319
320 void
321 save_principal(char *p, char *n, char *i, char *c)
322 {
323 int s = 255;
324 int l;
325
326 l = strlen(n);
327 if (l > s)
328 return;
329 strcpy(p, n);
330 s -= l;
331 if (i && strlen(i)) {
332 if (s-- <= 0)
333 return;
334 strcat(p, ".");
335 l = strlen(i);
336 if (l > s)
337 return;
338 strcat(p, i);
339 s -= l;
340 }
341 if (c && strlen(c)) {
342 if (s-- <= 0)
343 return;
344 strcat(p, "@");
345 l = strlen(c);
346 if (l > s)
347 return;
348 strcat(p, c);
349 }
350 }
351
352 static afs_int32
353 check_auth(struct rx_call *call,
354 struct ubik_trans *at,
355 int admin, /* require caller to be ADMIN */
356 afs_int32 *acaller_id)
357 {
358 rxkad_level level;
359 char name[MAXKTCNAMELEN];
360 char instance[MAXKTCNAMELEN];
361 char cell[MAXKTCREALMLEN];
362 afs_int32 kvno;
363 Date expiration; /* checked by Security Module */
364 struct kaentry tentry;
365 int code;
366 int si;
367
368 *acaller_id = 0;
369
370 if (recheckNoAuth)
371 noAuthenticationRequired = afsconf_GetNoAuthFlag(KA_conf);
372
373 si = rx_SecurityClassOf(rx_ConnectionOf(call));
374 if (si == RX_SECIDX_VAB) {
375 printf("No support for VAB security module yet.\n");
376 return -1;
377 } else if (si == RX_SECIDX_NULL) {
378 code = KANOAUTH;
379 goto no_auth;
380 } else if (si != RX_SECIDX_KAD) {
381 es_Report("Unknown security index %d\n", si);
382 return -1;
383 }
384
385 code =
386 rxkad_GetServerInfo(rx_ConnectionOf(call), &level, &expiration, name,
387 instance, cell, &kvno);
388 if (code) {
389 goto no_auth;
390 }
391 if (level != rxkad_crypt) {
392 es_Report("Incorrect security level = %d\n", level);
393 code = KANOAUTH;
394 goto no_auth;
395 }
396
397 if (!name_instance_legal(name, instance))
398 return KABADNAME;
399 if (strlen(cell)) {
400 ka_PrintUserID
401 ("Authorization rejected because we don't understand intercell stuff yet: ",
402 name, instance, "");
403 printf("@%s\n", cell);
404 return KANOAUTH;
405 }
406
407 code = FindBlock(at, name, instance, acaller_id, &tentry);
408 if (code)
409 return code;
410 if (*acaller_id == 0) {
411 ka_PrintUserID("User ", name, instance, " unknown.\n");
412 return KANOENT;
413 }
414 save_principal(adminPrincipal, name, instance, 0);
415
416 if (admin) {
417 if (!(ntohl(tentry.flags) & KAFADMIN)) {
418 if (noAuthenticationRequired) {
419 ka_PrintUserID("Authorization approved for ", name, instance,
420 " because there is no authentication required\n");
421 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR,
422 instance, AUD_STR, cell, AUD_END);
423 return 0;
424 }
425 ka_PrintUserID("User ", name, instance, " is not ADMIN.\n");
426 return KANOAUTH;
427 }
428 osi_auditU(call, UseOfPrivilegeEvent, code, AUD_STR, name, AUD_STR,
429 instance, AUD_STR, cell, AUD_END);
430 }
431 return 0;
432
433 no_auth:
434 if (noAuthenticationRequired) {
435 es_Report
436 ("Caller w/o authorization approved no authentication required\n");
437 osi_auditU(call, UnAuthEvent, code, AUD_STR, name, AUD_STR, instance,
438 AUD_STR, cell, AUD_END);
439 return 0;
440 }
441 return code; /* no auth info */
442 }
443
444 afs_int32
445 AwaitInitialization(void)
446 {
447 afs_int32 start = 0;
448 while (!kaprocsInited) {
449 if (!start)
450 start = time(0);
451 else if (time(0) - start > 5)
452 return UNOQUORUM;
453 IOMGR_Sleep(1);
454 }
455 return 0;
456 }
457
458 /* This is called by every RPC interface to create a Ubik transaction and read
459 the database header into core */
460
461 afs_int32
462 InitAuthServ(struct ubik_trans **tt,
463 int lock, /* indicate read/write transaction */
464 int *this_op) /* opcode of RPC proc, for COUNT_ABO */
465 {
466 int code;
467 afs_int32 start = 0; /* time started waiting for quorum */
468 float wait = 0.91; /* start waiting for 1 second */
469
470 /* Wait for server initialization to finish if not during init_kaprocs */
471 if (this_op)
472 if ((code = AwaitInitialization()))
473 return code;
474
475 for (code = UNOQUORUM; code == UNOQUORUM;) {
476 if (lock == LOCKREAD)
477 code = ubik_BeginTransReadAny(KA_dbase, UBIK_READTRANS, tt);
478 else
479 code = ubik_BeginTrans(KA_dbase, UBIK_WRITETRANS, tt);
480 if (code == UNOQUORUM) { /* no quorum elected */
481 if (!start)
482 start = time(0);
483 else {
484 int delay = time(0) - start;
485 if (this_op) { /* punt quickly, if RPC call */
486 if (delay > 5)
487 return code;
488 } else { /* more patient during init. */
489 if (delay > 500)
490 return code;
491 }
492 }
493 printf("Waiting for quorum election.\n");
494 if (wait < 15.0)
495 wait *= 1.1;
496 IOMGR_Sleep((int)wait);
497 }
498 }
499 if (code)
500 return code;
501 if ((code = ubik_SetLock(*tt, 1, 1, lock))) {
502 if (this_op)
503 COUNT_ABO;
504 ubik_AbortTrans(*tt);
505 return code;
506 }
507 /* check that dbase is initialized and setup cheader */
508 if (lock == LOCKREAD) {
509 /* init but don't fix because this is read only */
510 code = CheckInit(*tt, 0);
511 if (code) {
512 ubik_AbortTrans(*tt); /* abort, since probably I/O error */
513 /* we did the check under a ReadAny transaction, but now, after
514 * getting a write transaction (and thus some real guarantees
515 * about what databases are really out there), we will check again
516 * in CheckInit before nuking the database. Since this may now get
517 * a UNOQUORUM we'll just do this from the top.
518 */
519 if ((code = InitAuthServ(tt, LOCKWRITE, this_op)))
520 return code;
521 if ((code = ubik_EndTrans(*tt)))
522 return code;
523
524 /* now open the read transaction that was originally requested. */
525 return InitAuthServ(tt, lock, this_op);
526 }
527 } else {
528 if ((code = CheckInit(*tt, rebuildDatabase))) {
529 if (this_op)
530 COUNT_ABO;
531 ubik_AbortTrans(*tt);
532 return code;
533 }
534 }
535 lastTrans = time(0);
536 ka_FillKeyCache(*tt); /* ensure in-core copy is uptodate */
537 return 0;
538 }
539
540 /* returns true if name is specially known by AuthServer */
541
542 static int
543 special_name(char *name, char *instance)
544
545 {
546 return ((!strcmp(name, KA_TGS_NAME) && !strcmp(instance, lrealm))
547 || (strcmp(name, KA_ADMIN_NAME) == 0));
548 }
549
550 static int
551 create_user(struct ubik_trans *tt, char *name, char *instance,
552 struct ktc_encryptionKey *key, afs_int32 caller,
553 afs_int32 flags)
554 {
555 int code;
556 afs_int32 to;
557 struct kaentry tentry;
558 afs_int32 maxLifetime;
559
560 code = FindBlock(tt, name, instance, &to, &tentry);
561 if (code)
562 return code;
563 if (to)
564 return KAEXIST; /* name already exists, we fail */
565
566 to = AllocBlock(tt, &tentry);
567 if (to == 0)
568 return KACREATEFAIL;
569
570 /* otherwise we have a block */
571 strncpy(tentry.userID.name, name, sizeof(tentry.userID.name));
572 strncpy(tentry.userID.instance, instance, sizeof(tentry.userID.instance));
573 tentry.flags = htonl(flags);
574 if (special_name(name, instance)) { /* this overrides key & version */
575 tentry.flags = htonl(ntohl(tentry.flags) | KAFSPECIAL);
576 tentry.key_version = htonl(-1); /* don't save this key */
577 if ((code = ka_NewKey(tt, to, &tentry, key)))
578 return code;
579 } else {
580 memcpy(&tentry.key, key, sizeof(tentry.key));
581 tentry.key_version = htonl(0);
582 }
583 tentry.user_expiration = htonl(NEVERDATE);
584 code = get_time(&tentry.modification_time, tt, 1);
585 if (code)
586 return code;
587
588 /* time and addr of entry for guy changing this entry */
589 tentry.modification_time = htonl(tentry.modification_time);
590 tentry.modification_id = htonl(caller);
591 tentry.change_password_time = tentry.modification_time;
592
593 if (strcmp(name, KA_TGS_NAME) == 0)
594 maxLifetime = MAXKTCTICKETLIFETIME;
595 else if (strcmp(name, KA_ADMIN_NAME) == 0)
596 maxLifetime = 10 * 3600;
597 else if (strcmp(name, AUTH_SUPERUSER) == 0)
598 maxLifetime = 100 * 3600;
599 else
600 maxLifetime = 25 * 3600; /* regular users */
601 tentry.max_ticket_lifetime = htonl(maxLifetime);
602
603 code = ThreadBlock(tt, to, &tentry);
604 return code;
605 }
606
607 /* Put actual stub routines here */
608
609 afs_int32
610 SKAM_CreateUser(struct rx_call *call, char *aname, char *ainstance,
611 EncryptionKey ainitpw)
612 {
613 afs_int32 code;
614
615 code = kamCreateUser(call, aname, ainstance, ainitpw);
616 osi_auditU(call, AFS_KAM_CrUserEvent, code, AUD_STR, aname, AUD_STR,
617 ainstance, AUD_END);
618 return code;
619 }
620
621
622 afs_int32
623 kamCreateUser(struct rx_call *call, char *aname, char *ainstance,
624 EncryptionKey ainitpw)
625 {
626 int code;
627 struct ubik_trans *tt;
628 afs_int32 caller; /* Disk offset of caller's entry */
629
630 COUNT_REQ(CreateUser);
631 if (!DES_check_key_parity(EncryptionKey_to_cblock(&ainitpw)) ||
632 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;
643 }
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;
649 }
650 code = ubik_EndTrans(tt);
651 KALOG(aname, ainstance, NULL, NULL, NULL,
652 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_CRUSER);
653 return code;
654 }
655
656 afs_int32
657 SKAA_ChangePassword(struct rx_call *call, char *aname, char *ainstance,
658 ka_CBS *arequest, ka_BBS *oanswer)
659 {
660 afs_int32 code;
661
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;
666 }
667
668 afs_int32
669 ChangePassWord(struct rx_call *call, char *aname, char *ainstance,
670 ka_CBS *arequest, ka_BBS *oanswer)
671 {
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 */
682
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;
690
691 code = FindBlock(tt, aname, ainstance, &to, &tentry);
692 if (code) {
693 goto abort;
694 }
695 if (to == 0) { /* no such user */
696 code = KANOENT;
697 goto abort;
698 }
699 if (ntohl(tentry.flags) & KAFNOCPW) {
700 code = KABADCPW;
701 goto abort;
702 }
703
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);
710
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;
719 }
720
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
723 */
724 code = impose_reuse_limits(ktc_to_EncryptionKey(&request.newpw), &tentry);
725 if (code) {
726 goto abort;
727 }
728
729 /* Create the Answer Packet */
730 answer_len = sizeof(Date) + KA_LABELSIZE;
731 if (oanswer->MaxSeqLen < answer_len) {
732 code = KAANSWERTOOLONG;
733 goto abort;
734 }
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);
741
742 DES_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, answer_len,
743 &user_schedule, ktc_to_cblockptr(&tentry.key), ENCRYPT);
744
745 code = set_password(tt, aname, ainstance, &request.newpw, kvno, 0);
746 if (code) {
747 code = KAIO;
748 goto abort;
749 }
750
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;
758 }
759
760 code = ubik_EndTrans(tt);
761 return code;
762
763 abort:
764 COUNT_ABO;
765 ubik_AbortTrans(tt);
766 return code;
767 }
768
769 static afs_int32
770 impose_reuse_limits(EncryptionKey *password, struct kaentry *tentry)
771 {
772 int code;
773 Date now;
774 int i;
775 extern int MinHours;
776 afs_uint32 newsum;
777
778 if (!tentry->pwsums[0] && npwSums > 1 && !tentry->pwsums[1])
779 return 0; /* password reuse limits not in effect */
780
781 code = get_time(&now, 0, 0);
782 if (code)
783 return code;
784
785 if ((now - ntohl(tentry->change_password_time)) < MinHours * 60 * 60)
786 return KATOOSOON;
787
788 if (!memcmp(password, &(tentry->key), sizeof(EncryptionKey)))
789 return KAREUSED;
790
791 code = ka_KeyCheckSum((char *)password, &newsum);
792 if (code)
793 return code;
794
795 newsum = newsum & 0x000000ff;
796 for (i = 0; i < npwSums; i++) {
797 if (newsum == tentry->pwsums[i])
798 return KAREUSED;
799 }
800
801 return 0;
802 }
803
804
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)
808 {
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;
816
817 code = FindBlock(tt, name, instance, &to, &tentry);
818 if (code)
819 return code;
820 if (to == 0)
821 return KANOENT; /* no such user */
822
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;
833 }
834
835
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++;
848 }
849 tentry.key_version = htonl((afs_int32) kvno); /* requested key version */
850 }
851
852
853
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);
861 }
862
863 tentry.change_password_time = htonl(now);
864
865 if ((code = kawrite(tt, to, (char *) &tentry, sizeof(tentry))))
866 return (KAIO);
867 return (0);
868 }
869
870 afs_int32
871 SKAM_SetPassword(struct rx_call *call, char *aname, char *ainstance,
872 afs_int32 akvno, EncryptionKey apassword)
873 {
874 afs_int32 code;
875
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;
880 }
881
882 afs_int32
883 kamSetPassword(struct rx_call *call, char *aname, char *ainstance,
884 afs_int32 akvno, EncryptionKey apassword)
885 {
886 int code;
887 struct ubik_trans *tt;
888 afs_int32 caller; /* Disk offset of caller's entry */
889 struct kaentry tentry;
890
891 COUNT_REQ(SetPassword);
892 if (akvno > MAXKAKVNO)
893 return KABADARGUMENT;
894 if (!DES_check_key_parity(EncryptionKey_to_cblock(&apassword)) ||
895 DES_is_weak_key(EncryptionKey_to_cblock(&apassword)))
896 return KABADKEY;
897
898 if (!name_instance_legal(aname, ainstance))
899 return KABADNAME;
900 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
901 return code;
902 code = check_auth(call, tt, 0, &caller);
903 if (code) {
904 goto abort;
905 }
906 if ((code = karead(tt, caller, (char *)&tentry, sizeof(tentry)))) {
907 code = KAIO;
908 goto abort;
909 }
910 /* if the user is changing his own password or ADMIN then go ahead. */
911 if ((strcmp(tentry.userID.name, aname) == 0)
912 && (strcmp(tentry.userID.instance, ainstance) == 0)) {
913 if (ntohl(tentry.flags) & KAFNOCPW)
914 code = KABADCPW;
915 else {
916 code = impose_reuse_limits(&apassword, &tentry);
917 if (!code)
918 code =
919 set_password(tt, aname, ainstance, EncryptionKey_to_ktc(&apassword), akvno, 0);
920 }
921 } else if (ntohl(tentry.flags) & KAFADMIN) {
922 code = set_password(tt, aname, ainstance, EncryptionKey_to_ktc(&apassword), akvno, caller);
923 } else
924 code = KANOAUTH;
925 if (code)
926 goto abort;
927
928 code = ubik_EndTrans(tt);
929 KALOG(aname, ainstance, NULL, NULL, NULL,
930 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_CHPASSWD);
931 return code;
932
933 abort:
934 COUNT_ABO;
935 ubik_AbortTrans(tt);
936 return code;
937 }
938
939 static Date
940 CoerseLifetime(Date start, Date end)
941 {
942 unsigned char kerberosV4Life;
943 kerberosV4Life = time_to_life(start, end);
944 end = life_to_time(start, kerberosV4Life);
945 return end;
946 }
947
948 static afs_int32
949 GetEndTime(Date start, /* start time of ticket */
950 Date reqEnd, /* requested end time */
951 Date expiration, /* authorizing ticket's expiration */
952 struct kaentry *caller,
953 struct kaentry *server,
954 Date *endP) /* actual end time */
955 {
956 Date cExp, sExp;
957 Date cLife, sLife;
958 Date end;
959
960 if (ntohl(caller->flags) & KAFNOTGS)
961 return KABADUSER; /* no new tickets for this user */
962 if (expiration && (ntohl(server->flags) & KAFNOSEAL))
963 return KABADSERVER; /* can't be target of GetTicket req */
964 if (!expiration)
965 expiration = NEVERDATE;
966
967 cExp = ntohl(caller->user_expiration);
968 sExp = ntohl(server->user_expiration);
969 if (cExp < start)
970 return KAPWEXPIRED;
971 if (sExp < start)
972 return KABADSERVER;
973 cLife = start + ntohl(caller->max_ticket_lifetime);
974 sLife = start + ntohl(server->max_ticket_lifetime);
975 end =
976 umin(umin(reqEnd, expiration),
977 umin(umin(cLife, sLife), umin(cExp, sExp)));
978 end = CoerseLifetime(start, end);
979 *endP = end;
980 return 0;
981 }
982
983 static afs_int32
984 PrepareTicketAnswer(ka_BBS *oanswer, afs_int32 challenge, char *ticket,
985 afs_int32 ticketLen, struct ktc_encryptionKey *sessionKey,
986 Date start, Date end, struct kaentry *caller,
987 struct kaentry *server, char *cell, char *label)
988 {
989 afs_int32 code;
990 struct ka_ticketAnswer *answer;
991 afs_int32 cksum;
992
993 code = KAANSWERTOOLONG;
994 if (oanswer->MaxSeqLen <
995 sizeof(struct ka_ticketAnswer) - 5 * MAXKTCNAMELEN - MAXKTCTICKETLEN +
996 ticketLen)
997 return code;
998
999 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
1000 answer->challenge = htonl(challenge);
1001 memcpy(&answer->sessionKey, sessionKey, sizeof(struct ktc_encryptionKey));
1002 answer->startTime = htonl(start);
1003 answer->endTime = htonl(end);
1004 answer->kvno = server->key_version;
1005 answer->ticketLen = htonl(ticketLen);
1006
1007 {
1008 char *ans = answer->name; /* pointer to variable part */
1009 int rem; /* space remaining */
1010 int len; /* macro temp. */
1011
1012 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1013 #undef putstr
1014 #define putstr(str) len = strlen (str)+1;\
1015 if (rem < len) return code;\
1016 strcpy (ans, str);\
1017 ans += len; rem -= len
1018 putstr(caller->userID.name);
1019 putstr(caller->userID.instance);
1020 putstr(cell);
1021 putstr(server->userID.name);
1022 putstr(server->userID.instance);
1023 if (rem < ticketLen + KA_LABELSIZE)
1024 return code;
1025 memcpy(ans, ticket, ticketLen);
1026 ans += ticketLen;
1027 if (label)
1028 memcpy(ans, label, KA_LABELSIZE);
1029 else
1030 memset(ans, 0, KA_LABELSIZE);
1031 ans += KA_LABELSIZE;
1032 oanswer->SeqLen = (ans - oanswer->SeqBody);
1033 }
1034 cksum = 0;
1035 answer->cksum = htonl(cksum);
1036 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1037 if (oanswer->SeqLen > oanswer->MaxSeqLen)
1038 return code;
1039 return 0;
1040 }
1041
1042 /* This is used to get a ticket granting ticket or an admininstration ticket.
1043 These two specific, built-in servers are special cases, which require the
1044 client's key as an additional security precaution. The GetTicket operation
1045 is normally disabled for these two principals. */
1046
1047 static afs_int32
1048 Authenticate(int version, struct rx_call *call, char *aname, char *ainstance,
1049 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1050 {
1051 int code;
1052 struct ubik_trans *tt;
1053 afs_int32 to; /* offset of block */
1054 kaentry tentry;
1055 struct kaentry server; /* entry for desired server */
1056 struct ka_gettgtRequest request; /* request after decryption */
1057 int tgt, adm; /* type of request */
1058 char *sname; /* principal of server */
1059 char *sinst;
1060 char ticket[MAXKTCTICKETLEN]; /* our copy of the ticket */
1061 int ticketLen;
1062 struct ktc_encryptionKey sessionKey; /* we have to invent a session key */
1063 char *answer; /* where answer is to be put */
1064 int answer_len; /* length of answer packet */
1065 Date answer_time; /* 1+ request time in network order */
1066 afs_int32 temp; /* for htonl conversions */
1067 DES_key_schedule user_schedule; /* key schedule for user's key */
1068 afs_int32 tgskvno; /* key version of service key */
1069 struct ktc_encryptionKey tgskey; /* service key for encrypting ticket */
1070 Date now;
1071 afs_uint32 pwexpires;
1072
1073 COUNT_REQ(Authenticate);
1074 if (!name_instance_legal(aname, ainstance))
1075 return KABADNAME;
1076 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1077 return code;
1078 get_time(&now, 0, 0);
1079
1080 sname = sinst = NULL;
1081
1082 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1083 if (code) {
1084 goto abort;
1085 }
1086 if (to == 0) { /* no such user */
1087 code = KANOENT;
1088 goto abort;
1089 }
1090 #ifdef LOCKPW
1091 /* have to check for locked before verifying the password, otherwise all
1092 * KALOCKED means is "yup, you guessed the password all right, now wait a
1093 * few minutes and we'll let you in"
1094 */
1095 if (kaux_islocked
1096 (to, (u_int) tentry.misc_auth_bytes[ATTEMPTS],
1097 (afs_uint32) tentry.misc_auth_bytes[LOCKTIME] << 9)) {
1098 code = KALOCKED;
1099 goto abort;
1100 }
1101 #endif /* LOCKPW */
1102
1103 save_principal(authPrincipal, aname, ainstance, 0);
1104
1105 /* decrypt request w/ user password */
1106 if ((code = DES_key_sched(ktc_to_cblock(&tentry.key), &user_schedule)))
1107 es_Report("In KAAuthenticate: key_sched returned %d\n", code);
1108 DES_pcbc_encrypt(arequest->SeqBody, &request,
1109 min(arequest->SeqLen, sizeof(request)), &user_schedule,
1110 ktc_to_cblockptr(&tentry.key), DECRYPT);
1111
1112 request.time = ntohl(request.time); /* reorder date */
1113 tgt = !strncmp(request.label, KA_GETTGT_REQ_LABEL, sizeof(request.label));
1114 adm = !strncmp(request.label, KA_GETADM_REQ_LABEL, sizeof(request.label));
1115 if (!(tgt || adm)) {
1116 kaux_inc(to, ((unsigned char)tentry.misc_auth_bytes[LOCKTIME]) << 9);
1117 code = KABADREQUEST;
1118 goto abort;
1119 } else
1120 kaux_write(to, 0, 0); /* reset counters */
1121
1122 #ifdef EXPIREPW
1123 if (!tentry.misc_auth_bytes[EXPIRES]) {
1124 /* 0 in the database means never, but 0 on the network means today */
1125 /* 255 on the network means "long time, maybe never" */
1126 pwexpires = 255;
1127 } else {
1128 pwexpires = tentry.misc_auth_bytes[EXPIRES];
1129
1130 pwexpires =
1131 ntohl(tentry.change_password_time) + 24 * 60 * 60 * pwexpires;
1132 if (adm) { /* provide a little slack for admin ticket */
1133 pwexpires += 30 * 24 * 60 * 60; /* 30 days */
1134 }
1135 if (pwexpires < now) {
1136 code = KAPWEXPIRED;
1137 goto abort;
1138 } else {
1139 pwexpires = (pwexpires - now) / (24 * 60 * 60);
1140 if (pwexpires > 255)
1141 pwexpires = 255;
1142 }
1143 }
1144 #endif /* EXPIREPW */
1145
1146 if (check_ka_skew(request.time, now, KTC_TIME_UNCERTAINTY)) {
1147 #if 0
1148 if (oanswer->MaxSeqLen < sizeof(afs_int32))
1149 code = KAANSWERTOOLONG;
1150 else { /* return our time if possible */
1151 oanswer->SeqLen = sizeof(afs_int32);
1152 request.time = htonl(now);
1153 memcpy(oanswer->SeqBody, &request.time, sizeof(afs_int32));
1154 }
1155 #endif
1156 code = KACLOCKSKEW;
1157 goto abort;
1158 }
1159 sname = (tgt ? KA_TGS_NAME : KA_ADMIN_NAME);
1160 sinst = (tgt ? lrealm : KA_ADMIN_INST);
1161 code = FindBlock(tt, sname, sinst, &to, &server);
1162 if (code)
1163 goto abort;
1164 if (to == 0) {
1165 code = KANOENT;
1166 goto abort;
1167 }
1168
1169 tgskvno = ntohl(server.key_version);
1170 memcpy(&tgskey, &server.key, sizeof(tgskey));
1171
1172 code = DES_new_random_key(ktc_to_cblock(&sessionKey));
1173 if (code) {
1174 code = KANOKEYS;
1175 goto abort;
1176 }
1177
1178 code = GetEndTime(start, end, 0 /*!GetTicket */ , &tentry, &server, &end);
1179 if (code)
1180 goto abort;
1181
1182 code =
1183 tkt_MakeTicket(ticket, &ticketLen, &tgskey, aname, ainstance, "",
1184 start, end, &sessionKey,
1185 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), sname,
1186 sinst);
1187 if (code)
1188 goto abort;
1189
1190 switch (version) {
1191 case 0:
1192 answer_len =
1193 ticketLen + sizeof(Date) + sizeof(struct ktc_encryptionKey) +
1194 2 * sizeof(afs_int32) + KA_LABELSIZE;
1195 answer_len = round_up_to_ebs(answer_len);
1196 if (answer_len > oanswer->MaxSeqLen) {
1197 code = KAANSWERTOOLONG;
1198 goto abort;
1199 }
1200 oanswer->SeqLen = answer_len;
1201 answer = oanswer->SeqBody;
1202 answer_time = htonl(request.time + 1);
1203 memcpy(answer, (char *)&answer_time, sizeof(Date));
1204 answer += sizeof(Date);
1205 memcpy(answer, (char *)&sessionKey, sizeof(struct ktc_encryptionKey));
1206 answer += sizeof(struct ktc_encryptionKey);
1207 temp = htonl(tgskvno);
1208 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1209 answer += sizeof(afs_int32);
1210 temp = htonl(ticketLen);
1211 memcpy(answer, (char *)&temp, sizeof(afs_int32));
1212 answer += sizeof(afs_int32);
1213 memcpy(answer, ticket, ticketLen);
1214 answer += ticketLen;
1215 memcpy(answer, (tgt ? KA_GETTGT_ANS_LABEL : KA_GETADM_ANS_LABEL),
1216 KA_LABELSIZE);
1217 break;
1218 case 1:
1219 case 2:
1220 code =
1221 PrepareTicketAnswer(oanswer, request.time + 1, ticket, ticketLen,
1222 &sessionKey, start, end, &tentry, &server, "",
1223 (tgt ? KA_GETTGT_ANS_LABEL :
1224 KA_GETADM_ANS_LABEL));
1225 if (code)
1226 goto abort;
1227 #ifdef EXPIREPW
1228 if ((version == 2)
1229 && oanswer->SeqLen < oanswer->MaxSeqLen + sizeof(afs_int32)) {
1230 temp = pwexpires << 24; /* move it into the high byte */
1231 pwexpires = htonl(temp);
1232
1233 memcpy((char *)oanswer->SeqBody + oanswer->SeqLen, &pwexpires,
1234 sizeof(afs_int32));
1235 oanswer->SeqLen += sizeof(afs_int32);
1236 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1237 if (oanswer->SeqLen > oanswer->MaxSeqLen) {
1238 code = KAANSWERTOOLONG;
1239 goto abort;
1240 }
1241 }
1242 #endif /* EXPIREPW */
1243 break;
1244
1245 default:
1246 code = KAINTERNALERROR;
1247 goto abort;
1248 }
1249 DES_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1250 &user_schedule, ktc_to_cblockptr(&tentry.key), ENCRYPT);
1251 code = ubik_EndTrans(tt);
1252 KALOG(aname, ainstance, sname, sinst, NULL,
1253 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_AUTHENTICATE);
1254 return code;
1255
1256 abort:
1257 COUNT_ABO;
1258 ubik_AbortTrans(tt);
1259 KALOG(aname, ainstance, sname, sinst, NULL,
1260 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_AUTHFAILED);
1261 return code;
1262 }
1263
1264 afs_int32
1265 SKAA_Authenticate_old(struct rx_call *call, char *aname, char *ainstance,
1266 Date start, Date end, ka_CBS *arequest,
1267 ka_BBS *oanswer)
1268 {
1269 int code;
1270
1271 IOMGR_Sleep(1); /* discourage use of this mechanism */
1272 code =
1273 Authenticate(0, call, aname, ainstance, start, end, arequest,
1274 oanswer);
1275 osi_auditU(call, AFS_KAA_AuthOEvent, code, AUD_STR, aname, AUD_STR,
1276 ainstance, AUD_END);
1277
1278 return code;
1279 }
1280
1281 afs_int32
1282 SKAA_Authenticate(struct rx_call *call, char *aname, char *ainstance,
1283 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1284 {
1285 int code;
1286
1287 code =
1288 Authenticate(1, call, aname, ainstance, start, end, arequest,
1289 oanswer);
1290 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1291 ainstance, AUD_END);
1292
1293 return code;
1294 }
1295
1296 afs_int32
1297 SKAA_AuthenticateV2(struct rx_call *call, char *aname, char *ainstance,
1298 Date start, Date end, ka_CBS *arequest, ka_BBS *oanswer)
1299 {
1300 int code;
1301
1302 code =
1303 Authenticate(2, call, aname, ainstance, start, end, arequest,
1304 oanswer);
1305 osi_auditU(call, AFS_KAA_AuthEvent, code, AUD_STR, aname, AUD_STR,
1306 ainstance, AUD_END);
1307
1308 return code;
1309 }
1310
1311 afs_int32
1312 SKAM_SetFields(struct rx_call *call,
1313 char *aname,
1314 char *ainstance,
1315 afs_int32 aflags,
1316 Date aexpiration,
1317 afs_int32 alifetime,
1318 afs_int32 amaxAssociates,
1319 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1320 afs_int32 spare2)
1321 {
1322 afs_int32 code;
1323
1324 code =
1325 kamSetFields(call, aname, ainstance, aflags, aexpiration, alifetime,
1326 amaxAssociates, misc_auth_bytes, spare2);
1327 osi_auditU(call, AFS_KAM_SetFldEvent, code, AUD_STR, aname, AUD_STR,
1328 ainstance, AUD_LONG, aflags, AUD_DATE, aexpiration, AUD_LONG,
1329 alifetime, AUD_LONG, amaxAssociates, AUD_END);
1330 return code;
1331 }
1332
1333 afs_int32
1334 kamSetFields(struct rx_call *call,
1335 char *aname,
1336 char *ainstance,
1337 afs_int32 aflags,
1338 Date aexpiration,
1339 afs_int32 alifetime,
1340 afs_int32 amaxAssociates,
1341 afs_uint32 misc_auth_bytes, /* 4 bytes, each 0 means unspecified */
1342 afs_int32 spare2)
1343 {
1344 afs_int32 code;
1345 Date now;
1346 struct ubik_trans *tt;
1347 afs_int32 caller;
1348 afs_int32 tentry_offset; /* offset of entry */
1349 struct kaentry tentry;
1350 unsigned char newvals[4];
1351
1352 COUNT_REQ(SetFields);
1353
1354 if (spare2)
1355 return KABADARGUMENT; /* not supported yet... */
1356
1357 /* make sure we're supposed to do something */
1358 if (!(aflags || aexpiration || alifetime || (amaxAssociates >= 0)
1359 || misc_auth_bytes)
1360 || ((aflags & ~KAFNORMAL) & ~KAF_SETTABLE_FLAGS))
1361 return KABADARGUMENT; /* arguments no good */
1362 if (!name_instance_legal(aname, ainstance))
1363 return KABADNAME;
1364 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1365 return code;
1366 code = check_auth(call, tt, 1, &caller);
1367 if (code) {
1368 goto abort;
1369 }
1370
1371 code = FindBlock(tt, aname, ainstance, &tentry_offset, &tentry);
1372 if (code)
1373 goto abort;
1374 if (tentry_offset == 0) { /* no such user */
1375 code = KANOENT;
1376 goto abort;
1377 }
1378 if ((ntohl(tentry.flags) & KAFNORMAL) == 0)
1379 return KAINTERNALERROR;
1380 if (aflags) {
1381 /* Keep track of the total number of admin accounts. This way we can
1382 * update database without any admin privilege initially */
1383 if ((aflags & KAFADMIN) != (ntohl(tentry.flags) & KAFADMIN)) {
1384 /* if admin state is changing */
1385 int delta;
1386 if (ntohl(tentry.flags) & KAFADMIN)
1387 delta = -1;
1388 else
1389 delta = 1;
1390 if ((code = update_admin_count(tt, delta)))
1391 goto abort;
1392 }
1393 tentry.flags =
1394 htonl((ntohl(tentry.flags) & ~KAF_SETTABLE_FLAGS) | aflags);
1395 }
1396 if ((code = get_time(&now, tt, 1)))
1397 goto abort;
1398 if (aexpiration) {
1399 tentry.user_expiration = htonl(aexpiration);
1400 if (!ntohl(tentry.change_password_time)) {
1401 tentry.change_password_time = htonl(now);
1402 }
1403 }
1404 if (alifetime)
1405 tentry.max_ticket_lifetime = htonl(alifetime);
1406
1407 #ifndef NOPWCONTROLS
1408 /*
1409 * We've packed a bunch of bytes into a long for backward compatibility.
1410 * These include password expiration time, and some failed login limits
1411 * counters. Now let's unpack them and stick them into the
1412 * kaentry struct. All the bytes have values in the range
1413 * 1..255, else they were not specified in the interface, and are
1414 * set to zero.
1415 * In the case of password expiration times, 1 means password never
1416 * expires (==>0), 2 means password only lives for one day (==>1),
1417 * and so on.
1418 */
1419 if (misc_auth_bytes) {
1420 unpack_long(misc_auth_bytes, newvals);
1421 if (newvals[EXPIRES]) {
1422 tentry.misc_auth_bytes[EXPIRES] = newvals[EXPIRES] - 1;
1423 }
1424
1425 if (newvals[REUSEFLAGS]) {
1426 if (newvals[REUSEFLAGS] & KA_REUSEPW)
1427 memset(tentry.pwsums, 0, KA_NPWSUMS);
1428 else if ((newvals[REUSEFLAGS] & KA_NOREUSEPW)
1429 && !tentry.pwsums[0])
1430 tentry.pwsums[0] = 0xff;
1431 }
1432
1433 if (newvals[ATTEMPTS]) {
1434 tentry.misc_auth_bytes[ATTEMPTS] = newvals[ATTEMPTS] - 1;
1435 }
1436 if (newvals[LOCKTIME]) {
1437 tentry.misc_auth_bytes[LOCKTIME] = newvals[LOCKTIME] - 1;
1438 }
1439 /*
1440 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1441 */
1442 }
1443 #endif /* NOPWCONTROLS */
1444
1445 if (amaxAssociates >= 0) {
1446 if ((ntohl(tentry.flags) & KAFASSOC)
1447 || (ntohl(tentry.flags) & KAFSPECIAL))
1448 return KAASSOCUSER;
1449 if (((ntohl(tentry.flags) & KAFASSOCROOT) == 0) && (amaxAssociates > 0)) /* convert normal user to assoc root */
1450 tentry.flags = htonl(ntohl(tentry.flags) | KAFASSOCROOT);
1451 tentry.misc.assocRoot.maxAssociates = htonl(amaxAssociates);
1452 }
1453
1454 tentry.modification_time = htonl(now);
1455 tentry.modification_id = htonl(caller);
1456 code = kawrite(tt, tentry_offset, (char *) &tentry, sizeof(tentry));
1457 if (code)
1458 goto abort;
1459
1460 code = ubik_EndTrans(tt);
1461 KALOG(aname, ainstance, NULL, NULL, NULL,
1462 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_SETFIELDS);
1463 return code;
1464
1465 abort:
1466 COUNT_ABO;
1467 ubik_AbortTrans(tt);
1468 return code;
1469 }
1470
1471 /* delete a user */
1472
1473 afs_int32
1474 SKAM_DeleteUser(struct rx_call *call, char *aname, char *ainstance)
1475 {
1476 afs_int32 code;
1477
1478 code = kamDeleteUser(call, aname, ainstance);
1479 osi_auditU(call, AFS_KAM_DelUserEvent, code, AUD_STR, aname, AUD_STR,
1480 ainstance, AUD_END);
1481 return code;
1482 }
1483
1484 afs_int32
1485 kamDeleteUser(struct rx_call *call, char *aname, char *ainstance)
1486 {
1487 int code;
1488 struct ubik_trans *tt;
1489 afs_int32 caller;
1490 afs_int32 to;
1491 struct kaentry tentry;
1492 unsigned int nfailures;
1493 afs_uint32 locktime;
1494
1495 COUNT_REQ(DeleteUser);
1496 if (!name_instance_legal(aname, ainstance))
1497 return KABADNAME;
1498 if ((code = InitAuthServ(&tt, LOCKWRITE, this_op)))
1499 return code;
1500 code = check_auth(call, tt, 1, &caller);
1501 if (code) {
1502 abort:
1503 COUNT_ABO;
1504 ubik_AbortTrans(tt);
1505 return code;
1506 }
1507
1508 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1509 if (code)
1510 goto abort;
1511 if (to == 0) { /* name not found */
1512 code = KANOENT;
1513 goto abort;
1514 }
1515
1516 kaux_read(to, &nfailures, &locktime);
1517 if (nfailures || locktime)
1518 kaux_write(to, 0, 0); /* zero failure counters at this offset */
1519
1520 /* track all AuthServer identities */
1521 if (special_name(aname, ainstance))
1522 if ((code = ka_DelKey(tt, to, &tentry)))
1523 goto abort;
1524
1525 if (ntohl(tentry.flags) & KAFADMIN) /* keep admin count up-to-date */
1526 if ((code = update_admin_count(tt, -1)))
1527 goto abort;
1528
1529 if ((code = UnthreadBlock(tt, &tentry)) || (code = FreeBlock(tt, to)) || (code = get_time(0, tt, 1)) /* update randomness */
1530 )
1531 goto abort;
1532
1533 code = ubik_EndTrans(tt);
1534 KALOG(aname, ainstance, NULL, NULL, NULL,
1535 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_DELUSER);
1536 return code;
1537 }
1538
1539 /* we set a bit in here which indicates that the user's limit of
1540 * authentication failures has been exceeded. If that bit is not set,
1541 * kas can take it on faith that the user ID is not locked. If that
1542 * bit is set, kas has to check all the servers to find one who will
1543 * report that the ID is not locked, or else to find out when the ID
1544 * will be unlocked.
1545 */
1546 afs_int32
1547 SKAM_GetEntry(struct rx_call *call,
1548 char *aname,
1549 char *ainstance,
1550 afs_int32 aversion, /* major version assumed by caller */
1551 kaentryinfo *aentry) /* entry data copied here */
1552 {
1553 afs_int32 code;
1554
1555 code = kamGetEntry(call, aname, ainstance, aversion, aentry);
1556 osi_auditU(call, AFS_KAM_GetEntEvent, code, AUD_STR, aname, AUD_STR,
1557 ainstance, AUD_END);
1558 return code;
1559 }
1560
1561 afs_int32
1562 kamGetEntry(struct rx_call *call,
1563 char *aname,
1564 char *ainstance,
1565 afs_int32 aversion, /* major version assumed by caller */
1566 kaentryinfo *aentry) /* entry data copied here */
1567 {
1568 afs_int32 code;
1569 struct ubik_trans *tt;
1570 afs_int32 callerIndex;
1571 struct kaentry caller;
1572 afs_int32 to;
1573 afs_uint32 temp;
1574 struct kaentry tentry;
1575 rxkad_level enc_level = rxkad_clear;
1576 int callerIsAdmin = 0;
1577
1578 COUNT_REQ(GetEntry);
1579 if (aversion != KAMAJORVERSION)
1580 return KAOLDINTERFACE;
1581 if (!name_instance_legal(aname, ainstance))
1582 return KABADNAME;
1583 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1584 return code;
1585 code = check_auth(call, tt, 0, &callerIndex);
1586 if (code) {
1587 goto abort;
1588 }
1589 if (noAuthenticationRequired) {
1590 } else if (!callerIndex) {
1591 code = KANOENT;
1592 goto abort;
1593 } else {
1594 if ((code = karead(tt, callerIndex, (char *)&caller, sizeof(caller)))) {
1595 code = KAIO;
1596 goto abort;
1597 }
1598 /* if the user is checking his own entry or ADMIN then go ahead. */
1599 callerIsAdmin = (ntohl(caller.flags) & KAFADMIN);
1600
1601 if (strcmp(caller.userID.name, aname) != 0 && !callerIsAdmin) {
1602 code = KANOAUTH;
1603 goto abort;
1604 }
1605 }
1606
1607 code = FindBlock(tt, aname, ainstance, &to, &tentry);
1608 if (code)
1609 goto abort;
1610 if (to == 0) { /* entry not found */
1611 code = KANOENT;
1612 goto abort;
1613 }
1614
1615 get_time(0, 0, 0); /* generate random update */
1616
1617 memset(aentry, 0, sizeof(*aentry));
1618 aentry->minor_version = KAMINORVERSION;
1619 aentry->flags = ntohl(tentry.flags);
1620 aentry->user_expiration = ntohl(tentry.user_expiration);
1621 aentry->modification_time = ntohl(tentry.modification_time);
1622 aentry->change_password_time = ntohl(tentry.change_password_time);
1623 aentry->max_ticket_lifetime = ntohl(tentry.max_ticket_lifetime);
1624 aentry->key_version = ntohl(tentry.key_version);
1625
1626 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
1627 temp = temp << 9;
1628 if (kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp))
1629 tentry.misc_auth_bytes[REUSEFLAGS] |= KA_ISLOCKED; /* saves an RPC */
1630
1631 temp = pack_long(tentry.misc_auth_bytes);
1632 aentry->misc_auth_bytes = temp;
1633 /*
1634 * only return user's key if security disabled or if admin and
1635 * we have an encrypted connection to the user
1636 */
1637 rxkad_GetServerInfo(rx_ConnectionOf(call), &enc_level, 0, 0, 0, 0, 0);
1638 if ((noAuthenticationRequired)
1639 || (callerIsAdmin && enc_level == rxkad_crypt))
1640 memcpy(&aentry->key, &tentry.key, sizeof(struct ktc_encryptionKey));
1641 else
1642 memset(&aentry->key, 0, sizeof(aentry->key));
1643
1644 code = ka_KeyCheckSum((char *)&tentry.key, &aentry->keyCheckSum);
1645 if (code)
1646 goto abort;
1647
1648 if (!tentry.pwsums[0] && npwSums > 1 && !tentry.pwsums[1]) {
1649 aentry->reserved3 = 0x12340000;
1650 } else {
1651 aentry->reserved3 = 0x12340001;
1652 }
1653
1654 /* Now get entry of user who last modified this entry */
1655 if (ntohl(tentry.modification_id)) {
1656 temp = ntohl(tentry.modification_id);
1657 code = karead(tt, temp, (char *)&tentry, sizeof(tentry));
1658 if (code) {
1659 code = KAIO;
1660 goto abort;
1661 }
1662 aentry->modification_user = tentry.userID;
1663 } else {
1664 strcpy(aentry->modification_user.name, "<none>");
1665 strcpy(aentry->modification_user.instance, "\0");
1666 }
1667 code = ubik_EndTrans(tt);
1668 return code;
1669
1670 abort:
1671 COUNT_ABO;
1672 ubik_AbortTrans(tt);
1673 return code;
1674 }
1675
1676 afs_int32
1677 SKAM_ListEntry(struct rx_call *call,
1678 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1679 afs_int32 *index, /* index of this entry */
1680 afs_int32 *count, /* total entries in database */
1681 kaident *name) /* name & instance of this entry */
1682 {
1683 afs_int32 code;
1684
1685 code = kamListEntry(call, previous_index, index, count, name);
1686 osi_auditU(call, AFS_KAM_LstEntEvent, code, AUD_LONG, *index, AUD_END);
1687 return code;
1688 }
1689
1690
1691 afs_int32
1692 kamListEntry(struct rx_call *call,
1693 afs_int32 previous_index, /* last entry ret'd or 0 for first */
1694 afs_int32 *index, /* index of this entry */
1695 afs_int32 *count, /* total entries in database */
1696 kaident *name) /* name & instance of this entry */
1697 {
1698 int code;
1699 struct ubik_trans *tt;
1700 afs_int32 caller;
1701 struct kaentry tentry;
1702
1703 memset(name, 0, sizeof(*name));
1704 COUNT_REQ(ListEntry);
1705 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1706 return code;
1707 code = check_auth(call, tt, 1, &caller);
1708 if (code) {
1709 goto abort;
1710 }
1711
1712 *index = NextBlock(tt, previous_index, &tentry, count);
1713 if (*count < 0) {
1714 code = KAIO;
1715 goto abort;
1716 }
1717
1718 if (*index) { /* return name & inst of this entry */
1719 strncpy(name->name, tentry.userID.name, sizeof(name->name));
1720 strncpy(name->instance, tentry.userID.instance,
1721 sizeof(name->instance));
1722 } else {
1723 strcpy(name->name, "\0");
1724 strcpy(name->instance, "\0");
1725 }
1726 code = ubik_EndTrans(tt);
1727 return code;
1728
1729 abort:
1730 COUNT_ABO;
1731 ubik_AbortTrans(tt);
1732 return code;
1733 }
1734
1735 static afs_int32
1736 GetTicket(int version,
1737 struct rx_call *call,
1738 afs_int32 kvno,
1739 char *authDomain,
1740 ka_CBS *aticket,
1741 char *sname,
1742 char *sinstance,
1743 ka_CBS *atimes, /* encrypted start & end time */
1744 ka_BBS *oanswer)
1745 {
1746 afs_int32 code;
1747 int import, export;
1748 struct ubik_trans *tt;
1749 struct ktc_encryptionKey tgskey;
1750 DES_key_schedule schedule;
1751 afs_int32 to;
1752 char name[MAXKTCNAMELEN];
1753 char instance[MAXKTCNAMELEN];
1754 char cell[MAXKTCNAMELEN];
1755 int celllen;
1756 struct kaentry caller;
1757 struct kaentry server;
1758 struct ktc_encryptionKey authSessionKey;
1759 struct ktc_encryptionKey sessionKey;
1760 int ticketLen;
1761 char ticket[MAXKTCTICKETLEN];
1762 afs_int32 host;
1763 Date start;
1764 Date expiration;
1765 Date now;
1766 Date end;
1767 struct ka_getTicketTimes times;
1768 struct ka_getTicketAnswer *answer;
1769
1770 COUNT_REQ(GetTicket);
1771 if (!name_instance_legal(sname, sinstance))
1772 return KABADNAME;
1773 if (atimes->SeqLen != sizeof(times))
1774 return KABADARGUMENT;
1775 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
1776 return code;
1777
1778 export = import = 0;
1779 if ((strcmp(sname, KA_TGS_NAME) == 0) && (strcmp(sinstance, lrealm) != 0))
1780 export = 1;
1781 if ((strlen(authDomain) > 0) && (strcmp(authDomain, lrealm) != 0))
1782 import = 1;
1783
1784 if (strlen(authDomain) == 0)
1785 authDomain = lrealm;
1786 code = ka_LookupKvno(tt, KA_TGS_NAME, authDomain, kvno, &tgskey);
1787 if (code) {
1788 goto abort;
1789 }
1790 code =
1791 tkt_DecodeTicket(aticket->SeqBody, aticket->SeqLen, &tgskey, name,
1792 instance, cell, &authSessionKey, &host, &start,
1793 &expiration);
1794 if (code) {
1795 code = KANOAUTH;
1796 goto abort;
1797 }
1798 save_principal(tgsPrincipal, name, instance, cell);
1799
1800 if ((code = get_time(&now, 0, 0)))
1801 goto abort;
1802
1803 code = tkt_CheckTimes(start, expiration, now);
1804 if (code <= 0) {
1805 if (code == -1)
1806 code = RXKADEXPIRED;
1807 else
1808 code = KANOAUTH;
1809 goto abort;
1810 }
1811 code = DES_key_sched(ktc_to_cblock(&authSessionKey), &schedule);
1812 if (code) {
1813 code = KANOAUTH;
1814 goto abort;
1815 }
1816 celllen = strlen(cell);
1817 if (import && (celllen == 0)) {
1818 code = KABADTICKET;
1819 goto abort;
1820 }
1821 if (export && (celllen == 0))
1822 strcpy(cell, lrealm);
1823
1824 if (!krb4_cross && celllen && strcmp(lrealm, cell) != 0) {
1825 code = KABADUSER;
1826 goto abort;
1827 }
1828
1829 DES_ecb_encrypt((DES_cblock *)atimes->SeqBody, (DES_cblock *)&times, &schedule, DECRYPT);
1830 times.start = ntohl(times.start);
1831 times.end = ntohl(times.end);
1832 code = tkt_CheckTimes(times.start, times.end, now);
1833 if (code < 0) {
1834 code = KABADREQUEST;
1835 goto abort;
1836 }
1837
1838 if (import) {
1839 strcpy(caller.userID.name, name);
1840 strcpy(caller.userID.instance, instance);
1841 caller.max_ticket_lifetime = htonl(MAXKTCTICKETLIFETIME);
1842 caller.flags = htonl(KAFNORMAL);
1843 caller.user_expiration = htonl(NEVERDATE);
1844 } else {
1845 code = FindBlock(tt, name, instance, &to, &caller);
1846 if (code)
1847 goto abort;
1848 if (to == 0) {
1849 ka_PrintUserID("GetTicket: User ", name, instance, " unknown.\n");
1850 code = KANOENT;
1851 goto abort;
1852 }
1853 }
1854
1855 /* get server's entry */
1856 code = FindBlock(tt, sname, sinstance, &to, &server);
1857 if (code)
1858 goto abort;
1859 if (to == 0) { /* entry not found */
1860 ka_PrintUserID("GetTicket: Server ", sname, sinstance, " unknown.\n");
1861 code = KANOENT;
1862 goto abort;
1863 }
1864 save_principal(tgsServerPrincipal, sname, sinstance, 0);
1865
1866 code = DES_new_random_key(ktc_to_cblock(&sessionKey));
1867 if (code) {
1868 code = KANOKEYS;
1869 goto abort;
1870 }
1871
1872 code =
1873 GetEndTime(times.start, times.end, expiration, &caller, &server,
1874 &end);
1875 if (code)
1876 goto abort;
1877
1878 code =
1879 tkt_MakeTicket(ticket, &ticketLen, &server.key, caller.userID.name,
1880 caller.userID.instance, cell, times.start, end,
1881 &sessionKey,
1882 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))),
1883 server.userID.name, server.userID.instance);
1884 if (code)
1885 goto abort;
1886
1887 switch (version) {
1888 case 0:
1889 code = KAANSWERTOOLONG;
1890 if (oanswer->MaxSeqLen <
1891 sizeof(struct ka_getTicketAnswer) - 5 * MAXKTCNAMELEN -
1892 MAXKTCTICKETLEN + ticketLen)
1893 goto abort;
1894
1895 answer = (struct ka_getTicketAnswer *)oanswer->SeqBody;
1896 memcpy(&answer->sessionKey, &sessionKey,
1897 sizeof(struct ktc_encryptionKey));
1898 answer->startTime = htonl(times.start);
1899 answer->endTime = htonl(end);
1900 answer->kvno = server.key_version;
1901 answer->ticketLen = htonl(ticketLen);
1902
1903 {
1904 char *ans = answer->name; /* ptr to variable part of answer */
1905 int rem, len;
1906
1907 /* space remaining */
1908 rem = oanswer->MaxSeqLen - (ans - oanswer->SeqBody);
1909 #undef putstr
1910 #define putstr(str) len = strlen (str)+1;\
1911 if (rem < len) goto abort;\
1912 strcpy (ans, str);\
1913 ans += len; rem -= len
1914
1915 putstr(name);
1916 putstr(instance);
1917 putstr(cell);
1918 putstr(sname);
1919 putstr(sinstance);
1920 if (rem < ticketLen)
1921 goto abort;
1922 memcpy(ans, ticket, ticketLen);
1923 oanswer->SeqLen = (ans - oanswer->SeqBody) + ticketLen;
1924 }
1925 oanswer->SeqLen = round_up_to_ebs(oanswer->SeqLen);
1926 break;
1927 case 1:
1928 code =
1929 PrepareTicketAnswer(oanswer, /*challenge */ 0, ticket, ticketLen,
1930 &sessionKey, times.start, end, &caller,
1931 &server, cell, KA_GETTICKET_ANS_LABEL);
1932 if (code)
1933 goto abort;
1934 break;
1935 default:
1936 code = KAINTERNALERROR;
1937 goto abort;
1938 }
1939 DES_pcbc_encrypt(oanswer->SeqBody, oanswer->SeqBody, oanswer->SeqLen,
1940 &schedule, ktc_to_cblockptr(&authSessionKey), ENCRYPT);
1941 code = ubik_EndTrans(tt);
1942 KALOG(name, instance, sname, sinstance, (import ? authDomain : NULL),
1943 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_GETTICKET);
1944 return code;
1945
1946 abort:
1947 COUNT_ABO;
1948 ubik_AbortTrans(tt);
1949 return code;
1950 }
1951
1952 afs_int32
1953 SKAT_GetTicket_old(struct rx_call *call,
1954 afs_int32 kvno,
1955 char *authDomain,
1956 ka_CBS *aticket,
1957 char *sname,
1958 char *sinstance,
1959 ka_CBS *atimes, /* encrypted start & end time */
1960 ka_BBS *oanswer)
1961 {
1962 int code;
1963
1964 sleep(1); /* strongly discourage this */
1965 code =
1966 GetTicket(0, call, kvno, authDomain, aticket, sname, sinstance,
1967 atimes, oanswer);
1968
1969 osi_auditU(call, AFS_KAT_GetTicketOEvent, code, AUD_STR, sname, AUD_STR,
1970 sinstance, AUD_END);
1971 return code;
1972 }
1973
1974 afs_int32
1975 SKAT_GetTicket(struct rx_call *call,
1976 afs_int32 kvno,
1977 char *authDomain,
1978 ka_CBS *aticket,
1979 char *sname,
1980 char *sinstance,
1981 ka_CBS *atimes, /* encrypted start & end time */
1982 ka_BBS *oanswer)
1983 {
1984 int code;
1985
1986 code =
1987 GetTicket(1, call, kvno, authDomain, aticket, sname, sinstance,
1988 atimes, oanswer);
1989 osi_auditU(call, AFS_KAT_GetTicketEvent, code, AUD_STR, sname, AUD_STR,
1990 sinstance, AUD_END);
1991 return code;
1992 }
1993
1994 afs_int32
1995 SKAM_GetStats(struct rx_call *call, afs_int32 version,
1996 afs_int32 *admin_accounts, kasstats *statics,
1997 kadstats *dynamics)
1998 {
1999 afs_int32 code;
2000
2001 code = kamGetStats(call, version, admin_accounts, statics, dynamics);
2002 osi_auditU(call, AFS_KAM_GetStatEvent, code, AUD_END);
2003 return code;
2004 }
2005
2006 afs_int32
2007 kamGetStats(struct rx_call *call, afs_int32 version,
2008 afs_int32 *admin_accounts, kasstats *statics,
2009 kadstats *dynamics)
2010 {
2011 afs_int32 code;
2012 struct ubik_trans *tt;
2013 afs_int32 caller;
2014
2015 COUNT_REQ(GetStats);
2016 if (version != KAMAJORVERSION)
2017 return KAOLDINTERFACE;
2018 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2019 return code;
2020 code = check_auth(call, tt, 1, &caller);
2021 if (code) {
2022 COUNT_ABO;
2023 ubik_AbortTrans(tt);
2024 return code;
2025 }
2026
2027 *admin_accounts = ntohl(cheader.admin_accounts);
2028 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
2029 /* these are stored in network byte order and must be copied */
2030 statics->allocs = ntohl(cheader.stats.allocs);
2031 statics->frees = ntohl(cheader.stats.frees);
2032 statics->cpws = ntohl(cheader.stats.cpws);
2033 #if KADBVERSION != 5
2034 check that the statistics command copies all the fields
2035 #endif
2036 memcpy((char *)dynamics, (char *)&dynamic_statistics, sizeof(kadstats));
2037 statics->minor_version = KAMINORVERSION;
2038 dynamics->minor_version = KAMINORVERSION;
2039
2040 {
2041 int used = 0;
2042 int i;
2043
2044 for (i = 0; i < HASHSIZE; i++)
2045 if (cheader.nameHash[i])
2046 used++;
2047 dynamics->hashTableUtilization =
2048 (used * 10000 + HASHSIZE / 2) / HASHSIZE;
2049 }
2050 {
2051 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
2052 struct rusage ru;
2053 /* Unfortunately, although aix_22 has a minimal compatibility
2054 * method of getting to some rusage fields (i.e. stime &
2055 * utime), the version that we have doesn't even have the
2056 * related include files needed for the aix vtimes() call; so
2057 * ignore this for aix till v3.1... */
2058 getrusage(RUSAGE_SELF, &ru);
2059 #if (KAMAJORVERSION>5)
2060 memcpy(&dynamics->utime, &ru.ru_utime, sizeof(struct katimeval));
2061 memcpy(&dynamics->stime, &ru.ru_stime, sizeof(struct katimeval));
2062 dynamics->dataSize = ru.ru_idrss;
2063 dynamics->stackSize = ru.ru_isrss;
2064 dynamics->pageFailts = ru.ru_majflt;
2065 #else
2066 dynamics->string_checks =
2067 (afs_int32) (1000.0 *
2068 ((ru.ru_utime.tv_sec +
2069 ru.ru_utime.tv_usec / 1000000.0) +
2070 (ru.ru_stime.tv_sec +
2071 ru.ru_stime.tv_usec / 1000000.0)));
2072 #endif
2073 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
2074 }
2075
2076 code = ubik_EndTrans(tt);
2077 return code;
2078 }
2079
2080 afs_int32
2081 SKAM_GetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2082 {
2083 afs_int32 code;
2084
2085 code = kamGetPassword(call, name, password);
2086 osi_auditU(call, AFS_KAM_GetPswdEvent, code, AUD_STR, name, AUD_END);
2087 return code;
2088 }
2089
2090 afs_int32
2091 kamGetPassword(struct rx_call *call, char *name, EncryptionKey *password)
2092 {
2093 int code = KANOAUTH;
2094 AFS_UNUSED COUNT_REQ(GetPassword);
2095 #ifdef GETPASSWORD
2096 {
2097 afs_int32 to;
2098 struct ubik_trans *tt;
2099 struct kaentry tentry;
2100
2101 if (!name_instance_legal(name, ""))
2102 return KABADNAME;
2103 /* only requests from this host work */
2104 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))) !=
2105 htonl(INADDR_LOOPBACK))
2106 return KANOAUTH;
2107 if (code = InitAuthServ(&tt, LOCKREAD, this_op))
2108 return code;
2109
2110 /* this isn't likely to be used because of string to key problems, so since
2111 * this is a temporary thing anyway, we'll use it here. */
2112 {
2113 extern char udpAuthPrincipal[256];
2114
2115 save_principal(udpAuthPrincipal, name, 0, 0);
2116 }
2117
2118 get_time(0, 0, 0); /* update random value */
2119 code = FindBlock(tt, name, "", &to, &tentry);
2120 if (code)
2121 goto abort;
2122 if (to == 0) {
2123 code = KANOENT;
2124 abort:
2125 COUNT_ABO;
2126 ubik_AbortTrans(tt);
2127 return code;
2128 }
2129
2130 memcpy(password, &tentry.key, sizeof(*password));
2131 code = ubik_EndTrans(tt);
2132 }
2133 #endif
2134 return code;
2135 }
2136
2137 afs_int32
2138 SKAM_GetRandomKey(struct rx_call *call, EncryptionKey *key)
2139 {
2140 afs_int32 code;
2141
2142 code = kamGetRandomKey(call, key);
2143 osi_auditU(call, AFS_KAM_GetRndKeyEvent, code, AUD_END);
2144 return code;
2145 }
2146
2147 afs_int32
2148 kamGetRandomKey(struct rx_call *call, EncryptionKey *key)
2149 {
2150 int code;
2151
2152 AFS_UNUSED COUNT_REQ(GetRandomKey);
2153 if ((code = AwaitInitialization()))
2154 return code;
2155 code = DES_new_random_key(EncryptionKey_to_cblock(key));
2156 if (code)
2157 return KANOKEYS;
2158 return 0;
2159 }
2160
2161 afs_int32
2162 SKAM_Debug(struct rx_call *call,
2163 afs_int32 version,
2164 int checkDB, /* start a transaction to examine DB */
2165 struct ka_debugInfo *info)
2166 {
2167 afs_int32 code;
2168
2169 code = kamDebug(call, version, checkDB, info);
2170 osi_auditU(call, AFS_KAM_DbgEvent, code, AUD_END);
2171 return code;
2172 }
2173
2174 afs_int32
2175 kamDebug(struct rx_call *call,
2176 afs_int32 version,
2177 int checkDB, /* start a transaction to examine DB */
2178 struct ka_debugInfo *info)
2179 {
2180 /* COUNT_REQ (Debug); */
2181 if (sizeof(struct kaentry) != sizeof(struct kaOldKeys))
2182 return KAINTERNALERROR;
2183 if (sizeof(struct ka_cpwRequest) % 8)
2184 return KAINTERNALERROR;
2185 if (version != KAMAJORVERSION)
2186 return KAOLDINTERFACE;
2187
2188 memset(info, 0, sizeof(*info));
2189
2190 info->minorVersion = KAMINORVERSION;
2191 info->host = dynamic_statistics.host;
2192 info->startTime = dynamic_statistics.start_time;
2193 info->
2194 #if (KAMAJORVERSION>5)
2195 now
2196 #else
2197 reserved1
2198 #endif
2199 = time(0);
2200 info->noAuth = noAuthenticationRequired;
2201
2202 info->dbVersion = ntohl(cheader.version);
2203 info->dbFreePtr = ntohl(cheader.freePtr);
2204 info->dbEofPtr = ntohl(cheader.eofPtr);
2205 info->dbKvnoPtr = ntohl(cheader.kvnoPtr);
2206 info->dbSpecialKeysVersion = ntohl(cheader.specialKeysVersion);
2207
2208 info->dbHeaderRead = cheaderReadTime;
2209 info->lastTrans = lastTrans;
2210 if (!lastOperation)
2211 lastOperation = "(Not Available)";
2212 strncpy(info->lastOperation, lastOperation, sizeof(info->lastOperation));
2213 strncpy(info->lastAuth, authPrincipal, sizeof(info->lastAuth));
2214 strncpy(info->lastTGS, tgsPrincipal, sizeof(info->lastTGS));
2215 strncpy(info->lastAdmin, adminPrincipal, sizeof(info->lastAdmin));
2216 strncpy(info->lastTGSServer, tgsServerPrincipal,
2217 sizeof(info->lastTGSServer));
2218 {
2219 extern char udpAuthPrincipal[256];
2220 extern char udptgsPrincipal[256];
2221 extern char udptgsServerPrincipal[256];
2222
2223 strncpy(info->lastUAuth, udpAuthPrincipal, sizeof(info->lastUAuth));
2224 strncpy(info->lastUTGS, udptgsPrincipal, sizeof(info->lastUTGS));
2225 strncpy(info->lastUTGSServer, udptgsServerPrincipal,
2226 sizeof(info->lastUTGSServer));
2227 }
2228 info->nextAutoCPW = nextAutoCPWTime;
2229 info->updatesRemaining = autoCPWUpdates - totalUpdates;
2230 ka_debugKeyCache(info);
2231 return 0;
2232 }
2233
2234 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2235 * a tacked-on-the-side data file.
2236 * prob'ly ought to check the noauth flag.
2237 */
2238 #define ABORTIF(A) {if((code = A)){goto abort;}}
2239 afs_int32
2240 SKAM_Unlock(struct rx_call *call,
2241 char *aname,
2242 char *ainstance,
2243 afs_int32 spare1,
2244 afs_int32 spare2,
2245 afs_int32 spare3,
2246 afs_int32 spare4)
2247 {
2248 int code;
2249 struct ubik_trans *tt;
2250 afs_int32 caller;
2251 afs_int32 to;
2252 struct kaentry tentry;
2253
2254 COUNT_REQ(Unlock);
2255 if (!name_instance_legal(aname, ainstance)) {
2256 code = KABADNAME;
2257 goto exit;
2258 }
2259 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2260 goto exit;
2261
2262 ABORTIF(check_auth(call, tt, 1, &caller));
2263 ABORTIF(FindBlock(tt, aname, ainstance, &to, &tentry));
2264 ABORTIF((to == 0 ? KANOENT : 0));
2265
2266 kaux_write(to, 0, 0); /* zero failure counters at this offset */
2267
2268 code = ubik_EndTrans(tt);
2269 KALOG(aname, ainstance, NULL, NULL, NULL,
2270 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call))), LOG_UNLOCK);
2271 goto exit;
2272
2273 abort:
2274 COUNT_ABO;
2275 ubik_AbortTrans(tt);
2276
2277 exit:
2278 osi_auditU(call, UnlockEvent, code, AUD_STR, aname, AUD_STR, ainstance,
2279 AUD_END);
2280 return code;
2281 }
2282
2283 afs_int32
2284 SKAM_LockStatus(struct rx_call *call,
2285 char *aname,
2286 char *ainstance,
2287 afs_int32 *lockeduntil,
2288 afs_int32 spare1,
2289 afs_int32 spare2,
2290 afs_int32 spare3,
2291 afs_int32 spare4)
2292 {
2293 int code;
2294 struct ubik_trans *tt;
2295 afs_int32 callerIndex;
2296 afs_int32 to;
2297 struct kaentry caller;
2298 struct kaentry tentry;
2299 afs_uint32 temp;
2300
2301 COUNT_REQ(LockStatus);
2302
2303 if (!name_instance_legal(aname, ainstance)) {
2304 code = KABADNAME;
2305 goto exit;
2306 }
2307 if ((code = InitAuthServ(&tt, LOCKREAD, this_op)))
2308 goto exit;
2309
2310 if ((code = check_auth(call, tt, 0, &callerIndex)))
2311 goto abort;
2312
2313 if (!noAuthenticationRequired && callerIndex) {
2314 if (karead(tt, callerIndex, (char *)&caller, sizeof(caller))) {
2315 code = KAIO;
2316 goto abort;
2317 }
2318 /* if the user is checking his own entry or ADMIN then go ahead. */
2319 if ((strcmp(caller.userID.name, aname) != 0)
2320 && !(ntohl(caller.flags) & KAFADMIN)) {
2321 code = KANOAUTH;
2322 goto abort;
2323 }
2324 }
2325
2326 if ((code = FindBlock(tt, aname, ainstance, &to, &tentry)))
2327 goto abort;
2328
2329 if (to == 0) {
2330 code = KANOENT;
2331 goto abort;
2332 }
2333
2334 temp = (unsigned char)tentry.misc_auth_bytes[LOCKTIME];
2335 temp = temp << 9;
2336 *lockeduntil =
2337 kaux_islocked(to, (u_int) tentry.misc_auth_bytes[ATTEMPTS], temp);
2338
2339 code = ubik_EndTrans(tt);
2340 goto exit;
2341
2342 abort:
2343 COUNT_ABO;
2344 ubik_AbortTrans(tt);
2345 osi_auditU(call, LockStatusEvent, code, AUD_STR, aname, AUD_STR,
2346 ainstance, AUD_END);
2347
2348 exit:
2349 return code;
2350 }