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