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