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