diff options
Diffstat (limited to 'sys/netncp')
-rw-r--r-- | sys/netncp/ncp_conn.c | 161 | ||||
-rw-r--r-- | sys/netncp/ncp_conn.h | 36 | ||||
-rw-r--r-- | sys/netncp/ncp_login.c | 68 | ||||
-rw-r--r-- | sys/netncp/ncp_mod.c | 121 | ||||
-rw-r--r-- | sys/netncp/ncp_ncp.c | 623 | ||||
-rw-r--r-- | sys/netncp/ncp_ncp.h | 18 | ||||
-rw-r--r-- | sys/netncp/ncp_nls.c | 3 | ||||
-rw-r--r-- | sys/netncp/ncp_nls.h | 2 | ||||
-rw-r--r-- | sys/netncp/ncp_rq.c | 786 | ||||
-rw-r--r-- | sys/netncp/ncp_rq.h | 99 | ||||
-rw-r--r-- | sys/netncp/ncp_sock.c | 58 | ||||
-rw-r--r-- | sys/netncp/ncp_sock.h | 3 | ||||
-rw-r--r-- | sys/netncp/ncp_subr.c | 175 | ||||
-rw-r--r-- | sys/netncp/ncp_subr.h | 17 |
14 files changed, 916 insertions, 1254 deletions
diff --git a/sys/netncp/ncp_conn.c b/sys/netncp/ncp_conn.c index f020731..51151d2 100644 --- a/sys/netncp/ncp_conn.c +++ b/sys/netncp/ncp_conn.c @@ -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 */ diff --git a/sys/netncp/ncp_conn.h b/sys/netncp/ncp_conn.h index 0171421..df64eff 100644 --- a/sys/netncp/ncp_conn.h +++ b/sys/netncp/ncp_conn.h @@ -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; diff --git a/sys/netncp/ncp_login.c b/sys/netncp/ncp_login.c index 7c3c1f2..b7e76c7 100644 --- a/sys/netncp/ncp_login.c +++ b/sys/netncp/ncp_login.c @@ -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); diff --git a/sys/netncp/ncp_mod.c b/sys/netncp/ncp_mod.c index 11df855..ee8d995 100644 --- a/sys/netncp/ncp_mod.c +++ b/sys/netncp/ncp_mod.c @@ -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; diff --git a/sys/netncp/ncp_ncp.c b/sys/netncp/ncp_ncp.c index 69a7776..43a388b 100644 --- a/sys/netncp/ncp_ncp.c +++ b/sys/netncp/ncp_ncp.c @@ -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); - 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; + 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); } - 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; + conn->flags |= NCPFL_INVALID; + ncp_sock_disconnect(conn); + return 0; } /* - * Here we will try to restore any loggedin & dropped connection, - * connection should be locked on entry + * All negotiation functions expect a locked connection */ -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) { +ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target) +{ + struct ncp_rq *rqp; + u_int16_t bsize; 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; + 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,115 +245,148 @@ 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 + if (conn->li.saddr.sa_family == AF_IPX) + ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM); 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; +void +ncp_check_rq(struct ncp_conn *conn){ + return; + if (conn->flags & NCPFL_INTR) return; + /* first, check for signals */ + if (ncp_chkintr(conn,conn->procp)) { + conn->flags |= NCPFL_INTR; } - if (!error) - error = ncp_ncp_connect(conn); - return error; + return; } -/* - * 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) +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_conn *conn; - struct ucred *owner; - int error, isroot; + struct ncp_rq *rqp; + int error; - 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); + 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); - 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; + 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; } -/* - * Break connection and deallocate memory - */ + int -ncp_disconnect(struct ncp_conn *conn) { +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 - 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); + 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; } - ncp_sock_disconnect(conn); - ncp_conn_free(conn); - return 0; + return (error); } -void -ncp_check_rq(struct ncp_conn *conn){ - return; - if (conn->flags & NCPFL_INTR) return; - /* first, check for signals */ - if (ncp_chkintr(conn,conn->procp)) { - conn->flags |= NCPFL_INTR; +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; } - return; + 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); } diff --git a/sys/netncp/ncp_ncp.h b/sys/netncp/ncp_ncp.h index b43370d..779350b 100644 --- a/sys/netncp/ncp_ncp.h +++ b/sys/netncp/ncp_ncp.h @@ -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_ */ diff --git a/sys/netncp/ncp_nls.c b/sys/netncp/ncp_nls.c index 3c7892f..ccbf3cc 100644 --- a/sys/netncp/ncp_nls.c +++ b/sys/netncp/ncp_nls.c @@ -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;*/ diff --git a/sys/netncp/ncp_nls.h b/sys/netncp/ncp_nls.h index bedc7ca..61d3dcd 100644 --- a/sys/netncp/ncp_nls.h +++ b/sys/netncp/ncp_nls.h @@ -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); diff --git a/sys/netncp/ncp_rq.c b/sys/netncp/ncp_rq.c index dacdee0..fb53775 100644 --- a/sys/netncp/ncp_rq.c +++ b/sys/netncp/ncp_rq.c @@ -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> +static MALLOC_DEFINE(M_NCPRQ, "NCPRQ", "NCP request"); + +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; + } + *rqpp = rqp; + return 0; +} + +int +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_head(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,struct proc *p, - struct ucred *cred) +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 mbuf *m; struct ncp_rqhdr *rq; struct ncp_bursthdr *brq; - caddr_t pstart; + struct mbchain *mbp; + int error; 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; + 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: - MH_ALIGN(m, sizeof(*brq) + 24); - m->m_len = sizeof(*brq); - brq = mtod(m, struct ncp_bursthdr *); + brq = (struct ncp_bursthdr*)mb_reserve(mbp, sizeof(*brq)); 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 = (struct ncp_rqhdr*)mb_reserve(mbp, sizeof(*rq)); rq->type = ptype; rq->seq = 0; /* filled later */ rq->fn = fn; - pstart = (caddr_t)rq; break; } - rqp->bpos = pstart + m->m_len; + rqp->nr_minrplen = -1; 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); +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); } + return 0; } -/* - * fetch reply routines + +/* + * Make a signature for the current packet and add it at the end of the + * packet. */ -#define ncp_mspaceleft (mtod(rqp->mrp,caddr_t)+rqp->mrp->m_len-rqp->bpos) +static int +ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size) +{ + u_char data[64]; + int error; -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]; + 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; } -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); +/* + * 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; } - 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); + 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); } - togo = 0; - while (rest--) { - ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++)); + 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; } - 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++)); + if (conn->flags & NCPFL_SIGNACTIVE) { + error = ncp_sign_packet(conn, rqp, &len); + if (error) + return error; + mbp->mb_top->m_pkthdr.len = len; } - 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); + 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 */ } - togo = 0; - while (rest--) { - ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++)); + 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); } - 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++)); + if (conn->flags & NCPFL_SIGNACTIVE) { + /* XXX: check reply signature */ + m_adj(mreply, -8); + plen -= 8; } - 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; + 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; } - rqp->mrp=m; - return; + md_get_mem(&rqp->rp, NULL, sizeof(*rp), MB_MSYSTEM); + return error; } -int -ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size) { - register struct mbuf *m=rqp->mrp; - register unsigned count; +/* + * 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; - - 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; + 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 -nwfs_mbuftouio(mrep, uiop, siz, dpos) - struct mbuf **mrep; - register struct uio *uiop; - int siz; - caddr_t *dpos; +ncp_request(struct ncp_rq *rqp) { - 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; + 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 (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; + if (rcnt-- == 0) { + error = ECONNRESET; + break; } - siz -= uiosiz; - } - *dpos = mbufcp; - *mrep = mp; - return (error); -} -/* - * copies a uio scatter/gather list to an mbuf chain. - * NOTE: can ony handle iovcnt == 1 - */ -int -nwfs_uiotombuf(uiop, mq, siz, bpos) - register struct uio *uiop; - struct mbuf **mq; - int siz; - caddr_t *bpos; -{ - register char *uiocp; - register struct mbuf *mp, *mp2; - register int xfer, left, mlen; - int uiosiz, clflg; - -#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; + /* + * Do not attempt to restore connection recursively + */ + if (ncp->flags & NCPFL_RESTORING) { + error = ENOTCONN; + break; } - uiop->uio_iov->iov_base += uiosiz; - uiop->uio_iov->iov_len -= uiosiz; - siz -= uiosiz; + error = ncp_restore_login(ncp); + if (error) + continue; } - *bpos = mtod(mp, caddr_t)+mp->m_len; - *mq = mp; - return (0); + ncp_conn_unlock(ncp, rqp->nr_p); +out: + if (error && (rqp->nr_flags & NCPR_DONTFREEONERR) == 0) + ncp_rq_done(rqp); + return error; } diff --git a/sys/netncp/ncp_rq.h b/sys/netncp/ncp_rq.h index 7c90e9f..bff912d 100644 --- a/sys/netncp/ncp_rq.h +++ b/sys/netncp/ncp_rq.h @@ -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_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_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_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); - -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); -} +int ncp_rq_pstring(struct ncp_rq *rqp, const char *s); + void ncp_sign_init(const char *logindata, char *sign_root); #else /* ifdef _KERNEL */ diff --git a/sys/netncp/ncp_sock.c b/sys/netncp/ncp_sock.c index 206c341..6503c2b 100644 --- a/sys/netncp/ncp_sock.c +++ b/sys/netncp/ncp_sock.c @@ -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 @@ done: 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 @@ bad: } 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 @@ bad: 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); } diff --git a/sys/netncp/ncp_sock.h b/sys/netncp/ncp_sock.h index acd2380..5172138 100644 --- a/sys/netncp/ncp_sock.h +++ b/sys/netncp/ncp_sock.h @@ -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); diff --git a/sys/netncp/ncp_subr.c b/sys/netncp/ncp_subr.c index 00c8503..4d208f9 100644 --- a/sys/netncp/ncp_subr.c +++ b/sys/netncp/ncp_subr.c @@ -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); -} diff --git a/sys/netncp/ncp_subr.h b/sys/netncp/ncp_subr.h index 7f493af..4eb6342 100644 --- a/sys/netncp/ncp_subr.h +++ b/sys/netncp/ncp_subr.h @@ -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_ */ |