bootparamd.c revision 1.11 1 /* $NetBSD: bootparamd.c,v 1.11 1996/12/08 13:53:25 mycroft Exp $ */
2
3 /*
4 * This code is not copyright, and is placed in the public domain.
5 * Feel free to use and modify. Please send modifications and/or
6 * suggestions + bug fixes to Klas Heggemann <klas (at) nada.kth.se>
7 *
8 * Various small changes by Theo de Raadt <deraadt (at) fsa.ca>
9 * Parser rewritten (adding YP support) by Roland McGrath <roland (at) frob.com>
10 */
11
12 #include <sys/types.h>
13 #include <sys/ioctl.h>
14 #include <sys/stat.h>
15 #include <sys/socket.h>
16
17 #include <ctype.h>
18 #include <err.h>
19 #include <netdb.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <syslog.h>
23
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26
27 #include <rpc/rpc.h>
28 #include <rpcsvc/bootparam_prot.h>
29
30 #include "pathnames.h"
31
32 #define MAXLEN 800
33
34 static char hostname[MAX_MACHINE_NAME];
35 static char askname[MAX_MACHINE_NAME];
36 static char domain_name[MAX_MACHINE_NAME];
37
38 extern void bootparamprog_1 __P((struct svc_req *, SVCXPRT *));
39
40 int _rpcsvcdirty = 0;
41 int _rpcpmstart = 0;
42 int debug = 0;
43 int dolog = 0;
44 unsigned long route_addr, inet_addr();
45 struct sockaddr_in my_addr;
46 extern char *__progname;
47 char *bootpfile = _PATH_BOOTPARAMS;
48
49 extern char *optarg;
50 extern int optind;
51
52 void
53 usage()
54 {
55 fprintf(stderr,
56 "usage: rpc.bootparamd [-d] [-s] [-r router] [-f bootparmsfile]\n");
57 exit(1);
58 }
59
60
61 /*
62 * ever familiar
63 */
64 int
65 main(argc, argv)
66 int argc;
67 char **argv;
68 {
69 SVCXPRT *transp;
70 struct hostent *he;
71 struct stat buf;
72 int c;
73
74 while ((c = getopt(argc, argv, "dsr:f:")) != -1)
75 switch (c) {
76 case 'd':
77 debug = 1;
78 break;
79 case 'r':
80 if (isdigit(*optarg)) {
81 route_addr = inet_addr(optarg);
82 break;
83 }
84 he = gethostbyname(optarg);
85 if (!he) {
86 warnx("no such host: %s\n", optarg);
87 usage();
88 }
89 bcopy(he->h_addr, (char *) &route_addr, sizeof(route_addr));
90 break;
91 case 'f':
92 bootpfile = optarg;
93 break;
94 case 's':
95 dolog = 1;
96 #ifndef LOG_DAEMON
97 openlog(__progname, 0, 0);
98 #else
99 openlog(__progname, 0, LOG_DAEMON);
100 setlogmask(LOG_UPTO(LOG_NOTICE));
101 #endif
102 break;
103 default:
104 usage();
105 }
106
107 if (stat(bootpfile, &buf))
108 err(1, "%s", bootpfile);
109
110 if (!route_addr) {
111 get_myaddress(&my_addr);
112 bcopy(&my_addr.sin_addr.s_addr, &route_addr, sizeof(route_addr));
113 }
114 if (!debug) {
115 if (daemon(0, 0))
116 err(1, "can't detach from terminal");
117 }
118
119 (void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS);
120
121 transp = svcudp_create(RPC_ANYSOCK);
122 if (transp == NULL)
123 errx(1, "can't create udp service");
124
125 if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, bootparamprog_1,
126 IPPROTO_UDP))
127 errx(1, "unable to register BOOTPARAMPROG version %d, udp",
128 BOOTPARAMVERS);
129
130 svc_run();
131 errx(1, "svc_run returned");
132 }
133
134 bp_whoami_res *
135 bootparamproc_whoami_1_svc(whoami, rqstp)
136 bp_whoami_arg *whoami;
137 struct svc_req *rqstp;
138 {
139 static bp_whoami_res res;
140 struct hostent *he;
141 struct in_addr inaddr;
142 long haddr;
143
144 if (debug)
145 warnx("whoami got question for %d.%d.%d.%d\n",
146 255 & whoami->client_address.bp_address_u.ip_addr.net,
147 255 & whoami->client_address.bp_address_u.ip_addr.host,
148 255 & whoami->client_address.bp_address_u.ip_addr.lh,
149 255 & whoami->client_address.bp_address_u.ip_addr.impno);
150 if (dolog)
151 syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d\n",
152 255 & whoami->client_address.bp_address_u.ip_addr.net,
153 255 & whoami->client_address.bp_address_u.ip_addr.host,
154 255 & whoami->client_address.bp_address_u.ip_addr.lh,
155 255 & whoami->client_address.bp_address_u.ip_addr.impno);
156
157 bcopy((char *) &whoami->client_address.bp_address_u.ip_addr, (char *) &haddr,
158 sizeof(haddr));
159 he = gethostbyaddr((char *) &haddr, sizeof(haddr), AF_INET);
160 if (he)
161 strcpy(askname, he->h_name);
162 else {
163 inaddr.s_addr = haddr;
164 strcpy(askname, inet_ntoa(inaddr));
165 }
166
167 if (debug)
168 warnx("This is host %s\n", askname);
169 if (dolog)
170 syslog(LOG_NOTICE, "This is host %s\n", askname);
171
172 if (!lookup_bootparam(askname, hostname, NULL, NULL, NULL)) {
173 res.client_name = hostname;
174 getdomainname(domain_name, MAX_MACHINE_NAME);
175 res.domain_name = domain_name;
176
177 if (res.router_address.address_type != IP_ADDR_TYPE) {
178 res.router_address.address_type = IP_ADDR_TYPE;
179 bcopy(&route_addr, &res.router_address.bp_address_u.ip_addr, 4);
180 }
181 if (debug)
182 warnx("Returning %s %s %d.%d.%d.%d\n",
183 res.client_name, res.domain_name,
184 255 & res.router_address.bp_address_u.ip_addr.net,
185 255 & res.router_address.bp_address_u.ip_addr.host,
186 255 & res.router_address.bp_address_u.ip_addr.lh,
187 255 & res.router_address.bp_address_u.ip_addr.impno);
188 if (dolog)
189 syslog(LOG_NOTICE, "Returning %s %s %d.%d.%d.%d\n",
190 res.client_name, res.domain_name,
191 255 & res.router_address.bp_address_u.ip_addr.net,
192 255 & res.router_address.bp_address_u.ip_addr.host,
193 255 & res.router_address.bp_address_u.ip_addr.lh,
194 255 & res.router_address.bp_address_u.ip_addr.impno);
195
196 return (&res);
197 }
198 if (debug)
199 warnx("whoami failed\n");
200 if (dolog)
201 syslog(LOG_NOTICE, "whoami failed\n");
202 return (NULL);
203 }
204
205
206 bp_getfile_res *
207 bootparamproc_getfile_1_svc(getfile, rqstp)
208 bp_getfile_arg *getfile;
209 struct svc_req *rqstp;
210 {
211 static bp_getfile_res res;
212 struct hostent *he;
213 int err;
214
215 if (debug)
216 warnx("getfile got question for \"%s\" and file \"%s\"\n",
217 getfile->client_name, getfile->file_id);
218
219 if (dolog)
220 syslog(LOG_NOTICE, "getfile got question for \"%s\" and file \"%s\"\n",
221 getfile->client_name, getfile->file_id);
222
223 he = NULL;
224 he = gethostbyname(getfile->client_name);
225 if (!he)
226 goto failed;
227
228 strcpy(askname, he->h_name);
229 err = lookup_bootparam(askname, NULL, getfile->file_id,
230 &res.server_name, &res.server_path);
231 if (err == 0) {
232 he = gethostbyname(res.server_name);
233 if (!he)
234 goto failed;
235 bcopy(he->h_addr, &res.server_address.bp_address_u.ip_addr, 4);
236 res.server_address.address_type = IP_ADDR_TYPE;
237 } else if (err == ENOENT && !strcmp(getfile->file_id, "dump")) {
238 /* Special for dump, answer with null strings. */
239 res.server_name[0] = '\0';
240 res.server_path[0] = '\0';
241 bzero(&res.server_address.bp_address_u.ip_addr, 4);
242 } else {
243 failed:
244 if (debug)
245 warnx("getfile failed for %s\n",
246 getfile->client_name);
247 if (dolog)
248 syslog(LOG_NOTICE,
249 "getfile failed for %s\n", getfile->client_name);
250 return (NULL);
251 }
252
253 if (debug)
254 warnx(
255 "returning server:%s path:%s address: %d.%d.%d.%d\n",
256 res.server_name, res.server_path,
257 255 & res.server_address.bp_address_u.ip_addr.net,
258 255 & res.server_address.bp_address_u.ip_addr.host,
259 255 & res.server_address.bp_address_u.ip_addr.lh,
260 255 & res.server_address.bp_address_u.ip_addr.impno);
261 if (dolog)
262 syslog(LOG_NOTICE,
263 "returning server:%s path:%s address: %d.%d.%d.%d\n",
264 res.server_name, res.server_path,
265 255 & res.server_address.bp_address_u.ip_addr.net,
266 255 & res.server_address.bp_address_u.ip_addr.host,
267 255 & res.server_address.bp_address_u.ip_addr.lh,
268 255 & res.server_address.bp_address_u.ip_addr.impno);
269 return (&res);
270 }
271
272
273 int
274 lookup_bootparam(client, client_canonical, id, server, path)
275 char *client;
276 char *client_canonical;
277 char *id;
278 char **server;
279 char **path;
280 {
281 FILE *f = fopen(bootpfile, "r");
282 #ifdef YP
283 static char *ypbuf = NULL;
284 static int ypbuflen = 0;
285 #endif
286 static char buf[BUFSIZ];
287 char *bp, *word;
288 size_t idlen = id == NULL ? 0 : strlen(id);
289 int contin = 0;
290 int found = 0;
291
292 if (f == NULL)
293 return EINVAL; /* ? */
294
295 while (fgets(buf, sizeof buf, f)) {
296 int wascontin = contin;
297 contin = buf[strlen(buf) - 2] == '\\';
298 bp = buf + strspn(buf, " \t\n");
299
300 switch (wascontin) {
301 case -1:
302 /* Continuation of uninteresting line */
303 contin *= -1;
304 continue;
305 case 0:
306 /* New line */
307 contin *= -1;
308 if (*bp == '#')
309 continue;
310 if ((word = strsep(&bp, " \t\n")) == NULL)
311 continue;
312 #ifdef YP
313 /* A + in the file means try YP now */
314 if (!strcmp(word, "+")) {
315 char *ypdom;
316
317 if (yp_get_default_domain(&ypdom) ||
318 yp_match(ypdom, "bootparams", client,
319 strlen(client), &ypbuf, &ypbuflen))
320 continue;
321 bp = ypbuf;
322 word = client;
323 contin *= -1;
324 break;
325 }
326 #endif
327 /* See if this line's client is the one we are
328 * looking for */
329 if (strcasecmp(word, client) != 0) {
330 /*
331 * If it didn't match, try getting the
332 * canonical host name of the client
333 * on this line and comparing that to
334 * the client we are looking for
335 */
336 struct hostent *hp = gethostbyname(word);
337 if (hp == NULL ||
338 strcasecmp(hp->h_name, client))
339 continue;
340 }
341 contin *= -1;
342 break;
343 case 1:
344 /* Continued line we want to parse below */
345 break;
346 }
347
348 if (client_canonical)
349 strncpy(client_canonical, word, MAX_MACHINE_NAME);
350
351 /* We have found a line for CLIENT */
352 if (id == NULL) {
353 (void) fclose(f);
354 return 0;
355 }
356
357 /* Look for a value for the parameter named by ID */
358 while ((word = strsep(&bp, " \t\n")) != NULL) {
359 if (!strncmp(word, id, idlen) && word[idlen] == '=') {
360 /* We have found the entry we want */
361 *server = &word[idlen + 1];
362 *path = strchr(*server, ':');
363 if (*path == NULL)
364 /* Malformed entry */
365 continue;
366 *(*path)++ = '\0';
367 (void) fclose(f);
368 return 0;
369 }
370 }
371
372 found = 1;
373 }
374
375 (void) fclose(f);
376 return found ? ENOENT : EPERM;
377 }
378