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 ** 136 ** Returns: 137 ** A possibly new bp (if the buffer needed to grow); if 138 ** it is different, *bsp will updated to the size of 139 ** the new buffer and the caller is responsible for 140 ** freeing the memory. 141 */ 142 143 #define SM_MM_QUOTE(ch) (((ch) & 0377) == METAQUOTE || (((ch) & 0340) == 0200)) 144 145 char * 146 #if SM_HEAP_CHECK > 2 147 quote_internal_chars_tagged 148 #else 149 quote_internal_chars 150 #endif 151 (ibp, obp, bsp, rpool 152 #if SM_HEAP_CHECK > 2 153 , tag, line, group 154 #endif 155 ) 156 char *ibp; 157 char *obp; 158 int *bsp; 159 SM_RPOOL_T *rpool; 160 #if SM_HEAP_CHECK > 2 161 char *tag; 162 int line; 163 int group; 164 #else 165 # define tag "quote_internal_chars" 166 # define line 1 167 # define group 1 168 #endif 169 { 170 char *ip, *op; 171 int bufused, olen; 172 bool buffer_same, needs_quoting; 173 174 buffer_same = ibp == obp; 175 needs_quoting = false; 176 177 /* determine length of output string (starts at 1 for trailing '\0') */ 178 for (ip = ibp, olen = 1; *ip != '\0'; ip++, olen++) 179 { 180 if (SM_MM_QUOTE(*ip)) 181 { 182 olen++; 183 needs_quoting = true; 184 } 185 } 186 187 /* is the output buffer big enough? */ 188 if (olen > *bsp) 189 { 190 obp = sm_rpool_malloc_tagged_x(rpool, olen, tag, line, group); 191 buffer_same = false; 192 *bsp = olen; 193 } 194 195 /* 196 ** shortcut: no change needed? 197 ** Note: we don't check this first as some bozo may use the same 198 ** buffers but restrict the size of the output buffer to less 199 ** than the length of the input buffer in which case we need to 200 ** allocate a new buffer. 201 */ 202 203 if (!needs_quoting) 204 { 205 if (!buffer_same) 206 { 207 bufused = sm_strlcpy(obp, ibp, *bsp); 208 SM_ASSERT(bufused <= olen); 209 } 210 return obp; 211 } 212 213 if (buffer_same) 214 { 215 obp = sm_malloc_tagged_x(olen, tag, line + 1, group); 216 buffer_same = false; 217 *bsp = olen; 218 } 219 220 for (ip = ibp, op = obp, bufused = 0; *ip != '\0'; ip++) 221 { 222 if (SM_MM_QUOTE(*ip)) 223 { 224 SM_ASSERT(bufused < olen); 225 op[bufused++] = METAQUOTE; 226 } 227 SM_ASSERT(bufused < olen); 228 op[bufused++] = *ip; 229 } 230 op[bufused] = '\0'; 231 return obp; 232 } 233 #if SM_HEAP_CHECK <= 2 234 # undef tag 235 # undef line 236 # undef group 237 #endif 238 239 /* 240 ** DEQUOTE_INTERNAL_CHARS -- undo the effect of quote_internal_chars 241 ** 242 ** Parameters: 243 ** ibp -- a pointer to the string to be translated. [i] 244 ** obp -- a pointer to the output buffer. [x] 245 ** Can be the same as ibp. 246 ** obs -- the size of the output buffer. 247 ** 248 ** Returns: 249 ** number of character added to obp 250 */ 251 252 int 253 dequote_internal_chars(ibp, obp, obs) 254 char *ibp; 255 char *obp; 256 int obs; 257 { 258 char *ip, *op; 259 int len; 260 bool quoted; 261 262 quoted = false; 263 len = 0; 264 for (ip = ibp, op = obp; *ip != '\0'; ip++) 265 { 266 if ((*ip & 0377) == METAQUOTE && !quoted) 267 { 268 quoted = true; 269 continue; 270 } 271 if (op < &obp[obs - 1]) 272 { 273 *op++ = *ip; 274 ++len; 275 } 276 quoted = false; 277 } 278 *op = '\0'; 279 return len; 280 } 281