static void mplex_parse(struct line line) { switch (*line.data) { case '0' ... '9': sqfill(line); break; case 'I': addnet(line); break; case 'L': line_accept(line); break; case 'F': freeze_net(line); break; case 'D': delnet(line); break; case 'S': start_ssl(line); break; case 'X': io_stop = 1; break; case 'R': io_stop = 0; reboot(line); break; default: die("Protocol violation: %s", line.data); } }
/** * Embeds a socket in a ssl connection. * @param socket the socket to be used. * @return The ssl connection or NULL if an error occured. */ int embed_ssl_socket(ssl_connection *ssl, int socket) { int ssl_error; time_t ssl_time; if (!ssl) return FALSE; if (!ssl_initialized) start_ssl(); if (socket >= 0) { ssl->socket = socket; } else { LogError("%s: Socket error!\n", prog); goto sslerror; } if ((ssl->handler = SSL_new (ssl->ctx)) == NULL) { LogError("%s: Cannot initialize the SSL handler -- %s\n", prog, SSLERROR); goto sslerror; } set_noblock(ssl->socket); if ((ssl->socket_bio = BIO_new_socket(ssl->socket, BIO_NOCLOSE)) == NULL) { LogError("%s: Cannot generate IO buffer -- %s\n", prog, SSLERROR); goto sslerror; } SSL_set_bio(ssl->handler, ssl->socket_bio, ssl->socket_bio); ssl_time = time(NULL); while ((ssl_error = SSL_connect (ssl->handler)) < 0) { if ((time(NULL) - ssl_time) > SSL_TIMEOUT) { LogError("%s: SSL service timeout!\n", prog); goto sslerror; } if (!handle_error(ssl_error, ssl)) goto sslerror; if (!BIO_should_retry(ssl->socket_bio)) goto sslerror; } ssl->cipher = (char *) SSL_get_cipher(ssl->handler); if (! update_ssl_cert_data(ssl)) { LogError("%s: Cannot get the SSL server certificate!\n", prog); goto sslerror; } return TRUE; sslerror: cleanup_ssl_socket(ssl); return FALSE; }
bool winsock2_streambuf::start_ssl() { if (m_sslhandle) return do_sslconnect(m_sslhandle); else { const SSL_METHOD * sslm = ::SSLv23_client_method(); return start_ssl(sslm); } }
/** * Initializes a ssl connection for server use. * @param pemfilename Filename for the key/cert file * @return An ssl connection, or NULL if an error occured. */ ssl_server_connection *init_ssl_server(char *pemfile, char *clientpemfile) { ASSERT(pemfile); if (!ssl_initialized) start_ssl(); ssl_server_connection *ssl_server = new_ssl_server_connection(pemfile, clientpemfile); if (!(ssl_server->method = SSLv23_server_method())) { LogError("Cannot initialize the SSL method -- %s\n", SSLERROR); goto sslerror; } if (!(ssl_server->ctx = SSL_CTX_new(ssl_server->method))) { LogError("Cannot initialize SSL server certificate handler -- %s\n", SSLERROR); goto sslerror; } if (SSL_CTX_use_certificate_chain_file(ssl_server->ctx, pemfile) != 1) { LogError("Cannot initialize SSL server certificate -- %s\n", SSLERROR); goto sslerror; } if (SSL_CTX_use_PrivateKey_file(ssl_server->ctx, pemfile, SSL_FILETYPE_PEM) != 1) { LogError("Cannot initialize SSL server private key -- %s\n", SSLERROR); goto sslerror; } if (SSL_CTX_check_private_key(ssl_server->ctx) != 1) { LogError("The private key doesn't match the certificate public key -- %s\n", SSLERROR); goto sslerror; } if (SSL_CTX_set_cipher_list(ssl_server->ctx, CIPHER_LIST) != 1) { LogError("Error setting cipher list '%s' (no valid ciphers)\n", CIPHER_LIST); goto sslerror; } SSL_CTX_set_options(ssl_server->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); // Disable SSLv2 and SSLv3 for security reasons SSL_CTX_set_session_cache_mode(ssl_server->ctx, SSL_SESS_CACHE_OFF); // Disable session cache /* * We need this to force transmission of client certs */ if (!verify_init(ssl_server)) { LogError("Verification engine was not properly initialized -- %s\n", SSLERROR); goto sslerror; } if (ssl_server->clientpemfile) { STACK_OF(X509_NAME) *stack = SSL_CTX_get_client_CA_list(ssl_server->ctx); LogInfo("Found %d client certificates\n", sk_X509_NAME_num(stack)); } return ssl_server; sslerror: delete_ssl_server_socket(ssl_server); return NULL; }
/** * Creates a server socket (SOCK_STREAM type) and binds it to the * specified local port number. The socket get a ssl layer for * data transmission. * @param pemfilename Filename for the key/cert file * @param port The localhost port number to open * @param backlog The maximum queue length for incomming connections * @param bindAddr the local address the server will bind to * @return An ssl connection ready for accept, or NULL if an error occured. */ ssl_server_connection *create_ssl_server_socket(char *pemfile, int port, int backlog, char *bindAddr, char *clientpemfile) { #ifdef HAVE_OPENSSL int socket; ssl_server_connection *ssl_server; ASSERT(pemfile); ASSERT(bindAddr); if (!ssl_initilized) { start_ssl(); } if ((socket= create_server_socket(port, backlog, bindAddr)) == -1) { log("%s: create_ssl_server_socket(): Cannot connect!\n", prog); goto sslerror; } if (( ssl_server= init_ssl_server(pemfile, clientpemfile)) == NULL) { goto sslerror; } ssl_server->server_socket=socket; return ssl_server; sslerror: return NULL; #else return FALSE; #endif }
/** * Open a socket against hostname:port with the given protocol. * This socket is sent through a ssl connection. * The protocol is normaly either SOCK_STREAM or SOCK_DGRAM. * @param hostname The host to open a socket at * @param port The port number to connect to * @param protocol Socket protocol to use (SOCK_STREAM|SOCK_DGRAM) * @param sslversion Version of the ssl layer auto, SSLv3, SSLv2 or TLS * @return The ssl connection or NULL if an error occured. */ ssl_connection *create_ssl_socket(char *hostname, int port, int protocol, int sslversion) { #ifdef HAVE_OPENSSL int socket; ssl_connection *ssl = new_ssl_connection(NULL, sslversion); ASSERT(hostname); if (!ssl_initilized) { start_ssl(); } if((socket= create_socket(hostname, port, protocol, NET_TIMEOUT)) == -1) { log("%s: create_ssl_socket(): Cannot connect!\n", prog); goto sslerror; } if (! embed_ssl_socket(ssl, socket)) { goto sslerror; } return ssl; sslerror: return NULL; #else return NULL; #endif }
/** * Generate a new ssl server connection * @return ssl server connection container */ ssl_server_connection *new_ssl_server_connection(char * pemfile, char * clientpemfile) { #ifdef HAVE_OPENSSL ssl_server_connection *ssl_server = (ssl_server_connection *) NEW(ssl_server); ASSERT(pemfile); if (!ssl_initilized) { start_ssl(); } ssl_server->ctx= NULL; ssl_server->method= NULL; ssl_server->server_socket= 0; ssl_server->ssl_conn_list = NULL; ssl_server->pemfile=xstrdup(pemfile); if(clientpemfile != NULL) { ssl_server->clientpemfile= xstrdup(clientpemfile); } else { ssl_server->clientpemfile= NULL; } return ssl_server; #else return NULL; #endif }
/** * Inserts an SSL connection in the connection list of a server. * @param ssl_server data for ssl server connection * @return new SSL connection for the connection, or NULL if failed */ ssl_connection *insert_accepted_ssl_socket(ssl_server_connection *ssl_server) { ssl_connection *ssl; ASSERT(ssl_server); if (!ssl_initialized) start_ssl(); NEW(ssl); ssl->method = NULL; ssl->handler = NULL; ssl->cert = NULL; ssl->cipher = NULL; ssl->socket = 0; ssl->next = NULL; ssl->accepted = FALSE; ssl->cert_md5= NULL; ssl->cert_md5_len = 0; ssl->clientpemfile = NULL; if (ssl_server->clientpemfile != NULL) ssl->clientpemfile = xstrdup(ssl_server->clientpemfile); LOCK(ssl_mutex); ssl->prev = NULL; ssl->next = ssl_server->ssl_conn_list; if ( ssl->next != NULL ) ssl->next->prev = ssl; END_LOCK; ssl_server->ssl_conn_list = ssl; ssl->ctx = ssl_server->ctx; ssl->accepted = TRUE; return ssl; }
/** * Generate a new ssl connection * @return ssl connection container */ ssl_connection *new_ssl_connection(char *clientpemfile, int sslversion) { ssl_connection *ssl; if (!ssl_initialized) start_ssl(); NEW(ssl); ssl->socket_bio = NULL; ssl->handler = NULL; ssl->cert = NULL; ssl->cipher = NULL; ssl->socket = 0; ssl->next = NULL; ssl->accepted = FALSE; ssl->cert_md5 = NULL; ssl->cert_md5_len = 0; ssl->clientpemfile = clientpemfile ? xstrdup(clientpemfile) : NULL; switch (sslversion) { case SSL_VERSION_AUTO: #ifdef OPENSSL_FIPS if (FIPS_mode()) { ssl->method = TLSv1_client_method(); } else #endif ssl->method = SSLv23_client_method(); break; case SSL_VERSION_SSLV2: #ifdef OPENSSL_NO_SSL2 LogError("SSLv2 is not allowed - use either SSLv3 or TLSv1"); goto sslerror; #else #ifdef OPENSSL_FIPS if (FIPS_mode()) { LogError("SSLv2 is not allowed in FIPS mode - use TLSv1"); goto sslerror; } else #endif ssl->method = SSLv2_client_method(); #endif break; case SSL_VERSION_SSLV3: #ifdef OPENSSL_FIPS if (FIPS_mode()) { LogError("SSLv3 is not allowed in FIPS mode - use TLSv1"); goto sslerror; } else #endif ssl->method = SSLv3_client_method(); break; case SSL_VERSION_TLS: ssl->method = TLSv1_client_method(); break; default: LogError("%s: Unknown SSL version!\n", prog); goto sslerror; } if (!ssl->method) { LogError("%s: Cannot initialize SSL method -- %s\n", prog, SSLERROR); goto sslerror; } if (!(ssl->ctx = SSL_CTX_new(ssl->method))) { LogError("%s: Cannot initialize SSL server certificate handler -- %s\n", prog, SSLERROR); goto sslerror; } if (ssl->clientpemfile) { if (SSL_CTX_use_certificate_chain_file(ssl->ctx, ssl->clientpemfile) <= 0) { LogError("%s: Cannot initialize SSL server certificate -- %s\n", prog, SSLERROR); goto sslerror; } if (SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->clientpemfile, SSL_FILETYPE_PEM) <= 0) { LogError("%s: Cannot initialize SSL server private key -- %s\n", prog, SSLERROR); goto sslerror; } if (!SSL_CTX_check_private_key(ssl->ctx)) { LogError("%s: Private key does not match the certificate public key -- %s\n", prog, SSLERROR); goto sslerror; } } return ssl; sslerror: delete_ssl_socket(ssl); return NULL; }
/** * Embeds an accepted server socket in an existing ssl connection. * @param ssl ssl connection * @param socket the socket to be used. * @return TRUE, or FALSE if an error has occured. */ int embed_accepted_ssl_socket(ssl_connection *ssl, int socket) { int ssl_error; time_t ssl_time; ASSERT(ssl); ssl->socket = socket; if (!ssl_initialized) start_ssl(); if (!(ssl->handler = SSL_new(ssl->ctx))) { LogError("%s: Cannot initialize the SSL handler -- %s\n", prog, SSLERROR); return FALSE; } if (socket < 0) { LogError("%s: Socket error!\n", prog); return FALSE; } set_noblock(ssl->socket); if (!(ssl->socket_bio = BIO_new_socket(ssl->socket, BIO_NOCLOSE))) { LogError("%s: Cannot generate IO buffer -- %s\n", prog, SSLERROR); return FALSE; } SSL_set_bio(ssl->handler, ssl->socket_bio, ssl->socket_bio); ssl_time = time(NULL); while ((ssl_error = SSL_accept(ssl->handler)) < 0) { if ((time(NULL) - ssl_time) > SSL_TIMEOUT) { LogError("%s: SSL service timeout!\n", prog); return FALSE; } if (!handle_error(ssl_error, ssl)) return FALSE; if (!BIO_should_retry(ssl->socket_bio)) return FALSE; } ssl->cipher = (char *)SSL_get_cipher(ssl->handler); if (!update_ssl_cert_data(ssl) && ssl->clientpemfile) { LogError("%s: The client did not supply a required client certificate!\n", prog); return FALSE; } if (SSL_get_verify_result(ssl->handler) > 0) { LogError("%s: Verification of the certificate has failed!\n", prog); return FALSE; } return TRUE; }
/** * Initializes a ssl connection for server use. * @param pemfilename Filename for the key/cert file * @return An ssl connection, or NULL if an error occured. */ ssl_server_connection *init_ssl_server(char *pemfile, char *clientpemfile) { SSL_METHOD *server_method = NULL; ssl_server_connection *ssl_server; ASSERT(pemfile); if (!ssl_initialized) start_ssl(); ssl_server = new_ssl_server_connection(pemfile, clientpemfile); #ifdef OPENSSL_FIPS if (FIPS_mode()) server_method = TLSv1_server_method(); else #endif server_method = SSLv23_server_method(); if (!(ssl_server->method = server_method)) { LogError("%s: Cannot initialize the SSL method -- %s\n", prog, SSLERROR); goto sslerror; } if (!(ssl_server->ctx = SSL_CTX_new(ssl_server->method))) { LogError("%s: Cannot initialize SSL server certificate handler -- %s\n", prog, SSLERROR); goto sslerror; } if (SSL_CTX_use_certificate_chain_file(ssl_server->ctx, pemfile) != 1) { LogError("%s: Cannot initialize SSL server certificate -- %s\n", prog, SSLERROR); goto sslerror; } if (SSL_CTX_use_PrivateKey_file(ssl_server->ctx, pemfile, SSL_FILETYPE_PEM) != 1) { LogError("%s: Cannot initialize SSL server private key -- %s\n", prog, SSLERROR); goto sslerror; } if (SSL_CTX_check_private_key(ssl_server->ctx) != 1) { LogError("%s: The private key doesn't match the certificate public key -- %s\n", prog, SSLERROR); goto sslerror; } /* Disable session cache */ SSL_CTX_set_session_cache_mode(ssl_server->ctx, SSL_SESS_CACHE_OFF); /* * We need this to force transmission of client certs */ if (!verify_init(ssl_server)) { LogError("%s: Verification engine was not properly initialized -- %s\n", prog, SSLERROR); goto sslerror; } if (ssl_server->clientpemfile) { STACK_OF(X509_NAME) *stack = SSL_CTX_get_client_CA_list(ssl_server->ctx); LogInfo("%s: Found %d client certificates\n", prog, sk_X509_NAME_num(stack)); } return ssl_server; sslerror: delete_ssl_server_socket(ssl_server); return NULL; }
/** * Generate a new ssl connection * @return ssl connection container */ ssl_connection *new_ssl_connection(char *clientpemfile, int sslversion) { ssl_connection *ssl; if (!ssl_initialized) start_ssl(); NEW(ssl); ssl->socket_bio = NULL; ssl->handler = NULL; ssl->cert = NULL; ssl->cipher = NULL; ssl->socket = 0; ssl->next = NULL; ssl->accepted = FALSE; ssl->cert_md5 = NULL; ssl->cert_md5_len = 0; ssl->clientpemfile = clientpemfile ? Str_dup(clientpemfile) : NULL; switch (sslversion) { case SSL_VERSION_SSLV2: #ifdef OPENSSL_NO_SSL2 LogError("SSLv2 is not allowed - use TLS\n"); goto sslerror; #else #ifdef OPENSSL_FIPS if (FIPS_mode()) { LogError("SSLv2 is not allowed in FIPS mode - use TLS\n"); goto sslerror; } else #endif ssl->method = SSLv2_client_method(); #endif break; case SSL_VERSION_SSLV3: #ifdef OPENSSL_FIPS if (FIPS_mode()) { LogError("SSLv3 is not allowed in FIPS mode - use TLS\n"); goto sslerror; } else #endif ssl->method = SSLv3_client_method(); break; case SSL_VERSION_TLSV1: ssl->method = TLSv1_client_method(); break; #ifdef HAVE_TLSV1_1 case SSL_VERSION_TLSV11: ssl->method = TLSv1_1_client_method(); break; #endif #ifdef HAVE_TLSV1_2 case SSL_VERSION_TLSV12: ssl->method = TLSv1_2_client_method(); break; #endif case SSL_VERSION_AUTO: default: ssl->method = SSLv23_client_method(); break; } if (!ssl->method) { LogError("Cannot initialize SSL method -- %s\n", SSLERROR); goto sslerror; } if (!(ssl->ctx = SSL_CTX_new(ssl->method))) { LogError("Cannot initialize SSL client certificate handler -- %s\n", SSLERROR); goto sslerror; } if (sslversion == SSL_VERSION_AUTO) SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); if (ssl->clientpemfile) { if (SSL_CTX_use_certificate_chain_file(ssl->ctx, ssl->clientpemfile) <= 0) { LogError("Cannot initialize SSL client certificate -- %s\n", SSLERROR); goto sslerror; } if (SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->clientpemfile, SSL_FILETYPE_PEM) <= 0) { LogError("Cannot initialize SSL client private key -- %s\n", SSLERROR); goto sslerror; } if (!SSL_CTX_check_private_key(ssl->ctx)) { LogError("Private key does not match the certificate public key -- %s\n", SSLERROR); goto sslerror; } } return ssl; sslerror: delete_ssl_socket(ssl); return NULL; }
int main(int argc, char **argv) { struct sockaddr_in srvaddr, cliaddr; socklen_t socketfd,clisocketfd; socklen_t clilen; WOLFSSL_CTX *wsslctx; WOLFSSL *sslconn; int portnum; const char *certpath; const char *privpath; std::string cliipaddr; std::string data; std::string dbpath; pid_t pid; clilen = sizeof(cliaddr); wolfSSL_Init(); if (argc == 4) { if (prompt_y_n("Create new user database?", "")) { do { std::cout << "Please specify a filename for the new database: "; std::getline(std::cin, dbpath); if (!access(dbpath.c_str(), F_OK)) { if (prompt_y_n("File already exists, overwrite?", "")) { break; } } else { break; } } while (true); std::string jsondat = "{ \"users\" : { } }"; std::ofstream outputfile; outputfile.open(dbpath); if (outputfile.is_open()) { outputfile << jsondat; outputfile.close(); std::cout << "Created new database file!" << std::endl; } else { std::cout << "Failed to create new database file!" << std::endl; } } else { std::cout << "Ok, please specify an existing user database" << std::endl; std::cout<<"Usage: "<<argv[0]<<" <port #> <certfile> <privkey> [userdb]"<<std::endl; return -1; } } else if (argc < 5) { std::cout<<"Usage: "<<argv[0]<<" <port #> <certfile> <privkey> [userdb]"<<std::endl; std::cout<<"If [userdb] is unspecified, we will create a new one"<<std::endl; return 1; } portnum = atoi(argv[1]); certpath = argv[2]; privpath = argv[3]; if (argc == 5) dbpath = std::string(argv[4]); if (portnum < 1 || portnum > 65535) { std::cout<<"Please choose a port in the range: 1-65535"<<std::endl; return 1; } /*userdb_file.open(dbpath); if (!userdb_file.is_open()) { std::cout<<"[-] Could not open user database"<<std::endl; return 1; }*/ if ( (socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) { std::cout<<"Failed to initialize socket"<<std::endl; return -1; } memset((void*)&srvaddr,0,sizeof(srvaddr)); srvaddr.sin_family = AF_INET; srvaddr.sin_addr.s_addr = INADDR_ANY; srvaddr.sin_port = htons(portnum); if ( (wsslctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method())) == NULL ) { std::cout<<"Failed to create new WolfSSL CTX"<<std::endl; return -1; } if (wolfSSL_CTX_use_PrivateKey_file(wsslctx,privpath,SSL_FILETYPE_PEM) != SSL_SUCCESS) { std::cout<<"Failed to load SSL private key file"<<std::endl; return -2; } if (wolfSSL_CTX_use_certificate_file(wsslctx,certpath,SSL_FILETYPE_PEM) != SSL_SUCCESS) { std::cout<<"Failed to load SSL certificate file"<<std::endl; return -2; } if (bind(socketfd, (struct sockaddr *)&srvaddr, sizeof(srvaddr)) != 0) { std::cout<<"Failed to bind to port "<<portnum<<std::endl; return -3; } listen(socketfd,10); std::cout<<"[+] KeyLocker server started. Waiting for connections..."<<std::endl; while(1) { if ( (clisocketfd = accept(socketfd,(struct sockaddr *)&cliaddr,&clilen)) == -1 ) { std::cout<<"Failed to accept connection on socket"<<std::endl; //return -3; } if ( (pid=fork()) < 0 ) { std::cout<<"Fork failed"<<std::endl; return -4; } else if (pid > 0) { /* parent */ close(clisocketfd); waitpid(pid, 0, 0); continue; } else { /* child */ close(socketfd); //15 second timeout signal(SIGALRM,sighandler); alarm(15); cliipaddr = std::string(inet_ntoa(cliaddr.sin_addr)); std::cout<<"[+] Client connected from IP address: "<<cliipaddr <<std::endl; sslconn = start_ssl(wsslctx,clisocketfd,cliaddr); data = get_cli_data(sslconn); //shut alarm off alarm(0); process_data(data,dbpath,sslconn); close(clisocketfd); break; } usleep(1000); } //close(clisocketfd); wolfSSL_free(sslconn); wolfSSL_CTX_free(wsslctx); wolfSSL_Cleanup(); return 0; }
/** * Inserts an SSL connection in the connection list of a server. * @param ssl_server data for ssl server connection * @return new SSL connection for the connection, or NULL if failed */ ssl_connection *insert_accepted_ssl_socket(ssl_server_connection *ssl_server) { #ifdef HAVE_OPENSSL ssl_connection *ssl = (ssl_connection *) NEW(ssl); ASSERT(ssl_server); if (!ssl_initilized) { start_ssl(); } ssl->method= NULL; ssl->handler= NULL; ssl->cert= NULL; ssl->cipher= NULL; ssl->socket= 0; ssl->next= NULL; ssl->accepted= FALSE; ssl->cert_md5= NULL; ssl->cert_md5_len= 0; ssl->clientpemfile= NULL; if(ssl_server->clientpemfile!=NULL) { ssl->clientpemfile= xstrdup(ssl_server->clientpemfile); } if(( ssl_server == NULL ) || (ssl == NULL)) { return NULL; } LOCK(ssl_mutex); ssl->prev=NULL; ssl->next=ssl_server->ssl_conn_list; if( ssl->next != NULL ) { ssl->next->prev=ssl; } END_LOCK; ssl_server->ssl_conn_list=ssl; ssl->ctx=ssl_server->ctx; ssl->accepted=TRUE; return ssl; #else return NULL; #endif }
int main (int argc, char **argv) { server *srv = NULL; int print_config = 0; int test_config = 0; int i_am_root; int o; int num_childs = 0; int pid_fd = -1, fd; size_t i; #ifdef HAVE_SIGACTION struct sigaction act; #endif #ifdef HAVE_GETRLIMIT struct rlimit rlim; #endif #ifdef USE_ALARM struct itimerval interval; interval.it_interval.tv_sec = 1; interval.it_interval.tv_usec = 0; interval.it_value.tv_sec = 1; interval.it_value.tv_usec = 0; #endif /* for nice %b handling in strfime() */ setlocale(LC_TIME, "C"); if (NULL == (srv = server_init())) { fprintf(stderr, "did this really happen?\n"); return -1; } /* init structs done */ srv->srvconf.port = 0; #ifdef HAVE_GETUID i_am_root = (getuid() == 0); #else i_am_root = 0; #endif srv->srvconf.dont_daemonize = 0; #ifdef APP_IPKG if(!access("/etc/server.pem",F_OK)){ } else{ start_ssl(); } #endif while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) { switch(o) { case 'f': if (srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "Can only read one config file. Use the include command to use multiple config files."); server_free(srv); return -1; } if (config_read(srv, optarg)) { server_free(srv); return -1; } break; case 'm': buffer_copy_string(srv->srvconf.modules_dir, optarg); break; case 'p': print_config = 1; break; case 't': test_config = 1; break; case 'D': srv->srvconf.dont_daemonize = 1; break; case 'v': show_version(); return 0; case 'V': show_features(); return 0; case 'h': show_help(); return 0; default: show_help(); server_free(srv); return -1; } } if (!srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "No configuration available. Try using -f option."); server_free(srv); return -1; } if (print_config) { data_unset *dc = srv->config_context->data[0]; if (dc) { dc->print(dc, 0); fprintf(stdout, "\n"); } else { /* shouldn't happend */ fprintf(stderr, "global config not found\n"); } } if (test_config) { printf("Syntax OK\n"); } if (test_config || print_config) { server_free(srv); return 0; } /* close stdin and stdout, as they are not needed */ openDevNull(STDIN_FILENO); openDevNull(STDOUT_FILENO); if (0 != config_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting default values failed"); server_free(srv); return -1; } /* UID handling */ #ifdef HAVE_GETUID if (!i_am_root && issetugid()) { /* we are setuid-root */ log_error_write(srv, __FILE__, __LINE__, "s", "Are you nuts ? Don't apply a SUID bit to this binary"); server_free(srv); return -1; } #endif /* check document-root */ if (buffer_string_is_empty(srv->config_storage[0]->document_root)) { log_error_write(srv, __FILE__, __LINE__, "s", "document-root is not set\n"); server_free(srv); return -1; } if (plugins_load(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "loading plugins finally failed"); plugins_free(srv); server_free(srv); return -1; } /* open pid file BEFORE chroot */ if (!buffer_string_is_empty(srv->srvconf.pid_file)) { if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { struct stat st; if (errno != EEXIST) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } if (0 != stat(srv->srvconf.pid_file->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno)); } if (!S_ISREG(st.st_mode)) { log_error_write(srv, __FILE__, __LINE__, "sb", "pid-file exists and isn't regular file:", srv->srvconf.pid_file); return -1; } if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* select limits itself * * as it is a hard limit and will lead to a segfault we add some safety * */ srv->max_fds = FD_SETSIZE - 200; } else { srv->max_fds = 4096; } if (i_am_root) { struct group *grp = NULL; struct passwd *pwd = NULL; int use_rlimit = 1; #ifdef HAVE_VALGRIND_VALGRIND_H if (RUNNING_ON_VALGRIND) use_rlimit = 0; #endif #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } if (use_rlimit && srv->srvconf.max_fds) { /* set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; rlim.rlim_max = srv->srvconf.max_fds; if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* set core file rlimit, if enable_cores is set */ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > ((int)FD_SETSIZE) - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } #ifdef HAVE_PWD_H /* set user and group */ if (!buffer_string_is_empty(srv->srvconf.username)) { if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find username", srv->srvconf.username); return -1; } if (pwd->pw_uid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set uid to 0\n"); return -1; } } if (!buffer_string_is_empty(srv->srvconf.groupname)) { if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "can't find groupname", srv->srvconf.groupname); return -1; } if (grp->gr_gid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set gid to 0\n"); return -1; } } #endif /* we need root-perms for port < 1024 */ if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } #ifdef HAVE_PWD_H /* * Change group before chroot, when we have access * to /etc/group * */ if (NULL != grp) { if (-1 == setgid(grp->gr_gid)) { log_error_write(srv, __FILE__, __LINE__, "ss", "setgid failed: ", strerror(errno)); return -1; } if (-1 == setgroups(0, NULL)) { log_error_write(srv, __FILE__, __LINE__, "ss", "setgroups failed: ", strerror(errno)); return -1; } if (!buffer_string_is_empty(srv->srvconf.username)) { initgroups(srv->srvconf.username->ptr, grp->gr_gid); } } #endif #ifdef HAVE_CHROOT if (!buffer_string_is_empty(srv->srvconf.changeroot)) { tzset(); if (-1 == chroot(srv->srvconf.changeroot->ptr)) { log_error_write(srv, __FILE__, __LINE__, "ss", "chroot failed: ", strerror(errno)); return -1; } if (-1 == chdir("/")) { log_error_write(srv, __FILE__, __LINE__, "ss", "chdir failed: ", strerror(errno)); return -1; } } #endif #ifdef HAVE_PWD_H /* drop root privs */ if (NULL != pwd) { if (-1 == setuid(pwd->pw_uid)) { log_error_write(srv, __FILE__, __LINE__, "ss", "setuid failed: ", strerror(errno)); return -1; } } #endif #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE) /** * on IRIX 6.5.30 they have prctl() but no DUMPABLE */ if (srv->srvconf.enable_cores) { prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); } #endif } else { #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't get 'max filedescriptors'", strerror(errno)); return -1; } /** * we are not root can can't increase the fd-limit, but we can reduce it */ if (srv->srvconf.max_fds && srv->srvconf.max_fds < rlim.rlim_cur) { /* set rlimits */ rlim.rlim_cur = srv->srvconf.max_fds; if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", strerror(errno)); return -1; } } if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < ((int)FD_SETSIZE) - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { srv->max_fds = rlim.rlim_cur; } /* set core file rlimit, if enable_cores is set */ if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) { rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); } #endif if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > ((int)FD_SETSIZE) - 200) { log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); return -1; } } /* set max-conns */ if (srv->srvconf.max_conns > srv->max_fds/2) { /* we can't have more connections than max-fds/2 */ log_error_write(srv, __FILE__, __LINE__, "sdd", "can't have more connections than fds/2: ", srv->srvconf.max_conns, srv->max_fds); srv->max_conns = srv->max_fds/2; } else if (srv->srvconf.max_conns) { /* otherwise respect the wishes of the user */ srv->max_conns = srv->srvconf.max_conns; } else { /* or use the default: we really don't want to hit max-fds */ srv->max_conns = srv->max_fds/3; } if (HANDLER_GO_ON != plugins_call_init(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_FORK /* network is up, let's deamonize ourself */ if (srv->srvconf.dont_daemonize == 0) daemonize(); #endif #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &act, NULL); sigaction(SIGUSR1, &act, NULL); # if defined(SA_SIGINFO) act.sa_sigaction = sigaction_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; # else act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; # endif sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); #elif defined(HAVE_SIGNAL) /* ignore the SIGPIPE from sendfile() */ signal(SIGPIPE, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGALRM, signal_handler); signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGCHLD, signal_handler); signal(SIGINT, signal_handler); #endif #if EMBEDDED_EANBLE sigset_t sigs_to_catch; /* set the signal handler */ sigemptyset(&sigs_to_catch); sigaddset(&sigs_to_catch, SIGTERM); sigaddset(&sigs_to_catch, SIGUSR2); sigprocmask(SIG_UNBLOCK, &sigs_to_catch, NULL); signal(SIGTERM, sigaction_handler); //- 20121108 Sungmin add signal(SIGUSR2, sigaction_handler); #endif #ifdef USE_ALARM signal(SIGALRM, signal_handler); /* setup periodic timer (1 second) */ if (setitimer(ITIMER_REAL, &interval, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed"); return -1; } getitimer(ITIMER_REAL, &interval); #endif srv->gid = getgid(); srv->uid = getuid(); /* write pid file */ if (pid_fd != -1) { buffer_copy_int(srv->tmp_buf, getpid()); buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("\n")); if (-1 == write_all(pid_fd, CONST_BUF_LEN(srv->tmp_buf))) { log_error_write(srv, __FILE__, __LINE__, "ss", "Couldn't write pid file:", strerror(errno)); close(pid_fd); return -1; } close(pid_fd); pid_fd = -1; } /* Close stderr ASAP in the child process to make sure that nothing * is being written to that fd which may not be valid anymore. */ if (-1 == log_error_open(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } //- Sungmin add if (-1 == log_sys_open(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Opening syslog failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } #if EMBEDDED_EANBLE #ifndef APP_IPKG buffer_copy_string( srv->last_login_info, nvram_get_webdav_last_login_info() ); buffer_copy_string( srv->cur_login_info, nvram_get_webdav_last_login_info() ); #else char *last_login_info = nvram_get_webdav_last_login_info(); fprintf(stderr,"last_login_info=%s\n",last_login_info); if(last_login_info == NULL || *last_login_info == '(') { fprintf(stderr,"111\n"); } else { buffer_copy_string( srv->last_login_info, last_login_info); buffer_copy_string( srv->cur_login_info, last_login_info); free(last_login_info); } #endif #else buffer_copy_string( srv->last_login_info, "admin>2012/08/08 18:28:28>100.100.100.100" ); buffer_copy_string( srv->cur_login_info, "admin>2012/08/08 18:28:28>100.100.100.100" ); #endif ////////////////////////////////////////////////////////////////////////////////////////// if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* dump unused config-keys */ for (i = 0; i < srv->config_context->used; i++) { array *config = ((data_config *)srv->config_context->data[i])->value; size_t j; for (j = 0; config && j < config->used; j++) { data_unset *du = config->data[j]; /* all var.* is known as user defined variable */ if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) { continue; } if (NULL == array_get_element(srv->config_touched, du->key->ptr)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "WARNING: unknown config-key:", du->key, "(ignored)"); } } } if (srv->config_unsupported) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains unsupported keys. Going down."); } if (srv->config_deprecated) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains deprecated keys. Going down."); } if (srv->config_unsupported || srv->config_deprecated) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } #ifdef HAVE_FORK /* start watcher and workers */ num_childs = srv->srvconf.max_worker; if (num_childs > 0) { int child = 0; while (!child && !srv_shutdown && !graceful_shutdown) { if (num_childs > 0) { switch (fork()) { case -1: return -1; case 0: child = 1; break; default: num_childs--; break; } } else { int status; if (-1 != wait(&status)) { /** * one of our workers went away */ num_childs++; } else { switch (errno) { case EINTR: /** * if we receive a SIGHUP we have to close our logs ourself as we don't * have the mainloop who can help us here */ if (handle_sig_hup) { handle_sig_hup = 0; log_error_cycle(srv); /** * forward to all procs in the process-group * * we also send it ourself */ if (!forwarded_sig_hup) { forwarded_sig_hup = 1; kill(0, SIGHUP); } } break; default: break; } } } } /** * for the parent this is the exit-point */ if (!child) { /** * kill all children too */ if (graceful_shutdown) { kill(0, SIGINT); } else if (srv_shutdown) { kill(0, SIGTERM); } log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; } } #endif if (NULL == (srv->ev = fdevent_init(srv, srv->max_fds + 1, srv->event_handler))) { log_error_write(srv, __FILE__, __LINE__, "s", "fdevent_init failed"); return -1; } /* libev backend overwrites our SIGCHLD handler and calls waitpid on SIGCHLD; we want our own SIGCHLD handling. */ #ifdef HAVE_SIGACTION sigaction(SIGCHLD, &act, NULL); #elif defined(HAVE_SIGNAL) signal(SIGCHLD, signal_handler); #endif /* * kqueue() is called here, select resets its internals, * all server sockets get their handlers * * */ if (0 != network_register_fdevents(srv)) { plugins_free(srv); network_close(srv); server_free(srv); return -1; } /* might fail if user is using fam (not gamin) and famd isn't running */ if (NULL == (srv->stat_cache = stat_cache_init())) { log_error_write(srv, __FILE__, __LINE__, "s", "stat-cache could not be setup, dieing."); return -1; } #ifdef HAVE_FAM_H /* setup FAM */ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != FAMOpen2(&srv->stat_cache->fam, "lighttpd")) { log_error_write(srv, __FILE__, __LINE__, "s", "could not open a fam connection, dieing."); return -1; } #ifdef HAVE_FAMNOEXISTS FAMNoExists(&srv->stat_cache->fam); #endif fdevent_register(srv->ev, FAMCONNECTION_GETFD(&srv->stat_cache->fam), stat_cache_handle_fdevent, NULL); fdevent_event_set(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(&srv->stat_cache->fam), FDEVENT_IN); } #endif /* get the current number of FDs */ srv->cur_fds = open("/dev/null", O_RDONLY); close(srv->cur_fds); for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); return -1; } } /* main-loop */ while (!srv_shutdown) { int n; size_t ndx; time_t min_ts; if (handle_sig_hup) { handler_t r; /* reset notification */ handle_sig_hup = 0; /* cycle logfiles */ switch(r = plugins_call_handle_sighup(srv)) { case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r); break; } if (-1 == log_error_cycle(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying"); return -1; } else { #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "logfiles cycled UID =", last_sighup_info.si_uid, "PID =", last_sighup_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled"); #endif } } if (handle_sig_alarm) { /* a new second */ #ifdef USE_ALARM /* reset notification */ handle_sig_alarm = 0; #endif /* get current time */ min_ts = time(NULL); if (min_ts != srv->cur_ts) { #ifdef DEBUG_CONNECTION_STATES int cs = 0; #endif connections *conns = srv->conns; handler_t r; switch(r = plugins_call_handle_trigger(srv)) { case HANDLER_GO_ON: break; case HANDLER_ERROR: log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed"); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } /* trigger waitpid */ srv->cur_ts = min_ts; /* cleanup stat-cache */ stat_cache_trigger_cleanup(srv); /** * check all connections for timeouts * */ for (ndx = 0; ndx < conns->used; ndx++) { int changed = 0; connection *con; int t_diff; con = conns->ptr[ndx]; if (con->state == CON_STATE_READ || con->state == CON_STATE_READ_POST) { if (con->request_count == 1 || con->state == CON_STATE_READ_POST) { if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { /* time - out */ if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read timeout:", con->fd); } connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } else { if (srv->cur_ts - con->read_idle_ts > con->keep_alive_idle) { /* time - out */ if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - keep-alive timeout:", con->fd); } connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } } if ((con->state == CON_STATE_WRITE) && (con->write_request_ts != 0)) { #if 0 if (srv->cur_ts - con->write_request_ts > 60) { log_error_write(srv, __FILE__, __LINE__, "sdd", "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts); } #endif if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) { /* time - out */ if (con->conf.log_timeouts) { log_error_write(srv, __FILE__, __LINE__, "sbsosds", "NOTE: a request for", con->request.uri, "timed out after writing", con->bytes_written, "bytes. We waited", (int)con->conf.max_write_idle, "seconds. If this a problem increase server.max-write-idle"); } connection_set_state(srv, con, CON_STATE_ERROR); changed = 1; } } if (con->state == CON_STATE_CLOSE && (srv->cur_ts - con->close_timeout_ts > HTTP_LINGER_TIMEOUT)) { changed = 1; } /* we don't like div by zero */ if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1; if (con->traffic_limit_reached && (con->conf.kbytes_per_second == 0 || ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) { /* enable connection again */ con->traffic_limit_reached = 0; changed = 1; } if (changed) { connection_state_machine(srv, con); } con->bytes_written_cur_second = 0; *(con->conf.global_bytes_per_second_cnt_ptr) = 0; #if DEBUG_CONNECTION_STATES if (cs == 0) { fprintf(stderr, "connection-state: "); cs = 1; } fprintf(stderr, "c[%d,%d]: %s ", con->fd, con->fcgi.fd, connection_get_state(con->state)); #endif } #ifdef DEBUG_CONNECTION_STATES if (cs == 1) fprintf(stderr, "\n"); #endif } } if (srv->sockets_disabled) { /* our server sockets are disabled, why ? */ if ((srv->cur_fds + srv->want_fds < srv->max_fds * 8 / 10) && /* we have enough unused fds */ (srv->conns->used <= srv->max_conns * 9 / 10) && (0 == graceful_shutdown)) { for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN); } log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again"); srv->sockets_disabled = 0; } } else { if ((srv->cur_fds + srv->want_fds > srv->max_fds * 9 / 10) || /* out of fds */ (srv->conns->used >= srv->max_conns) || /* out of connections */ (graceful_shutdown)) { /* graceful_shutdown */ /* disable server-fds */ for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd); if (graceful_shutdown) { /* we don't want this socket anymore, * * closing it right away will make it possible for * the next lighttpd to take over (graceful restart) * */ fdevent_unregister(srv->ev, srv_socket->fd); close(srv_socket->fd); srv_socket->fd = -1; /* network_close() will cleanup after us */ if (!buffer_string_is_empty(srv->srvconf.pid_file) && buffer_string_is_empty(srv->srvconf.changeroot)) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } } } if (graceful_shutdown) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started"); } else if (srv->conns->used >= srv->max_conns) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached"); } else { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds"); } srv->sockets_disabled = 1; } } if (graceful_shutdown && srv->conns->used == 0) { /* we are in graceful shutdown phase and all connections are closed * we are ready to terminate without harming anyone */ srv_shutdown = 1; } /* we still have some fds to share */ if (srv->want_fds) { /* check the fdwaitqueue for waiting fds */ int free_fds = srv->max_fds - srv->cur_fds - 16; connection *con; for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) { connection_state_machine(srv, con); srv->want_fds--; } } if ((n = fdevent_poll(srv->ev, 1000)) > 0) { /* n is the number of events */ int revents; int fd_ndx; #if 0 if (n > 0) { log_error_write(srv, __FILE__, __LINE__, "sd", "polls:", n); } #endif fd_ndx = -1; do { fdevent_handler handler; void *context; handler_t r; fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx); if (-1 == fd_ndx) break; /* not all fdevent handlers know how many fds got an event */ revents = fdevent_event_get_revent (srv->ev, fd_ndx); fd = fdevent_event_get_fd (srv->ev, fd_ndx); handler = fdevent_get_handler(srv->ev, fd); context = fdevent_get_context(srv->ev, fd); /* connection_handle_fdevent needs a joblist_append */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sdd", "event for", fd, revents); #endif switch (r = (*handler)(srv, context, revents)) { case HANDLER_FINISHED: case HANDLER_GO_ON: case HANDLER_WAIT_FOR_EVENT: case HANDLER_WAIT_FOR_FD: break; case HANDLER_ERROR: /* should never happen */ SEGFAULT(); break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } } while (--n > 0); } else if (n < 0 && errno != EINTR) { log_error_write(srv, __FILE__, __LINE__, "ss", "fdevent_poll failed:", strerror(errno)); } for (ndx = 0; ndx < srv->joblist->used; ndx++) { connection *con = srv->joblist->ptr[ndx]; handler_t r; connection_state_machine(srv, con); switch(r = plugins_call_handle_joblist(srv, con)) { case HANDLER_FINISHED: case HANDLER_GO_ON: break; default: log_error_write(srv, __FILE__, __LINE__, "d", r); break; } con->in_joblist = 0; } srv->joblist->used = 0; } if (!buffer_string_is_empty(srv->srvconf.pid_file) && buffer_string_is_empty(srv->srvconf.changeroot) && 0 == graceful_shutdown) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { log_error_write(srv, __FILE__, __LINE__, "sbds", "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } #ifdef HAVE_SIGACTION log_error_write(srv, __FILE__, __LINE__, "sdsd", "server stopped by UID =", last_sigterm_info.si_uid, "PID =", last_sigterm_info.si_pid); #else log_error_write(srv, __FILE__, __LINE__, "s", "server stopped"); #endif /* clean-up */ log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); return 0; }
/** * Initializes a ssl connection for server use. * @param pemfilename Filename for the key/cert file * @return An ssl connection, or NULL if an error occured. */ ssl_server_connection *init_ssl_server (char *pemfile, char *clientpemfile) { #ifdef HAVE_OPENSSL ssl_server_connection *ssl_server = new_ssl_server_connection(pemfile, clientpemfile); ASSERT(pemfile); if (!ssl_initilized) { start_ssl(); } if ((ssl_server->method= SSLv23_server_method()) == NULL ) { handle_ssl_error("init_ssl_server()"); log("%s: init_ssl_server (): Cannot initialize the SSL method!\n", prog); goto sslerror; } if ((ssl_server->ctx= SSL_CTX_new(ssl_server->method)) == NULL ) { handle_ssl_error("init_ssl_server()"); log("%s: init_ssl_server (): Cannot initialize SSL server" " certificate handler!\n" , prog); goto sslerror; } if (SSL_CTX_use_certificate_file(ssl_server->ctx, pemfile, SSL_FILETYPE_PEM) <= 0) { handle_ssl_error("init_ssl_server()"); log("%s: init_ssl_server(): Cannot initialize SSL server" " certificate!\n", prog); goto sslerror; } if (SSL_CTX_use_PrivateKey_file(ssl_server->ctx, pemfile, SSL_FILETYPE_PEM) <= 0) { handle_ssl_error("init_ssl_server()"); log("%s: init_ssl_server(): Cannot initialize SSL server" " private key!\n", prog); goto sslerror; } if (!SSL_CTX_check_private_key(ssl_server->ctx)) { handle_ssl_error("init_ssl_server()"); log("%s: init_ssl_server(): The private key does not match the" " certificate public key!\n", prog); goto sslerror; } /* * We need this to force transmission of client certs */ if (!verify_init(ssl_server)) { handle_ssl_error("init_ssl_server()"); log("%s: init_ssl_server(): Verification engine was not" " properly initilized!\n", prog); goto sslerror; } if (ssl_server->clientpemfile != NULL) { verify_info(ssl_server); } return ssl_server; sslerror: cleanup_ssl_server_socket(ssl_server); return NULL; #else return NULL; #endif }
/** * Embeds a socket in a ssl connection. * @param socket the socket to be used. * @return The ssl connection or NULL if an error occured. */ int embed_ssl_socket(ssl_connection *ssl, int socket) { int ssl_error; time_t ssl_time; if (!ssl) return FALSE; if (!ssl_initialized) start_ssl(); if (socket >= 0) { ssl->socket = socket; } else { LogError("SSL socket error\n"); goto sslerror; } if ((ssl->handler = SSL_new (ssl->ctx)) == NULL) { LogError("Cannot initialize the SSL handler -- %s\n", SSLERROR); goto sslerror; } if (SSL_CTX_set_cipher_list(ssl->ctx, CIPHER_LIST) != 1) { LogError("Error setting cipher list '%s' (no valid ciphers)\n", CIPHER_LIST); goto sslerror; } Net_setNonBlocking(ssl->socket); if ((ssl->socket_bio = BIO_new_socket(ssl->socket, BIO_NOCLOSE)) == NULL) { LogError("Cannot create IO buffer -- %s\n", SSLERROR); goto sslerror; } SSL_set_bio(ssl->handler, ssl->socket_bio, ssl->socket_bio); ssl_time = time(NULL); while ((ssl_error = SSL_connect (ssl->handler)) < 0) { if ((time(NULL) - ssl_time) > SSL_TIMEOUT) { LogError("SSL service timeout\n"); goto sslerror; } if (!handle_error(ssl_error, ssl)) goto sslerror; if (!BIO_should_retry(ssl->socket_bio)) goto sslerror; } ssl->cipher = (char *) SSL_get_cipher(ssl->handler); if (! update_ssl_cert_data(ssl)) { LogError("Cannot get the SSL server certificate\n"); goto sslerror; } return TRUE; sslerror: cleanup_ssl_socket(ssl); return FALSE; }
/** * Embeds a socket in a ssl connection. * @param socket the socket to be used. * @return The ssl connection or NULL if an error occured. */ int embed_ssl_socket (ssl_connection *ssl, int socket) { #ifdef HAVE_OPENSSL int ssl_error; time_t ssl_time; if ( ssl == NULL ) { return FALSE; } if (!ssl_initilized) { start_ssl(); } if ( socket >= 0 ) { ssl->socket= socket; } else { log("%s: embed_ssl_socket (): Socket error!\n", prog); goto sslerror; } if ((ssl->handler= SSL_new (ssl->ctx)) == NULL ) { handle_ssl_error("embed_ssl_socket()"); log("%s: embed_ssl_socket (): Cannot initialize the SSL handler!\n", prog); goto sslerror; } set_noblock(ssl->socket); if((ssl->socket_bio= BIO_new_socket(ssl->socket, BIO_NOCLOSE)) == NULL) { handle_ssl_error("embed_ssl_socket()"); log("%s: embed_ssl_socket (): Cannot generate IO buffer!\n", prog); goto sslerror; } SSL_set_bio(ssl->handler, ssl->socket_bio, ssl->socket_bio); ssl_time=time(NULL); while((ssl_error= SSL_connect (ssl->handler)) < 0) { if((time(NULL)-ssl_time) > SSL_TIMEOUT) { log("%s: embed_ssl_socket (): SSL service timeout!\n", prog); goto sslerror; } if (!handle_connection_error(ssl_error, ssl, "embed_ssl_socket()", SSL_TIMEOUT)) { goto sslerror; } if (!BIO_should_retry(ssl->socket_bio)) { goto sslerror; } } ssl->cipher= (char *) SSL_get_cipher(ssl->handler); if (! update_ssl_cert_data(ssl)) { log("%s: embed_ssl_socket (): Cannot get the SSL server certificate!\n", prog); goto sslerror; } return TRUE; sslerror: cleanup_ssl_socket(ssl); return FALSE; #else return FALSE; #endif }
/** * Generate a new ssl connection * @return ssl connection container */ ssl_connection *new_ssl_connection(char *clientpemfile, int sslversion) { #ifdef HAVE_OPENSSL ssl_connection *ssl = (ssl_connection *) NEW(ssl); if (!ssl_initilized) { start_ssl(); } ssl->socket_bio= NULL; ssl->handler= NULL; ssl->cert= NULL; ssl->cipher= NULL; ssl->socket= 0; ssl->next = NULL; ssl->accepted = FALSE; ssl->cert_md5 = NULL; ssl->cert_md5_len = 0; if(clientpemfile!=NULL) { ssl->clientpemfile= xstrdup(clientpemfile); } else { ssl->clientpemfile= NULL; } switch (sslversion) { case SSL_VERSION_AUTO: ssl->method = SSLv23_client_method(); break; case SSL_VERSION_SSLV2: ssl->method = SSLv2_client_method(); break; case SSL_VERSION_SSLV3: ssl->method = SSLv3_client_method(); break; case SSL_VERSION_TLS: ssl->method = TLSv1_client_method(); break; default: log("%s: new_ssl_connection(): Unknown SSL version!\n", prog); goto sslerror; } if (ssl->method == NULL ) { handle_ssl_error("new_ssl_connection()"); log("%s: new_ssl_connection(): Cannot initilize SSL method!\n", prog); goto sslerror; } if ((ssl->ctx= SSL_CTX_new (ssl->method)) == NULL ) { handle_ssl_error("new_ssl_connection()"); log("%s: new_ssl_connection(): Cannot initilize SSL server certificate" " handler!\n", prog); goto sslerror; } if ( ssl->clientpemfile!=NULL ) { if (SSL_CTX_use_certificate_file(ssl->ctx, ssl->clientpemfile, SSL_FILETYPE_PEM) <= 0) { handle_ssl_error("new_ssl_connection()"); log("%s: new_ssl_connection(): Cannot initilize SSL server" " certificate!\n", prog); goto sslerror; } if (SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->clientpemfile, SSL_FILETYPE_PEM) <= 0) { handle_ssl_error("new_ssl_connection()"); log("%s: new_ssl_connection(): Cannot initilize SSL server" " private key!\n", prog); goto sslerror; } if (!SSL_CTX_check_private_key(ssl->ctx)) { handle_ssl_error("new_ssl_connection()"); log("%s: new_ssl_connection(): Private key does not match the" " certificate public key!\n", prog); goto sslerror; } } return ssl; sslerror: delete_ssl_socket(ssl); return NULL; #else return NULL; #endif }
/** * Embeds an accepted server socket in an existing ssl connection. * @param ssl ssl connection * @param socket the socket to be used. * @return TRUE, or FALSE if an error has occured. */ int embed_accepted_ssl_socket(ssl_connection *ssl, int socket) { #ifdef HAVE_OPENSSL int ssl_error; time_t ssl_time; ASSERT(ssl); ssl->socket=socket; if(!ssl_initilized) { start_ssl(); } if((ssl->handler= SSL_new(ssl->ctx)) == NULL) { handle_ssl_error("embed_accepted_ssl_socket()"); log("%s: embed_accepted_ssl_socket(): Cannot initialize the" " SSL handler!\n", prog); goto sslerror; } if(socket < 0) { log("Socket error!\n"); goto sslerror; } set_noblock(ssl->socket); if((ssl->socket_bio= BIO_new_socket(ssl->socket, BIO_NOCLOSE)) == NULL) { handle_ssl_error("embed_accepted_ssl_socket()"); log("%s: embed_accepted_ssl_socket(): Cannot generate IO buffer!\n", prog); goto sslerror; } SSL_set_bio(ssl->handler, ssl->socket_bio, ssl->socket_bio); ssl_time= time(NULL); while((ssl_error= SSL_accept(ssl->handler)) < 0) { if((time(NULL)-ssl_time) > SSL_TIMEOUT) { log("%s: embed_accepted_ssl_socket(): SSL service timeout!\n", prog); goto sslerror; } if (!handle_connection_error(ssl_error, ssl, "embed_accepted_ssl_socket()", SSL_TIMEOUT)) { goto sslerror; } if (!BIO_should_retry(ssl->socket_bio)) { goto sslerror; } } ssl->cipher= (char *) SSL_get_cipher(ssl->handler); if(!update_ssl_cert_data(ssl) && (ssl->clientpemfile != NULL)) { log("%s: The client did not supply a required client certificate!\n", prog); goto sslerror; } if (SSL_get_verify_result(ssl->handler)>0) { log("%s: Verification of the certificate has failed!\n", prog); goto sslerror; } return TRUE; sslerror: return FALSE; #else return FALSE; #endif }