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

Cache object: 27adcc62a6d41feb070123471ace510a


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