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