Subversion Repositories planix.SVN

Rev

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;
}