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