--- lmtp2nntp.c 2001/10/09 12:08:58 1.75
+++ lmtp2nntp.c 2001/10/09 15:22:10 1.76
@@ -123,6 +123,15 @@
l2_stream_t *l2;
};
+#define MAXACLS 32
+
+struct acl {
+ char *acl;
+ int not;
+ sa_addr_t *saa;
+ size_t prefixlen;
+};
+
typedef struct {
l2_context_t ctx;
char *progname;
@@ -143,6 +152,8 @@
char *option_pidfile;
int option_killflag;
int option_daemon;
+ int option_aclc;
+ struct acl option_acl[MAXACLS];
l2_stream_t *l2;
sa_addr_t *saaAltio;
sa_t *saAltio;
@@ -352,12 +363,15 @@
lmtp_t *lmtp = NULL;
lmtp_io_t lmtp_io;
lmtp2nntp_t *ctx = NULL;
+ int bOk;
int i; /* general purpose scratch int, index ... */
char *cp; /* general purpose character pointer */
char *azHosts;
size_t asHosts;
char *azTimeout;
size_t asTimeout;
+ char *azACL;
+ size_t asACL;
char *cpHost;
char *cpPort;
l2_channel_t *chPrefix;
@@ -368,6 +382,8 @@
char *cpName;
char *cpValue;
int nValue;
+ char *cpAddr;
+ char *cpPrefixLen;
/* library version check (run-time) */
if (l2_version.v_hex < L2_VERSION_HEX_REQ) {
@@ -418,6 +434,13 @@
ctx->ns[i].rc = LMTP_ERR_UNKNOWN;
ctx->ns[i].l2 = NULL;
}
+ ctx->option_aclc = 0;
+ for (i = 0; i < MAXACLS; i++) {
+ ctx->option_acl[i].acl = NULL;
+ ctx->option_acl[i].not = FALSE;
+ ctx->option_acl[i].saa = NULL;
+ ctx->option_acl[i].prefixlen = 0;
+ }
ctx->azGroupargs = NULL;
ctx->asGroupargs = 0;
initsession(&ctx->session);
@@ -435,7 +458,7 @@
*/
/* read in the arguments */
- while ((i = getopt(argc, argv, "D:KP:a:b:c:d:g:l:m:n:o:s:t:v")) != -1) {
+ while ((i = getopt(argc, argv, "DKP:a:b:c:d:g:l:m:n:o:s:t:v")) != -1) {
switch (i) {
case 'D': /*POD [B<-D>] */
ctx->option_daemon = TRUE;
@@ -447,7 +470,40 @@
ctx->option_pidfile = strdup(optarg);
break;
case 'a': /*POD [B<-a> I<addr>/I<mask>[,I<addr>/I<mask>[,...]] */
- /* FIXME */
+ if (argz_create_sep(optarg, ',', &azACL, &asACL) != 0)
+ CU(ERR_EXECUTION);
+ cp = NULL;
+ while ((cp = argz_next(azACL, asACL, cp)) != NULL) {
+ if (ctx->option_aclc >= MAXACLS) {
+ fprintf(stderr, "%s:Error: Too many ACL (%d) using option -a\n", ctx->progname, ctx->option_aclc);
+ CU(ERR_EXECUTION);
+ }
+ ctx->option_acl[ctx->option_aclc].acl = strdup(cp);
+ if (cp[0] == '!') {
+ ctx->option_acl[ctx->option_aclc].not = TRUE;
+ cpAddr = strdup(cp+1);
+ }
+ else {
+ cpAddr = strdup(cp);
+ }
+ if ((cpPrefixLen = strrchr(cpAddr, '/')) != NULL)
+ *cpPrefixLen++ = NUL;
+ else
+ cpPrefixLen = "-1";
+ ctx->option_acl[ctx->option_aclc].prefixlen = atoi(cpPrefixLen);
+ if ((rc = sa_addr_create(&ctx->option_acl[ctx->option_aclc].saa)) != SA_OK) {
+ fprintf(stderr, "%s:Error: Creating address failed for -a option (%d)\n",
+ ctx->progname, rc);
+ }
+ if ((rc = sa_addr_u2a(ctx->option_acl[ctx->option_aclc].saa, "inet://%s:0", cpAddr)) != SA_OK) {
+ fprintf(stderr, "%s:Error: Parsing host address failed for \"%s:0\" (%d)\n",
+ ctx->progname, cpAddr, rc);
+ CU(ERR_EXECUTION);
+ }
+ ctx->option_aclc++;
+ free(cpAddr);
+ }
+ free(azACL);
break;
case 'b': /*POD [B<-b> C<->|I<path>|I<addr>[I<:port>]] */
if (strcmp(optarg, "-") != 0) {
@@ -567,7 +623,7 @@
else
ctx->option_logfile = strdup("logfile");
- if (l2_util_s2l(optarg, strlen(optarg), ',', &ctx->option_levelmask) != L2_OK) {
+ if (l2_util_s2l(optarg, strlen(optarg), &ctx->option_levelmask) != L2_OK) {
fprintf(stderr, "%s:Error: invalid level \"%s\" to option -l\n", ctx->progname, optarg);
CU(ERR_EXECUTION);
}
@@ -803,6 +859,34 @@
CU(0);
}
+ /* if no positive ACL exists (option -a) add a wildcard match-all */
+ bOk = FALSE;
+ for (i = 0; i < ctx->option_aclc; i++) {
+ if (!ctx->option_acl[i].not) {
+ bOk = TRUE;
+ break;
+ }
+ }
+ if (!bOk) {
+ if (ctx->option_aclc >= MAXACLS) {
+ fprintf(stderr, "%s:Error: Too many ACL (%d) using option -a (no space for additional fake ACL)\n", ctx->progname, ctx->option_aclc);
+ CU(ERR_EXECUTION);
+ }
+ ctx->option_acl[ctx->option_aclc].acl = "0.0.0.0/0[FAKE]";
+ ctx->option_acl[ctx->option_aclc].not = FALSE;
+ ctx->option_acl[ctx->option_aclc].prefixlen = 0;
+ if ((rc = sa_addr_create(&ctx->option_acl[ctx->option_aclc].saa)) != SA_OK) {
+ fprintf(stderr, "%s:Error: Creating fake address failed for -a option (%d)\n",
+ ctx->progname, rc);
+ }
+ if ((rc = sa_addr_u2a(ctx->option_acl[ctx->option_aclc].saa, "inet://0.0.0.0:0")) != SA_OK) {
+ fprintf(stderr, "%s:Error: Parsing host address failed for \"0.0.0.0:0\" (%d)\n",
+ ctx->progname, rc);
+ CU(ERR_EXECUTION);
+ }
+ ctx->option_aclc++;
+ }
+
catchsignal(0, ctx);
signal(SIGCHLD, (void(*)())catchsignal);
signal(SIGHUP, (void(*)())catchsignal);
@@ -873,6 +957,62 @@
sa_timeout(ctx->saAltio, SA_TIMEOUT_READ, ctx->option_timeout_lmtp_read, 0);
sa_timeout(ctx->saAltio, SA_TIMEOUT_WRITE, ctx->option_timeout_lmtp_write, 0);
while ((rc = sa_accept(ctx->saAltio, &ctx->saaIO, &ctx->saIO)) == SA_OK) {
+
+ /* Access Control List */
+ bOk = FALSE;
+ /* check positive matches */
+ for (i = 0; i < ctx->option_aclc; i++) {
+ char *cpA1;
+ char *cpA2;
+ if (ctx->option_acl[i].not)
+ continue;
+ sa_addr_a2u(ctx->option_acl[i].saa, &cpA1);
+ sa_addr_a2u(ctx->saaIO, &cpA2);
+ if (sa_addr_match(ctx->saaIO, ctx->option_acl[i].saa, ctx->option_acl[i].prefixlen) == SA_OK) {
+ log4(ctx, TRACE, "positive/inclusive ACL \"%s\" (%s/%d) matching %s: OK", ctx->option_acl[i].acl, cpA1, ctx->option_acl[i].prefixlen, cpA2);
+ bOk = TRUE;
+ break;
+ }
+ else
+ log4(ctx, TRACE, "positive/inclusive ACL \"%s\" (%s/%d) matching %s: FAILED", ctx->option_acl[i].acl, cpA1, ctx->option_acl[i].prefixlen, cpA2);
+ free(cpA1);
+ free(cpA2);
+ }
+ /* check negative matches */
+ for (i = 0; i < ctx->option_aclc; i++) {
+ char *cpA1;
+ char *cpA2;
+ if (!ctx->option_acl[i].not)
+ continue;
+ sa_addr_a2u(ctx->option_acl[i].saa, &cpA1);
+ sa_addr_a2u(ctx->saaIO, &cpA2);
+ if (sa_addr_match(ctx->saaIO, ctx->option_acl[i].saa, ctx->option_acl[i].prefixlen) == SA_OK) {
+ log4(ctx, TRACE, "negative/exclusive ACL \"%s\" (not %s/%d) matching %s: OK (stop)", ctx->option_acl[i].acl, cpA1, ctx->option_acl[i].prefixlen, cpA2);
+ bOk = FALSE;
+ break;
+ }
+ else {
+ log4(ctx, TRACE, "negative/exclusive ACL \"%s\" (not %s/%d) matching %s: FAILED", ctx->option_acl[i].acl, cpA1, ctx->option_acl[i].prefixlen, cpA2);
+ }
+ }
+ if (bOk) {
+ char *cpA;
+ sa_addr_a2u(ctx->saaIO, &cpA);
+ log1(ctx, TRACE, "connection from %s accepted due to ACL", cpA);
+ free(cpA);
+ l2_stream_flush(ctx->l2);
+ }
+ else {
+ char *cpA;
+ sa_addr_a2u(ctx->saaIO, &cpA);
+ log1(ctx, ERROR, "connection from %s refused due to ACL", cpA);
+ free(cpA);
+ l2_stream_flush(ctx->l2);
+ sa_destroy(ctx->saIO);
+ sa_addr_destroy(ctx->saaIO);
+ continue;
+ }
+
l2_stream_flush(ctx->l2); /* must flush before fork() */
pid = fork();
if (pid == -1) {
|