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