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