1 /* 2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 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 if ((plname = ndmpd_get_prop(NDMP_PLUGIN_PATH)) == NULL) 79 return (0); 80 81 if ((mod_plp = dlopen(plname, RTLD_LOCAL | RTLD_NOW)) == NULL) { 82 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 83 return (0); 84 } 85 86 plugin_init = (ndmp_plugin_t *(*)(int))dlsym(mod_plp, "_ndmp_init"); 87 if (plugin_init == NULL) { 88 (void) dlclose(mod_plp); 89 return (0); 90 } 91 if ((ndmp_pl = plugin_init(NDMP_PLUGIN_VERSION)) == NULL) { 92 syslog(LOG_ERR, "Error loading the plug-in %s", plname); 93 return (-1); 94 } 95 return (0); 96 } 97 98 /* 99 * Unload 100 */ 101 static void 102 mod_fini() 103 { 104 if (ndmp_pl == NULL) 105 return; 106 107 void (*plugin_fini)(ndmp_plugin_t *); 108 109 plugin_fini = (void (*)(ndmp_plugin_t *))dlsym(mod_plp, "_ndmp_fini"); 110 if (plugin_fini == NULL) { 111 (void) dlclose(mod_plp); 112 return; 113 } 114 plugin_fini(ndmp_pl); 115 (void) dlclose(mod_plp); 116 } 117 118 static void 119 daemonize_init(char *arg) 120 { 121 sigset_t set, oset; 122 pid_t pid; 123 priv_set_t *pset = priv_allocset(); 124 125 /* 126 * Set effective sets privileges to 'least' required. If fails, send 127 * error messages to log file and proceed. 128 */ 129 if (pset != NULL) { 130 priv_basicset(pset); 131 (void) priv_addset(pset, PRIV_PROC_AUDIT); 132 (void) priv_addset(pset, PRIV_PROC_SETID); 133 (void) priv_addset(pset, PRIV_PROC_OWNER); 134 (void) priv_addset(pset, PRIV_FILE_CHOWN); 135 (void) priv_addset(pset, PRIV_FILE_CHOWN_SELF); 136 (void) priv_addset(pset, PRIV_FILE_DAC_READ); 137 (void) priv_addset(pset, PRIV_FILE_DAC_SEARCH); 138 (void) priv_addset(pset, PRIV_FILE_DAC_WRITE); 139 (void) priv_addset(pset, PRIV_FILE_OWNER); 140 (void) priv_addset(pset, PRIV_FILE_SETID); 141 (void) priv_addset(pset, PRIV_SYS_LINKDIR); 142 (void) priv_addset(pset, PRIV_SYS_DEVICES); 143 (void) priv_addset(pset, PRIV_SYS_MOUNT); 144 (void) priv_addset(pset, PRIV_SYS_CONFIG); 145 } 146 147 if (pset == NULL || setppriv(PRIV_SET, PRIV_EFFECTIVE, pset) != 0) { 148 syslog(LOG_ERR, "Failed to set least required privileges to " 149 "the service."); 150 } 151 priv_freeset(pset); 152 153 /* 154 * Block all signals prior to the fork and leave them blocked in the 155 * parent so we don't get in a situation where the parent gets SIGINT 156 * and returns non-zero exit status and the child is actually running. 157 * In the child, restore the signal mask once we've done our setsid(). 158 */ 159 (void) sigfillset(&set); 160 (void) sigdelset(&set, SIGABRT); 161 (void) sigprocmask(SIG_BLOCK, &set, &oset); 162 163 if ((pid = fork()) == -1) { 164 openlog(arg, LOG_PID | LOG_NDELAY, LOG_DAEMON); 165 syslog(LOG_ERR, "Failed to start process in background."); 166 exit(SMF_EXIT_ERR_CONFIG); 167 } 168 169 /* If we're the parent process, exit. */ 170 if (pid != 0) { 171 _exit(0); 172 } 173 (void) setsid(); 174 (void) sigprocmask(SIG_SETMASK, &oset, NULL); 175 (void) chdir("/"); 176 (void) umask(0); 177 } 178 179 static void 180 daemonize_fini(void) 181 { 182 int fd; 183 184 if ((fd = open("/dev/null", O_RDWR)) >= 0) { 185 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO); 186 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO); 187 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO); 188 (void) close(fd); 189 } 190 } 191 192 /* 193 * main 194 * 195 * The main NDMP daemon function 196 * 197 * Parameters: 198 * argc (input) - the argument count 199 * argv (input) - command line options 200 * 201 * Returns: 202 * 0 203 */ 204 int 205 main(int argc, char *argv[]) 206 { 207 char c; 208 struct sigaction act; 209 sigset_t set; 210 void *arg = 0; 211 212 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 213 214 /* 215 * Check for existing ndmpd door server (make sure ndmpd is not already 216 * running) 217 */ 218 if (ndmp_door_check()) { 219 /* ndmpd is already running, exit. */ 220 return (0); 221 } 222 223 /* load ENVs */ 224 if (ndmpd_load_prop()) { 225 syslog(LOG_ERR, 226 "%s SMF properties initialization failed.", argv[0]); 227 exit(SMF_EXIT_ERR_CONFIG); 228 } 229 230 /* Global zone check */ 231 if (getzoneid() != GLOBAL_ZONEID) { 232 syslog(LOG_ERR, "Local zone not supported."); 233 exit(SMF_EXIT_ERR_FATAL); 234 } 235 236 /* Trusted Solaris check */ 237 if (is_system_labeled()) { 238 syslog(LOG_ERR, "Trusted Solaris not supported."); 239 exit(SMF_EXIT_ERR_FATAL); 240 } 241 242 opterr = 0; 243 while ((c = getopt(argc, argv, ":d")) != -1) { 244 switch (c) { 245 case 'd': 246 (void) set_debug_level(TRUE); 247 break; 248 default: 249 syslog(LOG_ERR, "%s: Invalid option -%c.", 250 argv[0], optopt); 251 syslog(LOG_ERR, "Usage: %s [-d]", argv[0]); 252 exit(SMF_EXIT_ERR_CONFIG); 253 } 254 255 } 256 257 closelog(); 258 /* 259 * close any open file descriptors which are greater 260 * than STDERR_FILENO 261 */ 262 closefrom(STDERR_FILENO + 1); 263 264 /* set up signal handler */ 265 (void) sigfillset(&set); 266 (void) sigdelset(&set, SIGABRT); /* always unblocked for ASSERT() */ 267 (void) sigfillset(&act.sa_mask); 268 act.sa_handler = ndmpd_sig_handler; 269 act.sa_flags = 0; 270 271 (void) sigaction(SIGTERM, &act, NULL); 272 (void) sigaction(SIGHUP, &act, NULL); 273 (void) sigaction(SIGINT, &act, NULL); 274 (void) sigaction(SIGUSR1, &act, NULL); 275 (void) sigaction(SIGPIPE, &act, NULL); 276 (void) sigdelset(&set, SIGTERM); 277 (void) sigdelset(&set, SIGHUP); 278 (void) sigdelset(&set, SIGINT); 279 (void) sigdelset(&set, SIGUSR1); 280 (void) sigdelset(&set, SIGPIPE); 281 282 (void) daemonize_init(argv[0]); 283 284 openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_DAEMON); 285 (void) mutex_init(&log_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(&log_lock); 343 libzfs_fini(zlibh); 344 mod_fini(); 345 ndmp_door_fini(); 346 daemonize_fini(); 347 return (SMF_EXIT_OK); 348 } 349 350 static void 351 ndmpd_sig_handler(int sig) 352 { 353 if (ndmpd.s_sigval == 0) 354 ndmpd.s_sigval = sig; 355 } 356 357 /* 358 * Enable libumem debugging by default on DEBUG builds. 359 */ 360 #ifdef DEBUG 361 const char * 362 _umem_debug_init(void) 363 { 364 return ("default,verbose"); /* $UMEM_DEBUG setting */ 365 } 366 367 const char * 368 _umem_logging_init(void) 369 { 370 return ("fail,contents"); /* $UMEM_LOGGING setting */ 371 } 372 #endif 373