File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mpd / src / pap.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 08:44:29 2013 UTC (11 years, 5 months ago) by misho
Branches: mpd, MAIN
CVS tags: v5_8p7, v5_8p1_cross, v5_8p1, v5_8, v5_7p0, v5_7, v5_6, HEAD
5.7


/*
 * pap.c
 *
 * Written by Toshiharu OHNO <tony-o@iij.ad.jp>
 * Copyright (c) 1993, Internet Initiative Japan, Inc. All rights reserved.
 * See ``COPYRIGHT.iij''
 * 
 * Rewritten by Archie Cobbs <archie@freebsd.org>
 * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
 * See ``COPYRIGHT.whistle''
 */

#include "ppp.h"
#include "auth.h"
#include "util.h"

/*
 * INTERNAL FUNCTIONS
 */

  static void	PapSendRequest(Link l);
  static void	PapTimeout(void *ptr);

/*
 * PapStart()
 */

void
PapStart(Link l, int which)
{
  PapInfo pap = &l->lcp.auth.pap;

  switch (which) {
    case AUTH_PEER_TO_SELF:	/* Just wait for peer's request */
      break;

    case AUTH_SELF_TO_PEER:

      /* Initialize retry counter and timer */
      pap->next_id = 1;
      pap->retry = AUTH_RETRIES;

      TimerInit(&pap->timer, "PapTimer",
	l->conf.retry_timeout * SECONDS, PapTimeout, l);
      TimerStart(&pap->timer);

      /* Send first request */
      PapSendRequest(l);
      break;

    default:
      assert(0);
  }
}

/*
 * PapStop()
 */

void
PapStop(PapInfo pap)
{
  TimerStop(&pap->timer);
}

/*
 * PapSendRequest()
 *
 * Send a PAP packet to peer.
 */

static void
PapSendRequest(Link l)
{
    PapInfo		pap = &l->lcp.auth.pap;
    char		password[AUTH_MAX_PASSWORD];
    int			name_len, pass_len;
    u_char		*pkt;

    /* Get password corresponding to my authname */
    Log(LG_AUTH, ("[%s] PAP: using authname \"%s\"", 
	l->name, l->lcp.auth.conf.authname));
    if (l->lcp.auth.conf.password[0] != 0) {
	strlcpy(password, l->lcp.auth.conf.password, sizeof(password));
    } else if (AuthGetData(l->lcp.auth.conf.authname, password, 
	    sizeof(password), NULL, NULL) < 0) {
	Log(LG_AUTH, ("[%s] PAP: Warning: no secret for \"%s\" found", 
	    l->name, l->lcp.auth.conf.authname));
    }

    /* Build response packet */
    name_len = strlen(l->lcp.auth.conf.authname);
    pass_len = strlen(password);

    pkt = Malloc(MB_AUTH, 1 + name_len + 1 + pass_len);
    pkt[0] = name_len;
    memcpy(pkt + 1, l->lcp.auth.conf.authname, name_len);
    pkt[1 + name_len] = pass_len;
    memcpy(pkt + 1 + name_len + 1, password, pass_len);

    /* Send it off */
    AuthOutput(l, PROTO_PAP, PAP_REQUEST, pap->next_id++, pkt,
	1 + name_len + 1 + pass_len, 0, 0);
    Freee(pkt);
}

/*
 * PapInput()
 *
 * Accept an incoming PAP packet
 */

void
PapInput(Link l, AuthData auth, const u_char *pkt, u_short len)
{
    Auth		const a = &l->lcp.auth;
    PapInfo		const pap = &a->pap;
    PapParams		const pp = &auth->params.pap;
    char		failMesg[64];
    char		buf[16];

  switch (auth->code) {
    case PAP_REQUEST:
      {
	char		*name_ptr, name[256];
	char		*pass_ptr, pass[256];
	int		name_len, pass_len;

	/* Is this appropriate? */
	if (a->peer_to_self != PROTO_PAP) {
	    if (l->lcp.want_auth == PROTO_PAP && a->peer_to_self == 0) {
		Log(LG_AUTH, ("[%s] PAP: retransmitting ACK",
		    l->name));
		AuthOutput(l, PROTO_PAP, PAP_ACK, auth->id,
		    (u_char *) AUTH_MSG_WELCOME, strlen(AUTH_MSG_WELCOME), 1, 0);
		break;
	    }
	    Log(LG_AUTH, ("[%s] PAP: %s not expected",
		l->name, PapCode(auth->code, buf, sizeof(buf))));
	    auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
	    PapInputFinish(l, auth);
	    return;
	}

	/* Sanity check packet and extract fields */
	if (len < 1)
	    goto error;

	name_len = pkt[0];
	name_ptr = (char *)pkt + 1;

	if (1 + name_len >= len)
	    goto error;

	pass_len = pkt[1 + name_len];
	pass_ptr = (char *)pkt + 1 + name_len + 1;

	if (name_len + 1 + pass_len + 1 > len)
	    goto error;

	memcpy(name, name_ptr, name_len);
	name[name_len] = 0;
	memcpy(pass, pass_ptr, pass_len);
	pass[pass_len] = 0;

	strlcpy(pp->peer_name, name, sizeof(pp->peer_name));
	strlcpy(pp->peer_pass, pass, sizeof(pp->peer_pass));
	strlcpy(auth->params.authname, name, sizeof(auth->params.authname));
	auth->params.password[0] = 0;

	auth->finish = PapInputFinish;
	AuthAsyncStart(l, auth);
	return;
      }
      break;

    case PAP_ACK:
    case PAP_NAK:
      {
	/* Is this appropriate? */
	if (a->self_to_peer != PROTO_PAP) {
	    Log(LG_AUTH, ("[%s] PAP: %s not expected",
		l->name, PapCode(auth->code, buf, sizeof(buf))));
	    break;
	}

	/* Stop resend timer */
	TimerStop(&pap->timer);

	/* Show reply message */
	if (len > 0) {
	    int		msg_len = pkt[0];
	    char	*msg = (char *) &pkt[1];
	    if (msg_len < len - 1)
		msg_len = len - 1;
	    ShowMesg(LG_AUTH, l->name, msg, msg_len);
	}

	/* Done with my auth to peer */
	AuthFinish(l, AUTH_SELF_TO_PEER, auth->code == PAP_ACK);	
      }
      break;

    default:
      Log(LG_AUTH, ("[%s] PAP: unknown code", l->name));
      break;
  }
    AuthDataDestroy(auth);
    return;

error:
    Log(LG_AUTH, ("[%s] PAP: Bad PAP packet", l->name));
    auth->why_fail = AUTH_FAIL_INVALID_PACKET;
    AuthFailMsg(auth, failMesg, sizeof(failMesg));
    AuthOutput(l, PROTO_PAP, PAP_NAK, auth->id, (u_char *)failMesg, strlen(failMesg), 1, 0);
    AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
    AuthDataDestroy(auth);
}

/*
 * PapInputFinish()
 *
 * Possible return point from the asynch auth handler.
 * 
 */
 
void PapInputFinish(Link l, AuthData auth)
{
  Auth		const a = &l->lcp.auth;
  PapParams	pap = &a->params.pap;
  const char	*Mesg;
  
    Log(LG_AUTH, ("[%s] PAP: Auth return status: %s", 
	l->name, AuthStatusText(auth->status)));

    if (auth->status == AUTH_STATUS_BUSY) {
	AuthDataDestroy(auth);  
	return;
    } else if (auth->status == AUTH_STATUS_FAIL)
	goto badRequest;
    else if (auth->status == AUTH_STATUS_SUCCESS)
	goto goodRequest;
  
    /* Do name & password match? */
    if (strcmp(a->params.authname, pap->peer_name) ||
        strcmp(a->params.password, pap->peer_pass)) {
	Log(LG_AUTH, ("[%s] PAP: Invalid response", l->name));
	auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
	goto badRequest;
    }

goodRequest:
    /* Login accepted */
    Log(LG_AUTH, ("[%s] PAP: Response is valid", l->name));
    if (auth->reply_message) {
	Mesg = auth->reply_message;
    } else {
	Mesg = AUTH_MSG_WELCOME;
    }
    Log(LG_AUTH, ("[%s] PAP: Reply message: %s", l->name, Mesg));
    AuthOutput(l, PROTO_PAP, PAP_ACK, auth->id, (u_char *) Mesg, strlen(Mesg), 1, 0);
    AuthFinish(l, AUTH_PEER_TO_SELF, TRUE);  
    AuthDataDestroy(auth);
    return;

badRequest:
  {
    char        failMesg[64];

    Mesg = AuthFailMsg(auth, failMesg, sizeof(failMesg));
    Log(LG_AUTH, ("[%s] PAP: Reply message: %s", l->name, Mesg));
    AuthOutput(l, PROTO_PAP, PAP_NAK, auth->id, (u_char *) Mesg, strlen(Mesg), 1, 0);
    AuthFinish(l, AUTH_PEER_TO_SELF, FALSE);
    AuthDataDestroy(auth);  
  }
}

/*
 * PapTimeout()
 *
 * Timer expired for reply to our request
 */

static void
PapTimeout(void *ptr)
{
  Link		const l = (Link) ptr;
  PapInfo	const pap = &l->lcp.auth.pap;

  if (--pap->retry > 0) {
    TimerStart(&pap->timer);
    PapSendRequest(l);
  }
}

/*
 * PapCode()
 */

const char *
PapCode(int code, char *buf, size_t len)
{
  switch (code) {
    case PAP_REQUEST:
      strlcpy(buf, "REQUEST", len);
      break;
    case PAP_ACK:
      strlcpy(buf, "ACK", len);
      break;
    case PAP_NAK:
      strlcpy(buf, "NAK", len);
      break;
    default:
      snprintf(buf, len, "code%d", code);
  }
  return(buf);
}


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>