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