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