GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/rpc.bootparamd/bootparamd.c Lines: 0 165 0.0 %
Date: 2017-11-07 Branches: 0 105 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: bootparamd.c,v 1.21 2016/10/16 10:40:58 jca 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
 */
10
11
#include <sys/types.h>
12
#include <sys/ioctl.h>
13
#include <sys/stat.h>
14
#include <sys/socket.h>
15
16
#include <rpc/rpc.h>
17
#include <rpcsvc/bootparam_prot.h>
18
#include <rpcsvc/ypclnt.h>
19
#include <rpcsvc/yp_prot.h>
20
#include <arpa/inet.h>
21
22
#include <stdio.h>
23
#include <netdb.h>
24
#include <ctype.h>
25
#include <syslog.h>
26
#include <string.h>
27
#include <unistd.h>
28
#include <err.h>
29
#include <stdlib.h>
30
31
#include "pathnames.h"
32
33
#define MAXLEN 800
34
35
struct hostent *he;
36
static char hostname[MAX_MACHINE_NAME];
37
static char askname[MAX_MACHINE_NAME];
38
static char domain_name[MAX_MACHINE_NAME];
39
40
extern void bootparamprog_1(struct svc_req *, SVCXPRT *);
41
int lookup_bootparam(char *client, char *client_canonical, char *id,
42
    char **server, char **path);
43
44
int	_rpcsvcdirty = 0;
45
int	_rpcpmstart = 0;
46
int	debug = 0;
47
int	dolog = 0;
48
struct in_addr route_addr;
49
struct sockaddr_in my_addr;
50
extern char *__progname;
51
char   *bootpfile = _PATH_BOOTPARAMS;
52
53
extern char *optarg;
54
extern int optind;
55
56
static void
57
usage(void)
58
{
59
	extern char *__progname;
60
	fprintf(stderr, "usage: %s [-ds] [-f file] [-r router]\n",
61
	    __progname);
62
	exit(1);
63
}
64
65
/*
66
 * ever familiar
67
 */
68
int
69
main(int argc, char *argv[])
70
{
71
	struct hostent *he;
72
	struct stat buf;
73
	SVCXPRT *transp;
74
	int    c;
75
76
	while ((c = getopt(argc, argv, "dsr:f:")) != -1)
77
		switch (c) {
78
		case 'd':
79
			debug = 1;
80
			break;
81
		case 'r':
82
			if (inet_aton(optarg, &route_addr) == 1)
83
				break;
84
			he = gethostbyname(optarg);
85
			if (!he) {
86
				warnx("no such host: %s", optarg);
87
				usage();
88
			}
89
			bcopy(he->h_addr, &route_addr.s_addr,
90
			    sizeof(route_addr.s_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
		}
107
108
	if (stat(bootpfile, &buf))
109
		err(1, "%s", bootpfile);
110
111
	if (!route_addr.s_addr) {
112
		get_myaddress(&my_addr);
113
		bcopy(&my_addr.sin_addr.s_addr, &route_addr.s_addr,
114
		    sizeof(route_addr.s_addr));
115
	}
116
	if (!debug) {
117
		if (daemon(0, 0))
118
			err(1, "can't detach from terminal");
119
	}
120
121
	(void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS);
122
123
	transp = svcudp_create(RPC_ANYSOCK);
124
	if (transp == NULL)
125
		errx(1, "can't create udp service");
126
127
	if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, bootparamprog_1,
128
	    IPPROTO_UDP))
129
		errx(1, "unable to register BOOTPARAMPROG version %ld, udp",
130
		    BOOTPARAMVERS);
131
132
	if (pledge("stdio rpath dns flock cpath wpath", NULL) == -1)
133
		err(1, "pledge");
134
135
	svc_run();
136
	errx(1, "svc_run returned");
137
}
138
139
bp_whoami_res *
140
bootparamproc_whoami_1_svc(bp_whoami_arg *whoami, struct svc_req *rqstp)
141
{
142
	in_addr_t haddr;
143
	static bp_whoami_res res;
144
145
	if (debug)
146
		warnx("whoami got question for %d.%d.%d.%d",
147
		    255 & whoami->client_address.bp_address_u.ip_addr.net,
148
		    255 & whoami->client_address.bp_address_u.ip_addr.host,
149
		    255 & whoami->client_address.bp_address_u.ip_addr.lh,
150
		    255 & whoami->client_address.bp_address_u.ip_addr.impno);
151
	if (dolog)
152
		syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d",
153
		    255 & whoami->client_address.bp_address_u.ip_addr.net,
154
		    255 & whoami->client_address.bp_address_u.ip_addr.host,
155
		    255 & whoami->client_address.bp_address_u.ip_addr.lh,
156
		    255 & whoami->client_address.bp_address_u.ip_addr.impno);
157
158
	bcopy(&whoami->client_address.bp_address_u.ip_addr,
159
	    &haddr, sizeof(haddr));
160
	he = gethostbyaddr(&haddr, sizeof(haddr), AF_INET);
161
	if (!he)
162
		goto failed;
163
164
	if (debug)
165
		warnx("This is host %s", he->h_name);
166
	if (dolog)
167
		syslog(LOG_NOTICE, "This is host %s", he->h_name);
168
169
	strlcpy(askname, he->h_name, sizeof askname);
170
	if (!lookup_bootparam(askname, hostname, NULL, NULL, NULL)) {
171
		res.client_name = hostname;
172
		getdomainname(domain_name, MAX_MACHINE_NAME);
173
		res.domain_name = domain_name;
174
175
		if (res.router_address.address_type != IP_ADDR_TYPE) {
176
			res.router_address.address_type = IP_ADDR_TYPE;
177
			bcopy(&route_addr.s_addr,
178
			    &res.router_address.bp_address_u.ip_addr, 4);
179
		}
180
		if (debug)
181
			warnx("Returning %s   %s    %d.%d.%d.%d",
182
			    res.client_name, res.domain_name,
183
			    255 & res.router_address.bp_address_u.ip_addr.net,
184
			    255 & res.router_address.bp_address_u.ip_addr.host,
185
			    255 & res.router_address.bp_address_u.ip_addr.lh,
186
			    255 & res.router_address.bp_address_u.ip_addr.impno);
187
		if (dolog)
188
			syslog(LOG_NOTICE, "Returning %s   %s    %d.%d.%d.%d",
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
		return (&res);
195
	}
196
failed:
197
	if (debug)
198
		warnx("whoami failed");
199
	if (dolog)
200
		syslog(LOG_NOTICE, "whoami failed");
201
	return (NULL);
202
}
203
204
205
bp_getfile_res *
206
bootparamproc_getfile_1_svc(bp_getfile_arg *getfile, struct svc_req *rqstp)
207
{
208
	static bp_getfile_res res;
209
	int error;
210
211
	if (debug)
212
		warnx("getfile got question for \"%s\" and file \"%s\"",
213
		    getfile->client_name, getfile->file_id);
214
215
	if (dolog)
216
		syslog(LOG_NOTICE,
217
		    "getfile got question for \"%s\" and file \"%s\"",
218
		    getfile->client_name, getfile->file_id);
219
220
	he = NULL;
221
	he = gethostbyname(getfile->client_name);
222
	if (!he)
223
		goto failed;
224
225
	strlcpy(askname, he->h_name, sizeof askname);
226
	error = lookup_bootparam(askname, NULL, getfile->file_id,
227
	    &res.server_name, &res.server_path);
228
	if (error == 0) {
229
		he = gethostbyname(res.server_name);
230
		if (!he)
231
			goto failed;
232
		bcopy(he->h_addr, &res.server_address.bp_address_u.ip_addr, 4);
233
		res.server_address.address_type = IP_ADDR_TYPE;
234
	} else if (error == ENOENT && !strcmp(getfile->file_id, "dump")) {
235
		/* Special for dump, answer with null strings. */
236
		res.server_name[0] = '\0';
237
		res.server_path[0] = '\0';
238
		bzero(&res.server_address.bp_address_u.ip_addr, 4);
239
	} else {
240
failed:
241
		if (debug)
242
			warnx("getfile failed for %s", getfile->client_name);
243
		if (dolog)
244
			syslog(LOG_NOTICE,
245
			    "getfile failed for %s", getfile->client_name);
246
		return (NULL);
247
	}
248
249
	if (debug)
250
		warnx("returning server:%s path:%s address: %d.%d.%d.%d",
251
		    res.server_name, res.server_path,
252
		    255 & res.server_address.bp_address_u.ip_addr.net,
253
		    255 & res.server_address.bp_address_u.ip_addr.host,
254
		    255 & res.server_address.bp_address_u.ip_addr.lh,
255
		    255 & res.server_address.bp_address_u.ip_addr.impno);
256
	if (dolog)
257
		syslog(LOG_NOTICE,
258
		    "returning server:%s path:%s address: %d.%d.%d.%d",
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
	return (&res);
265
}
266
267
int
268
lookup_bootparam(char *client, char *client_canonical, char *id,
269
    char **server, char **path)
270
{
271
	FILE   *f;
272
	static char buf[BUFSIZ];
273
	char   *bp, *word = NULL;
274
	size_t  idlen = id == NULL ? 0 : strlen(id);
275
	int	contin = 0, found = 0;
276
277
	f = fopen(bootpfile, "r");
278
	if (f == NULL)
279
		return EINVAL;	/* ? */
280
281
	while (fgets(buf, sizeof buf, f)) {
282
		int	wascontin = contin;
283
284
		contin = buf[strlen(buf) - 2] == '\\';
285
		bp = buf + strspn(buf, " \t\n");
286
287
		switch (wascontin) {
288
		case -1:
289
			/* Continuation of uninteresting line */
290
			contin *= -1;
291
			continue;
292
		case 0:
293
			/* New line */
294
			contin *= -1;
295
			if (*bp == '#')
296
				continue;
297
			if ((word = strsep(&bp, " \t\n")) == NULL)
298
				continue;
299
			/* See if this line's client is the one we are
300
			 * looking for */
301
			if (strcasecmp(word, client) != 0) {
302
				/*
303
				 * If it didn't match, try getting the
304
				 * canonical host name of the client
305
				 * on this line and comparing that to
306
				 * the client we are looking for
307
				 */
308
				struct hostent *hp = gethostbyname(word);
309
				if (hp == NULL || strcasecmp(hp->h_name, client))
310
					continue;
311
			}
312
			contin *= -1;
313
			break;
314
		case 1:
315
			/* Continued line we want to parse below */
316
			break;
317
		}
318
319
		if (client_canonical)
320
			strlcpy(client_canonical, word, MAX_MACHINE_NAME);
321
322
		/* We have found a line for CLIENT */
323
		if (id == NULL) {
324
			(void) fclose(f);
325
			return 0;
326
		}
327
328
		/* Look for a value for the parameter named by ID */
329
		while ((word = strsep(&bp, " \t\n")) != NULL) {
330
			if (!strncmp(word, id, idlen) && word[idlen] == '=') {
331
				/* We have found the entry we want */
332
				*server = &word[idlen + 1];
333
				*path = strchr(*server, ':');
334
				if (*path == NULL)
335
					/* Malformed entry */
336
					continue;
337
				*(*path)++ = '\0';
338
				(void) fclose(f);
339
				return 0;
340
			}
341
		}
342
343
		found = 1;
344
	}
345
346
	(void) fclose(f);
347
	return found ? ENOENT : EPERM;
348
}