/*
* setcifsacl utility
*
* Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
*
* Used to alter entries of an ACL or replace an entire ACL in a
* security descriptor of a file system object that belongs to a
* share mounted using option cifsacl.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <string.h>
#include <getopt.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <sys/xattr.h>
#include "cifsacl.h"
#include "idmap_plugin.h"
enum setcifsacl_actions {
ActUnknown = -1,
ActDelete,
ActModify,
ActAdd,
ActSetAcl,
ActSetOwner,
ActSetGroup
};
static void *plugin_handle;
static bool plugin_loaded;
static int
copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
{
int i, size = 0;
dst->revision = src->revision;
size += sizeof(uint8_t);
dst->num_subauth = src->num_subauth;
size += sizeof(uint8_t);
for (i = 0; i < NUM_AUTHS; i++)
dst->authority[i] = src->authority[i];
size += (sizeof(uint8_t) * NUM_AUTHS);
for (i = 0; i < src->num_subauth; i++)
dst->sub_auth[i] = src->sub_auth[i];
size += (sizeof(uint32_t) * src->num_subauth);
return size;
}
static ssize_t
copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
int numaces, int acessize)
{
int size, osidsoffset, gsidsoffset, dacloffset;
ssize_t bufsize;
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
struct cifs_ctrl_acl *dacl_ptr, *ndacl_ptr;
/* copy security descriptor control portion */
osidsoffset = le32toh(pntsd->osidoffset);
gsidsoffset = le32toh(pntsd->gsidoffset);
dacloffset = le32toh(pntsd->dacloffset);
size = sizeof(struct cifs_ntsd);
pnntsd->revision = pntsd->revision;
pnntsd->type = pntsd->type;
pnntsd->osidoffset = pntsd->osidoffset;
pnntsd->gsidoffset = pntsd->gsidoffset;
pnntsd->dacloffset = pntsd->dacloffset;
bufsize = size;
dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
size = acessize + sizeof(struct cifs_ctrl_acl);
ndacl_ptr->revision = dacl_ptr->revision;
ndacl_ptr->size = htole16(size);
ndacl_ptr->num_aces = htole32(numaces);
bufsize += size;
/* copy owner sid */
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
/*
* some servers like Azure return the owner and group SIDs at end rather
* than at the beginning of the ACL so don't want to overwrite the last ACEs
*/
if (dacloffset <= osidsoffset) {
/* owners placed at end of ACL */
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + dacloffset + size);
osidsoffset = dacloffset + size;
pnntsd->osidoffset = htole32(osidsoffset);
size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
bufsize += size;
/* put group SID after owner SID */
ngroup_sid_ptr = (struct cifs_sid *)((char *)nowner_sid_ptr + size);
gsidsoffset = osidsoffset + size;
pnntsd->gsidoffset = htole32(gsidsoffset);
} else {
/*
* Most servers put the owner information at the beginning,
* before the ACL
*/
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
bufsize += size;
ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
}
/* copy group sid */
size = copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
bufsize += size;
return bufsize;
}
/*
* This function (and the one above) does not need to set the SACL-related
* fields, and this works fine because on the SMB protocol level, setting owner