Code

New /contrib plugin
[nagiosplug.git] / contrib / check_logins.c
1 /*=================================
2  *  check_logins - Nagios plugin
3  *  Copyright (C) 2003  Dag Robøle
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  *  Authors email: drobole@broadpark.no
20  */
21 //=================================
22 #include <sys/types.h>
23 #include <signal.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
30 #include "config.h"
31 #include "common.h"
32 #include "utils.h"
33 #include "popen.h"
34 //=================================
35 #define REVISION                "$Revision$"
36 #define COPYRIGHT               "2003"
37 #define AUTHOR                  "Dag Robole"
38 #define EMAIL                   "drobole@broadpark.no"
39 #define SUMMARY                 "Check for multiple user logins"
41 #define check(func, errmsg)     { if((func) == -1) die(STATE_UNKNOWN, errmsg); }
42 #define checkz(func, errmsg)    { if(!(func)) die(STATE_UNKNOWN, errmsg); }
43 //=================================
44 typedef struct USERNODE_TYP {
45         char *name;
46         char *host;
47         struct USERNODE_TYP* next;
48 } USERNODE;
49 //=================================
50 char *progname = NULL;
51 USERNODE *userlist = NULL, *adminlist = NULL;
52 int warning_limit = 0, critical_limit = 0;
54 void print_usage();
55 void print_help();
56 void process_arguments(int argc, char* *argv);
57 void parse_wholine(const char *line, char *name, char *host);
58 void node_create(USERNODE* *node, const char *name, const char *host);
59 void node_free(USERNODE* *node);
60 USERNODE* list_insert_sort_uniq(USERNODE* *list, USERNODE* *node);
61 void list_free(USERNODE* *list);
62 void cleanup();
63 //=================================
64 int main(int argc, char* *argv)
65 {
66         FILE *who;
67         USERNODE *newnode, *nptra, *nptrb;
68         char buffer[BUFSIZ], username[BUFSIZ], hostname[BUFSIZ], *cptra, *cptrb;
69         char max_login_name[BUFSIZ], currname[BUFSIZ];
70         int max_login_count = 0, counter = 0, skip;
71         void (*old_sig_alrm)();
73         progname = argv[0];
74         if(atexit(cleanup))
75                 die(STATE_UNKNOWN, "atexit failed\n");
76         
77         if((old_sig_alrm = signal((int)SIGALRM, timeout_alarm_handler)) == SIG_ERR)
78                 die(STATE_UNKNOWN, "signal failed\n");
79         alarm(timeout_interval);
81         process_arguments(argc, argv);
82         
83         checkz(who = spopen(PATH_TO_WHO), "spopen failed\n");
84         
85         while(fgets(buffer, sizeof(buffer), who) != NULL) {     
86                 parse_wholine(buffer, username, hostname);
87                 skip = 0;
88                 nptra = adminlist;
89                 
90                 while(nptra != NULL) {
91                         if(!strcmp(nptra->name, username)) {
92                                 skip = 1;
93                                 break;
94                         }
95                         nptra = nptra->next;
96                 }               
97                 if(!skip) {
98                         node_create(&newnode, username, hostname);
99                         if(!list_insert_sort_uniq(&userlist, &newnode))
100                                 node_free(&newnode);
101                 }
102         }
103         
104         check(spclose(who), "spclose failed\n");
106         if(userlist != NULL) {
107                 nptra = userlist;
108                 strcpy(currname, nptra->name);
109                 strcpy(max_login_name, nptra->name);
110                 max_login_count = 1;
111                 while(nptra != NULL) {
112                         if(!strcmp(currname, nptra->name))
113                                 ++counter;
114                         else {
115                                 if(counter > max_login_count) {
116                                         max_login_count = counter;
117                                         strcpy(max_login_name, currname);
118                                 }
119                                 strcpy(currname, nptra->name);
120                                 counter = 1;
121                         }
122                         nptra = nptra->next;
123                 }
124                 
125                 if(counter > max_login_count) {
126                         max_login_count = counter;
127                         strcpy(max_login_name, currname);
128                 }
129         }
131         if(signal((int)SIGALRM, old_sig_alrm) == SIG_ERR)
132                 die(STATE_UNKNOWN, "signal failed\n");
133                 
134         if(max_login_count) {
135                 if(critical_limit && max_login_count >= critical_limit) {
136                         printf("CRITICAL - User %s has logged in from %d different hosts\n", max_login_name, max_login_count);
137                         return STATE_CRITICAL;
138                 }
139                 else if(warning_limit && max_login_count >= warning_limit) {
140                         printf("WARNING - User %s has logged in from %d different hosts\n", max_login_name, max_login_count);
141                         return STATE_WARNING;
142                 }       
143         }
145         printf("OK - No users has exceeded the login limits\n");        
146         return STATE_OK;
148 //=================================
149 void print_usage()
151         fprintf(stderr, "Usage: %s [ -hV ] [ -w limit ] [ -c limit ] [ -u username1, ... ,usernameN ]\n", progname);
153 //=================================
154 void print_help()
156         print_revision(progname, REVISION);
157         printf("Copyright (c) %s %s <%s>\n\n%s\n\n", COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
158         print_usage();
159         printf("\nDescription:\n"
160                "\tThis plugin supports the w (warning) and c (critical) options indicating the upper limits\n"
161                "\tof logins allowed before a warning is given.\n"
162                "\tThe output from %s is the username and number of login sessions for the user\n"
163                "\twho has the most login sessions (from different hosts) running at a given point in time.\n"
164                "\tThe u (users) option takes a comma separated list of usernames that will be ignored\n"
165                "\twhile scannig users.\n"
166                "\nOptions:\n"
167                "\t-h | --help\n\t\tShow this help message and exit\n"
168                "\t-V | --version\n\t\tShow version description\n"
169                "\t-w | --warning=INTEGER\n\t\tSet warning limit for logins (minimum value is 2)\n"
170                "\t-c | --critical=INTEGER\n\t\tSet critical limit for logins (minimum value is 2)\n"
171                "\t-u | --users=STRING\n\t\tSet usernames to be ignored\n"
172                "\nExamples:\n\t%s -w 3 -c 5\n"
173                "\t%s -w 3 -c 5 -u root,guest,jcarmack\n\n", progname, progname, progname);
175 //=================================
176 void process_arguments(int argc, char* *argv)
177 {       
178         USERNODE *newnode;
179         int optch;
180         char buffer[BUFSIZ], *cptra;
181         static struct option long_opts[] = {
182                 {"help", no_argument, 0, 'h'},
183                 {"version", no_argument, 0, 'V'},
184                 {"warning", required_argument, 0, 'w'},
185                 {"critical", required_argument, 0, 'c'},
186                 {"users", required_argument, 0, 'u'},
187                 {0, 0, 0, 0},
188         };
189         
190         while((optch = getopt_long(argc, argv, "hVw:c:u:", long_opts, NULL)) != -1) {
191                 switch(optch) {
192                         case 'h':
193                                 print_help();
194                                 exit(STATE_OK);
195                                 break;
196                         case 'V':
197                                 print_revision(progname, REVISION);
198                                 exit(STATE_OK);
199                                 break;
200                         case 'w':
201                                 if(!is_numeric(optarg)) {
202                                         print_usage();
203                                         die(STATE_UNKNOWN, "invalid options\n");
204                                 }
205                                 warning_limit = atoi(optarg) > 2 ? atoi(optarg) : 2;
206                                 break;
207                         case 'c':
208                                 if(!is_numeric(optarg)) {
209                                         print_usage();
210                                         die(STATE_UNKNOWN, "invalid options\n");
211                                 }
212                                 critical_limit = atoi(optarg) > 2 ? atoi(optarg) : 2;
213                                 break;
214                         case 'u':
215                                 strcpy(buffer, optarg);
216                                 cptra = strtok(buffer, ",");
217                                 while(cptra != NULL) {
218                                         node_create(&newnode, cptra, "(adminhost)");
219                                         list_insert_sort_uniq(&adminlist, &newnode);
220                                         cptra = strtok(NULL, ",");
221                                 }
222                                 break;
223                         default:
224                                 print_usage();
225                                 exit(STATE_UNKNOWN);
226                                 break;
227                 }
228         }
230         if(argc > optind) {
231                 print_usage();
232                 die(STATE_UNKNOWN, "invalid options\n");
233         }
235         if(!warning_limit && !critical_limit) {
236                 print_usage();
237                 die(STATE_UNKNOWN, "you must provide a limit for this plugin\n");
238         }
239         
240         if(critical_limit && warning_limit > critical_limit) {
241                 print_usage();
242                 die(STATE_UNKNOWN, "warning limit must be less or equal critical limit\n");
243         }
245 //=================================
246 void parse_wholine(const char *line, char *name, char *host)
247 {       
248         char buffer[BUFSIZ], *cptra, *cptrb, *display;
249         strcpy(buffer, line);
251         cptra = buffer;
252         checkz(cptrb = (char*)strchr(buffer, ' '), "strchr failed\n");
253         strncpy(name, cptra, cptrb-cptra);
254         name[cptrb-cptra] = '\0';
256         if((cptra = strchr(buffer, '(')) != NULL) // hostname found in source arg...
257         {
258                 if(cptra[1] == ':') // local host
259                         strcpy(host, "(localhost)");
260                 else // extern host
261                 {
262                         checkz(cptrb = strchr(cptra, ')'), "strchr failed\n");
263                         cptrb++;
264                         strncpy(host, cptra, cptrb-cptra);
265                         host[cptrb-cptra] = '\0';
266                 }
267         }
268         else // no hostname in source arg, look in line arg...
269         {
270                 checkz(cptra = strtok(buffer, " \t\r\n"), "strtok failed\n"); 
271                 checkz(cptra = strtok(NULL, " \t\r\n"), "strtok failed\n");
272                 if(cptra[0] == ':') // local host
273                         strcpy(host, "(localhost)");
274                 else // extern host
275                         sprintf(host, "(%s)", cptra);
276         }
277         
278         if((cptra = strchr(host, ':')) != NULL) // remove display if any...
279                 strcpy(cptra, ")");
281 //================================= 
282 void node_create(USERNODE* *node, const char *name, const char *host)
283 {       
284         checkz(*node = (USERNODE*)malloc(sizeof(USERNODE)), "malloc failed\n");
285         checkz((*node)->name = (char*)malloc(strlen(name)+1), "malloc failed\n");
286         checkz((*node)->host = (char*)malloc(strlen(host)+1), "malloc failed\n");
287         (*node)->next = NULL;
288         strcpy((*node)->name, name);
289         strcpy((*node)->host, host);
291 //================================= 
292 void node_free(USERNODE* *node)
293 {       
294         free((*node)->name);
295         free((*node)->host);
296         free(*node);
297         *node = NULL;
299 //================================= 
300 USERNODE* list_insert_sort_uniq(USERNODE* *list, USERNODE* *node)
302         char n1[BUFSIZ], n2[BUFSIZ];
303         USERNODE *last_nptr = NULL, *nptr = *list;
304         
305         if(*list == NULL)
306                 return(*list = *node);
307         else {
308                 sprintf(n1, "%s %s", (*node)->name, (*node)->host);
309                 while(nptr != NULL) {
310                         sprintf(n2, "%s %s", nptr->name, nptr->host);
311                         if(!strcmp(n1, n2))
312                                 return NULL;
313                         else if(strcmp(n1, n2) < 0) {
314                                 if(last_nptr) {
315                                         last_nptr->next = *node;
316                                         (*node)->next = nptr;
317                                 }
318                                 else {
319                                         (*node)->next = *list;
320                                         *list = *node;
321                                 }
322                                 break;
323                         }
324                         else {
325                                 last_nptr = nptr;
326                                 nptr = nptr->next;
327                         }
328                 }
329                 if(nptr == NULL)
330                         last_nptr->next = *node;
331         }
332         return *node;
334 //================================= 
335 void list_free(USERNODE* *list)
336 {       
337         USERNODE *doe, *nptr = *list;
338         while(nptr != NULL) {
339                 doe = nptr;
340                 nptr = nptr->next;
341                 node_free(&doe);
342         }
343         *list = NULL;
345 //=================================
346 void cleanup()
348         list_free(&userlist);
349         list_free(&adminlist);
351 //=================================