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