GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/rtadvd/advcap.c Lines: 0 149 0.0 %
Date: 2017-11-07 Branches: 0 129 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: advcap.c,v 1.17 2015/10/25 22:36:17 jca Exp $	*/
2
/*	$KAME: advcap.c,v 1.9 2002/05/29 14:28:35 itojun Exp $	*/
3
4
/*
5
 * Copyright (c) 1983 The Regents of the University of California.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
/*
34
 * remcap - routines for dealing with the remote host data base
35
 *
36
 * derived from termcap
37
 */
38
#include <sys/types.h>
39
#include <sys/uio.h>
40
#include <unistd.h>
41
#include <fcntl.h>
42
#include <ctype.h>
43
#include <stdlib.h>
44
#include <stdio.h>
45
#include <errno.h>
46
#include <string.h>
47
#include "pathnames.h"
48
#include "log.h"
49
50
#define MAXHOP		32		/* max number of tc= indirections */
51
52
#define	tgetent		agetent
53
#define	tnchktc		anchktc
54
#define	tnamatch	anamatch
55
#define	tgetnum		agetnum
56
#define	tgetflag	agetflag
57
#define	tgetstr		agetstr
58
59
#if 0
60
#define V_TERMCAP	"REMOTE"
61
#define V_TERM		"HOST"
62
#endif
63
64
65
/*
66
 * termcap - routines for dealing with the terminal capability data base
67
 *
68
 * BUG:		Should use a "last" pointer in tbuf, so that searching
69
 *		for capabilities alphabetically would not be a n**2/2
70
 *		process when large numbers of capabilities are given.
71
 * Note:	If we add a last pointer now we will screw up the
72
 *		tc capability. We really should compile termcap.
73
 *
74
 * Essentially all the work here is scanning and decoding escapes
75
 * in string capabilities.  We don't use stdio because the editor
76
 * doesn't, and because living w/o it is not hard.
77
 */
78
79
static	char *tbuf;
80
static	int hopcount;	/* detect infinite loops in termcap, init 0 */
81
82
static	char *remotefile;
83
84
extern char *conffile;
85
86
int tgetent(char *, char *);
87
int getent(char *, char *, char *);
88
int tnchktc(void);
89
int tnamatch(char *);
90
static char *tskip(char *);
91
int64_t tgetnum(char *);
92
int tgetflag(char *);
93
char *tgetstr(char *, char **);
94
static char *tdecode(char *, char **);
95
96
/*
97
 * Get an entry for terminal name in buffer bp,
98
 * from the termcap file.  Parse is very rudimentary;
99
 * we just notice escaped newlines.
100
 */
101
int
102
tgetent(char *bp, char *name)
103
{
104
	char *cp;
105
106
	remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
107
	return (getent(bp, name, cp));
108
}
109
110
int
111
getent(char *bp, char *name, char *cp)
112
{
113
	int c;
114
	int i = 0, cnt = 0;
115
	char ibuf[BUFSIZ];
116
	int tf;
117
118
	tbuf = bp;
119
	tf = 0;
120
	/*
121
	 * TERMCAP can have one of two things in it. It can be the
122
	 * name of a file to use instead of /etc/termcap. In this
123
	 * case it better start with a "/". Or it can be an entry to
124
	 * use so we don't have to read the file. In this case it
125
	 * has to already have the newlines crunched out.
126
	 */
127
	if (cp && *cp) {
128
		tf = open(cp, O_RDONLY);
129
	}
130
	if (tf < 0) {
131
		log_warn("open(\"%s\")", cp);
132
		return (-2);
133
	}
134
	for (;;) {
135
		cp = bp;
136
		for (;;) {
137
			if (i == cnt) {
138
				cnt = read(tf, ibuf, BUFSIZ);
139
				if (cnt <= 0) {
140
					close(tf);
141
					return (0);
142
				}
143
				i = 0;
144
			}
145
			c = ibuf[i++];
146
			if (c == '\n') {
147
				if (cp > bp && cp[-1] == '\\') {
148
					cp--;
149
					continue;
150
				}
151
				break;
152
			}
153
			if (cp >= bp + BUFSIZ) {
154
				write(STDERR_FILENO, "Remcap entry too long\n", 23);
155
				break;
156
			} else
157
				*cp++ = c;
158
		}
159
		*cp = 0;
160
161
		/*
162
		 * The real work for the match.
163
		 */
164
		if (tnamatch(name)) {
165
			close(tf);
166
			return (tnchktc());
167
		}
168
	}
169
}
170
171
/*
172
 * tnchktc: check the last entry, see if it's tc=xxx. If so,
173
 * recursively find xxx and append that entry (minus the names)
174
 * to take the place of the tc=xxx entry. This allows termcap
175
 * entries to say "like an HP2621 but doesn't turn on the labels".
176
 * Note that this works because of the left to right scan.
177
 */
178
int
179
tnchktc(void)
180
{
181
	char *p, *q;
182
	char tcname[16];	/* name of similar terminal */
183
	char tcbuf[BUFSIZ];
184
	char *holdtbuf = tbuf;
185
	int l;
186
187
	p = tbuf + strlen(tbuf) - 2;	/* before the last colon */
188
	while (*--p != ':')
189
		if (p < tbuf) {
190
			write(STDERR_FILENO, "Bad remcap entry\n", 18);
191
			return (0);
192
		}
193
	p++;
194
	/* p now points to beginning of last field */
195
	if (p[0] != 't' || p[1] != 'c')
196
		return (1);
197
	strlcpy(tcname, p + 3, sizeof tcname);
198
	q = tcname;
199
	while (*q && *q != ':')
200
		q++;
201
	*q = 0;
202
	if (++hopcount > MAXHOP) {
203
		write(STDERR_FILENO, "Infinite tc= loop\n", 18);
204
		return (0);
205
	}
206
	if (getent(tcbuf, tcname, remotefile) != 1) {
207
		log_warnx("Could not parse %s: "
208
		    "Unresolvable reference to %s.", remotefile, tcname);
209
		return (0);
210
	}
211
	for (q = tcbuf; *q++ != ':'; )
212
		;
213
	l = p - holdtbuf + strlen(q);
214
	if (l > BUFSIZ) {
215
		write(STDERR_FILENO, "Remcap entry too long\n", 23);
216
		q[BUFSIZ - (p-holdtbuf)] = 0;
217
	}
218
	strlcpy(p, q, holdtbuf + BUFSIZ - p);
219
	tbuf = holdtbuf;
220
	return (1);
221
}
222
223
/*
224
 * Tnamatch deals with name matching.  The first field of the termcap
225
 * entry is a sequence of names separated by |'s, so we compare
226
 * against each such name.  The normal : terminator after the last
227
 * name (before the first field) stops us.
228
 */
229
int
230
tnamatch(char *np)
231
{
232
	char *Np, *Bp;
233
234
	Bp = tbuf;
235
	if (*Bp == '#')
236
		return (0);
237
	for (;;) {
238
		for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
239
			continue;
240
		if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
241
			return (1);
242
		while (*Bp && *Bp != ':' && *Bp != '|')
243
			Bp++;
244
		if (*Bp == 0 || *Bp == ':')
245
			return (0);
246
		Bp++;
247
	}
248
}
249
250
/*
251
 * Skip to the next field.  Notice that this is very dumb, not
252
 * knowing about \: escapes or any such.  If necessary, :'s can be put
253
 * into the termcap file in octal.
254
 */
255
static char *
256
tskip(char *bp)
257
{
258
	int dquote;
259
260
	dquote = 0;
261
	while (*bp) {
262
		switch (*bp) {
263
		case ':':
264
			if (!dquote)
265
				goto breakbreak;
266
			else
267
				bp++;
268
			break;
269
		case '\\':
270
			bp++;
271
			if (isdigit((unsigned char)*bp)) {
272
				while (isdigit((unsigned char)*bp++))
273
					;
274
			} else
275
				bp++;
276
		case '"':
277
			dquote = (dquote ? 1 : 0);
278
			bp++;
279
			break;
280
		default:
281
			bp++;
282
			break;
283
		}
284
	}
285
breakbreak:
286
	if (*bp == ':')
287
		bp++;
288
	return (bp);
289
}
290
291
/*
292
 * Return the (numeric) option id.
293
 * Numeric options look like
294
 *	li#80
295
 * i.e. the option string is separated from the numeric value by
296
 * a # character.  If the option is not found we return -1.
297
 * Note that we handle octal numbers beginning with 0.
298
 */
299
int64_t
300
tgetnum(char *id)
301
{
302
	int64_t i;
303
	int base;
304
	char *bp = tbuf;
305
306
	for (;;) {
307
		bp = tskip(bp);
308
		if (*bp == 0)
309
			return (-1);
310
		if (strncmp(bp, id, strlen(id)) != 0)
311
			continue;
312
		bp += strlen(id);
313
		if (*bp == '@')
314
			return (-1);
315
		if (*bp != '#')
316
			continue;
317
		bp++;
318
		base = 10;
319
		if (*bp == '0')
320
			base = 8;
321
		i = 0;
322
		while (isdigit((unsigned char)*bp))
323
			i *= base, i += *bp++ - '0';
324
		return (i);
325
	}
326
}
327
328
/*
329
 * Handle a flag option.
330
 * Flag options are given "naked", i.e. followed by a : or the end
331
 * of the buffer.  Return 1 if we find the option, or 0 if it is
332
 * not given.
333
 */
334
int
335
tgetflag(char *id)
336
{
337
	char *bp = tbuf;
338
339
	for (;;) {
340
		bp = tskip(bp);
341
		if (!*bp)
342
			return (0);
343
		if (strncmp(bp, id, strlen(id)) == 0) {
344
			bp += strlen(id);
345
			if (!*bp || *bp == ':')
346
				return (1);
347
			else if (*bp == '@')
348
				return (0);
349
		}
350
	}
351
}
352
353
/*
354
 * Get a string valued option.
355
 * These are given as
356
 *	cl=^Z
357
 * Much decoding is done on the strings, and the strings are
358
 * placed in area, which is a ref parameter which is updated.
359
 * No checking on area overflow.
360
 */
361
char *
362
tgetstr(char *id, char **area)
363
{
364
	char *bp = tbuf;
365
366
	for (;;) {
367
		bp = tskip(bp);
368
		if (!*bp)
369
			return (0);
370
		if (strncmp(bp, id, strlen(id)) != 0)
371
			continue;
372
		bp += strlen(id);
373
		if (*bp == '@')
374
			return (0);
375
		if (*bp != '=')
376
			continue;
377
		bp++;
378
		return (tdecode(bp, area));
379
	}
380
}
381
382
/*
383
 * Tdecode does the grung work to decode the
384
 * string capability escapes.
385
 */
386
static char *
387
tdecode(char *str, char **area)
388
{
389
	char *cp;
390
	int c;
391
	char *dp;
392
	int i;
393
	char term;
394
395
	term = ':';
396
	cp = *area;
397
again:
398
	if (*str == '"') {
399
		term = '"';
400
		str++;
401
	}
402
	while ((c = *str++) && c != term) {
403
		switch (c) {
404
405
		case '^':
406
			c = *str++ & 037;
407
			break;
408
409
		case '\\':
410
			dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\"";
411
			c = *str++;
412
nextc:
413
			if (*dp++ == c) {
414
				c = *dp++;
415
				break;
416
			}
417
			dp++;
418
			if (*dp)
419
				goto nextc;
420
			if (isdigit((unsigned char)c)) {
421
				c -= '0', i = 2;
422
				do
423
					c <<= 3, c |= *str++ - '0';
424
				while (--i && isdigit((unsigned char)*str));
425
			}
426
			break;
427
		}
428
		*cp++ = c;
429
	}
430
	if (c == term && term != ':') {
431
		term = ':';
432
		goto again;
433
	}
434
	*cp++ = 0;
435
	str = *area;
436
	*area = cp;
437
	return (str);
438
}