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