8b6915f021e4f00956fd6e4a3d473c5a6702afbb
[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((void *) 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((void *)iop->buffer);
158     free((void *)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             asprintf(path, "%s/%s", p, AFSDIR_CELLSERVDB_FILE_NTCLIENT);
331             free(p);
332         } else {
333             asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE_NTCLIENT);
334         }
335     } else {
336         asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE);
337     }
338     return;
339 }
340 #else
341 static void
342 _afsconf_CellServDBPath(struct afsconf_dir *adir, char **path)
343 {
344     asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE);
345 }
346 #endif /* AFS_NT40_ENV */
347
348 int
349 _afsconf_UpToDate(struct afsconf_dir *adir)
350 {
351     char *cellservDB;
352     struct stat tstat;
353     int code;
354     time_t now = time(0);
355
356     if (adir->timeCheck == now) {
357         return 1; /* stat no more than once a second */
358     }
359     adir->timeCheck = now;
360
361     _afsconf_CellServDBPath(adir, &cellservDB);
362     if (cellservDB == NULL)
363         return 0;
364
365     code = stat(cellservDB, &tstat);
366     free(cellservDB);
367     if (code < 0)
368         return 0; /* Can't throw the error, so just say we're not up to date */
369
370     /* did file change? */
371     if (tstat.st_mtime == adir->timeRead)
372         return 1;
373
374     /* otherwise file has changed */
375     return 0;
376 }
377
378 int
379 afsconf_UpToDate(void *rock)
380 {
381     int code;
382
383     LOCK_GLOBAL_MUTEX;
384     code = _afsconf_UpToDate(rock);
385     UNLOCK_GLOBAL_MUTEX;
386
387     return code;
388 }
389
390 int
391 _afsconf_Check(struct afsconf_dir *adir)
392 {
393     /* did configuration change? */
394     if (_afsconf_UpToDate(adir))
395         return 0;
396
397     /* otherwise file has changed, so reopen it */
398     return afsconf_Reopen(adir);
399 }
400
401 /* set modtime on file */
402 int
403 _afsconf_Touch(struct afsconf_dir *adir)
404 {
405     char *cellservDB;
406     int code;
407 #ifndef AFS_NT40_ENV
408     struct timeval tvp[2];
409 #endif
410
411     adir->timeRead = 0;         /* just in case */
412     adir->timeCheck = 0;
413
414     _afsconf_CellServDBPath(adir, &cellservDB);
415     if (cellservDB == NULL)
416         return ENOMEM;
417
418 #ifdef AFS_NT40_ENV
419     code = _utime(cellservDB, NULL);
420 #else
421     gettimeofday(&tvp[0], NULL);
422     tvp[1] = tvp[0];
423     code = utimes(cellservDB, tvp);
424 #endif /* AFS_NT40_ENV */
425     free(cellservDB);
426
427     return code;
428 }
429
430 struct afsconf_dir *
431 afsconf_Open(const char *adir)
432 {
433     struct afsconf_dir *tdir;
434     afs_int32 code;
435
436     LOCK_GLOBAL_MUTEX;
437     /* zero structure and fill in name; rest is done by internal routine */
438     tdir = (struct afsconf_dir *)malloc(sizeof(struct afsconf_dir));
439     memset(tdir, 0, sizeof(struct afsconf_dir));
440     tdir->name = strdup(adir);
441
442     code = afsconf_OpenInternal(tdir, 0, 0);
443     if (code) {
444         char *afsconf_path, afs_confdir[128];
445
446         free(tdir->name);
447         /* Check global place only when local Open failed for whatever reason */
448         if (!(afsconf_path = getenv("AFSCONF"))) {
449             /* 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... */
450             char *home_dir;
451             afsconf_FILE *fp;
452             size_t len;
453
454             if (!(home_dir = getenv("HOME"))) {
455                 /* Our last chance is the "/.AFSCONF" file */
456                 fp = fopen("/.AFSCONF", "r");
457                 if (fp == 0) {
458                     free(tdir);
459                     UNLOCK_GLOBAL_MUTEX;
460                     return (struct afsconf_dir *)0;
461                 }
462                 fgets(afs_confdir, 128, fp);
463                 fclose(fp);
464             } else {
465                 char pathname[256];
466
467                 sprintf(pathname, "%s/%s", home_dir, ".AFSCONF");
468                 fp = fopen(pathname, "r");
469                 if (fp == 0) {
470                     /* Our last chance is the "/.AFSCONF" file */
471                     fp = fopen("/.AFSCONF", "r");
472                     if (fp == 0) {
473                         free(tdir);
474                         UNLOCK_GLOBAL_MUTEX;
475                         return (struct afsconf_dir *)0;
476                     }
477                 }
478                 fgets(afs_confdir, 128, fp);
479                 fclose(fp);
480             }
481             len = strlen(afs_confdir);
482             if (len == 0) {
483                 free(tdir);
484                 UNLOCK_GLOBAL_MUTEX;
485                 return (struct afsconf_dir *)0;
486             }
487             if (afs_confdir[len - 1] == '\n') {
488                 afs_confdir[len - 1] = 0;
489             }
490             afsconf_path = afs_confdir;
491         }
492         tdir->name = strdup(afsconf_path);
493         code = afsconf_OpenInternal(tdir, 0, 0);
494         if (code) {
495             free(tdir->name);
496             free(tdir);
497             UNLOCK_GLOBAL_MUTEX;
498             return (struct afsconf_dir *)0;
499         }
500     }
501     UNLOCK_GLOBAL_MUTEX;
502     return tdir;
503 }
504
505 static int
506 GetCellUnix(struct afsconf_dir *adir)
507 {
508     char *rc;
509     char tbuffer[256];
510     char *start, *p;
511     afsconf_FILE *fp;
512
513     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
514     fp = fopen(tbuffer, "r");
515     if (fp == 0) {
516         return -1;
517     }
518     rc = fgets(tbuffer, 256, fp);
519     fclose(fp);
520     if (rc == NULL)
521         return -1;
522
523     start = tbuffer;
524     while (*start != '\0' && isspace(*start))
525         start++;
526     p = start;
527     while (*p != '\0' && !isspace(*p))
528         p++;
529     *p = '\0';
530     if (*start == '\0')
531         return -1;
532
533     adir->cellName = strdup(start);
534     return 0;
535 }
536
537
538 #ifdef AFS_NT40_ENV
539 static int
540 GetCellNT(struct afsconf_dir *adir)
541 {
542     if (_afsconf_IsClientConfigDirectory(adir->name)) {
543         /* NT client config dir; ThisCell is in registry (no file). */
544         return afssw_GetClientCellName(&adir->cellName);
545     } else {
546         /* NT server config dir; works just like Unix */
547         return GetCellUnix(adir);
548     }
549 }
550
551 /* The following procedures and structs are used on Windows only
552  * to enumerate the Cell information distributed within the
553  * Windows registry.  (See src/WINNT/afsd/cm_config.c)
554  */
555 typedef struct _cm_enumCellRegistry {
556     afs_uint32 client;  /* non-zero if client query */
557     struct afsconf_dir *adir;
558 } cm_enumCellRegistry_t;
559
560 static long
561 cm_serverConfigProc(void *rockp, struct sockaddr_in *addrp,
562                     char *hostNamep, unsigned short rank)
563 {
564     struct afsconf_cell *cellInfop = (struct afsconf_cell *)rockp;
565
566     if (cellInfop->numServers == MAXHOSTSPERCELL)
567         return 0;
568
569     cellInfop->hostAddr[cellInfop->numServers] = *addrp;
570     strncpy(cellInfop->hostName[cellInfop->numServers], hostNamep, MAXHOSTCHARS);
571     cellInfop->hostName[cellInfop->numServers][MAXHOSTCHARS-1] = '\0';
572     cellInfop->numServers++;
573
574     return 0;
575 }
576
577 static long
578 cm_enumCellRegistryProc(void *rockp, char * cellNamep)
579 {
580     long code;
581     cm_enumCellRegistry_t *enump = (cm_enumCellRegistry_t *)rockp;
582     char linkedName[256] = "";
583     int timeout = 0;
584     struct afsconf_entry *newEntry;
585
586
587     newEntry = malloc(sizeof(struct afsconf_entry));
588     if (newEntry == NULL)
589         return ENOMEM;
590     newEntry->cellInfo.numServers = 0;
591
592     code = cm_SearchCellRegistry(enump->client, cellNamep, NULL, linkedName, cm_serverConfigProc, &newEntry->cellInfo);
593     if (code == CM_ERROR_FORCE_DNS_LOOKUP)
594         code = cm_SearchCellByDNS(cellNamep, NULL, &timeout, cm_serverConfigProc, &newEntry->cellInfo);
595
596     if (code == 0) {
597         strncpy(newEntry->cellInfo.name, cellNamep, MAXCELLCHARS);
598         newEntry->cellInfo.name[MAXCELLCHARS-1];
599         if (linkedName[0])
600             newEntry->cellInfo.linkedCell = strdup(linkedName);
601         else
602             newEntry->cellInfo.linkedCell = NULL;
603         newEntry->cellInfo.timeout = timeout;
604         newEntry->cellInfo.flags = 0;
605
606         newEntry->next = enump->adir->entries;
607         enump->adir->entries = newEntry;
608     } else {
609         free(newEntry);
610     }
611     return code;
612 }
613 #endif /* AFS_NT40_ENV */
614
615
616 static int
617 afsconf_OpenInternal(struct afsconf_dir *adir, char *cell,
618                      char clones[])
619 {
620     afsconf_FILE *tf;
621     char *tp, *bp;
622     struct afsconf_entry *curEntry;
623     struct afsconf_aliasentry *curAlias;
624     afs_int32 code;
625     afs_int32 i;
626     char tbuffer[256];
627     struct stat tstat;
628     char *cellservDB;
629
630 #ifdef AFS_NT40_ENV
631     cm_enumCellRegistry_t enumCellRegistry = {0, 0};
632 #endif /* AFS_NT40_ENV */
633
634     /* figure out the local cell name */
635 #ifdef AFS_NT40_ENV
636     i = GetCellNT(adir);
637     enumCellRegistry.adir = adir;
638 #else
639     i = GetCellUnix(adir);
640 #endif
641
642 #ifndef AFS_FREELANCE_CLIENT    /* no local cell not fatal in freelance */
643     if (i) {
644         return i;
645     }
646 #endif
647
648     /* now parse the individual lines */
649     curEntry = 0;
650
651     _afsconf_CellServDBPath(adir, &cellservDB);
652
653 #ifdef AFS_NT40_ENV
654     if (_afsconf_IsClientConfigDirectory(adir->name))
655         enumCellRegistry.client = 1;
656 #endif /* AFS_NT40_ENV */
657
658     if (!stat(cellservDB, &tstat)) {
659         adir->timeRead = tstat.st_mtime;
660     } else {
661         adir->timeRead = 0;
662     }
663
664     tf = fopen(cellservDB, "r");
665     if (!tf) {
666         return -1;
667     }
668
669     /* init the keys queue before any call to afsconf_CloseInternal() */
670     _afsconf_InitKeys(adir);
671
672     /* The CellServDB file is now open.
673      * The following code parses the contents of the
674      * file and creates a list with the first cell entry
675      * in the CellServDB file at the end of the list.
676      *
677      * No checking is performed for duplicates.
678      * The side effects of this process are that duplicate
679      * entries appended to the end of the CellServDB file
680      * take precedence and are found in a shorter period
681      * of time.
682      */
683
684     while (1) {
685         tp = fgets(tbuffer, sizeof(tbuffer), tf);
686         if (!tp)
687             break;
688         TrimLine(tbuffer, sizeof tbuffer);      /* remove white space */
689         if (tbuffer[0] == 0 || tbuffer[0] == '\n')
690             continue;           /* empty line */
691         if (tbuffer[0] == '>') {
692             char linkedcell[MAXCELLCHARS];
693             /* start new cell item */
694             if (curEntry) {
695                 /* thread this guy on the list */
696                 curEntry->next = adir->entries;
697                 adir->entries = curEntry;
698                 curEntry = 0;
699             }
700             curEntry =
701                 (struct afsconf_entry *)malloc(sizeof(struct afsconf_entry));
702             memset(curEntry, 0, sizeof(struct afsconf_entry));
703             code =
704                 ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
705             if (code) {
706                 afsconf_CloseInternal(adir);
707                 fclose(tf);
708                 free(curEntry);
709                 return -1;
710             }
711             if (linkedcell[0] != '\0')
712                 curEntry->cellInfo.linkedCell = strdup(linkedcell);
713         } else {
714             /* new host in the current cell */
715             if (!curEntry) {
716                 afsconf_CloseInternal(adir);
717                 fclose(tf);
718                 return -1;
719             }
720             i = curEntry->cellInfo.numServers;
721             if (i < MAXHOSTSPERCELL) {
722                 if (cell && !strcmp(cell, curEntry->cellInfo.name))
723                     code =
724                         ParseHostLine(tbuffer,
725                                       &curEntry->cellInfo.hostAddr[i],
726                                       curEntry->cellInfo.hostName[i],
727                                       &clones[i]);
728                 else
729                     code =
730                         ParseHostLine(tbuffer,
731                                       &curEntry->cellInfo.hostAddr[i],
732                                       curEntry->cellInfo.hostName[i], 0);
733
734                 if (code) {
735                     if (code == AFSCONF_SYNTAX) {
736                         for (bp = tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
737                             if (!*bp)
738                                 break;
739                         }
740                         *bp = '\0';
741                         fprintf(stderr,
742                                 "Can't properly parse host line \"%s\" in configuration file %s\n",
743                                 tbuffer, cellservDB);
744                     }
745                     free(curEntry);
746                     fclose(tf);
747                     afsconf_CloseInternal(adir);
748                     return -1;
749                 }
750                 curEntry->cellInfo.numServers = ++i;
751             } else {
752                 fprintf(stderr,
753                         "Too many hosts for cell %s in configuration file %s\n",
754                         curEntry->cellInfo.name, cellservDB);
755             }
756         }
757     }
758     fclose(tf);                 /* close the file now */
759     free(cellservDB);
760
761     /* end the last partially-completed cell */
762     if (curEntry) {
763         curEntry->next = adir->entries;
764         adir->entries = curEntry;
765     }
766
767 #ifdef AFS_NT40_ENV
768      /*
769       * Windows maintains a CellServDB list in the Registry
770       * that supercedes the contents of the CellServDB file.
771       * Prepending these entries to the head of the list
772       * is sufficient to enforce the precedence.
773       */
774      cm_EnumerateCellRegistry( enumCellRegistry.client,
775                                cm_enumCellRegistryProc,
776                                &enumCellRegistry);
777 #endif /* AFS_NT40_ENV */
778
779     /* Read in the alias list */
780     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
781
782     tf = fopen(tbuffer, "r");
783     while (tf) {
784         char *aliasPtr;
785
786         tp = fgets(tbuffer, sizeof(tbuffer), tf);
787         if (!tp)
788             break;
789         TrimLine(tbuffer, sizeof tbuffer);      /* remove white space */
790
791         if (tbuffer[0] == '\0' || tbuffer[0] == '\n' || tbuffer[0] == '#')
792             continue;           /* empty line */
793
794         tp = tbuffer;
795         while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t')
796             tp++;
797         if (tp[0] == '\0')
798             continue;           /* invalid line */
799
800         while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t'))
801             0[tp++] = '\0';
802         if (tp[0] == '\0')
803             continue;           /* invalid line */
804
805         aliasPtr = tp;
806         while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' && tp[0] != '\r'
807                && tp[0] != '\n')
808             tp++;
809         tp[0] = '\0';
810
811         curAlias = malloc(sizeof(*curAlias));
812         memset(curAlias, 0, sizeof(*curAlias));
813
814         strlcpy(curAlias->aliasInfo.aliasName, aliasPtr, sizeof curAlias->aliasInfo.aliasName);
815         strlcpy(curAlias->aliasInfo.realName, tbuffer, sizeof curAlias->aliasInfo.realName);
816
817         curAlias->next = adir->alias_entries;
818         adir->alias_entries = curAlias;
819     }
820
821     if (tf != NULL)
822         fclose(tf);
823
824     /* now read the fs keys, if possible */
825     code = _afsconf_LoadKeys(adir);
826     if (code) {
827         return code;
828     }
829     code = _afsconf_LoadRealms(adir);
830
831     return code;
832 }
833
834 /* parse a line of the form
835  *"128.2.1.3   #hostname" or
836  *"[128.2.1.3]  #hostname" for clones
837  * into the appropriate pieces.
838  */
839 static int
840 ParseHostLine(char *aline, struct sockaddr_in *addr, char *aname,
841               char *aclone)
842 {
843     int c1, c2, c3, c4;
844     afs_int32 code;
845     char *tp;
846
847     if (*aline == '[') {
848         if (aclone)
849             *aclone = 1;
850         /* FIXME: length of aname unknown here */
851         code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
852     } else {
853         if (aclone)
854             *aclone = 0;
855         /* FIXME: length of aname unknown here */
856         code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
857     }
858     if (code != 5)
859         return AFSCONF_SYNTAX;
860     addr->sin_family = AF_INET;
861     addr->sin_port = 0;
862 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
863     addr->sin_len = sizeof(struct sockaddr_in);
864 #endif
865     tp = (char *)&addr->sin_addr;
866     *tp++ = c1;
867     *tp++ = c2;
868     *tp++ = c3;
869     *tp++ = c4;
870     return 0;
871 }
872
873 /* parse a line of the form
874  * ">cellname [linkedcellname] [#comments]"
875  * into the appropriate pieces.
876  */
877 static int
878 ParseCellLine(char *aline, char *aname,
879               char *alname)
880 {
881     int code;
882     /* FIXME: length of aname, alname unknown here */
883     code = sscanf(aline, ">%s %s", aname, alname);
884     if (code == 1)
885         *alname = '\0';
886     if (code == 2) {
887         if (*alname == '#') {
888             *alname = '\0';
889         }
890     }
891     return (code > 0 ? 0 : AFSCONF_SYNTAX);
892 }
893
894 /* call aproc(entry, arock, adir) for all cells.  Proc must return 0, or we'll stop early and return the code it returns */
895 int
896 afsconf_CellApply(struct afsconf_dir *adir,
897                   int (*aproc) (struct afsconf_cell * cell, void *arock,
898                                 struct afsconf_dir * dir), void *arock)
899 {
900     struct afsconf_entry *tde;
901     afs_int32 code;
902     LOCK_GLOBAL_MUTEX;
903     for (tde = adir->entries; tde; tde = tde->next) {
904         code = (*aproc) (&tde->cellInfo, arock, adir);
905         if (code) {
906             UNLOCK_GLOBAL_MUTEX;
907             return code;
908         }
909     }
910     UNLOCK_GLOBAL_MUTEX;
911     return 0;
912 }
913
914 /* call aproc(entry, arock, adir) for all cell aliases.
915  * Proc must return 0, or we'll stop early and return the code it returns
916  */
917 int
918 afsconf_CellAliasApply(struct afsconf_dir *adir,
919                        int (*aproc) (struct afsconf_cellalias * alias,
920                                      void *arock, struct afsconf_dir * dir),
921                        void *arock)
922 {
923     struct afsconf_aliasentry *tde;
924     afs_int32 code;
925     LOCK_GLOBAL_MUTEX;
926     for (tde = adir->alias_entries; tde; tde = tde->next) {
927         code = (*aproc) (&tde->aliasInfo, arock, adir);
928         if (code) {
929             UNLOCK_GLOBAL_MUTEX;
930             return code;
931         }
932     }
933     UNLOCK_GLOBAL_MUTEX;
934     return 0;
935 }
936
937 afs_int32 afsconf_SawCell = 0;
938
939 int
940 afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, char *acellName,
941                             char *aservice, struct afsconf_cell *acellInfo,
942                             char clones[])
943 {
944     afs_int32 code;
945     char *cell;
946
947     code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
948     if (code)
949         return code;
950
951     if (acellName)
952         cell = acellName;
953     else
954         cell = (char *)&acellInfo->name;
955
956     code = afsconf_OpenInternal(adir, cell, clones);
957     return code;
958 }
959
960 #if !defined(AFS_NT40_ENV)
961 int
962 afsconf_LookupServer(const char *service, const char *protocol,
963                      const char *cellName, unsigned short afsdbPort,
964                      int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
965                      unsigned short ports[], unsigned short ipRanks[],
966                      int *numServers, int *ttl, char **arealCellName)
967 {
968     int code = 0;
969     int len;
970     unsigned char answer[1024];
971     unsigned char *p;
972     char *dotcellname = NULL;
973     char *realCellName;
974     char host[256];
975     int server_num = 0;
976     int minttl = 0;
977     int try_init = 0;
978     int dnstype = 0;
979     int pass = 0;
980     char *IANAname = (char *) afsconf_FindIANAName(service);
981     int tservice = afsconf_FindService(service);
982
983     realCellName = NULL;
984
985     *numServers = 0;
986     *ttl = 0;
987     if (tservice <= 0 || !IANAname)
988         return AFSCONF_NOTFOUND;        /* service not found */
989
990     if (strchr(cellName,'.'))
991         pass += 2;
992
993 #ifdef HAVE_RES_RETRANSRETRY
994     if ((_res.options & RES_INIT) == 0 && res_init() == -1)
995       return (0);
996
997     /*
998      * Rx timeout is typically 56 seconds; limit user experience to
999      * similar timeout
1000      */
1001     _res.retrans = 18;
1002     _res.retry = 3;
1003 #endif
1004
1005  retryafsdb:
1006     switch (pass) {
1007     case 0:
1008         dnstype = T_SRV;
1009         asprintf(&dotcellname, "_%s._%s.%s.", IANAname, protocol, cellName);
1010         break;
1011     case 1:
1012         dnstype = T_AFSDB;
1013         asprintf(&dotcellname, "%s.", cellName);
1014         break;
1015     case 2:
1016         dnstype = T_SRV;
1017         asprintf(&dotcellname, "_%s._%s.%s", IANAname, protocol, cellName);
1018         break;
1019     case 3:
1020         dnstype = T_AFSDB;
1021         asprintf(&dotcellname, "%s", cellName);
1022         break;
1023     }
1024     if (dotcellname == NULL)
1025         goto findservererror;
1026
1027     LOCK_GLOBAL_MUTEX;
1028     len = res_search(dotcellname, C_IN, dnstype, answer, sizeof(answer));
1029     UNLOCK_GLOBAL_MUTEX;
1030
1031     if (dotcellname != NULL) {
1032         free(dotcellname);
1033         dotcellname = NULL;
1034     }
1035
1036     if (len < 0) {
1037         if (try_init < 1) {
1038             try_init++;
1039             res_init();
1040             goto retryafsdb;
1041         }
1042         if (pass < 3) {
1043             pass++;
1044             goto retryafsdb;
1045         } else {
1046             code = AFSCONF_NOTFOUND;
1047             goto findservererror;
1048         }
1049     }
1050
1051     p = answer + sizeof(HEADER);        /* Skip header */
1052     code = dn_expand(answer, answer + len, p, host, sizeof(host));
1053     if (code < 0) {
1054         code = AFSCONF_NOTFOUND;
1055         goto findservererror;
1056     }
1057
1058     p += code + QFIXEDSZ;       /* Skip name */
1059
1060     while (p < answer + len) {
1061         int type, ttl, size;
1062
1063         code = dn_expand(answer, answer + len, p, host, sizeof(host));
1064         if (code < 0) {
1065             code = AFSCONF_NOTFOUND;
1066             goto findservererror;
1067         }
1068
1069         p += code;              /* Skip the name */
1070         type = (p[0] << 8) | p[1];
1071         p += 4;                 /* Skip type and class */
1072         ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
1073         p += 4;                 /* Skip the TTL */
1074         size = (p[0] << 8) | p[1];
1075         p += 2;                 /* Skip the size */
1076
1077         if (type == T_AFSDB) {
1078             struct hostent *he;
1079             short afsdb_type;
1080
1081             afsdb_type = (p[0] << 8) | p[1];
1082             if (afsdb_type == 1) {
1083                 /*
1084                  * We know this is an AFSDB record for our cell, of the
1085                  * right AFSDB type.  Write down the true cell name that
1086                  * the resolver gave us above.
1087                  */
1088                 if (!realCellName)
1089                     realCellName = strdup(host);
1090             }
1091
1092             code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
1093             if (code < 0) {
1094                 code = AFSCONF_NOTFOUND;
1095                 goto findservererror;
1096             }
1097
1098             if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) &&
1099                 /* Do we want to get TTL data for the A record as well? */
1100                 (he = gethostbyname(host))) {
1101                 if (he->h_addrtype == AF_INET) {
1102                     afs_int32 ipaddr;
1103                     memcpy(&ipaddr, he->h_addr, sizeof(ipaddr));
1104                     cellHostAddrs[server_num] = ipaddr;
1105                     ports[server_num] = afsdbPort;
1106                     ipRanks[server_num] = 0;
1107                     strncpy(cellHostNames[server_num], host,
1108                             sizeof(cellHostNames[server_num]));
1109                     server_num++;
1110                     if (!minttl || ttl < minttl)
1111                         minttl = ttl;
1112                 }
1113             }
1114         }
1115         if (type == T_SRV) {
1116             struct hostent *he;
1117             /* math here: _ is 1, _ ._ is 3, _ ._ . is 4. then the domain. */
1118             if ((strncmp(host + 1, IANAname, strlen(IANAname)) == 0) &&
1119                 (strncmp(host + strlen(IANAname) + 3, protocol,
1120                          strlen(protocol)) == 0)) {
1121                 if (!realCellName)
1122                     realCellName = strdup(host + strlen(IANAname) +
1123                                           strlen(protocol) + 4);
1124             }
1125
1126             code = dn_expand(answer, answer + len, p + 6, host, sizeof(host));
1127             if (code < 0) {
1128                 code = AFSCONF_NOTFOUND;
1129                 goto findservererror;
1130             }
1131
1132             if ((server_num < MAXHOSTSPERCELL) &&
1133                 /* Do we want to get TTL data for the A record as well? */
1134                 (he = gethostbyname(host))) {
1135                 if (he->h_addrtype == AF_INET) {
1136                     afs_int32 ipaddr;
1137
1138                     memcpy(&ipaddr, he->h_addr, sizeof(ipaddr));
1139                     cellHostAddrs[server_num] = ipaddr;
1140                     ipRanks[server_num] = (p[0] << 8) | p[1];
1141                     ports[server_num] = htons((p[4] << 8) | p[5]);
1142                     /* weight = (p[2] << 8) | p[3]; */
1143                     strncpy(cellHostNames[server_num], host,
1144                             sizeof(cellHostNames[server_num]));
1145                     server_num++;
1146
1147                     if (!minttl || ttl < minttl)
1148                         minttl = ttl;
1149                 }
1150             }
1151         }
1152
1153         p += size;
1154     }
1155
1156     if (server_num == 0) {      /* No AFSDB or SRV records */
1157         code = AFSCONF_NOTFOUND;
1158         goto findservererror;
1159     }
1160
1161     if (realCellName) {
1162         /* Convert the real cell name to lowercase */
1163         for (p = (unsigned char *)realCellName; *p; p++)
1164             *p = tolower(*p);
1165     }
1166
1167     *numServers = server_num;
1168     *ttl = minttl ? (time(0) + minttl) : 0;
1169
1170     if ( *numServers > 0 ) {
1171         code =  0;
1172         *arealCellName = realCellName;
1173     } else
1174         code = AFSCONF_NOTFOUND;
1175
1176 findservererror:
1177     if (code && realCellName)
1178         free(realCellName);
1179     return code;
1180 }
1181
1182 int
1183 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1184                      struct afsconf_cell *acellInfo)
1185 {
1186     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
1187     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1188     unsigned short ipRanks[AFSMAXCELLHOSTS];
1189     unsigned short ports[AFSMAXCELLHOSTS];
1190     char *realCellName = NULL;
1191     int ttl, numServers, i;
1192     char *service = aservice;
1193     int code;
1194     unsigned short afsdbport;
1195     if (!service) {
1196         service = "afs3-vlserver";
1197         afsdbport = htons(7003);
1198     } else {
1199         service = aservice;
1200         afsdbport = afsconf_FindService(service);
1201     }
1202     code = afsconf_LookupServer((const char *)service, "udp",
1203                                 (const char *)acellName, afsdbport,
1204                                 cellHostAddrs, cellHostNames,
1205                                 ports, ipRanks, &numServers, &ttl,
1206                                 &realCellName);
1207
1208     /* If we couldn't find an entry for the requested service
1209      * and that service happens to be the prservice or kaservice
1210      * then fallback to searching for afs3-vlserver and assigning
1211      * the port number here. */
1212     if (code < 0 && (afsdbport == htons(7002) || afsdbport == htons(7004))) {
1213         code = afsconf_LookupServer("afs3-vlserver", "udp",
1214                                     (const char *)acellName, afsdbport,
1215                                     cellHostAddrs, cellHostNames,
1216                                     ports, ipRanks, &numServers, &ttl,
1217                                     &realCellName);
1218         if (code >= 0) {
1219             for (i = 0; i < numServers; i++)
1220                 ports[i] = afsdbport;
1221         }
1222     }
1223     if (code == 0) {
1224         acellInfo->timeout = ttl;
1225         acellInfo->numServers = numServers;
1226         for (i = 0; i < numServers; i++) {
1227             memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1228                    sizeof(afs_int32));
1229             memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1230             acellInfo->hostAddr[i].sin_family = AF_INET;
1231             acellInfo->hostAddr[i].sin_port = ports[i];
1232
1233             if (realCellName) {
1234                 strlcpy(acellInfo->name, realCellName,
1235                         sizeof(acellInfo->name));
1236                 free(realCellName);
1237                 realCellName = NULL;
1238             }
1239         }
1240         acellInfo->linkedCell = NULL;       /* no linked cell */
1241         acellInfo->flags = 0;
1242     }
1243     return code;
1244 }
1245 #else /* windows */
1246 int
1247 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1248                      struct afsconf_cell *acellInfo)
1249 {
1250     afs_int32 i;
1251     int tservice = afsconf_FindService(aservice);   /* network byte order */
1252     const char *ianaName = afsconf_FindIANAName(aservice);
1253     struct afsconf_entry DNSce;
1254     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
1255     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1256     unsigned short ipRanks[AFSMAXCELLHOSTS];
1257     unsigned short ports[AFSMAXCELLHOSTS];          /* network byte order */
1258     int numServers;
1259     int rc;
1260     int ttl;
1261
1262     if (tservice < 0) {
1263         if (aservice)
1264             return AFSCONF_NOTFOUND;
1265         else
1266             tservice = 0;       /* port will be assigned by caller */
1267     }
1268
1269     if (ianaName == NULL)
1270         ianaName = "afs3-vlserver";
1271
1272     DNSce.cellInfo.numServers = 0;
1273     DNSce.next = NULL;
1274
1275     rc = getAFSServer(ianaName, "udp", acellName, tservice,
1276                       cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1277                       &ttl);
1278     /* ignore the ttl here since this code is only called by transitory programs
1279      * like klog, etc. */
1280
1281     /* If we couldn't find an entry for the requested service
1282      * and that service happens to be the prservice or kaservice
1283      * then fallback to searching for afs3-vlserver and assigning
1284      * the port number here. */
1285     if (rc < 0 && (tservice == htons(7002) || tservice == htons(7004))) {
1286         rc = getAFSServer("afs3-vlserver", "udp", acellName, tservice,
1287                            cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1288                            &ttl);
1289         if (rc >= 0) {
1290             for (i = 0; i < numServers; i++)
1291                 ports[i] = tservice;
1292         }
1293     }
1294
1295     if (rc < 0 || numServers == 0)
1296         return -1;
1297
1298     for (i = 0; i < numServers; i++) {
1299         memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1300                sizeof(long));
1301         memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1302         acellInfo->hostAddr[i].sin_family = AF_INET;
1303         if (aservice)
1304             acellInfo->hostAddr[i].sin_port = ports[i];
1305         else
1306             acellInfo->hostAddr[i].sin_port = 0;
1307     }
1308
1309     acellInfo->numServers = numServers;
1310     strlcpy(acellInfo->name, acellName, sizeof acellInfo->name);
1311     acellInfo->linkedCell = NULL;       /* no linked cell */
1312     acellInfo->flags = 0;
1313     return 0;
1314 }
1315 #endif /* windows */
1316
1317 int
1318 afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
1319                     struct afsconf_cell *acellInfo)
1320 {
1321     struct afsconf_entry *tce;
1322     struct afsconf_aliasentry *tcae;
1323     struct afsconf_entry *bestce;
1324     afs_int32 i;
1325     int tservice;
1326     char *tcell;
1327     int cnLen;
1328     int ambig;
1329     char tbuffer[64];
1330
1331     LOCK_GLOBAL_MUTEX;
1332     if (adir)
1333         _afsconf_Check(adir);
1334     if (acellName) {
1335         tcell = acellName;
1336         cnLen = (int)(strlen(tcell) + 1);
1337         lcstring(tcell, tcell, cnLen);
1338         afsconf_SawCell = 1;    /* will ignore the AFSCELL switch on future */
1339         /* call to afsconf_GetLocalCell: like klog  */
1340     } else {
1341         i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
1342         if (i) {
1343             UNLOCK_GLOBAL_MUTEX;
1344             return i;
1345         }
1346         tcell = tbuffer;
1347     }
1348     cnLen = strlen(tcell);
1349     bestce = (struct afsconf_entry *)0;
1350     ambig = 0;
1351     if (!adir) {
1352         UNLOCK_GLOBAL_MUTEX;
1353         return 0;
1354     }
1355
1356     /* Look through the list of aliases */
1357     for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
1358         if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
1359             tcell = tcae->aliasInfo.realName;
1360             break;
1361         }
1362     }
1363
1364     for (tce = adir->entries; tce; tce = tce->next) {
1365         if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
1366             /* found our cell */
1367             bestce = tce;
1368             ambig = 0;
1369             break;
1370         }
1371         if (strlen(tce->cellInfo.name) < cnLen)
1372             continue;           /* clearly wrong */
1373         if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
1374             if (bestce)
1375                 ambig = 1;      /* ambiguous unless we get exact match */
1376             bestce = tce;
1377         }
1378     }
1379     if (!ambig && bestce && bestce->cellInfo.numServers) {
1380         *acellInfo = bestce->cellInfo;  /* structure assignment */
1381         if (aservice) {
1382             tservice = afsconf_FindService(aservice);
1383             if (tservice < 0) {
1384                 UNLOCK_GLOBAL_MUTEX;
1385                 return AFSCONF_NOTFOUND;        /* service not found */
1386             }
1387             for (i = 0; i < acellInfo->numServers; i++) {
1388                 acellInfo->hostAddr[i].sin_port = tservice;
1389             }
1390         }
1391         acellInfo->timeout = 0;
1392
1393         /*
1394          * Until we figure out how to separate out ubik server
1395          * queries from other server queries, only perform gethostbyname()
1396          * lookup on the specified hostnames for the client CellServDB files.
1397          */
1398         if (_afsconf_IsClientConfigDirectory(adir->name) &&
1399             !(acellInfo->flags & AFSCONF_CELL_FLAG_DNS_QUERIED)) {
1400             int j;
1401             short numServers=0;                                 /*Num active servers for the cell */
1402             struct sockaddr_in hostAddr[MAXHOSTSPERCELL];       /*IP addresses for cell's servers */
1403             char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];       /*Names for cell's servers */
1404
1405             memset(&hostAddr, 0, sizeof(hostAddr));
1406             memset(&hostName, 0, sizeof(hostName));
1407
1408             for ( j=0; j<acellInfo->numServers && numServers < MAXHOSTSPERCELL; j++ ) {
1409                 struct hostent *he = gethostbyname(acellInfo->hostName[j]);
1410                 int foundAddr = 0;
1411
1412                 if (he && he->h_addrtype == AF_INET) {
1413                     int i;
1414                     /* obtain all the valid address from the list */
1415                     for (i=0 ; he->h_addr_list[i] && numServers < MAXHOSTSPERCELL; i++) {
1416                         /* check to see if this is a new address; if so insert it into the list */
1417                         int k, dup;
1418                         for (k=0, dup=0; !dup && k < numServers; k++) {
1419                             if (hostAddr[k].sin_addr.s_addr == *(u_long *)he->h_addr_list[i])
1420                                 dup = 1;
1421                         }
1422                         if (dup)
1423                             continue;
1424
1425                         hostAddr[numServers].sin_family = AF_INET;
1426                         hostAddr[numServers].sin_port = acellInfo->hostAddr[0].sin_port;
1427 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
1428                         hostAddr[numServers].sin_len = sizeof(struct sockaddr_in);
1429 #endif
1430                         memcpy(&hostAddr[numServers].sin_addr.s_addr, he->h_addr_list[i], sizeof(long));
1431                         strcpy(hostName[numServers], acellInfo->hostName[j]);
1432                         foundAddr = 1;
1433                         numServers++;
1434                     }
1435                 }
1436                 if (!foundAddr) {
1437                     hostAddr[numServers] = acellInfo->hostAddr[j];
1438                     strcpy(hostName[numServers], acellInfo->hostName[j]);
1439                     numServers++;
1440                 }
1441             }
1442
1443             for (i=0; i<numServers; i++) {
1444                 acellInfo->hostAddr[i] = hostAddr[i];
1445                 strcpy(acellInfo->hostName[i], hostName[i]);
1446             }
1447             acellInfo->numServers = numServers;
1448             acellInfo->flags |= AFSCONF_CELL_FLAG_DNS_QUERIED;
1449         }
1450         UNLOCK_GLOBAL_MUTEX;
1451         return 0;
1452     } else {
1453         UNLOCK_GLOBAL_MUTEX;
1454         return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
1455     }
1456 }
1457
1458 /**
1459  * Get the current localcell name.
1460  *
1461  * Internal function to get a pointer to the local cell name.
1462  * This function must be called with the global afsconf lock held.
1463  *
1464  * @param[in]  adir    afsconf object
1465  * @param[out] aname   address to a char pointer
1466  * @param[in]  check   always perform a config check, even if the
1467  *                     the AFSCELL name is set.
1468  *
1469  * @return status
1470  *    @retval 0 success
1471  *    @retval AFSCONF_UNKNOWN failed to get cellname
1472  *
1473  * @internal
1474  */
1475 int
1476 _afsconf_GetLocalCell(struct afsconf_dir *adir, char **pname, int check)
1477 {
1478     static int afsconf_showcell = 0;
1479     char *afscell_path;
1480     afs_int32 code = 0;
1481
1482     /*
1483      * If a cell switch was specified in a command, then it should override the
1484      * AFSCELL variable.  If a cell was specified, then the afsconf_SawCell flag
1485      * is set and the cell name in the adir structure is used.
1486      * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
1487      * Optionally, check the configuration, even if using the environment variable.
1488      */
1489     if (!afsconf_SawCell && (afscell_path = getenv("AFSCELL"))) {
1490         if (check) {
1491             _afsconf_Check(adir);
1492         }
1493         if (!afsconf_showcell) {
1494             fprintf(stderr, "Note: Operation is performed on cell %s\n",
1495                     afscell_path);
1496             afsconf_showcell = 1;
1497         }
1498         *pname = afscell_path;
1499     } else {
1500         _afsconf_Check(adir);
1501         if (adir->cellName) {
1502             *pname = adir->cellName;
1503         } else
1504             code = AFSCONF_UNKNOWN;
1505     }
1506     return code;
1507 }
1508
1509 int
1510 afsconf_GetLocalCell(struct afsconf_dir *adir, char *aname, afs_int32 alen)
1511 {
1512     afs_int32 code = 0;
1513     char *cellname = NULL;
1514
1515     LOCK_GLOBAL_MUTEX;
1516     code = _afsconf_GetLocalCell(adir, &cellname, 0);
1517     if (!code && cellname) {
1518         strlcpy(aname, cellname, alen);
1519     }
1520     UNLOCK_GLOBAL_MUTEX;
1521     return (code);
1522 }
1523
1524 int
1525 afsconf_Close(struct afsconf_dir *adir)
1526 {
1527     LOCK_GLOBAL_MUTEX;
1528     afsconf_CloseInternal(adir);
1529     if (adir->name)
1530         free(adir->name);
1531     free(adir);
1532     UNLOCK_GLOBAL_MUTEX;
1533     return 0;
1534 }
1535
1536 static int
1537 afsconf_CloseInternal(struct afsconf_dir *adir)
1538 {
1539     struct afsconf_entry *td, *nd;
1540     struct afsconf_aliasentry *ta, *na;
1541     char *tname;
1542
1543     tname = adir->name;         /* remember name, since that's all we preserve */
1544
1545     /* free everything we can find */
1546     if (adir->cellName)
1547         free(adir->cellName);
1548     for (td = adir->entries; td; td = nd) {
1549         nd = td->next;
1550         if (td->cellInfo.linkedCell)
1551             free(td->cellInfo.linkedCell);
1552         free(td);
1553     }
1554     for (ta = adir->alias_entries; ta; ta = na) {
1555         na = ta->next;
1556         free(ta);
1557     }
1558
1559     _afsconf_FreeAllKeys(adir);
1560     _afsconf_FreeRealms(adir);
1561
1562     /* reinit */
1563     memset(adir, 0, sizeof(struct afsconf_dir));
1564     adir->name = tname;         /* restore it */
1565     return 0;
1566 }
1567
1568 static int
1569 afsconf_Reopen(struct afsconf_dir *adir)
1570 {
1571     afs_int32 code;
1572     code = afsconf_CloseInternal(adir);
1573     if (code)
1574         return code;
1575     code = afsconf_OpenInternal(adir, 0, 0);
1576     return code;
1577 }