138032Speter/* 2261194Sgshapiro * Copyright (c) 1998-2007, 2009 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1564562Sgshapiro 16266527SgshapiroSM_RCSID("@(#)$Id: util.c,v 8.427 2013-11-22 20:51:57 ca Exp $") 1764562Sgshapiro 18168515Sgshapiro#include <sm/sendmail.h> 1990792Sgshapiro#include <sysexits.h> 2090792Sgshapiro#include <sm/xtrap.h> 2164562Sgshapiro 2290792Sgshapiro/* 23132943Sgshapiro** NEWSTR -- Create a copy of a C string 24132943Sgshapiro** 25132943Sgshapiro** Parameters: 26132943Sgshapiro** s -- the string to copy. 27132943Sgshapiro** 28132943Sgshapiro** Returns: 29132943Sgshapiro** pointer to newly allocated string. 30132943Sgshapiro*/ 31132943Sgshapiro 32132943Sgshapirochar * 33132943Sgshapironewstr(s) 34132943Sgshapiro const char *s; 35132943Sgshapiro{ 36132943Sgshapiro size_t l; 37132943Sgshapiro char *n; 38132943Sgshapiro 39132943Sgshapiro l = strlen(s); 40132943Sgshapiro SM_ASSERT(l + 1 > l); 41132943Sgshapiro n = xalloc(l + 1); 42132943Sgshapiro sm_strlcpy(n, s, l + 1); 43132943Sgshapiro return n; 44132943Sgshapiro} 45132943Sgshapiro 46132943Sgshapiro/* 4738032Speter** ADDQUOTES -- Adds quotes & quote bits to a string. 4838032Speter** 4990792Sgshapiro** Runs through a string and adds backslashes and quote bits. 5038032Speter** 5138032Speter** Parameters: 5238032Speter** s -- the string to modify. 5390792Sgshapiro** rpool -- resource pool from which to allocate result 5438032Speter** 5538032Speter** Returns: 5638032Speter** pointer to quoted string. 5738032Speter*/ 5838032Speter 5938032Speterchar * 6090792Sgshapiroaddquotes(s, rpool) 6138032Speter char *s; 6290792Sgshapiro SM_RPOOL_T *rpool; 6338032Speter{ 6438032Speter int len = 0; 6538032Speter char c; 6638032Speter char *p = s, *q, *r; 6738032Speter 6838032Speter if (s == NULL) 6938032Speter return NULL; 7038032Speter 7138032Speter /* Find length of quoted string */ 7238032Speter while ((c = *p++) != '\0') 7338032Speter { 7438032Speter len++; 7538032Speter if (c == '\\' || c == '"') 7638032Speter len++; 7738032Speter } 7864562Sgshapiro 7990792Sgshapiro q = r = sm_rpool_malloc_x(rpool, len + 3); 8038032Speter p = s; 8138032Speter 8238032Speter /* add leading quote */ 8338032Speter *q++ = '"'; 8438032Speter while ((c = *p++) != '\0') 8538032Speter { 8638032Speter /* quote \ or " */ 8738032Speter if (c == '\\' || c == '"') 8838032Speter *q++ = '\\'; 8938032Speter *q++ = c; 9038032Speter } 9138032Speter *q++ = '"'; 9238032Speter *q = '\0'; 9338032Speter return r; 9438032Speter} 95110560Sgshapiro 9690792Sgshapiro/* 97141858Sgshapiro** STRIPBACKSLASH -- Strip all leading backslashes from a string, provided 98141858Sgshapiro** the following character is alpha-numerical. 99110560Sgshapiro** 100110560Sgshapiro** This is done in place. 101110560Sgshapiro** 102110560Sgshapiro** Parameters: 103110560Sgshapiro** s -- the string to strip. 104110560Sgshapiro** 105110560Sgshapiro** Returns: 106110560Sgshapiro** none. 107110560Sgshapiro*/ 108110560Sgshapiro 109110560Sgshapirovoid 110110560Sgshapirostripbackslash(s) 111110560Sgshapiro char *s; 112110560Sgshapiro{ 113110560Sgshapiro char *p, *q, c; 114110560Sgshapiro 115110560Sgshapiro if (s == NULL || *s == '\0') 116110560Sgshapiro return; 117110560Sgshapiro p = q = s; 118110560Sgshapiro while (*p == '\\' && (p[1] == '\\' || (isascii(p[1]) && isalnum(p[1])))) 119110560Sgshapiro p++; 120110560Sgshapiro do 121110560Sgshapiro { 122110560Sgshapiro c = *q++ = *p++; 123110560Sgshapiro } while (c != '\0'); 124110560Sgshapiro} 125110560Sgshapiro 126110560Sgshapiro/* 12738032Speter** RFC822_STRING -- Checks string for proper RFC822 string quoting. 12838032Speter** 12938032Speter** Runs through a string and verifies RFC822 special characters 13038032Speter** are only found inside comments, quoted strings, or backslash 13138032Speter** escaped. Also verified balanced quotes and parenthesis. 13238032Speter** 13338032Speter** Parameters: 13438032Speter** s -- the string to modify. 13538032Speter** 13638032Speter** Returns: 13790792Sgshapiro** true iff the string is RFC822 compliant, false otherwise. 13838032Speter*/ 13938032Speter 14038032Speterbool 14138032Speterrfc822_string(s) 14238032Speter char *s; 14338032Speter{ 14490792Sgshapiro bool quoted = false; 14538032Speter int commentlev = 0; 14638032Speter char *c = s; 14738032Speter 14838032Speter if (s == NULL) 14990792Sgshapiro return false; 15038032Speter 15138032Speter while (*c != '\0') 15238032Speter { 15338032Speter /* escaped character */ 15438032Speter if (*c == '\\') 15538032Speter { 15638032Speter c++; 15738032Speter if (*c == '\0') 15890792Sgshapiro return false; 15938032Speter } 16038032Speter else if (commentlev == 0 && *c == '"') 16138032Speter quoted = !quoted; 16238032Speter else if (!quoted) 16338032Speter { 16438032Speter if (*c == ')') 16538032Speter { 16638032Speter /* unbalanced ')' */ 16738032Speter if (commentlev == 0) 16890792Sgshapiro return false; 16938032Speter else 17038032Speter commentlev--; 17138032Speter } 17238032Speter else if (*c == '(') 17338032Speter commentlev++; 17438032Speter else if (commentlev == 0 && 17538032Speter strchr(MustQuoteChars, *c) != NULL) 17690792Sgshapiro return false; 17738032Speter } 17838032Speter c++; 17938032Speter } 18090792Sgshapiro 18138032Speter /* unbalanced '"' or '(' */ 18290792Sgshapiro return !quoted && commentlev == 0; 18338032Speter} 184168515Sgshapiro 18590792Sgshapiro/* 18642575Speter** SHORTEN_RFC822_STRING -- Truncate and rebalance an RFC822 string 18742575Speter** 18864562Sgshapiro** Arbitrarily shorten (in place) an RFC822 string and rebalance 18942575Speter** comments and quotes. 19042575Speter** 19142575Speter** Parameters: 19242575Speter** string -- the string to shorten 19342575Speter** length -- the maximum size, 0 if no maximum 19442575Speter** 19542575Speter** Returns: 19690792Sgshapiro** true if string is changed, false otherwise 19742575Speter** 19842575Speter** Side Effects: 19942575Speter** Changes string in place, possibly resulting 20042575Speter** in a shorter string. 20142575Speter*/ 20242575Speter 20342575Speterbool 20442575Spetershorten_rfc822_string(string, length) 20542575Speter char *string; 20642575Speter size_t length; 20742575Speter{ 20890792Sgshapiro bool backslash = false; 20990792Sgshapiro bool modified = false; 21090792Sgshapiro bool quoted = false; 21142575Speter size_t slen; 21242575Speter int parencount = 0; 21342575Speter char *ptr = string; 21464562Sgshapiro 21542575Speter /* 21642575Speter ** If have to rebalance an already short enough string, 21742575Speter ** need to do it within allocated space. 21842575Speter */ 21971345Sgshapiro 22042575Speter slen = strlen(string); 22142575Speter if (length == 0 || slen < length) 22242575Speter length = slen; 22342575Speter 22442575Speter while (*ptr != '\0') 22542575Speter { 22642575Speter if (backslash) 22742575Speter { 22890792Sgshapiro backslash = false; 22942575Speter goto increment; 23042575Speter } 23142575Speter 23242575Speter if (*ptr == '\\') 23390792Sgshapiro backslash = true; 23442575Speter else if (*ptr == '(') 23542575Speter { 23642575Speter if (!quoted) 23742575Speter parencount++; 23842575Speter } 23942575Speter else if (*ptr == ')') 24042575Speter { 24142575Speter if (--parencount < 0) 24242575Speter parencount = 0; 24342575Speter } 24464562Sgshapiro 24542575Speter /* Inside a comment, quotes don't matter */ 24642575Speter if (parencount <= 0 && *ptr == '"') 24742575Speter quoted = !quoted; 24842575Speter 24942575Speterincrement: 25042575Speter /* Check for sufficient space for next character */ 25164562Sgshapiro if (length - (ptr - string) <= (size_t) ((backslash ? 1 : 0) + 25242575Speter parencount + 25342575Speter (quoted ? 1 : 0))) 25442575Speter { 25542575Speter /* Not enough, backtrack */ 25642575Speter if (*ptr == '\\') 25790792Sgshapiro backslash = false; 25842575Speter else if (*ptr == '(' && !quoted) 25942575Speter parencount--; 26042575Speter else if (*ptr == '"' && parencount == 0) 26190792Sgshapiro quoted = false; 26242575Speter break; 26342575Speter } 26442575Speter ptr++; 26542575Speter } 26642575Speter 26742575Speter /* Rebalance */ 26842575Speter while (parencount-- > 0) 26942575Speter { 27042575Speter if (*ptr != ')') 27142575Speter { 27290792Sgshapiro modified = true; 27342575Speter *ptr = ')'; 27442575Speter } 27542575Speter ptr++; 27642575Speter } 27742575Speter if (quoted) 27842575Speter { 27942575Speter if (*ptr != '"') 28042575Speter { 28190792Sgshapiro modified = true; 28242575Speter *ptr = '"'; 28342575Speter } 28442575Speter ptr++; 28542575Speter } 28642575Speter if (*ptr != '\0') 28742575Speter { 28890792Sgshapiro modified = true; 28942575Speter *ptr = '\0'; 29042575Speter } 29142575Speter return modified; 29242575Speter} 293168515Sgshapiro 29490792Sgshapiro/* 29542575Speter** FIND_CHARACTER -- find an unquoted character in an RFC822 string 29642575Speter** 29742575Speter** Find an unquoted, non-commented character in an RFC822 29842575Speter** string and return a pointer to its location in the 29942575Speter** string. 30042575Speter** 30142575Speter** Parameters: 30242575Speter** string -- the string to search 30342575Speter** character -- the character to find 30442575Speter** 30542575Speter** Returns: 30642575Speter** pointer to the character, or 30742575Speter** a pointer to the end of the line if character is not found 30842575Speter*/ 30942575Speter 31042575Speterchar * 31142575Speterfind_character(string, character) 31242575Speter char *string; 31364562Sgshapiro int character; 31442575Speter{ 31590792Sgshapiro bool backslash = false; 31690792Sgshapiro bool quoted = false; 31742575Speter int parencount = 0; 31864562Sgshapiro 31942575Speter while (string != NULL && *string != '\0') 32042575Speter { 32142575Speter if (backslash) 32242575Speter { 32390792Sgshapiro backslash = false; 32442575Speter if (!quoted && character == '\\' && *string == '\\') 32542575Speter break; 32642575Speter string++; 32742575Speter continue; 32842575Speter } 32942575Speter switch (*string) 33042575Speter { 33142575Speter case '\\': 33290792Sgshapiro backslash = true; 33342575Speter break; 33464562Sgshapiro 33542575Speter case '(': 33642575Speter if (!quoted) 33742575Speter parencount++; 33842575Speter break; 33964562Sgshapiro 34042575Speter case ')': 34142575Speter if (--parencount < 0) 34242575Speter parencount = 0; 34342575Speter break; 34442575Speter } 34564562Sgshapiro 34642575Speter /* Inside a comment, nothing matters */ 34742575Speter if (parencount > 0) 34842575Speter { 34942575Speter string++; 35042575Speter continue; 35142575Speter } 35264562Sgshapiro 35342575Speter if (*string == '"') 35442575Speter quoted = !quoted; 35542575Speter else if (*string == character && !quoted) 35642575Speter break; 35742575Speter string++; 35842575Speter } 35942575Speter 36042575Speter /* Return pointer to the character */ 36142575Speter return string; 36242575Speter} 36390792Sgshapiro 36490792Sgshapiro/* 36590792Sgshapiro** CHECK_BODYTYPE -- check bodytype parameter 36638032Speter** 36738032Speter** Parameters: 36890792Sgshapiro** bodytype -- bodytype parameter 36938032Speter** 37038032Speter** Returns: 37190792Sgshapiro** BODYTYPE_* according to parameter 37238032Speter** 37338032Speter*/ 37438032Speter 37590792Sgshapiroint 37690792Sgshapirocheck_bodytype(bodytype) 37790792Sgshapiro char *bodytype; 37838032Speter{ 37990792Sgshapiro /* check body type for legality */ 38090792Sgshapiro if (bodytype == NULL) 38190792Sgshapiro return BODYTYPE_NONE; 38290792Sgshapiro if (sm_strcasecmp(bodytype, "7BIT") == 0) 38390792Sgshapiro return BODYTYPE_7BIT; 38490792Sgshapiro if (sm_strcasecmp(bodytype, "8BITMIME") == 0) 38590792Sgshapiro return BODYTYPE_8BITMIME; 38690792Sgshapiro return BODYTYPE_ILLEGAL; 38790792Sgshapiro} 38838032Speter 38990792Sgshapiro/* 39090792Sgshapiro** TRUNCATE_AT_DELIM -- truncate string at a delimiter and append "..." 39177349Sgshapiro** 39277349Sgshapiro** Parameters: 39390792Sgshapiro** str -- string to truncate 39490792Sgshapiro** len -- maximum length (including '\0') (0 for unlimited) 39590792Sgshapiro** delim -- delimiter character 39677349Sgshapiro** 39777349Sgshapiro** Returns: 39890792Sgshapiro** None. 39977349Sgshapiro*/ 40077349Sgshapiro 40190792Sgshapirovoid 40290792Sgshapirotruncate_at_delim(str, len, delim) 40390792Sgshapiro char *str; 40490792Sgshapiro size_t len; 40590792Sgshapiro int delim; 40677349Sgshapiro{ 40790792Sgshapiro char *p; 40877349Sgshapiro 40990792Sgshapiro if (str == NULL || len == 0 || strlen(str) < len) 41090792Sgshapiro return; 41177349Sgshapiro 41290792Sgshapiro *(str + len - 1) = '\0'; 41390792Sgshapiro while ((p = strrchr(str, delim)) != NULL) 41477349Sgshapiro { 41590792Sgshapiro *p = '\0'; 41690792Sgshapiro if (p - str + 4 < len) 41790792Sgshapiro { 418120256Sgshapiro *p++ = (char) delim; 41990792Sgshapiro *p = '\0'; 42090792Sgshapiro (void) sm_strlcat(str, "...", len); 42190792Sgshapiro return; 42290792Sgshapiro } 42390792Sgshapiro } 42477349Sgshapiro 42590792Sgshapiro /* Couldn't find a place to append "..." */ 42690792Sgshapiro if (len > 3) 42790792Sgshapiro (void) sm_strlcpy(str, "...", len); 42890792Sgshapiro else 42990792Sgshapiro str[0] = '\0'; 43077349Sgshapiro} 431168515Sgshapiro 43290792Sgshapiro/* 43390792Sgshapiro** XALLOC -- Allocate memory, raise an exception on error 43477349Sgshapiro** 43577349Sgshapiro** Parameters: 43690792Sgshapiro** sz -- size of area to allocate. 43777349Sgshapiro** 43877349Sgshapiro** Returns: 43977349Sgshapiro** pointer to data region. 44077349Sgshapiro** 44190792Sgshapiro** Exceptions: 44290792Sgshapiro** SmHeapOutOfMemory (F:sm.heap) -- cannot allocate memory 44390792Sgshapiro** 44477349Sgshapiro** Side Effects: 44577349Sgshapiro** Memory is allocated. 44677349Sgshapiro*/ 44777349Sgshapiro 44877349Sgshapirochar * 44990792Sgshapiro#if SM_HEAP_CHECK 45090792Sgshapiroxalloc_tagged(sz, file, line) 45190792Sgshapiro register int sz; 45290792Sgshapiro char *file; 45390792Sgshapiro int line; 45490792Sgshapiro#else /* SM_HEAP_CHECK */ 45590792Sgshapiroxalloc(sz) 45690792Sgshapiro register int sz; 45790792Sgshapiro#endif /* SM_HEAP_CHECK */ 45877349Sgshapiro{ 45977349Sgshapiro register char *p; 46077349Sgshapiro 461157001Sgshapiro SM_REQUIRE(sz >= 0); 462157001Sgshapiro 46377349Sgshapiro /* some systems can't handle size zero mallocs */ 46477349Sgshapiro if (sz <= 0) 46577349Sgshapiro sz = 1; 46677349Sgshapiro 46790792Sgshapiro /* scaffolding for testing error handling code */ 46890792Sgshapiro sm_xtrap_raise_x(&SmHeapOutOfMemory); 46990792Sgshapiro 47090792Sgshapiro p = sm_malloc_tagged((unsigned) sz, file, line, sm_heap_group()); 47177349Sgshapiro if (p == NULL) 47277349Sgshapiro { 47390792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 47477349Sgshapiro } 47577349Sgshapiro return p; 47677349Sgshapiro} 477168515Sgshapiro 47890792Sgshapiro/* 47938032Speter** COPYPLIST -- copy list of pointers. 48038032Speter** 48190792Sgshapiro** This routine is the equivalent of strdup for lists of 48238032Speter** pointers. 48338032Speter** 48438032Speter** Parameters: 48538032Speter** list -- list of pointers to copy. 48638032Speter** Must be NULL terminated. 48790792Sgshapiro** copycont -- if true, copy the contents of the vector 48838032Speter** (which must be a string) also. 48990792Sgshapiro** rpool -- resource pool from which to allocate storage, 49090792Sgshapiro** or NULL 49138032Speter** 49238032Speter** Returns: 49338032Speter** a copy of 'list'. 49438032Speter*/ 49538032Speter 49638032Speterchar ** 49790792Sgshapirocopyplist(list, copycont, rpool) 49838032Speter char **list; 49938032Speter bool copycont; 50090792Sgshapiro SM_RPOOL_T *rpool; 50138032Speter{ 50238032Speter register char **vp; 50338032Speter register char **newvp; 50438032Speter 50538032Speter for (vp = list; *vp != NULL; vp++) 50638032Speter continue; 50738032Speter 50838032Speter vp++; 50938032Speter 510168515Sgshapiro newvp = (char **) sm_rpool_malloc_x(rpool, (vp - list) * sizeof(*vp)); 511168515Sgshapiro memmove((char *) newvp, (char *) list, (int) (vp - list) * sizeof(*vp)); 51238032Speter 51338032Speter if (copycont) 51438032Speter { 51538032Speter for (vp = newvp; *vp != NULL; vp++) 51690792Sgshapiro *vp = sm_rpool_strdup_x(rpool, *vp); 51738032Speter } 51838032Speter 51964562Sgshapiro return newvp; 52038032Speter} 521168515Sgshapiro 52290792Sgshapiro/* 52338032Speter** COPYQUEUE -- copy address queue. 52438032Speter** 52590792Sgshapiro** This routine is the equivalent of strdup for address queues; 52664562Sgshapiro** addresses marked as QS_IS_DEAD() aren't copied 52738032Speter** 52838032Speter** Parameters: 52938032Speter** addr -- list of address structures to copy. 53090792Sgshapiro** rpool -- resource pool from which to allocate storage 53138032Speter** 53238032Speter** Returns: 53338032Speter** a copy of 'addr'. 53438032Speter*/ 53538032Speter 53638032SpeterADDRESS * 53790792Sgshapirocopyqueue(addr, rpool) 53838032Speter ADDRESS *addr; 53990792Sgshapiro SM_RPOOL_T *rpool; 54038032Speter{ 54138032Speter register ADDRESS *newaddr; 54238032Speter ADDRESS *ret; 54338032Speter register ADDRESS **tail = &ret; 54438032Speter 54538032Speter while (addr != NULL) 54638032Speter { 54764562Sgshapiro if (!QS_IS_DEAD(addr->q_state)) 54838032Speter { 54990792Sgshapiro newaddr = (ADDRESS *) sm_rpool_malloc_x(rpool, 550168515Sgshapiro sizeof(*newaddr)); 55138032Speter STRUCTCOPY(*addr, *newaddr); 55238032Speter *tail = newaddr; 55338032Speter tail = &newaddr->q_next; 55438032Speter } 55538032Speter addr = addr->q_next; 55638032Speter } 55738032Speter *tail = NULL; 55864562Sgshapiro 55938032Speter return ret; 56038032Speter} 561168515Sgshapiro 56290792Sgshapiro/* 56364562Sgshapiro** LOG_SENDMAIL_PID -- record sendmail pid and command line. 56464562Sgshapiro** 56564562Sgshapiro** Parameters: 56664562Sgshapiro** e -- the current envelope. 56764562Sgshapiro** 56864562Sgshapiro** Returns: 56964562Sgshapiro** none. 57064562Sgshapiro** 57164562Sgshapiro** Side Effects: 57290792Sgshapiro** writes pidfile, logs command line. 573132943Sgshapiro** keeps file open and locked to prevent overwrite of active file 57464562Sgshapiro*/ 57564562Sgshapiro 576132943Sgshapirostatic SM_FILE_T *Pidf = NULL; 577132943Sgshapiro 57864562Sgshapirovoid 57964562Sgshapirolog_sendmail_pid(e) 58064562Sgshapiro ENVELOPE *e; 58164562Sgshapiro{ 58264562Sgshapiro long sff; 58398121Sgshapiro char pidpath[MAXPATHLEN]; 58490792Sgshapiro extern char *CommandLineArgs; 58564562Sgshapiro 58664562Sgshapiro /* write the pid to the log file for posterity */ 587132943Sgshapiro sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT|SFF_NBLOCK; 58864562Sgshapiro if (TrustedUid != 0 && RealUid == TrustedUid) 58964562Sgshapiro sff |= SFF_OPENASROOT; 590168515Sgshapiro expand(PidFile, pidpath, sizeof(pidpath), e); 591132943Sgshapiro Pidf = safefopen(pidpath, O_WRONLY|O_TRUNC, FileMode, sff); 592132943Sgshapiro if (Pidf == NULL) 59364562Sgshapiro { 594132943Sgshapiro if (errno == EWOULDBLOCK) 595132943Sgshapiro sm_syslog(LOG_ERR, NOQID, 596132943Sgshapiro "unable to write pid to %s: file in use by another process", 597132943Sgshapiro pidpath); 598132943Sgshapiro else 599132943Sgshapiro sm_syslog(LOG_ERR, NOQID, 600132943Sgshapiro "unable to write pid to %s: %s", 601132943Sgshapiro pidpath, sm_errstring(errno)); 60264562Sgshapiro } 60364562Sgshapiro else 60464562Sgshapiro { 605132943Sgshapiro PidFilePid = getpid(); 60664562Sgshapiro 60764562Sgshapiro /* write the process id on line 1 */ 608132943Sgshapiro (void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%ld\n", 609132943Sgshapiro (long) PidFilePid); 61064562Sgshapiro 61164562Sgshapiro /* line 2 contains all command line flags */ 612132943Sgshapiro (void) sm_io_fprintf(Pidf, SM_TIME_DEFAULT, "%s\n", 61390792Sgshapiro CommandLineArgs); 61464562Sgshapiro 615132943Sgshapiro /* flush */ 616132943Sgshapiro (void) sm_io_flush(Pidf, SM_TIME_DEFAULT); 617132943Sgshapiro 618132943Sgshapiro /* 619132943Sgshapiro ** Leave pid file open until process ends 620132943Sgshapiro ** so it's not overwritten by another 621132943Sgshapiro ** process. 622132943Sgshapiro */ 62364562Sgshapiro } 62490792Sgshapiro if (LogLevel > 9) 62590792Sgshapiro sm_syslog(LOG_INFO, NOQID, "started as: %s", CommandLineArgs); 62664562Sgshapiro} 627132943Sgshapiro 62890792Sgshapiro/* 629132943Sgshapiro** CLOSE_SENDMAIL_PID -- close sendmail pid file 630132943Sgshapiro** 631132943Sgshapiro** Parameters: 632132943Sgshapiro** none. 633132943Sgshapiro** 634132943Sgshapiro** Returns: 635132943Sgshapiro** none. 636132943Sgshapiro*/ 637132943Sgshapiro 638132943Sgshapirovoid 639132943Sgshapiroclose_sendmail_pid() 640132943Sgshapiro{ 641132943Sgshapiro if (Pidf == NULL) 642132943Sgshapiro return; 643132943Sgshapiro 644132943Sgshapiro (void) sm_io_close(Pidf, SM_TIME_DEFAULT); 645132943Sgshapiro Pidf = NULL; 646132943Sgshapiro} 647132943Sgshapiro 648132943Sgshapiro/* 64964562Sgshapiro** SET_DELIVERY_MODE -- set and record the delivery mode 65064562Sgshapiro** 65164562Sgshapiro** Parameters: 65264562Sgshapiro** mode -- delivery mode 65364562Sgshapiro** e -- the current envelope. 65464562Sgshapiro** 65564562Sgshapiro** Returns: 65664562Sgshapiro** none. 65764562Sgshapiro** 65864562Sgshapiro** Side Effects: 65990792Sgshapiro** sets {deliveryMode} macro 66064562Sgshapiro*/ 66164562Sgshapiro 66264562Sgshapirovoid 66364562Sgshapiroset_delivery_mode(mode, e) 66464562Sgshapiro int mode; 66564562Sgshapiro ENVELOPE *e; 66664562Sgshapiro{ 66764562Sgshapiro char buf[2]; 66864562Sgshapiro 66990792Sgshapiro e->e_sendmode = (char) mode; 67090792Sgshapiro buf[0] = (char) mode; 67164562Sgshapiro buf[1] = '\0'; 67290792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{deliveryMode}"), buf); 67364562Sgshapiro} 674168515Sgshapiro 67590792Sgshapiro/* 67690792Sgshapiro** SET_OP_MODE -- set and record the op mode 67790792Sgshapiro** 67890792Sgshapiro** Parameters: 67990792Sgshapiro** mode -- op mode 68090792Sgshapiro** e -- the current envelope. 68190792Sgshapiro** 68290792Sgshapiro** Returns: 68390792Sgshapiro** none. 68490792Sgshapiro** 68590792Sgshapiro** Side Effects: 68690792Sgshapiro** sets {opMode} macro 68790792Sgshapiro*/ 68890792Sgshapiro 68990792Sgshapirovoid 69090792Sgshapiroset_op_mode(mode) 69190792Sgshapiro int mode; 69290792Sgshapiro{ 69390792Sgshapiro char buf[2]; 69490792Sgshapiro extern ENVELOPE BlankEnvelope; 69590792Sgshapiro 69690792Sgshapiro OpMode = (char) mode; 69790792Sgshapiro buf[0] = (char) mode; 69890792Sgshapiro buf[1] = '\0'; 69990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, MID_OPMODE, buf); 70090792Sgshapiro} 701168515Sgshapiro 70290792Sgshapiro/* 70338032Speter** PRINTAV -- print argument vector. 70438032Speter** 70538032Speter** Parameters: 706132943Sgshapiro** fp -- output file pointer. 70738032Speter** av -- argument vector. 70838032Speter** 70938032Speter** Returns: 71038032Speter** none. 71138032Speter** 71238032Speter** Side Effects: 71338032Speter** prints av. 71438032Speter*/ 71538032Speter 71638032Spetervoid 717132943Sgshapiroprintav(fp, av) 718132943Sgshapiro SM_FILE_T *fp; 719168515Sgshapiro char **av; 72038032Speter{ 72138032Speter while (*av != NULL) 72238032Speter { 72338032Speter if (tTd(0, 44)) 72490792Sgshapiro sm_dprintf("\n\t%08lx=", (unsigned long) *av); 72538032Speter else 726132943Sgshapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, ' '); 727168515Sgshapiro if (tTd(0, 99)) 728168515Sgshapiro sm_dprintf("%s", str2prt(*av++)); 729168515Sgshapiro else 730168515Sgshapiro xputs(fp, *av++); 73138032Speter } 732132943Sgshapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, '\n'); 73338032Speter} 734168515Sgshapiro 73590792Sgshapiro/* 73638032Speter** XPUTS -- put string doing control escapes. 73738032Speter** 73838032Speter** Parameters: 739132943Sgshapiro** fp -- output file pointer. 74038032Speter** s -- string to put. 74138032Speter** 74238032Speter** Returns: 74338032Speter** none. 74438032Speter** 74538032Speter** Side Effects: 74638032Speter** output to stdout 74738032Speter*/ 74838032Speter 74938032Spetervoid 750132943Sgshapiroxputs(fp, s) 751132943Sgshapiro SM_FILE_T *fp; 752168515Sgshapiro const char *s; 75338032Speter{ 754168515Sgshapiro int c; 755168515Sgshapiro struct metamac *mp; 75690792Sgshapiro bool shiftout = false; 75738032Speter extern struct metamac MetaMacros[]; 75890792Sgshapiro static SM_DEBUG_T DebugANSI = SM_DEBUG_INITIALIZER("ANSI", 75990792Sgshapiro "@(#)$Debug: ANSI - enable reverse video in debug output $"); 76038032Speter 76190792Sgshapiro /* 76290792Sgshapiro ** TermEscape is set here, rather than in main(), 76390792Sgshapiro ** because ANSI mode can be turned on or off at any time 76490792Sgshapiro ** if we are in -bt rule testing mode. 76590792Sgshapiro */ 76690792Sgshapiro 76790792Sgshapiro if (sm_debug_unknown(&DebugANSI)) 76890792Sgshapiro { 76990792Sgshapiro if (sm_debug_active(&DebugANSI, 1)) 77090792Sgshapiro { 77190792Sgshapiro TermEscape.te_rv_on = "\033[7m"; 772168515Sgshapiro TermEscape.te_normal = "\033[0m"; 77390792Sgshapiro } 77490792Sgshapiro else 77590792Sgshapiro { 77690792Sgshapiro TermEscape.te_rv_on = ""; 777168515Sgshapiro TermEscape.te_normal = ""; 77890792Sgshapiro } 77990792Sgshapiro } 78090792Sgshapiro 78138032Speter if (s == NULL) 78238032Speter { 783132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s<null>%s", 784168515Sgshapiro TermEscape.te_rv_on, TermEscape.te_normal); 78538032Speter return; 78638032Speter } 78738032Speter while ((c = (*s++ & 0377)) != '\0') 78838032Speter { 78938032Speter if (shiftout) 79038032Speter { 791132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 792168515Sgshapiro TermEscape.te_normal); 79390792Sgshapiro shiftout = false; 79438032Speter } 795168515Sgshapiro if (!isascii(c) && !tTd(84, 1)) 79638032Speter { 79738032Speter if (c == MATCHREPL) 79838032Speter { 799132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 80090792Sgshapiro "%s$", 80190792Sgshapiro TermEscape.te_rv_on); 80290792Sgshapiro shiftout = true; 80338032Speter if (*s == '\0') 80438032Speter continue; 80538032Speter c = *s++ & 0377; 80638032Speter goto printchar; 80738032Speter } 80838032Speter if (c == MACROEXPAND || c == MACRODEXPAND) 80938032Speter { 810132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, 81190792Sgshapiro "%s$", 81290792Sgshapiro TermEscape.te_rv_on); 81338032Speter if (c == MACRODEXPAND) 814132943Sgshapiro (void) sm_io_putc(fp, 81590792Sgshapiro SM_TIME_DEFAULT, '&'); 81690792Sgshapiro shiftout = true; 81738032Speter if (*s == '\0') 81838032Speter continue; 81938032Speter if (strchr("=~&?", *s) != NULL) 820132943Sgshapiro (void) sm_io_putc(fp, 82190792Sgshapiro SM_TIME_DEFAULT, 82290792Sgshapiro *s++); 82338032Speter if (bitset(0200, *s)) 824132943Sgshapiro (void) sm_io_fprintf(fp, 82590792Sgshapiro SM_TIME_DEFAULT, 82690792Sgshapiro "{%s}", 82790792Sgshapiro macname(bitidx(*s++))); 82838032Speter else 829132943Sgshapiro (void) sm_io_fprintf(fp, 83090792Sgshapiro SM_TIME_DEFAULT, 83190792Sgshapiro "%c", 83290792Sgshapiro *s++); 83338032Speter continue; 83438032Speter } 83538032Speter for (mp = MetaMacros; mp->metaname != '\0'; mp++) 83638032Speter { 83790792Sgshapiro if (bitidx(mp->metaval) == c) 83838032Speter { 839132943Sgshapiro (void) sm_io_fprintf(fp, 84090792Sgshapiro SM_TIME_DEFAULT, 84190792Sgshapiro "%s$%c", 84290792Sgshapiro TermEscape.te_rv_on, 84390792Sgshapiro mp->metaname); 84490792Sgshapiro shiftout = true; 84538032Speter break; 84638032Speter } 84738032Speter } 84838032Speter if (c == MATCHCLASS || c == MATCHNCLASS) 84938032Speter { 85038032Speter if (bitset(0200, *s)) 851132943Sgshapiro (void) sm_io_fprintf(fp, 85290792Sgshapiro SM_TIME_DEFAULT, 85390792Sgshapiro "{%s}", 85490792Sgshapiro macname(bitidx(*s++))); 85538032Speter else if (*s != '\0') 856132943Sgshapiro (void) sm_io_fprintf(fp, 85790792Sgshapiro SM_TIME_DEFAULT, 85890792Sgshapiro "%c", 85990792Sgshapiro *s++); 86038032Speter } 86138032Speter if (mp->metaname != '\0') 86238032Speter continue; 86338032Speter 86438032Speter /* unrecognized meta character */ 865132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%sM-", 86690792Sgshapiro TermEscape.te_rv_on); 86790792Sgshapiro shiftout = true; 86838032Speter c &= 0177; 86938032Speter } 87038032Speter printchar: 871203004Sgshapiro if (isascii(c) && isprint(c)) 87238032Speter { 873132943Sgshapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, c); 87438032Speter continue; 87538032Speter } 87638032Speter 87738032Speter /* wasn't a meta-macro -- find another way to print it */ 87838032Speter switch (c) 87938032Speter { 88038032Speter case '\n': 88138032Speter c = 'n'; 88238032Speter break; 88338032Speter 88438032Speter case '\r': 88538032Speter c = 'r'; 88638032Speter break; 88738032Speter 88838032Speter case '\t': 88938032Speter c = 't'; 89038032Speter break; 89138032Speter } 89238032Speter if (!shiftout) 89338032Speter { 894132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 89590792Sgshapiro TermEscape.te_rv_on); 89690792Sgshapiro shiftout = true; 89738032Speter } 898203004Sgshapiro if (isascii(c) && isprint(c)) 89938032Speter { 900132943Sgshapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, '\\'); 901132943Sgshapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, c); 90238032Speter } 903168515Sgshapiro else if (tTd(84, 2)) 904168515Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " %o ", c); 905168515Sgshapiro else if (tTd(84, 1)) 906168515Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, " %#x ", c); 907168515Sgshapiro else if (!isascii(c) && !tTd(84, 1)) 90838032Speter { 909132943Sgshapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, '^'); 910132943Sgshapiro (void) sm_io_putc(fp, SM_TIME_DEFAULT, c ^ 0100); 91138032Speter } 91238032Speter } 91338032Speter if (shiftout) 914132943Sgshapiro (void) sm_io_fprintf(fp, SM_TIME_DEFAULT, "%s", 915168515Sgshapiro TermEscape.te_normal); 916132943Sgshapiro (void) sm_io_flush(fp, SM_TIME_DEFAULT); 91738032Speter} 918168515Sgshapiro 91990792Sgshapiro/* 92038032Speter** MAKELOWER -- Translate a line into lower case 92138032Speter** 92238032Speter** Parameters: 92338032Speter** p -- the string to translate. If NULL, return is 92438032Speter** immediate. 92538032Speter** 92638032Speter** Returns: 92738032Speter** none. 92838032Speter** 92938032Speter** Side Effects: 93038032Speter** String pointed to by p is translated to lower case. 93138032Speter*/ 93238032Speter 93338032Spetervoid 93438032Spetermakelower(p) 93538032Speter register char *p; 93638032Speter{ 93738032Speter register char c; 93838032Speter 93938032Speter if (p == NULL) 94038032Speter return; 94138032Speter for (; (c = *p) != '\0'; p++) 94238032Speter if (isascii(c) && isupper(c)) 94338032Speter *p = tolower(c); 94438032Speter} 945168515Sgshapiro 94690792Sgshapiro/* 94738032Speter** FIXCRLF -- fix <CR><LF> in line. 94838032Speter** 94938032Speter** Looks for the <CR><LF> combination and turns it into the 95038032Speter** UNIX canonical <NL> character. It only takes one line, 95138032Speter** i.e., it is assumed that the first <NL> found is the end 95238032Speter** of the line. 95338032Speter** 95438032Speter** Parameters: 95538032Speter** line -- the line to fix. 95638032Speter** stripnl -- if true, strip the newline also. 95738032Speter** 95838032Speter** Returns: 95938032Speter** none. 96038032Speter** 96138032Speter** Side Effects: 96238032Speter** line is changed in place. 96338032Speter*/ 96438032Speter 96538032Spetervoid 96638032Speterfixcrlf(line, stripnl) 96738032Speter char *line; 96838032Speter bool stripnl; 96938032Speter{ 97038032Speter register char *p; 97138032Speter 97238032Speter p = strchr(line, '\n'); 97338032Speter if (p == NULL) 97438032Speter return; 97538032Speter if (p > line && p[-1] == '\r') 97638032Speter p--; 97738032Speter if (!stripnl) 97838032Speter *p++ = '\n'; 97938032Speter *p = '\0'; 98038032Speter} 981168515Sgshapiro 98290792Sgshapiro/* 98338032Speter** PUTLINE -- put a line like fputs obeying SMTP conventions 98438032Speter** 98538032Speter** This routine always guarantees outputing a newline (or CRLF, 98638032Speter** as appropriate) at the end of the string. 98738032Speter** 98838032Speter** Parameters: 98938032Speter** l -- line to put. 99038032Speter** mci -- the mailer connection information. 99138032Speter** 99238032Speter** Returns: 993157001Sgshapiro** true iff line was written successfully 99438032Speter** 99538032Speter** Side Effects: 99690792Sgshapiro** output of l to mci->mci_out. 99738032Speter*/ 99838032Speter 999157001Sgshapirobool 100038032Speterputline(l, mci) 100138032Speter register char *l; 100238032Speter register MCI *mci; 100338032Speter{ 1004157001Sgshapiro return putxline(l, strlen(l), mci, PXLF_MAPFROM); 100538032Speter} 1006168515Sgshapiro 100790792Sgshapiro/* 100838032Speter** PUTXLINE -- putline with flags bits. 100938032Speter** 101038032Speter** This routine always guarantees outputing a newline (or CRLF, 101138032Speter** as appropriate) at the end of the string. 101238032Speter** 101338032Speter** Parameters: 101438032Speter** l -- line to put. 101538032Speter** len -- the length of the line. 101638032Speter** mci -- the mailer connection information. 101738032Speter** pxflags -- flag bits: 101838032Speter** PXLF_MAPFROM -- map From_ to >From_. 101938032Speter** PXLF_STRIP8BIT -- strip 8th bit. 102038032Speter** PXLF_HEADER -- map bare newline in header to newline space. 102194334Sgshapiro** PXLF_NOADDEOL -- don't add an EOL if one wasn't present. 1022168515Sgshapiro** PXLF_STRIPMQUOTE -- strip METAQUOTE bytes. 102338032Speter** 102438032Speter** Returns: 1025157001Sgshapiro** true iff line was written successfully 102638032Speter** 102738032Speter** Side Effects: 102890792Sgshapiro** output of l to mci->mci_out. 102938032Speter*/ 103038032Speter 1031168515Sgshapiro 1032168515Sgshapiro#define PUTX(limit) \ 1033168515Sgshapiro do \ 1034168515Sgshapiro { \ 1035168515Sgshapiro quotenext = false; \ 1036168515Sgshapiro while (l < limit) \ 1037168515Sgshapiro { \ 1038168515Sgshapiro unsigned char c = (unsigned char) *l++; \ 1039168515Sgshapiro \ 1040168515Sgshapiro if (bitset(PXLF_STRIPMQUOTE, pxflags) && \ 1041168515Sgshapiro !quotenext && c == METAQUOTE) \ 1042168515Sgshapiro { \ 1043168515Sgshapiro quotenext = true; \ 1044168515Sgshapiro continue; \ 1045168515Sgshapiro } \ 1046168515Sgshapiro quotenext = false; \ 1047168515Sgshapiro if (strip8bit) \ 1048168515Sgshapiro c &= 0177; \ 1049168515Sgshapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, \ 1050168515Sgshapiro c) == SM_IO_EOF) \ 1051168515Sgshapiro { \ 1052168515Sgshapiro dead = true; \ 1053168515Sgshapiro break; \ 1054168515Sgshapiro } \ 1055168515Sgshapiro if (TrafficLogFile != NULL) \ 1056168515Sgshapiro (void) sm_io_putc(TrafficLogFile, \ 1057168515Sgshapiro SM_TIME_DEFAULT, \ 1058168515Sgshapiro c); \ 1059168515Sgshapiro } \ 1060168515Sgshapiro } while (0) 1061168515Sgshapiro 1062157001Sgshapirobool 106338032Speterputxline(l, len, mci, pxflags) 106438032Speter register char *l; 106538032Speter size_t len; 106638032Speter register MCI *mci; 106738032Speter int pxflags; 106838032Speter{ 106938032Speter register char *p, *end; 1070168515Sgshapiro int slop; 1071168515Sgshapiro bool dead, quotenext, strip8bit; 107238032Speter 107338032Speter /* strip out 0200 bits -- these can look like TELNET protocol */ 1074168515Sgshapiro strip8bit = bitset(MCIF_7BIT, mci->mci_flags) || 1075168515Sgshapiro bitset(PXLF_STRIP8BIT, pxflags); 1076168515Sgshapiro dead = false; 1077168515Sgshapiro slop = 0; 107838032Speter 107938032Speter end = l + len; 108038032Speter do 108138032Speter { 108294334Sgshapiro bool noeol = false; 108394334Sgshapiro 108438032Speter /* find the end of the line */ 108538032Speter p = memchr(l, '\n', end - l); 108638032Speter if (p == NULL) 108794334Sgshapiro { 108838032Speter p = end; 108994334Sgshapiro noeol = true; 109094334Sgshapiro } 109138032Speter 109238032Speter if (TrafficLogFile != NULL) 109390792Sgshapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 109490792Sgshapiro "%05d >>> ", (int) CurrentPid); 109538032Speter 109638032Speter /* check for line overflow */ 109738032Speter while (mci->mci_mailer->m_linelimit > 0 && 109838032Speter (p - l + slop) > mci->mci_mailer->m_linelimit) 109938032Speter { 110038032Speter register char *q = &l[mci->mci_mailer->m_linelimit - slop - 1]; 110138032Speter 110238032Speter if (l[0] == '.' && slop == 0 && 110338032Speter bitnset(M_XDOT, mci->mci_mailer->m_flags)) 110438032Speter { 110590792Sgshapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 110690792Sgshapiro '.') == SM_IO_EOF) 110790792Sgshapiro dead = true; 110838032Speter if (TrafficLogFile != NULL) 110990792Sgshapiro (void) sm_io_putc(TrafficLogFile, 111090792Sgshapiro SM_TIME_DEFAULT, '.'); 111138032Speter } 111238032Speter else if (l[0] == 'F' && slop == 0 && 111338032Speter bitset(PXLF_MAPFROM, pxflags) && 111438032Speter strncmp(l, "From ", 5) == 0 && 111538032Speter bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 111638032Speter { 111790792Sgshapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 111890792Sgshapiro '>') == SM_IO_EOF) 111990792Sgshapiro dead = true; 112038032Speter if (TrafficLogFile != NULL) 112190792Sgshapiro (void) sm_io_putc(TrafficLogFile, 112290792Sgshapiro SM_TIME_DEFAULT, 112390792Sgshapiro '>'); 112438032Speter } 112564562Sgshapiro if (dead) 112664562Sgshapiro break; 112764562Sgshapiro 1128168515Sgshapiro PUTX(q); 112964562Sgshapiro if (dead) 113064562Sgshapiro break; 113164562Sgshapiro 1132168515Sgshapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 1133168515Sgshapiro '!') == SM_IO_EOF || 113490792Sgshapiro sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 1135168515Sgshapiro mci->mci_mailer->m_eol) == SM_IO_EOF || 1136168515Sgshapiro sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 1137168515Sgshapiro ' ') == SM_IO_EOF) 113864562Sgshapiro { 113990792Sgshapiro dead = true; 114064562Sgshapiro break; 114164562Sgshapiro } 114238032Speter if (TrafficLogFile != NULL) 114338032Speter { 114490792Sgshapiro (void) sm_io_fprintf(TrafficLogFile, 114590792Sgshapiro SM_TIME_DEFAULT, 114690792Sgshapiro "!\n%05d >>> ", 114790792Sgshapiro (int) CurrentPid); 114838032Speter } 114938032Speter slop = 1; 115038032Speter } 115138032Speter 115264562Sgshapiro if (dead) 115364562Sgshapiro break; 115464562Sgshapiro 115538032Speter /* output last part */ 115638032Speter if (l[0] == '.' && slop == 0 && 1157173340Sgshapiro bitnset(M_XDOT, mci->mci_mailer->m_flags) && 1158173340Sgshapiro !bitset(MCIF_INLONGLINE, mci->mci_flags)) 115938032Speter { 116090792Sgshapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '.') == 116190792Sgshapiro SM_IO_EOF) 1162157001Sgshapiro { 1163157001Sgshapiro dead = true; 116464562Sgshapiro break; 116571345Sgshapiro } 116638032Speter if (TrafficLogFile != NULL) 116790792Sgshapiro (void) sm_io_putc(TrafficLogFile, 116890792Sgshapiro SM_TIME_DEFAULT, '.'); 116938032Speter } 117038032Speter else if (l[0] == 'F' && slop == 0 && 117138032Speter bitset(PXLF_MAPFROM, pxflags) && 117238032Speter strncmp(l, "From ", 5) == 0 && 1173173340Sgshapiro bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 1174173340Sgshapiro !bitset(MCIF_INLONGLINE, mci->mci_flags)) 117538032Speter { 117690792Sgshapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, '>') == 117790792Sgshapiro SM_IO_EOF) 1178157001Sgshapiro { 1179157001Sgshapiro dead = true; 118064562Sgshapiro break; 118171345Sgshapiro } 118238032Speter if (TrafficLogFile != NULL) 118390792Sgshapiro (void) sm_io_putc(TrafficLogFile, 118490792Sgshapiro SM_TIME_DEFAULT, '>'); 118538032Speter } 1186168515Sgshapiro PUTX(p); 118764562Sgshapiro if (dead) 118864562Sgshapiro break; 118964562Sgshapiro 119038032Speter if (TrafficLogFile != NULL) 119190792Sgshapiro (void) sm_io_putc(TrafficLogFile, SM_TIME_DEFAULT, 119290792Sgshapiro '\n'); 1193173340Sgshapiro if ((!bitset(PXLF_NOADDEOL, pxflags) || !noeol)) 1194157001Sgshapiro { 1195173340Sgshapiro mci->mci_flags &= ~MCIF_INLONGLINE; 1196173340Sgshapiro if (sm_io_fputs(mci->mci_out, SM_TIME_DEFAULT, 1197173340Sgshapiro mci->mci_mailer->m_eol) == SM_IO_EOF) 1198173340Sgshapiro { 1199173340Sgshapiro dead = true; 1200173340Sgshapiro break; 1201173340Sgshapiro } 120271345Sgshapiro } 1203173340Sgshapiro else 1204173340Sgshapiro mci->mci_flags |= MCIF_INLONGLINE; 1205173340Sgshapiro 120638032Speter if (l < end && *l == '\n') 120738032Speter { 120838032Speter if (*++l != ' ' && *l != '\t' && *l != '\0' && 120938032Speter bitset(PXLF_HEADER, pxflags)) 121038032Speter { 121190792Sgshapiro if (sm_io_putc(mci->mci_out, SM_TIME_DEFAULT, 121290792Sgshapiro ' ') == SM_IO_EOF) 1213157001Sgshapiro { 1214157001Sgshapiro dead = true; 121564562Sgshapiro break; 121671345Sgshapiro } 121790792Sgshapiro 121838032Speter if (TrafficLogFile != NULL) 121990792Sgshapiro (void) sm_io_putc(TrafficLogFile, 122090792Sgshapiro SM_TIME_DEFAULT, ' '); 122138032Speter } 122238032Speter } 122390792Sgshapiro 122438032Speter } while (l < end); 1225157001Sgshapiro return !dead; 122638032Speter} 1227157001Sgshapiro 122890792Sgshapiro/* 122938032Speter** XUNLINK -- unlink a file, doing logging as appropriate. 123038032Speter** 123138032Speter** Parameters: 123238032Speter** f -- name of file to unlink. 123338032Speter** 123438032Speter** Returns: 123590792Sgshapiro** return value of unlink() 123638032Speter** 123738032Speter** Side Effects: 123838032Speter** f is unlinked. 123938032Speter*/ 124038032Speter 124190792Sgshapiroint 124238032Speterxunlink(f) 124338032Speter char *f; 124438032Speter{ 124538032Speter register int i; 124690792Sgshapiro int save_errno; 124738032Speter 124838032Speter if (LogLevel > 98) 124990792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "unlink %s", f); 125038032Speter 125138032Speter i = unlink(f); 125290792Sgshapiro save_errno = errno; 125338032Speter if (i < 0 && LogLevel > 97) 125490792Sgshapiro sm_syslog(LOG_DEBUG, CurEnv->e_id, "%s: unlink-fail %d", 125564562Sgshapiro f, errno); 125690792Sgshapiro if (i >= 0) 125790792Sgshapiro SYNC_DIR(f, false); 125890792Sgshapiro errno = save_errno; 125990792Sgshapiro return i; 126038032Speter} 1261168515Sgshapiro 126290792Sgshapiro/* 126338032Speter** SFGETS -- "safe" fgets -- times out and ignores random interrupts. 126438032Speter** 126538032Speter** Parameters: 126638032Speter** buf -- place to put the input line. 126738032Speter** siz -- size of buf. 126838032Speter** fp -- file to read from. 126938032Speter** timeout -- the timeout before error occurs. 127038032Speter** during -- what we are trying to read (for error messages). 127138032Speter** 127238032Speter** Returns: 127390792Sgshapiro** NULL on error (including timeout). This may also leave 127438032Speter** buf containing a null string. 127538032Speter** buf otherwise. 127638032Speter*/ 127738032Speter 127864562Sgshapiro 127938032Speterchar * 128038032Spetersfgets(buf, siz, fp, timeout, during) 128138032Speter char *buf; 128238032Speter int siz; 128390792Sgshapiro SM_FILE_T *fp; 128438032Speter time_t timeout; 128538032Speter char *during; 128638032Speter{ 128738032Speter register char *p; 1288249729Sgshapiro int save_errno, io_timeout, l; 128938032Speter 129090792Sgshapiro SM_REQUIRE(siz > 0); 129190792Sgshapiro SM_REQUIRE(buf != NULL); 129290792Sgshapiro 129338032Speter if (fp == NULL) 129438032Speter { 129538032Speter buf[0] = '\0'; 129690792Sgshapiro errno = EBADF; 129738032Speter return NULL; 129838032Speter } 129938032Speter 130090792Sgshapiro /* try to read */ 1301249729Sgshapiro l = -1; 130290792Sgshapiro errno = 0; 130390792Sgshapiro 130490792Sgshapiro /* convert the timeout to sm_io notation */ 130590792Sgshapiro io_timeout = (timeout <= 0) ? SM_TIME_DEFAULT : timeout * 1000; 130690792Sgshapiro while (!sm_io_eof(fp) && !sm_io_error(fp)) 130738032Speter { 130890792Sgshapiro errno = 0; 1309249729Sgshapiro l = sm_io_fgets(fp, io_timeout, buf, siz); 1310249729Sgshapiro if (l < 0 && errno == EAGAIN) 131138032Speter { 131290792Sgshapiro /* The sm_io_fgets() call timedout */ 131338032Speter if (LogLevel > 1) 131438032Speter sm_syslog(LOG_NOTICE, CurEnv->e_id, 131564562Sgshapiro "timeout waiting for input from %.100s during %s", 131690792Sgshapiro CURHOSTNAME, 131764562Sgshapiro during); 131838032Speter buf[0] = '\0'; 131938032Speter#if XDEBUG 132038032Speter checkfd012(during); 1321363466Sgshapiro#endif 132238032Speter if (TrafficLogFile != NULL) 132390792Sgshapiro (void) sm_io_fprintf(TrafficLogFile, 132490792Sgshapiro SM_TIME_DEFAULT, 132590792Sgshapiro "%05d <<< [TIMEOUT]\n", 132690792Sgshapiro (int) CurrentPid); 132790792Sgshapiro errno = ETIMEDOUT; 132864562Sgshapiro return NULL; 132938032Speter } 1330249729Sgshapiro if (l >= 0 || errno != EINTR) 133138032Speter break; 133290792Sgshapiro (void) sm_io_clearerr(fp); 133338032Speter } 133443730Speter save_errno = errno; 133538032Speter 133638032Speter /* clean up the books and exit */ 133738032Speter LineNumber++; 1338249729Sgshapiro if (l < 0) 133938032Speter { 134038032Speter buf[0] = '\0'; 134138032Speter if (TrafficLogFile != NULL) 134290792Sgshapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 134390792Sgshapiro "%05d <<< [EOF]\n", 134490792Sgshapiro (int) CurrentPid); 134543730Speter errno = save_errno; 134664562Sgshapiro return NULL; 134738032Speter } 134838032Speter if (TrafficLogFile != NULL) 134990792Sgshapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 135090792Sgshapiro "%05d <<< %s", (int) CurrentPid, buf); 135138032Speter if (SevenBitInput) 135238032Speter { 135338032Speter for (p = buf; *p != '\0'; p++) 135438032Speter *p &= ~0200; 135538032Speter } 135638032Speter else if (!HasEightBits) 135738032Speter { 135838032Speter for (p = buf; *p != '\0'; p++) 135938032Speter { 136038032Speter if (bitset(0200, *p)) 136138032Speter { 136290792Sgshapiro HasEightBits = true; 136338032Speter break; 136438032Speter } 136538032Speter } 136638032Speter } 136764562Sgshapiro return buf; 136838032Speter} 1369168515Sgshapiro 137090792Sgshapiro/* 137190792Sgshapiro** FGETFOLDED -- like fgets, but knows about folded lines. 137238032Speter** 137338032Speter** Parameters: 137438032Speter** buf -- place to put result. 1375168515Sgshapiro** np -- pointer to bytes available; will be updated with 1376168515Sgshapiro** the actual buffer size (not number of bytes filled) 1377168515Sgshapiro** on return. 137838032Speter** f -- file to read from. 137938032Speter** 138038032Speter** Returns: 138190792Sgshapiro** input line(s) on success, NULL on error or SM_IO_EOF. 138238032Speter** This will normally be buf -- unless the line is too 138390792Sgshapiro** long, when it will be sm_malloc_x()ed. 138438032Speter** 138538032Speter** Side Effects: 138638032Speter** buf gets lines from f, with continuation lines (lines 138738032Speter** with leading white space) appended. CRLF's are mapped 138838032Speter** into single newlines. Any trailing NL is stripped. 1389363466Sgshapiro** Increases LineNumber for each line. 139038032Speter*/ 139138032Speter 139238032Speterchar * 1393168515Sgshapirofgetfolded(buf, np, f) 139438032Speter char *buf; 1395168515Sgshapiro int *np; 139690792Sgshapiro SM_FILE_T *f; 139738032Speter{ 139838032Speter register char *p = buf; 139938032Speter char *bp = buf; 140038032Speter register int i; 1401168515Sgshapiro int n; 140238032Speter 1403168515Sgshapiro SM_REQUIRE(np != NULL); 1404168515Sgshapiro n = *np; 140590792Sgshapiro SM_REQUIRE(n > 0); 140690792Sgshapiro SM_REQUIRE(buf != NULL); 140790792Sgshapiro if (f == NULL) 140890792Sgshapiro { 140990792Sgshapiro buf[0] = '\0'; 141090792Sgshapiro errno = EBADF; 141190792Sgshapiro return NULL; 141290792Sgshapiro } 141390792Sgshapiro 141438032Speter n--; 141590792Sgshapiro while ((i = sm_io_getc(f, SM_TIME_DEFAULT)) != SM_IO_EOF) 141638032Speter { 141738032Speter if (i == '\r') 141838032Speter { 141990792Sgshapiro i = sm_io_getc(f, SM_TIME_DEFAULT); 142038032Speter if (i != '\n') 142138032Speter { 142290792Sgshapiro if (i != SM_IO_EOF) 142390792Sgshapiro (void) sm_io_ungetc(f, SM_TIME_DEFAULT, 142490792Sgshapiro i); 142538032Speter i = '\r'; 142638032Speter } 142738032Speter } 142838032Speter if (--n <= 0) 142938032Speter { 143038032Speter /* allocate new space */ 143138032Speter char *nbp; 143238032Speter int nn; 143338032Speter 143438032Speter nn = (p - bp); 143538032Speter if (nn < MEMCHUNKSIZE) 143638032Speter nn *= 2; 143738032Speter else 143838032Speter nn += MEMCHUNKSIZE; 143990792Sgshapiro nbp = sm_malloc_x(nn); 144064562Sgshapiro memmove(nbp, bp, p - bp); 144138032Speter p = &nbp[p - bp]; 144238032Speter if (bp != buf) 144377349Sgshapiro sm_free(bp); 144438032Speter bp = nbp; 144538032Speter n = nn - (p - bp); 1446168515Sgshapiro *np = nn; 144738032Speter } 144838032Speter *p++ = i; 144938032Speter if (i == '\n') 145038032Speter { 145138032Speter LineNumber++; 145290792Sgshapiro i = sm_io_getc(f, SM_TIME_DEFAULT); 145390792Sgshapiro if (i != SM_IO_EOF) 145490792Sgshapiro (void) sm_io_ungetc(f, SM_TIME_DEFAULT, i); 145538032Speter if (i != ' ' && i != '\t') 145638032Speter break; 145738032Speter } 145838032Speter } 145938032Speter if (p == bp) 146064562Sgshapiro return NULL; 146138032Speter if (p[-1] == '\n') 146238032Speter p--; 146338032Speter *p = '\0'; 146464562Sgshapiro return bp; 146538032Speter} 1466168515Sgshapiro 146790792Sgshapiro/* 146838032Speter** CURTIME -- return current time. 146938032Speter** 147038032Speter** Parameters: 147138032Speter** none. 147238032Speter** 147338032Speter** Returns: 147438032Speter** the current time. 147538032Speter*/ 147638032Speter 147738032Spetertime_t 147838032Spetercurtime() 147938032Speter{ 148038032Speter auto time_t t; 148138032Speter 148238032Speter (void) time(&t); 148364562Sgshapiro return t; 148438032Speter} 1485168515Sgshapiro 148690792Sgshapiro/* 148738032Speter** ATOBOOL -- convert a string representation to boolean. 148838032Speter** 148990792Sgshapiro** Defaults to false 149038032Speter** 149138032Speter** Parameters: 149290792Sgshapiro** s -- string to convert. Takes "tTyY", empty, and NULL as true, 149338032Speter** others as false. 149438032Speter** 149538032Speter** Returns: 149638032Speter** A boolean representation of the string. 149738032Speter*/ 149838032Speter 149938032Speterbool 150038032Speteratobool(s) 150138032Speter register char *s; 150238032Speter{ 150338032Speter if (s == NULL || *s == '\0' || strchr("tTyY", *s) != NULL) 150490792Sgshapiro return true; 150590792Sgshapiro return false; 150638032Speter} 1507168515Sgshapiro 150890792Sgshapiro/* 150938032Speter** ATOOCT -- convert a string representation to octal. 151038032Speter** 151138032Speter** Parameters: 151238032Speter** s -- string to convert. 151338032Speter** 151438032Speter** Returns: 151538032Speter** An integer representing the string interpreted as an 151638032Speter** octal number. 151738032Speter*/ 151838032Speter 151938032Speterint 152038032Speteratooct(s) 152138032Speter register char *s; 152238032Speter{ 152338032Speter register int i = 0; 152438032Speter 152538032Speter while (*s >= '0' && *s <= '7') 152638032Speter i = (i << 3) | (*s++ - '0'); 152764562Sgshapiro return i; 152838032Speter} 1529168515Sgshapiro 153090792Sgshapiro/* 153138032Speter** BITINTERSECT -- tell if two bitmaps intersect 153238032Speter** 153338032Speter** Parameters: 153438032Speter** a, b -- the bitmaps in question 153538032Speter** 153638032Speter** Returns: 153790792Sgshapiro** true if they have a non-null intersection 153890792Sgshapiro** false otherwise 153938032Speter*/ 154038032Speter 154138032Speterbool 154238032Speterbitintersect(a, b) 154364562Sgshapiro BITMAP256 a; 154464562Sgshapiro BITMAP256 b; 154538032Speter{ 154638032Speter int i; 154738032Speter 1548168515Sgshapiro for (i = BITMAPBYTES / sizeof(int); --i >= 0; ) 154971345Sgshapiro { 155038032Speter if ((a[i] & b[i]) != 0) 155190792Sgshapiro return true; 155271345Sgshapiro } 155390792Sgshapiro return false; 155438032Speter} 1555168515Sgshapiro 155690792Sgshapiro/* 155738032Speter** BITZEROP -- tell if a bitmap is all zero 155838032Speter** 155938032Speter** Parameters: 156038032Speter** map -- the bit map to check 156138032Speter** 156238032Speter** Returns: 156390792Sgshapiro** true if map is all zero. 156490792Sgshapiro** false if there are any bits set in map. 156538032Speter*/ 156638032Speter 156738032Speterbool 156838032Speterbitzerop(map) 156964562Sgshapiro BITMAP256 map; 157038032Speter{ 157138032Speter int i; 157238032Speter 1573168515Sgshapiro for (i = BITMAPBYTES / sizeof(int); --i >= 0; ) 157471345Sgshapiro { 157538032Speter if (map[i] != 0) 157690792Sgshapiro return false; 157771345Sgshapiro } 157890792Sgshapiro return true; 157938032Speter} 1580168515Sgshapiro 158190792Sgshapiro/* 158238032Speter** STRCONTAINEDIN -- tell if one string is contained in another 158338032Speter** 158438032Speter** Parameters: 158590792Sgshapiro** icase -- ignore case? 158638032Speter** a -- possible substring. 158738032Speter** b -- possible superstring. 158838032Speter** 158938032Speter** Returns: 159090792Sgshapiro** true if a is contained in b (case insensitive). 159190792Sgshapiro** false otherwise. 159238032Speter*/ 159338032Speter 159438032Speterbool 159590792Sgshapirostrcontainedin(icase, a, b) 159690792Sgshapiro bool icase; 159738032Speter register char *a; 159838032Speter register char *b; 159938032Speter{ 160038032Speter int la; 160138032Speter int lb; 160238032Speter int c; 160338032Speter 160438032Speter la = strlen(a); 160538032Speter lb = strlen(b); 160638032Speter c = *a; 160790792Sgshapiro if (icase && isascii(c) && isupper(c)) 160838032Speter c = tolower(c); 160938032Speter for (; lb-- >= la; b++) 161038032Speter { 161190792Sgshapiro if (icase) 161290792Sgshapiro { 161390792Sgshapiro if (*b != c && 161490792Sgshapiro isascii(*b) && isupper(*b) && tolower(*b) != c) 161590792Sgshapiro continue; 161690792Sgshapiro if (sm_strncasecmp(a, b, la) == 0) 161790792Sgshapiro return true; 161890792Sgshapiro } 161990792Sgshapiro else 162090792Sgshapiro { 162190792Sgshapiro if (*b != c) 162290792Sgshapiro continue; 162390792Sgshapiro if (strncmp(a, b, la) == 0) 162490792Sgshapiro return true; 162590792Sgshapiro } 162638032Speter } 162790792Sgshapiro return false; 162838032Speter} 1629168515Sgshapiro 163090792Sgshapiro/* 163138032Speter** CHECKFD012 -- check low numbered file descriptors 163238032Speter** 163338032Speter** File descriptors 0, 1, and 2 should be open at all times. 163438032Speter** This routine verifies that, and fixes it if not true. 163538032Speter** 163638032Speter** Parameters: 163738032Speter** where -- a tag printed if the assertion failed 163838032Speter** 163938032Speter** Returns: 164038032Speter** none 164138032Speter*/ 164238032Speter 164338032Spetervoid 164438032Spetercheckfd012(where) 164538032Speter char *where; 164638032Speter{ 164738032Speter#if XDEBUG 164838032Speter register int i; 164938032Speter 165038032Speter for (i = 0; i < 3; i++) 165138032Speter fill_fd(i, where); 165238032Speter#endif /* XDEBUG */ 165338032Speter} 1654168515Sgshapiro 165590792Sgshapiro/* 165638032Speter** CHECKFDOPEN -- make sure file descriptor is open -- for extended debugging 165738032Speter** 165838032Speter** Parameters: 165938032Speter** fd -- file descriptor to check. 166038032Speter** where -- tag to print on failure. 166138032Speter** 166238032Speter** Returns: 166338032Speter** none. 166438032Speter*/ 166538032Speter 166638032Spetervoid 166738032Spetercheckfdopen(fd, where) 166838032Speter int fd; 166938032Speter char *where; 167038032Speter{ 167138032Speter#if XDEBUG 167238032Speter struct stat st; 167338032Speter 167438032Speter if (fstat(fd, &st) < 0 && errno == EBADF) 167538032Speter { 167638032Speter syserr("checkfdopen(%d): %s not open as expected!", fd, where); 167790792Sgshapiro printopenfds(true); 167838032Speter } 167964562Sgshapiro#endif /* XDEBUG */ 168038032Speter} 1681168515Sgshapiro 168290792Sgshapiro/* 168338032Speter** CHECKFDS -- check for new or missing file descriptors 168438032Speter** 168538032Speter** Parameters: 168638032Speter** where -- tag for printing. If null, take a base line. 168738032Speter** 168838032Speter** Returns: 168938032Speter** none 169038032Speter** 169138032Speter** Side Effects: 169238032Speter** If where is set, shows changes since the last call. 169338032Speter*/ 169438032Speter 169538032Spetervoid 169638032Spetercheckfds(where) 169738032Speter char *where; 169838032Speter{ 169938032Speter int maxfd; 170038032Speter register int fd; 170190792Sgshapiro bool printhdr = true; 170238032Speter int save_errno = errno; 170364562Sgshapiro static BITMAP256 baseline; 170438032Speter extern int DtableSize; 170538032Speter 170671345Sgshapiro if (DtableSize > BITMAPBITS) 170771345Sgshapiro maxfd = BITMAPBITS; 170838032Speter else 170938032Speter maxfd = DtableSize; 171038032Speter if (where == NULL) 171138032Speter clrbitmap(baseline); 171238032Speter 171338032Speter for (fd = 0; fd < maxfd; fd++) 171438032Speter { 171538032Speter struct stat stbuf; 171638032Speter 171738032Speter if (fstat(fd, &stbuf) < 0 && errno != EOPNOTSUPP) 171838032Speter { 171938032Speter if (!bitnset(fd, baseline)) 172038032Speter continue; 172138032Speter clrbitn(fd, baseline); 172238032Speter } 172338032Speter else if (!bitnset(fd, baseline)) 172438032Speter setbitn(fd, baseline); 172538032Speter else 172638032Speter continue; 172738032Speter 172838032Speter /* file state has changed */ 172938032Speter if (where == NULL) 173038032Speter continue; 173138032Speter if (printhdr) 173238032Speter { 173338032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 173464562Sgshapiro "%s: changed fds:", 173564562Sgshapiro where); 173690792Sgshapiro printhdr = false; 173738032Speter } 173890792Sgshapiro dumpfd(fd, true, true); 173938032Speter } 174038032Speter errno = save_errno; 174138032Speter} 1742168515Sgshapiro 174390792Sgshapiro/* 174438032Speter** PRINTOPENFDS -- print the open file descriptors (for debugging) 174538032Speter** 174638032Speter** Parameters: 174738032Speter** logit -- if set, send output to syslog; otherwise 174838032Speter** print for debugging. 174938032Speter** 175038032Speter** Returns: 175138032Speter** none. 175238032Speter*/ 175338032Speter 175464562Sgshapiro#if NETINET || NETINET6 175564562Sgshapiro# include <arpa/inet.h> 1756363466Sgshapiro#endif 175738032Speter 175838032Spetervoid 175938032Speterprintopenfds(logit) 176038032Speter bool logit; 176138032Speter{ 176238032Speter register int fd; 176338032Speter extern int DtableSize; 176438032Speter 176538032Speter for (fd = 0; fd < DtableSize; fd++) 176690792Sgshapiro dumpfd(fd, false, logit); 176738032Speter} 1768168515Sgshapiro 176990792Sgshapiro/* 177038032Speter** DUMPFD -- dump a file descriptor 177138032Speter** 177238032Speter** Parameters: 177338032Speter** fd -- the file descriptor to dump. 177438032Speter** printclosed -- if set, print a notification even if 177538032Speter** it is closed; otherwise print nothing. 1776132943Sgshapiro** logit -- if set, use sm_syslog instead of sm_dprintf() 177790792Sgshapiro** 177890792Sgshapiro** Returns: 177990792Sgshapiro** none. 178038032Speter*/ 178138032Speter 178238032Spetervoid 178338032Speterdumpfd(fd, printclosed, logit) 178438032Speter int fd; 178538032Speter bool printclosed; 178638032Speter bool logit; 178738032Speter{ 178838032Speter register char *p; 178938032Speter char *hp; 179038032Speter#ifdef S_IFSOCK 179138032Speter SOCKADDR sa; 1792363466Sgshapiro#endif 179338032Speter auto SOCKADDR_LEN_T slen; 179438032Speter int i; 179538032Speter#if STAT64 > 0 179638032Speter struct stat64 st; 1797363466Sgshapiro#else 179838032Speter struct stat st; 1799363466Sgshapiro#endif 180038032Speter char buf[200]; 180138032Speter 180238032Speter p = buf; 180390792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "%3d: ", fd); 180438032Speter p += strlen(p); 180538032Speter 180638032Speter if ( 180738032Speter#if STAT64 > 0 180838032Speter fstat64(fd, &st) 1809363466Sgshapiro#else 181038032Speter fstat(fd, &st) 1811363466Sgshapiro#endif 181238032Speter < 0) 181338032Speter { 181438032Speter if (errno != EBADF) 181538032Speter { 181690792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 181790792Sgshapiro "CANNOT STAT (%s)", 181890792Sgshapiro sm_errstring(errno)); 181938032Speter goto printit; 182038032Speter } 182138032Speter else if (printclosed) 182238032Speter { 182390792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "CLOSED"); 182438032Speter goto printit; 182538032Speter } 182638032Speter return; 182738032Speter } 182838032Speter 182994334Sgshapiro i = fcntl(fd, F_GETFL, 0); 183038032Speter if (i != -1) 183138032Speter { 183290792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "fl=0x%x, ", i); 183338032Speter p += strlen(p); 183438032Speter } 183538032Speter 183690792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "mode=%o: ", 1837285229Sgshapiro (unsigned int) st.st_mode); 183838032Speter p += strlen(p); 183938032Speter switch (st.st_mode & S_IFMT) 184038032Speter { 184138032Speter#ifdef S_IFSOCK 184238032Speter case S_IFSOCK: 184390792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "SOCK "); 184438032Speter p += strlen(p); 1845168515Sgshapiro memset(&sa, '\0', sizeof(sa)); 1846168515Sgshapiro slen = sizeof(sa); 184738032Speter if (getsockname(fd, &sa.sa, &slen) < 0) 184890792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)", 184990792Sgshapiro sm_errstring(errno)); 185038032Speter else 185138032Speter { 185238032Speter hp = hostnamebyanyaddr(&sa); 185364562Sgshapiro if (hp == NULL) 185464562Sgshapiro { 185564562Sgshapiro /* EMPTY */ 185664562Sgshapiro /* do nothing */ 185764562Sgshapiro } 185864562Sgshapiro# if NETINET 185964562Sgshapiro else if (sa.sa.sa_family == AF_INET) 186090792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 186190792Sgshapiro "%s/%d", hp, ntohs(sa.sin.sin_port)); 1862363466Sgshapiro# endif 186364562Sgshapiro# if NETINET6 186464562Sgshapiro else if (sa.sa.sa_family == AF_INET6) 186590792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 186690792Sgshapiro "%s/%d", hp, ntohs(sa.sin6.sin6_port)); 1867363466Sgshapiro# endif 186838032Speter else 186990792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 187090792Sgshapiro "%s", hp); 187138032Speter } 187238032Speter p += strlen(p); 187390792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "->"); 187438032Speter p += strlen(p); 1875168515Sgshapiro slen = sizeof(sa); 187638032Speter if (getpeername(fd, &sa.sa, &slen) < 0) 187790792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "(%s)", 187890792Sgshapiro sm_errstring(errno)); 187938032Speter else 188038032Speter { 188138032Speter hp = hostnamebyanyaddr(&sa); 188264562Sgshapiro if (hp == NULL) 188364562Sgshapiro { 188464562Sgshapiro /* EMPTY */ 188564562Sgshapiro /* do nothing */ 188664562Sgshapiro } 188764562Sgshapiro# if NETINET 188864562Sgshapiro else if (sa.sa.sa_family == AF_INET) 188990792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 189090792Sgshapiro "%s/%d", hp, ntohs(sa.sin.sin_port)); 1891363466Sgshapiro# endif 189264562Sgshapiro# if NETINET6 189364562Sgshapiro else if (sa.sa.sa_family == AF_INET6) 189490792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 189590792Sgshapiro "%s/%d", hp, ntohs(sa.sin6.sin6_port)); 1896363466Sgshapiro# endif 189738032Speter else 189890792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 189990792Sgshapiro "%s", hp); 190038032Speter } 190138032Speter break; 190264562Sgshapiro#endif /* S_IFSOCK */ 190338032Speter 190438032Speter case S_IFCHR: 190590792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "CHR: "); 190638032Speter p += strlen(p); 190738032Speter goto defprint; 190838032Speter 190990792Sgshapiro#ifdef S_IFBLK 191038032Speter case S_IFBLK: 191190792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "BLK: "); 191238032Speter p += strlen(p); 191338032Speter goto defprint; 1914363466Sgshapiro#endif 191538032Speter 191638032Speter#if defined(S_IFIFO) && (!defined(S_IFSOCK) || S_IFIFO != S_IFSOCK) 191738032Speter case S_IFIFO: 191890792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "FIFO: "); 191938032Speter p += strlen(p); 192038032Speter goto defprint; 1921363466Sgshapiro#endif 192238032Speter 192338032Speter#ifdef S_IFDIR 192438032Speter case S_IFDIR: 192590792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "DIR: "); 192638032Speter p += strlen(p); 192738032Speter goto defprint; 1928363466Sgshapiro#endif 192938032Speter 193038032Speter#ifdef S_IFLNK 193138032Speter case S_IFLNK: 193290792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "LNK: "); 193338032Speter p += strlen(p); 193438032Speter goto defprint; 1935363466Sgshapiro#endif 193638032Speter 193738032Speter default: 193838032Speterdefprint: 193990792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), 1940285229Sgshapiro "dev=%ld/%ld, ino=%llu, nlink=%d, u/gid=%ld/%ld, ", 1941285229Sgshapiro (long) major(st.st_dev), (long) minor(st.st_dev), 194290792Sgshapiro (ULONGLONG_T) st.st_ino, 1943285229Sgshapiro (int) st.st_nlink, (long) st.st_uid, 1944285229Sgshapiro (long) st.st_gid); 194590792Sgshapiro p += strlen(p); 194690792Sgshapiro (void) sm_snprintf(p, SPACELEFT(buf, p), "size=%llu", 194790792Sgshapiro (ULONGLONG_T) st.st_size); 194838032Speter break; 194938032Speter } 195038032Speter 195138032Speterprintit: 195238032Speter if (logit) 195338032Speter sm_syslog(LOG_DEBUG, CurEnv ? CurEnv->e_id : NULL, 195464562Sgshapiro "%.800s", buf); 195538032Speter else 1956132943Sgshapiro sm_dprintf("%s\n", buf); 195738032Speter} 1958168515Sgshapiro 195990792Sgshapiro/* 196038032Speter** SHORTEN_HOSTNAME -- strip local domain information off of hostname. 196138032Speter** 196238032Speter** Parameters: 196338032Speter** host -- the host to shorten (stripped in place). 196438032Speter** 196538032Speter** Returns: 196690792Sgshapiro** place where string was truncated, NULL if not truncated. 196738032Speter*/ 196838032Speter 196973188Sgshapirochar * 197038032Spetershorten_hostname(host) 197138032Speter char host[]; 197238032Speter{ 197338032Speter register char *p; 197438032Speter char *mydom; 197538032Speter int i; 197690792Sgshapiro bool canon = false; 197738032Speter 197838032Speter /* strip off final dot */ 197990792Sgshapiro i = strlen(host); 198090792Sgshapiro p = &host[(i == 0) ? 0 : i - 1]; 198138032Speter if (*p == '.') 198238032Speter { 198338032Speter *p = '\0'; 198490792Sgshapiro canon = true; 198538032Speter } 198638032Speter 198738032Speter /* see if there is any domain at all -- if not, we are done */ 198838032Speter p = strchr(host, '.'); 198938032Speter if (p == NULL) 199073188Sgshapiro return NULL; 199138032Speter 199238032Speter /* yes, we have a domain -- see if it looks like us */ 199338032Speter mydom = macvalue('m', CurEnv); 199438032Speter if (mydom == NULL) 199538032Speter mydom = ""; 199638032Speter i = strlen(++p); 199790792Sgshapiro if ((canon ? sm_strcasecmp(p, mydom) 199890792Sgshapiro : sm_strncasecmp(p, mydom, i)) == 0 && 199990792Sgshapiro (mydom[i] == '.' || mydom[i] == '\0')) 200073188Sgshapiro { 200138032Speter *--p = '\0'; 200273188Sgshapiro return p; 200373188Sgshapiro } 200473188Sgshapiro return NULL; 200538032Speter} 2006168515Sgshapiro 200790792Sgshapiro/* 200838032Speter** PROG_OPEN -- open a program for reading 200938032Speter** 201038032Speter** Parameters: 201138032Speter** argv -- the argument list. 201238032Speter** pfd -- pointer to a place to store the file descriptor. 201338032Speter** e -- the current envelope. 201438032Speter** 201538032Speter** Returns: 201638032Speter** pid of the process -- -1 if it failed. 201738032Speter*/ 201838032Speter 201977349Sgshapiropid_t 202038032Speterprog_open(argv, pfd, e) 202138032Speter char **argv; 202238032Speter int *pfd; 202338032Speter ENVELOPE *e; 202438032Speter{ 202577349Sgshapiro pid_t pid; 202664562Sgshapiro int save_errno; 202790792Sgshapiro int sff; 202890792Sgshapiro int ret; 202938032Speter int fdv[2]; 203038032Speter char *p, *q; 203198121Sgshapiro char buf[MAXPATHLEN]; 203238032Speter extern int DtableSize; 203338032Speter 203438032Speter if (pipe(fdv) < 0) 203538032Speter { 203638032Speter syserr("%s: cannot create pipe for stdout", argv[0]); 203738032Speter return -1; 203838032Speter } 203938032Speter pid = fork(); 204038032Speter if (pid < 0) 204138032Speter { 204238032Speter syserr("%s: cannot fork", argv[0]); 204364562Sgshapiro (void) close(fdv[0]); 204464562Sgshapiro (void) close(fdv[1]); 204538032Speter return -1; 204638032Speter } 204738032Speter if (pid > 0) 204838032Speter { 204938032Speter /* parent */ 205064562Sgshapiro (void) close(fdv[1]); 205138032Speter *pfd = fdv[0]; 205238032Speter return pid; 205338032Speter } 205438032Speter 205577349Sgshapiro /* Reset global flags */ 205677349Sgshapiro RestartRequest = NULL; 205790792Sgshapiro RestartWorkGroup = false; 205877349Sgshapiro ShutdownRequest = NULL; 205977349Sgshapiro PendingSignal = 0; 206090792Sgshapiro CurrentPid = getpid(); 206177349Sgshapiro 206290792Sgshapiro /* 206390792Sgshapiro ** Initialize exception stack and default exception 206490792Sgshapiro ** handler for child process. 206590792Sgshapiro */ 206690792Sgshapiro 206790792Sgshapiro sm_exc_newthread(fatal_error); 206890792Sgshapiro 206990792Sgshapiro /* child -- close stdin */ 207090792Sgshapiro (void) close(0); 207190792Sgshapiro 207238032Speter /* stdout goes back to parent */ 207364562Sgshapiro (void) close(fdv[0]); 207438032Speter if (dup2(fdv[1], 1) < 0) 207538032Speter { 207638032Speter syserr("%s: cannot dup2 for stdout", argv[0]); 207738032Speter _exit(EX_OSERR); 207838032Speter } 207964562Sgshapiro (void) close(fdv[1]); 208038032Speter 208138032Speter /* stderr goes to transcript if available */ 208238032Speter if (e->e_xfp != NULL) 208338032Speter { 208464562Sgshapiro int xfd; 208564562Sgshapiro 208690792Sgshapiro xfd = sm_io_getinfo(e->e_xfp, SM_IO_WHAT_FD, NULL); 208764562Sgshapiro if (xfd >= 0 && dup2(xfd, 2) < 0) 208838032Speter { 208938032Speter syserr("%s: cannot dup2 for stderr", argv[0]); 209038032Speter _exit(EX_OSERR); 209138032Speter } 209238032Speter } 209338032Speter 209438032Speter /* this process has no right to the queue file */ 209538032Speter if (e->e_lockfp != NULL) 2096159609Sgshapiro { 2097159609Sgshapiro int fd; 209838032Speter 2099159609Sgshapiro fd = sm_io_getinfo(e->e_lockfp, SM_IO_WHAT_FD, NULL); 2100159609Sgshapiro if (fd >= 0) 2101159609Sgshapiro (void) close(fd); 2102159609Sgshapiro else 2103159609Sgshapiro syserr("%s: lockfp does not have a fd", argv[0]); 2104159609Sgshapiro } 2105159609Sgshapiro 210664562Sgshapiro /* chroot to the program mailer directory, if defined */ 210764562Sgshapiro if (ProgMailer != NULL && ProgMailer->m_rootdir != NULL) 210864562Sgshapiro { 2109168515Sgshapiro expand(ProgMailer->m_rootdir, buf, sizeof(buf), e); 211064562Sgshapiro if (chroot(buf) < 0) 211164562Sgshapiro { 211264562Sgshapiro syserr("prog_open: cannot chroot(%s)", buf); 211364562Sgshapiro exit(EX_TEMPFAIL); 211464562Sgshapiro } 211564562Sgshapiro if (chdir("/") < 0) 211664562Sgshapiro { 211764562Sgshapiro syserr("prog_open: cannot chdir(/)"); 211864562Sgshapiro exit(EX_TEMPFAIL); 211964562Sgshapiro } 212064562Sgshapiro } 212164562Sgshapiro 212238032Speter /* run as default user */ 212338032Speter endpwent(); 212490792Sgshapiro sm_mbdb_terminate(); 2125157001Sgshapiro#if _FFR_MEMSTAT 2126157001Sgshapiro (void) sm_memstat_close(); 2127363466Sgshapiro#endif 212838032Speter if (setgid(DefGid) < 0 && geteuid() == 0) 212964562Sgshapiro { 213038032Speter syserr("prog_open: setgid(%ld) failed", (long) DefGid); 213164562Sgshapiro exit(EX_TEMPFAIL); 213264562Sgshapiro } 213338032Speter if (setuid(DefUid) < 0 && geteuid() == 0) 213464562Sgshapiro { 213538032Speter syserr("prog_open: setuid(%ld) failed", (long) DefUid); 213664562Sgshapiro exit(EX_TEMPFAIL); 213764562Sgshapiro } 213838032Speter 213938032Speter /* run in some directory */ 214038032Speter if (ProgMailer != NULL) 214138032Speter p = ProgMailer->m_execdir; 214238032Speter else 214338032Speter p = NULL; 214438032Speter for (; p != NULL; p = q) 214538032Speter { 214638032Speter q = strchr(p, ':'); 214738032Speter if (q != NULL) 214838032Speter *q = '\0'; 2149168515Sgshapiro expand(p, buf, sizeof(buf), e); 215038032Speter if (q != NULL) 215138032Speter *q++ = ':'; 215238032Speter if (buf[0] != '\0' && chdir(buf) >= 0) 215338032Speter break; 215438032Speter } 215538032Speter if (p == NULL) 215638032Speter { 215738032Speter /* backup directories */ 215838032Speter if (chdir("/tmp") < 0) 215938032Speter (void) chdir("/"); 216038032Speter } 216138032Speter 216290792Sgshapiro /* Check safety of program to be run */ 216390792Sgshapiro sff = SFF_ROOTOK|SFF_EXECOK; 216490792Sgshapiro if (!bitnset(DBS_RUNWRITABLEPROGRAM, DontBlameSendmail)) 216590792Sgshapiro sff |= SFF_NOGWFILES|SFF_NOWWFILES; 216690792Sgshapiro if (bitnset(DBS_RUNPROGRAMINUNSAFEDIRPATH, DontBlameSendmail)) 216790792Sgshapiro sff |= SFF_NOPATHCHECK; 216890792Sgshapiro else 216990792Sgshapiro sff |= SFF_SAFEDIRPATH; 217090792Sgshapiro ret = safefile(argv[0], DefUid, DefGid, DefUser, sff, 0, NULL); 217190792Sgshapiro if (ret != 0) 217290792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 217390792Sgshapiro "Warning: prog_open: program %s unsafe: %s", 217490792Sgshapiro argv[0], sm_errstring(ret)); 217590792Sgshapiro 217638032Speter /* arrange for all the files to be closed */ 2177132943Sgshapiro sm_close_on_exec(STDERR_FILENO + 1, DtableSize); 217838032Speter 217938032Speter /* now exec the process */ 218064562Sgshapiro (void) execve(argv[0], (ARGV_T) argv, (ARGV_T) UserEnviron); 218138032Speter 218238032Speter /* woops! failed */ 218364562Sgshapiro save_errno = errno; 218438032Speter syserr("%s: cannot exec", argv[0]); 218564562Sgshapiro if (transienterror(save_errno)) 218638032Speter _exit(EX_OSERR); 218738032Speter _exit(EX_CONFIG); 218838032Speter return -1; /* avoid compiler warning on IRIX */ 218938032Speter} 2190168515Sgshapiro 219190792Sgshapiro/* 219264562Sgshapiro** GET_COLUMN -- look up a Column in a line buffer 219338032Speter** 219438032Speter** Parameters: 219538032Speter** line -- the raw text line to search. 219638032Speter** col -- the column number to fetch. 219738032Speter** delim -- the delimiter between columns. If null, 219838032Speter** use white space. 219938032Speter** buf -- the output buffer. 220038032Speter** buflen -- the length of buf. 220138032Speter** 220238032Speter** Returns: 220338032Speter** buf if successful. 220438032Speter** NULL otherwise. 220538032Speter*/ 220638032Speter 220738032Speterchar * 220838032Speterget_column(line, col, delim, buf, buflen) 220938032Speter char line[]; 221038032Speter int col; 221164562Sgshapiro int delim; 221238032Speter char buf[]; 221338032Speter int buflen; 221438032Speter{ 221538032Speter char *p; 221638032Speter char *begin, *end; 221738032Speter int i; 221838032Speter char delimbuf[4]; 221964562Sgshapiro 222090792Sgshapiro if ((char) delim == '\0') 2221168515Sgshapiro (void) sm_strlcpy(delimbuf, "\n\t ", sizeof(delimbuf)); 222238032Speter else 222338032Speter { 222490792Sgshapiro delimbuf[0] = (char) delim; 222538032Speter delimbuf[1] = '\0'; 222638032Speter } 222738032Speter 222838032Speter p = line; 222938032Speter if (*p == '\0') 223038032Speter return NULL; /* line empty */ 223190792Sgshapiro if (*p == (char) delim && col == 0) 223238032Speter return NULL; /* first column empty */ 223338032Speter 223438032Speter begin = line; 223538032Speter 223690792Sgshapiro if (col == 0 && (char) delim == '\0') 223738032Speter { 2238363466Sgshapiro while (*begin != '\0' && SM_ISSPACE(*begin)) 223938032Speter begin++; 224038032Speter } 224138032Speter 224238032Speter for (i = 0; i < col; i++) 224338032Speter { 224438032Speter if ((begin = strpbrk(begin, delimbuf)) == NULL) 224538032Speter return NULL; /* no such column */ 224638032Speter begin++; 224790792Sgshapiro if ((char) delim == '\0') 224838032Speter { 2249363466Sgshapiro while (*begin != '\0' && SM_ISSPACE(*begin)) 225038032Speter begin++; 225138032Speter } 225238032Speter } 225364562Sgshapiro 225438032Speter end = strpbrk(begin, delimbuf); 225538032Speter if (end == NULL) 225638032Speter i = strlen(begin); 225738032Speter else 225838032Speter i = end - begin; 225938032Speter if (i >= buflen) 226038032Speter i = buflen - 1; 226190792Sgshapiro (void) sm_strlcpy(buf, begin, i + 1); 226238032Speter return buf; 226338032Speter} 2264168515Sgshapiro 226590792Sgshapiro/* 226638032Speter** CLEANSTRCPY -- copy string keeping out bogus characters 226738032Speter** 226838032Speter** Parameters: 226938032Speter** t -- "to" string. 227038032Speter** f -- "from" string. 227138032Speter** l -- length of space available in "to" string. 227238032Speter** 227338032Speter** Returns: 227438032Speter** none. 227538032Speter*/ 227638032Speter 227738032Spetervoid 227838032Spetercleanstrcpy(t, f, l) 227938032Speter register char *t; 228038032Speter register char *f; 228138032Speter int l; 228238032Speter{ 228338032Speter /* check for newlines and log if necessary */ 228490792Sgshapiro (void) denlstring(f, true, true); 228538032Speter 228664562Sgshapiro if (l <= 0) 228764562Sgshapiro syserr("!cleanstrcpy: length == 0"); 228864562Sgshapiro 228938032Speter l--; 229038032Speter while (l > 0 && *f != '\0') 229138032Speter { 229238032Speter if (isascii(*f) && 229338032Speter (isalnum(*f) || strchr("!#$%&'*+-./^_`{|}~", *f) != NULL)) 229438032Speter { 229538032Speter l--; 229638032Speter *t++ = *f; 229738032Speter } 229838032Speter f++; 229938032Speter } 230038032Speter *t = '\0'; 230138032Speter} 2302168515Sgshapiro 230390792Sgshapiro/* 230438032Speter** DENLSTRING -- convert newlines in a string to spaces 230538032Speter** 230638032Speter** Parameters: 230738032Speter** s -- the input string 230838032Speter** strict -- if set, don't permit continuation lines. 230938032Speter** logattacks -- if set, log attempted attacks. 231038032Speter** 231138032Speter** Returns: 231238032Speter** A pointer to a version of the string with newlines 231338032Speter** mapped to spaces. This should be copied. 231438032Speter*/ 231538032Speter 231638032Speterchar * 231738032Speterdenlstring(s, strict, logattacks) 231838032Speter char *s; 231938032Speter bool strict; 232038032Speter bool logattacks; 232138032Speter{ 232238032Speter register char *p; 232338032Speter int l; 232438032Speter static char *bp = NULL; 232538032Speter static int bl = 0; 232638032Speter 232738032Speter p = s; 232838032Speter while ((p = strchr(p, '\n')) != NULL) 232938032Speter if (strict || (*++p != ' ' && *p != '\t')) 233038032Speter break; 233138032Speter if (p == NULL) 233238032Speter return s; 233338032Speter 233438032Speter l = strlen(s) + 1; 233538032Speter if (bl < l) 233638032Speter { 233738032Speter /* allocate more space */ 233890792Sgshapiro char *nbp = sm_pmalloc_x(l); 233990792Sgshapiro 234038032Speter if (bp != NULL) 234177349Sgshapiro sm_free(bp); 234290792Sgshapiro bp = nbp; 234338032Speter bl = l; 234438032Speter } 234590792Sgshapiro (void) sm_strlcpy(bp, s, l); 234638032Speter for (p = bp; (p = strchr(p, '\n')) != NULL; ) 234738032Speter *p++ = ' '; 234838032Speter 234938032Speter if (logattacks) 235038032Speter { 2351168515Sgshapiro sm_syslog(LOG_NOTICE, CurEnv ? CurEnv->e_id : NULL, 235264562Sgshapiro "POSSIBLE ATTACK from %.100s: newline in string \"%s\"", 235364562Sgshapiro RealHostName == NULL ? "[UNKNOWN]" : RealHostName, 235464562Sgshapiro shortenstring(bp, MAXSHORTSTR)); 235538032Speter } 235638032Speter 235738032Speter return bp; 235838032Speter} 235998841Sgshapiro 236090792Sgshapiro/* 236198841Sgshapiro** STRREPLNONPRT -- replace "unprintable" characters in a string with subst 236298841Sgshapiro** 236398841Sgshapiro** Parameters: 236498841Sgshapiro** s -- string to manipulate (in place) 236598841Sgshapiro** subst -- character to use as replacement 236698841Sgshapiro** 236798841Sgshapiro** Returns: 236898841Sgshapiro** true iff string did not contain "unprintable" characters 236998841Sgshapiro*/ 237098841Sgshapiro 237198841Sgshapirobool 237298841Sgshapirostrreplnonprt(s, c) 237398841Sgshapiro char *s; 237498841Sgshapiro int c; 237598841Sgshapiro{ 237698841Sgshapiro bool ok; 237798841Sgshapiro 237898841Sgshapiro ok = true; 237998841Sgshapiro if (s == NULL) 238098841Sgshapiro return ok; 238198841Sgshapiro while (*s != '\0') 238298841Sgshapiro { 238398841Sgshapiro if (!(isascii(*s) && isprint(*s))) 238498841Sgshapiro { 238598841Sgshapiro *s = c; 238698841Sgshapiro ok = false; 238798841Sgshapiro } 238898841Sgshapiro ++s; 238998841Sgshapiro } 239098841Sgshapiro return ok; 239198841Sgshapiro} 239298841Sgshapiro 239398841Sgshapiro/* 239438032Speter** PATH_IS_DIR -- check to see if file exists and is a directory. 239538032Speter** 239638032Speter** There are some additional checks for security violations in 239738032Speter** here. This routine is intended to be used for the host status 239838032Speter** support. 239938032Speter** 240038032Speter** Parameters: 240138032Speter** pathname -- pathname to check for directory-ness. 240238032Speter** createflag -- if set, create directory if needed. 240338032Speter** 240438032Speter** Returns: 240590792Sgshapiro** true -- if the indicated pathname is a directory 240690792Sgshapiro** false -- otherwise 240738032Speter*/ 240838032Speter 2409120256Sgshapirobool 241038032Speterpath_is_dir(pathname, createflag) 241138032Speter char *pathname; 241238032Speter bool createflag; 241338032Speter{ 241438032Speter struct stat statbuf; 241538032Speter 241638032Speter#if HASLSTAT 241738032Speter if (lstat(pathname, &statbuf) < 0) 2418363466Sgshapiro#else 241938032Speter if (stat(pathname, &statbuf) < 0) 2420363466Sgshapiro#endif 242138032Speter { 242238032Speter if (errno != ENOENT || !createflag) 242390792Sgshapiro return false; 242438032Speter if (mkdir(pathname, 0755) < 0) 242590792Sgshapiro return false; 242690792Sgshapiro return true; 242738032Speter } 242838032Speter if (!S_ISDIR(statbuf.st_mode)) 242938032Speter { 243038032Speter errno = ENOTDIR; 243190792Sgshapiro return false; 243238032Speter } 243338032Speter 243438032Speter /* security: don't allow writable directories */ 243538032Speter if (bitset(S_IWGRP|S_IWOTH, statbuf.st_mode)) 243638032Speter { 243738032Speter errno = EACCES; 243890792Sgshapiro return false; 243938032Speter } 244090792Sgshapiro return true; 244138032Speter} 2442168515Sgshapiro 244390792Sgshapiro/* 244438032Speter** PROC_LIST_ADD -- add process id to list of our children 244538032Speter** 244638032Speter** Parameters: 244738032Speter** pid -- pid to add to list. 244864562Sgshapiro** task -- task of pid. 244964562Sgshapiro** type -- type of process. 245090792Sgshapiro** count -- number of processes. 245190792Sgshapiro** other -- other information for this type. 245238032Speter** 245338032Speter** Returns: 245438032Speter** none 245590792Sgshapiro** 245690792Sgshapiro** Side Effects: 245790792Sgshapiro** May increase CurChildren. May grow ProcList. 245838032Speter*/ 245938032Speter 246090792Sgshapirotypedef struct procs PROCS_T; 246142575Speter 246290792Sgshapirostruct procs 246390792Sgshapiro{ 2464132943Sgshapiro pid_t proc_pid; 2465132943Sgshapiro char *proc_task; 2466132943Sgshapiro int proc_type; 2467132943Sgshapiro int proc_count; 2468132943Sgshapiro int proc_other; 2469132943Sgshapiro SOCKADDR proc_hostaddr; 247090792Sgshapiro}; 247190792Sgshapiro 247290792Sgshapirostatic PROCS_T *volatile ProcListVec = NULL; 247390792Sgshapirostatic int ProcListSize = 0; 247490792Sgshapiro 247538032Spetervoid 2476132943Sgshapiroproc_list_add(pid, task, type, count, other, hostaddr) 247738032Speter pid_t pid; 247842575Speter char *task; 247964562Sgshapiro int type; 248090792Sgshapiro int count; 248190792Sgshapiro int other; 2482132943Sgshapiro SOCKADDR *hostaddr; 248338032Speter{ 248438032Speter int i; 248538032Speter 248638032Speter for (i = 0; i < ProcListSize; i++) 248738032Speter { 248842575Speter if (ProcListVec[i].proc_pid == NO_PID) 248938032Speter break; 249038032Speter } 249138032Speter if (i >= ProcListSize) 249238032Speter { 249338032Speter /* probe the existing vector to avoid growing infinitely */ 249438032Speter proc_list_probe(); 249538032Speter 249638032Speter /* now scan again */ 249738032Speter for (i = 0; i < ProcListSize; i++) 249838032Speter { 249942575Speter if (ProcListVec[i].proc_pid == NO_PID) 250038032Speter break; 250138032Speter } 250238032Speter } 250338032Speter if (i >= ProcListSize) 250438032Speter { 250538032Speter /* grow process list */ 2506168515Sgshapiro int chldwasblocked; 250790792Sgshapiro PROCS_T *npv; 250838032Speter 250990792Sgshapiro SM_ASSERT(ProcListSize < INT_MAX - PROC_LIST_SEG); 2510168515Sgshapiro npv = (PROCS_T *) sm_pmalloc_x((sizeof(*npv)) * 251190792Sgshapiro (ProcListSize + PROC_LIST_SEG)); 2512168515Sgshapiro 2513168515Sgshapiro /* Block SIGCHLD so reapchild() doesn't mess with us */ 2514168515Sgshapiro chldwasblocked = sm_blocksignal(SIGCHLD); 251538032Speter if (ProcListSize > 0) 251638032Speter { 251764562Sgshapiro memmove(npv, ProcListVec, 2518168515Sgshapiro ProcListSize * sizeof(PROCS_T)); 251977349Sgshapiro sm_free(ProcListVec); 252038032Speter } 252190792Sgshapiro 252290792Sgshapiro /* XXX just use memset() to initialize this part? */ 252338032Speter for (i = ProcListSize; i < ProcListSize + PROC_LIST_SEG; i++) 252442575Speter { 252542575Speter npv[i].proc_pid = NO_PID; 252642575Speter npv[i].proc_task = NULL; 252764562Sgshapiro npv[i].proc_type = PROC_NONE; 252842575Speter } 252938032Speter i = ProcListSize; 253038032Speter ProcListSize += PROC_LIST_SEG; 253138032Speter ProcListVec = npv; 2532168515Sgshapiro if (chldwasblocked == 0) 2533168515Sgshapiro (void) sm_releasesignal(SIGCHLD); 253438032Speter } 253542575Speter ProcListVec[i].proc_pid = pid; 253690792Sgshapiro PSTRSET(ProcListVec[i].proc_task, task); 253764562Sgshapiro ProcListVec[i].proc_type = type; 253890792Sgshapiro ProcListVec[i].proc_count = count; 253990792Sgshapiro ProcListVec[i].proc_other = other; 2540132943Sgshapiro if (hostaddr != NULL) 2541132943Sgshapiro ProcListVec[i].proc_hostaddr = *hostaddr; 2542132943Sgshapiro else 2543132943Sgshapiro memset(&ProcListVec[i].proc_hostaddr, 0, 2544132943Sgshapiro sizeof(ProcListVec[i].proc_hostaddr)); 254542575Speter 254642575Speter /* if process adding itself, it's not a child */ 254790792Sgshapiro if (pid != CurrentPid) 254890792Sgshapiro { 254990792Sgshapiro SM_ASSERT(CurChildren < INT_MAX); 255042575Speter CurChildren++; 255190792Sgshapiro } 255238032Speter} 2553168515Sgshapiro 255490792Sgshapiro/* 255542575Speter** PROC_LIST_SET -- set pid task in process list 255642575Speter** 255742575Speter** Parameters: 255842575Speter** pid -- pid to set 255942575Speter** task -- task of pid 256042575Speter** 256142575Speter** Returns: 256242575Speter** none. 256342575Speter*/ 256442575Speter 256542575Spetervoid 256642575Speterproc_list_set(pid, task) 256742575Speter pid_t pid; 256842575Speter char *task; 256942575Speter{ 257042575Speter int i; 257142575Speter 257242575Speter for (i = 0; i < ProcListSize; i++) 257342575Speter { 257442575Speter if (ProcListVec[i].proc_pid == pid) 257542575Speter { 257690792Sgshapiro PSTRSET(ProcListVec[i].proc_task, task); 257742575Speter break; 257842575Speter } 257942575Speter } 258042575Speter} 2581168515Sgshapiro 258290792Sgshapiro/* 258338032Speter** PROC_LIST_DROP -- drop pid from process list 258438032Speter** 258538032Speter** Parameters: 258638032Speter** pid -- pid to drop 258790792Sgshapiro** st -- process status 258890792Sgshapiro** other -- storage for proc_other (return). 258938032Speter** 259038032Speter** Returns: 259190792Sgshapiro** none. 259277349Sgshapiro** 259390792Sgshapiro** Side Effects: 259490792Sgshapiro** May decrease CurChildren, CurRunners, or 259590792Sgshapiro** set RestartRequest or ShutdownRequest. 259690792Sgshapiro** 259777349Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 259877349Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 259977349Sgshapiro** DOING. 260038032Speter*/ 260138032Speter 260290792Sgshapirovoid 260390792Sgshapiroproc_list_drop(pid, st, other) 260438032Speter pid_t pid; 260590792Sgshapiro int st; 260690792Sgshapiro int *other; 260738032Speter{ 260838032Speter int i; 260964562Sgshapiro int type = PROC_NONE; 261038032Speter 261138032Speter for (i = 0; i < ProcListSize; i++) 261238032Speter { 261342575Speter if (ProcListVec[i].proc_pid == pid) 261438032Speter { 261542575Speter ProcListVec[i].proc_pid = NO_PID; 261664562Sgshapiro type = ProcListVec[i].proc_type; 261790792Sgshapiro if (other != NULL) 261890792Sgshapiro *other = ProcListVec[i].proc_other; 2619157001Sgshapiro if (CurChildren > 0) 2620157001Sgshapiro CurChildren--; 262138032Speter break; 262238032Speter } 262338032Speter } 262464562Sgshapiro 262564562Sgshapiro 262690792Sgshapiro if (type == PROC_CONTROL && WIFEXITED(st)) 262790792Sgshapiro { 262890792Sgshapiro /* if so, see if we need to restart or shutdown */ 262990792Sgshapiro if (WEXITSTATUS(st) == EX_RESTART) 263090792Sgshapiro RestartRequest = "control socket"; 263190792Sgshapiro else if (WEXITSTATUS(st) == EX_SHUTDOWN) 263290792Sgshapiro ShutdownRequest = "control socket"; 263390792Sgshapiro } 263490792Sgshapiro else if (type == PROC_QUEUE_CHILD && !WIFSTOPPED(st) && 263590792Sgshapiro ProcListVec[i].proc_other > -1) 263690792Sgshapiro { 263790792Sgshapiro /* restart this persistent runner */ 263890792Sgshapiro mark_work_group_restart(ProcListVec[i].proc_other, st); 263990792Sgshapiro } 264090792Sgshapiro else if (type == PROC_QUEUE) 2641244833Sgshapiro { 264290792Sgshapiro CurRunners -= ProcListVec[i].proc_count; 2643244833Sgshapiro 2644244833Sgshapiro /* CHK_CUR_RUNNERS() can't be used here: uses syslog() */ 2645244833Sgshapiro if (CurRunners < 0) 2646244833Sgshapiro CurRunners = 0; 2647244833Sgshapiro } 264838032Speter} 2649168515Sgshapiro 265090792Sgshapiro/* 265138032Speter** PROC_LIST_CLEAR -- clear the process list 265238032Speter** 265338032Speter** Parameters: 265438032Speter** none. 265538032Speter** 265638032Speter** Returns: 265738032Speter** none. 265890792Sgshapiro** 265990792Sgshapiro** Side Effects: 266090792Sgshapiro** Sets CurChildren to zero. 266138032Speter*/ 266238032Speter 266338032Spetervoid 266438032Speterproc_list_clear() 266538032Speter{ 266638032Speter int i; 266738032Speter 266842575Speter /* start from 1 since 0 is the daemon itself */ 266942575Speter for (i = 1; i < ProcListSize; i++) 267042575Speter ProcListVec[i].proc_pid = NO_PID; 267138032Speter CurChildren = 0; 267238032Speter} 2673168515Sgshapiro 267490792Sgshapiro/* 267538032Speter** PROC_LIST_PROBE -- probe processes in the list to see if they still exist 267638032Speter** 267738032Speter** Parameters: 267838032Speter** none 267938032Speter** 268038032Speter** Returns: 268138032Speter** none 268290792Sgshapiro** 268390792Sgshapiro** Side Effects: 268490792Sgshapiro** May decrease CurChildren. 268538032Speter*/ 268638032Speter 268738032Spetervoid 268838032Speterproc_list_probe() 268938032Speter{ 2690157001Sgshapiro int i, children; 2691157001Sgshapiro int chldwasblocked; 2692157001Sgshapiro pid_t pid; 269338032Speter 2694157001Sgshapiro children = 0; 2695157001Sgshapiro chldwasblocked = sm_blocksignal(SIGCHLD); 2696157001Sgshapiro 269742575Speter /* start from 1 since 0 is the daemon itself */ 269842575Speter for (i = 1; i < ProcListSize; i++) 269938032Speter { 2700157001Sgshapiro pid = ProcListVec[i].proc_pid; 2701157001Sgshapiro if (pid == NO_PID || pid == CurrentPid) 270238032Speter continue; 2703157001Sgshapiro if (kill(pid, 0) < 0) 270438032Speter { 270538032Speter if (LogLevel > 3) 270638032Speter sm_syslog(LOG_DEBUG, CurEnv->e_id, 270764562Sgshapiro "proc_list_probe: lost pid %d", 270864562Sgshapiro (int) ProcListVec[i].proc_pid); 270942575Speter ProcListVec[i].proc_pid = NO_PID; 2710363466Sgshapiro SM_FREE(ProcListVec[i].proc_task); 2711244833Sgshapiro 2712244833Sgshapiro if (ProcListVec[i].proc_type == PROC_QUEUE) 2713244833Sgshapiro { 2714244833Sgshapiro CurRunners -= ProcListVec[i].proc_count; 2715244833Sgshapiro CHK_CUR_RUNNERS("proc_list_probe", i, 2716244833Sgshapiro ProcListVec[i].proc_count); 2717244833Sgshapiro } 2718244833Sgshapiro 271938032Speter CurChildren--; 272038032Speter } 2721157001Sgshapiro else 2722157001Sgshapiro { 2723157001Sgshapiro ++children; 2724157001Sgshapiro } 272538032Speter } 272638032Speter if (CurChildren < 0) 272738032Speter CurChildren = 0; 2728157001Sgshapiro if (chldwasblocked == 0) 2729157001Sgshapiro (void) sm_releasesignal(SIGCHLD); 2730159609Sgshapiro if (LogLevel > 10 && children != CurChildren && CurrentPid == DaemonPid) 2731157001Sgshapiro { 2732157001Sgshapiro sm_syslog(LOG_ERR, NOQID, 2733157001Sgshapiro "proc_list_probe: found %d children, expected %d", 2734157001Sgshapiro children, CurChildren); 2735157001Sgshapiro } 273638032Speter} 273790792Sgshapiro 273890792Sgshapiro/* 273942575Speter** PROC_LIST_DISPLAY -- display the process list 274042575Speter** 274142575Speter** Parameters: 274242575Speter** out -- output file pointer 274390792Sgshapiro** prefix -- string to output in front of each line. 274442575Speter** 274542575Speter** Returns: 274642575Speter** none. 274742575Speter*/ 274842575Speter 274942575Spetervoid 275090792Sgshapiroproc_list_display(out, prefix) 275190792Sgshapiro SM_FILE_T *out; 275290792Sgshapiro char *prefix; 275342575Speter{ 275442575Speter int i; 275542575Speter 275642575Speter for (i = 0; i < ProcListSize; i++) 275742575Speter { 275842575Speter if (ProcListVec[i].proc_pid == NO_PID) 275942575Speter continue; 276042575Speter 276190792Sgshapiro (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "%s%d %s%s\n", 276290792Sgshapiro prefix, 276390792Sgshapiro (int) ProcListVec[i].proc_pid, 276490792Sgshapiro ProcListVec[i].proc_task != NULL ? 276590792Sgshapiro ProcListVec[i].proc_task : "(unknown)", 276690792Sgshapiro (OpMode == MD_SMTP || 276790792Sgshapiro OpMode == MD_DAEMON || 276890792Sgshapiro OpMode == MD_ARPAFTP) ? "\r" : ""); 276942575Speter } 277042575Speter} 277190792Sgshapiro 277290792Sgshapiro/* 277390792Sgshapiro** PROC_LIST_SIGNAL -- send a signal to a type of process in the list 277480785Sgshapiro** 277580785Sgshapiro** Parameters: 277690792Sgshapiro** type -- type of process to signal 277790792Sgshapiro** signal -- the type of signal to send 277880785Sgshapiro** 277990792Sgshapiro** Results: 278090792Sgshapiro** none. 278190792Sgshapiro** 278290792Sgshapiro** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 278390792Sgshapiro** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 278490792Sgshapiro** DOING. 278580785Sgshapiro*/ 278680785Sgshapiro 278790792Sgshapirovoid 278890792Sgshapiroproc_list_signal(type, signal) 278990792Sgshapiro int type; 279090792Sgshapiro int signal; 279180785Sgshapiro{ 279290792Sgshapiro int chldwasblocked; 279390792Sgshapiro int alrmwasblocked; 279490792Sgshapiro int i; 279590792Sgshapiro pid_t mypid = getpid(); 279680785Sgshapiro 279790792Sgshapiro /* block these signals so that we may signal cleanly */ 279890792Sgshapiro chldwasblocked = sm_blocksignal(SIGCHLD); 279990792Sgshapiro alrmwasblocked = sm_blocksignal(SIGALRM); 280080785Sgshapiro 280190792Sgshapiro /* Find all processes of type and send signal */ 280290792Sgshapiro for (i = 0; i < ProcListSize; i++) 280380785Sgshapiro { 280490792Sgshapiro if (ProcListVec[i].proc_pid == NO_PID || 280590792Sgshapiro ProcListVec[i].proc_pid == mypid) 280690792Sgshapiro continue; 280790792Sgshapiro if (ProcListVec[i].proc_type != type) 280890792Sgshapiro continue; 280990792Sgshapiro (void) kill(ProcListVec[i].proc_pid, signal); 281080785Sgshapiro } 281180785Sgshapiro 281290792Sgshapiro /* restore the signals */ 281390792Sgshapiro if (alrmwasblocked == 0) 281490792Sgshapiro (void) sm_releasesignal(SIGALRM); 281590792Sgshapiro if (chldwasblocked == 0) 281690792Sgshapiro (void) sm_releasesignal(SIGCHLD); 281780785Sgshapiro} 2818132943Sgshapiro 2819132943Sgshapiro/* 2820132943Sgshapiro** COUNT_OPEN_CONNECTIONS 2821132943Sgshapiro** 2822132943Sgshapiro** Parameters: 2823132943Sgshapiro** hostaddr - ClientAddress 2824132943Sgshapiro** 2825132943Sgshapiro** Returns: 2826132943Sgshapiro** the number of open connections for this client 2827132943Sgshapiro** 2828132943Sgshapiro*/ 2829132943Sgshapiro 2830132943Sgshapiroint 2831132943Sgshapirocount_open_connections(hostaddr) 2832132943Sgshapiro SOCKADDR *hostaddr; 2833132943Sgshapiro{ 2834132943Sgshapiro int i, n; 2835132943Sgshapiro 2836132943Sgshapiro if (hostaddr == NULL) 2837132943Sgshapiro return 0; 2838173340Sgshapiro 2839173340Sgshapiro /* 2840182352Sgshapiro ** This code gets called before proc_list_add() gets called, 2841182352Sgshapiro ** so we (the daemon child for this connection) have not yet 2842182352Sgshapiro ** counted ourselves. Hence initialize the counter to 1 2843182352Sgshapiro ** instead of 0 to compensate. 2844173340Sgshapiro */ 2845173340Sgshapiro 2846173340Sgshapiro n = 1; 2847132943Sgshapiro for (i = 0; i < ProcListSize; i++) 2848132943Sgshapiro { 2849132943Sgshapiro if (ProcListVec[i].proc_pid == NO_PID) 2850132943Sgshapiro continue; 2851132943Sgshapiro if (hostaddr->sa.sa_family != 2852132943Sgshapiro ProcListVec[i].proc_hostaddr.sa.sa_family) 2853132943Sgshapiro continue; 2854132943Sgshapiro#if NETINET 2855132943Sgshapiro if (hostaddr->sa.sa_family == AF_INET && 2856132943Sgshapiro (hostaddr->sin.sin_addr.s_addr == 2857132943Sgshapiro ProcListVec[i].proc_hostaddr.sin.sin_addr.s_addr)) 2858132943Sgshapiro n++; 2859363466Sgshapiro#endif 2860132943Sgshapiro#if NETINET6 2861132943Sgshapiro if (hostaddr->sa.sa_family == AF_INET6 && 2862132943Sgshapiro IN6_ARE_ADDR_EQUAL(&(hostaddr->sin6.sin6_addr), 2863132943Sgshapiro &(ProcListVec[i].proc_hostaddr.sin6.sin6_addr))) 2864132943Sgshapiro n++; 2865363466Sgshapiro#endif 2866132943Sgshapiro } 2867132943Sgshapiro return n; 2868132943Sgshapiro} 2869244833Sgshapiro 2870285229Sgshapiro#if _FFR_XCNCT 2871285229Sgshapiro/* 2872285229Sgshapiro** XCONNECT -- get X-CONNECT info 2873285229Sgshapiro** 2874285229Sgshapiro** Parameters: 2875285229Sgshapiro** inchannel -- FILE to check 2876285229Sgshapiro** 2877285229Sgshapiro** Returns: 2878285229Sgshapiro** -1 on error 2879285229Sgshapiro** 0 if X-CONNECT was not given 2880285229Sgshapiro** >0 if X-CONNECT was used successfully (D_XCNCT*) 2881285229Sgshapiro*/ 2882285229Sgshapiro 2883285229Sgshapiroint 2884285229Sgshapiroxconnect(inchannel) 2885285229Sgshapiro SM_FILE_T *inchannel; 2886285229Sgshapiro{ 2887285229Sgshapiro int r, i; 2888285229Sgshapiro char *p, *b, delim, inp[MAXINPLINE]; 2889285229Sgshapiro SOCKADDR addr; 2890285229Sgshapiro char **pvp; 2891285229Sgshapiro char pvpbuf[PSBUFSIZE]; 2892285229Sgshapiro char *peerhostname; /* name of SMTP peer or "localhost" */ 2893285229Sgshapiro extern ENVELOPE BlankEnvelope; 2894285229Sgshapiro 2895285229Sgshapiro#define XCONNECT "X-CONNECT " 2896285229Sgshapiro#define XCNNCTLEN (sizeof(XCONNECT) - 1) 2897285229Sgshapiro 2898285229Sgshapiro /* Ask the ruleset whether to use x-connect */ 2899285229Sgshapiro pvp = NULL; 2900285229Sgshapiro peerhostname = RealHostName; 2901285229Sgshapiro if (peerhostname == NULL) 2902285229Sgshapiro peerhostname = "localhost"; 2903285229Sgshapiro r = rscap("x_connect", peerhostname, 2904285229Sgshapiro anynet_ntoa(&RealHostAddr), &BlankEnvelope, 2905285229Sgshapiro &pvp, pvpbuf, sizeof(pvpbuf)); 2906285229Sgshapiro if (tTd(75, 8)) 2907285229Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect: rscap=%d", r); 2908285229Sgshapiro if (r == EX_UNAVAILABLE) 2909285229Sgshapiro return 0; 2910285229Sgshapiro if (r != EX_OK) 2911285229Sgshapiro { 2912285229Sgshapiro /* ruleset error */ 2913285229Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect: rscap=%d", r); 2914285229Sgshapiro return 0; 2915285229Sgshapiro } 2916285229Sgshapiro if (pvp != NULL && pvp[0] != NULL && (pvp[0][0] & 0377) == CANONNET) 2917285229Sgshapiro { 2918285229Sgshapiro /* $#: no x-connect */ 2919285229Sgshapiro if (tTd(75, 7)) 2920285229Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect: nope"); 2921285229Sgshapiro return 0; 2922285229Sgshapiro } 2923285229Sgshapiro 2924363466Sgshapiro# if _FFR_XCNCT > 1 2925363466Sgshapiro if (pvp != NULL && pvp[0] != NULL && 2926363466Sgshapiro pvp[0][0] == '2' && pvp[0][1] == '2' && pvp[0][2] == '0') 2927363466Sgshapiro { 2928363466Sgshapiro char *hostname; /* my hostname ($j) */ 2929363466Sgshapiro 2930363466Sgshapiro hostname = macvalue('j', &BlankEnvelope); 2931363466Sgshapiro if (tTd(75, 7)) 2932363466Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect=%s", pvp[0]); 2933363466Sgshapiro message("220-%s %s", hostname != NULL ? hostname : "xconnect", 2934363466Sgshapiro pvp[1] != NULL ? pvp[1] : "waiting for xconnect"); 2935363466Sgshapiro sm_io_flush(OutChannel, SM_TIME_DEFAULT); 2936363466Sgshapiro } 2937363466Sgshapiro# endif 2938363466Sgshapiro 2939285229Sgshapiro p = sfgets(inp, sizeof(inp), InChannel, TimeOuts.to_nextcommand, "pre"); 2940285229Sgshapiro if (tTd(75, 6)) 2941285229Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect: input=%s", p); 2942285229Sgshapiro if (p == NULL || strncasecmp(p, XCONNECT, XCNNCTLEN) != 0) 2943285229Sgshapiro return -1; 2944285229Sgshapiro p += XCNNCTLEN; 2945363466Sgshapiro while (SM_ISSPACE(*p)) 2946285229Sgshapiro p++; 2947285229Sgshapiro 2948285229Sgshapiro /* parameters: IPAddress [Hostname[ M]] */ 2949285229Sgshapiro b = p; 2950285229Sgshapiro while (*p != '\0' && isascii(*p) && 2951285229Sgshapiro (isalnum(*p) || *p == '.' || *p== ':')) 2952285229Sgshapiro p++; 2953285229Sgshapiro delim = *p; 2954285229Sgshapiro *p = '\0'; 2955285229Sgshapiro 2956285229Sgshapiro memset(&addr, '\0', sizeof(addr)); 2957285229Sgshapiro addr.sin.sin_addr.s_addr = inet_addr(b); 2958285229Sgshapiro if (addr.sin.sin_addr.s_addr != INADDR_NONE) 2959285229Sgshapiro { 2960285229Sgshapiro addr.sa.sa_family = AF_INET; 2961285229Sgshapiro memcpy(&RealHostAddr, &addr, sizeof(addr)); 2962285229Sgshapiro if (tTd(75, 2)) 2963285229Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect: addr=%s", 2964285229Sgshapiro anynet_ntoa(&RealHostAddr)); 2965285229Sgshapiro } 2966285229Sgshapiro# if NETINET6 2967285229Sgshapiro else if ((r = inet_pton(AF_INET6, b, &addr.sin6.sin6_addr)) == 1) 2968285229Sgshapiro { 2969285229Sgshapiro addr.sa.sa_family = AF_INET6; 2970285229Sgshapiro memcpy(&RealHostAddr, &addr, sizeof(addr)); 2971285229Sgshapiro } 2972363466Sgshapiro# endif 2973285229Sgshapiro else 2974285229Sgshapiro return -1; 2975285229Sgshapiro 2976285229Sgshapiro /* more parameters? */ 2977285229Sgshapiro if (delim != ' ') 2978285229Sgshapiro return D_XCNCT; 2979285229Sgshapiro 2980285229Sgshapiro for (b = ++p, i = 0; 2981285229Sgshapiro *p != '\0' && isascii(*p) && (isalnum(*p) || *p == '.' || *p == '-'); 2982285229Sgshapiro p++, i++) 2983285229Sgshapiro ; 2984285229Sgshapiro if (i == 0) 2985285229Sgshapiro return D_XCNCT; 2986285229Sgshapiro delim = *p; 2987285229Sgshapiro if (i > MAXNAME) 2988285229Sgshapiro b[MAXNAME] = '\0'; 2989285229Sgshapiro else 2990285229Sgshapiro b[i] = '\0'; 2991363466Sgshapiro SM_FREE(RealHostName); 2992285229Sgshapiro RealHostName = newstr(b); 2993285229Sgshapiro if (tTd(75, 2)) 2994285229Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect: host=%s", b); 2995285229Sgshapiro *p = delim; 2996285229Sgshapiro 2997285229Sgshapiro b = p; 2998285229Sgshapiro if (*p != ' ') 2999285229Sgshapiro return D_XCNCT; 3000285229Sgshapiro 3001363466Sgshapiro while (*p != '\0' && SM_ISSPACE(*p)) 3002285229Sgshapiro p++; 3003285229Sgshapiro 3004285229Sgshapiro if (tTd(75, 4)) 3005285229Sgshapiro { 3006285229Sgshapiro char *e; 3007285229Sgshapiro 3008285229Sgshapiro e = strpbrk(p, "\r\n"); 3009285229Sgshapiro if (e != NULL) 3010285229Sgshapiro *e = '\0'; 3011285229Sgshapiro sm_syslog(LOG_INFO, NOQID, "x-connect: rest=%s", p); 3012285229Sgshapiro } 3013285229Sgshapiro if (*p == 'M') 3014285229Sgshapiro return D_XCNCT_M; 3015285229Sgshapiro 3016285229Sgshapiro return D_XCNCT; 3017285229Sgshapiro} 3018285229Sgshapiro#endif /* _FFR_XCNCT */ 3019