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