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