cifs-utils/cifs-utils-5.8-pre1.patch

1181 lines
31 KiB
Diff

diff --git a/cifs.idmap.8.in b/cifs.idmap.8.in
index efec7b6..c022402 100644
--- a/cifs.idmap.8.in
+++ b/cifs.idmap.8.in
@@ -22,7 +22,7 @@
cifs.idmap \- Userspace helper for mapping ids for Common Internet File System (CIFS)
.SH "SYNOPSIS"
.HP \w'\ 'u
-cifs\&.idmap [\-\-version|\-v] {keyid}
+cifs.idmap [--help|-h] [--timeout|-t] [--version|-v] {keyid}
.SH "DESCRIPTION"
.PP
This tool is part of the cifs-utils suite\&.
@@ -46,6 +46,16 @@ cifs\&.idmap works in conjuction with winbind facility of Samba suite to map own
In case winbind and cifs.idmap facilities are unavailable, file objects in a mounted share are assigned uid and gid of the credentials of the process that mounted the share\&. So it is strongly recomemended to use mount options of uid and gid to specify a default uid and gid to map owner SIDs and group SIDs respectively in case services of winbind and cifs.idmap facility are unavailable\&.
.SH "OPTIONS"
.PP
+--help|-h
+.RS
+Print the usage message and exit.
+.RE
+.PP
+--timeout|-t
+.RS 4
+Set the expiration timer, in seconds on the key. The default is 600 seconds (10 minutes). Setting this to 0 will cause the key to never expire.
+.RE
+.PP
\-\-version|\-v
.RS 4
Print version number and exit\&.
diff --git a/cifs.idmap.c b/cifs.idmap.c
index 80802d7..4109ca0 100644
--- a/cifs.idmap.c
+++ b/cifs.idmap.c
@@ -42,35 +42,76 @@
#include <limits.h>
#include <wbclient.h>
+#include "cifsacl.h"
+
static const char *prog = "cifs.idmap";
+static const struct option long_options[] = {
+ {"help", 0, NULL, 'h'},
+ {"timeout", 1, NULL, 't'},
+ {"version", 0, NULL, 'v'},
+ {NULL, 0, NULL, 0}
+};
+
static void usage(void)
{
- fprintf(stderr, "Usage: %s key_serial\n", prog);
+ fprintf(stderr, "Usage: %s [-h] [-v] [-t timeout] key_serial\n", prog);
}
-char *strget(const char *str, char *substr)
+char *strget(const char *str, const char *substr)
{
int len, sublen, retlen;
- char *retstr, *substrptr;
+ char *substrptr;
- sublen = strlen(substr);
+ /* find the prefix */
substrptr = strstr(str, substr);
- if (substrptr) {
- len = strlen(substrptr);
- substrptr += sublen;
-
- retlen = len - sublen;
- if (retlen > 0) {
- retstr = malloc(retlen + 1);
- if (retstr) {
- strncpy(retstr, substrptr, retlen);
- return retstr;
- }
- }
- }
+ if (!substrptr)
+ return substrptr;
+
+ /* skip over it */
+ sublen = strlen(substr);
+ substrptr += sublen;
+
+ /* if there's nothing after the prefix, return NULL */
+ if (*substrptr == '\0')
+ return NULL;
- return NULL;
+ return substrptr;
+}
+
+/*
+ * Convert a string representation of unsigned int into a numeric one. Also
+ * check for incomplete string conversion and overflow.
+ */
+static int
+str_to_uint(const char *src, unsigned int *dst)
+{
+ unsigned long tmp;
+ char *end;
+
+ errno = 0;
+ tmp = strtoul(src, &end, 0);
+
+ if (*end != '\0')
+ return EINVAL;
+ if (tmp > UINT_MAX)
+ return EOVERFLOW;
+
+ *dst = (unsigned int)tmp;
+ return 0;
+}
+
+/*
+ * Winbind keeps wbcDomainSid fields in host-endian. So, we must convert it
+ * to little endian since the kernel will expect that.
+ */
+static void
+convert_sid_endianness(struct cifs_sid *sid)
+{
+ int i;
+
+ for (i = 0; i < sid->num_subauth; i++)
+ sid->sub_auth[i] = htole32(sid->sub_auth[i]);
}
static int
@@ -136,12 +177,20 @@ cifs_idmap(const key_serial_t key, const char *key_descr)
sidstr = strget(key_descr, "oi:");
if (sidstr) {
- uid = atoi(sidstr);
- syslog(LOG_DEBUG, "SID: %s, uid: %d", sidstr, uid);
+ rc = str_to_uint(sidstr, (unsigned int *)&uid);
+ if (rc) {
+ syslog(LOG_ERR, "Unable to convert %s to uid: %s",
+ sidstr, strerror(rc));
+ goto cifs_idmap_ret;
+ }
+
+ syslog(LOG_DEBUG, "SID: %s, uid: %u", sidstr, uid);
rc = wbcUidToSid(uid, &sid);
if (rc)
- syslog(LOG_DEBUG, "uid %d to SID error: %d", uid, rc);
- if (!rc) { /* SID has been mapped to a uid */
+ syslog(LOG_DEBUG, "uid %u to SID error: %d", uid, rc);
+ if (!rc) {
+ /* SID has been mapped to a uid */
+ convert_sid_endianness((struct cifs_sid *)&sid);
rc = keyctl_instantiate(key, &sid,
sizeof(struct wbcDomainSid), 0);
if (rc)
@@ -154,12 +203,20 @@ cifs_idmap(const key_serial_t key, const char *key_descr)
sidstr = strget(key_descr, "gi:");
if (sidstr) {
- gid = atoi(sidstr);
- syslog(LOG_DEBUG, "SID: %s, gid: %d", sidstr, gid);
+ rc = str_to_uint(sidstr, (unsigned int *)&gid);
+ if (rc) {
+ syslog(LOG_ERR, "Unable to convert %s to gid: %s",
+ sidstr, strerror(rc));
+ goto cifs_idmap_ret;
+ }
+
+ syslog(LOG_DEBUG, "SID: %s, gid: %u", sidstr, gid);
rc = wbcGidToSid(gid, &sid);
if (rc)
- syslog(LOG_DEBUG, "gid %d to SID error: %d", gid, rc);
- if (!rc) { /* SID has been mapped to a gid */
+ syslog(LOG_DEBUG, "gid %u to SID error: %d", gid, rc);
+ if (!rc) {
+ /* SID has been mapped to a gid */
+ convert_sid_endianness((struct cifs_sid *)&sid);
rc = keyctl_instantiate(key, &sid,
sizeof(struct wbcDomainSid), 0);
if (rc)
@@ -174,32 +231,46 @@ cifs_idmap(const key_serial_t key, const char *key_descr)
syslog(LOG_DEBUG, "Invalid key: %s", key_descr);
cifs_idmap_ret:
- if (sidstr)
- free(sidstr);
-
return rc;
}
int main(const int argc, char *const argv[])
{
int c;
- long rc = 1;
+ long rc;
key_serial_t key = 0;
char *buf;
+ unsigned int timeout = 600; /* default idmap cache timeout */
openlog(prog, 0, LOG_DAEMON);
- while ((c = getopt_long(argc, argv, "v", NULL, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "ht:v",
+ long_options, NULL)) != -1) {
switch (c) {
+ case 'h':
+ rc = 0;
+ usage();
+ goto out;
+ case 't':
+ rc = str_to_uint(optarg, &timeout);
+ if (rc) {
+ syslog(LOG_ERR, "bad timeout value %s: %s",
+ optarg, strerror(rc));
+ goto out;
+ }
+ break;
case 'v':
+ rc = 0;
printf("version: %s\n", VERSION);
goto out;
default:
+ rc = EINVAL;
syslog(LOG_ERR, "unknown option: %c", c);
goto out;
}
}
+ rc = 1;
/* is there a key? */
if (argc <= optind) {
usage();
@@ -215,6 +286,14 @@ int main(const int argc, char *const argv[])
goto out;
}
+ /* set timeout on key */
+ rc = keyctl_set_timeout(key, timeout);
+ if (rc == -1) {
+ syslog(LOG_ERR, "unable to set key timeout: %s",
+ strerror(errno));
+ goto out;
+ }
+
rc = keyctl_describe_alloc(key, &buf);
if (rc == -1) {
syslog(LOG_ERR, "keyctl_describe_alloc failed: %s",
@@ -225,8 +304,7 @@ int main(const int argc, char *const argv[])
syslog(LOG_DEBUG, "key description: %s", buf);
- if ((strncmp(buf, "cifs.idmap", sizeof("cifs.idmap") - 1) == 0))
- rc = cifs_idmap(key, buf);
+ rc = cifs_idmap(key, buf);
out:
return rc;
}
diff --git a/cifsacl.h b/cifsacl.h
index 4ea7fd4..68fe0fd 100644
--- a/cifsacl.h
+++ b/cifsacl.h
@@ -83,7 +83,7 @@
#define NO_PROPAGATE_INHERIT_FLAG 0x04 /* NP */
#define INHERIT_ONLY_FLAG 0x08 /* IO */
#define INHERITED_ACE_FLAG 0x10 /* I */
-#define VFLAGS 0x1f
+#define VFLAGS (OBJECT_INHERIT_FLAG|CONTAINER_INHERIT_FLAG|NO_PROPAGATE_INHERIT_FLAG|INHERIT_ONLY_FLAG|INHERITED_ACE_FLAG)
#define ACCESS_ALLOWED 0 /* ALLOWED */
#define ACCESS_DENIED 1 /* DENIED */
@@ -94,15 +94,17 @@
#define COMPTYPE 0x2
#define COMPFLAG 0x4
#define COMPMASK 0x8
-#define COMPALL 0xf /* COMPSID | COMPTYPE | COMPFLAG | COMPMASK */
+#define COMPALL (COMPSID|COMPTYPE|COMPFLAG|COMPMASK)
-enum ace_action {
- acedelete = 0,
- acemodify,
- aceadd,
- aceset
-};
+#define NUM_AUTHS (6) /* number of authority fields */
+#define SID_MAX_SUB_AUTHORITIES (15) /* max number of sub authority fields */
+/*
+ * While not indicated here, the structs below represent on-the-wire data
+ * structures. Any multi-byte values are expected to be little-endian!
+ *
+ * FIXME: should we change these to use endianness annotations?
+ */
struct cifs_ntsd {
uint16_t revision; /* revision level */
uint16_t type;
@@ -110,20 +112,20 @@ struct cifs_ntsd {
uint32_t gsidoffset;
uint32_t sacloffset;
uint32_t dacloffset;
-};
+} __attribute__((packed));
struct cifs_sid {
uint8_t revision; /* revision level */
uint8_t num_subauth;
- uint8_t authority[6];
- uint32_t sub_auth[5]; /* sub_auth[num_subauth] */
-};
+ uint8_t authority[NUM_AUTHS];
+ uint32_t sub_auth[SID_MAX_SUB_AUTHORITIES];
+} __attribute__((packed));
struct cifs_ctrl_acl {
uint16_t revision; /* revision level */
uint16_t size;
uint32_t num_aces;
-};
+} __attribute__((packed));
struct cifs_ace {
uint8_t type;
@@ -131,6 +133,6 @@ struct cifs_ace {
uint16_t size;
uint32_t access_req;
struct cifs_sid sid; /* ie UUID of user or group who gets these perms */
-};
+} __attribute__((packed));
#endif /* CIFSACL_H */
diff --git a/configure.ac b/configure.ac
index f969b37..07df3be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-AC_INIT([cifs-utils], [5.7], [linux-cifs@vger.kernel.org], [cifs-utils], [https://wiki.samba.org/index.php/LinuxCIFS_utils])
+AC_INIT([cifs-utils], [5.7.1], [linux-cifs@vger.kernel.org], [cifs-utils], [https://wiki.samba.org/index.php/LinuxCIFS_utils])
AC_CONFIG_SRCDIR([replace.h])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile contrib/Makefile contrib/request-key.d/Makefile])
diff --git a/getcifsacl.c b/getcifsacl.c
index 8cbdb1d..c576fc0 100644
--- a/getcifsacl.c
+++ b/getcifsacl.c
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <errno.h>
#include <limits.h>
#include <wbclient.h>
@@ -38,7 +39,7 @@
#include <sys/xattr.h>
#include "cifsacl.h"
-static const char *prog = "getcifsacl";
+static const char *prog;
static void
print_each_ace_mask(uint32_t mask)
@@ -171,22 +172,37 @@ print_ace_type(uint8_t acetype, int raw)
}
}
+/*
+ * Winbind keeps wbcDomainSid fields in host-endian. So, we must convert from
+ * little endian here so that winbind will understand correctly.
+ */
+static void
+convert_sid_endianness(struct cifs_sid *sid)
+{
+ int i;
+
+ for (i = 0; i < sid->num_subauth; i++)
+ sid->sub_auth[i] = le32toh(sid->sub_auth[i]);
+}
+
static void
-print_sid(struct wbcDomainSid *sidptr, int raw)
+print_sid(struct cifs_sid *sidptr, int raw)
{
int i;
- int num_auths;
- int num_auth = MAX_NUM_AUTHS;
wbcErr rc;
char *domain_name = NULL;
char *sidname = NULL;
enum wbcSidType sntype;
+ unsigned long long id_auth_val;
+
+ convert_sid_endianness(sidptr);
if (raw)
goto print_sid_raw;
- rc = wbcLookupSid(sidptr, &domain_name, &sidname, &sntype);
- if (!rc) {
+ rc = wbcLookupSid((struct wbcDomainSid *)sidptr, &domain_name,
+ &sidname, &sntype);
+ if (WBC_ERROR_IS_OK(rc)) {
printf("%s", domain_name);
if (strlen(domain_name))
printf("%c", '\\');
@@ -195,36 +211,55 @@ print_sid(struct wbcDomainSid *sidptr, int raw)
}
print_sid_raw:
- num_auths = sidptr->num_auths;
- printf("S");
- printf("-%d", sidptr->sid_rev_num);
- for (i = 0; i < num_auth; ++i)
- if (sidptr->id_auth[i])
- printf("-%d", sidptr->id_auth[i]);
- for (i = 0; i < num_auths; i++)
- printf("-%u", le32toh(sidptr->sub_auths[i]));
+ printf("S-%hhu", sidptr->revision);
+
+ id_auth_val = (unsigned long long)sidptr->authority[5];
+ id_auth_val += (unsigned long long)sidptr->authority[4] << 8;
+ id_auth_val += (unsigned long long)sidptr->authority[3] << 16;
+ id_auth_val += (unsigned long long)sidptr->authority[2] << 24;
+ id_auth_val += (unsigned long long)sidptr->authority[1] << 32;
+ id_auth_val += (unsigned long long)sidptr->authority[0] << 48;
+
+ /*
+ * MS-DTYP states that if the authority is >= 2^32, then it should be
+ * expressed as a hex value.
+ */
+ if (id_auth_val <= UINT_MAX)
+ printf("-%llu", id_auth_val);
+ else
+ printf("-0x%llx", id_auth_val);
+
+ for (i = 0; i < sidptr->num_subauth; i++)
+ printf("-%u", sidptr->sub_auth[i]);
}
static void
print_ace(struct cifs_ace *pace, char *end_of_acl, int raw)
{
- /* validate that we do not go past end of acl */
+ uint16_t size;
+
+ /* make sure we can safely get to "size" */
+ if (end_of_acl < (char *)pace + offsetof(struct cifs_ace, size) + 1)
+ return;
+
+ size = le16toh(pace->size);
+ /* 16 == size of cifs_ace when cifs_sid has no subauths */
if (le16toh(pace->size) < 16)
return;
+ /* validate that we do not go past end of acl */
if (end_of_acl < (char *)pace + le16toh(pace->size))
return;
printf("ACL:");
- print_sid((struct wbcDomainSid *)&pace->sid, raw);
+ print_sid((struct cifs_sid *)&pace->sid, raw);
printf(":");
print_ace_type(pace->type, raw);
printf("/");
print_ace_flags(pace->flags, raw);
printf("/");
- print_ace_mask(pace->access_req, raw);
-
+ print_ace_mask(le32toh(pace->access_req), raw);
return;
}
@@ -261,14 +296,14 @@ parse_dacl(struct cifs_ctrl_acl *pdacl, char *end_of_acl, int raw)
}
static int
-parse_sid(struct wbcDomainSid *psid, char *end_of_acl, char *title, int raw)
+parse_sid(struct cifs_sid *psid, char *end_of_acl, char *title, int raw)
{
if (end_of_acl < (char *)psid + 8)
return -EINVAL;
if (title)
printf("%s:", title);
- print_sid((struct wbcDomainSid *)psid, raw);
+ print_sid((struct cifs_sid *)psid, raw);
printf("\n");
return 0;
@@ -280,15 +315,15 @@ parse_sec_desc(struct cifs_ntsd *pntsd, ssize_t acl_len, int raw)
int rc;
uint32_t dacloffset;
char *end_of_acl = ((char *)pntsd) + acl_len;
- struct wbcDomainSid *owner_sid_ptr, *group_sid_ptr;
+ struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
struct cifs_ctrl_acl *dacl_ptr; /* no need for SACL ptr */
if (pntsd == NULL)
return -EIO;
- owner_sid_ptr = (struct wbcDomainSid *)((char *)pntsd +
+ owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
le32toh(pntsd->osidoffset));
- group_sid_ptr = (struct wbcDomainSid *)((char *)pntsd +
+ group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
le32toh(pntsd->gsidoffset));
dacloffset = le32toh(pntsd->dacloffset);
dacl_ptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
@@ -333,6 +368,7 @@ main(const int argc, char *const argv[])
size_t bufsize = BUFSIZE;
char *filename, *attrval;
+ prog = basename(argv[0]);
openlog(prog, 0, LOG_DAEMON);
while ((c = getopt_long(argc, argv, "r:v", NULL, NULL)) != -1) {
diff --git a/mount.cifs.c b/mount.cifs.c
index 756fce2..9cf58a5 100644
--- a/mount.cifs.c
+++ b/mount.cifs.c
@@ -1335,6 +1335,7 @@ static int parse_unc(const char *unc_name, struct parsed_mount_info *parsed_info
}
/* Set up "host" and "share" pointers based on UNC format. */
+ /* TODO: Remove support for NFS syntax as of cifs-utils-6.0. */
if (strncmp(unc_name, "//", 2) && strncmp(unc_name, "\\\\", 2)) {
/*
* check for nfs syntax (server:/share/prepath)
@@ -1351,6 +1352,9 @@ static int parse_unc(const char *unc_name, struct parsed_mount_info *parsed_info
share++;
if (*share == '/')
++share;
+ fprintf(stderr, "WARNING: using NFS syntax for mounting CIFS "
+ "shares is deprecated and will be removed in cifs-utils"
+ "-6.0. Please migrate to UNC syntax.\n");
} else {
host = unc_name + 2;
hostlen = strcspn(host, "/\\");
diff --git a/setcifsacl.1 b/setcifsacl.1
index 550d23d..3dd755c 100644
--- a/setcifsacl.1
+++ b/setcifsacl.1
@@ -30,6 +30,10 @@ This tool is part of the cifs-utils suite\&.
setcifsacl is a userspace helper program for the Linux CIFS client file system. It is intended to alter an ACL of a security descriptor for a file system object. It is best utilized when an option of cifsacl is specified when mounting a cifs share in conjunction with winbind facility of Samba suite. Whether a security descriptor to be set is applied or not is determined by the CIFS/SMB server.
.SH "OPTIONS"
.PP
+-h
+.RS 4
+Print usage message and exit.
+.RE
\-v
.RS 4
Print version number and exit\&.
diff --git a/setcifsacl.c b/setcifsacl.c
index 29b7b93..8891844 100644
--- a/setcifsacl.c
+++ b/setcifsacl.c
@@ -39,23 +39,42 @@
#include <sys/xattr.h>
#include "cifsacl.h"
-static const char *prog = "setcifsacl";
+static const char *prog;
+
+enum setcifsacl_actions {
+ ActUnknown = -1,
+ ActDelete,
+ ActModify,
+ ActAdd,
+ ActSet
+};
static void
-copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
- int numaces, int acessize)
+copy_cifs_sid(struct cifs_sid *dst, const struct cifs_sid *src)
{
int i;
+ dst->revision = src->revision;
+ dst->num_subauth = src->num_subauth;
+ for (i = 0; i < NUM_AUTHS; i++)
+ dst->authority[i] = src->authority[i];
+ for (i = 0; i < src->num_subauth; i++)
+ dst->sub_auth[i] = src->sub_auth[i];
+}
+
+static void
+copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
+ int numaces, int acessize)
+{
int osidsoffset, gsidsoffset, dacloffset;
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 = htole32(pntsd->osidoffset);
- gsidsoffset = htole32(pntsd->gsidoffset);
- dacloffset = htole32(pntsd->dacloffset);
+ osidsoffset = le32toh(pntsd->osidoffset);
+ gsidsoffset = le32toh(pntsd->gsidoffset);
+ dacloffset = le32toh(pntsd->dacloffset);
pnntsd->revision = pntsd->revision;
pnntsd->type = pntsd->type;
@@ -73,24 +92,12 @@ copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
/* copy owner sid */
owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + osidsoffset);
nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + osidsoffset);
-
- nowner_sid_ptr->revision = owner_sid_ptr->revision;
- nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
- for (i = 0; i < 6; i++)
- nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
- for (i = 0; i < 5; i++)
- nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
+ copy_cifs_sid(nowner_sid_ptr, owner_sid_ptr);
/* copy group sid */
group_sid_ptr = (struct cifs_sid *)((char *)pntsd + gsidsoffset);
ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + gsidsoffset);
-
- ngroup_sid_ptr->revision = group_sid_ptr->revision;
- ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
- for (i = 0; i < 6; i++)
- ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
- for (i = 0; i < 5; i++)
- ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
+ copy_cifs_sid(ngroup_sid_ptr, group_sid_ptr);
return;
}
@@ -98,22 +105,15 @@ copy_sec_desc(const struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
static int
copy_ace(struct cifs_ace *dace, struct cifs_ace *sace)
{
- int i;
-
dace->type = sace->type;
dace->flags = sace->flags;
- dace->access_req = htole32(sace->access_req);
+ dace->access_req = sace->access_req;
- dace->sid.revision = sace->sid.revision;
- dace->sid.num_subauth = sace->sid.num_subauth;
- for (i = 0; i < 6; i++)
- dace->sid.authority[i] = sace->sid.authority[i];
- for (i = 0; i < sace->sid.num_subauth; i++)
- dace->sid.sub_auth[i] = sace->sid.sub_auth[i];
+ copy_cifs_sid(&dace->sid, &sace->sid);
- dace->size = htole16(sace->size);
+ dace->size = sace->size;
- return dace->size;
+ return le16toh(dace->size);
}
static int
@@ -126,7 +126,7 @@ compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
return 0;
if (dace->sid.num_subauth != sace->sid.num_subauth)
return 0;
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < NUM_AUTHS; i++) {
if (dace->sid.authority[i] != sace->sid.authority[i])
return 0;
}
@@ -147,7 +147,7 @@ compare_aces(struct cifs_ace *sace, struct cifs_ace *dace, int compflags)
}
if (compflags & COMPMASK) {
- if (dace->access_req != htole32(sace->access_req))
+ if (dace->access_req != sace->access_req)
return 0;
}
@@ -329,19 +329,16 @@ get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
struct cifs_ctrl_acl *ldaclptr;
char *end_of_acl = ((char *)pntsd) + acl_len;
- if (pntsd == NULL)
- return 0;
-
dacloffset = le32toh(pntsd->dacloffset);
if (!dacloffset)
return 0;
- else {
- ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
- /* validate that we do not go past end of acl */
- if (end_of_acl >= (char *)ldaclptr + le16toh(ldaclptr->size)) {
- numfaces = le32toh(ldaclptr->num_aces);
- *daclptr = ldaclptr;
- }
+
+ ldaclptr = (struct cifs_ctrl_acl *)((char *)pntsd + dacloffset);
+
+ /* validate that we do not go past end of acl */
+ if (end_of_acl >= (char *)ldaclptr + le16toh(ldaclptr->size)) {
+ numfaces = le32toh(ldaclptr->num_aces);
+ *daclptr = ldaclptr;
}
return numfaces;
@@ -350,74 +347,75 @@ get_numfaces(struct cifs_ntsd *pntsd, ssize_t acl_len,
static struct cifs_ace **
build_fetched_aces(char *daclptr, int numfaces)
{
- int i, j, rc = 0, acl_size;
+ int i, acl_size;
char *acl_base;
struct cifs_ace *pace, **facesptr;
- facesptr = (struct cifs_ace **)malloc(numfaces *
- sizeof(struct cifs_aces *));
+ facesptr = calloc(numfaces, sizeof(struct cifs_aces *));
if (!facesptr) {
printf("%s: Error %d allocating ACE array",
__func__, errno);
- rc = errno;
+ return facesptr;
}
acl_base = daclptr;
acl_size = sizeof(struct cifs_ctrl_acl);
for (i = 0; i < numfaces; ++i) {
facesptr[i] = malloc(sizeof(struct cifs_ace));
- if (!facesptr[i]) {
- rc = errno;
- goto build_fetched_aces_ret;
- }
+ if (!facesptr[i])
+ goto build_fetched_aces_err;
pace = (struct cifs_ace *) (acl_base + acl_size);
memcpy(facesptr[i], pace, sizeof(struct cifs_ace));
acl_base = (char *)pace;
acl_size = le16toh(pace->size);
}
-
-build_fetched_aces_ret:
- if (rc) {
- printf("%s: Invalid fetched ace\n", __func__);
- if (i) {
- for (j = i; j >= 0; --j)
- free(facesptr[j]);
- }
- free(facesptr);
- }
return facesptr;
+
+build_fetched_aces_err:
+ printf("%s: Invalid fetched ace\n", __func__);
+ for (i = 0; i < numfaces; ++i)
+ free(facesptr[i]);
+ free(facesptr);
+ return NULL;
}
static int
verify_ace_sid(char *sidstr, struct cifs_sid *sid)
{
- int rc;
- char *lstr;
- struct passwd *winpswdptr;
-
- lstr = strstr(sidstr, "\\"); /* everything before | */
- if (lstr)
- ++lstr;
- else
- lstr = sidstr;
-
- /* Check if it is a (raw) SID (string) */
- rc = wbcStringToSid(lstr, (struct wbcDomainSid *)sid);
- if (!rc)
- return rc;
-
- /* Check if it a name (string) which can be resolved to a SID*/
- rc = wbcGetpwnam(lstr, &winpswdptr);
- if (rc) {
- printf("%s: Invalid user name: %s\n", __func__, sidstr);
- return rc;
- }
- rc = wbcUidToSid(winpswdptr->pw_uid, (struct wbcDomainSid *)sid);
- if (rc) {
- printf("%s: Invalid user: %s\n", __func__, sidstr);
+ int i;
+ wbcErr rc;
+ char *name, *domain;
+ enum wbcSidType type;
+
+ name = strchr(sidstr, '\\');
+ if (!name) {
+ /* might be a raw string representation of SID */
+ rc = wbcStringToSid(sidstr, (struct wbcDomainSid *)sid);
+ if (WBC_ERROR_IS_OK(rc))
+ goto fix_endianness;
+
+ domain = "";
+ name = sidstr;
+ } else {
+ domain = sidstr;
+ *name = '\0';
+ ++name;
+ }
+
+ rc = wbcLookupName(domain, name, (struct wbcDomainSid *)sid, &type);
+ if (!WBC_ERROR_IS_OK(rc)) {
+ printf("%s: Error converting %s\\%s to SID: %s\n",
+ __func__, domain, name, wbcErrorString(rc));
return rc;
}
+fix_endianness:
+ /*
+ * Winbind keeps wbcDomainSid fields in host-endian. So, we must
+ * convert that to little endian since the server will expect that.
+ */
+ for (i = 0; i < sid->num_subauth; i++)
+ sid->sub_auth[i] = htole32(sid->sub_auth[i]);
return 0;
}
@@ -514,62 +512,61 @@ verify_ace_flags(char *flagstr, uint8_t *flagval)
}
static uint32_t
-ace_mask_value(char *maskstr)
+ace_mask_value(char *mask)
{
- int i, len;
- uint32_t maskval = 0x0;
- char *lmask;
+ uint32_t maskval = 0;
+ char cur;
- if (!strcmp(maskstr, "FULL"))
+ if (!strcmp(mask, "FULL"))
return FULL_CONTROL;
- else if (!strcmp(maskstr, "CHANGE"))
+ if (!strcmp(mask, "CHANGE"))
return CHANGE;
- else if (!strcmp(maskstr, "D"))
- return DELETE;
- else if (!strcmp(maskstr, "READ"))
+ if (!strcmp(mask, "READ"))
return EREAD;
- else {
- len = strlen(maskstr);
- lmask = maskstr;
- for (i = 0; i < len; ++i, ++lmask) {
- if (*lmask == 'R')
- maskval |= EREAD;
- else if (*lmask == 'W')
- maskval |= EWRITE;
- else if (*lmask == 'X')
- maskval |= EXEC;
- else if (*lmask == 'D')
- maskval |= DELETE;
- else if (*lmask == 'P')
- maskval |= WRITE_DAC;
- else if (*lmask == 'O')
- maskval |= WRITE_OWNER;
- else
- return 0;
+
+ while((cur = *mask++)) {
+ switch(cur) {
+ case 'R':
+ maskval |= EREAD;
+ break;
+ case 'W':
+ maskval |= EWRITE;
+ break;
+ case 'X':
+ maskval |= EXEC;
+ break;
+ case 'D':
+ maskval |= DELETE;
+ break;
+ case 'P':
+ maskval |= WRITE_DAC;
+ break;
+ case 'O':
+ maskval |= WRITE_OWNER;
+ break;
+ default:
+ return 0;
}
- return maskval;
}
-
- return 0;
+ return maskval;
}
static int
verify_ace_mask(char *maskstr, uint32_t *maskval)
{
- char *invalflag;
+ unsigned long val;
+ char *ep;
- if (strstr(maskstr, "0x") || !strcmp(maskstr, "DELDHLD")) {
- *maskval = strtol(maskstr, &invalflag, 16);
- if (!invalflag) {
- printf("%s: Invalid mask: %s\n", __func__, maskstr);
- return 1;
- }
- } else
- *maskval = ace_mask_value(maskstr);
+ errno = 0;
+ val = strtoul(maskstr, &ep, 0);
+ if (errno == 0 && *ep == '\0')
+ *maskval = htole32((uint32_t)val);
+ else
+ *maskval = htole32(ace_mask_value(maskstr));
if (!*maskval) {
- printf("%s: Invalid mask %s and value: 0x%x\n",
- __func__, maskstr, *maskval);
+ printf("%s: Invalid mask %s (value 0x%x)\n", __func__,
+ maskstr, *maskval);
return 1;
}
@@ -583,8 +580,7 @@ build_cmdline_aces(char **arrptr, int numcaces)
char *acesid, *acetype, *aceflag, *acemask;
struct cifs_ace **cacesptr;
- cacesptr = (struct cifs_ace **)malloc(numcaces *
- sizeof(struct cifs_aces *));
+ cacesptr = calloc(numcaces, sizeof(struct cifs_aces *));
if (!cacesptr) {
printf("%s: Error %d allocating ACE array", __func__, errno);
return NULL;
@@ -630,105 +626,90 @@ build_cmdline_aces(char **arrptr, int numcaces)
goto build_cmdline_aces_ret;
}
- cacesptr[i]->size = 1 + 1 + 2 + 4 + 1 + 1 + 6 +
- (cacesptr[i]->sid.num_subauth * 4);
+ cacesptr[i]->size = htole16(1 + 1 + 2 + 4 + 1 + 1 + 6 +
+ cacesptr[i]->sid.num_subauth * 4);
}
return cacesptr;
build_cmdline_aces_ret:
- for (; i >= 0; --i)
+ for (i = 0; i < numcaces; ++i)
free(cacesptr[i]);
free(cacesptr);
return NULL;
}
static char **
-parse_cmdline_aces(char *optarg, int numcaces)
+parse_cmdline_aces(char *acelist, int numcaces)
{
int i = 0, len;
char *acestr, *vacestr, **arrptr = NULL;
- errno = EINVAL;
arrptr = (char **)malloc(numcaces * sizeof(char *));
if (!arrptr) {
- printf("%s: Error %d allocating char array\n", __func__, errno);
+ printf("%s: Unable to allocate char array\n", __func__);
return NULL;
}
while (i < numcaces) {
- acestr = strtok(optarg, ","); /* everything before , */
- if (acestr) {
- vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
- if (vacestr) {
- vacestr = strchr(vacestr, ':');
- if (vacestr)
- ++vacestr; /* go past : */
- if (vacestr) {
- len = strlen(vacestr);
- arrptr[i] = malloc(len + 1);
- if (!arrptr[i])
- goto parse_cmdline_aces_ret;
- strcpy(arrptr[i], vacestr);
- ++i;
- } else
- goto parse_cmdline_aces_ret;
- } else
- goto parse_cmdline_aces_ret;
- } else
- goto parse_cmdline_aces_ret;
- optarg = NULL;
+ acestr = strtok(acelist, ","); /* everything before , */
+ if (!acestr)
+ goto parse_cmdline_aces_err;
+
+ vacestr = strstr(acestr, "ACL:"); /* ace as ACL:*" */
+ if (!vacestr)
+ goto parse_cmdline_aces_err;
+ vacestr += 4; /* skip past "ACL:" */
+ if (*vacestr) {
+ arrptr[i] = vacestr;
+ ++i;
+ }
+ acelist = NULL;
}
- errno = 0;
return arrptr;
-parse_cmdline_aces_ret:
- printf("%s: Error %d parsing ACEs\n", __func__, errno);
- for (; i >= 0; --i)
- free(arrptr[i]);
+parse_cmdline_aces_err:
+ printf("%s: Error parsing ACEs\n", __func__);
free(arrptr);
return NULL;
}
+/* How many aces were provided on the command-line? Count the commas. */
static unsigned int
-get_numcaces(const char *optarg)
+get_numcaces(const char *aces)
{
int i, len;
- unsigned int numcaces = 1;
-
- if (!optarg)
- return 0;
+ unsigned int num = 1;
+ const char *current;
- len = strlen(optarg);
- for (i = 0; i < len; ++i) {
- if (*(optarg + i) == ',')
- ++numcaces;
- }
+ current = aces;
+ while((current = strchr(current, ',')))
+ ++num;
- return numcaces;
+ return num;
}
static int
setacl_action(struct cifs_ntsd *pntsd, struct cifs_ntsd **npntsd,
ssize_t *bufsize, struct cifs_ace **facesptr, int numfaces,
struct cifs_ace **cacesptr, int numcaces,
- int maction)
+ enum setcifsacl_actions maction)
{
int rc = 1;
switch (maction) {
- case 0:
+ case ActDelete:
rc = ace_delete(pntsd, npntsd, bufsize, facesptr,
numfaces, cacesptr, numcaces);
break;
- case 1:
+ case ActModify:
rc = ace_modify(pntsd, npntsd, bufsize, facesptr,
numfaces, cacesptr, numcaces);
break;
- case 2:
+ case ActAdd:
rc = ace_add(pntsd, npntsd, bufsize, facesptr,
numfaces, cacesptr, numcaces);
break;
- case 3:
+ case ActSet:
rc = ace_set(pntsd, npntsd, bufsize, cacesptr, numcaces);
break;
default:
@@ -771,52 +752,62 @@ setcifsacl_usage(void)
int
main(const int argc, char *const argv[])
{
- int i, rc, c, numcaces, numfaces, maction = -1;
+ int i, rc, c, numcaces, numfaces;
+ enum setcifsacl_actions maction = ActUnknown;
ssize_t attrlen, bufsize = BUFSIZE;
- char *filename, *attrval, **arrptr = NULL;
+ char *ace_list, *filename, *attrval, **arrptr = NULL;
struct cifs_ctrl_acl *daclptr = NULL;
struct cifs_ace **cacesptr = NULL, **facesptr = NULL;
struct cifs_ntsd *ntsdptr = NULL;
+ prog = basename(argv[0]);
+
openlog(prog, 0, LOG_DAEMON);
- c = getopt(argc, argv, "v:D:M:a:S:?");
+ c = getopt(argc, argv, "hvD:M:a:S:");
switch (c) {
- case 'v':
- printf("Version: %s\n", VERSION);
- goto out;
case 'D':
- maction = 0;
+ maction = ActDelete;
+ ace_list = optarg;
break;
case 'M':
- maction = 1;
+ maction = ActModify;
+ ace_list = optarg;
break;
case 'a':
- maction = 2;
+ maction = ActAdd;
+ ace_list = optarg;
break;
case 'S':
- maction = 3;
+ maction = ActSet;
+ ace_list = optarg;
break;
- case '?':
+ case 'h':
setcifsacl_usage();
return 0;
+ case 'v':
+ printf("Version: %s\n", VERSION);
+ return 0;
default:
- break;
+ setcifsacl_usage();
+ return -1;
}
+ /* We expect 1 argument in addition to the option */
if (argc != 4) {
setcifsacl_usage();
return -1;
}
filename = argv[3];
- numcaces = get_numcaces(optarg);
- if (!numcaces) {
+ if (!ace_list) {
printf("%s: No valid ACEs specified\n", __func__);
return -1;
}
- arrptr = parse_cmdline_aces(optarg, numcaces);
+ numcaces = get_numcaces(ace_list);
+
+ arrptr = parse_cmdline_aces(ace_list, numcaces);
if (!arrptr)
goto setcifsacl_numcaces_ret;
@@ -850,7 +841,7 @@ cifsacl:
}
numfaces = get_numfaces((struct cifs_ntsd *)attrval, attrlen, &daclptr);
- if (!numfaces && maction != 2) { /* if we are not adding aces */
+ if (!numfaces && maction != ActAdd) { /* if we are not adding aces */
printf("%s: Empty DACL\n", __func__);
goto setcifsacl_facenum_ret;
}
@@ -870,7 +861,6 @@ cifsacl:
printf("%s: setxattr error: %s\n", __func__, strerror(errno));
goto setcifsacl_facenum_ret;
-out:
return 0;
setcifsacl_action_ret:
@@ -890,8 +880,6 @@ setcifsacl_cmdlineverify_ret:
free(cacesptr);
setcifsacl_cmdlineparse_ret:
- for (i = 0; i < numcaces; ++i)
- free(arrptr[i]);
free(arrptr);
setcifsacl_numcaces_ret: