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