smtp-client.c revision 2d0ebf1c0259ec9a27c4e088ac50824cb377f7a7
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (C) 2006 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen#include "lib.h"
659fe5d24825b160cae512538088020d97a60239Timo Sirainen#include "deliver.h"
659fe5d24825b160cae512538088020d97a60239Timo Sirainen#include "smtp-client.h"
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
35316602eabbae7dcb86dd74c71e04cce45ba7c7Timo Sirainen#include <sys/wait.h>
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen
27bc15088a485a8047fca9b0d24d2904c6dda919Timo Sirainenstruct smtp_client {
503a863a317acba125a4e46435694e35fad769e4Timo Sirainen FILE *f;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pid_t pid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct smtp_client *smtp_client_devnull(FILE **file_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen struct smtp_client *client;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
35316602eabbae7dcb86dd74c71e04cce45ba7c7Timo Sirainen client = i_new(struct smtp_client, 1);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen client->f = *file_r = fopen("/dev/null", "w");
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen if (client->f == NULL)
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen i_fatal("fopen() failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->pid = (pid_t)-1;
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen return client;
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen}
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainenstatic void __attr_noreturn__
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainensmtp_client_run_sendmail(const char *destination,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen const char *return_path, int fd)
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen const char *argv[7], *sendmail_path;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen /* deliver_set's contents may point to environment variables.
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen deliver_env_clean() cleans them up, so they have to be copied. */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen sendmail_path = t_strdup(deliver_set->sendmail_path);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen argv[0] = sendmail_path;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen argv[1] = "-i"; /* ignore dots */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen argv[2] = "-f";
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen argv[3] = return_path != NULL && *return_path != '\0' ?
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen return_path : "<>";
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen argv[4] = "--";
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen argv[5] = destination;
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen argv[6] = NULL;
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen if (dup2(fd, STDIN_FILENO) < 0)
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen i_fatal("dup2() failed: %m");
beb6125ee872e7fed57745ab33e6de99639180f3Timo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen deliver_env_clean();
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen (void)execv(sendmail_path, (void *)argv);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_fatal("execv(%s) failed: %m", sendmail_path);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainenstruct smtp_client *smtp_client_open(const char *destination,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const char *return_path, FILE **file_r)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct smtp_client *client;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen int fd[2];
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen pid_t pid;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (pipe(fd) < 0) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen i_error("pipe() failed: %m");
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return smtp_client_devnull(file_r);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen }
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if ((pid = fork()) == (pid_t)-1) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen i_error("fork() failed: %m");
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen (void)close(fd[0]); (void)close(fd[1]);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen return smtp_client_devnull(file_r);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen }
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (pid == 0) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen /* child */
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen (void)close(fd[1]);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen smtp_client_run_sendmail(destination, return_path, fd[0]);
e8acc691a14a6d0884c5ca9aa4d8507f1e082040Timo Sirainen }
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen (void)close(fd[0]);
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen client = i_new(struct smtp_client, 1);
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen client->f = *file_r = fdopen(fd[1], "w");
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen if (client->f == NULL)
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen i_fatal("fdopen() failed: %m");
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen return client;
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen}
6f73af3a3a6ee900c7e736874587968d76a20bc0Timo Sirainen
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainenint smtp_client_close(struct smtp_client *client)
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen{
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen int ret = EX_TEMPFAIL, status;
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen fclose(client->f);
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen if (client->pid == (pid_t)-1) {
a2cbf1d392ee983520451bc9b849a490f28ac298Timo Sirainen /* smtp_client_open() failed already */
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen } else if (waitpid(client->pid, &status, 0) < 0)
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen i_error("waitpid() failed: %m");
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen else if (WIFEXITED(status)) {
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen ret = WEXITSTATUS(status);
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen if (ret != 0) {
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen i_error("Sendmail process terminated abnormally, "
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen "exit status %d", ret);
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen }
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen } else if (WIFSIGNALED(status)) {
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen i_error("Sendmail process terminated abnormally, "
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen "signal %d", WTERMSIG(status));
123962e68d25c1c5b04160d70f65ef6a66298d40Timo Sirainen } else if (WIFSTOPPED(status)) {
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen i_error("Sendmail process stopped, signal %d",
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen WSTOPSIG(status));
2674b4f0cf8f3c203d8e56b29735f5e267038dafTimo Sirainen } else {
eac3948d67eff8623d51aeaea9eca582f3aec677Timo Sirainen i_error("Sendmail process terminated abnormally, "
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen "return status %d", status);
e8acc691a14a6d0884c5ca9aa4d8507f1e082040Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
48136ae5a0eb49daa44e343553f3688a500307e2Timo Sirainen