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 "../afs/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 ParseHostLine();
65 static ParseCellLine();
66 static afsconf_OpenInternal();
67 static afsconf_CloseInternal();
68 static afsconf_Reopen();
70 static struct afsconf_servPair serviceTable [] = {
75 { "afskauth", 7004, },
77 { "afserror", 7006, },
78 { "afsnanny", 7007, },
79 { "afsupdate", 7008, },
80 { "afsrmtsys", 7009, },
81 { "afsres", 7010, }, /* residency database for MR-AFS */
82 { "afsremio", 7011, }, /* remote I/O interface for MR-AFS */
83 { 0, 0 } /* insert new services before this spot */
87 * Basic Rule: we touch "<AFSCONF_DIR>/CellServDB" every time we change anything, so
88 * our code can tell if there is new info in the key files, the cell server db
89 * files or any of the other files (and reopen the thing) if the date on
93 /* return port number in network byte order in the low 16 bits of a long; return -1 if not found */
94 static afs_int32 afsconf_FindService(aname)
95 register char *aname; {
96 /* lookup a service name */
98 register struct afsconf_servPair *tsp;
100 #if defined(AFS_OSF_ENV) || defined(AFS_DEC_ENV)
101 ts = getservbyname(aname, "");
103 ts = getservbyname(aname, (char *) 0);
106 /* we found it in /etc/services, so we use this value */
107 return ts->s_port; /* already in network byte order */
110 /* not found in /etc/services, see if it is one of ours */
111 for(tsp = serviceTable;; tsp++) {
112 if (tsp->name == (char *) 0) return -1;
113 if (!strcmp(tsp->name, aname)) return htons(tsp->port);
117 static int TrimLine(abuffer)
125 if (!isspace(tc)) break;
129 strcpy(abuffer, tbuffer);
135 * IsClientConfigDirectory() -- determine if path matches well-known
136 * client configuration directory.
138 static int IsClientConfigDirectory(const char *path)
140 const char *cdir = AFSDIR_CLIENT_ETC_DIRPATH;
143 for (i = 0; cdir[i] != '\0' && path[i] != '\0'; i++) {
144 int cc = tolower(cdir[i]);
145 int pc = tolower(path[i]);
158 /* hit end of one or both; allow mismatch in existence of trailing slash */
159 if (cdir[i] != '\0') {
160 if ((cdir[i] != '\\' && cdir[i] != '/') || (cdir[i + 1] != '\0')) {
164 if (path[i] != '\0') {
165 if ((path[i] != '\\' && path[i] != '/') || (path[i + 1] != '\0')) {
171 #endif /* AFS_NT40_ENV */
174 static int afsconf_Check(adir)
175 register struct afsconf_dir *adir; {
178 register afs_int32 code;
181 /* NT client CellServDB has different file name than NT server or Unix */
182 if (IsClientConfigDirectory(adir->name)) {
183 strcompose(tbuffer, 256,
184 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
186 strcompose(tbuffer, 256,
187 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
190 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
191 #endif /* AFS_NT40_ENV */
193 code = stat(tbuffer, &tstat);
197 /* did file change? */
198 if (tstat.st_mtime == adir->timeRead) {
201 /* otherwise file has changed, so reopen it */
202 return afsconf_Reopen(adir);
205 /* set modtime on file */
206 static afsconf_Touch(adir)
207 register struct afsconf_dir *adir; {
210 struct timeval tvp[2];
213 adir->timeRead = 0; /* just in case */
216 /* NT client CellServDB has different file name than NT server or Unix */
218 if (IsClientConfigDirectory(adir->name)) {
219 strcompose(tbuffer, 256,
220 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
222 strcompose(tbuffer, 256,
223 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
226 return _utime(tbuffer, NULL);
229 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
230 gettimeofday(&tvp[0], NULL);
232 return utimes(tbuffer, tvp);
233 #endif /* AFS_NT40_ENV */
236 struct afsconf_dir *afsconf_Open(adir)
237 register char *adir; {
238 register struct afsconf_dir *tdir;
239 register afs_int32 code;
242 /* zero structure and fill in name; rest is done by internal routine */
243 tdir = (struct afsconf_dir *) malloc(sizeof(struct afsconf_dir));
244 memset(tdir, 0, sizeof(struct afsconf_dir));
245 tdir->name = (char *) malloc(strlen(adir)+1);
246 strcpy(tdir->name, adir);
248 code = afsconf_OpenInternal(tdir, 0, 0);
250 char *afsconf_path, *getenv(), afs_confdir[128];
253 /* Check global place only when local Open failed for whatever reason */
254 if (!(afsconf_path = getenv("AFSCONF"))) {
255 /* 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... */
260 if (!(home_dir = getenv("HOME"))) {
261 /* Our last chance is the "/.AFSCONF" file */
262 fp = fopen("/.AFSCONF", "r");
266 return (struct afsconf_dir *) 0;
268 fgets(afs_confdir, 128, fp);
273 sprintf(pathname, "%s/%s", home_dir, ".AFSCONF");
274 fp = fopen(pathname, "r");
276 /* Our last chance is the "/.AFSCONF" file */
277 fp = fopen("/.AFSCONF", "r");
281 return (struct afsconf_dir *) 0;
283 fgets(afs_confdir, 128, fp);
286 fgets(afs_confdir, 128, fp);
289 len = strlen(afs_confdir);
293 return (struct afsconf_dir *) 0;
295 if (afs_confdir[len-1] == '\n') {
296 afs_confdir[len-1] = 0;
298 afsconf_path = afs_confdir;
300 tdir->name = (char *) malloc(strlen(afsconf_path)+1);
301 strcpy(tdir->name, afsconf_path);
302 code = afsconf_OpenInternal(tdir, 0, 0);
307 return (struct afsconf_dir *) 0;
315 static int GetCellUnix(struct afsconf_dir *adir)
321 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_THISCELL_FILE, NULL);
322 tf = fopen(tbuffer, "r");
324 rc = fscanf(tf, "%s", tbuffer);
326 adir->cellName = (char *) malloc(strlen(tbuffer)+1);
327 strcpy(adir->cellName, tbuffer);
339 static int GetCellNT(struct afsconf_dir *adir)
341 if (IsClientConfigDirectory(adir->name)) {
342 /* NT client config dir; ThisCell is in registry (no file). */
343 return afssw_GetClientCellName(&adir->cellName);
345 /* NT server config dir; works just like Unix */
346 return GetCellUnix(adir);
349 #endif /* AFS_NT40_ENV */
352 static int afsconf_OpenInternal(adir, cell, clones)
353 register struct afsconf_dir *adir;
358 register char *tp, *bp;
359 register struct afsconf_entry *curEntry;
360 struct afsconf_aliasentry *curAlias;
361 register afs_int32 code;
363 char tbuffer[256], tbuf1[256];
366 /* figure out the cell name */
370 i = GetCellUnix(adir);
373 #ifndef AFS_FREELANCE_CLIENT /* no local cell not fatal in freelance */
379 /* now parse the individual lines */
383 /* NT client/server have a CellServDB that is the same format as Unix.
384 * However, the NT client uses a different file name
386 if (IsClientConfigDirectory(adir->name)) {
387 /* NT client config dir */
388 strcompose(tbuffer, 256,
389 adir->name, "/", AFSDIR_CELLSERVDB_FILE_NTCLIENT, NULL);
391 /* NT server config dir */
392 strcompose(tbuffer, 256,
393 adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
396 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLSERVDB_FILE, NULL);
397 #endif /* AFS_NT40_ENV */
399 if (!stat(tbuffer, &tstat)) {
400 adir->timeRead = tstat.st_mtime;
405 strcpy(tbuf1, tbuffer);
406 tf = fopen(tbuffer, "r");
411 tp = fgets(tbuffer, sizeof(tbuffer), tf);
413 TrimLine(tbuffer); /* remove white space */
414 if (tbuffer[0] == 0 || tbuffer[0] == '\n') continue; /* empty line */
415 if (tbuffer[0] == '>') {
416 char linkedcell[MAXCELLCHARS];
417 /* start new cell item */
419 /* thread this guy on the list */
420 curEntry->next = adir->entries;
421 adir->entries = curEntry;
424 curEntry = (struct afsconf_entry *) malloc(sizeof(struct afsconf_entry));
425 memset(curEntry, 0, sizeof(struct afsconf_entry));
426 code = ParseCellLine(tbuffer, curEntry->cellInfo.name, linkedcell);
428 afsconf_CloseInternal(adir);
432 if (linkedcell[0] != '\0') {
433 curEntry->cellInfo.linkedCell =
434 (char *) malloc(strlen(linkedcell) + 1);
435 strcpy(curEntry->cellInfo.linkedCell, linkedcell);
439 /* new host in the current cell */
441 afsconf_CloseInternal(adir);
445 i = curEntry->cellInfo.numServers;
446 if (cell && !strcmp(cell, curEntry->cellInfo.name))
447 code = ParseHostLine(tbuffer, (char *) &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i], &clones[i]);
449 code = ParseHostLine(tbuffer, (char *) &curEntry->cellInfo.hostAddr[i], curEntry->cellInfo.hostName[i], 0);
451 if (code == AFSCONF_SYNTAX) {
452 for (bp=tbuffer; *bp != '\n'; bp++) { /* Take out the <cr> from the buffer */
456 fprintf(stderr, "Can't properly parse host line \"%s\" in configuration file %s\n", tbuffer, tbuf1);
460 afsconf_CloseInternal(adir);
463 curEntry->cellInfo.numServers = ++i;
466 fclose(tf); /* close the file now */
468 /* end the last partially-completed cell */
470 curEntry->next = adir->entries;
471 adir->entries = curEntry;
474 /* Read in the alias list */
475 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_CELLALIAS_FILE, NULL);
477 tf = fopen(tbuffer, "r");
481 tp = fgets(tbuffer, sizeof(tbuffer), tf);
483 TrimLine(tbuffer); /* remove white space */
485 if (tbuffer[0] == '\0' ||
486 tbuffer[0] == '\n' ||
487 tbuffer[0] == '#') continue; /* empty line */
490 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t') tp++;
491 if (tp[0] == '\0') continue; /* invalid line */
493 while (tp[0] != '\0' && (tp[0] == ' ' || tp[0] == '\t')) 0[tp++] = '\0';
494 if (tp[0] == '\0') continue; /* invalid line */
497 while (tp[0] != '\0' && tp[0] != ' ' && tp[0] != '\t' &&
498 tp[0] != '\r' && tp[0] != '\n') tp++;
501 curAlias = malloc(sizeof(*curAlias));
502 memset(curAlias, 0, sizeof(*curAlias));
504 strcpy(curAlias->aliasInfo.aliasName, aliasPtr);
505 strcpy(curAlias->aliasInfo.realName, tbuffer);
507 curAlias->next = adir->alias_entries;
508 adir->alias_entries = curAlias;
511 /* now read the fs keys, if possible */
512 adir->keystr = (struct afsconf_keys *) 0;
513 afsconf_IntGetKeys(adir);
518 /* parse a line of the form
519 *"128.2.1.3 #hostname" or
520 *"[128.2.1.3] #hostname" for clones
521 * into the appropriate pieces.
523 static ParseHostLine(aline, addr, aname, aclone)
525 register struct sockaddr_in *addr;
529 register afs_int32 code;
533 if (aclone) *aclone = 1;
534 code = sscanf(aline, "[%d.%d.%d.%d] #%s", &c1, &c2, &c3, &c4, aname);
536 if (aclone) *aclone = 0;
537 code = sscanf(aline, "%d.%d.%d.%d #%s", &c1, &c2, &c3, &c4, aname);
539 if (code != 5) return AFSCONF_SYNTAX;
540 addr->sin_family = AF_INET;
542 tp = (char *) &addr->sin_addr;
550 /* parse a line of the form
551 * ">cellname [linkedcellname] [#comments]"
552 * into the appropriate pieces.
554 static ParseCellLine(aline, aname, alname)
555 register char *aline, *aname, *alname; {
557 code = sscanf(aline, ">%s %s", aname, alname);
558 if (code == 1) *alname = '\0';
560 if (*alname == '#') {
564 return (code > 0 ? 0 : AFSCONF_SYNTAX);
567 /* call aproc(entry, arock, adir) for all cells. Proc must return 0, or we'll stop early and return the code it returns */
568 afsconf_CellApply(adir, aproc, arock)
569 struct afsconf_dir *adir;
572 register struct afsconf_entry *tde;
573 register afs_int32 code;
575 for(tde=adir->entries; tde; tde=tde->next) {
576 code = (*aproc)(&tde->cellInfo, arock, adir);
586 /* call aproc(entry, arock, adir) for all cell aliases.
587 * Proc must return 0, or we'll stop early and return the code it returns
589 afsconf_CellAliasApply(adir, aproc, arock)
590 struct afsconf_dir *adir;
594 register struct afsconf_aliasentry *tde;
595 register afs_int32 code;
597 for(tde=adir->alias_entries; tde; tde=tde->next) {
598 code = (*aproc)(&tde->aliasInfo, arock, adir);
608 afs_int32 afsconf_SawCell = 0;
610 afsconf_GetExtendedCellInfo(adir, acellName, aservice, acellInfo, clones)
611 struct afsconf_dir *adir;
614 struct afsconf_cell *acellInfo;
620 code = afsconf_GetCellInfo(adir, acellName, aservice, acellInfo);
627 cell = (char *) &acellInfo->name;
629 code = afsconf_OpenInternal(adir, cell, clones);
634 #if !defined(AFS_NT40_ENV)
635 afsconf_GetAfsdbInfo(acellName, aservice, acellInfo)
638 struct afsconf_cell *acellInfo;
643 unsigned char answer[1024];
645 char realCellName[256];
650 /* The resolver isn't always MT-safe.. Perhaps this ought to be
651 * replaced with a more fine-grained lock just for the resolver
655 len = res_search(acellName, C_IN, T_AFSDB, answer, sizeof(answer));
659 return AFSCONF_NOTFOUND;
661 p = answer + sizeof(HEADER); /* Skip header */
662 code = dn_expand(answer, answer + len, p, host, sizeof(host));
664 return AFSCONF_NOTFOUND;
666 p += code + QFIXEDSZ; /* Skip name */
668 while (p < answer + len) {
671 code = dn_expand(answer, answer + len, p, host, sizeof(host));
673 return AFSCONF_NOTFOUND;
675 p += code; /* Skip the name */
676 type = (p[0] << 8) | p[1];
677 p += 4; /* Skip type and class */
678 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
679 p += 4; /* Skip the TTL */
680 size = (p[0] << 8) | p[1];
681 p += 2; /* Skip the size */
683 if (type == T_AFSDB) {
687 afsdb_type = (p[0] << 8) | p[1];
688 if (afsdb_type == 1) {
690 * We know this is an AFSDB record for our cell, of the
691 * right AFSDB type. Write down the true cell name that
692 * the resolver gave us above.
694 strcpy(realCellName, host);
697 code = dn_expand(answer, answer+len, p+2, host, sizeof(host));
699 return AFSCONF_NOTFOUND;
701 if ((afsdb_type == 1) &&
702 (server_num < MAXHOSTSPERCELL) &&
703 /* Do we want to get TTL data for the A record as well? */
704 (he = gethostbyname(host))) {
706 memcpy(&ipaddr, he->h_addr, he->h_length);
707 acellInfo->hostAddr[server_num].sin_addr.s_addr = ipaddr;
708 strncpy(acellInfo->hostName[server_num], host,
709 sizeof(acellInfo->hostName[server_num]));
712 if (!minttl || ttl < minttl) minttl = ttl;
719 if (server_num == 0) /* No AFSDB records */
720 return AFSCONF_NOTFOUND;
722 /* Convert the real cell name to lowercase */
723 for (p = (unsigned char *) realCellName; *p; p++)
726 strncpy(acellInfo->name, realCellName, sizeof(acellInfo->name));
727 acellInfo->numServers = server_num;
730 tservice = afsconf_FindService(aservice);
732 return AFSCONF_NOTFOUND; /* service not found */
733 for (i=0; i<acellInfo->numServers; i++) {
734 acellInfo->hostAddr[i].sin_port = tservice;
738 acellInfo->timeout = minttl ? (time(0) + minttl) : 0;
743 int afsconf_GetAfsdbInfo(acellName, aservice, acellInfo)
746 struct afsconf_cell *acellInfo;
748 register afs_int32 i;
750 struct afsconf_entry DNSce;
751 char *DNStmpStrp; /* a temp string pointer */
753 afs_int32 cellHosts[AFSMAXCELLHOSTS];
758 DNSce.cellInfo.numServers=0;
760 rc = getAFSServer(acellName, cellHosts, &numServers, &ttl);
761 /* ignore the ttl here since this code is only called by transitory programs
768 for (i = 0; i < numServers; i++)
770 memcpy(&acellInfo->hostAddr[i].sin_addr.s_addr, &cellHosts[i], sizeof(long));
771 acellInfo->hostAddr[i].sin_family = AF_INET;
773 /* sin_port supplied by connection code */
776 acellInfo->numServers = numServers;
777 strcpy(acellInfo->name, acellName);
780 tservice = afsconf_FindService(aservice);
783 return AFSCONF_NOTFOUND; /* service not found */
785 for(i=0; i< acellInfo->numServers; i++) {
786 acellInfo->hostAddr[i].sin_port = tservice;
789 acellInfo->linkedCell = NULL; /* no linked cell */
790 acellInfo->flags = 0;
794 #endif /* AFS_AFSDB_ENV */
796 afsconf_GetCellInfo(adir, acellName, aservice, acellInfo)
797 struct afsconf_dir *adir;
800 struct afsconf_cell *acellInfo; {
801 register struct afsconf_entry *tce;
802 struct afsconf_aliasentry *tcae;
803 struct afsconf_entry *bestce;
804 register afs_int32 i;
812 if (adir) afsconf_Check(adir);
815 cnLen = strlen(tcell)+1;
816 lcstring (tcell, tcell, cnLen);
817 afsconf_SawCell = 1; /* will ignore the AFSCELL switch on future */
818 /* call to afsconf_GetLocalCell: like klog */
820 i = afsconf_GetLocalCell(adir, tbuffer, sizeof(tbuffer));
827 cnLen = strlen(tcell);
828 bestce = (struct afsconf_entry *) 0;
835 /* Look through the list of aliases */
836 for (tcae = adir->alias_entries; tcae; tcae = tcae->next) {
837 if (strcasecmp(tcae->aliasInfo.aliasName, tcell) == 0) {
838 tcell = tcae->aliasInfo.realName;
843 for(tce=adir->entries;tce;tce=tce->next) {
844 if (strcasecmp(tce->cellInfo.name, tcell) == 0) {
850 if (strlen(tce->cellInfo.name) < cnLen) continue; /* clearly wrong */
851 if (strncasecmp(tce->cellInfo.name, tcell, cnLen) == 0) {
852 if (bestce) ambig = 1; /* ambiguous unless we get exact match */
856 if (!ambig && bestce) {
857 *acellInfo = bestce->cellInfo; /* structure assignment */
859 tservice = afsconf_FindService(aservice);
862 return AFSCONF_NOTFOUND; /* service not found */
864 for(i=0;i<acellInfo->numServers;i++) {
865 acellInfo->hostAddr[i].sin_port = tservice;
868 acellInfo->timeout = 0;
875 return afsconf_GetAfsdbInfo(tcell, aservice, acellInfo);
877 return AFSCONF_NOTFOUND;
878 #endif /* AFS_AFSDB_ENV */
882 afsconf_GetLocalCell(adir, aname, alen)
883 register struct afsconf_dir *adir;
886 static int afsconf_showcell = 0;
893 * If a cell switch was specified in a command, then it should override the
894 * AFSCELL variable. If a cell was specified, then the afsconf_SawCell flag
895 * is set and the cell name in the adir structure is used.
896 * Read the AFSCELL var each time: in case it changes (unsetenv AFSCELL).
898 if ( !afsconf_SawCell && (afscell_path= getenv("AFSCELL")) ) {
899 if ( !afsconf_showcell ) {
900 fprintf(stderr, "Note: Operation is performed on cell %s\n", afscell_path);
901 afsconf_showcell = 1;
903 strncpy(aname, afscell_path, alen);
906 if (adir->cellName) {
907 strncpy(aname, adir->cellName, alen);
909 else code = AFSCONF_UNKNOWN;
917 struct afsconf_dir *adir; {
919 afsconf_CloseInternal(adir);
920 if (adir->name) free(adir->name);
926 static int afsconf_CloseInternal(adir)
927 register struct afsconf_dir *adir; {
928 register struct afsconf_entry *td, *nd;
929 register char *tname;
931 tname = adir->name; /* remember name, since that's all we preserve */
933 /* free everything we can find */
934 if (adir->cellName) free(adir->cellName);
935 for(td=adir->entries;td;td=nd) {
937 if (td->cellInfo.linkedCell)
938 free(td->cellInfo.linkedCell);
941 if (adir->keystr) free(adir->keystr);
944 memset(adir, 0, sizeof(struct afsconf_dir));
945 adir->name = tname; /* restore it */
949 static int afsconf_Reopen(adir)
950 register struct afsconf_dir *adir; {
951 register afs_int32 code;
952 code = afsconf_CloseInternal(adir);
953 if (code) return code;
954 code = afsconf_OpenInternal(adir, 0, 0);
958 /* called during opening of config file */
959 afsconf_IntGetKeys(adir)
960 struct afsconf_dir *adir;
964 struct afsconf_keys *tstr;
965 register afs_int32 code;
968 /* NT client config dir has no KeyFile; don't risk attempting open
969 * because there might be a random file of this name if dir is shared.
971 if (IsClientConfigDirectory(adir->name)) {
972 adir->keystr = ((struct afsconf_keys *)
973 malloc(sizeof(struct afsconf_keys)));
974 adir->keystr->nkeys = 0;
977 #endif /* AFS_NT40_ENV */
980 /* compute the key name and other setup */
982 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
983 tstr = (struct afsconf_keys *) malloc(sizeof (struct afsconf_keys));
987 fd = open(tbuffer, O_RDONLY);
993 code = read(fd, tstr, sizeof(struct afsconf_keys));
995 if (code < sizeof(afs_int32)) {
1001 /* convert key structure to host order */
1002 tstr->nkeys = ntohl(tstr->nkeys);
1003 for(fd=0;fd<tstr->nkeys;fd++)
1004 tstr->key[fd].kvno = ntohl(tstr->key[fd].kvno);
1010 /* get keys structure */
1011 afsconf_GetKeys(adir, astr)
1012 struct afsconf_dir *adir;
1013 struct afsconf_keys *astr;
1015 register afs_int32 code;
1018 code = afsconf_Check(adir);
1020 return AFSCONF_FAILURE;
1021 memcpy(astr, adir->keystr, sizeof(struct afsconf_keys));
1026 /* get latest key */
1027 afs_int32 afsconf_GetLatestKey(adir, avno, akey)
1028 IN struct afsconf_dir *adir;
1029 OUT afs_int32 *avno;
1034 register struct afsconf_key *tk;
1035 register afs_int32 best;
1036 struct afsconf_key *bestk;
1037 register afs_int32 code;
1040 code = afsconf_Check(adir);
1042 return AFSCONF_FAILURE;
1043 maxa = adir->keystr->nkeys;
1045 best = -1; /* highest kvno we've seen yet */
1046 bestk = (struct afsconf_key *) 0; /* ptr to structure providing best */
1047 for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
1048 if (tk->kvno == 999) continue; /* skip bcrypt keys */
1049 if (tk->kvno > best) {
1054 if (bestk) { /* found any */
1055 if (akey) memcpy(akey, bestk->key, 8); /* copy out latest key */
1056 if (avno) *avno = bestk->kvno; /* and kvno to caller */
1061 return AFSCONF_NOTFOUND; /* didn't find any keys */
1064 /* get a particular key */
1065 afsconf_GetKey(adir, avno, akey)
1066 struct afsconf_dir *adir;
1070 register int i, maxa;
1071 register struct afsconf_key *tk;
1072 register afs_int32 code;
1075 code = afsconf_Check(adir);
1077 return AFSCONF_FAILURE;
1078 maxa = adir->keystr->nkeys;
1080 for(tk = adir->keystr->key,i=0;i<maxa;i++,tk++) {
1081 if (tk->kvno == avno) {
1082 memcpy(akey, tk->key, 8);
1089 return AFSCONF_NOTFOUND;
1092 /* save the key structure in the appropriate file */
1093 static SaveKeys(adir)
1094 struct afsconf_dir *adir;
1096 struct afsconf_keys tkeys;
1098 register afs_int32 i;
1101 memcpy(&tkeys, adir->keystr, sizeof(struct afsconf_keys));
1103 /* convert it to net byte order */
1104 for(i = 0; i<tkeys.nkeys; i++ )
1105 tkeys.key[i].kvno = htonl(tkeys.key[i].kvno);
1106 tkeys.nkeys = htonl(tkeys.nkeys);
1108 /* rewrite keys file */
1109 strcompose(tbuffer, 256, adir->name, "/", AFSDIR_KEY_FILE, NULL);
1110 fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0600);
1111 if (fd < 0) return AFSCONF_FAILURE;
1112 i = write(fd, &tkeys, sizeof(tkeys));
1113 if (i != sizeof(tkeys)) {
1115 return AFSCONF_FAILURE;
1117 if (close(fd) < 0) return AFSCONF_FAILURE;
1121 afsconf_AddKey(adir, akvno, akey, overwrite)
1122 struct afsconf_dir *adir;
1123 afs_int32 akvno, overwrite;
1126 register struct afsconf_keys *tk;
1127 register struct afsconf_key *tkey;
1128 register afs_int32 i;
1135 if (akvno < 0 || akvno > 255) {
1141 for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
1142 if (tkey->kvno == akvno) {
1145 return AFSCONF_KEYINUSE;
1152 if (tk->nkeys >= AFSCONF_MAXKEYS) {
1154 return AFSCONF_FULL;
1156 tkey = &tk->key[tk->nkeys++];
1159 memcpy(tkey->key, akey, 8);
1161 afsconf_Touch(adir);
1166 /* this proc works by sliding the other guys down, rather than using a funny
1167 kvno value, so that callers can count on getting a good key in key[0].
1169 afsconf_DeleteKey(adir, akvno)
1170 struct afsconf_dir *adir;
1173 register struct afsconf_keys *tk;
1174 register struct afsconf_key *tkey;
1181 for(i=0, tkey = tk->key; i<tk->nkeys; i++, tkey++) {
1182 if (tkey->kvno == akvno) {
1189 return AFSCONF_NOTFOUND;
1192 /* otherwise slide the others down. i and tkey point at the guy to delete */
1193 for(;i<tk->nkeys-1; i++,tkey++) {
1194 tkey->kvno = (tkey+1)->kvno;
1195 memcpy(tkey->key, (tkey+1)->key, 8);
1199 afsconf_Touch(adir);