81061b132153a1599a01cafefb7633d9d6f81a09
[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
881     memcpy(dest, &prin->principal[slot], sizeof(kas_identity_t));
882     rc = 1;
883
884     if (st != NULL) {
885         *st = tst;
886     }
887     return rc;
888 }
889
890 /*
891  * kas_PrincipalGetBegin - start the process of iterating over the entire
892  * kas database.
893  *
894  * PARAMETERS
895  *
896  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
897  *
898  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
899  *
900  * OUT iterationIdP - upon successful completion contains a iterator that
901  * can be passed to kas_PrincipalGetNext.
902  *
903  * LOCKS
904  *
905  * No locks are obtained or released by this function
906  *
907  * RETURN CODES
908  *
909  * Returns != 0 upon successful completion.
910  *
911  * ASSUMPTIONS
912  */
913  
914 int ADMINAPI kas_PrincipalGetBegin(
915   const void *cellHandle,
916   const void *serverHandle,
917   void **iterationIdP,
918   afs_status_p st)
919 {
920     int rc = 0;
921     afs_status_t tst = 0;
922     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
923     kas_server_p k_handle = (kas_server_p) serverHandle;
924     afs_admin_iterator_p iter = (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
925     principal_get_p principal = (principal_get_p) malloc(sizeof(principal_get_t));
926  
927     /*
928      * Validate arguments
929      */
930
931     if (iter == NULL) {
932         tst = ADMNOMEM;
933         goto fail_kas_PrincipalGetBegin;
934     }
935
936     if (principal == NULL) {
937         tst = ADMNOMEM;
938         goto fail_kas_PrincipalGetBegin;
939     }
940
941     if (iterationIdP == NULL) {
942         tst = ADMITERATIONIDPNULL;
943         goto fail_kas_PrincipalGetBegin;
944     }
945
946     if (!ChooseValidServer(c_handle, k_handle, &principal->kaserver, &tst)) {
947         goto fail_kas_PrincipalGetBegin;
948     }
949
950     /*
951      * Initialize the iterator structure
952      */
953
954     principal->current = 0;
955     principal->next = 0;
956     principal->count = 0;
957     if (IteratorInit(iter, (void *) principal, GetPrincipalRPC,
958                      GetPrincipalFromCache, NULL,
959                      DeletePrincipalSpecificData, &tst)) {
960         *iterationIdP = (void *) iter;
961         rc = 1;
962     }
963
964 fail_kas_PrincipalGetBegin:
965
966     if (rc == 0) {
967         if (iter != NULL) {
968             free(iter);
969         }
970         if (principal != NULL) {
971             free(principal);
972         }
973     }
974
975     if (st != NULL) {
976         *st = tst;
977     }
978     return rc;
979 }
980
981 /*
982  * kas_PrincipalGetNext - retrieve the next principal from the kaserver.
983  *
984  * PARAMETERS
985  *
986  * IN iterationId - an iterator previously returned by kas_PrincipalGetBegin
987  *
988  * OUT who - upon successful completion contains the next principal from the
989  * kaserver
990  *
991  * LOCKS
992  *
993  * Hold the iterator mutex across the call to the kaserver.
994  *
995  * RETURN CODES
996  *
997  * Returns != 0 upon successful completion.
998  * Returns 0 and st == ADMITERATORDONE when the last entry is returned.
999  */
1000  
1001 int ADMINAPI kas_PrincipalGetNext(
1002   const void *iterationId,
1003   kas_identity_p who,
1004   afs_status_p st)
1005 {
1006     int rc = 0;
1007     afs_status_t tst = 0;
1008     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
1009  
1010     /*
1011      * Validate arguments
1012      */
1013
1014     if (who == NULL) {
1015         tst = ADMKASWHONULL;
1016         goto fail_kas_PrincipalGetNext;
1017     }
1018
1019     if (iter == NULL) {
1020         tst = ADMITERATORNULL;
1021         goto fail_kas_PrincipalGetNext;
1022     }
1023
1024     rc = IteratorNext(iter, (void *) who, &tst);
1025
1026 fail_kas_PrincipalGetNext:
1027
1028     if (st != NULL) {
1029         *st = tst;
1030     }
1031     return rc;
1032 }
1033
1034 /*
1035  * kas_PrincipalGetDone - finish using a principal iterator
1036  *
1037  * PARAMETERS
1038  *
1039  * IN iterationId - an iterator previously returned by kas_PrincipalGetBegin
1040  *
1041  * LOCKS
1042  *
1043  * No locks are held by this function.
1044  *
1045  * RETURN CODES
1046  *
1047  * Returns != 0 upon successful completion.
1048  *
1049  * ASSUMPTIONS
1050  *
1051  * It is the user's responsibility to make sure kas_PrincipalGetDone
1052  * is called only once for each iterator.
1053  */
1054  
1055 int ADMINAPI kas_PrincipalGetDone(
1056   const void *iterationIdP,
1057   afs_status_p st)
1058 {
1059     int rc = 0;
1060     afs_status_t tst = 0;
1061     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationIdP;
1062  
1063     /*
1064      * Validate argument
1065      */
1066
1067     if (iter == NULL) {
1068         tst = ADMITERATORNULL;
1069         goto fail_kas_PrincipalGetDone;
1070     }
1071
1072     rc = IteratorDone(iter, &tst);
1073
1074 fail_kas_PrincipalGetDone:
1075  
1076     if (st != NULL) {
1077         *st = tst;
1078     }
1079     return rc;
1080 }
1081
1082 /*
1083  * kas_PrincipalKeySet - set a principal's password to a known value.
1084  *
1085  * PARAMETERS
1086  *
1087  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1088  *
1089  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1090  *
1091  * IN who - the principal for whom the password is being set.
1092  *
1093  * IN keyVersion - the version number of the new key.
1094  *
1095  * IN key - the new password.
1096  *
1097  * LOCKS
1098  *
1099  * No locks are held by this function.
1100  *
1101  * RETURN CODES
1102  *
1103  * Returns != 0 upon successful completion.
1104  */
1105  
1106 int ADMINAPI kas_PrincipalKeySet(
1107   const void *cellHandle,
1108   const void *serverHandle,
1109   const kas_identity_p who,
1110   int keyVersion,
1111   const kas_encryptionKey_p key,
1112   afs_status_p st)
1113 {
1114     int rc = 0;
1115     afs_status_t tst = 0;
1116     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1117     kas_server_p k_handle = (kas_server_p) serverHandle;
1118     kas_server_t kaserver;
1119  
1120     /*
1121      * Validate input arguments and make rpc.
1122      */
1123
1124     if (who == NULL) {
1125         tst = ADMKASWHONULL;
1126         goto fail_kas_PrincipalKeySet;
1127     }
1128
1129     if (key == NULL) {
1130         tst = ADMKASKEYNULL;
1131         goto fail_kas_PrincipalKeySet;
1132     }
1133
1134     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1135         goto fail_kas_PrincipalKeySet;
1136     }
1137
1138     tst = ubik_Call(KAM_SetPassword, kaserver.servers, 0,
1139                     who->principal, who->instance, keyVersion, *key);
1140     if (tst) {
1141         goto fail_kas_PrincipalKeySet;
1142     }
1143  
1144 fail_kas_PrincipalKeySet:
1145
1146     if (st != NULL) {
1147         *st = tst;
1148     }
1149     return rc;
1150 }
1151
1152 /*
1153  * kas_PrincipalLockStatusGet - determine a principal's lock status.
1154  *
1155  * PARAMETERS
1156  *
1157  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1158  *
1159  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1160  *
1161  * IN who - the principal whose lock status is being checked.
1162  *
1163  * OUT lock_end_timeP - the number of seconds until the principal is unlocked.
1164  * If 0 => user is unlocked.
1165  *
1166  * LOCKS
1167  *
1168  * No locks are held by this function.
1169  *
1170  * RETURN CODES
1171  *
1172  * Returns != 0 upon successful completion.
1173  *
1174  * ASSUMPTIONS
1175  *
1176  * See the comments in GetPrincipalLockStatus regarding how the locking data
1177  * is kept INconsistently between servers.
1178  */
1179  
1180 int ADMINAPI kas_PrincipalLockStatusGet(
1181   const void *cellHandle,
1182   const void *serverHandle,
1183   const kas_identity_p who,
1184   unsigned int *lock_end_timeP,
1185   afs_status_p st)
1186 {
1187     int rc = 0;
1188     afs_status_t tst = 0;
1189     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1190     kas_server_p k_handle = (kas_server_p) serverHandle;
1191     kas_server_t kaserver;
1192
1193     /*
1194      * Validate input arguments and make rpc.
1195      */
1196
1197     if (who == NULL) {
1198         tst = ADMKASWHONULL;
1199         goto fail_kas_PrincipalLockStatusGet;
1200     }
1201
1202     if (lock_end_timeP == NULL) {
1203         tst = ADMKASLOCKENDTIMEPNULL;
1204         goto fail_kas_PrincipalLockStatusGet;
1205     }
1206
1207     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1208         goto fail_kas_PrincipalLockStatusGet;
1209     }
1210
1211     rc = GetPrincipalLockStatus(&kaserver, who, lock_end_timeP, &tst);
1212  
1213 fail_kas_PrincipalLockStatusGet:
1214
1215     if (st != NULL) {
1216         *st = tst;
1217     }
1218     return rc;
1219 }
1220
1221 /*
1222  * kas_PrincipalUnlock - unlock a principal.
1223  *
1224  * PARAMETERS
1225  *
1226  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1227  *
1228  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1229  *
1230  * IN who - the principal who is being unlocked.
1231  *
1232  * LOCKS
1233  *
1234  * No locks are held by this function.
1235  *
1236  * RETURN CODES
1237  *
1238  * Returns != 0 upon successful completion.
1239  *
1240  * ASSUMPTIONS
1241  *
1242  * See the comments in GetPrincipalLockStatus regarding how the locking data
1243  * is kept INconsistently between servers.
1244  */
1245  
1246 int ADMINAPI kas_PrincipalUnlock(
1247   const void *cellHandle,
1248   const void *serverHandle,
1249   const kas_identity_p who,
1250   afs_status_p st)
1251 {
1252     int rc = 0;
1253     afs_status_t tst = 0;
1254     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1255     kas_server_p k_handle = (kas_server_p) serverHandle;
1256     kas_server_t kaserver;
1257     int count = 0;
1258     afs_status_t save_tst = 0;
1259
1260     /*
1261      * Validate input arguments and make rpc.
1262      */
1263  
1264     if (who == NULL) {
1265         tst = ADMKASWHONULL;
1266         goto fail_kas_PrincipalUnlock;
1267     }
1268
1269     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1270         goto fail_kas_PrincipalUnlock;
1271     }
1272
1273     do {
1274           tst = ubik_CallIter(KAM_Unlock, kaserver.servers, 0,
1275                             &count, who->principal, who->instance,
1276                             0, 0, 0, 0);
1277         if (tst && (tst != UNOSERVERS)) {
1278             if (save_tst == 0) {
1279                 save_tst = tst; /* save the first failure */
1280             }
1281         }
1282     } while (tst != UNOSERVERS);
1283
1284     if (tst == 0) {
1285         rc = 1;
1286     }
1287
1288 fail_kas_PrincipalUnlock:
1289
1290     if (st != NULL) {
1291         *st = tst;
1292     }
1293     return rc;
1294 }
1295  
1296 static int getPrincipalFlags(
1297   const void *cellHandle,
1298   const void *serverHandle,
1299   const kas_identity_p who,
1300   afs_int32 *cur_flags,
1301   afs_status_p st)
1302 {
1303     int rc = 0;
1304     afs_status_t tst = 0;
1305     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1306     kas_server_p k_handle = (kas_server_p) serverHandle;
1307     kas_server_t kaserver;
1308     struct kaentryinfo tentry;
1309
1310     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1311         goto fail_getPrincipalFlags;
1312     }
1313
1314     tst = ubik_Call(KAM_GetEntry, kaserver.servers, 0, who->principal,
1315                     who->instance, KAMAJORVERSION, &tentry);
1316     if (tst == 0) {
1317         *cur_flags = tentry.flags;
1318         rc = 1;
1319     }
1320
1321 fail_getPrincipalFlags:
1322
1323     if (st != NULL) {
1324         *st = tst;
1325     }
1326     return rc;
1327 }
1328
1329 /*
1330  * kas_PrincipalFieldsSet - modify an existing principal.
1331  *
1332  * PARAMETERS
1333  *
1334  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1335  *
1336  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1337  *
1338  * IN who - the principal who is being modified.
1339  *
1340  * IN isAdmin - the admin status of the principal.
1341  *
1342  * IN grantTickets - should the TGS issue tickets for the principal.
1343  *
1344  * IN canEncrypt - should the TGS allow the use of encryption via the 
1345  * principal's key.
1346  *
1347  * IN canChangePassword - should the principal be allowed to change their
1348  * own password?
1349  *
1350  * IN expirationDate - the date when the principal will expire.
1351  *
1352  * IN maxTicketLifetime - the maximum lifetime of a ticket issued for
1353  * the principal.
1354  *
1355  * IN passwordExpires - the maximum number of days a particular
1356  * password can be used.  The limit is 255, 0 => no expiration.
1357  *
1358  * IN passwordReuse - can a password be reused by this principal.
1359  *
1360  * IN failedPasswordAttempts - number of failed login attempts before
1361  * a principal is locked.  The limit is 255, 0 => no limit.
1362  *
1363  * IN failedPasswordLockTime - the number of seconds a principal is
1364  * locked once failedPasswordAttempts is reached.  Some bizarre rounding
1365  * occurs for this value, see kas for more details.
1366  *
1367  * LOCKS
1368  *
1369  * No locks are held by this function.
1370  *
1371  * RETURN CODES
1372  *
1373  * Returns != 0 upon successful completion.
1374  *
1375  * ASSUMPTIONS
1376  *
1377  * See the comments in GetPrincipalLockStatus regarding how the locking data
1378  * is kept INconsistently between servers.
1379  */
1380  
1381 int ADMINAPI kas_PrincipalFieldsSet(
1382   const void *cellHandle,
1383   const void *serverHandle,
1384   const kas_identity_p who,
1385   const kas_admin_p isAdmin,
1386   const kas_tgs_p grantTickets,
1387   const kas_enc_p canEncrypt,
1388   const kas_cpw_p canChangePassword,
1389   const unsigned int *expirationDate,
1390   const unsigned int *maxTicketLifetime,
1391   const unsigned int *passwordExpires,
1392   const kas_rpw_p passwordReuse,
1393   const unsigned int *failedPasswordAttempts,
1394   const unsigned int *failedPasswordLockTime,
1395   afs_status_p st)
1396 {
1397     int rc = 0;
1398     afs_status_t tst = 0;
1399     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1400     kas_server_p k_handle = (kas_server_p) serverHandle;
1401     kas_server_t kaserver;
1402     afs_int32 flags = 0;
1403     Date expiration = 0;
1404     afs_int32 lifetime = 0;
1405     int was_spare;
1406     char spare_bytes[4] = {0,0,0,0};
1407     int somethings_changing = 0;
1408
1409     /*
1410      * Validate input arguments.
1411      */
1412
1413     if (who == NULL) {
1414         tst = ADMKASWHONULL;
1415         goto fail_kas_PrincipalFieldsSet;
1416     }
1417
1418     /*
1419      * set flags based upon input
1420      *
1421      * If we're changing the flags, we need to get the current value of
1422      * the flags first and then make the changes
1423      */
1424
1425     if ((isAdmin != NULL) || (grantTickets != NULL) ||
1426         (canEncrypt != NULL) || (canChangePassword != NULL)) {
1427         if (!getPrincipalFlags(cellHandle, serverHandle, who, &flags,
1428                                &tst)) {
1429             goto fail_kas_PrincipalFieldsSet;
1430         }
1431     }
1432
1433     if (isAdmin != NULL) {
1434         somethings_changing = 1;
1435         if (*isAdmin == KAS_ADMIN) {
1436             flags |= KAFADMIN;
1437         } else {
1438             flags &= ~KAFADMIN;
1439         }
1440     }
1441
1442     if (grantTickets != NULL) {
1443         somethings_changing = 1;
1444         if (*grantTickets == NO_TGS) {
1445             flags |= KAFNOTGS;
1446         } else {
1447             flags &= ~KAFNOTGS;
1448         }
1449     }
1450
1451     if (canEncrypt != NULL) {
1452         somethings_changing = 1;
1453         if (*canEncrypt == NO_ENCRYPT) {
1454             flags |= KAFNOSEAL;
1455         } else {
1456             flags &= ~KAFNOSEAL;
1457         }
1458     }
1459
1460     if (canChangePassword != NULL) {
1461         somethings_changing = 1;
1462         if (*canChangePassword == NO_CHANGE_PASSWORD) {
1463             flags |= KAFNOCPW;
1464         } else {
1465             flags &= ~KAFNOCPW;
1466         }
1467     }
1468
1469     flags = (flags & KAF_SETTABLE_FLAGS) | KAFNORMAL;
1470
1471     if (expirationDate != NULL) {
1472         somethings_changing = 1;
1473         expiration = *expirationDate;
1474     }
1475
1476     if (maxTicketLifetime != NULL) {
1477         somethings_changing = 1;
1478         lifetime = *maxTicketLifetime;
1479     }
1480
1481     if (passwordExpires != NULL) {
1482         if (*passwordExpires > 255) {
1483             tst = ADMKASPASSWORDEXPIRESTOOBIG;
1484             goto fail_kas_PrincipalFieldsSet;
1485         }
1486         somethings_changing = 1;
1487         spare_bytes[0] = *passwordExpires + 1;
1488     }
1489
1490     if (passwordReuse != NULL) {
1491         somethings_changing = 1;
1492         if (*passwordReuse == REUSE_PASSWORD) {
1493             spare_bytes[1] = KA_REUSEPW;
1494         } else {
1495             spare_bytes[1] = KA_NOREUSEPW;
1496         }
1497     }
1498
1499     if (failedPasswordAttempts != NULL) {
1500         if (*failedPasswordAttempts > 255) {
1501             tst = ADMKASFAILEDPASSWORDATTEMPTSTOOBIG;
1502             goto fail_kas_PrincipalFieldsSet;
1503         }
1504         somethings_changing = 1;
1505         spare_bytes[2] = *failedPasswordAttempts + 1;
1506     }
1507
1508     if (failedPasswordLockTime != NULL) {
1509         if (*failedPasswordLockTime > 36*60*60) {
1510             tst = ADMKASFAILEDPASSWORDLOCKTIME;
1511             goto fail_kas_PrincipalFieldsSet;
1512         }
1513         somethings_changing = 1;
1514         spare_bytes[3] = ((*failedPasswordLockTime + 511) >> 9) + 1;
1515     }
1516
1517     was_spare = pack_long(spare_bytes);
1518
1519     if (somethings_changing) {
1520         if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1521             goto fail_kas_PrincipalFieldsSet;
1522         }
1523         tst = ubik_Call(KAM_SetFields, kaserver.servers, 0, who->principal,
1524                         who->instance, flags, expiration, lifetime,
1525                         -1, was_spare, 0);
1526         if (tst == 0) {
1527             rc = 1;
1528         }
1529     } else {
1530         tst = ADMKASPRINCIPALFIELDSNOCHANGE;
1531     }
1532  
1533 fail_kas_PrincipalFieldsSet:
1534
1535     if (st != NULL) {
1536         *st = tst;
1537     }
1538     return rc;
1539 }
1540
1541 /*
1542  * kas_ServerStatsGet - get server statistics.
1543  *
1544  * PARAMETERS
1545  *
1546  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1547  *
1548  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1549  *
1550  * OUT stats - the statistics retrieved.
1551  *
1552  * LOCKS
1553  *
1554  * No locks are held by this function.
1555  *
1556  * RETURN CODES
1557  *
1558  * Returns != 0 upon successful completion.
1559  */
1560  
1561 int ADMINAPI kas_ServerStatsGet(
1562   const void *cellHandle,
1563   const void *serverHandle,
1564   kas_serverStats_p stats,
1565   afs_status_p st)
1566 {
1567     int rc = 0;
1568     afs_status_t tst = 0;
1569     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1570     kas_server_p k_handle = (kas_server_p) serverHandle;
1571     kas_server_t kaserver;
1572     afs_int32 admins;
1573     kasstats statics;
1574     kadstats dynamics;
1575     size_t i;
1576
1577     /*
1578      * Validate input arguments and make rpc.
1579      */
1580
1581     if (stats == NULL) {
1582         tst = ADMKASSTATSNULL;
1583         goto fail_kas_ServerStatsGet;
1584     }
1585
1586     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1587         goto fail_kas_ServerStatsGet;
1588     }
1589
1590     tst = ubik_Call(KAM_GetStats, kaserver.servers, 0, KAMAJORVERSION, &admins, 
1591                     &statics, &dynamics);
1592     if (tst) {
1593         goto fail_kas_ServerStatsGet;
1594     }
1595
1596     stats->allocations = statics.allocs;
1597     stats->frees = statics.frees;
1598     stats->changePasswordRequests = statics.cpws;
1599     stats->adminAccounts = admins;
1600     stats->host = dynamics.host;
1601     stats->serverStartTime = dynamics.start_time;
1602     stats->hashTableUtilization = dynamics.hashTableUtilization;
1603
1604     i = sizeof(kas_serverProcStats_t);
1605     memcpy(&stats->authenticate, &dynamics.Authenticate, i);
1606     memcpy(&stats->changePassword, &dynamics.ChangePassword, i);
1607     memcpy(&stats->getTicket, &dynamics.GetTicket, i);
1608     memcpy(&stats->createUser, &dynamics.CreateUser, i);
1609     memcpy(&stats->setPassword, &dynamics.SetPassword, i);
1610     memcpy(&stats->setFields, &dynamics.SetFields, i);
1611     memcpy(&stats->deleteUser, &dynamics.DeleteUser, i);
1612     memcpy(&stats->getEntry, &dynamics.GetEntry, i);
1613     memcpy(&stats->listEntry, &dynamics.ListEntry, i);
1614     memcpy(&stats->getStats, &dynamics.GetStats, i);
1615     memcpy(&stats->getPassword, &dynamics.GetPassword, i);
1616     memcpy(&stats->getRandomKey, &dynamics.GetRandomKey, i);
1617     memcpy(&stats->debug, &dynamics.Debug, i);
1618     memcpy(&stats->udpAuthenticate, &dynamics.UAuthenticate, i);
1619     memcpy(&stats->udpGetTicket, &dynamics.UGetTicket, i);
1620     memcpy(&stats->unlock, &dynamics.Unlock, i);
1621     memcpy(&stats->lockStatus, &dynamics.LockStatus, i);
1622
1623     stats->stringChecks = dynamics.string_checks;
1624     rc = 1;
1625
1626 fail_kas_ServerStatsGet:
1627
1628     if (st != NULL) {
1629         *st = tst;
1630     }
1631     return rc;
1632 }
1633
1634 /*
1635  * kas_ServerDebugGet - get server debug info.
1636  *
1637  * PARAMETERS
1638  *
1639  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1640  *
1641  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1642  *
1643  * OUT stats - the debug info retrieved.
1644  *
1645  * LOCKS
1646  *
1647  * No locks are held by this function.
1648  *
1649  * RETURN CODES
1650  *
1651  * Returns != 0 upon successful completion.
1652  */
1653  
1654 int ADMINAPI kas_ServerDebugGet(
1655   const void *cellHandle,
1656   const void *serverHandle,
1657   kas_serverDebugInfo_p debug,
1658   afs_status_p st)
1659 {
1660     int rc = 0;
1661     afs_status_t tst = 0;
1662     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1663     kas_server_p k_handle = (kas_server_p) serverHandle;
1664     kas_server_t kaserver;
1665     struct ka_debugInfo info;
1666     int i;
1667  
1668     /*
1669      * Validate input arguments and make rpc.
1670      */
1671
1672     if (debug == NULL) {
1673         tst = ADMKASDEBUGNULL;
1674         goto fail_kas_ServerDebugGet;
1675     }
1676
1677     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1678         goto fail_kas_ServerDebugGet;
1679     }
1680     tst = ubik_Call(KAM_Debug, kaserver.servers, 0, KAMAJORVERSION, 0, &info);
1681     if (tst) {
1682         goto fail_kas_ServerDebugGet;
1683     }
1684     debug->host = info.host;
1685     debug->serverStartTime = info.startTime;
1686     debug->currentTime = info.reserved1;
1687     debug->noAuth = info.noAuth;
1688     debug->lastTransaction = info.lastTrans;
1689     strcpy(debug->lastOperation, info.lastOperation);
1690     strcpy(debug->lastPrincipalAuth, info.lastAuth);
1691     strcpy(debug->lastPrincipalUDPAuth, info.lastUAuth);
1692     strcpy(debug->lastPrincipalTGS, info.lastTGS);
1693     strcpy(debug->lastPrincipalUDPTGS, info.lastUTGS);
1694     strcpy(debug->lastPrincipalAdmin, info.lastAdmin);
1695     strcpy(debug->lastServerTGS, info.lastTGSServer);
1696     strcpy(debug->lastServerUDPTGS, info.lastUTGSServer);
1697     debug->nextAutoCheckPointWrite = info.nextAutoCPW;
1698     debug->updatesRemainingBeforeAutoCheckPointWrite = info.updatesRemaining;
1699     debug->dbHeaderRead = info.dbHeaderRead;
1700     debug->dbVersion = info.dbVersion;
1701     debug->dbFreePtr = info.dbFreePtr;
1702     debug->dbEOFPtr = info.dbEofPtr;
1703     debug->dbKvnoPtr = info.dbKvnoPtr;
1704     debug->dbSpecialKeysVersion = info.dbSpecialKeysVersion;
1705     debug->dbHeaderLock = info.cheader_lock;
1706     debug->keyCacheLock = info.keycache_lock;
1707     debug->keyCacheVersion = info.kcVersion;
1708     debug->keyCacheSize = info.kcSize;
1709     debug->keyCacheUsed = info.kcUsed;
1710     for(i=0;i<info.kcUsed;i++) {
1711         debug->keyCache[i].lastUsed = info.kcInfo[i].used;
1712         debug->keyCache[i].keyVersionNumber = info.kcInfo[i].kvno;
1713         debug->keyCache[i].primary = info.kcInfo[i].primary;
1714         debug->keyCache[i].keyCheckSum = info.kcInfo[i].keycksum;
1715         strcpy(debug->keyCache[i].principal,info.kcInfo[i].principal);
1716     }
1717     rc = 1;
1718
1719 fail_kas_ServerDebugGet:
1720
1721     if (st != NULL) {
1722         *st = tst;
1723     }
1724     return rc;
1725 }
1726
1727 /*
1728  * kas_ServerRandomKeyGet - get a random key from a server.
1729  *
1730  * PARAMETERS
1731  *
1732  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1733  *
1734  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
1735  *
1736  * OUT key - a random key.
1737  *
1738  * LOCKS
1739  *
1740  * No locks are held by this function.
1741  *
1742  * RETURN CODES
1743  *
1744  * Returns != 0 upon successful completion.
1745  */
1746  
1747 int ADMINAPI kas_ServerRandomKeyGet(
1748   const void *cellHandle,
1749   const void *serverHandle,
1750   kas_encryptionKey_p key,
1751   afs_status_p st)
1752 {
1753     int rc = 0;
1754     afs_status_t tst = 0;
1755     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1756     kas_server_p k_handle = (kas_server_p) serverHandle;
1757     kas_server_t kaserver;
1758  
1759     /*
1760      * Validate input arguments and make rpc.
1761      */
1762
1763     if (key == NULL) {
1764         tst = ADMKASKEYNULL;
1765         goto fail_kas_ServerRandomKeyGet;
1766     }
1767
1768     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
1769         goto fail_kas_ServerRandomKeyGet;
1770     }
1771
1772     tst = ubik_Call(KAM_GetRandomKey, kaserver.servers, 0, key);
1773     if (tst) {
1774         goto fail_kas_ServerRandomKeyGet;
1775     }
1776     rc = 1;
1777
1778 fail_kas_ServerRandomKeyGet:
1779
1780     if (st != NULL) {
1781         *st = tst;
1782     }
1783     return rc;
1784 }
1785
1786 /*
1787  * kas_StringToKey - turn a string key into a key.
1788  *
1789  * PARAMETERS
1790  *
1791  * IN cellName - the name of the cell where the key will be used.
1792  *
1793  * IN string - the string to be converted.
1794  *
1795  * OUT key - the encryption key.
1796  *
1797  * LOCKS
1798  *
1799  * No locks are held by this function.
1800  *
1801  * RETURN CODES
1802  *
1803  * Returns != 0 upon successful completion.
1804  */
1805  
1806 int ADMINAPI kas_StringToKey(
1807   const char *cellName,
1808   const char *string,
1809   kas_encryptionKey_p key,
1810   afs_status_p st)
1811 {
1812     int rc = 0;
1813     afs_status_t tst = 0;
1814  
1815     ka_StringToKey(string, cellName, (struct ktc_encryptionKey *) key);
1816     rc = 1;
1817
1818     if (st != NULL) {
1819         *st = tst;
1820     }
1821     return rc;
1822 }
1823
1824
1825 /*
1826  * kas_KeyCheckSum - compute the checksum of an encryption key.
1827  *
1828  * PARAMETERS
1829  *
1830  * IN key - the encryption key.
1831  *
1832  * OUT cksumP - key checksum
1833  *
1834  * LOCKS
1835  *
1836  * No locks are held by this function.
1837  *
1838  * RETURN CODES
1839  *
1840  * Returns != 0 upon successful completion.
1841  */
1842  
1843 int ADMINAPI kas_KeyCheckSum(
1844   const kas_encryptionKey_p key,
1845   unsigned int *cksumP,
1846   afs_status_p st
1847 ) {
1848     int rc = 0;
1849     afs_status_t tst = 0;
1850     afs_uint32 cksum32;
1851  
1852     if ((tst = ka_KeyCheckSum((char *)key, &cksum32)) == 0) {
1853         *cksumP = cksum32;
1854         rc = 1;
1855     }
1856
1857     if (st != NULL) {
1858         *st = tst;
1859     }
1860     return rc;
1861 }