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