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