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