1 /* 2 * Copyright (c) 1998-2002 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 */ 13 14 #include <sendmail.h> 15 16 SM_RCSID("@(#)$Id: conf.c,v 8.939 2002/01/09 17:26:28 gshapiro Exp $") 17 18 /* $FreeBSD$ */ 19 20 #include <sendmail/pathnames.h> 21 22 # include <sys/ioctl.h> 23 # include <sys/param.h> 24 25 #include <limits.h> 26 #if NETINET || NETINET6 27 # include <arpa/inet.h> 28 #endif /* NETINET || NETINET6 */ 29 #if HASULIMIT && defined(HPUX11) 30 # include <ulimit.h> 31 #endif /* HASULIMIT && defined(HPUX11) */ 32 33 34 static void setupmaps __P((void)); 35 static void setupmailers __P((void)); 36 static void setupqueues __P((void)); 37 static int get_num_procs_online __P((void)); 38 39 40 /* 41 ** CONF.C -- Sendmail Configuration Tables. 42 ** 43 ** Defines the configuration of this installation. 44 ** 45 ** Configuration Variables: 46 ** HdrInfo -- a table describing well-known header fields. 47 ** Each entry has the field name and some flags, 48 ** which are described in sendmail.h. 49 ** 50 ** Notes: 51 ** I have tried to put almost all the reasonable 52 ** configuration information into the configuration 53 ** file read at runtime. My intent is that anything 54 ** here is a function of the version of UNIX you 55 ** are running, or is really static -- for example 56 ** the headers are a superset of widely used 57 ** protocols. If you find yourself playing with 58 ** this file too much, you may be making a mistake! 59 */ 60 61 62 /* 63 ** Header info table 64 ** Final (null) entry contains the flags used for any other field. 65 ** 66 ** Not all of these are actually handled specially by sendmail 67 ** at this time. They are included as placeholders, to let 68 ** you know that "someday" I intend to have sendmail do 69 ** something with them. 70 */ 71 72 struct hdrinfo HdrInfo[] = 73 { 74 /* originator fields, most to least significant */ 75 { "resent-sender", H_FROM|H_RESENT, NULL }, 76 { "resent-from", H_FROM|H_RESENT, NULL }, 77 { "resent-reply-to", H_FROM|H_RESENT, NULL }, 78 { "sender", H_FROM, NULL }, 79 { "from", H_FROM, NULL }, 80 { "reply-to", H_FROM, NULL }, 81 { "errors-to", H_FROM|H_ERRORSTO, NULL }, 82 { "full-name", H_ACHECK, NULL }, 83 { "return-receipt-to", H_RECEIPTTO, NULL }, 84 { "disposition-notification-to", H_FROM, NULL }, 85 86 /* destination fields */ 87 { "to", H_RCPT, NULL }, 88 { "resent-to", H_RCPT|H_RESENT, NULL }, 89 { "cc", H_RCPT, NULL }, 90 { "resent-cc", H_RCPT|H_RESENT, NULL }, 91 { "bcc", H_RCPT|H_BCC, NULL }, 92 { "resent-bcc", H_RCPT|H_BCC|H_RESENT, NULL }, 93 { "apparently-to", H_RCPT, NULL }, 94 95 /* message identification and control */ 96 { "message-id", 0, NULL }, 97 { "resent-message-id", H_RESENT, NULL }, 98 { "message", H_EOH, NULL }, 99 { "text", H_EOH, NULL }, 100 101 /* date fields */ 102 { "date", 0, NULL }, 103 { "resent-date", H_RESENT, NULL }, 104 105 /* trace fields */ 106 { "received", H_TRACE|H_FORCE, NULL }, 107 { "x400-received", H_TRACE|H_FORCE, NULL }, 108 { "via", H_TRACE|H_FORCE, NULL }, 109 { "mail-from", H_TRACE|H_FORCE, NULL }, 110 111 /* miscellaneous fields */ 112 { "comments", H_FORCE|H_ENCODABLE, NULL }, 113 { "return-path", H_FORCE|H_ACHECK|H_BINDLATE, NULL }, 114 { "content-transfer-encoding", H_CTE, NULL }, 115 { "content-type", H_CTYPE, NULL }, 116 { "content-length", H_ACHECK, NULL }, 117 { "subject", H_ENCODABLE, NULL }, 118 { "x-authentication-warning", H_FORCE, NULL }, 119 120 { NULL, 0, NULL } 121 }; 122 123 124 125 /* 126 ** Privacy values 127 */ 128 129 struct prival PrivacyValues[] = 130 { 131 { "public", PRIV_PUBLIC }, 132 { "needmailhelo", PRIV_NEEDMAILHELO }, 133 { "needexpnhelo", PRIV_NEEDEXPNHELO }, 134 { "needvrfyhelo", PRIV_NEEDVRFYHELO }, 135 { "noexpn", PRIV_NOEXPN }, 136 { "novrfy", PRIV_NOVRFY }, 137 { "restrictexpand", PRIV_RESTRICTEXPAND }, 138 { "restrictmailq", PRIV_RESTRICTMAILQ }, 139 { "restrictqrun", PRIV_RESTRICTQRUN }, 140 { "noetrn", PRIV_NOETRN }, 141 { "noverb", PRIV_NOVERB }, 142 { "authwarnings", PRIV_AUTHWARNINGS }, 143 { "noreceipts", PRIV_NORECEIPTS }, 144 { "nobodyreturn", PRIV_NOBODYRETN }, 145 { "goaway", PRIV_GOAWAY }, 146 { NULL, 0 } 147 }; 148 149 /* 150 ** DontBlameSendmail values 151 */ 152 153 struct dbsval DontBlameSendmailValues[] = 154 { 155 { "safe", DBS_SAFE }, 156 { "assumesafechown", DBS_ASSUMESAFECHOWN }, 157 { "groupwritabledirpathsafe", DBS_GROUPWRITABLEDIRPATHSAFE }, 158 { "groupwritableforwardfilesafe", 159 DBS_GROUPWRITABLEFORWARDFILESAFE }, 160 { "groupwritableincludefilesafe", 161 DBS_GROUPWRITABLEINCLUDEFILESAFE }, 162 { "groupwritablealiasfile", DBS_GROUPWRITABLEALIASFILE }, 163 { "worldwritablealiasfile", DBS_WORLDWRITABLEALIASFILE }, 164 { "forwardfileinunsafedirpath", DBS_FORWARDFILEINUNSAFEDIRPATH }, 165 { "includefileinunsafedirpath", DBS_INCLUDEFILEINUNSAFEDIRPATH }, 166 { "mapinunsafedirpath", DBS_MAPINUNSAFEDIRPATH }, 167 { "linkedaliasfileinwritabledir", 168 DBS_LINKEDALIASFILEINWRITABLEDIR }, 169 { "linkedclassfileinwritabledir", 170 DBS_LINKEDCLASSFILEINWRITABLEDIR }, 171 { "linkedforwardfileinwritabledir", 172 DBS_LINKEDFORWARDFILEINWRITABLEDIR }, 173 { "linkedincludefileinwritabledir", 174 DBS_LINKEDINCLUDEFILEINWRITABLEDIR }, 175 { "linkedmapinwritabledir", DBS_LINKEDMAPINWRITABLEDIR }, 176 { "linkedserviceswitchfileinwritabledir", 177 DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR }, 178 { "filedeliverytohardlink", DBS_FILEDELIVERYTOHARDLINK }, 179 { "filedeliverytosymlink", DBS_FILEDELIVERYTOSYMLINK }, 180 { "writemaptohardlink", DBS_WRITEMAPTOHARDLINK }, 181 { "writemaptosymlink", DBS_WRITEMAPTOSYMLINK }, 182 { "writestatstohardlink", DBS_WRITESTATSTOHARDLINK }, 183 { "writestatstosymlink", DBS_WRITESTATSTOSYMLINK }, 184 { "forwardfileingroupwritabledirpath", 185 DBS_FORWARDFILEINGROUPWRITABLEDIRPATH }, 186 { "includefileingroupwritabledirpath", 187 DBS_INCLUDEFILEINGROUPWRITABLEDIRPATH }, 188 { "classfileinunsafedirpath", DBS_CLASSFILEINUNSAFEDIRPATH }, 189 { "errorheaderinunsafedirpath", DBS_ERRORHEADERINUNSAFEDIRPATH }, 190 { "helpfileinunsafedirpath", DBS_HELPFILEINUNSAFEDIRPATH }, 191 { "forwardfileinunsafedirpathsafe", 192 DBS_FORWARDFILEINUNSAFEDIRPATHSAFE }, 193 { "includefileinunsafedirpathsafe", 194 DBS_INCLUDEFILEINUNSAFEDIRPATHSAFE }, 195 { "runprograminunsafedirpath", DBS_RUNPROGRAMINUNSAFEDIRPATH }, 196 { "runwritableprogram", DBS_RUNWRITABLEPROGRAM }, 197 { "nonrootsafeaddr", DBS_NONROOTSAFEADDR }, 198 { "truststickybit", DBS_TRUSTSTICKYBIT }, 199 { "dontwarnforwardfileinunsafedirpath", 200 DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH }, 201 { "insufficiententropy", DBS_INSUFFICIENTENTROPY }, 202 { "groupreadablesasldbfile", DBS_GROUPREADABLESASLDBFILE }, 203 { "groupwritablesasldbfile", DBS_GROUPWRITABLESASLDBFILE }, 204 { "groupwritableforwardfile", DBS_GROUPWRITABLEFORWARDFILE }, 205 { "groupwritableincludefile", DBS_GROUPWRITABLEINCLUDEFILE }, 206 { "worldwritableforwardfile", DBS_WORLDWRITABLEFORWARDFILE }, 207 { "worldwritableincludefile", DBS_WORLDWRITABLEINCLUDEFILE }, 208 { "groupreadablekeyfile", DBS_GROUPREADABLEKEYFILE }, 209 #if _FFR_GROUPREADABLEAUTHINFOFILE 210 { "groupreadableadefaultauthinfofile", 211 DBS_GROUPREADABLEAUTHINFOFILE }, 212 #endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ 213 { NULL, 0 } 214 }; 215 216 /* 217 ** Miscellaneous stuff. 218 */ 219 220 int DtableSize = 50; /* max open files; reset in 4.2bsd */ 221 /* 222 ** SETDEFAULTS -- set default values 223 ** 224 ** Some of these must be initialized using direct code since they 225 ** depend on run-time values. So let's do all of them this way. 226 ** 227 ** Parameters: 228 ** e -- the default envelope. 229 ** 230 ** Returns: 231 ** none. 232 ** 233 ** Side Effects: 234 ** Initializes a bunch of global variables to their 235 ** default values. 236 */ 237 238 #define MINUTES * 60 239 #define HOURS * 60 MINUTES 240 #define DAYS * 24 HOURS 241 242 #ifndef MAXRULERECURSION 243 # define MAXRULERECURSION 50 /* max ruleset recursion depth */ 244 #endif /* ! MAXRULERECURSION */ 245 246 void 247 setdefaults(e) 248 register ENVELOPE *e; 249 { 250 int i; 251 int numprocs; 252 struct passwd *pw; 253 254 numprocs = get_num_procs_online(); 255 SpaceSub = ' '; /* option B */ 256 QueueLA = 8 * numprocs; /* option x */ 257 RefuseLA = 12 * numprocs; /* option X */ 258 WkRecipFact = 30000L; /* option y */ 259 WkClassFact = 1800L; /* option z */ 260 WkTimeFact = 90000L; /* option Z */ 261 QueueFactor = WkRecipFact * 20; /* option q */ 262 #if _FFR_QUARANTINE 263 QueueMode = QM_NORMAL; /* what queue items to act upon */ 264 #endif /* _FFR_QUARANTINE */ 265 FileMode = (RealUid != geteuid()) ? 0644 : 0600; 266 /* option F */ 267 QueueFileMode = (RealUid != geteuid()) ? 0644 : 0600; 268 /* option QueueFileMode */ 269 270 if (((pw = sm_getpwnam("mailnull")) != NULL && pw->pw_uid != 0) || 271 ((pw = sm_getpwnam("sendmail")) != NULL && pw->pw_uid != 0) || 272 ((pw = sm_getpwnam("daemon")) != NULL && pw->pw_uid != 0)) 273 { 274 DefUid = pw->pw_uid; /* option u */ 275 DefGid = pw->pw_gid; /* option g */ 276 DefUser = newstr(pw->pw_name); 277 } 278 else 279 { 280 DefUid = 1; /* option u */ 281 DefGid = 1; /* option g */ 282 setdefuser(); 283 } 284 TrustedUid = 0; 285 if (tTd(37, 4)) 286 sm_dprintf("setdefaults: DefUser=%s, DefUid=%d, DefGid=%d\n", 287 DefUser != NULL ? DefUser : "<1:1>", 288 (int) DefUid, (int) DefGid); 289 CheckpointInterval = 10; /* option C */ 290 MaxHopCount = 25; /* option h */ 291 set_delivery_mode(SM_FORK, e); /* option d */ 292 e->e_errormode = EM_PRINT; /* option e */ 293 e->e_qgrp = NOQGRP; 294 e->e_qdir = NOQDIR; 295 e->e_xfqgrp = NOQGRP; 296 e->e_xfqdir = NOQDIR; 297 e->e_ctime = curtime(); 298 SevenBitInput = false; /* option 7 */ 299 MaxMciCache = 1; /* option k */ 300 MciCacheTimeout = 5 MINUTES; /* option K */ 301 LogLevel = 9; /* option L */ 302 #if MILTER 303 MilterLogLevel = -1; 304 #endif /* MILTER */ 305 inittimeouts(NULL, false); /* option r */ 306 PrivacyFlags = PRIV_PUBLIC; /* option p */ 307 MeToo = true; /* option m */ 308 SendMIMEErrors = true; /* option f */ 309 SuperSafe = SAFE_REALLY; /* option s */ 310 clrbitmap(DontBlameSendmail); /* DontBlameSendmail option */ 311 #if MIME8TO7 312 MimeMode = MM_CVTMIME|MM_PASS8BIT; /* option 8 */ 313 #else /* MIME8TO7 */ 314 MimeMode = MM_PASS8BIT; 315 #endif /* MIME8TO7 */ 316 for (i = 0; i < MAXTOCLASS; i++) 317 { 318 TimeOuts.to_q_return[i] = 5 DAYS; /* option T */ 319 TimeOuts.to_q_warning[i] = 0; /* option T */ 320 } 321 ServiceSwitchFile = "/etc/mail/service.switch"; 322 ServiceCacheMaxAge = (time_t) 10; 323 HostsFile = _PATH_HOSTS; 324 PidFile = newstr(_PATH_SENDMAILPID); 325 MustQuoteChars = "@,;:\\()[].'"; 326 MciInfoTimeout = 30 MINUTES; 327 MaxRuleRecursion = MAXRULERECURSION; 328 MaxAliasRecursion = 10; 329 MaxMacroRecursion = 10; 330 ColonOkInAddr = true; 331 DontLockReadFiles = true; 332 DontProbeInterfaces = DPI_PROBEALL; 333 DoubleBounceAddr = "postmaster"; 334 MaxHeadersLength = MAXHDRSLEN; 335 MaxForwardEntries = 0; 336 FastSplit = 1; 337 #if SASL 338 AuthMechanisms = newstr(AUTH_MECHANISMS); 339 MaxSLBits = INT_MAX; 340 #endif /* SASL */ 341 #if STARTTLS 342 TLS_Srv_Opts = TLS_I_SRV; 343 #endif /* STARTTLS */ 344 #ifdef HESIOD_INIT 345 HesiodContext = NULL; 346 #endif /* HESIOD_INIT */ 347 #if NETINET6 348 /* Detect if IPv6 is available at run time */ 349 i = socket(AF_INET6, SOCK_STREAM, 0); 350 if (i >= 0) 351 { 352 InetMode = AF_INET6; 353 (void) close(i); 354 } 355 else 356 InetMode = AF_INET; 357 #else /* NETINET6 */ 358 InetMode = AF_INET; 359 #endif /* NETINET6 */ 360 ControlSocketName = NULL; 361 memset(&ConnectOnlyTo, '\0', sizeof ConnectOnlyTo); 362 DataFileBufferSize = 4096; 363 XscriptFileBufferSize = 4096; 364 for (i = 0; i < MAXRWSETS; i++) 365 RuleSetNames[i] = NULL; 366 #if MILTER 367 InputFilters[0] = NULL; 368 #endif /* MILTER */ 369 setupmaps(); 370 setupqueues(); 371 setupmailers(); 372 setupheaders(); 373 } 374 375 376 /* 377 ** SETDEFUSER -- set/reset DefUser using DefUid (for initgroups()) 378 */ 379 380 void 381 setdefuser() 382 { 383 struct passwd *defpwent; 384 static char defuserbuf[40]; 385 386 DefUser = defuserbuf; 387 defpwent = sm_getpwuid(DefUid); 388 (void) sm_strlcpy(defuserbuf, 389 (defpwent == NULL || defpwent->pw_name == NULL) 390 ? "nobody" : defpwent->pw_name, 391 sizeof defuserbuf); 392 if (tTd(37, 4)) 393 sm_dprintf("setdefuser: DefUid=%d, DefUser=%s\n", 394 (int) DefUid, DefUser); 395 } 396 /* 397 ** SETUPQUEUES -- initialize default queues 398 ** 399 ** The mqueue QUEUE structure gets filled in after readcf() but 400 ** we need something to point to now for the mailer setup, 401 ** which use "mqueue" as default queue. 402 */ 403 404 static void 405 setupqueues() 406 { 407 char buf[100]; 408 409 MaxRunnersPerQueue = 1; 410 (void) sm_strlcpy(buf, "mqueue, P=/var/spool/mqueue", sizeof buf); 411 makequeue(buf, false); 412 } 413 /* 414 ** SETUPMAILERS -- initialize default mailers 415 */ 416 417 static void 418 setupmailers() 419 { 420 char buf[100]; 421 422 (void) sm_strlcpy(buf, "prog, P=/bin/sh, F=lsouDq9, T=X-Unix/X-Unix/X-Unix, A=sh -c \201u", 423 sizeof buf); 424 makemailer(buf); 425 426 (void) sm_strlcpy(buf, "*file*, P=[FILE], F=lsDFMPEouq9, T=X-Unix/X-Unix/X-Unix, A=FILE \201u", 427 sizeof buf); 428 makemailer(buf); 429 430 (void) sm_strlcpy(buf, "*include*, P=/dev/null, F=su, A=INCLUDE \201u", 431 sizeof buf); 432 makemailer(buf); 433 initerrmailers(); 434 } 435 /* 436 ** SETUPMAPS -- set up map classes 437 */ 438 439 #define MAPDEF(name, ext, flags, parse, open, close, lookup, store) \ 440 { \ 441 extern bool parse __P((MAP *, char *)); \ 442 extern bool open __P((MAP *, int)); \ 443 extern void close __P((MAP *)); \ 444 extern char *lookup __P((MAP *, char *, char **, int *)); \ 445 extern void store __P((MAP *, char *, char *)); \ 446 s = stab(name, ST_MAPCLASS, ST_ENTER); \ 447 s->s_mapclass.map_cname = name; \ 448 s->s_mapclass.map_ext = ext; \ 449 s->s_mapclass.map_cflags = flags; \ 450 s->s_mapclass.map_parse = parse; \ 451 s->s_mapclass.map_open = open; \ 452 s->s_mapclass.map_close = close; \ 453 s->s_mapclass.map_lookup = lookup; \ 454 s->s_mapclass.map_store = store; \ 455 } 456 457 static void 458 setupmaps() 459 { 460 register STAB *s; 461 462 #if NEWDB 463 MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 464 map_parseargs, hash_map_open, db_map_close, 465 db_map_lookup, db_map_store); 466 467 MAPDEF("btree", ".db", MCF_ALIASOK|MCF_REBUILDABLE, 468 map_parseargs, bt_map_open, db_map_close, 469 db_map_lookup, db_map_store); 470 #endif /* NEWDB */ 471 472 #if NDBM 473 MAPDEF("dbm", ".dir", MCF_ALIASOK|MCF_REBUILDABLE, 474 map_parseargs, ndbm_map_open, ndbm_map_close, 475 ndbm_map_lookup, ndbm_map_store); 476 #endif /* NDBM */ 477 478 #if NIS 479 MAPDEF("nis", NULL, MCF_ALIASOK, 480 map_parseargs, nis_map_open, null_map_close, 481 nis_map_lookup, null_map_store); 482 #endif /* NIS */ 483 484 #if NISPLUS 485 MAPDEF("nisplus", NULL, MCF_ALIASOK, 486 map_parseargs, nisplus_map_open, null_map_close, 487 nisplus_map_lookup, null_map_store); 488 #endif /* NISPLUS */ 489 490 #if LDAPMAP 491 MAPDEF("ldap", NULL, MCF_ALIASOK|MCF_NOTPERSIST, 492 ldapmap_parseargs, ldapmap_open, ldapmap_close, 493 ldapmap_lookup, null_map_store); 494 #endif /* LDAPMAP */ 495 496 #if PH_MAP 497 MAPDEF("ph", NULL, MCF_NOTPERSIST, 498 ph_map_parseargs, ph_map_open, ph_map_close, 499 ph_map_lookup, null_map_store); 500 #endif /* PH_MAP */ 501 502 #if MAP_NSD 503 /* IRIX 6.5 nsd support */ 504 MAPDEF("nsd", NULL, MCF_ALIASOK, 505 map_parseargs, null_map_open, null_map_close, 506 nsd_map_lookup, null_map_store); 507 #endif /* MAP_NSD */ 508 509 #if HESIOD 510 MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY, 511 map_parseargs, hes_map_open, hes_map_close, 512 hes_map_lookup, null_map_store); 513 #endif /* HESIOD */ 514 515 #if NETINFO 516 MAPDEF("netinfo", NULL, MCF_ALIASOK, 517 map_parseargs, ni_map_open, null_map_close, 518 ni_map_lookup, null_map_store); 519 #endif /* NETINFO */ 520 521 #if 0 522 MAPDEF("dns", NULL, 0, 523 dns_map_init, null_map_open, null_map_close, 524 dns_map_lookup, null_map_store); 525 #endif /* 0 */ 526 527 #if NAMED_BIND 528 # if DNSMAP 529 MAPDEF("dns", NULL, 0, 530 dns_map_parseargs, dns_map_open, null_map_close, 531 dns_map_lookup, null_map_store); 532 # endif /* DNSMAP */ 533 #endif /* NAMED_BIND */ 534 535 #if NAMED_BIND 536 /* best MX DNS lookup */ 537 MAPDEF("bestmx", NULL, MCF_OPTFILE, 538 map_parseargs, null_map_open, null_map_close, 539 bestmx_map_lookup, null_map_store); 540 #endif /* NAMED_BIND */ 541 542 MAPDEF("host", NULL, 0, 543 host_map_init, null_map_open, null_map_close, 544 host_map_lookup, null_map_store); 545 546 MAPDEF("text", NULL, MCF_ALIASOK, 547 map_parseargs, text_map_open, null_map_close, 548 text_map_lookup, null_map_store); 549 550 MAPDEF("stab", NULL, MCF_ALIASOK|MCF_ALIASONLY, 551 map_parseargs, stab_map_open, null_map_close, 552 stab_map_lookup, stab_map_store); 553 554 MAPDEF("implicit", NULL, MCF_ALIASOK|MCF_ALIASONLY|MCF_REBUILDABLE, 555 map_parseargs, impl_map_open, impl_map_close, 556 impl_map_lookup, impl_map_store); 557 558 /* access to system passwd file */ 559 MAPDEF("user", NULL, MCF_OPTFILE, 560 map_parseargs, user_map_open, null_map_close, 561 user_map_lookup, null_map_store); 562 563 /* dequote map */ 564 MAPDEF("dequote", NULL, 0, 565 dequote_init, null_map_open, null_map_close, 566 dequote_map, null_map_store); 567 568 #if MAP_REGEX 569 MAPDEF("regex", NULL, 0, 570 regex_map_init, null_map_open, null_map_close, 571 regex_map_lookup, null_map_store); 572 #endif /* MAP_REGEX */ 573 574 #if USERDB 575 /* user database */ 576 MAPDEF("userdb", ".db", 0, 577 map_parseargs, null_map_open, null_map_close, 578 udb_map_lookup, null_map_store); 579 #endif /* USERDB */ 580 581 /* arbitrary programs */ 582 MAPDEF("program", NULL, MCF_ALIASOK, 583 map_parseargs, null_map_open, null_map_close, 584 prog_map_lookup, null_map_store); 585 586 /* sequenced maps */ 587 MAPDEF("sequence", NULL, MCF_ALIASOK, 588 seq_map_parse, null_map_open, null_map_close, 589 seq_map_lookup, seq_map_store); 590 591 /* switched interface to sequenced maps */ 592 MAPDEF("switch", NULL, MCF_ALIASOK, 593 map_parseargs, switch_map_open, null_map_close, 594 seq_map_lookup, seq_map_store); 595 596 /* null map lookup -- really for internal use only */ 597 MAPDEF("null", NULL, MCF_ALIASOK|MCF_OPTFILE, 598 map_parseargs, null_map_open, null_map_close, 599 null_map_lookup, null_map_store); 600 601 /* syslog map -- logs information to syslog */ 602 MAPDEF("syslog", NULL, 0, 603 syslog_map_parseargs, null_map_open, null_map_close, 604 syslog_map_lookup, null_map_store); 605 606 /* macro storage map -- rulesets can set macros */ 607 MAPDEF("macro", NULL, 0, 608 dequote_init, null_map_open, null_map_close, 609 macro_map_lookup, null_map_store); 610 611 /* arithmetic map -- add/subtract/compare */ 612 MAPDEF("arith", NULL, 0, 613 dequote_init, null_map_open, null_map_close, 614 arith_map_lookup, null_map_store); 615 616 if (tTd(38, 2)) 617 { 618 /* bogus map -- always return tempfail */ 619 MAPDEF("bogus", NULL, MCF_ALIASOK|MCF_OPTFILE, 620 map_parseargs, null_map_open, null_map_close, 621 bogus_map_lookup, null_map_store); 622 } 623 } 624 625 #undef MAPDEF 626 /* 627 ** INITHOSTMAPS -- initial host-dependent maps 628 ** 629 ** This should act as an interface to any local service switch 630 ** provided by the host operating system. 631 ** 632 ** Parameters: 633 ** none 634 ** 635 ** Returns: 636 ** none 637 ** 638 ** Side Effects: 639 ** Should define maps "host" and "users" as necessary 640 ** for this OS. If they are not defined, they will get 641 ** a default value later. It should check to make sure 642 ** they are not defined first, since it's possible that 643 ** the config file has provided an override. 644 */ 645 646 void 647 inithostmaps() 648 { 649 register int i; 650 int nmaps; 651 char *maptype[MAXMAPSTACK]; 652 short mapreturn[MAXMAPACTIONS]; 653 char buf[MAXLINE]; 654 655 /* 656 ** Set up default hosts maps. 657 */ 658 659 #if 0 660 nmaps = switch_map_find("hosts", maptype, mapreturn); 661 for (i = 0; i < nmaps; i++) 662 { 663 if (strcmp(maptype[i], "files") == 0 && 664 stab("hosts.files", ST_MAP, ST_FIND) == NULL) 665 { 666 (void) sm_strlcpy(buf, "hosts.files text -k 0 -v 1 /etc/hosts", 667 sizeof buf); 668 (void) makemapentry(buf); 669 } 670 # if NAMED_BIND 671 else if (strcmp(maptype[i], "dns") == 0 && 672 stab("hosts.dns", ST_MAP, ST_FIND) == NULL) 673 { 674 (void) sm_strlcpy(buf, "hosts.dns dns A", sizeof buf); 675 (void) makemapentry(buf); 676 } 677 # endif /* NAMED_BIND */ 678 # if NISPLUS 679 else if (strcmp(maptype[i], "nisplus") == 0 && 680 stab("hosts.nisplus", ST_MAP, ST_FIND) == NULL) 681 { 682 (void) sm_strlcpy(buf, "hosts.nisplus nisplus -k name -v address hosts.org_dir", 683 sizeof buf); 684 (void) makemapentry(buf); 685 } 686 # endif /* NISPLUS */ 687 # if NIS 688 else if (strcmp(maptype[i], "nis") == 0 && 689 stab("hosts.nis", ST_MAP, ST_FIND) == NULL) 690 { 691 (void) sm_strlcpy(buf, "hosts.nis nis -k 0 -v 1 hosts.byname", 692 sizeof buf); 693 (void) makemapentry(buf); 694 } 695 # endif /* NIS */ 696 # if NETINFO 697 else if (strcmp(maptype[i], "netinfo") == 0 && 698 stab("hosts.netinfo", ST_MAP, ST_FIND) == NULL) 699 { 700 (void) sm_strlcpy(buf, "hosts.netinfo netinfo -v name /machines", 701 sizeof buf); 702 (void) makemapentry(buf); 703 } 704 # endif /* NETINFO */ 705 } 706 #endif /* 0 */ 707 708 /* 709 ** Make sure we have a host map. 710 */ 711 712 if (stab("host", ST_MAP, ST_FIND) == NULL) 713 { 714 /* user didn't initialize: set up host map */ 715 (void) sm_strlcpy(buf, "host host", sizeof buf); 716 #if NAMED_BIND 717 if (ConfigLevel >= 2) 718 (void) sm_strlcat(buf, " -a. -D", sizeof buf); 719 #endif /* NAMED_BIND */ 720 (void) makemapentry(buf); 721 } 722 723 /* 724 ** Set up default aliases maps 725 */ 726 727 nmaps = switch_map_find("aliases", maptype, mapreturn); 728 for (i = 0; i < nmaps; i++) 729 { 730 if (strcmp(maptype[i], "files") == 0 && 731 stab("aliases.files", ST_MAP, ST_FIND) == NULL) 732 { 733 (void) sm_strlcpy(buf, "aliases.files null", 734 sizeof buf); 735 (void) makemapentry(buf); 736 } 737 #if NISPLUS 738 else if (strcmp(maptype[i], "nisplus") == 0 && 739 stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL) 740 { 741 (void) sm_strlcpy(buf, "aliases.nisplus nisplus -kalias -vexpansion mail_aliases.org_dir", 742 sizeof buf); 743 (void) makemapentry(buf); 744 } 745 #endif /* NISPLUS */ 746 #if NIS 747 else if (strcmp(maptype[i], "nis") == 0 && 748 stab("aliases.nis", ST_MAP, ST_FIND) == NULL) 749 { 750 (void) sm_strlcpy(buf, "aliases.nis nis mail.aliases", 751 sizeof buf); 752 (void) makemapentry(buf); 753 } 754 #endif /* NIS */ 755 #if NETINFO 756 else if (strcmp(maptype[i], "netinfo") == 0 && 757 stab("aliases.netinfo", ST_MAP, ST_FIND) == NULL) 758 { 759 (void) sm_strlcpy(buf, "aliases.netinfo netinfo -z, /aliases", 760 sizeof buf); 761 (void) makemapentry(buf); 762 } 763 #endif /* NETINFO */ 764 #if HESIOD 765 else if (strcmp(maptype[i], "hesiod") == 0 && 766 stab("aliases.hesiod", ST_MAP, ST_FIND) == NULL) 767 { 768 (void) sm_strlcpy(buf, "aliases.hesiod hesiod aliases", 769 sizeof buf); 770 (void) makemapentry(buf); 771 } 772 #endif /* HESIOD */ 773 } 774 if (stab("aliases", ST_MAP, ST_FIND) == NULL) 775 { 776 (void) sm_strlcpy(buf, "aliases switch aliases", sizeof buf); 777 (void) makemapentry(buf); 778 } 779 780 #if 0 /* "user" map class is a better choice */ 781 /* 782 ** Set up default users maps. 783 */ 784 785 nmaps = switch_map_find("passwd", maptype, mapreturn); 786 for (i = 0; i < nmaps; i++) 787 { 788 if (strcmp(maptype[i], "files") == 0 && 789 stab("users.files", ST_MAP, ST_FIND) == NULL) 790 { 791 (void) sm_strlcpy(buf, "users.files text -m -z: -k0 -v6 /etc/passwd", 792 sizeof buf); 793 (void) makemapentry(buf); 794 } 795 # if NISPLUS 796 else if (strcmp(maptype[i], "nisplus") == 0 && 797 stab("users.nisplus", ST_MAP, ST_FIND) == NULL) 798 { 799 (void) sm_strlcpy(buf, "users.nisplus nisplus -m -kname -vhome passwd.org_dir", 800 sizeof buf); 801 (void) makemapentry(buf); 802 } 803 # endif /* NISPLUS */ 804 # if NIS 805 else if (strcmp(maptype[i], "nis") == 0 && 806 stab("users.nis", ST_MAP, ST_FIND) == NULL) 807 { 808 (void) sm_strlcpy(buf, "users.nis nis -m passwd.byname", 809 sizeof buf); 810 (void) makemapentry(buf); 811 } 812 # endif /* NIS */ 813 # if HESIOD 814 else if (strcmp(maptype[i], "hesiod") == 0 && 815 stab("users.hesiod", ST_MAP, ST_FIND) == NULL) 816 { 817 (void) sm_strlcpy(buf, "users.hesiod hesiod", sizeof buf); 818 (void) makemapentry(buf); 819 } 820 # endif /* HESIOD */ 821 } 822 if (stab("users", ST_MAP, ST_FIND) == NULL) 823 { 824 (void) sm_strlcpy(buf, "users switch -m passwd", sizeof buf); 825 (void) makemapentry(buf); 826 } 827 #endif /* 0 */ 828 } 829 /* 830 ** SWITCH_MAP_FIND -- find the list of types associated with a map 831 ** 832 ** This is the system-dependent interface to the service switch. 833 ** 834 ** Parameters: 835 ** service -- the name of the service of interest. 836 ** maptype -- an out-array of strings containing the types 837 ** of access to use for this service. There can 838 ** be at most MAXMAPSTACK types for a single service. 839 ** mapreturn -- an out-array of return information bitmaps 840 ** for the map. 841 ** 842 ** Returns: 843 ** The number of map types filled in, or -1 for failure. 844 ** 845 ** Side effects: 846 ** Preserves errno so nothing in the routine clobbers it. 847 */ 848 849 #if defined(SOLARIS) || (defined(sony_news) && defined(__svr4)) 850 # define _USE_SUN_NSSWITCH_ 851 #endif /* defined(SOLARIS) || (defined(sony_news) && defined(__svr4)) */ 852 853 #if _FFR_HPUX_NSSWITCH 854 # ifdef __hpux 855 # define _USE_SUN_NSSWITCH_ 856 # endif /* __hpux */ 857 #endif /* _FFR_HPUX_NSSWITCH */ 858 859 #ifdef _USE_SUN_NSSWITCH_ 860 # include <nsswitch.h> 861 #endif /* _USE_SUN_NSSWITCH_ */ 862 863 #if defined(ultrix) || (defined(__osf__) && defined(__alpha)) 864 # define _USE_DEC_SVC_CONF_ 865 #endif /* defined(ultrix) || (defined(__osf__) && defined(__alpha)) */ 866 867 #ifdef _USE_DEC_SVC_CONF_ 868 # include <sys/svcinfo.h> 869 #endif /* _USE_DEC_SVC_CONF_ */ 870 871 int 872 switch_map_find(service, maptype, mapreturn) 873 char *service; 874 char *maptype[MAXMAPSTACK]; 875 short mapreturn[MAXMAPACTIONS]; 876 { 877 int svcno = 0; 878 int save_errno = errno; 879 880 #ifdef _USE_SUN_NSSWITCH_ 881 struct __nsw_switchconfig *nsw_conf; 882 enum __nsw_parse_err pserr; 883 struct __nsw_lookup *lk; 884 static struct __nsw_lookup lkp0 = 885 { "files", {1, 0, 0, 0}, NULL, NULL }; 886 static struct __nsw_switchconfig lkp_default = 887 { 0, "sendmail", 3, &lkp0 }; 888 889 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++) 890 mapreturn[svcno] = 0; 891 892 if ((nsw_conf = __nsw_getconfig(service, &pserr)) == NULL) 893 lk = lkp_default.lookups; 894 else 895 lk = nsw_conf->lookups; 896 svcno = 0; 897 while (lk != NULL && svcno < MAXMAPSTACK) 898 { 899 maptype[svcno] = lk->service_name; 900 if (lk->actions[__NSW_NOTFOUND] == __NSW_RETURN) 901 mapreturn[MA_NOTFOUND] |= 1 << svcno; 902 if (lk->actions[__NSW_TRYAGAIN] == __NSW_RETURN) 903 mapreturn[MA_TRYAGAIN] |= 1 << svcno; 904 if (lk->actions[__NSW_UNAVAIL] == __NSW_RETURN) 905 mapreturn[MA_TRYAGAIN] |= 1 << svcno; 906 svcno++; 907 lk = lk->next; 908 } 909 errno = save_errno; 910 return svcno; 911 #endif /* _USE_SUN_NSSWITCH_ */ 912 913 #ifdef _USE_DEC_SVC_CONF_ 914 struct svcinfo *svcinfo; 915 int svc; 916 917 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++) 918 mapreturn[svcno] = 0; 919 920 svcinfo = getsvc(); 921 if (svcinfo == NULL) 922 goto punt; 923 if (strcmp(service, "hosts") == 0) 924 svc = SVC_HOSTS; 925 else if (strcmp(service, "aliases") == 0) 926 svc = SVC_ALIASES; 927 else if (strcmp(service, "passwd") == 0) 928 svc = SVC_PASSWD; 929 else 930 { 931 errno = save_errno; 932 return -1; 933 } 934 for (svcno = 0; svcno < SVC_PATHSIZE && svcno < MAXMAPSTACK; svcno++) 935 { 936 switch (svcinfo->svcpath[svc][svcno]) 937 { 938 case SVC_LOCAL: 939 maptype[svcno] = "files"; 940 break; 941 942 case SVC_YP: 943 maptype[svcno] = "nis"; 944 break; 945 946 case SVC_BIND: 947 maptype[svcno] = "dns"; 948 break; 949 950 # ifdef SVC_HESIOD 951 case SVC_HESIOD: 952 maptype[svcno] = "hesiod"; 953 break; 954 # endif /* SVC_HESIOD */ 955 956 case SVC_LAST: 957 errno = save_errno; 958 return svcno; 959 } 960 } 961 errno = save_errno; 962 return svcno; 963 #endif /* _USE_DEC_SVC_CONF_ */ 964 965 #if !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) 966 /* 967 ** Fall-back mechanism. 968 */ 969 970 STAB *st; 971 static time_t servicecachetime; /* time service switch was cached */ 972 time_t now = curtime(); 973 974 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++) 975 mapreturn[svcno] = 0; 976 977 if ((now - servicecachetime) > (time_t) ServiceCacheMaxAge) 978 { 979 /* (re)read service switch */ 980 register SM_FILE_T *fp; 981 long sff = SFF_REGONLY|SFF_OPENASROOT|SFF_NOLOCK; 982 983 if (!bitnset(DBS_LINKEDSERVICESWITCHFILEINWRITABLEDIR, 984 DontBlameSendmail)) 985 sff |= SFF_NOWLINK; 986 987 if (ConfigFileRead) 988 servicecachetime = now; 989 fp = safefopen(ServiceSwitchFile, O_RDONLY, 0, sff); 990 if (fp != NULL) 991 { 992 char buf[MAXLINE]; 993 994 while (sm_io_fgets(fp, SM_TIME_DEFAULT, buf, 995 sizeof buf) != NULL) 996 { 997 register char *p; 998 999 p = strpbrk(buf, "#\n"); 1000 if (p != NULL) 1001 *p = '\0'; 1002 p = strpbrk(buf, " \t"); 1003 if (p != NULL) 1004 *p++ = '\0'; 1005 if (buf[0] == '\0') 1006 continue; 1007 if (p == NULL) 1008 { 1009 sm_syslog(LOG_ERR, NOQID, 1010 "Bad line on %.100s: %.100s", 1011 ServiceSwitchFile, 1012 buf); 1013 continue; 1014 } 1015 while (isspace(*p)) 1016 p++; 1017 if (*p == '\0') 1018 continue; 1019 1020 /* 1021 ** Find/allocate space for this service entry. 1022 ** Space for all of the service strings 1023 ** are allocated at once. This means 1024 ** that we only have to free the first 1025 ** one to free all of them. 1026 */ 1027 1028 st = stab(buf, ST_SERVICE, ST_ENTER); 1029 if (st->s_service[0] != NULL) 1030 sm_free((void *) st->s_service[0]); /* XXX */ 1031 p = newstr(p); 1032 for (svcno = 0; svcno < MAXMAPSTACK; ) 1033 { 1034 if (*p == '\0') 1035 break; 1036 st->s_service[svcno++] = p; 1037 p = strpbrk(p, " \t"); 1038 if (p == NULL) 1039 break; 1040 *p++ = '\0'; 1041 while (isspace(*p)) 1042 p++; 1043 } 1044 if (svcno < MAXMAPSTACK) 1045 st->s_service[svcno] = NULL; 1046 } 1047 (void) sm_io_close(fp, SM_TIME_DEFAULT); 1048 } 1049 } 1050 1051 /* look up entry in cache */ 1052 st = stab(service, ST_SERVICE, ST_FIND); 1053 if (st != NULL && st->s_service[0] != NULL) 1054 { 1055 /* extract data */ 1056 svcno = 0; 1057 while (svcno < MAXMAPSTACK) 1058 { 1059 maptype[svcno] = st->s_service[svcno]; 1060 if (maptype[svcno++] == NULL) 1061 break; 1062 } 1063 errno = save_errno; 1064 return --svcno; 1065 } 1066 #endif /* !defined(_USE_SUN_NSSWITCH_) && !defined(_USE_DEC_SVC_CONF_) */ 1067 1068 #if !defined(_USE_SUN_NSSWITCH_) 1069 /* if the service file doesn't work, use an absolute fallback */ 1070 # ifdef _USE_DEC_SVC_CONF_ 1071 punt: 1072 # endif /* _USE_DEC_SVC_CONF_ */ 1073 for (svcno = 0; svcno < MAXMAPACTIONS; svcno++) 1074 mapreturn[svcno] = 0; 1075 svcno = 0; 1076 if (strcmp(service, "aliases") == 0) 1077 { 1078 maptype[svcno++] = "files"; 1079 # if defined(AUTO_NETINFO_ALIASES) && defined (NETINFO) 1080 maptype[svcno++] = "netinfo"; 1081 # endif /* defined(AUTO_NETINFO_ALIASES) && defined (NETINFO) */ 1082 # ifdef AUTO_NIS_ALIASES 1083 # if NISPLUS 1084 maptype[svcno++] = "nisplus"; 1085 # endif /* NISPLUS */ 1086 # if NIS 1087 maptype[svcno++] = "nis"; 1088 # endif /* NIS */ 1089 # endif /* AUTO_NIS_ALIASES */ 1090 errno = save_errno; 1091 return svcno; 1092 } 1093 if (strcmp(service, "hosts") == 0) 1094 { 1095 # if NAMED_BIND 1096 maptype[svcno++] = "dns"; 1097 # else /* NAMED_BIND */ 1098 # if defined(sun) && !defined(BSD) 1099 /* SunOS */ 1100 maptype[svcno++] = "nis"; 1101 # endif /* defined(sun) && !defined(BSD) */ 1102 # endif /* NAMED_BIND */ 1103 # if defined(AUTO_NETINFO_HOSTS) && defined (NETINFO) 1104 maptype[svcno++] = "netinfo"; 1105 # endif /* defined(AUTO_NETINFO_HOSTS) && defined (NETINFO) */ 1106 maptype[svcno++] = "files"; 1107 errno = save_errno; 1108 return svcno; 1109 } 1110 errno = save_errno; 1111 return -1; 1112 #endif /* !defined(_USE_SUN_NSSWITCH_) */ 1113 } 1114 /* 1115 ** USERNAME -- return the user id of the logged in user. 1116 ** 1117 ** Parameters: 1118 ** none. 1119 ** 1120 ** Returns: 1121 ** The login name of the logged in user. 1122 ** 1123 ** Side Effects: 1124 ** none. 1125 ** 1126 ** Notes: 1127 ** The return value is statically allocated. 1128 */ 1129 1130 char * 1131 username() 1132 { 1133 static char *myname = NULL; 1134 extern char *getlogin(); 1135 register struct passwd *pw; 1136 1137 /* cache the result */ 1138 if (myname == NULL) 1139 { 1140 myname = getlogin(); 1141 if (myname == NULL || myname[0] == '\0') 1142 { 1143 pw = sm_getpwuid(RealUid); 1144 if (pw != NULL) 1145 myname = pw->pw_name; 1146 } 1147 else 1148 { 1149 uid_t uid = RealUid; 1150 1151 if ((pw = sm_getpwnam(myname)) == NULL || 1152 (uid != 0 && uid != pw->pw_uid)) 1153 { 1154 pw = sm_getpwuid(uid); 1155 if (pw != NULL) 1156 myname = pw->pw_name; 1157 } 1158 } 1159 if (myname == NULL || myname[0] == '\0') 1160 { 1161 syserr("554 5.3.0 Who are you?"); 1162 myname = "postmaster"; 1163 } 1164 else if (strpbrk(myname, ",;:/|\"\\") != NULL) 1165 myname = addquotes(myname, NULL); 1166 else 1167 myname = sm_pstrdup_x(myname); 1168 } 1169 return myname; 1170 } 1171 /* 1172 ** TTYPATH -- Get the path of the user's tty 1173 ** 1174 ** Returns the pathname of the user's tty. Returns NULL if 1175 ** the user is not logged in or if s/he has write permission 1176 ** denied. 1177 ** 1178 ** Parameters: 1179 ** none 1180 ** 1181 ** Returns: 1182 ** pathname of the user's tty. 1183 ** NULL if not logged in or write permission denied. 1184 ** 1185 ** Side Effects: 1186 ** none. 1187 ** 1188 ** WARNING: 1189 ** Return value is in a local buffer. 1190 ** 1191 ** Called By: 1192 ** savemail 1193 */ 1194 1195 char * 1196 ttypath() 1197 { 1198 struct stat stbuf; 1199 register char *pathn; 1200 extern char *ttyname(); 1201 extern char *getlogin(); 1202 1203 /* compute the pathname of the controlling tty */ 1204 if ((pathn = ttyname(2)) == NULL && (pathn = ttyname(1)) == NULL && 1205 (pathn = ttyname(0)) == NULL) 1206 { 1207 errno = 0; 1208 return NULL; 1209 } 1210 1211 /* see if we have write permission */ 1212 if (stat(pathn, &stbuf) < 0 || !bitset(S_IWOTH, stbuf.st_mode)) 1213 { 1214 errno = 0; 1215 return NULL; 1216 } 1217 1218 /* see if the user is logged in */ 1219 if (getlogin() == NULL) 1220 return NULL; 1221 1222 /* looks good */ 1223 return pathn; 1224 } 1225 /* 1226 ** CHECKCOMPAT -- check for From and To person compatible. 1227 ** 1228 ** This routine can be supplied on a per-installation basis 1229 ** to determine whether a person is allowed to send a message. 1230 ** This allows restriction of certain types of internet 1231 ** forwarding or registration of users. 1232 ** 1233 ** If the hosts are found to be incompatible, an error 1234 ** message should be given using "usrerr" and an EX_ code 1235 ** should be returned. You can also set to->q_status to 1236 ** a DSN-style status code. 1237 ** 1238 ** EF_NO_BODY_RETN can be set in e->e_flags to suppress the 1239 ** body during the return-to-sender function; this should be done 1240 ** on huge messages. This bit may already be set by the ESMTP 1241 ** protocol. 1242 ** 1243 ** Parameters: 1244 ** to -- the person being sent to. 1245 ** 1246 ** Returns: 1247 ** an exit status 1248 ** 1249 ** Side Effects: 1250 ** none (unless you include the usrerr stuff) 1251 */ 1252 1253 int 1254 checkcompat(to, e) 1255 register ADDRESS *to; 1256 register ENVELOPE *e; 1257 { 1258 if (tTd(49, 1)) 1259 sm_dprintf("checkcompat(to=%s, from=%s)\n", 1260 to->q_paddr, e->e_from.q_paddr); 1261 1262 #ifdef EXAMPLE_CODE 1263 /* this code is intended as an example only */ 1264 register STAB *s; 1265 1266 s = stab("arpa", ST_MAILER, ST_FIND); 1267 if (s != NULL && strcmp(e->e_from.q_mailer->m_name, "local") != 0 && 1268 to->q_mailer == s->s_mailer) 1269 { 1270 usrerr("553 No ARPA mail through this machine: see your system administration"); 1271 /* e->e_flags |= EF_NO_BODY_RETN; to suppress body on return */ 1272 to->q_status = "5.7.1"; 1273 return EX_UNAVAILABLE; 1274 } 1275 #endif /* EXAMPLE_CODE */ 1276 return EX_OK; 1277 } 1278 /* 1279 ** INIT_MD -- do machine dependent initializations 1280 ** 1281 ** Systems that have global modes that should be set should do 1282 ** them here rather than in main. 1283 */ 1284 1285 #ifdef _AUX_SOURCE 1286 # include <compat.h> 1287 #endif /* _AUX_SOURCE */ 1288 1289 #if SHARE_V1 1290 # include <shares.h> 1291 #endif /* SHARE_V1 */ 1292 1293 void 1294 init_md(argc, argv) 1295 int argc; 1296 char **argv; 1297 { 1298 #ifdef _AUX_SOURCE 1299 setcompat(getcompat() | COMPAT_BSDPROT); 1300 #endif /* _AUX_SOURCE */ 1301 1302 #ifdef SUN_EXTENSIONS 1303 init_md_sun(); 1304 #endif /* SUN_EXTENSIONS */ 1305 1306 #if _CONVEX_SOURCE 1307 /* keep gethostby*() from stripping the local domain name */ 1308 set_domain_trim_off(); 1309 #endif /* _CONVEX_SOURCE */ 1310 #ifdef __QNX__ 1311 /* 1312 ** Due to QNX's network distributed nature, you can target a tcpip 1313 ** stack on a different node in the qnx network; this patch lets 1314 ** this feature work. The __sock_locate() must be done before the 1315 ** environment is clear. 1316 */ 1317 __sock_locate(); 1318 #endif /* __QNX__ */ 1319 #if SECUREWARE || defined(_SCO_unix_) 1320 set_auth_parameters(argc, argv); 1321 1322 # ifdef _SCO_unix_ 1323 /* 1324 ** This is required for highest security levels (the kernel 1325 ** won't let it call set*uid() or run setuid binaries without 1326 ** it). It may be necessary on other SECUREWARE systems. 1327 */ 1328 1329 if (getluid() == -1) 1330 setluid(0); 1331 # endif /* _SCO_unix_ */ 1332 #endif /* SECUREWARE || defined(_SCO_unix_) */ 1333 1334 1335 #ifdef VENDOR_DEFAULT 1336 VendorCode = VENDOR_DEFAULT; 1337 #else /* VENDOR_DEFAULT */ 1338 VendorCode = VENDOR_BERKELEY; 1339 #endif /* VENDOR_DEFAULT */ 1340 } 1341 /* 1342 ** INIT_VENDOR_MACROS -- vendor-dependent macro initializations 1343 ** 1344 ** Called once, on startup. 1345 ** 1346 ** Parameters: 1347 ** e -- the global envelope. 1348 ** 1349 ** Returns: 1350 ** none. 1351 ** 1352 ** Side Effects: 1353 ** vendor-dependent. 1354 */ 1355 1356 void 1357 init_vendor_macros(e) 1358 register ENVELOPE *e; 1359 { 1360 } 1361 /* 1362 ** GETLA -- get the current load average 1363 ** 1364 ** This code stolen from la.c. 1365 ** 1366 ** Parameters: 1367 ** none. 1368 ** 1369 ** Returns: 1370 ** The current load average as an integer. 1371 ** 1372 ** Side Effects: 1373 ** none. 1374 */ 1375 1376 /* try to guess what style of load average we have */ 1377 #define LA_ZERO 1 /* always return load average as zero */ 1378 #define LA_INT 2 /* read kmem for avenrun; interpret as long */ 1379 #define LA_FLOAT 3 /* read kmem for avenrun; interpret as float */ 1380 #define LA_SUBR 4 /* call getloadavg */ 1381 #define LA_MACH 5 /* MACH load averages (as on NeXT boxes) */ 1382 #define LA_SHORT 6 /* read kmem for avenrun; interpret as short */ 1383 #define LA_PROCSTR 7 /* read string ("1.17") from /proc/loadavg */ 1384 #define LA_READKSYM 8 /* SVR4: use MIOC_READKSYM ioctl call */ 1385 #define LA_DGUX 9 /* special DGUX implementation */ 1386 #define LA_HPUX 10 /* special HPUX implementation */ 1387 #define LA_IRIX6 11 /* special IRIX 6.2 implementation */ 1388 #define LA_KSTAT 12 /* special Solaris kstat(3k) implementation */ 1389 #define LA_DEVSHORT 13 /* read short from a device */ 1390 #define LA_ALPHAOSF 14 /* Digital UNIX (OSF/1 on Alpha) table() call */ 1391 #define LA_PSET 15 /* Solaris per-processor-set load average */ 1392 1393 /* do guesses based on general OS type */ 1394 #ifndef LA_TYPE 1395 # define LA_TYPE LA_ZERO 1396 #endif /* ! LA_TYPE */ 1397 1398 #ifndef FSHIFT 1399 # if defined(unixpc) 1400 # define FSHIFT 5 1401 # endif /* defined(unixpc) */ 1402 1403 # if defined(__alpha) || defined(IRIX) 1404 # define FSHIFT 10 1405 # endif /* defined(__alpha) || defined(IRIX) */ 1406 1407 #endif /* ! FSHIFT */ 1408 1409 #ifndef FSHIFT 1410 # define FSHIFT 8 1411 #endif /* ! FSHIFT */ 1412 1413 #ifndef FSCALE 1414 # define FSCALE (1 << FSHIFT) 1415 #endif /* ! FSCALE */ 1416 1417 #ifndef LA_AVENRUN 1418 # ifdef SYSTEM5 1419 # define LA_AVENRUN "avenrun" 1420 # else /* SYSTEM5 */ 1421 # define LA_AVENRUN "_avenrun" 1422 # endif /* SYSTEM5 */ 1423 #endif /* ! LA_AVENRUN */ 1424 1425 /* _PATH_KMEM should be defined in <paths.h> */ 1426 #ifndef _PATH_KMEM 1427 # define _PATH_KMEM "/dev/kmem" 1428 #endif /* ! _PATH_KMEM */ 1429 1430 #if (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) 1431 1432 # include <nlist.h> 1433 1434 /* _PATH_UNIX should be defined in <paths.h> */ 1435 # ifndef _PATH_UNIX 1436 # if defined(SYSTEM5) 1437 # define _PATH_UNIX "/unix" 1438 # else /* defined(SYSTEM5) */ 1439 # define _PATH_UNIX "/vmunix" 1440 # endif /* defined(SYSTEM5) */ 1441 # endif /* ! _PATH_UNIX */ 1442 1443 # ifdef _AUX_SOURCE 1444 struct nlist Nl[2]; 1445 # else /* _AUX_SOURCE */ 1446 struct nlist Nl[] = 1447 { 1448 { LA_AVENRUN }, 1449 { 0 }, 1450 }; 1451 # endif /* _AUX_SOURCE */ 1452 # define X_AVENRUN 0 1453 1454 int 1455 getla() 1456 { 1457 int j; 1458 static int kmem = -1; 1459 # if LA_TYPE == LA_INT 1460 long avenrun[3]; 1461 # else /* LA_TYPE == LA_INT */ 1462 # if LA_TYPE == LA_SHORT 1463 short avenrun[3]; 1464 # else /* LA_TYPE == LA_SHORT */ 1465 double avenrun[3]; 1466 # endif /* LA_TYPE == LA_SHORT */ 1467 # endif /* LA_TYPE == LA_INT */ 1468 extern int errno; 1469 extern off_t lseek(); 1470 1471 if (kmem < 0) 1472 { 1473 # ifdef _AUX_SOURCE 1474 (void) sm_strlcpy(Nl[X_AVENRUN].n_name, LA_AVENRUN, 1475 sizeof Nl[X_AVENRUN].n_name); 1476 Nl[1].n_name[0] = '\0'; 1477 # endif /* _AUX_SOURCE */ 1478 1479 # if defined(_AIX3) || defined(_AIX4) 1480 if (knlist(Nl, 1, sizeof Nl[0]) < 0) 1481 # else /* defined(_AIX3) || defined(_AIX4) */ 1482 if (nlist(_PATH_UNIX, Nl) < 0) 1483 # endif /* defined(_AIX3) || defined(_AIX4) */ 1484 { 1485 if (tTd(3, 1)) 1486 sm_dprintf("getla: nlist(%s): %s\n", _PATH_UNIX, 1487 sm_errstring(errno)); 1488 return -1; 1489 } 1490 if (Nl[X_AVENRUN].n_value == 0) 1491 { 1492 if (tTd(3, 1)) 1493 sm_dprintf("getla: nlist(%s, %s) ==> 0\n", 1494 _PATH_UNIX, LA_AVENRUN); 1495 return -1; 1496 } 1497 # ifdef NAMELISTMASK 1498 Nl[X_AVENRUN].n_value &= NAMELISTMASK; 1499 # endif /* NAMELISTMASK */ 1500 1501 kmem = open(_PATH_KMEM, 0, 0); 1502 if (kmem < 0) 1503 { 1504 if (tTd(3, 1)) 1505 sm_dprintf("getla: open(/dev/kmem): %s\n", 1506 sm_errstring(errno)); 1507 return -1; 1508 } 1509 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 || 1510 fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0) 1511 { 1512 if (tTd(3, 1)) 1513 sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n", 1514 sm_errstring(errno)); 1515 (void) close(kmem); 1516 kmem = -1; 1517 return -1; 1518 } 1519 } 1520 if (tTd(3, 20)) 1521 sm_dprintf("getla: symbol address = %#lx\n", 1522 (unsigned long) Nl[X_AVENRUN].n_value); 1523 if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, SEEK_SET) == -1 || 1524 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 1525 { 1526 /* thank you Ian */ 1527 if (tTd(3, 1)) 1528 sm_dprintf("getla: lseek or read: %s\n", 1529 sm_errstring(errno)); 1530 return -1; 1531 } 1532 # if (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) 1533 if (tTd(3, 5)) 1534 { 1535 # if LA_TYPE == LA_SHORT 1536 sm_dprintf("getla: avenrun = %d", avenrun[0]); 1537 if (tTd(3, 15)) 1538 sm_dprintf(", %d, %d", avenrun[1], avenrun[2]); 1539 # else /* LA_TYPE == LA_SHORT */ 1540 sm_dprintf("getla: avenrun = %ld", avenrun[0]); 1541 if (tTd(3, 15)) 1542 sm_dprintf(", %ld, %ld", avenrun[1], avenrun[2]); 1543 # endif /* LA_TYPE == LA_SHORT */ 1544 sm_dprintf("\n"); 1545 } 1546 if (tTd(3, 1)) 1547 sm_dprintf("getla: %d\n", 1548 (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1549 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1550 # else /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */ 1551 if (tTd(3, 5)) 1552 { 1553 sm_dprintf("getla: avenrun = %g", avenrun[0]); 1554 if (tTd(3, 15)) 1555 sm_dprintf(", %g, %g", avenrun[1], avenrun[2]); 1556 sm_dprintf("\n"); 1557 } 1558 if (tTd(3, 1)) 1559 sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5)); 1560 return ((int) (avenrun[0] + 0.5)); 1561 # endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_SHORT) */ 1562 } 1563 1564 #endif /* (LA_TYPE == LA_INT) || (LA_TYPE == LA_FLOAT) || (LA_TYPE == LA_SHORT) */ 1565 1566 #if LA_TYPE == LA_READKSYM 1567 1568 # include <sys/ksym.h> 1569 1570 int 1571 getla() 1572 { 1573 int j; 1574 static int kmem = -1; 1575 long avenrun[3]; 1576 extern int errno; 1577 struct mioc_rksym mirk; 1578 1579 if (kmem < 0) 1580 { 1581 kmem = open("/dev/kmem", 0, 0); 1582 if (kmem < 0) 1583 { 1584 if (tTd(3, 1)) 1585 sm_dprintf("getla: open(/dev/kmem): %s\n", 1586 sm_errstring(errno)); 1587 return -1; 1588 } 1589 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 || 1590 fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0) 1591 { 1592 if (tTd(3, 1)) 1593 sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n", 1594 sm_errstring(errno)); 1595 (void) close(kmem); 1596 kmem = -1; 1597 return -1; 1598 } 1599 } 1600 mirk.mirk_symname = LA_AVENRUN; 1601 mirk.mirk_buf = avenrun; 1602 mirk.mirk_buflen = sizeof(avenrun); 1603 if (ioctl(kmem, MIOC_READKSYM, &mirk) < 0) 1604 { 1605 if (tTd(3, 1)) 1606 sm_dprintf("getla: ioctl(MIOC_READKSYM) failed: %s\n", 1607 sm_errstring(errno)); 1608 return -1; 1609 } 1610 if (tTd(3, 5)) 1611 { 1612 sm_dprintf("getla: avenrun = %d", avenrun[0]); 1613 if (tTd(3, 15)) 1614 sm_dprintf(", %d, %d", avenrun[1], avenrun[2]); 1615 sm_dprintf("\n"); 1616 } 1617 if (tTd(3, 1)) 1618 sm_dprintf("getla: %d\n", 1619 (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1620 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1621 } 1622 1623 #endif /* LA_TYPE == LA_READKSYM */ 1624 1625 #if LA_TYPE == LA_DGUX 1626 1627 # include <sys/dg_sys_info.h> 1628 1629 int 1630 getla() 1631 { 1632 struct dg_sys_info_load_info load_info; 1633 1634 dg_sys_info((long *)&load_info, 1635 DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); 1636 1637 if (tTd(3, 1)) 1638 sm_dprintf("getla: %d\n", (int) (load_info.one_minute + 0.5)); 1639 1640 return ((int) (load_info.one_minute + 0.5)); 1641 } 1642 1643 #endif /* LA_TYPE == LA_DGUX */ 1644 1645 #if LA_TYPE == LA_HPUX 1646 1647 /* forward declarations to keep gcc from complaining */ 1648 struct pst_dynamic; 1649 struct pst_status; 1650 struct pst_static; 1651 struct pst_vminfo; 1652 struct pst_diskinfo; 1653 struct pst_processor; 1654 struct pst_lv; 1655 struct pst_swapinfo; 1656 1657 # include <sys/param.h> 1658 # include <sys/pstat.h> 1659 1660 int 1661 getla() 1662 { 1663 struct pst_dynamic pstd; 1664 1665 if (pstat_getdynamic(&pstd, sizeof(struct pst_dynamic), 1666 (size_t) 1, 0) == -1) 1667 return 0; 1668 1669 if (tTd(3, 1)) 1670 sm_dprintf("getla: %d\n", (int) (pstd.psd_avg_1_min + 0.5)); 1671 1672 return (int) (pstd.psd_avg_1_min + 0.5); 1673 } 1674 1675 #endif /* LA_TYPE == LA_HPUX */ 1676 1677 #if LA_TYPE == LA_SUBR 1678 1679 int 1680 getla() 1681 { 1682 double avenrun[3]; 1683 1684 if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) < 0) 1685 { 1686 if (tTd(3, 1)) 1687 sm_dprintf("getla: getloadavg failed: %s", 1688 sm_errstring(errno)); 1689 return -1; 1690 } 1691 if (tTd(3, 1)) 1692 sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5)); 1693 return ((int) (avenrun[0] + 0.5)); 1694 } 1695 1696 #endif /* LA_TYPE == LA_SUBR */ 1697 1698 #if LA_TYPE == LA_MACH 1699 1700 /* 1701 ** This has been tested on NEXTSTEP release 2.1/3.X. 1702 */ 1703 1704 # if defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 1705 # include <mach/mach.h> 1706 # else /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */ 1707 # include <mach.h> 1708 # endif /* defined(NX_CURRENT_COMPILER_RELEASE) && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_0 */ 1709 1710 int 1711 getla() 1712 { 1713 processor_set_t default_set; 1714 kern_return_t error; 1715 unsigned int info_count; 1716 struct processor_set_basic_info info; 1717 host_t host; 1718 1719 error = processor_set_default(host_self(), &default_set); 1720 if (error != KERN_SUCCESS) 1721 { 1722 if (tTd(3, 1)) 1723 sm_dprintf("getla: processor_set_default failed: %s", 1724 sm_errstring(errno)); 1725 return -1; 1726 } 1727 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 1728 if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, 1729 &host, (processor_set_info_t)&info, 1730 &info_count) != KERN_SUCCESS) 1731 { 1732 if (tTd(3, 1)) 1733 sm_dprintf("getla: processor_set_info failed: %s", 1734 sm_errstring(errno)); 1735 return -1; 1736 } 1737 if (tTd(3, 1)) 1738 sm_dprintf("getla: %d\n", 1739 (int) ((info.load_average + (LOAD_SCALE / 2)) / 1740 LOAD_SCALE)); 1741 return (int) (info.load_average + (LOAD_SCALE / 2)) / LOAD_SCALE; 1742 } 1743 1744 #endif /* LA_TYPE == LA_MACH */ 1745 1746 #if LA_TYPE == LA_PROCSTR 1747 # if SM_CONF_BROKEN_STRTOD 1748 ERROR: This OS has most likely a broken strtod() implemenentation. 1749 ERROR: The function is required for getla(). 1750 ERROR: Check the compilation options _LA_PROCSTR and 1751 ERROR: _SM_CONF_BROKEN_STRTOD (without the leading _). 1752 # endif /* SM_CONF_BROKEN_STRTOD */ 1753 1754 /* 1755 ** Read /proc/loadavg for the load average. This is assumed to be 1756 ** in a format like "0.15 0.12 0.06". 1757 ** 1758 ** Initially intended for Linux. This has been in the kernel 1759 ** since at least 0.99.15. 1760 */ 1761 1762 # ifndef _PATH_LOADAVG 1763 # define _PATH_LOADAVG "/proc/loadavg" 1764 # endif /* ! _PATH_LOADAVG */ 1765 1766 int 1767 getla() 1768 { 1769 double avenrun; 1770 register int result; 1771 SM_FILE_T *fp; 1772 1773 fp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_LOADAVG, SM_IO_RDONLY, 1774 NULL); 1775 if (fp == NULL) 1776 { 1777 if (tTd(3, 1)) 1778 sm_dprintf("getla: sm_io_open(%s): %s\n", 1779 _PATH_LOADAVG, sm_errstring(errno)); 1780 return -1; 1781 } 1782 result = sm_io_fscanf(fp, SM_TIME_DEFAULT, "%lf", &avenrun); 1783 (void) sm_io_close(fp, SM_TIME_DEFAULT); 1784 if (result != 1) 1785 { 1786 if (tTd(3, 1)) 1787 sm_dprintf("getla: sm_io_fscanf() = %d: %s\n", 1788 result, sm_errstring(errno)); 1789 return -1; 1790 } 1791 1792 if (tTd(3, 1)) 1793 sm_dprintf("getla(): %.2f\n", avenrun); 1794 1795 return ((int) (avenrun + 0.5)); 1796 } 1797 1798 #endif /* LA_TYPE == LA_PROCSTR */ 1799 1800 #if LA_TYPE == LA_IRIX6 1801 1802 # include <sys/sysmp.h> 1803 1804 int 1805 getla(void) 1806 { 1807 int j; 1808 static int kmem = -1; 1809 int avenrun[3]; 1810 1811 if (kmem < 0) 1812 { 1813 kmem = open(_PATH_KMEM, 0, 0); 1814 if (kmem < 0) 1815 { 1816 if (tTd(3, 1)) 1817 sm_dprintf("getla: open(%s): %s\n", _PATH_KMEM, 1818 sm_errstring(errno)); 1819 return -1; 1820 } 1821 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 || 1822 fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0) 1823 { 1824 if (tTd(3, 1)) 1825 sm_dprintf("getla: fcntl(/dev/kmem, FD_CLOEXEC): %s\n", 1826 sm_errstring(errno)); 1827 (void) close(kmem); 1828 kmem = -1; 1829 return -1; 1830 } 1831 } 1832 1833 if (lseek(kmem, (sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff), SEEK_SET) == -1 || 1834 read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun)) 1835 { 1836 if (tTd(3, 1)) 1837 sm_dprintf("getla: lseek or read: %s\n", 1838 sm_errstring(errno)); 1839 return -1; 1840 } 1841 if (tTd(3, 5)) 1842 { 1843 sm_dprintf("getla: avenrun = %ld", (long int) avenrun[0]); 1844 if (tTd(3, 15)) 1845 sm_dprintf(", %ld, %ld", 1846 (long int) avenrun[1], (long int) avenrun[2]); 1847 sm_dprintf("\n"); 1848 } 1849 1850 if (tTd(3, 1)) 1851 sm_dprintf("getla: %d\n", 1852 (int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1853 return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT); 1854 1855 } 1856 #endif /* LA_TYPE == LA_IRIX6 */ 1857 1858 #if LA_TYPE == LA_KSTAT 1859 1860 # include <kstat.h> 1861 1862 int 1863 getla() 1864 { 1865 static kstat_ctl_t *kc = NULL; 1866 static kstat_t *ksp = NULL; 1867 kstat_named_t *ksn; 1868 int la; 1869 1870 if (kc == NULL) /* if not initialized before */ 1871 kc = kstat_open(); 1872 if (kc == NULL) 1873 { 1874 if (tTd(3, 1)) 1875 sm_dprintf("getla: kstat_open(): %s\n", 1876 sm_errstring(errno)); 1877 return -1; 1878 } 1879 if (ksp == NULL) 1880 ksp = kstat_lookup(kc, "unix", 0, "system_misc"); 1881 if (ksp == NULL) 1882 { 1883 if (tTd(3, 1)) 1884 sm_dprintf("getla: kstat_lookup(): %s\n", 1885 sm_errstring(errno)); 1886 return -1; 1887 } 1888 if (kstat_read(kc, ksp, NULL) < 0) 1889 { 1890 if (tTd(3, 1)) 1891 sm_dprintf("getla: kstat_read(): %s\n", 1892 sm_errstring(errno)); 1893 return -1; 1894 } 1895 ksn = (kstat_named_t *) kstat_data_lookup(ksp, "avenrun_1min"); 1896 la = ((double) ksn->value.ul + FSCALE/2) / FSCALE; 1897 /* kstat_close(kc); /o do not close for fast access */ 1898 return la; 1899 } 1900 1901 #endif /* LA_TYPE == LA_KSTAT */ 1902 1903 #if LA_TYPE == LA_DEVSHORT 1904 1905 /* 1906 ** Read /dev/table/avenrun for the load average. This should contain 1907 ** three shorts for the 1, 5, and 15 minute loads. We only read the 1908 ** first, since that's all we care about. 1909 ** 1910 ** Intended for SCO OpenServer 5. 1911 */ 1912 1913 # ifndef _PATH_AVENRUN 1914 # define _PATH_AVENRUN "/dev/table/avenrun" 1915 # endif /* ! _PATH_AVENRUN */ 1916 1917 int 1918 getla() 1919 { 1920 static int afd = -1; 1921 short avenrun; 1922 int loadav; 1923 int r; 1924 1925 errno = EBADF; 1926 1927 if (afd == -1 || lseek(afd, 0L, SEEK_SET) == -1) 1928 { 1929 if (errno != EBADF) 1930 return -1; 1931 afd = open(_PATH_AVENRUN, O_RDONLY|O_SYNC); 1932 if (afd < 0) 1933 { 1934 sm_syslog(LOG_ERR, NOQID, 1935 "can't open %s: %s", 1936 _PATH_AVENRUN, sm_errstring(errno)); 1937 return -1; 1938 } 1939 } 1940 1941 r = read(afd, &avenrun, sizeof avenrun); 1942 1943 if (tTd(3, 5)) 1944 sm_dprintf("getla: avenrun = %d\n", avenrun); 1945 loadav = (int) (avenrun + FSCALE/2) >> FSHIFT; 1946 if (tTd(3, 1)) 1947 sm_dprintf("getla: %d\n", loadav); 1948 return loadav; 1949 } 1950 1951 #endif /* LA_TYPE == LA_DEVSHORT */ 1952 1953 #if LA_TYPE == LA_ALPHAOSF 1954 struct rtentry; 1955 struct mbuf; 1956 # include <sys/table.h> 1957 1958 int 1959 getla() 1960 { 1961 int ave = 0; 1962 struct tbl_loadavg tab; 1963 1964 if (table(TBL_LOADAVG, 0, &tab, 1, sizeof(tab)) == -1) 1965 { 1966 if (tTd(3, 1)) 1967 sm_dprintf("getla: table %s\n", sm_errstring(errno)); 1968 return -1; 1969 } 1970 1971 if (tTd(3, 1)) 1972 sm_dprintf("getla: scale = %d\n", tab.tl_lscale); 1973 1974 if (tab.tl_lscale) 1975 ave = ((tab.tl_avenrun.l[2] + (tab.tl_lscale/2)) / 1976 tab.tl_lscale); 1977 else 1978 ave = (int) (tab.tl_avenrun.d[2] + 0.5); 1979 1980 if (tTd(3, 1)) 1981 sm_dprintf("getla: %d\n", ave); 1982 1983 return ave; 1984 } 1985 1986 #endif /* LA_TYPE == LA_ALPHAOSF */ 1987 1988 #if LA_TYPE == LA_PSET 1989 1990 int 1991 getla() 1992 { 1993 double avenrun[3]; 1994 1995 if (pset_getloadavg(PS_MYID, avenrun, 1996 sizeof(avenrun) / sizeof(avenrun[0])) < 0) 1997 { 1998 if (tTd(3, 1)) 1999 sm_dprintf("getla: pset_getloadavg failed: %s", 2000 sm_errstring(errno)); 2001 return -1; 2002 } 2003 if (tTd(3, 1)) 2004 sm_dprintf("getla: %d\n", (int) (avenrun[0] +0.5)); 2005 return ((int) (avenrun[0] + 0.5)); 2006 } 2007 2008 #endif /* LA_TYPE == LA_PSET */ 2009 2010 #if LA_TYPE == LA_ZERO 2011 2012 int 2013 getla() 2014 { 2015 if (tTd(3, 1)) 2016 sm_dprintf("getla: ZERO\n"); 2017 return 0; 2018 } 2019 2020 #endif /* LA_TYPE == LA_ZERO */ 2021 2022 /* 2023 * Copyright 1989 Massachusetts Institute of Technology 2024 * 2025 * Permission to use, copy, modify, distribute, and sell this software and its 2026 * documentation for any purpose is hereby granted without fee, provided that 2027 * the above copyright notice appear in all copies and that both that 2028 * copyright notice and this permission notice appear in supporting 2029 * documentation, and that the name of M.I.T. not be used in advertising or 2030 * publicity pertaining to distribution of the software without specific, 2031 * written prior permission. M.I.T. makes no representations about the 2032 * suitability of this software for any purpose. It is provided "as is" 2033 * without express or implied warranty. 2034 * 2035 * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 2036 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. 2037 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 2038 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 2039 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 2040 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2041 * 2042 * Authors: Many and varied... 2043 */ 2044 2045 /* Non Apollo stuff removed by Don Lewis 11/15/93 */ 2046 #ifndef lint 2047 SM_UNUSED(static char rcsid[]) = "@(#)$OrigId: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $"; 2048 #endif /* ! lint */ 2049 2050 #ifdef apollo 2051 # undef volatile 2052 # include <apollo/base.h> 2053 2054 /* ARGSUSED */ 2055 int getloadavg( call_data ) 2056 caddr_t call_data; /* pointer to (double) return value */ 2057 { 2058 double *avenrun = (double *) call_data; 2059 int i; 2060 status_$t st; 2061 long loadav[3]; 2062 2063 proc1_$get_loadav(loadav, &st); 2064 *avenrun = loadav[0] / (double) (1 << 16); 2065 return 0; 2066 } 2067 #endif /* apollo */ 2068 /* 2069 ** SM_GETLA -- get the current load average 2070 ** 2071 ** Parameters: 2072 ** none 2073 ** 2074 ** Returns: 2075 ** none 2076 ** 2077 ** Side Effects: 2078 ** Set CurrentLA to the current load average. 2079 ** Set {load_avg} in GlobalMacros to the current load average. 2080 */ 2081 2082 void 2083 sm_getla() 2084 { 2085 char labuf[8]; 2086 2087 CurrentLA = getla(); 2088 (void) sm_snprintf(labuf, sizeof labuf, "%d", CurrentLA); 2089 macdefine(&GlobalMacros, A_TEMP, macid("{load_avg}"), labuf); 2090 } 2091 /* 2092 ** SHOULDQUEUE -- should this message be queued or sent? 2093 ** 2094 ** Compares the message cost to the load average to decide. 2095 ** 2096 ** Note: Do NOT change this API! It is documented in op.me 2097 ** and theoretically the user can change this function... 2098 ** 2099 ** Parameters: 2100 ** pri -- the priority of the message in question. 2101 ** ct -- the message creation time (unused, but see above). 2102 ** 2103 ** Returns: 2104 ** true -- if this message should be queued up for the 2105 ** time being. 2106 ** false -- if the load is low enough to send this message. 2107 ** 2108 ** Side Effects: 2109 ** none. 2110 */ 2111 2112 /* ARGSUSED1 */ 2113 bool 2114 shouldqueue(pri, ct) 2115 long pri; 2116 time_t ct; 2117 { 2118 bool rval; 2119 2120 if (tTd(3, 30)) 2121 sm_dprintf("shouldqueue: CurrentLA=%d, pri=%ld: ", 2122 CurrentLA, pri); 2123 if (CurrentLA < QueueLA) 2124 { 2125 if (tTd(3, 30)) 2126 sm_dprintf("false (CurrentLA < QueueLA)\n"); 2127 return false; 2128 } 2129 # if 0 /* this code is reported to cause oscillation around RefuseLA */ 2130 if (CurrentLA >= RefuseLA && QueueLA < RefuseLA) 2131 { 2132 if (tTd(3, 30)) 2133 sm_dprintf("TRUE (CurrentLA >= RefuseLA)\n"); 2134 return true; 2135 } 2136 # endif /* 0 */ 2137 rval = pri > (QueueFactor / (CurrentLA - QueueLA + 1)); 2138 if (tTd(3, 30)) 2139 sm_dprintf("%s (by calculation)\n", rval ? "true" : "false"); 2140 return rval; 2141 } 2142 /* 2143 ** REFUSECONNECTIONS -- decide if connections should be refused 2144 ** 2145 ** Parameters: 2146 ** name -- daemon name (for error messages only) 2147 ** e -- the current envelope. 2148 ** d -- number of daemon 2149 ** active -- was this daemon actually active? 2150 ** 2151 ** Returns: 2152 ** true if incoming SMTP connections should be refused 2153 ** (for now). 2154 ** false if we should accept new work. 2155 ** 2156 ** Side Effects: 2157 ** Sets process title when it is rejecting connections. 2158 */ 2159 2160 bool 2161 refuseconnections(name, e, d, active) 2162 char *name; 2163 ENVELOPE *e; 2164 int d; 2165 bool active; 2166 { 2167 static time_t lastconn[MAXDAEMONS]; 2168 static int conncnt[MAXDAEMONS]; 2169 2170 #if XLA 2171 if (!xla_smtp_ok()) 2172 return true; 2173 #endif /* XLA */ 2174 2175 if (ConnRateThrottle > 0) 2176 { 2177 time_t now; 2178 2179 now = curtime(); 2180 if (active) 2181 { 2182 if (now != lastconn[d]) 2183 { 2184 lastconn[d] = now; 2185 conncnt[d] = 1; 2186 } 2187 else if (conncnt[d]++ > ConnRateThrottle) 2188 { 2189 #define D_MSG_CRT "deferring connections on daemon %s: %d per second" 2190 /* sleep to flatten out connection load */ 2191 sm_setproctitle(true, e, D_MSG_CRT, 2192 name, ConnRateThrottle); 2193 if (LogLevel > 8) 2194 sm_syslog(LOG_INFO, NOQID, D_MSG_CRT, 2195 name, ConnRateThrottle); 2196 (void) sleep(1); 2197 } 2198 } 2199 else if (now != lastconn[d]) 2200 conncnt[d] = 0; 2201 } 2202 2203 sm_getla(); 2204 if (RefuseLA > 0 && CurrentLA >= RefuseLA) 2205 { 2206 # define R_MSG_LA "rejecting connections on daemon %s: load average: %d" 2207 sm_setproctitle(true, e, R_MSG_LA, name, CurrentLA); 2208 if (LogLevel > 8) 2209 sm_syslog(LOG_INFO, NOQID, R_MSG_LA, name, CurrentLA); 2210 return true; 2211 } 2212 2213 if (DelayLA > 0 && CurrentLA >= DelayLA) 2214 { 2215 time_t now; 2216 static time_t log_delay = (time_t) 0; 2217 2218 # define MIN_DELAY_LOG 90 /* wait before logging this again */ 2219 # define D_MSG_LA "delaying connections on daemon %s: load average=%d >= %d" 2220 /* sleep to flatten out connection load */ 2221 sm_setproctitle(true, e, D_MSG_LA, name, DelayLA); 2222 if (LogLevel > 8 && (now = curtime()) > log_delay) 2223 { 2224 sm_syslog(LOG_INFO, NOQID, D_MSG_LA, 2225 name, CurrentLA, DelayLA); 2226 log_delay = now + MIN_DELAY_LOG; 2227 } 2228 (void) sleep(1); 2229 } 2230 2231 if (MaxChildren > 0 && CurChildren >= MaxChildren) 2232 { 2233 proc_list_probe(); 2234 if (CurChildren >= MaxChildren) 2235 { 2236 #define R_MSG_CHILD "rejecting connections on daemon %s: %d children, max %d" 2237 sm_setproctitle(true, e, R_MSG_CHILD, 2238 name, CurChildren, MaxChildren); 2239 if (LogLevel > 8) 2240 sm_syslog(LOG_INFO, NOQID, R_MSG_CHILD, 2241 name, CurChildren, MaxChildren); 2242 return true; 2243 } 2244 } 2245 return false; 2246 } 2247 /* 2248 ** SETPROCTITLE -- set process title for ps 2249 ** 2250 ** Parameters: 2251 ** fmt -- a printf style format string. 2252 ** a, b, c -- possible parameters to fmt. 2253 ** 2254 ** Returns: 2255 ** none. 2256 ** 2257 ** Side Effects: 2258 ** Clobbers argv of our main procedure so ps(1) will 2259 ** display the title. 2260 */ 2261 2262 #define SPT_NONE 0 /* don't use it at all */ 2263 #define SPT_REUSEARGV 1 /* cover argv with title information */ 2264 #define SPT_BUILTIN 2 /* use libc builtin */ 2265 #define SPT_PSTAT 3 /* use pstat(PSTAT_SETCMD, ...) */ 2266 #define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */ 2267 #define SPT_SYSMIPS 5 /* use sysmips() supported by NEWS-OS 6 */ 2268 #define SPT_SCO 6 /* write kernel u. area */ 2269 #define SPT_CHANGEARGV 7 /* write our own strings into argv[] */ 2270 2271 #ifndef SPT_TYPE 2272 # define SPT_TYPE SPT_REUSEARGV 2273 #endif /* ! SPT_TYPE */ 2274 2275 2276 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN 2277 2278 # if SPT_TYPE == SPT_PSTAT 2279 # include <sys/pstat.h> 2280 # endif /* SPT_TYPE == SPT_PSTAT */ 2281 # if SPT_TYPE == SPT_PSSTRINGS 2282 # include <machine/vmparam.h> 2283 # include <sys/exec.h> 2284 # ifndef PS_STRINGS /* hmmmm.... apparently not available after all */ 2285 # undef SPT_TYPE 2286 # define SPT_TYPE SPT_REUSEARGV 2287 # else /* ! PS_STRINGS */ 2288 # ifndef NKPDE /* FreeBSD 2.0 */ 2289 # define NKPDE 63 2290 typedef unsigned int *pt_entry_t; 2291 # endif /* ! NKPDE */ 2292 # endif /* ! PS_STRINGS */ 2293 # endif /* SPT_TYPE == SPT_PSSTRINGS */ 2294 2295 # if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV 2296 # define SETPROC_STATIC static 2297 # else /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */ 2298 # define SETPROC_STATIC 2299 # endif /* SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV */ 2300 2301 # if SPT_TYPE == SPT_SYSMIPS 2302 # include <sys/sysmips.h> 2303 # include <sys/sysnews.h> 2304 # endif /* SPT_TYPE == SPT_SYSMIPS */ 2305 2306 # if SPT_TYPE == SPT_SCO 2307 # include <sys/immu.h> 2308 # include <sys/dir.h> 2309 # include <sys/user.h> 2310 # include <sys/fs/s5param.h> 2311 # if PSARGSZ > MAXLINE 2312 # define SPT_BUFSIZE PSARGSZ 2313 # endif /* PSARGSZ > MAXLINE */ 2314 # endif /* SPT_TYPE == SPT_SCO */ 2315 2316 # ifndef SPT_PADCHAR 2317 # define SPT_PADCHAR ' ' 2318 # endif /* ! SPT_PADCHAR */ 2319 2320 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */ 2321 2322 #ifndef SPT_BUFSIZE 2323 # define SPT_BUFSIZE MAXLINE 2324 #endif /* ! SPT_BUFSIZE */ 2325 2326 /* 2327 ** Pointers for setproctitle. 2328 ** This allows "ps" listings to give more useful information. 2329 */ 2330 2331 static char **Argv = NULL; /* pointer to argument vector */ 2332 static char *LastArgv = NULL; /* end of argv */ 2333 #if SPT_TYPE != SPT_BUILTIN 2334 static void setproctitle __P((const char *, ...)); 2335 #endif /* SPT_TYPE != SPT_BUILTIN */ 2336 2337 void 2338 initsetproctitle(argc, argv, envp) 2339 int argc; 2340 char **argv; 2341 char **envp; 2342 { 2343 register int i; 2344 extern char **environ; 2345 2346 /* 2347 ** Move the environment so setproctitle can use the space at 2348 ** the top of memory. 2349 */ 2350 2351 for (i = 0; envp[i] != NULL; i++) 2352 continue; 2353 environ = (char **) xalloc(sizeof (char *) * (i + 1)); 2354 for (i = 0; envp[i] != NULL; i++) 2355 environ[i] = newstr(envp[i]); 2356 environ[i] = NULL; 2357 2358 /* 2359 ** Save start and extent of argv for setproctitle. 2360 */ 2361 2362 Argv = argv; 2363 2364 /* 2365 ** Determine how much space we can use for setproctitle. 2366 ** Use all contiguous argv and envp pointers starting at argv[0] 2367 */ 2368 for (i = 0; i < argc; i++) 2369 { 2370 if (i == 0 || LastArgv + 1 == argv[i]) 2371 LastArgv = argv[i] + strlen(argv[i]); 2372 } 2373 for (i = 0; LastArgv != NULL && envp[i] != NULL; i++) 2374 { 2375 if (LastArgv + 1 == envp[i]) 2376 LastArgv = envp[i] + strlen(envp[i]); 2377 } 2378 } 2379 2380 #if SPT_TYPE != SPT_BUILTIN 2381 2382 /*VARARGS1*/ 2383 static void 2384 # ifdef __STDC__ 2385 setproctitle(const char *fmt, ...) 2386 # else /* __STDC__ */ 2387 setproctitle(fmt, va_alist) 2388 const char *fmt; 2389 va_dcl 2390 # endif /* __STDC__ */ 2391 { 2392 # if SPT_TYPE != SPT_NONE 2393 register int i; 2394 register char *p; 2395 SETPROC_STATIC char buf[SPT_BUFSIZE]; 2396 SM_VA_LOCAL_DECL 2397 # if SPT_TYPE == SPT_PSTAT 2398 union pstun pst; 2399 # endif /* SPT_TYPE == SPT_PSTAT */ 2400 # if SPT_TYPE == SPT_SCO 2401 int j; 2402 off_t seek_off; 2403 static int kmem = -1; 2404 static pid_t kmempid = -1; 2405 struct user u; 2406 # endif /* SPT_TYPE == SPT_SCO */ 2407 2408 p = buf; 2409 2410 /* print sendmail: heading for grep */ 2411 (void) sm_strlcpy(p, "sendmail: ", SPACELEFT(buf, p)); 2412 p += strlen(p); 2413 2414 /* print the argument string */ 2415 SM_VA_START(ap, fmt); 2416 (void) sm_vsnprintf(p, SPACELEFT(buf, p), fmt, ap); 2417 SM_VA_END(ap); 2418 2419 i = (int) strlen(buf); 2420 if (i < 0) 2421 return; 2422 2423 # if SPT_TYPE == SPT_PSTAT 2424 pst.pst_command = buf; 2425 pstat(PSTAT_SETCMD, pst, i, 0, 0); 2426 # endif /* SPT_TYPE == SPT_PSTAT */ 2427 # if SPT_TYPE == SPT_PSSTRINGS 2428 PS_STRINGS->ps_nargvstr = 1; 2429 PS_STRINGS->ps_argvstr = buf; 2430 # endif /* SPT_TYPE == SPT_PSSTRINGS */ 2431 # if SPT_TYPE == SPT_SYSMIPS 2432 sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf); 2433 # endif /* SPT_TYPE == SPT_SYSMIPS */ 2434 # if SPT_TYPE == SPT_SCO 2435 if (kmem < 0 || kmempid != CurrentPid) 2436 { 2437 if (kmem >= 0) 2438 (void) close(kmem); 2439 kmem = open(_PATH_KMEM, O_RDWR, 0); 2440 if (kmem < 0) 2441 return; 2442 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 || 2443 fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0) 2444 { 2445 (void) close(kmem); 2446 kmem = -1; 2447 return; 2448 } 2449 kmempid = CurrentPid; 2450 } 2451 buf[PSARGSZ - 1] = '\0'; 2452 seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u; 2453 if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off) 2454 (void) write(kmem, buf, PSARGSZ); 2455 # endif /* SPT_TYPE == SPT_SCO */ 2456 # if SPT_TYPE == SPT_REUSEARGV 2457 if (LastArgv == NULL) 2458 return; 2459 2460 if (i > LastArgv - Argv[0] - 2) 2461 { 2462 i = LastArgv - Argv[0] - 2; 2463 buf[i] = '\0'; 2464 } 2465 (void) sm_strlcpy(Argv[0], buf, i + 1); 2466 p = &Argv[0][i]; 2467 while (p < LastArgv) 2468 *p++ = SPT_PADCHAR; 2469 Argv[1] = NULL; 2470 # endif /* SPT_TYPE == SPT_REUSEARGV */ 2471 # if SPT_TYPE == SPT_CHANGEARGV 2472 Argv[0] = buf; 2473 Argv[1] = 0; 2474 # endif /* SPT_TYPE == SPT_CHANGEARGV */ 2475 # endif /* SPT_TYPE != SPT_NONE */ 2476 } 2477 2478 #endif /* SPT_TYPE != SPT_BUILTIN */ 2479 /* 2480 ** SM_SETPROCTITLE -- set process task and set process title for ps 2481 ** 2482 ** Possibly set process status and call setproctitle() to 2483 ** change the ps display. 2484 ** 2485 ** Parameters: 2486 ** status -- whether or not to store as process status 2487 ** e -- the current envelope. 2488 ** fmt -- a printf style format string. 2489 ** a, b, c -- possible parameters to fmt. 2490 ** 2491 ** Returns: 2492 ** none. 2493 */ 2494 2495 /*VARARGS2*/ 2496 void 2497 #ifdef __STDC__ 2498 sm_setproctitle(bool status, ENVELOPE *e, const char *fmt, ...) 2499 #else /* __STDC__ */ 2500 sm_setproctitle(status, e, fmt, va_alist) 2501 bool status; 2502 ENVELOPE *e; 2503 const char *fmt; 2504 va_dcl 2505 #endif /* __STDC__ */ 2506 { 2507 char buf[SPT_BUFSIZE]; 2508 SM_VA_LOCAL_DECL 2509 2510 /* print the argument string */ 2511 SM_VA_START(ap, fmt); 2512 (void) sm_vsnprintf(buf, sizeof buf, fmt, ap); 2513 SM_VA_END(ap); 2514 2515 if (status) 2516 proc_list_set(CurrentPid, buf); 2517 2518 if (ProcTitlePrefix != NULL) 2519 { 2520 char prefix[SPT_BUFSIZE]; 2521 2522 expand(ProcTitlePrefix, prefix, sizeof prefix, e); 2523 setproctitle("%s: %s", prefix, buf); 2524 } 2525 else 2526 setproctitle("%s", buf); 2527 } 2528 /* 2529 ** WAITFOR -- wait for a particular process id. 2530 ** 2531 ** Parameters: 2532 ** pid -- process id to wait for. 2533 ** 2534 ** Returns: 2535 ** status of pid. 2536 ** -1 if pid never shows up. 2537 ** 2538 ** Side Effects: 2539 ** none. 2540 */ 2541 2542 int 2543 waitfor(pid) 2544 pid_t pid; 2545 { 2546 int st; 2547 pid_t i; 2548 2549 do 2550 { 2551 errno = 0; 2552 i = sm_wait(&st); 2553 if (i > 0) 2554 proc_list_drop(i, st, NULL); 2555 } while ((i >= 0 || errno == EINTR) && i != pid); 2556 if (i < 0) 2557 return -1; 2558 return st; 2559 } 2560 /* 2561 ** SM_WAIT -- wait 2562 ** 2563 ** Parameters: 2564 ** status -- pointer to status (return value) 2565 ** 2566 ** Returns: 2567 ** pid 2568 */ 2569 2570 pid_t 2571 sm_wait(status) 2572 int *status; 2573 { 2574 # ifdef WAITUNION 2575 union wait st; 2576 # else /* WAITUNION */ 2577 auto int st; 2578 # endif /* WAITUNION */ 2579 pid_t i; 2580 # if defined(ISC_UNIX) || defined(_SCO_unix_) 2581 int savesig; 2582 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ 2583 2584 # if defined(ISC_UNIX) || defined(_SCO_unix_) 2585 savesig = sm_releasesignal(SIGCHLD); 2586 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ 2587 i = wait(&st); 2588 # if defined(ISC_UNIX) || defined(_SCO_unix_) 2589 if (savesig > 0) 2590 sm_blocksignal(SIGCHLD); 2591 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ 2592 # ifdef WAITUNION 2593 *status = st.w_status; 2594 # else /* WAITUNION */ 2595 *status = st; 2596 # endif /* WAITUNION */ 2597 return i; 2598 } 2599 /* 2600 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 2601 ** 2602 ** Parameters: 2603 ** sig -- the signal that got us here (unused). 2604 ** 2605 ** Returns: 2606 ** none. 2607 ** 2608 ** Side Effects: 2609 ** Picks up extant zombies. 2610 ** Control socket exits may restart/shutdown daemon. 2611 ** 2612 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2613 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2614 ** DOING. 2615 */ 2616 2617 /* ARGSUSED0 */ 2618 SIGFUNC_DECL 2619 reapchild(sig) 2620 int sig; 2621 { 2622 int m = 0; 2623 int save_errno = errno; 2624 int st; 2625 pid_t pid; 2626 # if HASWAITPID 2627 auto int status; 2628 int count; 2629 2630 count = 0; 2631 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 2632 { 2633 st = status; 2634 if (count++ > 1000) 2635 break; 2636 # else /* HASWAITPID */ 2637 # ifdef WNOHANG 2638 union wait status; 2639 2640 while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0) 2641 { 2642 st = status.w_status; 2643 # else /* WNOHANG */ 2644 auto int status; 2645 2646 /* 2647 ** Catch one zombie -- we will be re-invoked (we hope) if there 2648 ** are more. Unreliable signals probably break this, but this 2649 ** is the "old system" situation -- waitpid or wait3 are to be 2650 ** strongly preferred. 2651 */ 2652 2653 if ((pid = wait(&status)) > 0) 2654 { 2655 st = status; 2656 # endif /* WNOHANG */ 2657 # endif /* HASWAITPID */ 2658 /* Drop PID and check if it was a control socket child */ 2659 proc_list_drop(pid, st, NULL); 2660 CurRunners -= m; /* Update */ 2661 } 2662 FIX_SYSV_SIGNAL(sig, reapchild); 2663 errno = save_errno; 2664 return SIGFUNC_RETURN; 2665 } 2666 /* 2667 ** GETDTABLESIZE -- return number of file descriptors 2668 ** 2669 ** Only on non-BSD systems 2670 ** 2671 ** Parameters: 2672 ** none 2673 ** 2674 ** Returns: 2675 ** size of file descriptor table 2676 ** 2677 ** Side Effects: 2678 ** none 2679 */ 2680 2681 #ifdef SOLARIS 2682 # include <sys/resource.h> 2683 #endif /* SOLARIS */ 2684 2685 int 2686 getdtsize() 2687 { 2688 # ifdef RLIMIT_NOFILE 2689 struct rlimit rl; 2690 2691 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 2692 return rl.rlim_cur; 2693 # endif /* RLIMIT_NOFILE */ 2694 2695 # if HASGETDTABLESIZE 2696 return getdtablesize(); 2697 # else /* HASGETDTABLESIZE */ 2698 # ifdef _SC_OPEN_MAX 2699 return sysconf(_SC_OPEN_MAX); 2700 # else /* _SC_OPEN_MAX */ 2701 return NOFILE; 2702 # endif /* _SC_OPEN_MAX */ 2703 # endif /* HASGETDTABLESIZE */ 2704 } 2705 /* 2706 ** UNAME -- get the UUCP name of this system. 2707 */ 2708 2709 #if !HASUNAME 2710 2711 int 2712 uname(name) 2713 struct utsname *name; 2714 { 2715 SM_FILE_T *file; 2716 char *n; 2717 2718 name->nodename[0] = '\0'; 2719 2720 /* try /etc/whoami -- one line with the node name */ 2721 if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, "/etc/whoami", 2722 SM_IO_RDONLY, NULL)) != NULL) 2723 { 2724 (void) sm_io_fgets(file, SM_TIME_DEFAULT, name->nodename, 2725 NODE_LENGTH + 1); 2726 (void) sm_io_close(file, SM_TIME_DEFAULT); 2727 n = strchr(name->nodename, '\n'); 2728 if (n != NULL) 2729 *n = '\0'; 2730 if (name->nodename[0] != '\0') 2731 return 0; 2732 } 2733 2734 /* try /usr/include/whoami.h -- has a #define somewhere */ 2735 if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 2736 "/usr/include/whoami.h", SM_IO_RDONLY, NULL)) 2737 != NULL) 2738 { 2739 char buf[MAXLINE]; 2740 2741 while (sm_io_fgets(file, SM_TIME_DEFAULT, buf, MAXLINE) != NULL) 2742 { 2743 if (sm_io_sscanf(buf, "#define sysname \"%*[^\"]\"", 2744 NODE_LENGTH, name->nodename) > 0) 2745 break; 2746 } 2747 (void) sm_io_close(file, SM_TIME_DEFAULT); 2748 if (name->nodename[0] != '\0') 2749 return 0; 2750 } 2751 2752 # if 0 2753 /* 2754 ** Popen is known to have security holes. 2755 */ 2756 2757 /* try uuname -l to return local name */ 2758 if ((file = popen("uuname -l", "r")) != NULL) 2759 { 2760 (void) sm_io_fgets(file, SM_TIME_DEFAULT, name, 2761 NODE_LENGTH + 1); 2762 (void) pclose(file); 2763 n = strchr(name, '\n'); 2764 if (n != NULL) 2765 *n = '\0'; 2766 if (name->nodename[0] != '\0') 2767 return 0; 2768 } 2769 # endif /* 0 */ 2770 2771 return -1; 2772 } 2773 #endif /* !HASUNAME */ 2774 /* 2775 ** INITGROUPS -- initialize groups 2776 ** 2777 ** Stub implementation for System V style systems 2778 */ 2779 2780 #if !HASINITGROUPS 2781 2782 initgroups(name, basegid) 2783 char *name; 2784 int basegid; 2785 { 2786 return 0; 2787 } 2788 2789 #endif /* !HASINITGROUPS */ 2790 /* 2791 ** SETGROUPS -- set group list 2792 ** 2793 ** Stub implementation for systems that don't have group lists 2794 */ 2795 2796 #ifndef NGROUPS_MAX 2797 2798 int 2799 setgroups(ngroups, grouplist) 2800 int ngroups; 2801 GIDSET_T grouplist[]; 2802 { 2803 return 0; 2804 } 2805 2806 #endif /* ! NGROUPS_MAX */ 2807 /* 2808 ** SETSID -- set session id (for non-POSIX systems) 2809 */ 2810 2811 #if !HASSETSID 2812 2813 pid_t 2814 setsid __P ((void)) 2815 { 2816 # ifdef TIOCNOTTY 2817 int fd; 2818 2819 fd = open("/dev/tty", O_RDWR, 0); 2820 if (fd >= 0) 2821 { 2822 (void) ioctl(fd, TIOCNOTTY, (char *) 0); 2823 (void) close(fd); 2824 } 2825 # endif /* TIOCNOTTY */ 2826 # ifdef SYS5SETPGRP 2827 return setpgrp(); 2828 # else /* SYS5SETPGRP */ 2829 return setpgid(0, CurrentPid); 2830 # endif /* SYS5SETPGRP */ 2831 } 2832 2833 #endif /* !HASSETSID */ 2834 /* 2835 ** FSYNC -- dummy fsync 2836 */ 2837 2838 #if NEEDFSYNC 2839 2840 fsync(fd) 2841 int fd; 2842 { 2843 # ifdef O_SYNC 2844 return fcntl(fd, F_SETFL, O_SYNC); 2845 # else /* O_SYNC */ 2846 /* nothing we can do */ 2847 return 0; 2848 # endif /* O_SYNC */ 2849 } 2850 2851 #endif /* NEEDFSYNC */ 2852 /* 2853 ** DGUX_INET_ADDR -- inet_addr for DG/UX 2854 ** 2855 ** Data General DG/UX version of inet_addr returns a struct in_addr 2856 ** instead of a long. This patches things. Only needed on versions 2857 ** prior to 5.4.3. 2858 */ 2859 2860 #ifdef DGUX_5_4_2 2861 2862 # undef inet_addr 2863 2864 long 2865 dgux_inet_addr(host) 2866 char *host; 2867 { 2868 struct in_addr haddr; 2869 2870 haddr = inet_addr(host); 2871 return haddr.s_addr; 2872 } 2873 2874 #endif /* DGUX_5_4_2 */ 2875 /* 2876 ** GETOPT -- for old systems or systems with bogus implementations 2877 */ 2878 2879 #if !SM_CONF_GETOPT 2880 2881 /* 2882 * Copyright (c) 1985 Regents of the University of California. 2883 * All rights reserved. The Berkeley software License Agreement 2884 * specifies the terms and conditions for redistribution. 2885 */ 2886 2887 2888 /* 2889 ** this version hacked to add `atend' flag to allow state machine 2890 ** to reset if invoked by the program to scan args for a 2nd time 2891 */ 2892 2893 # if defined(LIBC_SCCS) && !defined(lint) 2894 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 2895 # endif /* defined(LIBC_SCCS) && !defined(lint) */ 2896 2897 /* 2898 ** get option letter from argument vector 2899 */ 2900 # ifdef _CONVEX_SOURCE 2901 extern int optind, opterr, optopt; 2902 extern char *optarg; 2903 # else /* _CONVEX_SOURCE */ 2904 int opterr = 1; /* if error message should be printed */ 2905 int optind = 1; /* index into parent argv vector */ 2906 int optopt = 0; /* character checked for validity */ 2907 char *optarg = NULL; /* argument associated with option */ 2908 # endif /* _CONVEX_SOURCE */ 2909 2910 # define BADCH (int)'?' 2911 # define EMSG "" 2912 # define tell(s) if (opterr) \ 2913 {sm_io_fputs(smioerr, SM_TIME_DEFAULT, *nargv); \ 2914 (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, s); \ 2915 (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, optopt); \ 2916 (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, '\n'); \ 2917 return BADCH;} 2918 2919 int 2920 getopt(nargc,nargv,ostr) 2921 int nargc; 2922 char *const *nargv; 2923 const char *ostr; 2924 { 2925 static char *place = EMSG; /* option letter processing */ 2926 static char atend = 0; 2927 register char *oli = NULL; /* option letter list index */ 2928 2929 if (atend) { 2930 atend = 0; 2931 place = EMSG; 2932 } 2933 if(!*place) { /* update scanning pointer */ 2934 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 2935 atend++; 2936 return -1; 2937 } 2938 if (*place == '-') { /* found "--" */ 2939 ++optind; 2940 atend++; 2941 return -1; 2942 } 2943 } /* option letter okay? */ 2944 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 2945 if (!*place) ++optind; 2946 tell(": illegal option -- "); 2947 } 2948 if (oli && *++oli != ':') { /* don't need argument */ 2949 optarg = NULL; 2950 if (!*place) ++optind; 2951 } 2952 else { /* need an argument */ 2953 if (*place) optarg = place; /* no white space */ 2954 else if (nargc <= ++optind) { /* no arg */ 2955 place = EMSG; 2956 tell(": option requires an argument -- "); 2957 } 2958 else optarg = nargv[optind]; /* white space */ 2959 place = EMSG; 2960 ++optind; 2961 } 2962 return optopt; /* dump back option letter */ 2963 } 2964 2965 #endif /* !SM_CONF_GETOPT */ 2966 /* 2967 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use 2968 ** 2969 ** Parameters: 2970 ** user -- the name of the user we are checking. 2971 ** shell -- the user's shell from /etc/passwd 2972 ** 2973 ** Returns: 2974 ** true -- if it is ok to use this for unrestricted access. 2975 ** false -- if the shell is restricted. 2976 */ 2977 2978 #if !HASGETUSERSHELL 2979 2980 # ifndef _PATH_SHELLS 2981 # define _PATH_SHELLS "/etc/shells" 2982 # endif /* ! _PATH_SHELLS */ 2983 2984 # if defined(_AIX3) || defined(_AIX4) 2985 # include <userconf.h> 2986 # if _AIX4 >= 40200 2987 # include <userpw.h> 2988 # endif /* _AIX4 >= 40200 */ 2989 # include <usersec.h> 2990 # endif /* defined(_AIX3) || defined(_AIX4) */ 2991 2992 static char *DefaultUserShells[] = 2993 { 2994 "/bin/sh", /* standard shell */ 2995 # ifdef MPE 2996 "/SYS/PUB/CI", 2997 # else /* MPE */ 2998 "/usr/bin/sh", 2999 "/bin/csh", /* C shell */ 3000 "/usr/bin/csh", 3001 # endif /* MPE */ 3002 # ifdef __hpux 3003 # ifdef V4FS 3004 "/usr/bin/rsh", /* restricted Bourne shell */ 3005 "/usr/bin/ksh", /* Korn shell */ 3006 "/usr/bin/rksh", /* restricted Korn shell */ 3007 "/usr/bin/pam", 3008 "/usr/bin/keysh", /* key shell (extended Korn shell) */ 3009 "/usr/bin/posix/sh", 3010 # else /* V4FS */ 3011 "/bin/rsh", /* restricted Bourne shell */ 3012 "/bin/ksh", /* Korn shell */ 3013 "/bin/rksh", /* restricted Korn shell */ 3014 "/bin/pam", 3015 "/usr/bin/keysh", /* key shell (extended Korn shell) */ 3016 "/bin/posix/sh", 3017 # endif /* V4FS */ 3018 # endif /* __hpux */ 3019 # if defined(_AIX3) || defined(_AIX4) 3020 "/bin/ksh", /* Korn shell */ 3021 "/usr/bin/ksh", 3022 "/bin/tsh", /* trusted shell */ 3023 "/usr/bin/tsh", 3024 "/bin/bsh", /* Bourne shell */ 3025 "/usr/bin/bsh", 3026 # endif /* defined(_AIX3) || defined(_AIX4) */ 3027 # if defined(__svr4__) || defined(__svr5__) 3028 "/bin/ksh", /* Korn shell */ 3029 "/usr/bin/ksh", 3030 # endif /* defined(__svr4__) || defined(__svr5__) */ 3031 # ifdef sgi 3032 "/sbin/sh", /* SGI's shells really live in /sbin */ 3033 "/sbin/csh", 3034 "/bin/ksh", /* Korn shell */ 3035 "/sbin/ksh", 3036 "/usr/bin/ksh", 3037 "/bin/tcsh", /* Extended csh */ 3038 "/usr/bin/tcsh", 3039 # endif /* sgi */ 3040 NULL 3041 }; 3042 3043 #endif /* !HASGETUSERSHELL */ 3044 3045 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/" 3046 3047 bool 3048 usershellok(user, shell) 3049 char *user; 3050 char *shell; 3051 { 3052 # if HASGETUSERSHELL 3053 register char *p; 3054 extern char *getusershell(); 3055 3056 if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') || 3057 ConfigLevel <= 1) 3058 return true; 3059 3060 setusershell(); 3061 while ((p = getusershell()) != NULL) 3062 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0) 3063 break; 3064 endusershell(); 3065 return p != NULL; 3066 # else /* HASGETUSERSHELL */ 3067 # if USEGETCONFATTR 3068 auto char *v; 3069 # endif /* USEGETCONFATTR */ 3070 register SM_FILE_T *shellf; 3071 char buf[MAXLINE]; 3072 3073 if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') || 3074 ConfigLevel <= 1) 3075 return true; 3076 3077 # if USEGETCONFATTR 3078 /* 3079 ** Naturally IBM has a "better" idea..... 3080 ** 3081 ** What a crock. This interface isn't documented, it is 3082 ** considered part of the security library (-ls), and it 3083 ** only works if you are running as root (since the list 3084 ** of valid shells is obviously a source of great concern). 3085 ** I recommend that you do NOT define USEGETCONFATTR, 3086 ** especially since you are going to have to set up an 3087 ** /etc/shells anyhow to handle the cases where getconfattr 3088 ** fails. 3089 */ 3090 3091 if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL) 3092 { 3093 while (*v != '\0') 3094 { 3095 if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0) 3096 return true; 3097 v += strlen(v) + 1; 3098 } 3099 return false; 3100 } 3101 # endif /* USEGETCONFATTR */ 3102 3103 shellf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_SHELLS, 3104 SM_IO_RDONLY, NULL); 3105 if (shellf == NULL) 3106 { 3107 /* no /etc/shells; see if it is one of the std shells */ 3108 char **d; 3109 3110 if (errno != ENOENT && LogLevel > 3) 3111 sm_syslog(LOG_ERR, NOQID, 3112 "usershellok: cannot open %s: %s", 3113 _PATH_SHELLS, sm_errstring(errno)); 3114 3115 for (d = DefaultUserShells; *d != NULL; d++) 3116 { 3117 if (strcmp(shell, *d) == 0) 3118 return true; 3119 } 3120 return false; 3121 } 3122 3123 while (sm_io_fgets(shellf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 3124 { 3125 register char *p, *q; 3126 3127 p = buf; 3128 while (*p != '\0' && *p != '#' && *p != '/') 3129 p++; 3130 if (*p == '#' || *p == '\0') 3131 continue; 3132 q = p; 3133 while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p))) 3134 p++; 3135 *p = '\0'; 3136 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0) 3137 { 3138 (void) sm_io_close(shellf, SM_TIME_DEFAULT); 3139 return true; 3140 } 3141 } 3142 (void) sm_io_close(shellf, SM_TIME_DEFAULT); 3143 return false; 3144 # endif /* HASGETUSERSHELL */ 3145 } 3146 /* 3147 ** FREEDISKSPACE -- see how much free space is on the queue filesystem 3148 ** 3149 ** Only implemented if you have statfs. 3150 ** 3151 ** Parameters: 3152 ** dir -- the directory in question. 3153 ** bsize -- a variable into which the filesystem 3154 ** block size is stored. 3155 ** 3156 ** Returns: 3157 ** The number of blocks free on the queue filesystem. 3158 ** -1 if the statfs call fails. 3159 ** 3160 ** Side effects: 3161 ** Puts the filesystem block size into bsize. 3162 */ 3163 3164 /* statfs types */ 3165 # define SFS_NONE 0 /* no statfs implementation */ 3166 # define SFS_USTAT 1 /* use ustat */ 3167 # define SFS_4ARGS 2 /* use four-argument statfs call */ 3168 # define SFS_VFS 3 /* use <sys/vfs.h> implementation */ 3169 # define SFS_MOUNT 4 /* use <sys/mount.h> implementation */ 3170 # define SFS_STATFS 5 /* use <sys/statfs.h> implementation */ 3171 # define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */ 3172 3173 # ifndef SFS_TYPE 3174 # define SFS_TYPE SFS_NONE 3175 # endif /* ! SFS_TYPE */ 3176 3177 # if SFS_TYPE == SFS_USTAT 3178 # include <ustat.h> 3179 # endif /* SFS_TYPE == SFS_USTAT */ 3180 # if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS 3181 # include <sys/statfs.h> 3182 # endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */ 3183 # if SFS_TYPE == SFS_VFS 3184 # include <sys/vfs.h> 3185 # endif /* SFS_TYPE == SFS_VFS */ 3186 # if SFS_TYPE == SFS_MOUNT 3187 # include <sys/mount.h> 3188 # endif /* SFS_TYPE == SFS_MOUNT */ 3189 # if SFS_TYPE == SFS_STATVFS 3190 # include <sys/statvfs.h> 3191 # endif /* SFS_TYPE == SFS_STATVFS */ 3192 3193 long 3194 freediskspace(dir, bsize) 3195 char *dir; 3196 long *bsize; 3197 { 3198 # if SFS_TYPE == SFS_NONE 3199 if (bsize != NULL) 3200 *bsize = 4096L; 3201 3202 /* assume free space is plentiful */ 3203 return (long) LONG_MAX; 3204 # else /* SFS_TYPE == SFS_NONE */ 3205 # if SFS_TYPE == SFS_USTAT 3206 struct ustat fs; 3207 struct stat statbuf; 3208 # define FSBLOCKSIZE DEV_BSIZE 3209 # define SFS_BAVAIL f_tfree 3210 # else /* SFS_TYPE == SFS_USTAT */ 3211 # if defined(ultrix) 3212 struct fs_data fs; 3213 # define SFS_BAVAIL fd_bfreen 3214 # define FSBLOCKSIZE 1024L 3215 # else /* defined(ultrix) */ 3216 # if SFS_TYPE == SFS_STATVFS 3217 struct statvfs fs; 3218 # define FSBLOCKSIZE fs.f_frsize 3219 # else /* SFS_TYPE == SFS_STATVFS */ 3220 struct statfs fs; 3221 # define FSBLOCKSIZE fs.f_bsize 3222 # endif /* SFS_TYPE == SFS_STATVFS */ 3223 # endif /* defined(ultrix) */ 3224 # endif /* SFS_TYPE == SFS_USTAT */ 3225 # ifndef SFS_BAVAIL 3226 # define SFS_BAVAIL f_bavail 3227 # endif /* ! SFS_BAVAIL */ 3228 3229 # if SFS_TYPE == SFS_USTAT 3230 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 3231 # else /* SFS_TYPE == SFS_USTAT */ 3232 # if SFS_TYPE == SFS_4ARGS 3233 if (statfs(dir, &fs, sizeof fs, 0) == 0) 3234 # else /* SFS_TYPE == SFS_4ARGS */ 3235 # if SFS_TYPE == SFS_STATVFS 3236 if (statvfs(dir, &fs) == 0) 3237 # else /* SFS_TYPE == SFS_STATVFS */ 3238 # if defined(ultrix) 3239 if (statfs(dir, &fs) > 0) 3240 # else /* defined(ultrix) */ 3241 if (statfs(dir, &fs) == 0) 3242 # endif /* defined(ultrix) */ 3243 # endif /* SFS_TYPE == SFS_STATVFS */ 3244 # endif /* SFS_TYPE == SFS_4ARGS */ 3245 # endif /* SFS_TYPE == SFS_USTAT */ 3246 { 3247 if (bsize != NULL) 3248 *bsize = FSBLOCKSIZE; 3249 if (fs.SFS_BAVAIL <= 0) 3250 return 0; 3251 else if (fs.SFS_BAVAIL > LONG_MAX) 3252 return (long) LONG_MAX; 3253 else 3254 return (long) fs.SFS_BAVAIL; 3255 } 3256 return -1; 3257 # endif /* SFS_TYPE == SFS_NONE */ 3258 } 3259 /* 3260 ** ENOUGHDISKSPACE -- is there enough free space on the queue file systems? 3261 ** 3262 ** Parameters: 3263 ** msize -- the size to check against. If zero, we don't yet 3264 ** know how big the message will be, so just check for 3265 ** a "reasonable" amount. 3266 ** e -- envelope, or NULL -- controls logging 3267 ** 3268 ** Returns: 3269 ** true if in every queue group there is at least one 3270 ** queue directory whose file system contains enough free space. 3271 ** false otherwise. 3272 ** 3273 ** Side Effects: 3274 ** If there is not enough disk space and e != NULL 3275 ** then sm_syslog is called. 3276 */ 3277 3278 bool 3279 enoughdiskspace(msize, e) 3280 long msize; 3281 ENVELOPE *e; 3282 { 3283 int i; 3284 3285 if (MinBlocksFree <= 0 && msize <= 0) 3286 { 3287 if (tTd(4, 80)) 3288 sm_dprintf("enoughdiskspace: no threshold\n"); 3289 return true; 3290 } 3291 3292 filesys_update(); 3293 for (i = 0; i < NumQueue; ++i) 3294 { 3295 if (pickqdir(Queue[i], msize, e) < 0) 3296 return false; 3297 } 3298 return true; 3299 } 3300 /* 3301 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 3302 ** 3303 ** This looks at an errno value and tells if this is likely to 3304 ** go away if retried later. 3305 ** 3306 ** Parameters: 3307 ** err -- the errno code to classify. 3308 ** 3309 ** Returns: 3310 ** true if this is probably transient. 3311 ** false otherwise. 3312 */ 3313 3314 bool 3315 transienterror(err) 3316 int err; 3317 { 3318 switch (err) 3319 { 3320 case EIO: /* I/O error */ 3321 case ENXIO: /* Device not configured */ 3322 case EAGAIN: /* Resource temporarily unavailable */ 3323 case ENOMEM: /* Cannot allocate memory */ 3324 case ENODEV: /* Operation not supported by device */ 3325 case ENFILE: /* Too many open files in system */ 3326 case EMFILE: /* Too many open files */ 3327 case ENOSPC: /* No space left on device */ 3328 case ETIMEDOUT: /* Connection timed out */ 3329 #ifdef ESTALE 3330 case ESTALE: /* Stale NFS file handle */ 3331 #endif /* ESTALE */ 3332 #ifdef ENETDOWN 3333 case ENETDOWN: /* Network is down */ 3334 #endif /* ENETDOWN */ 3335 #ifdef ENETUNREACH 3336 case ENETUNREACH: /* Network is unreachable */ 3337 #endif /* ENETUNREACH */ 3338 #ifdef ENETRESET 3339 case ENETRESET: /* Network dropped connection on reset */ 3340 #endif /* ENETRESET */ 3341 #ifdef ECONNABORTED 3342 case ECONNABORTED: /* Software caused connection abort */ 3343 #endif /* ECONNABORTED */ 3344 #ifdef ECONNRESET 3345 case ECONNRESET: /* Connection reset by peer */ 3346 #endif /* ECONNRESET */ 3347 #ifdef ENOBUFS 3348 case ENOBUFS: /* No buffer space available */ 3349 #endif /* ENOBUFS */ 3350 #ifdef ESHUTDOWN 3351 case ESHUTDOWN: /* Can't send after socket shutdown */ 3352 #endif /* ESHUTDOWN */ 3353 #ifdef ECONNREFUSED 3354 case ECONNREFUSED: /* Connection refused */ 3355 #endif /* ECONNREFUSED */ 3356 #ifdef EHOSTDOWN 3357 case EHOSTDOWN: /* Host is down */ 3358 #endif /* EHOSTDOWN */ 3359 #ifdef EHOSTUNREACH 3360 case EHOSTUNREACH: /* No route to host */ 3361 #endif /* EHOSTUNREACH */ 3362 #ifdef EDQUOT 3363 case EDQUOT: /* Disc quota exceeded */ 3364 #endif /* EDQUOT */ 3365 #ifdef EPROCLIM 3366 case EPROCLIM: /* Too many processes */ 3367 #endif /* EPROCLIM */ 3368 #ifdef EUSERS 3369 case EUSERS: /* Too many users */ 3370 #endif /* EUSERS */ 3371 #ifdef EDEADLK 3372 case EDEADLK: /* Resource deadlock avoided */ 3373 #endif /* EDEADLK */ 3374 #ifdef EISCONN 3375 case EISCONN: /* Socket already connected */ 3376 #endif /* EISCONN */ 3377 #ifdef EINPROGRESS 3378 case EINPROGRESS: /* Operation now in progress */ 3379 #endif /* EINPROGRESS */ 3380 #ifdef EALREADY 3381 case EALREADY: /* Operation already in progress */ 3382 #endif /* EALREADY */ 3383 #ifdef EADDRINUSE 3384 case EADDRINUSE: /* Address already in use */ 3385 #endif /* EADDRINUSE */ 3386 #ifdef EADDRNOTAVAIL 3387 case EADDRNOTAVAIL: /* Can't assign requested address */ 3388 #endif /* EADDRNOTAVAIL */ 3389 #ifdef ETXTBSY 3390 case ETXTBSY: /* (Apollo) file locked */ 3391 #endif /* ETXTBSY */ 3392 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 3393 case ENOSR: /* Out of streams resources */ 3394 #endif /* defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) */ 3395 #ifdef ENOLCK 3396 case ENOLCK: /* No locks available */ 3397 #endif /* ENOLCK */ 3398 case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */ 3399 return true; 3400 } 3401 3402 /* nope, must be permanent */ 3403 return false; 3404 } 3405 /* 3406 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 3407 ** 3408 ** Parameters: 3409 ** fd -- the file descriptor of the file. 3410 ** filename -- the file name (for error messages). 3411 ** ext -- the filename extension. 3412 ** type -- type of the lock. Bits can be: 3413 ** LOCK_EX -- exclusive lock. 3414 ** LOCK_NB -- non-blocking. 3415 ** LOCK_UN -- unlock. 3416 ** 3417 ** Returns: 3418 ** true if the lock was acquired. 3419 ** false otherwise. 3420 */ 3421 3422 bool 3423 lockfile(fd, filename, ext, type) 3424 int fd; 3425 char *filename; 3426 char *ext; 3427 int type; 3428 { 3429 int i; 3430 int save_errno; 3431 # if !HASFLOCK 3432 int action; 3433 struct flock lfd; 3434 3435 if (ext == NULL) 3436 ext = ""; 3437 3438 memset(&lfd, '\0', sizeof lfd); 3439 if (bitset(LOCK_UN, type)) 3440 lfd.l_type = F_UNLCK; 3441 else if (bitset(LOCK_EX, type)) 3442 lfd.l_type = F_WRLCK; 3443 else 3444 lfd.l_type = F_RDLCK; 3445 3446 if (bitset(LOCK_NB, type)) 3447 action = F_SETLK; 3448 else 3449 action = F_SETLKW; 3450 3451 if (tTd(55, 60)) 3452 sm_dprintf("lockfile(%s%s, action=%d, type=%d): ", 3453 filename, ext, action, lfd.l_type); 3454 3455 while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR) 3456 continue; 3457 if (i >= 0) 3458 { 3459 if (tTd(55, 60)) 3460 sm_dprintf("SUCCESS\n"); 3461 return true; 3462 } 3463 save_errno = errno; 3464 3465 if (tTd(55, 60)) 3466 sm_dprintf("(%s) ", sm_errstring(save_errno)); 3467 3468 /* 3469 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 3470 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 3471 ** as type "tmp" (that is, served from swap space), the 3472 ** previous fcntl will fail with "Invalid argument" errors. 3473 ** Since this is fairly common during testing, we will assume 3474 ** that this indicates that the lock is successfully grabbed. 3475 */ 3476 3477 if (save_errno == EINVAL) 3478 { 3479 if (tTd(55, 60)) 3480 sm_dprintf("SUCCESS\n"); 3481 return true; 3482 } 3483 3484 if (!bitset(LOCK_NB, type) || 3485 (save_errno != EACCES && save_errno != EAGAIN)) 3486 { 3487 int omode = -1; 3488 # ifdef F_GETFL 3489 (void) fcntl(fd, F_GETFL, &omode); 3490 errno = save_errno; 3491 # endif /* F_GETFL */ 3492 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 3493 filename, ext, fd, type, omode, geteuid()); 3494 dumpfd(fd, true, true); 3495 } 3496 # else /* !HASFLOCK */ 3497 if (ext == NULL) 3498 ext = ""; 3499 3500 if (tTd(55, 60)) 3501 sm_dprintf("lockfile(%s%s, type=%o): ", filename, ext, type); 3502 3503 while ((i = flock(fd, type)) < 0 && errno == EINTR) 3504 continue; 3505 if (i >= 0) 3506 { 3507 if (tTd(55, 60)) 3508 sm_dprintf("SUCCESS\n"); 3509 return true; 3510 } 3511 save_errno = errno; 3512 3513 if (tTd(55, 60)) 3514 sm_dprintf("(%s) ", sm_errstring(save_errno)); 3515 3516 if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK) 3517 { 3518 int omode = -1; 3519 # ifdef F_GETFL 3520 (void) fcntl(fd, F_GETFL, &omode); 3521 errno = save_errno; 3522 # endif /* F_GETFL */ 3523 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 3524 filename, ext, fd, type, omode, geteuid()); 3525 dumpfd(fd, true, true); 3526 } 3527 # endif /* !HASFLOCK */ 3528 if (tTd(55, 60)) 3529 sm_dprintf("FAIL\n"); 3530 errno = save_errno; 3531 return false; 3532 } 3533 /* 3534 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) 3535 ** 3536 ** Unfortunately, given that we can't predict other systems on which 3537 ** a remote mounted (NFS) filesystem will be mounted, the answer is 3538 ** almost always that this is unsafe. 3539 ** 3540 ** Note also that many operating systems have non-compliant 3541 ** implementations of the _POSIX_CHOWN_RESTRICTED variable and the 3542 ** fpathconf() routine. According to IEEE 1003.1-1990, if 3543 ** _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then 3544 ** no non-root process can give away the file. However, vendors 3545 ** don't take NFS into account, so a comfortable value of 3546 ** _POSIX_CHOWN_RESTRICTED tells us nothing. 3547 ** 3548 ** Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf() 3549 ** even on files where chown is not restricted. Many systems get 3550 ** this wrong on NFS-based filesystems (that is, they say that chown 3551 ** is restricted [safe] on NFS filesystems where it may not be, since 3552 ** other systems can access the same filesystem and do file giveaway; 3553 ** only the NFS server knows for sure!) Hence, it is important to 3554 ** get the value of SAFENFSPATHCONF correct -- it should be defined 3555 ** _only_ after testing (see test/t_pathconf.c) a system on an unsafe 3556 ** NFS-based filesystem to ensure that you can get meaningful results. 3557 ** If in doubt, assume unsafe! 3558 ** 3559 ** You may also need to tweak IS_SAFE_CHOWN -- it should be a 3560 ** condition indicating whether the return from pathconf indicates 3561 ** that chown is safe (typically either > 0 or >= 0 -- there isn't 3562 ** even any agreement about whether a zero return means that a file 3563 ** is or is not safe). It defaults to "> 0". 3564 ** 3565 ** If the parent directory is safe (writable only by owner back 3566 ** to the root) then we can relax slightly and trust fpathconf 3567 ** in more circumstances. This is really a crock -- if this is an 3568 ** NFS mounted filesystem then we really know nothing about the 3569 ** underlying implementation. However, most systems pessimize and 3570 ** return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which 3571 ** we interpret as unsafe, as we should. Thus, this heuristic gets 3572 ** us into a possible problem only on systems that have a broken 3573 ** pathconf implementation and which are also poorly configured 3574 ** (have :include: files in group- or world-writable directories). 3575 ** 3576 ** Parameters: 3577 ** fd -- the file descriptor to check. 3578 ** safedir -- set if the parent directory is safe. 3579 ** 3580 ** Returns: 3581 ** true -- if the chown(2) operation is "safe" -- that is, 3582 ** only root can chown the file to an arbitrary user. 3583 ** false -- if an arbitrary user can give away a file. 3584 */ 3585 3586 #ifndef IS_SAFE_CHOWN 3587 # define IS_SAFE_CHOWN > 0 3588 #endif /* ! IS_SAFE_CHOWN */ 3589 3590 bool 3591 chownsafe(fd, safedir) 3592 int fd; 3593 bool safedir; 3594 { 3595 # if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ 3596 (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H)) 3597 int rval; 3598 3599 /* give the system administrator a chance to override */ 3600 if (bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail)) 3601 return true; 3602 3603 /* 3604 ** Some systems (e.g., SunOS) seem to have the call and the 3605 ** #define _PC_CHOWN_RESTRICTED, but don't actually implement 3606 ** the call. This heuristic checks for that. 3607 */ 3608 3609 errno = 0; 3610 rval = fpathconf(fd, _PC_CHOWN_RESTRICTED); 3611 # if SAFENFSPATHCONF 3612 return errno == 0 && rval IS_SAFE_CHOWN; 3613 # else /* SAFENFSPATHCONF */ 3614 return safedir && errno == 0 && rval IS_SAFE_CHOWN; 3615 # endif /* SAFENFSPATHCONF */ 3616 # else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */ 3617 return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail); 3618 # endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */ 3619 } 3620 /* 3621 ** RESETLIMITS -- reset system controlled resource limits 3622 ** 3623 ** This is to avoid denial-of-service attacks 3624 ** 3625 ** Parameters: 3626 ** none 3627 ** 3628 ** Returns: 3629 ** none 3630 */ 3631 3632 #if HASSETRLIMIT 3633 # ifdef RLIMIT_NEEDS_SYS_TIME_H 3634 # include <sys/time.h> 3635 # endif /* RLIMIT_NEEDS_SYS_TIME_H */ 3636 # include <sys/resource.h> 3637 #endif /* HASSETRLIMIT */ 3638 #ifndef FD_SETSIZE 3639 # define FD_SETSIZE 256 3640 #endif /* ! FD_SETSIZE */ 3641 3642 void 3643 resetlimits() 3644 { 3645 #if HASSETRLIMIT 3646 struct rlimit lim; 3647 3648 lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; 3649 (void) setrlimit(RLIMIT_CPU, &lim); 3650 (void) setrlimit(RLIMIT_FSIZE, &lim); 3651 # ifdef RLIMIT_NOFILE 3652 lim.rlim_cur = lim.rlim_max = FD_SETSIZE; 3653 (void) setrlimit(RLIMIT_NOFILE, &lim); 3654 # endif /* RLIMIT_NOFILE */ 3655 #else /* HASSETRLIMIT */ 3656 # if HASULIMIT 3657 (void) ulimit(2, 0x3fffff); 3658 (void) ulimit(4, FD_SETSIZE); 3659 # endif /* HASULIMIT */ 3660 #endif /* HASSETRLIMIT */ 3661 errno = 0; 3662 } 3663 /* 3664 ** SETVENDOR -- process vendor code from V configuration line 3665 ** 3666 ** Parameters: 3667 ** vendor -- string representation of vendor. 3668 ** 3669 ** Returns: 3670 ** true -- if ok. 3671 ** false -- if vendor code could not be processed. 3672 ** 3673 ** Side Effects: 3674 ** It is reasonable to set mode flags here to tweak 3675 ** processing in other parts of the code if necessary. 3676 ** For example, if you are a vendor that uses $%y to 3677 ** indicate YP lookups, you could enable that here. 3678 */ 3679 3680 bool 3681 setvendor(vendor) 3682 char *vendor; 3683 { 3684 if (sm_strcasecmp(vendor, "Berkeley") == 0) 3685 { 3686 VendorCode = VENDOR_BERKELEY; 3687 return true; 3688 } 3689 3690 /* add vendor extensions here */ 3691 3692 #ifdef SUN_EXTENSIONS 3693 if (sm_strcasecmp(vendor, "Sun") == 0) 3694 { 3695 VendorCode = VENDOR_SUN; 3696 return true; 3697 } 3698 #endif /* SUN_EXTENSIONS */ 3699 3700 #if defined(VENDOR_NAME) && defined(VENDOR_CODE) 3701 if (sm_strcasecmp(vendor, VENDOR_NAME) == 0) 3702 { 3703 VendorCode = VENDOR_CODE; 3704 return true; 3705 } 3706 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */ 3707 3708 return false; 3709 } 3710 /* 3711 ** GETVENDOR -- return vendor name based on vendor code 3712 ** 3713 ** Parameters: 3714 ** vendorcode -- numeric representation of vendor. 3715 ** 3716 ** Returns: 3717 ** string containing vendor name. 3718 */ 3719 3720 char * 3721 getvendor(vendorcode) 3722 int vendorcode; 3723 { 3724 #if defined(VENDOR_NAME) && defined(VENDOR_CODE) 3725 /* 3726 ** Can't have the same switch case twice so need to 3727 ** handle VENDOR_CODE outside of switch. It might 3728 ** match one of the existing VENDOR_* codes. 3729 */ 3730 3731 if (vendorcode == VENDOR_CODE) 3732 return VENDOR_NAME; 3733 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */ 3734 3735 switch (vendorcode) 3736 { 3737 case VENDOR_BERKELEY: 3738 return "Berkeley"; 3739 3740 case VENDOR_SUN: 3741 return "Sun"; 3742 3743 case VENDOR_HP: 3744 return "HP"; 3745 3746 case VENDOR_IBM: 3747 return "IBM"; 3748 3749 case VENDOR_SENDMAIL: 3750 return "Sendmail"; 3751 3752 default: 3753 return "Unknown"; 3754 } 3755 } 3756 /* 3757 ** VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults 3758 ** 3759 ** Vendor_pre_defaults is called before reading the configuration 3760 ** file; vendor_post_defaults is called immediately after. 3761 ** 3762 ** Parameters: 3763 ** e -- the global environment to initialize. 3764 ** 3765 ** Returns: 3766 ** none. 3767 */ 3768 3769 #if SHARE_V1 3770 int DefShareUid; /* default share uid to run as -- unused??? */ 3771 #endif /* SHARE_V1 */ 3772 3773 void 3774 vendor_pre_defaults(e) 3775 ENVELOPE *e; 3776 { 3777 #if SHARE_V1 3778 /* OTHERUID is defined in shares.h, do not be alarmed */ 3779 DefShareUid = OTHERUID; 3780 #endif /* SHARE_V1 */ 3781 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) 3782 sun_pre_defaults(e); 3783 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */ 3784 #ifdef apollo 3785 /* 3786 ** stupid domain/os can't even open 3787 ** /etc/mail/sendmail.cf without this 3788 */ 3789 3790 setuserenv("ISP", NULL); 3791 setuserenv("SYSTYPE", NULL); 3792 #endif /* apollo */ 3793 } 3794 3795 3796 void 3797 vendor_post_defaults(e) 3798 ENVELOPE *e; 3799 { 3800 #ifdef __QNX__ 3801 char *p; 3802 3803 /* Makes sure the SOCK environment variable remains */ 3804 if (p = getextenv("SOCK")) 3805 setuserenv("SOCK", p); 3806 #endif /* __QNX__ */ 3807 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) 3808 sun_post_defaults(e); 3809 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */ 3810 } 3811 /* 3812 ** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode 3813 */ 3814 3815 void 3816 vendor_daemon_setup(e) 3817 ENVELOPE *e; 3818 { 3819 #if HASSETLOGIN 3820 (void) setlogin(RunAsUserName); 3821 #endif /* HASSETLOGIN */ 3822 #if SECUREWARE 3823 if (getluid() != -1) 3824 { 3825 usrerr("Daemon cannot have LUID"); 3826 finis(false, true, EX_USAGE); 3827 } 3828 #endif /* SECUREWARE */ 3829 } 3830 /* 3831 ** VENDOR_SET_UID -- do setup for setting a user id 3832 ** 3833 ** This is called when we are still root. 3834 ** 3835 ** Parameters: 3836 ** uid -- the uid we are about to become. 3837 ** 3838 ** Returns: 3839 ** none. 3840 */ 3841 3842 void 3843 vendor_set_uid(uid) 3844 UID_T uid; 3845 { 3846 /* 3847 ** We need to setup the share groups (lnodes) 3848 ** and add auditing information (luid's) 3849 ** before we loose our ``root''ness. 3850 */ 3851 #if SHARE_V1 3852 if (setupshares(uid, syserr) != 0) 3853 syserr("Unable to set up shares"); 3854 #endif /* SHARE_V1 */ 3855 #if SECUREWARE 3856 (void) setup_secure(uid); 3857 #endif /* SECUREWARE */ 3858 } 3859 /* 3860 ** VALIDATE_CONNECTION -- check connection for rationality 3861 ** 3862 ** If the connection is rejected, this routine should log an 3863 ** appropriate message -- but should never issue any SMTP protocol. 3864 ** 3865 ** Parameters: 3866 ** sap -- a pointer to a SOCKADDR naming the peer. 3867 ** hostname -- the name corresponding to sap. 3868 ** e -- the current envelope. 3869 ** 3870 ** Returns: 3871 ** error message from rejection. 3872 ** NULL if not rejected. 3873 */ 3874 3875 #if TCPWRAPPERS 3876 # include <tcpd.h> 3877 3878 /* tcpwrappers does no logging, but you still have to declare these -- ugh */ 3879 int allow_severity = LOG_INFO; 3880 int deny_severity = LOG_NOTICE; 3881 #endif /* TCPWRAPPERS */ 3882 3883 char * 3884 validate_connection(sap, hostname, e) 3885 SOCKADDR *sap; 3886 char *hostname; 3887 ENVELOPE *e; 3888 { 3889 #if TCPWRAPPERS 3890 char *host; 3891 char *addr; 3892 extern int hosts_ctl(); 3893 #endif /* TCPWRAPPERS */ 3894 3895 if (tTd(48, 3)) 3896 sm_dprintf("validate_connection(%s, %s)\n", 3897 hostname, anynet_ntoa(sap)); 3898 3899 if (rscheck("check_relay", hostname, anynet_ntoa(sap), 3900 e, true, true, 3, NULL, NOQID) != EX_OK) 3901 { 3902 static char reject[BUFSIZ*2]; 3903 extern char MsgBuf[]; 3904 3905 if (tTd(48, 4)) 3906 sm_dprintf(" ... validate_connection: BAD (rscheck)\n"); 3907 3908 if (strlen(MsgBuf) >= 3) 3909 (void) sm_strlcpy(reject, MsgBuf, sizeof reject); 3910 else 3911 (void) sm_strlcpy(reject, "Access denied", sizeof reject); 3912 3913 return reject; 3914 } 3915 3916 #if TCPWRAPPERS 3917 if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']') 3918 host = "unknown"; 3919 else 3920 host = hostname; 3921 addr = anynet_ntoa(sap); 3922 3923 # if NETINET6 3924 /* TCP/Wrappers don't want the IPv6: protocol label */ 3925 if (addr != NULL && sm_strncasecmp(addr, "IPv6:", 5) == 0) 3926 addr += 5; 3927 # endif /* NETINET6 */ 3928 3929 if (!hosts_ctl("sendmail", host, addr, STRING_UNKNOWN)) 3930 { 3931 if (tTd(48, 4)) 3932 sm_dprintf(" ... validate_connection: BAD (tcpwrappers)\n"); 3933 if (LogLevel > 3) 3934 sm_syslog(LOG_NOTICE, e->e_id, 3935 "tcpwrappers (%s, %s) rejection", 3936 host, addr); 3937 return "Access denied"; 3938 } 3939 #endif /* TCPWRAPPERS */ 3940 if (tTd(48, 4)) 3941 sm_dprintf(" ... validate_connection: OK\n"); 3942 return NULL; 3943 } 3944 3945 /* 3946 ** STRTOL -- convert string to long integer 3947 ** 3948 ** For systems that don't have it in the C library. 3949 ** 3950 ** This is taken verbatim from the 4.4-Lite C library. 3951 */ 3952 3953 #if NEEDSTRTOL 3954 3955 # if defined(LIBC_SCCS) && !defined(lint) 3956 static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 3957 # endif /* defined(LIBC_SCCS) && !defined(lint) */ 3958 3959 /* 3960 ** Convert a string to a long integer. 3961 ** 3962 ** Ignores `locale' stuff. Assumes that the upper and lower case 3963 ** alphabets and digits are each contiguous. 3964 */ 3965 3966 long 3967 strtol(nptr, endptr, base) 3968 const char *nptr; 3969 char **endptr; 3970 register int base; 3971 { 3972 register const char *s = nptr; 3973 register unsigned long acc; 3974 register int c; 3975 register unsigned long cutoff; 3976 register int neg = 0, any, cutlim; 3977 3978 /* 3979 ** Skip white space and pick up leading +/- sign if any. 3980 ** If base is 0, allow 0x for hex and 0 for octal, else 3981 ** assume decimal; if base is already 16, allow 0x. 3982 */ 3983 do { 3984 c = *s++; 3985 } while (isspace(c)); 3986 if (c == '-') { 3987 neg = 1; 3988 c = *s++; 3989 } else if (c == '+') 3990 c = *s++; 3991 if ((base == 0 || base == 16) && 3992 c == '0' && (*s == 'x' || *s == 'X')) { 3993 c = s[1]; 3994 s += 2; 3995 base = 16; 3996 } 3997 if (base == 0) 3998 base = c == '0' ? 8 : 10; 3999 4000 /* 4001 ** Compute the cutoff value between legal numbers and illegal 4002 ** numbers. That is the largest legal value, divided by the 4003 ** base. An input number that is greater than this value, if 4004 ** followed by a legal input character, is too big. One that 4005 ** is equal to this value may be valid or not; the limit 4006 ** between valid and invalid numbers is then based on the last 4007 ** digit. For instance, if the range for longs is 4008 ** [-2147483648..2147483647] and the input base is 10, 4009 ** cutoff will be set to 214748364 and cutlim to either 4010 ** 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 4011 ** a value > 214748364, or equal but the next digit is > 7 (or 8), 4012 ** the number is too big, and we will return a range error. 4013 ** 4014 ** Set any if any `digits' consumed; make it negative to indicate 4015 ** overflow. 4016 */ 4017 cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX; 4018 cutlim = cutoff % (unsigned long) base; 4019 cutoff /= (unsigned long) base; 4020 for (acc = 0, any = 0;; c = *s++) { 4021 if (isdigit(c)) 4022 c -= '0'; 4023 else if (isalpha(c)) 4024 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 4025 else 4026 break; 4027 if (c >= base) 4028 break; 4029 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 4030 any = -1; 4031 else { 4032 any = 1; 4033 acc *= base; 4034 acc += c; 4035 } 4036 } 4037 if (any < 0) { 4038 acc = neg ? LONG_MIN : LONG_MAX; 4039 errno = ERANGE; 4040 } else if (neg) 4041 acc = -acc; 4042 if (endptr != 0) 4043 *endptr = (char *)(any ? s - 1 : nptr); 4044 return acc; 4045 } 4046 4047 #endif /* NEEDSTRTOL */ 4048 /* 4049 ** STRSTR -- find first substring in string 4050 ** 4051 ** Parameters: 4052 ** big -- the big (full) string. 4053 ** little -- the little (sub) string. 4054 ** 4055 ** Returns: 4056 ** A pointer to the first instance of little in big. 4057 ** big if little is the null string. 4058 ** NULL if little is not contained in big. 4059 */ 4060 4061 #if NEEDSTRSTR 4062 4063 char * 4064 strstr(big, little) 4065 char *big; 4066 char *little; 4067 { 4068 register char *p = big; 4069 int l; 4070 4071 if (*little == '\0') 4072 return big; 4073 l = strlen(little); 4074 4075 while ((p = strchr(p, *little)) != NULL) 4076 { 4077 if (strncmp(p, little, l) == 0) 4078 return p; 4079 p++; 4080 } 4081 return NULL; 4082 } 4083 4084 #endif /* NEEDSTRSTR */ 4085 /* 4086 ** SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX 4087 ** 4088 ** Some operating systems have wierd problems with the gethostbyXXX 4089 ** routines. For example, Solaris versions at least through 2.3 4090 ** don't properly deliver a canonical h_name field. This tries to 4091 ** work around these problems. 4092 ** 4093 ** Support IPv6 as well as IPv4. 4094 */ 4095 4096 #if NETINET6 && NEEDSGETIPNODE 4097 4098 # ifndef AI_DEFAULT 4099 # define AI_DEFAULT 0 /* dummy */ 4100 # endif /* ! AI_DEFAULT */ 4101 # ifndef AI_ADDRCONFIG 4102 # define AI_ADDRCONFIG 0 /* dummy */ 4103 # endif /* ! AI_ADDRCONFIG */ 4104 # ifndef AI_V4MAPPED 4105 # define AI_V4MAPPED 0 /* dummy */ 4106 # endif /* ! AI_V4MAPPED */ 4107 # ifndef AI_ALL 4108 # define AI_ALL 0 /* dummy */ 4109 # endif /* ! AI_ALL */ 4110 4111 static struct hostent * 4112 getipnodebyname(name, family, flags, err) 4113 char *name; 4114 int family; 4115 int flags; 4116 int *err; 4117 { 4118 bool resv6 = true; 4119 struct hostent *h; 4120 4121 if (family == AF_INET6) 4122 { 4123 /* From RFC2133, section 6.1 */ 4124 resv6 = bitset(RES_USE_INET6, _res.options); 4125 _res.options |= RES_USE_INET6; 4126 } 4127 SM_SET_H_ERRNO(0); 4128 h = gethostbyname(name); 4129 if (!resv6) 4130 _res.options &= ~RES_USE_INET6; 4131 *err = h_errno; 4132 return h; 4133 } 4134 4135 static struct hostent * 4136 getipnodebyaddr(addr, len, family, err) 4137 char *addr; 4138 int len; 4139 int family; 4140 int *err; 4141 { 4142 struct hostent *h; 4143 4144 SM_SET_H_ERRNO(0); 4145 h = gethostbyaddr(addr, len, family); 4146 *err = h_errno; 4147 return h; 4148 } 4149 4150 void 4151 freehostent(h) 4152 struct hostent *h; 4153 { 4154 /* 4155 ** Stub routine -- if they don't have getipnodeby*(), 4156 ** they probably don't have the free routine either. 4157 */ 4158 4159 return; 4160 } 4161 #endif /* NETINET6 && NEEDSGETIPNODE */ 4162 4163 struct hostent * 4164 sm_gethostbyname(name, family) 4165 char *name; 4166 int family; 4167 { 4168 int save_errno; 4169 struct hostent *h = NULL; 4170 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) 4171 # if SOLARIS == 20300 || SOLARIS == 203 4172 static struct hostent hp; 4173 static char buf[1000]; 4174 extern struct hostent *_switch_gethostbyname_r(); 4175 4176 if (tTd(61, 10)) 4177 sm_dprintf("_switch_gethostbyname_r(%s)... ", name); 4178 h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); 4179 save_errno = errno; 4180 # else /* SOLARIS == 20300 || SOLARIS == 203 */ 4181 extern struct hostent *__switch_gethostbyname(); 4182 4183 if (tTd(61, 10)) 4184 sm_dprintf("__switch_gethostbyname(%s)... ", name); 4185 h = __switch_gethostbyname(name); 4186 save_errno = errno; 4187 # endif /* SOLARIS == 20300 || SOLARIS == 203 */ 4188 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */ 4189 int nmaps; 4190 # if NETINET6 4191 int flags = AI_DEFAULT|AI_ALL; 4192 int err; 4193 # endif /* NETINET6 */ 4194 char *maptype[MAXMAPSTACK]; 4195 short mapreturn[MAXMAPACTIONS]; 4196 char hbuf[MAXNAME]; 4197 4198 if (tTd(61, 10)) 4199 sm_dprintf("sm_gethostbyname(%s, %d)... ", name, family); 4200 4201 # if NETINET6 4202 # if ADDRCONFIG_IS_BROKEN 4203 flags &= ~AI_ADDRCONFIG; 4204 # endif /* ADDRCONFIG_IS_BROKEN */ 4205 h = getipnodebyname(name, family, flags, &err); 4206 SM_SET_H_ERRNO(err); 4207 # else /* NETINET6 */ 4208 h = gethostbyname(name); 4209 # endif /* NETINET6 */ 4210 4211 save_errno = errno; 4212 if (h == NULL) 4213 { 4214 if (tTd(61, 10)) 4215 sm_dprintf("failure\n"); 4216 4217 nmaps = switch_map_find("hosts", maptype, mapreturn); 4218 while (--nmaps >= 0) 4219 { 4220 if (strcmp(maptype[nmaps], "nis") == 0 || 4221 strcmp(maptype[nmaps], "files") == 0) 4222 break; 4223 } 4224 4225 if (nmaps >= 0) 4226 { 4227 /* try short name */ 4228 if (strlen(name) > sizeof hbuf - 1) 4229 { 4230 errno = save_errno; 4231 return NULL; 4232 } 4233 (void) sm_strlcpy(hbuf, name, sizeof hbuf); 4234 (void) shorten_hostname(hbuf); 4235 4236 /* if it hasn't been shortened, there's no point */ 4237 if (strcmp(hbuf, name) != 0) 4238 { 4239 if (tTd(61, 10)) 4240 sm_dprintf("sm_gethostbyname(%s, %d)... ", 4241 hbuf, family); 4242 4243 # if NETINET6 4244 h = getipnodebyname(hbuf, family, flags, &err); 4245 SM_SET_H_ERRNO(err); 4246 save_errno = errno; 4247 # else /* NETINET6 */ 4248 h = gethostbyname(hbuf); 4249 save_errno = errno; 4250 # endif /* NETINET6 */ 4251 } 4252 } 4253 } 4254 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */ 4255 if (tTd(61, 10)) 4256 { 4257 if (h == NULL) 4258 sm_dprintf("failure\n"); 4259 else 4260 { 4261 sm_dprintf("%s\n", h->h_name); 4262 if (tTd(61, 11)) 4263 { 4264 #if NETINET6 4265 struct in6_addr ia6; 4266 char buf6[INET6_ADDRSTRLEN]; 4267 #else /* NETINET6 */ 4268 struct in_addr ia; 4269 #endif /* NETINET6 */ 4270 size_t i; 4271 4272 if (h->h_aliases != NULL) 4273 for (i = 0; h->h_aliases[i] != NULL; 4274 i++) 4275 sm_dprintf("\talias: %s\n", 4276 h->h_aliases[i]); 4277 for (i = 0; h->h_addr_list[i] != NULL; i++) 4278 { 4279 char *addr; 4280 4281 #if NETINET6 4282 memmove(&ia6, h->h_addr_list[i], 4283 IN6ADDRSZ); 4284 addr = anynet_ntop(&ia6, 4285 buf6, sizeof buf6); 4286 #else /* NETINET6 */ 4287 memmove(&ia, h->h_addr_list[i], 4288 INADDRSZ); 4289 addr = (char *) inet_ntoa(ia); 4290 #endif /* NETINET6 */ 4291 if (addr != NULL) 4292 sm_dprintf("\taddr: %s\n", addr); 4293 } 4294 } 4295 } 4296 } 4297 errno = save_errno; 4298 return h; 4299 } 4300 4301 struct hostent * 4302 sm_gethostbyaddr(addr, len, type) 4303 char *addr; 4304 int len; 4305 int type; 4306 { 4307 struct hostent *hp; 4308 4309 #if NETINET6 4310 if (type == AF_INET6 && 4311 IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *) addr)) 4312 { 4313 /* Avoid reverse lookup for IPv6 unspecified address */ 4314 SM_SET_H_ERRNO(HOST_NOT_FOUND); 4315 return NULL; 4316 } 4317 #endif /* NETINET6 */ 4318 4319 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) 4320 # if SOLARIS == 20300 || SOLARIS == 203 4321 { 4322 static struct hostent he; 4323 static char buf[1000]; 4324 extern struct hostent *_switch_gethostbyaddr_r(); 4325 4326 hp = _switch_gethostbyaddr_r(addr, len, type, &he, 4327 buf, sizeof(buf), &h_errno); 4328 } 4329 # else /* SOLARIS == 20300 || SOLARIS == 203 */ 4330 { 4331 extern struct hostent *__switch_gethostbyaddr(); 4332 4333 hp = __switch_gethostbyaddr(addr, len, type); 4334 } 4335 # endif /* SOLARIS == 20300 || SOLARIS == 203 */ 4336 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */ 4337 # if NETINET6 4338 { 4339 int err; 4340 4341 hp = getipnodebyaddr(addr, len, type, &err); 4342 SM_SET_H_ERRNO(err); 4343 } 4344 # else /* NETINET6 */ 4345 hp = gethostbyaddr(addr, len, type); 4346 # endif /* NETINET6 */ 4347 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */ 4348 return hp; 4349 } 4350 /* 4351 ** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid 4352 */ 4353 4354 struct passwd * 4355 sm_getpwnam(user) 4356 char *user; 4357 { 4358 #ifdef _AIX4 4359 extern struct passwd *_getpwnam_shadow(const char *, const int); 4360 4361 return _getpwnam_shadow(user, 0); 4362 #else /* _AIX4 */ 4363 return getpwnam(user); 4364 #endif /* _AIX4 */ 4365 } 4366 4367 struct passwd * 4368 sm_getpwuid(uid) 4369 UID_T uid; 4370 { 4371 #if defined(_AIX4) && 0 4372 extern struct passwd *_getpwuid_shadow(const int, const int); 4373 4374 return _getpwuid_shadow(uid,0); 4375 #else /* defined(_AIX4) && 0 */ 4376 return getpwuid(uid); 4377 #endif /* defined(_AIX4) && 0 */ 4378 } 4379 /* 4380 ** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup 4381 ** 4382 ** Set up the trusted computing environment for C2 level security 4383 ** under SecureWare. 4384 ** 4385 ** Parameters: 4386 ** uid -- uid of the user to initialize in the TCB 4387 ** 4388 ** Returns: 4389 ** none 4390 ** 4391 ** Side Effects: 4392 ** Initialized the user in the trusted computing base 4393 */ 4394 4395 #if SECUREWARE 4396 4397 # include <sys/security.h> 4398 # include <prot.h> 4399 4400 void 4401 secureware_setup_secure(uid) 4402 UID_T uid; 4403 { 4404 int rc; 4405 4406 if (getluid() != -1) 4407 return; 4408 4409 if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN) 4410 { 4411 switch (rc) 4412 { 4413 case SSI_NO_PRPW_ENTRY: 4414 syserr("No protected passwd entry, uid = %d", 4415 (int) uid); 4416 break; 4417 4418 case SSI_LOCKED: 4419 syserr("Account has been disabled, uid = %d", 4420 (int) uid); 4421 break; 4422 4423 case SSI_RETIRED: 4424 syserr("Account has been retired, uid = %d", 4425 (int) uid); 4426 break; 4427 4428 case SSI_BAD_SET_LUID: 4429 syserr("Could not set LUID, uid = %d", (int) uid); 4430 break; 4431 4432 case SSI_BAD_SET_PRIVS: 4433 syserr("Could not set kernel privs, uid = %d", 4434 (int) uid); 4435 4436 default: 4437 syserr("Unknown return code (%d) from set_secure_info(%d)", 4438 rc, (int) uid); 4439 break; 4440 } 4441 finis(false, true, EX_NOPERM); 4442 } 4443 } 4444 #endif /* SECUREWARE */ 4445 /* 4446 ** ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address 4447 ** 4448 ** Add hostnames to class 'w' based on the IP address read from 4449 ** the network interface. 4450 ** 4451 ** Parameters: 4452 ** sa -- a pointer to a SOCKADDR containing the address 4453 ** 4454 ** Returns: 4455 ** 0 if successful, -1 if host lookup fails. 4456 */ 4457 4458 static int 4459 add_hostnames(sa) 4460 SOCKADDR *sa; 4461 { 4462 struct hostent *hp; 4463 char **ha; 4464 char hnb[MAXHOSTNAMELEN]; 4465 4466 /* lookup name with IP address */ 4467 switch (sa->sa.sa_family) 4468 { 4469 #if NETINET 4470 case AF_INET: 4471 hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr, 4472 sizeof(sa->sin.sin_addr), 4473 sa->sa.sa_family); 4474 break; 4475 #endif /* NETINET */ 4476 4477 #if NETINET6 4478 case AF_INET6: 4479 hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr, 4480 sizeof(sa->sin6.sin6_addr), 4481 sa->sa.sa_family); 4482 break; 4483 #endif /* NETINET6 */ 4484 4485 default: 4486 /* Give warning about unsupported family */ 4487 if (LogLevel > 3) 4488 sm_syslog(LOG_WARNING, NOQID, 4489 "Unsupported address family %d: %.100s", 4490 sa->sa.sa_family, anynet_ntoa(sa)); 4491 return -1; 4492 } 4493 4494 if (hp == NULL) 4495 { 4496 int save_errno = errno; 4497 4498 if (LogLevel > 3 && 4499 #if NETINET6 4500 !(sa->sa.sa_family == AF_INET6 && 4501 IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) && 4502 #endif /* NETINET6 */ 4503 true) 4504 sm_syslog(LOG_WARNING, NOQID, 4505 "gethostbyaddr(%.100s) failed: %d", 4506 anynet_ntoa(sa), 4507 #if NAMED_BIND 4508 h_errno 4509 #else /* NAMED_BIND */ 4510 -1 4511 #endif /* NAMED_BIND */ 4512 ); 4513 errno = save_errno; 4514 return -1; 4515 } 4516 4517 /* save its cname */ 4518 if (!wordinclass((char *) hp->h_name, 'w')) 4519 { 4520 setclass('w', (char *) hp->h_name); 4521 if (tTd(0, 4)) 4522 sm_dprintf("\ta.k.a.: %s\n", hp->h_name); 4523 4524 if (sm_snprintf(hnb, sizeof hnb, "[%s]", hp->h_name) < sizeof hnb 4525 && !wordinclass((char *) hnb, 'w')) 4526 setclass('w', hnb); 4527 } 4528 else 4529 { 4530 if (tTd(0, 43)) 4531 sm_dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name); 4532 } 4533 4534 /* save all it aliases name */ 4535 for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 4536 { 4537 if (!wordinclass(*ha, 'w')) 4538 { 4539 setclass('w', *ha); 4540 if (tTd(0, 4)) 4541 sm_dprintf("\ta.k.a.: %s\n", *ha); 4542 if (sm_snprintf(hnb, sizeof hnb, 4543 "[%s]", *ha) < sizeof hnb && 4544 !wordinclass((char *) hnb, 'w')) 4545 setclass('w', hnb); 4546 } 4547 else 4548 { 4549 if (tTd(0, 43)) 4550 sm_dprintf("\ta.k.a.: %s (already in $=w)\n", 4551 *ha); 4552 } 4553 } 4554 #if NETINET6 4555 freehostent(hp); 4556 #endif /* NETINET6 */ 4557 return 0; 4558 } 4559 /* 4560 ** LOAD_IF_NAMES -- load interface-specific names into $=w 4561 ** 4562 ** Parameters: 4563 ** none. 4564 ** 4565 ** Returns: 4566 ** none. 4567 ** 4568 ** Side Effects: 4569 ** Loads $=w with the names of all the interfaces. 4570 */ 4571 4572 #if !NETINET 4573 # define SIOCGIFCONF_IS_BROKEN 1 /* XXX */ 4574 #endif /* !NETINET */ 4575 4576 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN 4577 struct rtentry; 4578 struct mbuf; 4579 # ifndef SUNOS403 4580 # include <sys/time.h> 4581 # endif /* ! SUNOS403 */ 4582 # if (_AIX4 >= 40300) && !defined(_NET_IF_H) 4583 # undef __P 4584 # endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */ 4585 # include <net/if.h> 4586 #endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */ 4587 4588 void 4589 load_if_names() 4590 { 4591 # if NETINET6 && defined(SIOCGLIFCONF) 4592 # ifdef __hpux 4593 4594 /* 4595 ** Unfortunately, HP has changed all of the structures, 4596 ** making life difficult for implementors. 4597 */ 4598 4599 # define lifconf if_laddrconf 4600 # define lifc_len iflc_len 4601 # define lifc_buf iflc_buf 4602 # define lifreq if_laddrreq 4603 # define lifr_addr iflr_addr 4604 # define lifr_name iflr_name 4605 # define lifr_flags iflr_flags 4606 # define ss_family sa_family 4607 # undef SIOCGLIFNUM 4608 # endif /* __hpux */ 4609 4610 int s; 4611 int i; 4612 size_t len; 4613 int numifs; 4614 char *buf; 4615 struct lifconf lifc; 4616 # ifdef SIOCGLIFNUM 4617 struct lifnum lifn; 4618 # endif /* SIOCGLIFNUM */ 4619 4620 s = socket(InetMode, SOCK_DGRAM, 0); 4621 if (s == -1) 4622 return; 4623 4624 /* get the list of known IP address from the kernel */ 4625 # ifdef __hpux 4626 i = ioctl(s, SIOCGIFNUM, (char *) &numifs); 4627 # endif /* __hpux */ 4628 # ifdef SIOCGLIFNUM 4629 lifn.lifn_family = AF_UNSPEC; 4630 lifn.lifn_flags = 0; 4631 i = ioctl(s, SIOCGLIFNUM, (char *)&lifn); 4632 numifs = lifn.lifn_count; 4633 # endif /* SIOCGLIFNUM */ 4634 4635 # if defined(__hpux) || defined(SIOCGLIFNUM) 4636 if (i < 0) 4637 { 4638 /* can't get number of interfaces -- fall back */ 4639 if (tTd(0, 4)) 4640 sm_dprintf("SIOCGLIFNUM failed: %s\n", 4641 sm_errstring(errno)); 4642 numifs = -1; 4643 } 4644 else if (tTd(0, 42)) 4645 sm_dprintf("system has %d interfaces\n", numifs); 4646 if (numifs < 0) 4647 # endif /* defined(__hpux) || defined(SIOCGLIFNUM) */ 4648 numifs = MAXINTERFACES; 4649 4650 if (numifs <= 0) 4651 { 4652 (void) close(s); 4653 return; 4654 } 4655 4656 len = lifc.lifc_len = numifs * sizeof (struct lifreq); 4657 buf = lifc.lifc_buf = xalloc(lifc.lifc_len); 4658 # ifndef __hpux 4659 lifc.lifc_family = AF_UNSPEC; 4660 lifc.lifc_flags = 0; 4661 # endif /* __hpux */ 4662 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) 4663 { 4664 if (tTd(0, 4)) 4665 sm_dprintf("SIOCGLIFCONF failed: %s\n", 4666 sm_errstring(errno)); 4667 (void) close(s); 4668 sm_free(buf); 4669 return; 4670 } 4671 4672 /* scan the list of IP address */ 4673 if (tTd(0, 40)) 4674 sm_dprintf("scanning for interface specific names, lifc_len=%ld\n", 4675 (long) len); 4676 4677 for (i = 0; i < len && i >= 0; ) 4678 { 4679 int flags; 4680 struct lifreq *ifr = (struct lifreq *)&buf[i]; 4681 SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr; 4682 int af = ifr->lifr_addr.ss_family; 4683 char *addr; 4684 char *name; 4685 struct in6_addr ia6; 4686 struct in_addr ia; 4687 # ifdef SIOCGLIFFLAGS 4688 struct lifreq ifrf; 4689 # endif /* SIOCGLIFFLAGS */ 4690 char ip_addr[256]; 4691 char buf6[INET6_ADDRSTRLEN]; 4692 4693 /* 4694 ** We must close and recreate the socket each time 4695 ** since we don't know what type of socket it is now 4696 ** (each status function may change it). 4697 */ 4698 4699 (void) close(s); 4700 4701 s = socket(af, SOCK_DGRAM, 0); 4702 if (s == -1) 4703 { 4704 sm_free(buf); /* XXX */ 4705 return; 4706 } 4707 4708 /* 4709 ** If we don't have a complete ifr structure, 4710 ** don't try to use it. 4711 */ 4712 4713 if ((len - i) < sizeof *ifr) 4714 break; 4715 4716 # ifdef BSD4_4_SOCKADDR 4717 if (sa->sa.sa_len > sizeof ifr->lifr_addr) 4718 i += sizeof ifr->lifr_name + sa->sa.sa_len; 4719 else 4720 # endif /* BSD4_4_SOCKADDR */ 4721 i += sizeof *ifr; 4722 4723 if (tTd(0, 20)) 4724 sm_dprintf("%s\n", anynet_ntoa(sa)); 4725 4726 if (af != AF_INET && af != AF_INET6) 4727 continue; 4728 4729 # ifdef SIOCGLIFFLAGS 4730 memset(&ifrf, '\0', sizeof(struct lifreq)); 4731 (void) sm_strlcpy(ifrf.lifr_name, ifr->lifr_name, 4732 sizeof(ifrf.lifr_name)); 4733 if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0) 4734 { 4735 if (tTd(0, 4)) 4736 sm_dprintf("SIOCGLIFFLAGS failed: %s\n", 4737 sm_errstring(errno)); 4738 continue; 4739 } 4740 4741 name = ifr->lifr_name; 4742 flags = ifrf.lifr_flags; 4743 4744 if (tTd(0, 41)) 4745 sm_dprintf("\tflags: %lx\n", (unsigned long) flags); 4746 4747 if (!bitset(IFF_UP, flags)) 4748 continue; 4749 # endif /* SIOCGLIFFLAGS */ 4750 4751 ip_addr[0] = '\0'; 4752 4753 /* extract IP address from the list*/ 4754 switch (af) 4755 { 4756 case AF_INET6: 4757 # ifdef __KAME__ 4758 /* convert into proper scoped address */ 4759 if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) || 4760 IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) && 4761 sa->sin6.sin6_scope_id == 0) 4762 { 4763 struct in6_addr *ia6p; 4764 4765 ia6p = &sa->sin6.sin6_addr; 4766 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] | 4767 ((unsigned int)ia6p->s6_addr[2] << 8)); 4768 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0; 4769 } 4770 # endif /* __KAME__ */ 4771 ia6 = sa->sin6.sin6_addr; 4772 if (IN6_IS_ADDR_UNSPECIFIED(&ia6)) 4773 { 4774 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 4775 message("WARNING: interface %s is UP with %s address", 4776 name, addr == NULL ? "(NULL)" : addr); 4777 continue; 4778 } 4779 4780 /* save IP address in text from */ 4781 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 4782 if (addr != NULL) 4783 (void) sm_snprintf(ip_addr, sizeof ip_addr, 4784 "[%.*s]", 4785 (int) sizeof ip_addr - 3, 4786 addr); 4787 break; 4788 4789 case AF_INET: 4790 ia = sa->sin.sin_addr; 4791 if (ia.s_addr == INADDR_ANY || 4792 ia.s_addr == INADDR_NONE) 4793 { 4794 message("WARNING: interface %s is UP with %s address", 4795 name, inet_ntoa(ia)); 4796 continue; 4797 } 4798 4799 /* save IP address in text from */ 4800 (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]", 4801 (int) sizeof ip_addr - 3, inet_ntoa(ia)); 4802 break; 4803 } 4804 4805 if (*ip_addr == '\0') 4806 continue; 4807 4808 if (!wordinclass(ip_addr, 'w')) 4809 { 4810 setclass('w', ip_addr); 4811 if (tTd(0, 4)) 4812 sm_dprintf("\ta.k.a.: %s\n", ip_addr); 4813 } 4814 4815 # ifdef SIOCGLIFFLAGS 4816 /* skip "loopback" interface "lo" */ 4817 if (DontProbeInterfaces == DPI_SKIPLOOPBACK && 4818 bitset(IFF_LOOPBACK, flags)) 4819 continue; 4820 # endif /* SIOCGLIFFLAGS */ 4821 (void) add_hostnames(sa); 4822 } 4823 sm_free(buf); /* XXX */ 4824 (void) close(s); 4825 # else /* NETINET6 && defined(SIOCGLIFCONF) */ 4826 # if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN 4827 int s; 4828 int i; 4829 struct ifconf ifc; 4830 int numifs; 4831 4832 s = socket(AF_INET, SOCK_DGRAM, 0); 4833 if (s == -1) 4834 return; 4835 4836 /* get the list of known IP address from the kernel */ 4837 # if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN 4838 if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) 4839 { 4840 /* can't get number of interfaces -- fall back */ 4841 if (tTd(0, 4)) 4842 sm_dprintf("SIOCGIFNUM failed: %s\n", 4843 sm_errstring(errno)); 4844 numifs = -1; 4845 } 4846 else if (tTd(0, 42)) 4847 sm_dprintf("system has %d interfaces\n", numifs); 4848 if (numifs < 0) 4849 # endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */ 4850 numifs = MAXINTERFACES; 4851 4852 if (numifs <= 0) 4853 { 4854 (void) close(s); 4855 return; 4856 } 4857 ifc.ifc_len = numifs * sizeof (struct ifreq); 4858 ifc.ifc_buf = xalloc(ifc.ifc_len); 4859 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) 4860 { 4861 if (tTd(0, 4)) 4862 sm_dprintf("SIOCGIFCONF failed: %s\n", 4863 sm_errstring(errno)); 4864 (void) close(s); 4865 return; 4866 } 4867 4868 /* scan the list of IP address */ 4869 if (tTd(0, 40)) 4870 sm_dprintf("scanning for interface specific names, ifc_len=%d\n", 4871 ifc.ifc_len); 4872 4873 for (i = 0; i < ifc.ifc_len && i >= 0; ) 4874 { 4875 int af; 4876 struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i]; 4877 SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr; 4878 # if NETINET6 4879 char *addr; 4880 struct in6_addr ia6; 4881 # endif /* NETINET6 */ 4882 struct in_addr ia; 4883 # ifdef SIOCGIFFLAGS 4884 struct ifreq ifrf; 4885 # endif /* SIOCGIFFLAGS */ 4886 char ip_addr[256]; 4887 # if NETINET6 4888 char buf6[INET6_ADDRSTRLEN]; 4889 # endif /* NETINET6 */ 4890 4891 /* 4892 ** If we don't have a complete ifr structure, 4893 ** don't try to use it. 4894 */ 4895 4896 if ((ifc.ifc_len - i) < sizeof *ifr) 4897 break; 4898 4899 # ifdef BSD4_4_SOCKADDR 4900 if (sa->sa.sa_len > sizeof ifr->ifr_addr) 4901 i += sizeof ifr->ifr_name + sa->sa.sa_len; 4902 else 4903 # endif /* BSD4_4_SOCKADDR */ 4904 i += sizeof *ifr; 4905 4906 if (tTd(0, 20)) 4907 sm_dprintf("%s\n", anynet_ntoa(sa)); 4908 4909 af = ifr->ifr_addr.sa_family; 4910 if (af != AF_INET 4911 # if NETINET6 4912 && af != AF_INET6 4913 # endif /* NETINET6 */ 4914 ) 4915 continue; 4916 4917 # ifdef SIOCGIFFLAGS 4918 memset(&ifrf, '\0', sizeof(struct ifreq)); 4919 (void) sm_strlcpy(ifrf.ifr_name, ifr->ifr_name, 4920 sizeof(ifrf.ifr_name)); 4921 (void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf); 4922 if (tTd(0, 41)) 4923 sm_dprintf("\tflags: %lx\n", 4924 (unsigned long) ifrf.ifr_flags); 4925 # define IFRFREF ifrf 4926 # else /* SIOCGIFFLAGS */ 4927 # define IFRFREF (*ifr) 4928 # endif /* SIOCGIFFLAGS */ 4929 4930 if (!bitset(IFF_UP, IFRFREF.ifr_flags)) 4931 continue; 4932 4933 ip_addr[0] = '\0'; 4934 4935 /* extract IP address from the list*/ 4936 switch (af) 4937 { 4938 case AF_INET: 4939 ia = sa->sin.sin_addr; 4940 if (ia.s_addr == INADDR_ANY || 4941 ia.s_addr == INADDR_NONE) 4942 { 4943 message("WARNING: interface %s is UP with %s address", 4944 ifr->ifr_name, inet_ntoa(ia)); 4945 continue; 4946 } 4947 4948 /* save IP address in text from */ 4949 (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]", 4950 (int) sizeof ip_addr - 3, 4951 inet_ntoa(ia)); 4952 break; 4953 4954 # if NETINET6 4955 case AF_INET6: 4956 # ifdef __KAME__ 4957 /* convert into proper scoped address */ 4958 if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) || 4959 IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) && 4960 sa->sin6.sin6_scope_id == 0) 4961 { 4962 struct in6_addr *ia6p; 4963 4964 ia6p = &sa->sin6.sin6_addr; 4965 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] | 4966 ((unsigned int)ia6p->s6_addr[2] << 8)); 4967 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0; 4968 } 4969 # endif /* __KAME__ */ 4970 ia6 = sa->sin6.sin6_addr; 4971 if (IN6_IS_ADDR_UNSPECIFIED(&ia6)) 4972 { 4973 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 4974 message("WARNING: interface %s is UP with %s address", 4975 ifr->ifr_name, 4976 addr == NULL ? "(NULL)" : addr); 4977 continue; 4978 } 4979 4980 /* save IP address in text from */ 4981 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 4982 if (addr != NULL) 4983 (void) sm_snprintf(ip_addr, sizeof ip_addr, 4984 "[%.*s]", 4985 (int) sizeof ip_addr - 3, 4986 addr); 4987 break; 4988 4989 # endif /* NETINET6 */ 4990 } 4991 4992 if (ip_addr[0] == '\0') 4993 continue; 4994 4995 if (!wordinclass(ip_addr, 'w')) 4996 { 4997 setclass('w', ip_addr); 4998 if (tTd(0, 4)) 4999 sm_dprintf("\ta.k.a.: %s\n", ip_addr); 5000 } 5001 5002 /* skip "loopback" interface "lo" */ 5003 if (DontProbeInterfaces == DPI_SKIPLOOPBACK && 5004 bitset(IFF_LOOPBACK, IFRFREF.ifr_flags)) 5005 continue; 5006 5007 (void) add_hostnames(sa); 5008 } 5009 sm_free(ifc.ifc_buf); /* XXX */ 5010 (void) close(s); 5011 # undef IFRFREF 5012 # endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */ 5013 # endif /* NETINET6 && defined(SIOCGLIFCONF) */ 5014 } 5015 /* 5016 ** ISLOOPBACK -- is socket address in the loopback net? 5017 ** 5018 ** Parameters: 5019 ** sa -- socket address. 5020 ** 5021 ** Returns: 5022 ** true -- is socket address in the loopback net? 5023 ** false -- otherwise 5024 ** 5025 */ 5026 5027 bool 5028 isloopback(sa) 5029 SOCKADDR sa; 5030 { 5031 #if NETINET6 5032 if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr)) 5033 return true; 5034 #else /* NETINET6 */ 5035 /* XXX how to correctly extract IN_LOOPBACKNET part? */ 5036 if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET) 5037 >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 5038 return true; 5039 #endif /* NETINET6 */ 5040 return false; 5041 } 5042 /* 5043 ** GET_NUM_PROCS_ONLINE -- return the number of processors currently online 5044 ** 5045 ** Parameters: 5046 ** none. 5047 ** 5048 ** Returns: 5049 ** The number of processors online. 5050 */ 5051 5052 static int 5053 get_num_procs_online() 5054 { 5055 int nproc = 0; 5056 5057 #ifdef USESYSCTL 5058 # if defined(CTL_HW) && defined(HW_NCPU) 5059 size_t sz; 5060 int mib[2]; 5061 5062 mib[0] = CTL_HW; 5063 mib[1] = HW_NCPU; 5064 sz = (size_t) sizeof nproc; 5065 (void) sysctl(mib, 2, &nproc, &sz, NULL, 0); 5066 # endif /* defined(CTL_HW) && defined(HW_NCPU) */ 5067 #else /* USESYSCTL */ 5068 # ifdef _SC_NPROCESSORS_ONLN 5069 nproc = (int) sysconf(_SC_NPROCESSORS_ONLN); 5070 # else /* _SC_NPROCESSORS_ONLN */ 5071 # ifdef __hpux 5072 # include <sys/pstat.h> 5073 struct pst_dynamic psd; 5074 5075 if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1) 5076 nproc = psd.psd_proc_cnt; 5077 # endif /* __hpux */ 5078 # endif /* _SC_NPROCESSORS_ONLN */ 5079 #endif /* USESYSCTL */ 5080 5081 if (nproc <= 0) 5082 nproc = 1; 5083 return nproc; 5084 } 5085 /* 5086 ** SEED_RANDOM -- seed the random number generator 5087 ** 5088 ** Parameters: 5089 ** none 5090 ** 5091 ** Returns: 5092 ** none 5093 */ 5094 5095 void 5096 seed_random() 5097 { 5098 #if HASSRANDOMDEV 5099 srandomdev(); 5100 #else /* HASSRANDOMDEV */ 5101 long seed; 5102 struct timeval t; 5103 5104 seed = (long) CurrentPid; 5105 if (gettimeofday(&t, NULL) >= 0) 5106 seed += t.tv_sec + t.tv_usec; 5107 5108 # if HASRANDOM 5109 (void) srandom(seed); 5110 # else /* HASRANDOM */ 5111 (void) srand((unsigned int) seed); 5112 # endif /* HASRANDOM */ 5113 #endif /* HASSRANDOMDEV */ 5114 } 5115 /* 5116 ** SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE 5117 ** 5118 ** Parameters: 5119 ** level -- syslog level 5120 ** id -- envelope ID or NULL (NOQUEUE) 5121 ** fmt -- format string 5122 ** arg... -- arguments as implied by fmt. 5123 ** 5124 ** Returns: 5125 ** none 5126 */ 5127 5128 /* VARARGS3 */ 5129 void 5130 #ifdef __STDC__ 5131 sm_syslog(int level, const char *id, const char *fmt, ...) 5132 #else /* __STDC__ */ 5133 sm_syslog(level, id, fmt, va_alist) 5134 int level; 5135 const char *id; 5136 const char *fmt; 5137 va_dcl 5138 #endif /* __STDC__ */ 5139 { 5140 static char *buf = NULL; 5141 static size_t bufsize; 5142 char *begin, *end; 5143 int save_errno; 5144 int seq = 1; 5145 int idlen; 5146 char buf0[MAXLINE]; 5147 char *newstring; 5148 extern int SyslogPrefixLen; 5149 SM_VA_LOCAL_DECL 5150 5151 save_errno = errno; 5152 if (id == NULL) 5153 { 5154 id = "NOQUEUE"; 5155 idlen = strlen(id) + SyslogPrefixLen; 5156 } 5157 else if (strcmp(id, NOQID) == 0) 5158 { 5159 id = ""; 5160 idlen = SyslogPrefixLen; 5161 } 5162 else 5163 idlen = strlen(id) + SyslogPrefixLen; 5164 5165 if (buf == NULL) 5166 { 5167 buf = buf0; 5168 bufsize = sizeof buf0; 5169 } 5170 5171 for (;;) 5172 { 5173 int n; 5174 5175 /* print log message into buf */ 5176 SM_VA_START(ap, fmt); 5177 n = sm_vsnprintf(buf, bufsize, fmt, ap); 5178 SM_VA_END(ap); 5179 SM_ASSERT(n > 0); 5180 if (n < bufsize) 5181 break; 5182 5183 /* String too small, redo with correct size */ 5184 bufsize = n + 1; 5185 if (buf != buf0) 5186 { 5187 sm_free(buf); 5188 buf = NULL; 5189 } 5190 buf = sm_malloc_x(bufsize); 5191 } 5192 5193 /* clean up buf after it has been expanded with args */ 5194 newstring = str2prt(buf); 5195 if ((strlen(newstring) + idlen + 1) < SYSLOG_BUFSIZE) 5196 { 5197 #if LOG 5198 if (*id == '\0') 5199 syslog(level, "%s", newstring); 5200 else 5201 syslog(level, "%s: %s", id, newstring); 5202 #else /* LOG */ 5203 /*XXX should do something more sensible */ 5204 if (*id == '\0') 5205 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", 5206 newstring); 5207 else 5208 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5209 "%s: %s\n", id, newstring); 5210 #endif /* LOG */ 5211 if (buf == buf0) 5212 buf = NULL; 5213 errno = save_errno; 5214 return; 5215 } 5216 5217 /* 5218 ** additional length for splitting: " ..." + 3, where 3 is magic to 5219 ** have some data for the next entry. 5220 */ 5221 5222 #define SL_SPLIT 7 5223 5224 begin = newstring; 5225 idlen += 5; /* strlen("[999]"), see below */ 5226 while (*begin != '\0' && 5227 (strlen(begin) + idlen) > SYSLOG_BUFSIZE) 5228 { 5229 char save; 5230 5231 if (seq >= 999) 5232 { 5233 /* Too many messages */ 5234 break; 5235 } 5236 end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT; 5237 while (end > begin) 5238 { 5239 /* Break on comma or space */ 5240 if (*end == ',' || *end == ' ') 5241 { 5242 end++; /* Include separator */ 5243 break; 5244 } 5245 end--; 5246 } 5247 /* No separator, break midstring... */ 5248 if (end == begin) 5249 end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT; 5250 save = *end; 5251 *end = 0; 5252 #if LOG 5253 syslog(level, "%s[%d]: %s ...", id, seq++, begin); 5254 #else /* LOG */ 5255 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5256 "%s[%d]: %s ...\n", id, seq++, begin); 5257 #endif /* LOG */ 5258 *end = save; 5259 begin = end; 5260 } 5261 if (seq >= 999) 5262 #if LOG 5263 syslog(level, "%s[%d]: log terminated, too many parts", 5264 id, seq); 5265 #else /* LOG */ 5266 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5267 "%s[%d]: log terminated, too many parts\n", id, seq); 5268 #endif /* LOG */ 5269 else if (*begin != '\0') 5270 #if LOG 5271 syslog(level, "%s[%d]: %s", id, seq, begin); 5272 #else /* LOG */ 5273 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5274 "%s[%d]: %s\n", id, seq, begin); 5275 #endif /* LOG */ 5276 if (buf == buf0) 5277 buf = NULL; 5278 errno = save_errno; 5279 } 5280 /* 5281 ** HARD_SYSLOG -- call syslog repeatedly until it works 5282 ** 5283 ** Needed on HP-UX, which apparently doesn't guarantee that 5284 ** syslog succeeds during interrupt handlers. 5285 */ 5286 5287 #if defined(__hpux) && !defined(HPUX11) 5288 5289 # define MAXSYSLOGTRIES 100 5290 # undef syslog 5291 # ifdef V4FS 5292 # define XCNST const 5293 # define CAST (const char *) 5294 # else /* V4FS */ 5295 # define XCNST 5296 # define CAST 5297 # endif /* V4FS */ 5298 5299 void 5300 # ifdef __STDC__ 5301 hard_syslog(int pri, XCNST char *msg, ...) 5302 # else /* __STDC__ */ 5303 hard_syslog(pri, msg, va_alist) 5304 int pri; 5305 XCNST char *msg; 5306 va_dcl 5307 # endif /* __STDC__ */ 5308 { 5309 int i; 5310 char buf[SYSLOG_BUFSIZE]; 5311 SM_VA_LOCAL_DECL 5312 5313 SM_VA_START(ap, msg); 5314 (void) sm_vsnprintf(buf, sizeof buf, msg, ap); 5315 SM_VA_END(ap); 5316 5317 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; ) 5318 continue; 5319 } 5320 5321 # undef CAST 5322 #endif /* defined(__hpux) && !defined(HPUX11) */ 5323 #if NEEDLOCAL_HOSTNAME_LENGTH 5324 /* 5325 ** LOCAL_HOSTNAME_LENGTH 5326 ** 5327 ** This is required to get sendmail to compile against BIND 4.9.x 5328 ** on Ultrix. 5329 ** 5330 ** Unfortunately, a Compaq Y2K patch kit provides it without 5331 ** bumping __RES in /usr/include/resolv.h so we can't automatically 5332 ** figure out whether it is needed. 5333 */ 5334 5335 int 5336 local_hostname_length(hostname) 5337 char *hostname; 5338 { 5339 size_t len_host, len_domain; 5340 5341 if (!*_res.defdname) 5342 res_init(); 5343 len_host = strlen(hostname); 5344 len_domain = strlen(_res.defdname); 5345 if (len_host > len_domain && 5346 (sm_strcasecmp(hostname + len_host - len_domain, 5347 _res.defdname) == 0) && 5348 hostname[len_host - len_domain - 1] == '.') 5349 return len_host - len_domain - 1; 5350 else 5351 return 0; 5352 } 5353 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */ 5354 5355 #if NEEDLINK 5356 /* 5357 ** LINK -- clone a file 5358 ** 5359 ** Some OS's lacks link() and hard links. Since sendmail is using 5360 ** link() as an efficient way to clone files, this implementation 5361 ** will simply do a file copy. 5362 ** 5363 ** NOTE: This link() replacement is not a generic replacement as it 5364 ** does not handle all of the semantics of the real link(2). 5365 ** 5366 ** Parameters: 5367 ** source -- pathname of existing file. 5368 ** target -- pathname of link (clone) to be created. 5369 ** 5370 ** Returns: 5371 ** 0 -- success. 5372 ** -1 -- failure, see errno for details. 5373 */ 5374 5375 int 5376 link(source, target) 5377 const char *source; 5378 const char *target; 5379 { 5380 int save_errno; 5381 int sff; 5382 int src = -1, dst = -1; 5383 ssize_t readlen; 5384 ssize_t writelen; 5385 char buf[BUFSIZ]; 5386 struct stat st; 5387 5388 sff = SFF_REGONLY|SFF_OPENASROOT; 5389 if (DontLockReadFiles) 5390 sff |= SFF_NOLOCK; 5391 5392 /* Open the original file */ 5393 src = safeopen((char *)source, O_RDONLY, 0, sff); 5394 if (src < 0) 5395 goto fail; 5396 5397 /* Obtain the size and the mode */ 5398 if (fstat(src, &st) < 0) 5399 goto fail; 5400 5401 /* Create the duplicate copy */ 5402 sff &= ~SFF_NOLOCK; 5403 sff |= SFF_CREAT; 5404 dst = safeopen((char *)target, O_CREAT|O_EXCL|O_WRONLY, 5405 st.st_mode, sff); 5406 if (dst < 0) 5407 goto fail; 5408 5409 /* Copy all of the bytes one buffer at a time */ 5410 while ((readlen = read(src, &buf, sizeof(buf))) > 0) 5411 { 5412 ssize_t left = readlen; 5413 char *p = buf; 5414 5415 while (left > 0 && 5416 (writelen = write(dst, p, (size_t) left)) >= 0) 5417 { 5418 left -= writelen; 5419 p += writelen; 5420 } 5421 if (writeln < 0) 5422 break; 5423 } 5424 5425 /* Any trouble reading? */ 5426 if (readlen < 0 || writelen < 0) 5427 goto fail; 5428 5429 /* Close the input file */ 5430 if (close(src) < 0) 5431 { 5432 src = -1; 5433 goto fail; 5434 } 5435 src = -1; 5436 5437 /* Close the output file */ 5438 if (close(dst) < 0) 5439 { 5440 /* don't set dst = -1 here so we unlink the file */ 5441 goto fail; 5442 } 5443 5444 /* Success */ 5445 return 0; 5446 5447 fail: 5448 save_errno = errno; 5449 if (src >= 0) 5450 (void) close(src); 5451 if (dst >= 0) 5452 { 5453 (void) unlink(target); 5454 (void) close(dst); 5455 } 5456 errno = save_errno; 5457 return -1; 5458 } 5459 #endif /* NEEDLINK */ 5460 5461 /* 5462 ** Compile-Time options 5463 */ 5464 5465 char *CompileOptions[] = 5466 { 5467 #if NAMED_BIND 5468 # if DNSMAP 5469 "DNSMAP", 5470 # endif /* DNSMAP */ 5471 #endif /* NAMED_BIND */ 5472 #if EGD 5473 "EGD", 5474 #endif /* EGD */ 5475 #if HESIOD 5476 "HESIOD", 5477 #endif /* HESIOD */ 5478 #if HES_GETMAILHOST 5479 "HES_GETMAILHOST", 5480 #endif /* HES_GETMAILHOST */ 5481 #if LDAPMAP 5482 "LDAPMAP", 5483 #endif /* LDAPMAP */ 5484 #if LOG 5485 "LOG", 5486 #endif /* LOG */ 5487 #if MAP_NSD 5488 "MAP_NSD", 5489 #endif /* MAP_NSD */ 5490 #if MAP_REGEX 5491 "MAP_REGEX", 5492 #endif /* MAP_REGEX */ 5493 #if MATCHGECOS 5494 "MATCHGECOS", 5495 #endif /* MATCHGECOS */ 5496 #if MILTER 5497 "MILTER", 5498 #endif /* MILTER */ 5499 #if MIME7TO8 5500 "MIME7TO8", 5501 #endif /* MIME7TO8 */ 5502 #if MIME8TO7 5503 "MIME8TO7", 5504 #endif /* MIME8TO7 */ 5505 #if NAMED_BIND 5506 "NAMED_BIND", 5507 #endif /* NAMED_BIND */ 5508 #if NDBM 5509 "NDBM", 5510 #endif /* NDBM */ 5511 #if NETINET 5512 "NETINET", 5513 #endif /* NETINET */ 5514 #if NETINET6 5515 "NETINET6", 5516 #endif /* NETINET6 */ 5517 #if NETINFO 5518 "NETINFO", 5519 #endif /* NETINFO */ 5520 #if NETISO 5521 "NETISO", 5522 #endif /* NETISO */ 5523 #if NETNS 5524 "NETNS", 5525 #endif /* NETNS */ 5526 #if NETUNIX 5527 "NETUNIX", 5528 #endif /* NETUNIX */ 5529 #if NETX25 5530 "NETX25", 5531 #endif /* NETX25 */ 5532 #if NEWDB 5533 "NEWDB", 5534 #endif /* NEWDB */ 5535 #if NIS 5536 "NIS", 5537 #endif /* NIS */ 5538 #if NISPLUS 5539 "NISPLUS", 5540 #endif /* NISPLUS */ 5541 #if NO_DH 5542 "NO_DH", 5543 #endif /* NO_DH */ 5544 #if PH_MAP 5545 "PH_MAP", 5546 #endif /* PH_MAP */ 5547 #ifdef PICKY_HELO_CHECK 5548 "PICKY_HELO_CHECK", 5549 #endif /* PICKY_HELO_CHECK */ 5550 #if PIPELINING 5551 "PIPELINING", 5552 #endif /* PIPELINING */ 5553 #if SASL 5554 "SASL", 5555 #endif /* SASL */ 5556 #if SCANF 5557 "SCANF", 5558 #endif /* SCANF */ 5559 #if SMTPDEBUG 5560 "SMTPDEBUG", 5561 #endif /* SMTPDEBUG */ 5562 #if STARTTLS 5563 "STARTTLS", 5564 #endif /* STARTTLS */ 5565 #if SUID_ROOT_FILES_OK 5566 "SUID_ROOT_FILES_OK", 5567 #endif /* SUID_ROOT_FILES_OK */ 5568 #if TCPWRAPPERS 5569 "TCPWRAPPERS", 5570 #endif /* TCPWRAPPERS */ 5571 #if TLS_NO_RSA 5572 "TLS_NO_RSA", 5573 #endif /* TLS_NO_RSA */ 5574 #if TLS_VRFY_PER_CTX 5575 "TLS_VRFY_PER_CTX", 5576 #endif /* TLS_VRFY_PER_CTX */ 5577 #if USERDB 5578 "USERDB", 5579 #endif /* USERDB */ 5580 #if XDEBUG 5581 "XDEBUG", 5582 #endif /* XDEBUG */ 5583 #if XLA 5584 "XLA", 5585 #endif /* XLA */ 5586 NULL 5587 }; 5588 5589 5590 /* 5591 ** OS compile options. 5592 */ 5593 5594 char *OsCompileOptions[] = 5595 { 5596 #if ADDRCONFIG_IS_BROKEN 5597 "ADDRCONFIG_IS_BROKEN", 5598 #endif /* ADDRCONFIG_IS_BROKEN */ 5599 #ifdef AUTO_NETINFO_HOSTS 5600 "AUTO_NETINFO_HOSTS", 5601 #endif /* AUTO_NETINFO_HOSTS */ 5602 #ifdef AUTO_NIS_ALIASES 5603 "AUTO_NIS_ALIASES", 5604 #endif /* AUTO_NIS_ALIASES */ 5605 #if BROKEN_RES_SEARCH 5606 "BROKEN_RES_SEARCH", 5607 #endif /* BROKEN_RES_SEARCH */ 5608 #ifdef BSD4_4_SOCKADDR 5609 "BSD4_4_SOCKADDR", 5610 #endif /* BSD4_4_SOCKADDR */ 5611 #if BOGUS_O_EXCL 5612 "BOGUS_O_EXCL", 5613 #endif /* BOGUS_O_EXCL */ 5614 #if DEC_OSF_BROKEN_GETPWENT 5615 "DEC_OSF_BROKEN_GETPWENT", 5616 #endif /* DEC_OSF_BROKEN_GETPWENT */ 5617 #if FAST_PID_RECYCLE 5618 "FAST_PID_RECYCLE", 5619 #endif /* FAST_PID_RECYCLE */ 5620 #if HASFCHOWN 5621 "HASFCHOWN", 5622 #endif /* HASFCHOWN */ 5623 #if HASFCHMOD 5624 "HASFCHMOD", 5625 #endif /* HASFCHMOD */ 5626 #if HASFLOCK 5627 "HASFLOCK", 5628 #endif /* HASFLOCK */ 5629 #if HASGETDTABLESIZE 5630 "HASGETDTABLESIZE", 5631 #endif /* HASGETDTABLESIZE */ 5632 #if HASGETUSERSHELL 5633 "HASGETUSERSHELL", 5634 #endif /* HASGETUSERSHELL */ 5635 #if HASINITGROUPS 5636 "HASINITGROUPS", 5637 #endif /* HASINITGROUPS */ 5638 #if HASLSTAT 5639 "HASLSTAT", 5640 #endif /* HASLSTAT */ 5641 #if HASNICE 5642 "HASNICE", 5643 #endif /* HASNICE */ 5644 #if HASRANDOM 5645 "HASRANDOM", 5646 #endif /* HASRANDOM */ 5647 #if HASRRESVPORT 5648 "HASRRESVPORT", 5649 #endif /* HASRRESVPORT */ 5650 #if HASSETEGID 5651 "HASSETEGID", 5652 #endif /* HASSETEGID */ 5653 #if HASSETLOGIN 5654 "HASSETLOGIN", 5655 #endif /* HASSETLOGIN */ 5656 #if HASSETREGID 5657 "HASSETREGID", 5658 #endif /* HASSETREGID */ 5659 #if HASSETRESGID 5660 "HASSETRESGID", 5661 #endif /* HASSETRESGID */ 5662 #if HASSETREUID 5663 "HASSETREUID", 5664 #endif /* HASSETREUID */ 5665 #if HASSETRLIMIT 5666 "HASSETRLIMIT", 5667 #endif /* HASSETRLIMIT */ 5668 #if HASSETSID 5669 "HASSETSID", 5670 #endif /* HASSETSID */ 5671 #if HASSETUSERCONTEXT 5672 "HASSETUSERCONTEXT", 5673 #endif /* HASSETUSERCONTEXT */ 5674 #if HASSETVBUF 5675 "HASSETVBUF", 5676 #endif /* HASSETVBUF */ 5677 #if HAS_ST_GEN 5678 "HAS_ST_GEN", 5679 #endif /* HAS_ST_GEN */ 5680 #if HASSRANDOMDEV 5681 "HASSRANDOMDEV", 5682 #endif /* HASSRANDOMDEV */ 5683 #if HASURANDOMDEV 5684 "HASURANDOMDEV", 5685 #endif /* HASURANDOMDEV */ 5686 #if HASSTRERROR 5687 "HASSTRERROR", 5688 #endif /* HASSTRERROR */ 5689 #if HASULIMIT 5690 "HASULIMIT", 5691 #endif /* HASULIMIT */ 5692 #if HASUNAME 5693 "HASUNAME", 5694 #endif /* HASUNAME */ 5695 #if HASUNSETENV 5696 "HASUNSETENV", 5697 #endif /* HASUNSETENV */ 5698 #if HASWAITPID 5699 "HASWAITPID", 5700 #endif /* HASWAITPID */ 5701 #if IDENTPROTO 5702 "IDENTPROTO", 5703 #endif /* IDENTPROTO */ 5704 #if IP_SRCROUTE 5705 "IP_SRCROUTE", 5706 #endif /* IP_SRCROUTE */ 5707 #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL 5708 "LOCK_ON_OPEN", 5709 #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */ 5710 #if NEEDFSYNC 5711 "NEEDFSYNC", 5712 #endif /* NEEDFSYNC */ 5713 #if NEEDLINK 5714 "NEEDLINK", 5715 #endif /* NEEDLINK */ 5716 #if NEEDLOCAL_HOSTNAME_LENGTH 5717 "NEEDLOCAL_HOSTNAME_LENGTH", 5718 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */ 5719 #if NEEDSGETIPNODE 5720 "NEEDSGETIPNODE", 5721 #endif /* NEEDSGETIPNODE */ 5722 #if NEEDSTRSTR 5723 "NEEDSTRSTR", 5724 #endif /* NEEDSTRSTR */ 5725 #if NEEDSTRTOL 5726 "NEEDSTRTOL", 5727 #endif /* NEEDSTRTOL */ 5728 #ifdef NO_GETSERVBYNAME 5729 "NO_GETSERVBYNAME", 5730 #endif /* NO_GETSERVBYNAME */ 5731 #if NOFTRUNCATE 5732 "NOFTRUNCATE", 5733 #endif /* NOFTRUNCATE */ 5734 #if REQUIRES_DIR_FSYNC 5735 "REQUIRES_DIR_FSYNC", 5736 #endif /* REQUIRES_DIR_FSYNC */ 5737 #if RLIMIT_NEEDS_SYS_TIME_H 5738 "RLIMIT_NEEDS_SYS_TIME_H", 5739 #endif /* RLIMIT_NEEDS_SYS_TIME_H */ 5740 #if SAFENFSPATHCONF 5741 "SAFENFSPATHCONF", 5742 #endif /* SAFENFSPATHCONF */ 5743 #if SECUREWARE 5744 "SECUREWARE", 5745 #endif /* SECUREWARE */ 5746 #if SHARE_V1 5747 "SHARE_V1", 5748 #endif /* SHARE_V1 */ 5749 #if SIOCGIFCONF_IS_BROKEN 5750 "SIOCGIFCONF_IS_BROKEN", 5751 #endif /* SIOCGIFCONF_IS_BROKEN */ 5752 #if SIOCGIFNUM_IS_BROKEN 5753 "SIOCGIFNUM_IS_BROKEN", 5754 #endif /* SIOCGIFNUM_IS_BROKEN */ 5755 #if SNPRINTF_IS_BROKEN 5756 "SNPRINTF_IS_BROKEN", 5757 #endif /* SNPRINTF_IS_BROKEN */ 5758 #if SO_REUSEADDR_IS_BROKEN 5759 "SO_REUSEADDR_IS_BROKEN", 5760 #endif /* SO_REUSEADDR_IS_BROKEN */ 5761 #if SYS5SETPGRP 5762 "SYS5SETPGRP", 5763 #endif /* SYS5SETPGRP */ 5764 #if SYSTEM5 5765 "SYSTEM5", 5766 #endif /* SYSTEM5 */ 5767 #if USE_DOUBLE_FORK 5768 "USE_DOUBLE_FORK", 5769 #endif /* USE_DOUBLE_FORK */ 5770 #if USE_ENVIRON 5771 "USE_ENVIRON", 5772 #endif /* USE_ENVIRON */ 5773 #if USE_SA_SIGACTION 5774 "USE_SA_SIGACTION", 5775 #endif /* USE_SA_SIGACTION */ 5776 #if USE_SIGLONGJMP 5777 "USE_SIGLONGJMP", 5778 #endif /* USE_SIGLONGJMP */ 5779 #if USEGETCONFATTR 5780 "USEGETCONFATTR", 5781 #endif /* USEGETCONFATTR */ 5782 #if USESETEUID 5783 "USESETEUID", 5784 #endif /* USESETEUID */ 5785 #ifdef USESYSCTL 5786 "USESYSCTL", 5787 #endif /* USESYSCTL */ 5788 #if USING_NETSCAPE_LDAP 5789 "USING_NETSCAPE_LDAP", 5790 #endif /* USING_NETSCAPE_LDAP */ 5791 #ifdef WAITUNION 5792 "WAITUNION", 5793 #endif /* WAITUNION */ 5794 NULL 5795 }; 5796 5797 /* 5798 ** FFR compile options. 5799 */ 5800 5801 char *FFRCompileOptions[] = 5802 { 5803 #if _FFR_ADAPTIVE_EOL 5804 "_FFR_ADAPTIVE_EOL", 5805 #endif /* _FFR_ADAPTIVE_EOL */ 5806 #if _FFR_ALLOW_SASLINFO 5807 "_FFR_ALLOW_SASLINFO", 5808 #endif /* _FFR_ALLOW_SASLINFO */ 5809 #if _FFR_BESTMX_BETTER_TRUNCATION 5810 "_FFR_BESTMX_BETTER_TRUNCATION", 5811 #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 5812 #if _FFR_CACHE_LPC 5813 /* Christophe Wolfhugel of France Telecom Oleane */ 5814 "_FFR_CACHE_LPC", 5815 #endif /* _FFR_CACHE_LPC */ 5816 #if _FFR_CATCH_BROKEN_MTAS 5817 "_FFR_CATCH_BROKEN_MTAS", 5818 #endif /* _FFR_CATCH_BROKEN_MTAS */ 5819 #if _FFR_CHECK_EOM 5820 "_FFR_CHECK_EOM", 5821 #endif /* _FFR_CHECK_EOM */ 5822 #if _FFR_CONTROL_MSTAT 5823 "_FFR_CONTROL_MSTAT", 5824 #endif /* _FFR_CONTROL_MSTAT */ 5825 #if _FFR_DAEMON_NETUNIX 5826 "_FFR_DAEMON_NETUNIX", 5827 #endif /* _FFR_DAEMON_NETUNIX */ 5828 #if _FFR_DEPRECATE_MAILER_FLAG_I 5829 "_FFR_DEPRECATE_MAILER_FLAG_I", 5830 #endif /* _FFR_DEPRECATE_MAILER_FLAG_I */ 5831 #if _FFR_DNSMAP_BASE 5832 "_FFR_DNSMAP_BASE", 5833 #endif /* _FFR_DNSMAP_BASE */ 5834 #if _FFR_DNSMAP_MULTI 5835 "_FFR_DNSMAP_MULTI", 5836 # if _FFR_DNSMAP_MULTILIMIT 5837 "_FFR_DNSMAP_MULTILIMIT", 5838 # endif /* _FFR_DNSMAP_MULTILIMIT */ 5839 #endif /* _FFR_DNSMAP_MULTI */ 5840 #if _FFR_DONTLOCKFILESFORREAD_OPTION 5841 "_FFR_DONTLOCKFILESFORREAD_OPTION", 5842 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 5843 #if _FFR_DOTTED_USERNAMES 5844 "_FFR_DOTTED_USERNAMES", 5845 #endif /* _FFR_DOTTED_USERNAMES */ 5846 #if _FFR_DROP_TRUSTUSER_WARNING 5847 "_FFR_DROP_TRUSTUSER_WARNING", 5848 #endif /* _FFR_DROP_TRUSTUSER_WARNING */ 5849 #if _FFR_FIX_DASHT 5850 "_FFR_FIX_DASHT", 5851 #endif /* _FFR_FIX_DASHT */ 5852 #if _FFR_FORWARD_SYSERR 5853 "_FFR_FORWARD_SYSERR", 5854 #endif /* _FFR_FORWARD_SYSERR */ 5855 #if _FFR_GEN_ORCPT 5856 "_FFR_GEN_ORCPT", 5857 #endif /* _FFR_GEN_ORCPT */ 5858 #if _FFR_GROUPREADABLEAUTHINFOFILE 5859 "_FFR_GROUPREADABLEAUTHINFOFILE", 5860 #endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ 5861 #if _FFR_HDR_TYPE 5862 "_FFR_HDR_TYPE", 5863 #endif /* _FFR_HDR_TYPE */ 5864 #if _FFR_HPUX_NSSWITCH 5865 "_FFR_HPUX_NSSWITCH", 5866 #endif /* _FFR_HPUX_NSSWITCH */ 5867 #if _FFR_IGNORE_EXT_ON_HELO 5868 "_FFR_IGNORE_EXT_ON_HELO", 5869 #endif /* _FFR_IGNORE_EXT_ON_HELO */ 5870 #if _FFR_LDAP_RECURSION 5871 "_FFR_LDAP_RECURSION", 5872 #endif /* _FFR_LDAP_RECURSION */ 5873 #if _FFR_MAX_FORWARD_ENTRIES 5874 /* Randall S. Winchester of the University of Maryland */ 5875 "_FFR_MAX_FORWARD_ENTRIES", 5876 #endif /* _FFR_MAX_FORWARD_ENTRIES */ 5877 #if MILTER 5878 # if _FFR_MILTER_PERDAEMON 5879 "_FFR_MILTER_PERDAEMON", 5880 # endif /* _FFR_MILTER_PERDAEMON */ 5881 #endif /* MILTER */ 5882 #if _FFR_NODELAYDSN_ON_HOLD 5883 /* Steven Pitzl */ 5884 "_FFR_NODELAYDSN_ON_HOLD", 5885 #endif /* _FFR_NODELAYDSN_ON_HOLD */ 5886 #if _FFR_NO_PIPE 5887 "_FFR_NO_PIPE", 5888 #endif /* _FFR_NO_PIPE */ 5889 #if _FFR_QUARANTINE 5890 "_FFR_QUARANTINE", 5891 #endif /* _FFR_QUARANTINE */ 5892 #if _FFR_QUEUEDELAY 5893 "_FFR_QUEUEDELAY", 5894 #endif /* _FFR_QUEUEDELAY */ 5895 #if _FFR_QUEUE_MACRO 5896 "_FFR_QUEUE_MACRO", 5897 #endif /* _FFR_QUEUE_MACRO */ 5898 #if _FFR_QUEUE_SCHED_DBG 5899 "_FFR_QUEUE_SCHED_DBG", 5900 #endif /* _FFR_QUEUE_SCHED_DBG */ 5901 #if _FFR_REDIRECTEMPTY 5902 "_FFR_REDIRECTEMPTY", 5903 #endif /* _FFR_REDIRECTEMPTY */ 5904 #if _FFR_RESET_MACRO_GLOBALS 5905 "_FFR_RESET_MACRO_GLOBALS", 5906 #endif /* _FFR_RESET_MACRO_GLOBALS */ 5907 #if _FFR_RHS 5908 "_FFR_RHS", 5909 #endif /* _FFR_RHS */ 5910 #if _FFR_SHM_STATUS 5911 "_FFR_SHM_STATUS", 5912 #endif /* _FFR_SHM_STATUS */ 5913 #if _FFR_SMTP_SSL 5914 "_FFR_SMTP_SSL", 5915 #endif /* _FFR_SMTP_SSL */ 5916 #if _FFR_SOFT_BOUNCE 5917 "_FFR_SOFT_BOUNCE", 5918 #endif /* _FFR_SOFT_BOUNCE */ 5919 #if _FFR_TIMERS 5920 "_FFR_TIMERS", 5921 #endif /* _FFR_TIMERS */ 5922 #if _FFR_TLS_1 5923 "_FFR_TLS_1", 5924 #endif /* _FFR_TLS_1 */ 5925 #if _FFR_TRUSTED_QF 5926 "_FFR_TRUSTED_QF", 5927 #endif /* _FFR_TRUSTED_QF */ 5928 NULL 5929 }; 5930 5931