]> granicus.if.org Git - icinga2/blob - plugins/check_service.cpp
Update copyright year
[icinga2] / plugins / check_service.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 <iostream>
22
23 #include "thresholds.h"
24
25 #include "boost/program_options.hpp"
26
27 #define VERSION 1.0
28
29 namespace po = boost::program_options;
30
31 using std::wcout; using std::endl;
32 using std::cout; using std::wstring;
33
34 static BOOL debug;
35
36 struct printInfoStruct 
37 {
38         bool warn;
39         int ServiceState;
40         wstring service;
41 };
42
43 static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
44 static int printOutput(const printInfoStruct&);
45 static int ServiceStatus(const printInfoStruct&);
46
47 int wmain(int argc, wchar_t **argv)
48 {
49         po::variables_map vm;
50         printInfoStruct printInfo = { false, 0, L"" };
51
52         int ret = parseArguments(argc, argv, vm, printInfo);
53         if (ret != -1)
54                 return ret;
55
56         printInfo.ServiceState = ServiceStatus(printInfo);
57         if (printInfo.ServiceState == -1)
58                 return 3;
59
60         return printOutput(printInfo);
61 }
62
63 int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) 
64 {
65         wchar_t namePath[MAX_PATH];
66         GetModuleFileName(NULL, namePath, MAX_PATH);
67         wchar_t *progName = PathFindFileName(namePath);
68
69         po::options_description desc;
70
71         desc.add_options()
72                 ("help,h", "print help message and exit")
73                 ("version,V", "print version and exit")
74                 ("debug,d", "Verbose/Debug output")
75                 ("service,s", po::wvalue<wstring>(), "service to check (required)")
76                 ("warn,w", "return warning (1) instead of critical (2),\n when service is not running")
77                 ;
78
79         po::basic_command_line_parser<wchar_t> parser(ac, av);
80
81         try {
82                 po::store(
83                         parser
84                         .options(desc)
85                         .style(
86                         po::command_line_style::unix_style |
87                         po::command_line_style::allow_long_disguise)
88                         .run(),
89                         vm);
90                 vm.notify();
91         } catch (std::exception& e) {
92                 cout << e.what() << endl << desc << endl;
93                 return 3;
94         }
95
96         if (vm.count("help")) {
97                 wcout << progName << " Help\n\tVersion: " << VERSION << endl;
98                 wprintf(
99                         L"%s is a simple program to check the status of a service.\n"
100                         L"You can use the following options to define its behaviour:\n\n", progName);
101                 cout << desc;
102                 wprintf(
103                         L"\nIt will then output a string looking something like this:\n\n"
104                         L"\tSERVICE CRITICAL NOT_RUNNING|service=4;!4;!4;1;7\n\n"
105                         L"\"SERVICE\" being the type of the check, \"CRITICAL\" the returned status\n"
106                         L"and \"1\" is the returned value.\n"
107                         L"A service is either running (Code 0x04) or not running (any other).\n"
108                         L"For more information consult the msdn on service state transitions.\n\n"
109                         L"%s' exit codes denote the following:\n"
110                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
111                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
112                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
113                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
114                         L"%s' thresholds work differently, since a service is either running or not\n"
115                         L"all \"-w\" and \"-c\" do is say whether a not running service is a warning\n"
116                         L"or critical state respectively.\n\n"
117                         L"Known issue: Since icinga2 runs as NETWORK SERVICE it can't access the access control lists\n"
118                         L"it will not be able to find a service like NTDS. To fix this add ACL read permissions to icinga2.\n"
119                         , progName, progName);
120                 cout << endl;
121                 return 0;
122         }
123     
124          if (vm.count("version")) {
125                 cout << "Version: " << VERSION << endl;
126                 return 0;
127         } 
128     
129     if (!vm.count("service")) {
130                 cout << "Missing argument: service" << endl << desc << endl;
131                 return 3;
132         }
133
134         if (vm.count("warn"))
135                 printInfo.warn = true;
136         
137         printInfo.service = vm["service"].as<wstring>();
138
139         if (vm.count("debug"))
140                 debug = TRUE;
141         
142         return -1;
143 }
144
145 int printOutput(const printInfoStruct& printInfo) 
146 {
147         if (debug)
148                 wcout << L"Constructing output string" << endl;
149
150         wstring perf;
151         state state = OK;
152
153         if (!printInfo.ServiceState) {
154                 wcout << L"SERVICE CRITICAL NOT_FOUND | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
155                 return 3;
156         }
157
158         if (printInfo.ServiceState != 0x04) 
159                 printInfo.warn ? state = WARNING : state = CRITICAL;
160
161         switch (state) {
162         case OK:
163                 wcout << L"SERVICE OK RUNNING | service=4;!4;!4;1;7" << endl;
164                 break;
165         case WARNING:
166                 wcout << L"SERVICE WARNING NOT_RUNNING | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
167                 break;
168         case CRITICAL:
169                 wcout << L"SERVICE CRITICAL NOT_RUNNING | service=" << printInfo.ServiceState << ";!4;!4;1;7" << endl;
170                 break;
171         }
172     
173         return state;
174 }
175
176 int ServiceStatus(const printInfoStruct& printInfo) 
177 {
178         if (debug)
179                 wcout << L"Opening SC Manager" << endl;
180
181         SC_HANDLE service_api = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
182         if (service_api == NULL)
183                 goto die;
184
185         LPBYTE lpServices = NULL;
186         DWORD cbBufSize = 0;
187         DWORD pcbBytesNeeded = NULL, ServicesReturned = NULL, ResumeHandle = NULL;
188
189         if (debug)
190                 wcout << L"Creating service info structure" << endl;
191
192         if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
193                 lpServices, cbBufSize, &pcbBytesNeeded, &ServicesReturned, &ResumeHandle, NULL)
194                 && GetLastError() != ERROR_MORE_DATA) 
195                 goto die;
196
197         lpServices = reinterpret_cast<LPBYTE>(new BYTE[pcbBytesNeeded]);
198         cbBufSize = pcbBytesNeeded;
199
200         if (!EnumServicesStatusEx(service_api, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
201                 lpServices, cbBufSize, &pcbBytesNeeded, &ServicesReturned, &ResumeHandle, NULL))
202                 goto die;
203
204         LPENUM_SERVICE_STATUS_PROCESS pInfo = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;
205     
206         if (debug)
207                 wcout << L"Traversing services" << endl;
208
209         for (DWORD i = 0; i < ServicesReturned; i++) {
210                 if (debug)
211                         wcout << L"Comparing " << pInfo[i].lpServiceName << L" to " << printInfo.service << endl;
212
213                 if (!wcscmp(printInfo.service.c_str(), pInfo[i].lpServiceName)) {
214                         if (debug)
215                                 wcout << L"Service " << pInfo[i].lpServiceName << L" = " << printInfo.service << ". Returning" << endl;
216
217                         int state = pInfo[i].ServiceStatusProcess.dwCurrentState;
218                         delete lpServices;
219                         return state;
220                 }
221         }
222         delete[] reinterpret_cast<LPBYTE>(lpServices);
223         return 0;
224
225 die:
226         die();
227         if (lpServices)
228                 delete[] reinterpret_cast<LPBYTE>(lpServices);
229         return -1;
230 }