[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netsmb/smb_smb.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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: src/sys/netsmb/smb_smb.c,v 1.15 2007/06/15 23:49:54 mjacob Exp $");
 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 
131         if (smb_smb_nomux(vcp, scred, __func__) != 0)
132                 return EINVAL;
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_uint16(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                         vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
203                         if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
204                             sp->sv_maxtx < 4096 &&
205                             (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
206                                 vcp->obj.co_flags |= SMBV_WIN95;
207                                 SMBSDEBUG("Win95 detected\n");
208                         }
209                 } else if (dp->d_id > SMB_DIALECT_CORE) {
210                         md_get_uint16le(mdp, &tw);
211                         sp->sv_sm = tw;
212                         md_get_uint16le(mdp, &tw);
213                         sp->sv_maxtx = tw;
214                         md_get_uint16le(mdp, &sp->sv_maxmux);
215                         md_get_uint16le(mdp, &sp->sv_maxvcs);
216                         md_get_uint16le(mdp, &tw);      /* rawmode */
217                         md_get_uint32le(mdp, &sp->sv_skey);
218                         if (wc == 13) {         /* >= LANMAN1 */
219                                 md_get_uint16(mdp, &tw);                /* time */
220                                 md_get_uint16(mdp, &tw1);               /* date */
221                                 md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
222                                 md_get_uint16le(mdp, &swlen);
223                                 if (swlen > SMB_MAXCHALLENGELEN)
224                                         break;
225                                 md_get_uint16(mdp, NULL);       /* mbz */
226                                 if (md_get_uint16(mdp, &bc) != 0)
227                                         break;
228                                 if (bc < swlen)
229                                         break;
230                                 if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
231                                         error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM);
232                                         if (error)
233                                                 break;
234                                         vcp->vc_chlen = swlen;
235                                         vcp->obj.co_flags |= SMBV_ENCRYPT;
236                                 }
237                         }
238                         vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
239                 } else {        /* an old CORE protocol */
240                         sp->sv_maxmux = 1;
241                 }
242                 error = 0;
243         } while (0);
244         if (error == 0) {
245                 vcp->vc_maxvcs = sp->sv_maxvcs;
246                 if (vcp->vc_maxvcs <= 1) {
247                         if (vcp->vc_maxvcs == 0)
248                                 vcp->vc_maxvcs = 1;
249                 }
250                 if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff)
251                         sp->sv_maxtx = 1024;
252                 else
253                         sp->sv_maxtx = min(sp->sv_maxtx,
254                                            63*1024 + SMB_HDRLEN + 16);
255                 SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz);
256                 vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024);
257                 SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz);
258                 vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024);
259                 vcp->vc_txmax = min(sp->sv_maxtx, maxqsz);
260                 SMBSDEBUG("TZ = %d\n", sp->sv_tz);
261                 SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
262                 SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux);
263                 SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs);
264                 SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw);
265                 SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx);
266         }
267 bad:
268         smb_rq_done(rqp);
269         return error;
270 }
271 
272 int
273 smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
274 {
275         struct smb_rq *rqp;
276         struct mbchain *mbp;
277 /*      u_int8_t wc;
278         u_int16_t tw, tw1;*/
279         smb_uniptr unipp, ntencpass = NULL;
280         char *pp, *up, *pbuf, *encpass;
281         int error, plen, uniplen, ulen, upper;
282 
283         upper = 0;
284 
285 again:
286 
287         vcp->vc_smbuid = SMB_UID_UNKNOWN;
288 
289         if (smb_smb_nomux(vcp, scred, __func__) != 0)
290                 return EINVAL;
291 
292         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
293         if (error)
294                 return error;
295         pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
296         encpass = malloc(24, M_SMBTEMP, M_WAITOK);
297         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
298                 /*
299                  * We try w/o uppercasing first so Samba mixed case
300                  * passwords work.  If that fails we come back and try
301                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
302                  */
303                 if (upper++) {
304                         iconv_convstr(vcp->vc_toupper, pbuf,
305                                       smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/);
306                 } else {
307                         strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
308                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
309                 }
310                 if (!SMB_UNICODE_STRINGS(vcp))
311                         iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*,
312                                       SMB_MAXPASSWORDLEN*/);
313 
314                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
315                         uniplen = plen = 24;
316                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
317                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
318                         if (SMB_UNICODE_STRINGS(vcp)) {
319                                 strncpy(pbuf, smb_vc_getpass(vcp),
320                                         SMB_MAXPASSWORDLEN);
321                                 pbuf[SMB_MAXPASSWORDLEN] = '\0';
322                         } else
323                                 iconv_convstr(vcp->vc_toserver, pbuf,
324                                               smb_vc_getpass(vcp)/*,
325                                               SMB_MAXPASSWORDLEN*/);
326                         smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
327                         pp = encpass;
328                         unipp = ntencpass;
329                 } else {
330                         plen = strlen(pbuf) + 1;
331                         pp = pbuf;
332                         uniplen = plen * 2;
333                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
334                         smb_strtouni(ntencpass, smb_vc_getpass(vcp));
335                         plen--;
336 
337                         /*
338                          * The uniplen is zeroed because Samba cannot deal
339                          * with this 2nd cleartext password.  This Samba
340                          * "bug" is actually a workaround for problems in
341                          * Microsoft clients.
342                          */
343                         uniplen = 0/*-= 2*/;
344                         unipp = ntencpass;
345                 }
346         } else {
347                 /*
348                  * In the share security mode password will be used
349                  * only in the tree authentication
350                  */
351                  pp = "";
352                  plen = 1;
353                  unipp = &smb_unieol;
354                  uniplen = 0 /* sizeof(smb_unieol) */;
355         }
356         smb_rq_wstart(rqp);
357         mbp = &rqp->sr_rq;
358         up = vcp->vc_username;
359         ulen = strlen(up) + 1;
360         /*
361          * If userid is null we are attempting anonymous browse login
362          * so passwords must be zero length.
363          */
364         if (ulen == 1)
365                 plen = uniplen = 0;
366         mb_put_uint8(mbp, 0xff);
367         mb_put_uint8(mbp, 0);
368         mb_put_uint16le(mbp, 0);
369         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
370         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
371         mb_put_uint16le(mbp, vcp->vc_number);
372         mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
373         mb_put_uint16le(mbp, plen);
374         if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
375                 mb_put_uint32le(mbp, 0);
376                 smb_rq_wend(rqp);
377                 smb_rq_bstart(rqp);
378                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
379                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
380         } else {
381                 mb_put_uint16le(mbp, uniplen);
382                 mb_put_uint32le(mbp, 0);                /* reserved */
383                 mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ?
384                                      SMB_CAP_UNICODE : 0);
385                 smb_rq_wend(rqp);
386                 smb_rq_bstart(rqp);
387                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
388                 mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
389                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);             /* AccountName */
390                 smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */
391                 smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE);      /* Client's OS */
392                 smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE);               /* Client name */
393         }
394         smb_rq_bend(rqp);
395         if (ntencpass)
396                 free(ntencpass, M_SMBTEMP);
397         if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
398                 smb_calcmackey(vcp);
399         error = smb_rq_simple(rqp);
400         SMBSDEBUG("%d\n", error);
401         if (error) {
402                 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess)
403                         error = EAUTH;
404                 goto bad;
405         }
406         vcp->vc_smbuid = rqp->sr_rpuid;
407 bad:
408         free(encpass, M_SMBTEMP);
409         free(pbuf, M_SMBTEMP);
410         smb_rq_done(rqp);
411         if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER)
412                 goto again;
413         return error;
414 }
415 
416 int
417 smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
418 {
419         struct smb_rq *rqp;
420         struct mbchain *mbp;
421         int error;
422 
423         if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
424                 return 0;
425 
426         if (smb_smb_nomux(vcp, scred, __func__) != 0)
427                 return EINVAL;
428 
429         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
430         if (error)
431                 return error;
432         mbp = &rqp->sr_rq;
433         smb_rq_wstart(rqp);
434         mb_put_uint8(mbp, 0xff);
435         mb_put_uint8(mbp, 0);
436         mb_put_uint16le(mbp, 0);
437         smb_rq_wend(rqp);
438         smb_rq_bstart(rqp);
439         smb_rq_bend(rqp);
440         error = smb_rq_simple(rqp);
441         SMBSDEBUG("%d\n", error);
442         smb_rq_done(rqp);
443         return error;
444 }
445 
446 static char smb_any_share[] = "?????";
447 
448 static char *
449 smb_share_typename(int stype)
450 {
451         char *pp;
452 
453         switch (stype) {
454             case SMB_ST_DISK:
455                 pp = "A:";
456                 break;
457             case SMB_ST_PRINTER:
458                 pp = smb_any_share;             /* can't use LPT: here... */
459                 break;
460             case SMB_ST_PIPE:
461                 pp = "IPC";
462                 break;
463             case SMB_ST_COMM:
464                 pp = "COMM";
465                 break;
466             case SMB_ST_ANY:
467             default:
468                 pp = smb_any_share;
469                 break;
470         }
471         return pp;
472 }
473 
474 int
475 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
476 {
477         struct smb_vc *vcp;
478         struct smb_rq rq, *rqp = &rq;
479         struct mbchain *mbp;
480         char *pp, *pbuf, *encpass;
481         int error, plen, caseopt, upper;
482 
483         upper = 0;
484 
485 again:
486 
487 #if 0
488         /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */
489         if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) {
490                 vcp = SSTOVC(ssp);
491                 if (vcp->vc_toserver) {
492                         iconv_close(vcp->vc_toserver);
493                         /* Use NULL until UTF-8 -> ASCII works */
494                         vcp->vc_toserver = NULL;
495                 }
496                 if (vcp->vc_tolocal) {
497                         iconv_close(vcp->vc_tolocal);
498                         /* Use NULL until ASCII -> UTF-8 works*/
499                         vcp->vc_tolocal = NULL;
500                 }
501                 vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
502         }
503 #endif
504 
505         ssp->ss_tid = SMB_TID_UNKNOWN;
506         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
507         if (error)
508                 return error;
509         vcp = rqp->sr_vc;
510         caseopt = SMB_CS_NONE;
511         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
512                 plen = 1;
513                 pp = "";
514                 pbuf = NULL;
515                 encpass = NULL;
516         } else {
517                 pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
518                 encpass = malloc(24, M_SMBTEMP, M_WAITOK);
519                 /*
520                  * We try w/o uppercasing first so Samba mixed case
521                  * passwords work.  If that fails we come back and try
522                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
523                  */
524                 if (upper++) {
525                         iconv_convstr(vcp->vc_toupper, pbuf,
526                                       smb_share_getpass(ssp)/*,
527                                       SMB_MAXPASSWORDLEN*/);
528                 } else {
529                         strncpy(pbuf, smb_share_getpass(ssp),
530                                 SMB_MAXPASSWORDLEN);
531                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
532                 }
533                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
534                         plen = 24;
535                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
536                         pp = encpass;
537                 } else {
538                         plen = strlen(pbuf) + 1;
539                         pp = pbuf;
540                 }
541         }
542         mbp = &rqp->sr_rq;
543         smb_rq_wstart(rqp);
544         mb_put_uint8(mbp, 0xff);
545         mb_put_uint8(mbp, 0);
546         mb_put_uint16le(mbp, 0);
547         mb_put_uint16le(mbp, 0);                /* Flags */
548         mb_put_uint16le(mbp, plen);
549         smb_rq_wend(rqp);
550         smb_rq_bstart(rqp);
551         mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
552         smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
553         pp = vcp->vc_srvname;
554         smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
555         smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
556         pp = ssp->ss_name;
557         smb_put_dstring(mbp, vcp, pp, caseopt);
558         pp = smb_share_typename(ssp->ss_type);
559         smb_put_dstring(mbp, vcp, pp, caseopt);
560         smb_rq_bend(rqp);
561         error = smb_rq_simple(rqp);
562         SMBSDEBUG("%d\n", error);
563         if (error)
564                 goto bad;
565         ssp->ss_tid = rqp->sr_rptid;
566         ssp->ss_vcgenid = vcp->vc_genid;
567         ssp->ss_flags |= SMBS_CONNECTED;
568 bad:
569         if (encpass)
570                 free(encpass, M_SMBTEMP);
571         if (pbuf)
572                 free(pbuf, M_SMBTEMP);
573         smb_rq_done(rqp);
574         if (error && upper == 1)
575                 goto again;
576         return error;
577 }
578 
579 int
580 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
581 {
582         struct smb_rq *rqp;
583         struct mbchain *mbp;
584         int error;
585 
586         if (ssp->ss_tid == SMB_TID_UNKNOWN)
587                 return 0;
588         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
589         if (error)
590                 return error;
591         mbp = &rqp->sr_rq;
592         smb_rq_wstart(rqp);
593         smb_rq_wend(rqp);
594         smb_rq_bstart(rqp);
595         smb_rq_bend(rqp);
596         error = smb_rq_simple(rqp);
597         SMBSDEBUG("%d\n", error);
598         smb_rq_done(rqp);
599         ssp->ss_tid = SMB_TID_UNKNOWN;
600         return error;
601 }
602 
603 static __inline int
604 smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
605               struct uio *uio, struct smb_cred *scred)
606 {
607         struct smb_rq *rqp;
608         struct mbchain *mbp;
609         struct mdchain *mdp;
610         u_int8_t wc;
611         int error;
612         u_int16_t residhi, residlo, off, doff;
613         u_int32_t resid;
614 
615         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
616         if (error)
617                 return error;
618         smb_rq_getrequest(rqp, &mbp);
619         smb_rq_wstart(rqp);
620         mb_put_uint8(mbp, 0xff);        /* no secondary command */
621         mb_put_uint8(mbp, 0);           /* MBZ */
622         mb_put_uint16le(mbp, 0);        /* offset to secondary */
623         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
624         mb_put_uint32le(mbp, uio->uio_offset);
625         *len = min(SSTOVC(ssp)->vc_rxmax, *len);
626         mb_put_uint16le(mbp, *len);     /* MaxCount */
627         mb_put_uint16le(mbp, *len);     /* MinCount (only indicates blocking) */
628         mb_put_uint32le(mbp, (unsigned)*len >> 16);     /* MaxCountHigh */
629         mb_put_uint16le(mbp, *len);     /* Remaining ("obsolete") */
630         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
631         smb_rq_wend(rqp);
632         smb_rq_bstart(rqp);
633         smb_rq_bend(rqp);
634         do {
635                 error = smb_rq_simple(rqp);
636                 if (error)
637                         break;
638                 smb_rq_getreply(rqp, &mdp);
639                 off = SMB_HDRLEN;
640                 md_get_uint8(mdp, &wc);
641                 off++;
642                 if (wc != 12) {
643                         error = EBADRPC;
644                         break;
645                 }
646                 md_get_uint8(mdp, NULL);
647                 off++;
648                 md_get_uint8(mdp, NULL);
649                 off++;
650                 md_get_uint16le(mdp, NULL);
651                 off += 2;
652                 md_get_uint16le(mdp, NULL);
653                 off += 2;
654                 md_get_uint16le(mdp, NULL);     /* data compaction mode */
655                 off += 2;
656                 md_get_uint16le(mdp, NULL);
657                 off += 2;
658                 md_get_uint16le(mdp, &residlo);
659                 off += 2;
660                 md_get_uint16le(mdp, &doff);    /* data offset */
661                 off += 2;
662                 md_get_uint16le(mdp, &residhi);
663                 off += 2;
664                 resid = (residhi << 16) | residlo;
665                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
666                 off += 4*2;
667                 md_get_uint16le(mdp, NULL);     /* ByteCount */
668                 off += 2;
669                 if (doff > off) /* pad byte(s)? */
670                         md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
671                 if (resid == 0) {
672                         *rresid = resid;
673                         break;
674                 }
675                 error = md_get_uio(mdp, uio, resid);
676                 if (error)
677                         break;
678                 *rresid = resid;
679         } while(0);
680         smb_rq_done(rqp);
681         return (error);
682 }
683 
684 static __inline int
685 smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
686         struct uio *uio, struct smb_cred *scred)
687 {
688         struct smb_rq *rqp;
689         struct mbchain *mbp;
690         struct mdchain *mdp;
691         int error;
692         u_int8_t wc;
693         u_int16_t resid;
694 
695         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
696         if (error)
697                 return (error);
698         smb_rq_getrequest(rqp, &mbp);
699         smb_rq_wstart(rqp);
700         mb_put_uint8(mbp, 0xff);        /* no secondary command */
701         mb_put_uint8(mbp, 0);           /* MBZ */
702         mb_put_uint16le(mbp, 0);        /* offset to secondary */
703         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
704         mb_put_uint32le(mbp, uio->uio_offset);
705         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
706         mb_put_uint16le(mbp, 0);        /* !write-thru */
707         mb_put_uint16le(mbp, 0);
708         *len = min(SSTOVC(ssp)->vc_wxmax, *len);
709         mb_put_uint16le(mbp, (unsigned)*len >> 16);
710         mb_put_uint16le(mbp, *len);
711         mb_put_uint16le(mbp, 64);       /* data offset from header start */
712         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
713         smb_rq_wend(rqp);
714         smb_rq_bstart(rqp);
715         do {
716                 mb_put_uint8(mbp, 0xee);        /* mimic xp pad byte! */
717                 error = mb_put_uio(mbp, uio, *len);
718                 if (error)
719                         break;
720                 smb_rq_bend(rqp);
721                 error = smb_rq_simple(rqp);
722                 if (error)
723                         break;
724                 smb_rq_getreply(rqp, &mdp);
725                 md_get_uint8(mdp, &wc);
726                 if (wc != 6) {
727                         error = EBADRPC;
728                         break;
729                 }
730                 md_get_uint8(mdp, NULL);
731                 md_get_uint8(mdp, NULL);
732                 md_get_uint16le(mdp, NULL);
733                 md_get_uint16le(mdp, &resid);
734                 *rresid = resid;
735         } while(0);
736 
737         smb_rq_done(rqp);
738         return (error);
739 }
740 
741 static __inline int
742 smb_smb_read(struct smb_share *ssp, u_int16_t fid,
743         int *len, int *rresid, struct uio *uio, struct smb_cred *scred)
744 {
745         struct smb_rq *rqp;
746         struct mbchain *mbp;
747         struct mdchain *mdp;
748         u_int16_t resid, bc;
749         u_int8_t wc;
750         int error, rlen, blksz;
751 
752         if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
753                 return (smb_smb_readx(ssp, fid, len, rresid, uio, scred));
754 
755         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
756         if (error)
757                 return error;
758 
759         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
760         rlen = *len = min(blksz, *len);
761 
762         smb_rq_getrequest(rqp, &mbp);
763         smb_rq_wstart(rqp);
764         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
765         mb_put_uint16le(mbp, rlen);
766         mb_put_uint32le(mbp, uio->uio_offset);
767         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
768         smb_rq_wend(rqp);
769         smb_rq_bstart(rqp);
770         smb_rq_bend(rqp);
771         do {
772                 error = smb_rq_simple(rqp);
773                 if (error)
774                         break;
775                 smb_rq_getreply(rqp, &mdp);
776                 md_get_uint8(mdp, &wc);
777                 if (wc != 5) {
778                         error = EBADRPC;
779                         break;
780                 }
781                 md_get_uint16le(mdp, &resid);
782                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
783                 md_get_uint16le(mdp, &bc);
784                 md_get_uint8(mdp, NULL);                /* ignore buffer type */
785                 md_get_uint16le(mdp, &resid);
786                 if (resid == 0) {
787                         *rresid = resid;
788                         break;
789                 }
790                 error = md_get_uio(mdp, uio, resid);
791                 if (error)
792                         break;
793                 *rresid = resid;
794         } while(0);
795         smb_rq_done(rqp);
796         return error;
797 }
798 
799 int
800 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
801         struct smb_cred *scred)
802 {
803         int tsize, len, resid;
804         int error = 0;
805 
806         tsize = uio->uio_resid;
807         while (tsize > 0) {
808                 resid = 0;
809                 len = tsize;
810                 error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
811                 if (error)
812                         break;
813                 tsize -= resid;
814                 if (resid < len)
815                         break;
816         }
817         return error;
818 }
819 
820 static __inline int
821 smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
822         struct uio *uio, struct smb_cred *scred)
823 {
824         struct smb_rq *rqp;
825         struct mbchain *mbp;
826         struct mdchain *mdp;
827         u_int16_t resid;
828         u_int8_t wc;
829         int error, blksz;
830 
831         if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
832                 return (smb_smb_writex(ssp, fid, len, rresid, uio, scred));
833  
834         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
835         if (blksz > 0xffff)
836                 blksz = 0xffff;
837 
838         resid = *len = min(blksz, *len);
839 
840         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
841         if (error)
842                 return error;
843         smb_rq_getrequest(rqp, &mbp);
844         smb_rq_wstart(rqp);
845         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
846         mb_put_uint16le(mbp, resid);
847         mb_put_uint32le(mbp, uio->uio_offset);
848         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
849         smb_rq_wend(rqp);