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