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