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