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