auth: Tidy header includes
[openafs.git] / src / auth / cellconfig.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #ifdef AFS_NT40_ENV
17 #include <sys/utime.h>
18 #include <WINNT/afssw.h>
19 #endif
20
21 #include <ctype.h>
22
23 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
24 #include <arpa/nameser_compat.h>
25 #endif
26
27 #include <afs/pthread_glock.h>
28 #include <afs/afsint.h>
29 #include <rx/rxkad.h>
30 #include <rx/rx.h>
31
32 #include <afs/afsutil.h>
33 #include "keys.h"
34 #include "cellconfig.h"
35 #include "internal.h"
36
37 #ifdef AFS_NT40_ENV
38 #include <cm.h>
39 #include <cm_config.h>
40 /* cm_dns.h depends on cellconfig.h */
41 #include <cm_nls.h>
42 #include <cm_dns.h>
43 #endif
44 #include <rx/rx.h>
45 #include <rx/rxkad.h>
46
47 struct afsconf_servPair {
48     const char *name;
49     const char *ianaName;
50     int port;
51 };
52
53 static struct afsconf_servPair serviceTable[] = {
54     {"afs", "afs3-fileserver", 7000,},
55     {"afscb", "afs3-callback", 7001,},
56     {"afsprot", "afs3-prserver", 7002,},
57     {"afsvldb", "afs3-vlserver", 7003,},
58     {"afskauth", "afs3-kaserver", 7004,},
59     {"afsvol", "afs3-volserver", 7005,},
60     {"afserror", "afs3-errors", 7006,},
61     {"afsnanny", "afs3-bos", 7007,},
62     {"afsupdate", "afs3-update", 7008,},
63     {"afsrmtsys", "afs3-rmtsys", 7009,},
64     {"afsres", NULL, 7010,},/* residency database for MR-AFS */
65     {"afsremio", NULL, 7011,},  /* remote I/O interface for MR-AFS */
66     {0, 0, 0}                   /* insert new services before this spot */
67 };
68
69 /* Prototypes */
70 static int TrimLine(char *abuffer, int abufsize);
71 #ifdef AFS_NT40_ENV
72 static int GetCellNT(struct afsconf_dir *adir);
73 #endif
74 static int GetCellUnix(struct afsconf_dir *adir);
75 static int afsconf_OpenInternal(struct afsconf_dir *adir, char *cell,
76                                 char clones[]);
77 static int ParseHostLine(char *aline, struct sockaddr_in *addr,
78                          char *aname, char *aclone);
79 static int ParseCellLine(char *aline, char *aname,
80                          char *alname);
81 static int afsconf_CloseInternal(struct afsconf_dir *adir);
82 static int afsconf_Reopen(struct afsconf_dir *adir);
83
84 #ifndef T_AFSDB
85 #define T_AFSDB 18              /* per RFC1183 section 1 */
86 #endif
87 #ifndef T_SRV
88 #define T_SRV 33                /* RFC2782 */
89 #endif
90
91 /*
92  * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
93  * our code can tell if there is new info in the key files, the cell server db
94  * files or any of the other files (and reopen the thing) if the date on
95  * CellServDB changes.
96  */
97
98 #if defined(AFS_SUN5_ENV) && !defined(__sparcv9)
99 /* Solaris through 10 in 32 bit mode will return EMFILE if fopen can't
100    get an fd <= 255. We allow the fileserver to claim more fds than that.
101    This has always been a problem since pr_Initialize would have the same
102    issue, but hpr_Initialize makes it more likely that we would see this.
103    Work around it. This is not generic. It's coded with the needs of
104    afsconf_* in mind only.
105
106    http://www.opensolaris.org/os/community/onnv/flag-days/pages/2006042001/
107 */
108
109 #define BUFFER 4096
110
111 struct afsconf_iobuffer {
112     int _file;
113     char *buffer;
114     char *ptr;
115     char *endptr;
116 };
117
118 typedef struct afsconf_iobuffer afsconf_FILE;
119
120 static afsconf_FILE *
121 afsconf_fopen(const char *fname, const char *fmode)
122 {
123     int fd;
124     afsconf_FILE *iop;
125
126     if ((fd = open(fname, O_RDONLY)) == -1) {
127         return NULL;
128     }
129
130     iop = malloc(sizeof(struct afsconf_iobuffer));
131     if (iop == NULL) {
132         (void) close(fd);
133         errno = ENOMEM;
134         return NULL;
135     }
136     iop->_file = fd;
137     iop->buffer = malloc(BUFFER);
138     if (iop->buffer == NULL) {
139         (void) close(fd);
140         free((void *) iop);
141         errno = ENOMEM;
142         return NULL;
143     }
144     iop->ptr = iop->buffer;
145     iop->endptr = iop->buffer;
146     return iop;
147 }
148
149 static int
150 afsconf_fclose(afsconf_FILE *iop)
151 {
152     if (iop == NULL) {
153         return 0;
154     }
155     close(iop->_file);
156     free((void *)iop->buffer);
157     free((void *)iop);
158     return 0;
159 }
160
161 static char *
162 afsconf_fgets(char *s, int n, afsconf_FILE *iop)
163 {
164     char *p;
165
166     p = s;
167     for (;;) {
168         char c;
169
170         if (iop->ptr == iop->endptr) {
171             ssize_t len;
172
173             if ((len = read(iop->_file, (void *)iop->buffer, BUFFER)) == -1) {
174                 return NULL;
175             }
176             if (len == 0) {
177                 *p = 0;
178                 if (s == p) {
179                     return NULL;
180                 }
181                 return s;
182             }
183             iop->ptr = iop->buffer;
184             iop->endptr = iop->buffer + len;
185         }
186         c = *iop->ptr++;
187         *p++ = c;
188         if ((p - s) == (n - 1)) {
189             *p = 0;
190             return s;
191         }
192         if (c == '\n') {
193             *p = 0;
194             return s;
195         }
196     }
197 }
198 #define fopen afsconf_fopen
199 #define fclose afsconf_fclose
200 #define fgets afsconf_fgets
201 #else
202 #define afsconf_FILE FILE
203 #endif /* AFS_SUN5_ENV && ! __sparcv9 */
204
205 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
206 afs_int32
207 afsconf_FindService(const char *aname)
208 {
209     /* lookup a service name */
210     struct servent *ts;
211     struct afsconf_servPair *tsp;
212
213     if (aname == NULL || aname[0] == '\0')
214         return -1;
215
216 #if     defined(AFS_OSF_ENV)
217     ts = getservbyname(aname, "");
218 #else
219     ts = (struct servent *) getservbyname(aname, NULL);
220 #endif
221     if (ts) {
222         /* we found it in /etc/services, so we use this value */
223         return ts->s_port;      /* already in network byte order */
224     }
225
226     /* not found in /etc/services, see if it is one of ours */
227     for (tsp = serviceTable; tsp->port; tsp++) {
228         if ((tsp->name && (!strcmp(tsp->name, aname)))
229             || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
230             return htons(tsp->port);
231     }
232     return -1;
233 }
234
235 const char *
236 afsconf_FindIANAName(const char *aname)
237 {
238     /* lookup a service name */
239     struct afsconf_servPair *tsp;
240
241     if (aname == NULL || aname[0] == '\0')
242         return NULL;
243
244     /* see if it is one of ours */
245     for (tsp = serviceTable; tsp->port; tsp++) {
246         if ((tsp->name && (!strcmp(tsp->name, aname)))
247             || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
248             return tsp->ianaName;
249     }
250     return NULL;
251 }
252
253 static int
254 TrimLine(char *abuffer, int abufsize)
255 {
256     char tbuffer[256];
257     char *tp;
258     int tc;
259
260     tp = abuffer;
261     while ((tc = *tp)) {
262         if (!isspace(tc))
263             break;
264         tp++;
265     }
266     strlcpy(tbuffer, tp, sizeof tbuffer);
267     strlcpy(abuffer, tbuffer, abufsize);
268     return 0;
269 }
270
271 /*
272  * IsClientConfigDirectory() -- determine if path matches well-known
273  *     client configuration directory.
274  */
275 #ifdef AFS_NT40_ENV
276 #define IS_SEP(x) ((x) == '\\' || (x) == '/')
277 #else /* AFS_NT40_ENV */
278 #define IS_SEP(x) ((x) == '/')
279 #endif /* AFS_NT40_ENV */
280 int
281 _afsconf_IsClientConfigDirectory(const char *path)
282 {
283     const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
284     int i, cc, pc;
285
286     for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
287 #ifdef AFS_NT40_ENV
288         cc = tolower(cdir[i]);
289         pc = tolower(path[i]);
290
291         if (cc == '\\') {
292             cc = '/';
293         }
294         if (pc == '\\') {
295             pc = '/';
296         }
297 #else /* AFS_NT40_ENV */
298         cc = cdir[i];
299         pc = path[i];
300 #endif /* AFS_NT40_ENV */
301         if (cc != pc) {
302             return 0;
303         }
304     }
305
306     /* hit end of one or both; allow mismatch in existence of trailing slash */
307     if (cdir[i] != '\0') {
308         if (!IS_SEP(cdir[i]) || (cdir[i + 1] != '\0')) {
309             return 0;
310         }
311     }
312     if (path[i] != '\0') {
313         if (!IS_SEP(path[i]) || (path[i + 1] != '\0')) {
314             return 0;
315         }
316     }
317     return 1;
318 }
319
320 #ifdef AFS_NT40_ENV
321 static void
322 _afsconf_CellServDBPath(struct afsconf_dir *adir, char **path)
323 {
324     char *p;
325
326     /* NT client CellServDB has different file name than NT server or Unix */
327     if (_afsconf_IsClientConfigDirectory(adir->name)) {
328         if (!afssw_GetClientCellServDBDir(&p)) {
329             asprintf(path, "%s/%s", p, AFSDIR_CELLSERVDB_FILE_NTCLIENT);
330             free(p);
331         } else {
332             asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE_NTCLIENT);
333         }
334     } else {
335         asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE);
336     }
337     return;
338 }
339 #else
340 static void
341 _afsconf_CellServDBPath(struct afsconf_dir *adir, char **path)
342 {
343     asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE);
344 }
345 #endif /* AFS_NT40_ENV */
346
347 int
348 _afsconf_UpToDate(struct afsconf_dir *adir)
349 {
350     char *cellservDB;
351     struct stat tstat;
352     int code;
353
354     _afsconf_CellServDBPath(adir, &cellservDB);
355     if (cellservDB == NULL)
356         return 0;
357
358     code = stat(cellservDB, &tstat);
359     free(cellservDB);
360     if (code < 0)
361         return 0; /* Can't throw the error, so just say we're not up to date */
362
363     /* did file change? */
364     if (tstat.st_mtime == adir->timeRead)
365         return 1;
366
367     /* otherwise file has changed */
368     return 0;
369 }
370
371 int
372 afsconf_UpToDate(void *rock)
373 {
374     int code;
375
376     LOCK_GLOBAL_MUTEX;
377     code = _afsconf_UpToDate(rock);
378     UNLOCK_GLOBAL_MUTEX;
379
380     return code;
381 }
382
383 int
384 _afsconf_Check(struct afsconf_dir *adir)
385 {
386     /* did configuration change? */
387     if (_afsconf_UpToDate(adir))
388         return 0;
389
390     /* otherwise file has changed, so reopen it */
391     return afsconf_Reopen(adir);
392 }
393
394 /* set modtime on file */
395 int
396 _afsconf_Touch(struct afsconf_dir *adir)
397 {
398     char *cellservDB;
399     int code;
400 #ifndef AFS_NT40_ENV
401     struct timeval tvp[2];
402 #endif
403
404     adir->timeRead = 0;         /* just in case */
405
406     _afsconf_CellServDBPath(adir, &cellservDB);
407     if (cellservDB == NULL)
408         return ENOMEM;
409
410 #ifdef AFS_NT40_ENV
411     code = _utime(cellservDB, NULL);
412 #else
413     gettimeofday(&tvp[0], NULL);
414     tvp[1] = tvp[0];
415     code = utimes(cellservDB, tvp);
416 #endif /* AFS_NT40_ENV */
417     free(cellservDB);
418
419     return code;
420 }
421
422 struct afsconf_dir *
423 afsconf_Open(const char *adir)
424 {
425     struct afsconf_dir *tdir;
426     afs_int32 code;
427
428     LOCK_GLOBAL_MUTEX;
429     /* zero structure and fill in name; rest is done by internal routine */
430     tdir = (struct afsconf_dir *)malloc(sizeof(struct afsconf_dir));
431     memset(tdir, 0, sizeof(struct afsconf_dir));
432     tdir->name = strdup(adir);
433
434     code = afsconf_OpenInternal(tdir, 0, 0);
435     if (code) {
436         char *afsconf_path, afs_confdir[128];
437
438         free(tdir->name);
439         /* Check global place only when local Open failed for whatever reason */
440         if (!(afsconf_path = getenv("AFSCONF"))) {
441             /* 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... */
442             char *home_dir;
443             afsconf_FILE *fp;
444             size_t len;
445
446             if (!(home_dir = getenv("HOME"))) {
447                 /* Our last chance is the "/.AFSCONF" file */
448                 fp = fopen("/.AFSCONF", "r");
449                 if (fp == 0) {
450                     free(tdir);
451                     UNLOCK_GLOBAL_MUTEX;
452                     return (struct afsconf_dir *)0;
453                 }
454                 fgets(afs_confdir, 128, fp);
455                 fclose(fp);
456             } else {
457                 char pathname[256];
458
459                 sprintf(pathname, "%s/%s", home_dir, ".AFSCONF");
460                 fp = fopen(pathname, "r");
461                 if (fp == 0) {
462                     /* Our last chance is the "/.AFSCONF" file */
463                     fp = fopen("/.AFSCONF", "r");
464                     if (fp == 0) {
465                         free(tdir);
466                         UNLOCK_GLOBAL_MUTEX;
467                         return (struct afsconf_dir *)0;
468                     }
469                 }
470                 fgets(afs_confdir, 128, fp);
471                 fclose(fp);
472             }
473             len = strlen(afs_confdir);
474             if (len == 0) {
475                 free(tdir);
476                 UNLOCK_GLOBAL_MUTEX;
477                 return (struct afsconf_dir *)0;
478             }
479             if (afs_confdir[len - 1] == '\n') {
480                 afs_confdir[len - 1] = 0;
481             }
482             afsconf_path = afs_confdir;
483         }
484         tdir->name = strdup(afsconf_path);
485         code = afsconf_OpenInternal(tdir, 0, 0);
486         if (code) {
487             free(tdir->name);
488             free(tdir);
489             UNLOCK_GLOBAL_MUTEX;
490             return (struct afsconf_dir *)0;
491         }
492     }
493     UNLOCK_GLOBAL_MUTEX;
494     return tdir;
495 }
496
497 static int
498 GetCellUnix(struct afsconf_dir *adir)
499 {
500     char *rc;
501     char tbuffer[256];
502     char *start, *p;
503     afsconf_FILE *fp;
504
505     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
506     fp = fopen(tbuffer, "r");
507     if (fp == 0) {
508         return -1;
509     }
510     rc = fgets(tbuffer, 256, fp);
511     fclose(fp);
512     if (rc == NULL)
513         return -1;
514
515     start = tbuffer;
516     while (*start != '\0' && isspace(*start))
517         start++;
518     p = start;
519     while (*p != '\0' && !isspace(*p))
520         p++;
521     *p = '\0';
522     if (*start == '\0')
523         return -1;
524
525     adir->cellName = strdup(start);
526     return 0;
527 }
528
529
530 #ifdef AFS_NT40_ENV
531 static int
532 GetCellNT(struct afsconf_dir *adir)
533 {
534     if (_afsconf_IsClientConfigDirectory(adir->name)) {
535         /* NT client config dir; ThisCell is in registry (no file). */
536         return afssw_GetClientCellName(&adir->cellName);
537     } else {
538         /* NT server config dir; works just like Unix */
539         return GetCellUnix(adir);
540     }
541 }
542
543 /* The following procedures and structs are used on Windows only
544  * to enumerate the Cell information distributed within the
545  * Windows registry.  (See src/WINNT/afsd/cm_config.c)
546  */
547 typedef struct _cm_enumCellRegistry {
548     afs_uint32 client;  /* non-zero if client query */
549     struct afsconf_dir *adir;
550 } cm_enumCellRegistry_t;
551
552 static long
553 cm_serverConfigProc(void *rockp, struct sockaddr_in *addrp,
554                     char *hostNamep, unsigned short rank)
555 {
556     struct afsconf_cell *cellInfop = (struct afsconf_cell *)rockp;
557
558     if (cellInfop->numServers == MAXHOSTSPERCELL)
559         return 0;
560
561     cellInfop->hostAddr[cellInfop->numServers] = *addrp;
562     strncpy(cellInfop->hostName[cellInfop->numServers], hostNamep, MAXHOSTCHARS);
563     cellInfop->hostName[cellInfop->numServers][MAXHOSTCHARS-1] = '\0';
564     cellInfop->numServers++;
565
566     return 0;
567 }
568
569 static long
570 cm_enumCellRegistryProc(void *rockp, char * cellNamep)
571 {
572     long code;
573     cm_enumCellRegistry_t *enump = (cm_enumCellRegistry_t *)rockp;
574     char linkedName[256] = "";
575     int timeout = 0;
576     struct afsconf_entry *newEntry;
577
578
579     newEntry = malloc(sizeof(struct afsconf_entry));
580     if (newEntry == NULL)
581         return ENOMEM;
582     newEntry->cellInfo.numServers = 0;
583
584     code = cm_SearchCellRegistry(enump->client, cellNamep, NULL, linkedName, cm_serverConfigProc, &newEntry->cellInfo);
585     if (code == CM_ERROR_FORCE_DNS_LOOKUP)
586         code = cm_SearchCellByDNS(cellNamep, NULL, &timeout, cm_serverConfigProc, &newEntry->cellInfo);
587
588     if (code == 0) {
589         strncpy(newEntry->cellInfo.name, cellNamep, MAXCELLCHARS);
590         newEntry->cellInfo.name[MAXCELLCHARS-1];
591         if (linkedName[0])
592             newEntry->cellInfo.linkedCell = strdup(linkedName);
593         else
594             newEntry->cellInfo.linkedCell = NULL;
595         newEntry->cellInfo.timeout = timeout;
596         newEntry->cellInfo.flags = 0;
597
598         newEntry->next = enump->adir->entries;
599         enump->adir->entries = newEntry;
600     } else {
601         free(newEntry);
602     }
603     return code;
604 }
605 #endif /* AFS_NT40_ENV */
606
607
608 static int
609 afsconf_OpenInternal(struct afsconf_dir *adir, char *cell,
610                      char clones[])
611 {
612     afsconf_FILE *tf;
613     char *tp, *bp;
614     struct afsconf_entry *curEntry;
615     struct afsconf_aliasentry *curAlias;
616     afs_int32 code;
617     afs_int32 i;
618     char tbuffer[256];
619     struct stat tstat;
620     char *cellservDB;
621
622 #ifdef AFS_NT40_ENV
623     cm_enumCellRegistry_t enumCellRegistry = {0, 0};
624 #endif /* AFS_NT40_ENV */
625
626     /* figure out the local cell name */
627 #ifdef AFS_NT40_ENV
628     i = GetCellNT(adir);
629     enumCellRegistry.adir = adir;
630 #else
631     i = GetCellUnix(adir);
632 #endif
633
634 #ifndef AFS_FREELANCE_CLIENT    /* no local cell not fatal in freelance */
635     if (i) {
636         return i;
637     }
638 #endif
639
640     /* now parse the individual lines */
641     curEntry = 0;
642
643     _afsconf_CellServDBPath(adir, &cellservDB);
644
645 #ifdef AFS_NT40_ENV
646     if (_afsconf_IsClientConfigDirectory(adir->name))
647         enumCellRegistry.client = 1;
648 #endif /* AFS_NT40_ENV */
649
650     if (!stat(cellservDB, &tstat)) {
651         adir->timeRead = tstat.st_mtime;
652     } else {
653         adir->timeRead = 0;
654     }
655
656     tf = fopen(cellservDB, "r");
657     if (!tf) {
658         return -1;
659     }
660
661     /* The CellServDB file is now open.
662      * The following code parses the contents of the
663      * file and creates a list with the first cell entry
664      * in the CellServDB file at the end of the list.
665      *
666      * No checking is performed for duplicates.
667      * The side effects of this process are that duplicate
668      * entries appended to the end of the CellServDB file
669      * take precedence and are found in a shorter period
670      * of time.
671      */
672
673     while (1) {
674         tp = fgets(tbuffer, sizeof(tbuffer), tf);
675         if (!tp)
676             break;
677         TrimLine(tbuffer, sizeof tbuffer);      /* remove white space */
678         if (tbuffer[0] == 0 || tbuffer[0] == '\n')
679             continue;           /* empty line */
680         if (tbuffer[0] == '>') {
681             char linkedcell[MAXCELLCHARS];
682             /* start new cell item */
683             if (curEntry) {
684                 /* thread this guy on the list */
685                 curEntry->next = adir->entries;
686                 adir->entries = curEntry;
687                 curEntry = 0;
688             }
689             curEntry =
690                 (struct afsconf_entry *)malloc(sizeof(struct afsconf_entry));
691             memset(curEntry, 0, sizeof(struct afsconf_entry));
692             code =
693                 ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
694             if (code) {
695                 afsconf_CloseInternal(adir);
696                 fclose(tf);
697                 free(curEntry);
698                 return -1;
699             }
700             if (linkedcell[0] != '\0')
701                 curEntry->cellInfo.linkedCell = strdup(linkedcell);
702         } else {
703             /* new host in the current cell */
704             if (!curEntry) {
705                 afsconf_CloseInternal(adir);
706                 fclose(tf);
707                 return -1;
708             }
709             i = curEntry->cellInfo.numServers;
710             if (i < MAXHOSTSPERCELL) {
711                 if (cell && !strcmp(cell, curEntry->cellInfo.name))
712                     code =
713                         ParseHostLine(tbuffer,
714                                       &curEntry->cellInfo.hostAddr[i],
715                                       curEntry->cellInfo.hostName[i],
716                                       &clones[i]);
717                 else
718                     code =
719                         ParseHostLine(tbuffer,
720                                       &curEntry->cellInfo.hostAddr[i],
721                                       curEntry->cellInfo.hostName[i], 0);
722
723                 if (code) {
724                     if (code == AFSCONF_SYNTAX) {
725                         for (bp = tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
726                             if (!*bp)
727                                 break;
728                         }
729                         *bp = '\0';
730                         fprintf(stderr,
731                                 "Can't properly parse host line \"%s\" in configuration file %s\n",
732                                 tbuffer, cellservDB);
733                     }
734                     free(curEntry);
735                     fclose(tf);
736                     afsconf_CloseInternal(adir);
737                     return -1;
738                 }
739                 curEntry->cellInfo.numServers = ++i;
740             } else {
741                 fprintf(stderr,
742                         "Too many hosts for cell %s in configuration file %s\n",
743                         curEntry->cellInfo.name, cellservDB);
744             }
745         }
746     }
747     fclose(tf);                 /* close the file now */
748     free(cellservDB);
749
750     /* end the last partially-completed cell */
751     if (curEntry) {
752         curEntry->next = adir->entries;
753         adir->entries = curEntry;
754     }
755
756 #ifdef AFS_NT40_ENV
757      /*
758       * Windows maintains a CellServDB list in the Registry
759       * that supercedes the contents of the CellServDB file.
760       * Prepending these entries to the head of the list
761       * is sufficient to enforce the precedence.
762       */
763      cm_EnumerateCellRegistry( enumCellRegistry.client,
764                                cm_enumCellRegistryProc,
765                                &enumCellRegistry);
766 #endif /* AFS_NT40_ENV */
767
768     /* Read in the alias list */
769     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
770
771     tf = fopen(tbuffer, "r");
772     while (tf) {
773         char *aliasPtr;
774
775         tp = fgets(tbuffer, sizeof(tbuffer), tf);
776         if (!tp)
777             break;
778         TrimLine(tbuffer, sizeof tbuffer);      /* remove white space */
779
780         if (tbuffer[0] == '\0' || tbuffer[0] == '\n' || tbuffer[0] == '#')
781             continue;           /* empty line */
782
783         tp = tbuffer;
784         while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t')
785             tp++;
786         if (tp[0] == '\0')
787             continue;           /* invalid line */
788
789         while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t'))
790             0[tp++] = '\0';
791         if (tp[0] == '\0')
792             continue;           /* invalid line */
793
794         aliasPtr = tp;
795         while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' && tp[0] != '\r'
796                && tp[0] != '\n')
797             tp++;
798         tp[0] = '\0';
799
800         curAlias = malloc(sizeof(*curAlias));
801         memset(curAlias, 0, sizeof(*curAlias));
802
803         strlcpy(curAlias->aliasInfo.aliasName, aliasPtr, sizeof curAlias->aliasInfo.aliasName);
804         strlcpy(curAlias->aliasInfo.realName, tbuffer, sizeof curAlias->aliasInfo.realName);
805
806         curAlias->next = adir->alias_entries;
807         adir->alias_entries = curAlias;
808     }
809
810     if (tf != NULL)
811         fclose(tf);
812     /* now read the fs keys, if possible */
813
814     _afsconf_InitKeys(adir);
815     code = _afsconf_LoadKeys(adir);
816
817     return code;
818 }
819
820 /* parse a line of the form
821  *"128.2.1.3   #hostname" or
822  *"[128.2.1.3]  #hostname" for clones
823  * into the appropriate pieces.
824  */
825 static int
826 ParseHostLine(char *aline, struct sockaddr_in *addr, char *aname,
827               char *aclone)
828 {
829     int c1, c2, c3, c4;
830     afs_int32 code;
831     char *tp;
832
833     if (*aline == '[') {
834         if (aclone)
835             *aclone = 1;
836         /* FIXME: length of aname unknown here */
837         code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
838     } else {
839         if (aclone)
840             *aclone = 0;
841         /* FIXME: length of aname unknown here */
842         code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
843     }
844     if (code != 5)
845         return AFSCONF_SYNTAX;
846     addr->sin_family = AF_INET;
847     addr->sin_port = 0;
848 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
849     addr->sin_len = sizeof(struct sockaddr_in);
850 #endif
851     tp = (char *)&addr->sin_addr;
852     *tp++ = c1;
853     *tp++ = c2;
854     *tp++ = c3;
855     *tp++ = c4;
856     return 0;
857 }
858
859 /* parse a line of the form
860  * ">cellname [linkedcellname] [#comments]"
861  * into the appropriate pieces.
862  */
863 static int
864 ParseCellLine(char *aline, char *aname,
865               char *alname)
866 {
867     int code;
868     /* FIXME: length of aname, alname unknown here */
869     code = sscanf(aline, ">%s %s", aname, alname);
870     if (code == 1)
871         *alname = '\0';
872     if (code == 2) {
873         if (*alname == '#') {
874             *alname = '\0';
875         }
876     }
877     return (code > 0 ? 0 : AFSCONF_SYNTAX);
878 }
879
880 /* call aproc(entry, arock, adir) for all cells.  Proc must return 0, or we'll stop early and return the code it returns */
881 int
882 afsconf_CellApply(struct afsconf_dir *adir,
883                   int (*aproc) (struct afsconf_cell * cell, void *arock,
884                                 struct afsconf_dir * dir), void *arock)
885 {
886     struct afsconf_entry *tde;
887     afs_int32 code;
888     LOCK_GLOBAL_MUTEX;
889     for (tde = adir->entries; tde; tde = tde->next) {
890         code = (*aproc) (&tde->cellInfo, arock, adir);
891         if (code) {
892             UNLOCK_GLOBAL_MUTEX;
893             return code;
894         }
895     }
896     UNLOCK_GLOBAL_MUTEX;
897     return 0;
898 }
899
900 /* call aproc(entry, arock, adir) for all cell aliases.
901  * Proc must return 0, or we'll stop early and return the code it returns
902  */
903 int
904 afsconf_CellAliasApply(struct afsconf_dir *adir,
905                        int (*aproc) (struct afsconf_cellalias * alias,
906                                      void *arock, struct afsconf_dir * dir),
907                        void *arock)
908 {
909     struct afsconf_aliasentry *tde;
910     afs_int32 code;
911     LOCK_GLOBAL_MUTEX;
912     for (tde = adir->alias_entries; tde; tde = tde->next) {
913         code = (*aproc) (&tde->aliasInfo, arock, adir);
914         if (code) {
915             UNLOCK_GLOBAL_MUTEX;
916             return code;
917         }
918     }
919     UNLOCK_GLOBAL_MUTEX;
920     return 0;
921 }
922
923 afs_int32 afsconf_SawCell = 0;
924
925 int
926 afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, char *acellName,
927                             char *aservice, struct afsconf_cell *acellInfo,
928                             char clones[])
929 {
930     afs_int32 code;
931     char *cell;
932
933     code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
934     if (code)
935         return code;
936
937     if (acellName)
938         cell = acellName;
939     else
940         cell = (char *)&acellInfo->name;
941
942     code = afsconf_OpenInternal(adir, cell, clones);
943     return code;
944 }
945
946 #if !defined(AFS_NT40_ENV)
947 int
948 afsconf_LookupServer(const char *service, const char *protocol,
949                      const char *cellName, unsigned short afsdbPort,
950                      int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
951                      unsigned short ports[], unsigned short ipRanks[],
952                      int *numServers, int *ttl, char **arealCellName)
953 {
954     int code = 0;
955     int len;
956     unsigned char answer[1024];
957     unsigned char *p;
958     char *dotcellname;
959     char *realCellName;
960     int cellnamelength, fullnamelength;
961     char host[256];
962     int server_num = 0;
963     int minttl = 0;
964     int try_init = 0;
965     int dnstype = 0;
966     int pass = 0;
967     char *IANAname = (char *) afsconf_FindIANAName(service);
968     int tservice = afsconf_FindService(service);
969
970     realCellName = NULL;
971
972     *numServers = 0;
973     *ttl = 0;
974     if (tservice <= 0 || !IANAname)
975         return AFSCONF_NOTFOUND;        /* service not found */
976
977     if (strchr(cellName,'.'))
978         pass += 2;
979
980     cellnamelength=strlen(cellName); /* _ ._ . . \0 */
981     fullnamelength=cellnamelength+strlen(protocol)+strlen(IANAname)+6;
982     dotcellname=malloc(fullnamelength);
983     if (!dotcellname)
984         return AFSCONF_NOTFOUND;        /* service not found */
985
986 #ifdef HAVE_RES_RETRANSRETRY
987     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
988       return (0);
989
990     /*
991      * Rx timeout is typically 56 seconds; limit user experience to
992      * similar timeout
993      */
994     _res.retrans = 18;
995     _res.retry = 3;
996 #endif
997
998  retryafsdb:
999     switch (pass) {
1000     case 0:
1001         dnstype = T_SRV;
1002         code = snprintf(dotcellname, fullnamelength, "_%s._%s.%s.",
1003                  IANAname, protocol, cellName);
1004         break;
1005     case 1:
1006         dnstype = T_AFSDB;
1007         code = snprintf(dotcellname, fullnamelength, "%s.",
1008                  cellName);
1009         break;
1010     case 2:
1011         dnstype = T_SRV;
1012         code = snprintf(dotcellname, fullnamelength, "_%s._%s.%s",
1013                  IANAname, protocol, cellName);
1014         break;
1015     case 3:
1016         dnstype = T_AFSDB;
1017         code = snprintf(dotcellname, fullnamelength, "%s",
1018                  cellName);
1019         break;
1020     }
1021     if ((code < 0) || (code >= fullnamelength))
1022         goto findservererror;
1023     LOCK_GLOBAL_MUTEX;
1024     len = res_search(dotcellname, C_IN, dnstype, answer, sizeof(answer));
1025     UNLOCK_GLOBAL_MUTEX;
1026
1027     if (len < 0) {
1028         if (try_init < 1) {
1029             try_init++;
1030             res_init();
1031             goto retryafsdb;
1032         }
1033         if (pass < 3) {
1034             pass++;
1035             goto retryafsdb;
1036         } else {
1037             code = AFSCONF_NOTFOUND;
1038             goto findservererror;
1039         }
1040     }
1041
1042     p = answer + sizeof(HEADER);        /* Skip header */
1043     code = dn_expand(answer, answer + len, p, host, sizeof(host));
1044     if (code < 0) {
1045         code = AFSCONF_NOTFOUND;
1046         goto findservererror;
1047     }
1048
1049     p += code + QFIXEDSZ;       /* Skip name */
1050
1051     while (p < answer + len) {
1052         int type, ttl, size;
1053
1054         code = dn_expand(answer, answer + len, p, host, sizeof(host));
1055         if (code < 0) {
1056             code = AFSCONF_NOTFOUND;
1057             goto findservererror;
1058         }
1059
1060         p += code;              /* Skip the name */
1061         type = (p[0] << 8) | p[1];
1062         p += 4;                 /* Skip type and class */
1063         ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
1064         p += 4;                 /* Skip the TTL */
1065         size = (p[0] << 8) | p[1];
1066         p += 2;                 /* Skip the size */
1067
1068         if (type == T_AFSDB) {
1069             struct hostent *he;
1070             short afsdb_type;
1071
1072             afsdb_type = (p[0] << 8) | p[1];
1073             if (afsdb_type == 1) {
1074                 /*
1075                  * We know this is an AFSDB record for our cell, of the
1076                  * right AFSDB type.  Write down the true cell name that
1077                  * the resolver gave us above.
1078                  */
1079                 if (!realCellName)
1080                     realCellName = strdup(host);
1081             }
1082
1083             code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
1084             if (code < 0) {
1085                 code = AFSCONF_NOTFOUND;
1086                 goto findservererror;
1087             }
1088
1089             if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) &&
1090                 /* Do we want to get TTL data for the A record as well? */
1091                 (he = gethostbyname(host))) {
1092                 afs_int32 ipaddr;
1093                 memcpy(&ipaddr, he->h_addr, he->h_length);
1094                 cellHostAddrs[server_num] = ipaddr;
1095                 ports[server_num] = afsdbPort;
1096                 ipRanks[server_num] = 0;
1097                 strncpy(cellHostNames[server_num], host,
1098                         sizeof(cellHostNames[server_num]));
1099                 server_num++;
1100
1101                 if (!minttl || ttl < minttl)
1102                     minttl = ttl;
1103             }
1104         }
1105         if (type == T_SRV) {
1106             struct hostent *he;
1107             /* math here: _ is 1, _ ._ is 3, _ ._ . is 4. then the domain. */
1108             if ((strncmp(host + 1, IANAname, strlen(IANAname)) == 0) &&
1109                 (strncmp(host + strlen(IANAname) + 3, protocol,
1110                          strlen(protocol)) == 0)) {
1111                 if (!realCellName)
1112                     realCellName = strdup(host + strlen(IANAname) +
1113                                           strlen(protocol) + 4);
1114             }
1115
1116             code = dn_expand(answer, answer + len, p + 6, host, sizeof(host));
1117             if (code < 0) {
1118                 code = AFSCONF_NOTFOUND;
1119                 goto findservererror;
1120             }
1121
1122             if ((server_num < MAXHOSTSPERCELL) &&
1123                 /* Do we want to get TTL data for the A record as well? */
1124                 (he = gethostbyname(host))) {
1125                 afs_int32 ipaddr;
1126                 memcpy(&ipaddr, he->h_addr, he->h_length);
1127                 cellHostAddrs[server_num] = ipaddr;
1128                 ipRanks[server_num] = (p[0] << 8) | p[1];
1129                 ports[server_num] = htons((p[4] << 8) | p[5]);
1130                 /* weight = (p[2] << 8) | p[3]; */
1131                 strncpy(cellHostNames[server_num], host,
1132                         sizeof(cellHostNames[server_num]));
1133                 server_num++;
1134
1135                 if (!minttl || ttl < minttl)
1136                     minttl = ttl;
1137             }
1138         }
1139
1140         p += size;
1141     }
1142
1143     if (server_num == 0) {      /* No AFSDB or SRV records */
1144         code = AFSCONF_NOTFOUND;
1145         goto findservererror;
1146     }
1147
1148     if (realCellName) {
1149         /* Convert the real cell name to lowercase */
1150         for (p = (unsigned char *)realCellName; *p; p++)
1151             *p = tolower(*p);
1152     }
1153
1154     *numServers = server_num;
1155     *ttl = minttl ? (time(0) + minttl) : 0;
1156
1157     if ( *numServers > 0 ) {
1158         code =  0;
1159         *arealCellName = realCellName;
1160     } else
1161         code = AFSCONF_NOTFOUND;
1162
1163 findservererror:
1164     if (code && realCellName)
1165         free(realCellName);
1166     free(dotcellname);
1167     return code;
1168 }
1169
1170 int
1171 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1172                      struct afsconf_cell *acellInfo)
1173 {
1174     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
1175     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1176     unsigned short ipRanks[AFSMAXCELLHOSTS];
1177     unsigned short ports[AFSMAXCELLHOSTS];
1178     char *realCellName = NULL;
1179     int ttl, numServers, i;
1180     char *service = aservice;
1181     int code;
1182     unsigned short afsdbport;
1183     if (!service) {
1184         service = "afs3-vlserver";
1185         afsdbport = htons(7003);
1186     } else {
1187         service = aservice;
1188         afsdbport = afsconf_FindService(service);
1189     }
1190     code = afsconf_LookupServer((const char *)service, "udp",
1191                                 (const char *)acellName, afsdbport,
1192                                 cellHostAddrs, cellHostNames,
1193                                 ports, ipRanks, &numServers, &ttl,
1194                                 &realCellName);
1195
1196     if (code == 0) {
1197         acellInfo->timeout = ttl;
1198         acellInfo->numServers = numServers;
1199         for (i = 0; i < numServers; i++) {
1200             memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1201                    sizeof(afs_int32));
1202             memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1203             acellInfo->hostAddr[i].sin_family = AF_INET;
1204             acellInfo->hostAddr[i].sin_port = ports[i];
1205
1206             if (realCellName) {
1207                 strlcpy(acellInfo->name, realCellName,
1208                         sizeof(acellInfo->name));
1209                 free(realCellName);
1210                 realCellName = NULL;
1211             }
1212         }
1213         acellInfo->linkedCell = NULL;       /* no linked cell */
1214         acellInfo->flags = 0;
1215     }
1216     return code;
1217 }
1218 #else /* windows */
1219 int
1220 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1221                      struct afsconf_cell *acellInfo)
1222 {
1223     afs_int32 i;
1224     int tservice = afsconf_FindService(aservice);   /* network byte order */
1225     const char *ianaName = afsconf_FindIANAName(aservice);
1226     struct afsconf_entry DNSce;
1227     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
1228     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1229     unsigned short ipRanks[AFSMAXCELLHOSTS];
1230     unsigned short ports[AFSMAXCELLHOSTS];          /* network byte order */
1231     int numServers;
1232     int rc;
1233     int ttl;
1234
1235     if (tservice < 0) {
1236         if (aservice)
1237             return AFSCONF_NOTFOUND;
1238         else
1239             tservice = 0;       /* port will be assigned by caller */
1240     }
1241
1242     if (ianaName == NULL)
1243         ianaName = "afs3-vlserver";
1244
1245     DNSce.cellInfo.numServers = 0;
1246     DNSce.next = NULL;
1247
1248     rc = getAFSServer(ianaName, "udp", acellName, tservice,
1249                       cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1250                       &ttl);
1251     /* ignore the ttl here since this code is only called by transitory programs
1252      * like klog, etc. */
1253
1254     /* If we couldn't find an entry for the requested service
1255      * and that service happens to be the prservice or kaservice
1256      * then fallback to searching for afs3-vlserver and assigning
1257      * the port number here. */
1258     if (rc < 0 && tservice == htons(7002) || tservice == htons(7004)) {
1259         rc = getAFSServer("afs3-vlserver", "udp", acellName, tservice,
1260                            cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1261                            &ttl);
1262         if (rc >= 0) {
1263             for (i = 0; i < numServers; i++)
1264                 ports[i] = tservice;
1265         }
1266     }
1267
1268     if (rc < 0 || numServers == 0)
1269         return -1;
1270
1271     for (i = 0; i < numServers; i++) {
1272         memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1273                sizeof(long));
1274         memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1275         acellInfo->hostAddr[i].sin_family = AF_INET;
1276         if (aservice)
1277             acellInfo->hostAddr[i].sin_port = ports[i];
1278         else
1279             acellInfo->hostAddr[i].sin_port = 0;
1280     }
1281
1282     acellInfo->numServers = numServers;
1283     strlcpy(acellInfo->name, acellName, sizeof acellInfo->name);
1284     acellInfo->linkedCell = NULL;       /* no linked cell */
1285     acellInfo->flags = 0;
1286     return 0;
1287 }
1288 #endif /* windows */
1289
1290 int
1291 afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
1292                     struct afsconf_cell *acellInfo)
1293 {
1294     struct afsconf_entry *tce;
1295     struct afsconf_aliasentry *tcae;
1296     struct afsconf_entry *bestce;
1297     afs_int32 i;
1298     int tservice;
1299     char *tcell;
1300     int cnLen;
1301     int ambig;
1302     char tbuffer[64];
1303
1304     LOCK_GLOBAL_MUTEX;
1305     if (adir)
1306         _afsconf_Check(adir);
1307     if (acellName) {
1308         tcell = acellName;
1309         cnLen = (int)(strlen(tcell) + 1);
1310         lcstring(tcell, tcell, cnLen);
1311         afsconf_SawCell = 1;    /* will ignore the AFSCELL switch on future */
1312         /* call to afsconf_GetLocalCell: like klog  */
1313     } else {
1314         i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
1315         if (i) {
1316             UNLOCK_GLOBAL_MUTEX;
1317             return i;
1318         }
1319         tcell = tbuffer;
1320     }
1321     cnLen = strlen(tcell);
1322     bestce = (struct afsconf_entry *)0;
1323     ambig = 0;
1324     if (!adir) {
1325         UNLOCK_GLOBAL_MUTEX;
1326         return 0;
1327     }
1328
1329     /* Look through the list of aliases */
1330     for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
1331         if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
1332             tcell = tcae->aliasInfo.realName;
1333             break;
1334         }
1335     }
1336
1337     for (tce = adir->entries; tce; tce = tce->next) {
1338         if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
1339             /* found our cell */
1340             bestce = tce;
1341             ambig = 0;
1342             break;
1343         }
1344         if (strlen(tce->cellInfo.name) < cnLen)
1345             continue;           /* clearly wrong */
1346         if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
1347             if (bestce)
1348                 ambig = 1;      /* ambiguous unless we get exact match */
1349             bestce = tce;
1350         }
1351     }
1352     if (!ambig && bestce && bestce->cellInfo.numServers) {
1353         *acellInfo = bestce->cellInfo;  /* structure assignment */
1354         if (aservice) {
1355             tservice = afsconf_FindService(aservice);
1356             if (tservice < 0) {
1357                 UNLOCK_GLOBAL_MUTEX;
1358                 return AFSCONF_NOTFOUND;        /* service not found */
1359             }
1360             for (i = 0; i < acellInfo->numServers; i++) {
1361                 acellInfo->hostAddr[i].sin_port = tservice;
1362             }
1363         }
1364         acellInfo->timeout = 0;
1365
1366         /*
1367          * Until we figure out how to separate out ubik server
1368          * queries from other server queries, only perform gethostbyname()
1369          * lookup on the specified hostnames for the client CellServDB files.
1370          */
1371         if (_afsconf_IsClientConfigDirectory(adir->name) &&
1372             !(acellInfo->flags & AFSCONF_CELL_FLAG_DNS_QUERIED)) {
1373             int j;
1374             short numServers=0;                                 /*Num active servers for the cell */
1375             struct sockaddr_in hostAddr[MAXHOSTSPERCELL];       /*IP addresses for cell's servers */
1376             char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];       /*Names for cell's servers */
1377
1378             memset(&hostAddr, 0, sizeof(hostAddr));
1379             memset(&hostName, 0, sizeof(hostName));
1380
1381             for ( j=0; j<acellInfo->numServers && numServers < MAXHOSTSPERCELL; j++ ) {
1382                 struct hostent *he = gethostbyname(acellInfo->hostName[j]);
1383                 int foundAddr = 0;
1384
1385                 if (he && he->h_addrtype == AF_INET) {
1386                     int i;
1387                     /* obtain all the valid address from the list */
1388                     for (i=0 ; he->h_addr_list[i] && numServers < MAXHOSTSPERCELL; i++) {
1389                         /* check to see if this is a new address; if so insert it into the list */
1390                         int k, dup;
1391                         for (k=0, dup=0; !dup && k < numServers; k++) {
1392                             if (hostAddr[k].sin_addr.s_addr == *(u_long *)he->h_addr_list[i])
1393                                 dup = 1;
1394                         }
1395                         if (dup)
1396                             continue;
1397
1398                         hostAddr[numServers].sin_family = AF_INET;
1399                         hostAddr[numServers].sin_port = acellInfo->hostAddr[0].sin_port;
1400 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
1401                         hostAddr[numServers].sin_len = sizeof(struct sockaddr_in);
1402 #endif
1403                         memcpy(&hostAddr[numServers].sin_addr.s_addr, he->h_addr_list[i], sizeof(long));
1404                         strcpy(hostName[numServers], acellInfo->hostName[j]);
1405                         foundAddr = 1;
1406                         numServers++;
1407                     }
1408                 }
1409                 if (!foundAddr) {
1410                     hostAddr[numServers] = acellInfo->hostAddr[j];
1411                     strcpy(hostName[numServers], acellInfo->hostName[j]);
1412                     numServers++;
1413                 }
1414             }
1415
1416             for (i=0; i<numServers; i++) {
1417                 acellInfo->hostAddr[i] = hostAddr[i];
1418                 strcpy(acellInfo->hostName[i], hostName[i]);
1419             }
1420             acellInfo->numServers = numServers;
1421             acellInfo->flags |= AFSCONF_CELL_FLAG_DNS_QUERIED;
1422         }
1423         UNLOCK_GLOBAL_MUTEX;
1424         return 0;
1425     } else {
1426         UNLOCK_GLOBAL_MUTEX;
1427         return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
1428     }
1429 }
1430
1431 int
1432 afsconf_GetLocalCell(struct afsconf_dir *adir, char *aname,
1433                      afs_int32 alen)
1434 {
1435     static int afsconf_showcell = 0;
1436     char *afscell_path;
1437     afs_int32 code = 0;
1438
1439     LOCK_GLOBAL_MUTEX;
1440     /*
1441      * If a cell switch was specified in a command, then it should override the
1442      * AFSCELL variable.  If a cell was specified, then the afsconf_SawCell flag
1443      * is set and the cell name in the adir structure is used.
1444      * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
1445      */
1446     if (!afsconf_SawCell && (afscell_path = getenv("AFSCELL"))) {
1447         if (!afsconf_showcell) {
1448             fprintf(stderr, "Note: Operation is performed on cell %s\n",
1449                     afscell_path);
1450             afsconf_showcell = 1;
1451         }
1452         strncpy(aname, afscell_path, alen);
1453     } else {
1454         _afsconf_Check(adir);
1455         if (adir->cellName) {
1456             strncpy(aname, adir->cellName, alen);
1457         } else
1458             code = AFSCONF_UNKNOWN;
1459     }
1460
1461     UNLOCK_GLOBAL_MUTEX;
1462     return (code);
1463 }
1464
1465 int
1466 afsconf_Close(struct afsconf_dir *adir)
1467 {
1468     LOCK_GLOBAL_MUTEX;
1469     afsconf_CloseInternal(adir);
1470     if (adir->name)
1471         free(adir->name);
1472     free(adir);
1473     UNLOCK_GLOBAL_MUTEX;
1474     return 0;
1475 }
1476
1477 static int
1478 afsconf_CloseInternal(struct afsconf_dir *adir)
1479 {
1480     struct afsconf_entry *td, *nd;
1481     struct afsconf_aliasentry *ta, *na;
1482     char *tname;
1483
1484     tname = adir->name;         /* remember name, since that's all we preserve */
1485
1486     /* free everything we can find */
1487     if (adir->cellName)
1488         free(adir->cellName);
1489     for (td = adir->entries; td; td = nd) {
1490         nd = td->next;
1491         if (td->cellInfo.linkedCell)
1492             free(td->cellInfo.linkedCell);
1493         free(td);
1494     }
1495     for (ta = adir->alias_entries; ta; ta = na) {
1496         na = ta->next;
1497         free(ta);
1498     }
1499
1500     _afsconf_FreeAllKeys(adir);
1501
1502     /* reinit */
1503     memset(adir, 0, sizeof(struct afsconf_dir));
1504     adir->name = tname;         /* restore it */
1505     return 0;
1506 }
1507
1508 static int
1509 afsconf_Reopen(struct afsconf_dir *adir)
1510 {
1511     afs_int32 code;
1512     code = afsconf_CloseInternal(adir);
1513     if (code)
1514         return code;
1515     code = afsconf_OpenInternal(adir, 0, 0);
1516     return code;
1517 }