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