xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 ((cookie != SMB_DR_SVC_COOKIE) || (argp == NULL) ||
171 	    (arg_size < sizeof (uint32_t))) {
172 		(void) door_return(NULL, 0, NULL, 0);
173 	}
174 
175 	if ((opcode = smb_dr_get_opcode(argp, arg_size)) < 0) {
176 		tmpbuf = smb_door_srv_err_hdlr(SMB_DR_OP_ERR_DECODE,
177 		    &rbufsize);
178 		goto door_return;
179 	}
180 
181 	syslog(LOG_DEBUG, "smb_door_srv_func: execute server routine"
182 	    "(opcode=%d)", opcode);
183 	if (smb_dr_is_valid_opcode(opcode) != 0) {
184 		tmpbuf = smb_door_srv_err_hdlr(SMB_DR_OP_ERR_INVALID_OPCODE,
185 		    &rbufsize);
186 	} else {
187 		smbop = smb_doorsrv_optab[opcode];
188 		if ((tmpbuf = smbop(argp + sizeof (opcode),
189 		    arg_size - sizeof (opcode), dp, n_desc,
190 		    &rbufsize, &err)) == NULL)
191 			tmpbuf = smb_door_srv_err_hdlr(err, &rbufsize);
192 	}
193 
194 door_return:
195 	if (tmpbuf) {
196 		if ((resbuf = (char *)alloca(rbufsize)) == NULL)
197 			rbufsize = 0;
198 		else
199 			(void) memcpy(resbuf, tmpbuf, rbufsize);
200 		free(tmpbuf);
201 	}
202 
203 	(void) door_return(resbuf, rbufsize, NULL, 0);
204 	/*NOTREACHED*/
205 }
206