]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/netsmb/smb_smb.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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                         if (sp->sv_sm & SMB_SM_SIGS_REQUIRE)
201                                 vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
202                         vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
203                         if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
204                             sp->sv_maxtx < 4096 &&
205                             (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
206                                 vcp->obj.co_flags |= SMBV_WIN95;
207                                 SMBSDEBUG("Win95 detected\n");
208                         }
209                 } else if (dp->d_id > SMB_DIALECT_CORE) {
210                         md_get_uint16le(mdp, &tw);
211                         sp->sv_sm = tw;
212                         md_get_uint16le(mdp, &tw);
213                         sp->sv_maxtx = tw;
214                         md_get_uint16le(mdp, &sp->sv_maxmux);
215                         md_get_uint16le(mdp, &sp->sv_maxvcs);
216                         md_get_uint16le(mdp, &tw);      /* rawmode */
217                         md_get_uint32le(mdp, &sp->sv_skey);
218                         if (wc == 13) {         /* >= LANMAN1 */
219                                 md_get_uint16(mdp, &tw);                /* time */
220                                 md_get_uint16(mdp, &tw1);               /* date */
221                                 md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
222                                 md_get_uint16le(mdp, &swlen);
223                                 if (swlen > SMB_MAXCHALLENGELEN)
224                                         break;
225                                 md_get_uint16(mdp, NULL);       /* mbz */
226                                 if (md_get_uint16(mdp, &bc) != 0)
227                                         break;
228                                 if (bc < swlen)
229                                         break;
230                                 if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
231                                         error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM);
232                                         if (error)
233                                                 break;
234                                         vcp->vc_chlen = swlen;
235                                         vcp->obj.co_flags |= SMBV_ENCRYPT;
236                                 }
237                         }
238                         vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
239                 } else {        /* an old CORE protocol */
240                         sp->sv_maxmux = 1;
241                 }
242                 error = 0;
243         } while (0);
244         if (error == 0) {
245                 vcp->vc_maxvcs = sp->sv_maxvcs;
246                 if (vcp->vc_maxvcs <= 1) {
247                         if (vcp->vc_maxvcs == 0)
248                                 vcp->vc_maxvcs = 1;
249                 }
250                 if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff)
251                         sp->sv_maxtx = 1024;
252                 else
253                         sp->sv_maxtx = min(sp->sv_maxtx,
254                                            63*1024 + SMB_HDRLEN + 16);
255                 SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz);
256                 vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024);
257                 SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz);
258                 vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024);
259                 vcp->vc_txmax = min(sp->sv_maxtx, maxqsz);
260                 SMBSDEBUG("TZ = %d\n", sp->sv_tz);
261                 SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
262                 SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux);
263                 SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs);
264                 SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw);
265                 SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx);
266         }
267 bad:
268         smb_rq_done(rqp);
269         return error;
270 }
271
272 int
273 smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
274 {
275         struct smb_rq *rqp;
276         struct mbchain *mbp;
277 /*      u_int8_t wc;
278         u_int16_t tw, tw1;*/
279         smb_uniptr unipp, ntencpass = NULL;
280         char *pp, *up, *pbuf, *encpass;
281         int error, plen, uniplen, ulen, upper;
282
283         upper = 0;
284
285 again:
286
287         vcp->vc_smbuid = SMB_UID_UNKNOWN;
288
289         if (smb_smb_nomux(vcp, scred, __func__) != 0)
290                 return EINVAL;
291
292         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
293         if (error)
294                 return error;
295         pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
296         encpass = malloc(24, M_SMBTEMP, M_WAITOK);
297         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
298                 /*
299                  * We try w/o uppercasing first so Samba mixed case
300                  * passwords work.  If that fails we come back and try
301                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
302                  */
303                 if (upper++) {
304                         iconv_convstr(vcp->vc_toupper, pbuf,
305                                       smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/);
306                 } else {
307                         strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
308                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
309                 }
310                 if (!SMB_UNICODE_STRINGS(vcp))
311                         iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*,
312                                       SMB_MAXPASSWORDLEN*/);
313
314                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
315                         uniplen = plen = 24;
316                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
317                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
318                         if (SMB_UNICODE_STRINGS(vcp)) {
319                                 strncpy(pbuf, smb_vc_getpass(vcp),
320                                         SMB_MAXPASSWORDLEN);
321                                 pbuf[SMB_MAXPASSWORDLEN] = '\0';
322                         } else
323                                 iconv_convstr(vcp->vc_toserver, pbuf,
324                                               smb_vc_getpass(vcp)/*,
325                                               SMB_MAXPASSWORDLEN*/);
326                         smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
327                         pp = encpass;
328                         unipp = ntencpass;
329                 } else {
330                         plen = strlen(pbuf) + 1;
331                         pp = pbuf;
332                         uniplen = plen * 2;
333                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
334                         smb_strtouni(ntencpass, smb_vc_getpass(vcp));
335                         plen--;
336
337                         /*
338                          * The uniplen is zeroed because Samba cannot deal
339                          * with this 2nd cleartext password.  This Samba
340                          * "bug" is actually a workaround for problems in
341                          * Microsoft clients.
342                          */
343                         uniplen = 0/*-= 2*/;
344                         unipp = ntencpass;
345                 }
346         } else {
347                 /*
348                  * In the share security mode password will be used
349                  * only in the tree authentication
350                  */
351                  pp = "";
352                  plen = 1;
353                  unipp = &smb_unieol;
354                  uniplen = 0 /* sizeof(smb_unieol) */;
355         }
356         smb_rq_wstart(rqp);
357         mbp = &rqp->sr_rq;
358         up = vcp->vc_username;
359         ulen = strlen(up) + 1;
360         /*
361          * If userid is null we are attempting anonymous browse login
362          * so passwords must be zero length.
363          */
364         if (ulen == 1)
365                 plen = uniplen = 0;
366         mb_put_uint8(mbp, 0xff);
367         mb_put_uint8(mbp, 0);
368         mb_put_uint16le(mbp, 0);
369         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
370         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
371         mb_put_uint16le(mbp, vcp->vc_number);
372         mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
373         mb_put_uint16le(mbp, plen);
374         if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
375                 mb_put_uint32le(mbp, 0);
376                 smb_rq_wend(rqp);
377                 smb_rq_bstart(rqp);
378                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
379                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
380         } else {
381                 mb_put_uint16le(mbp, uniplen);
382                 mb_put_uint32le(mbp, 0);                /* reserved */
383                 mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ?
384                                      SMB_CAP_UNICODE : 0);
385                 smb_rq_wend(rqp);
386                 smb_rq_bstart(rqp);
387                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
388                 mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
389                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);             /* AccountName */
390                 smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */
391                 smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE);      /* Client's OS */
392                 smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE);               /* Client name */
393         }
394         smb_rq_bend(rqp);
395         if (ntencpass)
396                 free(ntencpass, M_SMBTEMP);
397         if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
398                 smb_calcmackey(vcp);
399         error = smb_rq_simple(rqp);
400         SMBSDEBUG("%d\n", error);
401         if (error) {
402                 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess)
403                         error = EAUTH;
404                 goto bad;
405         }
406         vcp->vc_smbuid = rqp->sr_rpuid;
407 bad:
408         free(encpass, M_SMBTEMP);
409         free(pbuf, M_SMBTEMP);
410         smb_rq_done(rqp);
411         if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER)
412                 goto again;
413         return error;
414 }
415
416 int
417 smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
418 {
419         struct smb_rq *rqp;
420         struct mbchain *mbp;
421         int error;
422
423         if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
424                 return 0;
425
426         if (smb_smb_nomux(vcp, scred, __func__) != 0)
427                 return EINVAL;
428
429         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
430         if (error)
431                 return error;
432         mbp = &rqp->sr_rq;
433         smb_rq_wstart(rqp);
434         mb_put_uint8(mbp, 0xff);
435         mb_put_uint8(mbp, 0);
436         mb_put_uint16le(mbp, 0);
437         smb_rq_wend(rqp);
438         smb_rq_bstart(rqp);
439         smb_rq_bend(rqp);
440         error = smb_rq_simple(rqp);
441         SMBSDEBUG("%d\n", error);
442         smb_rq_done(rqp);
443         return error;
444 }
445
446 static char smb_any_share[] = "?????";
447
448 static char *
449 smb_share_typename(int stype)
450 {
451         char *pp;
452
453         switch (stype) {
454             case SMB_ST_DISK:
455                 pp = "A:";
456                 break;
457             case SMB_ST_PRINTER:
458                 pp = smb_any_share;             /* can't use LPT: here... */
459                 break;
460             case SMB_ST_PIPE:
461                 pp = "IPC";
462                 break;
463             case SMB_ST_COMM:
464                 pp = "COMM";
465                 break;
466             case SMB_ST_ANY:
467             default:
468                 pp = smb_any_share;
469                 break;
470         }
471         return pp;
472 }
473
474 int
475 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
476 {
477         struct smb_vc *vcp;
478         struct smb_rq rq, *rqp = &rq;
479         struct mbchain *mbp;
480         char *pp, *pbuf, *encpass;
481         int error, plen, caseopt, upper;
482
483         upper = 0;
484
485 again:
486
487 #if 0
488         /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */
489         if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) {
490                 vcp = SSTOVC(ssp);
491                 if (vcp->vc_toserver) {
492                         iconv_close(vcp->vc_toserver);
493                         /* Use NULL until UTF-8 -> ASCII works */
494                         vcp->vc_toserver = NULL;
495                 }
496                 if (vcp->vc_tolocal) {
497                         iconv_close(vcp->vc_tolocal);
498                         /* Use NULL until ASCII -> UTF-8 works*/
499                         vcp->vc_tolocal = NULL;
500                 }
501                 vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
502         }
503 #endif
504
505         ssp->ss_tid = SMB_TID_UNKNOWN;
506         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
507         if (error)
508                 return error;
509         vcp = rqp->sr_vc;
510         caseopt = SMB_CS_NONE;
511         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
512                 plen = 1;
513                 pp = "";
514                 pbuf = NULL;
515                 encpass = NULL;
516         } else {
517                 pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
518                 encpass = malloc(24, M_SMBTEMP, M_WAITOK);
519                 /*
520                  * We try w/o uppercasing first so Samba mixed case
521                  * passwords work.  If that fails we come back and try
522                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
523                  */
524                 if (upper++) {
525                         iconv_convstr(vcp->vc_toupper, pbuf,
526                                       smb_share_getpass(ssp)/*,
527                                       SMB_MAXPASSWORDLEN*/);
528                 } else {
529                         strncpy(pbuf, smb_share_getpass(ssp),
530                                 SMB_MAXPASSWORDLEN);
531                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
532                 }
533                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
534                         plen = 24;
535                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
536                         pp = encpass;
537                 } else {
538                         plen = strlen(pbuf) + 1;
539                         pp = pbuf;
540                 }
541         }
542         mbp = &rqp->sr_rq;
543         smb_rq_wstart(rqp);
544         mb_put_uint8(mbp, 0xff);
545         mb_put_uint8(mbp, 0);
546         mb_put_uint16le(mbp, 0);
547         mb_put_uint16le(mbp, 0);                /* Flags */
548         mb_put_uint16le(mbp, plen);
549         smb_rq_wend(rqp);
550         smb_rq_bstart(rqp);
551         mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
552         smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
553         pp = vcp->vc_srvname;
554         smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
555         smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
556         pp = ssp->ss_name;
557         smb_put_dstring(mbp, vcp, pp, caseopt);
558         pp = smb_share_typename(ssp->ss_type);
559         smb_put_dstring(mbp, vcp, pp, caseopt);
560         smb_rq_bend(rqp);
561         error = smb_rq_simple(rqp);
562         SMBSDEBUG("%d\n", error);
563         if (error)
564                 goto bad;
565         ssp->ss_tid = rqp->sr_rptid;
566         ssp->ss_vcgenid = vcp->vc_genid;
567         ssp->ss_flags |= SMBS_CONNECTED;
568 bad:
569         if (encpass)
570                 free(encpass, M_SMBTEMP);
571         if (pbuf)
572                 free(pbuf, M_SMBTEMP);
573         smb_rq_done(rqp);
574         if (error && upper == 1)
575                 goto again;
576         return error;
577 }
578
579 int
580 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
581 {
582         struct smb_rq *rqp;
583         struct mbchain *mbp;
584         int error;
585
586         if (ssp->ss_tid == SMB_TID_UNKNOWN)
587                 return 0;
588         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
589         if (error)
590                 return error;
591         mbp = &rqp->sr_rq;
592         smb_rq_wstart(rqp);
593         smb_rq_wend(rqp);
594         smb_rq_bstart(rqp);
595         smb_rq_bend(rqp);
596         error = smb_rq_simple(rqp);
597         SMBSDEBUG("%d\n", error);
598         smb_rq_done(rqp);
599         ssp->ss_tid = SMB_TID_UNKNOWN;
600         return error;
601 }
602
603 static __inline int
604 smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
605               struct uio *uio, struct smb_cred *scred)
606 {
607         struct smb_rq *rqp;
608         struct mbchain *mbp;
609         struct mdchain *mdp;
610         u_int8_t wc;
611         int error;
612         u_int16_t residhi, residlo, off, doff;
613         u_int32_t resid;
614
615         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
616         if (error)
617                 return error;
618         smb_rq_getrequest(rqp, &mbp);
619         smb_rq_wstart(rqp);
620         mb_put_uint8(mbp, 0xff);        /* no secondary command */
621         mb_put_uint8(mbp, 0);           /* MBZ */
622         mb_put_uint16le(mbp, 0);        /* offset to secondary */
623         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
624         mb_put_uint32le(mbp, uio->uio_offset);
625         *len = min(SSTOVC(ssp)->vc_rxmax, *len);
626         mb_put_uint16le(mbp, *len);     /* MaxCount */
627         mb_put_uint16le(mbp, *len);     /* MinCount (only indicates blocking) */
628         mb_put_uint32le(mbp, (unsigned)*len >> 16);     /* MaxCountHigh */
629         mb_put_uint16le(mbp, *len);     /* Remaining ("obsolete") */
630         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
631         smb_rq_wend(rqp);
632         smb_rq_bstart(rqp);
633         smb_rq_bend(rqp);
634         do {
635                 error = smb_rq_simple(rqp);
636                 if (error)
637                         break;
638                 smb_rq_getreply(rqp, &mdp);
639                 off = SMB_HDRLEN;
640                 md_get_uint8(mdp, &wc);
641                 off++;
642                 if (wc != 12) {
643                         error = EBADRPC;
644                         break;
645                 }
646                 md_get_uint8(mdp, NULL);
647                 off++;
648                 md_get_uint8(mdp, NULL);
649                 off++;
650                 md_get_uint16le(mdp, NULL);
651                 off += 2;
652                 md_get_uint16le(mdp, NULL);
653                 off += 2;
654                 md_get_uint16le(mdp, NULL);     /* data compaction mode */
655                 off += 2;
656                 md_get_uint16le(mdp, NULL);
657                 off += 2;
658                 md_get_uint16le(mdp, &residlo);
659                 off += 2;
660                 md_get_uint16le(mdp, &doff);    /* data offset */
661                 off += 2;
662                 md_get_uint16le(mdp, &residhi);
663                 off += 2;
664                 resid = (residhi << 16) | residlo;
665                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
666                 off += 4*2;
667                 md_get_uint16le(mdp, NULL);     /* ByteCount */
668                 off += 2;
669                 if (doff > off) /* pad byte(s)? */
670                         md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
671                 if (resid == 0) {
672                         *rresid = resid;
673                         break;
674                 }
675                 error = md_get_uio(mdp, uio, resid);
676                 if (error)
677                         break;
678                 *rresid = resid;
679         } while(0);
680         smb_rq_done(rqp);
681         return (error);
682 }
683
684 static __inline int
685 smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
686         struct uio *uio, struct smb_cred *scred)
687 {
688         struct smb_rq *rqp;
689         struct mbchain *mbp;
690         struct mdchain *mdp;
691         int error;
692         u_int8_t wc;
693         u_int16_t resid;
694
695         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
696         if (error)
697                 return (error);
698         smb_rq_getrequest(rqp, &mbp);
699         smb_rq_wstart(rqp);
700         mb_put_uint8(mbp, 0xff);        /* no secondary command */
701         mb_put_uint8(mbp, 0);           /* MBZ */
702         mb_put_uint16le(mbp, 0);        /* offset to secondary */
703         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
704         mb_put_uint32le(mbp, uio->uio_offset);
705         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
706         mb_put_uint16le(mbp, 0);        /* !write-thru */
707         mb_put_uint16le(mbp, 0);
708         *len = min(SSTOVC(ssp)->vc_wxmax, *len);
709         mb_put_uint16le(mbp, (unsigned)*len >> 16);
710         mb_put_uint16le(mbp, *len);
711         mb_put_uint16le(mbp, 64);       /* data offset from header start */
712         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
713         smb_rq_wend(rqp);
714         smb_rq_bstart(rqp);
715         do {
716                 mb_put_uint8(mbp, 0xee);        /* mimic xp pad byte! */
717                 error = mb_put_uio(mbp, uio, *len);
718                 if (error)
719                         break;
720                 smb_rq_bend(rqp);
721                 error = smb_rq_simple(rqp);
722                 if (error)
723                         break;
724                 smb_rq_getreply(rqp, &mdp);
725                 md_get_uint8(mdp, &wc);
726                 if (wc != 6) {
727                         error = EBADRPC;
728                         break;
729                 }
730                 md_get_uint8(mdp, NULL);
731                 md_get_uint8(mdp, NULL);
732                 md_get_uint16le(mdp, NULL);
733                 md_get_uint16le(mdp, &resid);
734                 *rresid = resid;
735         } while(0);
736
737         smb_rq_done(rqp);
738         return (error);
739 }
740
741 static __inline int
742 smb_smb_read(struct smb_share *ssp, u_int16_t fid,
743         int *len, int *rresid, struct uio *uio, struct smb_cred *scred)
744 {
745         struct smb_rq *rqp;
746         struct mbchain *mbp;
747         struct mdchain *mdp;
748         u_int16_t resid, bc;
749         u_int8_t wc;
750         int error, rlen, blksz;
751
752         if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
753                 return (smb_smb_readx(ssp, fid, len, rresid, uio, scred));
754
755         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
756         if (error)
757                 return error;
758
759         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
760         rlen = *len = min(blksz, *len);
761
762         smb_rq_getrequest(rqp, &mbp);
763         smb_rq_wstart(rqp);
764         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
765         mb_put_uint16le(mbp, rlen);
766         mb_put_uint32le(mbp, uio->uio_offset);
767         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
768         smb_rq_wend(rqp);
769         smb_rq_bstart(rqp);
770         smb_rq_bend(rqp);
771         do {
772                 error = smb_rq_simple(rqp);
773                 if (error)
774                         break;
775                 smb_rq_getreply(rqp, &mdp);
776                 md_get_uint8(mdp, &wc);
777                 if (wc != 5) {
778                         error = EBADRPC;
779                         break;
780                 }
781                 md_get_uint16le(mdp, &resid);
782                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
783                 md_get_uint16le(mdp, &bc);
784                 md_get_uint8(mdp, NULL);                /* ignore buffer type */
785                 md_get_uint16le(mdp, &resid);
786                 if (resid == 0) {
787                         *rresid = resid;
788                         break;
789                 }
790                 error = md_get_uio(mdp, uio, resid);
791                 if (error)
792                         break;
793                 *rresid = resid;
794         } while(0);
795         smb_rq_done(rqp);
796         return error;
797 }
798
799 int
800 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
801         struct smb_cred *scred)
802 {
803         int tsize, len, resid;
804         int error = 0;
805
806         tsize = uio->uio_resid;
807         while (tsize > 0) {
808                 resid = 0;
809                 len = tsize;
810                 error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
811                 if (error)
812                         break;
813                 tsize -= resid;
814                 if (resid < len)
815                         break;
816         }
817         return error;
818 }
819
820 static __inline int
821 smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
822         struct uio *uio, struct smb_cred *scred)
823 {
824         struct smb_rq *rqp;
825         struct mbchain *mbp;
826         struct mdchain *mdp;
827         u_int16_t resid;
828         u_int8_t wc;
829         int error, blksz;
830
831         if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
832                 return (smb_smb_writex(ssp, fid, len, rresid, uio, scred));
833  
834         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
835         if (blksz > 0xffff)
836                 blksz = 0xffff;
837
838         resid = *len = min(blksz, *len);
839
840         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
841         if (error)
842                 return error;
843         smb_rq_getrequest(rqp, &mbp);
844         smb_rq_wstart(rqp);
845         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
846         mb_put_uint16le(mbp, resid);
847         mb_put_uint32le(mbp, uio->uio_offset);
848         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
849         smb_rq_wend(rqp);
850         smb_rq_bstart(rqp);
851         mb_put_uint8(mbp, SMB_DT_DATA);
852         mb_put_uint16le(mbp, resid);
853         do {
854                 error = mb_put_uio(mbp, uio, resid);
855                 if (error)
856                         break;
857                 smb_rq_bend(rqp);
858                 error = smb_rq_simple(rqp);
859                 if (error)
860                         break;
861                 smb_rq_getreply(rqp, &mdp);
862                 md_get_uint8(mdp, &wc);
863                 if (wc != 1) {
864                         error = EBADRPC;
865                         break;
866                 }
867                 md_get_uint16le(mdp, &resid);
868                 *rresid = resid;
869         } while(0);
870         smb_rq_done(rqp);
871         return error;
872 }
873
874 int
875 smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
876         struct smb_cred *scred)
877 {
878         int error = 0, len, tsize, resid;
879         struct uio olduio;
880
881         tsize = uio->uio_resid;
882         olduio = *uio;
883         while (tsize > 0) {
884                 resid = 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 }