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