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
25/****************************************************************************
26 Call a remote api
27****************************************************************************/
28
29bool cli_api(struct cli_state *cli,
30	     char *param, int prcnt, int mprcnt,
31	     char *data, int drcnt, int mdrcnt,
32	     char **rparam, unsigned int *rprcnt,
33	     char **rdata, unsigned int *rdrcnt)
34{
35	cli_send_trans(cli,SMBtrans,
36                 PIPE_LANMAN,             /* Name */
37                 0,0,                     /* fid, flags */
38                 NULL,0,0,                /* Setup, length, max */
39                 param, prcnt, mprcnt,    /* Params, length, max */
40                 data, drcnt, mdrcnt      /* Data, length, max */
41                );
42
43	return (cli_receive_trans(cli,SMBtrans,
44                            rparam, rprcnt,
45                            rdata, rdrcnt));
46}
47
48/****************************************************************************
49 Perform a NetWkstaUserLogon.
50****************************************************************************/
51
52bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
53{
54	char *rparam = NULL;
55	char *rdata = NULL;
56	char *p;
57	unsigned int rdrcnt,rprcnt;
58	char param[1024];
59
60	memset(param, 0, sizeof(param));
61
62	/* send a SMBtrans command with api NetWkstaUserLogon */
63	p = param;
64	SSVAL(p,0,132); /* api number */
65	p += 2;
66	strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
67	p = skip_string(param,sizeof(param),p);
68	strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
69	p = skip_string(param,sizeof(param),p);
70	SSVAL(p,0,1);
71	p += 2;
72	strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
73	strupper_m(p);
74	p += 21;
75	p++;
76	p += 15;
77	p++;
78	strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
79	strupper_m(p);
80	p += 16;
81	SSVAL(p, 0, CLI_BUFFER_SIZE);
82	p += 2;
83	SSVAL(p, 0, CLI_BUFFER_SIZE);
84	p += 2;
85
86	if (cli_api(cli,
87                    param, PTR_DIFF(p,param),1024,  /* param, length, max */
88                    NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
89                    &rparam, &rprcnt,               /* return params, return size */
90                    &rdata, &rdrcnt                 /* return data, return size */
91                   )) {
92		cli->rap_error = rparam? SVAL(rparam,0) : -1;
93		p = rdata;
94
95		if (cli->rap_error == 0) {
96			DEBUG(4,("NetWkstaUserLogon success\n"));
97			cli->privileges = SVAL(p, 24);
98			/* The cli->eff_name field used to be set here
99	                   but it wasn't used anywhere else. */
100		} else {
101			DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
102		}
103	}
104
105	SAFE_FREE(rparam);
106	SAFE_FREE(rdata);
107	return (cli->rap_error == 0);
108}
109
110/****************************************************************************
111 Call a NetShareEnum - try and browse available connections on a host.
112****************************************************************************/
113
114int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
115{
116	char *rparam = NULL;
117	char *rdata = NULL;
118	char *p;
119	unsigned int rdrcnt,rprcnt;
120	char param[1024];
121	int count = -1;
122
123	/* now send a SMBtrans command with api RNetShareEnum */
124	p = param;
125	SSVAL(p,0,0); /* api number */
126	p += 2;
127	strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
128	p = skip_string(param,sizeof(param),p);
129	strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
130	p = skip_string(param,sizeof(param),p);
131	SSVAL(p,0,1);
132	/*
133	 * Win2k needs a *smaller* buffer than 0xFFFF here -
134	 * it returns "out of server memory" with 0xFFFF !!! JRA.
135	 */
136	SSVAL(p,2,0xFFE0);
137	p += 4;
138
139	if (cli_api(cli,
140		    param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
141		    NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
142		    &rparam, &rprcnt,                /* return params, length */
143		    &rdata, &rdrcnt))                /* return data, length */
144		{
145			int res = rparam? SVAL(rparam,0) : -1;
146
147			if (res == 0 || res == ERRmoredata) {
148				int converter=SVAL(rparam,2);
149				int i;
150				char *rdata_end = rdata + rdrcnt;
151
152				count=SVAL(rparam,4);
153				p = rdata;
154
155				for (i=0;i<count;i++,p+=20) {
156					char *sname;
157					int type;
158					int comment_offset;
159					const char *cmnt;
160					const char *p1;
161					char *s1, *s2;
162					size_t len;
163					TALLOC_CTX *frame = talloc_stackframe();
164
165					if (p + 20 > rdata_end) {
166						TALLOC_FREE(frame);
167						break;
168					}
169
170					sname = p;
171					type = SVAL(p,14);
172					comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
173					if (comment_offset < 0 ||
174							comment_offset > (int)rdrcnt) {
175						TALLOC_FREE(frame);
176						break;
177					}
178					cmnt = comment_offset?(rdata+comment_offset):"";
179
180					/* Work out the comment length. */
181					for (p1 = cmnt, len = 0; *p1 &&
182							p1 < rdata_end; len++)
183						p1++;
184					if (!*p1) {
185						len++;
186					}
187					pull_string_talloc(frame,rdata,0,
188						&s1,sname,14,STR_ASCII);
189					pull_string_talloc(frame,rdata,0,
190						&s2,cmnt,len,STR_ASCII);
191					if (!s1 || !s2) {
192						TALLOC_FREE(frame);
193						continue;
194					}
195
196					fn(s1, type, s2, state);
197
198					TALLOC_FREE(frame);
199				}
200			} else {
201				DEBUG(4,("NetShareEnum res=%d\n", res));
202			}
203		} else {
204			DEBUG(4,("NetShareEnum failed\n"));
205		}
206
207	SAFE_FREE(rparam);
208	SAFE_FREE(rdata);
209
210	return count;
211}
212
213/****************************************************************************
214 Call a NetServerEnum for the specified workgroup and servertype mask.  This
215 function then calls the specified callback function for each name returned.
216
217 The callback function takes 4 arguments: the machine name, the server type,
218 the comment and a state pointer.
219****************************************************************************/
220
221bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
222		       void (*fn)(const char *, uint32, const char *, void *),
223		       void *state)
224{
225	char *rparam = NULL;
226	char *rdata = NULL;
227	char *rdata_end = NULL;
228	unsigned int rdrcnt,rprcnt;
229	char *p;
230	char param[1024];
231	int uLevel = 1;
232	size_t len;
233	uint32 func = RAP_NetServerEnum2;
234	char *last_entry = NULL;
235	int total_cnt = 0;
236	int return_cnt = 0;
237	int res;
238
239	errno = 0; /* reset */
240
241	/*
242	 * This may take more than one transaction, so we should loop until
243	 * we no longer get a more data to process or we have all of the
244	 * items.
245	 */
246	do {
247		/* send a SMBtrans command with api NetServerEnum */
248	        p = param;
249		SIVAL(p,0,func); /* api number */
250	        p += 2;
251
252		if (func == RAP_NetServerEnum3) {
253			strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
254		} else {
255			strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
256		}
257
258		p = skip_string(param, sizeof(param), p);
259		strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
260
261		p = skip_string(param, sizeof(param), p);
262		SSVAL(p,0,uLevel);
263		SSVAL(p,2,CLI_BUFFER_SIZE);
264		p += 4;
265		SIVAL(p,0,stype);
266		p += 4;
267
268		/* If we have more data, tell the server where
269		 * to continue from.
270		 */
271		len = push_ascii(p,
272				workgroup,
273				sizeof(param) - PTR_DIFF(p,param) - 1,
274				STR_TERMINATE|STR_UPPER);
275
276		if (len == (size_t)-1) {
277			SAFE_FREE(last_entry);
278			return false;
279		}
280		p += len;
281
282		if (func == RAP_NetServerEnum3) {
283			len = push_ascii(p,
284					last_entry ? last_entry : "",
285					sizeof(param) - PTR_DIFF(p,param) - 1,
286					STR_TERMINATE);
287
288			if (len == (size_t)-1) {
289				SAFE_FREE(last_entry);
290				return false;
291			}
292			p += len;
293		}
294
295		/* Next time through we need to use the continue api */
296		func = RAP_NetServerEnum3;
297
298		if (!cli_api(cli,
299			param, PTR_DIFF(p,param), 8, /* params, length, max */
300			NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
301		            &rparam, &rprcnt, /* return params, return size */
302		            &rdata, &rdrcnt)) { /* return data, return size */
303
304			/* break out of the loop on error */
305		        res = -1;
306		        break;
307		}
308
309		rdata_end = rdata + rdrcnt;
310		res = rparam ? SVAL(rparam,0) : -1;
311
312		if (res == 0 || res == ERRmoredata ||
313                    (res != -1 && cli_errno(cli) == 0)) {
314			char *sname = NULL;
315			int i, count;
316			int converter=SVAL(rparam,2);
317
318			/* Get the number of items returned in this buffer */
319			count = SVAL(rparam, 4);
320
321			/* The next field contains the number of items left,
322			 * including those returned in this buffer. So the
323			 * first time through this should contain all of the
324			 * entries.
325			 */
326			if (total_cnt == 0) {
327			        total_cnt = SVAL(rparam, 6);
328			}
329
330			/* Keep track of how many we have read */
331			return_cnt += count;
332			p = rdata;
333
334			/* The last name in the previous NetServerEnum reply is
335			 * sent back to server in the NetServerEnum3 request
336			 * (last_entry). The next reply should repeat this entry
337			 * as the first element. We have no proof that this is
338			 * always true, but from traces that seems to be the
339			 * behavior from Window Servers. So first lets do a lot
340			 * of checking, just being paranoid. If the string
341			 * matches then we already saw this entry so skip it.
342			 *
343			 * NOTE: sv1_name field must be null terminated and has
344			 * a max size of 16 (NetBIOS Name).
345			 */
346			if (last_entry && count && p &&
347				(strncmp(last_entry, p, 16) == 0)) {
348			    count -= 1; /* Skip this entry */
349			    return_cnt = -1; /* Not part of total, so don't count. */
350			    p = rdata + 26; /* Skip the whole record */
351			}
352
353			for (i = 0; i < count; i++, p += 26) {
354				int comment_offset;
355				const char *cmnt;
356				const char *p1;
357				char *s1, *s2;
358				TALLOC_CTX *frame = talloc_stackframe();
359				uint32_t entry_stype;
360
361				if (p + 26 > rdata_end) {
362					TALLOC_FREE(frame);
363					break;
364				}
365
366				sname = p;
367				comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
368				cmnt = comment_offset?(rdata+comment_offset):"";
369
370				if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
371					TALLOC_FREE(frame);
372					continue;
373				}
374
375				/* Work out the comment length. */
376				for (p1 = cmnt, len = 0; *p1 &&
377						p1 < rdata_end; len++)
378					p1++;
379				if (!*p1) {
380					len++;
381				}
382
383				entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
384
385				pull_string_talloc(frame,rdata,0,
386					&s1,sname,16,STR_ASCII);
387				pull_string_talloc(frame,rdata,0,
388					&s2,cmnt,len,STR_ASCII);
389
390				if (!s1 || !s2) {
391					TALLOC_FREE(frame);
392					continue;
393				}
394
395				fn(s1, entry_stype, s2, state);
396				TALLOC_FREE(frame);
397			}
398
399			/* We are done with the old last entry, so now we can free it */
400			if (last_entry) {
401			        SAFE_FREE(last_entry); /* This will set it to null */
402			}
403
404			/* We always make a copy of  the last entry if we have one */
405			if (sname) {
406			        last_entry = smb_xstrdup(sname);
407			}
408
409			/* If we have more data, but no last entry then error out */
410			if (!last_entry && (res == ERRmoredata)) {
411			        errno = EINVAL;
412			        res = 0;
413			}
414
415		}
416
417		SAFE_FREE(rparam);
418		SAFE_FREE(rdata);
419	} while ((res == ERRmoredata) && (total_cnt > return_cnt));
420
421	SAFE_FREE(rparam);
422	SAFE_FREE(rdata);
423	SAFE_FREE(last_entry);
424
425	if (res == -1) {
426		errno = cli_errno(cli);
427	} else {
428		if (!return_cnt) {
429			/* this is a very special case, when the domain master for the
430			   work group isn't part of the work group itself, there is something
431			   wild going on */
432			errno = ENOENT;
433		}
434	    }
435
436	return(return_cnt > 0);
437}
438
439/****************************************************************************
440 Send a SamOEMChangePassword command.
441****************************************************************************/
442
443bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
444                             const char *old_password)
445{
446	char param[1024];
447	unsigned char data[532];
448	char *p = param;
449	unsigned char old_pw_hash[16];
450	unsigned char new_pw_hash[16];
451	unsigned int data_len;
452	unsigned int param_len = 0;
453	char *rparam = NULL;
454	char *rdata = NULL;
455	unsigned int rprcnt, rdrcnt;
456
457	if (strlen(user) >= sizeof(fstring)-1) {
458		DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
459		return False;
460	}
461
462	SSVAL(p,0,214); /* SamOEMChangePassword command. */
463	p += 2;
464	strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
465	p = skip_string(param,sizeof(param),p);
466	strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
467	p = skip_string(param,sizeof(param),p);
468	strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
469	p = skip_string(param,sizeof(param),p);
470	SSVAL(p,0,532);
471	p += 2;
472
473	param_len = PTR_DIFF(p,param);
474
475	/*
476	 * Get the Lanman hash of the old password, we
477	 * use this as the key to make_oem_passwd_hash().
478	 */
479	E_deshash(old_password, old_pw_hash);
480
481	encode_pw_buffer(data, new_password, STR_ASCII);
482
483#ifdef DEBUG_PASSWORD
484	DEBUG(100,("make_oem_passwd_hash\n"));
485	dump_data(100, data, 516);
486#endif
487	arcfour_crypt( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
488
489	/*
490	 * Now place the old password hash in the data.
491	 */
492	E_deshash(new_password, new_pw_hash);
493
494	E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
495
496	data_len = 532;
497
498	if (cli_send_trans(cli,SMBtrans,
499                    PIPE_LANMAN,                          /* name */
500                    0,0,                                  /* fid, flags */
501                    NULL,0,0,                             /* setup, length, max */
502                    param,param_len,2,                    /* param, length, max */
503                    (char *)data,data_len,0                       /* data, length, max */
504                   ) == False) {
505		DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
506			user ));
507		return False;
508	}
509
510	if (!cli_receive_trans(cli,SMBtrans,
511                       &rparam, &rprcnt,
512                       &rdata, &rdrcnt)) {
513		DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
514			user ));
515		return False;
516	}
517
518	if (rparam) {
519		cli->rap_error = SVAL(rparam,0);
520	}
521
522	SAFE_FREE(rparam);
523	SAFE_FREE(rdata);
524
525	return (cli->rap_error == 0);
526}
527
528/****************************************************************************
529 Send a qpathinfo call.
530****************************************************************************/
531
532bool cli_qpathinfo(struct cli_state *cli,
533			const char *fname,
534			time_t *change_time,
535			time_t *access_time,
536			time_t *write_time,
537			SMB_OFF_T *size,
538			uint16 *mode)
539{
540	unsigned int data_len = 0;
541	unsigned int param_len = 0;
542	unsigned int rparam_len, rdata_len;
543	uint16 setup = TRANSACT2_QPATHINFO;
544	char *param;
545	char *rparam=NULL, *rdata=NULL;
546	int count=8;
547	bool ret;
548	time_t (*date_fn)(struct cli_state *, const void *);
549	char *p;
550	size_t nlen = 2*(strlen(fname)+1);
551
552	param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
553	if (!param) {
554		return false;
555	}
556	p = param;
557	memset(p, '\0', 6);
558	SSVAL(p, 0, SMB_INFO_STANDARD);
559	p += 6;
560	p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
561	param_len = PTR_DIFF(p, param);
562
563	do {
564		ret = (cli_send_trans(cli, SMBtrans2,
565				      NULL,           /* Name */
566				      -1, 0,          /* fid, flags */
567				      &setup, 1, 0,   /* setup, length, max */
568				      param, param_len, 10, /* param, length, max */
569				      NULL, data_len, cli->max_xmit /* data, length, max */
570				      ) &&
571		       cli_receive_trans(cli, SMBtrans2,
572					 &rparam, &rparam_len,
573					 &rdata, &rdata_len));
574		if (!cli_is_dos_error(cli)) break;
575		if (!ret) {
576			/* we need to work around a Win95 bug - sometimes
577			   it gives ERRSRV/ERRerror temprarily */
578			uint8 eclass;
579			uint32 ecode;
580			cli_dos_error(cli, &eclass, &ecode);
581			if (eclass != ERRSRV || ecode != ERRerror) break;
582			smb_msleep(100);
583		}
584	} while (count-- && ret==False);
585
586	SAFE_FREE(param);
587	if (!ret || !rdata || rdata_len < 22) {
588		return False;
589	}
590
591	if (cli->win95) {
592		date_fn = cli_make_unix_date;
593	} else {
594		date_fn = cli_make_unix_date2;
595	}
596
597	if (change_time) {
598		*change_time = date_fn(cli, rdata+0);
599	}
600	if (access_time) {
601		*access_time = date_fn(cli, rdata+4);
602	}
603	if (write_time) {
604		*write_time = date_fn(cli, rdata+8);
605	}
606	if (size) {
607		*size = IVAL(rdata, 12);
608	}
609	if (mode) {
610		*mode = SVAL(rdata,l1_attrFile);
611	}
612
613	SAFE_FREE(rdata);
614	SAFE_FREE(rparam);
615	return True;
616}
617
618/****************************************************************************
619 Send a setpathinfo call.
620****************************************************************************/
621
622bool cli_setpathinfo(struct cli_state *cli, const char *fname,
623                     time_t create_time,
624                     time_t access_time,
625                     time_t write_time,
626                     time_t change_time,
627                     uint16 mode)
628{
629	unsigned int data_len = 0;
630	unsigned int param_len = 0;
631	unsigned int rparam_len, rdata_len;
632	uint16 setup = TRANSACT2_SETPATHINFO;
633	char *param;
634	char data[40];
635	char *rparam=NULL, *rdata=NULL;
636	int count=8;
637	bool ret;
638	char *p;
639	size_t nlen = 2*(strlen(fname)+1);
640
641	param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
642	if (!param) {
643		return false;
644	}
645	memset(param, '\0', 6);
646	memset(data, 0, sizeof(data));
647
648        p = param;
649
650        /* Add the information level */
651	SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
652
653        /* Skip reserved */
654	p += 6;
655
656        /* Add the file name */
657	p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
658
659	param_len = PTR_DIFF(p, param);
660
661        p = data;
662
663        /*
664         * Add the create, last access, modification, and status change times
665         */
666        put_long_date(p, create_time);
667        p += 8;
668
669        put_long_date(p, access_time);
670        p += 8;
671
672        put_long_date(p, write_time);
673        p += 8;
674
675        put_long_date(p, change_time);
676        p += 8;
677
678        /* Add attributes */
679        SIVAL(p, 0, mode);
680        p += 4;
681
682        /* Add padding */
683        SIVAL(p, 0, 0);
684        p += 4;
685
686        data_len = PTR_DIFF(p, data);
687
688	do {
689		ret = (cli_send_trans(cli, SMBtrans2,
690				      NULL,           /* Name */
691				      -1, 0,          /* fid, flags */
692				      &setup, 1, 0,   /* setup, length, max */
693				      param, param_len, 10, /* param, length, max */
694				      data, data_len, cli->max_xmit /* data, length, max */
695				      ) &&
696		       cli_receive_trans(cli, SMBtrans2,
697					 &rparam, &rparam_len,
698					 &rdata, &rdata_len));
699		if (!cli_is_dos_error(cli)) break;
700		if (!ret) {
701			/* we need to work around a Win95 bug - sometimes
702			   it gives ERRSRV/ERRerror temprarily */
703			uint8 eclass;
704			uint32 ecode;
705			cli_dos_error(cli, &eclass, &ecode);
706			if (eclass != ERRSRV || ecode != ERRerror) break;
707			smb_msleep(100);
708		}
709	} while (count-- && ret==False);
710
711	SAFE_FREE(param);
712	if (!ret) {
713		return False;
714	}
715
716	SAFE_FREE(rdata);
717	SAFE_FREE(rparam);
718	return True;
719}
720
721/****************************************************************************
722 Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
723****************************************************************************/
724
725bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
726		    struct timespec *create_time,
727                    struct timespec *access_time,
728                    struct timespec *write_time,
729		    struct timespec *change_time,
730                    SMB_OFF_T *size, uint16 *mode,
731		    SMB_INO_T *ino)
732{
733	unsigned int data_len = 0;
734	unsigned int param_len = 0;
735	uint16 setup = TRANSACT2_QPATHINFO;
736	char *param;
737	char *rparam=NULL, *rdata=NULL;
738	char *p;
739	size_t nlen = 2*(strlen(fname)+1);
740
741	param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
742	if (!param) {
743		return false;
744	}
745	p = param;
746	memset(param, '\0', 6);
747	SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
748	p += 6;
749	p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
750
751	param_len = PTR_DIFF(p, param);
752
753	if (!cli_send_trans(cli, SMBtrans2,
754                            NULL,                         /* name */
755                            -1, 0,                        /* fid, flags */
756                            &setup, 1, 0,                 /* setup, length, max */
757                            param, param_len, 10,         /* param, length, max */
758                            NULL, data_len, cli->max_xmit /* data, length, max */
759                           )) {
760		SAFE_FREE(param);
761		return False;
762	}
763
764	SAFE_FREE(param);
765	if (!cli_receive_trans(cli, SMBtrans2,
766                               &rparam, &param_len,
767                               &rdata, &data_len)) {
768		return False;
769	}
770
771	if (!rdata || data_len < 22) {
772		return False;
773	}
774
775	if (create_time) {
776                *create_time = interpret_long_date(rdata+0);
777	}
778	if (access_time) {
779		*access_time = interpret_long_date(rdata+8);
780	}
781	if (write_time) {
782		*write_time = interpret_long_date(rdata+16);
783	}
784	if (change_time) {
785		*change_time = interpret_long_date(rdata+24);
786	}
787	if (mode) {
788		*mode = SVAL(rdata, 32);
789	}
790	if (size) {
791                *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
792	}
793	if (ino) {
794		*ino = IVAL(rdata, 64);
795	}
796
797	SAFE_FREE(rdata);
798	SAFE_FREE(rparam);
799	return True;
800}
801
802/****************************************************************************
803 Get the stream info
804****************************************************************************/
805
806bool cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
807			   TALLOC_CTX *mem_ctx,
808			   unsigned int *pnum_streams,
809			   struct stream_struct **pstreams)
810{
811	unsigned int data_len = 0;
812	unsigned int param_len = 0;
813	uint16 setup = TRANSACT2_QPATHINFO;
814	char *param;
815	char *rparam=NULL, *rdata=NULL;
816	char *p;
817	unsigned int num_streams;
818	struct stream_struct *streams;
819	unsigned int ofs;
820	size_t namelen = 2*(strlen(fname)+1);
821
822	param = SMB_MALLOC_ARRAY(char, 6+namelen+2);
823	if (param == NULL) {
824		return false;
825	}
826	p = param;
827	memset(p, 0, 6);
828	SSVAL(p, 0, SMB_FILE_STREAM_INFORMATION);
829	p += 6;
830	p += clistr_push(cli, p, fname, namelen, STR_TERMINATE);
831
832	param_len = PTR_DIFF(p, param);
833
834	if (!cli_send_trans(cli, SMBtrans2,
835                            NULL,                     /* name */
836                            -1, 0,                    /* fid, flags */
837                            &setup, 1, 0,             /* setup, len, max */
838                            param, param_len, 10,     /* param, len, max */
839                            NULL, data_len, cli->max_xmit /* data, len, max */
840                           )) {
841		return false;
842	}
843
844	if (!cli_receive_trans(cli, SMBtrans2,
845                               &rparam, &param_len,
846                               &rdata, &data_len)) {
847		return false;
848	}
849
850	if (!rdata) {
851		SAFE_FREE(rparam);
852		return false;
853	}
854
855	num_streams = 0;
856	streams = NULL;
857	ofs = 0;
858
859	while ((data_len > ofs) && (data_len - ofs >= 24)) {
860		uint32_t nlen, len;
861		size_t size;
862		void *vstr;
863		struct stream_struct *tmp;
864		uint8_t *tmp_buf;
865
866		tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams,
867					   struct stream_struct,
868					   num_streams+1);
869
870		if (tmp == NULL) {
871			goto fail;
872		}
873		streams = tmp;
874
875		nlen                      = IVAL(rdata, ofs + 0x04);
876
877		streams[num_streams].size = IVAL_TO_SMB_OFF_T(
878			rdata, ofs + 0x08);
879		streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
880			rdata, ofs + 0x10);
881
882		if (nlen > data_len - (ofs + 24)) {
883			goto fail;
884		}
885
886		/*
887		 * We need to null-terminate src, how do I do this with
888		 * convert_string_talloc??
889		 */
890
891		tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2);
892		if (tmp_buf == NULL) {
893			goto fail;
894		}
895
896		memcpy(tmp_buf, rdata+ofs+24, nlen);
897		tmp_buf[nlen] = 0;
898		tmp_buf[nlen+1] = 0;
899
900		if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
901					   nlen+2, &vstr, &size, false))
902		{
903			TALLOC_FREE(tmp_buf);
904			goto fail;
905		}
906
907		TALLOC_FREE(tmp_buf);
908		streams[num_streams].name = (char *)vstr;
909		num_streams++;
910
911		len = IVAL(rdata, ofs);
912		if (len > data_len - ofs) {
913			goto fail;
914		}
915		if (len == 0) break;
916		ofs += len;
917	}
918
919	SAFE_FREE(rdata);
920	SAFE_FREE(rparam);
921
922	*pnum_streams = num_streams;
923	*pstreams = streams;
924	return true;
925
926 fail:
927	TALLOC_FREE(streams);
928	SAFE_FREE(rdata);
929	SAFE_FREE(rparam);
930	return false;
931}
932
933/****************************************************************************
934 Send a qfileinfo QUERY_FILE_NAME_INFO call.
935****************************************************************************/
936
937bool cli_qfilename(struct cli_state *cli, uint16_t fnum, char *name, size_t namelen)
938{
939	unsigned int data_len = 0;
940	unsigned int param_len = 0;
941	uint16 setup = TRANSACT2_QFILEINFO;
942	char param[4];
943	char *rparam=NULL, *rdata=NULL;
944
945	param_len = 4;
946	SSVAL(param, 0, fnum);
947	SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
948
949	if (!cli_send_trans(cli, SMBtrans2,
950                            NULL,                         /* name */
951                            -1, 0,                        /* fid, flags */
952                            &setup, 1, 0,                 /* setup, length, max */
953                            param, param_len, 2,          /* param, length, max */
954                            NULL, data_len, cli->max_xmit /* data, length, max */
955                           )) {
956		return False;
957	}
958
959	if (!cli_receive_trans(cli, SMBtrans2,
960                               &rparam, &param_len,
961                               &rdata, &data_len)) {
962		return False;
963	}
964
965	if (!rdata || data_len < 4) {
966		SAFE_FREE(rparam);
967		SAFE_FREE(rdata);
968		return False;
969	}
970
971	clistr_pull(cli->inbuf, name, rdata+4, namelen, IVAL(rdata, 0),
972		    STR_UNICODE);
973
974	SAFE_FREE(rparam);
975	SAFE_FREE(rdata);
976
977	return True;
978}
979
980/****************************************************************************
981 Send a qfileinfo call.
982****************************************************************************/
983
984bool cli_qfileinfo(struct cli_state *cli, uint16_t fnum,
985		   uint16 *mode, SMB_OFF_T *size,
986		   struct timespec *create_time,
987                   struct timespec *access_time,
988                   struct timespec *write_time,
989		   struct timespec *change_time,
990                   SMB_INO_T *ino)
991{
992	unsigned int data_len = 0;
993	unsigned int param_len = 0;
994	uint16 setup;
995	uint8_t param[4];
996	uint8_t *rparam=NULL, *rdata=NULL;
997	NTSTATUS status;
998
999	/* if its a win95 server then fail this - win95 totally screws it
1000	   up */
1001	if (cli->win95) return False;
1002
1003	param_len = 4;
1004
1005	SSVAL(param, 0, fnum);
1006	SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
1007
1008	SSVAL(&setup, 0, TRANSACT2_QFILEINFO);
1009
1010	status = cli_trans(talloc_tos(), cli, SMBtrans2,
1011			   NULL, -1, 0, 0, /* name, fid, function, flags */
1012			   &setup, 1, 0,          /* setup, length, max */
1013			   param, param_len, 2,   /* param, length, max */
1014			   NULL, 0, MIN(cli->max_xmit, 0xffff), /* data, length, max */
1015			   NULL, NULL, /* rsetup, length */
1016			   &rparam, &param_len,	/* rparam, length */
1017			   &rdata, &data_len);
1018
1019	if (!NT_STATUS_IS_OK(status)) {
1020		return false;
1021	}
1022
1023	if (!rdata || data_len < 68) {
1024		return False;
1025	}
1026
1027	if (create_time) {
1028		*create_time = interpret_long_date((char *)rdata+0);
1029	}
1030	if (access_time) {
1031		*access_time = interpret_long_date((char *)rdata+8);
1032	}
1033	if (write_time) {
1034		*write_time = interpret_long_date((char *)rdata+16);
1035	}
1036	if (change_time) {
1037		*change_time = interpret_long_date((char *)rdata+24);
1038	}
1039	if (mode) {
1040		*mode = SVAL(rdata, 32);
1041	}
1042	if (size) {
1043                *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
1044	}
1045	if (ino) {
1046		*ino = IVAL(rdata, 64);
1047	}
1048
1049	TALLOC_FREE(rdata);
1050	TALLOC_FREE(rparam);
1051	return True;
1052}
1053
1054/****************************************************************************
1055 Send a qpathinfo BASIC_INFO call.
1056****************************************************************************/
1057
1058bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
1059                          SMB_STRUCT_STAT *sbuf, uint32 *attributes )
1060{
1061	unsigned int param_len = 0;
1062	unsigned int data_len = 0;
1063	uint16 setup = TRANSACT2_QPATHINFO;
1064	char *param;
1065	char *rparam=NULL, *rdata=NULL;
1066	char *p;
1067	char *path;
1068	int len;
1069	size_t nlen;
1070	TALLOC_CTX *frame = talloc_stackframe();
1071
1072	path = talloc_strdup(frame, name);
1073	if (!path) {
1074		TALLOC_FREE(frame);
1075		return false;
1076	}
1077	/* cleanup */
1078
1079	len = strlen(path);
1080	if ( path[len-1] == '\\' || path[len-1] == '/') {
1081		path[len-1] = '\0';
1082	}
1083	nlen = 2*(strlen(path)+1);
1084
1085	param = TALLOC_ARRAY(frame,char,6+nlen+2);
1086	if (!param) {
1087		return false;
1088	}
1089	p = param;
1090	memset(param, '\0', 6);
1091
1092	SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
1093	p += 6;
1094	p += clistr_push(cli, p, path, nlen, STR_TERMINATE);
1095	param_len = PTR_DIFF(p, param);
1096
1097
1098	if (!cli_send_trans(cli, SMBtrans2,
1099			NULL,                        /* name */
1100			-1, 0,                       /* fid, flags */
1101			&setup, 1, 0,                /* setup, length, max */
1102			param, param_len, 2,         /* param, length, max */
1103			NULL,  0, cli->max_xmit      /* data, length, max */
1104			)) {
1105		TALLOC_FREE(frame);
1106		return False;
1107	}
1108
1109	TALLOC_FREE(frame);
1110
1111	if (!cli_receive_trans(cli, SMBtrans2,
1112		&rparam, &param_len,
1113		&rdata, &data_len)) {
1114			return False;
1115	}
1116
1117	if (data_len < 36) {
1118		SAFE_FREE(rdata);
1119		SAFE_FREE(rparam);
1120		return False;
1121	}
1122
1123	sbuf->st_ex_atime = interpret_long_date( rdata+8 ); /* Access time. */
1124	sbuf->st_ex_mtime = interpret_long_date( rdata+16 ); /* Write time. */
1125	sbuf->st_ex_ctime = interpret_long_date( rdata+24 ); /* Change time. */
1126
1127	*attributes = IVAL( rdata, 32 );
1128
1129	SAFE_FREE(rparam);
1130	SAFE_FREE(rdata);
1131
1132	return True;
1133}
1134
1135/****************************************************************************
1136 Send a qfileinfo call.
1137****************************************************************************/
1138
1139bool cli_qfileinfo_test(struct cli_state *cli, uint16_t fnum, int level, char **poutdata, uint32 *poutlen)
1140{
1141	unsigned int data_len = 0;
1142	unsigned int param_len = 0;
1143	uint16 setup = TRANSACT2_QFILEINFO;
1144	char param[4];
1145	char *rparam=NULL, *rdata=NULL;
1146
1147	*poutdata = NULL;
1148	*poutlen = 0;
1149
1150	/* if its a win95 server then fail this - win95 totally screws it
1151	   up */
1152	if (cli->win95)
1153		return False;
1154
1155	param_len = 4;
1156
1157	SSVAL(param, 0, fnum);
1158	SSVAL(param, 2, level);
1159
1160	if (!cli_send_trans(cli, SMBtrans2,
1161                            NULL,                           /* name */
1162                            -1, 0,                          /* fid, flags */
1163                            &setup, 1, 0,                   /* setup, length, max */
1164                            param, param_len, 2,            /* param, length, max */
1165                            NULL, data_len, cli->max_xmit   /* data, length, max */
1166                           )) {
1167		return False;
1168	}
1169
1170	if (!cli_receive_trans(cli, SMBtrans2,
1171                               &rparam, &param_len,
1172                               &rdata, &data_len)) {
1173		return False;
1174	}
1175
1176	*poutdata = (char *)memdup(rdata, data_len);
1177	if (!*poutdata) {
1178		SAFE_FREE(rdata);
1179		SAFE_FREE(rparam);
1180		return False;
1181	}
1182
1183	*poutlen = data_len;
1184
1185	SAFE_FREE(rdata);
1186	SAFE_FREE(rparam);
1187	return True;
1188}
1189
1190/****************************************************************************
1191 Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1192****************************************************************************/
1193
1194NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1195{
1196	unsigned int data_len = 0;
1197	unsigned int param_len = 0;
1198	uint16 setup = TRANSACT2_QPATHINFO;
1199	char *param;
1200	char *rparam=NULL, *rdata=NULL;
1201	int count=8;
1202	char *p;
1203	bool ret;
1204	unsigned int len;
1205	size_t nlen = 2*(strlen(fname)+1);
1206
1207	param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
1208	if (!param) {
1209		return NT_STATUS_NO_MEMORY;
1210	}
1211	p = param;
1212	memset(param, '\0', 6);
1213	SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
1214	p += 6;
1215	p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
1216	param_len = PTR_DIFF(p, param);
1217
1218	do {
1219		ret = (cli_send_trans(cli, SMBtrans2,
1220				      NULL,           /* Name */
1221				      -1, 0,          /* fid, flags */
1222				      &setup, 1, 0,   /* setup, length, max */
1223				      param, param_len, 10, /* param, length, max */
1224				      NULL, data_len, cli->max_xmit /* data, length, max */
1225				      ) &&
1226		       cli_receive_trans(cli, SMBtrans2,
1227					 &rparam, &param_len,
1228					 &rdata, &data_len));
1229		if (!ret && cli_is_dos_error(cli)) {
1230			/* we need to work around a Win95 bug - sometimes
1231			   it gives ERRSRV/ERRerror temprarily */
1232			uint8 eclass;
1233			uint32 ecode;
1234			cli_dos_error(cli, &eclass, &ecode);
1235			if (eclass != ERRSRV || ecode != ERRerror) break;
1236			smb_msleep(100);
1237		}
1238	} while (count-- && ret==False);
1239
1240	SAFE_FREE(param);
1241
1242	if (!ret || !rdata || data_len < 4) {
1243		return NT_STATUS_UNSUCCESSFUL;
1244	}
1245
1246	len = IVAL(rdata, 0);
1247
1248	if (len > data_len - 4) {
1249		return NT_STATUS_INVALID_NETWORK_RESPONSE;
1250	}
1251
1252	clistr_pull(cli->inbuf, alt_name, rdata+4, sizeof(fstring), len,
1253		    STR_UNICODE);
1254
1255	SAFE_FREE(rdata);
1256	SAFE_FREE(rparam);
1257
1258	return NT_STATUS_OK;
1259}
1260