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