tacacs-F4.0.4.28/client_count.c (138 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
#include "tac_plus.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#define MSGBUFSZ 1024
static char msgbuf[MSGBUFSZ];
static void *client_table[HASH_TAB_SIZE]; /* Table of client declarations */
static void *proc_table[HASH_TAB_SIZE]; /* Table of proc declarations */
/* initialize the client table proc tables
* The client table stores the number of connections for
* each client ip.
* The proc table stores the link between process id and
* client ip. When a tacacs process dies, the parent only
* get the process id, so we need to link the two */
void client_count_init(void) {
memset(proc_table, 0, sizeof(proc_table));
memset(client_table, 0, sizeof(client_table));
}
void remove_client_entry(char* client_ip)
{
CLIENT *entry = (CLIENT *)hash_delete_entry(client_table, client_ip);
if (entry) {
if (entry->name)
free(entry->name);
free(entry);
}
}
void remove_proc_entry(char* proc_id)
{
PROC_CLIENT *entry = (PROC_CLIENT *)hash_delete_entry(proc_table, proc_id);
if (entry) {
if (entry->name)
free(entry->name);
if (entry->client_ip)
free(entry->client_ip);
free(entry);
}
}
/* Map a process id to client IP address */
void create_proc_client_map(pid_t process_id, char* client_ip)
{
/* max size of a 64bit number is 19 chars */
char pid_str[20];
snprintf(pid_str, 20, "%d", process_id);
PROC_CLIENT *pc = (PROC_CLIENT *)tac_malloc(sizeof(PROC_CLIENT));
memset(pc, 0, sizeof(PROC_CLIENT));
pc->name = tac_strdup(pid_str);
pc->hash = NULL;
pc->client_ip = tac_strdup(client_ip);
hash_add_entry(proc_table, (void*)pc);
}
/* delete the mapping between process id and IP address */
void delete_proc_client_map(pid_t process_id)
{
char pid_str[20];
snprintf(pid_str, 20, "%d", process_id);
remove_proc_entry(pid_str);
}
/* get the client count for a given client ip */
int get_client_count(char* client_ip)
{
int count = 0;
/* now we see if there is a hash entry for this client_ip
* returns 0 if the client does not yet exist */
CLIENT *c = hash_lookup(client_table, client_ip);
if (c)
count = c->con_count;
return count;
}
/* increment the client counter for a client */
int increment_client_count(char* client_ip)
{
int count = get_client_count(client_ip);
/* create a new hash entry add it to the hash table */
CLIENT *nc = (CLIENT *)tac_malloc(sizeof(CLIENT));
memset(nc, 0, sizeof(CLIENT));
nc->name = tac_strdup(client_ip);
nc->hash = NULL;
nc->con_count = count + 1;
if (count) {
/* the hash does not support update, so we need to delete + add */
remove_client_entry(client_ip);
}
hash_add_entry(client_table, (void *)nc);
return nc->con_count;
}
char * get_client_ip_from_pid(pid_t process_id)
{
char pid_str[20];
/* hashing only works in strings, so we convert here */
snprintf(pid_str, 20, "%d", process_id);
PROC_CLIENT *pc = hash_lookup(proc_table, pid_str);
if (pc) {
return pc->client_ip;
}
}
/* derement the client counter for a given client IP */
int decrement_client_count(char* client_ip) {
CLIENT *nc;
int count = get_client_count(client_ip);
if (! count) {
return 0;
}
count--;
if (count >= 1) {
/* we update the existing hash entry if the count is still positive
* but the hash does not support update so we have to delete
* and then add */
CLIENT *nc = (CLIENT *)tac_malloc(sizeof(CLIENT));
memset(nc, 0, sizeof(CLIENT));
nc->name = tac_strdup(client_ip);
nc->hash = NULL;
nc->con_count = count;
remove_client_entry(client_ip);
hash_add_entry(client_table, (void *)nc);
} else if (count == 0) {
/* if it was the last client, we delete the entry */
remove_client_entry(client_ip);
}
return count;
}
int decrement_client_count_for_proc(pid_t process_id)
{
int proc_count = 0;
char* client_ip = get_client_ip_from_pid(process_id);
if (client_ip) {
proc_count = decrement_client_count(client_ip);
snprintf(msgbuf, MSGBUFSZ, "Pid %lu Lowered Count for %s to %d",
process_id, client_ip, proc_count);
report(LOG_ALERT, msgbuf);
delete_proc_client_map(process_id);
} else {
snprintf(msgbuf, MSGBUFSZ, "Failed to find client ip for pid %lu", process_id);
report(LOG_ALERT, msgbuf);
}
return proc_count;
}
int increment_client_count_for_proc(pid_t process_id, char* client_ip)
{
/* first we need to map pid to client_ip */
create_proc_client_map(process_id, client_ip);
/* now we inrement */
return increment_client_count(client_ip);
}
void dump_client_tables()
{
CLIENT *cl;
PROC_CLIENT *pc;
CLIENT **clients = (CLIENT **) hash_get_entries(client_table);
PROC_CLIENT **procs = (PROC_CLIENT **) hash_get_entries(proc_table);
CLIENT **c;
PROC_CLIENT **p;
for (p = procs; *p; p++) {
pc = *p;
report(LOG_ALERT, "Proc: %s, IP: %s", pc->name, pc->client_ip);
}
for (c = clients; *c; c++) {
cl = *c;
report(LOG_ALERT, "Client: %s, Count: %d", cl->name, cl->con_count);
}
}