/************************************************************************
** MODULE INFORMATION*
**********************
**     FILE     NAME:       aut.c
**     SYSTEM   NAME:       SNMP Authentication Module
**     ORIGINAL AUTHOR(S):  Dirk Wisse
**     VERSION  NUMBER:     1
**     CREATION DATE:       1990/11/28
**
** DESCRIPTION: SNMP Authentication Module
**
*************************************************************************
** CHANGES INFORMATION **
*************************
** REVISION:    $Revision$
** WORKFILE:    $Workfile$
** LOGINFO:     $Log$
*************************************************************************/
#if ! defined(PRD)
static char _pvcs_hdr[] =
"$Header$";
#endif
#include "asn1.h"
#include "snmp.h"
#include "aut.h"


aut_sck
    AutSck =
{
    NULL,
    0,
    0
};

/**************************************************************
** NAME:        AutAddSrv                                 [API]
** SYNOPSIS:    aut_srv
**                  *AutAddSrv
**                  (
**                      char        *Com,
**                      unsigned    ComLen,
**                      int         (*Enc) (asn_sck  *Asn),
**                      int         (*Dec) (asn_sck  *Asn)
**                  )
** DESCRIPTION: Gets or Adds an authentication service.
**              Parameters:
**              Com: Community
**              ComLen: Length of community.
**              Enc: Function to encode encryption or NULL.
**              Dec: Function to decode encryption or NULL.
** RETURNS:     NULL --> error
**              else     pointer to desired service.
**************************************************************/
aut_srv *AutAddSrv (Com,ComLen,Enc,Dec)
char        *Com;
unsigned    ComLen;
int         (*Enc) __((asn_sck  *Asn));
int         (*Dec) __((asn_sck  *Asn));
{
    aut_srv
        *Srv;

    if ((Srv = AutGetSrv (Com, ComLen)) != NULL)
        return (Srv);
    if (ComLen > AUT_SZECOM)
        return (NULL);
    if ((Srv = (aut_srv *) malloc (sizeof (aut_srv))) == NULL)
        return (NULL);
    memcpy (Srv->SrvCom, Com, ComLen);
    Srv->SrvComLen = ComLen;
    Srv->SrvEnc = Enc;
    Srv->SrvDec = Dec;
    Srv->SrvNet = NULL;
    Srv->SrvNxt = AutSck.SckSrv;
    AutSck.SckSrv = Srv;
    return (Srv);
}

/**************************************************************
** NAME:        AutGetSrv
** SYNOPSIS:    aut_srv
**                  *AutGetSrv
**                  (
**                      char        *Com,
**                      unsigned    ComLen
**                  )
** DESCRIPTION: Gets an authentication service.
**              Parameters:
**              Com: Community
**              ComLen: Length of community.
** RETURNS:     NULL --> error
**              else     pointer to service.
**************************************************************/
aut_srv *AutGetSrv (Com,ComLen)
char        *Com;
unsigned    ComLen;
{
   aut_srv
      *Srv;

    Srv = AutSck.SckSrv;
    while (Srv != NULL)
    {
        if (Srv->SrvComLen == ComLen && !memcmp (Srv->SrvCom, Com, ComLen))
            return (Srv);
        Srv = Srv->SrvNxt;
    }
    return (NULL);
}

/**************************************************************
** NAME:        AutAddNet                                 [API]
** SYNOPSIS:    int
**                  AutAddNet
**                  (
**                      aut_srv     *Srv,
**                      long        Adr,
**                      long        Msk
**                  )
** DESCRIPTION: Adds a network mask to an authentication service.
**              Parameters:
**              Srv: Service
**              Adr: IP address.
**              Msk: IP mask.
**              A host is an authenticated member of the
**              community if (<address of host> & Msk) == Adr.
** RETURNS:     0 -->   no error
**              else    error code
**************************************************************/
int AutAddNet (Srv,Adr,Msk)
aut_srv     *Srv;
long        Adr;
long        Msk;
{
    aut_net
        *Net;

    if ((Net = (aut_net *) malloc (sizeof (aut_net))) == NULL)
        return (-1);
    Net->NetAdr = Adr;
    Net->NetMsk = Msk;
    Net->NetNxt = Srv->SrvNet;
    Srv->SrvNet = Net;
    return (0);
}

/**************************************************************
** NAME:        AutAdr
** SYNOPSIS:    int
**                  AutAdr
**                  (
**                      aut_srv *Srv,
**                      long    Adr
**                  )
** DESCRIPTION: Checks if address is part of community.
**              Parameters:
**              Srv: Authentication service for a particular
**                   community.
**              Adr: IP address to check.
** RETURNS:     0 --> address is authenticated
**              else  authentication failure.
**************************************************************/
int AutAdr (Srv,Adr)
aut_srv *Srv;
long    Adr;
{
    aut_net
        *Net;

    Net = Srv->SrvNet;
    while (Net != NULL)
    {
        if ((Adr & Net->NetMsk) == Net->NetAdr)
            return (0);
        Net = Net->NetNxt;
    }
    return (-1);
}

/**************************************************************
** NAME:        AutEnc                                    [API]
** SYNOPSIS:    int
**                  AutEnc
**                  (
**                      char        *Com,
**                      unsigned    ComLen,
**                      long        Adr,
**                      asn_sck     *Asn
**                  )
** DESCRIPTION: Authenticates a PDU of a message to be encoded.
**              Parameters:
**              Com: Community
**              ComLen: Length of community.
**              Adr: IP destination address.
**              Asn: Structure pointing to encoding of PDU.
**              If the pointer to the linked list of
**              authentication services is NULL it is assumed
**              that no authentication is desired.
**              Otherwise first the service for this community
**              is found. If the linked list of subnets is NULL
**              all hosts belong to this community otherwise it
**              is checked if the destination address belongs
**              to the community.
**              Then if the encryption funtion is not NULL the
**              ASN encoding of the PDU can be encrypted.
** RETURNS:     0 --> PDU authenticated.
**              else  authentication failure.
**************************************************************/
int AutEnc (Com,ComLen,Adr,Asn)
char        *Com;
unsigned    ComLen;
long        Adr;
asn_sck     *Asn;
{
    aut_srv
        *Srv;

    if (AutSck.SckSrv == NULL)
        return (0);
    if ((Srv = AutGetSrv (Com, ComLen)) == NULL)
        return (-1);
    if (Srv->SrvNet == NULL)
        return (0);
    if (AutAdr (Srv, Adr) < 0)
        return (-1);
    if (Srv->SrvEnc == NULL)
        return (0);
    if (Srv->SrvEnc (Asn) < 0)
        return (-1);
    return (0);
}

/**************************************************************
** NAME:        AutDec                                    [API]
** SYNOPSIS:    int
**                  AutDec
**                  (
**                      char        *Com,
**                      unsigned    ComLen,
**                      long        Adr,
**                      asn_sck     *Asn
**                  )
** DESCRIPTION: Authenticates a PDU of a decoded message.
**              Parameters:
**              Com: Community
**              ComLen: Length of community.
**              Adr: IP source address.
**              Asn: Structure pointing to encoding of PDU.
**              If the pointer to the linked list of
**              authentication services is NULL it is assumed
**              that no authentication is desired.
**              Otherwise first the service for this community
**              is found. If the linked list of subnets is NULL
**              all hosts belong to this community otherwise it
**              is checked if the source address belongs
**              to the community.
**              Then if the decryption funtion is not NULL the
**              ASN encoding of the PDU is decrypted.
** RETURNS:     0 --> PDU authenticated.
**              else  authentication failure.
**************************************************************/
int AutDec (Com,ComLen,Adr,Asn)
char                *Com;
unsigned            ComLen;
long                Adr;
asn_sck             *Asn;
{
    aut_srv
        *Srv;

    if (AutSck.SckSrv == NULL)
        return (0);
    if ((Srv = AutGetSrv (Com, ComLen)) == NULL)
    {
        AutSck.SckBadCom++;
        return (-1);
    }
    if (Srv->SrvNet == NULL)
        return (0);
    if (AutAdr (Srv, Adr) < 0)
    {
        AutSck.SckBadUse++;
        return (-1);
    }
    if (Srv->SrvDec == NULL)
        return (0);
    if (Srv->SrvDec (Asn) < 0)
    {
        AutSck.SckBadUse++;
        return (-1);
    }
    return (0);
}
