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