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

Cache object: 9549df4d80f5736ff7f4588c9daff59b


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