CERTIFICATE RETRIEVAL

STATUS OF THIS MEMO

INTRODUCTION

PROTOCOL

SECURITY ISSUES

SIMILAR SERVICES

COMMAND LINES AND REPLIES





BEGIN CERTIFICATE



END CERTIFICATE



EXAMPLE CODE


/*
   Copyright Jeremey Barrett 2004 for CAcert.org
   You may create derivative works, as long as this copyright notice remains at the top
*/

/*
   Example finger daemon that can return certificates from a database. 
   Currently only tested on debian stable. 
   use the following command to build program
   gcc -o cacert-finger cacert-finger.c -I/usr/include/mysql -L/usr/lib \
                -lmysqlclient -lz -DUSE_MYSQL
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>

#ifdef USE_MYSQL
#include <mysql.h>
#endif

#ifdef USE_MYSQL
static MYSQL mysql_db;
#endif

#define DEFAULT_PORT    79

#define EMAIL_QUERY   "select CRT from certs where `EMAIL`='%s' and \
                        `revoked`='0000-00-00 00:00:00'"
#define DOMAIN_QUERY  "select CRT from domaincerts where \
                        `revoked`='0000-00-00 00:00:00' and `CN`='%s'"
#define WILD_DOMAIN_QUERY  "select CRT from domaincerts where \ 
                `revoked`='0000-00-00 00:00:00' and (`CN`='%s' OR  `CN`='%s')"

void err_exit(void)
  {
    perror("");
    exit(1);
  }


#ifdef USE_MYSQL
void do_mysql(int client_fd, char *query)
  {
    MYSQL_RES *res;
    MYSQL_ROW  row;
    char *cert;

    if(!(mysql_real_connect(&mysql_db, "host", "username", "password",
                "database", 0, "/var/run/mysqld/mysqld.sock", 0) != NULL))
        {
                printf(mysql_error(&mysql_db));
                exit(1);
        }
    
    if(mysql_real_query(&mysql_db, query, strlen(query)))
      goto _err_return;

    res = mysql_store_result(&mysql_db);
    if(mysql_num_rows(res) > 0)
    {
    row = mysql_fetch_row(res);

    if(!row[0])
      goto _free_res_return;

    cert = strstr(row[0], "-----BEGIN CERTIFICATE");
    if(cert) {
      char *response;
      int   response_len = strlen(cert)+2;

      response = (char *)calloc(1, response_len+1);
      if(!response)
        goto _free_res_return;
      memcpy(response, cert, response_len-2);
      response[response_len-2] = '\r';
      response[response_len-1] = '\n';
      
      /* should be checked for errors, more writing */
      write(client_fd, response, response_len); 

      free(response);
    } }

  _free_res_return:
    mysql_free_result(res);

  _err_return:
    mysql_close(&mysql_db);
  }
#endif


int read_line(int fd, char *buf, int size)
  {
    int n = 0;
    int t = 0;
    char *p;
    char *q;

    for(; t < size; )  {
      n = read(fd, buf+t, size-t);
      if(n < 0) {
        switch(errno) {
          case EINTR:
            continue;

          default:
            return -1;
        }
      }

      if(n == 0) {
        return t;
      }

      if(t)
        p = buf+t-1;
      else
        p = buf;

      for(; *p && *p != '\n' && *p != '\r'; p++);

      if(*p) {
        *p = 0;
        t = p-buf;
        return t;
      }
        
      t += n;
    }

    return -1;
  }


int handle_request(int fd)
  {
    char *buf;
    int   buf_size;
    int   len;
    int   i;
    int   email_query = 0;
    char  query[4096]; /* ugly */
    char *email = NULL;
    char *domain = NULL;
    char *wildcard = NULL;

    buf_size = 2048;

    buf = (char *)calloc(1, buf_size);
    if(!buf)
      return -1;

    if((len = read_line(fd, buf, buf_size-1)) <= 0)
      goto _free_return;

    memset(buf+len, 0, buf_size-len);

    if(strchr(buf, '@')) {
      email_query = 1;
      email = buf;
    }
    else {
      char *p;
      char *q;

      p = strchr(buf, '.');
      if(p) {
        q = strchr(p+1, '.');
        if(q) {
          wildcard = (char *)calloc(1, strlen(p)+2);
          if(wildcard) {
            *wildcard = '*';
            memcpy(wildcard+1, p, strlen(p));
          }
        }
      }

      domain = buf;
    }

    memset(query, 0, sizeof(query));

    if(email_query) {
      snprintf(query, sizeof(query)-2, EMAIL_QUERY, email);
    }
    else {
      if(wildcard && strcmp(wildcard, domain))
        snprintf(query, sizeof(query)-2, WILD_DOMAIN_QUERY, domain, wildcard);
      else
        snprintf(query, sizeof(query)-2, DOMAIN_QUERY, domain);

      if(wildcard)
        free(wildcard);
    }


    /* go and do MySQL stuff here */

#ifdef USE_MYSQL
    do_mysql(fd, query);
#else
    strcat(query, "\n");
    write(fd, query, strlen(query));
#endif


  _free_return:
    free(buf);
    return 0;
  }


int main(int argc, char **argv)
  {
    struct sockaddr_in server_sock;
    struct sockaddr_in client_sock;
    int client_addr_size;
    int server_fd = -1;
    int client_fd = -1;
    int pid;

    /* take command line args, e.g. -p <port>, later */

    if ((pid=fork()) < 0)
    {
        perror ("Fork failed");
        exit(errno);


    }

    if (pid)
    {
        exit(0);
    }

    server_fd = socket(PF_INET, SOCK_STREAM, 0);
    if(server_fd < 0)
      err_exit();
    
    memset(&server_sock, 0, sizeof(server_sock));

    server_sock.sin_family = AF_INET;
    server_sock.sin_addr.s_addr = INADDR_ANY;
    server_sock.sin_port = htons(DEFAULT_PORT);
    
    if(bind(server_fd, (struct sockaddr *)&server_sock,
                                sizeof(struct sockaddr_in)) < 0)
      err_exit();

    if(listen(server_fd, 64) < 0)
      err_exit();

    setgid(65534);
    setuid(65534);

    for(;;) {
      memset(&client_sock, 0, sizeof(client_sock));
      client_addr_size = sizeof(client_sock);

      client_fd = accept(server_fd,
                (struct sockaddr *)&client_sock, &client_addr_size);
      if(client_fd < 0)
        err_exit();

      if(handle_request(client_fd) < 0)
        break;

      close(client_fd);
      client_fd = -1;
    }

    if(client_fd >= 0)
      close(client_fd);

    close(server_fd);

    exit(0);
  }

CertificateRetrieval (last edited 2008-08-27 11:10:08 by PhilippGuehring)