busybox/mailutils/mail.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * helper routines
   4 *
   5 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
   6 *
   7 * Licensed under GPLv2, see file LICENSE in this source tree.
   8 */
   9#if defined(__linux__)
  10# include <sys/prctl.h>
  11# define PRCTL
  12#elif defined(__FreeBSD__)
  13# include <sys/procctl.h>
  14# define PROCCTL
  15#endif
  16#include "libbb.h"
  17#include "mail.h"
  18
  19// common signal handler
  20static void signal_handler(int signo)
  21{
  22        if (SIGALRM == signo) {
  23                bb_simple_error_msg_and_die("timed out");
  24        }
  25
  26        // SIGCHLD. reap the zombie if we expect one
  27        if (G.helper_pid == 0)
  28                return;
  29#define status signo
  30        if (safe_waitpid(G.helper_pid, &status, WNOHANG) > 0) {
  31                G.helper_pid = 0;
  32                if (WIFSIGNALED(status))
  33                        bb_error_msg_and_die("helper killed by signal %u", WTERMSIG(status));
  34                if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
  35                        bb_error_msg_and_die("helper exited (%u)", WEXITSTATUS(status));
  36        }
  37#undef status
  38}
  39
  40void FAST_FUNC launch_helper(const char **argv)
  41{
  42        pid_t pid;
  43        struct fd_pair child_out;
  44        struct fd_pair child_in;
  45
  46        xpiped_pair(child_out);
  47        xpiped_pair(child_in);
  48
  49        // NB: handler must be installed before vfork
  50        bb_signals(0
  51                + (1 << SIGCHLD)
  52                + (1 << SIGALRM)
  53                , signal_handler);
  54
  55        fflush_all();
  56        pid = xvfork();
  57        if (pid == 0) {
  58                // child
  59                close(child_in.wr);
  60                close(child_out.rd);
  61                xmove_fd(child_in.rd, STDIN_FILENO);
  62                xmove_fd(child_out.wr, STDOUT_FILENO);
  63                // if parent dies, get SIGTERM
  64#if defined(PRCTL)
  65                prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0);
  66#elif defined(PROCCTL)
  67                {
  68                        int signum = SIGTERM;
  69                        procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signum);
  70                }
  71#endif
  72                // try to execute connection helper
  73                // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec
  74                BB_EXECVP_or_die((char**)argv);
  75        }
  76        G.helper_pid = pid;
  77        close(child_out.wr);
  78        close(child_in.rd);
  79        xmove_fd(child_out.rd, STDIN_FILENO);
  80        xmove_fd(child_in.wr, STDOUT_FILENO);
  81
  82        // parent goes on
  83}
  84
  85void FAST_FUNC send_r_n(const char *s)
  86{
  87        if (G.verbose)
  88                bb_error_msg("send:'%s'", s);
  89        printf("%s\r\n", s);
  90}
  91
  92char* FAST_FUNC send_mail_command(const char *fmt, const char *param)
  93{
  94        char *msg;
  95        if (G.timeout)
  96                alarm(G.timeout);
  97        msg = (char*)fmt;
  98        if (fmt) {
  99                msg = xasprintf(fmt, param);
 100                send_r_n(msg);
 101        }
 102        fflush_all();
 103        return msg;
 104}
 105
 106// NB: parse_url can modify url[] (despite const), but only if '@' is there
 107/*
 108static char* FAST_FUNC parse_url(char *url, char **user, char **pass)
 109{
 110        // parse [user[:pass]@]host
 111        // return host
 112        char *s = strchr(url, '@');
 113        *user = *pass = NULL;
 114        if (s) {
 115                *s++ = '\0';
 116                *user = url;
 117                url = s;
 118                s = strchr(*user, ':');
 119                if (s) {
 120                        *s++ = '\0';
 121                        *pass = s;
 122                }
 123        }
 124        return url;
 125}
 126*/
 127
 128static void encode_n_base64(const char *fname, const char *text, size_t len)
 129{
 130        enum {
 131                SRC_BUF_SIZE = 57,  /* This *MUST* be a multiple of 3 */
 132                DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
 133        };
 134#define src_buf text
 135        char src[SRC_BUF_SIZE];
 136        FILE *fp = fp;
 137        char dst_buf[DST_BUF_SIZE + 1];
 138
 139        if (fname) {
 140                fp = (NOT_LONE_DASH(fname)) ? xfopen_for_read(fname) : stdin;
 141                src_buf = src;
 142        }
 143
 144        while (1) {
 145                size_t size;
 146                if (fname) {
 147                        size = fread((char *)src_buf, 1, SRC_BUF_SIZE, fp);
 148                        if ((ssize_t)size < 0)
 149                                bb_simple_perror_msg_and_die(bb_msg_read_error);
 150                } else {
 151                        size = len;
 152                        if (len > SRC_BUF_SIZE)
 153                                size = SRC_BUF_SIZE;
 154                }
 155                if (!size)
 156                        break;
 157                // encode the buffer we just read in
 158                bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64);
 159                if (fname) {
 160                        puts("");
 161                } else {
 162                        src_buf += size;
 163                        len -= size;
 164                }
 165                fwrite(dst_buf, 1, 4 * ((size + 2) / 3), stdout);
 166        }
 167        if (fname && NOT_LONE_DASH(fname))
 168                fclose(fp);
 169#undef src_buf
 170}
 171
 172void FAST_FUNC printstr_base64(const char *text)
 173{
 174        encode_n_base64(NULL, text, strlen(text));
 175}
 176
 177void FAST_FUNC printbuf_base64(const char *text, unsigned len)
 178{
 179        encode_n_base64(NULL, text, len);
 180}
 181
 182void FAST_FUNC printfile_base64(const char *fname)
 183{
 184        encode_n_base64(fname, NULL, 0);
 185}
 186
 187/*
 188 * get username and password from a file descriptor
 189 */
 190void FAST_FUNC get_cred_or_die(int fd)
 191{
 192        if (isatty(fd)) {
 193                G.user = bb_ask_noecho(fd, /* timeout: */ 0, "User: ");
 194                G.pass = bb_ask_noecho(fd, /* timeout: */ 0, "Password: ");
 195        } else {
 196                G.user = xmalloc_reads(fd, /* maxsize: */ NULL);
 197                G.pass = xmalloc_reads(fd, /* maxsize: */ NULL);
 198        }
 199        if (!G.user || !*G.user || !G.pass)
 200                bb_simple_error_msg_and_die("no username or password");
 201}
 202