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