summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h2
-rw-r--r--source3/lib/iconv.c6
-rw-r--r--source3/smbd/posix_acls.c277
3 files changed, 203 insertions, 82 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index ddc1adff4e0..7c5efec10e9 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1695,7 +1695,7 @@ struct unix_error_map {
/* generic iconv conversion structure */
typedef struct {
- size_t (*direct)(void *cd, char **inbuf, size_t *inbytesleft,
+ size_t (*direct)(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
size_t (*pull)(void *cd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
diff --git a/source3/lib/iconv.c b/source3/lib/iconv.c
index e4845e47349..54733c2ac27 100644
--- a/source3/lib/iconv.c
+++ b/source3/lib/iconv.c
@@ -35,7 +35,7 @@ static size_t iconv_copy(void *,char **, size_t *, char **, size_t *);
a ucs2 buffer, and a function that pushes to a ucs2 buffer
*/
static struct {
- char *name;
+ const char *name;
size_t (*pull)(void *, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
size_t (*push)(void *, char **inbuf, size_t *inbytesleft,
@@ -357,8 +357,8 @@ static size_t ucs2hex_push(void *cd, char **inbuf, size_t *inbytesleft,
support and finding bugs. Don't use on a production system!
*/
static struct {
- char from;
- char *to;
+ const char from;
+ const char *to;
int len;
} weird_table[] = {
{'q', "^q^", 3},
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 93a57925f13..2aea3a2c902 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -559,12 +559,18 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
extern DOM_SID global_sid_World;
fstring u_name;
fstring g_name;
+ extern struct current_user current_user;
/* "Everyone" always matches every uid. */
if (sid_equal(&group_ace->trustee, &global_sid_World))
return True;
+ /* Assume that the current user is in the current group (force group) */
+
+ if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid)
+ return True;
+
fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
@@ -600,6 +606,14 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
BOOL got_other = False;
canon_ace *pace_other = NULL;
canon_ace *pace_group = NULL;
+ connection_struct *conn = fsp->conn;
+ SMB_ACL_T current_posix_acl = NULL;
+ mode_t current_user_perms = 0;
+ mode_t current_grp_perms = 0;
+ mode_t current_other_perms = 0;
+ BOOL got_current_user = False;
+ BOOL got_current_grp = False;
+ BOOL got_current_other = False;
for (pace = *pp_ace; pace; pace = pace->next) {
if (pace->type == SMB_ACL_USER_OBJ) {
@@ -632,6 +646,62 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
}
}
+ /*
+ * When setting ACLs and missing one out of SMB_ACL_USER_OBJ,
+ * SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER, try to retrieve current
+ * values. For user and other a simple vfs_stat would do, but
+ * we would get mask instead of group. Let's do it via ACL.
+ */
+
+ if (setting_acl && (!got_user || !got_grp || !got_other)) {
+
+ SMB_ACL_ENTRY_T entry;
+ int entry_id = SMB_ACL_FIRST_ENTRY;
+
+ if(fsp->is_directory || fsp->fd == -1) {
+ current_posix_acl = conn->vfs_ops.sys_acl_get_file(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
+ } else {
+ current_posix_acl = conn->vfs_ops.sys_acl_get_fd(fsp, fsp->fd);
+ }
+
+ if (current_posix_acl) {
+ while (conn->vfs_ops.sys_acl_get_entry(conn, current_posix_acl, entry_id, &entry) == 1) {
+ SMB_ACL_TAG_T tagtype;
+ SMB_ACL_PERMSET_T permset;
+
+ /* get_next... */
+ if (entry_id == SMB_ACL_FIRST_ENTRY)
+ entry_id = SMB_ACL_NEXT_ENTRY;
+
+ /* Is this a MASK entry ? */
+ if (conn->vfs_ops.sys_acl_get_tag_type(conn, entry, &tagtype) == -1)
+ continue;
+
+ if (conn->vfs_ops.sys_acl_get_permset(conn, entry, &permset) == -1)
+ continue;
+
+ switch(tagtype) {
+ case SMB_ACL_USER_OBJ:
+ current_user_perms = convert_permset_to_mode_t(conn, permset);
+ got_current_user = True;
+ break;
+ case SMB_ACL_GROUP_OBJ:
+ current_grp_perms = convert_permset_to_mode_t(conn, permset);
+ got_current_grp = True;
+ break;
+ case SMB_ACL_OTHER:
+ current_other_perms = convert_permset_to_mode_t(conn, permset);
+ got_current_other = True;
+ break;
+ }
+ }
+ conn->vfs_ops.sys_acl_free_acl(conn, current_posix_acl);
+ } else {
+ DEBUG(10,("ensure_canon_entry_valid: failed to retrieve current ACL of %s\n",
+ fsp->fsp_name));
+ }
+ }
+
if (!got_user) {
if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
@@ -646,13 +716,19 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->attr = ALLOW_ACE;
if (setting_acl) {
- /* If we only got an "everyone" perm, just use that. */
- if (!got_grp && got_other)
- pace->perms = pace_other->perms;
- else if (got_grp && uid_entry_in_group(pace, pace_group))
- pace->perms = pace_group->perms;
- else
- pace->perms = 0;
+ if (got_current_user) {
+ pace->perms = current_user_perms;
+ } else {
+ /* If we only got an "everyone" perm, just use that. */
+ if (!got_grp && got_other)
+ pace->perms = pace_other->perms;
+ else if (got_grp && uid_entry_in_group(pace, pace_group))
+ pace->perms = pace_group->perms;
+ else
+ pace->perms = 0;
+
+ }
+
apply_default_perms(fsp, pace, S_IRUSR);
} else {
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
@@ -674,11 +750,15 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->trustee = *pfile_grp_sid;
pace->attr = ALLOW_ACE;
if (setting_acl) {
- /* If we only got an "everyone" perm, just use that. */
- if (got_other)
- pace->perms = pace_other->perms;
- else
- pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ if (got_current_grp) {
+ pace->perms = current_grp_perms;
+ } else {
+ /* If we only got an "everyone" perm, just use that. */
+ if (got_other)
+ pace->perms = pace_other->perms;
+ else
+ pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+ }
apply_default_perms(fsp, pace, S_IRGRP);
} else {
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
@@ -700,7 +780,10 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
pace->trustee = global_sid_World;
pace->attr = ALLOW_ACE;
if (setting_acl) {
- pace->perms = 0;
+ if (got_current_other)
+ pace->perms = current_other_perms;
+ else
+ pace->perms = 0;
apply_default_perms(fsp, pace, S_IROTH);
} else
pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
@@ -1734,6 +1817,11 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
BOOL needs_mask = False;
mode_t mask_perms = 0;
+#if defined(POSIX_ACL_NEEDS_MASK)
+ /* HP-UX always wants to have a mask (called "class" there). */
+ needs_mask = True;
+#endif
+
if (the_acl == NULL) {
if (errno != ENOSYS) {
@@ -1748,6 +1836,13 @@ static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL defau
return False;
}
+ if( DEBUGLVL( 10 )) {
+ dbgtext("set_canon_ace_list: setting ACL:\n");
+ for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
+ print_canon_ace( p_ace, i);
+ }
+ }
+
for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
SMB_ACL_ENTRY_T the_entry;
SMB_ACL_PERMSET_T the_permset;
@@ -2460,6 +2555,8 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
mode_t orig_mode = (mode_t)0;
uid_t orig_uid;
gid_t orig_gid;
+ BOOL need_chown = False;
+ extern struct current_user current_user;
DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
@@ -2496,7 +2593,15 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
* Do we need to chown ?
*/
- if((user != (uid_t)-1 || grp != (uid_t)-1) && (orig_uid != user || orig_gid != grp)) {
+ need_chown = (user != (uid_t)-1 && orig_uid != user || grp != (uid_t)-1 && orig_gid != grp);
+
+ /*
+ * Chown before setting ACL only if we don't change the user, or
+ * if we change to the current user, but not if we want to give away
+ * the file.
+ */
+
+ if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
@@ -2533,6 +2638,9 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
orig_mode = sbuf.st_mode;
orig_uid = sbuf.st_uid;
orig_gid = sbuf.st_gid;
+
+ /* We did it, don't try again */
+ need_chown = False;
}
create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
@@ -2540,97 +2648,110 @@ BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
&file_ace_list, &dir_ace_list, security_info_sent, psd);
- if ((file_ace_list == NULL) && (dir_ace_list == NULL)) {
- /* W2K traverse DACL set - ignore. */
- return True;
- }
-
- if (!acl_perms) {
- DEBUG(3,("set_nt_acl: cannot set permissions\n"));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return False;
- }
+ /* Ignore W2K traverse DACL set. */
+ if (file_ace_list || dir_ace_list) {
- /*
- * Only change security if we got a DACL.
- */
-
- if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
-
- BOOL acl_set_support = False;
- BOOL ret = False;
+ if (!acl_perms) {
+ DEBUG(3,("set_nt_acl: cannot set permissions\n"));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
/*
- * Try using the POSIX ACL set first. Fall back to chmod if
- * we have no ACL support on this filesystem.
+ * Only change security if we got a DACL.
*/
- if (acl_perms && file_ace_list) {
- ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
- if (acl_set_support && ret == False) {
- DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return False;
- }
- }
+ if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
- if (acl_perms && acl_set_support && fsp->is_directory) {
- if (dir_ace_list) {
- if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
- DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return False;
- }
- } else {
+ BOOL acl_set_support = False;
+ BOOL ret = False;
- /*
- * No default ACL - delete one if it exists.
- */
+ /*
+ * Try using the POSIX ACL set first. Fall back to chmod if
+ * we have no ACL support on this filesystem.
+ */
- if (conn->vfs_ops.sys_acl_delete_def_file(conn, fsp->fsp_name) == -1) {
- DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
+ if (acl_perms && file_ace_list) {
+ ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
+ if (acl_set_support && ret == False) {
+ DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
return False;
}
}
- }
- /*
- * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
- */
+ if (acl_perms && acl_set_support && fsp->is_directory) {
+ if (dir_ace_list) {
+ if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
+ DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
+ } else {
- if(!acl_set_support && acl_perms) {
- mode_t posix_perms;
+ /*
+ * No default ACL - delete one if it exists.
+ */
- if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
- fsp->fsp_name ));
- return False;
+ if (conn->vfs_ops.sys_acl_delete_def_file(conn, fsp->fsp_name) == -1) {
+ DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
+ }
}
- if (orig_mode != posix_perms) {
+ /*
+ * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
+ */
- DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
- fsp->fsp_name, (unsigned int)posix_perms ));
+ if(!acl_set_support && acl_perms) {
+ mode_t posix_perms;
- if(conn->vfs_ops.chmod(conn,fsp->fsp_name, posix_perms) == -1) {
- DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
- fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
+ if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
free_canon_ace_list(file_ace_list);
free_canon_ace_list(dir_ace_list);
+ DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
+ fsp->fsp_name ));
return False;
}
+
+ if (orig_mode != posix_perms) {
+
+ DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
+ fsp->fsp_name, (unsigned int)posix_perms ));
+
+ if(conn->vfs_ops.chmod(conn,fsp->fsp_name, posix_perms) == -1) {
+ DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return False;
+ }
+ }
}
}
+
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
}
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
+ /* Any chown pending? */
+ if (need_chown) {
+
+ DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+
+ if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
+ DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+ return False;
+ }
+ }
return True;
}