Logo Search packages:      
Sourcecode: tacacs+ version File versions  Download package

dump.c

/*
 * $Id: dump.c,v 1.12 2009-03-18 21:09:26 heas Exp $
 *
 * Copyright (c) 1995-1998 by Cisco systems, Inc.
 *
 * Permission to use, copy, modify, and distribute this software for
 * any purpose and without fee is hereby granted, provided that this
 * copyright and permission notice appear on all copies of the
 * software and supporting documentation, the name of Cisco Systems,
 * Inc. not be used in advertising or publicity pertaining to
 * distribution of the program without specific prior permission, and
 * notice be given in supporting documentation that modification,
 * copying and distribution is by permission of Cisco Systems, Inc.
 *
 * Cisco Systems, Inc. makes no representations about the suitability
 * of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
 * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "tac_plus.h"

/* Routines for dumping packets to stderr */
char *
summarise_outgoing_packet_type(u_char *pak)
{
    HDR *hdr;
    struct authen_reply *authen;
    struct author_reply *author;
    char *p;

    hdr = (HDR *)pak;

    switch (hdr->type) {
    case TAC_PLUS_AUTHEN:
      authen = (struct authen_reply *) (pak + TAC_PLUS_HDR_SIZE);

      switch (authen->status) {
      case TAC_PLUS_AUTHEN_STATUS_PASS:
          p = "AUTHEN/SUCCEED";
          break;
      case TAC_PLUS_AUTHEN_STATUS_FAIL:
          p = "AUTHEN/FAIL";
          break;
      case TAC_PLUS_AUTHEN_STATUS_GETDATA:
          p = "AUTHEN/GETDATA";
          break;
      case TAC_PLUS_AUTHEN_STATUS_GETUSER:
          p = "AUTHEN/GETUSER";
          break;
      case TAC_PLUS_AUTHEN_STATUS_GETPASS:
          p = "AUTHEN/GETPASS";
          break;
      case TAC_PLUS_AUTHEN_STATUS_ERROR:
          p = "AUTHEN/ERROR";
          break;
      default:
          p = "AUTHEN/UNKNOWN";
          break;
      }
      break;

    case TAC_PLUS_AUTHOR:
      author = (struct author_reply *) (pak + TAC_PLUS_HDR_SIZE);
      switch (author->status) {
      case AUTHOR_STATUS_PASS_ADD:
          p = "AUTHOR/PASS_ADD";
          break;
      case AUTHOR_STATUS_FAIL:
          p = "AUTHOR/FAIL";
          break;
      case AUTHOR_STATUS_PASS_REPL:
          p = "AUTHOR/PASS_REPL";
          break;
      case AUTHOR_STATUS_ERROR:
          p = "AUTHOR/ERROR";
          break;
      default:
          p = "AUTHOR/UNKNOWN";
          break;
      }
      break;
    case TAC_PLUS_ACCT:
      p = "ACCT";
      break;
    default:
      p = "UNKNOWN";
      break;
    }
    return(p);
}

void
dump_header(u_char *pak)
{
    HDR *hdr;
    u_char *data;

    hdr = (HDR *)pak;

    report(LOG_DEBUG, "PACKET: key=%s", session.key ? session.key : "<NULL>");
    report(LOG_DEBUG, "version %d (0x%x), type %d, seq no %d, flags 0x%x",
         hdr->version, hdr->version, hdr->type, hdr->seq_no, hdr->flags);
    report(LOG_DEBUG, "session_id %u (0x%x), Data length %d (0x%x)",
         ntohl(hdr->session_id), ntohl(hdr->session_id),
         ntohl(hdr->datalength), ntohl(hdr->datalength));

    report(LOG_DEBUG, "End header");

    if (debug & DEBUG_HEX_FLAG) {
      report(LOG_DEBUG, "Packet body hex dump:");
      data = (u_char *)(pak + TAC_PLUS_HDR_SIZE);
      report_hex(LOG_DEBUG, data, ntohl(hdr->datalength));
    }
}

/* Dump packets originated by a NAS */
void
dump_nas_pak(u_char *pak)
{
    struct authen_start *start;
    struct authen_cont *cont;
    struct author *author;
    struct acct *acct;
    int i, resid;
    HDR *hdr;
    u_char *p, *argsizep;
    int seq;

    dump_header(pak);

    hdr = (HDR *)pak;

    seq = hdr->seq_no;
    if (seq % 2 != 1) {
      report(LOG_DEBUG, "nas packets should be odd numbered seq=%d",
             seq);
      exit(1);
    }

    resid = hdr->datalength;
    switch (hdr->type) {
    case TAC_PLUS_AUTHEN:
      start = (struct authen_start *) (pak + TAC_PLUS_HDR_SIZE);

      switch (hdr->seq_no) {
      case 1:
          report(LOG_DEBUG, "type=AUTHEN/START, priv_lvl = %d",
               start->priv_lvl);
          if (resid < TAC_AUTHEN_START_FIXED_FIELDS_SIZE) {
            report(LOG_DEBUG, "Bad AUTHEN/START packet length %d", resid);
            return;
          }
          resid -= TAC_AUTHEN_START_FIXED_FIELDS_SIZE;

          switch (start->action) {
          case TAC_PLUS_AUTHEN_LOGIN:
            report(LOG_DEBUG, "action=login");
            break;
          case TAC_PLUS_AUTHEN_CHPASS:
            report(LOG_DEBUG, "action=chpass");
            break;
          case TAC_PLUS_AUTHEN_SENDPASS:
            report(LOG_DEBUG, "action=sendpass");
            break;
          case TAC_PLUS_AUTHEN_SENDAUTH:
            report(LOG_DEBUG, "action=sendauth");
            break;
          default:
            report(LOG_DEBUG, "action=UNKNOWN %d", start->action);
            break;
          }

          switch(start->authen_type) {
          case TAC_PLUS_AUTHEN_TYPE_ASCII:
            report(LOG_DEBUG, "authen_type=ascii");
            break;
          case TAC_PLUS_AUTHEN_TYPE_PAP:
            report(LOG_DEBUG, "authen_type=pap");
            break;
          case TAC_PLUS_AUTHEN_TYPE_CHAP:
            report(LOG_DEBUG, "authen_type=chap");
            break;
          case TAC_PLUS_AUTHEN_TYPE_ARAP:
            report(LOG_DEBUG, "authen_type=arap");
            break;
          default:
            report(LOG_DEBUG, "authen_type=unknown %d", start->authen_type);
            break;
          }

          switch(start->service) {
          case TAC_PLUS_AUTHEN_SVC_LOGIN:
            report(LOG_DEBUG, "service=login");
            break;
          case TAC_PLUS_AUTHEN_SVC_ENABLE:
            report(LOG_DEBUG, "service=enable");
            break;
          case TAC_PLUS_AUTHEN_SVC_PPP:
            report(LOG_DEBUG, "service=ppp");
            break;
          case TAC_PLUS_AUTHEN_SVC_ARAP:
            report(LOG_DEBUG, "service=arap");
            break;
          case TAC_PLUS_AUTHEN_SVC_PT:
            report(LOG_DEBUG, "service=pt");
            break;
          case TAC_PLUS_AUTHEN_SVC_RCMD:
            report(LOG_DEBUG, "service=rcmd");
            break;
          case TAC_PLUS_AUTHEN_SVC_X25:
            report(LOG_DEBUG, "service=x25");
            break;
          case TAC_PLUS_AUTHEN_SVC_NASI:
            report(LOG_DEBUG, "service=nasi");
            break;
          default:
            report(LOG_DEBUG, "service=unknown %d", start->service);
            break;
          }

          report(LOG_DEBUG, "user_len=%d port_len=%d (0x%x), rem_addr_len=%d"
               " (0x%x)", start->user_len, start->port_len, start->port_len,
               start->rem_addr_len, start->rem_addr_len);
          report(LOG_DEBUG, "data_len=%d", start->data_len);
          if (resid < (start->user_len + start->port_len +
                   start->rem_addr_len + start->data_len)) {
            report(LOG_DEBUG, "AUTHEN/START data length (%d) exceeds "
                   "packet length length %d", (start->user_len +
                   start->port_len + start->rem_addr_len + start->data_len),
                   resid);
            return;
          }

          /* start of variable length data is here */
          p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_START_FIXED_FIELDS_SIZE;

          report(LOG_DEBUG, "User: ");
          report_string(LOG_DEBUG, p, start->user_len);
          p += start->user_len;

          report(LOG_DEBUG, "port: ");
          report_string(LOG_DEBUG, p, start->port_len);
          p += start->port_len;

          report(LOG_DEBUG, "rem_addr: ");
          report_string(LOG_DEBUG, p, start->rem_addr_len);
          p += start->rem_addr_len;

          report(LOG_DEBUG, "data: ");
          report_string(LOG_DEBUG, p, start->data_len);

          report(LOG_DEBUG, "End packet");
          return;

      default:
          cont = (struct authen_cont *) (pak + TAC_PLUS_HDR_SIZE);
          report(LOG_DEBUG, "type=AUTHEN/CONT");
          if (resid < TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE) {
            report(LOG_DEBUG, "Bad AUTHEN/CONT packet length %d", resid);
            return;
          }
          resid -= TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;

          report(LOG_DEBUG, "user_msg_len %d (0x%x), user_data_len %d (0x%x)",
               cont->user_msg_len, cont->user_msg_len,
               cont->user_data_len, cont->user_data_len);
          report(LOG_DEBUG, "flags=0x%x", cont->flags);
          if (resid < (cont->user_msg_len + cont->user_data_len)) {
            report(LOG_DEBUG, "AUTHEN/CONT data length (%d) exceeds "
                   "packet length length %d", (cont->user_msg_len +
                   cont->user_data_len), resid);
            return;
          }

          /* start of variable length data is here */
          p = pak + TAC_PLUS_HDR_SIZE +
            TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;

          report(LOG_DEBUG, "User msg: ");
          report_string(LOG_DEBUG, p, cont->user_msg_len);
          p += cont->user_msg_len;

          report(LOG_DEBUG, "User data: ");
          report_string(LOG_DEBUG, p, cont->user_data_len);

          report(LOG_DEBUG, "End packet");
          return;
      }

    case TAC_PLUS_AUTHOR:
      author = (struct author *) (pak + TAC_PLUS_HDR_SIZE);

      report(LOG_DEBUG, "type=AUTHOR, priv_lvl=%d, authen=%d",
             author->priv_lvl,
             author->authen_type);
      if (resid < TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE) {
          report(LOG_DEBUG, "Bad AUTHOR packet length %d", resid);
          return;
      }
      resid -= TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE;

      switch(author->authen_method) {
      case AUTHEN_METH_NONE:
            report(LOG_DEBUG, "method=none");
            break;
      case AUTHEN_METH_KRB5:
            report(LOG_DEBUG, "method=krb5");
            break;
      case AUTHEN_METH_LINE:
            report(LOG_DEBUG, "method=line");
            break;
      case AUTHEN_METH_ENABLE:
            report(LOG_DEBUG, "method=enable");
            break;
      case AUTHEN_METH_LOCAL:
            report(LOG_DEBUG, "method=local");
            break;
      case AUTHEN_METH_TACACSPLUS:
            report(LOG_DEBUG, "method=tacacs+");
            break;
      case AUTHEN_METH_RCMD:
            report(LOG_DEBUG, "method=rcmd");
            break;
      default:
            report(LOG_DEBUG, "method=unknown %d", author->authen_method);
            break;
      }

      report(LOG_DEBUG, "svc=%d user_len=%d port_len=%d rem_addr_len=%d",
             author->service, author->user_len,
             author->port_len, author->rem_addr_len);
      report(LOG_DEBUG, "arg_cnt=%d", author->arg_cnt);
      if (resid < (author->service + author->user_len + author->port_len +
                 author->rem_addr_len)) {
          report(LOG_DEBUG, "AUTHOR data length (%d) exceeds packet length "
               "length %d", (author->service + author->user_len +
               author->port_len + author->rem_addr_len), resid);
          return;
      }

      /* variable length data start here */
      p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REQ_FIXED_FIELDS_SIZE;
      argsizep = p;
      p += author->arg_cnt;

      report(LOG_DEBUG, "User: ");
      report_string(LOG_DEBUG, p, author->user_len);
      p += author->user_len;

      report(LOG_DEBUG, "port: ");
      report_string(LOG_DEBUG, p, author->port_len);
      p += author->port_len;

      report(LOG_DEBUG, "rem_addr: ");
      report_string(LOG_DEBUG, p, author->rem_addr_len);
      p += author->rem_addr_len;

      for (i = 0; i < (int)author->arg_cnt; i++) {
          report(LOG_DEBUG, "arg[%d]: size=%d ", i, *argsizep);
          report_string(LOG_DEBUG, p, *argsizep);
          p += *argsizep;
          argsizep++;
      }
      break;

    case TAC_PLUS_ACCT:
      acct = (struct acct *) (pak + TAC_PLUS_HDR_SIZE);
      report(LOG_DEBUG, "ACCT, flags=0x%x method=%d priv_lvl=%d",
             acct->flags, acct->authen_method, acct->priv_lvl);
      report(LOG_DEBUG, "type=%d svc=%d",
             acct->authen_type, acct->authen_service);
      if (resid < TAC_ACCT_REQ_FIXED_FIELDS_SIZE) {
          report(LOG_DEBUG, "Bad ACCT packet length %d", resid);
          return;
      }
      resid -= TAC_ACCT_REQ_FIXED_FIELDS_SIZE;
      if (resid < (acct->user_len + acct->port_len + acct->rem_addr_len)) {
          report(LOG_DEBUG, "AUTHOR data length (%d) exceeds packet length "
               "%d", (acct->user_len + acct->port_len + acct->rem_addr_len),
               resid);
          return;
      }
      resid -= acct->user_len + acct->port_len + acct->rem_addr_len;
      report(LOG_DEBUG, "user_len=%d port_len=%d rem_addr_len=%d",
             acct->user_len, acct->port_len, acct->rem_addr_len);
      report(LOG_DEBUG, "arg_cnt=%d", acct->arg_cnt);

      p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REQ_FIXED_FIELDS_SIZE;
      argsizep = p;
      p += acct->arg_cnt;

      report(LOG_DEBUG, "User: ");
      report_string(LOG_DEBUG, p, acct->user_len);
      p += acct->user_len;

      report(LOG_DEBUG, "port: ");
      report_string(LOG_DEBUG, p, acct->port_len);
      p += acct->port_len;

      report(LOG_DEBUG, "rem_addr: ");
      report_string(LOG_DEBUG, p, acct->rem_addr_len);
      p += acct->rem_addr_len;

      for (i = 0; i < (int)acct->arg_cnt; i++) {
          report(LOG_DEBUG, "arg[%d]: size=%d ", i, *argsizep);
          if (resid < 1 + *argsizep) {
            report(LOG_DEBUG, "ACCT arg %d data length (%d) exceeds packet "
                  "length %d", i, (1 + *argsizep), resid);
            return;
          }
          resid -= 1 + *argsizep;
          report_string(LOG_DEBUG, p, *argsizep);
          p += *argsizep;
          argsizep++;
      }
      break;

    default:
      report(LOG_DEBUG, "dump_nas_pak: unrecognized header type %d",
             hdr->type);
    }
    report(LOG_DEBUG, "End packet");
}

/* Dump packets originated by Tacacsd  */
void
dump_tacacs_pak(u_char *pak)
{
    struct authen_reply *authen;
    struct author_reply *author;
    struct acct_reply *acct;
    HDR *hdr;
    u_char *p, *argsizep;
    int i;
    int seq;

    dump_header(pak);

    hdr = (HDR *)pak;
    seq = hdr->seq_no;

    if (seq % 2 != 0) {
      report(LOG_ERR, "%s: Bad sequence number %d should be even",
             session.peer, seq);
      tac_exit(1);
    }

    switch (hdr->type) {
    case TAC_PLUS_AUTHEN:
      authen = (struct authen_reply *) (pak + TAC_PLUS_HDR_SIZE);

      report(LOG_DEBUG, "type=AUTHEN status=%d (%s) flags=0x%x",
             authen->status, summarise_outgoing_packet_type(pak),
             authen->flags);

      report(LOG_DEBUG, "msg_len=%d, data_len=%d",
             authen->msg_len, authen->data_len);

      /* start of variable length data is here */
      p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_REPLY_FIXED_FIELDS_SIZE;

      report(LOG_DEBUG, "msg: ");
      report_string(LOG_DEBUG, p, authen->msg_len);
      p += authen->msg_len;

      report(LOG_DEBUG, "data: ");
      report_string(LOG_DEBUG, p, authen->data_len);

      report(LOG_DEBUG, "End packet");
      return;

    case TAC_PLUS_AUTHOR:
      author = (struct author_reply *) (pak + TAC_PLUS_HDR_SIZE);

      report(LOG_DEBUG, "type=AUTHOR/REPLY status=%d (%s) ",
             author->status, summarise_outgoing_packet_type(pak));
      report(LOG_DEBUG, "msg_len=%d, data_len=%d arg_cnt=%d",
             author->msg_len, author->data_len, author->arg_cnt);

      /* start of variable length data is here */
      p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHOR_REPLY_FIXED_FIELDS_SIZE;

      /* arg sizes come next */
      argsizep = p;

      p += author->arg_cnt;

      report(LOG_DEBUG, "msg: ");
      report_string(LOG_DEBUG, p, author->msg_len);
      p += author->msg_len;

      report(LOG_DEBUG, "data: ");
      report_string(LOG_DEBUG, p, author->data_len);
      p += author->data_len;

      /* args follow */
      for (i = 0; i < (int)author->arg_cnt; i++) {
          int size = argsizep[i];

          report(LOG_DEBUG, "arg[%d] size=%d ", i, size);
          report_string(LOG_DEBUG, p, size);
          p += size;
      }
      break;

    case TAC_PLUS_ACCT:
      acct = (struct acct_reply *) (pak + TAC_PLUS_HDR_SIZE);
      report(LOG_DEBUG, "ACCT/REPLY status=%d", acct->status);

      report(LOG_DEBUG, "msg_len=%d data_len=%d",
             acct->msg_len, acct->data_len);

      p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REPLY_FIXED_FIELDS_SIZE;

      report(LOG_DEBUG, "msg: ");

      report_string(LOG_DEBUG, p, acct->msg_len);
      p += acct->msg_len;

      report(LOG_DEBUG, "data: ");
      report_string(LOG_DEBUG, p, acct->data_len);

      break;

    default:
      report(LOG_DEBUG, "dump_tacacs_pak: unrecognized header type %d",
             hdr->type);
    }
    report(LOG_DEBUG, "End packet");
}

/* summarise packet types for logging routines. */
char *
summarise_incoming_packet_type(u_char *pak)
{
    HDR *hdr;
    char *p;

    hdr = (HDR *)pak;

    switch (hdr->type) {
    case TAC_PLUS_AUTHEN:
      switch (hdr->seq_no) {
      case 1:
          p = "AUTHEN/START";
          break;
      default:
          p = "AUTHEN/CONT";
          break;
      }
      return(p);

    case TAC_PLUS_AUTHOR:
      p = "AUTHOR";
      break;
    case TAC_PLUS_ACCT:
      p = "ACCT";
      break;
    default:
      p = "UNKNOWN";
      break;
    }
    return(p);
}

Generated by  Doxygen 1.6.0   Back to index