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.21 2003/10/30 01:43:10 simonb 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.21 2003/10/30 01:43:10 simonb 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*/);
  291                 } else {
  292                         strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
  293                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
  294                 }
  295                 if (!SMB_UNICODE_STRINGS(vcp))
  296                         iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*,
  297                                       SMB_MAXPASSWORDLEN*/);
  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                                 strncpy(pbuf, smb_vc_getpass(vcp),
  305                                         SMB_MAXPASSWORDLEN);
  306                                 pbuf[SMB_MAXPASSWORDLEN] = '\0';
  307                         } else
  308                                 iconv_convstr(vcp->vc_toserver, pbuf,
  309                                               smb_vc_getpass(vcp)/*,
  310                                               SMB_MAXPASSWORDLEN*/);
  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, (caddr_t)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_p == vcp->vc_iod->iod_p);
  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)/*,
  511                                       SMB_MAXPASSWORDLEN*/);
  512                 } else {
  513                         strncpy(pbuf, smb_share_getpass(ssp),
  514                                 SMB_MAXPASSWORDLEN);
  515                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
  516                 }
  517                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
  518                         plen = 24;
  519                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
  520                         pp = encpass;
  521                 } else {
  522                         plen = strlen(pbuf) + 1;
  523                         pp = pbuf;
  524                 }
  525         }
  526         mbp = &rqp->sr_rq;
  527         smb_rq_wstart(rqp);
  528         mb_put_uint8(mbp, 0xff);
  529         mb_put_uint8(mbp, 0);
  530         mb_put_uint16le(mbp, 0);
  531         mb_put_uint16le(mbp, 0);                /* Flags */
  532         mb_put_uint16le(mbp, plen);
  533         smb_rq_wend(rqp);
  534         smb_rq_bstart(rqp);
  535         mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
  536         smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
  537         pp = vcp->vc_srvname;
  538         smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
  539         smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
  540         pp = ssp->ss_name;
  541         smb_put_dstring(mbp, vcp, pp, caseopt);
  542         pp = smb_share_typename(ssp->ss_type);
  543         smb_put_dstring(mbp, vcp, pp, caseopt);
  544         smb_rq_bend(rqp);
  545         error = smb_rq_simple(rqp);
  546         SMBSDEBUG("%d\n", error);
  547         if (error)
  548                 goto bad;
  549         ssp->ss_tid = rqp->sr_rptid;
  550         ssp->ss_vcgenid = vcp->vc_genid;
  551         ssp->ss_flags |= SMBS_CONNECTED;
  552 bad:
  553         if (encpass)
  554                 free(encpass, M_SMBTEMP);
  555         if (pbuf)
  556                 free(pbuf, M_SMBTEMP);
  557         smb_rq_done(rqp);
  558         if (error && !upper) {
  559                 upper = 1;
  560                 goto again;
  561         }
  562         return error;
  563 }
  564 
  565 int
  566 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
  567 {
  568         struct smb_rq *rqp;
  569         int error;
  570 
  571         if (ssp->ss_tid == SMB_TID_UNKNOWN)
  572                 return 0;
  573         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
  574         if (error)
  575                 return error;
  576         smb_rq_wstart(rqp);
  577         smb_rq_wend(rqp);
  578         smb_rq_bstart(rqp);
  579         smb_rq_bend(rqp);
  580         error = smb_rq_simple(rqp);
  581         SMBSDEBUG("%d\n", error);
  582         smb_rq_done(rqp);
  583         ssp->ss_tid = SMB_TID_UNKNOWN;
  584         return error;
  585 }
  586 
  587 static __inline int
  588 smb_smb_readx(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
  589               struct uio *uio, struct smb_cred *scred)
  590 {
  591         struct smb_rq *rqp;
  592         struct mbchain *mbp;
  593         struct mdchain *mdp;
  594         u_int8_t wc;
  595         int error;
  596         u_int16_t residhi, residlo, off, doff;
  597         u_int32_t resid;
  598 
  599         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
  600         if (error)
  601                 return error;
  602         smb_rq_getrequest(rqp, &mbp);
  603         smb_rq_wstart(rqp);
  604         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  605         mb_put_uint8(mbp, 0);           /* MBZ */
  606         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  607         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  608         mb_put_uint32le(mbp, uio->uio_offset);
  609         *len = min(SSTOVC(ssp)->vc_rxmax, *len);
  610         mb_put_uint16le(mbp, *len);     /* MaxCount */
  611         mb_put_uint16le(mbp, *len);     /* MinCount (only indicates blocking) */
  612         mb_put_uint32le(mbp, *len >> 16);       /* MaxCountHigh */
  613         mb_put_uint16le(mbp, *len);     /* Remaining ("obsolete") */
  614         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  615         smb_rq_wend(rqp);
  616         smb_rq_bstart(rqp);
  617         smb_rq_bend(rqp);
  618         do {
  619                 error = smb_rq_simple(rqp);
  620                 if (error)
  621                         break;
  622                 smb_rq_getreply(rqp, &mdp);
  623                 off = SMB_HDRLEN;
  624                 md_get_uint8(mdp, &wc);
  625                 off++;
  626                 if (wc != 12) {
  627                         error = EBADRPC;
  628                         break;
  629                 }
  630                 md_get_uint8(mdp, NULL);
  631                 off++;
  632                 md_get_uint8(mdp, NULL);
  633                 off++;
  634                 md_get_uint16(mdp, NULL);
  635                 off += 2;
  636                 md_get_uint16(mdp, NULL);
  637                 off += 2;
  638                 md_get_uint16(mdp, NULL);       /* data compaction mode */
  639                 off += 2;
  640                 md_get_uint16(mdp, NULL);
  641                 off += 2;
  642                 md_get_uint16le(mdp, &residlo);
  643                 off += 2;
  644                 md_get_uint16le(mdp, &doff);    /* data offset */
  645                 off += 2;
  646                 md_get_uint16le(mdp, &residhi);
  647                 off += 2;
  648                 resid = (residhi << 16) | residlo;
  649                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  650                 off += 4*2;
  651                 md_get_uint16(mdp, NULL);       /* ByteCount */
  652                 off += 2;
  653                 if (doff > off) /* pad byte(s)? */
  654                         md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
  655                 if (resid == 0) {
  656                         *rresid = resid;
  657                         break;
  658                 }
  659                 error = md_get_uio(mdp, uio, resid);
  660                 if (error)
  661                         break;
  662                 *rresid = resid;
  663         } while(0);
  664         smb_rq_done(rqp);
  665         return (error);
  666 }
  667 
  668 static __inline int
  669 smb_smb_writex(struct smb_share *ssp, u_int16_t fid, size_t *len, size_t *rresid,
  670         struct uio *uio, struct smb_cred *scred)
  671 {
  672         struct smb_rq *rqp;
  673         struct mbchain *mbp;
  674         struct mdchain *mdp;
  675         int error;
  676         u_int8_t wc;
  677         u_int16_t resid;
  678 
  679         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
  680         if (error)
  681                 return (error);
  682         smb_rq_getrequest(rqp, &mbp);
  683         smb_rq_wstart(rqp);
  684         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  685         mb_put_uint8(mbp, 0);           /* MBZ */
  686         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  687         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  688         mb_put_uint32le(mbp, uio->uio_offset);
  689         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
  690         mb_put_uint16le(mbp, 0);        /* !write-thru */
  691         mb_put_uint16le(mbp, 0);
  692         *len = min(SSTOVC(ssp)->vc_wxmax, *len);
  693         mb_put_uint16le(mbp, *len >> 16);
  694         mb_put_uint16le(mbp, *len);
  695         mb_put_uint16le(mbp, 64);       /* data offset from header start */
  696         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  697         smb_rq_wend(rqp);
  698         smb_rq_bstart(rqp);
  699         do {
  700                 mb_put_uint8(mbp, 0xee);        /* mimic xp pad byte! */
  701                 error = mb_put_uio(mbp, uio, *len);
  702                 if (error)
  703                         break;
  704                 smb_rq_bend(rqp);
  705                 error = smb_rq_simple(rqp);
  706                 if (error)
  707                         break;
  708                 smb_rq_getreply(rqp, &mdp);
  709                 md_get_uint8(mdp, &wc);
  710                 if (wc != 6) {
  711                         error = EBADRPC;
  712                         break;
  713                 }
  714                 md_get_uint8(mdp, NULL);
  715                 md_get_uint8(mdp, NULL);
  716                 md_get_uint16(mdp, NULL);
  717                 md_get_uint16le(mdp, &resid);
  718                 *rresid = resid;
  719         } while(0);
  720 
  721         smb_rq_done(rqp);
  722         return (error);
  723 }
  724 
  725 static __inline int
  726 smb_smb_read(struct smb_share *ssp, u_int16_t fid,
  727         size_t *len, size_t *rresid, struct uio *uio, struct smb_cred *scred)
  728 {
  729         struct smb_rq *rqp;
  730         struct mbchain *mbp;
  731         struct mdchain *mdp;
  732         u_int16_t resid, bc;
  733         u_int8_t wc;
  734         int error, rlen, blksz;
  735 
  736         /* Cannot read at/beyond 4G */
  737         if (uio->uio_offset >= (1LL << 32))
  738                 return (EFBIG);
  739 
  740         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
  741         if (error)
  742                 return error;
  743 
  744         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
  745         rlen = *len = min(blksz, *len);
  746 
  747         smb_rq_getrequest(rqp, &mbp);
  748         smb_rq_wstart(rqp);
  749         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  750         mb_put_uint16le(mbp, rlen);
  751         mb_put_uint32le(mbp, uio->uio_offset);
  752         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
  753         smb_rq_wend(rqp);
  754         smb_rq_bstart(rqp);
  755         smb_rq_bend(rqp);
  756         do {
  757                 error = smb_rq_simple(rqp);
  758                 if (error)
  759                         break;
  760                 smb_rq_getreply(rqp, &mdp);
  761                 md_get_uint8(mdp, &wc);
  762                 if (wc != 5) {
  763                         error = EBADRPC;
  764                         break;
  765                 }
  766                 md_get_uint16le(mdp, &resid);
  767                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  768                 md_get_uint16le(mdp, &bc);
  769                 md_get_uint8(mdp, NULL);                /* ignore buffer type */
  770                 md_get_uint16le(mdp, &resid);
  771                 if (resid == 0) {
  772                         *rresid = resid;
  773                         break;
  774                 }
  775                 error = md_get_uio(mdp, uio, resid);
  776                 if (error)
  777                         break;
  778                 *rresid = resid;
  779         } while(0);
  780         smb_rq_done(rqp);
  781         return error;
  782 }
  783 
  784 int
  785 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
  786         struct smb_cred *scred)
  787 {
  788         size_t tsize, len, resid;
  789         int error = 0;
  790         int rx = (SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_LARGE_READX);
  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         tsize = uio->uio_resid;
  872         while (tsize > 0) {
  873                 len = tsize;
  874                 if (wx)
  875                     error = smb_smb_writex(ssp, fid, &len, &resid, uio, scred);
  876                 else
  877                     error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
  878                 if (error)
  879                         break;
  880                 if (resid < len) {
  881                         error = EIO;
  882                         break;
  883                 }
  884                 tsize -= resid;
  885         }
  886         return error;
  887 }
  888 
  889 #if 0
  890 int
  891 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
  892 {
  893         struct smb_rq *rqp;
  894         struct mbchain *mbp;
  895         int error;
  896 
  897         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
  898         if (error)
  899                 return error;
  900         mbp = &rqp->sr_rq;
  901         smb_rq_wstart(rqp);
  902         mb_put_uint16le(mbp, 1);
  903         smb_rq_wend(rqp);
  904         smb_rq_bstart(rqp);
  905         mb_put_uint32le(mbp, 0);
  906         smb_rq_bend(rqp);
  907         error = smb_rq_simple(rqp);
  908         SMBSDEBUG("%d\n", error);
  909         smb_rq_done(rqp);
  910         return error;
  911 }
  912 #endif

Cache object: b94ba9b2ec0d8772e3b38e79590fa10d


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