1/* 2 Unix SMB/CIFS implementation. 3 4 POSIX NTVFS backend - xattr support 5 6 Copyright (C) Andrew Tridgell 2004 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 "includes.h" 23#include "vfs_posix.h" 24#include "../lib/util/unix_privs.h" 25#include "librpc/gen_ndr/ndr_xattr.h" 26#include "param/param.h" 27 28/* 29 pull a xattr as a blob 30*/ 31static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs, 32 TALLOC_CTX *mem_ctx, 33 const char *attr_name, 34 const char *fname, 35 int fd, 36 size_t estimated_size, 37 DATA_BLOB *blob) 38{ 39 NTSTATUS status; 40 41 if (pvfs->ea_db) { 42 return pull_xattr_blob_tdb(pvfs, mem_ctx, attr_name, fname, 43 fd, estimated_size, blob); 44 } 45 46 status = pull_xattr_blob_system(pvfs, mem_ctx, attr_name, fname, 47 fd, estimated_size, blob); 48 49 /* if the filesystem doesn't support them, then tell pvfs not to try again */ 50 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)|| 51 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)|| 52 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_SYSTEM_SERVICE)) { 53 DEBUG(2,("pvfs_xattr: xattr not supported in filesystem: %s\n", nt_errstr(status))); 54 pvfs->flags &= ~PVFS_FLAG_XATTR_ENABLE; 55 status = NT_STATUS_NOT_FOUND; 56 } 57 58 return status; 59} 60 61/* 62 push a xattr as a blob 63*/ 64static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs, 65 const char *attr_name, 66 const char *fname, 67 int fd, 68 const DATA_BLOB *blob) 69{ 70 if (pvfs->ea_db) { 71 return push_xattr_blob_tdb(pvfs, attr_name, fname, fd, blob); 72 } 73 return push_xattr_blob_system(pvfs, attr_name, fname, fd, blob); 74} 75 76 77/* 78 delete a xattr 79*/ 80static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name, 81 const char *fname, int fd) 82{ 83 if (pvfs->ea_db) { 84 return delete_xattr_tdb(pvfs, attr_name, fname, fd); 85 } 86 return delete_xattr_system(pvfs, attr_name, fname, fd); 87} 88 89/* 90 a hook called on unlink - allows the tdb xattr backend to cleanup 91*/ 92NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname) 93{ 94 if (pvfs->ea_db) { 95 return unlink_xattr_tdb(pvfs, fname); 96 } 97 return unlink_xattr_system(pvfs, fname); 98} 99 100 101/* 102 load a NDR structure from a xattr 103*/ 104NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs, 105 TALLOC_CTX *mem_ctx, 106 const char *fname, int fd, const char *attr_name, 107 void *p, void *pull_fn) 108{ 109 NTSTATUS status; 110 DATA_BLOB blob; 111 enum ndr_err_code ndr_err; 112 113 status = pull_xattr_blob(pvfs, mem_ctx, attr_name, fname, 114 fd, XATTR_DOSATTRIB_ESTIMATED_SIZE, &blob); 115 if (!NT_STATUS_IS_OK(status)) { 116 return status; 117 } 118 119 /* pull the blob */ 120 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), 121 p, (ndr_pull_flags_fn_t)pull_fn); 122 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 123 return ndr_map_error2ntstatus(ndr_err); 124 } 125 126 data_blob_free(&blob); 127 128 return NT_STATUS_OK; 129} 130 131/* 132 save a NDR structure into a xattr 133*/ 134NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs, 135 const char *fname, int fd, const char *attr_name, 136 void *p, void *push_fn) 137{ 138 TALLOC_CTX *mem_ctx = talloc_new(NULL); 139 DATA_BLOB blob; 140 NTSTATUS status; 141 enum ndr_err_code ndr_err; 142 143 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), p, (ndr_push_flags_fn_t)push_fn); 144 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 145 talloc_free(mem_ctx); 146 return ndr_map_error2ntstatus(ndr_err); 147 } 148 149 status = push_xattr_blob(pvfs, attr_name, fname, fd, &blob); 150 talloc_free(mem_ctx); 151 152 return status; 153} 154 155 156/* 157 fill in file attributes from extended attributes 158*/ 159NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd) 160{ 161 NTSTATUS status; 162 struct xattr_DosAttrib attrib; 163 TALLOC_CTX *mem_ctx = talloc_new(name); 164 struct xattr_DosInfo1 *info1; 165 struct xattr_DosInfo2Old *info2; 166 167 if (name->stream_name != NULL) { 168 name->stream_exists = false; 169 } else { 170 name->stream_exists = true; 171 } 172 173 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 174 return NT_STATUS_OK; 175 } 176 177 status = pvfs_xattr_ndr_load(pvfs, mem_ctx, name->full_name, 178 fd, XATTR_DOSATTRIB_NAME, 179 &attrib, 180 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosAttrib); 181 182 /* not having a DosAttrib is not an error */ 183 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { 184 talloc_free(mem_ctx); 185 return pvfs_stream_info(pvfs, name, fd); 186 } 187 188 if (!NT_STATUS_IS_OK(status)) { 189 talloc_free(mem_ctx); 190 return status; 191 } 192 193 switch (attrib.version) { 194 case 1: 195 info1 = &attrib.info.info1; 196 name->dos.attrib = pvfs_attrib_normalise(info1->attrib, 197 name->st.st_mode); 198 name->dos.ea_size = info1->ea_size; 199 if (name->st.st_size == info1->size) { 200 name->dos.alloc_size = 201 pvfs_round_alloc_size(pvfs, info1->alloc_size); 202 } 203 if (!null_nttime(info1->create_time)) { 204 name->dos.create_time = info1->create_time; 205 } 206 if (!null_nttime(info1->change_time)) { 207 name->dos.change_time = info1->change_time; 208 } 209 name->dos.flags = 0; 210 break; 211 212 case 2: 213 /* 214 * Note: This is only used to parse existing values from disk 215 * We use xattr_DosInfo1 again for storing new values 216 */ 217 info2 = &attrib.info.oldinfo2; 218 name->dos.attrib = pvfs_attrib_normalise(info2->attrib, 219 name->st.st_mode); 220 name->dos.ea_size = info2->ea_size; 221 if (name->st.st_size == info2->size) { 222 name->dos.alloc_size = 223 pvfs_round_alloc_size(pvfs, info2->alloc_size); 224 } 225 if (!null_nttime(info2->create_time)) { 226 name->dos.create_time = info2->create_time; 227 } 228 if (!null_nttime(info2->change_time)) { 229 name->dos.change_time = info2->change_time; 230 } 231 name->dos.flags = info2->flags; 232 break; 233 234 default: 235 DEBUG(0,("ERROR: Unsupported xattr DosAttrib version %d on '%s'\n", 236 attrib.version, name->full_name)); 237 talloc_free(mem_ctx); 238 return NT_STATUS_INVALID_LEVEL; 239 } 240 talloc_free(mem_ctx); 241 242 status = pvfs_stream_info(pvfs, name, fd); 243 244 return status; 245} 246 247 248/* 249 save the file attribute into the xattr 250*/ 251NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd) 252{ 253 struct xattr_DosAttrib attrib; 254 struct xattr_DosInfo1 *info1; 255 256 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 257 return NT_STATUS_OK; 258 } 259 260 attrib.version = 1; 261 info1 = &attrib.info.info1; 262 263 name->dos.attrib = pvfs_attrib_normalise(name->dos.attrib, name->st.st_mode); 264 265 info1->attrib = name->dos.attrib; 266 info1->ea_size = name->dos.ea_size; 267 info1->size = name->st.st_size; 268 info1->alloc_size = name->dos.alloc_size; 269 info1->create_time = name->dos.create_time; 270 info1->change_time = name->dos.change_time; 271 272 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 273 XATTR_DOSATTRIB_NAME, &attrib, 274 (ndr_push_flags_fn_t)ndr_push_xattr_DosAttrib); 275} 276 277 278/* 279 load the set of DOS EAs 280*/ 281NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, 282 struct xattr_DosEAs *eas) 283{ 284 NTSTATUS status; 285 ZERO_STRUCTP(eas); 286 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 287 return NT_STATUS_OK; 288 } 289 status = pvfs_xattr_ndr_load(pvfs, eas, name->full_name, fd, XATTR_DOSEAS_NAME, 290 eas, (ndr_pull_flags_fn_t)ndr_pull_xattr_DosEAs); 291 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { 292 return NT_STATUS_OK; 293 } 294 return status; 295} 296 297/* 298 save the set of DOS EAs 299*/ 300NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, 301 struct xattr_DosEAs *eas) 302{ 303 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 304 return NT_STATUS_OK; 305 } 306 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, XATTR_DOSEAS_NAME, eas, 307 (ndr_push_flags_fn_t)ndr_push_xattr_DosEAs); 308} 309 310 311/* 312 load the set of streams from extended attributes 313*/ 314NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, 315 struct xattr_DosStreams *streams) 316{ 317 NTSTATUS status; 318 ZERO_STRUCTP(streams); 319 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 320 return NT_STATUS_OK; 321 } 322 status = pvfs_xattr_ndr_load(pvfs, streams, name->full_name, fd, 323 XATTR_DOSSTREAMS_NAME, 324 streams, 325 (ndr_pull_flags_fn_t)ndr_pull_xattr_DosStreams); 326 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { 327 return NT_STATUS_OK; 328 } 329 return status; 330} 331 332/* 333 save the set of streams into filesystem xattr 334*/ 335NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, 336 struct xattr_DosStreams *streams) 337{ 338 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 339 return NT_STATUS_OK; 340 } 341 return pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 342 XATTR_DOSSTREAMS_NAME, 343 streams, 344 (ndr_push_flags_fn_t)ndr_push_xattr_DosStreams); 345} 346 347 348/* 349 load the current ACL from extended attributes 350*/ 351NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, 352 struct xattr_NTACL *acl) 353{ 354 NTSTATUS status; 355 ZERO_STRUCTP(acl); 356 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 357 return NT_STATUS_NOT_FOUND; 358 } 359 status = pvfs_xattr_ndr_load(pvfs, acl, name->full_name, fd, 360 XATTR_NTACL_NAME, 361 acl, 362 (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL); 363 return status; 364} 365 366/* 367 save the acl for a file into filesystem xattr 368*/ 369NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd, 370 struct xattr_NTACL *acl) 371{ 372 NTSTATUS status; 373 void *privs; 374 375 if (!(pvfs->flags & PVFS_FLAG_XATTR_ENABLE)) { 376 return NT_STATUS_OK; 377 } 378 379 /* this xattr is in the "system" namespace, so we need 380 admin privileges to set it */ 381 privs = root_privileges(); 382 status = pvfs_xattr_ndr_save(pvfs, name->full_name, fd, 383 XATTR_NTACL_NAME, 384 acl, 385 (ndr_push_flags_fn_t)ndr_push_xattr_NTACL); 386 talloc_free(privs); 387 return status; 388} 389 390/* 391 create a zero length xattr with the given name 392*/ 393NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs, 394 const char *fname, int fd, 395 const char *attr_prefix, 396 const char *attr_name) 397{ 398 NTSTATUS status; 399 DATA_BLOB blob = data_blob(NULL, 0); 400 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name); 401 if (aname == NULL) { 402 return NT_STATUS_NO_MEMORY; 403 } 404 status = push_xattr_blob(pvfs, aname, fname, fd, &blob); 405 talloc_free(aname); 406 return status; 407} 408 409 410/* 411 delete a xattr with the given name 412*/ 413NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs, 414 const char *fname, int fd, 415 const char *attr_prefix, 416 const char *attr_name) 417{ 418 NTSTATUS status; 419 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name); 420 if (aname == NULL) { 421 return NT_STATUS_NO_MEMORY; 422 } 423 status = delete_xattr(pvfs, aname, fname, fd); 424 talloc_free(aname); 425 return status; 426} 427 428/* 429 load a xattr with the given name 430*/ 431NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs, 432 TALLOC_CTX *mem_ctx, 433 const char *fname, int fd, 434 const char *attr_prefix, 435 const char *attr_name, 436 size_t estimated_size, 437 DATA_BLOB *blob) 438{ 439 NTSTATUS status; 440 char *aname = talloc_asprintf(mem_ctx, "%s%s", attr_prefix, attr_name); 441 if (aname == NULL) { 442 return NT_STATUS_NO_MEMORY; 443 } 444 status = pull_xattr_blob(pvfs, mem_ctx, aname, fname, fd, estimated_size, blob); 445 talloc_free(aname); 446 return status; 447} 448 449/* 450 save a xattr with the given name 451*/ 452NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs, 453 const char *fname, int fd, 454 const char *attr_prefix, 455 const char *attr_name, 456 const DATA_BLOB *blob) 457{ 458 NTSTATUS status; 459 char *aname = talloc_asprintf(NULL, "%s%s", attr_prefix, attr_name); 460 if (aname == NULL) { 461 return NT_STATUS_NO_MEMORY; 462 } 463 status = push_xattr_blob(pvfs, aname, fname, fd, blob); 464 talloc_free(aname); 465 return status; 466} 467 468 469/* 470 probe for system support for xattrs 471*/ 472void pvfs_xattr_probe(struct pvfs_state *pvfs) 473{ 474 TALLOC_CTX *tmp_ctx = talloc_new(pvfs); 475 DATA_BLOB blob; 476 pull_xattr_blob(pvfs, tmp_ctx, "user.XattrProbe", pvfs->base_directory, 477 -1, 1, &blob); 478 pull_xattr_blob(pvfs, tmp_ctx, "security.XattrProbe", pvfs->base_directory, 479 -1, 1, &blob); 480 talloc_free(tmp_ctx); 481} 482