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