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