/* ======================================================================== * Copyright (c) 2007-2009 The University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ======================================================================== */ /* idp audit plotter Inputs shib idp 2.x audit.log entries, produces activity plot. */ #include #include #include #include #include "ezp.h" char *prog = "(null)"; void usage() { fprintf(stderr, "usage: %s [-f from_date] [-t to_date] \n", prog); fprintf(stderr, " [-pd daily_plot_file ] \n"); fprintf(stderr, " [-ph hourly_plot_file ] \n"); fprintf(stderr, " [-sp sp_name ] \n"); fprintf(stderr, " [-sum summary_file ] \n"); fprintf(stderr, " idp_audit_logs \n"); fprintf(stderr, " \n"); exit (1); } /* SPs - a sorted list of all SPs */ typedef struct SP__ { struct SP__ *next; int index; int count; char *name; } SP_, *SP; SP splist = NULL; int nsp = 0; SP find_sp(char *name) { SP S, L; for (S=splist,L=NULL; S; L=S,S=S->next) { int c = strcmp(S->name, name); if (c==0) return (S); if (c>0) break; } S = (SP) malloc(sizeof(SP_)); memset (S, 0, sizeof(SP_)); S->index = nsp++; S->name = strdup(name); if (L) { S->next = L->next; L->next = S; } else { S->next = splist; splist = S; } return (S); } /* Hosts - a sorted list of all hosts */ typedef struct Host__ { struct Host__ *next; int index; int count; char *name; } Host_, *Host; Host hostlist = NULL; int nhost = 0; Host find_host(char *name) { Host H, L; for (H=hostlist,L=NULL; H; L=H,H=H->next) { int c = strcmp(H->name, name); if (c==0) return (H); if (c>0) break; } H = (Host) malloc(sizeof(Host_)); memset (H, 0, sizeof(Host_)); H->index = nhost++; H->name = strdup(name); if (L) { H->next = L->next; L->next = H; } else { H->next = hostlist; hostlist = H; } return (H); } /* run-time params */ char *daily_plot = NULL; int daily_plot_w = 700; int daily_plot_h = 400; char *daily_plot_title = NULL; char *hourly_plot = NULL; int hourly_plot_w = 700; int hourly_plot_h = 400; char *hourly_plot_title = NULL; char *sum_file = NULL; int start_time = 0; int end_time = 0; time_t low_time = 0; time_t high_time = 0; int n_authn = 0; int n_authz = 0; SP select_sp = NULL; /* types */ #define IDP_AUTHN 0 /* log record info, lookup sp, drop userid */ typedef struct ShibLog__ { struct ShibLog__ *next; Host host; int type; time_t time; SP sp; char *userid; int ymd; } ShibLog_, *ShibLog; ShibLog shiblogs = NULL; /* get the ymd from a time */ int get_ymd(time_t time) { struct tm *t = localtime(&time); return ((t->tm_year+1900) * 10000 + (t->tm_mon+1) * 100 + t->tm_mday); } /* get the time from a ymd and hms */ time_t get_time(int ymd, int hms, int dst) { struct tm t; memset (&t, 0, sizeof(t)); t.tm_year = ymd/10000 - 1900; ymd = ymd - (ymd/10000)*10000; t.tm_mon = ymd/100 - 1; ymd = ymd - (ymd/100)*100; t.tm_mday = ymd; t.tm_isdst = dst; if (hms) { t.tm_hour = hms/10000; hms = hms - (hms/10000)*10000; t.tm_min = hms/100; hms = hms - (hms/100)*100; t.tm_sec = hms; } return (mktime(&t)); } /* Parse a shib 2.x audit log record (with hostname prepended). host | time|type||spid|profile|idpid|resptype|xxx|userid|referer|attrs|xxx| */ static char *nextfield(char **rec) { char *f = *rec; char *p; for (p=f; *p && *p!='|'; p++); if (*p) *p++ = '\0'; *rec = p; return (f); } static ShibLog parse_rec(char *rec) { ShibLog S = (ShibLog) malloc(sizeof(ShibLog_)); char *s, *a, *b; int ms; int nerr = 0; int i; int ymd, hms; memset (S, 0, sizeof(ShibLog_)); for (i=0;i<1;i++) { /* gives us a bailout */ /* host */ s = nextfield(&rec); S->host = find_host(s); /* parse date and time */ s = nextfield(&rec); if (sscanf(s, "%dT%dZ", &ymd, &hms) < 2 ) { break; } S->time = get_time(ymd, hms, 0); /* get the SP */ s = nextfield(&rec); s = nextfield(&rec); s = nextfield(&rec); S->sp = find_sp(s); /* get the user */ s = nextfield(&rec); s = nextfield(&rec); s = nextfield(&rec); s = nextfield(&rec); s = nextfield(&rec); S->userid = strdup(s); } if (S->time>0) return (S); fprintf(stderr, " error: %s\n", rec); free (S); return (NULL); } /* Daily plot data */ char *color_bg = "white"; char *color_fg = "black"; #define MAX_SP 5 /* first is total */ char *sp_colors[] = {"black", "red", "blue", "orange", "green" }; #define SPD 86400 /* seconds per day */ #define SPH 3600 /* seconds per hour */ void do_daily_plot() { ShibLog L; int l; EZP_Image ei; EZP_Graph g0, g1; EZP_Color bgc, fgc, c[MAX_SP]; EZP_Style s[MAX_SP]; int i,j; EZP_Graph_attrs ga; char *labels[MAX_SP]; int ix; V *x; V *y[MAX_SP]; SP sps[MAX_SP]; int spsi; int ndays; /* num days plus one */ SP z; if (!start_time) start_time = get_time(get_ymd(low_time),0,-1); if (!end_time) end_time = get_time(get_ymd(high_time+SPD), 0,-1); ndays = (end_time - start_time) / SPD + 1; /* decide which SPs to plot */ /* for few enough SPs this will work - else need sort */ for (spsi=0;spsinext) { if (z->count>mc) { mc = z->count; sc = z; } } if (!sc) break; sps[spsi] = sc; sc->count = 0 - sc->count; } for (z=splist;z;z=z->next) if (z->count<0) z->count = 0 - z->count; /* create image, allocate colors, title image */ ei = ezp_create_image (daily_plot_w, daily_plot_h); bgc = ezp_allocate_color(ei, color_bg); fgc = ezp_allocate_color(ei, color_fg); if (daily_plot_title) ezp_image_title(ei, daily_plot_title, fgc); else if (select_sp) ezp_image_title(ei, select_sp->name, fgc); else ezp_image_title(ei, "All service providers", fgc); for (i=0;iname); else labels[i] = "All service providers"; } g0 = ezp_create_graph(ei, EZP_TYPE_TIME, EZP_TYPE_INT); ezp_graph_captions(g0, "date", "#logins", fgc); /* fill in plot data */ x = (V*) malloc(ndays*sizeof(V)); for (i=0;inext) { int day = (L->time-start_time)/SPD; if ((day<0)||(day>=ndays)) continue; for (j=0;jsp) break; y[0][day].i += 1; if (j==spsi) continue; y[j+1][day].i += 1; } for (i=select_sp?1:0;inext) { if (z->count>mc) { mc = z->count; sc = z; } } if (!sc) break; sps[spsi] = sc; sc->count = 0 - sc->count; } for (z=splist;z;z=z->next) if (z->count<0) z->count = 0 - z->count; /* create image, allocate colors, title image */ ei = ezp_create_image (hourly_plot_w, hourly_plot_h); bgc = ezp_allocate_color(ei, color_bg); fgc = ezp_allocate_color(ei, color_fg); if (hourly_plot_title) ezp_image_title(ei, hourly_plot_title, fgc); else if (select_sp) ezp_image_title(ei, select_sp->name, fgc); else ezp_image_title(ei, "All service providers", fgc); for (i=0;iname); else labels[i] = "All service providers"; } g0 = ezp_create_graph(ei, EZP_TYPE_TIME, EZP_TYPE_INT); ezp_graph_captions(g0, "date", "logins/hour", fgc); /* fill in plot data */ x = (V*) malloc(nhours*sizeof(V)); for (i=0;inext) { int hour = (L->time-start_time)/SPH; if ((hour<0)||(hour>=nhours)) continue; for (j=0;jsp) break; y[0][hour].i += 1; if (j==spsi) continue; y[j+1][hour].i += 1; } for (i=select_sp?1:0;inext) { int s = S->count; if (s<=0) continue; spd = (1.0 * s)/(1.0 * ndays); // fprintf(f, "%s%d%7.2f\n", S->name, s, spd); fprintf(f, "%s%d\n", S->name, s); totacc += s; } spd = (1.0 * totacc)/(1.0 * ndays); fprintf(f, "\n"); fprintf(f, " -- All providers --%d\n", totacc); fclose(f); } int scan_log_file(char *name) { FILE *fp; char rec[5000]; int recno = 1; ShibLog S; int dn; int spn; char *tz = getenv("TZ"); if (!(fp=fopen(name, "r"))) { perror(name); return (0); } setenv("TZ", "", 1); while (fgets(rec, 5000, fp)) { recno++; if (S=parse_rec(rec)) { if (start_time && (start_time>S->time)) { free(S); continue; } if (end_time && (end_timetime)) { free(S); continue; } if (select_sp && (select_sp!=S->sp)) continue; S->sp->count++; if ((low_time==0) || (S->timetime; if (S->time>high_time) high_time = S->time; S->next = shiblogs; shiblogs = S; } } fclose(fp); if (tz) setenv("TZ", tz, 1); else unsetenv("TZ"); printf("eof on %s, authn=%d, authz=%d\n", name, n_authn, n_authz); } int main(int argc, char **argv) { char *s; prog = argv[0]; while (--argc) { ++argv; if (!strcmp(argv[0],"-f")) { if (--argc<0) usage(); start_time = get_time(atoi((++argv)[0]), 0, -1); } else if (!strcmp(argv[0],"-t")) { if (--argc<0) usage(); end_time = get_time(atoi((++argv)[0]), 235959, -1); } else if (!strcmp(argv[0],"-pd")) { if (--argc<0) usage(); daily_plot = (++argv)[0]; } else if (!strcmp(argv[0],"-pdh")) { if (--argc<0) usage(); daily_plot_h = atoi((++argv)[0]); } else if (!strcmp(argv[0],"-pdw")) { if (--argc<0) usage(); daily_plot_w = atoi((++argv)[0]); } else if (!strcmp(argv[0],"-pdt")) { if (--argc<0) usage(); daily_plot_title = (++argv)[0]; } else if (!strcmp(argv[0],"-ph")) { if (--argc<0) usage(); hourly_plot = (++argv)[0]; } else if (!strcmp(argv[0],"-phh")) { if (--argc<0) usage(); hourly_plot_h = atoi((++argv)[0]); } else if (!strcmp(argv[0],"-phw")) { if (--argc<0) usage(); hourly_plot_w = atoi((++argv)[0]); } else if (!strcmp(argv[0],"-pht")) { if (--argc<0) usage(); hourly_plot_title = (++argv)[0]; } else if (!strcmp(argv[0],"-sp")) { if (--argc<0) usage(); select_sp = find_sp((++argv)[0]); } else if (!strcmp(argv[0],"-sum")) { if (--argc<0) usage(); sum_file = (++argv)[0]; } else if (!strcmp(argv[0],"-bg")) { if (--argc<0) usage(); color_bg = (++argv)[0]; } else if (!strcmp(argv[0],"-fg")) { if (--argc<0) usage(); color_fg = (++argv)[0]; } else if (argv[0][0]=='-') { usage(); } else scan_log_file(argv[0]); } if (daily_plot) do_daily_plot(); if (hourly_plot) do_hourly_plot(); if (sum_file) do_sum_report(); }