The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netsmb/smb_smb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: a2508e03de380f6675f2741d2436ada1


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