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