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