xref: /titanic_51/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision 1ba18ff1efb9bb19540297cbee0a824685da1622)
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  * Utility functions to support the RPC interface library.
30  */
31 
32 #include <stdio.h>
33 #include <stdarg.h>
34 #include <strings.h>
35 #include <unistd.h>
36 #include <netdb.h>
37 #include <stdlib.h>
38 #include <pwd.h>
39 #include <grp.h>
40 
41 #include <sys/time.h>
42 #include <sys/systm.h>
43 
44 #include <smbsrv/libsmb.h>
45 #include <smbsrv/libsmbrdr.h>
46 #include <smbsrv/libsmbns.h>
47 #include <smbsrv/libmlsvc.h>
48 
49 #include <smbsrv/smbinfo.h>
50 #include <smbsrv/ntsid.h>
51 #include <smbsrv/lsalib.h>
52 #include <smbsrv/samlib.h>
53 #include <smbsrv/mlsvc_util.h>
54 #include <smbsrv/mlsvc.h>
55 
56 extern int netr_open(char *, char *, mlsvc_handle_t *);
57 extern int netr_close(mlsvc_handle_t *);
58 extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
59 extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *);
60 
61 static int mlsvc_lookup_local_name(char *name, nt_sid_t **sid);
62 static int mlsvc_lookup_nt_name(char *name, nt_sid_t **sid);
63 static int mlsvc_lookup_nt_sid(nt_sid_t *sid, char *buf, int bufsize);
64 
65 /*
66  * Compare the supplied domain name with the local hostname.
67  * We need to deal with both server names and fully-qualified
68  * domain names.
69  *
70  * Returns:
71  *	0	The specified domain is not the local domain,
72  *	1	The Specified domain is the local domain.
73  *	-1	Invalid parameter or unable to get the local
74  *		system information.
75  */
76 int
77 mlsvc_is_local_domain(const char *domain)
78 {
79 	char hostname[MAXHOSTNAMELEN];
80 	uint32_t mode;
81 	int rc;
82 
83 	if (strchr(domain, '.') != NULL)
84 		rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
85 	else
86 		rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
87 
88 	if (rc != 0)
89 		return (-1);
90 
91 	rc = strcasecmp(domain, hostname);
92 	mode = smb_get_security_mode();
93 
94 	if ((rc == 0) || (mode == SMB_SECMODE_WORKGRP))
95 		return (1);
96 
97 	return (0);
98 }
99 
100 /*
101  * mlsvc_lookup_name
102  *
103  * Lookup a name in the specified domain and translate it to a SID.
104  * If the name is in the NT domain, it may refer to a user, group or
105  * alias. Otherwise it must refer to a UNIX username. The memory for
106  * the sid is allocated using malloc so the caller should call free
107  * when it is no longer required.
108  *
109  * On success, 0 will be returned and sid will point to a local domain
110  * user SID. Otherwise -1 will be returned.
111  */
112 int
113 mlsvc_lookup_name(char *domain, char *name, nt_sid_t **sid)
114 {
115 	if (domain == NULL || name == NULL || sid == NULL)
116 		return (-1);
117 
118 	if (mlsvc_is_local_domain(domain) == 1)
119 		return (mlsvc_lookup_local_name(name, sid));
120 	else
121 		return (mlsvc_lookup_nt_name(name, sid));
122 }
123 
124 /*
125  * mlsvc_lookup_local_name
126  *
127  * Lookup a name in the local password file and translate it to a SID.
128  * The name must refer to a user. This is a private function intended
129  * to support mlsvc_lookup_name so it doesn't perform any parameter
130  * validation. The memory for the sid is allocated using malloc so the
131  * caller must call free when it is no longer required.
132  *
133  * On success, 0 will be returned and sid will point to a local domain
134  * user SID. Otherwise -1 will be returned.
135  */
136 static int
137 mlsvc_lookup_local_name(char *name, nt_sid_t **sid)
138 {
139 	struct passwd *pw;
140 	nt_sid_t *domain_sid;
141 
142 	if ((pw = getpwnam(name)) == NULL)
143 		return (-1);
144 
145 	if ((domain_sid = nt_domain_local_sid()) == NULL)
146 		return (-1);
147 
148 	*sid = nt_sid_splice(domain_sid, pw->pw_uid);
149 	return (0);
150 }
151 
152 /*
153  * mlsvc_lookup_nt_name
154  *
155  * Lookup a name in the specified NT domain and translate it to a SID.
156  * The name may refer to a user, group or alias. This is a private
157  * function intended to support mlsvc_lookup_name so it doesn't do any
158  * parameter validation. The memory for the sid is allocated using
159  * malloc so the caller should call free when it is no longer required.
160  *
161  * On success, 0 will be returned and sid will point to an NT domain
162  * user SID. Otherwise -1 will be returned.
163  */
164 static int
165 mlsvc_lookup_nt_name(char *name, nt_sid_t **sid)
166 {
167 	smb_userinfo_t *user_info;
168 
169 	if ((user_info = mlsvc_alloc_user_info()) == NULL)
170 		return (-1);
171 
172 	if (lsa_lookup_name(0, 0, name, user_info) != 0)
173 		return (-1);
174 
175 	*sid = nt_sid_splice(user_info->domain_sid, user_info->rid);
176 	mlsvc_free_user_info(user_info);
177 	return (0);
178 }
179 
180 /*
181  * mlsvc_lookup_sid
182  *
183  * Lookup a SID and translate it to a name. The name returned may refer
184  * to a domain, user, group or alias dependent on the SID. On success 0
185  * will be returned. Otherwise -1 will be returned.
186  */
187 int
188 mlsvc_lookup_sid(nt_sid_t *sid, char *buf, int bufsize)
189 {
190 	struct passwd *pw;
191 	struct group *gr;
192 	nt_group_t *grp;
193 	DWORD rid;
194 
195 	if (sid == NULL || buf == NULL)
196 		return (-1);
197 
198 	if (nt_sid_is_local(sid)) {
199 		(void) nt_sid_get_rid(sid, &rid);
200 
201 		switch (SAM_RID_TYPE(rid)) {
202 		case SAM_RT_NT_UID:
203 			break;
204 
205 		case SAM_RT_NT_GID:
206 			if ((grp = nt_groups_lookup_rid(rid)) == NULL)
207 				return (-1);
208 
209 			(void) strlcpy(buf, grp->name, bufsize);
210 			break;
211 
212 		case SAM_RT_UNIX_UID:
213 			if ((pw = getpwuid(SAM_DECODE_RID(rid))) == NULL)
214 				return (-1);
215 
216 			(void) strlcpy(buf, pw->pw_name, bufsize);
217 			break;
218 
219 		case SAM_RT_UNIX_GID:
220 			if ((gr = getgrgid(SAM_DECODE_RID(rid))) == NULL)
221 				return (-1);
222 
223 			(void) strlcpy(buf, gr->gr_name, bufsize);
224 			break;
225 		}
226 
227 		return (0);
228 	}
229 
230 	return (mlsvc_lookup_nt_sid(sid, buf, bufsize));
231 }
232 
233 /*
234  * mlsvc_lookup_nt_sid
235  *
236  * Lookup an NT SID and translate it to a name. This is a private
237  * function intended to support mlsvc_lookup_sid so it doesn't do any
238  * parameter validation. The input account_name specifies the logon/
239  * session to be used for the lookup. It doesn't need to have any
240  * association with the SID being looked up. The name returned may
241  * refer to a domain, user, group or alias dependent on the SID.
242  *
243  * On success the name will be copied into buf and 0 will be returned.
244  * Otherwise -1 will be returned.
245  */
246 static int
247 mlsvc_lookup_nt_sid(nt_sid_t *sid, char *buf, int bufsize)
248 {
249 	smb_userinfo_t *user_info;
250 	int rc;
251 
252 	if ((user_info = mlsvc_alloc_user_info()) == NULL)
253 		return (-1);
254 
255 	if ((rc = lsa_lookup_sid(sid, user_info)) == 0)
256 		(void) strlcpy(buf, user_info->name, bufsize);
257 
258 	mlsvc_free_user_info(user_info);
259 	return (rc);
260 }
261 
262 /*
263  * mlsvc_alloc_user_info
264  *
265  * Allocate a user_info structure and set the contents to zero. A
266  * pointer to the user_info structure is returned.
267  */
268 smb_userinfo_t *
269 mlsvc_alloc_user_info(void)
270 {
271 	smb_userinfo_t *user_info;
272 
273 	user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
274 	if (user_info == NULL)
275 		return (NULL);
276 
277 	bzero(user_info, sizeof (smb_userinfo_t));
278 	return (user_info);
279 }
280 
281 /*
282  * mlsvc_free_user_info
283  *
284  * Free a user_info structure. This function ensures that the contents
285  * of the user_info are freed as well as the user_info itself.
286  */
287 void
288 mlsvc_free_user_info(smb_userinfo_t *user_info)
289 {
290 	if (user_info) {
291 		mlsvc_release_user_info(user_info);
292 		free(user_info);
293 	}
294 }
295 
296 /*
297  * mlsvc_release_user_info
298  *
299  * Release the contents of a user_info structure and zero out the
300  * elements but do not free the user_info structure itself. This
301  * function cleans out the structure so that it can be reused without
302  * worrying about stale contents.
303  */
304 void
305 mlsvc_release_user_info(smb_userinfo_t *user_info)
306 {
307 	int i;
308 
309 	if (user_info == NULL)
310 		return;
311 
312 	free(user_info->name);
313 	free(user_info->domain_sid);
314 	free(user_info->domain_name);
315 	free(user_info->groups);
316 
317 	if (user_info->n_other_grps) {
318 		for (i = 0; i < user_info->n_other_grps; i++)
319 			free(user_info->other_grps[i].sid);
320 
321 		free(user_info->other_grps);
322 	}
323 
324 	free(user_info->user_sid);
325 	free(user_info->pgrp_sid);
326 	bzero(user_info, sizeof (smb_userinfo_t));
327 }
328 
329 /*
330  * mlsvc_setadmin_user_info
331  *
332  * Determines if the given user is the domain Administrator or a
333  * member of Domain Admins or Administrators group and set the
334  * user_info->flags accordingly.
335  */
336 void
337 mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
338 {
339 	nt_domain_t *domain;
340 	nt_group_t *grp;
341 	int i;
342 
343 	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
344 		return;
345 
346 	if (!nt_sid_is_equal((nt_sid_t *)user_info->domain_sid, domain->sid))
347 		return;
348 
349 	if (user_info->rid == DOMAIN_USER_RID_ADMIN)
350 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
351 	else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
352 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
353 	else {
354 		for (i = 0; i < user_info->n_groups; i++)
355 			if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
356 				user_info->flags |= SMB_UINFO_FLAG_DADMIN;
357 	}
358 
359 	grp = nt_group_getinfo("Administrators", RWLOCK_READER);
360 	if (grp) {
361 		i = nt_group_is_member(grp, user_info->user_sid);
362 		nt_group_putinfo(grp);
363 		if (i)
364 			user_info->flags |= SMB_UINFO_FLAG_LADMIN;
365 	}
366 }
367 
368 /*
369  * mlsvc_string_save
370  *
371  * This is a convenience function to prepare strings for an RPC call.
372  * An ms_string_t is set up with the appropriate lengths and str is
373  * set up to point to a copy of the original string on the heap. The
374  * macro MLRPC_HEAP_STRSAVE is an alias for mlrpc_heap_strsave, which
375  * extends the heap and copies the string into the new area.
376  */
377 int
378 mlsvc_string_save(ms_string_t *ms, char *str, struct mlrpc_xaction *mxa)
379 {
380 	int length;
381 	char *p;
382 
383 	if (ms == NULL || str == NULL || mxa == NULL)
384 		return (0);
385 
386 	/*
387 	 * Windows NT expects the name length to exclude the
388 	 * terminating wchar null but doesn't care whether or
389 	 * not the allosize includes it. Windows 2000 insists
390 	 * that both the length and the allosize include the
391 	 * wchar null.
392 	 */
393 	length = mts_wcequiv_strlen(str);
394 	ms->allosize = length + sizeof (mts_wchar_t);
395 
396 	if (mxa->context->user_ctx->du_native_os == NATIVE_OS_WIN2000)
397 		ms->length = ms->allosize;
398 	else
399 		ms->length = length;
400 
401 	if ((p = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL) {
402 		return (0);
403 	}
404 
405 	ms->str = (LPTSTR)p;
406 	return (1);
407 }
408 
409 /*
410  * mlsvc_sid_save
411  *
412  * Expand the heap and copy the sid into the new area.
413  * Returns a pointer to the copy of the sid on the heap.
414  */
415 nt_sid_t *
416 mlsvc_sid_save(nt_sid_t *sid, struct mlrpc_xaction *mxa)
417 {
418 	nt_sid_t *heap_sid;
419 	unsigned size;
420 
421 	if (sid == NULL)
422 		return (NULL);
423 
424 	size = nt_sid_length(sid);
425 
426 	if ((heap_sid = (nt_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL)
427 		return (0);
428 
429 	bcopy(sid, heap_sid, size);
430 	return (heap_sid);
431 }
432 
433 /*
434  * mlsvc_is_null_handle
435  *
436  * Check a handle against a null handle. Returns 1 if the handle is
437  * null. Otherwise returns 0.
438  */
439 int
440 mlsvc_is_null_handle(mlsvc_handle_t *handle)
441 {
442 	static ms_handle_t zero_handle;
443 
444 	if (handle == NULL || handle->context == NULL)
445 		return (1);
446 
447 	if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t)))
448 		return (1);
449 
450 	return (0);
451 }
452 
453 /*
454  * mlsvc_validate_user
455  *
456  * Returns NT status codes.
457  */
458 DWORD
459 mlsvc_validate_user(char *server, char *domain, char *plain_user,
460     char *plain_text)
461 {
462 	smb_auth_info_t auth;
463 	smb_ntdomain_t *di;
464 	int erc;
465 	DWORD status;
466 	mlsvc_handle_t netr_handle;
467 	char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX];
468 
469 	machine_passwd[0] = '\0';
470 
471 	/*
472 	 * Ensure that the domain name is uppercase.
473 	 */
474 	(void) utf8_strupr(domain);
475 
476 	/*
477 	 * There is no point continuing if the domain information is
478 	 * not available. Wait for up to 10 seconds and then give up.
479 	 */
480 	if ((di = smb_getdomaininfo(10)) == 0) {
481 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
482 		return (status);
483 	}
484 
485 	if (strcasecmp(domain, di->domain) != 0) {
486 		status = NT_STATUS_INVALID_PARAMETER;
487 		return (status);
488 	}
489 
490 	erc = mlsvc_user_logon(server, domain, plain_user, plain_text);
491 
492 	if (erc == AUTH_USER_GRANT) {
493 		int isenabled;
494 
495 		smb_config_rdlock();
496 		isenabled = smb_config_getyorn(SMB_CI_ADS_ENABLE);
497 		smb_config_unlock();
498 		if (isenabled) {
499 			if (adjoin(machine_passwd,
500 			    sizeof (machine_passwd)) == ADJOIN_SUCCESS) {
501 				status = NT_STATUS_SUCCESS;
502 			} else {
503 				status = NT_STATUS_UNSUCCESSFUL;
504 			}
505 		} else {
506 			/*
507 			 * Ensure that we don't have an old account in
508 			 * this domain. There's no need to check the
509 			 * return status.
510 			 */
511 			(void) sam_remove_trust_account(server, domain);
512 
513 			if (mlsvc_user_getauth(server, plain_user, &auth)
514 			    != 0) {
515 				status = NT_STATUS_INVALID_PARAMETER;
516 				return (status);
517 			}
518 
519 			status = sam_create_trust_account(server, domain,
520 			    &auth);
521 			if (status == NT_STATUS_SUCCESS) {
522 				(void) smb_gethostname(machine_passwd,
523 				    sizeof (machine_passwd), 0);
524 				(void) utf8_strlwr(machine_passwd);
525 			}
526 		}
527 
528 		if (status == NT_STATUS_SUCCESS) {
529 			smb_config_wrlock();
530 			if (smb_config_set(SMB_CI_MACHINE_PASSWD,
531 			    machine_passwd) != 0) {
532 				smb_config_unlock();
533 				return (NT_STATUS_UNSUCCESSFUL);
534 			}
535 			smb_config_unlock();
536 
537 			/*
538 			 * If we successfully create a trust account, we mark
539 			 * ourselves as a domain member in the environment so
540 			 * that we use the SAMLOGON version of the NETLOGON
541 			 * PDC location protocol.
542 			 */
543 			smb_set_domain_member(1);
544 
545 			if (netr_open(server, domain, &netr_handle) == 0) {
546 				status = netlogon_auth(server, &netr_handle,
547 				    NETR_FLG_INIT);
548 				(void) netr_close(&netr_handle);
549 			} else {
550 				status = NT_STATUS_OPEN_FAILED;
551 			}
552 		}
553 	} else {
554 		status = NT_STATUS_LOGON_FAILURE;
555 	}
556 
557 	return (status);
558 }
559 
560 /*ARGSUSED*/
561 void
562 nt_group_ht_lock(krwmode_t locktype)
563 {
564 }
565 
566 void
567 nt_group_ht_unlock(void)
568 {
569 }
570 
571 int
572 nt_group_num_groups(void)
573 {
574 	return (0);
575 }
576 
577 /*ARGSUSED*/
578 uint32_t
579 nt_group_add(char *gname, char *comment)
580 {
581 	return (NT_STATUS_NOT_SUPPORTED);
582 }
583 
584 /*ARGSUSED*/
585 uint32_t
586 nt_group_modify(char *gname, char *new_gname, char *comment)
587 {
588 	return (NT_STATUS_NOT_SUPPORTED);
589 }
590 
591 /*ARGSUSED*/
592 uint32_t
593 nt_group_delete(char *gname)
594 {
595 	return (NT_STATUS_NOT_SUPPORTED);
596 }
597 
598 /*ARGSUSED*/
599 nt_group_t *
600 nt_group_getinfo(char *gname, krwmode_t locktype)
601 {
602 	return (NULL);
603 }
604 
605 /*ARGSUSED*/
606 void
607 nt_group_putinfo(nt_group_t *grp)
608 {
609 }
610 
611 /*ARGSUSED*/
612 int
613 nt_group_getpriv(nt_group_t *grp, uint32_t priv_id)
614 {
615 	return (SE_PRIVILEGE_DISABLED);
616 }
617 
618 /*ARGSUSED*/
619 uint32_t
620 nt_group_setpriv(nt_group_t *grp, uint32_t priv_id, uint32_t new_attr)
621 {
622 	return (NT_STATUS_NOT_SUPPORTED);
623 }
624 
625 /*ARGSUSED*/
626 int
627 nt_group_is_member(nt_group_t *grp, nt_sid_t *sid)
628 {
629 	return (0);
630 }
631 
632 /*ARGSUSED*/
633 uint32_t
634 nt_group_add_member(nt_group_t *grp, nt_sid_t *msid, uint16_t sid_name_use,
635     char *account)
636 {
637 	return (NT_STATUS_NOT_SUPPORTED);
638 }
639 
640 /*ARGSUSED*/
641 uint32_t
642 nt_group_del_member(nt_group_t *grp, void *key, int keytype)
643 {
644 	return (NT_STATUS_NOT_SUPPORTED);
645 }
646 
647 /*ARGSUSED*/
648 int
649 nt_group_num_members(nt_group_t *grp)
650 {
651 	return (0);
652 }
653 
654 nt_group_iterator_t *
655 nt_group_open_iterator(void)
656 {
657 	return (NULL);
658 }
659 
660 /*ARGSUSED*/
661 void
662 nt_group_close_iterator(nt_group_iterator_t *gi)
663 {
664 }
665 
666 /*ARGSUSED*/
667 nt_group_t *
668 nt_group_iterate(nt_group_iterator_t *gi)
669 {
670 	return (NULL);
671 }
672 
673 int
674 nt_group_cache_size(void)
675 {
676 	return (0);
677 }
678 
679 uint32_t
680 sam_init(void)
681 {
682 	return (NT_STATUS_SUCCESS);
683 }
684 
685 /*ARGSUSED*/
686 uint32_t
687 nt_group_add_member_byname(char *gname, char *account)
688 {
689 	return (NT_STATUS_NOT_SUPPORTED);
690 }
691 
692 /*ARGSUSED*/
693 uint32_t
694 nt_group_del_member_byname(nt_group_t *grp, char *member_name)
695 {
696 	return (NT_STATUS_NOT_SUPPORTED);
697 }
698 
699 /*ARGSUSED*/
700 void
701 nt_group_add_groupprivs(nt_group_t *grp, smb_privset_t *priv)
702 {
703 }
704 
705 /*ARGSUSED*/
706 uint32_t
707 nt_groups_member_privs(nt_sid_t *sid, smb_privset_t *priv)
708 {
709 	return (NT_STATUS_SUCCESS);
710 }
711 
712 /*ARGSUSED*/
713 int
714 nt_groups_member_ngroups(nt_sid_t *sid)
715 {
716 	return (0);
717 }
718 
719 /*ARGSUSED*/
720 uint32_t
721 nt_groups_member_groups(nt_sid_t *sid, smb_id_t *grps, int ngrps)
722 {
723 	return (NT_STATUS_SUCCESS);
724 }
725 
726 /*ARGSUSED*/
727 nt_group_t *
728 nt_groups_lookup_rid(uint32_t rid)
729 {
730 	return (NULL);
731 }
732 
733 /*ARGSUSED*/
734 int
735 nt_groups_count(int cnt_opt)
736 {
737 	return (0);
738 }
739 
740 /*ARGSUSED*/
741 int
742 nt_group_member_list(int offset, nt_group_t *grp,
743     ntgrp_member_list_t *rmembers)
744 {
745 	return (0);
746 }
747 
748 /*ARGSUSED*/
749 void
750 nt_group_list(int offset, char *pattern, ntgrp_list_t *list)
751 {
752 }
753