summaryrefslogtreecommitdiffstats
path: root/plugins/check_users.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_users.c')
-rw-r--r--plugins/check_users.c433
1 files changed, 217 insertions, 216 deletions
diff --git a/plugins/check_users.c b/plugins/check_users.c
index 89b95369..3b2e265e 100644
--- a/plugins/check_users.c
+++ b/plugins/check_users.c
@@ -1,282 +1,283 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_users plugin 3 * Monitoring check_users plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2012 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_users plugin 10 * This file contains the check_users plugin
11* 11 *
12* This plugin checks the number of users currently logged in on the local 12 * This plugin checks the number of users currently logged in on the local
13* system and generates an error if the number exceeds the thresholds 13 * system and generates an error if the number exceeds the thresholds
14* specified. 14 * specified.
15* 15 *
16* 16 *
17* This program is free software: you can redistribute it and/or modify 17 * This program is free software: you can redistribute it and/or modify
18* it under the terms of the GNU General Public License as published by 18 * it under the terms of the GNU General Public License as published by
19* the Free Software Foundation, either version 3 of the License, or 19 * the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20 * (at your option) any later version.
21* 21 *
22* This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25 * GNU General Public License for more details.
26* 26 *
27* You should have received a copy of the GNU General Public License 27 * You should have received a copy of the GNU General Public License
28* along with this program. If not, see <http://www.gnu.org/licenses/>. 28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29 *
30* 30 *
31*****************************************************************************/ 31 *****************************************************************************/
32 32
33const char *progname = "check_users"; 33const char *progname = "check_users";
34const char *copyright = "2000-2007"; 34const char *copyright = "2000-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#include "common.h" 37#include "check_users.d/users.h"
38#include "utils.h" 38#include "output.h"
39#include "perfdata.h"
40#include "states.h"
41#include "utils_base.h"
42#include "./common.h"
43#include "./utils.h"
44#include "check_users.d/config.h"
45#include "thresholds.h"
39 46
40#if HAVE_WTSAPI32_H 47#if HAVE_WTSAPI32_H
41# include <windows.h> 48# include <windows.h>
42# include <wtsapi32.h> 49# include <wtsapi32.h>
43# undef ERROR 50# undef ERROR
44# define ERROR -1 51# define ERROR -1
45#elif HAVE_UTMPX_H 52#elif HAVE_UTMPX_H
46# include <utmpx.h> 53# include <utmpx.h>
47#else
48# include "popen.h"
49#endif 54#endif
50 55
51#ifdef HAVE_LIBSYSTEMD 56#ifdef HAVE_LIBSYSTEMD
52#include <systemd/sd-daemon.h> 57# include <systemd/sd-daemon.h>
53#include <systemd/sd-login.h> 58# include <systemd/sd-login.h>
54#endif 59#endif
55 60
56#define possibly_set(a,b) ((a) == 0 ? (b) : 0) 61typedef struct process_argument_wrapper {
57 62 int errorcode;
58int process_arguments (int, char **); 63 check_users_config config;
59void print_help (void); 64} check_users_config_wrapper;
60void print_usage (void); 65check_users_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
61
62char *warning_range = NULL;
63char *critical_range = NULL;
64thresholds *thlds = NULL;
65 66
66int 67void print_help(void);
67main (int argc, char **argv) 68void print_usage(void);
68{
69 int users = -1;
70 int result = STATE_UNKNOWN;
71#if HAVE_WTSAPI32_H
72 WTS_SESSION_INFO *wtsinfo;
73 DWORD wtscount;
74 DWORD index;
75#elif HAVE_UTMPX_H
76 struct utmpx *putmpx;
77#else
78 char input_buffer[MAX_INPUT_BUFFER];
79#endif
80 69
81 setlocale (LC_ALL, ""); 70int main(int argc, char **argv) {
82 bindtextdomain (PACKAGE, LOCALEDIR); 71 setlocale(LC_ALL, "");
83 textdomain (PACKAGE); 72 bindtextdomain(PACKAGE, LOCALEDIR);
73 textdomain(PACKAGE);
84 74
85 /* Parse extra opts if any */ 75 /* Parse extra opts if any */
86 argv = np_extra_opts (&argc, argv, progname); 76 argv = np_extra_opts(&argc, argv, progname);
87
88 if (process_arguments (argc, argv) == ERROR)
89 usage4 (_("Could not parse arguments"));
90 77
91 users = 0; 78 check_users_config_wrapper tmp_config = process_arguments(argc, argv);
92 79
93#ifdef HAVE_LIBSYSTEMD 80 if (tmp_config.errorcode == ERROR) {
94 if (sd_booted () > 0) 81 usage4(_("Could not parse arguments"));
95 users = sd_get_sessions (NULL);
96 else {
97#endif
98#if HAVE_WTSAPI32_H
99 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE,
100 0, 1, &wtsinfo, &wtscount)) {
101 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
102 return STATE_UNKNOWN;
103 } 82 }
104 83
105 for (index = 0; index < wtscount; index++) { 84 check_users_config config = tmp_config.config;
106 LPTSTR username;
107 DWORD size;
108 int len;
109
110 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
111 wtsinfo[index].SessionId, WTSUserName, &username, &size))
112 continue;
113 85
114 len = lstrlen(username); 86#ifdef _WIN32
115 87# if HAVE_WTSAPI32_H
116 WTSFreeMemory(username); 88 get_num_of_users_wrapper user_wrapper = get_num_of_users_windows();
117 89# else
118 if (len == 0) 90# error Did not find WTSAPI32
119 continue; 91# endif // HAVE_WTSAPI32_H
120
121 if (wtsinfo[index].State == WTSActive ||
122 wtsinfo[index].State == WTSDisconnected)
123 users++;
124 }
125
126 WTSFreeMemory(wtsinfo);
127#elif HAVE_UTMPX_H
128 /* get currently logged users from utmpx */
129 setutxent ();
130
131 while ((putmpx = getutxent ()) != NULL)
132 if (putmpx->ut_type == USER_PROCESS)
133 users++;
134
135 endutxent ();
136#else 92#else
137 /* run the command */ 93# ifdef HAVE_LIBSYSTEMD
138 child_process = spopen (WHO_COMMAND); 94 get_num_of_users_wrapper user_wrapper = get_num_of_users_systemd();
139 if (child_process == NULL) { 95# elif HAVE_UTMPX_H
140 printf (_("Could not open pipe: %s\n"), WHO_COMMAND); 96 get_num_of_users_wrapper user_wrapper = get_num_of_users_utmp();
141 return STATE_UNKNOWN; 97# else // !HAVE_LIBSYSTEMD && !HAVE_UTMPX_H
98 get_num_of_users_wrapper user_wrapper = get_num_of_users_who_command();
99# endif // HAVE_LIBSYSTEMD
100#endif // _WIN32
101
102 mp_check overall = mp_check_init();
103 if (config.output_format_is_set) {
104 mp_set_format(config.output_format);
142 } 105 }
106 mp_subcheck sc_users = mp_subcheck_init();
143 107
144 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 108 if (user_wrapper.errorcode != 0) {
145 if (child_stderr == NULL) 109 sc_users = mp_set_subcheck_state(sc_users, STATE_UNKNOWN);
146 printf (_("Could not open stderr for %s\n"), WHO_COMMAND); 110 sc_users.output = "Failed to retrieve number of users";
147 111 mp_add_subcheck_to_check(&overall, sc_users);
148 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 112 mp_exit(overall);
149 /* increment 'users' on all lines except total user count */
150 if (input_buffer[0] != '#') {
151 users++;
152 continue;
153 }
154
155 /* get total logged in users */
156 if (sscanf (input_buffer, _("# users=%d"), &users) == 1)
157 break;
158 } 113 }
114 /* check the user count against warning and critical thresholds */
159 115
160 /* check STDERR */ 116 mp_perfdata users_pd = {
161 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) 117 .label = "users",
162 result = possibly_set (result, STATE_UNKNOWN); 118 .value = mp_create_pd_value(user_wrapper.users),
163 (void) fclose (child_stderr); 119 };
164
165 /* close the pipe */
166 if (spclose (child_process))
167 result = possibly_set (result, STATE_UNKNOWN);
168#endif
169#ifdef HAVE_LIBSYSTEMD
170 }
171#endif
172 120
173 /* check the user count against warning and critical thresholds */ 121 users_pd = mp_pd_set_thresholds(users_pd, config.thresholds);
174 result = get_status((double)users, thlds); 122 mp_add_perfdata_to_subcheck(&sc_users, users_pd);
175 123
176 if (result == STATE_UNKNOWN) 124 int tmp_status = mp_get_pd_status(users_pd);
177 printf ("%s\n", _("Unable to read output")); 125 sc_users = mp_set_subcheck_state(sc_users, tmp_status);
178 else { 126
179 printf (_("USERS %s - %d users currently logged in |%s\n"), 127 switch (tmp_status) {
180 state_text(result), users, 128 case STATE_WARNING:
181 sperfdata_int("users", users, "", warning_range, 129 xasprintf(&sc_users.output,
182 critical_range, true, 0, false, 0)); 130 "%d users currently logged in. This violates the warning threshold",
131 user_wrapper.users);
132 break;
133 case STATE_CRITICAL:
134 xasprintf(&sc_users.output,
135 "%d users currently logged in. This violates the critical threshold",
136 user_wrapper.users);
137 break;
138 default:
139 xasprintf(&sc_users.output, "%d users currently logged in", user_wrapper.users);
183 } 140 }
184 141
185 return result; 142 mp_add_subcheck_to_check(&overall, sc_users);
143 mp_exit(overall);
186} 144}
187 145
146#define output_format_index CHAR_MAX + 1
147
188/* process command-line arguments */ 148/* process command-line arguments */
189int 149check_users_config_wrapper process_arguments(int argc, char **argv) {
190process_arguments (int argc, char **argv) 150 static struct option longopts[] = {{"critical", required_argument, 0, 'c'},
191{ 151 {"warning", required_argument, 0, 'w'},
192 int c; 152 {"version", no_argument, 0, 'V'},
193 int option = 0; 153 {"help", no_argument, 0, 'h'},
194 static struct option longopts[] = { 154 {"output-format", required_argument, 0, output_format_index},
195 {"critical", required_argument, 0, 'c'}, 155 {0, 0, 0, 0}};
196 {"warning", required_argument, 0, 'w'}, 156
197 {"version", no_argument, 0, 'V'}, 157 if (argc < 2) {
198 {"help", no_argument, 0, 'h'}, 158 usage(progname);
199 {0, 0, 0, 0} 159 }
200 };
201 160
202 if (argc < 2) 161 char *warning_range = NULL;
203 usage ("\n"); 162 char *critical_range = NULL;
163 check_users_config_wrapper result = {
164 .config = check_users_config_init(),
165 .errorcode = OK,
166 };
204 167
205 while (true) { 168 while (true) {
206 c = getopt_long (argc, argv, "+hVvc:w:", longopts, &option); 169 int counter = getopt_long(argc, argv, "+hVvc:w:", longopts, NULL);
207 170
208 if (c == -1 || c == EOF || c == 1) 171 if (counter == -1 || counter == EOF || counter == 1) {
209 break; 172 break;
173 }
210 174
211 switch (c) { 175 switch (counter) {
212 case '?': /* print short usage statement if args not parsable */ 176 case '?': /* print short usage statement if args not parsable */
213 usage5 (); 177 usage5();
214 case 'h': /* help */ 178 case 'h': /* help */
215 print_help (); 179 print_help();
216 exit (STATE_UNKNOWN); 180 exit(STATE_UNKNOWN);
217 case 'V': /* version */ 181 case 'V': /* version */
218 print_revision (progname, NP_VERSION); 182 print_revision(progname, NP_VERSION);
219 exit (STATE_UNKNOWN); 183 exit(STATE_UNKNOWN);
220 case 'c': /* critical */ 184 case 'c': /* critical */
221 critical_range = optarg; 185 critical_range = optarg;
222 break; 186 break;
223 case 'w': /* warning */ 187 case 'w': /* warning */
224 warning_range = optarg; 188 warning_range = optarg;
225 break; 189 break;
190 case output_format_index: {
191 parsed_output_format parser = mp_parse_output_format(optarg);
192 if (!parser.parsing_success) {
193 // TODO List all available formats here, maybe add anothoer usage function
194 printf("Invalid output format: %s\n", optarg);
195 exit(STATE_UNKNOWN);
196 }
197
198 result.config.output_format_is_set = true;
199 result.config.output_format = parser.output_format;
200 break;
201 }
226 } 202 }
227 } 203 }
228 204
229 c = optind; 205 int option_char = optind;
230 206
231 if (warning_range == NULL && argc > c) 207 if (warning_range == NULL && argc > option_char) {
232 warning_range = argv[c++]; 208 warning_range = argv[option_char++];
209 }
233 210
234 if (critical_range == NULL && argc > c) 211 if (critical_range == NULL && argc > option_char) {
235 critical_range = argv[c++]; 212 critical_range = argv[option_char++];
213 }
236 214
237 /* this will abort in case of invalid ranges */ 215 // TODO add proper verification for ranges here!
238 set_thresholds (&thlds, warning_range, critical_range); 216 mp_range_parsed tmp;
217 if (warning_range) {
218 tmp = mp_parse_range_string(warning_range);
219 } else {
220 printf("Warning threshold missing\n");
221 print_usage();
222 exit(STATE_UNKNOWN);
223 }
239 224
240 if (!thlds->warning) { 225 if (tmp.error == MP_PARSING_SUCCES) {
241 usage4 (_("Warning threshold must be a valid range expression")); 226 result.config.thresholds.warning = tmp.range;
227 result.config.thresholds.warning_is_set = true;
228 } else {
229 printf("Failed to parse warning range: %s", warning_range);
230 exit(STATE_UNKNOWN);
242 } 231 }
243 232
244 if (!thlds->critical) { 233 if (critical_range) {
245 usage4 (_("Critical threshold must be a valid range expression")); 234 tmp = mp_parse_range_string(critical_range);
235 } else {
236 printf("Critical threshold missing\n");
237 print_usage();
238 exit(STATE_UNKNOWN);
246 } 239 }
247 240
248 return OK; 241 if (tmp.error == MP_PARSING_SUCCES) {
242 result.config.thresholds.critical = tmp.range;
243 result.config.thresholds.critical_is_set = true;
244 } else {
245 printf("Failed to parse critical range: %s", critical_range);
246 exit(STATE_UNKNOWN);
247 }
248
249 return result;
249} 250}
250 251
251void 252void print_help(void) {
252print_help (void) 253 print_revision(progname, NP_VERSION);
253{
254 print_revision (progname, NP_VERSION);
255 254
256 printf ("Copyright (c) 1999 Ethan Galstad\n"); 255 printf("Copyright (c) 1999 Ethan Galstad\n");
257 printf (COPYRIGHT, copyright, email); 256 printf(COPYRIGHT, copyright, email);
258 257
259 printf ("%s\n", _("This plugin checks the number of users currently logged in on the local")); 258 printf("%s\n", _("This plugin checks the number of users currently logged in on the local"));
260 printf ("%s\n", _("system and generates an error if the number exceeds the thresholds specified.")); 259 printf("%s\n",
260 _("system and generates an error if the number exceeds the thresholds specified."));
261 261
262 printf ("\n\n"); 262 printf("\n\n");
263 263
264 print_usage (); 264 print_usage();
265 265
266 printf (UT_HELP_VRSN); 266 printf(UT_HELP_VRSN);
267 printf (UT_EXTRA_OPTS); 267 printf(UT_EXTRA_OPTS);
268 268
269 printf (" %s\n", "-w, --warning=RANGE_EXPRESSION"); 269 printf(" %s\n", "-w, --warning=RANGE_EXPRESSION");
270 printf (" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION")); 270 printf(" %s\n",
271 printf (" %s\n", "-c, --critical=RANGE_EXPRESSION"); 271 _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION"));
272 printf (" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION")); 272 printf(" %s\n", "-c, --critical=RANGE_EXPRESSION");
273 printf(" %s\n",
274 _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION"));
275 printf(UT_OUTPUT_FORMAT);
273 276
274 printf (UT_SUPPORT); 277 printf(UT_SUPPORT);
275} 278}
276 279
277void 280void print_usage(void) {
278print_usage (void) 281 printf("%s\n", _("Usage:"));
279{ 282 printf("%s -w <users> -c <users>\n", progname);
280 printf ("%s\n", _("Usage:"));
281 printf ("%s -w <users> -c <users>\n", progname);
282} 283}