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