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 * 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 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