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 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 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 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 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