diff options
-rw-r--r-- | source3/lib/sysacls.c | 75 |
1 files changed, 56 insertions, 19 deletions
diff --git a/source3/lib/sysacls.c b/source3/lib/sysacls.c index cc0c70aa3e..0079c1323a 100644 --- a/source3/lib/sysacls.c +++ b/source3/lib/sysacls.c @@ -655,15 +655,38 @@ int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d) return 0; } -int sys_acl_valid(SMB_ACL_T acl_d) +/* + * sort the ACL and check it for validity + * + * if it's a minimal ACL with only 4 entries then we + * need to recalculate the mask permissions to make + * sure that they are the same as the GROUP_OBJ + * permissions as required by the UnixWare acl() system call. + * + * (note: since POSIX allows minimal ACLs which only contain + * 3 entries - ie there is no mask entry - we should, in theory, + * check for this and add a mask entry if necessary - however + * we "know" that the caller of this interface always specifies + * a mask so, in practice "this never happens" (tm) - if it *does* + * happen aclsort() will fail and return an error and someone will + * have to fix it ...) + */ + +static int acl_sort(SMB_ACL_T acl_d) { - if (aclsort(acl_d->count, 1, acl_d->acl) != 0) { + int fixmask = (acl_d->count <= 4); + + if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) { errno = EINVAL; return -1; } - return 0; } + +int sys_acl_valid(SMB_ACL_T acl_d) +{ + return acl_sort(acl_d); +} int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) { @@ -678,7 +701,7 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) return -1; } - if (stat(name, &s) != 0) { + if (acl_sort(acl_d) != 0) { return -1; } @@ -690,6 +713,9 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) * since the acl() system call will replace both * the access ACLs and the default ACLs (if any) */ + if (stat(name, &s) != 0) { + return -1; + } if (S_ISDIR(s.st_mode)) { SMB_ACL_T acc_acl; SMB_ACL_T def_acl; @@ -698,13 +724,11 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) if (type == SMB_ACL_TYPE_ACCESS) { acc_acl = acl_d; - def_acl = - tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); + def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); } else { def_acl = acl_d; - acc_acl = - tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); + acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); } if (tmp_acl == NULL) { @@ -714,9 +738,8 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) /* * allocate a temporary buffer for the complete ACL */ - acl_count = acc_acl->count + def_acl->count; - acl_p = - acl_buf = malloc(acl_count * sizeof(acl_buf[0])); + acl_count = acc_acl->count + def_acl->count; + acl_p = acl_buf = malloc(acl_count * sizeof(acl_buf[0])); if (acl_buf == NULL) { sys_acl_free_acl(tmp_acl); @@ -747,12 +770,7 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) return -1; } - if (aclsort(acl_count, 1, acl_p) != 0) { - errno = EINVAL; - ret = -1; - } else { - ret = acl(name, SETACL, acl_count, acl_p); - } + ret = acl(name, SETACL, acl_count, acl_p); if (acl_buf) { free(acl_buf); @@ -763,14 +781,33 @@ int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) { - if (aclsort(acl_d->count, 1, acl_d->acl) != 0) { - errno = EINVAL; + if (acl_sort(acl_d) { return -1; } return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]); } +int sys_acl_delete_def_file(const char *path) +{ + SMB_ACL_T acl_d; + int ret; + + /* + * fetching the access ACL and rewriting it has + * the effect of deleting the default ACL + */ + if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) { + return -1; + } + + ret = acl(path, SETACL, acl_d->count, acl_d->acl); + + sys_acl_free_acl(acl_d); + + return ret; +} + int sys_acl_free_text(char *text) { free(text); |