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