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