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