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.23 2005/02/26 22:39:50 perry 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.23 2005/02/26 22:39:50 perry 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_p == vcp->vc_iod->iod_p);
  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 *pp, *up, *pbuf, *encpass;
  267         int error, plen, uniplen, ulen, upper;
  268 
  269         KASSERT(scred->scr_p == vcp->vc_iod->iod_p);
  270 
  271         upper = 0;
  272 
  273 again:
  274 
  275         vcp->vc_smbuid = SMB_UID_UNKNOWN;
  276 
  277         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
  278         if (error)
  279                 return error;
  280         pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
  281         encpass = malloc(24, M_SMBTEMP, M_WAITOK);
  282         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
  283                 /*
  284                  * We try w/o uppercasing first so Samba mixed case
  285                  * passwords work.  If that fails we come back and try
  286                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
  287                  */
  288                 if (upper) {
  289                         iconv_convstr(vcp->vc_toupper, pbuf,
  290                             smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN + 1);
  291                 } else {
  292                         strlcpy(pbuf, smb_vc_getpass(vcp),
  293                             SMB_MAXPASSWORDLEN + 1);
  294                 }
  295                 if (!SMB_UNICODE_STRINGS(vcp))
  296                         iconv_convstr(vcp->vc_toserver, pbuf, pbuf,
  297                             SMB_MAXPASSWORDLEN + 1);
  298 
  299                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
  300                         uniplen = plen = 24;
  301                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
  302                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
  303                         if (SMB_UNICODE_STRINGS(vcp)) {
  304                                 strlcpy(pbuf, smb_vc_getpass(vcp),
  305                                     SMB_MAXPASSWORDLEN + 1);
  306                         } else
  307                                 iconv_convstr(vcp->vc_toserver, pbuf,
  308                                     smb_vc_getpass(vcp),
  309                                     SMB_MAXPASSWORDLEN + 1);
  310                         smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
  311                         pp = encpass;
  312                         unipp = ntencpass;
  313                 } else {
  314                         plen = strlen(pbuf) + 1;
  315                         pp = pbuf;
  316                         uniplen = plen * 2;
  317                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
  318                         smb_strtouni(ntencpass, smb_vc_getpass(vcp));
  319                         plen--;
  320 
  321                         /*
  322                          * The uniplen is zeroed because Samba cannot deal
  323                          * with this 2nd cleartext password.  This Samba
  324                          * "bug" is actually a workaround for problems in
  325                          * Microsoft clients.
  326                          */
  327                         uniplen = 0/*-= 2*/;
  328                         unipp = ntencpass;
  329                 }
  330         } else {
  331                 /*
  332                  * In the share security mode password will be used
  333                  * only in the tree authentication
  334                  */
  335                  pp = "";
  336                  plen = 1;
  337                  unipp = &smb_unieol;
  338                  uniplen = 0;
  339         }
  340         smb_rq_wstart(rqp);
  341         mbp = &rqp->sr_rq;
  342         up = vcp->vc_username;
  343         ulen = strlen(up) + 1;
  344         /*
  345          * If userid is null we are attempting anonymous browse login
  346          * so passwords must be zero length.
  347          */
  348         if (ulen == 1)
  349                 plen = uniplen = 0;
  350         mb_put_uint8(mbp, 0xff);
  351         mb_put_uint8(mbp, 0);
  352         mb_put_uint16le(mbp, 0);
  353         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
  354         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
  355         mb_put_uint16le(mbp, vcp->vc_number);
  356         mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
  357         mb_put_uint16le(mbp, plen);
  358         if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
  359                 mb_put_uint32le(mbp, 0);
  360                 smb_rq_wend(rqp);
  361                 smb_rq_bstart(rqp);
  362                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
  363                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
  364         } else {
  365                 mb_put_uint16le(mbp, uniplen);
  366                 mb_put_uint32le(mbp, 0);                /* reserved */
  367                 mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ?
  368                                      SMB_CAP_UNICODE : 0);
  369                 smb_rq_wend(rqp);
  370                 smb_rq_bstart(rqp);
  371                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
  372                 mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
  373                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);             /* AccountName */
  374                 smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */
  375                 smb_put_dstring(mbp, vcp, "NetBSD", SMB_CS_NONE);       /* Client's OS */
  376                 smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE);               /* Client name */
  377         }
  378         smb_rq_bend(rqp);
  379         if (ntencpass)
  380                 free(ntencpass, M_SMBTEMP);
  381         error = smb_rq_simple(rqp);
  382         SMBSDEBUG("%d\n", error);
  383         if (error) {
  384                 if (error == EACCES)
  385                         error = EAUTH;
  386                 goto bad;
  387         }
  388         vcp->vc_smbuid = rqp->sr_rpuid;
  389 bad:
  390         free(encpass, M_SMBTEMP);
  391         free(pbuf, M_SMBTEMP);
  392         smb_rq_done(rqp);
  393         if (error && !upper && vcp->vc_sopt.sv_sm & SMB_SM_USER) {
  394                 upper = 1;
  395                 goto again;
  396         }
  397         return error;
  398 }
  399 
  400 int
  401 smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
  402 {
  403         struct smb_rq *rqp;
  404         struct mbchain *mbp;
  405         int error;
  406 
  407         KASSERT(scred->scr_p == vcp->vc_iod->iod_p);
  408 
  409         if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
  410                 return 0;
  411 
  412         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
  413         if (error)
  414                 return error;
  415         mbp = &rqp->sr_rq;
  416         smb_rq_wstart(rqp);
  417         mb_put_uint8(mbp, 0xff);
  418         mb_put_uint8(mbp, 0);
  419         mb_put_uint16le(mbp, 0);
  420         smb_rq_wend(rqp);
  421         smb_rq_bstart(rqp);
  422         smb_rq_bend(rqp);
  423         error = smb_rq_simple(rqp);
  424         SMBSDEBUG("%d\n", error);
  425         smb_rq_done(rqp);
  426         return error;
  427 }
  428 
  429 static const char *
  430 smb_share_typename(int stype)
  431 {
  432         static const char smb_any_share[] = "?????";
  433         const char *pp;
  434 
  435         switch (stype) {
  436         case SMB_ST_DISK:
  437                 pp = "A:";
  438                 break;
  439         case SMB_ST_PRINTER:
  440                 pp = smb_any_share;             /* can't use LPT: here... */
  441                 break;
  442         case SMB_ST_PIPE:
  443                 pp = "IPC";
  444                 break;
  445         case SMB_ST_COMM:
  446                 pp = "COMM";
  447                 break;
  448         case SMB_ST_ANY:
  449         default:
  450                 pp = smb_any_share;
  451                 break;
  452         }
  453         return pp;
  454 }
  455 
  456 int
  457 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
  458 {
  459         struct smb_vc *vcp;
  460         struct smb_rq rq, *rqp = &rq;
  461         struct mbchain *mbp;
  462         const char *pp;
  463         char *pbuf, *encpass;
  464         int error, plen, caseopt, upper;
  465 
  466         upper = 0;
  467 
  468 again:
  469 
  470 #if 0
  471         /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */
  472         if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) {
  473                 vcp = SSTOVC(ssp);
  474                 if (vcp->vc_toserver) {
  475                         iconv_close(vcp->vc_toserver);
  476                         /* Use NULL until UTF-8 -> ASCII works */
  477                         vcp->vc_toserver = NULL;
  478                 }
  479                 if (vcp->vc_tolocal) {
  480                         iconv_close(vcp->vc_tolocal);
  481                         /* Use NULL until ASCII -> UTF-8 works*/
  482                         vcp->vc_tolocal = NULL;
  483                 }
  484                 vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
  485         }
  486 #endif
  487 
  488         ssp->ss_tid = SMB_TID_UNKNOWN;
  489         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
  490         if (error)
  491                 return error;
  492         vcp = rqp->sr_vc;
  493         caseopt = SMB_CS_NONE;
  494         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
  495                 plen = 1;
  496                 pp = "";
  497                 pbuf = NULL;
  498                 encpass = NULL;
  499         } else {
  500                 pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
  501                 encpass = malloc(24, M_SMBTEMP, M_WAITOK);
  502                 /*
  503                  * We try w/o uppercasing first so Samba mixed case
  504                  * passwords work.  If that fails we come back and try
  505                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
  506                  */
  507                 if (upper) {
  508                         iconv_convstr(vcp->vc_toupper, pbuf,
  509                             smb_share_getpass(ssp), SMB_MAXPASSWORDLEN + 1);
  510                 } else {
  511                         strlcpy(pbuf, smb_share_getpass(ssp),
  512                             SMB_MAXPASSWORDLEN + 1);
  513                 }
  514                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
  515                         plen = 24;
  516                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
  517                         pp = encpass;
  518                 } else {
  519                         plen = strlen(pbuf) + 1;
  520                         pp = pbuf;
  521                 }
  522         }
  523         mbp = &rqp->sr_rq;
  524         smb_rq_wstart(rqp);
  525         mb_put_uint8(mbp, 0xff);
  526         mb_put_uint8(mbp, 0);
  527         mb_put_uint16le(mbp, 0);
  528         mb_put_uint16le(mbp, 0);                /* Flags */
  529         mb_put_uint16le(mbp, plen);
  530         smb_rq_wend(rqp);
  531         smb_rq_bstart(rqp);
  532         mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
  533         smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
  534         pp = vcp->vc_srvname;
  535         smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
  536         smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
  537         pp = ssp->ss_name;
  538         smb_put_dstring(mbp, vcp, pp, caseopt);
  539         pp = smb_share_typename(ssp->ss_type);
  540         smb_put_dstring(mbp, vcp, pp, caseopt);
  541         smb_rq_bend(rqp);
  542         error = smb_rq_simple(rqp);
  543         SMBSDEBUG("%d\n", error);
  544         if (error)
  545                 goto bad;
  546         ssp->ss_tid = rqp->sr_rptid;
  547         ssp->ss_vcgenid = vcp->vc_genid;
  548         ssp->ss_flags |= SMBS_CONNECTED;
  549 bad:
  550         if (encpass)
  551                 free(encpass, M_SMBTEMP);
  552         if (pbuf)
  553                 free(pbuf, M_SMBTEMP);
  554         smb_rq_done(rqp);
  555         if (error && !upper) {
  556                 upper = 1;
  557                 goto again;
  558         }
  559         return error;
  560 }
  561 
  562 int
  563 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
  564 {
  565         struct smb_rq *rqp;
  566         int error;
  567 
  568         if (ssp->ss_tid == SMB_TID_UNKNOWN)
  569                 return 0;
  570         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
  571         if (error)
  572                 return error;
  573         smb_rq_wstart(rqp);
  574         smb_rq_wend(rqp);
  575         smb_rq_bstart(rqp);
  576         smb_rq_bend(rqp);
  577         error = smb_rq_simple(rqp);
  578         SMBSDEBUG("%d\n", error);
  579         smb_rq_done(rqp);
  580         ssp->ss_tid = SMB_TID_UNKNOWN;
  581         return error;
  582 }
  583 
  584 static __inline int
  585 smb_smb_readx(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
  586               struct uio *uio, struct smb_cred *scred)
  587 {
  588         struct smb_rq *rqp;
  589         struct mbchain *mbp;
  590         struct mdchain *mdp;
  591         u_int8_t wc;
  592         int error;
  593         u_int16_t residhi, residlo, off, doff;
  594         u_int32_t resid;
  595 
  596         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
  597         if (error)
  598                 return error;
  599         smb_rq_getrequest(rqp, &mbp);
  600         smb_rq_wstart(rqp);
  601         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  602         mb_put_uint8(mbp, 0);           /* MBZ */
  603         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  604         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  605         mb_put_uint32le(mbp, uio->uio_offset);
  606         *len = min(SSTOVC(ssp)->vc_rxmax, *len);
  607         mb_put_uint16le(mbp, *len);     /* MaxCount */
  608         mb_put_uint16le(mbp, *len);     /* MinCount (only indicates blocking) */
  609         mb_put_uint32le(mbp, *len >> 16);       /* MaxCountHigh */
  610         mb_put_uint16le(mbp, *len);     /* Remaining ("obsolete") */
  611         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  612         smb_rq_wend(rqp);
  613         smb_rq_bstart(rqp);
  614         smb_rq_bend(rqp);
  615         do {
  616                 error = smb_rq_simple(rqp);
  617                 if (error)
  618                         break;
  619                 smb_rq_getreply(rqp, &mdp);
  620                 off = SMB_HDRLEN;
  621                 md_get_uint8(mdp, &wc);
  622                 off++;
  623                 if (wc != 12) {
  624                         error = EBADRPC;
  625                         break;
  626                 }
  627                 md_get_uint8(mdp, NULL);
  628                 off++;
  629                 md_get_uint8(mdp, NULL);
  630                 off++;
  631                 md_get_uint16(mdp, NULL);
  632                 off += 2;
  633                 md_get_uint16(mdp, NULL);
  634                 off += 2;
  635                 md_get_uint16(mdp, NULL);       /* data compaction mode */
  636                 off += 2;
  637                 md_get_uint16(mdp, NULL);
  638                 off += 2;
  639                 md_get_uint16le(mdp, &residlo);
  640                 off += 2;
  641                 md_get_uint16le(mdp, &doff);    /* data offset */
  642                 off += 2;
  643                 md_get_uint16le(mdp, &residhi);
  644                 off += 2;
  645                 resid = (residhi << 16) | residlo;
  646                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  647                 off += 4*2;
  648                 md_get_uint16(mdp, NULL);       /* ByteCount */
  649                 off += 2;
  650                 if (doff > off) /* pad byte(s)? */
  651                         md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
  652                 if (resid == 0) {
  653                         *rresid = resid;
  654                         break;
  655                 }
  656                 error = md_get_uio(mdp, uio, resid);
  657                 if (error)
  658                         break;
  659                 *rresid = resid;
  660         } while(0);
  661         smb_rq_done(rqp);
  662         return (error);
  663 }
  664 
  665 static __inline int
  666 smb_smb_writex(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
  667         struct uio *uio, struct smb_cred *scred)
  668 {
  669         struct smb_rq *rqp;
  670         struct mbchain *mbp;
  671         struct mdchain *mdp;
  672         int error;
  673         u_int8_t wc;
  674         u_int16_t resid;
  675 
  676         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
  677         if (error)
  678                 return (error);
  679         smb_rq_getrequest(rqp, &mbp);
  680         smb_rq_wstart(rqp);
  681         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  682         mb_put_uint8(mbp, 0);           /* MBZ */
  683         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  684         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  685         mb_put_uint32le(mbp, uio->uio_offset);
  686         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
  687         mb_put_uint16le(mbp, 0);        /* !write-thru */
  688         mb_put_uint16le(mbp, 0);
  689         *len = min(SSTOVC(ssp)->vc_wxmax, *len);
  690         mb_put_uint16le(mbp, *len >> 16);
  691         mb_put_uint16le(mbp, *len);
  692         mb_put_uint16le(mbp, 64);       /* data offset from header start */
  693         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  694         smb_rq_wend(rqp);
  695         smb_rq_bstart(rqp);
  696         do {
  697                 mb_put_uint8(mbp, 0xee);        /* mimic xp pad byte! */
  698                 error = mb_put_uio(mbp, uio, *len);
  699                 if (error)
  700                         break;
  701                 smb_rq_bend(rqp);
  702                 error = smb_rq_simple(rqp);
  703                 if (error)
  704                         break;
  705                 smb_rq_getreply(rqp, &mdp);
  706                 md_get_uint8(mdp, &wc);
  707                 if (wc != 6) {
  708                         error = EBADRPC;
  709                         break;
  710                 }
  711                 md_get_uint8(mdp, NULL);
  712                 md_get_uint8(mdp, NULL);
  713                 md_get_uint16(mdp, NULL);
  714                 md_get_uint16le(mdp, &resid);
  715                 *rresid = resid;
  716         } while(0);
  717 
  718         smb_rq_done(rqp);
  719         return (error);
  720 }
  721 
  722 static __inline int
  723 smb_smb_read(struct smb_share *ssp, u_int16_t fid,
  724         size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred)
  725 {
  726         struct smb_rq *rqp;
  727         struct mbchain *mbp;
  728         struct mdchain *mdp;
  729         u_int16_t resid, bc;
  730         u_int8_t wc;
  731         int error, rlen, blksz;
  732 
  733         /* Cannot read at/beyond 4G */
  734         if (uio->uio_offset >= (1LL << 32))
  735                 return (EFBIG);
  736 
  737         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
  738         if (error)
  739                 return error;
  740 
  741         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
  742         rlen = *len = min(blksz, *len);
  743 
  744         smb_rq_getrequest(rqp, &mbp);
  745         smb_rq_wstart(rqp);
  746         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  747         mb_put_uint16le(mbp, rlen);
  748         mb_put_uint32le(mbp, uio->uio_offset);
  749         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
  750         smb_rq_wend(rqp);
  751         smb_rq_bstart(rqp);
  752         smb_rq_bend(rqp);
  753         do {
  754                 error = smb_rq_simple(rqp);
  755                 if (error)
  756                         break;
  757                 smb_rq_getreply(rqp, &mdp);
  758                 md_get_uint8(mdp, &wc);
  759                 if (wc != 5) {
  760                         error = EBADRPC;
  761                         break;
  762                 }
  763                 md_get_uint16le(mdp, &resid);
  764                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  765                 md_get_uint16le(mdp, &bc);
  766                 md_get_uint8(mdp, NULL);                /* ignore buffer type */
  767                 md_get_uint16le(mdp, &resid);
  768                 if (resid == 0) {
  769                         *rresid = resid;
  770                         break;
  771                 }
  772                 error = md_get_uio(mdp, uio, resid);
  773                 if (error)
  774                         break;
  775                 *rresid = resid;
  776         } while(0);
  777         smb_rq_done(rqp);
  778         return error;
  779 }
  780 
  781 int
  782 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
  783         struct smb_cred *scred)
  784 {
  785         size_t tsize, len, resid;
  786         int error = 0;
  787         int rx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX);
  788 
  789         tsize = uio->uio_resid;
  790         while (tsize > 0) {
  791                 len = tsize;
  792                 if (rx)
  793                     error = smb_smb_readx(ssp, fid, &len, &resid, uio, scred);
  794                 else
  795                     error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
  796                 if (error)
  797                         break;
  798                 tsize -= resid;
  799                 if (resid < len)
  800                         break;
  801         }
  802         return error;
  803 }
  804 
  805 static __inline int
  806 smb_smb_write(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
  807         struct uio *uio, struct smb_cred *scred)
  808 {
  809         struct smb_rq *rqp;
  810         struct mbchain *mbp;
  811         struct mdchain *mdp;
  812         u_int16_t resid;
  813         u_int8_t wc;
  814         int error, blksz;
  815 
  816         /* Cannot write at/beyond 4G */
  817         if (uio->uio_offset >= (1LL << 32))
  818                 return (EFBIG);
  819 
  820         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
  821         if (blksz > 0xffff)
  822                 blksz = 0xffff;
  823 
  824         resid = *len = min(blksz, *len);
  825 
  826         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
  827         if (error)
  828                 return error;
  829         smb_rq_getrequest(rqp, &mbp);
  830         smb_rq_wstart(rqp);
  831         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  832         mb_put_uint16le(mbp, resid);
  833         mb_put_uint32le(mbp, uio->uio_offset);
  834         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
  835         smb_rq_wend(rqp);
  836         smb_rq_bstart(rqp);
  837         mb_put_uint8(mbp, SMB_DT_DATA);
  838         mb_put_uint16le(mbp, resid);
  839         do {
  840                 error = mb_put_uio(mbp, uio, resid);
  841                 if (error)
  842                         break;
  843                 smb_rq_bend(rqp);
  844                 error = smb_rq_simple(rqp);
  845                 if (error)
  846                         break;
  847                 smb_rq_getreply(rqp, &mdp);
  848                 md_get_uint8(mdp, &wc);
  849                 if (wc != 1) {
  850                         error = EBADRPC;
  851                         break;
  852                 }
  853                 md_get_uint16le(mdp, &resid);
  854                 *rresid = resid;
  855         } while(0);
  856         smb_rq_done(rqp);
  857         return error;
  858 }
  859 
  860 int
  861 smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
  862         struct smb_cred *scred)
  863 {
  864         int error = 0;
  865         size_t len, tsize, resid;
  866         int wx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_WRITEX);
  867 
  868         tsize = uio->uio_resid;
  869         while (tsize > 0) {
  870                 len = tsize;
  871                 if (wx)
  872                     error = smb_smb_writex(ssp, fid, &len, &resid, uio, scred);
  873                 else
  874                     error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
  875                 if (error)
  876                         break;
  877                 if (resid < len) {
  878                         error = EIO;
  879                         break;
  880                 }
  881                 tsize -= resid;
  882         }
  883         return error;
  884 }
  885 
  886 #if 0
  887 int
  888 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
  889 {
  890         struct smb_rq *rqp;
  891         struct mbchain *mbp;
  892         int error;
  893 
  894         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
  895         if (error)
  896                 return error;
  897         mbp = &rqp->sr_rq;
  898         smb_rq_wstart(rqp);
  899         mb_put_uint16le(mbp, 1);
  900         smb_rq_wend(rqp);
  901         smb_rq_bstart(rqp);
  902         mb_put_uint32le(mbp, 0);
  903         smb_rq_bend(rqp);
  904         error = smb_rq_simple(rqp);
  905         SMBSDEBUG("%d\n", error);
  906         smb_rq_done(rqp);
  907         return error;
  908 }
  909 #endif

Cache object: 2e10486148e346e88a6049d37d1f2ecb


[ 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.