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

Cache object: 51f68c000b845220dbfb94ffaca9a075


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