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