1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * NT Security Identifier (SID) library functions. 30 */ 31 32 #ifndef _KERNEL 33 #include <stdio.h> 34 #include <strings.h> 35 #include <stdlib.h> 36 #include <syslog.h> 37 #include <smbsrv/libsmb.h> 38 #else /* _KERNEL */ 39 #include <sys/types.h> 40 #include <sys/sunddi.h> 41 #endif /* _KERNEL */ 42 43 #include <smbsrv/alloc.h> 44 #include <smbsrv/ntsid.h> 45 #include <smbsrv/ntstatus.h> 46 #include <smbsrv/smbinfo.h> 47 48 49 /* 50 * nt_sid_is_valid 51 * 52 * Check that a sid is valid. The checking is minimal: check the pointer 53 * is valid and that the revision and sub-authority count is legal. 54 * Returns 1 if the sid appears to be valid. Otherwise 0. 55 */ 56 int 57 nt_sid_is_valid(nt_sid_t *sid) 58 { 59 if (sid == 0) 60 return (0); 61 62 return (sid->Revision == NT_SID_REVISION && 63 sid->SubAuthCount < NT_SID_SUBAUTH_MAX) ? 1 : 0; 64 } 65 66 67 /* 68 * nt_sid_length 69 * 70 * Returns the number of bytes required to hold the sid. 71 */ 72 int 73 nt_sid_length(nt_sid_t *sid) 74 { 75 if (sid == 0) 76 return (0); 77 78 return (sizeof (nt_sid_t) - sizeof (DWORD) 79 + (sid->SubAuthCount * sizeof (DWORD))); 80 } 81 82 83 /* 84 * nt_sid_dup 85 * 86 * Make a duplicate of the specified sid. The memory for the new sid is 87 * allocated using malloc so the caller should call free when it is no 88 * longer required. A pointer to the new sid is returned. 89 */ 90 nt_sid_t * 91 nt_sid_dup(nt_sid_t *sid) 92 { 93 nt_sid_t *new_sid; 94 int size; 95 int i; 96 97 if (sid == 0) 98 return (0); 99 100 size = sizeof (nt_sid_t) 101 + (sid->SubAuthCount * sizeof (DWORD)) 102 + sizeof (DWORD); 103 104 if ((new_sid = MEM_MALLOC("libnt", size)) == 0) 105 return (0); 106 107 (void) memcpy(new_sid, sid, sizeof (nt_sid_t)); 108 109 for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i) 110 new_sid->SubAuthority[i] = sid->SubAuthority[i]; 111 112 return (new_sid); 113 } 114 115 116 /* 117 * nt_sid_splice 118 * 119 * Make a full user sid from the domain sid and the user relative id 120 * (rid). The memory for the new sid is allocated using malloc so the 121 * caller should call free when it is no longer required. A pointer 122 * to the new sid is returned. 123 */ 124 nt_sid_t * 125 nt_sid_splice(nt_sid_t *domain_sid, DWORD rid) 126 { 127 nt_sid_t *sid; 128 int size; 129 int i; 130 131 if (domain_sid == 0) 132 return (0); 133 134 size = sizeof (nt_sid_t) 135 + (domain_sid->SubAuthCount * sizeof (DWORD)) 136 + sizeof (DWORD); 137 138 if ((sid = MEM_MALLOC("libnt", size)) == 0) 139 return (0); 140 141 (void) memcpy(sid, domain_sid, sizeof (nt_sid_t)); 142 143 for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i) 144 sid->SubAuthority[i] = domain_sid->SubAuthority[i]; 145 146 sid->SubAuthority[i] = rid; 147 ++sid->SubAuthCount; 148 return (sid); 149 } 150 151 152 /* 153 * nt_sid_get_rid 154 * 155 * Return the Relative Id (RID) from the specified SID. It is the 156 * caller's responsibility to ensure that this is an appropriate SID. 157 * All we do here is return the last sub-authority from the SID. 158 */ 159 int 160 nt_sid_get_rid(nt_sid_t *sid, DWORD *rid) 161 { 162 if (!nt_sid_is_valid(sid)) 163 return (-1); 164 165 if (sid->SubAuthCount == 0) { 166 return (-1); 167 } 168 169 if (rid) 170 *rid = sid->SubAuthority[sid->SubAuthCount - 1]; 171 return (0); 172 } 173 174 175 /* 176 * nt_sid_split 177 * 178 * Take a full user sid and split it into the domain sid and the user 179 * relative id (rid). The original sid is modified in place - use 180 * nt_sid_dup before calling this function to preserve the original SID. 181 */ 182 int 183 nt_sid_split(nt_sid_t *sid, DWORD *rid) 184 { 185 if (!nt_sid_is_valid(sid)) { 186 return (-1); 187 } 188 189 if (sid->SubAuthCount == 0) { 190 return (-1); 191 } 192 193 --sid->SubAuthCount; 194 if (rid) 195 *rid = sid->SubAuthority[sid->SubAuthCount]; 196 return (0); 197 } 198 199 200 /* 201 * nt_sid_gen_null_sid 202 * 203 * This function allocates a SID structure and initializes it as the 204 * well-known Null SID (S-1-0-0). A pointer to the SID is returned. 205 * As the memory for this structure is obtained via malloc, it is the 206 * caller's responsibility to free the memory when it is no longer 207 * required. If malloc fails, a null pointer is returned. 208 */ 209 nt_sid_t * 210 nt_sid_gen_null_sid(void) 211 { 212 nt_sid_t *sid; 213 int size; 214 215 size = sizeof (nt_sid_t) + sizeof (DWORD); 216 217 if ((sid = MEM_MALLOC("libnt", size)) == 0) { 218 return (0); 219 } 220 221 sid->Revision = 1; 222 sid->SubAuthCount = 1; 223 return (sid); 224 } 225 226 227 /* 228 * nt_sid_is_equal 229 * 230 * Compare two SIDs and return a boolean result. The checks are ordered 231 * such that components that are more likely to differ are checked 232 * first. For example, after checking that the SIDs contain the same 233 * SubAuthCount, we check the sub-authorities in reverse order because 234 * the RID is the most likely differentiator between two SIDs, i.e. 235 * they are probably going to be in the same domain. 236 * 237 * Returns 1 if the SIDs are equal. Otherwise returns 0. 238 */ 239 int 240 nt_sid_is_equal(nt_sid_t *sid1, nt_sid_t *sid2) 241 { 242 int i; 243 244 if (sid1 == 0 || sid2 == 0) 245 return (0); 246 247 if (sid1->SubAuthCount != sid2->SubAuthCount || 248 sid1->Revision != sid2->Revision) 249 return (0); 250 251 for (i = sid1->SubAuthCount - 1; i >= 0; --i) 252 if (sid1->SubAuthority[i] != sid2->SubAuthority[i]) 253 return (0); 254 255 if (bcmp(&sid1->Authority, &sid2->Authority, NT_SID_AUTH_MAX)) 256 return (0); 257 258 return (1); 259 } 260 261 /* 262 * nt_sid_is_indomain 263 * 264 * Check if given SID is in given domain. 265 * Returns 1 on success. Otherwise returns 0. 266 */ 267 int 268 nt_sid_is_indomain(nt_sid_t *domain_sid, nt_sid_t *sid) 269 { 270 int i; 271 272 if (sid == 0 || domain_sid == 0) { 273 return (0); 274 } 275 276 if (domain_sid->Revision != sid->Revision || 277 sid->SubAuthCount < domain_sid->SubAuthCount) 278 return (0); 279 280 for (i = domain_sid->SubAuthCount - 1; i >= 0; --i) 281 if (domain_sid->SubAuthority[i] != sid->SubAuthority[i]) 282 return (0); 283 284 if (bcmp(&domain_sid->Authority, &sid->Authority, NT_SID_AUTH_MAX)) 285 return (0); 286 287 return (1); 288 } 289 290 #ifndef _KERNEL 291 /* 292 * nt_sid_is_local 293 * 294 * Check a SID to see if it belongs to the local domain. This is almost 295 * the same as checking that two SIDs are equal except that we don't 296 * care if the specified SID contains extra sub-authorities. We're only 297 * interested in the domain part. 298 * 299 * Returns 1 if the SIDs are equal. Otherwise returns 0. 300 */ 301 int 302 nt_sid_is_local(nt_sid_t *sid) 303 { 304 nt_sid_t *local_sid; 305 306 local_sid = nt_domain_local_sid(); 307 return (nt_sid_is_indomain(local_sid, sid)); 308 } 309 310 /* 311 * nt_sid_is_builtin 312 * 313 * Check a SID to see if it belongs to the builtin domain. 314 * Returns 1 if the SID is a builtin SID. Otherwise returns 0. 315 */ 316 int 317 nt_sid_is_builtin(nt_sid_t *sid) 318 { 319 nt_domain_t *domain; 320 321 domain = nt_domain_lookupbytype(NT_DOMAIN_BUILTIN); 322 if (domain == 0) 323 return (0); 324 return (nt_sid_is_indomain(domain->sid, sid)); 325 } 326 #endif /* _KERNEL */ 327 328 /* 329 * nt_sid_is_domain_equal 330 * 331 * Compare two SIDs's domain and return a boolean result. 332 * 333 * Returns 1 if the domain SID are the same. Otherwise returns 0. 334 */ 335 int 336 nt_sid_is_domain_equal(nt_sid_t *pSid1, nt_sid_t *pSid2) 337 { 338 int i, n; 339 340 if (pSid1->Revision != pSid2->Revision) 341 return (0); 342 343 if (pSid1->SubAuthCount != pSid2->SubAuthCount) 344 return (0); 345 346 if (bcmp(pSid1->Authority, pSid2->Authority, NT_SID_AUTH_MAX) != 0) 347 return (0); 348 349 n = pSid1->SubAuthCount; 350 351 n -= 1; /* don't compare last SubAuthority[] (aka RID) */ 352 353 for (i = 0; i < n; i++) 354 if (pSid1->SubAuthority[i] != pSid2->SubAuthority[i]) 355 return (0); 356 357 return (1); 358 } 359 360 /* 361 * nt_sid_logf 362 * 363 * Format a sid and write it to the system log. See nt_sid_format 364 * for format information. 365 */ 366 void 367 nt_sid_logf(nt_sid_t *sid) 368 { 369 char *s; 370 371 if ((s = nt_sid_format(sid)) == 0) 372 return; 373 374 MEM_FREE("libnt", s); 375 } 376 377 378 /* 379 * nt_sid_format 380 * 381 * Format a sid and return it as a string. The memory for the string is 382 * allocated using malloc so the caller should call free when it is no 383 * longer required. A pointer to the string is returned. 384 */ 385 char * 386 nt_sid_format(nt_sid_t *sid) 387 { 388 int i; 389 char *fmtbuf; 390 char *p; 391 392 if (sid == 0) 393 return (0); 394 395 if ((fmtbuf = MEM_MALLOC("libnt", NT_SID_FMTBUF_SIZE)) == 0) 396 return (0); 397 398 p = fmtbuf; 399 (void) sprintf(p, "S-%d-", sid->Revision); 400 while (*p) 401 ++p; 402 403 for (i = 0; i < NT_SID_AUTH_MAX; ++i) { 404 if (sid->Authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) { 405 (void) sprintf(p, "%d", sid->Authority[i]); 406 while (*p) 407 ++p; 408 } 409 } 410 411 for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i) { 412 (void) sprintf(p, "-%u", sid->SubAuthority[i]); 413 while (*p) 414 ++p; 415 } 416 417 return (fmtbuf); 418 } 419 420 /* 421 * nt_sid_format2 422 * 423 * Format a sid and return it in the passed buffer. 424 */ 425 void 426 nt_sid_format2(nt_sid_t *sid, char *fmtbuf) 427 { 428 int i; 429 char *p; 430 431 if (sid == 0 || fmtbuf == 0) 432 return; 433 434 p = fmtbuf; 435 (void) sprintf(p, "S-%d-", sid->Revision); 436 while (*p) 437 ++p; 438 439 for (i = 0; i < NT_SID_AUTH_MAX; ++i) { 440 if (sid->Authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) { 441 (void) sprintf(p, "%d", sid->Authority[i]); 442 while (*p) 443 ++p; 444 } 445 } 446 447 for (i = 0; i < sid->SubAuthCount && i < NT_SID_SUBAUTH_MAX; ++i) { 448 (void) sprintf(p, "-%u", sid->SubAuthority[i]); 449 while (*p) 450 ++p; 451 } 452 } 453 454 /* 455 * nt_sid_strtosid 456 * 457 * Converts a SID in string form to a SID structure. There are lots of 458 * simplifying assumptions in here. The memory for the SID is allocated 459 * as if it was the largest possible SID; the caller is responsible for 460 * freeing the memory when it is no longer required. We assume that the 461 * string starts with "S-1-" and that the authority is held in the last 462 * byte, which should be okay for most situations. It also assumes the 463 * sub-authorities are in decimal format. 464 * 465 * On success, a pointer to a SID is returned. Otherwise a null pointer 466 * is returned. 467 * 468 * XXX this function may have endian issues 469 */ 470 nt_sid_t * 471 nt_sid_strtosid(char *sidstr) 472 { 473 nt_sid_t *sid; 474 char *p; 475 int size; 476 BYTE i; 477 #ifdef _KERNEL 478 long sua; 479 #endif /* _KERNEL */ 480 481 if (sidstr == 0) { 482 return (0); 483 } 484 485 if (strncmp(sidstr, "S-1-", 4) != 0) { 486 return (0); 487 } 488 489 size = sizeof (nt_sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (DWORD)); 490 491 if ((sid = MEM_MALLOC("libnt", size)) == 0) { 492 return (0); 493 } 494 495 bzero(sid, size); 496 sid->Revision = NT_SID_REVISION; 497 #ifndef _KERNEL 498 sid->Authority[5] = atoi(&sidstr[4]); 499 #else /* _KERNEL */ 500 sua = 0; 501 /* XXX Why are we treating sua as a long/unsigned long? */ 502 (void) ddi_strtoul(&sidstr[4], 0, 10, (unsigned long *)&sua); 503 sid->Authority[5] = (BYTE)sua; 504 #endif /* _KERNEL */ 505 506 for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) { 507 while (*p && *p == '-') 508 ++p; 509 510 if (*p < '0' || *p > '9') { 511 MEM_FREE("libnt", sid); 512 return (0); 513 } 514 515 #ifndef _KERNEL 516 sid->SubAuthority[i] = strtoul(p, 0, 10); 517 #else /* _KERNEL */ 518 sua = 0; 519 (void) ddi_strtoul(p, 0, 10, (unsigned long *)&sua); 520 sid->SubAuthority[i] = (DWORD)sua; 521 #endif /* _KERNEL */ 522 523 while (*p && *p != '-') 524 ++p; 525 } 526 527 sid->SubAuthCount = i; 528 return (sid); 529 } 530 531 532 /* 533 * nt_sid_name_use 534 * 535 * Returns the text name for a SID_NAME_USE value. The SID_NAME_USE 536 * provides the context for a SID, i.e. the type of resource to which 537 * it refers. 538 */ 539 char * 540 nt_sid_name_use(unsigned int snu_id) 541 { 542 static char *snu_name[] = { 543 "SidTypeSidPrefix", 544 "SidTypeUser", 545 "SidTypeGroup", 546 "SidTypeDomain", 547 "SidTypeAlias", 548 "SidTypeWellKnownGroup", 549 "SidTypeDeletedAccount", 550 "SidTypeInvalid", 551 "SidTypeUnknown" 552 }; 553 554 if (snu_id < ((sizeof (snu_name)/sizeof (snu_name[0])))) 555 return (snu_name[snu_id]); 556 else { 557 return (snu_name[SidTypeUnknown]); 558 } 559 } 560 561 562 /* 563 * nt_sid_copy 564 * 565 * Copy information of srcsid to dessid. The buffer should be allocated 566 * for dessid before passing to this function. The size of buffer for 567 * dessid should be specified in the buflen. 568 * 569 * Returns total bytes of information copied. If there is an error, 0 570 * will be returned. 571 */ 572 int 573 nt_sid_copy(nt_sid_t *dessid, nt_sid_t *srcsid, unsigned buflen) 574 { 575 unsigned n_bytes; 576 577 if (!dessid || !srcsid) 578 return (0); 579 580 n_bytes = nt_sid_length(srcsid); 581 if (n_bytes > buflen) 582 return (0); 583 584 bcopy((char *)srcsid, (char *)dessid, n_bytes); 585 586 return (n_bytes); 587 } 588