15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
215331Samw /*
22*12508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw */
245331Samw
255331Samw #ifndef _KERNEL
265331Samw #include <stdio.h>
275331Samw #include <strings.h>
285331Samw #include <stdlib.h>
295331Samw #include <syslog.h>
305331Samw #include <smbsrv/libsmb.h>
315331Samw #else /* _KERNEL */
325331Samw #include <sys/types.h>
335331Samw #include <sys/sunddi.h>
345331Samw #endif /* _KERNEL */
355331Samw
366432Sas200622 #include <smbsrv/smb_sid.h>
375331Samw
386432Sas200622 static smb_sid_t *smb_sid_alloc(size_t);
395331Samw
405331Samw /*
416432Sas200622 * smb_sid_isvalid
425331Samw *
436432Sas200622 * Performs a minimal SID validation.
445331Samw */
456432Sas200622 boolean_t
smb_sid_isvalid(smb_sid_t * sid)466432Sas200622 smb_sid_isvalid(smb_sid_t *sid)
475331Samw {
486432Sas200622 if (sid == NULL)
496432Sas200622 return (B_FALSE);
505331Samw
516432Sas200622 return ((sid->sid_revision == NT_SID_REVISION) &&
526432Sas200622 (sid->sid_subauthcnt < NT_SID_SUBAUTH_MAX));
535331Samw }
545331Samw
555331Samw /*
566432Sas200622 * smb_sid_len
575331Samw *
585331Samw * Returns the number of bytes required to hold the sid.
595331Samw */
605331Samw int
smb_sid_len(smb_sid_t * sid)616432Sas200622 smb_sid_len(smb_sid_t *sid)
625331Samw {
636432Sas200622 if (sid == NULL)
645331Samw return (0);
655331Samw
666432Sas200622 return (sizeof (smb_sid_t) - sizeof (uint32_t)
676432Sas200622 + (sid->sid_subauthcnt * sizeof (uint32_t)));
685331Samw }
695331Samw
705331Samw /*
716432Sas200622 * smb_sid_dup
725331Samw *
736432Sas200622 * Make a duplicate of the specified sid. The memory for the new sid
746432Sas200622 * should be freed by calling smb_sid_free().
756432Sas200622 * A pointer to the new sid is returned.
765331Samw */
776432Sas200622 smb_sid_t *
smb_sid_dup(smb_sid_t * sid)786432Sas200622 smb_sid_dup(smb_sid_t *sid)
795331Samw {
806432Sas200622 smb_sid_t *new_sid;
815331Samw int size;
825331Samw
836432Sas200622 if (sid == NULL)
846432Sas200622 return (NULL);
855331Samw
866432Sas200622 size = smb_sid_len(sid);
876432Sas200622 if ((new_sid = smb_sid_alloc(size)) == NULL)
886432Sas200622 return (NULL);
895331Samw
906432Sas200622 bcopy(sid, new_sid, size);
915331Samw return (new_sid);
925331Samw }
935331Samw
945331Samw
955331Samw /*
966432Sas200622 * smb_sid_splice
975331Samw *
986432Sas200622 * Make a full sid from a domain sid and a relative id (rid).
996432Sas200622 * The memory for the result sid should be freed by calling
1006432Sas200622 * smb_sid_free(). A pointer to the new sid is returned.
1015331Samw */
1026432Sas200622 smb_sid_t *
smb_sid_splice(smb_sid_t * domain_sid,uint32_t rid)1036432Sas200622 smb_sid_splice(smb_sid_t *domain_sid, uint32_t rid)
1045331Samw {
1056432Sas200622 smb_sid_t *sid;
1065331Samw int size;
1075331Samw
1086432Sas200622 if (domain_sid == NULL)
1096432Sas200622 return (NULL);
1105331Samw
1116432Sas200622 size = smb_sid_len(domain_sid);
1126432Sas200622 if ((sid = smb_sid_alloc(size + sizeof (rid))) == NULL)
1136432Sas200622 return (NULL);
1145331Samw
1156432Sas200622 bcopy(domain_sid, sid, size);
1165331Samw
1176432Sas200622 sid->sid_subauth[domain_sid->sid_subauthcnt] = rid;
1186432Sas200622 ++sid->sid_subauthcnt;
1196432Sas200622
1205331Samw return (sid);
1215331Samw }
1225331Samw
1235331Samw /*
1246432Sas200622 * smb_sid_getrid
1255331Samw *
1266432Sas200622 * Return the Relative Id (RID) of the specified SID. It is the
1275331Samw * caller's responsibility to ensure that this is an appropriate SID.
1285331Samw * All we do here is return the last sub-authority from the SID.
1295331Samw */
1305331Samw int
smb_sid_getrid(smb_sid_t * sid,uint32_t * rid)1316432Sas200622 smb_sid_getrid(smb_sid_t *sid, uint32_t *rid)
1325331Samw {
1336432Sas200622 if (!smb_sid_isvalid(sid) || (rid == NULL) ||
1346432Sas200622 (sid->sid_subauthcnt == 0))
1355331Samw return (-1);
1365331Samw
1376432Sas200622 *rid = sid->sid_subauth[sid->sid_subauthcnt - 1];
1386432Sas200622 return (0);
1396432Sas200622 }
1406432Sas200622
1416432Sas200622 /*
1426432Sas200622 * smb_sid_split
1436432Sas200622 *
1446432Sas200622 * Take a full sid and split it into a domain sid and a relative id (rid).
1458670SJose.Borrego@Sun.COM * The domain SID is allocated and a pointer to it will be returned. The
1468670SJose.Borrego@Sun.COM * RID value is passed back in 'rid' arg if it's not NULL. The allocated
1478670SJose.Borrego@Sun.COM * memory for the domain SID must be freed by caller.
1486432Sas200622 */
1498670SJose.Borrego@Sun.COM smb_sid_t *
smb_sid_split(smb_sid_t * sid,uint32_t * rid)1506432Sas200622 smb_sid_split(smb_sid_t *sid, uint32_t *rid)
1516432Sas200622 {
1528670SJose.Borrego@Sun.COM smb_sid_t *domsid;
1538670SJose.Borrego@Sun.COM
1546432Sas200622 if (!smb_sid_isvalid(sid) || (sid->sid_subauthcnt == 0))
1558670SJose.Borrego@Sun.COM return (NULL);
1565331Samw
1578670SJose.Borrego@Sun.COM if ((domsid = smb_sid_dup(sid)) == NULL)
1588670SJose.Borrego@Sun.COM return (NULL);
1598670SJose.Borrego@Sun.COM
1608670SJose.Borrego@Sun.COM --domsid->sid_subauthcnt;
1615331Samw if (rid)
1628670SJose.Borrego@Sun.COM *rid = domsid->sid_subauth[domsid->sid_subauthcnt];
1638670SJose.Borrego@Sun.COM
1648670SJose.Borrego@Sun.COM return (domsid);
1655331Samw }
1665331Samw
1675331Samw /*
1686432Sas200622 * smb_sid_splitstr
1695331Samw *
1706432Sas200622 * Takes a full sid in string form and split it into a domain sid and a
1716432Sas200622 * relative id (rid).
1726432Sas200622 *
1736432Sas200622 * IMPORTANT: The original sid is modified in place. This function assumes
1746432Sas200622 * given SID is in valid string format.
1755331Samw */
1765331Samw int
smb_sid_splitstr(char * strsid,uint32_t * rid)1776432Sas200622 smb_sid_splitstr(char *strsid, uint32_t *rid)
1785331Samw {
1796432Sas200622 char *p;
1806432Sas200622
1816432Sas200622 if ((p = strrchr(strsid, '-')) == NULL)
1825331Samw return (-1);
1836432Sas200622
1846432Sas200622 *p++ = '\0';
1856432Sas200622 if (rid) {
1866432Sas200622 #ifdef _KERNEL
1876432Sas200622 unsigned long sua = 0;
1886432Sas200622 (void) ddi_strtoul(p, NULL, 10, &sua);
1896432Sas200622 *rid = (uint32_t)sua;
1906432Sas200622 #else
1916432Sas200622 *rid = strtoul(p, NULL, 10);
1926432Sas200622 #endif
1935331Samw }
1945331Samw
1955331Samw return (0);
1965331Samw }
1975331Samw
1985331Samw /*
1996432Sas200622 * smb_sid_cmp
2005331Samw *
2015331Samw * Compare two SIDs and return a boolean result. The checks are ordered
2025331Samw * such that components that are more likely to differ are checked
2035331Samw * first. For example, after checking that the SIDs contain the same
2046432Sas200622 * sid_subauthcnt, we check the sub-authorities in reverse order because
2055331Samw * the RID is the most likely differentiator between two SIDs, i.e.
2065331Samw * they are probably going to be in the same domain.
2075331Samw */
2086432Sas200622 boolean_t
smb_sid_cmp(smb_sid_t * sid1,smb_sid_t * sid2)2096432Sas200622 smb_sid_cmp(smb_sid_t *sid1, smb_sid_t *sid2)
2105331Samw {
2115331Samw int i;
2125331Samw
2136432Sas200622 if (sid1 == NULL || sid2 == NULL)
2146432Sas200622 return (B_FALSE);
2155331Samw
2166432Sas200622 if (sid1->sid_subauthcnt != sid2->sid_subauthcnt ||
2176432Sas200622 sid1->sid_revision != sid2->sid_revision)
2186432Sas200622 return (B_FALSE);
2195331Samw
2206432Sas200622 for (i = sid1->sid_subauthcnt - 1; i >= 0; --i)
2216432Sas200622 if (sid1->sid_subauth[i] != sid2->sid_subauth[i])
2226432Sas200622 return (B_FALSE);
2235331Samw
2246432Sas200622 if (bcmp(&sid1->sid_authority, &sid2->sid_authority, NT_SID_AUTH_MAX))
2256432Sas200622 return (B_FALSE);
2265331Samw
2276432Sas200622 return (B_TRUE);
2285331Samw }
2295331Samw
2305331Samw /*
2316432Sas200622 * smb_sid_indomain
2325331Samw *
2335331Samw * Check if given SID is in given domain.
2345331Samw */
2356432Sas200622 boolean_t
smb_sid_indomain(smb_sid_t * domain_sid,smb_sid_t * sid)2366432Sas200622 smb_sid_indomain(smb_sid_t *domain_sid, smb_sid_t *sid)
2375331Samw {
2385331Samw int i;
2395331Samw
2406432Sas200622 if (sid == NULL || domain_sid == NULL)
2416432Sas200622 return (B_FALSE);
2425331Samw
2436432Sas200622 if (domain_sid->sid_revision != sid->sid_revision ||
2446432Sas200622 sid->sid_subauthcnt < domain_sid->sid_subauthcnt)
2456432Sas200622 return (B_FALSE);
2465331Samw
2476432Sas200622 for (i = domain_sid->sid_subauthcnt - 1; i >= 0; --i)
2486432Sas200622 if (domain_sid->sid_subauth[i] != sid->sid_subauth[i])
2496432Sas200622 return (B_FALSE);
2505331Samw
2516432Sas200622 if (bcmp(&domain_sid->sid_authority, &sid->sid_authority,
2526432Sas200622 NT_SID_AUTH_MAX))
2536432Sas200622 return (B_FALSE);
2545331Samw
2556432Sas200622 return (B_TRUE);
2565331Samw }
2575331Samw
2585331Samw #ifndef _KERNEL
2595331Samw /*
2606432Sas200622 * smb_sid_islocal
2615331Samw *
2626432Sas200622 * Check a SID to see if it belongs to the local domain.
2635331Samw */
2646432Sas200622 boolean_t
smb_sid_islocal(smb_sid_t * sid)2656432Sas200622 smb_sid_islocal(smb_sid_t *sid)
2665331Samw {
26710717Samw@Sun.COM smb_domain_t di;
2689832Samw@Sun.COM boolean_t islocal = B_FALSE;
2699832Samw@Sun.COM
27010717Samw@Sun.COM if (smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di))
2719832Samw@Sun.COM islocal = smb_sid_indomain(di.di_binsid, sid);
2729832Samw@Sun.COM
2739832Samw@Sun.COM return (islocal);
2745331Samw }
2755331Samw #endif /* _KERNEL */
2765331Samw
2775331Samw /*
2786432Sas200622 * smb_sid_tostr
2795331Samw *
2806432Sas200622 * Fill in the passed buffer with the string form of the given
2816432Sas200622 * binary sid.
2825331Samw */
2835331Samw void
smb_sid_tostr(const smb_sid_t * sid,char * strsid)284*12508Samw@Sun.COM smb_sid_tostr(const smb_sid_t *sid, char *strsid)
2855331Samw {
2866432Sas200622 char *p = strsid;
2876432Sas200622 int i;
2885331Samw
2896432Sas200622 if (sid == NULL || strsid == NULL)
2905331Samw return;
2915331Samw
2926432Sas200622 (void) sprintf(p, "S-%d-", sid->sid_revision);
2935331Samw while (*p)
2946432Sas200622 p++;
2955331Samw
2965331Samw for (i = 0; i < NT_SID_AUTH_MAX; ++i) {
2976432Sas200622 if (sid->sid_authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) {
2986432Sas200622 (void) sprintf(p, "%d", sid->sid_authority[i]);
2995331Samw while (*p)
3006432Sas200622 p++;
3015331Samw }
3025331Samw }
3035331Samw
3046432Sas200622 for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
3056432Sas200622 (void) sprintf(p, "-%u", sid->sid_subauth[i]);
3065331Samw while (*p)
3076432Sas200622 p++;
3085331Samw }
3095331Samw }
3105331Samw
3115331Samw /*
3126432Sas200622 * smb_sid_fromstr
3135331Samw *
3145331Samw * Converts a SID in string form to a SID structure. There are lots of
3155331Samw * simplifying assumptions in here. The memory for the SID is allocated
3165331Samw * as if it was the largest possible SID; the caller is responsible for
3175331Samw * freeing the memory when it is no longer required. We assume that the
3185331Samw * string starts with "S-1-" and that the authority is held in the last
3195331Samw * byte, which should be okay for most situations. It also assumes the
3205331Samw * sub-authorities are in decimal format.
3215331Samw *
3225331Samw * On success, a pointer to a SID is returned. Otherwise a null pointer
3235331Samw * is returned.
3245331Samw */
3256432Sas200622 #ifdef _KERNEL
3266432Sas200622 smb_sid_t *
smb_sid_fromstr(const char * sidstr)327*12508Samw@Sun.COM smb_sid_fromstr(const char *sidstr)
3285331Samw {
3296432Sas200622 smb_sid_t *sid;
3306432Sas200622 smb_sid_t *retsid;
331*12508Samw@Sun.COM const char *p;
3325331Samw int size;
3336432Sas200622 uint8_t i;
3346432Sas200622 unsigned long sua;
3355331Samw
3366432Sas200622 if (sidstr == NULL)
3376432Sas200622 return (NULL);
3385331Samw
3396432Sas200622 if (strncmp(sidstr, "S-1-", 4) != 0)
3406432Sas200622 return (NULL);
3415331Samw
3426432Sas200622 size = sizeof (smb_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t));
3436432Sas200622 sid = kmem_zalloc(size, KM_SLEEP);
3446432Sas200622
3456432Sas200622 sid->sid_revision = NT_SID_REVISION;
3465331Samw sua = 0;
3476432Sas200622 (void) ddi_strtoul(&sidstr[4], 0, 10, &sua);
3486432Sas200622 sid->sid_authority[5] = (uint8_t)sua;
3495331Samw
3505331Samw for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) {
3515331Samw while (*p && *p == '-')
3525331Samw ++p;
3535331Samw
3545331Samw if (*p < '0' || *p > '9') {
3556432Sas200622 kmem_free(sid, size);
3566432Sas200622 return (NULL);
3575331Samw }
3585331Samw
3595331Samw sua = 0;
3606432Sas200622 (void) ddi_strtoul(p, 0, 10, &sua);
3616432Sas200622 sid->sid_subauth[i] = (uint32_t)sua;
3625331Samw
3635331Samw while (*p && *p != '-')
3645331Samw ++p;
3655331Samw }
3665331Samw
3676432Sas200622 sid->sid_subauthcnt = i;
3686432Sas200622 retsid = smb_sid_dup(sid);
3696432Sas200622 kmem_free(sid, size);
3706432Sas200622
3716432Sas200622 return (retsid);
3726432Sas200622 }
3736432Sas200622 #else /* _KERNEL */
3746432Sas200622 smb_sid_t *
smb_sid_fromstr(const char * sidstr)375*12508Samw@Sun.COM smb_sid_fromstr(const char *sidstr)
3766432Sas200622 {
3776432Sas200622 smb_sid_t *sid;
378*12508Samw@Sun.COM const char *p;
3796432Sas200622 int size;
3806432Sas200622 uint8_t i;
3816432Sas200622
3826432Sas200622 if (sidstr == NULL)
3836432Sas200622 return (NULL);
3846432Sas200622
3856432Sas200622 if (strncmp(sidstr, "S-1-", 4) != 0)
3866432Sas200622 return (NULL);
3876432Sas200622
3886432Sas200622 size = sizeof (smb_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t));
3896432Sas200622
3906432Sas200622 if ((sid = malloc(size)) == NULL)
3916432Sas200622 return (NULL);
3926432Sas200622
3936432Sas200622 bzero(sid, size);
3946432Sas200622 sid->sid_revision = NT_SID_REVISION;
3956432Sas200622 sid->sid_authority[5] = atoi(&sidstr[4]);
3966432Sas200622
3976432Sas200622 for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) {
3986432Sas200622 while (*p && *p == '-')
3996432Sas200622 ++p;
4006432Sas200622
4016432Sas200622 if (*p < '0' || *p > '9') {
4026432Sas200622 free(sid);
4036432Sas200622 return (NULL);
4046432Sas200622 }
4056432Sas200622
4066432Sas200622 sid->sid_subauth[i] = strtoul(p, NULL, 10);
4076432Sas200622
4086432Sas200622 while (*p && *p != '-')
4096432Sas200622 ++p;
4106432Sas200622 }
4116432Sas200622
4126432Sas200622 sid->sid_subauthcnt = i;
4135331Samw return (sid);
4145331Samw }
4156432Sas200622 #endif /* _KERNEL */
4165331Samw
4175331Samw /*
4186432Sas200622 * smb_sid_type2str
4195331Samw *
4205331Samw * Returns the text name for a SID_NAME_USE value. The SID_NAME_USE
4215331Samw * provides the context for a SID, i.e. the type of resource to which
4225331Samw * it refers.
4235331Samw */
4245331Samw char *
smb_sid_type2str(uint16_t snu_id)4256432Sas200622 smb_sid_type2str(uint16_t snu_id)
4265331Samw {
4275331Samw static char *snu_name[] = {
4285331Samw "SidTypeSidPrefix",
4295331Samw "SidTypeUser",
4305331Samw "SidTypeGroup",
4315331Samw "SidTypeDomain",
4325331Samw "SidTypeAlias",
4335331Samw "SidTypeWellKnownGroup",
4345331Samw "SidTypeDeletedAccount",
4355331Samw "SidTypeInvalid",
43611337SWilliam.Krier@Sun.COM "SidTypeUnknown",
43711337SWilliam.Krier@Sun.COM "SidTypeComputer",
43811337SWilliam.Krier@Sun.COM "SidTypeLabel"
4395331Samw };
4405331Samw
4415331Samw if (snu_id < ((sizeof (snu_name)/sizeof (snu_name[0]))))
4425331Samw return (snu_name[snu_id]);
4436432Sas200622
4446432Sas200622 return (snu_name[SidTypeUnknown]);
4455331Samw }
4465331Samw
4476432Sas200622 static smb_sid_t *
smb_sid_alloc(size_t size)4486432Sas200622 smb_sid_alloc(size_t size)
4495331Samw {
4506432Sas200622 smb_sid_t *sid;
4516432Sas200622 #ifdef _KERNEL
4526432Sas200622 sid = kmem_alloc(size, KM_SLEEP);
4536432Sas200622 #else
4546432Sas200622 sid = malloc(size);
4556432Sas200622 #endif
4566432Sas200622 return (sid);
4576432Sas200622 }
4585331Samw
4596432Sas200622 void
smb_sid_free(smb_sid_t * sid)4606432Sas200622 smb_sid_free(smb_sid_t *sid)
4616432Sas200622 {
4626432Sas200622 #ifdef _KERNEL
4636432Sas200622 if (sid == NULL)
4646432Sas200622 return;
4655331Samw
4666432Sas200622 kmem_free(sid, smb_sid_len(sid));
4676432Sas200622 #else
4686432Sas200622 free(sid);
4696432Sas200622 #endif
4705331Samw }
4718670SJose.Borrego@Sun.COM
4728670SJose.Borrego@Sun.COM #ifndef _KERNEL
4738670SJose.Borrego@Sun.COM void
smb_ids_free(smb_ids_t * ids)4748670SJose.Borrego@Sun.COM smb_ids_free(smb_ids_t *ids)
4758670SJose.Borrego@Sun.COM {
4768670SJose.Borrego@Sun.COM smb_id_t *id;
4778670SJose.Borrego@Sun.COM int i;
4788670SJose.Borrego@Sun.COM
4798670SJose.Borrego@Sun.COM if ((ids != NULL) && (ids->i_ids != NULL)) {
4808670SJose.Borrego@Sun.COM id = ids->i_ids;
4818670SJose.Borrego@Sun.COM for (i = 0; i < ids->i_cnt; i++, id++)
4828670SJose.Borrego@Sun.COM smb_sid_free(id->i_sid);
4838670SJose.Borrego@Sun.COM
4848670SJose.Borrego@Sun.COM free(ids->i_ids);
4858670SJose.Borrego@Sun.COM }
4868670SJose.Borrego@Sun.COM }
4878670SJose.Borrego@Sun.COM #endif
488