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
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/****************************************************************************
28Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
29****************************************************************************/
30BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name,
31                  uint16 *setup, uint32 setup_count, uint32 max_setup_count,
32                  char *params, uint32 param_count, uint32 max_param_count,
33                  char *data, uint32 data_count, uint32 max_data_count,
34                  char **rparam, uint32 *rparam_count,
35                  char **rdata, uint32 *rdata_count)
36{
37  cli_send_trans(cli, SMBtrans,
38                 pipe_name,
39                 0,0,                         /* fid, flags */
40                 setup, setup_count, max_setup_count,
41                 params, param_count, max_param_count,
42                 data, data_count, max_data_count);
43
44  return (cli_receive_trans(cli, SMBtrans,
45                            rparam, (unsigned int *)rparam_count,
46                            rdata, (unsigned int *)rdata_count));
47}
48
49/****************************************************************************
50call a remote api
51****************************************************************************/
52BOOL cli_api(struct cli_state *cli,
53	     char *param, int prcnt, int mprcnt,
54	     char *data, int drcnt, int mdrcnt,
55	     char **rparam, unsigned int *rprcnt,
56	     char **rdata, unsigned int *rdrcnt)
57{
58  cli_send_trans(cli,SMBtrans,
59                 PIPE_LANMAN,             /* Name */
60                 0,0,                     /* fid, flags */
61                 NULL,0,0,                /* Setup, length, max */
62                 param, prcnt, mprcnt,    /* Params, length, max */
63                 data, drcnt, mdrcnt      /* Data, length, max */
64                );
65
66  return (cli_receive_trans(cli,SMBtrans,
67                            rparam, rprcnt,
68                            rdata, rdrcnt));
69}
70
71
72/****************************************************************************
73perform a NetWkstaUserLogon
74****************************************************************************/
75BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
76{
77	char *rparam = NULL;
78	char *rdata = NULL;
79	char *p;
80	unsigned int rdrcnt,rprcnt;
81	pstring param;
82
83	memset(param, 0, sizeof(param));
84
85	/* send a SMBtrans command with api NetWkstaUserLogon */
86	p = param;
87	SSVAL(p,0,132); /* api number */
88	p += 2;
89	pstrcpy_base(p,"OOWb54WrLh",param);
90	p = skip_string(p,1);
91	pstrcpy_base(p,"WB21BWDWWDDDDDDDzzzD",param);
92	p = skip_string(p,1);
93	SSVAL(p,0,1);
94	p += 2;
95	pstrcpy_base(p,user,param);
96	strupper_m(p);
97	p += 21;
98	p++;
99	p += 15;
100	p++;
101	pstrcpy_base(p, workstation, param);
102	strupper_m(p);
103	p += 16;
104	SSVAL(p, 0, CLI_BUFFER_SIZE);
105	p += 2;
106	SSVAL(p, 0, CLI_BUFFER_SIZE);
107	p += 2;
108
109	if (cli_api(cli,
110                    param, PTR_DIFF(p,param),1024,  /* param, length, max */
111                    NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
112                    &rparam, &rprcnt,               /* return params, return size */
113                    &rdata, &rdrcnt                 /* return data, return size */
114                   )) {
115		cli->rap_error = rparam? SVAL(rparam,0) : -1;
116		p = rdata;
117
118		if (cli->rap_error == 0) {
119			DEBUG(4,("NetWkstaUserLogon success\n"));
120			cli->privileges = SVAL(p, 24);
121			/* The cli->eff_name field used to be set here
122	                   but it wasn't used anywhere else. */
123		} else {
124			DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
125		}
126	}
127
128	SAFE_FREE(rparam);
129	SAFE_FREE(rdata);
130	return (cli->rap_error == 0);
131}
132
133/****************************************************************************
134call a NetShareEnum - try and browse available connections on a host
135****************************************************************************/
136int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
137{
138	char *rparam = NULL;
139	char *rdata = NULL;
140	char *p;
141	unsigned int rdrcnt,rprcnt;
142	pstring param;
143	int count = -1;
144
145	/* now send a SMBtrans command with api RNetShareEnum */
146	p = param;
147	SSVAL(p,0,0); /* api number */
148	p += 2;
149	pstrcpy_base(p,"WrLeh",param);
150	p = skip_string(p,1);
151	pstrcpy_base(p,"B13BWz",param);
152	p = skip_string(p,1);
153	SSVAL(p,0,1);
154	/*
155	 * Win2k needs a *smaller* buffer than 0xFFFF here -
156	 * it returns "out of server memory" with 0xFFFF !!! JRA.
157	 */
158	SSVAL(p,2,0xFFE0);
159	p += 4;
160
161	if (cli_api(cli,
162		    param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
163		    NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
164		    &rparam, &rprcnt,                /* return params, length */
165		    &rdata, &rdrcnt))                /* return data, length */
166		{
167			int res = rparam? SVAL(rparam,0) : -1;
168
169			if (res == 0 || res == ERRmoredata) {
170				int converter=SVAL(rparam,2);
171				int i;
172
173				count=SVAL(rparam,4);
174				p = rdata;
175
176				for (i=0;i<count;i++,p+=20) {
177					char *sname = p;
178					int type = SVAL(p,14);
179					int comment_offset = IVAL(p,16) & 0xFFFF;
180					const char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
181					pstring s1, s2;
182
183					pull_ascii_pstring(s1, sname);
184					pull_ascii_pstring(s2, cmnt);
185
186					fn(s1, type, s2, state);
187				}
188			} else {
189				DEBUG(4,("NetShareEnum res=%d\n", res));
190			}
191		} else {
192			DEBUG(4,("NetShareEnum failed\n"));
193		}
194
195	SAFE_FREE(rparam);
196	SAFE_FREE(rdata);
197
198	return count;
199}
200
201
202/****************************************************************************
203call a NetServerEnum for the specified workgroup and servertype mask.  This
204function then calls the specified callback function for each name returned.
205
206The callback function takes 4 arguments: the machine name, the server type,
207the comment and a state pointer.
208****************************************************************************/
209BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
210		       void (*fn)(const char *, uint32, const char *, void *),
211		       void *state)
212{
213	char *rparam = NULL;
214	char *rdata = NULL;
215	unsigned int rdrcnt,rprcnt;
216	char *p;
217	pstring param;
218	int uLevel = 1;
219	int count = -1;
220
221	errno = 0; /* reset */
222
223	/* send a SMBtrans command with api NetServerEnum */
224	p = param;
225	SSVAL(p,0,0x68); /* api number */
226	p += 2;
227	pstrcpy_base(p,"WrLehDz", param);
228	p = skip_string(p,1);
229
230	pstrcpy_base(p,"B16BBDz", param);
231
232	p = skip_string(p,1);
233	SSVAL(p,0,uLevel);
234	SSVAL(p,2,CLI_BUFFER_SIZE);
235	p += 4;
236	SIVAL(p,0,stype);
237	p += 4;
238
239	p += push_ascii(p, workgroup, sizeof(pstring)-PTR_DIFF(p,param)-1, STR_TERMINATE|STR_UPPER);
240
241	if (cli_api(cli,
242                    param, PTR_DIFF(p,param), 8,        /* params, length, max */
243                    NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
244                    &rparam, &rprcnt,                   /* return params, return size */
245                    &rdata, &rdrcnt                     /* return data, return size */
246                   )) {
247		int res = rparam? SVAL(rparam,0) : -1;
248
249		if (res == 0 || res == ERRmoredata) {
250			int i;
251			int converter=SVAL(rparam,2);
252
253			count=SVAL(rparam,4);
254			p = rdata;
255
256			for (i = 0;i < count;i++, p += 26) {
257				char *sname = p;
258				int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
259				const char *cmnt = comment_offset?(rdata+comment_offset):"";
260				pstring s1, s2;
261
262				if (comment_offset < 0 || comment_offset > (int)rdrcnt) continue;
263
264				stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
265
266				pull_ascii_pstring(s1, sname);
267				pull_ascii_pstring(s2, cmnt);
268				fn(s1, stype, s2, state);
269			}
270		}
271	}
272
273	SAFE_FREE(rparam);
274	SAFE_FREE(rdata);
275
276	if (count < 0) {
277	    errno = cli_errno(cli);
278	} else {
279	    if (!count) {
280		/* this is a very special case, when the domain master for the
281		   work group isn't part of the work group itself, there is something
282		   wild going on */
283		errno = ENOENT;
284	    }
285	}
286
287	return(count > 0);
288}
289
290
291
292/****************************************************************************
293Send a SamOEMChangePassword command
294****************************************************************************/
295BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
296                             const char *old_password)
297{
298  pstring param;
299  char data[532];
300  char *p = param;
301  unsigned char old_pw_hash[16];
302  unsigned char new_pw_hash[16];
303  unsigned int data_len;
304  unsigned int param_len = 0;
305  char *rparam = NULL;
306  char *rdata = NULL;
307  unsigned int rprcnt, rdrcnt;
308
309  if (strlen(user) >= sizeof(fstring)-1) {
310    DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
311    return False;
312  }
313
314  SSVAL(p,0,214); /* SamOEMChangePassword command. */
315  p += 2;
316  pstrcpy_base(p, "zsT", param);
317  p = skip_string(p,1);
318  pstrcpy_base(p, "B516B16", param);
319  p = skip_string(p,1);
320  pstrcpy_base(p,user, param);
321  p = skip_string(p,1);
322  SSVAL(p,0,532);
323  p += 2;
324
325  param_len = PTR_DIFF(p,param);
326
327  /*
328   * Get the Lanman hash of the old password, we
329   * use this as the key to make_oem_passwd_hash().
330   */
331  E_deshash(old_password, old_pw_hash);
332
333  encode_pw_buffer(data, new_password, STR_ASCII);
334
335#ifdef DEBUG_PASSWORD
336  DEBUG(100,("make_oem_passwd_hash\n"));
337  dump_data(100, data, 516);
338#endif
339  SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
340
341  /*
342   * Now place the old password hash in the data.
343   */
344  E_deshash(new_password, new_pw_hash);
345
346  E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
347
348  data_len = 532;
349
350  if (cli_send_trans(cli,SMBtrans,
351                    PIPE_LANMAN,                          /* name */
352                    0,0,                                  /* fid, flags */
353                    NULL,0,0,                             /* setup, length, max */
354                    param,param_len,2,                    /* param, length, max */
355                    data,data_len,0                       /* data, length, max */
356                   ) == False) {
357    DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
358              user ));
359    return False;
360  }
361
362  if (!cli_receive_trans(cli,SMBtrans,
363                       &rparam, &rprcnt,
364                       &rdata, &rdrcnt)) {
365	  DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
366		   user ));
367	  return False;
368  }
369
370  if (rparam)
371	  cli->rap_error = SVAL(rparam,0);
372
373  SAFE_FREE(rparam);
374  SAFE_FREE(rdata);
375
376  return (cli->rap_error == 0);
377}
378
379
380/****************************************************************************
381send a qpathinfo call
382****************************************************************************/
383BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
384		   time_t *c_time, time_t *a_time, time_t *m_time,
385		   size_t *size, uint16 *mode)
386{
387	unsigned int data_len = 0;
388	unsigned int param_len = 0;
389	unsigned int rparam_len, rdata_len;
390	uint16 setup = TRANSACT2_QPATHINFO;
391	pstring param;
392	char *rparam=NULL, *rdata=NULL;
393	int count=8;
394	BOOL ret;
395	time_t (*date_fn)(void *);
396	char *p;
397
398	p = param;
399	memset(p, 0, 6);
400	SSVAL(p, 0, SMB_INFO_STANDARD);
401	p += 6;
402	p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
403
404	param_len = PTR_DIFF(p, param);
405
406	do {
407		ret = (cli_send_trans(cli, SMBtrans2,
408				      NULL,           /* Name */
409				      -1, 0,          /* fid, flags */
410				      &setup, 1, 0,   /* setup, length, max */
411				      param, param_len, 10, /* param, length, max */
412				      NULL, data_len, cli->max_xmit /* data, length, max */
413				      ) &&
414		       cli_receive_trans(cli, SMBtrans2,
415					 &rparam, &rparam_len,
416					 &rdata, &rdata_len));
417		if (!cli_is_dos_error(cli)) break;
418		if (!ret) {
419			/* we need to work around a Win95 bug - sometimes
420			   it gives ERRSRV/ERRerror temprarily */
421			uint8 eclass;
422			uint32 ecode;
423			cli_dos_error(cli, &eclass, &ecode);
424			if (eclass != ERRSRV || ecode != ERRerror) break;
425			smb_msleep(100);
426		}
427	} while (count-- && ret==False);
428
429	if (!ret || !rdata || rdata_len < 22) {
430		return False;
431	}
432
433	if (cli->win95) {
434		date_fn = make_unix_date;
435	} else {
436		date_fn = make_unix_date2;
437	}
438
439	if (c_time) {
440		*c_time = date_fn(rdata+0);
441	}
442	if (a_time) {
443		*a_time = date_fn(rdata+4);
444	}
445	if (m_time) {
446		*m_time = date_fn(rdata+8);
447	}
448	if (size) {
449		*size = IVAL(rdata, 12);
450	}
451	if (mode) {
452		*mode = SVAL(rdata,l1_attrFile);
453	}
454
455	SAFE_FREE(rdata);
456	SAFE_FREE(rparam);
457	return True;
458}
459
460/****************************************************************************
461send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
462****************************************************************************/
463BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
464		    time_t *c_time, time_t *a_time, time_t *m_time,
465		    time_t *w_time, size_t *size, uint16 *mode,
466		    SMB_INO_T *ino)
467{
468	unsigned int data_len = 0;
469	unsigned int param_len = 0;
470	uint16 setup = TRANSACT2_QPATHINFO;
471	pstring param;
472	char *rparam=NULL, *rdata=NULL;
473	char *p;
474
475	p = param;
476	memset(p, 0, 6);
477	SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
478	p += 6;
479	p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
480
481	param_len = PTR_DIFF(p, param);
482
483	if (!cli_send_trans(cli, SMBtrans2,
484                            NULL,                         /* name */
485                            -1, 0,                        /* fid, flags */
486                            &setup, 1, 0,                 /* setup, length, max */
487                            param, param_len, 10,         /* param, length, max */
488                            NULL, data_len, cli->max_xmit /* data, length, max */
489                           )) {
490		return False;
491	}
492
493	if (!cli_receive_trans(cli, SMBtrans2,
494                               &rparam, &param_len,
495                               &rdata, &data_len)) {
496		return False;
497	}
498
499	if (!rdata || data_len < 22) {
500		return False;
501	}
502
503	if (c_time) {
504		*c_time = interpret_long_date(rdata+0) - cli->serverzone;
505	}
506	if (a_time) {
507		*a_time = interpret_long_date(rdata+8) - cli->serverzone;
508	}
509	if (m_time) {
510		*m_time = interpret_long_date(rdata+16) - cli->serverzone;
511	}
512	if (w_time) {
513		*w_time = interpret_long_date(rdata+24) - cli->serverzone;
514	}
515	if (mode) {
516		*mode = SVAL(rdata, 32);
517	}
518	if (size) {
519		*size = IVAL(rdata, 48);
520	}
521	if (ino) {
522		*ino = IVAL(rdata, 64);
523	}
524
525	SAFE_FREE(rdata);
526	SAFE_FREE(rparam);
527	return True;
528}
529
530
531/****************************************************************************
532send a qfileinfo QUERY_FILE_NAME_INFO call
533****************************************************************************/
534BOOL cli_qfilename(struct cli_state *cli, int fnum,
535		   pstring name)
536{
537	unsigned int data_len = 0;
538	unsigned int param_len = 0;
539	uint16 setup = TRANSACT2_QFILEINFO;
540	pstring param;
541	char *rparam=NULL, *rdata=NULL;
542
543	param_len = 4;
544	memset(param, 0, param_len);
545	SSVAL(param, 0, fnum);
546	SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
547
548	if (!cli_send_trans(cli, SMBtrans2,
549                            NULL,                           /* name */
550                            -1, 0,                          /* fid, flags */
551                            &setup, 1, 0,                   /* setup, length, max */
552                            param, param_len, 2,            /* param, length, max */
553                            NULL, data_len, cli->max_xmit   /* data, length, max */
554                           )) {
555		return False;
556	}
557
558	if (!cli_receive_trans(cli, SMBtrans2,
559                               &rparam, &param_len,
560                               &rdata, &data_len)) {
561		return False;
562	}
563
564	if (!rdata || data_len < 4) {
565		return False;
566	}
567
568	clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
569
570	return True;
571}
572
573
574/****************************************************************************
575send a qfileinfo call
576****************************************************************************/
577BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
578		   uint16 *mode, size_t *size,
579		   time_t *c_time, time_t *a_time, time_t *m_time,
580		   time_t *w_time, SMB_INO_T *ino)
581{
582	unsigned int data_len = 0;
583	unsigned int param_len = 0;
584	uint16 setup = TRANSACT2_QFILEINFO;
585	pstring param;
586	char *rparam=NULL, *rdata=NULL;
587
588	/* if its a win95 server then fail this - win95 totally screws it
589	   up */
590	if (cli->win95) return False;
591
592	param_len = 4;
593
594	memset(param, 0, param_len);
595	SSVAL(param, 0, fnum);
596	SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
597
598	if (!cli_send_trans(cli, SMBtrans2,
599                            NULL,                           /* name */
600                            -1, 0,                          /* fid, flags */
601                            &setup, 1, 0,                   /* setup, length, max */
602                            param, param_len, 2,            /* param, length, max */
603                            NULL, data_len, cli->max_xmit   /* data, length, max */
604                           )) {
605		return False;
606	}
607
608	if (!cli_receive_trans(cli, SMBtrans2,
609                               &rparam, &param_len,
610                               &rdata, &data_len)) {
611		return False;
612	}
613
614	if (!rdata || data_len < 68) {
615		return False;
616	}
617
618	if (c_time) {
619		*c_time = interpret_long_date(rdata+0) - cli->serverzone;
620	}
621	if (a_time) {
622		*a_time = interpret_long_date(rdata+8) - cli->serverzone;
623	}
624	if (m_time) {
625		*m_time = interpret_long_date(rdata+16) - cli->serverzone;
626	}
627	if (w_time) {
628		*w_time = interpret_long_date(rdata+24) - cli->serverzone;
629	}
630	if (mode) {
631		*mode = SVAL(rdata, 32);
632	}
633	if (size) {
634		*size = IVAL(rdata, 48);
635	}
636	if (ino) {
637		*ino = IVAL(rdata, 64);
638	}
639
640	SAFE_FREE(rdata);
641	SAFE_FREE(rparam);
642	return True;
643}
644
645
646/****************************************************************************
647send a qpathinfo BASIC_INFO call
648****************************************************************************/
649BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name,
650                          SMB_STRUCT_STAT *sbuf, uint32 *attributes )
651{
652	unsigned int param_len = 0;
653	unsigned int data_len = 0;
654	uint16 setup = TRANSACT2_QPATHINFO;
655	char param[sizeof(pstring)+6];
656	char *rparam=NULL, *rdata=NULL;
657	char *p;
658	pstring path;
659	int len;
660
661	/* send full paths to dfs root shares */
662
663	if ( cli->dfsroot )
664		pstr_sprintf(path, "\\%s\\%s\\%s", cli->desthost, cli->share, name );
665	else
666		pstrcpy( path, name );
667
668	/* cleanup */
669
670	len = strlen( path );
671	if ( path[len] == '\\' )
672		path[len] = '\0';
673
674	p = param;
675	memset(p, 0, 6);
676	SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
677	p += 6;
678	p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
679	param_len = PTR_DIFF(p, param);
680
681	if (!cli_send_trans(cli, SMBtrans2,
682		NULL,                        /* name */
683		-1, 0,                       /* fid, flags */
684		&setup, 1, 0,                /* setup, length, max */
685		param, param_len, 2,         /* param, length, max */
686		NULL,  0, cli->max_xmit      /* data, length, max */
687		)) {
688			return False;
689	}
690
691	if (!cli_receive_trans(cli, SMBtrans2,
692		&rparam, &param_len,
693		&rdata, &data_len)) {
694			return False;
695	}
696
697	if (data_len < 36) {
698		SAFE_FREE(rdata);
699		SAFE_FREE(rparam);
700		return False;
701	}
702
703	sbuf->st_atime = interpret_long_date( rdata+8 );
704	sbuf->st_mtime = interpret_long_date( rdata+16 );
705	sbuf->st_ctime = interpret_long_date( rdata+24 );
706
707	*attributes = IVAL( rdata, 32 );
708
709	SAFE_FREE(rparam);
710	SAFE_FREE(rdata);
711
712	return True;
713}
714
715/****************************************************************************
716send a qfileinfo call
717****************************************************************************/
718
719BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
720{
721	unsigned int data_len = 0;
722	unsigned int param_len = 0;
723	uint16 setup = TRANSACT2_QFILEINFO;
724	pstring param;
725	char *rparam=NULL, *rdata=NULL;
726
727	*poutdata = NULL;
728	*poutlen = 0;
729
730	/* if its a win95 server then fail this - win95 totally screws it
731	   up */
732	if (cli->win95)
733		return False;
734
735	param_len = 4;
736
737	memset(param, 0, param_len);
738	SSVAL(param, 0, fnum);
739	SSVAL(param, 2, level);
740
741	if (!cli_send_trans(cli, SMBtrans2,
742                            NULL,                           /* name */
743                            -1, 0,                          /* fid, flags */
744                            &setup, 1, 0,                   /* setup, length, max */
745                            param, param_len, 2,            /* param, length, max */
746                            NULL, data_len, cli->max_xmit   /* data, length, max */
747                           )) {
748		return False;
749	}
750
751	if (!cli_receive_trans(cli, SMBtrans2,
752                               &rparam, &param_len,
753                               &rdata, &data_len)) {
754		return False;
755	}
756
757	*poutdata = memdup(rdata, data_len);
758	*poutlen = data_len;
759
760	SAFE_FREE(rdata);
761	SAFE_FREE(rparam);
762	return True;
763}
764
765
766
767/****************************************************************************
768send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
769****************************************************************************/
770NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
771{
772	unsigned int data_len = 0;
773	unsigned int param_len = 0;
774	uint16 setup = TRANSACT2_QPATHINFO;
775	pstring param;
776	char *rparam=NULL, *rdata=NULL;
777	int count=8;
778	char *p;
779	BOOL ret;
780	unsigned int len;
781
782	p = param;
783	memset(p, 0, 6);
784	SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
785	p += 6;
786	p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
787
788	param_len = PTR_DIFF(p, param);
789
790	do {
791		ret = (cli_send_trans(cli, SMBtrans2,
792				      NULL,           /* Name */
793				      -1, 0,          /* fid, flags */
794				      &setup, 1, 0,   /* setup, length, max */
795				      param, param_len, 10, /* param, length, max */
796				      NULL, data_len, cli->max_xmit /* data, length, max */
797				      ) &&
798		       cli_receive_trans(cli, SMBtrans2,
799					 &rparam, &param_len,
800					 &rdata, &data_len));
801		if (!ret && cli_is_dos_error(cli)) {
802			/* we need to work around a Win95 bug - sometimes
803			   it gives ERRSRV/ERRerror temprarily */
804			uint8 eclass;
805			uint32 ecode;
806			cli_dos_error(cli, &eclass, &ecode);
807			if (eclass != ERRSRV || ecode != ERRerror) break;
808			smb_msleep(100);
809		}
810	} while (count-- && ret==False);
811
812	if (!ret || !rdata || data_len < 4) {
813		return NT_STATUS_UNSUCCESSFUL;
814	}
815
816	len = IVAL(rdata, 0);
817
818	if (len > data_len - 4) {
819		return NT_STATUS_INVALID_NETWORK_RESPONSE;
820	}
821
822	clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
823
824	SAFE_FREE(rdata);
825	SAFE_FREE(rparam);
826
827	return NT_STATUS_OK;
828}
829