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:
parent
df54111fe4
commit
29ad26f932
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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;*/
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user