libroken: Build on windows
[openafs.git] / src / libadmin / client / afs_clientAdmin.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 #include <roken.h>
14
15 #include <afs/stds.h>
16 #include "afs_clientAdmin.h"
17 #include "../adminutil/afs_AdminInternal.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <afs/cellconfig.h>
22 #ifdef AFS_NT40_ENV
23 #include <afs/afssyscalls.h>
24 #include <winsock2.h>
25 #include <afs/fs_utils.h>
26 #define close(x) closesocket(x)
27 #else
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <netdb.h>
32 #include <afs/venus.h>
33 #include <errno.h>
34 #include <strings.h>
35 #include <unistd.h>
36 #endif
37 #include <string.h>
38 #include <afs/kautils.h>
39 #include <rx/rx.h>
40 #include <rx/rxstat.h>
41 #include <rx/rx_null.h>
42 #include <rx/rxkad.h>
43 #include <afs/dirpath.h>
44 #include <afs/afs_AdminErrors.h>
45 #include <afs/afs_vosAdmin.h>
46 #include <afs/afs_utilAdmin.h>
47 #include <afs/ptserver.h>
48 #include <afs/vlserver.h>
49 #include <afs/pthread_glock.h>
50 #include <afs/sys_prototypes.h>
51
52 /*
53  * AFS client administration functions.
54  *
55  * Admin functions that are normally associated with the client.
56  *
57  * All of the functions related to authentication are here, plus
58  * some miscellaneous others.
59  *
60  */
61
62 static const unsigned long ADMIN_TICKET_LIFETIME = 24 * 3600;
63
64 static const unsigned long SERVER_TTL = 10 * 60;
65
66 /*
67  * We need a way to track whether or not the client library has been 
68  * initialized.  We count on the fact that the other library initialization
69  * functions are protected by their own once mechanism.  We only track
70  * our own internal status
71  */
72
73 static int client_init;
74 static pthread_once_t client_init_once = PTHREAD_ONCE_INIT;
75
76 static void
77 client_once(void)
78 {
79     client_init = 1;
80 }
81
82 /*
83  * IsTokenValid - validate a token handle
84  *
85  * PARAMETERS
86  *
87  * IN token - the token to be validated.
88  *
89  * LOCKS
90  *
91  * No locks are obtained or released by this function
92  *
93  * CAUTIONS
94  *
95  * None.
96  *
97  * RETURN CODES
98  *
99  * Returns != 0 upon successful completion.
100  */
101
102 static int
103 IsTokenValid(const afs_token_handle_p token, afs_status_p st)
104 {
105     int rc = 0;
106     afs_status_t tst = 0;
107
108     if (token == NULL) {
109         tst = ADMCLIENTTOKENHANDLENULL;
110         goto fail_IsTokenValid;
111     }
112
113     if (token->is_valid == 0) {
114         tst = ADMCLIENTTOKENHANDLEINVALID;
115         goto fail_IsTokenValid;
116     }
117
118     if ((token->begin_magic != BEGIN_MAGIC)
119         || (token->end_magic != END_MAGIC)) {
120         tst = ADMCLIENTTOKENHANDLEBADMAGIC;
121         goto fail_IsTokenValid;
122     }
123     rc = 1;
124
125   fail_IsTokenValid:
126
127     if (st != NULL) {
128         *st = tst;
129     }
130     return rc;
131 }
132
133 /*
134  * afsclient_TokenGetExisting - get tokens that already exist and
135  * are held by the cache manager.
136  *
137  * PARAMETERS
138  *
139  * IN cellName - the name of the cell where the token originated.
140  *
141  * OUT tokenHandle - a handle to the tokens if they were obtained
142  * successfully.
143  *
144  * LOCKS
145  *
146  * No locks are obtained or released by this function
147  *
148  * CAUTIONS
149  *
150  * The tokenHandle returned by this function cannot be used for kas
151  * related operations, since kas tokens aren't stored in the kernel.
152  *
153  * RETURN CODES
154  *
155  * Returns != 0 upon successful completion.
156  */
157
158 int ADMINAPI
159 afsclient_TokenGetExisting(const char *cellName, void **tokenHandle,
160                            afs_status_p st)
161 {
162     int rc = 0;
163     afs_status_t tst = 0;
164     struct ktc_principal afs_server;
165     afs_token_handle_p t_handle =
166         (afs_token_handle_p) calloc(1, sizeof(afs_token_handle_t));
167
168     if (client_init == 0) {
169         tst = ADMCLIENTNOINIT;
170         goto fail_afsclient_TokenGetExisting;
171     }
172
173     if (cellName == NULL) {
174         tst = ADMCLIENTCELLNAMENULL;
175         goto fail_afsclient_TokenGetExisting;
176     }
177
178     if (tokenHandle == NULL) {
179         tst = ADMCLIENTTOKENHANDLENULL;
180         goto fail_afsclient_TokenGetExisting;
181     }
182
183     if (t_handle == NULL) {
184         tst = ADMNOMEM;
185         goto fail_afsclient_TokenGetExisting;
186     }
187
188     strcpy(afs_server.name, "afs");
189     afs_server.instance[0] = 0;
190     strcpy(afs_server.cell, cellName);
191
192     if (!
193         (tst =
194          ktc_GetToken(&afs_server, &t_handle->afs_token,
195                       sizeof(t_handle->afs_token), &t_handle->client))) {
196         /*
197          * The token has been retrieved successfully, initialize
198          * the rest of the token handle structure
199          */
200         strncpy(t_handle->cell, cellName, MAXCELLCHARS);
201         t_handle->cell[MAXCELLCHARS - 1] = '\0';
202         t_handle->afs_token_set = 1;
203         t_handle->from_kernel = 1;
204         t_handle->kas_token_set = 0;
205         t_handle->sc_index = 2;
206         t_handle->afs_sc[t_handle->sc_index] =
207             rxkad_NewClientSecurityObject(rxkad_clear,
208                                           &t_handle->afs_token.sessionKey,
209                                           t_handle->afs_token.kvno,
210                                           t_handle->afs_token.ticketLen,
211                                           t_handle->afs_token.ticket);
212         t_handle->afs_encrypt_sc[t_handle->sc_index] =
213             rxkad_NewClientSecurityObject(rxkad_crypt,
214                                           &t_handle->afs_token.sessionKey,
215                                           t_handle->afs_token.kvno,
216                                           t_handle->afs_token.ticketLen,
217                                           t_handle->afs_token.ticket);
218         if ((t_handle->afs_sc[t_handle->sc_index] == NULL)
219             || (t_handle->afs_sc[t_handle->sc_index] == NULL)) {
220             tst = ADMCLIENTTOKENHANDLENOSECURITY;
221             goto fail_afsclient_TokenGetExisting;
222         } else {
223             t_handle->begin_magic = BEGIN_MAGIC;
224             t_handle->is_valid = 1;
225             t_handle->end_magic = END_MAGIC;
226             *tokenHandle = (void *)t_handle;
227         }
228     } else {
229         goto fail_afsclient_TokenGetExisting;
230     }
231     rc = 1;
232
233   fail_afsclient_TokenGetExisting:
234
235     if ((rc == 0) && (t_handle != NULL)) {
236         free(t_handle);
237     }
238     if (st != NULL) {
239         *st = tst;
240     }
241     return rc;
242 }
243
244 /*
245  * afsclient_TokenSet - set the tokens represented by tokenHandle to be
246  * active in the kernel (aka ka_SetToken).
247  *
248  * PARAMETERS
249  *
250  * IN cellName - the name of the cell where the token originated.
251  *
252  * OUT tokenHandle - a handle to the tokens if they were obtained
253  * successfully.
254  *
255  * LOCKS
256  *
257  * No locks are obtained or released by this function
258  *
259  * CAUTIONS
260  *
261  * The tokenHandle returned by this function cannot be used for kas
262  * related operations, since kas tokens aren't stored in the kernel.
263  *
264  * RETURN CODES
265  *
266  * Returns != 0 upon successful completion.
267  */
268
269 int ADMINAPI
270 afsclient_TokenSet(const void *tokenHandle, afs_status_p st)
271 {
272     int rc = 0;
273     afs_status_t tst = 0;
274     struct ktc_principal afs_server;
275     afs_token_handle_p t_handle = (afs_token_handle_p) tokenHandle;
276
277     if (!IsTokenValid(t_handle, &tst)) {
278         goto fail_afsclient_TokenSet;
279     }
280
281     strcpy(afs_server.name, "afs");
282     afs_server.instance[0] = 0;
283     strcpy(afs_server.cell, t_handle->cell);
284
285     tst =
286         ktc_SetToken(&afs_server, &t_handle->afs_token, &t_handle->client, 0);
287
288     if (!tst) {
289         rc = 1;
290     }
291
292   fail_afsclient_TokenSet:
293
294     if (st != NULL) {
295         *st = tst;
296     }
297     return rc;
298 }
299
300 /*
301  * GetKASToken - get a KAS token and store it in the tokenHandle.
302  *
303  * PARAMETERS
304  *
305  * IN cellName - the name of the cell where the token should be obtained.
306  * 
307  * IN principal - the name of the user of the token.
308  *
309  * IN password - the password for the principal.
310  *
311  * OUT tokenHandle - a handle to the tokens if they were obtained
312  * successfully.
313  *
314  * LOCKS
315  *
316  * No locks are obtained or released by this function
317  *
318  * CAUTIONS
319  *
320  * None.
321  *
322  * RETURN CODES
323  *
324  * Returns != 0 upon successful completion.
325  */
326
327 static int
328 GetKASToken(const char *cellName, const char *principal, const char *password,
329             afs_token_handle_p tokenHandle, afs_status_p st)
330 {
331     int rc = 0;
332     afs_status_t tst = 0;
333     struct ubik_client *unauth_conn;
334     afs_int32 expire;
335     struct ktc_encryptionKey key;
336     struct ktc_token *token;
337     unsigned long now = time(0);
338     char name[MAXKTCNAMELEN];
339     char inst[MAXKTCNAMELEN];
340     int have_server_conn = 0;
341
342     token = &tokenHandle->kas_token;
343
344     ka_StringToKey((char *)password, (char *)cellName, &key);
345
346     /* 
347      * Get an unauthenticated connection in the right cell to use for
348      * retrieving the token.
349      */
350
351     tst =
352         ka_AuthServerConn((char *)cellName, KA_AUTHENTICATION_SERVICE, 0,
353                           &unauth_conn);
354     if (tst != 0) {
355         goto fail_GetKASToken;
356     }
357     have_server_conn = 1;
358
359     tst = ka_ParseLoginName((char *)principal, name, inst, NULL);
360     if (tst != 0) {
361         goto fail_GetKASToken;
362     }
363
364     tst =
365         ka_Authenticate(name, inst, (char *)cellName, unauth_conn,
366                         KA_MAINTENANCE_SERVICE, &key, now,
367                         now + ADMIN_TICKET_LIFETIME, token, &expire);
368     if (tst != 0) {
369         goto fail_GetKASToken;
370     }
371     rc = 1;
372
373   fail_GetKASToken:
374
375     if (have_server_conn) {
376         ubik_ClientDestroy(unauth_conn);
377     }
378
379     if (st != NULL) {
380         *st = tst;
381     }
382     return rc;
383 }
384
385 /*
386  * GetAFSToken - get a AFS token and store it in the tokenHandle.
387  *
388  * PARAMETERS
389  *
390  * IN cellName - the name of the cell where the token should be obtained.
391  * 
392  * IN principal - the name of the user of the token.
393  *
394  * IN password - the password for the principal.
395  *
396  * OUT tokenHandle - a handle to the tokens if they were obtained
397  * successfully.
398  *
399  * LOCKS
400  *
401  * No locks are obtained or released by this function
402  *
403  * CAUTIONS
404  *
405  * None.
406  *
407  * RETURN CODES
408  *
409  * Returns != 0 upon successful completion.
410  */
411
412 static int
413 GetAFSToken(const char *cellName, const char *principal, const char *password,
414             afs_token_handle_p tokenHandle, afs_status_p st)
415 {
416     int rc = 0;
417     afs_status_t tst = 0;
418     struct ubik_client *unauth_conn = NULL, *auth_conn = NULL;
419     afs_int32 expire;
420     struct ktc_encryptionKey key;
421     struct ktc_token auth_token;
422     struct ktc_token *token;
423     unsigned long now = time(0);
424
425     token = &tokenHandle->afs_token;
426
427     ka_StringToKey((char *)password, (char *)cellName, &key);
428
429     /* 
430      * Get an unauthenticated connection in the right cell to use for
431      * retrieving the token.
432      */
433
434     tst =
435         ka_AuthServerConn((char *)cellName, KA_AUTHENTICATION_SERVICE, 0,
436                           &unauth_conn);
437     if (tst) {
438         goto fail_GetAFSToken;
439     }
440
441     tst =
442         ka_ParseLoginName((char *)principal, tokenHandle->client.name,
443                           tokenHandle->client.instance, NULL);
444     if (tst) {
445         goto fail_GetAFSToken;
446     }
447
448     tst =
449         ka_Authenticate(tokenHandle->client.name,
450                         tokenHandle->client.instance, (char *)cellName,
451                         unauth_conn, KA_TICKET_GRANTING_SERVICE, &key, now,
452                         now + ADMIN_TICKET_LIFETIME, &auth_token, &expire);
453     if (tst) {
454         goto fail_GetAFSToken;
455     }
456
457     tst =
458         ka_AuthServerConn((char *)cellName, KA_TICKET_GRANTING_SERVICE, 0,
459                           &auth_conn);
460     if (tst) {
461         goto fail_GetAFSToken;
462     }
463
464     tst =
465         ka_CellToRealm((char *)cellName, tokenHandle->client.cell, (int *)0);
466     if (tst) {
467         goto fail_GetAFSToken;
468     }
469
470     tst =
471         ka_GetToken("afs", "", (char *)cellName, tokenHandle->client.name,
472                     tokenHandle->client.instance, auth_conn, now,
473                     now + ADMIN_TICKET_LIFETIME, &auth_token,
474                     tokenHandle->client.cell, token);
475     if (tst) {
476         goto fail_GetAFSToken;
477     }
478     rc = 1;
479
480   fail_GetAFSToken:
481
482     if (auth_conn) {
483         ubik_ClientDestroy(auth_conn);
484     }
485
486     if (unauth_conn) {
487         ubik_ClientDestroy(unauth_conn);
488     }
489
490     if (st != NULL) {
491         *st = tst;
492     }
493     return rc;
494 }
495
496
497 /*
498  * afsclient_TokenGetNew - get new tokens for a user and store them
499  * in the tokenHandle.
500  *
501  * PARAMETERS
502  *
503  * IN cellName - the name of the cell where the tokens should be obtained.
504  * 
505  * IN principal - the name of the user of the tokens.
506  *
507  * IN password - the password for the principal.
508  *
509  * OUT tokenHandle - a handle to the tokens if they were obtained
510  * successfully.
511  *
512  * LOCKS
513  *
514  * No locks are obtained or released by this function
515  *
516  * CAUTIONS
517  *
518  * None.
519  *
520  * RETURN CODES
521  *
522  * Returns != 0 upon successful completion.
523  */
524
525 int ADMINAPI
526 afsclient_TokenGetNew(const char *cellName, const char *principal,
527                       const char *password, void **tokenHandle,
528                       afs_status_p st)
529 {
530     int rc = 0;
531     afs_status_t tst = 0;
532     afs_token_handle_p t_handle =
533         (afs_token_handle_p) calloc(1, sizeof(afs_token_handle_t));
534
535     if (client_init == 0) {
536         tst = ADMCLIENTNOINIT;
537         goto fail_afsclient_TokenGetNew;
538     }
539
540     if (t_handle == NULL) {
541         tst = ADMNOMEM;
542         goto fail_afsclient_TokenGetNew;
543     }
544
545     /*
546      * Check to see if the principal or password is missing.  If it is,
547      * get unauthenticated tokens for the cell
548      */
549
550     if ((principal == NULL) || (*principal == 0) || (password == NULL)
551         || (*password == 0)) {
552         t_handle->from_kernel = 0;
553         t_handle->afs_token_set = 1;
554         t_handle->kas_token_set = 1;
555         t_handle->sc_index = 0;
556         t_handle->afs_sc[t_handle->sc_index] =
557             rxnull_NewClientSecurityObject();
558         t_handle->afs_encrypt_sc[t_handle->sc_index] =
559             rxnull_NewClientSecurityObject();
560         t_handle->kas_sc[t_handle->sc_index] =
561             rxnull_NewClientSecurityObject();
562         t_handle->begin_magic = BEGIN_MAGIC;
563         t_handle->is_valid = 1;
564         t_handle->afs_token.endTime = 0;
565         t_handle->end_magic = END_MAGIC;
566         *tokenHandle = (void *)t_handle;
567
568     } else {
569
570         /*
571          * create an authenticated token
572          */
573
574         if ((GetAFSToken(cellName, principal, password, t_handle, &tst))
575             && (GetKASToken(cellName, principal, password, t_handle, &tst))) {
576             strncpy(t_handle->cell, cellName, MAXCELLCHARS);
577             t_handle->cell[MAXCELLCHARS - 1] = '\0';
578             t_handle->from_kernel = 0;
579             t_handle->afs_token_set = 1;
580             t_handle->kas_token_set = 1;
581             t_handle->sc_index = 2;
582             t_handle->afs_sc[t_handle->sc_index] =
583                 rxkad_NewClientSecurityObject(rxkad_clear,
584                                               &t_handle->afs_token.sessionKey,
585                                               t_handle->afs_token.kvno,
586                                               t_handle->afs_token.ticketLen,
587                                               t_handle->afs_token.ticket);
588             t_handle->afs_encrypt_sc[t_handle->sc_index] =
589                 rxkad_NewClientSecurityObject(rxkad_crypt,
590                                               &t_handle->afs_token.sessionKey,
591                                               t_handle->afs_token.kvno,
592                                               t_handle->afs_token.ticketLen,
593                                               t_handle->afs_token.ticket);
594             t_handle->kas_sc[t_handle->sc_index] =
595                 rxkad_NewClientSecurityObject(rxkad_crypt,
596                                               &t_handle->kas_token.sessionKey,
597                                               t_handle->kas_token.kvno,
598                                               t_handle->kas_token.ticketLen,
599                                               t_handle->kas_token.ticket);
600             if ((t_handle->afs_sc[t_handle->sc_index] != NULL)
601                 && (t_handle->afs_encrypt_sc[t_handle->sc_index] != NULL)
602                 && (t_handle->kas_sc[t_handle->sc_index] != NULL)) {
603                 t_handle->begin_magic = BEGIN_MAGIC;
604                 t_handle->is_valid = 1;
605                 t_handle->end_magic = END_MAGIC;
606                 *tokenHandle = (void *)t_handle;
607             } else {
608                 tst = ADMCLIENTTOKENHANDLENOSECURITY;
609                 goto fail_afsclient_TokenGetNew;
610             }
611         } else {
612             goto fail_afsclient_TokenGetNew;
613         }
614     }
615     rc = 1;
616
617   fail_afsclient_TokenGetNew:
618
619     if ((rc == 0) && (t_handle != NULL)) {
620         free(t_handle);
621     }
622
623     if (st != NULL) {
624         *st = tst;
625     }
626     return rc;
627 }
628
629 /*
630  * afsclient_TokenQuery - get the expiration time of the tokens.
631  *
632  * PARAMETERS
633  *
634  * IN tokenHandle - a previously obtained valid token.
635  * 
636  * OUT expirationDateP - the time at which the tokens expire.
637  * 
638  * OUT principal - the owning principal
639  * 
640  * OUT instance - principal instance if it exists.
641  * 
642  * OUT cell - the principal's cell
643  * 
644  * OUT hasKasTokens - set to 1 if the token handle contains kas tokens.
645  *
646  * LOCKS
647  *
648  * No locks are obtained or released by this function
649  *
650  * CAUTIONS
651  *
652  * We only check the AFS tokens since we always get these.  The
653  * KAS tokens may expirer later than the AFS tokens, but this 
654  * difference is minor and reporting an earlier time won't cause
655  * the user problems.
656  *
657  * RETURN CODES
658  *
659  * Returns != 0 upon successful completion.
660  */
661
662 int ADMINAPI
663 afsclient_TokenQuery(void *tokenHandle, unsigned long *expirationDateP,
664                      char *principal, char *instance, char *cell,
665                      int *hasKasTokens, afs_status_p st)
666 {
667     int rc = 0;
668     afs_status_t tst = 0;
669     afs_token_handle_p t_handle = (afs_token_handle_p) tokenHandle;
670
671     if (client_init == 0) {
672         tst = ADMCLIENTNOINIT;
673         rc = 0;
674         goto fail_afsclient_TokenQuery;
675     }
676
677     if (IsTokenValid(t_handle, &tst)) {
678         if (principal != NULL) {
679             strcpy(principal, t_handle->client.name);
680         }
681         if (instance != NULL) {
682             strcpy(instance, t_handle->client.instance);
683         }
684         if (cell != NULL) {
685             strcpy(cell, t_handle->client.cell);
686         }
687         if (hasKasTokens != NULL) {
688             *hasKasTokens = t_handle->kas_token_set;
689         }
690         if (expirationDateP != NULL) {
691             *expirationDateP = t_handle->afs_token.endTime;
692         }
693         rc = 1;
694     }
695
696   fail_afsclient_TokenQuery:
697
698     if (st != NULL) {
699         *st = tst;
700     }
701     return rc;
702 }
703
704 /*
705  * afsclient_TokenClose - close an existing token.
706  *
707  * PARAMETERS
708  *
709  * IN token - the token to be closed.
710  *
711  * LOCKS
712  *
713  * No locks are obtained or released by this function
714  *
715  * CAUTIONS
716  *
717  * None.
718  *
719  * RETURN CODES
720  *
721  * Returns != 0 upon successful completion.
722  */
723
724 int ADMINAPI
725 afsclient_TokenClose(const void *tokenHandle, afs_status_p st)
726 {
727     int rc = 0;
728     afs_status_t tst = 0;
729     afs_token_handle_p t_handle = (afs_token_handle_p) tokenHandle;
730
731     if (client_init == 0) {
732         tst = ADMCLIENTNOINIT;
733         goto fail_afsclient_TokenClose;
734     }
735
736     if (IsTokenValid(t_handle, &tst)) {
737         t_handle->is_valid = 0;
738         free(t_handle);
739         rc = 1;
740     }
741
742   fail_afsclient_TokenClose:
743
744     if (st != NULL) {
745         *st = tst;
746     }
747     return rc;
748 }
749
750 #define NUM_SERVER_TYPES 3
751
752 /* must match NUM_SERVER_TYPES */
753 typedef enum { KAS, PTS, VOS } afs_server_list_t;
754
755 typedef struct afs_server {
756     char *serv;
757     int serviceId;
758     struct ubik_client **ubik;
759     struct rx_securityClass *sc;
760     int *valid;
761 } afs_server_t, *afs_server_p;
762
763 /*
764  * afsclient_CellOpen - Open a particular cell for work as a particular
765  * user.
766  *
767  * PARAMETERS
768  *
769  * IN cellName - the cell where future admin calls will be made.
770  *
771  * IN tokenHandle - the tokens work will be done under.
772  * 
773  * OUT cellHandleP - an opaque pointer that is the first parameter to
774  * almost all subsequent admin api calls.
775  *
776  * LOCKS
777  *
778  * No locks are obtained or released by this function
779  *
780  * CAUTIONS
781  *
782  * None.
783  *
784  * RETURN CODES
785  *
786  * Returns != 0 upon successful completion.
787  */
788
789 int ADMINAPI
790 afsclient_CellOpen(const char *cellName, const void *tokenHandle,
791                    void **cellHandleP, afs_status_p st)
792 {
793     int rc = 0;
794     afs_status_t tst = 0;
795     afs_token_handle_p t_handle = (afs_token_handle_p) tokenHandle;
796     afs_cell_handle_p c_handle = (afs_cell_handle_p)
797         calloc(1, sizeof(afs_cell_handle_t));
798     struct afsconf_dir *tdir = NULL;
799     struct afsconf_cell info;
800     struct rx_connection *serverconns[MAXSERVERS];
801     int i, j;
802     struct rx_securityClass *sc[3];
803     int scIndex;
804     char copyCell[MAXCELLCHARS];
805
806     afs_server_t servers[NUM_SERVER_TYPES]
807       = { {AFSCONF_KAUTHSERVICE, KA_MAINTENANCE_SERVICE, 0, 0, 0},
808           {AFSCONF_PROTSERVICE, PRSRV, 0, 0, 0},
809           {AFSCONF_VLDBSERVICE, USER_SERVICE_ID, 0, 0, 0}
810       };
811     
812     if (client_init == 0) {
813         tst = ADMCLIENTNOINIT;
814         goto fail_afsclient_CellOpen;
815     }
816
817     if (c_handle == NULL) {
818         tst = ADMNOMEM;
819         goto fail_afsclient_CellOpen;
820     }
821
822     if (t_handle == NULL) {
823         tst = ADMCLIENTTOKENHANDLENULL;
824         goto fail_afsclient_CellOpen;
825     }
826
827     if ((cellName == NULL) || (*cellName == 0)) {
828         tst = ADMCLIENTCELLNAMENULL;
829         goto fail_afsclient_CellOpen;
830     }
831
832     if (cellHandleP == NULL) {
833         tst = ADMCLIENTCELLHANDLEPNULL;
834         goto fail_afsclient_CellOpen;
835     }
836
837     /*
838      * Check that the token handle contains valid data and the calloc 
839      * succeeded
840      */
841     if (!t_handle->afs_token_set) {
842         tst = ADMCLIENTCELLOPENBADTOKEN;
843         goto fail_afsclient_CellOpen;
844     }
845
846     /*
847      * Use a table to initialize the cell handle structure, since
848      * most of the steps are the same for all the servers.
849      * 
850      * Start by creating rx_securityClass objects for each of the
851      * servers.  A potential optimization is to do this in 
852      * afsclient_TokenGetNew and just keep the expiration time of
853      * the tokens around.
854      * Also, initialize the ubik client pointers in the table
855      */
856     servers[KAS].sc = t_handle->kas_sc[t_handle->sc_index];
857     servers[PTS].sc = t_handle->afs_sc[t_handle->sc_index];
858     servers[VOS].sc = servers[PTS].sc;
859     servers[KAS].ubik = &c_handle->kas;
860     servers[PTS].ubik = &c_handle->pts;
861     servers[VOS].ubik = &c_handle->vos;
862     servers[KAS].valid = &c_handle->kas_valid;
863     servers[PTS].valid = &c_handle->pts_valid;
864     servers[VOS].valid = &c_handle->vos_valid;
865     c_handle->vos_new = 1;
866
867     if ((servers[PTS].sc == NULL) || (servers[VOS].sc == NULL)) {
868         tst = ADMCLIENTBADTOKENHANDLE;
869         goto fail_afsclient_CellOpen;
870     }
871
872     /*
873      * If the initialization has succeeded so far, get the address
874      * information for each server in the cell
875      */
876
877     strncpy(c_handle->working_cell, cellName, MAXCELLCHARS);
878     c_handle->working_cell[MAXCELLCHARS - 1] = '\0';
879     if (!(tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH))) {
880         tst = ADMCLIENTBADCLIENTCONFIG;
881         goto fail_afsclient_CellOpen;
882     }
883
884     /*
885      * We must copy the cellName here because afsconf_GetCellInfo
886      * actually writes over the cell name it is passed.
887      */
888     strncpy(copyCell, cellName, MAXCELLCHARS);
889     copyCell[MAXCELLCHARS - 1] ='\0';
890     for (i = 0; (i < NUM_SERVER_TYPES); i++) {
891         if (i == KAS) {
892             tst =
893                 ka_AuthServerConn((char *)cellName, servers[i].serviceId,
894                                   ((t_handle->sc_index == 0)
895                                    || (!t_handle->
896                                        kas_token_set)) ? 0 : &t_handle->
897                                   kas_token, servers[i].ubik);
898             if (tst) {
899                 goto fail_afsclient_CellOpen;
900             }
901         } else {
902             tst = afsconf_GetCellInfo(tdir, copyCell, servers[i].serv, &info);
903             if (!tst) {
904                 /* create ubik client handles for each server */
905                 scIndex = t_handle->sc_index;
906                 sc[scIndex] = servers[i].sc;
907                 for (j = 0; (j < info.numServers); j++) {
908                     serverconns[j] =
909                         rx_GetCachedConnection(info.hostAddr[j].sin_addr.
910                                                s_addr,
911                                                info.hostAddr[j].sin_port,
912                                                servers[i].serviceId,
913                                                sc[scIndex], scIndex);
914                 }
915                 serverconns[j] = 0;
916                 tst = ubik_ClientInit(serverconns, servers[i].ubik);
917                 if (tst) {
918                     goto fail_afsclient_CellOpen;
919                 }
920             } else {
921                 goto fail_afsclient_CellOpen;
922             }
923         }
924         /* initialization complete, mark handle valid */
925         *servers[i].valid = 1;
926     }
927     c_handle->tokens = t_handle;
928     rc = 1;
929
930   fail_afsclient_CellOpen:
931
932     if (tdir) {
933         afsconf_Close(tdir);
934     }
935
936     /*
937      * Upon error, free any obtained resources.
938      */
939     if (rc == 0) {
940         if (c_handle != NULL) {
941             if (c_handle->kas_valid)
942                 ubik_ClientDestroy(c_handle->kas);
943             if (c_handle->pts_valid)
944                 ubik_ClientDestroy(c_handle->pts);
945             if (c_handle->vos_valid)
946                 ubik_ClientDestroy(c_handle->vos);
947             free(c_handle);
948         }
949     } else {
950         c_handle->begin_magic = BEGIN_MAGIC;
951         c_handle->is_valid = 1;
952         c_handle->is_null = 0;
953         c_handle->server_list = NULL;
954         c_handle->server_ttl = 0;
955         c_handle->end_magic = END_MAGIC;
956         *cellHandleP = (void *)c_handle;
957     }
958
959     if (st != NULL) {
960         *st = tst;
961     }
962     return rc;
963 }
964
965 /*
966  * afsclient_NullCellOpen - open a null cell handle for access.
967  *
968  * PARAMETERS
969  * 
970  * OUT cellHandleP - an opaque pointer that is the first parameter to
971  * almost all subsequent admin api calls.
972  *
973  * LOCKS
974  *
975  * No locks are obtained or released by this function
976  *
977  * CAUTIONS
978  *
979  * None.
980  *
981  * RETURN CODES
982  *
983  * Returns != 0 upon successful completion.
984  */
985
986 int ADMINAPI
987 afsclient_NullCellOpen(void **cellHandleP, afs_status_p st)
988 {
989     int rc = 0;
990     afs_status_t tst = 0;
991     afs_cell_handle_p c_handle = (afs_cell_handle_p)
992         calloc(1, sizeof(afs_cell_handle_t));
993
994
995     /*
996      * Validate parameters
997      */
998
999     if (cellHandleP == NULL) {
1000         tst = ADMCLIENTCELLHANDLEPNULL;
1001         goto fail_afsclient_NullCellOpen;
1002     }
1003
1004     if (client_init == 0) {
1005         tst = ADMCLIENTNOINIT;
1006         goto fail_afsclient_NullCellOpen;
1007     }
1008
1009     if (c_handle == NULL) {
1010         tst = ADMNOMEM;
1011         goto fail_afsclient_NullCellOpen;
1012     }
1013
1014     /*
1015      * Get unauthenticated tokens for any cell
1016      */
1017
1018     if (!afsclient_TokenGetNew(0, 0, 0, (void *)&c_handle->tokens, &tst)) {
1019         goto fail_afsclient_NullCellOpen;
1020     }
1021
1022     c_handle->begin_magic = BEGIN_MAGIC;
1023     c_handle->is_valid = 1;
1024     c_handle->is_null = 1;
1025     c_handle->end_magic = END_MAGIC;
1026     c_handle->kas_valid = 0;
1027     c_handle->pts_valid = 0;
1028     c_handle->vos_valid = 0;
1029     c_handle->kas = NULL;
1030     c_handle->pts = NULL;
1031     c_handle->vos = NULL;
1032     c_handle->server_list = NULL;
1033     c_handle->server_ttl = 0;
1034     *cellHandleP = (void *)c_handle;
1035     rc = 1;
1036
1037   fail_afsclient_NullCellOpen:
1038
1039     if (st != NULL) {
1040         *st = tst;
1041     }
1042     return rc;
1043 }
1044
1045 /*
1046  * afsclient_CellClose - close a previously opened cellHandle.
1047  *
1048  * PARAMETERS
1049  *
1050  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
1051  *
1052  * LOCKS
1053  *
1054  * No locks are obtained or released by this function
1055  *
1056  * CAUTIONS
1057  *
1058  * None.
1059  *
1060  * RETURN CODES
1061  *
1062  * Returns != 0 upon successful completion.
1063  */
1064
1065 int ADMINAPI
1066 afsclient_CellClose(const void *cellHandle, afs_status_p st)
1067 {
1068     int rc = 0;
1069     afs_status_t tst = 0;
1070     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1071
1072     if (client_init == 0) {
1073         tst = ADMCLIENTNOINIT;
1074         goto fail_afsclient_CellClose;
1075     }
1076
1077     if (c_handle == NULL) {
1078         tst = ADMCLIENTCELLHANDLENULL;
1079         goto fail_afsclient_CellClose;
1080     }
1081
1082     if (c_handle->server_list)
1083         free(c_handle->server_list);
1084     if (c_handle->kas_valid)
1085         ubik_ClientDestroy(c_handle->kas);
1086     if (c_handle->pts_valid)
1087         ubik_ClientDestroy(c_handle->pts);
1088     if (c_handle->vos_valid)
1089         ubik_ClientDestroy(c_handle->vos);
1090     if (c_handle->is_null)
1091         afsclient_TokenClose(c_handle->tokens, 0);
1092     c_handle->kas_valid = 0;
1093     c_handle->pts_valid = 0;
1094     c_handle->vos_valid = 0;
1095     c_handle->is_valid = 0;
1096     free(c_handle);
1097     rc = 1;
1098
1099   fail_afsclient_CellClose:
1100
1101     if (st != NULL) {
1102         *st = tst;
1103     }
1104     return rc;
1105 }
1106
1107
1108 /*
1109  * afsclient_CellNameGet() -- get a pointer to the cell name in a cell handle
1110  *
1111  * PARAMETERS
1112  *
1113  * IN  cellHandle - a valid cell handle
1114  * OUT cellNameP  - a pointer to the cell name in the cell handle.
1115  *
1116  * LOCKS
1117  *
1118  * No locks are obtained or released by this function
1119  *
1120  * CAUTIONS
1121  *
1122  * If cellHandle is closed then the pointer returned by this function
1123  * is no longer valid.
1124  *
1125  * RETURN CODES
1126  *
1127  * Returns != 0 upon successful completion.
1128  */
1129 int ADMINAPI
1130 afsclient_CellNameGet(const void *cellHandle, const char **cellNameP,
1131                       afs_status_p st)
1132 {
1133     int rc = 0;
1134     afs_status_t tst = 0;
1135     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1136
1137     if (!CellHandleIsValid(cellHandle, &tst)) {
1138         goto fail_afsclient_CellNameGet;
1139     }
1140
1141     *cellNameP = c_handle->working_cell;
1142     rc = 1;
1143
1144   fail_afsclient_CellNameGet:
1145
1146     if (st != NULL) {
1147         *st = tst;
1148     }
1149     return rc;
1150 }
1151
1152
1153 /*
1154  * afsclient_LocalCellGet - get the name of the cell the machine
1155  * belongs to where this process is running.
1156  *
1157  * PARAMETERS
1158  *
1159  * OUT cellName - an array of characters that must be MAXCELLCHARS
1160  * long.
1161  *
1162  * LOCKS
1163  *
1164  * No locks are obtained or released by this function
1165  *
1166  * CAUTIONS
1167  *
1168  * If cellName is smaller than MAXCELLCHARS chars, this function won't
1169  * detect it.
1170  *
1171  * RETURN CODES
1172  *
1173  * Returns != 0 upon successful completion.
1174  */
1175
1176 int ADMINAPI
1177 afsclient_LocalCellGet(char *cellName, afs_status_p st)
1178 {
1179     int rc = 0;
1180     afs_status_t tst = 0;
1181     struct afsconf_dir *tdir = NULL;
1182
1183     if (client_init == 0) {
1184         tst = ADMCLIENTNOINIT;
1185         goto fail_afsclient_LocalCellGet;
1186     }
1187
1188     if (cellName == NULL) {
1189         tst = ADMCLIENTCELLNAMENULL;
1190         goto fail_afsclient_LocalCellGet;
1191     }
1192
1193     tdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
1194
1195     if (!tdir) {
1196         tst = ADMCLIENTBADCLIENTCONFIG;
1197         goto fail_afsclient_LocalCellGet;
1198     }
1199
1200     if ((tst = afsconf_GetLocalCell(tdir, cellName, MAXCELLCHARS))) {
1201         goto fail_afsclient_LocalCellGet;
1202     }
1203
1204     rc = 1;
1205
1206   fail_afsclient_LocalCellGet:
1207
1208     if (tdir != NULL) {
1209         afsconf_Close(tdir);
1210     }
1211
1212     if (st != NULL) {
1213         *st = tst;
1214     }
1215     return rc;
1216 }
1217
1218
1219 #ifdef AFS_NT40_ENV
1220
1221 static int
1222 client_ExtractDriveLetter(char *path)
1223 {
1224     int rc = 0;
1225
1226     if (path[0] != 0 && path[1] == ':') {
1227         path[2] = 0;
1228         rc = 1;
1229     }
1230
1231     return rc;
1232 }
1233
1234 /*
1235  * Determine the parent directory of a give directory
1236  */
1237
1238 static int
1239 Parent(char *directory, char *parentDirectory)
1240 {
1241     char *tp;
1242     int rc = 0;
1243
1244     strcpy(parentDirectory, directory);
1245     tp = strrchr(parentDirectory, '\\');
1246     if (tp) {
1247         /* lv trailing slash so Parent("k:\foo") is "k:\" not "k :" */
1248         *(tp + 1) = 0;
1249         rc = 1;
1250     } else {
1251         if (client_ExtractDriveLetter(parentDirectory)) {
1252             strcat(parentDirectory, ".");
1253             rc = 1;
1254         }
1255     }
1256
1257     return rc;
1258 }
1259
1260 #else
1261 /*
1262  * Determine the parent directory of a give directory
1263  */
1264 static int
1265 Parent(const char *directory, char *parentDirectory)
1266 {
1267     char *tp;
1268     int rc = 0;
1269
1270     strcpy(parentDirectory, directory);
1271     tp = strrchr(parentDirectory, '/');
1272     if (tp) {
1273         *tp = 0;
1274         rc = 1;
1275     } else {
1276         strcpy(parentDirectory, ".");
1277         rc = 1;
1278     }
1279
1280     return rc;
1281 }
1282 #endif
1283
1284 /*
1285  * afsclient_MountPointCreate - create a mount point for a volume.
1286  *
1287  * PARAMETERS
1288  *
1289  * IN cellHandle - a handle to the cell where volumeName resides.
1290  *
1291  * IN directory - the directory where the mountpoint should be created.
1292  *
1293  * IN volumeName - the name of the volume to mount.
1294  *
1295  * IN volType - the type of mount point to create.
1296  *
1297  * IN volCheck - indicates whether or not to check the VLDB to see if
1298  * volumeName exists.
1299  *
1300  * LOCKS
1301  *
1302  * No locks are obtained or released by this function
1303  *
1304  * RETURN CODES
1305  *
1306  * Returns != 0 upon successful completion.
1307  */
1308
1309 #define TMP_DATA_SIZE 2048
1310
1311 int ADMINAPI
1312 afsclient_MountPointCreate(const void *cellHandle, const char *directory,
1313                            const char *volumeName, vol_type_t volType,
1314                            vol_check_t volCheck, afs_status_p st)
1315 {
1316     int rc = 0;
1317     afs_status_t tst = 0;
1318     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1319     char parent_dir[TMP_DATA_SIZE];
1320     char space[TMP_DATA_SIZE];
1321     char directoryCell[MAXCELLCHARS];
1322     struct ViceIoctl idata;
1323     int i;
1324     vos_vldbEntry_t vldbEntry;
1325
1326     /*
1327      * Validate arguments
1328      */
1329
1330     if (client_init == 0) {
1331         tst = ADMCLIENTNOINIT;
1332         goto fail_afsclient_MountPointCreate;
1333     }
1334
1335     if ((directory == NULL) || (*directory == 0)) {
1336         tst = ADMCLIENTDIRECTORYNULL;
1337         goto fail_afsclient_MountPointCreate;
1338     }
1339
1340     if ((volumeName == NULL) || (*volumeName == 0)) {
1341         tst = ADMCLIENTVOLUMENAME;
1342         goto fail_afsclient_MountPointCreate;
1343     }
1344
1345     /*
1346      * Extract the parent directory and make sure it is in AFS.
1347      */
1348
1349     if (!Parent(directory, parent_dir)) {
1350         tst = ADMCLIENTBADDIRECTORY;
1351         goto fail_afsclient_MountPointCreate;
1352     }
1353
1354     idata.in_size = 0;
1355     idata.out_size = TMP_DATA_SIZE;
1356     idata.out = space;
1357     i = pioctl(parent_dir, VIOC_FILE_CELL_NAME, &idata, 1);
1358     if (i) {
1359         if ((errno == EINVAL) || (errno == ENOENT)) {
1360             tst = ADMCLIENTNOAFSDIRECTORY;
1361             goto fail_afsclient_MountPointCreate;
1362         }
1363     }
1364     strcpy(directoryCell, space);
1365
1366     /*
1367      * If the user requested, check that the volume exists
1368      */
1369
1370     if (volCheck == CHECK_VOLUME) {
1371         if (!vos_VLDBGet(cellHandle, 0, 0, (char *)volumeName, &vldbEntry,
1372                          &tst)) {
1373             goto fail_afsclient_MountPointCreate;
1374         }
1375     }
1376
1377     /*
1378      * Begin constructing the pioctl buffer
1379      */
1380
1381     if (volType == READ_WRITE) {
1382         strcpy(space, "%");
1383     } else {
1384         strcpy(space, "#");
1385     }
1386
1387     /*
1388      * Append the cell to the mount point if the volume is in a different
1389      * cell than the directory
1390      */
1391
1392     if (strcmp(c_handle->working_cell, directoryCell)) {
1393         strcat(space, c_handle->working_cell);
1394         strcat(space, ":");
1395     }
1396     strcat(space, volumeName);
1397     strcat(space, ".");
1398
1399
1400 #ifdef AFS_NT40_ENV
1401     idata.out_size = 0;
1402     idata.out = NULL;
1403     idata.in_size = 1 + strlen(space);
1404     idata.in = space;
1405     if (tst = pioctl(directory, VIOC_AFS_CREATE_MT_PT, &idata, 0)) {
1406         goto fail_afsclient_MountPointCreate;
1407     }
1408 #else
1409     if ((tst = symlink(space, directory))) {
1410         goto fail_afsclient_MountPointCreate;
1411     }
1412 #endif
1413
1414     rc = 1;
1415
1416   fail_afsclient_MountPointCreate:
1417
1418     if (st != NULL) {
1419         *st = tst;
1420     }
1421     return rc;
1422 }
1423
1424 typedef struct Acl {
1425     int dfs;
1426     char cell[1025];
1427     int nplus;
1428     int nminus;
1429 } Acl_t, *Acl_p;
1430
1431 int ADMINAPI
1432 afsclient_ACLEntryAdd(const char *directory, const char *user,
1433                       const acl_p acl, afs_status_p st)
1434 {
1435     int rc = 0;
1436     afs_status_t tst = 0;
1437     struct ViceIoctl idata;
1438     char old_acl_string[2048];
1439     char new_acl_string[2048];
1440     int newacl = 0;
1441     char *ptr;
1442     Acl_t cur_acl;
1443     char cur_user[64];
1444     int cur_user_acl = 0;
1445     int i;
1446     char tmp[64 + 35];
1447     int is_dfs;
1448
1449     if (client_init == 0) {
1450         tst = ADMCLIENTNOINIT;
1451         goto fail_afsclient_ACLEntryAdd;
1452     }
1453
1454     if ((directory == NULL) || (*directory == 0)) {
1455         tst = ADMMISCDIRECTORYNULL;
1456         goto fail_afsclient_ACLEntryAdd;
1457     }
1458
1459     if ((user == NULL) || (*user == 0)) {
1460         tst = ADMMISCUSERNULL;
1461         goto fail_afsclient_ACLEntryAdd;
1462     }
1463
1464     if (acl == NULL) {
1465         tst = ADMMISCACLNULL;
1466         goto fail_afsclient_ACLEntryAdd;
1467     }
1468
1469     if (acl->read == READ) {
1470         newacl |= 0x01;
1471     }
1472
1473     if (acl->write == WRITE) {
1474         newacl |= 0x02;
1475     }
1476
1477     if (acl->insert == INSERT) {
1478         newacl |= 0x04;
1479     }
1480
1481     if (acl->lookup == LOOKUP) {
1482         newacl |= 0x08;
1483     }
1484
1485     if (acl->del == DELETE) {
1486         newacl |= 0x10;
1487     }
1488
1489     if (acl->lock == LOCK) {
1490         newacl |= 0x20;
1491     }
1492
1493     if (acl->admin == ADMIN) {
1494         newacl |= 0x40;
1495     }
1496
1497     /*
1498      * Get the current acl for the directory
1499      */
1500
1501     idata.out_size = 2048;
1502     idata.in_size = 0;
1503     idata.in = idata.out = old_acl_string;
1504     tst = pioctl((char *)directory, VIOCGETAL, &idata, 1);
1505
1506     if (tst != 0) {
1507         goto fail_afsclient_ACLEntryAdd;
1508     }
1509
1510     /*
1511      * The acl is presented to us in string format.  The format of the
1512      * string is:
1513      *
1514      * A header which contains the number of positive and negative entries
1515      * and a string indicating whether or not this is a dfs acl:
1516      *
1517      * num_pos "\n" dfs_string "\n" num_neg
1518      *
1519      * An entry for each acl that's of the form:
1520      *
1521      * name rights "\n"
1522      *
1523      * There are no blanks in the string between fields, but I use them here
1524      * to make the reading easier.
1525      *
1526      * Since we are only going to add another entry to the acl, our approach
1527      * is simple.  Get the num_pos dfs_string and num_neg from the current acl,
1528      * increment num_pos by one and create a new string.  Concatenate the new
1529      * user and rights to the new string, and then concatenate the remaining
1530      * contents of the old acl to the new string.
1531      *
1532      * Unfortunately, this approach doesn't work since the format the kernel
1533      * hands the acl back to us in, is NOT WHAT IT WANTS BACK!!!!
1534      * So instead we need to parse the entire freaking acl and put a space
1535      * between each user and their acl.
1536      *
1537      * This is really ugly.
1538      */
1539
1540     /*
1541      * Parse the first few fields of the acl and see if this is a DFS
1542      * file.
1543      */
1544
1545     is_dfs =
1546         sscanf(old_acl_string, "%d dfs:%d %s", &cur_acl.nplus, &cur_acl.dfs,
1547                cur_acl.cell);
1548     ptr = strchr(old_acl_string, '\n');
1549     ptr++;
1550     sscanf(ptr, "%d", &cur_acl.nminus);
1551     ptr = strchr(ptr, '\n');
1552     ptr++;
1553     if (is_dfs == 3) {
1554         tst = ADMMISCNODFSACL;
1555         goto fail_afsclient_ACLEntryAdd;
1556     } else {
1557         /*
1558          * It isn't a DFS file, so create the beginning of the string
1559          * we will hand back to the kernel
1560          */
1561         sprintf(new_acl_string, "%d\n%d\n%s %d\n", (cur_acl.nplus + 1),
1562                 cur_acl.nminus, user, newacl);
1563     }
1564
1565     /*
1566      * Finish scanning the old acl, parsing each user/acl pair and
1567      * adding a space in the new acl.
1568      */
1569
1570     for (i = 0; i < (cur_acl.nplus + cur_acl.nminus); i++) {
1571         sscanf(ptr, "%s%d\n", cur_user, &cur_user_acl);
1572         /*
1573          * Skip the entry for the user we are replacing/adding
1574          */
1575
1576         if (strcmp(cur_user, user)) {
1577             ptr = strchr(ptr, '\n');
1578             ptr++;
1579             sprintf(tmp, "%s %d\n", cur_user, cur_user_acl);
1580             strcat(new_acl_string, tmp);
1581         }
1582     }
1583
1584     strcat(new_acl_string, ptr);
1585
1586     /*
1587      * Set the acl
1588      */
1589
1590     idata.out_size = 0;
1591     idata.in_size = strlen(new_acl_string) + 1;
1592     idata.in = idata.out = new_acl_string;
1593     tst = pioctl((char *) directory, VIOCSETAL, &idata, 1);
1594
1595     if (tst != 0) {
1596         goto fail_afsclient_ACLEntryAdd;
1597     }
1598     rc = 1;
1599
1600   fail_afsclient_ACLEntryAdd:
1601
1602     if (st != NULL) {
1603         *st = tst;
1604     }
1605     return rc;
1606 }
1607
1608 /*
1609  * afsclient_Init - initialize AFS components before use.
1610  *
1611  * PARAMETERS
1612  *
1613  * LOCKS
1614  *
1615  * No locks are obtained or released by this function
1616  *
1617  * CAUTIONS
1618  *
1619  * None.
1620  *
1621  * RETURN CODES
1622  *
1623  * Returns != 0 upon successful completion.
1624  */
1625
1626 int ADMINAPI
1627 afsclient_Init(afs_status_p st)
1628 {
1629     int rc = 0;
1630     afs_status_t tst = 0;
1631
1632     if (!client_init)
1633         pthread_once(&client_init_once, client_once);
1634
1635 #ifdef AFS_NT40_ENV
1636     if (afs_winsockInit() < 0) {
1637         tst = ADMCLIENTCANTINITWINSOCK;
1638         goto fail_afsclient_Init;
1639     }
1640 #endif
1641
1642     if (!(initAFSDirPath() & AFSDIR_CLIENT_PATHS_OK)) {
1643         tst = ADMCLIENTCANTINITAFSLOCATION;
1644         goto fail_afsclient_Init;
1645     }
1646
1647     if (rx_Init(0) < 0) {
1648         tst = ADMCLIENTCANTINITRX;
1649         goto fail_afsclient_Init;
1650     }
1651
1652     if ((tst = ka_CellConfig((char *)AFSDIR_CLIENT_ETC_DIRPATH))) {
1653         goto fail_afsclient_Init;
1654     }
1655
1656     rc = 1;
1657
1658   fail_afsclient_Init:
1659
1660     if (st != NULL) {
1661         *st = tst;
1662     }
1663     return rc;
1664 }
1665
1666 /*
1667  * afsclient_AFSServerGet - determine what kind of server serverName 
1668  * is and fill in serverEntryP accordingly.
1669  *
1670  * PARAMETERS
1671  *
1672  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1673  *
1674  * IN serverName - the hostname of the server of interest.
1675  *
1676  * OUT serverEntryP - upon successful completion contains a description of
1677  * the server.
1678  *
1679  * LOCKS
1680  *
1681  * No locks are obtained or released by this function
1682  *
1683  * CAUTIONS
1684  *
1685  * None.
1686  *
1687  * RETURN CODES
1688  *
1689  * Returns != 0 upon successful completion.
1690  */
1691
1692 int ADMINAPI
1693 afsclient_AFSServerGet(const void *cellHandle, const char *serverName,
1694                        afs_serverEntry_p serverEntryP, afs_status_p st)
1695 {
1696     int rc = 0;
1697     afs_status_t tst = 0;
1698     void *iter;
1699     int found_match = 0;
1700
1701     if ((serverName == NULL) || (*serverName == 0)) {
1702         tst = ADMUTILSERVERNAMENULL;
1703         goto fail_afsclient_AFSServerGet;
1704     }
1705
1706     if (serverEntryP == NULL) {
1707         tst = ADMUTILSERVERENTRYPNULL;
1708         goto fail_afsclient_AFSServerGet;
1709     }
1710
1711     /*
1712      * Iterate over server entries and try to find a match for serverName
1713      */
1714
1715     if (!afsclient_AFSServerGetBegin(cellHandle, &iter, &tst)) {
1716         goto fail_afsclient_AFSServerGet;
1717     }
1718
1719     while (afsclient_AFSServerGetNext(iter, serverEntryP, &tst)) {
1720         if (!strcmp(serverName, serverEntryP->serverName)) {
1721             found_match = 1;
1722             break;
1723         }
1724     }
1725
1726     /*
1727      * If we didn't find a match, the iterator should have terminated
1728      * normally.  If it didn't, return the error
1729      */
1730
1731     if (!found_match) {
1732         if (tst != ADMITERATORDONE) {
1733             afsclient_AFSServerGetDone(iter, 0);
1734         } else {
1735             afsclient_AFSServerGetDone(iter, &tst);
1736         }
1737         tst = ADMCLIENTNOMATCHINGSERVER;
1738         goto fail_afsclient_AFSServerGet;
1739     } else {
1740         if (!afsclient_AFSServerGetDone(iter, &tst)) {
1741             goto fail_afsclient_AFSServerGet;
1742         }
1743     }
1744     rc = 1;
1745
1746   fail_afsclient_AFSServerGet:
1747
1748     if (st != NULL) {
1749         *st = tst;
1750     }
1751     return rc;
1752 }
1753
1754 /*
1755  * The iterator functions and data for the server retrieval functions
1756  */
1757
1758 typedef struct server_get {
1759     int total;
1760     int index;
1761     afs_serverEntry_t server[MAXHOSTSPERCELL + BADSERVERID];
1762     afs_serverEntry_t cache[CACHED_ITEMS];
1763 } server_get_t, *server_get_p;
1764
1765 static int
1766 GetServerRPC(void *rpc_specific, int slot, int *last_item,
1767              int *last_item_contains_data, afs_status_p st)
1768 {
1769     int rc = 0;
1770     afs_status_t tst = 0;
1771     server_get_p serv = (server_get_p) rpc_specific;
1772
1773     memcpy(&serv->cache[slot], &serv->server[serv->index],
1774            sizeof(afs_serverEntry_t));
1775
1776     serv->index++;
1777     if (serv->index == serv->total) {
1778         *last_item = 1;
1779         *last_item_contains_data = 1;
1780     }
1781     rc = 1;
1782
1783     if (st != NULL) {
1784         *st = tst;
1785     }
1786     return rc;
1787 }
1788
1789 static int
1790 GetServerFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
1791 {
1792     int rc = 0;
1793     afs_status_t tst = 0;
1794     server_get_p serv = (server_get_p) rpc_specific;
1795
1796     memcpy(dest, (const void *)&serv->cache[slot], sizeof(afs_serverEntry_t));
1797     rc = 1;
1798
1799     if (st != NULL) {
1800         *st = tst;
1801     }
1802     return rc;
1803 }
1804
1805 /*
1806  * afsclient_AFSServerGetBegin - start the process of iterating over
1807  * every server in the cell.
1808  *
1809  * PARAMETERS
1810  *
1811  * IN cellHandle - a cellHandle previously returned by afsclient_CellOpen.
1812  *
1813  * OUT iterationIdP - - upon successful completion contains an iterator
1814  * that can be passed to afsclient_AFSServerGetNext.
1815  *
1816  * LOCKS
1817  *
1818  * No locks are obtained or released by this function
1819  *
1820  * CAUTIONS
1821  *
1822  * None.
1823  *
1824  * RETURN CODES
1825  *
1826  * Returns != 0 upon successful completion.
1827  */
1828
1829 int ADMINAPI
1830 afsclient_AFSServerGetBegin(const void *cellHandle, void **iterationIdP,
1831                             afs_status_p st)
1832 {
1833     int rc = 0;
1834     afs_status_t tst = 0;
1835     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1836     afs_admin_iterator_p iter =
1837         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
1838     server_get_p serv = (server_get_p) calloc(1, sizeof(server_get_t));
1839     server_get_p serv_cache = NULL;
1840     const char *cellName = NULL;
1841     void *database_iter;
1842     util_databaseServerEntry_t database_entry;
1843     void *fileserver_iter;
1844     vos_fileServerEntry_t fileserver_entry;
1845     int iserv, iservaddr, ientryaddr, is_dup;
1846     struct hostent *host;
1847
1848     if (!CellHandleIsValid(c_handle, &tst)) {
1849         goto fail_afsclient_AFSServerGetBegin;
1850     }
1851
1852     if (iterationIdP == NULL) {
1853         tst = ADMITERATIONIDPNULL;
1854         goto fail_afsclient_AFSServerGetBegin;
1855     }
1856
1857     if ((serv == NULL) || (iter == NULL)) {
1858         tst = ADMNOMEM;
1859         goto fail_afsclient_AFSServerGetBegin;
1860     }
1861
1862   restart:
1863     LOCK_GLOBAL_MUTEX;
1864     if (c_handle->server_list != NULL && c_handle->server_ttl < time(NULL)) {
1865         serv_cache = c_handle->server_list;
1866         c_handle->server_list = NULL;
1867     }
1868     UNLOCK_GLOBAL_MUTEX;
1869
1870     if (c_handle->server_list == NULL) {
1871         if (serv_cache == NULL) {
1872             serv_cache = (server_get_p) calloc(1, sizeof(server_get_t));
1873
1874             if (serv_cache == NULL) {
1875                 tst = ADMNOMEM;
1876                 goto fail_afsclient_AFSServerGetBegin;
1877             }
1878         }
1879
1880         /*
1881          * Retrieve the list of database servers for this cell.
1882          */
1883
1884         if (!afsclient_CellNameGet(c_handle, &cellName, &tst)) {
1885             goto fail_afsclient_AFSServerGetBegin;
1886         }
1887
1888         if (!util_DatabaseServerGetBegin(cellName, &database_iter, &tst)) {
1889             goto fail_afsclient_AFSServerGetBegin;
1890         }
1891
1892         while (util_DatabaseServerGetNext(database_iter, &database_entry, &tst)) {
1893             serv->server[serv->total].serverAddress[0] =
1894                 database_entry.serverAddress;
1895             serv->server[serv->total].serverType = DATABASE_SERVER;
1896             serv->total++;
1897         }
1898
1899         if (tst != ADMITERATORDONE) {
1900             util_DatabaseServerGetDone(database_iter, 0);
1901             goto fail_afsclient_AFSServerGetBegin;
1902         }
1903
1904         if (!util_DatabaseServerGetDone(database_iter, &tst)) {
1905             goto fail_afsclient_AFSServerGetBegin;
1906         }
1907
1908         /*
1909          * Retrieve the list of file servers for this cell.
1910          */
1911
1912         if (!vos_FileServerGetBegin(c_handle, 0, &fileserver_iter, &tst)) {
1913             goto fail_afsclient_AFSServerGetBegin;
1914         }
1915
1916         while (vos_FileServerGetNext(fileserver_iter, &fileserver_entry, &tst)) {
1917             /*
1918              * See if any of the addresses returned in this fileserver_entry
1919              * structure already exist in the list of servers we're building.
1920              * If not, create a new record for this server.
1921              */
1922             is_dup = 0;
1923             for (iserv = 0; iserv < serv->total; iserv++) {
1924                 for (ientryaddr = 0; ientryaddr < fileserver_entry.count; ientryaddr++) {
1925                     for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS; iservaddr++) {
1926                         if (serv->server[iserv].serverAddress[iservaddr] ==
1927                              fileserver_entry.serverAddress[ientryaddr]) {
1928                             is_dup = 1;
1929                             break;
1930                         }
1931                     }
1932                     if (is_dup) {
1933                         break;
1934                     }
1935                 }
1936                 if (is_dup) {
1937                     break;
1938                 }
1939             }
1940
1941             if (is_dup) {
1942                 serv->server[iserv].serverType |= FILE_SERVER;
1943             } else {
1944                 iserv = serv->total++;
1945                 serv->server[iserv].serverType = FILE_SERVER;
1946             }
1947
1948             /*
1949              * Add the addresses from the vldb list to the serv->server[iserv]
1950              * record.  Remember that VLDB's list-of-addrs is not guaranteed
1951              * to be unique in a particular entry, or to return only one entry
1952              * per machine--so when we add addresses, always check for
1953              * duplicate entries.
1954              */
1955
1956             for (ientryaddr = 0; ientryaddr < fileserver_entry.count; ientryaddr++) {
1957                 for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS; iservaddr++) {
1958                     if (serv->server[iserv].serverAddress[iservaddr] ==
1959                          fileserver_entry.serverAddress[ientryaddr]) {
1960                         break;
1961                     }
1962                 }
1963                 if (iservaddr == AFS_MAX_SERVER_ADDRESS) {
1964                     for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS;
1965                           iservaddr++) {
1966                         if (!serv->server[iserv].serverAddress[iservaddr]) {
1967                             serv->server[iserv].serverAddress[iservaddr] =
1968                                 fileserver_entry.serverAddress[ientryaddr];
1969                             break;
1970                         }
1971                     }
1972                 }
1973             }
1974         }
1975
1976         if (tst != ADMITERATORDONE) {
1977             vos_FileServerGetDone(fileserver_iter, 0);
1978             goto fail_afsclient_AFSServerGetBegin;
1979         }
1980
1981         if (!vos_FileServerGetDone(fileserver_iter, &tst)) {
1982             goto fail_afsclient_AFSServerGetBegin;
1983         }
1984
1985         /*
1986          * Iterate over the list and fill in the hostname of each of the servers
1987          */
1988
1989         for (iserv = 0; iserv < serv->total; iserv++) {
1990             int addr = htonl(serv->server[iserv].serverAddress[0]);
1991             LOCK_GLOBAL_MUTEX;
1992             host = gethostbyaddr((const char *)&addr, sizeof(int), AF_INET);
1993             if (host != NULL) {
1994                 strncpy(serv->server[iserv].serverName, host->h_name,
1995                          AFS_MAX_SERVER_NAME_LEN);
1996                 serv->server[iserv].serverName[AFS_MAX_SERVER_NAME_LEN - 1] = '\0';
1997             }
1998             UNLOCK_GLOBAL_MUTEX;
1999         }
2000     
2001         memcpy(serv_cache, serv, sizeof(server_get_t));
2002     } else {
2003         int race = 0;
2004         LOCK_GLOBAL_MUTEX;
2005         if (c_handle->server_list == NULL)
2006             race = 1;
2007         else
2008             memcpy(serv, c_handle->server_list, sizeof(server_get_t));
2009         UNLOCK_GLOBAL_MUTEX;
2010         if (race)
2011             goto restart;
2012     }
2013
2014     if (IteratorInit
2015             (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL, NULL,
2016              &tst)) {
2017         *iterationIdP = (void *)iter;
2018         rc = 1;
2019     }
2020
2021   fail_afsclient_AFSServerGetBegin:
2022
2023     if (rc == 0) {
2024         if (iter != NULL)
2025             free(iter);
2026         if (serv != NULL)
2027             free(serv);
2028         if (serv_cache != NULL)
2029             free(serv_cache);
2030     } else {
2031         if (serv_cache) {
2032             LOCK_GLOBAL_MUTEX;
2033             /* in case there was a race and we constructed the list twice */
2034             if (c_handle->server_list)
2035                 free(c_handle->server_list);
2036
2037             c_handle->server_list = serv_cache;
2038             c_handle->server_ttl = time(NULL) + SERVER_TTL;
2039             UNLOCK_GLOBAL_MUTEX;
2040         }
2041     }
2042
2043     if (st != NULL)
2044         *st = tst;
2045
2046     return rc;
2047 }
2048
2049 /*
2050  * afsclient_AFSServerGetNext - retrieve the next server in the cell.
2051  *
2052  * PARAMETERS
2053  *
2054  * IN iterationId - an iterator previously returned by
2055  * afsclient_AFSServerGetBegin.
2056  *
2057  * OUT serverEntryP - upon successful completion contains the next server.
2058  *
2059  * LOCKS
2060  *
2061  * No locks are obtained or released by this function
2062  *
2063  * CAUTIONS
2064  *
2065  * None.
2066  *
2067  * RETURN CODES
2068  *
2069  * Returns != 0 upon successful completion.
2070  */
2071
2072 int ADMINAPI
2073 afsclient_AFSServerGetNext(void *iterationId, afs_serverEntry_p serverEntryP,
2074                            afs_status_p st)
2075 {
2076     int rc = 0;
2077     afs_status_t tst = 0;
2078     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2079
2080     if (iterationId == NULL) {
2081         tst = ADMITERATORNULL;
2082         goto fail_afsclient_AFSServerGetNext;
2083     }
2084
2085     if (serverEntryP == NULL) {
2086         tst = ADMUTILSERVERENTRYPNULL;
2087         goto fail_afsclient_AFSServerGetNext;
2088     }
2089
2090     rc = IteratorNext(iter, (void *)serverEntryP, &tst);
2091
2092   fail_afsclient_AFSServerGetNext:
2093
2094     if (st != NULL) {
2095         *st = tst;
2096     }
2097     return rc;
2098 }
2099
2100 /*
2101  * afsclient_AFSServerGetDone - finish using a server iterator.
2102  *
2103  * PARAMETERS
2104  *
2105  * IN iterationId - an iterator previously returned by
2106  * afsclient_AFSServerGetBegin.
2107  *
2108  * LOCKS
2109  *
2110  * No locks are obtained or released by this function
2111  *
2112  * CAUTIONS
2113  *
2114  * None.
2115  *
2116  * RETURN CODES
2117  *
2118  * Returns != 0 upon successful completion.
2119  */
2120
2121 int ADMINAPI
2122 afsclient_AFSServerGetDone(void *iterationId, afs_status_p st)
2123 {
2124     int rc = 0;
2125     afs_status_t tst = 0;
2126     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2127
2128     if (iterationId == NULL) {
2129         tst = ADMITERATORNULL;
2130         goto fail_afsclient_AFSServerGetDone;
2131     }
2132
2133     rc = IteratorDone(iter, &tst);
2134
2135   fail_afsclient_AFSServerGetDone:
2136
2137     if (st != NULL) {
2138         *st = tst;
2139     }
2140     return rc;
2141 }
2142
2143 /*
2144  * afsclient_RPCStatOpen - open an rx connection to a server to retrieve
2145  * statistics.
2146  *
2147  * PARAMETERS
2148  *
2149  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2150  *
2151  * IN serverName - the host name where the server resides.
2152  *
2153  * IN type - what type of process to query
2154  *
2155  * OUT rpcStatHandleP - contains an rx connection to the server of interest
2156  *
2157  * LOCKS
2158  *
2159  * No locks are obtained or released by this function
2160  *
2161  * CAUTIONS
2162  *
2163  * None.
2164  *
2165  * RETURN CODES
2166  *
2167  * Returns != 0 upon successful completion.
2168  */
2169
2170 int ADMINAPI
2171 afsclient_RPCStatOpen(const void *cellHandle, const char *serverName,
2172                       afs_stat_source_t type,
2173                       struct rx_connection **rpcStatHandleP, afs_status_p st)
2174 {
2175     int rc = 0;
2176     afs_status_t tst = 0;
2177     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2178     int servAddr = 0;
2179     int servPort;
2180     struct rx_securityClass *sc;
2181
2182     if (!CellHandleIsValid(cellHandle, &tst)) {
2183         goto fail_afsclient_RPCStatOpen;
2184     }
2185
2186     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2187         goto fail_afsclient_RPCStatOpen;
2188     }
2189
2190     if (rpcStatHandleP == NULL) {
2191         tst = ADMCLIENTRPCSTATHANDLEPNULL;
2192         goto fail_afsclient_RPCStatOpen;
2193     }
2194
2195     switch (type) {
2196
2197     case AFS_BOSSERVER:
2198         servPort = AFSCONF_NANNYPORT;
2199         break;
2200
2201     case AFS_FILESERVER:
2202         servPort = AFSCONF_FILEPORT;
2203         break;
2204
2205     case AFS_KASERVER:
2206         servPort = AFSCONF_KAUTHPORT;
2207         break;
2208
2209     case AFS_PTSERVER:
2210         servPort = AFSCONF_PROTPORT;
2211         break;
2212
2213     case AFS_VOLSERVER:
2214         servPort = AFSCONF_VOLUMEPORT;
2215         break;
2216
2217     case AFS_VLSERVER:
2218         servPort = AFSCONF_VLDBPORT;
2219         break;
2220
2221     case AFS_CLIENT:
2222         servPort = AFSCONF_CALLBACKPORT;
2223         break;
2224
2225     default:
2226         tst = ADMTYPEINVALID;
2227         goto fail_afsclient_RPCStatOpen;
2228     }
2229
2230     /*
2231      * special processing of tokens by server type
2232      */
2233
2234     if (type == AFS_KASERVER) {
2235         if (!c_handle->tokens->kas_token_set) {
2236             tst = ADMCLIENTNOKASTOKENS;
2237             goto fail_afsclient_RPCStatOpen;
2238         }
2239         sc = c_handle->tokens->kas_sc[c_handle->tokens->sc_index];
2240     } else {
2241         sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2242     }
2243
2244     *rpcStatHandleP =
2245         rx_GetCachedConnection(htonl(servAddr), htons(servPort),
2246                                RX_STATS_SERVICE_ID, sc,
2247                                c_handle->tokens->sc_index);
2248
2249     if (*rpcStatHandleP == NULL) {
2250         tst = ADMCLIENTRPCSTATNOCONNECTION;
2251         goto fail_afsclient_RPCStatOpen;
2252     }
2253     rc = 1;
2254
2255   fail_afsclient_RPCStatOpen:
2256
2257     if (st != NULL) {
2258         *st = tst;
2259     }
2260     return rc;
2261 }
2262
2263 /*
2264  * afsclient_RPCStatOpenPort - open an rx connection to a server to retrieve
2265  * statistics.
2266  *
2267  * PARAMETERS
2268  *
2269  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2270  *
2271  * IN serverName - the host name where the server resides.
2272  *
2273  * IN port - the UDP port number where the server resides.
2274  *
2275  * OUT rpcStatHandleP - contains an rx connection to the server of interest
2276  *
2277  * LOCKS
2278  *
2279  * No locks are obtained or released by this function
2280  *
2281  * CAUTIONS
2282  *
2283  * None.
2284  *
2285  * RETURN CODES
2286  *
2287  * Returns != 0 upon successful completion.
2288  */
2289
2290 int ADMINAPI
2291 afsclient_RPCStatOpenPort(const void *cellHandle, const char *serverName,
2292                           const int serverPort,
2293                           struct rx_connection **rpcStatHandleP,
2294                           afs_status_p st)
2295 {
2296     int rc = 0;
2297     afs_status_t tst = 0;
2298     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2299     int servAddr = 0;
2300     struct rx_securityClass *sc;
2301
2302     if (!CellHandleIsValid(cellHandle, &tst)) {
2303         goto fail_afsclient_RPCStatOpenPort;
2304     }
2305
2306     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2307         goto fail_afsclient_RPCStatOpenPort;
2308     }
2309
2310     if (rpcStatHandleP == NULL) {
2311         tst = ADMCLIENTRPCSTATHANDLEPNULL;
2312         goto fail_afsclient_RPCStatOpenPort;
2313     }
2314
2315     /*
2316      * special processing of tokens by server type
2317      */
2318
2319     if (serverPort == AFSCONF_KAUTHPORT) {
2320         if (!c_handle->tokens->kas_token_set) {
2321             tst = ADMCLIENTNOKASTOKENS;
2322             goto fail_afsclient_RPCStatOpenPort;
2323         }
2324         sc = c_handle->tokens->kas_sc[c_handle->tokens->sc_index];
2325     } else {
2326         sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2327     }
2328
2329     *rpcStatHandleP =
2330         rx_GetCachedConnection(htonl(servAddr), htons(serverPort),
2331                                RX_STATS_SERVICE_ID, sc,
2332                                c_handle->tokens->sc_index);
2333
2334     if (*rpcStatHandleP == NULL) {
2335         tst = ADMCLIENTRPCSTATNOCONNECTION;
2336         goto fail_afsclient_RPCStatOpenPort;
2337     }
2338     rc = 1;
2339
2340   fail_afsclient_RPCStatOpenPort:
2341
2342     if (st != NULL) {
2343         *st = tst;
2344     }
2345     return rc;
2346 }
2347
2348 /*
2349  * afsclient_RPCStatClose - close a previously opened rx connection.
2350  *
2351  * PARAMETERS
2352  *
2353  * IN rpcStatHandle - an rx connection returned by afsclient_RPCStatOpen
2354  *
2355  * LOCKS
2356  *
2357  * No locks are obtained or released by this function
2358  *
2359  * CAUTIONS
2360  *
2361  * None.
2362  *
2363  * RETURN CODES
2364  *
2365  * Returns != 0 upon successful completion.
2366  */
2367
2368 int ADMINAPI
2369 afsclient_RPCStatClose(struct rx_connection *rpcStatHandle, afs_status_p st)
2370 {
2371     int rc = 0;
2372     afs_status_t tst = 0;
2373
2374     if (rpcStatHandle == NULL) {
2375         tst = ADMCLIENTRPCSTATHANDLEPNULL;
2376         goto fail_afsclient_RPCStatClose;
2377     }
2378
2379     rx_ReleaseCachedConnection(rpcStatHandle);
2380     rc = 1;
2381   fail_afsclient_RPCStatClose:
2382
2383     if (st != NULL) {
2384         *st = tst;
2385     }
2386     return rc;
2387 }
2388
2389 /*
2390  * afsclient_CMStatOpen - open an rx connection to a server to retrieve
2391  * statistics.
2392  *
2393  * PARAMETERS
2394  *
2395  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2396  *
2397  * IN serverName - the host name where the server resides.
2398  *
2399  * OUT cmStatHandleP - contains an rx connection to the server of interest
2400  *
2401  * LOCKS
2402  *
2403  * No locks are obtained or released by this function
2404  *
2405  * CAUTIONS
2406  *
2407  * None.
2408  *
2409  * RETURN CODES
2410  *
2411  * Returns != 0 upon successful completion.
2412  */
2413
2414 int ADMINAPI
2415 afsclient_CMStatOpen(const void *cellHandle, const char *serverName,
2416                      struct rx_connection **cmStatHandleP, afs_status_p st)
2417 {
2418     int rc = 0;
2419     afs_status_t tst = 0;
2420     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2421     int servAddr = 0;
2422     struct rx_securityClass *sc;
2423
2424     if (!CellHandleIsValid(cellHandle, &tst)) {
2425         goto fail_afsclient_CMStatOpen;
2426     }
2427
2428     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2429         goto fail_afsclient_CMStatOpen;
2430     }
2431
2432     if (cmStatHandleP == NULL) {
2433         tst = ADMCLIENTCMSTATHANDLEPNULL;
2434         goto fail_afsclient_CMStatOpen;
2435     }
2436
2437     sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2438
2439     *cmStatHandleP =
2440         rx_GetCachedConnection(htonl(servAddr), htons(AFSCONF_CALLBACKPORT),
2441                                1, sc, c_handle->tokens->sc_index);
2442
2443     if (*cmStatHandleP == NULL) {
2444         tst = ADMCLIENTCMSTATNOCONNECTION;
2445         goto fail_afsclient_CMStatOpen;
2446     }
2447     rc = 1;
2448
2449   fail_afsclient_CMStatOpen:
2450
2451     if (st != NULL) {
2452         *st = tst;
2453     }
2454     return rc;
2455 }
2456
2457 /*
2458  * afsclient_CMStatOpenPort - open an rx connection to a server to retrieve
2459  * statistics.
2460  *
2461  * PARAMETERS
2462  *
2463  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2464  *
2465  * IN serverName - the host name where the server resides.
2466  *
2467  * IN port - the UDP port number where the server resides.
2468  *
2469  * OUT cmStatHandleP - contains an rx connection to the server of interest
2470  *
2471  * LOCKS
2472  *
2473  * No locks are obtained or released by this function
2474  *
2475  * CAUTIONS
2476  *
2477  * None.
2478  *
2479  * RETURN CODES
2480  *
2481  * Returns != 0 upon successful completion.
2482  */
2483
2484 int ADMINAPI
2485 afsclient_CMStatOpenPort(const void *cellHandle, const char *serverName,
2486                          const int serverPort,
2487                          struct rx_connection **cmStatHandleP,
2488                          afs_status_p st)
2489 {
2490     int rc = 0;
2491     afs_status_t tst = 0;
2492     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2493     int servAddr = 0;
2494     struct rx_securityClass *sc;
2495
2496     if (!CellHandleIsValid(cellHandle, &tst)) {
2497         goto fail_afsclient_CMStatOpenPort;
2498     }
2499
2500     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2501         goto fail_afsclient_CMStatOpenPort;
2502     }
2503
2504     if (cmStatHandleP == NULL) {
2505         tst = ADMCLIENTCMSTATHANDLEPNULL;
2506         goto fail_afsclient_CMStatOpenPort;
2507     }
2508
2509     sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2510
2511     *cmStatHandleP =
2512         rx_GetCachedConnection(htonl(servAddr), htons(serverPort), 1, sc,
2513                                c_handle->tokens->sc_index);
2514
2515     if (*cmStatHandleP == NULL) {
2516         tst = ADMCLIENTCMSTATNOCONNECTION;
2517         goto fail_afsclient_CMStatOpenPort;
2518     }
2519     rc = 1;
2520
2521   fail_afsclient_CMStatOpenPort:
2522
2523     if (st != NULL) {
2524         *st = tst;
2525     }
2526     return rc;
2527 }
2528
2529 /*
2530  * afsclient_CMStatClose - close a previously opened rx connection.
2531  *
2532  * PARAMETERS
2533  *
2534  * IN cmStatHandle - an rx connection returned by afsclient_CMStatOpen
2535  *
2536  * LOCKS
2537  *
2538  * No locks are obtained or released by this function
2539  *
2540  * CAUTIONS
2541  *
2542  * None.
2543  *
2544  * RETURN CODES
2545  *
2546  * Returns != 0 upon successful completion.
2547  */
2548
2549 int ADMINAPI
2550 afsclient_CMStatClose(struct rx_connection *cmStatHandle, afs_status_p st)
2551 {
2552     int rc = 0;
2553     afs_status_t tst = 0;
2554
2555     if (cmStatHandle == NULL) {
2556         tst = ADMCLIENTCMSTATHANDLEPNULL;
2557         goto fail_afsclient_CMStatClose;
2558     }
2559
2560     rx_ReleaseCachedConnection(cmStatHandle);
2561     rc = 1;
2562   fail_afsclient_CMStatClose:
2563
2564     if (st != NULL) {
2565         *st = tst;
2566     }
2567     return rc;
2568 }
2569
2570 /*
2571  * afsclient_RXDebugOpen - open an rxdebug handle to a server.
2572  *
2573  * PARAMETERS
2574  *
2575  * IN serverName - the host name where the server resides.
2576  *
2577  * IN type - what type of process to query
2578  *
2579  * OUT rxdebugHandle_p - contains an rxdebug handle for the server of interest
2580  *
2581  * LOCKS
2582  *
2583  * No locks are obtained or released by this function
2584  *
2585  * CAUTIONS
2586  *
2587  * None.
2588  *
2589  * RETURN CODES
2590  *
2591  * Returns != 0 upon successful completion.
2592  */
2593
2594 int ADMINAPI
2595 afsclient_RXDebugOpen(const char *serverName, afs_stat_source_t type,
2596                       rxdebugHandle_p * rxdebugHandleP, afs_status_p st)
2597 {
2598     int rc = 0;
2599     afs_status_t tst = 0;
2600     int code;
2601     rxdebugHandle_p handle;
2602     rxdebugSocket_t sock;
2603     struct sockaddr_in taddr;
2604     int serverPort;
2605     int serverAddr;
2606
2607     if (rxdebugHandleP == NULL) {
2608         tst = ADMCLIENTRXDEBUGHANDLEPNULL;
2609         goto fail_afsclient_RXDebugOpen;
2610     }
2611
2612     switch (type) {
2613
2614     case AFS_BOSSERVER:
2615         serverPort = AFSCONF_NANNYPORT;
2616         break;
2617
2618     case AFS_FILESERVER:
2619         serverPort = AFSCONF_FILEPORT;
2620         break;
2621
2622     case AFS_KASERVER:
2623         serverPort = AFSCONF_KAUTHPORT;
2624         break;
2625
2626     case AFS_PTSERVER:
2627         serverPort = AFSCONF_PROTPORT;
2628         break;
2629
2630     case AFS_VOLSERVER:
2631         serverPort = AFSCONF_VOLUMEPORT;
2632         break;
2633
2634     case AFS_VLSERVER:
2635         serverPort = AFSCONF_VLDBPORT;
2636         break;
2637
2638     case AFS_CLIENT:
2639         serverPort = AFSCONF_CALLBACKPORT;
2640         break;
2641
2642     default:
2643         tst = ADMTYPEINVALID;
2644         goto fail_afsclient_RXDebugOpen;
2645     }
2646
2647     if (!util_AdminServerAddressGetFromName(serverName, &serverAddr, &tst)) {
2648         goto fail_afsclient_RXDebugOpen;
2649     }
2650
2651     sock = (rxdebugSocket_t) socket(AF_INET, SOCK_DGRAM, 0);
2652     if (sock == INVALID_RXDEBUG_SOCKET) {
2653         tst = ADMSOCKFAIL;
2654         goto fail_afsclient_RXDebugOpen;
2655     }
2656
2657     memset(&taddr, 0, sizeof(taddr));
2658     taddr.sin_family = AF_INET;
2659     taddr.sin_port = 0;
2660     taddr.sin_addr.s_addr = INADDR_ANY;
2661     code = bind(sock, (struct sockaddr *)&taddr, sizeof(taddr));
2662     if (code) {
2663         close(sock);
2664         tst = ADMSOCKFAIL;
2665         goto fail_afsclient_RXDebugOpen;
2666     }
2667
2668     handle = (rxdebugHandle_p) malloc(sizeof(rxdebugHandle_t));
2669     if (!handle) {
2670         close(sock);
2671         tst = ADMNOMEM;
2672         goto fail_afsclient_RXDebugOpen;
2673     }
2674
2675     handle->sock = sock;
2676     handle->ipAddr = serverAddr;
2677     handle->udpPort = serverPort;
2678     handle->firstFlag = 1;
2679     handle->supportedStats = 0;
2680     *rxdebugHandleP = handle;
2681     rc = 1;
2682
2683   fail_afsclient_RXDebugOpen:
2684
2685     if (st != NULL) {
2686         *st = tst;
2687     }
2688     return rc;
2689 }
2690
2691 /*
2692  * afsclient_RXDebugOpenPort - open an rxdebug handle to a server.
2693  *
2694  * PARAMETERS
2695  *
2696  * IN serverName - the host name where the server resides.
2697  *
2698  * IN port - the UDP port number where the server resides.
2699  *
2700  * OUT rxdebugHandle_p - contains an rxdebug handle for the server of interest
2701  *
2702  * LOCKS
2703  *
2704  * No locks are obtained or released by this function
2705  *
2706  * CAUTIONS
2707  *
2708  * None.
2709  *
2710  * RETURN CODES
2711  *
2712  * Returns != 0 upon successful completion.
2713  */
2714
2715 int ADMINAPI
2716 afsclient_RXDebugOpenPort(const char *serverName, int serverPort,
2717                           rxdebugHandle_p * rxdebugHandleP, afs_status_p st)
2718 {
2719     int rc = 0;
2720     afs_status_t tst = 0;
2721     int code;
2722     rxdebugHandle_p handle;
2723     rxdebugSocket_t sock;
2724     struct sockaddr_in taddr;
2725     int serverAddr;
2726
2727     if (rxdebugHandleP == NULL) {
2728         tst = ADMCLIENTRXDEBUGHANDLEPNULL;
2729         goto fail_afsclient_RXDebugOpenPort;
2730     }
2731
2732     if (!util_AdminServerAddressGetFromName(serverName, &serverAddr, &tst)) {
2733         goto fail_afsclient_RXDebugOpenPort;
2734     }
2735
2736     sock = (rxdebugSocket_t) socket(AF_INET, SOCK_DGRAM, 0);
2737     if (sock == INVALID_RXDEBUG_SOCKET) {
2738         tst = ADMSOCKFAIL;
2739         goto fail_afsclient_RXDebugOpenPort;
2740     }
2741
2742     memset(&taddr, 0, sizeof(taddr));
2743     taddr.sin_family = AF_INET;
2744     taddr.sin_port = 0;
2745     taddr.sin_addr.s_addr = INADDR_ANY;
2746     code = bind(sock, (struct sockaddr *)&taddr, sizeof(taddr));
2747     if (code) {
2748         close(sock);
2749         tst = ADMSOCKFAIL;
2750         goto fail_afsclient_RXDebugOpenPort;
2751     }
2752
2753     handle = (rxdebugHandle_p) malloc(sizeof(rxdebugHandle_t));
2754     if (!handle) {
2755         close(sock);
2756         tst = ADMNOMEM;
2757         goto fail_afsclient_RXDebugOpenPort;
2758     }
2759
2760     handle->sock = sock;
2761     handle->ipAddr = serverAddr;
2762     handle->udpPort = serverPort;
2763     handle->firstFlag = 1;
2764     handle->supportedStats = 0;
2765     *rxdebugHandleP = handle;
2766     rc = 1;
2767
2768   fail_afsclient_RXDebugOpenPort:
2769
2770     if (st != NULL) {
2771         *st = tst;
2772     }
2773     return rc;
2774 }
2775
2776 /*
2777  * afsclient_RXDebugClose - close a previously opened rxdebug handle.
2778  *
2779  * PARAMETERS
2780  *
2781  * IN rxdebugHandle - an rxdebug handle returned by afsclient_RXDebugOpen
2782  *
2783  * LOCKS
2784  *
2785  * No locks are obtained or released by this function
2786  *
2787  * CAUTIONS
2788  *
2789  * None.
2790  *
2791  * RETURN CODES
2792  *
2793  * Returns != 0 upon successful completion.
2794  */
2795
2796 int ADMINAPI
2797 afsclient_RXDebugClose(rxdebugHandle_p rxdebugHandle, afs_status_p st)
2798 {
2799     int rc = 0;
2800     afs_status_t tst = 0;
2801
2802     if (rxdebugHandle == NULL) {
2803         tst = ADMCLIENTRXDEBUGHANDLEPNULL;
2804         goto fail_afsclient_RXDebugClose;
2805     }
2806
2807     close(rxdebugHandle->sock);
2808     free(rxdebugHandle);
2809     rc = 1;
2810   fail_afsclient_RXDebugClose:
2811
2812     if (st != NULL) {
2813         *st = tst;
2814     }
2815     return rc;
2816 }