Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netsmb/smb_smb.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2000-2001 Boris Popov
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
/*
30
* various SMB requests. Most of the routines merely packs data into mbufs.
31
*/
32
33
#include <sys/param.h>
34
#include <sys/systm.h>
35
#include <sys/kernel.h>
36
#include <sys/malloc.h>
37
#include <sys/proc.h>
38
#include <sys/lock.h>
39
#include <sys/sysctl.h>
40
#include <sys/socket.h>
41
#include <sys/uio.h>
42
43
#include <sys/iconv.h>
44
45
#include <netsmb/smb.h>
46
#include <netsmb/smb_subr.h>
47
#include <netsmb/smb_rq.h>
48
#include <netsmb/smb_conn.h>
49
#include <netsmb/smb_tran.h>
50
51
#include "opt_netsmb.h"
52
53
struct smb_dialect {
54
int d_id;
55
const char * d_name;
56
};
57
58
static struct smb_dialect smb_dialects[] = {
59
{SMB_DIALECT_CORE, "PC NETWORK PROGRAM 1.0"},
60
{SMB_DIALECT_COREPLUS, "MICROSOFT NETWORKS 1.03"},
61
{SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"},
62
{SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
63
{SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
64
{SMB_DIALECT_LANMAN2_0, "Samba"},
65
{SMB_DIALECT_NTLM0_12, "NT LANMAN 1.0"},
66
{SMB_DIALECT_NTLM0_12, "NT LM 0.12"},
67
{-1, NULL}
68
};
69
70
static u_int32_t
71
smb_vc_maxread(struct smb_vc *vcp)
72
{
73
/*
74
* Specs say up to 64k data bytes, but Windows traffic
75
* uses 60k... no doubt for some good reason.
76
*
77
* Don't exceed the server's buffer size if signatures
78
* are enabled otherwise Windows 2003 chokes. Allow space
79
* for the SMB header & a little bit extra.
80
*/
81
if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) &&
82
(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
83
return (60*1024);
84
else
85
return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
86
}
87
88
static u_int32_t
89
smb_vc_maxwrite(struct smb_vc *vcp)
90
{
91
/*
92
* See comment above.
93
*/
94
if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) &&
95
(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
96
return (60*1024);
97
else
98
return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
99
}
100
101
static int
102
smb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name)
103
{
104
if (scred->scr_td->td_proc == vcp->vc_iod->iod_p)
105
return 0;
106
SMBERROR("wrong function called(%s)\n", name);
107
return EINVAL;
108
}
109
110
int
111
smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
112
{
113
struct smb_dialect *dp;
114
struct smb_sopt *sp = NULL;
115
struct smb_rq *rqp;
116
struct mbchain *mbp;
117
struct mdchain *mdp;
118
u_int8_t wc, stime[8], sblen;
119
u_int16_t dindex, tw, tw1, swlen, bc;
120
int error, maxqsz;
121
int unicode = SMB_UNICODE_STRINGS(vcp);
122
void * servercharset = vcp->vc_toserver;
123
void * localcharset = vcp->vc_tolocal;
124
125
if (smb_smb_nomux(vcp, scred, __func__) != 0)
126
return EINVAL;
127
/* Disable Unicode for SMB_COM_NEGOTIATE requests */
128
if (unicode) {
129
vcp->vc_toserver = vcp->vc_cp_toserver;
130
vcp->vc_tolocal = vcp->vc_cp_tolocal;
131
}
132
vcp->vc_hflags = 0;
133
vcp->vc_hflags2 = 0;
134
vcp->obj.co_flags &= ~(SMBV_ENCRYPT);
135
sp = &vcp->vc_sopt;
136
bzero(sp, sizeof(struct smb_sopt));
137
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
138
if (error)
139
return error;
140
smb_rq_getrequest(rqp, &mbp);
141
smb_rq_wstart(rqp);
142
smb_rq_wend(rqp);
143
smb_rq_bstart(rqp);
144
for(dp = smb_dialects; dp->d_id != -1; dp++) {
145
mb_put_uint8(mbp, SMB_DT_DIALECT);
146
smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE);
147
}
148
smb_rq_bend(rqp);
149
error = smb_rq_simple(rqp);
150
SMBSDEBUG("%d\n", error);
151
if (error)
152
goto bad;
153
smb_rq_getreply(rqp, &mdp);
154
do {
155
error = md_get_uint8(mdp, &wc);
156
if (error)
157
break;
158
error = md_get_uint16le(mdp, &dindex);
159
if (error)
160
break;
161
if (dindex > 7) {
162
SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex);
163
error = EBADRPC;
164
break;
165
}
166
dp = smb_dialects + dindex;
167
sp->sv_proto = dp->d_id;
168
SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc);
169
error = EBADRPC;
170
if (dp->d_id >= SMB_DIALECT_NTLM0_12) {
171
if (wc != 17)
172
break;
173
md_get_uint8(mdp, &sp->sv_sm);
174
md_get_uint16le(mdp, &sp->sv_maxmux);
175
md_get_uint16le(mdp, &sp->sv_maxvcs);
176
md_get_uint32le(mdp, &sp->sv_maxtx);
177
md_get_uint32le(mdp, &sp->sv_maxraw);
178
md_get_uint32le(mdp, &sp->sv_skey);
179
md_get_uint32le(mdp, &sp->sv_caps);
180
md_get_mem(mdp, stime, 8, MB_MSYSTEM);
181
md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
182
md_get_uint8(mdp, &sblen);
183
if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
184
if (sblen != SMB_MAXCHALLENGELEN) {
185
SMBERROR("Unexpected length of security blob (%d)\n", sblen);
186
break;
187
}
188
error = md_get_uint16le(mdp, &bc);
189
if (error)
190
break;
191
if (sp->sv_caps & SMB_CAP_EXT_SECURITY)
192
md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
193
error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM);
194
if (error)
195
break;
196
vcp->vc_chlen = sblen;
197
vcp->obj.co_flags |= SMBV_ENCRYPT;
198
}
199
if (sp->sv_sm & SMB_SM_SIGS_REQUIRE)
200
vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
201
if (vcp->vc_ucs_toserver &&
202
sp->sv_caps & SMB_CAP_UNICODE) {
203
/*
204
* They do Unicode.
205
*/
206
vcp->obj.co_flags |= SMBV_UNICODE;
207
}
208
vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
209
if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
210
sp->sv_maxtx < 4096 &&
211
(sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
212
vcp->obj.co_flags |= SMBV_WIN95;
213
SMBSDEBUG("Win95 detected\n");
214
}
215
error = 0;
216
break;
217
}
218
vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS|
219
SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE);
220
unicode = 0;
221
if (dp->d_id > SMB_DIALECT_CORE) {
222
md_get_uint16le(mdp, &tw);
223
sp->sv_sm = tw;
224
md_get_uint16le(mdp, &tw);
225
sp->sv_maxtx = tw;
226
md_get_uint16le(mdp, &sp->sv_maxmux);
227
md_get_uint16le(mdp, &sp->sv_maxvcs);
228
md_get_uint16le(mdp, &tw); /* rawmode */
229
md_get_uint32le(mdp, &sp->sv_skey);
230
if (wc == 13) { /* >= LANMAN1 */
231
md_get_uint16(mdp, &tw); /* time */
232
md_get_uint16(mdp, &tw1); /* date */
233
md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
234
md_get_uint16le(mdp, &swlen);
235
if (swlen > SMB_MAXCHALLENGELEN)
236
break;
237
md_get_uint16(mdp, NULL); /* mbz */
238
if (md_get_uint16le(mdp, &bc) != 0)
239
break;
240
if (bc < swlen)
241
break;
242
if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
243
error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM);
244
if (error)
245
break;
246
vcp->vc_chlen = swlen;
247
vcp->obj.co_flags |= SMBV_ENCRYPT;
248
}
249
}
250
vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
251
} else { /* an old CORE protocol */
252
sp->sv_maxmux = 1;
253
}
254
error = 0;
255
} while (0);
256
if (error == 0) {
257
vcp->vc_maxvcs = sp->sv_maxvcs;
258
if (vcp->vc_maxvcs <= 1) {
259
if (vcp->vc_maxvcs == 0)
260
vcp->vc_maxvcs = 1;
261
}
262
if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff)
263
sp->sv_maxtx = 1024;
264
else
265
sp->sv_maxtx = min(sp->sv_maxtx,
266
63*1024 + SMB_HDRLEN + 16);
267
SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz);
268
vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024);
269
SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz);
270
vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024);
271
vcp->vc_txmax = min(sp->sv_maxtx, maxqsz);
272
SMBSDEBUG("TZ = %d\n", sp->sv_tz);
273
SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
274
SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux);
275
SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs);
276
SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw);
277
SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx);
278
}
279
bad:
280
/* Restore Unicode conversion state */
281
if (unicode) {
282
vcp->vc_toserver = servercharset;
283
vcp->vc_tolocal = localcharset;
284
vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
285
}
286
smb_rq_done(rqp);
287
return error;
288
}
289
290
int
291
smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
292
{
293
struct smb_rq *rqp;
294
struct mbchain *mbp;
295
/* u_int8_t wc;
296
u_int16_t tw, tw1;*/
297
smb_uniptr unipp, ntencpass = NULL;
298
char *pp, *up, *pbuf, *encpass;
299
int error, plen, uniplen, ulen, upper;
300
u_int32_t caps = 0;
301
302
upper = 0;
303
304
if (vcp->obj.co_flags & SMBV_UNICODE)
305
caps |= SMB_CAP_UNICODE;
306
307
again:
308
309
vcp->vc_smbuid = SMB_UID_UNKNOWN;
310
311
if (smb_smb_nomux(vcp, scred, __func__) != 0)
312
return EINVAL;
313
314
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
315
if (error)
316
return error;
317
pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
318
encpass = malloc(24, M_SMBTEMP, M_WAITOK);
319
if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
320
/*
321
* We try w/o uppercasing first so Samba mixed case
322
* passwords work. If that fails we come back and try
323
* uppercasing to satisfy OS/2 and Windows for Workgroups.
324
*/
325
if (upper++) {
326
iconv_convstr(vcp->vc_toupper, pbuf,
327
smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/);
328
} else {
329
strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
330
pbuf[SMB_MAXPASSWORDLEN] = '\0';
331
}
332
if (!SMB_UNICODE_STRINGS(vcp))
333
iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*,
334
SMB_MAXPASSWORDLEN*/);
335
336
if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
337
uniplen = plen = 24;
338
smb_encrypt(pbuf, vcp->vc_ch, encpass);
339
ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
340
if (SMB_UNICODE_STRINGS(vcp)) {
341
strncpy(pbuf, smb_vc_getpass(vcp),
342
SMB_MAXPASSWORDLEN);
343
pbuf[SMB_MAXPASSWORDLEN] = '\0';
344
} else
345
iconv_convstr(vcp->vc_toserver, pbuf,
346
smb_vc_getpass(vcp)/*,
347
SMB_MAXPASSWORDLEN*/);
348
smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
349
pp = encpass;
350
unipp = ntencpass;
351
} else {
352
plen = strlen(pbuf) + 1;
353
pp = pbuf;
354
uniplen = plen * 2;
355
ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
356
smb_strtouni(ntencpass, smb_vc_getpass(vcp));
357
plen--;
358
359
/*
360
* The uniplen is zeroed because Samba cannot deal
361
* with this 2nd cleartext password. This Samba
362
* "bug" is actually a workaround for problems in
363
* Microsoft clients.
364
*/
365
uniplen = 0/*-= 2*/;
366
unipp = ntencpass;
367
}
368
} else {
369
/*
370
* In the share security mode password will be used
371
* only in the tree authentication
372
*/
373
pp = "";
374
plen = 1;
375
unipp = &smb_unieol;
376
uniplen = 0 /* sizeof(smb_unieol) */;
377
}
378
smb_rq_wstart(rqp);
379
mbp = &rqp->sr_rq;
380
up = vcp->vc_username;
381
ulen = strlen(up) + 1;
382
/*
383
* If userid is null we are attempting anonymous browse login
384
* so passwords must be zero length.
385
*/
386
if (ulen == 1)
387
plen = uniplen = 0;
388
mb_put_uint8(mbp, 0xff);
389
mb_put_uint8(mbp, 0);
390
mb_put_uint16le(mbp, 0);
391
mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
392
mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
393
mb_put_uint16le(mbp, vcp->vc_number);
394
mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
395
mb_put_uint16le(mbp, plen);
396
if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
397
mb_put_uint32le(mbp, 0);
398
smb_rq_wend(rqp);
399
smb_rq_bstart(rqp);
400
mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
401
smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
402
} else {
403
mb_put_uint16le(mbp, uniplen);
404
mb_put_uint32le(mbp, 0); /* reserved */
405
mb_put_uint32le(mbp, caps);
406
smb_rq_wend(rqp);
407
smb_rq_bstart(rqp);
408
mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
409
mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
410
smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* AccountName */
411
smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */
412
smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE); /* Client's OS */
413
smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE); /* Client name */
414
}
415
smb_rq_bend(rqp);
416
if (ntencpass)
417
free(ntencpass, M_SMBTEMP);
418
if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
419
smb_calcmackey(vcp);
420
error = smb_rq_simple(rqp);
421
SMBSDEBUG("%d\n", error);
422
if (error) {
423
if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess)
424
error = EAUTH;
425
goto bad;
426
}
427
vcp->vc_smbuid = rqp->sr_rpuid;
428
bad:
429
free(encpass, M_SMBTEMP);
430
free(pbuf, M_SMBTEMP);
431
smb_rq_done(rqp);
432
if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER)
433
goto again;
434
return error;
435
}
436
437
int
438
smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
439
{
440
struct smb_rq *rqp;
441
struct mbchain *mbp;
442
int error;
443
444
if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
445
return 0;
446
447
if (smb_smb_nomux(vcp, scred, __func__) != 0)
448
return EINVAL;
449
450
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
451
if (error)
452
return error;
453
mbp = &rqp->sr_rq;
454
smb_rq_wstart(rqp);
455
mb_put_uint8(mbp, 0xff);
456
mb_put_uint8(mbp, 0);
457
mb_put_uint16le(mbp, 0);
458
smb_rq_wend(rqp);
459
smb_rq_bstart(rqp);
460
smb_rq_bend(rqp);
461
error = smb_rq_simple(rqp);
462
SMBSDEBUG("%d\n", error);
463
smb_rq_done(rqp);
464
return error;
465
}
466
467
static char smb_any_share[] = "?????";
468
469
static char *
470
smb_share_typename(int stype)
471
{
472
char *pp;
473
474
switch (stype) {
475
case SMB_ST_DISK:
476
pp = "A:";
477
break;
478
case SMB_ST_PRINTER:
479
pp = smb_any_share; /* can't use LPT: here... */
480
break;
481
case SMB_ST_PIPE:
482
pp = "IPC";
483
break;
484
case SMB_ST_COMM:
485
pp = "COMM";
486
break;
487
case SMB_ST_ANY:
488
default:
489
pp = smb_any_share;
490
break;
491
}
492
return pp;
493
}
494
495
int
496
smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
497
{
498
struct smb_vc *vcp;
499
struct smb_rq rq, *rqp = &rq;
500
struct mbchain *mbp;
501
char *pp, *pbuf, *encpass;
502
int error, plen, caseopt, upper;
503
504
upper = 0;
505
506
again:
507
/* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */
508
if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) {
509
vcp = SSTOVC(ssp);
510
vcp->vc_toserver = vcp->vc_cp_toserver;
511
vcp->vc_tolocal = vcp->vc_cp_tolocal;
512
vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
513
}
514
515
ssp->ss_tid = SMB_TID_UNKNOWN;
516
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
517
if (error)
518
return error;
519
vcp = rqp->sr_vc;
520
caseopt = SMB_CS_NONE;
521
if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
522
plen = 1;
523
pp = "";
524
pbuf = NULL;
525
encpass = NULL;
526
} else {
527
pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
528
encpass = malloc(24, M_SMBTEMP, M_WAITOK);
529
/*
530
* We try w/o uppercasing first so Samba mixed case
531
* passwords work. If that fails we come back and try
532
* uppercasing to satisfy OS/2 and Windows for Workgroups.
533
*/
534
if (upper++) {
535
iconv_convstr(vcp->vc_toupper, pbuf,
536
smb_share_getpass(ssp)/*,
537
SMB_MAXPASSWORDLEN*/);
538
} else {
539
strncpy(pbuf, smb_share_getpass(ssp),
540
SMB_MAXPASSWORDLEN);
541
pbuf[SMB_MAXPASSWORDLEN] = '\0';
542
}
543
if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
544
plen = 24;
545
smb_encrypt(pbuf, vcp->vc_ch, encpass);
546
pp = encpass;
547
} else {
548
plen = strlen(pbuf) + 1;
549
pp = pbuf;
550
}
551
}
552
mbp = &rqp->sr_rq;
553
smb_rq_wstart(rqp);
554
mb_put_uint8(mbp, 0xff);
555
mb_put_uint8(mbp, 0);
556
mb_put_uint16le(mbp, 0);
557
mb_put_uint16le(mbp, 0); /* Flags */
558
mb_put_uint16le(mbp, plen);
559
smb_rq_wend(rqp);
560
smb_rq_bstart(rqp);
561
mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
562
smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
563
pp = vcp->vc_srvname;
564
smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
565
smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
566
pp = ssp->ss_name;
567
smb_put_dstring(mbp, vcp, pp, caseopt);
568
pp = smb_share_typename(ssp->ss_type);
569
smb_put_dstring(mbp, vcp, pp, caseopt);
570
smb_rq_bend(rqp);
571
error = smb_rq_simple(rqp);
572
SMBSDEBUG("%d\n", error);
573
if (error)
574
goto bad;
575
ssp->ss_tid = rqp->sr_rptid;
576
ssp->ss_vcgenid = vcp->vc_genid;
577
ssp->ss_flags |= SMBS_CONNECTED;
578
/*
579
* If the server can speak Unicode then switch
580
* our converters to do Unicode <--> Local
581
*/
582
if (vcp->obj.co_flags & SMBV_UNICODE) {
583
vcp->vc_toserver = vcp->vc_ucs_toserver;
584
vcp->vc_tolocal = vcp->vc_ucs_tolocal;
585
vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
586
}
587
bad:
588
if (encpass)
589
free(encpass, M_SMBTEMP);
590
if (pbuf)
591
free(pbuf, M_SMBTEMP);
592
smb_rq_done(rqp);
593
if (error && upper == 1)
594
goto again;
595
return error;
596
}
597
598
int
599
smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
600
{
601
struct smb_rq *rqp;
602
int error;
603
604
if (ssp->ss_tid == SMB_TID_UNKNOWN)
605
return 0;
606
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
607
if (error)
608
return error;
609
smb_rq_wstart(rqp);
610
smb_rq_wend(rqp);
611
smb_rq_bstart(rqp);
612
smb_rq_bend(rqp);
613
error = smb_rq_simple(rqp);
614
SMBSDEBUG("%d\n", error);
615
smb_rq_done(rqp);
616
ssp->ss_tid = SMB_TID_UNKNOWN;
617
return error;
618
}
619
620
static __inline int
621
smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
622
struct uio *uio, struct smb_cred *scred)
623
{
624
struct smb_rq *rqp;
625
struct mbchain *mbp;
626
struct mdchain *mdp;
627
u_int8_t wc;
628
int error;
629
u_int16_t residhi, residlo, off, doff;
630
u_int32_t resid;
631
632
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
633
if (error)
634
return error;
635
smb_rq_getrequest(rqp, &mbp);
636
smb_rq_wstart(rqp);
637
mb_put_uint8(mbp, 0xff); /* no secondary command */
638
mb_put_uint8(mbp, 0); /* MBZ */
639
mb_put_uint16le(mbp, 0); /* offset to secondary */
640
mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
641
mb_put_uint32le(mbp, uio->uio_offset);
642
*len = min(SSTOVC(ssp)->vc_rxmax, *len);
643
mb_put_uint16le(mbp, *len); /* MaxCount */
644
mb_put_uint16le(mbp, *len); /* MinCount (only indicates blocking) */
645
mb_put_uint32le(mbp, (unsigned)*len >> 16); /* MaxCountHigh */
646
mb_put_uint16le(mbp, *len); /* Remaining ("obsolete") */
647
mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */
648
smb_rq_wend(rqp);
649
smb_rq_bstart(rqp);
650
smb_rq_bend(rqp);
651
do {
652
error = smb_rq_simple(rqp);
653
if (error)
654
break;
655
smb_rq_getreply(rqp, &mdp);
656
off = SMB_HDRLEN;
657
md_get_uint8(mdp, &wc);
658
off++;
659
if (wc != 12) {
660
error = EBADRPC;
661
break;
662
}
663
md_get_uint8(mdp, NULL);
664
off++;
665
md_get_uint8(mdp, NULL);
666
off++;
667
md_get_uint16le(mdp, NULL);
668
off += 2;
669
md_get_uint16le(mdp, NULL);
670
off += 2;
671
md_get_uint16le(mdp, NULL); /* data compaction mode */
672
off += 2;
673
md_get_uint16le(mdp, NULL);
674
off += 2;
675
md_get_uint16le(mdp, &residlo);
676
off += 2;
677
md_get_uint16le(mdp, &doff); /* data offset */
678
off += 2;
679
md_get_uint16le(mdp, &residhi);
680
off += 2;
681
resid = (residhi << 16) | residlo;
682
md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
683
off += 4*2;
684
md_get_uint16le(mdp, NULL); /* ByteCount */
685
off += 2;
686
if (doff > off) /* pad byte(s)? */
687
md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
688
if (resid == 0) {
689
*rresid = resid;
690
break;
691
}
692
error = md_get_uio(mdp, uio, resid);
693
if (error)
694
break;
695
*rresid = resid;
696
} while(0);
697
smb_rq_done(rqp);
698
return (error);
699
}
700
701
static __inline int
702
smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
703
struct uio *uio, struct smb_cred *scred)
704
{
705
struct smb_rq *rqp;
706
struct mbchain *mbp;
707
struct mdchain *mdp;
708
int error;
709
u_int8_t wc;
710
u_int16_t resid;
711
712
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
713
if (error)
714
return (error);
715
smb_rq_getrequest(rqp, &mbp);
716
smb_rq_wstart(rqp);
717
mb_put_uint8(mbp, 0xff); /* no secondary command */
718
mb_put_uint8(mbp, 0); /* MBZ */
719
mb_put_uint16le(mbp, 0); /* offset to secondary */
720
mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
721
mb_put_uint32le(mbp, uio->uio_offset);
722
mb_put_uint32le(mbp, 0); /* MBZ (timeout) */
723
mb_put_uint16le(mbp, 0); /* !write-thru */
724
mb_put_uint16le(mbp, 0);
725
*len = min(SSTOVC(ssp)->vc_wxmax, *len);
726
mb_put_uint16le(mbp, (unsigned)*len >> 16);
727
mb_put_uint16le(mbp, *len);
728
mb_put_uint16le(mbp, 64); /* data offset from header start */
729
mb_put_uint32le(mbp, uio->uio_offset >> 32); /* OffsetHigh */
730
smb_rq_wend(rqp);
731
smb_rq_bstart(rqp);
732
do {
733
mb_put_uint8(mbp, 0xee); /* mimic xp pad byte! */
734
error = mb_put_uio(mbp, uio, *len);
735
if (error)
736
break;
737
smb_rq_bend(rqp);
738
error = smb_rq_simple(rqp);
739
if (error)
740
break;
741
smb_rq_getreply(rqp, &mdp);
742
md_get_uint8(mdp, &wc);
743
if (wc != 6) {
744
error = EBADRPC;
745
break;
746
}
747
md_get_uint8(mdp, NULL);
748
md_get_uint8(mdp, NULL);
749
md_get_uint16le(mdp, NULL);
750
md_get_uint16le(mdp, &resid);
751
*rresid = resid;
752
} while(0);
753
754
smb_rq_done(rqp);
755
return (error);
756
}
757
758
static __inline int
759
smb_smb_read(struct smb_share *ssp, u_int16_t fid,
760
int *len, int *rresid, struct uio *uio, struct smb_cred *scred)
761
{
762
struct smb_rq *rqp;
763
struct mbchain *mbp;
764
struct mdchain *mdp;
765
u_int16_t resid, bc;
766
u_int8_t wc;
767
int error, rlen, blksz;
768
769
if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
770
return (smb_smb_readx(ssp, fid, len, rresid, uio, scred));
771
772
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
773
if (error)
774
return error;
775
776
blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
777
rlen = *len = min(blksz, *len);
778
779
smb_rq_getrequest(rqp, &mbp);
780
smb_rq_wstart(rqp);
781
mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
782
mb_put_uint16le(mbp, rlen);
783
mb_put_uint32le(mbp, uio->uio_offset);
784
mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
785
smb_rq_wend(rqp);
786
smb_rq_bstart(rqp);
787
smb_rq_bend(rqp);
788
do {
789
error = smb_rq_simple(rqp);
790
if (error)
791
break;
792
smb_rq_getreply(rqp, &mdp);
793
md_get_uint8(mdp, &wc);
794
if (wc != 5) {
795
error = EBADRPC;
796
break;
797
}
798
md_get_uint16le(mdp, &resid);
799
md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
800
md_get_uint16le(mdp, &bc);
801
md_get_uint8(mdp, NULL); /* ignore buffer type */
802
md_get_uint16le(mdp, &resid);
803
if (resid == 0) {
804
*rresid = resid;
805
break;
806
}
807
error = md_get_uio(mdp, uio, resid);
808
if (error)
809
break;
810
*rresid = resid;
811
} while(0);
812
smb_rq_done(rqp);
813
return error;
814
}
815
816
int
817
smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
818
struct smb_cred *scred)
819
{
820
int tsize, len, resid;
821
int error = 0;
822
823
tsize = uio->uio_resid;
824
while (tsize > 0) {
825
resid = 0;
826
len = tsize;
827
error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
828
if (error)
829
break;
830
tsize -= resid;
831
if (resid < len)
832
break;
833
}
834
return error;
835
}
836
837
static __inline int
838
smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
839
struct uio *uio, struct smb_cred *scred)
840
{
841
struct smb_rq *rqp;
842
struct mbchain *mbp;
843
struct mdchain *mdp;
844
u_int16_t resid;
845
u_int8_t wc;
846
int error, blksz;
847
848
if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
849
return (smb_smb_writex(ssp, fid, len, rresid, uio, scred));
850
851
blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
852
if (blksz > 0xffff)
853
blksz = 0xffff;
854
855
resid = *len = min(blksz, *len);
856
857
error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
858
if (error)
859
return error;
860
smb_rq_getrequest(rqp, &mbp);
861
smb_rq_wstart(rqp);
862
mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
863
mb_put_uint16le(mbp, resid);
864
mb_put_uint32le(mbp, uio->uio_offset);
865
mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
866
smb_rq_wend(rqp);
867
smb_rq_bstart(rqp);
868
mb_put_uint8(mbp, SMB_DT_DATA);
869
mb_put_uint16le(mbp, resid);
870
do {
871
error = mb_put_uio(mbp, uio, resid);
872
if (error)
873
break;
874
smb_rq_bend(rqp);
875
error = smb_rq_simple(rqp);
876
if (error)
877
break;
878
smb_rq_getreply(rqp, &mdp);
879
md_get_uint8(mdp, &wc);
880
if (wc != 1) {
881
error = EBADRPC;
882
break;
883
}
884
md_get_uint16le(mdp, &resid);
885
*rresid = resid;
886
} while(0);
887
smb_rq_done(rqp);
888
return error;
889
}
890
891
int
892
smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
893
struct smb_cred *scred)
894
{
895
int error = 0, len, tsize, resid;
896
struct uio olduio;
897
898
tsize = uio->uio_resid;
899
olduio = *uio;
900
while (tsize > 0) {
901
resid = 0;
902
len = tsize;
903
error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
904
if (error)
905
break;
906
if (resid < len) {
907
error = EIO;
908
break;
909
}
910
tsize -= resid;
911
}
912
if (error) {
913
/*
914
* Errors can happen on the copyin, the rpc, etc. So they
915
* imply resid is unreliable. The only safe thing is
916
* to pretend zero bytes made it. We needn't restore the
917
* iovs because callers don't depend on them in error
918
* paths - uio_resid and uio_offset are what matter.
919
*/
920
*uio = olduio;
921
}
922
return error;
923
}
924
925
int
926
smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
927
{
928
struct smb_rq *rqp;
929
struct mbchain *mbp;
930
int error;
931
932
error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
933
if (error)
934
return error;
935
mbp = &rqp->sr_rq;
936
smb_rq_wstart(rqp);
937
mb_put_uint16le(mbp, 1);
938
smb_rq_wend(rqp);
939
smb_rq_bstart(rqp);
940
mb_put_uint32le(mbp, 0);
941
smb_rq_bend(rqp);
942
error = smb_rq_simple(rqp);
943
SMBSDEBUG("%d\n", error);
944
smb_rq_done(rqp);
945
return error;
946
}
947
948