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