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