comparison src/local.c @ 332:63efd381e27b

refactoring, partly also related to set_euidgid()
author markus schnalke <meillo@marmaro.de>
date Sat, 27 Aug 2011 16:21:17 +0200
parents fc1c6425c024
children 41958685480d
comparison
equal deleted inserted replaced
331:e507c854a63e 332:63efd381e27b
52 gboolean 52 gboolean
53 append_file(message * msg, GList * hdr_list, gchar * user) 53 append_file(message * msg, GList * hdr_list, gchar * user)
54 { 54 {
55 struct passwd *pw; 55 struct passwd *pw;
56 gboolean ok = FALSE; 56 gboolean ok = FALSE;
57 uid_t saved_uid = geteuid();
58 gid_t saved_gid = getegid();
59 gboolean uid_ok = TRUE, gid_ok = TRUE;
60 gchar *filename;
61 FILE *out;
57 62
58 /* headers may be special for a local delivery */ 63 /* headers may be special for a local delivery */
59 if (hdr_list == NULL) 64 if (!hdr_list)
60 hdr_list = msg->hdr_list; 65 hdr_list = msg->hdr_list;
61 66
62 if ((pw = getpwnam(user))) { 67 if (!(pw = getpwnam(user))) {
63 uid_t saved_uid = geteuid();
64 gid_t saved_gid = getegid();
65 gboolean uid_ok = TRUE, gid_ok = TRUE;
66
67 if (!conf.run_as_user) {
68 uid_ok = (seteuid(0) == 0);
69 if (uid_ok) {
70 gid_ok = (setegid(conf.mail_gid) == 0);
71 uid_ok = (seteuid(pw->pw_uid) == 0);
72 }
73 }
74
75 DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
76
77 if (uid_ok && gid_ok) {
78 gchar *filename;
79 FILE *out;
80
81 filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
82 if ((out = fopen(filename, "a"))) {
83 #ifdef USE_LIBLOCKFILE
84 gint err;
85 /* lock file using liblockfile */
86 err = maillock(user, 3);
87 if (err == 0) {
88 #else
89 /* lock file: */
90 struct flock lock;
91 lock.l_type = F_WRLCK;
92 lock.l_whence = SEEK_END;
93 lock.l_start = lock.l_len = 0;
94 if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
95 #endif
96 fchmod(fileno(out), 0600);
97 message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
98 ok = TRUE;
99
100 /* close when still user */
101 fclose(out);
102 #ifdef USE_LIBLOCKFILE
103 mailunlock();
104 #endif
105 } else {
106 fclose(out);
107 #ifdef USE_LIBLOCKFILE
108 DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
109 } /* XEmacs indenting convenience... */
110 #else
111 DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
112 }
113 #endif
114 } else {
115 logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
116 }
117 g_free(filename);
118
119 if (!conf.run_as_user) {
120 uid_ok = (seteuid(0) == 0);
121 if (uid_ok) {
122 gid_ok = (setegid(saved_gid) == 0);
123 uid_ok = (seteuid(saved_uid) == 0);
124 }
125 }
126
127 if (!uid_ok || !gid_ok) {
128 /* FIXME: if this fails we HAVE to exit, because we shall not run
129 with some users id. But we do not return, and so this message
130 will not be finished, so the user will get the message again
131 next time a delivery is attempted... */
132 logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
133 logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
134 getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
135 exit(1);
136 }
137 } else {
138 logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
139 }
140 } else {
141 logwrite(LOG_ALERT, "could not find password entry for user %s\n", user); 68 logwrite(LOG_ALERT, "could not find password entry for user %s\n", user);
142 errno = ENOENT; /* getpwnam does not set errno correctly */ 69 errno = ENOENT; /* getpwnam does not set errno correctly */
143 } 70 return FALSE;
144 71 }
72
73 if (!conf.run_as_user) {
74 uid_ok = (seteuid(0) == 0);
75 if (uid_ok) {
76 gid_ok = (setegid(conf.mail_gid) == 0);
77 uid_ok = (seteuid(pw->pw_uid) == 0);
78 }
79 if (!uid_ok || !gid_ok) {
80 logwrite(LOG_ALERT, "could not set uid or gid for local delivery, uid = %d: %s\n", pw->pw_uid, strerror(errno));
81 return FALSE;
82 }
83 }
84
85 DEBUG(5) debugf("running as euid %d, egid %d\n", geteuid(), getegid());
86
87 filename = g_strdup_printf("%s/%s", conf.mail_dir, user);
88 if (!(out = fopen(filename, "a"))) {
89 logwrite(LOG_ALERT, "could not open file %s: %s\n", filename, strerror(errno));
90 } else {
91 #ifdef USE_LIBLOCKFILE
92 gint err;
93 /* lock file using liblockfile */
94 err = maillock(user, 3);
95 if (err == 0) {
96 #else
97 /* lock file: */
98 struct flock lock;
99 lock.l_type = F_WRLCK;
100 lock.l_whence = SEEK_END;
101 lock.l_start = lock.l_len = 0;
102 if (fcntl(fileno(out), F_SETLK, &lock) != -1) {
103 #endif
104 fchmod(fileno(out), 0600);
105 message_stream(out, msg, hdr_list, MSGSTR_FROMLINE | MSGSTR_FROMHACK);
106 ok = TRUE;
107
108 /* close when still user */
109 fclose(out);
110 #ifdef USE_LIBLOCKFILE
111 mailunlock();
112 #endif
113 } else {
114 fclose(out);
115 #ifdef USE_LIBLOCKFILE
116 DEBUG(3) debugf("could not lock file %s: error %d\n", filename, err);
117 } /* XEmacs indenting convenience... */
118 #else
119 DEBUG(3) debugf("could not lock file %s: %s\n", filename, strerror(errno));
120 }
121 #endif
122 }
123 g_free(filename);
124
125 if (!conf.run_as_user) {
126 uid_ok = (seteuid(0) == 0);
127 if (uid_ok) {
128 gid_ok = (setegid(saved_gid) == 0);
129 uid_ok = (seteuid(saved_uid) == 0);
130 }
131 }
132
133 if (!uid_ok || !gid_ok) {
134 /* FIXME: if this fails we HAVE to exit, because we shall not run
135 with some users id. But we do not return, and so this message
136 will not be finished, so the user will get the message again
137 next time a delivery is attempted... */
138 logwrite(LOG_ALERT, "could not set back uid or gid after local delivery: %s\n", strerror(errno));
139 logwrite(LOG_ALERT, "uid=%d, gid=%d, euid=%d, egid=%d, want = %d, %d\n",
140 getuid(), getgid(), geteuid(), getegid(), saved_uid, saved_gid);
141 logwrite(LOG_ALERT, "In case of trouble, see local.c:append_file() for details.\n", strerror(errno));
142 exit(1);
143 }
145 return ok; 144 return ok;
146 } 145 }
147 146
148 gboolean 147 gboolean
149 pipe_out(message * msg, GList * hdr_list, address * rcpt, gchar * cmd, guint flags) 148 pipe_out(message * msg, GList * hdr_list, address * rcpt, gchar * cmd, guint flags)
155 gboolean ok = FALSE; 154 gboolean ok = FALSE;
156 gint i, n; 155 gint i, n;
157 pid_t pid; 156 pid_t pid;
158 void (*old_signal) (int); 157 void (*old_signal) (int);
159 int status; 158 int status;
159 address *ancestor = addr_find_ancestor(rcpt);
160 160
161 /* set uid and gid to the mail ids */ 161 /* set uid and gid to the mail ids */
162 if (!conf.run_as_user) { 162 if (!conf.run_as_user) {
163 set_euidgid(conf.mail_uid, conf.mail_gid, &saved_uid, &saved_gid); 163 set_euidgid(conf.mail_uid, conf.mail_gid, &saved_uid, &saved_gid);
164 } 164 }
165 165
166 /* set environment */ 166 /* set environment */
167 { 167 n = 0;
168 gint i = 0; 168 envp[n++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain);
169 address *ancestor = addr_find_ancestor(rcpt); 169 envp[n++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain);
170 170 envp[n++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part);
171 envp[i++] = g_strdup_printf("SENDER=%s@%s", msg->return_path->local_part, msg->return_path->domain); 171 envp[n++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : "");
172 envp[i++] = g_strdup_printf("SENDER_DOMAIN=%s", msg->return_path->domain); 172
173 envp[i++] = g_strdup_printf("SENDER_LOCAL=%s", msg->return_path->local_part); 173 envp[n++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain);
174 envp[i++] = g_strdup_printf("RECEIVED_HOST=%s", msg->received_host ? msg->received_host : ""); 174 envp[n++] = g_strdup_printf("DOMAIN=%s", ancestor->domain);
175 175
176 envp[i++] = g_strdup_printf("RETURN_PATH=%s@%s", msg->return_path->local_part, msg->return_path->domain); 176 envp[n++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part);
177 envp[i++] = g_strdup_printf("DOMAIN=%s", ancestor->domain); 177 envp[n++] = g_strdup_printf("USER=%s", ancestor->local_part);
178 178 envp[n++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part);
179 envp[i++] = g_strdup_printf("LOCAL_PART=%s", ancestor->local_part); 179
180 envp[i++] = g_strdup_printf("USER=%s", ancestor->local_part); 180 envp[n++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid);
181 envp[i++] = g_strdup_printf("LOGNAME=%s", ancestor->local_part); 181 envp[n++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
182 182
183 envp[i++] = g_strdup_printf("MESSAGE_ID=%s", msg->uid); 183 envp[n] = NULL;
184 envp[i++] = g_strdup_printf("QUALIFY_DOMAIN=%s", conf.host_name);
185
186 envp[i] = NULL;
187 n = i;
188 }
189 184
190 old_signal = signal(SIGCHLD, SIG_DFL); 185 old_signal = signal(SIGCHLD, SIG_DFL);
191 186
192 out = peidopen(cmd, "w", envp, &pid, conf.mail_uid, conf.mail_gid); 187 out = peidopen(cmd, "w", envp, &pid, conf.mail_uid, conf.mail_gid);
193 if (out != NULL) { 188 if (!out) {
189 logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
190 } else {
194 message_stream(out, msg, hdr_list, flags); 191 message_stream(out, msg, hdr_list, flags);
195 192
196 fclose(out); 193 fclose(out);
197 194
198 waitpid(pid, &status, 0); 195 waitpid(pid, &status, 0);
204 } else if (WIFSIGNALED(status)) { 201 } else if (WIFSIGNALED(status)) {
205 logwrite(LOG_ALERT, "process got signal %d\n", WTERMSIG(status)); 202 logwrite(LOG_ALERT, "process got signal %d\n", WTERMSIG(status));
206 } else 203 } else
207 ok = TRUE; 204 ok = TRUE;
208 205
209 } else 206 }
210 logwrite(LOG_ALERT, "could not open pipe '%s': %s\n", cmd, strerror(errno));
211 207
212 signal(SIGCHLD, old_signal); 208 signal(SIGCHLD, old_signal);
213 209
214 /* free environment */ 210 /* free environment */
215 for (i = 0; i < n; i++) { 211 for (i = 0; i < n; i++) {