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