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>
17 #include <afs/pthread_glock.h>
19 #include "afs/sysincludes.h"
20 #include "afsincludes.h"
25 #include <sys/types.h>
28 #include <sys/utime.h>
30 #include <WINNT/afssw.h>
32 #include <sys/socket.h>
33 #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"
65 /* cm_dns.h depends on cellconfig.h */
68 #endif /* AFS_AFSDB_ENV */
73 static struct afsconf_servPair serviceTable[] = {
84 {"afsres", 7010,}, /* residency database for MR-AFS */
85 {"afsremio", 7011,}, /* remote I/O interface for MR-AFS */
86 {0, 0} /* insert new services before this spot */
90 static afs_int32 afsconf_FindService(register const char *aname);
91 static int TrimLine(char *abuffer, int abufsize);
93 static int IsClientConfigDirectory(const char *path);
94 static int GetCellNT(struct afsconf_dir *adir);
96 static int afsconf_Check(register struct afsconf_dir *adir);
97 static int afsconf_Touch(register struct afsconf_dir *adir);
98 static int GetCellUnix(struct afsconf_dir *adir);
99 static int afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
101 static int ParseHostLine(char *aline, register struct sockaddr_in *addr,
102 char *aname, char *aclone);
103 static int ParseCellLine(register char *aline, register char *aname,
104 register char *alname);
105 static int afsconf_CloseInternal(register struct afsconf_dir *adir);
106 static int afsconf_Reopen(register struct afsconf_dir *adir);
107 static int SaveKeys(struct afsconf_dir *adir);
110 #define T_AFSDB 18 /* per RFC1183 section 1 */
114 * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
115 * our code can tell if there is new info in the key files, the cell server db
116 * files or any of the other files (and reopen the thing) if the date on
117 * CellServDB changes.
120 #if defined(AFS_SUN5_ENV) && !defined(__sparcv9)
121 /* Solaris through 10 in 32 bit mode will return EMFILE if fopen can't
122 get an fd <= 255. We allow the fileserver to claim more fds than that.
123 This has always been a problem since pr_Initialize would have the same
124 issue, but hpr_Initialize makes it more likely that we would see this.
125 Work around it. This is not generic. It's coded with the needs of
126 afsconf_* in mind only.
128 http://www.opensolaris.org/os/community/onnv/flag-days/pages/2006042001/
133 struct afsconf_iobuffer {
140 typedef struct afsconf_iobuffer afsconf_FILE;
142 static afsconf_FILE *
143 afsconf_fopen(const char *fname, const char *fmode)
148 if ((fd = open(fname, O_RDONLY)) == -1) {
152 iop = malloc(sizeof(struct afsconf_iobuffer));
159 iop->buffer = malloc(BUFFER);
160 if (iop->buffer == NULL) {
166 iop->ptr = iop->buffer;
167 iop->endptr = iop->buffer;
172 afsconf_fclose(afsconf_FILE *iop)
178 free((void *)iop->buffer);
184 afsconf_fgets(char *s, int n, afsconf_FILE *iop)
192 if (iop->ptr == iop->endptr) {
195 if ((len = read(iop->_file, (void *)iop->buffer, BUFFER)) == -1) {
205 iop->ptr = iop->buffer;
206 iop->endptr = iop->buffer + len;
210 if ((p - s) == (n - 1)) {
220 #define fopen afsconf_fopen
221 #define fclose afsconf_fclose
222 #define fgets afsconf_fgets
224 #define afsconf_FILE FILE
225 #endif /* AFS_SUN5_ENV && ! __sparcv9 */
227 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
229 afsconf_FindService(register const char *aname)
231 /* lookup a service name */
233 register struct afsconf_servPair *tsp;
235 #if defined(AFS_OSF_ENV)
236 ts = getservbyname(aname, "");
238 ts = (struct servent *) getservbyname(aname, NULL);
241 /* we found it in /etc/services, so we use this value */
242 return ts->s_port; /* already in network byte order */
245 /* not found in /etc/services, see if it is one of ours */
246 for (tsp = serviceTable;; tsp++) {
247 if (tsp->name == NULL)
249 if (!strcmp(tsp->name, aname))
250 return htons(tsp->port);
255 TrimLine(char *abuffer, int abufsize)
267 strlcpy(tbuffer, tp, sizeof tbuffer);
268 strlcpy(abuffer, tbuffer, abufsize);
274 * IsClientConfigDirectory() -- determine if path matches well-known
275 * client configuration directory.
278 IsClientConfigDirectory(const char *path)
280 const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
283 for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
284 int cc = tolower(cdir[i]);
285 int pc = tolower(path[i]);
298 /* hit end of one or both; allow mismatch in existence of trailing slash */
299 if (cdir[i] != '\0') {
300 if ((cdir[i] != '\\' && cdir[i] != '/') || (cdir[i + 1] != '\0')) {
304 if (path[i] != '\0') {
305 if ((path[i] != '\\' && path[i] != '/') || (path[i + 1] != '\0')) {
311 #endif /* AFS_NT40_ENV */
315 afsconf_Check(register struct afsconf_dir *adir)
322 register afs_int32 code;
325 /* NT client CellServDB has different file name than NT server or Unix */
326 if (IsClientConfigDirectory(adir->name)) {
327 if (!afssw_GetClientCellServDBDir(&p)) {
328 strcompose(tbuffer, sizeof(tbuffer), p, "/",
329 AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
333 strncpy(tbuffer, adir->name, sizeof(tbuffer));
334 len = (int)strlen(tbuffer);
335 if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
336 strncat(tbuffer, "\\", sizeof(tbuffer));
338 strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
340 tbuffer[sizeof(tbuffer) - 1] = '\0';
343 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
347 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
348 #endif /* AFS_NT40_ENV */
350 code = stat(tbuffer, &tstat);
354 /* did file change? */
355 if (tstat.st_mtime == adir->timeRead) {
358 /* otherwise file has changed, so reopen it */
359 return afsconf_Reopen(adir);
362 /* set modtime on file */
364 afsconf_Touch(register struct afsconf_dir *adir)
368 struct timeval tvp[2];
373 adir->timeRead = 0; /* just in case */
376 /* NT client CellServDB has different file name than NT server or Unix */
378 if (IsClientConfigDirectory(adir->name)) {
379 if (!afssw_GetClientCellServDBDir(&p)) {
380 strcompose(tbuffer, sizeof(tbuffer), p, "/",
381 AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
384 int len = (int)strlen(tbuffer);
385 if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
386 strncat(tbuffer, "\\", sizeof(tbuffer));
388 strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
390 tbuffer[sizeof(tbuffer) - 1] = '\0';
393 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
397 return _utime(tbuffer, NULL);
400 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
401 gettimeofday(&tvp[0], NULL);
403 return utimes(tbuffer, tvp);
404 #endif /* AFS_NT40_ENV */
408 afsconf_Open(register const char *adir)
410 register struct afsconf_dir *tdir;
411 register afs_int32 code;
414 /* zero structure and fill in name; rest is done by internal routine */
415 tdir = (struct afsconf_dir *)malloc(sizeof(struct afsconf_dir));
416 memset(tdir, 0, sizeof(struct afsconf_dir));
417 tdir->name = strdup(adir);
419 code = afsconf_OpenInternal(tdir, 0, 0);
421 char *afsconf_path, afs_confdir[128];
424 /* Check global place only when local Open failed for whatever reason */
425 if (!(afsconf_path = getenv("AFSCONF"))) {
426 /* 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... */
431 if (!(home_dir = getenv("HOME"))) {
432 /* Our last chance is the "/.AFSCONF" file */
433 fp = fopen("/.AFSCONF", "r");
437 return (struct afsconf_dir *)0;
439 fgets(afs_confdir, 128, fp);
444 sprintf(pathname, "%s/%s", home_dir, ".AFSCONF");
445 fp = fopen(pathname, "r");
447 /* Our last chance is the "/.AFSCONF" file */
448 fp = fopen("/.AFSCONF", "r");
452 return (struct afsconf_dir *)0;
455 fgets(afs_confdir, 128, fp);
458 len = strlen(afs_confdir);
462 return (struct afsconf_dir *)0;
464 if (afs_confdir[len - 1] == '\n') {
465 afs_confdir[len - 1] = 0;
467 afsconf_path = afs_confdir;
469 tdir->name = strdup(afsconf_path);
470 code = afsconf_OpenInternal(tdir, 0, 0);
475 return (struct afsconf_dir *)0;
483 GetCellUnix(struct afsconf_dir *adir)
490 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
491 fp = fopen(tbuffer, "r");
495 rc = fgets(tbuffer, 256, fp);
501 while (*start != '\0' && isspace(*start))
504 while (*p != '\0' && !isspace(*p))
510 adir->cellName = strdup(start);
517 GetCellNT(struct afsconf_dir *adir)
519 if (IsClientConfigDirectory(adir->name)) {
520 /* NT client config dir; ThisCell is in registry (no file). */
521 return afssw_GetClientCellName(&adir->cellName);
523 /* NT server config dir; works just like Unix */
524 return GetCellUnix(adir);
527 #endif /* AFS_NT40_ENV */
531 afsconf_OpenInternal(register struct afsconf_dir *adir, char *cell,
535 register char *tp, *bp;
536 register struct afsconf_entry *curEntry;
537 struct afsconf_aliasentry *curAlias;
538 register afs_int32 code;
540 char tbuffer[256], tbuf1[256];
543 /* figure out the local cell name */
547 i = GetCellUnix(adir);
550 #ifndef AFS_FREELANCE_CLIENT /* no local cell not fatal in freelance */
556 /* now parse the individual lines */
560 /* NT client/server have a CellServDB that is the same format as Unix.
561 * However, the NT client uses a different file name
563 if (IsClientConfigDirectory(adir->name)) {
564 /* NT client config dir */
566 if (!afssw_GetClientCellServDBDir(&p)) {
567 strcompose(tbuffer, sizeof(tbuffer), p, "/",
568 AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
572 strncpy(tbuffer, adir->name, sizeof(tbuffer));
573 len = (int)strlen(tbuffer);
574 if (tbuffer[len - 1] != '\\' && tbuffer[len - 1] != '/') {
575 strncat(tbuffer, "\\", sizeof(tbuffer));
577 strncat(tbuffer, AFSDIR_CELLSERVDB_FILE_NTCLIENT,
579 tbuffer[sizeof(tbuffer) - 1] = '\0';
582 /* NT server config dir */
583 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE,
587 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
588 #endif /* AFS_NT40_ENV */
590 if (!stat(tbuffer, &tstat)) {
591 adir->timeRead = tstat.st_mtime;
596 strlcpy(tbuf1, tbuffer, sizeof tbuf1);
597 tf = fopen(tbuffer, "r");
602 tp = fgets(tbuffer, sizeof(tbuffer), tf);
605 TrimLine(tbuffer, sizeof tbuffer); /* remove white space */
606 if (tbuffer[0] == 0 || tbuffer[0] == '\n')
607 continue; /* empty line */
608 if (tbuffer[0] == '>') {
609 char linkedcell[MAXCELLCHARS];
610 /* start new cell item */
612 /* thread this guy on the list */
613 curEntry->next = adir->entries;
614 adir->entries = curEntry;
618 (struct afsconf_entry *)malloc(sizeof(struct afsconf_entry));
619 memset(curEntry, 0, sizeof(struct afsconf_entry));
621 ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
623 afsconf_CloseInternal(adir);
628 if (linkedcell[0] != '\0')
629 curEntry->cellInfo.linkedCell = strdup(linkedcell);
631 /* new host in the current cell */
633 afsconf_CloseInternal(adir);
637 i = curEntry->cellInfo.numServers;
638 if (cell && !strcmp(cell, curEntry->cellInfo.name))
640 ParseHostLine(tbuffer, &curEntry->cellInfo.hostAddr[i],
641 curEntry->cellInfo.hostName[i], &clones[i]);
644 ParseHostLine(tbuffer, &curEntry->cellInfo.hostAddr[i],
645 curEntry->cellInfo.hostName[i], 0);
647 if (code == AFSCONF_SYNTAX) {
648 for (bp = tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
654 "Can't properly parse host line \"%s\" in configuration file %s\n",
659 afsconf_CloseInternal(adir);
662 curEntry->cellInfo.numServers = ++i;
665 fclose(tf); /* close the file now */
667 /* end the last partially-completed cell */
669 curEntry->next = adir->entries;
670 adir->entries = curEntry;
673 /* Read in the alias list */
674 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
676 tf = fopen(tbuffer, "r");
680 tp = fgets(tbuffer, sizeof(tbuffer), tf);
683 TrimLine(tbuffer, sizeof tbuffer); /* remove white space */
685 if (tbuffer[0] == '\0' || tbuffer[0] == '\n' || tbuffer[0] == '#')
686 continue; /* empty line */
689 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t')
692 continue; /* invalid line */
694 while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t'))
697 continue; /* invalid line */
700 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' && tp[0] != '\r'
705 curAlias = malloc(sizeof(*curAlias));
706 memset(curAlias, 0, sizeof(*curAlias));
708 strlcpy(curAlias->aliasInfo.aliasName, aliasPtr, sizeof curAlias->aliasInfo.aliasName);
709 strlcpy(curAlias->aliasInfo.realName, tbuffer, sizeof curAlias->aliasInfo.realName);
711 curAlias->next = adir->alias_entries;
712 adir->alias_entries = curAlias;
717 /* now read the fs keys, if possible */
718 adir->keystr = (struct afsconf_keys *)0;
719 afsconf_IntGetKeys(adir);
724 /* parse a line of the form
725 *"128.2.1.3 #hostname" or
726 *"[128.2.1.3] #hostname" for clones
727 * into the appropriate pieces.
730 ParseHostLine(char *aline, register struct sockaddr_in *addr, char *aname,
734 register afs_int32 code;
740 /* FIXME: length of aname unknown here */
741 code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
745 /* FIXME: length of aname unknown here */
746 code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
749 return AFSCONF_SYNTAX;
750 addr->sin_family = AF_INET;
752 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
753 addr->sin_len = sizeof(struct sockaddr_in);
755 tp = (char *)&addr->sin_addr;
763 /* parse a line of the form
764 * ">cellname [linkedcellname] [#comments]"
765 * into the appropriate pieces.
768 ParseCellLine(register char *aline, register char *aname,
769 register char *alname)
772 /* FIXME: length of aname, alname unknown here */
773 code = sscanf(aline, ">%s %s", aname, alname);
777 if (*alname == '#') {
781 return (code > 0 ? 0 : AFSCONF_SYNTAX);
784 /* call aproc(entry, arock, adir) for all cells. Proc must return 0, or we'll stop early and return the code it returns */
786 afsconf_CellApply(struct afsconf_dir *adir,
787 int (*aproc) (struct afsconf_cell * cell, void *arock,
788 struct afsconf_dir * dir), void *arock)
790 register struct afsconf_entry *tde;
791 register afs_int32 code;
793 for (tde = adir->entries; tde; tde = tde->next) {
794 code = (*aproc) (&tde->cellInfo, arock, adir);
804 /* call aproc(entry, arock, adir) for all cell aliases.
805 * Proc must return 0, or we'll stop early and return the code it returns
808 afsconf_CellAliasApply(struct afsconf_dir *adir,
809 int (*aproc) (struct afsconf_cellalias * alias,
810 void *arock, struct afsconf_dir * dir),
813 register struct afsconf_aliasentry *tde;
814 register afs_int32 code;
816 for (tde = adir->alias_entries; tde; tde = tde->next) {
817 code = (*aproc) (&tde->aliasInfo, arock, adir);
827 afs_int32 afsconf_SawCell = 0;
830 afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, char *acellName,
831 char *aservice, struct afsconf_cell *acellInfo,
837 code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
844 cell = (char *)&acellInfo->name;
846 code = afsconf_OpenInternal(adir, cell, clones);
851 #if !defined(AFS_NT40_ENV)
853 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
854 struct afsconf_cell *acellInfo)
857 int tservice, i, len;
858 unsigned char answer[1024];
862 char realCellName[256];
868 /* The resolver isn't always MT-safe.. Perhaps this ought to be
869 * replaced with a more fine-grained lock just for the resolver
874 if ( ! strchr(acellName,'.') ) {
875 cellnamelength=strlen(acellName);
876 dotcellname=malloc(cellnamelength+2);
877 memcpy(dotcellname,acellName,cellnamelength);
878 dotcellname[cellnamelength]='.';
879 dotcellname[cellnamelength+1]=0;
881 len = res_search(dotcellname, C_IN, T_AFSDB, answer, sizeof(answer));
883 len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
889 len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
898 return AFSCONF_NOTFOUND;
901 p = answer + sizeof(HEADER); /* Skip header */
902 code = dn_expand(answer, answer + len, p, host, sizeof(host));
904 return AFSCONF_NOTFOUND;
906 p += code + QFIXEDSZ; /* Skip name */
908 while (p < answer + len) {
911 code = dn_expand(answer, answer + len, p, host, sizeof(host));
913 return AFSCONF_NOTFOUND;
915 p += code; /* Skip the name */
916 type = (p[0] << 8) | p[1];
917 p += 4; /* Skip type and class */
918 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
919 p += 4; /* Skip the TTL */
920 size = (p[0] << 8) | p[1];
921 p += 2; /* Skip the size */
923 if (type == T_AFSDB) {
927 afsdb_type = (p[0] << 8) | p[1];
928 if (afsdb_type == 1) {
930 * We know this is an AFSDB record for our cell, of the
931 * right AFSDB type. Write down the true cell name that
932 * the resolver gave us above.
934 strlcpy(realCellName, host, sizeof realCellName);
937 code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
939 return AFSCONF_NOTFOUND;
941 if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) &&
942 /* Do we want to get TTL data for the A record as well? */
943 (he = gethostbyname(host))) {
945 memcpy(&ipaddr, he->h_addr, he->h_length);
946 acellInfo->hostAddr[server_num].sin_addr.s_addr = ipaddr;
947 strncpy(acellInfo->hostName[server_num], host,
948 sizeof(acellInfo->hostName[server_num]));
951 if (!minttl || ttl < minttl)
959 if (server_num == 0) /* No AFSDB records */
960 return AFSCONF_NOTFOUND;
962 /* Convert the real cell name to lowercase */
963 for (p = (unsigned char *)realCellName; *p; p++)
966 strncpy(acellInfo->name, realCellName, sizeof(acellInfo->name));
967 acellInfo->numServers = server_num;
970 tservice = afsconf_FindService(aservice);
972 return AFSCONF_NOTFOUND; /* service not found */
973 for (i = 0; i < acellInfo->numServers; i++) {
974 acellInfo->hostAddr[i].sin_port = tservice;
978 acellInfo->timeout = minttl ? (time(0) + minttl) : 0;
984 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
985 struct afsconf_cell *acellInfo)
987 register afs_int32 i;
989 struct afsconf_entry DNSce;
990 afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
991 char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
996 DNSce.cellInfo.numServers = 0;
998 rc = getAFSServer(acellName, cellHostAddrs, cellHostNames, &numServers,
1000 /* ignore the ttl here since this code is only called by transitory programs
1001 * like klog, etc. */
1004 if (numServers == 0)
1007 for (i = 0; i < numServers; i++) {
1008 memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1010 memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1011 acellInfo->hostAddr[i].sin_family = AF_INET;
1013 /* sin_port supplied by connection code */
1016 acellInfo->numServers = numServers;
1017 strlcpy(acellInfo->name, acellName, sizeof acellInfo->name);
1020 tservice = afsconf_FindService(aservice);
1021 UNLOCK_GLOBAL_MUTEX;
1023 return AFSCONF_NOTFOUND; /* service not found */
1025 for (i = 0; i < acellInfo->numServers; i++) {
1026 acellInfo->hostAddr[i].sin_port = tservice;
1029 acellInfo->linkedCell = NULL; /* no linked cell */
1030 acellInfo->flags = 0;
1033 #endif /* windows */
1034 #endif /* AFS_AFSDB_ENV */
1037 afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
1038 struct afsconf_cell *acellInfo)
1040 register struct afsconf_entry *tce;
1041 struct afsconf_aliasentry *tcae;
1042 struct afsconf_entry *bestce;
1043 register afs_int32 i;
1052 afsconf_Check(adir);
1055 cnLen = (int)(strlen(tcell) + 1);
1056 lcstring(tcell, tcell, cnLen);
1057 afsconf_SawCell = 1; /* will ignore the AFSCELL switch on future */
1058 /* call to afsconf_GetLocalCell: like klog */
1060 i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
1062 UNLOCK_GLOBAL_MUTEX;
1067 cnLen = strlen(tcell);
1068 bestce = (struct afsconf_entry *)0;
1071 UNLOCK_GLOBAL_MUTEX;
1075 /* Look through the list of aliases */
1076 for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
1077 if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
1078 tcell = tcae->aliasInfo.realName;
1083 for (tce = adir->entries; tce; tce = tce->next) {
1084 if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
1085 /* found our cell */
1090 if (strlen(tce->cellInfo.name) < cnLen)
1091 continue; /* clearly wrong */
1092 if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
1094 ambig = 1; /* ambiguous unless we get exact match */
1098 if (!ambig && bestce && bestce->cellInfo.numServers) {
1099 *acellInfo = bestce->cellInfo; /* structure assignment */
1101 tservice = afsconf_FindService(aservice);
1103 UNLOCK_GLOBAL_MUTEX;
1104 return AFSCONF_NOTFOUND; /* service not found */
1106 for (i = 0; i < acellInfo->numServers; i++) {
1107 acellInfo->hostAddr[i].sin_port = tservice;
1110 acellInfo->timeout = 0;
1111 UNLOCK_GLOBAL_MUTEX;
1114 UNLOCK_GLOBAL_MUTEX;
1115 #ifdef AFS_AFSDB_ENV
1116 return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
1118 return AFSCONF_NOTFOUND;
1119 #endif /* AFS_AFSDB_ENV */
1124 afsconf_GetLocalCell(register struct afsconf_dir *adir, char *aname,
1127 static int afsconf_showcell = 0;
1133 * If a cell switch was specified in a command, then it should override the
1134 * AFSCELL variable. If a cell was specified, then the afsconf_SawCell flag
1135 * is set and the cell name in the adir structure is used.
1136 * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
1138 if (!afsconf_SawCell && (afscell_path = getenv("AFSCELL"))) {
1139 if (!afsconf_showcell) {
1140 fprintf(stderr, "Note: Operation is performed on cell %s\n",
1142 afsconf_showcell = 1;
1144 strncpy(aname, afscell_path, alen);
1146 afsconf_Check(adir);
1147 if (adir->cellName) {
1148 strncpy(aname, adir->cellName, alen);
1150 code = AFSCONF_UNKNOWN;
1153 UNLOCK_GLOBAL_MUTEX;
1158 afsconf_Close(struct afsconf_dir *adir)
1161 afsconf_CloseInternal(adir);
1165 UNLOCK_GLOBAL_MUTEX;
1170 afsconf_CloseInternal(register struct afsconf_dir *adir)
1172 register struct afsconf_entry *td, *nd;
1173 struct afsconf_aliasentry *ta, *na;
1174 register char *tname;
1176 tname = adir->name; /* remember name, since that's all we preserve */
1178 /* free everything we can find */
1180 free(adir->cellName);
1181 for (td = adir->entries; td; td = nd) {
1183 if (td->cellInfo.linkedCell)
1184 free(td->cellInfo.linkedCell);
1187 for (ta = adir->alias_entries; ta; ta = na) {
1195 memset(adir, 0, sizeof(struct afsconf_dir));
1196 adir->name = tname; /* restore it */
1201 afsconf_Reopen(register struct afsconf_dir *adir)
1203 register afs_int32 code;
1204 code = afsconf_CloseInternal(adir);
1207 code = afsconf_OpenInternal(adir, 0, 0);
1211 /* called during opening of config file */
1213 afsconf_IntGetKeys(struct afsconf_dir *adir)
1217 struct afsconf_keys *tstr;
1218 register afs_int32 code;
1221 /* NT client config dir has no KeyFile; don't risk attempting open
1222 * because there might be a random file of this name if dir is shared.
1224 if (IsClientConfigDirectory(adir->name)) {
1225 adir->keystr = ((struct afsconf_keys *)
1226 malloc(sizeof(struct afsconf_keys)));
1227 adir->keystr->nkeys = 0;
1230 #endif /* AFS_NT40_ENV */
1233 /* compute the key name and other setup */
1234 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1235 tstr = (struct afsconf_keys *)malloc(sizeof(struct afsconf_keys));
1236 adir->keystr = tstr;
1239 fd = open(tbuffer, O_RDONLY);
1242 UNLOCK_GLOBAL_MUTEX;
1245 code = read(fd, tstr, sizeof(struct afsconf_keys));
1247 if (code < sizeof(afs_int32)) {
1249 UNLOCK_GLOBAL_MUTEX;
1253 /* convert key structure to host order */
1254 tstr->nkeys = ntohl(tstr->nkeys);
1256 if (code < sizeof(afs_int32) + (tstr->nkeys*sizeof(struct afsconf_key))) {
1258 UNLOCK_GLOBAL_MUTEX;
1262 for (fd = 0; fd < tstr->nkeys; fd++)
1263 tstr->key[fd].kvno = ntohl(tstr->key[fd].kvno);
1265 UNLOCK_GLOBAL_MUTEX;
1269 /* get keys structure */
1271 afsconf_GetKeys(struct afsconf_dir *adir, struct afsconf_keys *astr)
1273 register afs_int32 code;
1276 code = afsconf_Check(adir);
1278 UNLOCK_GLOBAL_MUTEX;
1279 return AFSCONF_FAILURE;
1281 memcpy(astr, adir->keystr, sizeof(struct afsconf_keys));
1282 UNLOCK_GLOBAL_MUTEX;
1286 /* get latest key */
1288 afsconf_GetLatestKey(struct afsconf_dir * adir, afs_int32 * avno,
1289 struct ktc_encryptionKey *akey)
1293 register struct afsconf_key *tk;
1294 register afs_int32 best;
1295 struct afsconf_key *bestk;
1296 register afs_int32 code;
1299 code = afsconf_Check(adir);
1301 UNLOCK_GLOBAL_MUTEX;
1302 return AFSCONF_FAILURE;
1304 maxa = adir->keystr->nkeys;
1306 best = -1; /* highest kvno we've seen yet */
1307 bestk = (struct afsconf_key *)0; /* ptr to structure providing best */
1308 for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
1309 if (tk->kvno == 999)
1310 continue; /* skip bcrypt keys */
1311 if (tk->kvno > best) {
1316 if (bestk) { /* found any */
1318 memcpy(akey, bestk->key, 8); /* copy out latest key */
1320 *avno = bestk->kvno; /* and kvno to caller */
1321 UNLOCK_GLOBAL_MUTEX;
1324 UNLOCK_GLOBAL_MUTEX;
1325 return AFSCONF_NOTFOUND; /* didn't find any keys */
1328 /* get a particular key */
1330 afsconf_GetKey(void *rock, int avno, struct ktc_encryptionKey *akey)
1332 struct afsconf_dir *adir = (struct afsconf_dir *) rock;
1333 register int i, maxa;
1334 register struct afsconf_key *tk;
1335 register afs_int32 code;
1338 code = afsconf_Check(adir);
1340 UNLOCK_GLOBAL_MUTEX;
1341 return AFSCONF_FAILURE;
1343 maxa = adir->keystr->nkeys;
1345 for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
1346 if (tk->kvno == avno) {
1347 memcpy(akey, tk->key, 8);
1348 UNLOCK_GLOBAL_MUTEX;
1353 UNLOCK_GLOBAL_MUTEX;
1354 return AFSCONF_NOTFOUND;
1357 /* save the key structure in the appropriate file */
1359 SaveKeys(struct afsconf_dir *adir)
1361 struct afsconf_keys tkeys;
1363 register afs_int32 i;
1366 memcpy(&tkeys, adir->keystr, sizeof(struct afsconf_keys));
1368 /* convert it to net byte order */
1369 for (i = 0; i < tkeys.nkeys; i++)
1370 tkeys.key[i].kvno = htonl(tkeys.key[i].kvno);
1371 tkeys.nkeys = htonl(tkeys.nkeys);
1373 /* rewrite keys file */
1374 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1375 fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0600);
1377 return AFSCONF_FAILURE;
1378 i = write(fd, &tkeys, sizeof(tkeys));
1379 if (i != sizeof(tkeys)) {
1381 return AFSCONF_FAILURE;
1384 return AFSCONF_FAILURE;
1389 afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno, char akey[8],
1390 afs_int32 overwrite)
1392 register struct afsconf_keys *tk;
1393 register struct afsconf_key *tkey;
1394 register afs_int32 i;
1401 if (akvno < 0 || akvno > 255) {
1402 UNLOCK_GLOBAL_MUTEX;
1407 for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
1408 if (tkey->kvno == akvno) {
1410 UNLOCK_GLOBAL_MUTEX;
1411 return AFSCONF_KEYINUSE;
1418 if (tk->nkeys >= AFSCONF_MAXKEYS) {
1419 UNLOCK_GLOBAL_MUTEX;
1420 return AFSCONF_FULL;
1422 tkey = &tk->key[tk->nkeys++];
1425 memcpy(tkey->key, akey, 8);
1427 afsconf_Touch(adir);
1428 UNLOCK_GLOBAL_MUTEX;
1432 /* this proc works by sliding the other guys down, rather than using a funny
1433 kvno value, so that callers can count on getting a good key in key[0].
1436 afsconf_DeleteKey(struct afsconf_dir *adir, afs_int32 akvno)
1438 register struct afsconf_keys *tk;
1439 register struct afsconf_key *tkey;
1446 for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
1447 if (tkey->kvno == akvno) {
1453 UNLOCK_GLOBAL_MUTEX;
1454 return AFSCONF_NOTFOUND;
1457 /* otherwise slide the others down. i and tkey point at the guy to delete */
1458 for (; i < tk->nkeys - 1; i++, tkey++) {
1459 tkey->kvno = (tkey + 1)->kvno;
1460 memcpy(tkey->key, (tkey + 1)->key, 8);
1464 afsconf_Touch(adir);
1465 UNLOCK_GLOBAL_MUTEX;