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