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