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