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