1 /* 2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /* 6 * BSD 3 Clause License 7 * 8 * Copyright (c) 2007, The Storage Networking Industry Association. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * - Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * - Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * - Neither the name of The Storage Networking Industry Association (SNIA) 22 * nor the names of its contributors may be used to endorse or promote 23 * products derived from this software without specific prior written 24 * permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */ 39 40 #include <errno.h> 41 #include <signal.h> 42 #include <libgen.h> 43 #include <libscf.h> 44 #include <libintl.h> 45 #include <sys/wait.h> 46 #include <zone.h> 47 #include <tsol/label.h> 48 #include <dlfcn.h> 49 #include "ndmpd.h" 50 #include "ndmpd_common.h" 51 52 /* zfs library handle & mutex */ 53 libzfs_handle_t *zlibh; 54 mutex_t zlib_mtx; 55 void *mod_plp; 56 57 static void ndmpd_sig_handler(int sig); 58 59 typedef struct ndmpd { 60 int s_shutdown_flag; /* Fields for shutdown control */ 61 int s_sigval; 62 } ndmpd_t; 63 64 ndmpd_t ndmpd; 65 66 67 /* 68 * Load and initialize the plug-in module 69 */ 70 static int 71 mod_init() 72 { 73 char *plname; 74 ndmp_plugin_t *(*plugin_init)(int); 75 76 ndmp_pl = NULL; 77 if ((plname = ndmpd_get_prop(NDMP_PLUGIN_PATH)) == NULL) 78 return (0); 79 80 if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) { 81 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 82 return (0); 83 } 84 85 plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init"); 86 if (plugin_init == NULL) { 87 (void) dlclose(mod_plp); 88 return (0); 89 } 90 if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) { 91 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 92 return (-1); 93 } 94 return (0); 95 } 96 97 /* 98 * Unload 99 */ 100 static void 101 mod_fini() 102 { 103 if (ndmp_pl == NULL) 104 return; 105 106 void (*plugin_fini)(ndmp_plugin_t *); 107 108 plugin_fini = (void (*)(ndmp_plugin_t *))dlsym(mod_plp, "_ndmp_fini"); 109 if (plugin_fini == NULL) { 110 (void) dlclose(mod_plp); 111 return; 112 } 113 plugin_fini(ndmp_pl); 114 (void) dlclose(mod_plp); 115 } 116 117 static void 118 daemonize_init(char *arg) 119 { 120 sigset_t set, oset; 121 pid_t pid; 122 priv_set_t *pset = priv_allocset(); 123 124 /* 125 * Set effective sets privileges to 'least' required. If fails, send 126 * error messages to log file and proceed. 127 */ 128 if (pset != NULL) { 129 priv_basicset(pset); 130 (void) priv_addset(pset, PRIV_PROC_AUDIT); 131 (void) priv_addset(pset, PRIV_PROC_SETID); 132 (void) priv_addset(pset, PRIV_PROC_OWNER); 133 (void) priv_addset(pset, PRIV_FILE_CHOWN); 134 (void) priv_addset(pset, PRIV_FILE_CHOWN_SELF); 135 (void) priv_addset(pset, PRIV_FILE_DAC_READ); 136 (void) priv_addset(pset, PRIV_FILE_DAC_SEARCH); 137 (void) priv_addset(pset, PRIV_FILE_DAC_WRITE); 138 (void) priv_addset(pset, PRIV_FILE_OWNER); 139 (void) priv_addset(pset, PRIV_FILE_SETID); 140 (void) priv_addset(pset, PRIV_SYS_LINKDIR); 141 (void) priv_addset(pset, PRIV_SYS_DEVICES); 142 (void) priv_addset(pset, PRIV_SYS_MOUNT); 143 (void) priv_addset(pset, PRIV_SYS_CONFIG); 144 } 145 146 if (pset == NULL || setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) != 0) { 147 syslog(LOG_ERR, "Failed to set least required privileges to " 148 "the service."); 149 } 150 priv_freeset(pset); 151 152 /* 153 * Block all signals prior to the fork and leave them blocked in the 154 * parent so we don't get in a situation where the parent gets SIGINT 155 * and returns non-zero exit status and the child is actually running. 156 * In the child, restore the signal mask once we've done our setsid(). 157 */ 158 (void) sigfillset(&set); 159 (void) sigdelset(&set, SIGABRT); 160 (void) sigprocmask(SIG_BLOCK, &set, &oset); 161 162 if ((pid = fork()) == -1) { 163 openlog(arg, LOG_PID | LOG_NDELAY, LOG_DAEMON); 164 syslog(LOG_ERR, "Failed to start process in background."); 165 exit(SMF_EXIT_ERR_CONFIG); 166 } 167 168 /* If we're the parent process, exit. */ 169 if (pid != 0) { 170 _exit(0); 171 } 172 (void) setsid(); 173 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 174 (void) chdir("/"); 175 (void) umask(0); 176 } 177 178 static void 179 daemonize_fini(void) 180 { 181 int fd; 182 183 if ((fd = open("/dev/null", O_RDWR)) >= 0) { 184 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 185 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 186 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 187 (void) close(fd); 188 } 189 } 190 191 /* 192 * main 193 * 194 * The main NDMP daemon function 195 * 196 * Parameters: 197 * argc (input) - the argument count 198 * argv (input) - command line options 199 * 200 * Returns: 201 * 0 202 */ 203 int 204 main(int argc, char *argv[]) 205 { 206 char c; 207 struct sigaction act; 208 sigset_t set; 209 void *arg = 0; 210 211 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 212 213 /* 214 * Check for existing ndmpd door server (make sure ndmpd is not already 215 * running) 216 */ 217 if (ndmp_door_check()) { 218 /* ndmpd is already running, exit. */ 219 return (0); 220 } 221 222 /* load ENVs */ 223 if (ndmpd_load_prop()) { 224 syslog(LOG_ERR, 225 "%s SMF properties initialization failed.", argv[0]); 226 exit(SMF_EXIT_ERR_CONFIG); 227 } 228 229 /* Global zone check */ 230 if (getzoneid() != GLOBAL_ZONEID) { 231 syslog(LOG_ERR, "Local zone not supported."); 232 exit(SMF_EXIT_ERR_FATAL); 233 } 234 235 /* Trusted Solaris check */ 236 if (is_system_labeled()) { 237 syslog(LOG_ERR, "Trusted Solaris not supported."); 238 exit(SMF_EXIT_ERR_FATAL); 239 } 240 241 opterr = 0; 242 while ((c = getopt(argc, argv, ":d")) != -1) { 243 switch (c) { 244 case 'd': 245 (void) set_debug_level(TRUE); 246 break; 247 default: 248 syslog(LOG_ERR, "%s: Invalid option -%c.", 249 argv[0], optopt); 250 syslog(LOG_ERR, "Usage: %s [-d]", argv[0]); 251 exit(SMF_EXIT_ERR_CONFIG); 252 } 253 254 } 255 256 closelog(); 257 /* 258 * close any open file descriptors which are greater 259 * than STDERR_FILENO 260 */ 261 closefrom(STDERR_FILENO + 1); 262 263 /* set up signal handler */ 264 (void) sigfillset(&set); 265 (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */ 266 (void) sigfillset(&act.sa_mask); 267 act.sa_handler = ndmpd_sig_handler; 268 act.sa_flags = 0; 269 270 (void) sigaction(SIGTERM, &act, NULL); 271 (void) sigaction(SIGHUP, &act, NULL); 272 (void) sigaction(SIGINT, &act, NULL); 273 (void) sigaction(SIGUSR1, &act, NULL); 274 (void) sigaction(SIGPIPE, &act, NULL); 275 (void) sigdelset(&set, SIGTERM); 276 (void) sigdelset(&set, SIGHUP); 277 (void) sigdelset(&set, SIGINT); 278 (void) sigdelset(&set, SIGUSR1); 279 (void) sigdelset(&set, SIGPIPE); 280 281 (void) daemonize_init(argv[0]); 282 283 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 284 (void) mutex_init(&log_lock, 0, NULL); 285 (void) mutex_init(&ndmpd_zfs_fd_lock, 0, NULL); 286 287 if (mod_init() != 0) { 288 syslog(LOG_ERR, "Failed to load the plugin module."); 289 exit(SMF_EXIT_ERR_CONFIG); 290 } 291 292 /* libzfs init */ 293 if ((zlibh = libzfs_init()) == NULL) { 294 syslog(LOG_ERR, "Failed to initialize ZFS library."); 295 exit(SMF_EXIT_ERR_CONFIG); 296 } 297 298 /* initialize and start the door server */ 299 if (ndmp_door_init()) { 300 syslog(LOG_ERR, "Can not start ndmpd door server."); 301 exit(SMF_EXIT_ERR_CONFIG); 302 } 303 304 (void) tlm_init(); 305 306 /* 307 * Prior to this point, we are single-threaded. We will be 308 * multi-threaded from this point on. 309 */ 310 (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main, 311 (void *)&arg); 312 313 while (!ndmpd.s_shutdown_flag) { 314 (void) sigsuspend(&set); 315 316 switch (ndmpd.s_sigval) { 317 case 0: 318 break; 319 320 case SIGPIPE: 321 break; 322 323 case SIGHUP: 324 /* Refresh SMF properties */ 325 if (ndmpd_load_prop()) 326 syslog(LOG_ERR, 327 "Service properties initialization " 328 "failed."); 329 break; 330 331 default: 332 /* 333 * Typically SIGINT or SIGTERM. 334 */ 335 ndmpd.s_shutdown_flag = 1; 336 break; 337 } 338 339 ndmpd.s_sigval = 0; 340 } 341 342 (void) mutex_destroy(&ndmpd_zfs_fd_lock); 343 (void) mutex_destroy(&log_lock); 344 libzfs_fini(zlibh); 345 mod_fini(); 346 ndmp_door_fini(); 347 daemonize_fini(); 348 return (SMF_EXIT_OK); 349 } 350 351 static void 352 ndmpd_sig_handler(int sig) 353 { 354 if (ndmpd.s_sigval == 0) 355 ndmpd.s_sigval = sig; 356 } 357 358 /* 359 * Enable libumem debugging by default on DEBUG builds. 360 */ 361 #ifdef DEBUG 362 const char * 363 _umem_debug_init(void) 364 { 365 return ("default,verbose"); /* $UMEM_DEBUG setting */ 366 } 367 368 const char * 369 _umem_logging_init(void) 370 { 371 return ("fail,contents"); /* $UMEM_LOGGING setting */ 372 } 373 #endif 374