/* Unix SMB/CIFS implementation. routines for marshalling/unmarshalling security descriptors and related structures Copyright (C) Andrew Tridgell 2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" /* parse a security_ace */ NTSTATUS ndr_pull_security_ace(struct ndr_pull *ndr, struct security_ace *ace) { uint16 size; struct ndr_pull_save save; ndr_pull_save(ndr, &save); NDR_CHECK(ndr_pull_uint8(ndr, &ace->type)); NDR_CHECK(ndr_pull_uint8(ndr, &ace->flags)); NDR_CHECK(ndr_pull_uint16(ndr, &size)); NDR_CHECK(ndr_pull_limit_size(ndr, size, 4)); NDR_CHECK(ndr_pull_uint32(ndr, &ace->access_mask)); if (sec_ace_object(ace->type)) { NDR_ALLOC(ndr, ace->obj); NDR_CHECK(ndr_pull_uint32(ndr, &ace->obj->flags)); if (ace->obj->flags & SEC_ACE_OBJECT_PRESENT) { NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &ace->obj->object_guid)); } if (ace->obj->flags & SEC_ACE_OBJECT_INHERITED_PRESENT) { NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &ace->obj->inherit_guid)); } } else { ace->obj = NULL; } NDR_CHECK(ndr_pull_dom_sid(ndr, &ace->trustee)); ndr_pull_restore(ndr, &save); NDR_CHECK(ndr_pull_advance(ndr, size)); return NT_STATUS_OK; } /* parse a security_acl */ NTSTATUS ndr_pull_security_acl(struct ndr_pull *ndr, struct security_acl *acl) { int i; uint16 size; struct ndr_pull_save save; ndr_pull_save(ndr, &save); NDR_CHECK(ndr_pull_uint16(ndr, &acl->revision)); NDR_CHECK(ndr_pull_uint16(ndr, &size)); NDR_CHECK(ndr_pull_limit_size(ndr, size, 4)); NDR_CHECK(ndr_pull_uint32(ndr, &acl->num_aces)); NDR_ALLOC_N(ndr, acl->aces, acl->num_aces); for (i=0;inum_aces;i++) { NDR_CHECK(ndr_pull_security_ace(ndr, &acl->aces[i])); } ndr_pull_restore(ndr, &save); NDR_CHECK(ndr_pull_advance(ndr, size)); return NT_STATUS_OK; } /* parse a security_acl offset and structure */ NTSTATUS ndr_pull_security_acl_ofs(struct ndr_pull *ndr, struct security_acl **acl) { uint32 ofs; struct ndr_pull_save save; NDR_CHECK(ndr_pull_uint32(ndr, &ofs)); if (ofs == 0) { /* it is valid for an acl ptr to be NULL */ *acl = NULL; return NT_STATUS_OK; } ndr_pull_save(ndr, &save); NDR_CHECK(ndr_pull_set_offset(ndr, ofs)); NDR_ALLOC(ndr, *acl); NDR_CHECK(ndr_pull_security_acl(ndr, *acl)); ndr_pull_restore(ndr, &save); return NT_STATUS_OK; } /* parse a dom_sid */ NTSTATUS ndr_pull_dom_sid(struct ndr_pull *ndr, struct dom_sid *sid) { int i; NDR_CHECK(ndr_pull_uint8(ndr, &sid->sid_rev_num)); NDR_CHECK(ndr_pull_uint8(ndr, &sid->num_auths)); for (i=0;i<6;i++) { NDR_CHECK(ndr_pull_uint8(ndr, &sid->id_auth[i])); } NDR_ALLOC_N(ndr, sid->sub_auths, sid->num_auths); for (i=0;inum_auths;i++) { NDR_CHECK(ndr_pull_uint32(ndr, &sid->sub_auths[i])); } return NT_STATUS_OK; } /* parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field */ NTSTATUS ndr_pull_dom_sid2(struct ndr_pull *ndr, struct dom_sid *sid) { uint32 num_auths; NDR_CHECK(ndr_pull_uint32(ndr, &num_auths)); return ndr_pull_dom_sid(ndr, sid); } /* parse a dom_sid offset and structure */ NTSTATUS ndr_pull_dom_sid_ofs(struct ndr_pull *ndr, struct dom_sid **sid) { uint32 ofs; struct ndr_pull_save save; NDR_CHECK(ndr_pull_uint32(ndr, &ofs)); if (ofs == 0) { /* it is valid for a dom_sid ptr to be NULL */ *sid = NULL; return NT_STATUS_OK; } ndr_pull_save(ndr, &save); NDR_CHECK(ndr_pull_set_offset(ndr, ofs)); NDR_ALLOC(ndr, *sid); NDR_CHECK(ndr_pull_dom_sid(ndr, *sid)); ndr_pull_restore(ndr, &save); return NT_STATUS_OK; } /* parse a security descriptor */ NTSTATUS ndr_pull_security_descriptor(struct ndr_pull *ndr, struct security_descriptor *sd) { NDR_CHECK(ndr_pull_uint8(ndr, &sd->revision)); NDR_CHECK(ndr_pull_uint16(ndr, &sd->type)); NDR_CHECK(ndr_pull_dom_sid_ofs(ndr, &sd->owner_sid)); NDR_CHECK(ndr_pull_dom_sid_ofs(ndr, &sd->group_sid)); NDR_CHECK(ndr_pull_security_acl_ofs(ndr, &sd->sacl)); NDR_CHECK(ndr_pull_security_acl_ofs(ndr, &sd->dacl)); return NT_STATUS_OK; } /* parse a security_ace */ NTSTATUS ndr_push_security_ace(struct ndr_push *ndr, struct security_ace *ace) { struct ndr_push_save save1, save2; NDR_CHECK(ndr_push_uint8(ndr, ace->type)); NDR_CHECK(ndr_push_uint8(ndr, ace->flags)); ndr_push_save(ndr, &save1); NDR_CHECK(ndr_push_uint16(ndr, 0)); NDR_CHECK(ndr_push_uint32(ndr, ace->access_mask)); if (sec_ace_object(ace->type)) { NDR_CHECK(ndr_push_uint32(ndr, ace->obj->flags)); if (ace->obj->flags & SEC_ACE_OBJECT_PRESENT) { NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &ace->obj->object_guid)); } if (ace->obj->flags & SEC_ACE_OBJECT_INHERITED_PRESENT) { NDR_CHECK(ndr_push_GUID(ndr, NDR_SCALARS, &ace->obj->inherit_guid)); } } NDR_CHECK(ndr_push_dom_sid(ndr, &ace->trustee)); ndr_push_save(ndr, &save2); ndr_push_restore(ndr, &save1); NDR_CHECK(ndr_push_uint16(ndr, 2 + save2.offset - save1.offset)); ndr_push_restore(ndr, &save2); return NT_STATUS_OK; } /* push a security_acl */ NTSTATUS ndr_push_security_acl(struct ndr_push *ndr, struct security_acl *acl) { int i; struct ndr_push_save save1, save2; NDR_CHECK(ndr_push_uint16(ndr, acl->revision)); ndr_push_save(ndr, &save1); NDR_CHECK(ndr_push_uint16(ndr, 0)); NDR_CHECK(ndr_push_uint32(ndr, acl->num_aces)); for (i=0;inum_aces;i++) { NDR_CHECK(ndr_push_security_ace(ndr, &acl->aces[i])); } ndr_push_save(ndr, &save2); ndr_push_restore(ndr, &save1); NDR_CHECK(ndr_push_uint16(ndr, 2 + save2.offset - save1.offset)); ndr_push_restore(ndr, &save2); return NT_STATUS_OK; } /* push a dom_sid */ NTSTATUS ndr_push_dom_sid(struct ndr_push *ndr, struct dom_sid *sid) { int i; NDR_CHECK(ndr_push_uint8(ndr, sid->sid_rev_num)); NDR_CHECK(ndr_push_uint8(ndr, sid->num_auths)); for (i=0;i<6;i++) { NDR_CHECK(ndr_push_uint8(ndr, sid->id_auth[i])); } for (i=0;inum_auths;i++) { NDR_CHECK(ndr_push_uint32(ndr, sid->sub_auths[i])); } return NT_STATUS_OK; } /* parse a dom_sid2 - this is a dom_sid but with an extra copy of the num_auths field */ NTSTATUS ndr_push_dom_sid2(struct ndr_push *ndr, struct dom_sid *sid) { NDR_CHECK(ndr_push_uint32(ndr, sid->num_auths)); return ndr_push_dom_sid(ndr, sid); } /* generate a ndr security descriptor */ NTSTATUS ndr_push_security_descriptor(struct ndr_push *ndr, struct security_descriptor *sd) { struct ndr_push_save save; struct ndr_push_save ofs1, ofs2, ofs3, ofs4; ndr_push_save(ndr, &save); NDR_CHECK(ndr_push_uint8(ndr, sd->revision)); NDR_CHECK(ndr_push_uint16(ndr, sd->type)); NDR_CHECK(ndr_push_offset(ndr, &ofs1)); NDR_CHECK(ndr_push_offset(ndr, &ofs2)); NDR_CHECK(ndr_push_offset(ndr, &ofs3)); NDR_CHECK(ndr_push_offset(ndr, &ofs4)); if (sd->owner_sid) { NDR_CHECK(ndr_push_offset_ptr(ndr, &ofs1, &save)); NDR_CHECK(ndr_push_dom_sid(ndr, sd->owner_sid)); } if (sd->group_sid) { NDR_CHECK(ndr_push_offset_ptr(ndr, &ofs2, &save)); NDR_CHECK(ndr_push_dom_sid(ndr, sd->group_sid)); } if (sd->sacl) { NDR_CHECK(ndr_push_offset_ptr(ndr, &ofs3, &save)); NDR_CHECK(ndr_push_security_acl(ndr, sd->sacl)); } if (sd->dacl) { NDR_CHECK(ndr_push_offset_ptr(ndr, &ofs4, &save)); NDR_CHECK(ndr_push_security_acl(ndr, sd->dacl)); } return NT_STATUS_OK; } /* print a dom_sid */ void ndr_print_dom_sid(struct ndr_print *ndr, const char *name, struct dom_sid *sid) { int i, ofs, maxlen; uint32 ia; char *ret; if (!sid) { ndr->print(ndr, "%-25s: (NULL SID)", name); return; } maxlen = sid->num_auths * 11 + 25; ret = talloc(ndr->mem_ctx, maxlen); if (!ret) return; ia = (sid->id_auth[5]) + (sid->id_auth[4] << 8 ) + (sid->id_auth[3] << 16) + (sid->id_auth[2] << 24); ofs = snprintf(ret, maxlen, "S-%u-%lu", (unsigned int)sid->sid_rev_num, (unsigned long)ia); for (i = 0; i < sid->num_auths; i++) { ofs += snprintf(ret + ofs, maxlen - ofs, "-%lu", (unsigned long)sid->sub_auths[i]); } ndr->print(ndr, "%-25s: %s", name, ret); } void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, struct dom_sid2 *sid) { ndr_print_dom_sid(ndr, name, sid); } /* print a security_ace */ void ndr_print_security_ace(struct ndr_print *ndr, const char *name, struct security_ace *ace) { ndr_print_struct(ndr, name, "security_ace"); ndr->depth++; ndr_print_uint8(ndr, "type", ace->type); ndr_print_uint8(ndr, "flags", ace->flags); ndr_print_uint32(ndr, "access_mask", ace->access_mask); if (ace->obj) { ndr_print_struct(ndr, name, "security_ace_obj"); ndr->depth++; ndr_print_uint32(ndr, "flags", ace->obj->flags); ndr_print_GUID(ndr, "object_guid", &ace->obj->object_guid); ndr_print_GUID(ndr, "inherit_guid", &ace->obj->inherit_guid); ndr->depth--; } ndr_print_dom_sid(ndr, "trustee", &ace->trustee); ndr->depth--; } /* print a security_acl */ void ndr_print_security_acl(struct ndr_print *ndr, const char *name, struct security_acl *acl) { ndr_print_struct(ndr, name, "security_acl"); ndr->depth++; ndr_print_uint16(ndr, "revision", acl->revision); ndr_print_uint32(ndr, "num_aces", acl->num_aces); ndr_print_array(ndr, "aces", acl->aces, sizeof(acl->aces[0]), acl->num_aces, (ndr_print_fn_t) ndr_print_security_ace); ndr->depth--; } /* print a security descriptor */ void ndr_print_security_descriptor(struct ndr_print *ndr, const char *name, struct security_descriptor *sd) { ndr_print_struct(ndr, name, "security_descriptor"); ndr->depth++; ndr_print_uint8(ndr, "revision", sd->revision); ndr_print_uint16(ndr, "type", sd->type); ndr_print_ptr(ndr, "owner_sid", sd->owner_sid); if (sd->owner_sid) { ndr_print_dom_sid(ndr, "owner_sid", sd->owner_sid); } ndr_print_ptr(ndr, "group_sid", sd->group_sid); if (sd->group_sid) { ndr_print_dom_sid(ndr, "group_sid", sd->group_sid); } ndr_print_ptr(ndr, "sacl", sd->sacl); if (sd->sacl) { ndr_print_security_acl(ndr, "sacl", sd->sacl); } ndr_print_ptr(ndr, "dacl", sd->dacl); if (sd->dacl) { ndr_print_security_acl(ndr, "dacl", sd->dacl); } ndr->depth--; } /* implementation of sec_desc_buf - an encapsulated security descriptor */ NTSTATUS ndr_pull_sec_desc_buf(struct ndr_pull *ndr, int ndr_flags, struct sec_desc_buf *sdbuf) { if (ndr_flags & NDR_SCALARS) { uint32 _ptr; NDR_CHECK(ndr_pull_uint32(ndr, &sdbuf->size)); NDR_CHECK(ndr_pull_uint32(ndr, &_ptr)); if (_ptr) { NDR_ALLOC(ndr, sdbuf->sd); } else { sdbuf->sd = NULL; } } if (ndr_flags & NDR_BUFFERS) { if (sdbuf->sd) { struct ndr_pull ndr2; uint32 size; NDR_CHECK(ndr_pull_uint32(ndr, &size)); if (size != sdbuf->size) { return NT_STATUS_INFO_LENGTH_MISMATCH; } NDR_CHECK(ndr_pull_subcontext(ndr, &ndr2, sdbuf->size)); NDR_CHECK(ndr_pull_security_descriptor(&ndr2, sdbuf->sd)); NDR_CHECK(ndr_pull_advance(ndr, sdbuf->size)); } } return NT_STATUS_OK; } /* print a sec_desc_buf */ void ndr_print_sec_desc_buf(struct ndr_print *ndr, const char *name, struct sec_desc_buf *sdbuf) { ndr_print_struct(ndr, name, "sec_desc_buf"); ndr->depth++; ndr_print_uint32(ndr, "size", sdbuf->size); ndr_print_ptr(ndr, "sd", sdbuf->sd); if (sdbuf->sd) { ndr_print_security_descriptor(ndr, "sd", sdbuf->sd); } }