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 9004b59eacSDag-Erling Smørgrav #ifdef HAVE_SBRK 91b7579f77SDag-Erling Smørgrav /** global debug value to keep track of heap memory allocation */ 92b7579f77SDag-Erling Smørgrav void* unbound_start_brk = 0; 9304b59eacSDag-Erling Smørgrav #endif 94b7579f77SDag-Erling Smørgrav 95b7579f77SDag-Erling Smørgrav /** print usage. */ 96*b5663de9SDag-Erling Smørgrav static void usage(void) 97b7579f77SDag-Erling Smørgrav { 98b7579f77SDag-Erling Smørgrav const char** m; 99b7579f77SDag-Erling Smørgrav const char *evnm="event", *evsys="", *evmethod=""; 100*b5663de9SDag-Erling Smørgrav time_t t; 101*b5663de9SDag-Erling Smørgrav struct timeval now; 102*b5663de9SDag-Erling Smørgrav struct ub_event_base* base; 103b7579f77SDag-Erling Smørgrav printf("usage: unbound [options]\n"); 104b7579f77SDag-Erling Smørgrav printf(" start unbound daemon DNS resolver.\n"); 105b7579f77SDag-Erling Smørgrav printf("-h this help\n"); 106b7579f77SDag-Erling Smørgrav printf("-c file config file to read instead of %s\n", CONFIGFILE); 107b7579f77SDag-Erling Smørgrav printf(" file format is described in unbound.conf(5).\n"); 108b7579f77SDag-Erling Smørgrav printf("-d do not fork into the background.\n"); 109b7579f77SDag-Erling Smørgrav printf("-v verbose (more times to increase verbosity)\n"); 110b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 111b7579f77SDag-Erling Smørgrav printf("-w opt windows option: \n"); 112b7579f77SDag-Erling Smørgrav printf(" install, remove - manage the services entry\n"); 113b7579f77SDag-Erling Smørgrav printf(" service - used to start from services control panel\n"); 114b7579f77SDag-Erling Smørgrav #endif 115b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 116*b5663de9SDag-Erling Smørgrav base = ub_default_event_base(0,&t,&now); 117*b5663de9SDag-Erling Smørgrav ub_get_event_sys(base, &evnm, &evsys, &evmethod); 11817d15b25SDag-Erling Smørgrav printf("linked libs: %s %s (it uses %s), %s\n", 11917d15b25SDag-Erling Smørgrav evnm, evsys, evmethod, 1208ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 121*b5663de9SDag-Erling Smørgrav # ifdef SSLEAY_VERSION 1228ed2b524SDag-Erling Smørgrav SSLeay_version(SSLEAY_VERSION) 123*b5663de9SDag-Erling Smørgrav # else 124*b5663de9SDag-Erling Smørgrav OpenSSL_version(OPENSSL_VERSION) 125*b5663de9SDag-Erling Smørgrav # endif 1268ed2b524SDag-Erling Smørgrav #elif defined(HAVE_NSS) 1278ed2b524SDag-Erling Smørgrav NSS_GetVersion() 12805ab2901SDag-Erling Smørgrav #elif defined(HAVE_NETTLE) 12905ab2901SDag-Erling Smørgrav "nettle" 1308ed2b524SDag-Erling Smørgrav #endif 1318ed2b524SDag-Erling Smørgrav ); 132b7579f77SDag-Erling Smørgrav printf("linked modules:"); 133b7579f77SDag-Erling Smørgrav for(m = module_list_avail(); *m; m++) 134b7579f77SDag-Erling Smørgrav printf(" %s", *m); 135b7579f77SDag-Erling Smørgrav printf("\n"); 136b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 137b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 138*b5663de9SDag-Erling Smørgrav ub_event_base_free(base); 139b7579f77SDag-Erling Smørgrav } 140b7579f77SDag-Erling Smørgrav 141b7579f77SDag-Erling Smørgrav #ifndef unbound_testbound 142b7579f77SDag-Erling Smørgrav int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 143b7579f77SDag-Erling Smørgrav { 144b7579f77SDag-Erling Smørgrav log_assert(0); 145b7579f77SDag-Erling Smørgrav return 0; 146b7579f77SDag-Erling Smørgrav } 147b7579f77SDag-Erling Smørgrav #endif 148b7579f77SDag-Erling Smørgrav 149b7579f77SDag-Erling Smørgrav /** check file descriptor count */ 150b7579f77SDag-Erling Smørgrav static void 151b7579f77SDag-Erling Smørgrav checkrlimits(struct config_file* cfg) 152b7579f77SDag-Erling Smørgrav { 15317d15b25SDag-Erling Smørgrav #ifndef S_SPLINT_S 154b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETRLIMIT 155b7579f77SDag-Erling Smørgrav /* list has number of ports to listen to, ifs number addresses */ 156b7579f77SDag-Erling Smørgrav int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 + 157b7579f77SDag-Erling Smørgrav (int)cfg->incoming_num_tcp:0)); 158b7579f77SDag-Erling Smørgrav size_t listen_ifs = (size_t)(cfg->num_ifs==0? 159b7579f77SDag-Erling Smørgrav ((cfg->do_ip4 && !cfg->if_automatic?1:0) + 160b7579f77SDag-Erling Smørgrav (cfg->do_ip6?1:0)):cfg->num_ifs); 161b7579f77SDag-Erling Smørgrav size_t listen_num = list*listen_ifs; 162b7579f77SDag-Erling Smørgrav size_t outudpnum = (size_t)cfg->outgoing_num_ports; 163b7579f77SDag-Erling Smørgrav size_t outtcpnum = cfg->outgoing_num_tcp; 164b7579f77SDag-Erling Smørgrav size_t misc = 4; /* logfile, pidfile, stdout... */ 165b7579f77SDag-Erling Smørgrav size_t perthread_noudp = listen_num + outtcpnum + 166b7579f77SDag-Erling Smørgrav 2/*cmdpipe*/ + 2/*libevent*/ + misc; 167b7579f77SDag-Erling Smørgrav size_t perthread = perthread_noudp + outudpnum; 168b7579f77SDag-Erling Smørgrav 169b7579f77SDag-Erling Smørgrav #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) 170b7579f77SDag-Erling Smørgrav int numthread = 1; /* it forks */ 171b7579f77SDag-Erling Smørgrav #else 172b7579f77SDag-Erling Smørgrav int numthread = (cfg->num_threads?cfg->num_threads:1); 173b7579f77SDag-Erling Smørgrav #endif 174b7579f77SDag-Erling Smørgrav size_t total = numthread * perthread + misc; 175b7579f77SDag-Erling Smørgrav size_t avail; 176b7579f77SDag-Erling Smørgrav struct rlimit rlim; 177b7579f77SDag-Erling Smørgrav 178b7579f77SDag-Erling Smørgrav if(total > 1024 && 179e2d15004SDag-Erling Smørgrav strncmp(ub_event_get_version(), "mini-event", 10) == 0) { 180b7579f77SDag-Erling Smørgrav log_warn("too many file descriptors requested. The builtin" 181b7579f77SDag-Erling Smørgrav "mini-event cannot handle more than 1024. Config " 182b7579f77SDag-Erling Smørgrav "for less fds or compile with libevent"); 183b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > 1024) 184b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 185b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((1024 186b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 187b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 188b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 189b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 190b7579f77SDag-Erling Smørgrav total = 1024; 191b7579f77SDag-Erling Smørgrav } 192b7579f77SDag-Erling Smørgrav if(perthread > 64 && 193e2d15004SDag-Erling Smørgrav strncmp(ub_event_get_version(), "winsock-event", 13) == 0) { 194b7579f77SDag-Erling Smørgrav log_err("too many file descriptors requested. The winsock" 195b7579f77SDag-Erling Smørgrav " event handler cannot handle more than 64 per " 196b7579f77SDag-Erling Smørgrav " thread. Config for less fds"); 197b7579f77SDag-Erling Smørgrav if(perthread_noudp+2 > 64) 198b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 199b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((64 200b7579f77SDag-Erling Smørgrav - perthread_noudp 201b7579f77SDag-Erling Smørgrav - 2/* safety margin */)); 202b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 203b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 204b7579f77SDag-Erling Smørgrav total = numthread*(perthread_noudp+ 205b7579f77SDag-Erling Smørgrav (size_t)cfg->outgoing_num_ports)+misc; 206b7579f77SDag-Erling Smørgrav } 207b7579f77SDag-Erling Smørgrav if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 208b7579f77SDag-Erling Smørgrav log_warn("getrlimit: %s", strerror(errno)); 209b7579f77SDag-Erling Smørgrav return; 210b7579f77SDag-Erling Smørgrav } 211b7579f77SDag-Erling Smørgrav if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY) 212b7579f77SDag-Erling Smørgrav return; 213b7579f77SDag-Erling Smørgrav if((size_t)rlim.rlim_cur < total) { 214b7579f77SDag-Erling Smørgrav avail = (size_t)rlim.rlim_cur; 215b7579f77SDag-Erling Smørgrav rlim.rlim_cur = (rlim_t)(total + 10); 216b7579f77SDag-Erling Smørgrav rlim.rlim_max = (rlim_t)(total + 10); 217b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRLIMIT 218b7579f77SDag-Erling Smørgrav if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) { 219b7579f77SDag-Erling Smørgrav log_warn("setrlimit: %s", strerror(errno)); 220b7579f77SDag-Erling Smørgrav #endif 221b7579f77SDag-Erling Smørgrav log_warn("cannot increase max open fds from %u to %u", 222b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 223b7579f77SDag-Erling Smørgrav /* check that calculation below does not underflow, 224b7579f77SDag-Erling Smørgrav * with 15 as margin */ 225b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > avail) 226b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 227b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((avail 228b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 229b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 230b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 231b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 232b7579f77SDag-Erling Smørgrav log_warn("increase ulimit or decrease threads, " 233b7579f77SDag-Erling Smørgrav "ports in config to remove this warning"); 234b7579f77SDag-Erling Smørgrav return; 235ff825849SDag-Erling Smørgrav #ifdef HAVE_SETRLIMIT 236b7579f77SDag-Erling Smørgrav } 237ff825849SDag-Erling Smørgrav #endif 238ff825849SDag-Erling Smørgrav verbose(VERB_ALGO, "increased limit(open files) from %u to %u", 239b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 240b7579f77SDag-Erling Smørgrav } 241b7579f77SDag-Erling Smørgrav #else 242b7579f77SDag-Erling Smørgrav (void)cfg; 243b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETRLIMIT */ 24417d15b25SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 245b7579f77SDag-Erling Smørgrav } 246b7579f77SDag-Erling Smørgrav 247b7579f77SDag-Erling Smørgrav /** set verbosity, check rlimits, cache settings */ 248b7579f77SDag-Erling Smørgrav static void 249b7579f77SDag-Erling Smørgrav apply_settings(struct daemon* daemon, struct config_file* cfg, 250ff825849SDag-Erling Smørgrav int cmdline_verbose, int debug_mode) 251b7579f77SDag-Erling Smørgrav { 252b7579f77SDag-Erling Smørgrav /* apply if they have changed */ 253b7579f77SDag-Erling Smørgrav verbosity = cmdline_verbose + cfg->verbosity; 254ff825849SDag-Erling Smørgrav if (debug_mode > 1) { 255ff825849SDag-Erling Smørgrav cfg->use_syslog = 0; 256ff825849SDag-Erling Smørgrav cfg->logfile = NULL; 257ff825849SDag-Erling Smørgrav } 258b7579f77SDag-Erling Smørgrav daemon_apply_cfg(daemon, cfg); 259b7579f77SDag-Erling Smørgrav checkrlimits(cfg); 260b7579f77SDag-Erling Smørgrav } 261b7579f77SDag-Erling Smørgrav 262b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 263b7579f77SDag-Erling Smørgrav /** Read existing pid from pidfile. 264b7579f77SDag-Erling Smørgrav * @param file: file name of pid file. 265b7579f77SDag-Erling Smørgrav * @return: the pid from the file or -1 if none. 266b7579f77SDag-Erling Smørgrav */ 267b7579f77SDag-Erling Smørgrav static pid_t 268b7579f77SDag-Erling Smørgrav readpid (const char* file) 269b7579f77SDag-Erling Smørgrav { 270b7579f77SDag-Erling Smørgrav int fd; 271b7579f77SDag-Erling Smørgrav pid_t pid; 272b7579f77SDag-Erling Smørgrav char pidbuf[32]; 273b7579f77SDag-Erling Smørgrav char* t; 274b7579f77SDag-Erling Smørgrav ssize_t l; 275b7579f77SDag-Erling Smørgrav 276b7579f77SDag-Erling Smørgrav if ((fd = open(file, O_RDONLY)) == -1) { 277b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 278b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 279b7579f77SDag-Erling Smørgrav file, strerror(errno)); 280b7579f77SDag-Erling Smørgrav return -1; 281b7579f77SDag-Erling Smørgrav } 282b7579f77SDag-Erling Smørgrav 283b7579f77SDag-Erling Smørgrav if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) { 284b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 285b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 286b7579f77SDag-Erling Smørgrav file, strerror(errno)); 287b7579f77SDag-Erling Smørgrav close(fd); 288b7579f77SDag-Erling Smørgrav return -1; 289b7579f77SDag-Erling Smørgrav } 290b7579f77SDag-Erling Smørgrav 291b7579f77SDag-Erling Smørgrav close(fd); 292b7579f77SDag-Erling Smørgrav 293b7579f77SDag-Erling Smørgrav /* Empty pidfile means no pidfile... */ 294b7579f77SDag-Erling Smørgrav if (l == 0) { 295b7579f77SDag-Erling Smørgrav return -1; 296b7579f77SDag-Erling Smørgrav } 297b7579f77SDag-Erling Smørgrav 298b7579f77SDag-Erling Smørgrav pidbuf[sizeof(pidbuf)-1] = 0; 299b7579f77SDag-Erling Smørgrav pid = (pid_t)strtol(pidbuf, &t, 10); 300b7579f77SDag-Erling Smørgrav 301b7579f77SDag-Erling Smørgrav if (*t && *t != '\n') { 302b7579f77SDag-Erling Smørgrav return -1; 303b7579f77SDag-Erling Smørgrav } 304b7579f77SDag-Erling Smørgrav return pid; 305b7579f77SDag-Erling Smørgrav } 306b7579f77SDag-Erling Smørgrav 307b7579f77SDag-Erling Smørgrav /** write pid to file. 308b7579f77SDag-Erling Smørgrav * @param pidfile: file name of pid file. 309b7579f77SDag-Erling Smørgrav * @param pid: pid to write to file. 310b7579f77SDag-Erling Smørgrav */ 311b7579f77SDag-Erling Smørgrav static void 312b7579f77SDag-Erling Smørgrav writepid (const char* pidfile, pid_t pid) 313b7579f77SDag-Erling Smørgrav { 314b7579f77SDag-Erling Smørgrav FILE* f; 315b7579f77SDag-Erling Smørgrav 316b7579f77SDag-Erling Smørgrav if ((f = fopen(pidfile, "w")) == NULL ) { 317b7579f77SDag-Erling Smørgrav log_err("cannot open pidfile %s: %s", 318b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 319b7579f77SDag-Erling Smørgrav return; 320b7579f77SDag-Erling Smørgrav } 321b7579f77SDag-Erling Smørgrav if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) { 322b7579f77SDag-Erling Smørgrav log_err("cannot write to pidfile %s: %s", 323b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 324b7579f77SDag-Erling Smørgrav } 325b7579f77SDag-Erling Smørgrav fclose(f); 326b7579f77SDag-Erling Smørgrav } 327b7579f77SDag-Erling Smørgrav 328b7579f77SDag-Erling Smørgrav /** 329b7579f77SDag-Erling Smørgrav * check old pid file. 330b7579f77SDag-Erling Smørgrav * @param pidfile: the file name of the pid file. 331b7579f77SDag-Erling Smørgrav * @param inchroot: if pidfile is inchroot and we can thus expect to 332b7579f77SDag-Erling Smørgrav * be able to delete it. 333b7579f77SDag-Erling Smørgrav */ 334b7579f77SDag-Erling Smørgrav static void 335b7579f77SDag-Erling Smørgrav checkoldpid(char* pidfile, int inchroot) 336b7579f77SDag-Erling Smørgrav { 337b7579f77SDag-Erling Smørgrav pid_t old; 338b7579f77SDag-Erling Smørgrav if((old = readpid(pidfile)) != -1) { 339b7579f77SDag-Erling Smørgrav /* see if it is still alive */ 340b7579f77SDag-Erling Smørgrav if(kill(old, 0) == 0 || errno == EPERM) 341b7579f77SDag-Erling Smørgrav log_warn("unbound is already running as pid %u.", 342b7579f77SDag-Erling Smørgrav (unsigned)old); 343b7579f77SDag-Erling Smørgrav else if(inchroot) 344b7579f77SDag-Erling Smørgrav log_warn("did not exit gracefully last time (%u)", 345b7579f77SDag-Erling Smørgrav (unsigned)old); 346b7579f77SDag-Erling Smørgrav } 347b7579f77SDag-Erling Smørgrav } 348b7579f77SDag-Erling Smørgrav #endif /* HAVE_KILL */ 349b7579f77SDag-Erling Smørgrav 350b7579f77SDag-Erling Smørgrav /** detach from command line */ 351b7579f77SDag-Erling Smørgrav static void 352b7579f77SDag-Erling Smørgrav detach(void) 353b7579f77SDag-Erling Smørgrav { 354b7579f77SDag-Erling Smørgrav #if defined(HAVE_DAEMON) && !defined(DEPRECATED_DAEMON) 355b7579f77SDag-Erling Smørgrav /* use POSIX daemon(3) function */ 356b7579f77SDag-Erling Smørgrav if(daemon(1, 0) != 0) 357b7579f77SDag-Erling Smørgrav fatal_exit("daemon failed: %s", strerror(errno)); 358b7579f77SDag-Erling Smørgrav #else /* no HAVE_DAEMON */ 359b7579f77SDag-Erling Smørgrav #ifdef HAVE_FORK 360b7579f77SDag-Erling Smørgrav int fd; 361b7579f77SDag-Erling Smørgrav /* Take off... */ 362b7579f77SDag-Erling Smørgrav switch (fork()) { 363b7579f77SDag-Erling Smørgrav case 0: 364b7579f77SDag-Erling Smørgrav break; 365b7579f77SDag-Erling Smørgrav case -1: 366b7579f77SDag-Erling Smørgrav fatal_exit("fork failed: %s", strerror(errno)); 367b7579f77SDag-Erling Smørgrav default: 368b7579f77SDag-Erling Smørgrav /* exit interactive session */ 369b7579f77SDag-Erling Smørgrav exit(0); 370b7579f77SDag-Erling Smørgrav } 371b7579f77SDag-Erling Smørgrav /* detach */ 372b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETSID 373b7579f77SDag-Erling Smørgrav if(setsid() == -1) 374b7579f77SDag-Erling Smørgrav fatal_exit("setsid() failed: %s", strerror(errno)); 375b7579f77SDag-Erling Smørgrav #endif 376b7579f77SDag-Erling Smørgrav if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { 377b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDIN_FILENO); 378b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDOUT_FILENO); 379b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDERR_FILENO); 380b7579f77SDag-Erling Smørgrav if (fd > 2) 381b7579f77SDag-Erling Smørgrav (void)close(fd); 382b7579f77SDag-Erling Smørgrav } 383b7579f77SDag-Erling Smørgrav #endif /* HAVE_FORK */ 384b7579f77SDag-Erling Smørgrav #endif /* HAVE_DAEMON */ 385b7579f77SDag-Erling Smørgrav } 386b7579f77SDag-Erling Smørgrav 387b7579f77SDag-Erling Smørgrav /** daemonize, drop user priviliges and chroot if needed */ 388b7579f77SDag-Erling Smørgrav static void 389b7579f77SDag-Erling Smørgrav perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, 390b7579f77SDag-Erling Smørgrav const char** cfgfile) 391b7579f77SDag-Erling Smørgrav { 392f61ef7f6SDag-Erling Smørgrav #ifdef HAVE_KILL 393f61ef7f6SDag-Erling Smørgrav int pidinchroot; 394f61ef7f6SDag-Erling Smørgrav #endif 395b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 396b7579f77SDag-Erling Smørgrav struct passwd *pwd = NULL; 397b7579f77SDag-Erling Smørgrav 398b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 399b7579f77SDag-Erling Smørgrav if((pwd = getpwnam(cfg->username)) == NULL) 400b7579f77SDag-Erling Smørgrav fatal_exit("user '%s' does not exist.", cfg->username); 401b7579f77SDag-Erling Smørgrav /* endpwent below, in case we need pwd for setusercontext */ 402b7579f77SDag-Erling Smørgrav } 403b7579f77SDag-Erling Smørgrav #endif 40405ab2901SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 40505ab2901SDag-Erling Smørgrav w_config_adjust_directory(cfg); 40605ab2901SDag-Erling Smørgrav #endif 407b7579f77SDag-Erling Smørgrav 408b7579f77SDag-Erling Smørgrav /* init syslog (as root) if needed, before daemonize, otherwise 409b7579f77SDag-Erling Smørgrav * a fork error could not be printed since daemonize closed stderr.*/ 410b7579f77SDag-Erling Smørgrav if(cfg->use_syslog) { 411b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 412b7579f77SDag-Erling Smørgrav } 413b7579f77SDag-Erling Smørgrav /* if using a logfile, we cannot open it because the logfile would 414b7579f77SDag-Erling Smørgrav * be created with the wrong permissions, we cannot chown it because 415b7579f77SDag-Erling Smørgrav * we cannot chown system logfiles, so we do not open at all. 416b7579f77SDag-Erling Smørgrav * So, using a logfile, the user does not see errors unless -d is 417b7579f77SDag-Erling Smørgrav * given to unbound on the commandline. */ 418b7579f77SDag-Erling Smørgrav 419b7579f77SDag-Erling Smørgrav /* read ssl keys while superuser and outside chroot */ 4208ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 421b7579f77SDag-Erling Smørgrav if(!(daemon->rc = daemon_remote_create(cfg))) 422b7579f77SDag-Erling Smørgrav fatal_exit("could not set up remote-control"); 423b7579f77SDag-Erling Smørgrav if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { 424b7579f77SDag-Erling Smørgrav if(!(daemon->listen_sslctx = listen_sslctx_create( 425b7579f77SDag-Erling Smørgrav cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) 426b7579f77SDag-Erling Smørgrav fatal_exit("could not set up listen SSL_CTX"); 427b7579f77SDag-Erling Smørgrav } 428b7579f77SDag-Erling Smørgrav if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, NULL))) 429b7579f77SDag-Erling Smørgrav fatal_exit("could not set up connect SSL_CTX"); 4308ed2b524SDag-Erling Smørgrav #endif 431b7579f77SDag-Erling Smørgrav 432b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 433f61ef7f6SDag-Erling Smørgrav /* true if pidfile is inside chrootdir, or nochroot */ 434f61ef7f6SDag-Erling Smørgrav pidinchroot = !(cfg->chrootdir && cfg->chrootdir[0]) || 435f61ef7f6SDag-Erling Smørgrav (cfg->chrootdir && cfg->chrootdir[0] && 436f61ef7f6SDag-Erling Smørgrav strncmp(cfg->pidfile, cfg->chrootdir, 437f61ef7f6SDag-Erling Smørgrav strlen(cfg->chrootdir))==0); 438f61ef7f6SDag-Erling Smørgrav 439b7579f77SDag-Erling Smørgrav /* check old pid file before forking */ 440b7579f77SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0]) { 441b7579f77SDag-Erling Smørgrav /* calculate position of pidfile */ 442b7579f77SDag-Erling Smørgrav if(cfg->pidfile[0] == '/') 443b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(cfg->pidfile); 444b7579f77SDag-Erling Smørgrav else daemon->pidfile = fname_after_chroot(cfg->pidfile, 445b7579f77SDag-Erling Smørgrav cfg, 1); 446b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 447b7579f77SDag-Erling Smørgrav fatal_exit("pidfile alloc: out of memory"); 448f61ef7f6SDag-Erling Smørgrav checkoldpid(daemon->pidfile, pidinchroot); 449b7579f77SDag-Erling Smørgrav } 450b7579f77SDag-Erling Smørgrav #endif 451b7579f77SDag-Erling Smørgrav 452b7579f77SDag-Erling Smørgrav /* daemonize because pid is needed by the writepid func */ 453b7579f77SDag-Erling Smørgrav if(!debug_mode && cfg->do_daemonize) { 454b7579f77SDag-Erling Smørgrav detach(); 455b7579f77SDag-Erling Smørgrav } 456b7579f77SDag-Erling Smørgrav 457b7579f77SDag-Erling Smørgrav /* write new pidfile (while still root, so can be outside chroot) */ 458b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 459b7579f77SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0]) { 460b7579f77SDag-Erling Smørgrav writepid(daemon->pidfile, getpid()); 461f61ef7f6SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1 && 462f61ef7f6SDag-Erling Smørgrav pidinchroot) { 4636480faa8SDag-Erling Smørgrav # ifdef HAVE_CHOWN 4646480faa8SDag-Erling Smørgrav if(chown(daemon->pidfile, cfg_uid, cfg_gid) == -1) { 465f61ef7f6SDag-Erling Smørgrav verbose(VERB_QUERY, "cannot chown %u.%u %s: %s", 4666480faa8SDag-Erling Smørgrav (unsigned)cfg_uid, (unsigned)cfg_gid, 467b7579f77SDag-Erling Smørgrav daemon->pidfile, strerror(errno)); 468b7579f77SDag-Erling Smørgrav } 4696480faa8SDag-Erling Smørgrav # endif /* HAVE_CHOWN */ 470b7579f77SDag-Erling Smørgrav } 471b7579f77SDag-Erling Smørgrav } 472b7579f77SDag-Erling Smørgrav #else 473b7579f77SDag-Erling Smørgrav (void)daemon; 4746480faa8SDag-Erling Smørgrav #endif /* HAVE_KILL */ 475b7579f77SDag-Erling Smørgrav 476b7579f77SDag-Erling Smørgrav /* Set user context */ 477b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 4786480faa8SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { 479b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETUSERCONTEXT 480b7579f77SDag-Erling Smørgrav /* setusercontext does initgroups, setuid, setgid, and 481b7579f77SDag-Erling Smørgrav * also resource limits from login config, but we 482b7579f77SDag-Erling Smørgrav * still call setresuid, setresgid to be sure to set all uid*/ 4836480faa8SDag-Erling Smørgrav if(setusercontext(NULL, pwd, cfg_uid, (unsigned) 484b7579f77SDag-Erling Smørgrav LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) 485b7579f77SDag-Erling Smørgrav log_warn("unable to setusercontext %s: %s", 486b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 487b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETUSERCONTEXT */ 488b7579f77SDag-Erling Smørgrav } 489b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 490b7579f77SDag-Erling Smørgrav 491b7579f77SDag-Erling Smørgrav /* box into the chroot */ 492b7579f77SDag-Erling Smørgrav #ifdef HAVE_CHROOT 493b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0]) { 494b7579f77SDag-Erling Smørgrav if(chdir(cfg->chrootdir)) { 495b7579f77SDag-Erling Smørgrav fatal_exit("unable to chdir to chroot %s: %s", 496b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 497b7579f77SDag-Erling Smørgrav } 498b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", cfg->chrootdir); 499b7579f77SDag-Erling Smørgrav if(chroot(cfg->chrootdir)) 500b7579f77SDag-Erling Smørgrav fatal_exit("unable to chroot to %s: %s", 501b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 5028ed2b524SDag-Erling Smørgrav if(chdir("/")) 5038ed2b524SDag-Erling Smørgrav fatal_exit("unable to chdir to / in chroot %s: %s", 5048ed2b524SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 505b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir); 506b7579f77SDag-Erling Smørgrav if(strncmp(*cfgfile, cfg->chrootdir, 507b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 508b7579f77SDag-Erling Smørgrav (*cfgfile) += strlen(cfg->chrootdir); 509b7579f77SDag-Erling Smørgrav 510b7579f77SDag-Erling Smørgrav /* adjust stored pidfile for chroot */ 511b7579f77SDag-Erling Smørgrav if(daemon->pidfile && daemon->pidfile[0] && 512b7579f77SDag-Erling Smørgrav strncmp(daemon->pidfile, cfg->chrootdir, 513b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir))==0) { 514b7579f77SDag-Erling Smørgrav char* old = daemon->pidfile; 515b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(old+strlen(cfg->chrootdir)); 516b7579f77SDag-Erling Smørgrav free(old); 517b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 518b7579f77SDag-Erling Smørgrav log_err("out of memory in pidfile adjust"); 519b7579f77SDag-Erling Smørgrav } 520b7579f77SDag-Erling Smørgrav daemon->chroot = strdup(cfg->chrootdir); 521b7579f77SDag-Erling Smørgrav if(!daemon->chroot) 522b7579f77SDag-Erling Smørgrav log_err("out of memory in daemon chroot dir storage"); 523b7579f77SDag-Erling Smørgrav } 524b7579f77SDag-Erling Smørgrav #else 525b7579f77SDag-Erling Smørgrav (void)cfgfile; 526b7579f77SDag-Erling Smørgrav #endif 527b7579f77SDag-Erling Smørgrav /* change to working directory inside chroot */ 528b7579f77SDag-Erling Smørgrav if(cfg->directory && cfg->directory[0]) { 529b7579f77SDag-Erling Smørgrav char* dir = cfg->directory; 530b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0] && 531b7579f77SDag-Erling Smørgrav strncmp(dir, cfg->chrootdir, 532b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 533b7579f77SDag-Erling Smørgrav dir += strlen(cfg->chrootdir); 534b7579f77SDag-Erling Smørgrav if(dir[0]) { 535b7579f77SDag-Erling Smørgrav if(chdir(dir)) { 536b7579f77SDag-Erling Smørgrav fatal_exit("Could not chdir to %s: %s", 537b7579f77SDag-Erling Smørgrav dir, strerror(errno)); 538b7579f77SDag-Erling Smørgrav } 539b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", dir); 540b7579f77SDag-Erling Smørgrav } 541b7579f77SDag-Erling Smørgrav } 542b7579f77SDag-Erling Smørgrav 543b7579f77SDag-Erling Smørgrav /* drop permissions after chroot, getpwnam, pidfile, syslog done*/ 544b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 5456480faa8SDag-Erling Smørgrav if(cfg->username && cfg->username[0] && cfg_uid != (uid_t)-1) { 546b7579f77SDag-Erling Smørgrav # ifdef HAVE_INITGROUPS 5476480faa8SDag-Erling Smørgrav if(initgroups(cfg->username, cfg_gid) != 0) 548b7579f77SDag-Erling Smørgrav log_warn("unable to initgroups %s: %s", 549b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 550b7579f77SDag-Erling Smørgrav # endif /* HAVE_INITGROUPS */ 551*b5663de9SDag-Erling Smørgrav # ifdef HAVE_ENDPWENT 552b7579f77SDag-Erling Smørgrav endpwent(); 553*b5663de9SDag-Erling Smørgrav # endif 554b7579f77SDag-Erling Smørgrav 555b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESGID 5566480faa8SDag-Erling Smørgrav if(setresgid(cfg_gid,cfg_gid,cfg_gid) != 0) 557b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) 5586480faa8SDag-Erling Smørgrav if(setregid(cfg_gid,cfg_gid) != 0) 559b7579f77SDag-Erling Smørgrav #else /* use setgid */ 5606480faa8SDag-Erling Smørgrav if(setgid(cfg_gid) != 0) 561b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESGID */ 562b7579f77SDag-Erling Smørgrav fatal_exit("unable to set group id of %s: %s", 563b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 564b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESUID 5656480faa8SDag-Erling Smørgrav if(setresuid(cfg_uid,cfg_uid,cfg_uid) != 0) 566b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) 5676480faa8SDag-Erling Smørgrav if(setreuid(cfg_uid,cfg_uid) != 0) 568b7579f77SDag-Erling Smørgrav #else /* use setuid */ 5696480faa8SDag-Erling Smørgrav if(setuid(cfg_uid) != 0) 570b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESUID */ 571b7579f77SDag-Erling Smørgrav fatal_exit("unable to set user id of %s: %s", 572b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 573b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "drop user privileges, run as %s", 574b7579f77SDag-Erling Smørgrav cfg->username); 575b7579f77SDag-Erling Smørgrav } 576b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 577b7579f77SDag-Erling Smørgrav /* file logging inited after chroot,chdir,setuid is done so that 578b7579f77SDag-Erling Smørgrav * it would succeed on SIGHUP as well */ 579b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 580b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 581b7579f77SDag-Erling Smørgrav } 582b7579f77SDag-Erling Smørgrav 583b7579f77SDag-Erling Smørgrav /** 584b7579f77SDag-Erling Smørgrav * Run the daemon. 585b7579f77SDag-Erling Smørgrav * @param cfgfile: the config file name. 586b7579f77SDag-Erling Smørgrav * @param cmdline_verbose: verbosity resulting from commandline -v. 587b7579f77SDag-Erling Smørgrav * These increase verbosity as specified in the config file. 588b7579f77SDag-Erling Smørgrav * @param debug_mode: if set, do not daemonize. 589b7579f77SDag-Erling Smørgrav */ 590b7579f77SDag-Erling Smørgrav static void 591b7579f77SDag-Erling Smørgrav run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) 592b7579f77SDag-Erling Smørgrav { 593b7579f77SDag-Erling Smørgrav struct config_file* cfg = NULL; 594b7579f77SDag-Erling Smørgrav struct daemon* daemon = NULL; 595b7579f77SDag-Erling Smørgrav int done_setup = 0; 596b7579f77SDag-Erling Smørgrav 597b7579f77SDag-Erling Smørgrav if(!(daemon = daemon_init())) 598b7579f77SDag-Erling Smørgrav fatal_exit("alloc failure"); 599b7579f77SDag-Erling Smørgrav while(!daemon->need_to_exit) { 600b7579f77SDag-Erling Smørgrav if(done_setup) 601b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING); 602b7579f77SDag-Erling Smørgrav else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING); 603b7579f77SDag-Erling Smørgrav 604b7579f77SDag-Erling Smørgrav /* config stuff */ 605b7579f77SDag-Erling Smørgrav if(!(cfg = config_create())) 606b7579f77SDag-Erling Smørgrav fatal_exit("Could not alloc config defaults"); 607b7579f77SDag-Erling Smørgrav if(!config_read(cfg, cfgfile, daemon->chroot)) { 608b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 609b7579f77SDag-Erling Smørgrav fatal_exit("Could not read config file: %s", 610b7579f77SDag-Erling Smørgrav cfgfile); 611b7579f77SDag-Erling Smørgrav log_warn("Continuing with default config settings"); 612b7579f77SDag-Erling Smørgrav } 613ff825849SDag-Erling Smørgrav apply_settings(daemon, cfg, cmdline_verbose, debug_mode); 6146480faa8SDag-Erling Smørgrav if(!done_setup) 615748bd829SDag-Erling Smørgrav config_lookup_uid(cfg); 616b7579f77SDag-Erling Smørgrav 617b7579f77SDag-Erling Smørgrav /* prepare */ 618b7579f77SDag-Erling Smørgrav if(!daemon_open_shared_ports(daemon)) 619b7579f77SDag-Erling Smørgrav fatal_exit("could not open ports"); 620b7579f77SDag-Erling Smørgrav if(!done_setup) { 621b7579f77SDag-Erling Smørgrav perform_setup(daemon, cfg, debug_mode, &cfgfile); 622b7579f77SDag-Erling Smørgrav done_setup = 1; 623b7579f77SDag-Erling Smørgrav } else { 624b7579f77SDag-Erling Smørgrav /* reopen log after HUP to facilitate log rotation */ 625b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 626b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, 0, cfg->chrootdir); 627b7579f77SDag-Erling Smørgrav } 628b7579f77SDag-Erling Smørgrav /* work */ 629b7579f77SDag-Erling Smørgrav daemon_fork(daemon); 630b7579f77SDag-Erling Smørgrav 631b7579f77SDag-Erling Smørgrav /* clean up for restart */ 632b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "cleanup."); 633b7579f77SDag-Erling Smørgrav daemon_cleanup(daemon); 634b7579f77SDag-Erling Smørgrav config_delete(cfg); 635b7579f77SDag-Erling Smørgrav } 636b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Exit cleanup."); 637b7579f77SDag-Erling Smørgrav /* this unlink may not work if the pidfile is located outside 638b7579f77SDag-Erling Smørgrav * of the chroot/workdir or we no longer have permissions */ 639b7579f77SDag-Erling Smørgrav if(daemon->pidfile) { 640b7579f77SDag-Erling Smørgrav int fd; 641b7579f77SDag-Erling Smørgrav /* truncate pidfile */ 642b7579f77SDag-Erling Smørgrav fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644); 643b7579f77SDag-Erling Smørgrav if(fd != -1) 644b7579f77SDag-Erling Smørgrav close(fd); 645b7579f77SDag-Erling Smørgrav /* delete pidfile */ 646b7579f77SDag-Erling Smørgrav unlink(daemon->pidfile); 647b7579f77SDag-Erling Smørgrav } 648b7579f77SDag-Erling Smørgrav daemon_delete(daemon); 649b7579f77SDag-Erling Smørgrav } 650b7579f77SDag-Erling Smørgrav 651b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 652b7579f77SDag-Erling Smørgrav extern int optind; 653b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 654b7579f77SDag-Erling Smørgrav extern char* optarg; 655b7579f77SDag-Erling Smørgrav 656b7579f77SDag-Erling Smørgrav /** 657b7579f77SDag-Erling Smørgrav * main program. Set options given commandline arguments. 658b7579f77SDag-Erling Smørgrav * @param argc: number of commandline arguments. 659b7579f77SDag-Erling Smørgrav * @param argv: array of commandline arguments. 660b7579f77SDag-Erling Smørgrav * @return: exit status of the program. 661b7579f77SDag-Erling Smørgrav */ 662b7579f77SDag-Erling Smørgrav int 663b7579f77SDag-Erling Smørgrav main(int argc, char* argv[]) 664b7579f77SDag-Erling Smørgrav { 665b7579f77SDag-Erling Smørgrav int c; 666b7579f77SDag-Erling Smørgrav const char* cfgfile = CONFIGFILE; 667b7579f77SDag-Erling Smørgrav const char* winopt = NULL; 668b7579f77SDag-Erling Smørgrav int cmdline_verbose = 0; 669b7579f77SDag-Erling Smørgrav int debug_mode = 0; 670b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 671b7579f77SDag-Erling Smørgrav int cmdline_cfg = 0; 672b7579f77SDag-Erling Smørgrav #endif 673b7579f77SDag-Erling Smørgrav 674b7579f77SDag-Erling Smørgrav #ifdef HAVE_SBRK 675b7579f77SDag-Erling Smørgrav /* take debug snapshot of heap */ 676b7579f77SDag-Erling Smørgrav unbound_start_brk = sbrk(0); 677b7579f77SDag-Erling Smørgrav #endif 678b7579f77SDag-Erling Smørgrav 679b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); 68017d15b25SDag-Erling Smørgrav log_ident_set(strrchr(argv[0],'/')?strrchr(argv[0],'/')+1:argv[0]); 681b7579f77SDag-Erling Smørgrav /* parse the options */ 682b7579f77SDag-Erling Smørgrav while( (c=getopt(argc, argv, "c:dhvw:")) != -1) { 683b7579f77SDag-Erling Smørgrav switch(c) { 684b7579f77SDag-Erling Smørgrav case 'c': 685b7579f77SDag-Erling Smørgrav cfgfile = optarg; 686b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 687b7579f77SDag-Erling Smørgrav cmdline_cfg = 1; 688b7579f77SDag-Erling Smørgrav #endif 689b7579f77SDag-Erling Smørgrav break; 690b7579f77SDag-Erling Smørgrav case 'v': 691b7579f77SDag-Erling Smørgrav cmdline_verbose++; 692b7579f77SDag-Erling Smørgrav verbosity++; 693b7579f77SDag-Erling Smørgrav break; 694b7579f77SDag-Erling Smørgrav case 'd': 695ff825849SDag-Erling Smørgrav debug_mode++; 696b7579f77SDag-Erling Smørgrav break; 697b7579f77SDag-Erling Smørgrav case 'w': 698b7579f77SDag-Erling Smørgrav winopt = optarg; 699b7579f77SDag-Erling Smørgrav break; 700b7579f77SDag-Erling Smørgrav case '?': 701b7579f77SDag-Erling Smørgrav case 'h': 702b7579f77SDag-Erling Smørgrav default: 703b7579f77SDag-Erling Smørgrav usage(); 704b7579f77SDag-Erling Smørgrav return 1; 705b7579f77SDag-Erling Smørgrav } 706b7579f77SDag-Erling Smørgrav } 707b7579f77SDag-Erling Smørgrav argc -= optind; 708b7579f77SDag-Erling Smørgrav argv += optind; 709b7579f77SDag-Erling Smørgrav 710b7579f77SDag-Erling Smørgrav if(winopt) { 711b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 712b7579f77SDag-Erling Smørgrav wsvc_command_option(winopt, cfgfile, cmdline_verbose, 713b7579f77SDag-Erling Smørgrav cmdline_cfg); 714b7579f77SDag-Erling Smørgrav #else 715b7579f77SDag-Erling Smørgrav fatal_exit("option not supported"); 716b7579f77SDag-Erling Smørgrav #endif 717b7579f77SDag-Erling Smørgrav } 718b7579f77SDag-Erling Smørgrav 719b7579f77SDag-Erling Smørgrav if(argc != 0) { 720b7579f77SDag-Erling Smørgrav usage(); 721b7579f77SDag-Erling Smørgrav return 1; 722b7579f77SDag-Erling Smørgrav } 723b7579f77SDag-Erling Smørgrav 724b7579f77SDag-Erling Smørgrav run_daemon(cfgfile, cmdline_verbose, debug_mode); 725b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); /* close logfile */ 726b7579f77SDag-Erling Smørgrav return 0; 727b7579f77SDag-Erling Smørgrav } 728