Back to index

courier  0.68.2
Defines | Functions
tlsclient.c File Reference
#include "config.h"
#include "numlib/numlib.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <sys/time.h>
#include "tlsclient.h"

Go to the source code of this file.

Defines

#define dirent   direct
#define NAMLEN(dirent)   (dirent)->d_namlen
#define WEXITSTATUS(stat_val)   ((unsigned)(stat_val) >> 8)
#define WIFEXITED(stat_val)   (((stat_val) & 255) == 0)
#define ERRMSG(s)
#define SYSERRMSG

Functions

void couriertls_init (struct couriertls_info *cinfo)
static int do_couriertls_start (char **, struct couriertls_info *)
int couriertls_start (char **args, struct couriertls_info *cinfo)
const char * couriertls_get_subject (struct couriertls_info *cinfo, const char *subject)
void couriertls_export_subject_environment (struct couriertls_info *cinfo)
void couriertls_destroy (struct couriertls_info *info)

Define Documentation

#define dirent   direct

Definition at line 16 of file tlsclient.c.

#define ERRMSG (   s)
Value:
(cinfo->errmsg[0]=0, \
              strncat(cinfo->errmsg, (s), sizeof(cinfo->errmsg)-3))

Definition at line 56 of file tlsclient.c.

#define NAMLEN (   dirent)    (dirent)->d_namlen

Definition at line 17 of file tlsclient.c.

#define SYSERRMSG
Value:
(strncat(strcpy(cinfo->errmsg, "Failed: "), \
              strerror(errno), sizeof(cinfo->errmsg)-15))

Definition at line 59 of file tlsclient.c.

#define WEXITSTATUS (   stat_val)    ((unsigned)(stat_val) >> 8)

Definition at line 46 of file tlsclient.c.

#define WIFEXITED (   stat_val)    (((stat_val) & 255) == 0)

Definition at line 49 of file tlsclient.c.


Function Documentation

void couriertls_destroy ( struct couriertls_info info)

Definition at line 486 of file tlsclient.c.

{
       struct tls_subject *subj;
       struct tls_subjitem *subjitem;

       if (info->x509info)
              free(info->x509info);

       while ((subj=info->first_subject) != 0)
       {
              info->first_subject=subj->next;
              while ((subjitem=subj->firstitem) != 0)
              {
                     subj->firstitem=subjitem->nextitem;
                     free(subjitem);
              }
              free(subj);
       }
}

Here is the caller graph for this function:

Definition at line 253 of file tlsclient.c.

{
       struct tls_subject *subj;
       struct tls_subjitem *item;

       if ((subj=cinfo->first_subject) == 0)
              return;

       for (item=subj->firstitem; item; item=item->nextitem)
       {
              char *a=malloc(strlen(item->name)+20);
              const char *b=item->value;
              char *p;

              if (!a) continue;

              strcat(strcpy(a, "TLS_SUBJECT_"), item->name);

              for (p=a; *p; p++)
                     if (*p >= 'a' && *p <= 'z')
                            *p -= 'a' - 'A';

              setenv(a, b, 1);
              free(a);
       }
}

Here is the caller graph for this function:

const char* couriertls_get_subject ( struct couriertls_info cinfo,
const char *  subject 
)

Definition at line 207 of file tlsclient.c.

{
       struct tls_subject *subj;
       struct tls_subjitem *item, *p;

       if ((subj=cinfo->first_subject) == 0)
              return NULL;

       p=NULL;

       for (item=subj->firstitem; item; item=item->nextitem)
       {
              const char *a=item->name;
              const char *b=subject;

              while (*a && *b)
              {
                     int ca= *a++;
                     int cb= *b++;

                     /* Locale muddies things up, do this by hand */

                     if (ca >= 'a' && ca <= 'z')
                            ca -= 'a' - 'A';

                     if (cb >= 'a' && cb <= 'z')
                            cb -= 'a' - 'A';

                     if (ca != cb)
                            break;
              }

              if (!*a && !*b)
                     p=item;
              /*
              ** We want the last one, to match the behavior when couriertls
              ** passes this stuff via the environment.
              */
       }

       if (p)
              return p->value;
       return (0);
}

Here is the call graph for this function:

void couriertls_init ( struct couriertls_info cinfo)

Definition at line 62 of file tlsclient.c.

{
       memset(cinfo, 0, sizeof(*cinfo));
       cinfo->cipher=cinfo->version="Unknown";
}

Here is the caller graph for this function:

int couriertls_start ( char **  args,
struct couriertls_info cinfo 
)

Definition at line 75 of file tlsclient.c.

{
       int rc=do_couriertls_start(args, cinfo);
       int l;
       char *p;

       if (rc && cinfo->errmsg[0] == 0)
              strcpy(cinfo->errmsg, "Failed to initialize TLS/SSL\n");

       l=strlen(cinfo->errmsg);

       while (l > 0 && cinfo->errmsg[l-1] == '\n')
              --l;
       cinfo->errmsg[l]=0;

       if (rc || cinfo->x509info == 0)
              return (rc);

       cinfo->x509info[cinfo->x509info_len]=0;
       p=strtok(cinfo->x509info, "\r\n");

       while (p)
       {
              int i;

              for (i=0; p[i]; i++)
                     if (!isalpha(p[i]))
                            break;

              if (p[i] != ':')
              {
                     p=strtok(NULL, "\r\n");
                     continue;
              }
              p[i++]=0;

              /*
              ** IMPORTANT: UCase *MUST* match the output of couriertls.
              ** I'd love to use strcasecmp, here, but certain glibc
              ** locale break the standard case of lower ascii chset
              ** range.
              */

              if (strcmp(p, "Subject") == 0)
              {
                     struct tls_subject *subj, *subj2;
                     struct tls_subjitem **itemptr;

                     p += i;

                     for (subj=cinfo->first_subject; subj && subj->next;
                          subj=subj->next)
                            ;

                     subj2=(struct tls_subject *)
                            malloc(sizeof(struct tls_subject));
                     if (!subj2)
                     {
                            SYSERRMSG;
                            return (-1);
                     }

                     if (subj)
                            subj->next=subj2;
                     else
                            cinfo->first_subject=subj2;

                     subj2->next=0;
                     subj2->firstitem=0;
                     itemptr= &subj2->firstitem;

                     while ( p && (*p == 0
                                  || isspace((int)(unsigned char)*p)))
                     {
                            while (*p && isspace((int)(unsigned char)*p))
                                   ++p;
                            for (i=0; p[i]; i++)
                                   if (!isalpha((int)(unsigned char)p[i]))
                                          break;
                            if (p[i] != '=')
                            {
                                   p=strtok(NULL, "\r\n");
                                   continue;
                            }
                            p[i++]=0;

                            *itemptr= (struct tls_subjitem *)
                                   malloc(sizeof (struct tls_subjitem));

                            if (!*itemptr)
                            {
                                   SYSERRMSG;
                                   return (-1);
                            }

                            (*itemptr)->name=p;
                            (*itemptr)->value=p+i;
                            (*itemptr)->nextitem=0;

                            itemptr= &(*itemptr)->nextitem;
                            p=strtok(NULL, "\r\n");
                     }
                     continue;
              }

              if (strcmp(p, "Cipher") == 0)
              {
                     p += i;
                     while (*p && isspace((int)(unsigned char)*p))
                            ++p;
                     cinfo->cipher=p;
              }
              else if (strcmp(p, "Version") == 0)
              {
                     p += i;
                     while (*p && isspace((int)(unsigned char)*p))
                            ++p;
                     cinfo->version=p;
              }
              else if (strcmp(p, "Bits") == 0)
              {
                     p += i;
                     while (*p && isspace((int)(unsigned char)*p))
                            ++p;
                     cinfo->bits=atoi(p);
              }
              p=strtok(NULL, "\r\n");
       }

       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int do_couriertls_start ( char **  args,
struct couriertls_info cinfo 
) [static]

Definition at line 280 of file tlsclient.c.

{
       pid_t p, p2;
       int waitstat;
       char **argvec;
       int nargs;
       char readbuf[BUFSIZ];
       fd_set fdr;
       int statuspipe_fd[2];
       int x509_fd[2];


       /* Create the pipes, and run couriertls */

       for (nargs=0; args[nargs]; nargs++)
              ;

       argvec=malloc(sizeof(char *)*(nargs+10));
       if (!argvec)
       {
              SYSERRMSG;
              return (-1);
       }

       if (pipe(statuspipe_fd) < 0)
       {
              free(argvec);
              SYSERRMSG;
              return (-1);
       }

       if (pipe(x509_fd) < 0)
       {
              close(statuspipe_fd[0]);
              close(statuspipe_fd[1]);
              free(argvec);
              SYSERRMSG;
              return (-1);
       }

       if ((p=fork()) < 0)
       {
              close(x509_fd[0]);
              close(x509_fd[1]);
              close(statuspipe_fd[0]);
              close(statuspipe_fd[1]);
              free(argvec);
              SYSERRMSG;
              return (-1);
       }

       /* Child process starts another child process, which runs couriertls */

       if (p == 0)
       {
              static const char msg[]="500 Unable to start couriertls - insufficient resources.\n";

              FILE *fp;
              char miscbuf[NUMBUFSIZE];
              char statusfd_buf[NUMBUFSIZE+40];
              char x509fd_buf[NUMBUFSIZE+40];
              const char *s;

              close(statuspipe_fd[0]);
              close(x509_fd[0]);

              fp=fdopen(statuspipe_fd[1], "w");

              if (!fp)
              {
                     if (write(statuspipe_fd[1], msg, sizeof(msg)-1) < 0)
                            ; /* Ignore */
                     exit(0);
              }

              if ((p=fork()) != 0)
              {
                     if (p < 0)
                     {
                            fprintf(fp,
                                   "500 Unable to start couriertls: %s\n",
                                   strerror(errno));
                            fflush(fp);
                     }
                     exit(0);
              }

              argvec[0]="couriertls";
              argvec[1]=strcat(strcpy(statusfd_buf, "-statusfd="),
                             libmail_str_size_t(statuspipe_fd[1], miscbuf));
              argvec[2]=strcat(strcpy(x509fd_buf, "-printx509="),
                             libmail_str_size_t(x509_fd[1], miscbuf));
              for (nargs=0; (argvec[nargs+3]=args[nargs]) != 0; nargs++)
                     ;

              s=getenv("COURIERTLS");
              if (!s || !*s)
                     s="couriertls";

              execv(s, argvec);
              fprintf(fp, "500 Unable to start couriertls: %s\n",
                     strerror(errno));
              fflush(fp);
              exit(0);
       }

       /* The parent wait for the first child to exit */

       close(statuspipe_fd[1]);
       close(x509_fd[1]);

       while ((p2=wait(&waitstat)) != p)
              if (p2 < 0 && errno == ECHILD)
                     break;

       if (p2 != p || !WIFEXITED(waitstat) || WEXITSTATUS(waitstat))
       {
              close(statuspipe_fd[0]);
              close(x509_fd[0]);
              ERRMSG("500 Error starting couriertls.");
              return (-1);
       }

       /* Now, we need to read from two pipes simultaneously, and save the
       ** results.
       */

       while (statuspipe_fd[0] >= 0 || x509_fd[0] >= 0)
       {
              FD_ZERO(&fdr);
              if (statuspipe_fd[0] >= 0)
                     FD_SET(statuspipe_fd[0], &fdr);
              if (x509_fd[0] >= 0)
                     FD_SET(x509_fd[0], &fdr);
              if (select( (statuspipe_fd[0] > x509_fd[0] ?
                          statuspipe_fd[0]:x509_fd[0])+1,
                         &fdr, NULL, NULL, NULL) < 0)
              {
                     close(statuspipe_fd[0]);
                     close(x509_fd[0]);
                     SYSERRMSG;
                     return (-1);
              }

              if (statuspipe_fd[0] >= 0 && FD_ISSET(statuspipe_fd[0], &fdr))
              {
                     int n=read(statuspipe_fd[0], readbuf,
                               sizeof(readbuf)-1);

                     if (n <= 0)
                     {
                            close(statuspipe_fd[0]);
                            statuspipe_fd[0]= -1;
                     }
                     else
                     {
                            int l=strlen(cinfo->errmsg);

                            readbuf[n]=0;
                            if (l < sizeof(cinfo->errmsg)-2)
                                   strncat(cinfo->errmsg, readbuf,
                                          sizeof(cinfo->errmsg)-2-l);
                     }
              }

              if (x509_fd[0] >= 0 && FD_ISSET(x509_fd[0], &fdr))
              {
                     int n=read(x509_fd[0], readbuf, sizeof(readbuf));

                     if (n <= 0)
                     {
                            close(x509_fd[0]);
                            x509_fd[0]= -1;
                     }
                     else
                     {
                            if (n + cinfo->x509info_len >=
                                cinfo->x509info_size)
                            {
                                   size_t news=n+cinfo->x509info_len
                                          + 1024;
                                   char *newp= cinfo->x509info ?
                                          realloc(cinfo->x509info, news)
                                          : malloc(news);

                                   if (!newp)
                                   {
                                          SYSERRMSG;
                                          close(x509_fd[0]);
                                          x509_fd[0]= -1;
                                          continue;
                                   }
                                   cinfo->x509info=newp;
                                   cinfo->x509info_size=news;
                            }

                            memcpy(cinfo->x509info + cinfo->x509info_len,
                                   readbuf, n);
                            cinfo->x509info_len += n;
                     }
              }

       }
       return (cinfo->errmsg[0] ? -1:0);
}

Here is the call graph for this function:

Here is the caller graph for this function: