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