avoid writing loopback addresses into CellServDB
[openafs.git] / src / auth / writeconfig.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14 #include <afs/opr.h>
15
16 #include <afs/pthread_glock.h>
17 #include <afs/afsutil.h>
18 #include <rx/rxkad.h>
19
20 #include "cellconfig.h"
21 #include "keys.h"
22
23 /* write ThisCell and CellServDB containing exactly one cell's info specified
24     by acellInfo parm.   Useful only on the server (which describes only one cell).
25 */
26
27 static int
28 VerifyEntries(struct afsconf_cell *aci)
29 {
30     int i;
31     struct hostent *th;
32
33     for (i = 0; i < aci->numServers; i++) {
34         if (aci->hostAddr[i].sin_addr.s_addr == 0) {
35             /* no address spec'd */
36             if (*(aci->hostName[i]) != 0) {
37                 int code;
38                 struct addrinfo hints;
39                 struct addrinfo *result;
40                 struct addrinfo *rp;
41
42                 memset(&hints, 0, sizeof(struct addrinfo));
43                 hints.ai_family = AF_INET;
44                 hints.ai_socktype = SOCK_DGRAM;
45
46                 code = getaddrinfo(aci->hostName[i], NULL, &hints, &result);
47                 if (code) {
48                     return AFSCONF_FAILURE;
49                 }
50                 for (rp = result; rp != NULL; rp = rp->ai_next) {
51                     struct sockaddr_in *sa = (struct sockaddr_in *)rp->ai_addr;
52                     if (!rx_IsLoopbackAddr(ntohl(sa->sin_addr.s_addr))) {
53                         aci->hostAddr[i].sin_addr.s_addr = sa->sin_addr.s_addr;
54                         break;
55                     }
56                 }
57                 freeaddrinfo(result);
58                 if (aci->hostAddr[i].sin_addr.s_addr == 0) {
59                     return AFSCONF_FAILURE;
60                 }
61             }
62             /* otherwise we're deleting this entry */
63         } else {
64             /* address spec'd, perhaps no name known */
65             if (aci->hostName[i][0] != 0)
66                 continue;       /* name known too */
67             /* figure out name, if possible */
68             th = gethostbyaddr((char *)(&aci->hostAddr[i].sin_addr), 4,
69                                AF_INET);
70             if (!th) {
71                 strcpy(aci->hostName[i], "UNKNOWNHOST");
72             } else {
73                 if (strlcpy(aci->hostName[i],
74                             th->h_name,
75                             sizeof(aci->hostName[i]))
76                         >= sizeof(aci->hostName[i])) {
77                    strcpy(aci->hostName[i], "UNKNOWNHOST");
78                 }
79             }
80         }
81     }
82     return 0;
83 }
84
85 /* Changed the interface to accept the afsconf_dir datastructure.
86    This is a handle to the internal cache that is maintained by the bosserver.
87    */
88
89 int
90 afsconf_SetCellInfo(struct afsconf_dir *adir, const char *apath,
91                     struct afsconf_cell *acellInfo)
92 {
93     afs_int32 code;
94
95     code = afsconf_SetExtendedCellInfo(adir, apath, acellInfo, NULL);
96     return code;
97 }
98
99 int
100 afsconf_SetExtendedCellInfo(struct afsconf_dir *adir,
101                             const char *apath,
102                             struct afsconf_cell *acellInfo, char clones[])
103 {
104     afs_int32 code;
105     int fd;
106     char tbuffer[1024];
107     FILE *tf;
108     afs_int32 i;
109
110     LOCK_GLOBAL_MUTEX;
111     /* write ThisCell file */
112     strcompose(tbuffer, 1024, apath, "/", AFSDIR_THISCELL_FILE, (char *)NULL);
113
114     fd = open(tbuffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
115     if (fd < 0) {
116         UNLOCK_GLOBAL_MUTEX;
117         return errno;
118     }
119     i = (int)strlen(acellInfo->name);
120     code = write(fd, acellInfo->name, i);
121     if (code != i) {
122         UNLOCK_GLOBAL_MUTEX;
123         return AFSCONF_FAILURE;
124     }
125     if (close(fd) < 0) {
126         UNLOCK_GLOBAL_MUTEX;
127         return errno;
128     }
129
130     /* make sure we have both name and address for each host, looking up other
131      * if need be */
132     code = VerifyEntries(acellInfo);
133     if (code) {
134         UNLOCK_GLOBAL_MUTEX;
135         return code;
136     }
137
138     /* write CellServDB */
139     strcompose(tbuffer, 1024, apath, "/", AFSDIR_CELLSERVDB_FILE, (char *)NULL);
140     tf = fopen(tbuffer, "w");
141     if (!tf) {
142         UNLOCK_GLOBAL_MUTEX;
143         return AFSCONF_NOTFOUND;
144     }
145     fprintf(tf, ">%s    #Cell name\n", acellInfo->name);
146     for (i = 0; i < acellInfo->numServers; i++) {
147         code = acellInfo->hostAddr[i].sin_addr.s_addr;  /* net order */
148         if (code == 0)
149             continue;           /* delete request */
150         code = ntohl(code);     /* convert to host order */
151         if (clones && clones[i])
152             fprintf(tf, "[%d.%d.%d.%d]  #%s\n", (code >> 24) & 0xff,
153                     (code >> 16) & 0xff, (code >> 8) & 0xff, code & 0xff,
154                     acellInfo->hostName[i]);
155         else
156             fprintf(tf, "%d.%d.%d.%d    #%s\n", (code >> 24) & 0xff,
157                     (code >> 16) & 0xff, (code >> 8) & 0xff, code & 0xff,
158                     acellInfo->hostName[i]);
159     }
160     if (ferror(tf)) {
161         fclose(tf);
162         UNLOCK_GLOBAL_MUTEX;
163         return AFSCONF_FAILURE;
164     }
165     code = fclose(tf);
166
167     /* Reset the timestamp in the cache, so that
168      * the CellServDB is read into the cache next time.
169      * Resolves the lost update problem due to an inconsistent cache
170      */
171     if (adir)
172         adir->timeRead = 0;
173
174     UNLOCK_GLOBAL_MUTEX;
175     if (code == EOF)
176         return AFSCONF_FAILURE;
177     return 0;
178 }