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