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