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