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