listener.c revision 71345
1/* 2 * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 */ 10 11#ifndef lint 12static char id[] = "@(#)$Id: listener.c,v 8.38.2.1.2.18 2000/12/29 19:44:28 gshapiro Exp $"; 13#endif /* ! lint */ 14 15#if _FFR_MILTER 16/* 17** listener.c -- threaded network listener 18*/ 19 20#include "libmilter.h" 21 22 23# if NETINET || NETINET6 24# include <arpa/inet.h> 25# endif /* NETINET || NETINET6 */ 26/* 27** MI_MILTEROPEN -- setup socket to listen on 28** 29** Parameters: 30** conn -- connection description 31** backlog -- listen backlog 32** socksize -- socksize of created socket 33** 34** Returns: 35** socket upon success, error code otherwise. 36*/ 37 38static socket_t 39mi_milteropen(conn, backlog, socksize, name) 40 char *conn; 41 int backlog; 42 SOCKADDR_LEN_T *socksize; 43 char *name; 44{ 45 socket_t sock; 46 int sockopt = 1; 47 char *p; 48 char *colon; 49 char *at; 50 SOCKADDR addr; 51 52 if (conn == NULL || conn[0] == '\0') 53 { 54 smi_log(SMI_LOG_ERR, "%s: empty or missing socket information", 55 name); 56 return INVALID_SOCKET; 57 } 58 (void) memset(&addr, '\0', sizeof addr); 59 60 /* protocol:filename or protocol:port@host */ 61 p = conn; 62 colon = strchr(p, ':'); 63 if (colon != NULL) 64 { 65 *colon = '\0'; 66 67 if (*p == '\0') 68 { 69#if NETUNIX 70 /* default to AF_UNIX */ 71 addr.sa.sa_family = AF_UNIX; 72 *socksize = sizeof (struct sockaddr_un); 73#else /* NETUNIX */ 74# if NETINET 75 /* default to AF_INET */ 76 addr.sa.sa_family = AF_INET; 77 *socksize = sizeof addr.sin; 78# else /* NETINET */ 79# if NETINET6 80 /* default to AF_INET6 */ 81 addr.sa.sa_family = AF_INET6; 82 *socksize = sizeof addr.sin6; 83# else /* NETINET6 */ 84 /* no protocols available */ 85 smi_log(SMI_LOG_ERR, 86 "%s: no valid socket protocols available", 87 name); 88 return INVALID_SOCKET; 89# endif /* NETINET6 */ 90# endif /* NETINET */ 91#endif /* NETUNIX */ 92 } 93#if NETUNIX 94 else if (strcasecmp(p, "unix") == 0 || 95 strcasecmp(p, "local") == 0) 96 { 97 addr.sa.sa_family = AF_UNIX; 98 *socksize = sizeof (struct sockaddr_un); 99 } 100#endif /* NETUNIX */ 101#if NETINET 102 else if (strcasecmp(p, "inet") == 0) 103 { 104 addr.sa.sa_family = AF_INET; 105 *socksize = sizeof addr.sin; 106 } 107#endif /* NETINET */ 108#if NETINET6 109 else if (strcasecmp(p, "inet6") == 0) 110 { 111 addr.sa.sa_family = AF_INET6; 112 *socksize = sizeof addr.sin6; 113 } 114#endif /* NETINET6 */ 115 else 116 { 117 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 118 name, p); 119 return INVALID_SOCKET; 120 } 121 *colon++ = ':'; 122 } 123 else 124 { 125 colon = p; 126#if NETUNIX 127 /* default to AF_UNIX */ 128 addr.sa.sa_family = AF_UNIX; 129 *socksize = sizeof (struct sockaddr_un); 130#else /* NETUNIX */ 131# if NETINET 132 /* default to AF_INET */ 133 addr.sa.sa_family = AF_INET; 134 *socksize = sizeof addr.sin; 135# else /* NETINET */ 136# if NETINET6 137 /* default to AF_INET6 */ 138 addr.sa.sa_family = AF_INET6; 139 *socksize = sizeof addr.sin6; 140# else /* NETINET6 */ 141 smi_log(SMI_LOG_ERR, "%s: unknown socket type %s", 142 name, p); 143 return INVALID_SOCKET; 144# endif /* NETINET6 */ 145# endif /* NETINET */ 146#endif /* NETUNIX */ 147 } 148 149#if NETUNIX 150 if (addr.sa.sa_family == AF_UNIX) 151 { 152# if 0 153 long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_CREAT|SFF_MUSTOWN; 154# endif /* 0 */ 155 156 at = colon; 157 if (strlcpy(addr.sunix.sun_path, colon, 158 sizeof addr.sunix.sun_path) >= 159 sizeof addr.sunix.sun_path) 160 { 161 errno = EINVAL; 162 smi_log(SMI_LOG_ERR, "%s: UNIX socket name %s too long", 163 name, colon); 164 return INVALID_SOCKET; 165 } 166# if 0 167 errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 168 S_IRUSR|S_IWUSR, NULL); 169 170 /* if not safe, don't create */ 171 if (errno != 0) 172 { 173 smi_log(SMI_LOG_ERR, 174 "%s: UNIX socket name %s unsafe", 175 name, colon); 176 return INVALID_SOCKET; 177 } 178# endif /* 0 */ 179 180 } 181#endif /* NETUNIX */ 182 183#if NETINET || NETINET6 184 if ( 185# if NETINET 186 addr.sa.sa_family == AF_INET 187# endif /* NETINET */ 188# if NETINET && NETINET6 189 || 190# endif /* NETINET && NETINET6 */ 191# if NETINET6 192 addr.sa.sa_family == AF_INET6 193# endif /* NETINET6 */ 194 ) 195 { 196 u_short port; 197 198 /* Parse port@host */ 199 at = strchr(colon, '@'); 200 if (at == NULL) 201 { 202 switch (addr.sa.sa_family) 203 { 204# if NETINET 205 case AF_INET: 206 addr.sin.sin_addr.s_addr = INADDR_ANY; 207 break; 208# endif /* NETINET */ 209 210# if NETINET6 211 case AF_INET6: 212 addr.sin6.sin6_addr = in6addr_any; 213 break; 214# endif /* NETINET6 */ 215 } 216 } 217 else 218 *at = '\0'; 219 220 if (isascii(*colon) && isdigit(*colon)) 221 port = htons((u_short) atoi(colon)); 222 else 223 { 224# ifdef NO_GETSERVBYNAME 225 smi_log(SMI_LOG_ERR, "%s: invalid port number %s", 226 name, colon); 227 return INVALID_SOCKET; 228# else /* NO_GETSERVBYNAME */ 229 register struct servent *sp; 230 231 sp = getservbyname(colon, "tcp"); 232 if (sp == NULL) 233 { 234 smi_log(SMI_LOG_ERR, 235 "%s: unknown port name %s", 236 name, colon); 237 return INVALID_SOCKET; 238 } 239 port = sp->s_port; 240# endif /* NO_GETSERVBYNAME */ 241 } 242 if (at != NULL) 243 { 244 *at++ = '@'; 245 if (*at == '[') 246 { 247 char *end; 248 249 end = strchr(at, ']'); 250 if (end != NULL) 251 { 252 bool found = FALSE; 253# if NETINET 254 unsigned long hid = INADDR_NONE; 255# endif /* NETINET */ 256# if NETINET6 257 struct sockaddr_in6 hid6; 258# endif /* NETINET6 */ 259 260 *end = '\0'; 261# if NETINET 262 if (addr.sa.sa_family == AF_INET && 263 (hid = inet_addr(&at[1])) != 264 INADDR_NONE) 265 { 266 addr.sin.sin_addr.s_addr = hid; 267 addr.sin.sin_port = port; 268 found = TRUE; 269 } 270# endif /* NETINET */ 271# if NETINET6 272 (void) memset(&hid6, '\0', sizeof hid6); 273 if (addr.sa.sa_family == AF_INET6 && 274 inet_pton(AF_INET6, &at[1], 275 &hid6.sin6_addr) == 1) 276 { 277 addr.sin6.sin6_addr = hid6.sin6_addr; 278 addr.sin6.sin6_port = port; 279 found = TRUE; 280 } 281# endif /* NETINET6 */ 282 *end = ']'; 283 if (!found) 284 { 285 smi_log(SMI_LOG_ERR, 286 "%s: Invalid numeric domain spec \"%s\"", 287 name, at); 288 return INVALID_SOCKET; 289 } 290 } 291 else 292 { 293 smi_log(SMI_LOG_ERR, 294 "%s: Invalid numeric domain spec \"%s\"", 295 name, at); 296 return INVALID_SOCKET; 297 } 298 } 299 else 300 { 301 struct hostent *hp = NULL; 302 303 hp = mi_gethostbyname(at, addr.sa.sa_family); 304 if (hp == NULL) 305 { 306 smi_log(SMI_LOG_ERR, 307 "%s: Unknown host name %s", 308 name, at); 309 return INVALID_SOCKET; 310 } 311 addr.sa.sa_family = hp->h_addrtype; 312 switch (hp->h_addrtype) 313 { 314# if NETINET 315 case AF_INET: 316 memmove(&addr.sin.sin_addr, 317 hp->h_addr, 318 INADDRSZ); 319 addr.sin.sin_port = port; 320 break; 321# endif /* NETINET */ 322 323# if NETINET6 324 case AF_INET6: 325 memmove(&addr.sin6.sin6_addr, 326 hp->h_addr, 327 IN6ADDRSZ); 328 addr.sin6.sin6_port = port; 329 break; 330# endif /* NETINET6 */ 331 332 default: 333 smi_log(SMI_LOG_ERR, 334 "%s: Unknown protocol for %s (%d)", 335 name, at, hp->h_addrtype); 336 return INVALID_SOCKET; 337 } 338# if _FFR_FREEHOSTENT && NETINET6 339 freehostent(hp); 340# endif /* _FFR_FREEHOSTENT && NETINET6 */ 341 } 342 } 343 else 344 { 345 switch (addr.sa.sa_family) 346 { 347# if NETINET 348 case AF_INET: 349 addr.sin.sin_port = port; 350 break; 351# endif /* NETINET */ 352# if NETINET6 353 case AF_INET6: 354 addr.sin6.sin6_port = port; 355 break; 356# endif /* NETINET6 */ 357 } 358 } 359 } 360#endif /* NETINET || NETINET6 */ 361 362 sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 363 if (!ValidSocket(sock)) 364 { 365 smi_log(SMI_LOG_ERR, 366 "%s: Unable to create new socket: %s", 367 name, strerror(errno)); 368 return INVALID_SOCKET; 369 } 370 371 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, 372 sizeof(sockopt)) == -1) 373 { 374 smi_log(SMI_LOG_ERR, 375 "%s: Unable to setsockopt: %s", name, strerror(errno)); 376 (void) close(sock); 377 return INVALID_SOCKET; 378 } 379 380 if (bind(sock, &addr.sa, *socksize) < 0) 381 { 382 smi_log(SMI_LOG_ERR, 383 "%s: Unable to bind to port %s: %s", 384 name, conn, strerror(errno)); 385 (void) close(sock); 386 return INVALID_SOCKET; 387 } 388 389 if (listen(sock, backlog) < 0) 390 { 391 smi_log(SMI_LOG_ERR, 392 "%s: listen call failed: %s", name, strerror(errno)); 393 (void) close(sock); 394 return INVALID_SOCKET; 395 } 396 397 return sock; 398} 399/* 400** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session 401** 402** Parameters: 403** arg -- argument to pass to mi_handle_session() 404** 405** Returns: 406** results from mi_handle_session() 407*/ 408 409void * 410mi_thread_handle_wrapper(arg) 411 void *arg; 412{ 413 return (void *) mi_handle_session(arg); 414} 415 416static socket_t listenfd = INVALID_SOCKET; 417 418static smutex_t L_Mutex; 419 420/* 421** MI_CLOSENER -- close listen socket 422** 423** Parameters: 424** none. 425** 426** Returns: 427** none. 428*/ 429 430void 431mi_closener() 432{ 433 (void) smutex_lock(&L_Mutex); 434 if (ValidSocket(listenfd)) 435 { 436 (void) close(listenfd); 437 listenfd = INVALID_SOCKET; 438 } 439 (void) smutex_unlock(&L_Mutex); 440} 441 442/* 443** MI_LISTENER -- Generic listener harness 444** 445** Open up listen port 446** Wait for connections 447** 448** Parameters: 449** conn -- connection description 450** dbg -- debug level 451** smfi -- filter structure to use 452** timeout -- timeout for reads/writes 453** 454** Returns: 455** MI_SUCCESS -- Exited normally 456** (session finished or we were told to exit) 457** MI_FAILURE -- Network initialization failed. 458*/ 459 460int 461mi_listener(conn, dbg, smfi, timeout, backlog) 462 char *conn; 463 int dbg; 464 smfiDesc_ptr smfi; 465 time_t timeout; 466 int backlog; 467{ 468 socket_t connfd = INVALID_SOCKET; 469 int sockopt = 1; 470 int r; 471 int ret = MI_SUCCESS; 472 int cnt_m = 0; 473 int cnt_t = 0; 474 sthread_t thread_id; 475 _SOCK_ADDR cliaddr; 476 SOCKADDR_LEN_T socksize; 477 SOCKADDR_LEN_T clilen; 478 SMFICTX_PTR ctx; 479 fd_set readset, excset; 480 struct timeval chktime; 481 482 if (dbg > 0) 483 smi_log(SMI_LOG_DEBUG, 484 "%s: Opening listen socket on conn %s", 485 smfi->xxfi_name, conn); 486 (void) smutex_init(&L_Mutex); 487 (void) smutex_lock(&L_Mutex); 488 listenfd = mi_milteropen(conn, backlog, &socksize, smfi->xxfi_name); 489 if (!ValidSocket(listenfd)) 490 { 491 smi_log(SMI_LOG_FATAL, 492 "%s: Unable to create listening socket on conn %s", 493 smfi->xxfi_name, conn); 494 (void) smutex_unlock(&L_Mutex); 495 return MI_FAILURE; 496 } 497 clilen = socksize; 498 499 if (listenfd >= FD_SETSIZE) 500 { 501 smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", 502 smfi->xxfi_name, listenfd, FD_SETSIZE); 503 (void) smutex_unlock(&L_Mutex); 504 return MI_FAILURE; 505 } 506 (void) smutex_unlock(&L_Mutex); 507 508 while (mi_stop() == MILTER_CONT) 509 { 510 (void) smutex_lock(&L_Mutex); 511 if (!ValidSocket(listenfd)) 512 { 513 (void) smutex_unlock(&L_Mutex); 514 break; 515 } 516 517 /* select on interface ports */ 518 FD_ZERO(&readset); 519 FD_ZERO(&excset); 520 FD_SET((u_int) listenfd, &readset); 521 FD_SET((u_int) listenfd, &excset); 522 chktime.tv_sec = MI_CHK_TIME; 523 chktime.tv_usec = 0; 524 r = select(listenfd + 1, &readset, NULL, &excset, &chktime); 525 if (r == 0) /* timeout */ 526 { 527 (void) smutex_unlock(&L_Mutex); 528 continue; /* just check mi_stop() */ 529 } 530 if (r < 0) 531 { 532 int err = errno; 533 534 (void) smutex_unlock(&L_Mutex); 535 if (err == EINTR) 536 continue; 537 ret = MI_FAILURE; 538 break; 539 } 540 if (!FD_ISSET(listenfd, &readset)) 541 { 542 /* some error: just stop for now... */ 543 ret = MI_FAILURE; 544 (void) smutex_unlock(&L_Mutex); 545 break; 546 } 547 548 connfd = accept(listenfd, (struct sockaddr *) &cliaddr, 549 &clilen); 550 (void) smutex_unlock(&L_Mutex); 551 552 if (!ValidSocket(connfd)) 553 { 554 smi_log(SMI_LOG_ERR, 555 "%s: accept() returned invalid socket", 556 smfi->xxfi_name); 557 continue; 558 } 559 560 if (setsockopt(connfd, SOL_SOCKET, SO_KEEPALIVE, 561 (void *) &sockopt, sizeof sockopt) < 0) 562 { 563 smi_log(SMI_LOG_WARN, "%s: setsockopt() failed", 564 smfi->xxfi_name); 565 /* XXX: continue? */ 566 } 567 if ((ctx = (SMFICTX_PTR) malloc(sizeof *ctx)) == NULL) 568 { 569 (void) close(connfd); 570 smi_log(SMI_LOG_ERR, "%s: malloc(ctx) failed", 571 smfi->xxfi_name); 572 sleep(++cnt_m); 573 if (cnt_m >= MAX_FAILS_M) 574 { 575 ret = MI_FAILURE; 576 break; 577 } 578 continue; 579 } 580 cnt_m = 0; 581 memset(ctx, '\0', sizeof *ctx); 582 ctx->ctx_sd = connfd; 583 ctx->ctx_dbg = dbg; 584 ctx->ctx_timeout = timeout; 585 ctx->ctx_smfi = smfi; 586#if 0 587 if (smfi->xxfi_eoh == NULL) 588 if (smfi->xxfi_eom == NULL) 589 if (smfi->xxfi_abort == NULL) 590 if (smfi->xxfi_close == NULL) 591#endif /* 0 */ 592 if (smfi->xxfi_connect == NULL) 593 ctx->ctx_pflags |= SMFIP_NOCONNECT; 594 if (smfi->xxfi_helo == NULL) 595 ctx->ctx_pflags |= SMFIP_NOHELO; 596 if (smfi->xxfi_envfrom == NULL) 597 ctx->ctx_pflags |= SMFIP_NOMAIL; 598 if (smfi->xxfi_envrcpt == NULL) 599 ctx->ctx_pflags |= SMFIP_NORCPT; 600 if (smfi->xxfi_header == NULL) 601 ctx->ctx_pflags |= SMFIP_NOHDRS; 602 if (smfi->xxfi_eoh == NULL) 603 ctx->ctx_pflags |= SMFIP_NOEOH; 604 if (smfi->xxfi_body == NULL) 605 ctx->ctx_pflags |= SMFIP_NOBODY; 606 607 if ((r = thread_create(&thread_id, 608 mi_thread_handle_wrapper, 609 (void *) ctx)) != 0) 610 { 611 smi_log(SMI_LOG_ERR, 612 "%s: thread_create() failed: %d", 613 smfi->xxfi_name, r); 614 sleep(++cnt_t); 615 (void) close(connfd); 616 free(ctx); 617 if (cnt_t >= MAX_FAILS_T) 618 { 619 ret = MI_FAILURE; 620 break; 621 } 622 continue; 623 } 624 cnt_t = 0; 625 } 626 if (ret != MI_SUCCESS) 627 mi_stop_milters(MILTER_ABRT); 628 else 629 mi_closener(); 630 (void) smutex_destroy(&L_Mutex); 631 return ret; 632} 633#endif /* _FFR_MILTER */ 634