The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

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

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 282058f8c8ae1a6ed7f45551db108d74


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.