1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
14  */
15 
16 /*
17  * Test NetrSamLogon and NetrSamLogonEx, uses for NTLM pass-thru auth.
18  */
19 
20 #include <smbsrv/libmlsvc.h>
21 #include <smbsrv/netrauth.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include <util_common.h>
26 
27 extern void netr_initialize(void);
28 extern uint32_t netlogon_logon(smb_logon_t *, smb_token_t *, smb_domainex_t *);
29 
30 boolean_t
compare_tokens(const smb_token_t * src,const smb_token_t * dst)31 compare_tokens(const smb_token_t *src, const smb_token_t *dst)
32 {
33 	int i;
34 	const smb_ids_t *src_wgrps, *dst_wgrps;
35 	smb_id_t *src_grp, *dst_grp;
36 	char src_sid[SMB_SID_STRSZ] = "NULL", dst_sid[SMB_SID_STRSZ] = "NULL";
37 
38 	if (strcmp(src->tkn_domain_name, dst->tkn_domain_name) != 0) {
39 		fprintf(stderr, "src domain %s does not match dst %s\n",
40 		    src->tkn_domain_name, dst->tkn_domain_name);
41 		return (B_FALSE);
42 	}
43 
44 	if (strcmp(src->tkn_account_name, dst->tkn_account_name) != 0) {
45 		fprintf(stderr, "src account %s does not match dst %s\n",
46 		    src->tkn_account_name, dst->tkn_account_name);
47 		return (B_FALSE);
48 	}
49 
50 	if (src->tkn_user.i_attrs != dst->tkn_user.i_attrs) {
51 		fprintf(stderr, "src attrs 0x%x does not match dst 0x%x\n",
52 		    src->tkn_user.i_attrs, dst->tkn_user.i_attrs);
53 		return (B_FALSE);
54 	}
55 
56 	if (!smb_sid_cmp(src->tkn_user.i_sid, dst->tkn_user.i_sid)) {
57 		smb_sid_tostr(src->tkn_user.i_sid, src_sid);
58 		smb_sid_tostr(dst->tkn_user.i_sid, dst_sid);
59 		fprintf(stderr, "src usersid %s does not match dst %s\n",
60 		    src_sid, dst_sid);
61 		return (B_FALSE);
62 	}
63 
64 	/* tkn_owner can be NULL if we haven't called smb_token_setup_common */
65 	if (src->tkn_owner.i_sid != dst->tkn_owner.i_sid &&
66 	    !smb_sid_cmp(src->tkn_owner.i_sid, dst->tkn_owner.i_sid)) {
67 		smb_sid_tostr(src->tkn_owner.i_sid, src_sid);
68 		smb_sid_tostr(dst->tkn_owner.i_sid, dst_sid);
69 		fprintf(stderr, "src ownersid %s does not match dst %s\n",
70 		    src_sid, dst_sid);
71 		return (B_FALSE);
72 	}
73 
74 	if (!smb_sid_cmp(src->tkn_primary_grp.i_sid,
75 	    dst->tkn_primary_grp.i_sid)) {
76 		smb_sid_tostr(src->tkn_primary_grp.i_sid, src_sid);
77 		smb_sid_tostr(dst->tkn_primary_grp.i_sid, dst_sid);
78 		fprintf(stderr, "src primarysid %s does not match dst %s\n",
79 		    src_sid, dst_sid);
80 		return (B_FALSE);
81 	}
82 
83 	src_wgrps = &src->tkn_win_grps;
84 	dst_wgrps = &dst->tkn_win_grps;
85 
86 	if ((src_wgrps->i_ids == NULL && dst_wgrps->i_ids != NULL) ||
87 	    (src_wgrps->i_ids != NULL && dst_wgrps->i_ids == NULL)) {
88 		fprintf(stderr,
89 		    "src wingrp nullness 0x%p does not match dst 0x%p\n",
90 		    src_wgrps->i_ids, dst_wgrps->i_ids);
91 		return (B_FALSE);
92 	}
93 
94 	if (src_wgrps->i_ids != NULL) {
95 		src_grp = &src_wgrps->i_ids[0];
96 		dst_grp = &dst_wgrps->i_ids[0];
97 		if (src_wgrps->i_cnt != dst_wgrps->i_cnt) {
98 			fprintf(stderr,
99 			    "src wingrp count %d does not match dst %d\n",
100 			    src_wgrps->i_cnt, dst_wgrps->i_cnt);
101 			return (B_FALSE);
102 		}
103 
104 		for (i = 0; i < src_wgrps->i_cnt; i++, src_grp++, dst_grp++) {
105 			if ((src_grp->i_sid == NULL &&
106 			    dst_grp->i_sid != NULL) ||
107 			    (src_grp->i_sid != NULL &&
108 			    dst_grp->i_sid == NULL)) {
109 				fprintf(stderr,
110 				    "src wgrp %d nullness 0x%p does not "
111 				    "match dst 0x%p\n",
112 				    i, src_grp->i_sid, dst_grp->i_sid);
113 				return (B_FALSE);
114 			}
115 
116 
117 			if (src_grp->i_sid != NULL &&
118 			    !smb_sid_cmp(src_grp->i_sid, dst_grp->i_sid)) {
119 				smb_sid_tostr(src_grp->i_sid, src_sid);
120 				smb_sid_tostr(dst_grp->i_sid, dst_sid);
121 				fprintf(stderr, "src wingrp %d sid %s "
122 				    "does not match dst %s\n",
123 				    i, src_sid, dst_sid);
124 				return (B_FALSE);
125 			}
126 		}
127 	}
128 
129 	if ((src->tkn_posix_grps == NULL && dst->tkn_posix_grps != NULL) ||
130 	    (src->tkn_posix_grps != NULL && dst->tkn_posix_grps == NULL)) {
131 		fprintf(stderr, "src pgrp nullness 0x%p does not match "
132 		    "dst 0x%p\n",
133 		    src->tkn_posix_grps, dst->tkn_posix_grps);
134 		return (B_FALSE);
135 	}
136 
137 	if (src->tkn_posix_grps != NULL) {
138 		if (src->tkn_posix_grps->pg_ngrps !=
139 		    dst->tkn_posix_grps->pg_ngrps) {
140 			fprintf(stderr,
141 			    "src pgrp count %d does not match dst %d\n",
142 			    src->tkn_posix_grps->pg_ngrps,
143 			    dst->tkn_posix_grps->pg_ngrps);
144 			return (B_FALSE);
145 		}
146 
147 		for (i = 0; i < src->tkn_posix_grps->pg_ngrps; i++) {
148 			if (src->tkn_posix_grps->pg_grps[i] !=
149 			    dst->tkn_posix_grps->pg_grps[i]) {
150 				fprintf(stderr,
151 				    "src pgrp num %d %d does not match "
152 				    "dst %d\n", i,
153 				    src->tkn_posix_grps->pg_grps[i],
154 				    dst->tkn_posix_grps->pg_grps[i]);
155 				return (B_FALSE);
156 			}
157 		}
158 	}
159 
160 	return (B_TRUE);
161 }
162 
163 enum SAMLOGON_RC {
164 	SL_SUCCESS = 0,
165 	SL_ARGC,
166 	SL_DC_FQDN,
167 	SL_NB_DOMAIN,
168 	SL_CHALLENGE,
169 	SL_NT_PASS,
170 	SL_LM_PASS,
171 	SL_TOKEN_ALLOC,
172 	SL_NETLOGON,
173 	SL_TOKEN_COMP,
174 	SL_NETLOGON_LOOP,
175 	SL_NETLOGON_SAMLOGON,
176 	SL_NETLOGON_NOVERIFY
177 };
178 
179 int
main(int argc,char * argv[])180 main(int argc, char *argv[])
181 {
182 	smb_logon_t user_info = {
183 		.lg_secmode = SMB_SECMODE_DOMAIN,
184 		.lg_domain_type = SMB_DOMAIN_PRIMARY,
185 		.lg_level = NETR_NETWORK_LOGON
186 	};
187 	smb_token_t *token = NULL;
188 	smb_token_t cmp_token;
189 	smb_domainex_t di = {0};
190 	char *nb_domain, *dc_name, *user_name, *workstation, *chall_file;
191 	char *nt_file, *lm_file;
192 	uint32_t status;
193 	int i;
194 
195 	if (argc < 8) {
196 		fprintf(stderr, "usage: %s <NETBIOS domain> <DC FQDN> "
197 		    "<user name> "
198 		    "<client computer name> <Binary Challenge File> "
199 		    "<Binary NT response file> <Binary LM response file>\n",
200 		    argv[0]);
201 		return (-SL_ARGC);
202 	}
203 
204 	nb_domain = argv[1];
205 	dc_name = argv[2];
206 	user_name = argv[3];
207 	workstation = argv[4];
208 	chall_file = argv[5];
209 	nt_file = argv[6];
210 	lm_file = argv[7];
211 
212 	if (strlcpy(di.d_dci.dc_name, dc_name, sizeof (di.d_dci.dc_name)) >=
213 	    sizeof (di.d_dci.dc_name)) {
214 		fprintf(stderr, "DC FQDN %s is too long\n", dc_name);
215 		return (-SL_DC_FQDN);
216 	}
217 	if (strlcpy(di.d_primary.di_nbname, nb_domain,
218 	    sizeof (di.d_primary.di_nbname)) >=
219 	    sizeof (di.d_primary.di_nbname)) {
220 		fprintf(stderr, "Netbios Domain %s is too long\n", nb_domain);
221 		return (-SL_NB_DOMAIN);
222 	}
223 
224 	user_info.lg_domain = nb_domain;
225 	user_info.lg_e_domain = user_info.lg_domain;
226 	user_info.lg_username = user_name;
227 	user_info.lg_workstation = workstation;
228 
229 	user_info.lg_challenge_key.val =
230 	    read_buf_from_file(chall_file, &user_info.lg_challenge_key.len);
231 	if (user_info.lg_challenge_key.val == NULL) {
232 		fprintf(stderr, "failed to get challenge\n");
233 		return (-SL_CHALLENGE);
234 	}
235 
236 	user_info.lg_nt_password.val =
237 	    read_buf_from_file(nt_file, &user_info.lg_nt_password.len);
238 	if (user_info.lg_nt_password.val == NULL) {
239 		fprintf(stderr, "failed to get NT pass\n");
240 		return (-SL_NT_PASS);
241 	}
242 
243 	user_info.lg_lm_password.val =
244 	    read_buf_from_file(lm_file, &user_info.lg_lm_password.len);
245 	if (user_info.lg_lm_password.val == NULL) {
246 		fprintf(stderr, "failed to get LM pass\n");
247 		return (-SL_LM_PASS);
248 	}
249 
250 	/* Initialize only those bits on which netlogon_logon depends */
251 	(void) smb_lgrp_start();
252 	smb_ipc_init();
253 	netr_initialize();
254 
255 	token = calloc(1, sizeof (*token));
256 	if (token == NULL) {
257 		fprintf(stderr, "failed to allocate token\n");
258 		return (-SL_TOKEN_ALLOC);
259 	}
260 	status = netlogon_logon(&user_info, token, &di);
261 
262 	if (status != NT_STATUS_SUCCESS) {
263 		fprintf(stderr, "netlogon_logon failed: 0x%x\n", status);
264 		return (-SL_NETLOGON);
265 	}
266 	smb_token_log(token);
267 
268 	/* struct copy */
269 	cmp_token = *token;
270 
271 	for (i = 0; i < 10; i++) {
272 		token = calloc(1, sizeof (*token));
273 		if (token == NULL) {
274 			fprintf(stderr, "iter %d: failed to allocate token\n",
275 			    i);
276 			return (-SL_TOKEN_ALLOC);
277 		}
278 		status = netlogon_logon(&user_info, token, &di);
279 
280 		if (status != NT_STATUS_SUCCESS) {
281 			fprintf(stderr,
282 			    "iter %d: netlogon_logon failed: 0x%x\n",
283 			    i, status);
284 			return (-SL_NETLOGON_LOOP);
285 		}
286 		if (!compare_tokens(&cmp_token, token)) {
287 			fprintf(stderr, "iter %d: tokens didn't match\n", i);
288 			smb_token_log(token);
289 			return (-SL_TOKEN_COMP);
290 		}
291 		if (i != 9)
292 			smb_token_destroy(token);
293 	}
294 	smb_token_log(token);
295 	smb_token_destroy(token);
296 
297 	token = calloc(1, sizeof (*token));
298 	if (token == NULL) {
299 		fprintf(stderr, "failed to allocate token\n");
300 		return (-SL_TOKEN_ALLOC);
301 	}
302 
303 	/* Turn off SamLogonEx */
304 	netlogon_init_global(0x00000004);
305 	status = netlogon_logon(&user_info, token, &di);
306 	if (status != NT_STATUS_SUCCESS) {
307 		fprintf(stderr, "NoSamLogonEx: netlogon_logon failed: 0x%x\n",
308 		    status);
309 		return (-SL_NETLOGON_SAMLOGON);
310 	}
311 	smb_token_log(token);
312 	if (!compare_tokens(&cmp_token, token)) {
313 		fprintf(stderr, "tokens didn't match\n");
314 		return (-SL_TOKEN_COMP);
315 	}
316 	smb_token_destroy(token);
317 
318 	token = calloc(1, sizeof (*token));
319 	if (token == NULL) {
320 		fprintf(stderr, "failed to allocate token\n");
321 		return (-SL_TOKEN_ALLOC);
322 	}
323 
324 	/* Don't verify responses */
325 	netlogon_init_global(0x00000002);
326 	status = netlogon_logon(&user_info, token, &di);
327 
328 	if (status != NT_STATUS_SUCCESS) {
329 		fprintf(stderr, "NoVerify: netlogon_logon failed: 0x%x\n",
330 		    status);
331 		return (-SL_NETLOGON_NOVERIFY);
332 	}
333 	smb_token_log(token);
334 
335 	if (!compare_tokens(&cmp_token, token)) {
336 		fprintf(stderr, "tokens didn't match\n");
337 		return (-SL_TOKEN_COMP);
338 	}
339 	smb_token_destroy(token);
340 	return (SL_SUCCESS);
341 }
342