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