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

Cache object: 0c698d052e312e91840b8f46a0a7a344


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