|
Packit |
5f9837 |
/*
|
|
Packit |
5f9837 |
* setcifsacl utility
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* Used to alter entries of an ACL or replace an entire ACL in a
|
|
Packit |
5f9837 |
* security descriptor of a file system object that belongs to a
|
|
Packit |
5f9837 |
* share mounted using option cifsacl.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
5f9837 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
5f9837 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
5f9837 |
* (at your option) any later version.
|
|
Packit |
5f9837 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
5f9837 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5f9837 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
5f9837 |
* GNU General Public License for more details.
|
|
Packit |
5f9837 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
5f9837 |
* along with this program; if not, write to the Free Software
|
|
Packit |
5f9837 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
5f9837 |
#include "config.h"
|
|
Packit |
5f9837 |
#endif /* HAVE_CONFIG_H */
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#include <string.h>
|
|
Packit |
5f9837 |
#include <getopt.h>
|
|
Packit |
5f9837 |
#include <stdint.h>
|
|
Packit |
5f9837 |
#include <stdbool.h>
|
|
Packit |
5f9837 |
#include <unistd.h>
|
|
Packit |
5f9837 |
#include <stdio.h>
|
|
Packit |
5f9837 |
#include <stdlib.h>
|
|
Packit |
5f9837 |
#include <errno.h>
|
|
Packit |
5f9837 |
#include <limits.h>
|
|
Packit |
5f9837 |
#include <ctype.h>
|
|
Packit |
5f9837 |
#include <sys/xattr.h>
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#include "cifsacl.h"
|
|
Packit |
5f9837 |
#include "idmap_plugin.h"
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
enum setcifsacl_actions {
|
|
Packit |
5f9837 |
ActUnknown = -1,
|
|
Packit |
5f9837 |
ActDelete,
|
|
Packit |
5f9837 |
ActModify,
|
|
Packit |
5f9837 |
ActAdd,
|
|
Packit |
5f9837 |
ActSet
|
|
Packit |
5f9837 |
};
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static void *plugin_handle;
|
|
Packit |
5f9837 |
static bool plugin_loaded;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, size = 0;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
dst->revision = src->revision;
|
|
Packit |
5f9837 |
size += sizeof(uint8_t);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
dst->num_subauth = src->num_subauth;
|
|
Packit |
5f9837 |
size += sizeof(uint8_t);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
for (i = 0; i < NUM_AUTHS; i++)
|
|
Packit |
5f9837 |
dst->authority[i] = src->authority[i];
|
|
Packit |
5f9837 |
size += (sizeof(uint8_t) * NUM_AUTHS);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
for (i = 0; i < src->num_subauth; i++)
|
|
Packit |
5f9837 |
dst->sub_auth[i] = src->sub_auth[i];
|
|
Packit |
5f9837 |
size += (sizeof(uint32_t) * src->num_subauth);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return size;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static ssize_t
|
|
Packit |
5f9837 |
copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
|
Packit |
5f9837 |
int numaces, int acessize)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int size, osidsoffset, gsidsoffset, dacloffset;
|
|
Packit |
5f9837 |
ssize_t bufsize;
|
|
Packit |
5f9837 |
struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
|
|
Packit |
5f9837 |
struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
|
|
Packit |
5f9837 |
struct cifs_ctrl_acl *dacl_ptr, *ndacl_ptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* copy security descriptor control portion */
|
|
Packit |
5f9837 |
osidsoffset = le32toh(pntsd->osidoffset);
|
|
Packit |
5f9837 |
gsidsoffset = le32toh(pntsd->gsidoffset);
|
|
Packit |
5f9837 |
dacloffset = le32toh(pntsd->dacloffset);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
size = sizeof(struct cifs_ntsd);
|
|
Packit |
5f9837 |
pnntsd->revision = pntsd->revision;
|
|
Packit |
5f9837 |
pnntsd->type = pntsd->type;
|
|
Packit |
5f9837 |
pnntsd->osidoffset = pntsd->osidoffset;
|
|
Packit |
5f9837 |
pnntsd->gsidoffset = pntsd->gsidoffset;
|
|
Packit |
5f9837 |
pnntsd->dacloffset = pntsd->dacloffset;
|
|
Packit |
5f9837 |
bufsize = size;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
|
|
Packit |
5f9837 |
ndacl_ptr = (struct cifs_ctrl_acl *)((char *)pnntsd + dacloffset);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
size = acessize + sizeof(struct cifs_ctrl_acl);
|
|
Packit |
5f9837 |
ndacl_ptr->revision = dacl_ptr->revision;
|
|
Packit |
5f9837 |
ndacl_ptr->size = htole16(size);
|
|
Packit |
5f9837 |
ndacl_ptr->num_aces = htole32(numaces);
|
|
Packit |
5f9837 |
bufsize += size;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* copy owner sid */
|
|
Packit |
5f9837 |
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
|
|
Packit Service |
be8ff3 |
group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
|
|
Packit Service |
be8ff3 |
/*
|
|
Packit Service |
be8ff3 |
* some servers like Azure return the owner and group SIDs at end rather
|
|
Packit Service |
be8ff3 |
* than at the beginning of the ACL so don't want to overwrite the last ACEs
|
|
Packit Service |
be8ff3 |
*/
|
|
Packit Service |
be8ff3 |
if (dacloffset <= osidsoffset) {
|
|
Packit Service |
be8ff3 |
/* owners placed at end of ACL */
|
|
Packit Service |
be8ff3 |
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + dacloffset + size);
|
|
Packit Service |
be8ff3 |
pnntsd->osidoffset = dacloffset + size;
|
|
Packit Service |
be8ff3 |
size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
|
|
Packit Service |
be8ff3 |
bufsize += size;
|
|
Packit Service |
be8ff3 |
/* put group SID after owner SID */
|
|
Packit Service |
be8ff3 |
ngroup_sid_ptr = (struct cifs_sid *)((char *)nowner_sid_ptr + size);
|
|
Packit Service |
be8ff3 |
pnntsd->gsidoffset = pnntsd->osidoffset + size;
|
|
Packit Service |
be8ff3 |
} else {
|
|
Packit Service |
be8ff3 |
/*
|
|
Packit Service |
be8ff3 |
* Most servers put the owner information at the beginning,
|
|
Packit Service |
be8ff3 |
* before the ACL
|
|
Packit Service |
be8ff3 |
*/
|
|
Packit Service |
be8ff3 |
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
|
|
Packit Service |
be8ff3 |
size = copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
|
|
Packit Service |
be8ff3 |
bufsize += size;
|
|
Packit Service |
be8ff3 |
ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
|
|
Packit Service |
be8ff3 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* copy group sid */
|
|
Packit |
5f9837 |
size = copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
|
|
Packit |
5f9837 |
bufsize += size;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return bufsize;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
dace->type = sace->type;
|
|
Packit |
5f9837 |
dace->flags = sace->flags;
|
|
Packit |
5f9837 |
dace->access_req = sace->access_req;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
copy_cifs_sid(&dace->sid, &sace->sid);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
dace->size = sace->size;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return le16toh(dace->size);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (compflags & COMPSID) {
|
|
Packit |
5f9837 |
if (dace->sid.revision != sace->sid.revision)
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
if (dace->sid.num_subauth != sace->sid.num_subauth)
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
for (i = 0; i < NUM_AUTHS; i++) {
|
|
Packit |
5f9837 |
if (dace->sid.authority[i] != sace->sid.authority[i])
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
for (i = 0; i < sace->sid.num_subauth; i++) {
|
|
Packit |
5f9837 |
if (dace->sid.sub_auth[i] != sace->sid.sub_auth[i])
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (compflags & COMPTYPE) {
|
|
Packit |
5f9837 |
if (dace->type != sace->type)
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (compflags & COMPFLAG) {
|
|
Packit |
5f9837 |
if (dace->flags != sace->flags)
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (compflags & COMPMASK) {
|
|
Packit |
5f9837 |
if (dace->access_req != sace->access_req)
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
alloc_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
|
|
Packit |
5f9837 |
int aces, size_t *acesoffset)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
unsigned int size, acessize, bufsize, dacloffset;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
size = sizeof(struct cifs_ntsd) +
|
|
Packit |
5f9837 |
2 * sizeof(struct cifs_sid) +
|
|
Packit |
5f9837 |
sizeof(struct cifs_ctrl_acl);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
dacloffset = le32toh(pntsd->dacloffset);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
*acesoffset = dacloffset + sizeof(struct cifs_ctrl_acl);
|
|
Packit |
5f9837 |
acessize = aces * sizeof(struct cifs_ace);
|
|
Packit |
5f9837 |
bufsize = size + acessize;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
*npntsd = malloc(bufsize);
|
|
Packit |
5f9837 |
if (!*npntsd) {
|
|
Packit |
5f9837 |
printf("%s: Memory allocation failure", __func__);
|
|
Packit |
5f9837 |
return errno;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
ace_set(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
|
|
Packit |
5f9837 |
struct cifs_ace **cacesptr, int numcaces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, rc, size = 0, acessize = 0;
|
|
Packit |
5f9837 |
size_t acesoffset;
|
|
Packit |
5f9837 |
char *acesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
rc = alloc_sec_desc(pntsd, npntsd, numcaces, &acesoffset);
|
|
Packit |
5f9837 |
if (rc)
|
|
Packit |
5f9837 |
return rc;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
acesptr = (char *)*npntsd + acesoffset;
|
|
Packit |
5f9837 |
for (i = 0; i < numcaces; ++i) {
|
|
Packit |
5f9837 |
size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
|
|
Packit |
5f9837 |
acessize += size;
|
|
Packit |
5f9837 |
acesptr += size;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
*bufsize = copy_sec_desc(pntsd, *npntsd, numcaces, acessize);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
ace_add(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
|
|
Packit |
5f9837 |
struct cifs_ace **facesptr, int numfaces,
|
|
Packit |
5f9837 |
struct cifs_ace **cacesptr, int numcaces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, rc, numaces, size, acessize = 0;
|
|
Packit |
5f9837 |
size_t acesoffset;
|
|
Packit |
5f9837 |
char *acesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
numaces = numfaces + numcaces;
|
|
Packit |
5f9837 |
rc = alloc_sec_desc(pntsd, npntsd, numaces, &acesoffset);
|
|
Packit |
5f9837 |
if (rc)
|
|
Packit |
5f9837 |
return rc;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
acesptr = (char *)*npntsd + acesoffset;
|
|
Packit |
5f9837 |
for (i = 0; i < numfaces; ++i) {
|
|
Packit |
5f9837 |
size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
|
|
Packit |
5f9837 |
acesptr += size;
|
|
Packit |
5f9837 |
acessize += size;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
for (i = 0; i < numcaces; ++i) {
|
|
Packit |
5f9837 |
size = copy_ace((struct cifs_ace *)acesptr, cacesptr[i]);
|
|
Packit |
5f9837 |
acesptr += size;
|
|
Packit |
5f9837 |
acessize += size;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
*bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
ace_modify(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
|
|
Packit |
5f9837 |
struct cifs_ace **facesptr, int numfaces,
|
|
Packit |
5f9837 |
struct cifs_ace **cacesptr, int numcaces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, j, rc, size, acessize = 0;
|
|
Packit |
5f9837 |
size_t acesoffset;
|
|
Packit |
5f9837 |
char *acesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (numfaces == 0) {
|
|
Packit |
5f9837 |
printf("%s: No entries to modify", __func__);
|
|
Packit |
5f9837 |
return -1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset);
|
|
Packit |
5f9837 |
if (rc)
|
|
Packit |
5f9837 |
return rc;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
for (j = 0; j < numcaces; ++j) {
|
|
Packit |
5f9837 |
for (i = 0; i < numfaces; ++i) {
|
|
Packit |
5f9837 |
if (compare_aces(facesptr[i], cacesptr[j],
|
|
Packit |
5f9837 |
COMPSID | COMPTYPE)) {
|
|
Packit |
5f9837 |
copy_ace(facesptr[i], cacesptr[j]);
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
acesptr = (char *)*npntsd + acesoffset;
|
|
Packit |
5f9837 |
for (i = 0; i < numfaces; ++i) {
|
|
Packit |
5f9837 |
size = copy_ace((struct cifs_ace *)acesptr, facesptr[i]);
|
|
Packit |
5f9837 |
acesptr += size;
|
|
Packit |
5f9837 |
acessize += size;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
*bufsize = copy_sec_desc(pntsd, *npntsd, numfaces, acessize);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
ace_delete(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd, ssize_t *bufsize,
|
|
Packit |
5f9837 |
struct cifs_ace **facesptr, int numfaces,
|
|
Packit |
5f9837 |
struct cifs_ace **cacesptr, int numcaces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, j, numaces = 0, rc, size, acessize = 0;
|
|
Packit |
5f9837 |
size_t acesoffset;
|
|
Packit |
5f9837 |
char *acesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (numfaces == 0) {
|
|
Packit |
5f9837 |
printf("%s: No entries to delete\n", __func__);
|
|
Packit |
5f9837 |
return -1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (numfaces < numcaces) {
|
|
Packit |
5f9837 |
printf("%s: Invalid entries to delete\n", __func__);
|
|
Packit |
5f9837 |
return -1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
rc = alloc_sec_desc(pntsd, npntsd, numfaces, &acesoffset);
|
|
Packit |
5f9837 |
if (rc)
|
|
Packit |
5f9837 |
return rc;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
acesptr = (char *)*npntsd + acesoffset;
|
|
Packit |
5f9837 |
for (i = 0; i < numfaces; ++i) {
|
|
Packit |
5f9837 |
for (j = 0; j < numcaces; ++j) {
|
|
Packit |
5f9837 |
if (compare_aces(facesptr[i], cacesptr[j], COMPALL))
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
if (j == numcaces) {
|
|
Packit |
5f9837 |
size = copy_ace((struct cifs_ace *)acesptr,
|
|
Packit |
5f9837 |
facesptr[i]);
|
|
Packit |
5f9837 |
acessize += size;
|
|
Packit |
5f9837 |
acesptr += size;
|
|
Packit |
5f9837 |
++numaces;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (numaces == numfaces) {
|
|
Packit |
5f9837 |
printf("%s: Nothing to delete\n", __func__);
|
|
Packit |
5f9837 |
return 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
*bufsize = copy_sec_desc(pntsd, *npntsd, numaces, acessize);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
|
|
Packit |
5f9837 |
struct cifs_ctrl_acl **daclptr)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int numfaces = 0;
|
|
Packit |
5f9837 |
uint32_t dacloffset;
|
|
Packit |
5f9837 |
struct cifs_ctrl_acl *ldaclptr;
|
|
Packit |
5f9837 |
char *end_of_acl = ((char *)pntsd) + acl_len;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
dacloffset = le32toh(pntsd->dacloffset);
|
|
Packit |
5f9837 |
if (!dacloffset)
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* validate that we do not go past end of acl */
|
|
Packit |
5f9837 |
if (end_of_acl >= (char *)ldaclptr + le16toh(ldaclptr->size)) {
|
|
Packit |
5f9837 |
numfaces = le32toh(ldaclptr->num_aces);
|
|
Packit |
5f9837 |
*daclptr = ldaclptr;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return numfaces;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static struct cifs_ace **
|
|
Packit |
5f9837 |
build_fetched_aces(char *daclptr, int numfaces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, acl_size;
|
|
Packit |
5f9837 |
char *acl_base;
|
|
Packit |
5f9837 |
struct cifs_ace *pace, **facesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
facesptr = calloc(numfaces, sizeof(struct cifs_aces *));
|
|
Packit |
5f9837 |
if (!facesptr) {
|
|
Packit |
5f9837 |
printf("%s: Error %d allocating ACE array",
|
|
Packit |
5f9837 |
__func__, errno);
|
|
Packit |
5f9837 |
return facesptr;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
acl_base = daclptr;
|
|
Packit |
5f9837 |
acl_size = sizeof(struct cifs_ctrl_acl);
|
|
Packit |
5f9837 |
for (i = 0; i < numfaces; ++i) {
|
|
Packit |
5f9837 |
facesptr[i] = malloc(sizeof(struct cifs_ace));
|
|
Packit |
5f9837 |
if (!facesptr[i])
|
|
Packit |
5f9837 |
goto build_fetched_aces_err;
|
|
Packit |
5f9837 |
pace = (struct cifs_ace *) (acl_base + acl_size);
|
|
Packit |
5f9837 |
memcpy(facesptr[i], pace, sizeof(struct cifs_ace));
|
|
Packit |
5f9837 |
acl_base = (char *)pace;
|
|
Packit |
5f9837 |
acl_size = le16toh(pace->size);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return facesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
build_fetched_aces_err:
|
|
Packit |
5f9837 |
printf("%s: Invalid fetched ace\n", __func__);
|
|
Packit |
5f9837 |
for (i = 0; i < numfaces; ++i)
|
|
Packit |
5f9837 |
free(facesptr[i]);
|
|
Packit |
5f9837 |
free(facesptr);
|
|
Packit |
5f9837 |
return NULL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
verify_ace_type(char *typestr, uint8_t *typeval)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, len;
|
|
Packit |
5f9837 |
char *invaltype;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (strstr(typestr, "0x")) { /* hex type value */
|
|
Packit |
5f9837 |
*typeval = strtol(typestr, &invaltype, 16);
|
|
Packit |
5f9837 |
if (!strlen(invaltype)) {
|
|
Packit |
5f9837 |
if (*typeval != ACCESS_ALLOWED &&
|
|
Packit |
5f9837 |
*typeval != ACCESS_DENIED &&
|
|
Packit |
5f9837 |
*typeval != ACCESS_ALLOWED_OBJECT &&
|
|
Packit |
5f9837 |
*typeval != ACCESS_DENIED_OBJECT) {
|
|
Packit |
5f9837 |
printf("%s: Invalid type: %s\n",
|
|
Packit |
5f9837 |
__func__, typestr);
|
|
Packit |
5f9837 |
return 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
len = strlen(typestr);
|
|
Packit |
5f9837 |
for (i = 0; i < len; ++i)
|
|
Packit |
5f9837 |
*(typestr + i) = toupper(*(typestr + i));
|
|
Packit |
5f9837 |
if (!strcmp(typestr, "ALLOWED"))
|
|
Packit |
5f9837 |
*typeval = 0x0;
|
|
Packit |
5f9837 |
else if (!strcmp(typestr, "DENIED"))
|
|
Packit |
5f9837 |
*typeval = 0x1;
|
|
Packit |
5f9837 |
else if (!strcmp(typestr, "ALLOWED_OBJECT"))
|
|
Packit |
5f9837 |
*typeval = 0x5;
|
|
Packit |
5f9837 |
else if (!strcmp(typestr, "DENIED_OBJECT"))
|
|
Packit |
5f9837 |
*typeval = 0x6;
|
|
Packit |
5f9837 |
else {
|
|
Packit |
5f9837 |
printf("%s: Invalid type: %s\n", __func__, typestr);
|
|
Packit |
5f9837 |
return 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static uint8_t
|
|
Packit |
5f9837 |
ace_flag_value(char *flagstr)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
uint8_t flagval = 0x0;
|
|
Packit |
5f9837 |
char *iflag;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
iflag = strtok(flagstr, "|"); /* everything before | */
|
|
Packit |
5f9837 |
while (iflag) {
|
|
Packit |
5f9837 |
if (!strcmp(iflag, "OI"))
|
|
Packit |
5f9837 |
flagval += 0x1;
|
|
Packit |
5f9837 |
else if (!strcmp(iflag, "CI"))
|
|
Packit |
5f9837 |
flagval += 0x2;
|
|
Packit |
5f9837 |
else if (!strcmp(iflag, "NP"))
|
|
Packit |
5f9837 |
flagval += 0x4;
|
|
Packit |
5f9837 |
else if (!strcmp(iflag, "IO"))
|
|
Packit |
5f9837 |
flagval += 0x8;
|
|
Packit |
5f9837 |
else if (!strcmp(iflag, "I"))
|
|
Packit |
5f9837 |
flagval += 0x10;
|
|
Packit |
5f9837 |
else
|
|
Packit |
5f9837 |
return 0x0; /* Invalid flag */
|
|
Packit |
5f9837 |
iflag = strtok(NULL, "|"); /* everything before | */
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return flagval;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
verify_ace_flags(char *flagstr, uint8_t *flagval)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
char *invalflag;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!strcmp(flagstr, "0") || !strcmp(flagstr, "0x0"))
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (strstr(flagstr, "0x")) { /* hex flag value */
|
|
Packit |
5f9837 |
*flagval = strtol(flagstr, &invalflag, 16);
|
|
Packit |
5f9837 |
if (strlen(invalflag)) {
|
|
Packit |
5f9837 |
printf("%s: Invalid flags: %s\n", __func__, flagstr);
|
|
Packit |
5f9837 |
return 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
} else
|
|
Packit |
5f9837 |
*flagval = ace_flag_value(flagstr);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!*flagval || (*flagval & ~VFLAGS)) {
|
|
Packit |
5f9837 |
printf("%s: Invalid flag %s and value: 0x%x\n",
|
|
Packit |
5f9837 |
__func__, flagstr, *flagval);
|
|
Packit |
5f9837 |
return 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static uint32_t
|
|
Packit |
5f9837 |
ace_mask_value(char *mask)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
uint32_t maskval = 0;
|
|
Packit |
5f9837 |
char cur;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!strcmp(mask, "FULL"))
|
|
Packit |
5f9837 |
return FULL_CONTROL;
|
|
Packit |
5f9837 |
if (!strcmp(mask, "CHANGE"))
|
|
Packit |
5f9837 |
return CHANGE;
|
|
Packit |
5f9837 |
if (!strcmp(mask, "READ"))
|
|
Packit |
5f9837 |
return EREAD;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
while((cur = *mask++)) {
|
|
Packit |
5f9837 |
switch(cur) {
|
|
Packit |
5f9837 |
case 'R':
|
|
Packit |
5f9837 |
maskval |= EREAD;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'W':
|
|
Packit |
5f9837 |
maskval |= EWRITE;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'X':
|
|
Packit |
5f9837 |
maskval |= EXEC;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'D':
|
|
Packit |
5f9837 |
maskval |= DELETE;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'P':
|
|
Packit |
5f9837 |
maskval |= WRITE_DAC;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'O':
|
|
Packit |
5f9837 |
maskval |= WRITE_OWNER;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
default:
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return maskval;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
verify_ace_mask(char *maskstr, uint32_t *maskval)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
unsigned long val;
|
|
Packit |
5f9837 |
char *ep;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
errno = 0;
|
|
Packit |
5f9837 |
val = strtoul(maskstr, &ep, 0);
|
|
Packit |
5f9837 |
if (errno == 0 && *ep == '\0')
|
|
Packit |
5f9837 |
*maskval = htole32((uint32_t)val);
|
|
Packit |
5f9837 |
else
|
|
Packit |
5f9837 |
*maskval = htole32(ace_mask_value(maskstr));
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!*maskval) {
|
|
Packit |
5f9837 |
printf("%s: Invalid mask %s (value 0x%x)\n", __func__,
|
|
Packit |
5f9837 |
maskstr, *maskval);
|
|
Packit |
5f9837 |
return 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#define AUTHORITY_MASK (~(0xffffffffffffULL))
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
raw_str_to_sid(const char *str, struct cifs_sid *csid)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
const char *p;
|
|
Packit |
5f9837 |
char *q;
|
|
Packit |
5f9837 |
unsigned long long x;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Sanity check for either "S-" or "s-" */
|
|
Packit |
5f9837 |
if ((str[0] != 'S' && str[0] != 's') || (str[1]!='-')) {
|
|
Packit |
5f9837 |
plugin_errmsg = "SID string does not start with \"S-\"";
|
|
Packit |
5f9837 |
return -EINVAL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Get the SID revision number */
|
|
Packit |
5f9837 |
p = str + 2;
|
|
Packit |
5f9837 |
x = strtoull(p, &q, 10);
|
|
Packit |
5f9837 |
if (x == 0 || x > UCHAR_MAX || !q || *q != '-') {
|
|
Packit |
5f9837 |
plugin_errmsg = "Invalid SID revision number";
|
|
Packit |
5f9837 |
return -EINVAL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
csid->revision = (uint8_t)x;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/*
|
|
Packit |
5f9837 |
* Next the Identifier Authority. This is stored in big-endian in a
|
|
Packit |
5f9837 |
* 6 byte array. If the authority value is > UINT_MAX, then it should
|
|
Packit |
5f9837 |
* be expressed as a hex value.
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
p = q + 1;
|
|
Packit |
5f9837 |
x = strtoull(p, &q, 0);
|
|
Packit |
5f9837 |
if ((x & AUTHORITY_MASK) || !q || *q !='-') {
|
|
Packit |
5f9837 |
plugin_errmsg = "Invalid SID authority";
|
|
Packit |
5f9837 |
return -EINVAL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
csid->authority[5] = (x & 0x0000000000ffULL);
|
|
Packit |
5f9837 |
csid->authority[4] = (x & 0x00000000ff00ULL) >> 8;
|
|
Packit |
5f9837 |
csid->authority[3] = (x & 0x000000ff0000ULL) >> 16;
|
|
Packit |
5f9837 |
csid->authority[2] = (x & 0x0000ff000000ULL) >> 24;
|
|
Packit |
5f9837 |
csid->authority[1] = (x & 0x00ff00000000ULL) >> 32;
|
|
Packit |
5f9837 |
csid->authority[0] = (x & 0xff0000000000ULL) >> 40;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* now read the the subauthorities and store as __le32 vals */
|
|
Packit |
5f9837 |
p = q + 1;
|
|
Packit |
5f9837 |
csid->num_subauth = 0;
|
|
Packit |
5f9837 |
while (csid->num_subauth < SID_MAX_SUB_AUTHORITIES) {
|
|
Packit |
5f9837 |
x = strtoul(p, &q, 10);
|
|
Packit |
5f9837 |
if (p == q)
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
if (x > UINT_MAX) {
|
|
Packit |
5f9837 |
plugin_errmsg = "Invalid sub authority value";
|
|
Packit |
5f9837 |
return -EINVAL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
csid->sub_auth[csid->num_subauth++] = htole32((uint32_t)x);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (*q != '-')
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
p = q + 1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* IF we ended early, then the SID could not be converted */
|
|
Packit |
5f9837 |
if (q && *q != '\0') {
|
|
Packit |
5f9837 |
plugin_errmsg = "Invalid sub authority value";
|
|
Packit |
5f9837 |
return -EINVAL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
setcifsacl_str_to_sid(const char *str, struct cifs_sid *sid)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
if (plugin_loaded)
|
|
Packit |
5f9837 |
return str_to_sid(plugin_handle, str, sid);
|
|
Packit |
5f9837 |
return raw_str_to_sid(str, sid);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static struct cifs_ace **
|
|
Packit |
5f9837 |
build_cmdline_aces(char **arrptr, int numcaces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i;
|
|
Packit |
5f9837 |
char *acesid, *acetype, *aceflag, *acemask;
|
|
Packit |
5f9837 |
struct cifs_ace **cacesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
cacesptr = calloc(numcaces, sizeof(struct cifs_aces *));
|
|
Packit |
5f9837 |
if (!cacesptr) {
|
|
Packit |
5f9837 |
printf("%s: Error %d allocating ACE array", __func__, errno);
|
|
Packit |
5f9837 |
return NULL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
for (i = 0; i < numcaces; ++i) {
|
|
Packit |
5f9837 |
acesid = strtok(arrptr[i], ":");
|
|
Packit |
5f9837 |
acetype = strtok(NULL, "/");
|
|
Packit |
5f9837 |
aceflag = strtok(NULL, "/");
|
|
Packit |
5f9837 |
acemask = strtok(NULL, "/");
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!acesid || !acetype || !aceflag || !acemask) {
|
|
Packit |
5f9837 |
printf("%s: Incomplete ACE: %s\n", __func__, arrptr[i]);
|
|
Packit |
5f9837 |
goto build_cmdline_aces_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
cacesptr[i] = malloc(sizeof(struct cifs_ace));
|
|
Packit |
5f9837 |
if (!cacesptr[i]) {
|
|
Packit |
5f9837 |
printf("%s: ACE alloc error %d\n", __func__, errno);
|
|
Packit |
5f9837 |
goto build_cmdline_aces_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (setcifsacl_str_to_sid(acesid, &cacesptr[i]->sid)) {
|
|
Packit |
5f9837 |
printf("%s: Invalid SID (%s): %s\n", __func__, arrptr[i],
|
|
Packit |
5f9837 |
plugin_errmsg);
|
|
Packit |
5f9837 |
goto build_cmdline_aces_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (verify_ace_type(acetype, &cacesptr[i]->type)) {
|
|
Packit |
5f9837 |
printf("%s: Invalid ACE type: %s\n",
|
|
Packit |
5f9837 |
__func__, arrptr[i]);
|
|
Packit |
5f9837 |
goto build_cmdline_aces_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (verify_ace_flags(aceflag, &cacesptr[i]->flags)) {
|
|
Packit |
5f9837 |
printf("%s: Invalid ACE flag: %s\n",
|
|
Packit |
5f9837 |
__func__, arrptr[i]);
|
|
Packit |
5f9837 |
goto build_cmdline_aces_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (verify_ace_mask(acemask, &cacesptr[i]->access_req)) {
|
|
Packit |
5f9837 |
printf("%s: Invalid ACE mask: %s\n",
|
|
Packit |
5f9837 |
__func__, arrptr[i]);
|
|
Packit |
5f9837 |
goto build_cmdline_aces_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
cacesptr[i]->size = htole16(1 + 1 + 2 + 4 + 1 + 1 + 6 +
|
|
Packit |
5f9837 |
cacesptr[i]->sid.num_subauth * 4);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return cacesptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
build_cmdline_aces_ret:
|
|
Packit |
5f9837 |
for (i = 0; i < numcaces; ++i)
|
|
Packit |
5f9837 |
free(cacesptr[i]);
|
|
Packit |
5f9837 |
free(cacesptr);
|
|
Packit |
5f9837 |
return NULL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static char **
|
|
Packit |
5f9837 |
parse_cmdline_aces(char *acelist, int numcaces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i = 0;
|
|
Packit |
5f9837 |
char *acestr, *vacestr, **arrptr = NULL;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
arrptr = (char **)malloc(numcaces * sizeof(char *));
|
|
Packit |
5f9837 |
if (!arrptr) {
|
|
Packit |
5f9837 |
printf("%s: Unable to allocate char array\n", __func__);
|
|
Packit |
5f9837 |
return NULL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
while (i < numcaces) {
|
|
Packit |
5f9837 |
acestr = strtok(acelist, ","); /* everything before , */
|
|
Packit |
5f9837 |
if (!acestr)
|
|
Packit |
5f9837 |
goto parse_cmdline_aces_err;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
|
|
Packit |
5f9837 |
if (!vacestr)
|
|
Packit |
5f9837 |
goto parse_cmdline_aces_err;
|
|
Packit |
5f9837 |
vacestr += 4; /* skip past "ACL:" */
|
|
Packit |
5f9837 |
if (*vacestr) {
|
|
Packit |
5f9837 |
arrptr[i] = vacestr;
|
|
Packit |
5f9837 |
++i;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
acelist = NULL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return arrptr;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
parse_cmdline_aces_err:
|
|
Packit |
5f9837 |
printf("%s: Error parsing ACEs\n", __func__);
|
|
Packit |
5f9837 |
free(arrptr);
|
|
Packit |
5f9837 |
return NULL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* How many aces were provided on the command-line? Count the commas. */
|
|
Packit |
5f9837 |
static unsigned int
|
|
Packit |
5f9837 |
get_numcaces(const char *aces)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
unsigned int num = 1;
|
|
Packit |
5f9837 |
const char *current;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
current = aces;
|
|
Packit |
5f9837 |
while((current = strchr(current, ','))) {
|
|
Packit |
5f9837 |
++current;
|
|
Packit |
5f9837 |
++num;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return num;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static int
|
|
Packit |
5f9837 |
setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
|
|
Packit |
5f9837 |
ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
|
|
Packit |
5f9837 |
struct cifs_ace **cacesptr, int numcaces,
|
|
Packit |
5f9837 |
enum setcifsacl_actions maction)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int rc = 1;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
switch (maction) {
|
|
Packit |
5f9837 |
case ActDelete:
|
|
Packit |
5f9837 |
rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
|
|
Packit |
5f9837 |
numfaces, cacesptr, numcaces);
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case ActModify:
|
|
Packit |
5f9837 |
rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
|
|
Packit |
5f9837 |
numfaces, cacesptr, numcaces);
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case ActAdd:
|
|
Packit |
5f9837 |
rc = ace_add(pntsd, npntsd, bufsize, facesptr,
|
|
Packit |
5f9837 |
numfaces, cacesptr, numcaces);
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case ActSet:
|
|
Packit |
5f9837 |
rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
default:
|
|
Packit |
5f9837 |
printf("%s: Invalid action: %d\n", __func__, maction);
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return rc;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static void
|
|
Packit |
5f9837 |
setcifsacl_usage(const char *prog)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"%s: Alter CIFS/NTFS ACL in a security descriptor of a file object\n",
|
|
Packit |
5f9837 |
prog);
|
|
Packit |
5f9837 |
fprintf(stderr, "Usage: %s option <list_of_ACEs> <file_name>\n", prog);
|
|
Packit |
5f9837 |
fprintf(stderr, "Valid options:\n");
|
|
Packit |
5f9837 |
fprintf(stderr, "\t-v Version of the program\n");
|
|
Packit |
5f9837 |
fprintf(stderr, "\n\t-a Add ACE(s), separated by a comma, to an ACL\n");
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"\tsetcifsacl -a \"ACL:Administrator:ALLOWED/0x0/FULL\" <file_name>\n");
|
|
Packit |
5f9837 |
fprintf(stderr, "\n");
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"\t-D Delete ACE(s), separated by a comma, from an ACL\n");
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"\tsetcifsacl -D \"ACL:Administrator:DENIED/0x0/D\" <file_name>\n");
|
|
Packit |
5f9837 |
fprintf(stderr, "\n");
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"\t-M Modify ACE(s), separated by a comma, in an ACL\n");
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"\tsetcifsacl -M \"ACL:user1:ALLOWED/0x0/0x1e01ff\" <file_name>\n");
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"\n\t-S Replace existing ACL with ACE(s), separated by a comma\n");
|
|
Packit |
5f9837 |
fprintf(stderr,
|
|
Packit |
5f9837 |
"\tsetcifsacl -S \"ACL:Administrator:ALLOWED/0x0/D\" <file_name>\n");
|
|
Packit |
5f9837 |
fprintf(stderr, "\nRefer to setcifsacl(1) manpage for details\n");
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
int
|
|
Packit |
5f9837 |
main(const int argc, char *const argv[])
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int i, rc, c, numcaces, numfaces;
|
|
Packit |
5f9837 |
enum setcifsacl_actions maction = ActUnknown;
|
|
Packit |
5f9837 |
ssize_t attrlen, bufsize = BUFSIZE;
|
|
Packit |
5f9837 |
char *ace_list, *filename, *attrval, **arrptr = NULL;
|
|
Packit |
5f9837 |
struct cifs_ctrl_acl *daclptr = NULL;
|
|
Packit |
5f9837 |
struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
|
|
Packit |
5f9837 |
struct cifs_ntsd *ntsdptr = NULL;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
c = getopt(argc, argv, "hvD:M:a:S:");
|
|
Packit |
5f9837 |
switch (c) {
|
|
Packit |
5f9837 |
case 'D':
|
|
Packit |
5f9837 |
maction = ActDelete;
|
|
Packit |
5f9837 |
ace_list = optarg;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'M':
|
|
Packit |
5f9837 |
maction = ActModify;
|
|
Packit |
5f9837 |
ace_list = optarg;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'a':
|
|
Packit |
5f9837 |
maction = ActAdd;
|
|
Packit |
5f9837 |
ace_list = optarg;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'S':
|
|
Packit |
5f9837 |
maction = ActSet;
|
|
Packit |
5f9837 |
ace_list = optarg;
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
case 'h':
|
|
Packit |
5f9837 |
setcifsacl_usage(basename(argv[0]));
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
case 'v':
|
|
Packit |
5f9837 |
printf("Version: %s\n", VERSION);
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
default:
|
|
Packit |
5f9837 |
setcifsacl_usage(basename(argv[0]));
|
|
Packit |
5f9837 |
return -1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* We expect 1 argument in addition to the option */
|
|
Packit |
5f9837 |
if (argc != 4) {
|
|
Packit |
5f9837 |
setcifsacl_usage(basename(argv[0]));
|
|
Packit |
5f9837 |
return -1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
filename = argv[3];
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!ace_list) {
|
|
Packit |
5f9837 |
printf("%s: No valid ACEs specified\n", __func__);
|
|
Packit |
5f9837 |
return -1;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (init_plugin(&plugin_handle)) {
|
|
Packit |
5f9837 |
fprintf(stderr, "WARNING: unable to initialize idmapping "
|
|
Packit |
5f9837 |
"plugin. Only \"raw\" SID strings will be "
|
|
Packit |
5f9837 |
"accepted: %s\n", plugin_errmsg);
|
|
Packit |
5f9837 |
plugin_loaded = false;
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
plugin_loaded = true;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
numcaces = get_numcaces(ace_list);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
arrptr = parse_cmdline_aces(ace_list, numcaces);
|
|
Packit |
5f9837 |
if (!arrptr)
|
|
Packit |
5f9837 |
goto setcifsacl_numcaces_ret;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
cacesptr = build_cmdline_aces(arrptr, numcaces);
|
|
Packit |
5f9837 |
if (!cacesptr)
|
|
Packit |
5f9837 |
goto setcifsacl_cmdlineparse_ret;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
cifsacl:
|
|
Packit |
5f9837 |
if (bufsize >= XATTR_SIZE_MAX) {
|
|
Packit |
5f9837 |
printf("%s: Buffer size %zd exceeds max size of %d\n",
|
|
Packit |
5f9837 |
__func__, bufsize, XATTR_SIZE_MAX);
|
|
Packit |
5f9837 |
goto setcifsacl_cmdlineverify_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
attrval = malloc(bufsize * sizeof(char));
|
|
Packit |
5f9837 |
if (!attrval) {
|
|
Packit |
5f9837 |
printf("error allocating memory for attribute value buffer\n");
|
|
Packit |
5f9837 |
goto setcifsacl_cmdlineverify_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
attrlen = getxattr(filename, ATTRNAME, attrval, bufsize);
|
|
Packit |
5f9837 |
if (attrlen == -1) {
|
|
Packit |
5f9837 |
if (errno == ERANGE) {
|
|
Packit |
5f9837 |
free(attrval);
|
|
Packit |
5f9837 |
bufsize += BUFSIZE;
|
|
Packit |
5f9837 |
goto cifsacl;
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
printf("getxattr error: %d\n", errno);
|
|
Packit |
5f9837 |
goto setcifsacl_getx_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
|
|
Packit |
5f9837 |
if (!numfaces && maction != ActAdd) { /* if we are not adding aces */
|
|
Packit |
5f9837 |
printf("%s: Empty DACL\n", __func__);
|
|
Packit |
5f9837 |
goto setcifsacl_facenum_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
facesptr = build_fetched_aces((char *)daclptr, numfaces);
|
|
Packit |
5f9837 |
if (!facesptr)
|
|
Packit |
5f9837 |
goto setcifsacl_facenum_ret;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
bufsize = 0;
|
|
Packit |
5f9837 |
rc = setacl_action((struct cifs_ntsd *)attrval, &ntsdptr, &bufsize,
|
|
Packit |
5f9837 |
facesptr, numfaces, cacesptr, numcaces, maction);
|
|
Packit |
5f9837 |
if (rc)
|
|
Packit |
5f9837 |
goto setcifsacl_action_ret;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
attrlen = setxattr(filename, ATTRNAME, ntsdptr, bufsize, 0);
|
|
Packit |
5f9837 |
if (attrlen == -1) {
|
|
Packit |
5f9837 |
printf("%s: setxattr error: %s\n", __func__, strerror(errno));
|
|
Packit |
5f9837 |
goto setcifsacl_facenum_ret;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (plugin_loaded)
|
|
Packit |
5f9837 |
exit_plugin(plugin_handle);
|
|
Packit |
5f9837 |
return 0;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
setcifsacl_action_ret:
|
|
Packit |
5f9837 |
free(ntsdptr);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
setcifsacl_facenum_ret:
|
|
Packit |
5f9837 |
for (i = 0; i < numfaces; ++i)
|
|
Packit |
5f9837 |
free(facesptr[i]);
|
|
Packit |
5f9837 |
free(facesptr);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
setcifsacl_getx_ret:
|
|
Packit |
5f9837 |
free(attrval);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
setcifsacl_cmdlineverify_ret:
|
|
Packit |
5f9837 |
for (i = 0; i < numcaces; ++i)
|
|
Packit |
5f9837 |
free(cacesptr[i]);
|
|
Packit |
5f9837 |
free(cacesptr);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
setcifsacl_cmdlineparse_ret:
|
|
Packit |
5f9837 |
free(arrptr);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
setcifsacl_numcaces_ret:
|
|
Packit |
5f9837 |
exit_plugin(plugin_handle);
|
|
Packit |
5f9837 |
return -1;
|
|
Packit |
5f9837 |
}
|