GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/dhclient/options.c Lines: 0 304 0.0 %
Date: 2017-11-13 Branches: 0 187 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: options.c,v 1.109 2017/10/11 00:09:32 krw Exp $	*/
2
3
/* DHCP options parsing and reassembly. */
4
5
/*
6
 * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
7
 * All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 *
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of The Internet Software Consortium nor the names
19
 *    of its contributors may be used to endorse or promote products derived
20
 *    from this software without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23
 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
 * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34
 * SUCH DAMAGE.
35
 *
36
 * This software has been written for the Internet Software Consortium
37
 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38
 * Enterprises.  To learn more about the Internet Software Consortium,
39
 * see ``http://www.vix.com/isc''.  To learn more about Vixie
40
 * Enterprises, see ``http://www.vix.com''.
41
 */
42
43
#include <sys/queue.h>
44
#include <sys/socket.h>
45
46
#include <arpa/inet.h>
47
48
#include <net/if.h>
49
50
#include <netinet/in.h>
51
#include <netinet/if_ether.h>
52
53
#include <ctype.h>
54
#include <signal.h>
55
#include <stdio.h>
56
#include <stdlib.h>
57
#include <string.h>
58
#include <vis.h>
59
60
#include "dhcp.h"
61
#include "dhcpd.h"
62
#include "log.h"
63
64
int parse_option_buffer(struct option_data *, unsigned char *, int);
65
int expand_search_domain_name(unsigned char *, size_t, int *, unsigned char *);
66
67
/*
68
 * DHCP Option names, formats and codes, from RFC1533.
69
 *
70
 * Format codes:
71
 *
72
 * e - end of data
73
 * I - IP address
74
 * l - 32-bit signed integer
75
 * L - 32-bit unsigned integer
76
 * S - 16-bit unsigned integer
77
 * B - 8-bit unsigned integer
78
 * t - ASCII text
79
 * f - flag (true or false)
80
 * A - array of whatever precedes (e.g., IA means array of IP addresses)
81
 * C - CIDR description
82
 */
83
84
static const struct {
85
	char *name;
86
	char *format;
87
} dhcp_options[DHO_COUNT] = {
88
	/*   0 */ { "pad", "" },
89
	/*   1 */ { "subnet-mask", "I" },
90
	/*   2 */ { "time-offset", "l" },
91
	/*   3 */ { "routers", "IA" },
92
	/*   4 */ { "time-servers", "IA" },
93
	/*   5 */ { "ien116-name-servers", "IA" },
94
	/*   6 */ { "domain-name-servers", "IA" },
95
	/*   7 */ { "log-servers", "IA" },
96
	/*   8 */ { "cookie-servers", "IA" },
97
	/*   9 */ { "lpr-servers", "IA" },
98
	/*  10 */ { "impress-servers", "IA" },
99
	/*  11 */ { "resource-location-servers", "IA" },
100
	/*  12 */ { "host-name", "t" },
101
	/*  13 */ { "boot-size", "S" },
102
	/*  14 */ { "merit-dump", "t" },
103
	/*  15 */ { "domain-name", "t" },
104
	/*  16 */ { "swap-server", "I" },
105
	/*  17 */ { "root-path", "t" },
106
	/*  18 */ { "extensions-path", "t" },
107
	/*  19 */ { "ip-forwarding", "f" },
108
	/*  20 */ { "non-local-source-routing", "f" },
109
	/*  21 */ { "policy-filter", "IIA" },
110
	/*  22 */ { "max-dgram-reassembly", "S" },
111
	/*  23 */ { "default-ip-ttl", "B" },
112
	/*  24 */ { "path-mtu-aging-timeout", "L" },
113
	/*  25 */ { "path-mtu-plateau-table", "SA" },
114
	/*  26 */ { "interface-mtu", "S" },
115
	/*  27 */ { "all-subnets-local", "f" },
116
	/*  28 */ { "broadcast-address", "I" },
117
	/*  29 */ { "perform-mask-discovery", "f" },
118
	/*  30 */ { "mask-supplier", "f" },
119
	/*  31 */ { "router-discovery", "f" },
120
	/*  32 */ { "router-solicitation-address", "I" },
121
	/*  33 */ { "static-routes", "IIA" },
122
	/*  34 */ { "trailer-encapsulation", "f" },
123
	/*  35 */ { "arp-cache-timeout", "L" },
124
	/*  36 */ { "ieee802-3-encapsulation", "f" },
125
	/*  37 */ { "default-tcp-ttl", "B" },
126
	/*  38 */ { "tcp-keepalive-interval", "L" },
127
	/*  39 */ { "tcp-keepalive-garbage", "f" },
128
	/*  40 */ { "nis-domain", "t" },
129
	/*  41 */ { "nis-servers", "IA" },
130
	/*  42 */ { "ntp-servers", "IA" },
131
	/*  43 */ { "vendor-encapsulated-options", "X" },
132
	/*  44 */ { "netbios-name-servers", "IA" },
133
	/*  45 */ { "netbios-dd-server", "IA" },
134
	/*  46 */ { "netbios-node-type", "B" },
135
	/*  47 */ { "netbios-scope", "t" },
136
	/*  48 */ { "font-servers", "IA" },
137
	/*  49 */ { "x-display-manager", "IA" },
138
	/*  50 */ { "dhcp-requested-address", "I" },
139
	/*  51 */ { "dhcp-lease-time", "L" },
140
	/*  52 */ { "dhcp-option-overload", "B" },
141
	/*  53 */ { "dhcp-message-type", "B" },
142
	/*  54 */ { "dhcp-server-identifier", "I" },
143
	/*  55 */ { "dhcp-parameter-request-list", "BA" },
144
	/*  56 */ { "dhcp-message", "t" },
145
	/*  57 */ { "dhcp-max-message-size", "S" },
146
	/*  58 */ { "dhcp-renewal-time", "L" },
147
	/*  59 */ { "dhcp-rebinding-time", "L" },
148
	/*  60 */ { "dhcp-class-identifier", "t" },
149
	/*  61 */ { "dhcp-client-identifier", "X" },
150
	/*  62 */ { NULL, NULL },
151
	/*  63 */ { NULL, NULL },
152
	/*  64 */ { "nisplus-domain", "t" },
153
	/*  65 */ { "nisplus-servers", "IA" },
154
	/*  66 */ { "tftp-server-name", "t" },
155
	/*  67 */ { "bootfile-name", "t" },
156
	/*  68 */ { "mobile-ip-home-agent", "IA" },
157
	/*  69 */ { "smtp-server", "IA" },
158
	/*  70 */ { "pop-server", "IA" },
159
	/*  71 */ { "nntp-server", "IA" },
160
	/*  72 */ { "www-server", "IA" },
161
	/*  73 */ { "finger-server", "IA" },
162
	/*  74 */ { "irc-server", "IA" },
163
	/*  75 */ { "streettalk-server", "IA" },
164
	/*  76 */ { "streettalk-directory-assistance-server", "IA" },
165
	/*  77 */ { "user-class", "t" },
166
	/*  78 */ { NULL, NULL },
167
	/*  79 */ { NULL, NULL },
168
	/*  80 */ { NULL, NULL },
169
	/*  81 */ { NULL, NULL },
170
	/*  82 */ { "relay-agent-information", "X" },
171
	/*  83 */ { NULL, NULL },
172
	/*  84 */ { NULL, NULL },
173
	/*  85 */ { "nds-servers", "IA" },
174
	/*  86 */ { "nds-tree-name", "X" },
175
	/*  87 */ { "nds-context", "X" },
176
	/*  88 */ { NULL, NULL },
177
	/*  89 */ { NULL, NULL },
178
	/*  90 */ { NULL, NULL },
179
	/*  91 */ { NULL, NULL },
180
	/*  92 */ { NULL, NULL },
181
	/*  93 */ { NULL, NULL },
182
	/*  94 */ { NULL, NULL },
183
	/*  95 */ { NULL, NULL },
184
	/*  96 */ { NULL, NULL },
185
	/*  97 */ { NULL, NULL },
186
	/*  98 */ { NULL, NULL },
187
	/*  99 */ { NULL, NULL },
188
	/* 100 */ { NULL, NULL },
189
	/* 101 */ { NULL, NULL },
190
	/* 102 */ { NULL, NULL },
191
	/* 103 */ { NULL, NULL },
192
	/* 104 */ { NULL, NULL },
193
	/* 105 */ { NULL, NULL },
194
	/* 106 */ { NULL, NULL },
195
	/* 107 */ { NULL, NULL },
196
	/* 108 */ { NULL, NULL },
197
	/* 109 */ { NULL, NULL },
198
	/* 110 */ { NULL, NULL },
199
	/* 111 */ { NULL, NULL },
200
	/* 112 */ { NULL, NULL },
201
	/* 113 */ { NULL, NULL },
202
	/* 114 */ { NULL, NULL },
203
	/* 115 */ { NULL, NULL },
204
	/* 116 */ { NULL, NULL },
205
	/* 117 */ { NULL, NULL },
206
	/* 118 */ { NULL, NULL },
207
	/* 119 */ { "domain-search", "X" },
208
	/* 120 */ { NULL, NULL },
209
	/* 121 */ { "classless-static-routes", "CIA" },
210
	/* 122 */ { NULL, NULL },
211
	/* 123 */ { NULL, NULL },
212
	/* 124 */ { NULL, NULL },
213
	/* 125 */ { NULL, NULL },
214
	/* 126 */ { NULL, NULL },
215
	/* 127 */ { NULL, NULL },
216
	/* 128 */ { NULL, NULL },
217
	/* 129 */ { NULL, NULL },
218
	/* 130 */ { NULL, NULL },
219
	/* 131 */ { NULL, NULL },
220
	/* 132 */ { NULL, NULL },
221
	/* 133 */ { NULL, NULL },
222
	/* 134 */ { NULL, NULL },
223
	/* 135 */ { NULL, NULL },
224
	/* 136 */ { NULL, NULL },
225
	/* 137 */ { NULL, NULL },
226
	/* 138 */ { NULL, NULL },
227
	/* 139 */ { NULL, NULL },
228
	/* 140 */ { NULL, NULL },
229
	/* 141 */ { NULL, NULL },
230
	/* 142 */ { NULL, NULL },
231
	/* 143 */ { NULL, NULL },
232
	/* 144 */ { "tftp-config-file", "t" },
233
	/* 145 */ { NULL, NULL },
234
	/* 146 */ { NULL, NULL },
235
	/* 147 */ { NULL, NULL },
236
	/* 148 */ { NULL, NULL },
237
	/* 149 */ { NULL, NULL },
238
	/* 150 */ { "voip-configuration-server", "IA" },
239
	/* 151 */ { NULL, NULL },
240
	/* 152 */ { NULL, NULL },
241
	/* 153 */ { NULL, NULL },
242
	/* 154 */ { NULL, NULL },
243
	/* 155 */ { NULL, NULL },
244
	/* 156 */ { NULL, NULL },
245
	/* 157 */ { NULL, NULL },
246
	/* 158 */ { NULL, NULL },
247
	/* 159 */ { NULL, NULL },
248
	/* 160 */ { NULL, NULL },
249
	/* 161 */ { NULL, NULL },
250
	/* 162 */ { NULL, NULL },
251
	/* 163 */ { NULL, NULL },
252
	/* 164 */ { NULL, NULL },
253
	/* 165 */ { NULL, NULL },
254
	/* 166 */ { NULL, NULL },
255
	/* 167 */ { NULL, NULL },
256
	/* 168 */ { NULL, NULL },
257
	/* 169 */ { NULL, NULL },
258
	/* 170 */ { NULL, NULL },
259
	/* 171 */ { NULL, NULL },
260
	/* 172 */ { NULL, NULL },
261
	/* 173 */ { NULL, NULL },
262
	/* 174 */ { NULL, NULL },
263
	/* 175 */ { NULL, NULL },
264
	/* 176 */ { NULL, NULL },
265
	/* 177 */ { NULL, NULL },
266
	/* 178 */ { NULL, NULL },
267
	/* 179 */ { NULL, NULL },
268
	/* 180 */ { NULL, NULL },
269
	/* 181 */ { NULL, NULL },
270
	/* 182 */ { NULL, NULL },
271
	/* 183 */ { NULL, NULL },
272
	/* 184 */ { NULL, NULL },
273
	/* 185 */ { NULL, NULL },
274
	/* 186 */ { NULL, NULL },
275
	/* 187 */ { NULL, NULL },
276
	/* 188 */ { NULL, NULL },
277
	/* 189 */ { NULL, NULL },
278
	/* 190 */ { NULL, NULL },
279
	/* 191 */ { NULL, NULL },
280
	/* 192 */ { NULL, NULL },
281
	/* 193 */ { NULL, NULL },
282
	/* 194 */ { NULL, NULL },
283
	/* 195 */ { NULL, NULL },
284
	/* 196 */ { NULL, NULL },
285
	/* 197 */ { NULL, NULL },
286
	/* 198 */ { NULL, NULL },
287
	/* 199 */ { NULL, NULL },
288
	/* 200 */ { NULL, NULL },
289
	/* 201 */ { NULL, NULL },
290
	/* 202 */ { NULL, NULL },
291
	/* 203 */ { NULL, NULL },
292
	/* 204 */ { NULL, NULL },
293
	/* 205 */ { NULL, NULL },
294
	/* 206 */ { NULL, NULL },
295
	/* 207 */ { NULL, NULL },
296
	/* 208 */ { NULL, NULL },
297
	/* 209 */ { NULL, NULL },
298
	/* 210 */ { NULL, NULL },
299
	/* 211 */ { NULL, NULL },
300
	/* 212 */ { NULL, NULL },
301
	/* 213 */ { NULL, NULL },
302
	/* 214 */ { NULL, NULL },
303
	/* 215 */ { NULL, NULL },
304
	/* 216 */ { NULL, NULL },
305
	/* 217 */ { NULL, NULL },
306
	/* 218 */ { NULL, NULL },
307
	/* 219 */ { NULL, NULL },
308
	/* 220 */ { NULL, NULL },
309
	/* 221 */ { NULL, NULL },
310
	/* 222 */ { NULL, NULL },
311
	/* 223 */ { NULL, NULL },
312
	/* 224 */ { NULL, NULL },
313
	/* 225 */ { NULL, NULL },
314
	/* 226 */ { NULL, NULL },
315
	/* 227 */ { NULL, NULL },
316
	/* 228 */ { NULL, NULL },
317
	/* 229 */ { NULL, NULL },
318
	/* 230 */ { NULL, NULL },
319
	/* 231 */ { NULL, NULL },
320
	/* 232 */ { NULL, NULL },
321
	/* 233 */ { NULL, NULL },
322
	/* 234 */ { NULL, NULL },
323
	/* 235 */ { NULL, NULL },
324
	/* 236 */ { NULL, NULL },
325
	/* 237 */ { NULL, NULL },
326
	/* 238 */ { NULL, NULL },
327
	/* 239 */ { NULL, NULL },
328
	/* 240 */ { NULL, NULL },
329
	/* 241 */ { NULL, NULL },
330
	/* 242 */ { NULL, NULL },
331
	/* 243 */ { NULL, NULL },
332
	/* 244 */ { NULL, NULL },
333
	/* 245 */ { NULL, NULL },
334
	/* 246 */ { NULL, NULL },
335
	/* 247 */ { NULL, NULL },
336
	/* 248 */ { NULL, NULL },
337
	/* 249 */ { "classless-ms-static-routes", "CIA" },
338
	/* 250 */ { NULL, NULL },
339
	/* 251 */ { NULL, NULL },
340
	/* 252 */ { "autoproxy-script", "t" },
341
	/* 253 */ { NULL, NULL },
342
	/* 254 */ { NULL, NULL },
343
	/* 255 */ { "option-end", "e" },
344
};
345
346
char *
347
code_to_name(int code)
348
{
349
	static char	 unknown[11];	/* "option-NNN" */
350
	int		 ret;
351
352
	if (code < 0 || code >= DHO_COUNT)
353
		return "";
354
355
	if (dhcp_options[code].name != NULL)
356
		return dhcp_options[code].name;
357
358
	ret = snprintf(unknown, sizeof(unknown), "option-%d", code);
359
	if (ret == -1 || ret >= (int)sizeof(unknown))
360
		return "";
361
362
	return unknown;
363
}
364
365
int
366
name_to_code(char *name)
367
{
368
	char	unknown[11];	/* "option-NNN" */
369
	int	code, ret;
370
371
	for (code = 1; code < DHO_END; code++) {
372
		if (dhcp_options[code].name == NULL) {
373
			ret = snprintf(unknown, sizeof(unknown), "option-%d",
374
			    code);
375
			if (ret == -1 || ret >= (int)sizeof(unknown))
376
				return DHO_END;
377
			if (strcasecmp(unknown, name) == 0)
378
				return code;
379
		} else if (strcasecmp(dhcp_options[code].name, name) == 0) {
380
			return code;
381
		}
382
	}
383
384
	return DHO_END;
385
}
386
387
char *
388
code_to_format(int code)
389
{
390
	if (code < 0 || code >= DHO_COUNT)
391
		return "";
392
393
	if (dhcp_options[code].format == NULL)
394
		return "X";
395
396
	return dhcp_options[code].format;
397
}
398
399
/*
400
 * Parse options out of the specified buffer, storing addresses of
401
 * option values in options. Return 0 if errors, 1 if not.
402
 */
403
int
404
parse_option_buffer(struct option_data *options, unsigned char *buffer,
405
    int length)
406
{
407
	unsigned char	*s, *t, *end = buffer + length;
408
	char		*name, *fmt;
409
	int		 len, code;
410
411
	for (s = buffer; *s != DHO_END && s < end; ) {
412
		code = s[0];
413
414
		/* Pad options don't have a length - just skip them. */
415
		if (code == DHO_PAD) {
416
			s++;
417
			continue;
418
		}
419
420
		name = code_to_name(code);
421
		fmt = code_to_format(code);
422
423
		/*
424
		 * All options other than DHO_PAD and DHO_END have a one-byte
425
		 * length field. It could be 0! Make sure that the length byte
426
		 * is present, and all the data is available.
427
		 */
428
		if (s + 1 < end) {
429
			len = s[1];
430
			if (s + 1 + len < end) {
431
				; /* option data is all there. */
432
			} else {
433
				log_warnx("%s: option %s (%d) larger than "
434
				    "buffer", log_procname, name, len);
435
				return 0;
436
			}
437
		} else {
438
			log_warnx("%s: option %s has no length field",
439
			    log_procname, name);
440
			return 0;
441
		}
442
443
		/*
444
		 * Strip trailing NULs from ascii ('t') options. They
445
		 * will be treated as DHO_PAD options. i.e. ignored. RFC 2132
446
		 * says "Options containing NVT ASCII data SHOULD NOT include
447
		 * a trailing NULL; however, the receiver of such options
448
		 * MUST be prepared to delete trailing nulls if they exist."
449
		 */
450
		if (fmt[0] == 't') {
451
			while (len > 0 && s[len + 1] == '\0')
452
				len--;
453
		}
454
455
		/*
456
		 * If we haven't seen this option before, just make
457
		 * space for it and copy it there.
458
		 */
459
		if (options[code].data == NULL) {
460
			t = calloc(1, len + 1);
461
			if (t == NULL)
462
				fatal("option %s", name);
463
			/*
464
			 * Copy and NUL-terminate the option (in case
465
			 * it's an ASCII string).
466
			 */
467
			memcpy(t, &s[2], len);
468
			t[len] = 0;
469
			options[code].len = len;
470
			options[code].data = t;
471
		} else {
472
			/*
473
			 * If it's a repeat, concatenate it to whatever
474
			 * we last saw.
475
			 */
476
			t = calloc(1, len + options[code].len + 1);
477
			if (t == NULL)
478
				fatal("option %s concat", name);
479
			memcpy(t, options[code].data, options[code].len);
480
			memcpy(t + options[code].len, &s[2], len);
481
			options[code].len += len;
482
			t[options[code].len] = 0;
483
			free(options[code].data);
484
			options[code].data = t;
485
		}
486
		s += len + 2;
487
	}
488
489
	return 1;
490
}
491
492
/*
493
 * Pack as many options as fit in buflen bytes of buf. Return the
494
 * offset of the start of the last option copied. A caller can check
495
 * to see if it's DHO_END to decide if all the options were copied.
496
 */
497
int
498
pack_options(unsigned char *buf, int buflen, struct option_data *options)
499
{
500
	int	 ix, incr, length, bufix, code, lastopt = -1;
501
502
	memset(buf, 0, buflen);
503
504
	memcpy(buf, DHCP_OPTIONS_COOKIE, 4);
505
	if (options[DHO_DHCP_MESSAGE_TYPE].data != NULL) {
506
		memcpy(&buf[4], DHCP_OPTIONS_MESSAGE_TYPE, 3);
507
		buf[6] = options[DHO_DHCP_MESSAGE_TYPE].data[0];
508
		bufix = 7;
509
	} else
510
		bufix = 4;
511
512
	for (code = DHO_SUBNET_MASK; code < DHO_END; code++) {
513
		if (options[code].data == NULL ||
514
		    code == DHO_DHCP_MESSAGE_TYPE)
515
			continue;
516
517
		length = options[code].len;
518
		if (bufix + length + 2*((length+254)/255) >= buflen)
519
			return lastopt;
520
521
		lastopt = bufix;
522
		ix = 0;
523
524
		while (length) {
525
			incr = length > 255 ? 255 : length;
526
527
			buf[bufix++] = code;
528
			buf[bufix++] = incr;
529
			memcpy(buf + bufix, options[code].data + ix, incr);
530
531
			length -= incr;
532
			ix += incr;
533
			bufix += incr;
534
		}
535
	}
536
537
	if (bufix < buflen) {
538
		buf[bufix] = DHO_END;
539
		lastopt = bufix;
540
	}
541
542
	return lastopt;
543
}
544
545
/*
546
 * Use vis() to encode characters of src and append encoded characters onto
547
 * dst. Also encode ", ', $, ` and \, to ensure resulting strings can be
548
 * represented as '"' delimited strings and safely passed to scripts. Surround
549
 * result with double quotes if emit_punct is true.
550
 */
551
char *
552
pretty_print_string(unsigned char *src, size_t srclen, int emit_punct)
553
{
554
	static char	 string[8196];
555
	char		 visbuf[5];
556
	unsigned char	*origsrc = src;
557
	size_t		 rslt = 0;
558
559
	memset(string, 0, sizeof(string));
560
561
	if (emit_punct != 0)
562
		rslt = strlcat(string, "\"", sizeof(string));
563
564
	for (; src < origsrc + srclen; src++) {
565
		if (*src && strchr("\"'$`\\", *src))
566
			vis(visbuf, *src, VIS_ALL | VIS_OCTAL, *src+1);
567
		else
568
			vis(visbuf, *src, VIS_OCTAL, *src+1);
569
		rslt = strlcat(string, visbuf, sizeof(string));
570
	}
571
572
	if (emit_punct != 0)
573
		rslt = strlcat(string, "\"", sizeof(string));
574
575
	if (rslt >= sizeof(string))
576
		return NULL;
577
578
	return string;
579
}
580
581
/*
582
 * Must special case *_CLASSLESS_* route options due to the variable size
583
 * of the CIDR element in its CIA format.
584
 */
585
void
586
pretty_print_classless_routes(unsigned char *src, size_t srclen,
587
    unsigned char *buf, size_t buflen)
588
{
589
	char		 bitsbuf[5];	/* to hold "/nn " */
590
	struct in_addr	 dest, netmask, gateway;
591
	unsigned int	 bits, i, len;
592
	uint32_t	 m;
593
	int		 rslt;
594
595
	i = 0;
596
	while (i < srclen) {
597
		len = extract_classless_route(&src[i], srclen - i,
598
		    &dest.s_addr, &netmask.s_addr, &gateway.s_addr);
599
		if (len == 0)
600
			goto bad;
601
		i += len;
602
603
		m = ntohl(netmask.s_addr);
604
		bits = 32;
605
		while ((bits > 0) && ((m & 1) == 0)) {
606
			m >>= 1;
607
			bits--;
608
		}
609
610
		rslt = snprintf(bitsbuf, sizeof(bitsbuf), "/%d ", bits);
611
		if (rslt == -1 || (unsigned int)rslt >= sizeof(bitsbuf))
612
			goto bad;
613
614
		if (strlen(buf) > 0)
615
			strlcat(buf, ", ", buflen);
616
		strlcat(buf, inet_ntoa(dest), buflen);
617
		strlcat(buf, bitsbuf, buflen);
618
		if (strlcat(buf, inet_ntoa(gateway), buflen) >= buflen)
619
			goto bad;
620
	}
621
622
	return;
623
624
bad:
625
	memset(buf, 0, buflen);
626
}
627
628
int
629
expand_search_domain_name(unsigned char *src, size_t srclen, int *offset,
630
    unsigned char *domain_search)
631
{
632
	char		*cursor;
633
	unsigned int	 i;
634
	int		 domain_name_len, label_len, pointer, pointed_len;
635
636
	cursor = domain_search + strlen(domain_search);
637
	domain_name_len = 0;
638
639
	i = *offset;
640
	while (i <= srclen) {
641
		label_len = src[i];
642
		if (label_len == 0) {
643
			/*
644
			 * A zero-length label marks the end of this
645
			 * domain name.
646
			 */
647
			*offset = i + 1;
648
			return domain_name_len;
649
		} else if ((label_len & 0xC0) != 0) {
650
			/* This is a pointer to another list of labels. */
651
			if (i + 1 >= srclen) {
652
				/* The pointer is truncated. */
653
				log_warnx("%s: truncated pointer in DHCP "
654
				    "Domain Search option", log_procname);
655
				return -1;
656
			}
657
658
			pointer = ((label_len & ~(0xC0)) << 8) + src[i + 1];
659
			if (pointer >= *offset) {
660
				/*
661
				 * The pointer must indicates a prior
662
				 * occurance.
663
				 */
664
				log_warnx("%s: invalid forward pointer in DHCP "
665
				    "Domain Search option compression",
666
				    log_procname);
667
				return -1;
668
			}
669
670
			pointed_len = expand_search_domain_name(src, srclen,
671
			    &pointer, domain_search);
672
			domain_name_len += pointed_len;
673
674
			*offset = i + 2;
675
			return domain_name_len;
676
		}
677
		if (i + label_len + 1 > srclen) {
678
			log_warnx("%s: truncated label in DHCP Domain Search "
679
			    "option", log_procname);
680
			return -1;
681
		}
682
		/*
683
		 * Update the domain name length with the length of the
684
		 * current label, plus a trailing dot ('.').
685
		 */
686
		domain_name_len += label_len + 1;
687
688
		if (strlen(domain_search) + domain_name_len >=
689
		    DHCP_DOMAIN_SEARCH_LEN) {
690
			log_warnx("%s: domain search list too long",
691
			    log_procname);
692
			return -1;
693
		}
694
695
		/* Copy the label found. */
696
		memcpy(cursor, src + i + 1, label_len);
697
		cursor[label_len] = '.';
698
699
		/* Move cursor. */
700
		i += label_len + 1;
701
		cursor += label_len + 1;
702
	}
703
704
	log_warnx("%s: truncated DHCP Domain Search option", log_procname);
705
706
	return -1;
707
}
708
709
/*
710
 * Must special case DHO_DOMAIN_SEARCH because it is encoded as described
711
 * in RFC 1035 section 4.1.4.
712
 */
713
char *
714
pretty_print_domain_search(unsigned char *src, size_t srclen)
715
{
716
	static char	 domain_search[DHCP_DOMAIN_SEARCH_LEN];
717
	unsigned char	*cursor;
718
	unsigned int	 offset;
719
	int		 len, expanded_len, domains;
720
721
	memset(domain_search, 0, sizeof(domain_search));
722
723
	/* Compute expanded length. */
724
	expanded_len = len = 0;
725
	domains = 0;
726
	offset = 0;
727
	while (offset < srclen) {
728
		cursor = domain_search + strlen(domain_search);
729
		if (domain_search[0] != '\0') {
730
			*cursor = ' ';
731
			expanded_len++;
732
		}
733
		len = expand_search_domain_name(src, srclen, &offset,
734
		    domain_search);
735
		if (len == -1)
736
			return NULL;
737
		domains++;
738
		expanded_len += len;
739
		if (domains > DHCP_DOMAIN_SEARCH_CNT)
740
			return NULL;
741
	}
742
743
	return domain_search;
744
}
745
746
/*
747
 * Format the specified option so that a human can easily read it.
748
 */
749
char *
750
pretty_print_option(unsigned int code, struct option_data *option,
751
    int emit_punct)
752
{
753
	static char	 optbuf[8192]; /* XXX */
754
	char		 fmtbuf[32];
755
	struct in_addr	 foo;
756
	unsigned char	*data = option->data;
757
	unsigned char	*dp = data;
758
	char		*op = optbuf, *buf, *name, *fmt;
759
	int		 hunksize = 0, numhunk = -1, numelem = 0;
760
	int		 i, j, k, opleft = sizeof(optbuf);
761
	int		 len = option->len;
762
	int		 opcount = 0;
763
	int32_t		 int32val;
764
	uint32_t	 uint32val;
765
	uint16_t	 uint16val;
766
	char		 comma;
767
768
	memset(optbuf, 0, sizeof(optbuf));
769
770
	/* Code should be between 0 and 255. */
771
	if (code > 255) {
772
		log_warnx("%s: pretty_print_option: bad code %d", log_procname,
773
		    code);
774
		goto done;
775
	}
776
777
	if (emit_punct != 0)
778
		comma = ',';
779
	else
780
		comma = ' ';
781
782
	/* Handle the princess class options with weirdo formats. */
783
	switch (code) {
784
	case DHO_CLASSLESS_STATIC_ROUTES:
785
	case DHO_CLASSLESS_MS_STATIC_ROUTES:
786
		pretty_print_classless_routes(dp, len, optbuf,
787
		    sizeof(optbuf));
788
		goto done;
789
	default:
790
		break;
791
	}
792
793
	name = code_to_name(code);
794
	fmt = code_to_format(code);
795
796
	/* Figure out the size of the data. */
797
	for (i = 0; fmt[i]; i++) {
798
		if (numhunk == 0) {
799
			log_warnx("%s: %s: excess information in format "
800
			    "string: %s", log_procname, name, &fmt[i]);
801
			goto done;
802
		}
803
		numelem++;
804
		fmtbuf[i] = fmt[i];
805
		switch (fmt[i]) {
806
		case 'A':
807
			--numelem;
808
			fmtbuf[i] = 0;
809
			numhunk = 0;
810
			if (hunksize == 0) {
811
				log_warnx("%s: %s: no size indicator before A"
812
				    " in format string: %s", log_procname,
813
				    name, fmt);
814
				goto done;
815
			}
816
			break;
817
		case 'X':
818
			for (k = 0; k < len; k++)
819
				if (isascii(data[k]) == 0 ||
820
				    isprint(data[k]) == 0)
821
					break;
822
			if (k == len) {
823
				fmtbuf[i] = 't';
824
				numhunk = -2;
825
			} else {
826
				hunksize++;
827
				comma = ':';
828
				numhunk = 0;
829
			}
830
			fmtbuf[i + 1] = 0;
831
			break;
832
		case 't':
833
			fmtbuf[i + 1] = 0;
834
			numhunk = -2;
835
			break;
836
		case 'I':
837
		case 'l':
838
		case 'L':
839
			hunksize += 4;
840
			break;
841
		case 'S':
842
			hunksize += 2;
843
			break;
844
		case 'B':
845
		case 'f':
846
			hunksize++;
847
			break;
848
		case 'e':
849
			break;
850
		default:
851
			log_warnx("%s: %s: garbage in format string: %s",
852
			    log_procname, name, &fmt[i]);
853
			goto done;
854
		}
855
	}
856
857
	/* Check for too few bytes. */
858
	if (hunksize > len) {
859
		log_warnx("%s: %s: expecting at least %d bytes; got %d",
860
		    log_procname, name, hunksize, len);
861
		goto done;
862
	}
863
	/* Check for too many bytes. */
864
	if (numhunk == -1 && hunksize < len) {
865
		log_warnx("%s: %s: expecting only %d bytes: got %d",
866
		    log_procname, name, hunksize, len);
867
		goto done;
868
	}
869
870
	/* If this is an array, compute its size. */
871
	if (numhunk == 0)
872
		numhunk = len / hunksize;
873
	/* See if we got an exact number of hunks. */
874
	if (numhunk > 0 && numhunk * hunksize != len) {
875
		log_warnx("%s: %s: expecting %d bytes: got %d", log_procname,
876
		    name, numhunk * hunksize, len);
877
		goto done;
878
	}
879
880
	/* A one-hunk array prints the same as a single hunk. */
881
	if (numhunk < 0)
882
		numhunk = 1;
883
884
	/* Cycle through the array (or hunk) printing the data. */
885
	for (i = 0; i < numhunk; i++) {
886
		for (j = 0; j < numelem; j++) {
887
			switch (fmtbuf[j]) {
888
			case 't':
889
				buf = pretty_print_string(dp, len, emit_punct);
890
				if (buf == NULL)
891
					opcount = -1;
892
				else
893
					opcount = strlcat(op, buf, opleft);
894
				break;
895
			case 'I':
896
				memcpy(&foo.s_addr, dp, sizeof(foo.s_addr));
897
				opcount = snprintf(op, opleft, "%s",
898
				    inet_ntoa(foo));
899
				dp += sizeof(foo.s_addr);
900
				break;
901
			case 'l':
902
				memcpy(&int32val, dp, sizeof(int32val));
903
				opcount = snprintf(op, opleft, "%d",
904
				    ntohl(int32val));
905
				dp += sizeof(int32val);
906
				break;
907
			case 'L':
908
				memcpy(&uint32val, dp, sizeof(uint32val));
909
				opcount = snprintf(op, opleft, "%u",
910
				    ntohl(uint32val));
911
				dp += sizeof(uint32val);
912
				break;
913
			case 'S':
914
				memcpy(&uint16val, dp, sizeof(uint16val));
915
				opcount = snprintf(op, opleft, "%hu",
916
				    ntohs(uint16val));
917
				dp += sizeof(uint16val);
918
				break;
919
			case 'B':
920
				opcount = snprintf(op, opleft, "%u", *dp);
921
				dp++;
922
				break;
923
			case 'X':
924
				opcount = snprintf(op, opleft, "%x", *dp);
925
				dp++;
926
				break;
927
			case 'f':
928
				opcount = snprintf(op, opleft, "%s",
929
				    *dp ? "true" : "false");
930
				dp++;
931
				break;
932
			default:
933
				log_warnx("%s: unexpected format code %c",
934
				    log_procname, fmtbuf[j]);
935
				goto toobig;
936
			}
937
			if (opcount >= opleft || opcount == -1)
938
				goto toobig;
939
			opleft -= opcount;
940
			op += opcount;
941
			if (j + 1 < numelem && comma != ':') {
942
				opcount = snprintf(op, opleft, " ");
943
				if (opcount >= opleft || opcount == -1)
944
					goto toobig;
945
				opleft -= opcount;
946
				op += opcount;
947
			}
948
		}
949
		if (i + 1 < numhunk) {
950
			opcount = snprintf(op, opleft, "%c", comma);
951
			if (opcount >= opleft || opcount == -1)
952
				goto toobig;
953
			opleft -= opcount;
954
			op += opcount;
955
		}
956
	}
957
958
done:
959
	return optbuf;
960
961
toobig:
962
	memset(optbuf, 0, sizeof(optbuf));
963
	return optbuf;
964
}
965
966
struct option_data *
967
unpack_options(struct dhcp_packet *packet)
968
{
969
	static struct option_data	 options[DHO_COUNT];
970
	int				 i;
971
972
	for (i = 0; i < DHO_COUNT; i++) {
973
		free(options[i].data);
974
		options[i].data = NULL;
975
		options[i].len = 0;
976
	}
977
978
	if (memcmp(&packet->options, DHCP_OPTIONS_COOKIE, 4) == 0) {
979
		/* Parse the BOOTP/DHCP options field. */
980
		parse_option_buffer(options, &packet->options[4],
981
		    sizeof(packet->options) - 4);
982
983
		/* DHCP packets can also use overload areas for options. */
984
		if (options[DHO_DHCP_MESSAGE_TYPE].data != NULL &&
985
		    options[DHO_DHCP_OPTION_OVERLOAD].data != NULL) {
986
			if ((options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) !=
987
			    0)
988
				parse_option_buffer(options,
989
				    (unsigned char *)packet->file,
990
				    sizeof(packet->file));
991
			if ((options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) !=
992
			    0)
993
				parse_option_buffer(options,
994
				    (unsigned char *)packet->sname,
995
				    sizeof(packet->sname));
996
		}
997
	}
998
999
	return options;
1000
}