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
mod_init()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
mod_fini()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
daemonize_init(char * arg)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
daemonize_fini(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
main(int argc,char * argv[])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 if (tlm_init() == -1) {
305 syslog(LOG_ERR, "Failed to initialize tape manager.");
306 exit(SMF_EXIT_ERR_CONFIG);
307 }
308
309 /*
310 * Prior to this point, we are single-threaded. We will be
311 * multi-threaded from this point on.
312 */
313 (void) pthread_create(NULL, NULL, (funct_t)ndmpd_main,
314 (void *)&arg);
315
316 while (!ndmpd.s_shutdown_flag) {
317 (void) sigsuspend(&set);
318
319 switch (ndmpd.s_sigval) {
320 case 0:
321 break;
322
323 case SIGPIPE:
324 break;
325
326 case SIGHUP:
327 /* Refresh SMF properties */
328 if (ndmpd_load_prop())
329 syslog(LOG_ERR,
330 "Service properties initialization "
331 "failed.");
332 break;
333
334 default:
335 /*
336 * Typically SIGINT or SIGTERM.
337 */
338 ndmpd.s_shutdown_flag = 1;
339 break;
340 }
341
342 ndmpd.s_sigval = 0;
343 }
344
345 (void) mutex_destroy(&ndmpd_zfs_fd_lock);
346 (void) mutex_destroy(&log_lock);
347 libzfs_fini(zlibh);
348 mod_fini();
349 ndmp_door_fini();
350 daemonize_fini();
351 return (SMF_EXIT_OK);
352 }
353
354 static void
ndmpd_sig_handler(int sig)355 ndmpd_sig_handler(int sig)
356 {
357 if (ndmpd.s_sigval == 0)
358 ndmpd.s_sigval = sig;
359 }
360
361 /*
362 * Enable libumem debugging by default on DEBUG builds.
363 */
364 #ifdef DEBUG
365 const char *
_umem_debug_init(void)366 _umem_debug_init(void)
367 {
368 return ("default,verbose"); /* $UMEM_DEBUG setting */
369 }
370
371 const char *
_umem_logging_init(void)372 _umem_logging_init(void)
373 {
374 return ("fail,contents"); /* $UMEM_LOGGING setting */
375 }
376 #endif
377