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