1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22faa1795aSjb150015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * SMBd door server
30da6c28aaSamw  */
31da6c28aaSamw 
32da6c28aaSamw #include <alloca.h>
33da6c28aaSamw #include <door.h>
34da6c28aaSamw #include <errno.h>
35da6c28aaSamw #include <syslog.h>
36da6c28aaSamw #include <unistd.h>
37da6c28aaSamw #include <varargs.h>
38da6c28aaSamw #include <stdio.h>
39da6c28aaSamw #include <synch.h>
40da6c28aaSamw #include <string.h>
41da6c28aaSamw #include <stdlib.h>
42da6c28aaSamw #include <sys/stat.h>
43da6c28aaSamw #include <fcntl.h>
44da6c28aaSamw #include <pthread.h>
45da6c28aaSamw #include <strings.h>
46da6c28aaSamw #include <smbsrv/smb_door_svc.h>
47da6c28aaSamw #include <smbsrv/smb_common_door.h>
48da6c28aaSamw 
49da6c28aaSamw 
50da6c28aaSamw static int smb_doorsrv_fildes = -1;
51da6c28aaSamw static mutex_t smb_doorsrv_mutex;
52da6c28aaSamw 
53da6c28aaSamw static void smb_door_srv_func(void *cookie, char *ptr, size_t size,
54da6c28aaSamw     door_desc_t *dp, uint_t n_odesc);
55da6c28aaSamw 
56da6c28aaSamw /*
57da6c28aaSamw  * smb_door_srv_start
58da6c28aaSamw  *
59da6c28aaSamw  * Start the smbd door service.  Create and bind to a door.
60da6c28aaSamw  * Returns 0 on success. Otherwise, -1.
61da6c28aaSamw  */
62da6c28aaSamw int
63da6c28aaSamw smb_door_srv_start()
64da6c28aaSamw {
65da6c28aaSamw 	int	newfd;
66da6c28aaSamw 
67da6c28aaSamw 	(void) mutex_lock(&smb_doorsrv_mutex);
68da6c28aaSamw 
69da6c28aaSamw 	if (smb_doorsrv_fildes != -1) {
70da6c28aaSamw 		(void) fprintf(stderr, "smb_doorsrv_start: already started");
71da6c28aaSamw 		(void) mutex_unlock(&smb_doorsrv_mutex);
72da6c28aaSamw 		return (-1);
73da6c28aaSamw 	}
74da6c28aaSamw 
75da6c28aaSamw 	if ((smb_doorsrv_fildes = door_create(smb_door_srv_func,
76da6c28aaSamw 	    SMB_DR_SVC_COOKIE, DOOR_UNREF)) < 0) {
77da6c28aaSamw 		(void) fprintf(stderr, "smb_doorsrv_start: door_create: %s",
78da6c28aaSamw 		    strerror(errno));
79da6c28aaSamw 		smb_doorsrv_fildes = -1;
80da6c28aaSamw 		(void) mutex_unlock(&smb_doorsrv_mutex);
81da6c28aaSamw 		return (-1);
82da6c28aaSamw 	}
83da6c28aaSamw 
84da6c28aaSamw 	(void) unlink(SMB_DR_SVC_NAME);
85da6c28aaSamw 
86da6c28aaSamw 	if ((newfd = creat(SMB_DR_SVC_NAME, 0644)) < 0) {
87da6c28aaSamw 		(void) fprintf(stderr, "smb_doorsrv_start: open: %s",
88da6c28aaSamw 		    strerror(errno));
89da6c28aaSamw 		(void) door_revoke(smb_doorsrv_fildes);
90da6c28aaSamw 		smb_doorsrv_fildes = -1;
91da6c28aaSamw 		(void) mutex_unlock(&smb_doorsrv_mutex);
92da6c28aaSamw 		return (-1);
93da6c28aaSamw 	}
94da6c28aaSamw 
95da6c28aaSamw 	(void) close(newfd);
96da6c28aaSamw 	(void) fdetach(SMB_DR_SVC_NAME);
97da6c28aaSamw 
98da6c28aaSamw 	if (fattach(smb_doorsrv_fildes, SMB_DR_SVC_NAME) < 0) {
99da6c28aaSamw 		(void) fprintf(stderr, "smb_doorsrv_start: fattach: %s",
100da6c28aaSamw 		    strerror(errno));
101da6c28aaSamw 		(void) door_revoke(smb_doorsrv_fildes);
102da6c28aaSamw 		smb_doorsrv_fildes = -1;
103da6c28aaSamw 		(void) mutex_unlock(&smb_doorsrv_mutex);
104da6c28aaSamw 		return (-1);
105da6c28aaSamw 	}
106da6c28aaSamw 
107da6c28aaSamw 	(void) mutex_unlock(&smb_doorsrv_mutex);
108faa1795aSjb150015 	return (smb_doorsrv_fildes);
109da6c28aaSamw }
110da6c28aaSamw 
111da6c28aaSamw 
112da6c28aaSamw /*
113da6c28aaSamw  * smb_door_srv_stop
114da6c28aaSamw  *
115da6c28aaSamw  * Stop the smbd door service.
116da6c28aaSamw  */
117da6c28aaSamw void
118da6c28aaSamw smb_door_srv_stop(void)
119da6c28aaSamw {
120da6c28aaSamw 	(void) mutex_lock(&smb_doorsrv_mutex);
121da6c28aaSamw 
122da6c28aaSamw 	if (smb_doorsrv_fildes != -1) {
123da6c28aaSamw 		(void) fdetach(SMB_DR_SVC_NAME);
124da6c28aaSamw 		(void) door_revoke(smb_doorsrv_fildes);
125da6c28aaSamw 		smb_doorsrv_fildes = -1;
126da6c28aaSamw 	}
127da6c28aaSamw 
128da6c28aaSamw 	(void) mutex_unlock(&smb_doorsrv_mutex);
129da6c28aaSamw }
130da6c28aaSamw 
131da6c28aaSamw /*
132da6c28aaSamw  * smb_door_err_hdlr
133da6c28aaSamw  *
134da6c28aaSamw  * Encode the appropriate error code to the first 4-byte of the result
135da6c28aaSamw  * buffer upon any door operation failure.
136da6c28aaSamw  */
137da6c28aaSamw static char *
138da6c28aaSamw smb_door_srv_err_hdlr(int stat, size_t *rbufsize)
139da6c28aaSamw {
140da6c28aaSamw 	char *rbuf;
141da6c28aaSamw 
142da6c28aaSamw 	if ((rbuf = smb_dr_set_res_stat(stat, rbufsize)) == NULL) {
143da6c28aaSamw 		*rbufsize = 0;
144da6c28aaSamw 		return (NULL);
145da6c28aaSamw 	}
146da6c28aaSamw 
147da6c28aaSamw 	return (rbuf);
148da6c28aaSamw }
149da6c28aaSamw 
150da6c28aaSamw /*
151da6c28aaSamw  * smb_door_srv_func
152da6c28aaSamw  *
153da6c28aaSamw  * This function will determine the opcode by decoding the first 4-byte of
154da6c28aaSamw  * the argument buffer passed by a door client.  The corresponding door
155da6c28aaSamw  * operation will be looked up from the optab and get invoked.
156da6c28aaSamw  * Basically, any door operation will takes the argument buffer as its
157da6c28aaSamw  * parameter, and generates the result buffer.
158da6c28aaSamw  */
159da6c28aaSamw /*ARGSUSED*/
160da6c28aaSamw void
161da6c28aaSamw smb_door_srv_func(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
162da6c28aaSamw     uint_t n_desc)
163da6c28aaSamw {
164da6c28aaSamw 	char *resbuf = NULL, *tmpbuf = NULL;
165da6c28aaSamw 	size_t rbufsize = 0;
166da6c28aaSamw 	int opcode;
167da6c28aaSamw 	int err;
168da6c28aaSamw 	smb_dr_op_t smbop;
169da6c28aaSamw 
170*3ad684d6Sjb150015 	if ((cookie != SMB_DR_SVC_COOKIE) || (argp == NULL) ||
171*3ad684d6Sjb150015 	    (arg_size < sizeof (uint32_t))) {
172*3ad684d6Sjb150015 		(void) door_return(NULL, 0, NULL, 0);
173*3ad684d6Sjb150015 	}
174*3ad684d6Sjb150015 
175da6c28aaSamw 	if ((opcode = smb_dr_get_opcode(argp, arg_size)) < 0) {
176da6c28aaSamw 		tmpbuf = smb_door_srv_err_hdlr(SMB_DR_OP_ERR_DECODE,
177da6c28aaSamw 		    &rbufsize);
178da6c28aaSamw 		goto door_return;
179da6c28aaSamw 	}
180da6c28aaSamw 
181da6c28aaSamw 	syslog(LOG_DEBUG, "smb_door_srv_func: execute server routine"
182da6c28aaSamw 	    "(opcode=%d)", opcode);
183da6c28aaSamw 	if (smb_dr_is_valid_opcode(opcode) != 0) {
184da6c28aaSamw 		tmpbuf = smb_door_srv_err_hdlr(SMB_DR_OP_ERR_INVALID_OPCODE,
185da6c28aaSamw 		    &rbufsize);
186da6c28aaSamw 	} else {
187da6c28aaSamw 		smbop = smb_doorsrv_optab[opcode];
188da6c28aaSamw 		if ((tmpbuf = smbop(argp + sizeof (opcode),
189da6c28aaSamw 		    arg_size - sizeof (opcode), dp, n_desc,
190da6c28aaSamw 		    &rbufsize, &err)) == NULL)
191da6c28aaSamw 			tmpbuf = smb_door_srv_err_hdlr(err, &rbufsize);
192da6c28aaSamw 	}
193da6c28aaSamw 
194da6c28aaSamw door_return:
195da6c28aaSamw 	if (tmpbuf) {
196da6c28aaSamw 		if ((resbuf = (char *)alloca(rbufsize)) == NULL)
197da6c28aaSamw 			rbufsize = 0;
198da6c28aaSamw 		else
199da6c28aaSamw 			(void) memcpy(resbuf, tmpbuf, rbufsize);
200da6c28aaSamw 		free(tmpbuf);
201da6c28aaSamw 	}
202da6c28aaSamw 
203da6c28aaSamw 	(void) door_return(resbuf, rbufsize, NULL, 0);
204da6c28aaSamw 	/*NOTREACHED*/
205da6c28aaSamw }
206