1/* 2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 *
| 1/* 2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 *
|
| 12 * $FreeBSD: head/contrib/sendmail/src/err.c 168520 2007-04-09 01:44:16Z gshapiro $
|
12 */ 13 14#include <sendmail.h> 15
| 13 */ 14 15#include <sendmail.h> 16
|
16SM_RCSID("@(#)$Id: err.c,v 8.191 2003/01/10 02:16:46 ca Exp $")
| 17SM_RCSID("@(#)$Id: err.c,v 8.196 2006/11/10 23:14:08 ca Exp $")
|
17 18#if LDAPMAP 19# include <lber.h> 20# include <ldap.h> /* for LDAP error codes */ 21#endif /* LDAPMAP */ 22 23static void putoutmsg __P((char *, bool, bool)); 24static void puterrmsg __P((char *)); 25static char *fmtmsg __P((char *, const char *, const char *, const char *, 26 int, const char *, va_list)); 27 28/* 29** FATAL_ERROR -- handle a fatal exception 30** 31** This function is installed as the default exception handler 32** in the main sendmail process, and in all child processes 33** that we create. Its job is to handle exceptions that are not 34** handled at a lower level. 35** 36** The theory is that unhandled exceptions will be 'fatal' class 37** exceptions (with an "F:" prefix), such as the out-of-memory 38** exception "F:sm.heap". As such, they are handled by exiting 39** the process in exactly the same way that xalloc() in Sendmail 8.10 40** exits the process when it fails due to lack of memory: 41** we call syserr with a message beginning with "!". 42** 43** Parameters: 44** exc -- exception which is terminating this process 45** 46** Returns: 47** none 48*/ 49 50void 51fatal_error(exc) 52 SM_EXC_T *exc; 53{ 54 static char buf[256]; 55 SM_FILE_T f; 56 57 /* 58 ** This function may be called when the heap is exhausted. 59 ** The following code writes the message for 'exc' into our 60 ** static buffer without allocating memory or raising exceptions. 61 */ 62 63 sm_strio_init(&f, buf, sizeof(buf)); 64 sm_exc_write(exc, &f); 65 (void) sm_io_flush(&f, SM_TIME_DEFAULT); 66 67 /* 68 ** Terminate the process after logging an error and cleaning up. 69 ** Problems: 70 ** - syserr decides what class of error this is by looking at errno. 71 ** That's no good; we should look at the exc structure. 72 ** - The cleanup code should be moved out of syserr 73 ** and into individual exception handlers 74 ** that are part of the module they clean up after. 75 */ 76 77 errno = ENOMEM; 78 syserr("!%s", buf); 79} 80 81/* 82** SYSERR -- Print error message. 83** 84** Prints an error message via sm_io_printf to the diagnostic output. 85** 86** If the first character of the syserr message is `!' it will 87** log this as an ALERT message and exit immediately. This can 88** leave queue files in an indeterminate state, so it should not 89** be used lightly. 90** 91** If the first character of the syserr message is '!' or '@' 92** then syserr knows that the process is about to be terminated, 93** so the SMTP reply code defaults to 421. Otherwise, the 94** reply code defaults to 451 or 554, depending on errno. 95** 96** Parameters: 97** fmt -- the format string. An optional '!' or '@', 98** followed by an optional three-digit SMTP 99** reply code, followed by message text. 100** (others) -- parameters 101** 102** Returns: 103** none 104** Raises E:mta.quickabort if QuickAbort is set. 105** 106** Side Effects: 107** increments Errors. 108** sets ExitStat. 109*/ 110 111char MsgBuf[BUFSIZ*2]; /* text of most recent message */
| 18 19#if LDAPMAP 20# include <lber.h> 21# include <ldap.h> /* for LDAP error codes */ 22#endif /* LDAPMAP */ 23 24static void putoutmsg __P((char *, bool, bool)); 25static void puterrmsg __P((char *)); 26static char *fmtmsg __P((char *, const char *, const char *, const char *, 27 int, const char *, va_list)); 28 29/* 30** FATAL_ERROR -- handle a fatal exception 31** 32** This function is installed as the default exception handler 33** in the main sendmail process, and in all child processes 34** that we create. Its job is to handle exceptions that are not 35** handled at a lower level. 36** 37** The theory is that unhandled exceptions will be 'fatal' class 38** exceptions (with an "F:" prefix), such as the out-of-memory 39** exception "F:sm.heap". As such, they are handled by exiting 40** the process in exactly the same way that xalloc() in Sendmail 8.10 41** exits the process when it fails due to lack of memory: 42** we call syserr with a message beginning with "!". 43** 44** Parameters: 45** exc -- exception which is terminating this process 46** 47** Returns: 48** none 49*/ 50 51void 52fatal_error(exc) 53 SM_EXC_T *exc; 54{ 55 static char buf[256]; 56 SM_FILE_T f; 57 58 /* 59 ** This function may be called when the heap is exhausted. 60 ** The following code writes the message for 'exc' into our 61 ** static buffer without allocating memory or raising exceptions. 62 */ 63 64 sm_strio_init(&f, buf, sizeof(buf)); 65 sm_exc_write(exc, &f); 66 (void) sm_io_flush(&f, SM_TIME_DEFAULT); 67 68 /* 69 ** Terminate the process after logging an error and cleaning up. 70 ** Problems: 71 ** - syserr decides what class of error this is by looking at errno. 72 ** That's no good; we should look at the exc structure. 73 ** - The cleanup code should be moved out of syserr 74 ** and into individual exception handlers 75 ** that are part of the module they clean up after. 76 */ 77 78 errno = ENOMEM; 79 syserr("!%s", buf); 80} 81 82/* 83** SYSERR -- Print error message. 84** 85** Prints an error message via sm_io_printf to the diagnostic output. 86** 87** If the first character of the syserr message is `!' it will 88** log this as an ALERT message and exit immediately. This can 89** leave queue files in an indeterminate state, so it should not 90** be used lightly. 91** 92** If the first character of the syserr message is '!' or '@' 93** then syserr knows that the process is about to be terminated, 94** so the SMTP reply code defaults to 421. Otherwise, the 95** reply code defaults to 451 or 554, depending on errno. 96** 97** Parameters: 98** fmt -- the format string. An optional '!' or '@', 99** followed by an optional three-digit SMTP 100** reply code, followed by message text. 101** (others) -- parameters 102** 103** Returns: 104** none 105** Raises E:mta.quickabort if QuickAbort is set. 106** 107** Side Effects: 108** increments Errors. 109** sets ExitStat. 110*/ 111 112char MsgBuf[BUFSIZ*2]; /* text of most recent message */
|
112static char HeldMessageBuf[sizeof MsgBuf]; /* for held messages */
| 113static char HeldMessageBuf[sizeof(MsgBuf)]; /* for held messages */
|
113 114#if NAMED_BIND && !defined(NO_DATA) 115# define NO_DATA NO_ADDRESS 116#endif /* NAMED_BIND && !defined(NO_DATA) */ 117 118void 119/*VARARGS1*/ 120#ifdef __STDC__ 121syserr(const char *fmt, ...) 122#else /* __STDC__ */ 123syserr(fmt, va_alist) 124 const char *fmt; 125 va_dcl 126#endif /* __STDC__ */ 127{ 128 register char *p; 129 int save_errno = errno; 130 bool panic; 131 bool exiting; 132 char *user; 133 char *enhsc; 134 char *errtxt; 135 struct passwd *pw; 136 char ubuf[80]; 137 SM_VA_LOCAL_DECL 138 139 switch (*fmt) 140 { 141 case '!': 142 ++fmt; 143 panic = true; 144 exiting = true; 145 break; 146 case '@': 147 ++fmt; 148 panic = false; 149 exiting = true; 150 break; 151 default: 152 panic = false; 153 exiting = false; 154 break; 155 } 156 157 /* format and output the error message */ 158 if (exiting) 159 { 160 /* 161 ** Since we are terminating the process, 162 ** we are aborting the entire SMTP session, 163 ** rather than just the current transaction. 164 */ 165 166 p = "421"; 167 enhsc = "4.0.0"; 168 } 169 else if (save_errno == 0) 170 { 171 p = "554"; 172 enhsc = "5.0.0"; 173 } 174 else 175 { 176 p = "451"; 177 enhsc = "4.0.0"; 178 } 179 SM_VA_START(ap, fmt); 180 errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap); 181 SM_VA_END(ap); 182 puterrmsg(MsgBuf); 183 184 /* save this message for mailq printing */ 185 if (!panic && CurEnv != NULL) 186 { 187 char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 188 189 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 190 sm_free(CurEnv->e_message); 191 CurEnv->e_message = nmsg; 192 } 193 194 /* determine exit status if not already set */ 195 if (ExitStat == EX_OK) 196 { 197 if (save_errno == 0) 198 ExitStat = EX_SOFTWARE; 199 else 200 ExitStat = EX_OSERR; 201 if (tTd(54, 1)) 202 sm_dprintf("syserr: ExitStat = %d\n", ExitStat); 203 } 204 205 pw = sm_getpwuid(RealUid); 206 if (pw != NULL) 207 user = pw->pw_name; 208 else 209 { 210 user = ubuf;
| 114 115#if NAMED_BIND && !defined(NO_DATA) 116# define NO_DATA NO_ADDRESS 117#endif /* NAMED_BIND && !defined(NO_DATA) */ 118 119void 120/*VARARGS1*/ 121#ifdef __STDC__ 122syserr(const char *fmt, ...) 123#else /* __STDC__ */ 124syserr(fmt, va_alist) 125 const char *fmt; 126 va_dcl 127#endif /* __STDC__ */ 128{ 129 register char *p; 130 int save_errno = errno; 131 bool panic; 132 bool exiting; 133 char *user; 134 char *enhsc; 135 char *errtxt; 136 struct passwd *pw; 137 char ubuf[80]; 138 SM_VA_LOCAL_DECL 139 140 switch (*fmt) 141 { 142 case '!': 143 ++fmt; 144 panic = true; 145 exiting = true; 146 break; 147 case '@': 148 ++fmt; 149 panic = false; 150 exiting = true; 151 break; 152 default: 153 panic = false; 154 exiting = false; 155 break; 156 } 157 158 /* format and output the error message */ 159 if (exiting) 160 { 161 /* 162 ** Since we are terminating the process, 163 ** we are aborting the entire SMTP session, 164 ** rather than just the current transaction. 165 */ 166 167 p = "421"; 168 enhsc = "4.0.0"; 169 } 170 else if (save_errno == 0) 171 { 172 p = "554"; 173 enhsc = "5.0.0"; 174 } 175 else 176 { 177 p = "451"; 178 enhsc = "4.0.0"; 179 } 180 SM_VA_START(ap, fmt); 181 errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap); 182 SM_VA_END(ap); 183 puterrmsg(MsgBuf); 184 185 /* save this message for mailq printing */ 186 if (!panic && CurEnv != NULL) 187 { 188 char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 189 190 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 191 sm_free(CurEnv->e_message); 192 CurEnv->e_message = nmsg; 193 } 194 195 /* determine exit status if not already set */ 196 if (ExitStat == EX_OK) 197 { 198 if (save_errno == 0) 199 ExitStat = EX_SOFTWARE; 200 else 201 ExitStat = EX_OSERR; 202 if (tTd(54, 1)) 203 sm_dprintf("syserr: ExitStat = %d\n", ExitStat); 204 } 205 206 pw = sm_getpwuid(RealUid); 207 if (pw != NULL) 208 user = pw->pw_name; 209 else 210 { 211 user = ubuf;
|
211 (void) sm_snprintf(ubuf, sizeof ubuf, "UID%d", (int) RealUid);
| 212 (void) sm_snprintf(ubuf, sizeof(ubuf), "UID%d", (int) RealUid);
|
212 } 213 214 if (LogLevel > 0) 215 sm_syslog(panic ? LOG_ALERT : LOG_CRIT, 216 CurEnv == NULL ? NOQID : CurEnv->e_id, 217 "SYSERR(%s): %.900s", 218 user, errtxt); 219 switch (save_errno) 220 { 221 case EBADF: 222 case ENFILE: 223 case EMFILE: 224 case ENOTTY: 225#ifdef EFBIG 226 case EFBIG: 227#endif /* EFBIG */ 228#ifdef ESPIPE 229 case ESPIPE: 230#endif /* ESPIPE */ 231#ifdef EPIPE 232 case EPIPE: 233#endif /* EPIPE */ 234#ifdef ENOBUFS 235 case ENOBUFS: 236#endif /* ENOBUFS */ 237#ifdef ESTALE 238 case ESTALE: 239#endif /* ESTALE */ 240 printopenfds(true); 241 mci_dump_all(smioout, true); 242 break; 243 } 244 if (panic) 245 { 246#if XLA 247 xla_all_end(); 248#endif /* XLA */ 249 sync_queue_time(); 250 if (tTd(0, 1)) 251 abort(); 252 exit(EX_OSERR); 253 } 254 errno = 0; 255 if (QuickAbort) 256 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 257} 258/* 259** USRERR -- Signal user error. 260** 261** This is much like syserr except it is for user errors. 262** 263** Parameters: 264** fmt -- the format string. If it does not begin with 265** a three-digit SMTP reply code, 550 is assumed. 266** (others) -- sm_io_printf strings 267** 268** Returns: 269** none 270** Raises E:mta.quickabort if QuickAbort is set. 271** 272** Side Effects: 273** increments Errors. 274*/ 275 276/*VARARGS1*/ 277void 278#ifdef __STDC__ 279usrerr(const char *fmt, ...) 280#else /* __STDC__ */ 281usrerr(fmt, va_alist) 282 const char *fmt; 283 va_dcl 284#endif /* __STDC__ */ 285{ 286 char *enhsc; 287 char *errtxt; 288 SM_VA_LOCAL_DECL 289 290 if (fmt[0] == '5' || fmt[0] == '6') 291 enhsc = "5.0.0"; 292 else if (fmt[0] == '4' || fmt[0] == '8') 293 enhsc = "4.0.0"; 294 else if (fmt[0] == '2') 295 enhsc = "2.0.0"; 296 else 297 enhsc = NULL; 298 SM_VA_START(ap, fmt); 299 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 300 SM_VA_END(ap); 301 302 if (SuprErrs) 303 return; 304 305 /* save this message for mailq printing */ 306 switch (MsgBuf[0]) 307 { 308 case '4': 309 case '8': 310 if (CurEnv->e_message != NULL) 311 break; 312 313 /* FALLTHROUGH */ 314 315 case '5': 316 case '6': 317 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 318 sm_free(CurEnv->e_message); 319 if (MsgBuf[0] == '6') 320 { 321 char buf[MAXLINE]; 322
| 213 } 214 215 if (LogLevel > 0) 216 sm_syslog(panic ? LOG_ALERT : LOG_CRIT, 217 CurEnv == NULL ? NOQID : CurEnv->e_id, 218 "SYSERR(%s): %.900s", 219 user, errtxt); 220 switch (save_errno) 221 { 222 case EBADF: 223 case ENFILE: 224 case EMFILE: 225 case ENOTTY: 226#ifdef EFBIG 227 case EFBIG: 228#endif /* EFBIG */ 229#ifdef ESPIPE 230 case ESPIPE: 231#endif /* ESPIPE */ 232#ifdef EPIPE 233 case EPIPE: 234#endif /* EPIPE */ 235#ifdef ENOBUFS 236 case ENOBUFS: 237#endif /* ENOBUFS */ 238#ifdef ESTALE 239 case ESTALE: 240#endif /* ESTALE */ 241 printopenfds(true); 242 mci_dump_all(smioout, true); 243 break; 244 } 245 if (panic) 246 { 247#if XLA 248 xla_all_end(); 249#endif /* XLA */ 250 sync_queue_time(); 251 if (tTd(0, 1)) 252 abort(); 253 exit(EX_OSERR); 254 } 255 errno = 0; 256 if (QuickAbort) 257 sm_exc_raisenew_x(&EtypeQuickAbort, 2); 258} 259/* 260** USRERR -- Signal user error. 261** 262** This is much like syserr except it is for user errors. 263** 264** Parameters: 265** fmt -- the format string. If it does not begin with 266** a three-digit SMTP reply code, 550 is assumed. 267** (others) -- sm_io_printf strings 268** 269** Returns: 270** none 271** Raises E:mta.quickabort if QuickAbort is set. 272** 273** Side Effects: 274** increments Errors. 275*/ 276 277/*VARARGS1*/ 278void 279#ifdef __STDC__ 280usrerr(const char *fmt, ...) 281#else /* __STDC__ */ 282usrerr(fmt, va_alist) 283 const char *fmt; 284 va_dcl 285#endif /* __STDC__ */ 286{ 287 char *enhsc; 288 char *errtxt; 289 SM_VA_LOCAL_DECL 290 291 if (fmt[0] == '5' || fmt[0] == '6') 292 enhsc = "5.0.0"; 293 else if (fmt[0] == '4' || fmt[0] == '8') 294 enhsc = "4.0.0"; 295 else if (fmt[0] == '2') 296 enhsc = "2.0.0"; 297 else 298 enhsc = NULL; 299 SM_VA_START(ap, fmt); 300 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 301 SM_VA_END(ap); 302 303 if (SuprErrs) 304 return; 305 306 /* save this message for mailq printing */ 307 switch (MsgBuf[0]) 308 { 309 case '4': 310 case '8': 311 if (CurEnv->e_message != NULL) 312 break; 313 314 /* FALLTHROUGH */ 315 316 case '5': 317 case '6': 318 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 319 sm_free(CurEnv->e_message); 320 if (MsgBuf[0] == '6') 321 { 322 char buf[MAXLINE]; 323
|
323 (void) sm_snprintf(buf, sizeof buf,
| 324 (void) sm_snprintf(buf, sizeof(buf),
|
324 "Postmaster warning: %.*s",
| 325 "Postmaster warning: %.*s",
|
325 (int) sizeof buf - 22, errtxt);
| 326 (int) sizeof(buf) - 22, errtxt);
|
326 CurEnv->e_message = 327 sm_rpool_strdup_x(CurEnv->e_rpool, buf); 328 } 329 else 330 { 331 CurEnv->e_message = 332 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 333 } 334 break; 335 } 336 337 puterrmsg(MsgBuf); 338 if (LogLevel > 3 && LogUsrErrs) 339 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 340 if (QuickAbort) 341 sm_exc_raisenew_x(&EtypeQuickAbort, 1); 342} 343/* 344** USRERRENH -- Signal user error. 345** 346** Same as usrerr but with enhanced status code. 347** 348** Parameters: 349** enhsc -- the enhanced status code. 350** fmt -- the format string. If it does not begin with 351** a three-digit SMTP reply code, 550 is assumed. 352** (others) -- sm_io_printf strings 353** 354** Returns: 355** none 356** Raises E:mta.quickabort if QuickAbort is set. 357** 358** Side Effects: 359** increments Errors. 360*/ 361 362/*VARARGS1*/ 363void 364#ifdef __STDC__ 365usrerrenh(char *enhsc, const char *fmt, ...) 366#else /* __STDC__ */ 367usrerrenh(enhsc, fmt, va_alist) 368 char *enhsc; 369 const char *fmt; 370 va_dcl 371#endif /* __STDC__ */ 372{ 373 char *errtxt; 374 SM_VA_LOCAL_DECL 375 376 if (enhsc == NULL || *enhsc == '\0') 377 { 378 if (fmt[0] == '5' || fmt[0] == '6') 379 enhsc = "5.0.0"; 380 else if (fmt[0] == '4' || fmt[0] == '8') 381 enhsc = "4.0.0"; 382 else if (fmt[0] == '2') 383 enhsc = "2.0.0"; 384 } 385 SM_VA_START(ap, fmt); 386 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 387 SM_VA_END(ap); 388 389 if (SuprErrs) 390 return; 391 392 /* save this message for mailq printing */ 393 switch (MsgBuf[0]) 394 { 395 case '4': 396 case '8': 397 if (CurEnv->e_message != NULL) 398 break; 399 400 /* FALLTHROUGH */ 401 402 case '5': 403 case '6': 404 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 405 sm_free(CurEnv->e_message); 406 if (MsgBuf[0] == '6') 407 { 408 char buf[MAXLINE]; 409
| 327 CurEnv->e_message = 328 sm_rpool_strdup_x(CurEnv->e_rpool, buf); 329 } 330 else 331 { 332 CurEnv->e_message = 333 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 334 } 335 break; 336 } 337 338 puterrmsg(MsgBuf); 339 if (LogLevel > 3 && LogUsrErrs) 340 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 341 if (QuickAbort) 342 sm_exc_raisenew_x(&EtypeQuickAbort, 1); 343} 344/* 345** USRERRENH -- Signal user error. 346** 347** Same as usrerr but with enhanced status code. 348** 349** Parameters: 350** enhsc -- the enhanced status code. 351** fmt -- the format string. If it does not begin with 352** a three-digit SMTP reply code, 550 is assumed. 353** (others) -- sm_io_printf strings 354** 355** Returns: 356** none 357** Raises E:mta.quickabort if QuickAbort is set. 358** 359** Side Effects: 360** increments Errors. 361*/ 362 363/*VARARGS1*/ 364void 365#ifdef __STDC__ 366usrerrenh(char *enhsc, const char *fmt, ...) 367#else /* __STDC__ */ 368usrerrenh(enhsc, fmt, va_alist) 369 char *enhsc; 370 const char *fmt; 371 va_dcl 372#endif /* __STDC__ */ 373{ 374 char *errtxt; 375 SM_VA_LOCAL_DECL 376 377 if (enhsc == NULL || *enhsc == '\0') 378 { 379 if (fmt[0] == '5' || fmt[0] == '6') 380 enhsc = "5.0.0"; 381 else if (fmt[0] == '4' || fmt[0] == '8') 382 enhsc = "4.0.0"; 383 else if (fmt[0] == '2') 384 enhsc = "2.0.0"; 385 } 386 SM_VA_START(ap, fmt); 387 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 388 SM_VA_END(ap); 389 390 if (SuprErrs) 391 return; 392 393 /* save this message for mailq printing */ 394 switch (MsgBuf[0]) 395 { 396 case '4': 397 case '8': 398 if (CurEnv->e_message != NULL) 399 break; 400 401 /* FALLTHROUGH */ 402 403 case '5': 404 case '6': 405 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 406 sm_free(CurEnv->e_message); 407 if (MsgBuf[0] == '6') 408 { 409 char buf[MAXLINE]; 410
|
410 (void) sm_snprintf(buf, sizeof buf,
| 411 (void) sm_snprintf(buf, sizeof(buf),
|
411 "Postmaster warning: %.*s",
| 412 "Postmaster warning: %.*s",
|
412 (int) sizeof buf - 22, errtxt);
| 413 (int) sizeof(buf) - 22, errtxt);
|
413 CurEnv->e_message = 414 sm_rpool_strdup_x(CurEnv->e_rpool, buf); 415 } 416 else 417 { 418 CurEnv->e_message = 419 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 420 } 421 break; 422 } 423 424 puterrmsg(MsgBuf); 425 if (LogLevel > 3 && LogUsrErrs) 426 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 427 if (QuickAbort) 428 sm_exc_raisenew_x(&EtypeQuickAbort, 1); 429} 430/* 431** MESSAGE -- print message (not necessarily an error) 432** 433** Parameters: 434** msg -- the message (sm_io_printf fmt) -- it can begin with 435** an SMTP reply code. If not, 050 is assumed. 436** (others) -- sm_io_printf arguments 437** 438** Returns: 439** none 440** 441** Side Effects: 442** none. 443*/ 444 445/*VARARGS1*/ 446void 447#ifdef __STDC__ 448message(const char *msg, ...) 449#else /* __STDC__ */ 450message(msg, va_alist) 451 const char *msg; 452 va_dcl 453#endif /* __STDC__ */ 454{ 455 char *errtxt; 456 SM_VA_LOCAL_DECL 457 458 errno = 0; 459 SM_VA_START(ap, msg); 460 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap); 461 SM_VA_END(ap); 462 putoutmsg(MsgBuf, false, false); 463 464 /* save this message for mailq printing */ 465 switch (MsgBuf[0]) 466 { 467 case '4': 468 case '8': 469 if (CurEnv->e_message != NULL) 470 break; 471 /* FALLTHROUGH */ 472 473 case '5': 474 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 475 sm_free(CurEnv->e_message); 476 CurEnv->e_message = 477 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 478 break; 479 } 480} 481/* 482** NMESSAGE -- print message (not necessarily an error) 483** 484** Just like "message" except it never puts the to... tag on. 485** 486** Parameters: 487** msg -- the message (sm_io_printf fmt) -- if it begins 488** with a three digit SMTP reply code, that is used, 489** otherwise 050 is assumed. 490** (others) -- sm_io_printf arguments 491** 492** Returns: 493** none 494** 495** Side Effects: 496** none. 497*/ 498 499/*VARARGS1*/ 500void 501#ifdef __STDC__ 502nmessage(const char *msg, ...) 503#else /* __STDC__ */ 504nmessage(msg, va_alist) 505 const char *msg; 506 va_dcl 507#endif /* __STDC__ */ 508{ 509 char *errtxt; 510 SM_VA_LOCAL_DECL 511 512 errno = 0; 513 SM_VA_START(ap, msg); 514 errtxt = fmtmsg(MsgBuf, (char *) NULL, "050", 515 (char *) NULL, 0, msg, ap); 516 SM_VA_END(ap); 517 putoutmsg(MsgBuf, false, false); 518 519 /* save this message for mailq printing */ 520 switch (MsgBuf[0]) 521 { 522 case '4': 523 case '8': 524 if (CurEnv->e_message != NULL) 525 break; 526 /* FALLTHROUGH */ 527 528 case '5': 529 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 530 sm_free(CurEnv->e_message);
| 414 CurEnv->e_message = 415 sm_rpool_strdup_x(CurEnv->e_rpool, buf); 416 } 417 else 418 { 419 CurEnv->e_message = 420 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 421 } 422 break; 423 } 424 425 puterrmsg(MsgBuf); 426 if (LogLevel > 3 && LogUsrErrs) 427 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 428 if (QuickAbort) 429 sm_exc_raisenew_x(&EtypeQuickAbort, 1); 430} 431/* 432** MESSAGE -- print message (not necessarily an error) 433** 434** Parameters: 435** msg -- the message (sm_io_printf fmt) -- it can begin with 436** an SMTP reply code. If not, 050 is assumed. 437** (others) -- sm_io_printf arguments 438** 439** Returns: 440** none 441** 442** Side Effects: 443** none. 444*/ 445 446/*VARARGS1*/ 447void 448#ifdef __STDC__ 449message(const char *msg, ...) 450#else /* __STDC__ */ 451message(msg, va_alist) 452 const char *msg; 453 va_dcl 454#endif /* __STDC__ */ 455{ 456 char *errtxt; 457 SM_VA_LOCAL_DECL 458 459 errno = 0; 460 SM_VA_START(ap, msg); 461 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap); 462 SM_VA_END(ap); 463 putoutmsg(MsgBuf, false, false); 464 465 /* save this message for mailq printing */ 466 switch (MsgBuf[0]) 467 { 468 case '4': 469 case '8': 470 if (CurEnv->e_message != NULL) 471 break; 472 /* FALLTHROUGH */ 473 474 case '5': 475 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 476 sm_free(CurEnv->e_message); 477 CurEnv->e_message = 478 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 479 break; 480 } 481} 482/* 483** NMESSAGE -- print message (not necessarily an error) 484** 485** Just like "message" except it never puts the to... tag on. 486** 487** Parameters: 488** msg -- the message (sm_io_printf fmt) -- if it begins 489** with a three digit SMTP reply code, that is used, 490** otherwise 050 is assumed. 491** (others) -- sm_io_printf arguments 492** 493** Returns: 494** none 495** 496** Side Effects: 497** none. 498*/ 499 500/*VARARGS1*/ 501void 502#ifdef __STDC__ 503nmessage(const char *msg, ...) 504#else /* __STDC__ */ 505nmessage(msg, va_alist) 506 const char *msg; 507 va_dcl 508#endif /* __STDC__ */ 509{ 510 char *errtxt; 511 SM_VA_LOCAL_DECL 512 513 errno = 0; 514 SM_VA_START(ap, msg); 515 errtxt = fmtmsg(MsgBuf, (char *) NULL, "050", 516 (char *) NULL, 0, msg, ap); 517 SM_VA_END(ap); 518 putoutmsg(MsgBuf, false, false); 519 520 /* save this message for mailq printing */ 521 switch (MsgBuf[0]) 522 { 523 case '4': 524 case '8': 525 if (CurEnv->e_message != NULL) 526 break; 527 /* FALLTHROUGH */ 528 529 case '5': 530 if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 531 sm_free(CurEnv->e_message);
|
531 CurEnv->e_message = 532 sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
| 532 CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
|
533 break; 534 } 535} 536/* 537** PUTOUTMSG -- output error message to transcript and channel 538** 539** Parameters: 540** msg -- message to output (in SMTP format). 541** holdmsg -- if true, don't output a copy of the message to 542** our output channel. 543** heldmsg -- if true, this is a previously held message; 544** don't log it to the transcript file. 545** 546** Returns: 547** none. 548** 549** Side Effects: 550** Outputs msg to the transcript. 551** If appropriate, outputs it to the channel. 552** Deletes SMTP reply code number as appropriate. 553*/ 554 555static void 556putoutmsg(msg, holdmsg, heldmsg) 557 char *msg; 558 bool holdmsg; 559 bool heldmsg; 560{
| 533 break; 534 } 535} 536/* 537** PUTOUTMSG -- output error message to transcript and channel 538** 539** Parameters: 540** msg -- message to output (in SMTP format). 541** holdmsg -- if true, don't output a copy of the message to 542** our output channel. 543** heldmsg -- if true, this is a previously held message; 544** don't log it to the transcript file. 545** 546** Returns: 547** none. 548** 549** Side Effects: 550** Outputs msg to the transcript. 551** If appropriate, outputs it to the channel. 552** Deletes SMTP reply code number as appropriate. 553*/ 554 555static void 556putoutmsg(msg, holdmsg, heldmsg) 557 char *msg; 558 bool holdmsg; 559 bool heldmsg; 560{
|
561 char *errtxt = msg;
| |
562 char msgcode = msg[0];
| 561 char msgcode = msg[0];
|
| 562 char *errtxt = msg; 563 char *id;
|
563 564 /* display for debugging */ 565 if (tTd(54, 8)) 566 sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "", 567 heldmsg ? " (held)" : ""); 568 569 /* map warnings to something SMTP can handle */ 570 if (msgcode == '6') 571 msg[0] = '5'; 572 else if (msgcode == '8') 573 msg[0] = '4';
| 564 565 /* display for debugging */ 566 if (tTd(54, 8)) 567 sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "", 568 heldmsg ? " (held)" : ""); 569 570 /* map warnings to something SMTP can handle */ 571 if (msgcode == '6') 572 msg[0] = '5'; 573 else if (msgcode == '8') 574 msg[0] = '4';
|
| 575 id = (CurEnv != NULL) ? CurEnv->e_id : NULL;
|
574 575 /* output to transcript if serious */ 576 if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL && 577 strchr("45", msg[0]) != NULL) 578 (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n", 579 msg); 580 581 if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
| 576 577 /* output to transcript if serious */ 578 if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL && 579 strchr("45", msg[0]) != NULL) 580 (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n", 581 msg); 582 583 if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
|
582 sm_syslog(LOG_INFO, CurEnv->e_id,
| 584 sm_syslog(LOG_INFO, id,
|
583 "--- %s%s%s", msg, holdmsg ? " (hold)" : "", 584 heldmsg ? " (held)" : ""); 585 586 if (msgcode == '8') 587 msg[0] = '0'; 588 589 /* output to channel if appropriate */ 590 if (!Verbose && msg[0] == '0') 591 return; 592 if (holdmsg) 593 { 594 /* save for possible future display */ 595 msg[0] = msgcode; 596 if (HeldMessageBuf[0] == '5' && msgcode == '4') 597 return;
| 585 "--- %s%s%s", msg, holdmsg ? " (hold)" : "", 586 heldmsg ? " (held)" : ""); 587 588 if (msgcode == '8') 589 msg[0] = '0'; 590 591 /* output to channel if appropriate */ 592 if (!Verbose && msg[0] == '0') 593 return; 594 if (holdmsg) 595 { 596 /* save for possible future display */ 597 msg[0] = msgcode; 598 if (HeldMessageBuf[0] == '5' && msgcode == '4') 599 return;
|
598 (void) sm_strlcpy(HeldMessageBuf, msg, sizeof HeldMessageBuf);
| 600 (void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf));
|
599 return; 600 } 601 602 (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 603 604 if (OutChannel == NULL) 605 return; 606 607 /* find actual text of error (after SMTP status codes) */ 608 if (ISSMTPREPLY(errtxt)) 609 { 610 int l; 611 612 errtxt += 4; 613 l = isenhsc(errtxt, ' '); 614 if (l <= 0) 615 l = isenhsc(errtxt, '\0'); 616 if (l > 0) 617 errtxt += l + 1; 618 } 619 620 /* if DisConnected, OutChannel now points to the transcript */ 621 if (!DisConnected && 622 (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) 623 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n", 624 msg); 625 else 626 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n", 627 errtxt); 628 if (TrafficLogFile != NULL) 629 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 630 "%05d >>> %s\n", (int) CurrentPid, 631 (OpMode == MD_SMTP || OpMode == MD_DAEMON) 632 ? msg : errtxt); 633#if !PIPELINING 634 /* XXX can't flush here for SMTP pipelining */ 635 if (msg[3] == ' ') 636 (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 637 if (!sm_io_error(OutChannel) || DisConnected) 638 return; 639 640 /* 641 ** Error on output -- if reporting lost channel, just ignore it. 642 ** Also, ignore errors from QUIT response (221 message) -- some 643 ** rude servers don't read result. 644 */ 645 646 if (InChannel == NULL || sm_io_eof(InChannel) || 647 sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0) 648 return; 649 650 /* can't call syserr, 'cause we are using MsgBuf */ 651 HoldErrs = true; 652 if (LogLevel > 0)
| 601 return; 602 } 603 604 (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 605 606 if (OutChannel == NULL) 607 return; 608 609 /* find actual text of error (after SMTP status codes) */ 610 if (ISSMTPREPLY(errtxt)) 611 { 612 int l; 613 614 errtxt += 4; 615 l = isenhsc(errtxt, ' '); 616 if (l <= 0) 617 l = isenhsc(errtxt, '\0'); 618 if (l > 0) 619 errtxt += l + 1; 620 } 621 622 /* if DisConnected, OutChannel now points to the transcript */ 623 if (!DisConnected && 624 (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) 625 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n", 626 msg); 627 else 628 (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n", 629 errtxt); 630 if (TrafficLogFile != NULL) 631 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 632 "%05d >>> %s\n", (int) CurrentPid, 633 (OpMode == MD_SMTP || OpMode == MD_DAEMON) 634 ? msg : errtxt); 635#if !PIPELINING 636 /* XXX can't flush here for SMTP pipelining */ 637 if (msg[3] == ' ') 638 (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 639 if (!sm_io_error(OutChannel) || DisConnected) 640 return; 641 642 /* 643 ** Error on output -- if reporting lost channel, just ignore it. 644 ** Also, ignore errors from QUIT response (221 message) -- some 645 ** rude servers don't read result. 646 */ 647 648 if (InChannel == NULL || sm_io_eof(InChannel) || 649 sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0) 650 return; 651 652 /* can't call syserr, 'cause we are using MsgBuf */ 653 HoldErrs = true; 654 if (LogLevel > 0)
|
653 sm_syslog(LOG_CRIT, CurEnv->e_id,
| 655 sm_syslog(LOG_CRIT, id,
|
654 "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", 655 CURHOSTNAME, 656 shortenstring(msg, MAXSHORTSTR), sm_errstring(errno)); 657#endif /* !PIPELINING */ 658} 659/* 660** PUTERRMSG -- like putoutmsg, but does special processing for error messages 661** 662** Parameters: 663** msg -- the message to output. 664** 665** Returns: 666** none. 667** 668** Side Effects: 669** Sets the fatal error bit in the envelope as appropriate. 670*/ 671 672static void 673puterrmsg(msg) 674 char *msg; 675{ 676 char msgcode = msg[0]; 677 678 /* output the message as usual */ 679 putoutmsg(msg, HoldErrs, false); 680 681 /* be careful about multiple error messages */ 682 if (OnlyOneError) 683 HoldErrs = true; 684 685 /* signal the error */ 686 Errors++; 687 688 if (CurEnv == NULL) 689 return; 690 691 if (msgcode == '6') 692 { 693 /* notify the postmaster */ 694 CurEnv->e_flags |= EF_PM_NOTIFY; 695 } 696 else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 697 { 698 /* mark long-term fatal errors */ 699 CurEnv->e_flags |= EF_FATALERRS; 700 } 701} 702/* 703** ISENHSC -- check whether a string contains an enhanced status code 704** 705** Parameters: 706** s -- string with possible enhanced status code. 707** delim -- delim for enhanced status code. 708** 709** Returns: 710** 0 -- no enhanced status code. 711** >4 -- length of enhanced status code. 712** 713** Side Effects: 714** none. 715*/ 716int 717isenhsc(s, delim) 718 const char *s; 719 int delim; 720{ 721 int l, h; 722 723 if (s == NULL) 724 return 0; 725 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 726 return 0; 727 h = 0; 728 l = 2; 729 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 730 ++h; 731 if (h == 0 || s[l + h] != '.') 732 return 0; 733 l += h + 1; 734 h = 0; 735 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 736 ++h; 737 if (h == 0 || s[l + h] != delim) 738 return 0; 739 return l + h; 740} 741/* 742** EXTENHSC -- check and extract an enhanced status code 743** 744** Parameters: 745** s -- string with possible enhanced status code. 746** delim -- delim for enhanced status code. 747** e -- pointer to storage for enhanced status code. 748** must be != NULL and have space for at least 749** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3}) 750** 751** Returns: 752** 0 -- no enhanced status code. 753** >4 -- length of enhanced status code. 754** 755** Side Effects: 756** fills e with enhanced status code. 757*/ 758 759int 760extenhsc(s, delim, e) 761 const char *s; 762 int delim; 763 char *e; 764{ 765 int l, h; 766 767 if (s == NULL) 768 return 0; 769 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 770 return 0; 771 h = 0; 772 l = 2; 773 e[0] = s[0]; 774 e[1] = '.'; 775 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 776 { 777 e[l + h] = s[l + h]; 778 ++h; 779 } 780 if (h == 0 || s[l + h] != '.') 781 return 0; 782 e[l + h] = '.'; 783 l += h + 1; 784 h = 0; 785 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 786 { 787 e[l + h] = s[l + h]; 788 ++h; 789 } 790 if (h == 0 || s[l + h] != delim) 791 return 0; 792 e[l + h] = '\0'; 793 return l + h; 794} 795/* 796** FMTMSG -- format a message into buffer. 797** 798** Parameters: 799** eb -- error buffer to get result -- MUST BE MsgBuf. 800** to -- the recipient tag for this message. 801** num -- default three digit SMTP reply code. 802** enhsc -- enhanced status code. 803** en -- the error number to display. 804** fmt -- format of string. 805** ap -- arguments for fmt. 806** 807** Returns: 808** pointer to error text beyond status codes. 809** 810** Side Effects: 811** none. 812*/ 813 814static char * 815fmtmsg(eb, to, num, enhsc, eno, fmt, ap) 816 register char *eb; 817 const char *to; 818 const char *num; 819 const char *enhsc; 820 int eno; 821 const char *fmt; 822 SM_VA_LOCAL_DECL 823{ 824 char del; 825 int l;
| 656 "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", 657 CURHOSTNAME, 658 shortenstring(msg, MAXSHORTSTR), sm_errstring(errno)); 659#endif /* !PIPELINING */ 660} 661/* 662** PUTERRMSG -- like putoutmsg, but does special processing for error messages 663** 664** Parameters: 665** msg -- the message to output. 666** 667** Returns: 668** none. 669** 670** Side Effects: 671** Sets the fatal error bit in the envelope as appropriate. 672*/ 673 674static void 675puterrmsg(msg) 676 char *msg; 677{ 678 char msgcode = msg[0]; 679 680 /* output the message as usual */ 681 putoutmsg(msg, HoldErrs, false); 682 683 /* be careful about multiple error messages */ 684 if (OnlyOneError) 685 HoldErrs = true; 686 687 /* signal the error */ 688 Errors++; 689 690 if (CurEnv == NULL) 691 return; 692 693 if (msgcode == '6') 694 { 695 /* notify the postmaster */ 696 CurEnv->e_flags |= EF_PM_NOTIFY; 697 } 698 else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 699 { 700 /* mark long-term fatal errors */ 701 CurEnv->e_flags |= EF_FATALERRS; 702 } 703} 704/* 705** ISENHSC -- check whether a string contains an enhanced status code 706** 707** Parameters: 708** s -- string with possible enhanced status code. 709** delim -- delim for enhanced status code. 710** 711** Returns: 712** 0 -- no enhanced status code. 713** >4 -- length of enhanced status code. 714** 715** Side Effects: 716** none. 717*/ 718int 719isenhsc(s, delim) 720 const char *s; 721 int delim; 722{ 723 int l, h; 724 725 if (s == NULL) 726 return 0; 727 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 728 return 0; 729 h = 0; 730 l = 2; 731 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 732 ++h; 733 if (h == 0 || s[l + h] != '.') 734 return 0; 735 l += h + 1; 736 h = 0; 737 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 738 ++h; 739 if (h == 0 || s[l + h] != delim) 740 return 0; 741 return l + h; 742} 743/* 744** EXTENHSC -- check and extract an enhanced status code 745** 746** Parameters: 747** s -- string with possible enhanced status code. 748** delim -- delim for enhanced status code. 749** e -- pointer to storage for enhanced status code. 750** must be != NULL and have space for at least 751** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3}) 752** 753** Returns: 754** 0 -- no enhanced status code. 755** >4 -- length of enhanced status code. 756** 757** Side Effects: 758** fills e with enhanced status code. 759*/ 760 761int 762extenhsc(s, delim, e) 763 const char *s; 764 int delim; 765 char *e; 766{ 767 int l, h; 768 769 if (s == NULL) 770 return 0; 771 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 772 return 0; 773 h = 0; 774 l = 2; 775 e[0] = s[0]; 776 e[1] = '.'; 777 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 778 { 779 e[l + h] = s[l + h]; 780 ++h; 781 } 782 if (h == 0 || s[l + h] != '.') 783 return 0; 784 e[l + h] = '.'; 785 l += h + 1; 786 h = 0; 787 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 788 { 789 e[l + h] = s[l + h]; 790 ++h; 791 } 792 if (h == 0 || s[l + h] != delim) 793 return 0; 794 e[l + h] = '\0'; 795 return l + h; 796} 797/* 798** FMTMSG -- format a message into buffer. 799** 800** Parameters: 801** eb -- error buffer to get result -- MUST BE MsgBuf. 802** to -- the recipient tag for this message. 803** num -- default three digit SMTP reply code. 804** enhsc -- enhanced status code. 805** en -- the error number to display. 806** fmt -- format of string. 807** ap -- arguments for fmt. 808** 809** Returns: 810** pointer to error text beyond status codes. 811** 812** Side Effects: 813** none. 814*/ 815 816static char * 817fmtmsg(eb, to, num, enhsc, eno, fmt, ap) 818 register char *eb; 819 const char *to; 820 const char *num; 821 const char *enhsc; 822 int eno; 823 const char *fmt; 824 SM_VA_LOCAL_DECL 825{ 826 char del; 827 int l;
|
826 int spaceleft = sizeof MsgBuf;
| 828 int spaceleft = sizeof(MsgBuf);
|
827 char *errtxt; 828 829 /* output the reply code */ 830 if (ISSMTPCODE(fmt)) 831 { 832 num = fmt; 833 fmt += 4; 834 } 835 if (num[3] == '-') 836 del = '-'; 837 else 838 del = ' ';
| 829 char *errtxt; 830 831 /* output the reply code */ 832 if (ISSMTPCODE(fmt)) 833 { 834 num = fmt; 835 fmt += 4; 836 } 837 if (num[3] == '-') 838 del = '-'; 839 else 840 del = ' ';
|
839#if _FFR_SOFT_BOUNCE
| |
840 if (SoftBounce && num[0] == '5') 841 { 842 /* replace 5 by 4 */ 843 (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del); 844 } 845 else
| 841 if (SoftBounce && num[0] == '5') 842 { 843 /* replace 5 by 4 */ 844 (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del); 845 } 846 else
|
846#endif /* _FFR_SOFT_BOUNCE */ 847 (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
| 847 (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
|
848 eb += 4; 849 spaceleft -= 4; 850 851 if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4) 852 { 853 /* copy enh.status code including trailing blank */ 854 l++; 855 (void) sm_strlcpy(eb, fmt, l + 1); 856 eb += l; 857 spaceleft -= l; 858 fmt += l; 859 } 860 else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4) 861 { 862 /* copy enh.status code */ 863 (void) sm_strlcpy(eb, enhsc, l + 1); 864 eb[l] = ' '; 865 eb[++l] = '\0'; 866 eb += l; 867 spaceleft -= l; 868 }
| 848 eb += 4; 849 spaceleft -= 4; 850 851 if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4) 852 { 853 /* copy enh.status code including trailing blank */ 854 l++; 855 (void) sm_strlcpy(eb, fmt, l + 1); 856 eb += l; 857 spaceleft -= l; 858 fmt += l; 859 } 860 else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4) 861 { 862 /* copy enh.status code */ 863 (void) sm_strlcpy(eb, enhsc, l + 1); 864 eb[l] = ' '; 865 eb[++l] = '\0'; 866 eb += l; 867 spaceleft -= l; 868 }
|
869#if _FFR_SOFT_BOUNCE
| |
870 if (SoftBounce && eb[-l] == '5') 871 { 872 /* replace 5 by 4 */ 873 eb[-l] = '4'; 874 }
| 869 if (SoftBounce && eb[-l] == '5') 870 { 871 /* replace 5 by 4 */ 872 eb[-l] = '4'; 873 }
|
875#endif /* _FFR_SOFT_BOUNCE */
| |
876 errtxt = eb; 877 878 /* output the file name and line number */ 879 if (FileName != NULL) 880 { 881 (void) sm_snprintf(eb, spaceleft, "%s: line %d: ", 882 shortenstring(FileName, 83), LineNumber); 883 eb += (l = strlen(eb)); 884 spaceleft -= l; 885 } 886 887 /* 888 ** output the "to" address only if it is defined and one of the 889 ** following codes is used: 890 ** 050 internal notices, e.g., alias expansion 891 ** 250 Ok 892 ** 252 Cannot VRFY user, but will accept message and attempt delivery 893 ** 450 Requested mail action not taken: mailbox unavailable 894 ** 550 Requested action not taken: mailbox unavailable 895 ** 553 Requested action not taken: mailbox name not allowed 896 ** 897 ** Notice: this still isn't "the right thing", this code shouldn't 898 ** (indirectly) depend on CurEnv->e_to. 899 */ 900 901 if (to != NULL && to[0] != '\0' && 902 (strncmp(num, "050", 3) == 0 || 903 strncmp(num, "250", 3) == 0 || 904 strncmp(num, "252", 3) == 0 || 905 strncmp(num, "450", 3) == 0 || 906 strncmp(num, "550", 3) == 0 || 907 strncmp(num, "553", 3) == 0)) 908 { 909 (void) sm_strlcpyn(eb, spaceleft, 2, 910 shortenstring(to, MAXSHORTSTR), "... "); 911 spaceleft -= strlen(eb); 912 while (*eb != '\0') 913 *eb++ &= 0177; 914 } 915 916 /* output the message */ 917 (void) sm_vsnprintf(eb, spaceleft, fmt, ap); 918 spaceleft -= strlen(eb); 919 while (*eb != '\0') 920 *eb++ &= 0177; 921 922 /* output the error code, if any */ 923 if (eno != 0) 924 (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno)); 925 926 return errtxt; 927} 928/* 929** BUFFER_ERRORS -- arrange to buffer future error messages 930** 931** Parameters: 932** none 933** 934** Returns: 935** none. 936*/ 937 938void 939buffer_errors() 940{ 941 HeldMessageBuf[0] = '\0'; 942 HoldErrs = true; 943} 944/* 945** FLUSH_ERRORS -- flush the held error message buffer 946** 947** Parameters: 948** print -- if set, print the message, otherwise just 949** delete it. 950** 951** Returns: 952** none. 953*/ 954 955void 956flush_errors(print) 957 bool print; 958{ 959 if (print && HeldMessageBuf[0] != '\0') 960 putoutmsg(HeldMessageBuf, false, true); 961 HeldMessageBuf[0] = '\0'; 962 HoldErrs = false; 963} 964/* 965** SM_ERRSTRING -- return string description of error code 966** 967** Parameters: 968** errnum -- the error number to translate 969** 970** Returns: 971** A string description of errnum. 972** 973** Side Effects: 974** none. 975*/ 976 977const char * 978sm_errstring(errnum) 979 int errnum; 980{ 981 char *dnsmsg; 982 char *bp; 983 static char buf[MAXLINE]; 984#if HASSTRERROR 985 char *err; 986 char errbuf[30]; 987#endif /* HASSTRERROR */ 988#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 989 extern char *sys_errlist[]; 990 extern int sys_nerr; 991#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */ 992 993 /* 994 ** Handle special network error codes. 995 ** 996 ** These are 4.2/4.3bsd specific; they should be in daemon.c. 997 */ 998 999 dnsmsg = NULL; 1000 switch (errnum) 1001 { 1002 case ETIMEDOUT: 1003 case ECONNRESET: 1004 bp = buf; 1005#if HASSTRERROR 1006 err = strerror(errnum); 1007 if (err == NULL) 1008 {
| 874 errtxt = eb; 875 876 /* output the file name and line number */ 877 if (FileName != NULL) 878 { 879 (void) sm_snprintf(eb, spaceleft, "%s: line %d: ", 880 shortenstring(FileName, 83), LineNumber); 881 eb += (l = strlen(eb)); 882 spaceleft -= l; 883 } 884 885 /* 886 ** output the "to" address only if it is defined and one of the 887 ** following codes is used: 888 ** 050 internal notices, e.g., alias expansion 889 ** 250 Ok 890 ** 252 Cannot VRFY user, but will accept message and attempt delivery 891 ** 450 Requested mail action not taken: mailbox unavailable 892 ** 550 Requested action not taken: mailbox unavailable 893 ** 553 Requested action not taken: mailbox name not allowed 894 ** 895 ** Notice: this still isn't "the right thing", this code shouldn't 896 ** (indirectly) depend on CurEnv->e_to. 897 */ 898 899 if (to != NULL && to[0] != '\0' && 900 (strncmp(num, "050", 3) == 0 || 901 strncmp(num, "250", 3) == 0 || 902 strncmp(num, "252", 3) == 0 || 903 strncmp(num, "450", 3) == 0 || 904 strncmp(num, "550", 3) == 0 || 905 strncmp(num, "553", 3) == 0)) 906 { 907 (void) sm_strlcpyn(eb, spaceleft, 2, 908 shortenstring(to, MAXSHORTSTR), "... "); 909 spaceleft -= strlen(eb); 910 while (*eb != '\0') 911 *eb++ &= 0177; 912 } 913 914 /* output the message */ 915 (void) sm_vsnprintf(eb, spaceleft, fmt, ap); 916 spaceleft -= strlen(eb); 917 while (*eb != '\0') 918 *eb++ &= 0177; 919 920 /* output the error code, if any */ 921 if (eno != 0) 922 (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno)); 923 924 return errtxt; 925} 926/* 927** BUFFER_ERRORS -- arrange to buffer future error messages 928** 929** Parameters: 930** none 931** 932** Returns: 933** none. 934*/ 935 936void 937buffer_errors() 938{ 939 HeldMessageBuf[0] = '\0'; 940 HoldErrs = true; 941} 942/* 943** FLUSH_ERRORS -- flush the held error message buffer 944** 945** Parameters: 946** print -- if set, print the message, otherwise just 947** delete it. 948** 949** Returns: 950** none. 951*/ 952 953void 954flush_errors(print) 955 bool print; 956{ 957 if (print && HeldMessageBuf[0] != '\0') 958 putoutmsg(HeldMessageBuf, false, true); 959 HeldMessageBuf[0] = '\0'; 960 HoldErrs = false; 961} 962/* 963** SM_ERRSTRING -- return string description of error code 964** 965** Parameters: 966** errnum -- the error number to translate 967** 968** Returns: 969** A string description of errnum. 970** 971** Side Effects: 972** none. 973*/ 974 975const char * 976sm_errstring(errnum) 977 int errnum; 978{ 979 char *dnsmsg; 980 char *bp; 981 static char buf[MAXLINE]; 982#if HASSTRERROR 983 char *err; 984 char errbuf[30]; 985#endif /* HASSTRERROR */ 986#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 987 extern char *sys_errlist[]; 988 extern int sys_nerr; 989#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */ 990 991 /* 992 ** Handle special network error codes. 993 ** 994 ** These are 4.2/4.3bsd specific; they should be in daemon.c. 995 */ 996 997 dnsmsg = NULL; 998 switch (errnum) 999 { 1000 case ETIMEDOUT: 1001 case ECONNRESET: 1002 bp = buf; 1003#if HASSTRERROR 1004 err = strerror(errnum); 1005 if (err == NULL) 1006 {
|
1009 (void) sm_snprintf(errbuf, sizeof errbuf,
| 1007 (void) sm_snprintf(errbuf, sizeof(errbuf),
|
1010 "Error %d", errnum); 1011 err = errbuf; 1012 } 1013 (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp)); 1014#else /* HASSTRERROR */ 1015 if (errnum >= 0 && errnum < sys_nerr) 1016 (void) sm_strlcpy(bp, sys_errlist[errnum], 1017 SPACELEFT(buf, bp)); 1018 else 1019 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1020 "Error %d", errnum); 1021#endif /* HASSTRERROR */ 1022 bp += strlen(bp); 1023 if (CurHostName != NULL) 1024 { 1025 if (errnum == ETIMEDOUT) 1026 { 1027 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1028 " with "); 1029 bp += strlen(bp); 1030 } 1031 else 1032 { 1033 bp = buf; 1034 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1035 "Connection reset by "); 1036 bp += strlen(bp); 1037 } 1038 (void) sm_strlcpy(bp, 1039 shortenstring(CurHostName, MAXSHORTSTR), 1040 SPACELEFT(buf, bp)); 1041 bp += strlen(buf); 1042 } 1043 if (SmtpPhase != NULL) 1044 { 1045 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1046 " during %s", SmtpPhase); 1047 } 1048 return buf; 1049 1050 case EHOSTDOWN: 1051 if (CurHostName == NULL) 1052 break;
| 1008 "Error %d", errnum); 1009 err = errbuf; 1010 } 1011 (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp)); 1012#else /* HASSTRERROR */ 1013 if (errnum >= 0 && errnum < sys_nerr) 1014 (void) sm_strlcpy(bp, sys_errlist[errnum], 1015 SPACELEFT(buf, bp)); 1016 else 1017 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1018 "Error %d", errnum); 1019#endif /* HASSTRERROR */ 1020 bp += strlen(bp); 1021 if (CurHostName != NULL) 1022 { 1023 if (errnum == ETIMEDOUT) 1024 { 1025 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1026 " with "); 1027 bp += strlen(bp); 1028 } 1029 else 1030 { 1031 bp = buf; 1032 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1033 "Connection reset by "); 1034 bp += strlen(bp); 1035 } 1036 (void) sm_strlcpy(bp, 1037 shortenstring(CurHostName, MAXSHORTSTR), 1038 SPACELEFT(buf, bp)); 1039 bp += strlen(buf); 1040 } 1041 if (SmtpPhase != NULL) 1042 { 1043 (void) sm_snprintf(bp, SPACELEFT(buf, bp), 1044 " during %s", SmtpPhase); 1045 } 1046 return buf; 1047 1048 case EHOSTDOWN: 1049 if (CurHostName == NULL) 1050 break;
|
1053 (void) sm_snprintf(buf, sizeof buf, "Host %s is down",
| 1051 (void) sm_snprintf(buf, sizeof(buf), "Host %s is down",
|
1054 shortenstring(CurHostName, MAXSHORTSTR)); 1055 return buf; 1056 1057 case ECONNREFUSED: 1058 if (CurHostName == NULL) 1059 break;
| 1052 shortenstring(CurHostName, MAXSHORTSTR)); 1053 return buf; 1054 1055 case ECONNREFUSED: 1056 if (CurHostName == NULL) 1057 break;
|
1060 (void) sm_strlcpyn(buf, sizeof buf, 2, "Connection refused by ",
| 1058 (void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ",
|
1061 shortenstring(CurHostName, MAXSHORTSTR)); 1062 return buf; 1063 1064#if NAMED_BIND 1065 case HOST_NOT_FOUND + E_DNSBASE: 1066 dnsmsg = "host not found"; 1067 break; 1068 1069 case TRY_AGAIN + E_DNSBASE: 1070 dnsmsg = "host name lookup failure"; 1071 break; 1072 1073 case NO_RECOVERY + E_DNSBASE: 1074 dnsmsg = "non-recoverable error"; 1075 break; 1076 1077 case NO_DATA + E_DNSBASE: 1078 dnsmsg = "no data known"; 1079 break; 1080#endif /* NAMED_BIND */ 1081 1082 case EPERM: 1083 /* SunOS gives "Not owner" -- this is the POSIX message */ 1084 return "Operation not permitted"; 1085 1086 /* 1087 ** Error messages used internally in sendmail. 1088 */ 1089 1090 case E_SM_OPENTIMEOUT: 1091 return "Timeout on file open"; 1092 1093 case E_SM_NOSLINK: 1094 return "Symbolic links not allowed"; 1095 1096 case E_SM_NOHLINK: 1097 return "Hard links not allowed"; 1098 1099 case E_SM_REGONLY: 1100 return "Regular files only"; 1101 1102 case E_SM_ISEXEC: 1103 return "Executable files not allowed"; 1104 1105 case E_SM_WWDIR: 1106 return "World writable directory"; 1107 1108 case E_SM_GWDIR: 1109 return "Group writable directory"; 1110 1111 case E_SM_FILECHANGE: 1112 return "File changed after open"; 1113 1114 case E_SM_WWFILE: 1115 return "World writable file"; 1116 1117 case E_SM_GWFILE: 1118 return "Group writable file"; 1119 1120 case E_SM_GRFILE: 1121 return "Group readable file"; 1122 1123 case E_SM_WRFILE: 1124 return "World readable file"; 1125 } 1126 1127 if (dnsmsg != NULL) 1128 { 1129 bp = buf;
| 1059 shortenstring(CurHostName, MAXSHORTSTR)); 1060 return buf; 1061 1062#if NAMED_BIND 1063 case HOST_NOT_FOUND + E_DNSBASE: 1064 dnsmsg = "host not found"; 1065 break; 1066 1067 case TRY_AGAIN + E_DNSBASE: 1068 dnsmsg = "host name lookup failure"; 1069 break; 1070 1071 case NO_RECOVERY + E_DNSBASE: 1072 dnsmsg = "non-recoverable error"; 1073 break; 1074 1075 case NO_DATA + E_DNSBASE: 1076 dnsmsg = "no data known"; 1077 break; 1078#endif /* NAMED_BIND */ 1079 1080 case EPERM: 1081 /* SunOS gives "Not owner" -- this is the POSIX message */ 1082 return "Operation not permitted"; 1083 1084 /* 1085 ** Error messages used internally in sendmail. 1086 */ 1087 1088 case E_SM_OPENTIMEOUT: 1089 return "Timeout on file open"; 1090 1091 case E_SM_NOSLINK: 1092 return "Symbolic links not allowed"; 1093 1094 case E_SM_NOHLINK: 1095 return "Hard links not allowed"; 1096 1097 case E_SM_REGONLY: 1098 return "Regular files only"; 1099 1100 case E_SM_ISEXEC: 1101 return "Executable files not allowed"; 1102 1103 case E_SM_WWDIR: 1104 return "World writable directory"; 1105 1106 case E_SM_GWDIR: 1107 return "Group writable directory"; 1108 1109 case E_SM_FILECHANGE: 1110 return "File changed after open"; 1111 1112 case E_SM_WWFILE: 1113 return "World writable file"; 1114 1115 case E_SM_GWFILE: 1116 return "Group writable file"; 1117 1118 case E_SM_GRFILE: 1119 return "Group readable file"; 1120 1121 case E_SM_WRFILE: 1122 return "World readable file"; 1123 } 1124 1125 if (dnsmsg != NULL) 1126 { 1127 bp = buf;
|
1130 bp += sm_strlcpy(bp, "Name server: ", sizeof buf);
| 1128 bp += sm_strlcpy(bp, "Name server: ", sizeof(buf));
|
1131 if (CurHostName != NULL) 1132 { 1133 (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, 1134 shortenstring(CurHostName, MAXSHORTSTR), ": "); 1135 bp += strlen(bp); 1136 } 1137 (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp)); 1138 return buf; 1139 } 1140 1141#if LDAPMAP 1142 if (errnum >= E_LDAPBASE) 1143 return ldap_err2string(errnum - E_LDAPBASE); 1144#endif /* LDAPMAP */ 1145 1146#if HASSTRERROR 1147 err = strerror(errnum); 1148 if (err == NULL) 1149 {
| 1129 if (CurHostName != NULL) 1130 { 1131 (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, 1132 shortenstring(CurHostName, MAXSHORTSTR), ": "); 1133 bp += strlen(bp); 1134 } 1135 (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp)); 1136 return buf; 1137 } 1138 1139#if LDAPMAP 1140 if (errnum >= E_LDAPBASE) 1141 return ldap_err2string(errnum - E_LDAPBASE); 1142#endif /* LDAPMAP */ 1143 1144#if HASSTRERROR 1145 err = strerror(errnum); 1146 if (err == NULL) 1147 {
|
1150 (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
| 1148 (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
|
1151 return buf; 1152 } 1153 return err; 1154#else /* HASSTRERROR */ 1155 if (errnum > 0 && errnum < sys_nerr) 1156 return sys_errlist[errnum]; 1157
| 1149 return buf; 1150 } 1151 return err; 1152#else /* HASSTRERROR */ 1153 if (errnum > 0 && errnum < sys_nerr) 1154 return sys_errlist[errnum]; 1155
|
1158 (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
| 1156 (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum);
|
1159 return buf; 1160#endif /* HASSTRERROR */ 1161}
| 1157 return buf; 1158#endif /* HASSTRERROR */ 1159}
|