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