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  * Copyright 2022 RackTop Systems, Inc.
25  */
26 
27 /*
28  * LanMan share door server
29  */
30 
31 #include <door.h>
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <syslog.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <pthread.h>
41 #include <priv.h>
42 
43 #include <smbsrv/libsmb.h>
44 #include <smbsrv/smb_share.h>
45 #include <smbsrv/smbinfo.h>
46 #include "smbd.h"
47 
48 #define	SMB_SHARE_DSRV_VERSION	1
49 #define	SMB_SHARE_DSRV_COOKIE	((void*)(0xdeadbeef^SMB_SHARE_DSRV_VERSION))
50 
51 static int smb_share_dsrv_fd = -1;
52 static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER;
53 static smbd_door_t smb_share_sdh;
54 
55 static void smbd_share_dispatch(void *, char *, size_t, door_desc_t *, uint_t);
56 
57 /*
58  * Start the LanMan share door service.
59  * Returns 0 on success. Otherwise, -1.
60  */
61 int
smbd_share_start(void)62 smbd_share_start(void)
63 {
64 	int		newfd;
65 	const char	*door_name;
66 
67 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
68 
69 	if (smb_share_dsrv_fd != -1) {
70 		syslog(LOG_ERR, "smbd_share_start: duplicate");
71 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
72 		return (smb_share_dsrv_fd);
73 	}
74 
75 	smbd_door_init(&smb_share_sdh, "share");
76 
77 	if ((smb_share_dsrv_fd = door_create(smbd_share_dispatch,
78 	    SMB_SHARE_DSRV_COOKIE, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) {
79 		syslog(LOG_ERR, "smbd_share_start: door_create: %s",
80 		    strerror(errno));
81 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
82 		return (-1);
83 	}
84 
85 	door_name = getenv("SMB_SHARE_DNAME");
86 	if (door_name == NULL)
87 		door_name = SMB_SHARE_DNAME;
88 
89 	(void) unlink(door_name);
90 
91 	if ((newfd = creat(door_name, 0644)) < 0) {
92 		syslog(LOG_ERR, "smbd_share_start: open: %s",
93 		    strerror(errno));
94 		(void) door_revoke(smb_share_dsrv_fd);
95 		smb_share_dsrv_fd = -1;
96 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
97 		return (-1);
98 	}
99 
100 	(void) close(newfd);
101 	(void) fdetach(door_name);
102 
103 	if (fattach(smb_share_dsrv_fd, door_name) < 0) {
104 		syslog(LOG_ERR, "smbd_share_start: fattach: %s",
105 		    strerror(errno));
106 		(void) door_revoke(smb_share_dsrv_fd);
107 		smb_share_dsrv_fd = -1;
108 		(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
109 		return (-1);
110 	}
111 
112 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
113 	return (smb_share_dsrv_fd);
114 }
115 
116 /*
117  * Stop the LanMan share door service.
118  */
119 void
smbd_share_stop(void)120 smbd_share_stop(void)
121 {
122 	(void) pthread_mutex_lock(&smb_share_dsrv_mtx);
123 
124 	smbd_door_fini(&smb_share_sdh);
125 
126 	if (smb_share_dsrv_fd != -1) {
127 		const char *door_name;
128 
129 		door_name = getenv("SMB_SHARE_DNAME");
130 		if (door_name == NULL)
131 			door_name = SMB_SHARE_DNAME;
132 		(void) fdetach(door_name);
133 		(void) door_revoke(smb_share_dsrv_fd);
134 		smb_share_dsrv_fd = -1;
135 	}
136 
137 	(void) pthread_mutex_unlock(&smb_share_dsrv_mtx);
138 }
139 
140 static boolean_t
have_priv_sys_smb(void)141 have_priv_sys_smb(void)
142 {
143 	ucred_t *uc = NULL;
144 	const priv_set_t *ps = NULL;
145 	boolean_t ret = B_FALSE;
146 	pid_t pid;
147 
148 	if (door_ucred(&uc) != 0) {
149 		syslog(LOG_DEBUG, "%s: door_ucred failed", __func__);
150 		goto out;
151 	}
152 
153 	/*
154 	 * in-kernel callers have pid==0
155 	 * If we have pid zero, that's sufficient.
156 	 * If not, allow with sys_smb priv (below)
157 	 */
158 	pid = ucred_getpid(uc);
159 	if (pid == 0) {
160 		ret = B_TRUE;
161 		goto out;
162 	}
163 
164 	ps = ucred_getprivset(uc, PRIV_EFFECTIVE);
165 	if (ps == NULL) {
166 		syslog(LOG_DEBUG, "%s: ucred_getprivset failed", __func__);
167 		goto out;
168 	}
169 	if (priv_ismember(ps, PRIV_SYS_SMB)) {
170 		ret = B_TRUE;
171 		goto out;
172 	}
173 
174 	syslog(LOG_DEBUG, "smbd_share_dispatch: missing privilege, "
175 	    "PID = %d UID = %d", (int)pid, ucred_getruid(uc));
176 
177 out:
178 	/* ps is free'd with the ucred */
179 	if (uc != NULL)
180 		ucred_free(uc);
181 
182 	return (ret);
183 }
184 
185 /*
186  * This function with which the LMSHARE door is associated
187  * will invoke the appropriate CIFS share management function
188  * based on the request type of the door call.
189  */
190 /*ARGSUSED*/
191 static void
smbd_share_dispatch(void * cookie,char * ptr,size_t size,door_desc_t * dp,uint_t n_desc)192 smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp,
193     uint_t n_desc)
194 {
195 	uint32_t rc;
196 	int req_type;
197 	char buf[SMB_SHARE_DSIZE];
198 	unsigned int used;
199 	smb_dr_ctx_t *dec_ctx;
200 	smb_dr_ctx_t *enc_ctx;
201 	unsigned int dec_status;
202 	unsigned int enc_status;
203 	char *sharename, *sharename2;
204 	smb_share_t lmshr_info;
205 	smb_shrlist_t lmshr_list;
206 	int offset;
207 
208 	smbd_door_enter(&smb_share_sdh);
209 
210 	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
211 	    (size < sizeof (uint32_t))) {
212 		smbd_door_return(&smb_share_sdh, NULL, 0, NULL, 0);
213 	}
214 
215 	dec_ctx = smb_dr_decode_start(ptr, size);
216 	enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
217 	req_type = smb_dr_get_uint32(dec_ctx);
218 
219 	if (req_type != SMB_SHROP_NUM_SHARES &&
220 	    req_type != SMB_SHROP_LIST &&
221 	    !have_priv_sys_smb()) {
222 		dec_status = EPERM;
223 		goto decode_error;
224 	}
225 
226 	switch (req_type) {
227 	case SMB_SHROP_NUM_SHARES:
228 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
229 			goto decode_error;
230 
231 		rc = smb_shr_count();
232 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
233 		smb_dr_put_uint32(enc_ctx, rc);
234 		break;
235 
236 	case SMB_SHROP_DELETE:
237 		sharename = smb_dr_get_string(dec_ctx);
238 
239 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
240 			smb_dr_free_string(sharename);
241 			goto decode_error;
242 		}
243 
244 		rc = smb_shr_remove(sharename);
245 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
246 		smb_dr_put_uint32(enc_ctx, rc);
247 		smb_dr_free_string(sharename);
248 		break;
249 
250 	case SMB_SHROP_RENAME:
251 		sharename = smb_dr_get_string(dec_ctx);
252 		sharename2 = smb_dr_get_string(dec_ctx);
253 
254 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
255 			smb_dr_free_string(sharename);
256 			smb_dr_free_string(sharename2);
257 			goto decode_error;
258 		}
259 
260 		rc = smb_shr_rename(sharename, sharename2);
261 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
262 		smb_dr_put_uint32(enc_ctx, rc);
263 		smb_dr_free_string(sharename);
264 		smb_dr_free_string(sharename2);
265 		break;
266 
267 	case SMB_SHROP_ADD:
268 		smb_dr_get_share(dec_ctx, &lmshr_info);
269 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
270 			goto decode_error;
271 
272 		rc = smb_shr_add(&lmshr_info);
273 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
274 		smb_dr_put_uint32(enc_ctx, rc);
275 		smb_dr_put_share(enc_ctx, &lmshr_info);
276 		break;
277 
278 	case SMB_SHROP_MODIFY:
279 		smb_dr_get_share(dec_ctx, &lmshr_info);
280 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
281 			goto decode_error;
282 		}
283 
284 		rc = smb_shr_modify(&lmshr_info);
285 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
286 		smb_dr_put_uint32(enc_ctx, rc);
287 
288 		break;
289 
290 	case SMB_SHROP_LIST:
291 		offset = smb_dr_get_int32(dec_ctx);
292 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
293 			goto decode_error;
294 
295 		smb_shr_list(offset, &lmshr_list);
296 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
297 		smb_dr_put_buf(enc_ctx, (unsigned char *)&lmshr_list,
298 		    sizeof (smb_shrlist_t));
299 		break;
300 
301 	default:
302 		dec_status = smb_dr_decode_finish(dec_ctx);
303 		goto decode_error;
304 	}
305 
306 	if ((enc_status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
307 		enc_ctx = smb_dr_encode_start(buf, sizeof (buf));
308 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
309 		smb_dr_put_uint32(enc_ctx, enc_status);
310 		(void) smb_dr_encode_finish(enc_ctx, &used);
311 	}
312 
313 	smbd_door_return(&smb_share_sdh, buf, used, NULL, 0);
314 	return;
315 
316 decode_error:
317 	smb_dr_put_int32(enc_ctx, SMB_SHARE_DERROR);
318 	smb_dr_put_uint32(enc_ctx, dec_status);
319 	(void) smb_dr_encode_finish(enc_ctx, &used);
320 	smbd_door_return(&smb_share_sdh, buf, used, NULL, 0);
321 }
322