2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * This is a helper file to get/set Windows security descriptor. This is used by
2N/A * SRVSVC service.
2N/A *
2N/A * A security descriptor can be in either absolute or self-relative format.
2N/A * In absolute format, a security descriptor contains pointers to its
2N/A * information, not the information itself. In self-relative format, a security
2N/A * descriptor stores the security descriptor structure and associated security
2N/A * information in a contiguous block of memory.
2N/A *
2N/A * The security descriptor that the SMB server sends over the wire via
2N/A * NetrShareGetInfo is in self-relative format. The following functions
2N/A * are used in converting a security descriptor from absolute to self-relative
2N/A * format.
2N/A * - srvsvc_sd_set_relative()
2N/A * - srvsvc_acl_set_relative()
2N/A * - srvsvc_ace_set_relative()
2N/A *
2N/A * The security descriptor that is set on the SMB server via NetrShareSetInfo
2N/A * is in absolute format. The following functions are used in converting a
2N/A * security descriptor from self-relative to absolute format.
2N/A * - srvsvc_sd_set_absolute()
2N/A * - srvsvc_acl_set_absolute()
2N/A * - srvsvc_ace_set_absolute()
2N/A */
2N/A#include <strings.h>
2N/A#include <libzfs.h>
2N/A
2N/A#include <smbsrv/libsmb.h>
2N/A#include <smbsrv/libntsvcs.h>
2N/A#include <smbsrv/ndl/srvsvc.ndl>
2N/A#include "ntsvcs.h"
2N/A
2N/A/* Size of offset members in mslm_security_descriptor structure */
2N/A#define SRVSVC_SD_OFFSET_SZ 16
2N/A
2N/A#define SRVSVC_ACE_OFFSET 8
2N/A#define SRVSVC_SID_OFFSET 8
2N/A
2N/Auint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
2N/A
2N/Astatic uint32_t srvsvc_sd_get_autohome(const smb_share_t *, smb_sd_t *);
2N/Astatic uint32_t srvsvc_sd_status_to_error(uint32_t);
2N/Astatic uint32_t srvsvc_sd_set_absolute(uint8_t *, smb_sd_t *);
2N/A
2N/A/*
2N/A * This method sets Security Descriptor on a share path.
2N/A *
2N/A * Returns:
2N/A * ERROR_SUCCESS
2N/A * ERROR_NOT_ENOUGH_MEMORY
2N/A * ERROR_INVALID_ACL
2N/A * ERROR_INVALID_SID
2N/A * ERROR_INVALID_SECURITY_DESCR
2N/A * ERROR_NONE_MAPPED
2N/A * ERROR_INTERNAL_ERROR
2N/A * ERROR_PATH_NOT_FOUND
2N/A */
2N/Auint32_t
2N/Asrvsvc_sd_set(smb_share_t *si, uint8_t *sdbuf)
2N/A{
2N/A smb_sd_t sd;
2N/A uint32_t status;
2N/A
2N/A smb_sd_init(&sd, 0);
2N/A status = srvsvc_sd_set_absolute(sdbuf, &sd);
2N/A if (status != ERROR_SUCCESS) {
2N/A smb_sd_term(&sd);
2N/A return (status);
2N/A }
2N/A
2N/A status = smb_sd_write(si, &sd, SMB_DACL_SECINFO);
2N/A status = srvsvc_sd_status_to_error(status);
2N/A smb_sd_term(&sd);
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * This method returns a Security Descriptor of a share path in self relative
2N/A * format. Call to this function with NULL buffer, returns the size of the
2N/A * security descriptor, which can be used to allocate buffer.
2N/A *
2N/A * Returns:
2N/A * ERROR_SUCCESS
2N/A * ERROR_NOT_ENOUGH_MEMORY
2N/A * ERROR_INVALID_ACL
2N/A * ERROR_INVALID_SID
2N/A * ERROR_INVALID_SECURITY_DESCR
2N/A * ERROR_INVALID_PARAMETER
2N/A * ERROR_NONE_MAPPED
2N/A * ERROR_INTERNAL_ERROR
2N/A * ERROR_PATH_NOT_FOUND
2N/A */
2N/Auint32_t
2N/Asrvsvc_sd_get(smb_share_t *si, uint8_t *sdbuf, uint32_t *size)
2N/A{
2N/A smb_sd_t sd;
2N/A uint32_t status = ERROR_SUCCESS;
2N/A
2N/A if (sdbuf == NULL && size == NULL)
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A bzero(&sd, sizeof (smb_sd_t));
2N/A
2N/A if (si->shr_flags & SMB_SHRF_AUTOHOME) {
2N/A status = srvsvc_sd_get_autohome(si, &sd);
2N/A } else {
2N/A status = smb_sd_read(si, &sd, SMB_ALL_SECINFO);
2N/A status = srvsvc_sd_status_to_error(status);
2N/A }
2N/A
2N/A if (status != ERROR_SUCCESS) {
2N/A smb_sd_term(&sd);
2N/A return (status);
2N/A }
2N/A
2N/A if (sdbuf == NULL) {
2N/A *size = smb_sd_len(&sd, SMB_ALL_SECINFO);
2N/A smb_sd_term(&sd);
2N/A return (status);
2N/A }
2N/A
2N/A status = srvsvc_sd_set_relative(&sd, sdbuf);
2N/A
2N/A smb_sd_term(&sd);
2N/A return (status);
2N/A}
2N/A
2N/Astatic uint32_t
2N/Asrvsvc_sd_get_autohome(const smb_share_t *si, smb_sd_t *sd)
2N/A{
2N/A smb_fssd_t fs_sd;
2N/A acl_t *acl;
2N/A uint32_t status;
2N/A
2N/A if (acl_fromtext(SMB_NTSVCS_OWNER_ALLOW_ALL_ACL, &acl) != 0)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR);
2N/A fs_sd.sd_uid = si->shr_uid;
2N/A fs_sd.sd_gid = si->shr_gid;
2N/A fs_sd.sd_zdacl = acl;
2N/A fs_sd.sd_zsacl = NULL;
2N/A
2N/A status = smb_sd_fromfs(&fs_sd, sd);
2N/A status = srvsvc_sd_status_to_error(status);
2N/A smb_fssd_term(&fs_sd);
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * This method converts an ACE from absolute (pointer) to
2N/A * self relative (flat buffer) format.
2N/A *
2N/A * Returns Win32 error codes.
2N/A */
2N/Astatic uint32_t
2N/Asrvsvc_ace_set_relative(mslm_ace_t *m_ace, struct mslm_sid *m_sid,
2N/A smb_ace_t *ace)
2N/A{
2N/A int i;
2N/A
2N/A if ((m_ace == NULL) || (ace == NULL))
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A bcopy(&ace->se_hdr, &m_ace->header, sizeof (mslm_ace_hdr_t));
2N/A m_ace->header.size = LE_IN16(&m_ace->header.size);
2N/A m_ace->mask = LE_IN32(&ace->se_mask);
2N/A
2N/A if ((ace->se_sid == NULL) || (m_sid == NULL))
2N/A return (ERROR_INVALID_PARAMETER);
2N/A bcopy(ace->se_sid, m_sid, smb_sid_len(ace->se_sid));
2N/A
2N/A assert(m_sid->sub_auth_count <= NT_SID_SUBAUTH_MAX);
2N/A for (i = 0; i < m_sid->sub_auth_count; ++i)
2N/A m_sid->sub_authority[i] = LE_IN32(&m_sid->sub_authority[i]);
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This method converts an ACL from absolute (pointer) to
2N/A * self relative (flat buffer) format.
2N/A *
2N/A * Returns an initialized mslm_acl structure on success.
2N/A * Returns NULL on failure.
2N/A */
2N/Astatic struct mslm_acl *
2N/Asrvsvc_acl_set_relative(uint8_t *sdbuf, smb_acl_t *acl)
2N/A{
2N/A struct mslm_acl *m_acl;
2N/A
2N/A if (sdbuf == NULL)
2N/A return (NULL);
2N/A
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_acl = (struct mslm_acl *)sdbuf;
2N/A m_acl->revision = acl->sl_revision;
2N/A m_acl->sbz1 = 0;
2N/A m_acl->size = LE_IN16(&acl->sl_bsize);
2N/A m_acl->sbz2 = 0;
2N/A m_acl->ace_count = LE_IN16(&acl->sl_acecnt);
2N/A
2N/A return (m_acl);
2N/A}
2N/A
2N/A/*
2N/A * This method converts Security Descriptor from absolute (pointer) to
2N/A * self relative (flat buffer) format.
2N/A *
2N/A * Returns Win32 error codes.
2N/A */
2N/Auint32_t
2N/Asrvsvc_sd_set_relative(smb_sd_t *sd, uint8_t *sdbuf)
2N/A{
2N/A mslm_security_descriptor_t *msd;
2N/A int offset, len, i;
2N/A smb_ace_t *ace;
2N/A mslm_ace_t *m_ace;
2N/A struct mslm_sid *m_sid;
2N/A uint16_t ace_cnt;
2N/A uint32_t status = ERROR_SUCCESS;
2N/A
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A msd = (mslm_security_descriptor_t *)sdbuf;
2N/A if (msd == NULL)
2N/A return (ERROR_INVALID_SECURITY_DESCR);
2N/A
2N/A msd->revision = sd->sd_revision;
2N/A msd->sbz1 = 0;
2N/A msd->control = sd->sd_control | SE_SELF_RELATIVE;
2N/A msd->control = LE_IN16(&msd->control);
2N/A
2N/A offset = sizeof (mslm_security_descriptor_t) - SRVSVC_SD_OFFSET_SZ;
2N/A msd->offset_owner = msd->offset_group = 0;
2N/A msd->offset_sacl = msd->offset_dacl = 0;
2N/A
2N/A if (sd->sd_owner != NULL) {
2N/A msd->offset_owner = LE_IN32(&offset);
2N/A
2N/A if (sd->sd_owner == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A len = smb_sid_len(sd->sd_owner);
2N/A bcopy(sd->sd_owner, &sdbuf[offset], len);
2N/A offset += len;
2N/A }
2N/A
2N/A if (sd->sd_group != NULL) {
2N/A msd->offset_group = LE_IN32(&offset);
2N/A
2N/A if (sd->sd_group == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A len = smb_sid_len(sd->sd_group);
2N/A bcopy(sd->sd_group, &sdbuf[offset], len);
2N/A offset += len;
2N/A }
2N/A
2N/A if (sd->sd_sacl != NULL) {
2N/A msd->offset_sacl = LE_IN32(&offset);
2N/A msd->sacl = srvsvc_acl_set_relative(&sdbuf[offset],
2N/A sd->sd_sacl);
2N/A if (msd->sacl == NULL)
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A ace = sd->sd_sacl->sl_aces;
2N/A ace_cnt = sd->sd_sacl->sl_acecnt;
2N/A
2N/A offset += SRVSVC_ACE_OFFSET;
2N/A
2N/A for (i = 0; i < ace_cnt; i++, ace++) {
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_ace = (mslm_ace_t *)&sdbuf[offset];
2N/A offset += SRVSVC_SID_OFFSET;
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_sid = (struct mslm_sid *)&sdbuf[offset];
2N/A
2N/A status = srvsvc_ace_set_relative(m_ace, m_sid, ace);
2N/A if (status != ERROR_SUCCESS)
2N/A return (status);
2N/A offset += smb_sid_len(ace->se_sid);
2N/A }
2N/A }
2N/A
2N/A if (sd->sd_dacl != NULL) {
2N/A msd->offset_dacl = LE_IN32(&offset);
2N/A msd->dacl = srvsvc_acl_set_relative(&sdbuf[offset],
2N/A sd->sd_dacl);
2N/A if (msd->dacl == NULL)
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A ace = sd->sd_dacl->sl_aces;
2N/A ace_cnt = sd->sd_dacl->sl_acecnt;
2N/A
2N/A offset += SRVSVC_ACE_OFFSET;
2N/A
2N/A for (i = 0; i < ace_cnt; i++, ace++) {
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_ace = (mslm_ace_t *)&sdbuf[offset];
2N/A offset += SRVSVC_SID_OFFSET;
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_sid = (struct mslm_sid *)&sdbuf[offset];
2N/A
2N/A status = srvsvc_ace_set_relative(m_ace, m_sid, ace);
2N/A if (status != ERROR_SUCCESS)
2N/A return (status);
2N/A offset += smb_sid_len(ace->se_sid);
2N/A }
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * This method converts an ACE from self relative (flat buffer) to
2N/A * absolute (pointer) format.
2N/A *
2N/A * Returns Win32 error codes.
2N/A */
2N/Astatic uint32_t
2N/Asrvsvc_ace_set_absolute(mslm_ace_t *m_ace, struct mslm_sid *m_sid,
2N/A smb_ace_t *ace)
2N/A{
2N/A int sid_size = 0;
2N/A int i;
2N/A smb_sid_t *smb_sid;
2N/A
2N/A if ((m_ace == NULL) || (ace == NULL) || (m_sid == NULL))
2N/A return (ERROR_INVALID_PARAMETER);
2N/A
2N/A bzero(ace, sizeof (smb_ace_t));
2N/A bcopy(&m_ace->header, &ace->se_hdr, sizeof (mslm_ace_hdr_t));
2N/A ace->se_hdr.se_bsize = LE_IN16(&ace->se_hdr.se_bsize);
2N/A ace->se_mask = LE_IN32(&m_ace->mask);
2N/A
2N/A sid_size = smb_sid_len((smb_sid_t *)m_sid);
2N/A if ((ace->se_sid = malloc(sid_size)) == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A bcopy(m_sid, ace->se_sid, sid_size);
2N/A
2N/A smb_sid = ace->se_sid;
2N/A if (smb_sid->sid_subauthcnt > NT_SID_SUBAUTH_MAX)
2N/A return (ERROR_INVALID_SID);
2N/A
2N/A for (i = 0; i < smb_sid->sid_subauthcnt; ++i)
2N/A smb_sid->sid_subauth[i] = LE_IN32(&smb_sid->sid_subauth[i]);
2N/A
2N/A return (ERROR_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * This method converts an ACL from self relative (flat buffer) to
2N/A * absolute (pointer) format.
2N/A *
2N/A * Returns an initialized smb_acl_t structure on success.
2N/A * Returns NULL on failure.
2N/A */
2N/Astatic smb_acl_t *
2N/Asrvsvc_acl_set_absolute(uint8_t *sdbuf, int *offset)
2N/A{
2N/A uint8_t rev;
2N/A uint16_t sz, ace_cnt;
2N/A smb_acl_t *acl;
2N/A
2N/A bcopy(&sdbuf[*offset], &rev, sizeof (uint8_t));
2N/A *offset += 2; /* Pad for Sbz1 */
2N/A bcopy(&sdbuf[*offset], &sz, sizeof (uint16_t));
2N/A sz = LE_IN16(&sz);
2N/A *offset += 2;
2N/A bcopy(&sdbuf[*offset], &ace_cnt, sizeof (uint16_t));
2N/A ace_cnt = LE_IN16(&ace_cnt);
2N/A *offset += 4; /* Pad for Sbz2 */
2N/A
2N/A acl = smb_acl_alloc(rev, sz, ace_cnt);
2N/A
2N/A return (acl);
2N/A}
2N/A
2N/A/*
2N/A * This method converts Security Descriptor from self relative (flat buffer) to
2N/A * absolute (pointer) format.
2N/A *
2N/A * Returns Win32 error codes.
2N/A */
2N/Astatic uint32_t
2N/Asrvsvc_sd_set_absolute(uint8_t *sdbuf, smb_sd_t *sd)
2N/A{
2N/A mslm_security_descriptor_t *msd;
2N/A mslm_ace_t *m_ace;
2N/A struct mslm_sid *m_sid;
2N/A smb_ace_t *ace;
2N/A uint16_t ace_cnt;
2N/A int offset, i, sid_size;
2N/A uint32_t status = ERROR_SUCCESS;
2N/A uint32_t be_off_owner, be_off_grp;
2N/A
2N/A if (sdbuf == NULL)
2N/A return (ERROR_INVALID_SECURITY_DESCR);
2N/A
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A msd = (mslm_security_descriptor_t *)sdbuf;
2N/A
2N/A sd->sd_revision = msd->revision;
2N/A sd->sd_control = msd->control & (~SE_SELF_RELATIVE);
2N/A sd->sd_control = LE_IN16(&sd->sd_control);
2N/A
2N/A if (msd->offset_owner != 0) {
2N/A be_off_owner = LE_IN32(&msd->offset_owner);
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_sid = (struct mslm_sid *)&sdbuf[be_off_owner];
2N/A sid_size = smb_sid_len((smb_sid_t *)m_sid);
2N/A
2N/A if ((sd->sd_owner = malloc(sid_size)) == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A bcopy(m_sid, sd->sd_owner, sid_size);
2N/A }
2N/A
2N/A if (msd->offset_group != 0) {
2N/A be_off_grp = LE_IN32(&msd->offset_group);
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_sid = (struct mslm_sid *)&sdbuf[be_off_grp];
2N/A sid_size = smb_sid_len((smb_sid_t *)m_sid);
2N/A
2N/A if ((sd->sd_group = malloc(sid_size)) == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A bcopy(m_sid, sd->sd_group, sid_size);
2N/A }
2N/A
2N/A if (msd->offset_sacl != 0) {
2N/A offset = msd->offset_sacl;
2N/A offset = LE_IN32(&offset);
2N/A sd->sd_sacl = srvsvc_acl_set_absolute(sdbuf, &offset);
2N/A if (sd->sd_sacl == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A ace = sd->sd_sacl->sl_aces;
2N/A ace_cnt = sd->sd_sacl->sl_acecnt;
2N/A
2N/A for (i = 0; i < ace_cnt; i++, ace++) {
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_ace = (mslm_ace_t *)&sdbuf[offset];
2N/A offset += SRVSVC_SID_OFFSET;
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_sid = (struct mslm_sid *)&sdbuf[offset];
2N/A
2N/A status = srvsvc_ace_set_absolute(m_ace, m_sid, ace);
2N/A if (status != ERROR_SUCCESS)
2N/A return (status);
2N/A offset += smb_sid_len(ace->se_sid);
2N/A }
2N/A }
2N/A
2N/A if (msd->offset_dacl != 0) {
2N/A offset = msd->offset_dacl;
2N/A offset = LE_IN32(&offset);
2N/A sd->sd_dacl = srvsvc_acl_set_absolute(sdbuf, &offset);
2N/A if (sd->sd_dacl == NULL)
2N/A return (ERROR_NOT_ENOUGH_MEMORY);
2N/A
2N/A ace = sd->sd_dacl->sl_aces;
2N/A ace_cnt = sd->sd_dacl->sl_acecnt;
2N/A for (i = 0; i < ace_cnt; i++, ace++) {
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_ace = (mslm_ace_t *)&sdbuf[offset];
2N/A offset += SRVSVC_SID_OFFSET;
2N/A /*LINTED E_BAD_PTR_CAST_ALIGN*/
2N/A m_sid = (struct mslm_sid *)&sdbuf[offset];
2N/A
2N/A status = srvsvc_ace_set_absolute(m_ace, m_sid, ace);
2N/A if (status != ERROR_SUCCESS)
2N/A return (status);
2N/A offset += smb_sid_len(ace->se_sid);
2N/A }
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * This method maps NT status codes into Win 32 error codes.
2N/A * This method operates on status codes that are related
2N/A * to processing of Security Descriptor.
2N/A */
2N/Astatic uint32_t
2N/Asrvsvc_sd_status_to_error(uint32_t status)
2N/A{
2N/A int i;
2N/A static struct {
2N/A uint32_t nt_status;
2N/A uint32_t err_code;
2N/A } errmap[] = {
2N/A { NT_STATUS_SUCCESS, ERROR_SUCCESS },
2N/A { NT_STATUS_OBJECT_PATH_NOT_FOUND, ERROR_PATH_NOT_FOUND },
2N/A { NT_STATUS_INVALID_ACL, ERROR_INVALID_ACL },
2N/A { NT_STATUS_INVALID_SID, ERROR_INVALID_SID },
2N/A { NT_STATUS_NONE_MAPPED, ERROR_NONE_MAPPED }
2N/A };
2N/A
2N/A for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
2N/A if (status == errmap[i].nt_status)
2N/A return (errmap[i].err_code);
2N/A }
2N/A
2N/A return (ERROR_PATH_NOT_FOUND);
2N/A}