1*b7579f77SDag-Erling Smørgrav /* 2*b7579f77SDag-Erling Smørgrav * daemon/unbound.c - main program for unbound DNS resolver daemon. 3*b7579f77SDag-Erling Smørgrav * 4*b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5*b7579f77SDag-Erling Smørgrav * 6*b7579f77SDag-Erling Smørgrav * This software is open source. 7*b7579f77SDag-Erling Smørgrav * 8*b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9*b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10*b7579f77SDag-Erling Smørgrav * are met: 11*b7579f77SDag-Erling Smørgrav * 12*b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14*b7579f77SDag-Erling Smørgrav * 15*b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17*b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18*b7579f77SDag-Erling Smørgrav * 19*b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20*b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21*b7579f77SDag-Erling Smørgrav * specific prior written permission. 22*b7579f77SDag-Erling Smørgrav * 23*b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*b7579f77SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25*b7579f77SDag-Erling Smørgrav * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26*b7579f77SDag-Erling Smørgrav * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27*b7579f77SDag-Erling Smørgrav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28*b7579f77SDag-Erling Smørgrav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29*b7579f77SDag-Erling Smørgrav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30*b7579f77SDag-Erling Smørgrav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31*b7579f77SDag-Erling Smørgrav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32*b7579f77SDag-Erling Smørgrav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33*b7579f77SDag-Erling Smørgrav * POSSIBILITY OF SUCH DAMAGE. 34*b7579f77SDag-Erling Smørgrav * 35*b7579f77SDag-Erling Smørgrav */ 36*b7579f77SDag-Erling Smørgrav 37*b7579f77SDag-Erling Smørgrav /** 38*b7579f77SDag-Erling Smørgrav * \file 39*b7579f77SDag-Erling Smørgrav * 40*b7579f77SDag-Erling Smørgrav * Main program to start the DNS resolver daemon. 41*b7579f77SDag-Erling Smørgrav */ 42*b7579f77SDag-Erling Smørgrav 43*b7579f77SDag-Erling Smørgrav #include "config.h" 44*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETOPT_H 45*b7579f77SDag-Erling Smørgrav #include <getopt.h> 46*b7579f77SDag-Erling Smørgrav #endif 47*b7579f77SDag-Erling Smørgrav #include <sys/time.h> 48*b7579f77SDag-Erling Smørgrav #include "util/log.h" 49*b7579f77SDag-Erling Smørgrav #include "daemon/daemon.h" 50*b7579f77SDag-Erling Smørgrav #include "daemon/remote.h" 51*b7579f77SDag-Erling Smørgrav #include "util/config_file.h" 52*b7579f77SDag-Erling Smørgrav #include "util/storage/slabhash.h" 53*b7579f77SDag-Erling Smørgrav #include "services/listen_dnsport.h" 54*b7579f77SDag-Erling Smørgrav #include "services/cache/rrset.h" 55*b7579f77SDag-Erling Smørgrav #include "services/cache/infra.h" 56*b7579f77SDag-Erling Smørgrav #include "util/data/msgreply.h" 57*b7579f77SDag-Erling Smørgrav #include "util/module.h" 58*b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 59*b7579f77SDag-Erling Smørgrav #include <signal.h> 60*b7579f77SDag-Erling Smørgrav #include <fcntl.h> 61*b7579f77SDag-Erling Smørgrav #include <openssl/crypto.h> 62*b7579f77SDag-Erling Smørgrav #ifdef HAVE_PWD_H 63*b7579f77SDag-Erling Smørgrav #include <pwd.h> 64*b7579f77SDag-Erling Smørgrav #endif 65*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GRP_H 66*b7579f77SDag-Erling Smørgrav #include <grp.h> 67*b7579f77SDag-Erling Smørgrav #endif 68*b7579f77SDag-Erling Smørgrav 69*b7579f77SDag-Erling Smørgrav #ifdef HAVE_SYS_RESOURCE_H 70*b7579f77SDag-Erling Smørgrav #include <sys/resource.h> 71*b7579f77SDag-Erling Smørgrav #endif 72*b7579f77SDag-Erling Smørgrav #ifdef HAVE_LOGIN_CAP_H 73*b7579f77SDag-Erling Smørgrav #include <login_cap.h> 74*b7579f77SDag-Erling Smørgrav #endif 75*b7579f77SDag-Erling Smørgrav 76*b7579f77SDag-Erling Smørgrav #ifdef USE_MINI_EVENT 77*b7579f77SDag-Erling Smørgrav # ifdef USE_WINSOCK 78*b7579f77SDag-Erling Smørgrav # include "util/winsock_event.h" 79*b7579f77SDag-Erling Smørgrav # else 80*b7579f77SDag-Erling Smørgrav # include "util/mini_event.h" 81*b7579f77SDag-Erling Smørgrav # endif 82*b7579f77SDag-Erling Smørgrav #else 83*b7579f77SDag-Erling Smørgrav # include <event.h> 84*b7579f77SDag-Erling Smørgrav #endif 85*b7579f77SDag-Erling Smørgrav 86*b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 87*b7579f77SDag-Erling Smørgrav # include "winrc/win_svc.h" 88*b7579f77SDag-Erling Smørgrav #endif 89*b7579f77SDag-Erling Smørgrav 90*b7579f77SDag-Erling Smørgrav /** global debug value to keep track of heap memory allocation */ 91*b7579f77SDag-Erling Smørgrav void* unbound_start_brk = 0; 92*b7579f77SDag-Erling Smørgrav 93*b7579f77SDag-Erling Smørgrav #if !defined(HAVE_EVENT_BASE_GET_METHOD) && (defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)) 94*b7579f77SDag-Erling Smørgrav static const char* ev_backend2str(int b) 95*b7579f77SDag-Erling Smørgrav { 96*b7579f77SDag-Erling Smørgrav switch(b) { 97*b7579f77SDag-Erling Smørgrav case EVBACKEND_SELECT: return "select"; 98*b7579f77SDag-Erling Smørgrav case EVBACKEND_POLL: return "poll"; 99*b7579f77SDag-Erling Smørgrav case EVBACKEND_EPOLL: return "epoll"; 100*b7579f77SDag-Erling Smørgrav case EVBACKEND_KQUEUE: return "kqueue"; 101*b7579f77SDag-Erling Smørgrav case EVBACKEND_DEVPOLL: return "devpoll"; 102*b7579f77SDag-Erling Smørgrav case EVBACKEND_PORT: return "evport"; 103*b7579f77SDag-Erling Smørgrav } 104*b7579f77SDag-Erling Smørgrav return "unknown"; 105*b7579f77SDag-Erling Smørgrav } 106*b7579f77SDag-Erling Smørgrav #endif 107*b7579f77SDag-Erling Smørgrav 108*b7579f77SDag-Erling Smørgrav /** get the event system in use */ 109*b7579f77SDag-Erling Smørgrav static void get_event_sys(const char** n, const char** s, const char** m) 110*b7579f77SDag-Erling Smørgrav { 111*b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 112*b7579f77SDag-Erling Smørgrav *n = "event"; 113*b7579f77SDag-Erling Smørgrav *s = "winsock"; 114*b7579f77SDag-Erling Smørgrav *m = "WSAWaitForMultipleEvents"; 115*b7579f77SDag-Erling Smørgrav #elif defined(USE_MINI_EVENT) 116*b7579f77SDag-Erling Smørgrav *n = "mini-event"; 117*b7579f77SDag-Erling Smørgrav *s = "internal"; 118*b7579f77SDag-Erling Smørgrav *m = "select"; 119*b7579f77SDag-Erling Smørgrav #else 120*b7579f77SDag-Erling Smørgrav struct event_base* b; 121*b7579f77SDag-Erling Smørgrav *s = event_get_version(); 122*b7579f77SDag-Erling Smørgrav # ifdef HAVE_EVENT_BASE_GET_METHOD 123*b7579f77SDag-Erling Smørgrav *n = "libevent"; 124*b7579f77SDag-Erling Smørgrav b = event_base_new(); 125*b7579f77SDag-Erling Smørgrav *m = event_base_get_method(b); 126*b7579f77SDag-Erling Smørgrav # elif defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 127*b7579f77SDag-Erling Smørgrav *n = "libev"; 128*b7579f77SDag-Erling Smørgrav b = (struct event_base*)ev_default_loop(EVFLAG_AUTO); 129*b7579f77SDag-Erling Smørgrav *m = ev_backend2str(ev_backend((struct ev_loop*)b)); 130*b7579f77SDag-Erling Smørgrav # else 131*b7579f77SDag-Erling Smørgrav *n = "unknown"; 132*b7579f77SDag-Erling Smørgrav *m = "not obtainable"; 133*b7579f77SDag-Erling Smørgrav b = NULL; 134*b7579f77SDag-Erling Smørgrav # endif 135*b7579f77SDag-Erling Smørgrav # ifdef HAVE_EVENT_BASE_FREE 136*b7579f77SDag-Erling Smørgrav event_base_free(b); 137*b7579f77SDag-Erling Smørgrav # endif 138*b7579f77SDag-Erling Smørgrav #endif 139*b7579f77SDag-Erling Smørgrav } 140*b7579f77SDag-Erling Smørgrav 141*b7579f77SDag-Erling Smørgrav /** print usage. */ 142*b7579f77SDag-Erling Smørgrav static void usage() 143*b7579f77SDag-Erling Smørgrav { 144*b7579f77SDag-Erling Smørgrav const char** m; 145*b7579f77SDag-Erling Smørgrav const char *evnm="event", *evsys="", *evmethod=""; 146*b7579f77SDag-Erling Smørgrav printf("usage: unbound [options]\n"); 147*b7579f77SDag-Erling Smørgrav printf(" start unbound daemon DNS resolver.\n"); 148*b7579f77SDag-Erling Smørgrav printf("-h this help\n"); 149*b7579f77SDag-Erling Smørgrav printf("-c file config file to read instead of %s\n", CONFIGFILE); 150*b7579f77SDag-Erling Smørgrav printf(" file format is described in unbound.conf(5).\n"); 151*b7579f77SDag-Erling Smørgrav printf("-d do not fork into the background.\n"); 152*b7579f77SDag-Erling Smørgrav printf("-v verbose (more times to increase verbosity)\n"); 153*b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 154*b7579f77SDag-Erling Smørgrav printf("-w opt windows option: \n"); 155*b7579f77SDag-Erling Smørgrav printf(" install, remove - manage the services entry\n"); 156*b7579f77SDag-Erling Smørgrav printf(" service - used to start from services control panel\n"); 157*b7579f77SDag-Erling Smørgrav #endif 158*b7579f77SDag-Erling Smørgrav printf("Version %s\n", PACKAGE_VERSION); 159*b7579f77SDag-Erling Smørgrav get_event_sys(&evnm, &evsys, &evmethod); 160*b7579f77SDag-Erling Smørgrav printf("linked libs: %s %s (it uses %s), ldns %s, %s\n", 161*b7579f77SDag-Erling Smørgrav evnm, evsys, evmethod, ldns_version(), 162*b7579f77SDag-Erling Smørgrav SSLeay_version(SSLEAY_VERSION)); 163*b7579f77SDag-Erling Smørgrav printf("linked modules:"); 164*b7579f77SDag-Erling Smørgrav for(m = module_list_avail(); *m; m++) 165*b7579f77SDag-Erling Smørgrav printf(" %s", *m); 166*b7579f77SDag-Erling Smørgrav printf("\n"); 167*b7579f77SDag-Erling Smørgrav printf("configured for %s on %s with options:%s\n", 168*b7579f77SDag-Erling Smørgrav CONFIGURE_TARGET, CONFIGURE_DATE, CONFIGURE_BUILD_WITH); 169*b7579f77SDag-Erling Smørgrav printf("BSD licensed, see LICENSE in source package for details.\n"); 170*b7579f77SDag-Erling Smørgrav printf("Report bugs to %s\n", PACKAGE_BUGREPORT); 171*b7579f77SDag-Erling Smørgrav } 172*b7579f77SDag-Erling Smørgrav 173*b7579f77SDag-Erling Smørgrav #ifndef unbound_testbound 174*b7579f77SDag-Erling Smørgrav int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) 175*b7579f77SDag-Erling Smørgrav { 176*b7579f77SDag-Erling Smørgrav log_assert(0); 177*b7579f77SDag-Erling Smørgrav return 0; 178*b7579f77SDag-Erling Smørgrav } 179*b7579f77SDag-Erling Smørgrav #endif 180*b7579f77SDag-Erling Smørgrav 181*b7579f77SDag-Erling Smørgrav /** check file descriptor count */ 182*b7579f77SDag-Erling Smørgrav static void 183*b7579f77SDag-Erling Smørgrav checkrlimits(struct config_file* cfg) 184*b7579f77SDag-Erling Smørgrav { 185*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETRLIMIT 186*b7579f77SDag-Erling Smørgrav /* list has number of ports to listen to, ifs number addresses */ 187*b7579f77SDag-Erling Smørgrav int list = ((cfg->do_udp?1:0) + (cfg->do_tcp?1 + 188*b7579f77SDag-Erling Smørgrav (int)cfg->incoming_num_tcp:0)); 189*b7579f77SDag-Erling Smørgrav size_t listen_ifs = (size_t)(cfg->num_ifs==0? 190*b7579f77SDag-Erling Smørgrav ((cfg->do_ip4 && !cfg->if_automatic?1:0) + 191*b7579f77SDag-Erling Smørgrav (cfg->do_ip6?1:0)):cfg->num_ifs); 192*b7579f77SDag-Erling Smørgrav size_t listen_num = list*listen_ifs; 193*b7579f77SDag-Erling Smørgrav size_t outudpnum = (size_t)cfg->outgoing_num_ports; 194*b7579f77SDag-Erling Smørgrav size_t outtcpnum = cfg->outgoing_num_tcp; 195*b7579f77SDag-Erling Smørgrav size_t misc = 4; /* logfile, pidfile, stdout... */ 196*b7579f77SDag-Erling Smørgrav size_t perthread_noudp = listen_num + outtcpnum + 197*b7579f77SDag-Erling Smørgrav 2/*cmdpipe*/ + 2/*libevent*/ + misc; 198*b7579f77SDag-Erling Smørgrav size_t perthread = perthread_noudp + outudpnum; 199*b7579f77SDag-Erling Smørgrav 200*b7579f77SDag-Erling Smørgrav #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) 201*b7579f77SDag-Erling Smørgrav int numthread = 1; /* it forks */ 202*b7579f77SDag-Erling Smørgrav #else 203*b7579f77SDag-Erling Smørgrav int numthread = (cfg->num_threads?cfg->num_threads:1); 204*b7579f77SDag-Erling Smørgrav #endif 205*b7579f77SDag-Erling Smørgrav size_t total = numthread * perthread + misc; 206*b7579f77SDag-Erling Smørgrav size_t avail; 207*b7579f77SDag-Erling Smørgrav struct rlimit rlim; 208*b7579f77SDag-Erling Smørgrav 209*b7579f77SDag-Erling Smørgrav if(total > 1024 && 210*b7579f77SDag-Erling Smørgrav strncmp(event_get_version(), "mini-event", 10) == 0) { 211*b7579f77SDag-Erling Smørgrav log_warn("too many file descriptors requested. The builtin" 212*b7579f77SDag-Erling Smørgrav "mini-event cannot handle more than 1024. Config " 213*b7579f77SDag-Erling Smørgrav "for less fds or compile with libevent"); 214*b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > 1024) 215*b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 216*b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((1024 217*b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 218*b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 219*b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 220*b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 221*b7579f77SDag-Erling Smørgrav total = 1024; 222*b7579f77SDag-Erling Smørgrav } 223*b7579f77SDag-Erling Smørgrav if(perthread > 64 && 224*b7579f77SDag-Erling Smørgrav strncmp(event_get_version(), "winsock-event", 13) == 0) { 225*b7579f77SDag-Erling Smørgrav log_err("too many file descriptors requested. The winsock" 226*b7579f77SDag-Erling Smørgrav " event handler cannot handle more than 64 per " 227*b7579f77SDag-Erling Smørgrav " thread. Config for less fds"); 228*b7579f77SDag-Erling Smørgrav if(perthread_noudp+2 > 64) 229*b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 230*b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((64 231*b7579f77SDag-Erling Smørgrav - perthread_noudp 232*b7579f77SDag-Erling Smørgrav - 2/* safety margin */)); 233*b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 234*b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 235*b7579f77SDag-Erling Smørgrav total = numthread*(perthread_noudp+ 236*b7579f77SDag-Erling Smørgrav (size_t)cfg->outgoing_num_ports)+misc; 237*b7579f77SDag-Erling Smørgrav } 238*b7579f77SDag-Erling Smørgrav if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 239*b7579f77SDag-Erling Smørgrav log_warn("getrlimit: %s", strerror(errno)); 240*b7579f77SDag-Erling Smørgrav return; 241*b7579f77SDag-Erling Smørgrav } 242*b7579f77SDag-Erling Smørgrav if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY) 243*b7579f77SDag-Erling Smørgrav return; 244*b7579f77SDag-Erling Smørgrav if((size_t)rlim.rlim_cur < total) { 245*b7579f77SDag-Erling Smørgrav avail = (size_t)rlim.rlim_cur; 246*b7579f77SDag-Erling Smørgrav rlim.rlim_cur = (rlim_t)(total + 10); 247*b7579f77SDag-Erling Smørgrav rlim.rlim_max = (rlim_t)(total + 10); 248*b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRLIMIT 249*b7579f77SDag-Erling Smørgrav if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) { 250*b7579f77SDag-Erling Smørgrav log_warn("setrlimit: %s", strerror(errno)); 251*b7579f77SDag-Erling Smørgrav #else 252*b7579f77SDag-Erling Smørgrav if(1) { 253*b7579f77SDag-Erling Smørgrav #endif 254*b7579f77SDag-Erling Smørgrav log_warn("cannot increase max open fds from %u to %u", 255*b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 256*b7579f77SDag-Erling Smørgrav /* check that calculation below does not underflow, 257*b7579f77SDag-Erling Smørgrav * with 15 as margin */ 258*b7579f77SDag-Erling Smørgrav if(numthread*perthread_noudp+15 > avail) 259*b7579f77SDag-Erling Smørgrav fatal_exit("too much tcp. not enough fds."); 260*b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports = (int)((avail 261*b7579f77SDag-Erling Smørgrav - numthread*perthread_noudp 262*b7579f77SDag-Erling Smørgrav - 10 /* safety margin */) /numthread); 263*b7579f77SDag-Erling Smørgrav log_warn("continuing with less udp ports: %u", 264*b7579f77SDag-Erling Smørgrav cfg->outgoing_num_ports); 265*b7579f77SDag-Erling Smørgrav log_warn("increase ulimit or decrease threads, " 266*b7579f77SDag-Erling Smørgrav "ports in config to remove this warning"); 267*b7579f77SDag-Erling Smørgrav return; 268*b7579f77SDag-Erling Smørgrav } 269*b7579f77SDag-Erling Smørgrav log_warn("increased limit(open files) from %u to %u", 270*b7579f77SDag-Erling Smørgrav (unsigned)avail, (unsigned)total+10); 271*b7579f77SDag-Erling Smørgrav } 272*b7579f77SDag-Erling Smørgrav #else 273*b7579f77SDag-Erling Smørgrav (void)cfg; 274*b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETRLIMIT */ 275*b7579f77SDag-Erling Smørgrav } 276*b7579f77SDag-Erling Smørgrav 277*b7579f77SDag-Erling Smørgrav /** set verbosity, check rlimits, cache settings */ 278*b7579f77SDag-Erling Smørgrav static void 279*b7579f77SDag-Erling Smørgrav apply_settings(struct daemon* daemon, struct config_file* cfg, 280*b7579f77SDag-Erling Smørgrav int cmdline_verbose) 281*b7579f77SDag-Erling Smørgrav { 282*b7579f77SDag-Erling Smørgrav /* apply if they have changed */ 283*b7579f77SDag-Erling Smørgrav verbosity = cmdline_verbose + cfg->verbosity; 284*b7579f77SDag-Erling Smørgrav daemon_apply_cfg(daemon, cfg); 285*b7579f77SDag-Erling Smørgrav checkrlimits(cfg); 286*b7579f77SDag-Erling Smørgrav } 287*b7579f77SDag-Erling Smørgrav 288*b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 289*b7579f77SDag-Erling Smørgrav /** Read existing pid from pidfile. 290*b7579f77SDag-Erling Smørgrav * @param file: file name of pid file. 291*b7579f77SDag-Erling Smørgrav * @return: the pid from the file or -1 if none. 292*b7579f77SDag-Erling Smørgrav */ 293*b7579f77SDag-Erling Smørgrav static pid_t 294*b7579f77SDag-Erling Smørgrav readpid (const char* file) 295*b7579f77SDag-Erling Smørgrav { 296*b7579f77SDag-Erling Smørgrav int fd; 297*b7579f77SDag-Erling Smørgrav pid_t pid; 298*b7579f77SDag-Erling Smørgrav char pidbuf[32]; 299*b7579f77SDag-Erling Smørgrav char* t; 300*b7579f77SDag-Erling Smørgrav ssize_t l; 301*b7579f77SDag-Erling Smørgrav 302*b7579f77SDag-Erling Smørgrav if ((fd = open(file, O_RDONLY)) == -1) { 303*b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 304*b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 305*b7579f77SDag-Erling Smørgrav file, strerror(errno)); 306*b7579f77SDag-Erling Smørgrav return -1; 307*b7579f77SDag-Erling Smørgrav } 308*b7579f77SDag-Erling Smørgrav 309*b7579f77SDag-Erling Smørgrav if (((l = read(fd, pidbuf, sizeof(pidbuf)))) == -1) { 310*b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 311*b7579f77SDag-Erling Smørgrav log_err("Could not read pidfile %s: %s", 312*b7579f77SDag-Erling Smørgrav file, strerror(errno)); 313*b7579f77SDag-Erling Smørgrav close(fd); 314*b7579f77SDag-Erling Smørgrav return -1; 315*b7579f77SDag-Erling Smørgrav } 316*b7579f77SDag-Erling Smørgrav 317*b7579f77SDag-Erling Smørgrav close(fd); 318*b7579f77SDag-Erling Smørgrav 319*b7579f77SDag-Erling Smørgrav /* Empty pidfile means no pidfile... */ 320*b7579f77SDag-Erling Smørgrav if (l == 0) { 321*b7579f77SDag-Erling Smørgrav return -1; 322*b7579f77SDag-Erling Smørgrav } 323*b7579f77SDag-Erling Smørgrav 324*b7579f77SDag-Erling Smørgrav pidbuf[sizeof(pidbuf)-1] = 0; 325*b7579f77SDag-Erling Smørgrav pid = (pid_t)strtol(pidbuf, &t, 10); 326*b7579f77SDag-Erling Smørgrav 327*b7579f77SDag-Erling Smørgrav if (*t && *t != '\n') { 328*b7579f77SDag-Erling Smørgrav return -1; 329*b7579f77SDag-Erling Smørgrav } 330*b7579f77SDag-Erling Smørgrav return pid; 331*b7579f77SDag-Erling Smørgrav } 332*b7579f77SDag-Erling Smørgrav 333*b7579f77SDag-Erling Smørgrav /** write pid to file. 334*b7579f77SDag-Erling Smørgrav * @param pidfile: file name of pid file. 335*b7579f77SDag-Erling Smørgrav * @param pid: pid to write to file. 336*b7579f77SDag-Erling Smørgrav */ 337*b7579f77SDag-Erling Smørgrav static void 338*b7579f77SDag-Erling Smørgrav writepid (const char* pidfile, pid_t pid) 339*b7579f77SDag-Erling Smørgrav { 340*b7579f77SDag-Erling Smørgrav FILE* f; 341*b7579f77SDag-Erling Smørgrav 342*b7579f77SDag-Erling Smørgrav if ((f = fopen(pidfile, "w")) == NULL ) { 343*b7579f77SDag-Erling Smørgrav log_err("cannot open pidfile %s: %s", 344*b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 345*b7579f77SDag-Erling Smørgrav return; 346*b7579f77SDag-Erling Smørgrav } 347*b7579f77SDag-Erling Smørgrav if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) { 348*b7579f77SDag-Erling Smørgrav log_err("cannot write to pidfile %s: %s", 349*b7579f77SDag-Erling Smørgrav pidfile, strerror(errno)); 350*b7579f77SDag-Erling Smørgrav } 351*b7579f77SDag-Erling Smørgrav fclose(f); 352*b7579f77SDag-Erling Smørgrav } 353*b7579f77SDag-Erling Smørgrav 354*b7579f77SDag-Erling Smørgrav /** 355*b7579f77SDag-Erling Smørgrav * check old pid file. 356*b7579f77SDag-Erling Smørgrav * @param pidfile: the file name of the pid file. 357*b7579f77SDag-Erling Smørgrav * @param inchroot: if pidfile is inchroot and we can thus expect to 358*b7579f77SDag-Erling Smørgrav * be able to delete it. 359*b7579f77SDag-Erling Smørgrav */ 360*b7579f77SDag-Erling Smørgrav static void 361*b7579f77SDag-Erling Smørgrav checkoldpid(char* pidfile, int inchroot) 362*b7579f77SDag-Erling Smørgrav { 363*b7579f77SDag-Erling Smørgrav pid_t old; 364*b7579f77SDag-Erling Smørgrav if((old = readpid(pidfile)) != -1) { 365*b7579f77SDag-Erling Smørgrav /* see if it is still alive */ 366*b7579f77SDag-Erling Smørgrav if(kill(old, 0) == 0 || errno == EPERM) 367*b7579f77SDag-Erling Smørgrav log_warn("unbound is already running as pid %u.", 368*b7579f77SDag-Erling Smørgrav (unsigned)old); 369*b7579f77SDag-Erling Smørgrav else if(inchroot) 370*b7579f77SDag-Erling Smørgrav log_warn("did not exit gracefully last time (%u)", 371*b7579f77SDag-Erling Smørgrav (unsigned)old); 372*b7579f77SDag-Erling Smørgrav } 373*b7579f77SDag-Erling Smørgrav } 374*b7579f77SDag-Erling Smørgrav #endif /* HAVE_KILL */ 375*b7579f77SDag-Erling Smørgrav 376*b7579f77SDag-Erling Smørgrav /** detach from command line */ 377*b7579f77SDag-Erling Smørgrav static void 378*b7579f77SDag-Erling Smørgrav detach(void) 379*b7579f77SDag-Erling Smørgrav { 380*b7579f77SDag-Erling Smørgrav #if defined(HAVE_DAEMON) && !defined(DEPRECATED_DAEMON) 381*b7579f77SDag-Erling Smørgrav /* use POSIX daemon(3) function */ 382*b7579f77SDag-Erling Smørgrav if(daemon(1, 0) != 0) 383*b7579f77SDag-Erling Smørgrav fatal_exit("daemon failed: %s", strerror(errno)); 384*b7579f77SDag-Erling Smørgrav #else /* no HAVE_DAEMON */ 385*b7579f77SDag-Erling Smørgrav #ifdef HAVE_FORK 386*b7579f77SDag-Erling Smørgrav int fd; 387*b7579f77SDag-Erling Smørgrav /* Take off... */ 388*b7579f77SDag-Erling Smørgrav switch (fork()) { 389*b7579f77SDag-Erling Smørgrav case 0: 390*b7579f77SDag-Erling Smørgrav break; 391*b7579f77SDag-Erling Smørgrav case -1: 392*b7579f77SDag-Erling Smørgrav fatal_exit("fork failed: %s", strerror(errno)); 393*b7579f77SDag-Erling Smørgrav default: 394*b7579f77SDag-Erling Smørgrav /* exit interactive session */ 395*b7579f77SDag-Erling Smørgrav exit(0); 396*b7579f77SDag-Erling Smørgrav } 397*b7579f77SDag-Erling Smørgrav /* detach */ 398*b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETSID 399*b7579f77SDag-Erling Smørgrav if(setsid() == -1) 400*b7579f77SDag-Erling Smørgrav fatal_exit("setsid() failed: %s", strerror(errno)); 401*b7579f77SDag-Erling Smørgrav #endif 402*b7579f77SDag-Erling Smørgrav if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { 403*b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDIN_FILENO); 404*b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDOUT_FILENO); 405*b7579f77SDag-Erling Smørgrav (void)dup2(fd, STDERR_FILENO); 406*b7579f77SDag-Erling Smørgrav if (fd > 2) 407*b7579f77SDag-Erling Smørgrav (void)close(fd); 408*b7579f77SDag-Erling Smørgrav } 409*b7579f77SDag-Erling Smørgrav #endif /* HAVE_FORK */ 410*b7579f77SDag-Erling Smørgrav #endif /* HAVE_DAEMON */ 411*b7579f77SDag-Erling Smørgrav } 412*b7579f77SDag-Erling Smørgrav 413*b7579f77SDag-Erling Smørgrav /** daemonize, drop user priviliges and chroot if needed */ 414*b7579f77SDag-Erling Smørgrav static void 415*b7579f77SDag-Erling Smørgrav perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, 416*b7579f77SDag-Erling Smørgrav const char** cfgfile) 417*b7579f77SDag-Erling Smørgrav { 418*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 419*b7579f77SDag-Erling Smørgrav struct passwd *pwd = NULL; 420*b7579f77SDag-Erling Smørgrav uid_t uid; 421*b7579f77SDag-Erling Smørgrav gid_t gid; 422*b7579f77SDag-Erling Smørgrav /* initialize, but not to 0 (root) */ 423*b7579f77SDag-Erling Smørgrav memset(&uid, 112, sizeof(uid)); 424*b7579f77SDag-Erling Smørgrav memset(&gid, 112, sizeof(gid)); 425*b7579f77SDag-Erling Smørgrav log_assert(cfg); 426*b7579f77SDag-Erling Smørgrav 427*b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 428*b7579f77SDag-Erling Smørgrav if((pwd = getpwnam(cfg->username)) == NULL) 429*b7579f77SDag-Erling Smørgrav fatal_exit("user '%s' does not exist.", cfg->username); 430*b7579f77SDag-Erling Smørgrav uid = pwd->pw_uid; 431*b7579f77SDag-Erling Smørgrav gid = pwd->pw_gid; 432*b7579f77SDag-Erling Smørgrav /* endpwent below, in case we need pwd for setusercontext */ 433*b7579f77SDag-Erling Smørgrav } 434*b7579f77SDag-Erling Smørgrav #endif 435*b7579f77SDag-Erling Smørgrav 436*b7579f77SDag-Erling Smørgrav /* init syslog (as root) if needed, before daemonize, otherwise 437*b7579f77SDag-Erling Smørgrav * a fork error could not be printed since daemonize closed stderr.*/ 438*b7579f77SDag-Erling Smørgrav if(cfg->use_syslog) { 439*b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 440*b7579f77SDag-Erling Smørgrav } 441*b7579f77SDag-Erling Smørgrav /* if using a logfile, we cannot open it because the logfile would 442*b7579f77SDag-Erling Smørgrav * be created with the wrong permissions, we cannot chown it because 443*b7579f77SDag-Erling Smørgrav * we cannot chown system logfiles, so we do not open at all. 444*b7579f77SDag-Erling Smørgrav * So, using a logfile, the user does not see errors unless -d is 445*b7579f77SDag-Erling Smørgrav * given to unbound on the commandline. */ 446*b7579f77SDag-Erling Smørgrav 447*b7579f77SDag-Erling Smørgrav /* read ssl keys while superuser and outside chroot */ 448*b7579f77SDag-Erling Smørgrav if(!(daemon->rc = daemon_remote_create(cfg))) 449*b7579f77SDag-Erling Smørgrav fatal_exit("could not set up remote-control"); 450*b7579f77SDag-Erling Smørgrav if(cfg->ssl_service_key && cfg->ssl_service_key[0]) { 451*b7579f77SDag-Erling Smørgrav if(!(daemon->listen_sslctx = listen_sslctx_create( 452*b7579f77SDag-Erling Smørgrav cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) 453*b7579f77SDag-Erling Smørgrav fatal_exit("could not set up listen SSL_CTX"); 454*b7579f77SDag-Erling Smørgrav } 455*b7579f77SDag-Erling Smørgrav if(!(daemon->connect_sslctx = connect_sslctx_create(NULL, NULL, NULL))) 456*b7579f77SDag-Erling Smørgrav fatal_exit("could not set up connect SSL_CTX"); 457*b7579f77SDag-Erling Smørgrav 458*b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 459*b7579f77SDag-Erling Smørgrav /* check old pid file before forking */ 460*b7579f77SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0]) { 461*b7579f77SDag-Erling Smørgrav /* calculate position of pidfile */ 462*b7579f77SDag-Erling Smørgrav if(cfg->pidfile[0] == '/') 463*b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(cfg->pidfile); 464*b7579f77SDag-Erling Smørgrav else daemon->pidfile = fname_after_chroot(cfg->pidfile, 465*b7579f77SDag-Erling Smørgrav cfg, 1); 466*b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 467*b7579f77SDag-Erling Smørgrav fatal_exit("pidfile alloc: out of memory"); 468*b7579f77SDag-Erling Smørgrav checkoldpid(daemon->pidfile, 469*b7579f77SDag-Erling Smørgrav /* true if pidfile is inside chrootdir, or nochroot */ 470*b7579f77SDag-Erling Smørgrav !(cfg->chrootdir && cfg->chrootdir[0]) || 471*b7579f77SDag-Erling Smørgrav (cfg->chrootdir && cfg->chrootdir[0] && 472*b7579f77SDag-Erling Smørgrav strncmp(daemon->pidfile, cfg->chrootdir, 473*b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir))==0)); 474*b7579f77SDag-Erling Smørgrav } 475*b7579f77SDag-Erling Smørgrav #endif 476*b7579f77SDag-Erling Smørgrav 477*b7579f77SDag-Erling Smørgrav /* daemonize because pid is needed by the writepid func */ 478*b7579f77SDag-Erling Smørgrav if(!debug_mode && cfg->do_daemonize) { 479*b7579f77SDag-Erling Smørgrav detach(); 480*b7579f77SDag-Erling Smørgrav } 481*b7579f77SDag-Erling Smørgrav 482*b7579f77SDag-Erling Smørgrav /* write new pidfile (while still root, so can be outside chroot) */ 483*b7579f77SDag-Erling Smørgrav #ifdef HAVE_KILL 484*b7579f77SDag-Erling Smørgrav if(cfg->pidfile && cfg->pidfile[0]) { 485*b7579f77SDag-Erling Smørgrav writepid(daemon->pidfile, getpid()); 486*b7579f77SDag-Erling Smørgrav if(!(cfg->chrootdir && cfg->chrootdir[0]) || 487*b7579f77SDag-Erling Smørgrav (cfg->chrootdir && cfg->chrootdir[0] && 488*b7579f77SDag-Erling Smørgrav strncmp(daemon->pidfile, cfg->chrootdir, 489*b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir))==0)) { 490*b7579f77SDag-Erling Smørgrav /* delete of pidfile could potentially work, 491*b7579f77SDag-Erling Smørgrav * chown to get permissions */ 492*b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 493*b7579f77SDag-Erling Smørgrav if(chown(daemon->pidfile, uid, gid) == -1) { 494*b7579f77SDag-Erling Smørgrav log_err("cannot chown %u.%u %s: %s", 495*b7579f77SDag-Erling Smørgrav (unsigned)uid, (unsigned)gid, 496*b7579f77SDag-Erling Smørgrav daemon->pidfile, strerror(errno)); 497*b7579f77SDag-Erling Smørgrav } 498*b7579f77SDag-Erling Smørgrav } 499*b7579f77SDag-Erling Smørgrav } 500*b7579f77SDag-Erling Smørgrav } 501*b7579f77SDag-Erling Smørgrav #else 502*b7579f77SDag-Erling Smørgrav (void)daemon; 503*b7579f77SDag-Erling Smørgrav #endif 504*b7579f77SDag-Erling Smørgrav 505*b7579f77SDag-Erling Smørgrav /* Set user context */ 506*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 507*b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 508*b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETUSERCONTEXT 509*b7579f77SDag-Erling Smørgrav /* setusercontext does initgroups, setuid, setgid, and 510*b7579f77SDag-Erling Smørgrav * also resource limits from login config, but we 511*b7579f77SDag-Erling Smørgrav * still call setresuid, setresgid to be sure to set all uid*/ 512*b7579f77SDag-Erling Smørgrav if(setusercontext(NULL, pwd, uid, 513*b7579f77SDag-Erling Smørgrav LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0) 514*b7579f77SDag-Erling Smørgrav log_warn("unable to setusercontext %s: %s", 515*b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 516*b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETUSERCONTEXT */ 517*b7579f77SDag-Erling Smørgrav } 518*b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 519*b7579f77SDag-Erling Smørgrav 520*b7579f77SDag-Erling Smørgrav /* box into the chroot */ 521*b7579f77SDag-Erling Smørgrav #ifdef HAVE_CHROOT 522*b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0]) { 523*b7579f77SDag-Erling Smørgrav if(chdir(cfg->chrootdir)) { 524*b7579f77SDag-Erling Smørgrav fatal_exit("unable to chdir to chroot %s: %s", 525*b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 526*b7579f77SDag-Erling Smørgrav } 527*b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", cfg->chrootdir); 528*b7579f77SDag-Erling Smørgrav if(chroot(cfg->chrootdir)) 529*b7579f77SDag-Erling Smørgrav fatal_exit("unable to chroot to %s: %s", 530*b7579f77SDag-Erling Smørgrav cfg->chrootdir, strerror(errno)); 531*b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chroot to %s", cfg->chrootdir); 532*b7579f77SDag-Erling Smørgrav if(strncmp(*cfgfile, cfg->chrootdir, 533*b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 534*b7579f77SDag-Erling Smørgrav (*cfgfile) += strlen(cfg->chrootdir); 535*b7579f77SDag-Erling Smørgrav 536*b7579f77SDag-Erling Smørgrav /* adjust stored pidfile for chroot */ 537*b7579f77SDag-Erling Smørgrav if(daemon->pidfile && daemon->pidfile[0] && 538*b7579f77SDag-Erling Smørgrav strncmp(daemon->pidfile, cfg->chrootdir, 539*b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir))==0) { 540*b7579f77SDag-Erling Smørgrav char* old = daemon->pidfile; 541*b7579f77SDag-Erling Smørgrav daemon->pidfile = strdup(old+strlen(cfg->chrootdir)); 542*b7579f77SDag-Erling Smørgrav free(old); 543*b7579f77SDag-Erling Smørgrav if(!daemon->pidfile) 544*b7579f77SDag-Erling Smørgrav log_err("out of memory in pidfile adjust"); 545*b7579f77SDag-Erling Smørgrav } 546*b7579f77SDag-Erling Smørgrav daemon->chroot = strdup(cfg->chrootdir); 547*b7579f77SDag-Erling Smørgrav if(!daemon->chroot) 548*b7579f77SDag-Erling Smørgrav log_err("out of memory in daemon chroot dir storage"); 549*b7579f77SDag-Erling Smørgrav } 550*b7579f77SDag-Erling Smørgrav #else 551*b7579f77SDag-Erling Smørgrav (void)cfgfile; 552*b7579f77SDag-Erling Smørgrav #endif 553*b7579f77SDag-Erling Smørgrav /* change to working directory inside chroot */ 554*b7579f77SDag-Erling Smørgrav if(cfg->directory && cfg->directory[0]) { 555*b7579f77SDag-Erling Smørgrav char* dir = cfg->directory; 556*b7579f77SDag-Erling Smørgrav if(cfg->chrootdir && cfg->chrootdir[0] && 557*b7579f77SDag-Erling Smørgrav strncmp(dir, cfg->chrootdir, 558*b7579f77SDag-Erling Smørgrav strlen(cfg->chrootdir)) == 0) 559*b7579f77SDag-Erling Smørgrav dir += strlen(cfg->chrootdir); 560*b7579f77SDag-Erling Smørgrav if(dir[0]) { 561*b7579f77SDag-Erling Smørgrav if(chdir(dir)) { 562*b7579f77SDag-Erling Smørgrav fatal_exit("Could not chdir to %s: %s", 563*b7579f77SDag-Erling Smørgrav dir, strerror(errno)); 564*b7579f77SDag-Erling Smørgrav } 565*b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "chdir to %s", dir); 566*b7579f77SDag-Erling Smørgrav } 567*b7579f77SDag-Erling Smørgrav } 568*b7579f77SDag-Erling Smørgrav 569*b7579f77SDag-Erling Smørgrav /* drop permissions after chroot, getpwnam, pidfile, syslog done*/ 570*b7579f77SDag-Erling Smørgrav #ifdef HAVE_GETPWNAM 571*b7579f77SDag-Erling Smørgrav if(cfg->username && cfg->username[0]) { 572*b7579f77SDag-Erling Smørgrav # ifdef HAVE_INITGROUPS 573*b7579f77SDag-Erling Smørgrav if(initgroups(cfg->username, gid) != 0) 574*b7579f77SDag-Erling Smørgrav log_warn("unable to initgroups %s: %s", 575*b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 576*b7579f77SDag-Erling Smørgrav # endif /* HAVE_INITGROUPS */ 577*b7579f77SDag-Erling Smørgrav endpwent(); 578*b7579f77SDag-Erling Smørgrav 579*b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESGID 580*b7579f77SDag-Erling Smørgrav if(setresgid(gid,gid,gid) != 0) 581*b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID) 582*b7579f77SDag-Erling Smørgrav if(setregid(gid,gid) != 0) 583*b7579f77SDag-Erling Smørgrav #else /* use setgid */ 584*b7579f77SDag-Erling Smørgrav if(setgid(gid) != 0) 585*b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESGID */ 586*b7579f77SDag-Erling Smørgrav fatal_exit("unable to set group id of %s: %s", 587*b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 588*b7579f77SDag-Erling Smørgrav #ifdef HAVE_SETRESUID 589*b7579f77SDag-Erling Smørgrav if(setresuid(uid,uid,uid) != 0) 590*b7579f77SDag-Erling Smørgrav #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID) 591*b7579f77SDag-Erling Smørgrav if(setreuid(uid,uid) != 0) 592*b7579f77SDag-Erling Smørgrav #else /* use setuid */ 593*b7579f77SDag-Erling Smørgrav if(setuid(uid) != 0) 594*b7579f77SDag-Erling Smørgrav #endif /* HAVE_SETRESUID */ 595*b7579f77SDag-Erling Smørgrav fatal_exit("unable to set user id of %s: %s", 596*b7579f77SDag-Erling Smørgrav cfg->username, strerror(errno)); 597*b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "drop user privileges, run as %s", 598*b7579f77SDag-Erling Smørgrav cfg->username); 599*b7579f77SDag-Erling Smørgrav } 600*b7579f77SDag-Erling Smørgrav #endif /* HAVE_GETPWNAM */ 601*b7579f77SDag-Erling Smørgrav /* file logging inited after chroot,chdir,setuid is done so that 602*b7579f77SDag-Erling Smørgrav * it would succeed on SIGHUP as well */ 603*b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 604*b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); 605*b7579f77SDag-Erling Smørgrav } 606*b7579f77SDag-Erling Smørgrav 607*b7579f77SDag-Erling Smørgrav /** 608*b7579f77SDag-Erling Smørgrav * Run the daemon. 609*b7579f77SDag-Erling Smørgrav * @param cfgfile: the config file name. 610*b7579f77SDag-Erling Smørgrav * @param cmdline_verbose: verbosity resulting from commandline -v. 611*b7579f77SDag-Erling Smørgrav * These increase verbosity as specified in the config file. 612*b7579f77SDag-Erling Smørgrav * @param debug_mode: if set, do not daemonize. 613*b7579f77SDag-Erling Smørgrav */ 614*b7579f77SDag-Erling Smørgrav static void 615*b7579f77SDag-Erling Smørgrav run_daemon(const char* cfgfile, int cmdline_verbose, int debug_mode) 616*b7579f77SDag-Erling Smørgrav { 617*b7579f77SDag-Erling Smørgrav struct config_file* cfg = NULL; 618*b7579f77SDag-Erling Smørgrav struct daemon* daemon = NULL; 619*b7579f77SDag-Erling Smørgrav int done_setup = 0; 620*b7579f77SDag-Erling Smørgrav 621*b7579f77SDag-Erling Smørgrav if(!(daemon = daemon_init())) 622*b7579f77SDag-Erling Smørgrav fatal_exit("alloc failure"); 623*b7579f77SDag-Erling Smørgrav while(!daemon->need_to_exit) { 624*b7579f77SDag-Erling Smørgrav if(done_setup) 625*b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "Restart of %s.", PACKAGE_STRING); 626*b7579f77SDag-Erling Smørgrav else verbose(VERB_OPS, "Start of %s.", PACKAGE_STRING); 627*b7579f77SDag-Erling Smørgrav 628*b7579f77SDag-Erling Smørgrav /* config stuff */ 629*b7579f77SDag-Erling Smørgrav if(!(cfg = config_create())) 630*b7579f77SDag-Erling Smørgrav fatal_exit("Could not alloc config defaults"); 631*b7579f77SDag-Erling Smørgrav if(!config_read(cfg, cfgfile, daemon->chroot)) { 632*b7579f77SDag-Erling Smørgrav if(errno != ENOENT) 633*b7579f77SDag-Erling Smørgrav fatal_exit("Could not read config file: %s", 634*b7579f77SDag-Erling Smørgrav cfgfile); 635*b7579f77SDag-Erling Smørgrav log_warn("Continuing with default config settings"); 636*b7579f77SDag-Erling Smørgrav } 637*b7579f77SDag-Erling Smørgrav apply_settings(daemon, cfg, cmdline_verbose); 638*b7579f77SDag-Erling Smørgrav 639*b7579f77SDag-Erling Smørgrav /* prepare */ 640*b7579f77SDag-Erling Smørgrav if(!daemon_open_shared_ports(daemon)) 641*b7579f77SDag-Erling Smørgrav fatal_exit("could not open ports"); 642*b7579f77SDag-Erling Smørgrav if(!done_setup) { 643*b7579f77SDag-Erling Smørgrav perform_setup(daemon, cfg, debug_mode, &cfgfile); 644*b7579f77SDag-Erling Smørgrav done_setup = 1; 645*b7579f77SDag-Erling Smørgrav } else { 646*b7579f77SDag-Erling Smørgrav /* reopen log after HUP to facilitate log rotation */ 647*b7579f77SDag-Erling Smørgrav if(!cfg->use_syslog) 648*b7579f77SDag-Erling Smørgrav log_init(cfg->logfile, 0, cfg->chrootdir); 649*b7579f77SDag-Erling Smørgrav } 650*b7579f77SDag-Erling Smørgrav /* work */ 651*b7579f77SDag-Erling Smørgrav daemon_fork(daemon); 652*b7579f77SDag-Erling Smørgrav 653*b7579f77SDag-Erling Smørgrav /* clean up for restart */ 654*b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "cleanup."); 655*b7579f77SDag-Erling Smørgrav daemon_cleanup(daemon); 656*b7579f77SDag-Erling Smørgrav config_delete(cfg); 657*b7579f77SDag-Erling Smørgrav } 658*b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Exit cleanup."); 659*b7579f77SDag-Erling Smørgrav /* this unlink may not work if the pidfile is located outside 660*b7579f77SDag-Erling Smørgrav * of the chroot/workdir or we no longer have permissions */ 661*b7579f77SDag-Erling Smørgrav if(daemon->pidfile) { 662*b7579f77SDag-Erling Smørgrav int fd; 663*b7579f77SDag-Erling Smørgrav /* truncate pidfile */ 664*b7579f77SDag-Erling Smørgrav fd = open(daemon->pidfile, O_WRONLY | O_TRUNC, 0644); 665*b7579f77SDag-Erling Smørgrav if(fd != -1) 666*b7579f77SDag-Erling Smørgrav close(fd); 667*b7579f77SDag-Erling Smørgrav /* delete pidfile */ 668*b7579f77SDag-Erling Smørgrav unlink(daemon->pidfile); 669*b7579f77SDag-Erling Smørgrav } 670*b7579f77SDag-Erling Smørgrav daemon_delete(daemon); 671*b7579f77SDag-Erling Smørgrav } 672*b7579f77SDag-Erling Smørgrav 673*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 674*b7579f77SDag-Erling Smørgrav extern int optind; 675*b7579f77SDag-Erling Smørgrav /** getopt global, in case header files fail to declare it. */ 676*b7579f77SDag-Erling Smørgrav extern char* optarg; 677*b7579f77SDag-Erling Smørgrav 678*b7579f77SDag-Erling Smørgrav /** 679*b7579f77SDag-Erling Smørgrav * main program. Set options given commandline arguments. 680*b7579f77SDag-Erling Smørgrav * @param argc: number of commandline arguments. 681*b7579f77SDag-Erling Smørgrav * @param argv: array of commandline arguments. 682*b7579f77SDag-Erling Smørgrav * @return: exit status of the program. 683*b7579f77SDag-Erling Smørgrav */ 684*b7579f77SDag-Erling Smørgrav int 685*b7579f77SDag-Erling Smørgrav main(int argc, char* argv[]) 686*b7579f77SDag-Erling Smørgrav { 687*b7579f77SDag-Erling Smørgrav int c; 688*b7579f77SDag-Erling Smørgrav const char* cfgfile = CONFIGFILE; 689*b7579f77SDag-Erling Smørgrav const char* winopt = NULL; 690*b7579f77SDag-Erling Smørgrav int cmdline_verbose = 0; 691*b7579f77SDag-Erling Smørgrav int debug_mode = 0; 692*b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 693*b7579f77SDag-Erling Smørgrav int cmdline_cfg = 0; 694*b7579f77SDag-Erling Smørgrav #endif 695*b7579f77SDag-Erling Smørgrav 696*b7579f77SDag-Erling Smørgrav #ifdef HAVE_SBRK 697*b7579f77SDag-Erling Smørgrav /* take debug snapshot of heap */ 698*b7579f77SDag-Erling Smørgrav unbound_start_brk = sbrk(0); 699*b7579f77SDag-Erling Smørgrav #endif 700*b7579f77SDag-Erling Smørgrav 701*b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); 702*b7579f77SDag-Erling Smørgrav /* parse the options */ 703*b7579f77SDag-Erling Smørgrav while( (c=getopt(argc, argv, "c:dhvw:")) != -1) { 704*b7579f77SDag-Erling Smørgrav switch(c) { 705*b7579f77SDag-Erling Smørgrav case 'c': 706*b7579f77SDag-Erling Smørgrav cfgfile = optarg; 707*b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 708*b7579f77SDag-Erling Smørgrav cmdline_cfg = 1; 709*b7579f77SDag-Erling Smørgrav #endif 710*b7579f77SDag-Erling Smørgrav break; 711*b7579f77SDag-Erling Smørgrav case 'v': 712*b7579f77SDag-Erling Smørgrav cmdline_verbose ++; 713*b7579f77SDag-Erling Smørgrav verbosity++; 714*b7579f77SDag-Erling Smørgrav break; 715*b7579f77SDag-Erling Smørgrav case 'd': 716*b7579f77SDag-Erling Smørgrav debug_mode = 1; 717*b7579f77SDag-Erling Smørgrav break; 718*b7579f77SDag-Erling Smørgrav case 'w': 719*b7579f77SDag-Erling Smørgrav winopt = optarg; 720*b7579f77SDag-Erling Smørgrav break; 721*b7579f77SDag-Erling Smørgrav case '?': 722*b7579f77SDag-Erling Smørgrav case 'h': 723*b7579f77SDag-Erling Smørgrav default: 724*b7579f77SDag-Erling Smørgrav usage(); 725*b7579f77SDag-Erling Smørgrav return 1; 726*b7579f77SDag-Erling Smørgrav } 727*b7579f77SDag-Erling Smørgrav } 728*b7579f77SDag-Erling Smørgrav argc -= optind; 729*b7579f77SDag-Erling Smørgrav argv += optind; 730*b7579f77SDag-Erling Smørgrav 731*b7579f77SDag-Erling Smørgrav if(winopt) { 732*b7579f77SDag-Erling Smørgrav #ifdef UB_ON_WINDOWS 733*b7579f77SDag-Erling Smørgrav wsvc_command_option(winopt, cfgfile, cmdline_verbose, 734*b7579f77SDag-Erling Smørgrav cmdline_cfg); 735*b7579f77SDag-Erling Smørgrav #else 736*b7579f77SDag-Erling Smørgrav fatal_exit("option not supported"); 737*b7579f77SDag-Erling Smørgrav #endif 738*b7579f77SDag-Erling Smørgrav } 739*b7579f77SDag-Erling Smørgrav 740*b7579f77SDag-Erling Smørgrav if(argc != 0) { 741*b7579f77SDag-Erling Smørgrav usage(); 742*b7579f77SDag-Erling Smørgrav return 1; 743*b7579f77SDag-Erling Smørgrav } 744*b7579f77SDag-Erling Smørgrav 745*b7579f77SDag-Erling Smørgrav run_daemon(cfgfile, cmdline_verbose, debug_mode); 746*b7579f77SDag-Erling Smørgrav log_init(NULL, 0, NULL); /* close logfile */ 747*b7579f77SDag-Erling Smørgrav return 0; 748*b7579f77SDag-Erling Smørgrav } 749