tacacs-F4.0.4.28/acct.c (114 lines of code) (raw):
/*
* $Id: acct.c,v 1.11 2009-04-21 15:59:25 heas Exp $
*
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
* 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"
/*
* Come here when we receive an Start Accounting packet
*/
static void account(u_char *);
void
accounting(u_char *pak)
{
struct acct *acct_pak;
u_char *p;
HDR *hdr;
int i, len;
if (debug & DEBUG_ACCT_FLAG)
report(LOG_DEBUG, "Start accounting request");
hdr = (HDR *)pak;
acct_pak = (struct acct *)(pak + TAC_PLUS_HDR_SIZE);
/* Do some sanity checking on the packet */
/* Check if there's at least sizeof(struct acct) of useful data */
if (ntohl(hdr->datalength) < TAC_ACCT_REQ_FIXED_FIELDS_SIZE) {
report(LOG_ERR, "%s: acct minimum payload length: %zu, got: %u",
session.peer, TAC_ACCT_REQ_FIXED_FIELDS_SIZE,
ntohl(hdr->datalength));
send_error_reply(TAC_PLUS_ACCT, NULL);
return;
}
/* arg counts start here */
p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REQ_FIXED_FIELDS_SIZE;
/* Length checks */
len = TAC_ACCT_REQ_FIXED_FIELDS_SIZE;
len += acct_pak->user_len + acct_pak->port_len +
acct_pak->rem_addr_len + acct_pak->arg_cnt;
/* Is there enough space for acct_pak->length arguments */
if (ntohl(hdr->datalength) <
(TAC_ACCT_REQ_FIXED_FIELDS_SIZE + acct_pak->arg_cnt)) {
report(LOG_ERR, "%s: acct minimum payload: %zu, got: %u",
session.peer, TAC_ACCT_REQ_FIXED_FIELDS_SIZE + acct_pak->arg_cnt,
ntohl(hdr->datalength));
send_error_reply(TAC_PLUS_ACCT, NULL);
return;
}
for (i = 0; i < (int)acct_pak->arg_cnt; i++) {
len += p[i];
}
if (len != ntohl(hdr->datalength)) {
send_error_reply(TAC_PLUS_ACCT, NULL);
return;
}
account(pak);
}
static void
account(u_char *pak)
{
struct acct *acct_pak;
u_char *p, *argsizep;
struct acct_rec rec;
struct identity identity;
char **cmd_argp;
int i, errors = 0, status;
acct_pak = (struct acct *)(pak + TAC_PLUS_HDR_SIZE);
/* Fill out accounting record structure */
memset(&rec, 0, sizeof(struct acct_rec));
if (acct_pak->flags & TAC_PLUS_ACCT_FLAG_WATCHDOG)
rec.acct_type = ACCT_TYPE_UPDATE;
if (acct_pak->flags & TAC_PLUS_ACCT_FLAG_START)
rec.acct_type = ACCT_TYPE_START;
if (acct_pak->flags & TAC_PLUS_ACCT_FLAG_STOP)
rec.acct_type = ACCT_TYPE_STOP;
rec.authen_method = acct_pak->authen_method;
rec.authen_type = acct_pak->authen_type;
rec.authen_service = acct_pak->authen_service;
/* start of variable length data is here */
p = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REQ_FIXED_FIELDS_SIZE;
/* skip arg cnts */
p += acct_pak->arg_cnt;
/* zero out identity struct */
memset(&identity, 0, sizeof(struct identity));
identity.username = tac_make_string(p, (int)acct_pak->user_len);
p += acct_pak->user_len;
identity.NAS_name = tac_strdup(session.peer);
identity.NAS_port = tac_make_string(p, (int)acct_pak->port_len);
p += acct_pak->port_len;
if (acct_pak->port_len <= 0) {
strcpy(session.port, "unknown-port");
} else {
strcpy(session.port, identity.NAS_port);
}
identity.NAC_address = tac_make_string(p, (int)acct_pak->rem_addr_len);
p += acct_pak->rem_addr_len;
identity.priv_lvl = acct_pak->priv_lvl;
rec.identity = &identity;
/* Now process cmd args */
argsizep = pak + TAC_PLUS_HDR_SIZE + TAC_ACCT_REQ_FIXED_FIELDS_SIZE;
cmd_argp = (char **)tac_malloc(acct_pak->arg_cnt * sizeof(char *));
for (i = 0; i < (int)acct_pak->arg_cnt; i++) {
cmd_argp[i] = tac_make_string(p, *argsizep);
p += *argsizep++;
}
rec.args = cmd_argp;
rec.num_args = acct_pak->arg_cnt;
#ifdef MAXSESS
/* Tally for MAXSESS counting */
loguser(&rec);
#endif
/* Do accounting */
if (wtmpfile)
errors = do_wtmp(&rec);
if (session.acctfile != NULL)
errors += do_acct_file(&rec);
if (session.flags & SESS_FLAG_ACCTSYSL)
errors += do_acct_syslog(&rec);
if (errors) {
status = TAC_PLUS_ACCT_STATUS_ERROR;
} else {
status = TAC_PLUS_ACCT_STATUS_SUCCESS;
}
send_acct_reply(status, rec.msg, rec.admin_msg);
free(identity.username);
free(identity.NAS_name);
free(identity.NAS_port);
free(identity.NAC_address);
for (i = 0; i < (int)acct_pak->arg_cnt; i++) {
free(cmd_argp[i]);
}
free(cmd_argp);
if (rec.msg)
free(rec.msg);
if (rec.admin_msg)
free(rec.admin_msg);
}