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