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