1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * daemon/unbound.c - main program for unbound DNS resolver daemon. 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2417d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2517d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2617d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2717d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2817d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2917d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3017d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3117d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3217d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3317d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav * 35b7579f77SDag-Erling Smørgrav */ 36b7579f77SDag-Erling Smørgrav 37b7579f77SDag-Erling Smørgrav /** 38b7579f77SDag-Erling Smørgrav * \file 39b7579f77SDag-Erling Smørgrav * 40b7579f77SDag-Erling Smørgrav * Main program to start the DNS resolver daemon. 41b7579f77SDag-Erling Smørgrav */ 42b7579f77SDag-Erling Smørgrav 43b7579f77SDag-Erling Smørgrav #include "config.h" 44b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H 45b7579f77SDag-Erling Smørgrav #include <getopt.h> 46b7579f77SDag-Erling Smørgrav #endif 47b7579f77SDag-Erling Smørgrav #include <sys/time.h> 48b7579f77SDag-Erling Smørgrav #include "util/log.h" 49b7579f77SDag-Erling Smørgrav #include "daemon/daemon.h" 50b7579f77SDag-Erling Smørgrav #include "daemon/remote.h" 51b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 52b7579f77SDag-Erling Smørgrav #include "util/storage/slabhash.h" 53b7579f77SDag-Erling Smørgrav #include "services/listen_dnsport.h" 54b7579f77SDag-Erling Smørgrav #include "services/cache/rrset.h" 55b7579f77SDag-Erling Smørgrav #include "services/cache/infra.h" 5604b59eacSDag-Erling Smørgrav #include "util/fptr_wlist.h" 57b7579f77SDag-Erling Smørgrav #include "util/data/msgreply.h" 58b7579f77SDag-Erling Smørgrav #include "util/module.h" 59b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 60e2d15004SDag-Erling Smørgrav #include "util/ub_event.h" 61b7579f77SDag-Erling Smørgrav #include <signal.h> 62b7579f77SDag-Erling Smørgrav #include <fcntl.h> 63b7579f77SDag-Erling Smørgrav #include <openssl/crypto.h> 64b7579f77SDag-Erling Smørgrav #ifdef HAVE_PWD_H 65b7579f77SDag-Erling Smørgrav #include <pwd.h> 66b7579f77SDag-Erling Smørgrav #endif 67b7579f77SDag-Erling Smørgrav #ifdef HAVE_GRP_H 68b7579f77SDag-Erling Smørgrav #include <grp.h> 69b7579f77SDag-Erling Smørgrav #endif 70e86b9096SDag-Erling Smørgrav #include <openssl/ssl.h> 71b7579f77SDag-Erling Smørgrav 7217d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S 7317d15b25SDag-Erling Smørgrav /* splint chokes on this system header file */ 74b7579f77SDag-Erling Smørgrav #ifdef HAVE_SYS_RESOURCE_H 75b7579f77SDag-Erling Smørgrav #include <sys/resource.h> 76b7579f77SDag-Erling Smørgrav #endif 7717d15b25SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 78b7579f77SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP_H 79b7579f77SDag-Erling Smørgrav #include <login_cap.h> 80b7579f77SDag-Erling Smørgrav #endif 81b7579f77SDag-Erling Smørgrav 82b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 83b7579f77SDag-Erling Smørgrav # include "winrc/win_svc.h" 84b7579f77SDag-Erling Smørgrav #endif 85b7579f77SDag-Erling Smørgrav 868ed2b524SDag-Erling Smørgrav #ifdef HAVE_NSS 878ed2b524SDag-Erling Smørgrav /* nss3 */ 888ed2b524SDag-Erling Smørgrav # include "nss.h" 898ed2b524SDag-Erling Smørgrav #endif 908ed2b524SDag-Erling Smørgrav 9125039b37SCy Schubert #ifdef HAVE_TARGETCONDITIONALS_H 9225039b37SCy Schubert #include <TargetConditionals.h> 9325039b37SCy Schubert #endif 9425039b37SCy Schubert 95c0caa2e2SCy Schubert #if (defined(TARGET_OS_TV) && TARGET_OS_TV) || (defined(TARGET_OS_WATCH) && TARGET_OS_WATCH) 9625039b37SCy Schubert #undef HAVE_FORK 9725039b37SCy Schubert #endif 9825039b37SCy Schubert 990eefd307SCy Schubert /** print build options. */ 1000eefd307SCy Schubert static void 1010eefd307SCy Schubert print_build_options(void) 102b7579f77SDag-Erling Smørgrav { 103b7579f77SDag-Erling Smørgrav const char** m; 104b7579f77SDag-Erling Smørgrav const char *evnm="event", *evsys="", *evmethod=""; 105b5663de9SDag-Erling Smørgrav time_t t; 106b5663de9SDag-Erling Smørgrav struct timeval now; 107b5663de9SDag-Erling Smørgrav struct ub_event_base* base; 1080eefd307SCy Schubert printf("Version %s\n\n", PACKAGE_VERSION); 1090eefd307SCy Schubert printf("Configure line: %s\n", CONFCMDLINE); 110b5663de9SDag-Erling Smørgrav base = ub_default_event_base(0,&t,&now); 111b5663de9SDag-Erling Smørgrav ub_get_event_sys(base, &evnm, &evsys, &evmethod); 1120eefd307SCy Schubert printf("Linked libs: %s %s (it uses %s), %s\n", 11317d15b25SDag-Erling Smørgrav evnm, evsys, evmethod, 1148ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 115b5663de9SDag-Erling Smørgrav # ifdef SSLEAY_VERSION 1168ed2b524SDag-Erling Smørgrav SSLeay_version(SSLEAY_VERSION) 117b5663de9SDag-Erling Smørgrav # else 118b5663de9SDag-Erling Smørgrav OpenSSL_version(OPENSSL_VERSION) 119b5663de9SDag-Erling Smørgrav # endif 1208ed2b524SDag-Erling Smørgrav #elif defined(HAVE_NSS) 1218ed2b524SDag-Erling Smørgrav NSS_GetVersion() 12205ab2901SDag-Erling Smørgrav #elif defined(HAVE_NETTLE) 12305ab2901SDag-Erling Smørgrav "nettle" 1248ed2b524SDag-Erling Smørgrav #endif 1258ed2b524SDag-Erling Smørgrav ); 1260eefd307SCy Schubert printf("Linked modules:"); 127b7579f77SDag-Erling Smørgrav for(m = module_list_avail(); *m; m++) 128b7579f77SDag-Erling Smørgrav printf(" %s", *m); 129b7579f77SDag-Erling Smørgrav printf("\n"); 130971980c3SDag-Erling Smørgrav #ifdef USE_DNSCRYPT 131971980c3SDag-Erling Smørgrav printf("DNSCrypt feature available\n"); 132971980c3SDag-Erling Smørgrav #endif 1330eefd307SCy Schubert #ifdef USE_TCP_FASTOPEN 1340eefd307SCy Schubert printf("TCP Fastopen feature available\n"); 1350eefd307SCy Schubert #endif 1360eefd307SCy Schubert ub_event_base_free(base); 1370eefd307SCy Schubert printf("\nBSD licensed, see LICENSE in source package for details.\n"); 1380eefd307SCy Schubert printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 1390eefd307SCy Schubert } 1400eefd307SCy Schubert 1410eefd307SCy Schubert /** print usage. */ 1420eefd307SCy Schubert static void 1430eefd307SCy Schubert usage(void) 1440eefd307SCy Schubert { 1450eefd307SCy Schubert printf("usage: unbound [options]\n"); 1460eefd307SCy Schubert printf(" start unbound daemon DNS resolver.\n"); 1470eefd307SCy Schubert printf("-h this help.\n"); 1480eefd307SCy Schubert printf("-c file config file to read instead of %s\n", CONFIGFILE); 1490eefd307SCy Schubert printf(" file format is described in unbound.conf(5).\n"); 1500eefd307SCy Schubert printf("-d do not fork into the background.\n"); 1510eefd307SCy Schubert printf("-p do not create a pidfile.\n"); 1520eefd307SCy Schubert printf("-v verbose (more times to increase verbosity).\n"); 1530eefd307SCy Schubert printf("-V show version number and build options.\n"); 1540eefd307SCy Schubert #ifdef UB_ON_WINDOWS 1550eefd307SCy Schubert printf("-w opt windows option: \n"); 1560eefd307SCy Schubert printf(" install, remove - manage the services entry\n"); 1570eefd307SCy Schubert printf(" service - used to start from services control panel\n"); 1580eefd307SCy Schubert #endif 1590eefd307SCy Schubert printf("\nVersion %s\n", PACKAGE_VERSION); 160b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 161b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 162b7579f77SDag-Erling Smørgrav } 163b7579f77SDag-Erling Smørgrav 164b7579f77SDag-Erling Smørgrav #ifndef unbound_testbound 165b7579f77SDag-Erling Smørgrav int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 166b7579f77SDag-Erling Smørgrav { 167b7579f77SDag-Erling Smørgrav log_assert(0); 168b7579f77SDag-Erling Smørgrav return 0; 169b7579f77SDag-Erling Smørgrav } 170b7579f77SDag-Erling Smørgrav #endif 171b7579f77SDag-Erling Smørgrav 172b7579f77SDag-Erling Smørgrav /** check file descriptor count */ 173b7579f77SDag-Erling Smørgrav static void 174b7579f77SDag-Erling Smørgrav checkrlimits(struct config_file* cfg) 175b7579f77SDag-Erling Smørgrav { 17617d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S 177b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETRLIMIT 178b7579f77SDag-Erling Smørgrav /* list has number of ports to listen to, ifs number addresses */ 179b7579f77SDag-Erling Smørgrav int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 + 180b7579f77SDag-Erling Smørgrav (int)cfg->incoming_num_tcp:0)); 181b7579f77SDag-Erling Smørgrav size_t listen_ifs = (size_t)(cfg->num_ifs==0? 182b7579f77SDag-Erling Smørgrav ((cfg->do_ip4 && !cfg->if_automatic?1:0) + 183b7579f77SDag-Erling Smørgrav (cfg->do_ip6?1:0)):cfg->num_ifs); 184b7579f77SDag-Erling Smørgrav size_t listen_num = list*listen_ifs; 185b7579f77SDag-Erling Smørgrav size_t outudpnum = (size_t)cfg->outgoing_num_ports; 186b7579f77SDag-Erling Smørgrav size_t outtcpnum = cfg->outgoing_num_tcp; 187b7579f77SDag-Erling Smørgrav size_t misc = 4; /* logfile, pidfile, stdout... */ 188b7579f77SDag-Erling Smørgrav size_t perthread_noudp = listen_num + outtcpnum + 189b7579f77SDag-Erling Smørgrav 2/*cmdpipe*/ + 2/*libevent*/ + misc; 190b7579f77SDag-Erling Smørgrav size_t perthread = perthread_noudp + outudpnum; 191b7579f77SDag-Erling Smørgrav 192b7579f77SDag-Erling Smørgrav #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) 193b7579f77SDag-Erling Smørgrav int numthread = 1; /* it forks */ 194b7579f77SDag-Erling Smørgrav #else 195b7579f77SDag-Erling Smørgrav int numthread = (cfg->num_threads?cfg->num_threads:1); 196b7579f77SDag-Erling Smørgrav #endif 197b7579f77SDag-Erling Smørgrav size_t total = numthread * perthread + misc; 198b7579f77SDag-Erling Smørgrav size_t avail; 199b7579f77SDag-Erling Smørgrav struct rlimit rlim; 2005469a995SCy Schubert size_t memsize_expect = cfg->msg_cache_size + cfg->rrset_cache_size 2015469a995SCy Schubert + (cfg->do_tcp?cfg->stream_wait_size:0) 2025469a995SCy Schubert + (cfg->ip_ratelimit?cfg->ip_ratelimit_size:0) 2035469a995SCy Schubert + (cfg->ratelimit?cfg->ratelimit_size:0) 2045469a995SCy Schubert + (cfg->dnscrypt?cfg->dnscrypt_shared_secret_cache_size + cfg->dnscrypt_nonce_cache_size:0) 2055469a995SCy Schubert + cfg->infra_cache_numhosts * (sizeof(struct infra_key)+sizeof(struct infra_data)); 2065469a995SCy Schubert if(strstr(cfg->module_conf, "validator") && (cfg->trust_anchor_file_list || cfg->trust_anchor_list || cfg->auto_trust_anchor_file_list || cfg->trusted_keys_file_list)) { 2075469a995SCy Schubert memsize_expect += cfg->key_cache_size + cfg->neg_cache_size; 2085469a995SCy Schubert } 2095469a995SCy Schubert #ifdef HAVE_NGHTTP2_NGHTTP2_H 2105469a995SCy Schubert if(cfg_has_https(cfg)) { 2115469a995SCy Schubert memsize_expect += cfg->http_query_buffer_size + cfg->http_response_buffer_size; 2125469a995SCy Schubert } 2135469a995SCy Schubert #endif 2145469a995SCy Schubert 2155469a995SCy Schubert #ifdef RLIMIT_AS 2165469a995SCy Schubert if(getrlimit(RLIMIT_AS, &rlim) == 0) { 2175469a995SCy Schubert if(rlim.rlim_cur != (rlim_t)RLIM_INFINITY && 2185469a995SCy Schubert rlim.rlim_cur < (rlim_t)memsize_expect) { 2195469a995SCy Schubert log_warn("the ulimit(max memory size) is smaller than the expected memory usage (added size of caches). %u < %u bytes", (unsigned)rlim.rlim_cur, (unsigned)memsize_expect); 2205469a995SCy Schubert } 2215469a995SCy Schubert } 2225469a995SCy Schubert #endif 2235469a995SCy Schubert if(getrlimit(RLIMIT_DATA, &rlim) == 0) { 2245469a995SCy Schubert if(rlim.rlim_cur != (rlim_t)RLIM_INFINITY && 2255469a995SCy Schubert rlim.rlim_cur < (rlim_t)memsize_expect) { 2265469a995SCy Schubert log_warn("the ulimit(data seg size) is smaller than the expected memory usage (added size of caches). %u < %u bytes", (unsigned)rlim.rlim_cur, (unsigned)memsize_expect); 2275469a995SCy Schubert } 2285469a995SCy Schubert } 229b7579f77SDag-Erling Smørgrav 230b7579f77SDag-Erling Smørgrav if(total > 1024 && 231e2d15004SDag-Erling Smørgrav strncmp(ub_event_get_version(), "mini-event", 10) == 0) { 232b7579f77SDag-Erling Smørgrav log_warn("too many file descriptors requested. The builtin" 233b7579f77SDag-Erling Smørgrav "mini-event cannot handle more than 1024. Config " 234b7579f77SDag-Erling Smørgrav "for less fds or compile with libevent"); 235b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > 1024) 236b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 237b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((1024 238b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 239b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 240b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 241b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 242b7579f77SDag-Erling Smørgrav total = 1024; 243b7579f77SDag-Erling Smørgrav } 244b7579f77SDag-Erling Smørgrav if(perthread > 64 && 245e2d15004SDag-Erling Smørgrav strncmp(ub_event_get_version(), "winsock-event", 13) == 0) { 246b7579f77SDag-Erling Smørgrav log_err("too many file descriptors requested. The winsock" 247b7579f77SDag-Erling Smørgrav " event handler cannot handle more than 64 per " 248b7579f77SDag-Erling Smørgrav " thread. Config for less fds"); 249b7579f77SDag-Erling Smørgrav if(perthread_noudp+2 > 64) 250b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 251b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((64 252b7579f77SDag-Erling Smørgrav - perthread_noudp 253b7579f77SDag-Erling Smørgrav - 2/* safety margin */)); 254b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 255b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 256b7579f77SDag-Erling Smørgrav total = numthread*(perthread_noudp+ 257b7579f77SDag-Erling Smørgrav (size_t)cfg->outgoing_num_ports)+misc; 258b7579f77SDag-Erling Smørgrav } 259b7579f77SDag-Erling Smørgrav if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 260b7579f77SDag-Erling Smørgrav log_warn("getrlimit: %s", strerror(errno)); 261b7579f77SDag-Erling Smørgrav return; 262b7579f77SDag-Erling Smørgrav } 263b7579f77SDag-Erling Smørgrav if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY) 264b7579f77SDag-Erling Smørgrav return; 265b7579f77SDag-Erling Smørgrav if((size_t)rlim.rlim_cur < total) { 266b7579f77SDag-Erling Smørgrav avail = (size_t)rlim.rlim_cur; 267b7579f77SDag-Erling Smørgrav rlim.rlim_cur = (rlim_t)(total + 10); 268b7579f77SDag-Erling Smørgrav rlim.rlim_max = (rlim_t)(total + 10); 269b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRLIMIT 270b7579f77SDag-Erling Smørgrav if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) { 271b7579f77SDag-Erling Smørgrav log_warn("setrlimit: %s", strerror(errno)); 272b7579f77SDag-Erling Smørgrav #endif 273b7579f77SDag-Erling Smørgrav log_warn("cannot increase max open fds from %u to %u", 274b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 275b7579f77SDag-Erling Smørgrav /* check that calculation below does not underflow, 276b7579f77SDag-Erling Smørgrav * with 15 as margin */ 277b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > avail) 278b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 279b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((avail 280b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 281b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 282b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 283b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 284b7579f77SDag-Erling Smørgrav log_warn("increase ulimit or decrease threads, " 285b7579f77SDag-Erling Smørgrav "ports in config to remove this warning"); 286b7579f77SDag-Erling Smørgrav return; 287ff825849SDag-Erling Smørgrav #ifdef HAVE_SETRLIMIT 288b7579f77SDag-Erling Smørgrav } 289ff825849SDag-Erling Smørgrav #endif 290ff825849SDag-Erling Smørgrav verbose(VERB_ALGO, "increased limit(open files) from %u to %u", 291b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 292b7579f77SDag-Erling Smørgrav } 293b7579f77SDag-Erling Smørgrav #else 294b7579f77SDag-Erling Smørgrav (void)cfg; 295b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETRLIMIT */ 29617d15b25SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 297b7579f77SDag-Erling Smørgrav } 298b7579f77SDag-Erling Smørgrav 299b7579f77SDag-Erling Smørgrav /** set verbosity, check rlimits, cache settings */ 300b7579f77SDag-Erling Smørgrav static void 301b7579f77SDag-Erling Smørgrav apply_settings(struct daemon* daemon, struct config_file* cfg, 302091e9e46SCy Schubert int cmdline_verbose, int debug_mode) 303b7579f77SDag-Erling Smørgrav { 304b7579f77SDag-Erling Smørgrav /* apply if they have changed */ 305b7579f77SDag-Erling Smørgrav verbosity = cmdline_verbose + cfg->verbosity; 306ff825849SDag-Erling Smørgrav if (debug_mode > 1) { 307ff825849SDag-Erling Smørgrav cfg->use_syslog = 0; 308bc892140SDag-Erling Smørgrav free(cfg->logfile); 309ff825849SDag-Erling Smørgrav cfg->logfile = NULL; 310ff825849SDag-Erling Smørgrav } 311b7579f77SDag-Erling Smørgrav daemon_apply_cfg(daemon, cfg); 312b7579f77SDag-Erling Smørgrav checkrlimits(cfg); 3133005e0a3SDag-Erling Smørgrav 3143005e0a3SDag-Erling Smørgrav if (cfg->use_systemd && cfg->do_daemonize) { 3153005e0a3SDag-Erling Smørgrav log_warn("use-systemd and do-daemonize should not be enabled at the same time"); 3163005e0a3SDag-Erling Smørgrav } 3173005e0a3SDag-Erling Smørgrav 318091e9e46SCy Schubert log_ident_set_or_default(cfg->log_identity); 319b7579f77SDag-Erling Smørgrav } 320b7579f77SDag-Erling Smørgrav 321b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 322b7579f77SDag-Erling Smørgrav /** Read existing pid from pidfile. 323b7579f77SDag-Erling Smørgrav * @param file: file name of pid file. 324b7579f77SDag-Erling Smørgrav * @return: the pid from the file or -1 if none. 325b7579f77SDag-Erling Smørgrav */ 326b7579f77SDag-Erling Smørgrav static pid_t 327b7579f77SDag-Erling Smørgrav readpid (const char* file) 328b7579f77SDag-Erling Smørgrav { 329b7579f77SDag-Erling Smørgrav int fd; 330b7579f77SDag-Erling Smørgrav pid_t pid; 331b7579f77SDag-Erling Smørgrav char pidbuf[32]; 332b7579f77SDag-Erling Smørgrav char* t; 333b7579f77SDag-Erling Smørgrav ssize_t l; 334b7579f77SDag-Erling Smørgrav 335b7579f77SDag-Erling Smørgrav if ((fd = open(file, O_RDONLY)) == -1) { 336b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 337b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 338b7579f77SDag-Erling Smørgrav file, strerror(errno)); 339b7579f77SDag-Erling Smørgrav return -1; 340b7579f77SDag-Erling Smørgrav } 341b7579f77SDag-Erling Smørgrav 342b7579f77SDag-Erling Smørgrav if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) { 343b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 344b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 345b7579f77SDag-Erling Smørgrav file, strerror(errno)); 346b7579f77SDag-Erling Smørgrav close(fd); 347b7579f77SDag-Erling Smørgrav return -1; 348b7579f77SDag-Erling Smørgrav } 349b7579f77SDag-Erling Smørgrav 350b7579f77SDag-Erling Smørgrav close(fd); 351b7579f77SDag-Erling Smørgrav 352b7579f77SDag-Erling Smørgrav /* Empty pidfile means no pidfile... */ 353b7579f77SDag-Erling Smørgrav if (l == 0) { 354b7579f77SDag-Erling Smørgrav return -1; 355b7579f77SDag-Erling Smørgrav } 356b7579f77SDag-Erling Smørgrav 357b7579f77SDag-Erling Smørgrav pidbuf[sizeof(pidbuf)-1] = 0; 358b7579f77SDag-Erling Smørgrav pid = (pid_t)strtol(pidbuf, &t, 10); 359b7579f77SDag-Erling Smørgrav 360b7579f77SDag-Erling Smørgrav if (*t && *t != '\n') { 361b7579f77SDag-Erling Smørgrav return -1; 362b7579f77SDag-Erling Smørgrav } 363b7579f77SDag-Erling Smørgrav return pid; 364b7579f77SDag-Erling Smørgrav } 365b7579f77SDag-Erling Smørgrav 366b7579f77SDag-Erling Smørgrav /** write pid to file. 367b7579f77SDag-Erling Smørgrav * @param pidfile: file name of pid file. 368b7579f77SDag-Erling Smørgrav * @param pid: pid to write to file. 369b7579f77SDag-Erling Smørgrav */ 370335c7cdaSCy Schubert static void 371b7579f77SDag-Erling Smørgrav writepid (const char* pidfile, pid_t pid) 372b7579f77SDag-Erling Smørgrav { 373369c6923SCy Schubert int fd; 374369c6923SCy Schubert char pidbuf[32]; 375369c6923SCy Schubert size_t count = 0; 376369c6923SCy Schubert snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long)pid); 377b7579f77SDag-Erling Smørgrav 378369c6923SCy Schubert if((fd = open(pidfile, O_WRONLY | O_CREAT | O_TRUNC 379369c6923SCy Schubert #ifdef O_NOFOLLOW 380369c6923SCy Schubert | O_NOFOLLOW 381369c6923SCy Schubert #endif 382369c6923SCy Schubert , 0644)) == -1) { 383b7579f77SDag-Erling Smørgrav log_err("cannot open pidfile %s: %s", 384b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 385335c7cdaSCy Schubert return; 386b7579f77SDag-Erling Smørgrav } 387369c6923SCy Schubert while(count < strlen(pidbuf)) { 388369c6923SCy Schubert ssize_t r = write(fd, pidbuf+count, strlen(pidbuf)-count); 389369c6923SCy Schubert if(r == -1) { 390369c6923SCy Schubert if(errno == EAGAIN || errno == EINTR) 391369c6923SCy Schubert continue; 392b7579f77SDag-Erling Smørgrav log_err("cannot write to pidfile %s: %s", 393b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 394369c6923SCy Schubert close(fd); 395335c7cdaSCy Schubert return; 396369c6923SCy Schubert } else if(r == 0) { 397369c6923SCy Schubert log_err("cannot write any bytes to pidfile %s: " 398369c6923SCy Schubert "write returns 0 bytes written", pidfile); 399369c6923SCy Schubert close(fd); 400335c7cdaSCy Schubert return; 401b7579f77SDag-Erling Smørgrav } 402369c6923SCy Schubert count += r; 403369c6923SCy Schubert } 404369c6923SCy Schubert close(fd); 405b7579f77SDag-Erling Smørgrav } 406b7579f77SDag-Erling Smørgrav 407b7579f77SDag-Erling Smørgrav /** 408b7579f77SDag-Erling Smørgrav * check old pid file. 409b7579f77SDag-Erling Smørgrav * @param pidfile: the file name of the pid file. 410b7579f77SDag-Erling Smørgrav * @param inchroot: if pidfile is inchroot and we can thus expect to 411b7579f77SDag-Erling Smørgrav * be able to delete it. 412b7579f77SDag-Erling Smørgrav */ 413b7579f77SDag-Erling Smørgrav static void 414b7579f77SDag-Erling Smørgrav checkoldpid(char* pidfile, int inchroot) 415b7579f77SDag-Erling Smørgrav { 416b7579f77SDag-Erling Smørgrav pid_t old; 417b7579f77SDag-Erling Smørgrav if((old = readpid(pidfile)) != -1) { 418b7579f77SDag-Erling Smørgrav /* see if it is still alive */ 419b7579f77SDag-Erling Smørgrav if(kill(old, 0) == 0 || errno == EPERM) 420b7579f77SDag-Erling Smørgrav log_warn("unbound is already running as pid %u.", 421b7579f77SDag-Erling Smørgrav (unsigned)old); 422b7579f77SDag-Erling Smørgrav else if(inchroot) 423b7579f77SDag-Erling Smørgrav log_warn("did not exit gracefully last time (%u)", 424b7579f77SDag-Erling Smørgrav (unsigned)old); 425b7579f77SDag-Erling Smørgrav } 426b7579f77SDag-Erling Smørgrav } 427b7579f77SDag-Erling Smørgrav #endif /* HAVE_KILL */ 428b7579f77SDag-Erling Smørgrav 429b7579f77SDag-Erling Smørgrav /** detach from command line */ 430b7579f77SDag-Erling Smørgrav static void 431b7579f77SDag-Erling Smørgrav detach(void) 432b7579f77SDag-Erling Smørgrav { 433b7579f77SDag-Erling Smørgrav #if defined(HAVE_DAEMON) && !defined(DEPRECATED_DAEMON) 434b7579f77SDag-Erling Smørgrav /* use POSIX daemon(3) function */ 435b7579f77SDag-Erling Smørgrav if(daemon(1, 0) != 0) 436b7579f77SDag-Erling Smørgrav fatal_exit("daemon failed: %s", strerror(errno)); 437b7579f77SDag-Erling Smørgrav #else /* no HAVE_DAEMON */ 438b7579f77SDag-Erling Smørgrav #ifdef HAVE_FORK 439b7579f77SDag-Erling Smørgrav int fd; 440b7579f77SDag-Erling Smørgrav /* Take off... */ 441b7579f77SDag-Erling Smørgrav switch (fork()) { 442b7579f77SDag-Erling Smørgrav case 0: 443b7579f77SDag-Erling Smørgrav break; 444b7579f77SDag-Erling Smørgrav case -1: 445b7579f77SDag-Erling Smørgrav fatal_exit("fork failed: %s", strerror(errno)); 446b7579f77SDag-Erling Smørgrav default: 447b7579f77SDag-Erling Smørgrav /* exit interactive session */ 448b7579f77SDag-Erling Smørgrav exit(0); 449b7579f77SDag-Erling Smørgrav } 450b7579f77SDag-Erling Smørgrav /* detach */ 451b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETSID 452b7579f77SDag-Erling Smørgrav if(setsid() == -1) 453b7579f77SDag-Erling Smørgrav fatal_exit("setsid() failed: %s", strerror(errno)); 454b7579f77SDag-Erling Smørgrav #endif 455b7579f77SDag-Erling Smørgrav if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { 456b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDIN_FILENO); 457b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDOUT_FILENO); 458b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDERR_FILENO); 459b7579f77SDag-Erling Smørgrav if (fd > 2) 460b7579f77SDag-Erling Smørgrav (void)close(fd); 461b7579f77SDag-Erling Smørgrav } 462b7579f77SDag-Erling Smørgrav #endif /* HAVE_FORK */ 463b7579f77SDag-Erling Smørgrav #endif /* HAVE_DAEMON */ 464b7579f77SDag-Erling Smørgrav } 465b7579f77SDag-Erling Smørgrav 4668a384985SDag-Erling Smørgrav /** daemonize, drop user privileges and chroot if needed */ 467b7579f77SDag-Erling Smørgrav static void 468b7579f77SDag-Erling Smørgrav perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, 469971980c3SDag-Erling Smørgrav const char** cfgfile, int need_pidfile) 470b7579f77SDag-Erling Smørgrav { 471f61ef7f6SDag-Erling Smørgrav #ifdef HAVE_KILL 472f61ef7f6SDag-Erling Smørgrav int pidinchroot; 473f61ef7f6SDag-Erling Smørgrav #endif 474b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 475b7579f77SDag-Erling Smørgrav struct passwd *pwd = NULL; 476*56850988SCy Schubert #endif 477b7579f77SDag-Erling Smørgrav 478*56850988SCy Schubert if(!daemon_privileged(daemon)) 479*56850988SCy Schubert fatal_exit("could not do privileged setup"); 480*56850988SCy Schubert #ifdef HAVE_GETPWNAM 481b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 482b7579f77SDag-Erling Smørgrav if((pwd = getpwnam(cfg->username)) == NULL) 483b7579f77SDag-Erling Smørgrav fatal_exit("user '%s' does not exist.", cfg->username); 484b7579f77SDag-Erling Smørgrav /* endpwent below, in case we need pwd for setusercontext */ 485b7579f77SDag-Erling Smørgrav } 486b7579f77SDag-Erling Smørgrav #endif 48705ab2901SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 48805ab2901SDag-Erling Smørgrav w_config_adjust_directory(cfg); 48905ab2901SDag-Erling Smørgrav #endif 490b7579f77SDag-Erling Smørgrav 49157bddd21SDag-Erling Smørgrav /* read ssl keys while superuser and outside chroot */ 49257bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL 49357bddd21SDag-Erling Smørgrav if(!(daemon->rc = daemon_remote_create(cfg))) 49457bddd21SDag-Erling Smørgrav fatal_exit("could not set up remote-control"); 49557bddd21SDag-Erling Smørgrav if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { 49657bddd21SDag-Erling Smørgrav if(!(daemon->listen_sslctx = listen_sslctx_create( 49757bddd21SDag-Erling Smørgrav cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) 49857bddd21SDag-Erling Smørgrav fatal_exit("could not set up listen SSL_CTX"); 499e86b9096SDag-Erling Smørgrav if(cfg->tls_ciphers && cfg->tls_ciphers[0]) { 500e86b9096SDag-Erling Smørgrav if (!SSL_CTX_set_cipher_list(daemon->listen_sslctx, cfg->tls_ciphers)) { 501e86b9096SDag-Erling Smørgrav fatal_exit("failed to set tls-cipher %s", cfg->tls_ciphers); 502e86b9096SDag-Erling Smørgrav } 503e86b9096SDag-Erling Smørgrav } 504e86b9096SDag-Erling Smørgrav #ifdef HAVE_SSL_CTX_SET_CIPHERSUITES 505e86b9096SDag-Erling Smørgrav if(cfg->tls_ciphersuites && cfg->tls_ciphersuites[0]) { 506e86b9096SDag-Erling Smørgrav if (!SSL_CTX_set_ciphersuites(daemon->listen_sslctx, cfg->tls_ciphersuites)) { 507e86b9096SDag-Erling Smørgrav fatal_exit("failed to set tls-ciphersuites %s", cfg->tls_ciphersuites); 508e86b9096SDag-Erling Smørgrav } 509e86b9096SDag-Erling Smørgrav } 510e86b9096SDag-Erling Smørgrav #endif 511e86b9096SDag-Erling Smørgrav if(cfg->tls_session_ticket_keys.first && 512e86b9096SDag-Erling Smørgrav cfg->tls_session_ticket_keys.first->str[0] != 0) { 513e86b9096SDag-Erling Smørgrav if(!listen_sslctx_setup_ticket_keys(daemon->listen_sslctx, cfg->tls_session_ticket_keys.first)) { 514e86b9096SDag-Erling Smørgrav fatal_exit("could not set session ticket SSL_CTX"); 515e86b9096SDag-Erling Smørgrav } 516e86b9096SDag-Erling Smørgrav } 51757bddd21SDag-Erling Smørgrav } 51857bddd21SDag-Erling Smørgrav if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, 5193bd4df0aSDag-Erling Smørgrav cfg->tls_cert_bundle, cfg->tls_win_cert))) 52057bddd21SDag-Erling Smørgrav fatal_exit("could not set up connect SSL_CTX"); 52157bddd21SDag-Erling Smørgrav #endif 52257bddd21SDag-Erling Smørgrav 523b7579f77SDag-Erling Smørgrav /* init syslog (as root) if needed, before daemonize, otherwise 524b7579f77SDag-Erling Smørgrav * a fork error could not be printed since daemonize closed stderr.*/ 525b7579f77SDag-Erling Smørgrav if(cfg->use_syslog) { 526b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 527b7579f77SDag-Erling Smørgrav } 528b7579f77SDag-Erling Smørgrav /* if using a logfile, we cannot open it because the logfile would 529b7579f77SDag-Erling Smørgrav * be created with the wrong permissions, we cannot chown it because 530b7579f77SDag-Erling Smørgrav * we cannot chown system logfiles, so we do not open at all. 531b7579f77SDag-Erling Smørgrav * So, using a logfile, the user does not see errors unless -d is 532b7579f77SDag-Erling Smørgrav * given to unbound on the commandline. */ 533b7579f77SDag-Erling Smørgrav 534b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 535f61ef7f6SDag-Erling Smørgrav /* true if pidfile is inside chrootdir, or nochroot */ 536971980c3SDag-Erling Smørgrav pidinchroot = need_pidfile && (!(cfg->chrootdir && cfg->chrootdir[0]) || 537f61ef7f6SDag-Erling Smørgrav (cfg->chrootdir && cfg->chrootdir[0] && 538f61ef7f6SDag-Erling Smørgrav strncmp(cfg->pidfile, cfg->chrootdir, 539971980c3SDag-Erling Smørgrav strlen(cfg->chrootdir))==0)); 540f61ef7f6SDag-Erling Smørgrav 541b7579f77SDag-Erling Smørgrav /* check old pid file before forking */ 542971980c3SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) { 543b7579f77SDag-Erling Smørgrav /* calculate position of pidfile */ 544b7579f77SDag-Erling Smørgrav if(cfg->pidfile[0] == '/') 545b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(cfg->pidfile); 546b7579f77SDag-Erling Smørgrav else daemon->pidfile = fname_after_chroot(cfg->pidfile, 547b7579f77SDag-Erling Smørgrav cfg, 1); 548b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 549b7579f77SDag-Erling Smørgrav fatal_exit("pidfile alloc: out of memory"); 550335c7cdaSCy Schubert /* Check old pid if there is no username configured. 551335c7cdaSCy Schubert * With a username, the assumption is that the privilege 552335c7cdaSCy Schubert * drop makes a pidfile not removed when the server stopped 553335c7cdaSCy Schubert * last time. The server does not chown the pidfile for it, 554335c7cdaSCy Schubert * because that creates privilege escape problems, with the 555335c7cdaSCy Schubert * pidfile writable by unprivileged users, but used by 556335c7cdaSCy Schubert * privileged users. */ 557*56850988SCy Schubert if(!(cfg->username && cfg->username[0])) 558f61ef7f6SDag-Erling Smørgrav checkoldpid(daemon->pidfile, pidinchroot); 559b7579f77SDag-Erling Smørgrav } 560b7579f77SDag-Erling Smørgrav #endif 561b7579f77SDag-Erling Smørgrav 562b7579f77SDag-Erling Smørgrav /* daemonize because pid is needed by the writepid func */ 563b7579f77SDag-Erling Smørgrav if(!debug_mode && cfg->do_daemonize) { 564b7579f77SDag-Erling Smørgrav detach(); 565b7579f77SDag-Erling Smørgrav } 566b7579f77SDag-Erling Smørgrav 567b7579f77SDag-Erling Smørgrav /* write new pidfile (while still root, so can be outside chroot) */ 568b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 569971980c3SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) { 570335c7cdaSCy Schubert writepid(daemon->pidfile, getpid()); 571369c6923SCy Schubert } 572b7579f77SDag-Erling Smørgrav #else 573b7579f77SDag-Erling Smørgrav (void)daemon; 574971980c3SDag-Erling Smørgrav (void)need_pidfile; 5756480faa8SDag-Erling Smørgrav #endif /* HAVE_KILL */ 576b7579f77SDag-Erling Smørgrav 577b7579f77SDag-Erling Smørgrav /* Set user context */ 578b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 5796480faa8SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { 580b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETUSERCONTEXT 581b7579f77SDag-Erling Smørgrav /* setusercontext does initgroups, setuid, setgid, and 582b7579f77SDag-Erling Smørgrav * also resource limits from login config, but we 583b7579f77SDag-Erling Smørgrav * still call setresuid, setresgid to be sure to set all uid*/ 5846480faa8SDag-Erling Smørgrav if(setusercontext(NULL, pwd, cfg_uid, (unsigned) 585b7579f77SDag-Erling Smørgrav LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) 586b7579f77SDag-Erling Smørgrav log_warn("unable to setusercontext %s: %s", 587b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 58825039b37SCy Schubert #else 58925039b37SCy Schubert (void)pwd; 590b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETUSERCONTEXT */ 591b7579f77SDag-Erling Smørgrav } 592b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 593b7579f77SDag-Erling Smørgrav 594b7579f77SDag-Erling Smørgrav /* box into the chroot */ 595b7579f77SDag-Erling Smørgrav #ifdef HAVE_CHROOT 596b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0]) { 597b7579f77SDag-Erling Smørgrav if(chdir(cfg->chrootdir)) { 598b7579f77SDag-Erling Smørgrav fatal_exit("unable to chdir to chroot %s: %s", 599b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 600b7579f77SDag-Erling Smørgrav } 601b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", cfg->chrootdir); 602b7579f77SDag-Erling Smørgrav if(chroot(cfg->chrootdir)) 603b7579f77SDag-Erling Smørgrav fatal_exit("unable to chroot to %s: %s", 604b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 6058ed2b524SDag-Erling Smørgrav if(chdir("/")) 6068ed2b524SDag-Erling Smørgrav fatal_exit("unable to chdir to / in chroot %s: %s", 6078ed2b524SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 608b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir); 609b7579f77SDag-Erling Smørgrav if(strncmp(*cfgfile, cfg->chrootdir, 610b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 611b7579f77SDag-Erling Smørgrav (*cfgfile) += strlen(cfg->chrootdir); 612b7579f77SDag-Erling Smørgrav 613b7579f77SDag-Erling Smørgrav /* adjust stored pidfile for chroot */ 614b7579f77SDag-Erling Smørgrav if(daemon->pidfile && daemon->pidfile[0] && 615b7579f77SDag-Erling Smørgrav strncmp(daemon->pidfile, cfg->chrootdir, 616b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir))==0) { 617b7579f77SDag-Erling Smørgrav char* old = daemon->pidfile; 618b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(old+strlen(cfg->chrootdir)); 619b7579f77SDag-Erling Smørgrav free(old); 620b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 621b7579f77SDag-Erling Smørgrav log_err("out of memory in pidfile adjust"); 622b7579f77SDag-Erling Smørgrav } 623b7579f77SDag-Erling Smørgrav daemon->chroot = strdup(cfg->chrootdir); 624b7579f77SDag-Erling Smørgrav if(!daemon->chroot) 625b7579f77SDag-Erling Smørgrav log_err("out of memory in daemon chroot dir storage"); 626b7579f77SDag-Erling Smørgrav } 627b7579f77SDag-Erling Smørgrav #else 628b7579f77SDag-Erling Smørgrav (void)cfgfile; 629b7579f77SDag-Erling Smørgrav #endif 630b7579f77SDag-Erling Smørgrav /* change to working directory inside chroot */ 631b7579f77SDag-Erling Smørgrav if(cfg->directory && cfg->directory[0]) { 632b7579f77SDag-Erling Smørgrav char* dir = cfg->directory; 633b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0] && 634b7579f77SDag-Erling Smørgrav strncmp(dir, cfg->chrootdir, 635b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 636b7579f77SDag-Erling Smørgrav dir += strlen(cfg->chrootdir); 637b7579f77SDag-Erling Smørgrav if(dir[0]) { 638b7579f77SDag-Erling Smørgrav if(chdir(dir)) { 639b7579f77SDag-Erling Smørgrav fatal_exit("Could not chdir to %s: %s", 640b7579f77SDag-Erling Smørgrav dir, strerror(errno)); 641b7579f77SDag-Erling Smørgrav } 642b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", dir); 643b7579f77SDag-Erling Smørgrav } 644b7579f77SDag-Erling Smørgrav } 645b7579f77SDag-Erling Smørgrav 646b7579f77SDag-Erling Smørgrav /* drop permissions after chroot, getpwnam, pidfile, syslog done*/ 647b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 6486480faa8SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { 649b7579f77SDag-Erling Smørgrav # ifdef HAVE_INITGROUPS 6506480faa8SDag-Erling Smørgrav if(initgroups(cfg->username, cfg_gid) != 0) 651b7579f77SDag-Erling Smørgrav log_warn("unable to initgroups %s: %s", 652b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 653b7579f77SDag-Erling Smørgrav # endif /* HAVE_INITGROUPS */ 654b5663de9SDag-Erling Smørgrav # ifdef HAVE_ENDPWENT 655b7579f77SDag-Erling Smørgrav endpwent(); 656b5663de9SDag-Erling Smørgrav # endif 657b7579f77SDag-Erling Smørgrav 658b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESGID 6596480faa8SDag-Erling Smørgrav if(setresgid(cfg_gid,cfg_gid,cfg_gid) != 0) 660b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) 6616480faa8SDag-Erling Smørgrav if(setregid(cfg_gid,cfg_gid) != 0) 662b7579f77SDag-Erling Smørgrav #else /* use setgid */ 6636480faa8SDag-Erling Smørgrav if(setgid(cfg_gid) != 0) 664b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESGID */ 665b7579f77SDag-Erling Smørgrav fatal_exit("unable to set group id of %s: %s", 666b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 667b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESUID 6686480faa8SDag-Erling Smørgrav if(setresuid(cfg_uid,cfg_uid,cfg_uid) != 0) 669b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) 6706480faa8SDag-Erling Smørgrav if(setreuid(cfg_uid,cfg_uid) != 0) 671b7579f77SDag-Erling Smørgrav #else /* use setuid */ 6726480faa8SDag-Erling Smørgrav if(setuid(cfg_uid) != 0) 673b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESUID */ 674b7579f77SDag-Erling Smørgrav fatal_exit("unable to set user id of %s: %s", 675b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 676b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "drop user privileges, run as %s", 677b7579f77SDag-Erling Smørgrav cfg->username); 678b7579f77SDag-Erling Smørgrav } 679b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 680b7579f77SDag-Erling Smørgrav /* file logging inited after chroot,chdir,setuid is done so that 681b7579f77SDag-Erling Smørgrav * it would succeed on SIGHUP as well */ 682b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 683b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 684b7579f77SDag-Erling Smørgrav } 685b7579f77SDag-Erling Smørgrav 686b7579f77SDag-Erling Smørgrav /** 687b7579f77SDag-Erling Smørgrav * Run the daemon. 688b7579f77SDag-Erling Smørgrav * @param cfgfile: the config file name. 689b7579f77SDag-Erling Smørgrav * @param cmdline_verbose: verbosity resulting from commandline -v. 690b7579f77SDag-Erling Smørgrav * These increase verbosity as specified in the config file. 691b7579f77SDag-Erling Smørgrav * @param debug_mode: if set, do not daemonize. 692971980c3SDag-Erling Smørgrav * @param need_pidfile: if false, no pidfile is checked or created. 693b7579f77SDag-Erling Smørgrav */ 694b7579f77SDag-Erling Smørgrav static void 695091e9e46SCy Schubert run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, int need_pidfile) 696b7579f77SDag-Erling Smørgrav { 697b7579f77SDag-Erling Smørgrav struct config_file* cfg = NULL; 698b7579f77SDag-Erling Smørgrav struct daemon* daemon = NULL; 699b7579f77SDag-Erling Smørgrav int done_setup = 0; 700b7579f77SDag-Erling Smørgrav 701b7579f77SDag-Erling Smørgrav if(!(daemon = daemon_init())) 702b7579f77SDag-Erling Smørgrav fatal_exit("alloc failure"); 703b7579f77SDag-Erling Smørgrav while(!daemon->need_to_exit) { 704b7579f77SDag-Erling Smørgrav if(done_setup) 705b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING); 706b7579f77SDag-Erling Smørgrav else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING); 707b7579f77SDag-Erling Smørgrav 708b7579f77SDag-Erling Smørgrav /* config stuff */ 709b7579f77SDag-Erling Smørgrav if(!(cfg = config_create())) 710b7579f77SDag-Erling Smørgrav fatal_exit("Could not alloc config defaults"); 711b7579f77SDag-Erling Smørgrav if(!config_read(cfg, cfgfile, daemon->chroot)) { 712b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 7134c75e3aaSDag-Erling Smørgrav fatal_exit("Could not read config file: %s." 7144c75e3aaSDag-Erling Smørgrav " Maybe try unbound -dd, it stays on " 7154c75e3aaSDag-Erling Smørgrav "the commandline to see more errors, " 7164c75e3aaSDag-Erling Smørgrav "or unbound-checkconf", cfgfile); 717b7579f77SDag-Erling Smørgrav log_warn("Continuing with default config settings"); 718b7579f77SDag-Erling Smørgrav } 719091e9e46SCy Schubert apply_settings(daemon, cfg, cmdline_verbose, debug_mode); 7206480faa8SDag-Erling Smørgrav if(!done_setup) 721748bd829SDag-Erling Smørgrav config_lookup_uid(cfg); 722b7579f77SDag-Erling Smørgrav 723b7579f77SDag-Erling Smørgrav /* prepare */ 724b7579f77SDag-Erling Smørgrav if(!daemon_open_shared_ports(daemon)) 725b7579f77SDag-Erling Smørgrav fatal_exit("could not open ports"); 726b7579f77SDag-Erling Smørgrav if(!done_setup) { 727971980c3SDag-Erling Smørgrav perform_setup(daemon, cfg, debug_mode, &cfgfile, need_pidfile); 728b7579f77SDag-Erling Smørgrav done_setup = 1; 729b7579f77SDag-Erling Smørgrav } else { 730b7579f77SDag-Erling Smørgrav /* reopen log after HUP to facilitate log rotation */ 731b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 732b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, 0, cfg->chrootdir); 733b7579f77SDag-Erling Smørgrav } 734b7579f77SDag-Erling Smørgrav /* work */ 735b7579f77SDag-Erling Smørgrav daemon_fork(daemon); 736b7579f77SDag-Erling Smørgrav 737b7579f77SDag-Erling Smørgrav /* clean up for restart */ 738b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "cleanup."); 739b7579f77SDag-Erling Smørgrav daemon_cleanup(daemon); 740b7579f77SDag-Erling Smørgrav config_delete(cfg); 741b7579f77SDag-Erling Smørgrav } 742b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Exit cleanup."); 743b7579f77SDag-Erling Smørgrav /* this unlink may not work if the pidfile is located outside 744b7579f77SDag-Erling Smørgrav * of the chroot/workdir or we no longer have permissions */ 745b7579f77SDag-Erling Smørgrav if(daemon->pidfile) { 746b7579f77SDag-Erling Smørgrav int fd; 747b7579f77SDag-Erling Smørgrav /* truncate pidfile */ 748335c7cdaSCy Schubert fd = open(daemon->pidfile, O_WRONLY | O_TRUNC 749335c7cdaSCy Schubert #ifdef O_NOFOLLOW 750335c7cdaSCy Schubert | O_NOFOLLOW 751335c7cdaSCy Schubert #endif 752335c7cdaSCy Schubert , 0644); 753b7579f77SDag-Erling Smørgrav if(fd != -1) 754b7579f77SDag-Erling Smørgrav close(fd); 755b7579f77SDag-Erling Smørgrav /* delete pidfile */ 756b7579f77SDag-Erling Smørgrav unlink(daemon->pidfile); 757b7579f77SDag-Erling Smørgrav } 758b7579f77SDag-Erling Smørgrav daemon_delete(daemon); 759b7579f77SDag-Erling Smørgrav } 760b7579f77SDag-Erling Smørgrav 761b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 762b7579f77SDag-Erling Smørgrav extern int optind; 763b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 764b7579f77SDag-Erling Smørgrav extern char* optarg; 765b7579f77SDag-Erling Smørgrav 766b7579f77SDag-Erling Smørgrav /** 767b7579f77SDag-Erling Smørgrav * main program. Set options given commandline arguments. 768b7579f77SDag-Erling Smørgrav * @param argc: number of commandline arguments. 769b7579f77SDag-Erling Smørgrav * @param argv: array of commandline arguments. 770b7579f77SDag-Erling Smørgrav * @return: exit status of the program. 771b7579f77SDag-Erling Smørgrav */ 772b7579f77SDag-Erling Smørgrav int 773b7579f77SDag-Erling Smørgrav main(int argc, char* argv[]) 774b7579f77SDag-Erling Smørgrav { 775b7579f77SDag-Erling Smørgrav int c; 776b7579f77SDag-Erling Smørgrav const char* cfgfile = CONFIGFILE; 777b7579f77SDag-Erling Smørgrav const char* winopt = NULL; 778bc892140SDag-Erling Smørgrav const char* log_ident_default; 779b7579f77SDag-Erling Smørgrav int cmdline_verbose = 0; 780b7579f77SDag-Erling Smørgrav int debug_mode = 0; 781971980c3SDag-Erling Smørgrav int need_pidfile = 1; 782971980c3SDag-Erling Smørgrav 783b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 784b7579f77SDag-Erling Smørgrav int cmdline_cfg = 0; 785b7579f77SDag-Erling Smørgrav #endif 786b7579f77SDag-Erling Smørgrav 78724e36522SCy Schubert checklock_start(); 788b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); 789bc892140SDag-Erling Smørgrav log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]; 790091e9e46SCy Schubert log_ident_set_default(log_ident_default); 791bc892140SDag-Erling Smørgrav log_ident_set(log_ident_default); 792b7579f77SDag-Erling Smørgrav /* parse the options */ 7930eefd307SCy Schubert while( (c=getopt(argc, argv, "c:dhpvw:V")) != -1) { 794b7579f77SDag-Erling Smørgrav switch(c) { 795b7579f77SDag-Erling Smørgrav case 'c': 796b7579f77SDag-Erling Smørgrav cfgfile = optarg; 797b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 798b7579f77SDag-Erling Smørgrav cmdline_cfg = 1; 799b7579f77SDag-Erling Smørgrav #endif 800b7579f77SDag-Erling Smørgrav break; 801b7579f77SDag-Erling Smørgrav case 'v': 802b7579f77SDag-Erling Smørgrav cmdline_verbose++; 803b7579f77SDag-Erling Smørgrav verbosity++; 804b7579f77SDag-Erling Smørgrav break; 805971980c3SDag-Erling Smørgrav case 'p': 806971980c3SDag-Erling Smørgrav need_pidfile = 0; 807971980c3SDag-Erling Smørgrav break; 808b7579f77SDag-Erling Smørgrav case 'd': 809ff825849SDag-Erling Smørgrav debug_mode++; 810b7579f77SDag-Erling Smørgrav break; 811b7579f77SDag-Erling Smørgrav case 'w': 812b7579f77SDag-Erling Smørgrav winopt = optarg; 813b7579f77SDag-Erling Smørgrav break; 8140eefd307SCy Schubert case 'V': 8150eefd307SCy Schubert print_build_options(); 8160eefd307SCy Schubert return 0; 817b7579f77SDag-Erling Smørgrav case '?': 818b7579f77SDag-Erling Smørgrav case 'h': 819b7579f77SDag-Erling Smørgrav default: 820b7579f77SDag-Erling Smørgrav usage(); 821b7579f77SDag-Erling Smørgrav return 1; 822b7579f77SDag-Erling Smørgrav } 823b7579f77SDag-Erling Smørgrav } 824b7579f77SDag-Erling Smørgrav argc -= optind; 825a755b6f6SDag-Erling Smørgrav /* argv += optind; not using further arguments */ 826b7579f77SDag-Erling Smørgrav 827b7579f77SDag-Erling Smørgrav if(winopt) { 828b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 829b7579f77SDag-Erling Smørgrav wsvc_command_option(winopt, cfgfile, cmdline_verbose, 830b7579f77SDag-Erling Smørgrav cmdline_cfg); 831b7579f77SDag-Erling Smørgrav #else 832b7579f77SDag-Erling Smørgrav fatal_exit("option not supported"); 833b7579f77SDag-Erling Smørgrav #endif 834b7579f77SDag-Erling Smørgrav } 835b7579f77SDag-Erling Smørgrav 836b7579f77SDag-Erling Smørgrav if(argc != 0) { 837b7579f77SDag-Erling Smørgrav usage(); 838b7579f77SDag-Erling Smørgrav return 1; 839b7579f77SDag-Erling Smørgrav } 840b7579f77SDag-Erling Smørgrav 841091e9e46SCy Schubert run_daemon(cfgfile, cmdline_verbose, debug_mode, need_pidfile); 842b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); /* close logfile */ 84357bddd21SDag-Erling Smørgrav #ifndef unbound_testbound 84457bddd21SDag-Erling Smørgrav if(log_get_lock()) { 8450eefd307SCy Schubert lock_basic_destroy((lock_basic_type*)log_get_lock()); 84657bddd21SDag-Erling Smørgrav } 84757bddd21SDag-Erling Smørgrav #endif 848b7579f77SDag-Erling Smørgrav return 0; 849b7579f77SDag-Erling Smørgrav } 850