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