xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c (revision 3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5)
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * LanMan share door server
27  */
28 
29 #include <door.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <syslog.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <pthread.h>
39 #include <smbsrv/libsmb.h>
40 #include <smbsrv/smb_share.h>
41 #include <smbsrv/smbinfo.h>
42 #include "smbd.h"
43 
44 #define	SMB_SHARE_DSRV_VERSION	1
45 #define	SMB_SHARE_DSRV_COOKIE	((void*)(0xdeadbeef^SMB_SHARE_DSRV_VERSION))
46 
47 static int smb_share_dsrv_fd = -1;
48 static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER;
49 static smbd_door_t smb_share_sdh;
50 
51 static void smbd_share_dispatch(void *, char *, size_t, door_desc_t *, uint_t);
52 static int smbd_share_enum(smb_enumshare_info_t *esi);
53 
54 /*
55  * Start the LanMan share door service.
56  * Returns 0 on success. Otherwise, -1.
57  */
58 int
59 smbd_share_start(void)
60 {
61 	int	newfd;
62 
63 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
64 
65 	if (smb_share_dsrv_fd != -1) {
66 		syslog(LOG_ERR, "smbd_share_start: duplicate");
67 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
68 		return (smb_share_dsrv_fd);
69 	}
70 
71 	smbd_door_init(&smb_share_sdh, "share");
72 
73 	if ((smb_share_dsrv_fd = door_create(smbd_share_dispatch,
74 	    SMB_SHARE_DSRV_COOKIE, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) {
75 		syslog(LOG_ERR, "smbd_share_start: door_create: %s",
76 		    strerror(errno));
77 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
78 		return (-1);
79 	}
80 
81 	(void) unlink(SMB_SHARE_DNAME);
82 
83 	if ((newfd = creat(SMB_SHARE_DNAME, 0644)) < 0) {
84 		syslog(LOG_ERR, "smbd_share_start: open: %s",
85 		    strerror(errno));
86 		(void) door_revoke(smb_share_dsrv_fd);
87 		smb_share_dsrv_fd = -1;
88 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
89 		return (-1);
90 	}
91 
92 	(void) close(newfd);
93 	(void) fdetach(SMB_SHARE_DNAME);
94 
95 	if (fattach(smb_share_dsrv_fd, SMB_SHARE_DNAME) < 0) {
96 		syslog(LOG_ERR, "smbd_share_start: fattach: %s",
97 		    strerror(errno));
98 		(void) door_revoke(smb_share_dsrv_fd);
99 		smb_share_dsrv_fd = -1;
100 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
101 		return (-1);
102 	}
103 
104 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
105 	return (smb_share_dsrv_fd);
106 }
107 
108 /*
109  * Stop the LanMan share door service.
110  */
111 void
112 smbd_share_stop(void)
113 {
114 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
115 
116 	smbd_door_fini(&smb_share_sdh);
117 
118 	if (smb_share_dsrv_fd != -1) {
119 		(void) fdetach(SMB_SHARE_DNAME);
120 		(void) door_revoke(smb_share_dsrv_fd);
121 		smb_share_dsrv_fd = -1;
122 	}
123 
124 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
125 }
126 
127 /*
128  * This function with which the LMSHARE door is associated
129  * will invoke the appropriate CIFS share management function
130  * based on the request type of the door call.
131  */
132 /*ARGSUSED*/
133 static void
134 smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp,
135     uint_t n_desc)
136 {
137 	uint32_t rc;
138 	int req_type;
139 	char buf[SMB_SHARE_DSIZE];
140 	unsigned int used;
141 	smb_dr_ctx_t *dec_ctx;
142 	smb_dr_ctx_t *enc_ctx;
143 	unsigned int dec_status;
144 	unsigned int enc_status;
145 	char *sharename, *sharename2;
146 	smb_share_t lmshr_info;
147 	smb_shrlist_t lmshr_list;
148 	smb_enumshare_info_t esi;
149 	int offset;
150 	smb_inaddr_t ipaddr;
151 	int exec_type;
152 	smb_execsub_info_t subs;
153 
154 	smbd_door_enter(&smb_share_sdh);
155 
156 	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
157 	    (size < sizeof (uint32_t))) {
158 		smbd_door_return(&smb_share_sdh, NULL, 0, NULL, 0);
159 	}
160 
161 	dec_ctx = smb_dr_decode_start(ptr, size);
162 	enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
163 	req_type = smb_dr_get_uint32(dec_ctx);
164 
165 	switch (req_type) {
166 	case SMB_SHROP_NUM_SHARES:
167 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
168 			goto decode_error;
169 
170 		rc = smb_shr_count();
171 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
172 		smb_dr_put_uint32(enc_ctx, rc);
173 		break;
174 
175 	case SMB_SHROP_DELETE:
176 		sharename = smb_dr_get_string(dec_ctx);
177 
178 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
179 			smb_dr_free_string(sharename);
180 			goto decode_error;
181 		}
182 
183 		rc = smb_shr_remove(sharename);
184 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
185 		smb_dr_put_uint32(enc_ctx, rc);
186 		smb_dr_free_string(sharename);
187 		break;
188 
189 	case SMB_SHROP_RENAME:
190 		sharename = smb_dr_get_string(dec_ctx);
191 		sharename2 = smb_dr_get_string(dec_ctx);
192 
193 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
194 			smb_dr_free_string(sharename);
195 			smb_dr_free_string(sharename2);
196 			goto decode_error;
197 		}
198 
199 		rc = smb_shr_rename(sharename, sharename2);
200 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
201 		smb_dr_put_uint32(enc_ctx, rc);
202 		smb_dr_free_string(sharename);
203 		smb_dr_free_string(sharename2);
204 		break;
205 
206 	case SMB_SHROP_GETINFO:
207 		sharename = smb_dr_get_string(dec_ctx);
208 		(void) smb_dr_get_buf(dec_ctx, (unsigned char *)&ipaddr,
209 		    sizeof (smb_inaddr_t));
210 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
211 			smb_dr_free_string(sharename);
212 			goto decode_error;
213 		}
214 		rc = smb_shr_get(sharename, &lmshr_info);
215 		if (rc == NERR_Success)
216 			smb_shr_hostaccess(&lmshr_info, &ipaddr);
217 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
218 		smb_dr_put_uint32(enc_ctx, rc);
219 		smb_dr_put_share(enc_ctx, &lmshr_info);
220 		smb_dr_free_string(sharename);
221 		break;
222 
223 	case SMB_SHROP_ADD:
224 		smb_dr_get_share(dec_ctx, &lmshr_info);
225 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
226 			goto decode_error;
227 
228 		rc = smb_shr_add(&lmshr_info);
229 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
230 		smb_dr_put_uint32(enc_ctx, rc);
231 		smb_dr_put_share(enc_ctx, &lmshr_info);
232 		break;
233 
234 	case SMB_SHROP_MODIFY:
235 		smb_dr_get_share(dec_ctx, &lmshr_info);
236 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
237 			goto decode_error;
238 		}
239 
240 		rc = smb_shr_modify(&lmshr_info);
241 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
242 		smb_dr_put_uint32(enc_ctx, rc);
243 
244 		break;
245 
246 	case SMB_SHROP_LIST:
247 		offset = smb_dr_get_int32(dec_ctx);
248 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
249 			goto decode_error;
250 
251 		smb_shr_list(offset, &lmshr_list);
252 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
253 		smb_dr_put_buf(enc_ctx, (unsigned char *)&lmshr_list,
254 		    sizeof (smb_shrlist_t));
255 		break;
256 
257 	case SMB_SHROP_ENUM:
258 		esi.es_bufsize = smb_dr_get_ushort(dec_ctx);
259 		esi.es_posix_uid = smb_dr_get_uint32(dec_ctx);
260 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
261 			goto decode_error;
262 
263 		rc = smbd_share_enum(&esi);
264 
265 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
266 		smb_dr_put_uint32(enc_ctx, rc);
267 		if (rc == NERR_Success) {
268 			smb_dr_put_ushort(enc_ctx, esi.es_ntotal);
269 			smb_dr_put_ushort(enc_ctx, esi.es_nsent);
270 			smb_dr_put_ushort(enc_ctx, esi.es_datasize);
271 			smb_dr_put_buf(enc_ctx,
272 			    (unsigned char *)esi.es_buf, esi.es_bufsize);
273 			free(esi.es_buf);
274 		}
275 		break;
276 
277 	case SMB_SHROP_EXEC:
278 		sharename = smb_dr_get_string(dec_ctx);
279 		subs.e_winname = smb_dr_get_string(dec_ctx);
280 		subs.e_userdom = smb_dr_get_string(dec_ctx);
281 		(void) smb_dr_get_buf(dec_ctx,
282 		    (unsigned char *)&subs.e_srv_ipaddr, sizeof (smb_inaddr_t));
283 		(void) smb_dr_get_buf(dec_ctx,
284 		    (unsigned char *)&subs.e_cli_ipaddr, sizeof (smb_inaddr_t));
285 		subs.e_cli_netbiosname = smb_dr_get_string(dec_ctx);
286 		subs.e_uid = smb_dr_get_int32(dec_ctx);
287 		exec_type = smb_dr_get_int32(dec_ctx);
288 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
289 			smb_dr_free_string(sharename);
290 			smb_dr_free_string(subs.e_winname);
291 			smb_dr_free_string(subs.e_userdom);
292 			smb_dr_free_string(subs.e_cli_netbiosname);
293 			goto decode_error;
294 		}
295 
296 		rc = smb_shr_exec(sharename, &subs, exec_type);
297 
298 		if (rc != 0)
299 			syslog(LOG_NOTICE, "Failed to execute %s command",
300 			    (exec_type == SMB_SHR_UNMAP) ? "unmap" : "map");
301 
302 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
303 		smb_dr_put_uint32(enc_ctx, rc);
304 		smb_dr_free_string(sharename);
305 		smb_dr_free_string(subs.e_winname);
306 		smb_dr_free_string(subs.e_userdom);
307 		smb_dr_free_string(subs.e_cli_netbiosname);
308 		break;
309 
310 	default:
311 		dec_status = smb_dr_decode_finish(dec_ctx);
312 		goto decode_error;
313 	}
314 
315 	if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
316 		enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
317 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
318 		smb_dr_put_uint32(enc_ctx, enc_status);
319 		(void) smb_dr_encode_finish(enc_ctx, &used);
320 	}
321 
322 	smbd_door_return(&smb_share_sdh, buf, used, NULL, 0);
323 	return;
324 
325 decode_error:
326 	smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
327 	smb_dr_put_uint32(enc_ctx, dec_status);
328 	(void) smb_dr_encode_finish(enc_ctx, &used);
329 	smbd_door_return(&smb_share_sdh, buf, used, NULL, 0);
330 }
331 
332 /*
333  * This function builds a response for a NetShareEnum RAP request which
334  * originates from smbsrv kernel module. A response buffer is allocated
335  * with the specified size in esi->es_bufsize. List of shares is scanned
336  * twice. In the first round the total number of shares which their OEM
337  * name is shorter than 13 chars (esi->es_ntotal) and also the number of
338  * shares that fit in the given buffer are calculated. In the second
339  * round the shares data are encoded in the buffer.
340  *
341  * The data associated with each share has two parts, a fixed size part and
342  * a variable size part which is share's comment. The outline of the response
343  * buffer is so that fixed part for all the shares will appear first and follows
344  * with the comments for all those shares and that's why the data cannot be
345  * encoded in one round without unnecessarily complicating the code.
346  */
347 static int
348 smbd_share_enum(smb_enumshare_info_t *esi)
349 {
350 	smb_shriter_t shi;
351 	smb_share_t *si;
352 	int remained;
353 	uint16_t infolen = 0;
354 	uint16_t cmntlen = 0;
355 	uint16_t sharelen;
356 	uint16_t clen;
357 	uint32_t cmnt_offs;
358 	smb_msgbuf_t info_mb;
359 	smb_msgbuf_t cmnt_mb;
360 	boolean_t autohome_added = B_FALSE;
361 
362 	esi->es_ntotal = esi->es_nsent = 0;
363 
364 	if ((esi->es_buf = malloc(esi->es_bufsize)) == NULL)
365 		return (NERR_InternalError);
366 
367 	bzero(esi->es_buf, esi->es_bufsize);
368 	remained = esi->es_bufsize;
369 
370 	/* Do the necessary calculations in the first round */
371 	smb_shr_iterinit(&shi);
372 
373 	while ((si = smb_shr_iterate(&shi)) != NULL) {
374 		if (si->shr_flags & SMB_SHRF_LONGNAME)
375 			continue;
376 
377 		if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
378 			if (esi->es_posix_uid == si->shr_uid)
379 				autohome_added = B_TRUE;
380 			else
381 				continue;
382 		}
383 
384 		esi->es_ntotal++;
385 
386 		if (remained <= 0)
387 			continue;
388 
389 		clen = strlen(si->shr_cmnt) + 1;
390 		sharelen = SHARE_INFO_1_SIZE + clen;
391 
392 		if (sharelen <= remained) {
393 			infolen += SHARE_INFO_1_SIZE;
394 			cmntlen += clen;
395 		}
396 
397 		remained -= sharelen;
398 	}
399 
400 	esi->es_datasize = infolen + cmntlen;
401 
402 	smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
403 	smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
404 	cmnt_offs = infolen;
405 
406 	/* Encode the data in the second round */
407 	smb_shr_iterinit(&shi);
408 	autohome_added = B_FALSE;
409 
410 	while ((si = smb_shr_iterate(&shi)) != NULL) {
411 		if (si->shr_flags & SMB_SHRF_LONGNAME)
412 			continue;
413 
414 		if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
415 			if (esi->es_posix_uid == si->shr_uid)
416 				autohome_added = B_TRUE;
417 			else
418 				continue;
419 		}
420 
421 		if (smb_msgbuf_encode(&info_mb, "13c.wl",
422 		    si->shr_oemname, si->shr_type, cmnt_offs) < 0)
423 			break;
424 
425 		if (smb_msgbuf_encode(&cmnt_mb, "s", si->shr_cmnt) < 0)
426 			break;
427 
428 		cmnt_offs += strlen(si->shr_cmnt) + 1;
429 		esi->es_nsent++;
430 	}
431 
432 	smb_msgbuf_term(&info_mb);
433 	smb_msgbuf_term(&cmnt_mb);
434 
435 	return (NERR_Success);
436 }
437