libadmin: #define UBIK_LEGACY_CALLITER 1 in afs_kasAdmin.c
[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 #define UBIK_LEGACY_CALLITER 1
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14 #include <afs/stds.h>
15
16 #include <roken.h>
17
18 #include <rx/rx.h>
19 #include <rx/rxstat.h>
20 #include "afs_kasAdmin.h"
21 #include "../adminutil/afs_AdminInternal.h"
22 #include <afs/afs_AdminErrors.h>
23 #include <afs/afs_utilAdmin.h>
24 #include <afs/kauth.h>
25 #include <afs/kautils.h>
26 #include <afs/kaport.h>
27 #include <pthread.h>
28
29 #undef ENCRYPT
30
31 typedef struct {
32     int begin_magic;
33     int is_valid;
34     struct ubik_client *servers;
35     char *cell;
36     int end_magic;
37 } kas_server_t, *kas_server_p;
38
39 /*
40  * IsValidServerHandle - verify the validity of a kas_server_t handle.
41  *
42  * PARAMETERS
43  *
44  * IN serverHandle - the handle to be verified.
45  *
46  * LOCKS
47  *
48  * No locks are obtained or released by this function
49  *
50  * RETURN CODES
51  *
52  * Returns != 0 upon successful completion.
53  */
54
55 static int
56 IsValidServerHandle(const kas_server_p serverHandle, afs_status_p st)
57 {
58     int rc = 0;
59     afs_status_t tst = 0;
60
61     /*
62      * Validate input parameters
63      */
64
65     if (serverHandle == NULL) {
66         tst = ADMKASSERVERHANDLENULL;
67         goto fail_IsValidServerHandle;
68     }
69
70     if ((serverHandle->begin_magic != BEGIN_MAGIC)
71         || (serverHandle->end_magic != END_MAGIC)) {
72         tst = ADMKASSERVERHANDLEBADMAGIC;
73         goto fail_IsValidServerHandle;
74     }
75
76     if (!serverHandle->is_valid) {
77         tst = ADMKASSERVERHANDLENOTVALID;
78         goto fail_IsValidServerHandle;
79     }
80
81     if (serverHandle->servers == NULL) {
82         tst = ADMKASSERVERHANDLENOSERVERS;
83         goto fail_IsValidServerHandle;
84     }
85     rc = 1;
86
87   fail_IsValidServerHandle:
88
89     if (st != NULL) {
90         *st = tst;
91     }
92     return rc;
93 }
94
95 /*
96  * IsValidCellHandle - verify the validity of a afs_cell_handle_t handle
97  * for doing kas related functions.
98  *
99  * PARAMETERS
100  *
101  * IN cellHandle - the handle to be verified.
102  *
103  * LOCKS
104  *
105  * No locks are obtained or released by this function
106  *
107  * RETURN CODES
108  *
109  * Returns != 0 upon successful completion.
110  */
111
112 static int
113 IsValidCellHandle(const afs_cell_handle_p cellHandle, afs_status_p st)
114 {
115     int rc = 0;
116     afs_status_t tst = 0;
117
118     /*
119      * Validate input parameters
120      */
121
122     if (!CellHandleIsValid((void *)cellHandle, &tst)) {
123         goto fail_IsValidCellHandle;
124     }
125
126     if (!cellHandle->kas_valid) {
127         tst = ADMCLIENTCELLKASINVALID;
128         goto fail_IsValidCellHandle;
129     }
130
131     if (cellHandle->kas == NULL) {
132         tst = ADMCLIENTCELLKASNULL;
133         goto fail_IsValidCellHandle;
134     }
135     rc = 1;
136
137   fail_IsValidCellHandle:
138
139     if (st != NULL) {
140         *st = tst;
141     }
142     return rc;
143 }
144
145 /*
146  * For all kas admin functions that take a cellHandle and a serverHandle,
147  * the intention is that is the cellHandle is not NULL, we should use
148  * it.  Otherwise, we use the serverHandle.  It is an error for both
149  * of these parameters to be non-NULL.
150  */
151
152 /*
153  * ChooseValidServer - given a serverHandle and a cellHandle, choose the
154  * one that is non-NULL, validate it, and return a ubik_client structure
155  * that contains it.
156  *
157  * PARAMETERS
158  *
159  * IN cellHandle - the cell where kas calls are to be made
160  *
161  * IN serverHandle - the group of server(s) that should be used to satisfy
162  * kas calls.
163  *
164  * LOCKS
165  *
166  * No locks are obtained or released by this function
167  *
168  * RETURN CODES
169  *
170  * Returns != 0 upon successful completion.
171  */
172
173 static int
174 ChooseValidServer(const afs_cell_handle_p cellHandle,
175                   const kas_server_p serverHandle, kas_server_p kasHandle,
176                   afs_status_p st)
177 {
178     int rc = 0;
179     afs_status_t tst = 0;
180
181     /*
182      * Validate input parameters
183      */
184
185     if (kasHandle == NULL) {
186         tst = ADMKASKASHANDLENULL;
187         goto fail_ChooseValidServer;
188     }
189
190     /*
191      * Only one of the input handle parameters to this function should
192      * not be NULL
193      */
194     if ((cellHandle == NULL) && (serverHandle == NULL)) {
195         tst = ADMKASCELLHANDLEANDSERVERHANDLENULL;
196         goto fail_ChooseValidServer;
197     }
198
199     if ((cellHandle != NULL) && (serverHandle != NULL)) {
200         tst = ADMKASCELLHANDLEANDSERVERHANDLENOTNULL;
201         goto fail_ChooseValidServer;
202     }
203
204     /*
205      * Validate the non-NULL handle
206      */
207
208     if (cellHandle != NULL) {
209         if (IsValidCellHandle(cellHandle, &tst)) {
210             kasHandle->servers = cellHandle->kas;
211             kasHandle->cell = cellHandle->working_cell;
212         } else {
213             goto fail_ChooseValidServer;
214         }
215     } else {
216         if (IsValidServerHandle(serverHandle, &tst)) {
217             kasHandle->servers = serverHandle->servers;
218             kasHandle->cell = serverHandle->cell;
219         } else {
220             goto fail_ChooseValidServer;
221         }
222     }
223
224     kasHandle->begin_magic = BEGIN_MAGIC;
225     kasHandle->end_magic = END_MAGIC;
226     kasHandle->is_valid = 1;
227     rc = 1;
228
229   fail_ChooseValidServer:
230
231     if (st != NULL) {
232         *st = tst;
233     }
234     return rc;
235 }
236
237
238 static int
239 kaentryinfo_to_kas_principalEntry_t(struct kaentryinfo *from,
240                                     kas_principalEntry_p to, afs_status_p st)
241 {
242     int rc = 0;
243     afs_status_t tst = 0;
244     int short reuse;
245     unsigned char misc_stuff[4];
246
247     if (from == NULL) {
248         tst = ADMKASFROMNULL;
249         goto fail_kaentryinfo_to_kas_principalEntry_t;
250     }
251
252     if (to == NULL) {
253         tst = ADMKASTONULL;
254         goto fail_kaentryinfo_to_kas_principalEntry_t;
255     }
256
257     if (from->flags & KAFADMIN) {
258         to->adminSetting = KAS_ADMIN;
259     } else {
260         to->adminSetting = NO_KAS_ADMIN;
261     }
262
263     if (from->flags & KAFNOTGS) {
264         to->tgsSetting = NO_TGS;
265     } else {
266         to->tgsSetting = TGS;
267     }
268
269     if (from->flags & KAFNOSEAL) {
270         to->encSetting = NO_ENCRYPT;
271     } else {
272         to->encSetting = ENCRYPT;
273     }
274
275     if (from->flags & KAFNOCPW) {
276         to->cpwSetting = NO_CHANGE_PASSWORD;
277     } else {
278         to->cpwSetting = CHANGE_PASSWORD;
279     }
280
281     reuse = (short)from->reserved3;
282     if (!reuse) {
283         to->rpwSetting = REUSE_PASSWORD;
284     } else {
285         to->rpwSetting = NO_REUSE_PASSWORD;
286     }
287
288
289     if (from->user_expiration == NEVERDATE) {
290         to->userExpiration = 0;
291     } else {
292         to->userExpiration = from->user_expiration;
293     }
294
295     to->lastModTime = from->modification_time;
296     strcpy(to->lastModPrincipal.principal, from->modification_user.name);
297     strcpy(to->lastModPrincipal.instance, from->modification_user.instance);
298     to->lastChangePasswordTime = from->change_password_time;
299     to->maxTicketLifetime = from->max_ticket_lifetime;
300     to->keyVersion = from->key_version;
301     memcpy(&to->key, &from->key, sizeof(to->key));
302     to->keyCheckSum = from->keyCheckSum;
303
304     unpack_long(from->misc_auth_bytes, misc_stuff);
305     to->daysToPasswordExpire = misc_stuff[0];
306     to->failLoginCount = misc_stuff[2];
307     to->lockTime = misc_stuff[3] << 9;
308     rc = 1;
309
310   fail_kaentryinfo_to_kas_principalEntry_t:
311
312     if (st != NULL) {
313         *st = tst;
314     }
315     return rc;
316 }
317
318 /*
319  * kas_ServerOpen - open a handle to a set of kaserver's.
320  *
321  * PARAMETERS
322  *
323  * IN cellHandle - a previously opened cellHandle that corresponds
324  * to the cell where the server(s) live.
325  *
326  * IN serverList - a NULL terminated list (a la argv) of server's that 
327  * should be opened.
328  *
329  * OUT serverHandleP - a pointer to a void pointer that upon successful
330  * completion contains serverHandle that can be used in other kas functions.
331  *
332  * LOCKS
333  *
334  * No locks are obtained or released by this function
335  *
336  * RETURN CODES
337  *
338  * Returns != 0 upon successful completion.
339  * 
340  * ASSUMPTIONS
341  * 
342  * This function make some assumptions about the afsconf_cell used by 
343  * ka_AuthSpecificServersConn (since I just wrote ka_AuthSpecificServersConn).
344  * It only fills in the fields that are required.
345  *
346  * Also we assume that the servers listed are members of the cell in
347  * cellHandle without verifying that this is in fact the case.  kas itself
348  * always assumes that the -servers parameter lists servers in the current
349  * cell without verifying, so I am no worse than the current
350  * implementation.  In fact I'm actually a little more flexible since you
351  * can actually use my serverList to play with servers in another cell.
352  * You can't do that with kas.  For certain functions in kas the same
353  * cell assumption can cause things to fail (the ka_StringToKey function in
354  * UserCreate).
355  */
356
357 int ADMINAPI
358 kas_ServerOpen(const void *cellHandle, const char **serverList,
359                void **serverHandleP, afs_status_p st)
360 {
361     int rc = 0;
362     afs_status_t tst = 0;
363     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
364     int server_count = 0, server_addr;
365     struct afsconf_cell server_info;
366     kas_server_p k_handle = malloc(sizeof(kas_server_t));
367
368     /*
369      * Validate input parameters
370      */
371
372     if (c_handle == NULL) {
373         tst = ADMCLIENTCELLHANDLENULL;
374         goto fail_kas_ServerOpen;
375     }
376
377     if (c_handle->kas_valid == 0) {
378         tst = ADMCLIENTCELLKASINVALID;
379         goto fail_kas_ServerOpen;
380     }
381
382     if (serverList == NULL) {
383         tst = ADMKASSERVERLISTNULL;
384         goto fail_kas_ServerOpen;
385     }
386
387     if (serverHandleP == NULL) {
388         tst = ADMKASSERVERHANDLEPNULL;
389         goto fail_kas_ServerOpen;
390     }
391
392     if (k_handle == NULL) {
393         tst = ADMNOMEM;
394         goto fail_kas_ServerOpen;
395     }
396
397     k_handle->begin_magic = BEGIN_MAGIC;
398     k_handle->end_magic = END_MAGIC;
399     k_handle->is_valid = 0;
400     k_handle->servers = NULL;
401
402     /*
403      * Convert serverList to numeric addresses
404      */
405
406     for (server_count = 0; serverList[server_count] != NULL; server_count++) {
407         if (server_count >= MAXHOSTSPERCELL) {
408             tst = ADMKASSERVERLISTTOOLONG;
409             goto fail_kas_ServerOpen;
410         }
411         if (util_AdminServerAddressGetFromName
412             (serverList[server_count], &server_addr, &tst)) {
413             server_info.hostAddr[server_count].sin_addr.s_addr =
414                 htonl(server_addr);
415             server_info.hostAddr[server_count].sin_port =
416                 htons(AFSCONF_KAUTHPORT);
417         } else {
418             goto fail_kas_ServerOpen;
419         }
420     }
421
422     if (server_count == 0) {
423         tst = ADMKASSERVERLISTEMPTY;
424         goto fail_kas_ServerOpen;
425     }
426
427     /*
428      * Get a ubik_client handle for the specified servers
429      */
430     server_info.numServers = server_count;
431     if (!
432         (tst =
433          ka_AuthSpecificServersConn(KA_MAINTENANCE_SERVICE,
434                                     &c_handle->tokens->kas_token,
435                                     &server_info, &k_handle->servers))) {
436         k_handle->is_valid = 1;
437         k_handle->cell = c_handle->working_cell;
438         *serverHandleP = (void *)k_handle;
439     } else {
440         goto fail_kas_ServerOpen;
441     }
442     rc = 1;
443
444   fail_kas_ServerOpen:
445
446     if ((rc == 0) && (k_handle != NULL)) {
447         free(k_handle);
448     }
449
450     if (st != NULL) {
451         *st = tst;
452     }
453     return rc;
454 }
455
456 /*
457  * kas_ServerClose - close a serverHandle.
458  *
459  * PARAMETERS
460  *
461  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
462  *
463  * LOCKS
464  *
465  * No locks are obtained or released by this function
466  *
467  * RETURN CODES
468  *
469  * Returns != 0 upon successful completion.
470  */
471
472 int ADMINAPI
473 kas_ServerClose(const void *serverHandle, afs_status_p st)
474 {
475     int rc = 0;
476     afs_status_t tst = 0;
477     kas_server_p k_handle = (kas_server_p) serverHandle;
478
479     if (!IsValidServerHandle(k_handle, &tst)) {
480         goto fail_kas_ServerClose;
481     }
482
483     tst = ubik_ClientDestroy(k_handle->servers);
484     if (tst) {
485         goto fail_kas_ServerClose;
486     }
487
488     k_handle->is_valid = 0;
489     free(k_handle);
490     rc = 1;
491
492   fail_kas_ServerClose:
493
494     if (st != NULL) {
495         *st = tst;
496     }
497     return rc;
498 }
499
500 /*
501  * kas_PrincipalCreate - create a new principal.
502  *
503  * PARAMETERS
504  *
505  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
506  *
507  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
508  *
509  * IN who - a kas_identity_p containing the identity of the new principal
510  * to be created.
511  *
512  * IN password - the new principal's initial password.
513  *
514  * LOCKS
515  *
516  * No locks are obtained or released by this function
517  *
518  * RETURN CODES
519  *
520  * Returns != 0 upon successful completion.
521  */
522
523 int ADMINAPI
524 kas_PrincipalCreate(const void *cellHandle, const void *serverHandle,
525                     const kas_identity_p who, const char *password,
526                     afs_status_p st)
527 {
528     int rc = 0;
529     afs_status_t tst = 0;
530     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
531     kas_server_p k_handle = (kas_server_p) serverHandle;
532     kas_server_t kaserver;
533     EncryptionKey key;
534     struct kas_encryptionKey kas_key;
535
536     /*
537      * Validate input arguments and make rpc.
538      */
539
540     if (who == NULL) {
541         tst = ADMKASWHONULL;
542         goto fail_kas_PrincipalCreate;
543     }
544
545     if (password == NULL) {
546         tst = ADMKASPASSWORDNULL;
547         goto fail_kas_PrincipalCreate;
548     }
549
550     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
551         goto fail_kas_PrincipalCreate;
552     }
553
554     if (!kas_StringToKey(kaserver.cell, password, &kas_key, &tst)) {
555         goto fail_kas_PrincipalCreate;
556     }
557
558     memcpy(&key, &kas_key, sizeof(key));
559
560     tst =
561         ubik_KAM_CreateUser(kaserver.servers, 0, who->principal,
562                   who->instance, key);
563     if (tst) {
564         goto fail_kas_PrincipalCreate;
565     }
566     rc = 1;
567
568
569   fail_kas_PrincipalCreate:
570
571     if (st != NULL) {
572         *st = tst;
573     }
574     return rc;
575 }
576
577 /*
578  * kas_PrincipalDelete - delete an existing principal.
579  *
580  * PARAMETERS
581  *
582  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
583  *
584  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
585  *
586  * IN who - a kas_identity_p containing the identity of the principal
587  * to be deleted.
588  *
589  * LOCKS
590  *
591  * No locks are obtained or released by this function
592  *
593  * RETURN CODES
594  *
595  * Returns != 0 upon successful completion.
596  */
597
598 int ADMINAPI
599 kas_PrincipalDelete(const void *cellHandle, const void *serverHandle,
600                     const kas_identity_p who, afs_status_p st)
601 {
602     int rc = 0;
603     afs_status_t tst = 0;
604     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
605     kas_server_p k_handle = (kas_server_p) serverHandle;
606     kas_server_t kaserver;
607
608     /*
609      * Validate input arguments and make rpc.
610      */
611
612     if (who == NULL) {
613         tst = ADMKASWHONULL;
614         goto fail_kas_PrincipalDelete;
615     }
616
617     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
618         goto fail_kas_PrincipalDelete;
619     }
620     tst =
621         ubik_KAM_DeleteUser(kaserver.servers, 0, who->principal,
622                   who->instance);
623     if (tst) {
624         goto fail_kas_PrincipalDelete;
625     }
626     rc = 1;
627
628   fail_kas_PrincipalDelete:
629
630     if (st != NULL) {
631         *st = tst;
632     }
633     return rc;
634 }
635
636 /*
637  * GetPrincipalLockStatus - get the lock status of a principal.
638  *
639  * PARAMETERS
640  *
641  * IN kaserver - a valid kaserver handle previously returned by 
642  * ChooseValidServer
643  *
644  * IN who - a kas_identity_p containing the identity of the principal
645  * to be queried.
646  *
647  * OUT lockedUntil - the remaining number of seconds the principal is locked.
648  *
649  * LOCKS
650  *
651  * No locks are obtained or released by this function
652  *
653  * RETURN CODES
654  *
655  * Returns != 0 upon successful completion.
656  */
657
658 static int
659 GetPrincipalLockStatus(const kas_server_p kaserver, const kas_identity_p who,
660                        unsigned int *lockedUntil, afs_status_p st)
661 {
662     int rc = 0;
663     afs_status_t tst = 0;
664     unsigned int locked;
665     int count = 0;
666     int once = 0;
667
668     /*
669      * Validate input arguments and make rpc.
670      */
671
672     if (kaserver == NULL) {
673         tst = ADMKASKASERVERNULL;
674         goto fail_GetPrincipalLockStatus;
675     }
676
677     if (who == NULL) {
678         tst = ADMKASWHONULL;
679         goto fail_GetPrincipalLockStatus;
680     }
681
682     if (lockedUntil == NULL) {
683         tst = ADMKASLOCKEDUNTILNULL;
684         goto fail_GetPrincipalLockStatus;
685     }
686
687     /*
688      * Unlike every other kas rpc we make here, the lock/unlock rpc's
689      * aren't ubik based.  So instead of calling ubik_Call, we use
690      * ubik_CallIter.  ubik_CallIter steps through the list of hosts
691      * in the ubik_client and calls them one at a time.  Since there's
692      * no synchronization of this data across the servers we have to 
693      * manually keep track of the shortest time to unlock the user ourselves.
694      *
695      * The original inspiration for this function is ka_islocked
696      * in admin_tools.c.  I think that function is totally bogus so I'm
697      * rewriting it here.
698      *
699      * This function should contact all the kaservers and request the lock
700      * status of the principal.  If any of the servers say the principal is
701      * unlocked, we report it as unlocked.  If all the servers say the
702      * principal is locked, we find the server with the shortest lock time
703      * remaining on the principal and return that time.
704      *
705      * This is different than kas, but I think kas is buggy.
706      */
707
708     *lockedUntil = 0;
709     do {
710         locked = 0;
711         tst =
712             ubik_CallIter(KAM_LockStatus, kaserver->servers, UPUBIKONLY,
713                           &count, (long)who->principal, (long)who->instance, (long)&locked, 0,
714                           0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
715         if (tst == 0) {
716             if (locked) {
717                 if ((locked < *lockedUntil) || !once) {
718                     *lockedUntil = locked;
719                     once++;
720                 }
721             }
722         }
723     } while ((tst != UNOSERVERS) && (locked != 0));
724
725     /*
726      * Check to see if any server reported this principal unlocked.
727      */
728
729     if ((tst == 0) && (locked == 0)) {
730         *lockedUntil = 0;
731     }
732     if ((tst == 0) || (tst == UNOSERVERS)) {
733         rc = 1;
734     }
735
736   fail_GetPrincipalLockStatus:
737
738     if (st != NULL) {
739         *st = tst;
740     }
741     return rc;
742 }
743
744 /*
745  * kas_PrincipalGet - retrieve information about a single principal.
746  *
747  * PARAMETERS
748  *
749  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
750  *
751  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
752  *
753  * IN who - a kas_identity_p containing the identity of the principal
754  * to be retrieved.
755  *
756  * OUT principal - upon successful completion contains information
757  * about who.
758  *
759  * LOCKS
760  *
761  * No locks are obtained or released by this function
762  *
763  * RETURN CODES
764  *
765  * Returns != 0 upon successful completion.
766  */
767
768 int ADMINAPI
769 kas_PrincipalGet(const void *cellHandle, const void *serverHandle,
770                  const kas_identity_p who, kas_principalEntry_p principal,
771                  afs_status_p st)
772 {
773     int rc = 0;
774     afs_status_t tst = 0;
775     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
776     kas_server_p k_handle = (kas_server_p) serverHandle;
777     kas_server_t kaserver;
778     struct kaentryinfo entry;
779
780     /*
781      * Validate input arguments and make rpc.
782      */
783
784     if (who == NULL) {
785         tst = ADMKASWHONULL;
786         goto fail_kas_PrincipalGet;
787     }
788
789     if (principal == NULL) {
790         tst = ADMKASPRINCIPALNULL;
791         goto fail_kas_PrincipalGet;
792     }
793
794     if (!ChooseValidServer(c_handle, k_handle, &kaserver, &tst)) {
795         goto fail_kas_PrincipalGet;
796     }
797
798     tst =
799         ubik_KAM_GetEntry(kaserver.servers, 0, who->principal,
800                   who->instance, KAMAJORVERSION, &entry);
801     if (tst) {
802         goto fail_kas_PrincipalGet;
803     }
804
805     /*
806      * copy the kaentryinfo structure to our kas_principalEntry_t
807      * format
808      */
809     if (!kaentryinfo_to_kas_principalEntry_t(&entry, principal, &tst)) {
810         goto fail_kas_PrincipalGet;
811     }
812     rc = 1;
813
814   fail_kas_PrincipalGet:
815
816     if (st != NULL) {
817         *st = tst;
818     }
819     return rc;
820 }
821
822 typedef struct principal_get {
823     int current;
824     int next;
825     int count;
826     kas_server_t kaserver;
827     kas_identity_t principal[CACHED_ITEMS];
828 } principal_get_t, *principal_get_p;
829
830 static int
831 DeletePrincipalSpecificData(void *rpc_specific, afs_status_p st)
832 {
833     int rc = 0;
834     afs_status_t tst = 0;
835     principal_get_p prin = (principal_get_p) rpc_specific;
836
837     prin->kaserver.is_valid = 0;
838     rc = 1;
839
840     if (st != NULL) {
841         *st = tst;
842     }
843     return rc;
844 }
845
846 static int
847 GetPrincipalRPC(void *rpc_specific, int slot, int *last_item,
848                 int *last_item_contains_data, afs_status_p st)
849 {
850     int rc = 0;
851     afs_status_t tst = 0;
852     principal_get_p prin = (principal_get_p) rpc_specific;
853
854     tst =
855         ubik_KAM_ListEntry(prin->kaserver.servers, 0, prin->current,
856                            &prin->next, &prin->count, (kaident *)&prin->principal[slot]);
857     if (tst == 0) {
858         prin->current = prin->next;
859         if (prin->next == 0) {
860             *last_item = 1;
861             *last_item_contains_data = 0;
862         }
863         rc = 1;
864     }
865
866     if (st != NULL) {
867         *st = tst;
868     }
869     return rc;
870 }
871
872 static int
873 GetPrincipalFromCache(void *rpc_specific, int slot, void *dest,
874                       afs_status_p st)
875 {
876     int rc = 0;
877     afs_status_t tst = 0;
878     principal_get_p prin = (principal_get_p) rpc_specific;
879
880     memcpy(dest, &prin->principal[slot], sizeof(kas_identity_t));
881     rc = 1;
882
883     if (st != NULL) {
884         *st = tst;
885     }
886     return rc;
887 }
888
889 /*
890  * kas_PrincipalGetBegin - start the process of iterating over the entire
891  * kas database.
892  *
893  * PARAMETERS
894  *
895  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
896  *
897  * IN serverHandle - a serverHandle previously returned by kas_ServerOpen.
898  *
899  * OUT iterationIdP - upon successful completion contains a iterator that
900  * can be passed to kas_PrincipalGetNext.
901  *
902  * LOCKS
903  *
904  * No locks are obtained or released by this function
905  *
906  * RETURN CODES
907  *
908  * Returns != 0 upon successful completion.
909  *
910  * ASSUMPTIONS
911  */
912
913 int ADMINAPI
914 kas_PrincipalGetBegin(const void *cellHandle, const void *serverHandle,
915                       void **iterationIdP, afs_status_p st)
916 {
917     int rc = 0;
918     afs_status_t tst = 0;
919     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
920     kas_server_p k_handle = (kas_server_p) serverHandle;
921     afs_admin_iterator_p iter = malloc(sizeof(afs_admin_iterator_t));
922     principal_get_p principal = 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 }