123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sysexits.h>
- #include <unistd.h>
- #include <errno.h>
- #include <pwd.h>
- #include <grp.h>
- #include "libmilter/mfapi.h"
- #include "libmilter/mfdef.h"
- struct mlfiPriv {
- int is_auth;
- char *env_from;
- int env_from_len;
- int reject;
- };
- #define MLFIPRIV ((struct mlfiPriv*)smfi_getpriv(ctx))
- static unsigned long mta_caps = 0;
- const char *parse_address(const char *address, int *len)
- {
- int inlen = strlen(address);
- int pos_open = -1, pos_close = -1;
- int i;
- for (i = 0; i < inlen; ++i) {
- if (address[i] == '<') pos_open = i;
- else if (address[i] == '>') pos_close = i;
- }
- if (pos_open != -1 && pos_close != -1 && pos_open < pos_close) {
- *len = pos_close - pos_open - 1;
- return address + pos_open + 1;
- } else {
- *len = inlen;
- return address;
- }
- }
- void mlfi_cleanup(SMFICTX *ctx)
- {
- struct mlfiPriv *priv = MLFIPRIV;
- if (priv == NULL) return;
- free(priv->env_from);
- free(priv);
- smfi_setpriv(ctx, NULL);
- }
- sfsistat mlfi_envfrom(SMFICTX *ctx, char **envfrom)
- {
- struct mlfiPriv *priv;
-
- priv = malloc(sizeof *priv);
- if (priv == NULL) return SMFIS_TEMPFAIL;
- memset(priv, '\0', sizeof *priv);
-
- int len;
- const char *from = parse_address(*envfrom, &len);
- char *fromcp = strndup(from, len);
- if (fromcp == NULL) return SMFIS_TEMPFAIL;
-
- priv->is_auth = smfi_getsymval(ctx, "{auth_type}") ? 1 : 0;
- priv->env_from = fromcp;
- priv->env_from_len = len;
- priv->reject = 0;
- smfi_setpriv(ctx, priv);
- return SMFIS_CONTINUE;
- }
- sfsistat mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
- {
- struct mlfiPriv *priv = MLFIPRIV;
-
- if (priv->is_auth && !priv->reject) {
- if (strcasecmp(headerf, "from") == 0) {
- int len;
- const char *from = parse_address(headerv, &len);
-
- if (len != priv->env_from_len || strncasecmp(from, priv->env_from, len) != 0) priv->reject = 1;
- }
- }
- return ((mta_caps & SMFIP_NR_HDR) != 0) ? SMFIS_NOREPLY : SMFIS_CONTINUE;
- }
- sfsistat mlfi_eom(SMFICTX *ctx)
- {
- struct mlfiPriv *priv = MLFIPRIV;
- if (priv->reject) {
- smfi_setreply(ctx, "550", "5.7.1", "Rejected due to unmatching envelope and header sender.");
- mlfi_cleanup(ctx);
- return SMFIS_REJECT;
- }
- mlfi_cleanup(ctx);
- return SMFIS_CONTINUE;
- }
- sfsistat mlfi_abort(SMFICTX *ctx)
- {
- mlfi_cleanup(ctx);
- return SMFIS_CONTINUE;
- }
- sfsistat mlfi_negotiate(SMFICTX *ctx, unsigned long f0, unsigned long f1, unsigned long f2, unsigned long f3, unsigned long *pf0, unsigned long *pf1, unsigned long *pf2, unsigned long *pf3)
- {
- *pf0 = 0;
-
- *pf1 = SMFIP_NOCONNECT|SMFIP_NOHELO|SMFIP_NORCPT;
- mta_caps = f1;
- if ((mta_caps & SMFIP_NR_HDR) != 0) *pf1 |= SMFIP_NR_HDR;
- *pf2 = 0;
- *pf3 = 0;
- return SMFIS_CONTINUE;
- }
- struct smfiDesc smfilter =
- {
- "Header from check",
- SMFI_VERSION,
- 0,
- NULL,
- NULL,
- mlfi_envfrom,
- NULL,
- mlfi_header,
- NULL,
- NULL,
- mlfi_eom,
- mlfi_abort,
- NULL,
- NULL,
- NULL,
- mlfi_negotiate
- };
- uid_t get_uid(const char *name)
- {
- struct passwd *pwd = getpwnam(name);
- return pwd == NULL ? -1 : pwd->pw_uid;
- }
- gid_t get_gid(const char *name)
- {
- struct group *grp = getgrnam(name);
- return grp == NULL ? -1 : grp->gr_gid;
- }
- int main(int argc, char **argv)
- {
- int c, daemonize = 0;
- uid_t uid = -1; gid_t gid = -1;
- mode_t um = -1;
- char *pidfilename = NULL, *sockname = NULL;
- FILE *pidfile = NULL;
- while ((c = getopt(argc, argv, "ds:p:u:g:m:")) != -1) {
- switch (c) {
- case 's':
- sockname = strdup(optarg);
- break;
- case 'p':
- pidfilename = strdup(optarg);
- break;
- case 'd':
- daemonize = 1;
- break;
- case 'u':
- uid = get_uid(optarg);
- break;
- case 'g':
- gid = get_gid(optarg);
- break;
- case 'm':
- um = strtol(optarg, 0, 8);
- break;
- }
- }
- if (!sockname) {
- fprintf(stderr, "%s: Missing required -s argument\n", argv[0]);
- exit(EX_USAGE);
- }
- if (pidfilename) {
- unlink(pidfilename);
- pidfile = fopen(pidfilename, "w");
- if (!pidfile)
- {
- fprintf(stderr, "Could not open pidfile: %s\n", strerror(errno));
- exit(1);
- }
- free(pidfilename);
- }
- if (um != (mode_t)-1) umask(um);
- if (gid != (gid_t)-1) setgid(gid);
- if (uid != (uid_t)-1) setuid(uid);
- if (daemonize) {
- if (daemon(0, 0) == -1) {
- fprintf(stderr, "daemon() failed: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- }
- if (pidfile) {
- fprintf(pidfile, "%ld\n", (long)getpid());
- fclose(pidfile);
- }
- struct stat junk;
- if (stat(sockname, &junk) == 0) unlink(sockname);
- smfi_setconn(sockname);
- free(sockname);
- if (smfi_register(smfilter) == MI_FAILURE) {
- fprintf(stderr, "smfi_register failed\n");
- exit(EX_UNAVAILABLE);
- }
- return smfi_main();
- }
|