2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <afs/pthread_glock.h>
18 #include "afs/sysincludes.h"
19 #include "afsincludes.h"
21 #include <sys/types.h>
24 #include <sys/utime.h>
26 #include <WINNT/afssw.h>
29 #endif /* AFS_AFSDB_ENV */
31 #include <sys/socket.h>
32 #include <netinet/in.h>
37 #include <arpa/nameser.h>
39 #endif /* AFS_AFSDB_ENV */
40 #endif /* AFS_NT40_ENV */
41 #include <afs/afsint.h>
60 #include <afs/afsutil.h>
61 #include "cellconfig.h"
64 static struct afsconf_servPair serviceTable [] = {
69 { "afskauth", 7004, },
71 { "afserror", 7006, },
72 { "afsnanny", 7007, },
73 { "afsupdate", 7008, },
74 { "afsrmtsys", 7009, },
75 { "afsres", 7010, }, /* residency database for MR-AFS */
76 { "afsremio", 7011, }, /* remote I/O interface for MR-AFS */
77 { 0, 0 } /* insert new services before this spot */
81 static afs_int32 afsconf_FindService(register const char *aname);
82 static int TrimLine(char *abuffer);
84 static int IsClientConfigDirectory(const char *path);
85 static int GetCellNT(struct afsconf_dir *adir);
87 static int afsconf_Check(register struct afsconf_dir *adir);
88 static int afsconf_Touch(register struct afsconf_dir *adir);
89 static int GetCellUnix(struct afsconf_dir *adir);
90 static int afsconf_OpenInternal(register struct afsconf_dir *adir,
91 char *cell, char clones[]);
92 static int ParseHostLine(char *aline, register struct sockaddr_in *addr,
93 char *aname, char *aclone);
94 static int ParseCellLine(register char *aline, register char *aname,
95 register char *alname);
96 static int afsconf_CloseInternal(register struct afsconf_dir *adir);
97 static int afsconf_Reopen(register struct afsconf_dir *adir);
98 static int SaveKeys(struct afsconf_dir *adir);
101 #define T_AFSDB 18 /* per RFC1183 section 1 */
105 * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
106 * our code can tell if there is new info in the key files, the cell server db
107 * files or any of the other files (and reopen the thing) if the date on
108 * CellServDB changes.
111 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
112 static afs_int32 afsconf_FindService(register const char *aname)
114 /* lookup a service name */
116 register struct afsconf_servPair *tsp;
118 #if defined(AFS_OSF_ENV) || defined(AFS_DEC_ENV)
119 ts = getservbyname(aname, "");
121 ts = getservbyname(aname, NULL);
124 /* we found it in /etc/services, so we use this value */
125 return ts->s_port; /* already in network byte order */
128 /* not found in /etc/services, see if it is one of ours */
129 for(tsp = serviceTable;; tsp++) {
130 if (tsp->name == NULL) return -1;
131 if (!strcmp(tsp->name, aname)) return htons(tsp->port);
135 static int TrimLine(char *abuffer)
143 if (!isspace(tc)) break;
147 strcpy(abuffer, tbuffer);
153 * IsClientConfigDirectory() -- determine if path matches well-known
154 * client configuration directory.
156 static int IsClientConfigDirectory(const char *path)
158 const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
161 for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
162 int cc = tolower(cdir[i]);
163 int pc = tolower(path[i]);
176 /* hit end of one or both; allow mismatch in existence of trailing slash */
177 if (cdir[i] != '\0') {
178 if ((cdir[i] != '\\' && cdir[i] != '/') || (cdir[i + 1] != '\0')) {
182 if (path[i] != '\0') {
183 if ((path[i] != '\\' && path[i] != '/') || (path[i + 1] != '\0')) {
189 #endif /* AFS_NT40_ENV */
192 static int afsconf_Check(register struct afsconf_dir *adir)
196 register afs_int32 code;
199 /* NT client CellServDB has different file name than NT server or Unix */
200 if (IsClientConfigDirectory(adir->name)) {
201 strcompose(tbuffer, 256,
202 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
204 strcompose(tbuffer, 256,
205 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
208 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
209 #endif /* AFS_NT40_ENV */
211 code = stat(tbuffer, &tstat);
215 /* did file change? */
216 if (tstat.st_mtime == adir->timeRead) {
219 /* otherwise file has changed, so reopen it */
220 return afsconf_Reopen(adir);
223 /* set modtime on file */
224 static int afsconf_Touch(register struct afsconf_dir *adir)
228 struct timeval tvp[2];
231 adir->timeRead = 0; /* just in case */
234 /* NT client CellServDB has different file name than NT server or Unix */
236 if (IsClientConfigDirectory(adir->name)) {
237 strcompose(tbuffer, 256,
238 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
240 strcompose(tbuffer, 256,
241 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
244 return _utime(tbuffer, NULL);
247 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
248 gettimeofday(&tvp[0], NULL);
250 return utimes(tbuffer, tvp);
251 #endif /* AFS_NT40_ENV */
254 struct afsconf_dir *afsconf_Open(register const char *adir)
256 register struct afsconf_dir *tdir;
257 register afs_int32 code;
260 /* zero structure and fill in name; rest is done by internal routine */
261 tdir = (struct afsconf_dir *) malloc(sizeof(struct afsconf_dir));
262 memset(tdir, 0, sizeof(struct afsconf_dir));
263 tdir->name = (char *) malloc(strlen(adir)+1);
264 strcpy(tdir->name, adir);
266 code = afsconf_OpenInternal(tdir, 0, 0);
268 char *afsconf_path, afs_confdir[128];
271 /* Check global place only when local Open failed for whatever reason */
272 if (!(afsconf_path = getenv("AFSCONF"))) {
273 /* 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... */
278 if (!(home_dir = getenv("HOME"))) {
279 /* Our last chance is the "/.AFSCONF" file */
280 fp = fopen("/.AFSCONF", "r");
284 return (struct afsconf_dir *) 0;
286 fgets(afs_confdir, 128, fp);
291 sprintf(pathname, "%s/%s", home_dir, ".AFSCONF");
292 fp = fopen(pathname, "r");
294 /* Our last chance is the "/.AFSCONF" file */
295 fp = fopen("/.AFSCONF", "r");
299 return (struct afsconf_dir *) 0;
301 fgets(afs_confdir, 128, fp);
304 fgets(afs_confdir, 128, fp);
307 len = strlen(afs_confdir);
311 return (struct afsconf_dir *) 0;
313 if (afs_confdir[len-1] == '\n') {
314 afs_confdir[len-1] = 0;
316 afsconf_path = afs_confdir;
318 tdir->name = (char *) malloc(strlen(afsconf_path)+1);
319 strcpy(tdir->name, afsconf_path);
320 code = afsconf_OpenInternal(tdir, 0, 0);
325 return (struct afsconf_dir *) 0;
333 static int GetCellUnix(struct afsconf_dir *adir)
339 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
340 tf = fopen(tbuffer, "r");
342 rc = fscanf(tf, "%s", tbuffer);
344 adir->cellName = (char *) malloc(strlen(tbuffer)+1);
345 strcpy(adir->cellName, tbuffer);
357 static int GetCellNT(struct afsconf_dir *adir)
359 if (IsClientConfigDirectory(adir->name)) {
360 /* NT client config dir; ThisCell is in registry (no file). */
361 return afssw_GetClientCellName(&adir->cellName);
363 /* NT server config dir; works just like Unix */
364 return GetCellUnix(adir);
367 #endif /* AFS_NT40_ENV */
370 static int afsconf_OpenInternal(register struct afsconf_dir *adir,
371 char *cell, char clones[])
374 register char *tp, *bp;
375 register struct afsconf_entry *curEntry;
376 struct afsconf_aliasentry *curAlias;
377 register afs_int32 code;
379 char tbuffer[256], tbuf1[256];
382 /* figure out the cell name */
386 i = GetCellUnix(adir);
389 #ifndef AFS_FREELANCE_CLIENT /* no local cell not fatal in freelance */
395 /* now parse the individual lines */
399 /* NT client/server have a CellServDB that is the same format as Unix.
400 * However, the NT client uses a different file name
402 if (IsClientConfigDirectory(adir->name)) {
403 /* NT client config dir */
404 strcompose(tbuffer, 256,
405 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
407 /* NT server config dir */
408 strcompose(tbuffer, 256,
409 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
412 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
413 #endif /* AFS_NT40_ENV */
415 if (!stat(tbuffer, &tstat)) {
416 adir->timeRead = tstat.st_mtime;
421 strcpy(tbuf1, tbuffer);
422 tf = fopen(tbuffer, "r");
427 tp = fgets(tbuffer, sizeof(tbuffer), tf);
429 TrimLine(tbuffer); /* remove white space */
430 if (tbuffer[0] == 0 || tbuffer[0] == '\n') continue; /* empty line */
431 if (tbuffer[0] == '>') {
432 char linkedcell[MAXCELLCHARS];
433 /* start new cell item */
435 /* thread this guy on the list */
436 curEntry->next = adir->entries;
437 adir->entries = curEntry;
440 curEntry = (struct afsconf_entry *) malloc(sizeof(struct afsconf_entry));
441 memset(curEntry, 0, sizeof(struct afsconf_entry));
442 code = ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
444 afsconf_CloseInternal(adir);
448 if (linkedcell[0] != '\0') {
449 curEntry->cellInfo.linkedCell =
450 (char *) malloc(strlen(linkedcell) + 1);
451 strcpy(curEntry->cellInfo.linkedCell, linkedcell);
455 /* new host in the current cell */
457 afsconf_CloseInternal(adir);
461 i = curEntry->cellInfo.numServers;
462 if (cell && !strcmp(cell, curEntry->cellInfo.name))
463 code = ParseHostLine(tbuffer, &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i], &clones[i]);
465 code = ParseHostLine(tbuffer, &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i], 0);
467 if (code == AFSCONF_SYNTAX) {
468 for (bp=tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
472 fprintf(stderr, "Can't properly parse host line \"%s\" in configuration file %s\n", tbuffer, tbuf1);
476 afsconf_CloseInternal(adir);
479 curEntry->cellInfo.numServers = ++i;
482 fclose(tf); /* close the file now */
484 /* end the last partially-completed cell */
486 curEntry->next = adir->entries;
487 adir->entries = curEntry;
490 /* Read in the alias list */
491 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
493 tf = fopen(tbuffer, "r");
497 tp = fgets(tbuffer, sizeof(tbuffer), tf);
499 TrimLine(tbuffer); /* remove white space */
501 if (tbuffer[0] == '\0' ||
502 tbuffer[0] == '\n' ||
503 tbuffer[0] == '#') continue; /* empty line */
506 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t') tp++;
507 if (tp[0] == '\0') continue; /* invalid line */
509 while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t')) 0[tp++] = '\0';
510 if (tp[0] == '\0') continue; /* invalid line */
513 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' &&
514 tp[0] != '\r' && tp[0] != '\n') tp++;
517 curAlias = malloc(sizeof(*curAlias));
518 memset(curAlias, 0, sizeof(*curAlias));
520 strcpy(curAlias->aliasInfo.aliasName, aliasPtr);
521 strcpy(curAlias->aliasInfo.realName, tbuffer);
523 curAlias->next = adir->alias_entries;
524 adir->alias_entries = curAlias;
527 /* now read the fs keys, if possible */
528 adir->keystr = (struct afsconf_keys *) 0;
529 afsconf_IntGetKeys(adir);
534 /* parse a line of the form
535 *"128.2.1.3 #hostname" or
536 *"[128.2.1.3] #hostname" for clones
537 * into the appropriate pieces.
539 static int ParseHostLine(char *aline, register struct sockaddr_in *addr,
540 char *aname, char *aclone)
543 register afs_int32 code;
547 if (aclone) *aclone = 1;
548 code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
550 if (aclone) *aclone = 0;
551 code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
553 if (code != 5) return AFSCONF_SYNTAX;
554 addr->sin_family = AF_INET;
556 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
557 addr->sin_len = sizeof(struct sockaddr_in);
559 tp = (char *) &addr->sin_addr;
567 /* parse a line of the form
568 * ">cellname [linkedcellname] [#comments]"
569 * into the appropriate pieces.
571 static int ParseCellLine(register char *aline, register char *aname,
572 register char *alname)
575 code = sscanf(aline, ">%s %s", aname, alname);
576 if (code == 1) *alname = '\0';
578 if (*alname == '#') {
582 return (code > 0 ? 0 : AFSCONF_SYNTAX);
585 /* call aproc(entry, arock, adir) for all cells. Proc must return 0, or we'll stop early and return the code it returns */
586 int afsconf_CellApply(struct afsconf_dir *adir, int (*aproc)(struct afsconf_cell *cell,
587 char *arock, struct afsconf_dir *dir), char *arock)
589 register struct afsconf_entry *tde;
590 register afs_int32 code;
592 for(tde=adir->entries; tde; tde=tde->next) {
593 code = (*aproc)(&tde->cellInfo, arock, adir);
603 /* call aproc(entry, arock, adir) for all cell aliases.
604 * Proc must return 0, or we'll stop early and return the code it returns
606 int afsconf_CellAliasApply(struct afsconf_dir *adir, int (*aproc)(
607 struct afsconf_cellalias *alias, char *arock, struct afsconf_dir *dir), char *arock)
609 register struct afsconf_aliasentry *tde;
610 register afs_int32 code;
612 for(tde=adir->alias_entries; tde; tde=tde->next) {
613 code = (*aproc)(&tde->aliasInfo, arock, adir);
623 afs_int32 afsconf_SawCell = 0;
625 int afsconf_GetExtendedCellInfo(struct afsconf_dir *adir,
626 char *acellName, char *aservice, struct afsconf_cell *acellInfo,
632 code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
639 cell = (char *) &acellInfo->name;
641 code = afsconf_OpenInternal(adir, cell, clones);
646 #if !defined(AFS_NT40_ENV)
647 int afsconf_GetAfsdbInfo(char *acellName, char *aservice,
648 struct afsconf_cell *acellInfo)
653 unsigned char answer[1024];
655 char realCellName[256];
660 /* The resolver isn't always MT-safe.. Perhaps this ought to be
661 * replaced with a more fine-grained lock just for the resolver
665 len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
669 return AFSCONF_NOTFOUND;
671 p = answer + sizeof(HEADER); /* Skip header */
672 code = dn_expand(answer, answer + len, p, host, sizeof(host));
674 return AFSCONF_NOTFOUND;
676 p += code + QFIXEDSZ; /* Skip name */
678 while (p < answer + len) {
681 code = dn_expand(answer, answer + len, p, host, sizeof(host));
683 return AFSCONF_NOTFOUND;
685 p += code; /* Skip the name */
686 type = (p[0] << 8) | p[1];
687 p += 4; /* Skip type and class */
688 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
689 p += 4; /* Skip the TTL */
690 size = (p[0] << 8) | p[1];
691 p += 2; /* Skip the size */
693 if (type == T_AFSDB) {
697 afsdb_type = (p[0] << 8) | p[1];
698 if (afsdb_type == 1) {
700 * We know this is an AFSDB record for our cell, of the
701 * right AFSDB type. Write down the true cell name that
702 * the resolver gave us above.
704 strcpy(realCellName, host);
707 code = dn_expand(answer, answer+len, p+2, host, sizeof(host));
709 return AFSCONF_NOTFOUND;
711 if ((afsdb_type == 1) &&
712 (server_num < MAXHOSTSPERCELL) &&
713 /* Do we want to get TTL data for the A record as well? */
714 (he = gethostbyname(host))) {
716 memcpy(&ipaddr, he->h_addr, he->h_length);
717 acellInfo->hostAddr[server_num].sin_addr.s_addr = ipaddr;
718 strncpy(acellInfo->hostName[server_num], host,
719 sizeof(acellInfo->hostName[server_num]));
722 if (!minttl || ttl < minttl) minttl = ttl;
729 if (server_num == 0) /* No AFSDB records */
730 return AFSCONF_NOTFOUND;
732 /* Convert the real cell name to lowercase */
733 for (p = (unsigned char *) realCellName; *p; p++)
736 strncpy(acellInfo->name, realCellName, sizeof(acellInfo->name));
737 acellInfo->numServers = server_num;
740 tservice = afsconf_FindService(aservice);
742 return AFSCONF_NOTFOUND; /* service not found */
743 for (i=0; i<acellInfo->numServers; i++) {
744 acellInfo->hostAddr[i].sin_port = tservice;
748 acellInfo->timeout = minttl ? (time(0) + minttl) : 0;
753 int afsconf_GetAfsdbInfo(char *acellName, char *aservice,
754 struct afsconf_cell *acellInfo)
756 register afs_int32 i;
758 struct afsconf_entry DNSce;
759 char *DNStmpStrp; /* a temp string pointer */
761 afs_int32 cellHosts[AFSMAXCELLHOSTS];
766 DNSce.cellInfo.numServers=0;
768 rc = getAFSServer(acellName, cellHosts, &numServers, &ttl);
769 /* ignore the ttl here since this code is only called by transitory programs
776 for (i = 0; i < numServers; i++)
778 memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHosts[i], sizeof(long));
779 acellInfo->hostAddr[i].sin_family = AF_INET;
781 /* sin_port supplied by connection code */
784 acellInfo->numServers = numServers;
785 strcpy(acellInfo->name, acellName);
788 tservice = afsconf_FindService(aservice);
791 return AFSCONF_NOTFOUND; /* service not found */
793 for(i=0; i< acellInfo->numServers; i++) {
794 acellInfo->hostAddr[i].sin_port = tservice;
797 acellInfo->linkedCell = NULL; /* no linked cell */
798 acellInfo->flags = 0;
802 #endif /* AFS_AFSDB_ENV */
804 int afsconf_GetCellInfo(struct afsconf_dir *adir, char *acellName,
805 char *aservice, struct afsconf_cell *acellInfo)
807 register struct afsconf_entry *tce;
808 struct afsconf_aliasentry *tcae;
809 struct afsconf_entry *bestce;
810 register afs_int32 i;
818 if (adir) afsconf_Check(adir);
821 cnLen = strlen(tcell)+1;
822 lcstring (tcell, tcell, cnLen);
823 afsconf_SawCell = 1; /* will ignore the AFSCELL switch on future */
824 /* call to afsconf_GetLocalCell: like klog */
826 i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
833 cnLen = strlen(tcell);
834 bestce = (struct afsconf_entry *) 0;
841 /* Look through the list of aliases */
842 for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
843 if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
844 tcell = tcae->aliasInfo.realName;
849 for(tce=adir->entries;tce;tce=tce->next) {
850 if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
856 if (strlen(tce->cellInfo.name) < cnLen) continue; /* clearly wrong */
857 if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
858 if (bestce) ambig = 1; /* ambiguous unless we get exact match */
862 if (!ambig && bestce && bestce->cellInfo.numServers) {
863 *acellInfo = bestce->cellInfo; /* structure assignment */
865 tservice = afsconf_FindService(aservice);
868 return AFSCONF_NOTFOUND; /* service not found */
870 for(i=0;i<acellInfo->numServers;i++) {
871 acellInfo->hostAddr[i].sin_port = tservice;
874 acellInfo->timeout = 0;
881 return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
883 return AFSCONF_NOTFOUND;
884 #endif /* AFS_AFSDB_ENV */
888 int afsconf_GetLocalCell(register struct afsconf_dir *adir,
889 char *aname, afs_int32 alen)
891 static int afsconf_showcell = 0;
897 * If a cell switch was specified in a command, then it should override the
898 * AFSCELL variable. If a cell was specified, then the afsconf_SawCell flag
899 * is set and the cell name in the adir structure is used.
900 * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
902 if ( !afsconf_SawCell && (afscell_path= getenv("AFSCELL")) ) {
903 if ( !afsconf_showcell ) {
904 fprintf(stderr, "Note: Operation is performed on cell %s\n", afscell_path);
905 afsconf_showcell = 1;
907 strncpy(aname, afscell_path, alen);
910 if (adir->cellName) {
911 strncpy(aname, adir->cellName, alen);
913 else code = AFSCONF_UNKNOWN;
920 int afsconf_Close(struct afsconf_dir *adir)
923 afsconf_CloseInternal(adir);
924 if (adir->name) free(adir->name);
930 static int afsconf_CloseInternal(register struct afsconf_dir *adir)
932 register struct afsconf_entry *td, *nd;
933 struct afsconf_aliasentry *ta, *na;
934 register char *tname;
936 tname = adir->name; /* remember name, since that's all we preserve */
938 /* free everything we can find */
939 if (adir->cellName) free(adir->cellName);
940 for(td=adir->entries;td;td=nd) {
942 if (td->cellInfo.linkedCell)
943 free(td->cellInfo.linkedCell);
946 for (ta = adir->alias_entries; ta; ta = na) {
950 if (adir->keystr) free(adir->keystr);
953 memset(adir, 0, sizeof(struct afsconf_dir));
954 adir->name = tname; /* restore it */
958 static int afsconf_Reopen(register struct afsconf_dir *adir)
960 register afs_int32 code;
961 code = afsconf_CloseInternal(adir);
962 if (code) return code;
963 code = afsconf_OpenInternal(adir, 0, 0);
967 /* called during opening of config file */
968 int afsconf_IntGetKeys(struct afsconf_dir *adir)
972 struct afsconf_keys *tstr;
973 register afs_int32 code;
976 /* NT client config dir has no KeyFile; don't risk attempting open
977 * because there might be a random file of this name if dir is shared.
979 if (IsClientConfigDirectory(adir->name)) {
980 adir->keystr = ((struct afsconf_keys *)
981 malloc(sizeof(struct afsconf_keys)));
982 adir->keystr->nkeys = 0;
985 #endif /* AFS_NT40_ENV */
988 /* compute the key name and other setup */
990 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
991 tstr = (struct afsconf_keys *) malloc(sizeof (struct afsconf_keys));
995 fd = open(tbuffer, O_RDONLY);
1001 code = read(fd, tstr, sizeof(struct afsconf_keys));
1003 if (code < sizeof(afs_int32)) {
1009 /* convert key structure to host order */
1010 tstr->nkeys = ntohl(tstr->nkeys);
1011 for(fd=0;fd<tstr->nkeys;fd++)
1012 tstr->key[fd].kvno = ntohl(tstr->key[fd].kvno);
1018 /* get keys structure */
1019 int afsconf_GetKeys(struct afsconf_dir *adir, struct afsconf_keys *astr)
1021 register afs_int32 code;
1024 code = afsconf_Check(adir);
1027 return AFSCONF_FAILURE;
1029 memcpy(astr, adir->keystr, sizeof(struct afsconf_keys));
1034 /* get latest key */
1035 afs_int32 afsconf_GetLatestKey(struct afsconf_dir *adir,
1036 afs_int32 *avno, char *akey)
1040 register struct afsconf_key *tk;
1041 register afs_int32 best;
1042 struct afsconf_key *bestk;
1043 register afs_int32 code;
1046 code = afsconf_Check(adir);
1049 return AFSCONF_FAILURE;
1051 maxa = adir->keystr->nkeys;
1053 best = -1; /* highest kvno we've seen yet */
1054 bestk = (struct afsconf_key *) 0; /* ptr to structure providing best */
1055 for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
1056 if (tk->kvno == 999) continue; /* skip bcrypt keys */
1057 if (tk->kvno > best) {
1062 if (bestk) { /* found any */
1063 if (akey) memcpy(akey, bestk->key, 8); /* copy out latest key */
1064 if (avno) *avno = bestk->kvno; /* and kvno to caller */
1069 return AFSCONF_NOTFOUND; /* didn't find any keys */
1072 /* get a particular key */
1073 int afsconf_GetKey(struct afsconf_dir *adir, afs_int32 avno,
1076 register int i, maxa;
1077 register struct afsconf_key *tk;
1078 register afs_int32 code;
1081 code = afsconf_Check(adir);
1084 return AFSCONF_FAILURE;
1086 maxa = adir->keystr->nkeys;
1088 for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
1089 if (tk->kvno == avno) {
1090 memcpy(akey, tk->key, 8);
1097 return AFSCONF_NOTFOUND;
1100 /* save the key structure in the appropriate file */
1101 static int SaveKeys(struct afsconf_dir *adir)
1103 struct afsconf_keys tkeys;
1105 register afs_int32 i;
1108 memcpy(&tkeys, adir->keystr, sizeof(struct afsconf_keys));
1110 /* convert it to net byte order */
1111 for(i = 0; i<tkeys.nkeys; i++ )
1112 tkeys.key[i].kvno = htonl(tkeys.key[i].kvno);
1113 tkeys.nkeys = htonl(tkeys.nkeys);
1115 /* rewrite keys file */
1116 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1117 fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0600);
1118 if (fd < 0) return AFSCONF_FAILURE;
1119 i = write(fd, &tkeys, sizeof(tkeys));
1120 if (i != sizeof(tkeys)) {
1122 return AFSCONF_FAILURE;
1124 if (close(fd) < 0) return AFSCONF_FAILURE;
1128 int afsconf_AddKey(struct afsconf_dir *adir, afs_int32 akvno,
1129 char akey[8], afs_int32 overwrite)
1131 register struct afsconf_keys *tk;
1132 register struct afsconf_key *tkey;
1133 register afs_int32 i;
1140 if (akvno < 0 || akvno > 255) {
1146 for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
1147 if (tkey->kvno == akvno) {
1150 return AFSCONF_KEYINUSE;
1157 if (tk->nkeys >= AFSCONF_MAXKEYS) {
1159 return AFSCONF_FULL;
1161 tkey = &tk->key[tk->nkeys++];
1164 memcpy(tkey->key, akey, 8);
1166 afsconf_Touch(adir);
1171 /* this proc works by sliding the other guys down, rather than using a funny
1172 kvno value, so that callers can count on getting a good key in key[0].
1174 int afsconf_DeleteKey(struct afsconf_dir *adir, afs_int32 akvno)
1176 register struct afsconf_keys *tk;
1177 register struct afsconf_key *tkey;
1184 for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
1185 if (tkey->kvno == akvno) {
1192 return AFSCONF_NOTFOUND;
1195 /* otherwise slide the others down. i and tkey point at the guy to delete */
1196 for(;i<tk->nkeys-1; i++,tkey++) {
1197 tkey->kvno = (tkey+1)->kvno;
1198 memcpy(tkey->key, (tkey+1)->key, 8);
1202 afsconf_Touch(adir);