📄 smtp.c
字号:
/* File: smtp/smtp.c Copyright (C) 1999 by Wolfgang Zekoll <wzk@quietsche-entchen.de> This source is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This source is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/fcntl.h>#include <sys/socket.h>#include <signal.h>#include <netdb.h>#include <netinet/in.h>#include <syslog.h>#include <sys/time.h>#include "smtp.h"#include "ip-lib.h"#include "lib.h"int sdebug(char *line){ if (debug != 0) { noctrl(line); fprintf (stderr, "*** %s\n", line); } return (0);}char *getline(char *line, int size, FILE *fp, int debug){ *line = 0; if (fgets(line, size, fp) == NULL) { syslog(LOG_NOTICE, "sendmail closed read pipe."); return (NULL); } noctrl(line); if (debug != 0) sdebug(line); return (line);}int getresp(char *line, int size, FILE *fp, int debug){ if (getline(line, size, fp, debug) == NULL) return (-1); return (atoi(line));}int echoline(FILE *fp, char *line, int rc){ if (rc == -1) { syslog(LOG_NOTICE, "closing connection with 421"); fprintf (fp, "421 service unavailable\r\n"); } else { noctrl(line); fprintf (fp, "%s\r\n", line); } fflush(fp); return (0);}int putcmd(FILE *fp, char *cmd, char *par, char *dbg){ fprintf (fp, "%s", cmd); if (par != NULL && *par != 0) fprintf (fp, " %s", par); fprintf (fp, "\n"); fflush(fp); if (debug != 0 && dbg != NULL && *dbg != 0) fprintf (stderr, ">>> %s: %s %s\n", dbg, cmd, par); return (0);}int reset_connection(smtp_t *x){ x->nrcpt = 0; x->state = WAITING; *x->sender = 0; x->nrcpt = 0; *x->jobid = 0; *x->msgid = 0; x->size = 0; return (0);}void sigalrm_handler(int sig){ syslog(LOG_NOTICE, "client timed out"); fclose (stdin); return;}char *get_clientinput(char *line, int size, int timeout){ char *p; alarm(timeout); signal(SIGALRM, sigalrm_handler); *line = 0; p = fgets(line, size, stdin); noctrl(line); return (p);}char *get_emailadr(char *envelope, char *email, int size){ char *p, *r; *email = 0; /* * Sonderfall: Es ist moeglich, dass die envelope Adresse `<>' * ist. In diesem liefern wir sie unveraendert zurueck. Das * beisst sich nicht mit Adressen der Form `<<>>', da geschachtelte * spitze Klammern nicht unterstuetzt werden. */ if (strcmp(envelope, "<>") == 0) { strcpy(email, "<>"); return (email); } p = envelope; if (*p != '<') return (email); p++; if ((r = strchr(p, '>')) == NULL) return (email); else if (r[1] != 0) return (email); get_quoted(&p, '>', email, size); return (email);}int check_emailadr(char *emailadr){ char *domain; if (strcmp(emailadr, "<>") == 0) return (1); else if (*emailadr == 0) return (0);/* else if (*emailadr == '@') * return (0); */ else if ((domain = strchr(emailadr, '@')) == NULL) return (0);/* else if (domain[1] == '0') * return (0); */ else if (strchr(&domain[1], '@') != NULL) return (0); else if (strchr(emailadr, '!') != NULL || strchr(emailadr, '%') != NULL) return (0); else if (strchr(emailadr, ':') != NULL || strchr(emailadr, ',') != NULL) return (0); return (1);}int search_allowlist(char *emailadr, char *list){ char *p, *domain, pattern[200]; if (strcmp(emailadr, "<>") == 0) return (1); domain = strchr(emailadr, '@'); if (domain == NULL || *domain == 0) { /* * Das kann eigentlich nicht passieren, die E-Mail Adresse * wurde schon auf genau ein @-Zeichen getestet. */ return (0); } else if (list == NULL || *list == 0) { /* * Kann eigentlich auch nicht vorkommen. */ return (0); } p = list; while ((p = skip_ws(p)), *get_quoted(&p, ',', pattern, sizeof(pattern)) != 0) { noctrl(pattern); if (*pattern == '@' && strpcmp(domain, pattern) == 0) return (1); else if (strpcmp(emailadr, pattern) == 0) return (1); } return (0);}int receive_data(smtp_t *x){ int lineno, isheader, bytes; char line[2048]; lineno = 0; isheader = 1; while (1) { if (get_clientinput(line, sizeof(line), x->config->timeout) == NULL) { syslog(LOG_NOTICE, "client terminated while sending data"); return (-1); } lineno++; noctrl(line); /* Received Zeile einbauen */ if (lineno == 1) { if (x->config->droppath != 2) { fprintf (x->sout, "Received: from %s (%s) by %s\r\n", x->client, x->ipnum, x->hostname); } } /* * Ggf. Message-ID aus Mail-Header lesen, bzw. Mail-Path * aus dem Header loeschen. */ if (isheader == 1) { if (*line == 0) { isheader = 0; if (*x->msgid == 0) { unsigned long now; now = time(NULL); snprintf (x->msgid, sizeof(x->msgid) - 2, "%lu.%d.%d", now, getpid(), x->mailcount); syslog(LOG_NOTICE, "no message id, assuming %s, client= %s", x->msgid, x->client); } } else { char *p, word[80]; p = line; get_word(&p, word, sizeof(word)); strlwr(word); if (strcmp(word, "message-id:") == 0) { if (*x->msgid != 0) { syslog(LOG_NOTICE, "duplicate message id, client= %s", x->client); continue; } else { if ((p = strchr(p, '<')) != NULL) { p++; get_quoted(&p, '>', x->msgid, sizeof(x->msgid)); } } } else if (strcmp(word, "received:") == 0) { if (x->config->droppath != 0) continue; } } } /* Zeile an Sendmail weitergeben */ if ((bytes = fprintf(x->sout, "%s\r\n", line)) != strlen(line) + 2) { syslog(LOG_NOTICE, "server terminated while receiving data"); return (-1); } x->size += bytes; /* Ende der Mail erreicht? */ if (line[0] == '.' && line[1] == 0) { fflush(x->sout); break; } } return (0);}int proxy_request(config_t *config){ int rc; char *p, command[10], word[200], line[2048]; smtp_t *x; x = allocate(sizeof(smtp_t)); get_client_info(0, x->ipnum, x->client); x->mailcount = 0; syslog(LOG_NOTICE, "connected to client: %s", x->ipnum); if (*config->clientdir != 0) { char logfile[200]; unsigned long now; struct stat sbuf; now = time(NULL); snprintf (logfile, sizeof(logfile) - 2, "%s/%s", config->clientdir, x->ipnum); if (stat(logfile, &sbuf) != 0 || (now - sbuf.st_mtime) >= config->accepttime) { printf ("421 service unavailable - authenticate with POP3 first\r\n"); syslog(LOG_NOTICE, "client not permitted: %s", x->ipnum); goto end; } } if (*config->server != 0) { unsigned int port; char server[200]; copy_string(server, config->server, sizeof(server)); port = get_port(server, 25); if ((x->sin = ip_open(server, port)) == NULL) { printf ("451 Service unavailable\r\n"); syslog(LOG_NOTICE, "can't connect to server: %s:%u, %m", server, port); exit (1); } x->sout = x->sin; p = config->server; } else if (config->argv != NULL) { int pid, pin[2], pout[2]; if (pipe(pin) != 0 || pipe(pout) != 0) { printf ("451 Service unavailable\r\n"); syslog(LOG_NOTICE, "can't pipe(): %m"); exit (-1); } else if ((pid = fork()) < 0) { printf ("451 Service unavailable\r\n"); syslog(LOG_NOTICE, "can't fork(): %m"); exit (-1); } else if (pid == 0) { dup2(pin[1], 1); close (pin[0]); dup2(pout[0], 0); close(pout[1]); close (2); execvp(config->argv[0], config->argv);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -