Appendix A Sendmail Supplemental Information

  Table of Contents

  Glossary

  Index

Sendmail Supplemental Information

This appendix includes the following Sendmail information:

Creating a Certificate of Authority

Local SSL certificates can be created using the security software included in the Sendmail subset of Internet Express. To create a local Certificate Authority, use the CA.pl command and fill in the required fields. The Perl script will ask for your site information for creating the Authority and the public and private keys.

# alias openssl=/usr/internet/bin/openssl

# /usr/internet/openssl/misc/CA.pl

Executed in the /var/adm/sendmail directory, the default created directory for this command is demoCA. Using the demoCA directory allows key creation without interfering with the live system resources. The public key is created in cacert.pem and the private key is in private/cakey.pem. The private key is used to sign other SSL certs.

Background - OpenSSL Certificate Creation

OpenSSL is part of the sendmail kit and the command openssl is installed in /usr/internet/ssl/bin directory.

There are two ways to create a certificate authority. One is to follow the command list below. The other is to run the CA.pl command included in the /usr/internet/ssl/misc directory. The CA.pl command steps through the same procedure as listed here.

  1. Create Certificate Authority (CA)

    #
    # mkdir certs crl newcerts private
    # chmod 0700 private
    #
    # echo "01" > serial
    # cp /dev/null index.txt
    #
    # openssl req -new -x509 -keyout  private/cakey.pem -out cacert.pem
  2. Create certificates

    #  umask 0066
    #  openssl req -nodes -new -x509  -keyout key.pem -out newcert.pem
  3. Sign new certificates using CA

    #  openssl x509 -x509toreq -in newcert.pem  -signkey key.pem -out csr.pem
    #  openssl ca -policy policy_anything  -out cert.pem -infiles csr.pem
    # rm -f csr.pem
    # 

Mail Filter Example

This sample code is taken from the sendmail.org distribution, the sendmail/milter/README file:

Note that this filter may not be thread safe on some operating systems. You should check your system man pages for the functions used below to verify the functions are thread safe.

/* A trivial filter that logs all email to a file. */

#include <sts/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>

#include "libmilter/mfapi.h"

#ifndef true
typedef int bool;
# define false  0
# define true   1
#endif /* ! true */

struct mlfiPriv
{
        char    *mlfi_fname;
        FILE    *mlfi_fp;
};

#define MLFIPRIV        ((struct mlfiPriv *) smfi_getpriv(ctx))

extern sfsistat  mlfi_cleanup(SMFICTX *, bool);

sfsistat
mlfi_envfrom(ctx, envfrom)
        SMFICTX *ctx;
        char **envfrom;
{
        struct mlfiPriv *priv;
        int fd = -1;
        /* allocate some private memory */
        priv = malloc(sizeof *priv);
        if (priv == NULL)
        {
                /* can't accept this message right now */
                return SMFIS_TEMPFAIL;
        }
        memset(priv, '\0', sizeof *priv);

        /* open a file to store this message */
        priv->mlfi_fname = strdup("/tmp/msg.XXXXXXXX");
        if (priv->mlfi_fname == NULL)
        {
                free(priv);
                return SMFIS_TEMPFAIL;
        }
        if ((fd = mkstemp(priv->mlfi_fname)) < 0 ||
            (priv->mlfi_fp = fdopen(fd, "w+")) == NULL)
        {
                if (fd >= 0)
                        (void) close(fd);
                free(priv->mlfi_fname);
                free(priv);
                return SMFIS_TEMPFAIL;
        }

        /* save the private data */
        smfi_setpriv(ctx, priv);

        /* continue processing */
        return SMFIS_CONTINUE;
}

sfsistat
mlfi_header(ctx, headerf, headerv)
        SMFICTX *ctx;
        char *headerf;
        char *headerv;
{
        /* write the header to the log file */
        fprintf(MLFIPRIV->mlfi_fp, "%s: %s\r\n", headerf, headerv);

        /* continue processing */
        return SMFIS_CONTINUE;
}

sfsistat
mlfi_eoh(ctx)
        SMFICTX *ctx;
{
        /* output the blank line between the header and the body */
        fprintf(MLFIPRIV->mlfi_fp, "\r\n");

        /* continue processing */
        return SMFIS_CONTINUE;
}

sfsistat
mlfi_body(ctx, bodyp, bodylen)
        SMFICTX *ctx;
        u_char *bodyp;
        size_t bodylen;
{
        /* output body block to log file */
        if (fwrite(bodyp, bodylen, 1, MLFIPRIV->mlfi_fp) <= 0)
        {
                /* write failed */
                (void) mlfi_cleanup(ctx, false);
                return SMFIS_TEMPFAIL;
        }

        /* continue processing */
        return SMFIS_CONTINUE;
}

sfsistat
mlfi_eom(ctx)
        SMFICTX *ctx;
{
        return mlfi_cleanup(ctx, true);
}

Sfsistat
mlfi_close(ctx)
        SMFICTX *ctx;
{
        return SMFIS_ACCEPT;
}

sfsistat
mlfi_abort(ctx)
        SMFICTX *ctx;
{
        return mlfi_cleanup(ctx, false);
}

sfsistat
mlfi_cleanup(ctx, ok)
        SMFICTX *ctx;
        bool ok;
{
        sfsistat rstat = SMFIS_CONTINUE;
        struct mlfiPriv *priv = MLFIPRIV;
        char *p;
        char host[512];
        char hbuf[1024];

        if (priv == NULL)
                return rstat;

        /* close the archive file */
        if (priv->mlfi_fp != NULL && fclose(priv->mlfi_fp) == EOF)
        {
                /* failed; we have to wait until later */
                rstat = SMFIS_TEMPFAIL;
                (void) unlink(priv->mlfi_fname);
        }
        else if (ok)
        {
                /* add a header to the message announcing our presence */
                if (gethostname(host, sizeof host) < 0)
                        snprintf(host, sizeof host, "localhost");
                p = strrchr(priv->mlfi_fname, '/');
                if (p == NULL)
                        p = priv->mlfi_fname;
                else
                        p++;
                snprintf(hbuf, sizeof hbuf, "%s@%s", p, host);
                smfi_addheader(ctx, "X-Archived", hbuf);
        }
        else
        {
                /* message was aborted -- delete the archive file */
                (void) unlink(priv->mlfi_fname);
        }

        /* release private memory */
        free(priv->mlfi_fname);
        free(priv);
        smfi_setpriv(ctx, NULL);

        /* return status */
        return rstat;
}

struct smfiDesc smfilter =
{
        "SampleFilter", /* filter name */
        SMFI_VERSION,   /* version code -- do not change */
        SMFIF_ADDHDRS,  /* flags */
        NULL,           /* connection info filter */
        NULL,           /* SMTP HELO command filter */
        mlfi_envfrom,   /* envelope sender filter */
        NULL,           /* envelope recipient filter */
        mlfi_header,    /* header filter */
        mlfi_eoh,       /* end of header */
        mlfi_body,      /* body block filter */
        mlfi_eom,       /* end of message */
        mlfi_abort,     /* message aborted */
        mlfi_close      /* connection cleanup */
};


int
main(argc, argv)
        int argc;
        char *argv[];
{
        bool setconn = false;
        int c;
        const char *args = "p:";

        /* Process command line options */
        while ((c = getopt(argc, argv, args)) != -1)
        {
                switch (c)
                {
                  case 'p':
                        if (optarg == NULL || *optarg == '\0')
                        {
                                (void) fprintf(stderr, "Illegal conn: %s\n",
                                               optarg);
                                exit(EX_USAGE);
                        }
                        (void) smfi_setconn(optarg);
                        setconn = true;
                        break;

                }
        }
        if (!setconn)
        {
                fprintf(stderr, "%s: Missing required -p argument\n", argv[0]);
                exit(EX_USAGE);
        }
        if (smfi_register(smfilter) == MI_FAILURE)
        {
                fprintf(stderr, "smfi_register failed\n");
                exit(EX_UNAVAILABLE);
        }
        return smfi_main();
}

/* eof */

*** example taken from the sendmail.org documentation*******