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