masqmail-0.2
diff src/masqmail.c @ 0:08114f7dcc23
this is masqmail-0.2.21 from oliver kurth
author | meillo@marmaro.de |
---|---|
date | Fri, 26 Sep 2008 17:05:23 +0200 |
parents | |
children | 26e34ae9a3e3 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/masqmail.c Fri Sep 26 17:05:23 2008 +0200 1.3 @@ -0,0 +1,828 @@ 1.4 +/* MasqMail 1.5 + Copyright (C) 1999-2001 Oliver Kurth 1.6 + 1.7 + This program is free software; you can redistribute it and/or modify 1.8 + it under the terms of the GNU General Public License as published by 1.9 + the Free Software Foundation; either version 2 of the License, or 1.10 + (at your option) any later version. 1.11 + 1.12 + This program is distributed in the hope that it will be useful, 1.13 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.15 + GNU General Public License for more details. 1.16 + 1.17 + You should have received a copy of the GNU General Public License 1.18 + along with this program; if not, write to the Free Software 1.19 + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1.20 +*/ 1.21 + 1.22 +#include <stdio.h> 1.23 +#include <errno.h> 1.24 +#include <stdlib.h> 1.25 +#include <string.h> 1.26 +#include <unistd.h> 1.27 +#include <sys/types.h> 1.28 +#include <sys/socket.h> 1.29 +#include <sys/time.h> 1.30 +#include <netinet/in.h> 1.31 +#include <netdb.h> 1.32 +#include <syslog.h> 1.33 +#include <signal.h> 1.34 + 1.35 +#include <glib.h> 1.36 + 1.37 +#include "masqmail.h" 1.38 + 1.39 +/* mutually exclusive modes. Note that there is neither a 'get' mode 1.40 + nor a 'queue daemon' mode. These, as well as the distinction beween 1.41 + the two (non exclusive) daemon (queue and listen) modes are handled 1.42 + by flags.*/ 1.43 +typedef enum _mta_mode 1.44 +{ 1.45 + MODE_ACCEPT = 0, /* accept message on stdin */ 1.46 + MODE_DAEMON, /* run as daemon */ 1.47 + MODE_RUNQUEUE, /* single queue run, online or offline */ 1.48 + MODE_GET_DAEMON, /* run as get (retrieve) daemon */ 1.49 + MODE_SMTP, /* accept SMTP on stdin */ 1.50 + MODE_LIST, /* list queue */ 1.51 + MODE_MCMD, /* do queue manipulation */ 1.52 + MODE_VERSION, /* show version */ 1.53 + MODE_BI, /* fake ;-) */ 1.54 + MODE_NONE /* to prevent default MODE_ACCEPT */ 1.55 +}mta_mode; 1.56 + 1.57 +char *pidfile = NULL; 1.58 +volatile int sigterm_in_progress = 0; 1.59 + 1.60 +static 1.61 +void sigterm_handler(int sig) 1.62 +{ 1.63 + if(sigterm_in_progress) 1.64 + raise(sig); 1.65 + sigterm_in_progress = 1; 1.66 + 1.67 + if(pidfile){ 1.68 + uid_t uid; 1.69 + uid = seteuid(0); 1.70 + if(unlink(pidfile) != 0) 1.71 + logwrite(LOG_WARNING, "could not delete pid file %s: %s\n", 1.72 + pidfile, strerror(errno)); 1.73 + seteuid(uid); /* we exit anyway after this, just to be sure */ 1.74 + } 1.75 + 1.76 + signal(sig, SIG_DFL); 1.77 + raise(sig); 1.78 +} 1.79 + 1.80 +#ifdef ENABLE_IDENT /* so far used for that only */ 1.81 +static 1.82 +gboolean is_in_netlist(gchar *host, GList *netlist) 1.83 +{ 1.84 + guint hostip = inet_addr(host); 1.85 + struct in_addr addr; 1.86 + 1.87 + addr.s_addr = hostip; 1.88 + if(addr.s_addr != INADDR_NONE){ 1.89 + GList *node; 1.90 + foreach(netlist, node){ 1.91 + struct in_addr *net = (struct in_addr *)(node->data); 1.92 + if((addr.s_addr & net->s_addr) == net->s_addr) 1.93 + return TRUE; 1.94 + } 1.95 + } 1.96 + return FALSE; 1.97 +} 1.98 +#endif 1.99 + 1.100 +gchar *get_optarg(char *argv[], gint argc, gint *argp, gint *pos) 1.101 +{ 1.102 + if(argv[*argp][*pos]) 1.103 + return &(argv[*argp][*pos]); 1.104 + else{ 1.105 + if(*argp+1 < argc){ 1.106 + if(argv[(*argp)+1][0] != '-'){ 1.107 + (*argp)++; 1.108 + *pos = 0; 1.109 + return &(argv[*argp][*pos]); 1.110 + } 1.111 + } 1.112 + } 1.113 + return NULL; 1.114 +} 1.115 + 1.116 +gchar *get_progname(gchar *arg0) 1.117 +{ 1.118 + gchar *p = arg0 + strlen(arg0) - 1; 1.119 + while(p > arg0){ 1.120 + if(*p == '/') 1.121 + return p+1; 1.122 + p--; 1.123 + } 1.124 + return p; 1.125 +} 1.126 + 1.127 +gboolean write_pidfile(gchar *name) 1.128 +{ 1.129 + FILE *fptr; 1.130 + 1.131 + if((fptr = fopen(name, "wt"))){ 1.132 + fprintf(fptr, "%d\n", getpid()); 1.133 + fclose(fptr); 1.134 + pidfile = strdup(name); 1.135 + return TRUE; 1.136 + } 1.137 + logwrite(LOG_WARNING, "could not write pid file: %s\n", strerror(errno)); 1.138 + return FALSE; 1.139 +} 1.140 + 1.141 +static 1.142 +void mode_daemon(gboolean do_listen, gint queue_interval, char *argv[]) 1.143 +{ 1.144 + guint pid; 1.145 + 1.146 + /* daemon */ 1.147 + if(!conf.run_as_user){ 1.148 + if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){ 1.149 + fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER); 1.150 + exit(EXIT_FAILURE); 1.151 + } 1.152 + } 1.153 + 1.154 + if((pid = fork()) > 0){ 1.155 + exit(EXIT_SUCCESS); 1.156 + }else if(pid < 0){ 1.157 + logwrite(LOG_ALERT, "could not fork!"); 1.158 + exit(EXIT_FAILURE); 1.159 + } 1.160 + 1.161 + signal(SIGTERM, sigterm_handler); 1.162 + write_pidfile(PIDFILEDIR"/masqmail.pid"); 1.163 + 1.164 + conf.do_verbose = FALSE; 1.165 + 1.166 + fclose(stdin); 1.167 + fclose(stdout); 1.168 + fclose(stderr); 1.169 + 1.170 + listen_port(do_listen ? conf.listen_addresses : NULL, 1.171 + queue_interval, argv); 1.172 +} 1.173 + 1.174 +#ifdef ENABLE_POP3 1.175 +static 1.176 +void mode_get_daemon(gint get_interval, char *argv[]) 1.177 +{ 1.178 + guint pid; 1.179 + 1.180 + /* daemon */ 1.181 + if(!conf.run_as_user){ 1.182 + if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){ 1.183 + fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER); 1.184 + exit(EXIT_FAILURE); 1.185 + } 1.186 + } 1.187 + 1.188 + if((pid = fork()) > 0){ 1.189 + exit(EXIT_SUCCESS); 1.190 + }else if(pid < 0){ 1.191 + logwrite(LOG_ALERT, "could not fork!"); 1.192 + exit(EXIT_FAILURE); 1.193 + } 1.194 + 1.195 + signal(SIGTERM, sigterm_handler); 1.196 + write_pidfile(PIDFILEDIR"/masqmail-get.pid"); 1.197 + 1.198 + conf.do_verbose = FALSE; 1.199 + 1.200 + fclose(stdin); 1.201 + fclose(stdout); 1.202 + fclose(stderr); 1.203 + 1.204 + get_daemon(get_interval, argv); 1.205 +} 1.206 +#endif 1.207 + 1.208 +#ifdef ENABLE_SMTP_SERVER 1.209 +static void mode_smtp() 1.210 +{ 1.211 + /* accept smtp message on stdin */ 1.212 + /* write responses to stderr. */ 1.213 + 1.214 + struct sockaddr_in saddr; 1.215 + gchar *peername = NULL; 1.216 + int dummy = sizeof(saddr); 1.217 +#ifdef ENABLE_IDENT 1.218 + gchar *ident = NULL; 1.219 +#endif 1.220 + 1.221 + conf.do_verbose = FALSE; 1.222 + 1.223 + if(!conf.run_as_user){ 1.224 + seteuid(conf.orig_uid); 1.225 + setegid(conf.orig_gid); 1.226 + } 1.227 + 1.228 + DEBUG(5) debugf("accepting smtp message on stdin\n"); 1.229 + 1.230 + if(getpeername(0, (struct sockaddr *)(&saddr), &dummy) == 0){ 1.231 + peername = g_strdup(inet_ntoa(saddr.sin_addr)); 1.232 +#ifdef ENABLE_IDENT 1.233 + { 1.234 + gchar *id = NULL; 1.235 + if((id = (gchar *)ident_id(0, 60))){ 1.236 + ident = g_strdup(id); 1.237 + } 1.238 + } 1.239 +#endif 1.240 + }else if(errno != ENOTSOCK) 1.241 + exit(EXIT_FAILURE); 1.242 + 1.243 + //smtp_in(stdin, stdout, peername); 1.244 + smtp_in(stdin, stderr, peername, NULL); 1.245 + 1.246 +#ifdef ENABLE_IDENT 1.247 + if(ident) g_free(ident); 1.248 +#endif 1.249 +} 1.250 +#endif 1.251 + 1.252 +static void mode_accept(address *return_path, gchar *full_sender_name, 1.253 + guint accept_flags, char **addresses, int addr_cnt) 1.254 +{ 1.255 + /* accept message on stdin */ 1.256 + accept_error err; 1.257 + message *msg = create_message(); 1.258 + gint i; 1.259 + 1.260 + if(return_path != NULL){ 1.261 + if((conf.orig_uid != 0) && 1.262 + (conf.orig_uid != conf.mail_uid) && 1.263 + (!is_ingroup(conf.orig_uid, conf.mail_gid))){ 1.264 + fprintf(stderr, 1.265 + "must be in root, %s or in group %s for setting return path.\n", 1.266 + DEF_MAIL_USER, DEF_MAIL_GROUP); 1.267 + exit(EXIT_FAILURE); 1.268 + } 1.269 + } 1.270 + 1.271 + if(!conf.run_as_user){ 1.272 + seteuid(conf.orig_uid); 1.273 + setegid(conf.orig_gid); 1.274 + } 1.275 + 1.276 + DEBUG(5) debugf("accepting message on stdin\n"); 1.277 + 1.278 + msg->received_prot = PROT_LOCAL; 1.279 + for(i = 0; i < addr_cnt; i++){ 1.280 + if(addresses[i][0] != '|') 1.281 + msg->rcpt_list = 1.282 + g_list_append(msg->rcpt_list, 1.283 + create_address_qualified(addresses[i], TRUE, conf.host_name)); 1.284 + else{ 1.285 + logwrite(LOG_ALERT, "no pipe allowed as recipient address: %s\n", addresses[i]); 1.286 + exit(EXIT_FAILURE); 1.287 + } 1.288 + } 1.289 + 1.290 + /* -f option */ 1.291 + msg->return_path = return_path; 1.292 + 1.293 + /* -F option */ 1.294 + msg->full_sender_name = full_sender_name; 1.295 + 1.296 + if((err = accept_message(stdin, msg, accept_flags)) == AERR_OK){ 1.297 + if(spool_write(msg, TRUE)){ 1.298 + pid_t pid; 1.299 + logwrite(LOG_NOTICE, "%s <= %s with %s\n", 1.300 + msg->uid, addr_string(msg->return_path), 1.301 + prot_names[PROT_LOCAL]); 1.302 + 1.303 + if(!conf.do_queue){ 1.304 + 1.305 + if((pid = fork()) == 0){ 1.306 + 1.307 + conf.do_verbose = FALSE; 1.308 + 1.309 + fclose(stdin); 1.310 + fclose(stdout); 1.311 + fclose(stderr); 1.312 + 1.313 + if(deliver(msg)){ 1.314 + exit(EXIT_SUCCESS); 1.315 + }else 1.316 + exit(EXIT_FAILURE); 1.317 + }else if(pid < 0){ 1.318 + logwrite(LOG_ALERT, "could not fork for delivery, id = %s", 1.319 + msg->uid); 1.320 + } 1.321 + } 1.322 + }else{ 1.323 + fprintf(stderr, "Could not write spool file\n"); 1.324 + exit(EXIT_FAILURE); 1.325 + } 1.326 + }else{ 1.327 + switch(err){ 1.328 + case AERR_EOF: 1.329 + fprintf(stderr, "unexpected EOF.\n"); 1.330 + exit(EXIT_FAILURE); 1.331 + case AERR_NORCPT: 1.332 + fprintf(stderr, "no recipients.\n"); 1.333 + exit(EXIT_FAILURE); 1.334 + default: 1.335 + /* should never happen: */ 1.336 + fprintf(stderr, "Unknown error (%d)\r\n", err); 1.337 + exit(EXIT_FAILURE); 1.338 + } 1.339 + exit(EXIT_FAILURE); 1.340 + } 1.341 +} 1.342 + 1.343 +int 1.344 +main(int argc, char *argv[]) 1.345 +{ 1.346 + /* cmd line flags */ 1.347 + gchar *conf_file = CONF_FILE; 1.348 + gint arg = 1; 1.349 + gboolean do_get = FALSE; 1.350 + gboolean do_get_online = FALSE; 1.351 + 1.352 + gboolean do_listen = FALSE; 1.353 + gboolean do_runq = FALSE; 1.354 + gboolean do_runq_online = FALSE; 1.355 + 1.356 + gboolean do_queue = FALSE; 1.357 + 1.358 + gboolean do_verbose = FALSE; 1.359 + gint debug_level = -1; 1.360 + 1.361 + mta_mode mta_mode = MODE_ACCEPT; 1.362 + 1.363 + gint queue_interval = 0; 1.364 + gint get_interval = 0; 1.365 + gboolean opt_t = FALSE; 1.366 + gboolean opt_i = FALSE; 1.367 + gboolean opt_odb = FALSE; 1.368 + gboolean opt_oem = FALSE; 1.369 + gboolean exit_failure = FALSE; 1.370 + 1.371 + gchar *M_cmd = NULL; 1.372 + 1.373 + gint exit_code = EXIT_SUCCESS; 1.374 + gchar *route_name = NULL; 1.375 + gchar *get_name = NULL; 1.376 + gchar *progname; 1.377 + gchar *f_address = NULL; 1.378 + gchar *full_sender_name = NULL; 1.379 + address *return_path = NULL; /* may be changed by -f option */ 1.380 + 1.381 + progname = get_progname(argv[0]); 1.382 + 1.383 + if(strcmp(progname, "mailq") == 0) 1.384 + { mta_mode = MODE_LIST; } 1.385 + else if(strcmp(progname, "mailrm") == 0) 1.386 + { mta_mode = MODE_MCMD; M_cmd = "rm"; } 1.387 + else if(strcmp(progname, "runq") == 0) 1.388 + { mta_mode = MODE_RUNQUEUE; do_runq = TRUE; } 1.389 + else if(strcmp(progname, "rmail") == 0) 1.390 + { mta_mode = MODE_ACCEPT; opt_i = TRUE; } 1.391 + else if(strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0) 1.392 + { mta_mode = MODE_SMTP; } 1.393 + 1.394 + /* parse cmd line */ 1.395 + while(arg < argc){ 1.396 + gint pos = 0; 1.397 + if((argv[arg][pos] == '-') && (argv[arg][pos+1] != '-')){ 1.398 + pos++; 1.399 + switch(argv[arg][pos++]){ 1.400 + case 'b': 1.401 + switch(argv[arg][pos++]){ 1.402 + case 'd': 1.403 + do_listen = TRUE; 1.404 + mta_mode = MODE_DAEMON; 1.405 + break; 1.406 + case 'i': 1.407 + /* ignored */ 1.408 + mta_mode = MODE_BI; 1.409 + break; 1.410 + case 's': 1.411 + mta_mode = MODE_SMTP; 1.412 + break; 1.413 + case 'p': 1.414 + mta_mode = MODE_LIST; 1.415 + break; 1.416 + case 'V': 1.417 + mta_mode = MODE_VERSION; 1.418 + break; 1.419 + default: 1.420 + fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.421 + exit(EXIT_FAILURE); 1.422 + } 1.423 + break; 1.424 + case 'B': 1.425 + /* we ignore this and throw the argument away */ 1.426 + get_optarg(argv, argc, &arg, &pos); 1.427 + break; 1.428 + case 'C': 1.429 + if(!(conf_file = get_optarg(argv, argc, &arg, &pos))){ 1.430 + fprintf(stderr, "-C requires a filename as argument.\n"); 1.431 + exit(EXIT_FAILURE); 1.432 + } 1.433 + break; 1.434 + case 'F': 1.435 + { 1.436 + full_sender_name = get_optarg(argv, argc, &arg, &pos); 1.437 + if(!full_sender_name){ 1.438 + fprintf(stderr, "-F requires a name as an argument\n"); 1.439 + exit(EXIT_FAILURE); 1.440 + } 1.441 + } 1.442 + break; 1.443 + case 'd': 1.444 + if(getuid() == 0){ 1.445 + char *lvl = get_optarg(argv, argc, &arg, &pos); 1.446 + if(lvl) 1.447 + debug_level = atoi(lvl); 1.448 + else{ 1.449 + fprintf(stderr, "-d requires a number as an argument.\n"); 1.450 + exit(EXIT_FAILURE); 1.451 + } 1.452 + }else{ 1.453 + fprintf(stderr, "only root may set the debug level.\n"); 1.454 + exit(EXIT_FAILURE); 1.455 + } 1.456 + break; 1.457 + case 'f': 1.458 + /* set return path */ 1.459 + { 1.460 + gchar *address; 1.461 + address = get_optarg(argv, argc, &arg, &pos); 1.462 + if(address){ 1.463 + f_address = g_strdup(address); 1.464 + }else{ 1.465 + fprintf(stderr, "-f requires an address as an argument\n"); 1.466 + exit(EXIT_FAILURE); 1.467 + } 1.468 + } 1.469 + break; 1.470 + case 'g': 1.471 + do_get = TRUE; 1.472 + if(!mta_mode) mta_mode = MODE_NONE; /* to prevent default MODE_ACCEPT */ 1.473 + if(argv[arg][pos] == 'o'){ 1.474 + pos++; 1.475 + do_get_online = TRUE; 1.476 + /* can be NULL, then we use online detection method */ 1.477 + route_name = get_optarg(argv, argc, &arg, &pos); 1.478 + 1.479 + if(route_name != NULL){ 1.480 + if(isdigit(route_name[0])){ 1.481 + get_interval = time_interval(route_name, &pos); 1.482 + route_name = get_optarg(argv, argc, &arg, &pos); 1.483 + mta_mode = MODE_GET_DAEMON; 1.484 + do_get = FALSE; 1.485 + } 1.486 + } 1.487 + }else{ 1.488 + if((optarg = get_optarg(argv, argc, &arg, &pos))){ 1.489 + get_name = get_optarg(argv, argc, &arg, &pos); 1.490 + } 1.491 + } 1.492 + break; 1.493 + case 'i': 1.494 + if(argv[arg][pos] == 0){ 1.495 + opt_i = TRUE; 1.496 + exit_failure = FALSE; /* may override -oem */ 1.497 + }else{ 1.498 + fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.499 + exit(EXIT_FAILURE); 1.500 + } 1.501 + break; 1.502 + case 'M': 1.503 + { 1.504 + mta_mode = MODE_MCMD; 1.505 + M_cmd = g_strdup(&(argv[arg][pos])); 1.506 + } 1.507 + break; 1.508 + case 'o': 1.509 + switch(argv[arg][pos++]){ 1.510 + case 'e': 1.511 + if(argv[arg][pos++] == 'm') /* -oem */ 1.512 + if(!opt_i) exit_failure = TRUE; 1.513 + opt_oem = TRUE; 1.514 + break; 1.515 + case 'd': 1.516 + if(argv[arg][pos] == 'b') /* -odb */ 1.517 + opt_odb = TRUE; 1.518 + else if(argv[arg][pos] == 'q') /* -odq */ 1.519 + do_queue = TRUE; 1.520 + break; 1.521 + case 'i': 1.522 + opt_i = TRUE; 1.523 + exit_failure = FALSE; /* may override -oem */ 1.524 + break; 1.525 + } 1.526 + break; 1.527 + 1.528 + case 'q': 1.529 + { 1.530 + gchar *optarg; 1.531 + 1.532 + do_runq = TRUE; 1.533 + mta_mode = MODE_RUNQUEUE; 1.534 + if(argv[arg][pos] == 'o'){ 1.535 + pos++; 1.536 + do_runq = FALSE; 1.537 + do_runq_online = TRUE; 1.538 + /* can be NULL, then we use online detection method */ 1.539 + route_name = get_optarg(argv, argc, &arg, &pos); 1.540 + }else if((optarg = get_optarg(argv, argc, &arg, &pos))){ 1.541 + mta_mode = MODE_DAEMON; 1.542 + queue_interval = time_interval(optarg, &pos); 1.543 + } 1.544 + } 1.545 + break; 1.546 + case 't': 1.547 + if(argv[arg][pos] == 0){ 1.548 + opt_t = TRUE; 1.549 + }else{ 1.550 + fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.551 + exit(EXIT_FAILURE); 1.552 + } 1.553 + break; 1.554 + case 'v': 1.555 + do_verbose = TRUE; 1.556 + break; 1.557 + default: 1.558 + fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.559 + exit(EXIT_FAILURE); 1.560 + } 1.561 + }else{ 1.562 + if(argv[arg][pos+1] == '-'){ 1.563 + if(argv[arg][pos+2] != '\0'){ 1.564 + fprintf(stderr, "unrecognized option '%s'\n", argv[arg]); 1.565 + exit(EXIT_FAILURE); 1.566 + } 1.567 + arg++; 1.568 + } 1.569 + break; 1.570 + } 1.571 + arg++; 1.572 + } 1.573 + 1.574 + if(mta_mode == MODE_VERSION){ 1.575 + gchar *with_resolver = "", *with_smtp_server = "", *with_pop3 = "", *with_auth = "", 1.576 + *with_maildir = "", *with_ident = "", *with_mserver = ""; 1.577 + 1.578 +#ifdef ENABLE_RESOLVER 1.579 + with_resolver = " +resolver"; 1.580 +#endif 1.581 +#ifdef ENABLE_SMTP_SERVER 1.582 + with_smtp_server = " +smtp-server"; 1.583 +#endif 1.584 +#ifdef ENABLE_POP3 1.585 + with_pop3 = " +pop3"; 1.586 +#endif 1.587 +#ifdef ENABLE_AUTH 1.588 + with_auth = " +auth"; 1.589 +#endif 1.590 +#ifdef ENABLE_MAILDIR 1.591 + with_maildir = " +maildir"; 1.592 +#endif 1.593 +#ifdef ENABLE_IDENT 1.594 + with_ident = " +ident"; 1.595 +#endif 1.596 +#ifdef ENABLE_MSERVER 1.597 + with_mserver = " +mserver"; 1.598 +#endif 1.599 + 1.600 + printf("%s %s%s%s%s%s%s%s%s\n", PACKAGE, VERSION, 1.601 + with_resolver, with_smtp_server, with_pop3, with_auth, 1.602 + with_maildir, with_ident, with_mserver); 1.603 + 1.604 + exit(EXIT_SUCCESS); 1.605 + } 1.606 + 1.607 + /* initialize random generator */ 1.608 + srand(time(NULL)); 1.609 + /* ignore SIGPIPE signal */ 1.610 + signal(SIGPIPE, SIG_IGN); 1.611 + 1.612 + /* close all possibly open file descriptors */ 1.613 + { 1.614 + int i, max_fd = sysconf(_SC_OPEN_MAX); 1.615 + 1.616 + if(max_fd <= 0) max_fd = 64; 1.617 + for(i = 3; i < max_fd; i++) 1.618 + close(i); 1.619 + } 1.620 + 1.621 + init_conf(); 1.622 + 1.623 + /* if we are not privileged, and the config file was changed we 1.624 + implicetely set the the run_as_user flag and give up all 1.625 + privileges. 1.626 + 1.627 + So it is possible for a user to run his own daemon without 1.628 + breaking security. 1.629 + */ 1.630 + if(strcmp(conf_file, CONF_FILE) != 0){ 1.631 + if(conf.orig_uid != 0){ 1.632 + conf.run_as_user = TRUE; 1.633 + seteuid(conf.orig_uid); 1.634 + setegid(conf.orig_gid); 1.635 + setuid(conf.orig_uid); 1.636 + setgid(conf.orig_gid); 1.637 + } 1.638 + } 1.639 + 1.640 + read_conf(conf_file); 1.641 + 1.642 + if(do_queue) conf.do_queue = TRUE; 1.643 + if(do_verbose) conf.do_verbose = TRUE; 1.644 + if(debug_level >= 0) /* if >= 0, it was given by argument */ 1.645 + conf.debug_level = debug_level; 1.646 + 1.647 + chdir("/"); 1.648 + 1.649 + if(!conf.run_as_user){ 1.650 + if(setgid(0) != 0){ 1.651 + fprintf(stderr, 1.652 + "could not set gid to 0. Is the setuid bit set? : %s\n", 1.653 + strerror(errno)); 1.654 + exit(EXIT_FAILURE); 1.655 + } 1.656 + if(setuid(0) != 0){ 1.657 + fprintf(stderr, 1.658 + "could not gain root privileges. Is the setuid bit set? : %s\n", 1.659 + strerror(errno)); 1.660 + exit(EXIT_FAILURE); 1.661 + } 1.662 + } 1.663 + 1.664 + if(!logopen()){ 1.665 + fprintf(stderr, "could not open log file\n"); 1.666 + exit(EXIT_FAILURE); 1.667 + } 1.668 + 1.669 + DEBUG(1) debugf("masqmail %s starting\n", VERSION); 1.670 + 1.671 + DEBUG(5){ 1.672 + gchar **str = argv; 1.673 + debugf("args: \n"); 1.674 + while(*str){ 1.675 + debugf("%s \n", *str); 1.676 + str++; 1.677 + } 1.678 + } 1.679 + DEBUG(5) debugf("queue_interval = %d\n", queue_interval); 1.680 + 1.681 + if(f_address){ 1.682 + return_path = create_address_qualified(f_address, TRUE, conf.host_name); 1.683 + g_free(f_address); 1.684 + if(!return_path){ 1.685 + fprintf(stderr, "invalid RFC821 address: %s\n", f_address); 1.686 + exit(EXIT_FAILURE); 1.687 + } 1.688 + } 1.689 + 1.690 + if(do_get){ 1.691 +#ifdef ENABLE_POP3 1.692 + if((mta_mode == MODE_NONE) || (mta_mode == MODE_RUNQUEUE)){ 1.693 + 1.694 + set_identity(conf.orig_uid, "getting mail"); 1.695 + 1.696 + if(do_get_online){ 1.697 + if(route_name != NULL){ 1.698 + conf.online_detect = g_strdup("argument"); 1.699 + set_online_name(route_name); 1.700 + } 1.701 + get_online(); 1.702 + }else{ 1.703 + if(get_name) 1.704 + get_from_name(get_name); 1.705 + else 1.706 + get_all(); 1.707 + } 1.708 + }else{ 1.709 + logwrite(LOG_ALERT, "get (-g) only allowed alone or together with queue run (-q)\n"); 1.710 + } 1.711 +#else 1.712 + fprintf(stderr, "get (pop) support not compiled in\n"); 1.713 +#endif 1.714 + } 1.715 + 1.716 + switch(mta_mode){ 1.717 + case MODE_DAEMON: 1.718 + mode_daemon(do_listen, queue_interval, argv); 1.719 + break; 1.720 + case MODE_RUNQUEUE: 1.721 + { 1.722 + /* queue runs */ 1.723 + set_identity(conf.orig_uid, "queue run"); 1.724 + 1.725 + if(do_runq) 1.726 + exit_code = queue_run() ? EXIT_SUCCESS : EXIT_FAILURE; 1.727 + 1.728 + if(do_runq_online){ 1.729 + if(route_name != NULL){ 1.730 + conf.online_detect = g_strdup("argument"); 1.731 + set_online_name(route_name); 1.732 + } 1.733 + exit_code = queue_run_online() ? EXIT_SUCCESS : EXIT_FAILURE; 1.734 + } 1.735 + } 1.736 + break; 1.737 + case MODE_GET_DAEMON: 1.738 +#ifdef ENABLE_POP3 1.739 + if(route_name != NULL){ 1.740 + conf.online_detect = g_strdup("argument"); 1.741 + set_online_name(route_name); 1.742 + } 1.743 + mode_get_daemon(get_interval, argv); 1.744 +#endif 1.745 + break; 1.746 + 1.747 + case MODE_SMTP: 1.748 +#ifdef ENABLE_SMTP_SERVER 1.749 + mode_smtp(); 1.750 +#else 1.751 + fprintf(stderr, "smtp server support not compiled in\n"); 1.752 +#endif 1.753 + break; 1.754 + case MODE_LIST: 1.755 + 1.756 + queue_list(); 1.757 + break; 1.758 + 1.759 + case MODE_BI: 1.760 + 1.761 + exit(EXIT_SUCCESS); 1.762 + break; /* well... */ 1.763 + 1.764 + case MODE_MCMD: 1.765 + if(strcmp(M_cmd, "rm") == 0){ 1.766 + gboolean ok = FALSE; 1.767 + 1.768 + set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL); 1.769 + 1.770 + if(is_privileged_user(conf.orig_uid)){ 1.771 + for(; arg < argc; arg++){ 1.772 + if(queue_delete(argv[arg])) 1.773 + ok = TRUE; 1.774 + } 1.775 + }else{ 1.776 + struct passwd *pw = getpwuid(conf.orig_uid); 1.777 + if(pw){ 1.778 + for(; arg < argc; arg++){ 1.779 + message *msg = msg_spool_read(argv[arg], FALSE); 1.780 +#ifdef ENABLE_IDENT 1.781 + if(((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)) || 1.782 + is_in_netlist(msg->received_host, conf.ident_trusted_nets)){ 1.783 +#else 1.784 + if((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)){ 1.785 +#endif 1.786 + if(msg->ident){ 1.787 + if(strcmp(pw->pw_name, msg->ident) == 0){ 1.788 + if(queue_delete(argv[arg])) 1.789 + ok = TRUE; 1.790 + }else{ 1.791 + fprintf(stderr, "you do not own message id %s\n", argv[arg]); 1.792 + } 1.793 + }else 1.794 + fprintf(stderr, "message %s does not have an ident.\n", argv[arg]); 1.795 + }else{ 1.796 + fprintf(stderr, "message %s was not received locally or from a trusted network.\n", argv[arg]); 1.797 + } 1.798 + } 1.799 + }else{ 1.800 + fprintf(stderr, "could not find a passwd entry for uid %d: %s\n", conf.orig_uid, strerror(errno)); 1.801 + } 1.802 + } 1.803 + exit(ok ? EXIT_SUCCESS : EXIT_FAILURE); 1.804 + }else{ 1.805 + fprintf(stderr, "unknown command %s\n", M_cmd); 1.806 + exit(EXIT_FAILURE); 1.807 + } 1.808 + break; 1.809 + 1.810 + case MODE_ACCEPT: 1.811 + { 1.812 + guint accept_flags = 1.813 + (opt_t ? ACC_DEL_RCPTS|ACC_DEL_BCC|ACC_RCPT_FROM_HEAD : ACC_HEAD_FROM_RCPT) | 1.814 + (opt_i ? ACC_NODOT_TERM : ACC_NODOT_RELAX); 1.815 + 1.816 + mode_accept(return_path, full_sender_name, accept_flags, &(argv[arg]), argc - arg); 1.817 + 1.818 + exit(exit_failure ? EXIT_FAILURE : EXIT_SUCCESS); 1.819 + } 1.820 + break; 1.821 + case MODE_NONE: 1.822 + break; 1.823 + default: 1.824 + fprintf(stderr, "unknown mode: %d\n", mta_mode); 1.825 + break; 1.826 + } 1.827 + 1.828 + logclose(); 1.829 + 1.830 + exit(exit_code); 1.831 +}