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 70b7579f77SDag-Erling Smørgrav 7117d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S 7217d15b25SDag-Erling Smørgrav /* splint chokes on this system header file */ 73b7579f77SDag-Erling Smørgrav #ifdef HAVE_SYS_RESOURCE_H 74b7579f77SDag-Erling Smørgrav #include <sys/resource.h> 75b7579f77SDag-Erling Smørgrav #endif 7617d15b25SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 77b7579f77SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP_H 78b7579f77SDag-Erling Smørgrav #include <login_cap.h> 79b7579f77SDag-Erling Smørgrav #endif 80b7579f77SDag-Erling Smørgrav 81b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 82b7579f77SDag-Erling Smørgrav # include "winrc/win_svc.h" 83b7579f77SDag-Erling Smørgrav #endif 84b7579f77SDag-Erling Smørgrav 858ed2b524SDag-Erling Smørgrav #ifdef HAVE_NSS 868ed2b524SDag-Erling Smørgrav /* nss3 */ 878ed2b524SDag-Erling Smørgrav # include "nss.h" 888ed2b524SDag-Erling Smørgrav #endif 898ed2b524SDag-Erling Smørgrav 90b7579f77SDag-Erling Smørgrav /** print usage. */ 91b5663de9SDag-Erling Smørgrav static void usage(void) 92b7579f77SDag-Erling Smørgrav { 93b7579f77SDag-Erling Smørgrav const char** m; 94b7579f77SDag-Erling Smørgrav const char *evnm="event", *evsys="", *evmethod=""; 95b5663de9SDag-Erling Smørgrav time_t t; 96b5663de9SDag-Erling Smørgrav struct timeval now; 97b5663de9SDag-Erling Smørgrav struct ub_event_base* base; 98b70d78d6SDag-Erling Smørgrav printf("usage: local-unbound [options]\n"); 99b7579f77SDag-Erling Smørgrav printf(" start unbound daemon DNS resolver.\n"); 100b7579f77SDag-Erling Smørgrav printf("-h this help\n"); 101b7579f77SDag-Erling Smørgrav printf("-c file config file to read instead of %s\n", CONFIGFILE); 102b7579f77SDag-Erling Smørgrav printf(" file format is described in unbound.conf(5).\n"); 103b7579f77SDag-Erling Smørgrav printf("-d do not fork into the background.\n"); 104b7579f77SDag-Erling Smørgrav printf("-v verbose (more times to increase verbosity)\n"); 105b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 106b7579f77SDag-Erling Smørgrav printf("-w opt windows option: \n"); 107b7579f77SDag-Erling Smørgrav printf(" install, remove - manage the services entry\n"); 108b7579f77SDag-Erling Smørgrav printf(" service - used to start from services control panel\n"); 109b7579f77SDag-Erling Smørgrav #endif 110b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 111b5663de9SDag-Erling Smørgrav base = ub_default_event_base(0,&t,&now); 112b5663de9SDag-Erling Smørgrav ub_get_event_sys(base, &evnm, &evsys, &evmethod); 11317d15b25SDag-Erling Smørgrav printf("linked libs: %s %s (it uses %s), %s\n", 11417d15b25SDag-Erling Smørgrav evnm, evsys, evmethod, 1158ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 116b5663de9SDag-Erling Smørgrav # ifdef SSLEAY_VERSION 1178ed2b524SDag-Erling Smørgrav SSLeay_version(SSLEAY_VERSION) 118b5663de9SDag-Erling Smørgrav # else 119b5663de9SDag-Erling Smørgrav OpenSSL_version(OPENSSL_VERSION) 120b5663de9SDag-Erling Smørgrav # endif 1218ed2b524SDag-Erling Smørgrav #elif defined(HAVE_NSS) 1228ed2b524SDag-Erling Smørgrav NSS_GetVersion() 12305ab2901SDag-Erling Smørgrav #elif defined(HAVE_NETTLE) 12405ab2901SDag-Erling Smørgrav "nettle" 1258ed2b524SDag-Erling Smørgrav #endif 1268ed2b524SDag-Erling Smørgrav ); 127b7579f77SDag-Erling Smørgrav printf("linked modules:"); 128b7579f77SDag-Erling Smørgrav for(m = module_list_avail(); *m; m++) 129b7579f77SDag-Erling Smørgrav printf(" %s", *m); 130b7579f77SDag-Erling Smørgrav printf("\n"); 131971980c3SDag-Erling Smørgrav #ifdef USE_DNSCRYPT 132971980c3SDag-Erling Smørgrav printf("DNSCrypt feature available\n"); 133971980c3SDag-Erling Smørgrav #endif 134b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 135b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 136b5663de9SDag-Erling Smørgrav ub_event_base_free(base); 137b7579f77SDag-Erling Smørgrav } 138b7579f77SDag-Erling Smørgrav 139b7579f77SDag-Erling Smørgrav #ifndef unbound_testbound 140b7579f77SDag-Erling Smørgrav int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 141b7579f77SDag-Erling Smørgrav { 142b7579f77SDag-Erling Smørgrav log_assert(0); 143b7579f77SDag-Erling Smørgrav return 0; 144b7579f77SDag-Erling Smørgrav } 145b7579f77SDag-Erling Smørgrav #endif 146b7579f77SDag-Erling Smørgrav 147b7579f77SDag-Erling Smørgrav /** check file descriptor count */ 148b7579f77SDag-Erling Smørgrav static void 149b7579f77SDag-Erling Smørgrav checkrlimits(struct config_file* cfg) 150b7579f77SDag-Erling Smørgrav { 15117d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S 152b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETRLIMIT 153b7579f77SDag-Erling Smørgrav /* list has number of ports to listen to, ifs number addresses */ 154b7579f77SDag-Erling Smørgrav int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 + 155b7579f77SDag-Erling Smørgrav (int)cfg->incoming_num_tcp:0)); 156b7579f77SDag-Erling Smørgrav size_t listen_ifs = (size_t)(cfg->num_ifs==0? 157b7579f77SDag-Erling Smørgrav ((cfg->do_ip4 && !cfg->if_automatic?1:0) + 158b7579f77SDag-Erling Smørgrav (cfg->do_ip6?1:0)):cfg->num_ifs); 159b7579f77SDag-Erling Smørgrav size_t listen_num = list*listen_ifs; 160b7579f77SDag-Erling Smørgrav size_t outudpnum = (size_t)cfg->outgoing_num_ports; 161b7579f77SDag-Erling Smørgrav size_t outtcpnum = cfg->outgoing_num_tcp; 162b7579f77SDag-Erling Smørgrav size_t misc = 4; /* logfile, pidfile, stdout... */ 163b7579f77SDag-Erling Smørgrav size_t perthread_noudp = listen_num + outtcpnum + 164b7579f77SDag-Erling Smørgrav 2/*cmdpipe*/ + 2/*libevent*/ + misc; 165b7579f77SDag-Erling Smørgrav size_t perthread = perthread_noudp + outudpnum; 166b7579f77SDag-Erling Smørgrav 167b7579f77SDag-Erling Smørgrav #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) 168b7579f77SDag-Erling Smørgrav int numthread = 1; /* it forks */ 169b7579f77SDag-Erling Smørgrav #else 170b7579f77SDag-Erling Smørgrav int numthread = (cfg->num_threads?cfg->num_threads:1); 171b7579f77SDag-Erling Smørgrav #endif 172b7579f77SDag-Erling Smørgrav size_t total = numthread * perthread + misc; 173b7579f77SDag-Erling Smørgrav size_t avail; 174b7579f77SDag-Erling Smørgrav struct rlimit rlim; 175b7579f77SDag-Erling Smørgrav 176b7579f77SDag-Erling Smørgrav if(total > 1024 && 177e2d15004SDag-Erling Smørgrav strncmp(ub_event_get_version(), "mini-event", 10) == 0) { 178b7579f77SDag-Erling Smørgrav log_warn("too many file descriptors requested. The builtin" 179b7579f77SDag-Erling Smørgrav "mini-event cannot handle more than 1024. Config " 180b7579f77SDag-Erling Smørgrav "for less fds or compile with libevent"); 181b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > 1024) 182b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 183b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((1024 184b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 185b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 186b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 187b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 188b7579f77SDag-Erling Smørgrav total = 1024; 189b7579f77SDag-Erling Smørgrav } 190b7579f77SDag-Erling Smørgrav if(perthread > 64 && 191e2d15004SDag-Erling Smørgrav strncmp(ub_event_get_version(), "winsock-event", 13) == 0) { 192b7579f77SDag-Erling Smørgrav log_err("too many file descriptors requested. The winsock" 193b7579f77SDag-Erling Smørgrav " event handler cannot handle more than 64 per " 194b7579f77SDag-Erling Smørgrav " thread. Config for less fds"); 195b7579f77SDag-Erling Smørgrav if(perthread_noudp+2 > 64) 196b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 197b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((64 198b7579f77SDag-Erling Smørgrav - perthread_noudp 199b7579f77SDag-Erling Smørgrav - 2/* safety margin */)); 200b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 201b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 202b7579f77SDag-Erling Smørgrav total = numthread*(perthread_noudp+ 203b7579f77SDag-Erling Smørgrav (size_t)cfg->outgoing_num_ports)+misc; 204b7579f77SDag-Erling Smørgrav } 205b7579f77SDag-Erling Smørgrav if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 206b7579f77SDag-Erling Smørgrav log_warn("getrlimit: %s", strerror(errno)); 207b7579f77SDag-Erling Smørgrav return; 208b7579f77SDag-Erling Smørgrav } 209b7579f77SDag-Erling Smørgrav if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY) 210b7579f77SDag-Erling Smørgrav return; 211b7579f77SDag-Erling Smørgrav if((size_t)rlim.rlim_cur < total) { 212b7579f77SDag-Erling Smørgrav avail = (size_t)rlim.rlim_cur; 213b7579f77SDag-Erling Smørgrav rlim.rlim_cur = (rlim_t)(total + 10); 214b7579f77SDag-Erling Smørgrav rlim.rlim_max = (rlim_t)(total + 10); 215b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRLIMIT 216b7579f77SDag-Erling Smørgrav if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) { 217b7579f77SDag-Erling Smørgrav log_warn("setrlimit: %s", strerror(errno)); 218b7579f77SDag-Erling Smørgrav #endif 219b7579f77SDag-Erling Smørgrav log_warn("cannot increase max open fds from %u to %u", 220b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 221b7579f77SDag-Erling Smørgrav /* check that calculation below does not underflow, 222b7579f77SDag-Erling Smørgrav * with 15 as margin */ 223b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > avail) 224b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 225b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((avail 226b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 227b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 228b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 229b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 230b7579f77SDag-Erling Smørgrav log_warn("increase ulimit or decrease threads, " 231b7579f77SDag-Erling Smørgrav "ports in config to remove this warning"); 232b7579f77SDag-Erling Smørgrav return; 233ff825849SDag-Erling Smørgrav #ifdef HAVE_SETRLIMIT 234b7579f77SDag-Erling Smørgrav } 235ff825849SDag-Erling Smørgrav #endif 236ff825849SDag-Erling Smørgrav verbose(VERB_ALGO, "increased limit(open files) from %u to %u", 237b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 238b7579f77SDag-Erling Smørgrav } 239b7579f77SDag-Erling Smørgrav #else 240b7579f77SDag-Erling Smørgrav (void)cfg; 241b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETRLIMIT */ 24217d15b25SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 243b7579f77SDag-Erling Smørgrav } 244b7579f77SDag-Erling Smørgrav 245bc892140SDag-Erling Smørgrav /** set default logfile identity based on value from argv[0] at startup **/ 246bc892140SDag-Erling Smørgrav static void 247bc892140SDag-Erling Smørgrav log_ident_set_fromdefault(struct config_file* cfg, 248bc892140SDag-Erling Smørgrav const char *log_default_identity) 249bc892140SDag-Erling Smørgrav { 250bc892140SDag-Erling Smørgrav if(cfg->log_identity == NULL || cfg->log_identity[0] == 0) 251bc892140SDag-Erling Smørgrav log_ident_set(log_default_identity); 252bc892140SDag-Erling Smørgrav else 253bc892140SDag-Erling Smørgrav log_ident_set(cfg->log_identity); 254bc892140SDag-Erling Smørgrav } 255bc892140SDag-Erling Smørgrav 256b7579f77SDag-Erling Smørgrav /** set verbosity, check rlimits, cache settings */ 257b7579f77SDag-Erling Smørgrav static void 258b7579f77SDag-Erling Smørgrav apply_settings(struct daemon* daemon, struct config_file* cfg, 259bc892140SDag-Erling Smørgrav int cmdline_verbose, int debug_mode, const char* log_default_identity) 260b7579f77SDag-Erling Smørgrav { 261b7579f77SDag-Erling Smørgrav /* apply if they have changed */ 262b7579f77SDag-Erling Smørgrav verbosity = cmdline_verbose + cfg->verbosity; 263ff825849SDag-Erling Smørgrav if (debug_mode > 1) { 264ff825849SDag-Erling Smørgrav cfg->use_syslog = 0; 265bc892140SDag-Erling Smørgrav free(cfg->logfile); 266ff825849SDag-Erling Smørgrav cfg->logfile = NULL; 267ff825849SDag-Erling Smørgrav } 268b7579f77SDag-Erling Smørgrav daemon_apply_cfg(daemon, cfg); 269b7579f77SDag-Erling Smørgrav checkrlimits(cfg); 2703005e0a3SDag-Erling Smørgrav 2713005e0a3SDag-Erling Smørgrav if (cfg->use_systemd && cfg->do_daemonize) { 2723005e0a3SDag-Erling Smørgrav log_warn("use-systemd and do-daemonize should not be enabled at the same time"); 2733005e0a3SDag-Erling Smørgrav } 2743005e0a3SDag-Erling Smørgrav 275bc892140SDag-Erling Smørgrav log_ident_set_fromdefault(cfg, log_default_identity); 276b7579f77SDag-Erling Smørgrav } 277b7579f77SDag-Erling Smørgrav 278b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 279b7579f77SDag-Erling Smørgrav /** Read existing pid from pidfile. 280b7579f77SDag-Erling Smørgrav * @param file: file name of pid file. 281b7579f77SDag-Erling Smørgrav * @return: the pid from the file or -1 if none. 282b7579f77SDag-Erling Smørgrav */ 283b7579f77SDag-Erling Smørgrav static pid_t 284b7579f77SDag-Erling Smørgrav readpid (const char* file) 285b7579f77SDag-Erling Smørgrav { 286b7579f77SDag-Erling Smørgrav int fd; 287b7579f77SDag-Erling Smørgrav pid_t pid; 288b7579f77SDag-Erling Smørgrav char pidbuf[32]; 289b7579f77SDag-Erling Smørgrav char* t; 290b7579f77SDag-Erling Smørgrav ssize_t l; 291b7579f77SDag-Erling Smørgrav 292b7579f77SDag-Erling Smørgrav if ((fd = open(file, O_RDONLY)) == -1) { 293b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 294b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 295b7579f77SDag-Erling Smørgrav file, strerror(errno)); 296b7579f77SDag-Erling Smørgrav return -1; 297b7579f77SDag-Erling Smørgrav } 298b7579f77SDag-Erling Smørgrav 299b7579f77SDag-Erling Smørgrav if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) { 300b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 301b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 302b7579f77SDag-Erling Smørgrav file, strerror(errno)); 303b7579f77SDag-Erling Smørgrav close(fd); 304b7579f77SDag-Erling Smørgrav return -1; 305b7579f77SDag-Erling Smørgrav } 306b7579f77SDag-Erling Smørgrav 307b7579f77SDag-Erling Smørgrav close(fd); 308b7579f77SDag-Erling Smørgrav 309b7579f77SDag-Erling Smørgrav /* Empty pidfile means no pidfile... */ 310b7579f77SDag-Erling Smørgrav if (l == 0) { 311b7579f77SDag-Erling Smørgrav return -1; 312b7579f77SDag-Erling Smørgrav } 313b7579f77SDag-Erling Smørgrav 314b7579f77SDag-Erling Smørgrav pidbuf[sizeof(pidbuf)-1] = 0; 315b7579f77SDag-Erling Smørgrav pid = (pid_t)strtol(pidbuf, &t, 10); 316b7579f77SDag-Erling Smørgrav 317b7579f77SDag-Erling Smørgrav if (*t && *t != '\n') { 318b7579f77SDag-Erling Smørgrav return -1; 319b7579f77SDag-Erling Smørgrav } 320b7579f77SDag-Erling Smørgrav return pid; 321b7579f77SDag-Erling Smørgrav } 322b7579f77SDag-Erling Smørgrav 323b7579f77SDag-Erling Smørgrav /** write pid to file. 324b7579f77SDag-Erling Smørgrav * @param pidfile: file name of pid file. 325b7579f77SDag-Erling Smørgrav * @param pid: pid to write to file. 326b7579f77SDag-Erling Smørgrav */ 327b7579f77SDag-Erling Smørgrav static void 328b7579f77SDag-Erling Smørgrav writepid (const char* pidfile, pid_t pid) 329b7579f77SDag-Erling Smørgrav { 330b7579f77SDag-Erling Smørgrav FILE* f; 331b7579f77SDag-Erling Smørgrav 332b7579f77SDag-Erling Smørgrav if ((f = fopen(pidfile, "w")) == NULL ) { 333b7579f77SDag-Erling Smørgrav log_err("cannot open pidfile %s: %s", 334b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 335b7579f77SDag-Erling Smørgrav return; 336b7579f77SDag-Erling Smørgrav } 337b7579f77SDag-Erling Smørgrav if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) { 338b7579f77SDag-Erling Smørgrav log_err("cannot write to pidfile %s: %s", 339b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 340b7579f77SDag-Erling Smørgrav } 341b7579f77SDag-Erling Smørgrav fclose(f); 342b7579f77SDag-Erling Smørgrav } 343b7579f77SDag-Erling Smørgrav 344b7579f77SDag-Erling Smørgrav /** 345b7579f77SDag-Erling Smørgrav * check old pid file. 346b7579f77SDag-Erling Smørgrav * @param pidfile: the file name of the pid file. 347b7579f77SDag-Erling Smørgrav * @param inchroot: if pidfile is inchroot and we can thus expect to 348b7579f77SDag-Erling Smørgrav * be able to delete it. 349b7579f77SDag-Erling Smørgrav */ 350b7579f77SDag-Erling Smørgrav static void 351b7579f77SDag-Erling Smørgrav checkoldpid(char* pidfile, int inchroot) 352b7579f77SDag-Erling Smørgrav { 353b7579f77SDag-Erling Smørgrav pid_t old; 354b7579f77SDag-Erling Smørgrav if((old = readpid(pidfile)) != -1) { 355b7579f77SDag-Erling Smørgrav /* see if it is still alive */ 356b7579f77SDag-Erling Smørgrav if(kill(old, 0) == 0 || errno == EPERM) 357b7579f77SDag-Erling Smørgrav log_warn("unbound is already running as pid %u.", 358b7579f77SDag-Erling Smørgrav (unsigned)old); 359b7579f77SDag-Erling Smørgrav else if(inchroot) 360b7579f77SDag-Erling Smørgrav log_warn("did not exit gracefully last time (%u)", 361b7579f77SDag-Erling Smørgrav (unsigned)old); 362b7579f77SDag-Erling Smørgrav } 363b7579f77SDag-Erling Smørgrav } 364b7579f77SDag-Erling Smørgrav #endif /* HAVE_KILL */ 365b7579f77SDag-Erling Smørgrav 366b7579f77SDag-Erling Smørgrav /** detach from command line */ 367b7579f77SDag-Erling Smørgrav static void 368b7579f77SDag-Erling Smørgrav detach(void) 369b7579f77SDag-Erling Smørgrav { 370b7579f77SDag-Erling Smørgrav #if defined(HAVE_DAEMON) && !defined(DEPRECATED_DAEMON) 371b7579f77SDag-Erling Smørgrav /* use POSIX daemon(3) function */ 372b7579f77SDag-Erling Smørgrav if(daemon(1, 0) != 0) 373b7579f77SDag-Erling Smørgrav fatal_exit("daemon failed: %s", strerror(errno)); 374b7579f77SDag-Erling Smørgrav #else /* no HAVE_DAEMON */ 375b7579f77SDag-Erling Smørgrav #ifdef HAVE_FORK 376b7579f77SDag-Erling Smørgrav int fd; 377b7579f77SDag-Erling Smørgrav /* Take off... */ 378b7579f77SDag-Erling Smørgrav switch (fork()) { 379b7579f77SDag-Erling Smørgrav case 0: 380b7579f77SDag-Erling Smørgrav break; 381b7579f77SDag-Erling Smørgrav case -1: 382b7579f77SDag-Erling Smørgrav fatal_exit("fork failed: %s", strerror(errno)); 383b7579f77SDag-Erling Smørgrav default: 384b7579f77SDag-Erling Smørgrav /* exit interactive session */ 385b7579f77SDag-Erling Smørgrav exit(0); 386b7579f77SDag-Erling Smørgrav } 387b7579f77SDag-Erling Smørgrav /* detach */ 388b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETSID 389b7579f77SDag-Erling Smørgrav if(setsid() == -1) 390b7579f77SDag-Erling Smørgrav fatal_exit("setsid() failed: %s", strerror(errno)); 391b7579f77SDag-Erling Smørgrav #endif 392b7579f77SDag-Erling Smørgrav if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { 393b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDIN_FILENO); 394b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDOUT_FILENO); 395b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDERR_FILENO); 396b7579f77SDag-Erling Smørgrav if (fd > 2) 397b7579f77SDag-Erling Smørgrav (void)close(fd); 398b7579f77SDag-Erling Smørgrav } 399b7579f77SDag-Erling Smørgrav #endif /* HAVE_FORK */ 400b7579f77SDag-Erling Smørgrav #endif /* HAVE_DAEMON */ 401b7579f77SDag-Erling Smørgrav } 402b7579f77SDag-Erling Smørgrav 4038a384985SDag-Erling Smørgrav /** daemonize, drop user privileges and chroot if needed */ 404b7579f77SDag-Erling Smørgrav static void 405b7579f77SDag-Erling Smørgrav perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, 406971980c3SDag-Erling Smørgrav const char** cfgfile, int need_pidfile) 407b7579f77SDag-Erling Smørgrav { 408f61ef7f6SDag-Erling Smørgrav #ifdef HAVE_KILL 409f61ef7f6SDag-Erling Smørgrav int pidinchroot; 410f61ef7f6SDag-Erling Smørgrav #endif 411b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 412b7579f77SDag-Erling Smørgrav struct passwd *pwd = NULL; 413b7579f77SDag-Erling Smørgrav 414b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 415b7579f77SDag-Erling Smørgrav if((pwd = getpwnam(cfg->username)) == NULL) 416b7579f77SDag-Erling Smørgrav fatal_exit("user '%s' does not exist.", cfg->username); 417b7579f77SDag-Erling Smørgrav /* endpwent below, in case we need pwd for setusercontext */ 418b7579f77SDag-Erling Smørgrav } 419b7579f77SDag-Erling Smørgrav #endif 42005ab2901SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 42105ab2901SDag-Erling Smørgrav w_config_adjust_directory(cfg); 42205ab2901SDag-Erling Smørgrav #endif 423b7579f77SDag-Erling Smørgrav 42457bddd21SDag-Erling Smørgrav /* read ssl keys while superuser and outside chroot */ 42557bddd21SDag-Erling Smørgrav #ifdef HAVE_SSL 42657bddd21SDag-Erling Smørgrav if(!(daemon->rc = daemon_remote_create(cfg))) 42757bddd21SDag-Erling Smørgrav fatal_exit("could not set up remote-control"); 42857bddd21SDag-Erling Smørgrav if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { 42957bddd21SDag-Erling Smørgrav if(!(daemon->listen_sslctx = listen_sslctx_create( 43057bddd21SDag-Erling Smørgrav cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) 43157bddd21SDag-Erling Smørgrav fatal_exit("could not set up listen SSL_CTX"); 43257bddd21SDag-Erling Smørgrav } 43357bddd21SDag-Erling Smørgrav if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, 434*3bd4df0aSDag-Erling Smørgrav cfg->tls_cert_bundle, cfg->tls_win_cert))) 43557bddd21SDag-Erling Smørgrav fatal_exit("could not set up connect SSL_CTX"); 43657bddd21SDag-Erling Smørgrav #endif 43757bddd21SDag-Erling Smørgrav 438b7579f77SDag-Erling Smørgrav /* init syslog (as root) if needed, before daemonize, otherwise 439b7579f77SDag-Erling Smørgrav * a fork error could not be printed since daemonize closed stderr.*/ 440b7579f77SDag-Erling Smørgrav if(cfg->use_syslog) { 441b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 442b7579f77SDag-Erling Smørgrav } 443b7579f77SDag-Erling Smørgrav /* if using a logfile, we cannot open it because the logfile would 444b7579f77SDag-Erling Smørgrav * be created with the wrong permissions, we cannot chown it because 445b7579f77SDag-Erling Smørgrav * we cannot chown system logfiles, so we do not open at all. 446b7579f77SDag-Erling Smørgrav * So, using a logfile, the user does not see errors unless -d is 447b7579f77SDag-Erling Smørgrav * given to unbound on the commandline. */ 448b7579f77SDag-Erling Smørgrav 449b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 450f61ef7f6SDag-Erling Smørgrav /* true if pidfile is inside chrootdir, or nochroot */ 451971980c3SDag-Erling Smørgrav pidinchroot = need_pidfile && (!(cfg->chrootdir && cfg->chrootdir[0]) || 452f61ef7f6SDag-Erling Smørgrav (cfg->chrootdir && cfg->chrootdir[0] && 453f61ef7f6SDag-Erling Smørgrav strncmp(cfg->pidfile, cfg->chrootdir, 454971980c3SDag-Erling Smørgrav strlen(cfg->chrootdir))==0)); 455f61ef7f6SDag-Erling Smørgrav 456b7579f77SDag-Erling Smørgrav /* check old pid file before forking */ 457971980c3SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) { 458b7579f77SDag-Erling Smørgrav /* calculate position of pidfile */ 459b7579f77SDag-Erling Smørgrav if(cfg->pidfile[0] == '/') 460b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(cfg->pidfile); 461b7579f77SDag-Erling Smørgrav else daemon->pidfile = fname_after_chroot(cfg->pidfile, 462b7579f77SDag-Erling Smørgrav cfg, 1); 463b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 464b7579f77SDag-Erling Smørgrav fatal_exit("pidfile alloc: out of memory"); 465f61ef7f6SDag-Erling Smørgrav checkoldpid(daemon->pidfile, pidinchroot); 466b7579f77SDag-Erling Smørgrav } 467b7579f77SDag-Erling Smørgrav #endif 468b7579f77SDag-Erling Smørgrav 469b7579f77SDag-Erling Smørgrav /* daemonize because pid is needed by the writepid func */ 470b7579f77SDag-Erling Smørgrav if(!debug_mode && cfg->do_daemonize) { 471b7579f77SDag-Erling Smørgrav detach(); 472b7579f77SDag-Erling Smørgrav } 473b7579f77SDag-Erling Smørgrav 474b7579f77SDag-Erling Smørgrav /* write new pidfile (while still root, so can be outside chroot) */ 475b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 476971980c3SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0] && need_pidfile) { 477b7579f77SDag-Erling Smørgrav writepid(daemon->pidfile, getpid()); 478f61ef7f6SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 && 479f61ef7f6SDag-Erling Smørgrav pidinchroot) { 4806480faa8SDag-Erling Smørgrav # ifdef HAVE_CHOWN 4816480faa8SDag-Erling Smørgrav if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) { 482f61ef7f6SDag-Erling Smørgrav verbose(VERB_QUERY, "cannot chown %u.%u %s: %s", 4836480faa8SDag-Erling Smørgrav (unsigned)cfg_uid, (unsigned)cfg_gid, 484b7579f77SDag-Erling Smørgrav daemon->pidfile, strerror(errno)); 485b7579f77SDag-Erling Smørgrav } 4866480faa8SDag-Erling Smørgrav # endif /* HAVE_CHOWN */ 487b7579f77SDag-Erling Smørgrav } 488b7579f77SDag-Erling Smørgrav } 489b7579f77SDag-Erling Smørgrav #else 490b7579f77SDag-Erling Smørgrav (void)daemon; 491971980c3SDag-Erling Smørgrav (void)need_pidfile; 4926480faa8SDag-Erling Smørgrav #endif /* HAVE_KILL */ 493b7579f77SDag-Erling Smørgrav 494b7579f77SDag-Erling Smørgrav /* Set user context */ 495b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 4966480faa8SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { 497b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETUSERCONTEXT 498b7579f77SDag-Erling Smørgrav /* setusercontext does initgroups, setuid, setgid, and 499b7579f77SDag-Erling Smørgrav * also resource limits from login config, but we 500b7579f77SDag-Erling Smørgrav * still call setresuid, setresgid to be sure to set all uid*/ 5016480faa8SDag-Erling Smørgrav if(setusercontext(NULL, pwd, cfg_uid, (unsigned) 502b7579f77SDag-Erling Smørgrav LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) 503b7579f77SDag-Erling Smørgrav log_warn("unable to setusercontext %s: %s", 504b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 505b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETUSERCONTEXT */ 506b7579f77SDag-Erling Smørgrav } 507b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 508b7579f77SDag-Erling Smørgrav 509b7579f77SDag-Erling Smørgrav /* box into the chroot */ 510b7579f77SDag-Erling Smørgrav #ifdef HAVE_CHROOT 511b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0]) { 512b7579f77SDag-Erling Smørgrav if(chdir(cfg->chrootdir)) { 513b7579f77SDag-Erling Smørgrav fatal_exit("unable to chdir to chroot %s: %s", 514b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 515b7579f77SDag-Erling Smørgrav } 516b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", cfg->chrootdir); 517b7579f77SDag-Erling Smørgrav if(chroot(cfg->chrootdir)) 518b7579f77SDag-Erling Smørgrav fatal_exit("unable to chroot to %s: %s", 519b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 5208ed2b524SDag-Erling Smørgrav if(chdir("/")) 5218ed2b524SDag-Erling Smørgrav fatal_exit("unable to chdir to / in chroot %s: %s", 5228ed2b524SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 523b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir); 524b7579f77SDag-Erling Smørgrav if(strncmp(*cfgfile, cfg->chrootdir, 525b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 526b7579f77SDag-Erling Smørgrav (*cfgfile) += strlen(cfg->chrootdir); 527b7579f77SDag-Erling Smørgrav 528b7579f77SDag-Erling Smørgrav /* adjust stored pidfile for chroot */ 529b7579f77SDag-Erling Smørgrav if(daemon->pidfile && daemon->pidfile[0] && 530b7579f77SDag-Erling Smørgrav strncmp(daemon->pidfile, cfg->chrootdir, 531b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir))==0) { 532b7579f77SDag-Erling Smørgrav char* old = daemon->pidfile; 533b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(old+strlen(cfg->chrootdir)); 534b7579f77SDag-Erling Smørgrav free(old); 535b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 536b7579f77SDag-Erling Smørgrav log_err("out of memory in pidfile adjust"); 537b7579f77SDag-Erling Smørgrav } 538b7579f77SDag-Erling Smørgrav daemon->chroot = strdup(cfg->chrootdir); 539b7579f77SDag-Erling Smørgrav if(!daemon->chroot) 540b7579f77SDag-Erling Smørgrav log_err("out of memory in daemon chroot dir storage"); 541b7579f77SDag-Erling Smørgrav } 542b7579f77SDag-Erling Smørgrav #else 543b7579f77SDag-Erling Smørgrav (void)cfgfile; 544b7579f77SDag-Erling Smørgrav #endif 545b7579f77SDag-Erling Smørgrav /* change to working directory inside chroot */ 546b7579f77SDag-Erling Smørgrav if(cfg->directory && cfg->directory[0]) { 547b7579f77SDag-Erling Smørgrav char* dir = cfg->directory; 548b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0] && 549b7579f77SDag-Erling Smørgrav strncmp(dir, cfg->chrootdir, 550b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 551b7579f77SDag-Erling Smørgrav dir += strlen(cfg->chrootdir); 552b7579f77SDag-Erling Smørgrav if(dir[0]) { 553b7579f77SDag-Erling Smørgrav if(chdir(dir)) { 554b7579f77SDag-Erling Smørgrav fatal_exit("Could not chdir to %s: %s", 555b7579f77SDag-Erling Smørgrav dir, strerror(errno)); 556b7579f77SDag-Erling Smørgrav } 557b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", dir); 558b7579f77SDag-Erling Smørgrav } 559b7579f77SDag-Erling Smørgrav } 560b7579f77SDag-Erling Smørgrav 561b7579f77SDag-Erling Smørgrav /* drop permissions after chroot, getpwnam, pidfile, syslog done*/ 562b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 5636480faa8SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { 564b7579f77SDag-Erling Smørgrav # ifdef HAVE_INITGROUPS 5656480faa8SDag-Erling Smørgrav if(initgroups(cfg->username, cfg_gid) != 0) 566b7579f77SDag-Erling Smørgrav log_warn("unable to initgroups %s: %s", 567b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 568b7579f77SDag-Erling Smørgrav # endif /* HAVE_INITGROUPS */ 569b5663de9SDag-Erling Smørgrav # ifdef HAVE_ENDPWENT 570b7579f77SDag-Erling Smørgrav endpwent(); 571b5663de9SDag-Erling Smørgrav # endif 572b7579f77SDag-Erling Smørgrav 573b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESGID 5746480faa8SDag-Erling Smørgrav if(setresgid(cfg_gid,cfg_gid,cfg_gid) != 0) 575b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) 5766480faa8SDag-Erling Smørgrav if(setregid(cfg_gid,cfg_gid) != 0) 577b7579f77SDag-Erling Smørgrav #else /* use setgid */ 5786480faa8SDag-Erling Smørgrav if(setgid(cfg_gid) != 0) 579b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESGID */ 580b7579f77SDag-Erling Smørgrav fatal_exit("unable to set group id of %s: %s", 581b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 582b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESUID 5836480faa8SDag-Erling Smørgrav if(setresuid(cfg_uid,cfg_uid,cfg_uid) != 0) 584b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) 5856480faa8SDag-Erling Smørgrav if(setreuid(cfg_uid,cfg_uid) != 0) 586b7579f77SDag-Erling Smørgrav #else /* use setuid */ 5876480faa8SDag-Erling Smørgrav if(setuid(cfg_uid) != 0) 588b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESUID */ 589b7579f77SDag-Erling Smørgrav fatal_exit("unable to set user id of %s: %s", 590b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 591b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "drop user privileges, run as %s", 592b7579f77SDag-Erling Smørgrav cfg->username); 593b7579f77SDag-Erling Smørgrav } 594b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 595b7579f77SDag-Erling Smørgrav /* file logging inited after chroot,chdir,setuid is done so that 596b7579f77SDag-Erling Smørgrav * it would succeed on SIGHUP as well */ 597b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 598b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 599b7579f77SDag-Erling Smørgrav } 600b7579f77SDag-Erling Smørgrav 601b7579f77SDag-Erling Smørgrav /** 602b7579f77SDag-Erling Smørgrav * Run the daemon. 603b7579f77SDag-Erling Smørgrav * @param cfgfile: the config file name. 604b7579f77SDag-Erling Smørgrav * @param cmdline_verbose: verbosity resulting from commandline -v. 605b7579f77SDag-Erling Smørgrav * These increase verbosity as specified in the config file. 606b7579f77SDag-Erling Smørgrav * @param debug_mode: if set, do not daemonize. 607bc892140SDag-Erling Smørgrav * @param log_default_identity: Default identity to report in logs 608971980c3SDag-Erling Smørgrav * @param need_pidfile: if false, no pidfile is checked or created. 609b7579f77SDag-Erling Smørgrav */ 610b7579f77SDag-Erling Smørgrav static void 611971980c3SDag-Erling Smørgrav run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode, const char* log_default_identity, int need_pidfile) 612b7579f77SDag-Erling Smørgrav { 613b7579f77SDag-Erling Smørgrav struct config_file* cfg = NULL; 614b7579f77SDag-Erling Smørgrav struct daemon* daemon = NULL; 615b7579f77SDag-Erling Smørgrav int done_setup = 0; 616b7579f77SDag-Erling Smørgrav 617b7579f77SDag-Erling Smørgrav if(!(daemon = daemon_init())) 618b7579f77SDag-Erling Smørgrav fatal_exit("alloc failure"); 619b7579f77SDag-Erling Smørgrav while(!daemon->need_to_exit) { 620b7579f77SDag-Erling Smørgrav if(done_setup) 621b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING); 622b7579f77SDag-Erling Smørgrav else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING); 623b7579f77SDag-Erling Smørgrav 624b7579f77SDag-Erling Smørgrav /* config stuff */ 625b7579f77SDag-Erling Smørgrav if(!(cfg = config_create())) 626b7579f77SDag-Erling Smørgrav fatal_exit("Could not alloc config defaults"); 627b7579f77SDag-Erling Smørgrav if(!config_read(cfg, cfgfile, daemon->chroot)) { 628b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 629b7579f77SDag-Erling Smørgrav fatal_exit("Could not read config file: %s", 630b7579f77SDag-Erling Smørgrav cfgfile); 631b7579f77SDag-Erling Smørgrav log_warn("Continuing with default config settings"); 632b7579f77SDag-Erling Smørgrav } 633bc892140SDag-Erling Smørgrav apply_settings(daemon, cfg, cmdline_verbose, debug_mode, log_default_identity); 6346480faa8SDag-Erling Smørgrav if(!done_setup) 635748bd829SDag-Erling Smørgrav config_lookup_uid(cfg); 636b7579f77SDag-Erling Smørgrav 637b7579f77SDag-Erling Smørgrav /* prepare */ 638b7579f77SDag-Erling Smørgrav if(!daemon_open_shared_ports(daemon)) 639b7579f77SDag-Erling Smørgrav fatal_exit("could not open ports"); 640b7579f77SDag-Erling Smørgrav if(!done_setup) { 641971980c3SDag-Erling Smørgrav perform_setup(daemon, cfg, debug_mode, &cfgfile, need_pidfile); 642b7579f77SDag-Erling Smørgrav done_setup = 1; 643b7579f77SDag-Erling Smørgrav } else { 644b7579f77SDag-Erling Smørgrav /* reopen log after HUP to facilitate log rotation */ 645b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 646b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, 0, cfg->chrootdir); 647b7579f77SDag-Erling Smørgrav } 648b7579f77SDag-Erling Smørgrav /* work */ 649b7579f77SDag-Erling Smørgrav daemon_fork(daemon); 650b7579f77SDag-Erling Smørgrav 651b7579f77SDag-Erling Smørgrav /* clean up for restart */ 652b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "cleanup."); 653b7579f77SDag-Erling Smørgrav daemon_cleanup(daemon); 654b7579f77SDag-Erling Smørgrav config_delete(cfg); 655b7579f77SDag-Erling Smørgrav } 656b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Exit cleanup."); 657b7579f77SDag-Erling Smørgrav /* this unlink may not work if the pidfile is located outside 658b7579f77SDag-Erling Smørgrav * of the chroot/workdir or we no longer have permissions */ 659b7579f77SDag-Erling Smørgrav if(daemon->pidfile) { 660b7579f77SDag-Erling Smørgrav int fd; 661b7579f77SDag-Erling Smørgrav /* truncate pidfile */ 662b7579f77SDag-Erling Smørgrav fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644); 663b7579f77SDag-Erling Smørgrav if(fd != -1) 664b7579f77SDag-Erling Smørgrav close(fd); 665b7579f77SDag-Erling Smørgrav /* delete pidfile */ 666b7579f77SDag-Erling Smørgrav unlink(daemon->pidfile); 667b7579f77SDag-Erling Smørgrav } 668b7579f77SDag-Erling Smørgrav daemon_delete(daemon); 669b7579f77SDag-Erling Smørgrav } 670b7579f77SDag-Erling Smørgrav 671b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 672b7579f77SDag-Erling Smørgrav extern int optind; 673b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 674b7579f77SDag-Erling Smørgrav extern char* optarg; 675b7579f77SDag-Erling Smørgrav 676b7579f77SDag-Erling Smørgrav /** 677b7579f77SDag-Erling Smørgrav * main program. Set options given commandline arguments. 678b7579f77SDag-Erling Smørgrav * @param argc: number of commandline arguments. 679b7579f77SDag-Erling Smørgrav * @param argv: array of commandline arguments. 680b7579f77SDag-Erling Smørgrav * @return: exit status of the program. 681b7579f77SDag-Erling Smørgrav */ 682b7579f77SDag-Erling Smørgrav int 683b7579f77SDag-Erling Smørgrav main(int argc, char* argv[]) 684b7579f77SDag-Erling Smørgrav { 685b7579f77SDag-Erling Smørgrav int c; 686b7579f77SDag-Erling Smørgrav const char* cfgfile = CONFIGFILE; 687b7579f77SDag-Erling Smørgrav const char* winopt = NULL; 688bc892140SDag-Erling Smørgrav const char* log_ident_default; 689b7579f77SDag-Erling Smørgrav int cmdline_verbose = 0; 690b7579f77SDag-Erling Smørgrav int debug_mode = 0; 691971980c3SDag-Erling Smørgrav int need_pidfile = 1; 692971980c3SDag-Erling Smørgrav 693b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 694b7579f77SDag-Erling Smørgrav int cmdline_cfg = 0; 695b7579f77SDag-Erling Smørgrav #endif 696b7579f77SDag-Erling Smørgrav 697b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); 698bc892140SDag-Erling Smørgrav log_ident_default = strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]; 699bc892140SDag-Erling Smørgrav log_ident_set(log_ident_default); 700b7579f77SDag-Erling Smørgrav /* parse the options */ 701971980c3SDag-Erling Smørgrav while( (c=getopt(argc, argv, "c:dhpvw:")) != -1) { 702b7579f77SDag-Erling Smørgrav switch(c) { 703b7579f77SDag-Erling Smørgrav case 'c': 704b7579f77SDag-Erling Smørgrav cfgfile = optarg; 705b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 706b7579f77SDag-Erling Smørgrav cmdline_cfg = 1; 707b7579f77SDag-Erling Smørgrav #endif 708b7579f77SDag-Erling Smørgrav break; 709b7579f77SDag-Erling Smørgrav case 'v': 710b7579f77SDag-Erling Smørgrav cmdline_verbose++; 711b7579f77SDag-Erling Smørgrav verbosity++; 712b7579f77SDag-Erling Smørgrav break; 713971980c3SDag-Erling Smørgrav case 'p': 714971980c3SDag-Erling Smørgrav need_pidfile = 0; 715971980c3SDag-Erling Smørgrav break; 716b7579f77SDag-Erling Smørgrav case 'd': 717ff825849SDag-Erling Smørgrav debug_mode++; 718b7579f77SDag-Erling Smørgrav break; 719b7579f77SDag-Erling Smørgrav case 'w': 720b7579f77SDag-Erling Smørgrav winopt = optarg; 721b7579f77SDag-Erling Smørgrav break; 722b7579f77SDag-Erling Smørgrav case '?': 723b7579f77SDag-Erling Smørgrav case 'h': 724b7579f77SDag-Erling Smørgrav default: 725b7579f77SDag-Erling Smørgrav usage(); 726b7579f77SDag-Erling Smørgrav return 1; 727b7579f77SDag-Erling Smørgrav } 728b7579f77SDag-Erling Smørgrav } 729b7579f77SDag-Erling Smørgrav argc -= optind; 730b7579f77SDag-Erling Smørgrav argv += optind; 731b7579f77SDag-Erling Smørgrav 732b7579f77SDag-Erling Smørgrav if(winopt) { 733b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 734b7579f77SDag-Erling Smørgrav wsvc_command_option(winopt, cfgfile, cmdline_verbose, 735b7579f77SDag-Erling Smørgrav cmdline_cfg); 736b7579f77SDag-Erling Smørgrav #else 737b7579f77SDag-Erling Smørgrav fatal_exit("option not supported"); 738b7579f77SDag-Erling Smørgrav #endif 739b7579f77SDag-Erling Smørgrav } 740b7579f77SDag-Erling Smørgrav 741b7579f77SDag-Erling Smørgrav if(argc != 0) { 742b7579f77SDag-Erling Smørgrav usage(); 743b7579f77SDag-Erling Smørgrav return 1; 744b7579f77SDag-Erling Smørgrav } 745b7579f77SDag-Erling Smørgrav 746971980c3SDag-Erling Smørgrav run_daemon(cfgfile, cmdline_verbose, debug_mode, log_ident_default, need_pidfile); 747b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); /* close logfile */ 74857bddd21SDag-Erling Smørgrav #ifndef unbound_testbound 74957bddd21SDag-Erling Smørgrav if(log_get_lock()) { 75057bddd21SDag-Erling Smørgrav lock_quick_destroy((lock_quick_type*)log_get_lock()); 75157bddd21SDag-Erling Smørgrav } 75257bddd21SDag-Erling Smørgrav #endif 753b7579f77SDag-Erling Smørgrav return 0; 754b7579f77SDag-Erling Smørgrav } 755