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