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