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