Index: ossp-pkg/lmtp2nntp/lmtp2nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v rcsdiff -q -kk '-r1.75' '-r1.76' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v' 2>/dev/null --- 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/I[,I/I[,...]] */ - /* 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|I[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) {