1 /*
2    Unix SMB/CIFS implementation.
3    client RAP calls
4    Copyright (C) Andrew Tridgell         1994-1998
5    Copyright (C) Gerald (Jerry) Carter   2004
6    Copyright (C) James Peach		 2007
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "includes.h"
23 #include "../libcli/auth/libcli_auth.h"
24 #include "../librpc/gen_ndr/rap.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "async_smb.h"
27 #include "libsmb/libsmb.h"
28 #include "libsmb/clirap.h"
29 #include "trans2.h"
30 #include "../libcli/smb/smbXcli_base.h"
31 #include "cli_smb2_fnum.h"
32 
33 #include <gnutls/gnutls.h>
34 #include <gnutls/crypto.h>
35 
36 #define PIPE_LANMAN   "\\PIPE\\LANMAN"
37 
38 /****************************************************************************
39  Call a remote api
40 ****************************************************************************/
41 
cli_api(struct cli_state * cli,char * param,int prcnt,int mprcnt,char * data,int drcnt,int mdrcnt,char ** rparam,unsigned int * rprcnt,char ** rdata,unsigned int * rdrcnt)42 bool cli_api(struct cli_state *cli,
43 	     char *param, int prcnt, int mprcnt,
44 	     char *data, int drcnt, int mdrcnt,
45 	     char **rparam, unsigned int *rprcnt,
46 	     char **rdata, unsigned int *rdrcnt)
47 {
48 	NTSTATUS status;
49 
50 	uint8_t *my_rparam, *my_rdata;
51 	uint32_t num_my_rparam, num_my_rdata;
52 
53 	status = cli_trans(talloc_tos(), cli, SMBtrans,
54 			   PIPE_LANMAN, 0, /* name, fid */
55 			   0, 0,	   /* function, flags */
56 			   NULL, 0, 0,	   /* setup */
57 			   (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
58 			   (uint8_t *)data, drcnt, mdrcnt,  /* Data, length, max */
59 			   NULL,		 /* recv_flags2 */
60 			   NULL, 0, NULL,	 /* rsetup */
61 			   &my_rparam, 0, &num_my_rparam,
62 			   &my_rdata, 0, &num_my_rdata);
63 	if (!NT_STATUS_IS_OK(status)) {
64 		return false;
65 	}
66 
67 	/*
68 	 * I know this memcpy massively hurts, but there are just tons
69 	 * of callers of cli_api that eventually need changing to
70 	 * talloc
71 	 */
72 
73 	*rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
74 	if (*rparam == NULL) {
75 		goto fail;
76 	}
77 	*rprcnt = num_my_rparam;
78 	TALLOC_FREE(my_rparam);
79 
80 	*rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
81 	if (*rdata == NULL) {
82 		goto fail;
83 	}
84 	*rdrcnt = num_my_rdata;
85 	TALLOC_FREE(my_rdata);
86 
87 	return true;
88 fail:
89 	TALLOC_FREE(my_rdata);
90 	TALLOC_FREE(my_rparam);
91 	*rparam = NULL;
92 	*rprcnt = 0;
93 	*rdata = NULL;
94 	*rdrcnt = 0;
95 	return false;
96 }
97 
98 /****************************************************************************
99  Perform a NetWkstaUserLogon.
100 ****************************************************************************/
101 
cli_NetWkstaUserLogon(struct cli_state * cli,char * user,char * workstation)102 bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
103 {
104 	char *rparam = NULL;
105 	char *rdata = NULL;
106 	char *p;
107 	unsigned int rdrcnt,rprcnt;
108 	char param[1024];
109 
110 	memset(param, 0, sizeof(param));
111 
112 	/* send a SMBtrans command with api NetWkstaUserLogon */
113 	p = param;
114 	SSVAL(p,0,132); /* api number */
115 	p += 2;
116 	strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
117 	p = skip_string(param,sizeof(param),p);
118 	strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
119 	p = skip_string(param,sizeof(param),p);
120 	SSVAL(p,0,1);
121 	p += 2;
122 	strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
123 	if (!strupper_m(p)) {
124 		return false;
125 	}
126 	p += 21;
127 	p++;
128 	p += 15;
129 	p++;
130 	strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
131 	if (!strupper_m(p)) {
132 		return false;
133 	}
134 	p += 16;
135 	SSVAL(p, 0, CLI_BUFFER_SIZE);
136 	p += 2;
137 	SSVAL(p, 0, CLI_BUFFER_SIZE);
138 	p += 2;
139 
140 	if (cli_api(cli,
141                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
142                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
143                     &rparam, &rprcnt,               /* return params, return size */
144                     &rdata, &rdrcnt                 /* return data, return size */
145                    )) {
146 		cli->rap_error = rparam? SVAL(rparam,0) : -1;
147 
148 		if (cli->rap_error == 0) {
149 			DEBUG(4,("NetWkstaUserLogon success\n"));
150 			/*
151 			 * The cli->privileges = SVAL(p, 24); field was set here
152 			 * but it was not use anywhere else.
153 			 */
154 			/* The cli->eff_name field used to be set here
155 	                   but it wasn't used anywhere else. */
156 		} else {
157 			DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
158 		}
159 	}
160 
161 	SAFE_FREE(rparam);
162 	SAFE_FREE(rdata);
163 	return (cli->rap_error == 0);
164 }
165 
166 /****************************************************************************
167  Call a NetShareEnum - try and browse available connections on a host.
168 ****************************************************************************/
169 
cli_RNetShareEnum(struct cli_state * cli,void (* fn)(const char *,uint32_t,const char *,void *),void * state)170 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
171 {
172 	char *rparam = NULL;
173 	char *rdata = NULL;
174 	char *p;
175 	unsigned int rdrcnt,rprcnt;
176 	char param[1024];
177 	int count = -1;
178 	bool ok;
179 	int res;
180 
181 	/* now send a SMBtrans command with api RNetShareEnum */
182 	p = param;
183 	SSVAL(p,0,0); /* api number */
184 	p += 2;
185 	strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
186 	p = skip_string(param,sizeof(param),p);
187 	strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
188 	p = skip_string(param,sizeof(param),p);
189 	SSVAL(p,0,1);
190 	/*
191 	 * Win2k needs a *smaller* buffer than 0xFFFF here -
192 	 * it returns "out of server memory" with 0xFFFF !!! JRA.
193 	 */
194 	SSVAL(p,2,0xFFE0);
195 	p += 4;
196 
197 	ok = cli_api(
198 		cli,
199 		param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
200 		NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
201 		&rparam, &rprcnt,                /* return params, length */
202 		&rdata, &rdrcnt);                /* return data, length */
203 	if (!ok) {
204 		DEBUG(4,("NetShareEnum failed\n"));
205 		goto done;
206 	}
207 
208 	if (rprcnt < 6) {
209 		DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
210 		goto done;
211 	}
212 
213 	res = rparam? SVAL(rparam,0) : -1;
214 
215 	if (res == 0 || res == ERRmoredata) {
216 		int converter=SVAL(rparam,2);
217 		int i;
218 		char *rdata_end = rdata + rdrcnt;
219 
220 		count=SVAL(rparam,4);
221 		p = rdata;
222 
223 		for (i=0;i<count;i++,p+=20) {
224 			char *sname;
225 			int type;
226 			int comment_offset;
227 			const char *cmnt;
228 			const char *p1;
229 			char *s1, *s2;
230 			size_t len;
231 			TALLOC_CTX *frame = talloc_stackframe();
232 
233 			if (p + 20 > rdata_end) {
234 				TALLOC_FREE(frame);
235 				break;
236 			}
237 
238 			sname = p;
239 			type = SVAL(p,14);
240 			comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
241 			if (comment_offset < 0 ||
242 			    comment_offset > (int)rdrcnt) {
243 				TALLOC_FREE(frame);
244 				break;
245 			}
246 			cmnt = comment_offset?(rdata+comment_offset):"";
247 
248 			/* Work out the comment length. */
249 			for (p1 = cmnt, len = 0; *p1 &&
250 				     p1 < rdata_end; len++)
251 				p1++;
252 			if (!*p1) {
253 				len++;
254 			}
255 			pull_string_talloc(frame,rdata,0,
256 					   &s1,sname,14,STR_ASCII);
257 			pull_string_talloc(frame,rdata,0,
258 					   &s2,cmnt,len,STR_ASCII);
259 			if (!s1 || !s2) {
260 				TALLOC_FREE(frame);
261 				continue;
262 			}
263 
264 			fn(s1, type, s2, state);
265 
266 			TALLOC_FREE(frame);
267 		}
268 	} else {
269 			DEBUG(4,("NetShareEnum res=%d\n", res));
270 	}
271 
272 done:
273 	SAFE_FREE(rparam);
274 	SAFE_FREE(rdata);
275 
276 	return count;
277 }
278 
279 /****************************************************************************
280  Call a NetServerEnum for the specified workgroup and servertype mask.  This
281  function then calls the specified callback function for each name returned.
282 
283  The callback function takes 4 arguments: the machine name, the server type,
284  the comment and a state pointer.
285 ****************************************************************************/
286 
cli_NetServerEnum(struct cli_state * cli,char * workgroup,uint32_t stype,void (* fn)(const char *,uint32_t,const char *,void *),void * state)287 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
288 		       void (*fn)(const char *, uint32_t, const char *, void *),
289 		       void *state)
290 {
291 	char *rparam = NULL;
292 	char *rdata = NULL;
293 	char *rdata_end = NULL;
294 	unsigned int rdrcnt,rprcnt;
295 	char *p;
296 	char param[1024];
297 	int uLevel = 1;
298 	size_t len;
299 	uint32_t func = RAP_NetServerEnum2;
300 	char *last_entry = NULL;
301 	int total_cnt = 0;
302 	int return_cnt = 0;
303 	int res;
304 
305 	errno = 0; /* reset */
306 
307 	/*
308 	 * This may take more than one transaction, so we should loop until
309 	 * we no longer get a more data to process or we have all of the
310 	 * items.
311 	 */
312 	do {
313 		/* send a SMBtrans command with api NetServerEnum */
314 	        p = param;
315 		SIVAL(p,0,func); /* api number */
316 	        p += 2;
317 
318 		if (func == RAP_NetServerEnum3) {
319 			strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
320 		} else {
321 			strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
322 		}
323 
324 		p = skip_string(param, sizeof(param), p);
325 		strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
326 
327 		p = skip_string(param, sizeof(param), p);
328 		SSVAL(p,0,uLevel);
329 		SSVAL(p,2,CLI_BUFFER_SIZE);
330 		p += 4;
331 		SIVAL(p,0,stype);
332 		p += 4;
333 
334 		/* If we have more data, tell the server where
335 		 * to continue from.
336 		 */
337 		len = push_ascii(p,
338 				workgroup,
339 				sizeof(param) - PTR_DIFF(p,param) - 1,
340 				STR_TERMINATE|STR_UPPER);
341 
342 		if (len == 0) {
343 			SAFE_FREE(last_entry);
344 			return false;
345 		}
346 		p += len;
347 
348 		if (func == RAP_NetServerEnum3) {
349 			len = push_ascii(p,
350 					last_entry ? last_entry : "",
351 					sizeof(param) - PTR_DIFF(p,param) - 1,
352 					STR_TERMINATE);
353 
354 			if (len == 0) {
355 				SAFE_FREE(last_entry);
356 				return false;
357 			}
358 			p += len;
359 		}
360 
361 		/* Next time through we need to use the continue api */
362 		func = RAP_NetServerEnum3;
363 
364 		if (!cli_api(cli,
365 			param, PTR_DIFF(p,param), 8, /* params, length, max */
366 			NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
367 		            &rparam, &rprcnt, /* return params, return size */
368 		            &rdata, &rdrcnt)) { /* return data, return size */
369 
370 			/* break out of the loop on error */
371 		        res = -1;
372 		        break;
373 		}
374 
375 		rdata_end = rdata + rdrcnt;
376 
377 		if (rprcnt < 6) {
378 			DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
379 			res = -1;
380 			break;
381 		}
382 
383 		res = rparam ? SVAL(rparam,0) : -1;
384 
385 		if (res == 0 || res == ERRmoredata ||
386                     (res != -1 && cli_errno(cli) == 0)) {
387 			char *sname = NULL;
388 			int i, count;
389 			int converter=SVAL(rparam,2);
390 
391 			/* Get the number of items returned in this buffer */
392 			count = SVAL(rparam, 4);
393 
394 			/* The next field contains the number of items left,
395 			 * including those returned in this buffer. So the
396 			 * first time through this should contain all of the
397 			 * entries.
398 			 */
399 			if (total_cnt == 0) {
400 			        total_cnt = SVAL(rparam, 6);
401 			}
402 
403 			/* Keep track of how many we have read */
404 			return_cnt += count;
405 			p = rdata;
406 
407 			/* The last name in the previous NetServerEnum reply is
408 			 * sent back to server in the NetServerEnum3 request
409 			 * (last_entry). The next reply should repeat this entry
410 			 * as the first element. We have no proof that this is
411 			 * always true, but from traces that seems to be the
412 			 * behavior from Window Servers. So first lets do a lot
413 			 * of checking, just being paranoid. If the string
414 			 * matches then we already saw this entry so skip it.
415 			 *
416 			 * NOTE: sv1_name field must be null terminated and has
417 			 * a max size of 16 (NetBIOS Name).
418 			 */
419 			if (last_entry && count && p &&
420 				(strncmp(last_entry, p, 16) == 0)) {
421 			    count -= 1; /* Skip this entry */
422 			    return_cnt = -1; /* Not part of total, so don't count. */
423 			    p = rdata + 26; /* Skip the whole record */
424 			}
425 
426 			for (i = 0; i < count; i++, p += 26) {
427 				int comment_offset;
428 				const char *cmnt;
429 				const char *p1;
430 				char *s1, *s2;
431 				TALLOC_CTX *frame = talloc_stackframe();
432 				uint32_t entry_stype;
433 
434 				if (p + 26 > rdata_end) {
435 					TALLOC_FREE(frame);
436 					break;
437 				}
438 
439 				sname = p;
440 				comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
441 				cmnt = comment_offset?(rdata+comment_offset):"";
442 
443 				if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
444 					TALLOC_FREE(frame);
445 					continue;
446 				}
447 
448 				/* Work out the comment length. */
449 				for (p1 = cmnt, len = 0; *p1 &&
450 						p1 < rdata_end; len++)
451 					p1++;
452 				if (!*p1) {
453 					len++;
454 				}
455 
456 				entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
457 
458 				pull_string_talloc(frame,rdata,0,
459 					&s1,sname,16,STR_ASCII);
460 				pull_string_talloc(frame,rdata,0,
461 					&s2,cmnt,len,STR_ASCII);
462 
463 				if (!s1 || !s2) {
464 					TALLOC_FREE(frame);
465 					continue;
466 				}
467 
468 				fn(s1, entry_stype, s2, state);
469 				TALLOC_FREE(frame);
470 			}
471 
472 			/* We are done with the old last entry, so now we can free it */
473 			if (last_entry) {
474 			        SAFE_FREE(last_entry); /* This will set it to null */
475 			}
476 
477 			/* We always make a copy of  the last entry if we have one */
478 			if (sname) {
479 			        last_entry = smb_xstrdup(sname);
480 			}
481 
482 			/* If we have more data, but no last entry then error out */
483 			if (!last_entry && (res == ERRmoredata)) {
484 			        errno = EINVAL;
485 			        res = 0;
486 			}
487 
488 		}
489 
490 		SAFE_FREE(rparam);
491 		SAFE_FREE(rdata);
492 	} while ((res == ERRmoredata) && (total_cnt > return_cnt));
493 
494 	SAFE_FREE(rparam);
495 	SAFE_FREE(rdata);
496 	SAFE_FREE(last_entry);
497 
498 	if (res == -1) {
499 		errno = cli_errno(cli);
500 	} else {
501 		if (!return_cnt) {
502 			/* this is a very special case, when the domain master for the
503 			   work group isn't part of the work group itself, there is something
504 			   wild going on */
505 			errno = ENOENT;
506 		}
507 	    }
508 
509 	return(return_cnt > 0);
510 }
511 
512 /****************************************************************************
513  Send a SamOEMChangePassword command.
514 ****************************************************************************/
515 
cli_oem_change_password(struct cli_state * cli,const char * user,const char * new_password,const char * old_password)516 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
517                              const char *old_password)
518 {
519 	char param[1024];
520 	unsigned char data[532];
521 	char *p = param;
522 	unsigned char old_pw_hash[16];
523 	unsigned char new_pw_hash[16];
524 	unsigned int data_len;
525 	unsigned int param_len = 0;
526 	char *rparam = NULL;
527 	char *rdata = NULL;
528 	unsigned int rprcnt, rdrcnt;
529 	gnutls_cipher_hd_t cipher_hnd = NULL;
530 	gnutls_datum_t old_pw_key = {
531 		.data = old_pw_hash,
532 		.size = sizeof(old_pw_hash),
533 	};
534 	int rc;
535 
536 	if (strlen(user) >= sizeof(fstring)-1) {
537 		DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
538 		return False;
539 	}
540 
541 	SSVAL(p,0,214); /* SamOEMChangePassword command. */
542 	p += 2;
543 	strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
544 	p = skip_string(param,sizeof(param),p);
545 	strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
546 	p = skip_string(param,sizeof(param),p);
547 	strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
548 	p = skip_string(param,sizeof(param),p);
549 	SSVAL(p,0,532);
550 	p += 2;
551 
552 	param_len = PTR_DIFF(p,param);
553 
554 	/*
555 	 * Get the Lanman hash of the old password, we
556 	 * use this as the key to make_oem_passwd_hash().
557 	 */
558 	E_deshash(old_password, old_pw_hash);
559 
560 	encode_pw_buffer(data, new_password, STR_ASCII);
561 
562 #ifdef DEBUG_PASSWORD
563 	DEBUG(100,("make_oem_passwd_hash\n"));
564 	dump_data(100, data, 516);
565 #endif
566 	rc = gnutls_cipher_init(&cipher_hnd,
567 				GNUTLS_CIPHER_ARCFOUR_128,
568 				&old_pw_key,
569 				NULL);
570 	if (rc < 0) {
571 		DBG_ERR("gnutls_cipher_init failed: %s\n",
572 			gnutls_strerror(rc));
573 		return false;
574 	}
575 	rc = gnutls_cipher_encrypt(cipher_hnd,
576 			      data,
577 			      516);
578 	gnutls_cipher_deinit(cipher_hnd);
579 	if (rc < 0) {
580 		return false;
581 	}
582 
583 	/*
584 	 * Now place the old password hash in the data.
585 	 */
586 	E_deshash(new_password, new_pw_hash);
587 
588 	rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
589 	if (rc != 0) {
590 		DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
591 		return false;
592 	}
593 
594 	data_len = 532;
595 
596 	if (!cli_api(cli,
597 		     param, param_len, 4,		/* param, length, max */
598 		     (char *)data, data_len, 0,		/* data, length, max */
599 		     &rparam, &rprcnt,
600 		     &rdata, &rdrcnt)) {
601 		DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
602 			user ));
603 		return False;
604 	}
605 
606 	if (rdrcnt < 2) {
607 		cli->rap_error = ERRbadformat;
608 		goto done;
609 	}
610 
611 	if (rparam) {
612 		cli->rap_error = SVAL(rparam,0);
613 	}
614 
615 done:
616 	SAFE_FREE(rparam);
617 	SAFE_FREE(rdata);
618 
619 	return (cli->rap_error == 0);
620 }
621 
622 /****************************************************************************
623  Send a qpathinfo call.
624 ****************************************************************************/
625 
626 struct cli_qpathinfo1_state {
627 	struct cli_state *cli;
628 	uint32_t num_data;
629 	uint8_t *data;
630 };
631 
632 static void cli_qpathinfo1_done(struct tevent_req *subreq);
633 
cli_qpathinfo1_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname)634 struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
635 				       struct tevent_context *ev,
636 				       struct cli_state *cli,
637 				       const char *fname)
638 {
639 	struct tevent_req *req = NULL, *subreq = NULL;
640 	struct cli_qpathinfo1_state *state = NULL;
641 
642 	req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
643 	if (req == NULL) {
644 		return NULL;
645 	}
646 	state->cli = cli;
647 	subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
648 				    22, CLI_BUFFER_SIZE);
649 	if (tevent_req_nomem(subreq, req)) {
650 		return tevent_req_post(req, ev);
651 	}
652 	tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
653 	return req;
654 }
655 
cli_qpathinfo1_done(struct tevent_req * subreq)656 static void cli_qpathinfo1_done(struct tevent_req *subreq)
657 {
658 	struct tevent_req *req = tevent_req_callback_data(
659 		subreq, struct tevent_req);
660 	struct cli_qpathinfo1_state *state = tevent_req_data(
661 		req, struct cli_qpathinfo1_state);
662 	NTSTATUS status;
663 
664 	status = cli_qpathinfo_recv(subreq, state, &state->data,
665 				    &state->num_data);
666 	TALLOC_FREE(subreq);
667 	if (!NT_STATUS_IS_OK(status)) {
668 		tevent_req_nterror(req, status);
669 		return;
670 	}
671 	tevent_req_done(req);
672 }
673 
cli_qpathinfo1_recv(struct tevent_req * req,time_t * change_time,time_t * access_time,time_t * write_time,off_t * size,uint16_t * mode)674 NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
675 			     time_t *change_time,
676 			     time_t *access_time,
677 			     time_t *write_time,
678 			     off_t *size,
679 			     uint16_t *mode)
680 {
681 	struct cli_qpathinfo1_state *state = tevent_req_data(
682 		req, struct cli_qpathinfo1_state);
683 	NTSTATUS status;
684 
685 	time_t (*date_fn)(const void *buf, int serverzone);
686 
687 	if (tevent_req_is_nterror(req, &status)) {
688 		return status;
689 	}
690 
691 	if (state->cli->win95) {
692 		date_fn = make_unix_date;
693 	} else {
694 		date_fn = make_unix_date2;
695 	}
696 
697 	if (change_time) {
698 		*change_time = date_fn(state->data+0, smb1cli_conn_server_time_zone(state->cli->conn));
699 	}
700 	if (access_time) {
701 		*access_time = date_fn(state->data+4, smb1cli_conn_server_time_zone(state->cli->conn));
702 	}
703 	if (write_time) {
704 		*write_time = date_fn(state->data+8, smb1cli_conn_server_time_zone(state->cli->conn));
705 	}
706 	if (size) {
707 		*size = IVAL(state->data, 12);
708 	}
709 	if (mode) {
710 		*mode = SVAL(state->data, l1_attrFile);
711 	}
712 	return NT_STATUS_OK;
713 }
714 
cli_qpathinfo1(struct cli_state * cli,const char * fname,time_t * change_time,time_t * access_time,time_t * write_time,off_t * size,uint16_t * mode)715 NTSTATUS cli_qpathinfo1(struct cli_state *cli,
716 			const char *fname,
717 			time_t *change_time,
718 			time_t *access_time,
719 			time_t *write_time,
720 			off_t *size,
721 			uint16_t *mode)
722 {
723 	TALLOC_CTX *frame = talloc_stackframe();
724 	struct tevent_context *ev;
725 	struct tevent_req *req;
726 	NTSTATUS status = NT_STATUS_NO_MEMORY;
727 
728 	if (smbXcli_conn_has_async_calls(cli->conn)) {
729 		/*
730 		 * Can't use sync call while an async call is in flight
731 		 */
732 		status = NT_STATUS_INVALID_PARAMETER;
733 		goto fail;
734 	}
735 	ev = samba_tevent_context_init(frame);
736 	if (ev == NULL) {
737 		goto fail;
738 	}
739 	req = cli_qpathinfo1_send(frame, ev, cli, fname);
740 	if (req == NULL) {
741 		goto fail;
742 	}
743 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
744 		goto fail;
745 	}
746 	status = cli_qpathinfo1_recv(req, change_time, access_time,
747 				     write_time, size, mode);
748  fail:
749 	TALLOC_FREE(frame);
750 	return status;
751 }
752 
753 /****************************************************************************
754  Send a setpathinfo call.
755 ****************************************************************************/
756 
cli_setpathinfo_basic(struct cli_state * cli,const char * fname,time_t create_time,time_t access_time,time_t write_time,time_t change_time,uint16_t mode)757 NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname,
758 			       time_t create_time,
759 			       time_t access_time,
760 			       time_t write_time,
761 			       time_t change_time,
762 			       uint16_t mode)
763 {
764 	unsigned int data_len = 0;
765 	char data[40];
766 	char *p;
767 
768         p = data;
769 
770         /*
771          * Add the create, last access, modification, and status change times
772          */
773         put_long_date(p, create_time);
774         p += 8;
775 
776         put_long_date(p, access_time);
777         p += 8;
778 
779         put_long_date(p, write_time);
780         p += 8;
781 
782         put_long_date(p, change_time);
783         p += 8;
784 
785 	if (mode == (uint16_t)-1 || mode == FILE_ATTRIBUTE_NORMAL) {
786 		/* No change. */
787 		mode = 0;
788 	} else if (mode == 0) {
789 		/* Clear all existing attributes. */
790 		mode = FILE_ATTRIBUTE_NORMAL;
791 	}
792 
793 	/* Add attributes */
794 	SIVAL(p, 0, mode);
795 
796         p += 4;
797 
798         /* Add padding */
799         SIVAL(p, 0, 0);
800         p += 4;
801 
802         data_len = PTR_DIFF(p, data);
803 
804 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
805 		DATA_BLOB in_data = data_blob_const(data, data_len);
806 		/*
807 		 * Split out SMB2 here as we need to select
808 		 * the correct info type and level.
809 		 */
810 		return cli_smb2_setpathinfo(cli,
811 				fname,
812 				1, /* SMB2_SETINFO_FILE */
813 				SMB_FILE_BASIC_INFORMATION - 1000,
814 				&in_data);
815 	}
816 
817 	return cli_setpathinfo(cli, SMB_FILE_BASIC_INFORMATION, fname,
818 			       (uint8_t *)data, data_len);
819 }
820 
cli_setpathinfo_ext(struct cli_state * cli,const char * fname,const struct timespec * create_time,const struct timespec * access_time,const struct timespec * write_time,const struct timespec * change_time,uint16_t mode)821 NTSTATUS cli_setpathinfo_ext(struct cli_state *cli, const char *fname,
822 			     const struct timespec *create_time,
823 			     const struct timespec *access_time,
824 			     const struct timespec *write_time,
825 			     const struct timespec *change_time,
826 			     uint16_t mode)
827 {
828 	unsigned int data_len = 0;
829 	char data[40];
830 	char *p;
831 
832 	p = data;
833 
834 	/*
835 	 * Add the create, last access, modification, and status change times
836 	 */
837 	put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, p, create_time);
838 	p += 8;
839 
840 	put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, p, access_time);
841 	p += 8;
842 
843 	put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, p, write_time);
844 	p += 8;
845 
846 	put_long_date_full_timespec(TIMESTAMP_SET_NT_OR_BETTER, p, change_time);
847 	p += 8;
848 
849 	if (mode == (uint16_t)-1 || mode == FILE_ATTRIBUTE_NORMAL) {
850 		/* No change. */
851 		mode = 0;
852 	} else if (mode == 0) {
853 		/* Clear all existing attributes. */
854 		mode = FILE_ATTRIBUTE_NORMAL;
855 	}
856 
857 	/* Add attributes */
858 	SIVAL(p, 0, mode);
859 
860 	p += 4;
861 
862 	/* Add padding */
863 	SIVAL(p, 0, 0);
864 	p += 4;
865 
866 	data_len = PTR_DIFF(p, data);
867 
868 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
869 		DATA_BLOB in_data = data_blob_const(data, data_len);
870 		/*
871 		 * Split out SMB2 here as we need to select
872 		 * the correct info type and level.
873 		 */
874 		return cli_smb2_setpathinfo(cli,
875 				fname,
876 				1, /* SMB2_SETINFO_FILE */
877 				SMB_FILE_BASIC_INFORMATION - 1000,
878 				&in_data);
879 	}
880 
881 	return cli_setpathinfo(cli, SMB_FILE_BASIC_INFORMATION, fname,
882 			       (uint8_t *)data, data_len);
883 }
884 
885 /****************************************************************************
886  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
887 ****************************************************************************/
888 
889 struct cli_qpathinfo2_state {
890 	uint32_t num_data;
891 	uint8_t *data;
892 };
893 
894 static void cli_qpathinfo2_done(struct tevent_req *subreq);
895 
cli_qpathinfo2_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname)896 struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
897 				       struct tevent_context *ev,
898 				       struct cli_state *cli,
899 				       const char *fname)
900 {
901 	struct tevent_req *req = NULL, *subreq = NULL;
902 	struct cli_qpathinfo2_state *state = NULL;
903 
904 	req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
905 	if (req == NULL) {
906 		return NULL;
907 	}
908 	subreq = cli_qpathinfo_send(state, ev, cli, fname,
909 				    SMB_QUERY_FILE_ALL_INFO,
910 				    68, CLI_BUFFER_SIZE);
911 	if (tevent_req_nomem(subreq, req)) {
912 		return tevent_req_post(req, ev);
913 	}
914 	tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
915 	return req;
916 }
917 
cli_qpathinfo2_done(struct tevent_req * subreq)918 static void cli_qpathinfo2_done(struct tevent_req *subreq)
919 {
920 	struct tevent_req *req = tevent_req_callback_data(
921 		subreq, struct tevent_req);
922 	struct cli_qpathinfo2_state *state = tevent_req_data(
923 		req, struct cli_qpathinfo2_state);
924 	NTSTATUS status;
925 
926 	status = cli_qpathinfo_recv(subreq, state, &state->data,
927 				    &state->num_data);
928 	TALLOC_FREE(subreq);
929 	if (!NT_STATUS_IS_OK(status)) {
930 		tevent_req_nterror(req, status);
931 		return;
932 	}
933 	tevent_req_done(req);
934 }
935 
cli_qpathinfo2_recv(struct tevent_req * req,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,off_t * size,uint16_t * mode,SMB_INO_T * ino)936 NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
937 			     struct timespec *create_time,
938 			     struct timespec *access_time,
939 			     struct timespec *write_time,
940 			     struct timespec *change_time,
941 			     off_t *size, uint16_t *mode,
942 			     SMB_INO_T *ino)
943 {
944 	struct cli_qpathinfo2_state *state = tevent_req_data(
945 		req, struct cli_qpathinfo2_state);
946 	NTSTATUS status;
947 
948 	if (tevent_req_is_nterror(req, &status)) {
949 		return status;
950 	}
951 
952 	if (create_time) {
953                 *create_time = interpret_long_date((char *)state->data+0);
954 	}
955 	if (access_time) {
956 		*access_time = interpret_long_date((char *)state->data+8);
957 	}
958 	if (write_time) {
959 		*write_time = interpret_long_date((char *)state->data+16);
960 	}
961 	if (change_time) {
962 		*change_time = interpret_long_date((char *)state->data+24);
963 	}
964 	if (mode) {
965 		*mode = SVAL(state->data, 32);
966 	}
967 	if (size) {
968                 *size = IVAL2_TO_SMB_BIG_UINT(state->data,48);
969 	}
970 	if (ino) {
971 		/*
972 		 * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO
973 		 * which doesn't return an inode number (fileid).
974 		 * We can't change this to one of the FILE_ID
975 		 * info levels as only Win2003 and above support
976 		 * these [MS-SMB: 2.2.2.3.1] and the SMB1 code
977 		 * needs to support older servers.
978 		 */
979 		*ino = 0;
980 	}
981 	return NT_STATUS_OK;
982 }
983 
cli_qpathinfo2(struct cli_state * cli,const char * fname,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,off_t * size,uint16_t * mode,SMB_INO_T * ino)984 NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
985 			struct timespec *create_time,
986 			struct timespec *access_time,
987 			struct timespec *write_time,
988 			struct timespec *change_time,
989 			off_t *size, uint16_t *mode,
990 			SMB_INO_T *ino)
991 {
992 	TALLOC_CTX *frame = NULL;
993 	struct tevent_context *ev;
994 	struct tevent_req *req;
995 	NTSTATUS status = NT_STATUS_NO_MEMORY;
996 
997 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
998 		return cli_smb2_qpathinfo2(cli,
999 					fname,
1000 					create_time,
1001 					access_time,
1002 					write_time,
1003 					change_time,
1004 					size,
1005 					mode,
1006 					ino);
1007 	}
1008 
1009 	frame = talloc_stackframe();
1010 
1011 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1012 		/*
1013 		 * Can't use sync call while an async call is in flight
1014 		 */
1015 		status = NT_STATUS_INVALID_PARAMETER;
1016 		goto fail;
1017 	}
1018 	ev = samba_tevent_context_init(frame);
1019 	if (ev == NULL) {
1020 		goto fail;
1021 	}
1022 	req = cli_qpathinfo2_send(frame, ev, cli, fname);
1023 	if (req == NULL) {
1024 		goto fail;
1025 	}
1026 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1027 		goto fail;
1028 	}
1029 	status = cli_qpathinfo2_recv(req, create_time, access_time,
1030 				     write_time, change_time, size, mode, ino);
1031  fail:
1032 	TALLOC_FREE(frame);
1033 	return status;
1034 }
1035 
1036 /****************************************************************************
1037  Get the stream info
1038 ****************************************************************************/
1039 
1040 struct cli_qpathinfo_streams_state {
1041 	uint32_t num_data;
1042 	uint8_t *data;
1043 };
1044 
1045 static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
1046 
cli_qpathinfo_streams_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname)1047 struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
1048 					      struct tevent_context *ev,
1049 					      struct cli_state *cli,
1050 					      const char *fname)
1051 {
1052 	struct tevent_req *req = NULL, *subreq = NULL;
1053 	struct cli_qpathinfo_streams_state *state = NULL;
1054 
1055 	req = tevent_req_create(mem_ctx, &state,
1056 				struct cli_qpathinfo_streams_state);
1057 	if (req == NULL) {
1058 		return NULL;
1059 	}
1060 	subreq = cli_qpathinfo_send(state, ev, cli, fname,
1061 				    SMB_FILE_STREAM_INFORMATION,
1062 				    0, CLI_BUFFER_SIZE);
1063 	if (tevent_req_nomem(subreq, req)) {
1064 		return tevent_req_post(req, ev);
1065 	}
1066 	tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
1067 	return req;
1068 }
1069 
cli_qpathinfo_streams_done(struct tevent_req * subreq)1070 static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
1071 {
1072 	struct tevent_req *req = tevent_req_callback_data(
1073 		subreq, struct tevent_req);
1074 	struct cli_qpathinfo_streams_state *state = tevent_req_data(
1075 		req, struct cli_qpathinfo_streams_state);
1076 	NTSTATUS status;
1077 
1078 	status = cli_qpathinfo_recv(subreq, state, &state->data,
1079 				    &state->num_data);
1080 	TALLOC_FREE(subreq);
1081 	if (!NT_STATUS_IS_OK(status)) {
1082 		tevent_req_nterror(req, status);
1083 		return;
1084 	}
1085 	tevent_req_done(req);
1086 }
1087 
cli_qpathinfo_streams_recv(struct tevent_req * req,TALLOC_CTX * mem_ctx,unsigned int * pnum_streams,struct stream_struct ** pstreams)1088 NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
1089 				    TALLOC_CTX *mem_ctx,
1090 				    unsigned int *pnum_streams,
1091 				    struct stream_struct **pstreams)
1092 {
1093 	struct cli_qpathinfo_streams_state *state = tevent_req_data(
1094                 req, struct cli_qpathinfo_streams_state);
1095         NTSTATUS status;
1096 
1097 	if (tevent_req_is_nterror(req, &status)) {
1098 		return status;
1099 	}
1100 	if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
1101 				pnum_streams, pstreams)) {
1102 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1103 	}
1104 	return NT_STATUS_OK;
1105 }
1106 
cli_qpathinfo_streams(struct cli_state * cli,const char * fname,TALLOC_CTX * mem_ctx,unsigned int * pnum_streams,struct stream_struct ** pstreams)1107 NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
1108 			       TALLOC_CTX *mem_ctx,
1109 			       unsigned int *pnum_streams,
1110 			       struct stream_struct **pstreams)
1111 {
1112 	TALLOC_CTX *frame = NULL;
1113 	struct tevent_context *ev;
1114 	struct tevent_req *req;
1115 	NTSTATUS status = NT_STATUS_NO_MEMORY;
1116 
1117 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1118 		return cli_smb2_qpathinfo_streams(cli,
1119 					fname,
1120 					mem_ctx,
1121 					pnum_streams,
1122 					pstreams);
1123 	}
1124 
1125 	frame = talloc_stackframe();
1126 
1127 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1128 		/*
1129 		 * Can't use sync call while an async call is in flight
1130 		 */
1131 		status = NT_STATUS_INVALID_PARAMETER;
1132 		goto fail;
1133 	}
1134 	ev = samba_tevent_context_init(frame);
1135 	if (ev == NULL) {
1136 		goto fail;
1137 	}
1138 	req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
1139 	if (req == NULL) {
1140 		goto fail;
1141 	}
1142 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1143 		goto fail;
1144 	}
1145 	status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
1146 					    pstreams);
1147  fail:
1148 	TALLOC_FREE(frame);
1149 	return status;
1150 }
1151 
parse_streams_blob(TALLOC_CTX * mem_ctx,const uint8_t * rdata,size_t data_len,unsigned int * pnum_streams,struct stream_struct ** pstreams)1152 bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
1153 			       size_t data_len,
1154 			       unsigned int *pnum_streams,
1155 			       struct stream_struct **pstreams)
1156 {
1157 	unsigned int num_streams;
1158 	struct stream_struct *streams;
1159 	unsigned int ofs;
1160 
1161 	num_streams = 0;
1162 	streams = NULL;
1163 	ofs = 0;
1164 
1165 	while ((data_len > ofs) && (data_len - ofs >= 24)) {
1166 		uint32_t nlen, len;
1167 		size_t size;
1168 		void *vstr;
1169 		struct stream_struct *tmp;
1170 		uint8_t *tmp_buf;
1171 
1172 		tmp = talloc_realloc(mem_ctx, streams,
1173 					   struct stream_struct,
1174 					   num_streams+1);
1175 
1176 		if (tmp == NULL) {
1177 			goto fail;
1178 		}
1179 		streams = tmp;
1180 
1181 		nlen                      = IVAL(rdata, ofs + 0x04);
1182 
1183 		streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1184 			rdata, ofs + 0x08);
1185 		streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1186 			rdata, ofs + 0x10);
1187 
1188 		if (nlen > data_len - (ofs + 24)) {
1189 			goto fail;
1190 		}
1191 
1192 		/*
1193 		 * We need to null-terminate src, how do I do this with
1194 		 * convert_string_talloc??
1195 		 */
1196 
1197 		tmp_buf = talloc_array(streams, uint8_t, nlen+2);
1198 		if (tmp_buf == NULL) {
1199 			goto fail;
1200 		}
1201 
1202 		memcpy(tmp_buf, rdata+ofs+24, nlen);
1203 		tmp_buf[nlen] = 0;
1204 		tmp_buf[nlen+1] = 0;
1205 
1206 		if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1207 					   nlen+2, &vstr, &size))
1208 		{
1209 			TALLOC_FREE(tmp_buf);
1210 			goto fail;
1211 		}
1212 
1213 		TALLOC_FREE(tmp_buf);
1214 		streams[num_streams].name = (char *)vstr;
1215 		num_streams++;
1216 
1217 		len = IVAL(rdata, ofs);
1218 		if (len > data_len - ofs) {
1219 			goto fail;
1220 		}
1221 		if (len == 0) break;
1222 		ofs += len;
1223 	}
1224 
1225 	*pnum_streams = num_streams;
1226 	*pstreams = streams;
1227 	return true;
1228 
1229  fail:
1230 	TALLOC_FREE(streams);
1231 	return false;
1232 }
1233 
1234 /****************************************************************************
1235  Send a qfileinfo QUERY_FILE_NAME_INFO call.
1236 ****************************************************************************/
1237 
cli_qfilename(struct cli_state * cli,uint16_t fnum,TALLOC_CTX * mem_ctx,char ** _name)1238 NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum,
1239 		       TALLOC_CTX *mem_ctx, char **_name)
1240 {
1241 	uint16_t recv_flags2;
1242 	uint8_t *rdata;
1243 	uint32_t num_rdata;
1244 	NTSTATUS status;
1245 	char *name = NULL;
1246 	uint32_t namelen;
1247 
1248 	status = cli_qfileinfo(talloc_tos(), cli, fnum,
1249 			       SMB_QUERY_FILE_NAME_INFO,
1250 			       4, CLI_BUFFER_SIZE, &recv_flags2,
1251 			       &rdata, &num_rdata);
1252 	if (!NT_STATUS_IS_OK(status)) {
1253 		return status;
1254 	}
1255 
1256 	namelen = IVAL(rdata, 0);
1257 	if (namelen > (num_rdata - 4)) {
1258 		TALLOC_FREE(rdata);
1259 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1260 	}
1261 
1262 	clistr_pull_talloc(mem_ctx,
1263 			   (const char *)rdata,
1264 			   recv_flags2,
1265 			   &name,
1266 			   rdata + 4,
1267 			   namelen,
1268 			   STR_UNICODE);
1269 	if (name == NULL) {
1270 		status = map_nt_error_from_unix(errno);
1271 		TALLOC_FREE(rdata);
1272 		return status;
1273 	}
1274 
1275 	*_name = name;
1276 	TALLOC_FREE(rdata);
1277 	return NT_STATUS_OK;
1278 }
1279 
1280 /****************************************************************************
1281  Send a qfileinfo call.
1282 ****************************************************************************/
1283 
cli_qfileinfo_basic(struct cli_state * cli,uint16_t fnum,uint16_t * mode,off_t * size,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,SMB_INO_T * ino)1284 NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum,
1285 			     uint16_t *mode, off_t *size,
1286 			     struct timespec *create_time,
1287 			     struct timespec *access_time,
1288 			     struct timespec *write_time,
1289 			     struct timespec *change_time,
1290 			     SMB_INO_T *ino)
1291 {
1292 	uint8_t *rdata;
1293 	uint32_t num_rdata;
1294 	NTSTATUS status;
1295 
1296 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1297 		return cli_smb2_qfileinfo_basic(cli,
1298 						fnum,
1299 						mode,
1300 						size,
1301 						create_time,
1302 						access_time,
1303 						write_time,
1304 						change_time,
1305 						ino);
1306 	}
1307 
1308 	/* if its a win95 server then fail this - win95 totally screws it
1309 	   up */
1310 	if (cli->win95) {
1311 		return NT_STATUS_NOT_SUPPORTED;
1312 	}
1313 
1314 	status = cli_qfileinfo(talloc_tos(), cli, fnum,
1315 			       SMB_QUERY_FILE_ALL_INFO,
1316 			       68, CLI_BUFFER_SIZE,
1317 			       NULL,
1318 			       &rdata, &num_rdata);
1319 	if (!NT_STATUS_IS_OK(status)) {
1320 		return status;
1321 	}
1322 
1323 	if (create_time) {
1324 		*create_time = interpret_long_date((char *)rdata+0);
1325 	}
1326 	if (access_time) {
1327 		*access_time = interpret_long_date((char *)rdata+8);
1328 	}
1329 	if (write_time) {
1330 		*write_time = interpret_long_date((char *)rdata+16);
1331 	}
1332 	if (change_time) {
1333 		*change_time = interpret_long_date((char *)rdata+24);
1334 	}
1335 	if (mode) {
1336 		*mode = SVAL(rdata, 32);
1337 	}
1338 	if (size) {
1339                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
1340 	}
1341 	if (ino) {
1342 		*ino = IVAL(rdata, 64);
1343 	}
1344 
1345 	TALLOC_FREE(rdata);
1346 	return NT_STATUS_OK;
1347 }
1348 
1349 /****************************************************************************
1350  Send a qpathinfo BASIC_INFO call.
1351 ****************************************************************************/
1352 
1353 struct cli_qpathinfo_basic_state {
1354 	uint32_t num_data;
1355 	uint8_t *data;
1356 };
1357 
1358 static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1359 
cli_qpathinfo_basic_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct cli_state * cli,const char * fname)1360 struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1361 					    struct tevent_context *ev,
1362 					    struct cli_state *cli,
1363 					    const char *fname)
1364 {
1365 	struct tevent_req *req = NULL, *subreq = NULL;
1366 	struct cli_qpathinfo_basic_state *state = NULL;
1367 
1368 	req = tevent_req_create(mem_ctx, &state,
1369 				struct cli_qpathinfo_basic_state);
1370 	if (req == NULL) {
1371 		return NULL;
1372 	}
1373 	subreq = cli_qpathinfo_send(state, ev, cli, fname,
1374 				    SMB_QUERY_FILE_BASIC_INFO,
1375 				    36, CLI_BUFFER_SIZE);
1376 	if (tevent_req_nomem(subreq, req)) {
1377 		return tevent_req_post(req, ev);
1378 	}
1379 	tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1380 	return req;
1381 }
1382 
cli_qpathinfo_basic_done(struct tevent_req * subreq)1383 static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1384 {
1385 	struct tevent_req *req = tevent_req_callback_data(
1386 		subreq, struct tevent_req);
1387 	struct cli_qpathinfo_basic_state *state = tevent_req_data(
1388 		req, struct cli_qpathinfo_basic_state);
1389 	NTSTATUS status;
1390 
1391 	status = cli_qpathinfo_recv(subreq, state, &state->data,
1392 				    &state->num_data);
1393 	TALLOC_FREE(subreq);
1394 	if (!NT_STATUS_IS_OK(status)) {
1395 		tevent_req_nterror(req, status);
1396 		return;
1397 	}
1398 	tevent_req_done(req);
1399 }
1400 
cli_qpathinfo_basic_recv(struct tevent_req * req,SMB_STRUCT_STAT * sbuf,uint32_t * attributes)1401 NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1402 				  SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1403 {
1404 	struct cli_qpathinfo_basic_state *state = tevent_req_data(
1405 		req, struct cli_qpathinfo_basic_state);
1406 	NTSTATUS status;
1407 
1408 	if (tevent_req_is_nterror(req, &status)) {
1409 		return status;
1410 	}
1411 
1412 	sbuf->st_ex_btime = interpret_long_date((char *)state->data);
1413 	sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
1414 	sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
1415 	sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
1416 	*attributes = IVAL(state->data, 32);
1417 	return NT_STATUS_OK;
1418 }
1419 
cli_qpathinfo_basic(struct cli_state * cli,const char * name,SMB_STRUCT_STAT * sbuf,uint32_t * attributes)1420 NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1421 			     SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1422 {
1423 	TALLOC_CTX *frame = NULL;
1424 	struct tevent_context *ev;
1425 	struct tevent_req *req;
1426 	NTSTATUS status = NT_STATUS_NO_MEMORY;
1427 
1428 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1429 		return cli_smb2_qpathinfo_basic(cli,
1430 						name,
1431 						sbuf,
1432 						attributes);
1433 	}
1434 
1435 	frame = talloc_stackframe();
1436 
1437 	if (smbXcli_conn_has_async_calls(cli->conn)) {
1438 		/*
1439 		 * Can't use sync call while an async call is in flight
1440 		 */
1441 		status = NT_STATUS_INVALID_PARAMETER;
1442 		goto fail;
1443 	}
1444 	ev = samba_tevent_context_init(frame);
1445 	if (ev == NULL) {
1446 		goto fail;
1447 	}
1448 	req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1449 	if (req == NULL) {
1450 		goto fail;
1451 	}
1452 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1453 		goto fail;
1454 	}
1455 	status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1456  fail:
1457 	TALLOC_FREE(frame);
1458 	return status;
1459 }
1460 
1461 /****************************************************************************
1462  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1463 ****************************************************************************/
1464 
cli_qpathinfo_alt_name(struct cli_state * cli,const char * fname,fstring alt_name)1465 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1466 {
1467 	uint8_t *rdata;
1468 	uint32_t num_rdata;
1469 	unsigned int len;
1470 	char *converted = NULL;
1471 	size_t converted_size = 0;
1472 	NTSTATUS status;
1473 
1474 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1475 		return cli_smb2_qpathinfo_alt_name(cli,
1476 						fname,
1477 						alt_name);
1478 	}
1479 
1480 	status = cli_qpathinfo(talloc_tos(), cli, fname,
1481 			       SMB_QUERY_FILE_ALT_NAME_INFO,
1482 			       4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1483 	if (!NT_STATUS_IS_OK(status)) {
1484 		return status;
1485 	}
1486 
1487 	len = IVAL(rdata, 0);
1488 
1489 	if (len > num_rdata - 4) {
1490 		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1491 	}
1492 
1493 	/* The returned data is a pushed string, not raw data. */
1494 	if (!convert_string_talloc(talloc_tos(),
1495 				   smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1496 				   CH_UNIX,
1497 				   rdata + 4,
1498 				   len,
1499 				   &converted,
1500 				   &converted_size)) {
1501 		return NT_STATUS_NO_MEMORY;
1502 	}
1503 	fstrcpy(alt_name, converted);
1504 
1505 	TALLOC_FREE(converted);
1506 	TALLOC_FREE(rdata);
1507 
1508 	return NT_STATUS_OK;
1509 }
1510 
1511 /****************************************************************************
1512  Send a qpathinfo SMB_QUERY_FILE_STADNDARD_INFO call.
1513 ****************************************************************************/
1514 
cli_qpathinfo_standard(struct cli_state * cli,const char * fname,uint64_t * allocated,uint64_t * size,uint32_t * nlinks,bool * is_del_pending,bool * is_dir)1515 NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
1516 				uint64_t *allocated, uint64_t *size,
1517 				uint32_t *nlinks,
1518 				bool *is_del_pending, bool *is_dir)
1519 {
1520 	uint8_t *rdata;
1521 	uint32_t num_rdata;
1522 	NTSTATUS status;
1523 
1524 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1525 		return NT_STATUS_NOT_IMPLEMENTED;
1526 	}
1527 
1528 	status = cli_qpathinfo(talloc_tos(), cli, fname,
1529 			       SMB_QUERY_FILE_STANDARD_INFO,
1530 			       24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1531 	if (!NT_STATUS_IS_OK(status)) {
1532 		return status;
1533 	}
1534 
1535 	if (allocated) {
1536 		*allocated = BVAL(rdata, 0);
1537 	}
1538 
1539 	if (size) {
1540 		*size = BVAL(rdata, 8);
1541 	}
1542 
1543 	if (nlinks) {
1544 		*nlinks = IVAL(rdata, 16);
1545 	}
1546 
1547 	if (is_del_pending) {
1548 		*is_del_pending = CVAL(rdata, 20);
1549 	}
1550 
1551 	if (is_dir) {
1552 		*is_dir = CVAL(rdata, 20);
1553 	}
1554 
1555 	TALLOC_FREE(rdata);
1556 
1557 	return NT_STATUS_OK;
1558 }
1559 
1560 
1561 /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
cli_qpathinfo3(struct cli_state * cli,const char * fname,struct timespec * create_time,struct timespec * access_time,struct timespec * write_time,struct timespec * change_time,off_t * size,uint16_t * mode,SMB_INO_T * ino)1562 NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
1563 			struct timespec *create_time,
1564 			struct timespec *access_time,
1565 			struct timespec *write_time,
1566 			struct timespec *change_time,
1567 			off_t *size, uint16_t *mode,
1568 			SMB_INO_T *ino)
1569 {
1570 	NTSTATUS status = NT_STATUS_OK;
1571 	SMB_STRUCT_STAT st = { 0 };
1572 	uint32_t attr = 0;
1573 	uint64_t pos;
1574 
1575 	if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1576 		return cli_qpathinfo2(cli, fname,
1577 				      create_time, access_time, write_time, change_time,
1578 				      size, mode, ino);
1579 	}
1580 
1581 	if (create_time || access_time || write_time || change_time || mode) {
1582 		status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1583 		if (!NT_STATUS_IS_OK(status)) {
1584 			return status;
1585 		}
1586 	}
1587 
1588 	if (size) {
1589 		status = cli_qpathinfo_standard(cli, fname,
1590 						NULL, &pos, NULL, NULL, NULL);
1591 		if (!NT_STATUS_IS_OK(status)) {
1592 			return status;
1593 		}
1594 
1595 		*size = pos;
1596 	}
1597 
1598 	if (create_time) {
1599 		*create_time = st.st_ex_btime;
1600 	}
1601 	if (access_time) {
1602 		*access_time = st.st_ex_atime;
1603 	}
1604 	if (write_time) {
1605 		*write_time = st.st_ex_mtime;
1606 	}
1607 	if (change_time) {
1608 		*change_time = st.st_ex_ctime;
1609 	}
1610 	if (mode) {
1611 		*mode = attr;
1612 	}
1613 	if (ino) {
1614 		*ino = 0;
1615 	}
1616 
1617 	return NT_STATUS_OK;
1618 }
1619