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