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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2000-2001 Boris Popov
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * various SMB requests. Most of the routines merely packs data into mbufs.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/kernel.h>
   39 #include <sys/malloc.h>
   40 #include <sys/proc.h>
   41 #include <sys/lock.h>
   42 #include <sys/sysctl.h>
   43 #include <sys/socket.h>
   44 #include <sys/uio.h>
   45 
   46 #include <sys/iconv.h>
   47 
   48 #include <netsmb/smb.h>
   49 #include <netsmb/smb_subr.h>
   50 #include <netsmb/smb_rq.h>
   51 #include <netsmb/smb_conn.h>
   52 #include <netsmb/smb_tran.h>
   53 
   54 #include "opt_netsmb.h"
   55 
   56 struct smb_dialect {
   57         int             d_id;
   58         const char *    d_name;
   59 };
   60 
   61 static struct smb_dialect smb_dialects[] = {
   62         {SMB_DIALECT_CORE,      "PC NETWORK PROGRAM 1.0"},
   63         {SMB_DIALECT_COREPLUS,  "MICROSOFT NETWORKS 1.03"},
   64         {SMB_DIALECT_LANMAN1_0, "MICROSOFT NETWORKS 3.0"},
   65         {SMB_DIALECT_LANMAN1_0, "LANMAN1.0"},
   66         {SMB_DIALECT_LANMAN2_0, "LM1.2X002"},
   67         {SMB_DIALECT_LANMAN2_0, "Samba"},
   68         {SMB_DIALECT_NTLM0_12,  "NT LANMAN 1.0"},
   69         {SMB_DIALECT_NTLM0_12,  "NT LM 0.12"},
   70         {-1,                    NULL}
   71 };
   72 
   73 static u_int32_t
   74 smb_vc_maxread(struct smb_vc *vcp)
   75 {
   76         /*
   77          * Specs say up to 64k data bytes, but Windows traffic
   78          * uses 60k... no doubt for some good reason.
   79          *
   80          * Don't exceed the server's buffer size if signatures
   81          * are enabled otherwise Windows 2003 chokes. Allow space
   82          * for the SMB header & a little bit extra.
   83          */
   84         if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) &&
   85             (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
   86                 return (60*1024);
   87         else
   88                 return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
   89 }
   90 
   91 static u_int32_t
   92 smb_vc_maxwrite(struct smb_vc *vcp)
   93 {
   94         /*
   95          * See comment above.
   96          */
   97         if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) &&
   98             (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
   99                 return (60*1024);
  100         else
  101                 return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
  102 }
  103 
  104 static int
  105 smb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name)
  106 {
  107         if (scred->scr_td->td_proc == vcp->vc_iod->iod_p)
  108                 return 0;
  109         SMBERROR("wrong function called(%s)\n", name);
  110         return EINVAL;
  111 }
  112 
  113 int
  114 smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
  115 {
  116         struct smb_dialect *dp;
  117         struct smb_sopt *sp = NULL;
  118         struct smb_rq *rqp;
  119         struct mbchain *mbp;
  120         struct mdchain *mdp;
  121         u_int8_t wc, stime[8], sblen;
  122         u_int16_t dindex, tw, tw1, swlen, bc;
  123         int error, maxqsz;
  124         int unicode = SMB_UNICODE_STRINGS(vcp);
  125         void * servercharset = vcp->vc_toserver;
  126         void * localcharset = vcp->vc_tolocal;
  127 
  128         if (smb_smb_nomux(vcp, scred, __func__) != 0)
  129                 return EINVAL;
  130         /* Disable Unicode for SMB_COM_NEGOTIATE requests */ 
  131         if (unicode) {
  132                 vcp->vc_toserver = vcp->vc_cp_toserver;
  133                 vcp->vc_tolocal  = vcp->vc_cp_tolocal;
  134         }
  135         vcp->vc_hflags = 0;
  136         vcp->vc_hflags2 = 0;
  137         vcp->obj.co_flags &= ~(SMBV_ENCRYPT);
  138         sp = &vcp->vc_sopt;
  139         bzero(sp, sizeof(struct smb_sopt));
  140         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
  141         if (error)
  142                 return error;
  143         smb_rq_getrequest(rqp, &mbp);
  144         smb_rq_wstart(rqp);
  145         smb_rq_wend(rqp);
  146         smb_rq_bstart(rqp);
  147         for(dp = smb_dialects; dp->d_id != -1; dp++) {
  148                 mb_put_uint8(mbp, SMB_DT_DIALECT);
  149                 smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE);
  150         }
  151         smb_rq_bend(rqp);
  152         error = smb_rq_simple(rqp);
  153         SMBSDEBUG("%d\n", error);
  154         if (error)
  155                 goto bad;
  156         smb_rq_getreply(rqp, &mdp);
  157         do {
  158                 error = md_get_uint8(mdp, &wc);
  159                 if (error)
  160                         break;
  161                 error = md_get_uint16le(mdp, &dindex);
  162                 if (error)
  163                         break;
  164                 if (dindex > 7) {
  165                         SMBERROR("Don't know how to talk with server %s (%d)\n", "xxx", dindex);
  166                         error = EBADRPC;
  167                         break;
  168                 }
  169                 dp = smb_dialects + dindex;
  170                 sp->sv_proto = dp->d_id;
  171                 SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc);
  172                 error = EBADRPC;
  173                 if (dp->d_id >= SMB_DIALECT_NTLM0_12) {
  174                         if (wc != 17)
  175                                 break;
  176                         md_get_uint8(mdp, &sp->sv_sm);
  177                         md_get_uint16le(mdp, &sp->sv_maxmux);
  178                         md_get_uint16le(mdp, &sp->sv_maxvcs);
  179                         md_get_uint32le(mdp, &sp->sv_maxtx);
  180                         md_get_uint32le(mdp, &sp->sv_maxraw);
  181                         md_get_uint32le(mdp, &sp->sv_skey);
  182                         md_get_uint32le(mdp, &sp->sv_caps);
  183                         md_get_mem(mdp, stime, 8, MB_MSYSTEM);
  184                         md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
  185                         md_get_uint8(mdp, &sblen);
  186                         if (sblen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
  187                                 if (sblen != SMB_MAXCHALLENGELEN) {
  188                                         SMBERROR("Unexpected length of security blob (%d)\n", sblen);
  189                                         break;
  190                                 }
  191                                 error = md_get_uint16le(mdp, &bc);
  192                                 if (error)
  193                                         break;
  194                                 if (sp->sv_caps & SMB_CAP_EXT_SECURITY)
  195                                         md_get_mem(mdp, NULL, 16, MB_MSYSTEM);
  196                                 error = md_get_mem(mdp, vcp->vc_ch, sblen, MB_MSYSTEM);
  197                                 if (error)
  198                                         break;
  199                                 vcp->vc_chlen = sblen;
  200                                 vcp->obj.co_flags |= SMBV_ENCRYPT;
  201                         }
  202                         if (sp->sv_sm & SMB_SM_SIGS_REQUIRE)
  203                                 vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
  204                         if (vcp->vc_ucs_toserver &&
  205                                 sp->sv_caps & SMB_CAP_UNICODE) {
  206                                 /*
  207                                 * They do Unicode.
  208                                 */
  209                                 vcp->obj.co_flags |= SMBV_UNICODE;
  210                         }
  211                         vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
  212                         if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
  213                             sp->sv_maxtx < 4096 &&
  214                             (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
  215                                 vcp->obj.co_flags |= SMBV_WIN95;
  216                                 SMBSDEBUG("Win95 detected\n");
  217                         }
  218                         error = 0;
  219                         break;
  220                 }
  221                 vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS|
  222                                      SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE);
  223                 unicode = 0;
  224                 if (dp->d_id > SMB_DIALECT_CORE) {
  225                         md_get_uint16le(mdp, &tw);
  226                         sp->sv_sm = tw;
  227                         md_get_uint16le(mdp, &tw);
  228                         sp->sv_maxtx = tw;
  229                         md_get_uint16le(mdp, &sp->sv_maxmux);
  230                         md_get_uint16le(mdp, &sp->sv_maxvcs);
  231                         md_get_uint16le(mdp, &tw);      /* rawmode */
  232                         md_get_uint32le(mdp, &sp->sv_skey);
  233                         if (wc == 13) {         /* >= LANMAN1 */
  234                                 md_get_uint16(mdp, &tw);                /* time */
  235                                 md_get_uint16(mdp, &tw1);               /* date */
  236                                 md_get_uint16le(mdp, (u_int16_t*)&sp->sv_tz);
  237                                 md_get_uint16le(mdp, &swlen);
  238                                 if (swlen > SMB_MAXCHALLENGELEN)
  239                                         break;
  240                                 md_get_uint16(mdp, NULL);       /* mbz */
  241                                 if (md_get_uint16le(mdp, &bc) != 0)
  242                                         break;
  243                                 if (bc < swlen)
  244                                         break;
  245                                 if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
  246                                         error = md_get_mem(mdp, vcp->vc_ch, swlen, MB_MSYSTEM);
  247                                         if (error)
  248                                                 break;
  249                                         vcp->vc_chlen = swlen;
  250                                         vcp->obj.co_flags |= SMBV_ENCRYPT;
  251                                 }
  252                         }
  253                         vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
  254                 } else {        /* an old CORE protocol */
  255                         sp->sv_maxmux = 1;
  256                 }
  257                 error = 0;
  258         } while (0);
  259         if (error == 0) {
  260                 vcp->vc_maxvcs = sp->sv_maxvcs;
  261                 if (vcp->vc_maxvcs <= 1) {
  262                         if (vcp->vc_maxvcs == 0)
  263                                 vcp->vc_maxvcs = 1;
  264                 }
  265                 if (sp->sv_maxtx <= 0 || sp->sv_maxtx > 0xffff)
  266                         sp->sv_maxtx = 1024;
  267                 else
  268                         sp->sv_maxtx = min(sp->sv_maxtx,
  269                                            63*1024 + SMB_HDRLEN + 16);
  270                 SMB_TRAN_GETPARAM(vcp, SMBTP_RCVSZ, &maxqsz);
  271                 vcp->vc_rxmax = min(smb_vc_maxread(vcp), maxqsz - 1024);
  272                 SMB_TRAN_GETPARAM(vcp, SMBTP_SNDSZ, &maxqsz);
  273                 vcp->vc_wxmax = min(smb_vc_maxwrite(vcp), maxqsz - 1024);
  274                 vcp->vc_txmax = min(sp->sv_maxtx, maxqsz);
  275                 SMBSDEBUG("TZ = %d\n", sp->sv_tz);
  276                 SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
  277                 SMBSDEBUG("MAXMUX = %d\n", sp->sv_maxmux);
  278                 SMBSDEBUG("MAXVCS = %d\n", sp->sv_maxvcs);
  279                 SMBSDEBUG("MAXRAW = %d\n", sp->sv_maxraw);
  280                 SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx);
  281         }
  282 bad:
  283         /* Restore Unicode conversion state */
  284         if (unicode) {
  285                 vcp->vc_toserver = servercharset;
  286                 vcp->vc_tolocal  = localcharset;
  287                 vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
  288         }
  289         smb_rq_done(rqp);
  290         return error;
  291 }
  292 
  293 int
  294 smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
  295 {
  296         struct smb_rq *rqp;
  297         struct mbchain *mbp;
  298 /*      u_int8_t wc;
  299         u_int16_t tw, tw1;*/
  300         smb_uniptr unipp, ntencpass = NULL;
  301         char *pp, *up, *pbuf, *encpass;
  302         int error, plen, uniplen, ulen, upper;
  303         u_int32_t caps = 0;
  304 
  305         upper = 0;
  306 
  307         if (vcp->obj.co_flags & SMBV_UNICODE)
  308                 caps |= SMB_CAP_UNICODE;
  309 
  310 again:
  311 
  312         vcp->vc_smbuid = SMB_UID_UNKNOWN;
  313 
  314         if (smb_smb_nomux(vcp, scred, __func__) != 0)
  315                 return EINVAL;
  316 
  317         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX, scred, &rqp);
  318         if (error)
  319                 return error;
  320         pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
  321         encpass = malloc(24, M_SMBTEMP, M_WAITOK);
  322         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
  323                 /*
  324                  * We try w/o uppercasing first so Samba mixed case
  325                  * passwords work.  If that fails we come back and try
  326                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
  327                  */
  328                 if (upper++) {
  329                         iconv_convstr(vcp->vc_toupper, pbuf,
  330                                       smb_vc_getpass(vcp)/*, SMB_MAXPASSWORDLEN*/);
  331                 } else {
  332                         strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
  333                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
  334                 }
  335                 if (!SMB_UNICODE_STRINGS(vcp))
  336                         iconv_convstr(vcp->vc_toserver, pbuf, pbuf/*,
  337                                       SMB_MAXPASSWORDLEN*/);
  338 
  339                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
  340                         uniplen = plen = 24;
  341                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
  342                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
  343                         if (SMB_UNICODE_STRINGS(vcp)) {
  344                                 strncpy(pbuf, smb_vc_getpass(vcp),
  345                                         SMB_MAXPASSWORDLEN);
  346                                 pbuf[SMB_MAXPASSWORDLEN] = '\0';
  347                         } else
  348                                 iconv_convstr(vcp->vc_toserver, pbuf,
  349                                               smb_vc_getpass(vcp)/*,
  350                                               SMB_MAXPASSWORDLEN*/);
  351                         smb_ntencrypt(pbuf, vcp->vc_ch, (u_char*)ntencpass);
  352                         pp = encpass;
  353                         unipp = ntencpass;
  354                 } else {
  355                         plen = strlen(pbuf) + 1;
  356                         pp = pbuf;
  357                         uniplen = plen * 2;
  358                         ntencpass = malloc(uniplen, M_SMBTEMP, M_WAITOK);
  359                         smb_strtouni(ntencpass, smb_vc_getpass(vcp));
  360                         plen--;
  361 
  362                         /*
  363                          * The uniplen is zeroed because Samba cannot deal
  364                          * with this 2nd cleartext password.  This Samba
  365                          * "bug" is actually a workaround for problems in
  366                          * Microsoft clients.
  367                          */
  368                         uniplen = 0/*-= 2*/;
  369                         unipp = ntencpass;
  370                 }
  371         } else {
  372                 /*
  373                  * In the share security mode password will be used
  374                  * only in the tree authentication
  375                  */
  376                  pp = "";
  377                  plen = 1;
  378                  unipp = &smb_unieol;
  379                  uniplen = 0 /* sizeof(smb_unieol) */;
  380         }
  381         smb_rq_wstart(rqp);
  382         mbp = &rqp->sr_rq;
  383         up = vcp->vc_username;
  384         ulen = strlen(up) + 1;
  385         /*
  386          * If userid is null we are attempting anonymous browse login
  387          * so passwords must be zero length.
  388          */
  389         if (ulen == 1)
  390                 plen = uniplen = 0;
  391         mb_put_uint8(mbp, 0xff);
  392         mb_put_uint8(mbp, 0);
  393         mb_put_uint16le(mbp, 0);
  394         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
  395         mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
  396         mb_put_uint16le(mbp, vcp->vc_number);
  397         mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
  398         mb_put_uint16le(mbp, plen);
  399         if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
  400                 mb_put_uint32le(mbp, 0);
  401                 smb_rq_wend(rqp);
  402                 smb_rq_bstart(rqp);
  403                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
  404                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);
  405         } else {
  406                 mb_put_uint16le(mbp, uniplen);
  407                 mb_put_uint32le(mbp, 0);                /* reserved */
  408                 mb_put_uint32le(mbp, caps);
  409                 smb_rq_wend(rqp);
  410                 smb_rq_bstart(rqp);
  411                 mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
  412                 mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
  413                 smb_put_dstring(mbp, vcp, up, SMB_CS_NONE);             /* AccountName */
  414                 smb_put_dstring(mbp, vcp, vcp->vc_domain, SMB_CS_NONE); /* PrimaryDomain */
  415                 smb_put_dstring(mbp, vcp, "FreeBSD", SMB_CS_NONE);      /* Client's OS */
  416                 smb_put_dstring(mbp, vcp, "NETSMB", SMB_CS_NONE);               /* Client name */
  417         }
  418         smb_rq_bend(rqp);
  419         if (ntencpass)
  420                 free(ntencpass, M_SMBTEMP);
  421         if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
  422                 smb_calcmackey(vcp);
  423         error = smb_rq_simple(rqp);
  424         SMBSDEBUG("%d\n", error);
  425         if (error) {
  426                 if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnoaccess)
  427                         error = EAUTH;
  428                 goto bad;
  429         }
  430         vcp->vc_smbuid = rqp->sr_rpuid;
  431 bad:
  432         free(encpass, M_SMBTEMP);
  433         free(pbuf, M_SMBTEMP);
  434         smb_rq_done(rqp);
  435         if (error && upper == 1 && vcp->vc_sopt.sv_sm & SMB_SM_USER)
  436                 goto again;
  437         return error;
  438 }
  439 
  440 int
  441 smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
  442 {
  443         struct smb_rq *rqp;
  444         struct mbchain *mbp;
  445         int error;
  446 
  447         if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
  448                 return 0;
  449 
  450         if (smb_smb_nomux(vcp, scred, __func__) != 0)
  451                 return EINVAL;
  452 
  453         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
  454         if (error)
  455                 return error;
  456         mbp = &rqp->sr_rq;
  457         smb_rq_wstart(rqp);
  458         mb_put_uint8(mbp, 0xff);
  459         mb_put_uint8(mbp, 0);
  460         mb_put_uint16le(mbp, 0);
  461         smb_rq_wend(rqp);
  462         smb_rq_bstart(rqp);
  463         smb_rq_bend(rqp);
  464         error = smb_rq_simple(rqp);
  465         SMBSDEBUG("%d\n", error);
  466         smb_rq_done(rqp);
  467         return error;
  468 }
  469 
  470 static char smb_any_share[] = "?????";
  471 
  472 static char *
  473 smb_share_typename(int stype)
  474 {
  475         char *pp;
  476 
  477         switch (stype) {
  478             case SMB_ST_DISK:
  479                 pp = "A:";
  480                 break;
  481             case SMB_ST_PRINTER:
  482                 pp = smb_any_share;             /* can't use LPT: here... */
  483                 break;
  484             case SMB_ST_PIPE:
  485                 pp = "IPC";
  486                 break;
  487             case SMB_ST_COMM:
  488                 pp = "COMM";
  489                 break;
  490             case SMB_ST_ANY:
  491             default:
  492                 pp = smb_any_share;
  493                 break;
  494         }
  495         return pp;
  496 }
  497 
  498 int
  499 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
  500 {
  501         struct smb_vc *vcp;
  502         struct smb_rq rq, *rqp = &rq;
  503         struct mbchain *mbp;
  504         char *pp, *pbuf, *encpass;
  505         int error, plen, caseopt, upper;
  506 
  507         upper = 0;
  508 
  509 again:
  510         /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */
  511         if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) {
  512                 vcp = SSTOVC(ssp);
  513                 vcp->vc_toserver = vcp->vc_cp_toserver;
  514                 vcp->vc_tolocal = vcp->vc_cp_tolocal;
  515                 vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
  516         }
  517 
  518         ssp->ss_tid = SMB_TID_UNKNOWN;
  519         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp);
  520         if (error)
  521                 return error;
  522         vcp = rqp->sr_vc;
  523         caseopt = SMB_CS_NONE;
  524         if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
  525                 plen = 1;
  526                 pp = "";
  527                 pbuf = NULL;
  528                 encpass = NULL;
  529         } else {
  530                 pbuf = malloc(SMB_MAXPASSWORDLEN + 1, M_SMBTEMP, M_WAITOK);
  531                 encpass = malloc(24, M_SMBTEMP, M_WAITOK);
  532                 /*
  533                  * We try w/o uppercasing first so Samba mixed case
  534                  * passwords work.  If that fails we come back and try
  535                  * uppercasing to satisfy OS/2 and Windows for Workgroups.
  536                  */
  537                 if (upper++) {
  538                         iconv_convstr(vcp->vc_toupper, pbuf,
  539                                       smb_share_getpass(ssp)/*,
  540                                       SMB_MAXPASSWORDLEN*/);
  541                 } else {
  542                         strncpy(pbuf, smb_share_getpass(ssp),
  543                                 SMB_MAXPASSWORDLEN);
  544                         pbuf[SMB_MAXPASSWORDLEN] = '\0';
  545                 }
  546                 if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
  547                         plen = 24;
  548                         smb_encrypt(pbuf, vcp->vc_ch, encpass);
  549                         pp = encpass;
  550                 } else {
  551                         plen = strlen(pbuf) + 1;
  552                         pp = pbuf;
  553                 }
  554         }
  555         mbp = &rqp->sr_rq;
  556         smb_rq_wstart(rqp);
  557         mb_put_uint8(mbp, 0xff);
  558         mb_put_uint8(mbp, 0);
  559         mb_put_uint16le(mbp, 0);
  560         mb_put_uint16le(mbp, 0);                /* Flags */
  561         mb_put_uint16le(mbp, plen);
  562         smb_rq_wend(rqp);
  563         smb_rq_bstart(rqp);
  564         mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
  565         smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt);
  566         pp = vcp->vc_srvname;
  567         smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt);
  568         smb_put_dmem(mbp, vcp, "\\", 1, caseopt);
  569         pp = ssp->ss_name;
  570         smb_put_dstring(mbp, vcp, pp, caseopt);
  571         pp = smb_share_typename(ssp->ss_type);
  572         smb_put_dstring(mbp, vcp, pp, caseopt);
  573         smb_rq_bend(rqp);
  574         error = smb_rq_simple(rqp);
  575         SMBSDEBUG("%d\n", error);
  576         if (error)
  577                 goto bad;
  578         ssp->ss_tid = rqp->sr_rptid;
  579         ssp->ss_vcgenid = vcp->vc_genid;
  580         ssp->ss_flags |= SMBS_CONNECTED;
  581         /*
  582          * If the server can speak Unicode then switch
  583          * our converters to do Unicode <--> Local
  584          */
  585         if (vcp->obj.co_flags & SMBV_UNICODE) {
  586                 vcp->vc_toserver = vcp->vc_ucs_toserver;
  587                 vcp->vc_tolocal = vcp->vc_ucs_tolocal;
  588                 vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
  589         }
  590 bad:
  591         if (encpass)
  592                 free(encpass, M_SMBTEMP);
  593         if (pbuf)
  594                 free(pbuf, M_SMBTEMP);
  595         smb_rq_done(rqp);
  596         if (error && upper == 1)
  597                 goto again;
  598         return error;
  599 }
  600 
  601 int
  602 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
  603 {
  604         struct smb_rq *rqp;
  605         int error;
  606 
  607         if (ssp->ss_tid == SMB_TID_UNKNOWN)
  608                 return 0;
  609         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
  610         if (error)
  611                 return error;
  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: 1ad5e3c8ba661a8c7412ef2d21df18dc


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