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>
15 #include <afs/pthread_glock.h>
17 #include "afs/sysincludes.h"
18 #include "afsincludes.h"
24 #include <sys/types.h>
27 #include <sys/utime.h>
29 #include <WINNT/afssw.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
38 #include <arpa/nameser.h>
39 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
40 #include <arpa/nameser_compat.h>
43 #endif /* AFS_AFSDB_ENV */
44 #endif /* AFS_NT40_ENV */
45 #include <afs/afsint.h>
60 #include <afs/afsutil.h>
61 #include "cellconfig.h"
66 #include <cm_config.h>
67 /* cm_dns.h depends on cellconfig.h */
70 #endif /* AFS_AFSDB_ENV */
75 struct afsconf_servPair {
81 static struct afsconf_servPair serviceTable[] = {
82 {"afs", "afs3-fileserver", 7000,},
83 {"afscb", "afs3-callback", 7001,},
84 {"afsprot", "afs3-prserver", 7002,},
85 {"afsvldb", "afs3-vlserver", 7003,},
86 {"afskauth", "afs3-kaserver", 7004,},
87 {"afsvol", "afs3-volserver", 7005,},
88 {"afserror", "afs3-errors", 7006,},
89 {"afsnanny", "afs3-bos", 7007,},
90 {"afsupdate", "afs3-update", 7008,},
91 {"afsrmtsys", "afs3-rmtsys", 7009,},
92 {"afsres", NULL, 7010,},/* residency database for MR-AFS */
93 {"afsremio", NULL, 7011,}, /* remote I/O interface for MR-AFS */
94 {0, 0, 0} /* insert new services before this spot */
98 static int TrimLine(char *abuffer, int abufsize);
99 static int IsClientConfigDirectory(const char *path);
101 static int GetCellNT(struct afsconf_dir *adir);
103 static int afsconf_Check(register struct afsconf_dir *adir);
104 static int afsconf_Touch(register struct afsconf_dir *adir);
105 static int GetCellUnix(struct afsconf_dir *adir);
106 static int afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
108 static int ParseHostLine(char *aline, register struct sockaddr_in *addr,
109 char *aname, char *aclone);
110 static int ParseCellLine(register char *aline, register char *aname,
111 register char *alname);
112 static int afsconf_CloseInternal(register struct afsconf_dir *adir);
113 static int afsconf_Reopen(register struct afsconf_dir *adir);
114 static int SaveKeys(struct afsconf_dir *adir);
117 #define T_AFSDB 18 /* per RFC1183 section 1 */
120 #define T_SRV 33 /* RFC2782 */
124 * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
125 * our code can tell if there is new info in the key files, the cell server db
126 * files or any of the other files (and reopen the thing) if the date on
127 * CellServDB changes.
130 #if defined(AFS_SUN5_ENV) && !defined(__sparcv9)
131 /* Solaris through 10 in 32 bit mode will return EMFILE if fopen can't
132 get an fd <= 255. We allow the fileserver to claim more fds than that.
133 This has always been a problem since pr_Initialize would have the same
134 issue, but hpr_Initialize makes it more likely that we would see this.
135 Work around it. This is not generic. It's coded with the needs of
136 afsconf_* in mind only.
138 http://www.opensolaris.org/os/community/onnv/flag-days/pages/2006042001/
143 struct afsconf_iobuffer {
150 typedef struct afsconf_iobuffer afsconf_FILE;
152 static afsconf_FILE *
153 afsconf_fopen(const char *fname, const char *fmode)
158 if ((fd = open(fname, O_RDONLY)) == -1) {
162 iop = malloc(sizeof(struct afsconf_iobuffer));
169 iop->buffer = malloc(BUFFER);
170 if (iop->buffer == NULL) {
176 iop->ptr = iop->buffer;
177 iop->endptr = iop->buffer;
182 afsconf_fclose(afsconf_FILE *iop)
188 free((void *)iop->buffer);
194 afsconf_fgets(char *s, int n, afsconf_FILE *iop)
202 if (iop->ptr == iop->endptr) {
205 if ((len = read(iop->_file, (void *)iop->buffer, BUFFER)) == -1) {
215 iop->ptr = iop->buffer;
216 iop->endptr = iop->buffer + len;
220 if ((p - s) == (n - 1)) {
230 #define fopen afsconf_fopen
231 #define fclose afsconf_fclose
232 #define fgets afsconf_fgets
234 #define afsconf_FILE FILE
235 #endif /* AFS_SUN5_ENV && ! __sparcv9 */
237 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
239 afsconf_FindService(const char *aname)
241 /* lookup a service name */
243 struct afsconf_servPair *tsp;
245 if (aname == NULL || aname[0] == '\0')
248 #if defined(AFS_OSF_ENV)
249 ts = getservbyname(aname, "");
251 ts = (struct servent *) getservbyname(aname, NULL);
254 /* we found it in /etc/services, so we use this value */
255 return ts->s_port; /* already in network byte order */
258 /* not found in /etc/services, see if it is one of ours */
259 for (tsp = serviceTable; tsp->port; tsp++) {
260 if ((tsp->name && (!strcmp(tsp->name, aname)))
261 || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
262 return htons(tsp->port);
268 afsconf_FindIANAName(const char *aname)
270 /* lookup a service name */
271 struct afsconf_servPair *tsp;
273 if (aname == NULL || aname[0] == '\0')
276 /* see if it is one of ours */
277 for (tsp = serviceTable; tsp->port; tsp++) {
278 if ((tsp->name && (!strcmp(tsp->name, aname)))
279 || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
280 return tsp->ianaName;
286 TrimLine(char *abuffer, int abufsize)
298 strlcpy(tbuffer, tp, sizeof tbuffer);
299 strlcpy(abuffer, tbuffer, abufsize);
304 * IsClientConfigDirectory() -- determine if path matches well-known
305 * client configuration directory.
308 #define IS_SEP(x) ((x) == '\\' || (x) == '/')
309 #else /* AFS_NT40_ENV */
310 #define IS_SEP(x) ((x) == '/')
311 #endif /* AFS_NT40_ENV */
313 IsClientConfigDirectory(const char *path)
315 const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
318 for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
320 cc = tolower(cdir[i]);
321 pc = tolower(path[i]);
329 #else /* AFS_NT40_ENV */
332 #endif /* AFS_NT40_ENV */
338 /* hit end of one or both; allow mismatch in existence of trailing slash */
339 if (cdir[i] != '\0') {
340 if (!IS_SEP(cdir[i]) || (cdir[i + 1] != '\0')) {
344 if (path[i] != '\0') {
345 if (!IS_SEP(path[i]) || (path[i + 1] != '\0')) {
354 afsconf_Check(register struct afsconf_dir *adir)
361 register afs_int32 code;
364 /* NT client CellServDB has different file name than NT server or Unix */
365 if (IsClientConfigDirectory(adir->name)) {
366 if (!afssw_GetClientCellServDBDir(&p)) {
367 strcompose(tbuffer, sizeof(tbuffer), p, "/",
368 AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
372 strncpy(tbuffer, adir->name, sizeof(tbuffer));
373 len = (int)strlen(tbuffer);
374 if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
375 strncat(tbuffer, "\\", sizeof(tbuffer));
377 strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
379 tbuffer[sizeof(tbuffer) - 1] = '\0';
382 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
386 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
387 #endif /* AFS_NT40_ENV */
389 code = stat(tbuffer, &tstat);
393 /* did file change? */
394 if (tstat.st_mtime == adir->timeRead) {
397 /* otherwise file has changed, so reopen it */
398 return afsconf_Reopen(adir);
401 /* set modtime on file */
403 afsconf_Touch(register struct afsconf_dir *adir)
407 struct timeval tvp[2];
412 adir->timeRead = 0; /* just in case */
415 /* NT client CellServDB has different file name than NT server or Unix */
417 if (IsClientConfigDirectory(adir->name)) {
418 if (!afssw_GetClientCellServDBDir(&p)) {
419 strcompose(tbuffer, sizeof(tbuffer), p, "/",
420 AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
423 int len = (int)strlen(tbuffer);
424 if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
425 strncat(tbuffer, "\\", sizeof(tbuffer));
427 strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
429 tbuffer[sizeof(tbuffer) - 1] = '\0';
432 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
436 return _utime(tbuffer, NULL);
439 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
440 gettimeofday(&tvp[0], NULL);
442 return utimes(tbuffer, tvp);
443 #endif /* AFS_NT40_ENV */
447 afsconf_Open(register const char *adir)
449 register struct afsconf_dir *tdir;
450 register afs_int32 code;
453 /* zero structure and fill in name; rest is done by internal routine */
454 tdir = (struct afsconf_dir *)malloc(sizeof(struct afsconf_dir));
455 memset(tdir, 0, sizeof(struct afsconf_dir));
456 tdir->name = strdup(adir);
458 code = afsconf_OpenInternal(tdir, 0, 0);
460 char *afsconf_path, afs_confdir[128];
463 /* Check global place only when local Open failed for whatever reason */
464 if (!(afsconf_path = getenv("AFSCONF"))) {
465 /* 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... */
470 if (!(home_dir = getenv("HOME"))) {
471 /* Our last chance is the "/.AFSCONF" file */
472 fp = fopen("/.AFSCONF", "r");
476 return (struct afsconf_dir *)0;
478 fgets(afs_confdir, 128, fp);
483 sprintf(pathname, "%s/%s", home_dir, ".AFSCONF");
484 fp = fopen(pathname, "r");
486 /* Our last chance is the "/.AFSCONF" file */
487 fp = fopen("/.AFSCONF", "r");
491 return (struct afsconf_dir *)0;
494 fgets(afs_confdir, 128, fp);
497 len = strlen(afs_confdir);
501 return (struct afsconf_dir *)0;
503 if (afs_confdir[len - 1] == '\n') {
504 afs_confdir[len - 1] = 0;
506 afsconf_path = afs_confdir;
508 tdir->name = strdup(afsconf_path);
509 code = afsconf_OpenInternal(tdir, 0, 0);
514 return (struct afsconf_dir *)0;
522 GetCellUnix(struct afsconf_dir *adir)
529 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
530 fp = fopen(tbuffer, "r");
534 rc = fgets(tbuffer, 256, fp);
540 while (*start != '\0' && isspace(*start))
543 while (*p != '\0' && !isspace(*p))
549 adir->cellName = strdup(start);
556 GetCellNT(struct afsconf_dir *adir)
558 if (IsClientConfigDirectory(adir->name)) {
559 /* NT client config dir; ThisCell is in registry (no file). */
560 return afssw_GetClientCellName(&adir->cellName);
562 /* NT server config dir; works just like Unix */
563 return GetCellUnix(adir);
567 /* The following procedures and structs are used on Windows only
568 * to enumerate the Cell information distributed within the
569 * Windows registry. (See src/WINNT/afsd/cm_config.c)
571 typedef struct _cm_enumCellRegistry {
572 afs_uint32 client; /* non-zero if client query */
573 struct afsconf_dir *adir;
574 } cm_enumCellRegistry_t;
577 cm_serverConfigProc(void *rockp, struct sockaddr_in *addrp,
578 char *hostNamep, unsigned short rank)
580 struct afsconf_cell *cellInfop = (struct afsconf_cell *)rockp;
582 if (cellInfop->numServers == MAXHOSTSPERCELL)
585 cellInfop->hostAddr[cellInfop->numServers] = *addrp;
586 strncpy(cellInfop->hostName[cellInfop->numServers], hostNamep, MAXHOSTCHARS);
587 cellInfop->hostName[cellInfop->numServers][MAXHOSTCHARS-1] = '\0';
588 cellInfop->numServers++;
594 cm_enumCellRegistryProc(void *rockp, char * cellNamep)
597 cm_enumCellRegistry_t *enump = (cm_enumCellRegistry_t *)rockp;
598 char linkedName[256] = "";
600 struct afsconf_entry *newEntry;
603 newEntry = malloc(sizeof(struct afsconf_entry));
604 if (newEntry == NULL)
606 newEntry->cellInfo.numServers = 0;
608 code = cm_SearchCellRegistry(enump->client, cellNamep, NULL, linkedName, cm_serverConfigProc, &newEntry->cellInfo);
609 if (code == CM_ERROR_FORCE_DNS_LOOKUP)
610 code = cm_SearchCellByDNS(cellNamep, NULL, &timeout, cm_serverConfigProc, &newEntry->cellInfo);
613 strncpy(newEntry->cellInfo.name, cellNamep, MAXCELLCHARS);
614 newEntry->cellInfo.name[MAXCELLCHARS-1];
616 newEntry->cellInfo.linkedCell = strdup(linkedName);
618 newEntry->cellInfo.linkedCell = NULL;
619 newEntry->cellInfo.timeout = timeout;
620 newEntry->cellInfo.flags = 0;
622 newEntry->next = enump->adir->entries;
623 enump->adir->entries = newEntry;
629 #endif /* AFS_NT40_ENV */
633 afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
637 register char *tp, *bp;
638 register struct afsconf_entry *curEntry;
639 struct afsconf_aliasentry *curAlias;
640 register afs_int32 code;
642 char tbuffer[256], tbuf1[256];
645 cm_enumCellRegistry_t enumCellRegistry = {0, 0};
646 #endif /* AFS_NT40_ENV */
648 /* figure out the local cell name */
651 enumCellRegistry.adir = adir;
653 i = GetCellUnix(adir);
656 #ifndef AFS_FREELANCE_CLIENT /* no local cell not fatal in freelance */
662 /* now parse the individual lines */
666 /* NT client/server have a CellServDB that is the same format as Unix.
667 * However, the NT client uses a different file name
669 if (IsClientConfigDirectory(adir->name)) {
670 /* NT client config dir */
673 enumCellRegistry.client = 1;
675 if (!afssw_GetClientCellServDBDir(&p)) {
676 strcompose(tbuffer, sizeof(tbuffer), p, "/",
677 AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
681 strncpy(tbuffer, adir->name, sizeof(tbuffer));
682 len = (int)strlen(tbuffer);
683 if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
684 strncat(tbuffer, "\\", sizeof(tbuffer));
686 strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
688 tbuffer[sizeof(tbuffer) - 1] = '\0';
691 /* NT server config dir */
692 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
696 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
697 #endif /* AFS_NT40_ENV */
699 if (!stat(tbuffer, &tstat)) {
700 adir->timeRead = tstat.st_mtime;
705 strlcpy(tbuf1, tbuffer, sizeof tbuf1);
706 tf = fopen(tbuffer, "r");
711 /* The CellServDB file is now open.
712 * The following code parses the contents of the
713 * file and creates a list with the first cell entry
714 * in the CellServDB file at the end of the list.
716 * No checking is performed for duplicates.
717 * The side effects of this process are that duplicate
718 * entries appended to the end of the CellServDB file
719 * take precedence and are found in a shorter period
724 tp = fgets(tbuffer, sizeof(tbuffer), tf);
727 TrimLine(tbuffer, sizeof tbuffer); /* remove white space */
728 if (tbuffer[0] == 0 || tbuffer[0] == '\n')
729 continue; /* empty line */
730 if (tbuffer[0] == '>') {
731 char linkedcell[MAXCELLCHARS];
732 /* start new cell item */
734 /* thread this guy on the list */
735 curEntry->next = adir->entries;
736 adir->entries = curEntry;
740 (struct afsconf_entry *)malloc(sizeof(struct afsconf_entry));
741 memset(curEntry, 0, sizeof(struct afsconf_entry));
743 ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
745 afsconf_CloseInternal(adir);
750 if (linkedcell[0] != '\0')
751 curEntry->cellInfo.linkedCell = strdup(linkedcell);
753 /* new host in the current cell */
755 afsconf_CloseInternal(adir);
759 i = curEntry->cellInfo.numServers;
760 if (i < MAXHOSTSPERCELL) {
761 if (cell && !strcmp(cell, curEntry->cellInfo.name))
763 ParseHostLine(tbuffer,
764 &curEntry->cellInfo.hostAddr[i],
765 curEntry->cellInfo.hostName[i],
769 ParseHostLine(tbuffer,
770 &curEntry->cellInfo.hostAddr[i],
771 curEntry->cellInfo.hostName[i], 0);
774 if (code == AFSCONF_SYNTAX) {
775 for (bp = tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
781 "Can't properly parse host line \"%s\" in configuration file %s\n",
786 afsconf_CloseInternal(adir);
789 curEntry->cellInfo.numServers = ++i;
792 "Too many hosts for cell %s in configuration file %s\n",
793 curEntry->cellInfo.name, tbuf1);
797 fclose(tf); /* close the file now */
799 /* end the last partially-completed cell */
801 curEntry->next = adir->entries;
802 adir->entries = curEntry;
807 * Windows maintains a CellServDB list in the Registry
808 * that supercedes the contents of the CellServDB file.
809 * Prepending these entries to the head of the list
810 * is sufficient to enforce the precedence.
812 cm_EnumerateCellRegistry( enumCellRegistry.client,
813 cm_enumCellRegistryProc,
815 #endif /* AFS_NT40_ENV */
817 /* Read in the alias list */
818 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
820 tf = fopen(tbuffer, "r");
824 tp = fgets(tbuffer, sizeof(tbuffer), tf);
827 TrimLine(tbuffer, sizeof tbuffer); /* remove white space */
829 if (tbuffer[0] == '\0' || tbuffer[0] == '\n' || tbuffer[0] == '#')
830 continue; /* empty line */
833 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t')
836 continue; /* invalid line */
838 while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t'))
841 continue; /* invalid line */
844 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' && tp[0] != '\r'
849 curAlias = malloc(sizeof(*curAlias));
850 memset(curAlias, 0, sizeof(*curAlias));
852 strlcpy(curAlias->aliasInfo.aliasName, aliasPtr, sizeof curAlias->aliasInfo.aliasName);
853 strlcpy(curAlias->aliasInfo.realName, tbuffer, sizeof curAlias->aliasInfo.realName);
855 curAlias->next = adir->alias_entries;
856 adir->alias_entries = curAlias;
861 /* now read the fs keys, if possible */
862 adir->keystr = (struct afsconf_keys *)0;
863 afsconf_IntGetKeys(adir);
868 /* parse a line of the form
869 *"128.2.1.3 #hostname" or
870 *"[128.2.1.3] #hostname" for clones
871 * into the appropriate pieces.
874 ParseHostLine(char *aline, register struct sockaddr_in *addr, char *aname,
878 register afs_int32 code;
884 /* FIXME: length of aname unknown here */
885 code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
889 /* FIXME: length of aname unknown here */
890 code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
893 return AFSCONF_SYNTAX;
894 addr->sin_family = AF_INET;
896 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
897 addr->sin_len = sizeof(struct sockaddr_in);
899 tp = (char *)&addr->sin_addr;
907 /* parse a line of the form
908 * ">cellname [linkedcellname] [#comments]"
909 * into the appropriate pieces.
912 ParseCellLine(register char *aline, register char *aname,
913 register char *alname)
916 /* FIXME: length of aname, alname unknown here */
917 code = sscanf(aline, ">%s %s", aname, alname);
921 if (*alname == '#') {
925 return (code > 0 ? 0 : AFSCONF_SYNTAX);
928 /* call aproc(entry, arock, adir) for all cells. Proc must return 0, or we'll stop early and return the code it returns */
930 afsconf_CellApply(struct afsconf_dir *adir,
931 int (*aproc) (struct afsconf_cell * cell, void *arock,
932 struct afsconf_dir * dir), void *arock)
934 register struct afsconf_entry *tde;
935 register afs_int32 code;
937 for (tde = adir->entries; tde; tde = tde->next) {
938 code = (*aproc) (&tde->cellInfo, arock, adir);
948 /* call aproc(entry, arock, adir) for all cell aliases.
949 * Proc must return 0, or we'll stop early and return the code it returns
952 afsconf_CellAliasApply(struct afsconf_dir *adir,
953 int (*aproc) (struct afsconf_cellalias * alias,
954 void *arock, struct afsconf_dir * dir),
957 register struct afsconf_aliasentry *tde;
958 register afs_int32 code;
960 for (tde = adir->alias_entries; tde; tde = tde->next) {
961 code = (*aproc) (&tde->aliasInfo, arock, adir);
971 afs_int32 afsconf_SawCell = 0;
974 afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, char *acellName,
975 char *aservice, struct afsconf_cell *acellInfo,
981 code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
988 cell = (char *)&acellInfo->name;
990 code = afsconf_OpenInternal(adir, cell, clones);
995 #if !defined(AFS_NT40_ENV)
997 afsconf_LookupServer(const char *service, const char *protocol,
998 const char *cellName, unsigned short afsdbPort,
999 int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
1000 unsigned short ports[], unsigned short ipRanks[],
1001 int *numServers, int *ttl, char **arealCellName)
1005 unsigned char answer[1024];
1009 int cellnamelength, fullnamelength;
1016 char *IANAname = (char *) afsconf_FindIANAName(service);
1017 int tservice = afsconf_FindService(service);
1019 realCellName = NULL;
1023 if (tservice <= 0 || !IANAname)
1024 return AFSCONF_NOTFOUND; /* service not found */
1026 if (strchr(cellName,'.'))
1029 cellnamelength=strlen(cellName); /* _ ._ . . \0 */
1030 fullnamelength=cellnamelength+strlen(protocol)+strlen(IANAname)+6;
1031 dotcellname=malloc(fullnamelength);
1033 return AFSCONF_NOTFOUND; /* service not found */
1039 code = snprintf(dotcellname, fullnamelength, "_%s._%s.%s.",
1040 IANAname, protocol, cellName);
1044 code = snprintf(dotcellname, fullnamelength, "%s.",
1049 code = snprintf(dotcellname, fullnamelength, "_%s._%s.%s",
1050 IANAname, protocol, cellName);
1054 code = snprintf(dotcellname, fullnamelength, "%s",
1058 if ((code < 0) || (code >= fullnamelength))
1059 goto findservererror;
1061 len = res_search(dotcellname, C_IN, dnstype, answer, sizeof(answer));
1062 UNLOCK_GLOBAL_MUTEX;
1074 code = AFSCONF_NOTFOUND;
1075 goto findservererror;
1079 p = answer + sizeof(HEADER); /* Skip header */
1080 code = dn_expand(answer, answer + len, p, host, sizeof(host));
1082 code = AFSCONF_NOTFOUND;
1083 goto findservererror;
1086 p += code + QFIXEDSZ; /* Skip name */
1088 while (p < answer + len) {
1089 int type, ttl, size;
1091 code = dn_expand(answer, answer + len, p, host, sizeof(host));
1093 code = AFSCONF_NOTFOUND;
1094 goto findservererror;
1097 p += code; /* Skip the name */
1098 type = (p[0] << 8) | p[1];
1099 p += 4; /* Skip type and class */
1100 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
1101 p += 4; /* Skip the TTL */
1102 size = (p[0] << 8) | p[1];
1103 p += 2; /* Skip the size */
1105 if (type == T_AFSDB) {
1109 afsdb_type = (p[0] << 8) | p[1];
1110 if (afsdb_type == 1) {
1112 * We know this is an AFSDB record for our cell, of the
1113 * right AFSDB type. Write down the true cell name that
1114 * the resolver gave us above.
1116 realCellName = strdup(host);
1119 code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
1121 code = AFSCONF_NOTFOUND;
1122 goto findservererror;
1125 if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) &&
1126 /* Do we want to get TTL data for the A record as well? */
1127 (he = gethostbyname(host))) {
1129 memcpy(&ipaddr, he->h_addr, he->h_length);
1130 cellHostAddrs[server_num] = ipaddr;
1131 ports[server_num] = afsdbPort;
1132 ipRanks[server_num] = 0;
1133 strncpy(cellHostNames[server_num], host,
1134 sizeof(cellHostNames[server_num]));
1137 if (!minttl || ttl < minttl)
1141 if (type == T_SRV) {
1144 code = dn_expand(answer, answer + len, p + 6, host, sizeof(host));
1146 code = AFSCONF_NOTFOUND;
1147 goto findservererror;
1150 if ((server_num < MAXHOSTSPERCELL) &&
1151 /* Do we want to get TTL data for the A record as well? */
1152 (he = gethostbyname(host))) {
1154 memcpy(&ipaddr, he->h_addr, he->h_length);
1155 cellHostAddrs[server_num] = ipaddr;
1156 ipRanks[server_num] = (p[0] << 8) | p[1];
1157 ports[server_num] = (p[4] << 8) | p[5];
1158 /* weight = (p[2] << 8) | p[3]; */
1159 strncpy(cellHostNames[server_num], host,
1160 sizeof(cellHostNames[server_num]));
1163 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 *arealCellName = realCellName;
1184 *numServers = server_num;
1185 *ttl = minttl ? (time(0) + minttl) : 0;
1187 if ( *numServers > 0 )
1190 code = AFSCONF_NOTFOUND;
1198 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1199 struct afsconf_cell *acellInfo)
1201 afs_int32 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,
1224 acellInfo->timeout = ttl;
1225 acellInfo->numServers = numServers;
1226 for (i = 0; i < numServers; i++) {
1227 memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1229 memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1230 acellInfo->hostAddr[i].sin_family = AF_INET;
1231 acellInfo->hostAddr[i].sin_port = ports[i];
1234 strlcpy(acellInfo->name, realCellName,
1235 sizeof(acellInfo->name));
1237 acellInfo->linkedCell = NULL; /* no linked cell */
1238 acellInfo->flags = 0;
1244 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1245 struct afsconf_cell *acellInfo)
1248 int tservice = afsconf_FindService(aservice); /* network byte order */
1249 const char *ianaName = afsconf_FindIANAName(aservice);
1250 struct afsconf_entry DNSce;
1251 afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
1252 char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1253 unsigned short ipRanks[AFSMAXCELLHOSTS];
1254 unsigned short ports[AFSMAXCELLHOSTS]; /* network byte order */
1261 return AFSCONF_NOTFOUND;
1263 tservice = 0; /* port will be assigned by caller */
1266 if (ianaName == NULL)
1267 ianaName = "afs3-vlserver";
1269 DNSce.cellInfo.numServers = 0;
1272 rc = getAFSServer(ianaName, "udp", acellName, tservice,
1273 cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1275 /* ignore the ttl here since this code is only called by transitory programs
1276 * like klog, etc. */
1278 /* If we couldn't find an entry for the requested service
1279 * and that service happens to be the prservice or kaservice
1280 * then fallback to searching for afs3-vlserver and assigning
1281 * the port number here. */
1282 if (rc < 0 && tservice == htons(7002) || tservice == htons(7004)) {
1283 rc = getAFSServer("afs3-vlserver", "udp", acellName, tservice,
1284 cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1287 for (i = 0; i < numServers; i++)
1288 ports[i] = tservice;
1292 if (rc < 0 || numServers == 0)
1295 for (i = 0; i < numServers; i++) {
1296 memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1298 memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1299 acellInfo->hostAddr[i].sin_family = AF_INET;
1301 acellInfo->hostAddr[i].sin_port = ports[i];
1303 acellInfo->hostAddr[i].sin_port = 0;
1306 acellInfo->numServers = numServers;
1307 strlcpy(acellInfo->name, acellName, sizeof acellInfo->name);
1308 acellInfo->linkedCell = NULL; /* no linked cell */
1309 acellInfo->flags = 0;
1312 #endif /* windows */
1313 #endif /* AFS_AFSDB_ENV */
1316 afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
1317 struct afsconf_cell *acellInfo)
1319 register struct afsconf_entry *tce;
1320 struct afsconf_aliasentry *tcae;
1321 struct afsconf_entry *bestce;
1322 register afs_int32 i;
1331 afsconf_Check(adir);
1334 cnLen = (int)(strlen(tcell) + 1);
1335 lcstring(tcell, tcell, cnLen);
1336 afsconf_SawCell = 1; /* will ignore the AFSCELL switch on future */
1337 /* call to afsconf_GetLocalCell: like klog */
1339 i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
1341 UNLOCK_GLOBAL_MUTEX;
1346 cnLen = strlen(tcell);
1347 bestce = (struct afsconf_entry *)0;
1350 UNLOCK_GLOBAL_MUTEX;
1354 /* Look through the list of aliases */
1355 for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
1356 if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
1357 tcell = tcae->aliasInfo.realName;
1362 for (tce = adir->entries; tce; tce = tce->next) {
1363 if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
1364 /* found our cell */
1369 if (strlen(tce->cellInfo.name) < cnLen)
1370 continue; /* clearly wrong */
1371 if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
1373 ambig = 1; /* ambiguous unless we get exact match */
1377 if (!ambig && bestce && bestce->cellInfo.numServers) {
1378 *acellInfo = bestce->cellInfo; /* structure assignment */
1380 tservice = afsconf_FindService(aservice);
1382 UNLOCK_GLOBAL_MUTEX;
1383 return AFSCONF_NOTFOUND; /* service not found */
1385 for (i = 0; i < acellInfo->numServers; i++) {
1386 acellInfo->hostAddr[i].sin_port = tservice;
1389 acellInfo->timeout = 0;
1392 * Until we figure out how to separate out ubik server
1393 * queries from other server queries, only perform gethostbyname()
1394 * lookup on the specified hostnames for the client CellServDB files.
1396 if (IsClientConfigDirectory(adir->name) &&
1397 !(acellInfo->flags & AFSCONF_CELL_FLAG_DNS_QUERIED)) {
1399 short numServers=0; /*Num active servers for the cell */
1400 struct sockaddr_in hostAddr[MAXHOSTSPERCELL]; /*IP addresses for cell's servers */
1401 char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS]; /*Names for cell's servers */
1403 memset(&hostAddr, 0, sizeof(hostAddr));
1404 memset(&hostName, 0, sizeof(hostName));
1406 for ( j=0; j<acellInfo->numServers && numServers < MAXHOSTSPERCELL; j++ ) {
1407 struct hostent *he = gethostbyname(acellInfo->hostName[j]);
1410 if (he && he->h_addrtype == AF_INET) {
1412 /* obtain all the valid address from the list */
1413 for (i=0 ; he->h_addr_list[i] && numServers < MAXHOSTSPERCELL; i++) {
1414 /* check to see if this is a new address; if so insert it into the list */
1416 for (k=0, dup=0; !dup && k < numServers; k++) {
1417 if (hostAddr[k].sin_addr.s_addr == *(u_long *)he->h_addr_list[i])
1423 hostAddr[numServers].sin_family = AF_INET;
1424 hostAddr[numServers].sin_port = acellInfo->hostAddr[0].sin_port;
1425 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
1426 hostAddr[numServers].sin_len = sizeof(struct sockaddr_in);
1428 memcpy(&hostAddr[numServers].sin_addr.s_addr, he->h_addr_list[i], sizeof(long));
1429 strcpy(hostName[numServers], acellInfo->hostName[j]);
1435 hostAddr[numServers] = acellInfo->hostAddr[j];
1436 strcpy(hostName[numServers], acellInfo->hostName[j]);
1441 for (i=0; i<numServers; i++) {
1442 acellInfo->hostAddr[i] = hostAddr[i];
1443 strcpy(acellInfo->hostName[i], hostName[i]);
1445 acellInfo->numServers = numServers;
1446 acellInfo->flags |= AFSCONF_CELL_FLAG_DNS_QUERIED;
1448 UNLOCK_GLOBAL_MUTEX;
1451 UNLOCK_GLOBAL_MUTEX;
1452 #ifdef AFS_AFSDB_ENV
1453 return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
1455 return AFSCONF_NOTFOUND;
1456 #endif /* AFS_AFSDB_ENV */
1461 afsconf_GetLocalCell(register struct afsconf_dir *adir, char *aname,
1464 static int afsconf_showcell = 0;
1470 * If a cell switch was specified in a command, then it should override the
1471 * AFSCELL variable. If a cell was specified, then the afsconf_SawCell flag
1472 * is set and the cell name in the adir structure is used.
1473 * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
1475 if (!afsconf_SawCell && (afscell_path = getenv("AFSCELL"))) {
1476 if (!afsconf_showcell) {
1477 fprintf(stderr, "Note: Operation is performed on cell %s\n",
1479 afsconf_showcell = 1;
1481 strncpy(aname, afscell_path, alen);
1483 afsconf_Check(adir);
1484 if (adir->cellName) {
1485 strncpy(aname, adir->cellName, alen);
1487 code = AFSCONF_UNKNOWN;
1490 UNLOCK_GLOBAL_MUTEX;
1495 afsconf_Close(struct afsconf_dir *adir)
1498 afsconf_CloseInternal(adir);
1502 UNLOCK_GLOBAL_MUTEX;
1507 afsconf_CloseInternal(register struct afsconf_dir *adir)
1509 register struct afsconf_entry *td, *nd;
1510 struct afsconf_aliasentry *ta, *na;
1511 register char *tname;
1513 tname = adir->name; /* remember name, since that's all we preserve */
1515 /* free everything we can find */
1517 free(adir->cellName);
1518 for (td = adir->entries; td; td = nd) {
1520 if (td->cellInfo.linkedCell)
1521 free(td->cellInfo.linkedCell);
1524 for (ta = adir->alias_entries; ta; ta = na) {
1532 memset(adir, 0, sizeof(struct afsconf_dir));
1533 adir->name = tname; /* restore it */
1538 afsconf_Reopen(register struct afsconf_dir *adir)
1540 register afs_int32 code;
1541 code = afsconf_CloseInternal(adir);
1544 code = afsconf_OpenInternal(adir, 0, 0);
1548 /* called during opening of config file */
1550 afsconf_IntGetKeys(struct afsconf_dir *adir)
1554 struct afsconf_keys *tstr;
1555 register afs_int32 code;
1558 /* NT client config dir has no KeyFile; don't risk attempting open
1559 * because there might be a random file of this name if dir is shared.
1561 if (IsClientConfigDirectory(adir->name)) {
1562 adir->keystr = ((struct afsconf_keys *)
1563 malloc(sizeof(struct afsconf_keys)));
1564 adir->keystr->nkeys = 0;
1567 #endif /* AFS_NT40_ENV */
1570 /* compute the key name and other setup */
1571 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1572 tstr = (struct afsconf_keys *)malloc(sizeof(struct afsconf_keys));
1573 adir->keystr = tstr;
1576 fd = open(tbuffer, O_RDONLY);
1579 UNLOCK_GLOBAL_MUTEX;
1582 code = read(fd, tstr, sizeof(struct afsconf_keys));
1584 if (code < sizeof(afs_int32)) {
1586 UNLOCK_GLOBAL_MUTEX;
1590 /* convert key structure to host order */
1591 tstr->nkeys = ntohl(tstr->nkeys);
1593 if (code < sizeof(afs_int32) + (tstr->nkeys*sizeof(struct afsconf_key))) {
1595 UNLOCK_GLOBAL_MUTEX;
1599 for (fd = 0; fd < tstr->nkeys; fd++)
1600 tstr->key[fd].kvno = ntohl(tstr->key[fd].kvno);
1602 UNLOCK_GLOBAL_MUTEX;
1606 /* get keys structure */
1608 afsconf_GetKeys(struct afsconf_dir *adir, struct afsconf_keys *astr)
1610 register afs_int32 code;
1613 code = afsconf_Check(adir);
1615 UNLOCK_GLOBAL_MUTEX;
1616 return AFSCONF_FAILURE;
1618 memcpy(astr, adir->keystr, sizeof(struct afsconf_keys));
1619 UNLOCK_GLOBAL_MUTEX;
1623 /* get latest key */
1625 afsconf_GetLatestKey(struct afsconf_dir * adir, afs_int32 * avno,
1626 struct ktc_encryptionKey *akey)
1630 register struct afsconf_key *tk;
1631 register afs_int32 best;
1632 struct afsconf_key *bestk;
1633 register afs_int32 code;
1636 code = afsconf_Check(adir);
1638 UNLOCK_GLOBAL_MUTEX;
1639 return AFSCONF_FAILURE;
1641 maxa = adir->keystr->nkeys;
1643 best = -1; /* highest kvno we've seen yet */
1644 bestk = (struct afsconf_key *)0; /* ptr to structure providing best */
1645 for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
1646 if (tk->kvno == 999)
1647 continue; /* skip bcrypt keys */
1648 if (tk->kvno > best) {
1653 if (bestk) { /* found any */
1655 memcpy(akey, bestk->key, 8); /* copy out latest key */
1657 *avno = bestk->kvno; /* and kvno to caller */
1658 UNLOCK_GLOBAL_MUTEX;
1661 UNLOCK_GLOBAL_MUTEX;
1662 return AFSCONF_NOTFOUND; /* didn't find any keys */
1665 /* get a particular key */
1667 afsconf_GetKey(void *rock, int avno, struct ktc_encryptionKey *akey)
1669 struct afsconf_dir *adir = (struct afsconf_dir *) rock;
1670 register int i, maxa;
1671 register struct afsconf_key *tk;
1672 register afs_int32 code;
1675 code = afsconf_Check(adir);
1677 UNLOCK_GLOBAL_MUTEX;
1678 return AFSCONF_FAILURE;
1680 maxa = adir->keystr->nkeys;
1682 for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
1683 if (tk->kvno == avno) {
1684 memcpy(akey, tk->key, 8);
1685 UNLOCK_GLOBAL_MUTEX;
1690 UNLOCK_GLOBAL_MUTEX;
1691 return AFSCONF_NOTFOUND;
1694 /* save the key structure in the appropriate file */
1696 SaveKeys(struct afsconf_dir *adir)
1698 struct afsconf_keys tkeys;
1700 register afs_int32 i;
1703 memcpy(&tkeys, adir->keystr, sizeof(struct afsconf_keys));
1705 /* convert it to net byte order */
1706 for (i = 0; i < tkeys.nkeys; i++)
1707 tkeys.key[i].kvno = htonl(tkeys.key[i].kvno);
1708 tkeys.nkeys = htonl(tkeys.nkeys);
1710 /* rewrite keys file */
1711 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1712 fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0600);
1714 return AFSCONF_FAILURE;
1715 i = write(fd, &tkeys, sizeof(tkeys));
1716 if (i != sizeof(tkeys)) {
1718 return AFSCONF_FAILURE;
1721 return AFSCONF_FAILURE;
1726 afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno, char akey[8],
1727 afs_int32 overwrite)
1729 register struct afsconf_keys *tk;
1730 register struct afsconf_key *tkey;
1731 register afs_int32 i;
1738 if (akvno < 0 || akvno > 255) {
1739 UNLOCK_GLOBAL_MUTEX;
1744 for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
1745 if (tkey->kvno == akvno) {
1747 UNLOCK_GLOBAL_MUTEX;
1748 return AFSCONF_KEYINUSE;
1755 if (tk->nkeys >= AFSCONF_MAXKEYS) {
1756 UNLOCK_GLOBAL_MUTEX;
1757 return AFSCONF_FULL;
1759 tkey = &tk->key[tk->nkeys++];
1762 memcpy(tkey->key, akey, 8);
1764 afsconf_Touch(adir);
1765 UNLOCK_GLOBAL_MUTEX;
1769 /* this proc works by sliding the other guys down, rather than using a funny
1770 kvno value, so that callers can count on getting a good key in key[0].
1773 afsconf_DeleteKey(struct afsconf_dir *adir, afs_int32 akvno)
1775 register struct afsconf_keys *tk;
1776 register struct afsconf_key *tkey;
1783 for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
1784 if (tkey->kvno == akvno) {
1790 UNLOCK_GLOBAL_MUTEX;
1791 return AFSCONF_NOTFOUND;
1794 /* otherwise slide the others down. i and tkey point at the guy to delete */
1795 for (; i < tk->nkeys - 1; i++, tkey++) {
1796 tkey->kvno = (tkey + 1)->kvno;
1797 memcpy(tkey->key, (tkey + 1)->key, 8);
1801 afsconf_Touch(adir);
1802 UNLOCK_GLOBAL_MUTEX;