xref: /freebsd/contrib/sendmail/libsm/util.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
1d0cef73dSGregory Neil Shapiro /*
25dd76dd0SGregory 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 
134313cc83SGregory 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
242fb4f839SGregory Neil Shapiro **		(except for some special chars, see below)
25d0cef73dSGregory Neil Shapiro **
26d0cef73dSGregory Neil Shapiro **	Parameters:
272fb4f839SGregory Neil Shapiro **		s -- string to convert [A]
28d0cef73dSGregory Neil Shapiro **
29d0cef73dSGregory Neil Shapiro **	Returns:
302fb4f839SGregory Neil Shapiro **		converted string [S][U]
31d0cef73dSGregory Neil Shapiro **		This is a static local buffer, string must be copied
32d0cef73dSGregory Neil Shapiro **		before this function is called again!
33d0cef73dSGregory Neil Shapiro */
34d0cef73dSGregory Neil Shapiro 
35d0cef73dSGregory Neil Shapiro char *
36d0cef73dSGregory Neil Shapiro str2prt(s)
37d0cef73dSGregory Neil Shapiro 	char *s;
38d0cef73dSGregory Neil Shapiro {
39d0cef73dSGregory Neil Shapiro 	int l;
40d0cef73dSGregory Neil Shapiro 	char c, *h;
41d0cef73dSGregory Neil Shapiro 	bool ok;
42d0cef73dSGregory Neil Shapiro 	static int len = 0;
43d0cef73dSGregory Neil Shapiro 	static char *buf = NULL;
44d0cef73dSGregory Neil Shapiro 
452fb4f839SGregory Neil Shapiro #if _FFR_LOGASIS >= 1
462fb4f839SGregory Neil Shapiro #define BADCHAR(ch)	((unsigned char)(ch) <= 31)
472fb4f839SGregory Neil Shapiro #else
482fb4f839SGregory Neil Shapiro #define BADCHAR(ch)	(!(isascii(ch) && isprint(ch)))
492fb4f839SGregory Neil Shapiro #endif
502fb4f839SGregory Neil Shapiro 
51d0cef73dSGregory Neil Shapiro 	if (s == NULL)
52d0cef73dSGregory Neil Shapiro 		return NULL;
53d0cef73dSGregory Neil Shapiro 	ok = true;
54d0cef73dSGregory Neil Shapiro 	for (h = s, l = 1; *h != '\0'; h++, l++)
55d0cef73dSGregory Neil Shapiro 	{
56d0cef73dSGregory Neil Shapiro 		if (*h == '\\')
57d0cef73dSGregory Neil Shapiro 		{
58d0cef73dSGregory Neil Shapiro 			++l;
59d0cef73dSGregory Neil Shapiro 			ok = false;
60d0cef73dSGregory Neil Shapiro 		}
612fb4f839SGregory Neil Shapiro 		else if (BADCHAR(*h))
62d0cef73dSGregory Neil Shapiro 		{
63d0cef73dSGregory Neil Shapiro 			l += 3;
64d0cef73dSGregory Neil Shapiro 			ok = false;
65d0cef73dSGregory Neil Shapiro 		}
66d0cef73dSGregory Neil Shapiro 	}
67d0cef73dSGregory Neil Shapiro 	if (ok)
68d0cef73dSGregory Neil Shapiro 		return s;
69d0cef73dSGregory Neil Shapiro 	if (l > len)
70d0cef73dSGregory Neil Shapiro 	{
71d0cef73dSGregory Neil Shapiro 		char *nbuf = sm_pmalloc_x(l);
72d0cef73dSGregory Neil Shapiro 
73d0cef73dSGregory Neil Shapiro 		if (buf != NULL)
74d0cef73dSGregory Neil Shapiro 			sm_free(buf);
75d0cef73dSGregory Neil Shapiro 		len = l;
76d0cef73dSGregory Neil Shapiro 		buf = nbuf;
77d0cef73dSGregory Neil Shapiro 	}
78d0cef73dSGregory Neil Shapiro 	for (h = buf; *s != '\0' && l > 0; s++, l--)
79d0cef73dSGregory Neil Shapiro 	{
80d0cef73dSGregory Neil Shapiro 		c = *s;
812fb4f839SGregory Neil Shapiro 		if (c != '\\' && !BADCHAR(c))
82d0cef73dSGregory Neil Shapiro 		{
83d0cef73dSGregory Neil Shapiro 			*h++ = c;
84d0cef73dSGregory Neil Shapiro 		}
85d0cef73dSGregory Neil Shapiro 		else
86d0cef73dSGregory Neil Shapiro 		{
87d0cef73dSGregory Neil Shapiro 			*h++ = '\\';
88d0cef73dSGregory Neil Shapiro 			--l;
89d0cef73dSGregory Neil Shapiro 			switch (c)
90d0cef73dSGregory Neil Shapiro 			{
91d0cef73dSGregory Neil Shapiro 			  case '\\':
92d0cef73dSGregory Neil Shapiro 				*h++ = '\\';
93d0cef73dSGregory Neil Shapiro 				break;
94d0cef73dSGregory Neil Shapiro 			  case '\t':
95d0cef73dSGregory Neil Shapiro 				*h++ = 't';
96d0cef73dSGregory Neil Shapiro 				break;
97d0cef73dSGregory Neil Shapiro 			  case '\n':
98d0cef73dSGregory Neil Shapiro 				*h++ = 'n';
99d0cef73dSGregory Neil Shapiro 				break;
100d0cef73dSGregory Neil Shapiro 			  case '\r':
101d0cef73dSGregory Neil Shapiro 				*h++ = 'r';
102d0cef73dSGregory Neil Shapiro 				break;
103d0cef73dSGregory Neil Shapiro 			  default:
104d0cef73dSGregory Neil Shapiro 				SM_ASSERT(l >= 2);
105d0cef73dSGregory Neil Shapiro 				(void) sm_snprintf(h, l, "%03o",
106d0cef73dSGregory Neil Shapiro 					(unsigned int)((unsigned char) c));
107d0cef73dSGregory Neil Shapiro 
108d0cef73dSGregory Neil Shapiro 				/*
1092fb4f839SGregory Neil Shapiro 				**  XXX since l is unsigned this may wrap
1102fb4f839SGregory Neil Shapiro 				**  around if the calculation is screwed up...
111d0cef73dSGregory Neil Shapiro 				*/
112d0cef73dSGregory Neil Shapiro 
113d0cef73dSGregory Neil Shapiro 				l -= 2;
114d0cef73dSGregory Neil Shapiro 				h += 3;
115d0cef73dSGregory Neil Shapiro 				break;
116d0cef73dSGregory Neil Shapiro 			}
117d0cef73dSGregory Neil Shapiro 		}
118d0cef73dSGregory Neil Shapiro 	}
119d0cef73dSGregory Neil Shapiro 	*h = '\0';
120d0cef73dSGregory Neil Shapiro 	buf[len - 1] = '\0';
121d0cef73dSGregory Neil Shapiro 	return buf;
122d0cef73dSGregory Neil Shapiro }
123d0cef73dSGregory Neil Shapiro 
124d0cef73dSGregory Neil Shapiro /*
125d0cef73dSGregory Neil Shapiro **  QUOTE_INTERNAL_CHARS -- do quoting of internal characters
126d0cef73dSGregory Neil Shapiro **
127d0cef73dSGregory Neil Shapiro **	Necessary to make sure that we don't have metacharacters such
128d0cef73dSGregory Neil Shapiro **	as the internal versions of "$*" or "$&" in a string.
129d0cef73dSGregory Neil Shapiro **	The input and output pointers can be the same.
130d0cef73dSGregory Neil Shapiro **
131d0cef73dSGregory Neil Shapiro **	Parameters:
1322fb4f839SGregory Neil Shapiro **		ibp -- a pointer to the string to translate [x]
1332fb4f839SGregory Neil Shapiro **		obp -- a pointer to an output buffer [i][m:A]
134d0cef73dSGregory Neil Shapiro **		bsp -- pointer to the length of the output buffer
135*d39bd2c1SGregory Neil Shapiro **		rpool -- rpool for allocations
136d0cef73dSGregory Neil Shapiro **
137d0cef73dSGregory Neil Shapiro **	Returns:
138*d39bd2c1SGregory Neil Shapiro **		A possibly new obp (if the buffer needed to grow);
139*d39bd2c1SGregory Neil Shapiro **		if it is different, *bsp will updated to the size of
140d0cef73dSGregory Neil Shapiro **		the new buffer and the caller is responsible for
141d0cef73dSGregory Neil Shapiro **		freeing the memory.
142d0cef73dSGregory Neil Shapiro */
143d0cef73dSGregory Neil Shapiro 
144d0cef73dSGregory Neil Shapiro #define SM_MM_QUOTE(ch) (((ch) & 0377) == METAQUOTE || (((ch) & 0340) == 0200))
145d0cef73dSGregory Neil Shapiro 
146d0cef73dSGregory Neil Shapiro char *
1472fb4f839SGregory Neil Shapiro #if SM_HEAP_CHECK > 2
quote_internal_chars_tagged(ibp,obp,bsp,rpool,tag,line,group)1482fb4f839SGregory Neil Shapiro quote_internal_chars_tagged
1492fb4f839SGregory Neil Shapiro #else
1502fb4f839SGregory Neil Shapiro quote_internal_chars
1512fb4f839SGregory Neil Shapiro #endif
1522fb4f839SGregory Neil Shapiro 	(ibp, obp, bsp, rpool
1532fb4f839SGregory Neil Shapiro #if SM_HEAP_CHECK > 2
1542fb4f839SGregory Neil Shapiro 	, tag, line, group
1552fb4f839SGregory Neil Shapiro #endif
1562fb4f839SGregory Neil Shapiro 	)
157d0cef73dSGregory Neil Shapiro 	char *ibp;
158d0cef73dSGregory Neil Shapiro 	char *obp;
159d0cef73dSGregory Neil Shapiro 	int *bsp;
1602fb4f839SGregory Neil Shapiro 	SM_RPOOL_T *rpool;
1612fb4f839SGregory Neil Shapiro #if SM_HEAP_CHECK > 2
1622fb4f839SGregory Neil Shapiro 	char *tag;
1632fb4f839SGregory Neil Shapiro 	int line;
1642fb4f839SGregory Neil Shapiro 	int group;
1652fb4f839SGregory Neil Shapiro #else
1662fb4f839SGregory Neil Shapiro # define tag  "quote_internal_chars"
1672fb4f839SGregory Neil Shapiro # define line 1
1682fb4f839SGregory Neil Shapiro # define group 1
1692fb4f839SGregory Neil Shapiro #endif
170d0cef73dSGregory Neil Shapiro {
171d0cef73dSGregory Neil Shapiro 	char *ip, *op;
172d0cef73dSGregory Neil Shapiro 	int bufused, olen;
173d0cef73dSGregory Neil Shapiro 	bool buffer_same, needs_quoting;
174d0cef73dSGregory Neil Shapiro 
175*d39bd2c1SGregory Neil Shapiro 	if (NULL == ibp)
176*d39bd2c1SGregory Neil Shapiro 		return NULL;
177d0cef73dSGregory Neil Shapiro 	buffer_same = ibp == obp;
178*d39bd2c1SGregory Neil Shapiro 	SM_REQUIRE(NULL != bsp);
179*d39bd2c1SGregory Neil Shapiro 	if (NULL == obp)
180*d39bd2c1SGregory Neil Shapiro 		*bsp = 0;
181d0cef73dSGregory Neil Shapiro 	needs_quoting = false;
182d0cef73dSGregory Neil Shapiro 
183d0cef73dSGregory Neil Shapiro 	/* determine length of output string (starts at 1 for trailing '\0') */
184d0cef73dSGregory Neil Shapiro 	for (ip = ibp, olen = 1; *ip != '\0'; ip++, olen++)
185d0cef73dSGregory Neil Shapiro 	{
186d0cef73dSGregory Neil Shapiro 		if (SM_MM_QUOTE(*ip))
187d0cef73dSGregory Neil Shapiro 		{
188d0cef73dSGregory Neil Shapiro 			olen++;
189d0cef73dSGregory Neil Shapiro 			needs_quoting = true;
190d0cef73dSGregory Neil Shapiro 		}
191d0cef73dSGregory Neil Shapiro 	}
192d0cef73dSGregory Neil Shapiro 
193d0cef73dSGregory Neil Shapiro 	/* is the output buffer big enough? */
194d0cef73dSGregory Neil Shapiro 	if (olen > *bsp)
195d0cef73dSGregory Neil Shapiro 	{
1962fb4f839SGregory Neil Shapiro 		obp = sm_rpool_malloc_tagged_x(rpool, olen, tag, line, group);
197d0cef73dSGregory Neil Shapiro 		buffer_same = false;
198d0cef73dSGregory Neil Shapiro 		*bsp = olen;
199d0cef73dSGregory Neil Shapiro 	}
200d0cef73dSGregory Neil Shapiro 
201d0cef73dSGregory Neil Shapiro 	/*
202d0cef73dSGregory Neil Shapiro 	**  shortcut: no change needed?
203d0cef73dSGregory Neil Shapiro 	**  Note: we don't check this first as some bozo may use the same
204d0cef73dSGregory Neil Shapiro 	**  buffers but restrict the size of the output buffer to less
205d0cef73dSGregory Neil Shapiro 	**  than the length of the input buffer in which case we need to
206d0cef73dSGregory Neil Shapiro 	**  allocate a new buffer.
207d0cef73dSGregory Neil Shapiro 	*/
208d0cef73dSGregory Neil Shapiro 
209d0cef73dSGregory Neil Shapiro 	if (!needs_quoting)
210d0cef73dSGregory Neil Shapiro 	{
211d0cef73dSGregory Neil Shapiro 		if (!buffer_same)
212d0cef73dSGregory Neil Shapiro 		{
213d0cef73dSGregory Neil Shapiro 			bufused = sm_strlcpy(obp, ibp, *bsp);
214d0cef73dSGregory Neil Shapiro 			SM_ASSERT(bufused <= olen);
215d0cef73dSGregory Neil Shapiro 		}
216d0cef73dSGregory Neil Shapiro 		return obp;
217d0cef73dSGregory Neil Shapiro 	}
218d0cef73dSGregory Neil Shapiro 
219d0cef73dSGregory Neil Shapiro 	if (buffer_same)
220d0cef73dSGregory Neil Shapiro 	{
2212fb4f839SGregory Neil Shapiro 		obp = sm_malloc_tagged_x(olen, tag, line + 1, group);
222d0cef73dSGregory Neil Shapiro 		buffer_same = false;
223d0cef73dSGregory Neil Shapiro 		*bsp = olen;
224d0cef73dSGregory Neil Shapiro 	}
225d0cef73dSGregory Neil Shapiro 
226d0cef73dSGregory Neil Shapiro 	for (ip = ibp, op = obp, bufused = 0; *ip != '\0'; ip++)
227d0cef73dSGregory Neil Shapiro 	{
228d0cef73dSGregory Neil Shapiro 		if (SM_MM_QUOTE(*ip))
229d0cef73dSGregory Neil Shapiro 		{
230d0cef73dSGregory Neil Shapiro 			SM_ASSERT(bufused < olen);
231d0cef73dSGregory Neil Shapiro 			op[bufused++] = METAQUOTE;
232d0cef73dSGregory Neil Shapiro 		}
233d0cef73dSGregory Neil Shapiro 		SM_ASSERT(bufused < olen);
234d0cef73dSGregory Neil Shapiro 		op[bufused++] = *ip;
235d0cef73dSGregory Neil Shapiro 	}
236d0cef73dSGregory Neil Shapiro 	op[bufused] = '\0';
237d0cef73dSGregory Neil Shapiro 	return obp;
238d0cef73dSGregory Neil Shapiro }
2392fb4f839SGregory Neil Shapiro #if SM_HEAP_CHECK <= 2
2402fb4f839SGregory Neil Shapiro # undef tag
2412fb4f839SGregory Neil Shapiro # undef line
2422fb4f839SGregory Neil Shapiro # undef group
2432fb4f839SGregory Neil Shapiro #endif
244d0cef73dSGregory Neil Shapiro 
245d0cef73dSGregory Neil Shapiro /*
246d0cef73dSGregory Neil Shapiro **  DEQUOTE_INTERNAL_CHARS -- undo the effect of quote_internal_chars
247d0cef73dSGregory Neil Shapiro **
248d0cef73dSGregory Neil Shapiro **	Parameters:
2492fb4f839SGregory Neil Shapiro **		ibp -- a pointer to the string to be translated. [i]
2502fb4f839SGregory Neil Shapiro **		obp -- a pointer to the output buffer. [x]
2512fb4f839SGregory Neil Shapiro **			Can be the same as ibp.
252d0cef73dSGregory Neil Shapiro **		obs -- the size of the output buffer.
253d0cef73dSGregory Neil Shapiro **
254d0cef73dSGregory Neil Shapiro **	Returns:
255d0cef73dSGregory Neil Shapiro **		number of character added to obp
256d0cef73dSGregory Neil Shapiro */
257d0cef73dSGregory Neil Shapiro 
258d0cef73dSGregory Neil Shapiro int
dequote_internal_chars(ibp,obp,obs)259d0cef73dSGregory Neil Shapiro dequote_internal_chars(ibp, obp, obs)
260d0cef73dSGregory Neil Shapiro 	char *ibp;
261d0cef73dSGregory Neil Shapiro 	char *obp;
262d0cef73dSGregory Neil Shapiro 	int obs;
263d0cef73dSGregory Neil Shapiro {
264d0cef73dSGregory Neil Shapiro 	char *ip, *op;
265d0cef73dSGregory Neil Shapiro 	int len;
266d0cef73dSGregory Neil Shapiro 	bool quoted;
267d0cef73dSGregory Neil Shapiro 
268d0cef73dSGregory Neil Shapiro 	quoted = false;
269d0cef73dSGregory Neil Shapiro 	len = 0;
270d0cef73dSGregory Neil Shapiro 	for (ip = ibp, op = obp; *ip != '\0'; ip++)
271d0cef73dSGregory Neil Shapiro 	{
272d0cef73dSGregory Neil Shapiro 		if ((*ip & 0377) == METAQUOTE && !quoted)
273d0cef73dSGregory Neil Shapiro 		{
274d0cef73dSGregory Neil Shapiro 			quoted = true;
275d0cef73dSGregory Neil Shapiro 			continue;
276d0cef73dSGregory Neil Shapiro 		}
277d0cef73dSGregory Neil Shapiro 		if (op < &obp[obs - 1])
278d0cef73dSGregory Neil Shapiro 		{
279d0cef73dSGregory Neil Shapiro 			*op++ = *ip;
280d0cef73dSGregory Neil Shapiro 			++len;
281d0cef73dSGregory Neil Shapiro 		}
282d0cef73dSGregory Neil Shapiro 		quoted = false;
283d0cef73dSGregory Neil Shapiro 	}
284d0cef73dSGregory Neil Shapiro 	*op = '\0';
285d0cef73dSGregory Neil Shapiro 	return len;
286d0cef73dSGregory Neil Shapiro }
287