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