xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/roken/vis.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1 /*	$NetBSD: vis.c,v 1.2 2017/01/28 21:31:50 christos Exp $	*/
2 
3 /*	NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp	*/
4 
5 /*-
6  * Copyright (c) 1989, 1993
7  *	The Regents of the University of California.  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  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*-
35  * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
48  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
49  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57  * POSSIBILITY OF SUCH DAMAGE.
58  */
59 
60 #if 1
61 #include <config.h>
62 #include <krb5/roken.h>
63 #ifndef _DIAGASSERT
64 #define _DIAGASSERT(X)
65 #endif
66 #else /* heimdal */
67 #include <sys/cdefs.h>
68 #if defined(LIBC_SCCS) && !defined(lint)
69 __RCSID("NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp");
70 #endif /* LIBC_SCCS and not lint */
71 
72 #include "namespace.h"
73 #endif /* heimdal */
74 
75 #include <sys/types.h>
76 
77 #include <assert.h>
78 #include <ctype.h>
79 #include <limits.h>
80 #include <stdio.h>
81 #include <string.h>
82 #include <vis.h>
83 #include <stdlib.h>
84 
85 #if 0
86 #ifdef __weak_alias
87 __weak_alias(strsvis,_strsvis)
88 __weak_alias(strsvisx,_strsvisx)
89 __weak_alias(strvis,_strvis)
90 __weak_alias(strvisx,_strvisx)
91 __weak_alias(svis,_svis)
92 __weak_alias(vis,_vis)
93 #endif
94 #endif
95 
96 #if !HAVE_VIS || !HAVE_SVIS
97 #include <ctype.h>
98 #include <limits.h>
99 #include <stdio.h>
100 #include <string.h>
101 
102 static char *do_svis(char *, int, int, int, const char *);
103 
104 #undef BELL
105 #if defined(__STDC__)
106 #define BELL '\a'
107 #else
108 #define BELL '\007'
109 #endif
110 
111 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
112 	rk_vis (char *, int, int, int);
113 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
114 	rk_svis (char *, int, int, int, const char *);
115 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
116 	rk_strvis (char *, const char *, int);
117 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
118 	rk_strsvis (char *, const char *, int, const char *);
119 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
120 	rk_strvisx (char *, const char *, size_t, int);
121 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
122 	rk_strsvisx (char *, const char *, size_t, int, const char *);
123 
124 
125 #define isoctal(c)	(((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
126 #define iswhite(c)	(c == ' ' || c == '\t' || c == '\n')
127 #define issafe(c)	(c == '\b' || c == BELL || c == '\r')
128 #define xtoa(c)		"0123456789abcdef"[c]
129 
130 #define MAXEXTRAS	5
131 
132 #define MAKEEXTRALIST(flag, extra, orig_str)				      \
133 do {									      \
134 	const char *orig = orig_str;					      \
135 	const char *o = orig;						      \
136 	char *e;							      \
137 	while (*o++)							      \
138 		continue;						      \
139 	extra = malloc((size_t)((o - orig) + MAXEXTRAS));		      \
140 	if (!extra) break;						      \
141 	for (o = orig, e = extra; (*e++ = *o++) != '\0';)		      \
142 		continue;						      \
143 	e--;								      \
144 	if (flag & VIS_SP) *e++ = ' ';					      \
145 	if (flag & VIS_TAB) *e++ = '\t';				      \
146 	if (flag & VIS_NL) *e++ = '\n';					      \
147 	if ((flag & VIS_NOSLASH) == 0) *e++ = '\\';			      \
148 	*e = '\0';							      \
149 } while (/*CONSTCOND*/0)
150 
151 /*
152  * This is do_hvis, for HTTP style (RFC 1808)
153  */
154 static char *
do_hvis(char * dst,int c,int flag,int nextc,const char * extra)155 do_hvis(char *dst, int c, int flag, int nextc, const char *extra)
156 {
157 	if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) {
158 		*dst++ = '%';
159 		*dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
160 		*dst++ = xtoa((unsigned int)c & 0xf);
161 	} else {
162 		dst = do_svis(dst, c, flag, nextc, extra);
163 	}
164 	return dst;
165 }
166 
167 /*
168  * This is do_vis, the central code of vis.
169  * dst:	      Pointer to the destination buffer
170  * c:	      Character to encode
171  * flag:      Flag word
172  * nextc:     The character following 'c'
173  * extra:     Pointer to the list of extra characters to be
174  *	      backslash-protected.
175  */
176 static char *
do_svis(char * dst,int c,int flag,int nextc,const char * extra)177 do_svis(char *dst, int c, int flag, int nextc, const char *extra)
178 {
179 	int isextra;
180 	isextra = strchr(extra, c) != NULL;
181 	if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
182 	    ((flag & VIS_SAFE) && issafe(c)))) {
183 		*dst++ = c;
184 		return dst;
185 	}
186 	if (flag & VIS_CSTYLE) {
187 		switch (c) {
188 		case '\n':
189 			*dst++ = '\\'; *dst++ = 'n';
190 			return dst;
191 		case '\r':
192 			*dst++ = '\\'; *dst++ = 'r';
193 			return dst;
194 		case '\b':
195 			*dst++ = '\\'; *dst++ = 'b';
196 			return dst;
197 		case BELL:
198 			*dst++ = '\\'; *dst++ = 'a';
199 			return dst;
200 		case '\v':
201 			*dst++ = '\\'; *dst++ = 'v';
202 			return dst;
203 		case '\t':
204 			*dst++ = '\\'; *dst++ = 't';
205 			return dst;
206 		case '\f':
207 			*dst++ = '\\'; *dst++ = 'f';
208 			return dst;
209 		case ' ':
210 			*dst++ = '\\'; *dst++ = 's';
211 			return dst;
212 		case '\0':
213 			*dst++ = '\\'; *dst++ = '0';
214 			if (isoctal(nextc)) {
215 				*dst++ = '0';
216 				*dst++ = '0';
217 			}
218 			return dst;
219 		default:
220 			if (isgraph(c)) {
221 				*dst++ = '\\'; *dst++ = c;
222 				return dst;
223 			}
224 		}
225 	}
226 	if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
227 		*dst++ = '\\';
228 		*dst++ = (u_char)(((unsigned int)(u_char)c >> 6) & 03) + '0';
229 		*dst++ = (u_char)(((unsigned int)(u_char)c >> 3) & 07) + '0';
230 		*dst++ = (u_char)(			 c       & 07) + '0';
231 	} else {
232 		if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
233 		if (c & 0200) {
234 			c &= 0177; *dst++ = 'M';
235 		}
236 		if (iscntrl(c)) {
237 			*dst++ = '^';
238 			if (c == 0177)
239 				*dst++ = '?';
240 			else
241 				*dst++ = c + '@';
242 		} else {
243 			*dst++ = '-'; *dst++ = c;
244 		}
245 	}
246 	return dst;
247 }
248 
249 
250 /*
251  * svis - visually encode characters, also encoding the characters
252  *	  pointed to by `extra'
253  */
254 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
rk_svis(char * dst,int c,int flag,int nextc,const char * extra)255 rk_svis(char *dst, int c, int flag, int nextc, const char *extra)
256 {
257 	char *nextra = NULL;
258 
259 	_DIAGASSERT(dst != NULL);
260 	_DIAGASSERT(extra != NULL);
261 	MAKEEXTRALIST(flag, nextra, extra);
262 	if (!nextra) {
263 		*dst = '\0';		/* can't create nextra, return "" */
264 		return dst;
265 	}
266 	if (flag & VIS_HTTPSTYLE)
267 		dst = do_hvis(dst, c, flag, nextc, nextra);
268 	else
269 		dst = do_svis(dst, c, flag, nextc, nextra);
270 	free(nextra);
271 	*dst = '\0';
272 	return dst;
273 }
274 
275 
276 /*
277  * strsvis, strsvisx - visually encode characters from src into dst
278  *
279  *	Extra is a pointer to a \0-terminated list of characters to
280  *	be encoded, too. These functions are useful e. g. to
281  *	encode strings in such a way so that they are not interpreted
282  *	by a shell.
283  *
284  *	Dst must be 4 times the size of src to account for possible
285  *	expansion.  The length of dst, not including the trailing NULL,
286  *	is returned.
287  *
288  *	Strsvisx encodes exactly len bytes from src into dst.
289  *	This is useful for encoding a block of data.
290  */
291 
292 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_strsvis(char * dst,const char * csrc,int flag,const char * extra)293 rk_strsvis(char *dst, const char *csrc, int flag, const char *extra)
294 {
295 	int c;
296 	char *start;
297 	char *nextra = NULL;
298 	const unsigned char *src = (const unsigned char *)csrc;
299 
300 	_DIAGASSERT(dst != NULL);
301 	_DIAGASSERT(src != NULL);
302 	_DIAGASSERT(extra != NULL);
303 	MAKEEXTRALIST(flag, nextra, extra);
304 	if (!nextra) {
305 		*dst = '\0';		/* can't create nextra, return "" */
306 		return 0;
307 	}
308 	if (flag & VIS_HTTPSTYLE) {
309 		for (start = dst; (c = *src++) != '\0'; /* empty */)
310 			dst = do_hvis(dst, c, flag, *src, nextra);
311 	} else {
312 		for (start = dst; (c = *src++) != '\0'; /* empty */)
313 			dst = do_svis(dst, c, flag, *src, nextra);
314 	}
315 	free(nextra);
316 	*dst = '\0';
317 	return (dst - start);
318 }
319 
320 
321 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_strsvisx(char * dst,const char * csrc,size_t len,int flag,const char * extra)322 rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
323 {
324 	unsigned char c;
325 	char *start;
326 	char *nextra = NULL;
327 	const unsigned char *src = (const unsigned char *)csrc;
328 
329 	_DIAGASSERT(dst != NULL);
330 	_DIAGASSERT(src != NULL);
331 	_DIAGASSERT(extra != NULL);
332 	MAKEEXTRALIST(flag, nextra, extra);
333 	if (! nextra) {
334 		*dst = '\0';		/* can't create nextra, return "" */
335 		return 0;
336 	}
337 
338 	if (flag & VIS_HTTPSTYLE) {
339 		for (start = dst; len > 0; len--) {
340 			c = *src++;
341 			dst = do_hvis(dst, c, flag, len ? *src : '\0', nextra);
342 		}
343 	} else {
344 		for (start = dst; len > 0; len--) {
345 			c = *src++;
346 			dst = do_svis(dst, c, flag, len ? *src : '\0', nextra);
347 		}
348 	}
349 	free(nextra);
350 	*dst = '\0';
351 	return (dst - start);
352 }
353 #endif
354 
355 #if !HAVE_VIS
356 /*
357  * vis - visually encode characters
358  */
359 ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
rk_vis(char * dst,int c,int flag,int nextc)360 rk_vis(char *dst, int c, int flag, int nextc)
361 {
362 	char *extra = NULL;
363 	unsigned char uc = (unsigned char)c;
364 
365 	_DIAGASSERT(dst != NULL);
366 
367 	MAKEEXTRALIST(flag, extra, "");
368 	if (! extra) {
369 		*dst = '\0';		/* can't create extra, return "" */
370 		return dst;
371 	}
372 	if (flag & VIS_HTTPSTYLE)
373 		dst = do_hvis(dst, uc, flag, nextc, extra);
374 	else
375 		dst = do_svis(dst, uc, flag, nextc, extra);
376 	free(extra);
377 	*dst = '\0';
378 	return dst;
379 }
380 
381 
382 /*
383  * strvis, strvisx - visually encode characters from src into dst
384  *
385  *	Dst must be 4 times the size of src to account for possible
386  *	expansion.  The length of dst, not including the trailing NULL,
387  *	is returned.
388  *
389  *	Strvisx encodes exactly len bytes from src into dst.
390  *	This is useful for encoding a block of data.
391  */
392 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_strvis(char * dst,const char * src,int flag)393 rk_strvis(char *dst, const char *src, int flag)
394 {
395 	char *extra = NULL;
396 	int rv;
397 
398 	MAKEEXTRALIST(flag, extra, "");
399 	if (!extra) {
400 		*dst = '\0';		/* can't create extra, return "" */
401 		return 0;
402 	}
403 	rv = strsvis(dst, src, flag, extra);
404 	free(extra);
405 	return rv;
406 }
407 
408 
409 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_strvisx(char * dst,const char * src,size_t len,int flag)410 rk_strvisx(char *dst, const char *src, size_t len, int flag)
411 {
412 	char *extra = NULL;
413 	int rv;
414 
415 	MAKEEXTRALIST(flag, extra, "");
416 	if (!extra) {
417 		*dst = '\0';		/* can't create extra, return "" */
418 		return 0;
419 	}
420 	rv = strsvisx(dst, src, len, flag, extra);
421 	free(extra);
422 	return rv;
423 }
424 #endif
425