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