1c2aa98e2SPeter Wemm /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2007, 2009 Proofpoint, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 1540266059SGregory Neil Shapiro 164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: util.c,v 8.427 2013-11-22 20:51:57 ca Exp $") 1740266059SGregory Neil Shapiro 18d0cef73dSGregory Neil Shapiro #include <sm/sendmail.h> 19c2aa98e2SPeter Wemm #include <sysexits.h> 2040266059SGregory Neil Shapiro #include <sm/xtrap.h> 2106f25ae9SGregory Neil Shapiro 2240266059SGregory Neil Shapiro /* 23e92d3f3fSGregory Neil Shapiro ** NEWSTR -- Create a copy of a C string 24e92d3f3fSGregory Neil Shapiro ** 25e92d3f3fSGregory Neil Shapiro ** Parameters: 26e92d3f3fSGregory Neil Shapiro ** s -- the string to copy. 27e92d3f3fSGregory Neil Shapiro ** 28e92d3f3fSGregory Neil Shapiro ** Returns: 29e92d3f3fSGregory Neil Shapiro ** pointer to newly allocated string. 30e92d3f3fSGregory Neil Shapiro */ 31e92d3f3fSGregory Neil Shapiro 32e92d3f3fSGregory Neil Shapiro char * 33e92d3f3fSGregory Neil Shapiro newstr(s) 34e92d3f3fSGregory Neil Shapiro const char *s; 35e92d3f3fSGregory Neil Shapiro { 36e92d3f3fSGregory Neil Shapiro size_t l; 37e92d3f3fSGregory Neil Shapiro char *n; 38e92d3f3fSGregory Neil Shapiro 39e92d3f3fSGregory Neil Shapiro l = strlen(s); 40e92d3f3fSGregory Neil Shapiro SM_ASSERT(l + 1 > l); 41e92d3f3fSGregory Neil Shapiro n = xalloc(l + 1); 42e92d3f3fSGregory Neil Shapiro sm_strlcpy(n, s, l + 1); 43e92d3f3fSGregory Neil Shapiro return n; 44e92d3f3fSGregory Neil Shapiro } 45e92d3f3fSGregory Neil Shapiro 46e92d3f3fSGregory Neil Shapiro /* 47c2aa98e2SPeter Wemm ** ADDQUOTES -- Adds quotes & quote bits to a string. 48c2aa98e2SPeter Wemm ** 4940266059SGregory Neil Shapiro ** Runs through a string and adds backslashes and quote bits. 50c2aa98e2SPeter Wemm ** 51c2aa98e2SPeter Wemm ** Parameters: 52c2aa98e2SPeter Wemm ** s -- the string to modify. 5340266059SGregory Neil Shapiro ** rpool -- resource pool from which to allocate result 54c2aa98e2SPeter Wemm ** 55c2aa98e2SPeter Wemm ** Returns: 56c2aa98e2SPeter Wemm ** pointer to quoted string. 57c2aa98e2SPeter Wemm */ 58c2aa98e2SPeter Wemm 59c2aa98e2SPeter Wemm char * 6040266059SGregory Neil Shapiro addquotes(s, rpool) 61c2aa98e2SPeter Wemm char *s; 6240266059SGregory Neil Shapiro SM_RPOOL_T *rpool; 63c2aa98e2SPeter Wemm { 64c2aa98e2SPeter Wemm int len = 0; 65c2aa98e2SPeter Wemm char c; 66c2aa98e2SPeter Wemm char *p = s, *q, *r; 67c2aa98e2SPeter Wemm 68c2aa98e2SPeter Wemm if (s == NULL) 69c2aa98e2SPeter Wemm return NULL; 70c2aa98e2SPeter Wemm 71c2aa98e2SPeter Wemm /* Find length of quoted string */ 72c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 73c2aa98e2SPeter Wemm { 74c2aa98e2SPeter Wemm len++; 75c2aa98e2SPeter Wemm if (c == '\\' || c == '"') 76c2aa98e2SPeter Wemm len++; 77c2aa98e2SPeter Wemm } 78c2aa98e2SPeter Wemm 7940266059SGregory Neil Shapiro q = r = sm_rpool_malloc_x(rpool, len + 3); 80c2aa98e2SPeter Wemm p = s; 81c2aa98e2SPeter Wemm 82c2aa98e2SPeter Wemm /* add leading quote */ 83c2aa98e2SPeter Wemm *q++ = '"'; 84c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 85c2aa98e2SPeter Wemm { 86c2aa98e2SPeter Wemm /* quote \ or " */ 87c2aa98e2SPeter Wemm if (c == '\\' || c == '"') 88c2aa98e2SPeter Wemm *q++ = '\\'; 89c2aa98e2SPeter Wemm *q++ = c; 90c2aa98e2SPeter Wemm } 91c2aa98e2SPeter Wemm *q++ = '"'; 92c2aa98e2SPeter Wemm *q = '\0'; 93c2aa98e2SPeter Wemm return r; 94c2aa98e2SPeter Wemm } 9513bd1963SGregory Neil Shapiro 9613bd1963SGregory Neil Shapiro /* 97b6bacd31SGregory Neil Shapiro ** STRIPBACKSLASH -- Strip all leading backslashes from a string, provided 98b6bacd31SGregory Neil Shapiro ** the following character is alpha-numerical. 9913bd1963SGregory Neil Shapiro ** 10013bd1963SGregory Neil Shapiro ** This is done in place. 10113bd1963SGregory Neil Shapiro ** 10213bd1963SGregory Neil Shapiro ** Parameters: 10313bd1963SGregory Neil Shapiro ** s -- the string to strip. 10413bd1963SGregory Neil Shapiro ** 10513bd1963SGregory Neil Shapiro ** Returns: 10613bd1963SGregory Neil Shapiro ** none. 10713bd1963SGregory Neil Shapiro */ 10813bd1963SGregory Neil Shapiro 10913bd1963SGregory Neil Shapiro void 11013bd1963SGregory Neil Shapiro stripbackslash(s) 11113bd1963SGregory Neil Shapiro char *s; 11213bd1963SGregory Neil Shapiro { 11313bd1963SGregory Neil Shapiro char *p, *q, c; 11413bd1963SGregory Neil Shapiro 11513bd1963SGregory Neil Shapiro if (s == NULL || *s == '\0') 11613bd1963SGregory Neil Shapiro return; 11713bd1963SGregory Neil Shapiro p = q = s; 11813bd1963SGregory Neil Shapiro while (*p == '\\' && (p[1] == '\\' || (isascii(p[1]) && isalnum(p[1])))) 11913bd1963SGregory Neil Shapiro p++; 12013bd1963SGregory Neil Shapiro do 12113bd1963SGregory Neil Shapiro { 12213bd1963SGregory Neil Shapiro c = *q++ = *p++; 12313bd1963SGregory Neil Shapiro } while (c != '\0'); 12413bd1963SGregory Neil Shapiro } 12513bd1963SGregory Neil Shapiro 12640266059SGregory Neil Shapiro /* 127c2aa98e2SPeter Wemm ** RFC822_STRING -- Checks string for proper RFC822 string quoting. 128c2aa98e2SPeter Wemm ** 129c2aa98e2SPeter Wemm ** Runs through a string and verifies RFC822 special characters 130c2aa98e2SPeter Wemm ** are only found inside comments, quoted strings, or backslash 131c2aa98e2SPeter Wemm ** escaped. Also verified balanced quotes and parenthesis. 132c2aa98e2SPeter Wemm ** 133c2aa98e2SPeter Wemm ** Parameters: 134c2aa98e2SPeter Wemm ** s -- the string to modify. 135c2aa98e2SPeter Wemm ** 136c2aa98e2SPeter Wemm ** Returns: 13740266059SGregory Neil Shapiro ** true iff the string is RFC822 compliant, false otherwise. 138c2aa98e2SPeter Wemm */ 139c2aa98e2SPeter Wemm 140c2aa98e2SPeter Wemm bool 141c2aa98e2SPeter Wemm rfc822_string(s) 142c2aa98e2SPeter Wemm char *s; 143c2aa98e2SPeter Wemm { 14440266059SGregory Neil Shapiro bool quoted = false; 145c2aa98e2SPeter Wemm int commentlev = 0; 146c2aa98e2SPeter Wemm char *c = s; 147c2aa98e2SPeter Wemm 148c2aa98e2SPeter Wemm if (s == NULL) 14940266059SGregory Neil Shapiro return false; 150c2aa98e2SPeter Wemm 151c2aa98e2SPeter Wemm while (*c != '\0') 152c2aa98e2SPeter Wemm { 153c2aa98e2SPeter Wemm /* escaped character */ 154c2aa98e2SPeter Wemm if (*c == '\\') 155c2aa98e2SPeter Wemm { 156c2aa98e2SPeter Wemm c++; 157c2aa98e2SPeter Wemm if (*c == '\0') 15840266059SGregory Neil Shapiro return false; 159c2aa98e2SPeter Wemm } 160c2aa98e2SPeter Wemm else if (commentlev == 0 && *c == '"') 161c2aa98e2SPeter Wemm quoted = !quoted; 162c2aa98e2SPeter Wemm else if (!quoted) 163c2aa98e2SPeter Wemm { 164c2aa98e2SPeter Wemm if (*c == ')') 165c2aa98e2SPeter Wemm { 166c2aa98e2SPeter Wemm /* unbalanced ')' */ 167c2aa98e2SPeter Wemm if (commentlev == 0) 16840266059SGregory Neil Shapiro return false; 169c2aa98e2SPeter Wemm else 170c2aa98e2SPeter Wemm commentlev--; 171c2aa98e2SPeter Wemm } 172c2aa98e2SPeter Wemm else if (*c == '(') 173c2aa98e2SPeter Wemm commentlev++; 174c2aa98e2SPeter Wemm else if (commentlev == 0 && 175c2aa98e2SPeter Wemm strchr(MustQuoteChars, *c) != NULL) 17640266059SGregory Neil Shapiro return false; 177c2aa98e2SPeter Wemm } 178c2aa98e2SPeter Wemm c++; 179c2aa98e2SPeter Wemm } 18040266059SGregory Neil Shapiro 181c2aa98e2SPeter Wemm /* unbalanced '"' or '(' */ 18240266059SGregory Neil Shapiro return !quoted && commentlev == 0; 183c2aa98e2SPeter Wemm } 184d0cef73dSGregory Neil Shapiro 18540266059SGregory Neil Shapiro /* 186065a643dSPeter Wemm ** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string 187065a643dSPeter Wemm ** 18806f25ae9SGregory Neil Shapiro ** Arbitrarily shorten (in place) an RFC822 string and rebalance 189065a643dSPeter Wemm ** comments and quotes. 190065a643dSPeter Wemm ** 191065a643dSPeter Wemm ** Parameters: 192065a643dSPeter Wemm ** string -- the string to shorten 193065a643dSPeter Wemm ** length -- the maximum size, 0 if no maximum 194065a643dSPeter Wemm ** 195065a643dSPeter Wemm ** Returns: 19640266059SGregory Neil Shapiro ** true if string is changed, false otherwise 197065a643dSPeter Wemm ** 198065a643dSPeter Wemm ** Side Effects: 199065a643dSPeter Wemm ** Changes string in place, possibly resulting 200065a643dSPeter Wemm ** in a shorter string. 201065a643dSPeter Wemm */ 202065a643dSPeter Wemm 203065a643dSPeter Wemm bool 204065a643dSPeter Wemm shorten_rfc822_string(string, length) 205065a643dSPeter Wemm char *string; 206065a643dSPeter Wemm size_t length; 207065a643dSPeter Wemm { 20840266059SGregory Neil Shapiro bool backslash = false; 20940266059SGregory Neil Shapiro bool modified = false; 21040266059SGregory Neil Shapiro bool quoted = false; 211065a643dSPeter Wemm size_t slen; 212065a643dSPeter Wemm int parencount = 0; 213065a643dSPeter Wemm char *ptr = string; 214065a643dSPeter Wemm 215065a643dSPeter Wemm /* 216065a643dSPeter Wemm ** If have to rebalance an already short enough string, 217065a643dSPeter Wemm ** need to do it within allocated space. 218065a643dSPeter Wemm */ 219193538b7SGregory Neil Shapiro 220065a643dSPeter Wemm slen = strlen(string); 221065a643dSPeter Wemm if (length == 0 || slen < length) 222065a643dSPeter Wemm length = slen; 223065a643dSPeter Wemm 224065a643dSPeter Wemm while (*ptr != '\0') 225065a643dSPeter Wemm { 226065a643dSPeter Wemm if (backslash) 227065a643dSPeter Wemm { 22840266059SGregory Neil Shapiro backslash = false; 229065a643dSPeter Wemm goto increment; 230065a643dSPeter Wemm } 231065a643dSPeter Wemm 232065a643dSPeter Wemm if (*ptr == '\\') 23340266059SGregory Neil Shapiro backslash = true; 234065a643dSPeter Wemm else if (*ptr == '(') 235065a643dSPeter Wemm { 236065a643dSPeter Wemm if (!quoted) 237065a643dSPeter Wemm parencount++; 238065a643dSPeter Wemm } 239065a643dSPeter Wemm else if (*ptr == ')') 240065a643dSPeter Wemm { 241065a643dSPeter Wemm if (--parencount < 0) 242065a643dSPeter Wemm parencount = 0; 243065a643dSPeter Wemm } 244065a643dSPeter Wemm 245065a643dSPeter Wemm /* Inside a comment, quotes don't matter */ 246065a643dSPeter Wemm if (parencount <= 0 && *ptr == '"') 247065a643dSPeter Wemm quoted = !quoted; 248065a643dSPeter Wemm 249065a643dSPeter Wemm increment: 250065a643dSPeter Wemm /* Check for sufficient space for next character */ 25106f25ae9SGregory Neil Shapiro if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) + 252065a643dSPeter Wemm parencount + 253065a643dSPeter Wemm (quoted ? 1 : 0))) 254065a643dSPeter Wemm { 255065a643dSPeter Wemm /* Not enough, backtrack */ 256065a643dSPeter Wemm if (*ptr == '\\') 25740266059SGregory Neil Shapiro backslash = false; 258065a643dSPeter Wemm else if (*ptr == '(' && !quoted) 259065a643dSPeter Wemm parencount--; 260065a643dSPeter Wemm else if (*ptr == '"' && parencount == 0) 26140266059SGregory Neil Shapiro quoted = false; 262065a643dSPeter Wemm break; 263065a643dSPeter Wemm } 264065a643dSPeter Wemm ptr++; 265065a643dSPeter Wemm } 266065a643dSPeter Wemm 267065a643dSPeter Wemm /* Rebalance */ 268065a643dSPeter Wemm while (parencount-- > 0) 269065a643dSPeter Wemm { 270065a643dSPeter Wemm if (*ptr != ')') 271065a643dSPeter Wemm { 27240266059SGregory Neil Shapiro modified = true; 273065a643dSPeter Wemm *ptr = ')'; 274065a643dSPeter Wemm } 275065a643dSPeter Wemm ptr++; 276065a643dSPeter Wemm } 277065a643dSPeter Wemm if (quoted) 278065a643dSPeter Wemm { 279065a643dSPeter Wemm if (*ptr != '"') 280065a643dSPeter Wemm { 28140266059SGregory Neil Shapiro modified = true; 282065a643dSPeter Wemm *ptr = '"'; 283065a643dSPeter Wemm } 284065a643dSPeter Wemm ptr++; 285065a643dSPeter Wemm } 286065a643dSPeter Wemm if (*ptr != '\0') 287065a643dSPeter Wemm { 28840266059SGregory Neil Shapiro modified = true; 289065a643dSPeter Wemm *ptr = '\0'; 290065a643dSPeter Wemm } 291065a643dSPeter Wemm return modified; 292065a643dSPeter Wemm } 293d0cef73dSGregory Neil Shapiro 29440266059SGregory Neil Shapiro /* 295065a643dSPeter Wemm ** FIND_CHARACTER -- find an unquoted character in an RFC822 string 296065a643dSPeter Wemm ** 297065a643dSPeter Wemm ** Find an unquoted, non-commented character in an RFC822 298065a643dSPeter Wemm ** string and return a pointer to its location in the 299065a643dSPeter Wemm ** string. 300065a643dSPeter Wemm ** 301065a643dSPeter Wemm ** Parameters: 302065a643dSPeter Wemm ** string -- the string to search 303065a643dSPeter Wemm ** character -- the character to find 304065a643dSPeter Wemm ** 305065a643dSPeter Wemm ** Returns: 306065a643dSPeter Wemm ** pointer to the character, or 307065a643dSPeter Wemm ** a pointer to the end of the line if character is not found 308065a643dSPeter Wemm */ 309065a643dSPeter Wemm 310065a643dSPeter Wemm char * 311065a643dSPeter Wemm find_character(string, character) 312065a643dSPeter Wemm char *string; 31306f25ae9SGregory Neil Shapiro int character; 314065a643dSPeter Wemm { 31540266059SGregory Neil Shapiro bool backslash = false; 31640266059SGregory Neil Shapiro bool quoted = false; 317065a643dSPeter Wemm int parencount = 0; 318065a643dSPeter Wemm 319065a643dSPeter Wemm while (string != NULL && *string != '\0') 320065a643dSPeter Wemm { 321065a643dSPeter Wemm if (backslash) 322065a643dSPeter Wemm { 32340266059SGregory Neil Shapiro backslash = false; 324065a643dSPeter Wemm if (!quoted && character == '\\' && *string == '\\') 325065a643dSPeter Wemm break; 326065a643dSPeter Wemm string++; 327065a643dSPeter Wemm continue; 328065a643dSPeter Wemm } 329065a643dSPeter Wemm switch (*string) 330065a643dSPeter Wemm { 331065a643dSPeter Wemm case '\\': 33240266059SGregory Neil Shapiro backslash = true; 333065a643dSPeter Wemm break; 334065a643dSPeter Wemm 335065a643dSPeter Wemm case '(': 336065a643dSPeter Wemm if (!quoted) 337065a643dSPeter Wemm parencount++; 338065a643dSPeter Wemm break; 339065a643dSPeter Wemm 340065a643dSPeter Wemm case ')': 341065a643dSPeter Wemm if (--parencount < 0) 342065a643dSPeter Wemm parencount = 0; 343065a643dSPeter Wemm break; 344065a643dSPeter Wemm } 345065a643dSPeter Wemm 346065a643dSPeter Wemm /* Inside a comment, nothing matters */ 347065a643dSPeter Wemm if (parencount > 0) 348065a643dSPeter Wemm { 349065a643dSPeter Wemm string++; 350065a643dSPeter Wemm continue; 351065a643dSPeter Wemm } 352065a643dSPeter Wemm 353065a643dSPeter Wemm if (*string == '"') 354065a643dSPeter Wemm quoted = !quoted; 355065a643dSPeter Wemm else if (*string == character && !quoted) 356065a643dSPeter Wemm break; 357065a643dSPeter Wemm string++; 358065a643dSPeter Wemm } 359065a643dSPeter Wemm 360065a643dSPeter Wemm /* Return pointer to the character */ 361065a643dSPeter Wemm return string; 362065a643dSPeter Wemm } 36340266059SGregory Neil Shapiro 36440266059SGregory Neil Shapiro /* 36540266059SGregory Neil Shapiro ** CHECK_BODYTYPE -- check bodytype parameter 366c2aa98e2SPeter Wemm ** 36740266059SGregory Neil Shapiro ** Parameters: 36840266059SGregory Neil Shapiro ** bodytype -- bodytype parameter 36940266059SGregory Neil Shapiro ** 37040266059SGregory Neil Shapiro ** Returns: 37140266059SGregory Neil Shapiro ** BODYTYPE_* according to parameter 37240266059SGregory Neil Shapiro ** 37340266059SGregory Neil Shapiro */ 37440266059SGregory Neil Shapiro 37540266059SGregory Neil Shapiro int 37640266059SGregory Neil Shapiro check_bodytype(bodytype) 37740266059SGregory Neil Shapiro char *bodytype; 37840266059SGregory Neil Shapiro { 37940266059SGregory Neil Shapiro /* check body type for legality */ 38040266059SGregory Neil Shapiro if (bodytype == NULL) 38140266059SGregory Neil Shapiro return BODYTYPE_NONE; 38240266059SGregory Neil Shapiro if (sm_strcasecmp(bodytype, "7BIT") == 0) 38340266059SGregory Neil Shapiro return BODYTYPE_7BIT; 38440266059SGregory Neil Shapiro if (sm_strcasecmp(bodytype, "8BITMIME") == 0) 38540266059SGregory Neil Shapiro return BODYTYPE_8BITMIME; 38640266059SGregory Neil Shapiro return BODYTYPE_ILLEGAL; 38740266059SGregory Neil Shapiro } 38840266059SGregory Neil Shapiro 38940266059SGregory Neil Shapiro /* 39040266059SGregory Neil Shapiro ** TRUNCATE_AT_DELIM -- truncate string at a delimiter and append "..." 39140266059SGregory Neil Shapiro ** 39240266059SGregory Neil Shapiro ** Parameters: 39340266059SGregory Neil Shapiro ** str -- string to truncate 39440266059SGregory Neil Shapiro ** len -- maximum length (including '\0') (0 for unlimited) 39540266059SGregory Neil Shapiro ** delim -- delimiter character 39640266059SGregory Neil Shapiro ** 39740266059SGregory Neil Shapiro ** Returns: 39840266059SGregory Neil Shapiro ** None. 39940266059SGregory Neil Shapiro */ 40040266059SGregory Neil Shapiro 40140266059SGregory Neil Shapiro void 40240266059SGregory Neil Shapiro truncate_at_delim(str, len, delim) 40340266059SGregory Neil Shapiro char *str; 40440266059SGregory Neil Shapiro size_t len; 40540266059SGregory Neil Shapiro int delim; 40640266059SGregory Neil Shapiro { 40740266059SGregory Neil Shapiro char *p; 40840266059SGregory Neil Shapiro 40940266059SGregory Neil Shapiro if (str == NULL || len == 0 || strlen(str) < len) 41040266059SGregory Neil Shapiro return; 41140266059SGregory Neil Shapiro 41240266059SGregory Neil Shapiro *(str + len - 1) = '\0'; 41340266059SGregory Neil Shapiro while ((p = strrchr(str, delim)) != NULL) 41440266059SGregory Neil Shapiro { 41540266059SGregory Neil Shapiro *p = '\0'; 41640266059SGregory Neil Shapiro if (p - str + 4 < len) 41740266059SGregory Neil Shapiro { 418a7ec597cSGregory Neil Shapiro *p++ = (char) delim; 41940266059SGregory Neil Shapiro *p = '\0'; 42040266059SGregory Neil Shapiro (void) sm_strlcat(str, "...", len); 42140266059SGregory Neil Shapiro return; 42240266059SGregory Neil Shapiro } 42340266059SGregory Neil Shapiro } 42440266059SGregory Neil Shapiro 42540266059SGregory Neil Shapiro /* Couldn't find a place to append "..." */ 42640266059SGregory Neil Shapiro if (len > 3) 42740266059SGregory Neil Shapiro (void) sm_strlcpy(str, "...", len); 42840266059SGregory Neil Shapiro else 42940266059SGregory Neil Shapiro str[0] = '\0'; 43040266059SGregory Neil Shapiro } 431d0cef73dSGregory Neil Shapiro 43240266059SGregory Neil Shapiro /* 43340266059SGregory Neil Shapiro ** XALLOC -- Allocate memory, raise an exception on error 434c2aa98e2SPeter Wemm ** 435c2aa98e2SPeter Wemm ** Parameters: 436c2aa98e2SPeter Wemm ** sz -- size of area to allocate. 437c2aa98e2SPeter Wemm ** 438c2aa98e2SPeter Wemm ** Returns: 439c2aa98e2SPeter Wemm ** pointer to data region. 440c2aa98e2SPeter Wemm ** 44140266059SGregory Neil Shapiro ** Exceptions: 44240266059SGregory Neil Shapiro ** SmHeapOutOfMemory (F:sm.heap) -- cannot allocate memory 44340266059SGregory Neil Shapiro ** 444c2aa98e2SPeter Wemm ** Side Effects: 445c2aa98e2SPeter Wemm ** Memory is allocated. 446c2aa98e2SPeter Wemm */ 447c2aa98e2SPeter Wemm 448c2aa98e2SPeter Wemm char * 44940266059SGregory Neil Shapiro #if SM_HEAP_CHECK 45040266059SGregory Neil Shapiro xalloc_tagged(sz, file, line) 45140266059SGregory Neil Shapiro register int sz; 45240266059SGregory Neil Shapiro char *file; 45340266059SGregory Neil Shapiro int line; 45440266059SGregory Neil Shapiro #else /* SM_HEAP_CHECK */ 455c2aa98e2SPeter Wemm xalloc(sz) 456c2aa98e2SPeter Wemm register int sz; 45740266059SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */ 458c2aa98e2SPeter Wemm { 459c2aa98e2SPeter Wemm register char *p; 460c2aa98e2SPeter Wemm 4614e4196cbSGregory Neil Shapiro SM_REQUIRE(sz >= 0); 4624e4196cbSGregory Neil Shapiro 463c2aa98e2SPeter Wemm /* some systems can't handle size zero mallocs */ 464c2aa98e2SPeter Wemm if (sz <= 0) 465c2aa98e2SPeter Wemm sz = 1; 466c2aa98e2SPeter Wemm 46740266059SGregory Neil Shapiro /* scaffolding for testing error handling code */ 46840266059SGregory Neil Shapiro sm_xtrap_raise_x(&SmHeapOutOfMemory); 46940266059SGregory Neil Shapiro 47040266059SGregory Neil Shapiro p = sm_malloc_tagged((unsigned) sz, file, line, sm_heap_group()); 471c2aa98e2SPeter Wemm if (p == NULL) 472c2aa98e2SPeter Wemm { 47340266059SGregory Neil Shapiro sm_exc_raise_x(&SmHeapOutOfMemory); 474c2aa98e2SPeter Wemm } 47506f25ae9SGregory Neil Shapiro return p; 476c2aa98e2SPeter Wemm } 477d0cef73dSGregory Neil Shapiro 47840266059SGregory Neil Shapiro /* 479c2aa98e2SPeter Wemm ** COPYPLIST -- copy list of pointers. 480c2aa98e2SPeter Wemm ** 48140266059SGregory Neil Shapiro ** This routine is the equivalent of strdup for lists of 482c2aa98e2SPeter Wemm ** pointers. 483c2aa98e2SPeter Wemm ** 484c2aa98e2SPeter Wemm ** Parameters: 485c2aa98e2SPeter Wemm ** list -- list of pointers to copy. 486c2aa98e2SPeter Wemm ** Must be NULL terminated. 48740266059SGregory Neil Shapiro ** copycont -- if true, copy the contents of the vector 488c2aa98e2SPeter Wemm ** (which must be a string) also. 48940266059SGregory Neil Shapiro ** rpool -- resource pool from which to allocate storage, 49040266059SGregory Neil Shapiro ** or NULL 491c2aa98e2SPeter Wemm ** 492c2aa98e2SPeter Wemm ** Returns: 493c2aa98e2SPeter Wemm ** a copy of 'list'. 494c2aa98e2SPeter Wemm */ 495c2aa98e2SPeter Wemm 496c2aa98e2SPeter Wemm char ** 49740266059SGregory Neil Shapiro copyplist(list, copycont, rpool) 498c2aa98e2SPeter Wemm char **list; 499c2aa98e2SPeter Wemm bool copycont; 50040266059SGregory Neil Shapiro SM_RPOOL_T *rpool; 501c2aa98e2SPeter Wemm { 502c2aa98e2SPeter Wemm register char **vp; 503c2aa98e2SPeter Wemm register char **newvp; 504c2aa98e2SPeter Wemm 505c2aa98e2SPeter Wemm for (vp = list; *vp != NULL; vp++) 506c2aa98e2SPeter Wemm continue; 507c2aa98e2SPeter Wemm 508c2aa98e2SPeter Wemm vp++; 509c2aa98e2SPeter Wemm 510d0cef73dSGregory Neil Shapiro newvp = (char **) sm_rpool_malloc_x(rpool, (vp - list) * sizeof(*vp)); 511d0cef73dSGregory Neil Shapiro memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof(*vp)); 512c2aa98e2SPeter Wemm 513c2aa98e2SPeter Wemm if (copycont) 514c2aa98e2SPeter Wemm { 515c2aa98e2SPeter Wemm for (vp = newvp; *vp != NULL; vp++) 51640266059SGregory Neil Shapiro *vp = sm_rpool_strdup_x(rpool, *vp); 517c2aa98e2SPeter Wemm } 518c2aa98e2SPeter Wemm 51906f25ae9SGregory Neil Shapiro return newvp; 520c2aa98e2SPeter Wemm } 521d0cef73dSGregory Neil Shapiro 52240266059SGregory Neil Shapiro /* 523c2aa98e2SPeter Wemm ** COPYQUEUE -- copy address queue. 524c2aa98e2SPeter Wemm ** 52540266059SGregory Neil Shapiro ** This routine is the equivalent of strdup for address queues; 52606f25ae9SGregory Neil Shapiro ** addresses marked as QS_IS_DEAD() aren't copied 527c2aa98e2SPeter Wemm ** 528c2aa98e2SPeter Wemm ** Parameters: 529c2aa98e2SPeter Wemm ** addr -- list of address structures to copy. 53040266059SGregory Neil Shapiro ** rpool -- resource pool from which to allocate storage 531c2aa98e2SPeter Wemm ** 532c2aa98e2SPeter Wemm ** Returns: 533c2aa98e2SPeter Wemm ** a copy of 'addr'. 534c2aa98e2SPeter Wemm */ 535c2aa98e2SPeter Wemm 536c2aa98e2SPeter Wemm ADDRESS * 53740266059SGregory Neil Shapiro copyqueue(addr, rpool) 538c2aa98e2SPeter Wemm ADDRESS *addr; 53940266059SGregory Neil Shapiro SM_RPOOL_T *rpool; 540c2aa98e2SPeter Wemm { 541c2aa98e2SPeter Wemm register ADDRESS *newaddr; 542c2aa98e2SPeter Wemm ADDRESS *ret; 543c2aa98e2SPeter Wemm register ADDRESS **tail = &ret; 544c2aa98e2SPeter Wemm 545c2aa98e2SPeter Wemm while (addr != NULL) 546c2aa98e2SPeter Wemm { 54706f25ae9SGregory Neil Shapiro if (!QS_IS_DEAD(addr->q_state)) 548c2aa98e2SPeter Wemm { 54940266059SGregory Neil Shapiro newaddr = (ADDRESS *) sm_rpool_malloc_x(rpool, 550d0cef73dSGregory Neil Shapiro sizeof(*newaddr)); 551c2aa98e2SPeter Wemm STRUCTCOPY(*addr, *newaddr); 552c2aa98e2SPeter Wemm *tail = newaddr; 553c2aa98e2SPeter Wemm tail = &newaddr->q_next; 554c2aa98e2SPeter Wemm } 555c2aa98e2SPeter Wemm addr = addr->q_next; 556c2aa98e2SPeter Wemm } 557c2aa98e2SPeter Wemm *tail = NULL; 558c2aa98e2SPeter Wemm 559c2aa98e2SPeter Wemm return ret; 560c2aa98e2SPeter Wemm } 561d0cef73dSGregory Neil Shapiro 56240266059SGregory Neil Shapiro /* 56306f25ae9SGregory Neil Shapiro ** LOG_SENDMAIL_PID -- record sendmail pid and command line. 56406f25ae9SGregory Neil Shapiro ** 56506f25ae9SGregory Neil Shapiro ** Parameters: 56606f25ae9SGregory Neil Shapiro ** e -- the current envelope. 56706f25ae9SGregory Neil Shapiro ** 56806f25ae9SGregory Neil Shapiro ** Returns: 56906f25ae9SGregory Neil Shapiro ** none. 57006f25ae9SGregory Neil Shapiro ** 57106f25ae9SGregory Neil Shapiro ** Side Effects: 57240266059SGregory Neil Shapiro ** writes pidfile, logs command line. 573e92d3f3fSGregory Neil Shapiro ** keeps file open and locked to prevent overwrite of active file 57406f25ae9SGregory Neil Shapiro */ 57506f25ae9SGregory Neil Shapiro 576e92d3f3fSGregory Neil Shapiro static SM_FILE_T *Pidf = NULL; 577e92d3f3fSGregory Neil Shapiro 57806f25ae9SGregory Neil Shapiro void 57906f25ae9SGregory Neil Shapiro log_sendmail_pid(e) 58006f25ae9SGregory Neil Shapiro ENVELOPE *e; 58106f25ae9SGregory Neil Shapiro { 58206f25ae9SGregory Neil Shapiro long sff; 58394c01205SGregory Neil Shapiro char pidpath[MAXPATHLEN]; 58440266059SGregory Neil Shapiro extern char *CommandLineArgs; 58506f25ae9SGregory Neil Shapiro 58606f25ae9SGregory Neil Shapiro /* write the pid to the log file for posterity */ 587e92d3f3fSGregory Neil Shapiro sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT|SFF_NBLOCK; 58806f25ae9SGregory Neil Shapiro if (TrustedUid != 0 && RealUid == TrustedUid) 58906f25ae9SGregory Neil Shapiro sff |= SFF_OPENASROOT; 590d0cef73dSGregory Neil Shapiro expand(PidFile, pidpath, sizeof(pidpath), e); 591e92d3f3fSGregory Neil Shapiro Pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, FileMode, sff); 592e92d3f3fSGregory Neil Shapiro if (Pidf == NULL) 59306f25ae9SGregory Neil Shapiro { 594e92d3f3fSGregory Neil Shapiro if (errno == EWOULDBLOCK) 595e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 596e92d3f3fSGregory Neil Shapiro "unable to write pid to %s: file in use by another process", 597e92d3f3fSGregory Neil Shapiro pidpath); 598e92d3f3fSGregory Neil Shapiro else 599e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 600e92d3f3fSGregory Neil Shapiro "unable to write pid to %s: %s", 60140266059SGregory Neil Shapiro pidpath, sm_errstring(errno)); 60206f25ae9SGregory Neil Shapiro } 60306f25ae9SGregory Neil Shapiro else 60406f25ae9SGregory Neil Shapiro { 605e92d3f3fSGregory Neil Shapiro PidFilePid = getpid(); 606193538b7SGregory Neil Shapiro 60706f25ae9SGregory Neil Shapiro /* write the process id on line 1 */ 608e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%ld\n", 609e92d3f3fSGregory Neil Shapiro (long) PidFilePid); 61006f25ae9SGregory Neil Shapiro 61106f25ae9SGregory Neil Shapiro /* line 2 contains all command line flags */ 612e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%s\n", 61340266059SGregory Neil Shapiro CommandLineArgs); 61406f25ae9SGregory Neil Shapiro 615e92d3f3fSGregory Neil Shapiro /* flush */ 616e92d3f3fSGregory Neil Shapiro (void) sm_io_flush(Pidf, SM_TIME_DEFAULT); 617e92d3f3fSGregory Neil Shapiro 618e92d3f3fSGregory Neil Shapiro /* 619e92d3f3fSGregory Neil Shapiro ** Leave pid file open until process ends 620e92d3f3fSGregory Neil Shapiro ** so it's not overwritten by another 621e92d3f3fSGregory Neil Shapiro ** process. 622e92d3f3fSGregory Neil Shapiro */ 62306f25ae9SGregory Neil Shapiro } 62440266059SGregory Neil Shapiro if (LogLevel > 9) 62540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "started as: %s", CommandLineArgs); 62606f25ae9SGregory Neil Shapiro } 627e92d3f3fSGregory Neil Shapiro 628e92d3f3fSGregory Neil Shapiro /* 629e92d3f3fSGregory Neil Shapiro ** CLOSE_SENDMAIL_PID -- close sendmail pid file 630e92d3f3fSGregory Neil Shapiro ** 631e92d3f3fSGregory Neil Shapiro ** Parameters: 632e92d3f3fSGregory Neil Shapiro ** none. 633e92d3f3fSGregory Neil Shapiro ** 634e92d3f3fSGregory Neil Shapiro ** Returns: 635e92d3f3fSGregory Neil Shapiro ** none. 636e92d3f3fSGregory Neil Shapiro */ 637e92d3f3fSGregory Neil Shapiro 638e92d3f3fSGregory Neil Shapiro void 639e92d3f3fSGregory Neil Shapiro close_sendmail_pid() 640e92d3f3fSGregory Neil Shapiro { 641e92d3f3fSGregory Neil Shapiro if (Pidf == NULL) 642e92d3f3fSGregory Neil Shapiro return; 643e92d3f3fSGregory Neil Shapiro 644e92d3f3fSGregory Neil Shapiro (void) sm_io_close(Pidf, SM_TIME_DEFAULT); 645e92d3f3fSGregory Neil Shapiro Pidf = NULL; 646e92d3f3fSGregory Neil Shapiro } 647e92d3f3fSGregory Neil Shapiro 64840266059SGregory Neil Shapiro /* 64906f25ae9SGregory Neil Shapiro ** SET_DELIVERY_MODE -- set and record the delivery mode 65006f25ae9SGregory Neil Shapiro ** 65106f25ae9SGregory Neil Shapiro ** Parameters: 65206f25ae9SGregory Neil Shapiro ** mode -- delivery mode 65306f25ae9SGregory Neil Shapiro ** e -- the current envelope. 65406f25ae9SGregory Neil Shapiro ** 65506f25ae9SGregory Neil Shapiro ** Returns: 65606f25ae9SGregory Neil Shapiro ** none. 65706f25ae9SGregory Neil Shapiro ** 65806f25ae9SGregory Neil Shapiro ** Side Effects: 65940266059SGregory Neil Shapiro ** sets {deliveryMode} macro 66006f25ae9SGregory Neil Shapiro */ 66106f25ae9SGregory Neil Shapiro 66206f25ae9SGregory Neil Shapiro void 66306f25ae9SGregory Neil Shapiro set_delivery_mode(mode, e) 66406f25ae9SGregory Neil Shapiro int mode; 66506f25ae9SGregory Neil Shapiro ENVELOPE *e; 66606f25ae9SGregory Neil Shapiro { 66706f25ae9SGregory Neil Shapiro char buf[2]; 66806f25ae9SGregory Neil Shapiro 66906f25ae9SGregory Neil Shapiro e->e_sendmode = (char) mode; 67006f25ae9SGregory Neil Shapiro buf[0] = (char) mode; 67106f25ae9SGregory Neil Shapiro buf[1] = '\0'; 67240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{deliveryMode}"), buf); 67306f25ae9SGregory Neil Shapiro } 674d0cef73dSGregory Neil Shapiro 67540266059SGregory Neil Shapiro /* 67640266059SGregory Neil Shapiro ** SET_OP_MODE -- set and record the op mode 67740266059SGregory Neil Shapiro ** 67840266059SGregory Neil Shapiro ** Parameters: 67940266059SGregory Neil Shapiro ** mode -- op mode 68040266059SGregory Neil Shapiro ** e -- the current envelope. 68140266059SGregory Neil Shapiro ** 68240266059SGregory Neil Shapiro ** Returns: 68340266059SGregory Neil Shapiro ** none. 68440266059SGregory Neil Shapiro ** 68540266059SGregory Neil Shapiro ** Side Effects: 68640266059SGregory Neil Shapiro ** sets {opMode} macro 68740266059SGregory Neil Shapiro */ 68840266059SGregory Neil Shapiro 68940266059SGregory Neil Shapiro void 69040266059SGregory Neil Shapiro set_op_mode(mode) 69140266059SGregory Neil Shapiro int mode; 69240266059SGregory Neil Shapiro { 69340266059SGregory Neil Shapiro char buf[2]; 69440266059SGregory Neil Shapiro extern ENVELOPE BlankEnvelope; 69540266059SGregory Neil Shapiro 69640266059SGregory Neil Shapiro OpMode = (char) mode; 69740266059SGregory Neil Shapiro buf[0] = (char) mode; 69840266059SGregory Neil Shapiro buf[1] = '\0'; 69940266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, MID_OPMODE, buf); 70040266059SGregory Neil Shapiro } 701d0cef73dSGregory Neil Shapiro 70240266059SGregory Neil Shapiro /* 703c2aa98e2SPeter Wemm ** PRINTAV -- print argument vector. 704c2aa98e2SPeter Wemm ** 705c2aa98e2SPeter Wemm ** Parameters: 706e92d3f3fSGregory Neil Shapiro ** fp -- output file pointer. 707c2aa98e2SPeter Wemm ** av -- argument vector. 708c2aa98e2SPeter Wemm ** 709c2aa98e2SPeter Wemm ** Returns: 710c2aa98e2SPeter Wemm ** none. 711c2aa98e2SPeter Wemm ** 712c2aa98e2SPeter Wemm ** Side Effects: 713c2aa98e2SPeter Wemm ** prints av. 714c2aa98e2SPeter Wemm */ 715c2aa98e2SPeter Wemm 716c2aa98e2SPeter Wemm void 717e92d3f3fSGregory Neil Shapiro printav(fp, av) 718e92d3f3fSGregory Neil Shapiro SM_FILE_T *fp; 719d0cef73dSGregory Neil Shapiro char **av; 720c2aa98e2SPeter Wemm { 721c2aa98e2SPeter Wemm while (*av != NULL) 722c2aa98e2SPeter Wemm { 723c2aa98e2SPeter Wemm if (tTd(0, 44)) 72440266059SGregory Neil Shapiro sm_dprintf("\n\t%08lx=", (unsigned long) *av); 725c2aa98e2SPeter Wemm else 726e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, ' '); 727d0cef73dSGregory Neil Shapiro if (tTd(0, 99)) 728d0cef73dSGregory Neil Shapiro sm_dprintf("%s", str2prt(*av++)); 729d0cef73dSGregory Neil Shapiro else 730e92d3f3fSGregory Neil Shapiro xputs(fp, *av++); 731c2aa98e2SPeter Wemm } 732e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, '\n'); 733c2aa98e2SPeter Wemm } 734d0cef73dSGregory Neil Shapiro 73540266059SGregory Neil Shapiro /* 736c2aa98e2SPeter Wemm ** XPUTS -- put string doing control escapes. 737c2aa98e2SPeter Wemm ** 738c2aa98e2SPeter Wemm ** Parameters: 739e92d3f3fSGregory Neil Shapiro ** fp -- output file pointer. 740c2aa98e2SPeter Wemm ** s -- string to put. 741c2aa98e2SPeter Wemm ** 742c2aa98e2SPeter Wemm ** Returns: 743c2aa98e2SPeter Wemm ** none. 744c2aa98e2SPeter Wemm ** 745c2aa98e2SPeter Wemm ** Side Effects: 746c2aa98e2SPeter Wemm ** output to stdout 747c2aa98e2SPeter Wemm */ 748c2aa98e2SPeter Wemm 749c2aa98e2SPeter Wemm void 750e92d3f3fSGregory Neil Shapiro xputs(fp, s) 751e92d3f3fSGregory Neil Shapiro SM_FILE_T *fp; 752d0cef73dSGregory Neil Shapiro const char *s; 753c2aa98e2SPeter Wemm { 754d0cef73dSGregory Neil Shapiro int c; 755d0cef73dSGregory Neil Shapiro struct metamac *mp; 75640266059SGregory Neil Shapiro bool shiftout = false; 757c2aa98e2SPeter Wemm extern struct metamac MetaMacros[]; 75840266059SGregory Neil Shapiro static SM_DEBUG_T DebugANSI = SM_DEBUG_INITIALIZER("ANSI", 75940266059SGregory Neil Shapiro "@(#)$Debug: ANSI - enable reverse video in debug output $"); 76040266059SGregory Neil Shapiro 76140266059SGregory Neil Shapiro /* 76240266059SGregory Neil Shapiro ** TermEscape is set here, rather than in main(), 76340266059SGregory Neil Shapiro ** because ANSI mode can be turned on or off at any time 76440266059SGregory Neil Shapiro ** if we are in -bt rule testing mode. 76540266059SGregory Neil Shapiro */ 76640266059SGregory Neil Shapiro 76740266059SGregory Neil Shapiro if (sm_debug_unknown(&DebugANSI)) 76840266059SGregory Neil Shapiro { 76940266059SGregory Neil Shapiro if (sm_debug_active(&DebugANSI, 1)) 77040266059SGregory Neil Shapiro { 77140266059SGregory Neil Shapiro TermEscape.te_rv_on = "\033[7m"; 772d0cef73dSGregory Neil Shapiro TermEscape.te_normal = "\033[0m"; 77340266059SGregory Neil Shapiro } 77440266059SGregory Neil Shapiro else 77540266059SGregory Neil Shapiro { 77640266059SGregory Neil Shapiro TermEscape.te_rv_on = ""; 777d0cef73dSGregory Neil Shapiro TermEscape.te_normal = ""; 77840266059SGregory Neil Shapiro } 77940266059SGregory Neil Shapiro } 780c2aa98e2SPeter Wemm 781c2aa98e2SPeter Wemm if (s == NULL) 782c2aa98e2SPeter Wemm { 783e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s<null>%s", 784d0cef73dSGregory Neil Shapiro TermEscape.te_rv_on, TermEscape.te_normal); 785c2aa98e2SPeter Wemm return; 786c2aa98e2SPeter Wemm } 787c2aa98e2SPeter Wemm while ((c = (*s++ & 0377)) != '\0') 788c2aa98e2SPeter Wemm { 789c2aa98e2SPeter Wemm if (shiftout) 790c2aa98e2SPeter Wemm { 791e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 792d0cef73dSGregory Neil Shapiro TermEscape.te_normal); 79340266059SGregory Neil Shapiro shiftout = false; 794c2aa98e2SPeter Wemm } 795d0cef73dSGregory Neil Shapiro if (!isascii(c) && !tTd(84, 1)) 796c2aa98e2SPeter Wemm { 797c2aa98e2SPeter Wemm if (c == MATCHREPL) 798c2aa98e2SPeter Wemm { 799e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 80040266059SGregory Neil Shapiro "%s$", 80140266059SGregory Neil Shapiro TermEscape.te_rv_on); 80240266059SGregory Neil Shapiro shiftout = true; 803c2aa98e2SPeter Wemm if (*s == '\0') 804c2aa98e2SPeter Wemm continue; 805c2aa98e2SPeter Wemm c = *s++ & 0377; 806c2aa98e2SPeter Wemm goto printchar; 807c2aa98e2SPeter Wemm } 808c2aa98e2SPeter Wemm if (c == MACROEXPAND || c == MACRODEXPAND) 809c2aa98e2SPeter Wemm { 810e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 81140266059SGregory Neil Shapiro "%s$", 81240266059SGregory Neil Shapiro TermEscape.te_rv_on); 813c2aa98e2SPeter Wemm if (c == MACRODEXPAND) 814e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, 81540266059SGregory Neil Shapiro SM_TIME_DEFAULT, '&'); 81640266059SGregory Neil Shapiro shiftout = true; 817c2aa98e2SPeter Wemm if (*s == '\0') 818c2aa98e2SPeter Wemm continue; 819c2aa98e2SPeter Wemm if (strchr("=~&?", *s) != NULL) 820e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, 82140266059SGregory Neil Shapiro SM_TIME_DEFAULT, 82240266059SGregory Neil Shapiro *s++); 823c2aa98e2SPeter Wemm if (bitset(0200, *s)) 824e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, 82540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 82640266059SGregory Neil Shapiro "{%s}", 82740266059SGregory Neil Shapiro macname(bitidx(*s++))); 828c2aa98e2SPeter Wemm else 829e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, 83040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 83140266059SGregory Neil Shapiro "%c", 83240266059SGregory Neil Shapiro *s++); 833c2aa98e2SPeter Wemm continue; 834c2aa98e2SPeter Wemm } 835c2aa98e2SPeter Wemm for (mp = MetaMacros; mp->metaname != '\0'; mp++) 836c2aa98e2SPeter Wemm { 83740266059SGregory Neil Shapiro if (bitidx(mp->metaval) == c) 838c2aa98e2SPeter Wemm { 839e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, 84040266059SGregory Neil Shapiro SM_TIME_DEFAULT, 84140266059SGregory Neil Shapiro "%s$%c", 842c2aa98e2SPeter Wemm TermEscape.te_rv_on, 843c2aa98e2SPeter Wemm mp->metaname); 84440266059SGregory Neil Shapiro shiftout = true; 845c2aa98e2SPeter Wemm break; 846c2aa98e2SPeter Wemm } 847c2aa98e2SPeter Wemm } 848c2aa98e2SPeter Wemm if (c == MATCHCLASS || c == MATCHNCLASS) 849c2aa98e2SPeter Wemm { 850c2aa98e2SPeter Wemm if (bitset(0200, *s)) 851e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, 85240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 85340266059SGregory Neil Shapiro "{%s}", 85440266059SGregory Neil Shapiro macname(bitidx(*s++))); 855c2aa98e2SPeter Wemm else if (*s != '\0') 856e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, 85740266059SGregory Neil Shapiro SM_TIME_DEFAULT, 85840266059SGregory Neil Shapiro "%c", 85940266059SGregory Neil Shapiro *s++); 860c2aa98e2SPeter Wemm } 861c2aa98e2SPeter Wemm if (mp->metaname != '\0') 862c2aa98e2SPeter Wemm continue; 863c2aa98e2SPeter Wemm 864c2aa98e2SPeter Wemm /* unrecognized meta character */ 865e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%sM-", 86640266059SGregory Neil Shapiro TermEscape.te_rv_on); 86740266059SGregory Neil Shapiro shiftout = true; 868c2aa98e2SPeter Wemm c &= 0177; 869c2aa98e2SPeter Wemm } 870c2aa98e2SPeter Wemm printchar: 8719bd497b8SGregory Neil Shapiro if (isascii(c) && isprint(c)) 872c2aa98e2SPeter Wemm { 873e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, c); 874c2aa98e2SPeter Wemm continue; 875c2aa98e2SPeter Wemm } 876c2aa98e2SPeter Wemm 877c2aa98e2SPeter Wemm /* wasn't a meta-macro -- find another way to print it */ 878c2aa98e2SPeter Wemm switch (c) 879c2aa98e2SPeter Wemm { 880c2aa98e2SPeter Wemm case '\n': 881c2aa98e2SPeter Wemm c = 'n'; 882c2aa98e2SPeter Wemm break; 883c2aa98e2SPeter Wemm 884c2aa98e2SPeter Wemm case '\r': 885c2aa98e2SPeter Wemm c = 'r'; 886c2aa98e2SPeter Wemm break; 887c2aa98e2SPeter Wemm 888c2aa98e2SPeter Wemm case '\t': 889c2aa98e2SPeter Wemm c = 't'; 890c2aa98e2SPeter Wemm break; 891c2aa98e2SPeter Wemm } 892c2aa98e2SPeter Wemm if (!shiftout) 893c2aa98e2SPeter Wemm { 894e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 89540266059SGregory Neil Shapiro TermEscape.te_rv_on); 89640266059SGregory Neil Shapiro shiftout = true; 897c2aa98e2SPeter Wemm } 8989bd497b8SGregory Neil Shapiro if (isascii(c) && isprint(c)) 899c2aa98e2SPeter Wemm { 900e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, '\\'); 901e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, c); 902c2aa98e2SPeter Wemm } 903d0cef73dSGregory Neil Shapiro else if (tTd(84, 2)) 904d0cef73dSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " %o ", c); 905d0cef73dSGregory Neil Shapiro else if (tTd(84, 1)) 906d0cef73dSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " %#x ", c); 907d0cef73dSGregory Neil Shapiro else if (!isascii(c) && !tTd(84, 1)) 908c2aa98e2SPeter Wemm { 909e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, '^'); 910e92d3f3fSGregory Neil Shapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, c ^ 0100); 911c2aa98e2SPeter Wemm } 912c2aa98e2SPeter Wemm } 913c2aa98e2SPeter Wemm if (shiftout) 914e92d3f3fSGregory Neil Shapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 915d0cef73dSGregory Neil Shapiro TermEscape.te_normal); 916e92d3f3fSGregory Neil Shapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 917c2aa98e2SPeter Wemm } 918d0cef73dSGregory Neil Shapiro 91940266059SGregory Neil Shapiro /* 920c2aa98e2SPeter Wemm ** MAKELOWER -- Translate a line into lower case 921c2aa98e2SPeter Wemm ** 922c2aa98e2SPeter Wemm ** Parameters: 923c2aa98e2SPeter Wemm ** p -- the string to translate. If NULL, return is 924c2aa98e2SPeter Wemm ** immediate. 925c2aa98e2SPeter Wemm ** 926c2aa98e2SPeter Wemm ** Returns: 927c2aa98e2SPeter Wemm ** none. 928c2aa98e2SPeter Wemm ** 929c2aa98e2SPeter Wemm ** Side Effects: 930c2aa98e2SPeter Wemm ** String pointed to by p is translated to lower case. 931c2aa98e2SPeter Wemm */ 932c2aa98e2SPeter Wemm 933c2aa98e2SPeter Wemm void 934c2aa98e2SPeter Wemm makelower(p) 935c2aa98e2SPeter Wemm register char *p; 936c2aa98e2SPeter Wemm { 937c2aa98e2SPeter Wemm register char c; 938c2aa98e2SPeter Wemm 939c2aa98e2SPeter Wemm if (p == NULL) 940c2aa98e2SPeter Wemm return; 941c2aa98e2SPeter Wemm for (; (c = *p) != '\0'; p++) 942c2aa98e2SPeter Wemm if (isascii(c) && isupper(c)) 943c2aa98e2SPeter Wemm *p = tolower(c); 944c2aa98e2SPeter Wemm } 945d0cef73dSGregory Neil Shapiro 94640266059SGregory Neil Shapiro /* 947c2aa98e2SPeter Wemm ** FIXCRLF -- fix <CR><LF> in line. 948c2aa98e2SPeter Wemm ** 949c2aa98e2SPeter Wemm ** Looks for the <CR><LF> combination and turns it into the 950c2aa98e2SPeter Wemm ** UNIX canonical <NL> character. It only takes one line, 951c2aa98e2SPeter Wemm ** i.e., it is assumed that the first <NL> found is the end 952c2aa98e2SPeter Wemm ** of the line. 953c2aa98e2SPeter Wemm ** 954c2aa98e2SPeter Wemm ** Parameters: 955c2aa98e2SPeter Wemm ** line -- the line to fix. 956c2aa98e2SPeter Wemm ** stripnl -- if true, strip the newline also. 957c2aa98e2SPeter Wemm ** 958c2aa98e2SPeter Wemm ** Returns: 959c2aa98e2SPeter Wemm ** none. 960c2aa98e2SPeter Wemm ** 961c2aa98e2SPeter Wemm ** Side Effects: 962c2aa98e2SPeter Wemm ** line is changed in place. 963c2aa98e2SPeter Wemm */ 964c2aa98e2SPeter Wemm 965c2aa98e2SPeter Wemm void 966c2aa98e2SPeter Wemm fixcrlf(line, stripnl) 967c2aa98e2SPeter Wemm char *line; 968c2aa98e2SPeter Wemm bool stripnl; 969c2aa98e2SPeter Wemm { 970c2aa98e2SPeter Wemm register char *p; 971c2aa98e2SPeter Wemm 972c2aa98e2SPeter Wemm p = strchr(line, '\n'); 973c2aa98e2SPeter Wemm if (p == NULL) 974c2aa98e2SPeter Wemm return; 975c2aa98e2SPeter Wemm if (p > line && p[-1] == '\r') 976c2aa98e2SPeter Wemm p--; 977c2aa98e2SPeter Wemm if (!stripnl) 978c2aa98e2SPeter Wemm *p++ = '\n'; 979c2aa98e2SPeter Wemm *p = '\0'; 980c2aa98e2SPeter Wemm } 981d0cef73dSGregory Neil Shapiro 98240266059SGregory Neil Shapiro /* 983c2aa98e2SPeter Wemm ** PUTLINE -- put a line like fputs obeying SMTP conventions 984c2aa98e2SPeter Wemm ** 985c2aa98e2SPeter Wemm ** This routine always guarantees outputing a newline (or CRLF, 986c2aa98e2SPeter Wemm ** as appropriate) at the end of the string. 987c2aa98e2SPeter Wemm ** 988c2aa98e2SPeter Wemm ** Parameters: 989c2aa98e2SPeter Wemm ** l -- line to put. 990c2aa98e2SPeter Wemm ** mci -- the mailer connection information. 991c2aa98e2SPeter Wemm ** 992c2aa98e2SPeter Wemm ** Returns: 9934e4196cbSGregory Neil Shapiro ** true iff line was written successfully 994c2aa98e2SPeter Wemm ** 995c2aa98e2SPeter Wemm ** Side Effects: 99640266059SGregory Neil Shapiro ** output of l to mci->mci_out. 997c2aa98e2SPeter Wemm */ 998c2aa98e2SPeter Wemm 9994e4196cbSGregory Neil Shapiro bool 1000c2aa98e2SPeter Wemm putline(l, mci) 1001c2aa98e2SPeter Wemm register char *l; 1002c2aa98e2SPeter Wemm register MCI *mci; 1003c2aa98e2SPeter Wemm { 10044e4196cbSGregory Neil Shapiro return putxline(l, strlen(l), mci, PXLF_MAPFROM); 1005c2aa98e2SPeter Wemm } 1006d0cef73dSGregory Neil Shapiro 100740266059SGregory Neil Shapiro /* 1008c2aa98e2SPeter Wemm ** PUTXLINE -- putline with flags bits. 1009c2aa98e2SPeter Wemm ** 1010c2aa98e2SPeter Wemm ** This routine always guarantees outputing a newline (or CRLF, 1011c2aa98e2SPeter Wemm ** as appropriate) at the end of the string. 1012c2aa98e2SPeter Wemm ** 1013c2aa98e2SPeter Wemm ** Parameters: 1014c2aa98e2SPeter Wemm ** l -- line to put. 1015c2aa98e2SPeter Wemm ** len -- the length of the line. 1016c2aa98e2SPeter Wemm ** mci -- the mailer connection information. 1017c2aa98e2SPeter Wemm ** pxflags -- flag bits: 1018c2aa98e2SPeter Wemm ** PXLF_MAPFROM -- map From_ to >From_. 1019c2aa98e2SPeter Wemm ** PXLF_STRIP8BIT -- strip 8th bit. 1020c2aa98e2SPeter Wemm ** PXLF_HEADER -- map bare newline in header to newline space. 1021605302a5SGregory Neil Shapiro ** PXLF_NOADDEOL -- don't add an EOL if one wasn't present. 1022d0cef73dSGregory Neil Shapiro ** PXLF_STRIPMQUOTE -- strip METAQUOTE bytes. 1023c2aa98e2SPeter Wemm ** 1024c2aa98e2SPeter Wemm ** Returns: 10254e4196cbSGregory Neil Shapiro ** true iff line was written successfully 1026c2aa98e2SPeter Wemm ** 1027c2aa98e2SPeter Wemm ** Side Effects: 102840266059SGregory Neil Shapiro ** output of l to mci->mci_out. 1029c2aa98e2SPeter Wemm */ 1030c2aa98e2SPeter Wemm 1031d0cef73dSGregory Neil Shapiro 1032d0cef73dSGregory Neil Shapiro #define PUTX(limit) \ 1033d0cef73dSGregory Neil Shapiro do \ 1034d0cef73dSGregory Neil Shapiro { \ 1035d0cef73dSGregory Neil Shapiro quotenext = false; \ 1036d0cef73dSGregory Neil Shapiro while (l < limit) \ 1037d0cef73dSGregory Neil Shapiro { \ 1038d0cef73dSGregory Neil Shapiro unsigned char c = (unsigned char) *l++; \ 1039d0cef73dSGregory Neil Shapiro \ 1040d0cef73dSGregory Neil Shapiro if (bitset(PXLF_STRIPMQUOTE, pxflags) && \ 1041d0cef73dSGregory Neil Shapiro !quotenext && c == METAQUOTE) \ 1042d0cef73dSGregory Neil Shapiro { \ 1043d0cef73dSGregory Neil Shapiro quotenext = true; \ 1044d0cef73dSGregory Neil Shapiro continue; \ 1045d0cef73dSGregory Neil Shapiro } \ 1046d0cef73dSGregory Neil Shapiro quotenext = false; \ 1047d0cef73dSGregory Neil Shapiro if (strip8bit) \ 1048d0cef73dSGregory Neil Shapiro c &= 0177; \ 1049d0cef73dSGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, \ 1050d0cef73dSGregory Neil Shapiro c) == SM_IO_EOF) \ 1051d0cef73dSGregory Neil Shapiro { \ 1052d0cef73dSGregory Neil Shapiro dead = true; \ 1053d0cef73dSGregory Neil Shapiro break; \ 1054d0cef73dSGregory Neil Shapiro } \ 1055d0cef73dSGregory Neil Shapiro if (TrafficLogFile != NULL) \ 1056d0cef73dSGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, \ 1057d0cef73dSGregory Neil Shapiro SM_TIME_DEFAULT, \ 1058d0cef73dSGregory Neil Shapiro c); \ 1059d0cef73dSGregory Neil Shapiro } \ 1060d0cef73dSGregory Neil Shapiro } while (0) 1061d0cef73dSGregory Neil Shapiro 10624e4196cbSGregory Neil Shapiro bool 1063c2aa98e2SPeter Wemm putxline(l, len, mci, pxflags) 1064c2aa98e2SPeter Wemm register char *l; 1065c2aa98e2SPeter Wemm size_t len; 1066c2aa98e2SPeter Wemm register MCI *mci; 1067c2aa98e2SPeter Wemm int pxflags; 1068c2aa98e2SPeter Wemm { 1069c2aa98e2SPeter Wemm register char *p, *end; 1070d0cef73dSGregory Neil Shapiro int slop; 1071d0cef73dSGregory Neil Shapiro bool dead, quotenext, strip8bit; 1072c2aa98e2SPeter Wemm 1073c2aa98e2SPeter Wemm /* strip out 0200 bits -- these can look like TELNET protocol */ 1074d0cef73dSGregory Neil Shapiro strip8bit = bitset(MCIF_7BIT, mci->mci_flags) || 1075d0cef73dSGregory Neil Shapiro bitset(PXLF_STRIP8BIT, pxflags); 1076d0cef73dSGregory Neil Shapiro dead = false; 1077d0cef73dSGregory Neil Shapiro slop = 0; 1078c2aa98e2SPeter Wemm 1079c2aa98e2SPeter Wemm end = l + len; 1080c2aa98e2SPeter Wemm do 1081c2aa98e2SPeter Wemm { 1082605302a5SGregory Neil Shapiro bool noeol = false; 1083605302a5SGregory Neil Shapiro 1084c2aa98e2SPeter Wemm /* find the end of the line */ 1085c2aa98e2SPeter Wemm p = memchr(l, '\n', end - l); 1086c2aa98e2SPeter Wemm if (p == NULL) 1087605302a5SGregory Neil Shapiro { 1088c2aa98e2SPeter Wemm p = end; 1089605302a5SGregory Neil Shapiro noeol = true; 1090605302a5SGregory Neil Shapiro } 1091c2aa98e2SPeter Wemm 1092c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 109340266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 109440266059SGregory Neil Shapiro "%05d >>> ", (int) CurrentPid); 1095c2aa98e2SPeter Wemm 1096c2aa98e2SPeter Wemm /* check for line overflow */ 1097c2aa98e2SPeter Wemm while (mci->mci_mailer->m_linelimit > 0 && 1098c2aa98e2SPeter Wemm (p - l + slop) > mci->mci_mailer->m_linelimit) 1099c2aa98e2SPeter Wemm { 1100c2aa98e2SPeter Wemm register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 1101c2aa98e2SPeter Wemm 1102c2aa98e2SPeter Wemm if (l[0] == '.' && slop == 0 && 1103c2aa98e2SPeter Wemm bitnset(M_XDOT, mci->mci_mailer->m_flags)) 1104c2aa98e2SPeter Wemm { 110540266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 110640266059SGregory Neil Shapiro '.') == SM_IO_EOF) 110740266059SGregory Neil Shapiro dead = true; 1108c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 110940266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 111040266059SGregory Neil Shapiro SM_TIME_DEFAULT, '.'); 1111c2aa98e2SPeter Wemm } 1112c2aa98e2SPeter Wemm else if (l[0] == 'F' && slop == 0 && 1113c2aa98e2SPeter Wemm bitset(PXLF_MAPFROM, pxflags) && 1114c2aa98e2SPeter Wemm strncmp(l, "From ", 5) == 0 && 1115c2aa98e2SPeter Wemm bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 1116c2aa98e2SPeter Wemm { 111740266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 111840266059SGregory Neil Shapiro '>') == SM_IO_EOF) 111940266059SGregory Neil Shapiro dead = true; 1120c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 112140266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 112240266059SGregory Neil Shapiro SM_TIME_DEFAULT, 112340266059SGregory Neil Shapiro '>'); 1124c2aa98e2SPeter Wemm } 112506f25ae9SGregory Neil Shapiro if (dead) 112606f25ae9SGregory Neil Shapiro break; 112706f25ae9SGregory Neil Shapiro 1128d0cef73dSGregory Neil Shapiro PUTX(q); 112906f25ae9SGregory Neil Shapiro if (dead) 113006f25ae9SGregory Neil Shapiro break; 113106f25ae9SGregory Neil Shapiro 1132d0cef73dSGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 1133d0cef73dSGregory Neil Shapiro '!') == SM_IO_EOF || 113440266059SGregory Neil Shapiro sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 1135d0cef73dSGregory Neil Shapiro mci->mci_mailer->m_eol) == SM_IO_EOF || 1136d0cef73dSGregory Neil Shapiro sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 1137d0cef73dSGregory Neil Shapiro ' ') == SM_IO_EOF) 113806f25ae9SGregory Neil Shapiro { 113940266059SGregory Neil Shapiro dead = true; 114006f25ae9SGregory Neil Shapiro break; 114106f25ae9SGregory Neil Shapiro } 1142c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 1143c2aa98e2SPeter Wemm { 114440266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 114540266059SGregory Neil Shapiro SM_TIME_DEFAULT, 114640266059SGregory Neil Shapiro "!\n%05d >>> ", 114740266059SGregory Neil Shapiro (int) CurrentPid); 1148c2aa98e2SPeter Wemm } 1149c2aa98e2SPeter Wemm slop = 1; 1150c2aa98e2SPeter Wemm } 1151c2aa98e2SPeter Wemm 115206f25ae9SGregory Neil Shapiro if (dead) 115306f25ae9SGregory Neil Shapiro break; 115406f25ae9SGregory Neil Shapiro 1155c2aa98e2SPeter Wemm /* output last part */ 1156c2aa98e2SPeter Wemm if (l[0] == '.' && slop == 0 && 1157ffb83623SGregory Neil Shapiro bitnset(M_XDOT, mci->mci_mailer->m_flags) && 1158ffb83623SGregory Neil Shapiro !bitset(MCIF_INLONGLINE, mci->mci_flags)) 1159c2aa98e2SPeter Wemm { 116040266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '.') == 116140266059SGregory Neil Shapiro SM_IO_EOF) 1162193538b7SGregory Neil Shapiro { 11634e4196cbSGregory Neil Shapiro dead = true; 11644e4196cbSGregory Neil Shapiro break; 1165193538b7SGregory Neil Shapiro } 1166c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 116740266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 116840266059SGregory Neil Shapiro SM_TIME_DEFAULT, '.'); 1169c2aa98e2SPeter Wemm } 1170c2aa98e2SPeter Wemm else if (l[0] == 'F' && slop == 0 && 1171c2aa98e2SPeter Wemm bitset(PXLF_MAPFROM, pxflags) && 1172c2aa98e2SPeter Wemm strncmp(l, "From ", 5) == 0 && 1173ffb83623SGregory Neil Shapiro bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 1174ffb83623SGregory Neil Shapiro !bitset(MCIF_INLONGLINE, mci->mci_flags)) 1175c2aa98e2SPeter Wemm { 117640266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '>') == 117740266059SGregory Neil Shapiro SM_IO_EOF) 1178193538b7SGregory Neil Shapiro { 11794e4196cbSGregory Neil Shapiro dead = true; 11804e4196cbSGregory Neil Shapiro break; 1181193538b7SGregory Neil Shapiro } 1182c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 118340266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 118440266059SGregory Neil Shapiro SM_TIME_DEFAULT, '>'); 1185c2aa98e2SPeter Wemm } 1186d0cef73dSGregory Neil Shapiro PUTX(p); 118706f25ae9SGregory Neil Shapiro if (dead) 118806f25ae9SGregory Neil Shapiro break; 118906f25ae9SGregory Neil Shapiro 1190c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 119140266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, SM_TIME_DEFAULT, 119240266059SGregory Neil Shapiro '\n'); 1193ffb83623SGregory Neil Shapiro if ((!bitset(PXLF_NOADDEOL, pxflags) || !noeol)) 1194ffb83623SGregory Neil Shapiro { 1195ffb83623SGregory Neil Shapiro mci->mci_flags &= ~MCIF_INLONGLINE; 1196ffb83623SGregory Neil Shapiro if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 119740266059SGregory Neil Shapiro mci->mci_mailer->m_eol) == SM_IO_EOF) 1198193538b7SGregory Neil Shapiro { 11994e4196cbSGregory Neil Shapiro dead = true; 12004e4196cbSGregory Neil Shapiro break; 1201193538b7SGregory Neil Shapiro } 1202ffb83623SGregory Neil Shapiro } 1203ffb83623SGregory Neil Shapiro else 1204ffb83623SGregory Neil Shapiro mci->mci_flags |= MCIF_INLONGLINE; 1205ffb83623SGregory Neil Shapiro 1206c2aa98e2SPeter Wemm if (l < end && *l == '\n') 1207c2aa98e2SPeter Wemm { 1208c2aa98e2SPeter Wemm if (*++l != ' ' && *l != '\t' && *l != '\0' && 1209c2aa98e2SPeter Wemm bitset(PXLF_HEADER, pxflags)) 1210c2aa98e2SPeter Wemm { 121140266059SGregory Neil Shapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 121240266059SGregory Neil Shapiro ' ') == SM_IO_EOF) 1213193538b7SGregory Neil Shapiro { 12144e4196cbSGregory Neil Shapiro dead = true; 12154e4196cbSGregory Neil Shapiro break; 1216193538b7SGregory Neil Shapiro } 121740266059SGregory Neil Shapiro 1218c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 121940266059SGregory Neil Shapiro (void) sm_io_putc(TrafficLogFile, 122040266059SGregory Neil Shapiro SM_TIME_DEFAULT, ' '); 1221c2aa98e2SPeter Wemm } 1222c2aa98e2SPeter Wemm } 122340266059SGregory Neil Shapiro 1224c2aa98e2SPeter Wemm } while (l < end); 12254e4196cbSGregory Neil Shapiro return !dead; 1226c2aa98e2SPeter Wemm } 12274e4196cbSGregory Neil Shapiro 122840266059SGregory Neil Shapiro /* 1229c2aa98e2SPeter Wemm ** XUNLINK -- unlink a file, doing logging as appropriate. 1230c2aa98e2SPeter Wemm ** 1231c2aa98e2SPeter Wemm ** Parameters: 1232c2aa98e2SPeter Wemm ** f -- name of file to unlink. 1233c2aa98e2SPeter Wemm ** 1234c2aa98e2SPeter Wemm ** Returns: 123540266059SGregory Neil Shapiro ** return value of unlink() 1236c2aa98e2SPeter Wemm ** 1237c2aa98e2SPeter Wemm ** Side Effects: 1238c2aa98e2SPeter Wemm ** f is unlinked. 1239c2aa98e2SPeter Wemm */ 1240c2aa98e2SPeter Wemm 124140266059SGregory Neil Shapiro int 1242c2aa98e2SPeter Wemm xunlink(f) 1243c2aa98e2SPeter Wemm char *f; 1244c2aa98e2SPeter Wemm { 1245c2aa98e2SPeter Wemm register int i; 124640266059SGregory Neil Shapiro int save_errno; 1247c2aa98e2SPeter Wemm 1248c2aa98e2SPeter Wemm if (LogLevel > 98) 124940266059SGregory Neil Shapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "unlink %s", f); 1250c2aa98e2SPeter Wemm 1251c2aa98e2SPeter Wemm i = unlink(f); 125240266059SGregory Neil Shapiro save_errno = errno; 1253c2aa98e2SPeter Wemm if (i < 0 && LogLevel > 97) 125440266059SGregory Neil Shapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s: unlink-fail %d", 1255c2aa98e2SPeter Wemm f, errno); 125640266059SGregory Neil Shapiro if (i >= 0) 125740266059SGregory Neil Shapiro SYNC_DIR(f, false); 125840266059SGregory Neil Shapiro errno = save_errno; 125940266059SGregory Neil Shapiro return i; 1260c2aa98e2SPeter Wemm } 1261d0cef73dSGregory Neil Shapiro 126240266059SGregory Neil Shapiro /* 1263c2aa98e2SPeter Wemm ** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 1264c2aa98e2SPeter Wemm ** 1265c2aa98e2SPeter Wemm ** Parameters: 1266c2aa98e2SPeter Wemm ** buf -- place to put the input line. 1267c2aa98e2SPeter Wemm ** siz -- size of buf. 1268c2aa98e2SPeter Wemm ** fp -- file to read from. 1269c2aa98e2SPeter Wemm ** timeout -- the timeout before error occurs. 1270c2aa98e2SPeter Wemm ** during -- what we are trying to read (for error messages). 1271c2aa98e2SPeter Wemm ** 1272c2aa98e2SPeter Wemm ** Returns: 127340266059SGregory Neil Shapiro ** NULL on error (including timeout). This may also leave 1274c2aa98e2SPeter Wemm ** buf containing a null string. 1275c2aa98e2SPeter Wemm ** buf otherwise. 1276c2aa98e2SPeter Wemm */ 1277c2aa98e2SPeter Wemm 127806f25ae9SGregory Neil Shapiro 1279c2aa98e2SPeter Wemm char * 1280c2aa98e2SPeter Wemm sfgets(buf, siz, fp, timeout, during) 1281c2aa98e2SPeter Wemm char *buf; 1282c2aa98e2SPeter Wemm int siz; 128340266059SGregory Neil Shapiro SM_FILE_T *fp; 1284c2aa98e2SPeter Wemm time_t timeout; 1285c2aa98e2SPeter Wemm char *during; 1286c2aa98e2SPeter Wemm { 1287c2aa98e2SPeter Wemm register char *p; 1288552d4955SGregory Neil Shapiro int save_errno, io_timeout, l; 128940266059SGregory Neil Shapiro 129040266059SGregory Neil Shapiro SM_REQUIRE(siz > 0); 129140266059SGregory Neil Shapiro SM_REQUIRE(buf != NULL); 1292c2aa98e2SPeter Wemm 1293c2aa98e2SPeter Wemm if (fp == NULL) 1294c2aa98e2SPeter Wemm { 1295c2aa98e2SPeter Wemm buf[0] = '\0'; 129640266059SGregory Neil Shapiro errno = EBADF; 1297c2aa98e2SPeter Wemm return NULL; 1298c2aa98e2SPeter Wemm } 1299c2aa98e2SPeter Wemm 130040266059SGregory Neil Shapiro /* try to read */ 1301552d4955SGregory Neil Shapiro l = -1; 130240266059SGregory Neil Shapiro errno = 0; 130340266059SGregory Neil Shapiro 130440266059SGregory Neil Shapiro /* convert the timeout to sm_io notation */ 130540266059SGregory Neil Shapiro io_timeout = (timeout <= 0) ? SM_TIME_DEFAULT : timeout * 1000; 130640266059SGregory Neil Shapiro while (!sm_io_eof(fp) && !sm_io_error(fp)) 1307c2aa98e2SPeter Wemm { 130840266059SGregory Neil Shapiro errno = 0; 1309552d4955SGregory Neil Shapiro l = sm_io_fgets(fp, io_timeout, buf, siz); 1310552d4955SGregory Neil Shapiro if (l < 0 && errno == EAGAIN) 1311c2aa98e2SPeter Wemm { 131240266059SGregory Neil Shapiro /* The sm_io_fgets() call timedout */ 1313c2aa98e2SPeter Wemm if (LogLevel > 1) 1314c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, CurEnv->e_id, 1315c2aa98e2SPeter Wemm "timeout waiting for input from %.100s during %s", 131640266059SGregory Neil Shapiro CURHOSTNAME, 1317c2aa98e2SPeter Wemm during); 1318c2aa98e2SPeter Wemm buf[0] = '\0'; 1319c2aa98e2SPeter Wemm #if XDEBUG 1320c2aa98e2SPeter Wemm checkfd012(during); 132106f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1322c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 132340266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, 132440266059SGregory Neil Shapiro SM_TIME_DEFAULT, 132540266059SGregory Neil Shapiro "%05d <<< [TIMEOUT]\n", 132640266059SGregory Neil Shapiro (int) CurrentPid); 132740266059SGregory Neil Shapiro errno = ETIMEDOUT; 132806f25ae9SGregory Neil Shapiro return NULL; 1329c2aa98e2SPeter Wemm } 1330552d4955SGregory Neil Shapiro if (l >= 0 || errno != EINTR) 1331c2aa98e2SPeter Wemm break; 133240266059SGregory Neil Shapiro (void) sm_io_clearerr(fp); 1333c2aa98e2SPeter Wemm } 13342e43090eSPeter Wemm save_errno = errno; 1335c2aa98e2SPeter Wemm 1336c2aa98e2SPeter Wemm /* clean up the books and exit */ 1337c2aa98e2SPeter Wemm LineNumber++; 1338552d4955SGregory Neil Shapiro if (l < 0) 1339c2aa98e2SPeter Wemm { 1340c2aa98e2SPeter Wemm buf[0] = '\0'; 1341c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 134240266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 134340266059SGregory Neil Shapiro "%05d <<< [EOF]\n", 134440266059SGregory Neil Shapiro (int) CurrentPid); 13452e43090eSPeter Wemm errno = save_errno; 134606f25ae9SGregory Neil Shapiro return NULL; 1347c2aa98e2SPeter Wemm } 1348c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 134940266059SGregory Neil Shapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 135040266059SGregory Neil Shapiro "%05d <<< %s", (int) CurrentPid, buf); 1351c2aa98e2SPeter Wemm if (SevenBitInput) 1352c2aa98e2SPeter Wemm { 1353c2aa98e2SPeter Wemm for (p = buf; *p != '\0'; p++) 1354c2aa98e2SPeter Wemm *p &= ~0200; 1355c2aa98e2SPeter Wemm } 1356c2aa98e2SPeter Wemm else if (!HasEightBits) 1357c2aa98e2SPeter Wemm { 1358c2aa98e2SPeter Wemm for (p = buf; *p != '\0'; p++) 1359c2aa98e2SPeter Wemm { 1360c2aa98e2SPeter Wemm if (bitset(0200, *p)) 1361c2aa98e2SPeter Wemm { 136240266059SGregory Neil Shapiro HasEightBits = true; 1363c2aa98e2SPeter Wemm break; 1364c2aa98e2SPeter Wemm } 1365c2aa98e2SPeter Wemm } 1366c2aa98e2SPeter Wemm } 136706f25ae9SGregory Neil Shapiro return buf; 1368c2aa98e2SPeter Wemm } 1369d0cef73dSGregory Neil Shapiro 13708774250cSGregory Neil Shapiro /* 137140266059SGregory Neil Shapiro ** FGETFOLDED -- like fgets, but knows about folded lines. 1372c2aa98e2SPeter Wemm ** 1373c2aa98e2SPeter Wemm ** Parameters: 1374c2aa98e2SPeter Wemm ** buf -- place to put result. 1375d0cef73dSGregory Neil Shapiro ** np -- pointer to bytes available; will be updated with 1376d0cef73dSGregory Neil Shapiro ** the actual buffer size (not number of bytes filled) 1377d0cef73dSGregory Neil Shapiro ** on return. 1378c2aa98e2SPeter Wemm ** f -- file to read from. 1379c2aa98e2SPeter Wemm ** 1380c2aa98e2SPeter Wemm ** Returns: 138140266059SGregory Neil Shapiro ** input line(s) on success, NULL on error or SM_IO_EOF. 1382c2aa98e2SPeter Wemm ** This will normally be buf -- unless the line is too 138340266059SGregory Neil Shapiro ** long, when it will be sm_malloc_x()ed. 1384c2aa98e2SPeter Wemm ** 1385c2aa98e2SPeter Wemm ** Side Effects: 1386c2aa98e2SPeter Wemm ** buf gets lines from f, with continuation lines (lines 1387c2aa98e2SPeter Wemm ** with leading white space) appended. CRLF's are mapped 1388c2aa98e2SPeter Wemm ** into single newlines. Any trailing NL is stripped. 1389c2aa98e2SPeter Wemm */ 1390c2aa98e2SPeter Wemm 1391c2aa98e2SPeter Wemm char * 1392d0cef73dSGregory Neil Shapiro fgetfolded(buf, np, f) 1393c2aa98e2SPeter Wemm char *buf; 1394d0cef73dSGregory Neil Shapiro int *np; 139540266059SGregory Neil Shapiro SM_FILE_T *f; 1396c2aa98e2SPeter Wemm { 1397c2aa98e2SPeter Wemm register char *p = buf; 1398c2aa98e2SPeter Wemm char *bp = buf; 1399c2aa98e2SPeter Wemm register int i; 1400d0cef73dSGregory Neil Shapiro int n; 1401c2aa98e2SPeter Wemm 1402d0cef73dSGregory Neil Shapiro SM_REQUIRE(np != NULL); 1403d0cef73dSGregory Neil Shapiro n = *np; 140440266059SGregory Neil Shapiro SM_REQUIRE(n > 0); 140540266059SGregory Neil Shapiro SM_REQUIRE(buf != NULL); 140640266059SGregory Neil Shapiro if (f == NULL) 140740266059SGregory Neil Shapiro { 140840266059SGregory Neil Shapiro buf[0] = '\0'; 140940266059SGregory Neil Shapiro errno = EBADF; 141040266059SGregory Neil Shapiro return NULL; 141140266059SGregory Neil Shapiro } 141240266059SGregory Neil Shapiro 1413c2aa98e2SPeter Wemm n--; 141440266059SGregory Neil Shapiro while ((i = sm_io_getc(f, SM_TIME_DEFAULT)) != SM_IO_EOF) 1415c2aa98e2SPeter Wemm { 1416c2aa98e2SPeter Wemm if (i == '\r') 1417c2aa98e2SPeter Wemm { 141840266059SGregory Neil Shapiro i = sm_io_getc(f, SM_TIME_DEFAULT); 1419c2aa98e2SPeter Wemm if (i != '\n') 1420c2aa98e2SPeter Wemm { 142140266059SGregory Neil Shapiro if (i != SM_IO_EOF) 142240266059SGregory Neil Shapiro (void) sm_io_ungetc(f, SM_TIME_DEFAULT, 142340266059SGregory Neil Shapiro i); 1424c2aa98e2SPeter Wemm i = '\r'; 1425c2aa98e2SPeter Wemm } 1426c2aa98e2SPeter Wemm } 1427c2aa98e2SPeter Wemm if (--n <= 0) 1428c2aa98e2SPeter Wemm { 1429c2aa98e2SPeter Wemm /* allocate new space */ 1430c2aa98e2SPeter Wemm char *nbp; 1431c2aa98e2SPeter Wemm int nn; 1432c2aa98e2SPeter Wemm 1433c2aa98e2SPeter Wemm nn = (p - bp); 1434c2aa98e2SPeter Wemm if (nn < MEMCHUNKSIZE) 1435c2aa98e2SPeter Wemm nn *= 2; 1436c2aa98e2SPeter Wemm else 1437c2aa98e2SPeter Wemm nn += MEMCHUNKSIZE; 143840266059SGregory Neil Shapiro nbp = sm_malloc_x(nn); 143906f25ae9SGregory Neil Shapiro memmove(nbp, bp, p - bp); 1440c2aa98e2SPeter Wemm p = &nbp[p - bp]; 1441c2aa98e2SPeter Wemm if (bp != buf) 14428774250cSGregory Neil Shapiro sm_free(bp); 1443c2aa98e2SPeter Wemm bp = nbp; 1444c2aa98e2SPeter Wemm n = nn - (p - bp); 1445d0cef73dSGregory Neil Shapiro *np = nn; 1446c2aa98e2SPeter Wemm } 1447c2aa98e2SPeter Wemm *p++ = i; 1448c2aa98e2SPeter Wemm if (i == '\n') 1449c2aa98e2SPeter Wemm { 1450c2aa98e2SPeter Wemm LineNumber++; 145140266059SGregory Neil Shapiro i = sm_io_getc(f, SM_TIME_DEFAULT); 145240266059SGregory Neil Shapiro if (i != SM_IO_EOF) 145340266059SGregory Neil Shapiro (void) sm_io_ungetc(f, SM_TIME_DEFAULT, i); 1454c2aa98e2SPeter Wemm if (i != ' ' && i != '\t') 1455c2aa98e2SPeter Wemm break; 1456c2aa98e2SPeter Wemm } 1457c2aa98e2SPeter Wemm } 1458c2aa98e2SPeter Wemm if (p == bp) 145906f25ae9SGregory Neil Shapiro return NULL; 1460c2aa98e2SPeter Wemm if (p[-1] == '\n') 1461c2aa98e2SPeter Wemm p--; 1462c2aa98e2SPeter Wemm *p = '\0'; 146306f25ae9SGregory Neil Shapiro return bp; 1464c2aa98e2SPeter Wemm } 1465d0cef73dSGregory Neil Shapiro 146640266059SGregory Neil Shapiro /* 1467c2aa98e2SPeter Wemm ** CURTIME -- return current time. 1468c2aa98e2SPeter Wemm ** 1469c2aa98e2SPeter Wemm ** Parameters: 1470c2aa98e2SPeter Wemm ** none. 1471c2aa98e2SPeter Wemm ** 1472c2aa98e2SPeter Wemm ** Returns: 1473c2aa98e2SPeter Wemm ** the current time. 1474c2aa98e2SPeter Wemm */ 1475c2aa98e2SPeter Wemm 1476c2aa98e2SPeter Wemm time_t 1477c2aa98e2SPeter Wemm curtime() 1478c2aa98e2SPeter Wemm { 1479c2aa98e2SPeter Wemm auto time_t t; 1480c2aa98e2SPeter Wemm 1481c2aa98e2SPeter Wemm (void) time(&t); 148206f25ae9SGregory Neil Shapiro return t; 1483c2aa98e2SPeter Wemm } 1484d0cef73dSGregory Neil Shapiro 148540266059SGregory Neil Shapiro /* 1486c2aa98e2SPeter Wemm ** ATOBOOL -- convert a string representation to boolean. 1487c2aa98e2SPeter Wemm ** 148840266059SGregory Neil Shapiro ** Defaults to false 1489c2aa98e2SPeter Wemm ** 1490c2aa98e2SPeter Wemm ** Parameters: 149140266059SGregory Neil Shapiro ** s -- string to convert. Takes "tTyY", empty, and NULL as true, 1492c2aa98e2SPeter Wemm ** others as false. 1493c2aa98e2SPeter Wemm ** 1494c2aa98e2SPeter Wemm ** Returns: 1495c2aa98e2SPeter Wemm ** A boolean representation of the string. 1496c2aa98e2SPeter Wemm */ 1497c2aa98e2SPeter Wemm 1498c2aa98e2SPeter Wemm bool 1499c2aa98e2SPeter Wemm atobool(s) 1500c2aa98e2SPeter Wemm register char *s; 1501c2aa98e2SPeter Wemm { 1502c2aa98e2SPeter Wemm if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 150340266059SGregory Neil Shapiro return true; 150440266059SGregory Neil Shapiro return false; 1505c2aa98e2SPeter Wemm } 1506d0cef73dSGregory Neil Shapiro 150740266059SGregory Neil Shapiro /* 1508c2aa98e2SPeter Wemm ** ATOOCT -- convert a string representation to octal. 1509c2aa98e2SPeter Wemm ** 1510c2aa98e2SPeter Wemm ** Parameters: 1511c2aa98e2SPeter Wemm ** s -- string to convert. 1512c2aa98e2SPeter Wemm ** 1513c2aa98e2SPeter Wemm ** Returns: 1514c2aa98e2SPeter Wemm ** An integer representing the string interpreted as an 1515c2aa98e2SPeter Wemm ** octal number. 1516c2aa98e2SPeter Wemm */ 1517c2aa98e2SPeter Wemm 1518c2aa98e2SPeter Wemm int 1519c2aa98e2SPeter Wemm atooct(s) 1520c2aa98e2SPeter Wemm register char *s; 1521c2aa98e2SPeter Wemm { 1522c2aa98e2SPeter Wemm register int i = 0; 1523c2aa98e2SPeter Wemm 1524c2aa98e2SPeter Wemm while (*s >= '0' && *s <= '7') 1525c2aa98e2SPeter Wemm i = (i << 3) | (*s++ - '0'); 152606f25ae9SGregory Neil Shapiro return i; 1527c2aa98e2SPeter Wemm } 1528d0cef73dSGregory Neil Shapiro 152940266059SGregory Neil Shapiro /* 1530c2aa98e2SPeter Wemm ** BITINTERSECT -- tell if two bitmaps intersect 1531c2aa98e2SPeter Wemm ** 1532c2aa98e2SPeter Wemm ** Parameters: 1533c2aa98e2SPeter Wemm ** a, b -- the bitmaps in question 1534c2aa98e2SPeter Wemm ** 1535c2aa98e2SPeter Wemm ** Returns: 153640266059SGregory Neil Shapiro ** true if they have a non-null intersection 153740266059SGregory Neil Shapiro ** false otherwise 1538c2aa98e2SPeter Wemm */ 1539c2aa98e2SPeter Wemm 1540c2aa98e2SPeter Wemm bool 1541c2aa98e2SPeter Wemm bitintersect(a, b) 154206f25ae9SGregory Neil Shapiro BITMAP256 a; 154306f25ae9SGregory Neil Shapiro BITMAP256 b; 1544c2aa98e2SPeter Wemm { 1545c2aa98e2SPeter Wemm int i; 1546c2aa98e2SPeter Wemm 1547c2aa98e2SPeter Wemm for (i = BITMAPBYTES / sizeof(int); --i >= 0; ) 1548193538b7SGregory Neil Shapiro { 1549c2aa98e2SPeter Wemm if ((a[i] & b[i]) != 0) 155040266059SGregory Neil Shapiro return true; 1551193538b7SGregory Neil Shapiro } 155240266059SGregory Neil Shapiro return false; 1553c2aa98e2SPeter Wemm } 1554d0cef73dSGregory Neil Shapiro 155540266059SGregory Neil Shapiro /* 1556c2aa98e2SPeter Wemm ** BITZEROP -- tell if a bitmap is all zero 1557c2aa98e2SPeter Wemm ** 1558c2aa98e2SPeter Wemm ** Parameters: 1559c2aa98e2SPeter Wemm ** map -- the bit map to check 1560c2aa98e2SPeter Wemm ** 1561c2aa98e2SPeter Wemm ** Returns: 156240266059SGregory Neil Shapiro ** true if map is all zero. 156340266059SGregory Neil Shapiro ** false if there are any bits set in map. 1564c2aa98e2SPeter Wemm */ 1565c2aa98e2SPeter Wemm 1566c2aa98e2SPeter Wemm bool 1567c2aa98e2SPeter Wemm bitzerop(map) 156806f25ae9SGregory Neil Shapiro BITMAP256 map; 1569c2aa98e2SPeter Wemm { 1570c2aa98e2SPeter Wemm int i; 1571c2aa98e2SPeter Wemm 1572c2aa98e2SPeter Wemm for (i = BITMAPBYTES / sizeof(int); --i >= 0; ) 1573193538b7SGregory Neil Shapiro { 1574c2aa98e2SPeter Wemm if (map[i] != 0) 157540266059SGregory Neil Shapiro return false; 1576193538b7SGregory Neil Shapiro } 157740266059SGregory Neil Shapiro return true; 1578c2aa98e2SPeter Wemm } 1579d0cef73dSGregory Neil Shapiro 158040266059SGregory Neil Shapiro /* 1581c2aa98e2SPeter Wemm ** STRCONTAINEDIN -- tell if one string is contained in another 1582c2aa98e2SPeter Wemm ** 1583c2aa98e2SPeter Wemm ** Parameters: 158440266059SGregory Neil Shapiro ** icase -- ignore case? 1585c2aa98e2SPeter Wemm ** a -- possible substring. 1586c2aa98e2SPeter Wemm ** b -- possible superstring. 1587c2aa98e2SPeter Wemm ** 1588c2aa98e2SPeter Wemm ** Returns: 158940266059SGregory Neil Shapiro ** true if a is contained in b (case insensitive). 159040266059SGregory Neil Shapiro ** false otherwise. 1591c2aa98e2SPeter Wemm */ 1592c2aa98e2SPeter Wemm 1593c2aa98e2SPeter Wemm bool 159440266059SGregory Neil Shapiro strcontainedin(icase, a, b) 159540266059SGregory Neil Shapiro bool icase; 1596c2aa98e2SPeter Wemm register char *a; 1597c2aa98e2SPeter Wemm register char *b; 1598c2aa98e2SPeter Wemm { 1599c2aa98e2SPeter Wemm int la; 1600c2aa98e2SPeter Wemm int lb; 1601c2aa98e2SPeter Wemm int c; 1602c2aa98e2SPeter Wemm 1603c2aa98e2SPeter Wemm la = strlen(a); 1604c2aa98e2SPeter Wemm lb = strlen(b); 1605c2aa98e2SPeter Wemm c = *a; 160640266059SGregory Neil Shapiro if (icase && isascii(c) && isupper(c)) 1607c2aa98e2SPeter Wemm c = tolower(c); 1608c2aa98e2SPeter Wemm for (; lb-- >= la; b++) 1609c2aa98e2SPeter Wemm { 161040266059SGregory Neil Shapiro if (icase) 161140266059SGregory Neil Shapiro { 161240266059SGregory Neil Shapiro if (*b != c && 161340266059SGregory Neil Shapiro isascii(*b) && isupper(*b) && tolower(*b) != c) 1614c2aa98e2SPeter Wemm continue; 161540266059SGregory Neil Shapiro if (sm_strncasecmp(a, b, la) == 0) 161640266059SGregory Neil Shapiro return true; 1617c2aa98e2SPeter Wemm } 161840266059SGregory Neil Shapiro else 161940266059SGregory Neil Shapiro { 162040266059SGregory Neil Shapiro if (*b != c) 162140266059SGregory Neil Shapiro continue; 162240266059SGregory Neil Shapiro if (strncmp(a, b, la) == 0) 162340266059SGregory Neil Shapiro return true; 1624c2aa98e2SPeter Wemm } 162540266059SGregory Neil Shapiro } 162640266059SGregory Neil Shapiro return false; 162740266059SGregory Neil Shapiro } 1628d0cef73dSGregory Neil Shapiro 162940266059SGregory Neil Shapiro /* 1630c2aa98e2SPeter Wemm ** CHECKFD012 -- check low numbered file descriptors 1631c2aa98e2SPeter Wemm ** 1632c2aa98e2SPeter Wemm ** File descriptors 0, 1, and 2 should be open at all times. 1633c2aa98e2SPeter Wemm ** This routine verifies that, and fixes it if not true. 1634c2aa98e2SPeter Wemm ** 1635c2aa98e2SPeter Wemm ** Parameters: 1636c2aa98e2SPeter Wemm ** where -- a tag printed if the assertion failed 1637c2aa98e2SPeter Wemm ** 1638c2aa98e2SPeter Wemm ** Returns: 1639c2aa98e2SPeter Wemm ** none 1640c2aa98e2SPeter Wemm */ 1641c2aa98e2SPeter Wemm 1642c2aa98e2SPeter Wemm void 1643c2aa98e2SPeter Wemm checkfd012(where) 1644c2aa98e2SPeter Wemm char *where; 1645c2aa98e2SPeter Wemm { 1646c2aa98e2SPeter Wemm #if XDEBUG 1647c2aa98e2SPeter Wemm register int i; 1648c2aa98e2SPeter Wemm 1649c2aa98e2SPeter Wemm for (i = 0; i < 3; i++) 1650c2aa98e2SPeter Wemm fill_fd(i, where); 1651c2aa98e2SPeter Wemm #endif /* XDEBUG */ 1652c2aa98e2SPeter Wemm } 1653d0cef73dSGregory Neil Shapiro 165440266059SGregory Neil Shapiro /* 1655c2aa98e2SPeter Wemm ** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging 1656c2aa98e2SPeter Wemm ** 1657c2aa98e2SPeter Wemm ** Parameters: 1658c2aa98e2SPeter Wemm ** fd -- file descriptor to check. 1659c2aa98e2SPeter Wemm ** where -- tag to print on failure. 1660c2aa98e2SPeter Wemm ** 1661c2aa98e2SPeter Wemm ** Returns: 1662c2aa98e2SPeter Wemm ** none. 1663c2aa98e2SPeter Wemm */ 1664c2aa98e2SPeter Wemm 1665c2aa98e2SPeter Wemm void 1666c2aa98e2SPeter Wemm checkfdopen(fd, where) 1667c2aa98e2SPeter Wemm int fd; 1668c2aa98e2SPeter Wemm char *where; 1669c2aa98e2SPeter Wemm { 1670c2aa98e2SPeter Wemm #if XDEBUG 1671c2aa98e2SPeter Wemm struct stat st; 1672c2aa98e2SPeter Wemm 1673c2aa98e2SPeter Wemm if (fstat(fd, &st) < 0 && errno == EBADF) 1674c2aa98e2SPeter Wemm { 1675c2aa98e2SPeter Wemm syserr("checkfdopen(%d): %s not open as expected!", fd, where); 167640266059SGregory Neil Shapiro printopenfds(true); 1677c2aa98e2SPeter Wemm } 167806f25ae9SGregory Neil Shapiro #endif /* XDEBUG */ 1679c2aa98e2SPeter Wemm } 1680d0cef73dSGregory Neil Shapiro 168140266059SGregory Neil Shapiro /* 1682c2aa98e2SPeter Wemm ** CHECKFDS -- check for new or missing file descriptors 1683c2aa98e2SPeter Wemm ** 1684c2aa98e2SPeter Wemm ** Parameters: 1685c2aa98e2SPeter Wemm ** where -- tag for printing. If null, take a base line. 1686c2aa98e2SPeter Wemm ** 1687c2aa98e2SPeter Wemm ** Returns: 1688c2aa98e2SPeter Wemm ** none 1689c2aa98e2SPeter Wemm ** 1690c2aa98e2SPeter Wemm ** Side Effects: 1691c2aa98e2SPeter Wemm ** If where is set, shows changes since the last call. 1692c2aa98e2SPeter Wemm */ 1693c2aa98e2SPeter Wemm 1694c2aa98e2SPeter Wemm void 1695c2aa98e2SPeter Wemm checkfds(where) 1696c2aa98e2SPeter Wemm char *where; 1697c2aa98e2SPeter Wemm { 1698c2aa98e2SPeter Wemm int maxfd; 1699c2aa98e2SPeter Wemm register int fd; 170040266059SGregory Neil Shapiro bool printhdr = true; 1701c2aa98e2SPeter Wemm int save_errno = errno; 170206f25ae9SGregory Neil Shapiro static BITMAP256 baseline; 1703c2aa98e2SPeter Wemm extern int DtableSize; 1704c2aa98e2SPeter Wemm 1705193538b7SGregory Neil Shapiro if (DtableSize > BITMAPBITS) 1706193538b7SGregory Neil Shapiro maxfd = BITMAPBITS; 1707c2aa98e2SPeter Wemm else 1708c2aa98e2SPeter Wemm maxfd = DtableSize; 1709c2aa98e2SPeter Wemm if (where == NULL) 1710c2aa98e2SPeter Wemm clrbitmap(baseline); 1711c2aa98e2SPeter Wemm 1712c2aa98e2SPeter Wemm for (fd = 0; fd < maxfd; fd++) 1713c2aa98e2SPeter Wemm { 1714c2aa98e2SPeter Wemm struct stat stbuf; 1715c2aa98e2SPeter Wemm 1716c2aa98e2SPeter Wemm if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) 1717c2aa98e2SPeter Wemm { 1718c2aa98e2SPeter Wemm if (!bitnset(fd, baseline)) 1719c2aa98e2SPeter Wemm continue; 1720c2aa98e2SPeter Wemm clrbitn(fd, baseline); 1721c2aa98e2SPeter Wemm } 1722c2aa98e2SPeter Wemm else if (!bitnset(fd, baseline)) 1723c2aa98e2SPeter Wemm setbitn(fd, baseline); 1724c2aa98e2SPeter Wemm else 1725c2aa98e2SPeter Wemm continue; 1726c2aa98e2SPeter Wemm 1727c2aa98e2SPeter Wemm /* file state has changed */ 1728c2aa98e2SPeter Wemm if (where == NULL) 1729c2aa98e2SPeter Wemm continue; 1730c2aa98e2SPeter Wemm if (printhdr) 1731c2aa98e2SPeter Wemm { 1732c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 1733c2aa98e2SPeter Wemm "%s: changed fds:", 1734c2aa98e2SPeter Wemm where); 173540266059SGregory Neil Shapiro printhdr = false; 1736c2aa98e2SPeter Wemm } 173740266059SGregory Neil Shapiro dumpfd(fd, true, true); 1738c2aa98e2SPeter Wemm } 1739c2aa98e2SPeter Wemm errno = save_errno; 1740c2aa98e2SPeter Wemm } 1741d0cef73dSGregory Neil Shapiro 174240266059SGregory Neil Shapiro /* 1743c2aa98e2SPeter Wemm ** PRINTOPENFDS -- print the open file descriptors (for debugging) 1744c2aa98e2SPeter Wemm ** 1745c2aa98e2SPeter Wemm ** Parameters: 1746c2aa98e2SPeter Wemm ** logit -- if set, send output to syslog; otherwise 1747c2aa98e2SPeter Wemm ** print for debugging. 1748c2aa98e2SPeter Wemm ** 1749c2aa98e2SPeter Wemm ** Returns: 1750c2aa98e2SPeter Wemm ** none. 1751c2aa98e2SPeter Wemm */ 1752c2aa98e2SPeter Wemm 175306f25ae9SGregory Neil Shapiro #if NETINET || NETINET6 1754c2aa98e2SPeter Wemm # include <arpa/inet.h> 175506f25ae9SGregory Neil Shapiro #endif /* NETINET || NETINET6 */ 1756c2aa98e2SPeter Wemm 1757c2aa98e2SPeter Wemm void 1758c2aa98e2SPeter Wemm printopenfds(logit) 1759c2aa98e2SPeter Wemm bool logit; 1760c2aa98e2SPeter Wemm { 1761c2aa98e2SPeter Wemm register int fd; 1762c2aa98e2SPeter Wemm extern int DtableSize; 1763c2aa98e2SPeter Wemm 1764c2aa98e2SPeter Wemm for (fd = 0; fd < DtableSize; fd++) 176540266059SGregory Neil Shapiro dumpfd(fd, false, logit); 1766c2aa98e2SPeter Wemm } 1767d0cef73dSGregory Neil Shapiro 176840266059SGregory Neil Shapiro /* 1769c2aa98e2SPeter Wemm ** DUMPFD -- dump a file descriptor 1770c2aa98e2SPeter Wemm ** 1771c2aa98e2SPeter Wemm ** Parameters: 1772c2aa98e2SPeter Wemm ** fd -- the file descriptor to dump. 1773c2aa98e2SPeter Wemm ** printclosed -- if set, print a notification even if 1774c2aa98e2SPeter Wemm ** it is closed; otherwise print nothing. 1775e92d3f3fSGregory Neil Shapiro ** logit -- if set, use sm_syslog instead of sm_dprintf() 177640266059SGregory Neil Shapiro ** 177740266059SGregory Neil Shapiro ** Returns: 177840266059SGregory Neil Shapiro ** none. 1779c2aa98e2SPeter Wemm */ 1780c2aa98e2SPeter Wemm 1781c2aa98e2SPeter Wemm void 1782c2aa98e2SPeter Wemm dumpfd(fd, printclosed, logit) 1783c2aa98e2SPeter Wemm int fd; 1784c2aa98e2SPeter Wemm bool printclosed; 1785c2aa98e2SPeter Wemm bool logit; 1786c2aa98e2SPeter Wemm { 1787c2aa98e2SPeter Wemm register char *p; 1788c2aa98e2SPeter Wemm char *hp; 1789c2aa98e2SPeter Wemm #ifdef S_IFSOCK 1790c2aa98e2SPeter Wemm SOCKADDR sa; 179106f25ae9SGregory Neil Shapiro #endif /* S_IFSOCK */ 1792c2aa98e2SPeter Wemm auto SOCKADDR_LEN_T slen; 1793c2aa98e2SPeter Wemm int i; 1794c2aa98e2SPeter Wemm #if STAT64 > 0 1795c2aa98e2SPeter Wemm struct stat64 st; 179606f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 1797c2aa98e2SPeter Wemm struct stat st; 179806f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 1799c2aa98e2SPeter Wemm char buf[200]; 1800c2aa98e2SPeter Wemm 1801c2aa98e2SPeter Wemm p = buf; 180240266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "%3d: ", fd); 1803c2aa98e2SPeter Wemm p += strlen(p); 1804c2aa98e2SPeter Wemm 1805c2aa98e2SPeter Wemm if ( 1806c2aa98e2SPeter Wemm #if STAT64 > 0 1807c2aa98e2SPeter Wemm fstat64(fd, &st) 180806f25ae9SGregory Neil Shapiro #else /* STAT64 > 0 */ 1809c2aa98e2SPeter Wemm fstat(fd, &st) 181006f25ae9SGregory Neil Shapiro #endif /* STAT64 > 0 */ 1811c2aa98e2SPeter Wemm < 0) 1812c2aa98e2SPeter Wemm { 1813c2aa98e2SPeter Wemm if (errno != EBADF) 1814c2aa98e2SPeter Wemm { 181540266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 181640266059SGregory Neil Shapiro "CANNOT STAT (%s)", 181740266059SGregory Neil Shapiro sm_errstring(errno)); 1818c2aa98e2SPeter Wemm goto printit; 1819c2aa98e2SPeter Wemm } 1820c2aa98e2SPeter Wemm else if (printclosed) 1821c2aa98e2SPeter Wemm { 182240266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "CLOSED"); 1823c2aa98e2SPeter Wemm goto printit; 1824c2aa98e2SPeter Wemm } 1825c2aa98e2SPeter Wemm return; 1826c2aa98e2SPeter Wemm } 1827c2aa98e2SPeter Wemm 1828605302a5SGregory Neil Shapiro i = fcntl(fd, F_GETFL, 0); 1829c2aa98e2SPeter Wemm if (i != -1) 1830c2aa98e2SPeter Wemm { 183140266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i); 1832c2aa98e2SPeter Wemm p += strlen(p); 1833c2aa98e2SPeter Wemm } 1834c2aa98e2SPeter Wemm 183540266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "mode=%o: ", 1836*da7d7b9cSGregory Neil Shapiro (unsigned int) st.st_mode); 1837c2aa98e2SPeter Wemm p += strlen(p); 1838c2aa98e2SPeter Wemm switch (st.st_mode & S_IFMT) 1839c2aa98e2SPeter Wemm { 1840c2aa98e2SPeter Wemm #ifdef S_IFSOCK 1841c2aa98e2SPeter Wemm case S_IFSOCK: 184240266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "SOCK "); 1843c2aa98e2SPeter Wemm p += strlen(p); 1844d0cef73dSGregory Neil Shapiro memset(&sa, '\0', sizeof(sa)); 1845d0cef73dSGregory Neil Shapiro slen = sizeof(sa); 1846c2aa98e2SPeter Wemm if (getsockname(fd, &sa.sa, &slen) < 0) 184740266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)", 184840266059SGregory Neil Shapiro sm_errstring(errno)); 1849c2aa98e2SPeter Wemm else 1850c2aa98e2SPeter Wemm { 1851c2aa98e2SPeter Wemm hp = hostnamebyanyaddr(&sa); 185206f25ae9SGregory Neil Shapiro if (hp == NULL) 185306f25ae9SGregory Neil Shapiro { 185406f25ae9SGregory Neil Shapiro /* EMPTY */ 185506f25ae9SGregory Neil Shapiro /* do nothing */ 185606f25ae9SGregory Neil Shapiro } 185706f25ae9SGregory Neil Shapiro # if NETINET 185806f25ae9SGregory Neil Shapiro else if (sa.sa.sa_family == AF_INET) 185940266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 186040266059SGregory Neil Shapiro "%s/%d", hp, ntohs(sa.sin.sin_port)); 186106f25ae9SGregory Neil Shapiro # endif /* NETINET */ 186206f25ae9SGregory Neil Shapiro # if NETINET6 186306f25ae9SGregory Neil Shapiro else if (sa.sa.sa_family == AF_INET6) 186440266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 186540266059SGregory Neil Shapiro "%s/%d", hp, ntohs(sa.sin6.sin6_port)); 186606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 1867c2aa98e2SPeter Wemm else 186840266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 186940266059SGregory Neil Shapiro "%s", hp); 1870c2aa98e2SPeter Wemm } 1871c2aa98e2SPeter Wemm p += strlen(p); 187240266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "->"); 1873c2aa98e2SPeter Wemm p += strlen(p); 1874d0cef73dSGregory Neil Shapiro slen = sizeof(sa); 1875c2aa98e2SPeter Wemm if (getpeername(fd, &sa.sa, &slen) < 0) 187640266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)", 187740266059SGregory Neil Shapiro sm_errstring(errno)); 1878c2aa98e2SPeter Wemm else 1879c2aa98e2SPeter Wemm { 1880c2aa98e2SPeter Wemm hp = hostnamebyanyaddr(&sa); 188106f25ae9SGregory Neil Shapiro if (hp == NULL) 188206f25ae9SGregory Neil Shapiro { 188306f25ae9SGregory Neil Shapiro /* EMPTY */ 188406f25ae9SGregory Neil Shapiro /* do nothing */ 188506f25ae9SGregory Neil Shapiro } 188606f25ae9SGregory Neil Shapiro # if NETINET 188706f25ae9SGregory Neil Shapiro else if (sa.sa.sa_family == AF_INET) 188840266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 188940266059SGregory Neil Shapiro "%s/%d", hp, ntohs(sa.sin.sin_port)); 189006f25ae9SGregory Neil Shapiro # endif /* NETINET */ 189106f25ae9SGregory Neil Shapiro # if NETINET6 189206f25ae9SGregory Neil Shapiro else if (sa.sa.sa_family == AF_INET6) 189340266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 189440266059SGregory Neil Shapiro "%s/%d", hp, ntohs(sa.sin6.sin6_port)); 189506f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 1896c2aa98e2SPeter Wemm else 189740266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 189840266059SGregory Neil Shapiro "%s", hp); 1899c2aa98e2SPeter Wemm } 1900c2aa98e2SPeter Wemm break; 190106f25ae9SGregory Neil Shapiro #endif /* S_IFSOCK */ 1902c2aa98e2SPeter Wemm 1903c2aa98e2SPeter Wemm case S_IFCHR: 190440266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "CHR: "); 1905c2aa98e2SPeter Wemm p += strlen(p); 1906c2aa98e2SPeter Wemm goto defprint; 1907c2aa98e2SPeter Wemm 190840266059SGregory Neil Shapiro #ifdef S_IFBLK 1909c2aa98e2SPeter Wemm case S_IFBLK: 191040266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "BLK: "); 1911c2aa98e2SPeter Wemm p += strlen(p); 1912c2aa98e2SPeter Wemm goto defprint; 191340266059SGregory Neil Shapiro #endif /* S_IFBLK */ 1914c2aa98e2SPeter Wemm 1915c2aa98e2SPeter Wemm #if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 1916c2aa98e2SPeter Wemm case S_IFIFO: 191740266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "FIFO: "); 1918c2aa98e2SPeter Wemm p += strlen(p); 1919c2aa98e2SPeter Wemm goto defprint; 192006f25ae9SGregory Neil Shapiro #endif /* defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) */ 1921c2aa98e2SPeter Wemm 1922c2aa98e2SPeter Wemm #ifdef S_IFDIR 1923c2aa98e2SPeter Wemm case S_IFDIR: 192440266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "DIR: "); 1925c2aa98e2SPeter Wemm p += strlen(p); 1926c2aa98e2SPeter Wemm goto defprint; 192706f25ae9SGregory Neil Shapiro #endif /* S_IFDIR */ 1928c2aa98e2SPeter Wemm 1929c2aa98e2SPeter Wemm #ifdef S_IFLNK 1930c2aa98e2SPeter Wemm case S_IFLNK: 193140266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "LNK: "); 1932c2aa98e2SPeter Wemm p += strlen(p); 1933c2aa98e2SPeter Wemm goto defprint; 193406f25ae9SGregory Neil Shapiro #endif /* S_IFLNK */ 1935c2aa98e2SPeter Wemm 1936c2aa98e2SPeter Wemm default: 1937c2aa98e2SPeter Wemm defprint: 193840266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 1939*da7d7b9cSGregory Neil Shapiro "dev=%ld/%ld, ino=%llu, nlink=%d, u/gid=%ld/%ld, ", 1940*da7d7b9cSGregory Neil Shapiro (long) major(st.st_dev), (long) minor(st.st_dev), 194140266059SGregory Neil Shapiro (ULONGLONG_T) st.st_ino, 1942*da7d7b9cSGregory Neil Shapiro (int) st.st_nlink, (long) st.st_uid, 1943*da7d7b9cSGregory Neil Shapiro (long) st.st_gid); 194440266059SGregory Neil Shapiro p += strlen(p); 194540266059SGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "size=%llu", 194640266059SGregory Neil Shapiro (ULONGLONG_T) st.st_size); 1947c2aa98e2SPeter Wemm break; 1948c2aa98e2SPeter Wemm } 1949c2aa98e2SPeter Wemm 1950c2aa98e2SPeter Wemm printit: 1951c2aa98e2SPeter Wemm if (logit) 1952c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL, 1953c2aa98e2SPeter Wemm "%.800s", buf); 1954c2aa98e2SPeter Wemm else 1955e92d3f3fSGregory Neil Shapiro sm_dprintf("%s\n", buf); 1956c2aa98e2SPeter Wemm } 1957d0cef73dSGregory Neil Shapiro 195840266059SGregory Neil Shapiro /* 1959c2aa98e2SPeter Wemm ** SHORTEN_HOSTNAME -- strip local domain information off of hostname. 1960c2aa98e2SPeter Wemm ** 1961c2aa98e2SPeter Wemm ** Parameters: 1962c2aa98e2SPeter Wemm ** host -- the host to shorten (stripped in place). 1963c2aa98e2SPeter Wemm ** 1964c2aa98e2SPeter Wemm ** Returns: 196540266059SGregory Neil Shapiro ** place where string was truncated, NULL if not truncated. 1966c2aa98e2SPeter Wemm */ 1967c2aa98e2SPeter Wemm 1968602a2b1bSGregory Neil Shapiro char * 1969c2aa98e2SPeter Wemm shorten_hostname(host) 1970c2aa98e2SPeter Wemm char host[]; 1971c2aa98e2SPeter Wemm { 1972c2aa98e2SPeter Wemm register char *p; 1973c2aa98e2SPeter Wemm char *mydom; 1974c2aa98e2SPeter Wemm int i; 197540266059SGregory Neil Shapiro bool canon = false; 1976c2aa98e2SPeter Wemm 1977c2aa98e2SPeter Wemm /* strip off final dot */ 197840266059SGregory Neil Shapiro i = strlen(host); 197940266059SGregory Neil Shapiro p = &host[(i == 0) ? 0 : i - 1]; 1980c2aa98e2SPeter Wemm if (*p == '.') 1981c2aa98e2SPeter Wemm { 1982c2aa98e2SPeter Wemm *p = '\0'; 198340266059SGregory Neil Shapiro canon = true; 1984c2aa98e2SPeter Wemm } 1985c2aa98e2SPeter Wemm 1986c2aa98e2SPeter Wemm /* see if there is any domain at all -- if not, we are done */ 1987c2aa98e2SPeter Wemm p = strchr(host, '.'); 1988c2aa98e2SPeter Wemm if (p == NULL) 1989602a2b1bSGregory Neil Shapiro return NULL; 1990c2aa98e2SPeter Wemm 1991c2aa98e2SPeter Wemm /* yes, we have a domain -- see if it looks like us */ 1992c2aa98e2SPeter Wemm mydom = macvalue('m', CurEnv); 1993c2aa98e2SPeter Wemm if (mydom == NULL) 1994c2aa98e2SPeter Wemm mydom = ""; 1995c2aa98e2SPeter Wemm i = strlen(++p); 199640266059SGregory Neil Shapiro if ((canon ? sm_strcasecmp(p, mydom) 199740266059SGregory Neil Shapiro : sm_strncasecmp(p, mydom, i)) == 0 && 1998c2aa98e2SPeter Wemm (mydom[i] == '.' || mydom[i] == '\0')) 1999602a2b1bSGregory Neil Shapiro { 2000c2aa98e2SPeter Wemm *--p = '\0'; 2001602a2b1bSGregory Neil Shapiro return p; 2002602a2b1bSGregory Neil Shapiro } 2003602a2b1bSGregory Neil Shapiro return NULL; 2004c2aa98e2SPeter Wemm } 2005d0cef73dSGregory Neil Shapiro 200640266059SGregory Neil Shapiro /* 2007c2aa98e2SPeter Wemm ** PROG_OPEN -- open a program for reading 2008c2aa98e2SPeter Wemm ** 2009c2aa98e2SPeter Wemm ** Parameters: 2010c2aa98e2SPeter Wemm ** argv -- the argument list. 2011c2aa98e2SPeter Wemm ** pfd -- pointer to a place to store the file descriptor. 2012c2aa98e2SPeter Wemm ** e -- the current envelope. 2013c2aa98e2SPeter Wemm ** 2014c2aa98e2SPeter Wemm ** Returns: 2015c2aa98e2SPeter Wemm ** pid of the process -- -1 if it failed. 2016c2aa98e2SPeter Wemm */ 2017c2aa98e2SPeter Wemm 20188774250cSGregory Neil Shapiro pid_t 2019c2aa98e2SPeter Wemm prog_open(argv, pfd, e) 2020c2aa98e2SPeter Wemm char **argv; 2021c2aa98e2SPeter Wemm int *pfd; 2022c2aa98e2SPeter Wemm ENVELOPE *e; 2023c2aa98e2SPeter Wemm { 20248774250cSGregory Neil Shapiro pid_t pid; 202506f25ae9SGregory Neil Shapiro int save_errno; 202640266059SGregory Neil Shapiro int sff; 202740266059SGregory Neil Shapiro int ret; 2028c2aa98e2SPeter Wemm int fdv[2]; 2029c2aa98e2SPeter Wemm char *p, *q; 203094c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 2031c2aa98e2SPeter Wemm extern int DtableSize; 2032c2aa98e2SPeter Wemm 2033c2aa98e2SPeter Wemm if (pipe(fdv) < 0) 2034c2aa98e2SPeter Wemm { 2035c2aa98e2SPeter Wemm syserr("%s: cannot create pipe for stdout", argv[0]); 2036c2aa98e2SPeter Wemm return -1; 2037c2aa98e2SPeter Wemm } 2038c2aa98e2SPeter Wemm pid = fork(); 2039c2aa98e2SPeter Wemm if (pid < 0) 2040c2aa98e2SPeter Wemm { 2041c2aa98e2SPeter Wemm syserr("%s: cannot fork", argv[0]); 204206f25ae9SGregory Neil Shapiro (void) close(fdv[0]); 204306f25ae9SGregory Neil Shapiro (void) close(fdv[1]); 2044c2aa98e2SPeter Wemm return -1; 2045c2aa98e2SPeter Wemm } 2046c2aa98e2SPeter Wemm if (pid > 0) 2047c2aa98e2SPeter Wemm { 2048c2aa98e2SPeter Wemm /* parent */ 204906f25ae9SGregory Neil Shapiro (void) close(fdv[1]); 2050c2aa98e2SPeter Wemm *pfd = fdv[0]; 2051c2aa98e2SPeter Wemm return pid; 2052c2aa98e2SPeter Wemm } 2053c2aa98e2SPeter Wemm 20548774250cSGregory Neil Shapiro /* Reset global flags */ 20558774250cSGregory Neil Shapiro RestartRequest = NULL; 205640266059SGregory Neil Shapiro RestartWorkGroup = false; 20578774250cSGregory Neil Shapiro ShutdownRequest = NULL; 20588774250cSGregory Neil Shapiro PendingSignal = 0; 205940266059SGregory Neil Shapiro CurrentPid = getpid(); 206040266059SGregory Neil Shapiro 206140266059SGregory Neil Shapiro /* 206240266059SGregory Neil Shapiro ** Initialize exception stack and default exception 206340266059SGregory Neil Shapiro ** handler for child process. 206440266059SGregory Neil Shapiro */ 206540266059SGregory Neil Shapiro 206640266059SGregory Neil Shapiro sm_exc_newthread(fatal_error); 206740266059SGregory Neil Shapiro 206840266059SGregory Neil Shapiro /* child -- close stdin */ 206940266059SGregory Neil Shapiro (void) close(0); 20708774250cSGregory Neil Shapiro 2071c2aa98e2SPeter Wemm /* stdout goes back to parent */ 207206f25ae9SGregory Neil Shapiro (void) close(fdv[0]); 2073c2aa98e2SPeter Wemm if (dup2(fdv[1], 1) < 0) 2074c2aa98e2SPeter Wemm { 2075c2aa98e2SPeter Wemm syserr("%s: cannot dup2 for stdout", argv[0]); 2076c2aa98e2SPeter Wemm _exit(EX_OSERR); 2077c2aa98e2SPeter Wemm } 207806f25ae9SGregory Neil Shapiro (void) close(fdv[1]); 2079c2aa98e2SPeter Wemm 2080c2aa98e2SPeter Wemm /* stderr goes to transcript if available */ 2081c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 2082c2aa98e2SPeter Wemm { 208306f25ae9SGregory Neil Shapiro int xfd; 208406f25ae9SGregory Neil Shapiro 208540266059SGregory Neil Shapiro xfd = sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL); 208606f25ae9SGregory Neil Shapiro if (xfd >= 0 && dup2(xfd, 2) < 0) 2087c2aa98e2SPeter Wemm { 2088c2aa98e2SPeter Wemm syserr("%s: cannot dup2 for stderr", argv[0]); 2089c2aa98e2SPeter Wemm _exit(EX_OSERR); 2090c2aa98e2SPeter Wemm } 2091c2aa98e2SPeter Wemm } 2092c2aa98e2SPeter Wemm 2093c2aa98e2SPeter Wemm /* this process has no right to the queue file */ 2094c2aa98e2SPeter Wemm if (e->e_lockfp != NULL) 2095af9557fdSGregory Neil Shapiro { 2096af9557fdSGregory Neil Shapiro int fd; 2097af9557fdSGregory Neil Shapiro 2098af9557fdSGregory Neil Shapiro fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL); 2099af9557fdSGregory Neil Shapiro if (fd >= 0) 2100af9557fdSGregory Neil Shapiro (void) close(fd); 2101af9557fdSGregory Neil Shapiro else 2102af9557fdSGregory Neil Shapiro syserr("%s: lockfp does not have a fd", argv[0]); 2103af9557fdSGregory Neil Shapiro } 210406f25ae9SGregory Neil Shapiro 210506f25ae9SGregory Neil Shapiro /* chroot to the program mailer directory, if defined */ 210606f25ae9SGregory Neil Shapiro if (ProgMailer != NULL && ProgMailer->m_rootdir != NULL) 210706f25ae9SGregory Neil Shapiro { 2108d0cef73dSGregory Neil Shapiro expand(ProgMailer->m_rootdir, buf, sizeof(buf), e); 210906f25ae9SGregory Neil Shapiro if (chroot(buf) < 0) 211006f25ae9SGregory Neil Shapiro { 211106f25ae9SGregory Neil Shapiro syserr("prog_open: cannot chroot(%s)", buf); 211206f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 211306f25ae9SGregory Neil Shapiro } 211406f25ae9SGregory Neil Shapiro if (chdir("/") < 0) 211506f25ae9SGregory Neil Shapiro { 211606f25ae9SGregory Neil Shapiro syserr("prog_open: cannot chdir(/)"); 211706f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 211806f25ae9SGregory Neil Shapiro } 211906f25ae9SGregory Neil Shapiro } 2120c2aa98e2SPeter Wemm 2121c2aa98e2SPeter Wemm /* run as default user */ 2122c2aa98e2SPeter Wemm endpwent(); 212340266059SGregory Neil Shapiro sm_mbdb_terminate(); 21244e4196cbSGregory Neil Shapiro #if _FFR_MEMSTAT 21254e4196cbSGregory Neil Shapiro (void) sm_memstat_close(); 21264e4196cbSGregory Neil Shapiro #endif /* _FFR_MEMSTAT */ 2127c2aa98e2SPeter Wemm if (setgid(DefGid) < 0 && geteuid() == 0) 212806f25ae9SGregory Neil Shapiro { 2129c2aa98e2SPeter Wemm syserr("prog_open: setgid(%ld) failed", (long) DefGid); 213006f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 213106f25ae9SGregory Neil Shapiro } 2132c2aa98e2SPeter Wemm if (setuid(DefUid) < 0 && geteuid() == 0) 213306f25ae9SGregory Neil Shapiro { 2134c2aa98e2SPeter Wemm syserr("prog_open: setuid(%ld) failed", (long) DefUid); 213506f25ae9SGregory Neil Shapiro exit(EX_TEMPFAIL); 213606f25ae9SGregory Neil Shapiro } 2137c2aa98e2SPeter Wemm 2138c2aa98e2SPeter Wemm /* run in some directory */ 2139c2aa98e2SPeter Wemm if (ProgMailer != NULL) 2140c2aa98e2SPeter Wemm p = ProgMailer->m_execdir; 2141c2aa98e2SPeter Wemm else 2142c2aa98e2SPeter Wemm p = NULL; 2143c2aa98e2SPeter Wemm for (; p != NULL; p = q) 2144c2aa98e2SPeter Wemm { 2145c2aa98e2SPeter Wemm q = strchr(p, ':'); 2146c2aa98e2SPeter Wemm if (q != NULL) 2147c2aa98e2SPeter Wemm *q = '\0'; 2148d0cef73dSGregory Neil Shapiro expand(p, buf, sizeof(buf), e); 2149c2aa98e2SPeter Wemm if (q != NULL) 2150c2aa98e2SPeter Wemm *q++ = ':'; 2151c2aa98e2SPeter Wemm if (buf[0] != '\0' && chdir(buf) >= 0) 2152c2aa98e2SPeter Wemm break; 2153c2aa98e2SPeter Wemm } 2154c2aa98e2SPeter Wemm if (p == NULL) 2155c2aa98e2SPeter Wemm { 2156c2aa98e2SPeter Wemm /* backup directories */ 2157c2aa98e2SPeter Wemm if (chdir("/tmp") < 0) 2158c2aa98e2SPeter Wemm (void) chdir("/"); 2159c2aa98e2SPeter Wemm } 2160c2aa98e2SPeter Wemm 216140266059SGregory Neil Shapiro /* Check safety of program to be run */ 216240266059SGregory Neil Shapiro sff = SFF_ROOTOK|SFF_EXECOK; 216340266059SGregory Neil Shapiro if (!bitnset(DBS_RUNWRITABLEPROGRAM, DontBlameSendmail)) 216440266059SGregory Neil Shapiro sff |= SFF_NOGWFILES|SFF_NOWWFILES; 216540266059SGregory Neil Shapiro if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, DontBlameSendmail)) 216640266059SGregory Neil Shapiro sff |= SFF_NOPATHCHECK; 216740266059SGregory Neil Shapiro else 216840266059SGregory Neil Shapiro sff |= SFF_SAFEDIRPATH; 216940266059SGregory Neil Shapiro ret = safefile(argv[0], DefUid, DefGid, DefUser, sff, 0, NULL); 217040266059SGregory Neil Shapiro if (ret != 0) 217140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 217240266059SGregory Neil Shapiro "Warning: prog_open: program %s unsafe: %s", 217340266059SGregory Neil Shapiro argv[0], sm_errstring(ret)); 217440266059SGregory Neil Shapiro 2175c2aa98e2SPeter Wemm /* arrange for all the files to be closed */ 2176e92d3f3fSGregory Neil Shapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 2177c2aa98e2SPeter Wemm 2178c2aa98e2SPeter Wemm /* now exec the process */ 217906f25ae9SGregory Neil Shapiro (void) execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron); 2180c2aa98e2SPeter Wemm 2181c2aa98e2SPeter Wemm /* woops! failed */ 218206f25ae9SGregory Neil Shapiro save_errno = errno; 2183c2aa98e2SPeter Wemm syserr("%s: cannot exec", argv[0]); 218406f25ae9SGregory Neil Shapiro if (transienterror(save_errno)) 2185c2aa98e2SPeter Wemm _exit(EX_OSERR); 2186c2aa98e2SPeter Wemm _exit(EX_CONFIG); 2187c2aa98e2SPeter Wemm return -1; /* avoid compiler warning on IRIX */ 2188c2aa98e2SPeter Wemm } 2189d0cef73dSGregory Neil Shapiro 219040266059SGregory Neil Shapiro /* 2191c2aa98e2SPeter Wemm ** GET_COLUMN -- look up a Column in a line buffer 2192c2aa98e2SPeter Wemm ** 2193c2aa98e2SPeter Wemm ** Parameters: 2194c2aa98e2SPeter Wemm ** line -- the raw text line to search. 2195c2aa98e2SPeter Wemm ** col -- the column number to fetch. 2196c2aa98e2SPeter Wemm ** delim -- the delimiter between columns. If null, 2197c2aa98e2SPeter Wemm ** use white space. 2198c2aa98e2SPeter Wemm ** buf -- the output buffer. 2199c2aa98e2SPeter Wemm ** buflen -- the length of buf. 2200c2aa98e2SPeter Wemm ** 2201c2aa98e2SPeter Wemm ** Returns: 2202c2aa98e2SPeter Wemm ** buf if successful. 2203c2aa98e2SPeter Wemm ** NULL otherwise. 2204c2aa98e2SPeter Wemm */ 2205c2aa98e2SPeter Wemm 2206c2aa98e2SPeter Wemm char * 2207c2aa98e2SPeter Wemm get_column(line, col, delim, buf, buflen) 2208c2aa98e2SPeter Wemm char line[]; 2209c2aa98e2SPeter Wemm int col; 221006f25ae9SGregory Neil Shapiro int delim; 2211c2aa98e2SPeter Wemm char buf[]; 2212c2aa98e2SPeter Wemm int buflen; 2213c2aa98e2SPeter Wemm { 2214c2aa98e2SPeter Wemm char *p; 2215c2aa98e2SPeter Wemm char *begin, *end; 2216c2aa98e2SPeter Wemm int i; 2217c2aa98e2SPeter Wemm char delimbuf[4]; 2218c2aa98e2SPeter Wemm 221906f25ae9SGregory Neil Shapiro if ((char) delim == '\0') 2220d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(delimbuf, "\n\t ", sizeof(delimbuf)); 2221c2aa98e2SPeter Wemm else 2222c2aa98e2SPeter Wemm { 222306f25ae9SGregory Neil Shapiro delimbuf[0] = (char) delim; 2224c2aa98e2SPeter Wemm delimbuf[1] = '\0'; 2225c2aa98e2SPeter Wemm } 2226c2aa98e2SPeter Wemm 2227c2aa98e2SPeter Wemm p = line; 2228c2aa98e2SPeter Wemm if (*p == '\0') 2229c2aa98e2SPeter Wemm return NULL; /* line empty */ 223006f25ae9SGregory Neil Shapiro if (*p == (char) delim && col == 0) 2231c2aa98e2SPeter Wemm return NULL; /* first column empty */ 2232c2aa98e2SPeter Wemm 2233c2aa98e2SPeter Wemm begin = line; 2234c2aa98e2SPeter Wemm 223506f25ae9SGregory Neil Shapiro if (col == 0 && (char) delim == '\0') 2236c2aa98e2SPeter Wemm { 2237c2aa98e2SPeter Wemm while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 2238c2aa98e2SPeter Wemm begin++; 2239c2aa98e2SPeter Wemm } 2240c2aa98e2SPeter Wemm 2241c2aa98e2SPeter Wemm for (i = 0; i < col; i++) 2242c2aa98e2SPeter Wemm { 2243c2aa98e2SPeter Wemm if ((begin = strpbrk(begin, delimbuf)) == NULL) 2244c2aa98e2SPeter Wemm return NULL; /* no such column */ 2245c2aa98e2SPeter Wemm begin++; 224606f25ae9SGregory Neil Shapiro if ((char) delim == '\0') 2247c2aa98e2SPeter Wemm { 2248c2aa98e2SPeter Wemm while (*begin != '\0' && isascii(*begin) && isspace(*begin)) 2249c2aa98e2SPeter Wemm begin++; 2250c2aa98e2SPeter Wemm } 2251c2aa98e2SPeter Wemm } 2252c2aa98e2SPeter Wemm 2253c2aa98e2SPeter Wemm end = strpbrk(begin, delimbuf); 2254c2aa98e2SPeter Wemm if (end == NULL) 2255c2aa98e2SPeter Wemm i = strlen(begin); 2256c2aa98e2SPeter Wemm else 2257c2aa98e2SPeter Wemm i = end - begin; 2258c2aa98e2SPeter Wemm if (i >= buflen) 2259c2aa98e2SPeter Wemm i = buflen - 1; 226040266059SGregory Neil Shapiro (void) sm_strlcpy(buf, begin, i + 1); 2261c2aa98e2SPeter Wemm return buf; 2262c2aa98e2SPeter Wemm } 2263d0cef73dSGregory Neil Shapiro 226440266059SGregory Neil Shapiro /* 2265c2aa98e2SPeter Wemm ** CLEANSTRCPY -- copy string keeping out bogus characters 2266c2aa98e2SPeter Wemm ** 2267c2aa98e2SPeter Wemm ** Parameters: 2268c2aa98e2SPeter Wemm ** t -- "to" string. 2269c2aa98e2SPeter Wemm ** f -- "from" string. 2270c2aa98e2SPeter Wemm ** l -- length of space available in "to" string. 2271c2aa98e2SPeter Wemm ** 2272c2aa98e2SPeter Wemm ** Returns: 2273c2aa98e2SPeter Wemm ** none. 2274c2aa98e2SPeter Wemm */ 2275c2aa98e2SPeter Wemm 2276c2aa98e2SPeter Wemm void 2277c2aa98e2SPeter Wemm cleanstrcpy(t, f, l) 2278c2aa98e2SPeter Wemm register char *t; 2279c2aa98e2SPeter Wemm register char *f; 2280c2aa98e2SPeter Wemm int l; 2281c2aa98e2SPeter Wemm { 2282c2aa98e2SPeter Wemm /* check for newlines and log if necessary */ 228340266059SGregory Neil Shapiro (void) denlstring(f, true, true); 2284c2aa98e2SPeter Wemm 228506f25ae9SGregory Neil Shapiro if (l <= 0) 228606f25ae9SGregory Neil Shapiro syserr("!cleanstrcpy: length == 0"); 228706f25ae9SGregory Neil Shapiro 2288c2aa98e2SPeter Wemm l--; 2289c2aa98e2SPeter Wemm while (l > 0 && *f != '\0') 2290c2aa98e2SPeter Wemm { 2291c2aa98e2SPeter Wemm if (isascii(*f) && 2292c2aa98e2SPeter Wemm (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) 2293c2aa98e2SPeter Wemm { 2294c2aa98e2SPeter Wemm l--; 2295c2aa98e2SPeter Wemm *t++ = *f; 2296c2aa98e2SPeter Wemm } 2297c2aa98e2SPeter Wemm f++; 2298c2aa98e2SPeter Wemm } 2299c2aa98e2SPeter Wemm *t = '\0'; 2300c2aa98e2SPeter Wemm } 2301d0cef73dSGregory Neil Shapiro 230240266059SGregory Neil Shapiro /* 2303c2aa98e2SPeter Wemm ** DENLSTRING -- convert newlines in a string to spaces 2304c2aa98e2SPeter Wemm ** 2305c2aa98e2SPeter Wemm ** Parameters: 2306c2aa98e2SPeter Wemm ** s -- the input string 2307c2aa98e2SPeter Wemm ** strict -- if set, don't permit continuation lines. 2308c2aa98e2SPeter Wemm ** logattacks -- if set, log attempted attacks. 2309c2aa98e2SPeter Wemm ** 2310c2aa98e2SPeter Wemm ** Returns: 2311c2aa98e2SPeter Wemm ** A pointer to a version of the string with newlines 2312c2aa98e2SPeter Wemm ** mapped to spaces. This should be copied. 2313c2aa98e2SPeter Wemm */ 2314c2aa98e2SPeter Wemm 2315c2aa98e2SPeter Wemm char * 2316c2aa98e2SPeter Wemm denlstring(s, strict, logattacks) 2317c2aa98e2SPeter Wemm char *s; 2318c2aa98e2SPeter Wemm bool strict; 2319c2aa98e2SPeter Wemm bool logattacks; 2320c2aa98e2SPeter Wemm { 2321c2aa98e2SPeter Wemm register char *p; 2322c2aa98e2SPeter Wemm int l; 2323c2aa98e2SPeter Wemm static char *bp = NULL; 2324c2aa98e2SPeter Wemm static int bl = 0; 2325c2aa98e2SPeter Wemm 2326c2aa98e2SPeter Wemm p = s; 2327c2aa98e2SPeter Wemm while ((p = strchr(p, '\n')) != NULL) 2328c2aa98e2SPeter Wemm if (strict || (*++p != ' ' && *p != '\t')) 2329c2aa98e2SPeter Wemm break; 2330c2aa98e2SPeter Wemm if (p == NULL) 2331c2aa98e2SPeter Wemm return s; 2332c2aa98e2SPeter Wemm 2333c2aa98e2SPeter Wemm l = strlen(s) + 1; 2334c2aa98e2SPeter Wemm if (bl < l) 2335c2aa98e2SPeter Wemm { 2336c2aa98e2SPeter Wemm /* allocate more space */ 233740266059SGregory Neil Shapiro char *nbp = sm_pmalloc_x(l); 233840266059SGregory Neil Shapiro 2339c2aa98e2SPeter Wemm if (bp != NULL) 23408774250cSGregory Neil Shapiro sm_free(bp); 234140266059SGregory Neil Shapiro bp = nbp; 2342c2aa98e2SPeter Wemm bl = l; 2343c2aa98e2SPeter Wemm } 234440266059SGregory Neil Shapiro (void) sm_strlcpy(bp, s, l); 2345c2aa98e2SPeter Wemm for (p = bp; (p = strchr(p, '\n')) != NULL; ) 2346c2aa98e2SPeter Wemm *p++ = ' '; 2347c2aa98e2SPeter Wemm 2348c2aa98e2SPeter Wemm if (logattacks) 2349c2aa98e2SPeter Wemm { 2350d0cef73dSGregory Neil Shapiro sm_syslog(LOG_NOTICE, CurEnv ? CurEnv->e_id : NULL, 2351c2aa98e2SPeter Wemm "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", 2352c2aa98e2SPeter Wemm RealHostName == NULL ? "[UNKNOWN]" : RealHostName, 2353c2aa98e2SPeter Wemm shortenstring(bp, MAXSHORTSTR)); 2354c2aa98e2SPeter Wemm } 2355c2aa98e2SPeter Wemm 2356c2aa98e2SPeter Wemm return bp; 2357c2aa98e2SPeter Wemm } 2358739ac4d4SGregory Neil Shapiro 2359739ac4d4SGregory Neil Shapiro /* 2360739ac4d4SGregory Neil Shapiro ** STRREPLNONPRT -- replace "unprintable" characters in a string with subst 2361739ac4d4SGregory Neil Shapiro ** 2362739ac4d4SGregory Neil Shapiro ** Parameters: 2363739ac4d4SGregory Neil Shapiro ** s -- string to manipulate (in place) 2364739ac4d4SGregory Neil Shapiro ** subst -- character to use as replacement 2365739ac4d4SGregory Neil Shapiro ** 2366739ac4d4SGregory Neil Shapiro ** Returns: 2367739ac4d4SGregory Neil Shapiro ** true iff string did not contain "unprintable" characters 2368739ac4d4SGregory Neil Shapiro */ 2369739ac4d4SGregory Neil Shapiro 2370739ac4d4SGregory Neil Shapiro bool 2371739ac4d4SGregory Neil Shapiro strreplnonprt(s, c) 2372739ac4d4SGregory Neil Shapiro char *s; 2373739ac4d4SGregory Neil Shapiro int c; 2374739ac4d4SGregory Neil Shapiro { 2375739ac4d4SGregory Neil Shapiro bool ok; 2376739ac4d4SGregory Neil Shapiro 2377739ac4d4SGregory Neil Shapiro ok = true; 2378739ac4d4SGregory Neil Shapiro if (s == NULL) 2379739ac4d4SGregory Neil Shapiro return ok; 2380739ac4d4SGregory Neil Shapiro while (*s != '\0') 2381739ac4d4SGregory Neil Shapiro { 2382739ac4d4SGregory Neil Shapiro if (!(isascii(*s) && isprint(*s))) 2383739ac4d4SGregory Neil Shapiro { 2384739ac4d4SGregory Neil Shapiro *s = c; 2385739ac4d4SGregory Neil Shapiro ok = false; 2386739ac4d4SGregory Neil Shapiro } 2387739ac4d4SGregory Neil Shapiro ++s; 2388739ac4d4SGregory Neil Shapiro } 2389739ac4d4SGregory Neil Shapiro return ok; 2390739ac4d4SGregory Neil Shapiro } 2391739ac4d4SGregory Neil Shapiro 239240266059SGregory Neil Shapiro /* 2393c2aa98e2SPeter Wemm ** PATH_IS_DIR -- check to see if file exists and is a directory. 2394c2aa98e2SPeter Wemm ** 2395c2aa98e2SPeter Wemm ** There are some additional checks for security violations in 2396c2aa98e2SPeter Wemm ** here. This routine is intended to be used for the host status 2397c2aa98e2SPeter Wemm ** support. 2398c2aa98e2SPeter Wemm ** 2399c2aa98e2SPeter Wemm ** Parameters: 2400c2aa98e2SPeter Wemm ** pathname -- pathname to check for directory-ness. 2401c2aa98e2SPeter Wemm ** createflag -- if set, create directory if needed. 2402c2aa98e2SPeter Wemm ** 2403c2aa98e2SPeter Wemm ** Returns: 240440266059SGregory Neil Shapiro ** true -- if the indicated pathname is a directory 240540266059SGregory Neil Shapiro ** false -- otherwise 2406c2aa98e2SPeter Wemm */ 2407c2aa98e2SPeter Wemm 2408a7ec597cSGregory Neil Shapiro bool 2409c2aa98e2SPeter Wemm path_is_dir(pathname, createflag) 2410c2aa98e2SPeter Wemm char *pathname; 2411c2aa98e2SPeter Wemm bool createflag; 2412c2aa98e2SPeter Wemm { 2413c2aa98e2SPeter Wemm struct stat statbuf; 2414c2aa98e2SPeter Wemm 2415c2aa98e2SPeter Wemm #if HASLSTAT 2416c2aa98e2SPeter Wemm if (lstat(pathname, &statbuf) < 0) 241706f25ae9SGregory Neil Shapiro #else /* HASLSTAT */ 2418c2aa98e2SPeter Wemm if (stat(pathname, &statbuf) < 0) 241906f25ae9SGregory Neil Shapiro #endif /* HASLSTAT */ 2420c2aa98e2SPeter Wemm { 2421c2aa98e2SPeter Wemm if (errno != ENOENT || !createflag) 242240266059SGregory Neil Shapiro return false; 2423c2aa98e2SPeter Wemm if (mkdir(pathname, 0755) < 0) 242440266059SGregory Neil Shapiro return false; 242540266059SGregory Neil Shapiro return true; 2426c2aa98e2SPeter Wemm } 2427c2aa98e2SPeter Wemm if (!S_ISDIR(statbuf.st_mode)) 2428c2aa98e2SPeter Wemm { 2429c2aa98e2SPeter Wemm errno = ENOTDIR; 243040266059SGregory Neil Shapiro return false; 2431c2aa98e2SPeter Wemm } 2432c2aa98e2SPeter Wemm 2433c2aa98e2SPeter Wemm /* security: don't allow writable directories */ 2434c2aa98e2SPeter Wemm if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) 2435c2aa98e2SPeter Wemm { 2436c2aa98e2SPeter Wemm errno = EACCES; 243740266059SGregory Neil Shapiro return false; 2438c2aa98e2SPeter Wemm } 243940266059SGregory Neil Shapiro return true; 2440c2aa98e2SPeter Wemm } 2441d0cef73dSGregory Neil Shapiro 244240266059SGregory Neil Shapiro /* 2443c2aa98e2SPeter Wemm ** PROC_LIST_ADD -- add process id to list of our children 2444c2aa98e2SPeter Wemm ** 2445c2aa98e2SPeter Wemm ** Parameters: 2446c2aa98e2SPeter Wemm ** pid -- pid to add to list. 244706f25ae9SGregory Neil Shapiro ** task -- task of pid. 244806f25ae9SGregory Neil Shapiro ** type -- type of process. 244940266059SGregory Neil Shapiro ** count -- number of processes. 245040266059SGregory Neil Shapiro ** other -- other information for this type. 2451c2aa98e2SPeter Wemm ** 2452c2aa98e2SPeter Wemm ** Returns: 2453c2aa98e2SPeter Wemm ** none 245440266059SGregory Neil Shapiro ** 245540266059SGregory Neil Shapiro ** Side Effects: 245640266059SGregory Neil Shapiro ** May increase CurChildren. May grow ProcList. 2457c2aa98e2SPeter Wemm */ 2458c2aa98e2SPeter Wemm 245940266059SGregory Neil Shapiro typedef struct procs PROCS_T; 246040266059SGregory Neil Shapiro 246140266059SGregory Neil Shapiro struct procs 246240266059SGregory Neil Shapiro { 246340266059SGregory Neil Shapiro pid_t proc_pid; 246440266059SGregory Neil Shapiro char *proc_task; 246540266059SGregory Neil Shapiro int proc_type; 246640266059SGregory Neil Shapiro int proc_count; 246740266059SGregory Neil Shapiro int proc_other; 2468e92d3f3fSGregory Neil Shapiro SOCKADDR proc_hostaddr; 246940266059SGregory Neil Shapiro }; 247040266059SGregory Neil Shapiro 247140266059SGregory Neil Shapiro static PROCS_T *volatile ProcListVec = NULL; 2472c2aa98e2SPeter Wemm static int ProcListSize = 0; 2473c2aa98e2SPeter Wemm 2474c2aa98e2SPeter Wemm void 2475e92d3f3fSGregory Neil Shapiro proc_list_add(pid, task, type, count, other, hostaddr) 2476c2aa98e2SPeter Wemm pid_t pid; 2477065a643dSPeter Wemm char *task; 247806f25ae9SGregory Neil Shapiro int type; 247940266059SGregory Neil Shapiro int count; 248040266059SGregory Neil Shapiro int other; 2481e92d3f3fSGregory Neil Shapiro SOCKADDR *hostaddr; 2482c2aa98e2SPeter Wemm { 2483c2aa98e2SPeter Wemm int i; 2484c2aa98e2SPeter Wemm 2485c2aa98e2SPeter Wemm for (i = 0; i < ProcListSize; i++) 2486c2aa98e2SPeter Wemm { 2487065a643dSPeter Wemm if (ProcListVec[i].proc_pid == NO_PID) 2488c2aa98e2SPeter Wemm break; 2489c2aa98e2SPeter Wemm } 2490c2aa98e2SPeter Wemm if (i >= ProcListSize) 2491c2aa98e2SPeter Wemm { 2492c2aa98e2SPeter Wemm /* probe the existing vector to avoid growing infinitely */ 2493c2aa98e2SPeter Wemm proc_list_probe(); 2494c2aa98e2SPeter Wemm 2495c2aa98e2SPeter Wemm /* now scan again */ 2496c2aa98e2SPeter Wemm for (i = 0; i < ProcListSize; i++) 2497c2aa98e2SPeter Wemm { 2498065a643dSPeter Wemm if (ProcListVec[i].proc_pid == NO_PID) 2499c2aa98e2SPeter Wemm break; 2500c2aa98e2SPeter Wemm } 2501c2aa98e2SPeter Wemm } 2502c2aa98e2SPeter Wemm if (i >= ProcListSize) 2503c2aa98e2SPeter Wemm { 2504c2aa98e2SPeter Wemm /* grow process list */ 2505d0cef73dSGregory Neil Shapiro int chldwasblocked; 250640266059SGregory Neil Shapiro PROCS_T *npv; 2507c2aa98e2SPeter Wemm 250840266059SGregory Neil Shapiro SM_ASSERT(ProcListSize < INT_MAX - PROC_LIST_SEG); 2509d0cef73dSGregory Neil Shapiro npv = (PROCS_T *) sm_pmalloc_x((sizeof(*npv)) * 251006f25ae9SGregory Neil Shapiro (ProcListSize + PROC_LIST_SEG)); 2511d0cef73dSGregory Neil Shapiro 2512d0cef73dSGregory Neil Shapiro /* Block SIGCHLD so reapchild() doesn't mess with us */ 2513d0cef73dSGregory Neil Shapiro chldwasblocked = sm_blocksignal(SIGCHLD); 2514c2aa98e2SPeter Wemm if (ProcListSize > 0) 2515c2aa98e2SPeter Wemm { 251606f25ae9SGregory Neil Shapiro memmove(npv, ProcListVec, 251740266059SGregory Neil Shapiro ProcListSize * sizeof(PROCS_T)); 25188774250cSGregory Neil Shapiro sm_free(ProcListVec); 2519c2aa98e2SPeter Wemm } 252040266059SGregory Neil Shapiro 252140266059SGregory Neil Shapiro /* XXX just use memset() to initialize this part? */ 2522c2aa98e2SPeter Wemm for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) 2523065a643dSPeter Wemm { 2524065a643dSPeter Wemm npv[i].proc_pid = NO_PID; 2525065a643dSPeter Wemm npv[i].proc_task = NULL; 252606f25ae9SGregory Neil Shapiro npv[i].proc_type = PROC_NONE; 2527065a643dSPeter Wemm } 2528c2aa98e2SPeter Wemm i = ProcListSize; 2529c2aa98e2SPeter Wemm ProcListSize += PROC_LIST_SEG; 2530c2aa98e2SPeter Wemm ProcListVec = npv; 2531d0cef73dSGregory Neil Shapiro if (chldwasblocked == 0) 2532d0cef73dSGregory Neil Shapiro (void) sm_releasesignal(SIGCHLD); 2533c2aa98e2SPeter Wemm } 2534065a643dSPeter Wemm ProcListVec[i].proc_pid = pid; 253540266059SGregory Neil Shapiro PSTRSET(ProcListVec[i].proc_task, task); 253606f25ae9SGregory Neil Shapiro ProcListVec[i].proc_type = type; 253740266059SGregory Neil Shapiro ProcListVec[i].proc_count = count; 253840266059SGregory Neil Shapiro ProcListVec[i].proc_other = other; 2539e92d3f3fSGregory Neil Shapiro if (hostaddr != NULL) 2540e92d3f3fSGregory Neil Shapiro ProcListVec[i].proc_hostaddr = *hostaddr; 2541e92d3f3fSGregory Neil Shapiro else 2542e92d3f3fSGregory Neil Shapiro memset(&ProcListVec[i].proc_hostaddr, 0, 2543e92d3f3fSGregory Neil Shapiro sizeof(ProcListVec[i].proc_hostaddr)); 2544065a643dSPeter Wemm 2545065a643dSPeter Wemm /* if process adding itself, it's not a child */ 254640266059SGregory Neil Shapiro if (pid != CurrentPid) 254740266059SGregory Neil Shapiro { 254840266059SGregory Neil Shapiro SM_ASSERT(CurChildren < INT_MAX); 2549c2aa98e2SPeter Wemm CurChildren++; 2550c2aa98e2SPeter Wemm } 255140266059SGregory Neil Shapiro } 2552d0cef73dSGregory Neil Shapiro 255340266059SGregory Neil Shapiro /* 2554065a643dSPeter Wemm ** PROC_LIST_SET -- set pid task in process list 2555065a643dSPeter Wemm ** 2556065a643dSPeter Wemm ** Parameters: 2557065a643dSPeter Wemm ** pid -- pid to set 2558065a643dSPeter Wemm ** task -- task of pid 2559065a643dSPeter Wemm ** 2560065a643dSPeter Wemm ** Returns: 2561065a643dSPeter Wemm ** none. 2562065a643dSPeter Wemm */ 2563065a643dSPeter Wemm 2564065a643dSPeter Wemm void 2565065a643dSPeter Wemm proc_list_set(pid, task) 2566065a643dSPeter Wemm pid_t pid; 2567065a643dSPeter Wemm char *task; 2568065a643dSPeter Wemm { 2569065a643dSPeter Wemm int i; 2570065a643dSPeter Wemm 2571065a643dSPeter Wemm for (i = 0; i < ProcListSize; i++) 2572065a643dSPeter Wemm { 2573065a643dSPeter Wemm if (ProcListVec[i].proc_pid == pid) 2574065a643dSPeter Wemm { 257540266059SGregory Neil Shapiro PSTRSET(ProcListVec[i].proc_task, task); 2576065a643dSPeter Wemm break; 2577065a643dSPeter Wemm } 2578065a643dSPeter Wemm } 2579065a643dSPeter Wemm } 2580d0cef73dSGregory Neil Shapiro 258140266059SGregory Neil Shapiro /* 2582c2aa98e2SPeter Wemm ** PROC_LIST_DROP -- drop pid from process list 2583c2aa98e2SPeter Wemm ** 2584c2aa98e2SPeter Wemm ** Parameters: 2585c2aa98e2SPeter Wemm ** pid -- pid to drop 258640266059SGregory Neil Shapiro ** st -- process status 258740266059SGregory Neil Shapiro ** other -- storage for proc_other (return). 2588c2aa98e2SPeter Wemm ** 2589c2aa98e2SPeter Wemm ** Returns: 259040266059SGregory Neil Shapiro ** none. 259140266059SGregory Neil Shapiro ** 259240266059SGregory Neil Shapiro ** Side Effects: 259340266059SGregory Neil Shapiro ** May decrease CurChildren, CurRunners, or 259440266059SGregory Neil Shapiro ** set RestartRequest or ShutdownRequest. 25958774250cSGregory Neil Shapiro ** 25968774250cSGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 25978774250cSGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 25988774250cSGregory Neil Shapiro ** DOING. 2599c2aa98e2SPeter Wemm */ 2600c2aa98e2SPeter Wemm 260140266059SGregory Neil Shapiro void 260240266059SGregory Neil Shapiro proc_list_drop(pid, st, other) 2603c2aa98e2SPeter Wemm pid_t pid; 260440266059SGregory Neil Shapiro int st; 260540266059SGregory Neil Shapiro int *other; 2606c2aa98e2SPeter Wemm { 2607c2aa98e2SPeter Wemm int i; 260806f25ae9SGregory Neil Shapiro int type = PROC_NONE; 2609c2aa98e2SPeter Wemm 2610c2aa98e2SPeter Wemm for (i = 0; i < ProcListSize; i++) 2611c2aa98e2SPeter Wemm { 2612065a643dSPeter Wemm if (ProcListVec[i].proc_pid == pid) 2613c2aa98e2SPeter Wemm { 2614065a643dSPeter Wemm ProcListVec[i].proc_pid = NO_PID; 261506f25ae9SGregory Neil Shapiro type = ProcListVec[i].proc_type; 261640266059SGregory Neil Shapiro if (other != NULL) 261740266059SGregory Neil Shapiro *other = ProcListVec[i].proc_other; 26184e4196cbSGregory Neil Shapiro if (CurChildren > 0) 26194e4196cbSGregory Neil Shapiro CurChildren--; 2620c2aa98e2SPeter Wemm break; 2621c2aa98e2SPeter Wemm } 2622c2aa98e2SPeter Wemm } 262306f25ae9SGregory Neil Shapiro 262406f25ae9SGregory Neil Shapiro 262540266059SGregory Neil Shapiro if (type == PROC_CONTROL && WIFEXITED(st)) 262640266059SGregory Neil Shapiro { 262740266059SGregory Neil Shapiro /* if so, see if we need to restart or shutdown */ 262840266059SGregory Neil Shapiro if (WEXITSTATUS(st) == EX_RESTART) 262940266059SGregory Neil Shapiro RestartRequest = "control socket"; 263040266059SGregory Neil Shapiro else if (WEXITSTATUS(st) == EX_SHUTDOWN) 263140266059SGregory Neil Shapiro ShutdownRequest = "control socket"; 2632c2aa98e2SPeter Wemm } 263340266059SGregory Neil Shapiro else if (type == PROC_QUEUE_CHILD && !WIFSTOPPED(st) && 263440266059SGregory Neil Shapiro ProcListVec[i].proc_other > -1) 263540266059SGregory Neil Shapiro { 263640266059SGregory Neil Shapiro /* restart this persistent runner */ 263740266059SGregory Neil Shapiro mark_work_group_restart(ProcListVec[i].proc_other, st); 263840266059SGregory Neil Shapiro } 263940266059SGregory Neil Shapiro else if (type == PROC_QUEUE) 2640ba00ec3dSGregory Neil Shapiro { 264140266059SGregory Neil Shapiro CurRunners -= ProcListVec[i].proc_count; 2642ba00ec3dSGregory Neil Shapiro 2643ba00ec3dSGregory Neil Shapiro /* CHK_CUR_RUNNERS() can't be used here: uses syslog() */ 2644ba00ec3dSGregory Neil Shapiro if (CurRunners < 0) 2645ba00ec3dSGregory Neil Shapiro CurRunners = 0; 2646ba00ec3dSGregory Neil Shapiro } 264740266059SGregory Neil Shapiro } 2648d0cef73dSGregory Neil Shapiro 264940266059SGregory Neil Shapiro /* 2650c2aa98e2SPeter Wemm ** PROC_LIST_CLEAR -- clear the process list 2651c2aa98e2SPeter Wemm ** 2652c2aa98e2SPeter Wemm ** Parameters: 2653c2aa98e2SPeter Wemm ** none. 2654c2aa98e2SPeter Wemm ** 2655c2aa98e2SPeter Wemm ** Returns: 2656c2aa98e2SPeter Wemm ** none. 265740266059SGregory Neil Shapiro ** 265840266059SGregory Neil Shapiro ** Side Effects: 265940266059SGregory Neil Shapiro ** Sets CurChildren to zero. 2660c2aa98e2SPeter Wemm */ 2661c2aa98e2SPeter Wemm 2662c2aa98e2SPeter Wemm void 2663c2aa98e2SPeter Wemm proc_list_clear() 2664c2aa98e2SPeter Wemm { 2665c2aa98e2SPeter Wemm int i; 2666c2aa98e2SPeter Wemm 2667065a643dSPeter Wemm /* start from 1 since 0 is the daemon itself */ 2668065a643dSPeter Wemm for (i = 1; i < ProcListSize; i++) 2669065a643dSPeter Wemm ProcListVec[i].proc_pid = NO_PID; 2670c2aa98e2SPeter Wemm CurChildren = 0; 2671c2aa98e2SPeter Wemm } 2672d0cef73dSGregory Neil Shapiro 267340266059SGregory Neil Shapiro /* 2674c2aa98e2SPeter Wemm ** PROC_LIST_PROBE -- probe processes in the list to see if they still exist 2675c2aa98e2SPeter Wemm ** 2676c2aa98e2SPeter Wemm ** Parameters: 2677c2aa98e2SPeter Wemm ** none 2678c2aa98e2SPeter Wemm ** 2679c2aa98e2SPeter Wemm ** Returns: 2680c2aa98e2SPeter Wemm ** none 268140266059SGregory Neil Shapiro ** 268240266059SGregory Neil Shapiro ** Side Effects: 268340266059SGregory Neil Shapiro ** May decrease CurChildren. 2684c2aa98e2SPeter Wemm */ 2685c2aa98e2SPeter Wemm 2686c2aa98e2SPeter Wemm void 2687c2aa98e2SPeter Wemm proc_list_probe() 2688c2aa98e2SPeter Wemm { 26894e4196cbSGregory Neil Shapiro int i, children; 26904e4196cbSGregory Neil Shapiro int chldwasblocked; 26914e4196cbSGregory Neil Shapiro pid_t pid; 26924e4196cbSGregory Neil Shapiro 26934e4196cbSGregory Neil Shapiro children = 0; 26944e4196cbSGregory Neil Shapiro chldwasblocked = sm_blocksignal(SIGCHLD); 2695c2aa98e2SPeter Wemm 2696065a643dSPeter Wemm /* start from 1 since 0 is the daemon itself */ 2697065a643dSPeter Wemm for (i = 1; i < ProcListSize; i++) 2698c2aa98e2SPeter Wemm { 26994e4196cbSGregory Neil Shapiro pid = ProcListVec[i].proc_pid; 27004e4196cbSGregory Neil Shapiro if (pid == NO_PID || pid == CurrentPid) 2701c2aa98e2SPeter Wemm continue; 27024e4196cbSGregory Neil Shapiro if (kill(pid, 0) < 0) 2703c2aa98e2SPeter Wemm { 2704c2aa98e2SPeter Wemm if (LogLevel > 3) 2705c2aa98e2SPeter Wemm sm_syslog(LOG_DEBUG, CurEnv->e_id, 2706c2aa98e2SPeter Wemm "proc_list_probe: lost pid %d", 2707065a643dSPeter Wemm (int) ProcListVec[i].proc_pid); 2708065a643dSPeter Wemm ProcListVec[i].proc_pid = NO_PID; 270940266059SGregory Neil Shapiro SM_FREE_CLR(ProcListVec[i].proc_task); 2710ba00ec3dSGregory Neil Shapiro 2711ba00ec3dSGregory Neil Shapiro if (ProcListVec[i].proc_type == PROC_QUEUE) 2712ba00ec3dSGregory Neil Shapiro { 2713ba00ec3dSGregory Neil Shapiro CurRunners -= ProcListVec[i].proc_count; 2714ba00ec3dSGregory Neil Shapiro CHK_CUR_RUNNERS("proc_list_probe", i, 2715ba00ec3dSGregory Neil Shapiro ProcListVec[i].proc_count); 2716ba00ec3dSGregory Neil Shapiro } 2717ba00ec3dSGregory Neil Shapiro 2718c2aa98e2SPeter Wemm CurChildren--; 2719c2aa98e2SPeter Wemm } 27204e4196cbSGregory Neil Shapiro else 27214e4196cbSGregory Neil Shapiro { 27224e4196cbSGregory Neil Shapiro ++children; 27234e4196cbSGregory Neil Shapiro } 2724c2aa98e2SPeter Wemm } 2725c2aa98e2SPeter Wemm if (CurChildren < 0) 2726c2aa98e2SPeter Wemm CurChildren = 0; 27274e4196cbSGregory Neil Shapiro if (chldwasblocked == 0) 27284e4196cbSGregory Neil Shapiro (void) sm_releasesignal(SIGCHLD); 2729af9557fdSGregory Neil Shapiro if (LogLevel > 10 && children != CurChildren && CurrentPid == DaemonPid) 27304e4196cbSGregory Neil Shapiro { 27314e4196cbSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID, 27324e4196cbSGregory Neil Shapiro "proc_list_probe: found %d children, expected %d", 27334e4196cbSGregory Neil Shapiro children, CurChildren); 27344e4196cbSGregory Neil Shapiro } 2735c2aa98e2SPeter Wemm } 273640266059SGregory Neil Shapiro 273740266059SGregory Neil Shapiro /* 2738065a643dSPeter Wemm ** PROC_LIST_DISPLAY -- display the process list 2739065a643dSPeter Wemm ** 2740065a643dSPeter Wemm ** Parameters: 2741065a643dSPeter Wemm ** out -- output file pointer 274240266059SGregory Neil Shapiro ** prefix -- string to output in front of each line. 2743065a643dSPeter Wemm ** 2744065a643dSPeter Wemm ** Returns: 2745065a643dSPeter Wemm ** none. 2746065a643dSPeter Wemm */ 2747065a643dSPeter Wemm 2748065a643dSPeter Wemm void 274940266059SGregory Neil Shapiro proc_list_display(out, prefix) 275040266059SGregory Neil Shapiro SM_FILE_T *out; 275140266059SGregory Neil Shapiro char *prefix; 2752065a643dSPeter Wemm { 2753065a643dSPeter Wemm int i; 2754065a643dSPeter Wemm 2755065a643dSPeter Wemm for (i = 0; i < ProcListSize; i++) 2756065a643dSPeter Wemm { 2757065a643dSPeter Wemm if (ProcListVec[i].proc_pid == NO_PID) 2758065a643dSPeter Wemm continue; 2759065a643dSPeter Wemm 276040266059SGregory Neil Shapiro (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "%s%d %s%s\n", 276140266059SGregory Neil Shapiro prefix, 276240266059SGregory Neil Shapiro (int) ProcListVec[i].proc_pid, 2763065a643dSPeter Wemm ProcListVec[i].proc_task != NULL ? 2764065a643dSPeter Wemm ProcListVec[i].proc_task : "(unknown)", 2765065a643dSPeter Wemm (OpMode == MD_SMTP || 2766065a643dSPeter Wemm OpMode == MD_DAEMON || 2767065a643dSPeter Wemm OpMode == MD_ARPAFTP) ? "\r" : ""); 2768065a643dSPeter Wemm } 2769065a643dSPeter Wemm } 277040266059SGregory Neil Shapiro 277140266059SGregory Neil Shapiro /* 277240266059SGregory Neil Shapiro ** PROC_LIST_SIGNAL -- send a signal to a type of process in the list 277313058a91SGregory Neil Shapiro ** 277413058a91SGregory Neil Shapiro ** Parameters: 277540266059SGregory Neil Shapiro ** type -- type of process to signal 277640266059SGregory Neil Shapiro ** signal -- the type of signal to send 277713058a91SGregory Neil Shapiro ** 277840266059SGregory Neil Shapiro ** Results: 277940266059SGregory Neil Shapiro ** none. 2780c2aa98e2SPeter Wemm ** 278140266059SGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 278240266059SGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 278340266059SGregory Neil Shapiro ** DOING. 2784c2aa98e2SPeter Wemm */ 2785c2aa98e2SPeter Wemm 278640266059SGregory Neil Shapiro void 278740266059SGregory Neil Shapiro proc_list_signal(type, signal) 278840266059SGregory Neil Shapiro int type; 278940266059SGregory Neil Shapiro int signal; 2790c2aa98e2SPeter Wemm { 279140266059SGregory Neil Shapiro int chldwasblocked; 279240266059SGregory Neil Shapiro int alrmwasblocked; 279340266059SGregory Neil Shapiro int i; 279440266059SGregory Neil Shapiro pid_t mypid = getpid(); 2795c2aa98e2SPeter Wemm 279640266059SGregory Neil Shapiro /* block these signals so that we may signal cleanly */ 279740266059SGregory Neil Shapiro chldwasblocked = sm_blocksignal(SIGCHLD); 279840266059SGregory Neil Shapiro alrmwasblocked = sm_blocksignal(SIGALRM); 279940266059SGregory Neil Shapiro 280040266059SGregory Neil Shapiro /* Find all processes of type and send signal */ 280140266059SGregory Neil Shapiro for (i = 0; i < ProcListSize; i++) 280240266059SGregory Neil Shapiro { 280340266059SGregory Neil Shapiro if (ProcListVec[i].proc_pid == NO_PID || 280440266059SGregory Neil Shapiro ProcListVec[i].proc_pid == mypid) 280540266059SGregory Neil Shapiro continue; 280640266059SGregory Neil Shapiro if (ProcListVec[i].proc_type != type) 280740266059SGregory Neil Shapiro continue; 280840266059SGregory Neil Shapiro (void) kill(ProcListVec[i].proc_pid, signal); 2809c2aa98e2SPeter Wemm } 2810c2aa98e2SPeter Wemm 281140266059SGregory Neil Shapiro /* restore the signals */ 281240266059SGregory Neil Shapiro if (alrmwasblocked == 0) 281340266059SGregory Neil Shapiro (void) sm_releasesignal(SIGALRM); 281440266059SGregory Neil Shapiro if (chldwasblocked == 0) 281540266059SGregory Neil Shapiro (void) sm_releasesignal(SIGCHLD); 2816c2aa98e2SPeter Wemm } 2817e92d3f3fSGregory Neil Shapiro 2818e92d3f3fSGregory Neil Shapiro /* 2819e92d3f3fSGregory Neil Shapiro ** COUNT_OPEN_CONNECTIONS 2820e92d3f3fSGregory Neil Shapiro ** 2821e92d3f3fSGregory Neil Shapiro ** Parameters: 2822e92d3f3fSGregory Neil Shapiro ** hostaddr - ClientAddress 2823e92d3f3fSGregory Neil Shapiro ** 2824e92d3f3fSGregory Neil Shapiro ** Returns: 2825e92d3f3fSGregory Neil Shapiro ** the number of open connections for this client 2826e92d3f3fSGregory Neil Shapiro ** 2827e92d3f3fSGregory Neil Shapiro */ 2828e92d3f3fSGregory Neil Shapiro 2829e92d3f3fSGregory Neil Shapiro int 2830e92d3f3fSGregory Neil Shapiro count_open_connections(hostaddr) 2831e92d3f3fSGregory Neil Shapiro SOCKADDR *hostaddr; 2832e92d3f3fSGregory Neil Shapiro { 2833e92d3f3fSGregory Neil Shapiro int i, n; 2834e92d3f3fSGregory Neil Shapiro 2835e92d3f3fSGregory Neil Shapiro if (hostaddr == NULL) 2836e92d3f3fSGregory Neil Shapiro return 0; 2837ffb83623SGregory Neil Shapiro 2838ffb83623SGregory Neil Shapiro /* 2839e3793f76SGregory Neil Shapiro ** This code gets called before proc_list_add() gets called, 2840e3793f76SGregory Neil Shapiro ** so we (the daemon child for this connection) have not yet 2841e3793f76SGregory Neil Shapiro ** counted ourselves. Hence initialize the counter to 1 2842e3793f76SGregory Neil Shapiro ** instead of 0 to compensate. 2843ffb83623SGregory Neil Shapiro */ 2844ffb83623SGregory Neil Shapiro 2845ffb83623SGregory Neil Shapiro n = 1; 2846e92d3f3fSGregory Neil Shapiro for (i = 0; i < ProcListSize; i++) 2847e92d3f3fSGregory Neil Shapiro { 2848e92d3f3fSGregory Neil Shapiro if (ProcListVec[i].proc_pid == NO_PID) 2849e92d3f3fSGregory Neil Shapiro continue; 2850e92d3f3fSGregory Neil Shapiro if (hostaddr->sa.sa_family != 2851e92d3f3fSGregory Neil Shapiro ProcListVec[i].proc_hostaddr.sa.sa_family) 2852e92d3f3fSGregory Neil Shapiro continue; 2853e92d3f3fSGregory Neil Shapiro #if NETINET 2854e92d3f3fSGregory Neil Shapiro if (hostaddr->sa.sa_family == AF_INET && 2855e92d3f3fSGregory Neil Shapiro (hostaddr->sin.sin_addr.s_addr == 2856e92d3f3fSGregory Neil Shapiro ProcListVec[i].proc_hostaddr.sin.sin_addr.s_addr)) 2857e92d3f3fSGregory Neil Shapiro n++; 2858e92d3f3fSGregory Neil Shapiro #endif /* NETINET */ 2859e92d3f3fSGregory Neil Shapiro #if NETINET6 2860e92d3f3fSGregory Neil Shapiro if (hostaddr->sa.sa_family == AF_INET6 && 2861e92d3f3fSGregory Neil Shapiro IN6_ARE_ADDR_EQUAL(&(hostaddr->sin6.sin6_addr), 2862e92d3f3fSGregory Neil Shapiro &(ProcListVec[i].proc_hostaddr.sin6.sin6_addr))) 2863e92d3f3fSGregory Neil Shapiro n++; 2864e92d3f3fSGregory Neil Shapiro #endif /* NETINET6 */ 2865e92d3f3fSGregory Neil Shapiro } 2866e92d3f3fSGregory Neil Shapiro return n; 2867e92d3f3fSGregory Neil Shapiro } 2868ba00ec3dSGregory Neil Shapiro 2869*da7d7b9cSGregory Neil Shapiro #if _FFR_XCNCT 2870*da7d7b9cSGregory Neil Shapiro /* 2871*da7d7b9cSGregory Neil Shapiro ** XCONNECT -- get X-CONNECT info 2872*da7d7b9cSGregory Neil Shapiro ** 2873*da7d7b9cSGregory Neil Shapiro ** Parameters: 2874*da7d7b9cSGregory Neil Shapiro ** inchannel -- FILE to check 2875*da7d7b9cSGregory Neil Shapiro ** 2876*da7d7b9cSGregory Neil Shapiro ** Returns: 2877*da7d7b9cSGregory Neil Shapiro ** -1 on error 2878*da7d7b9cSGregory Neil Shapiro ** 0 if X-CONNECT was not given 2879*da7d7b9cSGregory Neil Shapiro ** >0 if X-CONNECT was used successfully (D_XCNCT*) 2880*da7d7b9cSGregory Neil Shapiro */ 2881*da7d7b9cSGregory Neil Shapiro 2882*da7d7b9cSGregory Neil Shapiro int 2883*da7d7b9cSGregory Neil Shapiro xconnect(inchannel) 2884*da7d7b9cSGregory Neil Shapiro SM_FILE_T *inchannel; 2885*da7d7b9cSGregory Neil Shapiro { 2886*da7d7b9cSGregory Neil Shapiro int r, i; 2887*da7d7b9cSGregory Neil Shapiro char *p, *b, delim, inp[MAXINPLINE]; 2888*da7d7b9cSGregory Neil Shapiro SOCKADDR addr; 2889*da7d7b9cSGregory Neil Shapiro char **pvp; 2890*da7d7b9cSGregory Neil Shapiro char pvpbuf[PSBUFSIZE]; 2891*da7d7b9cSGregory Neil Shapiro char *peerhostname; /* name of SMTP peer or "localhost" */ 2892*da7d7b9cSGregory Neil Shapiro extern ENVELOPE BlankEnvelope; 2893*da7d7b9cSGregory Neil Shapiro 2894*da7d7b9cSGregory Neil Shapiro #define XCONNECT "X-CONNECT " 2895*da7d7b9cSGregory Neil Shapiro #define XCNNCTLEN (sizeof(XCONNECT) - 1) 2896*da7d7b9cSGregory Neil Shapiro 2897*da7d7b9cSGregory Neil Shapiro /* Ask the ruleset whether to use x-connect */ 2898*da7d7b9cSGregory Neil Shapiro pvp = NULL; 2899*da7d7b9cSGregory Neil Shapiro peerhostname = RealHostName; 2900*da7d7b9cSGregory Neil Shapiro if (peerhostname == NULL) 2901*da7d7b9cSGregory Neil Shapiro peerhostname = "localhost"; 2902*da7d7b9cSGregory Neil Shapiro r = rscap("x_connect", peerhostname, 2903*da7d7b9cSGregory Neil Shapiro anynet_ntoa(&RealHostAddr), &BlankEnvelope, 2904*da7d7b9cSGregory Neil Shapiro &pvp, pvpbuf, sizeof(pvpbuf)); 2905*da7d7b9cSGregory Neil Shapiro if (tTd(75, 8)) 2906*da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "x-connect: rscap=%d", r); 2907*da7d7b9cSGregory Neil Shapiro if (r == EX_UNAVAILABLE) 2908*da7d7b9cSGregory Neil Shapiro return 0; 2909*da7d7b9cSGregory Neil Shapiro if (r != EX_OK) 2910*da7d7b9cSGregory Neil Shapiro { 2911*da7d7b9cSGregory Neil Shapiro /* ruleset error */ 2912*da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "x-connect: rscap=%d", r); 2913*da7d7b9cSGregory Neil Shapiro return 0; 2914*da7d7b9cSGregory Neil Shapiro } 2915*da7d7b9cSGregory Neil Shapiro if (pvp != NULL && pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 2916*da7d7b9cSGregory Neil Shapiro { 2917*da7d7b9cSGregory Neil Shapiro /* $#: no x-connect */ 2918*da7d7b9cSGregory Neil Shapiro if (tTd(75, 7)) 2919*da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "x-connect: nope"); 2920*da7d7b9cSGregory Neil Shapiro return 0; 2921*da7d7b9cSGregory Neil Shapiro } 2922*da7d7b9cSGregory Neil Shapiro 2923*da7d7b9cSGregory Neil Shapiro p = sfgets(inp, sizeof(inp), InChannel, TimeOuts.to_nextcommand, "pre"); 2924*da7d7b9cSGregory Neil Shapiro if (tTd(75, 6)) 2925*da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "x-connect: input=%s", p); 2926*da7d7b9cSGregory Neil Shapiro if (p == NULL || strncasecmp(p, XCONNECT, XCNNCTLEN) != 0) 2927*da7d7b9cSGregory Neil Shapiro return -1; 2928*da7d7b9cSGregory Neil Shapiro p += XCNNCTLEN; 2929*da7d7b9cSGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 2930*da7d7b9cSGregory Neil Shapiro p++; 2931*da7d7b9cSGregory Neil Shapiro 2932*da7d7b9cSGregory Neil Shapiro /* parameters: IPAddress [Hostname[ M]] */ 2933*da7d7b9cSGregory Neil Shapiro b = p; 2934*da7d7b9cSGregory Neil Shapiro while (*p != '\0' && isascii(*p) && 2935*da7d7b9cSGregory Neil Shapiro (isalnum(*p) || *p == '.' || *p== ':')) 2936*da7d7b9cSGregory Neil Shapiro p++; 2937*da7d7b9cSGregory Neil Shapiro delim = *p; 2938*da7d7b9cSGregory Neil Shapiro *p = '\0'; 2939*da7d7b9cSGregory Neil Shapiro 2940*da7d7b9cSGregory Neil Shapiro memset(&addr, '\0', sizeof(addr)); 2941*da7d7b9cSGregory Neil Shapiro addr.sin.sin_addr.s_addr = inet_addr(b); 2942*da7d7b9cSGregory Neil Shapiro if (addr.sin.sin_addr.s_addr != INADDR_NONE) 2943*da7d7b9cSGregory Neil Shapiro { 2944*da7d7b9cSGregory Neil Shapiro addr.sa.sa_family = AF_INET; 2945*da7d7b9cSGregory Neil Shapiro memcpy(&RealHostAddr, &addr, sizeof(addr)); 2946*da7d7b9cSGregory Neil Shapiro if (tTd(75, 2)) 2947*da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "x-connect: addr=%s", 2948*da7d7b9cSGregory Neil Shapiro anynet_ntoa(&RealHostAddr)); 2949*da7d7b9cSGregory Neil Shapiro } 2950*da7d7b9cSGregory Neil Shapiro # if NETINET6 2951*da7d7b9cSGregory Neil Shapiro else if ((r = inet_pton(AF_INET6, b, &addr.sin6.sin6_addr)) == 1) 2952*da7d7b9cSGregory Neil Shapiro { 2953*da7d7b9cSGregory Neil Shapiro addr.sa.sa_family = AF_INET6; 2954*da7d7b9cSGregory Neil Shapiro memcpy(&RealHostAddr, &addr, sizeof(addr)); 2955*da7d7b9cSGregory Neil Shapiro } 2956*da7d7b9cSGregory Neil Shapiro # endif /* NETINET6 */ 2957*da7d7b9cSGregory Neil Shapiro else 2958*da7d7b9cSGregory Neil Shapiro return -1; 2959*da7d7b9cSGregory Neil Shapiro 2960*da7d7b9cSGregory Neil Shapiro /* more parameters? */ 2961*da7d7b9cSGregory Neil Shapiro if (delim != ' ') 2962*da7d7b9cSGregory Neil Shapiro return D_XCNCT; 2963*da7d7b9cSGregory Neil Shapiro while (*p != '\0' && isascii(*p) && isspace(*p)) 2964*da7d7b9cSGregory Neil Shapiro p++; 2965*da7d7b9cSGregory Neil Shapiro 2966*da7d7b9cSGregory Neil Shapiro for (b = ++p, i = 0; 2967*da7d7b9cSGregory Neil Shapiro *p != '\0' && isascii(*p) && (isalnum(*p) || *p == '.' || *p == '-'); 2968*da7d7b9cSGregory Neil Shapiro p++, i++) 2969*da7d7b9cSGregory Neil Shapiro ; 2970*da7d7b9cSGregory Neil Shapiro if (i == 0) 2971*da7d7b9cSGregory Neil Shapiro return D_XCNCT; 2972*da7d7b9cSGregory Neil Shapiro delim = *p; 2973*da7d7b9cSGregory Neil Shapiro if (i > MAXNAME) 2974*da7d7b9cSGregory Neil Shapiro b[MAXNAME] = '\0'; 2975*da7d7b9cSGregory Neil Shapiro else 2976*da7d7b9cSGregory Neil Shapiro b[i] = '\0'; 2977*da7d7b9cSGregory Neil Shapiro SM_FREE_CLR(RealHostName); 2978*da7d7b9cSGregory Neil Shapiro RealHostName = newstr(b); 2979*da7d7b9cSGregory Neil Shapiro if (tTd(75, 2)) 2980*da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "x-connect: host=%s", b); 2981*da7d7b9cSGregory Neil Shapiro *p = delim; 2982*da7d7b9cSGregory Neil Shapiro 2983*da7d7b9cSGregory Neil Shapiro b = p; 2984*da7d7b9cSGregory Neil Shapiro if (*p != ' ') 2985*da7d7b9cSGregory Neil Shapiro return D_XCNCT; 2986*da7d7b9cSGregory Neil Shapiro 2987*da7d7b9cSGregory Neil Shapiro while (*p != '\0' && isascii(*p) && isspace(*p)) 2988*da7d7b9cSGregory Neil Shapiro p++; 2989*da7d7b9cSGregory Neil Shapiro 2990*da7d7b9cSGregory Neil Shapiro if (tTd(75, 4)) 2991*da7d7b9cSGregory Neil Shapiro { 2992*da7d7b9cSGregory Neil Shapiro char *e; 2993*da7d7b9cSGregory Neil Shapiro 2994*da7d7b9cSGregory Neil Shapiro e = strpbrk(p, "\r\n"); 2995*da7d7b9cSGregory Neil Shapiro if (e != NULL) 2996*da7d7b9cSGregory Neil Shapiro *e = '\0'; 2997*da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, "x-connect: rest=%s", p); 2998*da7d7b9cSGregory Neil Shapiro } 2999*da7d7b9cSGregory Neil Shapiro if (*p == 'M') 3000*da7d7b9cSGregory Neil Shapiro return D_XCNCT_M; 3001*da7d7b9cSGregory Neil Shapiro 3002*da7d7b9cSGregory Neil Shapiro return D_XCNCT; 3003*da7d7b9cSGregory Neil Shapiro } 3004*da7d7b9cSGregory Neil Shapiro #endif /* _FFR_XCNCT */ 3005