2 * (C) COPYRIGHT IBM CORPORATION 1987
3 * LICENSED MATERIALS - PROPERTY OF IBM
7 #include <afs/pthread_glock.h>
9 #include "../afs/sysincludes.h"
10 #include "../afs/afsincludes.h"
12 #include <sys/types.h>
15 #include <sys/utime.h>
17 #include <WINNT/afssw.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
32 #include <afs/afsutil.h>
33 #include "cellconfig.h"
36 static ParseHostLine();
37 static ParseCellLine();
39 static struct afsconf_servPair serviceTable [] = {
50 0, 0 /* insert new services before this spot */
54 * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
55 * our code can tell if there is new info in the key files, the cell server db
56 * files or any of the other files (and reopen the thing) if the date on
60 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
61 static afs_int32 afsconf_FindService(aname)
62 register char *aname; {
63 /* lookup a service name */
65 register struct afsconf_servPair *tsp;
66 #if defined(AFS_OSF_ENV) || defined(AFS_DEC_ENV)
67 ts = getservbyname(aname, "");
69 ts = getservbyname(aname, (char *) 0);
72 /* we found it in /etc/services, so we use this value */
73 return ts->s_port; /* already in network byte order */
75 /* not found in /etc/services, see if it is one of ours */
76 for(tsp = serviceTable;; tsp++) {
77 if (tsp->name == (char *) 0) return -1;
78 if (!strcmp(tsp->name, aname)) return htons(tsp->port);
82 static int TrimLine(abuffer)
90 if (!isspace(tc)) break;
94 strcpy(abuffer, tbuffer);
100 * IsClientConfigDirectory() -- determine if path matches well-known
101 * client configuration directory.
103 static int IsClientConfigDirectory(const char *path)
105 const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
108 for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
109 int cc = tolower(cdir[i]);
110 int pc = tolower(path[i]);
123 /* hit end of one or both; allow mismatch in existence of trailing slash */
124 if (cdir[i] != '\0') {
125 if ((cdir[i] != '\\' && cdir[i] != '/') || (cdir[i + 1] != '\0')) {
129 if (path[i] != '\0') {
130 if ((path[i] != '\\' && path[i] != '/') || (path[i + 1] != '\0')) {
136 #endif /* AFS_NT40_ENV */
139 static int afsconf_Check(adir)
140 register struct afsconf_dir *adir; {
143 register afs_int32 code;
146 /* NT client CellServDB has different file name than NT server or Unix */
147 if (IsClientConfigDirectory(adir->name)) {
148 strcompose(tbuffer, 256,
149 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
151 strcompose(tbuffer, 256,
152 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
155 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
156 #endif /* AFS_NT40_ENV */
158 code = stat(tbuffer, &tstat);
162 /* did file change? */
163 if (tstat.st_mtime == adir->timeRead) {
166 /* otherwise file has changed, so reopen it */
167 return afsconf_Reopen(adir);
170 /* set modtime on file */
171 static afsconf_Touch(adir)
172 register struct afsconf_dir *adir; {
174 struct timeval tvp[2];
177 /* NT client CellServDB has different file name than NT server or Unix */
178 if (IsClientConfigDirectory(adir->name)) {
179 strcompose(tbuffer, 256,
180 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
182 strcompose(tbuffer, 256,
183 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
186 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
187 #endif /* AFS_NT40_ENV */
189 adir->timeRead = 0; /* just in case */
191 return _utime(tbuffer, NULL);
193 gettimeofday(&tvp[0], (char *) 0);
195 return utimes(tbuffer, tvp);
196 #endif /* AFS_NT40_ENV */
199 struct afsconf_dir *afsconf_Open(adir)
200 register char *adir; {
201 register struct afsconf_dir *tdir;
202 register afs_int32 code;
205 /* zero structure and fill in name; rest is done by internal routine */
206 tdir = (struct afsconf_dir *) malloc(sizeof(struct afsconf_dir));
207 bzero(tdir, sizeof(struct afsconf_dir));
208 tdir->name = (char *) malloc(strlen(adir)+1);
209 strcpy(tdir->name, adir);
211 code = afsconf_OpenInternal(tdir);
213 char *afsconf_path, *getenv(), afs_confdir[128];
216 /* Check global place only when local Open failed for whatever reason */
217 if (!(afsconf_path = getenv("AFSCONF"))) {
218 /* 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... */
223 if (!(home_dir = getenv("HOME"))) {
224 /* Our last chance is the "/.AFSCONF" file */
225 fp = fopen("/.AFSCONF", "r");
229 return (struct afsconf_dir *) 0;
231 fgets(afs_confdir, 128, fp);
236 sprintf(pathname, "%s/%s", home_dir, ".AFSCONF");
237 fp = fopen(pathname, "r");
239 /* Our last chance is the "/.AFSCONF" file */
240 fp = fopen("/.AFSCONF", "r");
244 return (struct afsconf_dir *) 0;
246 fgets(afs_confdir, 128, fp);
249 fgets(afs_confdir, 128, fp);
252 len = strlen(afs_confdir);
256 return (struct afsconf_dir *) 0;
258 if (afs_confdir[len-1] == '\n') {
259 afs_confdir[len-1] = 0;
261 afsconf_path = afs_confdir;
263 tdir->name = (char *) malloc(strlen(afsconf_path)+1);
264 strcpy(tdir->name, afsconf_path);
265 code = afsconf_OpenInternal(tdir);
270 return (struct afsconf_dir *) 0;
278 static int GetCellUnix(struct afsconf_dir *adir)
284 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
285 tf = fopen(tbuffer, "r");
287 rc = fscanf(tf, "%s", tbuffer);
289 adir->cellName = (char *) malloc(strlen(tbuffer)+1);
290 strcpy(adir->cellName, tbuffer);
302 static int GetCellNT(struct afsconf_dir *adir)
304 if (IsClientConfigDirectory(adir->name)) {
305 /* NT client config dir; ThisCell is in registry (no file). */
306 return afssw_GetClientCellName(&adir->cellName);
308 /* NT server config dir; works just like Unix */
309 return GetCellUnix(adir);
312 #endif /* AFS_NT40_ENV */
315 static int afsconf_OpenInternal(adir)
316 register struct afsconf_dir *adir; {
318 register char *tp, *bp;
319 register struct afsconf_entry *curEntry;
320 register afs_int32 code;
322 char tbuffer[256], tbuf1[256];
325 /* figure out the cell name */
329 i = GetCellUnix(adir);
335 /* now parse the individual lines */
339 /* NT client/server have a CellServDB that is the same format as Unix.
340 * However, the NT client uses a different file name
342 if (IsClientConfigDirectory(adir->name)) {
343 /* NT client config dir */
344 strcompose(tbuffer, 256,
345 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
347 /* NT server config dir */
348 strcompose(tbuffer, 256,
349 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
352 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
353 #endif /* AFS_NT40_ENV */
355 if (!stat(tbuffer, &tstat)) {
356 adir->timeRead = tstat.st_mtime;
361 strcpy(tbuf1, tbuffer);
362 tf = fopen(tbuffer, "r");
367 tp = fgets(tbuffer, sizeof(tbuffer), tf);
369 TrimLine(tbuffer); /* remove white space */
370 if (tbuffer[0] == 0 || tbuffer[0] == '\n') continue; /* empty line */
371 if (tbuffer[0] == '>') {
372 char linkedcell[MAXCELLCHARS];
373 /* start new cell item */
375 /* thread this guy on the list */
376 curEntry->next = adir->entries;
377 adir->entries = curEntry;
380 curEntry = (struct afsconf_entry *) malloc(sizeof(struct afsconf_entry));
381 bzero(curEntry, sizeof(struct afsconf_entry));
382 code = ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
384 afsconf_CloseInternal(adir);
388 if (linkedcell[0] != '\0') {
389 curEntry->cellInfo.linkedCell =
390 (char *) malloc(strlen(linkedcell) + 1);
391 strcpy(curEntry->cellInfo.linkedCell, linkedcell);
395 /* new host in the current cell */
397 afsconf_CloseInternal(adir);
401 i = curEntry->cellInfo.numServers;
402 code = ParseHostLine(tbuffer, (char *) &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i]);
404 if (code == AFSCONF_SYNTAX) {
405 for (bp=tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
409 fprintf(stderr, "Can't properly parse host line \"%s\" in configuration file %s\n", tbuffer, tbuf1);
413 afsconf_CloseInternal(adir);
416 curEntry->cellInfo.numServers = ++i;
419 fclose(tf); /* close the file now */
421 /* end the last partially-completed cell */
423 curEntry->next = adir->entries;
424 adir->entries = curEntry;
427 /* now read the fs keys, if possible */
428 adir->keystr = (struct afsconf_keys *) 0;
429 afsconf_IntGetKeys(adir);
434 /* parse a line of the form
435 *"128.2.1.3 #hostname"
436 * into the appropriate pieces.
438 static ParseHostLine(aline, addr, aname)
439 register struct sockaddr_in *addr;
440 char *aline, *aname; {
442 register afs_int32 code;
445 code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
446 if (code != 5) return AFSCONF_SYNTAX;
447 addr->sin_family = AF_INET;
449 tp = (char *) &addr->sin_addr;
457 /* parse a line of the form
458 * ">cellname [linkedcellname] [#comments]"
459 * into the appropriate pieces.
461 static ParseCellLine(aline, aname, alname)
462 register char *aline, *aname, *alname; {
464 code = sscanf(aline, ">%s %s", aname, alname);
465 if (code == 1) *alname = '\0';
467 if (*alname == '#') {
471 return (code > 0 ? 0 : AFSCONF_SYNTAX);
474 /* call aproc(entry, arock, adir) for all cells. Proc must return 0, or we'll stop early and return the code it returns */
475 afsconf_CellApply(adir, aproc, arock)
476 struct afsconf_dir *adir;
479 register struct afsconf_entry *tde;
480 register afs_int32 code;
482 for(tde=adir->entries; tde; tde=tde->next) {
483 code = (*aproc)(&tde->cellInfo, arock, adir);
493 afs_int32 afsconf_SawCell = 0;
494 afsconf_GetCellInfo(adir, acellName, aservice, acellInfo)
495 struct afsconf_dir *adir;
498 struct afsconf_cell *acellInfo; {
499 register struct afsconf_entry *tce;
500 struct afsconf_entry *bestce;
501 register afs_int32 i;
508 if (adir) afsconf_Check(adir);
511 cnLen = strlen(tcell)+1;
512 lcstring (tcell, tcell, cnLen);
513 afsconf_SawCell = 1; /* will ignore the AFSCELL switch on future */
514 /* call to afsconf_GetLocalCell: like klog */
516 i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
523 cnLen = strlen(tcell);
524 bestce = (struct afsconf_entry *) 0;
530 for(tce=adir->entries;tce;tce=tce->next) {
531 if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
537 if (strlen(tce->cellInfo.name) < cnLen) continue; /* clearly wrong */
538 if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
539 if (bestce) ambig = 1; /* ambiguous unless we get exact match */
543 if (!ambig && bestce) {
544 *acellInfo = bestce->cellInfo; /* structure assignment */
546 tservice = afsconf_FindService(aservice);
549 return AFSCONF_NOTFOUND; /* service not found */
551 for(i=0;i<acellInfo->numServers;i++) {
552 acellInfo->hostAddr[i].sin_port = tservice;
560 return AFSCONF_NOTFOUND;
564 afsconf_GetLocalCell(adir, aname, alen)
565 register struct afsconf_dir *adir;
568 static int afsconf_showcell = 0;
575 * If a cell switch was specified in a command, then it should override the
576 * AFSCELL variable. If a cell was specified, then the afsconf_SawCell flag
577 * is set and the cell name in the adir structure is used.
578 * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
580 if ( !afsconf_SawCell && (afscell_path= getenv("AFSCELL")) ) {
581 if ( !afsconf_showcell ) {
582 fprintf(stderr, "Note: Operation is performed on cell %s\n", afscell_path);
583 afsconf_showcell = 1;
585 strncpy(aname, afscell_path, alen);
588 if (adir->cellName) {
589 strncpy(aname, adir->cellName, alen);
591 else code = AFSCONF_UNKNOWN;
599 struct afsconf_dir *adir; {
601 afsconf_CloseInternal(adir);
602 if (adir->name) free(adir->name);
608 static int afsconf_CloseInternal(adir)
609 register struct afsconf_dir *adir; {
610 register struct afsconf_entry *td, *nd;
611 register char *tname;
613 tname = adir->name; /* remember name, since that's all we preserve */
615 /* free everything we can find */
616 if (adir->cellName) free(adir->cellName);
617 for(td=adir->entries;td;td=nd) {
619 if (td->cellInfo.linkedCell)
620 free(td->cellInfo.linkedCell);
623 if (adir->keystr) free(adir->keystr);
626 bzero(adir, sizeof(struct afsconf_dir));
627 adir->name = tname; /* restore it */
631 static int afsconf_Reopen(adir)
632 register struct afsconf_dir *adir; {
633 register afs_int32 code;
634 code = afsconf_CloseInternal(adir);
635 if (code) return code;
636 code = afsconf_OpenInternal(adir);
640 /* called during opening of config file */
641 afsconf_IntGetKeys(adir)
642 struct afsconf_dir *adir;
646 struct afsconf_keys *tstr;
647 register afs_int32 code;
650 /* NT client config dir has no KeyFile; don't risk attempting open
651 * because there might be a random file of this name if dir is shared.
653 if (IsClientConfigDirectory(adir->name)) {
654 adir->keystr = ((struct afsconf_keys *)
655 malloc(sizeof(struct afsconf_keys)));
656 adir->keystr->nkeys = 0;
659 #endif /* AFS_NT40_ENV */
662 /* compute the key name and other setup */
664 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
665 tstr = (struct afsconf_keys *) malloc(sizeof (struct afsconf_keys));
669 fd = open(tbuffer, O_RDONLY);
675 code = read(fd, tstr, sizeof(struct afsconf_keys));
677 if (code < sizeof(afs_int32)) {
683 /* convert key structure to host order */
684 tstr->nkeys = ntohl(tstr->nkeys);
685 for(fd=0;fd<tstr->nkeys;fd++)
686 tstr->key[fd].kvno = ntohl(tstr->key[fd].kvno);
692 /* get keys structure */
693 afsconf_GetKeys(adir, astr)
694 struct afsconf_dir *adir;
695 struct afsconf_keys *astr;
699 bcopy(adir->keystr, astr, sizeof(struct afsconf_keys));
705 afs_int32 afsconf_GetLatestKey(adir, avno, akey)
706 IN struct afsconf_dir *adir;
712 register struct afsconf_key *tk;
713 register afs_int32 best;
714 struct afsconf_key *bestk;
718 maxa = adir->keystr->nkeys;
720 best = -1; /* highest kvno we've seen yet */
721 bestk = (struct afsconf_key *) 0; /* ptr to structure providing best */
722 for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
723 if (tk->kvno == 999) continue; /* skip bcrypt keys */
724 if (tk->kvno > best) {
729 if (bestk) { /* found any */
730 if (akey) bcopy(bestk->key, akey, 8); /* copy out latest key */
731 if (avno) *avno = bestk->kvno; /* and kvno to caller */
736 return AFSCONF_NOTFOUND; /* didn't find any keys */
739 /* get a particular key */
740 afsconf_GetKey(adir, avno, akey)
741 struct afsconf_dir *adir;
745 register int i, maxa;
746 register struct afsconf_key *tk;
750 maxa = adir->keystr->nkeys;
752 for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
753 if (tk->kvno == avno) {
754 bcopy(tk->key, akey, 8);
761 return AFSCONF_NOTFOUND;
764 /* save the key structure in the appropriate file */
765 static SaveKeys(adir)
766 struct afsconf_dir *adir;
768 struct afsconf_keys tkeys;
770 register afs_int32 i;
773 bcopy(adir->keystr, &tkeys, sizeof(struct afsconf_keys));
775 /* convert it to net byte order */
776 for(i = 0; i<tkeys.nkeys; i++ )
777 tkeys.key[i].kvno = htonl(tkeys.key[i].kvno);
778 tkeys.nkeys = htonl(tkeys.nkeys);
780 /* rewrite keys file */
781 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
782 fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0600);
783 if (fd < 0) return AFSCONF_FAILURE;
784 i = write(fd, &tkeys, sizeof(tkeys));
785 if (i != sizeof(tkeys)) {
787 return AFSCONF_FAILURE;
789 if (close(fd) < 0) return AFSCONF_FAILURE;
793 afsconf_AddKey(adir, akvno, akey, overwrite)
794 struct afsconf_dir *adir;
795 afs_int32 akvno, overwrite;
798 register struct afsconf_keys *tk;
799 register struct afsconf_key *tkey;
800 register afs_int32 i;
807 if (akvno < 0 || akvno > 255) {
813 for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
814 if (tkey->kvno == akvno) {
817 return AFSCONF_KEYINUSE;
824 if (tk->nkeys >= AFSCONF_MAXKEYS) {
828 tkey = &tk->key[tk->nkeys++];
831 bcopy(akey, tkey->key, 8);
838 /* this proc works by sliding the other guys down, rather than using a funny
839 kvno value, so that callers can count on getting a good key in key[0].
841 afsconf_DeleteKey(adir, akvno)
842 struct afsconf_dir *adir;
845 register struct afsconf_keys *tk;
846 register struct afsconf_key *tkey;
853 for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
854 if (tkey->kvno == akvno) {
861 return AFSCONF_NOTFOUND;
864 /* otherwise slide the others down. i and tkey point at the guy to delete */
865 for(;i<tk->nkeys-1; i++,tkey++) {
866 tkey->kvno = (tkey+1)->kvno;
867 bcopy((tkey+1)->key, tkey->key, 8);