76caad9f07745a8ff0cb6cd479db2f216144ac13
[openafs.git] / src / libadmin / kas / afs_kasAdmin.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afsconfig.h>
12
13 RCSID("$Header$");
14
15 #include <stdio.h>
16 #include <afs/stds.h>
17 #include "afs_kasAdmin.h"
18 #include "../adminutil/afs_AdminInternal.h"
19 #include <afs/afs_AdminErrors.h>
20 #include <afs/afs_utilAdmin.h>
21 #include <afs/kauth.h>
22 #include <afs/kautils.h>
23 #include <afs/kaport.h>
24 #include <pthread.h>
25
26 #undef ENCRYPT
27
28 extern int ubik_Call();
29 extern int ubik_Call_New();
30 extern int ubik_CallIter();
31
32 typedef struct {
33     int begin_magic;
34     int is_valid;
35     struct ubik_client *servers;
36     char *cell;
37     int end_magic;
38 } kas_server_t, *kas_server_p;
39
40 /*
41  * IsValidServerHandle - verify the validity of a kas_server_t handle.
42  *
43  * PARAMETERS
44  *
45  * IN serverHandle - the handle to be verified.
46  *
47  * LOCKS
48  *
49  * No locks are obtained or released by this function
50  *
51  * RETURN CODES
52  *
53  * Returns != 0 upon successful completion.
54  */
55  
56 static int IsValidServerHandle(
57   const kas_server_p serverHandle,
58   afs_status_p st)
59 {
60     int rc = 0;
61     afs_status_t tst = 0;
62
63     /*
64      * Validate input parameters
65      */
66
67     if (serverHandle == NULL) {
68         tst = ADMKASSERVERHANDLENULL;
69         goto fail_IsValidServerHandle;
70     }
71
72     if ((serverHandle->begin_magic != BEGIN_MAGIC) || 
73         (serverHandle->end_magic != END_MAGIC)) {
74         tst = ADMKASSERVERHANDLEBADMAGIC;
75         goto fail_IsValidServerHandle;
76     }
77
78     if (!serverHandle->is_valid) {
79         tst = ADMKASSERVERHANDLENOTVALID;
80         goto fail_IsValidServerHandle;
81     }
82
83     if (serverHandle->servers == NULL) {
84         tst = ADMKASSERVERHANDLENOSERVERS;
85         goto fail_IsValidServerHandle;
86     }
87     rc = 1;
88
89 fail_IsValidServerHandle:
90
91     if (st != NULL) {
92         *st = tst;
93     }
94     return rc;
95 }
96
97 /*
98  * IsValidCellHandle - verify the validity of a afs_cell_handle_t handle
99  * for doing kas related functions.
100  *
101  * PARAMETERS
102  *
103  * IN cellHandle - the handle to be verified.
104  *
105  * LOCKS
106  *
107  * No locks are obtained or released by this function
108  *
109  * RETURN CODES
110  *
111  * Returns != 0 upon successful completion.
112  */
113  
114 static int IsValidCellHandle(
115   const afs_cell_handle_p cellHandle,
116   afs_status_p st)
117 {
118     int rc = 0;
119     afs_status_t tst = 0;
120
121     /*
122      * Validate input parameters
123      */
124
125     if (!CellHandleIsValid((void *) cellHandle, &tst)) {
126         goto fail_IsValidCellHandle;
127     }
128
129     if (!cellHandle->kas_valid) {
130         tst = ADMCLIENTCELLKASINVALID;
131         goto fail_IsValidCellHandle;
132     }
133
134     if (cellHandle->kas == NULL) {
135         tst = ADMCLIENTCELLKASNULL;
136         goto fail_IsValidCellHandle;
137     }
138     rc = 1;
139
140 fail_IsValidCellHandle:
141
142     if (st != NULL) {
143         *st = tst;
144     }
145     return rc;
146 }
147
148 /*
149  * For all kas admin functions that take a cellHandle and a serverHandle,
150  * the intention is that is the cellHandle is not NULL, we should use
151  * it.  Otherwise, we use the serverHandle.  It is an error for both
152  * of these parameters to be non-NULL.
153  */
154
155 /*
156  * ChooseValidServer - given a serverHandle and a cellHandle, choose the
157  * one that is non-NULL, validate it, and return a ubik_client structure
158  * that contains it.
159  *
160  * PARAMETERS
161  *
162  * IN cellHandle - the cell where kas calls are to be made
163  *
164  * IN serverHandle - the group of server(s) that should be used to satisfy
165  * kas calls.
166  *
167  * LOCKS
168  *
169  * No locks are obtained or released by this function
170  *
171  * RETURN CODES
172  *
173  * Returns != 0 upon successful completion.
174  */
175  
176 static int ChooseValidServer(
177   const afs_cell_handle_p cellHandle,
178   const kas_server_p serverHandle,
179   kas_server_p kasHandle,
180   afs_status_p st)
181 {
182     int rc = 0;
183     afs_status_t tst = 0;
184
185     /*
186      * Validate input parameters
187      */
188
189     if (kasHandle == NULL) {
190         tst = ADMKASKASHANDLENULL;
191         goto fail_ChooseValidServer;
192     }
193
194     /*
195      * Only one of the input handle parameters to this function should
196      * not be NULL
197      */
198     if ((cellHandle == NULL) && (serverHandle == NULL)) {
199         tst = ADMKASCELLHANDLEANDSERVERHANDLENULL;
200         goto fail_ChooseValidServer;
201     }
202
203     if ((cellHandle != NULL) && (serverHandle != NULL)) {
204         tst = ADMKASCELLHANDLEANDSERVERHANDLENOTNULL;
205         goto fail_ChooseValidServer;
206     }
207
208     /*
209      * Validate the non-NULL handle
210      */
211
212     if (cellHandle != NULL) {
213         if (IsValidCellHandle(cellHandle, &tst)) {
214             kasHandle->servers = cellHandle->kas;
215             kasHandle->cell = cellHandle->working_cell;
216         } else {
217             goto fail_ChooseValidServer;
218         }
219     } else {
220         if (IsValidServerHandle(serverHandle, &tst)) {
221             kasHandle->servers = serverHandle->servers;
222             kasHandle->cell = serverHandle->cell;
223         } else {
224             goto fail_ChooseValidServer;
225         }
226     }
227
228     kasHandle->begin_magic = BEGIN_MAGIC;
229     kasHandle->end_magic = END_MAGIC;
230     kasHandle->is_valid = 1;
231     rc = 1;
232
233 fail_ChooseValidServer:
234
235     if (st != NULL) {
236         *st = tst;
237     }
238     return rc;
239 }
240
241
242 static int kaentryinfo_to_kas_principalEntry_t(
243   struct kaentryinfo *from,
244   kas_principalEntry_p to,
245   afs_status_p st)
246 {
247     int rc = 0;
248     afs_status_t tst = 0;
249     int short reuse;
250     unsigned char misc_stuff[4];
251
252     if (from == NULL) {
253         tst = ADMKASFROMNULL;
254         goto fail_kaentryinfo_to_kas_principalEntry_t;
255     }
256
257     if (to == NULL) {
258         tst = ADMKASTONULL;
259         goto fail_kaentryinfo_to_kas_principalEntry_t;
260     }
261
262     if (from->flags & KAFADMIN) {
263         to->adminSetting = KAS_ADMIN;
264     } else {
265         to->adminSetting = NO_KAS_ADMIN;
266     }
267
268     if (from->flags & KAFNOTGS) {
269         to->tgsSetting = NO_TGS;
270     } else {
271         to->tgsSetting = TGS;
272     }
273
274     if (from->flags & KAFNOSEAL) {
275         to->encSetting = NO_ENCRYPT;
276     } else {
277         to->encSetting = ENCRYPT;
278     }
279
280     if (from->flags & KAFNOCPW) {
281         to->cpwSetting = NO_CHANGE_PASSWORD;
282     } else {
283         to->cpwSetting = CHANGE_PASSWORD;
284     }
285
286     reuse = (short) from->reserved3;
287     if (!reuse) {
288         to->rpwSetting = REUSE_PASSWORD;
289     } else {
290         to->rpwSetting = NO_REUSE_PASSWORD;
291     }
292
293
294     if (from->user_expiration == NEVERDATE) {
295         to->userExpiration = 0;
296     } else {
297         to->userExpiration = from->user_expiration;
298     }
299     
300     to->lastModTime = from->modification_time;
301     strcpy(to->lastModPrincipal.principal, from->modification_user.name);
302     strcpy(to->lastModPrincipal.instance, from->modification_user.instance);
303     to->lastChangePasswordTime = from->change_password_time;
304     to->maxTicketLifetime = from->max_ticket_lifetime;
305     to->keyVersion = from->key_version;
306     memcpy(&to->key, &from->key, sizeof(to->key));
307     to->keyCheckSum = from->keyCheckSum;
308
309     unpack_long(from->misc_auth_bytes, misc_stuff);
310     to->daysToPasswordExpire = misc_stuff[0];
311     to->failLoginCount = misc_stuff[2];
312     to->lockTime = misc_stuff[3] << 9;
313     rc = 1;
314
315 fail_kaentryinfo_to_kas_principalEntry_t:
316
317     if (st != NULL) {
318         *st = tst;
319     }
320     return rc;
321 }
322
323 /*
324  * kas_ServerOpen - open a handle to a set of kaserver's.
325  *
326  * PARAMETERS
327  *
328  * IN cellHandle - a previously opened cellHandle that corresponds
329  * to the cell where the server(s) live.
330  *
331  * IN serverList - a NULL terminated list (a la argv) of server's that 
332  * should be opened.
333  *
334  * OUT serverHandleP - a pointer to a void pointer that upon successful
335  * completion contains serverHandle that can be used in other kas functions.
336  *
337  * LOCKS
338  *
339  * No locks are obtained or released by this function
340  *
341  * RETURN CODES
342  *
343  * Returns != 0 upon successful completion.
344  * 
345  * ASSUMPTIONS
346  * 
347  * This function make some assumptions about the afsconf_cell used by 
348  * ka_AuthSpecificServersConn (since I just wrote ka_AuthSpecificServersConn).
349  * It only fills in the fields that are required.
350  *
351  * Also we assume that the servers listed are members of the cell in
352  * cellHandle without verifying that this is in fact the case.  kas itself
353  * always assumes that the -servers parameter lists servers in the current
354  * cell without verifying, so I am no worse than the current
355  * implementation.  In fact I'm actually a little more flexible since you
356  * can actually use my serverList to play with servers in another cell.
357  * You can't do that with kas.  For certain functions in kas the same
358  * cell assumption can cause things to fail (the ka_StringToKey function in
359  * UserCreate).
360  */
361  
362 int ADMINAPI kas_ServerOpen(
363   const void *cellHandle,
364   const char **serverList,
365   void **serverHandleP,
366   afs_status_p st)
367 {
368     int rc = 0;
369     afs_status_t tst = 0;
370     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
371     int server_count=0, server_addr;
372     struct afsconf_cell server_info;
373     kas_server_p k_handle = (kas_server_p) malloc (sizeof(kas_server_t));
374
375     /*
376      * Validate input parameters
377      */
378
379     if (c_handle == NULL) {
380         tst = ADMCLIENTCELLHANDLENULL;
381         goto fail_kas_ServerOpen;
382     }
383
384     if (c_handle->kas_valid == 0) {
385         tst = ADMCLIENTCELLKASINVALID;
386         goto fail_kas_ServerOpen;
387     }
388
389     if (serverList == NULL) {
390         tst = ADMKASSERVERLISTNULL;
391         goto fail_kas_ServerOpen;
392     }
393
394     if (serverHandleP == NULL) {
395         tst = ADMKASSERVERHANDLEPNULL;
396         goto fail_kas_ServerOpen;
397     }
398
399     if (k_handle == NULL) {
400         tst = ADMNOMEM;
401         goto fail_kas_ServerOpen;
402     }
403
404     k_handle->begin_magic = BEGIN_MAGIC;
405     k_handle->end_magic = END_MAGIC;
406     k_handle->is_valid = 0;
407     k_handle->servers = NULL;
408
409     /*
410      * Convert serverList to numeric addresses
411      */
412
413     for(server_count=0; serverList[server_count] != NULL; server_count++) {
414         if (server_count >= MAXHOSTSPERCELL) {
415             tst = ADMKASSERVERLISTTOOLONG;
416             goto fail_kas_ServerOpen;
417         }
418         if (util_AdminServerAddressGetFromName(serverList[server_count],&server_addr,&tst)) {
419             server_info.hostAddr[server_count].sin_addr.s_addr = htonl(server_addr);
420             server_info.hostAddr[server_count].sin_port = htons(AFSCONF_KAUTHPORT);
421         } else {
422             goto fail_kas_ServerOpen;
423         }
424     }
425
426     if (server_count == 0) {
427         tst = ADMKASSERVERLISTEMPTY;
428         goto fail_kas_ServerOpen;
429     }
430
431     /*
432      * Get a ubik_client handle for the specified servers
433      */
434     server_info.numServers = server_count;
435     if (!(tst = ka_AuthSpecificServersConn(KA_MAINTENANCE_SERVICE, &c_handle->tokens->kas_token, &server_info, &k_handle->servers))) {
436         k_handle->is_valid = 1;
437         k_handle->cell = c_handle->working_cell;
438         *serverHandleP = (void *) k_handle;
439     } else {
440         goto fail_kas_ServerOpen;
441     }
442     rc = 1;
443
444 fail_kas_ServerOpen:
445
446     if ((rc == 0) && (k_handle != NULL)) {
447         free(k_handle);
448     }
449
450     if (st != NULL) {
451         *st = tst;
452     }
453     return rc;
454 }
455  
456 /*
457  * kas_ServerClose - close a serverHandle.
458  *
459  * PARAMETERS
460  *
461  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
462  *
463  * LOCKS
464  *
465  * No locks are obtained or released by this function
466  *
467  * RETURN CODES
468  *
469  * Returns != 0 upon successful completion.
470  */
471  
472 int ADMINAPI kas_ServerClose(
473   const void *serverHandle,
474   afs_status_p st)
475 {
476     int rc = 0;
477     afs_status_t tst = 0;
478     kas_server_p k_handle = (kas_server_p) serverHandle;
479  
480     if (!IsValidServerHandle(k_handle, &tst)) {
481         goto fail_kas_ServerClose;
482     }
483
484     tst = ubik_ClientDestroy(k_handle->servers);
485     if (tst) {
486         goto fail_kas_ServerClose;
487     }
488
489     k_handle->is_valid = 0;
490     free(k_handle);
491     rc = 1;
492
493 fail_kas_ServerClose:
494
495     if (st != NULL) {
496         *st = tst;
497     }
498     return rc;
499 }
500
501 /*
502  * kas_PrincipalCreate - create a new principal.
503  *
504  * PARAMETERS
505  *
506  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
507  *
508  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
509  *
510  * IN who - a kas_identity_p containing the identity of the new principal
511  * to be created.
512  *
513  * IN password - the new principal's initial password.
514  *
515  * LOCKS
516  *
517  * No locks are obtained or released by this function
518  *
519  * RETURN CODES
520  *
521  * Returns != 0 upon successful completion.
522  */
523  
524 int ADMINAPI kas_PrincipalCreate(
525   const void *cellHandle,
526   const void *serverHandle,
527   const kas_identity_p who,
528   const char *password,
529   afs_status_p st)
530 {
531     int rc = 0;
532     afs_status_t tst = 0;
533     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
534     kas_server_p k_handle = (kas_server_p) serverHandle;
535     kas_server_t kaserver;
536     struct kas_encryptionKey key;
537  
538     /*
539      * Validate input arguments and make rpc.
540      */
541
542     if (who == NULL) {
543         tst = ADMKASWHONULL;
544         goto fail_kas_PrincipalCreate;
545     }
546
547     if (password == NULL) {
548         tst = ADMKASPASSWORDNULL;
549         goto fail_kas_PrincipalCreate;
550     }
551
552     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
553         goto fail_kas_PrincipalCreate;
554     }
555
556     if (!kas_StringToKey(kaserver.cell, password, &key, &tst)) {
557         goto fail_kas_PrincipalCreate;
558     }
559
560     tst = ubik_Call(KAM_CreateUser, kaserver.servers, 0,
561                     who->principal, who->instance, key);
562     if (tst) {
563         goto fail_kas_PrincipalCreate;
564     }
565     rc = 1;
566
567
568 fail_kas_PrincipalCreate:
569
570     if (st != NULL) {
571         *st = tst;
572     }
573     return rc;
574 }
575
576 /*
577  * kas_PrincipalDelete - delete an existing principal.
578  *
579  * PARAMETERS
580  *
581  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
582  *
583  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
584  *
585  * IN who - a kas_identity_p containing the identity of the principal
586  * to be deleted.
587  *
588  * LOCKS
589  *
590  * No locks are obtained or released by this function
591  *
592  * RETURN CODES
593  *
594  * Returns != 0 upon successful completion.
595  */
596  
597 int ADMINAPI kas_PrincipalDelete(
598   const void *cellHandle,
599   const void *serverHandle,
600   const kas_identity_p who,
601   afs_status_p st)
602 {
603     int rc = 0;
604     afs_status_t tst = 0;
605     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
606     kas_server_p k_handle = (kas_server_p) serverHandle;
607     kas_server_t kaserver;
608  
609     /*
610      * Validate input arguments and make rpc.
611      */
612
613     if (who == NULL) {
614         tst = ADMKASWHONULL;
615         goto fail_kas_PrincipalDelete;
616     }
617
618     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
619         goto fail_kas_PrincipalDelete;
620     }
621     tst = ubik_Call(KAM_DeleteUser, kaserver.servers, 0,
622                     who->principal, who->instance);
623     if (tst) {
624         goto fail_kas_PrincipalDelete;
625     }
626     rc = 1;
627
628 fail_kas_PrincipalDelete:
629
630     if (st != NULL) {
631         *st = tst;
632     }
633     return rc;
634 }
635
636 /*
637  * GetPrincipalLockStatus - get the lock status of a principal.
638  *
639  * PARAMETERS
640  *
641  * IN kaserver - a valid kaserver handle previously returned by 
642  * ChooseValidServer
643  *
644  * IN who - a kas_identity_p containing the identity of the principal
645  * to be queried.
646  *
647  * OUT lockedUntil - the remaining number of seconds the principal is locked.
648  *
649  * LOCKS
650  *
651  * No locks are obtained or released by this function
652  *
653  * RETURN CODES
654  *
655  * Returns != 0 upon successful completion.
656  */
657  
658 static int GetPrincipalLockStatus(
659   const kas_server_p kaserver,
660   const kas_identity_p who,
661   unsigned int *lockedUntil,
662   afs_status_p st)
663 {
664     int rc = 0;
665     afs_status_t tst = 0;
666     unsigned int locked;
667     int count=0;
668  
669     /*
670      * Validate input arguments and make rpc.
671      */
672
673     if (kaserver == NULL) {
674         tst = ADMKASKASERVERNULL;
675         goto fail_GetPrincipalLockStatus;
676     }
677
678     if (who == NULL) {
679         tst = ADMKASWHONULL;
680         goto fail_GetPrincipalLockStatus;
681     }
682
683     if (lockedUntil == NULL) {
684         tst = ADMKASLOCKEDUNTILNULL;
685         goto fail_GetPrincipalLockStatus;
686     }
687
688     /*
689      * Unlike every other kas rpc we make here, the lock/unlock rpc's
690      * aren't ubik based.  So instead of calling ubik_Call, we use
691      * ubik_CallIter.  ubik_CallIter steps through the list of hosts
692      * in the ubik_client and calls them one at a time.  Since there's
693      * no synchronization of this data across the servers we have to 
694      * manually keep track of the shortest time to unlock the user ourselves.
695      *
696      * The original inspiration for this function is ka_islocked
697      * in admin_tools.c.  I think that function is totally bogus so I'm
698      * rewriting it here.
699      *
700      * This function should contact all the kaservers and request the lock
701      * status of the principal.  If any of the servers say the principal is
702      * unlocked, we report it as unlocked.  If all the servers say the
703      * principal is locked, we find the server with the shortest lock time
704      * remaining on the principal and return that time.
705      *
706      * This is different than kas, but I think kas is buggy.
707      */
708
709     *lockedUntil = 0;
710     do {
711         locked = 0;
712         tst = ubik_CallIter(KAM_LockStatus, kaserver->servers, UPUBIKONLY,
713                             &count, who->principal, who->instance,
714                             &locked, 0, 0, 0, 0);
715         if (tst == 0) {
716             if (locked) {
717                 if (locked < *lockedUntil) {
718                     *lockedUntil = locked;
719                 }
720             }
721         }
722     } while ((tst != UNOSERVERS) && (locked != 0));
723
724     /*
725      * Check to see if any server reported this principal unlocked.
726      */
727
728     if ((tst == 0) && (locked == 0)) {
729         *lockedUntil = 0;
730     }
731     if (tst == 0) {
732         rc = 1;
733     }
734
735 fail_GetPrincipalLockStatus:
736
737     if (st != NULL) {
738         *st = tst;
739     }
740     return rc;
741 }
742
743 /*
744  * kas_PrincipalGet - retrieve information about a single principal.
745  *
746  * PARAMETERS
747  *
748  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
749  *
750  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
751  *
752  * IN who - a kas_identity_p containing the identity of the principal
753  * to be retrieved.
754  *
755  * OUT principal - upon successful completion contains information
756  * about who.
757  *
758  * LOCKS
759  *
760  * No locks are obtained or released by this function
761  *
762  * RETURN CODES
763  *
764  * Returns != 0 upon successful completion.
765  */
766  
767 int ADMINAPI kas_PrincipalGet(
768   const void *cellHandle,
769   const void *serverHandle,
770   const kas_identity_p who,
771   kas_principalEntry_p principal,
772   afs_status_p st)
773 {
774     int rc = 0;
775     afs_status_t tst = 0;
776     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
777     kas_server_p k_handle = (kas_server_p) serverHandle;
778     kas_server_t kaserver;
779     struct kaentryinfo entry;
780  
781     /*
782      * Validate input arguments and make rpc.
783      */
784
785     if (who == NULL) {
786         tst = ADMKASWHONULL;
787         goto fail_kas_PrincipalGet;
788     }
789
790     if (principal == NULL) {
791         tst = ADMKASPRINCIPALNULL;
792         goto fail_kas_PrincipalGet;
793     }
794
795     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
796         goto fail_kas_PrincipalGet;
797     }
798
799     tst = ubik_Call(KAM_GetEntry, kaserver.servers, 0,
800                     who->principal, who->instance, KAMAJORVERSION, &entry);
801     if (tst) {
802         goto fail_kas_PrincipalGet;
803     }
804
805     /*
806      * copy the kaentryinfo structure to our kas_principalEntry_t
807      * format
808      */
809     if (!kaentryinfo_to_kas_principalEntry_t(&entry, principal, &tst)) {
810         goto fail_kas_PrincipalGet;
811     }
812     rc = 1;
813
814 fail_kas_PrincipalGet:
815
816     if (st != NULL) {
817         *st = tst;
818     }
819     return rc;
820 }
821
822 typedef struct principal_get {
823     int current;
824     int next;
825     int count;
826     kas_server_t kaserver;
827     kas_identity_t principal[CACHED_ITEMS];
828 } principal_get_t, *principal_get_p;
829
830 static int DeletePrincipalSpecificData(
831     void *rpc_specific,
832     afs_status_p st)
833 {
834     int rc = 0;
835     afs_status_t tst = 0;
836     principal_get_p prin = (principal_get_p) rpc_specific;
837
838     prin->kaserver.is_valid = 0;
839     rc = 1;
840
841     if (st != NULL) {
842         *st = tst;
843     }
844     return rc;
845 }
846
847 static int GetPrincipalRPC(
848     void *rpc_specific,
849     int slot,
850     int *last_item,
851     int *last_item_contains_data,
852     afs_status_p st)
853 {
854     int rc = 0;
855     afs_status_t tst = 0;
856     principal_get_p prin = (principal_get_p) rpc_specific;
857
858     tst = ubik_Call(KAM_ListEntry, prin->kaserver.servers, 0,
859                     prin->current, &prin->next, &prin->count,
860                     &prin->principal[slot]);
861     if (tst == 0) {
862         prin->current = prin->next;
863         if (prin->next == 0) {
864             *last_item = 1;
865             *last_item_contains_data = 0;
866         }
867         rc = 1;
868     }
869
870     if (st != NULL) {
871         *st = tst;
872     }
873     return rc;
874 }
875
876 static int GetPrincipalFromCache(
877     void *rpc_specific,
878     int slot,
879     void *dest,
880     afs_status_p st)
881 {
882     int rc = 0;
883     afs_status_t tst = 0;
884     principal_get_p prin = (principal_get_p) rpc_specific;
885
886     memcpy(dest, &prin->principal[slot], sizeof(kas_identity_t));
887     rc = 1;
888
889     if (st != NULL) {
890         *st = tst;
891     }
892     return rc;
893 }
894
895 /*
896  * kas_PrincipalGetBegin - start the process of iterating over the entire
897  * kas database.
898  *
899  * PARAMETERS
900  *
901  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
902  *
903  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
904  *
905  * OUT iterationIdP - upon successful completion contains a iterator that
906  * can be passed to kas_PrincipalGetNext.
907  *
908  * LOCKS
909  *
910  * No locks are obtained or released by this function
911  *
912  * RETURN CODES
913  *
914  * Returns != 0 upon successful completion.
915  *
916  * ASSUMPTIONS
917  */
918  
919 int ADMINAPI kas_PrincipalGetBegin(
920   const void *cellHandle,
921   const void *serverHandle,
922   void **iterationIdP,
923   afs_status_p st)
924 {
925     int rc = 0;
926     afs_status_t tst = 0;
927     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
928     kas_server_p k_handle = (kas_server_p) serverHandle;
929     afs_admin_iterator_p iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
930     principal_get_p principal = (principal_get_p) malloc(sizeof(principal_get_t));
931  
932     /*
933      * Validate arguments
934      */
935
936     if (iter == NULL) {
937         tst = ADMNOMEM;
938         goto fail_kas_PrincipalGetBegin;
939     }
940
941     if (principal == NULL) {
942         tst = ADMNOMEM;
943         goto fail_kas_PrincipalGetBegin;
944     }
945
946     if (iterationIdP == NULL) {
947         tst = ADMITERATIONIDPNULL;
948         goto fail_kas_PrincipalGetBegin;
949     }
950
951     if (!ChooseValidServer(c_handle, k_handle, &principal->kaserver, &tst)) {
952         goto fail_kas_PrincipalGetBegin;
953     }
954
955     /*
956      * Initialize the iterator structure
957      */
958
959     principal->current = 0;
960     principal->next = 0;
961     principal->count = 0;
962     if (IteratorInit(iter, (void *) principal, GetPrincipalRPC,
963                      GetPrincipalFromCache, NULL,
964                      DeletePrincipalSpecificData, &tst)) {
965         *iterationIdP = (void *) iter;
966         rc = 1;
967     }
968
969 fail_kas_PrincipalGetBegin:
970
971     if (rc == 0) {
972         if (iter != NULL) {
973             free(iter);
974         }
975         if (principal != NULL) {
976             free(principal);
977         }
978     }
979
980     if (st != NULL) {
981         *st = tst;
982     }
983     return rc;
984 }
985
986 /*
987  * kas_PrincipalGetNext - retrieve the next principal from the kaserver.
988  *
989  * PARAMETERS
990  *
991  * IN iterationId - an iterator previously returned by kas_PrincipalGetBegin
992  *
993  * OUT who - upon successful completion contains the next principal from the
994  * kaserver
995  *
996  * LOCKS
997  *
998  * Hold the iterator mutex across the call to the kaserver.
999  *
1000  * RETURN CODES
1001  *
1002  * Returns != 0 upon successful completion.
1003  * Returns 0 and st == ADMITERATORDONE when the last entry is returned.
1004  */
1005  
1006 int ADMINAPI kas_PrincipalGetNext(
1007   const void *iterationId,
1008   kas_identity_p who,
1009   afs_status_p st)
1010 {
1011     int rc = 0;
1012     afs_status_t tst = 0;
1013     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1014  
1015     /*
1016      * Validate arguments
1017      */
1018
1019     if (who == NULL) {
1020         tst = ADMKASWHONULL;
1021         goto fail_kas_PrincipalGetNext;
1022     }
1023
1024     if (iter == NULL) {
1025         tst = ADMITERATORNULL;
1026         goto fail_kas_PrincipalGetNext;
1027     }
1028
1029     rc = IteratorNext(iter, (void *) who, &tst);
1030
1031 fail_kas_PrincipalGetNext:
1032
1033     if (st != NULL) {
1034         *st = tst;
1035     }
1036     return rc;
1037 }
1038
1039 /*
1040  * kas_PrincipalGetDone - finish using a principal iterator
1041  *
1042  * PARAMETERS
1043  *
1044  * IN iterationId - an iterator previously returned by kas_PrincipalGetBegin
1045  *
1046  * LOCKS
1047  *
1048  * No locks are held by this function.
1049  *
1050  * RETURN CODES
1051  *
1052  * Returns != 0 upon successful completion.
1053  *
1054  * ASSUMPTIONS
1055  *
1056  * It is the user's responsibility to make sure kas_PrincipalGetDone
1057  * is called only once for each iterator.
1058  */
1059  
1060 int ADMINAPI kas_PrincipalGetDone(
1061   const void *iterationIdP,
1062   afs_status_p st)
1063 {
1064     int rc = 0;
1065     afs_status_t tst = 0;
1066     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationIdP;
1067  
1068     /*
1069      * Validate argument
1070      */
1071
1072     if (iter == NULL) {
1073         tst = ADMITERATORNULL;
1074         goto fail_kas_PrincipalGetDone;
1075     }
1076
1077     rc = IteratorDone(iter, &tst);
1078
1079 fail_kas_PrincipalGetDone:
1080  
1081     if (st != NULL) {
1082         *st = tst;
1083     }
1084     return rc;
1085 }
1086
1087 /*
1088  * kas_PrincipalKeySet - set a principal's password to a known value.
1089  *
1090  * PARAMETERS
1091  *
1092  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1093  *
1094  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1095  *
1096  * IN who - the principal for whom the password is being set.
1097  *
1098  * IN keyVersion - the version number of the new key.
1099  *
1100  * IN key - the new password.
1101  *
1102  * LOCKS
1103  *
1104  * No locks are held by this function.
1105  *
1106  * RETURN CODES
1107  *
1108  * Returns != 0 upon successful completion.
1109  */
1110  
1111 int ADMINAPI kas_PrincipalKeySet(
1112   const void *cellHandle,
1113   const void *serverHandle,
1114   const kas_identity_p who,
1115   int keyVersion,
1116   const kas_encryptionKey_p key,
1117   afs_status_p st)
1118 {
1119     int rc = 0;
1120     afs_status_t tst = 0;
1121     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1122     kas_server_p k_handle = (kas_server_p) serverHandle;
1123     kas_server_t kaserver;
1124  
1125     /*
1126      * Validate input arguments and make rpc.
1127      */
1128
1129     if (who == NULL) {
1130         tst = ADMKASWHONULL;
1131         goto fail_kas_PrincipalKeySet;
1132     }
1133
1134     if (key == NULL) {
1135         tst = ADMKASKEYNULL;
1136         goto fail_kas_PrincipalKeySet;
1137     }
1138
1139     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1140         goto fail_kas_PrincipalKeySet;
1141     }
1142
1143     tst = ubik_Call(KAM_SetPassword, kaserver.servers, 0,
1144                     who->principal, who->instance, keyVersion, *key);
1145     if (tst) {
1146         goto fail_kas_PrincipalKeySet;
1147     }
1148  
1149 fail_kas_PrincipalKeySet:
1150
1151     if (st != NULL) {
1152         *st = tst;
1153     }
1154     return rc;
1155 }
1156
1157 /*
1158  * kas_PrincipalLockStatusGet - determine a principal's lock status.
1159  *
1160  * PARAMETERS
1161  *
1162  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1163  *
1164  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1165  *
1166  * IN who - the principal whose lock status is being checked.
1167  *
1168  * OUT lock_end_timeP - the number of seconds until the principal is unlocked.
1169  * If 0 => user is unlocked.
1170  *
1171  * LOCKS
1172  *
1173  * No locks are held by this function.
1174  *
1175  * RETURN CODES
1176  *
1177  * Returns != 0 upon successful completion.
1178  *
1179  * ASSUMPTIONS
1180  *
1181  * See the comments in GetPrincipalLockStatus regarding how the locking data
1182  * is kept INconsistently between servers.
1183  */
1184  
1185 int ADMINAPI kas_PrincipalLockStatusGet(
1186   const void *cellHandle,
1187   const void *serverHandle,
1188   const kas_identity_p who,
1189   unsigned int *lock_end_timeP,
1190   afs_status_p st)
1191 {
1192     int rc = 0;
1193     afs_status_t tst = 0;
1194     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1195     kas_server_p k_handle = (kas_server_p) serverHandle;
1196     kas_server_t kaserver;
1197
1198     /*
1199      * Validate input arguments and make rpc.
1200      */
1201
1202     if (who == NULL) {
1203         tst = ADMKASWHONULL;
1204         goto fail_kas_PrincipalLockStatusGet;
1205     }
1206
1207     if (lock_end_timeP == NULL) {
1208         tst = ADMKASLOCKENDTIMEPNULL;
1209         goto fail_kas_PrincipalLockStatusGet;
1210     }
1211
1212     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1213         goto fail_kas_PrincipalLockStatusGet;
1214     }
1215
1216     rc = GetPrincipalLockStatus(&kaserver, who, lock_end_timeP, &tst);
1217  
1218 fail_kas_PrincipalLockStatusGet:
1219
1220     if (st != NULL) {
1221         *st = tst;
1222     }
1223     return rc;
1224 }
1225
1226 /*
1227  * kas_PrincipalUnlock - unlock a principal.
1228  *
1229  * PARAMETERS
1230  *
1231  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1232  *
1233  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1234  *
1235  * IN who - the principal who is being unlocked.
1236  *
1237  * LOCKS
1238  *
1239  * No locks are held by this function.
1240  *
1241  * RETURN CODES
1242  *
1243  * Returns != 0 upon successful completion.
1244  *
1245  * ASSUMPTIONS
1246  *
1247  * See the comments in GetPrincipalLockStatus regarding how the locking data
1248  * is kept INconsistently between servers.
1249  */
1250  
1251 int ADMINAPI kas_PrincipalUnlock(
1252   const void *cellHandle,
1253   const void *serverHandle,
1254   const kas_identity_p who,
1255   afs_status_p st)
1256 {
1257     int rc = 0;
1258     afs_status_t tst = 0;
1259     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1260     kas_server_p k_handle = (kas_server_p) serverHandle;
1261     kas_server_t kaserver;
1262     int count = 0;
1263     afs_status_t save_tst = 0;
1264
1265     /*
1266      * Validate input arguments and make rpc.
1267      */
1268  
1269     if (who == NULL) {
1270         tst = ADMKASWHONULL;
1271         goto fail_kas_PrincipalUnlock;
1272     }
1273
1274     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1275         goto fail_kas_PrincipalUnlock;
1276     }
1277
1278     do {
1279           tst = ubik_CallIter(KAM_Unlock, kaserver.servers, 0,
1280                             &count, who->principal, who->instance,
1281                             0, 0, 0, 0);
1282         if (tst && (tst != UNOSERVERS)) {
1283             if (save_tst == 0) {
1284                 save_tst = tst; /* save the first failure */
1285             }
1286         }
1287     } while (tst != UNOSERVERS);
1288
1289     if (tst == 0) {
1290         rc = 1;
1291     }
1292
1293 fail_kas_PrincipalUnlock:
1294
1295     if (st != NULL) {
1296         *st = tst;
1297     }
1298     return rc;
1299 }
1300  
1301 static int getPrincipalFlags(
1302   const void *cellHandle,
1303   const void *serverHandle,
1304   const kas_identity_p who,
1305   afs_int32 *cur_flags,
1306   afs_status_p st)
1307 {
1308     int rc = 0;
1309     afs_status_t tst = 0;
1310     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1311     kas_server_p k_handle = (kas_server_p) serverHandle;
1312     kas_server_t kaserver;
1313     struct kaentryinfo tentry;
1314
1315     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1316         goto fail_getPrincipalFlags;
1317     }
1318
1319     tst = ubik_Call(KAM_GetEntry, kaserver.servers, 0, who->principal,
1320                     who->instance, KAMAJORVERSION, &tentry);
1321     if (tst == 0) {
1322         *cur_flags = tentry.flags;
1323         rc = 1;
1324     }
1325
1326 fail_getPrincipalFlags:
1327
1328     if (st != NULL) {
1329         *st = tst;
1330     }
1331     return rc;
1332 }
1333
1334 /*
1335  * kas_PrincipalFieldsSet - modify an existing principal.
1336  *
1337  * PARAMETERS
1338  *
1339  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1340  *
1341  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1342  *
1343  * IN who - the principal who is being modified.
1344  *
1345  * IN isAdmin - the admin status of the principal.
1346  *
1347  * IN grantTickets - should the TGS issue tickets for the principal.
1348  *
1349  * IN canEncrypt - should the TGS allow the use of encryption via the 
1350  * principal's key.
1351  *
1352  * IN canChangePassword - should the principal be allowed to change their
1353  * own password?
1354  *
1355  * IN expirationDate - the date when the principal will expire.
1356  *
1357  * IN maxTicketLifetime - the maximum lifetime of a ticket issued for
1358  * the principal.
1359  *
1360  * IN passwordExpires - the maximum number of days a particular
1361  * password can be used.  The limit is 255, 0 => no expiration.
1362  *
1363  * IN passwordReuse - can a password be reused by this principal.
1364  *
1365  * IN failedPasswordAttempts - number of failed login attempts before
1366  * a principal is locked.  The limit is 255, 0 => no limit.
1367  *
1368  * IN failedPasswordLockTime - the number of seconds a principal is
1369  * locked once failedPasswordAttempts is reached.  Some bizarre rounding
1370  * occurs for this value, see kas for more details.
1371  *
1372  * LOCKS
1373  *
1374  * No locks are held by this function.
1375  *
1376  * RETURN CODES
1377  *
1378  * Returns != 0 upon successful completion.
1379  *
1380  * ASSUMPTIONS
1381  *
1382  * See the comments in GetPrincipalLockStatus regarding how the locking data
1383  * is kept INconsistently between servers.
1384  */
1385  
1386 int ADMINAPI kas_PrincipalFieldsSet(
1387   const void *cellHandle,
1388   const void *serverHandle,
1389   const kas_identity_p who,
1390   const kas_admin_p isAdmin,
1391   const kas_tgs_p grantTickets,
1392   const kas_enc_p canEncrypt,
1393   const kas_cpw_p canChangePassword,
1394   const unsigned int *expirationDate,
1395   const unsigned int *maxTicketLifetime,
1396   const unsigned int *passwordExpires,
1397   const kas_rpw_p passwordReuse,
1398   const unsigned int *failedPasswordAttempts,
1399   const unsigned int *failedPasswordLockTime,
1400   afs_status_p st)
1401 {
1402     int rc = 0;
1403     afs_status_t tst = 0;
1404     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1405     kas_server_p k_handle = (kas_server_p) serverHandle;
1406     kas_server_t kaserver;
1407     afs_int32 flags = 0;
1408     Date expiration = 0;
1409     afs_int32 lifetime = 0;
1410     int was_spare;
1411     char spare_bytes[4] = {0,0,0,0};
1412     int somethings_changing = 0;
1413
1414     /*
1415      * Validate input arguments.
1416      */
1417
1418     if (who == NULL) {
1419         tst = ADMKASWHONULL;
1420         goto fail_kas_PrincipalFieldsSet;
1421     }
1422
1423     /*
1424      * set flags based upon input
1425      *
1426      * If we're changing the flags, we need to get the current value of
1427      * the flags first and then make the changes
1428      */
1429
1430     if ((isAdmin != NULL) || (grantTickets != NULL) ||
1431         (canEncrypt != NULL) || (canChangePassword != NULL)) {
1432         if (!getPrincipalFlags(cellHandle, serverHandle, who, &flags,
1433                                &tst)) {
1434             goto fail_kas_PrincipalFieldsSet;
1435         }
1436     }
1437
1438     if (isAdmin != NULL) {
1439         somethings_changing = 1;
1440         if (*isAdmin == KAS_ADMIN) {
1441             flags |= KAFADMIN;
1442         } else {
1443             flags &= ~KAFADMIN;
1444         }
1445     }
1446
1447     if (grantTickets != NULL) {
1448         somethings_changing = 1;
1449         if (*grantTickets == NO_TGS) {
1450             flags |= KAFNOTGS;
1451         } else {
1452             flags &= ~KAFNOTGS;
1453         }
1454     }
1455
1456     if (canEncrypt != NULL) {
1457         somethings_changing = 1;
1458         if (*canEncrypt == NO_ENCRYPT) {
1459             flags |= KAFNOSEAL;
1460         } else {
1461             flags &= ~KAFNOSEAL;
1462         }
1463     }
1464
1465     if (canChangePassword != NULL) {
1466         somethings_changing = 1;
1467         if (*canChangePassword == NO_CHANGE_PASSWORD) {
1468             flags |= KAFNOCPW;
1469         } else {
1470             flags &= ~KAFNOCPW;
1471         }
1472     }
1473
1474     flags = (flags & KAF_SETTABLE_FLAGS) | KAFNORMAL;
1475
1476     if (expirationDate != NULL) {
1477         somethings_changing = 1;
1478         expiration = *expirationDate;
1479     }
1480
1481     if (maxTicketLifetime != NULL) {
1482         somethings_changing = 1;
1483         lifetime = *maxTicketLifetime;
1484     }
1485
1486     if (passwordExpires != NULL) {
1487         if (*passwordExpires > 255) {
1488             tst = ADMKASPASSWORDEXPIRESTOOBIG;
1489             goto fail_kas_PrincipalFieldsSet;
1490         }
1491         somethings_changing = 1;
1492         spare_bytes[0] = *passwordExpires + 1;
1493     }
1494
1495     if (passwordReuse != NULL) {
1496         somethings_changing = 1;
1497         if (*passwordReuse == REUSE_PASSWORD) {
1498             spare_bytes[1] = KA_REUSEPW;
1499         } else {
1500             spare_bytes[1] = KA_NOREUSEPW;
1501         }
1502     }
1503
1504     if (failedPasswordAttempts != NULL) {
1505         if (*failedPasswordAttempts > 255) {
1506             tst = ADMKASFAILEDPASSWORDATTEMPTSTOOBIG;
1507             goto fail_kas_PrincipalFieldsSet;
1508         }
1509         somethings_changing = 1;
1510         spare_bytes[2] = *failedPasswordAttempts + 1;
1511     }
1512
1513     if (failedPasswordLockTime != NULL) {
1514         if (*failedPasswordLockTime > 36*60*60) {
1515             tst = ADMKASFAILEDPASSWORDLOCKTIME;
1516             goto fail_kas_PrincipalFieldsSet;
1517         }
1518         somethings_changing = 1;
1519         spare_bytes[3] = ((*failedPasswordLockTime + 511) >> 9) + 1;
1520     }
1521
1522     was_spare = pack_long(spare_bytes);
1523
1524     if (somethings_changing) {
1525         if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1526             goto fail_kas_PrincipalFieldsSet;
1527         }
1528         tst = ubik_Call(KAM_SetFields, kaserver.servers, 0, who->principal,
1529                         who->instance, flags, expiration, lifetime,
1530                         -1, was_spare, 0);
1531         if (tst == 0) {
1532             rc = 1;
1533         }
1534     } else {
1535         tst = ADMKASPRINCIPALFIELDSNOCHANGE;
1536     }
1537  
1538 fail_kas_PrincipalFieldsSet:
1539
1540     if (st != NULL) {
1541         *st = tst;
1542     }
1543     return rc;
1544 }
1545
1546 /*
1547  * kas_ServerStatsGet - get server statistics.
1548  *
1549  * PARAMETERS
1550  *
1551  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1552  *
1553  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1554  *
1555  * OUT stats - the statistics retrieved.
1556  *
1557  * LOCKS
1558  *
1559  * No locks are held by this function.
1560  *
1561  * RETURN CODES
1562  *
1563  * Returns != 0 upon successful completion.
1564  */
1565  
1566 int ADMINAPI kas_ServerStatsGet(
1567   const void *cellHandle,
1568   const void *serverHandle,
1569   kas_serverStats_p stats,
1570   afs_status_p st)
1571 {
1572     int rc = 0;
1573     afs_status_t tst = 0;
1574     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1575     kas_server_p k_handle = (kas_server_p) serverHandle;
1576     kas_server_t kaserver;
1577     afs_int32 admins;
1578     kasstats statics;
1579     kadstats dynamics;
1580     size_t i;
1581
1582     /*
1583      * Validate input arguments and make rpc.
1584      */
1585
1586     if (stats == NULL) {
1587         tst = ADMKASSTATSNULL;
1588         goto fail_kas_ServerStatsGet;
1589     }
1590
1591     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1592         goto fail_kas_ServerStatsGet;
1593     }
1594
1595     tst = ubik_Call(KAM_GetStats, kaserver.servers, 0, KAMAJORVERSION, &admins, 
1596                     &statics, &dynamics);
1597     if (tst) {
1598         goto fail_kas_ServerStatsGet;
1599     }
1600
1601     stats->allocations = statics.allocs;
1602     stats->frees = statics.frees;
1603     stats->changePasswordRequests = statics.cpws;
1604     stats->adminAccounts = admins;
1605     stats->host = dynamics.host;
1606     stats->serverStartTime = dynamics.start_time;
1607     stats->hashTableUtilization = dynamics.hashTableUtilization;
1608
1609     i = sizeof(kas_serverProcStats_t);
1610     memcpy(&stats->authenticate, &dynamics.Authenticate, i);
1611     memcpy(&stats->changePassword, &dynamics.ChangePassword, i);
1612     memcpy(&stats->getTicket, &dynamics.GetTicket, i);
1613     memcpy(&stats->createUser, &dynamics.CreateUser, i);
1614     memcpy(&stats->setPassword, &dynamics.SetPassword, i);
1615     memcpy(&stats->setFields, &dynamics.SetFields, i);
1616     memcpy(&stats->deleteUser, &dynamics.DeleteUser, i);
1617     memcpy(&stats->getEntry, &dynamics.GetEntry, i);
1618     memcpy(&stats->listEntry, &dynamics.ListEntry, i);
1619     memcpy(&stats->getStats, &dynamics.GetStats, i);
1620     memcpy(&stats->getPassword, &dynamics.GetPassword, i);
1621     memcpy(&stats->getRandomKey, &dynamics.GetRandomKey, i);
1622     memcpy(&stats->debug, &dynamics.Debug, i);
1623     memcpy(&stats->udpAuthenticate, &dynamics.UAuthenticate, i);
1624     memcpy(&stats->udpGetTicket, &dynamics.UGetTicket, i);
1625     memcpy(&stats->unlock, &dynamics.Unlock, i);
1626     memcpy(&stats->lockStatus, &dynamics.LockStatus, i);
1627
1628     stats->stringChecks = dynamics.string_checks;
1629     rc = 1;
1630
1631 fail_kas_ServerStatsGet:
1632
1633     if (st != NULL) {
1634         *st = tst;
1635     }
1636     return rc;
1637 }
1638
1639 /*
1640  * kas_ServerDebugGet - get server debug info.
1641  *
1642  * PARAMETERS
1643  *
1644  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1645  *
1646  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1647  *
1648  * OUT stats - the debug info retrieved.
1649  *
1650  * LOCKS
1651  *
1652  * No locks are held by this function.
1653  *
1654  * RETURN CODES
1655  *
1656  * Returns != 0 upon successful completion.
1657  */
1658  
1659 int ADMINAPI kas_ServerDebugGet(
1660   const void *cellHandle,
1661   const void *serverHandle,
1662   kas_serverDebugInfo_p debug,
1663   afs_status_p st)
1664 {
1665     int rc = 0;
1666     afs_status_t tst = 0;
1667     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1668     kas_server_p k_handle = (kas_server_p) serverHandle;
1669     kas_server_t kaserver;
1670     struct ka_debugInfo info;
1671     int i;
1672  
1673     /*
1674      * Validate input arguments and make rpc.
1675      */
1676
1677     if (debug == NULL) {
1678         tst = ADMKASDEBUGNULL;
1679         goto fail_kas_ServerDebugGet;
1680     }
1681
1682     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1683         goto fail_kas_ServerDebugGet;
1684     }
1685     tst = ubik_Call(KAM_Debug, kaserver.servers, 0, KAMAJORVERSION, 0, &info);
1686     if (tst) {
1687         goto fail_kas_ServerDebugGet;
1688     }
1689     debug->host = info.host;
1690     debug->serverStartTime = info.startTime;
1691     debug->currentTime = info.reserved1;
1692     debug->noAuth = info.noAuth;
1693     debug->lastTransaction = info.lastTrans;
1694     strcpy(debug->lastOperation, info.lastOperation);
1695     strcpy(debug->lastPrincipalAuth, info.lastAuth);
1696     strcpy(debug->lastPrincipalUDPAuth, info.lastUAuth);
1697     strcpy(debug->lastPrincipalTGS, info.lastTGS);
1698     strcpy(debug->lastPrincipalUDPTGS, info.lastUTGS);
1699     strcpy(debug->lastPrincipalAdmin, info.lastAdmin);
1700     strcpy(debug->lastServerTGS, info.lastTGSServer);
1701     strcpy(debug->lastServerUDPTGS, info.lastUTGSServer);
1702     debug->nextAutoCheckPointWrite = info.nextAutoCPW;
1703     debug->updatesRemainingBeforeAutoCheckPointWrite = info.updatesRemaining;
1704     debug->dbHeaderRead = info.dbHeaderRead;
1705     debug->dbVersion = info.dbVersion;
1706     debug->dbFreePtr = info.dbFreePtr;
1707     debug->dbEOFPtr = info.dbEofPtr;
1708     debug->dbKvnoPtr = info.dbKvnoPtr;
1709     debug->dbSpecialKeysVersion = info.dbSpecialKeysVersion;
1710     debug->dbHeaderLock = info.cheader_lock;
1711     debug->keyCacheLock = info.keycache_lock;
1712     debug->keyCacheVersion = info.kcVersion;
1713     debug->keyCacheSize = info.kcSize;
1714     debug->keyCacheUsed = info.kcUsed;
1715     for(i=0;i<info.kcUsed;i++) {
1716         debug->keyCache[i].lastUsed = info.kcInfo[i].used;
1717         debug->keyCache[i].keyVersionNumber = info.kcInfo[i].kvno;
1718         debug->keyCache[i].primary = info.kcInfo[i].primary;
1719         debug->keyCache[i].keyCheckSum = info.kcInfo[i].keycksum;
1720         strcpy(debug->keyCache[i].principal,info.kcInfo[i].principal);
1721     }
1722     rc = 1;
1723
1724 fail_kas_ServerDebugGet:
1725
1726     if (st != NULL) {
1727         *st = tst;
1728     }
1729     return rc;
1730 }
1731
1732 /*
1733  * kas_ServerRandomKeyGet - get a random key from a server.
1734  *
1735  * PARAMETERS
1736  *
1737  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1738  *
1739  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1740  *
1741  * OUT key - a random key.
1742  *
1743  * LOCKS
1744  *
1745  * No locks are held by this function.
1746  *
1747  * RETURN CODES
1748  *
1749  * Returns != 0 upon successful completion.
1750  */
1751  
1752 int ADMINAPI kas_ServerRandomKeyGet(
1753   const void *cellHandle,
1754   const void *serverHandle,
1755   kas_encryptionKey_p key,
1756   afs_status_p st)
1757 {
1758     int rc = 0;
1759     afs_status_t tst = 0;
1760     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1761     kas_server_p k_handle = (kas_server_p) serverHandle;
1762     kas_server_t kaserver;
1763  
1764     /*
1765      * Validate input arguments and make rpc.
1766      */
1767
1768     if (key == NULL) {
1769         tst = ADMKASKEYNULL;
1770         goto fail_kas_ServerRandomKeyGet;
1771     }
1772
1773     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1774         goto fail_kas_ServerRandomKeyGet;
1775     }
1776
1777     tst = ubik_Call(KAM_GetRandomKey, kaserver.servers, 0, key);
1778     if (tst) {
1779         goto fail_kas_ServerRandomKeyGet;
1780     }
1781     rc = 1;
1782
1783 fail_kas_ServerRandomKeyGet:
1784
1785     if (st != NULL) {
1786         *st = tst;
1787     }
1788     return rc;
1789 }
1790
1791 /*
1792  * kas_StringToKey - turn a string key into a key.
1793  *
1794  * PARAMETERS
1795  *
1796  * IN cellName - the name of the cell where the key will be used.
1797  *
1798  * IN string - the string to be converted.
1799  *
1800  * OUT key - the encryption key.
1801  *
1802  * LOCKS
1803  *
1804  * No locks are held by this function.
1805  *
1806  * RETURN CODES
1807  *
1808  * Returns != 0 upon successful completion.
1809  */
1810  
1811 int ADMINAPI kas_StringToKey(
1812   const char *cellName,
1813   const char *string,
1814   kas_encryptionKey_p key,
1815   afs_status_p st)
1816 {
1817     int rc = 0;
1818     afs_status_t tst = 0;
1819  
1820     ka_StringToKey(string, cellName, (struct ktc_encryptionKey *) key);
1821     rc = 1;
1822
1823     if (st != NULL) {
1824         *st = tst;
1825     }
1826     return rc;
1827 }
1828
1829
1830 /*
1831  * kas_KeyCheckSum - compute the checksum of an encryption key.
1832  *
1833  * PARAMETERS
1834  *
1835  * IN key - the encryption key.
1836  *
1837  * OUT cksumP - key checksum
1838  *
1839  * LOCKS
1840  *
1841  * No locks are held by this function.
1842  *
1843  * RETURN CODES
1844  *
1845  * Returns != 0 upon successful completion.
1846  */
1847  
1848 int ADMINAPI kas_KeyCheckSum(
1849   const kas_encryptionKey_p key,
1850   unsigned int *cksumP,
1851   afs_status_p st
1852 ) {
1853     int rc = 0;
1854     afs_status_t tst = 0;
1855     afs_uint32 cksum32;
1856  
1857     if ((tst = ka_KeyCheckSum((char *)key, &cksum32)) == 0) {
1858         *cksumP = cksum32;
1859         rc = 1;
1860     }
1861
1862     if (st != NULL) {
1863         *st = tst;
1864     }
1865     return rc;
1866 }