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