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 * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
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
48static int smb_share_dsrv_fd = -1;
49static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER;
50static smbd_door_t smb_share_sdh;
51
52static void smbd_share_dispatch(void *, char *, size_t, door_desc_t *, uint_t);
53
54/*
55 * Start the LanMan share door service.
56 * Returns 0 on success. Otherwise, -1.
57 */
58int
59smbd_share_start(void)
60{
61	int		newfd;
62	const char	*door_name;
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	door_name = getenv("SMB_SHARE_DNAME");
83	if (door_name == NULL)
84		door_name = SMB_SHARE_DNAME;
85
86	(void) unlink(door_name);
87
88	if ((newfd = creat(door_name, 0644)) < 0) {
89		syslog(LOG_ERR, "smbd_share_start: open: %s",
90		    strerror(errno));
91		(void) door_revoke(smb_share_dsrv_fd);
92		smb_share_dsrv_fd = -1;
93		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
94		return (-1);
95	}
96
97	(void) close(newfd);
98	(void) fdetach(door_name);
99
100	if (fattach(smb_share_dsrv_fd, door_name) < 0) {
101		syslog(LOG_ERR, "smbd_share_start: fattach: %s",
102		    strerror(errno));
103		(void) door_revoke(smb_share_dsrv_fd);
104		smb_share_dsrv_fd = -1;
105		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
106		return (-1);
107	}
108
109	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
110	return (smb_share_dsrv_fd);
111}
112
113/*
114 * Stop the LanMan share door service.
115 */
116void
117smbd_share_stop(void)
118{
119	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
120
121	smbd_door_fini(&smb_share_sdh);
122
123	if (smb_share_dsrv_fd != -1) {
124		const char *door_name;
125
126		door_name = getenv("SMB_SHARE_DNAME");
127		if (door_name == NULL)
128			door_name = SMB_SHARE_DNAME;
129		(void) fdetach(door_name);
130		(void) door_revoke(smb_share_dsrv_fd);
131		smb_share_dsrv_fd = -1;
132	}
133
134	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
135}
136
137/*
138 * This function with which the LMSHARE door is associated
139 * will invoke the appropriate CIFS share management function
140 * based on the request type of the door call.
141 */
142/*ARGSUSED*/
143static void
144smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp,
145    uint_t n_desc)
146{
147	uint32_t rc;
148	int req_type;
149	char buf[SMB_SHARE_DSIZE];
150	unsigned int used;
151	smb_dr_ctx_t *dec_ctx;
152	smb_dr_ctx_t *enc_ctx;
153	unsigned int dec_status;
154	unsigned int enc_status;
155	char *sharename, *sharename2;
156	smb_share_t lmshr_info;
157	smb_shrlist_t lmshr_list;
158	int offset;
159
160	smbd_door_enter(&smb_share_sdh);
161
162	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
163	    (size < sizeof (uint32_t))) {
164		smbd_door_return(&smb_share_sdh, NULL, 0, NULL, 0);
165	}
166
167	dec_ctx = smb_dr_decode_start(ptr, size);
168	enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
169	req_type = smb_dr_get_uint32(dec_ctx);
170
171	switch (req_type) {
172	case SMB_SHROP_NUM_SHARES:
173		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
174			goto decode_error;
175
176		rc = smb_shr_count();
177		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
178		smb_dr_put_uint32(enc_ctx, rc);
179		break;
180
181	case SMB_SHROP_DELETE:
182		sharename = smb_dr_get_string(dec_ctx);
183
184		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
185			smb_dr_free_string(sharename);
186			goto decode_error;
187		}
188
189		rc = smb_shr_remove(sharename);
190		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
191		smb_dr_put_uint32(enc_ctx, rc);
192		smb_dr_free_string(sharename);
193		break;
194
195	case SMB_SHROP_RENAME:
196		sharename = smb_dr_get_string(dec_ctx);
197		sharename2 = smb_dr_get_string(dec_ctx);
198
199		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
200			smb_dr_free_string(sharename);
201			smb_dr_free_string(sharename2);
202			goto decode_error;
203		}
204
205		rc = smb_shr_rename(sharename, sharename2);
206		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
207		smb_dr_put_uint32(enc_ctx, rc);
208		smb_dr_free_string(sharename);
209		smb_dr_free_string(sharename2);
210		break;
211
212	case SMB_SHROP_ADD:
213		smb_dr_get_share(dec_ctx, &lmshr_info);
214		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
215			goto decode_error;
216
217		rc = smb_shr_add(&lmshr_info);
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		break;
222
223	case SMB_SHROP_MODIFY:
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
229		rc = smb_shr_modify(&lmshr_info);
230		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
231		smb_dr_put_uint32(enc_ctx, rc);
232
233		break;
234
235	case SMB_SHROP_LIST:
236		offset = smb_dr_get_int32(dec_ctx);
237		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
238			goto decode_error;
239
240		smb_shr_list(offset, &lmshr_list);
241		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
242		smb_dr_put_buf(enc_ctx, (unsigned char *)&lmshr_list,
243		    sizeof (smb_shrlist_t));
244		break;
245
246	default:
247		dec_status = smb_dr_decode_finish(dec_ctx);
248		goto decode_error;
249	}
250
251	if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
252		enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
253		smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
254		smb_dr_put_uint32(enc_ctx, enc_status);
255		(void) smb_dr_encode_finish(enc_ctx, &used);
256	}
257
258	smbd_door_return(&smb_share_sdh, buf, used, NULL, 0);
259	return;
260
261decode_error:
262	smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
263	smb_dr_put_uint32(enc_ctx, dec_status);
264	(void) smb_dr_encode_finish(enc_ctx, &used);
265	smbd_door_return(&smb_share_sdh, buf, used, NULL, 0);
266}
267