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