xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c (revision a73c0fe4e90b82a478f821ef3adb5cf34f6a9346)
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 2009 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  * mlsvc_lookup_name
58  *
59  * This is just a wrapper for lsa_lookup_name.
60  *
61  * The memory for the sid is allocated using malloc so the caller should
62  * call free when it is no longer required.
63  */
64 uint32_t
65 mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type)
66 {
67 	smb_userinfo_t *ainfo;
68 	uint32_t status;
69 
70 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
71 		return (NT_STATUS_NO_MEMORY);
72 
73 	status = lsa_lookup_name(account, *sid_type, ainfo);
74 	if (status == NT_STATUS_SUCCESS) {
75 		*sid = ainfo->user_sid;
76 		ainfo->user_sid = NULL;
77 		*sid_type = ainfo->sid_name_use;
78 	}
79 
80 	mlsvc_free_user_info(ainfo);
81 	return (status);
82 }
83 
84 /*
85  * mlsvc_lookup_sid
86  *
87  * This is just a wrapper for lsa_lookup_sid.
88  *
89  * The allocated memory for the returned name must be freed by caller upon
90  * successful return.
91  */
92 uint32_t
93 mlsvc_lookup_sid(smb_sid_t *sid, char **name)
94 {
95 	smb_userinfo_t *ainfo;
96 	uint32_t status;
97 	int namelen;
98 
99 	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
100 		return (NT_STATUS_NO_MEMORY);
101 
102 	status = lsa_lookup_sid(sid, ainfo);
103 	if (status == NT_STATUS_SUCCESS) {
104 		namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2;
105 		if ((*name = malloc(namelen)) == NULL) {
106 			mlsvc_free_user_info(ainfo);
107 			return (NT_STATUS_NO_MEMORY);
108 		}
109 		(void) snprintf(*name, namelen, "%s\\%s",
110 		    ainfo->domain_name, ainfo->name);
111 	}
112 
113 	mlsvc_free_user_info(ainfo);
114 	return (status);
115 }
116 
117 /*
118  * mlsvc_alloc_user_info
119  *
120  * Allocate a user_info structure and set the contents to zero. A
121  * pointer to the user_info structure is returned.
122  */
123 smb_userinfo_t *
124 mlsvc_alloc_user_info(void)
125 {
126 	smb_userinfo_t *user_info;
127 
128 	user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
129 	if (user_info == NULL)
130 		return (NULL);
131 
132 	bzero(user_info, sizeof (smb_userinfo_t));
133 	return (user_info);
134 }
135 
136 /*
137  * mlsvc_free_user_info
138  *
139  * Free a user_info structure. This function ensures that the contents
140  * of the user_info are freed as well as the user_info itself.
141  */
142 void
143 mlsvc_free_user_info(smb_userinfo_t *user_info)
144 {
145 	if (user_info) {
146 		mlsvc_release_user_info(user_info);
147 		free(user_info);
148 	}
149 }
150 
151 /*
152  * mlsvc_release_user_info
153  *
154  * Release the contents of a user_info structure and zero out the
155  * elements but do not free the user_info structure itself. This
156  * function cleans out the structure so that it can be reused without
157  * worrying about stale contents.
158  */
159 void
160 mlsvc_release_user_info(smb_userinfo_t *user_info)
161 {
162 	int i;
163 
164 	if (user_info == NULL)
165 		return;
166 
167 	free(user_info->name);
168 	free(user_info->domain_sid);
169 	free(user_info->domain_name);
170 	free(user_info->groups);
171 
172 	if (user_info->n_other_grps) {
173 		for (i = 0; i < user_info->n_other_grps; i++)
174 			free(user_info->other_grps[i].sid);
175 
176 		free(user_info->other_grps);
177 	}
178 
179 	free(user_info->session_key);
180 	free(user_info->user_sid);
181 	free(user_info->pgrp_sid);
182 	bzero(user_info, sizeof (smb_userinfo_t));
183 }
184 
185 /*
186  * mlsvc_setadmin_user_info
187  *
188  * Determines if the given user is the domain Administrator or a
189  * member of Domain Admins or Administrators group and set the
190  * user_info->flags accordingly.
191  */
192 void
193 mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
194 {
195 	nt_domain_t *domain;
196 	smb_group_t grp;
197 	int rc, i;
198 
199 	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
200 		return;
201 
202 	if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid))
203 		return;
204 
205 	if (user_info->rid == DOMAIN_USER_RID_ADMIN)
206 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
207 	else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
208 		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
209 	else {
210 		for (i = 0; i < user_info->n_groups; i++)
211 			if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
212 				user_info->flags |= SMB_UINFO_FLAG_DADMIN;
213 	}
214 
215 	rc = smb_lgrp_getbyname("Administrators", &grp);
216 	if (rc == SMB_LGRP_SUCCESS) {
217 		if (smb_lgrp_is_member(&grp, user_info->user_sid))
218 			user_info->flags |= SMB_UINFO_FLAG_LADMIN;
219 		smb_lgrp_free(&grp);
220 	}
221 }
222 
223 DWORD
224 mlsvc_netlogon(char *server, char *domain)
225 {
226 	mlsvc_handle_t netr_handle;
227 	DWORD status;
228 
229 	if (netr_open(server, domain, &netr_handle) == 0) {
230 		status = netlogon_auth(server, &netr_handle,
231 		    NETR_FLG_INIT);
232 		(void) netr_close(&netr_handle);
233 	} else {
234 		status = NT_STATUS_OPEN_FAILED;
235 	}
236 
237 	return (status);
238 }
239 
240 /*
241  * mlsvc_join
242  *
243  * Returns NT status codes.
244  */
245 DWORD
246 mlsvc_join(smb_domain_t *dinfo, char *user, char *plain_text)
247 {
248 	smb_auth_info_t auth;
249 	int erc;
250 	DWORD status;
251 	char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX];
252 
253 	machine_passwd[0] = '\0';
254 
255 	/*
256 	 * Ensure that the domain name is uppercase.
257 	 */
258 	(void) utf8_strupr(dinfo->d_nbdomain);
259 
260 	erc = mlsvc_logon(dinfo->d_dc, dinfo->d_nbdomain, user);
261 
262 	if (erc == AUTH_USER_GRANT) {
263 		if (mlsvc_ntjoin_support == B_FALSE) {
264 
265 			if (smb_ads_join(dinfo->d_fqdomain, user, plain_text,
266 			    machine_passwd, sizeof (machine_passwd))
267 			    == SMB_ADJOIN_SUCCESS)
268 				status = NT_STATUS_SUCCESS;
269 			else
270 				status = NT_STATUS_UNSUCCESSFUL;
271 		} else {
272 			if (mlsvc_user_getauth(dinfo->d_dc, user, &auth)
273 			    != 0) {
274 				status = NT_STATUS_INVALID_PARAMETER;
275 				return (status);
276 			}
277 
278 			status = sam_create_trust_account(dinfo->d_dc,
279 			    dinfo->d_nbdomain, &auth);
280 			if (status == NT_STATUS_SUCCESS) {
281 				(void) smb_getnetbiosname(machine_passwd,
282 				    sizeof (machine_passwd));
283 				(void) utf8_strlwr(machine_passwd);
284 			}
285 		}
286 
287 		if (status == NT_STATUS_SUCCESS) {
288 			erc = smb_setdomainprops(NULL, dinfo->d_dc,
289 			    machine_passwd);
290 			if (erc != 0)
291 				return (NT_STATUS_UNSUCCESSFUL);
292 
293 			status = mlsvc_netlogon(dinfo->d_dc, dinfo->d_nbdomain);
294 		}
295 	} else {
296 		status = NT_STATUS_LOGON_FAILURE;
297 	}
298 
299 	return (status);
300 }
301