meillo@0: /* MasqMail meillo@0: Copyright (C) 1999-2001 Oliver Kurth meillo@0: meillo@0: This program is free software; you can redistribute it and/or modify meillo@0: it under the terms of the GNU General Public License as published by meillo@0: the Free Software Foundation; either version 2 of the License, or meillo@0: (at your option) any later version. meillo@0: meillo@0: This program is distributed in the hope that it will be useful, meillo@0: but WITHOUT ANY WARRANTY; without even the implied warranty of meillo@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the meillo@0: GNU General Public License for more details. meillo@0: meillo@0: You should have received a copy of the GNU General Public License meillo@0: along with this program; if not, write to the Free Software meillo@0: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. meillo@0: */ meillo@0: meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: #include meillo@0: meillo@0: #include meillo@0: meillo@0: #include "masqmail.h" meillo@0: meillo@0: /* mutually exclusive modes. Note that there is neither a 'get' mode meillo@0: nor a 'queue daemon' mode. These, as well as the distinction beween meillo@0: the two (non exclusive) daemon (queue and listen) modes are handled meillo@0: by flags.*/ meillo@0: typedef enum _mta_mode meillo@0: { meillo@0: MODE_ACCEPT = 0, /* accept message on stdin */ meillo@0: MODE_DAEMON, /* run as daemon */ meillo@0: MODE_RUNQUEUE, /* single queue run, online or offline */ meillo@0: MODE_GET_DAEMON, /* run as get (retrieve) daemon */ meillo@0: MODE_SMTP, /* accept SMTP on stdin */ meillo@0: MODE_LIST, /* list queue */ meillo@0: MODE_MCMD, /* do queue manipulation */ meillo@0: MODE_VERSION, /* show version */ meillo@0: MODE_BI, /* fake ;-) */ meillo@0: MODE_NONE /* to prevent default MODE_ACCEPT */ meillo@0: }mta_mode; meillo@0: meillo@0: char *pidfile = NULL; meillo@0: volatile int sigterm_in_progress = 0; meillo@0: meillo@0: static meillo@0: void sigterm_handler(int sig) meillo@0: { meillo@0: if(sigterm_in_progress) meillo@0: raise(sig); meillo@0: sigterm_in_progress = 1; meillo@0: meillo@0: if(pidfile){ meillo@0: uid_t uid; meillo@0: uid = seteuid(0); meillo@0: if(unlink(pidfile) != 0) meillo@0: logwrite(LOG_WARNING, "could not delete pid file %s: %s\n", meillo@0: pidfile, strerror(errno)); meillo@0: seteuid(uid); /* we exit anyway after this, just to be sure */ meillo@0: } meillo@0: meillo@0: signal(sig, SIG_DFL); meillo@0: raise(sig); meillo@0: } meillo@0: meillo@0: #ifdef ENABLE_IDENT /* so far used for that only */ meillo@0: static meillo@0: gboolean is_in_netlist(gchar *host, GList *netlist) meillo@0: { meillo@0: guint hostip = inet_addr(host); meillo@0: struct in_addr addr; meillo@0: meillo@0: addr.s_addr = hostip; meillo@0: if(addr.s_addr != INADDR_NONE){ meillo@0: GList *node; meillo@0: foreach(netlist, node){ meillo@0: struct in_addr *net = (struct in_addr *)(node->data); meillo@0: if((addr.s_addr & net->s_addr) == net->s_addr) meillo@0: return TRUE; meillo@0: } meillo@0: } meillo@0: return FALSE; meillo@0: } meillo@0: #endif meillo@0: meillo@0: gchar *get_optarg(char *argv[], gint argc, gint *argp, gint *pos) meillo@0: { meillo@0: if(argv[*argp][*pos]) meillo@0: return &(argv[*argp][*pos]); meillo@0: else{ meillo@0: if(*argp+1 < argc){ meillo@0: if(argv[(*argp)+1][0] != '-'){ meillo@0: (*argp)++; meillo@0: *pos = 0; meillo@0: return &(argv[*argp][*pos]); meillo@0: } meillo@0: } meillo@0: } meillo@0: return NULL; meillo@0: } meillo@0: meillo@0: gchar *get_progname(gchar *arg0) meillo@0: { meillo@0: gchar *p = arg0 + strlen(arg0) - 1; meillo@0: while(p > arg0){ meillo@0: if(*p == '/') meillo@0: return p+1; meillo@0: p--; meillo@0: } meillo@0: return p; meillo@0: } meillo@0: meillo@0: gboolean write_pidfile(gchar *name) meillo@0: { meillo@0: FILE *fptr; meillo@0: meillo@0: if((fptr = fopen(name, "wt"))){ meillo@0: fprintf(fptr, "%d\n", getpid()); meillo@0: fclose(fptr); meillo@0: pidfile = strdup(name); meillo@0: return TRUE; meillo@0: } meillo@0: logwrite(LOG_WARNING, "could not write pid file: %s\n", strerror(errno)); meillo@0: return FALSE; meillo@0: } meillo@0: meillo@0: static meillo@0: void mode_daemon(gboolean do_listen, gint queue_interval, char *argv[]) meillo@0: { meillo@0: guint pid; meillo@0: meillo@0: /* daemon */ meillo@0: if(!conf.run_as_user){ meillo@0: if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){ meillo@0: fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: meillo@0: if((pid = fork()) > 0){ meillo@0: exit(EXIT_SUCCESS); meillo@0: }else if(pid < 0){ meillo@0: logwrite(LOG_ALERT, "could not fork!"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: meillo@0: signal(SIGTERM, sigterm_handler); meillo@0: write_pidfile(PIDFILEDIR"/masqmail.pid"); meillo@0: meillo@0: conf.do_verbose = FALSE; meillo@0: meillo@0: fclose(stdin); meillo@0: fclose(stdout); meillo@0: fclose(stderr); meillo@0: meillo@0: listen_port(do_listen ? conf.listen_addresses : NULL, meillo@0: queue_interval, argv); meillo@0: } meillo@0: meillo@0: #ifdef ENABLE_POP3 meillo@0: static meillo@0: void mode_get_daemon(gint get_interval, char *argv[]) meillo@0: { meillo@0: guint pid; meillo@0: meillo@0: /* daemon */ meillo@0: if(!conf.run_as_user){ meillo@0: if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){ meillo@0: fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: meillo@0: if((pid = fork()) > 0){ meillo@0: exit(EXIT_SUCCESS); meillo@0: }else if(pid < 0){ meillo@0: logwrite(LOG_ALERT, "could not fork!"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: meillo@0: signal(SIGTERM, sigterm_handler); meillo@0: write_pidfile(PIDFILEDIR"/masqmail-get.pid"); meillo@0: meillo@0: conf.do_verbose = FALSE; meillo@0: meillo@0: fclose(stdin); meillo@0: fclose(stdout); meillo@0: fclose(stderr); meillo@0: meillo@0: get_daemon(get_interval, argv); meillo@0: } meillo@0: #endif meillo@0: meillo@0: #ifdef ENABLE_SMTP_SERVER meillo@0: static void mode_smtp() meillo@0: { meillo@0: /* accept smtp message on stdin */ meillo@0: /* write responses to stderr. */ meillo@0: meillo@0: struct sockaddr_in saddr; meillo@0: gchar *peername = NULL; meillo@0: int dummy = sizeof(saddr); meillo@0: #ifdef ENABLE_IDENT meillo@0: gchar *ident = NULL; meillo@0: #endif meillo@0: meillo@0: conf.do_verbose = FALSE; meillo@0: meillo@0: if(!conf.run_as_user){ meillo@0: seteuid(conf.orig_uid); meillo@0: setegid(conf.orig_gid); meillo@0: } meillo@0: meillo@0: DEBUG(5) debugf("accepting smtp message on stdin\n"); meillo@0: meillo@0: if(getpeername(0, (struct sockaddr *)(&saddr), &dummy) == 0){ meillo@0: peername = g_strdup(inet_ntoa(saddr.sin_addr)); meillo@0: #ifdef ENABLE_IDENT meillo@0: { meillo@0: gchar *id = NULL; meillo@0: if((id = (gchar *)ident_id(0, 60))){ meillo@0: ident = g_strdup(id); meillo@0: } meillo@0: } meillo@0: #endif meillo@0: }else if(errno != ENOTSOCK) meillo@0: exit(EXIT_FAILURE); meillo@0: meillo@0: //smtp_in(stdin, stdout, peername); meillo@0: smtp_in(stdin, stderr, peername, NULL); meillo@0: meillo@0: #ifdef ENABLE_IDENT meillo@0: if(ident) g_free(ident); meillo@0: #endif meillo@0: } meillo@0: #endif meillo@0: meillo@0: static void mode_accept(address *return_path, gchar *full_sender_name, meillo@0: guint accept_flags, char **addresses, int addr_cnt) meillo@0: { meillo@0: /* accept message on stdin */ meillo@0: accept_error err; meillo@0: message *msg = create_message(); meillo@0: gint i; meillo@0: meillo@0: if(return_path != NULL){ meillo@0: if((conf.orig_uid != 0) && meillo@0: (conf.orig_uid != conf.mail_uid) && meillo@0: (!is_ingroup(conf.orig_uid, conf.mail_gid))){ meillo@0: fprintf(stderr, meillo@0: "must be in root, %s or in group %s for setting return path.\n", meillo@0: DEF_MAIL_USER, DEF_MAIL_GROUP); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: meillo@0: if(!conf.run_as_user){ meillo@0: seteuid(conf.orig_uid); meillo@0: setegid(conf.orig_gid); meillo@0: } meillo@0: meillo@0: DEBUG(5) debugf("accepting message on stdin\n"); meillo@0: meillo@0: msg->received_prot = PROT_LOCAL; meillo@0: for(i = 0; i < addr_cnt; i++){ meillo@0: if(addresses[i][0] != '|') meillo@0: msg->rcpt_list = meillo@0: g_list_append(msg->rcpt_list, meillo@0: create_address_qualified(addresses[i], TRUE, conf.host_name)); meillo@0: else{ meillo@0: logwrite(LOG_ALERT, "no pipe allowed as recipient address: %s\n", addresses[i]); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: meillo@0: /* -f option */ meillo@0: msg->return_path = return_path; meillo@0: meillo@0: /* -F option */ meillo@0: msg->full_sender_name = full_sender_name; meillo@0: meillo@0: if((err = accept_message(stdin, msg, accept_flags)) == AERR_OK){ meillo@0: if(spool_write(msg, TRUE)){ meillo@0: pid_t pid; meillo@0: logwrite(LOG_NOTICE, "%s <= %s with %s\n", meillo@0: msg->uid, addr_string(msg->return_path), meillo@0: prot_names[PROT_LOCAL]); meillo@0: meillo@0: if(!conf.do_queue){ meillo@0: meillo@0: if((pid = fork()) == 0){ meillo@0: meillo@0: conf.do_verbose = FALSE; meillo@0: meillo@0: fclose(stdin); meillo@0: fclose(stdout); meillo@0: fclose(stderr); meillo@0: meillo@0: if(deliver(msg)){ meillo@0: exit(EXIT_SUCCESS); meillo@0: }else meillo@0: exit(EXIT_FAILURE); meillo@0: }else if(pid < 0){ meillo@0: logwrite(LOG_ALERT, "could not fork for delivery, id = %s", meillo@0: msg->uid); meillo@0: } meillo@0: } meillo@0: }else{ meillo@0: fprintf(stderr, "Could not write spool file\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: }else{ meillo@0: switch(err){ meillo@0: case AERR_EOF: meillo@0: fprintf(stderr, "unexpected EOF.\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: case AERR_NORCPT: meillo@0: fprintf(stderr, "no recipients.\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: default: meillo@0: /* should never happen: */ meillo@0: fprintf(stderr, "Unknown error (%d)\r\n", err); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: meillo@0: int meillo@0: main(int argc, char *argv[]) meillo@0: { meillo@0: /* cmd line flags */ meillo@0: gchar *conf_file = CONF_FILE; meillo@0: gint arg = 1; meillo@0: gboolean do_get = FALSE; meillo@0: gboolean do_get_online = FALSE; meillo@0: meillo@0: gboolean do_listen = FALSE; meillo@0: gboolean do_runq = FALSE; meillo@0: gboolean do_runq_online = FALSE; meillo@0: meillo@0: gboolean do_queue = FALSE; meillo@0: meillo@0: gboolean do_verbose = FALSE; meillo@0: gint debug_level = -1; meillo@0: meillo@0: mta_mode mta_mode = MODE_ACCEPT; meillo@0: meillo@0: gint queue_interval = 0; meillo@0: gint get_interval = 0; meillo@0: gboolean opt_t = FALSE; meillo@0: gboolean opt_i = FALSE; meillo@0: gboolean opt_odb = FALSE; meillo@0: gboolean opt_oem = FALSE; meillo@0: gboolean exit_failure = FALSE; meillo@0: meillo@0: gchar *M_cmd = NULL; meillo@0: meillo@0: gint exit_code = EXIT_SUCCESS; meillo@0: gchar *route_name = NULL; meillo@0: gchar *get_name = NULL; meillo@0: gchar *progname; meillo@0: gchar *f_address = NULL; meillo@0: gchar *full_sender_name = NULL; meillo@0: address *return_path = NULL; /* may be changed by -f option */ meillo@0: meillo@0: progname = get_progname(argv[0]); meillo@0: meillo@0: if(strcmp(progname, "mailq") == 0) meillo@0: { mta_mode = MODE_LIST; } meillo@0: else if(strcmp(progname, "mailrm") == 0) meillo@0: { mta_mode = MODE_MCMD; M_cmd = "rm"; } meillo@0: else if(strcmp(progname, "runq") == 0) meillo@0: { mta_mode = MODE_RUNQUEUE; do_runq = TRUE; } meillo@0: else if(strcmp(progname, "rmail") == 0) meillo@0: { mta_mode = MODE_ACCEPT; opt_i = TRUE; } meillo@0: else if(strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0) meillo@0: { mta_mode = MODE_SMTP; } meillo@0: meillo@0: /* parse cmd line */ meillo@0: while(arg < argc){ meillo@0: gint pos = 0; meillo@0: if((argv[arg][pos] == '-') && (argv[arg][pos+1] != '-')){ meillo@0: pos++; meillo@0: switch(argv[arg][pos++]){ meillo@0: case 'b': meillo@0: switch(argv[arg][pos++]){ meillo@0: case 'd': meillo@0: do_listen = TRUE; meillo@0: mta_mode = MODE_DAEMON; meillo@0: break; meillo@0: case 'i': meillo@0: /* ignored */ meillo@0: mta_mode = MODE_BI; meillo@0: break; meillo@0: case 's': meillo@0: mta_mode = MODE_SMTP; meillo@0: break; meillo@0: case 'p': meillo@0: mta_mode = MODE_LIST; meillo@0: break; meillo@0: case 'V': meillo@0: mta_mode = MODE_VERSION; meillo@0: break; meillo@0: default: meillo@0: fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: break; meillo@0: case 'B': meillo@0: /* we ignore this and throw the argument away */ meillo@0: get_optarg(argv, argc, &arg, &pos); meillo@0: break; meillo@0: case 'C': meillo@0: if(!(conf_file = get_optarg(argv, argc, &arg, &pos))){ meillo@0: fprintf(stderr, "-C requires a filename as argument.\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: break; meillo@0: case 'F': meillo@0: { meillo@0: full_sender_name = get_optarg(argv, argc, &arg, &pos); meillo@0: if(!full_sender_name){ meillo@0: fprintf(stderr, "-F requires a name as an argument\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: break; meillo@0: case 'd': meillo@0: if(getuid() == 0){ meillo@0: char *lvl = get_optarg(argv, argc, &arg, &pos); meillo@0: if(lvl) meillo@0: debug_level = atoi(lvl); meillo@0: else{ meillo@0: fprintf(stderr, "-d requires a number as an argument.\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: }else{ meillo@0: fprintf(stderr, "only root may set the debug level.\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: break; meillo@0: case 'f': meillo@0: /* set return path */ meillo@0: { meillo@0: gchar *address; meillo@0: address = get_optarg(argv, argc, &arg, &pos); meillo@0: if(address){ meillo@0: f_address = g_strdup(address); meillo@0: }else{ meillo@0: fprintf(stderr, "-f requires an address as an argument\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: break; meillo@0: case 'g': meillo@0: do_get = TRUE; meillo@0: if(!mta_mode) mta_mode = MODE_NONE; /* to prevent default MODE_ACCEPT */ meillo@0: if(argv[arg][pos] == 'o'){ meillo@0: pos++; meillo@0: do_get_online = TRUE; meillo@0: /* can be NULL, then we use online detection method */ meillo@0: route_name = get_optarg(argv, argc, &arg, &pos); meillo@0: meillo@0: if(route_name != NULL){ meillo@0: if(isdigit(route_name[0])){ meillo@0: get_interval = time_interval(route_name, &pos); meillo@0: route_name = get_optarg(argv, argc, &arg, &pos); meillo@0: mta_mode = MODE_GET_DAEMON; meillo@0: do_get = FALSE; meillo@0: } meillo@0: } meillo@0: }else{ meillo@0: if((optarg = get_optarg(argv, argc, &arg, &pos))){ meillo@0: get_name = get_optarg(argv, argc, &arg, &pos); meillo@0: } meillo@0: } meillo@0: break; meillo@0: case 'i': meillo@0: if(argv[arg][pos] == 0){ meillo@0: opt_i = TRUE; meillo@0: exit_failure = FALSE; /* may override -oem */ meillo@0: }else{ meillo@0: fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: break; meillo@0: case 'M': meillo@0: { meillo@0: mta_mode = MODE_MCMD; meillo@0: M_cmd = g_strdup(&(argv[arg][pos])); meillo@0: } meillo@0: break; meillo@0: case 'o': meillo@0: switch(argv[arg][pos++]){ meillo@0: case 'e': meillo@0: if(argv[arg][pos++] == 'm') /* -oem */ meillo@0: if(!opt_i) exit_failure = TRUE; meillo@0: opt_oem = TRUE; meillo@0: break; meillo@0: case 'd': meillo@0: if(argv[arg][pos] == 'b') /* -odb */ meillo@0: opt_odb = TRUE; meillo@0: else if(argv[arg][pos] == 'q') /* -odq */ meillo@0: do_queue = TRUE; meillo@0: break; meillo@0: case 'i': meillo@0: opt_i = TRUE; meillo@0: exit_failure = FALSE; /* may override -oem */ meillo@0: break; meillo@0: } meillo@0: break; meillo@0: meillo@0: case 'q': meillo@0: { meillo@0: gchar *optarg; meillo@0: meillo@0: do_runq = TRUE; meillo@0: mta_mode = MODE_RUNQUEUE; meillo@0: if(argv[arg][pos] == 'o'){ meillo@0: pos++; meillo@0: do_runq = FALSE; meillo@0: do_runq_online = TRUE; meillo@0: /* can be NULL, then we use online detection method */ meillo@0: route_name = get_optarg(argv, argc, &arg, &pos); meillo@0: }else if((optarg = get_optarg(argv, argc, &arg, &pos))){ meillo@0: mta_mode = MODE_DAEMON; meillo@0: queue_interval = time_interval(optarg, &pos); meillo@0: } meillo@0: } meillo@0: break; meillo@0: case 't': meillo@0: if(argv[arg][pos] == 0){ meillo@0: opt_t = TRUE; meillo@0: }else{ meillo@0: fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: break; meillo@0: case 'v': meillo@0: do_verbose = TRUE; meillo@0: break; meillo@0: default: meillo@0: fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: }else{ meillo@0: if(argv[arg][pos+1] == '-'){ meillo@0: if(argv[arg][pos+2] != '\0'){ meillo@0: fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: arg++; meillo@0: } meillo@0: break; meillo@0: } meillo@0: arg++; meillo@0: } meillo@0: meillo@0: if(mta_mode == MODE_VERSION){ meillo@0: gchar *with_resolver = "", *with_smtp_server = "", *with_pop3 = "", *with_auth = "", meillo@0: *with_maildir = "", *with_ident = "", *with_mserver = ""; meillo@0: meillo@0: #ifdef ENABLE_RESOLVER meillo@0: with_resolver = " +resolver"; meillo@0: #endif meillo@0: #ifdef ENABLE_SMTP_SERVER meillo@0: with_smtp_server = " +smtp-server"; meillo@0: #endif meillo@0: #ifdef ENABLE_POP3 meillo@0: with_pop3 = " +pop3"; meillo@0: #endif meillo@0: #ifdef ENABLE_AUTH meillo@0: with_auth = " +auth"; meillo@0: #endif meillo@0: #ifdef ENABLE_MAILDIR meillo@0: with_maildir = " +maildir"; meillo@0: #endif meillo@0: #ifdef ENABLE_IDENT meillo@0: with_ident = " +ident"; meillo@0: #endif meillo@0: #ifdef ENABLE_MSERVER meillo@0: with_mserver = " +mserver"; meillo@0: #endif meillo@0: meillo@0: printf("%s %s%s%s%s%s%s%s%s\n", PACKAGE, VERSION, meillo@0: with_resolver, with_smtp_server, with_pop3, with_auth, meillo@0: with_maildir, with_ident, with_mserver); meillo@0: meillo@0: exit(EXIT_SUCCESS); meillo@0: } meillo@0: meillo@0: /* initialize random generator */ meillo@0: srand(time(NULL)); meillo@0: /* ignore SIGPIPE signal */ meillo@0: signal(SIGPIPE, SIG_IGN); meillo@0: meillo@0: /* close all possibly open file descriptors */ meillo@0: { meillo@0: int i, max_fd = sysconf(_SC_OPEN_MAX); meillo@0: meillo@0: if(max_fd <= 0) max_fd = 64; meillo@0: for(i = 3; i < max_fd; i++) meillo@0: close(i); meillo@0: } meillo@0: meillo@0: init_conf(); meillo@0: meillo@0: /* if we are not privileged, and the config file was changed we meillo@0: implicetely set the the run_as_user flag and give up all meillo@0: privileges. meillo@0: meillo@0: So it is possible for a user to run his own daemon without meillo@0: breaking security. meillo@0: */ meillo@0: if(strcmp(conf_file, CONF_FILE) != 0){ meillo@0: if(conf.orig_uid != 0){ meillo@0: conf.run_as_user = TRUE; meillo@0: seteuid(conf.orig_uid); meillo@0: setegid(conf.orig_gid); meillo@0: setuid(conf.orig_uid); meillo@0: setgid(conf.orig_gid); meillo@0: } meillo@0: } meillo@0: meillo@0: read_conf(conf_file); meillo@0: meillo@0: if(do_queue) conf.do_queue = TRUE; meillo@0: if(do_verbose) conf.do_verbose = TRUE; meillo@0: if(debug_level >= 0) /* if >= 0, it was given by argument */ meillo@0: conf.debug_level = debug_level; meillo@0: meillo@0: chdir("/"); meillo@0: meillo@0: if(!conf.run_as_user){ meillo@0: if(setgid(0) != 0){ meillo@0: fprintf(stderr, meillo@0: "could not set gid to 0. Is the setuid bit set? : %s\n", meillo@0: strerror(errno)); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: if(setuid(0) != 0){ meillo@0: fprintf(stderr, meillo@0: "could not gain root privileges. Is the setuid bit set? : %s\n", meillo@0: strerror(errno)); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: meillo@0: if(!logopen()){ meillo@0: fprintf(stderr, "could not open log file\n"); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: meillo@0: DEBUG(1) debugf("masqmail %s starting\n", VERSION); meillo@0: meillo@0: DEBUG(5){ meillo@0: gchar **str = argv; meillo@0: debugf("args: \n"); meillo@0: while(*str){ meillo@0: debugf("%s \n", *str); meillo@0: str++; meillo@0: } meillo@0: } meillo@0: DEBUG(5) debugf("queue_interval = %d\n", queue_interval); meillo@0: meillo@0: if(f_address){ meillo@0: return_path = create_address_qualified(f_address, TRUE, conf.host_name); meillo@0: g_free(f_address); meillo@0: if(!return_path){ meillo@0: fprintf(stderr, "invalid RFC821 address: %s\n", f_address); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: } meillo@0: meillo@0: if(do_get){ meillo@0: #ifdef ENABLE_POP3 meillo@0: if((mta_mode == MODE_NONE) || (mta_mode == MODE_RUNQUEUE)){ meillo@0: meillo@0: set_identity(conf.orig_uid, "getting mail"); meillo@0: meillo@0: if(do_get_online){ meillo@0: if(route_name != NULL){ meillo@0: conf.online_detect = g_strdup("argument"); meillo@0: set_online_name(route_name); meillo@0: } meillo@0: get_online(); meillo@0: }else{ meillo@0: if(get_name) meillo@0: get_from_name(get_name); meillo@0: else meillo@0: get_all(); meillo@0: } meillo@0: }else{ meillo@0: logwrite(LOG_ALERT, "get (-g) only allowed alone or together with queue run (-q)\n"); meillo@0: } meillo@0: #else meillo@0: fprintf(stderr, "get (pop) support not compiled in\n"); meillo@0: #endif meillo@0: } meillo@0: meillo@0: switch(mta_mode){ meillo@0: case MODE_DAEMON: meillo@0: mode_daemon(do_listen, queue_interval, argv); meillo@0: break; meillo@0: case MODE_RUNQUEUE: meillo@0: { meillo@0: /* queue runs */ meillo@0: set_identity(conf.orig_uid, "queue run"); meillo@0: meillo@0: if(do_runq) meillo@0: exit_code = queue_run() ? EXIT_SUCCESS : EXIT_FAILURE; meillo@0: meillo@0: if(do_runq_online){ meillo@0: if(route_name != NULL){ meillo@0: conf.online_detect = g_strdup("argument"); meillo@0: set_online_name(route_name); meillo@0: } meillo@0: exit_code = queue_run_online() ? EXIT_SUCCESS : EXIT_FAILURE; meillo@0: } meillo@0: } meillo@0: break; meillo@0: case MODE_GET_DAEMON: meillo@0: #ifdef ENABLE_POP3 meillo@0: if(route_name != NULL){ meillo@0: conf.online_detect = g_strdup("argument"); meillo@0: set_online_name(route_name); meillo@0: } meillo@0: mode_get_daemon(get_interval, argv); meillo@0: #endif meillo@0: break; meillo@0: meillo@0: case MODE_SMTP: meillo@0: #ifdef ENABLE_SMTP_SERVER meillo@0: mode_smtp(); meillo@0: #else meillo@0: fprintf(stderr, "smtp server support not compiled in\n"); meillo@0: #endif meillo@0: break; meillo@0: case MODE_LIST: meillo@0: meillo@0: queue_list(); meillo@0: break; meillo@0: meillo@0: case MODE_BI: meillo@0: meillo@0: exit(EXIT_SUCCESS); meillo@0: break; /* well... */ meillo@0: meillo@0: case MODE_MCMD: meillo@0: if(strcmp(M_cmd, "rm") == 0){ meillo@0: gboolean ok = FALSE; meillo@0: meillo@0: set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL); meillo@0: meillo@0: if(is_privileged_user(conf.orig_uid)){ meillo@0: for(; arg < argc; arg++){ meillo@0: if(queue_delete(argv[arg])) meillo@0: ok = TRUE; meillo@0: } meillo@0: }else{ meillo@0: struct passwd *pw = getpwuid(conf.orig_uid); meillo@0: if(pw){ meillo@0: for(; arg < argc; arg++){ meillo@0: message *msg = msg_spool_read(argv[arg], FALSE); meillo@0: #ifdef ENABLE_IDENT meillo@0: if(((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)) || meillo@0: is_in_netlist(msg->received_host, conf.ident_trusted_nets)){ meillo@0: #else meillo@0: if((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)){ meillo@0: #endif meillo@0: if(msg->ident){ meillo@0: if(strcmp(pw->pw_name, msg->ident) == 0){ meillo@0: if(queue_delete(argv[arg])) meillo@0: ok = TRUE; meillo@0: }else{ meillo@0: fprintf(stderr, "you do not own message id %s\n", argv[arg]); meillo@0: } meillo@0: }else meillo@0: fprintf(stderr, "message %s does not have an ident.\n", argv[arg]); meillo@0: }else{ meillo@0: fprintf(stderr, "message %s was not received locally or from a trusted network.\n", argv[arg]); meillo@0: } meillo@0: } meillo@0: }else{ meillo@0: fprintf(stderr, "could not find a passwd entry for uid %d: %s\n", conf.orig_uid, strerror(errno)); meillo@0: } meillo@0: } meillo@0: exit(ok ? EXIT_SUCCESS : EXIT_FAILURE); meillo@0: }else{ meillo@0: fprintf(stderr, "unknown command %s\n", M_cmd); meillo@0: exit(EXIT_FAILURE); meillo@0: } meillo@0: break; meillo@0: meillo@0: case MODE_ACCEPT: meillo@0: { meillo@0: guint accept_flags = meillo@0: (opt_t ? ACC_DEL_RCPTS|ACC_DEL_BCC|ACC_RCPT_FROM_HEAD : ACC_HEAD_FROM_RCPT) | meillo@0: (opt_i ? ACC_NODOT_TERM : ACC_NODOT_RELAX); meillo@0: meillo@0: mode_accept(return_path, full_sender_name, accept_flags, &(argv[arg]), argc - arg); meillo@0: meillo@0: exit(exit_failure ? EXIT_FAILURE : EXIT_SUCCESS); meillo@0: } meillo@0: break; meillo@0: case MODE_NONE: meillo@0: break; meillo@0: default: meillo@0: fprintf(stderr, "unknown mode: %d\n", mta_mode); meillo@0: break; meillo@0: } meillo@0: meillo@0: logclose(); meillo@0: meillo@0: exit(exit_code); meillo@0: }