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