]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netsmb/smb_smb.c
Merge from stable/11:
[FreeBSD/FreeBSD.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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * various SMB requests. Most of the routines merely packs data into mbufs.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
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         struct mbchain *mbp;
604         int error;
605
606         if (ssp->ss_tid == SMB_TID_UNKNOWN)
607                 return 0;
608         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
609         if (error)
610                 return error;
611         mbp = &rqp->sr_rq;
612         smb_rq_wstart(rqp);
613         smb_rq_wend(rqp);
614         smb_rq_bstart(rqp);
615         smb_rq_bend(rqp);
616         error = smb_rq_simple(rqp);
617         SMBSDEBUG("%d\n", error);
618         smb_rq_done(rqp);
619         ssp->ss_tid = SMB_TID_UNKNOWN;
620         return error;
621 }
622
623 static __inline int
624 smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
625               struct uio *uio, struct smb_cred *scred)
626 {
627         struct smb_rq *rqp;
628         struct mbchain *mbp;
629         struct mdchain *mdp;
630         u_int8_t wc;
631         int error;
632         u_int16_t residhi, residlo, off, doff;
633         u_int32_t resid;
634
635         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
636         if (error)
637                 return error;
638         smb_rq_getrequest(rqp, &mbp);
639         smb_rq_wstart(rqp);
640         mb_put_uint8(mbp, 0xff);        /* no secondary command */
641         mb_put_uint8(mbp, 0);           /* MBZ */
642         mb_put_uint16le(mbp, 0);        /* offset to secondary */
643         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
644         mb_put_uint32le(mbp, uio->uio_offset);
645         *len = min(SSTOVC(ssp)->vc_rxmax, *len);
646         mb_put_uint16le(mbp, *len);     /* MaxCount */
647         mb_put_uint16le(mbp, *len);     /* MinCount (only indicates blocking) */
648         mb_put_uint32le(mbp, (unsigned)*len >> 16);     /* MaxCountHigh */
649         mb_put_uint16le(mbp, *len);     /* Remaining ("obsolete") */
650         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
651         smb_rq_wend(rqp);
652         smb_rq_bstart(rqp);
653         smb_rq_bend(rqp);
654         do {
655                 error = smb_rq_simple(rqp);
656                 if (error)
657                         break;
658                 smb_rq_getreply(rqp, &mdp);
659                 off = SMB_HDRLEN;
660                 md_get_uint8(mdp, &wc);
661                 off++;
662                 if (wc != 12) {
663                         error = EBADRPC;
664                         break;
665                 }
666                 md_get_uint8(mdp, NULL);
667                 off++;
668                 md_get_uint8(mdp, NULL);
669                 off++;
670                 md_get_uint16le(mdp, NULL);
671                 off += 2;
672                 md_get_uint16le(mdp, NULL);
673                 off += 2;
674                 md_get_uint16le(mdp, NULL);     /* data compaction mode */
675                 off += 2;
676                 md_get_uint16le(mdp, NULL);
677                 off += 2;
678                 md_get_uint16le(mdp, &residlo);
679                 off += 2;
680                 md_get_uint16le(mdp, &doff);    /* data offset */
681                 off += 2;
682                 md_get_uint16le(mdp, &residhi);
683                 off += 2;
684                 resid = (residhi << 16) | residlo;
685                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
686                 off += 4*2;
687                 md_get_uint16le(mdp, NULL);     /* ByteCount */
688                 off += 2;
689                 if (doff > off) /* pad byte(s)? */
690                         md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
691                 if (resid == 0) {
692                         *rresid = resid;
693                         break;
694                 }
695                 error = md_get_uio(mdp, uio, resid);
696                 if (error)
697                         break;
698                 *rresid = resid;
699         } while(0);
700         smb_rq_done(rqp);
701         return (error);
702 }
703
704 static __inline int
705 smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
706         struct uio *uio, struct smb_cred *scred)
707 {
708         struct smb_rq *rqp;
709         struct mbchain *mbp;
710         struct mdchain *mdp;
711         int error;
712         u_int8_t wc;
713         u_int16_t resid;
714
715         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
716         if (error)
717                 return (error);
718         smb_rq_getrequest(rqp, &mbp);
719         smb_rq_wstart(rqp);
720         mb_put_uint8(mbp, 0xff);        /* no secondary command */
721         mb_put_uint8(mbp, 0);           /* MBZ */
722         mb_put_uint16le(mbp, 0);        /* offset to secondary */
723         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
724         mb_put_uint32le(mbp, uio->uio_offset);
725         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
726         mb_put_uint16le(mbp, 0);        /* !write-thru */
727         mb_put_uint16le(mbp, 0);
728         *len = min(SSTOVC(ssp)->vc_wxmax, *len);
729         mb_put_uint16le(mbp, (unsigned)*len >> 16);
730         mb_put_uint16le(mbp, *len);
731         mb_put_uint16le(mbp, 64);       /* data offset from header start */
732         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
733         smb_rq_wend(rqp);
734         smb_rq_bstart(rqp);
735         do {
736                 mb_put_uint8(mbp, 0xee);        /* mimic xp pad byte! */
737                 error = mb_put_uio(mbp, uio, *len);
738                 if (error)
739                         break;
740                 smb_rq_bend(rqp);
741                 error = smb_rq_simple(rqp);
742                 if (error)
743                         break;
744                 smb_rq_getreply(rqp, &mdp);
745                 md_get_uint8(mdp, &wc);
746                 if (wc != 6) {
747                         error = EBADRPC;
748                         break;
749                 }
750                 md_get_uint8(mdp, NULL);
751                 md_get_uint8(mdp, NULL);
752                 md_get_uint16le(mdp, NULL);
753                 md_get_uint16le(mdp, &resid);
754                 *rresid = resid;
755         } while(0);
756
757         smb_rq_done(rqp);
758         return (error);
759 }
760
761 static __inline int
762 smb_smb_read(struct smb_share *ssp, u_int16_t fid,
763         int *len, int *rresid, struct uio *uio, struct smb_cred *scred)
764 {
765         struct smb_rq *rqp;
766         struct mbchain *mbp;
767         struct mdchain *mdp;
768         u_int16_t resid, bc;
769         u_int8_t wc;
770         int error, rlen, blksz;
771
772         if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
773                 return (smb_smb_readx(ssp, fid, len, rresid, uio, scred));
774
775         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
776         if (error)
777                 return error;
778
779         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
780         rlen = *len = min(blksz, *len);
781
782         smb_rq_getrequest(rqp, &mbp);
783         smb_rq_wstart(rqp);
784         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
785         mb_put_uint16le(mbp, rlen);
786         mb_put_uint32le(mbp, uio->uio_offset);
787         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
788         smb_rq_wend(rqp);
789         smb_rq_bstart(rqp);
790         smb_rq_bend(rqp);
791         do {
792                 error = smb_rq_simple(rqp);
793                 if (error)
794                         break;
795                 smb_rq_getreply(rqp, &mdp);
796                 md_get_uint8(mdp, &wc);
797                 if (wc != 5) {
798                         error = EBADRPC;
799                         break;
800                 }
801                 md_get_uint16le(mdp, &resid);
802                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
803                 md_get_uint16le(mdp, &bc);
804                 md_get_uint8(mdp, NULL);                /* ignore buffer type */
805                 md_get_uint16le(mdp, &resid);
806                 if (resid == 0) {
807                         *rresid = resid;
808                         break;
809                 }
810                 error = md_get_uio(mdp, uio, resid);
811                 if (error)
812                         break;
813                 *rresid = resid;
814         } while(0);
815         smb_rq_done(rqp);
816         return error;
817 }
818
819 int
820 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
821         struct smb_cred *scred)
822 {
823         int tsize, len, resid;
824         int error = 0;
825
826         tsize = uio->uio_resid;
827         while (tsize > 0) {
828                 resid = 0;
829                 len = tsize;
830                 error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
831                 if (error)
832                         break;
833                 tsize -= resid;
834                 if (resid < len)
835                         break;
836         }
837         return error;
838 }
839
840 static __inline int
841 smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
842         struct uio *uio, struct smb_cred *scred)
843 {
844         struct smb_rq *rqp;
845         struct mbchain *mbp;
846         struct mdchain *mdp;
847         u_int16_t resid;
848         u_int8_t wc;
849         int error, blksz;
850
851         if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
852                 return (smb_smb_writex(ssp, fid, len, rresid, uio, scred));
853  
854         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
855         if (blksz > 0xffff)
856                 blksz = 0xffff;
857
858         resid = *len = min(blksz, *len);
859
860         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
861         if (error)
862                 return error;
863         smb_rq_getrequest(rqp, &mbp);
864         smb_rq_wstart(rqp);
865         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
866         mb_put_uint16le(mbp, resid);
867         mb_put_uint32le(mbp, uio->uio_offset);
868         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
869         smb_rq_wend(rqp);
870         smb_rq_bstart(rqp);
871         mb_put_uint8(mbp, SMB_DT_DATA);
872         mb_put_uint16le(mbp, resid);
873         do {
874                 error = mb_put_uio(mbp, uio, resid);
875                 if (error)
876                         break;
877                 smb_rq_bend(rqp);
878                 error = smb_rq_simple(rqp);
879                 if (error)
880                         break;
881                 smb_rq_getreply(rqp, &mdp);
882                 md_get_uint8(mdp, &wc);
883                 if (wc != 1) {
884                         error = EBADRPC;
885                         break;
886                 }
887                 md_get_uint16le(mdp, &resid);
888                 *rresid = resid;
889         } while(0);
890         smb_rq_done(rqp);
891         return error;
892 }
893
894 int
895 smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
896         struct smb_cred *scred)
897 {
898         int error = 0, len, tsize, resid;
899         struct uio olduio;
900
901         tsize = uio->uio_resid;
902         olduio = *uio;
903         while (tsize > 0) {
904                 resid = 0;
905                 len = tsize;
906                 error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
907                 if (error)
908                         break;
909                 if (resid < len) {
910                         error = EIO;
911                         break;
912                 }
913                 tsize -= resid;
914         }
915         if (error) {
916                 /*
917                  * Errors can happen on the copyin, the rpc, etc.  So they
918                  * imply resid is unreliable.  The only safe thing is
919                  * to pretend zero bytes made it.  We needn't restore the
920                  * iovs because callers don't depend on them in error
921                  * paths - uio_resid and uio_offset are what matter.
922                  */
923                 *uio = olduio;
924         }
925         return error;
926 }
927
928 int
929 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
930 {
931         struct smb_rq *rqp;
932         struct mbchain *mbp;
933         int error;
934
935         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
936         if (error)
937                 return error;
938         mbp = &rqp->sr_rq;
939         smb_rq_wstart(rqp);
940         mb_put_uint16le(mbp, 1);
941         smb_rq_wend(rqp);
942         smb_rq_bstart(rqp);
943         mb_put_uint32le(mbp, 0);
944         smb_rq_bend(rqp);
945         error = smb_rq_simple(rqp);
946         SMBSDEBUG("%d\n", error);
947         smb_rq_done(rqp);
948         return error;
949 }