4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
31 #include <stdio_ext.h>
35 #include <sys/types.h>
49 #include <sys/param.h>
50 #include <sys/systeminfo.h>
51 #include <sys/thread.h>
54 #include <sys/fs_reparse.h>
55 #include <priv_utils.h>
56 #include <rpcsvc/daemon_utils.h>
58 #define REPARSED_CMD_OPTS "v"
59 #define DOOR_RESULT_BUFSZ (MAXPATHLEN + sizeof (reparsed_door_res_t))
60 #define SAFETY_BUFFER 8*1024
63 static int verbose
= 0;
65 static int start_reparsed_svcs();
66 static void daemonize(void);
67 static void reparsed_door_call_error(int error
, int buflen
);
68 static void reparsed_doorfunc(void *cookie
, char *argp
, size_t arg_size
,
69 door_desc_t
*dp
, uint_t n_desc
);
74 syslog(LOG_ERR
, "Usage: %s", MyName
);
75 syslog(LOG_ERR
, "\t[-v]\t\tverbose error messages)");
82 syslog(LOG_ERR
, "SIGHUP received: ignored");
83 (void) signal(SIGHUP
, warn_hup
);
87 * Processing for daemonization
94 syslog(LOG_ERR
, "reparsed: can't fork - errno %d", errno
);
100 default: /* parent */
106 * Close stdin, stdout, and stderr.
107 * Open again to redirect input+output
112 (void) open("/dev/null", O_RDONLY
);
113 (void) open("/dev/null", O_WRONLY
);
119 main(int argc
, char *argv
[])
127 if (geteuid() != 0) {
128 syslog(LOG_ERR
, "%s must be run as root", MyName
);
132 while ((c
= getopt(argc
, argv
, REPARSED_CMD_OPTS
)) != EOF
) {
143 openlog(MyName
, LOG_PID
| LOG_NDELAY
, LOG_DAEMON
);
145 (void) _create_daemon_lock(REPARSED
, DAEMON_UID
, DAEMON_GID
);
146 (void) enable_extended_FILE_stdio(-1, -1);
147 switch (_enter_daemon_lock(REPARSED
)) {
151 syslog(LOG_ERR
, "Error locking for %s", REPARSED
);
154 /* daemon was already running */
158 (void) signal(SIGHUP
, warn_hup
);
161 * Make the process a privilege aware daemon.
162 * Only "basic" privileges are required.
165 if (__init_daemon_priv(PU_RESETGROUPS
|PU_CLEARLIMITSET
, 0, 0,
167 syslog(LOG_ERR
, "should be run with sufficient privileges");
172 * Clear basic privileges not required by reparsed.
174 __fini_daemon_priv(PRIV_PROC_FORK
, PRIV_PROC_EXEC
, PRIV_PROC_SESSION
,
175 PRIV_FILE_LINK_ANY
, PRIV_PROC_INFO
, NULL
);
177 return (start_reparsed_svcs());
181 reparsed_door_call_error(int error
, int buflen
)
183 reparsed_door_res_t rpd_res
;
185 memset(&rpd_res
, 0, sizeof (reparsed_door_res_t
));
186 rpd_res
.res_status
= error
;
187 rpd_res
.res_len
= buflen
;
188 door_return((char *)&rpd_res
, sizeof (reparsed_door_res_t
), NULL
, 0);
190 (void) door_return(NULL
, 0, NULL
, 0);
197 * argp: "service_type:service_data" string
198 * dp & n_desc: not used.
201 reparsed_doorfunc(void *cookie
, char *argp
, size_t arg_size
,
202 door_desc_t
*dp
, uint_t n_desc
)
206 char *svc_type
, *svc_data
;
207 char *cp
, *buf
, *sbuf
, res_buf
[DOOR_RESULT_BUFSZ
];
208 reparsed_door_res_t
*resp
;
210 if ((argp
== NULL
) || (arg_size
== 0)) {
211 reparsed_door_call_error(EINVAL
, 0);
216 syslog(LOG_NOTICE
, "reparsed_door: [%s, %d]", argp
, arg_size
);
218 if ((svc_type
= strdup(argp
)) == NULL
) {
219 reparsed_door_call_error(ENOMEM
, 0);
224 * Door argument string comes in "service_type:service_data" format.
225 * Need to break it into separate "service_type" and "service_data"
226 * string before passing them to reparse_deref() to process them.
228 if ((cp
= strchr(svc_type
, ':')) == NULL
) {
230 reparsed_door_call_error(EINVAL
, 0);
237 * Setup buffer for reparse_deref(). 'bufsz' is the actual
238 * buffer size to hold the result returned by reparse_deref().
240 resp
= (reparsed_door_res_t
*)res_buf
;
241 buf
= resp
->res_data
;
242 bufsz
= sizeof (res_buf
) - sizeof (reparsed_door_res_t
);
245 * reparse_deref() calls the service type plugin library to process
246 * the service data. The plugin library function should understand
247 * the context of the service data and should be the one to XDR the
248 * results before returning it to the caller.
250 err
= reparse_deref(svc_type
, svc_data
, buf
, &bufsz
);
254 "reparsed_deref(svc_type: %s, data: %s, size: %d) -> %d",
255 svc_type
, svc_data
, bufsz
, err
);
263 * bufsz was returned with size needed by reparse_deref().
265 * We cannot use malloc() here because door_return() never
266 * returns, and memory allocated by malloc() would get leaked.
268 sbuf
= alloca(bufsz
+ sizeof (reparsed_door_res_t
));
269 if (sbuf
== NULL
|| stack_inbounds(buf
) == 0 ||
270 stack_inbounds(buf
+ sizeof (reparsed_door_res_t
) +
271 SAFETY_BUFFER
- 1) == 0) {
273 reparsed_door_call_error(ENOMEM
, 0);
277 resp
= (reparsed_door_res_t
*)sbuf
;
278 if ((err
= reparse_deref(svc_type
, svc_data
, resp
->res_data
,
286 reparsed_door_call_error(err
, 0);
293 syslog(LOG_NOTICE
, "reparsed_door_return <buf=%s> size=%d",
296 resp
->res_status
= 0;
297 resp
->res_len
= bufsz
;
298 (void) door_return((char *)resp
, bufsz
+ sizeof (reparsed_door_res_t
),
301 (void) door_return(NULL
, 0, NULL
, 0);
306 start_reparsed_svcs()
311 if ((doorfd
= door_create(reparsed_doorfunc
, NULL
,
312 DOOR_REFUSE_DESC
|DOOR_NO_CANCEL
)) == -1) {
313 syslog(LOG_ERR
, "Unable to create door");
318 * Create a file system path for the door
320 if ((dfd
= open(REPARSED_DOOR
, O_RDWR
|O_CREAT
|O_TRUNC
,
321 S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
)) == -1) {
322 syslog(LOG_ERR
, "unable to open %s", REPARSED_DOOR
);
323 (void) close(doorfd
);
328 * Clean up any stale associations
330 (void) fdetach(REPARSED_DOOR
);
333 * Register in the kernel namespace for door_ki_open().
335 if (fattach(doorfd
, REPARSED_DOOR
) == -1) {
336 syslog(LOG_ERR
, "Unable to fattach door %s", REPARSED_DOOR
);
337 (void) close(doorfd
);
344 * Wait for incoming calls
350 syslog(LOG_ERR
, "Door server exited");