xref: /titanic_52/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision 1c2187e7a735b31a46941879f0bd124e0aa325a3)
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 	if (str == NULL)
381 		return (0);
382 
383 	ms->length = mts_wcequiv_strlen(str);
384 	ms->allosize = ms->length + sizeof (mts_wchar_t);
385 
386 	if ((ms->str = MLRPC_HEAP_STRSAVE(mxa, str)) == NULL)
387 		return (0);
388 
389 	return (1);
390 }
391 
392 /*
393  * mlsvc_sid_save
394  *
395  * Expand the heap and copy the sid into the new area.
396  * Returns a pointer to the copy of the sid on the heap.
397  */
398 nt_sid_t *
399 mlsvc_sid_save(nt_sid_t *sid, struct mlrpc_xaction *mxa)
400 {
401 	nt_sid_t *heap_sid;
402 	unsigned size;
403 
404 	if (sid == NULL)
405 		return (NULL);
406 
407 	size = nt_sid_length(sid);
408 
409 	if ((heap_sid = (nt_sid_t *)MLRPC_HEAP_MALLOC(mxa, size)) == NULL)
410 		return (0);
411 
412 	bcopy(sid, heap_sid, size);
413 	return (heap_sid);
414 }
415 
416 /*
417  * mlsvc_is_null_handle
418  *
419  * Check a handle against a null handle. Returns 1 if the handle is
420  * null. Otherwise returns 0.
421  */
422 int
423 mlsvc_is_null_handle(mlsvc_handle_t *handle)
424 {
425 	static ms_handle_t zero_handle;
426 
427 	if (handle == NULL || handle->context == NULL)
428 		return (1);
429 
430 	if (!memcmp(&handle->handle, &zero_handle, sizeof (ms_handle_t)))
431 		return (1);
432 
433 	return (0);
434 }
435 
436 /*
437  * mlsvc_join
438  *
439  * Returns NT status codes.
440  */
441 DWORD
442 mlsvc_join(char *server, char *domain, char *plain_user, char *plain_text)
443 {
444 	smb_auth_info_t auth;
445 	smb_ntdomain_t *di;
446 	int erc;
447 	DWORD status;
448 	mlsvc_handle_t netr_handle;
449 	char machine_passwd[MLSVC_MACHINE_ACCT_PASSWD_MAX];
450 
451 	machine_passwd[0] = '\0';
452 
453 	/*
454 	 * Ensure that the domain name is uppercase.
455 	 */
456 	(void) utf8_strupr(domain);
457 
458 	/*
459 	 * There is no point continuing if the domain information is
460 	 * not available. Wait for up to 10 seconds and then give up.
461 	 */
462 	if ((di = smb_getdomaininfo(10)) == 0) {
463 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
464 		return (status);
465 	}
466 
467 	if (strcasecmp(domain, di->domain) != 0) {
468 		status = NT_STATUS_INVALID_PARAMETER;
469 		return (status);
470 	}
471 
472 	erc = mlsvc_logon(server, domain, plain_user);
473 
474 	if (erc == AUTH_USER_GRANT) {
475 		int isenabled;
476 
477 		smb_config_rdlock();
478 		isenabled = smb_config_getyorn(SMB_CI_ADS_ENABLE);
479 		smb_config_unlock();
480 		if (isenabled) {
481 			if (ads_join(plain_user, plain_text, machine_passwd,
482 			    sizeof (machine_passwd)) == ADJOIN_SUCCESS)
483 				status = NT_STATUS_SUCCESS;
484 			else
485 				status = NT_STATUS_UNSUCCESSFUL;
486 		} else {
487 			if (mlsvc_user_getauth(server, plain_user, &auth)
488 			    != 0) {
489 				status = NT_STATUS_INVALID_PARAMETER;
490 				return (status);
491 			}
492 
493 			status = sam_create_trust_account(server, domain,
494 			    &auth);
495 			if (status == NT_STATUS_SUCCESS) {
496 				(void) smb_gethostname(machine_passwd,
497 				    sizeof (machine_passwd), 0);
498 				(void) utf8_strlwr(machine_passwd);
499 			}
500 		}
501 
502 		if (status == NT_STATUS_SUCCESS) {
503 			if (smb_set_machine_pwd(machine_passwd) != 0)
504 				return (NT_STATUS_UNSUCCESSFUL);
505 
506 			/*
507 			 * If we successfully create a trust account, we mark
508 			 * ourselves as a domain member in the environment so
509 			 * that we use the SAMLOGON version of the NETLOGON
510 			 * PDC location protocol.
511 			 */
512 			smb_set_domain_member(1);
513 
514 			if (netr_open(server, domain, &netr_handle) == 0) {
515 				status = netlogon_auth(server, &netr_handle,
516 				    NETR_FLG_INIT);
517 				(void) netr_close(&netr_handle);
518 			} else {
519 				status = NT_STATUS_OPEN_FAILED;
520 			}
521 		}
522 	} else {
523 		status = NT_STATUS_LOGON_FAILURE;
524 	}
525 
526 	return (status);
527 }
528 
529 /*ARGSUSED*/
530 void
531 nt_group_ht_lock(krwmode_t locktype)
532 {
533 }
534 
535 void
536 nt_group_ht_unlock(void)
537 {
538 }
539 
540 int
541 nt_group_num_groups(void)
542 {
543 	return (0);
544 }
545 
546 /*ARGSUSED*/
547 uint32_t
548 nt_group_add(char *gname, char *comment)
549 {
550 	return (NT_STATUS_NOT_SUPPORTED);
551 }
552 
553 /*ARGSUSED*/
554 uint32_t
555 nt_group_modify(char *gname, char *new_gname, char *comment)
556 {
557 	return (NT_STATUS_NOT_SUPPORTED);
558 }
559 
560 /*ARGSUSED*/
561 uint32_t
562 nt_group_delete(char *gname)
563 {
564 	return (NT_STATUS_NOT_SUPPORTED);
565 }
566 
567 /*ARGSUSED*/
568 nt_group_t *
569 nt_group_getinfo(char *gname, krwmode_t locktype)
570 {
571 	return (NULL);
572 }
573 
574 /*ARGSUSED*/
575 void
576 nt_group_putinfo(nt_group_t *grp)
577 {
578 }
579 
580 /*ARGSUSED*/
581 int
582 nt_group_getpriv(nt_group_t *grp, uint32_t priv_id)
583 {
584 	return (SE_PRIVILEGE_DISABLED);
585 }
586 
587 /*ARGSUSED*/
588 uint32_t
589 nt_group_setpriv(nt_group_t *grp, uint32_t priv_id, uint32_t new_attr)
590 {
591 	return (NT_STATUS_NOT_SUPPORTED);
592 }
593 
594 /*ARGSUSED*/
595 int
596 nt_group_is_member(nt_group_t *grp, nt_sid_t *sid)
597 {
598 	return (0);
599 }
600 
601 /*ARGSUSED*/
602 uint32_t
603 nt_group_add_member(nt_group_t *grp, nt_sid_t *msid, uint16_t sid_name_use,
604     char *account)
605 {
606 	return (NT_STATUS_NOT_SUPPORTED);
607 }
608 
609 /*ARGSUSED*/
610 uint32_t
611 nt_group_del_member(nt_group_t *grp, void *key, int keytype)
612 {
613 	return (NT_STATUS_NOT_SUPPORTED);
614 }
615 
616 /*ARGSUSED*/
617 int
618 nt_group_num_members(nt_group_t *grp)
619 {
620 	return (0);
621 }
622 
623 nt_group_iterator_t *
624 nt_group_open_iterator(void)
625 {
626 	return (NULL);
627 }
628 
629 /*ARGSUSED*/
630 void
631 nt_group_close_iterator(nt_group_iterator_t *gi)
632 {
633 }
634 
635 /*ARGSUSED*/
636 nt_group_t *
637 nt_group_iterate(nt_group_iterator_t *gi)
638 {
639 	return (NULL);
640 }
641 
642 int
643 nt_group_cache_size(void)
644 {
645 	return (0);
646 }
647 
648 uint32_t
649 sam_init(void)
650 {
651 	return (NT_STATUS_SUCCESS);
652 }
653 
654 /*ARGSUSED*/
655 uint32_t
656 nt_group_add_member_byname(char *gname, char *account)
657 {
658 	return (NT_STATUS_NOT_SUPPORTED);
659 }
660 
661 /*ARGSUSED*/
662 uint32_t
663 nt_group_del_member_byname(nt_group_t *grp, char *member_name)
664 {
665 	return (NT_STATUS_NOT_SUPPORTED);
666 }
667 
668 /*ARGSUSED*/
669 void
670 nt_group_add_groupprivs(nt_group_t *grp, smb_privset_t *priv)
671 {
672 }
673 
674 /*ARGSUSED*/
675 uint32_t
676 nt_groups_member_privs(nt_sid_t *sid, smb_privset_t *priv)
677 {
678 	return (NT_STATUS_SUCCESS);
679 }
680 
681 /*ARGSUSED*/
682 int
683 nt_groups_member_ngroups(nt_sid_t *sid)
684 {
685 	return (0);
686 }
687 
688 /*ARGSUSED*/
689 uint32_t
690 nt_groups_member_groups(nt_sid_t *sid, smb_id_t *grps, int ngrps)
691 {
692 	return (NT_STATUS_SUCCESS);
693 }
694 
695 /*ARGSUSED*/
696 nt_group_t *
697 nt_groups_lookup_rid(uint32_t rid)
698 {
699 	return (NULL);
700 }
701 
702 /*ARGSUSED*/
703 int
704 nt_groups_count(int cnt_opt)
705 {
706 	return (0);
707 }
708 
709 /*ARGSUSED*/
710 int
711 nt_group_member_list(int offset, nt_group_t *grp,
712     ntgrp_member_list_t *rmembers)
713 {
714 	return (0);
715 }
716 
717 /*ARGSUSED*/
718 void
719 nt_group_list(int offset, char *pattern, ntgrp_list_t *list)
720 {
721 }
722