/* * Get the Access and/or Default ACL of a file. */ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp) { struct posix_acl *acl; struct inode *inode; svc_fh *fh; __be32 nfserr = 0; dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); if (nfserr) RETURN_STATUS(nfserr); inode = fh->fh_dentry->d_inode; if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) RETURN_STATUS(nfserr_inval); resp->mask = argp->mask; nfserr = fh_getattr(fh, &resp->stat); if (nfserr) goto fail; if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { acl = get_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) { nfserr = nfserrno(PTR_ERR(acl)); goto fail; } if (acl == NULL) { /* Solaris returns the inode's minimum ACL. */ acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); } resp->acl_access = acl; } if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) { /* Check how Solaris handles requests for the Default ACL of a non-directory! */ acl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) { nfserr = nfserrno(PTR_ERR(acl)); goto fail; } resp->acl_default = acl; } /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ RETURN_STATUS(0); fail: posix_acl_release(resp->acl_access); posix_acl_release(resp->acl_default); RETURN_STATUS(nfserr); }
int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl) { struct inode *inode = d_inode(dentry); int error = 0; struct posix_acl *pacl = NULL, *dpacl = NULL; unsigned int flags = 0; int size = 0; pacl = get_acl(inode, ACL_TYPE_ACCESS); if (!pacl) pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); if (IS_ERR(pacl)) return PTR_ERR(pacl); /* allocate for worst case: one (deny, allow) pair each: */ size += 2 * pacl->a_count; if (S_ISDIR(inode->i_mode)) { flags = NFS4_ACL_DIR; dpacl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(dpacl)) { error = PTR_ERR(dpacl); goto rel_pacl; } if (dpacl) size += 2 * dpacl->a_count; } *acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL); if (*acl == NULL) { error = -ENOMEM; goto out; } (*acl)->naces = 0; _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT); if (dpacl) _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT); out: posix_acl_release(dpacl); rel_pacl: posix_acl_release(pacl); return error; }
/* This is used to cache the default acl before a new object is created. * The biggest reason for this is to get an idea of how many blocks will * actually be required for the create operation if we must inherit an ACL. * An ACL write can add up to 3 object creations and an additional file write * so we'd prefer not to reserve that many blocks in the journal if we can. * It also has the advantage of not loading the ACL with a transaction open, * this may seem silly, but if the owner of the directory is doing the * creation, the ACL may not be loaded since the permissions wouldn't require * it. * We return the number of blocks required for the transaction. */ int reiserfs_cache_default_acl(struct inode *inode) { struct posix_acl *acl; int nblocks = 0; if (IS_PRIVATE(inode)) return 0; acl = get_acl(inode, ACL_TYPE_DEFAULT); if (acl && !IS_ERR(acl)) { int size = reiserfs_acl_size(acl->a_count); /* Other xattrs can be created during inode creation. We don't * want to claim too many blocks, so we check to see if we * we need to create the tree to the xattrs, and then we * just want two files. */ nblocks = reiserfs_xattr_jcreate_nblocks(inode); nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); REISERFS_I(inode)->i_flags |= i_has_xattr_dir; /* We need to account for writes + bitmaps for two files */ nblocks += reiserfs_xattr_nblocks(inode, size) * 4; posix_acl_release(acl); } return nblocks; }
void init_tree(t_tree *tree, t_tree *ref, t_data *data) { char *str; tree->type = '-'; tree->acl = get_acl(tree->full_path); tree->rights[0] = (tree->stat.st_mode & S_IRUSR) ? 'r' : '-'; tree->rights[1] = (tree->stat.st_mode & S_IWUSR) ? 'w' : '-'; tree->rights[2] = (tree->stat.st_mode & S_IXUSR) ? 'x' : '-'; tree->rights[3] = (tree->stat.st_mode & S_IRGRP) ? 'r' : '-'; tree->rights[4] = (tree->stat.st_mode & S_IWGRP) ? 'w' : '-'; tree->rights[5] = (tree->stat.st_mode & S_IXGRP) ? 'x' : '-'; tree->rights[6] = (tree->stat.st_mode & S_IROTH) ? 'r' : '-'; tree->rights[7] = (tree->stat.st_mode & S_IWOTH) ? 'w' : '-'; tree->rights[8] = (tree->stat.st_mode & S_IXOTH) ? 'x' : '-'; tree->type = (S_ISDIR(tree->stat.st_mode) ? 'd' : tree->type); tree->type = (S_ISSOCK(tree->stat.st_mode) ? 's' : tree->type); tree->type = (S_ISFIFO(tree->stat.st_mode) ? 'p' : tree->type); tree->type = (S_ISCHR(tree->stat.st_mode) ? 'c' : tree->type); tree->type = (S_ISBLK(tree->stat.st_mode) ? 'b' : tree->type); tree->type = (S_ISLNK(tree->stat.st_mode) ? 'l' : tree->type); str = ft_itoa(tree->stat.st_nlink); if (ft_strlen(str) > (size_t)ref->physical_link_len) ref->physical_link_len = ft_strlen(str); free(str); get_id(tree, ref, data); }
int get_extrameta(struct asfd *asfd, BFILE *bfd, struct sbuf *sb, char **extrameta, size_t *elen, struct conf **confs) { #if defined (WIN32_VSS) if(get_vss(bfd, sb, extrameta, elen, confs)) return -1; #endif // Important to do xattr directly after acl, because xattr is excluding // some entries if acls were set. #if defined(HAVE_LINUX_OS) || \ defined(HAVE_FREEBSD_OS) || \ defined(HAVE_OPENBSD_OS) || \ defined(HAVE_NETBSD_OS) #ifdef HAVE_ACL if(get_acl(asfd, sb, extrameta, elen, confs)) return -1; #endif #endif #if defined(HAVE_LINUX_OS) || \ defined(HAVE_FREEBSD_OS) || \ defined(HAVE_OPENBSD_OS) || \ defined(HAVE_NETBSD_OS) #ifdef HAVE_XATTR if(get_xattr(asfd, sb, extrameta, elen, confs)) return -1; #endif #endif return 0; }
struct posix_acl *ovl_get_acl(struct inode *inode, int type) { struct inode *realinode = ovl_inode_real(inode); const struct cred *old_cred; struct posix_acl *acl; if (!IS_ENABLED(CONFIG_FS_POSIX_ACL) || !IS_POSIXACL(realinode)) return NULL; old_cred = ovl_override_creds(inode->i_sb); acl = get_acl(realinode, type); revert_creds(old_cred); return acl; }
int get_extrameta(const char *path, struct stat *statp, char **extrameta, size_t *elen, struct cntr *cntr) { // Important to do xattr directly after acl, because xattr is excluding // some entries if acls were set. #if defined(HAVE_LINUX_OS) || \ defined(HAVE_FREEBSD_OS) || \ defined(HAVE_OPENBSD_OS) || \ defined(HAVE_NETBSD_OS) #ifdef HAVE_ACL if(get_acl(path, statp, extrameta, elen, cntr)) return -1; #endif #endif #if defined(HAVE_LINUX_OS) || \ defined(HAVE_FREEBSD_OS) || \ defined(HAVE_OPENBSD_OS) || \ defined(HAVE_NETBSD_OS) #ifdef HAVE_XATTR if(get_xattr(path, statp, extrameta, elen, cntr)) return -1; #endif #endif return 0; }
/**************************************************************************** Create a directory given an absolute path, perms based upon another directory path ****************************************************************************/ int make_bak_dir(const char *fullpath) { char fbuf[MAXPATHLEN], *rel, *end, *p; struct file_struct *file; int len = backup_dir_len; stat_x sx; while (*fullpath == '.' && fullpath[1] == '/') { fullpath += 2; len -= 2; } if (strlcpy(fbuf, fullpath, sizeof fbuf) >= sizeof fbuf) return -1; rel = fbuf + len; end = p = rel + strlen(rel); /* Try to find an existing dir, starting from the deepest dir. */ while (1) { if (--p == fbuf) return -1; if (*p == '/') { *p = '\0'; if (mkdir_defmode(fbuf) == 0) break; if (errno != ENOENT) { rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed", full_fname(fbuf)); return -1; } } } /* Make all the dirs that we didn't find on the way here. */ while (1) { if (p >= rel) { /* Try to transfer the directory settings of the * actual dir that the files are coming from. */ if (x_stat(rel, &sx.st, NULL) < 0) { rsyserr(FERROR, errno, "make_bak_dir stat %s failed", full_fname(rel)); } else { #ifdef SUPPORT_ACLS sx.acc_acl = sx.def_acl = NULL; #endif #ifdef SUPPORT_XATTRS sx.xattr = NULL; #endif if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS))) continue; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(rel, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(rel, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif set_file_attrs(fbuf, file, NULL, NULL, 0); unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif } } *p = '/'; p += strlen(p); if (p == end) break; if (mkdir_defmode(fbuf) < 0) { rsyserr(FERROR, errno, "make_bak_dir mkdir %s failed", full_fname(fbuf)); return -1; } } return 0; }
/* If we have a --backup-dir, then we get here from make_backup(). * We will move the file to be deleted into a parallel directory tree. */ static int keep_backup(const char *fname) { stat_x sx; struct file_struct *file; char *buf; int save_preserve_xattrs = preserve_xattrs; int kept = 0; int ret_code; /* return if no file to keep */ if (x_lstat(fname, &sx.st, NULL) < 0) return 1; #ifdef SUPPORT_ACLS sx.acc_acl = sx.def_acl = NULL; #endif #ifdef SUPPORT_XATTRS sx.xattr = NULL; #endif if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) return 1; /* the file could have disappeared */ if (!(buf = get_backup_name(fname))) { unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return 0; } #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(fname, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(fname, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif /* Check to see if this is a device file, or link */ if ((am_root && preserve_devices && IS_DEVICE(file->mode)) || (preserve_specials && IS_SPECIAL(file->mode))) { int save_errno; do_unlink(buf); if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) { save_errno = errno ? errno : EINVAL; /* 0 paranoia */ if (errno == ENOENT && make_bak_dir(buf) == 0) { if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) save_errno = errno ? errno : save_errno; else save_errno = 0; } if (save_errno) { rsyserr(FERROR, save_errno, "mknod %s failed", full_fname(buf)); } } else save_errno = 0; if (verbose > 2 && save_errno == 0) { rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname); } kept = 1; do_unlink(fname); } if (!kept && S_ISDIR(file->mode)) { /* make an empty directory */ if (do_mkdir(buf, file->mode) < 0) { int save_errno = errno ? errno : EINVAL; /* 0 paranoia */ if (errno == ENOENT && make_bak_dir(buf) == 0) { if (do_mkdir(buf, file->mode) < 0) save_errno = errno ? errno : save_errno; else save_errno = 0; } if (save_errno) { rsyserr(FINFO, save_errno, "mkdir %s failed", full_fname(buf)); } } ret_code = do_rmdir(fname); if (verbose > 2) { rprintf(FINFO, "make_backup: RMDIR %s returns %i\n", full_fname(fname), ret_code); } kept = 1; } #ifdef SUPPORT_LINKS if (!kept && preserve_links && S_ISLNK(file->mode)) { const char *sl = F_SYMLINK(file); if (safe_symlinks && unsafe_symlink(sl, fname)) { if (verbose) { rprintf(FINFO, "ignoring unsafe symlink %s -> %s\n", full_fname(buf), sl); } kept = 1; } else { do_unlink(buf); if (do_symlink(sl, buf) < 0) { int save_errno = errno ? errno : EINVAL; /* 0 paranoia */ if (errno == ENOENT && make_bak_dir(buf) == 0) { if (do_symlink(sl, buf) < 0) save_errno = errno ? errno : save_errno; else save_errno = 0; } if (save_errno) { rsyserr(FERROR, save_errno, "link %s -> \"%s\"", full_fname(buf), sl); } } do_unlink(fname); kept = 1; } } #endif if (!kept && !S_ISREG(file->mode)) { rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname); unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return 1; } /* move to keep tree if a file */ if (!kept) { if (robust_move(fname, buf) != 0) { rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"", full_fname(fname), buf); } else if (sx.st.st_nlink > 1) { /* If someone has hard-linked the file into the backup * dir, rename() might return success but do nothing! */ robust_unlink(fname); /* Just in case... */ } } preserve_xattrs = 0; set_file_attrs(buf, file, NULL, fname, 0); preserve_xattrs = save_preserve_xattrs; unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif if (verbose > 1) { rprintf(FINFO, "backed up %s to %s\n", fname, buf); } return 1; }
/* Create a backup path from the given fname, putting the result into * backup_dir_buf. Any new directories (compared to the prior backup * path) are ensured to exist as directories, replacing anything else * that may be in the way (e.g. a symlink). */ static BOOL copy_valid_path(const char *fname) { const char *f; int val; BOOL ret = True; stat_x sx; char *b, *rel = backup_dir_buf + backup_dir_len, *name = rel; for (f = fname, b = rel; *f && *f == *b; f++, b++) { if (*b == '/') name = b + 1; } if (stringjoin(rel, backup_dir_remainder, fname, backup_suffix, NULL) >= backup_dir_remainder) { rprintf(FERROR, "backup filename too long\n"); *name = '\0'; return False; } for ( ; ; name = b + 1) { if ((b = strchr(name, '/')) == NULL) return True; *b = '\0'; val = validate_backup_dir(); if (val == 0) break; if (val < 0) { *name = '\0'; return False; } *b = '/'; } init_stat_x(&sx); for ( ; b; name = b + 1, b = strchr(name, '/')) { *b = '\0'; while (do_mkdir(backup_dir_buf, ACCESSPERMS) < 0) { if (errno == EEXIST) { val = validate_backup_dir(); if (val > 0) break; if (val == 0) continue; } else rsyserr(FERROR, errno, "backup mkdir %s failed", backup_dir_buf); *name = '\0'; ret = False; goto cleanup; } /* Try to transfer the directory settings of the actual dir * that the files are coming from. */ if (x_stat(rel, &sx.st, NULL) < 0) rsyserr(FERROR, errno, "backup stat %s failed", full_fname(rel)); else { struct file_struct *file; if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS))) continue; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(rel, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(rel, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif set_file_attrs(backup_dir_buf, file, NULL, NULL, 0); unmake_file(file); } *b = '/'; } cleanup: #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return ret; }
/* Hard-link, rename, or copy an item to the backup name. Returns 0 for * failure, 1 if item was moved, 2 if item was duplicated or hard linked * into backup area, or 3 if item doesn't exist or isn't a regular file. */ int make_backup(const char *fname, BOOL prefer_rename) { stat_x sx; struct file_struct *file; int save_preserve_xattrs; char *buf; int ret = 0; init_stat_x(&sx); /* Return success if no file to keep. */ if (x_lstat(fname, &sx.st, NULL) < 0) return 3; if (!(buf = get_backup_name(fname))) return 0; /* Try a hard-link or a rename first. Using rename is not atomic, but * is more efficient than forcing a copy for larger files when no hard- * linking is possible. */ if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0) goto success; if (errno == EEXIST || errno == EISDIR) { STRUCT_STAT bakst; if (do_lstat(buf, &bakst) == 0) { int flags = get_del_for_flag(bakst.st_mode) | DEL_FOR_BACKUP | DEL_RECURSE; if (delete_item(buf, bakst.st_mode, flags) != 0) return 0; } if ((ret = link_or_rename(fname, buf, prefer_rename, &sx.st)) != 0) goto success; } /* Fall back to making a copy. */ if (!(file = make_file(fname, NULL, &sx.st, 0, NO_FILTERS))) return 3; /* the file could have disappeared */ #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { get_acl(fname, &sx); cache_tmp_acl(file, &sx); free_acl(&sx); } #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { get_xattr(fname, &sx); cache_tmp_xattr(file, &sx); free_xattr(&sx); } #endif /* Check to see if this is a device file, or link */ if ((am_root && preserve_devices && IS_DEVICE(file->mode)) || (preserve_specials && IS_SPECIAL(file->mode))) { if (do_mknod(buf, file->mode, sx.st.st_rdev) < 0) rsyserr(FERROR, errno, "mknod %s failed", full_fname(buf)); else if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: DEVICE %s successful.\n", fname); ret = 2; } #ifdef SUPPORT_LINKS if (!ret && preserve_links && S_ISLNK(file->mode)) { const char *sl = F_SYMLINK(file); if (safe_symlinks && unsafe_symlink(sl, fname)) { if (INFO_GTE(SYMSAFE, 1)) { rprintf(FINFO, "not backing up unsafe symlink \"%s\" -> \"%s\"\n", fname, sl); } ret = 2; } else { if (do_symlink(sl, buf) < 0) rsyserr(FERROR, errno, "link %s -> \"%s\"", full_fname(buf), sl); else if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: SYMLINK %s successful.\n", fname); ret = 2; } } #endif if (!ret && !S_ISREG(file->mode)) { rprintf(FINFO, "make_bak: skipping non-regular file %s\n", fname); unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return 3; } /* Copy to backup tree if a file. */ if (!ret) { if (copy_file(fname, buf, -1, file->mode) < 0) { rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"", full_fname(fname), buf); unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif return 0; } if (DEBUG_GTE(BACKUP, 1)) rprintf(FINFO, "make_backup: COPY %s successful.\n", fname); ret = 2; } save_preserve_xattrs = preserve_xattrs; preserve_xattrs = 0; set_file_attrs(buf, file, NULL, fname, ATTRS_SET_NANO); preserve_xattrs = save_preserve_xattrs; unmake_file(file); #ifdef SUPPORT_ACLS uncache_tmp_acls(); #endif #ifdef SUPPORT_XATTRS uncache_tmp_xattrs(); #endif success: if (INFO_GTE(BACKUP, 1)) rprintf(FINFO, "backed up %s to %s\n", fname, buf); return ret; }