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

Cache object: 0a19cae4e8a568582f92f0b737e3e8c1


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