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