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

Cache object: 29c6e572de6cc0c6610f347118a613f6


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