d0f61f106380316dab4c007c0ec20f0e01a19a14
[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 %1024s", &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, "%63s%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 = malloc(sizeof(afs_admin_iterator_t));
1826     server_get_p serv = calloc(1, sizeof(server_get_t));
1827     server_get_p serv_cache = NULL;
1828     const char *cellName = NULL;
1829     void *database_iter;
1830     util_databaseServerEntry_t database_entry;
1831     void *fileserver_iter;
1832     vos_fileServerEntry_t fileserver_entry;
1833     int iserv, iservaddr, ientryaddr, is_dup;
1834     struct hostent *host;
1835
1836     if (!CellHandleIsValid(c_handle, &tst)) {
1837         goto fail_afsclient_AFSServerGetBegin;
1838     }
1839
1840     if (iterationIdP == NULL) {
1841         tst = ADMITERATIONIDPNULL;
1842         goto fail_afsclient_AFSServerGetBegin;
1843     }
1844
1845     if ((serv == NULL) || (iter == NULL)) {
1846         tst = ADMNOMEM;
1847         goto fail_afsclient_AFSServerGetBegin;
1848     }
1849
1850   restart:
1851     LOCK_GLOBAL_MUTEX;
1852     if (c_handle->server_list != NULL && c_handle->server_ttl < time(NULL)) {
1853         serv_cache = c_handle->server_list;
1854         c_handle->server_list = NULL;
1855     }
1856     UNLOCK_GLOBAL_MUTEX;
1857
1858     if (c_handle->server_list == NULL) {
1859         if (serv_cache == NULL) {
1860             serv_cache = (server_get_p) calloc(1, sizeof(server_get_t));
1861
1862             if (serv_cache == NULL) {
1863                 tst = ADMNOMEM;
1864                 goto fail_afsclient_AFSServerGetBegin;
1865             }
1866         }
1867
1868         /*
1869          * Retrieve the list of database servers for this cell.
1870          */
1871
1872         if (!afsclient_CellNameGet(c_handle, &cellName, &tst)) {
1873             goto fail_afsclient_AFSServerGetBegin;
1874         }
1875
1876         if (!util_DatabaseServerGetBegin(cellName, &database_iter, &tst)) {
1877             goto fail_afsclient_AFSServerGetBegin;
1878         }
1879
1880         while (util_DatabaseServerGetNext(database_iter, &database_entry, &tst)) {
1881             serv->server[serv->total].serverAddress[0] =
1882                 database_entry.serverAddress;
1883             serv->server[serv->total].serverType = DATABASE_SERVER;
1884             serv->total++;
1885         }
1886
1887         if (tst != ADMITERATORDONE) {
1888             util_DatabaseServerGetDone(database_iter, 0);
1889             goto fail_afsclient_AFSServerGetBegin;
1890         }
1891
1892         if (!util_DatabaseServerGetDone(database_iter, &tst)) {
1893             goto fail_afsclient_AFSServerGetBegin;
1894         }
1895
1896         /*
1897          * Retrieve the list of file servers for this cell.
1898          */
1899
1900         if (!vos_FileServerGetBegin(c_handle, 0, &fileserver_iter, &tst)) {
1901             goto fail_afsclient_AFSServerGetBegin;
1902         }
1903
1904         while (vos_FileServerGetNext(fileserver_iter, &fileserver_entry, &tst)) {
1905             /*
1906              * See if any of the addresses returned in this fileserver_entry
1907              * structure already exist in the list of servers we're building.
1908              * If not, create a new record for this server.
1909              */
1910             is_dup = 0;
1911             for (iserv = 0; iserv < serv->total; iserv++) {
1912                 for (ientryaddr = 0; ientryaddr < fileserver_entry.count; ientryaddr++) {
1913                     for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS; iservaddr++) {
1914                         if (serv->server[iserv].serverAddress[iservaddr] ==
1915                              fileserver_entry.serverAddress[ientryaddr]) {
1916                             is_dup = 1;
1917                             break;
1918                         }
1919                     }
1920                     if (is_dup) {
1921                         break;
1922                     }
1923                 }
1924                 if (is_dup) {
1925                     break;
1926                 }
1927             }
1928
1929             if (is_dup) {
1930                 serv->server[iserv].serverType |= FILE_SERVER;
1931             } else {
1932                 iserv = serv->total++;
1933                 serv->server[iserv].serverType = FILE_SERVER;
1934             }
1935
1936             /*
1937              * Add the addresses from the vldb list to the serv->server[iserv]
1938              * record.  Remember that VLDB's list-of-addrs is not guaranteed
1939              * to be unique in a particular entry, or to return only one entry
1940              * per machine--so when we add addresses, always check for
1941              * duplicate entries.
1942              */
1943
1944             for (ientryaddr = 0; ientryaddr < fileserver_entry.count; ientryaddr++) {
1945                 for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS; iservaddr++) {
1946                     if (serv->server[iserv].serverAddress[iservaddr] ==
1947                          fileserver_entry.serverAddress[ientryaddr]) {
1948                         break;
1949                     }
1950                 }
1951                 if (iservaddr == AFS_MAX_SERVER_ADDRESS) {
1952                     for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS;
1953                           iservaddr++) {
1954                         if (!serv->server[iserv].serverAddress[iservaddr]) {
1955                             serv->server[iserv].serverAddress[iservaddr] =
1956                                 fileserver_entry.serverAddress[ientryaddr];
1957                             break;
1958                         }
1959                     }
1960                 }
1961             }
1962         }
1963
1964         if (tst != ADMITERATORDONE) {
1965             vos_FileServerGetDone(fileserver_iter, 0);
1966             goto fail_afsclient_AFSServerGetBegin;
1967         }
1968
1969         if (!vos_FileServerGetDone(fileserver_iter, &tst)) {
1970             goto fail_afsclient_AFSServerGetBegin;
1971         }
1972
1973         /*
1974          * Iterate over the list and fill in the hostname of each of the servers
1975          */
1976
1977         for (iserv = 0; iserv < serv->total; iserv++) {
1978             int addr = htonl(serv->server[iserv].serverAddress[0]);
1979             LOCK_GLOBAL_MUTEX;
1980             host = gethostbyaddr((const char *)&addr, sizeof(int), AF_INET);
1981             if (host != NULL) {
1982                 strncpy(serv->server[iserv].serverName, host->h_name,
1983                          AFS_MAX_SERVER_NAME_LEN);
1984                 serv->server[iserv].serverName[AFS_MAX_SERVER_NAME_LEN - 1] = '\0';
1985             }
1986             UNLOCK_GLOBAL_MUTEX;
1987         }
1988     
1989         memcpy(serv_cache, serv, sizeof(server_get_t));
1990     } else {
1991         int race = 0;
1992         LOCK_GLOBAL_MUTEX;
1993         if (c_handle->server_list == NULL)
1994             race = 1;
1995         else
1996             memcpy(serv, c_handle->server_list, sizeof(server_get_t));
1997         UNLOCK_GLOBAL_MUTEX;
1998         if (race)
1999             goto restart;
2000     }
2001
2002     if (IteratorInit
2003             (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL, NULL,
2004              &tst)) {
2005         *iterationIdP = (void *)iter;
2006         rc = 1;
2007     }
2008
2009   fail_afsclient_AFSServerGetBegin:
2010
2011     if (rc == 0) {
2012         if (iter != NULL)
2013             free(iter);
2014         if (serv != NULL)
2015             free(serv);
2016         if (serv_cache != NULL)
2017             free(serv_cache);
2018     } else {
2019         if (serv_cache) {
2020             LOCK_GLOBAL_MUTEX;
2021             /* in case there was a race and we constructed the list twice */
2022             if (c_handle->server_list)
2023                 free(c_handle->server_list);
2024
2025             c_handle->server_list = serv_cache;
2026             c_handle->server_ttl = time(NULL) + SERVER_TTL;
2027             UNLOCK_GLOBAL_MUTEX;
2028         }
2029     }
2030
2031     if (st != NULL)
2032         *st = tst;
2033
2034     return rc;
2035 }
2036
2037 /*
2038  * afsclient_AFSServerGetNext - retrieve the next server in the cell.
2039  *
2040  * PARAMETERS
2041  *
2042  * IN iterationId - an iterator previously returned by
2043  * afsclient_AFSServerGetBegin.
2044  *
2045  * OUT serverEntryP - upon successful completion contains the next server.
2046  *
2047  * LOCKS
2048  *
2049  * No locks are obtained or released by this function
2050  *
2051  * CAUTIONS
2052  *
2053  * None.
2054  *
2055  * RETURN CODES
2056  *
2057  * Returns != 0 upon successful completion.
2058  */
2059
2060 int ADMINAPI
2061 afsclient_AFSServerGetNext(void *iterationId, afs_serverEntry_p serverEntryP,
2062                            afs_status_p st)
2063 {
2064     int rc = 0;
2065     afs_status_t tst = 0;
2066     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2067
2068     if (iterationId == NULL) {
2069         tst = ADMITERATORNULL;
2070         goto fail_afsclient_AFSServerGetNext;
2071     }
2072
2073     if (serverEntryP == NULL) {
2074         tst = ADMUTILSERVERENTRYPNULL;
2075         goto fail_afsclient_AFSServerGetNext;
2076     }
2077
2078     rc = IteratorNext(iter, (void *)serverEntryP, &tst);
2079
2080   fail_afsclient_AFSServerGetNext:
2081
2082     if (st != NULL) {
2083         *st = tst;
2084     }
2085     return rc;
2086 }
2087
2088 /*
2089  * afsclient_AFSServerGetDone - finish using a server iterator.
2090  *
2091  * PARAMETERS
2092  *
2093  * IN iterationId - an iterator previously returned by
2094  * afsclient_AFSServerGetBegin.
2095  *
2096  * LOCKS
2097  *
2098  * No locks are obtained or released by this function
2099  *
2100  * CAUTIONS
2101  *
2102  * None.
2103  *
2104  * RETURN CODES
2105  *
2106  * Returns != 0 upon successful completion.
2107  */
2108
2109 int ADMINAPI
2110 afsclient_AFSServerGetDone(void *iterationId, afs_status_p st)
2111 {
2112     int rc = 0;
2113     afs_status_t tst = 0;
2114     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2115
2116     if (iterationId == NULL) {
2117         tst = ADMITERATORNULL;
2118         goto fail_afsclient_AFSServerGetDone;
2119     }
2120
2121     rc = IteratorDone(iter, &tst);
2122
2123   fail_afsclient_AFSServerGetDone:
2124
2125     if (st != NULL) {
2126         *st = tst;
2127     }
2128     return rc;
2129 }
2130
2131 /*
2132  * afsclient_RPCStatOpen - open an rx connection to a server to retrieve
2133  * statistics.
2134  *
2135  * PARAMETERS
2136  *
2137  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2138  *
2139  * IN serverName - the host name where the server resides.
2140  *
2141  * IN type - what type of process to query
2142  *
2143  * OUT rpcStatHandleP - contains an rx connection to the server of interest
2144  *
2145  * LOCKS
2146  *
2147  * No locks are obtained or released by this function
2148  *
2149  * CAUTIONS
2150  *
2151  * None.
2152  *
2153  * RETURN CODES
2154  *
2155  * Returns != 0 upon successful completion.
2156  */
2157
2158 int ADMINAPI
2159 afsclient_RPCStatOpen(const void *cellHandle, const char *serverName,
2160                       afs_stat_source_t type,
2161                       struct rx_connection **rpcStatHandleP, afs_status_p st)
2162 {
2163     int rc = 0;
2164     afs_status_t tst = 0;
2165     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2166     int servAddr = 0;
2167     int servPort;
2168     struct rx_securityClass *sc;
2169
2170     if (!CellHandleIsValid(cellHandle, &tst)) {
2171         goto fail_afsclient_RPCStatOpen;
2172     }
2173
2174     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2175         goto fail_afsclient_RPCStatOpen;
2176     }
2177
2178     if (rpcStatHandleP == NULL) {
2179         tst = ADMCLIENTRPCSTATHANDLEPNULL;
2180         goto fail_afsclient_RPCStatOpen;
2181     }
2182
2183     switch (type) {
2184
2185     case AFS_BOSSERVER:
2186         servPort = AFSCONF_NANNYPORT;
2187         break;
2188
2189     case AFS_FILESERVER:
2190         servPort = AFSCONF_FILEPORT;
2191         break;
2192
2193     case AFS_KASERVER:
2194         servPort = AFSCONF_KAUTHPORT;
2195         break;
2196
2197     case AFS_PTSERVER:
2198         servPort = AFSCONF_PROTPORT;
2199         break;
2200
2201     case AFS_VOLSERVER:
2202         servPort = AFSCONF_VOLUMEPORT;
2203         break;
2204
2205     case AFS_VLSERVER:
2206         servPort = AFSCONF_VLDBPORT;
2207         break;
2208
2209     case AFS_CLIENT:
2210         servPort = AFSCONF_CALLBACKPORT;
2211         break;
2212
2213     default:
2214         tst = ADMTYPEINVALID;
2215         goto fail_afsclient_RPCStatOpen;
2216     }
2217
2218     /*
2219      * special processing of tokens by server type
2220      */
2221
2222     if (type == AFS_KASERVER) {
2223         if (!c_handle->tokens->kas_token_set) {
2224             tst = ADMCLIENTNOKASTOKENS;
2225             goto fail_afsclient_RPCStatOpen;
2226         }
2227         sc = c_handle->tokens->kas_sc[c_handle->tokens->sc_index];
2228     } else {
2229         sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2230     }
2231
2232     *rpcStatHandleP =
2233         rx_GetCachedConnection(htonl(servAddr), htons(servPort),
2234                                RX_STATS_SERVICE_ID, sc,
2235                                c_handle->tokens->sc_index);
2236
2237     if (*rpcStatHandleP == NULL) {
2238         tst = ADMCLIENTRPCSTATNOCONNECTION;
2239         goto fail_afsclient_RPCStatOpen;
2240     }
2241     rc = 1;
2242
2243   fail_afsclient_RPCStatOpen:
2244
2245     if (st != NULL) {
2246         *st = tst;
2247     }
2248     return rc;
2249 }
2250
2251 /*
2252  * afsclient_RPCStatOpenPort - open an rx connection to a server to retrieve
2253  * statistics.
2254  *
2255  * PARAMETERS
2256  *
2257  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2258  *
2259  * IN serverName - the host name where the server resides.
2260  *
2261  * IN port - the UDP port number where the server resides.
2262  *
2263  * OUT rpcStatHandleP - contains an rx connection to the server of interest
2264  *
2265  * LOCKS
2266  *
2267  * No locks are obtained or released by this function
2268  *
2269  * CAUTIONS
2270  *
2271  * None.
2272  *
2273  * RETURN CODES
2274  *
2275  * Returns != 0 upon successful completion.
2276  */
2277
2278 int ADMINAPI
2279 afsclient_RPCStatOpenPort(const void *cellHandle, const char *serverName,
2280                           const int serverPort,
2281                           struct rx_connection **rpcStatHandleP,
2282                           afs_status_p st)
2283 {
2284     int rc = 0;
2285     afs_status_t tst = 0;
2286     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2287     int servAddr = 0;
2288     struct rx_securityClass *sc;
2289
2290     if (!CellHandleIsValid(cellHandle, &tst)) {
2291         goto fail_afsclient_RPCStatOpenPort;
2292     }
2293
2294     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2295         goto fail_afsclient_RPCStatOpenPort;
2296     }
2297
2298     if (rpcStatHandleP == NULL) {
2299         tst = ADMCLIENTRPCSTATHANDLEPNULL;
2300         goto fail_afsclient_RPCStatOpenPort;
2301     }
2302
2303     /*
2304      * special processing of tokens by server type
2305      */
2306
2307     if (serverPort == AFSCONF_KAUTHPORT) {
2308         if (!c_handle->tokens->kas_token_set) {
2309             tst = ADMCLIENTNOKASTOKENS;
2310             goto fail_afsclient_RPCStatOpenPort;
2311         }
2312         sc = c_handle->tokens->kas_sc[c_handle->tokens->sc_index];
2313     } else {
2314         sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2315     }
2316
2317     *rpcStatHandleP =
2318         rx_GetCachedConnection(htonl(servAddr), htons(serverPort),
2319                                RX_STATS_SERVICE_ID, sc,
2320                                c_handle->tokens->sc_index);
2321
2322     if (*rpcStatHandleP == NULL) {
2323         tst = ADMCLIENTRPCSTATNOCONNECTION;
2324         goto fail_afsclient_RPCStatOpenPort;
2325     }
2326     rc = 1;
2327
2328   fail_afsclient_RPCStatOpenPort:
2329
2330     if (st != NULL) {
2331         *st = tst;
2332     }
2333     return rc;
2334 }
2335
2336 /*
2337  * afsclient_RPCStatClose - close a previously opened rx connection.
2338  *
2339  * PARAMETERS
2340  *
2341  * IN rpcStatHandle - an rx connection returned by afsclient_RPCStatOpen
2342  *
2343  * LOCKS
2344  *
2345  * No locks are obtained or released by this function
2346  *
2347  * CAUTIONS
2348  *
2349  * None.
2350  *
2351  * RETURN CODES
2352  *
2353  * Returns != 0 upon successful completion.
2354  */
2355
2356 int ADMINAPI
2357 afsclient_RPCStatClose(struct rx_connection *rpcStatHandle, afs_status_p st)
2358 {
2359     int rc = 0;
2360     afs_status_t tst = 0;
2361
2362     if (rpcStatHandle == NULL) {
2363         tst = ADMCLIENTRPCSTATHANDLEPNULL;
2364         goto fail_afsclient_RPCStatClose;
2365     }
2366
2367     rx_ReleaseCachedConnection(rpcStatHandle);
2368     rc = 1;
2369   fail_afsclient_RPCStatClose:
2370
2371     if (st != NULL) {
2372         *st = tst;
2373     }
2374     return rc;
2375 }
2376
2377 /*
2378  * afsclient_CMStatOpen - open an rx connection to a server to retrieve
2379  * statistics.
2380  *
2381  * PARAMETERS
2382  *
2383  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2384  *
2385  * IN serverName - the host name where the server resides.
2386  *
2387  * OUT cmStatHandleP - contains an rx connection to the server of interest
2388  *
2389  * LOCKS
2390  *
2391  * No locks are obtained or released by this function
2392  *
2393  * CAUTIONS
2394  *
2395  * None.
2396  *
2397  * RETURN CODES
2398  *
2399  * Returns != 0 upon successful completion.
2400  */
2401
2402 int ADMINAPI
2403 afsclient_CMStatOpen(const void *cellHandle, const char *serverName,
2404                      struct rx_connection **cmStatHandleP, afs_status_p st)
2405 {
2406     int rc = 0;
2407     afs_status_t tst = 0;
2408     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2409     int servAddr = 0;
2410     struct rx_securityClass *sc;
2411
2412     if (!CellHandleIsValid(cellHandle, &tst)) {
2413         goto fail_afsclient_CMStatOpen;
2414     }
2415
2416     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2417         goto fail_afsclient_CMStatOpen;
2418     }
2419
2420     if (cmStatHandleP == NULL) {
2421         tst = ADMCLIENTCMSTATHANDLEPNULL;
2422         goto fail_afsclient_CMStatOpen;
2423     }
2424
2425     sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2426
2427     *cmStatHandleP =
2428         rx_GetCachedConnection(htonl(servAddr), htons(AFSCONF_CALLBACKPORT),
2429                                1, sc, c_handle->tokens->sc_index);
2430
2431     if (*cmStatHandleP == NULL) {
2432         tst = ADMCLIENTCMSTATNOCONNECTION;
2433         goto fail_afsclient_CMStatOpen;
2434     }
2435     rc = 1;
2436
2437   fail_afsclient_CMStatOpen:
2438
2439     if (st != NULL) {
2440         *st = tst;
2441     }
2442     return rc;
2443 }
2444
2445 /*
2446  * afsclient_CMStatOpenPort - open an rx connection to a server to retrieve
2447  * statistics.
2448  *
2449  * PARAMETERS
2450  *
2451  * IN cellHandle - a cellHandle created by afsclient_CellOpen.
2452  *
2453  * IN serverName - the host name where the server resides.
2454  *
2455  * IN port - the UDP port number where the server resides.
2456  *
2457  * OUT cmStatHandleP - contains an rx connection to the server of interest
2458  *
2459  * LOCKS
2460  *
2461  * No locks are obtained or released by this function
2462  *
2463  * CAUTIONS
2464  *
2465  * None.
2466  *
2467  * RETURN CODES
2468  *
2469  * Returns != 0 upon successful completion.
2470  */
2471
2472 int ADMINAPI
2473 afsclient_CMStatOpenPort(const void *cellHandle, const char *serverName,
2474                          const int serverPort,
2475                          struct rx_connection **cmStatHandleP,
2476                          afs_status_p st)
2477 {
2478     int rc = 0;
2479     afs_status_t tst = 0;
2480     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2481     int servAddr = 0;
2482     struct rx_securityClass *sc;
2483
2484     if (!CellHandleIsValid(cellHandle, &tst)) {
2485         goto fail_afsclient_CMStatOpenPort;
2486     }
2487
2488     if (!util_AdminServerAddressGetFromName(serverName, &servAddr, &tst)) {
2489         goto fail_afsclient_CMStatOpenPort;
2490     }
2491
2492     if (cmStatHandleP == NULL) {
2493         tst = ADMCLIENTCMSTATHANDLEPNULL;
2494         goto fail_afsclient_CMStatOpenPort;
2495     }
2496
2497     sc = c_handle->tokens->afs_sc[c_handle->tokens->sc_index];
2498
2499     *cmStatHandleP =
2500         rx_GetCachedConnection(htonl(servAddr), htons(serverPort), 1, sc,
2501                                c_handle->tokens->sc_index);
2502
2503     if (*cmStatHandleP == NULL) {
2504         tst = ADMCLIENTCMSTATNOCONNECTION;
2505         goto fail_afsclient_CMStatOpenPort;
2506     }
2507     rc = 1;
2508
2509   fail_afsclient_CMStatOpenPort:
2510
2511     if (st != NULL) {
2512         *st = tst;
2513     }
2514     return rc;
2515 }
2516
2517 /*
2518  * afsclient_CMStatClose - close a previously opened rx connection.
2519  *
2520  * PARAMETERS
2521  *
2522  * IN cmStatHandle - an rx connection returned by afsclient_CMStatOpen
2523  *
2524  * LOCKS
2525  *
2526  * No locks are obtained or released by this function
2527  *
2528  * CAUTIONS
2529  *
2530  * None.
2531  *
2532  * RETURN CODES
2533  *
2534  * Returns != 0 upon successful completion.
2535  */
2536
2537 int ADMINAPI
2538 afsclient_CMStatClose(struct rx_connection *cmStatHandle, afs_status_p st)
2539 {
2540     int rc = 0;
2541     afs_status_t tst = 0;
2542
2543     if (cmStatHandle == NULL) {
2544         tst = ADMCLIENTCMSTATHANDLEPNULL;
2545         goto fail_afsclient_CMStatClose;
2546     }
2547
2548     rx_ReleaseCachedConnection(cmStatHandle);
2549     rc = 1;
2550   fail_afsclient_CMStatClose:
2551
2552     if (st != NULL) {
2553         *st = tst;
2554     }
2555     return rc;
2556 }
2557
2558 /*
2559  * afsclient_RXDebugOpen - open an rxdebug handle to a server.
2560  *
2561  * PARAMETERS
2562  *
2563  * IN serverName - the host name where the server resides.
2564  *
2565  * IN type - what type of process to query
2566  *
2567  * OUT rxdebugHandle_p - contains an rxdebug handle for the server of interest
2568  *
2569  * LOCKS
2570  *
2571  * No locks are obtained or released by this function
2572  *
2573  * CAUTIONS
2574  *
2575  * None.
2576  *
2577  * RETURN CODES
2578  *
2579  * Returns != 0 upon successful completion.
2580  */
2581
2582 int ADMINAPI
2583 afsclient_RXDebugOpen(const char *serverName, afs_stat_source_t type,
2584                       rxdebugHandle_p * rxdebugHandleP, afs_status_p st)
2585 {
2586     int rc = 0;
2587     afs_status_t tst = 0;
2588     int code;
2589     rxdebugHandle_p handle;
2590     rxdebugSocket_t sock;
2591     struct sockaddr_in taddr;
2592     int serverPort;
2593     int serverAddr;
2594
2595     if (rxdebugHandleP == NULL) {
2596         tst = ADMCLIENTRXDEBUGHANDLEPNULL;
2597         goto fail_afsclient_RXDebugOpen;
2598     }
2599
2600     switch (type) {
2601
2602     case AFS_BOSSERVER:
2603         serverPort = AFSCONF_NANNYPORT;
2604         break;
2605
2606     case AFS_FILESERVER:
2607         serverPort = AFSCONF_FILEPORT;
2608         break;
2609
2610     case AFS_KASERVER:
2611         serverPort = AFSCONF_KAUTHPORT;
2612         break;
2613
2614     case AFS_PTSERVER:
2615         serverPort = AFSCONF_PROTPORT;
2616         break;
2617
2618     case AFS_VOLSERVER:
2619         serverPort = AFSCONF_VOLUMEPORT;
2620         break;
2621
2622     case AFS_VLSERVER:
2623         serverPort = AFSCONF_VLDBPORT;
2624         break;
2625
2626     case AFS_CLIENT:
2627         serverPort = AFSCONF_CALLBACKPORT;
2628         break;
2629
2630     default:
2631         tst = ADMTYPEINVALID;
2632         goto fail_afsclient_RXDebugOpen;
2633     }
2634
2635     if (!util_AdminServerAddressGetFromName(serverName, &serverAddr, &tst)) {
2636         goto fail_afsclient_RXDebugOpen;
2637     }
2638
2639     sock = (rxdebugSocket_t) socket(AF_INET, SOCK_DGRAM, 0);
2640     if (sock == INVALID_RXDEBUG_SOCKET) {
2641         tst = ADMSOCKFAIL;
2642         goto fail_afsclient_RXDebugOpen;
2643     }
2644
2645     memset(&taddr, 0, sizeof(taddr));
2646     taddr.sin_family = AF_INET;
2647     taddr.sin_port = 0;
2648     taddr.sin_addr.s_addr = INADDR_ANY;
2649     code = bind(sock, (struct sockaddr *)&taddr, sizeof(taddr));
2650     if (code) {
2651         close(sock);
2652         tst = ADMSOCKFAIL;
2653         goto fail_afsclient_RXDebugOpen;
2654     }
2655
2656     handle = malloc(sizeof(rxdebugHandle_t));
2657     if (!handle) {
2658         close(sock);
2659         tst = ADMNOMEM;
2660         goto fail_afsclient_RXDebugOpen;
2661     }
2662
2663     handle->sock = sock;
2664     handle->ipAddr = serverAddr;
2665     handle->udpPort = serverPort;
2666     handle->firstFlag = 1;
2667     handle->supportedStats = 0;
2668     *rxdebugHandleP = handle;
2669     rc = 1;
2670
2671   fail_afsclient_RXDebugOpen:
2672
2673     if (st != NULL) {
2674         *st = tst;
2675     }
2676     return rc;
2677 }
2678
2679 /*
2680  * afsclient_RXDebugOpenPort - open an rxdebug handle to a server.
2681  *
2682  * PARAMETERS
2683  *
2684  * IN serverName - the host name where the server resides.
2685  *
2686  * IN port - the UDP port number where the server resides.
2687  *
2688  * OUT rxdebugHandle_p - contains an rxdebug handle for the server of interest
2689  *
2690  * LOCKS
2691  *
2692  * No locks are obtained or released by this function
2693  *
2694  * CAUTIONS
2695  *
2696  * None.
2697  *
2698  * RETURN CODES
2699  *
2700  * Returns != 0 upon successful completion.
2701  */
2702
2703 int ADMINAPI
2704 afsclient_RXDebugOpenPort(const char *serverName, int serverPort,
2705                           rxdebugHandle_p * rxdebugHandleP, afs_status_p st)
2706 {
2707     int rc = 0;
2708     afs_status_t tst = 0;
2709     int code;
2710     rxdebugHandle_p handle;
2711     rxdebugSocket_t sock;
2712     struct sockaddr_in taddr;
2713     int serverAddr;
2714
2715     if (rxdebugHandleP == NULL) {
2716         tst = ADMCLIENTRXDEBUGHANDLEPNULL;
2717         goto fail_afsclient_RXDebugOpenPort;
2718     }
2719
2720     if (!util_AdminServerAddressGetFromName(serverName, &serverAddr, &tst)) {
2721         goto fail_afsclient_RXDebugOpenPort;
2722     }
2723
2724     sock = (rxdebugSocket_t) socket(AF_INET, SOCK_DGRAM, 0);
2725     if (sock == INVALID_RXDEBUG_SOCKET) {
2726         tst = ADMSOCKFAIL;
2727         goto fail_afsclient_RXDebugOpenPort;
2728     }
2729
2730     memset(&taddr, 0, sizeof(taddr));
2731     taddr.sin_family = AF_INET;
2732     taddr.sin_port = 0;
2733     taddr.sin_addr.s_addr = INADDR_ANY;
2734     code = bind(sock, (struct sockaddr *)&taddr, sizeof(taddr));
2735     if (code) {
2736         close(sock);
2737         tst = ADMSOCKFAIL;
2738         goto fail_afsclient_RXDebugOpenPort;
2739     }
2740
2741     handle = malloc(sizeof(rxdebugHandle_t));
2742     if (!handle) {
2743         close(sock);
2744         tst = ADMNOMEM;
2745         goto fail_afsclient_RXDebugOpenPort;
2746     }
2747
2748     handle->sock = sock;
2749     handle->ipAddr = serverAddr;
2750     handle->udpPort = serverPort;
2751     handle->firstFlag = 1;
2752     handle->supportedStats = 0;
2753     *rxdebugHandleP = handle;
2754     rc = 1;
2755
2756   fail_afsclient_RXDebugOpenPort:
2757
2758     if (st != NULL) {
2759         *st = tst;
2760     }
2761     return rc;
2762 }
2763
2764 /*
2765  * afsclient_RXDebugClose - close a previously opened rxdebug handle.
2766  *
2767  * PARAMETERS
2768  *
2769  * IN rxdebugHandle - an rxdebug handle returned by afsclient_RXDebugOpen
2770  *
2771  * LOCKS
2772  *
2773  * No locks are obtained or released by this function
2774  *
2775  * CAUTIONS
2776  *
2777  * None.
2778  *
2779  * RETURN CODES
2780  *
2781  * Returns != 0 upon successful completion.
2782  */
2783
2784 int ADMINAPI
2785 afsclient_RXDebugClose(rxdebugHandle_p rxdebugHandle, afs_status_p st)
2786 {
2787     int rc = 0;
2788     afs_status_t tst = 0;
2789
2790     if (rxdebugHandle == NULL) {
2791         tst = ADMCLIENTRXDEBUGHANDLEPNULL;
2792         goto fail_afsclient_RXDebugClose;
2793     }
2794
2795     close(rxdebugHandle->sock);
2796     free(rxdebugHandle);
2797     rc = 1;
2798   fail_afsclient_RXDebugClose:
2799
2800     if (st != NULL) {
2801         *st = tst;
2802     }
2803     return rc;
2804 }