1 /*
2    Unix SMB/CIFS implementation.
3    client connect/disconnect routines
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Andrew Bartlett 2001-2003
6    Copyright (C) Volker Lendecke 2011
7    Copyright (C) Jeremy Allison 2011
8    Copyright (C) Stefan Metzmacher 2016
9 
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23 
24 #include "includes.h"
25 #include "system/network.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "../libcli/smb/smb_common.h"
28 #include "../libcli/smb/smbXcli_base.h"
29 
30 
31 struct smb1cli_session_setup_lm21_state {
32 	struct smbXcli_session *session;
33 	uint16_t vwv[10];
34 	struct iovec *recv_iov;
35 	uint16_t out_session_id;
36 	uint16_t out_action;
37 	char *out_native_os;
38 	char *out_native_lm;
39 };
40 
41 static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq);
42 
smb1cli_session_setup_lm21_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct smbXcli_conn * conn,uint32_t timeout_msec,uint32_t pid,struct smbXcli_session * session,uint16_t in_buf_size,uint16_t in_mpx_max,uint16_t in_vc_num,uint32_t in_sess_key,const char * in_user,const char * in_domain,const DATA_BLOB in_apassword,const char * in_native_os,const char * in_native_lm)43 struct tevent_req *smb1cli_session_setup_lm21_send(TALLOC_CTX *mem_ctx,
44 				struct tevent_context *ev,
45 				struct smbXcli_conn *conn,
46 				uint32_t timeout_msec,
47 				uint32_t pid,
48 				struct smbXcli_session *session,
49 				uint16_t in_buf_size,
50 				uint16_t in_mpx_max,
51 				uint16_t in_vc_num,
52 				uint32_t in_sess_key,
53 				const char *in_user,
54 				const char *in_domain,
55 				const DATA_BLOB in_apassword,
56 				const char *in_native_os,
57 				const char *in_native_lm)
58 {
59 	struct tevent_req *req = NULL;
60 	struct smb1cli_session_setup_lm21_state *state = NULL;
61 	struct tevent_req *subreq = NULL;
62 	uint16_t *vwv = NULL;
63 	uint8_t *bytes = NULL;
64 
65 	req = tevent_req_create(mem_ctx, &state,
66 				struct smb1cli_session_setup_lm21_state);
67 	if (req == NULL) {
68 		return NULL;
69 	}
70 	state->session = session;
71 	vwv = state->vwv;
72 
73 	if (in_user == NULL) {
74 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
75 		return tevent_req_post(req, ev);
76 	}
77 
78 	if (in_domain == NULL) {
79 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
80 		return tevent_req_post(req, ev);
81 	}
82 
83 	if (in_apassword.length > UINT16_MAX) {
84 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
85 		return tevent_req_post(req, ev);
86 	}
87 
88 	if (in_native_os == NULL && in_native_lm != NULL) {
89 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
90 		return tevent_req_post(req, ev);
91 	}
92 
93 	SCVAL(vwv+0, 0, 0xff);
94 	SCVAL(vwv+0, 1, 0);
95 	SSVAL(vwv+1, 0, 0);
96 	SSVAL(vwv+2, 0, in_buf_size);
97 	SSVAL(vwv+3, 0, in_mpx_max);
98 	SSVAL(vwv+4, 0, in_vc_num);
99 	SIVAL(vwv+5, 0, in_sess_key);
100 	SSVAL(vwv+7, 0, in_apassword.length);
101 	SSVAL(vwv+8, 0, 0); /* reserved */
102 	SSVAL(vwv+9, 0, 0); /* reserved */
103 
104 	bytes = talloc_array(state, uint8_t,
105 			     in_apassword.length);
106 	if (tevent_req_nomem(bytes, req)) {
107 		return tevent_req_post(req, ev);
108 	}
109 	if (in_apassword.length != 0) {
110 		memcpy(bytes,
111 		       in_apassword.data,
112 		       in_apassword.length);
113 	}
114 
115 	bytes = smb_bytes_push_str(bytes,
116 				   smbXcli_conn_use_unicode(conn),
117 				   in_user, strlen(in_user)+1,
118 				   NULL);
119 	bytes = smb_bytes_push_str(bytes,
120 				   smbXcli_conn_use_unicode(conn),
121 				   in_domain, strlen(in_domain)+1,
122 				   NULL);
123 	if (in_native_os != NULL) {
124 		bytes = smb_bytes_push_str(bytes,
125 					   smbXcli_conn_use_unicode(conn),
126 					   in_native_os, strlen(in_native_os)+1,
127 					   NULL);
128 	}
129 	if (in_native_lm != NULL) {
130 		bytes = smb_bytes_push_str(bytes,
131 					   smbXcli_conn_use_unicode(conn),
132 					   in_native_lm, strlen(in_native_lm)+1,
133 					   NULL);
134 	}
135 	if (tevent_req_nomem(bytes, req)) {
136 		return tevent_req_post(req, ev);
137 	}
138 
139 	subreq = smb1cli_req_send(state, ev, conn,
140 				  SMBsesssetupX,
141 				  0, /*  additional_flags */
142 				  0, /*  clear_flags */
143 				  0, /*  additional_flags2 */
144 				  0, /*  clear_flags2 */
145 				  timeout_msec,
146 				  pid,
147 				  NULL, /* tcon */
148 				  session,
149 				  10, /* wct */
150 				  vwv,
151 				  talloc_get_size(bytes),
152 				  bytes);
153 	if (tevent_req_nomem(subreq, req)) {
154 		return tevent_req_post(req, ev);
155 	}
156 	tevent_req_set_callback(subreq, smb1cli_session_setup_lm21_done, req);
157 
158 	return req;
159 }
160 
smb1cli_session_setup_lm21_done(struct tevent_req * subreq)161 static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq)
162 {
163 	struct tevent_req *req =
164 		tevent_req_callback_data(subreq,
165 		struct tevent_req);
166 	struct smb1cli_session_setup_lm21_state *state =
167 		tevent_req_data(req,
168 		struct smb1cli_session_setup_lm21_state);
169 	NTSTATUS status;
170 	uint8_t *inhdr = NULL;
171 	uint8_t wct;
172 	uint16_t *vwv = NULL;
173 	uint32_t num_bytes;
174 	uint8_t *bytes = NULL;
175 	const uint8_t *p = NULL;
176 	size_t ret = 0;
177 	uint16_t flags2;
178 	bool use_unicode = false;
179 	struct smb1cli_req_expected_response expected[] = {
180 	{
181 		.status = NT_STATUS_OK,
182 		.wct    = 3,
183 	},
184 	};
185 
186 	status = smb1cli_req_recv(subreq, state,
187 				  &state->recv_iov,
188 				  &inhdr,
189 				  &wct,
190 				  &vwv,
191 				  NULL, /* pvwv_offset */
192 				  &num_bytes,
193 				  &bytes,
194 				  NULL, /* pbytes_offset */
195 				  NULL, /* pinbuf */
196 				  expected, ARRAY_SIZE(expected));
197 	TALLOC_FREE(subreq);
198 	if (tevent_req_nterror(req, status)) {
199 		return;
200 	}
201 
202 	flags2 = SVAL(inhdr, HDR_FLG2);
203 	if (flags2 & FLAGS2_UNICODE_STRINGS) {
204 		use_unicode = true;
205 	}
206 
207 	state->out_session_id = SVAL(inhdr, HDR_UID);
208 	state->out_action = SVAL(vwv+2, 0);
209 
210 	p = bytes;
211 
212 	status = smb_bytes_pull_str(state, &state->out_native_os,
213 				    use_unicode, bytes, num_bytes,
214 				    p, &ret);
215 	if (tevent_req_nterror(req, status)) {
216 		return;
217 	}
218 	p += ret;
219 
220 	status = smb_bytes_pull_str(state, &state->out_native_lm,
221 				    use_unicode, bytes, num_bytes,
222 				    p, &ret);
223 	if (tevent_req_nterror(req, status)) {
224 		return;
225 	}
226 
227 	smb1cli_session_set_id(state->session, state->out_session_id);
228 	smb1cli_session_set_action(state->session, state->out_action);
229 
230 	tevent_req_done(req);
231 }
232 
smb1cli_session_setup_lm21_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,char ** out_native_os,char ** out_native_lm)233 NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req,
234 					 TALLOC_CTX *mem_ctx,
235 					 char **out_native_os,
236 					 char **out_native_lm)
237 {
238 	struct smb1cli_session_setup_lm21_state *state =
239 		tevent_req_data(req,
240 		struct smb1cli_session_setup_lm21_state);
241 	NTSTATUS status;
242 
243 	if (tevent_req_is_nterror(req, &status)) {
244 		tevent_req_received(req);
245 		return status;
246 	}
247 
248 	if (out_native_os != NULL) {
249 		*out_native_os = talloc_move(mem_ctx, &state->out_native_os);
250 	}
251 
252 	if (out_native_lm != NULL) {
253 		*out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
254 	}
255 
256 	tevent_req_received(req);
257 	return NT_STATUS_OK;
258 }
259 
260 struct smb1cli_session_setup_nt1_state {
261 	struct smbXcli_session *session;
262 	uint16_t vwv[13];
263 	struct iovec *recv_iov;
264 	uint8_t *inbuf;
265 	uint16_t out_session_id;
266 	uint16_t out_action;
267 	char *out_native_os;
268 	char *out_native_lm;
269 	char *out_primary_domain;
270 };
271 
272 static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq);
273 
smb1cli_session_setup_nt1_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct smbXcli_conn * conn,uint32_t timeout_msec,uint32_t pid,struct smbXcli_session * session,uint16_t in_buf_size,uint16_t in_mpx_max,uint16_t in_vc_num,uint32_t in_sess_key,const char * in_user,const char * in_domain,const DATA_BLOB in_apassword,const DATA_BLOB in_upassword,uint32_t in_capabilities,const char * in_native_os,const char * in_native_lm)274 struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx,
275 				struct tevent_context *ev,
276 				struct smbXcli_conn *conn,
277 				uint32_t timeout_msec,
278 				uint32_t pid,
279 				struct smbXcli_session *session,
280 				uint16_t in_buf_size,
281 				uint16_t in_mpx_max,
282 				uint16_t in_vc_num,
283 				uint32_t in_sess_key,
284 				const char *in_user,
285 				const char *in_domain,
286 				const DATA_BLOB in_apassword,
287 				const DATA_BLOB in_upassword,
288 				uint32_t in_capabilities,
289 				const char *in_native_os,
290 				const char *in_native_lm)
291 {
292 	struct tevent_req *req = NULL;
293 	struct smb1cli_session_setup_nt1_state *state = NULL;
294 	struct tevent_req *subreq = NULL;
295 	uint16_t *vwv = NULL;
296 	uint8_t *bytes = NULL;
297 	size_t align_upassword = 0;
298 	size_t apassword_ofs = 0;
299 	size_t upassword_ofs = 0;
300 
301 	req = tevent_req_create(mem_ctx, &state,
302 				struct smb1cli_session_setup_nt1_state);
303 	if (req == NULL) {
304 		return NULL;
305 	}
306 	state->session = session;
307 	vwv = state->vwv;
308 
309 	if (in_user == NULL) {
310 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
311 		return tevent_req_post(req, ev);
312 	}
313 
314 	if (in_domain == NULL) {
315 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
316 		return tevent_req_post(req, ev);
317 	}
318 
319 	if (in_apassword.length > UINT16_MAX) {
320 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
321 		return tevent_req_post(req, ev);
322 	}
323 
324 	if (in_upassword.length > UINT16_MAX) {
325 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
326 		return tevent_req_post(req, ev);
327 	}
328 
329 	if (in_native_os == NULL && in_native_lm != NULL) {
330 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
331 		return tevent_req_post(req, ev);
332 	}
333 
334 	SCVAL(vwv+0,  0, 0xff);
335 	SCVAL(vwv+0,  1, 0);
336 	SSVAL(vwv+1,  0, 0);
337 	SSVAL(vwv+2,  0, in_buf_size);
338 	SSVAL(vwv+3,  0, in_mpx_max);
339 	SSVAL(vwv+4,  0, in_vc_num);
340 	SIVAL(vwv+5,  0, in_sess_key);
341 	SSVAL(vwv+7,  0, in_apassword.length);
342 	SSVAL(vwv+8,  0, in_upassword.length);
343 	SSVAL(vwv+9,  0, 0); /* reserved */
344 	SSVAL(vwv+10, 0, 0); /* reserved */
345 	SIVAL(vwv+11, 0, in_capabilities);
346 
347 	if (in_apassword.length == 0 && in_upassword.length > 0) {
348 		/*
349 		 * This is plaintext auth with a unicode password,
350 		 * we need to align the buffer.
351 		 *
352 		 * This is what smbclient and Windows XP send as
353 		 * a client. And what smbd expects.
354 		 *
355 		 * But it doesn't follow [MS-CIFS] (v20160714)
356 		 * 2.2.4.53.1 SMB_COM_SESSION_SETUP_ANDX Request:
357 		 *
358 		 * ...
359 		 *
360 		 *  If SMB_FLAGS2_UNICODE is set (1), the value of OEMPasswordLen
361 		 *  MUST be 0x0000 and the password MUST be encoded using
362 		 *  UTF-16LE Unicode. Padding MUST NOT be added to
363 		 *  align this plaintext Unicode string to a word boundary.
364 		 *
365 		 * ...
366 		 */
367 		uint16_t security_mode = smb1cli_conn_server_security_mode(conn);
368 
369 		if (!(security_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) {
370 			align_upassword = 1;
371 		}
372 	}
373 
374 	bytes = talloc_array(state, uint8_t,
375 			     in_apassword.length +
376 			     align_upassword +
377 			     in_upassword.length);
378 	if (tevent_req_nomem(bytes, req)) {
379 		return tevent_req_post(req, ev);
380 	}
381 	if (in_apassword.length != 0) {
382 		memcpy(bytes + apassword_ofs,
383 		       in_apassword.data,
384 		       in_apassword.length);
385 		upassword_ofs += in_apassword.length;
386 	}
387 	if (align_upassword != 0) {
388 		memset(bytes + upassword_ofs, 0, align_upassword);
389 		upassword_ofs += align_upassword;
390 	}
391 	if (in_upassword.length != 0) {
392 		memcpy(bytes + upassword_ofs,
393 		       in_upassword.data,
394 		       in_upassword.length);
395 	}
396 
397 	bytes = smb_bytes_push_str(bytes,
398 				   smbXcli_conn_use_unicode(conn),
399 				   in_user, strlen(in_user)+1,
400 				   NULL);
401 	bytes = smb_bytes_push_str(bytes,
402 				   smbXcli_conn_use_unicode(conn),
403 				   in_domain, strlen(in_domain)+1,
404 				   NULL);
405 	if (in_native_os != NULL) {
406 		bytes = smb_bytes_push_str(bytes,
407 					   smbXcli_conn_use_unicode(conn),
408 					   in_native_os, strlen(in_native_os)+1,
409 					   NULL);
410 	}
411 	if (in_native_lm != NULL) {
412 		bytes = smb_bytes_push_str(bytes,
413 					   smbXcli_conn_use_unicode(conn),
414 					   in_native_lm, strlen(in_native_lm)+1,
415 					   NULL);
416 	}
417 	if (tevent_req_nomem(bytes, req)) {
418 		return tevent_req_post(req, ev);
419 	}
420 
421 	subreq = smb1cli_req_send(state, ev, conn,
422 				  SMBsesssetupX,
423 				  0, /*  additional_flags */
424 				  0, /*  clear_flags */
425 				  0, /*  additional_flags2 */
426 				  0, /*  clear_flags2 */
427 				  timeout_msec,
428 				  pid,
429 				  NULL, /* tcon */
430 				  session,
431 				  13, /* wct */
432 				  vwv,
433 				  talloc_get_size(bytes),
434 				  bytes);
435 	if (tevent_req_nomem(subreq, req)) {
436 		return tevent_req_post(req, ev);
437 	}
438 	tevent_req_set_callback(subreq, smb1cli_session_setup_nt1_done, req);
439 
440 	return req;
441 }
442 
smb1cli_session_setup_nt1_done(struct tevent_req * subreq)443 static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq)
444 {
445 	struct tevent_req *req =
446 		tevent_req_callback_data(subreq,
447 		struct tevent_req);
448 	struct smb1cli_session_setup_nt1_state *state =
449 		tevent_req_data(req,
450 		struct smb1cli_session_setup_nt1_state);
451 	NTSTATUS status;
452 	uint8_t *inhdr = NULL;
453 	uint8_t wct;
454 	uint16_t *vwv = NULL;
455 	uint32_t num_bytes;
456 	uint8_t *bytes = NULL;
457 	const uint8_t *p = NULL;
458 	size_t ret = 0;
459 	uint16_t flags2;
460 	bool use_unicode = false;
461 	struct smb1cli_req_expected_response expected[] = {
462 	{
463 		.status = NT_STATUS_OK,
464 		.wct    = 3,
465 	},
466 	};
467 
468 	status = smb1cli_req_recv(subreq, state,
469 				  &state->recv_iov,
470 				  &inhdr,
471 				  &wct,
472 				  &vwv,
473 				  NULL, /* pvwv_offset */
474 				  &num_bytes,
475 				  &bytes,
476 				  NULL, /* pbytes_offset */
477 				  &state->inbuf,
478 				  expected, ARRAY_SIZE(expected));
479 	TALLOC_FREE(subreq);
480 	if (tevent_req_nterror(req, status)) {
481 		return;
482 	}
483 
484 	flags2 = SVAL(inhdr, HDR_FLG2);
485 	if (flags2 & FLAGS2_UNICODE_STRINGS) {
486 		use_unicode = true;
487 	}
488 
489 	state->out_session_id = SVAL(inhdr, HDR_UID);
490 	state->out_action = SVAL(vwv+2, 0);
491 
492 	p = bytes;
493 
494 	status = smb_bytes_pull_str(state, &state->out_native_os,
495 				    use_unicode, bytes, num_bytes,
496 				    p, &ret);
497 	if (tevent_req_nterror(req, status)) {
498 		return;
499 	}
500 	p += ret;
501 
502 	status = smb_bytes_pull_str(state, &state->out_native_lm,
503 				    use_unicode, bytes, num_bytes,
504 				    p, &ret);
505 	if (tevent_req_nterror(req, status)) {
506 		return;
507 	}
508 	p += ret;
509 
510 	status = smb_bytes_pull_str(state, &state->out_primary_domain,
511 				    use_unicode, bytes, num_bytes,
512 				    p, &ret);
513 	if (tevent_req_nterror(req, status)) {
514 		return;
515 	}
516 
517 	smb1cli_session_set_id(state->session, state->out_session_id);
518 	smb1cli_session_set_action(state->session, state->out_action);
519 
520 	tevent_req_done(req);
521 }
522 
smb1cli_session_setup_nt1_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct iovec ** precv_iov,const uint8_t ** precv_inbuf,char ** out_native_os,char ** out_native_lm,char ** out_primary_domain)523 NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req,
524 					TALLOC_CTX *mem_ctx,
525 					struct iovec **precv_iov,
526 					const uint8_t **precv_inbuf,
527 					char **out_native_os,
528 					char **out_native_lm,
529 					char **out_primary_domain)
530 {
531 	struct smb1cli_session_setup_nt1_state *state =
532 		tevent_req_data(req,
533 		struct smb1cli_session_setup_nt1_state);
534 	NTSTATUS status;
535 	struct iovec *recv_iov = NULL;
536 
537 	if (tevent_req_is_nterror(req, &status)) {
538 		tevent_req_received(req);
539 		return status;
540 	}
541 
542 	recv_iov = talloc_move(mem_ctx, &state->recv_iov);
543 	if (precv_iov != NULL) {
544 		*precv_iov = recv_iov;
545 	}
546 	if (precv_inbuf != NULL) {
547 		*precv_inbuf = state->inbuf;
548 	}
549 
550 	if (out_native_os != NULL) {
551 		*out_native_os = talloc_move(mem_ctx, &state->out_native_os);
552 	}
553 
554 	if (out_native_lm != NULL) {
555 		*out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
556 	}
557 
558 	if (out_primary_domain != NULL) {
559 		*out_primary_domain = talloc_move(mem_ctx,
560 						  &state->out_primary_domain);
561 	}
562 
563 	tevent_req_received(req);
564 	return NT_STATUS_OK;
565 }
566 
567 struct smb1cli_session_setup_ext_state {
568 	struct smbXcli_session *session;
569 	uint16_t vwv[12];
570 	struct iovec *recv_iov;
571 	uint8_t *inbuf;
572 	NTSTATUS status;
573 	uint16_t out_session_id;
574 	uint16_t out_action;
575 	DATA_BLOB out_security_blob;
576 	char *out_native_os;
577 	char *out_native_lm;
578 };
579 
580 static void smb1cli_session_setup_ext_done(struct tevent_req *subreq);
581 
smb1cli_session_setup_ext_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct smbXcli_conn * conn,uint32_t timeout_msec,uint32_t pid,struct smbXcli_session * session,uint16_t in_buf_size,uint16_t in_mpx_max,uint16_t in_vc_num,uint32_t in_sess_key,const DATA_BLOB in_security_blob,uint32_t in_capabilities,const char * in_native_os,const char * in_native_lm)582 struct tevent_req *smb1cli_session_setup_ext_send(TALLOC_CTX *mem_ctx,
583 				struct tevent_context *ev,
584 				struct smbXcli_conn *conn,
585 				uint32_t timeout_msec,
586 				uint32_t pid,
587 				struct smbXcli_session *session,
588 				uint16_t in_buf_size,
589 				uint16_t in_mpx_max,
590 				uint16_t in_vc_num,
591 				uint32_t in_sess_key,
592 				const DATA_BLOB in_security_blob,
593 				uint32_t in_capabilities,
594 				const char *in_native_os,
595 				const char *in_native_lm)
596 {
597 	struct tevent_req *req = NULL;
598 	struct smb1cli_session_setup_ext_state *state = NULL;
599 	struct tevent_req *subreq = NULL;
600 	uint16_t *vwv = NULL;
601 	uint8_t *bytes = NULL;
602 
603 	req = tevent_req_create(mem_ctx, &state,
604 				struct smb1cli_session_setup_ext_state);
605 	if (req == NULL) {
606 		return NULL;
607 	}
608 	state->session = session;
609 	vwv = state->vwv;
610 
611 	if (in_security_blob.length > UINT16_MAX) {
612 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
613 		return tevent_req_post(req, ev);
614 	}
615 
616 	if (in_native_os == NULL && in_native_lm != NULL) {
617 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
618 		return tevent_req_post(req, ev);
619 	}
620 
621 	SCVAL(vwv+0,  0, 0xff);
622 	SCVAL(vwv+0,  1, 0);
623 	SSVAL(vwv+1,  0, 0);
624 	SSVAL(vwv+2,  0, in_buf_size);
625 	SSVAL(vwv+3,  0, in_mpx_max);
626 	SSVAL(vwv+4,  0, in_vc_num);
627 	SIVAL(vwv+5,  0, in_sess_key);
628 	SSVAL(vwv+7,  0, in_security_blob.length);
629 	SSVAL(vwv+8,  0, 0); /* reserved */
630 	SSVAL(vwv+9,  0, 0); /* reserved */
631 	SIVAL(vwv+10, 0, in_capabilities);
632 
633 	bytes = talloc_array(state, uint8_t,
634 			     in_security_blob.length);
635 	if (tevent_req_nomem(bytes, req)) {
636 		return tevent_req_post(req, ev);
637 	}
638 	if (in_security_blob.length != 0) {
639 		memcpy(bytes,
640 		       in_security_blob.data,
641 		       in_security_blob.length);
642 	}
643 
644 	if (in_native_os != NULL) {
645 		bytes = smb_bytes_push_str(bytes,
646 					   smbXcli_conn_use_unicode(conn),
647 					   in_native_os, strlen(in_native_os)+1,
648 					   NULL);
649 	}
650 	if (in_native_lm != NULL) {
651 		bytes = smb_bytes_push_str(bytes,
652 					   smbXcli_conn_use_unicode(conn),
653 					   in_native_lm, strlen(in_native_lm)+1,
654 					   NULL);
655 	}
656 	if (tevent_req_nomem(bytes, req)) {
657 		return tevent_req_post(req, ev);
658 	}
659 
660 	subreq = smb1cli_req_send(state, ev, conn,
661 				  SMBsesssetupX,
662 				  0, /*  additional_flags */
663 				  0, /*  clear_flags */
664 				  0, /*  additional_flags2 */
665 				  0, /*  clear_flags2 */
666 				  timeout_msec,
667 				  pid,
668 				  NULL, /* tcon */
669 				  session,
670 				  12, /* wct */
671 				  vwv,
672 				  talloc_get_size(bytes),
673 				  bytes);
674 	if (tevent_req_nomem(subreq, req)) {
675 		return tevent_req_post(req, ev);
676 	}
677 	tevent_req_set_callback(subreq, smb1cli_session_setup_ext_done, req);
678 
679 	return req;
680 }
681 
smb1cli_session_setup_ext_done(struct tevent_req * subreq)682 static void smb1cli_session_setup_ext_done(struct tevent_req *subreq)
683 {
684 	struct tevent_req *req =
685 		tevent_req_callback_data(subreq,
686 		struct tevent_req);
687 	struct smb1cli_session_setup_ext_state *state =
688 		tevent_req_data(req,
689 		struct smb1cli_session_setup_ext_state);
690 	NTSTATUS status;
691 	uint8_t *inhdr = NULL;
692 	uint8_t wct;
693 	uint16_t *vwv = NULL;
694 	uint32_t num_bytes;
695 	uint8_t *bytes = NULL;
696 	const uint8_t *p = NULL;
697 	size_t ret = 0;
698 	uint16_t flags2;
699 	uint16_t out_security_blob_length = 0;
700 	bool use_unicode = false;
701 	struct smb1cli_req_expected_response expected[] = {
702 	{
703 		.status = NT_STATUS_OK,
704 		.wct    = 4,
705 	},
706 	{
707 		.status = NT_STATUS_MORE_PROCESSING_REQUIRED,
708 		.wct    = 4,
709 	},
710 	};
711 
712 	status = smb1cli_req_recv(subreq, state,
713 				  &state->recv_iov,
714 				  &inhdr,
715 				  &wct,
716 				  &vwv,
717 				  NULL, /* pvwv_offset */
718 				  &num_bytes,
719 				  &bytes,
720 				  NULL, /* pbytes_offset */
721 				  &state->inbuf,
722 				  expected, ARRAY_SIZE(expected));
723 	TALLOC_FREE(subreq);
724 	state->status = status;
725 	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
726 		status = NT_STATUS_OK;
727 	}
728 	if (tevent_req_nterror(req, status)) {
729 		return;
730 	}
731 
732 	flags2 = SVAL(inhdr, HDR_FLG2);
733 	if (flags2 & FLAGS2_UNICODE_STRINGS) {
734 		use_unicode = true;
735 	}
736 
737 	state->out_session_id = SVAL(inhdr, HDR_UID);
738 	state->out_action = SVAL(vwv+2, 0);
739 	out_security_blob_length = SVAL(vwv+3, 0);
740 
741 	if (out_security_blob_length > num_bytes) {
742 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
743 		return;
744 	}
745 
746 	p = bytes;
747 
748 	/*
749 	 * Note: this points into state->recv_iov!
750 	 */
751 	state->out_security_blob = data_blob_const(p, out_security_blob_length);
752 	p += out_security_blob_length;
753 
754 	status = smb_bytes_pull_str(state, &state->out_native_os,
755 				    use_unicode, bytes, num_bytes,
756 				    p, &ret);
757 	if (tevent_req_nterror(req, status)) {
758 		return;
759 	}
760 	p += ret;
761 
762 	status = smb_bytes_pull_str(state, &state->out_native_lm,
763 				    use_unicode, bytes, num_bytes,
764 				    p, &ret);
765 	if (tevent_req_nterror(req, status)) {
766 		return;
767 	}
768 	/* p += ret; */
769 
770 	smb1cli_session_set_id(state->session, state->out_session_id);
771 	smb1cli_session_set_action(state->session, state->out_action);
772 
773 	tevent_req_done(req);
774 }
775 
smb1cli_session_setup_ext_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,struct iovec ** precv_iov,const uint8_t ** precv_inbuf,DATA_BLOB * out_security_blob,char ** out_native_os,char ** out_native_lm)776 NTSTATUS smb1cli_session_setup_ext_recv(struct tevent_req *req,
777 					TALLOC_CTX *mem_ctx,
778 					struct iovec **precv_iov,
779 					const uint8_t **precv_inbuf,
780 					DATA_BLOB *out_security_blob,
781 					char **out_native_os,
782 					char **out_native_lm)
783 {
784 	struct smb1cli_session_setup_ext_state *state =
785 		tevent_req_data(req,
786 		struct smb1cli_session_setup_ext_state);
787 	NTSTATUS status;
788 	struct iovec *recv_iov = NULL;
789 
790 	if (tevent_req_is_nterror(req, &status)) {
791 		tevent_req_received(req);
792 		return status;
793 	}
794 
795 	recv_iov = talloc_move(mem_ctx, &state->recv_iov);
796 	if (precv_iov != NULL) {
797 		*precv_iov = recv_iov;
798 	}
799 	if (precv_inbuf != NULL) {
800 		*precv_inbuf = state->inbuf;
801 	}
802 
803 	*out_security_blob = state->out_security_blob;
804 
805 	if (out_native_os != NULL) {
806 		*out_native_os = talloc_move(mem_ctx, &state->out_native_os);
807 	}
808 
809 	if (out_native_lm != NULL) {
810 		*out_native_lm = talloc_move(mem_ctx, &state->out_native_lm);
811 	}
812 
813 	/*
814 	 * Return the status from the server:
815 	 * NT_STATUS_MORE_PROCESSING_REQUIRED or
816 	 * NT_STATUS_OK.
817 	 */
818 	status = state->status;
819 	tevent_req_received(req);
820 	return status;
821 }
822