xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision 9b4e3ac25d882519cad3fc11f0c53b07f4e60536)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Utility functions to support the RPC interface library.
28  */
29 
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <strings.h>
33 #include <unistd.h>
34 #include <netdb.h>
35 #include <stdlib.h>
36 #include <sys/time.h>
37 #include <sys/systm.h>
38 
39 #include <smbsrv/libsmb.h>
40 #include <smbsrv/libsmbrdr.h>
41 #include <smbsrv/libsmbns.h>
42 #include <smbsrv/libmlsvc.h>
43 #include <smbsrv/smbinfo.h>
44 #include <lsalib.h>
45 #include <samlib.h>
46 #include <smbsrv/netrauth.h>
47 
48 /* Domain join support (using MS-RPC) */
49 static boolean_t mlsvc_ntjoin_support = B_FALSE;
50 
51 extern int netr_open(char *, char *, mlsvc_handle_t *);
52 extern int netr_close(mlsvc_handle_t *);
53 extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
54 extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *);
55 
56 /*
57  * Compare the supplied domain name with the local hostname.
58  * We need to deal with both server names and fully-qualified
59  * domain names.
60  *
61  * Returns:
62  *	0	The specified domain is not the local domain,
63  *	1	The Specified domain is the local domain.
64  *	-1	Invalid parameter or unable to get the local
65  *		system information.
66  */
67 int
68 mlsvc_is_local_domain(const char *domain)
69 {
70 	char hostname[MAXHOSTNAMELEN];
71 	int rc;
72 
73 	if (smb_config_get_secmode() == SMB_SECMODE_WORKGRP)
74 		return (1);
75 
76 	if (strchr(domain, '.') != NULL)
77 		rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
78 	else {
79 		if (strlen(domain) < NETBIOS_NAME_SZ)
80 			rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
81 		else
82 			rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
83 	}
84 
85 	if (rc != 0)
86 		return (-1);
87 
88 	if (strcasecmp(domain, hostname) == 0)
89 		return (1);
90 
91 	return (0);
92 }
93 
94 /*
95  * mlsvc_lookup_name
96  *
97  * This is just a wrapper for lsa_lookup_name.
98  *
99  * The memory for the sid is allocated using malloc so the caller should
100  * call free when it is no longer required.
101  */
102 uint32_t
103 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type)
104 {
105 	smb_userinfo_t *ainfo;
106 	uint32_t status;
107 
108 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
109 		return (NT_STATUS_NO_MEMORY);
110 
111 	status = lsa_lookup_name(account, *sid_type, ainfo);
112 	if (status == NT_STATUS_SUCCESS) {
113 		*sid = ainfo->user_sid;
114 		ainfo->user_sid = NULL;
115 		*sid_type = ainfo->sid_name_use;
116 	}
117 
118 	mlsvc_free_user_info(ainfo);
119 	return (status);
120 }
121 
122 /*
123  * mlsvc_lookup_sid
124  *
125  * This is just a wrapper for lsa_lookup_sid.
126  *
127  * The allocated memory for the returned name must be freed by caller upon
128  * successful return.
129  */
130 uint32_t
131 mlsvc_lookup_sid(smb_sid_t *sid, char **name)
132 {
133 	smb_userinfo_t *ainfo;
134 	uint32_t status;
135 	int namelen;
136 
137 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
138 		return (NT_STATUS_NO_MEMORY);
139 
140 	status = lsa_lookup_sid(sid, ainfo);
141 	if (status == NT_STATUS_SUCCESS) {
142 		namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2;
143 		if ((*name = malloc(namelen)) == NULL) {
144 			mlsvc_free_user_info(ainfo);
145 			return (NT_STATUS_NO_MEMORY);
146 		}
147 		(void) snprintf(*name, namelen, "%s\\%s",
148 		    ainfo->domain_name, ainfo->name);
149 	}
150 
151 	mlsvc_free_user_info(ainfo);
152 	return (status);
153 }
154 
155 /*
156  * mlsvc_alloc_user_info
157  *
158  * Allocate a user_info structure and set the contents to zero. A
159  * pointer to the user_info structure is returned.
160  */
161 smb_userinfo_t *
162 mlsvc_alloc_user_info(void)
163 {
164 	smb_userinfo_t *user_info;
165 
166 	user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
167 	if (user_info == NULL)
168 		return (NULL);
169 
170 	bzero(user_info, sizeof (smb_userinfo_t));
171 	return (user_info);
172 }
173 
174 /*
175  * mlsvc_free_user_info
176  *
177  * Free a user_info structure. This function ensures that the contents
178  * of the user_info are freed as well as the user_info itself.
179  */
180 void
181 mlsvc_free_user_info(smb_userinfo_t *user_info)
182 {
183 	if (user_info) {
184 		mlsvc_release_user_info(user_info);
185 		free(user_info);
186 	}
187 }
188 
189 /*
190  * mlsvc_release_user_info
191  *
192  * Release the contents of a user_info structure and zero out the
193  * elements but do not free the user_info structure itself. This
194  * function cleans out the structure so that it can be reused without
195  * worrying about stale contents.
196  */
197 void
198 mlsvc_release_user_info(smb_userinfo_t *user_info)
199 {
200 	int i;
201 
202 	if (user_info == NULL)
203 		return;
204 
205 	free(user_info->name);
206 	free(user_info->domain_sid);
207 	free(user_info->domain_name);
208 	free(user_info->groups);
209 
210 	if (user_info->n_other_grps) {
211 		for (i = 0; i < user_info->n_other_grps; i++)
212 			free(user_info->other_grps[i].sid);
213 
214 		free(user_info->other_grps);
215 	}
216 
217 	free(user_info->session_key);
218 	free(user_info->user_sid);
219 	free(user_info->pgrp_sid);
220 	bzero(user_info, sizeof (smb_userinfo_t));
221 }
222 
223 /*
224  * mlsvc_setadmin_user_info
225  *
226  * Determines if the given user is the domain Administrator or a
227  * member of Domain Admins or Administrators group and set the
228  * user_info->flags accordingly.
229  */
230 void
231 mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
232 {
233 	nt_domain_t *domain;
234 	smb_group_t grp;
235 	int rc, i;
236 
237 	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
238 		return;
239 
240 	if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid))
241 		return;
242 
243 	if (user_info->rid == DOMAIN_USER_RID_ADMIN)
244 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
245 	else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
246 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
247 	else {
248 		for (i = 0; i < user_info->n_groups; i++)
249 			if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
250 				user_info->flags |= SMB_UINFO_FLAG_DADMIN;
251 	}
252 
253 	rc = smb_lgrp_getbyname("Administrators", &grp);
254 	if (rc == SMB_LGRP_SUCCESS) {
255 		if (smb_lgrp_is_member(&grp, user_info->user_sid))
256 			user_info->flags |= SMB_UINFO_FLAG_LADMIN;
257 		smb_lgrp_free(&grp);
258 	}
259 }
260 
261 DWORD
262 mlsvc_netlogon(char *server, char *domain)
263 {
264 	mlsvc_handle_t netr_handle;
265 	DWORD status;
266 
267 	if (netr_open(server, domain, &netr_handle) == 0) {
268 		status = netlogon_auth(server, &netr_handle,
269 		    NETR_FLG_INIT);
270 		(void) netr_close(&netr_handle);
271 	} else {
272 		status = NT_STATUS_OPEN_FAILED;
273 	}
274 
275 	return (status);
276 }
277 
278 /*
279  * mlsvc_join
280  *
281  * Returns NT status codes.
282  */
283 DWORD
284 mlsvc_join(smb_domain_t *dinfo, char *user, char *plain_text)
285 {
286 	smb_auth_info_t auth;
287 	int erc;
288 	DWORD status;
289 	char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX];
290 
291 	machine_passwd[0] = '\0';
292 
293 	/*
294 	 * Ensure that the domain name is uppercase.
295 	 */
296 	(void) utf8_strupr(dinfo->d_nbdomain);
297 
298 	erc = mlsvc_logon(dinfo->d_dc, dinfo->d_nbdomain, user);
299 
300 	if (erc == AUTH_USER_GRANT) {
301 		if (mlsvc_ntjoin_support == B_FALSE) {
302 
303 			if (smb_ads_join(dinfo->d_fqdomain, user, plain_text,
304 			    machine_passwd, sizeof (machine_passwd))
305 			    == SMB_ADJOIN_SUCCESS)
306 				status = NT_STATUS_SUCCESS;
307 			else
308 				status = NT_STATUS_UNSUCCESSFUL;
309 		} else {
310 			if (mlsvc_user_getauth(dinfo->d_dc, user, &auth)
311 			    != 0) {
312 				status = NT_STATUS_INVALID_PARAMETER;
313 				return (status);
314 			}
315 
316 			status = sam_create_trust_account(dinfo->d_dc,
317 			    dinfo->d_nbdomain, &auth);
318 			if (status == NT_STATUS_SUCCESS) {
319 				(void) smb_getnetbiosname(machine_passwd,
320 				    sizeof (machine_passwd));
321 				(void) utf8_strlwr(machine_passwd);
322 			}
323 		}
324 
325 		if (status == NT_STATUS_SUCCESS) {
326 			erc = smb_setdomainprops(NULL, dinfo->d_dc,
327 			    machine_passwd);
328 			if (erc != 0)
329 				return (NT_STATUS_UNSUCCESSFUL);
330 
331 			status = mlsvc_netlogon(dinfo->d_dc, dinfo->d_nbdomain);
332 		}
333 	} else {
334 		status = NT_STATUS_LOGON_FAILURE;
335 	}
336 
337 	return (status);
338 }
339