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