xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_share_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 2009 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 
41 #include <smbsrv/libsmb.h>
42 
43 #include <smbsrv/smb_share.h>
44 #include <smbsrv/smbinfo.h>
45 
46 #define	SMB_SHARE_DSRV_VERSION	1
47 #define	SMB_SHARE_DSRV_COOKIE	((void*)(0xdeadbeef^SMB_SHARE_DSRV_VERSION))
48 
49 static int smb_share_dsrv_fd = -1;
50 static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER;
51 
52 static void smb_share_dsrv_dispatch(void *, char *, size_t, door_desc_t *,
53     uint_t);
54 static int smb_share_dsrv_enum(smb_enumshare_info_t *esi);
55 
56 /*
57  * smb_share_dsrv_start
58  *
59  * Start the LanMan share door service.
60  * Returns 0 on success. Otherwise, -1.
61  */
62 int
63 smb_share_dsrv_start(void)
64 {
65 	int	newfd;
66 
67 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
68 
69 	if (smb_share_dsrv_fd != -1) {
70 		syslog(LOG_ERR, "smb_share_dsrv_start: duplicate");
71 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
72 		return (smb_share_dsrv_fd);
73 	}
74 
75 	if ((smb_share_dsrv_fd = door_create(smb_share_dsrv_dispatch,
76 	    SMB_SHARE_DSRV_COOKIE, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) {
77 		syslog(LOG_ERR, "smb_share_dsrv_start: door_create: %s",
78 		    strerror(errno));
79 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
80 		return (-1);
81 	}
82 
83 	(void) unlink(SMB_SHARE_DNAME);
84 
85 	if ((newfd = creat(SMB_SHARE_DNAME, 0644)) < 0) {
86 		syslog(LOG_ERR, "smb_share_dsrv_start: open: %s",
87 		    strerror(errno));
88 		(void) door_revoke(smb_share_dsrv_fd);
89 		smb_share_dsrv_fd = -1;
90 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
91 		return (-1);
92 	}
93 
94 	(void) close(newfd);
95 	(void) fdetach(SMB_SHARE_DNAME);
96 
97 	if (fattach(smb_share_dsrv_fd, SMB_SHARE_DNAME) < 0) {
98 		syslog(LOG_ERR, "smb_share_dsrv_start: fattach: %s",
99 		    strerror(errno));
100 		(void) door_revoke(smb_share_dsrv_fd);
101 		smb_share_dsrv_fd = -1;
102 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
103 		return (-1);
104 	}
105 
106 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
107 	return (smb_share_dsrv_fd);
108 }
109 
110 /*
111  * smb_share_dsrv_stop
112  *
113  * Stop the LanMan share door service.
114  */
115 void
116 smb_share_dsrv_stop(void)
117 {
118 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
119 
120 	if (smb_share_dsrv_fd != -1) {
121 		(void) fdetach(SMB_SHARE_DNAME);
122 		(void) door_revoke(smb_share_dsrv_fd);
123 		smb_share_dsrv_fd = -1;
124 	}
125 
126 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
127 }
128 
129 /*
130  * smb_share_dsrv_dispatch
131  *
132  * This function with which the LMSHARE door is associated
133  * will invoke the appropriate CIFS share management function
134  * based on the request type of the door call.
135  */
136 /*ARGSUSED*/
137 static void
138 smb_share_dsrv_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp,
139     uint_t n_desc)
140 {
141 	uint32_t rc;
142 	int req_type;
143 	char buf[SMB_SHARE_DSIZE];
144 	unsigned int used;
145 	smb_dr_ctx_t *dec_ctx;
146 	smb_dr_ctx_t *enc_ctx;
147 	unsigned int dec_status;
148 	unsigned int enc_status;
149 	char *sharename, *sharename2;
150 	smb_share_t lmshr_info;
151 	smb_shrlist_t lmshr_list;
152 	smb_enumshare_info_t esi;
153 	int offset;
154 	smb_inaddr_t ipaddr;
155 	int exec_type;
156 	smb_execsub_info_t subs;
157 
158 	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
159 	    (size < sizeof (uint32_t))) {
160 		(void) door_return(NULL, 0, NULL, 0);
161 	}
162 
163 	dec_ctx = smb_dr_decode_start(ptr, size);
164 	enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
165 	req_type = smb_dr_get_uint32(dec_ctx);
166 
167 	switch (req_type) {
168 	case SMB_SHROP_NUM_SHARES:
169 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
170 			goto decode_error;
171 
172 		rc = smb_shr_count();
173 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
174 		smb_dr_put_uint32(enc_ctx, rc);
175 		break;
176 
177 	case SMB_SHROP_DELETE:
178 		sharename = smb_dr_get_string(dec_ctx);
179 
180 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
181 			smb_dr_free_string(sharename);
182 			goto decode_error;
183 		}
184 
185 		rc = smb_shr_remove(sharename);
186 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
187 		smb_dr_put_uint32(enc_ctx, rc);
188 		smb_dr_free_string(sharename);
189 		break;
190 
191 	case SMB_SHROP_RENAME:
192 		sharename = smb_dr_get_string(dec_ctx);
193 		sharename2 = smb_dr_get_string(dec_ctx);
194 
195 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
196 			smb_dr_free_string(sharename);
197 			smb_dr_free_string(sharename2);
198 			goto decode_error;
199 		}
200 
201 		rc = smb_shr_rename(sharename, sharename2);
202 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
203 		smb_dr_put_uint32(enc_ctx, rc);
204 		smb_dr_free_string(sharename);
205 		smb_dr_free_string(sharename2);
206 		break;
207 
208 	case SMB_SHROP_GETINFO:
209 		sharename = smb_dr_get_string(dec_ctx);
210 		(void) smb_dr_get_buf(dec_ctx, (unsigned char *)&ipaddr,
211 		    sizeof (smb_inaddr_t));
212 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
213 			smb_dr_free_string(sharename);
214 			goto decode_error;
215 		}
216 		rc = smb_shr_get(sharename, &lmshr_info);
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 = smb_share_dsrv_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" \
305 			    " command.\n",
306 			    (exec_type == SMB_SHR_UNMAP) ? "unmap" : "map");
307 
308 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
309 		smb_dr_put_uint32(enc_ctx, rc);
310 		smb_dr_free_string(sharename);
311 		smb_dr_free_string(subs.e_winname);
312 		smb_dr_free_string(subs.e_userdom);
313 		smb_dr_free_string(subs.e_cli_netbiosname);
314 		break;
315 
316 	default:
317 		dec_status = smb_dr_decode_finish(dec_ctx);
318 		goto decode_error;
319 	}
320 
321 	if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
322 		enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
323 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
324 		smb_dr_put_uint32(enc_ctx, enc_status);
325 		(void) smb_dr_encode_finish(enc_ctx, &used);
326 	}
327 
328 	(void) door_return(buf, used, NULL, 0);
329 	return;
330 
331 decode_error:
332 	smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
333 	smb_dr_put_uint32(enc_ctx, dec_status);
334 	(void) smb_dr_encode_finish(enc_ctx, &used);
335 	(void) door_return(buf, used, NULL, 0);
336 }
337 
338 /*
339  * smb_share_dsrv_enum
340  *
341  * This function builds a response for a NetShareEnum RAP request which
342  * originates from smbsrv kernel module. A response buffer is allocated
343  * with the specified size in esi->es_bufsize. List of shares is scanned
344  * twice. In the first round the total number of shares which their OEM
345  * name is shorter than 13 chars (esi->es_ntotal) and also the number of
346  * shares that fit in the given buffer are calculated. In the second
347  * round the shares data are encoded in the buffer.
348  *
349  * The data associated with each share has two parts, a fixed size part and
350  * a variable size part which is share's comment. The outline of the response
351  * buffer is so that fixed part for all the shares will appear first and follows
352  * with the comments for all those shares and that's why the data cannot be
353  * encoded in one round without unnecessarily complicating the code.
354  */
355 static int
356 smb_share_dsrv_enum(smb_enumshare_info_t *esi)
357 {
358 	smb_shriter_t shi;
359 	smb_share_t *si;
360 	int remained;
361 	uint16_t infolen = 0;
362 	uint16_t cmntlen = 0;
363 	uint16_t sharelen;
364 	uint16_t clen;
365 	uint32_t cmnt_offs;
366 	smb_msgbuf_t info_mb;
367 	smb_msgbuf_t cmnt_mb;
368 	boolean_t autohome_added = B_FALSE;
369 
370 	esi->es_ntotal = esi->es_nsent = 0;
371 
372 	if ((esi->es_buf = malloc(esi->es_bufsize)) == NULL)
373 		return (NERR_InternalError);
374 
375 	bzero(esi->es_buf, esi->es_bufsize);
376 	remained = esi->es_bufsize;
377 
378 	/* Do the necessary calculations in the first round */
379 	smb_shr_iterinit(&shi);
380 
381 	while ((si = smb_shr_iterate(&shi)) != NULL) {
382 		if (si->shr_flags & SMB_SHRF_LONGNAME)
383 			continue;
384 
385 		if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
386 			if (strcasecmp(esi->es_username, si->shr_name) == 0)
387 				autohome_added = B_TRUE;
388 			else
389 				continue;
390 		}
391 
392 		esi->es_ntotal++;
393 
394 		if (remained <= 0)
395 			continue;
396 
397 		clen = strlen(si->shr_cmnt) + 1;
398 		sharelen = SHARE_INFO_1_SIZE + clen;
399 
400 		if (sharelen <= remained) {
401 			infolen += SHARE_INFO_1_SIZE;
402 			cmntlen += clen;
403 		}
404 
405 		remained -= sharelen;
406 	}
407 
408 	esi->es_datasize = infolen + cmntlen;
409 
410 	smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
411 	smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
412 	cmnt_offs = infolen;
413 
414 	/* Encode the data in the second round */
415 	smb_shr_iterinit(&shi);
416 	autohome_added = B_FALSE;
417 
418 	while ((si = smb_shr_iterate(&shi)) != NULL) {
419 		if (si->shr_flags & SMB_SHRF_LONGNAME)
420 			continue;
421 
422 		if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
423 			if (strcasecmp(esi->es_username, si->shr_name) == 0)
424 				autohome_added = B_TRUE;
425 			else
426 				continue;
427 		}
428 
429 		if (smb_msgbuf_encode(&info_mb, "13c.wl",
430 		    si->shr_oemname, si->shr_type, cmnt_offs) < 0)
431 			break;
432 
433 		if (smb_msgbuf_encode(&cmnt_mb, "s", si->shr_cmnt) < 0)
434 			break;
435 
436 		cmnt_offs += strlen(si->shr_cmnt) + 1;
437 		esi->es_nsent++;
438 	}
439 
440 	smb_msgbuf_term(&info_mb);
441 	smb_msgbuf_term(&cmnt_mb);
442 
443 	return (NERR_Success);
444 }
445