Use a character device and ioctl() for communication between libncp

and the kernel instead of adding more syscalls at runtime. As a bonus,
you can now restrict access to the kernel NCP interface with chmod.
This commit is contained in:
Tim J. Robbins 2003-02-28 04:31:29 +00:00
parent 3fb37429df
commit 0e66bb97d8
6 changed files with 195 additions and 173 deletions

View File

@ -1,16 +0,0 @@
/*
* Describes all ncp_lib kernel functions
*
* $FreeBSD$
*/
#ifndef _NCP_MOD_H_
#define _NCP_MOD_H_
/* order of calls in syscall table relative to offset in system table */
#define NCP_SE(callno) (callno+sysentoffset)
#define NCP_CONNSCAN NCP_SE(0)
#define NCP_CONNECT NCP_SE(1)
#define NCP_INTFN NCP_SE(2)
#define SNCP_REQUEST NCP_SE(3)
#endif /* !_NCP_MOD_H_ */

View File

@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include "ipxsap.h"
#include <netncp/ncp_lib.h>
#include "ncp_mod.h"
static int ncp_find_server_in(struct ncp_conn_loginfo *li, int type, char *server_name);

View File

@ -37,9 +37,11 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <paths.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -49,9 +51,9 @@ __FBSDID("$FreeBSD$");
#include <netncp/ncp_rcfile.h>
#include <netncp/ncp_nls.h>
/*#include <netncp/ncp_cfg.h>*/
#include "ncp_mod.h"
#include <netncp/ncpio.h>
int sysentoffset;
#define _PATH_NCP _PATH_DEV NCP_NAME
void
ncp_add_word_lh(struct ncp_buf *conn, u_int16_t x) {
@ -158,7 +160,17 @@ ncp_reply_dword_lh(struct ncp_buf *conn, int offset) {
int
ncp_connect(struct ncp_conn_args *li, int *connHandle) {
return syscall(NCP_CONNECT,li,connHandle);
struct ncpioc_connect args;
int fd, r;
if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
return (errno);
args.ioc_li = li;
args.ioc_connhandle = connHandle;
errno = 0;
(void)ioctl(fd, NCPIOC_CONNECT, &args);
r = errno;
close(fd);
return (r);
}
int
@ -172,18 +184,38 @@ ncp_disconnect(int cH) {
int
ncp_request(int connHandle,int function, struct ncp_buf *ncpbuf){
int err = syscall(SNCP_REQUEST,connHandle,function,ncpbuf);
return (err<0) ? errno : 0;
struct ncpioc_request args;
int fd, r;
if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
return (errno);
args.ioc_connhandle = connHandle;
args.ioc_fn = function;
args.ioc_ncpbuf = ncpbuf;
errno = 0;
(void)ioctl(fd, NCPIOC_REQUEST, &args);
r = errno;
close(fd);
return (r);
}
int
ncp_conn_request(int connHandle, struct ncp_buf *ncpbuf){
return syscall(SNCP_REQUEST, connHandle, NCP_CONN, ncpbuf);
return (ncp_request(connHandle, NCP_CONN, ncpbuf));
}
int
ncp_conn_scan(struct ncp_conn_loginfo *li, int *connid) {
return syscall(NCP_CONNSCAN,li, connid);
struct ncpioc_connscan args;
int fd, r;
if ((fd = open(_PATH_NCP, O_RDWR)) < 0)
return (errno);
args.ioc_li = li;
args.ioc_connhandle = connid;
errno = 0;
(void)ioctl(fd, NCPIOC_CONNSCAN, &args);
r = errno;
close(fd);
return (r);
}
NWCCODE
@ -211,21 +243,11 @@ NWRequest(NWCONN_HANDLE cH, nuint16 fn,
int
ncp_initlib(void){
int error;
int len = sizeof(sysentoffset);
int kv, kvlen = sizeof(kv);
static int ncp_initialized;
if (ncp_initialized)
return 0;
#if __FreeBSD_version < 400001
error = sysctlbyname("net.ipx.ncp.sysent", &sysentoffset, &len, NULL, 0);
#else
error = sysctlbyname("net.ncp.sysent", &sysentoffset, &len, NULL, 0);
#endif
if (error) {
fprintf(stderr, "%s: can't find kernel module\n", __FUNCTION__);
return error;
}
#if __FreeBSD_version < 400001
error = sysctlbyname("net.ipx.ncp.version", &kv, &kvlen, NULL, 0);
#else

View File

@ -11,7 +11,7 @@
#define _NETNCP_NCP_H_
#define NCP_VERMAJ 1
#define NCP_VERMIN 3400
#define NCP_VERMIN 3500
#define NCP_VERSION (NCP_VERMAJ*100000 + NCP_VERMIN)
typedef u_int32_t nwdirent;

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2003 Tim J. Robbins.
* Copyright (c) 1999, 2000, 2001 Boris Popov
* All rights reserved.
*
@ -33,14 +34,13 @@
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/sysent.h>
#include <sys/conf.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/ioccom.h>
#include <netncp/ncp.h>
#include <netncp/ncp_conn.h>
@ -49,40 +49,75 @@
#include <netncp/ncp_user.h>
#include <netncp/ncp_rq.h>
#include <netncp/ncp_nls.h>
#include <netncp/ncpio.h>
int ncp_version = NCP_VERSION;
static int ncp_sysent;
SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester");
SYSCTL_INT(_net_ncp, OID_AUTO, sysent, CTLFLAG_RD, &ncp_sysent, 0, "");
SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, "");
MODULE_VERSION(ncp, 1);
MODULE_DEPEND(ncp, libmchain, 1, 1, 1);
static dev_t ncp_dev;
static d_ioctl_t ncp_ioctl;
static struct cdevsw ncp_cdevsw = {
/* open */ nullopen,
/* close */ nullclose,
/* read */ noread,
/* write */ nowrite,
/* ioctl */ ncp_ioctl,
/* poll */ nopoll,
/* mmap */ nommap,
/* strategy */ nostrategy,
/* name */ "ncp",
/* maj */ MAJOR_AUTO,
/* dump */ nodump,
/* psize */ nopsize,
/* flags */ 0
};
static int ncp_conn_frag_rq(struct ncp_conn *, struct thread *,
struct ncp_conn_frag *);
static int ncp_conn_handler(struct thread *, struct ncpioc_request *,
struct ncp_conn *, struct ncp_handle *);
static int sncp_conn_scan(struct thread *, struct ncpioc_connscan *);
static int sncp_connect(struct thread *, struct ncpioc_connect *);
static int sncp_request(struct thread *, struct ncpioc_request *);
static int
ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td,
struct ncp_conn_frag *nfp);
ncp_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
{
switch (cmd) {
case NCPIOC_CONNECT:
return (sncp_connect(td, (struct ncpioc_connect *)data));
case NCPIOC_CONNSCAN:
return (sncp_conn_scan(td, (struct ncpioc_connscan *)data));
case NCPIOC_REQUEST:
return (sncp_request(td, (struct ncpioc_request *)data));
}
return (EINVAL);
}
/*
* Attach to NCP server
*/
struct sncp_connect_args {
struct ncp_conn_args *li;
int *connHandle;
};
static int
sncp_connect(struct thread *td, struct sncp_connect_args *uap)
sncp_connect(struct thread *td, struct ncpioc_connect *args)
{
int connHandle = 0, error;
struct ncp_conn *conn;
struct ncp_handle *handle;
struct ncp_conn_args li;
checkbad(copyin(uap->li,&li,sizeof(li)));
checkbad(copyout(&connHandle,uap->connHandle,sizeof(connHandle))); /* check before */
checkbad(copyin(args->ioc_li,&li,sizeof(li)));
/* XXX Should be useracc() */
checkbad(copyout(&connHandle,args->ioc_connhandle,
sizeof(connHandle)));
li.password = li.user = NULL;
error = ncp_conn_getattached(&li, td, td->td_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn);
if (error) {
@ -95,45 +130,36 @@ sncp_connect(struct thread *td, struct sncp_connect_args *uap)
}
if (!error) {
error = ncp_conn_gethandle(conn, td, &handle);
copyout(&handle->nh_id, uap->connHandle, sizeof(uap->connHandle));
copyout(&handle->nh_id, args->ioc_connhandle,
sizeof(args->ioc_connhandle));
ncp_conn_unlock(conn,td);
}
bad:
td->td_retval[0]=error;
return error;
}
struct sncp_request_args {
int connHandle;
int fn;
struct ncp_buf *ncpbuf;
};
static int ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
struct ncp_conn *conn, struct ncp_handle *handle);
static int
sncp_request(struct thread *td, struct sncp_request_args *uap)
sncp_request(struct thread *td, struct ncpioc_request *args)
{
struct ncp_rq *rqp;
struct ncp_conn *conn;
struct ncp_handle *handle;
int error = 0, rqsize;
error = ncp_conn_findhandle(uap->connHandle, td, &handle);
error = ncp_conn_findhandle(args->ioc_connhandle, td, &handle);
if (error)
return error;
conn = handle->nh_conn;
if (uap->fn == NCP_CONN)
return ncp_conn_handler(td, uap, conn, handle);
error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
if (args->ioc_fn == NCP_CONN)
return ncp_conn_handler(td, args, conn, handle);
error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int));
if (error)
return(error);
error = ncp_rq_alloc(uap->fn, conn, td, td->td_ucred, &rqp);
error = ncp_rq_alloc(args->ioc_fn, conn, td, td->td_ucred, &rqp);
if (error)
return error;
if (rqsize) {
error = mb_put_mem(&rqp->rq, (caddr_t)uap->ncpbuf->packet,
error = mb_put_mem(&rqp->rq, (caddr_t)args->ioc_ncpbuf->packet,
rqsize, MB_MUSER);
if (error)
goto bad;
@ -141,11 +167,11 @@ sncp_request(struct thread *td, struct sncp_request_args *uap)
rqp->nr_flags |= NCPR_DONTFREEONERR;
error = ncp_request(rqp);
if (error == 0 && rqp->nr_rpsize)
error = md_get_mem(&rqp->rp, (caddr_t)uap->ncpbuf->packet,
error = md_get_mem(&rqp->rp, (caddr_t)args->ioc_ncpbuf->packet,
rqp->nr_rpsize, MB_MUSER);
copyout(&rqp->nr_cs, &uap->ncpbuf->cs, sizeof(rqp->nr_cs));
copyout(&rqp->nr_cc, &uap->ncpbuf->cc, sizeof(rqp->nr_cc));
copyout(&rqp->nr_rpsize, &uap->ncpbuf->rpsize, sizeof(rqp->nr_rpsize));
copyout(&rqp->nr_cs, &args->ioc_ncpbuf->cs, sizeof(rqp->nr_cs));
copyout(&rqp->nr_cc, &args->ioc_ncpbuf->cc, sizeof(rqp->nr_cc));
copyout(&rqp->nr_rpsize, &args->ioc_ncpbuf->rpsize, sizeof(rqp->nr_rpsize));
bad:
ncp_rq_done(rqp);
return error;
@ -186,7 +212,7 @@ ncp_mod_login(struct ncp_conn *conn, char *user, int objtype, char *password,
}
static int
ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
ncp_conn_handler(struct thread *td, struct ncpioc_request *args,
struct ncp_conn *conn, struct ncp_handle *hp)
{
int error = 0, rqsize, subfn;
@ -195,11 +221,11 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
char *pdata;
cred = td->td_ucred;
error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int));
if (error)
return(error);
error = 0;
pdata = uap->ncpbuf->packet;
pdata = args->ioc_ncpbuf->packet;
subfn = *(pdata++) & 0xff;
rqsize--;
switch (subfn) {
@ -227,7 +253,7 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
else
error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
rwrq.nrw_cnt -= auio.uio_resid;
td->td_retval[0] = rwrq.nrw_cnt;
/*td->td_retval[0] = rwrq.nrw_cnt;*/
break;
} /* case int_read/write */
case NCP_CONN_SETFLAGS: {
@ -272,7 +298,6 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
error = ncp_mod_login(conn, la.username, la.objtype,
la.password, td, td->td_ucred);
ncp_conn_unlock(conn, td);
td->td_retval[0] = error;
break;
}
case NCP_CONN_GETINFO: {
@ -283,8 +308,8 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
if (error)
return error;
ncp_conn_getinfo(conn, &ncs);
copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
error = copyout(&ncs, &uap->ncpbuf->packet, len);
copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
error = copyout(&ncs, &args->ioc_ncpbuf->packet, len);
ncp_conn_unlock(conn, td);
break;
}
@ -295,9 +320,10 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
if (error)
return error;
len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0;
copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
if (len) {
error = copyout(conn->li.user, &uap->ncpbuf->packet, len);
error = copyout(conn->li.user,
&args->ioc_ncpbuf->packet, len);
}
ncp_conn_unlock(conn, td);
break;
@ -308,9 +334,10 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ);
if (error)
return error;
copyout(&len, &uap->ncpbuf->rpsize, sizeof(int));
copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int));
if (len) {
error = copyout(&conn->nc_id, &uap->ncpbuf->packet, len);
error = copyout(&conn->nc_id,
&args->ioc_ncpbuf->packet, len);
}
ncp_conn_unlock(conn, td);
break;
@ -336,10 +363,11 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
error = ncp_conn_lock(conn, td, cred, NCPM_READ);
if (error) break;
copyout(&len, &uap->ncpbuf->rpsize, len);
copyout(&len, &args->ioc_ncpbuf->rpsize, len);
error = ncp_conn_gethandle(conn, td, &newhp);
if (!error)
error = copyout(&newhp->nh_id, uap->ncpbuf->packet, len);
error = copyout(&newhp->nh_id,
args->ioc_ncpbuf->packet, len);
ncp_conn_unlock(conn, td);
break;
}
@ -358,13 +386,8 @@ ncp_conn_handler(struct thread *td, struct sncp_request_args *uap,
return error;
}
struct sncp_conn_scan_args {
struct ncp_conn_args *li;
int *connHandle;
};
static int
sncp_conn_scan(struct thread *td, struct sncp_conn_scan_args *uap)
sncp_conn_scan(struct thread *td, struct ncpioc_connscan *args)
{
int connHandle = 0, error;
struct ncp_conn_args li, *lip;
@ -372,8 +395,8 @@ sncp_conn_scan(struct thread *td, struct sncp_conn_scan_args *uap)
struct ncp_handle *hp;
char *user = NULL, *password = NULL;
if (uap->li) {
if (copyin(uap->li, &li, sizeof(li)))
if (args->ioc_li) {
if (copyin(args->ioc_li, &li, sizeof(li)))
return EFAULT;
lip = &li;
} else {
@ -406,13 +429,12 @@ sncp_conn_scan(struct thread *td, struct sncp_conn_scan_args *uap)
ncp_conn_gethandle(conn, td, &hp);
connHandle = hp->nh_id;
ncp_conn_unlock(conn, td);
copyout(&connHandle, uap->connHandle, sizeof(connHandle));
copyout(&connHandle, args->ioc_connhandle, sizeof(connHandle));
}
if (user)
free(user, M_NCPDATA);
if (password)
free(password, M_NCPDATA);
td->td_retval[0] = error;
return error;
}
@ -461,83 +483,16 @@ ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td,
return error;
}
/*
* Internal functions, here should be all calls that do not require connection.
* To simplify possible future movement to cdev, we use IOCTL macros.
* Pretty much of this stolen from ioctl() function.
*/
struct sncp_intfn_args {
u_long com;
caddr_t data;
};
static int
sncp_intfn(struct proc *p, struct sncp_intfn_args *uap)
{
return ENOSYS;
}
/*
* define our new system calls
*/
static struct sysent newent[] = {
{2, (sy_call_t*)sncp_conn_scan},
{2, (sy_call_t*)sncp_connect},
{2, (sy_call_t*)sncp_intfn},
{3, (sy_call_t*)sncp_request}
};
#define SC_SIZE sizeof(newent)/sizeof(struct sysent)
/*
* Miscellaneous modules must have their own save areas...
*/
static struct sysent oldent[SC_SIZE]; /* save are for old callslot entry*/
/*
* Number of syscall entries for a.out executables
*/
#define nsysent SYS_MAXSYSCALL
/* #define nsysent (elf_sysvec.sv_size) */
static int
ncp_load(void)
{
int i, ff, scnt, err = 0;
int error;
while (1) {
/* Search the table looking for an enough number of slots... */
for (scnt = 0, ff = -1, i = 0; i < nsysent; i++) {
if (sysent[i].sy_call == (sy_call_t *)lkmnosys) {
if (ff == -1) {
ff = i;
scnt = 1;
} else {
scnt++;
if (scnt == SC_SIZE)
break;
}
} else {
ff = -1;
}
}
/* out of allocable slots?*/
if (i == nsysent || ff == -1) {
err = ENFILE;
break;
}
err = ncp_init();
if (err)
break;
bcopy(&sysent[ff], &oldent, sizeof(struct sysent) * SC_SIZE);
bcopy(&newent, &sysent[ff], sizeof(struct sysent) * SC_SIZE);
ncp_sysent = ff; /* slot in sysent[]*/
printf("ncp_load: [%d-%d]\n", ff, i);
break;
}
return (err);
if ((error = ncp_init()) != 0)
return (error);
ncp_dev = make_dev(&ncp_cdevsw, 0, 0, 0, 0666, "ncp");
printf("ncp_load: loaded\n");
return (0);
}
static int
@ -547,10 +502,10 @@ ncp_unload(void)
error = ncp_done();
if (error)
return error;
bcopy(&oldent, &sysent[ncp_sysent], sizeof(struct sysent) * SC_SIZE);
printf( "ncp_unload: unloaded\n");
return 0;
return (error);
destroy_dev(ncp_dev);
printf("ncp_unload: unloaded\n");
return (0);
}
static int

62
sys/netncp/ncpio.h Normal file
View File

@ -0,0 +1,62 @@
/*-
* Copyright (c) 2003 Tim J. Robbins.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _NETNCP_NCPIO_H_
#define _NETNCP_NCPIO_H_
#ifndef _KERNEL
#include <sys/types.h>
#endif
#include <sys/ioccom.h>
#define NCP_NAME "ncp"
struct ncp_conn_args;
struct ncp_buf;
struct ncpioc_connect {
struct ncp_conn_args *ioc_li;
int *ioc_connhandle;
};
struct ncpioc_request {
int ioc_connhandle;
int ioc_fn;
struct ncp_buf *ioc_ncpbuf;
};
struct ncpioc_connscan {
struct ncp_conn_args *ioc_li;
int *ioc_connhandle;
};
#define NCPIOC_CONNECT _IOW('N', 100, struct ncpioc_connect)
#define NCPIOC_REQUEST _IOW('N', 101, struct ncpioc_request)
#define NCPIOC_CONNSCAN _IOW('N', 102, struct ncpioc_connscan)
#endif /* _NETNCP_NCPIO_H_ */