~ubuntu-branches/ubuntu/dapper/postfix/dapper-security

« back to all changes in this revision

Viewing changes to src/local/include.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-02-27 09:33:07 UTC
  • Revision ID: james.westby@ubuntu.com-20050227093307-cn789t27ibnlh6tf
Tags: upstream-2.1.5
ImportĀ upstreamĀ versionĀ 2.1.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      deliver_include 3
 
4
/* SUMMARY
 
5
/*      deliver to addresses listed in include file
 
6
/* SYNOPSIS
 
7
/*      #include "local.h"
 
8
/*
 
9
/*      int     deliver_include(state, usr_attr, path)
 
10
/*      LOCAL_STATE state;
 
11
/*      USER_ATTR usr_attr;
 
12
/*      char    *path;
 
13
/* DESCRIPTION
 
14
/*      deliver_include() processes the contents of the named include
 
15
/*      file and delivers to each address listed. Some sanity checks
 
16
/*      are done on the include file permissions and type.
 
17
/*
 
18
/*      Arguments:
 
19
/* .IP state
 
20
/*      The attributes that specify the message, recipient and more.
 
21
/*      Attributes describing alias, include, or forward expansion.
 
22
/*      A table with the results from expanding aliases or lists.
 
23
/*      A table with delivered-to: addresses taken from the message.
 
24
/* .IP usr_attr
 
25
/*      Attributes describing user rights and environment.
 
26
/* .IP path
 
27
/*      Pathname of the include file.
 
28
/* DIAGNOSTICS
 
29
/*      Fatal errors: out of memory. Warnings: bad include file type
 
30
/*      or permissions. The result is non-zero when delivery should be
 
31
/*      tried again.
 
32
/* SEE ALSO
 
33
/*      token(3) tokenize list
 
34
/* LICENSE
 
35
/* .ad
 
36
/* .fi
 
37
/*      The Secure Mailer license must be distributed with this software.
 
38
/* AUTHOR(S)
 
39
/*      Wietse Venema
 
40
/*      IBM T.J. Watson Research
 
41
/*      P.O. Box 704
 
42
/*      Yorktown Heights, NY 10598, USA
 
43
/*--*/
 
44
 
 
45
/* System library. */
 
46
 
 
47
#include <sys_defs.h>
 
48
#include <sys/stat.h>
 
49
#include <unistd.h>
 
50
#include <string.h>
 
51
#include <fcntl.h>
 
52
 
 
53
/* Utility library. */
 
54
 
 
55
#include <msg.h>
 
56
#include <htable.h>
 
57
#include <mymalloc.h>
 
58
#include <vstream.h>
 
59
#include <open_as.h>
 
60
#include <stat_as.h>
 
61
#include <iostuff.h>
 
62
#include <mypwd.h>
 
63
 
 
64
/* Global library. */
 
65
 
 
66
#include <bounce.h>
 
67
#include <defer.h>
 
68
#include <been_here.h>
 
69
#include <mail_params.h>
 
70
#include <ext_prop.h>
 
71
#include <sent.h>
 
72
 
 
73
/* Application-specific. */
 
74
 
 
75
#include "local.h"
 
76
 
 
77
/* deliver_include - open include file and deliver */
 
78
 
 
79
int     deliver_include(LOCAL_STATE state, USER_ATTR usr_attr, char *path)
 
80
{
 
81
    char   *myname = "deliver_include";
 
82
    struct stat st;
 
83
    struct mypasswd *file_pwd = 0;
 
84
    int     status;
 
85
    VSTREAM *fp;
 
86
    int     fd;
 
87
 
 
88
    /*
 
89
     * Make verbose logging easier to understand.
 
90
     */
 
91
    state.level++;
 
92
    if (msg_verbose)
 
93
        MSG_LOG_STATE(myname, state);
 
94
 
 
95
    /*
 
96
     * DUPLICATE ELIMINATION
 
97
     * 
 
98
     * Don't process this include file more than once as this particular user.
 
99
     */
 
100
    if (been_here(state.dup_filter, "include %ld %s", (long) usr_attr.uid, path))
 
101
        return (0);
 
102
    state.msg_attr.exp_from = state.msg_attr.local;
 
103
 
 
104
    /*
 
105
     * Can of worms. Allow this include file to be symlinked, but disallow
 
106
     * inclusion of special files or of files with world write permission
 
107
     * enabled.
 
108
     */
 
109
    if (*path != '/')
 
110
        return (bounce_append(BOUNCE_FLAGS(state.request),
 
111
                              BOUNCE_ATTR(state.msg_attr),
 
112
                              ":include:%s uses a relative path", path));
 
113
    if (stat_as(path, &st, usr_attr.uid, usr_attr.gid) < 0)
 
114
        return (bounce_append(BOUNCE_FLAGS(state.request),
 
115
                              BOUNCE_ATTR(state.msg_attr),
 
116
                              "unable to lookup include file %s: %m", path));
 
117
    if (S_ISREG(st.st_mode) == 0)
 
118
        return (bounce_append(BOUNCE_FLAGS(state.request),
 
119
                              BOUNCE_ATTR(state.msg_attr),
 
120
                              "not a regular include file: %s", path));
 
121
    if (st.st_mode & S_IWOTH)
 
122
        return (bounce_append(BOUNCE_FLAGS(state.request),
 
123
                              BOUNCE_ATTR(state.msg_attr),
 
124
                              "world writable include file: %s", path));
 
125
 
 
126
    /*
 
127
     * DELIVERY POLICY
 
128
     * 
 
129
     * Set the expansion type attribute so that we can decide if destinations
 
130
     * such as /file/name and |command are allowed at all.
 
131
     */
 
132
    state.msg_attr.exp_type = EXPAND_TYPE_INCL;
 
133
 
 
134
    /*
 
135
     * DELIVERY RIGHTS
 
136
     * 
 
137
     * When a non-root include file is listed in a root-owned alias, use the
 
138
     * rights of the include file owner.  We do not want to give the include
 
139
     * file owner control of the default account.
 
140
     * 
 
141
     * When an include file is listed in a user-owned alias or .forward file,
 
142
     * leave the delivery rights alone. Users should not be able to make
 
143
     * things happen with someone else's rights just by including some file
 
144
     * that is owned by their victim.
 
145
     */
 
146
    if (usr_attr.uid == 0) {
 
147
        if ((file_pwd = mypwuid(st.st_uid)) == 0) {
 
148
            msg_warn("cannot find username for uid %ld", (long) st.st_uid);
 
149
            return (defer_append(BOUNCE_FLAGS(state.request),
 
150
                                 BOUNCE_ATTR(state.msg_attr),
 
151
                             "%s: cannot find :include: file owner", path));
 
152
        }
 
153
        if (file_pwd->pw_uid != 0)
 
154
            SET_USER_ATTR(usr_attr, file_pwd, state.level);
 
155
    }
 
156
 
 
157
    /*
 
158
     * MESSAGE FORWARDING
 
159
     * 
 
160
     * When no owner attribute is set (either via an owner- alias, or as part of
 
161
     * .forward file processing), set the owner attribute, to disable direct
 
162
     * delivery of local recipients. By now it is clear that the owner
 
163
     * attribute should have been called forwarder instead.
 
164
     */
 
165
    if (state.msg_attr.owner == 0)
 
166
        state.msg_attr.owner = state.msg_attr.recipient;
 
167
 
 
168
    /*
 
169
     * From here on no early returns or we have a memory leak.
 
170
     * 
 
171
     * FILE OPEN RIGHTS
 
172
     * 
 
173
     * Use the delivery rights to open the include file. When no delivery rights
 
174
     * were established sofar, the file containing the :include: is owned by
 
175
     * root, so it should be OK to open any file that is accessible to root.
 
176
     * The command and file delivery routines are responsible for setting the
 
177
     * proper delivery rights. These are the rights of the default user, in
 
178
     * case the :include: is in a root-owned alias.
 
179
     * 
 
180
     * Don't propagate unmatched extensions unless permitted to do so.
 
181
     */
 
182
#define FOPEN_AS(p,u,g) ((fd = open_as(p,O_RDONLY,0,u,g)) >= 0 ? \
 
183
                                vstream_fdopen(fd,O_RDONLY) : 0)
 
184
 
 
185
    if ((fp = FOPEN_AS(path, usr_attr.uid, usr_attr.gid)) == 0) {
 
186
        status = bounce_append(BOUNCE_FLAGS(state.request),
 
187
                               BOUNCE_ATTR(state.msg_attr),
 
188
                               "cannot open include file %s: %m", path);
 
189
    } else {
 
190
        if ((local_ext_prop_mask & EXT_PROP_INCLUDE) == 0)
 
191
            state.msg_attr.unmatched = 0;
 
192
        close_on_exec(vstream_fileno(fp), CLOSE_ON_EXEC);
 
193
        status = deliver_token_stream(state, usr_attr, fp, (int *) 0);
 
194
        if (vstream_fclose(fp))
 
195
            msg_warn("close %s: %m", path);
 
196
    }
 
197
 
 
198
    /*
 
199
     * Cleanup.
 
200
     */
 
201
    if (file_pwd)
 
202
        mypwfree(file_pwd);
 
203
 
 
204
    return (status);
 
205
}