~ubuntu-branches/ubuntu/trusty/sendmail/trusty

« back to all changes in this revision

Viewing changes to debian/sensible_mda/sensible-mda.c

  • Committer: Bazaar Package Importer
  • Author(s): Richard A Nelson (Rick)
  • Date: 2009-03-01 18:45:00 UTC
  • mfrom: (8.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20090301184500-z6683zxyomgmop6c
Tags: 8.14.3-9
Batting 1000, build-depend on quilt      Closes: #517676

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Sendmail: sensible-mda.c,v 8.14.3 2009-03-01 10:48:34 cowboy Exp $
 
3
 *
 
4
 * sensible-mda.c
 
5
 * Copyright (c) 1998, Johnie Ingram.
 
6
 * Copyright (c) 1998-2009 Richard Nelson <cowboy@debian.org>.
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 *
 
22
 */
 
23
 
 
24
#ifndef lint
 
25
static const char id[] = "@(#)$Id: sensible-mda.c,v 8.14.3 2009-03-01 10:48:34 cowboy Exp $";
 
26
#endif /* ! lint */
 
27
 
 
28
#include <stdio.h>
 
29
#include <stdlib.h>
 
30
#include <errno.h>
 
31
#include <sys/stat.h>
 
32
#include <sys/types.h>
 
33
#include <limits.h>
 
34
#include <unistd.h>
 
35
#include <pwd.h>
 
36
#include <grp.h>
 
37
#include <sysexits.h>
 
38
#include <string.h>
 
39
#include <syslog.h>
 
40
 
 
41
// TODO: declare -x TCPREMOTEIP="$3"
 
42
 
 
43
#  define min(a, b)   ((a) < (b) ? (a) : (b))
 
44
 
 
45
#ifndef DEBUG
 
46
        #define DEBUG 0
 
47
        #endif
 
48
#ifndef TESTING
 
49
        #define TESTING 0
 
50
        #endif
 
51
 
 
52
#define PROCMAIL   "/etc/mail/smrsh/procmail"
 
53
#define MAILDROP   "/etc/mail/smrsh/maildrop"
 
54
#define DELIVER    "/etc/mail/smrsh/deliver"
 
55
#define MAIL_LOCAL "/etc/mail/smrsh/mail.local"
 
56
 
 
57
#define PROCMAILRCS "/etc/procmailrcs/"
 
58
 
 
59
static void     help(void);
 
60
static int      drop_privs(char *, uid_t, gid_t);
 
61
static void show_privs(void);
 
62
static unsigned char program[PATH_MAX];
 
63
 
 
64
static uid_t RealUid, RunAsUid;
 
65
static gid_t RealGid, RunAsGid;
 
66
 
 
67
int
 
68
main (int argc, char *argv[]) {
 
69
 
 
70
        struct stat MDA_stat;
 
71
        int done = 1;
 
72
        struct passwd* passwd_entry;
 
73
 
 
74
        char *str_pos;
 
75
        int exec_rc = EX_OK;
 
76
 
 
77
        #if DEBUG
 
78
                int arg_index;
 
79
                int str_len;
 
80
                #endif
 
81
 
 
82
        (void) openlog( "sensible-mda", LOG_PID+LOG_PERROR, LOG_MAIL );
 
83
 
 
84
        /*----------------------------------------------------------------
 
85
         * Obtain program name
 
86
         *----------------------------------------------------------------*/
 
87
        str_pos = strrchr(argv[0], '/');
 
88
        if ( str_pos )
 
89
                str_pos++;
 
90
        else
 
91
                str_pos = argv[0];
 
92
        (void) strncpy(program, str_pos,
 
93
                min(strlen(str_pos), sizeof(program)-1));
 
94
        program[sizeof(program)-1] = '\0';
 
95
 
 
96
        #if DEBUG
 
97
                str_len = 0;
 
98
                for ( arg_index = 0; arg_index < argc; arg_index++ )
 
99
                        str_len += strlen( argv[arg_index] ) + 1;
 
100
                str_pos = malloc( str_len + 1);
 
101
                str_pos[0] = '\0';
 
102
                for ( arg_index = 0; arg_index < argc; arg_index++ ) {
 
103
                        (void) strcat( str_pos, argv[arg_index] );
 
104
                        (void) strcat( str_pos, " " );
 
105
                        };
 
106
                (void) syslog( LOG_INFO, "Parms: %s\n", str_pos );
 
107
                (void) free(str_pos);
 
108
                #endif
 
109
 
 
110
        /*----------------------------------------------------------------
 
111
         * Parse input to determine to whom to speak and who we are...
 
112
         * Must have at least three parameters unless first is ?,-?,/?.
 
113
         *----------------------------------------------------------------*/
 
114
        if (argc >= 2 &&
 
115
                (strcmp(argv[1],"?") == 0 || strcmp(argv[1],"-?")  == 0 ||
 
116
                strcmp(argv[1],"/?") == 0 || strcmp(argv[1],"\\?") == 0 ||
 
117
                strcmp(argv[1],"-h") == 0 || strcmp(argv[1],"--help") == 0)) {
 
118
                (void) printf( "%s - Help\n", program );
 
119
                help();
 
120
                (void) closelog();
 
121
                return (EX_USAGE);
 
122
                };
 
123
        if (argc < 3) {
 
124
                (void) syslog( LOG_ERR, "%s - Required parameters elided.\n",
 
125
                        program );
 
126
                help();
 
127
                (void) closelog();
 
128
                return (EX_USAGE);
 
129
                };
 
130
 
 
131
        /*----------------------------------------------------------------
 
132
         * Determine to whom we are delivering mail to, and set that
 
133
         * as our real, effective, and saved {u,g}ids
 
134
         *----------------------------------------------------------------*/
 
135
        RealUid = RunAsUid = geteuid();
 
136
        RealGid = RunAsGid = getegid();
 
137
        passwd_entry=getpwnam(argv[2]);
 
138
        if (passwd_entry) {
 
139
                RunAsUid = passwd_entry->pw_uid;
 
140
                RunAsGid = passwd_entry->pw_gid;
 
141
                }
 
142
        else {
 
143
                (void) syslog( LOG_ERR, "User(%s) does not exist!\n",
 
144
                        argv[2]);
 
145
                (void) closelog();
 
146
                return (EX_TEMPFAIL);
 
147
                };
 
148
 
 
149
        /*----------------------------------------------------------------
 
150
         * 1st: try delivery via PROCMAIL (Keep SUID, works better that way)
 
151
         *----------------------------------------------------------------*/
 
152
        if (!stat(PROCMAIL, &MDA_stat)) {
 
153
                done = 0;
 
154
                #if DEBUG
 
155
                        (void) syslog( LOG_INFO, "MDA: %s -t -f %s"
 
156
                                " -a %s -d %s\n",
 
157
                                PROCMAIL, argv[1], argv[3], argv[2]);
 
158
                        #endif
 
159
                #if ! TESTING
 
160
                        exec_rc = execl (PROCMAIL, PROCMAIL, "-t",
 
161
                                "-f", argv[1],
 
162
                                "-a", argv[3],
 
163
                                "-d", argv[2], NULL);
 
164
                        (void) syslog( LOG_ERR, "%s did not execute %i,%i\n",
 
165
                                PROCMAIL, exec_rc, errno);
 
166
                        (void) closelog();
 
167
                        return (EX_TEMPFAIL);
 
168
                        #endif
 
169
                done = 1;
 
170
                };
 
171
 
 
172
        /*----------------------------------------------------------------
 
173
         * 2nd: try delivery via MAILDROP
 
174
         *----------------------------------------------------------------*/
 
175
        if (done && !stat(MAILDROP, &MDA_stat)) {
 
176
                done = 0;
 
177
                #if DEBUG
 
178
                        (void) syslog( LOG_INFO, "MDA: %s -f %s -d %s %s\n",
 
179
                                MAILDROP, argv[1], argv[2], argv[3]);
 
180
                        #endif
 
181
                if (drop_privs( argv[2], RunAsUid, RunAsGid )) {
 
182
                        (void) closelog();
 
183
                        return (EX_TEMPFAIL);
 
184
                        };
 
185
                #if ! TESTING
 
186
                        exec_rc = execl (MAILDROP, MAILDROP,
 
187
                                "-f", argv[1], "-d", argv[2], argv[3], NULL);
 
188
                        (void) syslog( LOG_ERR, "%s did not execute %i,%i\n",
 
189
                                MAILDROP, exec_rc, errno);
 
190
                        (void) closelog();
 
191
                        return (EX_TEMPFAIL);
 
192
                        #endif
 
193
                done = 1;
 
194
                };
 
195
 
 
196
        /*----------------------------------------------------------------
 
197
         * 3rd: try delivery via DELIVER
 
198
         *----------------------------------------------------------------*/
 
199
        if (done && !stat(DELIVER, &MDA_stat)) {
 
200
                done = 0;
 
201
                #if DEBUG
 
202
                        (void) syslog( LOG_INFO, "MDA: %s -r %s %s\n",
 
203
                                DELIVER, argv[1], argv[2]);
 
204
                        #endif
 
205
                if (drop_privs( argv[2], RunAsUid, RunAsGid )) {
 
206
                        (void) closelog();
 
207
                        return (EX_TEMPFAIL);
 
208
                        };
 
209
                #if ! TESTING
 
210
                        exec_rc = execl (DELIVER, DELIVER,
 
211
                                "-r", argv[1], argv[2], NULL);
 
212
                        (void) syslog( LOG_ERR, "%s did not execute %i,%i\n",
 
213
                                DELIVER, exec_rc, errno);
 
214
                        (void) closelog();
 
215
                        return (EX_TEMPFAIL);
 
216
                        #endif
 
217
                done = 1;
 
218
                };
 
219
 
 
220
        /*----------------------------------------------------------------
 
221
         * 4th: try delivery via MAIL.LOCAL (Needs SUID because of LMTP)
 
222
         *----------------------------------------------------------------*/
 
223
        if (done && !stat(MAIL_LOCAL, &MDA_stat)) {
 
224
                done = 0;
 
225
                #if DEBUG
 
226
                        (void) syslog( LOG_INFO, "MDA: %s -f %s %s\n",
 
227
                        MAIL_LOCAL, argv[1], argv[2]);
 
228
                        #endif
 
229
                #if ! TESTING
 
230
                        exec_rc = execl (MAIL_LOCAL, MAIL_LOCAL,
 
231
                                "-f", argv[1], argv[2], NULL);
 
232
                        (void) syslog( LOG_ERR, "%s did not execute %i,%i\n",
 
233
                                MAIL_LOCAL, exec_rc, errno);
 
234
                        (void) closelog();
 
235
                        return (EX_TEMPFAIL);
 
236
                        #endif
 
237
                done = 1;
 
238
                };
 
239
 
 
240
        (void) syslog( LOG_ERR, "No MDA was found! Tried: "
 
241
                "%s, %s, %s, and %s.\n",
 
242
                        PROCMAIL, MAILDROP, DELIVER, MAIL_LOCAL );
 
243
 
 
244
        (void) closelog();
 
245
        return (EX_TEMPFAIL);
 
246
        };
 
247
 
 
248
/*-------------------------------------------------------------------
 
249
 * drop_privs...
 
250
 *-------------------------------------------------------------------*/
 
251
static int
 
252
drop_privs(char * luser, uid_t new_uid, gid_t new_gid) {
 
253
        gid_t emptygidset[1];
 
254
        uid_t EffUid;
 
255
        gid_t EffGid;
 
256
        int rval;
 
257
 
 
258
        rval = EX_OK;
 
259
        EffUid = geteuid();
 
260
        EffGid = getegid();
 
261
 
 
262
        /* reset group permissions; these can be set later */
 
263
        emptygidset[0] = (RunAsGid != 0) ? RunAsGid : EffGid;
 
264
        if (setgroups(1, emptygidset) == -1 && EffUid == 0) {
 
265
                (void) syslog( LOG_ERR, "drop_privs: setgroups(1, %d) failed\n",
 
266
                        (int) emptygidset[0]);
 
267
                rval = EX_OSERR;
 
268
                };
 
269
 
 
270
        /* reset primary group id */
 
271
        if ((RunAsGid != 0) && EffGid != RunAsGid && setgid(RunAsGid) < 0) {
 
272
                (void) syslog( LOG_ERR, "drop_privs: setgid(%d) failed\n",
 
273
                        (int) RunAsGid);
 
274
                rval = EX_OSERR;
 
275
                };
 
276
 
 
277
        /* reset primary user id */
 
278
        if ((RunAsUid != 0) && EffUid != RunAsUid && setuid(RunAsUid) < 0) {
 
279
                (void) syslog( LOG_ERR, "drop_privs: setuid(%d) failed\n",
 
280
                        (int) RunAsUid);
 
281
                rval = EX_OSERR;
 
282
                };
 
283
 
 
284
        #if DEBUG
 
285
                show_privs();
 
286
                (void) syslog( LOG_INFO, "drop_privs: rval = %d\n", rval);
 
287
                #endif
 
288
 
 
289
        if (rval) {
 
290
                (void) syslog( LOG_ERR, 
 
291
                        "Can not setreuid to %d:%d for user(%s)!\n",
 
292
                        RunAsUid, RunAsGid, luser);
 
293
                show_privs();
 
294
                };
 
295
 
 
296
        return rval;
 
297
        };
 
298
 
 
299
/*-------------------------------------------------------------------
 
300
 * show_privs...
 
301
 *-------------------------------------------------------------------*/
 
302
static void
 
303
show_privs(void) {
 
304
 
 
305
        (void) syslog( LOG_INFO, "show_privs: RealUser = %d:%d\n",
 
306
                (int) RealUid, (int) RealGid);
 
307
        (void) syslog( LOG_INFO, "show_privs: "
 
308
                "get[ug]id=%d:%d, gete[ug]id=%d:%d\n",
 
309
                (int) getuid(), (int) getgid(),
 
310
                (int) geteuid(), (int) getegid());
 
311
        (void) syslog( LOG_INFO, "show_privs: RunAsUser = %d:%d\n",
 
312
                (int) RunAsUid, (int) RunAsGid);
 
313
        return;
 
314
        };
 
315
 
 
316
/*-------------------------------------------------------------------
 
317
 * Help...
 
318
 *-------------------------------------------------------------------*/
 
319
static void
 
320
help(void) {
 
321
 
 
322
        (void) printf("\n%s - Help information.\n\n"
 
323
                "%s:\n"
 
324
                        "\tA general MTA->MDA wrapper to isolate the MTA from\n"
 
325
                        "\tthe vagaries of MDA installation and invocation.\n"
 
326
                "\nSupported MTAs:\n"
 
327
                        "\tsendmail\n"
 
328
                "\nSupported MDAs:\n"
 
329
                        "\tprocmail, maildrop, deliver, mail.local\n"
 
330
                "\nCalled by:\n"
 
331
                        "\tSendmail: \n"
 
332
                        "\tYou: "
 
333
                                "Go directly to jail, do not pass GO, "
 
334
                                "do not collect $200!\n"
 
335
                "\nSyntax:\n"
 
336
                        "\t%s <from:$g> <user:$u> [<detail:$h>]"
 
337
                                "[<client:${client_addr}>]\n"
 
338
                "\nCalls:\n"
 
339
                        "\tprocmail:\t procmail -t"
 
340
                                " -f <from>"
 
341
                                " -a <detail> -d <to>\n"
 
342
                        "\tmaildrop:\t maildrop -f <from> -d <to> <detail>\n"
 
343
                        "\tdeliver:\t deliver -r <from> <to>\n"
 
344
                        "\tmail.local:\t mail.local -f <from> <to>\n"
 
345
                "\n"
 
346
                ,program, program, program
 
347
                );
 
348
        return;
 
349
        };
 
350