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.27 2006/05/10 21:53:19 mrg 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.27 2006/05/10 21:53:19 mrg 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         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
  598         if (error)
  599                 return error;
  600         smb_rq_getrequest(rqp, &mbp);
  601         smb_rq_wstart(rqp);
  602         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  603         mb_put_uint8(mbp, 0);           /* MBZ */
  604         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  605         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  606         mb_put_uint32le(mbp, uio->uio_offset);
  607         *len = min(SSTOVC(ssp)->vc_rxmax, *len);
  608         mb_put_uint16le(mbp, *len);     /* MaxCount */
  609         mb_put_uint16le(mbp, *len);     /* MinCount (only indicates blocking) */
  610         mb_put_uint32le(mbp, *len >> 16);       /* MaxCountHigh */
  611         mb_put_uint16le(mbp, *len);     /* Remaining ("obsolete") */
  612         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  613         smb_rq_wend(rqp);
  614         smb_rq_bstart(rqp);
  615         smb_rq_bend(rqp);
  616         do {
  617                 error = smb_rq_simple(rqp);
  618                 if (error)
  619                         break;
  620                 smb_rq_getreply(rqp, &mdp);
  621                 off = SMB_HDRLEN;
  622                 md_get_uint8(mdp, &wc);
  623                 off++;
  624                 if (wc != 12) {
  625                         error = EBADRPC;
  626                         break;
  627                 }
  628                 md_get_uint8(mdp, NULL);
  629                 off++;
  630                 md_get_uint8(mdp, NULL);
  631                 off++;
  632                 md_get_uint16(mdp, NULL);
  633                 off += 2;
  634                 md_get_uint16(mdp, NULL);
  635                 off += 2;
  636                 md_get_uint16(mdp, NULL);       /* data compaction mode */
  637                 off += 2;
  638                 md_get_uint16(mdp, NULL);
  639                 off += 2;
  640                 md_get_uint16le(mdp, &residlo);
  641                 off += 2;
  642                 md_get_uint16le(mdp, &doff);    /* data offset */
  643                 off += 2;
  644                 md_get_uint16le(mdp, &residhi);
  645                 off += 2;
  646                 resid = (residhi << 16) | residlo;
  647                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  648                 off += 4*2;
  649                 md_get_uint16(mdp, NULL);       /* ByteCount */
  650                 off += 2;
  651                 if (doff > off) /* pad byte(s)? */
  652                         md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
  653                 if (resid == 0) {
  654                         *rresid = resid;
  655                         break;
  656                 }
  657                 error = md_get_uio(mdp, uio, resid);
  658                 if (error)
  659                         break;
  660                 *rresid = resid;
  661         } while(0);
  662         smb_rq_done(rqp);
  663         return (error);
  664 }
  665 
  666 static inline int
  667 smb_smb_writex(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
  668         struct uio *uio, struct smb_cred *scred)
  669 {
  670         struct smb_rq *rqp;
  671         struct mbchain *mbp;
  672         struct mdchain *mdp;
  673         int error;
  674         u_int8_t wc;
  675         u_int16_t resid;
  676 
  677         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
  678         if (error)
  679                 return (error);
  680         smb_rq_getrequest(rqp, &mbp);
  681         smb_rq_wstart(rqp);
  682         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  683         mb_put_uint8(mbp, 0);           /* MBZ */
  684         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  685         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  686         mb_put_uint32le(mbp, uio->uio_offset);
  687         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
  688         mb_put_uint16le(mbp, 0);        /* !write-thru */
  689         mb_put_uint16le(mbp, 0);
  690         *len = min(SSTOVC(ssp)->vc_wxmax, *len);
  691         mb_put_uint16le(mbp, *len >> 16);
  692         mb_put_uint16le(mbp, *len);
  693         mb_put_uint16le(mbp, 64);       /* data offset from header start */
  694         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  695         smb_rq_wend(rqp);
  696         smb_rq_bstart(rqp);
  697         do {
  698                 mb_put_uint8(mbp, 0xee);        /* mimic xp pad byte! */
  699                 error = mb_put_uio(mbp, uio, *len);
  700                 if (error)
  701                         break;
  702                 smb_rq_bend(rqp);
  703                 error = smb_rq_simple(rqp);
  704                 if (error)
  705                         break;
  706                 smb_rq_getreply(rqp, &mdp);
  707                 md_get_uint8(mdp, &wc);
  708                 if (wc != 6) {
  709                         error = EBADRPC;
  710                         break;
  711                 }
  712                 md_get_uint8(mdp, NULL);
  713                 md_get_uint8(mdp, NULL);
  714                 md_get_uint16(mdp, NULL);
  715                 md_get_uint16le(mdp, &resid);
  716                 *rresid = resid;
  717         } while(0);
  718 
  719         smb_rq_done(rqp);
  720         return (error);
  721 }
  722 
  723 static inline int
  724 smb_smb_read(struct smb_share *ssp, u_int16_t fid,
  725         size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred)
  726 {
  727         struct smb_rq *rqp;
  728         struct mbchain *mbp;
  729         struct mdchain *mdp;
  730         u_int16_t resid, bc;
  731         u_int8_t wc;
  732         int error, rlen, blksz;
  733 
  734         /* Cannot read at/beyond 4G */
  735         if (uio->uio_offset >= (1LL << 32))
  736                 return (EFBIG);
  737 
  738         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
  739         if (error)
  740                 return error;
  741 
  742         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
  743         rlen = *len = min(blksz, *len);
  744 
  745         smb_rq_getrequest(rqp, &mbp);
  746         smb_rq_wstart(rqp);
  747         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  748         mb_put_uint16le(mbp, rlen);
  749         mb_put_uint32le(mbp, uio->uio_offset);
  750         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
  751         smb_rq_wend(rqp);
  752         smb_rq_bstart(rqp);
  753         smb_rq_bend(rqp);
  754         do {
  755                 error = smb_rq_simple(rqp);
  756                 if (error)
  757                         break;
  758                 smb_rq_getreply(rqp, &mdp);
  759                 md_get_uint8(mdp, &wc);
  760                 if (wc != 5) {
  761                         error = EBADRPC;
  762                         break;
  763                 }
  764                 md_get_uint16le(mdp, &resid);
  765                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  766                 md_get_uint16le(mdp, &bc);
  767                 md_get_uint8(mdp, NULL);                /* ignore buffer type */
  768                 md_get_uint16le(mdp, &resid);
  769                 if (resid == 0) {
  770                         *rresid = resid;
  771                         break;
  772                 }
  773                 error = md_get_uio(mdp, uio, resid);
  774                 if (error)
  775                         break;
  776                 *rresid = resid;
  777         } while(0);
  778         smb_rq_done(rqp);
  779         return error;
  780 }
  781 
  782 int
  783 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
  784         struct smb_cred *scred)
  785 {
  786         size_t tsize, len, resid;
  787         int error = 0;
  788         int rx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX);
  789 
  790         resid = 0;      /* XXX gcc */
  791 
  792         tsize = uio->uio_resid;
  793         while (tsize > 0) {
  794                 len = tsize;
  795                 if (rx)
  796                     error = smb_smb_readx(ssp, fid, &len, &resid, uio, scred);
  797                 else
  798                     error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
  799                 if (error)
  800                         break;
  801                 tsize -= resid;
  802                 if (resid < len)
  803                         break;
  804         }
  805         return error;
  806 }
  807 
  808 static inline int
  809 smb_smb_write(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
  810         struct uio *uio, struct smb_cred *scred)
  811 {
  812         struct smb_rq *rqp;
  813         struct mbchain *mbp;
  814         struct mdchain *mdp;
  815         u_int16_t resid;
  816         u_int8_t wc;
  817         int error, blksz;
  818 
  819         /* Cannot write at/beyond 4G */
  820         if (uio->uio_offset >= (1LL << 32))
  821                 return (EFBIG);
  822 
  823         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
  824         if (blksz > 0xffff)
  825                 blksz = 0xffff;
  826 
  827         resid = *len = min(blksz, *len);
  828 
  829         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
  830         if (error)
  831                 return error;
  832         smb_rq_getrequest(rqp, &mbp);
  833         smb_rq_wstart(rqp);
  834         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  835         mb_put_uint16le(mbp, resid);
  836         mb_put_uint32le(mbp, uio->uio_offset);
  837         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
  838         smb_rq_wend(rqp);
  839         smb_rq_bstart(rqp);
  840         mb_put_uint8(mbp, SMB_DT_DATA);
  841         mb_put_uint16le(mbp, resid);
  842         do {
  843                 error = mb_put_uio(mbp, uio, resid);
  844                 if (error)
  845                         break;
  846                 smb_rq_bend(rqp);
  847                 error = smb_rq_simple(rqp);
  848                 if (error)
  849                         break;
  850                 smb_rq_getreply(rqp, &mdp);
  851                 md_get_uint8(mdp, &wc);
  852                 if (wc != 1) {
  853                         error = EBADRPC;
  854                         break;
  855                 }
  856                 md_get_uint16le(mdp, &resid);
  857                 *rresid = resid;
  858         } while(0);
  859         smb_rq_done(rqp);
  860         return error;
  861 }
  862 
  863 int
  864 smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
  865         struct smb_cred *scred)
  866 {
  867         int error = 0;
  868         size_t len, tsize, resid;
  869         int wx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_WRITEX);
  870 
  871         resid = 0;      /* XXX gcc */
  872 
  873         tsize = uio->uio_resid;
  874         while (tsize > 0) {
  875                 len = tsize;
  876                 if (wx)
  877                     error = smb_smb_writex(ssp, fid, &len, &resid, uio, scred);
  878                 else
  879                     error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
  880                 if (error)
  881                         break;
  882                 if (resid < len) {
  883                         error = EIO;
  884                         break;
  885                 }
  886                 tsize -= resid;
  887         }
  888         return error;
  889 }
  890 
  891 #if 0
  892 int
  893 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
  894 {
  895         struct smb_rq *rqp;
  896         struct mbchain *mbp;
  897         int error;
  898 
  899         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
  900         if (error)
  901                 return error;
  902         mbp = &rqp->sr_rq;
  903         smb_rq_wstart(rqp);
  904         mb_put_uint16le(mbp, 1);
  905         smb_rq_wend(rqp);
  906         smb_rq_bstart(rqp);
  907         mb_put_uint32le(mbp, 0);
  908         smb_rq_bend(rqp);
  909         error = smb_rq_simple(rqp);
  910         SMBSDEBUG("%d\n", error);
  911         smb_rq_done(rqp);
  912         return error;
  913 }
  914 #endif

Cache object: 6c2aa3a130ffe2178d2bf14453507bd3


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