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