From fb836eb1e24d9d1f2e39aea9909fc5e0a7e595d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Fonseca?= Date: Tue, 11 Feb 2003 00:09:16 +0000 Subject: Support for identities and custom configuration files based on patch by Jerome . Respective documentation updates. The use of '=' in the configuration file was made optional. --- NEWS | 17 ++++++++++++ TODO | 1 + esmtp.1 | 4 ++- esmtp.h | 30 +++++++++++++++++++++ lexer.l | 1 + main.c | 64 +++++++++++++++++++++++++++++++------------- parser.y | 83 +++++++++++++++++++++++++++++++++++++++------------------- sample.esmtprc | 46 +++++++++++++++++++++++++++----- 8 files changed, 194 insertions(+), 52 deletions(-) create mode 100644 esmtp.h diff --git a/NEWS b/NEWS index e69de29..b77d803 100644 --- a/NEWS +++ b/NEWS @@ -0,0 +1,17 @@ +Version 0.3 + + * Capability to generate log files. + * Better verbose output. + * Minor bug fixes and documentation enhancements. + * Multiple identities. + +Version 0.2: + + * Packaging corrections. + * Minor bug fixes and documentation enhancements. + * Use sendmail exit codes. + + +Version 0.1: + + * Initial release diff --git a/TODO b/TODO index d2cfa56..0b74cb8 100644 --- a/TODO +++ b/TODO @@ -1 +1,2 @@ - handle the '-t' option +- safer memory allocation diff --git a/esmtp.1 b/esmtp.1 index 2fd7e6d..4d46ea5 100644 --- a/esmtp.1 +++ b/esmtp.1 @@ -137,7 +137,6 @@ Verify names only \- do not try to collect or deliver a message. .TP .BI \-C file -(ignored) Use alternate configuration file. .TP @@ -160,6 +159,9 @@ if that header is missing during initial submission. The envelope sender address is used as the recipient for delivery status notifications and may also appear in a Return-Path: header. +.PP +This address is also used to select from different identities in the +configuration file. .TP .BI \-G diff --git a/esmtp.h b/esmtp.h new file mode 100644 index 0000000..7c61e9a --- /dev/null +++ b/esmtp.h @@ -0,0 +1,30 @@ +/* + * esmtp.h - global declarations + */ + +typedef struct { + char *identity; + char *host; + char *user; + char *pass; + enum starttls_option starttls; /* it should default to Starttls_DISABLED */ + char *certificate_passphrase; +} identity_t; + +extern identity_t default_identity; + +typedef struct identity_list_rec identity_list_t; + +struct identity_list_rec { + identity_list_t *next; + identity_t identity; +} ; + +extern identity_list_t *identities_head, **identities_tail; + + +extern char *rcfile; + + +extern void parse_rcfile(void); + diff --git a/lexer.l b/lexer.l index ef550e7..530e622 100644 --- a/lexer.l +++ b/lexer.l @@ -54,6 +54,7 @@ void escapes(const char *tp, char *cp); +identity { BEGIN(NAME); return IDENTITY; } host(name)? { BEGIN(NAME); return HOSTNAME; } user(name)? { BEGIN(NAME); return USERNAME; } pass(word)? { BEGIN(NAME); return PASSWORD; } diff --git a/main.c b/main.c index a8a1c65..f34a852 100644 --- a/main.c +++ b/main.c @@ -37,14 +37,19 @@ #include #include -char *from = NULL; -char *host = NULL; -char *user = NULL; -char *pass = NULL; -enum starttls_option starttls = Starttls_DISABLED; -char *certificate_passphrase = NULL; +#include "esmtp.h" -extern void parse_rcfile(void); +/* Identity management */ +identity_t default_identity = { + NULL, + NULL, + NULL, + NULL, + Starttls_DISABLED, + NULL +}; + +identity_list_t *identities_head = NULL, **identities_tail = &identities_head; /* Callback function to read the message from a file. Since libESMTP does not * provide callbacks which translate line endings, one must be provided by the @@ -197,14 +202,18 @@ void version (void) int authinteract (auth_client_request_t request, char **result, int fields, void *arg) { + identity_t *identity = (identity_t *)arg; int i; + if(!identity) + return 0; + for (i = 0; i < fields; i++) { - if (request[i].flags & AUTH_USER && user) - result[i] = user; - else if (request[i].flags & AUTH_PASS && pass) - result[i] = pass; + if (request[i].flags & AUTH_USER && identity->user) + result[i] = identity->user; + else if (request[i].flags & AUTH_PASS && identity->pass) + result[i] = identity->pass; else return 0; } @@ -213,12 +222,16 @@ int authinteract (auth_client_request_t request, char **result, int fields, int tlsinteract (char *buf, int buflen, int rwflag, void *arg) { + identity_t *identity = (identity_t *)arg; char *pw; int len; - if (certificate_passphrase) + if(!identity) + return 0; + + if (identity->certificate_passphrase) { - pw = certificate_passphrase; + pw = identity->certificate_passphrase; len = strlen (pw); if (len + 1 > buflen) return 0; @@ -251,13 +264,17 @@ int main (int argc, char **argv) int ret; enum notify_flags notify = Notify_NOTSET; FILE *fp = NULL; + identity_t *identity = &default_identity; + char *from = NULL; + identity_list_t *p; /* Parse the rc file. */ parse_rcfile(); /* This program sends only one message at a time. Create an SMTP session. */ - auth_client_init (); session = smtp_create_session (); + auth_client_init (); + session = smtp_create_session (); while ((c = getopt (argc, argv, "A:B:b:C:cd:e:F:f:Gh:IiL:M:mN:nO:o:p:q:R:r:sTtV:vX:")) != EOF) @@ -273,6 +290,7 @@ int main (int argc, char **argv) case 'C': /* Select configuration file */ + rcfile = optarg; break; case 'F': @@ -394,6 +412,16 @@ int main (int argc, char **argv) case 'r': /* Obsolete -f flag */ from = optarg; + p = identities_head; + while(p) + { + if(!strcmp(p->identity.identity, from)) + { + identity = &p->identity; + break; + } + p = p->next; + } break; case 'h': @@ -502,20 +530,20 @@ int main (int argc, char **argv) * number of 587, however this is not widely deployed so the port is * specified as 25 along with the default MTA host. */ - smtp_set_server (session, host ? host : "localhost:25"); + smtp_set_server (session, identity->host ? identity->host : "localhost:25"); /* Set the SMTP Starttls extension. */ - smtp_starttls_enable (session, starttls); + smtp_starttls_enable (session, identity->starttls); /* Do what's needed at application level to use authentication. */ authctx = auth_create_context (); auth_set_mechanism_flags (authctx, AUTH_PLUGIN_PLAIN, 0); - auth_set_interact_cb (authctx, authinteract, NULL); + auth_set_interact_cb (authctx, authinteract, identity); /* Use our callback for X.509 certificate passwords. If STARTTLS is not in * use or disabled in configure, the following is harmless. */ - smtp_starttls_set_password_cb (tlsinteract, NULL); + smtp_starttls_set_password_cb (tlsinteract, identity); /* Now tell libESMTP it can use the SMTP AUTH extension. */ smtp_auth_set_context (session, authctx); diff --git a/parser.y b/parser.y index 5694948..aebdd75 100644 --- a/parser.y +++ b/parser.y @@ -14,17 +14,15 @@ #include +#include "esmtp.h" + /* parser reads these */ char *rcfile = NULL; /* path name of dot file */ /* parser sets these */ int yydebug; /* in case we didn't generate with -- debug */ -extern char *host; -extern char *user; -extern char *pass; -extern enum starttls_option starttls; -extern char *certificate_passphrase; +static identity_t *identity = &default_identity; /* using Bison, this arranges that yydebug messages will show actual tokens */ extern char * yytext; @@ -38,7 +36,7 @@ void yyerror (const char *s); char *sval; } -%token HOSTNAME USERNAME PASSWORD STARTTLS CERTIFICATE_PASSPHRASE +%token IDENTITY HOSTNAME USERNAME PASSWORD STARTTLS CERTIFICATE_PASSPHRASE %token MAP @@ -50,6 +48,34 @@ void yyerror (const char *s); rcfile : /* empty */ | statement_list + | statement_list identity_list + | identity_list + ; + +identity_list : identity + | identity statement_list + | identity_list identity statement_list + ; + + +map : /* empty */ + | MAP + ; + +identity : IDENTITY map STRING + { + identity_list_t *item; + + item = malloc(sizeof(identity_list_t)); + memset(item, 0, sizeof(identity_list_t)); + + *identities_tail = item; + identities_tail = &item->next; + identity = &item->identity; + + identity->identity = strdup($3); + identity->starttls = Starttls_DISABLED; + } ; statement_list : statement @@ -57,19 +83,18 @@ statement_list : statement ; /* future global options should also have the form SET optmap */ -statement : HOSTNAME MAP STRING { host = strdup($3); } - | USERNAME MAP STRING { user = strdup($3); } - | PASSWORD MAP STRING { pass = strdup($3); } - | STARTTLS MAP DISABLED { starttls = Starttls_DISABLED; } - | STARTTLS MAP ENABLED { starttls = Starttls_ENABLED; } - | STARTTLS MAP REQUIRED { starttls = Starttls_REQUIRED; } - | CERTIFICATE_PASSPHRASE MAP STRING { certificate_passphrase = strdup($3); } +statement : HOSTNAME map STRING { identity->host = strdup($3); } + | USERNAME map STRING { identity->user = strdup($3); } + | PASSWORD map STRING { identity->pass = strdup($3); } + | STARTTLS map DISABLED { identity->starttls = Starttls_DISABLED; } + | STARTTLS map ENABLED { identity->starttls = Starttls_ENABLED; } + | STARTTLS map REQUIRED { identity->starttls = Starttls_REQUIRED; } + | CERTIFICATE_PASSPHRASE map STRING { identity->certificate_passphrase = strdup($3); } ; %% /* lexer interface */ -extern char *rcfile; extern int lineno; extern char *yytext; extern FILE *yyin; @@ -82,21 +107,25 @@ void yyerror (const char *s) } #define RCFILE ".esmtprc" + void parse_rcfile (void) { - char *home; - - /* Setup the rcfile name. */ - if (!(home = getenv("HOME"))) - return; - - if (!(rcfile = malloc(strlen(home) + sizeof(RCFILE) + 2))) - return; - - strcpy(rcfile, home); - if (rcfile[strlen(rcfile) - 1] != '/') - strcat(rcfile, "/"); - strcat(rcfile, RCFILE); + if(!rcfile) + { + char *home; + + /* Setup the rcfile name. */ + if (!(home = getenv("HOME"))) + return; + + if (!(rcfile = malloc(strlen(home) + strlen(RCFILE) + 2))) + return; + + strcpy(rcfile, home); + if (rcfile[strlen(rcfile) - 1] != '/') + strcat(rcfile, "/"); + strcat(rcfile, RCFILE); + } /* Open the configuration file and feed it to the lexer. */ if (!(yyin = fopen(rcfile, "r"))) diff --git a/sample.esmtprc b/sample.esmtprc index a5343f2..1a11e4e 100644 --- a/sample.esmtprc +++ b/sample.esmtprc @@ -1,15 +1,49 @@ -#set SMTP host and service (port) +# Sample configuration file for ESMTP. +# +# José Fonseca + +# Set SMTP host and service (port) +# hostname = localhost:25 +# +# This is specified in the format host.example.org[:service] with no whitespace +# surrounding the colon if service is specified. service may be a name from +# /etc/services or a decimal port number. If not specified the port defaults to +# 587. +# +# NOTE (from libESMTP documentation): The default port number is set to 587 +# since this is the port that should be used for mail submission, see RFC 2476. +# By choosing this default now, the API does not change behaviour unexpectedly +# in the future as use of the new standard becomes commonplace. The hostport +# nototion simplifies things for the application, the user can type +# localhost:smtp or localhost:25 where the application expects a host name. -# set the user name +# Set the user name +# username = "USERNAME" +# +# Note that the equal and quotes are optional but can be helpful in certain +# circumstances. -# set the password +# Set the password password = "PASSWORD" -# use the Starttls -#starttls = { enabled | disabled | required } +# Use the Starttls +# +starttls = disabled +# +# It can be one of "enabled", "disabled" or "required". It defaults to +# disabled. -# set the certificate passphrase +# Set the certificate passphrase +# #certificate_passphrase = "CERTIFICATE_PASSPHRASE" + +# A different identity which can be selected with the '-f' flag. You can have +# as many you like. +# +identity myself@somewhere.com + hostname smtp.somewhere.com:25 + username "myself" + password "secret" -- cgit v1.2.3