masqmail

annotate src/masqmail.c @ 2:653aef34b225

removed distribution specific data
author meillo@marmaro.de
date Fri, 26 Sep 2008 21:26:36 +0200
parents
children 26e34ae9a3e3
rev   line source
meillo@0 1 /* MasqMail
meillo@0 2 Copyright (C) 1999-2001 Oliver Kurth
meillo@0 3
meillo@0 4 This program is free software; you can redistribute it and/or modify
meillo@0 5 it under the terms of the GNU General Public License as published by
meillo@0 6 the Free Software Foundation; either version 2 of the License, or
meillo@0 7 (at your option) any later version.
meillo@0 8
meillo@0 9 This program is distributed in the hope that it will be useful,
meillo@0 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@0 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@0 12 GNU General Public License for more details.
meillo@0 13
meillo@0 14 You should have received a copy of the GNU General Public License
meillo@0 15 along with this program; if not, write to the Free Software
meillo@0 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
meillo@0 17 */
meillo@0 18
meillo@0 19 #include <stdio.h>
meillo@0 20 #include <errno.h>
meillo@0 21 #include <stdlib.h>
meillo@0 22 #include <string.h>
meillo@0 23 #include <unistd.h>
meillo@0 24 #include <sys/types.h>
meillo@0 25 #include <sys/socket.h>
meillo@0 26 #include <sys/time.h>
meillo@0 27 #include <netinet/in.h>
meillo@0 28 #include <netdb.h>
meillo@0 29 #include <syslog.h>
meillo@0 30 #include <signal.h>
meillo@0 31
meillo@0 32 #include <glib.h>
meillo@0 33
meillo@0 34 #include "masqmail.h"
meillo@0 35
meillo@0 36 /* mutually exclusive modes. Note that there is neither a 'get' mode
meillo@0 37 nor a 'queue daemon' mode. These, as well as the distinction beween
meillo@0 38 the two (non exclusive) daemon (queue and listen) modes are handled
meillo@0 39 by flags.*/
meillo@0 40 typedef enum _mta_mode
meillo@0 41 {
meillo@0 42 MODE_ACCEPT = 0, /* accept message on stdin */
meillo@0 43 MODE_DAEMON, /* run as daemon */
meillo@0 44 MODE_RUNQUEUE, /* single queue run, online or offline */
meillo@0 45 MODE_GET_DAEMON, /* run as get (retrieve) daemon */
meillo@0 46 MODE_SMTP, /* accept SMTP on stdin */
meillo@0 47 MODE_LIST, /* list queue */
meillo@0 48 MODE_MCMD, /* do queue manipulation */
meillo@0 49 MODE_VERSION, /* show version */
meillo@0 50 MODE_BI, /* fake ;-) */
meillo@0 51 MODE_NONE /* to prevent default MODE_ACCEPT */
meillo@0 52 }mta_mode;
meillo@0 53
meillo@0 54 char *pidfile = NULL;
meillo@0 55 volatile int sigterm_in_progress = 0;
meillo@0 56
meillo@0 57 static
meillo@0 58 void sigterm_handler(int sig)
meillo@0 59 {
meillo@0 60 if(sigterm_in_progress)
meillo@0 61 raise(sig);
meillo@0 62 sigterm_in_progress = 1;
meillo@0 63
meillo@0 64 if(pidfile){
meillo@0 65 uid_t uid;
meillo@0 66 uid = seteuid(0);
meillo@0 67 if(unlink(pidfile) != 0)
meillo@0 68 logwrite(LOG_WARNING, "could not delete pid file %s: %s\n",
meillo@0 69 pidfile, strerror(errno));
meillo@0 70 seteuid(uid); /* we exit anyway after this, just to be sure */
meillo@0 71 }
meillo@0 72
meillo@0 73 signal(sig, SIG_DFL);
meillo@0 74 raise(sig);
meillo@0 75 }
meillo@0 76
meillo@0 77 #ifdef ENABLE_IDENT /* so far used for that only */
meillo@0 78 static
meillo@0 79 gboolean is_in_netlist(gchar *host, GList *netlist)
meillo@0 80 {
meillo@0 81 guint hostip = inet_addr(host);
meillo@0 82 struct in_addr addr;
meillo@0 83
meillo@0 84 addr.s_addr = hostip;
meillo@0 85 if(addr.s_addr != INADDR_NONE){
meillo@0 86 GList *node;
meillo@0 87 foreach(netlist, node){
meillo@0 88 struct in_addr *net = (struct in_addr *)(node->data);
meillo@0 89 if((addr.s_addr & net->s_addr) == net->s_addr)
meillo@0 90 return TRUE;
meillo@0 91 }
meillo@0 92 }
meillo@0 93 return FALSE;
meillo@0 94 }
meillo@0 95 #endif
meillo@0 96
meillo@0 97 gchar *get_optarg(char *argv[], gint argc, gint *argp, gint *pos)
meillo@0 98 {
meillo@0 99 if(argv[*argp][*pos])
meillo@0 100 return &(argv[*argp][*pos]);
meillo@0 101 else{
meillo@0 102 if(*argp+1 < argc){
meillo@0 103 if(argv[(*argp)+1][0] != '-'){
meillo@0 104 (*argp)++;
meillo@0 105 *pos = 0;
meillo@0 106 return &(argv[*argp][*pos]);
meillo@0 107 }
meillo@0 108 }
meillo@0 109 }
meillo@0 110 return NULL;
meillo@0 111 }
meillo@0 112
meillo@0 113 gchar *get_progname(gchar *arg0)
meillo@0 114 {
meillo@0 115 gchar *p = arg0 + strlen(arg0) - 1;
meillo@0 116 while(p > arg0){
meillo@0 117 if(*p == '/')
meillo@0 118 return p+1;
meillo@0 119 p--;
meillo@0 120 }
meillo@0 121 return p;
meillo@0 122 }
meillo@0 123
meillo@0 124 gboolean write_pidfile(gchar *name)
meillo@0 125 {
meillo@0 126 FILE *fptr;
meillo@0 127
meillo@0 128 if((fptr = fopen(name, "wt"))){
meillo@0 129 fprintf(fptr, "%d\n", getpid());
meillo@0 130 fclose(fptr);
meillo@0 131 pidfile = strdup(name);
meillo@0 132 return TRUE;
meillo@0 133 }
meillo@0 134 logwrite(LOG_WARNING, "could not write pid file: %s\n", strerror(errno));
meillo@0 135 return FALSE;
meillo@0 136 }
meillo@0 137
meillo@0 138 static
meillo@0 139 void mode_daemon(gboolean do_listen, gint queue_interval, char *argv[])
meillo@0 140 {
meillo@0 141 guint pid;
meillo@0 142
meillo@0 143 /* daemon */
meillo@0 144 if(!conf.run_as_user){
meillo@0 145 if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){
meillo@0 146 fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
meillo@0 147 exit(EXIT_FAILURE);
meillo@0 148 }
meillo@0 149 }
meillo@0 150
meillo@0 151 if((pid = fork()) > 0){
meillo@0 152 exit(EXIT_SUCCESS);
meillo@0 153 }else if(pid < 0){
meillo@0 154 logwrite(LOG_ALERT, "could not fork!");
meillo@0 155 exit(EXIT_FAILURE);
meillo@0 156 }
meillo@0 157
meillo@0 158 signal(SIGTERM, sigterm_handler);
meillo@0 159 write_pidfile(PIDFILEDIR"/masqmail.pid");
meillo@0 160
meillo@0 161 conf.do_verbose = FALSE;
meillo@0 162
meillo@0 163 fclose(stdin);
meillo@0 164 fclose(stdout);
meillo@0 165 fclose(stderr);
meillo@0 166
meillo@0 167 listen_port(do_listen ? conf.listen_addresses : NULL,
meillo@0 168 queue_interval, argv);
meillo@0 169 }
meillo@0 170
meillo@0 171 #ifdef ENABLE_POP3
meillo@0 172 static
meillo@0 173 void mode_get_daemon(gint get_interval, char *argv[])
meillo@0 174 {
meillo@0 175 guint pid;
meillo@0 176
meillo@0 177 /* daemon */
meillo@0 178 if(!conf.run_as_user){
meillo@0 179 if((conf.orig_uid != 0) && (conf.orig_uid != conf.mail_uid)){
meillo@0 180 fprintf(stderr, "must be root or %s for daemon.\n", DEF_MAIL_USER);
meillo@0 181 exit(EXIT_FAILURE);
meillo@0 182 }
meillo@0 183 }
meillo@0 184
meillo@0 185 if((pid = fork()) > 0){
meillo@0 186 exit(EXIT_SUCCESS);
meillo@0 187 }else if(pid < 0){
meillo@0 188 logwrite(LOG_ALERT, "could not fork!");
meillo@0 189 exit(EXIT_FAILURE);
meillo@0 190 }
meillo@0 191
meillo@0 192 signal(SIGTERM, sigterm_handler);
meillo@0 193 write_pidfile(PIDFILEDIR"/masqmail-get.pid");
meillo@0 194
meillo@0 195 conf.do_verbose = FALSE;
meillo@0 196
meillo@0 197 fclose(stdin);
meillo@0 198 fclose(stdout);
meillo@0 199 fclose(stderr);
meillo@0 200
meillo@0 201 get_daemon(get_interval, argv);
meillo@0 202 }
meillo@0 203 #endif
meillo@0 204
meillo@0 205 #ifdef ENABLE_SMTP_SERVER
meillo@0 206 static void mode_smtp()
meillo@0 207 {
meillo@0 208 /* accept smtp message on stdin */
meillo@0 209 /* write responses to stderr. */
meillo@0 210
meillo@0 211 struct sockaddr_in saddr;
meillo@0 212 gchar *peername = NULL;
meillo@0 213 int dummy = sizeof(saddr);
meillo@0 214 #ifdef ENABLE_IDENT
meillo@0 215 gchar *ident = NULL;
meillo@0 216 #endif
meillo@0 217
meillo@0 218 conf.do_verbose = FALSE;
meillo@0 219
meillo@0 220 if(!conf.run_as_user){
meillo@0 221 seteuid(conf.orig_uid);
meillo@0 222 setegid(conf.orig_gid);
meillo@0 223 }
meillo@0 224
meillo@0 225 DEBUG(5) debugf("accepting smtp message on stdin\n");
meillo@0 226
meillo@0 227 if(getpeername(0, (struct sockaddr *)(&saddr), &dummy) == 0){
meillo@0 228 peername = g_strdup(inet_ntoa(saddr.sin_addr));
meillo@0 229 #ifdef ENABLE_IDENT
meillo@0 230 {
meillo@0 231 gchar *id = NULL;
meillo@0 232 if((id = (gchar *)ident_id(0, 60))){
meillo@0 233 ident = g_strdup(id);
meillo@0 234 }
meillo@0 235 }
meillo@0 236 #endif
meillo@0 237 }else if(errno != ENOTSOCK)
meillo@0 238 exit(EXIT_FAILURE);
meillo@0 239
meillo@0 240 //smtp_in(stdin, stdout, peername);
meillo@0 241 smtp_in(stdin, stderr, peername, NULL);
meillo@0 242
meillo@0 243 #ifdef ENABLE_IDENT
meillo@0 244 if(ident) g_free(ident);
meillo@0 245 #endif
meillo@0 246 }
meillo@0 247 #endif
meillo@0 248
meillo@0 249 static void mode_accept(address *return_path, gchar *full_sender_name,
meillo@0 250 guint accept_flags, char **addresses, int addr_cnt)
meillo@0 251 {
meillo@0 252 /* accept message on stdin */
meillo@0 253 accept_error err;
meillo@0 254 message *msg = create_message();
meillo@0 255 gint i;
meillo@0 256
meillo@0 257 if(return_path != NULL){
meillo@0 258 if((conf.orig_uid != 0) &&
meillo@0 259 (conf.orig_uid != conf.mail_uid) &&
meillo@0 260 (!is_ingroup(conf.orig_uid, conf.mail_gid))){
meillo@0 261 fprintf(stderr,
meillo@0 262 "must be in root, %s or in group %s for setting return path.\n",
meillo@0 263 DEF_MAIL_USER, DEF_MAIL_GROUP);
meillo@0 264 exit(EXIT_FAILURE);
meillo@0 265 }
meillo@0 266 }
meillo@0 267
meillo@0 268 if(!conf.run_as_user){
meillo@0 269 seteuid(conf.orig_uid);
meillo@0 270 setegid(conf.orig_gid);
meillo@0 271 }
meillo@0 272
meillo@0 273 DEBUG(5) debugf("accepting message on stdin\n");
meillo@0 274
meillo@0 275 msg->received_prot = PROT_LOCAL;
meillo@0 276 for(i = 0; i < addr_cnt; i++){
meillo@0 277 if(addresses[i][0] != '|')
meillo@0 278 msg->rcpt_list =
meillo@0 279 g_list_append(msg->rcpt_list,
meillo@0 280 create_address_qualified(addresses[i], TRUE, conf.host_name));
meillo@0 281 else{
meillo@0 282 logwrite(LOG_ALERT, "no pipe allowed as recipient address: %s\n", addresses[i]);
meillo@0 283 exit(EXIT_FAILURE);
meillo@0 284 }
meillo@0 285 }
meillo@0 286
meillo@0 287 /* -f option */
meillo@0 288 msg->return_path = return_path;
meillo@0 289
meillo@0 290 /* -F option */
meillo@0 291 msg->full_sender_name = full_sender_name;
meillo@0 292
meillo@0 293 if((err = accept_message(stdin, msg, accept_flags)) == AERR_OK){
meillo@0 294 if(spool_write(msg, TRUE)){
meillo@0 295 pid_t pid;
meillo@0 296 logwrite(LOG_NOTICE, "%s <= %s with %s\n",
meillo@0 297 msg->uid, addr_string(msg->return_path),
meillo@0 298 prot_names[PROT_LOCAL]);
meillo@0 299
meillo@0 300 if(!conf.do_queue){
meillo@0 301
meillo@0 302 if((pid = fork()) == 0){
meillo@0 303
meillo@0 304 conf.do_verbose = FALSE;
meillo@0 305
meillo@0 306 fclose(stdin);
meillo@0 307 fclose(stdout);
meillo@0 308 fclose(stderr);
meillo@0 309
meillo@0 310 if(deliver(msg)){
meillo@0 311 exit(EXIT_SUCCESS);
meillo@0 312 }else
meillo@0 313 exit(EXIT_FAILURE);
meillo@0 314 }else if(pid < 0){
meillo@0 315 logwrite(LOG_ALERT, "could not fork for delivery, id = %s",
meillo@0 316 msg->uid);
meillo@0 317 }
meillo@0 318 }
meillo@0 319 }else{
meillo@0 320 fprintf(stderr, "Could not write spool file\n");
meillo@0 321 exit(EXIT_FAILURE);
meillo@0 322 }
meillo@0 323 }else{
meillo@0 324 switch(err){
meillo@0 325 case AERR_EOF:
meillo@0 326 fprintf(stderr, "unexpected EOF.\n");
meillo@0 327 exit(EXIT_FAILURE);
meillo@0 328 case AERR_NORCPT:
meillo@0 329 fprintf(stderr, "no recipients.\n");
meillo@0 330 exit(EXIT_FAILURE);
meillo@0 331 default:
meillo@0 332 /* should never happen: */
meillo@0 333 fprintf(stderr, "Unknown error (%d)\r\n", err);
meillo@0 334 exit(EXIT_FAILURE);
meillo@0 335 }
meillo@0 336 exit(EXIT_FAILURE);
meillo@0 337 }
meillo@0 338 }
meillo@0 339
meillo@0 340 int
meillo@0 341 main(int argc, char *argv[])
meillo@0 342 {
meillo@0 343 /* cmd line flags */
meillo@0 344 gchar *conf_file = CONF_FILE;
meillo@0 345 gint arg = 1;
meillo@0 346 gboolean do_get = FALSE;
meillo@0 347 gboolean do_get_online = FALSE;
meillo@0 348
meillo@0 349 gboolean do_listen = FALSE;
meillo@0 350 gboolean do_runq = FALSE;
meillo@0 351 gboolean do_runq_online = FALSE;
meillo@0 352
meillo@0 353 gboolean do_queue = FALSE;
meillo@0 354
meillo@0 355 gboolean do_verbose = FALSE;
meillo@0 356 gint debug_level = -1;
meillo@0 357
meillo@0 358 mta_mode mta_mode = MODE_ACCEPT;
meillo@0 359
meillo@0 360 gint queue_interval = 0;
meillo@0 361 gint get_interval = 0;
meillo@0 362 gboolean opt_t = FALSE;
meillo@0 363 gboolean opt_i = FALSE;
meillo@0 364 gboolean opt_odb = FALSE;
meillo@0 365 gboolean opt_oem = FALSE;
meillo@0 366 gboolean exit_failure = FALSE;
meillo@0 367
meillo@0 368 gchar *M_cmd = NULL;
meillo@0 369
meillo@0 370 gint exit_code = EXIT_SUCCESS;
meillo@0 371 gchar *route_name = NULL;
meillo@0 372 gchar *get_name = NULL;
meillo@0 373 gchar *progname;
meillo@0 374 gchar *f_address = NULL;
meillo@0 375 gchar *full_sender_name = NULL;
meillo@0 376 address *return_path = NULL; /* may be changed by -f option */
meillo@0 377
meillo@0 378 progname = get_progname(argv[0]);
meillo@0 379
meillo@0 380 if(strcmp(progname, "mailq") == 0)
meillo@0 381 { mta_mode = MODE_LIST; }
meillo@0 382 else if(strcmp(progname, "mailrm") == 0)
meillo@0 383 { mta_mode = MODE_MCMD; M_cmd = "rm"; }
meillo@0 384 else if(strcmp(progname, "runq") == 0)
meillo@0 385 { mta_mode = MODE_RUNQUEUE; do_runq = TRUE; }
meillo@0 386 else if(strcmp(progname, "rmail") == 0)
meillo@0 387 { mta_mode = MODE_ACCEPT; opt_i = TRUE; }
meillo@0 388 else if(strcmp(progname, "smtpd") == 0 || strcmp(progname, "in.smtpd") == 0)
meillo@0 389 { mta_mode = MODE_SMTP; }
meillo@0 390
meillo@0 391 /* parse cmd line */
meillo@0 392 while(arg < argc){
meillo@0 393 gint pos = 0;
meillo@0 394 if((argv[arg][pos] == '-') && (argv[arg][pos+1] != '-')){
meillo@0 395 pos++;
meillo@0 396 switch(argv[arg][pos++]){
meillo@0 397 case 'b':
meillo@0 398 switch(argv[arg][pos++]){
meillo@0 399 case 'd':
meillo@0 400 do_listen = TRUE;
meillo@0 401 mta_mode = MODE_DAEMON;
meillo@0 402 break;
meillo@0 403 case 'i':
meillo@0 404 /* ignored */
meillo@0 405 mta_mode = MODE_BI;
meillo@0 406 break;
meillo@0 407 case 's':
meillo@0 408 mta_mode = MODE_SMTP;
meillo@0 409 break;
meillo@0 410 case 'p':
meillo@0 411 mta_mode = MODE_LIST;
meillo@0 412 break;
meillo@0 413 case 'V':
meillo@0 414 mta_mode = MODE_VERSION;
meillo@0 415 break;
meillo@0 416 default:
meillo@0 417 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
meillo@0 418 exit(EXIT_FAILURE);
meillo@0 419 }
meillo@0 420 break;
meillo@0 421 case 'B':
meillo@0 422 /* we ignore this and throw the argument away */
meillo@0 423 get_optarg(argv, argc, &arg, &pos);
meillo@0 424 break;
meillo@0 425 case 'C':
meillo@0 426 if(!(conf_file = get_optarg(argv, argc, &arg, &pos))){
meillo@0 427 fprintf(stderr, "-C requires a filename as argument.\n");
meillo@0 428 exit(EXIT_FAILURE);
meillo@0 429 }
meillo@0 430 break;
meillo@0 431 case 'F':
meillo@0 432 {
meillo@0 433 full_sender_name = get_optarg(argv, argc, &arg, &pos);
meillo@0 434 if(!full_sender_name){
meillo@0 435 fprintf(stderr, "-F requires a name as an argument\n");
meillo@0 436 exit(EXIT_FAILURE);
meillo@0 437 }
meillo@0 438 }
meillo@0 439 break;
meillo@0 440 case 'd':
meillo@0 441 if(getuid() == 0){
meillo@0 442 char *lvl = get_optarg(argv, argc, &arg, &pos);
meillo@0 443 if(lvl)
meillo@0 444 debug_level = atoi(lvl);
meillo@0 445 else{
meillo@0 446 fprintf(stderr, "-d requires a number as an argument.\n");
meillo@0 447 exit(EXIT_FAILURE);
meillo@0 448 }
meillo@0 449 }else{
meillo@0 450 fprintf(stderr, "only root may set the debug level.\n");
meillo@0 451 exit(EXIT_FAILURE);
meillo@0 452 }
meillo@0 453 break;
meillo@0 454 case 'f':
meillo@0 455 /* set return path */
meillo@0 456 {
meillo@0 457 gchar *address;
meillo@0 458 address = get_optarg(argv, argc, &arg, &pos);
meillo@0 459 if(address){
meillo@0 460 f_address = g_strdup(address);
meillo@0 461 }else{
meillo@0 462 fprintf(stderr, "-f requires an address as an argument\n");
meillo@0 463 exit(EXIT_FAILURE);
meillo@0 464 }
meillo@0 465 }
meillo@0 466 break;
meillo@0 467 case 'g':
meillo@0 468 do_get = TRUE;
meillo@0 469 if(!mta_mode) mta_mode = MODE_NONE; /* to prevent default MODE_ACCEPT */
meillo@0 470 if(argv[arg][pos] == 'o'){
meillo@0 471 pos++;
meillo@0 472 do_get_online = TRUE;
meillo@0 473 /* can be NULL, then we use online detection method */
meillo@0 474 route_name = get_optarg(argv, argc, &arg, &pos);
meillo@0 475
meillo@0 476 if(route_name != NULL){
meillo@0 477 if(isdigit(route_name[0])){
meillo@0 478 get_interval = time_interval(route_name, &pos);
meillo@0 479 route_name = get_optarg(argv, argc, &arg, &pos);
meillo@0 480 mta_mode = MODE_GET_DAEMON;
meillo@0 481 do_get = FALSE;
meillo@0 482 }
meillo@0 483 }
meillo@0 484 }else{
meillo@0 485 if((optarg = get_optarg(argv, argc, &arg, &pos))){
meillo@0 486 get_name = get_optarg(argv, argc, &arg, &pos);
meillo@0 487 }
meillo@0 488 }
meillo@0 489 break;
meillo@0 490 case 'i':
meillo@0 491 if(argv[arg][pos] == 0){
meillo@0 492 opt_i = TRUE;
meillo@0 493 exit_failure = FALSE; /* may override -oem */
meillo@0 494 }else{
meillo@0 495 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
meillo@0 496 exit(EXIT_FAILURE);
meillo@0 497 }
meillo@0 498 break;
meillo@0 499 case 'M':
meillo@0 500 {
meillo@0 501 mta_mode = MODE_MCMD;
meillo@0 502 M_cmd = g_strdup(&(argv[arg][pos]));
meillo@0 503 }
meillo@0 504 break;
meillo@0 505 case 'o':
meillo@0 506 switch(argv[arg][pos++]){
meillo@0 507 case 'e':
meillo@0 508 if(argv[arg][pos++] == 'm') /* -oem */
meillo@0 509 if(!opt_i) exit_failure = TRUE;
meillo@0 510 opt_oem = TRUE;
meillo@0 511 break;
meillo@0 512 case 'd':
meillo@0 513 if(argv[arg][pos] == 'b') /* -odb */
meillo@0 514 opt_odb = TRUE;
meillo@0 515 else if(argv[arg][pos] == 'q') /* -odq */
meillo@0 516 do_queue = TRUE;
meillo@0 517 break;
meillo@0 518 case 'i':
meillo@0 519 opt_i = TRUE;
meillo@0 520 exit_failure = FALSE; /* may override -oem */
meillo@0 521 break;
meillo@0 522 }
meillo@0 523 break;
meillo@0 524
meillo@0 525 case 'q':
meillo@0 526 {
meillo@0 527 gchar *optarg;
meillo@0 528
meillo@0 529 do_runq = TRUE;
meillo@0 530 mta_mode = MODE_RUNQUEUE;
meillo@0 531 if(argv[arg][pos] == 'o'){
meillo@0 532 pos++;
meillo@0 533 do_runq = FALSE;
meillo@0 534 do_runq_online = TRUE;
meillo@0 535 /* can be NULL, then we use online detection method */
meillo@0 536 route_name = get_optarg(argv, argc, &arg, &pos);
meillo@0 537 }else if((optarg = get_optarg(argv, argc, &arg, &pos))){
meillo@0 538 mta_mode = MODE_DAEMON;
meillo@0 539 queue_interval = time_interval(optarg, &pos);
meillo@0 540 }
meillo@0 541 }
meillo@0 542 break;
meillo@0 543 case 't':
meillo@0 544 if(argv[arg][pos] == 0){
meillo@0 545 opt_t = TRUE;
meillo@0 546 }else{
meillo@0 547 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
meillo@0 548 exit(EXIT_FAILURE);
meillo@0 549 }
meillo@0 550 break;
meillo@0 551 case 'v':
meillo@0 552 do_verbose = TRUE;
meillo@0 553 break;
meillo@0 554 default:
meillo@0 555 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
meillo@0 556 exit(EXIT_FAILURE);
meillo@0 557 }
meillo@0 558 }else{
meillo@0 559 if(argv[arg][pos+1] == '-'){
meillo@0 560 if(argv[arg][pos+2] != '\0'){
meillo@0 561 fprintf(stderr, "unrecognized option '%s'\n", argv[arg]);
meillo@0 562 exit(EXIT_FAILURE);
meillo@0 563 }
meillo@0 564 arg++;
meillo@0 565 }
meillo@0 566 break;
meillo@0 567 }
meillo@0 568 arg++;
meillo@0 569 }
meillo@0 570
meillo@0 571 if(mta_mode == MODE_VERSION){
meillo@0 572 gchar *with_resolver = "", *with_smtp_server = "", *with_pop3 = "", *with_auth = "",
meillo@0 573 *with_maildir = "", *with_ident = "", *with_mserver = "";
meillo@0 574
meillo@0 575 #ifdef ENABLE_RESOLVER
meillo@0 576 with_resolver = " +resolver";
meillo@0 577 #endif
meillo@0 578 #ifdef ENABLE_SMTP_SERVER
meillo@0 579 with_smtp_server = " +smtp-server";
meillo@0 580 #endif
meillo@0 581 #ifdef ENABLE_POP3
meillo@0 582 with_pop3 = " +pop3";
meillo@0 583 #endif
meillo@0 584 #ifdef ENABLE_AUTH
meillo@0 585 with_auth = " +auth";
meillo@0 586 #endif
meillo@0 587 #ifdef ENABLE_MAILDIR
meillo@0 588 with_maildir = " +maildir";
meillo@0 589 #endif
meillo@0 590 #ifdef ENABLE_IDENT
meillo@0 591 with_ident = " +ident";
meillo@0 592 #endif
meillo@0 593 #ifdef ENABLE_MSERVER
meillo@0 594 with_mserver = " +mserver";
meillo@0 595 #endif
meillo@0 596
meillo@0 597 printf("%s %s%s%s%s%s%s%s%s\n", PACKAGE, VERSION,
meillo@0 598 with_resolver, with_smtp_server, with_pop3, with_auth,
meillo@0 599 with_maildir, with_ident, with_mserver);
meillo@0 600
meillo@0 601 exit(EXIT_SUCCESS);
meillo@0 602 }
meillo@0 603
meillo@0 604 /* initialize random generator */
meillo@0 605 srand(time(NULL));
meillo@0 606 /* ignore SIGPIPE signal */
meillo@0 607 signal(SIGPIPE, SIG_IGN);
meillo@0 608
meillo@0 609 /* close all possibly open file descriptors */
meillo@0 610 {
meillo@0 611 int i, max_fd = sysconf(_SC_OPEN_MAX);
meillo@0 612
meillo@0 613 if(max_fd <= 0) max_fd = 64;
meillo@0 614 for(i = 3; i < max_fd; i++)
meillo@0 615 close(i);
meillo@0 616 }
meillo@0 617
meillo@0 618 init_conf();
meillo@0 619
meillo@0 620 /* if we are not privileged, and the config file was changed we
meillo@0 621 implicetely set the the run_as_user flag and give up all
meillo@0 622 privileges.
meillo@0 623
meillo@0 624 So it is possible for a user to run his own daemon without
meillo@0 625 breaking security.
meillo@0 626 */
meillo@0 627 if(strcmp(conf_file, CONF_FILE) != 0){
meillo@0 628 if(conf.orig_uid != 0){
meillo@0 629 conf.run_as_user = TRUE;
meillo@0 630 seteuid(conf.orig_uid);
meillo@0 631 setegid(conf.orig_gid);
meillo@0 632 setuid(conf.orig_uid);
meillo@0 633 setgid(conf.orig_gid);
meillo@0 634 }
meillo@0 635 }
meillo@0 636
meillo@0 637 read_conf(conf_file);
meillo@0 638
meillo@0 639 if(do_queue) conf.do_queue = TRUE;
meillo@0 640 if(do_verbose) conf.do_verbose = TRUE;
meillo@0 641 if(debug_level >= 0) /* if >= 0, it was given by argument */
meillo@0 642 conf.debug_level = debug_level;
meillo@0 643
meillo@0 644 chdir("/");
meillo@0 645
meillo@0 646 if(!conf.run_as_user){
meillo@0 647 if(setgid(0) != 0){
meillo@0 648 fprintf(stderr,
meillo@0 649 "could not set gid to 0. Is the setuid bit set? : %s\n",
meillo@0 650 strerror(errno));
meillo@0 651 exit(EXIT_FAILURE);
meillo@0 652 }
meillo@0 653 if(setuid(0) != 0){
meillo@0 654 fprintf(stderr,
meillo@0 655 "could not gain root privileges. Is the setuid bit set? : %s\n",
meillo@0 656 strerror(errno));
meillo@0 657 exit(EXIT_FAILURE);
meillo@0 658 }
meillo@0 659 }
meillo@0 660
meillo@0 661 if(!logopen()){
meillo@0 662 fprintf(stderr, "could not open log file\n");
meillo@0 663 exit(EXIT_FAILURE);
meillo@0 664 }
meillo@0 665
meillo@0 666 DEBUG(1) debugf("masqmail %s starting\n", VERSION);
meillo@0 667
meillo@0 668 DEBUG(5){
meillo@0 669 gchar **str = argv;
meillo@0 670 debugf("args: \n");
meillo@0 671 while(*str){
meillo@0 672 debugf("%s \n", *str);
meillo@0 673 str++;
meillo@0 674 }
meillo@0 675 }
meillo@0 676 DEBUG(5) debugf("queue_interval = %d\n", queue_interval);
meillo@0 677
meillo@0 678 if(f_address){
meillo@0 679 return_path = create_address_qualified(f_address, TRUE, conf.host_name);
meillo@0 680 g_free(f_address);
meillo@0 681 if(!return_path){
meillo@0 682 fprintf(stderr, "invalid RFC821 address: %s\n", f_address);
meillo@0 683 exit(EXIT_FAILURE);
meillo@0 684 }
meillo@0 685 }
meillo@0 686
meillo@0 687 if(do_get){
meillo@0 688 #ifdef ENABLE_POP3
meillo@0 689 if((mta_mode == MODE_NONE) || (mta_mode == MODE_RUNQUEUE)){
meillo@0 690
meillo@0 691 set_identity(conf.orig_uid, "getting mail");
meillo@0 692
meillo@0 693 if(do_get_online){
meillo@0 694 if(route_name != NULL){
meillo@0 695 conf.online_detect = g_strdup("argument");
meillo@0 696 set_online_name(route_name);
meillo@0 697 }
meillo@0 698 get_online();
meillo@0 699 }else{
meillo@0 700 if(get_name)
meillo@0 701 get_from_name(get_name);
meillo@0 702 else
meillo@0 703 get_all();
meillo@0 704 }
meillo@0 705 }else{
meillo@0 706 logwrite(LOG_ALERT, "get (-g) only allowed alone or together with queue run (-q)\n");
meillo@0 707 }
meillo@0 708 #else
meillo@0 709 fprintf(stderr, "get (pop) support not compiled in\n");
meillo@0 710 #endif
meillo@0 711 }
meillo@0 712
meillo@0 713 switch(mta_mode){
meillo@0 714 case MODE_DAEMON:
meillo@0 715 mode_daemon(do_listen, queue_interval, argv);
meillo@0 716 break;
meillo@0 717 case MODE_RUNQUEUE:
meillo@0 718 {
meillo@0 719 /* queue runs */
meillo@0 720 set_identity(conf.orig_uid, "queue run");
meillo@0 721
meillo@0 722 if(do_runq)
meillo@0 723 exit_code = queue_run() ? EXIT_SUCCESS : EXIT_FAILURE;
meillo@0 724
meillo@0 725 if(do_runq_online){
meillo@0 726 if(route_name != NULL){
meillo@0 727 conf.online_detect = g_strdup("argument");
meillo@0 728 set_online_name(route_name);
meillo@0 729 }
meillo@0 730 exit_code = queue_run_online() ? EXIT_SUCCESS : EXIT_FAILURE;
meillo@0 731 }
meillo@0 732 }
meillo@0 733 break;
meillo@0 734 case MODE_GET_DAEMON:
meillo@0 735 #ifdef ENABLE_POP3
meillo@0 736 if(route_name != NULL){
meillo@0 737 conf.online_detect = g_strdup("argument");
meillo@0 738 set_online_name(route_name);
meillo@0 739 }
meillo@0 740 mode_get_daemon(get_interval, argv);
meillo@0 741 #endif
meillo@0 742 break;
meillo@0 743
meillo@0 744 case MODE_SMTP:
meillo@0 745 #ifdef ENABLE_SMTP_SERVER
meillo@0 746 mode_smtp();
meillo@0 747 #else
meillo@0 748 fprintf(stderr, "smtp server support not compiled in\n");
meillo@0 749 #endif
meillo@0 750 break;
meillo@0 751 case MODE_LIST:
meillo@0 752
meillo@0 753 queue_list();
meillo@0 754 break;
meillo@0 755
meillo@0 756 case MODE_BI:
meillo@0 757
meillo@0 758 exit(EXIT_SUCCESS);
meillo@0 759 break; /* well... */
meillo@0 760
meillo@0 761 case MODE_MCMD:
meillo@0 762 if(strcmp(M_cmd, "rm") == 0){
meillo@0 763 gboolean ok = FALSE;
meillo@0 764
meillo@0 765 set_euidgid(conf.mail_uid, conf.mail_gid, NULL, NULL);
meillo@0 766
meillo@0 767 if(is_privileged_user(conf.orig_uid)){
meillo@0 768 for(; arg < argc; arg++){
meillo@0 769 if(queue_delete(argv[arg]))
meillo@0 770 ok = TRUE;
meillo@0 771 }
meillo@0 772 }else{
meillo@0 773 struct passwd *pw = getpwuid(conf.orig_uid);
meillo@0 774 if(pw){
meillo@0 775 for(; arg < argc; arg++){
meillo@0 776 message *msg = msg_spool_read(argv[arg], FALSE);
meillo@0 777 #ifdef ENABLE_IDENT
meillo@0 778 if(((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)) ||
meillo@0 779 is_in_netlist(msg->received_host, conf.ident_trusted_nets)){
meillo@0 780 #else
meillo@0 781 if((msg->received_host == NULL) && (msg->received_prot == PROT_LOCAL)){
meillo@0 782 #endif
meillo@0 783 if(msg->ident){
meillo@0 784 if(strcmp(pw->pw_name, msg->ident) == 0){
meillo@0 785 if(queue_delete(argv[arg]))
meillo@0 786 ok = TRUE;
meillo@0 787 }else{
meillo@0 788 fprintf(stderr, "you do not own message id %s\n", argv[arg]);
meillo@0 789 }
meillo@0 790 }else
meillo@0 791 fprintf(stderr, "message %s does not have an ident.\n", argv[arg]);
meillo@0 792 }else{
meillo@0 793 fprintf(stderr, "message %s was not received locally or from a trusted network.\n", argv[arg]);
meillo@0 794 }
meillo@0 795 }
meillo@0 796 }else{
meillo@0 797 fprintf(stderr, "could not find a passwd entry for uid %d: %s\n", conf.orig_uid, strerror(errno));
meillo@0 798 }
meillo@0 799 }
meillo@0 800 exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
meillo@0 801 }else{
meillo@0 802 fprintf(stderr, "unknown command %s\n", M_cmd);
meillo@0 803 exit(EXIT_FAILURE);
meillo@0 804 }
meillo@0 805 break;
meillo@0 806
meillo@0 807 case MODE_ACCEPT:
meillo@0 808 {
meillo@0 809 guint accept_flags =
meillo@0 810 (opt_t ? ACC_DEL_RCPTS|ACC_DEL_BCC|ACC_RCPT_FROM_HEAD : ACC_HEAD_FROM_RCPT) |
meillo@0 811 (opt_i ? ACC_NODOT_TERM : ACC_NODOT_RELAX);
meillo@0 812
meillo@0 813 mode_accept(return_path, full_sender_name, accept_flags, &(argv[arg]), argc - arg);
meillo@0 814
meillo@0 815 exit(exit_failure ? EXIT_FAILURE : EXIT_SUCCESS);
meillo@0 816 }
meillo@0 817 break;
meillo@0 818 case MODE_NONE:
meillo@0 819 break;
meillo@0 820 default:
meillo@0 821 fprintf(stderr, "unknown mode: %d\n", mta_mode);
meillo@0 822 break;
meillo@0 823 }
meillo@0 824
meillo@0 825 logclose();
meillo@0 826
meillo@0 827 exit(exit_code);
meillo@0 828 }