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