Major update of NCP requester:

Use mchain API to work with mbuf chains.

Do not depend on INET and IPX options.

Allocate ncp_rq structure dynamically to prevent possible stack overflows.

Let ncp_request() dispose control structure if request failed.

Move all NCP wrappers to ncp_ncp.c file and all NCP request processing
functions to ncp_rq.c file.

Improve reconnection logic.

Misc style fixes.
This commit is contained in:
Boris Popov 2001-03-10 05:24:45 +00:00
parent df54111fe4
commit 29ad26f932
14 changed files with 954 additions and 1292 deletions

View File

@ -41,8 +41,11 @@
#include <sys/sysctl.h>
#include <netncp/ncp.h>
#include <netncp/nwerror.h>
#include <netncp/ncp_subr.h>
#include <netncp/ncp_conn.h>
#include <netncp/ncp_sock.h>
#include <netncp/ncp_ncp.h>
SLIST_HEAD(ncp_handle_head,ncp_handle);
@ -72,31 +75,40 @@ SYSCTL_PROC(_net_ncp, OID_AUTO, conn_stat, CTLFLAG_RD|CTLTYPE_OPAQUE,
MALLOC_DEFINE(M_NCPDATA, "NCP data", "NCP private data");
int
ncp_conn_init(void) {
ncp_conn_init(void)
{
lockinit(&listlock, PSOCK, "ncpll", 0, 0);
lockinit(&lhlock, PSOCK, "ncplh", 0, 0);
return 0;
}
int
ncp_conn_destroy(void) {
ncp_conn_destroy(void)
{
if (ncp_conn_cnt) {
NCPERROR("There are %d connections active\n", ncp_conn_cnt);
return EBUSY;
}
lockdestroy(&listlock);
lockdestroy(&lhlock);
return 0;
}
int
ncp_conn_locklist(int flags, struct proc *p){
ncp_conn_locklist(int flags, struct proc *p)
{
return lockmgr(&listlock, flags | LK_CANRECURSE, 0, p);
}
void
ncp_conn_unlocklist(struct proc *p){
ncp_conn_unlocklist(struct proc *p)
{
lockmgr(&listlock, LK_RELEASE, 0, p);
}
int
ncp_conn_access(struct ncp_conn *conn, struct ucred *cred, mode_t mode) {
ncp_conn_access(struct ncp_conn *conn, struct ucred *cred, mode_t mode)
{
int error;
if (cred == NOCRED || ncp_suser(cred) == 0 ||
@ -110,7 +122,8 @@ ncp_conn_access(struct ncp_conn *conn, struct ucred *cred, mode_t mode) {
}
int
ncp_conn_lock_any(struct ncp_conn *conn, struct proc *p, struct ucred *cred) {
ncp_conn_lock_any(struct ncp_conn *conn, struct proc *p, struct ucred *cred)
{
int error;
if (conn->nc_id == 0) return EACCES;
@ -133,7 +146,8 @@ ncp_conn_lock_any(struct ncp_conn *conn, struct proc *p, struct ucred *cred) {
}
int
ncp_conn_lock(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode) {
ncp_conn_lock(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode)
{
int error;
error = ncp_conn_access(conn,cred,mode);
@ -145,7 +159,8 @@ ncp_conn_lock(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mod
* Lock conn but unlock connlist
*/
static int
ncp_conn_lock2(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode) {
ncp_conn_lock2(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mode)
{
int error;
error = ncp_conn_access(conn,cred,mode);
@ -164,7 +179,8 @@ ncp_conn_lock2(struct ncp_conn *conn, struct proc *p, struct ucred *cred, int mo
}
void
ncp_conn_unlock(struct ncp_conn *conn, struct proc *p) {
ncp_conn_unlock(struct ncp_conn *conn, struct proc *p)
{
/*
* note, that LK_RELASE will do wakeup() instead of wakeup_one().
* this will do a little overhead
@ -183,11 +199,31 @@ ncp_conn_assert_locked(struct ncp_conn *conn,char *checker, struct proc *p){
* create, fill with defaults and return in locked state
*/
int
ncp_conn_alloc(struct proc *p, struct ucred *cred, struct ncp_conn **conn)
ncp_conn_alloc(struct ncp_conn_args *cap, struct proc *p, struct ucred *cred,
struct ncp_conn **conn)
{
int error;
struct ncp_conn *ncp;
struct ucred *owner;
int error, isroot;
if (cap->saddr.sa_family != AF_INET && cap->saddr.sa_family != AF_IPX)
return EPROTONOSUPPORT;
isroot = ncp_suser(cred) == 0;
/*
* Only root can change ownership
*/
if (cap->owner != NCP_DEFAULT_OWNER && !isroot)
return EPERM;
if (cap->group != NCP_DEFAULT_GROUP &&
!groupmember(cap->group, cred) && !isroot)
return EPERM;
if (cap->owner != NCP_DEFAULT_OWNER) {
owner = crget();
owner->cr_uid = cap->owner;
} else {
owner = cred;
crhold(owner);
}
MALLOC(ncp, struct ncp_conn *, sizeof(struct ncp_conn),
M_NCPDATA, M_WAITOK | M_ZERO);
error = 0;
@ -197,6 +233,14 @@ ncp_conn_alloc(struct proc *p, struct ucred *cred, struct ncp_conn **conn)
ncp->nc_owner = cred;
ncp->seq = 0;
ncp->connid = 0xFFFF;
ncp->li = *cap;
ncp->nc_group = (cap->group != NCP_DEFAULT_GROUP) ?
cap->group : cred->cr_groups[0];
if (cap->retry_count == 0)
ncp->li.retry_count = NCP_RETRY_COUNT;
if (cap->timeout == 0)
ncp->li.timeout = NCP_RETRY_TIMEOUT;
ncp_conn_lock_any(ncp, p, ncp->nc_owner);
*conn = ncp;
ncp_conn_locklist(LK_EXCLUSIVE, p);
@ -209,60 +253,93 @@ ncp_conn_alloc(struct proc *p, struct ucred *cred, struct ncp_conn **conn)
* Remove the connection, on entry it must be locked
*/
int
ncp_conn_free(struct ncp_conn *ncp) {
ncp_conn_free(struct ncp_conn *ncp)
{
struct proc *p;
int error;
struct ncp_conn *ncp1;
if (ncp == NULL) {
NCPFATAL("ncp == NULL\n");
return 0;
}
if (ncp->nc_id == 0) {
printf("already!!!!\n");
NCPERROR("nc_id == 0\n");
return EACCES;
}
if (ncp==NULL) {
NCPFATAL("conn==NULL !\n");
return(EIO);
}
error = ncp_conn_assert_locked(ncp, __FUNCTION__, ncp->procp);
if (error) return error;
if (ncp->ref_cnt) {
NCPFATAL("there are %d referenses left\n",ncp->ref_cnt);
return(EBUSY);
}
p = ncp->procp;
error = ncp_conn_assert_locked(ncp, __FUNCTION__, p);
if (error)
return error;
if (ncp->ref_cnt != 0 || (ncp->flags & NCPFL_PERMANENT))
return EBUSY;
if (ncp_conn_access(ncp, ncp->ucred, NCPM_WRITE))
return EACCES;
if ((ncp->flags & (NCPFL_INVALID | NCPFL_ATTACHED)) == NCPFL_ATTACHED)
ncp_ncp_disconnect(ncp);
ncp_sock_disconnect(ncp);
/*
* Mark conn as died and wait for other process
* Mark conn as dead and wait for other process
*/
ncp->nc_id = 0;
ncp_conn_unlock(ncp,ncp->procp);
ncp_conn_unlock(ncp, p);
/*
* if signal is raised - how I do react ?
*/
lockmgr(&ncp->nc_lock, LK_DRAIN, 0, ncp->procp);
lockmgr(&ncp->nc_lock, LK_DRAIN, 0, p);
lockdestroy(&ncp->nc_lock);
while (ncp->nc_lwant) {
printf("lwant = %d\n", ncp->nc_lwant);
tsleep(&ncp->nc_lwant, PZERO,"ncpdr",2*hz);
}
ncp_conn_locklist(LK_EXCLUSIVE, ncp->procp);
/*
* It is possible, that other process destroy connection while we draining,
* and free it. So, we must rescan list
*/
SLIST_FOREACH(ncp1, &conn_list, nc_next) {
if (ncp1 == ncp) break;
}
if (ncp1 == NULL) {
ncp_conn_unlocklist(ncp->procp);
return 0;
}
ncp_conn_locklist(LK_EXCLUSIVE, p);
SLIST_REMOVE(&conn_list, ncp, ncp_conn, nc_next);
ncp_conn_cnt--;
ncp_conn_unlocklist(ncp->procp);
if (ncp->li.user) free(ncp->li.user, M_NCPDATA);
if (ncp->li.password) free(ncp->li.password, M_NCPDATA);
ncp_conn_unlocklist(p);
if (ncp->li.user)
free(ncp->li.user, M_NCPDATA);
if (ncp->li.password)
free(ncp->li.password, M_NCPDATA);
crfree(ncp->nc_owner);
FREE(ncp, M_NCPDATA);
return (0);
}
int
ncp_conn_reconnect(struct ncp_conn *ncp)
{
int error;
/*
* Close opened sockets if any
*/
ncp_sock_disconnect(ncp);
error = ncp_sock_connect(ncp);
if (error)
return error;
error = ncp_ncp_connect(ncp);
if (error)
return error;
error = ncp_renegotiate_connparam(ncp, NCP_DEFAULT_BUFSIZE, 0);
if (error == NWE_SIGNATURE_LEVEL_CONFLICT) {
printf("Unable to negotiate requested security level\n");
error = EOPNOTSUPP;
}
if (error) {
ncp_ncp_disconnect(ncp);
return error;
}
#ifdef NCPBURST
error = ncp_burst_connect(ncp);
if (error) {
ncp_ncp_disconnect(ncp);
return error;
}
#endif
return 0;
}
/*
* Lookup connection by handle, return a locked conn descriptor
*/

View File

@ -34,17 +34,13 @@
#ifndef _NETNCP_NCP_CONN_H_
#define _NETNCP_NCP_CONN_H_
#ifdef INET
#ifndef _NETINET_IN_H_
#include <netinet/in.h>
#endif
#endif
#ifdef IPX
#ifndef _NETIPX_IPX_H_
#include <netipx/ipx.h>
#endif
#endif
#ifndef _SYS_SOCKET_H_
#include <sys/socket.h>
@ -55,14 +51,16 @@
#define NCP_ON_TCP 1*/
/* flags field in conn structure */
#define NCPFL_SOCONN 0x01 /* socket layer is up */
#define NCPFL_ATTACHED 0x02 /* ncp layer is up */
#define NCPFL_LOGGED 0x04 /* logged in to server */
#define NCPFL_INVALID 0x08 /* last request was not completed */
#define NCPFL_INTR 0x10 /* interrupted call */
#define NCPFL_RESTORING 0x20 /* trying to reconnect */
#define NCPFL_PERMANENT 0x40 /* no way to kill conn, when this set */
#define NCPFL_PRIMARY 0x80 /* have meaning only for owner */
#define NCPFL_SOCONN 0x0001 /* socket layer is up */
#define NCPFL_ATTACHED 0x0002 /* ncp layer is up */
#define NCPFL_LOGGED 0x0004 /* logged in to server */
#define NCPFL_INVALID 0x0008 /* last request was not completed */
#define NCPFL_INTR 0x0010 /* interrupted call */
#define NCPFL_RESTORING 0x0020 /* trying to reconnect */
#define NCPFL_PERMANENT 0x0040 /* no way to kill conn, when this set */
#define NCPFL_PRIMARY 0x0080 /* have meaning only for owner */
#define NCPFL_WASATTACHED 0x0100 /* there was at least one successfull connect */
#define NCPFL_WASLOGGED 0x0200 /* there was at least one successfull login */
#define NCPFL_SIGNACTIVE 0x1000 /* packet signing active */
#define NCPFL_SIGNWANTED 0x2000 /* signing should start */
@ -92,12 +90,8 @@ struct ncp_conn_args {
u_int32_t objtype;
union {
struct sockaddr addr;
#ifdef IPX
struct sockaddr_ipx ipxaddr;
#endif
#ifdef INET
struct sockaddr_in inaddr;
#endif
} addr;
int timeout; /* ncp rq timeout */
int retry_count; /* counts to give an error */
@ -181,7 +175,6 @@ struct ncp_conn {
int nc_lwant; /* number of wanted locks */
struct proc *procp; /* pid currently operates */
struct ucred *ucred; /* usr currently operates */
struct ncp_rq *nc_rq; /* current request */
/* Fields used to process ncp requests */
int connid; /* assigned by server */
u_int8_t seq;
@ -199,13 +192,10 @@ struct ncp_conn {
#endif
};
#define ncp_conn_signwanted(conn) ((conn)->flags & NCPFL_SIGNWANTED)
#define ncp_conn_valid(conn) ((conn->flags & NCPFL_INVALID) == 0)
#define ncp_conn_invalidate(conn) {conn->flags |= NCPFL_INVALID;}
int ncp_conn_init(void);
int ncp_conn_destroy(void);
int ncp_conn_alloc(struct proc *p,struct ucred *cred, struct ncp_conn **connid);
int ncp_conn_alloc(struct ncp_conn_args *cap,
struct proc *p, struct ucred *cred, struct ncp_conn **connid);
int ncp_conn_free(struct ncp_conn *conn);
int ncp_conn_access(struct ncp_conn *conn,struct ucred *cred,mode_t mode);
int ncp_conn_lock(struct ncp_conn *conn,struct proc *p,struct ucred *cred,int mode);
@ -228,6 +218,8 @@ int ncp_conn_getattached(struct ncp_conn_args *li,struct proc *p,struct ucred *
int ncp_conn_putprochandles(struct proc *p);
int ncp_conn_getinfo(struct ncp_conn *ncp, struct ncp_conn_stat *ncs);
int ncp_conn_reconnect(struct ncp_conn *ncp);
extern struct ncp_conn_head conn_list;
extern int ncp_burst_enabled;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, Boris Popov
* Copyright (c) 1999, 2000, 2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -84,18 +84,20 @@ ncp_sign_start(struct ncp_conn *conn, char *logindata) {
* target is a 8-byte buffer
*/
int
ncp_get_encryption_key(struct ncp_conn *conn, char *target) {
ncp_get_encryption_key(struct ncp_conn *conn, char *target)
{
struct ncp_rq *rqp;
int error;
DECLARE_RQ;
NCP_RQ_HEAD_S(23,23,conn->procp,conn->ucred);
checkbad(ncp_request(conn,rqp));
if (rqp->rpsize < 8) {
NCPFATAL("rpsize=%d < 8\n", rqp->rpsize);
return EIO;
}
ncp_rp_mem(rqp, target, 8);
NCP_RQ_EXIT;
error = ncp_rq_alloc_subfn(23, 23, conn, conn->procp, conn->ucred, &rqp);
if (error)
return error;
rqp->nr_minrplen = 8;
error = ncp_request(rqp);
if (error)
return error;
md_get_mem(&rqp->rp, target, 8, MB_MSYSTEM);
ncp_rq_done(rqp);
return error;
}
@ -122,27 +124,32 @@ ncp_login_object(struct ncp_conn *conn, unsigned char *username,
int
ncp_login_encrypted(struct ncp_conn *conn, struct ncp_bindery_object *object,
unsigned char *key, unsigned char *passwd,
struct proc *p,struct ucred *cred) {
struct proc *p,struct ucred *cred)
{
struct ncp_rq *rqp;
struct mbchain *mbp;
u_int32_t tmpID = htonl(object->object_id);
u_char buf[16 + 8];
u_char encrypted[8];
int error;
DECLARE_RQ;
nw_keyhash((u_char*)&tmpID, passwd, strlen(passwd), buf);
nw_encrypt(key, buf, encrypted);
NCP_RQ_HEAD_S(23,24,p,cred);
ncp_rq_mem(rqp, encrypted, 8);
ncp_rq_word_hl(rqp, object->object_type);
error = ncp_rq_alloc_subfn(23, 24, conn, p, cred, &rqp);
if (error)
return error;
mbp = &rqp->rq;
mb_put_mem(mbp, encrypted, 8, MB_MSYSTEM);
mb_put_uint16be(mbp, object->object_type);
ncp_rq_pstring(rqp, object->object_name);
error = ncp_request(conn, rqp);
NCP_RQ_EXIT_NB;
if (conn->flags & NCPFL_SIGNWANTED) {
if (error == 0 || error == NWE_PASSWORD_EXPIRED) {
memcpy(buf + 16, key, 8);
error = ncp_sign_start(conn, buf);
}
error = ncp_request(rqp);
if (!error)
ncp_rq_done(rqp);
if ((conn->flags & NCPFL_SIGNWANTED) &&
(error == 0 || error == NWE_PASSWORD_EXPIRED)) {
bcopy(key, buf + 16, 8);
error = ncp_sign_start(conn, buf);
}
return error;
}
@ -152,15 +159,18 @@ ncp_login_unencrypted(struct ncp_conn *conn, u_int16_t object_type,
char *object_name, unsigned char *passwd,
struct proc *p, struct ucred *cred)
{
struct ncp_rq *rqp;
int error;
DECLARE_RQ;
NCP_RQ_HEAD_S(23,20,conn->procp,conn->ucred);
ncp_rq_word_hl(rqp, object_type);
error = ncp_rq_alloc_subfn(23, 20, conn, p, cred, &rqp);
if (error)
return error;
mb_put_uint16be(&rqp->rq, object_type);
ncp_rq_pstring(rqp, object_name);
ncp_rq_pstring(rqp, passwd);
error = ncp_request(conn,rqp);
NCP_RQ_EXIT_NB;
error = ncp_request(rqp);
if (!error)
ncp_rq_done(rqp);
return error;
}
@ -188,7 +198,7 @@ ncp_login(struct ncp_conn *conn, char *user, int objtype, char *password,
ncp_str_upper(conn->li.password);
checkbad(ncp_login_object(conn, conn->li.user, objtype, conn->li.password,p,cred));
conn->li.objtype = objtype;
conn->flags |= NCPFL_LOGGED;
conn->flags |= NCPFL_LOGGED | NCPFL_WASLOGGED;
return 0;
bad:
if (conn->li.user) free(conn->li.user, M_NCPDATA);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, Boris Popov
* Copyright (c) 1999, 2000, 2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -58,6 +58,7 @@ 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 int
ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp);
@ -71,7 +72,8 @@ struct sncp_connect_args {
};
static int
__P(sncp_connect(struct proc *p, struct sncp_connect_args *uap)){
sncp_connect(struct proc *p, struct sncp_connect_args *uap)
{
int connHandle = 0, error;
struct ncp_conn *conn;
struct ncp_handle *handle;
@ -82,7 +84,12 @@ __P(sncp_connect(struct proc *p, struct sncp_connect_args *uap)){
li.password = li.user = NULL;
error = ncp_conn_getattached(&li, p, p->p_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn);
if (error) {
error = ncp_connect(&li, p, p->p_ucred, &conn);
error = ncp_conn_alloc(&li, p, p->p_ucred, &conn);
if (error)
goto bad;
error = ncp_conn_reconnect(conn);
if (error)
ncp_conn_free(conn);
}
if (!error) {
error = ncp_conn_gethandle(conn, p, &handle);
@ -104,35 +111,41 @@ static int ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
struct ncp_conn *conn, struct ncp_handle *handle);
static int
__P(sncp_request(struct proc *p, struct sncp_request_args *uap)){
int error = 0, rqsize;
sncp_request(struct proc *p, struct sncp_request_args *uap)
{
struct ncp_rq *rqp;
struct ncp_conn *conn;
struct ncp_handle *handle;
DECLARE_RQ;
int error = 0, rqsize;
error = ncp_conn_findhandle(uap->connHandle,p,&handle);
if (error) return error;
if (error)
return error;
conn = handle->nh_conn;
if (uap->fn == NCP_CONN)
return ncp_conn_handler(p, uap, conn, handle);
error = copyin(&uap->ncpbuf->rqsize, &rqsize, sizeof(int));
if (error) return(error);
error = ncp_conn_lock(conn,p,p->p_ucred,NCPM_EXECUTE);
if (error) return(error);
ncp_rq_head(rqp,NCP_REQUEST,uap->fn,p,p->p_ucred);
if (rqsize)
error = ncp_rq_usermem(rqp,(caddr_t)uap->ncpbuf->packet, rqsize);
if (!error) {
error = ncp_request(conn, rqp);
if (error == 0 && rqp->rpsize)
ncp_rp_usermem(rqp, (caddr_t)uap->ncpbuf->packet,
rqp->rpsize);
copyout(&rqp->cs, &uap->ncpbuf->cs, sizeof(rqp->cs));
copyout(&rqp->cc, &uap->ncpbuf->cc, sizeof(rqp->cc));
copyout(&rqp->rpsize, &uap->ncpbuf->rpsize, sizeof(rqp->rpsize));
if (error)
return(error);
error = ncp_rq_alloc(uap->fn, conn, p, p->p_ucred, &rqp);
if (error)
return error;
if (rqsize) {
error = mb_put_mem(&rqp->rq, (caddr_t)uap->ncpbuf->packet,
rqsize, MB_MUSER);
if (error)
goto bad;
}
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,
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));
bad:
ncp_rq_done(rqp);
ncp_conn_unlock(conn,p);
return error;
}
@ -170,14 +183,11 @@ ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
auio.uio_segflg = UIO_USERSPACE;
auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE;
auio.uio_procp = p;
error = ncp_conn_lock(conn,p,cred,NCPM_EXECUTE);
if (error) return(error);
if (subfn == NCP_CONN_READ)
error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred);
else
error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred);
rwrq.nrw_cnt -= auio.uio_resid;
ncp_conn_unlock(conn,p);
p->p_retval[0] = rwrq.nrw_cnt;
break;
} /* case int_read/write */
@ -284,7 +294,7 @@ ncp_conn_handler(struct proc *p, struct sncp_request_args *uap,
error = ncp_conn_lock(conn, p, cred, NCPM_EXECUTE);
if (error) break;
ncp_conn_puthandle(hp, p, 0);
error = ncp_disconnect(conn);
error = ncp_conn_free(conn);
if (error)
ncp_conn_unlock(conn, p);
break;
@ -301,7 +311,8 @@ struct sncp_conn_scan_args {
};
static int
__P(sncp_conn_scan(struct proc *p, struct sncp_conn_scan_args *uap)){
sncp_conn_scan(struct proc *p, struct sncp_conn_scan_args *uap)
{
int connHandle = 0, error;
struct ncp_conn_args li, *lip;
struct ncp_conn *conn;
@ -350,32 +361,45 @@ __P(sncp_conn_scan(struct proc *p, struct sncp_conn_scan_args *uap)){
}
int
ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp){
int error = 0, i, rpsize;
u_int32_t fsize;
ncp_conn_frag_rq(struct ncp_conn *conn, struct proc *p, struct ncp_conn_frag *nfp)
{
NW_FRAGMENT *fp;
DECLARE_RQ;
struct ncp_rq *rqp;
u_int32_t fsize;
int error, i, rpsize;
ncp_rq_head(rqp,NCP_REQUEST,nfp->fn,p,p->p_ucred);
if (nfp->rqfcnt) {
for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
checkbad(ncp_rq_usermem(rqp,(caddr_t)fp->fragAddress, fp->fragSize));
}
error = ncp_rq_alloc(nfp->fn, conn, p, p->p_ucred, &rqp);
if (error)
return error;
for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) {
error = mb_put_mem(&rqp->rq, (caddr_t)fp->fragAddress, fp->fragSize, MB_MUSER);
if (error)
goto bad;
}
checkbad(ncp_request(conn, rqp));
rpsize = rqp->rpsize;
rqp->nr_flags |= NCPR_DONTFREEONERR;
error = ncp_request(rqp);
if (error)
goto bad;
rpsize = rqp->nr_rpsize;
if (rpsize && nfp->rpfcnt) {
for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) {
checkbad(copyin(&fp->fragSize, &fsize, sizeof (fsize)));
error = copyin(&fp->fragSize, &fsize, sizeof (fsize));
if (error)
break;
fsize = min(fsize, rpsize);
checkbad(ncp_rp_usermem(rqp,(caddr_t)fp->fragAddress, fsize));
error = md_get_mem(&rqp->rp, (caddr_t)fp->fragAddress, fsize, MB_MUSER);
if (error)
break;
rpsize -= fsize;
checkbad(copyout(&fsize, &fp->fragSize, sizeof (fsize)));
error = copyout(&fsize, &fp->fragSize, sizeof (fsize));
if (error)
break;
}
}
nfp->cs = rqp->cs;
nfp->cc = rqp->cc;
NCP_RQ_EXIT;
nfp->cs = rqp->nr_cs;
nfp->cc = rqp->nr_cc;
bad:
ncp_rq_done(rqp);
return error;
}
@ -454,8 +478,13 @@ ncp_load(void) {
}
static int
ncp_unload(void) {
ncp_done();
ncp_unload(void)
{
int error;
error = ncp_done();
if (error)
return error;
bcopy(&oldent, &sysent[ncp_sysent], sizeof(struct sysent) * SC_SIZE);
printf( "ncp_unload: unloaded\n");
return 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, Boris Popov
* Copyright (c) 1999, 2000, 2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -33,21 +33,17 @@
*
* Core of NCP protocol
*/
#include "opt_inet.h"
#include "opt_ipx.h"
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/poll.h>
#include <sys/signalvar.h>
#include <sys/mbuf.h>
#include <sys/uio.h>
#ifdef IPX
#include <netipx/ipx.h>
#include <netipx/ipx_var.h>
#endif
#include <netncp/ncp.h>
#include <netncp/ncp_conn.h>
@ -57,12 +53,6 @@
#include <netncp/ncp_rq.h>
#include <netncp/nwerror.h>
static int ncp_do_request(struct ncp_conn *,struct ncp_rq *rqp);
static int ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target);
static int ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options);
static void ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size);
#ifdef NCP_DATA_DEBUG
static
void m_dumpm(struct mbuf *m) {
@ -103,374 +93,132 @@ ncp_chkintr(struct ncp_conn *conn, struct proc *p)
* should be called with LOCKED connection, also they use procp & ucred
*/
int
ncp_ncp_connect(struct ncp_conn *conn) {
int error;
ncp_ncp_connect(struct ncp_conn *conn)
{
struct ncp_rq *rqp;
struct ncp_rphdr *rp;
DECLARE_RQ;
int error;
conn->flags &= ~(NCPFL_INVALID | NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED);
error = ncp_rq_alloc_any(NCP_ALLOC_SLOT, 0, conn, conn->procp, conn->ucred, &rqp);
if (error)
return error;
conn->flags &= ~(NCPFL_INVALID | NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED
| NCPFL_ATTACHED);
conn->seq = 0;
checkbad(ncp_rq_head(rqp,NCP_ALLOC_SLOT,0,conn->procp,conn->ucred));
error=ncp_do_request(conn,rqp);
error = ncp_request_int(rqp);
if (!error) {
rp = mtod(rqp->rp, struct ncp_rphdr*);
rp = mtod(rqp->rp.md_top, struct ncp_rphdr*);
conn->connid = rp->conn_low + (rp->conn_high << 8);
}
ncp_rq_done(rqp);
if (error) return error;
conn->flags |= NCPFL_ATTACHED;
error = ncp_renegotiate_connparam(conn, NCP_DEFAULT_BUFSIZE, 0);
if (error == NWE_SIGNATURE_LEVEL_CONFLICT) {
printf("Unable to negotiate requested security level\n");
error = EOPNOTSUPP;
}
if (error) {
ncp_ncp_disconnect(conn);
if (error)
return error;
}
#ifdef NCPBURST
ncp_burst_connect(conn);
#endif
bad:
return error;
conn->flags |= NCPFL_ATTACHED | NCPFL_WASATTACHED;
return 0;
}
int
ncp_ncp_disconnect(struct ncp_conn *conn) {
ncp_ncp_disconnect(struct ncp_conn *conn)
{
struct ncp_rq *rqp;
int error;
struct ncp_rqhdr *ncprq;
DECLARE_RQ;
NCPSDEBUG("for connid=%d\n",conn->nc_id);
#ifdef NCPBURST
ncp_burst_disconnect(conn);
#endif
error=ncp_rq_head(rqp,NCP_FREE_SLOT,0,conn->procp,conn->ucred);
ncprq = mtod(rqp->rq,struct ncp_rqhdr*);
error=ncp_do_request(conn,rqp);
ncp_rq_done(rqp);
ncp_conn_invalidate(conn);
if (conn->flags & NCPFL_ATTACHED) {
error = ncp_rq_alloc_any(NCP_FREE_SLOT, 0, conn, conn->procp, conn->ucred, &rqp);
if (!error) {
ncp_request_int(rqp);
ncp_rq_done(rqp);
}
}
conn->flags |= NCPFL_INVALID;
ncp_sock_disconnect(conn);
return 0;
}
/*
* Make a signature for the current packet and add it at the end of the
* packet.
*/
static void
ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size) {
u_char data[64];
bzero(data, sizeof(data));
bcopy(conn->sign_root, data, 8);
setdle(data, 8, *size);
m_copydata(rqp->rq, sizeof(struct ncp_rqhdr)-1,
min((*size) - sizeof(struct ncp_rqhdr)+1, 52),data+12);
ncp_sign(conn->sign_state, data, conn->sign_state);
ncp_rq_mem(rqp, (void*)conn->sign_state, 8);
(*size) += 8;
}
/*
* Low level send rpc, here we do not attempt to restore any connection,
* Connection expected to be locked
*/
static int
ncp_do_request(struct ncp_conn *conn, struct ncp_rq *rqp) {
int error=EIO,len, dosend, plen = 0, gotpacket, s;
struct socket *so;
struct proc *p = conn->procp;
struct ncp_rqhdr *rq;
struct ncp_rphdr *rp=NULL;
struct timeval tv;
struct mbuf *m, *mreply = NULL;
conn->nc_rq = rqp;
rqp->conn = conn;
if (p == NULL)
p = curproc; /* XXX maybe procpage ? */
if (!ncp_conn_valid(conn)) {
printf("%s: conn not valid\n",__FUNCTION__);
return (error);
}
so = conn->ncp_so;
if (!so) {
printf("%s: ncp_so is NULL !\n",__FUNCTION__);
ncp_conn_invalidate(conn); /* wow ! how we do that ? */
return EBADF;
}
/*
* Flush out replies on previous reqs
*/
s = splnet();
while (1/*so->so_rcv.sb_cc*/) {
if (ncp_poll(so,POLLIN) == 0) break;
if (ncp_sock_recv(so,&m,&len) != 0) break;
m_freem(m);
}
rq = mtod(rqp->rq,struct ncp_rqhdr *);
rq->seq = conn->seq;
m = rqp->rq;
len = 0;
while (m) {
len += m->m_len;
m = m->m_next;
}
rqp->rq->m_pkthdr.len = len;
switch(rq->fn) {
case 0x15: case 0x16: case 0x17: case 0x23:
m = rqp->rq;
*((u_int16_t*)(mtod(m,u_int8_t*)+sizeof(*rq))) = htons(len-2-sizeof(*rq));
break;
}
if (conn->flags & NCPFL_SIGNACTIVE) {
ncp_sign_packet(conn, rqp, &len);
rqp->rq->m_pkthdr.len = len;
}
rq->conn_low = conn->connid & 0xff;
/* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/
/* XXX: this is temporary fix till I find a better solution */
rq->task = rq->conn_low;
rq->conn_high = conn->connid >> 8;
rqp->rexmit = conn->li.retry_count;
for(dosend = 1;;) {
if (rqp->rexmit-- == 0) {
error = ETIMEDOUT;
break;
}
error = 0;
if (dosend) {
NCPSDEBUG("send:%04x f=%02x c=%d l=%d s=%d t=%d\n",rq->type, rq->fn, (rq->conn_high << 8) + rq->conn_low,
rqp->rq->m_pkthdr.len, rq->seq, rq->task
);
error = ncp_sock_send(so, rqp->rq, rqp);
if (error) break;
}
tv.tv_sec = conn->li.timeout;
tv.tv_usec = 0;
error = ncp_sock_rselect(so, p, &tv, POLLIN);
if (error == EWOULDBLOCK ) /* timeout expired */
continue;
error = ncp_chkintr(conn, p);
if (error == EINTR) /* we dont restart */
break;
if (error) break;
/*
* At this point it is possible to get more than one
* reply from server. In general, last reply should be for
* current request, but not always. So, we loop through
* all replies to find the right answer and flush others.
*/
gotpacket = 0; /* nothing good found */
dosend = 1; /* resend rq if error */
for (;;) {
error = 0;
if (ncp_poll(so,POLLIN) == 0) break;
/* if (so->so_rcv.sb_cc == 0) {
break;
}*/
error = ncp_sock_recv(so,&m,&len);
if (error) break; /* must be more checks !!! */
if (m->m_len < sizeof(*rp)) {
m = m_pullup(m, sizeof(*rp));
if (m == NULL) {
printf("%s: reply too short\n",__FUNCTION__);
continue;
}
}
rp = mtod(m, struct ncp_rphdr*);
if (len == sizeof(*rp) && rp->type == NCP_POSITIVE_ACK) {
NCPSDEBUG("got positive acknowledge\n");
m_freem(m);
rqp->rexmit = conn->li.retry_count;
dosend = 0; /* server just busy and will reply ASAP */
continue;
}
NCPSDEBUG("recv:%04x c=%d l=%d s=%d t=%d cc=%02x cs=%02x\n",rp->type,
(rp->conn_high << 8) + rp->conn_low, len, rp->seq, rp->task,
rp->completion_code, rp->connection_state);
NCPDDEBUG(m);
if ( (rp->type == NCP_REPLY) &&
((rq->type == NCP_ALLOC_SLOT) ||
((rp->conn_low == rq->conn_low) &&
(rp->conn_high == rq->conn_high)
))) {
if (rq->seq > rp->seq || (rq->seq == 0 && rp->seq == 0xff)) {
dosend = 1;
}
if (rp->seq == rq->seq) {
if (gotpacket) {
m_freem(m);
} else {
gotpacket = 1;
mreply = m;
plen = len;
}
continue; /* look up other for other packets */
}
}
m_freem(m);
NCPSDEBUG("reply mismatch\n");
} /* for receive */
if (error) break;
if (gotpacket) break;
/* try to resend, or just wait */
}
splx(s);
conn->seq++;
if (error) {
NCPSDEBUG("error=%d\n",error);
if (error != EINTR) /* if not just interrupt */
ncp_conn_invalidate(conn); /* only reconnect to restore */
return(error);
}
if (conn->flags & NCPFL_SIGNACTIVE) {
/* XXX: check reply signature */
m_adj(mreply, -8);
plen -= 8;
}
len = plen;
m = mreply;
rp = mtod(m, struct ncp_rphdr*);
len -= sizeof(*rp);
rqp->rpsize = len;
rqp->cc = error = rp->completion_code;
if (error) error |= 0x8900; /* server error */
rqp->cs = rp->connection_state;
if (rqp->cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) {
NCPSDEBUG("server drop us\n");
ncp_conn_invalidate(conn);
error = ECONNRESET;
}
rqp->rp = m;
rqp->mrp = m;
rqp->bpos = mtod(m, caddr_t) + sizeof(*rp);
return error;
}
/*
* Here we will try to restore any loggedin & dropped connection,
* connection should be locked on entry
*/
int ncp_restore_login(struct ncp_conn *conn);
int
ncp_restore_login(struct ncp_conn *conn) {
int error, oldflags;
if (conn->flags & NCPFL_RESTORING) {
printf("Hey, ncp_restore_login called twise !!!\n");
return 0;
}
oldflags = conn->flags;
printf("Restoring connection, flags = %d\n",oldflags);
if ((oldflags & NCPFL_LOGGED) == 0) {
return ECONNRESET; /* no need to restore empty conn */
}
conn->flags &= ~(NCPFL_LOGGED | NCPFL_ATTACHED);
conn->flags |= NCPFL_RESTORING;
do { /* not a loop */
error = ncp_reconnect(conn);
if (error) break;
if (conn->li.user)
error = ncp_login_object(conn, conn->li.user, conn->li.objtype, conn->li.password,conn->procp,conn->ucred);
if (error) break;
conn->flags |= NCPFL_LOGGED;
} while(0);
if (error) {
conn->flags = oldflags | NCPFL_INVALID;
}
conn->flags &= ~NCPFL_RESTORING;
return error;
}
int
ncp_request(struct ncp_conn *conn, struct ncp_rq *rqp) {
int error, rcnt;
/* struct ncp_rqhdr *rq = mtod(rqp->rq,struct ncp_rqhdr*);*/
error = ncp_conn_lock(conn,rqp->p,rqp->cred,NCPM_EXECUTE);
if (error) return error;
rcnt = NCP_RESTORE_COUNT;
for(;;) {
if (!ncp_conn_valid(conn)) {
if (rcnt==0) {
error = ECONNRESET;
break;
}
rcnt--;
error = ncp_restore_login(conn);
if (error)
continue;
}
error=ncp_do_request(conn, rqp);
if (ncp_conn_valid(conn)) /* not just error ! */
break;
}
ncp_conn_unlock(conn,rqp->p);
return error;
}
/*
* All negotiation functions expect a locked connection
*/
static int
ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target) {
int error;
DECLARE_RQ;
NCP_RQ_HEAD(0x21,conn->procp,conn->ucred);
ncp_rq_word_hl(rqp, size);
checkbad(ncp_request(conn,rqp));
*target = min(ncp_rp_word_hl(rqp), size);
NCP_RQ_EXIT;
int
ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target)
{
struct ncp_rq *rqp;
u_int16_t bsize;
int error;
error = ncp_rq_alloc(0x21, conn, conn->procp, conn->ucred, &rqp);
if (error)
return error;
mb_put_uint16be(&rqp->rq, size);
error = ncp_request(rqp);
if (error)
return error;
md_get_uint16be(&rqp->rp, &bsize);
*target = min(bsize, size);
ncp_rq_done(rqp);
return error;
}
static int
ncp_negotiate_size_and_options(struct ncp_conn *conn, int size, int options,
int *ret_size, int *ret_options) {
int *ret_size, u_int8_t *ret_options)
{
struct ncp_rq *rqp;
u_int16_t rs;
int error;
int rs;
DECLARE_RQ;
NCP_RQ_HEAD(0x61,conn->procp,conn->ucred);
ncp_rq_word_hl(rqp, size);
ncp_rq_byte(rqp, options);
checkbad(ncp_request(conn, rqp));
rs = ncp_rp_word_hl(rqp);
error = ncp_rq_alloc(0x61, conn, conn->procp, conn->ucred, &rqp);
if (error)
return error;
mb_put_uint16be(&rqp->rq, size);
mb_put_uint8(&rqp->rq, options);
rqp->nr_minrplen = 2 + 2 + 1;
error = ncp_request(rqp);
if (error)
return error;
md_get_uint16be(&rqp->rp, &rs);
*ret_size = (rs == 0) ? size : min(rs, size);
ncp_rp_word_hl(rqp); /* skip echo socket */
*ret_options = ncp_rp_byte(rqp);
NCP_RQ_EXIT;
md_get_uint16be(&rqp->rp, &rs); /* skip echo socket */
md_get_uint8(&rqp->rp, ret_options);
ncp_rq_done(rqp);
return error;
}
static int
ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options)
int
ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, u_int8_t in_options)
{
int neg_buffsize, error, options, sl;
u_int8_t options;
int neg_buffsize, error, sl, ckslevel, ilen;
sl = conn->li.sig_level;
if (sl >= 2)
in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS;
#ifdef IPX
if (ipxcksum == 2)
in_options |= NCP_IPX_CHECKSUM;
#endif
if (conn->li.saddr.sa_family == AF_IPX) {
ilen = sizeof(ckslevel);
error = ncp_sysctlbyname("net.ipx.ipx.checksum", &ckslevel, &ilen,
NULL, 0, NULL);
if (error)
return error;
if (ckslevel == 2)
in_options |= NCP_IPX_CHECKSUM;
}
error = ncp_negotiate_size_and_options(conn, buffsize, in_options,
&neg_buffsize, &options);
if (!error) {
#ifdef IPX
if ((options ^ in_options) & NCP_IPX_CHECKSUM) {
if (ipxcksum == 2) {
if (conn->li.saddr.sa_family == AF_IPX &&
((options ^ in_options) & NCP_IPX_CHECKSUM)) {
if (ckslevel == 2) {
printf("Server refuses to support IPX checksums\n");
return NWE_REQUESTER_FAILURE;
}
in_options |= NCP_IPX_CHECKSUM;
error = 1;
}
#endif /* IPX */
if ((options ^ in_options) & 2) {
if (sl == 0 || sl == 3)
return NWE_SIGNATURE_LEVEL_CONFLICT;
@ -497,105 +245,8 @@ ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options)
conn->buffer_size = neg_buffsize;
if (in_options & NCP_SECURITY_LEVEL_SIGN_HEADERS)
conn->flags |= NCPFL_SIGNWANTED;
#ifdef IPX
ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM);
#endif
return 0;
}
int
ncp_reconnect(struct ncp_conn *conn) {
int error;
/* close any open sockets */
ncp_sock_disconnect(conn);
switch( conn->li.saddr.sa_family ) {
#ifdef IPX
case AF_IPX:
error = ncp_sock_connect_ipx(conn);
break;
#endif
#ifdef INET
case AF_INET:
error = ncp_sock_connect_in(conn);
break;
#endif
default:
return EPROTONOSUPPORT;
}
if (!error)
error = ncp_ncp_connect(conn);
return error;
}
/*
* Create conn structure and try to do low level connect
* Server addr should be filled in.
*/
int
ncp_connect(struct ncp_conn_args *li, struct proc *p, struct ucred *cred,
struct ncp_conn **aconn)
{
struct ncp_conn *conn;
struct ucred *owner;
int error, isroot;
if (li->saddr.sa_family != AF_INET && li->saddr.sa_family != AF_IPX)
return EPROTONOSUPPORT;
isroot = ncp_suser(cred) == 0;
/*
* Only root can change ownership
*/
if (li->owner != NCP_DEFAULT_OWNER && !isroot)
return EPERM;
if (li->group != NCP_DEFAULT_GROUP &&
!groupmember(li->group, cred) && !isroot)
return EPERM;
if (li->owner != NCP_DEFAULT_OWNER) {
owner = crget();
owner->cr_uid = li->owner;
} else {
owner = cred;
crhold(owner);
}
error = ncp_conn_alloc(p, owner, &conn);
if (error)
return (error);
if (error) {
ncp_conn_free(conn);
return error;
}
conn->li = *li;
conn->nc_group = (li->group != NCP_DEFAULT_GROUP) ?
li->group : cred->cr_groups[0];
if (li->retry_count == 0)
conn->li.retry_count = NCP_RETRY_COUNT;
if (li->timeout == 0)
conn->li.timeout = NCP_RETRY_TIMEOUT;
error = ncp_reconnect(conn);
if (error) {
ncp_disconnect(conn);
} else {
*aconn=conn;
}
return error;
}
/*
* Break connection and deallocate memory
*/
int
ncp_disconnect(struct ncp_conn *conn) {
if (ncp_conn_access(conn,conn->ucred,NCPM_WRITE))
return EACCES;
if (conn->ref_cnt != 0) return EBUSY;
if (conn->flags & NCPFL_PERMANENT) return EBUSY;
if (ncp_conn_valid(conn)) {
ncp_ncp_disconnect(conn);
}
ncp_sock_disconnect(conn);
ncp_conn_free(conn);
if (conn->li.saddr.sa_family == AF_IPX)
ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM);
return 0;
}
@ -609,3 +260,133 @@ ncp_check_rq(struct ncp_conn *conn){
}
return;
}
int
ncp_get_bindery_object_id(struct ncp_conn *conn,
u_int16_t object_type, char *object_name,
struct ncp_bindery_object *target,
struct proc *p,struct ucred *cred)
{
struct ncp_rq *rqp;
int error;
error = ncp_rq_alloc_subfn(23, 53, conn, conn->procp, conn->ucred, &rqp);
mb_put_uint16be(&rqp->rq, object_type);
ncp_rq_pstring(rqp, object_name);
rqp->nr_minrplen = 54;
error = ncp_request(rqp);
if (error)
return error;
md_get_uint32be(&rqp->rp, &target->object_id);
md_get_uint16be(&rqp->rp, &target->object_type);
md_get_mem(&rqp->rp, (caddr_t)target->object_name, 48, MB_MSYSTEM);
ncp_rq_done(rqp);
return 0;
}
int
ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
{
struct ncp_rq *rqp;
struct mbchain *mbp;
u_int16_t retlen = 0 ;
int error = 0, len = 0, tsiz, burstio;
tsiz = uiop->uio_resid;
#ifdef NCPBURST
burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
#else
burstio = 0;
#endif
while (tsiz > 0) {
if (!burstio) {
len = min(4096 - (uiop->uio_offset % 4096), tsiz);
len = min(len, conn->buffer_size);
error = ncp_rq_alloc(72, conn, uiop->uio_procp, cred, &rqp);
if (error)
break;
mbp = &rqp->rq;
mb_put_uint8(mbp, 0);
mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM);
mb_put_uint32be(mbp, uiop->uio_offset);
mb_put_uint16be(mbp, len);
rqp->nr_minrplen = 2;
error = ncp_request(rqp);
if (error)
break;
md_get_uint16be(&rqp->rp, &retlen);
if (uiop->uio_offset & 1)
md_get_mem(&rqp->rp, NULL, 1, MB_MSYSTEM);
error = md_get_uio(&rqp->rp, uiop, retlen);
ncp_rq_done(rqp);
} else {
#ifdef NCPBURST
error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
#endif
}
if (error)
break;
tsiz -= retlen;
if (retlen < len)
break;
}
return (error);
}
int
ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
{
struct ncp_rq *rqp;
struct mbchain *mbp;
int error = 0, len, tsiz, backup;
if (uiop->uio_iovcnt != 1) {
printf("%s: can't handle iovcnt>1 !!!\n", __FUNCTION__);
return EIO;
}
tsiz = uiop->uio_resid;
while (tsiz > 0) {
len = min(4096 - (uiop->uio_offset % 4096), tsiz);
len = min(len, conn->buffer_size);
if (len == 0) {
printf("gotcha!\n");
}
/* rq head */
error = ncp_rq_alloc(73, conn, uiop->uio_procp, cred, &rqp);
if (error)
break;
mbp = &rqp->rq;
mb_put_uint8(mbp, 0);
mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM);
mb_put_uint32be(mbp, uiop->uio_offset);
mb_put_uint16be(mbp, len);
error = mb_put_uio(mbp, uiop, len);
if (error) {
ncp_rq_done(rqp);
break;
}
error = ncp_request(rqp);
if (!error)
ncp_rq_done(rqp);
if (len == 0)
break;
if (error) {
backup = len;
uiop->uio_iov->iov_base -= backup;
uiop->uio_iov->iov_len += backup;
uiop->uio_offset -= backup;
uiop->uio_resid += backup;
break;
}
tsiz -= len;
}
if (error)
uiop->uio_resid = tsiz;
switch (error) {
case NWE_INSUFFICIENT_SPACE:
error = ENOSPC;
break;
}
return (error);
}

View File

@ -111,13 +111,21 @@ struct ncp_rq;
struct proc;
struct ucred;
int ncp_request(struct ncp_conn *conn,struct ncp_rq *rqp);
int ncp_ncp_connect(struct ncp_conn *conn);
int ncp_ncp_disconnect(struct ncp_conn *conn);
int ncp_reconnect(struct ncp_conn *conn);
int ncp_connect(struct ncp_conn_args *li,struct proc *p, struct ucred *cred,struct ncp_conn **aconn);
int ncp_disconnect(struct ncp_conn *conn);
int ncp_login(struct ncp_conn *conn, char *user, int objtype, char *password,
struct proc *p, struct ucred *cred);
struct proc *p, struct ucred *cred);
int ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target);
int ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize,
u_int8_t in_options);
int ncp_get_bindery_object_id(struct ncp_conn *conn,
u_int16_t object_type, char *object_name,
struct ncp_bindery_object *target,
struct proc *p,struct ucred *cred);
int ncp_login_object(struct ncp_conn *conn, unsigned char *username,
int login_type, unsigned char *password,
struct proc *p,struct ucred *cred);
int ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred);
int ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred);
#endif /* _NCP_NCP_H_ */

View File

@ -237,7 +237,8 @@ ncp_pathcheck(char *s, int len, struct ncp_nlstables *nt, int strict) {
* leave it as is.
*/
void
ncp_pathcopy(char *src, char *dst, int len, struct ncp_nlstables *nt) {
ncp_pathcopy(const char *src, char *dst, int len, struct ncp_nlstables *nt)
{
int donls;
u_char c;
/* char *d = dst, *s = src;*/

View File

@ -81,7 +81,7 @@ extern struct ncp_nlstables ncp_defnls;
void ncp_str_upper(char *name);
void ncp_str_lower(char *name);
void ncp_pathcopy(char *src, char *dst, int len, struct ncp_nlstables *nt);
void ncp_pathcopy(const char *src, char *dst, int len, struct ncp_nlstables *nt);
int ncp_pathcheck(char *s, int len, struct ncp_nlstables *nt, int strict);
void ncp_path2unix(char *src, char *dst, int len, struct ncp_nlstables *nt);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, Boris Popov
* Copyright (c) 1999, 2000, 2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,7 +36,10 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/poll.h>
#include <sys/uio.h>
#include <netncp/ncp.h>
@ -44,523 +47,424 @@
#include <netncp/ncp_rq.h>
#include <netncp/ncp_subr.h>
#include <netncp/ncp_ncp.h>
#include <netncp/ncp_sock.h>
#include <netncp/ncp_nls.h>
int
ncp_rq_head(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,struct proc *p,
struct ucred *cred)
{
struct mbuf *m;
struct ncp_rqhdr *rq;
struct ncp_bursthdr *brq;
caddr_t pstart;
static MALLOC_DEFINE(M_NCPRQ, "NCPRQ", "NCP request");
bzero(rqp, sizeof(*rqp));
rqp->p = p;
rqp->cred = cred;
m = m_gethdr(M_TRYWAIT, MT_DATA);
if (m == NULL)
return ENOBUFS; /* if M_TRYWAIT ? */
m->m_pkthdr.rcvif = NULL;
rqp->rq = rqp->mrq = m;
rqp->rp = NULL;
switch(ptype) {
case NCP_PACKET_BURST:
MH_ALIGN(m, sizeof(*brq) + 24);
m->m_len = sizeof(*brq);
brq = mtod(m, struct ncp_bursthdr *);
brq->bh_type = ptype;
brq->bh_streamtype = 0x2;
pstart = (caddr_t)brq;
break;
default:
MH_ALIGN(m, sizeof(*rq) + 2); /* possible len field in some functions */
m->m_len = sizeof(*rq);
rq = mtod(m, struct ncp_rqhdr *);
rq->type = ptype;
rq->seq = 0; /* filled later */
rq->fn = fn;
pstart = (caddr_t)rq;
break;
static int ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size);
int
ncp_rq_alloc_any(u_int32_t ptype, u_int8_t fn, struct ncp_conn *ncp,
struct proc *p, struct ucred *cred,
struct ncp_rq **rqpp)
{
struct ncp_rq *rqp;
int error;
MALLOC(rqp, struct ncp_rq *, sizeof(*rqp), M_NCPRQ, M_WAITOK);
error = ncp_rq_init_any(rqp, ptype, fn, ncp, p, cred);
rqp->nr_flags |= NCPR_ALLOCED;
if (error) {
ncp_rq_done(rqp);
return error;
}
rqp->bpos = pstart + m->m_len;
*rqpp = rqp;
return 0;
}
int
ncp_rq_done(struct ncp_rq *rqp) {
m_freem(rqp->rq);
rqp->rq=NULL;
if (rqp->rp) m_freem(rqp->rp);
rqp->rp=NULL;
return (0);
ncp_rq_alloc(u_int8_t fn, struct ncp_conn *ncp,
struct proc *p, struct ucred *cred, struct ncp_rq **rqpp)
{
return ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, p, cred, rqpp);
}
int
ncp_rq_alloc_subfn(u_int8_t fn, u_int8_t subfn, struct ncp_conn *ncp,
struct proc *p, struct ucred *cred, struct ncp_rq **rqpp)
{
struct ncp_rq *rqp;
int error;
error = ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, p, cred, &rqp);
if (error)
return error;
mb_reserve(&rqp->rq, 2);
mb_put_uint8(&rqp->rq, subfn);
*rqpp = rqp;
return 0;
}
int
ncp_rq_init_any(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,
struct ncp_conn *ncp,
struct proc *p, struct ucred *cred)
{
struct ncp_rqhdr *rq;
struct ncp_bursthdr *brq;
struct mbchain *mbp;
int error;
bzero(rqp, sizeof(*rqp));
error = ncp_conn_access(ncp, cred, NCPM_EXECUTE);
if (error)
return error;
rqp->nr_p = p;
rqp->nr_cred = cred;
rqp->nr_conn = ncp;
mbp = &rqp->rq;
if (mb_init(mbp) != 0)
return ENOBUFS;
switch(ptype) {
case NCP_PACKET_BURST:
brq = (struct ncp_bursthdr*)mb_reserve(mbp, sizeof(*brq));
brq->bh_type = ptype;
brq->bh_streamtype = 0x2;
break;
default:
rq = (struct ncp_rqhdr*)mb_reserve(mbp, sizeof(*rq));
rq->type = ptype;
rq->seq = 0; /* filled later */
rq->fn = fn;
break;
}
rqp->nr_minrplen = -1;
return 0;
}
void
ncp_rq_done(struct ncp_rq *rqp)
{
mb_done(&rqp->rq);
md_done(&rqp->rp);
if (rqp->nr_flags & NCPR_ALLOCED)
free(rqp, M_NCPRQ);
return;
}
/*
* Routines to fill the request
*/
static caddr_t ncp_mchecksize(struct ncp_rq *rqp, int size);
#define NCP_RQADD(t) ((t*)(ncp_mchecksize(rqp,sizeof(t))))
caddr_t
ncp_mchecksize(struct ncp_rq *rqp, int size) {
caddr_t bpos1;
if (size>MLEN)
panic("ncp_mchecksize\n");
if (M_TRAILINGSPACE(rqp->mrq)<(size)) {
struct mbuf *m;
m = m_get(M_TRYWAIT, MT_DATA);
m->m_len = 0;
rqp->bpos = mtod(m, caddr_t);
rqp->mrq->m_next = m;
rqp->mrq = m;
}
rqp->mrq->m_len += size;
bpos1 = rqp->bpos;
rqp->bpos += size;
return bpos1;
}
void
ncp_rq_byte(struct ncp_rq *rqp,u_int8_t x) {
*NCP_RQADD(u_int8_t)=x;
}
void
ncp_rq_word_hl(struct ncp_rq *rqp, u_int16_t x) {
setwbe(NCP_RQADD(u_int16_t), 0, x);
}
void
ncp_rq_word_lh(struct ncp_rq *rqp, u_int16_t x) {
setwle(NCP_RQADD(u_int16_t), 0, x);
}
void
ncp_rq_dword_lh(struct ncp_rq *rqp, u_int32_t x) {
setdle(NCP_RQADD(u_int32_t), 0, x);
}
void
ncp_rq_pathstring(struct ncp_rq *rqp, int size, char *name, struct ncp_nlstables *nt) {
struct mbuf *m;
int cplen;
ncp_rq_byte(rqp, size);
m = rqp->mrq;
cplen = min(size, M_TRAILINGSPACE(m));
if (cplen) {
ncp_pathcopy(name, rqp->bpos, cplen, nt);
size -= cplen;
name += cplen;
m->m_len += cplen;
}
if (size) {
m = m_getm(m, size, MT_DATA, M_TRYWAIT);
while (size > 0){
m = m->m_next;
cplen = min(size, M_TRAILINGSPACE(m));
ncp_pathcopy(name, mtod(m, caddr_t) + m->m_len, cplen, nt);
size -= cplen;
name += cplen;
m->m_len += cplen;
}
}
rqp->bpos = mtod(m,caddr_t) + m->m_len;
rqp->mrq = m;
return;
}
int
ncp_rq_putanymem(struct ncp_rq *rqp, caddr_t source, int size, int type) {
struct mbuf *m;
int cplen, error;
m = rqp->mrq;
cplen = min(size, M_TRAILINGSPACE(m));
if (cplen) {
if (type==1) {
error = copyin(source, rqp->bpos, cplen);
if (error) return error;
} else
bcopy(source, rqp->bpos, cplen);
size -= cplen;
source += cplen;
m->m_len += cplen;
}
if (size) {
m = m_getm(m, size, MT_DATA, M_TRYWAIT);
while (size > 0){
m = m->m_next;
cplen = min(size, M_TRAILINGSPACE(m));
if (type==1) {
error = copyin(source, mtod(m, caddr_t) + m->m_len, cplen);
if (error) return error;
} else
bcopy(source, mtod(m, caddr_t) + m->m_len, cplen);
size -= cplen;
source += cplen;
m->m_len += cplen;
}
}
rqp->bpos = mtod(m,caddr_t) + m->m_len;
rqp->mrq = m;
static int
ncp_rq_pathstrhelp(struct mbchain *mbp, c_caddr_t src, caddr_t dst, int len)
{
ncp_pathcopy(src, dst, len, mbp->mb_udata);
return 0;
}
int
ncp_rq_mbuf(struct ncp_rq *rqp, struct mbuf *m, int size) {
ncp_rq_pathstring(struct ncp_rq *rqp, int size, const char *name,
struct ncp_nlstables *nt)
{
struct mbchain *mbp = &rqp->rq;
rqp->mrq->m_next = m;
m->m_next = NULL;
if (size != M_COPYALL) m->m_len = size;
rqp->bpos = mtod(m,caddr_t) + m->m_len;
rqp->mrq = m;
return 0;
mb_put_uint8(mbp, size);
mbp->mb_copy = ncp_rq_pathstrhelp;
mbp->mb_udata = nt;
return mb_put_mem(mbp, (c_caddr_t)name, size, MB_MCUSTOM);
}
void
ncp_rq_pstring(struct ncp_rq *rqp, char *s) {
int len = strlen(s);
if (len > 255) {
nwfs_printf("string too long: %s\n", s);
len = 255;
}
ncp_rq_byte(rqp, len);
ncp_rq_mem(rqp, s, len);
return;
int
ncp_rq_pstring(struct ncp_rq *rqp, const char *s)
{
u_int len = strlen(s);
int error;
if (len > 255)
return EINVAL;
error = mb_put_uint8(&rqp->rq, len);
if (error)
return error;
return mb_put_mem(&rqp->rq, s, len, MB_MSYSTEM);
}
void
int
ncp_rq_dbase_path(struct ncp_rq *rqp, u_int8_t vol_num, u_int32_t dir_base,
int namelen, u_char *path, struct ncp_nlstables *nt)
{
struct mbchain *mbp = &rqp->rq;
int complen;
ncp_rq_byte(rqp, vol_num);
ncp_rq_dword(rqp, dir_base);
ncp_rq_byte(rqp, 1); /* with dirbase */
mb_put_uint8(mbp, vol_num);
mb_put_mem(mbp, (c_caddr_t)&dir_base, sizeof(dir_base), MB_MSYSTEM);
mb_put_uint8(mbp, 1); /* with dirbase */
if (path != NULL && path[0]) {
if (namelen < 0) {
namelen = *path++;
ncp_rq_byte(rqp, namelen);
mb_put_uint8(mbp, namelen);
for(; namelen; namelen--) {
complen = *path++;
ncp_rq_byte(rqp, complen);
ncp_rq_mem(rqp, path, complen);
mb_put_uint8(mbp, complen);
mb_put_mem(mbp, path, complen, MB_MSYSTEM);
path += complen;
}
} else {
ncp_rq_byte(rqp, 1); /* 1 component */
mb_put_uint8(mbp, 1); /* 1 component */
ncp_rq_pathstring(rqp, namelen, path, nt);
}
} else {
ncp_rq_byte(rqp, 0);
ncp_rq_byte(rqp, 0);
mb_put_uint8(mbp, 0);
mb_put_uint8(mbp, 0);
}
}
/*
* fetch reply routines
*/
#define ncp_mspaceleft (mtod(rqp->mrp,caddr_t)+rqp->mrp->m_len-rqp->bpos)
u_int8_t
ncp_rp_byte(struct ncp_rq *rqp) {
if (rqp->mrp == NULL) return 0;
if (ncp_mspaceleft < 1) {
rqp->mrp = rqp->mrp->m_next;
if (rqp->mrp == NULL) return 0;
rqp->bpos = mtod(rqp->mrp, caddr_t);
}
rqp->bpos += 1;
return rqp->bpos[-1];
}
u_int16_t
ncp_rp_word_lh(struct ncp_rq *rqp) {
caddr_t prev = rqp->bpos;
u_int16_t t;
if (rqp->mrp == NULL) return 0;
if (ncp_mspaceleft >= 2) {
rqp->bpos += 2;
return getwle(prev,0);
}
t = *((u_int8_t*)(rqp->bpos));
rqp->mrp = rqp->mrp->m_next;
if (rqp->mrp == NULL) return 0;
((u_int8_t *)&t)[1] = *((u_int8_t*)(rqp->bpos = mtod(rqp->mrp, caddr_t)));
rqp->bpos += 2;
return t;
}
u_int16_t
ncp_rp_word_hl(struct ncp_rq *rqp) {
return (ntohs(ncp_rp_word_lh(rqp)));
}
u_int32_t
ncp_rp_dword_hl(struct ncp_rq *rqp) {
int togo, rest;
caddr_t prev = rqp->bpos;
u_int32_t t;
if (rqp->mrp == NULL) return 0;
rest = ncp_mspaceleft;
if (rest >= 4) {
rqp->bpos += 4;
return getdbe(prev,0);
}
togo = 0;
while (rest--) {
((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
}
rqp->mrp = rqp->mrp->m_next;
if (rqp->mrp == NULL) return 0;
prev = mtod(rqp->mrp, caddr_t);
rqp->bpos = prev + 4 - togo; /* XXX possible low than togo bytes in next mbuf */
while (togo < 4) {
((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
}
return getdbe(&t,0);
}
u_int32_t
ncp_rp_dword_lh(struct ncp_rq *rqp) {
int rest, togo;
caddr_t prev = rqp->bpos;
u_int32_t t;
if (rqp->mrp == NULL) return 0;
rest = ncp_mspaceleft;
if (rest >= 4) {
rqp->bpos += 4;
return getdle(prev,0);
}
togo = 0;
while (rest--) {
((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
}
rqp->mrp = rqp->mrp->m_next;
if (rqp->mrp == NULL) return 0;
prev = mtod(rqp->mrp, caddr_t);
rqp->bpos = prev + 4 - togo; /* XXX possible low than togo bytes in next mbuf */
while (togo < 4) {
((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
}
return getdle(&t,0);
}
void
ncp_rp_mem(struct ncp_rq *rqp,caddr_t target, int size) {
register struct mbuf *m=rqp->mrp;
register unsigned count;
while (size > 0) {
if (m==0) { /* should be panic */
printf("ncp_rp_mem: incomplete copy\n");
return;
}
count = mtod(m,caddr_t)+m->m_len-rqp->bpos;
if (count == 0) {
m=m->m_next;
rqp->bpos=mtod(m,caddr_t);
continue;
}
count = min(count,size);
bcopy(rqp->bpos, target, count);
size -= count;
target += count;
rqp->bpos += count;
}
rqp->mrp=m;
return;
}
int
ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size) {
register struct mbuf *m=rqp->mrp;
register unsigned count;
int error;
while (size>0) {
if (m==0) { /* should be panic */
printf("ncp_rp_mem: incomplete copy\n");
return EFAULT;
}
count = mtod(m,caddr_t)+m->m_len-rqp->bpos;
if (count == 0) {
m=m->m_next;
rqp->bpos=mtod(m,caddr_t);
continue;
}
count = min(count,size);
error=copyout(rqp->bpos, target, count);
if (error) return error;
size -= count;
target += count;
rqp->bpos += count;
}
rqp->mrp=m;
return 0;
}
struct mbuf*
ncp_rp_mbuf(struct ncp_rq *rqp, int size) {
register struct mbuf *m=rqp->mrp, *rm;
register unsigned count;
rm = m_copym(m, rqp->bpos - mtod(m,caddr_t), size, M_TRYWAIT);
while (size > 0) {
if (m == 0) {
printf("ncp_rp_mbuf: can't advance\n");
return rm;
}
count = mtod(m,caddr_t)+ m->m_len - rqp->bpos;
if (count == 0) {
m = m->m_next;
rqp->bpos = mtod(m, caddr_t);
continue;
}
count = min(count, size);
size -= count;
rqp->bpos += count;
}
rqp->mrp=m;
return rm;
}
int
nwfs_mbuftouio(mrep, uiop, siz, dpos)
struct mbuf **mrep;
register struct uio *uiop;
int siz;
caddr_t *dpos;
{
register char *mbufcp, *uiocp;
register int xfer, left, len;
register struct mbuf *mp;
long uiosiz;
int error = 0;
mp = *mrep;
if (!mp) return 0;
mbufcp = *dpos;
len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
while (siz > 0) {
if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
return (EFBIG);
left = uiop->uio_iov->iov_len;
uiocp = uiop->uio_iov->iov_base;
if (left > siz)
left = siz;
uiosiz = left;
while (left > 0) {
while (len == 0) {
mp = mp->m_next;
if (mp == NULL)
return (EBADRPC);
mbufcp = mtod(mp, caddr_t);
len = mp->m_len;
}
xfer = (left > len) ? len : left;
#ifdef notdef
/* Not Yet.. */
if (uiop->uio_iov->iov_op != NULL)
(*(uiop->uio_iov->iov_op))
(mbufcp, uiocp, xfer);
else
#endif
if (uiop->uio_segflg == UIO_SYSSPACE)
bcopy(mbufcp, uiocp, xfer);
else
copyout(mbufcp, uiocp, xfer);
left -= xfer;
len -= xfer;
mbufcp += xfer;
uiocp += xfer;
uiop->uio_offset += xfer;
uiop->uio_resid -= xfer;
}
if (uiop->uio_iov->iov_len <= siz) {
uiop->uio_iovcnt--;
uiop->uio_iov++;
} else {
uiop->uio_iov->iov_base += uiosiz;
uiop->uio_iov->iov_len -= uiosiz;
}
siz -= uiosiz;
}
*dpos = mbufcp;
*mrep = mp;
return (error);
}
/*
* copies a uio scatter/gather list to an mbuf chain.
* NOTE: can ony handle iovcnt == 1
/*
* Make a signature for the current packet and add it at the end of the
* packet.
*/
int
nwfs_uiotombuf(uiop, mq, siz, bpos)
register struct uio *uiop;
struct mbuf **mq;
int siz;
caddr_t *bpos;
static int
ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size)
{
register char *uiocp;
register struct mbuf *mp, *mp2;
register int xfer, left, mlen;
int uiosiz, clflg;
u_char data[64];
int error;
#ifdef DIAGNOSTIC
if (uiop->uio_iovcnt != 1)
panic("nfsm_uiotombuf: iovcnt != 1");
#endif
if (siz > MLEN) /* or should it >= MCLBYTES ?? */
clflg = 1;
else
clflg = 0;
mp = mp2 = *mq;
while (siz > 0) {
left = uiop->uio_iov->iov_len;
uiocp = uiop->uio_iov->iov_base;
if (left > siz)
left = siz;
uiosiz = left;
while (left > 0) {
mlen = M_TRAILINGSPACE(mp);
if (mlen == 0) {
MGET(mp, M_TRYWAIT, MT_DATA);
if (clflg)
MCLGET(mp, M_TRYWAIT);
mp->m_len = 0;
mp2->m_next = mp;
mp2 = mp;
mlen = M_TRAILINGSPACE(mp);
}
xfer = (left > mlen) ? mlen : left;
#ifdef notdef
/* Not Yet.. */
if (uiop->uio_iov->iov_op != NULL)
(*(uiop->uio_iov->iov_op))
(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
else
#endif
if (uiop->uio_segflg == UIO_SYSSPACE)
bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
else
copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
mp->m_len += xfer;
left -= xfer;
uiocp += xfer;
uiop->uio_offset += xfer;
uiop->uio_resid -= xfer;
}
uiop->uio_iov->iov_base += uiosiz;
uiop->uio_iov->iov_len -= uiosiz;
siz -= uiosiz;
}
*bpos = mtod(mp, caddr_t)+mp->m_len;
*mq = mp;
return (0);
bzero(data, sizeof(data));
bcopy(conn->sign_root, data, 8);
setdle(data, 8, *size);
m_copydata(rqp->rq.mb_top, sizeof(struct ncp_rqhdr) - 1,
min((*size) - sizeof(struct ncp_rqhdr)+1, 52), data + 12);
ncp_sign(conn->sign_state, data, conn->sign_state);
error = mb_put_mem(&rqp->rq, (caddr_t)conn->sign_state, 8, MB_MSYSTEM);
if (error)
return error;
(*size) += 8;
return 0;
}
/*
* Low level send rpc, here we do not attempt to restore any connection,
* Connection expected to be locked
*/
int
ncp_request_int(struct ncp_rq *rqp)
{
struct ncp_conn *conn = rqp->nr_conn;
struct proc *p = conn->procp;
struct socket *so = conn->ncp_so;
struct ncp_rqhdr *rq;
struct ncp_rphdr *rp=NULL;
struct timeval tv;
struct mbuf *m, *mreply = NULL;
struct mbchain *mbp;
int error, len, dosend, plen = 0, gotpacket;
if (conn->flags & NCPFL_INVALID)
return ENOTCONN;
if (so == NULL) {
printf("%s: ncp_so is NULL !\n",__FUNCTION__);
conn->flags |= NCPFL_INVALID;
return ENOTCONN;
}
if (p == NULL)
p = curproc; /* XXX maybe procpage ? */
/*
* Flush out replies on previous reqs
*/
while (ncp_poll(so, POLLIN) != 0) {
if (ncp_sock_recv(so, &m, &len) != 0)
break;
m_freem(m);
}
mbp = &rqp->rq;
len = mb_fixhdr(mbp);
rq = mtod(mbp->mb_top, struct ncp_rqhdr *);
rq->seq = conn->seq;
m = rqp->rq.mb_top;
switch (rq->fn) {
case 0x15: case 0x16: case 0x17: case 0x23:
*(u_int16_t*)(rq + 1) = htons(len - 2 - sizeof(*rq));
break;
}
if (conn->flags & NCPFL_SIGNACTIVE) {
error = ncp_sign_packet(conn, rqp, &len);
if (error)
return error;
mbp->mb_top->m_pkthdr.len = len;
}
rq->conn_low = conn->connid & 0xff;
/* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/
/* XXX: this is temporary fix till I find a better solution */
rq->task = rq->conn_low;
rq->conn_high = conn->connid >> 8;
rqp->rexmit = conn->li.retry_count;
error = 0;
for(dosend = 1;;) {
if (rqp->rexmit-- == 0) {
error = ETIMEDOUT;
break;
}
error = 0;
if (dosend) {
NCPSDEBUG("send:%04x f=%02x c=%d l=%d s=%d t=%d\n",rq->type, rq->fn, (rq->conn_high << 8) + rq->conn_low,
mbp->mb_top->m_pkthdr.len, rq->seq, rq->task
);
error = ncp_sock_send(so, mbp->mb_top, rqp);
if (error)
break;
}
tv.tv_sec = conn->li.timeout;
tv.tv_usec = 0;
error = ncp_sock_rselect(so, p, &tv, POLLIN);
if (error == EWOULDBLOCK ) /* timeout expired */
continue;
error = ncp_chkintr(conn, p);
if (error)
break;
/*
* At this point it is possible to get more than one
* reply from server. In general, last reply should be for
* current request, but not always. So, we loop through
* all replies to find the right answer and flush others.
*/
gotpacket = 0; /* nothing good found */
dosend = 1; /* resend rq if error */
for (;;) {
error = 0;
if (ncp_poll(so, POLLIN) == 0)
break;
/* if (so->so_rcv.sb_cc == 0) {
break;
}*/
error = ncp_sock_recv(so, &m, &len);
if (error)
break; /* must be more checks !!! */
if (m->m_len < sizeof(*rp)) {
m = m_pullup(m, sizeof(*rp));
if (m == NULL) {
printf("%s: reply too short\n",__FUNCTION__);
continue;
}
}
rp = mtod(m, struct ncp_rphdr*);
if (len == sizeof(*rp) && rp->type == NCP_POSITIVE_ACK) {
NCPSDEBUG("got positive acknowledge\n");
m_freem(m);
rqp->rexmit = conn->li.retry_count;
dosend = 0; /* server just busy and will reply ASAP */
continue;
}
NCPSDEBUG("recv:%04x c=%d l=%d s=%d t=%d cc=%02x cs=%02x\n",rp->type,
(rp->conn_high << 8) + rp->conn_low, len, rp->seq, rp->task,
rp->completion_code, rp->connection_state);
NCPDDEBUG(m);
if ( (rp->type == NCP_REPLY) &&
((rq->type == NCP_ALLOC_SLOT) ||
((rp->conn_low == rq->conn_low) &&
(rp->conn_high == rq->conn_high)
))) {
if (rq->seq > rp->seq || (rq->seq == 0 && rp->seq == 0xff)) {
dosend = 1;
}
if (rp->seq == rq->seq) {
if (gotpacket) {
m_freem(m);
} else {
gotpacket = 1;
mreply = m;
plen = len;
}
continue; /* look up other for other packets */
}
}
m_freem(m);
NCPSDEBUG("reply mismatch\n");
} /* for receive */
if (error || gotpacket)
break;
/* try to resend, or just wait */
}
conn->seq++;
if (error) {
NCPSDEBUG("error=%d\n", error);
/*
* Any error except interruped call means that we have
* to reconnect. So, eliminate future timeouts by invalidating
* connection now.
*/
if (error != EINTR)
conn->flags |= NCPFL_INVALID;
return (error);
}
if (conn->flags & NCPFL_SIGNACTIVE) {
/* XXX: check reply signature */
m_adj(mreply, -8);
plen -= 8;
}
rp = mtod(mreply, struct ncp_rphdr*);
md_initm(&rqp->rp, mreply);
rqp->nr_rpsize = plen - sizeof(*rp);
rqp->nr_cc = error = rp->completion_code;
if (error)
error |= 0x8900; /* server error */
rqp->nr_cs = rp->connection_state;
if (rqp->nr_cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) {
NCPSDEBUG("server drop us\n");
conn->flags |= NCPFL_INVALID;
error = ECONNRESET;
}
md_get_mem(&rqp->rp, NULL, sizeof(*rp), MB_MSYSTEM);
return error;
}
/*
* Here we will try to restore any loggedin & dropped connection,
* connection should be locked on entry
*/
static __inline int
ncp_restore_login(struct ncp_conn *conn)
{
int error;
printf("ncprq: Restoring connection, flags = %x\n", conn->flags);
conn->flags &= ~(NCPFL_LOGGED | NCPFL_ATTACHED);
conn->flags |= NCPFL_RESTORING;
error = ncp_conn_reconnect(conn);
if (!error && (conn->flags & NCPFL_WASLOGGED))
error = ncp_login_object(conn, conn->li.user, conn->li.objtype, conn->li.password,conn->procp,conn->ucred);
if (error)
conn->flags |= NCPFL_INVALID;
conn->flags &= ~NCPFL_RESTORING;
return error;
}
int
ncp_request(struct ncp_rq *rqp)
{
struct ncp_conn *ncp = rqp->nr_conn;
int error, rcnt;
error = ncp_conn_lock(ncp, rqp->nr_p, rqp->nr_cred, NCPM_EXECUTE);
if (error)
goto out;
rcnt = NCP_RESTORE_COUNT;
for(;;) {
if ((ncp->flags & NCPFL_INVALID) == 0) {
error = ncp_request_int(rqp);
if ((ncp->flags & NCPFL_INVALID) == 0)
break;
}
if (rcnt-- == 0) {
error = ECONNRESET;
break;
}
/*
* Do not attempt to restore connection recursively
*/
if (ncp->flags & NCPFL_RESTORING) {
error = ENOTCONN;
break;
}
error = ncp_restore_login(ncp);
if (error)
continue;
}
ncp_conn_unlock(ncp, rqp->nr_p);
out:
if (error && (rqp->nr_flags & NCPR_DONTFREEONERR) == 0)
ncp_rq_done(rqp);
return error;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, Boris Popov
* Copyright (c) 1999, 2000, 2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -82,76 +82,49 @@
#ifdef _KERNEL
struct ncp_nlstables;
#include <sys/mchain.h>
#define NCPR_ALLOCED 0x0001 /* request structure was allocated */
#define NCPR_DONTFREEONERR 0x0002 /* do not free structure on error */
/*
* Structure to prepare ncp request and receive reply
*/
struct ncp_rq {
struct ncp_conn *conn; /* back link */
struct mbuf *rq;
struct mbuf *mrq;
struct mbuf *rp;
struct mbuf *mrp;
caddr_t bpos;
/* int rqsize;*/ /* request size without ncp header */
int rpsize; /* reply size minus ncp header */
int cc; /* completion code */
int cs; /* connection state */
struct proc *p; /* proc that did rq */
struct ucred *cred; /* user that did rq */
int nr_flags;
struct mbchain rq;
struct mdchain rp;
int nr_minrplen; /* minimal rp size (-1 if not known) */
int nr_rpsize; /* reply size minus ncp header */
int nr_cc; /* completion code */
int nr_cs; /* connection state */
struct proc * nr_p; /* proc that did rq */
struct ucred * nr_cred; /* user that did rq */
int rexmit;
struct ncp_conn*nr_conn; /* back link */
};
#define DECLARE_RQ struct ncp_rq rq;struct ncp_rq *rqp=&rq
int ncp_rq_alloc(u_int8_t fn, struct ncp_conn *ncp, struct proc *p,
struct ucred *cred, struct ncp_rq **rqpp);
int ncp_rq_alloc_any(u_int32_t ptype, u_int8_t fn, struct ncp_conn *ncp,
struct proc *p, struct ucred *cred, struct ncp_rq **rqpp);
int ncp_rq_alloc_subfn(u_int8_t fn, u_int8_t subfn, struct ncp_conn *ncp,
struct proc *p, struct ucred *cred, struct ncp_rq **rqpp);
int ncp_rq_init_any(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,
struct ncp_conn *ncp,
struct proc *p, struct ucred *cred);
void ncp_rq_done(struct ncp_rq *rqp);
int ncp_request(struct ncp_rq *rqp);
int ncp_request_int(struct ncp_rq *rqp);
struct ncp_nlstables;
int ncp_rq_head(struct ncp_rq *rqp,u_int32_t ptype, u_int8_t fn,struct proc *p,
struct ucred *cred);
int ncp_rq_done(struct ncp_rq *rqp);
/* common case for normal request */
#define ncp_rq_init(rqp,fn,p,c) ncp_rq_head((rqp),NCP_REQUEST,(fn),(p),(c))
#define ncp_rq_close(rqp) ncp_rq_done((rqp))
#define NCP_RQ_HEAD(fn,p,c) ncp_rq_init(rqp,fn,p,c)
#define NCP_RQ_HEAD_S(fn,sfn,p,c) NCP_RQ_HEAD(fn,p,c);ncp_rq_word(rqp,0);ncp_rq_byte(rqp,(sfn))
#define NCP_RQ_EXIT bad: ncp_rq_close(rqp)
#define NCP_RQ_EXIT_NB ncp_rq_close(rqp)
#define ncp_rq_word ncp_rq_word_lh
#define ncp_rq_dword ncp_rq_dword_lh
/*void ncp_init_request(struct ncp_rq *rqp, int fn);
void ncp_close_request(struct ncp_rq *rqp);*/
void ncp_rq_byte(struct ncp_rq *rqp, u_int8_t x);
void ncp_rq_word_hl(struct ncp_rq *rqp, u_int16_t x);
void ncp_rq_word_lh(struct ncp_rq *rqp, u_int16_t x);
void ncp_rq_dword_lh(struct ncp_rq *rqp, u_int32_t x);
static void ncp_rq_mem(struct ncp_rq *rqp, caddr_t source, int size);
static int ncp_rq_usermem(struct ncp_rq *rqp, caddr_t source, int size);
int ncp_rq_mbuf(struct ncp_rq *rqp, struct mbuf *m, int size);
int ncp_rq_putanymem(struct ncp_rq *rqp, caddr_t source, int size,int type);
void ncp_rq_pathstring(struct ncp_rq *rqp, int size, char *name, struct ncp_nlstables*);
void ncp_rq_dbase_path(struct ncp_rq *, u_int8_t vol_num,
int ncp_rq_pathstring(struct ncp_rq *rqp, int size, const char *name, struct ncp_nlstables*);
int ncp_rq_dbase_path(struct ncp_rq *, u_int8_t vol_num,
u_int32_t dir_base, int namelen, u_char *name, struct ncp_nlstables *nt);
void ncp_rq_pstring(struct ncp_rq *rqp, char *s);
int ncp_rq_pstring(struct ncp_rq *rqp, const char *s);
u_int8_t ncp_rp_byte(struct ncp_rq *rqp);
u_int16_t ncp_rp_word_hl(struct ncp_rq *rqp);
u_int16_t ncp_rp_word_lh(struct ncp_rq *rqp);
u_int32_t ncp_rp_dword_hl(struct ncp_rq *rqp);
u_int32_t ncp_rp_dword_lh(struct ncp_rq *rqp);
void ncp_rp_mem(struct ncp_rq *rqp,caddr_t target, int size);
int ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size);
int nwfs_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos);
int nwfs_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos);
struct mbuf* ncp_rp_mbuf(struct ncp_rq *rqp, int size);
static void __inline ncp_rq_mem(struct ncp_rq *rqp, caddr_t source, int size) {
ncp_rq_putanymem(rqp,source,size,0);
}
static int __inline ncp_rq_usermem(struct ncp_rq *rqp, caddr_t source, int size) {
return ncp_rq_putanymem(rqp,source,size,1);
}
void ncp_sign_init(const char *logindata, char *sign_root);
#else /* ifdef _KERNEL */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, Boris Popov
* Copyright (c) 1999, 2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,13 +34,6 @@
* Low level socket routines
*/
#include "opt_inet.h"
#include "opt_ipx.h"
#if !defined(INET) && !defined(IPX)
#error "NCP requeires either INET of IPX protocol family"
#endif
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/malloc.h>
@ -55,10 +48,8 @@
#include <sys/mbuf.h>
#include <net/route.h>
#ifdef IPX
#include <netipx/ipx.h>
#include <netipx/ipx_pcb.h>
#endif
#include <netncp/ncp.h>
#include <netncp/ncp_conn.h>
@ -66,11 +57,9 @@
#include <netncp/ncp_subr.h>
#include <netncp/ncp_rq.h>
#ifdef IPX
#define ipx_setnullnet(x) ((x).x_net.s_net[0]=0); ((x).x_net.s_net[1]=0);
#define ipx_setnullhost(x) ((x).x_host.s_host[0] = 0); \
((x).x_host.s_host[1] = 0); ((x).x_host.s_host[2] = 0);
#endif
/*int ncp_poll(struct socket *so, int events);*/
/*static int ncp_getsockname(struct socket *so, caddr_t asa, int *alen);*/
@ -165,7 +154,7 @@ ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp)
{
struct proc *p = curproc; /* XXX */
struct sockaddr *to = 0;
struct ncp_conn *conn = rqp->conn;
struct ncp_conn *conn = rqp->nr_conn;
struct mbuf *m;
int error, flags=0;
int sendwait;
@ -243,12 +232,12 @@ ncp_sock_rselect(struct socket *so,struct proc *p, struct timeval *tv, int event
return (error);
}
#ifdef IPX
/*
* Connect to specified server via IPX
*/
int
ncp_sock_connect_ipx(struct ncp_conn *conn) {
static int
ncp_sock_connect_ipx(struct ncp_conn *conn)
{
struct sockaddr_ipx sipx;
struct ipxpcb *npcb;
struct proc *p = conn->procp;
@ -319,25 +308,23 @@ ncp_sock_connect_ipx(struct ncp_conn *conn) {
}
int
ncp_sock_checksum(struct ncp_conn *conn, int enable) {
ncp_sock_checksum(struct ncp_conn *conn, int enable)
{
#ifdef SO_IPX_CHECKSUM
if (enable) {
sotoipxpcb(conn->ncp_so)->ipxp_flags |= IPXP_CHECKSUM;
} else {
sotoipxpcb(conn->ncp_so)->ipxp_flags &= ~IPXP_CHECKSUM;
}
#endif
return 0;
}
#endif
#ifdef INET
/*
* Connect to specified server via IP
*/
int
ncp_sock_connect_in(struct ncp_conn *conn) {
static int
ncp_sock_connect_in(struct ncp_conn *conn)
{
struct sockaddr_in sin;
struct proc *p=conn->procp;
int addrlen=sizeof(sin), error;
@ -357,8 +344,24 @@ ncp_sock_connect_in(struct ncp_conn *conn) {
ncp_sock_disconnect(conn);
return (error);
}
#endif
int
ncp_sock_connect(struct ncp_conn *ncp)
{
int error;
switch (ncp->li.saddr.sa_family) {
case AF_IPX:
error = ncp_sock_connect_ipx(ncp);
break;
case AF_INET:
error = ncp_sock_connect_in(ncp);
break;
default:
return EPROTONOSUPPORT;
}
return error;
}
/*
* Connection expected to be locked
@ -390,7 +393,6 @@ ncp_sock_disconnect(struct ncp_conn *conn) {
return 0;
}
#ifdef IPX
static void
ncp_watchdog(struct ncp_conn *conn) {
char *buf;
@ -422,7 +424,6 @@ ncp_watchdog(struct ncp_conn *conn) {
if (sa) FREE(sa, M_SONAME);
return;
}
#endif /* IPX */
void
ncp_check_conn(struct ncp_conn *conn) {
@ -433,7 +434,6 @@ ncp_check_conn(struct ncp_conn *conn) {
s = splnet();
ncp_check_rq(conn);
splx(s);
#ifdef IPX
ncp_watchdog(conn);
#endif
if (conn->li.saddr.sa_family == AF_IPX)
ncp_watchdog(conn);
}

View File

@ -41,8 +41,7 @@ struct proc;
struct socket;
struct timeval;
int ncp_sock_connect_ipx(struct ncp_conn *);
int ncp_sock_connect_in(struct ncp_conn *);
int ncp_sock_connect(struct ncp_conn *ncp);
int ncp_sock_recv(struct socket *so, struct mbuf **mp, int *rlen);
int ncp_sock_send(struct socket *so, struct mbuf *data, struct ncp_rq *rqp);
int ncp_sock_disconnect(struct ncp_conn *conn);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, Boris Popov
* Copyright (c) 1999, 2000, 2001 Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -36,10 +36,9 @@
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/mbuf.h>
#include <netncp/ncp.h>
#include <netncp/ncp_conn.h>
@ -76,7 +75,8 @@ ncp_str_dup(char *s) {
void
ncp_at_exit(struct proc *p) {
ncp_at_exit(struct proc *p)
{
struct ncp_conn *ncp, *nncp;
if (ncp_conn_putprochandles(p) == 0) return;
@ -84,10 +84,9 @@ ncp_at_exit(struct proc *p) {
ncp_conn_locklist(LK_EXCLUSIVE, p);
for (ncp = SLIST_FIRST(&conn_list); ncp; ncp = nncp) {
nncp = SLIST_NEXT(ncp, nc_next);
if (ncp->ref_cnt != 0) continue;
if (ncp_conn_lock(ncp, p, p->p_ucred,NCPM_READ|NCPM_EXECUTE|NCPM_WRITE))
continue;
if (ncp_disconnect(ncp) != 0)
if (ncp_conn_free(ncp) != 0)
ncp_conn_unlock(ncp,p);
}
ncp_conn_unlocklist(p);
@ -95,7 +94,26 @@ ncp_at_exit(struct proc *p) {
}
int
ncp_init(void) {
ncp_sysctlbyname(char *name, void *old, size_t *oldlenp,
void *new, size_t newlen, size_t *retval)
{
int oid[CTL_MAXNAME];
int nmlen, plen, error;
oid[0] = 0; /* sysctl internal magic */
oid[1] = 3; /* name2oid */
nmlen = sizeof(oid);
error = kernel_sysctl(curproc, oid, 2, oid, &nmlen, name, strlen(name), &plen);
if (error)
return error;
error = kernel_sysctl(curproc, oid, plen / sizeof(int), old, oldlenp,
new, newlen, retval);
return error;
}
int
ncp_init(void)
{
ncp_conn_init();
if (at_exit(ncp_at_exit)) {
NCPFATAL("can't register at_exit handler\n");
@ -105,32 +123,24 @@ ncp_init(void) {
return 0;
}
void
ncp_done(void) {
struct ncp_conn *ncp, *nncp;
struct proc *p = curproc;
int
ncp_done(void)
{
int error;
error = ncp_conn_destroy();
if (error)
return error;
untimeout(ncp_timer,NULL,ncp_timer_handle);
rm_at_exit(ncp_at_exit);
ncp_conn_locklist(LK_EXCLUSIVE, p);
for (ncp = SLIST_FIRST(&conn_list); ncp; ncp = nncp) {
nncp = SLIST_NEXT(ncp, nc_next);
ncp->ref_cnt = 0;
if (ncp_conn_lock(ncp, p, p->p_ucred,NCPM_READ|NCPM_EXECUTE|NCPM_WRITE)) {
NCPFATAL("Can't lock connection !\n");
continue;
}
if (ncp_disconnect(ncp) != 0)
ncp_conn_unlock(ncp,p);
}
ncp_conn_unlocklist(p);
ncp_conn_destroy();
return 0;
}
/* tick every second and check for watch dog packets and lost connections */
static void
ncp_timer(void *arg){
ncp_timer(void *arg)
{
struct ncp_conn *conn;
if(ncp_conn_locklist(LK_SHARED | LK_NOWAIT, NULL) == 0) {
@ -140,116 +150,3 @@ ncp_timer(void *arg){
}
ncp_timer_handle = timeout(ncp_timer,NULL,NCP_TIMER_TICK);
}
int
ncp_get_bindery_object_id(struct ncp_conn *conn,
u_int16_t object_type, char *object_name,
struct ncp_bindery_object *target,
struct proc *p,struct ucred *cred)
{
int error;
DECLARE_RQ;
NCP_RQ_HEAD_S(23,53,p,cred);
ncp_rq_word_hl(rqp, object_type);
ncp_rq_pstring(rqp, object_name);
checkbad(ncp_request(conn,rqp));
if (rqp->rpsize < 54) {
printf("ncp_rp_size %d < 54\n", rqp->rpsize);
error = EINVAL;
goto bad;
}
target->object_id = ncp_rp_dword_hl(rqp);
target->object_type = ncp_rp_word_hl(rqp);
ncp_rp_mem(rqp,(caddr_t)target->object_name, 48);
NCP_RQ_EXIT;
return error;
}
int
ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) {
int error = 0, len = 0, retlen=0, tsiz, burstio;
DECLARE_RQ;
tsiz = uiop->uio_resid;
#ifdef NCPBURST
burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
#else
burstio = 0;
#endif
while (tsiz > 0) {
if (!burstio) {
len = min(4096 - (uiop->uio_offset % 4096), tsiz);
len = min(len, conn->buffer_size);
NCP_RQ_HEAD(72,uiop->uio_procp,cred);
ncp_rq_byte(rqp, 0);
ncp_rq_mem(rqp, (caddr_t)file, 6);
ncp_rq_dword(rqp, htonl(uiop->uio_offset));
ncp_rq_word(rqp, htons(len));
checkbad(ncp_request(conn,rqp));
retlen = ncp_rp_word_hl(rqp);
if (uiop->uio_offset & 1)
ncp_rp_byte(rqp);
error = nwfs_mbuftouio(&rqp->mrp,uiop,retlen,&rqp->bpos);
NCP_RQ_EXIT;
} else {
#ifdef NCPBURST
error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
#endif
}
if (error) break;
tsiz -= retlen;
if (retlen < len)
break;
}
return (error);
}
int
ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
{
int error = 0, len, tsiz, backup;
DECLARE_RQ;
if (uiop->uio_iovcnt != 1) {
printf("%s: can't handle iovcnt>1 !!!\n", __FUNCTION__);
return EIO;
}
tsiz = uiop->uio_resid;
while (tsiz > 0) {
len = min(4096 - (uiop->uio_offset % 4096), tsiz);
len = min(len, conn->buffer_size);
if (len == 0) {
printf("gotcha!\n");
}
/* rq head */
NCP_RQ_HEAD(73,uiop->uio_procp,cred);
ncp_rq_byte(rqp, 0);
ncp_rq_mem(rqp, (caddr_t)file, 6);
ncp_rq_dword(rqp, htonl(uiop->uio_offset));
ncp_rq_word_hl(rqp, len);
nwfs_uiotombuf(uiop,&rqp->mrq,len,&rqp->bpos);
checkbad(ncp_request(conn,rqp));
if (len == 0)
break;
NCP_RQ_EXIT;
if (error) {
backup = len;
uiop->uio_iov->iov_base -= backup;
uiop->uio_iov->iov_len += backup;
uiop->uio_offset -= backup;
uiop->uio_resid += backup;
break;
}
tsiz -= len;
}
if (error)
uiop->uio_resid = tsiz;
switch (error) {
case NWE_INSUFFICIENT_SPACE:
error = ENOSPC;
break;
}
return (error);
}

View File

@ -45,6 +45,7 @@
#define nwfs_printf NCP_PRINT
/* Maybe this should panic, but I dont like that */
#define NCPFATAL NCP_PRINT
#define NCPERROR NCP_PRINT
/* socket debugging */
#ifdef NCP_SOCKET_DEBUG
@ -109,25 +110,15 @@ struct proc;
struct ucred;
int ncp_init(void);
void ncp_done(void);
int ncp_done(void);
int ncp_chkintr(struct ncp_conn *conn, struct proc *p);
char*ncp_str_dup(char *s);
int ncp_sysctlbyname(char *name, void *old, size_t *oldlenp,
void *new, size_t newlen, size_t *retval);
/* ncp_crypt.c */
void nw_keyhash(const u_char *key, const u_char *buf, int buflen, u_char *target);
void nw_encrypt(const u_char *fra, const u_char *buf, u_char *target);
void ncp_sign(const u_int32_t *state, const char *x, u_int32_t *ostate);
/* ncp calls */
int ncp_get_bindery_object_id(struct ncp_conn *conn,
u_int16_t object_type, char *object_name,
struct ncp_bindery_object *target,
struct proc *p,struct ucred *cred);
int ncp_login_object(struct ncp_conn *conn, unsigned char *username,
int login_type, unsigned char *password,
struct proc *p,struct ucred *cred);
int ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred);
int ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred);
#endif /* _NCP_SUBR_H_ */