| 1 | /*
|
|---|
| 2 | * Store Windows ACLs in data store - common functions.
|
|---|
| 3 | * #included into modules/vfs_acl_xattr.c and modules/vfs_acl_tdb.c
|
|---|
| 4 | *
|
|---|
| 5 | * Copyright (C) Volker Lendecke, 2008
|
|---|
| 6 | * Copyright (C) Jeremy Allison, 2009
|
|---|
| 7 | *
|
|---|
| 8 | * This program is free software; you can redistribute it and/or modify
|
|---|
| 9 | * it under the terms of the GNU General Public License as published by
|
|---|
| 10 | * the Free Software Foundation; either version 3 of the License, or
|
|---|
| 11 | * (at your option) any later version.
|
|---|
| 12 | *
|
|---|
| 13 | * This program is distributed in the hope that it will be useful,
|
|---|
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 16 | * GNU General Public License for more details.
|
|---|
| 17 | *
|
|---|
| 18 | * You should have received a copy of the GNU General Public License
|
|---|
| 19 | * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|---|
| 20 | */
|
|---|
| 21 |
|
|---|
| 22 | #include "smbd/smbd.h"
|
|---|
| 23 | #include "system/filesys.h"
|
|---|
| 24 | #include "../libcli/security/security.h"
|
|---|
| 25 | #include "../librpc/gen_ndr/ndr_security.h"
|
|---|
| 26 |
|
|---|
| 27 | static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
|
|---|
| 28 | DATA_BLOB *pblob,
|
|---|
| 29 | uint16_t hash_type,
|
|---|
| 30 | uint8_t hash[XATTR_SD_HASH_SIZE]);
|
|---|
| 31 |
|
|---|
| 32 | static NTSTATUS get_acl_blob(TALLOC_CTX *ctx,
|
|---|
| 33 | vfs_handle_struct *handle,
|
|---|
| 34 | files_struct *fsp,
|
|---|
| 35 | const char *name,
|
|---|
| 36 | DATA_BLOB *pblob);
|
|---|
| 37 |
|
|---|
| 38 | static NTSTATUS store_acl_blob_fsp(vfs_handle_struct *handle,
|
|---|
| 39 | files_struct *fsp,
|
|---|
| 40 | DATA_BLOB *pblob);
|
|---|
| 41 |
|
|---|
| 42 | #define HASH_SECURITY_INFO (SECINFO_OWNER | \
|
|---|
| 43 | SECINFO_GROUP | \
|
|---|
| 44 | SECINFO_DACL | \
|
|---|
| 45 | SECINFO_SACL)
|
|---|
| 46 |
|
|---|
| 47 | /*******************************************************************
|
|---|
| 48 | Hash a security descriptor.
|
|---|
| 49 | *******************************************************************/
|
|---|
| 50 |
|
|---|
| 51 | static NTSTATUS hash_sd_sha256(struct security_descriptor *psd,
|
|---|
| 52 | uint8_t *hash)
|
|---|
| 53 | {
|
|---|
| 54 | DATA_BLOB blob;
|
|---|
| 55 | SHA256_CTX tctx;
|
|---|
| 56 | NTSTATUS status;
|
|---|
| 57 |
|
|---|
| 58 | memset(hash, '\0', XATTR_SD_HASH_SIZE);
|
|---|
| 59 | status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
|
|---|
| 60 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 61 | return status;
|
|---|
| 62 | }
|
|---|
| 63 |
|
|---|
| 64 | SHA256_Init(&tctx);
|
|---|
| 65 | SHA256_Update(&tctx, blob.data, blob.length);
|
|---|
| 66 | SHA256_Final(hash, &tctx);
|
|---|
| 67 |
|
|---|
| 68 | return NT_STATUS_OK;
|
|---|
| 69 | }
|
|---|
| 70 |
|
|---|
| 71 | /*******************************************************************
|
|---|
| 72 | Parse out a struct security_descriptor from a DATA_BLOB.
|
|---|
| 73 | *******************************************************************/
|
|---|
| 74 |
|
|---|
| 75 | static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob,
|
|---|
| 76 | struct security_descriptor **ppdesc,
|
|---|
| 77 | uint16_t *p_hash_type,
|
|---|
| 78 | uint8_t hash[XATTR_SD_HASH_SIZE])
|
|---|
| 79 | {
|
|---|
| 80 | TALLOC_CTX *ctx = talloc_tos();
|
|---|
| 81 | struct xattr_NTACL xacl;
|
|---|
| 82 | enum ndr_err_code ndr_err;
|
|---|
| 83 | size_t sd_size;
|
|---|
| 84 |
|
|---|
| 85 | ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl,
|
|---|
| 86 | (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL);
|
|---|
| 87 |
|
|---|
| 88 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
|---|
| 89 | DEBUG(5, ("parse_acl_blob: ndr_pull_xattr_NTACL failed: %s\n",
|
|---|
| 90 | ndr_errstr(ndr_err)));
|
|---|
| 91 | return ndr_map_error2ntstatus(ndr_err);
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | switch (xacl.version) {
|
|---|
| 95 | case 2:
|
|---|
| 96 | *ppdesc = make_sec_desc(ctx, SD_REVISION,
|
|---|
| 97 | xacl.info.sd_hs2->sd->type | SEC_DESC_SELF_RELATIVE,
|
|---|
| 98 | xacl.info.sd_hs2->sd->owner_sid,
|
|---|
| 99 | xacl.info.sd_hs2->sd->group_sid,
|
|---|
| 100 | xacl.info.sd_hs2->sd->sacl,
|
|---|
| 101 | xacl.info.sd_hs2->sd->dacl,
|
|---|
| 102 | &sd_size);
|
|---|
| 103 | /* No hash - null out. */
|
|---|
| 104 | *p_hash_type = XATTR_SD_HASH_TYPE_NONE;
|
|---|
| 105 | memset(hash, '\0', XATTR_SD_HASH_SIZE);
|
|---|
| 106 | break;
|
|---|
| 107 | case 3:
|
|---|
| 108 | *ppdesc = make_sec_desc(ctx, SD_REVISION,
|
|---|
| 109 | xacl.info.sd_hs3->sd->type | SEC_DESC_SELF_RELATIVE,
|
|---|
| 110 | xacl.info.sd_hs3->sd->owner_sid,
|
|---|
| 111 | xacl.info.sd_hs3->sd->group_sid,
|
|---|
| 112 | xacl.info.sd_hs3->sd->sacl,
|
|---|
| 113 | xacl.info.sd_hs3->sd->dacl,
|
|---|
| 114 | &sd_size);
|
|---|
| 115 | *p_hash_type = xacl.info.sd_hs3->hash_type;
|
|---|
| 116 | /* Current version 3. */
|
|---|
| 117 | memcpy(hash, xacl.info.sd_hs3->hash, XATTR_SD_HASH_SIZE);
|
|---|
| 118 | break;
|
|---|
| 119 | default:
|
|---|
| 120 | return NT_STATUS_REVISION_MISMATCH;
|
|---|
| 121 | }
|
|---|
| 122 |
|
|---|
| 123 | TALLOC_FREE(xacl.info.sd);
|
|---|
| 124 |
|
|---|
| 125 | return (*ppdesc != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | /*******************************************************************
|
|---|
| 129 | Create a DATA_BLOB from a security descriptor.
|
|---|
| 130 | *******************************************************************/
|
|---|
| 131 |
|
|---|
| 132 | static NTSTATUS create_acl_blob(const struct security_descriptor *psd,
|
|---|
| 133 | DATA_BLOB *pblob,
|
|---|
| 134 | uint16_t hash_type,
|
|---|
| 135 | uint8_t hash[XATTR_SD_HASH_SIZE])
|
|---|
| 136 | {
|
|---|
| 137 | struct xattr_NTACL xacl;
|
|---|
| 138 | struct security_descriptor_hash_v3 sd_hs3;
|
|---|
| 139 | enum ndr_err_code ndr_err;
|
|---|
| 140 | TALLOC_CTX *ctx = talloc_tos();
|
|---|
| 141 |
|
|---|
| 142 | ZERO_STRUCT(xacl);
|
|---|
| 143 | ZERO_STRUCT(sd_hs3);
|
|---|
| 144 |
|
|---|
| 145 | xacl.version = 3;
|
|---|
| 146 | xacl.info.sd_hs3 = &sd_hs3;
|
|---|
| 147 | xacl.info.sd_hs3->sd = CONST_DISCARD(struct security_descriptor *, psd);
|
|---|
| 148 | xacl.info.sd_hs3->hash_type = hash_type;
|
|---|
| 149 | memcpy(&xacl.info.sd_hs3->hash[0], hash, XATTR_SD_HASH_SIZE);
|
|---|
| 150 |
|
|---|
| 151 | ndr_err = ndr_push_struct_blob(
|
|---|
| 152 | pblob, ctx, &xacl,
|
|---|
| 153 | (ndr_push_flags_fn_t)ndr_push_xattr_NTACL);
|
|---|
| 154 |
|
|---|
| 155 | if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
|---|
| 156 | DEBUG(5, ("create_acl_blob: ndr_push_xattr_NTACL failed: %s\n",
|
|---|
| 157 | ndr_errstr(ndr_err)));
|
|---|
| 158 | return ndr_map_error2ntstatus(ndr_err);
|
|---|
| 159 | }
|
|---|
| 160 |
|
|---|
| 161 | return NT_STATUS_OK;
|
|---|
| 162 | }
|
|---|
| 163 |
|
|---|
| 164 | /*******************************************************************
|
|---|
| 165 | Add in 3 inheritable components for a non-inheritable directory ACL.
|
|---|
| 166 | CREATOR_OWNER/CREATOR_GROUP/WORLD.
|
|---|
| 167 | *******************************************************************/
|
|---|
| 168 |
|
|---|
| 169 | static NTSTATUS add_directory_inheritable_components(vfs_handle_struct *handle,
|
|---|
| 170 | const char *name,
|
|---|
| 171 | SMB_STRUCT_STAT *psbuf,
|
|---|
| 172 | struct security_descriptor *psd)
|
|---|
| 173 | {
|
|---|
| 174 | struct connection_struct *conn = handle->conn;
|
|---|
| 175 | int num_aces = (psd->dacl ? psd->dacl->num_aces : 0);
|
|---|
| 176 | struct smb_filename smb_fname;
|
|---|
| 177 | enum security_ace_type acltype;
|
|---|
| 178 | uint32_t access_mask;
|
|---|
| 179 | mode_t dir_mode;
|
|---|
| 180 | mode_t file_mode;
|
|---|
| 181 | mode_t mode;
|
|---|
| 182 | struct security_ace *new_ace_list = TALLOC_ZERO_ARRAY(talloc_tos(),
|
|---|
| 183 | struct security_ace,
|
|---|
| 184 | num_aces + 3);
|
|---|
| 185 |
|
|---|
| 186 | if (new_ace_list == NULL) {
|
|---|
| 187 | return NT_STATUS_NO_MEMORY;
|
|---|
| 188 | }
|
|---|
| 189 |
|
|---|
| 190 | /* Fake a quick smb_filename. */
|
|---|
| 191 | ZERO_STRUCT(smb_fname);
|
|---|
| 192 | smb_fname.st = *psbuf;
|
|---|
| 193 | smb_fname.base_name = CONST_DISCARD(char *, name);
|
|---|
| 194 |
|
|---|
| 195 | dir_mode = unix_mode(conn,
|
|---|
| 196 | FILE_ATTRIBUTE_DIRECTORY, &smb_fname, NULL);
|
|---|
| 197 | file_mode = unix_mode(conn,
|
|---|
| 198 | FILE_ATTRIBUTE_ARCHIVE, &smb_fname, NULL);
|
|---|
| 199 |
|
|---|
| 200 | mode = dir_mode | file_mode;
|
|---|
| 201 |
|
|---|
| 202 | DEBUG(10, ("add_directory_inheritable_components: directory %s, "
|
|---|
| 203 | "mode = 0%o\n",
|
|---|
| 204 | name,
|
|---|
| 205 | (unsigned int)mode ));
|
|---|
| 206 |
|
|---|
| 207 | if (num_aces) {
|
|---|
| 208 | memcpy(new_ace_list, psd->dacl->aces,
|
|---|
| 209 | num_aces * sizeof(struct security_ace));
|
|---|
| 210 | }
|
|---|
| 211 | access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
|
|---|
| 212 | mode & 0700, false);
|
|---|
| 213 |
|
|---|
| 214 | init_sec_ace(&new_ace_list[num_aces],
|
|---|
| 215 | &global_sid_Creator_Owner,
|
|---|
| 216 | acltype,
|
|---|
| 217 | access_mask,
|
|---|
| 218 | SEC_ACE_FLAG_CONTAINER_INHERIT|
|
|---|
| 219 | SEC_ACE_FLAG_OBJECT_INHERIT|
|
|---|
| 220 | SEC_ACE_FLAG_INHERIT_ONLY);
|
|---|
| 221 | access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
|
|---|
| 222 | (mode << 3) & 0700, false);
|
|---|
| 223 | init_sec_ace(&new_ace_list[num_aces+1],
|
|---|
| 224 | &global_sid_Creator_Group,
|
|---|
| 225 | acltype,
|
|---|
| 226 | access_mask,
|
|---|
| 227 | SEC_ACE_FLAG_CONTAINER_INHERIT|
|
|---|
| 228 | SEC_ACE_FLAG_OBJECT_INHERIT|
|
|---|
| 229 | SEC_ACE_FLAG_INHERIT_ONLY);
|
|---|
| 230 | access_mask = map_canon_ace_perms(SNUM(conn), &acltype,
|
|---|
| 231 | (mode << 6) & 0700, false);
|
|---|
| 232 | init_sec_ace(&new_ace_list[num_aces+2],
|
|---|
| 233 | &global_sid_World,
|
|---|
| 234 | acltype,
|
|---|
| 235 | access_mask,
|
|---|
| 236 | SEC_ACE_FLAG_CONTAINER_INHERIT|
|
|---|
| 237 | SEC_ACE_FLAG_OBJECT_INHERIT|
|
|---|
| 238 | SEC_ACE_FLAG_INHERIT_ONLY);
|
|---|
| 239 | if (psd->dacl) {
|
|---|
| 240 | psd->dacl->aces = new_ace_list;
|
|---|
| 241 | psd->dacl->num_aces += 3;
|
|---|
| 242 | } else {
|
|---|
| 243 | psd->dacl = make_sec_acl(talloc_tos(),
|
|---|
| 244 | NT4_ACL_REVISION,
|
|---|
| 245 | 3,
|
|---|
| 246 | new_ace_list);
|
|---|
| 247 | if (psd->dacl == NULL) {
|
|---|
| 248 | return NT_STATUS_NO_MEMORY;
|
|---|
| 249 | }
|
|---|
| 250 | }
|
|---|
| 251 | return NT_STATUS_OK;
|
|---|
| 252 | }
|
|---|
| 253 |
|
|---|
| 254 | /*******************************************************************
|
|---|
| 255 | Pull a DATA_BLOB from an xattr given a pathname.
|
|---|
| 256 | If the hash doesn't match, or doesn't exist - return the underlying
|
|---|
| 257 | filesystem sd.
|
|---|
| 258 | *******************************************************************/
|
|---|
| 259 |
|
|---|
| 260 | static NTSTATUS get_nt_acl_internal(vfs_handle_struct *handle,
|
|---|
| 261 | files_struct *fsp,
|
|---|
| 262 | const char *name,
|
|---|
| 263 | uint32_t security_info,
|
|---|
| 264 | struct security_descriptor **ppdesc)
|
|---|
| 265 | {
|
|---|
| 266 | DATA_BLOB blob = data_blob_null;
|
|---|
| 267 | NTSTATUS status;
|
|---|
| 268 | uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE;
|
|---|
| 269 | uint8_t hash[XATTR_SD_HASH_SIZE];
|
|---|
| 270 | uint8_t hash_tmp[XATTR_SD_HASH_SIZE];
|
|---|
| 271 | struct security_descriptor *psd = NULL;
|
|---|
| 272 | struct security_descriptor *pdesc_next = NULL;
|
|---|
| 273 | bool ignore_file_system_acl = lp_parm_bool(SNUM(handle->conn),
|
|---|
| 274 | ACL_MODULE_NAME,
|
|---|
| 275 | "ignore system acls",
|
|---|
| 276 | false);
|
|---|
| 277 |
|
|---|
| 278 | if (fsp && name == NULL) {
|
|---|
| 279 | name = fsp->fsp_name->base_name;
|
|---|
| 280 | }
|
|---|
| 281 |
|
|---|
| 282 | DEBUG(10, ("get_nt_acl_internal: name=%s\n", name));
|
|---|
| 283 |
|
|---|
| 284 | /* Get the full underlying sd for the hash
|
|---|
| 285 | or to return as backup. */
|
|---|
| 286 | if (fsp) {
|
|---|
| 287 | status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
|
|---|
| 288 | fsp,
|
|---|
| 289 | HASH_SECURITY_INFO,
|
|---|
| 290 | &pdesc_next);
|
|---|
| 291 | } else {
|
|---|
| 292 | status = SMB_VFS_NEXT_GET_NT_ACL(handle,
|
|---|
| 293 | name,
|
|---|
| 294 | HASH_SECURITY_INFO,
|
|---|
| 295 | &pdesc_next);
|
|---|
| 296 | }
|
|---|
| 297 |
|
|---|
| 298 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 299 | DEBUG(10, ("get_nt_acl_internal: get_next_acl for file %s "
|
|---|
| 300 | "returned %s\n",
|
|---|
| 301 | name,
|
|---|
| 302 | nt_errstr(status)));
|
|---|
| 303 | return status;
|
|---|
| 304 | }
|
|---|
| 305 |
|
|---|
| 306 | status = get_acl_blob(talloc_tos(), handle, fsp, name, &blob);
|
|---|
| 307 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 308 | DEBUG(10, ("get_nt_acl_internal: get_acl_blob returned %s\n",
|
|---|
| 309 | nt_errstr(status)));
|
|---|
| 310 | psd = pdesc_next;
|
|---|
| 311 | goto out;
|
|---|
| 312 | }
|
|---|
| 313 |
|
|---|
| 314 | status = parse_acl_blob(&blob, &psd,
|
|---|
| 315 | &hash_type, &hash[0]);
|
|---|
| 316 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 317 | DEBUG(10, ("parse_acl_blob returned %s\n",
|
|---|
| 318 | nt_errstr(status)));
|
|---|
| 319 | psd = pdesc_next;
|
|---|
| 320 | goto out;
|
|---|
| 321 | }
|
|---|
| 322 |
|
|---|
| 323 | /* Ensure the hash type is one we know. */
|
|---|
| 324 | switch (hash_type) {
|
|---|
| 325 | case XATTR_SD_HASH_TYPE_NONE:
|
|---|
| 326 | /* No hash, just return blob sd. */
|
|---|
| 327 | goto out;
|
|---|
| 328 | case XATTR_SD_HASH_TYPE_SHA256:
|
|---|
| 329 | break;
|
|---|
| 330 | default:
|
|---|
| 331 | DEBUG(10, ("get_nt_acl_internal: ACL blob revision "
|
|---|
| 332 | "mismatch (%u) for file %s\n",
|
|---|
| 333 | (unsigned int)hash_type,
|
|---|
| 334 | name));
|
|---|
| 335 | TALLOC_FREE(psd);
|
|---|
| 336 | psd = pdesc_next;
|
|---|
| 337 | goto out;
|
|---|
| 338 | }
|
|---|
| 339 |
|
|---|
| 340 | if (ignore_file_system_acl) {
|
|---|
| 341 | goto out;
|
|---|
| 342 | }
|
|---|
| 343 |
|
|---|
| 344 | status = hash_sd_sha256(pdesc_next, hash_tmp);
|
|---|
| 345 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 346 | TALLOC_FREE(psd);
|
|---|
| 347 | psd = pdesc_next;
|
|---|
| 348 | goto out;
|
|---|
| 349 | }
|
|---|
| 350 |
|
|---|
| 351 | if (memcmp(&hash[0], &hash_tmp[0], XATTR_SD_HASH_SIZE) == 0) {
|
|---|
| 352 | /* Hash matches, return blob sd. */
|
|---|
| 353 | DEBUG(10, ("get_nt_acl_internal: blob hash "
|
|---|
| 354 | "matches for file %s\n",
|
|---|
| 355 | name ));
|
|---|
| 356 | goto out;
|
|---|
| 357 | }
|
|---|
| 358 |
|
|---|
| 359 | /* Hash doesn't match, return underlying sd. */
|
|---|
| 360 | TALLOC_FREE(psd);
|
|---|
| 361 | psd = pdesc_next;
|
|---|
| 362 |
|
|---|
| 363 | out:
|
|---|
| 364 |
|
|---|
| 365 | if (psd != pdesc_next) {
|
|---|
| 366 | /* We're returning the blob, throw
|
|---|
| 367 | * away the filesystem SD. */
|
|---|
| 368 | TALLOC_FREE(pdesc_next);
|
|---|
| 369 | } else {
|
|---|
| 370 | SMB_STRUCT_STAT sbuf;
|
|---|
| 371 | SMB_STRUCT_STAT *psbuf = &sbuf;
|
|---|
| 372 | bool is_directory = false;
|
|---|
| 373 | /*
|
|---|
| 374 | * We're returning the underlying ACL from the
|
|---|
| 375 | * filesystem. If it's a directory, and has no
|
|---|
| 376 | * inheritable ACE entries we have to fake them.
|
|---|
| 377 | */
|
|---|
| 378 | if (fsp) {
|
|---|
| 379 | status = vfs_stat_fsp(fsp);
|
|---|
| 380 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 381 | return status;
|
|---|
| 382 | }
|
|---|
| 383 | psbuf = &fsp->fsp_name->st;
|
|---|
| 384 | } else {
|
|---|
| 385 | int ret = vfs_stat_smb_fname(handle->conn,
|
|---|
| 386 | name,
|
|---|
| 387 | &sbuf);
|
|---|
| 388 | if (ret == -1) {
|
|---|
| 389 | return map_nt_error_from_unix(errno);
|
|---|
| 390 | }
|
|---|
| 391 | }
|
|---|
| 392 | is_directory = S_ISDIR(psbuf->st_ex_mode);
|
|---|
| 393 |
|
|---|
| 394 | if (ignore_file_system_acl) {
|
|---|
| 395 | TALLOC_FREE(pdesc_next);
|
|---|
| 396 | status = make_default_filesystem_acl(talloc_tos(),
|
|---|
| 397 | name,
|
|---|
| 398 | psbuf,
|
|---|
| 399 | &psd);
|
|---|
| 400 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 401 | return status;
|
|---|
| 402 | }
|
|---|
| 403 | } else {
|
|---|
| 404 | if (is_directory &&
|
|---|
| 405 | !sd_has_inheritable_components(psd,
|
|---|
| 406 | true)) {
|
|---|
| 407 | status = add_directory_inheritable_components(
|
|---|
| 408 | handle,
|
|---|
| 409 | name,
|
|---|
| 410 | psbuf,
|
|---|
| 411 | psd);
|
|---|
| 412 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 413 | return status;
|
|---|
| 414 | }
|
|---|
| 415 | }
|
|---|
| 416 | /* The underlying POSIX module always sets
|
|---|
| 417 | the ~SEC_DESC_DACL_PROTECTED bit, as ACLs
|
|---|
| 418 | can't be inherited in this way under POSIX.
|
|---|
| 419 | Remove it for Windows-style ACLs. */
|
|---|
| 420 | psd->type &= ~SEC_DESC_DACL_PROTECTED;
|
|---|
| 421 | }
|
|---|
| 422 | }
|
|---|
| 423 |
|
|---|
| 424 | if (!(security_info & SECINFO_OWNER)) {
|
|---|
| 425 | psd->owner_sid = NULL;
|
|---|
| 426 | }
|
|---|
| 427 | if (!(security_info & SECINFO_GROUP)) {
|
|---|
| 428 | psd->group_sid = NULL;
|
|---|
| 429 | }
|
|---|
| 430 | if (!(security_info & SECINFO_DACL)) {
|
|---|
| 431 | psd->type &= ~SEC_DESC_DACL_PRESENT;
|
|---|
| 432 | psd->dacl = NULL;
|
|---|
| 433 | }
|
|---|
| 434 | if (!(security_info & SECINFO_SACL)) {
|
|---|
| 435 | psd->type &= ~SEC_DESC_SACL_PRESENT;
|
|---|
| 436 | psd->sacl = NULL;
|
|---|
| 437 | }
|
|---|
| 438 |
|
|---|
| 439 | TALLOC_FREE(blob.data);
|
|---|
| 440 | *ppdesc = psd;
|
|---|
| 441 |
|
|---|
| 442 | if (DEBUGLEVEL >= 10) {
|
|---|
| 443 | DEBUG(10,("get_nt_acl_internal: returning acl for %s is:\n",
|
|---|
| 444 | name ));
|
|---|
| 445 | NDR_PRINT_DEBUG(security_descriptor, psd);
|
|---|
| 446 | }
|
|---|
| 447 |
|
|---|
| 448 | return NT_STATUS_OK;
|
|---|
| 449 | }
|
|---|
| 450 |
|
|---|
| 451 | /*********************************************************************
|
|---|
| 452 | Create a default ACL by inheriting from the parent. If no inheritance
|
|---|
| 453 | from the parent available, don't set anything. This will leave the actual
|
|---|
| 454 | permissions the new file or directory already got from the filesystem
|
|---|
| 455 | as the NT ACL when read.
|
|---|
| 456 | *********************************************************************/
|
|---|
| 457 |
|
|---|
| 458 | static NTSTATUS inherit_new_acl(vfs_handle_struct *handle,
|
|---|
| 459 | files_struct *fsp,
|
|---|
| 460 | struct security_descriptor *parent_desc,
|
|---|
| 461 | bool is_directory)
|
|---|
| 462 | {
|
|---|
| 463 | TALLOC_CTX *ctx = talloc_tos();
|
|---|
| 464 | NTSTATUS status = NT_STATUS_OK;
|
|---|
| 465 | struct security_descriptor *psd = NULL;
|
|---|
| 466 | struct dom_sid *owner_sid = NULL;
|
|---|
| 467 | struct dom_sid *group_sid = NULL;
|
|---|
| 468 | uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
|
|---|
| 469 | bool inherit_owner = lp_inherit_owner(SNUM(handle->conn));
|
|---|
| 470 | bool inheritable_components = sd_has_inheritable_components(parent_desc,
|
|---|
| 471 | is_directory);
|
|---|
| 472 | size_t size;
|
|---|
| 473 |
|
|---|
| 474 | if (!inheritable_components && !inherit_owner) {
|
|---|
| 475 | /* Nothing to inherit and not setting owner. */
|
|---|
| 476 | return NT_STATUS_OK;
|
|---|
| 477 | }
|
|---|
| 478 |
|
|---|
| 479 | /* Create an inherited descriptor from the parent. */
|
|---|
| 480 |
|
|---|
| 481 | if (DEBUGLEVEL >= 10) {
|
|---|
| 482 | DEBUG(10,("inherit_new_acl: parent acl for %s is:\n",
|
|---|
| 483 | fsp_str_dbg(fsp) ));
|
|---|
| 484 | NDR_PRINT_DEBUG(security_descriptor, parent_desc);
|
|---|
| 485 | }
|
|---|
| 486 |
|
|---|
| 487 | /* Inherit from parent descriptor if "inherit owner" set. */
|
|---|
| 488 | if (inherit_owner) {
|
|---|
| 489 | owner_sid = parent_desc->owner_sid;
|
|---|
| 490 | group_sid = parent_desc->group_sid;
|
|---|
| 491 | }
|
|---|
| 492 |
|
|---|
| 493 | if (owner_sid == NULL) {
|
|---|
| 494 | owner_sid = &handle->conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX];
|
|---|
| 495 | }
|
|---|
| 496 | if (group_sid == NULL) {
|
|---|
| 497 | group_sid = &handle->conn->session_info->security_token->sids[PRIMARY_GROUP_SID_INDEX];
|
|---|
| 498 | }
|
|---|
| 499 |
|
|---|
| 500 | status = se_create_child_secdesc(ctx,
|
|---|
| 501 | &psd,
|
|---|
| 502 | &size,
|
|---|
| 503 | parent_desc,
|
|---|
| 504 | owner_sid,
|
|---|
| 505 | group_sid,
|
|---|
| 506 | is_directory);
|
|---|
| 507 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 508 | return status;
|
|---|
| 509 | }
|
|---|
| 510 |
|
|---|
| 511 | /* If inheritable_components == false,
|
|---|
| 512 | se_create_child_secdesc()
|
|---|
| 513 | creates a security desriptor with a NULL dacl
|
|---|
| 514 | entry, but with SEC_DESC_DACL_PRESENT. We need
|
|---|
| 515 | to remove that flag. */
|
|---|
| 516 |
|
|---|
| 517 | if (!inheritable_components) {
|
|---|
| 518 | security_info_sent &= ~SECINFO_DACL;
|
|---|
| 519 | psd->type &= ~SEC_DESC_DACL_PRESENT;
|
|---|
| 520 | }
|
|---|
| 521 |
|
|---|
| 522 | if (DEBUGLEVEL >= 10) {
|
|---|
| 523 | DEBUG(10,("inherit_new_acl: child acl for %s is:\n",
|
|---|
| 524 | fsp_str_dbg(fsp) ));
|
|---|
| 525 | NDR_PRINT_DEBUG(security_descriptor, psd);
|
|---|
| 526 | }
|
|---|
| 527 |
|
|---|
| 528 | if (inherit_owner) {
|
|---|
| 529 | /* We need to be root to force this. */
|
|---|
| 530 | become_root();
|
|---|
| 531 | }
|
|---|
| 532 | status = SMB_VFS_FSET_NT_ACL(fsp,
|
|---|
| 533 | security_info_sent,
|
|---|
| 534 | psd);
|
|---|
| 535 | if (inherit_owner) {
|
|---|
| 536 | unbecome_root();
|
|---|
| 537 | }
|
|---|
| 538 | return status;
|
|---|
| 539 | }
|
|---|
| 540 |
|
|---|
| 541 | static NTSTATUS get_parent_acl_common(vfs_handle_struct *handle,
|
|---|
| 542 | const char *path,
|
|---|
| 543 | struct security_descriptor **pp_parent_desc)
|
|---|
| 544 | {
|
|---|
| 545 | char *parent_name = NULL;
|
|---|
| 546 | NTSTATUS status;
|
|---|
| 547 |
|
|---|
| 548 | if (!parent_dirname(talloc_tos(), path, &parent_name, NULL)) {
|
|---|
| 549 | return NT_STATUS_NO_MEMORY;
|
|---|
| 550 | }
|
|---|
| 551 |
|
|---|
| 552 | status = get_nt_acl_internal(handle,
|
|---|
| 553 | NULL,
|
|---|
| 554 | parent_name,
|
|---|
| 555 | (SECINFO_OWNER |
|
|---|
| 556 | SECINFO_GROUP |
|
|---|
| 557 | SECINFO_DACL |
|
|---|
| 558 | SECINFO_SACL),
|
|---|
| 559 | pp_parent_desc);
|
|---|
| 560 |
|
|---|
| 561 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 562 | DEBUG(10,("get_parent_acl_common: get_nt_acl_internal "
|
|---|
| 563 | "on directory %s for "
|
|---|
| 564 | "path %s returned %s\n",
|
|---|
| 565 | parent_name,
|
|---|
| 566 | path,
|
|---|
| 567 | nt_errstr(status) ));
|
|---|
| 568 | }
|
|---|
| 569 | return status;
|
|---|
| 570 | }
|
|---|
| 571 |
|
|---|
| 572 | static NTSTATUS check_parent_acl_common(vfs_handle_struct *handle,
|
|---|
| 573 | const char *path,
|
|---|
| 574 | uint32_t access_mask,
|
|---|
| 575 | struct security_descriptor **pp_parent_desc)
|
|---|
| 576 | {
|
|---|
| 577 | struct security_descriptor *parent_desc = NULL;
|
|---|
| 578 | uint32_t access_granted = 0;
|
|---|
| 579 | NTSTATUS status;
|
|---|
| 580 |
|
|---|
| 581 | status = get_parent_acl_common(handle, path, &parent_desc);
|
|---|
| 582 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 583 | return status;
|
|---|
| 584 | }
|
|---|
| 585 | if (pp_parent_desc) {
|
|---|
| 586 | *pp_parent_desc = parent_desc;
|
|---|
| 587 | }
|
|---|
| 588 | status = smb1_file_se_access_check(handle->conn,
|
|---|
| 589 | parent_desc,
|
|---|
| 590 | get_current_nttok(handle->conn),
|
|---|
| 591 | access_mask,
|
|---|
| 592 | &access_granted);
|
|---|
| 593 | if(!NT_STATUS_IS_OK(status)) {
|
|---|
| 594 | DEBUG(10,("check_parent_acl_common: access check "
|
|---|
| 595 | "on parent directory of "
|
|---|
| 596 | "path %s for mask 0x%x returned %s\n",
|
|---|
| 597 | path,
|
|---|
| 598 | access_mask,
|
|---|
| 599 | nt_errstr(status) ));
|
|---|
| 600 | return status;
|
|---|
| 601 | }
|
|---|
| 602 | return NT_STATUS_OK;
|
|---|
| 603 | }
|
|---|
| 604 |
|
|---|
| 605 | /*********************************************************************
|
|---|
| 606 | Check ACL on open. For new files inherit from parent directory.
|
|---|
| 607 | *********************************************************************/
|
|---|
| 608 |
|
|---|
| 609 | static int open_acl_common(vfs_handle_struct *handle,
|
|---|
| 610 | struct smb_filename *smb_fname,
|
|---|
| 611 | files_struct *fsp,
|
|---|
| 612 | int flags,
|
|---|
| 613 | mode_t mode)
|
|---|
| 614 | {
|
|---|
| 615 | uint32_t access_granted = 0;
|
|---|
| 616 | struct security_descriptor *pdesc = NULL;
|
|---|
| 617 | bool file_existed = true;
|
|---|
| 618 | char *fname = NULL;
|
|---|
| 619 | NTSTATUS status;
|
|---|
| 620 |
|
|---|
| 621 | if (fsp->base_fsp) {
|
|---|
| 622 | /* Stream open. Base filename open already did the ACL check. */
|
|---|
| 623 | DEBUG(10,("open_acl_common: stream open on %s\n",
|
|---|
| 624 | fsp_str_dbg(fsp) ));
|
|---|
| 625 | return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
|
|---|
| 626 | }
|
|---|
| 627 |
|
|---|
| 628 | status = get_full_smb_filename(talloc_tos(), smb_fname,
|
|---|
| 629 | &fname);
|
|---|
| 630 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 631 | goto err;
|
|---|
| 632 | }
|
|---|
| 633 |
|
|---|
| 634 | status = get_nt_acl_internal(handle,
|
|---|
| 635 | NULL,
|
|---|
| 636 | fname,
|
|---|
| 637 | (SECINFO_OWNER |
|
|---|
| 638 | SECINFO_GROUP |
|
|---|
| 639 | SECINFO_DACL |
|
|---|
| 640 | SECINFO_SACL),
|
|---|
| 641 | &pdesc);
|
|---|
| 642 | if (NT_STATUS_IS_OK(status)) {
|
|---|
| 643 | /* See if we can access it. */
|
|---|
| 644 | status = smb1_file_se_access_check(handle->conn,
|
|---|
| 645 | pdesc,
|
|---|
| 646 | get_current_nttok(handle->conn),
|
|---|
| 647 | fsp->access_mask,
|
|---|
| 648 | &access_granted);
|
|---|
| 649 | /*
|
|---|
| 650 | * Check if we need to override ACCESS_DENIED for DELETE_ACCESS.
|
|---|
| 651 | * Do this if we only failed open on DELETE_ACCESS, and
|
|---|
| 652 | * we have permission to delete from the parent directory.
|
|---|
| 653 | */
|
|---|
| 654 | if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
|
|---|
| 655 | (fsp->access_mask & DELETE_ACCESS) &&
|
|---|
| 656 | (access_granted == DELETE_ACCESS) &&
|
|---|
| 657 | can_delete_file_in_directory(handle->conn, smb_fname)) {
|
|---|
| 658 | DEBUG(10,("open_acl_xattr: "
|
|---|
| 659 | "overrode "
|
|---|
| 660 | "DELETE_ACCESS on "
|
|---|
| 661 | "file %s\n",
|
|---|
| 662 | smb_fname_str_dbg(smb_fname)));
|
|---|
| 663 | status = NT_STATUS_OK;
|
|---|
| 664 | } else if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 665 | DEBUG(10,("open_acl_xattr: %s open "
|
|---|
| 666 | "for access 0x%x (0x%x) "
|
|---|
| 667 | "refused with error %s\n",
|
|---|
| 668 | fsp_str_dbg(fsp),
|
|---|
| 669 | (unsigned int)fsp->access_mask,
|
|---|
| 670 | (unsigned int)access_granted,
|
|---|
| 671 | nt_errstr(status) ));
|
|---|
| 672 | goto err;
|
|---|
| 673 | }
|
|---|
| 674 | } else if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
|
|---|
| 675 | file_existed = false;
|
|---|
| 676 | /*
|
|---|
| 677 | * If O_CREAT is true then we're trying to create a file.
|
|---|
| 678 | * Check the parent directory ACL will allow this.
|
|---|
| 679 | */
|
|---|
| 680 | if (flags & O_CREAT) {
|
|---|
| 681 | struct security_descriptor *parent_desc = NULL;
|
|---|
| 682 | struct security_descriptor **pp_psd = NULL;
|
|---|
| 683 |
|
|---|
| 684 | status = check_parent_acl_common(handle, fname,
|
|---|
| 685 | SEC_DIR_ADD_FILE, &parent_desc);
|
|---|
| 686 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 687 | goto err;
|
|---|
| 688 | }
|
|---|
| 689 |
|
|---|
| 690 | /* Cache the parent security descriptor for
|
|---|
| 691 | * later use. */
|
|---|
| 692 |
|
|---|
| 693 | pp_psd = VFS_ADD_FSP_EXTENSION(handle,
|
|---|
| 694 | fsp,
|
|---|
| 695 | struct security_descriptor *,
|
|---|
| 696 | NULL);
|
|---|
| 697 | if (!pp_psd) {
|
|---|
| 698 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 699 | goto err;
|
|---|
| 700 | }
|
|---|
| 701 |
|
|---|
| 702 | *pp_psd = parent_desc;
|
|---|
| 703 | status = NT_STATUS_OK;
|
|---|
| 704 | }
|
|---|
| 705 | }
|
|---|
| 706 |
|
|---|
| 707 | DEBUG(10,("open_acl_xattr: get_nt_acl_attr_internal for "
|
|---|
| 708 | "%s returned %s\n",
|
|---|
| 709 | fsp_str_dbg(fsp),
|
|---|
| 710 | nt_errstr(status) ));
|
|---|
| 711 |
|
|---|
| 712 | fsp->fh->fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
|
|---|
| 713 | return fsp->fh->fd;
|
|---|
| 714 |
|
|---|
| 715 | err:
|
|---|
| 716 |
|
|---|
| 717 | errno = map_errno_from_nt_status(status);
|
|---|
| 718 | return -1;
|
|---|
| 719 | }
|
|---|
| 720 |
|
|---|
| 721 | static int mkdir_acl_common(vfs_handle_struct *handle, const char *path, mode_t mode)
|
|---|
| 722 | {
|
|---|
| 723 | int ret;
|
|---|
| 724 | NTSTATUS status;
|
|---|
| 725 | SMB_STRUCT_STAT sbuf;
|
|---|
| 726 |
|
|---|
| 727 | ret = vfs_stat_smb_fname(handle->conn, path, &sbuf);
|
|---|
| 728 | if (ret == -1 && errno == ENOENT) {
|
|---|
| 729 | /* We're creating a new directory. */
|
|---|
| 730 | status = check_parent_acl_common(handle, path,
|
|---|
| 731 | SEC_DIR_ADD_SUBDIR, NULL);
|
|---|
| 732 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 733 | errno = map_errno_from_nt_status(status);
|
|---|
| 734 | return -1;
|
|---|
| 735 | }
|
|---|
| 736 | }
|
|---|
| 737 |
|
|---|
| 738 | return SMB_VFS_NEXT_MKDIR(handle, path, mode);
|
|---|
| 739 | }
|
|---|
| 740 |
|
|---|
| 741 | /*********************************************************************
|
|---|
| 742 | Fetch a security descriptor given an fsp.
|
|---|
| 743 | *********************************************************************/
|
|---|
| 744 |
|
|---|
| 745 | static NTSTATUS fget_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
|
|---|
| 746 | uint32_t security_info, struct security_descriptor **ppdesc)
|
|---|
| 747 | {
|
|---|
| 748 | return get_nt_acl_internal(handle, fsp,
|
|---|
| 749 | NULL, security_info, ppdesc);
|
|---|
| 750 | }
|
|---|
| 751 |
|
|---|
| 752 | /*********************************************************************
|
|---|
| 753 | Fetch a security descriptor given a pathname.
|
|---|
| 754 | *********************************************************************/
|
|---|
| 755 |
|
|---|
| 756 | static NTSTATUS get_nt_acl_common(vfs_handle_struct *handle,
|
|---|
| 757 | const char *name, uint32_t security_info, struct security_descriptor **ppdesc)
|
|---|
| 758 | {
|
|---|
| 759 | return get_nt_acl_internal(handle, NULL,
|
|---|
| 760 | name, security_info, ppdesc);
|
|---|
| 761 | }
|
|---|
| 762 |
|
|---|
| 763 | /*********************************************************************
|
|---|
| 764 | Store a security descriptor given an fsp.
|
|---|
| 765 | *********************************************************************/
|
|---|
| 766 |
|
|---|
| 767 | static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp,
|
|---|
| 768 | uint32_t security_info_sent, const struct security_descriptor *orig_psd)
|
|---|
| 769 | {
|
|---|
| 770 | NTSTATUS status;
|
|---|
| 771 | DATA_BLOB blob;
|
|---|
| 772 | struct security_descriptor *pdesc_next = NULL;
|
|---|
| 773 | struct security_descriptor *psd = NULL;
|
|---|
| 774 | uint8_t hash[XATTR_SD_HASH_SIZE];
|
|---|
| 775 |
|
|---|
| 776 | if (DEBUGLEVEL >= 10) {
|
|---|
| 777 | DEBUG(10,("fset_nt_acl_xattr: incoming sd for file %s\n",
|
|---|
| 778 | fsp_str_dbg(fsp)));
|
|---|
| 779 | NDR_PRINT_DEBUG(security_descriptor,
|
|---|
| 780 | CONST_DISCARD(struct security_descriptor *,orig_psd));
|
|---|
| 781 | }
|
|---|
| 782 |
|
|---|
| 783 | status = get_nt_acl_internal(handle, fsp,
|
|---|
| 784 | NULL,
|
|---|
| 785 | SECINFO_OWNER|SECINFO_GROUP|SECINFO_DACL|SECINFO_SACL,
|
|---|
| 786 | &psd);
|
|---|
| 787 |
|
|---|
| 788 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 789 | return status;
|
|---|
| 790 | }
|
|---|
| 791 |
|
|---|
| 792 | psd->revision = orig_psd->revision;
|
|---|
| 793 | /* All our SD's are self relative. */
|
|---|
| 794 | psd->type = orig_psd->type | SEC_DESC_SELF_RELATIVE;
|
|---|
| 795 |
|
|---|
| 796 | if ((security_info_sent & SECINFO_OWNER) && (orig_psd->owner_sid != NULL)) {
|
|---|
| 797 | psd->owner_sid = orig_psd->owner_sid;
|
|---|
| 798 | }
|
|---|
| 799 | if ((security_info_sent & SECINFO_GROUP) && (orig_psd->group_sid != NULL)) {
|
|---|
| 800 | psd->group_sid = orig_psd->group_sid;
|
|---|
| 801 | }
|
|---|
| 802 | if (security_info_sent & SECINFO_DACL) {
|
|---|
| 803 | psd->dacl = orig_psd->dacl;
|
|---|
| 804 | psd->type |= SEC_DESC_DACL_PRESENT;
|
|---|
| 805 | }
|
|---|
| 806 | if (security_info_sent & SECINFO_SACL) {
|
|---|
| 807 | psd->sacl = orig_psd->sacl;
|
|---|
| 808 | psd->type |= SEC_DESC_SACL_PRESENT;
|
|---|
| 809 | }
|
|---|
| 810 |
|
|---|
| 811 | status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
|
|---|
| 812 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 813 | return status;
|
|---|
| 814 | }
|
|---|
| 815 |
|
|---|
| 816 | /* Get the full underlying sd, then hash. */
|
|---|
| 817 | status = SMB_VFS_NEXT_FGET_NT_ACL(handle,
|
|---|
| 818 | fsp,
|
|---|
| 819 | HASH_SECURITY_INFO,
|
|---|
| 820 | &pdesc_next);
|
|---|
| 821 |
|
|---|
| 822 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 823 | return status;
|
|---|
| 824 | }
|
|---|
| 825 |
|
|---|
| 826 | status = hash_sd_sha256(pdesc_next, hash);
|
|---|
| 827 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 828 | return status;
|
|---|
| 829 | }
|
|---|
| 830 |
|
|---|
| 831 | if (DEBUGLEVEL >= 10) {
|
|---|
| 832 | DEBUG(10,("fset_nt_acl_xattr: storing xattr sd for file %s\n",
|
|---|
| 833 | fsp_str_dbg(fsp)));
|
|---|
| 834 | NDR_PRINT_DEBUG(security_descriptor,
|
|---|
| 835 | CONST_DISCARD(struct security_descriptor *,psd));
|
|---|
| 836 | }
|
|---|
| 837 | status = create_acl_blob(psd, &blob, XATTR_SD_HASH_TYPE_SHA256, hash);
|
|---|
| 838 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 839 | DEBUG(10, ("fset_nt_acl_xattr: create_acl_blob failed\n"));
|
|---|
| 840 | return status;
|
|---|
| 841 | }
|
|---|
| 842 |
|
|---|
| 843 | status = store_acl_blob_fsp(handle, fsp, &blob);
|
|---|
| 844 |
|
|---|
| 845 | return status;
|
|---|
| 846 | }
|
|---|
| 847 |
|
|---|
| 848 | static SMB_STRUCT_DIR *opendir_acl_common(vfs_handle_struct *handle,
|
|---|
| 849 | const char *fname, const char *mask, uint32 attr)
|
|---|
| 850 | {
|
|---|
| 851 | NTSTATUS status;
|
|---|
| 852 | uint32_t access_granted = 0;
|
|---|
| 853 | struct security_descriptor *sd = NULL;
|
|---|
| 854 |
|
|---|
| 855 | status = get_nt_acl_internal(handle,
|
|---|
| 856 | NULL,
|
|---|
| 857 | fname,
|
|---|
| 858 | (SECINFO_OWNER |
|
|---|
| 859 | SECINFO_GROUP |
|
|---|
| 860 | SECINFO_DACL |
|
|---|
| 861 | SECINFO_SACL),
|
|---|
| 862 | &sd);
|
|---|
| 863 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 864 | DEBUG(10,("opendir_acl_common: "
|
|---|
| 865 | "get_nt_acl_internal for dir %s "
|
|---|
| 866 | "failed with error %s\n",
|
|---|
| 867 | fname,
|
|---|
| 868 | nt_errstr(status) ));
|
|---|
| 869 | errno = map_errno_from_nt_status(status);
|
|---|
| 870 | return NULL;
|
|---|
| 871 | }
|
|---|
| 872 |
|
|---|
| 873 | /* See if we can access it. */
|
|---|
| 874 | status = smb1_file_se_access_check(handle->conn,
|
|---|
| 875 | sd,
|
|---|
| 876 | get_current_nttok(handle->conn),
|
|---|
| 877 | SEC_DIR_LIST,
|
|---|
| 878 | &access_granted);
|
|---|
| 879 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 880 | DEBUG(10,("opendir_acl_common: %s open "
|
|---|
| 881 | "for access SEC_DIR_LIST "
|
|---|
| 882 | "refused with error %s\n",
|
|---|
| 883 | fname,
|
|---|
| 884 | nt_errstr(status) ));
|
|---|
| 885 | errno = map_errno_from_nt_status(status);
|
|---|
| 886 | return NULL;
|
|---|
| 887 | }
|
|---|
| 888 |
|
|---|
| 889 | return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
|
|---|
| 890 | }
|
|---|
| 891 |
|
|---|
| 892 | static int acl_common_remove_object(vfs_handle_struct *handle,
|
|---|
| 893 | const char *path,
|
|---|
| 894 | bool is_directory)
|
|---|
| 895 | {
|
|---|
| 896 | connection_struct *conn = handle->conn;
|
|---|
| 897 | struct file_id id;
|
|---|
| 898 | files_struct *fsp = NULL;
|
|---|
| 899 | int ret = 0;
|
|---|
| 900 | char *parent_dir = NULL;
|
|---|
| 901 | const char *final_component = NULL;
|
|---|
| 902 | struct smb_filename local_fname;
|
|---|
| 903 | int saved_errno = 0;
|
|---|
| 904 | char *saved_dir = NULL;
|
|---|
| 905 |
|
|---|
| 906 | saved_dir = vfs_GetWd(talloc_tos(),conn);
|
|---|
| 907 | if (!saved_dir) {
|
|---|
| 908 | saved_errno = errno;
|
|---|
| 909 | goto out;
|
|---|
| 910 | }
|
|---|
| 911 |
|
|---|
| 912 | if (!parent_dirname(talloc_tos(), path,
|
|---|
| 913 | &parent_dir, &final_component)) {
|
|---|
| 914 | saved_errno = ENOMEM;
|
|---|
| 915 | goto out;
|
|---|
| 916 | }
|
|---|
| 917 |
|
|---|
| 918 | DEBUG(10,("acl_common_remove_object: removing %s %s/%s\n",
|
|---|
| 919 | is_directory ? "directory" : "file",
|
|---|
| 920 | parent_dir, final_component ));
|
|---|
| 921 |
|
|---|
| 922 | /* cd into the parent dir to pin it. */
|
|---|
| 923 | ret = vfs_ChDir(conn, parent_dir);
|
|---|
| 924 | if (ret == -1) {
|
|---|
| 925 | saved_errno = errno;
|
|---|
| 926 | goto out;
|
|---|
| 927 | }
|
|---|
| 928 |
|
|---|
| 929 | ZERO_STRUCT(local_fname);
|
|---|
| 930 | local_fname.base_name = CONST_DISCARD(char *,final_component);
|
|---|
| 931 |
|
|---|
| 932 | /* Must use lstat here. */
|
|---|
| 933 | ret = SMB_VFS_LSTAT(conn, &local_fname);
|
|---|
| 934 | if (ret == -1) {
|
|---|
| 935 | saved_errno = errno;
|
|---|
| 936 | goto out;
|
|---|
| 937 | }
|
|---|
| 938 |
|
|---|
| 939 | /* Ensure we have this file open with DELETE access. */
|
|---|
| 940 | id = vfs_file_id_from_sbuf(conn, &local_fname.st);
|
|---|
| 941 | for (fsp = file_find_di_first(conn->sconn, id); fsp;
|
|---|
| 942 | fsp = file_find_di_next(fsp)) {
|
|---|
| 943 | if (fsp->access_mask & DELETE_ACCESS &&
|
|---|
| 944 | fsp->delete_on_close) {
|
|---|
| 945 | /* We did open this for delete,
|
|---|
| 946 | * allow the delete as root.
|
|---|
| 947 | */
|
|---|
| 948 | break;
|
|---|
| 949 | }
|
|---|
| 950 | }
|
|---|
| 951 |
|
|---|
| 952 | if (!fsp) {
|
|---|
| 953 | DEBUG(10,("acl_common_remove_object: %s %s/%s "
|
|---|
| 954 | "not an open file\n",
|
|---|
| 955 | is_directory ? "directory" : "file",
|
|---|
| 956 | parent_dir, final_component ));
|
|---|
| 957 | saved_errno = EACCES;
|
|---|
| 958 | goto out;
|
|---|
| 959 | }
|
|---|
| 960 |
|
|---|
| 961 | become_root();
|
|---|
| 962 | if (is_directory) {
|
|---|
| 963 | ret = SMB_VFS_NEXT_RMDIR(handle, final_component);
|
|---|
| 964 | } else {
|
|---|
| 965 | ret = SMB_VFS_NEXT_UNLINK(handle, &local_fname);
|
|---|
| 966 | }
|
|---|
| 967 | unbecome_root();
|
|---|
| 968 |
|
|---|
| 969 | if (ret == -1) {
|
|---|
| 970 | saved_errno = errno;
|
|---|
| 971 | }
|
|---|
| 972 |
|
|---|
| 973 | out:
|
|---|
| 974 |
|
|---|
| 975 | TALLOC_FREE(parent_dir);
|
|---|
| 976 |
|
|---|
| 977 | if (saved_dir) {
|
|---|
| 978 | vfs_ChDir(conn, saved_dir);
|
|---|
| 979 | }
|
|---|
| 980 | if (saved_errno) {
|
|---|
| 981 | errno = saved_errno;
|
|---|
| 982 | }
|
|---|
| 983 | return ret;
|
|---|
| 984 | }
|
|---|
| 985 |
|
|---|
| 986 | static int rmdir_acl_common(struct vfs_handle_struct *handle,
|
|---|
| 987 | const char *path)
|
|---|
| 988 | {
|
|---|
| 989 | int ret;
|
|---|
| 990 |
|
|---|
| 991 | /* Try the normal rmdir first. */
|
|---|
| 992 | ret = SMB_VFS_NEXT_RMDIR(handle, path);
|
|---|
| 993 | if (ret == 0) {
|
|---|
| 994 | return 0;
|
|---|
| 995 | }
|
|---|
| 996 | if (errno == EACCES || errno == EPERM) {
|
|---|
| 997 | /* Failed due to access denied,
|
|---|
| 998 | see if we need to root override. */
|
|---|
| 999 | return acl_common_remove_object(handle,
|
|---|
| 1000 | path,
|
|---|
| 1001 | true);
|
|---|
| 1002 | }
|
|---|
| 1003 |
|
|---|
| 1004 | DEBUG(10,("rmdir_acl_common: unlink of %s failed %s\n",
|
|---|
| 1005 | path,
|
|---|
| 1006 | strerror(errno) ));
|
|---|
| 1007 | return -1;
|
|---|
| 1008 | }
|
|---|
| 1009 |
|
|---|
| 1010 | static NTSTATUS create_file_acl_common(struct vfs_handle_struct *handle,
|
|---|
| 1011 | struct smb_request *req,
|
|---|
| 1012 | uint16_t root_dir_fid,
|
|---|
| 1013 | struct smb_filename *smb_fname,
|
|---|
| 1014 | uint32_t access_mask,
|
|---|
| 1015 | uint32_t share_access,
|
|---|
| 1016 | uint32_t create_disposition,
|
|---|
| 1017 | uint32_t create_options,
|
|---|
| 1018 | uint32_t file_attributes,
|
|---|
| 1019 | uint32_t oplock_request,
|
|---|
| 1020 | uint64_t allocation_size,
|
|---|
| 1021 | uint32_t private_flags,
|
|---|
| 1022 | struct security_descriptor *sd,
|
|---|
| 1023 | struct ea_list *ea_list,
|
|---|
| 1024 | files_struct **result,
|
|---|
| 1025 | int *pinfo)
|
|---|
| 1026 | {
|
|---|
| 1027 | NTSTATUS status, status1;
|
|---|
| 1028 | files_struct *fsp = NULL;
|
|---|
| 1029 | int info;
|
|---|
| 1030 | struct security_descriptor *parent_sd = NULL;
|
|---|
| 1031 | struct security_descriptor **pp_parent_sd = NULL;
|
|---|
| 1032 |
|
|---|
| 1033 | status = SMB_VFS_NEXT_CREATE_FILE(handle,
|
|---|
| 1034 | req,
|
|---|
| 1035 | root_dir_fid,
|
|---|
| 1036 | smb_fname,
|
|---|
| 1037 | access_mask,
|
|---|
| 1038 | share_access,
|
|---|
| 1039 | create_disposition,
|
|---|
| 1040 | create_options,
|
|---|
| 1041 | file_attributes,
|
|---|
| 1042 | oplock_request,
|
|---|
| 1043 | allocation_size,
|
|---|
| 1044 | private_flags,
|
|---|
| 1045 | sd,
|
|---|
| 1046 | ea_list,
|
|---|
| 1047 | result,
|
|---|
| 1048 | &info);
|
|---|
| 1049 |
|
|---|
| 1050 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 1051 | goto out;
|
|---|
| 1052 | }
|
|---|
| 1053 |
|
|---|
| 1054 | if (info != FILE_WAS_CREATED) {
|
|---|
| 1055 | /* File/directory was opened, not created. */
|
|---|
| 1056 | goto out;
|
|---|
| 1057 | }
|
|---|
| 1058 |
|
|---|
| 1059 | fsp = *result;
|
|---|
| 1060 |
|
|---|
| 1061 | if (fsp == NULL) {
|
|---|
| 1062 | /* Only handle success. */
|
|---|
| 1063 | goto out;
|
|---|
| 1064 | }
|
|---|
| 1065 |
|
|---|
| 1066 | if (sd) {
|
|---|
| 1067 | /* Security descriptor already set. */
|
|---|
| 1068 | goto out;
|
|---|
| 1069 | }
|
|---|
| 1070 |
|
|---|
| 1071 | if (fsp->base_fsp) {
|
|---|
| 1072 | /* Stream open. */
|
|---|
| 1073 | goto out;
|
|---|
| 1074 | }
|
|---|
| 1075 |
|
|---|
| 1076 | /* See if we have a cached parent sd, if so, use it. */
|
|---|
| 1077 | pp_parent_sd = (struct security_descriptor **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
|
|---|
| 1078 | if (!pp_parent_sd) {
|
|---|
| 1079 | /* Must be a directory, fetch again (sigh). */
|
|---|
| 1080 | status = get_parent_acl_common(handle,
|
|---|
| 1081 | fsp->fsp_name->base_name,
|
|---|
| 1082 | &parent_sd);
|
|---|
| 1083 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 1084 | goto out;
|
|---|
| 1085 | }
|
|---|
| 1086 | } else {
|
|---|
| 1087 | parent_sd = *pp_parent_sd;
|
|---|
| 1088 | }
|
|---|
| 1089 |
|
|---|
| 1090 | if (!parent_sd) {
|
|---|
| 1091 | goto err;
|
|---|
| 1092 | }
|
|---|
| 1093 |
|
|---|
| 1094 | /* New directory - inherit from parent. */
|
|---|
| 1095 | status1 = inherit_new_acl(handle, fsp, parent_sd, fsp->is_directory);
|
|---|
| 1096 |
|
|---|
| 1097 | if (!NT_STATUS_IS_OK(status1)) {
|
|---|
| 1098 | DEBUG(1,("create_file_acl_common: error setting "
|
|---|
| 1099 | "sd for %s (%s)\n",
|
|---|
| 1100 | fsp_str_dbg(fsp),
|
|---|
| 1101 | nt_errstr(status1) ));
|
|---|
| 1102 | }
|
|---|
| 1103 |
|
|---|
| 1104 | out:
|
|---|
| 1105 |
|
|---|
| 1106 | if (fsp) {
|
|---|
| 1107 | VFS_REMOVE_FSP_EXTENSION(handle, fsp);
|
|---|
| 1108 | }
|
|---|
| 1109 |
|
|---|
| 1110 | if (NT_STATUS_IS_OK(status) && pinfo) {
|
|---|
| 1111 | *pinfo = info;
|
|---|
| 1112 | }
|
|---|
| 1113 | return status;
|
|---|
| 1114 |
|
|---|
| 1115 | err:
|
|---|
| 1116 |
|
|---|
| 1117 | smb_panic("create_file_acl_common: logic error.\n");
|
|---|
| 1118 | /* NOTREACHED */
|
|---|
| 1119 | return status;
|
|---|
| 1120 | }
|
|---|
| 1121 |
|
|---|
| 1122 | static int unlink_acl_common(struct vfs_handle_struct *handle,
|
|---|
| 1123 | const struct smb_filename *smb_fname)
|
|---|
| 1124 | {
|
|---|
| 1125 | int ret;
|
|---|
| 1126 |
|
|---|
| 1127 | /* Try the normal unlink first. */
|
|---|
| 1128 | ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
|
|---|
| 1129 | if (ret == 0) {
|
|---|
| 1130 | return 0;
|
|---|
| 1131 | }
|
|---|
| 1132 | if (errno == EACCES || errno == EPERM) {
|
|---|
| 1133 | /* Failed due to access denied,
|
|---|
| 1134 | see if we need to root override. */
|
|---|
| 1135 |
|
|---|
| 1136 | /* Don't do anything fancy for streams. */
|
|---|
| 1137 | if (smb_fname->stream_name) {
|
|---|
| 1138 | return -1;
|
|---|
| 1139 | }
|
|---|
| 1140 | return acl_common_remove_object(handle,
|
|---|
| 1141 | smb_fname->base_name,
|
|---|
| 1142 | false);
|
|---|
| 1143 | }
|
|---|
| 1144 |
|
|---|
| 1145 | DEBUG(10,("unlink_acl_common: unlink of %s failed %s\n",
|
|---|
| 1146 | smb_fname->base_name,
|
|---|
| 1147 | strerror(errno) ));
|
|---|
| 1148 | return -1;
|
|---|
| 1149 | }
|
|---|
| 1150 |
|
|---|
| 1151 | static int chmod_acl_module_common(struct vfs_handle_struct *handle,
|
|---|
| 1152 | const char *path, mode_t mode)
|
|---|
| 1153 | {
|
|---|
| 1154 | if (lp_posix_pathnames()) {
|
|---|
| 1155 | /* Only allow this on POSIX pathnames. */
|
|---|
| 1156 | return SMB_VFS_NEXT_CHMOD(handle, path, mode);
|
|---|
| 1157 | }
|
|---|
| 1158 | return 0;
|
|---|
| 1159 | }
|
|---|
| 1160 |
|
|---|
| 1161 | static int fchmod_acl_module_common(struct vfs_handle_struct *handle,
|
|---|
| 1162 | struct files_struct *fsp, mode_t mode)
|
|---|
| 1163 | {
|
|---|
| 1164 | if (fsp->posix_open) {
|
|---|
| 1165 | /* Only allow this on POSIX opens. */
|
|---|
| 1166 | return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
|
|---|
| 1167 | }
|
|---|
| 1168 | return 0;
|
|---|
| 1169 | }
|
|---|
| 1170 |
|
|---|
| 1171 | static int chmod_acl_acl_module_common(struct vfs_handle_struct *handle,
|
|---|
| 1172 | const char *name, mode_t mode)
|
|---|
| 1173 | {
|
|---|
| 1174 | if (lp_posix_pathnames()) {
|
|---|
| 1175 | /* Only allow this on POSIX pathnames. */
|
|---|
| 1176 | return SMB_VFS_NEXT_CHMOD_ACL(handle, name, mode);
|
|---|
| 1177 | }
|
|---|
| 1178 | return 0;
|
|---|
| 1179 | }
|
|---|
| 1180 |
|
|---|
| 1181 | static int fchmod_acl_acl_module_common(struct vfs_handle_struct *handle,
|
|---|
| 1182 | struct files_struct *fsp, mode_t mode)
|
|---|
| 1183 | {
|
|---|
| 1184 | if (fsp->posix_open) {
|
|---|
| 1185 | /* Only allow this on POSIX opens. */
|
|---|
| 1186 | return SMB_VFS_NEXT_FCHMOD_ACL(handle, fsp, mode);
|
|---|
| 1187 | }
|
|---|
| 1188 | return 0;
|
|---|
| 1189 | }
|
|---|