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

Cache object: eaa0eedb0b5725dd87d0c0f058d591a0


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