xref: /freebsd/contrib/sendmail/libsm/util.c (revision 5dd76dd0cc19450133aa379ce0ce4a68ae07fb39)
1d0cef73dSGregory Neil Shapiro /*
2*5dd76dd0SGregory Neil Shapiro  * Copyright (c) 2006 Proofpoint, Inc. and its suppliers.
3d0cef73dSGregory Neil Shapiro  *	All rights reserved.
4d0cef73dSGregory Neil Shapiro  *
5d0cef73dSGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
6d0cef73dSGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
7d0cef73dSGregory Neil Shapiro  * the sendmail distribution.
8d0cef73dSGregory Neil Shapiro  *
9d0cef73dSGregory Neil Shapiro  */
10d0cef73dSGregory Neil Shapiro 
11d0cef73dSGregory Neil Shapiro #include <sm/gen.h>
12d0cef73dSGregory Neil Shapiro 
13*5dd76dd0SGregory Neil Shapiro SM_RCSID("@(#)$Id: util.c,v 1.10 2013/11/22 20:51:44 ca Exp $")
14d0cef73dSGregory Neil Shapiro #include <sm/setjmp.h>
15d0cef73dSGregory Neil Shapiro #include <sm/conf.h>
16d0cef73dSGregory Neil Shapiro #include <sm/assert.h>
17d0cef73dSGregory Neil Shapiro #include <sm/heap.h>
18d0cef73dSGregory Neil Shapiro #include <sm/string.h>
19d0cef73dSGregory Neil Shapiro #include <sm/sendmail.h>
20d0cef73dSGregory Neil Shapiro #include <ctype.h>
21d0cef73dSGregory Neil Shapiro 
22d0cef73dSGregory Neil Shapiro /*
23d0cef73dSGregory Neil Shapiro **  STR2PRT -- convert "unprintable" characters in a string to \oct
24d0cef73dSGregory Neil Shapiro **
25d0cef73dSGregory Neil Shapiro **	Parameters:
26d0cef73dSGregory Neil Shapiro **		s -- string to convert
27d0cef73dSGregory Neil Shapiro **
28d0cef73dSGregory Neil Shapiro **	Returns:
29d0cef73dSGregory Neil Shapiro **		converted string.
30d0cef73dSGregory Neil Shapiro **		This is a static local buffer, string must be copied
31d0cef73dSGregory Neil Shapiro **		before this function is called again!
32d0cef73dSGregory Neil Shapiro */
33d0cef73dSGregory Neil Shapiro 
34d0cef73dSGregory Neil Shapiro char *
35d0cef73dSGregory Neil Shapiro str2prt(s)
36d0cef73dSGregory Neil Shapiro 	char *s;
37d0cef73dSGregory Neil Shapiro {
38d0cef73dSGregory Neil Shapiro 	int l;
39d0cef73dSGregory Neil Shapiro 	char c, *h;
40d0cef73dSGregory Neil Shapiro 	bool ok;
41d0cef73dSGregory Neil Shapiro 	static int len = 0;
42d0cef73dSGregory Neil Shapiro 	static char *buf = NULL;
43d0cef73dSGregory Neil Shapiro 
44d0cef73dSGregory Neil Shapiro 	if (s == NULL)
45d0cef73dSGregory Neil Shapiro 		return NULL;
46d0cef73dSGregory Neil Shapiro 	ok = true;
47d0cef73dSGregory Neil Shapiro 	for (h = s, l = 1; *h != '\0'; h++, l++)
48d0cef73dSGregory Neil Shapiro 	{
49d0cef73dSGregory Neil Shapiro 		if (*h == '\\')
50d0cef73dSGregory Neil Shapiro 		{
51d0cef73dSGregory Neil Shapiro 			++l;
52d0cef73dSGregory Neil Shapiro 			ok = false;
53d0cef73dSGregory Neil Shapiro 		}
54d0cef73dSGregory Neil Shapiro 		else if (!(isascii(*h) && isprint(*h)))
55d0cef73dSGregory Neil Shapiro 		{
56d0cef73dSGregory Neil Shapiro 			l += 3;
57d0cef73dSGregory Neil Shapiro 			ok = false;
58d0cef73dSGregory Neil Shapiro 		}
59d0cef73dSGregory Neil Shapiro 	}
60d0cef73dSGregory Neil Shapiro 	if (ok)
61d0cef73dSGregory Neil Shapiro 		return s;
62d0cef73dSGregory Neil Shapiro 	if (l > len)
63d0cef73dSGregory Neil Shapiro 	{
64d0cef73dSGregory Neil Shapiro 		char *nbuf = sm_pmalloc_x(l);
65d0cef73dSGregory Neil Shapiro 
66d0cef73dSGregory Neil Shapiro 		if (buf != NULL)
67d0cef73dSGregory Neil Shapiro 			sm_free(buf);
68d0cef73dSGregory Neil Shapiro 		len = l;
69d0cef73dSGregory Neil Shapiro 		buf = nbuf;
70d0cef73dSGregory Neil Shapiro 	}
71d0cef73dSGregory Neil Shapiro 	for (h = buf; *s != '\0' && l > 0; s++, l--)
72d0cef73dSGregory Neil Shapiro 	{
73d0cef73dSGregory Neil Shapiro 		c = *s;
74d0cef73dSGregory Neil Shapiro 		if (isascii(c) && isprint(c) && c != '\\')
75d0cef73dSGregory Neil Shapiro 		{
76d0cef73dSGregory Neil Shapiro 			*h++ = c;
77d0cef73dSGregory Neil Shapiro 		}
78d0cef73dSGregory Neil Shapiro 		else
79d0cef73dSGregory Neil Shapiro 		{
80d0cef73dSGregory Neil Shapiro 			*h++ = '\\';
81d0cef73dSGregory Neil Shapiro 			--l;
82d0cef73dSGregory Neil Shapiro 			switch (c)
83d0cef73dSGregory Neil Shapiro 			{
84d0cef73dSGregory Neil Shapiro 			  case '\\':
85d0cef73dSGregory Neil Shapiro 				*h++ = '\\';
86d0cef73dSGregory Neil Shapiro 				break;
87d0cef73dSGregory Neil Shapiro 			  case '\t':
88d0cef73dSGregory Neil Shapiro 				*h++ = 't';
89d0cef73dSGregory Neil Shapiro 				break;
90d0cef73dSGregory Neil Shapiro 			  case '\n':
91d0cef73dSGregory Neil Shapiro 				*h++ = 'n';
92d0cef73dSGregory Neil Shapiro 				break;
93d0cef73dSGregory Neil Shapiro 			  case '\r':
94d0cef73dSGregory Neil Shapiro 				*h++ = 'r';
95d0cef73dSGregory Neil Shapiro 				break;
96d0cef73dSGregory Neil Shapiro 			  default:
97d0cef73dSGregory Neil Shapiro 				SM_ASSERT(l >= 2);
98d0cef73dSGregory Neil Shapiro 				(void) sm_snprintf(h, l, "%03o",
99d0cef73dSGregory Neil Shapiro 					(unsigned int)((unsigned char) c));
100d0cef73dSGregory Neil Shapiro 
101d0cef73dSGregory Neil Shapiro 				/*
102d0cef73dSGregory Neil Shapiro 				**  XXX since l is unsigned this may
103d0cef73dSGregory Neil Shapiro 				**  wrap around if the calculation is screwed
104d0cef73dSGregory Neil Shapiro 				**  up...
105d0cef73dSGregory Neil Shapiro 				*/
106d0cef73dSGregory Neil Shapiro 
107d0cef73dSGregory Neil Shapiro 				l -= 2;
108d0cef73dSGregory Neil Shapiro 				h += 3;
109d0cef73dSGregory Neil Shapiro 				break;
110d0cef73dSGregory Neil Shapiro 			}
111d0cef73dSGregory Neil Shapiro 		}
112d0cef73dSGregory Neil Shapiro 	}
113d0cef73dSGregory Neil Shapiro 	*h = '\0';
114d0cef73dSGregory Neil Shapiro 	buf[len - 1] = '\0';
115d0cef73dSGregory Neil Shapiro 	return buf;
116d0cef73dSGregory Neil Shapiro }
117d0cef73dSGregory Neil Shapiro 
118d0cef73dSGregory Neil Shapiro /*
119d0cef73dSGregory Neil Shapiro **  QUOTE_INTERNAL_CHARS -- do quoting of internal characters
120d0cef73dSGregory Neil Shapiro **
121d0cef73dSGregory Neil Shapiro **	Necessary to make sure that we don't have metacharacters such
122d0cef73dSGregory Neil Shapiro **	as the internal versions of "$*" or "$&" in a string.
123d0cef73dSGregory Neil Shapiro **	The input and output pointers can be the same.
124d0cef73dSGregory Neil Shapiro **
125d0cef73dSGregory Neil Shapiro **	Parameters:
126d0cef73dSGregory Neil Shapiro **		ibp -- a pointer to the string to translate
127d0cef73dSGregory Neil Shapiro **		obp -- a pointer to an output buffer
128d0cef73dSGregory Neil Shapiro **		bsp -- pointer to the length of the output buffer
129d0cef73dSGregory Neil Shapiro **
130d0cef73dSGregory Neil Shapiro **	Returns:
131d0cef73dSGregory Neil Shapiro **		A possibly new bp (if the buffer needed to grow); if
132d0cef73dSGregory Neil Shapiro **		it is different, *bsp will updated to the size of
133d0cef73dSGregory Neil Shapiro **		the new buffer and the caller is responsible for
134d0cef73dSGregory Neil Shapiro **		freeing the memory.
135d0cef73dSGregory Neil Shapiro */
136d0cef73dSGregory Neil Shapiro 
137d0cef73dSGregory Neil Shapiro #define SM_MM_QUOTE(ch) (((ch) & 0377) == METAQUOTE || (((ch) & 0340) == 0200))
138d0cef73dSGregory Neil Shapiro 
139d0cef73dSGregory Neil Shapiro char *
140d0cef73dSGregory Neil Shapiro quote_internal_chars(ibp, obp, bsp)
141d0cef73dSGregory Neil Shapiro 	char *ibp;
142d0cef73dSGregory Neil Shapiro 	char *obp;
143d0cef73dSGregory Neil Shapiro 	int *bsp;
144d0cef73dSGregory Neil Shapiro {
145d0cef73dSGregory Neil Shapiro 	char *ip, *op;
146d0cef73dSGregory Neil Shapiro 	int bufused, olen;
147d0cef73dSGregory Neil Shapiro 	bool buffer_same, needs_quoting;
148d0cef73dSGregory Neil Shapiro 
149d0cef73dSGregory Neil Shapiro 	buffer_same = ibp == obp;
150d0cef73dSGregory Neil Shapiro 	needs_quoting = false;
151d0cef73dSGregory Neil Shapiro 
152d0cef73dSGregory Neil Shapiro 	/* determine length of output string (starts at 1 for trailing '\0') */
153d0cef73dSGregory Neil Shapiro 	for (ip = ibp, olen = 1; *ip != '\0'; ip++, olen++)
154d0cef73dSGregory Neil Shapiro 	{
155d0cef73dSGregory Neil Shapiro 		if (SM_MM_QUOTE(*ip))
156d0cef73dSGregory Neil Shapiro 		{
157d0cef73dSGregory Neil Shapiro 			olen++;
158d0cef73dSGregory Neil Shapiro 			needs_quoting = true;
159d0cef73dSGregory Neil Shapiro 		}
160d0cef73dSGregory Neil Shapiro 	}
161d0cef73dSGregory Neil Shapiro 
162d0cef73dSGregory Neil Shapiro 	/* is the output buffer big enough? */
163d0cef73dSGregory Neil Shapiro 	if (olen > *bsp)
164d0cef73dSGregory Neil Shapiro 	{
165d0cef73dSGregory Neil Shapiro 		obp = sm_malloc_x(olen);
166d0cef73dSGregory Neil Shapiro 		buffer_same = false;
167d0cef73dSGregory Neil Shapiro 		*bsp = olen;
168d0cef73dSGregory Neil Shapiro 	}
169d0cef73dSGregory Neil Shapiro 
170d0cef73dSGregory Neil Shapiro 	/*
171d0cef73dSGregory Neil Shapiro 	**  shortcut: no change needed?
172d0cef73dSGregory Neil Shapiro 	**  Note: we don't check this first as some bozo may use the same
173d0cef73dSGregory Neil Shapiro 	**  buffers but restrict the size of the output buffer to less
174d0cef73dSGregory Neil Shapiro 	**  than the length of the input buffer in which case we need to
175d0cef73dSGregory Neil Shapiro 	**  allocate a new buffer.
176d0cef73dSGregory Neil Shapiro 	*/
177d0cef73dSGregory Neil Shapiro 
178d0cef73dSGregory Neil Shapiro 	if (!needs_quoting)
179d0cef73dSGregory Neil Shapiro 	{
180d0cef73dSGregory Neil Shapiro 		if (!buffer_same)
181d0cef73dSGregory Neil Shapiro 		{
182d0cef73dSGregory Neil Shapiro 			bufused = sm_strlcpy(obp, ibp, *bsp);
183d0cef73dSGregory Neil Shapiro 			SM_ASSERT(bufused <= olen);
184d0cef73dSGregory Neil Shapiro 		}
185d0cef73dSGregory Neil Shapiro 		return obp;
186d0cef73dSGregory Neil Shapiro 	}
187d0cef73dSGregory Neil Shapiro 
188d0cef73dSGregory Neil Shapiro 	if (buffer_same)
189d0cef73dSGregory Neil Shapiro 	{
190d0cef73dSGregory Neil Shapiro 		obp = sm_malloc_x(olen);
191d0cef73dSGregory Neil Shapiro 		buffer_same = false;
192d0cef73dSGregory Neil Shapiro 		*bsp = olen;
193d0cef73dSGregory Neil Shapiro 	}
194d0cef73dSGregory Neil Shapiro 
195d0cef73dSGregory Neil Shapiro 	for (ip = ibp, op = obp, bufused = 0; *ip != '\0'; ip++)
196d0cef73dSGregory Neil Shapiro 	{
197d0cef73dSGregory Neil Shapiro 		if (SM_MM_QUOTE(*ip))
198d0cef73dSGregory Neil Shapiro 		{
199d0cef73dSGregory Neil Shapiro 			SM_ASSERT(bufused < olen);
200d0cef73dSGregory Neil Shapiro 			op[bufused++] = METAQUOTE;
201d0cef73dSGregory Neil Shapiro 		}
202d0cef73dSGregory Neil Shapiro 		SM_ASSERT(bufused < olen);
203d0cef73dSGregory Neil Shapiro 		op[bufused++] = *ip;
204d0cef73dSGregory Neil Shapiro 	}
205d0cef73dSGregory Neil Shapiro 	op[bufused] = '\0';
206d0cef73dSGregory Neil Shapiro 	return obp;
207d0cef73dSGregory Neil Shapiro }
208d0cef73dSGregory Neil Shapiro 
209d0cef73dSGregory Neil Shapiro /*
210d0cef73dSGregory Neil Shapiro **  DEQUOTE_INTERNAL_CHARS -- undo the effect of quote_internal_chars
211d0cef73dSGregory Neil Shapiro **
212d0cef73dSGregory Neil Shapiro **	Parameters:
213d0cef73dSGregory Neil Shapiro **		ibp -- a pointer to the string to be translated.
214d0cef73dSGregory Neil Shapiro **		obp -- a pointer to the output buffer.  Can be the
215d0cef73dSGregory Neil Shapiro **			same as ibp.
216d0cef73dSGregory Neil Shapiro **		obs -- the size of the output buffer.
217d0cef73dSGregory Neil Shapiro **
218d0cef73dSGregory Neil Shapiro **	Returns:
219d0cef73dSGregory Neil Shapiro **		number of character added to obp
220d0cef73dSGregory Neil Shapiro */
221d0cef73dSGregory Neil Shapiro 
222d0cef73dSGregory Neil Shapiro int
223d0cef73dSGregory Neil Shapiro dequote_internal_chars(ibp, obp, obs)
224d0cef73dSGregory Neil Shapiro 	char *ibp;
225d0cef73dSGregory Neil Shapiro 	char *obp;
226d0cef73dSGregory Neil Shapiro 	int obs;
227d0cef73dSGregory Neil Shapiro {
228d0cef73dSGregory Neil Shapiro 	char *ip, *op;
229d0cef73dSGregory Neil Shapiro 	int len;
230d0cef73dSGregory Neil Shapiro 	bool quoted;
231d0cef73dSGregory Neil Shapiro 
232d0cef73dSGregory Neil Shapiro 	quoted = false;
233d0cef73dSGregory Neil Shapiro 	len = 0;
234d0cef73dSGregory Neil Shapiro 	for (ip = ibp, op = obp; *ip != '\0'; ip++)
235d0cef73dSGregory Neil Shapiro 	{
236d0cef73dSGregory Neil Shapiro 		if ((*ip & 0377) == METAQUOTE && !quoted)
237d0cef73dSGregory Neil Shapiro 		{
238d0cef73dSGregory Neil Shapiro 			quoted = true;
239d0cef73dSGregory Neil Shapiro 			continue;
240d0cef73dSGregory Neil Shapiro 		}
241d0cef73dSGregory Neil Shapiro 		if (op < &obp[obs - 1])
242d0cef73dSGregory Neil Shapiro 		{
243d0cef73dSGregory Neil Shapiro 			*op++ = *ip;
244d0cef73dSGregory Neil Shapiro 			++len;
245d0cef73dSGregory Neil Shapiro 		}
246d0cef73dSGregory Neil Shapiro 		quoted = false;
247d0cef73dSGregory Neil Shapiro 	}
248d0cef73dSGregory Neil Shapiro 	*op = '\0';
249d0cef73dSGregory Neil Shapiro 	return len;
250d0cef73dSGregory Neil Shapiro }
251