posix_acls.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 2,170 行 · 第 1/5 页
C
2,170 行
for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { mode_t new_perms = (mode_t)0; canon_ace *allow_ace_p; canon_ace *tmp_ace; curr_ace_next = curr_ace->next; /* So we can't lose the link. */ if (curr_ace->attr != DENY_ACE) continue; if (curr_ace->owner_type != UID_ACE) continue; if (curr_ace->perms == ALL_ACE_PERMS) { /* * Optimisation - this is a deny everything to this user. * Convert to an allow nothing and push to the end of the list. */ curr_ace->attr = ALLOW_ACE; curr_ace->perms = (mode_t)0; DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); continue; } for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { if (allow_ace_p->attr != ALLOW_ACE) continue; /* We process GID_ACE and WORLD_ACE entries only. */ if (allow_ace_p->owner_type == UID_ACE) continue; if (uid_entry_in_group( curr_ace, allow_ace_p)) new_perms |= allow_ace_p->perms; } /* * Convert to a allow entry, modify the perms and push to the end * of the list. */ curr_ace->attr = ALLOW_ACE; curr_ace->perms = (new_perms & ~curr_ace->perms); DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); } /* Pass 3 above - deal with deny group entries. */ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { canon_ace *tmp_ace; canon_ace *allow_ace_p; canon_ace *allow_everyone_p = NULL; curr_ace_next = curr_ace->next; /* So we can't lose the link. */ if (curr_ace->attr != DENY_ACE) continue; if (curr_ace->owner_type != GID_ACE) continue; for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) { if (allow_ace_p->attr != ALLOW_ACE) continue; /* Store a pointer to the Everyone allow, if it exists. */ if (allow_ace_p->owner_type == WORLD_ACE) allow_everyone_p = allow_ace_p; /* We process UID_ACE entries only. */ if (allow_ace_p->owner_type != UID_ACE) continue; /* Mask off the deny group perms. */ if (uid_entry_in_group( allow_ace_p, curr_ace)) allow_ace_p->perms &= ~curr_ace->perms; } /* * Convert the deny to an allow with the correct perms and * push to the end of the list. */ curr_ace->attr = ALLOW_ACE; if (allow_everyone_p) curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms; else curr_ace->perms = (mode_t)0; DLIST_DEMOTE(ace_list, curr_ace, tmp_ace); } /* Doing this fourth pass allows Windows semantics to be layered * on top of POSIX semantics. I'm not sure if this is desirable. * For example, in W2K ACLs there is no way to say, "Group X no * access, user Y full access" if user Y is a member of group X. * This seems completely broken semantics to me.... JRA. */#if 0 /* Pass 4 above - deal with allow entries. */ for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) { canon_ace *allow_ace_p; curr_ace_next = curr_ace->next; /* So we can't lose the link. */ if (curr_ace->attr != ALLOW_ACE) continue; if (curr_ace->owner_type != UID_ACE) continue; for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) { if (allow_ace_p->attr != ALLOW_ACE) continue; /* We process GID_ACE entries only. */ if (allow_ace_p->owner_type != GID_ACE) continue; /* OR in the group perms. */ if (uid_entry_in_group( curr_ace, allow_ace_p)) curr_ace->perms |= allow_ace_p->perms; } }#endif *pp_ace_list = ace_list;}/**************************************************************************** Create a default mode that will be used if a security descriptor entry has no user/group/world entries.****************************************************************************/static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode){ int snum = SNUM(fsp->conn); mode_t and_bits = (mode_t)0; mode_t or_bits = (mode_t)0; mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, False) : S_IRUSR; if (fsp->is_directory) mode |= (S_IWUSR|S_IXUSR); /* * Now AND with the create mode/directory mode bits then OR with the * force create mode/force directory mode bits. */ if (fsp->is_directory) { and_bits = lp_dir_security_mask(snum); or_bits = lp_force_dir_security_mode(snum); } else { and_bits = lp_security_mask(snum); or_bits = lp_force_security_mode(snum); } return ((mode & and_bits)|or_bits);}/**************************************************************************** Unpack a SEC_DESC into two canonical ace lists. We don't depend on this succeeding.****************************************************************************/static BOOL unpack_canon_ace(files_struct *fsp, SMB_STRUCT_STAT *pst, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid, canon_ace **ppfile_ace, canon_ace **ppdir_ace, uint32 security_info_sent, SEC_DESC *psd){ canon_ace *file_ace = NULL; canon_ace *dir_ace = NULL; *ppfile_ace = NULL; *ppdir_ace = NULL; if(security_info_sent == 0) { DEBUG(0,("unpack_canon_ace: no security info sent !\n")); return False; } /* * If no DACL then this is a chown only security descriptor. */ if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl) return True; /* * Now go through the DACL and create the canon_ace lists. */ if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid, &file_ace, &dir_ace, psd->dacl)) return False; if ((file_ace == NULL) && (dir_ace == NULL)) { /* W2K traverse DACL set - ignore. */ return True; } /* * Go through the canon_ace list and merge entries * belonging to identical users of identical allow or deny type. * We can do this as all deny entries come first, followed by * all allow entries (we have mandated this before accepting this acl). */ print_canon_ace_list( "file ace - before merge", file_ace); merge_aces( &file_ace ); print_canon_ace_list( "dir ace - before merge", dir_ace); merge_aces( &dir_ace ); /* * NT ACLs are order dependent. Go through the acl lists and * process DENY entries by masking the allow entries. */ print_canon_ace_list( "file ace - before deny", file_ace); process_deny_list( &file_ace); print_canon_ace_list( "dir ace - before deny", dir_ace); process_deny_list( &dir_ace); /* * A well formed POSIX file or default ACL has at least 3 entries, a * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ * and optionally a mask entry. Ensure this is the case. */ print_canon_ace_list( "file ace - before valid", file_ace); /* * A default 3 element mode entry for a file should be r-- --- ---. * A default 3 element mode entry for a directory should be rwx --- ---. */ pst->st_mode = create_default_mode(fsp, False); if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; } print_canon_ace_list( "dir ace - before valid", dir_ace); /* * A default inheritable 3 element mode entry for a directory should be the * mode Samba will use to create a file within. Ensure user rwx bits are set if * it's a directory. */ pst->st_mode = create_default_mode(fsp, True); if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) { free_canon_ace_list(file_ace); free_canon_ace_list(dir_ace); return False; } print_canon_ace_list( "file ace - return", file_ace); print_canon_ace_list( "dir ace - return", dir_ace); *ppfile_ace = file_ace; *ppdir_ace = dir_ace; return True;}/****************************************************************************** When returning permissions, try and fit NT display semantics if possible. Note the the canon_entries here must have been malloced. The list format should be - first entry = owner, followed by group and other user entries, last entry = other. Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries are not ordered, and match on the most specific entry rather than walking a list, then a simple POSIX permission of rw-r--r-- should really map to 5 entries, Entry 0: owner : deny all except read and write. Entry 1: owner : allow read and write. Entry 2: group : deny all except read. Entry 3: group : allow read. Entry 4: Everyone : allow read. But NT cannot display this in their ACL editor !********************************************************************************/static void arrange_posix_perms( char *filename, canon_ace **pp_list_head){ canon_ace *list_head = *pp_list_head; canon_ace *owner_ace = NULL; canon_ace *other_ace = NULL; canon_ace *ace = NULL; for (ace = list_head; ace; ace = ace->next) { if (ace->type == SMB_ACL_USER_OBJ) owner_ace = ace; else if (ace->type == SMB_ACL_OTHER) { /* Last ace - this is "other" */ other_ace = ace; } } if (!owner_ace || !other_ace) { DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n", filename )); return; } /* * The POSIX algorithm applies to owner first, and other last, * so ensure they are arranged in this order. */ if (owner_ace) { DLIST_PROMOTE(list_head, owner_ace); } if (other_ace) { DLIST_DEMOTE(list_head, other_ace, ace); } /* We have probably changed the head of the list. */ *pp_list_head = list_head;} /**************************************************************************** Create a linked list of canonical ACE entries.****************************************************************************/static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf, const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type){ connection_struct *conn = fsp->conn; mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR); canon_ace *list_head = NULL; canon_ace *ace = NULL; canon_ace *next_ace = NULL; int entry_id = SMB_ACL_FIRST_ENTRY; SMB_ACL_ENTRY_T entry; size_t ace_count; while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) { SMB_ACL_TAG_T tagtype; SMB_ACL_PERMSET_T permset; DOM_SID sid; posix_id unix_ug; enum ace_owner owner_type; /* get_next... */ if (entry_id == SMB_ACL_FIRST_ENTRY) entry_id = SMB_ACL_NEXT_ENTRY; /* Is this a MASK entry ? */ if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) continue; if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) continue; /* Decide which SID to use based on the ACL type. */ switch(tagtype) { case SMB_ACL_USER_OBJ: /* Get the SID from the owner. */ sid_copy(&sid, powner); unix_ug.uid = psbuf->st_uid; owner_type = UID_ACE; break; case SMB_ACL_USER: { uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); if (puid == NULL) { DEBUG(0,("canonicalise_acl: Failed to get uid.\n")); continue; } /* * A SMB_ACL_USER entry for the owner is shadowed by the * SMB_ACL_USER_OBJ entry and Windows also cannot represent * that entry, so we ignore it. We also don't create such * entries out of the blue when setting ACLs, so a get/set * cycle will drop them. */ if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) { SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); continue; } uid_to_sid( &sid, *puid); unix_ug.uid = *puid; owner_type = UID_ACE; SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype); break; } case SMB_ACL_GROUP_OBJ: /* Get the SID from the owning group. */ sid_copy(&sid, pgroup); unix_ug.gid = psbuf->st_gid; owner_type = GID_ACE; break; case SMB_ACL_GROUP: { gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry); if (pgid == NULL) { DEBUG(0,("canonicalise_acl: Failed to get gid.\n")); continue; } gid_to_sid( &sid, *pgid); unix_ug.gid = *pgid; owner_type = GID_ACE; SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype); break; } case SMB_ACL_MASK: acl_mask = convert_permset_to_mode_t(conn, permset); continue; /* Don't count the mask as an entry. */ case SMB_ACL_OTHER:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?