Import Upstream version 1.8.5
[hcoop/debian/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 #include <afs/stds.h>
13
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #ifdef AFS_NT40_ENV
18 #include <sys/utime.h>
19 #include <WINNT/afssw.h>
20 #endif
21
22 #include <ctype.h>
23
24 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
25 #include <arpa/nameser_compat.h>
26 #endif
27
28 #include <afs/pthread_glock.h>
29 #include <afs/afsint.h>
30 #include <rx/rxkad.h>
31 #include <rx/rx.h>
32
33 #include <afs/afsutil.h>
34 #include "keys.h"
35 #include "cellconfig.h"
36 #include "internal.h"
37
38 #ifdef AFS_NT40_ENV
39 #include <cm.h>
40 #include <cm_config.h>
41 /* cm_dns.h depends on cellconfig.h */
42 #include <cm_nls.h>
43 #include <cm_dns.h>
44 #endif
45 #include <rx/rx.h>
46 #include <rx/rxkad.h>
47
48 struct afsconf_servPair {
49 const char *name;
50 const char *ianaName;
51 int port;
52 };
53
54 static struct afsconf_servPair serviceTable[] = {
55 {"afs", "afs3-fileserver", 7000,},
56 {"afscb", "afs3-callback", 7001,},
57 {"afsprot", "afs3-prserver", 7002,},
58 {"afsvldb", "afs3-vlserver", 7003,},
59 {"afskauth", "afs3-kaserver", 7004,},
60 {"afsvol", "afs3-volserver", 7005,},
61 {"afserror", "afs3-errors", 7006,},
62 {"afsnanny", "afs3-bos", 7007,},
63 {"afsupdate", "afs3-update", 7008,},
64 {"afsrmtsys", "afs3-rmtsys", 7009,},
65 {"afsres", NULL, 7010,},/* residency database for MR-AFS */
66 {"afsremio", NULL, 7011,}, /* remote I/O interface for MR-AFS */
67 {0, 0, 0} /* insert new services before this spot */
68 };
69
70 /* Prototypes */
71 static int TrimLine(char *abuffer, int abufsize);
72 #ifdef AFS_NT40_ENV
73 static int GetCellNT(struct afsconf_dir *adir);
74 #endif
75 static int GetCellUnix(struct afsconf_dir *adir);
76 static int afsconf_OpenInternal(struct afsconf_dir *adir, char *cell,
77 char clones[]);
78 static int ParseHostLine(char *aline, struct sockaddr_in *addr,
79 char *aname, char *aclone);
80 static int ParseCellLine(char *aline, char *aname,
81 char *alname);
82 static int afsconf_CloseInternal(struct afsconf_dir *adir);
83 static int afsconf_Reopen(struct afsconf_dir *adir);
84
85 #ifndef T_AFSDB
86 #define T_AFSDB 18 /* per RFC1183 section 1 */
87 #endif
88 #ifndef T_SRV
89 #define T_SRV 33 /* RFC2782 */
90 #endif
91
92 /*
93 * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
94 * our code can tell if there is new info in the key files, the cell server db
95 * files or any of the other files (and reopen the thing) if the date on
96 * CellServDB changes.
97 */
98
99 #if defined(AFS_SUN5_ENV) && !defined(__sparcv9)
100 /* Solaris through 10 in 32 bit mode will return EMFILE if fopen can't
101 get an fd <= 255. We allow the fileserver to claim more fds than that.
102 This has always been a problem since pr_Initialize would have the same
103 issue, but hpr_Initialize makes it more likely that we would see this.
104 Work around it. This is not generic. It's coded with the needs of
105 afsconf_* in mind only.
106
107 http://www.opensolaris.org/os/community/onnv/flag-days/pages/2006042001/
108 */
109
110 #define BUFFER 4096
111
112 struct afsconf_iobuffer {
113 int _file;
114 char *buffer;
115 char *ptr;
116 char *endptr;
117 };
118
119 typedef struct afsconf_iobuffer afsconf_FILE;
120
121 static afsconf_FILE *
122 afsconf_fopen(const char *fname, const char *fmode)
123 {
124 int fd;
125 afsconf_FILE *iop;
126
127 if ((fd = open(fname, O_RDONLY)) == -1) {
128 return NULL;
129 }
130
131 iop = malloc(sizeof(struct afsconf_iobuffer));
132 if (iop == NULL) {
133 (void) close(fd);
134 errno = ENOMEM;
135 return NULL;
136 }
137 iop->_file = fd;
138 iop->buffer = malloc(BUFFER);
139 if (iop->buffer == NULL) {
140 (void) close(fd);
141 free(iop);
142 errno = ENOMEM;
143 return NULL;
144 }
145 iop->ptr = iop->buffer;
146 iop->endptr = iop->buffer;
147 return iop;
148 }
149
150 static int
151 afsconf_fclose(afsconf_FILE *iop)
152 {
153 if (iop == NULL) {
154 return 0;
155 }
156 close(iop->_file);
157 free(iop->buffer);
158 free(iop);
159 return 0;
160 }
161
162 static char *
163 afsconf_fgets(char *s, int n, afsconf_FILE *iop)
164 {
165 char *p;
166
167 p = s;
168 for (;;) {
169 char c;
170
171 if (iop->ptr == iop->endptr) {
172 ssize_t len;
173
174 if ((len = read(iop->_file, (void *)iop->buffer, BUFFER)) == -1) {
175 return NULL;
176 }
177 if (len == 0) {
178 *p = 0;
179 if (s == p) {
180 return NULL;
181 }
182 return s;
183 }
184 iop->ptr = iop->buffer;
185 iop->endptr = iop->buffer + len;
186 }
187 c = *iop->ptr++;
188 *p++ = c;
189 if ((p - s) == (n - 1)) {
190 *p = 0;
191 return s;
192 }
193 if (c == '\n') {
194 *p = 0;
195 return s;
196 }
197 }
198 }
199 #define fopen afsconf_fopen
200 #define fclose afsconf_fclose
201 #define fgets afsconf_fgets
202 #else
203 #define afsconf_FILE FILE
204 #endif /* AFS_SUN5_ENV && ! __sparcv9 */
205
206 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
207 afs_int32
208 afsconf_FindService(const char *aname)
209 {
210 /* lookup a service name */
211 struct servent *ts;
212 struct afsconf_servPair *tsp;
213
214 if (aname == NULL || aname[0] == '\0')
215 return -1;
216
217 #if defined(AFS_OSF_ENV)
218 ts = getservbyname(aname, "");
219 #else
220 ts = (struct servent *) getservbyname(aname, NULL);
221 #endif
222 if (ts) {
223 /* we found it in /etc/services, so we use this value */
224 return ts->s_port; /* already in network byte order */
225 }
226
227 /* not found in /etc/services, see if it is one of ours */
228 for (tsp = serviceTable; tsp->port; tsp++) {
229 if ((tsp->name && (!strcmp(tsp->name, aname)))
230 || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
231 return htons(tsp->port);
232 }
233 return -1;
234 }
235
236 const char *
237 afsconf_FindIANAName(const char *aname)
238 {
239 /* lookup a service name */
240 struct afsconf_servPair *tsp;
241
242 if (aname == NULL || aname[0] == '\0')
243 return NULL;
244
245 /* see if it is one of ours */
246 for (tsp = serviceTable; tsp->port; tsp++) {
247 if ((tsp->name && (!strcmp(tsp->name, aname)))
248 || (tsp->ianaName && (!strcmp(tsp->ianaName, aname))))
249 return tsp->ianaName;
250 }
251 return NULL;
252 }
253
254 static int
255 TrimLine(char *abuffer, int abufsize)
256 {
257 char tbuffer[256];
258 char *tp;
259 int tc;
260
261 tp = abuffer;
262 while ((tc = *tp)) {
263 if (!isspace(tc))
264 break;
265 tp++;
266 }
267 strlcpy(tbuffer, tp, sizeof tbuffer);
268 strlcpy(abuffer, tbuffer, abufsize);
269 return 0;
270 }
271
272 /*
273 * IsClientConfigDirectory() -- determine if path matches well-known
274 * client configuration directory.
275 */
276 #ifdef AFS_NT40_ENV
277 #define IS_SEP(x) ((x) == '\\' || (x) == '/')
278 #else /* AFS_NT40_ENV */
279 #define IS_SEP(x) ((x) == '/')
280 #endif /* AFS_NT40_ENV */
281 int
282 _afsconf_IsClientConfigDirectory(const char *path)
283 {
284 const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
285 int i, cc, pc;
286
287 for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
288 #ifdef AFS_NT40_ENV
289 cc = tolower(cdir[i]);
290 pc = tolower(path[i]);
291
292 if (cc == '\\') {
293 cc = '/';
294 }
295 if (pc == '\\') {
296 pc = '/';
297 }
298 #else /* AFS_NT40_ENV */
299 cc = cdir[i];
300 pc = path[i];
301 #endif /* AFS_NT40_ENV */
302 if (cc != pc) {
303 return 0;
304 }
305 }
306
307 /* hit end of one or both; allow mismatch in existence of trailing slash */
308 if (cdir[i] != '\0') {
309 if (!IS_SEP(cdir[i]) || (cdir[i + 1] != '\0')) {
310 return 0;
311 }
312 }
313 if (path[i] != '\0') {
314 if (!IS_SEP(path[i]) || (path[i + 1] != '\0')) {
315 return 0;
316 }
317 }
318 return 1;
319 }
320
321 #ifdef AFS_NT40_ENV
322 static void
323 _afsconf_CellServDBPath(struct afsconf_dir *adir, char **path)
324 {
325 char *p;
326
327 /* NT client CellServDB has different file name than NT server or Unix */
328 if (_afsconf_IsClientConfigDirectory(adir->name)) {
329 if (!afssw_GetClientCellServDBDir(&p)) {
330 if (asprintf(path, "%s/%s", p, AFSDIR_CELLSERVDB_FILE_NTCLIENT) < 0)
331 *path = NULL;
332 free(p);
333 } else {
334 if (asprintf(path, "%s/%s", adir->name,
335 AFSDIR_CELLSERVDB_FILE_NTCLIENT) < 0)
336 *path = NULL;
337 }
338 } else {
339 if (asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE) < 0)
340 *path = NULL;
341 }
342 return;
343 }
344 #else
345 static void
346 _afsconf_CellServDBPath(struct afsconf_dir *adir, char **path)
347 {
348 if (asprintf(path, "%s/%s", adir->name, AFSDIR_CELLSERVDB_FILE) < 0)
349 *path = NULL;
350 }
351 #endif /* AFS_NT40_ENV */
352
353 int
354 _afsconf_UpToDate(struct afsconf_dir *adir)
355 {
356 char *cellservDB;
357 struct stat tstat;
358 int code;
359 time_t now = time(0);
360
361 if (adir->timeRead && (adir->timeCheck == now)) {
362 return 1; /* stat no more than once a second */
363 }
364 adir->timeCheck = now;
365
366 _afsconf_CellServDBPath(adir, &cellservDB);
367 if (cellservDB == NULL)
368 return 0;
369
370 code = stat(cellservDB, &tstat);
371 free(cellservDB);
372 if (code < 0)
373 return 0; /* Can't throw the error, so just say we're not up to date */
374
375 /* did file change? */
376 if (tstat.st_mtime == adir->timeRead)
377 return 1;
378
379 /* otherwise file has changed */
380 return 0;
381 }
382
383 int
384 afsconf_UpToDate(void *rock)
385 {
386 int code;
387
388 LOCK_GLOBAL_MUTEX;
389 code = _afsconf_UpToDate(rock);
390 UNLOCK_GLOBAL_MUTEX;
391
392 return code;
393 }
394
395 int
396 _afsconf_Check(struct afsconf_dir *adir)
397 {
398 /* did configuration change? */
399 if (_afsconf_UpToDate(adir))
400 return 0;
401
402 /* otherwise file has changed, so reopen it */
403 return afsconf_Reopen(adir);
404 }
405
406 /* set modtime on file */
407 int
408 _afsconf_Touch(struct afsconf_dir *adir)
409 {
410 char *cellservDB;
411 int code;
412 #ifndef AFS_NT40_ENV
413 struct timeval tvp[2];
414 #endif
415
416 adir->timeRead = 0; /* just in case */
417 adir->timeCheck = 0;
418
419 _afsconf_CellServDBPath(adir, &cellservDB);
420 if (cellservDB == NULL)
421 return ENOMEM;
422
423 #ifdef AFS_NT40_ENV
424 code = _utime(cellservDB, NULL);
425 #else
426 gettimeofday(&tvp[0], NULL);
427 tvp[1] = tvp[0];
428 code = utimes(cellservDB, tvp);
429 #endif /* AFS_NT40_ENV */
430 free(cellservDB);
431
432 return code;
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 = calloc(1, sizeof(struct afsconf_dir));
444 tdir->name = strdup(adir);
445
446 code = afsconf_OpenInternal(tdir, 0, 0);
447 if (code) {
448 char *afsconf_path, afs_confdir[128];
449
450 free(tdir->name);
451 /* Check global place only when local Open failed for whatever reason */
452 if (!(afsconf_path = getenv("AFSCONF"))) {
453 /* 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... */
454 char *home_dir;
455 afsconf_FILE *fp;
456 size_t len = 0;
457 int r;
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 goto fail;
464
465 } else {
466 char *pathname = NULL;
467
468 r = asprintf(&pathname, "%s/%s", home_dir, ".AFSCONF");
469 if (r < 0 || pathname == NULL)
470 goto fail;
471
472 fp = fopen(pathname, "r");
473 free(pathname);
474
475 if (fp == 0) {
476 /* Our last chance is the "/.AFSCONF" file */
477 fp = fopen("/.AFSCONF", "r");
478 if (fp == 0)
479 goto fail;
480 }
481 }
482 if (fgets(afs_confdir, 128, fp) != NULL)
483 len = strlen(afs_confdir);
484 fclose(fp);
485 if (len == 0)
486 goto fail;
487
488 if (afs_confdir[len - 1] == '\n') {
489 afs_confdir[len - 1] = 0;
490 }
491 afsconf_path = afs_confdir;
492 }
493 tdir->name = strdup(afsconf_path);
494 code = afsconf_OpenInternal(tdir, 0, 0);
495 if (code) {
496 free(tdir->name);
497 goto fail;
498 }
499 }
500 UNLOCK_GLOBAL_MUTEX;
501 return tdir;
502
503 fail:
504 free(tdir);
505 UNLOCK_GLOBAL_MUTEX;
506 return NULL;
507 }
508
509 static int
510 GetCellUnix(struct afsconf_dir *adir)
511 {
512 char *rc;
513 char tbuffer[256];
514 char *start, *p;
515 afsconf_FILE *fp;
516
517 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE,
518 (char *)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 (_afsconf_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];
632 struct stat tstat;
633 char *cellservDB;
634
635 #ifdef AFS_NT40_ENV
636 cm_enumCellRegistry_t enumCellRegistry = {0, 0};
637 #endif /* AFS_NT40_ENV */
638
639 /* init the keys queue before any call to afsconf_CloseInternal() */
640 _afsconf_InitKeys(adir);
641
642 /* figure out the local cell name */
643 #ifdef AFS_NT40_ENV
644 i = GetCellNT(adir);
645 enumCellRegistry.adir = adir;
646 #else
647 i = GetCellUnix(adir);
648 #endif
649
650 #ifndef AFS_FREELANCE_CLIENT /* no local cell not fatal in freelance */
651 if (i) {
652 return i;
653 }
654 #endif
655
656 /* now parse the individual lines */
657 curEntry = 0;
658
659 _afsconf_CellServDBPath(adir, &cellservDB);
660
661 #ifdef AFS_NT40_ENV
662 if (_afsconf_IsClientConfigDirectory(adir->name))
663 enumCellRegistry.client = 1;
664 #endif /* AFS_NT40_ENV */
665
666 if (!stat(cellservDB, &tstat)) {
667 adir->timeRead = tstat.st_mtime;
668 } else {
669 adir->timeRead = 0;
670 }
671
672 tf = fopen(cellservDB, "r");
673 if (!tf) {
674 return -1;
675 }
676
677 /* The CellServDB file is now open.
678 * The following code parses the contents of the
679 * file and creates a list with the first cell entry
680 * in the CellServDB file at the end of the list.
681 *
682 * No checking is performed for duplicates.
683 * The side effects of this process are that duplicate
684 * entries appended to the end of the CellServDB file
685 * take precedence and are found in a shorter period
686 * of time.
687 */
688
689 while (1) {
690 tp = fgets(tbuffer, sizeof(tbuffer), tf);
691 if (!tp)
692 break;
693 TrimLine(tbuffer, sizeof tbuffer); /* remove white space */
694 if (tbuffer[0] == 0 || tbuffer[0] == '\n')
695 continue; /* empty line */
696 if (tbuffer[0] == '>') {
697 char linkedcell[MAXCELLCHARS];
698 /* start new cell item */
699 if (curEntry) {
700 /* thread this guy on the list */
701 curEntry->next = adir->entries;
702 adir->entries = curEntry;
703 curEntry = 0;
704 }
705 curEntry = calloc(1, sizeof(struct afsconf_entry));
706 code =
707 ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
708 if (code) {
709 afsconf_CloseInternal(adir);
710 fclose(tf);
711 free(curEntry);
712 return -1;
713 }
714 if (linkedcell[0] != '\0')
715 curEntry->cellInfo.linkedCell = strdup(linkedcell);
716 } else {
717 /* new host in the current cell */
718 if (!curEntry) {
719 afsconf_CloseInternal(adir);
720 fclose(tf);
721 return -1;
722 }
723 i = curEntry->cellInfo.numServers;
724 if (i < MAXHOSTSPERCELL) {
725 if (cell && !strcmp(cell, curEntry->cellInfo.name))
726 code =
727 ParseHostLine(tbuffer,
728 &curEntry->cellInfo.hostAddr[i],
729 curEntry->cellInfo.hostName[i],
730 &clones[i]);
731 else
732 code =
733 ParseHostLine(tbuffer,
734 &curEntry->cellInfo.hostAddr[i],
735 curEntry->cellInfo.hostName[i], 0);
736
737 if (code) {
738 if (code == AFSCONF_SYNTAX) {
739 for (bp = tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
740 if (!*bp)
741 break;
742 }
743 *bp = '\0';
744 fprintf(stderr,
745 "Can't properly parse host line \"%s\" in configuration file %s\n",
746 tbuffer, cellservDB);
747 }
748 free(curEntry);
749 fclose(tf);
750 afsconf_CloseInternal(adir);
751 return -1;
752 }
753 curEntry->cellInfo.numServers = ++i;
754 } else {
755 fprintf(stderr,
756 "Too many hosts for cell %s in configuration file %s\n",
757 curEntry->cellInfo.name, cellservDB);
758 }
759 }
760 }
761 fclose(tf); /* close the file now */
762 free(cellservDB);
763
764 /* end the last partially-completed cell */
765 if (curEntry) {
766 curEntry->next = adir->entries;
767 adir->entries = curEntry;
768 }
769
770 #ifdef AFS_NT40_ENV
771 /*
772 * Windows maintains a CellServDB list in the Registry
773 * that supercedes the contents of the CellServDB file.
774 * Prepending these entries to the head of the list
775 * is sufficient to enforce the precedence.
776 */
777 cm_EnumerateCellRegistry( enumCellRegistry.client,
778 cm_enumCellRegistryProc,
779 &enumCellRegistry);
780 #endif /* AFS_NT40_ENV */
781
782 /* Read in the alias list */
783 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE,
784 (char *)NULL);
785
786 tf = fopen(tbuffer, "r");
787 while (tf) {
788 char *aliasPtr;
789
790 tp = fgets(tbuffer, sizeof(tbuffer), tf);
791 if (!tp)
792 break;
793 TrimLine(tbuffer, sizeof tbuffer); /* remove white space */
794
795 if (tbuffer[0] == '\0' || tbuffer[0] == '\n' || tbuffer[0] == '#')
796 continue; /* empty line */
797
798 tp = tbuffer;
799 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t')
800 tp++;
801 if (tp[0] == '\0')
802 continue; /* invalid line */
803
804 while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t'))
805 0[tp++] = '\0';
806 if (tp[0] == '\0')
807 continue; /* invalid line */
808
809 aliasPtr = tp;
810 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' && tp[0] != '\r'
811 && tp[0] != '\n')
812 tp++;
813 tp[0] = '\0';
814
815 curAlias = calloc(1, sizeof(*curAlias));
816
817 strlcpy(curAlias->aliasInfo.aliasName, aliasPtr, sizeof curAlias->aliasInfo.aliasName);
818 strlcpy(curAlias->aliasInfo.realName, tbuffer, sizeof curAlias->aliasInfo.realName);
819
820 curAlias->next = adir->alias_entries;
821 adir->alias_entries = curAlias;
822 }
823
824 if (tf != NULL)
825 fclose(tf);
826
827 /* now read the fs keys, if possible */
828 code = _afsconf_LoadKeys(adir);
829 if (code) {
830 return code;
831 }
832 code = _afsconf_LoadRealms(adir);
833
834 return code;
835 }
836
837 /* parse a line of the form
838 *"128.2.1.3 #hostname" or
839 *"[128.2.1.3] #hostname" for clones
840 * into the appropriate pieces.
841 */
842 static int
843 ParseHostLine(char *aline, struct sockaddr_in *addr, char *aname,
844 char *aclone)
845 {
846 int i;
847 int c[4];
848 afs_int32 code;
849 char *tp;
850
851 if (*aline == '[') {
852 if (aclone)
853 *aclone = 1;
854 /* FIXME: length of aname unknown here */
855 code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c[0], &c[1], &c[2], &c[3],
856 aname);
857 } else {
858 if (aclone)
859 *aclone = 0;
860 /* FIXME: length of aname unknown here */
861 code = sscanf(aline, "%d.%d.%d.%d #%s", &c[0], &c[1], &c[2], &c[3],
862 aname);
863 }
864 if (code != 5)
865 return AFSCONF_SYNTAX;
866 for(i = 0; i < 4; ++i) {
867 if (c[i] < 0 || c[i] > 255) {
868 fprintf(stderr, "Illegal IP address %d.%d.%d.%d\n", c[0], c[1],
869 c[2], c[3]);
870 return AFSCONF_SYNTAX;
871 }
872 }
873 addr->sin_family = AF_INET;
874 addr->sin_port = 0;
875 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
876 addr->sin_len = sizeof(struct sockaddr_in);
877 #endif
878 tp = (char *)&addr->sin_addr;
879 *tp++ = c[0];
880 *tp++ = c[1];
881 *tp++ = c[2];
882 *tp++ = c[3];
883 return 0;
884 }
885
886 /* parse a line of the form
887 * ">cellname [linkedcellname] [#comments]"
888 * into the appropriate pieces.
889 */
890 static int
891 ParseCellLine(char *aline, char *aname,
892 char *alname)
893 {
894 int code;
895 /* FIXME: length of aname, alname unknown here */
896 code = sscanf(aline, ">%s %s", aname, alname);
897 if (code == 1)
898 *alname = '\0';
899 if (code == 2) {
900 if (*alname == '#') {
901 *alname = '\0';
902 }
903 }
904 return (code > 0 ? 0 : AFSCONF_SYNTAX);
905 }
906
907 /* call aproc(entry, arock, adir) for all cells. Proc must return 0, or we'll stop early and return the code it returns */
908 int
909 afsconf_CellApply(struct afsconf_dir *adir,
910 int (*aproc) (struct afsconf_cell * cell, void *arock,
911 struct afsconf_dir * dir), void *arock)
912 {
913 struct afsconf_entry *tde;
914 afs_int32 code;
915 LOCK_GLOBAL_MUTEX;
916 for (tde = adir->entries; tde; tde = tde->next) {
917 code = (*aproc) (&tde->cellInfo, arock, adir);
918 if (code) {
919 UNLOCK_GLOBAL_MUTEX;
920 return code;
921 }
922 }
923 UNLOCK_GLOBAL_MUTEX;
924 return 0;
925 }
926
927 /* call aproc(entry, arock, adir) for all cell aliases.
928 * Proc must return 0, or we'll stop early and return the code it returns
929 */
930 int
931 afsconf_CellAliasApply(struct afsconf_dir *adir,
932 int (*aproc) (struct afsconf_cellalias * alias,
933 void *arock, struct afsconf_dir * dir),
934 void *arock)
935 {
936 struct afsconf_aliasentry *tde;
937 afs_int32 code;
938 LOCK_GLOBAL_MUTEX;
939 for (tde = adir->alias_entries; tde; tde = tde->next) {
940 code = (*aproc) (&tde->aliasInfo, arock, adir);
941 if (code) {
942 UNLOCK_GLOBAL_MUTEX;
943 return code;
944 }
945 }
946 UNLOCK_GLOBAL_MUTEX;
947 return 0;
948 }
949
950 afs_int32 afsconf_SawCell = 0;
951
952 int
953 afsconf_GetExtendedCellInfo(struct afsconf_dir *adir, char *acellName,
954 char *aservice, struct afsconf_cell *acellInfo,
955 char clones[])
956 {
957 afs_int32 code;
958 char *cell;
959
960 code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
961 if (code)
962 return code;
963
964 if (acellName)
965 cell = acellName;
966 else
967 cell = (char *)&acellInfo->name;
968
969 code = afsconf_OpenInternal(adir, cell, clones);
970 return code;
971 }
972
973 #if !defined(AFS_NT40_ENV)
974 int
975 afsconf_LookupServer(const char *service, const char *protocol,
976 const char *cellName, unsigned short afsdbPort,
977 afs_uint32 *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS],
978 unsigned short ports[], unsigned short ipRanks[],
979 int *numServers, int *ttl, char **arealCellName)
980 {
981 int code = 0;
982 int r;
983 int len;
984 unsigned char answer[4096];
985 unsigned char *p;
986 char *dotcellname = NULL;
987 char *realCellName;
988 char host[256];
989 int server_num = 0;
990 int minttl = 0;
991 int try_init = 0;
992 int dnstype = 0;
993 int pass = 0;
994 char *IANAname = (char *) afsconf_FindIANAName(service);
995 int tservice = afsconf_FindService(service);
996
997 realCellName = NULL;
998
999 *numServers = 0;
1000 *ttl = 0;
1001 if (tservice <= 0 || !IANAname)
1002 return AFSCONF_NOTFOUND; /* service not found */
1003
1004 if (strchr(cellName,'.'))
1005 pass += 2;
1006
1007 #ifdef HAVE_RES_RETRANSRETRY
1008 if ((_res.options & RES_INIT) == 0 && res_init() == -1)
1009 return (0);
1010
1011 /*
1012 * Rx timeout is typically 56 seconds; limit user experience to
1013 * similar timeout
1014 */
1015 _res.retrans = 18;
1016 _res.retry = 3;
1017 #endif
1018
1019 retryafsdb:
1020 r = -1;
1021 switch (pass) {
1022 case 0:
1023 dnstype = T_SRV;
1024 r = asprintf(&dotcellname, "_%s._%s.%s.", IANAname, protocol, cellName);
1025 break;
1026 case 1:
1027 dnstype = T_AFSDB;
1028 r = asprintf(&dotcellname, "%s.", cellName);
1029 break;
1030 case 2:
1031 dnstype = T_SRV;
1032 r = asprintf(&dotcellname, "_%s._%s.%s", IANAname, protocol, cellName);
1033 break;
1034 case 3:
1035 dnstype = T_AFSDB;
1036 r = asprintf(&dotcellname, "%s", cellName);
1037 break;
1038 }
1039 if (r < 0 || dotcellname == NULL)
1040 goto findservererror;
1041
1042 LOCK_GLOBAL_MUTEX;
1043 len = res_search(dotcellname, C_IN, dnstype, answer, sizeof(answer));
1044 UNLOCK_GLOBAL_MUTEX;
1045
1046 if (dotcellname != NULL) {
1047 free(dotcellname);
1048 dotcellname = NULL;
1049 }
1050
1051 if (len < 0) {
1052 if (try_init < 1) {
1053 try_init++;
1054 res_init();
1055 goto retryafsdb;
1056 }
1057 if (pass < 3) {
1058 pass++;
1059 goto retryafsdb;
1060 } else {
1061 code = AFSCONF_NOTFOUND;
1062 goto findservererror;
1063 }
1064 }
1065
1066 p = answer + sizeof(HEADER); /* Skip header */
1067 code = dn_expand(answer, answer + len, p, host, sizeof(host));
1068 if (code < 0) {
1069 code = AFSCONF_NOTFOUND;
1070 goto findservererror;
1071 }
1072
1073 p += code + QFIXEDSZ; /* Skip name */
1074
1075 while (p < answer + len) {
1076 int type, ttl, size;
1077
1078 code = dn_expand(answer, answer + len, p, host, sizeof(host));
1079 if (code < 0) {
1080 code = AFSCONF_NOTFOUND;
1081 goto findservererror;
1082 }
1083
1084 p += code; /* Skip the name */
1085 type = (p[0] << 8) | p[1];
1086 p += 4; /* Skip type and class */
1087 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
1088 p += 4; /* Skip the TTL */
1089 size = (p[0] << 8) | p[1];
1090 p += 2; /* Skip the size */
1091
1092 if (type == T_AFSDB) {
1093 struct hostent *he;
1094 short afsdb_type;
1095
1096 afsdb_type = (p[0] << 8) | p[1];
1097 if (afsdb_type == 1) {
1098 /*
1099 * We know this is an AFSDB record for our cell, of the
1100 * right AFSDB type. Write down the true cell name that
1101 * the resolver gave us above.
1102 */
1103 if (!realCellName)
1104 realCellName = strdup(host);
1105 }
1106
1107 code = dn_expand(answer, answer + len, p + 2, host, sizeof(host));
1108 if (code < 0) {
1109 code = AFSCONF_NOTFOUND;
1110 goto findservererror;
1111 }
1112
1113 if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) &&
1114 /* Do we want to get TTL data for the A record as well? */
1115 (he = gethostbyname(host))) {
1116 if (he->h_addrtype == AF_INET) {
1117 afs_uint32 ipaddr;
1118 memcpy(&ipaddr, he->h_addr, sizeof(ipaddr));
1119 cellHostAddrs[server_num] = ipaddr;
1120 ports[server_num] = afsdbPort;
1121 ipRanks[server_num] = 0;
1122 strncpy(cellHostNames[server_num], host,
1123 sizeof(cellHostNames[server_num]));
1124 server_num++;
1125 if (!minttl || ttl < minttl)
1126 minttl = ttl;
1127 }
1128 }
1129 }
1130 if (type == T_SRV) {
1131 struct hostent *he;
1132 /* math here: _ is 1, _ ._ is 3, _ ._ . is 4. then the domain. */
1133 if ((strncmp(host + 1, IANAname, strlen(IANAname)) == 0) &&
1134 (strncmp(host + strlen(IANAname) + 3, protocol,
1135 strlen(protocol)) == 0)) {
1136 if (!realCellName)
1137 realCellName = strdup(host + strlen(IANAname) +
1138 strlen(protocol) + 4);
1139 }
1140
1141 code = dn_expand(answer, answer + len, p + 6, host, sizeof(host));
1142 if (code < 0) {
1143 code = AFSCONF_NOTFOUND;
1144 goto findservererror;
1145 }
1146
1147 if ((server_num < MAXHOSTSPERCELL) &&
1148 /* Do we want to get TTL data for the A record as well? */
1149 (he = gethostbyname(host))) {
1150 if (he->h_addrtype == AF_INET) {
1151 afs_uint32 ipaddr;
1152
1153 memcpy(&ipaddr, he->h_addr, sizeof(ipaddr));
1154 cellHostAddrs[server_num] = ipaddr;
1155 ipRanks[server_num] = (p[0] << 8) | p[1];
1156 ports[server_num] = htons((p[4] << 8) | p[5]);
1157 /* weight = (p[2] << 8) | p[3]; */
1158 strncpy(cellHostNames[server_num], host,
1159 sizeof(cellHostNames[server_num]));
1160 server_num++;
1161
1162 if (!minttl || ttl < minttl)
1163 minttl = ttl;
1164 }
1165 }
1166 }
1167
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 *numServers = server_num;
1183 *ttl = minttl ? (time(0) + minttl) : 0;
1184
1185 if ( *numServers > 0 ) {
1186 code = 0;
1187 *arealCellName = realCellName;
1188 } else
1189 code = AFSCONF_NOTFOUND;
1190
1191 findservererror:
1192 if (code && realCellName)
1193 free(realCellName);
1194 return code;
1195 }
1196
1197 int
1198 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1199 struct afsconf_cell *acellInfo)
1200 {
1201 afs_uint32 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 we couldn't find an entry for the requested service
1224 * and that service happens to be the prservice or kaservice
1225 * then fallback to searching for afs3-vlserver and assigning
1226 * the port number here. */
1227 if (code < 0 && (afsdbport == htons(7002) || afsdbport == htons(7004))) {
1228 code = afsconf_LookupServer("afs3-vlserver", "udp",
1229 (const char *)acellName, afsdbport,
1230 cellHostAddrs, cellHostNames,
1231 ports, ipRanks, &numServers, &ttl,
1232 &realCellName);
1233 if (code >= 0) {
1234 for (i = 0; i < numServers; i++)
1235 ports[i] = afsdbport;
1236 }
1237 }
1238 if (code == 0) {
1239 acellInfo->timeout = ttl;
1240 acellInfo->numServers = numServers;
1241 for (i = 0; i < numServers; i++) {
1242 memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1243 sizeof(afs_int32));
1244 memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1245 acellInfo->hostAddr[i].sin_family = AF_INET;
1246 acellInfo->hostAddr[i].sin_port = ports[i];
1247
1248 if (realCellName) {
1249 strlcpy(acellInfo->name, realCellName,
1250 sizeof(acellInfo->name));
1251 free(realCellName);
1252 realCellName = NULL;
1253 }
1254 }
1255 acellInfo->linkedCell = NULL; /* no linked cell */
1256 acellInfo->flags = 0;
1257 }
1258 return code;
1259 }
1260 #else /* windows */
1261 int
1262 afsconf_GetAfsdbInfo(char *acellName, char *aservice,
1263 struct afsconf_cell *acellInfo)
1264 {
1265 afs_int32 i;
1266 int tservice = afsconf_FindService(aservice); /* network byte order */
1267 const char *ianaName = afsconf_FindIANAName(aservice);
1268 struct afsconf_entry DNSce;
1269 afs_uint32 cellHostAddrs[AFSMAXCELLHOSTS];
1270 char cellHostNames[AFSMAXCELLHOSTS][MAXHOSTCHARS];
1271 unsigned short ipRanks[AFSMAXCELLHOSTS];
1272 unsigned short ports[AFSMAXCELLHOSTS]; /* network byte order */
1273 int numServers;
1274 int rc;
1275 int ttl;
1276
1277 if (tservice < 0) {
1278 if (aservice)
1279 return AFSCONF_NOTFOUND;
1280 else
1281 tservice = 0; /* port will be assigned by caller */
1282 }
1283
1284 if (ianaName == NULL)
1285 ianaName = "afs3-vlserver";
1286
1287 DNSce.cellInfo.numServers = 0;
1288 DNSce.next = NULL;
1289
1290 rc = getAFSServer(ianaName, "udp", acellName, tservice,
1291 cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1292 &ttl);
1293 /* ignore the ttl here since this code is only called by transitory programs
1294 * like klog, etc. */
1295
1296 /* If we couldn't find an entry for the requested service
1297 * and that service happens to be the prservice or kaservice
1298 * then fallback to searching for afs3-vlserver and assigning
1299 * the port number here. */
1300 if (rc < 0 && (tservice == htons(7002) || tservice == htons(7004))) {
1301 rc = getAFSServer("afs3-vlserver", "udp", acellName, tservice,
1302 cellHostAddrs, cellHostNames, ports, ipRanks, &numServers,
1303 &ttl);
1304 if (rc >= 0) {
1305 for (i = 0; i < numServers; i++)
1306 ports[i] = tservice;
1307 }
1308 }
1309
1310 if (rc < 0 || numServers == 0)
1311 return -1;
1312
1313 for (i = 0; i < numServers; i++) {
1314 memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHostAddrs[i],
1315 sizeof(afs_uint32));
1316 memcpy(acellInfo->hostName[i], cellHostNames[i], MAXHOSTCHARS);
1317 acellInfo->hostAddr[i].sin_family = AF_INET;
1318 if (aservice)
1319 acellInfo->hostAddr[i].sin_port = ports[i];
1320 else
1321 acellInfo->hostAddr[i].sin_port = 0;
1322 }
1323
1324 acellInfo->numServers = numServers;
1325 strlcpy(acellInfo->name, acellName, sizeof acellInfo->name);
1326 acellInfo->linkedCell = NULL; /* no linked cell */
1327 acellInfo->flags = 0;
1328 return 0;
1329 }
1330 #endif /* windows */
1331
1332 int
1333 afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName, char *aservice,
1334 struct afsconf_cell *acellInfo)
1335 {
1336 struct afsconf_entry *tce;
1337 struct afsconf_aliasentry *tcae;
1338 struct afsconf_entry *bestce;
1339 afs_int32 i;
1340 int tservice;
1341 char *tcell;
1342 int cnLen;
1343 int ambig;
1344 char tbuffer[64];
1345
1346 LOCK_GLOBAL_MUTEX;
1347 if (adir)
1348 _afsconf_Check(adir);
1349 if (acellName) {
1350 tcell = acellName;
1351 cnLen = (int)(strlen(tcell) + 1);
1352 lcstring(tcell, tcell, cnLen);
1353 afsconf_SawCell = 1; /* will ignore the AFSCELL switch on future */
1354 /* call to afsconf_GetLocalCell: like klog */
1355 } else {
1356 i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
1357 if (i) {
1358 UNLOCK_GLOBAL_MUTEX;
1359 return i;
1360 }
1361 tcell = tbuffer;
1362 }
1363 cnLen = strlen(tcell);
1364 bestce = (struct afsconf_entry *)0;
1365 ambig = 0;
1366 if (!adir) {
1367 UNLOCK_GLOBAL_MUTEX;
1368 return 0;
1369 }
1370
1371 /* Look through the list of aliases */
1372 for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
1373 if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
1374 tcell = tcae->aliasInfo.realName;
1375 break;
1376 }
1377 }
1378
1379 for (tce = adir->entries; tce; tce = tce->next) {
1380 if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
1381 /* found our cell */
1382 bestce = tce;
1383 ambig = 0;
1384 break;
1385 }
1386 if (strlen(tce->cellInfo.name) < cnLen)
1387 continue; /* clearly wrong */
1388 if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
1389 if (bestce)
1390 ambig = 1; /* ambiguous unless we get exact match */
1391 bestce = tce;
1392 }
1393 }
1394 if (!ambig && bestce && bestce->cellInfo.numServers) {
1395 *acellInfo = bestce->cellInfo; /* structure assignment */
1396 if (aservice) {
1397 tservice = afsconf_FindService(aservice);
1398 if (tservice < 0) {
1399 UNLOCK_GLOBAL_MUTEX;
1400 return AFSCONF_NOTFOUND; /* service not found */
1401 }
1402 for (i = 0; i < acellInfo->numServers; i++) {
1403 acellInfo->hostAddr[i].sin_port = tservice;
1404 }
1405 }
1406 acellInfo->timeout = 0;
1407
1408 /*
1409 * Until we figure out how to separate out ubik server
1410 * queries from other server queries, only perform gethostbyname()
1411 * lookup on the specified hostnames for the client CellServDB files.
1412 */
1413 if (_afsconf_IsClientConfigDirectory(adir->name) &&
1414 !(acellInfo->flags & AFSCONF_CELL_FLAG_DNS_QUERIED)) {
1415 int j;
1416 short numServers=0; /*Num active servers for the cell */
1417 struct sockaddr_in hostAddr[MAXHOSTSPERCELL]; /*IP addresses for cell's servers */
1418 char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS]; /*Names for cell's servers */
1419
1420 memset(&hostAddr, 0, sizeof(hostAddr));
1421 memset(&hostName, 0, sizeof(hostName));
1422
1423 for ( j=0; j<acellInfo->numServers && numServers < MAXHOSTSPERCELL; j++ ) {
1424 struct hostent *he = gethostbyname(acellInfo->hostName[j]);
1425 int foundAddr = 0;
1426
1427 if (he && he->h_addrtype == AF_INET) {
1428 int i;
1429 /* obtain all the valid address from the list */
1430 for (i=0 ; he->h_addr_list[i] && numServers < MAXHOSTSPERCELL; i++) {
1431 /* check to see if this is a new address; if so insert it into the list */
1432 int k, dup;
1433 afs_uint32 addr;
1434 memcpy(&addr, he->h_addr_list[i], sizeof(addr));
1435 for (k=0, dup=0; !dup && k < numServers; k++) {
1436 if (hostAddr[k].sin_addr.s_addr == addr) {
1437 dup = 1;
1438 }
1439 }
1440 if (dup)
1441 continue;
1442
1443 hostAddr[numServers].sin_family = AF_INET;
1444 hostAddr[numServers].sin_port = acellInfo->hostAddr[0].sin_port;
1445 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
1446 hostAddr[numServers].sin_len = sizeof(struct sockaddr_in);
1447 #endif
1448 memcpy(&hostAddr[numServers].sin_addr.s_addr, he->h_addr_list[i], sizeof(afs_uint32));
1449 strcpy(hostName[numServers], acellInfo->hostName[j]);
1450 foundAddr = 1;
1451 numServers++;
1452 }
1453 }
1454 if (!foundAddr) {
1455 hostAddr[numServers] = acellInfo->hostAddr[j];
1456 strcpy(hostName[numServers], acellInfo->hostName[j]);
1457 numServers++;
1458 }
1459 }
1460
1461 for (i=0; i<numServers; i++) {
1462 acellInfo->hostAddr[i] = hostAddr[i];
1463 strcpy(acellInfo->hostName[i], hostName[i]);
1464 }
1465 acellInfo->numServers = numServers;
1466 acellInfo->flags |= AFSCONF_CELL_FLAG_DNS_QUERIED;
1467 }
1468 UNLOCK_GLOBAL_MUTEX;
1469 return 0;
1470 } else {
1471 UNLOCK_GLOBAL_MUTEX;
1472 return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
1473 }
1474 }
1475
1476 /**
1477 * Get the current localcell name.
1478 *
1479 * Internal function to get a pointer to the local cell name.
1480 * This function must be called with the global afsconf lock held.
1481 *
1482 * @param[in] adir afsconf object
1483 * @param[out] aname address to a char pointer
1484 * @param[in] check always perform a config check, even if the
1485 * the AFSCELL name is set.
1486 *
1487 * @return status
1488 * @retval 0 success
1489 * @retval AFSCONF_NOCELLNAME cannot determine local cell name
1490 *
1491 * @internal
1492 */
1493 int
1494 _afsconf_GetLocalCell(struct afsconf_dir *adir, char **pname, int check)
1495 {
1496 static int afsconf_showcell = 0;
1497 char *afscell_path;
1498 afs_int32 code = 0;
1499
1500 /*
1501 * If a cell switch was specified in a command, then it should override the
1502 * AFSCELL variable. If a cell was specified, then the afsconf_SawCell flag
1503 * is set and the cell name in the adir structure is used.
1504 * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
1505 * Optionally, check the configuration, even if using the environment variable.
1506 */
1507 if (!afsconf_SawCell && (afscell_path = getenv("AFSCELL"))) {
1508 if (check) {
1509 _afsconf_Check(adir);
1510 }
1511 if (!afsconf_showcell) {
1512 fprintf(stderr, "Note: Operation is performed on cell %s\n",
1513 afscell_path);
1514 afsconf_showcell = 1;
1515 }
1516 *pname = afscell_path;
1517 } else {
1518 _afsconf_Check(adir);
1519 if (adir->cellName) {
1520 *pname = adir->cellName;
1521 } else
1522 code = AFSCONF_NOCELLNAME;
1523 }
1524 return code;
1525 }
1526
1527 int
1528 afsconf_GetLocalCell(struct afsconf_dir *adir, char *aname, afs_int32 alen)
1529 {
1530 afs_int32 code = 0;
1531 char *cellname = NULL;
1532
1533 LOCK_GLOBAL_MUTEX;
1534 code = _afsconf_GetLocalCell(adir, &cellname, 0);
1535 if (!code && cellname) {
1536 strlcpy(aname, cellname, alen);
1537 }
1538 UNLOCK_GLOBAL_MUTEX;
1539 return (code);
1540 }
1541
1542 int
1543 afsconf_Close(struct afsconf_dir *adir)
1544 {
1545 if (adir == NULL) {
1546 return 0;
1547 }
1548
1549 LOCK_GLOBAL_MUTEX;
1550 afsconf_CloseInternal(adir);
1551 if (adir->name)
1552 free(adir->name);
1553 free(adir);
1554 UNLOCK_GLOBAL_MUTEX;
1555 return 0;
1556 }
1557
1558 static int
1559 afsconf_CloseInternal(struct afsconf_dir *adir)
1560 {
1561 struct afsconf_entry *td, *nd;
1562 struct afsconf_aliasentry *ta, *na;
1563 char *tname;
1564
1565 if (adir == NULL) {
1566 return 0;
1567 }
1568
1569 tname = adir->name; /* remember name, since that's all we preserve */
1570
1571 /* free everything we can find */
1572 if (adir->cellName)
1573 free(adir->cellName);
1574 for (td = adir->entries; td; td = nd) {
1575 nd = td->next;
1576 if (td->cellInfo.linkedCell)
1577 free(td->cellInfo.linkedCell);
1578 free(td);
1579 }
1580 for (ta = adir->alias_entries; ta; ta = na) {
1581 na = ta->next;
1582 free(ta);
1583 }
1584
1585 _afsconf_FreeAllKeys(adir);
1586 _afsconf_FreeRealms(adir);
1587
1588 /* reinit */
1589 memset(adir, 0, sizeof(struct afsconf_dir));
1590 adir->name = tname; /* restore it */
1591 return 0;
1592 }
1593
1594 static int
1595 afsconf_Reopen(struct afsconf_dir *adir)
1596 {
1597 afs_int32 code;
1598 code = afsconf_CloseInternal(adir);
1599 if (code)
1600 return code;
1601 code = afsconf_OpenInternal(adir, 0, 0);
1602 return code;
1603 }