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

Cache object: 418a3bd68ed41833c7ebdb2382ff8453


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