1/*
2   Unix SMB/CIFS implementation.
3   client file operations
4   Copyright (C) Andrew Tridgell 1994-1998
5   Copyright (C) Jeremy Allison 2001-2002
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#define NO_SYSLOG
23
24#include "includes.h"
25
26/****************************************************************************
27 Hard/Symlink a file (UNIX extensions).
28 Creates new name (sym)linked to oldname.
29****************************************************************************/
30
31static BOOL cli_link_internal(struct cli_state *cli, const char *oldname, const char *newname, BOOL hard_link)
32{
33	unsigned int data_len = 0;
34	unsigned int param_len = 0;
35	uint16 setup = TRANSACT2_SETPATHINFO;
36	char param[sizeof(pstring)+6];
37	pstring data;
38	char *rparam=NULL, *rdata=NULL;
39	char *p;
40	size_t oldlen = 2*(strlen(oldname)+1);
41	size_t newlen = 2*(strlen(newname)+1);
42
43	memset(param, 0, sizeof(param));
44	SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK);
45	p = &param[6];
46
47	p += clistr_push(cli, p, newname, MIN(newlen, sizeof(param)-6), STR_TERMINATE);
48	param_len = PTR_DIFF(p, param);
49
50	p = data;
51	p += clistr_push(cli, p, oldname, MIN(oldlen,sizeof(data)), STR_TERMINATE);
52	data_len = PTR_DIFF(p, data);
53
54	if (!cli_send_trans(cli, SMBtrans2,
55		NULL,                        /* name */
56		-1, 0,                          /* fid, flags */
57		&setup, 1, 0,                   /* setup, length, max */
58		param, param_len, 2,            /* param, length, max */
59		(char *)&data,  data_len, cli->max_xmit /* data, length, max */
60		)) {
61			return False;
62	}
63
64	if (!cli_receive_trans(cli, SMBtrans2,
65		&rparam, &param_len,
66		&rdata, &data_len)) {
67			return False;
68	}
69
70	SAFE_FREE(rdata);
71	SAFE_FREE(rparam);
72
73	return True;
74}
75
76/****************************************************************************
77 Map standard UNIX permissions onto wire representations.
78****************************************************************************/
79
80uint32 unix_perms_to_wire(mode_t perms)
81{
82        unsigned int ret = 0;
83
84        ret |= ((perms & S_IXOTH) ?  UNIX_X_OTH : 0);
85        ret |= ((perms & S_IWOTH) ?  UNIX_W_OTH : 0);
86        ret |= ((perms & S_IROTH) ?  UNIX_R_OTH : 0);
87        ret |= ((perms & S_IXGRP) ?  UNIX_X_GRP : 0);
88        ret |= ((perms & S_IWGRP) ?  UNIX_W_GRP : 0);
89        ret |= ((perms & S_IRGRP) ?  UNIX_R_GRP : 0);
90        ret |= ((perms & S_IXUSR) ?  UNIX_X_USR : 0);
91        ret |= ((perms & S_IWUSR) ?  UNIX_W_USR : 0);
92        ret |= ((perms & S_IRUSR) ?  UNIX_R_USR : 0);
93#ifdef S_ISVTX
94        ret |= ((perms & S_ISVTX) ?  UNIX_STICKY : 0);
95#endif
96#ifdef S_ISGID
97        ret |= ((perms & S_ISGID) ?  UNIX_SET_GID : 0);
98#endif
99#ifdef S_ISUID
100        ret |= ((perms & S_ISUID) ?  UNIX_SET_UID : 0);
101#endif
102        return ret;
103}
104
105/****************************************************************************
106 Map wire permissions to standard UNIX.
107****************************************************************************/
108
109mode_t wire_perms_to_unix(uint32 perms)
110{
111        mode_t ret = (mode_t)0;
112
113        ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
114        ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
115        ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
116        ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
117        ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
118        ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
119        ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
120        ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
121        ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
122#ifdef S_ISVTX
123        ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
124#endif
125#ifdef S_ISGID
126        ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
127#endif
128#ifdef S_ISUID
129        ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
130#endif
131        return ret;
132}
133
134/****************************************************************************
135 Return the file type from the wire filetype for UNIX extensions.
136****************************************************************************/
137
138static mode_t unix_filetype_from_wire(uint32 wire_type)
139{
140	switch (wire_type) {
141		case UNIX_TYPE_FILE:
142			return S_IFREG;
143		case UNIX_TYPE_DIR:
144			return S_IFDIR;
145#ifdef S_IFLNK
146		case UNIX_TYPE_SYMLINK:
147			return S_IFLNK;
148#endif
149#ifdef S_IFCHR
150		case UNIX_TYPE_CHARDEV:
151			return S_IFCHR;
152#endif
153#ifdef S_IFBLK
154		case UNIX_TYPE_BLKDEV:
155			return S_IFBLK;
156#endif
157#ifdef S_IFIFO
158		case UNIX_TYPE_FIFO:
159			return S_IFIFO;
160#endif
161#ifdef S_IFSOCK
162		case UNIX_TYPE_SOCKET:
163			return S_IFSOCK;
164#endif
165		default:
166			return (mode_t)0;
167	}
168}
169
170/****************************************************************************
171 Do a POSIX getfacl (UNIX extensions).
172****************************************************************************/
173
174BOOL cli_unix_getfacl(struct cli_state *cli, const char *name, size_t *prb_size, char **retbuf)
175{
176	unsigned int param_len = 0;
177	unsigned int data_len = 0;
178	uint16 setup = TRANSACT2_QPATHINFO;
179	char param[sizeof(pstring)+6];
180	char *rparam=NULL, *rdata=NULL;
181	char *p;
182
183	p = param;
184	memset(p, 0, 6);
185	SSVAL(p, 0, SMB_QUERY_POSIX_ACL);
186	p += 6;
187	p += clistr_push(cli, p, name, sizeof(pstring)-6, STR_TERMINATE);
188	param_len = PTR_DIFF(p, param);
189
190	if (!cli_send_trans(cli, SMBtrans2,
191		NULL,                        /* name */
192		-1, 0,                       /* fid, flags */
193		&setup, 1, 0,                /* setup, length, max */
194		param, param_len, 2,         /* param, length, max */
195		NULL,  0, cli->max_xmit      /* data, length, max */
196		)) {
197			return False;
198	}
199
200	if (!cli_receive_trans(cli, SMBtrans2,
201		&rparam, &param_len,
202		&rdata, &data_len)) {
203			return False;
204	}
205
206	if (data_len < 6) {
207		SAFE_FREE(rdata);
208		SAFE_FREE(rparam);
209		return False;
210	}
211
212	SAFE_FREE(rparam);
213	*retbuf = rdata;
214	*prb_size = (size_t)data_len;
215
216	return True;
217}
218
219/****************************************************************************
220 Stat a file (UNIX extensions).
221****************************************************************************/
222
223BOOL cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf)
224{
225	unsigned int param_len = 0;
226	unsigned int data_len = 0;
227	uint16 setup = TRANSACT2_QPATHINFO;
228	char param[sizeof(pstring)+6];
229	char *rparam=NULL, *rdata=NULL;
230	char *p;
231
232	ZERO_STRUCTP(sbuf);
233
234	p = param;
235	memset(p, 0, 6);
236	SSVAL(p, 0, SMB_QUERY_FILE_UNIX_BASIC);
237	p += 6;
238	p += clistr_push(cli, p, name, sizeof(pstring)-6, STR_TERMINATE);
239	param_len = PTR_DIFF(p, param);
240
241	if (!cli_send_trans(cli, SMBtrans2,
242		NULL,                        /* name */
243		-1, 0,                       /* fid, flags */
244		&setup, 1, 0,                /* setup, length, max */
245		param, param_len, 2,         /* param, length, max */
246		NULL,  0, cli->max_xmit      /* data, length, max */
247		)) {
248			return False;
249	}
250
251	if (!cli_receive_trans(cli, SMBtrans2,
252		&rparam, &param_len,
253		&rdata, &data_len)) {
254			return False;
255	}
256
257	if (data_len < 96) {
258		SAFE_FREE(rdata);
259		SAFE_FREE(rparam);
260		return False;
261	}
262
263	sbuf->st_size = IVAL2_TO_SMB_BIG_UINT(rdata,0);     /* total size, in bytes */
264	sbuf->st_blocks = IVAL2_TO_SMB_BIG_UINT(rdata,8);   /* number of blocks allocated */
265	sbuf->st_blocks /= STAT_ST_BLOCKSIZE;
266	sbuf->st_ctime = interpret_long_date(rdata + 16);    /* time of last change */
267	sbuf->st_atime = interpret_long_date(rdata + 24);    /* time of last access */
268	sbuf->st_mtime = interpret_long_date(rdata + 32);    /* time of last modification */
269	sbuf->st_uid = IVAL(rdata,40);      /* user ID of owner */
270	sbuf->st_gid = IVAL(rdata,48);      /* group ID of owner */
271	sbuf->st_mode |= unix_filetype_from_wire(IVAL(rdata, 56));
272#if defined(HAVE_MAKEDEV)
273	{
274		uint32 dev_major = IVAL(rdata,60);
275		uint32 dev_minor = IVAL(rdata,68);
276		sbuf->st_rdev = makedev(dev_major, dev_minor);
277	}
278#endif
279	sbuf->st_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(rdata,76);      /* inode */
280	sbuf->st_mode |= wire_perms_to_unix(IVAL(rdata,84));     /* protection */
281	sbuf->st_nlink = IVAL(rdata,92);    /* number of hard links */
282
283	SAFE_FREE(rdata);
284	SAFE_FREE(rparam);
285
286	return True;
287}
288
289/****************************************************************************
290 Symlink a file (UNIX extensions).
291****************************************************************************/
292
293BOOL cli_unix_symlink(struct cli_state *cli, const char *oldname, const char *newname)
294{
295	return cli_link_internal(cli, oldname, newname, False);
296}
297
298/****************************************************************************
299 Hard a file (UNIX extensions).
300****************************************************************************/
301
302BOOL cli_unix_hardlink(struct cli_state *cli, const char *oldname, const char *newname)
303{
304	return cli_link_internal(cli, oldname, newname, True);
305}
306
307/****************************************************************************
308 Chmod or chown a file internal (UNIX extensions).
309****************************************************************************/
310
311static BOOL cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32 mode, uint32 uid, uint32 gid)
312{
313	unsigned int data_len = 0;
314	unsigned int param_len = 0;
315	uint16 setup = TRANSACT2_SETPATHINFO;
316	char param[sizeof(pstring)+6];
317	char data[100];
318	char *rparam=NULL, *rdata=NULL;
319	char *p;
320
321	memset(param, 0, sizeof(param));
322	memset(data, 0, sizeof(data));
323	SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC);
324	p = &param[6];
325
326	p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
327	param_len = PTR_DIFF(p, param);
328
329	SIVAL(data,40,uid);
330	SIVAL(data,48,gid);
331	SIVAL(data,84,mode);
332
333	data_len = 100;
334
335	if (!cli_send_trans(cli, SMBtrans2,
336		NULL,                        /* name */
337		-1, 0,                          /* fid, flags */
338		&setup, 1, 0,                   /* setup, length, max */
339		param, param_len, 2,            /* param, length, max */
340		(char *)&data,  data_len, cli->max_xmit /* data, length, max */
341		)) {
342			return False;
343	}
344
345	if (!cli_receive_trans(cli, SMBtrans2,
346		&rparam, &param_len,
347		&rdata, &data_len)) {
348			return False;
349	}
350
351	SAFE_FREE(rdata);
352	SAFE_FREE(rparam);
353
354	return True;
355}
356
357/****************************************************************************
358 chmod a file (UNIX extensions).
359****************************************************************************/
360
361BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
362{
363	return cli_unix_chmod_chown_internal(cli, fname,
364		unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
365}
366
367/****************************************************************************
368 chown a file (UNIX extensions).
369****************************************************************************/
370
371BOOL cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
372{
373	return cli_unix_chmod_chown_internal(cli, fname, SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
374}
375
376/****************************************************************************
377 Rename a file.
378****************************************************************************/
379
380BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
381{
382	char *p;
383
384	memset(cli->outbuf,'\0',smb_size);
385	memset(cli->inbuf,'\0',smb_size);
386
387	set_message(cli->outbuf,1, 0, True);
388
389	SCVAL(cli->outbuf,smb_com,SMBmv);
390	SSVAL(cli->outbuf,smb_tid,cli->cnum);
391	cli_setup_packet(cli);
392
393	SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
394
395	p = smb_buf(cli->outbuf);
396	*p++ = 4;
397	p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
398	*p++ = 4;
399	p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
400
401	cli_setup_bcc(cli, p);
402
403	cli_send_smb(cli);
404	if (!cli_receive_smb(cli))
405		return False;
406
407	if (cli_is_error(cli))
408		return False;
409
410	return True;
411}
412
413/****************************************************************************
414 NT Rename a file.
415****************************************************************************/
416
417BOOL cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
418{
419	char *p;
420
421	memset(cli->outbuf,'\0',smb_size);
422	memset(cli->inbuf,'\0',smb_size);
423
424	set_message(cli->outbuf, 4, 0, True);
425
426	SCVAL(cli->outbuf,smb_com,SMBntrename);
427	SSVAL(cli->outbuf,smb_tid,cli->cnum);
428	cli_setup_packet(cli);
429
430	SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
431	SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_RENAME);
432
433	p = smb_buf(cli->outbuf);
434	*p++ = 4;
435	p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
436	*p++ = 4;
437	p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
438
439	cli_setup_bcc(cli, p);
440
441	cli_send_smb(cli);
442	if (!cli_receive_smb(cli))
443		return False;
444
445	if (cli_is_error(cli))
446		return False;
447
448	return True;
449}
450
451/****************************************************************************
452 NT hardlink a file.
453****************************************************************************/
454
455BOOL cli_nt_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
456{
457	char *p;
458
459	memset(cli->outbuf,'\0',smb_size);
460	memset(cli->inbuf,'\0',smb_size);
461
462	set_message(cli->outbuf, 4, 0, True);
463
464	SCVAL(cli->outbuf,smb_com,SMBntrename);
465	SSVAL(cli->outbuf,smb_tid,cli->cnum);
466	cli_setup_packet(cli);
467
468	SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
469	SSVAL(cli->outbuf,smb_vwv1, RENAME_FLAG_HARD_LINK);
470
471	p = smb_buf(cli->outbuf);
472	*p++ = 4;
473	p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE);
474	*p++ = 4;
475	p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE);
476
477	cli_setup_bcc(cli, p);
478
479	cli_send_smb(cli);
480	if (!cli_receive_smb(cli))
481		return False;
482
483	if (cli_is_error(cli))
484		return False;
485
486	return True;
487}
488
489/****************************************************************************
490 Delete a file.
491****************************************************************************/
492
493BOOL cli_unlink(struct cli_state *cli, const char *fname)
494{
495	char *p;
496
497	memset(cli->outbuf,'\0',smb_size);
498	memset(cli->inbuf,'\0',smb_size);
499
500	set_message(cli->outbuf,1, 0,True);
501
502	SCVAL(cli->outbuf,smb_com,SMBunlink);
503	SSVAL(cli->outbuf,smb_tid,cli->cnum);
504	cli_setup_packet(cli);
505
506	SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
507
508	p = smb_buf(cli->outbuf);
509	*p++ = 4;
510	p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
511
512	cli_setup_bcc(cli, p);
513	cli_send_smb(cli);
514	if (!cli_receive_smb(cli)) {
515		return False;
516	}
517
518	if (cli_is_error(cli)) {
519		return False;
520	}
521
522	return True;
523}
524
525/****************************************************************************
526 Create a directory.
527****************************************************************************/
528
529BOOL cli_mkdir(struct cli_state *cli, const char *dname)
530{
531	char *p;
532
533	memset(cli->outbuf,'\0',smb_size);
534	memset(cli->inbuf,'\0',smb_size);
535
536	set_message(cli->outbuf,0, 0,True);
537
538	SCVAL(cli->outbuf,smb_com,SMBmkdir);
539	SSVAL(cli->outbuf,smb_tid,cli->cnum);
540	cli_setup_packet(cli);
541
542	p = smb_buf(cli->outbuf);
543	*p++ = 4;
544	p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
545
546	cli_setup_bcc(cli, p);
547
548	cli_send_smb(cli);
549	if (!cli_receive_smb(cli)) {
550		return False;
551	}
552
553	if (cli_is_error(cli)) {
554		return False;
555	}
556
557	return True;
558}
559
560/****************************************************************************
561 Remove a directory.
562****************************************************************************/
563
564BOOL cli_rmdir(struct cli_state *cli, const char *dname)
565{
566	char *p;
567
568	memset(cli->outbuf,'\0',smb_size);
569	memset(cli->inbuf,'\0',smb_size);
570
571	set_message(cli->outbuf,0, 0, True);
572
573	SCVAL(cli->outbuf,smb_com,SMBrmdir);
574	SSVAL(cli->outbuf,smb_tid,cli->cnum);
575	cli_setup_packet(cli);
576
577	p = smb_buf(cli->outbuf);
578	*p++ = 4;
579	p += clistr_push(cli, p, dname, -1, STR_TERMINATE);
580
581	cli_setup_bcc(cli, p);
582
583	cli_send_smb(cli);
584	if (!cli_receive_smb(cli)) {
585		return False;
586	}
587
588	if (cli_is_error(cli)) {
589		return False;
590	}
591
592	return True;
593}
594
595/****************************************************************************
596 Set or clear the delete on close flag.
597****************************************************************************/
598
599int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
600{
601	unsigned int data_len = 1;
602	unsigned int param_len = 6;
603	uint16 setup = TRANSACT2_SETFILEINFO;
604	pstring param;
605	unsigned char data;
606	char *rparam=NULL, *rdata=NULL;
607
608	memset(param, 0, param_len);
609	SSVAL(param,0,fnum);
610	SSVAL(param,2,SMB_SET_FILE_DISPOSITION_INFO);
611
612	data = flag ? 1 : 0;
613
614	if (!cli_send_trans(cli, SMBtrans2,
615						NULL,                        /* name */
616						-1, 0,                          /* fid, flags */
617						&setup, 1, 0,                   /* setup, length, max */
618						param, param_len, 2,            /* param, length, max */
619						(char *)&data,  data_len, cli->max_xmit /* data, length, max */
620						)) {
621		return False;
622	}
623
624	if (!cli_receive_trans(cli, SMBtrans2,
625						&rparam, &param_len,
626						&rdata, &data_len)) {
627		return False;
628	}
629
630	SAFE_FREE(rdata);
631	SAFE_FREE(rparam);
632
633	return True;
634}
635
636/****************************************************************************
637 Open a file - exposing the full horror of the NT API :-).
638 Used in smbtorture.
639****************************************************************************/
640
641int cli_nt_create_full(struct cli_state *cli, const char *fname,
642		 uint32 CreatFlags, uint32 DesiredAccess,
643		 uint32 FileAttributes, uint32 ShareAccess,
644		 uint32 CreateDisposition, uint32 CreateOptions,
645		 uint8 SecuityFlags)
646{
647	char *p;
648	int len;
649
650	memset(cli->outbuf,'\0',smb_size);
651	memset(cli->inbuf,'\0',smb_size);
652
653	set_message(cli->outbuf,24,0,True);
654
655	SCVAL(cli->outbuf,smb_com,SMBntcreateX);
656	SSVAL(cli->outbuf,smb_tid,cli->cnum);
657	cli_setup_packet(cli);
658
659	SSVAL(cli->outbuf,smb_vwv0,0xFF);
660	if (cli->use_oplocks)
661		CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
662
663	SIVAL(cli->outbuf,smb_ntcreate_Flags, CreatFlags);
664	SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
665	SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, DesiredAccess);
666	SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, FileAttributes);
667	SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, ShareAccess);
668	SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, CreateDisposition);
669	SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, CreateOptions);
670	SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
671	SCVAL(cli->outbuf,smb_ntcreate_SecurityFlags, SecuityFlags);
672
673	p = smb_buf(cli->outbuf);
674	/* this alignment and termination is critical for netapp filers. Don't change */
675	p += clistr_align_out(cli, p, 0);
676	len = clistr_push(cli, p, fname, -1, 0);
677	p += len;
678	SSVAL(cli->outbuf,smb_ntcreate_NameLength, len);
679	/* sigh. this copes with broken netapp filer behaviour */
680	p += clistr_push(cli, p, "", -1, STR_TERMINATE);
681
682	cli_setup_bcc(cli, p);
683
684	cli_send_smb(cli);
685	if (!cli_receive_smb(cli)) {
686		return -1;
687	}
688
689	if (cli_is_error(cli)) {
690		return -1;
691	}
692
693	return SVAL(cli->inbuf,smb_vwv2 + 1);
694}
695
696/****************************************************************************
697 Open a file.
698****************************************************************************/
699
700int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess)
701{
702	return cli_nt_create_full(cli, fname, 0, DesiredAccess, 0,
703				FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_EXISTS_OPEN, 0x0, 0x0);
704}
705
706/****************************************************************************
707 Open a file
708 WARNING: if you open with O_WRONLY then getattrE won't work!
709****************************************************************************/
710
711int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
712{
713	char *p;
714	unsigned openfn=0;
715	unsigned accessmode=0;
716
717	if (flags & O_CREAT)
718		openfn |= (1<<4);
719	if (!(flags & O_EXCL)) {
720		if (flags & O_TRUNC)
721			openfn |= (1<<1);
722		else
723			openfn |= (1<<0);
724	}
725
726	accessmode = (share_mode<<4);
727
728	if ((flags & O_ACCMODE) == O_RDWR) {
729		accessmode |= 2;
730	} else if ((flags & O_ACCMODE) == O_WRONLY) {
731		accessmode |= 1;
732	}
733
734#if defined(O_SYNC)
735	if ((flags & O_SYNC) == O_SYNC) {
736		accessmode |= (1<<14);
737	}
738#endif /* O_SYNC */
739
740	if (share_mode == DENY_FCB) {
741		accessmode = 0xFF;
742	}
743
744	memset(cli->outbuf,'\0',smb_size);
745	memset(cli->inbuf,'\0',smb_size);
746
747	set_message(cli->outbuf,15,0,True);
748
749	SCVAL(cli->outbuf,smb_com,SMBopenX);
750	SSVAL(cli->outbuf,smb_tid,cli->cnum);
751	cli_setup_packet(cli);
752
753	SSVAL(cli->outbuf,smb_vwv0,0xFF);
754	SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
755	SSVAL(cli->outbuf,smb_vwv3,accessmode);
756	SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
757	SSVAL(cli->outbuf,smb_vwv5,0);
758	SSVAL(cli->outbuf,smb_vwv8,openfn);
759
760	if (cli->use_oplocks) {
761		/* if using oplocks then ask for a batch oplock via
762                   core and extended methods */
763		SCVAL(cli->outbuf,smb_flg, CVAL(cli->outbuf,smb_flg)|
764			FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK);
765		SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
766	}
767
768	p = smb_buf(cli->outbuf);
769	p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
770
771	cli_setup_bcc(cli, p);
772
773	cli_send_smb(cli);
774	if (!cli_receive_smb(cli)) {
775		return -1;
776	}
777
778	if (cli_is_error(cli)) {
779		return -1;
780	}
781
782	return SVAL(cli->inbuf,smb_vwv2);
783}
784
785/****************************************************************************
786 Close a file.
787****************************************************************************/
788
789BOOL cli_close(struct cli_state *cli, int fnum)
790{
791	memset(cli->outbuf,'\0',smb_size);
792	memset(cli->inbuf,'\0',smb_size);
793
794	set_message(cli->outbuf,3,0,True);
795
796	SCVAL(cli->outbuf,smb_com,SMBclose);
797	SSVAL(cli->outbuf,smb_tid,cli->cnum);
798	cli_setup_packet(cli);
799
800	SSVAL(cli->outbuf,smb_vwv0,fnum);
801	SIVALS(cli->outbuf,smb_vwv1,-1);
802
803	cli_send_smb(cli);
804	if (!cli_receive_smb(cli)) {
805		return False;
806	}
807
808	return !cli_is_error(cli);
809}
810
811
812/****************************************************************************
813 send a lock with a specified locktype
814 this is used for testing LOCKING_ANDX_CANCEL_LOCK
815****************************************************************************/
816NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
817		      uint32 offset, uint32 len, int timeout, unsigned char locktype)
818{
819	char *p;
820	int saved_timeout = cli->timeout;
821
822	memset(cli->outbuf,'\0',smb_size);
823	memset(cli->inbuf,'\0', smb_size);
824
825	set_message(cli->outbuf,8,0,True);
826
827	SCVAL(cli->outbuf,smb_com,SMBlockingX);
828	SSVAL(cli->outbuf,smb_tid,cli->cnum);
829	cli_setup_packet(cli);
830
831	SCVAL(cli->outbuf,smb_vwv0,0xFF);
832	SSVAL(cli->outbuf,smb_vwv2,fnum);
833	SCVAL(cli->outbuf,smb_vwv3,locktype);
834	SIVALS(cli->outbuf, smb_vwv4, timeout);
835	SSVAL(cli->outbuf,smb_vwv6,0);
836	SSVAL(cli->outbuf,smb_vwv7,1);
837
838	p = smb_buf(cli->outbuf);
839	SSVAL(p, 0, cli->pid);
840	SIVAL(p, 2, offset);
841	SIVAL(p, 6, len);
842
843	p += 10;
844
845	cli_setup_bcc(cli, p);
846
847	cli_send_smb(cli);
848
849	if (timeout != 0) {
850		cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
851	}
852
853	if (!cli_receive_smb(cli)) {
854		cli->timeout = saved_timeout;
855		return NT_STATUS_UNSUCCESSFUL;
856	}
857
858	cli->timeout = saved_timeout;
859
860	return cli_nt_error(cli);
861}
862
863
864/****************************************************************************
865 Lock a file.
866 note that timeout is in units of 2 milliseconds
867****************************************************************************/
868BOOL cli_lock(struct cli_state *cli, int fnum,
869	      uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
870{
871	char *p;
872	int saved_timeout = cli->timeout;
873
874	memset(cli->outbuf,'\0',smb_size);
875	memset(cli->inbuf,'\0', smb_size);
876
877	set_message(cli->outbuf,8,0,True);
878
879	SCVAL(cli->outbuf,smb_com,SMBlockingX);
880	SSVAL(cli->outbuf,smb_tid,cli->cnum);
881	cli_setup_packet(cli);
882
883	SCVAL(cli->outbuf,smb_vwv0,0xFF);
884	SSVAL(cli->outbuf,smb_vwv2,fnum);
885	SCVAL(cli->outbuf,smb_vwv3,(lock_type == READ_LOCK? 1 : 0));
886	SIVALS(cli->outbuf, smb_vwv4, timeout);
887	SSVAL(cli->outbuf,smb_vwv6,0);
888	SSVAL(cli->outbuf,smb_vwv7,1);
889
890	p = smb_buf(cli->outbuf);
891	SSVAL(p, 0, cli->pid);
892	SIVAL(p, 2, offset);
893	SIVAL(p, 6, len);
894
895	p += 10;
896
897	cli_setup_bcc(cli, p);
898
899	cli_send_smb(cli);
900
901	if (timeout != 0) {
902		cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout*2 + 5*1000);
903	}
904
905	if (!cli_receive_smb(cli)) {
906		cli->timeout = saved_timeout;
907		return False;
908	}
909
910	cli->timeout = saved_timeout;
911
912	if (cli_is_error(cli)) {
913		return False;
914	}
915
916	return True;
917}
918
919/****************************************************************************
920 Unlock a file.
921****************************************************************************/
922
923BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
924{
925	char *p;
926
927	memset(cli->outbuf,'\0',smb_size);
928	memset(cli->inbuf,'\0',smb_size);
929
930	set_message(cli->outbuf,8,0,True);
931
932	SCVAL(cli->outbuf,smb_com,SMBlockingX);
933	SSVAL(cli->outbuf,smb_tid,cli->cnum);
934	cli_setup_packet(cli);
935
936	SCVAL(cli->outbuf,smb_vwv0,0xFF);
937	SSVAL(cli->outbuf,smb_vwv2,fnum);
938	SCVAL(cli->outbuf,smb_vwv3,0);
939	SIVALS(cli->outbuf, smb_vwv4, 0);
940	SSVAL(cli->outbuf,smb_vwv6,1);
941	SSVAL(cli->outbuf,smb_vwv7,0);
942
943	p = smb_buf(cli->outbuf);
944	SSVAL(p, 0, cli->pid);
945	SIVAL(p, 2, offset);
946	SIVAL(p, 6, len);
947	p += 10;
948	cli_setup_bcc(cli, p);
949	cli_send_smb(cli);
950	if (!cli_receive_smb(cli)) {
951		return False;
952	}
953
954	if (cli_is_error(cli)) {
955		return False;
956	}
957
958	return True;
959}
960
961/****************************************************************************
962 Lock a file with 64 bit offsets.
963****************************************************************************/
964
965BOOL cli_lock64(struct cli_state *cli, int fnum,
966		SMB_BIG_UINT offset, SMB_BIG_UINT len, int timeout, enum brl_type lock_type)
967{
968	char *p;
969        int saved_timeout = cli->timeout;
970	int ltype;
971
972	if (! (cli->capabilities & CAP_LARGE_FILES)) {
973		return cli_lock(cli, fnum, offset, len, timeout, lock_type);
974	}
975
976	ltype = (lock_type == READ_LOCK? 1 : 0);
977	ltype |= LOCKING_ANDX_LARGE_FILES;
978
979	memset(cli->outbuf,'\0',smb_size);
980	memset(cli->inbuf,'\0', smb_size);
981
982	set_message(cli->outbuf,8,0,True);
983
984	SCVAL(cli->outbuf,smb_com,SMBlockingX);
985	SSVAL(cli->outbuf,smb_tid,cli->cnum);
986	cli_setup_packet(cli);
987
988	SCVAL(cli->outbuf,smb_vwv0,0xFF);
989	SSVAL(cli->outbuf,smb_vwv2,fnum);
990	SCVAL(cli->outbuf,smb_vwv3,ltype);
991	SIVALS(cli->outbuf, smb_vwv4, timeout);
992	SSVAL(cli->outbuf,smb_vwv6,0);
993	SSVAL(cli->outbuf,smb_vwv7,1);
994
995	p = smb_buf(cli->outbuf);
996	SIVAL(p, 0, cli->pid);
997	SOFF_T_R(p, 4, offset);
998	SOFF_T_R(p, 12, len);
999	p += 20;
1000
1001	cli_setup_bcc(cli, p);
1002	cli_send_smb(cli);
1003
1004	if (timeout != 0) {
1005		cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 5*1000);
1006	}
1007
1008	if (!cli_receive_smb(cli)) {
1009                cli->timeout = saved_timeout;
1010		return False;
1011	}
1012
1013	cli->timeout = saved_timeout;
1014
1015	if (cli_is_error(cli)) {
1016		return False;
1017	}
1018
1019	return True;
1020}
1021
1022/****************************************************************************
1023 Unlock a file with 64 bit offsets.
1024****************************************************************************/
1025
1026BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_BIG_UINT offset, SMB_BIG_UINT len)
1027{
1028	char *p;
1029
1030	if (! (cli->capabilities & CAP_LARGE_FILES)) {
1031		return cli_unlock(cli, fnum, offset, len);
1032	}
1033
1034	memset(cli->outbuf,'\0',smb_size);
1035	memset(cli->inbuf,'\0',smb_size);
1036
1037	set_message(cli->outbuf,8,0,True);
1038
1039	SCVAL(cli->outbuf,smb_com,SMBlockingX);
1040	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1041	cli_setup_packet(cli);
1042
1043	SCVAL(cli->outbuf,smb_vwv0,0xFF);
1044	SSVAL(cli->outbuf,smb_vwv2,fnum);
1045	SCVAL(cli->outbuf,smb_vwv3,LOCKING_ANDX_LARGE_FILES);
1046	SIVALS(cli->outbuf, smb_vwv4, 0);
1047	SSVAL(cli->outbuf,smb_vwv6,1);
1048	SSVAL(cli->outbuf,smb_vwv7,0);
1049
1050	p = smb_buf(cli->outbuf);
1051	SIVAL(p, 0, cli->pid);
1052	SOFF_T_R(p, 4, offset);
1053	SOFF_T_R(p, 12, len);
1054	p += 20;
1055	cli_setup_bcc(cli, p);
1056	cli_send_smb(cli);
1057	if (!cli_receive_smb(cli)) {
1058		return False;
1059	}
1060
1061	if (cli_is_error(cli)) {
1062		return False;
1063	}
1064
1065	return True;
1066}
1067
1068
1069/****************************************************************************
1070 Do a SMBgetattrE call.
1071****************************************************************************/
1072
1073BOOL cli_getattrE(struct cli_state *cli, int fd,
1074		  uint16 *attr, SMB_BIG_UINT *size,
1075		  time_t *c_time, time_t *a_time, time_t *m_time)
1076{
1077	memset(cli->outbuf,'\0',smb_size);
1078	memset(cli->inbuf,'\0',smb_size);
1079
1080	set_message(cli->outbuf,1,0,True);
1081
1082	SCVAL(cli->outbuf,smb_com,SMBgetattrE);
1083	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1084	cli_setup_packet(cli);
1085
1086	SSVAL(cli->outbuf,smb_vwv0,fd);
1087
1088	cli_send_smb(cli);
1089	if (!cli_receive_smb(cli)) {
1090		return False;
1091	}
1092
1093	if (cli_is_error(cli)) {
1094		return False;
1095	}
1096
1097	if (size) {
1098		*size = IVAL(cli->inbuf, smb_vwv6);
1099	}
1100
1101	if (attr) {
1102		*attr = SVAL(cli->inbuf,smb_vwv10);
1103	}
1104
1105	if (c_time) {
1106		*c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1107	}
1108
1109	if (a_time) {
1110		*a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1111	}
1112
1113	if (m_time) {
1114		*m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1115	}
1116
1117	return True;
1118}
1119
1120/****************************************************************************
1121 Do a SMBgetatr call
1122****************************************************************************/
1123
1124BOOL cli_getatr(struct cli_state *cli, const char *fname,
1125		uint16 *attr, size_t *size, time_t *t)
1126{
1127	char *p;
1128
1129	memset(cli->outbuf,'\0',smb_size);
1130	memset(cli->inbuf,'\0',smb_size);
1131
1132	set_message(cli->outbuf,0,0,True);
1133
1134	SCVAL(cli->outbuf,smb_com,SMBgetatr);
1135	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1136	cli_setup_packet(cli);
1137
1138	p = smb_buf(cli->outbuf);
1139	*p++ = 4;
1140	p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
1141
1142	cli_setup_bcc(cli, p);
1143
1144	cli_send_smb(cli);
1145	if (!cli_receive_smb(cli)) {
1146		return False;
1147	}
1148
1149	if (cli_is_error(cli)) {
1150		return False;
1151	}
1152
1153	if (size) {
1154		*size = IVAL(cli->inbuf, smb_vwv3);
1155	}
1156
1157	if (t) {
1158		*t = make_unix_date3(cli->inbuf+smb_vwv1);
1159	}
1160
1161	if (attr) {
1162		*attr = SVAL(cli->inbuf,smb_vwv0);
1163	}
1164
1165
1166	return True;
1167}
1168
1169/****************************************************************************
1170 Do a SMBsetattrE call.
1171****************************************************************************/
1172
1173BOOL cli_setattrE(struct cli_state *cli, int fd,
1174		  time_t c_time, time_t a_time, time_t m_time)
1175
1176{
1177	char *p;
1178
1179	memset(cli->outbuf,'\0',smb_size);
1180	memset(cli->inbuf,'\0',smb_size);
1181
1182	set_message(cli->outbuf,7,0,True);
1183
1184	SCVAL(cli->outbuf,smb_com,SMBsetattrE);
1185	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1186	cli_setup_packet(cli);
1187
1188	SSVAL(cli->outbuf,smb_vwv0, fd);
1189	put_dos_date3(cli->outbuf,smb_vwv1, c_time);
1190	put_dos_date3(cli->outbuf,smb_vwv3, a_time);
1191	put_dos_date3(cli->outbuf,smb_vwv5, m_time);
1192
1193	p = smb_buf(cli->outbuf);
1194	*p++ = 4;
1195
1196	cli_setup_bcc(cli, p);
1197
1198	cli_send_smb(cli);
1199	if (!cli_receive_smb(cli)) {
1200		return False;
1201	}
1202
1203	if (cli_is_error(cli)) {
1204		return False;
1205	}
1206
1207	return True;
1208}
1209
1210/****************************************************************************
1211 Do a SMBsetatr call.
1212****************************************************************************/
1213
1214BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 attr, time_t t)
1215{
1216	char *p;
1217
1218	memset(cli->outbuf,'\0',smb_size);
1219	memset(cli->inbuf,'\0',smb_size);
1220
1221	set_message(cli->outbuf,8,0,True);
1222
1223	SCVAL(cli->outbuf,smb_com,SMBsetatr);
1224	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1225	cli_setup_packet(cli);
1226
1227	SSVAL(cli->outbuf,smb_vwv0, attr);
1228	put_dos_date3(cli->outbuf,smb_vwv1, t);
1229
1230	p = smb_buf(cli->outbuf);
1231	*p++ = 4;
1232	p += clistr_push(cli, p, fname, -1, STR_TERMINATE);
1233	*p++ = 4;
1234
1235	cli_setup_bcc(cli, p);
1236
1237	cli_send_smb(cli);
1238	if (!cli_receive_smb(cli)) {
1239		return False;
1240	}
1241
1242	if (cli_is_error(cli)) {
1243		return False;
1244	}
1245
1246	return True;
1247}
1248
1249/****************************************************************************
1250 Check for existance of a dir.
1251****************************************************************************/
1252BOOL cli_chkpath(struct cli_state *cli, const char *path)
1253{
1254	pstring path2;
1255	char *p;
1256
1257	pstrcpy(path2,path);
1258	trim_char(path2,'\0','\\');
1259	if (!*path2)
1260		*path2 = '\\';
1261
1262	memset(cli->outbuf,'\0',smb_size);
1263	set_message(cli->outbuf,0,0,True);
1264	SCVAL(cli->outbuf,smb_com,SMBchkpth);
1265	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1266	cli_setup_packet(cli);
1267	p = smb_buf(cli->outbuf);
1268	*p++ = 4;
1269	p += clistr_push(cli, p, path2, -1, STR_TERMINATE);
1270
1271	cli_setup_bcc(cli, p);
1272
1273	cli_send_smb(cli);
1274	if (!cli_receive_smb(cli)) {
1275		return False;
1276	}
1277
1278	if (cli_is_error(cli)) return False;
1279
1280	return True;
1281}
1282
1283/****************************************************************************
1284 Query disk space.
1285****************************************************************************/
1286
1287BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
1288{
1289	memset(cli->outbuf,'\0',smb_size);
1290	set_message(cli->outbuf,0,0,True);
1291	SCVAL(cli->outbuf,smb_com,SMBdskattr);
1292	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1293	cli_setup_packet(cli);
1294
1295	cli_send_smb(cli);
1296	if (!cli_receive_smb(cli)) {
1297		return False;
1298	}
1299
1300	*bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
1301	*total = SVAL(cli->inbuf,smb_vwv0);
1302	*avail = SVAL(cli->inbuf,smb_vwv3);
1303
1304	return True;
1305}
1306
1307/****************************************************************************
1308 Create and open a temporary file.
1309****************************************************************************/
1310
1311int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
1312{
1313	int len;
1314	char *p;
1315
1316	memset(cli->outbuf,'\0',smb_size);
1317	memset(cli->inbuf,'\0',smb_size);
1318
1319	set_message(cli->outbuf,3,0,True);
1320
1321	SCVAL(cli->outbuf,smb_com,SMBctemp);
1322	SSVAL(cli->outbuf,smb_tid,cli->cnum);
1323	cli_setup_packet(cli);
1324
1325	SSVAL(cli->outbuf,smb_vwv0,0);
1326	SIVALS(cli->outbuf,smb_vwv1,-1);
1327
1328	p = smb_buf(cli->outbuf);
1329	*p++ = 4;
1330	p += clistr_push(cli, p, path, -1, STR_TERMINATE);
1331
1332	cli_setup_bcc(cli, p);
1333
1334	cli_send_smb(cli);
1335	if (!cli_receive_smb(cli)) {
1336		return -1;
1337	}
1338
1339	if (cli_is_error(cli)) {
1340		return -1;
1341	}
1342
1343	/* despite the spec, the result has a -1, followed by
1344	   length, followed by name */
1345	p = smb_buf(cli->inbuf);
1346	p += 4;
1347	len = smb_buflen(cli->inbuf) - 4;
1348	if (len <= 0) return -1;
1349
1350	if (tmp_path) {
1351		pstring path2;
1352		clistr_pull(cli, path2, p,
1353			    sizeof(path2), len, STR_ASCII);
1354		*tmp_path = SMB_STRDUP(path2);
1355	}
1356
1357	return SVAL(cli->inbuf,smb_vwv0);
1358}
1359
1360
1361/*
1362   send a raw ioctl - used by the torture code
1363*/
1364NTSTATUS cli_raw_ioctl(struct cli_state *cli, int fnum, uint32 code, DATA_BLOB *blob)
1365{
1366	memset(cli->outbuf,'\0',smb_size);
1367	memset(cli->inbuf,'\0',smb_size);
1368
1369	set_message(cli->outbuf, 3, 0, True);
1370	SCVAL(cli->outbuf,smb_com,SMBioctl);
1371	cli_setup_packet(cli);
1372
1373	SSVAL(cli->outbuf, smb_vwv0, fnum);
1374	SSVAL(cli->outbuf, smb_vwv1, code>>16);
1375	SSVAL(cli->outbuf, smb_vwv2, (code&0xFFFF));
1376
1377	cli_send_smb(cli);
1378	if (!cli_receive_smb(cli)) {
1379		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1380	}
1381
1382	if (cli_is_error(cli)) {
1383		return cli_nt_error(cli);
1384	}
1385
1386	*blob = data_blob(NULL, 0);
1387
1388	return NT_STATUS_OK;
1389}
1390
1391/*********************************************************
1392 Set an extended attribute utility fn.
1393*********************************************************/
1394
1395static BOOL cli_set_ea(struct cli_state *cli, uint16 setup, char *param, unsigned int param_len,
1396			const char *ea_name, const char *ea_val, size_t ea_len)
1397{
1398	unsigned int data_len = 0;
1399	char *data = NULL;
1400	char *rparam=NULL, *rdata=NULL;
1401	char *p;
1402	size_t ea_namelen = strlen(ea_name);
1403
1404	data_len = 4 + 4 + ea_namelen + 1 + ea_len;
1405	data = SMB_MALLOC(data_len);
1406	if (!data) {
1407		return False;
1408	}
1409	p = data;
1410	SIVAL(p,0,data_len);
1411	p += 4;
1412	SCVAL(p, 0, 0); /* EA flags. */
1413	SCVAL(p, 1, ea_namelen);
1414	SSVAL(p, 2, ea_len);
1415	memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
1416	memcpy(p+4+ea_namelen+1, ea_val, ea_len);
1417
1418	if (!cli_send_trans(cli, SMBtrans2,
1419		NULL,                        /* name */
1420		-1, 0,                          /* fid, flags */
1421		&setup, 1, 0,                   /* setup, length, max */
1422		param, param_len, 2,            /* param, length, max */
1423		data,  data_len, cli->max_xmit /* data, length, max */
1424		)) {
1425			return False;
1426	}
1427
1428	if (!cli_receive_trans(cli, SMBtrans2,
1429		&rparam, &param_len,
1430		&rdata, &data_len)) {
1431			return False;
1432	}
1433
1434	SAFE_FREE(data);
1435	SAFE_FREE(rdata);
1436	SAFE_FREE(rparam);
1437
1438	return True;
1439}
1440
1441/*********************************************************
1442 Set an extended attribute on a pathname.
1443*********************************************************/
1444
1445BOOL cli_set_ea_path(struct cli_state *cli, const char *path, const char *ea_name, const char *ea_val, size_t ea_len)
1446{
1447	uint16 setup = TRANSACT2_SETPATHINFO;
1448	unsigned int param_len = 0;
1449	char param[sizeof(pstring)+6];
1450	size_t srclen = 2*(strlen(path)+1);
1451	char *p;
1452
1453	memset(param, 0, sizeof(param));
1454	SSVAL(param,0,SMB_INFO_SET_EA);
1455	p = &param[6];
1456
1457	p += clistr_push(cli, p, path, MIN(srclen, sizeof(param)-6), STR_TERMINATE);
1458	param_len = PTR_DIFF(p, param);
1459
1460	return cli_set_ea(cli, setup, param, param_len, ea_name, ea_val, ea_len);
1461}
1462
1463/*********************************************************
1464 Set an extended attribute on an fnum.
1465*********************************************************/
1466
1467BOOL cli_set_ea_fnum(struct cli_state *cli, int fnum, const char *ea_name, const char *ea_val, size_t ea_len)
1468{
1469	char param[6];
1470	uint16 setup = TRANSACT2_SETFILEINFO;
1471
1472	memset(param, 0, 6);
1473	SSVAL(param,0,fnum);
1474	SSVAL(param,2,SMB_INFO_SET_EA);
1475
1476	return cli_set_ea(cli, setup, param, 6, ea_name, ea_val, ea_len);
1477}
1478
1479/*********************************************************
1480 Get an extended attribute list tility fn.
1481*********************************************************/
1482
1483static BOOL cli_get_ea_list(struct cli_state *cli,
1484		uint16 setup, char *param, unsigned int param_len,
1485		TALLOC_CTX *ctx,
1486		size_t *pnum_eas,
1487		struct ea_struct **pea_list)
1488{
1489	unsigned int data_len = 0;
1490	unsigned int rparam_len, rdata_len;
1491	char *rparam=NULL, *rdata=NULL;
1492	char *p;
1493	size_t ea_size;
1494	size_t num_eas;
1495	BOOL ret = False;
1496	struct ea_struct *ea_list;
1497
1498	*pnum_eas = 0;
1499	*pea_list = NULL;
1500
1501	if (!cli_send_trans(cli, SMBtrans2,
1502			NULL,           /* Name */
1503			-1, 0,          /* fid, flags */
1504			&setup, 1, 0,   /* setup, length, max */
1505			param, param_len, 10, /* param, length, max */
1506			NULL, data_len, cli->max_xmit /* data, length, max */
1507				)) {
1508		return False;
1509	}
1510
1511	if (!cli_receive_trans(cli, SMBtrans2,
1512			&rparam, &rparam_len,
1513			&rdata, &rdata_len)) {
1514		return False;
1515	}
1516
1517	if (!rdata || rdata_len < 4) {
1518		goto out;
1519	}
1520
1521	ea_size = (size_t)IVAL(rdata,0);
1522	if (ea_size > rdata_len) {
1523		goto out;
1524	}
1525
1526	if (ea_size == 0) {
1527		/* No EA's present. */
1528		ret = True;
1529		goto out;
1530	}
1531
1532	p = rdata + 4;
1533	ea_size -= 4;
1534
1535	/* Validate the EA list and count it. */
1536	for (num_eas = 0; ea_size >= 4; num_eas++) {
1537		unsigned int ea_namelen = CVAL(p,1);
1538		unsigned int ea_valuelen = SVAL(p,2);
1539		if (ea_namelen == 0) {
1540			goto out;
1541		}
1542		if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
1543			goto out;
1544		}
1545		ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
1546		p += 4 + ea_namelen + 1 + ea_valuelen;
1547	}
1548
1549	if (num_eas == 0) {
1550		ret = True;
1551		goto out;
1552	}
1553
1554	*pnum_eas = num_eas;
1555	if (!pea_list) {
1556		/* Caller only wants number of EA's. */
1557		ret = True;
1558		goto out;
1559	}
1560
1561	ea_list = TALLOC_ARRAY(ctx, struct ea_struct, num_eas);
1562	if (!ea_list) {
1563		goto out;
1564	}
1565
1566	ea_size = (size_t)IVAL(rdata,0);
1567	p = rdata + 4;
1568
1569	for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
1570		struct ea_struct *ea = &ea_list[num_eas];
1571		fstring unix_ea_name;
1572		unsigned int ea_namelen = CVAL(p,1);
1573		unsigned int ea_valuelen = SVAL(p,2);
1574
1575		ea->flags = CVAL(p,0);
1576		unix_ea_name[0] = '\0';
1577		pull_ascii_fstring(unix_ea_name, p + 4);
1578		ea->name = talloc_strdup(ctx, unix_ea_name);
1579		/* Ensure the value is null terminated (in case it's a string). */
1580		ea->value = data_blob_talloc(ctx, NULL, ea_valuelen + 1);
1581		if (!ea->value.data) {
1582			goto out;
1583		}
1584		if (ea_valuelen) {
1585			memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
1586		}
1587		ea->value.data[ea_valuelen] = 0;
1588		ea->value.length--;
1589		p += 4 + ea_namelen + 1 + ea_valuelen;
1590	}
1591
1592	*pea_list = ea_list;
1593	ret = True;
1594
1595 out :
1596
1597	SAFE_FREE(rdata);
1598	SAFE_FREE(rparam);
1599	return ret;
1600}
1601
1602/*********************************************************
1603 Get an extended attribute list from a pathname.
1604*********************************************************/
1605
1606BOOL cli_get_ea_list_path(struct cli_state *cli, const char *path,
1607		TALLOC_CTX *ctx,
1608		size_t *pnum_eas,
1609		struct ea_struct **pea_list)
1610{
1611	uint16 setup = TRANSACT2_QPATHINFO;
1612	unsigned int param_len = 0;
1613	char param[sizeof(pstring)+6];
1614	char *p;
1615
1616	p = param;
1617	memset(p, 0, 6);
1618	SSVAL(p, 0, SMB_INFO_QUERY_ALL_EAS);
1619	p += 6;
1620	p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
1621	param_len = PTR_DIFF(p, param);
1622
1623	return cli_get_ea_list(cli, setup, param, param_len, ctx, pnum_eas, pea_list);
1624}
1625
1626/*********************************************************
1627 Get an extended attribute list from an fnum.
1628*********************************************************/
1629
1630BOOL cli_get_ea_list_fnum(struct cli_state *cli, int fnum,
1631		TALLOC_CTX *ctx,
1632		size_t *pnum_eas,
1633		struct ea_struct **pea_list)
1634{
1635	uint16 setup = TRANSACT2_QFILEINFO;
1636	char param[6];
1637
1638	memset(param, 0, 6);
1639	SSVAL(param,0,fnum);
1640	SSVAL(param,2,SMB_INFO_SET_EA);
1641
1642	return cli_get_ea_list(cli, setup, param, 6, ctx, pnum_eas, pea_list);
1643}
1644