2
Unix SMB/CIFS implementation.
4
Copyright (C) Andrew Tridgell 1994-1998
5
Copyright (C) Gerald (Jerry) Carter 2004
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.
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.
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.
25
/****************************************************************************
26
Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
27
****************************************************************************/
28
BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name,
29
uint16 *setup, uint32 setup_count, uint32 max_setup_count,
30
char *params, uint32 param_count, uint32 max_param_count,
31
char *data, uint32 data_count, uint32 max_data_count,
32
char **rparam, uint32 *rparam_count,
33
char **rdata, uint32 *rdata_count)
35
cli_send_trans(cli, SMBtrans,
38
setup, setup_count, max_setup_count,
39
params, param_count, max_param_count,
40
data, data_count, max_data_count);
42
return (cli_receive_trans(cli, SMBtrans,
43
rparam, (unsigned int *)rparam_count,
44
rdata, (unsigned int *)rdata_count));
47
/****************************************************************************
49
****************************************************************************/
50
BOOL cli_api(struct cli_state *cli,
51
char *param, int prcnt, int mprcnt,
52
char *data, int drcnt, int mdrcnt,
53
char **rparam, unsigned int *rprcnt,
54
char **rdata, unsigned int *rdrcnt)
56
cli_send_trans(cli,SMBtrans,
57
PIPE_LANMAN, /* Name */
59
NULL,0,0, /* Setup, length, max */
60
param, prcnt, mprcnt, /* Params, length, max */
61
data, drcnt, mdrcnt /* Data, length, max */
64
return (cli_receive_trans(cli,SMBtrans,
70
/****************************************************************************
71
perform a NetWkstaUserLogon
72
****************************************************************************/
73
BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
78
unsigned int rdrcnt,rprcnt;
81
memset(param, 0, sizeof(param));
83
/* send a SMBtrans command with api NetWkstaUserLogon */
85
SSVAL(p,0,132); /* api number */
87
pstrcpy_base(p,"OOWb54WrLh",param);
89
pstrcpy_base(p,"WB21BWDWWDDDDDDDzzzD",param);
93
pstrcpy_base(p,user,param);
99
pstrcpy_base(p, workstation, param);
102
SSVAL(p, 0, CLI_BUFFER_SIZE);
104
SSVAL(p, 0, CLI_BUFFER_SIZE);
108
param, PTR_DIFF(p,param),1024, /* param, length, max */
109
NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
110
&rparam, &rprcnt, /* return params, return size */
111
&rdata, &rdrcnt /* return data, return size */
113
cli->rap_error = rparam? SVAL(rparam,0) : -1;
116
if (cli->rap_error == 0) {
117
DEBUG(4,("NetWkstaUserLogon success\n"));
118
cli->privileges = SVAL(p, 24);
119
/* The cli->eff_name field used to be set here
120
but it wasn't used anywhere else. */
122
DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
128
return (cli->rap_error == 0);
131
/****************************************************************************
132
call a NetShareEnum - try and browse available connections on a host
133
****************************************************************************/
134
int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
139
unsigned int rdrcnt,rprcnt;
143
/* now send a SMBtrans command with api RNetShareEnum */
145
SSVAL(p,0,0); /* api number */
147
pstrcpy_base(p,"WrLeh",param);
148
p = skip_string(p,1);
149
pstrcpy_base(p,"B13BWz",param);
150
p = skip_string(p,1);
153
* Win2k needs a *smaller* buffer than 0xFFFF here -
154
* it returns "out of server memory" with 0xFFFF !!! JRA.
160
param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
161
NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
162
&rparam, &rprcnt, /* return params, length */
163
&rdata, &rdrcnt)) /* return data, length */
165
int res = rparam? SVAL(rparam,0) : -1;
167
if (res == 0 || res == ERRmoredata) {
168
int converter=SVAL(rparam,2);
171
count=SVAL(rparam,4);
174
for (i=0;i<count;i++,p+=20) {
176
int type = SVAL(p,14);
177
int comment_offset = IVAL(p,16) & 0xFFFF;
178
const char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
181
pull_ascii_pstring(s1, sname);
182
pull_ascii_pstring(s2, cmnt);
184
fn(s1, type, s2, state);
187
DEBUG(4,("NetShareEnum res=%d\n", res));
190
DEBUG(4,("NetShareEnum failed\n"));
200
/****************************************************************************
201
call a NetServerEnum for the specified workgroup and servertype mask. This
202
function then calls the specified callback function for each name returned.
204
The callback function takes 4 arguments: the machine name, the server type,
205
the comment and a state pointer.
206
****************************************************************************/
207
BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
208
void (*fn)(const char *, uint32, const char *, void *),
213
unsigned int rdrcnt,rprcnt;
219
errno = 0; /* reset */
221
/* send a SMBtrans command with api NetServerEnum */
223
SSVAL(p,0,0x68); /* api number */
225
pstrcpy_base(p,"WrLehDz", param);
226
p = skip_string(p,1);
228
pstrcpy_base(p,"B16BBDz", param);
230
p = skip_string(p,1);
232
SSVAL(p,2,CLI_BUFFER_SIZE);
237
p += push_ascii(p, workgroup, sizeof(pstring)-PTR_DIFF(p,param)-1, STR_TERMINATE|STR_UPPER);
240
param, PTR_DIFF(p,param), 8, /* params, length, max */
241
NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
242
&rparam, &rprcnt, /* return params, return size */
243
&rdata, &rdrcnt /* return data, return size */
245
int res = rparam? SVAL(rparam,0) : -1;
247
if (res == 0 || res == ERRmoredata) {
249
int converter=SVAL(rparam,2);
251
count=SVAL(rparam,4);
254
for (i = 0;i < count;i++, p += 26) {
256
int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
257
const char *cmnt = comment_offset?(rdata+comment_offset):"";
260
if (comment_offset < 0 || comment_offset > (int)rdrcnt) continue;
262
stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
264
pull_ascii_pstring(s1, sname);
265
pull_ascii_pstring(s2, cmnt);
266
fn(s1, stype, s2, state);
275
errno = cli_errno(cli);
278
/* this is a very special case, when the domain master for the
279
work group isn't part of the work group itself, there is something
290
/****************************************************************************
291
Send a SamOEMChangePassword command
292
****************************************************************************/
293
BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
294
const char *old_password)
297
unsigned char data[532];
299
unsigned char old_pw_hash[16];
300
unsigned char new_pw_hash[16];
301
unsigned int data_len;
302
unsigned int param_len = 0;
305
unsigned int rprcnt, rdrcnt;
307
if (strlen(user) >= sizeof(fstring)-1) {
308
DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
312
SSVAL(p,0,214); /* SamOEMChangePassword command. */
314
pstrcpy_base(p, "zsT", param);
315
p = skip_string(p,1);
316
pstrcpy_base(p, "B516B16", param);
317
p = skip_string(p,1);
318
pstrcpy_base(p,user, param);
319
p = skip_string(p,1);
323
param_len = PTR_DIFF(p,param);
326
* Get the Lanman hash of the old password, we
327
* use this as the key to make_oem_passwd_hash().
329
E_deshash(old_password, old_pw_hash);
331
encode_pw_buffer(data, new_password, STR_ASCII);
333
#ifdef DEBUG_PASSWORD
334
DEBUG(100,("make_oem_passwd_hash\n"));
335
dump_data(100, (char *)data, 516);
337
SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
340
* Now place the old password hash in the data.
342
E_deshash(new_password, new_pw_hash);
344
E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
348
if (cli_send_trans(cli,SMBtrans,
349
PIPE_LANMAN, /* name */
350
0,0, /* fid, flags */
351
NULL,0,0, /* setup, length, max */
352
param,param_len,2, /* param, length, max */
353
(char *)data,data_len,0 /* data, length, max */
355
DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
360
if (!cli_receive_trans(cli,SMBtrans,
363
DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
369
cli->rap_error = SVAL(rparam,0);
374
return (cli->rap_error == 0);
378
/****************************************************************************
379
send a qpathinfo call
380
****************************************************************************/
381
BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
382
time_t *c_time, time_t *a_time, time_t *m_time,
383
SMB_OFF_T *size, uint16 *mode)
385
unsigned int data_len = 0;
386
unsigned int param_len = 0;
387
unsigned int rparam_len, rdata_len;
388
uint16 setup = TRANSACT2_QPATHINFO;
390
char *rparam=NULL, *rdata=NULL;
393
time_t (*date_fn)(struct cli_state *, void *);
398
SSVAL(p, 0, SMB_INFO_STANDARD);
400
p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
402
param_len = PTR_DIFF(p, param);
405
ret = (cli_send_trans(cli, SMBtrans2,
407
-1, 0, /* fid, flags */
408
&setup, 1, 0, /* setup, length, max */
409
param, param_len, 10, /* param, length, max */
410
NULL, data_len, cli->max_xmit /* data, length, max */
412
cli_receive_trans(cli, SMBtrans2,
413
&rparam, &rparam_len,
414
&rdata, &rdata_len));
415
if (!cli_is_dos_error(cli)) break;
417
/* we need to work around a Win95 bug - sometimes
418
it gives ERRSRV/ERRerror temprarily */
421
cli_dos_error(cli, &eclass, &ecode);
422
if (eclass != ERRSRV || ecode != ERRerror) break;
425
} while (count-- && ret==False);
427
if (!ret || !rdata || rdata_len < 22) {
432
date_fn = cli_make_unix_date;
434
date_fn = cli_make_unix_date2;
438
*c_time = date_fn(cli, rdata+0);
441
*a_time = date_fn(cli, rdata+4);
444
*m_time = date_fn(cli, rdata+8);
447
*size = IVAL(rdata, 12);
450
*mode = SVAL(rdata,l1_attrFile);
459
/****************************************************************************
460
send a setpathinfo call
461
****************************************************************************/
462
BOOL cli_setpathinfo(struct cli_state *cli, const char *fname,
463
time_t c_time, time_t a_time, time_t m_time, uint16 mode)
465
unsigned int data_len = 0;
466
unsigned int param_len = 0;
467
unsigned int rparam_len, rdata_len;
468
uint16 setup = TRANSACT2_SETPATHINFO;
471
char *rparam=NULL, *rdata=NULL;
476
memset(param, 0, sizeof(param));
477
memset(data, 0, sizeof(data));
481
/* Add the information level */
482
SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
487
/* Add the file name */
488
p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
490
param_len = PTR_DIFF(p, param);
495
* Add the create, last access, modification, and status change times
498
/* Don't set create time, at offset 0 */
501
put_long_date(p, a_time);
504
put_long_date(p, m_time);
507
put_long_date(p, c_time);
518
data_len = PTR_DIFF(p, data);
521
ret = (cli_send_trans(cli, SMBtrans2,
523
-1, 0, /* fid, flags */
524
&setup, 1, 0, /* setup, length, max */
525
param, param_len, 10, /* param, length, max */
526
data, data_len, cli->max_xmit /* data, length, max */
528
cli_receive_trans(cli, SMBtrans2,
529
&rparam, &rparam_len,
530
&rdata, &rdata_len));
531
if (!cli_is_dos_error(cli)) break;
533
/* we need to work around a Win95 bug - sometimes
534
it gives ERRSRV/ERRerror temprarily */
537
cli_dos_error(cli, &eclass, &ecode);
538
if (eclass != ERRSRV || ecode != ERRerror) break;
541
} while (count-- && ret==False);
553
/****************************************************************************
554
send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
555
****************************************************************************/
556
BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
557
time_t *c_time, time_t *a_time, time_t *m_time,
558
time_t *w_time, SMB_OFF_T *size, uint16 *mode,
561
unsigned int data_len = 0;
562
unsigned int param_len = 0;
563
uint16 setup = TRANSACT2_QPATHINFO;
565
char *rparam=NULL, *rdata=NULL;
570
SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
572
p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
574
param_len = PTR_DIFF(p, param);
576
if (!cli_send_trans(cli, SMBtrans2,
578
-1, 0, /* fid, flags */
579
&setup, 1, 0, /* setup, length, max */
580
param, param_len, 10, /* param, length, max */
581
NULL, data_len, cli->max_xmit /* data, length, max */
586
if (!cli_receive_trans(cli, SMBtrans2,
588
&rdata, &data_len)) {
592
if (!rdata || data_len < 22) {
597
*c_time = interpret_long_date(rdata+0);
600
*a_time = interpret_long_date(rdata+8);
603
*w_time = interpret_long_date(rdata+16);
606
*m_time = interpret_long_date(rdata+24);
609
*mode = SVAL(rdata, 32);
612
*size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
615
*ino = IVAL(rdata, 64);
624
/****************************************************************************
625
send a qfileinfo QUERY_FILE_NAME_INFO call
626
****************************************************************************/
627
BOOL cli_qfilename(struct cli_state *cli, int fnum,
630
unsigned int data_len = 0;
631
unsigned int param_len = 0;
632
uint16 setup = TRANSACT2_QFILEINFO;
634
char *rparam=NULL, *rdata=NULL;
637
memset(param, 0, param_len);
638
SSVAL(param, 0, fnum);
639
SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
641
if (!cli_send_trans(cli, SMBtrans2,
643
-1, 0, /* fid, flags */
644
&setup, 1, 0, /* setup, length, max */
645
param, param_len, 2, /* param, length, max */
646
NULL, data_len, cli->max_xmit /* data, length, max */
651
if (!cli_receive_trans(cli, SMBtrans2,
653
&rdata, &data_len)) {
657
if (!rdata || data_len < 4) {
661
clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
667
/****************************************************************************
668
send a qfileinfo call
669
****************************************************************************/
670
BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
671
uint16 *mode, SMB_OFF_T *size,
672
time_t *c_time, time_t *a_time, time_t *m_time,
673
time_t *w_time, SMB_INO_T *ino)
675
unsigned int data_len = 0;
676
unsigned int param_len = 0;
677
uint16 setup = TRANSACT2_QFILEINFO;
679
char *rparam=NULL, *rdata=NULL;
681
/* if its a win95 server then fail this - win95 totally screws it
683
if (cli->win95) return False;
687
memset(param, 0, param_len);
688
SSVAL(param, 0, fnum);
689
SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
691
if (!cli_send_trans(cli, SMBtrans2,
693
-1, 0, /* fid, flags */
694
&setup, 1, 0, /* setup, length, max */
695
param, param_len, 2, /* param, length, max */
696
NULL, data_len, cli->max_xmit /* data, length, max */
701
if (!cli_receive_trans(cli, SMBtrans2,
703
&rdata, &data_len)) {
707
if (!rdata || data_len < 68) {
712
*c_time = interpret_long_date(rdata+0) - cli->serverzone;
715
*a_time = interpret_long_date(rdata+8) - cli->serverzone;
718
*m_time = interpret_long_date(rdata+16) - cli->serverzone;
721
*w_time = interpret_long_date(rdata+24) - cli->serverzone;
724
*mode = SVAL(rdata, 32);
727
*size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
730
*ino = IVAL(rdata, 64);
739
/****************************************************************************
740
send a qpathinfo BASIC_INFO call
741
****************************************************************************/
742
BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name,
743
SMB_STRUCT_STAT *sbuf, uint32 *attributes )
745
unsigned int param_len = 0;
746
unsigned int data_len = 0;
747
uint16 setup = TRANSACT2_QPATHINFO;
748
char param[sizeof(pstring)+6];
749
char *rparam=NULL, *rdata=NULL;
754
/* send full paths to dfs root shares */
757
pstr_sprintf(path, "\\%s\\%s\\%s", cli->desthost, cli->share, name );
759
pstrcpy( path, name );
763
len = strlen( path );
764
if ( path[len] == '\\' )
769
SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
771
p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
772
param_len = PTR_DIFF(p, param);
774
if (!cli_send_trans(cli, SMBtrans2,
776
-1, 0, /* fid, flags */
777
&setup, 1, 0, /* setup, length, max */
778
param, param_len, 2, /* param, length, max */
779
NULL, 0, cli->max_xmit /* data, length, max */
784
if (!cli_receive_trans(cli, SMBtrans2,
786
&rdata, &data_len)) {
796
sbuf->st_atime = interpret_long_date( rdata+8 );
797
sbuf->st_mtime = interpret_long_date( rdata+16 );
798
sbuf->st_ctime = interpret_long_date( rdata+24 );
800
*attributes = IVAL( rdata, 32 );
808
/****************************************************************************
809
send a qfileinfo call
810
****************************************************************************/
812
BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
814
unsigned int data_len = 0;
815
unsigned int param_len = 0;
816
uint16 setup = TRANSACT2_QFILEINFO;
818
char *rparam=NULL, *rdata=NULL;
823
/* if its a win95 server then fail this - win95 totally screws it
830
memset(param, 0, param_len);
831
SSVAL(param, 0, fnum);
832
SSVAL(param, 2, level);
834
if (!cli_send_trans(cli, SMBtrans2,
836
-1, 0, /* fid, flags */
837
&setup, 1, 0, /* setup, length, max */
838
param, param_len, 2, /* param, length, max */
839
NULL, data_len, cli->max_xmit /* data, length, max */
844
if (!cli_receive_trans(cli, SMBtrans2,
846
&rdata, &data_len)) {
850
*poutdata = memdup(rdata, data_len);
866
/****************************************************************************
867
send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
868
****************************************************************************/
869
NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
871
unsigned int data_len = 0;
872
unsigned int param_len = 0;
873
uint16 setup = TRANSACT2_QPATHINFO;
875
char *rparam=NULL, *rdata=NULL;
883
SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
885
p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
887
param_len = PTR_DIFF(p, param);
890
ret = (cli_send_trans(cli, SMBtrans2,
892
-1, 0, /* fid, flags */
893
&setup, 1, 0, /* setup, length, max */
894
param, param_len, 10, /* param, length, max */
895
NULL, data_len, cli->max_xmit /* data, length, max */
897
cli_receive_trans(cli, SMBtrans2,
900
if (!ret && cli_is_dos_error(cli)) {
901
/* we need to work around a Win95 bug - sometimes
902
it gives ERRSRV/ERRerror temprarily */
905
cli_dos_error(cli, &eclass, &ecode);
906
if (eclass != ERRSRV || ecode != ERRerror) break;
909
} while (count-- && ret==False);
911
if (!ret || !rdata || data_len < 4) {
912
return NT_STATUS_UNSUCCESSFUL;
915
len = IVAL(rdata, 0);
917
if (len > data_len - 4) {
918
return NT_STATUS_INVALID_NETWORK_RESPONSE;
921
clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);