📄 smtp.c
字号:
printf ("451 Service unavailable\r\n"); syslog(LOG_NOTICE, "can't execute: %s: %m", config->argv[0]); exit (1); } else { x->sin = fdopen(pin[0], "r"); close(pin[1]); x->sout = fdopen(pout[1], "w"); close(pout[0]); p = config->argv[0]; } } else { printf ("451 Service unavailable\r\n"); syslog(LOG_NOTICE, "no server specified"); exit (1); } syslog(LOG_NOTICE, "connected to server: %s", p); /* Konfiguration uebernehmen */ x->config = config; /* Hostnamen holen */ gethostname(word, sizeof(word)); getdomainname(line, sizeof(line)); snprintf (x->hostname, sizeof(x->hostname) - 2, word, line); /* Greeting Message vom Sendmail Server lesen, und an * Client schicken. */ rc = getresp(line, sizeof(line), x->sin, debug); while (line[3] != ' ') { rc = getresp(line, sizeof(line), x->sin, debug); if (rc == -1) { syslog(LOG_NOTICE, "lost server while reading server greeting"); exit (1); } } echoline(stdout, line, rc); /* Wir stellen uns beim lokalen Sendmail Server vor. Die * EHLO-replys werden 'verschluckt' und durch einen eigenen * ersetzt. */ putcmd(x->sout, "EHLO", "localhost", "SVR"); while ((rc = getresp(line, sizeof(line), x->sin, debug)) != -1) { if (line[3] == ' ') break; } rc = atol(line); if (rc != 250) { syslog(LOG_NOTICE, "server HELO: status is not 250"); echoline(stdout, "421 service unavailable", 0); return (-1); } /* * ** S M T P M A I N L O O P */ x->state = WAITING; while (1) { rc = 0; /* Server response code loeschen */ /* Naechstes Kommando vom Client holen */ fflush(stdout); if (get_clientinput(line, sizeof(line), x->config->timeout) == NULL) { syslog(LOG_NOTICE, "client closed connection"); break; } /* Kommando isolieren */ p = noctrl(line); get_word(&p, command, sizeof(command)); strupr(command); p = skip_ws(p); /* QUIT ist immer moeglich. */ if (strcmp(command, "QUIT") == 0) { putcmd(x->sout, "QUIT", "", "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); x->state = SEND_QUIT; break; } /* HELP */ else if (strcmp(command, "HELP") == 0) { echoline(stdout, "503 no help available", 0); } /* NOOP */ else if (strcmp(command, "NOOP") == 0) { putcmd(x->sout, "NOOP", "", "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); } /* RSET */ else if (strcmp(command, "RSET") == 0) { putcmd(x->sout, "RSET", "", "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); reset_connection(x); syslog(LOG_NOTICE, "RSET command, client= %s", x->client); } /* ETRN */ else if (strcmp(command, "ETRN") == 0) { if (x->config->etrn == 0) { echoline(stdout, "500 unrecognized command", 0); syslog(LOG_NOTICE, "ETRN request rejected: client= %s", x->client); } else { if (*get_word(&p, word, sizeof(word)) == 0) echoline(stdout, "500 ETRN needs parameter", 0); else { putcmd(x->sout, "ETRN", word, "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); if (rc != 250) syslog(LOG_NOTICE, "ETRN rejected by server, client= %s", x->client); } } } /* HELO und EHLO sind auch immer verfuegbar, aber nur * einmal. */ else if (strcmp(command, "HELO") == 0 || strcmp(command, "EHLO") == 0) { if (x->helloseen != 0) echoline(stdout, "503 duplicate HELO/EHLO", 0); else if (*get_word(&p, word, sizeof(word)) == 0) { snprintf (line, sizeof(line) - 2, "501 %s requires domain name", command); echoline(stdout, line, 0); } else { if (strcmp(command, "HELO") == 0) { snprintf (line, sizeof(line) - 2, "250 SMTP server v%s ready %s [%s]", VERSION, x->client, x->ipnum); echoline(stdout, line, 0); } else { snprintf (line, sizeof(line) - 2, "250-SMTP server v%s ready %s [%s]", VERSION, x->client, x->ipnum); echoline(stdout, line, 0); echoline(stdout, "250-8BITMIME", 0); if (x->config->etrn != 0) echoline(stdout, "250-ETRN", 0); echoline(stdout, "250 HELP", 0); } x->helloseen = 1; } } /* MAIL, SEND, SOML, SAML * * Laut RFC 821 kann das MAIL Kommando jederzeit abgesetzt * werden, es macht dabei einen impliziten SMTP-Reset. Der * real existierende Sendmail will davon aber nichts wissen. */ else if (strcmp(command, "MAIL") == 0 || strcmp(command, "SEND") == 0 || strcmp(command, "SOML") == 0 || strcmp(command, "SAML") == 0) { get_quoted(&p, ':', word, sizeof(word)); if (strcasecmp(word, "FROM") != 0) echoline(stdout, "500 syntax error", 0); else if (*x->sender != 0) echoline(stdout, "503 sender already specified", 0); else { int allowed; char sender[200], emailadr[200]; p = skip_ws(p); get_word(&p, sender, sizeof(sender)); strlwr(sender); /* * Wir machen ein paar grundsaetzliche Tests mit * der Absenderadresse: * * - Ist die Adresse von spitzen Klammern * umgeben? * ... */ allowed = 1; get_emailadr(sender, emailadr, sizeof(emailadr)); if (*emailadr == 0) allowed = 0; /* * ... * - Enthaelt die Adresse mindestens ein @-Zeichen? * - Enthaelt die Adresse genau ein @-Zeichen? * - Ist in der Adresse kein !- und kein %-Zeichen * enthalten. * ... */ else if (check_emailadr(emailadr) == 0) allowed = 0; /* * ... * - Schliesslich wird ggf. noch getestet, * ob die Absenderadresse auch auf der * allow-Liste steht. * * Mit den Empfaengeradressen werden die gleichen Tests * durchgefuehrt. */ else if ((p = x->config->senderlist) == NULL || *p == 0) allowed = 1; /* kein Adresstest */ else allowed = search_allowlist(emailadr, x->config->senderlist); if (allowed == 0) { char line[300]; snprintf (line, sizeof(line) - 2, "550 not allowed: %s", sender); echoline(stdout, line, 0); syslog(LOG_NOTICE, "sender rejected: %s, client= %s", sender, x->client); } else { snprintf (line, sizeof(line) - 2, "%s FROM: %s", command, sender); putcmd(x->sout, line, "", "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); if (rc == 250) { copy_string(x->sender, sender, sizeof(sender)); x->state = MAIL_SEEN; } } } } /* RCPT */ else if (strcmp(command, "RCPT") == 0) { get_quoted(&p, ':', word, sizeof(word)); if (strcasecmp(word, "TO") != 0) echoline(stdout, "500 syntax error", 0); else if (x->state != MAIL_SEEN && x->state != RCPT_SEEN) echoline(stdout, "503 specify sender first", 0); else { int allowed; char rcpt[200], emailadr[200]; p = skip_ws(p); get_word(&p, rcpt, sizeof(rcpt)); strlwr(rcpt); get_emailadr(rcpt, emailadr, sizeof(emailadr)); if (*emailadr == 0) allowed = 0; else if (check_emailadr(emailadr) == 0) allowed = 0; else if ((p = x->config->rcptlist) == NULL || *p == 0) allowed = 1; else allowed = search_allowlist(emailadr, x->config->rcptlist); if (allowed == 0) { char line[300]; snprintf (line, sizeof(line) - 2, "550 no such user: %s", rcpt); echoline(stdout, line, 0); syslog(LOG_NOTICE, "recipient rejected: %s, client= %s", rcpt, x->client); } else { putcmd(x->sout, "RCPT TO:", rcpt, "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); if (rc == 250 || rc == 251) { x->nrcpt++; x->state = RCPT_SEEN; } } } } /* DATA */ else if (strcmp(command, "DATA") == 0) { x->mailcount++; if (x->state != RCPT_SEEN) echoline(stdout, "503 specify receipients first", 0); else { putcmd(x->sout, "DATA", "", "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); if (rc == 354) { if ((rc = receive_data(x)) == 0) { rc = getresp(line, sizeof(line), x->sin, debug); echoline(stdout, line, rc); if (rc == 250) { p = line; get_word(&p, word, sizeof(word)); get_word(&p, x->jobid, sizeof(x->jobid)); } } } snprintf (line, sizeof(line) - 2, "client= %s, sender= %s, nrcpt= %d, size= %ld, jobid= <%s>, message-id= <%s>, status= %d", x->client, x->sender, x->nrcpt, x->size, x->jobid, x->msgid, rc); syslog(LOG_NOTICE, line); reset_connection(x); x->state = WAITING; } } /* Alles andere ist unserem Server unbekannt. */ else { fprintf (stderr, "500 unrecognized command\r\n"); } if (rc == 421) { syslog(LOG_NOTICE, "sendmail returned 421, state= %d, command= %s", x->state, command); break; } else if (rc == -1) { syslog(LOG_NOTICE, "terminating (sendmail terminated)"); x->state = NO_SENDMAIL; break; } } if (x->state != SEND_QUIT && x->state != NO_SENDMAIL) { putcmd(x->sout, "QUIT", "", "SVR"); rc = getresp(line, sizeof(line), x->sin, debug); }end: syslog(LOG_NOTICE, "client %s disconnecting, %d mails", x->client, x->mailcount); return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -