Blob Blame History Raw
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: