Mercurial > masqmail
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++) { |