Blame | Last modification | View Log | RSS feed
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/uio.h>
#include <9fs/9p.h>
#include <9fs/9auth.h>
#define N2HCHAR(x) x = *p++
#define N2HSHORT(x) x = (p[0] | (p[1]<<8)); p += 2
#define N2HLONG(x) x = (p[0] | (p[1]<<8) |\
(p[2]<<16) | (p[3]<<24)); p += 4
#define N2HQUAD(x) x = (u_int64_t)(p[0] | (p[1]<<8) |\
(p[2]<<16) | (p[3]<<24)) |\
((u_int64_t)(p[4] | (p[5]<<8) |\
(p[6]<<16) | (p[7]<<24)) << 32); p += 8
#define N2HSTRING(x,n) bcopy(p, x, n); p += n
#define H2NCHAR(x) *p++ = x
#define H2NSHORT(x) p[0]=x; p[1]=x>>8; p += 2
#define H2NLONG(x) p[0]=x; p[1]=x>>8; p[2]=x>>16; p[3]=x>>24; p += 4
#define H2NQUAD(x) p[0]=x; p[1]=x>>8;\
p[2]=x>>16; p[3]=x>>24;\
p[4]=x>>32; p[5]=x>>40;\
p[6]=x>>48; p[7]=x>>56;\
p += 8
#define H2NSTRING(x,n) bcopy(x, p, n); p += n
static int u9auth_send __P((struct socket *so, struct mbuf *top, struct proc *p));
static int u9auth_recv __P((struct socket *so, struct mbuf **mp, struct proc *p));
static int u9auth_count = 0;
static int u9auth_tr2m(struct u9auth_ticketreq *f, char *ap)
{
int n;
u_char *p;
p = (u_char*)ap;
H2NCHAR(f->type);
H2NSTRING(f->authid, U9FS_NAMELEN);
H2NSTRING(f->authdom, U9FS_DOMLEN);
H2NSTRING(f->chal, U9FS_CHALLEN);
H2NSTRING(f->hostid, U9FS_NAMELEN);
H2NSTRING(f->uid, U9FS_NAMELEN);
n = p - (u_char*)ap;
return n;
}
static struct mbuf * u9auth_m_tr2m(struct u9auth_ticketreq * tktq)
{
register struct mbuf *m;
char * ap;
int sz = 141;
MGETHDR(m, M_WAIT, MT_DATA);
if( sz > MHLEN )
MCLGET(m, M_WAIT);
m->m_len = 0;
if ( M_TRAILINGSPACE(m) < sz )
panic("u9auth_m_tr2m");
ap = mtod(m, char *);
m->m_len = u9auth_tr2m(tktq, ap);
m->m_pkthdr.len = m->m_len;
return (m);
}
static int
u9auth_send(so, top, p)
register struct socket *so;
register struct mbuf *top;
register struct proc *p;
{
int error, soflags, flags;
soflags = so->so_proto->pr_flags;
if (so->so_type == SOCK_SEQPACKET)
flags = MSG_EOR;
else
flags = 0;
error = so->so_proto->pr_usrreqs->pru_sosend(so, 0, 0, top, 0, flags, p);
return (error);
}
static int
u9auth_recv(so, mp, p)
register struct socket * so;
register struct mbuf **mp;
struct proc *p;
{
struct uio auio;
u_int32_t len;
int error = 0, sotype, rcvflg;
*mp = 0;
sotype = so->so_type;
/*
* For reliable protocols, lock against other senders/receivers
* in case a reconnect is necessary.
* For SOCK_STREAM, first get the Record Mark to find out how much
* more there is to get.
* We must lock the socket against other receivers
* until we have an entire rpc request/reply.
*/
if (sotype == SOCK_SEQPACKET ) {
if( (so->so_state & SS_ISCONNECTED) == 0 )
return (EACCES);
auio.uio_resid = len = 1000000;
auio.uio_procp = p;
do {
rcvflg = 0;
error = so->so_proto->pr_usrreqs->pru_soreceive
(so, 0, &auio, mp,
(struct mbuf **)0, &rcvflg);
} while (error == EWOULDBLOCK);
len -= auio.uio_resid;
}
if (error) {
m_freem(*mp);
*mp = 0;
}
return (error);
}
static void
u9auth_m2t(char *ap, struct u9auth_ticket *f, char *key)
{
u_char *p;
if(key)
decrypt9(key, ap, U9AUTH_TICKETLEN);
p = (u_char*)ap;
N2HCHAR(f->num);
N2HSTRING(f->chal, U9FS_CHALLEN);
N2HSTRING(f->cuid, U9FS_NAMELEN);
f->cuid[U9FS_NAMELEN-1] = 0;
N2HSTRING(f->suid, U9FS_NAMELEN);
f->suid[U9FS_NAMELEN-1] = 0;
N2HSTRING(f->key, U9AUTH_DESKEYLEN);
};
static int
u9auth_a2m(struct u9auth_authenticator *f, char *ap, char *key)
{
int n;
u_char *p;
p = (u_char*)ap;
H2NCHAR(f->num);
H2NSTRING(f->chal, U9FS_CHALLEN);
H2NLONG(f->id);
n = p - (u_char*)ap;
if(key)
encrypt9(key, ap, n);
return n;
}
void u9auth_genchal (char * chal)
{
u_long * lp = (u_long *)chal;
*lp++ = random();
*lp = random();
}
int u9auth_gettickets (struct socket * so, struct u9fsreq * rep,
char * user, char * ckey, char * ts, char * authc,
struct proc *p)
{
char * cp;
struct u9auth_ticketreq tktq;
struct u9auth_ticket tc;
struct u9auth_authenticator auth;
struct mbuf * m;
int error, len;
bzero(&tktq, sizeof(tktq));
tktq.type = AuthTreq;
bcopy(rep->r_authid, tktq.authid, U9FS_NAMELEN);
bcopy(rep->r_authdom, tktq.authdom, U9FS_DOMLEN);
bcopy(rep->r_chal, tktq.chal, U9FS_CHALLEN);
strncpy(tktq.hostid, user, U9FS_NAMELEN);
strncpy(tktq.uid, user, U9FS_NAMELEN);
m = u9auth_m_tr2m(&tktq);
error = u9auth_send(so, m, p);
if( error )
goto bad;
error = u9auth_recv(so, &m, p);
if( error )
goto bad;
len = U9AUTH_TICKETLEN+1;
if( m->m_len < len && (m = m_pullup(m, len)) == 0 )
goto bad;
cp = mtod(m, char *);
switch( cp[0] ) {
case AuthOK:
u9auth_m2t(&cp[1], & tc, ckey);
bzero(&auth, sizeof(auth));
auth.num = AuthAc;
bcopy(tc.chal, auth.chal, sizeof(auth.chal));
auth.id = u9auth_count++;
m->m_len -= len;
m->m_data += len;
len = U9AUTH_TICKETLEN;
if( m->m_len < len && (m = m_pullup(m, len)) == 0 )
goto bad;
cp = mtod(m, char *);
bcopy(cp, ts, len);
break;
case AuthErr:
case AuthOKvar:
m_freem(m);
goto bad;
break;
}
u9auth_a2m(&auth, authc, tc.key);
return 0;
bad:
return error;
}