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/netncp/ncp_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) 1999, 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  * $FreeBSD$
   32  *
   33  * Connection tables
   34  */
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/proc.h>
   40 #include <sys/lock.h>
   41 #include <sys/sysctl.h>
   42 
   43 #include <netncp/ncp.h>
   44 #include <netncp/ncp_subr.h>
   45 #include <netncp/ncp_conn.h>
   46 
   47 SLIST_HEAD(ncp_handle_head,ncp_handle);
   48 
   49 int ncp_burst_enabled = 1;
   50 
   51 struct ncp_conn_head conn_list={NULL};
   52 static int ncp_conn_cnt = 0;
   53 static int ncp_next_ref = 1;
   54 static struct lock listlock;
   55 
   56 struct ncp_handle_head lhlist={NULL};
   57 static int ncp_next_handle = 1;
   58 static struct lock lhlock;
   59 
   60 static int ncp_sysctl_connstat(SYSCTL_HANDLER_ARGS);
   61 static int ncp_conn_lock_any(struct ncp_conn *conn, struct proc *p, 
   62     struct ucred *cred);
   63 
   64 extern struct linker_set sysctl_net_ncp;
   65 
   66 SYSCTL_DECL(_net_ncp);
   67 SYSCTL_INT (_net_ncp, OID_AUTO, burst_enabled, CTLFLAG_RD, &ncp_burst_enabled, 0, "");
   68 SYSCTL_INT (_net_ncp, OID_AUTO, conn_cnt, CTLFLAG_RD, &ncp_conn_cnt, 0, "");
   69 SYSCTL_PROC(_net_ncp, OID_AUTO, conn_stat, CTLFLAG_RD|CTLTYPE_OPAQUE,
   70             NULL, 0, ncp_sysctl_connstat, "S,connstat", "Connections list");
   71 
   72 MALLOC_DEFINE(M_NCPDATA, "NCP data", "NCP private data");
   73 
   74 int
   75 ncp_conn_init(void) {
   76         lockinit(&listlock, PSOCK, "ncpll", 0, 0);
   77         lockinit(&lhlock, PSOCK, "ncplh", 0, 0);
   78         return 0;
   79 }
   80 
   81 int
   82 ncp_conn_locklist(int flags, struct proc *p){
   83         return lockmgr(&listlock, flags | LK_CANRECURSE, 0, p);
   84 }
   85 
   86 void
   87 ncp_conn_unlocklist(struct proc *p){
   88         lockmgr(&listlock, LK_RELEASE, 0, p);
   89 }
   90 
   91 int
   92 ncp_conn_access(struct ncp_conn *conn, struct ucred *cred, mode_t mode) {
   93         int error;
   94 
   95         if (cred == NOCRED || ncp_suser(cred) == 0 ||
   96             cred->cr_uid == conn->nc_owner->cr_uid)
   97                 return 0;
   98         mode >>= 3;
   99         if (!groupmember(conn->nc_group, cred))
  100                 mode >>= 3;
  101         error = (conn->li.access_mode & mode) == mode ? 0 : EACCES;
  102         return error;
  103 }
  104 
  105 int
  106 ncp_conn_lock_any(struct ncp_conn *conn, struct proc *p, struct ucred *cred) {
  107         int error;
  108 
  109         if (conn->nc_id == 0) return EACCES;
  110         error = lockmgr(&conn->nc_lock, LK_EXCLUSIVE | LK_CANRECURSE, 0, p);
  111         if (error == ERESTART)
  112                 return EINTR;
  113         error = ncp_chkintr(conn, p);
  114         if (error) {
  115                 lockmgr(&conn->nc_lock, LK_RELEASE, 0, p);
  116                 return error;
  117         }
  118 
  119         if (conn->nc_id == 0) {
  120                 lockmgr(&conn->nc_lock, LK_RELEASE, 0, p);
  121                 return EACCES;
  122         }
  123         conn->procp = p;        /* who currently operates */
  124         conn->ucred = cred;
  125         return 0;
  126 }
  127 
  128 int
  129 ncp_conn_lock(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode) {
  130         int error;
  131 
  132         error = ncp_conn_access(conn,cred,mode);
  133         if (error) return error;
  134         return ncp_conn_lock_any(conn, p, cred);
  135 }
  136 
  137 /*
  138  * Lock conn but unlock connlist
  139  */
  140 static int
  141 ncp_conn_lock2(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode) {
  142         int error;
  143 
  144         error = ncp_conn_access(conn,cred,mode);
  145         if (error) {
  146                 ncp_conn_unlocklist(p);
  147                 return error;
  148         }
  149         conn->nc_lwant++;
  150         ncp_conn_unlocklist(p);
  151         error = ncp_conn_lock_any(conn,p,cred);
  152         conn->nc_lwant--;
  153         if (conn->nc_lwant == 0) {
  154                 wakeup(&conn->nc_lwant);
  155         }
  156         return error;
  157 }
  158 
  159 void
  160 ncp_conn_unlock(struct ncp_conn *conn, struct proc *p) {
  161         /*
  162          * note, that LK_RELASE will do wakeup() instead of wakeup_one().
  163          * this will do a little overhead
  164          */
  165         lockmgr(&conn->nc_lock, LK_RELEASE, 0, p);
  166 }
  167 
  168 int 
  169 ncp_conn_assert_locked(struct ncp_conn *conn,char *checker, struct proc *p){
  170         if (conn->nc_lock.lk_flags & LK_HAVE_EXCL) return 0;
  171         printf("%s: connection isn't locked!\n", checker);
  172         return EIO;
  173 }
  174 
  175 /* 
  176  * create, fill with defaults and return in locked state
  177  */
  178 int
  179 ncp_conn_alloc(struct proc *p, struct ucred *cred, struct ncp_conn **conn)
  180 {
  181         int error;
  182         struct ncp_conn *ncp;
  183 
  184         MALLOC(ncp, struct ncp_conn *, sizeof(struct ncp_conn), 
  185             M_NCPDATA, M_WAITOK | M_ZERO);
  186         error = 0;
  187         lockinit(&ncp->nc_lock, PZERO, "ncplck", 0, 0);
  188         ncp_conn_cnt++;
  189         ncp->nc_id = ncp_next_ref++;
  190         ncp->nc_owner = cred;
  191         ncp->seq = 0;
  192         ncp->connid = 0xFFFF;
  193         ncp_conn_lock_any(ncp, p, ncp->nc_owner);
  194         *conn = ncp;
  195         ncp_conn_locklist(LK_EXCLUSIVE, p);
  196         SLIST_INSERT_HEAD(&conn_list,ncp,nc_next);
  197         ncp_conn_unlocklist(p);
  198         return (error);
  199 }
  200 
  201 /*
  202  * Remove the connection, on entry it must be locked
  203  */
  204 int
  205 ncp_conn_free(struct ncp_conn *ncp) {
  206         int error;
  207         struct ncp_conn *ncp1;
  208 
  209         if (ncp->nc_id == 0) {
  210         printf("already!!!!\n");
  211                 return EACCES;
  212         }
  213         if (ncp==NULL) {
  214                 NCPFATAL("conn==NULL !\n");
  215                 return(EIO);
  216         }
  217         error = ncp_conn_assert_locked(ncp, __FUNCTION__, ncp->procp);
  218         if (error) return error;
  219         if (ncp->ref_cnt) {
  220                 NCPFATAL("there are %d referenses left\n",ncp->ref_cnt);
  221                 return(EBUSY);
  222         }
  223         /*
  224          * Mark conn as died and wait for other process
  225          */
  226         ncp->nc_id = 0;
  227         ncp_conn_unlock(ncp,ncp->procp);
  228         /*
  229          * if signal is raised - how I do react ?
  230          */
  231         lockmgr(&ncp->nc_lock, LK_DRAIN, 0, ncp->procp);
  232         while (ncp->nc_lwant) {
  233                 printf("lwant = %d\n", ncp->nc_lwant);
  234                 tsleep(&ncp->nc_lwant, PZERO,"ncpdr",2*hz);
  235         }
  236         ncp_conn_locklist(LK_EXCLUSIVE, ncp->procp);
  237         /*
  238          * It is possible, that other process destroy connection while we draining,
  239          * and free it. So, we must rescan list
  240          */
  241         SLIST_FOREACH(ncp1, &conn_list, nc_next) {
  242                 if (ncp1 == ncp) break;
  243         }
  244         if (ncp1 == NULL) {
  245                 ncp_conn_unlocklist(ncp->procp);
  246                 return 0;
  247         }
  248         SLIST_REMOVE(&conn_list, ncp, ncp_conn, nc_next);
  249         ncp_conn_cnt--;
  250         ncp_conn_unlocklist(ncp->procp);
  251         if (ncp->li.user) free(ncp->li.user, M_NCPDATA);
  252         if (ncp->li.password) free(ncp->li.password, M_NCPDATA);
  253         crfree(ncp->nc_owner);
  254         FREE(ncp, M_NCPDATA);
  255         return (0);
  256 }
  257 
  258 /* 
  259  * Lookup connection by handle, return a locked conn descriptor 
  260  */
  261 int
  262 ncp_conn_getbyref(int ref,struct proc *p,struct ucred *cred, int mode, struct ncp_conn **connpp){
  263         struct ncp_conn *ncp;
  264         int error=0;
  265 
  266         ncp_conn_locklist(LK_SHARED, p);
  267         SLIST_FOREACH(ncp, &conn_list, nc_next)
  268                 if (ncp->nc_id == ref) break;
  269         if (ncp == NULL) {
  270                 ncp_conn_unlocklist(p);
  271                 return(EBADF);
  272         }
  273         error = ncp_conn_lock2(ncp, p, cred, mode);
  274         if (!error)
  275                 *connpp = ncp;
  276         return (error);
  277 }
  278 /*
  279  * find attached, but not logged in connection to specified server
  280  */
  281 int
  282 ncp_conn_getattached(struct ncp_conn_args *li,struct proc *p,struct ucred *cred,int mode, struct ncp_conn **connpp){
  283         struct ncp_conn *ncp, *ncp2=NULL;
  284         int error = 0;
  285 
  286         ncp_conn_locklist(LK_SHARED, p);
  287         SLIST_FOREACH(ncp, &conn_list, nc_next) {
  288                 if ((ncp->flags & NCPFL_LOGGED) != 0 ||
  289                     strcmp(ncp->li.server,li->server) != 0 || 
  290                     ncp->li.saddr.sa_len != li->saddr.sa_len ||
  291                     bcmp(&ncp->li.saddr,&ncp->li.saddr,li->saddr.sa_len) != 0)
  292                         continue;
  293                 if (ncp_suser(cred) == 0 || 
  294                     cred->cr_uid == ncp->nc_owner->cr_uid)
  295                         break;
  296                 error = ncp_conn_access(ncp,cred,mode);
  297                 if (!error && ncp2 == NULL)
  298                         ncp2 = ncp;
  299         }
  300         if (ncp == NULL) ncp = ncp2;
  301         if (ncp == NULL) {
  302                 ncp_conn_unlocklist(p);
  303                 return(EBADF);
  304         }
  305         error = ncp_conn_lock2(ncp,p,cred,mode);
  306         if (!error)
  307                 *connpp=ncp;
  308         return (error);
  309 }
  310 
  311 /* 
  312  * Lookup connection by server/user pair, return a locked conn descriptor.
  313  * if li is NULL or server/user pair incomplete, try to select best connection 
  314  * based on owner.
  315  * Connection selected in next order:
  316  * 1. Try to search conn with ucred owner, if li is NULL also find a primary
  317  * 2. If 1. fails try to get first suitable shared connection
  318  * 3. If 2. fails then nothing can help to poor ucred owner
  319  */
  320 
  321 int
  322 ncp_conn_getbyli(struct ncp_conn_args *li,struct proc *p,struct ucred *cred,int mode, struct ncp_conn **connpp){
  323         struct ncp_conn *ncp, *ncp2=NULL;
  324         int error=0, partial, haveserv;
  325 
  326         partial = (li == NULL || li->server[0] == 0 || li->user == NULL);
  327         haveserv = (li && li->server[0]);
  328         ncp_conn_locklist(LK_SHARED, p);
  329         SLIST_FOREACH(ncp, &conn_list, nc_next) {
  330                 if (partial) {
  331                         if (cred->cr_uid == ncp->nc_owner->cr_uid) {
  332                                 if (haveserv) {
  333                                         if (strcmp(ncp->li.server,li->server) == 0)
  334                                                 break;
  335                                 } else {
  336                                         if (ncp->flags & NCPFL_PRIMARY)
  337                                                 break;
  338                                         ncp2 = ncp;
  339                                 }
  340                                 continue;
  341                         }
  342                 } else {
  343                         if (strcmp(ncp->li.server,li->server) != 0 || 
  344                             ncp->li.user == NULL ||
  345                             strcmp(ncp->li.user,li->user) != 0)
  346                                 continue;
  347                         if (cred->cr_uid == ncp->nc_owner->cr_uid)
  348                                 break;
  349                         if (ncp_suser(cred) == 0)
  350                                 ncp2 = ncp;
  351                 }
  352                 error = ncp_conn_access(ncp,cred,mode);
  353                 if (!error && ncp2 == NULL)
  354                         ncp2 = ncp;
  355         }
  356         if (ncp == NULL) ncp = ncp2;
  357         if (ncp == NULL) {
  358                 ncp_conn_unlocklist(p);
  359                 return(EBADF);
  360         }
  361         error = ncp_conn_lock2(ncp,p,cred,mode);
  362         if (!error)
  363                 *connpp=ncp;
  364         return (error);
  365 }
  366 
  367 /*
  368  * Set primary connection flag, since it have sence only for an owner,
  369  * only owner can modify this flag.
  370  * connection expected to be locked.
  371  */
  372 int
  373 ncp_conn_setprimary(struct ncp_conn *conn, int on){
  374         struct ncp_conn *ncp=NULL;
  375 
  376         if (conn->ucred->cr_uid != conn->nc_owner->cr_uid)
  377                 return EACCES;
  378         ncp_conn_locklist(LK_SHARED, conn->procp);
  379         SLIST_FOREACH(ncp, &conn_list, nc_next) {
  380                 if (conn->ucred->cr_uid == ncp->nc_owner->cr_uid)
  381                         ncp->flags &= ~NCPFL_PRIMARY;
  382         }
  383         ncp_conn_unlocklist(conn->procp);
  384         if (on)
  385                 conn->flags |= NCPFL_PRIMARY;
  386         return 0;
  387 }
  388 /* 
  389  * Lease conn to given proc, returning unique handle
  390  * problem: how locks should be applied ?
  391  */
  392 int
  393 ncp_conn_gethandle(struct ncp_conn *conn, struct proc *p, struct ncp_handle **handle){
  394         struct ncp_handle *refp;
  395 
  396         lockmgr(&lhlock, LK_EXCLUSIVE, 0, p);
  397         SLIST_FOREACH(refp, &lhlist, nh_next)
  398                 if (refp->nh_conn == conn && p == refp->nh_proc) break;
  399         if (refp) {
  400                 conn->ref_cnt++;
  401                 refp->nh_ref++;
  402                 *handle = refp;
  403                 lockmgr(&lhlock, LK_RELEASE, 0, p);
  404                 return 0;
  405         }
  406         MALLOC(refp,struct ncp_handle *,sizeof(struct ncp_handle),M_NCPDATA,
  407             M_WAITOK | M_ZERO);
  408         SLIST_INSERT_HEAD(&lhlist,refp,nh_next);
  409         refp->nh_ref++;
  410         refp->nh_proc = p;
  411         refp->nh_conn = conn;
  412         refp->nh_id = ncp_next_handle++;
  413         *handle = refp;
  414         conn->ref_cnt++;
  415         lockmgr(&lhlock, LK_RELEASE, 0, p);
  416         return 0;
  417 }
  418 /*
  419  * release reference, if force - ignore refcount
  420  */
  421 int
  422 ncp_conn_puthandle(struct ncp_handle *handle, struct proc *p, int force) {
  423         struct ncp_handle *refp = handle;
  424 
  425         lockmgr(&lhlock, LK_EXCLUSIVE, 0, p);
  426         refp->nh_ref--;
  427         refp->nh_conn->ref_cnt--;
  428         if (force) {
  429                 refp->nh_conn->ref_cnt -= refp->nh_ref;
  430                 refp->nh_ref = 0;
  431         }
  432         if (refp->nh_ref == 0) {
  433                 SLIST_REMOVE(&lhlist, refp, ncp_handle, nh_next);
  434                 FREE(refp, M_NCPDATA);
  435         }
  436         lockmgr(&lhlock, LK_RELEASE, 0, p);
  437         return 0;
  438 }
  439 /*
  440  * find a connHandle
  441  */
  442 int
  443 ncp_conn_findhandle(int connHandle, struct proc *p, struct ncp_handle **handle) {
  444         struct ncp_handle *refp;
  445 
  446         lockmgr(&lhlock, LK_SHARED, 0, p);
  447         SLIST_FOREACH(refp, &lhlist, nh_next)
  448                 if (refp->nh_proc == p && refp->nh_id == connHandle) break;
  449         lockmgr(&lhlock, LK_RELEASE, 0, p);
  450         if (refp == NULL) {
  451                 return EBADF;
  452         }
  453         *handle = refp;
  454         return 0;
  455 }
  456 /*
  457  * Clear handles associated with specified process
  458  */
  459 int
  460 ncp_conn_putprochandles(struct proc *p) {
  461         struct ncp_handle *hp, *nhp;
  462         int haveone = 0;
  463 
  464         lockmgr(&lhlock, LK_EXCLUSIVE, 0, p);
  465         for (hp = SLIST_FIRST(&lhlist); hp; hp = nhp) {
  466                 nhp = SLIST_NEXT(hp, nh_next);
  467                 if (hp->nh_proc != p) continue;
  468                 haveone = 1;
  469                 hp->nh_conn->ref_cnt -= hp->nh_ref;
  470                 SLIST_REMOVE(&lhlist, hp, ncp_handle, nh_next);
  471                 FREE(hp, M_NCPDATA);
  472         }
  473         lockmgr(&lhlock, LK_RELEASE, 0, p);
  474         return haveone;
  475 }
  476 /*
  477  * remove references in all possible connections,
  478  * XXX - possible problem is a locked list.
  479  */
  480 /*void
  481 ncp_conn_list_rm_ref(pid_t pid) {
  482         struct ncp_conn *ncp;
  483 
  484         ncp_conn_locklist(LK_SHARED, NULL);
  485         SLIST_FOREACH(ncp, &conn_list, nc_next) {
  486                 ncp_conn_rm_ref(ncp,pid,1);
  487         }
  488         ncp_conn_unlocklist(NULL);
  489         return;
  490 }
  491 */
  492 int
  493 ncp_conn_getinfo(struct ncp_conn *ncp, struct ncp_conn_stat *ncs) {
  494         bzero(ncs,sizeof(*ncs));
  495         ncs->li = ncp->li;
  496         ncs->li.user = ncs->user;
  497         if (ncp->li.user)
  498                 strcpy(ncs->user, ncp->li.user);
  499         ncs->li.password = NULL;
  500         ncs->connRef = ncp->nc_id;
  501         ncs->ref_cnt = ncp->ref_cnt;
  502         ncs->connid = ncp->connid;
  503         ncs->owner = ncp->nc_owner->cr_uid;
  504         ncs->group = ncp->nc_group;
  505         ncs->flags = ncp->flags;
  506         ncs->buffer_size = ncp->buffer_size;
  507         return 0;
  508 }
  509 
  510 static int
  511 ncp_sysctl_connstat(SYSCTL_HANDLER_ARGS) {
  512         int error;
  513         struct ncp_conn_stat ncs;
  514         struct ncp_conn *ncp;
  515 /*      struct ucred *cred = req->p->p_ucred;*/
  516 
  517         error = 0;
  518         ncp_conn_locklist(LK_SHARED, req->p);
  519         error = SYSCTL_OUT(req, &ncp_conn_cnt, sizeof(ncp_conn_cnt));
  520         SLIST_FOREACH(ncp, &conn_list, nc_next) {
  521                 if (error) break;
  522                 /* I can't do conn_lock while list is locked */
  523                 ncp->nc_lwant++;
  524                 if (!error) {
  525                         ncp_conn_getinfo(ncp, &ncs);
  526                 } else {
  527                         bzero(&ncs,sizeof(ncs));
  528                         ncs.connRef = ncp->nc_id;
  529                         strcpy(ncs.li.server,"***");
  530                 }
  531                 ncp->nc_lwant--;
  532                 error = SYSCTL_OUT(req, &ncs, sizeof(ncs));
  533         }
  534         ncp_conn_unlocklist(req->p);
  535         return(error);
  536 }

Cache object: fa3548047de9b6935c209c0c5cc23bd3


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