/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* ACL conversion support for smbfs
*/
#include <sys/byteorder.h>
#ifdef _KERNEL
#else /* _KERNEL */
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <idmap.h>
#endif /* _KERNEL */
#include "smbfs_ntacl.h"
#ifdef _KERNEL
#else /* _KERNEL */
#ifndef lint
#else /* lint */
/* ARGSUSED */
static void
{
free(p);
}
#endif /* lint */
#endif /* _KERNEL */
/*
* Security IDentifier (SID)
*/
static void
{
return;
}
static int
{
int error, i;
return (error);
return (error);
return (ENOMEM);
for (i = 0; i < subauthcount; i++) {
subauthp++;
}
/* Success! */
return (0);
return (error);
}
static int
{
int error, i;
return (EINVAL);
for (i = 0; i < sid->sid_subauthcount; i++) {
subauthp++;
}
/* Success! */
return (0);
return (error);
}
/*
* Access Control Entry (ACE)
*/
static void
{
return;
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
break;
/* other types todo */
default:
break;
}
}
static int
{
int error;
/*
* The ACE is realy variable length,
* with format determined by the type.
*
* There may also be padding after it, so
* decode it using a copy of the mdchain,
* and then consume the specified length.
*/
/* Fixed-size ACE header */
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
alloc_size = sizeof (i_ntace_v2_t);
return (ENOMEM);
/* ACE header */
/* Type-specific data. */
break;
/* other types todo */
default:
goto errout;
}
/* Now actually consume ace_hdr.ace_size */
/* Success! */
return (0);
return (error);
}
static int
{
return (EINVAL);
/*
* Put the (fixed-size) ACE header
* Will fill in the length later.
*/
goto errout;
}
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case SYSTEM_AUDIT_ACE_TYPE:
case SYSTEM_ALARM_ACE_TYPE:
/* Put type-specific data. */
break;
/* other types todo */
default:
goto errout;
}
/* Fill in the (OtW) ACE length. */
/* Success! */
return (0);
return (error);
}
/*
* Access Control List (ACL)
*/
/* Not an OTW structure, so size can be at our convenience. */
static void
{
int i;
return;
for (i = 0; i < acl->acl_acecount; i++) {
acep++;
}
}
static int
{
int i, error;
return (error);
return (error);
return (error);
return (error);
return (error);
return (ENOMEM);
for (i = 0; i < acl->acl_acecount; i++) {
acep++;
}
/*
* There may be more data here, but
* the caller takes care of that.
*/
/* Success! */
return (0);
return (error);
}
static int
{
goto errout;
}
for (i = 0; i < acl->acl_acecount; i++) {
acep++;
}
/* Fill in acl_len_p */
/* Success! */
return (0);
return (error);
}
/*
* Security Descriptor
*/
void
{
return;
}
/*
* Import a raw SD (mb chain) into "internal" form.
* (like "absolute" form per. NT docs)
* Returns allocated data in sdp
*
* Note: does NOT consume all the mdp data, so the
* caller has to take care of that if necessary.
*/
int
{
int error;
return (ENOMEM);
/*
* Offsets below are relative to this point,
* so save the mdp state for use below.
*/
/*
* The SD is "self-relative" on the wire,
* but not after this decodes it.
*/
/*
* For each section make a temporary copy of the
* top_md state, advance to the given offset, and
* pass that to the lower md_get_xxx functions.
* These could be marshalled in any order, but
* are normally found in the order shown here.
*/
if (sacloff) {
}
if (dacloff) {
}
if (owneroff) {
}
if (groupoff) {
}
/* Success! */
return (0);
return (error);
}
/*
* Export an "internal" SD into an raw SD (mb chain).
* (a.k.a "self-relative" form per. NT docs)
* Returns allocated mbchain in mbp.
*/
int
{
/* The SD is "self-relative" on the wire. */
goto errout;
}
/*
* These could be marshalled in any order, but
* are normally found in the order shown here.
*/
}
}
}
}
/* Fill in the offsets */
/* Success! */
return (0);
return (error);
}
/*
* ================================================================
* Support for ACL fetch, including conversions
* from Windows ACLs to NFSv4-style ACLs.
* ================================================================
*/
#define GENERIC_RIGHTS_MASK \
/*
* Table for converting NT GENERIC_RIGHT_... to specific rights
* appropriate for objects of type file.
*/
struct gen2fsr {
};
static const struct gen2fsr
smbfs_gen2fsr[] = {
{
{
{
{
{ 0, 0 }
};
/*
* Table for translating ZFS ACE flags to NT ACE flags.
* The low four bits are the same, but not others.
*/
struct zaf2naf {
};
static const struct zaf2naf
smbfs_zaf2naf[] = {
{ 0, 0 }
};
/*
* Convert an NT SID to a string. Optionally return the
* last sub-authority (or "relative ID" -- RID) in *ridp
* and truncate the output string after the domain part.
* If ridp==NULL, the output string is the whole SID,
* including both the domain and RID.
*
* Return length written, or -1 on error.
*/
int
{
char *s = obuf;
uint_t i, n;
if (n > osz)
return (-1);
s += n; osz -= n;
for (i = 0; i < 6; i++)
if (n > osz)
return (-1);
s += n; osz -= n;
return (-1);
if (ridp)
subs--;
if (n > osz)
return (-1);
s += n; osz -= n;
}
if (ridp)
/* LINTED E_PTRDIFF_OVERFLOW */
return (s - obuf);
}
/*
* Our interface to the idmap service.
*
* The idmap API is _almost_ the same between
* kernel and user-level. But not quite...
* Hope this improves readability below.
*/
#ifdef _KERNEL
#else /* _KERNEL */
#endif /* _KERNEL */
/*
* The idmap request types, chosen so they also
* match the values returned in mi_isuser.
*/
#define IDM_TYPE_GROUP 0
/*
* A sentinel value for mi_isuser (below) to indicate
* that the SID is the well-known "Everyone" (S-1-1-0).
* The idmap library only uses -1, 0, 1, so this value
* is arbitrary but must not overlap w/ idmap values.
* XXX: Could use a way for idmap to tell us when
* it recognizes this well-known SID.
*/
struct mapinfo2uid {
};
/*
* Build an idmap request. Cleanup is
* handled by the caller (error or not)
*/
static int
struct mapinfo2uid *mip,
int req_type)
{
char *sid_prefix;
return (EINVAL);
sid_prefix = strbuf;
/*
* Give the "Everyone" group special treatment.
*/
/* This is "Everyone" */
return (0);
}
switch (req_type) {
case IDM_TYPE_USER:
break;
case IDM_TYPE_GROUP:
break;
case IDM_TYPE_ANY:
break;
default:
break;
}
if (idms != IDMAP_SUCCESS)
return (EINVAL);
return (0);
}
/*
* Convert an NT ACE to a ZFS ACE.
* ACE type was already validated.
*/
static void
{
/*
* Set the "ID type" flags in the ZFS ace flags.
*/
zflags = 0;
case IDM_EVERYONE:
break;
case IDM_TYPE_GROUP: /* it's a GID */
break;
default:
case IDM_TYPE_USER: /* it's a UID */
zflags = 0;
break;
}
/*
* Translate NT ACE flags to ZFS ACE flags.
*/
/*
* The "normal" access mask bits are the same, but
* if the ACE has any GENERIC_RIGHT_... convert those
* to specific rights. GENERIC bits are rarely seen,
* but reportedly can happen with inherit-only ACEs.
*/
}
/*
* Fill in the ZFS-style ACE
*/
}
/*
* Convert an internal SD to a ZFS-style ACL.
*
* This makes two passes over the SD, the first building a
* "batch" request for idmap with results in mapinfo, the
* second building a ZFS-style ACL using the idmap results.
*/
int
#ifdef _KERNEL
#else /* _KERNEL */
#endif /* _KERNEL */
{
/*
* sanity checks
*/
if (acl_info) {
#ifndef _KERNEL
return (EINVAL);
#endif /* _KERNEL */
return (EINVAL);
}
/*
* How many SID mappings will we need?
*/
mapcnt = 0;
mapcnt++;
mapcnt++;
if (mapcnt == 0) {
/*
* We have a NULL DACL, SACL, and don't
* have an owner or group, so there's no
* idmap work to do. This is very rare,
* so rather than complicate things below,
* pretend we need one mapping slot.
*/
mapcnt = 1;
}
goto errout;
}
/*
* Get an imap "batch" request handle.
*/
#ifdef _KERNEL
#else /* _KERNEL */
if (idms != IDMAP_SUCCESS) {
error = ENOTACTIVE;
goto errout;
}
#endif /* _KERNEL */
/*
* Build our request to the idmap deamon,
* getting Unix IDs for every SID.
*/
if (error)
goto errout;
mip++;
}
if (error)
goto errout;
mip++;
}
for (i = 0; i < ntacl->acl_acecount; i++) {
if (error)
goto errout;
ntacep++;
mip++;
}
}
for (i = 0; i < ntacl->acl_acecount; i++) {
if (error)
goto errout;
ntacep++;
mip++;
}
}
if (idms != IDMAP_SUCCESS) {
/* creative error choice */
goto errout;
}
}
/*
* for every Windows SID in the security descriptor.
* The remaining work is just format conversion.
*/
mip++;
}
mip++;
}
if (uidp)
if (gidp)
goto done;
}
/*
* Build the ZFS-style ACL
* First, allocate the most ZFS ACEs we'll need.
*/
zacecnt = 0;
/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
} else {
/*
* DACL is NULL or empty. Either way,
* we'll need to add a ZFS ACE below.
*/
zacecnt++;
}
goto errout;
}
for (i = 0; i < ntacl->acl_acecount; i++) {
zacep++;
ntacep++;
mip++;
}
}
/* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */
for (i = 0; i < ntacl->acl_acecount; i++) {
zacep++;
ntacep++;
mip++;
}
}
/*
* The SD has a NULL DACL. That means
* everyone@, full-control
*/
/*
* The SD has an Empty DACL. We need
* at least one ACE, so add one giving
* the owner the usual implied access.
*/
}
#ifdef _KERNEL
#else /* _KERNEL */
#endif /* _KERNEL */
done:
error = 0;
#ifdef _KERNEL
#else /* _KERNEL */
#endif /* _KERNEL */
return (error);
}
/*
* ================================================================
* Support for ACL store, including conversions
* from NFSv4-style ACLs to Windows ACLs.
* ================================================================
*/
/*
* Convert a "sid-prefix" string plus RID into an NT SID.
*
* If successful, sets *osid and returns zero,
* otherwise returns an errno value.
*/
int
{
const char *p;
char *np;
int i;
int err;
if (sid_prefix == NULL)
return (EINVAL);
p = sid_prefix;
return (EINVAL);
p += 4;
/* Parse the "authority" */
#ifdef _KERNEL
if (err != 0)
return (err);
#else /* _KERNEL */
if (p == np)
return (EINVAL);
#endif /* _KERNEL */
/*
* Count the sub-authorities. Here, np points to
* the "-" before the first sub-authority.
*/
sacnt = 0;
for (p = np; *p; p++) {
if (*p == '-')
sacnt++;
}
sacnt++;
/* Allocate the internal SID. */
return (ENOMEM);
/* Fill it in. */
for (i = 5; i >= 0; i--) {
}
sacnt--; /* Last SA not from string */
p = np;
for (i = 0; i < sacnt; i++) {
if (*p != '-') {
goto out;
}
p++;
#ifdef _KERNEL
if (err != 0)
goto out;
#else /* _KERNEL */
if (p == np) {
goto out;
}
#endif /* _KERNEL */
p = np;
}
if (*p != '\0')
goto out;
err = 0;
out:
if (err)
else
return (err);
}
/*
* The idmap API is _almost_ the same between
* kernel and user-level. But not quite...
* Hope this improves readability below.
*/
#ifdef _KERNEL
#else /* _KERNEL */
#endif /* _KERNEL */
struct mapinfo2sid {
/* Yet another kernel vs. user difference. */
#ifdef _KERNEL
#else /* _KERNEL */
char *mi_dsid;
#endif /* _KERNEL */
};
/*
* Build an idmap request. Cleanup is
* handled by the caller (error or not)
*/
static int
struct mapinfo2sid *mip,
int req_type)
{
switch (req_type) {
case IDM_TYPE_USER:
return (EINVAL);
break;
case IDM_TYPE_GROUP:
return (EINVAL);
break;
case IDM_EVERYONE:
break;
default:
break;
}
if (idms != IDMAP_SUCCESS)
return (EINVAL);
return (0);
}
/*
* Convert a ZFS ACE to an NT ACE.
* ACE type was already validated.
*/
static int
{
int error;
return (EINVAL);
}
/*
* Translate ZFS ACE flags to NT ACE flags.
*/
aflags = 0;
/*
* The access rights bits are OK as-is.
*/
/*
* Make sure we can get the SID.
* Note: allocates sid.
*/
if (error)
return (error);
/*
* Allocate the NT ACE and fill it in.
*/
alloc_size = sizeof (i_ntace_v2_t);
return (ENOMEM);
}
return (0);
}
/*
* Convert a ZFS-style ACL to an internal SD.
* Always need to pass uid+gid, either the new
* (when setting them) or existing, so that any
* owner@ or group@ ACEs can be translated.
*
* This makes two passes over the ZFS ACL. The first builds a
* "batch" request for idmap with results in mapinfo, and the
* second builds the NT SD using the idmap SID results.
*/
int
#ifdef _KERNEL
#else /* _KERNEL */
#endif /* _KERNEL */
{
int dacl_acecnt = 0;
int sacl_acecnt = 0;
int zacecnt = 0;
/*
* First, get all the UID+GID to SID mappings.
* How many? Also sanity checks.
*/
mapcnt = 0;
if (selector & OWNER_SECURITY_INFORMATION) {
return (EINVAL);
mapcnt++;
}
if (selector & GROUP_SECURITY_INFORMATION) {
return (EINVAL);
mapcnt++;
}
if (selector & (DACL_SECURITY_INFORMATION |
return (EINVAL);
return (EINVAL);
return (EINVAL);
#ifdef _KERNEL
return (EINVAL);
#else /* _KERNEL */
return (EINVAL);
#endif /* _KERNEL */
return (EINVAL);
}
if (mapcnt == 0)
return (EINVAL);
return (ENOMEM);
/* no more returns until errout */
/*
* Get an imap "batch" request handle.
*/
#ifdef _KERNEL
#else /* _KERNEL */
if (idms != IDMAP_SUCCESS) {
error = ENOTACTIVE;
goto errout;
}
#endif /* _KERNEL */
/*
* Build our request to the idmap deamon,
* Also count DACL and SACL ACEs here.
*/
if (selector & OWNER_SECURITY_INFORMATION) {
if (error)
goto errout;
mip++;
}
if (selector & GROUP_SECURITY_INFORMATION) {
if (error)
goto errout;
mip++;
}
if (selector & (DACL_SECURITY_INFORMATION |
int rqtype;
for (i = 0; i < zacecnt; i++) {
dacl_acecnt++;
break;
sacl_acecnt++;
break;
/* other types todo */
}
/* owning group (a_who = -1) */
/* owning user (a_who = -1) */
/* regular group */
} else {
}
if (error)
goto errout;
zacep++;
mip++;
}
}
if (idms != IDMAP_SUCCESS) {
/* creative error choice */
goto errout;
}
/*
* With any luck, we now have a Windows SID for
* The remaining work is just format conversion,
* memory allocation, etc.
*/
goto errout;
}
if (selector & OWNER_SECURITY_INFORMATION) {
mip++;
}
if (selector & GROUP_SECURITY_INFORMATION) {
mip++;
}
/*
* If setting both DACL and SACL, we will
* make two passes starting here in mapinfo.
*/
if (selector & DACL_SECURITY_INFORMATION) {
/*
* Caller wants to set the DACL.
*/
goto errout;
}
/* 1st pass - scan for DACL ACE types. */
for (i = 0; i < zacecnt; i++) {
if (error != 0)
goto errout;
acep++;
break;
break;
/* other types todo */
}
zacep++;
mip++;
}
}
if (selector & SACL_SECURITY_INFORMATION) {
/*
* Caller wants to set the SACL.
*/
goto errout;
}
/* 2nd pass - scan for SACL ACE types. */
for (i = 0; i < zacecnt; i++) {
break;
if (error != 0)
goto errout;
acep++;
break;
/* other types todo */
}
zacep++;
mip++;
}
}
error = 0;
if (error != 0) {
}
#ifdef _KERNEL
#else /* _KERNEL */
#endif /* _KERNEL */
return (error);
}