]> granicus.if.org Git - icinga2/blob - plugins/check_users.cpp
Merge pull request #7124 from Icinga/bugfix/namespace-thread-safe
[icinga2] / plugins / check_users.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "plugins/thresholds.hpp"
4 #include <boost/program_options.hpp>
5 #include <iostream>
6 #include <windows.h>
7 #include <shlwapi.h>
8 #include <wtsapi32.h>
9
10 #define VERSION 1.0
11
12 namespace po = boost::program_options;
13
14 struct printInfoStruct
15 {
16         threshold warn;
17         threshold crit;
18         DOUBLE users;
19 };
20
21 static bool l_Debug;
22
23 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
24 {
25         WCHAR namePath[MAX_PATH];
26         GetModuleFileName(NULL, namePath, MAX_PATH);
27         WCHAR *progName = PathFindFileName(namePath);
28
29         po::options_description desc;
30
31         desc.add_options()
32                 ("help,h", "Print help message and exit")
33                 ("version,V", "Print version and exit")
34                 ("debug,d", "Verbose/Debug output")
35                 ("warning,w", po::wvalue<std::wstring>(), "Warning threshold")
36                 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
37                 ;
38
39         po::wcommand_line_parser parser(ac, av);
40
41         try {
42                 po::store(
43                         parser
44                         .options(desc)
45                         .style(
46                                 po::command_line_style::unix_style |
47                                 po::command_line_style::allow_long_disguise)
48                         .run(),
49                         vm);
50                 vm.notify();
51         } catch (const std::exception& e) {
52                 std::cout << e.what() << '\n' << desc << '\n';
53                 return 3;
54         }
55
56         if (vm.count("help")) {
57                 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
58                 wprintf(
59                         L"%s is a simple program to check a machines logged in users.\n"
60                         L"You can use the following options to define its behaviour:\n\n", progName);
61                 std::cout << desc;
62                 wprintf(
63                         L"\nIt will then output a string looking something like this:\n\n"
64                         L"\tUSERS WARNING 48 | users=48;10;50;0\n\n"
65                         L"\"USERS\" being the type of the check, \"WARNING\" the returned status\n"
66                         L"and \"48\" is the returned value.\n"
67                         L"The performance data is found behind the \"|\", in order:\n"
68                         L"returned value, warning threshold, critical threshold, minimal value and,\n"
69                         L"if applicable, the maximal value. Performance data will only be displayed when\n"
70                         L"you set at least one threshold\n\n"
71                         L"%s' exit codes denote the following:\n"
72                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
73                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
74                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
75                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
76                         L"Threshold syntax:\n\n"
77                         L"-w THRESHOLD\n"
78                         L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
79                         L"(unless stated differently)\n\n"
80                         L"-w !THRESHOLD\n"
81                         L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
82                         L"-w [THR1-THR2]\n"
83                         L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
84                         L"-w ![THR1-THR2]\n"
85                         L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
86                         L"-w THRESHOLD%%\n"
87                         L"if the plugin accepts percentage based thresholds those will be used.\n"
88                         L"Does nothing if the plugin does not accept percentages, or only uses\n"
89                         L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
90                         L"to end with a percentage sign.\n\n"
91                         L"All of these options work with the critical threshold \"-c\" too."
92                         , progName);
93                 std::cout << '\n';
94                 return 0;
95         }
96
97         if (vm.count("version"))
98                 std::wcout << L"Version: " << VERSION << '\n';
99
100         if (vm.count("warning")) {
101                 try {
102                         printInfo.warn = threshold(vm["warning"].as<std::wstring>());
103                 } catch (const std::invalid_argument& e) {
104                         std::cout << e.what() << '\n';
105                         return 3;
106                 }
107         }
108         if (vm.count("critical")) {
109                 try {
110                         printInfo.crit = threshold(vm["critical"].as<std::wstring>());
111                 } catch (const std::invalid_argument& e) {
112                         std::cout << e.what() << '\n';
113                         return 3;
114                 }
115         }
116
117         l_Debug = vm.count("debug") > 0;
118
119         return -1;
120 }
121
122 static int printOutput(printInfoStruct& printInfo)
123 {
124         if (l_Debug)
125                 std::wcout << L"Constructing output string" << '\n';
126
127         state state = OK;
128
129         if (printInfo.warn.rend(printInfo.users))
130                 state = WARNING;
131
132         if (printInfo.crit.rend(printInfo.users))
133                 state = CRITICAL;
134
135         switch (state) {
136         case OK:
137                 std::wcout << L"USERS OK " << printInfo.users << L" User(s) logged in | 'users'=" << printInfo.users << L";"
138                         << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n';
139                 break;
140         case WARNING:
141                 std::wcout << L"USERS WARNING " << printInfo.users << L" User(s) logged in | 'users'=" << printInfo.users << L";"
142                         << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n';
143                 break;
144         case CRITICAL:
145                 std::wcout << L"USERS CRITICAL " << printInfo.users << L" User(s) logged in | 'users'=" << printInfo.users << L";"
146                         << printInfo.warn.pString() << L";" << printInfo.crit.pString() << L";0;" << '\n';
147                 break;
148         }
149
150         return state;
151 }
152
153 static int check_users(printInfoStruct& printInfo)
154 {
155         DOUBLE users = 0;
156         WTS_SESSION_INFOW *pSessionInfo = NULL;
157         DWORD count;
158         DWORD index;
159
160         if (l_Debug)
161                 std::wcout << L"Trying to enumerate terminal sessions" << '\n';
162
163         if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &count)) {
164                 std::wcout << L"Failed to enumerate terminal sessions" << '\n';
165                 printErrorInfo();
166                 if (pSessionInfo)
167                         WTSFreeMemory(pSessionInfo);
168                 return 3;
169         }
170
171         if (l_Debug)
172                 std::wcout << L"Got all sessions (" << count << L"), traversing and counting active ones" << '\n';
173
174         for (index = 0; index < count; index++) {
175                 LPWSTR name;
176                 DWORD size;
177                 int len;
178
179                 if (l_Debug)
180                         std::wcout << L"Querrying session number " << index << '\n';
181
182                 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, pSessionInfo[index].SessionId,
183                         WTSUserName, &name, &size))
184                         continue;
185
186                 if (l_Debug)
187                         std::wcout << L"Found \"" << name << L"\". Checking whether it's a real session" << '\n';
188
189                 len = lstrlenW(name);
190
191                 WTSFreeMemory(name);
192
193                 if (!len)
194                         continue;
195
196                 if (pSessionInfo[index].State == WTSActive || pSessionInfo[index].State == WTSDisconnected) {
197                         users++;
198                         if (l_Debug)
199                                 std::wcout << L"\"" << name << L"\" is a real session, counting it. Now " << users << '\n';
200                 }
201         }
202
203         if (l_Debug)
204                 std::wcout << "Finished coutning user sessions (" << users << "). Freeing memory and returning" << '\n';
205
206         WTSFreeMemory(pSessionInfo);
207         printInfo.users = users;
208         return -1;
209 }
210
211 int wmain(int argc, WCHAR **argv)
212 {
213         printInfoStruct printInfo = { };
214         po::variables_map vm;
215
216         int ret = parseArguments(argc, argv, vm, printInfo);
217         if (ret != -1)
218                 return ret;
219
220         ret = check_users(printInfo);
221         if (ret != -1)
222                 return ret;
223
224         return printOutput(printInfo);
225 }