afsdb lookup shouldn't leak memory on realname lookup
[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                 if (!realCellName)
1124                     realCellName = strdup(host);
1125             }
1126
1127             code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
1128             if (code < 0) {
1129                 code = AFSCONF_NOTFOUND;
1130                 goto findservererror;
1131             }
1132
1133             if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) &&
1134                 /* Do we want to get TTL data for the A record as well? */
1135                 (he = gethostbyname(host))) {
1136                 afs_int32 ipaddr;
1137                 memcpy(&ipaddr, he->h_addr, he->h_length);
1138                 cellHostAddrs[server_num] = ipaddr;
1139                 ports[server_num] = afsdbPort;
1140                 ipRanks[server_num] = 0;
1141                 strncpy(cellHostNames[server_num], host,
1142                         sizeof(cellHostNames[server_num]));
1143                 server_num++;
1144
1145                 if (!minttl || ttl < minttl)
1146                     minttl = ttl;
1147             }
1148         }
1149         if (type == T_SRV) {
1150             struct hostent *he;
1151             /* math here: _ is 1, _ ._ is 3, _ ._ . is 4. then the domain. */
1152             if ((strncmp(host + 1, IANAname, strlen(IANAname)) == 0) &&
1153                 (strncmp(host + strlen(IANAname) + 3, protocol,
1154                          strlen(protocol)) == 0)) {
1155                 if (!realCellName)
1156                     realCellName = strdup(host + strlen(IANAname) +
1157                                           strlen(protocol) + 4);
1158             }
1159
1160             code = dn_expand(answer, answer + len, p + 6, host, sizeof(host));
1161             if (code < 0) {
1162                 code = AFSCONF_NOTFOUND;
1163                 goto findservererror;
1164             }
1165
1166             if ((server_num < MAXHOSTSPERCELL) &&
1167                 /* Do we want to get TTL data for the A record as well? */
1168                 (he = gethostbyname(host))) {
1169                 afs_int32 ipaddr;
1170                 memcpy(&ipaddr, he->h_addr, he->h_length);
1171                 cellHostAddrs[server_num] = ipaddr;
1172                 ipRanks[server_num] = (p[0] << 8) | p[1];
1173                 ports[server_num] = (p[4] << 8) | p[5];
1174                 /* weight = (p[2] << 8) | p[3]; */
1175                 strncpy(cellHostNames[server_num], host,
1176                         sizeof(cellHostNames[server_num]));
1177                 server_num++;
1178
1179                 if (!minttl || ttl < minttl)
1180                     minttl = ttl;
1181             }
1182         }
1183
1184         p += size;
1185     }
1186
1187     if (server_num == 0) {      /* No AFSDB or SRV records */
1188         code = AFSCONF_NOTFOUND;
1189         goto findservererror;
1190     }
1191
1192     if (realCellName) {
1193         /* Convert the real cell name to lowercase */
1194         for (p = (unsigned char *)realCellName; *p; p++)
1195             *p = tolower(*p);
1196     }
1197
1198     *numServers = server_num;
1199     *ttl = minttl ? (time(0) + minttl) : 0;
1200
1201     if ( *numServers > 0 ) {
1202         code =  0;
1203         *arealCellName = realCellName;
1204     } else
1205         code = AFSCONF_NOTFOUND;
1206
1207 findservererror:
1208     if (code && realCellName)
1209         free(realCellName);
1210     free(dotcellname);
1211     return code;
1212 }
1213
1214 int
1215 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1216                      struct afsconf_cell *acellInfo)
1217 {
1218     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
1219     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1220     unsigned short ipRanks[AFSMAXCELLHOSTS];
1221     unsigned short ports[AFSMAXCELLHOSTS];
1222     char *realCellName = NULL;
1223     int ttl, numServers, i;
1224     char *service = aservice;
1225     int code;
1226     unsigned short afsdbport;
1227     if (!service) {
1228         service = "afs3-vlserver";
1229         afsdbport = htons(7003);
1230     } else {
1231         service = aservice;
1232         afsdbport = afsconf_FindService(service);
1233     }
1234     code = afsconf_LookupServer((const char *)service, "udp",
1235                                 (const char *)acellName, afsdbport,
1236                                 cellHostAddrs, cellHostNames,
1237                                 ports, ipRanks, &numServers, &ttl,
1238                                 &realCellName);
1239
1240     if (code == 0) {
1241         acellInfo->timeout = ttl;
1242         acellInfo->numServers = numServers;
1243         for (i = 0; i < numServers; i++) {
1244             memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1245                    sizeof(afs_int32));
1246             memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1247             acellInfo->hostAddr[i].sin_family = AF_INET;
1248             acellInfo->hostAddr[i].sin_port = ports[i];
1249
1250             if (realCellName) {
1251                 strlcpy(acellInfo->name, realCellName,
1252                         sizeof(acellInfo->name));
1253                 free(realCellName);
1254             }
1255         }
1256         acellInfo->linkedCell = NULL;       /* no linked cell */
1257         acellInfo->flags = 0;
1258     }
1259     return code;
1260 }
1261 #else /* windows */
1262 int
1263 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1264                      struct afsconf_cell *acellInfo)
1265 {
1266     afs_int32 i;
1267     int tservice = afsconf_FindService(aservice);   /* network byte order */
1268     const char *ianaName = afsconf_FindIANAName(aservice);
1269     struct afsconf_entry DNSce;
1270     afs_int32 cellHostAddrs[AFSMAXCELLHOSTS];
1271     char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1272     unsigned short ipRanks[AFSMAXCELLHOSTS];
1273     unsigned short ports[AFSMAXCELLHOSTS];          /* network byte order */
1274     int numServers;
1275     int rc;
1276     int ttl;
1277
1278     if (tservice < 0) {
1279         if (aservice)
1280             return AFSCONF_NOTFOUND;
1281         else
1282             tservice = 0;       /* port will be assigned by caller */
1283     }
1284
1285     if (ianaName == NULL)
1286         ianaName = "afs3-vlserver";
1287
1288     DNSce.cellInfo.numServers = 0;
1289     DNSce.next = NULL;
1290
1291     rc = getAFSServer(ianaName, "udp", acellName, tservice,
1292                       cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1293                       &ttl);
1294     /* ignore the ttl here since this code is only called by transitory programs
1295      * like klog, etc. */
1296
1297     /* If we couldn't find an entry for the requested service
1298      * and that service happens to be the prservice or kaservice
1299      * then fallback to searching for afs3-vlserver and assigning
1300      * the port number here. */
1301     if (rc < 0 && tservice == htons(7002) || tservice == htons(7004)) {
1302         rc = getAFSServer("afs3-vlserver", "udp", acellName, tservice,
1303                            cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1304                            &ttl);
1305         if (rc >= 0) {
1306             for (i = 0; i < numServers; i++)
1307                 ports[i] = tservice;
1308         }
1309     }
1310
1311     if (rc < 0 || numServers == 0)
1312         return -1;
1313
1314     for (i = 0; i < numServers; i++) {
1315         memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1316                sizeof(long));
1317         memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1318         acellInfo->hostAddr[i].sin_family = AF_INET;
1319         if (aservice)
1320             acellInfo->hostAddr[i].sin_port = ports[i];
1321         else
1322             acellInfo->hostAddr[i].sin_port = 0;
1323     }
1324
1325     acellInfo->numServers = numServers;
1326     strlcpy(acellInfo->name, acellName, sizeof acellInfo->name);
1327     acellInfo->linkedCell = NULL;       /* no linked cell */
1328     acellInfo->flags = 0;
1329     return 0;
1330 }
1331 #endif /* windows */
1332
1333 int
1334 afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
1335                     struct afsconf_cell *acellInfo)
1336 {
1337     register struct afsconf_entry *tce;
1338     struct afsconf_aliasentry *tcae;
1339     struct afsconf_entry *bestce;
1340     register afs_int32 i;
1341     int tservice;
1342     char *tcell;
1343     int cnLen;
1344     int ambig;
1345     char tbuffer[64];
1346
1347     LOCK_GLOBAL_MUTEX;
1348     if (adir)
1349         afsconf_Check(adir);
1350     if (acellName) {
1351         tcell = acellName;
1352         cnLen = (int)(strlen(tcell) + 1);
1353         lcstring(tcell, tcell, cnLen);
1354         afsconf_SawCell = 1;    /* will ignore the AFSCELL switch on future */
1355         /* call to afsconf_GetLocalCell: like klog  */
1356     } else {
1357         i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
1358         if (i) {
1359             UNLOCK_GLOBAL_MUTEX;
1360             return i;
1361         }
1362         tcell = tbuffer;
1363     }
1364     cnLen = strlen(tcell);
1365     bestce = (struct afsconf_entry *)0;
1366     ambig = 0;
1367     if (!adir) {
1368         UNLOCK_GLOBAL_MUTEX;
1369         return 0;
1370     }
1371
1372     /* Look through the list of aliases */
1373     for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
1374         if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
1375             tcell = tcae->aliasInfo.realName;
1376             break;
1377         }
1378     }
1379
1380     for (tce = adir->entries; tce; tce = tce->next) {
1381         if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
1382             /* found our cell */
1383             bestce = tce;
1384             ambig = 0;
1385             break;
1386         }
1387         if (strlen(tce->cellInfo.name) < cnLen)
1388             continue;           /* clearly wrong */
1389         if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
1390             if (bestce)
1391                 ambig = 1;      /* ambiguous unless we get exact match */
1392             bestce = tce;
1393         }
1394     }
1395     if (!ambig && bestce && bestce->cellInfo.numServers) {
1396         *acellInfo = bestce->cellInfo;  /* structure assignment */
1397         if (aservice) {
1398             tservice = afsconf_FindService(aservice);
1399             if (tservice < 0) {
1400                 UNLOCK_GLOBAL_MUTEX;
1401                 return AFSCONF_NOTFOUND;        /* service not found */
1402             }
1403             for (i = 0; i < acellInfo->numServers; i++) {
1404                 acellInfo->hostAddr[i].sin_port = tservice;
1405             }
1406         }
1407         acellInfo->timeout = 0;
1408
1409         /* 
1410          * Until we figure out how to separate out ubik server
1411          * queries from other server queries, only perform gethostbyname()
1412          * lookup on the specified hostnames for the client CellServDB files.
1413          */
1414         if (IsClientConfigDirectory(adir->name) && 
1415             !(acellInfo->flags & AFSCONF_CELL_FLAG_DNS_QUERIED)) {
1416             int j;
1417             short numServers=0;                                 /*Num active servers for the cell */
1418             struct sockaddr_in hostAddr[MAXHOSTSPERCELL];       /*IP addresses for cell's servers */
1419             char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS];       /*Names for cell's servers */
1420
1421             memset(&hostAddr, 0, sizeof(hostAddr));
1422             memset(&hostName, 0, sizeof(hostName));
1423
1424             for ( j=0; j<acellInfo->numServers && numServers < MAXHOSTSPERCELL; j++ ) {
1425                 struct hostent *he = gethostbyname(acellInfo->hostName[j]);
1426                 int foundAddr = 0;
1427
1428                 if (he && he->h_addrtype == AF_INET) {
1429                     int i;
1430                     /* obtain all the valid address from the list */
1431                     for (i=0 ; he->h_addr_list[i] && numServers < MAXHOSTSPERCELL; i++) {
1432                         /* check to see if this is a new address; if so insert it into the list */
1433                         int k, dup;
1434                         for (k=0, dup=0; !dup && k < numServers; k++) {
1435                             if (hostAddr[k].sin_addr.s_addr == *(u_long *)he->h_addr_list[i])
1436                                 dup = 1;
1437                         }
1438                         if (dup)
1439                             continue;
1440
1441                         hostAddr[numServers].sin_family = AF_INET;
1442                         hostAddr[numServers].sin_port = acellInfo->hostAddr[0].sin_port;
1443 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
1444                         hostAddr[numServers].sin_len = sizeof(struct sockaddr_in);
1445 #endif
1446                         memcpy(&hostAddr[numServers].sin_addr.s_addr, he->h_addr_list[i], sizeof(long));
1447                         strcpy(hostName[numServers], acellInfo->hostName[j]);
1448                         foundAddr = 1;
1449                         numServers++;
1450                     }
1451                 }
1452                 if (!foundAddr) {
1453                     hostAddr[numServers] = acellInfo->hostAddr[j];
1454                     strcpy(hostName[numServers], acellInfo->hostName[j]);
1455                     numServers++;
1456                 }
1457             }
1458
1459             for (i=0; i<numServers; i++) {
1460                 acellInfo->hostAddr[i] = hostAddr[i];
1461                 strcpy(acellInfo->hostName[i], hostName[i]);
1462             }
1463             acellInfo->numServers = numServers;
1464             acellInfo->flags |= AFSCONF_CELL_FLAG_DNS_QUERIED;
1465         }
1466         UNLOCK_GLOBAL_MUTEX;
1467         return 0;
1468     } else {
1469         UNLOCK_GLOBAL_MUTEX;
1470         return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
1471     }
1472 }
1473
1474 int
1475 afsconf_GetLocalCell(register struct afsconf_dir *adir, char *aname,
1476                      afs_int32 alen)
1477 {
1478     static int afsconf_showcell = 0;
1479     char *afscell_path;
1480     afs_int32 code = 0;
1481
1482     LOCK_GLOBAL_MUTEX;
1483     /*
1484      * If a cell switch was specified in a command, then it should override the 
1485      * AFSCELL variable.  If a cell was specified, then the afsconf_SawCell flag
1486      * is set and the cell name in the adir structure is used.
1487      * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
1488      */
1489     if (!afsconf_SawCell && (afscell_path = getenv("AFSCELL"))) {
1490         if (!afsconf_showcell) {
1491             fprintf(stderr, "Note: Operation is performed on cell %s\n",
1492                     afscell_path);
1493             afsconf_showcell = 1;
1494         }
1495         strncpy(aname, afscell_path, alen);
1496     } else {
1497         afsconf_Check(adir);
1498         if (adir->cellName) {
1499             strncpy(aname, adir->cellName, alen);
1500         } else
1501             code = AFSCONF_UNKNOWN;
1502     }
1503
1504     UNLOCK_GLOBAL_MUTEX;
1505     return (code);
1506 }
1507
1508 int
1509 afsconf_Close(struct afsconf_dir *adir)
1510 {
1511     LOCK_GLOBAL_MUTEX;
1512     afsconf_CloseInternal(adir);
1513     if (adir->name)
1514         free(adir->name);
1515     free(adir);
1516     UNLOCK_GLOBAL_MUTEX;
1517     return 0;
1518 }
1519
1520 static int
1521 afsconf_CloseInternal(register struct afsconf_dir *adir)
1522 {
1523     register struct afsconf_entry *td, *nd;
1524     struct afsconf_aliasentry *ta, *na;
1525     register char *tname;
1526
1527     tname = adir->name;         /* remember name, since that's all we preserve */
1528
1529     /* free everything we can find */
1530     if (adir->cellName)
1531         free(adir->cellName);
1532     for (td = adir->entries; td; td = nd) {
1533         nd = td->next;
1534         if (td->cellInfo.linkedCell)
1535             free(td->cellInfo.linkedCell);
1536         free(td);
1537     }
1538     for (ta = adir->alias_entries; ta; ta = na) {
1539         na = ta->next;
1540         free(ta);
1541     }
1542     if (adir->keystr)
1543         free(adir->keystr);
1544
1545     /* reinit */
1546     memset(adir, 0, sizeof(struct afsconf_dir));
1547     adir->name = tname;         /* restore it */
1548     return 0;
1549 }
1550
1551 static int
1552 afsconf_Reopen(register struct afsconf_dir *adir)
1553 {
1554     register afs_int32 code;
1555     code = afsconf_CloseInternal(adir);
1556     if (code)
1557         return code;
1558     code = afsconf_OpenInternal(adir, 0, 0);
1559     return code;
1560 }
1561
1562 /* called during opening of config file */
1563 int
1564 afsconf_IntGetKeys(struct afsconf_dir *adir)
1565 {
1566     char tbuffer[256];
1567     register int fd;
1568     struct afsconf_keys *tstr;
1569     register afs_int32 code;
1570
1571 #ifdef AFS_NT40_ENV
1572     /* NT client config dir has no KeyFile; don't risk attempting open
1573      * because there might be a random file of this name if dir is shared.
1574      */
1575     if (IsClientConfigDirectory(adir->name)) {
1576         adir->keystr = ((struct afsconf_keys *)
1577                         malloc(sizeof(struct afsconf_keys)));
1578         adir->keystr->nkeys = 0;
1579         return 0;
1580     }
1581 #endif /* AFS_NT40_ENV */
1582
1583     LOCK_GLOBAL_MUTEX;
1584     /* compute the key name and other setup */
1585     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1586     tstr = (struct afsconf_keys *)malloc(sizeof(struct afsconf_keys));
1587     adir->keystr = tstr;
1588
1589     /* read key file */
1590     fd = open(tbuffer, O_RDONLY);
1591     if (fd < 0) {
1592         tstr->nkeys = 0;
1593         UNLOCK_GLOBAL_MUTEX;
1594         return 0;
1595     }
1596     code = read(fd, tstr, sizeof(struct afsconf_keys));
1597     close(fd);
1598     if (code < sizeof(afs_int32)) {
1599         tstr->nkeys = 0;
1600         UNLOCK_GLOBAL_MUTEX;
1601         return 0;
1602     }
1603
1604     /* convert key structure to host order */
1605     tstr->nkeys = ntohl(tstr->nkeys);
1606
1607     if (code < sizeof(afs_int32) + (tstr->nkeys*sizeof(struct afsconf_key))) {
1608         tstr->nkeys = 0;
1609         UNLOCK_GLOBAL_MUTEX;
1610         return 0;
1611     }
1612
1613     for (fd = 0; fd < tstr->nkeys; fd++)
1614         tstr->key[fd].kvno = ntohl(tstr->key[fd].kvno);
1615
1616     UNLOCK_GLOBAL_MUTEX;
1617     return 0;
1618 }
1619
1620 /* get keys structure */
1621 int
1622 afsconf_GetKeys(struct afsconf_dir *adir, struct afsconf_keys *astr)
1623 {
1624     register afs_int32 code;
1625
1626     LOCK_GLOBAL_MUTEX;
1627     code = afsconf_Check(adir);
1628     if (code) {
1629         UNLOCK_GLOBAL_MUTEX;
1630         return AFSCONF_FAILURE;
1631     }
1632     memcpy(astr, adir->keystr, sizeof(struct afsconf_keys));
1633     UNLOCK_GLOBAL_MUTEX;
1634     return 0;
1635 }
1636
1637 /* get latest key */
1638 afs_int32
1639 afsconf_GetLatestKey(struct afsconf_dir * adir, afs_int32 * avno, 
1640                      struct ktc_encryptionKey *akey)
1641 {
1642     register int i;
1643     int maxa;
1644     register struct afsconf_key *tk;
1645     register afs_int32 best;
1646     struct afsconf_key *bestk;
1647     register afs_int32 code;
1648
1649     LOCK_GLOBAL_MUTEX;
1650     code = afsconf_Check(adir);
1651     if (code) {
1652         UNLOCK_GLOBAL_MUTEX;
1653         return AFSCONF_FAILURE;
1654     }
1655     maxa = adir->keystr->nkeys;
1656
1657     best = -1;                  /* highest kvno we've seen yet */
1658     bestk = (struct afsconf_key *)0;    /* ptr to structure providing best */
1659     for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
1660         if (tk->kvno == 999)
1661             continue;           /* skip bcrypt keys */
1662         if (tk->kvno > best) {
1663             best = tk->kvno;
1664             bestk = tk;
1665         }
1666     }
1667     if (bestk) {                /* found any  */
1668         if (akey)
1669             memcpy(akey, bestk->key, 8);        /* copy out latest key */
1670         if (avno)
1671             *avno = bestk->kvno;        /* and kvno to caller */
1672         UNLOCK_GLOBAL_MUTEX;
1673         return 0;
1674     }
1675     UNLOCK_GLOBAL_MUTEX;
1676     return AFSCONF_NOTFOUND;    /* didn't find any keys */
1677 }
1678
1679 /* get a particular key */
1680 int
1681 afsconf_GetKey(void *rock, int avno, struct ktc_encryptionKey *akey)
1682 {
1683     struct afsconf_dir *adir = (struct afsconf_dir *) rock;
1684     register int i, maxa;
1685     register struct afsconf_key *tk;
1686     register afs_int32 code;
1687
1688     LOCK_GLOBAL_MUTEX;
1689     code = afsconf_Check(adir);
1690     if (code) {
1691         UNLOCK_GLOBAL_MUTEX;
1692         return AFSCONF_FAILURE;
1693     }
1694     maxa = adir->keystr->nkeys;
1695
1696     for (tk = adir->keystr->key, i = 0; i < maxa; i++, tk++) {
1697         if (tk->kvno == avno) {
1698             memcpy(akey, tk->key, 8);
1699             UNLOCK_GLOBAL_MUTEX;
1700             return 0;
1701         }
1702     }
1703
1704     UNLOCK_GLOBAL_MUTEX;
1705     return AFSCONF_NOTFOUND;
1706 }
1707
1708 /* save the key structure in the appropriate file */
1709 static int
1710 SaveKeys(struct afsconf_dir *adir)
1711 {
1712     struct afsconf_keys tkeys;
1713     register int fd;
1714     register afs_int32 i;
1715     char tbuffer[256];
1716
1717     memcpy(&tkeys, adir->keystr, sizeof(struct afsconf_keys));
1718
1719     /* convert it to net byte order */
1720     for (i = 0; i < tkeys.nkeys; i++)
1721         tkeys.key[i].kvno = htonl(tkeys.key[i].kvno);
1722     tkeys.nkeys = htonl(tkeys.nkeys);
1723
1724     /* rewrite keys file */
1725     strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1726     fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0600);
1727     if (fd < 0)
1728         return AFSCONF_FAILURE;
1729     i = write(fd, &tkeys, sizeof(tkeys));
1730     if (i != sizeof(tkeys)) {
1731         close(fd);
1732         return AFSCONF_FAILURE;
1733     }
1734     if (close(fd) < 0)
1735         return AFSCONF_FAILURE;
1736     return 0;
1737 }
1738
1739 int
1740 afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno, char akey[8],
1741                afs_int32 overwrite)
1742 {
1743     register struct afsconf_keys *tk;
1744     register struct afsconf_key *tkey;
1745     register afs_int32 i;
1746     int foundSlot;
1747
1748     LOCK_GLOBAL_MUTEX;
1749     tk = adir->keystr;
1750
1751     if (akvno != 999) {
1752         if (akvno < 0 || akvno > 255) {
1753             UNLOCK_GLOBAL_MUTEX;
1754             return ERANGE;
1755         }
1756     }
1757     foundSlot = 0;
1758     for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
1759         if (tkey->kvno == akvno) {
1760             if (!overwrite) {
1761                 UNLOCK_GLOBAL_MUTEX;
1762                 return AFSCONF_KEYINUSE;
1763             }
1764             foundSlot = 1;
1765             break;
1766         }
1767     }
1768     if (!foundSlot) {
1769         if (tk->nkeys >= AFSCONF_MAXKEYS) {
1770             UNLOCK_GLOBAL_MUTEX;
1771             return AFSCONF_FULL;
1772         }
1773         tkey = &tk->key[tk->nkeys++];
1774     }
1775     tkey->kvno = akvno;
1776     memcpy(tkey->key, akey, 8);
1777     i = SaveKeys(adir);
1778     afsconf_Touch(adir);
1779     UNLOCK_GLOBAL_MUTEX;
1780     return i;
1781 }
1782
1783 /* this proc works by sliding the other guys down, rather than using a funny
1784     kvno value, so that callers can count on getting a good key in key[0].
1785 */
1786 int
1787 afsconf_DeleteKey(struct afsconf_dir *adir, afs_int32 akvno)
1788 {
1789     register struct afsconf_keys *tk;
1790     register struct afsconf_key *tkey;
1791     register int i;
1792     int foundFlag = 0;
1793
1794     LOCK_GLOBAL_MUTEX;
1795     tk = adir->keystr;
1796
1797     for (i = 0, tkey = tk->key; i < tk->nkeys; i++, tkey++) {
1798         if (tkey->kvno == akvno) {
1799             foundFlag = 1;
1800             break;
1801         }
1802     }
1803     if (!foundFlag) {
1804         UNLOCK_GLOBAL_MUTEX;
1805         return AFSCONF_NOTFOUND;
1806     }
1807
1808     /* otherwise slide the others down.  i and tkey point at the guy to delete */
1809     for (; i < tk->nkeys - 1; i++, tkey++) {
1810         tkey->kvno = (tkey + 1)->kvno;
1811         memcpy(tkey->key, (tkey + 1)->key, 8);
1812     }
1813     tk->nkeys--;
1814     i = SaveKeys(adir);
1815     afsconf_Touch(adir);
1816     UNLOCK_GLOBAL_MUTEX;
1817     return i;
1818 }