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