int main(int argc, char **argv) { struct sockaddr_in serv_addr, client_addr; TSS_RESULT result; int newsd, c, option_index = 0; unsigned client_len; char *hostname = NULL; struct passwd *pwd; struct hostent *client_hostent = NULL; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"foreground", 0, NULL, 'f'}, {"config", 1, NULL, 'c'}, {0, 0, 0, 0} }; unsetenv("TCSD_USE_TCP_DEVICE"); while ((c = getopt_long(argc, argv, "fhec:", long_options, &option_index)) != -1) { switch (c) { case 'f': setenv("TCSD_FOREGROUND", "1", 1); break; case 'c': tcsd_config_file = optarg; break; case 'e': setenv("TCSD_USE_TCP_DEVICE", "1", 1); break; case 'h': /* fall through */ default: usage(); return -1; break; } } if (!tcsd_config_file) tcsd_config_file = TCSD_DEFAULT_CONFIG_FILE; if ((result = tcsd_startup())) return (int)result; sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) { LogError("Failed socket: %s", strerror(errno)); return -1; } memset(&serv_addr, 0, sizeof (serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(tcsd_options.port); /* If no remote_ops are defined, restrict connections to localhost * only at the socket. */ if (tcsd_options.remote_ops[0] == 0) serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); else serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); c = 1; setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &c, sizeof(c)); if (bind(sd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) { LogError("Failed bind: %s", strerror(errno)); return -1; } #ifndef SOLARIS pwd = getpwnam(TSS_USER_NAME); if (pwd == NULL) { if (errno == 0) { LogError("User \"%s\" not found, please add this user" " manually.", TSS_USER_NAME); } else { LogError("getpwnam(%s): %s", TSS_USER_NAME, strerror(errno)); } return TCSERR(TSS_E_INTERNAL_ERROR); } setuid(pwd->pw_uid); #endif if (listen(sd, TCSD_MAX_SOCKETS_QUEUED) < 0) { LogError("Failed listen: %s", strerror(errno)); return -1; } client_len = (unsigned)sizeof(client_addr); if (getenv("TCSD_FOREGROUND") == NULL) { if (daemon(0, 0) == -1) { perror("daemon"); tcsd_shutdown(); return -1; } } LogInfo("%s: TCSD up and running.", PACKAGE_STRING); do { newsd = accept(sd, (struct sockaddr *) &client_addr, &client_len); if (newsd < 0) { if (errno == EINTR) { if (term) break; else if (hup) { if (reload_config() != TSS_SUCCESS) LogError("Failed reloading config"); } continue; } else { LogError("Failed accept: %s", strerror(errno)); continue; } } LogDebug("accepted socket %i", newsd); if ((client_hostent = gethostbyaddr((char *) &client_addr.sin_addr, sizeof(client_addr.sin_addr), AF_INET)) == NULL) { char buf[16]; uint32_t addr = htonl(client_addr.sin_addr.s_addr); snprintf(buf, 16, "%d.%d.%d.%d", (addr & 0xff000000) >> 24, (addr & 0x00ff0000) >> 16, (addr & 0x0000ff00) >> 8, addr & 0x000000ff); LogWarn("Host name for connecting IP %s could not be resolved", buf); hostname = strdup(buf); } else { hostname = strdup(client_hostent->h_name); } tcsd_thread_create(newsd, hostname); hostname = NULL; if (hup) { if (reload_config() != TSS_SUCCESS) LogError("Failed reloading config"); } } while (term ==0);
int main(int argc, char **argv) { TSS_RESULT result; int newsd, c, rv, option_index = 0; int i; socklen_t client_len; char *hostname = NULL; fd_set rdfd_set; int num_fds = 0; int nfds = 0; int stor_errno; sigset_t sigmask, termmask, oldsigmask; struct sockaddr_storage client_addr; struct srv_sock_info socks_info[MAX_IP_PROTO]; struct passwd *pwd; struct option long_options[] = { {"help", 0, NULL, 'h'}, {"foreground", 0, NULL, 'f'}, {"config", 1, NULL, 'c'}, {0, 0, 0, 0} }; unsetenv("TCSD_USE_TCP_DEVICE"); while ((c = getopt_long(argc, argv, "fhec:", long_options, &option_index)) != -1) { switch (c) { case 'f': setenv("TCSD_FOREGROUND", "1", 1); break; case 'c': tcsd_config_file = optarg; break; case 'e': setenv("TCSD_USE_TCP_DEVICE", "1", 1); break; case 'h': /* fall through */ default: usage(); return -1; break; } } if (!tcsd_config_file) tcsd_config_file = TCSD_DEFAULT_CONFIG_FILE; if ((result = tcsd_startup())) return (int)result; #ifdef NOUSERCHECK LogWarn("will not switch user or check for file permissions. " "(Compiled with --disable-usercheck)"); #else #ifndef SOLARIS pwd = getpwnam(TSS_USER_NAME); if (pwd == NULL) { if (errno == 0) { LogError("User \"%s\" not found, please add this user" " manually.", TSS_USER_NAME); } else { LogError("getpwnam(%s): %s", TSS_USER_NAME, strerror(errno)); } return TCSERR(TSS_E_INTERNAL_ERROR); } setuid(pwd->pw_uid); #endif #endif if (setup_server_sockets(socks_info) == -1) { LogError("Could not create sockets to listen to connections. Aborting..."); return -1; } if (getenv("TCSD_FOREGROUND") == NULL) { if (daemon(0, 0) == -1) { perror("daemon"); tcsd_shutdown(socks_info); return -1; } } LogInfo("%s: TCSD up and running.", PACKAGE_STRING); sigemptyset(&sigmask); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGHUP); sigemptyset(&termmask); sigaddset(&termmask, SIGTERM); do { prepare_for_select(socks_info, &num_fds, &rdfd_set, &nfds); // Sanity check if (num_fds == 0) { LogError("No server sockets available to listen connections. Aborting..."); return -1; } // Block TERM and HUP signals to prevent race condition if (sigprocmask(SIG_BLOCK, &sigmask, &oldsigmask) == -1) { LogError("Error setting interrupt mask before accept"); } // TERM and HUP are blocked here, so its safe to test flags. if (hup) { // Config reading can be slow, so unmask SIGTERM. if (sigprocmask(SIG_UNBLOCK, &termmask, NULL) == -1) { LogError("Error unblocking SIGTERM before config reload"); } if (reload_config() != TSS_SUCCESS) LogError("Failed reloading config"); if (sigprocmask(SIG_BLOCK, &termmask, NULL) == -1) { LogError("Error blocking SIGTERM after config reload"); } } if (term) break; // Select IPv4 and IPv6 socket descriptors with appropriate sigmask. LogDebug("Waiting for connections"); rv = pselect(nfds+1, &rdfd_set, NULL, NULL, NULL, &oldsigmask); stor_errno = errno; // original mask must be set ASAP, so store errno. if (sigprocmask(SIG_SETMASK, &oldsigmask, NULL) == -1) { LogError("Error reseting signal mask to the original configuration."); } if (rv == -1) { if (stor_errno != EINTR) { LogError("Error monitoring server socket descriptors."); return -1; } continue; } for (i=0; i < num_fds; i++) { // accept connections from all IP versions (with valid sd) if (!FD_ISSET(socks_info[i].sd, &rdfd_set)) { continue; } client_len = socks_info[i].addr_len; newsd = accept(socks_info[i].sd, (struct sockaddr *) &client_addr, &client_len); if (newsd < 0) { if (errno != EINTR) LogError("Failed accept: %s", strerror(errno)); continue; } LogDebug("accepted socket %i", newsd); hostname = fetch_hostname(&client_addr, client_len); if (hostname == NULL) hostname=INVALID_ADDR_STR; tcsd_thread_create(newsd, hostname); hostname = NULL; } // for (i=0; i < MAX_IP_PROTO; i++) } while (term ==0); /* To close correctly, we must receive a SIGTERM */ tcsd_shutdown(socks_info); return 0; }