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