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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This module provides the high level interface to the LSA RPC functions. 28 */ 29 30 #include <strings.h> 31 #include <unistd.h> 32 33 #include <smbsrv/libsmb.h> 34 #include <smbsrv/libmlsvc.h> 35 #include <smbsrv/libsmbrdr.h> 36 #include <smbsrv/ntstatus.h> 37 #include <smbsrv/smbinfo.h> 38 #include <smbsrv/smb_token.h> 39 40 #include <lsalib.h> 41 42 static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *); 43 static uint32_t lsa_lookup_name_domain(char *, smb_account_t *); 44 45 static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *); 46 static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *); 47 48 static int lsa_list_accounts(mlsvc_handle_t *); 49 50 /* 51 * Lookup the given account and returns the account information 52 * in the passed smb_account_t structure. 53 * 54 * The lookup is performed in the following order: 55 * well known accounts 56 * local accounts 57 * domain accounts 58 * 59 * If it's established the given account is well know or local 60 * but the lookup fails for some reason, the next step(s) won't be 61 * performed. 62 * 63 * If the name is a domain account, it may refer to a user, group or 64 * alias. If it is a local account, its type should be specified 65 * in the sid_type parameter. In case the account type is unknown 66 * sid_type should be set to SidTypeUnknown. 67 * 68 * account argument could be either [domain\]name or [domain/]name. 69 * 70 * Return status: 71 * 72 * NT_STATUS_SUCCESS Account is successfully translated 73 * NT_STATUS_NONE_MAPPED Couldn't translate the account 74 */ 75 uint32_t 76 lsa_lookup_name(char *account, uint16_t type, smb_account_t *info) 77 { 78 char nambuf[SMB_USERNAME_MAXLEN]; 79 char dombuf[SMB_PI_MAX_DOMAIN]; 80 char *name, *domain; 81 uint32_t status; 82 char *slash; 83 84 (void) strsubst(account, '/', '\\'); 85 (void) strcanon(account, "\\"); 86 /* \john -> john */ 87 account += strspn(account, "\\"); 88 89 if ((slash = strchr(account, '\\')) != NULL) { 90 *slash = '\0'; 91 (void) strlcpy(dombuf, account, sizeof (dombuf)); 92 (void) strlcpy(nambuf, slash + 1, sizeof (nambuf)); 93 *slash = '\\'; 94 name = nambuf; 95 domain = dombuf; 96 } else { 97 name = account; 98 domain = NULL; 99 } 100 101 status = lsa_lookup_name_builtin(domain, name, info); 102 if (status == NT_STATUS_NOT_FOUND) { 103 status = smb_sam_lookup_name(domain, name, type, info); 104 if (status == NT_STATUS_SUCCESS) 105 return (status); 106 107 if ((domain == NULL) || (status == NT_STATUS_NOT_FOUND)) 108 status = lsa_lookup_name_domain(account, info); 109 } 110 111 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED); 112 } 113 114 uint32_t 115 lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info) 116 { 117 uint32_t status; 118 119 if (!smb_sid_isvalid(sid)) 120 return (NT_STATUS_INVALID_SID); 121 122 status = lsa_lookup_sid_builtin(sid, info); 123 if (status == NT_STATUS_NOT_FOUND) { 124 status = smb_sam_lookup_sid(sid, info); 125 if (status == NT_STATUS_NOT_FOUND) 126 status = lsa_lookup_sid_domain(sid, info); 127 } 128 129 return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED); 130 } 131 132 /* 133 * Obtains the primary domain SID and name from the specified server 134 * (domain controller). 135 * 136 * The requested information will be returned via 'info' argument. 137 * 138 * Returns NT status codes. 139 */ 140 DWORD 141 lsa_query_primary_domain_info(char *server, char *domain, 142 nt_domain_t *info) 143 { 144 mlsvc_handle_t domain_handle; 145 DWORD status; 146 char *user = smbrdr_ipc_get_user(); 147 148 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 149 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 150 151 status = lsar_query_info_policy(&domain_handle, 152 MSLSA_POLICY_PRIMARY_DOMAIN_INFO, info); 153 154 (void) lsar_close(&domain_handle); 155 return (status); 156 } 157 158 /* 159 * Obtains the account domain SID and name from the current server 160 * (domain controller). 161 * 162 * The requested information will be returned via 'info' argument. 163 * 164 * Returns NT status codes. 165 */ 166 DWORD 167 lsa_query_account_domain_info(char *server, char *domain, 168 nt_domain_t *info) 169 { 170 mlsvc_handle_t domain_handle; 171 DWORD status; 172 char *user = smbrdr_ipc_get_user(); 173 174 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 175 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 176 177 status = lsar_query_info_policy(&domain_handle, 178 MSLSA_POLICY_ACCOUNT_DOMAIN_INFO, info); 179 180 (void) lsar_close(&domain_handle); 181 return (status); 182 } 183 184 /* 185 * lsa_query_dns_domain_info 186 * 187 * Obtains the DNS domain info from the specified server 188 * (domain controller). 189 * 190 * The requested information will be returned via 'info' argument. 191 * 192 * Returns NT status codes. 193 */ 194 DWORD 195 lsa_query_dns_domain_info(char *server, char *domain, nt_domain_t *info) 196 { 197 mlsvc_handle_t domain_handle; 198 DWORD status; 199 char *user = smbrdr_ipc_get_user(); 200 201 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 202 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 203 204 status = lsar_query_info_policy(&domain_handle, 205 MSLSA_POLICY_DNS_DOMAIN_INFO, info); 206 207 (void) lsar_close(&domain_handle); 208 return (status); 209 } 210 211 /* 212 * Enumerate the trusted domains of primary domain. 213 * This is the basic enumaration call which only returns the 214 * NetBIOS name of the domain and its SID. 215 * 216 * The requested information will be returned via 'info' argument. 217 * 218 * Returns NT status codes. 219 */ 220 DWORD 221 lsa_enum_trusted_domains(char *server, char *domain, 222 smb_trusted_domains_t *info) 223 { 224 mlsvc_handle_t domain_handle; 225 DWORD enum_context; 226 DWORD status; 227 char *user = smbrdr_ipc_get_user(); 228 229 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 230 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 231 232 enum_context = 0; 233 234 status = lsar_enum_trusted_domains(&domain_handle, &enum_context, info); 235 if (status == MLSVC_NO_MORE_DATA) { 236 /* 237 * MLSVC_NO_MORE_DATA indicates that we 238 * have all of the available information. 239 */ 240 status = NT_STATUS_SUCCESS; 241 } 242 243 (void) lsar_close(&domain_handle); 244 return (status); 245 } 246 247 /* 248 * Enumerate the trusted domains of the primary domain. 249 * This is the extended enumaration call which besides 250 * NetBIOS name of the domain and its SID, it will return 251 * the FQDN plus some trust information which is not used. 252 * 253 * The requested information will be returned via 'info' argument. 254 * 255 * Returns NT status codes. 256 */ 257 DWORD 258 lsa_enum_trusted_domains_ex(char *server, char *domain, 259 smb_trusted_domains_t *info) 260 { 261 mlsvc_handle_t domain_handle; 262 DWORD enum_context; 263 DWORD status; 264 char *user = smbrdr_ipc_get_user(); 265 266 if ((lsar_open(server, domain, user, &domain_handle)) != 0) 267 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 268 269 enum_context = 0; 270 271 status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context, 272 info); 273 if (status == MLSVC_NO_MORE_DATA) { 274 /* 275 * MLSVC_NO_MORE_DATA indicates that we 276 * have all of the available information. 277 */ 278 status = NT_STATUS_SUCCESS; 279 } 280 281 (void) lsar_close(&domain_handle); 282 return (status); 283 } 284 285 /* 286 * Lookup well known accounts table 287 * 288 * Return status: 289 * 290 * NT_STATUS_SUCCESS Account is translated successfully 291 * NT_STATUS_NOT_FOUND This is not a well known account 292 * NT_STATUS_NONE_MAPPED Account is found but domains don't match 293 * NT_STATUS_NO_MEMORY Memory shortage 294 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure 295 */ 296 static uint32_t 297 lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info) 298 { 299 smb_wka_t *wka; 300 char *wkadom; 301 302 bzero(info, sizeof (smb_account_t)); 303 304 if ((wka = smb_wka_lookup_name(name)) == NULL) 305 return (NT_STATUS_NOT_FOUND); 306 307 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) 308 return (NT_STATUS_INTERNAL_ERROR); 309 310 if ((domain != NULL) && (utf8_strcasecmp(domain, wkadom) != 0)) 311 return (NT_STATUS_NONE_MAPPED); 312 313 info->a_name = strdup(name); 314 info->a_sid = smb_sid_dup(wka->wka_binsid); 315 info->a_domain = strdup(wkadom); 316 info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid); 317 info->a_type = wka->wka_type; 318 319 if (!smb_account_validate(info)) { 320 smb_account_free(info); 321 return (NT_STATUS_NO_MEMORY); 322 } 323 324 return (NT_STATUS_SUCCESS); 325 } 326 327 /* 328 * Lookup the given account in domain. 329 * 330 * The information is returned in the user_info structure. 331 * The caller is responsible for allocating and releasing 332 * this structure. 333 */ 334 static uint32_t 335 lsa_lookup_name_domain(char *account_name, smb_account_t *info) 336 { 337 mlsvc_handle_t domain_handle; 338 smb_domain_t dinfo; 339 char *user = smbrdr_ipc_get_user(); 340 uint32_t status; 341 342 if (!smb_domain_getinfo(&dinfo)) 343 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 344 345 if (lsar_open(dinfo.d_dc, dinfo.d_info.di_nbname, user, 346 &domain_handle) != 0) 347 return (NT_STATUS_INVALID_PARAMETER); 348 349 status = lsar_lookup_names2(&domain_handle, account_name, info); 350 if (status == NT_STATUS_REVISION_MISMATCH) { 351 /* 352 * Not a Windows 2000 domain controller: 353 * use the NT compatible call. 354 */ 355 status = lsar_lookup_names(&domain_handle, account_name, info); 356 } 357 358 (void) lsar_close(&domain_handle); 359 return (status); 360 } 361 362 /* 363 * lsa_lookup_privs 364 * 365 * Request the privileges associated with the specified account. In 366 * order to get the privileges, we first have to lookup the name on 367 * the specified domain controller and obtain the appropriate SID. 368 * The SID can then be used to open the account and obtain the 369 * account privileges. The results from both the name lookup and the 370 * privileges are returned in the user_info structure. The caller is 371 * responsible for allocating and releasing this structure. 372 * 373 * On success 0 is returned. Otherwise a -ve error code. 374 */ 375 /*ARGSUSED*/ 376 int 377 lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo) 378 { 379 mlsvc_handle_t domain_handle; 380 int rc; 381 char *user = smbrdr_ipc_get_user(); 382 smb_domain_t dinfo; 383 384 if (!smb_domain_getinfo(&dinfo)) 385 return (-1); 386 387 if ((lsar_open(dinfo.d_dc, dinfo.d_info.di_nbname, user, 388 &domain_handle)) != 0) 389 return (-1); 390 391 rc = lsa_list_accounts(&domain_handle); 392 (void) lsar_close(&domain_handle); 393 return (rc); 394 } 395 396 /* 397 * lsa_list_privs 398 * 399 * List the privileges supported by the specified server. 400 * This function is only intended for diagnostics. 401 * 402 * Returns NT status codes. 403 */ 404 DWORD 405 lsa_list_privs(char *server, char *domain) 406 { 407 static char name[128]; 408 static struct ms_luid luid; 409 mlsvc_handle_t domain_handle; 410 int rc; 411 int i; 412 char *user = smbrdr_ipc_get_user(); 413 414 rc = lsar_open(server, domain, user, &domain_handle); 415 if (rc != 0) 416 return (NT_STATUS_INVALID_PARAMETER); 417 418 for (i = 0; i < 30; ++i) { 419 luid.low_part = i; 420 rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128); 421 if (rc != 0) 422 continue; 423 424 (void) lsar_lookup_priv_value(&domain_handle, name, &luid); 425 (void) lsar_lookup_priv_display_name(&domain_handle, name, 426 name, 128); 427 } 428 429 (void) lsar_close(&domain_handle); 430 return (NT_STATUS_SUCCESS); 431 } 432 433 /* 434 * lsa_list_accounts 435 * 436 * This function can be used to list the accounts in the specified 437 * domain. For now the SIDs are just listed in the system log. 438 * 439 * On success 0 is returned. Otherwise a -ve error code. 440 */ 441 static int 442 lsa_list_accounts(mlsvc_handle_t *domain_handle) 443 { 444 mlsvc_handle_t account_handle; 445 struct mslsa_EnumAccountBuf accounts; 446 struct mslsa_sid *sid; 447 smb_account_t ainfo; 448 DWORD enum_context = 0; 449 int rc; 450 int i; 451 452 bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf)); 453 454 do { 455 rc = lsar_enum_accounts(domain_handle, &enum_context, 456 &accounts); 457 if (rc != 0) 458 return (rc); 459 460 for (i = 0; i < accounts.entries_read; ++i) { 461 sid = accounts.info[i].sid; 462 463 if (lsar_open_account(domain_handle, sid, 464 &account_handle) == 0) { 465 (void) lsar_enum_privs_account(&account_handle, 466 &ainfo); 467 (void) lsar_close(&account_handle); 468 } 469 470 free(accounts.info[i].sid); 471 } 472 473 if (accounts.info) 474 free(accounts.info); 475 } while (rc == 0 && accounts.entries_read != 0); 476 477 return (0); 478 } 479 480 /* 481 * Lookup well known accounts table for the given SID 482 * 483 * Return status: 484 * 485 * NT_STATUS_SUCCESS Account is translated successfully 486 * NT_STATUS_NOT_FOUND This is not a well known account 487 * NT_STATUS_NO_MEMORY Memory shortage 488 * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure 489 */ 490 static uint32_t 491 lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo) 492 { 493 smb_wka_t *wka; 494 char *wkadom; 495 496 bzero(ainfo, sizeof (smb_account_t)); 497 498 if ((wka = smb_wka_lookup_sid(sid)) == NULL) 499 return (NT_STATUS_NOT_FOUND); 500 501 if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) 502 return (NT_STATUS_INTERNAL_ERROR); 503 504 ainfo->a_name = strdup(wka->wka_name); 505 ainfo->a_sid = smb_sid_dup(wka->wka_binsid); 506 ainfo->a_domain = strdup(wkadom); 507 ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid); 508 ainfo->a_type = wka->wka_type; 509 510 if (!smb_account_validate(ainfo)) { 511 smb_account_free(ainfo); 512 return (NT_STATUS_NO_MEMORY); 513 } 514 515 return (NT_STATUS_SUCCESS); 516 } 517 518 static uint32_t 519 lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo) 520 { 521 mlsvc_handle_t domain_handle; 522 char *user = smbrdr_ipc_get_user(); 523 uint32_t status; 524 smb_domain_t dinfo; 525 526 if (!smb_domain_getinfo(&dinfo)) 527 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); 528 529 if (lsar_open(dinfo.d_dc, dinfo.d_info.di_nbname, user, 530 &domain_handle) != 0) 531 return (NT_STATUS_INVALID_PARAMETER); 532 533 status = lsar_lookup_sids2(&domain_handle, (struct mslsa_sid *)sid, 534 ainfo); 535 536 if (status == NT_STATUS_REVISION_MISMATCH) { 537 /* 538 * Not a Windows 2000 domain controller: 539 * use the NT compatible call. 540 */ 541 status = lsar_lookup_sids(&domain_handle, 542 (struct mslsa_sid *)sid, ainfo); 543 } 544 545 (void) lsar_close(&domain_handle); 546 return (status); 547 } 548