root/source4/ntvfs/posix/pvfs_xattr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pull_xattr_blob
  2. push_xattr_blob
  3. delete_xattr
  4. pvfs_xattr_unlink_hook
  5. pvfs_xattr_ndr_load
  6. pvfs_xattr_ndr_save
  7. pvfs_dosattrib_load
  8. pvfs_dosattrib_save
  9. pvfs_doseas_load
  10. pvfs_doseas_save
  11. pvfs_streams_load
  12. pvfs_streams_save
  13. pvfs_acl_load
  14. pvfs_acl_save
  15. pvfs_xattr_create
  16. pvfs_xattr_delete
  17. pvfs_xattr_load
  18. pvfs_xattr_save
  19. pvfs_xattr_probe

   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 */
  31 static NTSTATUS pull_xattr_blob(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
  64 static NTSTATUS push_xattr_blob(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
  80 static NTSTATUS delete_xattr(struct pvfs_state *pvfs, const char *attr_name, 
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
  92 NTSTATUS pvfs_xattr_unlink_hook(struct pvfs_state *pvfs, const char *fname)
     /* [<][>][^][v][top][bottom][index][help] */
  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 */
 104 NTSTATUS pvfs_xattr_ndr_load(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 134 NTSTATUS pvfs_xattr_ndr_save(struct pvfs_state *pvfs,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 159 NTSTATUS pvfs_dosattrib_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 251 NTSTATUS pvfs_dosattrib_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 281 NTSTATUS pvfs_doseas_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 300 NTSTATUS pvfs_doseas_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 314 NTSTATUS pvfs_streams_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 335 NTSTATUS pvfs_streams_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 351 NTSTATUS pvfs_acl_load(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 369 NTSTATUS pvfs_acl_save(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 393 NTSTATUS pvfs_xattr_create(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 413 NTSTATUS pvfs_xattr_delete(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 431 NTSTATUS pvfs_xattr_load(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 452 NTSTATUS pvfs_xattr_save(struct pvfs_state *pvfs, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 472 void pvfs_xattr_probe(struct pvfs_state *pvfs)
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */