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