Commit | Line | Data |
---|---|---|
805e021f CE |
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 | } |