Fix for SSL Versioning when multiple options are used.
[monitoring-plugins.git] / plugins / check_ldap.c
blob4717885aca309d38674a5b3e88317df83737e0a8
1 /*****************************************************************************
2 *
3 * Nagios check_ldap plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000-2008 Nagios Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_ldap plugin
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *****************************************************************************/
29 /* progname may be check_ldaps */
30 char *progname = "check_ldap";
31 const char *copyright = "2000-2008";
32 const char *email = "devel@nagios-plugins.org";
34 #include "common.h"
35 #include "netutils.h"
36 #include "utils.h"
38 #include <lber.h>
39 #define LDAP_DEPRECATED 1
40 #include <ldap.h>
42 enum {
43 UNDEFINED = 0,
44 #ifdef HAVE_LDAP_SET_OPTION
45 DEFAULT_PROTOCOL = 2,
46 #endif
47 DEFAULT_PORT = 389
50 int process_arguments (int, char **);
51 int validate_arguments (void);
52 void print_help (void);
53 void print_usage (void);
55 char ld_defattr[] = "(objectclass=*)";
56 char *ld_attr = ld_defattr;
57 char *ld_host = NULL;
58 char *ld_base = NULL;
59 char *ld_passwd = NULL;
60 char *ld_binddn = NULL;
61 int ld_port = -1;
62 #ifdef HAVE_LDAP_SET_OPTION
63 int ld_protocol = DEFAULT_PROTOCOL;
64 #endif
65 #ifndef LDAP_OPT_SUCCESS
66 # define LDAP_OPT_SUCCESS LDAP_SUCCESS
67 #endif
68 double warn_time = UNDEFINED;
69 double crit_time = UNDEFINED;
70 struct timeval tv;
71 int starttls = FALSE;
72 int ssl_on_connect = FALSE;
73 int verbose = 0;
75 /* for ldap tls */
77 char *SERVICE = "LDAP";
79 int
80 main (int argc, char *argv[])
83 LDAP *ld;
84 LDAPMessage *result;
86 /* should be int result = STATE_UNKNOWN; */
88 int status = STATE_UNKNOWN;
89 long microsec;
90 double elapsed_time;
92 /* for ldap tls */
94 int tls;
95 int version=3;
97 setlocale (LC_ALL, "");
98 bindtextdomain (PACKAGE, LOCALEDIR);
99 textdomain (PACKAGE);
101 if (strstr(argv[0],"check_ldaps")) {
102 xasprintf (&progname, "check_ldaps");
105 /* Parse extra opts if any */
106 argv=np_extra_opts (&argc, argv, progname);
108 if (process_arguments (argc, argv) == ERROR)
109 usage4 (_("Could not parse arguments"));
111 if (strstr(argv[0],"check_ldaps") && ! starttls && ! ssl_on_connect)
112 starttls = TRUE;
114 /* initialize alarm signal handling */
115 signal (SIGALRM, socket_timeout_alarm_handler);
117 /* set socket timeout */
118 alarm (socket_timeout);
120 /* get the start time */
121 gettimeofday (&tv, NULL);
123 /* initialize ldap */
124 #ifdef HAVE_LDAP_INIT
125 if (!(ld = ldap_init (ld_host, ld_port))) {
126 printf ("Could not connect to the server at port %i\n", ld_port);
127 return STATE_CRITICAL;
129 #else
130 if (!(ld = ldap_open (ld_host, ld_port))) {
131 if (verbose)
132 ldap_perror(ld, "ldap_open");
133 printf (_("Could not connect to the server at port %i\n"), ld_port);
134 return STATE_CRITICAL;
136 #endif /* HAVE_LDAP_INIT */
138 #ifdef HAVE_LDAP_SET_OPTION
139 /* set ldap options */
140 if (ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &ld_protocol) !=
141 LDAP_OPT_SUCCESS ) {
142 printf(_("Could not set protocol version %d\n"), ld_protocol);
143 return STATE_CRITICAL;
145 #endif
147 if (ld_port == LDAPS_PORT || ssl_on_connect) {
148 xasprintf (&SERVICE, "LDAPS");
149 #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
150 /* ldaps: set option tls */
151 tls = LDAP_OPT_X_TLS_HARD;
153 if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
155 if (verbose)
156 ldap_perror(ld, "ldaps_option");
157 printf (_("Could not init TLS at port %i!\n"), ld_port);
158 return STATE_CRITICAL;
160 #else
161 printf (_("TLS not supported by the libraries!\n"));
162 return STATE_CRITICAL;
163 #endif /* LDAP_OPT_X_TLS */
164 } else if (starttls) {
165 xasprintf (&SERVICE, "LDAP-TLS");
166 #if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
167 /* ldap with startTLS: set option version */
168 if (ldap_get_option(ld,LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS )
170 if (version < LDAP_VERSION3)
172 version = LDAP_VERSION3;
173 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
176 /* call start_tls */
177 if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS)
179 if (verbose)
180 ldap_perror(ld, "ldap_start_tls");
181 printf (_("Could not init startTLS at port %i!\n"), ld_port);
182 return STATE_CRITICAL;
184 #else
185 printf (_("startTLS not supported by the library, needs LDAPv3!\n"));
186 return STATE_CRITICAL;
187 #endif /* HAVE_LDAP_START_TLS_S */
190 /* bind to the ldap server */
191 if (ldap_bind_s (ld, ld_binddn, ld_passwd, LDAP_AUTH_SIMPLE) !=
192 LDAP_SUCCESS) {
193 if (verbose)
194 ldap_perror(ld, "ldap_bind");
195 printf (_("Could not bind to the LDAP server\n"));
196 return STATE_CRITICAL;
199 /* do a search of all objectclasses in the base dn */
200 if (ldap_search_s (ld, ld_base, LDAP_SCOPE_BASE, ld_attr, NULL, 0, &result)
201 != LDAP_SUCCESS) {
202 if (verbose)
203 ldap_perror(ld, "ldap_search");
204 printf (_("Could not search/find objectclasses in %s\n"), ld_base);
205 return STATE_CRITICAL;
208 /* unbind from the ldap server */
209 ldap_unbind (ld);
211 /* reset the alarm handler */
212 alarm (0);
214 /* calcutate the elapsed time and compare to thresholds */
216 microsec = deltime (tv);
217 elapsed_time = (double)microsec / 1.0e6;
219 if (crit_time!=UNDEFINED && elapsed_time>crit_time)
220 status = STATE_CRITICAL;
221 else if (warn_time!=UNDEFINED && elapsed_time>warn_time)
222 status = STATE_WARNING;
223 else
224 status = STATE_OK;
226 /* print out the result */
227 printf (_("LDAP %s - %.3f seconds response time|%s\n"),
228 state_text (status),
229 elapsed_time,
230 fperfdata ("time", elapsed_time, "s",
231 (int)warn_time, warn_time,
232 (int)crit_time, crit_time,
233 TRUE, 0, FALSE, 0));
235 return status;
238 /* process command-line arguments */
240 process_arguments (int argc, char **argv)
242 int c;
244 int option = 0;
245 /* initialize the long option struct */
246 static struct option longopts[] = {
247 {"help", no_argument, 0, 'h'},
248 {"version", no_argument, 0, 'V'},
249 {"timeout", required_argument, 0, 't'},
250 {"hostname", required_argument, 0, 'H'},
251 {"base", required_argument, 0, 'b'},
252 {"attr", required_argument, 0, 'a'},
253 {"bind", required_argument, 0, 'D'},
254 {"pass", required_argument, 0, 'P'},
255 #ifdef HAVE_LDAP_SET_OPTION
256 {"ver2", no_argument, 0, '2'},
257 {"ver3", no_argument, 0, '3'},
258 #endif
259 {"starttls", no_argument, 0, 'T'},
260 {"ssl", no_argument, 0, 'S'},
261 {"use-ipv4", no_argument, 0, '4'},
262 {"use-ipv6", no_argument, 0, '6'},
263 {"port", required_argument, 0, 'p'},
264 {"warn", required_argument, 0, 'w'},
265 {"crit", required_argument, 0, 'c'},
266 {"verbose", no_argument, 0, 'v'},
267 {0, 0, 0, 0}
270 if (argc < 2)
271 return ERROR;
273 for (c = 1; c < argc; c++) {
274 if (strcmp ("-to", argv[c]) == 0)
275 strcpy (argv[c], "-t");
278 while (1) {
279 c = getopt_long (argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:", longopts, &option);
281 if (c == -1 || c == EOF)
282 break;
284 switch (c) {
285 case 'h': /* help */
286 print_help ();
287 exit (STATE_OK);
288 case 'V': /* version */
289 print_revision (progname, NP_VERSION);
290 exit (STATE_OK);
291 case 't': /* timeout period */
292 if (!is_intnonneg (optarg))
293 usage2 (_("Timeout interval must be a positive integer"), optarg);
294 else
295 socket_timeout = atoi (optarg);
296 break;
297 case 'H':
298 ld_host = optarg;
299 break;
300 case 'b':
301 ld_base = optarg;
302 break;
303 case 'p':
304 ld_port = atoi (optarg);
305 break;
306 case 'a':
307 ld_attr = optarg;
308 break;
309 case 'D':
310 ld_binddn = optarg;
311 break;
312 case 'P':
313 ld_passwd = optarg;
314 break;
315 case 'w':
316 warn_time = strtod (optarg, NULL);
317 break;
318 case 'c':
319 crit_time = strtod (optarg, NULL);
320 break;
321 #ifdef HAVE_LDAP_SET_OPTION
322 case '2':
323 ld_protocol = 2;
324 break;
325 case '3':
326 ld_protocol = 3;
327 break;
328 #endif
329 case '4':
330 address_family = AF_INET;
331 break;
332 case 'v':
333 verbose++;
334 break;
335 case 'T':
336 if (! ssl_on_connect)
337 starttls = TRUE;
338 else
339 usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl");
340 break;
341 case 'S':
342 if (! starttls) {
343 ssl_on_connect = TRUE;
344 if (ld_port == -1)
345 ld_port = LDAPS_PORT;
346 } else
347 usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls");
348 break;
349 case '6':
350 #ifdef USE_IPV6
351 address_family = AF_INET6;
352 #else
353 usage (_("IPv6 support not available\n"));
354 #endif
355 break;
356 default:
357 usage5 ();
361 c = optind;
362 if (ld_host == NULL && is_host(argv[c]))
363 ld_host = strdup (argv[c++]);
365 if (ld_base == NULL && argv[c])
366 ld_base = strdup (argv[c++]);
368 if (ld_port == -1)
369 ld_port = DEFAULT_PORT;
371 return validate_arguments ();
376 validate_arguments ()
378 if (ld_host==NULL || strlen(ld_host)==0)
379 usage4 (_("Please specify the host name\n"));
381 if (ld_base==NULL)
382 usage4 (_("Please specify the LDAP base\n"));
384 return OK;
388 void
389 print_help (void)
391 char *myport;
392 xasprintf (&myport, "%d", DEFAULT_PORT);
394 print_revision (progname, NP_VERSION);
396 printf ("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n");
397 printf (COPYRIGHT, copyright, email);
399 printf ("\n\n");
401 print_usage ();
403 printf (UT_HELP_VRSN);
404 printf (UT_EXTRA_OPTS);
406 printf (UT_HOST_PORT, 'p', myport);
408 printf (UT_IPv46);
410 printf (" %s\n", "-a [--attr]");
411 printf (" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\""));
412 printf (" %s\n", "-b [--base]");
413 printf (" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at"));
414 printf (" %s\n", "-D [--bind]");
415 printf (" %s\n", _("ldap bind DN (if required)"));
416 printf (" %s\n", "-P [--pass]");
417 printf (" %s\n", _("ldap password (if required)"));
418 printf (" %s\n", "-T [--starttls]");
419 printf (" %s\n", _("use starttls mechanism introduced in protocol version 3"));
420 printf (" %s\n", "-S [--ssl]");
421 printf (" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT);
423 #ifdef HAVE_LDAP_SET_OPTION
424 printf (" %s\n", "-2 [--ver2]");
425 printf (" %s\n", _("use ldap protocol version 2"));
426 printf (" %s\n", "-3 [--ver3]");
427 printf (" %s\n", _("use ldap protocol version 3"));
428 printf (" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL);
429 #endif
431 printf (UT_WARN_CRIT);
433 printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
435 printf (UT_VERBOSE);
437 printf ("\n");
438 printf ("%s\n", _("Notes:"));
439 printf (" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be"));
440 printf (_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT);
441 printf (" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
442 printf (" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags"));
443 printf (" %s\n", _("to define the behaviour explicitly instead."));
445 printf (UT_SUPPORT);
448 void
449 print_usage (void)
451 printf ("%s\n", _("Usage:"));
452 printf (" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]",progname);
453 printf ("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
454 #ifdef HAVE_LDAP_SET_OPTION
455 "\n [-2|-3] [-4|-6]"
456 #else
458 #endif