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