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  * This module provides the high level interface to the LSA RPC functions.
30  */
31 
32 #include <strings.h>
33 #include <unistd.h>
34 #include <netdb.h>
35 
36 #include <smbsrv/libsmb.h>
37 #include <smbsrv/libsmbns.h>
38 #include <smbsrv/libmlsvc.h>
39 #include <smbsrv/libsmbrdr.h>
40 #include <smbsrv/lsalib.h>
41 #include <smbsrv/ntstatus.h>
42 #include <smbsrv/smbinfo.h>
43 #include <smbsrv/ntsid.h>
44 #include <smbsrv/smb_token.h>
45 
46 static int lsa_list_accounts(mlsvc_handle_t *);
47 
48 /*
49  * lsa_query_primary_domain_info
50  *
51  * Obtains the primary domain SID and name from the specified server
52  * (domain controller). The information is stored in the NT domain
53  * database by the lower level lsar_query_info_policy call. The caller
54  * should query the database to obtain a reference to the primary
55  * domain information.
56  *
57  * Returns NT status codes.
58  */
59 DWORD
60 lsa_query_primary_domain_info(void)
61 {
62 	mlsvc_handle_t domain_handle;
63 	DWORD status;
64 	char *user = smbrdr_ipc_get_user();
65 
66 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
67 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
68 
69 	status = lsar_query_info_policy(&domain_handle,
70 	    MSLSA_POLICY_PRIMARY_DOMAIN_INFO);
71 
72 	(void) lsar_close(&domain_handle);
73 	return (status);
74 }
75 
76 /*
77  * lsa_query_account_domain_info
78  *
79  * Obtains the account domain SID and name from the current server
80  * (domain controller). The information is stored in the NT domain
81  * database by the lower level lsar_query_info_policy call. The caller
82  * should query the database to obtain a reference to the account
83  * domain information.
84  *
85  * Returns NT status codes.
86  */
87 DWORD
88 lsa_query_account_domain_info(void)
89 {
90 	mlsvc_handle_t domain_handle;
91 	DWORD status;
92 	char *user = smbrdr_ipc_get_user();
93 
94 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
95 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
96 
97 	status = lsar_query_info_policy(&domain_handle,
98 	    MSLSA_POLICY_ACCOUNT_DOMAIN_INFO);
99 
100 	(void) lsar_close(&domain_handle);
101 	return (status);
102 }
103 
104 /*
105  * lsa_enum_trusted_domains
106  *
107  * Enumerate the trusted domains in our primary domain. The information
108  * is stored in the NT domain database by the lower level
109  * lsar_enum_trusted_domains call. The caller should query the database
110  * to obtain a reference to the trusted domain information.
111  *
112  * Returns NT status codes.
113  */
114 DWORD
115 lsa_enum_trusted_domains(void)
116 {
117 	mlsvc_handle_t domain_handle;
118 	DWORD enum_context;
119 	DWORD status;
120 	char *user = smbrdr_ipc_get_user();
121 
122 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
123 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
124 
125 	enum_context = 0;
126 
127 	status = lsar_enum_trusted_domains(&domain_handle, &enum_context);
128 	if (status == MLSVC_NO_MORE_DATA) {
129 		/*
130 		 * MLSVC_NO_MORE_DATA indicates that we
131 		 * have all of the available information.
132 		 */
133 		status = NT_STATUS_SUCCESS;
134 	}
135 
136 	(void) lsar_close(&domain_handle);
137 	return (status);
138 }
139 
140 /*
141  * lsa_test_lookup
142  *
143  * Test routine for lsa_lookup_name and lsa_lookup_sid.
144  */
145 void
146 lsa_test_lookup(char *name)
147 {
148 	smb_userinfo_t *user_info;
149 	nt_sid_t *sid;
150 	DWORD status;
151 	smb_ntdomain_t *di;
152 
153 	if ((di = smb_getdomaininfo(0)) == 0)
154 		return;
155 
156 	user_info = mlsvc_alloc_user_info();
157 
158 	if (lsa_lookup_builtin_name(name, user_info) != 0) {
159 		status = lsa_lookup_name(di->server, di->domain, name,
160 		    user_info);
161 
162 		if (status == 0) {
163 			sid = nt_sid_splice(user_info->domain_sid,
164 			    user_info->rid);
165 
166 			(void) lsa_lookup_sid(sid, user_info);
167 			free(sid);
168 		}
169 	}
170 
171 	mlsvc_free_user_info(user_info);
172 }
173 
174 /*
175  * lsa_lookup_builtin_name
176  *
177  * lookup builtin account table to see if account_name is
178  * there. If it is there, set sid_name_use, domain_sid,
179  * domain_name, and rid fields of the passed user_info
180  * structure and return 0. If lookup fails return 1.
181  */
182 int
183 lsa_lookup_builtin_name(char *account_name, smb_userinfo_t *user_info)
184 {
185 	char *domain;
186 	int res;
187 
188 	user_info->domain_sid = nt_builtin_lookup_name(account_name,
189 	    &user_info->sid_name_use);
190 
191 	if (user_info->domain_sid == 0)
192 		return (1);
193 
194 	res = nt_sid_split(user_info->domain_sid, &user_info->rid);
195 	if (res < 0)
196 		return (1);
197 
198 	domain = nt_builtin_lookup_domain(account_name);
199 	if (domain) {
200 		user_info->domain_name = strdup(domain);
201 		return (0);
202 	}
203 
204 	return (1);
205 }
206 
207 /*
208  * lsa_lookup_local_sam
209  *
210  * lookup for the given account name in the local SAM database.
211  * Returns 0 on success. If lookup fails return 1.
212  */
213 int
214 lsa_lookup_local_sam(char *domain, char *account_name,
215     smb_userinfo_t *user_info)
216 {
217 	nt_group_t *grp;
218 
219 	if (*domain == '\0' || *account_name == '\0')
220 		return (1);
221 
222 	grp = nt_group_getinfo(account_name, RWLOCK_READER);
223 	if (grp == 0)
224 		return (1);
225 
226 	user_info->sid_name_use = *grp->sid_name_use;
227 	user_info->domain_sid = nt_sid_dup(grp->sid);
228 	nt_group_putinfo(grp);
229 
230 	if (user_info->domain_sid == 0)
231 		return (1);
232 
233 	(void) nt_sid_split(user_info->domain_sid, &user_info->rid);
234 	user_info->domain_name = strdup(domain);
235 
236 	if (user_info->domain_name == 0) {
237 		free(user_info->domain_sid);
238 		user_info->domain_sid = 0;
239 		return (1);
240 	}
241 
242 	return (0);
243 }
244 
245 /*
246  * lsa_lookup_local
247  *
248  * if given account name has domain part, check to see if
249  * it matches with host name or any of host's primary addresses.
250  * if any match found first lookup in builtin accounts table and
251  * then in local SAM table.
252  *
253  * if account name doesn't have domain part, first do local lookups
254  * if nothing is found return 1. This means that caller function should
255  * do domain lookup.
256  * if any error happened return -1, if name is found return 0.
257  */
258 int
259 lsa_lookup_local(char *name, smb_userinfo_t *user_info)
260 {
261 	char hostname[MAXHOSTNAMELEN];
262 	int res = 0;
263 	int local_lookup = 0;
264 	char *tmp;
265 	net_cfg_t cfg;
266 	uint32_t addr;
267 
268 	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
269 		return (-1);
270 
271 	tmp = strchr(name, '\\');
272 	if (tmp != 0) {
273 		*tmp = 0;
274 		if (strcasecmp(name, hostname) == 0)
275 			local_lookup = 1;
276 
277 		if (!local_lookup) {
278 			addr = inet_addr(name);
279 			if (smb_nic_get_byip(addr, &cfg) != NULL) {
280 				local_lookup = 1;
281 			}
282 		}
283 
284 		if (!local_lookup) {
285 			/* do domain lookup */
286 			*tmp = '\\';
287 			return (1);
288 		}
289 
290 		name = tmp + 1;
291 		local_lookup = 1;
292 	}
293 
294 	res = lsa_lookup_builtin_name(name, user_info);
295 	if (res != 0)
296 		res = lsa_lookup_local_sam(hostname, name, user_info);
297 
298 	if (res == 0)
299 		return (0);
300 
301 	if (local_lookup)
302 		return (-1);
303 
304 	return (1);
305 }
306 
307 /*
308  * lsa_lookup_name
309  *
310  * Lookup a name on the specified server (domain controller) and obtain
311  * the appropriate SID. The information is returned in the user_info
312  * structure. The caller is responsible for allocating and releasing
313  * this structure. On success sid_name_use will be set to indicate the
314  * type of SID. If the name is the domain name, this function will be
315  * identical to lsa_domain_info. Otherwise the rid and name fields will
316  * also be valid. On failure sid_name_use will be set to SidTypeUnknown.
317  *
318  * On success 0 is returned. Otherwise a -ve error code.
319  */
320 int lsa_lookup_name(char *server, char *domain, char *account_name,
321     smb_userinfo_t *user_info)
322 {
323 	mlsvc_handle_t domain_handle;
324 	int rc;
325 	char *user = smbrdr_ipc_get_user();
326 
327 	rc = lsar_open(server, domain, user, &domain_handle);
328 	if (rc != 0)
329 		return (-1);
330 
331 	rc = lsar_lookup_names(&domain_handle, account_name, user_info);
332 
333 	(void) lsar_close(&domain_handle);
334 	return (rc);
335 }
336 
337 /*
338  * lsa_lookup_name2
339  *
340  * Returns NT status codes.
341  */
342 DWORD lsa_lookup_name2(char *server, char *domain, char *account_name,
343     smb_userinfo_t *user_info)
344 {
345 	mlsvc_handle_t domain_handle;
346 	DWORD status;
347 	int rc;
348 	char *user = smbrdr_ipc_get_user();
349 
350 	rc = lsar_open(server, domain, user, &domain_handle);
351 	if (rc != 0)
352 		return (NT_STATUS_INVALID_PARAMETER);
353 
354 	status = lsar_lookup_names2(&domain_handle, account_name, user_info);
355 	if (status == NT_STATUS_REVISION_MISMATCH) {
356 		/*
357 		 * Not a Windows 2000 domain controller:
358 		 * use the NT compatible call.
359 		 */
360 		if (lsar_lookup_names(&domain_handle, account_name,
361 		    user_info) != 0)
362 			status = NT_STATUS_NONE_MAPPED;
363 		else
364 			status = 0;
365 	}
366 
367 	(void) lsar_close(&domain_handle);
368 	return (status);
369 }
370 
371 /*
372  * lsa_lookup_sid
373  *
374  * Lookup a SID on the specified server (domain controller) and obtain
375  * the appropriate name. The information is returned in the user_info
376  * structure. The caller is responsible for allocating and releasing
377  * this structure. On success sid_name_use will be set to indicate the
378  * type of SID. On failure sid_name_use will be set to SidTypeUnknown.
379  *
380  * On success 0 is returned. Otherwise a -ve error code.
381  */
382 int
383 lsa_lookup_sid(nt_sid_t *sid, smb_userinfo_t *user_info)
384 {
385 	mlsvc_handle_t domain_handle;
386 	int rc;
387 	char *user = smbrdr_ipc_get_user();
388 
389 	rc = lsar_open(NULL, NULL, user, &domain_handle);
390 	if (rc != 0)
391 		return (-1);
392 
393 	rc = lsar_lookup_sids(&domain_handle,
394 	    (struct mslsa_sid *)sid, user_info);
395 
396 	(void) lsar_close(&domain_handle);
397 	return (rc);
398 }
399 
400 /*
401  * lsa_lookup_sid2
402  *
403  * Returns NT status codes.
404  */
405 DWORD
406 lsa_lookup_sid2(nt_sid_t *sid, smb_userinfo_t *user_info)
407 {
408 	mlsvc_handle_t domain_handle;
409 	DWORD status;
410 	int rc;
411 	char *user = smbrdr_ipc_get_user();
412 
413 	rc = lsar_open(NULL, NULL, user, &domain_handle);
414 	if (rc != 0)
415 		return (NT_STATUS_INVALID_PARAMETER);
416 
417 	status = lsar_lookup_sids2(&domain_handle,
418 	    (struct mslsa_sid *)sid, user_info);
419 
420 	if (status == NT_STATUS_REVISION_MISMATCH) {
421 		/*
422 		 * Not a Windows 2000 domain controller:
423 		 * use the NT compatible call.
424 		 */
425 		if (lsar_lookup_sids(&domain_handle, (struct mslsa_sid *)sid,
426 		    user_info) != 0)
427 			status = NT_STATUS_NONE_MAPPED;
428 		else
429 			status = 0;
430 	}
431 
432 	(void) lsar_close(&domain_handle);
433 	return (status);
434 }
435 
436 /*
437  * lsa_test_lookup2
438  *
439  * Test routine for lsa_lookup_name2 and lsa_lookup_sid2.
440  */
441 void
442 lsa_test_lookup2(char *name)
443 {
444 	smb_userinfo_t *user_info;
445 	nt_sid_t *sid;
446 	DWORD status;
447 	smb_ntdomain_t *di;
448 
449 	if ((di = smb_getdomaininfo(0)) == 0)
450 		return;
451 
452 	user_info = mlsvc_alloc_user_info();
453 
454 	if (lsa_lookup_builtin_name(name, user_info) != 0) {
455 		status = lsa_lookup_name2(di->server, di->domain, name,
456 		    user_info);
457 
458 		if (status == 0) {
459 			sid = nt_sid_splice(user_info->domain_sid,
460 			    user_info->rid);
461 
462 			(void) lsa_lookup_sid2(sid, user_info);
463 			free(sid);
464 		}
465 	}
466 
467 	mlsvc_free_user_info(user_info);
468 }
469 
470 /*
471  * lsa_lookup_privs
472  *
473  * Request the privileges associated with the specified account. In
474  * order to get the privileges, we first have to lookup the name on
475  * the specified domain controller and obtain the appropriate SID.
476  * The SID can then be used to open the account and obtain the
477  * account privileges. The results from both the name lookup and the
478  * privileges are returned in the user_info structure. The caller is
479  * responsible for allocating and releasing this structure.
480  *
481  * On success 0 is returned. Otherwise a -ve error code.
482  */
483 /*ARGSUSED*/
484 int
485 lsa_lookup_privs(char *server, char *account_name, char *target_name,
486     smb_userinfo_t *user_info)
487 {
488 	mlsvc_handle_t domain_handle;
489 	int rc;
490 	char *user = smbrdr_ipc_get_user();
491 
492 	if ((lsar_open(NULL, NULL, user, &domain_handle)) != 0)
493 		return (-1);
494 
495 	rc = lsa_list_accounts(&domain_handle);
496 	(void) lsar_close(&domain_handle);
497 	return (rc);
498 }
499 
500 /*
501  * lsa_list_privs
502  *
503  * List the privileges supported by the specified server.
504  * This function is only intended for diagnostics.
505  *
506  * Returns NT status codes.
507  */
508 DWORD
509 lsa_list_privs(char *server, char *domain)
510 {
511 	static char name[128];
512 	static struct ms_luid luid;
513 	mlsvc_handle_t domain_handle;
514 	int rc;
515 	int i;
516 	char *user = smbrdr_ipc_get_user();
517 
518 	rc = lsar_open(server, domain, user, &domain_handle);
519 	if (rc != 0)
520 		return (NT_STATUS_INVALID_PARAMETER);
521 
522 	for (i = 0; i < 30; ++i) {
523 		luid.low_part = i;
524 		rc = lsar_lookup_priv_name(&domain_handle, &luid, name, 128);
525 		if (rc != 0)
526 			continue;
527 
528 		(void) lsar_lookup_priv_value(&domain_handle, name, &luid);
529 		(void) lsar_lookup_priv_display_name(&domain_handle, name,
530 		    name, 128);
531 	}
532 
533 	(void) lsar_close(&domain_handle);
534 	return (NT_STATUS_SUCCESS);
535 }
536 
537 /*
538  * lsa_test
539  *
540  * LSA test routine: open and close the LSA interface.
541  * TBD: the parameters should be server and domain.
542  *
543  * On success 0 is returned. Otherwise a -ve error code.
544  */
545 /*ARGSUSED*/
546 int
547 lsa_test(char *server, char *account_name)
548 {
549 	mlsvc_handle_t domain_handle;
550 	int rc;
551 	char *user = smbrdr_ipc_get_user();
552 
553 	rc = lsar_open(NULL, NULL, user, &domain_handle);
554 	if (rc != 0)
555 		return (-1);
556 
557 	if (lsar_close(&domain_handle) != 0)
558 		return (-1);
559 
560 	return (0);
561 }
562 
563 /*
564  * lsa_list_accounts
565  *
566  * This function can be used to list the accounts in the specified
567  * domain. For now the SIDs are just listed in the system log.
568  *
569  * On success 0 is returned. Otherwise a -ve error code.
570  */
571 static int
572 lsa_list_accounts(mlsvc_handle_t *domain_handle)
573 {
574 	mlsvc_handle_t account_handle;
575 	struct mslsa_EnumAccountBuf accounts;
576 	struct mslsa_sid *sid;
577 	char *name;
578 	WORD sid_name_use;
579 	smb_userinfo_t *user_info;
580 	DWORD enum_context = 0;
581 	int rc;
582 	int i;
583 
584 	user_info = mlsvc_alloc_user_info();
585 	bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
586 
587 	do {
588 		rc = lsar_enum_accounts(domain_handle, &enum_context,
589 		    &accounts);
590 		if (rc != 0)
591 			return (rc);
592 
593 		for (i = 0; i < accounts.entries_read; ++i) {
594 			sid = accounts.info[i].sid;
595 
596 			name = nt_builtin_lookup_sid((nt_sid_t *)sid,
597 			    &sid_name_use);
598 
599 			if (name == 0) {
600 				if (lsar_lookup_sids(domain_handle, sid,
601 				    user_info) == 0) {
602 					name = user_info->name;
603 					sid_name_use = user_info->sid_name_use;
604 				} else {
605 					name = "unknown";
606 					sid_name_use = SidTypeUnknown;
607 				}
608 			}
609 
610 			nt_sid_logf((nt_sid_t *)sid);
611 
612 			if (lsar_open_account(domain_handle, sid,
613 			    &account_handle) == 0) {
614 				(void) lsar_enum_privs_account(&account_handle,
615 				    user_info);
616 				(void) lsar_close(&account_handle);
617 			}
618 
619 			free(accounts.info[i].sid);
620 			mlsvc_release_user_info(user_info);
621 		}
622 
623 		if (accounts.info)
624 			free(accounts.info);
625 	} while (rc == 0 && accounts.entries_read != 0);
626 
627 	mlsvc_free_user_info(user_info);
628 	return (0);
629 }
630