1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22*6537f381Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27da6c28aaSamw 28da6c28aaSamw /* 29da6c28aaSamw * NT Security Identifier (SID) library functions. 30da6c28aaSamw */ 31da6c28aaSamw 32da6c28aaSamw #ifndef _KERNEL 33da6c28aaSamw #include <stdio.h> 34da6c28aaSamw #include <strings.h> 35da6c28aaSamw #include <stdlib.h> 36da6c28aaSamw #include <syslog.h> 37da6c28aaSamw #include <smbsrv/libsmb.h> 38da6c28aaSamw #else /* _KERNEL */ 39da6c28aaSamw #include <sys/types.h> 40da6c28aaSamw #include <sys/sunddi.h> 41da6c28aaSamw #endif /* _KERNEL */ 42da6c28aaSamw 43*6537f381Sas200622 #include <smbsrv/smb_sid.h> 44da6c28aaSamw 45*6537f381Sas200622 static smb_sid_t *smb_sid_alloc(size_t); 46da6c28aaSamw 47da6c28aaSamw /* 48*6537f381Sas200622 * smb_sid_isvalid 49da6c28aaSamw * 50*6537f381Sas200622 * Performs a minimal SID validation. 51da6c28aaSamw */ 52*6537f381Sas200622 boolean_t 53*6537f381Sas200622 smb_sid_isvalid(smb_sid_t *sid) 54da6c28aaSamw { 55*6537f381Sas200622 if (sid == NULL) 56*6537f381Sas200622 return (B_FALSE); 57da6c28aaSamw 58*6537f381Sas200622 return ((sid->sid_revision == NT_SID_REVISION) && 59*6537f381Sas200622 (sid->sid_subauthcnt < NT_SID_SUBAUTH_MAX)); 60da6c28aaSamw } 61da6c28aaSamw 62da6c28aaSamw /* 63*6537f381Sas200622 * smb_sid_len 64da6c28aaSamw * 65da6c28aaSamw * Returns the number of bytes required to hold the sid. 66da6c28aaSamw */ 67da6c28aaSamw int 68*6537f381Sas200622 smb_sid_len(smb_sid_t *sid) 69da6c28aaSamw { 70*6537f381Sas200622 if (sid == NULL) 71da6c28aaSamw return (0); 72da6c28aaSamw 73*6537f381Sas200622 return (sizeof (smb_sid_t) - sizeof (uint32_t) 74*6537f381Sas200622 + (sid->sid_subauthcnt * sizeof (uint32_t))); 75da6c28aaSamw } 76da6c28aaSamw 77da6c28aaSamw /* 78*6537f381Sas200622 * smb_sid_dup 79da6c28aaSamw * 80*6537f381Sas200622 * Make a duplicate of the specified sid. The memory for the new sid 81*6537f381Sas200622 * should be freed by calling smb_sid_free(). 82*6537f381Sas200622 * A pointer to the new sid is returned. 83da6c28aaSamw */ 84*6537f381Sas200622 smb_sid_t * 85*6537f381Sas200622 smb_sid_dup(smb_sid_t *sid) 86da6c28aaSamw { 87*6537f381Sas200622 smb_sid_t *new_sid; 88da6c28aaSamw int size; 89da6c28aaSamw 90*6537f381Sas200622 if (sid == NULL) 91*6537f381Sas200622 return (NULL); 92da6c28aaSamw 93*6537f381Sas200622 size = smb_sid_len(sid); 94*6537f381Sas200622 if ((new_sid = smb_sid_alloc(size)) == NULL) 95*6537f381Sas200622 return (NULL); 96da6c28aaSamw 97*6537f381Sas200622 bcopy(sid, new_sid, size); 98da6c28aaSamw return (new_sid); 99da6c28aaSamw } 100da6c28aaSamw 101da6c28aaSamw 102da6c28aaSamw /* 103*6537f381Sas200622 * smb_sid_splice 104da6c28aaSamw * 105*6537f381Sas200622 * Make a full sid from a domain sid and a relative id (rid). 106*6537f381Sas200622 * The memory for the result sid should be freed by calling 107*6537f381Sas200622 * smb_sid_free(). A pointer to the new sid is returned. 108da6c28aaSamw */ 109*6537f381Sas200622 smb_sid_t * 110*6537f381Sas200622 smb_sid_splice(smb_sid_t *domain_sid, uint32_t rid) 111da6c28aaSamw { 112*6537f381Sas200622 smb_sid_t *sid; 113da6c28aaSamw int size; 114da6c28aaSamw 115*6537f381Sas200622 if (domain_sid == NULL) 116*6537f381Sas200622 return (NULL); 117da6c28aaSamw 118*6537f381Sas200622 size = smb_sid_len(domain_sid); 119*6537f381Sas200622 if ((sid = smb_sid_alloc(size + sizeof (rid))) == NULL) 120*6537f381Sas200622 return (NULL); 121da6c28aaSamw 122*6537f381Sas200622 bcopy(domain_sid, sid, size); 123da6c28aaSamw 124*6537f381Sas200622 sid->sid_subauth[domain_sid->sid_subauthcnt] = rid; 125*6537f381Sas200622 ++sid->sid_subauthcnt; 126da6c28aaSamw 127da6c28aaSamw return (sid); 128da6c28aaSamw } 129da6c28aaSamw 130da6c28aaSamw /* 131*6537f381Sas200622 * smb_sid_getrid 132da6c28aaSamw * 133*6537f381Sas200622 * Return the Relative Id (RID) of the specified SID. It is the 134da6c28aaSamw * caller's responsibility to ensure that this is an appropriate SID. 135da6c28aaSamw * All we do here is return the last sub-authority from the SID. 136da6c28aaSamw */ 137da6c28aaSamw int 138*6537f381Sas200622 smb_sid_getrid(smb_sid_t *sid, uint32_t *rid) 139da6c28aaSamw { 140*6537f381Sas200622 if (!smb_sid_isvalid(sid) || (rid == NULL) || 141*6537f381Sas200622 (sid->sid_subauthcnt == 0)) 142da6c28aaSamw return (-1); 143da6c28aaSamw 144*6537f381Sas200622 *rid = sid->sid_subauth[sid->sid_subauthcnt - 1]; 145da6c28aaSamw return (0); 146da6c28aaSamw } 147da6c28aaSamw 148da6c28aaSamw /* 149*6537f381Sas200622 * smb_sid_split 150da6c28aaSamw * 151*6537f381Sas200622 * Take a full sid and split it into a domain sid and a relative id (rid). 152*6537f381Sas200622 * 153*6537f381Sas200622 * IMPORTANT: The original sid is modified in place - use smb_sid_dup before 154*6537f381Sas200622 * calling this function to preserve the original SID. Be careful if you're 155*6537f381Sas200622 * using this function in kernel code, after calling this function 'sid' 156*6537f381Sas200622 * cannot be passed to smb_sid_free() because the size won't match the original 157*6537f381Sas200622 * allocated size. Use smb_sid_ksplit() instead. 158da6c28aaSamw */ 159da6c28aaSamw int 160*6537f381Sas200622 smb_sid_split(smb_sid_t *sid, uint32_t *rid) 161da6c28aaSamw { 162*6537f381Sas200622 if (!smb_sid_isvalid(sid) || (sid->sid_subauthcnt == 0)) 163da6c28aaSamw return (-1); 164da6c28aaSamw 165*6537f381Sas200622 --sid->sid_subauthcnt; 166da6c28aaSamw if (rid) 167*6537f381Sas200622 *rid = sid->sid_subauth[sid->sid_subauthcnt]; 168da6c28aaSamw return (0); 169da6c28aaSamw } 170da6c28aaSamw 171da6c28aaSamw /* 172*6537f381Sas200622 * smb_sid_splitstr 173da6c28aaSamw * 174*6537f381Sas200622 * Takes a full sid in string form and split it into a domain sid and a 175*6537f381Sas200622 * relative id (rid). 176*6537f381Sas200622 * 177*6537f381Sas200622 * IMPORTANT: The original sid is modified in place. This function assumes 178*6537f381Sas200622 * given SID is in valid string format. 179da6c28aaSamw */ 180*6537f381Sas200622 int 181*6537f381Sas200622 smb_sid_splitstr(char *strsid, uint32_t *rid) 182da6c28aaSamw { 183*6537f381Sas200622 char *p; 184da6c28aaSamw 185*6537f381Sas200622 if ((p = strrchr(strsid, '-')) == NULL) 186*6537f381Sas200622 return (-1); 187da6c28aaSamw 188*6537f381Sas200622 *p++ = '\0'; 189*6537f381Sas200622 if (rid) { 190*6537f381Sas200622 #ifdef _KERNEL 191*6537f381Sas200622 unsigned long sua = 0; 192*6537f381Sas200622 (void) ddi_strtoul(p, NULL, 10, &sua); 193*6537f381Sas200622 *rid = (uint32_t)sua; 194*6537f381Sas200622 #else 195*6537f381Sas200622 *rid = strtoul(p, NULL, 10); 196*6537f381Sas200622 #endif 197*6537f381Sas200622 } 198*6537f381Sas200622 199da6c28aaSamw return (0); 200da6c28aaSamw } 201da6c28aaSamw 202da6c28aaSamw /* 203*6537f381Sas200622 * smb_sid_cmp 204da6c28aaSamw * 205da6c28aaSamw * Compare two SIDs and return a boolean result. The checks are ordered 206da6c28aaSamw * such that components that are more likely to differ are checked 207da6c28aaSamw * first. For example, after checking that the SIDs contain the same 208*6537f381Sas200622 * sid_subauthcnt, we check the sub-authorities in reverse order because 209da6c28aaSamw * the RID is the most likely differentiator between two SIDs, i.e. 210da6c28aaSamw * they are probably going to be in the same domain. 211da6c28aaSamw */ 212*6537f381Sas200622 boolean_t 213*6537f381Sas200622 smb_sid_cmp(smb_sid_t *sid1, smb_sid_t *sid2) 214da6c28aaSamw { 215da6c28aaSamw int i; 216da6c28aaSamw 217*6537f381Sas200622 if (sid1 == NULL || sid2 == NULL) 218*6537f381Sas200622 return (B_FALSE); 219da6c28aaSamw 220*6537f381Sas200622 if (sid1->sid_subauthcnt != sid2->sid_subauthcnt || 221*6537f381Sas200622 sid1->sid_revision != sid2->sid_revision) 222*6537f381Sas200622 return (B_FALSE); 223da6c28aaSamw 224*6537f381Sas200622 for (i = sid1->sid_subauthcnt - 1; i >= 0; --i) 225*6537f381Sas200622 if (sid1->sid_subauth[i] != sid2->sid_subauth[i]) 226*6537f381Sas200622 return (B_FALSE); 227da6c28aaSamw 228*6537f381Sas200622 if (bcmp(&sid1->sid_authority, &sid2->sid_authority, NT_SID_AUTH_MAX)) 229*6537f381Sas200622 return (B_FALSE); 230da6c28aaSamw 231*6537f381Sas200622 return (B_TRUE); 232da6c28aaSamw } 233da6c28aaSamw 234da6c28aaSamw /* 235*6537f381Sas200622 * smb_sid_indomain 236da6c28aaSamw * 237da6c28aaSamw * Check if given SID is in given domain. 238da6c28aaSamw */ 239*6537f381Sas200622 boolean_t 240*6537f381Sas200622 smb_sid_indomain(smb_sid_t *domain_sid, smb_sid_t *sid) 241da6c28aaSamw { 242da6c28aaSamw int i; 243da6c28aaSamw 244*6537f381Sas200622 if (sid == NULL || domain_sid == NULL) 245*6537f381Sas200622 return (B_FALSE); 246da6c28aaSamw 247*6537f381Sas200622 if (domain_sid->sid_revision != sid->sid_revision || 248*6537f381Sas200622 sid->sid_subauthcnt < domain_sid->sid_subauthcnt) 249*6537f381Sas200622 return (B_FALSE); 250da6c28aaSamw 251*6537f381Sas200622 for (i = domain_sid->sid_subauthcnt - 1; i >= 0; --i) 252*6537f381Sas200622 if (domain_sid->sid_subauth[i] != sid->sid_subauth[i]) 253*6537f381Sas200622 return (B_FALSE); 254da6c28aaSamw 255*6537f381Sas200622 if (bcmp(&domain_sid->sid_authority, &sid->sid_authority, 256*6537f381Sas200622 NT_SID_AUTH_MAX)) 257*6537f381Sas200622 return (B_FALSE); 258da6c28aaSamw 259*6537f381Sas200622 return (B_TRUE); 260da6c28aaSamw } 261da6c28aaSamw 262da6c28aaSamw #ifndef _KERNEL 263da6c28aaSamw /* 264*6537f381Sas200622 * smb_sid_islocal 265da6c28aaSamw * 266*6537f381Sas200622 * Check a SID to see if it belongs to the local domain. 267da6c28aaSamw */ 268*6537f381Sas200622 boolean_t 269*6537f381Sas200622 smb_sid_islocal(smb_sid_t *sid) 270da6c28aaSamw { 271*6537f381Sas200622 return (smb_sid_indomain(nt_domain_local_sid(), sid)); 272da6c28aaSamw } 273da6c28aaSamw #endif /* _KERNEL */ 274da6c28aaSamw 275da6c28aaSamw /* 276*6537f381Sas200622 * smb_sid_tostr 277da6c28aaSamw * 278*6537f381Sas200622 * Fill in the passed buffer with the string form of the given 279*6537f381Sas200622 * binary sid. 280da6c28aaSamw */ 281da6c28aaSamw void 282*6537f381Sas200622 smb_sid_tostr(smb_sid_t *sid, char *strsid) 283da6c28aaSamw { 284*6537f381Sas200622 char *p = strsid; 285*6537f381Sas200622 int i; 286da6c28aaSamw 287*6537f381Sas200622 if (sid == NULL || strsid == NULL) 288da6c28aaSamw return; 289da6c28aaSamw 290*6537f381Sas200622 (void) sprintf(p, "S-%d-", sid->sid_revision); 291da6c28aaSamw while (*p) 292*6537f381Sas200622 p++; 293da6c28aaSamw 294da6c28aaSamw for (i = 0; i < NT_SID_AUTH_MAX; ++i) { 295*6537f381Sas200622 if (sid->sid_authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) { 296*6537f381Sas200622 (void) sprintf(p, "%d", sid->sid_authority[i]); 297da6c28aaSamw while (*p) 298*6537f381Sas200622 p++; 299da6c28aaSamw } 300da6c28aaSamw } 301da6c28aaSamw 302*6537f381Sas200622 for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) { 303*6537f381Sas200622 (void) sprintf(p, "-%u", sid->sid_subauth[i]); 304da6c28aaSamw while (*p) 305*6537f381Sas200622 p++; 306da6c28aaSamw } 307da6c28aaSamw } 308da6c28aaSamw 309da6c28aaSamw /* 310*6537f381Sas200622 * smb_sid_fromstr 311da6c28aaSamw * 312da6c28aaSamw * Converts a SID in string form to a SID structure. There are lots of 313da6c28aaSamw * simplifying assumptions in here. The memory for the SID is allocated 314da6c28aaSamw * as if it was the largest possible SID; the caller is responsible for 315da6c28aaSamw * freeing the memory when it is no longer required. We assume that the 316da6c28aaSamw * string starts with "S-1-" and that the authority is held in the last 317da6c28aaSamw * byte, which should be okay for most situations. It also assumes the 318da6c28aaSamw * sub-authorities are in decimal format. 319da6c28aaSamw * 320da6c28aaSamw * On success, a pointer to a SID is returned. Otherwise a null pointer 321da6c28aaSamw * is returned. 322da6c28aaSamw */ 323*6537f381Sas200622 #ifdef _KERNEL 324*6537f381Sas200622 smb_sid_t * 325*6537f381Sas200622 smb_sid_fromstr(char *sidstr) 326da6c28aaSamw { 327*6537f381Sas200622 smb_sid_t *sid; 328*6537f381Sas200622 smb_sid_t *retsid; 329da6c28aaSamw char *p; 330da6c28aaSamw int size; 331*6537f381Sas200622 uint8_t i; 332*6537f381Sas200622 unsigned long sua; 333da6c28aaSamw 334*6537f381Sas200622 if (sidstr == NULL) 335*6537f381Sas200622 return (NULL); 336da6c28aaSamw 337*6537f381Sas200622 if (strncmp(sidstr, "S-1-", 4) != 0) 338*6537f381Sas200622 return (NULL); 339da6c28aaSamw 340*6537f381Sas200622 size = sizeof (smb_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t)); 341*6537f381Sas200622 sid = kmem_zalloc(size, KM_SLEEP); 342da6c28aaSamw 343*6537f381Sas200622 sid->sid_revision = NT_SID_REVISION; 344da6c28aaSamw sua = 0; 345*6537f381Sas200622 (void) ddi_strtoul(&sidstr[4], 0, 10, &sua); 346*6537f381Sas200622 sid->sid_authority[5] = (uint8_t)sua; 347da6c28aaSamw 348da6c28aaSamw for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) { 349da6c28aaSamw while (*p && *p == '-') 350da6c28aaSamw ++p; 351da6c28aaSamw 352da6c28aaSamw if (*p < '0' || *p > '9') { 353*6537f381Sas200622 kmem_free(sid, size); 354*6537f381Sas200622 return (NULL); 355da6c28aaSamw } 356da6c28aaSamw 357da6c28aaSamw sua = 0; 358*6537f381Sas200622 (void) ddi_strtoul(p, 0, 10, &sua); 359*6537f381Sas200622 sid->sid_subauth[i] = (uint32_t)sua; 360da6c28aaSamw 361da6c28aaSamw while (*p && *p != '-') 362da6c28aaSamw ++p; 363da6c28aaSamw } 364da6c28aaSamw 365*6537f381Sas200622 sid->sid_subauthcnt = i; 366*6537f381Sas200622 retsid = smb_sid_dup(sid); 367*6537f381Sas200622 kmem_free(sid, size); 368*6537f381Sas200622 369*6537f381Sas200622 return (retsid); 370*6537f381Sas200622 } 371*6537f381Sas200622 #else /* _KERNEL */ 372*6537f381Sas200622 smb_sid_t * 373*6537f381Sas200622 smb_sid_fromstr(char *sidstr) 374*6537f381Sas200622 { 375*6537f381Sas200622 smb_sid_t *sid; 376*6537f381Sas200622 char *p; 377*6537f381Sas200622 int size; 378*6537f381Sas200622 uint8_t i; 379*6537f381Sas200622 380*6537f381Sas200622 if (sidstr == NULL) 381*6537f381Sas200622 return (NULL); 382*6537f381Sas200622 383*6537f381Sas200622 if (strncmp(sidstr, "S-1-", 4) != 0) 384*6537f381Sas200622 return (NULL); 385*6537f381Sas200622 386*6537f381Sas200622 size = sizeof (smb_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t)); 387*6537f381Sas200622 388*6537f381Sas200622 if ((sid = malloc(size)) == NULL) 389*6537f381Sas200622 return (NULL); 390*6537f381Sas200622 391*6537f381Sas200622 bzero(sid, size); 392*6537f381Sas200622 sid->sid_revision = NT_SID_REVISION; 393*6537f381Sas200622 sid->sid_authority[5] = atoi(&sidstr[4]); 394*6537f381Sas200622 395*6537f381Sas200622 for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) { 396*6537f381Sas200622 while (*p && *p == '-') 397*6537f381Sas200622 ++p; 398*6537f381Sas200622 399*6537f381Sas200622 if (*p < '0' || *p > '9') { 400*6537f381Sas200622 free(sid); 401*6537f381Sas200622 return (NULL); 402da6c28aaSamw } 403da6c28aaSamw 404*6537f381Sas200622 sid->sid_subauth[i] = strtoul(p, NULL, 10); 405*6537f381Sas200622 406*6537f381Sas200622 while (*p && *p != '-') 407*6537f381Sas200622 ++p; 408*6537f381Sas200622 } 409*6537f381Sas200622 410*6537f381Sas200622 sid->sid_subauthcnt = i; 411*6537f381Sas200622 return (sid); 412*6537f381Sas200622 } 413*6537f381Sas200622 #endif /* _KERNEL */ 414da6c28aaSamw 415da6c28aaSamw /* 416*6537f381Sas200622 * smb_sid_type2str 417da6c28aaSamw * 418da6c28aaSamw * Returns the text name for a SID_NAME_USE value. The SID_NAME_USE 419da6c28aaSamw * provides the context for a SID, i.e. the type of resource to which 420da6c28aaSamw * it refers. 421da6c28aaSamw */ 422da6c28aaSamw char * 423*6537f381Sas200622 smb_sid_type2str(uint16_t snu_id) 424da6c28aaSamw { 425da6c28aaSamw static char *snu_name[] = { 426da6c28aaSamw "SidTypeSidPrefix", 427da6c28aaSamw "SidTypeUser", 428da6c28aaSamw "SidTypeGroup", 429da6c28aaSamw "SidTypeDomain", 430da6c28aaSamw "SidTypeAlias", 431da6c28aaSamw "SidTypeWellKnownGroup", 432da6c28aaSamw "SidTypeDeletedAccount", 433da6c28aaSamw "SidTypeInvalid", 434da6c28aaSamw "SidTypeUnknown" 435da6c28aaSamw }; 436da6c28aaSamw 437da6c28aaSamw if (snu_id < ((sizeof (snu_name)/sizeof (snu_name[0])))) 438da6c28aaSamw return (snu_name[snu_id]); 439*6537f381Sas200622 440da6c28aaSamw return (snu_name[SidTypeUnknown]); 441da6c28aaSamw } 442*6537f381Sas200622 443*6537f381Sas200622 static smb_sid_t * 444*6537f381Sas200622 smb_sid_alloc(size_t size) 445*6537f381Sas200622 { 446*6537f381Sas200622 smb_sid_t *sid; 447*6537f381Sas200622 #ifdef _KERNEL 448*6537f381Sas200622 sid = kmem_alloc(size, KM_SLEEP); 449*6537f381Sas200622 #else 450*6537f381Sas200622 sid = malloc(size); 451*6537f381Sas200622 #endif 452*6537f381Sas200622 return (sid); 453da6c28aaSamw } 454da6c28aaSamw 455*6537f381Sas200622 void 456*6537f381Sas200622 smb_sid_free(smb_sid_t *sid) 457da6c28aaSamw { 458*6537f381Sas200622 #ifdef _KERNEL 459*6537f381Sas200622 if (sid == NULL) 460*6537f381Sas200622 return; 461da6c28aaSamw 462*6537f381Sas200622 kmem_free(sid, smb_sid_len(sid)); 463*6537f381Sas200622 #else 464*6537f381Sas200622 free(sid); 465*6537f381Sas200622 #endif 466da6c28aaSamw } 467