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