/* ** File name: ACC_DUMP ** Product: TCPware for VMS ** Version: V5.6 ** Edit level: 6 ** ** Copyright (c) 2000, 2001, 2002 by ** Process Software ** Framingham, Massachusetts ** ** This software is furnished under a license for use on a ** single computer system and may be copied only with the ** inclusion of the above copyright notice. This software, or ** any other copies thereof, may not be provided or otherwise ** made available to any other person except for use on such ** system and to one who agrees to these license terms. Title ** to and ownership of the software shall at all times remain ** in Process Software's name. ** ** The information in this document is subject to change ** without notice and should not be construed as a commitment ** by Process Software. Process Software assumes no ** responsibility for any errors that may appear in this ** document. ** ** Abstract: ** This program dumps the accounting file that can be written ** by the ACC_LISTENER progrm ** ** ** ** Author: Richard Whalen ** Date: September, 2000 ** ** 16-Feb-2001 RVW Edit 2 ** Update for changes in format in SMTP records. ** ** 12-Mar-2001 RVW Edit 3 ** Add checks for long enough records (especially SMTP) ** ** 1-May-2001 RVW Edit 4 ** Added CLI parameters: SINCE, BEFORE, PROTOCOL, INPUT, OUTPUT ** CSV (comma separated values) ** ** 29-May-2001 RVW Edit 5 ** Text fields in CSV might contain a comma, which would screw up ** the following fields; replace them with a space. ** ** 12-Jun-2002 SWL Edit 6 ** Updated product version and copyright date. ** */ #include #include #include #include #ifdef MULTINET_PRODUCT #include #include #include #include #include #include #else #include #include "in.h" #include "netdb.h" #include "socket.h" #include "accounting.h" #endif #include #include #include #include #include #include #include "stddef.h" #ifdef __DECC #include #include #include #else #include #include #include #endif #include #define MAX_ACCNTNG_MSG 4096 char accounting_record [MAX_ACCNTNG_MSG]; static struct FAB Fab; static struct RAB Rab; static struct NAM Nam; static FILE *out_file_desc; static int csv = 0; #define DBG_MASK DBG_ACCOUNTING #ifdef MULTINET_PRODUCT #define DSC struct dsc$descriptor #define $DSC(dsc,txt) struct dsc$descriptor dsc [1] = {sizeof (txt) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, txt} #define $DSCL(dsc,str,siz) struct dsc$descriptor dsc [1] = {siz, DSC$K_DTYPE_T, DSC$K_CLASS_S, str} #endif #define GEN_STR_LEN 255 static char msgbuf[GEN_STR_LEN + 1]; static $DSCL (msgbuf_desc, msgbuf, GEN_STR_LEN); static unsigned int efn_mask = 0; extern void read_config_file(); extern char *inet_ntoa(int); /* ** Format: format_time () ** ** Action: ** Displays a banner line with the date in it. */ int format_time (int time[]) { int wlen = 0; int status; status = SYS$ASCTIM (&wlen, msgbuf_desc, time, 0); /* get current time */ msgbuf[wlen] = 0; return (1); } rms_open(char *filename) { int status; LIB$MOVC5(&0, &Fab, &0, &sizeof(Fab), &Fab); Fab.fab$b_bid = FAB$C_BID; Fab.fab$b_bln = sizeof(Fab); Fab.fab$b_fac = FAB$M_GET; Fab.fab$b_rfm = FAB$C_VAR; Fab.fab$l_fna = filename; Fab.fab$b_fns = strlen(filename); Fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET; LIB$MOVC5(&0, &Rab, &0, &sizeof(Rab), &Rab); Rab.rab$b_bid = RAB$C_BID; Rab.rab$b_bln = sizeof (Rab); Rab.rab$l_fab = &Fab; Rab.rab$l_rop = RAB$M_RAH; status = sys$open(&Fab); if (!(status& 1)) printf ("%%accounting open returned %d, %d\n", status, Fab.fab$l_stv); if (!(status & 1)) return status; status = sys$connect(&Rab); if (!(status& 1)) printf ("%%accounting open returned %d, %d\n", status, Fab.fab$l_stv); if (!(status & 1)) return status; return status; } static void dump_ftp_record(struct FTPaccounting_data *entry, int RecordSize, int start_date[], int end_date[]) { int time_diff[2], status; if (RecordSize < sizeof(struct FTPaccounting_data)) { printf("undersized FTP record\n"); return; } if (start_date[0] != 0 || start_date[1] != 0) { status = lib$sub_times(entry->start_time, start_date, time_diff); if (status == LIB$_NEGTIM) return; } if (end_date[0] != 0 || end_date[1] != 0) { status = lib$sub_times(end_date, entry->start_time, time_diff); if (status == LIB$_NEGTIM) return; } if (csv) fprintf(out_file_desc, "%d, %c, %s", entry->header.port, entry->header.type, inet_ntoa(entry->header.reporterIP)); else if (entry->header.type == 'C') fprintf(out_file_desc,"FTP Client "); else if (entry->header.type == 'S') fprintf(out_file_desc,"FTP Server "); else fprintf(out_file_desc,"FTP Unknown "); format_time(entry->start_time); entry->user[12] = 0; if (!csv) { fprintf(out_file_desc,"reported from %s ", inet_ntoa(entry->header.reporterIP)); fprintf(out_file_desc,"from a session with %s, \n", inet_ntoa(entry->partnerIP)); fprintf(out_file_desc,"Starting at %s ", msgbuf); } else { fprintf(out_file_desc, ", %s, %s", inet_ntoa(entry->partnerIP), msgbuf); format_time(entry->end_time); fprintf(out_file_desc, ", %s, %s, %d, %d, %d, %d\n", msgbuf, entry->user, entry->filessent, entry->datasent, entry->filesrecv, entry->datarecv); } if (!csv) { format_time(entry->end_time); fprintf(out_file_desc," Ending at %s\n", msgbuf); fprintf(out_file_desc," User %s\n", entry->user); fprintf(out_file_desc," %d files sent, %d KBytes sent, %d files received, %d KBytes received\n\n", entry->filessent, entry->datasent, entry->filesrecv, entry->datarecv); } } static void dump_smtp_record(struct SMTPaccounting_data *entry, int RecordSize, int start_date[], int end_date[]) { int time_diff[2], status; char *cp; if (RecordSize < sizeof(struct SMTPaccounting_data)) { printf("undersized SMTP record\n"); return; } if (start_date[0] != 0 || start_date[1] != 0) { status = lib$sub_times(entry->date, start_date, time_diff); if (status == LIB$_NEGTIM) return; } if (end_date[0] != 0 || end_date[1] != 0) { status = lib$sub_times(end_date, entry->date, time_diff); if (status == LIB$_NEGTIM) return; } format_time(entry->date); if (csv) fprintf(out_file_desc, "%d, %c, %s, %s", entry->header.port, entry->header.type, inet_ntoa(entry->header.reporterIP), msgbuf); else if (entry->header.type == 'N') fprintf(out_file_desc, "SMTP Network delivery "); else if (entry->header.type == 'L') fprintf(out_file_desc, "SMTP Local delivery "); else if (entry->header.type == 'F') fprintf(out_file_desc, "SMTP Forwarded message "); else if (entry->header.type == 'R') fprintf(out_file_desc, "SMTP Returned message "); else if (entry->header.type == 'D') fprintf(out_file_desc, "SMTP Delivery Receipt sent "); else if (entry->header.type == 'Q') fprintf(out_file_desc, "SMTP message requeued "); else if (entry->header.type == 'J') fprintf(out_file_desc, "SMTP message rejected "); else fprintf(out_file_desc, "SMTP Unknown "); if (!csv) fprintf(out_file_desc, "reported from %s on %s ", inet_ntoa(entry->header.reporterIP), msgbuf); if (RecordSize < (sizeof(struct SMTPaccounting_data) + entry->from_str_size + 1)) { if (!csv) fprintf(out_file_desc, "\nrecord too short to contain valid user info\n\n"); else fprintf(out_file_desc, ", , , , \n"); return; } if (!csv) fprintf(out_file_desc, "%s sent %d bytes\n", entry->from_to_str, entry->msg_size); else { /* * replace commas with spaces so that the data doesn't get screwed up */ while (cp = strchr(entry->from_to_str, ',')) *cp = ' '; fprintf(out_file_desc, ",%s, %d", entry->from_to_str, entry->msg_size); } if (RecordSize < (sizeof(struct SMTPaccounting_data) + entry->from_str_size + entry->to_str_size)) { if (!csv) fprintf(out_file_desc, "to information missing\n\n"); else fprintf(out_file_desc, ", , , \n"); return; } if (!csv) fprintf(out_file_desc, "to %s ", &entry->from_to_str[entry->from_str_size + 1]); else { /* * replace commas with spaces so that the data doesn't get screwed up */ while (cp = strchr(&entry->from_to_str[entry->from_str_size + 1], ',')) *cp = ' '; fprintf(out_file_desc, ", %s", &entry->from_to_str[entry->from_str_size + 1]); } if (RecordSize < (sizeof(struct SMTPaccounting_data) + entry->from_str_size + entry->to_str_size + entry->partner_str_size)) { if (!csv) fprintf(out_file_desc, " Via information not present\n\n"); else fprintf(out_file_desc, ", \n"); return; } if (!csv) fprintf(out_file_desc, "via %s\n\n", &entry->from_to_str[entry->from_str_size + 1 + entry->to_str_size + 1]); else fprintf(out_file_desc, ", %s\n", &entry->from_to_str[entry->from_str_size + 1 + entry->to_str_size + 1]); } format_data(struct accountingPDU *entry, int size, int start_date[2], int end_date[2]) { if (entry->port == 21) dump_ftp_record((struct FTPaccounting_data *)entry, size, start_date, end_date); else if (entry->port == 25) dump_smtp_record((struct SMTPaccounting_data *)entry, size, start_date, end_date); else printf("record from unexpected port = %d\n", entry->port); } #define PROTOCOL_LIST_SIZE 10 #ifdef MULTINET_PRODUCT acc_dump() #else main() #endif { int status; char acc_file_name[255]; int start_date[2] = {0, 0}, end_date[2] = {0, 0}; int protocol_list[PROTOCOL_LIST_SIZE], list_entries_used=0; int entity_desc[2], ret_desc[2], ret_length = 0, temp_num; char return_string [255]; struct accountingPDU *entry; entity_desc[0] = strlen("INPUT"); entity_desc[1] = (int)"INPUT"; if (cli$present(entity_desc) == CLI$_PRESENT) { ret_desc[0] = sizeof(acc_file_name); ret_desc[1] = (int)acc_file_name; cli$get_value(entity_desc, ret_desc, &ret_length); acc_file_name[ret_length] = 0; } else { printf("Name of accounting file: "); scanf("%s", acc_file_name); } entity_desc[0] = strlen("SINCE"); entity_desc[1] = (int)"SINCE"; if (cli$present(entity_desc) == CLI$_PRESENT) { ret_desc[0] = sizeof(return_string); ret_desc[1] = (int)return_string; cli$get_value(entity_desc, ret_desc, &ret_length); return_string[ret_length] = 0; ret_desc[0] = ret_length; status = sys$bintim(ret_desc, &start_date); if ((status & 1) != 1) { printf("bad format for SINCE time\n"); sys$exit(status); } } entity_desc[0] = strlen("BEFORE"); entity_desc[1] = (int)"BEFORE"; if (cli$present(entity_desc) == CLI$_PRESENT) { ret_desc[0] = sizeof(return_string); ret_desc[1] = (int)return_string; cli$get_value(entity_desc, ret_desc, &ret_length); return_string[ret_length] = 0; ret_desc[0] = ret_length; status = sys$bintim(ret_desc, &end_date); if ((status & 1) != 1) { printf("bad format for BEFORE time\n"); sys$exit(status); } } entity_desc[0] = strlen("CSV"); entity_desc[1] = (int)"CSV"; if (cli$present(entity_desc) == CLI$_PRESENT) csv = 1; entity_desc[0] = strlen("PROTOCOL"); entity_desc[1] = (int)"PROTOCOL"; if (cli$present(entity_desc) != CLI$_ABSENT) { do { ret_desc[0] = sizeof(return_string); ret_desc[1] = (int)return_string; status = cli$get_value(entity_desc, ret_desc, &ret_length); if (status == CLI$_ABSENT) break; return_string[ret_length] = 0; ret_desc[0] = ret_length; if (strcmp(return_string, "MAIL") == 0) protocol_list[list_entries_used++] = 25; else if (strcmp(return_string, "SMTP") == 0) protocol_list[list_entries_used++] = 25; else if (strcmp(return_string, "FTP") == 0) protocol_list[list_entries_used++] = 21; else { temp_num = atoi(return_string); if (temp_num != 0) protocol_list[list_entries_used++] = temp_num; else printf("bad value %s for protocol\n", return_string); } } while (1); } status = rms_open(acc_file_name); if ((status & 1) != 1) { printf("Unable to open %s\n", acc_file_name); sys$exit(status); } entity_desc[0] = strlen("OUTPUT"); entity_desc[1] = (int)"OUTPUT"; if (cli$present(entity_desc) == CLI$_PRESENT) { ret_desc[0] = sizeof(acc_file_name); ret_desc[1] = (int)acc_file_name; cli$get_value(entity_desc, ret_desc, &ret_length); acc_file_name[ret_length] = 0; out_file_desc = fopen(acc_file_name, "w"); if (out_file_desc == 0) { printf("error opening output file %s\n", acc_file_name); } } else out_file_desc = fopen("sys$output:", "w"); for (;;) { Rab.rab$l_ubf = accounting_record; Rab.rab$w_usz = sizeof(accounting_record); status = sys$get(&Rab); if (!(status & 1)) break; entry = (struct accountingPDU *) Rab.rab$l_rbf; if (Rab.rab$w_rsz < sizeof(struct accountingPDU)) { printf("undersized record\n"); continue; } if (list_entries_used != 0) { for (temp_num = 0; temp_num < list_entries_used; temp_num++) if (entry->port == protocol_list[temp_num]) { format_data(entry, Rab.rab$w_rsz, start_date, end_date); break; } } else { format_data(entry, Rab.rab$w_rsz, start_date, end_date); } } fclose(out_file_desc); sys$exit(1); } /* end module ACC_DUMP.C */