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