Initial version.
authorLadislav Láska <ladislav.laska@gmail.com>
Mon, 11 Oct 2010 12:58:04 +0000 (14:58 +0200)
committerLadislav Láska <ladislav.laska@gmail.com>
Mon, 11 Oct 2010 12:58:04 +0000 (14:58 +0200)
Makefile [new file with mode: 0644]
Makefile.depend [new file with mode: 0644]
main.c [new file with mode: 0644]
tags [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..aa1daef
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+CFLAGS=-Wall -pedantic --std=c99 -lgnutls
+
+
+all:   cert-checker test
+
+cert-checker: main.o
+       gcc $(CFLAGS) -o $@ $^
+
+depend:
+       gcc $(CFLAGS) -MM *.c > Makefile.depend
+
+-include: Makefile.depend
+
+test:
+       ./cert-checker localhost:5556
+
+.PHONY: clean
+
+clean:
+       rm -f cert-checker *.o
diff --git a/Makefile.depend b/Makefile.depend
new file mode 100644 (file)
index 0000000..b8c24d2
--- /dev/null
@@ -0,0 +1 @@
+main.o: main.c
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..68f50e5
--- /dev/null
+++ b/main.c
@@ -0,0 +1,246 @@
+/******************************************************************************
+ * Filename: main.c
+ * Description:
+ *
+ * Version: 1.0
+ * Created: Oct 09 2010 19:14:12
+ * Last modified: Oct 09 2010 19:14:12
+ *
+ * Author: Ladislav Láska
+ * e-mail: ladislav.laska@gmail.com
+ *
+ ******************************************************************************/
+
+#define _XOPEN_SOURCE 500
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <signal.h>
+
+#define S_UNREACHABLE -1
+#define S_NO_X509 -2
+#define S_OK 0
+#define S_WARNING 1
+#define S_ERROR 2
+#define S_UNKNOWN 3
+
+int warning_after = 30;
+int error_after = 7;
+
+#define LOG_LEVEL 0
+
+#define die(msg) { fprintf(stderr, "Error: " msg "\n" ); exit(3); }
+#define gnutls_die(code) { gnutls_perror(code); exit(3); }
+
+char errmsg[256];
+
+void print_help();
+
+int tcp_open( char *hostname, char *service ) {
+       struct addrinfo hints;
+       struct addrinfo *result, *result_ptr;
+       int err, sfd;
+
+       /* Set hints */
+       memset(&hints, 0, sizeof(struct addrinfo));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       err = getaddrinfo(hostname, service, &hints, &result);
+       if (err) {
+               fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
+               exit(3);
+       }
+
+       for (result_ptr = result; result_ptr != NULL; result_ptr = result_ptr->ai_next) {
+               sfd = socket(result_ptr->ai_family, result_ptr->ai_socktype,
+                                               result_ptr->ai_protocol);
+               if (sfd == -1) continue; 
+
+               if (connect(sfd, result_ptr->ai_addr, result_ptr->ai_addrlen) != -1)
+                       break; /* Success */
+               
+               close(sfd);     /* connect(2) failed. */
+       }
+
+       if (result_ptr == NULL) {
+               /* No address succeeded */
+               return -1;
+       }
+
+       freeaddrinfo(result);
+
+       return sfd;
+}
+
+int check( char * hostname, char *service ) {
+       int state = S_OK;
+       int err;
+
+       gnutls_session_t session;
+       gnutls_certificate_credentials_t xcred;
+
+       /* x509 stuff */
+       
+       err = gnutls_certificate_allocate_credentials( &xcred );
+       if (err < 0) gnutls_die(err);
+
+       err = gnutls_init( &session, GNUTLS_CLIENT );
+       if (err < 0) gnutls_die(err);
+
+       /* priority init? */
+       err = gnutls_priority_set_direct(session, "EXPORT", NULL);
+       if (err < 0) gnutls_die(err);
+
+       err = gnutls_credentials_set( session, GNUTLS_CRD_CERTIFICATE, xcred );
+       if (err < 0) gnutls_die(err);
+
+       /* Connect to server */
+
+       int fd = tcp_open( hostname, service );
+       
+       if (fd == -1) {
+               state= S_UNREACHABLE;
+               goto cleanup;
+       }
+
+       /* Socket opened, establish tls connection */
+
+       /* Associate socket with session */
+       gnutls_transport_set_ptr( session, (gnutls_transport_ptr_t) fd );
+       
+       /* Do handshake */
+       err = gnutls_handshake( session );
+       if (err < 0) gnutls_die(err);
+       
+       /* Get server certificate. */
+       const gnutls_datum_t *cert_list;
+       unsigned int cert_list_size = 0;
+       time_t expiration_time, today;
+       gnutls_x509_crt_t cert;
+
+       if ( gnutls_certificate_type_get( session ) != GNUTLS_CRT_X509 ) {
+               state = S_NO_X509;
+               goto cleanup;
+       }
+
+       cert_list = gnutls_certificate_get_peers( session, &cert_list_size );
+
+       today = time(NULL);
+
+       for (int i = 0; i < cert_list_size; i++) {
+               gnutls_x509_crt_init( &cert );
+               gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER );
+               expiration_time = gnutls_x509_crt_get_expiration_time( cert );
+               int expires_in = (expiration_time - today) / 86400;
+               if ((state == S_OK) && (expires_in <= warning_after)) {
+                       state = S_WARNING;
+                       sprintf(errmsg, "Certificate will expire in %i days.", expires_in);
+               }
+               if ((state <= S_WARNING) && (expires_in <= error_after)) {
+                       state = S_ERROR;
+                       sprintf(errmsg, "Certificate will expire in %i days.", expires_in);
+               }
+       }
+
+       printf("Got %i certs.", cert_list_size);
+
+       /* Clean up */
+       err = gnutls_bye( session, GNUTLS_SHUT_WR );
+       if (err < 0) gnutls_die(err);
+       close( fd );
+       cleanup:
+       gnutls_deinit( session );
+       gnutls_certificate_free_credentials( xcred );
+
+       return state;
+}
+
+void log_func( int level, char *msg ) {
+       fprintf(stderr, "[%2i] %s", level, msg);
+}
+
+/* 
+ * This signal handler is wrong, but it's just a failsafe. 
+ */
+void sig_handler(int k) {
+       fputs("Timeout.", stderr);      
+       exit(S_UNKNOWN);
+}
+
+int main(int argc, char **argv) {
+       char *hostname;
+       char *service = NULL;
+
+       int opt;
+
+       while ((opt = getopt(argc, argv, "hvw:c:H:p:s:")) != -1) {
+               switch (opt) {
+                       case 'w':
+                               warning_after = atoi(optarg);
+                               break;
+                       case 'c':
+                               error_after = atoi(optarg);
+                               break;
+                       case 'H':
+                               hostname = strdup(optarg);
+                               break;
+                       case 'p':                       
+                       case 's':
+                               if (service != NULL) die("Only one service can be specified.");
+                               service = strdup(optarg);
+                               break;
+                       case 'h':
+                               print_help();
+                               exit(0);
+                       default: break;
+               }
+       }
+
+       if (argc <= 1) die("No address to try.");
+
+       gnutls_global_set_log_function((gnutls_log_func) log_func);
+       gnutls_global_set_log_level(LOG_LEVEL);
+
+
+       /* Initialize gnutls */
+       int err;
+       if ((err = gnutls_global_init())) {
+               gnutls_perror(err);
+               exit(3);
+       };
+
+       sprintf(errmsg, "OK");
+       int state = 0;
+
+       fflush(stdout);
+
+       /* Setup alarm */
+       /* TODO: doesn't work. */
+       signal(SIGALRM, sig_handler);
+       alarm(9*60);
+
+       /* Do checking */
+       state = check(hostname, service);
+       if (state < 0)
+               printf("Internal error.");
+       
+       gnutls_global_deinit();
+
+       free(hostname);
+       free(service);
+
+       printf("%s\n", errmsg);
+       return (state < 0) ? 127 : state;
+}
+
+void print_help() {
+       printf("Help yourself.");
+}
diff --git a/tags b/tags
new file mode 100644 (file)
index 0000000..4c916a1
--- /dev/null
+++ b/tags
@@ -0,0 +1,12 @@
+!_TAG_FILE_FORMAT      2       /extended format; --format=1 will not append ;" to lines/
+!_TAG_FILE_SORTED      1       /0=unsorted, 1=sorted, 2=foldcase/
+!_TAG_PROGRAM_AUTHOR   Darren Hiebert  /dhiebert@users.sourceforge.net/
+!_TAG_PROGRAM_NAME     Exuberant Ctags //
+!_TAG_PROGRAM_URL      http://ctags.sourceforge.net    /official site/
+!_TAG_PROGRAM_VERSION  5.8     //
+CFLAGS Makefile        /^CFLAGS=-Wall -pedantic --std=c99 -lgnutls$/;" m
+_XOPEN_SOURCE  main.c  14;"    d       file:
+check  main.c  /^int check( char * hostname, int port ) {$/;"  f       signature:( char * hostname, int port )
+die    main.c  25;"    d       file:
+main   main.c  /^int main(int argc, char **argv) {$/;" f       signature:(int argc, char **argv)
+tcp_open       main.c  /^int tcp_open( char *hostname, int port ) {$/;"        f       signature:( char *hostname, int port )