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_conn.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  * Connection engine.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/10.3/sys/netsmb/smb_conn.c 291655 2015-12-02 21:48:34Z rmacklem $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 #include <sys/priv.h>
   39 #include <sys/proc.h>
   40 #include <sys/lock.h>
   41 #include <sys/sysctl.h>
   42 #include <sys/socketvar.h>
   43 
   44 #include <sys/iconv.h>
   45 
   46 #include <netsmb/smb.h>
   47 #include <netsmb/smb_subr.h>
   48 #include <netsmb/smb_conn.h>
   49 #include <netsmb/smb_tran.h>
   50 #include <netsmb/smb_trantcp.h>
   51 
   52 static struct smb_connobj smb_vclist;
   53 static int smb_vcnext = 1;      /* next unique id for VC */
   54 
   55 SYSCTL_NODE(_net, OID_AUTO, smb, CTLFLAG_RW, NULL, "SMB protocol");
   56 
   57 static MALLOC_DEFINE(M_SMBCONN, "smb_conn", "SMB connection");
   58 
   59 static void smb_co_init(struct smb_connobj *cp, int level, char *ilockname,
   60     char *lockname);
   61 static void smb_co_done(struct smb_connobj *cp);
   62 static int  smb_vc_disconnect(struct smb_vc *vcp);
   63 static void smb_vc_free(struct smb_connobj *cp);
   64 static void smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred);
   65 static smb_co_free_t smb_share_free;
   66 static smb_co_gone_t smb_share_gone;
   67 
   68 static int  smb_sysctl_treedump(SYSCTL_HANDLER_ARGS);
   69 
   70 SYSCTL_PROC(_net_smb, OID_AUTO, treedump, CTLFLAG_RD | CTLTYPE_OPAQUE,
   71             NULL, 0, smb_sysctl_treedump, "S,treedump", "Requester tree");
   72 
   73 int
   74 smb_sm_init(void)
   75 {
   76 
   77         smb_co_init(&smb_vclist, SMBL_SM, "smbsm ilock", "smbsm");
   78         sx_xlock(&smb_vclist.co_interlock);
   79         smb_co_unlock(&smb_vclist);
   80         sx_unlock(&smb_vclist.co_interlock);
   81         return 0;
   82 }
   83 
   84 int
   85 smb_sm_done(void)
   86 {
   87 
   88         /* XXX: hold the mutex */
   89         if (smb_vclist.co_usecount > 1) {
   90                 SMBERROR("%d connections still active\n", smb_vclist.co_usecount - 1);
   91                 return EBUSY;
   92         }
   93         smb_co_done(&smb_vclist);
   94         return 0;
   95 }
   96 
   97 static int
   98 smb_sm_lockvclist(void)
   99 {
  100         int error;
  101 
  102         sx_xlock(&smb_vclist.co_interlock);
  103         error = smb_co_lock(&smb_vclist);
  104         sx_unlock(&smb_vclist.co_interlock);
  105 
  106         return error;
  107 }
  108 
  109 static void
  110 smb_sm_unlockvclist(void)
  111 {
  112 
  113         sx_xlock(&smb_vclist.co_interlock);
  114         smb_co_unlock(&smb_vclist);
  115         sx_unlock(&smb_vclist.co_interlock);
  116 }
  117 
  118 static int
  119 smb_sm_lookupint(struct smb_vcspec *vcspec, struct smb_sharespec *shspec,
  120         struct smb_cred *scred, struct smb_vc **vcpp)
  121 {
  122         struct smb_connobj *scp;
  123         struct smb_vc *vcp;
  124         int exact = 1;
  125         int error;
  126 
  127         vcspec->shspec = shspec;
  128         error = ENOENT;
  129         vcp = NULL;
  130         SMBCO_FOREACH(scp, &smb_vclist) {
  131                 vcp = (struct smb_vc *)scp;
  132                 error = smb_vc_lock(vcp);
  133                 if (error)
  134                         continue;
  135 
  136                 if ((vcp->obj.co_flags & SMBV_PRIVATE) ||
  137                     !CONNADDREQ(vcp->vc_paddr, vcspec->sap) ||
  138                     strcmp(vcp->vc_username, vcspec->username) != 0)
  139                         goto err1;
  140                 if (vcspec->owner != SMBM_ANY_OWNER) {
  141                         if (vcp->vc_uid != vcspec->owner)
  142                                 goto err1;
  143                 } else
  144                         exact = 0;
  145                 if (vcspec->group != SMBM_ANY_GROUP) {
  146                         if (vcp->vc_grp != vcspec->group)
  147                                 goto err1;
  148                 } else
  149                         exact = 0;
  150                 if (vcspec->mode & SMBM_EXACT) {
  151                         if (!exact || (vcspec->mode & SMBM_MASK) !=
  152                             vcp->vc_mode)
  153                                 goto err1;
  154                 }
  155                 if (smb_vc_access(vcp, scred, vcspec->mode) != 0)
  156                         goto err1;
  157                 vcspec->ssp = NULL;
  158                 if (shspec) {
  159                         error = (int)smb_vc_lookupshare(vcp, shspec, scred,
  160                             &vcspec->ssp);
  161                         if (error)
  162                                 goto fail;
  163                 }
  164                 error = 0;
  165                 break;
  166         err1:
  167                 error = 1;
  168         fail:
  169                 smb_vc_unlock(vcp);
  170         }
  171         if (vcp) {
  172                 smb_vc_ref(vcp);
  173                 *vcpp = vcp;
  174         }
  175         return (error);
  176 }
  177 
  178 int
  179 smb_sm_lookup(struct smb_vcspec *vcspec, struct smb_sharespec *shspec,
  180         struct smb_cred *scred, struct smb_vc **vcpp)
  181 {
  182         struct smb_vc *vcp;
  183         struct smb_share *ssp = NULL;
  184         int error;
  185 
  186         *vcpp = vcp = NULL;
  187 
  188         error = smb_sm_lockvclist();
  189         if (error)
  190                 return error;
  191         error = smb_sm_lookupint(vcspec, shspec, scred, vcpp);
  192         if (error == 0 || (vcspec->flags & SMBV_CREATE) == 0) {
  193                 smb_sm_unlockvclist();
  194                 return error;
  195         }
  196         error = smb_sm_lookupint(vcspec, NULL, scred, &vcp);
  197         if (error) {
  198                 error = smb_vc_create(vcspec, scred, &vcp);
  199                 if (error)
  200                         goto out;
  201                 error = smb_vc_connect(vcp, scred);
  202                 if (error)
  203                         goto out;
  204         }
  205         if (shspec == NULL)
  206                 goto out;
  207         error = smb_share_create(vcp, shspec, scred, &ssp);
  208         if (error)
  209                 goto out;
  210         error = smb_smb_treeconnect(ssp, scred);
  211         if (error == 0)
  212                 vcspec->ssp = ssp;
  213         else
  214                 smb_share_put(ssp, scred);
  215 out:
  216         smb_sm_unlockvclist();
  217         if (error == 0)
  218                 *vcpp = vcp;
  219         else if (vcp) {
  220                 smb_vc_lock(vcp);
  221                 smb_vc_put(vcp, scred);
  222         }
  223         return error;
  224 }
  225 
  226 /*
  227  * Common code for connection object
  228  */
  229 static void
  230 smb_co_init(struct smb_connobj *cp, int level, char *ilockname, char *lockname)
  231 {
  232         SLIST_INIT(&cp->co_children);
  233         sx_init_flags(&cp->co_interlock, ilockname, SX_RECURSE);
  234         cv_init(&cp->co_lock, "smblock");
  235         cp->co_lockcnt = 0;
  236         cp->co_locker = NULL;
  237         cp->co_level = level;
  238         cp->co_usecount = 1;
  239         sx_xlock(&cp->co_interlock);
  240         smb_co_lock(cp);
  241         sx_unlock(&cp->co_interlock);
  242 }
  243 
  244 static void
  245 smb_co_done(struct smb_connobj *cp)
  246 {
  247 
  248         sx_destroy(&cp->co_interlock);
  249         cv_destroy(&cp->co_lock);
  250         cp->co_locker = NULL;
  251         cp->co_flags = 0;
  252         cp->co_lockcnt = 0;
  253 }
  254 
  255 static void
  256 smb_co_gone(struct smb_connobj *cp, struct smb_cred *scred)
  257 {
  258         struct smb_connobj *parent;
  259 
  260         if (cp->co_gone)
  261                 cp->co_gone(cp, scred);
  262         parent = cp->co_parent;
  263         if (parent) {
  264                 sx_xlock(&parent->co_interlock);
  265                 smb_co_lock(parent);
  266                 sx_unlock(&parent->co_interlock);
  267                 SLIST_REMOVE(&parent->co_children, cp, smb_connobj, co_next);
  268                 smb_co_put(parent, scred);
  269         }
  270         if (cp->co_free)
  271                 cp->co_free(cp);
  272 }
  273 
  274 void
  275 smb_co_ref(struct smb_connobj *cp)
  276 {
  277 
  278         sx_xlock(&cp->co_interlock);
  279         cp->co_usecount++;
  280         sx_unlock(&cp->co_interlock);
  281 }
  282 
  283 void
  284 smb_co_rele(struct smb_connobj *cp, struct smb_cred *scred)
  285 {
  286 
  287         sx_xlock(&cp->co_interlock);
  288         smb_co_unlock(cp);
  289         if (cp->co_usecount > 1) {
  290                 cp->co_usecount--;
  291                 sx_unlock(&cp->co_interlock);
  292                 return;
  293         }
  294         if (cp->co_usecount == 0) {
  295                 SMBERROR("negative use_count for object %d", cp->co_level);
  296                 sx_unlock(&cp->co_interlock);
  297                 return;
  298         }
  299         cp->co_usecount--;
  300         cp->co_flags |= SMBO_GONE;
  301         sx_unlock(&cp->co_interlock);
  302         smb_co_gone(cp, scred);
  303 }
  304 
  305 int
  306 smb_co_get(struct smb_connobj *cp, struct smb_cred *scred)
  307 {
  308         int error;
  309 
  310         MPASS(sx_xholder(&cp->co_interlock) == curthread);
  311         cp->co_usecount++;
  312         error = smb_co_lock(cp);
  313         if (error) 
  314                 cp->co_usecount--;
  315         return error;
  316 }
  317 
  318 void
  319 smb_co_put(struct smb_connobj *cp, struct smb_cred *scred)
  320 {
  321 
  322         sx_xlock(&cp->co_interlock);
  323         if (cp->co_usecount > 1) {
  324                 cp->co_usecount--;
  325         } else if (cp->co_usecount == 1) {
  326                 cp->co_usecount--;
  327                 cp->co_flags |= SMBO_GONE;
  328         } else {
  329                 SMBERROR("negative usecount");
  330         }
  331         smb_co_unlock(cp);
  332         sx_unlock(&cp->co_interlock);
  333         if ((cp->co_flags & SMBO_GONE) == 0)
  334                 return;
  335         smb_co_gone(cp, scred);
  336 }
  337 
  338 int
  339 smb_co_lock(struct smb_connobj *cp)
  340 {
  341 
  342         MPASS(sx_xholder(&cp->co_interlock) == curthread); 
  343         for (;;) {
  344                 if (cp->co_flags & SMBO_GONE)
  345                         return EINVAL;
  346                 if (cp->co_locker == NULL) {
  347                         cp->co_locker = curthread;
  348                         return 0;
  349                 }
  350                 if (cp->co_locker == curthread) {
  351                         cp->co_lockcnt++;
  352                         return 0;
  353                 }
  354                 cv_wait(&cp->co_lock, &cp->co_interlock);
  355         }
  356 }
  357 
  358 void
  359 smb_co_unlock(struct smb_connobj *cp)
  360 {
  361 
  362         MPASS(sx_xholder(&cp->co_interlock) == curthread); 
  363         MPASS(cp->co_locker == curthread);
  364         if (cp->co_lockcnt != 0) {
  365                 cp->co_lockcnt--;
  366                 return;
  367         }
  368         cp->co_locker = NULL;
  369         cv_signal(&cp->co_lock);
  370 }
  371 
  372 static void
  373 smb_co_addchild(struct smb_connobj *parent, struct smb_connobj *child)
  374 {
  375 
  376         smb_co_ref(parent);
  377         SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
  378         child->co_parent = parent;
  379 }
  380 
  381 /*
  382  * Session implementation
  383  */
  384 
  385 int
  386 smb_vc_create(struct smb_vcspec *vcspec,
  387         struct smb_cred *scred, struct smb_vc **vcpp)
  388 {
  389         struct smb_vc *vcp;
  390         struct ucred *cred = scred->scr_cred;
  391         uid_t uid = vcspec->owner;
  392         gid_t gid = vcspec->group;
  393         uid_t realuid = cred->cr_uid;
  394         char *domain = vcspec->domain;
  395         int error, isroot;
  396 
  397         isroot = smb_suser(cred) == 0;
  398         /*
  399          * Only superuser can create VCs with different uid and gid
  400          */
  401         if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot)
  402                 return EPERM;
  403         if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot)
  404                 return EPERM;
  405 
  406         vcp = smb_zmalloc(sizeof(*vcp), M_SMBCONN, M_WAITOK);
  407         smb_co_init(VCTOCP(vcp), SMBL_VC, "smb_vc ilock", "smb_vc");
  408         vcp->obj.co_free = smb_vc_free;
  409         vcp->obj.co_gone = smb_vc_gone;
  410         vcp->vc_number = smb_vcnext++;
  411         vcp->vc_timo = SMB_DEFRQTIMO;
  412         vcp->vc_smbuid = SMB_UID_UNKNOWN;
  413         vcp->vc_mode = vcspec->rights & SMBM_MASK;
  414         vcp->obj.co_flags = vcspec->flags & (SMBV_PRIVATE | SMBV_SINGLESHARE);
  415         vcp->vc_tdesc = &smb_tran_nbtcp_desc;
  416         vcp->vc_seqno = 0;
  417         vcp->vc_mackey = NULL;
  418         vcp->vc_mackeylen = 0;
  419 
  420         if (uid == SMBM_ANY_OWNER)
  421                 uid = realuid;
  422         if (gid == SMBM_ANY_GROUP)
  423                 gid = cred->cr_groups[0];
  424         vcp->vc_uid = uid;
  425         vcp->vc_grp = gid;
  426 
  427         smb_sl_init(&vcp->vc_stlock, "vcstlock");
  428         error = ENOMEM;
  429 
  430         vcp->vc_paddr = sodupsockaddr(vcspec->sap, M_WAITOK);
  431         if (vcp->vc_paddr == NULL)
  432                 goto fail;
  433         vcp->vc_laddr = sodupsockaddr(vcspec->lap, M_WAITOK);
  434         if (vcp->vc_laddr == NULL)
  435                 goto fail;
  436         vcp->vc_pass = smb_strdup(vcspec->pass);
  437         if (vcp->vc_pass == NULL)
  438                 goto fail;
  439         vcp->vc_domain = smb_strdup((domain && domain[0]) ? domain :
  440             "NODOMAIN");
  441         if (vcp->vc_domain == NULL)
  442                 goto fail;
  443         vcp->vc_srvname = smb_strdup(vcspec->srvname);
  444         if (vcp->vc_srvname == NULL)
  445                 goto fail;
  446         vcp->vc_username = smb_strdup(vcspec->username);
  447         if (vcp->vc_username == NULL)
  448                 goto fail;
  449         error = (int)iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower);
  450         if (error)
  451                 goto fail;
  452         error = (int)iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper);
  453         if (error)
  454                 goto fail;
  455         if (vcspec->servercs[0]) {
  456                 error = (int)iconv_open(vcspec->servercs, vcspec->localcs,
  457                     &vcp->vc_cp_toserver);
  458                 if (error)
  459                         goto fail;
  460                 error = (int)iconv_open(vcspec->localcs, vcspec->servercs,
  461                     &vcp->vc_cp_tolocal);
  462                 if (error)
  463                         goto fail;
  464                 vcp->vc_toserver = vcp->vc_cp_toserver;
  465                 vcp->vc_tolocal = vcp->vc_cp_tolocal;
  466                 iconv_add(ENCODING_UNICODE, ENCODING_UNICODE, SMB_UNICODE_NAME);
  467                 iconv_add(ENCODING_UNICODE, SMB_UNICODE_NAME, ENCODING_UNICODE);
  468                 error = (int)iconv_open(SMB_UNICODE_NAME, vcspec->localcs,
  469                     &vcp->vc_ucs_toserver);
  470                 if (!error) {
  471                         error = (int)iconv_open(vcspec->localcs, SMB_UNICODE_NAME,
  472                             &vcp->vc_ucs_tolocal);
  473                 }
  474                 if (error) {
  475                         if (vcp->vc_ucs_toserver)
  476                                 iconv_close(vcp->vc_ucs_toserver);
  477                         vcp->vc_ucs_toserver = NULL;
  478                         vcp->vc_ucs_tolocal = NULL;
  479                 }
  480         }
  481         error = (int)smb_iod_create(vcp);
  482         if (error)
  483                 goto fail;
  484         *vcpp = vcp;
  485         smb_co_addchild(&smb_vclist, VCTOCP(vcp));
  486         return (0);
  487 
  488  fail:
  489         smb_vc_put(vcp, scred);
  490         return (error);
  491 }
  492 
  493 static void
  494 smb_vc_free(struct smb_connobj *cp)
  495 {
  496         struct smb_vc *vcp = CPTOVC(cp);
  497 
  498         if (vcp->vc_iod)
  499                 smb_iod_destroy(vcp->vc_iod);
  500         SMB_STRFREE(vcp->vc_username);
  501         SMB_STRFREE(vcp->vc_srvname);
  502         SMB_STRFREE(vcp->vc_pass);
  503         SMB_STRFREE(vcp->vc_domain);
  504         if (vcp->vc_mackey)
  505                 free(vcp->vc_mackey, M_SMBTEMP);
  506         if (vcp->vc_paddr)
  507                 free(vcp->vc_paddr, M_SONAME);
  508         if (vcp->vc_laddr)
  509                 free(vcp->vc_laddr, M_SONAME);
  510         if (vcp->vc_tolower)
  511                 iconv_close(vcp->vc_tolower);
  512         if (vcp->vc_toupper)
  513                 iconv_close(vcp->vc_toupper);
  514         if (vcp->vc_tolocal)
  515                 vcp->vc_tolocal = NULL;
  516         if (vcp->vc_toserver)
  517                 vcp->vc_toserver = NULL;
  518         if (vcp->vc_cp_tolocal)
  519                 iconv_close(vcp->vc_cp_tolocal);
  520         if (vcp->vc_cp_toserver)
  521                 iconv_close(vcp->vc_cp_toserver);
  522         if (vcp->vc_ucs_tolocal)
  523                 iconv_close(vcp->vc_ucs_tolocal);
  524         if (vcp->vc_ucs_toserver)
  525                 iconv_close(vcp->vc_ucs_toserver);
  526         smb_co_done(VCTOCP(vcp));
  527         smb_sl_destroy(&vcp->vc_stlock);
  528         free(vcp, M_SMBCONN);
  529 }
  530 
  531 /*
  532  * Called when use count of VC dropped to zero.
  533  */
  534 static void
  535 smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred)
  536 {
  537         struct smb_vc *vcp = CPTOVC(cp);
  538 
  539         smb_vc_disconnect(vcp);
  540 }
  541 
  542 void
  543 smb_vc_ref(struct smb_vc *vcp)
  544 {
  545         smb_co_ref(VCTOCP(vcp));
  546 }
  547 
  548 void
  549 smb_vc_rele(struct smb_vc *vcp, struct smb_cred *scred)
  550 {
  551         smb_co_rele(VCTOCP(vcp), scred);
  552 }
  553 
  554 int
  555 smb_vc_get(struct smb_vc *vcp, struct smb_cred *scred)
  556 {
  557         struct smb_connobj *cp;
  558         int error;
  559 
  560         cp = VCTOCP(vcp);
  561         sx_xlock(&cp->co_interlock);
  562         error = smb_co_get(cp, scred);
  563         sx_unlock(&cp->co_interlock);
  564         return error;
  565 }
  566 
  567 void
  568 smb_vc_put(struct smb_vc *vcp, struct smb_cred *scred)
  569 {
  570         smb_co_put(VCTOCP(vcp), scred);
  571 }
  572 
  573 int
  574 smb_vc_lock(struct smb_vc *vcp)
  575 {
  576         struct smb_connobj *cp;
  577         int error;
  578 
  579         cp = VCTOCP(vcp);
  580         sx_xlock(&cp->co_interlock);
  581         error = smb_co_lock(cp);
  582         sx_unlock(&cp->co_interlock);
  583         return error;
  584 }
  585 
  586 void
  587 smb_vc_unlock(struct smb_vc *vcp)
  588 {
  589 
  590         struct smb_connobj *cp;
  591 
  592         cp = VCTOCP(vcp);
  593         sx_xlock(&cp->co_interlock);
  594         smb_co_unlock(cp);
  595         sx_unlock(&cp->co_interlock);
  596 }
  597 
  598 int
  599 smb_vc_access(struct smb_vc *vcp, struct smb_cred *scred, mode_t mode)
  600 {
  601         struct ucred *cred = scred->scr_cred;
  602 
  603         if (smb_suser(cred) == 0 || cred->cr_uid == vcp->vc_uid)
  604                 return 0;
  605         mode >>= 3;
  606         if (!groupmember(vcp->vc_grp, cred))
  607                 mode >>= 3;
  608         return (vcp->vc_mode & mode) == mode ? 0 : EACCES;
  609 }
  610 
  611 static int
  612 smb_vc_cmpshare(struct smb_share *ssp, struct smb_sharespec *dp)
  613 {
  614         int exact = 1;
  615 
  616         if (strcmp(ssp->ss_name, dp->name) != 0)
  617                 return 1;
  618         if (dp->owner != SMBM_ANY_OWNER) {
  619                 if (ssp->ss_uid != dp->owner)
  620                         return 1;
  621         } else
  622                 exact = 0;
  623         if (dp->group != SMBM_ANY_GROUP) {
  624                 if (ssp->ss_grp != dp->group)
  625                         return 1;
  626         } else
  627                 exact = 0;
  628 
  629         if (dp->mode & SMBM_EXACT) {
  630                 if (!exact)
  631                         return 1;
  632                 return (dp->mode & SMBM_MASK) == ssp->ss_mode ? 0 : 1;
  633         }
  634         if (smb_share_access(ssp, dp->scred, dp->mode) != 0)
  635                 return 1;
  636         return 0;
  637 }
  638 
  639 /*
  640  * Lookup share in the given VC. Share referenced and locked on return.
  641  * VC expected to be locked on entry and will be left locked on exit.
  642  */
  643 int
  644 smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *dp,
  645         struct smb_cred *scred, struct smb_share **sspp)
  646 {
  647         struct smb_connobj *scp = NULL;
  648         struct smb_share *ssp = NULL;
  649         int error;
  650 
  651         *sspp = NULL;
  652         dp->scred = scred;
  653         SMBCO_FOREACH(scp, VCTOCP(vcp)) {
  654                 ssp = (struct smb_share *)scp;
  655                 error = smb_share_lock(ssp);
  656                 if (error)
  657                         continue;
  658                 if (smb_vc_cmpshare(ssp, dp) == 0)
  659                         break;
  660                 smb_share_unlock(ssp);
  661         }
  662         if (ssp) {
  663                 smb_share_ref(ssp);
  664                 *sspp = ssp;
  665                 error = 0;
  666         } else
  667                 error = ENOENT;
  668         return error;
  669 }
  670 
  671 int
  672 smb_vc_connect(struct smb_vc *vcp, struct smb_cred *scred)
  673 {
  674 
  675         return smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
  676 }
  677 
  678 /*
  679  * Destroy VC to server, invalidate shares linked with it.
  680  * Transport should be locked on entry.
  681  */
  682 int
  683 smb_vc_disconnect(struct smb_vc *vcp)
  684 {
  685 
  686         if (vcp->vc_iod != NULL)
  687                 smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT |
  688                     SMBIOD_EV_SYNC, NULL);
  689         return 0;
  690 }
  691 
  692 static char smb_emptypass[] = "";
  693 
  694 const char *
  695 smb_vc_getpass(struct smb_vc *vcp)
  696 {
  697         if (vcp->vc_pass)
  698                 return vcp->vc_pass;
  699         return smb_emptypass;
  700 }
  701 
  702 static int
  703 smb_vc_getinfo(struct smb_vc *vcp, struct smb_vc_info *vip)
  704 {
  705         bzero(vip, sizeof(struct smb_vc_info));
  706         vip->itype = SMB_INFO_VC;
  707         vip->usecount = vcp->obj.co_usecount;
  708         vip->uid = vcp->vc_uid;
  709         vip->gid = vcp->vc_grp;
  710         vip->mode = vcp->vc_mode;
  711         vip->flags = vcp->obj.co_flags;
  712         vip->sopt = vcp->vc_sopt;
  713         vip->iodstate = vcp->vc_iod->iod_state;
  714         bzero(&vip->sopt.sv_skey, sizeof(vip->sopt.sv_skey));
  715         snprintf(vip->srvname, sizeof(vip->srvname), "%s", vcp->vc_srvname);
  716         snprintf(vip->vcname, sizeof(vip->vcname), "%s", vcp->vc_username);
  717         return 0;
  718 }
  719 
  720 u_short
  721 smb_vc_nextmid(struct smb_vc *vcp)
  722 {
  723         u_short r;
  724         
  725         sx_xlock(&vcp->obj.co_interlock);
  726         r = vcp->vc_mid++;
  727         sx_unlock(&vcp->obj.co_interlock);
  728         return r;
  729 }
  730 
  731 /*
  732  * Share implementation
  733  */
  734 /*
  735  * Allocate share structure and attach it to the given VC
  736  * Connection expected to be locked on entry. Share will be returned
  737  * in locked state.
  738  */
  739 int
  740 smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
  741         struct smb_cred *scred, struct smb_share **sspp)
  742 {
  743         struct smb_share *ssp;
  744         struct ucred *cred = scred->scr_cred;
  745         uid_t realuid = cred->cr_uid;
  746         uid_t uid = shspec->owner;
  747         gid_t gid = shspec->group;
  748         int error, isroot;
  749 
  750         isroot = smb_suser(cred) == 0;
  751         /*
  752          * Only superuser can create shares with different uid and gid
  753          */
  754         if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot)
  755                 return EPERM;
  756         if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot)
  757                 return EPERM;
  758         error = smb_vc_lookupshare(vcp, shspec, scred, &ssp);
  759         if (!error) {
  760                 smb_share_put(ssp, scred);
  761                 return EEXIST;
  762         }
  763         if (uid == SMBM_ANY_OWNER)
  764                 uid = realuid;
  765         if (gid == SMBM_ANY_GROUP)
  766                 gid = cred->cr_groups[0];
  767         ssp = smb_zmalloc(sizeof(*ssp), M_SMBCONN, M_WAITOK);
  768         smb_co_init(SSTOCP(ssp), SMBL_SHARE, "smbss ilock", "smbss");
  769         ssp->obj.co_free = smb_share_free;
  770         ssp->obj.co_gone = smb_share_gone;
  771         smb_sl_init(&ssp->ss_stlock, "ssstlock");
  772         ssp->ss_name = smb_strdup(shspec->name);
  773         if (shspec->pass && shspec->pass[0])
  774                 ssp->ss_pass = smb_strdup(shspec->pass);
  775         ssp->ss_type = shspec->stype;
  776         ssp->ss_tid = SMB_TID_UNKNOWN;
  777         ssp->ss_uid = uid;
  778         ssp->ss_grp = gid;
  779         ssp->ss_mode = shspec->rights & SMBM_MASK;
  780         smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
  781         *sspp = ssp;
  782         return 0;
  783 }
  784 
  785 static void
  786 smb_share_free(struct smb_connobj *cp)
  787 {
  788         struct smb_share *ssp = CPTOSS(cp);
  789 
  790         SMB_STRFREE(ssp->ss_name);
  791         SMB_STRFREE(ssp->ss_pass);
  792         smb_sl_destroy(&ssp->ss_stlock);
  793         smb_co_done(SSTOCP(ssp));
  794         free(ssp, M_SMBCONN);
  795 }
  796 
  797 static void
  798 smb_share_gone(struct smb_connobj *cp, struct smb_cred *scred)
  799 {
  800         struct smb_share *ssp = CPTOSS(cp);
  801 
  802         smb_smb_treedisconnect(ssp, scred);
  803 }
  804 
  805 void
  806 smb_share_ref(struct smb_share *ssp)
  807 {
  808         smb_co_ref(SSTOCP(ssp));
  809 }
  810 
  811 void
  812 smb_share_rele(struct smb_share *ssp, struct smb_cred *scred)
  813 {
  814         smb_co_rele(SSTOCP(ssp), scred);
  815 }
  816 
  817 int
  818 smb_share_get(struct smb_share *ssp, struct smb_cred *scred)
  819 {
  820         struct smb_connobj *cp = SSTOCP(ssp);
  821         int error;
  822 
  823         sx_xlock(&cp->co_interlock);
  824         error = smb_co_get(cp, scred);
  825         sx_unlock(&cp->co_interlock);
  826         return error;
  827 }
  828 
  829 void
  830 smb_share_put(struct smb_share *ssp, struct smb_cred *scred)
  831 {
  832         
  833         smb_co_put(SSTOCP(ssp), scred);
  834 }
  835 
  836 int
  837 smb_share_lock(struct smb_share *ssp)
  838 {
  839         struct smb_connobj *cp;
  840         int error;
  841         
  842         cp = SSTOCP(ssp);
  843         sx_xlock(&cp->co_interlock);
  844         error = smb_co_lock(cp);
  845         sx_unlock(&cp->co_interlock);
  846         return error;
  847 }
  848 
  849 void
  850 smb_share_unlock(struct smb_share *ssp)
  851 {
  852         struct smb_connobj *cp;
  853         
  854         cp = SSTOCP(ssp);
  855         sx_xlock(&cp->co_interlock);
  856         smb_co_unlock(cp);
  857         sx_unlock(&cp->co_interlock);
  858 }
  859 
  860 int
  861 smb_share_access(struct smb_share *ssp, struct smb_cred *scred, mode_t mode)
  862 {
  863         struct ucred *cred = scred->scr_cred;
  864 
  865         if (smb_suser(cred) == 0 || cred->cr_uid == ssp->ss_uid)
  866                 return 0;
  867         mode >>= 3;
  868         if (!groupmember(ssp->ss_grp, cred))
  869                 mode >>= 3;
  870         return (ssp->ss_mode & mode) == mode ? 0 : EACCES;
  871 }
  872 
  873 void
  874 smb_share_invalidate(struct smb_share *ssp)
  875 {
  876         ssp->ss_tid = SMB_TID_UNKNOWN;
  877 }
  878 
  879 int
  880 smb_share_valid(struct smb_share *ssp)
  881 {
  882         return ssp->ss_tid != SMB_TID_UNKNOWN &&
  883             ssp->ss_vcgenid == SSTOVC(ssp)->vc_genid;
  884 }
  885 
  886 const char*
  887 smb_share_getpass(struct smb_share *ssp)
  888 {
  889         struct smb_vc *vcp;
  890 
  891         if (ssp->ss_pass)
  892                 return ssp->ss_pass;
  893         vcp = SSTOVC(ssp);
  894         if (vcp->vc_pass)
  895                 return vcp->vc_pass;
  896         return smb_emptypass;
  897 }
  898 
  899 static int
  900 smb_share_getinfo(struct smb_share *ssp, struct smb_share_info *sip)
  901 {
  902         bzero(sip, sizeof(struct smb_share_info));
  903         sip->itype = SMB_INFO_SHARE;
  904         sip->usecount = ssp->obj.co_usecount;
  905         sip->tid  = ssp->ss_tid;
  906         sip->type= ssp->ss_type;
  907         sip->uid = ssp->ss_uid;
  908         sip->gid = ssp->ss_grp;
  909         sip->mode= ssp->ss_mode;
  910         sip->flags = ssp->obj.co_flags;
  911         snprintf(sip->sname, sizeof(sip->sname), "%s", ssp->ss_name);
  912         return 0;
  913 }
  914 
  915 /*
  916  * Dump an entire tree into sysctl call
  917  */
  918 static int
  919 smb_sysctl_treedump(SYSCTL_HANDLER_ARGS)
  920 {
  921         struct smb_connobj *scp1, *scp2;
  922         struct smb_vc *vcp;
  923         struct smb_share *ssp;
  924         struct smb_vc_info vci;
  925         struct smb_share_info ssi;
  926         int error, itype;
  927 
  928         error = sysctl_wire_old_buffer(req, 0);
  929         if (error)
  930                 return (error);
  931         error = smb_sm_lockvclist();
  932         if (error)
  933                 return error;
  934         SMBCO_FOREACH(scp1, &smb_vclist) {
  935                 vcp = (struct smb_vc *)scp1;
  936                 error = smb_vc_lock(vcp);
  937                 if (error)
  938                         continue;
  939                 smb_vc_getinfo(vcp, &vci);
  940                 error = SYSCTL_OUT(req, &vci, sizeof(struct smb_vc_info));
  941                 if (error) {
  942                         smb_vc_unlock(vcp);
  943                         break;
  944                 }
  945                 SMBCO_FOREACH(scp2, VCTOCP(vcp)) {
  946                         ssp = (struct smb_share *)scp2;
  947                         error = smb_share_lock(ssp);
  948                         if (error) {
  949                                 error = 0;
  950                                 continue;
  951                         }
  952                         smb_share_getinfo(ssp, &ssi);
  953                         smb_share_unlock(ssp);
  954                         error = SYSCTL_OUT(req, &ssi, sizeof(struct smb_share_info));
  955                         if (error)
  956                                 break;
  957                 }
  958                 smb_vc_unlock(vcp);
  959                 if (error)
  960                         break;
  961         }
  962         if (!error) {
  963                 itype = SMB_INFO_NONE;
  964                 error = SYSCTL_OUT(req, &itype, sizeof(itype));
  965         }
  966         smb_sm_unlockvclist();
  967         return error;
  968 }

Cache object: e8b207af34e2e50d90c46bf7167c7f65


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