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