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