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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Connection tables
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: stable/9/sys/netncp/ncp_conn.c 206361 2010-04-07 16:50:38Z joel $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/priv.h>
37 #include <sys/proc.h>
38 #include <sys/lock.h>
39 #include <sys/sysctl.h>
40 
41 #include <netncp/ncp.h>
42 #include <netncp/nwerror.h>
43 #include <netncp/ncp_subr.h>
44 #include <netncp/ncp_conn.h>
45 #include <netncp/ncp_sock.h>
46 #include <netncp/ncp_ncp.h>
47 
48 SLIST_HEAD(ncp_handle_head,ncp_handle);
49 
50 int ncp_burst_enabled = 1;
51 
52 struct ncp_conn_head conn_list={NULL};
53 static int ncp_conn_cnt = 0;
54 static int ncp_next_ref = 1;
55 static struct lock listlock;
56 
57 struct ncp_handle_head lhlist={NULL};
58 static int ncp_next_handle = 1;
59 static struct lock lhlock;
60 
61 static int ncp_sysctl_connstat(SYSCTL_HANDLER_ARGS);
62 static int ncp_conn_lock_any(struct ncp_conn *conn, struct thread *td,
63     struct ucred *cred);
64 
65 SYSCTL_DECL(_net_ncp);
66 SYSCTL_INT (_net_ncp, OID_AUTO, burst_enabled, CTLFLAG_RD, &ncp_burst_enabled, 0, "");
67 SYSCTL_INT (_net_ncp, OID_AUTO, conn_cnt, CTLFLAG_RD, &ncp_conn_cnt, 0, "");
68 SYSCTL_PROC(_net_ncp, OID_AUTO, conn_stat, CTLFLAG_RD|CTLTYPE_OPAQUE,
69 	    NULL, 0, ncp_sysctl_connstat, "S,connstat", "Connections list");
70 
71 MALLOC_DEFINE(M_NCPDATA, "ncp_data", "NCP private data");
72 
73 int
ncp_conn_init(void)74 ncp_conn_init(void)
75 {
76 	lockinit(&listlock, PSOCK, "ncpll", 0, 0);
77 	lockinit(&lhlock, PSOCK, "ncplh", 0, 0);
78 	return 0;
79 }
80 
81 int
ncp_conn_destroy(void)82 ncp_conn_destroy(void)
83 {
84 	if (ncp_conn_cnt) {
85 		NCPERROR("There are %d connections active\n", ncp_conn_cnt);
86 		return EBUSY;
87 	}
88 	lockdestroy(&listlock);
89 	lockdestroy(&lhlock);
90 	return 0;
91 }
92 
93 int
ncp_conn_locklist(int flags,struct thread * td)94 ncp_conn_locklist(int flags, struct thread *td)
95 {
96 	return lockmgr(&listlock, flags | LK_CANRECURSE, 0);
97 }
98 
99 void
ncp_conn_unlocklist(struct thread * td)100 ncp_conn_unlocklist(struct thread *td)
101 {
102 	lockmgr(&listlock, LK_RELEASE, 0);
103 }
104 
105 int
ncp_conn_access(struct ncp_conn * conn,struct ucred * cred,mode_t mode)106 ncp_conn_access(struct ncp_conn *conn, struct ucred *cred, mode_t mode)
107 {
108 	int error;
109 
110 	if (cred == NOCRED || ncp_suser(cred) == 0 ||
111 	    cred->cr_uid == conn->nc_owner->cr_uid)
112 		return 0;
113 	mode >>= 3;
114 	if (!groupmember(conn->nc_group, cred))
115 		mode >>= 3;
116 	error = (conn->li.access_mode & mode) == mode ? 0 : EACCES;
117 	return error;
118 }
119 
120 int
ncp_conn_lock_any(struct ncp_conn * conn,struct thread * td,struct ucred * cred)121 ncp_conn_lock_any(struct ncp_conn *conn, struct thread *td, struct ucred *cred)
122 {
123 	int error;
124 
125 	if (conn->nc_id == 0) return EACCES;
126 	error = lockmgr(&conn->nc_lock, LK_EXCLUSIVE | LK_CANRECURSE, 0);
127 	if (error == ERESTART)
128 		return EINTR;
129 	error = ncp_chkintr(conn, td);
130 	if (error) {
131 		lockmgr(&conn->nc_lock, LK_RELEASE, 0);
132 		return error;
133 	}
134 
135 	if (conn->nc_id == 0) {
136 		lockmgr(&conn->nc_lock, LK_RELEASE, 0);
137 		return EACCES;
138 	}
139 	conn->td = td;		/* who currently operates */
140 	conn->ucred = cred;
141 	return 0;
142 }
143 
144 int
ncp_conn_lock(struct ncp_conn * conn,struct thread * td,struct ucred * cred,int mode)145 ncp_conn_lock(struct ncp_conn *conn, struct thread *td, struct ucred *cred, int mode)
146 {
147 	int error;
148 
149 	error = ncp_conn_access(conn, cred, mode);
150 	if (error) return error;
151 	return ncp_conn_lock_any(conn, td, cred);
152 }
153 
154 /*
155  * Lock conn but unlock connlist
156  */
157 static int
ncp_conn_lock2(struct ncp_conn * conn,struct thread * td,struct ucred * cred,int mode)158 ncp_conn_lock2(struct ncp_conn *conn, struct thread *td, struct ucred *cred, int mode)
159 {
160 	int error;
161 
162 	error = ncp_conn_access(conn, cred, mode);
163 	if (error) {
164 		ncp_conn_unlocklist(td);
165 		return error;
166 	}
167 	conn->nc_lwant++;
168 	ncp_conn_unlocklist(td);
169 	error = ncp_conn_lock_any(conn, td, cred);
170 	conn->nc_lwant--;
171 	if (conn->nc_lwant == 0) {
172 		wakeup(&conn->nc_lwant);
173 	}
174 	return error;
175 }
176 
177 void
ncp_conn_unlock(struct ncp_conn * conn,struct thread * td)178 ncp_conn_unlock(struct ncp_conn *conn, struct thread *td)
179 {
180 	/*
181 	 * note, that LK_RELASE will do wakeup() instead of wakeup_one().
182 	 * this will do a little overhead
183 	 */
184 	lockmgr(&conn->nc_lock, LK_RELEASE, 0);
185 }
186 
187 int
ncp_conn_assert_locked(struct ncp_conn * conn,const char * checker,struct thread * td)188 ncp_conn_assert_locked(struct ncp_conn *conn, const char *checker, struct thread *td)
189 {
190 	if (lockstatus(&conn->nc_lock) == LK_EXCLUSIVE) return 0;
191 	printf("%s: connection isn't locked!\n", checker);
192 	return EIO;
193 }
194 
195 void
ncp_conn_invalidate(struct ncp_conn * ncp)196 ncp_conn_invalidate(struct ncp_conn *ncp)
197 {
198 	ncp->flags &= ~(NCPFL_ATTACHED | NCPFL_LOGGED | NCPFL_INVALID);
199 }
200 
201 int
ncp_conn_invalid(struct ncp_conn * ncp)202 ncp_conn_invalid(struct ncp_conn *ncp)
203 {
204 	return ncp->flags & NCPFL_INVALID;
205 }
206 
207 /*
208  * create, fill with defaults and return in locked state
209  */
210 int
ncp_conn_alloc(struct ncp_conn_args * cap,struct thread * td,struct ucred * cred,struct ncp_conn ** conn)211 ncp_conn_alloc(struct ncp_conn_args *cap, struct thread *td, struct ucred *cred,
212 	struct ncp_conn **conn)
213 {
214 	struct ncp_conn *ncp;
215 	struct ucred *owner;
216 	int error, isroot;
217 
218 	if (cap->saddr.sa_family != AF_INET && cap->saddr.sa_family != AF_IPX)
219 		return EPROTONOSUPPORT;
220 	/*
221 	 * Only root can change ownership.
222 	 */
223 	isroot = ncp_suser(cred) == 0;
224 	if (cap->owner != NCP_DEFAULT_OWNER && !isroot)
225 		return EPERM;
226 	if (cap->group != NCP_DEFAULT_GROUP &&
227 	    !groupmember(cap->group, cred) && !isroot)
228 		return EPERM;
229 	if (cap->owner != NCP_DEFAULT_OWNER) {
230 		owner = crget();
231 		crcopy(owner, cred);
232 		owner->cr_uid = cap->owner;
233 	} else
234 		owner = crhold(cred);
235 	ncp = malloc(sizeof(struct ncp_conn),
236 	    M_NCPDATA, M_WAITOK | M_ZERO);
237 	error = 0;
238 	lockinit(&ncp->nc_lock, PZERO, "ncplck", 0, 0);
239 	ncp_conn_cnt++;
240 	ncp->nc_id = ncp_next_ref++;
241 	ncp->nc_owner = owner;
242 	ncp->seq = 0;
243 	ncp->connid = 0xFFFF;
244 	ncp->li = *cap;
245 	ncp->nc_group = (cap->group != NCP_DEFAULT_GROUP) ?
246 		cap->group : cred->cr_groups[0];
247 
248 	if (cap->retry_count == 0)
249 		ncp->li.retry_count = NCP_RETRY_COUNT;
250 	if (cap->timeout == 0)
251 		ncp->li.timeout = NCP_RETRY_TIMEOUT;
252 	ncp_conn_lock_any(ncp, td, ncp->nc_owner);
253 	*conn = ncp;
254 	ncp_conn_locklist(LK_EXCLUSIVE, td);
255 	SLIST_INSERT_HEAD(&conn_list,ncp,nc_next);
256 	ncp_conn_unlocklist(td);
257 	return (error);
258 }
259 
260 /*
261  * Remove the connection, on entry it must be locked
262  */
263 int
ncp_conn_free(struct ncp_conn * ncp)264 ncp_conn_free(struct ncp_conn *ncp)
265 {
266 	struct thread *td;
267 	int error;
268 
269 	if (ncp == NULL) {
270 		NCPFATAL("ncp == NULL\n");
271 		return 0;
272 	}
273 	if (ncp->nc_id == 0) {
274 		NCPERROR("nc_id == 0\n");
275 		return EACCES;
276 	}
277 	td = ncp->td;
278 	error = ncp_conn_assert_locked(ncp, __func__, td);
279 	if (error)
280 		return error;
281 	if (ncp->ref_cnt != 0 || (ncp->flags & NCPFL_PERMANENT))
282 		return EBUSY;
283 	if (ncp_conn_access(ncp, ncp->ucred, NCPM_WRITE))
284 		return EACCES;
285 
286 	if (ncp->flags & NCPFL_ATTACHED)
287 		ncp_ncp_disconnect(ncp);
288 	ncp_sock_disconnect(ncp);
289 
290 	/*
291 	 * Mark conn as dead and wait for other process
292 	 */
293 	ncp->nc_id = 0;
294 	ncp_conn_unlock(ncp, td);
295 	/*
296 	 * if signal is raised - how I do react ?
297 	 */
298 	lockmgr(&ncp->nc_lock, LK_DRAIN, 0);
299 	lockmgr(&ncp->nc_lock, LK_RELEASE, 0);
300 	lockdestroy(&ncp->nc_lock);
301 	while (ncp->nc_lwant) {
302 		printf("lwant = %d\n", ncp->nc_lwant);
303 		tsleep(&ncp->nc_lwant, PZERO,"ncpdr",2*hz);
304 	}
305 	ncp_conn_locklist(LK_EXCLUSIVE, td);
306 	SLIST_REMOVE(&conn_list, ncp, ncp_conn, nc_next);
307 	ncp_conn_cnt--;
308 	ncp_conn_unlocklist(td);
309 	if (ncp->li.user)
310 		free(ncp->li.user, M_NCPDATA);
311 	if (ncp->li.password)
312 		free(ncp->li.password, M_NCPDATA);
313 	crfree(ncp->nc_owner);
314 	free(ncp, M_NCPDATA);
315 	return (0);
316 }
317 
318 int
ncp_conn_reconnect(struct ncp_conn * ncp)319 ncp_conn_reconnect(struct ncp_conn *ncp)
320 {
321 	int error;
322 
323 	/*
324 	 * Close opened sockets if any
325 	 */
326 	ncp_sock_disconnect(ncp);
327 	error = ncp_sock_connect(ncp);
328 	if (error)
329 		return error;
330 	error = ncp_ncp_connect(ncp);
331 	if (error)
332 		return error;
333 	error = ncp_renegotiate_connparam(ncp, NCP_DEFAULT_BUFSIZE, 0);
334 	if (error == NWE_SIGNATURE_LEVEL_CONFLICT) {
335 		printf("Unable to negotiate requested security level\n");
336 		error = EOPNOTSUPP;
337 	}
338 	if (error) {
339 		ncp_ncp_disconnect(ncp);
340 		return error;
341 	}
342 #ifdef NCPBURST
343 	error = ncp_burst_connect(ncp);
344 	if (error) {
345 		ncp_ncp_disconnect(ncp);
346 		return error;
347 	}
348 #endif
349 	return 0;
350 }
351 
352 int
ncp_conn_login(struct ncp_conn * conn,struct thread * td,struct ucred * cred)353 ncp_conn_login(struct ncp_conn *conn, struct thread *td, struct ucred *cred)
354 {
355 	struct ncp_bindery_object user;
356 	u_char ncp_key[8];
357 	int error;
358 
359 	error = ncp_get_encryption_key(conn, ncp_key);
360 	if (error) {
361 		printf("%s: Warning: use unencrypted login\n", __func__);
362 		error = ncp_login_unencrypted(conn, conn->li.objtype,
363 		    conn->li.user, conn->li.password, td, cred);
364 	} else {
365 		error = ncp_get_bindery_object_id(conn, conn->li.objtype,
366 		    conn->li.user, &user, td, cred);
367 		if (error)
368 			return error;
369 		error = ncp_login_encrypted(conn, &user, ncp_key,
370 		    conn->li.password, td, cred);
371 	}
372 	if (!error)
373 		conn->flags |= NCPFL_LOGGED | NCPFL_WASLOGGED;
374 	return error;
375 }
376 
377 /*
378  * Lookup connection by handle, return a locked conn descriptor
379  */
380 int
ncp_conn_getbyref(int ref,struct thread * td,struct ucred * cred,int mode,struct ncp_conn ** connpp)381 ncp_conn_getbyref(int ref, struct thread *td, struct ucred *cred, int mode,
382 		  struct ncp_conn **connpp)
383 {
384 	struct ncp_conn *ncp;
385 	int error = 0;
386 
387 	ncp_conn_locklist(LK_SHARED, td);
388 	SLIST_FOREACH(ncp, &conn_list, nc_next)
389 		if (ncp->nc_id == ref) break;
390 	if (ncp == NULL) {
391 		ncp_conn_unlocklist(td);
392 		return(EBADF);
393 	}
394 	error = ncp_conn_lock2(ncp, td, cred, mode);
395 	if (!error)
396 		*connpp = ncp;
397 	return (error);
398 }
399 /*
400  * find attached, but not logged in connection to specified server
401  */
402 int
ncp_conn_getattached(struct ncp_conn_args * li,struct thread * td,struct ucred * cred,int mode,struct ncp_conn ** connpp)403 ncp_conn_getattached(struct ncp_conn_args *li, struct thread *td,
404 		     struct ucred *cred, int mode, struct ncp_conn **connpp)
405 {
406 	struct ncp_conn *ncp, *ncp2 = NULL;
407 	int error = 0;
408 
409 	ncp_conn_locklist(LK_SHARED, td);
410 	SLIST_FOREACH(ncp, &conn_list, nc_next) {
411 		if ((ncp->flags & NCPFL_LOGGED) != 0 ||
412 		    strcmp(ncp->li.server,li->server) != 0 ||
413 		    ncp->li.saddr.sa_len != li->saddr.sa_len ||
414 		    bcmp(&ncp->li.saddr,&ncp->li.saddr,li->saddr.sa_len) != 0)
415 			continue;
416 		if (ncp_suser(cred) == 0 ||
417 		    cred->cr_uid == ncp->nc_owner->cr_uid)
418 			break;
419 		error = ncp_conn_access(ncp,cred,mode);
420 		if (!error && ncp2 == NULL)
421 			ncp2 = ncp;
422 	}
423 	if (ncp == NULL) ncp = ncp2;
424 	if (ncp == NULL) {
425 		ncp_conn_unlocklist(td);
426 		return(EBADF);
427 	}
428 	error = ncp_conn_lock2(ncp, td, cred, mode);
429 	if (!error)
430 		*connpp=ncp;
431 	return (error);
432 }
433 
434 /*
435  * Lookup connection by server/user pair, return a locked conn descriptor.
436  * if li is NULL or server/user pair incomplete, try to select best connection
437  * based on owner.
438  * Connection selected in next order:
439  * 1. Try to search conn with ucred owner, if li is NULL also find a primary
440  * 2. If 1. fails try to get first suitable shared connection
441  * 3. If 2. fails then nothing can help to poor ucred owner
442  */
443 
444 int
ncp_conn_getbyli(struct ncp_conn_args * li,struct thread * td,struct ucred * cred,int mode,struct ncp_conn ** connpp)445 ncp_conn_getbyli(struct ncp_conn_args *li, struct thread *td,
446 		 struct ucred *cred, int mode, struct ncp_conn **connpp)
447 {
448 	struct ncp_conn *ncp, *ncp2 = NULL;
449 	int error = 0, partial, haveserv;
450 
451 	partial = (li == NULL || li->server[0] == 0 || li->user == NULL);
452 	haveserv = (li && li->server[0]);
453 	ncp_conn_locklist(LK_SHARED, td);
454 	SLIST_FOREACH(ncp, &conn_list, nc_next) {
455 		if (partial) {
456 			if (cred->cr_uid == ncp->nc_owner->cr_uid) {
457 				if (haveserv) {
458 					if (strcmp(ncp->li.server,li->server) == 0)
459 						break;
460 				} else {
461 					if (ncp->flags & NCPFL_PRIMARY)
462 						break;
463 					ncp2 = ncp;
464 				}
465 				continue;
466 			}
467 		} else {
468 			if (strcmp(ncp->li.server,li->server) != 0 ||
469 			    ncp->li.user == NULL ||
470 			    strcmp(ncp->li.user,li->user) != 0)
471 				continue;
472 			if (cred->cr_uid == ncp->nc_owner->cr_uid)
473 				break;
474 			if (ncp_suser(cred) == 0)
475 				ncp2 = ncp;
476 		}
477 		error = ncp_conn_access(ncp,cred,mode);
478 		if (!error && ncp2 == NULL)
479 			ncp2 = ncp;
480 	}
481 	if (ncp == NULL) ncp = ncp2;
482 	if (ncp == NULL) {
483 		ncp_conn_unlocklist(td);
484 		return(EBADF);
485 	}
486 	error = ncp_conn_lock2(ncp, td, cred,mode);
487 	if (!error)
488 		*connpp=ncp;
489 	return (error);
490 }
491 
492 /*
493  * Set primary connection flag, since it have sence only for an owner,
494  * only owner can modify this flag.
495  * connection expected to be locked.
496  */
497 int
ncp_conn_setprimary(struct ncp_conn * conn,int on)498 ncp_conn_setprimary(struct ncp_conn *conn, int on)
499 {
500 	struct ncp_conn *ncp=NULL;
501 
502 	if (conn->ucred->cr_uid != conn->nc_owner->cr_uid)
503 		return EACCES;
504 	ncp_conn_locklist(LK_SHARED, conn->td);
505 	SLIST_FOREACH(ncp, &conn_list, nc_next) {
506 		if (conn->ucred->cr_uid == ncp->nc_owner->cr_uid)
507 			ncp->flags &= ~NCPFL_PRIMARY;
508 	}
509 	ncp_conn_unlocklist(conn->td);
510 	if (on)
511 		conn->flags |= NCPFL_PRIMARY;
512 	return 0;
513 }
514 /*
515  * Lease conn to given proc, returning unique handle
516  * problem: how locks should be applied ?
517  */
518 int
ncp_conn_gethandle(struct ncp_conn * conn,struct thread * td,struct ncp_handle ** handle)519 ncp_conn_gethandle(struct ncp_conn *conn, struct thread *td, struct ncp_handle **handle)
520 {
521 	struct ncp_handle *refp;
522 
523 	lockmgr(&lhlock, LK_EXCLUSIVE, 0);
524 	SLIST_FOREACH(refp, &lhlist, nh_next)
525 		if (refp->nh_conn == conn && td == refp->nh_td) break;
526 	if (refp) {
527 		conn->ref_cnt++;
528 		refp->nh_ref++;
529 		*handle = refp;
530 		lockmgr(&lhlock, LK_RELEASE, 0);
531 		return 0;
532 	}
533 	refp = malloc(sizeof(struct ncp_handle),M_NCPDATA,
534 	    M_WAITOK | M_ZERO);
535 	SLIST_INSERT_HEAD(&lhlist,refp,nh_next);
536 	refp->nh_ref++;
537 	refp->nh_td = td;
538 	refp->nh_conn = conn;
539 	refp->nh_id = ncp_next_handle++;
540 	*handle = refp;
541 	conn->ref_cnt++;
542 	lockmgr(&lhlock, LK_RELEASE, 0);
543 	return 0;
544 }
545 /*
546  * release reference, if force - ignore refcount
547  */
548 int
ncp_conn_puthandle(struct ncp_handle * handle,struct thread * td,int force)549 ncp_conn_puthandle(struct ncp_handle *handle, struct thread *td, int force)
550 {
551 	struct ncp_handle *refp = handle;
552 
553 	lockmgr(&lhlock, LK_EXCLUSIVE, 0);
554 	refp->nh_ref--;
555 	refp->nh_conn->ref_cnt--;
556 	if (force) {
557 		refp->nh_conn->ref_cnt -= refp->nh_ref;
558 		refp->nh_ref = 0;
559 	}
560 	if (refp->nh_ref == 0) {
561 		SLIST_REMOVE(&lhlist, refp, ncp_handle, nh_next);
562 		free(refp, M_NCPDATA);
563 	}
564 	lockmgr(&lhlock, LK_RELEASE, 0);
565 	return 0;
566 }
567 /*
568  * find a connHandle
569  */
570 int
ncp_conn_findhandle(int connHandle,struct thread * td,struct ncp_handle ** handle)571 ncp_conn_findhandle(int connHandle, struct thread *td, struct ncp_handle **handle) {
572 	struct ncp_handle *refp;
573 
574 	lockmgr(&lhlock, LK_SHARED, 0);
575 	SLIST_FOREACH(refp, &lhlist, nh_next)
576 		if (refp->nh_td == td && refp->nh_id == connHandle) break;
577 	lockmgr(&lhlock, LK_RELEASE, 0);
578 	if (refp == NULL) {
579 		return EBADF;
580 	}
581 	*handle = refp;
582 	return 0;
583 }
584 /*
585  * Clear handles associated with specified process
586  */
587 int
ncp_conn_putprochandles(struct thread * td)588 ncp_conn_putprochandles(struct thread *td)
589 {
590 	struct ncp_handle *hp, *nhp;
591 	int haveone = 0;
592 
593 	lockmgr(&lhlock, LK_EXCLUSIVE, 0);
594 	for (hp = SLIST_FIRST(&lhlist); hp; hp = nhp) {
595 		nhp = SLIST_NEXT(hp, nh_next);
596 		if (hp->nh_td != td) continue;
597 		haveone = 1;
598 		hp->nh_conn->ref_cnt -= hp->nh_ref;
599 		SLIST_REMOVE(&lhlist, hp, ncp_handle, nh_next);
600 		free(hp, M_NCPDATA);
601 	}
602 	lockmgr(&lhlock, LK_RELEASE, 0);
603 	return haveone;
604 }
605 /*
606  * remove references in all possible connections,
607  * XXX - possible problem is a locked list.
608  */
609 /*void
610 ncp_conn_list_rm_ref(pid_t pid) {
611 	struct ncp_conn *ncp;
612 
613 	ncp_conn_locklist(LK_SHARED, NULL);
614 	SLIST_FOREACH(ncp, &conn_list, nc_next) {
615 		ncp_conn_rm_ref(ncp,pid,1);
616 	}
617 	ncp_conn_unlocklist(NULL);
618 	return;
619 }
620 */
621 int
ncp_conn_getinfo(struct ncp_conn * ncp,struct ncp_conn_stat * ncs)622 ncp_conn_getinfo(struct ncp_conn *ncp, struct ncp_conn_stat *ncs) {
623 	bzero(ncs,sizeof(*ncs));
624 	ncs->li = ncp->li;
625 	ncs->li.user = ncs->user;
626 	if (ncp->li.user)
627 		strcpy(ncs->user, ncp->li.user);
628 	ncs->li.password = NULL;
629 	ncs->connRef = ncp->nc_id;
630 	ncs->ref_cnt = ncp->ref_cnt;
631 	ncs->connid = ncp->connid;
632 	ncs->owner = ncp->nc_owner->cr_uid;
633 	ncs->group = ncp->nc_group;
634 	ncs->flags = ncp->flags;
635 	ncs->buffer_size = ncp->buffer_size;
636 	return 0;
637 }
638 
639 static int
ncp_sysctl_connstat(SYSCTL_HANDLER_ARGS)640 ncp_sysctl_connstat(SYSCTL_HANDLER_ARGS)
641 {
642 	int error;
643 	struct ncp_conn_stat ncs;
644 	struct ncp_conn *ncp;
645 /*	struct ucred *cred = req->td->td_ucred;*/
646 
647 	error = sysctl_wire_old_buffer(req, 0);
648 	if (error != 0)
649 		return (error);
650 	ncp_conn_locklist(LK_SHARED, req->td);
651 	error = SYSCTL_OUT(req, &ncp_conn_cnt, sizeof(ncp_conn_cnt));
652 	SLIST_FOREACH(ncp, &conn_list, nc_next) {
653 		if (error) break;
654 		/* I can't do conn_lock while list is locked */
655 		ncp->nc_lwant++;
656 		ncp_conn_getinfo(ncp, &ncs);
657 		ncp->nc_lwant--;
658 		error = SYSCTL_OUT(req, &ncs, sizeof(ncs));
659 	}
660 	ncp_conn_unlocklist(req->td);
661 	return(error);
662 }
663