Mercurial > dovecot > original-hg > dovecot-1.2
annotate src/master/login-process.c @ 532:3b53dd1280c6 HEAD
I/O buffers now use real blocking instead of setting up a sub-ioloop to
poll(). alarm() is called every 30 secs to send SIGHUP and break out of the
read/write calls, so the given timeout values aren't exact.
Also some other cleanups, like not including ioloop.h in [io]buffer.h which
broke several other files which hadn't included it itself..
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 28 Oct 2002 06:18:26 +0200 |
parents | 1f0e7229ee58 |
children | ab3590c3a7d9 |
rev | line source |
---|---|
0 | 1 /* Copyright (C) 2002 Timo Sirainen */ |
2 | |
3 #include "common.h" | |
532
3b53dd1280c6
I/O buffers now use real blocking instead of setting up a sub-ioloop to
Timo Sirainen <tss@iki.fi>
parents:
410
diff
changeset
|
4 #include "ioloop.h" |
0 | 5 #include "network.h" |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
6 #include "obuffer.h" |
0 | 7 #include "fdpass.h" |
8 #include "restrict-access.h" | |
9 #include "login-process.h" | |
10 #include "auth-process.h" | |
11 #include "master-interface.h" | |
12 | |
13 #include <stdlib.h> | |
14 #include <unistd.h> | |
15 #include <syslog.h> | |
16 | |
17 typedef struct { | |
18 int refcount; | |
19 | |
20 pid_t pid; | |
21 int fd; | |
22 IO io; | |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
23 OBuffer *outbuf; |
0 | 24 unsigned int destroyed:1; |
25 } LoginProcess; | |
26 | |
27 typedef struct { | |
28 LoginProcess *process; | |
29 int login_id; | |
30 int auth_id; | |
31 int fd; | |
32 | |
33 char login_tag[LOGIN_TAG_SIZE]; | |
34 } LoginAuthRequest; | |
35 | |
36 static int auth_id_counter; | |
37 static Timeout to; | |
38 static HashTable *processes = NULL; | |
39 | |
40 static void login_process_destroy(LoginProcess *p); | |
41 static void login_process_unref(LoginProcess *p); | |
42 | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
43 static void auth_callback(AuthCookieReplyData *cookie_reply, void *context) |
0 | 44 { |
45 const char *env[] = { | |
46 "MAIL", NULL, | |
47 "LOGIN_TAG", NULL, | |
48 NULL | |
49 }; | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
50 LoginAuthRequest *request = context; |
0 | 51 LoginProcess *process; |
52 MasterReply reply; | |
53 | |
54 env[1] = cookie_reply->mail; | |
55 env[3] = request->login_tag; | |
56 | |
57 if (cookie_reply == NULL || !cookie_reply->success) | |
58 reply.result = MASTER_RESULT_FAILURE; | |
59 else { | |
60 reply.result = create_imap_process(request->fd, | |
61 cookie_reply->user, | |
62 cookie_reply->uid, | |
63 cookie_reply->gid, | |
64 cookie_reply->home, | |
65 cookie_reply->chroot, env); | |
66 } | |
67 | |
68 /* reply to login */ | |
69 reply.id = request->login_id; | |
70 | |
71 process = request->process; | |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
72 if (o_buffer_send(process->outbuf, &reply, sizeof(reply)) < 0) |
0 | 73 login_process_destroy(process); |
74 | |
75 (void)close(request->fd); | |
76 login_process_unref(process); | |
77 i_free(request); | |
78 } | |
79 | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
80 static void login_process_input(void *context, int fd __attr_unused__, |
0 | 81 IO io __attr_unused__) |
82 { | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
83 LoginProcess *p = context; |
0 | 84 AuthProcess *auth_process; |
85 LoginAuthRequest *authreq; | |
86 MasterRequest req; | |
87 int client_fd, ret; | |
88 | |
89 ret = fd_read(p->fd, &req, sizeof(req), &client_fd); | |
90 if (ret != sizeof(req)) { | |
91 if (ret == 0) { | |
92 /* disconnected, ie. the login process died */ | |
93 } else if (ret > 0) { | |
94 /* req wasn't fully read */ | |
95 i_error("login: fd_read() couldn't read all req"); | |
96 } else { | |
97 i_error("login: fd_read() failed: %m"); | |
98 } | |
99 | |
100 login_process_destroy(p); | |
101 return; | |
102 } | |
103 | |
104 /* login process isn't trusted, validate all data to make sure | |
105 it's not trying to exploit us */ | |
106 if (!VALIDATE_STR(req.login_tag)) { | |
107 i_error("login: Received corrupted data"); | |
108 login_process_destroy(p); | |
109 return; | |
110 } | |
111 | |
112 /* ask the cookie from the auth process */ | |
113 authreq = i_new(LoginAuthRequest, 1); | |
114 p->refcount++; | |
115 authreq->process = p; | |
116 authreq->login_id = req.id; | |
117 authreq->auth_id = ++auth_id_counter; | |
118 authreq->fd = client_fd; | |
119 strcpy(authreq->login_tag, req.login_tag); | |
120 | |
121 auth_process = auth_process_find(req.auth_process); | |
122 if (auth_process == NULL) { | |
123 i_error("login: Authentication process %u doesn't exist", | |
124 req.auth_process); | |
125 auth_callback(NULL, &authreq); | |
126 } else { | |
127 auth_process_request(auth_process, authreq->auth_id, req.cookie, | |
128 auth_callback, authreq); | |
129 } | |
130 } | |
131 | |
132 static LoginProcess *login_process_new(pid_t pid, int fd) | |
133 { | |
134 LoginProcess *p; | |
135 | |
136 PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_LOGIN); | |
137 | |
138 p = i_new(LoginProcess, 1); | |
139 p->refcount = 1; | |
140 p->pid = pid; | |
141 p->fd = fd; | |
142 p->io = io_add(fd, IO_READ, login_process_input, p); | |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
143 p->outbuf = o_buffer_create_file(fd, default_pool, |
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
144 sizeof(MasterReply)*10, |
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
145 IO_PRIORITY_DEFAULT, FALSE); |
0 | 146 |
195
db6e288be0e9
Replaced INT_TO_POINTER and POINTER_TO_INT macros with POINTER_CAST and
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
147 hash_insert(processes, POINTER_CAST(pid), p); |
0 | 148 return p; |
149 } | |
150 | |
151 static void login_process_destroy(LoginProcess *p) | |
152 { | |
153 if (p->destroyed) | |
154 return; | |
155 p->destroyed = TRUE; | |
156 | |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
157 o_buffer_close(p->outbuf); |
0 | 158 io_remove(p->io); |
159 (void)close(p->fd); | |
160 | |
195
db6e288be0e9
Replaced INT_TO_POINTER and POINTER_TO_INT macros with POINTER_CAST and
Timo Sirainen <tss@iki.fi>
parents:
10
diff
changeset
|
161 hash_remove(processes, POINTER_CAST(p->pid)); |
0 | 162 login_process_unref(p); |
163 } | |
164 | |
165 static void login_process_unref(LoginProcess *p) | |
166 { | |
167 if (--p->refcount > 0) | |
168 return; | |
169 | |
410
1f0e7229ee58
Split IOBuffer into mmaped IBuffer, file IBuffer, memory data IBuffer and
Timo Sirainen <tss@iki.fi>
parents:
364
diff
changeset
|
170 o_buffer_unref(p->outbuf); |
0 | 171 i_free(p); |
172 } | |
173 | |
174 static pid_t create_login_process(void) | |
175 { | |
176 static const char *argv[] = { NULL, NULL }; | |
177 pid_t pid; | |
178 int fd[2]; | |
179 | |
180 if (set_login_uid == 0) | |
181 i_fatal("Login process must not run as root"); | |
182 | |
183 /* create communication to process with a socket pair */ | |
184 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) { | |
185 i_error("socketpair() failed: %m"); | |
186 return -1; | |
187 } | |
188 | |
189 pid = fork(); | |
190 if (pid < 0) { | |
191 (void)close(fd[0]); | |
192 (void)close(fd[1]); | |
193 i_error("fork() failed: %m"); | |
194 return -1; | |
195 } | |
196 | |
197 if (pid != 0) { | |
198 /* master */ | |
199 login_process_new(pid, fd[0]); | |
200 (void)close(fd[1]); | |
201 return pid; | |
202 } | |
203 | |
204 /* move communication handle */ | |
205 if (dup2(fd[1], LOGIN_MASTER_SOCKET_FD) < 0) | |
206 i_fatal("login: dup2() failed: %m"); | |
207 | |
208 /* move the listen handle */ | |
209 if (dup2(imap_fd, LOGIN_IMAP_LISTEN_FD) < 0) | |
210 i_fatal("login: dup2() failed: %m"); | |
211 | |
212 /* move the SSL listen handle */ | |
213 if (dup2(imaps_fd, LOGIN_IMAPS_LISTEN_FD) < 0) | |
214 i_fatal("login: dup2() failed: %m"); | |
215 | |
216 /* imap_fd and imaps_fd are closed by clean_child_process() */ | |
217 | |
218 (void)close(fd[0]); | |
219 (void)close(fd[1]); | |
220 | |
221 clean_child_process(); | |
222 | |
223 /* setup access environment - needs to be done after | |
224 clean_child_process() since it clears environment */ | |
225 restrict_access_set_env(set_login_user, set_login_uid, set_login_gid, | |
226 set_login_chroot ? set_login_dir : NULL); | |
227 | |
228 if (!set_login_chroot) { | |
229 /* no chrooting, but still change to the directory */ | |
230 if (chdir(set_login_dir) < 0) { | |
231 i_fatal("chdir(%s) failed: %m", | |
232 set_login_dir); | |
233 } | |
234 } | |
235 | |
236 if (set_ssl_cert_file != NULL) { | |
237 putenv((char *) t_strconcat("SSL_CERT_FILE=", | |
238 set_ssl_cert_file, NULL)); | |
239 } | |
240 | |
241 if (set_ssl_key_file != NULL) { | |
242 putenv((char *) t_strconcat("SSL_KEY_FILE=", | |
243 set_ssl_key_file, NULL)); | |
244 } | |
245 | |
246 if (set_disable_plaintext_auth) | |
247 putenv("DISABLE_PLAINTEXT_AUTH=1"); | |
248 | |
249 putenv((char *) t_strdup_printf("MAX_LOGGING_USERS=%d", | |
250 set_max_logging_users)); | |
251 | |
252 /* hide the path, it's ugly */ | |
253 argv[0] = strrchr(set_login_executable, '/'); | |
254 if (argv[0] == NULL) argv[0] = set_login_executable; else argv[0]++; | |
255 | |
256 execv(set_login_executable, (char **) argv); | |
257 | |
258 i_fatal("execv(%s) failed: %m", argv[0]); | |
259 return -1; | |
260 } | |
261 | |
262 static void login_hash_cleanup(void *key __attr_unused__, void *value, | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
263 void *context __attr_unused__) |
0 | 264 { |
265 LoginProcess *p = value; | |
266 | |
267 (void)close(p->fd); | |
268 } | |
269 | |
270 void login_processes_cleanup(void) | |
271 { | |
272 hash_foreach(processes, login_hash_cleanup, NULL); | |
273 } | |
274 | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
275 static void login_processes_start_missing(void *context __attr_unused__, |
0 | 276 Timeout timeout __attr_unused__) |
277 { | |
278 /* create max. one process every second, that way if it keeps | |
279 dying all the time we don't eat all cpu with fork()ing. */ | |
280 if (hash_size(processes) < set_login_processes_count) | |
281 (void)create_login_process(); | |
282 } | |
283 | |
284 void login_processes_init(void) | |
285 { | |
286 auth_id_counter = 0; | |
287 processes = hash_create(default_pool, 128, NULL, NULL); | |
288 to = timeout_add(1000, login_processes_start_missing, NULL); | |
289 } | |
290 | |
291 static void login_hash_destroy(void *key __attr_unused__, void *value, | |
10
82b7de533f98
s/user_data/context/ and some s/Data/Context/
Timo Sirainen <tss@iki.fi>
parents:
0
diff
changeset
|
292 void *context __attr_unused__) |
0 | 293 { |
294 login_process_destroy(value); | |
295 } | |
296 | |
297 void login_processes_deinit(void) | |
298 { | |
299 timeout_remove(to); | |
300 | |
301 hash_foreach(processes, login_hash_destroy, NULL); | |
302 hash_destroy(processes); | |
303 } |