/* parser.c -- This will have the parse and unparse routines to convert
 * internal structures into something that can be sent over the
 * wire and retreived.
 *
 * Created by:	Derek Atkins <warlord@MIT.EDU>
 *
 * $Source: /afs/net.mit.edu/user/warlord/Thesis/src/lib/RCS/parser.c,v $
 * $Author: warlord $
 *
 */

#include <warlord-copyright.h>

#if !defined(lint) && !defined(SABER)
static char rcsid_parser_c[] = "$Id: parser.c,v 1.6 93/12/11 15:15:22 warlord Exp $";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <krb.h>
#include <charon_prot.h>
#include <charon_err.h>

/* Requires:	octet be of at least size 4 bytes, and int >= 0, and int
 *		be of at most size 4 bytes
 * Modifies:	octet
 * Effects:	converts the integer num to an MSB-first represented
 *		octet string, and put this into octet.
 */
void
int2octet(int num, u_char *octet)
{
  int i;

  for (i = 3; i >=0; i--) {
    octet[i] = num%256;
    num /= 256;
  }
}

/* Requires:	octet be of size 4 bytes.
 * Modifies:	num
 * Effects:	converts an MSB-first octet string to an integer.
 */
void
octet2int(u_char *octet, int *num)
{
  int i;

  for (*num = 0, i = 0; i < 4; i++) {
    *num *= 256;
    *num += octet[i];
  }
}

/* This is a description of the format of the octet string from
 * the info structure, for each version.  If there is a new protocol
 * version, then this code might need to be changed.
 *
 * For version 2:
 *
 *  0...3 | 4...8 | 9 | 10 ... end
 * cookie |IP addr| e | principal 0 instance 0 realm 0 host 0 hostrealm 0
 */

/* Modifies:	data, datalen
 * Effects:	will convert the charon structure to an octet string
 *		of a form capable of being sent across the wire.
 *		The format should match that of octet2info.
 *		Will malloc the space needed.
 *		Returns CRN_OK on success, error otherwise.
 */
int
info2octet(charon_t *charon, u_char **data, u_int *datalen)
{
  *datalen = 0;			/* initialize length to zero */

  switch (charon->version) {

  case 2:
    /* allocate max size == 4 + sum(sizes of principal, inst, realm, hostinst, 
     * and hostrealm).
     */
    *data = (u_char *)malloc(4 + sizeof(struct sockaddr_in) +
			     sizeof(charon->principal) + 
			     sizeof(charon->instance) + 
			     sizeof(charon->realm) +
			     sizeof(charon->hostinst) +
			     sizeof(charon->hostrealm));

    if (*data == NULL)
      return(CRN_ALLOC);

    /* Ok, now that its actually allocated, lets convert it all. 
     * First, convert the cookie
     */
    COPY(charon->cookie, *data, 4);
    *datalen += 4;

    /* Copy in the address */
    COPY(&(charon->saddr.sin_addr), *data+*datalen, 
	  sizeof(charon->saddr.sin_addr));
    *datalen += sizeof(charon->saddr.sin_addr);

    /* Put in the srv_encrypt byte */
    *(*data+*datalen) = charon->srv_encrypt;
    (*datalen)++;

    /* Now, copy each of the other parts.  Make sure to keep the
     * NULL separation.  Start with the principal.
     */
    strcpy(*data+*datalen, charon->principal);
    *datalen += strlen(charon->principal) + 1;

    /* Copy the instance */
    strcpy(*data+*datalen, charon->instance);
    *datalen += strlen(charon->instance) + 1;

    /* And the realm */
    strcpy(*data+*datalen, charon->realm);
    *datalen += strlen(charon->realm) + 1;

    /* Now the host instance */
    strcpy(*data+*datalen, charon->hostinst);
    *datalen += strlen(charon->hostinst) + 1;

    /* And finally the host realm */
    strcpy(*data+*datalen, charon->hostrealm);
    *datalen += strlen(charon->hostrealm) + 1;

    break;

  default:
    return(CRN_BAD_VERSION);
  }
    
  return(CRN_OK);
}

/* Requires:	data be in the correct format for the version.
 * Modifies:	charon
 * Effects:	This function will convert an octet string to an internal
 * 		structure.  It is the reverse of info2octet, and it should
 *		match at all times.  The version of the software can be used
 *		as a flag if the structure changes.
 *		Returns CRN_OK on success, error otherwise.
 */
int
octet2info(u_char *data, charon_t *charon)
{
  char *char_p;

  switch(charon->version) {

  case 2:
    /* Pull out the cookie */
    COPY(data, charon->cookie, 4);
    data += 4;

    /* Now get the server address */
    COPY(data, &(charon->saddr.sin_addr), sizeof(charon->saddr.sin_addr));
    data += sizeof(charon->saddr.sin_addr);

    /* Get the server's encryption byte */
    charon->srv_encrypt = *data;
    data++;

    /* Now get the principal */
    char_p = charon->principal;
    do {
      *(char_p++) = *data;
    } while (*(data++) != NULL);

    /* And the instance */
    char_p = charon->instance;
    do {
      *(char_p++) = *data;
    } while (*(data++) != NULL);

    /* And the realm */
    char_p = charon->realm;
    do {
      *(char_p++) = *data;
    } while (*(data++) != NULL);

    /* And the hostname */
    char_p = charon->hostinst;
    do {
      *(char_p++) = *data;
    } while (*(data++) != NULL);

    /* And the hostrealm */
    char_p = charon->hostrealm;
    do {
      *(char_p++) = *data;
    } while (*(data++) != NULL);

    break;

  default:
    return (CRN_BAD_VERSION);
  }

  return(CRN_OK);
}

/* Effects:	Takes an octet string and puts it into a ktext
 *		structure.
 */
int
octet2ktext(u_char *octet, int datalen, KTEXT pkt)
{
  COPY(octet, pkt->dat, datalen);
  pkt->length = datalen;
  return(CRN_OK);
}

