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