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 #define SMB_DIALECT_MAX (sizeof(smb_dialects) / sizeof(struct smb_dialect) - 2)
   72 
   73 static u_int32_t
   74 smb_vc_maxread(struct smb_vc *vcp)
   75 {
   76         /*
   77          * Specs say up to 64k data bytes, but Windows traffic
   78          * uses 60k... no doubt for some good reason.
   79          *
   80          * Don't exceed the server's buffer size if signatures
   81          * are enabled otherwise Windows 2003 chokes. Allow space
   82          * for the SMB header & a little bit extra.
   83          */
   84         if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) &&
   85             (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
   86                 return (60*1024);
   87         else
   88                 return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
   89 }
   90 
   91 static u_int32_t
   92 smb_vc_maxwrite(struct smb_vc *vcp)
   93 {
   94         /*
   95          * See comment above.
   96          */
   97         if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) &&
   98             (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0)
   99                 return (60*1024);
  100         else
  101                 return (vcp->vc_sopt.sv_maxtx - SMB_HDRLEN - 64);
  102 }
  103 
  104 static int
  105 smb_smb_nomux(struct smb_vc *vcp, struct smb_cred *scred, const char *name)
  106 {
  107         if (scred->scr_td->td_proc == vcp->vc_iod->iod_p)
  108                 return 0;
  109         SMBERROR("wrong function called(%s)\n", name);
  110         return EINVAL;
  111 }
  112 
  113 int
  114 smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
  115 {
  116         struct smb_dialect *dp;
  117         struct smb_sopt *sp = NULL;
  118         struct smb_rq *rqp;
  119         struct mbchain *mbp;
  120         struct mdchain *mdp;
  121         u_int8_t wc, stime[8], sblen;
  122         u_int16_t dindex, tw, tw1, swlen, bc;
  123         int error, maxqsz;
  124         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         struct mbchain *mbp;
  606         int error;
  607 
  608         if (ssp->ss_tid == SMB_TID_UNKNOWN)
  609                 return 0;
  610         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
  611         if (error)
  612                 return error;
  613         mbp = &rqp->sr_rq;
  614         smb_rq_wstart(rqp);
  615         smb_rq_wend(rqp);
  616         smb_rq_bstart(rqp);
  617         smb_rq_bend(rqp);
  618         error = smb_rq_simple(rqp);
  619         SMBSDEBUG("%d\n", error);
  620         smb_rq_done(rqp);
  621         ssp->ss_tid = SMB_TID_UNKNOWN;
  622         return error;
  623 }
  624 
  625 static __inline int
  626 smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
  627               struct uio *uio, struct smb_cred *scred)
  628 {
  629         struct smb_rq *rqp;
  630         struct mbchain *mbp;
  631         struct mdchain *mdp;
  632         u_int8_t wc;
  633         int error;
  634         u_int16_t residhi, residlo, off, doff;
  635         u_int32_t resid;
  636 
  637         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
  638         if (error)
  639                 return error;
  640         smb_rq_getrequest(rqp, &mbp);
  641         smb_rq_wstart(rqp);
  642         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  643         mb_put_uint8(mbp, 0);           /* MBZ */
  644         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  645         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  646         mb_put_uint32le(mbp, uio->uio_offset);
  647         *len = min(SSTOVC(ssp)->vc_rxmax, *len);
  648         mb_put_uint16le(mbp, *len);     /* MaxCount */
  649         mb_put_uint16le(mbp, *len);     /* MinCount (only indicates blocking) */
  650         mb_put_uint32le(mbp, (unsigned)*len >> 16);     /* MaxCountHigh */
  651         mb_put_uint16le(mbp, *len);     /* Remaining ("obsolete") */
  652         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  653         smb_rq_wend(rqp);
  654         smb_rq_bstart(rqp);
  655         smb_rq_bend(rqp);
  656         do {
  657                 error = smb_rq_simple(rqp);
  658                 if (error)
  659                         break;
  660                 smb_rq_getreply(rqp, &mdp);
  661                 off = SMB_HDRLEN;
  662                 md_get_uint8(mdp, &wc);
  663                 off++;
  664                 if (wc != 12) {
  665                         error = EBADRPC;
  666                         break;
  667                 }
  668                 md_get_uint8(mdp, NULL);
  669                 off++;
  670                 md_get_uint8(mdp, NULL);
  671                 off++;
  672                 md_get_uint16le(mdp, NULL);
  673                 off += 2;
  674                 md_get_uint16le(mdp, NULL);
  675                 off += 2;
  676                 md_get_uint16le(mdp, NULL);     /* data compaction mode */
  677                 off += 2;
  678                 md_get_uint16le(mdp, NULL);
  679                 off += 2;
  680                 md_get_uint16le(mdp, &residlo);
  681                 off += 2;
  682                 md_get_uint16le(mdp, &doff);    /* data offset */
  683                 off += 2;
  684                 md_get_uint16le(mdp, &residhi);
  685                 off += 2;
  686                 resid = (residhi << 16) | residlo;
  687                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  688                 off += 4*2;
  689                 md_get_uint16le(mdp, NULL);     /* ByteCount */
  690                 off += 2;
  691                 if (doff > off) /* pad byte(s)? */
  692                         md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
  693                 if (resid == 0) {
  694                         *rresid = resid;
  695                         break;
  696                 }
  697                 error = md_get_uio(mdp, uio, resid);
  698                 if (error)
  699                         break;
  700                 *rresid = resid;
  701         } while(0);
  702         smb_rq_done(rqp);
  703         return (error);
  704 }
  705 
  706 static __inline int
  707 smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
  708         struct uio *uio, struct smb_cred *scred)
  709 {
  710         struct smb_rq *rqp;
  711         struct mbchain *mbp;
  712         struct mdchain *mdp;
  713         int error;
  714         u_int8_t wc;
  715         u_int16_t resid;
  716 
  717         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
  718         if (error)
  719                 return (error);
  720         smb_rq_getrequest(rqp, &mbp);
  721         smb_rq_wstart(rqp);
  722         mb_put_uint8(mbp, 0xff);        /* no secondary command */
  723         mb_put_uint8(mbp, 0);           /* MBZ */
  724         mb_put_uint16le(mbp, 0);        /* offset to secondary */
  725         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  726         mb_put_uint32le(mbp, uio->uio_offset);
  727         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
  728         mb_put_uint16le(mbp, 0);        /* !write-thru */
  729         mb_put_uint16le(mbp, 0);
  730         *len = min(SSTOVC(ssp)->vc_wxmax, *len);
  731         mb_put_uint16le(mbp, (unsigned)*len >> 16);
  732         mb_put_uint16le(mbp, *len);
  733         mb_put_uint16le(mbp, 64);       /* data offset from header start */
  734         mb_put_uint32le(mbp, uio->uio_offset >> 32);    /* OffsetHigh */
  735         smb_rq_wend(rqp);
  736         smb_rq_bstart(rqp);
  737         do {
  738                 mb_put_uint8(mbp, 0xee);        /* mimic xp pad byte! */
  739                 error = mb_put_uio(mbp, uio, *len);
  740                 if (error)
  741                         break;
  742                 smb_rq_bend(rqp);
  743                 error = smb_rq_simple(rqp);
  744                 if (error)
  745                         break;
  746                 smb_rq_getreply(rqp, &mdp);
  747                 md_get_uint8(mdp, &wc);
  748                 if (wc != 6) {
  749                         error = EBADRPC;
  750                         break;
  751                 }
  752                 md_get_uint8(mdp, NULL);
  753                 md_get_uint8(mdp, NULL);
  754                 md_get_uint16le(mdp, NULL);
  755                 md_get_uint16le(mdp, &resid);
  756                 *rresid = resid;
  757         } while(0);
  758 
  759         smb_rq_done(rqp);
  760         return (error);
  761 }
  762 
  763 static __inline int
  764 smb_smb_read(struct smb_share *ssp, u_int16_t fid,
  765         int *len, int *rresid, struct uio *uio, struct smb_cred *scred)
  766 {
  767         struct smb_rq *rqp;
  768         struct mbchain *mbp;
  769         struct mdchain *mdp;
  770         u_int16_t resid, bc;
  771         u_int8_t wc;
  772         int error, rlen, blksz;
  773 
  774         if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
  775                 return (smb_smb_readx(ssp, fid, len, rresid, uio, scred));
  776 
  777         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
  778         if (error)
  779                 return error;
  780 
  781         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
  782         rlen = *len = min(blksz, *len);
  783 
  784         smb_rq_getrequest(rqp, &mbp);
  785         smb_rq_wstart(rqp);
  786         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  787         mb_put_uint16le(mbp, rlen);
  788         mb_put_uint32le(mbp, uio->uio_offset);
  789         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
  790         smb_rq_wend(rqp);
  791         smb_rq_bstart(rqp);
  792         smb_rq_bend(rqp);
  793         do {
  794                 error = smb_rq_simple(rqp);
  795                 if (error)
  796                         break;
  797                 smb_rq_getreply(rqp, &mdp);
  798                 md_get_uint8(mdp, &wc);
  799                 if (wc != 5) {
  800                         error = EBADRPC;
  801                         break;
  802                 }
  803                 md_get_uint16le(mdp, &resid);
  804                 md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
  805                 md_get_uint16le(mdp, &bc);
  806                 md_get_uint8(mdp, NULL);                /* ignore buffer type */
  807                 md_get_uint16le(mdp, &resid);
  808                 if (resid == 0) {
  809                         *rresid = resid;
  810                         break;
  811                 }
  812                 error = md_get_uio(mdp, uio, resid);
  813                 if (error)
  814                         break;
  815                 *rresid = resid;
  816         } while(0);
  817         smb_rq_done(rqp);
  818         return error;
  819 }
  820 
  821 int
  822 smb_read(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
  823         struct smb_cred *scred)
  824 {
  825         int tsize, len, resid;
  826         int error = 0;
  827 
  828         tsize = uio->uio_resid;
  829         while (tsize > 0) {
  830                 resid = 0;
  831                 len = tsize;
  832                 error = smb_smb_read(ssp, fid, &len, &resid, uio, scred);
  833                 if (error)
  834                         break;
  835                 tsize -= resid;
  836                 if (resid < len)
  837                         break;
  838         }
  839         return error;
  840 }
  841 
  842 static __inline int
  843 smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
  844         struct uio *uio, struct smb_cred *scred)
  845 {
  846         struct smb_rq *rqp;
  847         struct mbchain *mbp;
  848         struct mdchain *mdp;
  849         u_int16_t resid;
  850         u_int8_t wc;
  851         int error, blksz;
  852 
  853         if (*len && SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
  854                 return (smb_smb_writex(ssp, fid, len, rresid, uio, scred));
  855  
  856         blksz = SSTOVC(ssp)->vc_txmax - SMB_HDRLEN - 16;
  857         if (blksz > 0xffff)
  858                 blksz = 0xffff;
  859 
  860         resid = *len = min(blksz, *len);
  861 
  862         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
  863         if (error)
  864                 return error;
  865         smb_rq_getrequest(rqp, &mbp);
  866         smb_rq_wstart(rqp);
  867         mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
  868         mb_put_uint16le(mbp, resid);
  869         mb_put_uint32le(mbp, uio->uio_offset);
  870         mb_put_uint16le(mbp, min(uio->uio_resid, 0xffff));
  871         smb_rq_wend(rqp);
  872         smb_rq_bstart(rqp);
  873         mb_put_uint8(mbp, SMB_DT_DATA);
  874         mb_put_uint16le(mbp, resid);
  875         do {
  876                 error = mb_put_uio(mbp, uio, resid);
  877                 if (error)
  878                         break;
  879                 smb_rq_bend(rqp);
  880                 error = smb_rq_simple(rqp);
  881                 if (error)
  882                         break;
  883                 smb_rq_getreply(rqp, &mdp);
  884                 md_get_uint8(mdp, &wc);
  885                 if (wc != 1) {
  886                         error = EBADRPC;
  887                         break;
  888                 }
  889                 md_get_uint16le(mdp, &resid);
  890                 *rresid = resid;
  891         } while(0);
  892         smb_rq_done(rqp);
  893         return error;
  894 }
  895 
  896 int
  897 smb_write(struct smb_share *ssp, u_int16_t fid, struct uio *uio,
  898         struct smb_cred *scred)
  899 {
  900         int error = 0, len, tsize, resid;
  901         struct uio olduio;
  902 
  903         tsize = uio->uio_resid;
  904         olduio = *uio;
  905         while (tsize > 0) {
  906                 resid = 0;
  907                 len = tsize;
  908                 error = smb_smb_write(ssp, fid, &len, &resid, uio, scred);
  909                 if (error)
  910                         break;
  911                 if (resid < len) {
  912                         error = EIO;
  913                         break;
  914                 }
  915                 tsize -= resid;
  916         }
  917         if (error) {
  918                 /*
  919                  * Errors can happen on the copyin, the rpc, etc.  So they
  920                  * imply resid is unreliable.  The only safe thing is
  921                  * to pretend zero bytes made it.  We needn't restore the
  922                  * iovs because callers don't depend on them in error
  923                  * paths - uio_resid and uio_offset are what matter.
  924                  */
  925                 *uio = olduio;
  926         }
  927         return error;
  928 }
  929 
  930 int
  931 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred)
  932 {
  933         struct smb_rq *rqp;
  934         struct mbchain *mbp;
  935         int error;
  936 
  937         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
  938         if (error)
  939                 return error;
  940         mbp = &rqp->sr_rq;
  941         smb_rq_wstart(rqp);
  942         mb_put_uint16le(mbp, 1);
  943         smb_rq_wend(rqp);
  944         smb_rq_bstart(rqp);
  945         mb_put_uint32le(mbp, 0);
  946         smb_rq_bend(rqp);
  947         error = smb_rq_simple(rqp);
  948         SMBSDEBUG("%d\n", error);
  949         smb_rq_done(rqp);
  950         return error;
  951 }

Cache object: c5defa7479d3863d81247dd39b6afd01


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