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