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