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