2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #include <sys/utime.h>
19 #include <WINNT/afssw.h>
24 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
25 #include <arpa/nameser_compat.h>
28 #include <afs/pthread_glock.h>
29 #include <afs/afsint.h>
33 #include <afs/afsutil.h>
35 #include "cellconfig.h"
40 #include <cm_config.h>
41 /* cm_dns.h depends on cellconfig.h */
48 struct afsconf_servPair
{
54 static struct afsconf_servPair serviceTable
[] = {
55 {"afs", "afs3-fileserver", 7000,},
56 {"afscb", "afs3-callback", 7001,},
57 {"afsprot", "afs3-prserver", 7002,},
58 {"afsvldb", "afs3-vlserver", 7003,},
59 {"afskauth", "afs3-kaserver", 7004,},
60 {"afsvol", "afs3-volserver", 7005,},
61 {"afserror", "afs3-errors", 7006,},
62 {"afsnanny", "afs3-bos", 7007,},
63 {"afsupdate", "afs3-update", 7008,},
64 {"afsrmtsys", "afs3-rmtsys", 7009,},
65 {"afsres", NULL
, 7010,},/* residency database for MR-AFS */
66 {"afsremio", NULL
, 7011,}, /* remote I/O interface for MR-AFS */
67 {0, 0, 0} /* insert new services before this spot */
71 static int TrimLine(char *abuffer
, int abufsize
);
73 static int GetCellNT(struct afsconf_dir
*adir
);
75 static int GetCellUnix(struct afsconf_dir
*adir
);
76 static int afsconf_OpenInternal(struct afsconf_dir
*adir
, char *cell
,
78 static int ParseHostLine(char *aline
, struct sockaddr_in
*addr
,
79 char *aname
, char *aclone
);
80 static int ParseCellLine(char *aline
, char *aname
,
82 static int afsconf_CloseInternal(struct afsconf_dir
*adir
);
83 static int afsconf_Reopen(struct afsconf_dir
*adir
);
86 #define T_AFSDB 18 /* per RFC1183 section 1 */
89 #define T_SRV 33 /* RFC2782 */
93 * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
94 * our code can tell if there is new info in the key files, the cell server db
95 * files or any of the other files (and reopen the thing) if the date on
99 #if defined(AFS_SUN5_ENV) && !defined(__sparcv9)
100 /* Solaris through 10 in 32 bit mode will return EMFILE if fopen can't
101 get an fd <= 255. We allow the fileserver to claim more fds than that.
102 This has always been a problem since pr_Initialize would have the same
103 issue, but hpr_Initialize makes it more likely that we would see this.
104 Work around it. This is not generic. It's coded with the needs of
105 afsconf_* in mind only.
107 http://www.opensolaris.org/os/community/onnv/flag-days/pages/2006042001/
112 struct afsconf_iobuffer
{
119 typedef struct afsconf_iobuffer afsconf_FILE
;
121 static afsconf_FILE
*
122 afsconf_fopen(const char *fname
, const char *fmode
)
127 if ((fd
= open(fname
, O_RDONLY
)) == -1) {
131 iop
= malloc(sizeof(struct afsconf_iobuffer
));
138 iop
->buffer
= malloc(BUFFER
);
139 if (iop
->buffer
== NULL
) {
145 iop
->ptr
= iop
->buffer
;
146 iop
->endptr
= iop
->buffer
;
151 afsconf_fclose(afsconf_FILE
*iop
)
163 afsconf_fgets(char *s
, int n
, afsconf_FILE
*iop
)
171 if (iop
->ptr
== iop
->endptr
) {
174 if ((len
= read(iop
->_file
, (void *)iop
->buffer
, BUFFER
)) == -1) {
184 iop
->ptr
= iop
->buffer
;
185 iop
->endptr
= iop
->buffer
+ len
;
189 if ((p
- s
) == (n
- 1)) {
199 #define fopen afsconf_fopen
200 #define fclose afsconf_fclose
201 #define fgets afsconf_fgets
203 #define afsconf_FILE FILE
204 #endif /* AFS_SUN5_ENV && ! __sparcv9 */
206 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
208 afsconf_FindService(const char *aname
)
210 /* lookup a service name */
212 struct afsconf_servPair
*tsp
;
214 if (aname
== NULL
|| aname
[0] == '\0')
217 #if defined(AFS_OSF_ENV)
218 ts
= getservbyname(aname
, "");
220 ts
= (struct servent
*) getservbyname(aname
, NULL
);
223 /* we found it in /etc/services, so we use this value */
224 return ts
->s_port
; /* already in network byte order */
227 /* not found in /etc/services, see if it is one of ours */
228 for (tsp
= serviceTable
; tsp
->port
; tsp
++) {
229 if ((tsp
->name
&& (!strcmp(tsp
->name
, aname
)))
230 || (tsp
->ianaName
&& (!strcmp(tsp
->ianaName
, aname
))))
231 return htons(tsp
->port
);
237 afsconf_FindIANAName(const char *aname
)
239 /* lookup a service name */
240 struct afsconf_servPair
*tsp
;
242 if (aname
== NULL
|| aname
[0] == '\0')
245 /* see if it is one of ours */
246 for (tsp
= serviceTable
; tsp
->port
; tsp
++) {
247 if ((tsp
->name
&& (!strcmp(tsp
->name
, aname
)))
248 || (tsp
->ianaName
&& (!strcmp(tsp
->ianaName
, aname
))))
249 return tsp
->ianaName
;
255 TrimLine(char *abuffer
, int abufsize
)
267 strlcpy(tbuffer
, tp
, sizeof tbuffer
);
268 strlcpy(abuffer
, tbuffer
, abufsize
);
273 * IsClientConfigDirectory() -- determine if path matches well-known
274 * client configuration directory.
277 #define IS_SEP(x) ((x) == '\\' || (x) == '/')
278 #else /* AFS_NT40_ENV */
279 #define IS_SEP(x) ((x) == '/')
280 #endif /* AFS_NT40_ENV */
282 _afsconf_IsClientConfigDirectory(const char *path
)
284 const char *cdir
= AFSDIR_CLIENT_ETC_DIRPATH
;
287 for (i
= 0; cdir
[i
] != '\0' && path
[i
] != '\0'; i
++) {
289 cc
= tolower(cdir
[i
]);
290 pc
= tolower(path
[i
]);
298 #else /* AFS_NT40_ENV */
301 #endif /* AFS_NT40_ENV */
307 /* hit end of one or both; allow mismatch in existence of trailing slash */
308 if (cdir
[i
] != '\0') {
309 if (!IS_SEP(cdir
[i
]) || (cdir
[i
+ 1] != '\0')) {
313 if (path
[i
] != '\0') {
314 if (!IS_SEP(path
[i
]) || (path
[i
+ 1] != '\0')) {
323 _afsconf_CellServDBPath(struct afsconf_dir
*adir
, char **path
)
327 /* NT client CellServDB has different file name than NT server or Unix */
328 if (_afsconf_IsClientConfigDirectory(adir
->name
)) {
329 if (!afssw_GetClientCellServDBDir(&p
)) {
330 if (asprintf(path
, "%s/%s", p
, AFSDIR_CELLSERVDB_FILE_NTCLIENT
) < 0)
334 if (asprintf(path
, "%s/%s", adir
->name
,
335 AFSDIR_CELLSERVDB_FILE_NTCLIENT
) < 0)
339 if (asprintf(path
, "%s/%s", adir
->name
, AFSDIR_CELLSERVDB_FILE
) < 0)
346 _afsconf_CellServDBPath(struct afsconf_dir
*adir
, char **path
)
348 if (asprintf(path
, "%s/%s", adir
->name
, AFSDIR_CELLSERVDB_FILE
) < 0)
351 #endif /* AFS_NT40_ENV */
354 _afsconf_UpToDate(struct afsconf_dir
*adir
)
359 time_t now
= time(0);
361 if (adir
->timeRead
&& (adir
->timeCheck
== now
)) {
362 return 1; /* stat no more than once a second */
364 adir
->timeCheck
= now
;
366 _afsconf_CellServDBPath(adir
, &cellservDB
);
367 if (cellservDB
== NULL
)
370 code
= stat(cellservDB
, &tstat
);
373 return 0; /* Can't throw the error, so just say we're not up to date */
375 /* did file change? */
376 if (tstat
.st_mtime
== adir
->timeRead
)
379 /* otherwise file has changed */
384 afsconf_UpToDate(void *rock
)
389 code
= _afsconf_UpToDate(rock
);
396 _afsconf_Check(struct afsconf_dir
*adir
)
398 /* did configuration change? */
399 if (_afsconf_UpToDate(adir
))
402 /* otherwise file has changed, so reopen it */
403 return afsconf_Reopen(adir
);
406 /* set modtime on file */
408 _afsconf_Touch(struct afsconf_dir
*adir
)
413 struct timeval tvp
[2];
416 adir
->timeRead
= 0; /* just in case */
419 _afsconf_CellServDBPath(adir
, &cellservDB
);
420 if (cellservDB
== NULL
)
424 code
= _utime(cellservDB
, NULL
);
426 gettimeofday(&tvp
[0], NULL
);
428 code
= utimes(cellservDB
, tvp
);
429 #endif /* AFS_NT40_ENV */
436 afsconf_Open(const char *adir
)
438 struct afsconf_dir
*tdir
;
442 /* zero structure and fill in name; rest is done by internal routine */
443 tdir
= calloc(1, sizeof(struct afsconf_dir
));
444 tdir
->name
= strdup(adir
);
446 code
= afsconf_OpenInternal(tdir
, 0, 0);
448 char *afsconf_path
, afs_confdir
[128];
451 /* Check global place only when local Open failed for whatever reason */
452 if (!(afsconf_path
= getenv("AFSCONF"))) {
453 /* The "AFSCONF" environment (or contents of "/.AFSCONF") will be typically set to something like "/afs/<cell>/common/etc" where, by convention, the default files for "ThisCell" and "CellServDB" will reside; note that a major drawback is that a given afs client on that cell may NOT contain the same contents... */
459 if (!(home_dir
= getenv("HOME"))) {
460 /* Our last chance is the "/.AFSCONF" file */
461 fp
= fopen("/.AFSCONF", "r");
466 char *pathname
= NULL
;
468 r
= asprintf(&pathname
, "%s/%s", home_dir
, ".AFSCONF");
469 if (r
< 0 || pathname
== NULL
)
472 fp
= fopen(pathname
, "r");
476 /* Our last chance is the "/.AFSCONF" file */
477 fp
= fopen("/.AFSCONF", "r");
482 if (fgets(afs_confdir
, 128, fp
) != NULL
)
483 len
= strlen(afs_confdir
);
488 if (afs_confdir
[len
- 1] == '\n') {
489 afs_confdir
[len
- 1] = 0;
491 afsconf_path
= afs_confdir
;
493 tdir
->name
= strdup(afsconf_path
);
494 code
= afsconf_OpenInternal(tdir
, 0, 0);
510 GetCellUnix(struct afsconf_dir
*adir
)
517 strcompose(tbuffer
, 256, adir
->name
, "/", AFSDIR_THISCELL_FILE
,
519 fp
= fopen(tbuffer
, "r");
523 rc
= fgets(tbuffer
, 256, fp
);
529 while (*start
!= '\0' && isspace(*start
))
532 while (*p
!= '\0' && !isspace(*p
))
538 adir
->cellName
= strdup(start
);
545 GetCellNT(struct afsconf_dir
*adir
)
547 if (_afsconf_IsClientConfigDirectory(adir
->name
)) {
548 /* NT client config dir; ThisCell is in registry (no file). */
549 return afssw_GetClientCellName(&adir
->cellName
);
551 /* NT server config dir; works just like Unix */
552 return GetCellUnix(adir
);
556 /* The following procedures and structs are used on Windows only
557 * to enumerate the Cell information distributed within the
558 * Windows registry. (See src/WINNT/afsd/cm_config.c)
560 typedef struct _cm_enumCellRegistry
{
561 afs_uint32 client
; /* non-zero if client query */
562 struct afsconf_dir
*adir
;
563 } cm_enumCellRegistry_t
;
566 cm_serverConfigProc(void *rockp
, struct sockaddr_in
*addrp
,
567 char *hostNamep
, unsigned short rank
)
569 struct afsconf_cell
*cellInfop
= (struct afsconf_cell
*)rockp
;
571 if (cellInfop
->numServers
== MAXHOSTSPERCELL
)
574 cellInfop
->hostAddr
[cellInfop
->numServers
] = *addrp
;
575 strncpy(cellInfop
->hostName
[cellInfop
->numServers
], hostNamep
, MAXHOSTCHARS
);
576 cellInfop
->hostName
[cellInfop
->numServers
][MAXHOSTCHARS
-1] = '\0';
577 cellInfop
->numServers
++;
583 cm_enumCellRegistryProc(void *rockp
, char * cellNamep
)
586 cm_enumCellRegistry_t
*enump
= (cm_enumCellRegistry_t
*)rockp
;
587 char linkedName
[256] = "";
589 struct afsconf_entry
*newEntry
;
592 newEntry
= malloc(sizeof(struct afsconf_entry
));
593 if (newEntry
== NULL
)
595 newEntry
->cellInfo
.numServers
= 0;
597 code
= cm_SearchCellRegistry(enump
->client
, cellNamep
, NULL
, linkedName
, cm_serverConfigProc
, &newEntry
->cellInfo
);
598 if (code
== CM_ERROR_FORCE_DNS_LOOKUP
)
599 code
= cm_SearchCellByDNS(cellNamep
, NULL
, &timeout
, cm_serverConfigProc
, &newEntry
->cellInfo
);
602 strncpy(newEntry
->cellInfo
.name
, cellNamep
, MAXCELLCHARS
);
603 newEntry
->cellInfo
.name
[MAXCELLCHARS
-1];
605 newEntry
->cellInfo
.linkedCell
= strdup(linkedName
);
607 newEntry
->cellInfo
.linkedCell
= NULL
;
608 newEntry
->cellInfo
.timeout
= timeout
;
609 newEntry
->cellInfo
.flags
= 0;
611 newEntry
->next
= enump
->adir
->entries
;
612 enump
->adir
->entries
= newEntry
;
618 #endif /* AFS_NT40_ENV */
622 afsconf_OpenInternal(struct afsconf_dir
*adir
, char *cell
,
627 struct afsconf_entry
*curEntry
;
628 struct afsconf_aliasentry
*curAlias
;
636 cm_enumCellRegistry_t enumCellRegistry
= {0, 0};
637 #endif /* AFS_NT40_ENV */
639 /* init the keys queue before any call to afsconf_CloseInternal() */
640 _afsconf_InitKeys(adir
);
642 /* figure out the local cell name */
645 enumCellRegistry
.adir
= adir
;
647 i
= GetCellUnix(adir
);
650 #ifndef AFS_FREELANCE_CLIENT /* no local cell not fatal in freelance */
656 /* now parse the individual lines */
659 _afsconf_CellServDBPath(adir
, &cellservDB
);
662 if (_afsconf_IsClientConfigDirectory(adir
->name
))
663 enumCellRegistry
.client
= 1;
664 #endif /* AFS_NT40_ENV */
666 if (!stat(cellservDB
, &tstat
)) {
667 adir
->timeRead
= tstat
.st_mtime
;
672 tf
= fopen(cellservDB
, "r");
677 /* The CellServDB file is now open.
678 * The following code parses the contents of the
679 * file and creates a list with the first cell entry
680 * in the CellServDB file at the end of the list.
682 * No checking is performed for duplicates.
683 * The side effects of this process are that duplicate
684 * entries appended to the end of the CellServDB file
685 * take precedence and are found in a shorter period
690 tp
= fgets(tbuffer
, sizeof(tbuffer
), tf
);
693 TrimLine(tbuffer
, sizeof tbuffer
); /* remove white space */
694 if (tbuffer
[0] == 0 || tbuffer
[0] == '\n')
695 continue; /* empty line */
696 if (tbuffer
[0] == '>') {
697 char linkedcell
[MAXCELLCHARS
];
698 /* start new cell item */
700 /* thread this guy on the list */
701 curEntry
->next
= adir
->entries
;
702 adir
->entries
= curEntry
;
705 curEntry
= calloc(1, sizeof(struct afsconf_entry
));
707 ParseCellLine(tbuffer
, curEntry
->cellInfo
.name
, linkedcell
);
709 afsconf_CloseInternal(adir
);
714 if (linkedcell
[0] != '\0')
715 curEntry
->cellInfo
.linkedCell
= strdup(linkedcell
);
717 /* new host in the current cell */
719 afsconf_CloseInternal(adir
);
723 i
= curEntry
->cellInfo
.numServers
;
724 if (i
< MAXHOSTSPERCELL
) {
725 if (cell
&& !strcmp(cell
, curEntry
->cellInfo
.name
))
727 ParseHostLine(tbuffer
,
728 &curEntry
->cellInfo
.hostAddr
[i
],
729 curEntry
->cellInfo
.hostName
[i
],
733 ParseHostLine(tbuffer
,
734 &curEntry
->cellInfo
.hostAddr
[i
],
735 curEntry
->cellInfo
.hostName
[i
], 0);
738 if (code
== AFSCONF_SYNTAX
) {
739 for (bp
= tbuffer
; *bp
!= '\n'; bp
++) { /* Take out the <cr> from the buffer */
745 "Can't properly parse host line \"%s\" in configuration file %s\n",
746 tbuffer
, cellservDB
);
750 afsconf_CloseInternal(adir
);
753 curEntry
->cellInfo
.numServers
= ++i
;
756 "Too many hosts for cell %s in configuration file %s\n",
757 curEntry
->cellInfo
.name
, cellservDB
);
761 fclose(tf
); /* close the file now */
764 /* end the last partially-completed cell */
766 curEntry
->next
= adir
->entries
;
767 adir
->entries
= curEntry
;
772 * Windows maintains a CellServDB list in the Registry
773 * that supercedes the contents of the CellServDB file.
774 * Prepending these entries to the head of the list
775 * is sufficient to enforce the precedence.
777 cm_EnumerateCellRegistry( enumCellRegistry
.client
,
778 cm_enumCellRegistryProc
,
780 #endif /* AFS_NT40_ENV */
782 /* Read in the alias list */
783 strcompose(tbuffer
, 256, adir
->name
, "/", AFSDIR_CELLALIAS_FILE
,
786 tf
= fopen(tbuffer
, "r");
790 tp
= fgets(tbuffer
, sizeof(tbuffer
), tf
);
793 TrimLine(tbuffer
, sizeof tbuffer
); /* remove white space */
795 if (tbuffer
[0] == '\0' || tbuffer
[0] == '\n' || tbuffer
[0] == '#')
796 continue; /* empty line */
799 while (tp
[0] != '\0' && tp
[0] != ' ' && tp
[0] != '\t')
802 continue; /* invalid line */
804 while (tp
[0] != '\0' && (tp
[0] == ' ' || tp
[0] == '\t'))
807 continue; /* invalid line */
810 while (tp
[0] != '\0' && tp
[0] != ' ' && tp
[0] != '\t' && tp
[0] != '\r'
815 curAlias
= calloc(1, sizeof(*curAlias
));
817 strlcpy(curAlias
->aliasInfo
.aliasName
, aliasPtr
, sizeof curAlias
->aliasInfo
.aliasName
);
818 strlcpy(curAlias
->aliasInfo
.realName
, tbuffer
, sizeof curAlias
->aliasInfo
.realName
);
820 curAlias
->next
= adir
->alias_entries
;
821 adir
->alias_entries
= curAlias
;
827 /* now read the fs keys, if possible */
828 code
= _afsconf_LoadKeys(adir
);
832 code
= _afsconf_LoadRealms(adir
);
837 /* parse a line of the form
838 *"128.2.1.3 #hostname" or
839 *"[128.2.1.3] #hostname" for clones
840 * into the appropriate pieces.
843 ParseHostLine(char *aline
, struct sockaddr_in
*addr
, char *aname
,
854 /* FIXME: length of aname unknown here */
855 code
= sscanf(aline
, "[%d.%d.%d.%d] #%s", &c
[0], &c
[1], &c
[2], &c
[3],
860 /* FIXME: length of aname unknown here */
861 code
= sscanf(aline
, "%d.%d.%d.%d #%s", &c
[0], &c
[1], &c
[2], &c
[3],
865 return AFSCONF_SYNTAX
;
866 for(i
= 0; i
< 4; ++i
) {
867 if (c
[i
] < 0 || c
[i
] > 255) {
868 fprintf(stderr
, "Illegal IP address %d.%d.%d.%d\n", c
[0], c
[1],
870 return AFSCONF_SYNTAX
;
873 addr
->sin_family
= AF_INET
;
875 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
876 addr
->sin_len
= sizeof(struct sockaddr_in
);
878 tp
= (char *)&addr
->sin_addr
;
886 /* parse a line of the form
887 * ">cellname [linkedcellname] [#comments]"
888 * into the appropriate pieces.
891 ParseCellLine(char *aline
, char *aname
,
895 /* FIXME: length of aname, alname unknown here */
896 code
= sscanf(aline
, ">%s %s", aname
, alname
);
900 if (*alname
== '#') {
904 return (code
> 0 ? 0 : AFSCONF_SYNTAX
);
907 /* call aproc(entry, arock, adir) for all cells. Proc must return 0, or we'll stop early and return the code it returns */
909 afsconf_CellApply(struct afsconf_dir
*adir
,
910 int (*aproc
) (struct afsconf_cell
* cell
, void *arock
,
911 struct afsconf_dir
* dir
), void *arock
)
913 struct afsconf_entry
*tde
;
916 for (tde
= adir
->entries
; tde
; tde
= tde
->next
) {
917 code
= (*aproc
) (&tde
->cellInfo
, arock
, adir
);
927 /* call aproc(entry, arock, adir) for all cell aliases.
928 * Proc must return 0, or we'll stop early and return the code it returns
931 afsconf_CellAliasApply(struct afsconf_dir
*adir
,
932 int (*aproc
) (struct afsconf_cellalias
* alias
,
933 void *arock
, struct afsconf_dir
* dir
),
936 struct afsconf_aliasentry
*tde
;
939 for (tde
= adir
->alias_entries
; tde
; tde
= tde
->next
) {
940 code
= (*aproc
) (&tde
->aliasInfo
, arock
, adir
);
950 afs_int32 afsconf_SawCell
= 0;
953 afsconf_GetExtendedCellInfo(struct afsconf_dir
*adir
, char *acellName
,
954 char *aservice
, struct afsconf_cell
*acellInfo
,
960 code
= afsconf_GetCellInfo(adir
, acellName
, aservice
, acellInfo
);
967 cell
= (char *)&acellInfo
->name
;
969 code
= afsconf_OpenInternal(adir
, cell
, clones
);
973 #if !defined(AFS_NT40_ENV)
975 afsconf_LookupServer(const char *service
, const char *protocol
,
976 const char *cellName
, unsigned short afsdbPort
,
977 afs_uint32
*cellHostAddrs
, char cellHostNames
[][MAXHOSTCHARS
],
978 unsigned short ports
[], unsigned short ipRanks
[],
979 int *numServers
, int *ttl
, char **arealCellName
)
984 unsigned char answer
[4096];
986 char *dotcellname
= NULL
;
994 char *IANAname
= (char *) afsconf_FindIANAName(service
);
995 int tservice
= afsconf_FindService(service
);
1001 if (tservice
<= 0 || !IANAname
)
1002 return AFSCONF_NOTFOUND
; /* service not found */
1004 if (strchr(cellName
,'.'))
1007 #ifdef HAVE_RES_RETRANSRETRY
1008 if ((_res
.options
& RES_INIT
) == 0 && res_init() == -1)
1012 * Rx timeout is typically 56 seconds; limit user experience to
1024 r
= asprintf(&dotcellname
, "_%s._%s.%s.", IANAname
, protocol
, cellName
);
1028 r
= asprintf(&dotcellname
, "%s.", cellName
);
1032 r
= asprintf(&dotcellname
, "_%s._%s.%s", IANAname
, protocol
, cellName
);
1036 r
= asprintf(&dotcellname
, "%s", cellName
);
1039 if (r
< 0 || dotcellname
== NULL
)
1040 goto findservererror
;
1043 len
= res_search(dotcellname
, C_IN
, dnstype
, answer
, sizeof(answer
));
1044 UNLOCK_GLOBAL_MUTEX
;
1046 if (dotcellname
!= NULL
) {
1061 code
= AFSCONF_NOTFOUND
;
1062 goto findservererror
;
1066 p
= answer
+ sizeof(HEADER
); /* Skip header */
1067 code
= dn_expand(answer
, answer
+ len
, p
, host
, sizeof(host
));
1069 code
= AFSCONF_NOTFOUND
;
1070 goto findservererror
;
1073 p
+= code
+ QFIXEDSZ
; /* Skip name */
1075 while (p
< answer
+ len
) {
1076 int type
, ttl
, size
;
1078 code
= dn_expand(answer
, answer
+ len
, p
, host
, sizeof(host
));
1080 code
= AFSCONF_NOTFOUND
;
1081 goto findservererror
;
1084 p
+= code
; /* Skip the name */
1085 type
= (p
[0] << 8) | p
[1];
1086 p
+= 4; /* Skip type and class */
1087 ttl
= (p
[0] << 24) | (p
[1] << 16) | (p
[2] << 8) | p
[3];
1088 p
+= 4; /* Skip the TTL */
1089 size
= (p
[0] << 8) | p
[1];
1090 p
+= 2; /* Skip the size */
1092 if (type
== T_AFSDB
) {
1096 afsdb_type
= (p
[0] << 8) | p
[1];
1097 if (afsdb_type
== 1) {
1099 * We know this is an AFSDB record for our cell, of the
1100 * right AFSDB type. Write down the true cell name that
1101 * the resolver gave us above.
1104 realCellName
= strdup(host
);
1107 code
= dn_expand(answer
, answer
+ len
, p
+ 2, host
, sizeof(host
));
1109 code
= AFSCONF_NOTFOUND
;
1110 goto findservererror
;
1113 if ((afsdb_type
== 1) && (server_num
< MAXHOSTSPERCELL
) &&
1114 /* Do we want to get TTL data for the A record as well? */
1115 (he
= gethostbyname(host
))) {
1116 if (he
->h_addrtype
== AF_INET
) {
1118 memcpy(&ipaddr
, he
->h_addr
, sizeof(ipaddr
));
1119 cellHostAddrs
[server_num
] = ipaddr
;
1120 ports
[server_num
] = afsdbPort
;
1121 ipRanks
[server_num
] = 0;
1122 strncpy(cellHostNames
[server_num
], host
,
1123 sizeof(cellHostNames
[server_num
]));
1125 if (!minttl
|| ttl
< minttl
)
1130 if (type
== T_SRV
) {
1132 /* math here: _ is 1, _ ._ is 3, _ ._ . is 4. then the domain. */
1133 if ((strncmp(host
+ 1, IANAname
, strlen(IANAname
)) == 0) &&
1134 (strncmp(host
+ strlen(IANAname
) + 3, protocol
,
1135 strlen(protocol
)) == 0)) {
1137 realCellName
= strdup(host
+ strlen(IANAname
) +
1138 strlen(protocol
) + 4);
1141 code
= dn_expand(answer
, answer
+ len
, p
+ 6, host
, sizeof(host
));
1143 code
= AFSCONF_NOTFOUND
;
1144 goto findservererror
;
1147 if ((server_num
< MAXHOSTSPERCELL
) &&
1148 /* Do we want to get TTL data for the A record as well? */
1149 (he
= gethostbyname(host
))) {
1150 if (he
->h_addrtype
== AF_INET
) {
1153 memcpy(&ipaddr
, he
->h_addr
, sizeof(ipaddr
));
1154 cellHostAddrs
[server_num
] = ipaddr
;
1155 ipRanks
[server_num
] = (p
[0] << 8) | p
[1];
1156 ports
[server_num
] = htons((p
[4] << 8) | p
[5]);
1157 /* weight = (p[2] << 8) | p[3]; */
1158 strncpy(cellHostNames
[server_num
], host
,
1159 sizeof(cellHostNames
[server_num
]));
1162 if (!minttl
|| ttl
< minttl
)
1171 if (server_num
== 0) { /* No AFSDB or SRV records */
1172 code
= AFSCONF_NOTFOUND
;
1173 goto findservererror
;
1177 /* Convert the real cell name to lowercase */
1178 for (p
= (unsigned char *)realCellName
; *p
; p
++)
1182 *numServers
= server_num
;
1183 *ttl
= minttl
? (time(0) + minttl
) : 0;
1185 if ( *numServers
> 0 ) {
1187 *arealCellName
= realCellName
;
1189 code
= AFSCONF_NOTFOUND
;
1192 if (code
&& realCellName
)
1198 afsconf_GetAfsdbInfo(char *acellName
, char *aservice
,
1199 struct afsconf_cell
*acellInfo
)
1201 afs_uint32 cellHostAddrs
[AFSMAXCELLHOSTS
];
1202 char cellHostNames
[AFSMAXCELLHOSTS
][MAXHOSTCHARS
];
1203 unsigned short ipRanks
[AFSMAXCELLHOSTS
];
1204 unsigned short ports
[AFSMAXCELLHOSTS
];
1205 char *realCellName
= NULL
;
1206 int ttl
, numServers
, i
;
1207 char *service
= aservice
;
1209 unsigned short afsdbport
;
1211 service
= "afs3-vlserver";
1212 afsdbport
= htons(7003);
1215 afsdbport
= afsconf_FindService(service
);
1217 code
= afsconf_LookupServer((const char *)service
, "udp",
1218 (const char *)acellName
, afsdbport
,
1219 cellHostAddrs
, cellHostNames
,
1220 ports
, ipRanks
, &numServers
, &ttl
,
1223 /* If we couldn't find an entry for the requested service
1224 * and that service happens to be the prservice or kaservice
1225 * then fallback to searching for afs3-vlserver and assigning
1226 * the port number here. */
1227 if (code
< 0 && (afsdbport
== htons(7002) || afsdbport
== htons(7004))) {
1228 code
= afsconf_LookupServer("afs3-vlserver", "udp",
1229 (const char *)acellName
, afsdbport
,
1230 cellHostAddrs
, cellHostNames
,
1231 ports
, ipRanks
, &numServers
, &ttl
,
1234 for (i
= 0; i
< numServers
; i
++)
1235 ports
[i
] = afsdbport
;
1239 acellInfo
->timeout
= ttl
;
1240 acellInfo
->numServers
= numServers
;
1241 for (i
= 0; i
< numServers
; i
++) {
1242 memcpy(&acellInfo
->hostAddr
[i
].sin_addr
.s_addr
, &cellHostAddrs
[i
],
1244 memcpy(acellInfo
->hostName
[i
], cellHostNames
[i
], MAXHOSTCHARS
);
1245 acellInfo
->hostAddr
[i
].sin_family
= AF_INET
;
1246 acellInfo
->hostAddr
[i
].sin_port
= ports
[i
];
1249 strlcpy(acellInfo
->name
, realCellName
,
1250 sizeof(acellInfo
->name
));
1252 realCellName
= NULL
;
1255 acellInfo
->linkedCell
= NULL
; /* no linked cell */
1256 acellInfo
->flags
= 0;
1262 afsconf_GetAfsdbInfo(char *acellName
, char *aservice
,
1263 struct afsconf_cell
*acellInfo
)
1266 int tservice
= afsconf_FindService(aservice
); /* network byte order */
1267 const char *ianaName
= afsconf_FindIANAName(aservice
);
1268 struct afsconf_entry DNSce
;
1269 afs_uint32 cellHostAddrs
[AFSMAXCELLHOSTS
];
1270 char cellHostNames
[AFSMAXCELLHOSTS
][MAXHOSTCHARS
];
1271 unsigned short ipRanks
[AFSMAXCELLHOSTS
];
1272 unsigned short ports
[AFSMAXCELLHOSTS
]; /* network byte order */
1279 return AFSCONF_NOTFOUND
;
1281 tservice
= 0; /* port will be assigned by caller */
1284 if (ianaName
== NULL
)
1285 ianaName
= "afs3-vlserver";
1287 DNSce
.cellInfo
.numServers
= 0;
1290 rc
= getAFSServer(ianaName
, "udp", acellName
, tservice
,
1291 cellHostAddrs
, cellHostNames
, ports
, ipRanks
, &numServers
,
1293 /* ignore the ttl here since this code is only called by transitory programs
1294 * like klog, etc. */
1296 /* If we couldn't find an entry for the requested service
1297 * and that service happens to be the prservice or kaservice
1298 * then fallback to searching for afs3-vlserver and assigning
1299 * the port number here. */
1300 if (rc
< 0 && (tservice
== htons(7002) || tservice
== htons(7004))) {
1301 rc
= getAFSServer("afs3-vlserver", "udp", acellName
, tservice
,
1302 cellHostAddrs
, cellHostNames
, ports
, ipRanks
, &numServers
,
1305 for (i
= 0; i
< numServers
; i
++)
1306 ports
[i
] = tservice
;
1310 if (rc
< 0 || numServers
== 0)
1313 for (i
= 0; i
< numServers
; i
++) {
1314 memcpy(&acellInfo
->hostAddr
[i
].sin_addr
.s_addr
, &cellHostAddrs
[i
],
1315 sizeof(afs_uint32
));
1316 memcpy(acellInfo
->hostName
[i
], cellHostNames
[i
], MAXHOSTCHARS
);
1317 acellInfo
->hostAddr
[i
].sin_family
= AF_INET
;
1319 acellInfo
->hostAddr
[i
].sin_port
= ports
[i
];
1321 acellInfo
->hostAddr
[i
].sin_port
= 0;
1324 acellInfo
->numServers
= numServers
;
1325 strlcpy(acellInfo
->name
, acellName
, sizeof acellInfo
->name
);
1326 acellInfo
->linkedCell
= NULL
; /* no linked cell */
1327 acellInfo
->flags
= 0;
1330 #endif /* windows */
1333 afsconf_GetCellInfo(struct afsconf_dir
*adir
, char *acellName
, char *aservice
,
1334 struct afsconf_cell
*acellInfo
)
1336 struct afsconf_entry
*tce
;
1337 struct afsconf_aliasentry
*tcae
;
1338 struct afsconf_entry
*bestce
;
1348 _afsconf_Check(adir
);
1351 cnLen
= (int)(strlen(tcell
) + 1);
1352 lcstring(tcell
, tcell
, cnLen
);
1353 afsconf_SawCell
= 1; /* will ignore the AFSCELL switch on future */
1354 /* call to afsconf_GetLocalCell: like klog */
1356 i
= afsconf_GetLocalCell(adir
, tbuffer
, sizeof(tbuffer
));
1358 UNLOCK_GLOBAL_MUTEX
;
1363 cnLen
= strlen(tcell
);
1364 bestce
= (struct afsconf_entry
*)0;
1367 UNLOCK_GLOBAL_MUTEX
;
1371 /* Look through the list of aliases */
1372 for (tcae
= adir
->alias_entries
; tcae
; tcae
= tcae
->next
) {
1373 if (strcasecmp(tcae
->aliasInfo
.aliasName
, tcell
) == 0) {
1374 tcell
= tcae
->aliasInfo
.realName
;
1379 for (tce
= adir
->entries
; tce
; tce
= tce
->next
) {
1380 if (strcasecmp(tce
->cellInfo
.name
, tcell
) == 0) {
1381 /* found our cell */
1386 if (strlen(tce
->cellInfo
.name
) < cnLen
)
1387 continue; /* clearly wrong */
1388 if (strncasecmp(tce
->cellInfo
.name
, tcell
, cnLen
) == 0) {
1390 ambig
= 1; /* ambiguous unless we get exact match */
1394 if (!ambig
&& bestce
&& bestce
->cellInfo
.numServers
) {
1395 *acellInfo
= bestce
->cellInfo
; /* structure assignment */
1397 tservice
= afsconf_FindService(aservice
);
1399 UNLOCK_GLOBAL_MUTEX
;
1400 return AFSCONF_NOTFOUND
; /* service not found */
1402 for (i
= 0; i
< acellInfo
->numServers
; i
++) {
1403 acellInfo
->hostAddr
[i
].sin_port
= tservice
;
1406 acellInfo
->timeout
= 0;
1409 * Until we figure out how to separate out ubik server
1410 * queries from other server queries, only perform gethostbyname()
1411 * lookup on the specified hostnames for the client CellServDB files.
1413 if (_afsconf_IsClientConfigDirectory(adir
->name
) &&
1414 !(acellInfo
->flags
& AFSCONF_CELL_FLAG_DNS_QUERIED
)) {
1416 short numServers
=0; /*Num active servers for the cell */
1417 struct sockaddr_in hostAddr
[MAXHOSTSPERCELL
]; /*IP addresses for cell's servers */
1418 char hostName
[MAXHOSTSPERCELL
][MAXHOSTCHARS
]; /*Names for cell's servers */
1420 memset(&hostAddr
, 0, sizeof(hostAddr
));
1421 memset(&hostName
, 0, sizeof(hostName
));
1423 for ( j
=0; j
<acellInfo
->numServers
&& numServers
< MAXHOSTSPERCELL
; j
++ ) {
1424 struct hostent
*he
= gethostbyname(acellInfo
->hostName
[j
]);
1427 if (he
&& he
->h_addrtype
== AF_INET
) {
1429 /* obtain all the valid address from the list */
1430 for (i
=0 ; he
->h_addr_list
[i
] && numServers
< MAXHOSTSPERCELL
; i
++) {
1431 /* check to see if this is a new address; if so insert it into the list */
1434 memcpy(&addr
, he
->h_addr_list
[i
], sizeof(addr
));
1435 for (k
=0, dup
=0; !dup
&& k
< numServers
; k
++) {
1436 if (hostAddr
[k
].sin_addr
.s_addr
== addr
) {
1443 hostAddr
[numServers
].sin_family
= AF_INET
;
1444 hostAddr
[numServers
].sin_port
= acellInfo
->hostAddr
[0].sin_port
;
1445 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
1446 hostAddr
[numServers
].sin_len
= sizeof(struct sockaddr_in
);
1448 memcpy(&hostAddr
[numServers
].sin_addr
.s_addr
, he
->h_addr_list
[i
], sizeof(afs_uint32
));
1449 strcpy(hostName
[numServers
], acellInfo
->hostName
[j
]);
1455 hostAddr
[numServers
] = acellInfo
->hostAddr
[j
];
1456 strcpy(hostName
[numServers
], acellInfo
->hostName
[j
]);
1461 for (i
=0; i
<numServers
; i
++) {
1462 acellInfo
->hostAddr
[i
] = hostAddr
[i
];
1463 strcpy(acellInfo
->hostName
[i
], hostName
[i
]);
1465 acellInfo
->numServers
= numServers
;
1466 acellInfo
->flags
|= AFSCONF_CELL_FLAG_DNS_QUERIED
;
1468 UNLOCK_GLOBAL_MUTEX
;
1471 UNLOCK_GLOBAL_MUTEX
;
1472 return afsconf_GetAfsdbInfo(tcell
, aservice
, acellInfo
);
1477 * Get the current localcell name.
1479 * Internal function to get a pointer to the local cell name.
1480 * This function must be called with the global afsconf lock held.
1482 * @param[in] adir afsconf object
1483 * @param[out] aname address to a char pointer
1484 * @param[in] check always perform a config check, even if the
1485 * the AFSCELL name is set.
1489 * @retval AFSCONF_NOCELLNAME cannot determine local cell name
1494 _afsconf_GetLocalCell(struct afsconf_dir
*adir
, char **pname
, int check
)
1496 static int afsconf_showcell
= 0;
1501 * If a cell switch was specified in a command, then it should override the
1502 * AFSCELL variable. If a cell was specified, then the afsconf_SawCell flag
1503 * is set and the cell name in the adir structure is used.
1504 * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
1505 * Optionally, check the configuration, even if using the environment variable.
1507 if (!afsconf_SawCell
&& (afscell_path
= getenv("AFSCELL"))) {
1509 _afsconf_Check(adir
);
1511 if (!afsconf_showcell
) {
1512 fprintf(stderr
, "Note: Operation is performed on cell %s\n",
1514 afsconf_showcell
= 1;
1516 *pname
= afscell_path
;
1518 _afsconf_Check(adir
);
1519 if (adir
->cellName
) {
1520 *pname
= adir
->cellName
;
1522 code
= AFSCONF_NOCELLNAME
;
1528 afsconf_GetLocalCell(struct afsconf_dir
*adir
, char *aname
, afs_int32 alen
)
1531 char *cellname
= NULL
;
1534 code
= _afsconf_GetLocalCell(adir
, &cellname
, 0);
1535 if (!code
&& cellname
) {
1536 strlcpy(aname
, cellname
, alen
);
1538 UNLOCK_GLOBAL_MUTEX
;
1543 afsconf_Close(struct afsconf_dir
*adir
)
1550 afsconf_CloseInternal(adir
);
1554 UNLOCK_GLOBAL_MUTEX
;
1559 afsconf_CloseInternal(struct afsconf_dir
*adir
)
1561 struct afsconf_entry
*td
, *nd
;
1562 struct afsconf_aliasentry
*ta
, *na
;
1569 tname
= adir
->name
; /* remember name, since that's all we preserve */
1571 /* free everything we can find */
1573 free(adir
->cellName
);
1574 for (td
= adir
->entries
; td
; td
= nd
) {
1576 if (td
->cellInfo
.linkedCell
)
1577 free(td
->cellInfo
.linkedCell
);
1580 for (ta
= adir
->alias_entries
; ta
; ta
= na
) {
1585 _afsconf_FreeAllKeys(adir
);
1586 _afsconf_FreeRealms(adir
);
1589 memset(adir
, 0, sizeof(struct afsconf_dir
));
1590 adir
->name
= tname
; /* restore it */
1595 afsconf_Reopen(struct afsconf_dir
*adir
)
1598 code
= afsconf_CloseInternal(adir
);
1601 code
= afsconf_OpenInternal(adir
, 0, 0);