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.972 2002/06/18 16:11:44 ca 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 #if _FFR_SPT_ALIGN 2331 2332 /* 2333 ** It looks like the Compaq Tru64 5.1A now aligns argv and envp to 2334 ** 64 bit alignment, so unless each piece of argv and envp is a multiple 2335 ** of 8 bytes (including terminating NULL), initsetproctitle() won't use 2336 ** any of the space beyond argv[0]. Be sure to set SPT_ALIGN_SIZE if 2337 ** you use this FFR. 2338 */ 2339 2340 # ifdef SPT_ALIGN_SIZE 2341 # define SPT_ALIGN(x, align) (((((x) + SPT_ALIGN_SIZE) >> (align)) << (align)) - 1) 2342 # else /* SPT_ALIGN_SIZE */ 2343 # define SPT_ALIGN(x, align) (x) 2344 # endif /* SPT_ALIGN_SIZE */ 2345 #else /* _FFR_SPT_ALIGN */ 2346 # define SPT_ALIGN(x, align) (x) 2347 #endif /* _FFR_SPT_ALIGN */ 2348 2349 /* 2350 ** Pointers for setproctitle. 2351 ** This allows "ps" listings to give more useful information. 2352 */ 2353 2354 static char **Argv = NULL; /* pointer to argument vector */ 2355 static char *LastArgv = NULL; /* end of argv */ 2356 #if SPT_TYPE != SPT_BUILTIN 2357 static void setproctitle __P((const char *, ...)); 2358 #endif /* SPT_TYPE != SPT_BUILTIN */ 2359 2360 void 2361 initsetproctitle(argc, argv, envp) 2362 int argc; 2363 char **argv; 2364 char **envp; 2365 { 2366 register int i; 2367 int align; 2368 extern char **environ; 2369 2370 /* 2371 ** Move the environment so setproctitle can use the space at 2372 ** the top of memory. 2373 */ 2374 2375 for (i = 0; envp[i] != NULL; i++) 2376 continue; 2377 environ = (char **) xalloc(sizeof (char *) * (i + 1)); 2378 for (i = 0; envp[i] != NULL; i++) 2379 environ[i] = newstr(envp[i]); 2380 environ[i] = NULL; 2381 2382 /* 2383 ** Save start and extent of argv for setproctitle. 2384 */ 2385 2386 Argv = argv; 2387 2388 /* 2389 ** Determine how much space we can use for setproctitle. 2390 ** Use all contiguous argv and envp pointers starting at argv[0] 2391 */ 2392 2393 align = -1; 2394 #if _FFR_SPT_ALIGN 2395 # ifdef SPT_ALIGN_SIZE 2396 for (i = SPT_ALIGN_SIZE; i > 0; i >>= 1) 2397 align++; 2398 # endif /* SPT_ALIGN_SIZE */ 2399 #endif /* _FFR_SPT_ALIGN */ 2400 2401 for (i = 0; i < argc; i++) 2402 { 2403 if (i == 0 || LastArgv + 1 == argv[i]) 2404 LastArgv = argv[i] + SPT_ALIGN(strlen(argv[i]), align); 2405 } 2406 for (i = 0; LastArgv != NULL && envp[i] != NULL; i++) 2407 { 2408 if (LastArgv + 1 == envp[i]) 2409 LastArgv = envp[i] + SPT_ALIGN(strlen(envp[i]), align); 2410 } 2411 } 2412 2413 #if SPT_TYPE != SPT_BUILTIN 2414 2415 /*VARARGS1*/ 2416 static void 2417 # ifdef __STDC__ 2418 setproctitle(const char *fmt, ...) 2419 # else /* __STDC__ */ 2420 setproctitle(fmt, va_alist) 2421 const char *fmt; 2422 va_dcl 2423 # endif /* __STDC__ */ 2424 { 2425 # if SPT_TYPE != SPT_NONE 2426 register int i; 2427 register char *p; 2428 SETPROC_STATIC char buf[SPT_BUFSIZE]; 2429 SM_VA_LOCAL_DECL 2430 # if SPT_TYPE == SPT_PSTAT 2431 union pstun pst; 2432 # endif /* SPT_TYPE == SPT_PSTAT */ 2433 # if SPT_TYPE == SPT_SCO 2434 int j; 2435 off_t seek_off; 2436 static int kmem = -1; 2437 static pid_t kmempid = -1; 2438 struct user u; 2439 # endif /* SPT_TYPE == SPT_SCO */ 2440 2441 p = buf; 2442 2443 /* print sendmail: heading for grep */ 2444 (void) sm_strlcpy(p, "sendmail: ", SPACELEFT(buf, p)); 2445 p += strlen(p); 2446 2447 /* print the argument string */ 2448 SM_VA_START(ap, fmt); 2449 (void) sm_vsnprintf(p, SPACELEFT(buf, p), fmt, ap); 2450 SM_VA_END(ap); 2451 2452 i = (int) strlen(buf); 2453 if (i < 0) 2454 return; 2455 2456 # if SPT_TYPE == SPT_PSTAT 2457 pst.pst_command = buf; 2458 pstat(PSTAT_SETCMD, pst, i, 0, 0); 2459 # endif /* SPT_TYPE == SPT_PSTAT */ 2460 # if SPT_TYPE == SPT_PSSTRINGS 2461 PS_STRINGS->ps_nargvstr = 1; 2462 PS_STRINGS->ps_argvstr = buf; 2463 # endif /* SPT_TYPE == SPT_PSSTRINGS */ 2464 # if SPT_TYPE == SPT_SYSMIPS 2465 sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf); 2466 # endif /* SPT_TYPE == SPT_SYSMIPS */ 2467 # if SPT_TYPE == SPT_SCO 2468 if (kmem < 0 || kmempid != CurrentPid) 2469 { 2470 if (kmem >= 0) 2471 (void) close(kmem); 2472 kmem = open(_PATH_KMEM, O_RDWR, 0); 2473 if (kmem < 0) 2474 return; 2475 if ((j = fcntl(kmem, F_GETFD, 0)) < 0 || 2476 fcntl(kmem, F_SETFD, j | FD_CLOEXEC) < 0) 2477 { 2478 (void) close(kmem); 2479 kmem = -1; 2480 return; 2481 } 2482 kmempid = CurrentPid; 2483 } 2484 buf[PSARGSZ - 1] = '\0'; 2485 seek_off = UVUBLK + (off_t) u.u_psargs - (off_t) &u; 2486 if (lseek(kmem, (off_t) seek_off, SEEK_SET) == seek_off) 2487 (void) write(kmem, buf, PSARGSZ); 2488 # endif /* SPT_TYPE == SPT_SCO */ 2489 # if SPT_TYPE == SPT_REUSEARGV 2490 if (LastArgv == NULL) 2491 return; 2492 2493 if (i > LastArgv - Argv[0] - 2) 2494 { 2495 i = LastArgv - Argv[0] - 2; 2496 buf[i] = '\0'; 2497 } 2498 (void) sm_strlcpy(Argv[0], buf, i + 1); 2499 p = &Argv[0][i]; 2500 while (p < LastArgv) 2501 *p++ = SPT_PADCHAR; 2502 Argv[1] = NULL; 2503 # endif /* SPT_TYPE == SPT_REUSEARGV */ 2504 # if SPT_TYPE == SPT_CHANGEARGV 2505 Argv[0] = buf; 2506 Argv[1] = 0; 2507 # endif /* SPT_TYPE == SPT_CHANGEARGV */ 2508 # endif /* SPT_TYPE != SPT_NONE */ 2509 } 2510 2511 #endif /* SPT_TYPE != SPT_BUILTIN */ 2512 /* 2513 ** SM_SETPROCTITLE -- set process task and set process title for ps 2514 ** 2515 ** Possibly set process status and call setproctitle() to 2516 ** change the ps display. 2517 ** 2518 ** Parameters: 2519 ** status -- whether or not to store as process status 2520 ** e -- the current envelope. 2521 ** fmt -- a printf style format string. 2522 ** a, b, c -- possible parameters to fmt. 2523 ** 2524 ** Returns: 2525 ** none. 2526 */ 2527 2528 /*VARARGS2*/ 2529 void 2530 #ifdef __STDC__ 2531 sm_setproctitle(bool status, ENVELOPE *e, const char *fmt, ...) 2532 #else /* __STDC__ */ 2533 sm_setproctitle(status, e, fmt, va_alist) 2534 bool status; 2535 ENVELOPE *e; 2536 const char *fmt; 2537 va_dcl 2538 #endif /* __STDC__ */ 2539 { 2540 char buf[SPT_BUFSIZE]; 2541 SM_VA_LOCAL_DECL 2542 2543 /* print the argument string */ 2544 SM_VA_START(ap, fmt); 2545 (void) sm_vsnprintf(buf, sizeof buf, fmt, ap); 2546 SM_VA_END(ap); 2547 2548 if (status) 2549 proc_list_set(CurrentPid, buf); 2550 2551 if (ProcTitlePrefix != NULL) 2552 { 2553 char prefix[SPT_BUFSIZE]; 2554 2555 expand(ProcTitlePrefix, prefix, sizeof prefix, e); 2556 setproctitle("%s: %s", prefix, buf); 2557 } 2558 else 2559 setproctitle("%s", buf); 2560 } 2561 /* 2562 ** WAITFOR -- wait for a particular process id. 2563 ** 2564 ** Parameters: 2565 ** pid -- process id to wait for. 2566 ** 2567 ** Returns: 2568 ** status of pid. 2569 ** -1 if pid never shows up. 2570 ** 2571 ** Side Effects: 2572 ** none. 2573 */ 2574 2575 int 2576 waitfor(pid) 2577 pid_t pid; 2578 { 2579 int st; 2580 pid_t i; 2581 2582 do 2583 { 2584 errno = 0; 2585 i = sm_wait(&st); 2586 if (i > 0) 2587 proc_list_drop(i, st, NULL); 2588 } while ((i >= 0 || errno == EINTR) && i != pid); 2589 if (i < 0) 2590 return -1; 2591 return st; 2592 } 2593 /* 2594 ** SM_WAIT -- wait 2595 ** 2596 ** Parameters: 2597 ** status -- pointer to status (return value) 2598 ** 2599 ** Returns: 2600 ** pid 2601 */ 2602 2603 pid_t 2604 sm_wait(status) 2605 int *status; 2606 { 2607 # ifdef WAITUNION 2608 union wait st; 2609 # else /* WAITUNION */ 2610 auto int st; 2611 # endif /* WAITUNION */ 2612 pid_t i; 2613 # if defined(ISC_UNIX) || defined(_SCO_unix_) 2614 int savesig; 2615 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ 2616 2617 # if defined(ISC_UNIX) || defined(_SCO_unix_) 2618 savesig = sm_releasesignal(SIGCHLD); 2619 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ 2620 i = wait(&st); 2621 # if defined(ISC_UNIX) || defined(_SCO_unix_) 2622 if (savesig > 0) 2623 sm_blocksignal(SIGCHLD); 2624 # endif /* defined(ISC_UNIX) || defined(_SCO_unix_) */ 2625 # ifdef WAITUNION 2626 *status = st.w_status; 2627 # else /* WAITUNION */ 2628 *status = st; 2629 # endif /* WAITUNION */ 2630 return i; 2631 } 2632 /* 2633 ** REAPCHILD -- pick up the body of my child, lest it become a zombie 2634 ** 2635 ** Parameters: 2636 ** sig -- the signal that got us here (unused). 2637 ** 2638 ** Returns: 2639 ** none. 2640 ** 2641 ** Side Effects: 2642 ** Picks up extant zombies. 2643 ** Control socket exits may restart/shutdown daemon. 2644 ** 2645 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 2646 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 2647 ** DOING. 2648 */ 2649 2650 /* ARGSUSED0 */ 2651 SIGFUNC_DECL 2652 reapchild(sig) 2653 int sig; 2654 { 2655 int m = 0; 2656 int save_errno = errno; 2657 int st; 2658 pid_t pid; 2659 # if HASWAITPID 2660 auto int status; 2661 int count; 2662 2663 count = 0; 2664 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) 2665 { 2666 st = status; 2667 if (count++ > 1000) 2668 break; 2669 # else /* HASWAITPID */ 2670 # ifdef WNOHANG 2671 union wait status; 2672 2673 while ((pid = wait3(&status, WNOHANG, (struct rusage *) NULL)) > 0) 2674 { 2675 st = status.w_status; 2676 # else /* WNOHANG */ 2677 auto int status; 2678 2679 /* 2680 ** Catch one zombie -- we will be re-invoked (we hope) if there 2681 ** are more. Unreliable signals probably break this, but this 2682 ** is the "old system" situation -- waitpid or wait3 are to be 2683 ** strongly preferred. 2684 */ 2685 2686 if ((pid = wait(&status)) > 0) 2687 { 2688 st = status; 2689 # endif /* WNOHANG */ 2690 # endif /* HASWAITPID */ 2691 /* Drop PID and check if it was a control socket child */ 2692 proc_list_drop(pid, st, NULL); 2693 CurRunners -= m; /* Update */ 2694 } 2695 FIX_SYSV_SIGNAL(sig, reapchild); 2696 errno = save_errno; 2697 return SIGFUNC_RETURN; 2698 } 2699 /* 2700 ** GETDTABLESIZE -- return number of file descriptors 2701 ** 2702 ** Only on non-BSD systems 2703 ** 2704 ** Parameters: 2705 ** none 2706 ** 2707 ** Returns: 2708 ** size of file descriptor table 2709 ** 2710 ** Side Effects: 2711 ** none 2712 */ 2713 2714 #ifdef SOLARIS 2715 # include <sys/resource.h> 2716 #endif /* SOLARIS */ 2717 2718 int 2719 getdtsize() 2720 { 2721 # ifdef RLIMIT_NOFILE 2722 struct rlimit rl; 2723 2724 if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 2725 return rl.rlim_cur; 2726 # endif /* RLIMIT_NOFILE */ 2727 2728 # if HASGETDTABLESIZE 2729 return getdtablesize(); 2730 # else /* HASGETDTABLESIZE */ 2731 # ifdef _SC_OPEN_MAX 2732 return sysconf(_SC_OPEN_MAX); 2733 # else /* _SC_OPEN_MAX */ 2734 return NOFILE; 2735 # endif /* _SC_OPEN_MAX */ 2736 # endif /* HASGETDTABLESIZE */ 2737 } 2738 /* 2739 ** UNAME -- get the UUCP name of this system. 2740 */ 2741 2742 #if !HASUNAME 2743 2744 int 2745 uname(name) 2746 struct utsname *name; 2747 { 2748 SM_FILE_T *file; 2749 char *n; 2750 2751 name->nodename[0] = '\0'; 2752 2753 /* try /etc/whoami -- one line with the node name */ 2754 if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, "/etc/whoami", 2755 SM_IO_RDONLY, NULL)) != NULL) 2756 { 2757 (void) sm_io_fgets(file, SM_TIME_DEFAULT, name->nodename, 2758 NODE_LENGTH + 1); 2759 (void) sm_io_close(file, SM_TIME_DEFAULT); 2760 n = strchr(name->nodename, '\n'); 2761 if (n != NULL) 2762 *n = '\0'; 2763 if (name->nodename[0] != '\0') 2764 return 0; 2765 } 2766 2767 /* try /usr/include/whoami.h -- has a #define somewhere */ 2768 if ((file = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, 2769 "/usr/include/whoami.h", SM_IO_RDONLY, NULL)) 2770 != NULL) 2771 { 2772 char buf[MAXLINE]; 2773 2774 while (sm_io_fgets(file, SM_TIME_DEFAULT, 2775 buf, sizeof buf) != NULL) 2776 { 2777 if (sm_io_sscanf(buf, "#define sysname \"%*[^\"]\"", 2778 NODE_LENGTH, name->nodename) > 0) 2779 break; 2780 } 2781 (void) sm_io_close(file, SM_TIME_DEFAULT); 2782 if (name->nodename[0] != '\0') 2783 return 0; 2784 } 2785 2786 # if 0 2787 /* 2788 ** Popen is known to have security holes. 2789 */ 2790 2791 /* try uuname -l to return local name */ 2792 if ((file = popen("uuname -l", "r")) != NULL) 2793 { 2794 (void) sm_io_fgets(file, SM_TIME_DEFAULT, name, 2795 NODE_LENGTH + 1); 2796 (void) pclose(file); 2797 n = strchr(name, '\n'); 2798 if (n != NULL) 2799 *n = '\0'; 2800 if (name->nodename[0] != '\0') 2801 return 0; 2802 } 2803 # endif /* 0 */ 2804 2805 return -1; 2806 } 2807 #endif /* !HASUNAME */ 2808 /* 2809 ** INITGROUPS -- initialize groups 2810 ** 2811 ** Stub implementation for System V style systems 2812 */ 2813 2814 #if !HASINITGROUPS 2815 2816 initgroups(name, basegid) 2817 char *name; 2818 int basegid; 2819 { 2820 return 0; 2821 } 2822 2823 #endif /* !HASINITGROUPS */ 2824 /* 2825 ** SETGROUPS -- set group list 2826 ** 2827 ** Stub implementation for systems that don't have group lists 2828 */ 2829 2830 #ifndef NGROUPS_MAX 2831 2832 int 2833 setgroups(ngroups, grouplist) 2834 int ngroups; 2835 GIDSET_T grouplist[]; 2836 { 2837 return 0; 2838 } 2839 2840 #endif /* ! NGROUPS_MAX */ 2841 /* 2842 ** SETSID -- set session id (for non-POSIX systems) 2843 */ 2844 2845 #if !HASSETSID 2846 2847 pid_t 2848 setsid __P ((void)) 2849 { 2850 # ifdef TIOCNOTTY 2851 int fd; 2852 2853 fd = open("/dev/tty", O_RDWR, 0); 2854 if (fd >= 0) 2855 { 2856 (void) ioctl(fd, TIOCNOTTY, (char *) 0); 2857 (void) close(fd); 2858 } 2859 # endif /* TIOCNOTTY */ 2860 # ifdef SYS5SETPGRP 2861 return setpgrp(); 2862 # else /* SYS5SETPGRP */ 2863 return setpgid(0, CurrentPid); 2864 # endif /* SYS5SETPGRP */ 2865 } 2866 2867 #endif /* !HASSETSID */ 2868 /* 2869 ** FSYNC -- dummy fsync 2870 */ 2871 2872 #if NEEDFSYNC 2873 2874 fsync(fd) 2875 int fd; 2876 { 2877 # ifdef O_SYNC 2878 return fcntl(fd, F_SETFL, O_SYNC); 2879 # else /* O_SYNC */ 2880 /* nothing we can do */ 2881 return 0; 2882 # endif /* O_SYNC */ 2883 } 2884 2885 #endif /* NEEDFSYNC */ 2886 /* 2887 ** DGUX_INET_ADDR -- inet_addr for DG/UX 2888 ** 2889 ** Data General DG/UX version of inet_addr returns a struct in_addr 2890 ** instead of a long. This patches things. Only needed on versions 2891 ** prior to 5.4.3. 2892 */ 2893 2894 #ifdef DGUX_5_4_2 2895 2896 # undef inet_addr 2897 2898 long 2899 dgux_inet_addr(host) 2900 char *host; 2901 { 2902 struct in_addr haddr; 2903 2904 haddr = inet_addr(host); 2905 return haddr.s_addr; 2906 } 2907 2908 #endif /* DGUX_5_4_2 */ 2909 /* 2910 ** GETOPT -- for old systems or systems with bogus implementations 2911 */ 2912 2913 #if !SM_CONF_GETOPT 2914 2915 /* 2916 * Copyright (c) 1985 Regents of the University of California. 2917 * All rights reserved. The Berkeley software License Agreement 2918 * specifies the terms and conditions for redistribution. 2919 */ 2920 2921 2922 /* 2923 ** this version hacked to add `atend' flag to allow state machine 2924 ** to reset if invoked by the program to scan args for a 2nd time 2925 */ 2926 2927 # if defined(LIBC_SCCS) && !defined(lint) 2928 static char sccsid[] = "@(#)getopt.c 4.3 (Berkeley) 3/9/86"; 2929 # endif /* defined(LIBC_SCCS) && !defined(lint) */ 2930 2931 /* 2932 ** get option letter from argument vector 2933 */ 2934 # ifdef _CONVEX_SOURCE 2935 extern int optind, opterr, optopt; 2936 extern char *optarg; 2937 # else /* _CONVEX_SOURCE */ 2938 int opterr = 1; /* if error message should be printed */ 2939 int optind = 1; /* index into parent argv vector */ 2940 int optopt = 0; /* character checked for validity */ 2941 char *optarg = NULL; /* argument associated with option */ 2942 # endif /* _CONVEX_SOURCE */ 2943 2944 # define BADCH (int)'?' 2945 # define EMSG "" 2946 # define tell(s) if (opterr) \ 2947 {sm_io_fputs(smioerr, SM_TIME_DEFAULT, *nargv); \ 2948 (void) sm_io_fputs(smioerr, SM_TIME_DEFAULT, s); \ 2949 (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, optopt); \ 2950 (void) sm_io_putc(smioerr, SM_TIME_DEFAULT, '\n'); \ 2951 return BADCH;} 2952 2953 int 2954 getopt(nargc,nargv,ostr) 2955 int nargc; 2956 char *const *nargv; 2957 const char *ostr; 2958 { 2959 static char *place = EMSG; /* option letter processing */ 2960 static char atend = 0; 2961 register char *oli = NULL; /* option letter list index */ 2962 2963 if (atend) { 2964 atend = 0; 2965 place = EMSG; 2966 } 2967 if(!*place) { /* update scanning pointer */ 2968 if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { 2969 atend++; 2970 return -1; 2971 } 2972 if (*place == '-') { /* found "--" */ 2973 ++optind; 2974 atend++; 2975 return -1; 2976 } 2977 } /* option letter okay? */ 2978 if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr,optopt))) { 2979 if (!*place) ++optind; 2980 tell(": illegal option -- "); 2981 } 2982 if (oli && *++oli != ':') { /* don't need argument */ 2983 optarg = NULL; 2984 if (!*place) ++optind; 2985 } 2986 else { /* need an argument */ 2987 if (*place) optarg = place; /* no white space */ 2988 else if (nargc <= ++optind) { /* no arg */ 2989 place = EMSG; 2990 tell(": option requires an argument -- "); 2991 } 2992 else optarg = nargv[optind]; /* white space */ 2993 place = EMSG; 2994 ++optind; 2995 } 2996 return optopt; /* dump back option letter */ 2997 } 2998 2999 #endif /* !SM_CONF_GETOPT */ 3000 /* 3001 ** USERSHELLOK -- tell if a user's shell is ok for unrestricted use 3002 ** 3003 ** Parameters: 3004 ** user -- the name of the user we are checking. 3005 ** shell -- the user's shell from /etc/passwd 3006 ** 3007 ** Returns: 3008 ** true -- if it is ok to use this for unrestricted access. 3009 ** false -- if the shell is restricted. 3010 */ 3011 3012 #if !HASGETUSERSHELL 3013 3014 # ifndef _PATH_SHELLS 3015 # define _PATH_SHELLS "/etc/shells" 3016 # endif /* ! _PATH_SHELLS */ 3017 3018 # if defined(_AIX3) || defined(_AIX4) 3019 # include <userconf.h> 3020 # if _AIX4 >= 40200 3021 # include <userpw.h> 3022 # endif /* _AIX4 >= 40200 */ 3023 # include <usersec.h> 3024 # endif /* defined(_AIX3) || defined(_AIX4) */ 3025 3026 static char *DefaultUserShells[] = 3027 { 3028 "/bin/sh", /* standard shell */ 3029 # ifdef MPE 3030 "/SYS/PUB/CI", 3031 # else /* MPE */ 3032 "/usr/bin/sh", 3033 "/bin/csh", /* C shell */ 3034 "/usr/bin/csh", 3035 # endif /* MPE */ 3036 # ifdef __hpux 3037 # ifdef V4FS 3038 "/usr/bin/rsh", /* restricted Bourne shell */ 3039 "/usr/bin/ksh", /* Korn shell */ 3040 "/usr/bin/rksh", /* restricted Korn shell */ 3041 "/usr/bin/pam", 3042 "/usr/bin/keysh", /* key shell (extended Korn shell) */ 3043 "/usr/bin/posix/sh", 3044 # else /* V4FS */ 3045 "/bin/rsh", /* restricted Bourne shell */ 3046 "/bin/ksh", /* Korn shell */ 3047 "/bin/rksh", /* restricted Korn shell */ 3048 "/bin/pam", 3049 "/usr/bin/keysh", /* key shell (extended Korn shell) */ 3050 "/bin/posix/sh", 3051 "/sbin/sh" 3052 # endif /* V4FS */ 3053 # endif /* __hpux */ 3054 # if defined(_AIX3) || defined(_AIX4) 3055 "/bin/ksh", /* Korn shell */ 3056 "/usr/bin/ksh", 3057 "/bin/tsh", /* trusted shell */ 3058 "/usr/bin/tsh", 3059 "/bin/bsh", /* Bourne shell */ 3060 "/usr/bin/bsh", 3061 # endif /* defined(_AIX3) || defined(_AIX4) */ 3062 # if defined(__svr4__) || defined(__svr5__) 3063 "/bin/ksh", /* Korn shell */ 3064 "/usr/bin/ksh", 3065 # endif /* defined(__svr4__) || defined(__svr5__) */ 3066 # ifdef sgi 3067 "/sbin/sh", /* SGI's shells really live in /sbin */ 3068 "/sbin/csh", 3069 "/bin/ksh", /* Korn shell */ 3070 "/sbin/ksh", 3071 "/usr/bin/ksh", 3072 "/bin/tcsh", /* Extended csh */ 3073 "/usr/bin/tcsh", 3074 # endif /* sgi */ 3075 NULL 3076 }; 3077 3078 #endif /* !HASGETUSERSHELL */ 3079 3080 #define WILDCARD_SHELL "/SENDMAIL/ANY/SHELL/" 3081 3082 bool 3083 usershellok(user, shell) 3084 char *user; 3085 char *shell; 3086 { 3087 # if HASGETUSERSHELL 3088 register char *p; 3089 extern char *getusershell(); 3090 3091 if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') || 3092 ConfigLevel <= 1) 3093 return true; 3094 3095 setusershell(); 3096 while ((p = getusershell()) != NULL) 3097 if (strcmp(p, shell) == 0 || strcmp(p, WILDCARD_SHELL) == 0) 3098 break; 3099 endusershell(); 3100 return p != NULL; 3101 # else /* HASGETUSERSHELL */ 3102 # if USEGETCONFATTR 3103 auto char *v; 3104 # endif /* USEGETCONFATTR */ 3105 register SM_FILE_T *shellf; 3106 char buf[MAXLINE]; 3107 3108 if (shell == NULL || shell[0] == '\0' || wordinclass(user, 't') || 3109 ConfigLevel <= 1) 3110 return true; 3111 3112 # if USEGETCONFATTR 3113 /* 3114 ** Naturally IBM has a "better" idea..... 3115 ** 3116 ** What a crock. This interface isn't documented, it is 3117 ** considered part of the security library (-ls), and it 3118 ** only works if you are running as root (since the list 3119 ** of valid shells is obviously a source of great concern). 3120 ** I recommend that you do NOT define USEGETCONFATTR, 3121 ** especially since you are going to have to set up an 3122 ** /etc/shells anyhow to handle the cases where getconfattr 3123 ** fails. 3124 */ 3125 3126 if (getconfattr(SC_SYS_LOGIN, SC_SHELLS, &v, SEC_LIST) == 0 && v != NULL) 3127 { 3128 while (*v != '\0') 3129 { 3130 if (strcmp(v, shell) == 0 || strcmp(v, WILDCARD_SHELL) == 0) 3131 return true; 3132 v += strlen(v) + 1; 3133 } 3134 return false; 3135 } 3136 # endif /* USEGETCONFATTR */ 3137 3138 shellf = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, _PATH_SHELLS, 3139 SM_IO_RDONLY, NULL); 3140 if (shellf == NULL) 3141 { 3142 /* no /etc/shells; see if it is one of the std shells */ 3143 char **d; 3144 3145 if (errno != ENOENT && LogLevel > 3) 3146 sm_syslog(LOG_ERR, NOQID, 3147 "usershellok: cannot open %s: %s", 3148 _PATH_SHELLS, sm_errstring(errno)); 3149 3150 for (d = DefaultUserShells; *d != NULL; d++) 3151 { 3152 if (strcmp(shell, *d) == 0) 3153 return true; 3154 } 3155 return false; 3156 } 3157 3158 while (sm_io_fgets(shellf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 3159 { 3160 register char *p, *q; 3161 3162 p = buf; 3163 while (*p != '\0' && *p != '#' && *p != '/') 3164 p++; 3165 if (*p == '#' || *p == '\0') 3166 continue; 3167 q = p; 3168 while (*p != '\0' && *p != '#' && !(isascii(*p) && isspace(*p))) 3169 p++; 3170 *p = '\0'; 3171 if (strcmp(shell, q) == 0 || strcmp(WILDCARD_SHELL, q) == 0) 3172 { 3173 (void) sm_io_close(shellf, SM_TIME_DEFAULT); 3174 return true; 3175 } 3176 } 3177 (void) sm_io_close(shellf, SM_TIME_DEFAULT); 3178 return false; 3179 # endif /* HASGETUSERSHELL */ 3180 } 3181 /* 3182 ** FREEDISKSPACE -- see how much free space is on the queue filesystem 3183 ** 3184 ** Only implemented if you have statfs. 3185 ** 3186 ** Parameters: 3187 ** dir -- the directory in question. 3188 ** bsize -- a variable into which the filesystem 3189 ** block size is stored. 3190 ** 3191 ** Returns: 3192 ** The number of blocks free on the queue filesystem. 3193 ** -1 if the statfs call fails. 3194 ** 3195 ** Side effects: 3196 ** Puts the filesystem block size into bsize. 3197 */ 3198 3199 /* statfs types */ 3200 # define SFS_NONE 0 /* no statfs implementation */ 3201 # define SFS_USTAT 1 /* use ustat */ 3202 # define SFS_4ARGS 2 /* use four-argument statfs call */ 3203 # define SFS_VFS 3 /* use <sys/vfs.h> implementation */ 3204 # define SFS_MOUNT 4 /* use <sys/mount.h> implementation */ 3205 # define SFS_STATFS 5 /* use <sys/statfs.h> implementation */ 3206 # define SFS_STATVFS 6 /* use <sys/statvfs.h> implementation */ 3207 3208 # ifndef SFS_TYPE 3209 # define SFS_TYPE SFS_NONE 3210 # endif /* ! SFS_TYPE */ 3211 3212 # if SFS_TYPE == SFS_USTAT 3213 # include <ustat.h> 3214 # endif /* SFS_TYPE == SFS_USTAT */ 3215 # if SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS 3216 # include <sys/statfs.h> 3217 # endif /* SFS_TYPE == SFS_4ARGS || SFS_TYPE == SFS_STATFS */ 3218 # if SFS_TYPE == SFS_VFS 3219 # include <sys/vfs.h> 3220 # endif /* SFS_TYPE == SFS_VFS */ 3221 # if SFS_TYPE == SFS_MOUNT 3222 # include <sys/mount.h> 3223 # endif /* SFS_TYPE == SFS_MOUNT */ 3224 # if SFS_TYPE == SFS_STATVFS 3225 # include <sys/statvfs.h> 3226 # endif /* SFS_TYPE == SFS_STATVFS */ 3227 3228 long 3229 freediskspace(dir, bsize) 3230 char *dir; 3231 long *bsize; 3232 { 3233 # if SFS_TYPE == SFS_NONE 3234 if (bsize != NULL) 3235 *bsize = 4096L; 3236 3237 /* assume free space is plentiful */ 3238 return (long) LONG_MAX; 3239 # else /* SFS_TYPE == SFS_NONE */ 3240 # if SFS_TYPE == SFS_USTAT 3241 struct ustat fs; 3242 struct stat statbuf; 3243 # define FSBLOCKSIZE DEV_BSIZE 3244 # define SFS_BAVAIL f_tfree 3245 # else /* SFS_TYPE == SFS_USTAT */ 3246 # if defined(ultrix) 3247 struct fs_data fs; 3248 # define SFS_BAVAIL fd_bfreen 3249 # define FSBLOCKSIZE 1024L 3250 # else /* defined(ultrix) */ 3251 # if SFS_TYPE == SFS_STATVFS 3252 struct statvfs fs; 3253 # define FSBLOCKSIZE fs.f_frsize 3254 # else /* SFS_TYPE == SFS_STATVFS */ 3255 struct statfs fs; 3256 # define FSBLOCKSIZE fs.f_bsize 3257 # endif /* SFS_TYPE == SFS_STATVFS */ 3258 # endif /* defined(ultrix) */ 3259 # endif /* SFS_TYPE == SFS_USTAT */ 3260 # ifndef SFS_BAVAIL 3261 # define SFS_BAVAIL f_bavail 3262 # endif /* ! SFS_BAVAIL */ 3263 3264 # if SFS_TYPE == SFS_USTAT 3265 if (stat(dir, &statbuf) == 0 && ustat(statbuf.st_dev, &fs) == 0) 3266 # else /* SFS_TYPE == SFS_USTAT */ 3267 # if SFS_TYPE == SFS_4ARGS 3268 if (statfs(dir, &fs, sizeof fs, 0) == 0) 3269 # else /* SFS_TYPE == SFS_4ARGS */ 3270 # if SFS_TYPE == SFS_STATVFS 3271 if (statvfs(dir, &fs) == 0) 3272 # else /* SFS_TYPE == SFS_STATVFS */ 3273 # if defined(ultrix) 3274 if (statfs(dir, &fs) > 0) 3275 # else /* defined(ultrix) */ 3276 if (statfs(dir, &fs) == 0) 3277 # endif /* defined(ultrix) */ 3278 # endif /* SFS_TYPE == SFS_STATVFS */ 3279 # endif /* SFS_TYPE == SFS_4ARGS */ 3280 # endif /* SFS_TYPE == SFS_USTAT */ 3281 { 3282 if (bsize != NULL) 3283 *bsize = FSBLOCKSIZE; 3284 if (fs.SFS_BAVAIL <= 0) 3285 return 0; 3286 else if (fs.SFS_BAVAIL > LONG_MAX) 3287 return (long) LONG_MAX; 3288 else 3289 return (long) fs.SFS_BAVAIL; 3290 } 3291 return -1; 3292 # endif /* SFS_TYPE == SFS_NONE */ 3293 } 3294 /* 3295 ** ENOUGHDISKSPACE -- is there enough free space on the queue file systems? 3296 ** 3297 ** Parameters: 3298 ** msize -- the size to check against. If zero, we don't yet 3299 ** know how big the message will be, so just check for 3300 ** a "reasonable" amount. 3301 ** e -- envelope, or NULL -- controls logging 3302 ** 3303 ** Returns: 3304 ** true if in every queue group there is at least one 3305 ** queue directory whose file system contains enough free space. 3306 ** false otherwise. 3307 ** 3308 ** Side Effects: 3309 ** If there is not enough disk space and e != NULL 3310 ** then sm_syslog is called. 3311 */ 3312 3313 bool 3314 enoughdiskspace(msize, e) 3315 long msize; 3316 ENVELOPE *e; 3317 { 3318 int i; 3319 3320 if (MinBlocksFree <= 0 && msize <= 0) 3321 { 3322 if (tTd(4, 80)) 3323 sm_dprintf("enoughdiskspace: no threshold\n"); 3324 return true; 3325 } 3326 3327 filesys_update(); 3328 for (i = 0; i < NumQueue; ++i) 3329 { 3330 if (pickqdir(Queue[i], msize, e) < 0) 3331 return false; 3332 } 3333 return true; 3334 } 3335 /* 3336 ** TRANSIENTERROR -- tell if an error code indicates a transient failure 3337 ** 3338 ** This looks at an errno value and tells if this is likely to 3339 ** go away if retried later. 3340 ** 3341 ** Parameters: 3342 ** err -- the errno code to classify. 3343 ** 3344 ** Returns: 3345 ** true if this is probably transient. 3346 ** false otherwise. 3347 */ 3348 3349 bool 3350 transienterror(err) 3351 int err; 3352 { 3353 switch (err) 3354 { 3355 case EIO: /* I/O error */ 3356 case ENXIO: /* Device not configured */ 3357 case EAGAIN: /* Resource temporarily unavailable */ 3358 case ENOMEM: /* Cannot allocate memory */ 3359 case ENODEV: /* Operation not supported by device */ 3360 case ENFILE: /* Too many open files in system */ 3361 case EMFILE: /* Too many open files */ 3362 case ENOSPC: /* No space left on device */ 3363 case ETIMEDOUT: /* Connection timed out */ 3364 #ifdef ESTALE 3365 case ESTALE: /* Stale NFS file handle */ 3366 #endif /* ESTALE */ 3367 #ifdef ENETDOWN 3368 case ENETDOWN: /* Network is down */ 3369 #endif /* ENETDOWN */ 3370 #ifdef ENETUNREACH 3371 case ENETUNREACH: /* Network is unreachable */ 3372 #endif /* ENETUNREACH */ 3373 #ifdef ENETRESET 3374 case ENETRESET: /* Network dropped connection on reset */ 3375 #endif /* ENETRESET */ 3376 #ifdef ECONNABORTED 3377 case ECONNABORTED: /* Software caused connection abort */ 3378 #endif /* ECONNABORTED */ 3379 #ifdef ECONNRESET 3380 case ECONNRESET: /* Connection reset by peer */ 3381 #endif /* ECONNRESET */ 3382 #ifdef ENOBUFS 3383 case ENOBUFS: /* No buffer space available */ 3384 #endif /* ENOBUFS */ 3385 #ifdef ESHUTDOWN 3386 case ESHUTDOWN: /* Can't send after socket shutdown */ 3387 #endif /* ESHUTDOWN */ 3388 #ifdef ECONNREFUSED 3389 case ECONNREFUSED: /* Connection refused */ 3390 #endif /* ECONNREFUSED */ 3391 #ifdef EHOSTDOWN 3392 case EHOSTDOWN: /* Host is down */ 3393 #endif /* EHOSTDOWN */ 3394 #ifdef EHOSTUNREACH 3395 case EHOSTUNREACH: /* No route to host */ 3396 #endif /* EHOSTUNREACH */ 3397 #ifdef EDQUOT 3398 case EDQUOT: /* Disc quota exceeded */ 3399 #endif /* EDQUOT */ 3400 #ifdef EPROCLIM 3401 case EPROCLIM: /* Too many processes */ 3402 #endif /* EPROCLIM */ 3403 #ifdef EUSERS 3404 case EUSERS: /* Too many users */ 3405 #endif /* EUSERS */ 3406 #ifdef EDEADLK 3407 case EDEADLK: /* Resource deadlock avoided */ 3408 #endif /* EDEADLK */ 3409 #ifdef EISCONN 3410 case EISCONN: /* Socket already connected */ 3411 #endif /* EISCONN */ 3412 #ifdef EINPROGRESS 3413 case EINPROGRESS: /* Operation now in progress */ 3414 #endif /* EINPROGRESS */ 3415 #ifdef EALREADY 3416 case EALREADY: /* Operation already in progress */ 3417 #endif /* EALREADY */ 3418 #ifdef EADDRINUSE 3419 case EADDRINUSE: /* Address already in use */ 3420 #endif /* EADDRINUSE */ 3421 #ifdef EADDRNOTAVAIL 3422 case EADDRNOTAVAIL: /* Can't assign requested address */ 3423 #endif /* EADDRNOTAVAIL */ 3424 #ifdef ETXTBSY 3425 case ETXTBSY: /* (Apollo) file locked */ 3426 #endif /* ETXTBSY */ 3427 #if defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) 3428 case ENOSR: /* Out of streams resources */ 3429 #endif /* defined(ENOSR) && (!defined(ENOBUFS) || (ENOBUFS != ENOSR)) */ 3430 #ifdef ENOLCK 3431 case ENOLCK: /* No locks available */ 3432 #endif /* ENOLCK */ 3433 case E_SM_OPENTIMEOUT: /* PSEUDO: open timed out */ 3434 return true; 3435 } 3436 3437 /* nope, must be permanent */ 3438 return false; 3439 } 3440 /* 3441 ** LOCKFILE -- lock a file using flock or (shudder) fcntl locking 3442 ** 3443 ** Parameters: 3444 ** fd -- the file descriptor of the file. 3445 ** filename -- the file name (for error messages). 3446 ** ext -- the filename extension. 3447 ** type -- type of the lock. Bits can be: 3448 ** LOCK_EX -- exclusive lock. 3449 ** LOCK_NB -- non-blocking. 3450 ** LOCK_UN -- unlock. 3451 ** 3452 ** Returns: 3453 ** true if the lock was acquired. 3454 ** false otherwise. 3455 */ 3456 3457 bool 3458 lockfile(fd, filename, ext, type) 3459 int fd; 3460 char *filename; 3461 char *ext; 3462 int type; 3463 { 3464 int i; 3465 int save_errno; 3466 # if !HASFLOCK 3467 int action; 3468 struct flock lfd; 3469 3470 if (ext == NULL) 3471 ext = ""; 3472 3473 memset(&lfd, '\0', sizeof lfd); 3474 if (bitset(LOCK_UN, type)) 3475 lfd.l_type = F_UNLCK; 3476 else if (bitset(LOCK_EX, type)) 3477 lfd.l_type = F_WRLCK; 3478 else 3479 lfd.l_type = F_RDLCK; 3480 3481 if (bitset(LOCK_NB, type)) 3482 action = F_SETLK; 3483 else 3484 action = F_SETLKW; 3485 3486 if (tTd(55, 60)) 3487 sm_dprintf("lockfile(%s%s, action=%d, type=%d): ", 3488 filename, ext, action, lfd.l_type); 3489 3490 while ((i = fcntl(fd, action, &lfd)) < 0 && errno == EINTR) 3491 continue; 3492 if (i >= 0) 3493 { 3494 if (tTd(55, 60)) 3495 sm_dprintf("SUCCESS\n"); 3496 return true; 3497 } 3498 save_errno = errno; 3499 3500 if (tTd(55, 60)) 3501 sm_dprintf("(%s) ", sm_errstring(save_errno)); 3502 3503 /* 3504 ** On SunOS, if you are testing using -oQ/tmp/mqueue or 3505 ** -oA/tmp/aliases or anything like that, and /tmp is mounted 3506 ** as type "tmp" (that is, served from swap space), the 3507 ** previous fcntl will fail with "Invalid argument" errors. 3508 ** Since this is fairly common during testing, we will assume 3509 ** that this indicates that the lock is successfully grabbed. 3510 */ 3511 3512 if (save_errno == EINVAL) 3513 { 3514 if (tTd(55, 60)) 3515 sm_dprintf("SUCCESS\n"); 3516 return true; 3517 } 3518 3519 if (!bitset(LOCK_NB, type) || 3520 (save_errno != EACCES && save_errno != EAGAIN)) 3521 { 3522 int omode = fcntl(fd, F_GETFL, 0); 3523 uid_t euid = geteuid(); 3524 3525 errno = save_errno; 3526 syserr("cannot lockf(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 3527 filename, ext, fd, type, omode, euid); 3528 dumpfd(fd, true, true); 3529 } 3530 # else /* !HASFLOCK */ 3531 if (ext == NULL) 3532 ext = ""; 3533 3534 if (tTd(55, 60)) 3535 sm_dprintf("lockfile(%s%s, type=%o): ", filename, ext, type); 3536 3537 while ((i = flock(fd, type)) < 0 && errno == EINTR) 3538 continue; 3539 if (i >= 0) 3540 { 3541 if (tTd(55, 60)) 3542 sm_dprintf("SUCCESS\n"); 3543 return true; 3544 } 3545 save_errno = errno; 3546 3547 if (tTd(55, 60)) 3548 sm_dprintf("(%s) ", sm_errstring(save_errno)); 3549 3550 if (!bitset(LOCK_NB, type) || save_errno != EWOULDBLOCK) 3551 { 3552 int omode = fcntl(fd, F_GETFL, 0); 3553 uid_t euid = geteuid(); 3554 3555 errno = save_errno; 3556 syserr("cannot flock(%s%s, fd=%d, type=%o, omode=%o, euid=%d)", 3557 filename, ext, fd, type, omode, euid); 3558 dumpfd(fd, true, true); 3559 } 3560 # endif /* !HASFLOCK */ 3561 if (tTd(55, 60)) 3562 sm_dprintf("FAIL\n"); 3563 errno = save_errno; 3564 return false; 3565 } 3566 /* 3567 ** CHOWNSAFE -- tell if chown is "safe" (executable only by root) 3568 ** 3569 ** Unfortunately, given that we can't predict other systems on which 3570 ** a remote mounted (NFS) filesystem will be mounted, the answer is 3571 ** almost always that this is unsafe. 3572 ** 3573 ** Note also that many operating systems have non-compliant 3574 ** implementations of the _POSIX_CHOWN_RESTRICTED variable and the 3575 ** fpathconf() routine. According to IEEE 1003.1-1990, if 3576 ** _POSIX_CHOWN_RESTRICTED is defined and not equal to -1, then 3577 ** no non-root process can give away the file. However, vendors 3578 ** don't take NFS into account, so a comfortable value of 3579 ** _POSIX_CHOWN_RESTRICTED tells us nothing. 3580 ** 3581 ** Also, some systems (e.g., IRIX 6.2) return 1 from fpathconf() 3582 ** even on files where chown is not restricted. Many systems get 3583 ** this wrong on NFS-based filesystems (that is, they say that chown 3584 ** is restricted [safe] on NFS filesystems where it may not be, since 3585 ** other systems can access the same filesystem and do file giveaway; 3586 ** only the NFS server knows for sure!) Hence, it is important to 3587 ** get the value of SAFENFSPATHCONF correct -- it should be defined 3588 ** _only_ after testing (see test/t_pathconf.c) a system on an unsafe 3589 ** NFS-based filesystem to ensure that you can get meaningful results. 3590 ** If in doubt, assume unsafe! 3591 ** 3592 ** You may also need to tweak IS_SAFE_CHOWN -- it should be a 3593 ** condition indicating whether the return from pathconf indicates 3594 ** that chown is safe (typically either > 0 or >= 0 -- there isn't 3595 ** even any agreement about whether a zero return means that a file 3596 ** is or is not safe). It defaults to "> 0". 3597 ** 3598 ** If the parent directory is safe (writable only by owner back 3599 ** to the root) then we can relax slightly and trust fpathconf 3600 ** in more circumstances. This is really a crock -- if this is an 3601 ** NFS mounted filesystem then we really know nothing about the 3602 ** underlying implementation. However, most systems pessimize and 3603 ** return an error (EINVAL or EOPNOTSUPP) on NFS filesystems, which 3604 ** we interpret as unsafe, as we should. Thus, this heuristic gets 3605 ** us into a possible problem only on systems that have a broken 3606 ** pathconf implementation and which are also poorly configured 3607 ** (have :include: files in group- or world-writable directories). 3608 ** 3609 ** Parameters: 3610 ** fd -- the file descriptor to check. 3611 ** safedir -- set if the parent directory is safe. 3612 ** 3613 ** Returns: 3614 ** true -- if the chown(2) operation is "safe" -- that is, 3615 ** only root can chown the file to an arbitrary user. 3616 ** false -- if an arbitrary user can give away a file. 3617 */ 3618 3619 #ifndef IS_SAFE_CHOWN 3620 # define IS_SAFE_CHOWN > 0 3621 #endif /* ! IS_SAFE_CHOWN */ 3622 3623 bool 3624 chownsafe(fd, safedir) 3625 int fd; 3626 bool safedir; 3627 { 3628 # if (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && \ 3629 (defined(_PC_CHOWN_RESTRICTED) || defined(_GNU_TYPES_H)) 3630 int rval; 3631 3632 /* give the system administrator a chance to override */ 3633 if (bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail)) 3634 return true; 3635 3636 /* 3637 ** Some systems (e.g., SunOS) seem to have the call and the 3638 ** #define _PC_CHOWN_RESTRICTED, but don't actually implement 3639 ** the call. This heuristic checks for that. 3640 */ 3641 3642 errno = 0; 3643 rval = fpathconf(fd, _PC_CHOWN_RESTRICTED); 3644 # if SAFENFSPATHCONF 3645 return errno == 0 && rval IS_SAFE_CHOWN; 3646 # else /* SAFENFSPATHCONF */ 3647 return safedir && errno == 0 && rval IS_SAFE_CHOWN; 3648 # endif /* SAFENFSPATHCONF */ 3649 # else /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */ 3650 return bitnset(DBS_ASSUMESAFECHOWN, DontBlameSendmail); 3651 # endif /* (!defined(_POSIX_CHOWN_RESTRICTED) || _POSIX_CHOWN_RESTRICTED != -1) && ... */ 3652 } 3653 /* 3654 ** RESETLIMITS -- reset system controlled resource limits 3655 ** 3656 ** This is to avoid denial-of-service attacks 3657 ** 3658 ** Parameters: 3659 ** none 3660 ** 3661 ** Returns: 3662 ** none 3663 */ 3664 3665 #if HASSETRLIMIT 3666 # ifdef RLIMIT_NEEDS_SYS_TIME_H 3667 # include <sys/time.h> 3668 # endif /* RLIMIT_NEEDS_SYS_TIME_H */ 3669 # include <sys/resource.h> 3670 #endif /* HASSETRLIMIT */ 3671 #ifndef FD_SETSIZE 3672 # define FD_SETSIZE 256 3673 #endif /* ! FD_SETSIZE */ 3674 3675 void 3676 resetlimits() 3677 { 3678 #if HASSETRLIMIT 3679 struct rlimit lim; 3680 3681 lim.rlim_cur = lim.rlim_max = RLIM_INFINITY; 3682 (void) setrlimit(RLIMIT_CPU, &lim); 3683 (void) setrlimit(RLIMIT_FSIZE, &lim); 3684 # ifdef RLIMIT_NOFILE 3685 lim.rlim_cur = lim.rlim_max = FD_SETSIZE; 3686 (void) setrlimit(RLIMIT_NOFILE, &lim); 3687 # endif /* RLIMIT_NOFILE */ 3688 #else /* HASSETRLIMIT */ 3689 # if HASULIMIT 3690 (void) ulimit(2, 0x3fffff); 3691 (void) ulimit(4, FD_SETSIZE); 3692 # endif /* HASULIMIT */ 3693 #endif /* HASSETRLIMIT */ 3694 errno = 0; 3695 } 3696 /* 3697 ** SETVENDOR -- process vendor code from V configuration line 3698 ** 3699 ** Parameters: 3700 ** vendor -- string representation of vendor. 3701 ** 3702 ** Returns: 3703 ** true -- if ok. 3704 ** false -- if vendor code could not be processed. 3705 ** 3706 ** Side Effects: 3707 ** It is reasonable to set mode flags here to tweak 3708 ** processing in other parts of the code if necessary. 3709 ** For example, if you are a vendor that uses $%y to 3710 ** indicate YP lookups, you could enable that here. 3711 */ 3712 3713 bool 3714 setvendor(vendor) 3715 char *vendor; 3716 { 3717 if (sm_strcasecmp(vendor, "Berkeley") == 0) 3718 { 3719 VendorCode = VENDOR_BERKELEY; 3720 return true; 3721 } 3722 3723 /* add vendor extensions here */ 3724 3725 #ifdef SUN_EXTENSIONS 3726 if (sm_strcasecmp(vendor, "Sun") == 0) 3727 { 3728 VendorCode = VENDOR_SUN; 3729 return true; 3730 } 3731 #endif /* SUN_EXTENSIONS */ 3732 3733 #if defined(VENDOR_NAME) && defined(VENDOR_CODE) 3734 if (sm_strcasecmp(vendor, VENDOR_NAME) == 0) 3735 { 3736 VendorCode = VENDOR_CODE; 3737 return true; 3738 } 3739 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */ 3740 3741 return false; 3742 } 3743 /* 3744 ** GETVENDOR -- return vendor name based on vendor code 3745 ** 3746 ** Parameters: 3747 ** vendorcode -- numeric representation of vendor. 3748 ** 3749 ** Returns: 3750 ** string containing vendor name. 3751 */ 3752 3753 char * 3754 getvendor(vendorcode) 3755 int vendorcode; 3756 { 3757 #if defined(VENDOR_NAME) && defined(VENDOR_CODE) 3758 /* 3759 ** Can't have the same switch case twice so need to 3760 ** handle VENDOR_CODE outside of switch. It might 3761 ** match one of the existing VENDOR_* codes. 3762 */ 3763 3764 if (vendorcode == VENDOR_CODE) 3765 return VENDOR_NAME; 3766 #endif /* defined(VENDOR_NAME) && defined(VENDOR_CODE) */ 3767 3768 switch (vendorcode) 3769 { 3770 case VENDOR_BERKELEY: 3771 return "Berkeley"; 3772 3773 case VENDOR_SUN: 3774 return "Sun"; 3775 3776 case VENDOR_HP: 3777 return "HP"; 3778 3779 case VENDOR_IBM: 3780 return "IBM"; 3781 3782 case VENDOR_SENDMAIL: 3783 return "Sendmail"; 3784 3785 default: 3786 return "Unknown"; 3787 } 3788 } 3789 /* 3790 ** VENDOR_PRE_DEFAULTS, VENDOR_POST_DEFAULTS -- set vendor-specific defaults 3791 ** 3792 ** Vendor_pre_defaults is called before reading the configuration 3793 ** file; vendor_post_defaults is called immediately after. 3794 ** 3795 ** Parameters: 3796 ** e -- the global environment to initialize. 3797 ** 3798 ** Returns: 3799 ** none. 3800 */ 3801 3802 #if SHARE_V1 3803 int DefShareUid; /* default share uid to run as -- unused??? */ 3804 #endif /* SHARE_V1 */ 3805 3806 void 3807 vendor_pre_defaults(e) 3808 ENVELOPE *e; 3809 { 3810 #if SHARE_V1 3811 /* OTHERUID is defined in shares.h, do not be alarmed */ 3812 DefShareUid = OTHERUID; 3813 #endif /* SHARE_V1 */ 3814 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) 3815 sun_pre_defaults(e); 3816 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */ 3817 #ifdef apollo 3818 /* 3819 ** stupid domain/os can't even open 3820 ** /etc/mail/sendmail.cf without this 3821 */ 3822 3823 setuserenv("ISP", NULL); 3824 setuserenv("SYSTYPE", NULL); 3825 #endif /* apollo */ 3826 } 3827 3828 3829 void 3830 vendor_post_defaults(e) 3831 ENVELOPE *e; 3832 { 3833 #ifdef __QNX__ 3834 char *p; 3835 3836 /* Makes sure the SOCK environment variable remains */ 3837 if (p = getextenv("SOCK")) 3838 setuserenv("SOCK", p); 3839 #endif /* __QNX__ */ 3840 #if defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) 3841 sun_post_defaults(e); 3842 #endif /* defined(SUN_EXTENSIONS) && defined(SUN_DEFAULT_VALUES) */ 3843 } 3844 /* 3845 ** VENDOR_DAEMON_SETUP -- special vendor setup needed for daemon mode 3846 */ 3847 3848 void 3849 vendor_daemon_setup(e) 3850 ENVELOPE *e; 3851 { 3852 #if HASSETLOGIN 3853 (void) setlogin(RunAsUserName); 3854 #endif /* HASSETLOGIN */ 3855 #if SECUREWARE 3856 if (getluid() != -1) 3857 { 3858 usrerr("Daemon cannot have LUID"); 3859 finis(false, true, EX_USAGE); 3860 } 3861 #endif /* SECUREWARE */ 3862 } 3863 /* 3864 ** VENDOR_SET_UID -- do setup for setting a user id 3865 ** 3866 ** This is called when we are still root. 3867 ** 3868 ** Parameters: 3869 ** uid -- the uid we are about to become. 3870 ** 3871 ** Returns: 3872 ** none. 3873 */ 3874 3875 void 3876 vendor_set_uid(uid) 3877 UID_T uid; 3878 { 3879 /* 3880 ** We need to setup the share groups (lnodes) 3881 ** and add auditing information (luid's) 3882 ** before we loose our ``root''ness. 3883 */ 3884 #if SHARE_V1 3885 if (setupshares(uid, syserr) != 0) 3886 syserr("Unable to set up shares"); 3887 #endif /* SHARE_V1 */ 3888 #if SECUREWARE 3889 (void) setup_secure(uid); 3890 #endif /* SECUREWARE */ 3891 } 3892 /* 3893 ** VALIDATE_CONNECTION -- check connection for rationality 3894 ** 3895 ** If the connection is rejected, this routine should log an 3896 ** appropriate message -- but should never issue any SMTP protocol. 3897 ** 3898 ** Parameters: 3899 ** sap -- a pointer to a SOCKADDR naming the peer. 3900 ** hostname -- the name corresponding to sap. 3901 ** e -- the current envelope. 3902 ** 3903 ** Returns: 3904 ** error message from rejection. 3905 ** NULL if not rejected. 3906 */ 3907 3908 #if TCPWRAPPERS 3909 # include <tcpd.h> 3910 3911 /* tcpwrappers does no logging, but you still have to declare these -- ugh */ 3912 int allow_severity = LOG_INFO; 3913 int deny_severity = LOG_NOTICE; 3914 #endif /* TCPWRAPPERS */ 3915 3916 char * 3917 validate_connection(sap, hostname, e) 3918 SOCKADDR *sap; 3919 char *hostname; 3920 ENVELOPE *e; 3921 { 3922 #if TCPWRAPPERS 3923 char *host; 3924 char *addr; 3925 extern int hosts_ctl(); 3926 #endif /* TCPWRAPPERS */ 3927 3928 if (tTd(48, 3)) 3929 sm_dprintf("validate_connection(%s, %s)\n", 3930 hostname, anynet_ntoa(sap)); 3931 3932 if (rscheck("check_relay", hostname, anynet_ntoa(sap), 3933 e, true, true, 3, NULL, NOQID) != EX_OK) 3934 { 3935 static char reject[BUFSIZ*2]; 3936 extern char MsgBuf[]; 3937 3938 if (tTd(48, 4)) 3939 sm_dprintf(" ... validate_connection: BAD (rscheck)\n"); 3940 3941 if (strlen(MsgBuf) >= 3) 3942 (void) sm_strlcpy(reject, MsgBuf, sizeof reject); 3943 else 3944 (void) sm_strlcpy(reject, "Access denied", sizeof reject); 3945 3946 return reject; 3947 } 3948 3949 #if TCPWRAPPERS 3950 if (hostname[0] == '[' && hostname[strlen(hostname) - 1] == ']') 3951 host = "unknown"; 3952 else 3953 host = hostname; 3954 addr = anynet_ntoa(sap); 3955 3956 # if NETINET6 3957 /* TCP/Wrappers don't want the IPv6: protocol label */ 3958 if (addr != NULL && sm_strncasecmp(addr, "IPv6:", 5) == 0) 3959 addr += 5; 3960 # endif /* NETINET6 */ 3961 3962 if (!hosts_ctl("sendmail", host, addr, STRING_UNKNOWN)) 3963 { 3964 if (tTd(48, 4)) 3965 sm_dprintf(" ... validate_connection: BAD (tcpwrappers)\n"); 3966 if (LogLevel > 3) 3967 sm_syslog(LOG_NOTICE, e->e_id, 3968 "tcpwrappers (%s, %s) rejection", 3969 host, addr); 3970 return "Access denied"; 3971 } 3972 #endif /* TCPWRAPPERS */ 3973 if (tTd(48, 4)) 3974 sm_dprintf(" ... validate_connection: OK\n"); 3975 return NULL; 3976 } 3977 3978 /* 3979 ** STRTOL -- convert string to long integer 3980 ** 3981 ** For systems that don't have it in the C library. 3982 ** 3983 ** This is taken verbatim from the 4.4-Lite C library. 3984 */ 3985 3986 #if NEEDSTRTOL 3987 3988 # if defined(LIBC_SCCS) && !defined(lint) 3989 static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 3990 # endif /* defined(LIBC_SCCS) && !defined(lint) */ 3991 3992 /* 3993 ** Convert a string to a long integer. 3994 ** 3995 ** Ignores `locale' stuff. Assumes that the upper and lower case 3996 ** alphabets and digits are each contiguous. 3997 */ 3998 3999 long 4000 strtol(nptr, endptr, base) 4001 const char *nptr; 4002 char **endptr; 4003 register int base; 4004 { 4005 register const char *s = nptr; 4006 register unsigned long acc; 4007 register int c; 4008 register unsigned long cutoff; 4009 register int neg = 0, any, cutlim; 4010 4011 /* 4012 ** Skip white space and pick up leading +/- sign if any. 4013 ** If base is 0, allow 0x for hex and 0 for octal, else 4014 ** assume decimal; if base is already 16, allow 0x. 4015 */ 4016 do { 4017 c = *s++; 4018 } while (isspace(c)); 4019 if (c == '-') { 4020 neg = 1; 4021 c = *s++; 4022 } else if (c == '+') 4023 c = *s++; 4024 if ((base == 0 || base == 16) && 4025 c == '0' && (*s == 'x' || *s == 'X')) { 4026 c = s[1]; 4027 s += 2; 4028 base = 16; 4029 } 4030 if (base == 0) 4031 base = c == '0' ? 8 : 10; 4032 4033 /* 4034 ** Compute the cutoff value between legal numbers and illegal 4035 ** numbers. That is the largest legal value, divided by the 4036 ** base. An input number that is greater than this value, if 4037 ** followed by a legal input character, is too big. One that 4038 ** is equal to this value may be valid or not; the limit 4039 ** between valid and invalid numbers is then based on the last 4040 ** digit. For instance, if the range for longs is 4041 ** [-2147483648..2147483647] and the input base is 10, 4042 ** cutoff will be set to 214748364 and cutlim to either 4043 ** 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 4044 ** a value > 214748364, or equal but the next digit is > 7 (or 8), 4045 ** the number is too big, and we will return a range error. 4046 ** 4047 ** Set any if any `digits' consumed; make it negative to indicate 4048 ** overflow. 4049 */ 4050 cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX; 4051 cutlim = cutoff % (unsigned long) base; 4052 cutoff /= (unsigned long) base; 4053 for (acc = 0, any = 0;; c = *s++) { 4054 if (isdigit(c)) 4055 c -= '0'; 4056 else if (isalpha(c)) 4057 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 4058 else 4059 break; 4060 if (c >= base) 4061 break; 4062 if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) 4063 any = -1; 4064 else { 4065 any = 1; 4066 acc *= base; 4067 acc += c; 4068 } 4069 } 4070 if (any < 0) { 4071 acc = neg ? LONG_MIN : LONG_MAX; 4072 errno = ERANGE; 4073 } else if (neg) 4074 acc = -acc; 4075 if (endptr != 0) 4076 *endptr = (char *)(any ? s - 1 : nptr); 4077 return acc; 4078 } 4079 4080 #endif /* NEEDSTRTOL */ 4081 /* 4082 ** STRSTR -- find first substring in string 4083 ** 4084 ** Parameters: 4085 ** big -- the big (full) string. 4086 ** little -- the little (sub) string. 4087 ** 4088 ** Returns: 4089 ** A pointer to the first instance of little in big. 4090 ** big if little is the null string. 4091 ** NULL if little is not contained in big. 4092 */ 4093 4094 #if NEEDSTRSTR 4095 4096 char * 4097 strstr(big, little) 4098 char *big; 4099 char *little; 4100 { 4101 register char *p = big; 4102 int l; 4103 4104 if (*little == '\0') 4105 return big; 4106 l = strlen(little); 4107 4108 while ((p = strchr(p, *little)) != NULL) 4109 { 4110 if (strncmp(p, little, l) == 0) 4111 return p; 4112 p++; 4113 } 4114 return NULL; 4115 } 4116 4117 #endif /* NEEDSTRSTR */ 4118 /* 4119 ** SM_GETHOSTBY{NAME,ADDR} -- compatibility routines for gethostbyXXX 4120 ** 4121 ** Some operating systems have wierd problems with the gethostbyXXX 4122 ** routines. For example, Solaris versions at least through 2.3 4123 ** don't properly deliver a canonical h_name field. This tries to 4124 ** work around these problems. 4125 ** 4126 ** Support IPv6 as well as IPv4. 4127 */ 4128 4129 #if NETINET6 && NEEDSGETIPNODE 4130 4131 # ifndef AI_DEFAULT 4132 # define AI_DEFAULT 0 /* dummy */ 4133 # endif /* ! AI_DEFAULT */ 4134 # ifndef AI_ADDRCONFIG 4135 # define AI_ADDRCONFIG 0 /* dummy */ 4136 # endif /* ! AI_ADDRCONFIG */ 4137 # ifndef AI_V4MAPPED 4138 # define AI_V4MAPPED 0 /* dummy */ 4139 # endif /* ! AI_V4MAPPED */ 4140 # ifndef AI_ALL 4141 # define AI_ALL 0 /* dummy */ 4142 # endif /* ! AI_ALL */ 4143 4144 static struct hostent * 4145 getipnodebyname(name, family, flags, err) 4146 char *name; 4147 int family; 4148 int flags; 4149 int *err; 4150 { 4151 bool resv6 = true; 4152 struct hostent *h; 4153 4154 if (family == AF_INET6) 4155 { 4156 /* From RFC2133, section 6.1 */ 4157 resv6 = bitset(RES_USE_INET6, _res.options); 4158 _res.options |= RES_USE_INET6; 4159 } 4160 SM_SET_H_ERRNO(0); 4161 h = gethostbyname(name); 4162 if (!resv6) 4163 _res.options &= ~RES_USE_INET6; 4164 *err = h_errno; 4165 return h; 4166 } 4167 4168 static struct hostent * 4169 getipnodebyaddr(addr, len, family, err) 4170 char *addr; 4171 int len; 4172 int family; 4173 int *err; 4174 { 4175 struct hostent *h; 4176 4177 SM_SET_H_ERRNO(0); 4178 h = gethostbyaddr(addr, len, family); 4179 *err = h_errno; 4180 return h; 4181 } 4182 4183 void 4184 freehostent(h) 4185 struct hostent *h; 4186 { 4187 /* 4188 ** Stub routine -- if they don't have getipnodeby*(), 4189 ** they probably don't have the free routine either. 4190 */ 4191 4192 return; 4193 } 4194 #endif /* NETINET6 && NEEDSGETIPNODE */ 4195 4196 struct hostent * 4197 sm_gethostbyname(name, family) 4198 char *name; 4199 int family; 4200 { 4201 int save_errno; 4202 struct hostent *h = NULL; 4203 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) 4204 # if SOLARIS == 20300 || SOLARIS == 203 4205 static struct hostent hp; 4206 static char buf[1000]; 4207 extern struct hostent *_switch_gethostbyname_r(); 4208 4209 if (tTd(61, 10)) 4210 sm_dprintf("_switch_gethostbyname_r(%s)... ", name); 4211 h = _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); 4212 save_errno = errno; 4213 # else /* SOLARIS == 20300 || SOLARIS == 203 */ 4214 extern struct hostent *__switch_gethostbyname(); 4215 4216 if (tTd(61, 10)) 4217 sm_dprintf("__switch_gethostbyname(%s)... ", name); 4218 h = __switch_gethostbyname(name); 4219 save_errno = errno; 4220 # endif /* SOLARIS == 20300 || SOLARIS == 203 */ 4221 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */ 4222 int nmaps; 4223 # if NETINET6 4224 int flags = AI_DEFAULT|AI_ALL; 4225 int err; 4226 # endif /* NETINET6 */ 4227 char *maptype[MAXMAPSTACK]; 4228 short mapreturn[MAXMAPACTIONS]; 4229 char hbuf[MAXNAME]; 4230 4231 if (tTd(61, 10)) 4232 sm_dprintf("sm_gethostbyname(%s, %d)... ", name, family); 4233 4234 # if NETINET6 4235 # if ADDRCONFIG_IS_BROKEN 4236 flags &= ~AI_ADDRCONFIG; 4237 # endif /* ADDRCONFIG_IS_BROKEN */ 4238 h = getipnodebyname(name, family, flags, &err); 4239 SM_SET_H_ERRNO(err); 4240 # else /* NETINET6 */ 4241 h = gethostbyname(name); 4242 # endif /* NETINET6 */ 4243 4244 save_errno = errno; 4245 if (h == NULL) 4246 { 4247 if (tTd(61, 10)) 4248 sm_dprintf("failure\n"); 4249 4250 nmaps = switch_map_find("hosts", maptype, mapreturn); 4251 while (--nmaps >= 0) 4252 { 4253 if (strcmp(maptype[nmaps], "nis") == 0 || 4254 strcmp(maptype[nmaps], "files") == 0) 4255 break; 4256 } 4257 4258 if (nmaps >= 0) 4259 { 4260 /* try short name */ 4261 if (strlen(name) > sizeof hbuf - 1) 4262 { 4263 errno = save_errno; 4264 return NULL; 4265 } 4266 (void) sm_strlcpy(hbuf, name, sizeof hbuf); 4267 (void) shorten_hostname(hbuf); 4268 4269 /* if it hasn't been shortened, there's no point */ 4270 if (strcmp(hbuf, name) != 0) 4271 { 4272 if (tTd(61, 10)) 4273 sm_dprintf("sm_gethostbyname(%s, %d)... ", 4274 hbuf, family); 4275 4276 # if NETINET6 4277 h = getipnodebyname(hbuf, family, flags, &err); 4278 SM_SET_H_ERRNO(err); 4279 save_errno = errno; 4280 # else /* NETINET6 */ 4281 h = gethostbyname(hbuf); 4282 save_errno = errno; 4283 # endif /* NETINET6 */ 4284 } 4285 } 4286 } 4287 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) || (defined(sony_news) && defined(__svr4)) */ 4288 if (tTd(61, 10)) 4289 { 4290 if (h == NULL) 4291 sm_dprintf("failure\n"); 4292 else 4293 { 4294 sm_dprintf("%s\n", h->h_name); 4295 if (tTd(61, 11)) 4296 { 4297 #if NETINET6 4298 struct in6_addr ia6; 4299 char buf6[INET6_ADDRSTRLEN]; 4300 #else /* NETINET6 */ 4301 struct in_addr ia; 4302 #endif /* NETINET6 */ 4303 size_t i; 4304 4305 if (h->h_aliases != NULL) 4306 for (i = 0; h->h_aliases[i] != NULL; 4307 i++) 4308 sm_dprintf("\talias: %s\n", 4309 h->h_aliases[i]); 4310 for (i = 0; h->h_addr_list[i] != NULL; i++) 4311 { 4312 char *addr; 4313 4314 #if NETINET6 4315 memmove(&ia6, h->h_addr_list[i], 4316 IN6ADDRSZ); 4317 addr = anynet_ntop(&ia6, 4318 buf6, sizeof buf6); 4319 #else /* NETINET6 */ 4320 memmove(&ia, h->h_addr_list[i], 4321 INADDRSZ); 4322 addr = (char *) inet_ntoa(ia); 4323 #endif /* NETINET6 */ 4324 if (addr != NULL) 4325 sm_dprintf("\taddr: %s\n", addr); 4326 } 4327 } 4328 } 4329 } 4330 errno = save_errno; 4331 return h; 4332 } 4333 4334 struct hostent * 4335 sm_gethostbyaddr(addr, len, type) 4336 char *addr; 4337 int len; 4338 int type; 4339 { 4340 struct hostent *hp; 4341 4342 #if NETINET6 4343 if (type == AF_INET6 && 4344 IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *) addr)) 4345 { 4346 /* Avoid reverse lookup for IPv6 unspecified address */ 4347 SM_SET_H_ERRNO(HOST_NOT_FOUND); 4348 return NULL; 4349 } 4350 #endif /* NETINET6 */ 4351 4352 #if (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) 4353 # if SOLARIS == 20300 || SOLARIS == 203 4354 { 4355 static struct hostent he; 4356 static char buf[1000]; 4357 extern struct hostent *_switch_gethostbyaddr_r(); 4358 4359 hp = _switch_gethostbyaddr_r(addr, len, type, &he, 4360 buf, sizeof(buf), &h_errno); 4361 } 4362 # else /* SOLARIS == 20300 || SOLARIS == 203 */ 4363 { 4364 extern struct hostent *__switch_gethostbyaddr(); 4365 4366 hp = __switch_gethostbyaddr(addr, len, type); 4367 } 4368 # endif /* SOLARIS == 20300 || SOLARIS == 203 */ 4369 #else /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */ 4370 # if NETINET6 4371 { 4372 int err; 4373 4374 hp = getipnodebyaddr(addr, len, type, &err); 4375 SM_SET_H_ERRNO(err); 4376 } 4377 # else /* NETINET6 */ 4378 hp = gethostbyaddr(addr, len, type); 4379 # endif /* NETINET6 */ 4380 #endif /* (SOLARIS > 10000 && SOLARIS < 20400) || (defined(SOLARIS) && SOLARIS < 204) */ 4381 return hp; 4382 } 4383 /* 4384 ** SM_GETPW{NAM,UID} -- wrapper for getpwnam and getpwuid 4385 */ 4386 4387 struct passwd * 4388 sm_getpwnam(user) 4389 char *user; 4390 { 4391 #ifdef _AIX4 4392 extern struct passwd *_getpwnam_shadow(const char *, const int); 4393 4394 return _getpwnam_shadow(user, 0); 4395 #else /* _AIX4 */ 4396 return getpwnam(user); 4397 #endif /* _AIX4 */ 4398 } 4399 4400 struct passwd * 4401 sm_getpwuid(uid) 4402 UID_T uid; 4403 { 4404 #if defined(_AIX4) && 0 4405 extern struct passwd *_getpwuid_shadow(const int, const int); 4406 4407 return _getpwuid_shadow(uid,0); 4408 #else /* defined(_AIX4) && 0 */ 4409 return getpwuid(uid); 4410 #endif /* defined(_AIX4) && 0 */ 4411 } 4412 /* 4413 ** SECUREWARE_SETUP_SECURE -- Convex SecureWare setup 4414 ** 4415 ** Set up the trusted computing environment for C2 level security 4416 ** under SecureWare. 4417 ** 4418 ** Parameters: 4419 ** uid -- uid of the user to initialize in the TCB 4420 ** 4421 ** Returns: 4422 ** none 4423 ** 4424 ** Side Effects: 4425 ** Initialized the user in the trusted computing base 4426 */ 4427 4428 #if SECUREWARE 4429 4430 # include <sys/security.h> 4431 # include <prot.h> 4432 4433 void 4434 secureware_setup_secure(uid) 4435 UID_T uid; 4436 { 4437 int rc; 4438 4439 if (getluid() != -1) 4440 return; 4441 4442 if ((rc = set_secure_info(uid)) != SSI_GOOD_RETURN) 4443 { 4444 switch (rc) 4445 { 4446 case SSI_NO_PRPW_ENTRY: 4447 syserr("No protected passwd entry, uid = %d", 4448 (int) uid); 4449 break; 4450 4451 case SSI_LOCKED: 4452 syserr("Account has been disabled, uid = %d", 4453 (int) uid); 4454 break; 4455 4456 case SSI_RETIRED: 4457 syserr("Account has been retired, uid = %d", 4458 (int) uid); 4459 break; 4460 4461 case SSI_BAD_SET_LUID: 4462 syserr("Could not set LUID, uid = %d", (int) uid); 4463 break; 4464 4465 case SSI_BAD_SET_PRIVS: 4466 syserr("Could not set kernel privs, uid = %d", 4467 (int) uid); 4468 4469 default: 4470 syserr("Unknown return code (%d) from set_secure_info(%d)", 4471 rc, (int) uid); 4472 break; 4473 } 4474 finis(false, true, EX_NOPERM); 4475 } 4476 } 4477 #endif /* SECUREWARE */ 4478 /* 4479 ** ADD_HOSTNAMES -- Add a hostname to class 'w' based on IP address 4480 ** 4481 ** Add hostnames to class 'w' based on the IP address read from 4482 ** the network interface. 4483 ** 4484 ** Parameters: 4485 ** sa -- a pointer to a SOCKADDR containing the address 4486 ** 4487 ** Returns: 4488 ** 0 if successful, -1 if host lookup fails. 4489 */ 4490 4491 static int 4492 add_hostnames(sa) 4493 SOCKADDR *sa; 4494 { 4495 struct hostent *hp; 4496 char **ha; 4497 char hnb[MAXHOSTNAMELEN]; 4498 4499 /* lookup name with IP address */ 4500 switch (sa->sa.sa_family) 4501 { 4502 #if NETINET 4503 case AF_INET: 4504 hp = sm_gethostbyaddr((char *) &sa->sin.sin_addr, 4505 sizeof(sa->sin.sin_addr), 4506 sa->sa.sa_family); 4507 break; 4508 #endif /* NETINET */ 4509 4510 #if NETINET6 4511 case AF_INET6: 4512 hp = sm_gethostbyaddr((char *) &sa->sin6.sin6_addr, 4513 sizeof(sa->sin6.sin6_addr), 4514 sa->sa.sa_family); 4515 break; 4516 #endif /* NETINET6 */ 4517 4518 default: 4519 /* Give warning about unsupported family */ 4520 if (LogLevel > 3) 4521 sm_syslog(LOG_WARNING, NOQID, 4522 "Unsupported address family %d: %.100s", 4523 sa->sa.sa_family, anynet_ntoa(sa)); 4524 return -1; 4525 } 4526 4527 if (hp == NULL) 4528 { 4529 int save_errno = errno; 4530 4531 if (LogLevel > 3 && 4532 #if NETINET6 4533 !(sa->sa.sa_family == AF_INET6 && 4534 IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr)) && 4535 #endif /* NETINET6 */ 4536 true) 4537 sm_syslog(LOG_WARNING, NOQID, 4538 "gethostbyaddr(%.100s) failed: %d", 4539 anynet_ntoa(sa), 4540 #if NAMED_BIND 4541 h_errno 4542 #else /* NAMED_BIND */ 4543 -1 4544 #endif /* NAMED_BIND */ 4545 ); 4546 errno = save_errno; 4547 return -1; 4548 } 4549 4550 /* save its cname */ 4551 if (!wordinclass((char *) hp->h_name, 'w')) 4552 { 4553 setclass('w', (char *) hp->h_name); 4554 if (tTd(0, 4)) 4555 sm_dprintf("\ta.k.a.: %s\n", hp->h_name); 4556 4557 if (sm_snprintf(hnb, sizeof hnb, "[%s]", hp->h_name) < sizeof hnb 4558 && !wordinclass((char *) hnb, 'w')) 4559 setclass('w', hnb); 4560 } 4561 else 4562 { 4563 if (tTd(0, 43)) 4564 sm_dprintf("\ta.k.a.: %s (already in $=w)\n", hp->h_name); 4565 } 4566 4567 /* save all it aliases name */ 4568 for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++) 4569 { 4570 if (!wordinclass(*ha, 'w')) 4571 { 4572 setclass('w', *ha); 4573 if (tTd(0, 4)) 4574 sm_dprintf("\ta.k.a.: %s\n", *ha); 4575 if (sm_snprintf(hnb, sizeof hnb, 4576 "[%s]", *ha) < sizeof hnb && 4577 !wordinclass((char *) hnb, 'w')) 4578 setclass('w', hnb); 4579 } 4580 else 4581 { 4582 if (tTd(0, 43)) 4583 sm_dprintf("\ta.k.a.: %s (already in $=w)\n", 4584 *ha); 4585 } 4586 } 4587 #if NETINET6 4588 freehostent(hp); 4589 #endif /* NETINET6 */ 4590 return 0; 4591 } 4592 /* 4593 ** LOAD_IF_NAMES -- load interface-specific names into $=w 4594 ** 4595 ** Parameters: 4596 ** none. 4597 ** 4598 ** Returns: 4599 ** none. 4600 ** 4601 ** Side Effects: 4602 ** Loads $=w with the names of all the interfaces. 4603 */ 4604 4605 #if !NETINET 4606 # define SIOCGIFCONF_IS_BROKEN 1 /* XXX */ 4607 #endif /* !NETINET */ 4608 4609 #if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN 4610 struct rtentry; 4611 struct mbuf; 4612 # ifndef SUNOS403 4613 # include <sys/time.h> 4614 # endif /* ! SUNOS403 */ 4615 # if (_AIX4 >= 40300) && !defined(_NET_IF_H) 4616 # undef __P 4617 # endif /* (_AIX4 >= 40300) && !defined(_NET_IF_H) */ 4618 # include <net/if.h> 4619 #endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */ 4620 4621 void 4622 load_if_names() 4623 { 4624 # if NETINET6 && defined(SIOCGLIFCONF) 4625 # ifdef __hpux 4626 4627 /* 4628 ** Unfortunately, HP has changed all of the structures, 4629 ** making life difficult for implementors. 4630 */ 4631 4632 # define lifconf if_laddrconf 4633 # define lifc_len iflc_len 4634 # define lifc_buf iflc_buf 4635 # define lifreq if_laddrreq 4636 # define lifr_addr iflr_addr 4637 # define lifr_name iflr_name 4638 # define lifr_flags iflr_flags 4639 # define ss_family sa_family 4640 # undef SIOCGLIFNUM 4641 # endif /* __hpux */ 4642 4643 int s; 4644 int i; 4645 size_t len; 4646 int numifs; 4647 char *buf; 4648 struct lifconf lifc; 4649 # ifdef SIOCGLIFNUM 4650 struct lifnum lifn; 4651 # endif /* SIOCGLIFNUM */ 4652 4653 s = socket(InetMode, SOCK_DGRAM, 0); 4654 if (s == -1) 4655 return; 4656 4657 /* get the list of known IP address from the kernel */ 4658 # ifdef __hpux 4659 i = ioctl(s, SIOCGIFNUM, (char *) &numifs); 4660 # endif /* __hpux */ 4661 # ifdef SIOCGLIFNUM 4662 lifn.lifn_family = AF_UNSPEC; 4663 lifn.lifn_flags = 0; 4664 i = ioctl(s, SIOCGLIFNUM, (char *)&lifn); 4665 numifs = lifn.lifn_count; 4666 # endif /* SIOCGLIFNUM */ 4667 4668 # if defined(__hpux) || defined(SIOCGLIFNUM) 4669 if (i < 0) 4670 { 4671 /* can't get number of interfaces -- fall back */ 4672 if (tTd(0, 4)) 4673 sm_dprintf("SIOCGLIFNUM failed: %s\n", 4674 sm_errstring(errno)); 4675 numifs = -1; 4676 } 4677 else if (tTd(0, 42)) 4678 sm_dprintf("system has %d interfaces\n", numifs); 4679 if (numifs < 0) 4680 # endif /* defined(__hpux) || defined(SIOCGLIFNUM) */ 4681 numifs = MAXINTERFACES; 4682 4683 if (numifs <= 0) 4684 { 4685 (void) close(s); 4686 return; 4687 } 4688 4689 len = lifc.lifc_len = numifs * sizeof (struct lifreq); 4690 buf = lifc.lifc_buf = xalloc(lifc.lifc_len); 4691 # ifndef __hpux 4692 lifc.lifc_family = AF_UNSPEC; 4693 lifc.lifc_flags = 0; 4694 # endif /* __hpux */ 4695 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) 4696 { 4697 if (tTd(0, 4)) 4698 sm_dprintf("SIOCGLIFCONF failed: %s\n", 4699 sm_errstring(errno)); 4700 (void) close(s); 4701 sm_free(buf); 4702 return; 4703 } 4704 4705 /* scan the list of IP address */ 4706 if (tTd(0, 40)) 4707 sm_dprintf("scanning for interface specific names, lifc_len=%ld\n", 4708 (long) len); 4709 4710 for (i = 0; i < len && i >= 0; ) 4711 { 4712 int flags; 4713 struct lifreq *ifr = (struct lifreq *)&buf[i]; 4714 SOCKADDR *sa = (SOCKADDR *) &ifr->lifr_addr; 4715 int af = ifr->lifr_addr.ss_family; 4716 char *addr; 4717 char *name; 4718 struct in6_addr ia6; 4719 struct in_addr ia; 4720 # ifdef SIOCGLIFFLAGS 4721 struct lifreq ifrf; 4722 # endif /* SIOCGLIFFLAGS */ 4723 char ip_addr[256]; 4724 char buf6[INET6_ADDRSTRLEN]; 4725 4726 /* 4727 ** We must close and recreate the socket each time 4728 ** since we don't know what type of socket it is now 4729 ** (each status function may change it). 4730 */ 4731 4732 (void) close(s); 4733 4734 s = socket(af, SOCK_DGRAM, 0); 4735 if (s == -1) 4736 { 4737 sm_free(buf); /* XXX */ 4738 return; 4739 } 4740 4741 /* 4742 ** If we don't have a complete ifr structure, 4743 ** don't try to use it. 4744 */ 4745 4746 if ((len - i) < sizeof *ifr) 4747 break; 4748 4749 # ifdef BSD4_4_SOCKADDR 4750 if (sa->sa.sa_len > sizeof ifr->lifr_addr) 4751 i += sizeof ifr->lifr_name + sa->sa.sa_len; 4752 else 4753 # endif /* BSD4_4_SOCKADDR */ 4754 i += sizeof *ifr; 4755 4756 if (tTd(0, 20)) 4757 sm_dprintf("%s\n", anynet_ntoa(sa)); 4758 4759 if (af != AF_INET && af != AF_INET6) 4760 continue; 4761 4762 # ifdef SIOCGLIFFLAGS 4763 memset(&ifrf, '\0', sizeof(struct lifreq)); 4764 (void) sm_strlcpy(ifrf.lifr_name, ifr->lifr_name, 4765 sizeof(ifrf.lifr_name)); 4766 if (ioctl(s, SIOCGLIFFLAGS, (char *) &ifrf) < 0) 4767 { 4768 if (tTd(0, 4)) 4769 sm_dprintf("SIOCGLIFFLAGS failed: %s\n", 4770 sm_errstring(errno)); 4771 continue; 4772 } 4773 4774 name = ifr->lifr_name; 4775 flags = ifrf.lifr_flags; 4776 4777 if (tTd(0, 41)) 4778 sm_dprintf("\tflags: %lx\n", (unsigned long) flags); 4779 4780 if (!bitset(IFF_UP, flags)) 4781 continue; 4782 # endif /* SIOCGLIFFLAGS */ 4783 4784 ip_addr[0] = '\0'; 4785 4786 /* extract IP address from the list*/ 4787 switch (af) 4788 { 4789 case AF_INET6: 4790 # ifdef __KAME__ 4791 /* convert into proper scoped address */ 4792 if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) || 4793 IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) && 4794 sa->sin6.sin6_scope_id == 0) 4795 { 4796 struct in6_addr *ia6p; 4797 4798 ia6p = &sa->sin6.sin6_addr; 4799 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] | 4800 ((unsigned int)ia6p->s6_addr[2] << 8)); 4801 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0; 4802 } 4803 # endif /* __KAME__ */ 4804 ia6 = sa->sin6.sin6_addr; 4805 if (IN6_IS_ADDR_UNSPECIFIED(&ia6)) 4806 { 4807 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 4808 message("WARNING: interface %s is UP with %s address", 4809 name, addr == NULL ? "(NULL)" : addr); 4810 continue; 4811 } 4812 4813 /* save IP address in text from */ 4814 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 4815 if (addr != NULL) 4816 (void) sm_snprintf(ip_addr, sizeof ip_addr, 4817 "[%.*s]", 4818 (int) sizeof ip_addr - 3, 4819 addr); 4820 break; 4821 4822 case AF_INET: 4823 ia = sa->sin.sin_addr; 4824 if (ia.s_addr == INADDR_ANY || 4825 ia.s_addr == INADDR_NONE) 4826 { 4827 message("WARNING: interface %s is UP with %s address", 4828 name, inet_ntoa(ia)); 4829 continue; 4830 } 4831 4832 /* save IP address in text from */ 4833 (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]", 4834 (int) sizeof ip_addr - 3, inet_ntoa(ia)); 4835 break; 4836 } 4837 4838 if (*ip_addr == '\0') 4839 continue; 4840 4841 if (!wordinclass(ip_addr, 'w')) 4842 { 4843 setclass('w', ip_addr); 4844 if (tTd(0, 4)) 4845 sm_dprintf("\ta.k.a.: %s\n", ip_addr); 4846 } 4847 4848 # ifdef SIOCGLIFFLAGS 4849 /* skip "loopback" interface "lo" */ 4850 if (DontProbeInterfaces == DPI_SKIPLOOPBACK && 4851 bitset(IFF_LOOPBACK, flags)) 4852 continue; 4853 # endif /* SIOCGLIFFLAGS */ 4854 (void) add_hostnames(sa); 4855 } 4856 sm_free(buf); /* XXX */ 4857 (void) close(s); 4858 # else /* NETINET6 && defined(SIOCGLIFCONF) */ 4859 # if defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN 4860 int s; 4861 int i; 4862 struct ifconf ifc; 4863 int numifs; 4864 4865 s = socket(AF_INET, SOCK_DGRAM, 0); 4866 if (s == -1) 4867 return; 4868 4869 /* get the list of known IP address from the kernel */ 4870 # if defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN 4871 if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) 4872 { 4873 /* can't get number of interfaces -- fall back */ 4874 if (tTd(0, 4)) 4875 sm_dprintf("SIOCGIFNUM failed: %s\n", 4876 sm_errstring(errno)); 4877 numifs = -1; 4878 } 4879 else if (tTd(0, 42)) 4880 sm_dprintf("system has %d interfaces\n", numifs); 4881 if (numifs < 0) 4882 # endif /* defined(SIOCGIFNUM) && !SIOCGIFNUM_IS_BROKEN */ 4883 numifs = MAXINTERFACES; 4884 4885 if (numifs <= 0) 4886 { 4887 (void) close(s); 4888 return; 4889 } 4890 ifc.ifc_len = numifs * sizeof (struct ifreq); 4891 ifc.ifc_buf = xalloc(ifc.ifc_len); 4892 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) 4893 { 4894 if (tTd(0, 4)) 4895 sm_dprintf("SIOCGIFCONF failed: %s\n", 4896 sm_errstring(errno)); 4897 (void) close(s); 4898 return; 4899 } 4900 4901 /* scan the list of IP address */ 4902 if (tTd(0, 40)) 4903 sm_dprintf("scanning for interface specific names, ifc_len=%d\n", 4904 ifc.ifc_len); 4905 4906 for (i = 0; i < ifc.ifc_len && i >= 0; ) 4907 { 4908 int af; 4909 struct ifreq *ifr = (struct ifreq *) &ifc.ifc_buf[i]; 4910 SOCKADDR *sa = (SOCKADDR *) &ifr->ifr_addr; 4911 # if NETINET6 4912 char *addr; 4913 struct in6_addr ia6; 4914 # endif /* NETINET6 */ 4915 struct in_addr ia; 4916 # ifdef SIOCGIFFLAGS 4917 struct ifreq ifrf; 4918 # endif /* SIOCGIFFLAGS */ 4919 char ip_addr[256]; 4920 # if NETINET6 4921 char buf6[INET6_ADDRSTRLEN]; 4922 # endif /* NETINET6 */ 4923 4924 /* 4925 ** If we don't have a complete ifr structure, 4926 ** don't try to use it. 4927 */ 4928 4929 if ((ifc.ifc_len - i) < sizeof *ifr) 4930 break; 4931 4932 # ifdef BSD4_4_SOCKADDR 4933 if (sa->sa.sa_len > sizeof ifr->ifr_addr) 4934 i += sizeof ifr->ifr_name + sa->sa.sa_len; 4935 else 4936 # endif /* BSD4_4_SOCKADDR */ 4937 i += sizeof *ifr; 4938 4939 if (tTd(0, 20)) 4940 sm_dprintf("%s\n", anynet_ntoa(sa)); 4941 4942 af = ifr->ifr_addr.sa_family; 4943 if (af != AF_INET 4944 # if NETINET6 4945 && af != AF_INET6 4946 # endif /* NETINET6 */ 4947 ) 4948 continue; 4949 4950 # ifdef SIOCGIFFLAGS 4951 memset(&ifrf, '\0', sizeof(struct ifreq)); 4952 (void) sm_strlcpy(ifrf.ifr_name, ifr->ifr_name, 4953 sizeof(ifrf.ifr_name)); 4954 (void) ioctl(s, SIOCGIFFLAGS, (char *) &ifrf); 4955 if (tTd(0, 41)) 4956 sm_dprintf("\tflags: %lx\n", 4957 (unsigned long) ifrf.ifr_flags); 4958 # define IFRFREF ifrf 4959 # else /* SIOCGIFFLAGS */ 4960 # define IFRFREF (*ifr) 4961 # endif /* SIOCGIFFLAGS */ 4962 4963 if (!bitset(IFF_UP, IFRFREF.ifr_flags)) 4964 continue; 4965 4966 ip_addr[0] = '\0'; 4967 4968 /* extract IP address from the list*/ 4969 switch (af) 4970 { 4971 case AF_INET: 4972 ia = sa->sin.sin_addr; 4973 if (ia.s_addr == INADDR_ANY || 4974 ia.s_addr == INADDR_NONE) 4975 { 4976 message("WARNING: interface %s is UP with %s address", 4977 ifr->ifr_name, inet_ntoa(ia)); 4978 continue; 4979 } 4980 4981 /* save IP address in text from */ 4982 (void) sm_snprintf(ip_addr, sizeof ip_addr, "[%.*s]", 4983 (int) sizeof ip_addr - 3, 4984 inet_ntoa(ia)); 4985 break; 4986 4987 # if NETINET6 4988 case AF_INET6: 4989 # ifdef __KAME__ 4990 /* convert into proper scoped address */ 4991 if ((IN6_IS_ADDR_LINKLOCAL(&sa->sin6.sin6_addr) || 4992 IN6_IS_ADDR_SITELOCAL(&sa->sin6.sin6_addr)) && 4993 sa->sin6.sin6_scope_id == 0) 4994 { 4995 struct in6_addr *ia6p; 4996 4997 ia6p = &sa->sin6.sin6_addr; 4998 sa->sin6.sin6_scope_id = ntohs(ia6p->s6_addr[3] | 4999 ((unsigned int)ia6p->s6_addr[2] << 8)); 5000 ia6p->s6_addr[2] = ia6p->s6_addr[3] = 0; 5001 } 5002 # endif /* __KAME__ */ 5003 ia6 = sa->sin6.sin6_addr; 5004 if (IN6_IS_ADDR_UNSPECIFIED(&ia6)) 5005 { 5006 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 5007 message("WARNING: interface %s is UP with %s address", 5008 ifr->ifr_name, 5009 addr == NULL ? "(NULL)" : addr); 5010 continue; 5011 } 5012 5013 /* save IP address in text from */ 5014 addr = anynet_ntop(&ia6, buf6, sizeof buf6); 5015 if (addr != NULL) 5016 (void) sm_snprintf(ip_addr, sizeof ip_addr, 5017 "[%.*s]", 5018 (int) sizeof ip_addr - 3, 5019 addr); 5020 break; 5021 5022 # endif /* NETINET6 */ 5023 } 5024 5025 if (ip_addr[0] == '\0') 5026 continue; 5027 5028 if (!wordinclass(ip_addr, 'w')) 5029 { 5030 setclass('w', ip_addr); 5031 if (tTd(0, 4)) 5032 sm_dprintf("\ta.k.a.: %s\n", ip_addr); 5033 } 5034 5035 /* skip "loopback" interface "lo" */ 5036 if (DontProbeInterfaces == DPI_SKIPLOOPBACK && 5037 bitset(IFF_LOOPBACK, IFRFREF.ifr_flags)) 5038 continue; 5039 5040 (void) add_hostnames(sa); 5041 } 5042 sm_free(ifc.ifc_buf); /* XXX */ 5043 (void) close(s); 5044 # undef IFRFREF 5045 # endif /* defined(SIOCGIFCONF) && !SIOCGIFCONF_IS_BROKEN */ 5046 # endif /* NETINET6 && defined(SIOCGLIFCONF) */ 5047 } 5048 /* 5049 ** ISLOOPBACK -- is socket address in the loopback net? 5050 ** 5051 ** Parameters: 5052 ** sa -- socket address. 5053 ** 5054 ** Returns: 5055 ** true -- is socket address in the loopback net? 5056 ** false -- otherwise 5057 ** 5058 */ 5059 5060 bool 5061 isloopback(sa) 5062 SOCKADDR sa; 5063 { 5064 #if NETINET6 5065 if (IN6_IS_ADDR_LOOPBACK(&sa.sin6.sin6_addr)) 5066 return true; 5067 #else /* NETINET6 */ 5068 /* XXX how to correctly extract IN_LOOPBACKNET part? */ 5069 if (((ntohl(sa.sin.sin_addr.s_addr) & IN_CLASSA_NET) 5070 >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) 5071 return true; 5072 #endif /* NETINET6 */ 5073 return false; 5074 } 5075 /* 5076 ** GET_NUM_PROCS_ONLINE -- return the number of processors currently online 5077 ** 5078 ** Parameters: 5079 ** none. 5080 ** 5081 ** Returns: 5082 ** The number of processors online. 5083 */ 5084 5085 static int 5086 get_num_procs_online() 5087 { 5088 int nproc = 0; 5089 5090 #ifdef USESYSCTL 5091 # if defined(CTL_HW) && defined(HW_NCPU) 5092 size_t sz; 5093 int mib[2]; 5094 5095 mib[0] = CTL_HW; 5096 mib[1] = HW_NCPU; 5097 sz = (size_t) sizeof nproc; 5098 (void) sysctl(mib, 2, &nproc, &sz, NULL, 0); 5099 # endif /* defined(CTL_HW) && defined(HW_NCPU) */ 5100 #else /* USESYSCTL */ 5101 # ifdef _SC_NPROCESSORS_ONLN 5102 nproc = (int) sysconf(_SC_NPROCESSORS_ONLN); 5103 # else /* _SC_NPROCESSORS_ONLN */ 5104 # ifdef __hpux 5105 # include <sys/pstat.h> 5106 struct pst_dynamic psd; 5107 5108 if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1) 5109 nproc = psd.psd_proc_cnt; 5110 # endif /* __hpux */ 5111 # endif /* _SC_NPROCESSORS_ONLN */ 5112 #endif /* USESYSCTL */ 5113 5114 if (nproc <= 0) 5115 nproc = 1; 5116 return nproc; 5117 } 5118 /* 5119 ** SEED_RANDOM -- seed the random number generator 5120 ** 5121 ** Parameters: 5122 ** none 5123 ** 5124 ** Returns: 5125 ** none 5126 */ 5127 5128 void 5129 seed_random() 5130 { 5131 #if HASSRANDOMDEV 5132 srandomdev(); 5133 #else /* HASSRANDOMDEV */ 5134 long seed; 5135 struct timeval t; 5136 5137 seed = (long) CurrentPid; 5138 if (gettimeofday(&t, NULL) >= 0) 5139 seed += t.tv_sec + t.tv_usec; 5140 5141 # if HASRANDOM 5142 (void) srandom(seed); 5143 # else /* HASRANDOM */ 5144 (void) srand((unsigned int) seed); 5145 # endif /* HASRANDOM */ 5146 #endif /* HASSRANDOMDEV */ 5147 } 5148 /* 5149 ** SM_SYSLOG -- syslog wrapper to keep messages under SYSLOG_BUFSIZE 5150 ** 5151 ** Parameters: 5152 ** level -- syslog level 5153 ** id -- envelope ID or NULL (NOQUEUE) 5154 ** fmt -- format string 5155 ** arg... -- arguments as implied by fmt. 5156 ** 5157 ** Returns: 5158 ** none 5159 */ 5160 5161 /* VARARGS3 */ 5162 void 5163 #ifdef __STDC__ 5164 sm_syslog(int level, const char *id, const char *fmt, ...) 5165 #else /* __STDC__ */ 5166 sm_syslog(level, id, fmt, va_alist) 5167 int level; 5168 const char *id; 5169 const char *fmt; 5170 va_dcl 5171 #endif /* __STDC__ */ 5172 { 5173 static char *buf = NULL; 5174 static size_t bufsize; 5175 char *begin, *end; 5176 int save_errno; 5177 int seq = 1; 5178 int idlen; 5179 char buf0[MAXLINE]; 5180 char *newstring; 5181 extern int SyslogPrefixLen; 5182 SM_VA_LOCAL_DECL 5183 5184 save_errno = errno; 5185 if (id == NULL) 5186 { 5187 id = "NOQUEUE"; 5188 idlen = strlen(id) + SyslogPrefixLen; 5189 } 5190 else if (strcmp(id, NOQID) == 0) 5191 { 5192 id = ""; 5193 idlen = SyslogPrefixLen; 5194 } 5195 else 5196 idlen = strlen(id) + SyslogPrefixLen; 5197 5198 if (buf == NULL) 5199 { 5200 buf = buf0; 5201 bufsize = sizeof buf0; 5202 } 5203 5204 for (;;) 5205 { 5206 int n; 5207 5208 /* print log message into buf */ 5209 SM_VA_START(ap, fmt); 5210 n = sm_vsnprintf(buf, bufsize, fmt, ap); 5211 SM_VA_END(ap); 5212 SM_ASSERT(n > 0); 5213 if (n < bufsize) 5214 break; 5215 5216 /* String too small, redo with correct size */ 5217 bufsize = n + 1; 5218 if (buf != buf0) 5219 { 5220 sm_free(buf); 5221 buf = NULL; 5222 } 5223 buf = sm_malloc_x(bufsize); 5224 } 5225 5226 /* clean up buf after it has been expanded with args */ 5227 newstring = str2prt(buf); 5228 if ((strlen(newstring) + idlen + 1) < SYSLOG_BUFSIZE) 5229 { 5230 #if LOG 5231 if (*id == '\0') 5232 syslog(level, "%s", newstring); 5233 else 5234 syslog(level, "%s: %s", id, newstring); 5235 #else /* LOG */ 5236 /*XXX should do something more sensible */ 5237 if (*id == '\0') 5238 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", 5239 newstring); 5240 else 5241 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5242 "%s: %s\n", id, newstring); 5243 #endif /* LOG */ 5244 if (buf == buf0) 5245 buf = NULL; 5246 errno = save_errno; 5247 return; 5248 } 5249 5250 /* 5251 ** additional length for splitting: " ..." + 3, where 3 is magic to 5252 ** have some data for the next entry. 5253 */ 5254 5255 #define SL_SPLIT 7 5256 5257 begin = newstring; 5258 idlen += 5; /* strlen("[999]"), see below */ 5259 while (*begin != '\0' && 5260 (strlen(begin) + idlen) > SYSLOG_BUFSIZE) 5261 { 5262 char save; 5263 5264 if (seq >= 999) 5265 { 5266 /* Too many messages */ 5267 break; 5268 } 5269 end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT; 5270 while (end > begin) 5271 { 5272 /* Break on comma or space */ 5273 if (*end == ',' || *end == ' ') 5274 { 5275 end++; /* Include separator */ 5276 break; 5277 } 5278 end--; 5279 } 5280 /* No separator, break midstring... */ 5281 if (end == begin) 5282 end = begin + SYSLOG_BUFSIZE - idlen - SL_SPLIT; 5283 save = *end; 5284 *end = 0; 5285 #if LOG 5286 syslog(level, "%s[%d]: %s ...", id, seq++, begin); 5287 #else /* LOG */ 5288 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5289 "%s[%d]: %s ...\n", id, seq++, begin); 5290 #endif /* LOG */ 5291 *end = save; 5292 begin = end; 5293 } 5294 if (seq >= 999) 5295 #if LOG 5296 syslog(level, "%s[%d]: log terminated, too many parts", 5297 id, seq); 5298 #else /* LOG */ 5299 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5300 "%s[%d]: log terminated, too many parts\n", id, seq); 5301 #endif /* LOG */ 5302 else if (*begin != '\0') 5303 #if LOG 5304 syslog(level, "%s[%d]: %s", id, seq, begin); 5305 #else /* LOG */ 5306 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 5307 "%s[%d]: %s\n", id, seq, begin); 5308 #endif /* LOG */ 5309 if (buf == buf0) 5310 buf = NULL; 5311 errno = save_errno; 5312 } 5313 /* 5314 ** HARD_SYSLOG -- call syslog repeatedly until it works 5315 ** 5316 ** Needed on HP-UX, which apparently doesn't guarantee that 5317 ** syslog succeeds during interrupt handlers. 5318 */ 5319 5320 #if defined(__hpux) && !defined(HPUX11) 5321 5322 # define MAXSYSLOGTRIES 100 5323 # undef syslog 5324 # ifdef V4FS 5325 # define XCNST const 5326 # define CAST (const char *) 5327 # else /* V4FS */ 5328 # define XCNST 5329 # define CAST 5330 # endif /* V4FS */ 5331 5332 void 5333 # ifdef __STDC__ 5334 hard_syslog(int pri, XCNST char *msg, ...) 5335 # else /* __STDC__ */ 5336 hard_syslog(pri, msg, va_alist) 5337 int pri; 5338 XCNST char *msg; 5339 va_dcl 5340 # endif /* __STDC__ */ 5341 { 5342 int i; 5343 char buf[SYSLOG_BUFSIZE]; 5344 SM_VA_LOCAL_DECL 5345 5346 SM_VA_START(ap, msg); 5347 (void) sm_vsnprintf(buf, sizeof buf, msg, ap); 5348 SM_VA_END(ap); 5349 5350 for (i = MAXSYSLOGTRIES; --i >= 0 && syslog(pri, CAST "%s", buf) < 0; ) 5351 continue; 5352 } 5353 5354 # undef CAST 5355 #endif /* defined(__hpux) && !defined(HPUX11) */ 5356 #if NEEDLOCAL_HOSTNAME_LENGTH 5357 /* 5358 ** LOCAL_HOSTNAME_LENGTH 5359 ** 5360 ** This is required to get sendmail to compile against BIND 4.9.x 5361 ** on Ultrix. 5362 ** 5363 ** Unfortunately, a Compaq Y2K patch kit provides it without 5364 ** bumping __RES in /usr/include/resolv.h so we can't automatically 5365 ** figure out whether it is needed. 5366 */ 5367 5368 int 5369 local_hostname_length(hostname) 5370 char *hostname; 5371 { 5372 size_t len_host, len_domain; 5373 5374 if (!*_res.defdname) 5375 res_init(); 5376 len_host = strlen(hostname); 5377 len_domain = strlen(_res.defdname); 5378 if (len_host > len_domain && 5379 (sm_strcasecmp(hostname + len_host - len_domain, 5380 _res.defdname) == 0) && 5381 hostname[len_host - len_domain - 1] == '.') 5382 return len_host - len_domain - 1; 5383 else 5384 return 0; 5385 } 5386 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */ 5387 5388 #if NEEDLINK 5389 /* 5390 ** LINK -- clone a file 5391 ** 5392 ** Some OS's lacks link() and hard links. Since sendmail is using 5393 ** link() as an efficient way to clone files, this implementation 5394 ** will simply do a file copy. 5395 ** 5396 ** NOTE: This link() replacement is not a generic replacement as it 5397 ** does not handle all of the semantics of the real link(2). 5398 ** 5399 ** Parameters: 5400 ** source -- pathname of existing file. 5401 ** target -- pathname of link (clone) to be created. 5402 ** 5403 ** Returns: 5404 ** 0 -- success. 5405 ** -1 -- failure, see errno for details. 5406 */ 5407 5408 int 5409 link(source, target) 5410 const char *source; 5411 const char *target; 5412 { 5413 int save_errno; 5414 int sff; 5415 int src = -1, dst = -1; 5416 ssize_t readlen; 5417 ssize_t writelen; 5418 char buf[BUFSIZ]; 5419 struct stat st; 5420 5421 sff = SFF_REGONLY|SFF_OPENASROOT; 5422 if (DontLockReadFiles) 5423 sff |= SFF_NOLOCK; 5424 5425 /* Open the original file */ 5426 src = safeopen((char *)source, O_RDONLY, 0, sff); 5427 if (src < 0) 5428 goto fail; 5429 5430 /* Obtain the size and the mode */ 5431 if (fstat(src, &st) < 0) 5432 goto fail; 5433 5434 /* Create the duplicate copy */ 5435 sff &= ~SFF_NOLOCK; 5436 sff |= SFF_CREAT; 5437 dst = safeopen((char *)target, O_CREAT|O_EXCL|O_WRONLY, 5438 st.st_mode, sff); 5439 if (dst < 0) 5440 goto fail; 5441 5442 /* Copy all of the bytes one buffer at a time */ 5443 while ((readlen = read(src, &buf, sizeof(buf))) > 0) 5444 { 5445 ssize_t left = readlen; 5446 char *p = buf; 5447 5448 while (left > 0 && 5449 (writelen = write(dst, p, (size_t) left)) >= 0) 5450 { 5451 left -= writelen; 5452 p += writelen; 5453 } 5454 if (writelen < 0) 5455 break; 5456 } 5457 5458 /* Any trouble reading? */ 5459 if (readlen < 0 || writelen < 0) 5460 goto fail; 5461 5462 /* Close the input file */ 5463 if (close(src) < 0) 5464 { 5465 src = -1; 5466 goto fail; 5467 } 5468 src = -1; 5469 5470 /* Close the output file */ 5471 if (close(dst) < 0) 5472 { 5473 /* don't set dst = -1 here so we unlink the file */ 5474 goto fail; 5475 } 5476 5477 /* Success */ 5478 return 0; 5479 5480 fail: 5481 save_errno = errno; 5482 if (src >= 0) 5483 (void) close(src); 5484 if (dst >= 0) 5485 { 5486 (void) unlink(target); 5487 (void) close(dst); 5488 } 5489 errno = save_errno; 5490 return -1; 5491 } 5492 #endif /* NEEDLINK */ 5493 5494 /* 5495 ** Compile-Time options 5496 */ 5497 5498 char *CompileOptions[] = 5499 { 5500 #if NAMED_BIND 5501 # if DNSMAP 5502 "DNSMAP", 5503 # endif /* DNSMAP */ 5504 #endif /* NAMED_BIND */ 5505 #if EGD 5506 "EGD", 5507 #endif /* EGD */ 5508 #if HESIOD 5509 "HESIOD", 5510 #endif /* HESIOD */ 5511 #if HES_GETMAILHOST 5512 "HES_GETMAILHOST", 5513 #endif /* HES_GETMAILHOST */ 5514 #if LDAPMAP 5515 "LDAPMAP", 5516 #endif /* LDAPMAP */ 5517 #if LOG 5518 "LOG", 5519 #endif /* LOG */ 5520 #if MAP_NSD 5521 "MAP_NSD", 5522 #endif /* MAP_NSD */ 5523 #if MAP_REGEX 5524 "MAP_REGEX", 5525 #endif /* MAP_REGEX */ 5526 #if MATCHGECOS 5527 "MATCHGECOS", 5528 #endif /* MATCHGECOS */ 5529 #if MILTER 5530 "MILTER", 5531 #endif /* MILTER */ 5532 #if MIME7TO8 5533 "MIME7TO8", 5534 #endif /* MIME7TO8 */ 5535 #if MIME8TO7 5536 "MIME8TO7", 5537 #endif /* MIME8TO7 */ 5538 #if NAMED_BIND 5539 "NAMED_BIND", 5540 #endif /* NAMED_BIND */ 5541 #if NDBM 5542 "NDBM", 5543 #endif /* NDBM */ 5544 #if NETINET 5545 "NETINET", 5546 #endif /* NETINET */ 5547 #if NETINET6 5548 "NETINET6", 5549 #endif /* NETINET6 */ 5550 #if NETINFO 5551 "NETINFO", 5552 #endif /* NETINFO */ 5553 #if NETISO 5554 "NETISO", 5555 #endif /* NETISO */ 5556 #if NETNS 5557 "NETNS", 5558 #endif /* NETNS */ 5559 #if NETUNIX 5560 "NETUNIX", 5561 #endif /* NETUNIX */ 5562 #if NETX25 5563 "NETX25", 5564 #endif /* NETX25 */ 5565 #if NEWDB 5566 "NEWDB", 5567 #endif /* NEWDB */ 5568 #if NIS 5569 "NIS", 5570 #endif /* NIS */ 5571 #if NISPLUS 5572 "NISPLUS", 5573 #endif /* NISPLUS */ 5574 #if NO_DH 5575 "NO_DH", 5576 #endif /* NO_DH */ 5577 #if PH_MAP 5578 "PH_MAP", 5579 #endif /* PH_MAP */ 5580 #ifdef PICKY_HELO_CHECK 5581 "PICKY_HELO_CHECK", 5582 #endif /* PICKY_HELO_CHECK */ 5583 #if PIPELINING 5584 "PIPELINING", 5585 #endif /* PIPELINING */ 5586 #if SASL 5587 # if SASL >= 20000 5588 "SASLv2", 5589 # else /* SASL >= 20000 */ 5590 "SASL", 5591 # endif /* SASL >= 20000 */ 5592 #endif /* SASL */ 5593 #if SCANF 5594 "SCANF", 5595 #endif /* SCANF */ 5596 #if SMTPDEBUG 5597 "SMTPDEBUG", 5598 #endif /* SMTPDEBUG */ 5599 #if STARTTLS 5600 "STARTTLS", 5601 #endif /* STARTTLS */ 5602 #if SUID_ROOT_FILES_OK 5603 "SUID_ROOT_FILES_OK", 5604 #endif /* SUID_ROOT_FILES_OK */ 5605 #if TCPWRAPPERS 5606 "TCPWRAPPERS", 5607 #endif /* TCPWRAPPERS */ 5608 #if TLS_NO_RSA 5609 "TLS_NO_RSA", 5610 #endif /* TLS_NO_RSA */ 5611 #if TLS_VRFY_PER_CTX 5612 "TLS_VRFY_PER_CTX", 5613 #endif /* TLS_VRFY_PER_CTX */ 5614 #if USERDB 5615 "USERDB", 5616 #endif /* USERDB */ 5617 #if USE_LDAP_INIT 5618 "USE_LDAP_INIT", 5619 #endif /* USE_LDAP_INIT */ 5620 #if XDEBUG 5621 "XDEBUG", 5622 #endif /* XDEBUG */ 5623 #if XLA 5624 "XLA", 5625 #endif /* XLA */ 5626 NULL 5627 }; 5628 5629 5630 /* 5631 ** OS compile options. 5632 */ 5633 5634 char *OsCompileOptions[] = 5635 { 5636 #if ADDRCONFIG_IS_BROKEN 5637 "ADDRCONFIG_IS_BROKEN", 5638 #endif /* ADDRCONFIG_IS_BROKEN */ 5639 #ifdef AUTO_NETINFO_HOSTS 5640 "AUTO_NETINFO_HOSTS", 5641 #endif /* AUTO_NETINFO_HOSTS */ 5642 #ifdef AUTO_NIS_ALIASES 5643 "AUTO_NIS_ALIASES", 5644 #endif /* AUTO_NIS_ALIASES */ 5645 #if BROKEN_RES_SEARCH 5646 "BROKEN_RES_SEARCH", 5647 #endif /* BROKEN_RES_SEARCH */ 5648 #ifdef BSD4_4_SOCKADDR 5649 "BSD4_4_SOCKADDR", 5650 #endif /* BSD4_4_SOCKADDR */ 5651 #if BOGUS_O_EXCL 5652 "BOGUS_O_EXCL", 5653 #endif /* BOGUS_O_EXCL */ 5654 #if DEC_OSF_BROKEN_GETPWENT 5655 "DEC_OSF_BROKEN_GETPWENT", 5656 #endif /* DEC_OSF_BROKEN_GETPWENT */ 5657 #if FAST_PID_RECYCLE 5658 "FAST_PID_RECYCLE", 5659 #endif /* FAST_PID_RECYCLE */ 5660 #if HASFCHOWN 5661 "HASFCHOWN", 5662 #endif /* HASFCHOWN */ 5663 #if HASFCHMOD 5664 "HASFCHMOD", 5665 #endif /* HASFCHMOD */ 5666 #if HASFLOCK 5667 "HASFLOCK", 5668 #endif /* HASFLOCK */ 5669 #if HASGETDTABLESIZE 5670 "HASGETDTABLESIZE", 5671 #endif /* HASGETDTABLESIZE */ 5672 #if HASGETUSERSHELL 5673 "HASGETUSERSHELL", 5674 #endif /* HASGETUSERSHELL */ 5675 #if HASINITGROUPS 5676 "HASINITGROUPS", 5677 #endif /* HASINITGROUPS */ 5678 #if HASLSTAT 5679 "HASLSTAT", 5680 #endif /* HASLSTAT */ 5681 #if HASNICE 5682 "HASNICE", 5683 #endif /* HASNICE */ 5684 #if HASRANDOM 5685 "HASRANDOM", 5686 #endif /* HASRANDOM */ 5687 #if HASRRESVPORT 5688 "HASRRESVPORT", 5689 #endif /* HASRRESVPORT */ 5690 #if HASSETEGID 5691 "HASSETEGID", 5692 #endif /* HASSETEGID */ 5693 #if HASSETLOGIN 5694 "HASSETLOGIN", 5695 #endif /* HASSETLOGIN */ 5696 #if HASSETREGID 5697 "HASSETREGID", 5698 #endif /* HASSETREGID */ 5699 #if HASSETRESGID 5700 "HASSETRESGID", 5701 #endif /* HASSETRESGID */ 5702 #if HASSETREUID 5703 "HASSETREUID", 5704 #endif /* HASSETREUID */ 5705 #if HASSETRLIMIT 5706 "HASSETRLIMIT", 5707 #endif /* HASSETRLIMIT */ 5708 #if HASSETSID 5709 "HASSETSID", 5710 #endif /* HASSETSID */ 5711 #if HASSETUSERCONTEXT 5712 "HASSETUSERCONTEXT", 5713 #endif /* HASSETUSERCONTEXT */ 5714 #if HASSETVBUF 5715 "HASSETVBUF", 5716 #endif /* HASSETVBUF */ 5717 #if HAS_ST_GEN 5718 "HAS_ST_GEN", 5719 #endif /* HAS_ST_GEN */ 5720 #if HASSRANDOMDEV 5721 "HASSRANDOMDEV", 5722 #endif /* HASSRANDOMDEV */ 5723 #if HASURANDOMDEV 5724 "HASURANDOMDEV", 5725 #endif /* HASURANDOMDEV */ 5726 #if HASSTRERROR 5727 "HASSTRERROR", 5728 #endif /* HASSTRERROR */ 5729 #if HASULIMIT 5730 "HASULIMIT", 5731 #endif /* HASULIMIT */ 5732 #if HASUNAME 5733 "HASUNAME", 5734 #endif /* HASUNAME */ 5735 #if HASUNSETENV 5736 "HASUNSETENV", 5737 #endif /* HASUNSETENV */ 5738 #if HASWAITPID 5739 "HASWAITPID", 5740 #endif /* HASWAITPID */ 5741 #if IDENTPROTO 5742 "IDENTPROTO", 5743 #endif /* IDENTPROTO */ 5744 #if IP_SRCROUTE 5745 "IP_SRCROUTE", 5746 #endif /* IP_SRCROUTE */ 5747 #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL 5748 "LOCK_ON_OPEN", 5749 #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */ 5750 #if NEEDFSYNC 5751 "NEEDFSYNC", 5752 #endif /* NEEDFSYNC */ 5753 #if NEEDLINK 5754 "NEEDLINK", 5755 #endif /* NEEDLINK */ 5756 #if NEEDLOCAL_HOSTNAME_LENGTH 5757 "NEEDLOCAL_HOSTNAME_LENGTH", 5758 #endif /* NEEDLOCAL_HOSTNAME_LENGTH */ 5759 #if NEEDSGETIPNODE 5760 "NEEDSGETIPNODE", 5761 #endif /* NEEDSGETIPNODE */ 5762 #if NEEDSTRSTR 5763 "NEEDSTRSTR", 5764 #endif /* NEEDSTRSTR */ 5765 #if NEEDSTRTOL 5766 "NEEDSTRTOL", 5767 #endif /* NEEDSTRTOL */ 5768 #ifdef NO_GETSERVBYNAME 5769 "NO_GETSERVBYNAME", 5770 #endif /* NO_GETSERVBYNAME */ 5771 #if NOFTRUNCATE 5772 "NOFTRUNCATE", 5773 #endif /* NOFTRUNCATE */ 5774 #if REQUIRES_DIR_FSYNC 5775 "REQUIRES_DIR_FSYNC", 5776 #endif /* REQUIRES_DIR_FSYNC */ 5777 #if RLIMIT_NEEDS_SYS_TIME_H 5778 "RLIMIT_NEEDS_SYS_TIME_H", 5779 #endif /* RLIMIT_NEEDS_SYS_TIME_H */ 5780 #if SAFENFSPATHCONF 5781 "SAFENFSPATHCONF", 5782 #endif /* SAFENFSPATHCONF */ 5783 #if SECUREWARE 5784 "SECUREWARE", 5785 #endif /* SECUREWARE */ 5786 #if SHARE_V1 5787 "SHARE_V1", 5788 #endif /* SHARE_V1 */ 5789 #if SIOCGIFCONF_IS_BROKEN 5790 "SIOCGIFCONF_IS_BROKEN", 5791 #endif /* SIOCGIFCONF_IS_BROKEN */ 5792 #if SIOCGIFNUM_IS_BROKEN 5793 "SIOCGIFNUM_IS_BROKEN", 5794 #endif /* SIOCGIFNUM_IS_BROKEN */ 5795 #if SNPRINTF_IS_BROKEN 5796 "SNPRINTF_IS_BROKEN", 5797 #endif /* SNPRINTF_IS_BROKEN */ 5798 #if SO_REUSEADDR_IS_BROKEN 5799 "SO_REUSEADDR_IS_BROKEN", 5800 #endif /* SO_REUSEADDR_IS_BROKEN */ 5801 #if SYS5SETPGRP 5802 "SYS5SETPGRP", 5803 #endif /* SYS5SETPGRP */ 5804 #if SYSTEM5 5805 "SYSTEM5", 5806 #endif /* SYSTEM5 */ 5807 #if USE_DOUBLE_FORK 5808 "USE_DOUBLE_FORK", 5809 #endif /* USE_DOUBLE_FORK */ 5810 #if USE_ENVIRON 5811 "USE_ENVIRON", 5812 #endif /* USE_ENVIRON */ 5813 #if USE_SA_SIGACTION 5814 "USE_SA_SIGACTION", 5815 #endif /* USE_SA_SIGACTION */ 5816 #if USE_SIGLONGJMP 5817 "USE_SIGLONGJMP", 5818 #endif /* USE_SIGLONGJMP */ 5819 #if USEGETCONFATTR 5820 "USEGETCONFATTR", 5821 #endif /* USEGETCONFATTR */ 5822 #if USESETEUID 5823 "USESETEUID", 5824 #endif /* USESETEUID */ 5825 #ifdef USESYSCTL 5826 "USESYSCTL", 5827 #endif /* USESYSCTL */ 5828 #if USING_NETSCAPE_LDAP 5829 "USING_NETSCAPE_LDAP", 5830 #endif /* USING_NETSCAPE_LDAP */ 5831 #ifdef WAITUNION 5832 "WAITUNION", 5833 #endif /* WAITUNION */ 5834 NULL 5835 }; 5836 5837 /* 5838 ** FFR compile options. 5839 */ 5840 5841 char *FFRCompileOptions[] = 5842 { 5843 #if _FFR_ADAPTIVE_EOL 5844 "_FFR_ADAPTIVE_EOL", 5845 #endif /* _FFR_ADAPTIVE_EOL */ 5846 #if _FFR_ALLOW_SASLINFO 5847 "_FFR_ALLOW_SASLINFO", 5848 #endif /* _FFR_ALLOW_SASLINFO */ 5849 #if _FFR_ALLOW_S0_ERROR_4XX 5850 "_FFR_ALLOW_S0_ERROR_4XX", 5851 #endif /* _FFR_ALLOW_S0_ERROR_4XX */ 5852 #if _FFR_BESTMX_BETTER_TRUNCATION 5853 "_FFR_BESTMX_BETTER_TRUNCATION", 5854 #endif /* _FFR_BESTMX_BETTER_TRUNCATION */ 5855 #if _FFR_CACHE_LPC 5856 /* Christophe Wolfhugel of France Telecom Oleane */ 5857 "_FFR_CACHE_LPC", 5858 #endif /* _FFR_CACHE_LPC */ 5859 #if _FFR_CATCH_BROKEN_MTAS 5860 "_FFR_CATCH_BROKEN_MTAS", 5861 #endif /* _FFR_CATCH_BROKEN_MTAS */ 5862 #if _FFR_CATCH_LONG_STRINGS 5863 "_FFR_CATCH_LONG_STRINGS", 5864 #endif /* _FFR_CATCH_LONG_STRINGS */ 5865 #if _FFR_CHECK_EOM 5866 "_FFR_CHECK_EOM", 5867 #endif /* _FFR_CHECK_EOM */ 5868 #if _FFR_CHK_QUEUE 5869 "_FFR_CHK_QUEUE", 5870 #endif /* _FFR_CHK_QUEUE */ 5871 #if _FFR_CONTROL_MSTAT 5872 "_FFR_CONTROL_MSTAT", 5873 #endif /* _FFR_CONTROL_MSTAT */ 5874 #if _FFR_DAEMON_NETUNIX 5875 "_FFR_DAEMON_NETUNIX", 5876 #endif /* _FFR_DAEMON_NETUNIX */ 5877 #if _FFR_DEPRECATE_MAILER_FLAG_I 5878 "_FFR_DEPRECATE_MAILER_FLAG_I", 5879 #endif /* _FFR_DEPRECATE_MAILER_FLAG_I */ 5880 #if _FFR_DIGUNIX_SAFECHOWN 5881 /* Problem noted by Anne Bennett of Concordia University */ 5882 "_FFR_DIGUNIX_SAFECHOWN", 5883 #endif /* _FFR_DIGUNIX_SAFECHOWN */ 5884 #if _FFR_DNSMAP_ALIASABLE 5885 /* Don Lewis of TDK */ 5886 "_FFR_DNSMAP_ALIASABLE", 5887 #endif /* _FFR_DNSMAP_ALIASABLE */ 5888 #if _FFR_DNSMAP_BASE 5889 "_FFR_DNSMAP_BASE", 5890 #endif /* _FFR_DNSMAP_BASE */ 5891 #if _FFR_DNSMAP_MULTI 5892 "_FFR_DNSMAP_MULTI", 5893 # if _FFR_DNSMAP_MULTILIMIT 5894 "_FFR_DNSMAP_MULTILIMIT", 5895 # endif /* _FFR_DNSMAP_MULTILIMIT */ 5896 #endif /* _FFR_DNSMAP_MULTI */ 5897 #if _FFR_DONTLOCKFILESFORREAD_OPTION 5898 "_FFR_DONTLOCKFILESFORREAD_OPTION", 5899 #endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 5900 # if _FFR_DONT_STOP_LOOKING 5901 /* Noted by Neil Rickert of Northern Illinois University */ 5902 "_FFR_DONT_STOP_LOOKING", 5903 # endif /* _FFR_DONT_STOP_LOOKING */ 5904 #if _FFR_DOTTED_USERNAMES 5905 "_FFR_DOTTED_USERNAMES", 5906 #endif /* _FFR_DOTTED_USERNAMES */ 5907 #if _FFR_DROP_TRUSTUSER_WARNING 5908 "_FFR_DROP_TRUSTUSER_WARNING", 5909 #endif /* _FFR_DROP_TRUSTUSER_WARNING */ 5910 #if _FFR_FIX_DASHT 5911 "_FFR_FIX_DASHT", 5912 #endif /* _FFR_FIX_DASHT */ 5913 #if _FFR_FORWARD_SYSERR 5914 "_FFR_FORWARD_SYSERR", 5915 #endif /* _FFR_FORWARD_SYSERR */ 5916 #if _FFR_GEN_ORCPT 5917 "_FFR_GEN_ORCPT", 5918 #endif /* _FFR_GEN_ORCPT */ 5919 #if _FFR_GROUPREADABLEAUTHINFOFILE 5920 "_FFR_GROUPREADABLEAUTHINFOFILE", 5921 #endif /* _FFR_GROUPREADABLEAUTHINFOFILE */ 5922 #if _FFR_HANDLE_ISO8859_GECOS 5923 /* Peter Eriksson of Linkopings universitet */ 5924 "_FFR_HANDLE_ISO8859_GECOS", 5925 #endif /* _FFR_HANDLE_ISO8859_GECOS */ 5926 #if _FFR_HDR_TYPE 5927 "_FFR_HDR_TYPE", 5928 #endif /* _FFR_HDR_TYPE */ 5929 #if _FFR_HPUX_NSSWITCH 5930 "_FFR_HPUX_NSSWITCH", 5931 #endif /* _FFR_HPUX_NSSWITCH */ 5932 #if _FFR_IGNORE_EXT_ON_HELO 5933 "_FFR_IGNORE_EXT_ON_HELO", 5934 #endif /* _FFR_IGNORE_EXT_ON_HELO */ 5935 #if _FFR_LDAP_RECURSION 5936 /* Andrew Baucom */ 5937 "_FFR_LDAP_RECURSION", 5938 #endif /* _FFR_LDAP_RECURSION */ 5939 #if _FFR_LDAP_SETVERSION 5940 "_FFR_LDAP_SETVERSION", 5941 #endif /* _FFR_LDAP_SETVERSION */ 5942 #if _FFR_LDAP_URI 5943 "_FFR_LDAP_URI", 5944 #endif /* _FFR_LDAP_URI */ 5945 #if _FFR_MAX_FORWARD_ENTRIES 5946 /* Randall S. Winchester of the University of Maryland */ 5947 "_FFR_MAX_FORWARD_ENTRIES", 5948 #endif /* _FFR_MAX_FORWARD_ENTRIES */ 5949 #if MILTER 5950 # if _FFR_MILTER_PERDAEMON 5951 "_FFR_MILTER_PERDAEMON", 5952 # endif /* _FFR_MILTER_PERDAEMON */ 5953 #endif /* MILTER */ 5954 #if _FFR_NODELAYDSN_ON_HOLD 5955 /* Steven Pitzl */ 5956 "_FFR_NODELAYDSN_ON_HOLD", 5957 #endif /* _FFR_NODELAYDSN_ON_HOLD */ 5958 #if _FFR_NO_PIPE 5959 "_FFR_NO_PIPE", 5960 #endif /* _FFR_NO_PIPE */ 5961 #if _FFR_QUARANTINE 5962 "_FFR_QUARANTINE", 5963 #endif /* _FFR_QUARANTINE */ 5964 #if _FFR_QUEUEDELAY 5965 "_FFR_QUEUEDELAY", 5966 #endif /* _FFR_QUEUEDELAY */ 5967 #if _FFR_QUEUE_GROUP_SORTORDER 5968 /* XXX: Still need to actually use qgrp->qg_sortorder */ 5969 "_FFR_QUEUE_GROUP_SORTORDER", 5970 #endif /* _FFR_QUEUE_GROUP_SORTORDER */ 5971 #if _FFR_QUEUE_MACRO 5972 "_FFR_QUEUE_MACRO", 5973 #endif /* _FFR_QUEUE_MACRO */ 5974 #if _FFR_QUEUE_RUN_PARANOIA 5975 "_FFR_QUEUE_RUN_PARANOIA", 5976 #endif /* _FFR_QUEUE_RUN_PARANOIA */ 5977 #if _FFR_QUEUE_SCHED_DBG 5978 "_FFR_QUEUE_SCHED_DBG", 5979 #endif /* _FFR_QUEUE_SCHED_DBG */ 5980 #if _FFR_REDIRECTEMPTY 5981 "_FFR_REDIRECTEMPTY", 5982 #endif /* _FFR_REDIRECTEMPTY */ 5983 #if _FFR_RESET_MACRO_GLOBALS 5984 "_FFR_RESET_MACRO_GLOBALS", 5985 #endif /* _FFR_RESET_MACRO_GLOBALS */ 5986 #if _FFR_RESPOND_ALL 5987 /* in vacation */ 5988 "_FFR_RESPOND_ALL", 5989 #endif /* _FFR_RESPOND_ALL */ 5990 #if _FFR_RHS 5991 "_FFR_RHS", 5992 #endif /* _FFR_RHS */ 5993 #if _FFR_SASL_OPT_M 5994 "_FFR_SASL_OPT_M", 5995 #endif /* _FFR_SASL_OPT_M */ 5996 #if _FFR_SELECT_SHM 5997 "_FFR_SELECT_SHM", 5998 #endif /* _FFR_SELECT_SHM */ 5999 #if _FFR_SHM_STATUS 6000 "_FFR_SHM_STATUS", 6001 #endif /* _FFR_SHM_STATUS */ 6002 #if _FFR_SMFI_OPENSOCKET 6003 "_FFR_SMFI_OPENSOCKET", 6004 #endif /* _FFR_SMFI_OPENSOCKET */ 6005 #if _FFR_SMTP_SSL 6006 "_FFR_SMTP_SSL", 6007 #endif /* _FFR_SMTP_SSL */ 6008 #if _FFR_SOFT_BOUNCE 6009 "_FFR_SOFT_BOUNCE", 6010 #endif /* _FFR_SOFT_BOUNCE */ 6011 #if _FFR_SPT_ALIGN 6012 /* Chris Adams of HiWAAY Informations Services */ 6013 "_FFR_SPT_ALIGN", 6014 #endif /* _FFR_SPT_ALIGN */ 6015 #if _FFR_TIMERS 6016 "_FFR_TIMERS", 6017 #endif /* _FFR_TIMERS */ 6018 #if _FFR_TLS_1 6019 "_FFR_TLS_1", 6020 #endif /* _FFR_TLS_1 */ 6021 #if _FFR_TRUSTED_QF 6022 "_FFR_TRUSTED_QF", 6023 #endif /* _FFR_TRUSTED_QF */ 6024 #if _FFR_USE_SETLOGIN 6025 /* Peter Philipp */ 6026 "_FFR_USE_SETLOGIN", 6027 #endif /* _FFR_USE_SETLOGIN */ 6028 NULL 6029 }; 6030 6031