]>
Commit | Line | Data |
---|---|---|
d1e348cf A |
1 | /* $NetBSD: privsep.c,v 1.6 2006/09/09 16:22:10 manu Exp $ */ |
2 | ||
3 | /* Id: privsep.c,v 1.15 2005/08/08 11:23:44 vanhu Exp */ | |
52b7d2ce A |
4 | |
5 | /* | |
6 | * Copyright (C) 2004 Emmanuel Dreyfus | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | |
17 | * 3. Neither the name of the project nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #include "config.h" | |
35 | ||
36 | #include <unistd.h> | |
37 | #include <string.h> | |
38 | #ifdef __NetBSD__ | |
39 | #include <stdlib.h> /* for setproctitle */ | |
40 | #endif | |
41 | #include <errno.h> | |
42 | #include <signal.h> | |
43 | #include <pwd.h> | |
44 | ||
45 | #include <sys/socket.h> | |
46 | #include <sys/param.h> | |
47 | ||
48 | #include "gcmalloc.h" | |
49 | #include "vmbuf.h" | |
50 | #include "misc.h" | |
51 | #include "plog.h" | |
52 | #include "var.h" | |
53 | #include "libpfkey.h" | |
54 | ||
55 | #include "crypto_openssl.h" | |
56 | #include "isakmp_var.h" | |
57 | #include "isakmp.h" | |
58 | #ifdef ENABLE_HYBRID | |
d1e348cf | 59 | #include "resolv.h" |
52b7d2ce A |
60 | #include "isakmp_xauth.h" |
61 | #include "isakmp_cfg.h" | |
62 | #endif | |
63 | #include "localconf.h" | |
64 | #include "remoteconf.h" | |
65 | #include "admin.h" | |
d1e348cf | 66 | #include "sockmisc.h" |
52b7d2ce A |
67 | #include "privsep.h" |
68 | ||
69 | static int privsep_sock[2] = { -1, -1 }; | |
70 | ||
71 | static int privsep_recv(int, struct privsep_com_msg **, size_t *); | |
72 | static int privsep_send(int, struct privsep_com_msg *, size_t); | |
73 | static int safety_check(struct privsep_com_msg *, int i); | |
52b7d2ce | 74 | static int port_check(int); |
52b7d2ce A |
75 | static int unsafe_env(char *const *); |
76 | static int unknown_name(int); | |
52b7d2ce | 77 | static int unsafe_path(char *, int); |
52b7d2ce A |
78 | |
79 | static int | |
80 | privsep_send(sock, buf, len) | |
81 | int sock; | |
82 | struct privsep_com_msg *buf; | |
83 | size_t len; | |
84 | { | |
85 | if (buf == NULL) | |
86 | return 0; | |
87 | ||
88 | if (sendto(sock, (char *)buf, len, 0, NULL, 0) == -1) { | |
89 | plog(LLV_ERROR, LOCATION, NULL, | |
90 | "privsep_send failed: %s\n", | |
91 | strerror(errno)); | |
92 | return -1; | |
93 | } | |
94 | ||
95 | racoon_free((char *)buf); | |
96 | ||
97 | return 0; | |
98 | } | |
99 | ||
100 | ||
101 | static int | |
102 | privsep_recv(sock, bufp, lenp) | |
103 | int sock; | |
104 | struct privsep_com_msg **bufp; | |
105 | size_t *lenp; | |
106 | { | |
107 | struct admin_com com; | |
108 | struct admin_com *combuf; | |
109 | size_t len; | |
110 | ||
111 | *bufp = NULL; | |
112 | *lenp = 0; | |
113 | ||
114 | /* Get the header */ | |
115 | while ((len = recvfrom(sock, (char *)&com, | |
116 | sizeof(com), MSG_PEEK, NULL, NULL)) == -1) { | |
117 | if (errno == EINTR) | |
118 | continue; | |
119 | ||
120 | plog(LLV_ERROR, LOCATION, NULL, | |
121 | "privsep_recv failed: %s\n", | |
122 | strerror(errno)); | |
123 | return -1; | |
124 | } | |
125 | ||
126 | /* Check for short packets */ | |
127 | if (len < sizeof(com)) { | |
128 | plog(LLV_ERROR, LOCATION, NULL, | |
129 | "corrupted privsep message (short header)\n"); | |
130 | return -1; | |
131 | } | |
132 | ||
133 | /* Allocate buffer for the whole message */ | |
134 | if ((combuf = (struct admin_com *)racoon_malloc(com.ac_len)) == NULL) { | |
135 | plog(LLV_ERROR, LOCATION, NULL, | |
136 | "failed to allocate memory: %s\n", strerror(errno)); | |
137 | return -1; | |
138 | } | |
139 | ||
140 | /* Get the whole buffer */ | |
141 | while ((len = recvfrom(sock, (char *)combuf, | |
142 | com.ac_len, 0, NULL, NULL)) == -1) { | |
143 | if (errno == EINTR) | |
144 | continue; | |
145 | plog(LLV_ERROR, LOCATION, NULL, | |
146 | "failed to recv privsep command: %s\n", | |
147 | strerror(errno)); | |
148 | return -1; | |
149 | } | |
150 | ||
151 | /* We expect len to match */ | |
152 | if (len != com.ac_len) { | |
153 | plog(LLV_ERROR, LOCATION, NULL, | |
154 | "corrupted privsep message (short packet)\n"); | |
155 | return -1; | |
156 | } | |
157 | ||
158 | *bufp = (struct privsep_com_msg *)combuf; | |
159 | *lenp = len; | |
160 | ||
161 | return 0; | |
162 | } | |
163 | ||
164 | int | |
165 | privsep_init(void) | |
166 | { | |
167 | int i; | |
168 | pid_t child_pid; | |
169 | ||
170 | /* If running as root, we don't use the privsep code path */ | |
171 | if (lcconf->uid == 0) | |
172 | return 0; | |
173 | ||
174 | /* | |
175 | * When running privsep, certificate and script paths | |
176 | * are mandatory, as they enable us to check path safety | |
177 | * in the privilegied instance | |
178 | */ | |
179 | if ((lcconf->pathinfo[LC_PATHTYPE_CERT] == NULL) || | |
180 | (lcconf->pathinfo[LC_PATHTYPE_SCRIPT] == NULL)) { | |
181 | plog(LLV_ERROR, LOCATION, NULL, "privilege separation " | |
d1e348cf | 182 | "require path cert and path script in the config file\n"); |
52b7d2ce A |
183 | return -1; |
184 | } | |
185 | ||
186 | if (socketpair(PF_LOCAL, SOCK_DGRAM, 0, privsep_sock) != 0) { | |
187 | plog(LLV_ERROR, LOCATION, NULL, | |
188 | "Cannot allocate privsep_sock: %s\n", strerror(errno)); | |
189 | return -1; | |
190 | } | |
191 | ||
192 | switch (child_pid = fork()) { | |
193 | case -1: | |
194 | plog(LLV_ERROR, LOCATION, NULL, "Cannot fork privsep: %s\n", | |
195 | strerror(errno)); | |
196 | return -1; | |
197 | break; | |
198 | ||
199 | case 0: /* Child: drop privileges */ | |
200 | if (lcconf->chroot != NULL) { | |
201 | if (chdir(lcconf->chroot) != 0) { | |
202 | plog(LLV_ERROR, LOCATION, NULL, | |
203 | "Cannot chdir(%s): %s\n", lcconf->chroot, | |
204 | strerror(errno)); | |
205 | return -1; | |
206 | } | |
207 | if (chroot(lcconf->chroot) != 0) { | |
208 | plog(LLV_ERROR, LOCATION, NULL, | |
209 | "Cannot chroot(%s): %s\n", lcconf->chroot, | |
210 | strerror(errno)); | |
211 | return -1; | |
212 | } | |
213 | } | |
214 | ||
215 | if (setgid(lcconf->gid) != 0) { | |
216 | plog(LLV_ERROR, LOCATION, NULL, | |
217 | "Cannot setgid(%d): %s\n", lcconf->gid, | |
218 | strerror(errno)); | |
219 | return -1; | |
220 | } | |
221 | ||
222 | if (setegid(lcconf->gid) != 0) { | |
223 | plog(LLV_ERROR, LOCATION, NULL, | |
224 | "Cannot setegid(%d): %s\n", lcconf->gid, | |
225 | strerror(errno)); | |
226 | return -1; | |
227 | } | |
228 | ||
229 | if (setuid(lcconf->uid) != 0) { | |
230 | plog(LLV_ERROR, LOCATION, NULL, | |
231 | "Cannot setuid(%d): %s\n", lcconf->uid, | |
232 | strerror(errno)); | |
233 | return -1; | |
234 | } | |
235 | ||
236 | if (seteuid(lcconf->uid) != 0) { | |
237 | plog(LLV_ERROR, LOCATION, NULL, | |
238 | "Cannot seteuid(%d): %s\n", lcconf->uid, | |
239 | strerror(errno)); | |
240 | return -1; | |
241 | } | |
242 | ||
243 | return 0; | |
244 | break; | |
245 | ||
246 | default: /* Parent: privilegied process */ | |
247 | break; | |
248 | } | |
249 | ||
250 | /* | |
251 | * Close everything except the socketpair, | |
252 | * and stdout if running in the forground. | |
253 | */ | |
254 | for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) { | |
255 | if (i == privsep_sock[0]) | |
256 | continue; | |
257 | if (i == privsep_sock[1]) | |
258 | continue; | |
259 | if ((f_foreground) && (i == 1)) | |
260 | continue; | |
261 | (void)close(i); | |
262 | } | |
263 | ||
264 | /* Above trickery closed the log file, reopen it */ | |
265 | ploginit(); | |
266 | ||
267 | plog(LLV_INFO, LOCATION, NULL, | |
268 | "racoon privilegied process running with PID %d\n", getpid()); | |
269 | ||
270 | #ifdef __NetBSD__ | |
271 | setproctitle("[priv]"); | |
272 | #endif | |
273 | ||
274 | /* | |
275 | * Don't catch any signal | |
276 | * This duplicate session:signals[], which is static... | |
277 | */ | |
278 | signal(SIGHUP, SIG_DFL); | |
279 | signal(SIGINT, SIG_DFL); | |
280 | signal(SIGTERM, SIG_DFL); | |
281 | signal(SIGUSR1, SIG_DFL); | |
282 | signal(SIGUSR2, SIG_DFL); | |
283 | signal(SIGCHLD, SIG_DFL); | |
284 | ||
285 | while (1) { | |
286 | size_t len; | |
287 | struct privsep_com_msg *combuf; | |
288 | struct privsep_com_msg *reply; | |
289 | char *data; | |
290 | size_t *buflen; | |
291 | size_t totallen; | |
292 | char *bufs[PRIVSEP_NBUF_MAX]; | |
293 | int i; | |
294 | ||
295 | if (privsep_recv(privsep_sock[0], &combuf, &len) != 0) | |
296 | goto out; | |
297 | ||
298 | /* Safety checks and gather the data */ | |
299 | if (len < sizeof(*combuf)) { | |
300 | plog(LLV_ERROR, LOCATION, NULL, | |
301 | "corrupted privsep message (short buflen)\n"); | |
302 | goto out; | |
303 | } | |
304 | ||
305 | data = (char *)(combuf + 1); | |
306 | totallen = sizeof(*combuf); | |
307 | for (i = 0; i < PRIVSEP_NBUF_MAX; i++) { | |
308 | bufs[i] = (char *)data; | |
309 | data += combuf->bufs.buflen[i]; | |
310 | totallen += combuf->bufs.buflen[i]; | |
311 | } | |
312 | ||
313 | if (totallen > len) { | |
314 | plog(LLV_ERROR, LOCATION, NULL, | |
315 | "corrupted privsep message (bufs too big)\n"); | |
316 | goto out; | |
317 | } | |
318 | ||
319 | /* Prepare the reply buffer */ | |
320 | if ((reply = racoon_malloc(sizeof(*reply))) == NULL) { | |
321 | plog(LLV_ERROR, LOCATION, NULL, | |
322 | "Cannot allocate reply buffer: %s\n", | |
323 | strerror(errno)); | |
324 | goto out; | |
325 | } | |
326 | bzero(reply, sizeof(*reply)); | |
327 | reply->hdr.ac_cmd = combuf->hdr.ac_cmd; | |
328 | reply->hdr.ac_len = sizeof(*reply); | |
329 | ||
330 | switch(combuf->hdr.ac_cmd) { | |
331 | /* | |
332 | * XXX Improvement: instead of returning the key, | |
333 | * stuff eay_get_pkcs1privkey and eay_get_x509sign | |
334 | * together and sign the hash in the privilegied | |
335 | * instance? | |
d1e348cf | 336 | * pro: the key remains inaccessible to unpriv |
52b7d2ce A |
337 | * con: a compromised unpriv racoon can still sign anything |
338 | */ | |
339 | case PRIVSEP_EAY_GET_PKCS1PRIVKEY: { | |
340 | vchar_t *privkey; | |
341 | ||
342 | /* Make sure the string is NULL terminated */ | |
343 | if (safety_check(combuf, 0) != 0) | |
344 | break; | |
345 | bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; | |
346 | ||
347 | if (unsafe_path(bufs[0], LC_PATHTYPE_CERT) != 0) { | |
d1e348cf | 348 | plog(LLV_ERROR, LOCATION, NULL, |
52b7d2ce | 349 | "privsep_eay_get_pkcs1privkey: " |
d1e348cf | 350 | "unsafe cert \"%s\"\n", bufs[0]); |
52b7d2ce A |
351 | } |
352 | ||
d1e348cf A |
353 | plog(LLV_DEBUG, LOCATION, NULL, |
354 | "eay_get_pkcs1privkey(\"%s\")\n", bufs[0]); | |
355 | ||
52b7d2ce A |
356 | if ((privkey = eay_get_pkcs1privkey(bufs[0])) == NULL){ |
357 | reply->hdr.ac_errno = errno; | |
358 | break; | |
359 | } | |
360 | ||
361 | reply->bufs.buflen[0] = privkey->l; | |
362 | reply->hdr.ac_len = sizeof(*reply) + privkey->l; | |
363 | reply = racoon_realloc(reply, reply->hdr.ac_len); | |
364 | if (reply == NULL) { | |
365 | plog(LLV_ERROR, LOCATION, NULL, | |
366 | "Cannot allocate reply buffer: %s\n", | |
367 | strerror(errno)); | |
368 | goto out; | |
369 | } | |
370 | ||
371 | memcpy(reply + 1, privkey->v, privkey->l); | |
372 | vfree(privkey); | |
373 | break; | |
374 | } | |
375 | ||
376 | case PRIVSEP_SCRIPT_EXEC: { | |
d1e348cf | 377 | char *script; |
52b7d2ce A |
378 | int name; |
379 | char **envp = NULL; | |
380 | int envc = 0; | |
381 | int count = 0; | |
382 | int i; | |
383 | ||
384 | /* | |
385 | * First count the bufs, and make sure strings | |
386 | * are NULL terminated. | |
387 | * | |
388 | * We expect: script, name, envp[], void | |
389 | */ | |
d1e348cf A |
390 | if (safety_check(combuf, 0) != 0) |
391 | break; | |
392 | bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; | |
52b7d2ce A |
393 | count++; /* script */ |
394 | count++; /* name */ | |
395 | ||
396 | for (; count < PRIVSEP_NBUF_MAX; count++) { | |
397 | if (combuf->bufs.buflen[count] == 0) | |
398 | break; | |
399 | bufs[count] | |
400 | [combuf->bufs.buflen[count] - 1] = '\0'; | |
401 | envc++; | |
402 | } | |
403 | ||
404 | /* count a void buf and perform safety check */ | |
405 | count++; | |
406 | if (count >= PRIVSEP_NBUF_MAX) { | |
407 | plog(LLV_ERROR, LOCATION, NULL, | |
408 | "privsep_script_exec: too many args\n"); | |
409 | goto out; | |
410 | } | |
411 | ||
412 | ||
413 | /* | |
414 | * Allocate the arrays for envp | |
415 | */ | |
416 | envp = racoon_malloc((envc + 1) * sizeof(char *)); | |
417 | if (envp == NULL) { | |
418 | plog(LLV_ERROR, LOCATION, NULL, | |
419 | "cannot allocate memory: %s\n", | |
420 | strerror(errno)); | |
421 | goto out; | |
422 | } | |
423 | bzero(envp, (envc + 1) * sizeof(char *)); | |
424 | ||
425 | ||
426 | /* | |
427 | * Populate script, name and envp | |
428 | */ | |
429 | count = 0; | |
d1e348cf | 430 | script = bufs[count++]; |
52b7d2ce A |
431 | |
432 | if (combuf->bufs.buflen[count] != sizeof(name)) { | |
433 | plog(LLV_ERROR, LOCATION, NULL, | |
434 | "privsep_script_exec: corrupted message\n"); | |
435 | goto out; | |
436 | } | |
437 | memcpy((char *)&name, bufs[count++], sizeof(name)); | |
438 | ||
439 | for (i = 0; combuf->bufs.buflen[count]; count++) | |
440 | envp[i++] = bufs[count]; | |
441 | ||
442 | count++; /* void */ | |
443 | ||
d1e348cf A |
444 | plog(LLV_DEBUG, LOCATION, NULL, |
445 | "script_exec(\"%s\", %d, %p)\n", | |
446 | script, name, envp); | |
447 | ||
52b7d2ce A |
448 | /* |
449 | * Check env for dangerous variables | |
450 | * Check script path and name | |
451 | * Perform fork and execve | |
452 | */ | |
453 | if ((unsafe_env(envp) == 0) && | |
454 | (unknown_name(name) == 0) && | |
d1e348cf | 455 | (unsafe_path(script, LC_PATHTYPE_SCRIPT) == 0)) |
52b7d2ce A |
456 | (void)script_exec(script, name, envp); |
457 | else | |
d1e348cf | 458 | plog(LLV_ERROR, LOCATION, NULL, |
52b7d2ce | 459 | "privsep_script_exec: " |
d1e348cf | 460 | "unsafe script \"%s\"\n", script); |
52b7d2ce A |
461 | |
462 | racoon_free(envp); | |
463 | break; | |
464 | } | |
465 | ||
466 | case PRIVSEP_GETPSK: { | |
467 | vchar_t *psk; | |
468 | int keylen; | |
469 | ||
470 | /* Make sure the string is NULL terminated */ | |
471 | if (safety_check(combuf, 0) != 0) | |
472 | break; | |
473 | bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; | |
474 | ||
475 | if (combuf->bufs.buflen[1] != sizeof(keylen)) { | |
476 | plog(LLV_ERROR, LOCATION, NULL, | |
477 | "privsep_getpsk: corrupted message\n"); | |
478 | goto out; | |
479 | } | |
480 | memcpy(&keylen, bufs[1], sizeof(keylen)); | |
d1e348cf A |
481 | |
482 | plog(LLV_DEBUG, LOCATION, NULL, | |
483 | "getpsk(\"%s\", %d)\n", bufs[0], keylen); | |
484 | ||
52b7d2ce A |
485 | if ((psk = getpsk(bufs[0], keylen)) == NULL) { |
486 | reply->hdr.ac_errno = errno; | |
487 | break; | |
488 | } | |
489 | ||
490 | reply->bufs.buflen[0] = psk->l; | |
491 | reply->hdr.ac_len = sizeof(*reply) + psk->l; | |
492 | reply = racoon_realloc(reply, reply->hdr.ac_len); | |
493 | if (reply == NULL) { | |
494 | plog(LLV_ERROR, LOCATION, NULL, | |
495 | "Cannot allocate reply buffer: %s\n", | |
496 | strerror(errno)); | |
497 | goto out; | |
498 | } | |
499 | ||
500 | memcpy(reply + 1, psk->v, psk->l); | |
501 | vfree(psk); | |
502 | break; | |
503 | } | |
504 | ||
505 | #ifdef ENABLE_HYBRID | |
d1e348cf A |
506 | case PRIVSEP_ACCOUNTING_SYSTEM: { |
507 | int pool_size; | |
508 | int port; | |
509 | int inout; | |
510 | struct sockaddr *raddr; | |
511 | ||
512 | if (safety_check(combuf, 0) != 0) | |
513 | break; | |
514 | if (safety_check(combuf, 1) != 0) | |
515 | break; | |
516 | if (safety_check(combuf, 2) != 0) | |
517 | break; | |
518 | if (safety_check(combuf, 3) != 0) | |
519 | break; | |
520 | ||
521 | memcpy(&port, bufs[0], sizeof(port)); | |
522 | raddr = (struct sockaddr *)bufs[1]; | |
523 | ||
524 | bufs[2][combuf->bufs.buflen[2] - 1] = '\0'; | |
525 | memcpy(&inout, bufs[3], sizeof(port)); | |
526 | ||
527 | if (port_check(port) != 0) | |
528 | break; | |
529 | ||
530 | plog(LLV_DEBUG, LOCATION, NULL, | |
531 | "accounting_system(%d, %s, %s)\n", | |
532 | port, saddr2str(raddr), bufs[2]); | |
533 | ||
534 | errno = 0; | |
535 | if (isakmp_cfg_accounting_system(port, | |
536 | raddr, bufs[2], inout) != 0) { | |
537 | if (errno == 0) | |
538 | reply->hdr.ac_errno = EINVAL; | |
539 | else | |
540 | reply->hdr.ac_errno = errno; | |
541 | } | |
542 | break; | |
543 | } | |
52b7d2ce A |
544 | case PRIVSEP_XAUTH_LOGIN_SYSTEM: { |
545 | if (safety_check(combuf, 0) != 0) | |
546 | break; | |
547 | bufs[0][combuf->bufs.buflen[0] - 1] = '\0'; | |
548 | ||
549 | if (safety_check(combuf, 1) != 0) | |
550 | break; | |
551 | bufs[1][combuf->bufs.buflen[1] - 1] = '\0'; | |
552 | ||
d1e348cf A |
553 | plog(LLV_DEBUG, LOCATION, NULL, |
554 | "xauth_login_system(\"%s\", <password>)\n", | |
555 | bufs[0]); | |
556 | ||
52b7d2ce A |
557 | errno = 0; |
558 | if (xauth_login_system(bufs[0], bufs[1]) != 0) { | |
559 | if (errno == 0) | |
560 | reply->hdr.ac_errno = EINVAL; | |
561 | else | |
562 | reply->hdr.ac_errno = errno; | |
563 | } | |
564 | break; | |
565 | } | |
566 | #ifdef HAVE_LIBPAM | |
567 | case PRIVSEP_ACCOUNTING_PAM: { | |
568 | int port; | |
569 | int inout; | |
d1e348cf | 570 | int pool_size; |
52b7d2ce A |
571 | |
572 | if (safety_check(combuf, 0) != 0) | |
573 | break; | |
574 | if (safety_check(combuf, 1) != 0) | |
575 | break; | |
d1e348cf A |
576 | if (safety_check(combuf, 2) != 0) |
577 | break; | |
52b7d2ce A |
578 | |
579 | memcpy(&port, bufs[0], sizeof(port)); | |
580 | memcpy(&inout, bufs[1], sizeof(inout)); | |
d1e348cf A |
581 | memcpy(&pool_size, bufs[2], sizeof(pool_size)); |
582 | ||
583 | if (pool_size != isakmp_cfg_config.pool_size) | |
584 | if (isakmp_cfg_resize_pool(pool_size) != 0) | |
585 | break; | |
52b7d2ce A |
586 | |
587 | if (port_check(port) != 0) | |
588 | break; | |
589 | ||
d1e348cf A |
590 | plog(LLV_DEBUG, LOCATION, NULL, |
591 | "isakmp_cfg_accounting_pam(%d, %d)\n", | |
592 | port, inout); | |
593 | ||
52b7d2ce A |
594 | errno = 0; |
595 | if (isakmp_cfg_accounting_pam(port, inout) != 0) { | |
596 | if (errno == 0) | |
597 | reply->hdr.ac_errno = EINVAL; | |
598 | else | |
599 | reply->hdr.ac_errno = errno; | |
600 | } | |
601 | break; | |
602 | } | |
603 | ||
604 | case PRIVSEP_XAUTH_LOGIN_PAM: { | |
605 | int port; | |
d1e348cf | 606 | int pool_size; |
52b7d2ce A |
607 | struct sockaddr *raddr; |
608 | ||
609 | if (safety_check(combuf, 0) != 0) | |
610 | break; | |
611 | if (safety_check(combuf, 1) != 0) | |
612 | break; | |
613 | if (safety_check(combuf, 2) != 0) | |
614 | break; | |
615 | if (safety_check(combuf, 3) != 0) | |
616 | break; | |
d1e348cf A |
617 | if (safety_check(combuf, 4) != 0) |
618 | break; | |
52b7d2ce A |
619 | |
620 | memcpy(&port, bufs[0], sizeof(port)); | |
d1e348cf A |
621 | memcpy(&pool_size, bufs[1], sizeof(pool_size)); |
622 | raddr = (struct sockaddr *)bufs[2]; | |
52b7d2ce | 623 | |
52b7d2ce | 624 | bufs[3][combuf->bufs.buflen[3] - 1] = '\0'; |
d1e348cf A |
625 | bufs[4][combuf->bufs.buflen[4] - 1] = '\0'; |
626 | ||
627 | if (pool_size != isakmp_cfg_config.pool_size) | |
628 | if (isakmp_cfg_resize_pool(pool_size) != 0) | |
629 | break; | |
52b7d2ce A |
630 | |
631 | if (port_check(port) != 0) | |
632 | break; | |
633 | ||
d1e348cf A |
634 | plog(LLV_DEBUG, LOCATION, NULL, |
635 | "xauth_login_pam(%d, %s, \"%s\", <password>)\n", | |
636 | port, saddr2str(raddr), bufs[3]); | |
637 | ||
52b7d2ce A |
638 | errno = 0; |
639 | if (xauth_login_pam(port, | |
d1e348cf | 640 | raddr, bufs[3], bufs[4]) != 0) { |
52b7d2ce A |
641 | if (errno == 0) |
642 | reply->hdr.ac_errno = EINVAL; | |
643 | else | |
644 | reply->hdr.ac_errno = errno; | |
645 | } | |
646 | break; | |
647 | } | |
648 | ||
649 | case PRIVSEP_CLEANUP_PAM: { | |
650 | int port; | |
d1e348cf | 651 | int pool_size; |
52b7d2ce A |
652 | |
653 | if (safety_check(combuf, 0) != 0) | |
654 | break; | |
d1e348cf A |
655 | if (safety_check(combuf, 1) != 0) |
656 | break; | |
52b7d2ce A |
657 | |
658 | memcpy(&port, bufs[0], sizeof(port)); | |
d1e348cf A |
659 | memcpy(&pool_size, bufs[1], sizeof(pool_size)); |
660 | ||
661 | if (pool_size != isakmp_cfg_config.pool_size) | |
662 | if (isakmp_cfg_resize_pool(pool_size) != 0) | |
663 | break; | |
52b7d2ce A |
664 | |
665 | if (port_check(port) != 0) | |
666 | break; | |
667 | ||
d1e348cf A |
668 | plog(LLV_DEBUG, LOCATION, NULL, |
669 | "cleanup_pam(%d)\n", port); | |
670 | ||
52b7d2ce A |
671 | cleanup_pam(port); |
672 | reply->hdr.ac_errno = 0; | |
673 | ||
674 | break; | |
675 | } | |
676 | #endif /* HAVE_LIBPAM */ | |
677 | #endif /* ENABLE_HYBRID */ | |
678 | ||
679 | default: | |
680 | plog(LLV_ERROR, LOCATION, NULL, | |
681 | "unexpected privsep command %d\n", | |
682 | combuf->hdr.ac_cmd); | |
683 | goto out; | |
684 | break; | |
685 | } | |
686 | ||
687 | /* This frees reply */ | |
688 | if (privsep_send(privsep_sock[0], | |
689 | reply, reply->hdr.ac_len) != 0) | |
690 | goto out; | |
691 | ||
692 | racoon_free(combuf); | |
693 | } | |
694 | ||
695 | out: | |
696 | plog(LLV_INFO, LOCATION, NULL, "privsep exit\n"); | |
697 | _exit(0); | |
698 | } | |
699 | ||
700 | ||
701 | vchar_t * | |
702 | privsep_eay_get_pkcs1privkey(path) | |
703 | char *path; | |
704 | { | |
705 | vchar_t *privkey; | |
706 | struct privsep_com_msg *msg; | |
707 | size_t len; | |
708 | ||
709 | if (geteuid() == 0) | |
710 | return eay_get_pkcs1privkey(path); | |
711 | ||
712 | len = sizeof(*msg) + strlen(path) + 1; | |
713 | if ((msg = racoon_malloc(len)) == NULL) { | |
714 | plog(LLV_ERROR, LOCATION, NULL, | |
715 | "Cannot allocate memory: %s\n", strerror(errno)); | |
716 | return NULL; | |
717 | } | |
718 | bzero(msg, len); | |
719 | msg->hdr.ac_cmd = PRIVSEP_EAY_GET_PKCS1PRIVKEY; | |
720 | msg->hdr.ac_len = len; | |
721 | msg->bufs.buflen[0] = len - sizeof(*msg); | |
722 | memcpy(msg + 1, path, msg->bufs.buflen[0]); | |
723 | ||
724 | if (privsep_send(privsep_sock[1], msg, len) != 0) | |
725 | return NULL; | |
726 | ||
727 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
728 | return NULL; | |
729 | ||
730 | if (msg->hdr.ac_errno != 0) { | |
731 | errno = msg->hdr.ac_errno; | |
732 | goto out; | |
733 | } | |
734 | ||
735 | if ((privkey = vmalloc(len - sizeof(*msg))) == NULL) | |
736 | goto out; | |
737 | ||
738 | memcpy(privkey->v, msg + 1, privkey->l); | |
739 | racoon_free(msg); | |
740 | return privkey; | |
741 | ||
742 | out: | |
743 | racoon_free(msg); | |
744 | return NULL; | |
745 | } | |
746 | ||
747 | /* | |
748 | * No prigilege separation trick here, we just open PFKEY before | |
749 | * dropping root privs and we remember it later. | |
750 | */ | |
751 | static int pfkey_socket = -1; | |
752 | int | |
753 | privsep_pfkey_open(void) | |
754 | { | |
755 | int ps; | |
756 | ||
757 | if (pfkey_socket != -1) | |
758 | return pfkey_socket; | |
759 | ||
760 | ps = pfkey_open(); | |
761 | if (ps != -1) | |
762 | pfkey_socket = ps; | |
763 | ||
764 | return ps; | |
765 | } | |
766 | ||
767 | /* | |
768 | * Consequence of the above trickery: don't | |
769 | * really close PFKEY as we never re-open it. | |
770 | */ | |
771 | void | |
772 | privsep_pfkey_close(ps) | |
773 | int ps; | |
774 | { | |
775 | return; | |
776 | } | |
777 | ||
778 | int | |
779 | privsep_script_exec(script, name, envp) | |
d1e348cf | 780 | char *script; |
52b7d2ce A |
781 | int name; |
782 | char *const envp[]; | |
783 | { | |
784 | int count = 0; | |
785 | char *const *c; | |
786 | char *data; | |
787 | size_t len; | |
788 | struct privsep_com_msg *msg; | |
789 | ||
790 | if (geteuid() == 0) | |
791 | return script_exec(script, name, envp); | |
792 | ||
793 | if ((msg = racoon_malloc(sizeof(*msg))) == NULL) { | |
794 | plog(LLV_ERROR, LOCATION, NULL, | |
795 | "Cannot allocate memory: %s\n", strerror(errno)); | |
796 | return -1; | |
797 | } | |
798 | ||
799 | bzero(msg, sizeof(*msg)); | |
800 | msg->hdr.ac_cmd = PRIVSEP_SCRIPT_EXEC; | |
801 | msg->hdr.ac_len = sizeof(*msg); | |
802 | ||
803 | /* | |
804 | * We send: | |
805 | * script, name, envp[0], ... envp[N], void | |
806 | */ | |
807 | ||
808 | /* | |
809 | * Safety check on the counts: PRIVSEP_NBUF_MAX max | |
810 | */ | |
811 | count = 0; | |
812 | count++; /* script */ | |
813 | count++; /* name */ | |
814 | for (c = envp; *c; c++) /* envp */ | |
815 | count++; | |
816 | count++; /* void */ | |
817 | ||
818 | if (count > PRIVSEP_NBUF_MAX) { | |
819 | plog(LLV_ERROR, LOCATION, NULL, "Unexpected error: " | |
820 | "privsep_script_exec count > PRIVSEP_NBUF_MAX\n"); | |
821 | racoon_free(msg); | |
822 | return -1; | |
823 | } | |
824 | ||
825 | ||
826 | /* | |
827 | * Compute the length | |
828 | */ | |
829 | count = 0; | |
d1e348cf | 830 | msg->bufs.buflen[count] = strlen(script) + 1; /* script */ |
52b7d2ce A |
831 | msg->hdr.ac_len += msg->bufs.buflen[count++]; |
832 | ||
833 | msg->bufs.buflen[count] = sizeof(name); /* name */ | |
834 | msg->hdr.ac_len += msg->bufs.buflen[count++]; | |
835 | ||
836 | for (c = envp; *c; c++) { /* envp */ | |
837 | msg->bufs.buflen[count] = strlen(*c) + 1; | |
838 | msg->hdr.ac_len += msg->bufs.buflen[count++]; | |
839 | } | |
840 | ||
841 | msg->bufs.buflen[count] = 0; /* void */ | |
842 | msg->hdr.ac_len += msg->bufs.buflen[count++]; | |
843 | ||
844 | if ((msg = racoon_realloc(msg, msg->hdr.ac_len)) == NULL) { | |
845 | plog(LLV_ERROR, LOCATION, NULL, | |
846 | "Cannot allocate memory: %s\n", strerror(errno)); | |
847 | return -1; | |
848 | } | |
849 | ||
850 | /* | |
851 | * Now copy the data | |
852 | */ | |
853 | data = (char *)(msg + 1); | |
854 | count = 0; | |
855 | ||
d1e348cf | 856 | memcpy(data, (char *)script, msg->bufs.buflen[count]); /* script */ |
52b7d2ce A |
857 | data += msg->bufs.buflen[count++]; |
858 | ||
859 | memcpy(data, (char *)&name, msg->bufs.buflen[count]); /* name */ | |
860 | data += msg->bufs.buflen[count++]; | |
861 | ||
862 | for (c = envp; *c; c++) { /* envp */ | |
863 | memcpy(data, *c, msg->bufs.buflen[count]); | |
864 | data += msg->bufs.buflen[count++]; | |
865 | } | |
866 | ||
867 | count++; /* void */ | |
868 | ||
869 | /* | |
870 | * And send it! | |
871 | */ | |
872 | if (privsep_send(privsep_sock[1], msg, msg->hdr.ac_len) != 0) | |
873 | return -1; | |
874 | ||
875 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
876 | return -1; | |
877 | ||
878 | if (msg->hdr.ac_errno != 0) { | |
879 | errno = msg->hdr.ac_errno; | |
880 | racoon_free(msg); | |
881 | return -1; | |
882 | } | |
883 | ||
884 | racoon_free(msg); | |
885 | return 0; | |
886 | } | |
887 | ||
888 | vchar_t * | |
889 | privsep_getpsk(str, keylen) | |
890 | const char *str; | |
891 | int keylen; | |
892 | { | |
893 | vchar_t *psk; | |
894 | struct privsep_com_msg *msg; | |
895 | size_t len; | |
896 | int *keylenp; | |
897 | char *data; | |
898 | ||
899 | if (geteuid() == 0) | |
900 | return getpsk(str, keylen); | |
901 | ||
902 | len = sizeof(*msg) + strlen(str) + 1 + sizeof(keylen); | |
903 | if ((msg = racoon_malloc(len)) == NULL) { | |
904 | plog(LLV_ERROR, LOCATION, NULL, | |
905 | "Cannot allocate memory: %s\n", strerror(errno)); | |
906 | return NULL; | |
907 | } | |
908 | bzero(msg, len); | |
909 | msg->hdr.ac_cmd = PRIVSEP_GETPSK; | |
910 | msg->hdr.ac_len = len; | |
911 | ||
912 | data = (char *)(msg + 1); | |
913 | msg->bufs.buflen[0] = strlen(str) + 1; | |
914 | memcpy(data, str, msg->bufs.buflen[0]); | |
915 | ||
916 | data += msg->bufs.buflen[0]; | |
917 | msg->bufs.buflen[1] = sizeof(keylen); | |
918 | memcpy(data, &keylen, sizeof(keylen)); | |
919 | ||
920 | if (privsep_send(privsep_sock[1], msg, len) != 0) | |
921 | return NULL; | |
922 | ||
923 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
924 | return NULL; | |
925 | ||
926 | if (msg->hdr.ac_errno != 0) { | |
927 | errno = msg->hdr.ac_errno; | |
928 | goto out; | |
929 | } | |
930 | ||
931 | if ((psk = vmalloc(len - sizeof(*msg))) == NULL) | |
932 | goto out; | |
933 | ||
934 | memcpy(psk->v, msg + 1, psk->l); | |
935 | racoon_free(msg); | |
936 | return psk; | |
937 | ||
938 | out: | |
939 | racoon_free(msg); | |
940 | return NULL; | |
941 | } | |
942 | ||
943 | #ifdef ENABLE_HYBRID | |
944 | int | |
945 | privsep_xauth_login_system(usr, pwd) | |
946 | char *usr; | |
947 | char *pwd; | |
948 | { | |
949 | struct privsep_com_msg *msg; | |
950 | size_t len; | |
951 | char *data; | |
952 | ||
953 | if (geteuid() == 0) | |
954 | return xauth_login_system(usr, pwd); | |
955 | ||
956 | len = sizeof(*msg) + strlen(usr) + 1 + strlen(pwd) + 1; | |
957 | if ((msg = racoon_malloc(len)) == NULL) { | |
958 | plog(LLV_ERROR, LOCATION, NULL, | |
959 | "Cannot allocate memory: %s\n", strerror(errno)); | |
960 | return -1; | |
961 | } | |
962 | bzero(msg, len); | |
963 | msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_SYSTEM; | |
964 | msg->hdr.ac_len = len; | |
965 | ||
966 | data = (char *)(msg + 1); | |
967 | msg->bufs.buflen[0] = strlen(usr) + 1; | |
968 | memcpy(data, usr, msg->bufs.buflen[0]); | |
969 | data += msg->bufs.buflen[0]; | |
970 | ||
971 | msg->bufs.buflen[1] = strlen(pwd) + 1; | |
972 | memcpy(data, pwd, msg->bufs.buflen[1]); | |
973 | ||
974 | if (privsep_send(privsep_sock[1], msg, len) != 0) | |
975 | return -1; | |
976 | ||
977 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
978 | return -1; | |
979 | ||
980 | if (msg->hdr.ac_errno != 0) { | |
981 | racoon_free(msg); | |
982 | return -1; | |
983 | } | |
984 | ||
985 | racoon_free(msg); | |
986 | return 0; | |
987 | } | |
52b7d2ce | 988 | |
d1e348cf A |
989 | int |
990 | privsep_accounting_system(port, raddr, usr, inout) | |
991 | int port; | |
992 | struct sockaddr *raddr; | |
993 | char *usr; | |
994 | int inout; | |
995 | { | |
996 | struct privsep_com_msg *msg; | |
997 | size_t len; | |
998 | char *data; | |
999 | int result; | |
1000 | ||
1001 | if (geteuid() == 0) | |
1002 | return isakmp_cfg_accounting_system(port, raddr, | |
1003 | usr, inout); | |
1004 | ||
1005 | len = sizeof(*msg) | |
1006 | + sizeof(port) | |
1007 | + sysdep_sa_len(raddr) | |
1008 | + strlen(usr) + 1 | |
1009 | + sizeof(inout); | |
1010 | ||
1011 | if ((msg = racoon_malloc(len)) == NULL) { | |
1012 | plog(LLV_ERROR, LOCATION, NULL, | |
1013 | "Cannot allocate memory: %s\n", strerror(errno)); | |
1014 | return -1; | |
1015 | } | |
1016 | bzero(msg, len); | |
1017 | msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_SYSTEM; | |
1018 | msg->hdr.ac_len = len; | |
1019 | msg->bufs.buflen[0] = sizeof(port); | |
1020 | msg->bufs.buflen[1] = sysdep_sa_len(raddr); | |
1021 | msg->bufs.buflen[2] = strlen(usr) + 1; | |
1022 | msg->bufs.buflen[3] = sizeof(inout); | |
1023 | ||
1024 | data = (char *)(msg + 1); | |
1025 | memcpy(data, &port, msg->bufs.buflen[0]); | |
1026 | ||
1027 | data += msg->bufs.buflen[0]; | |
1028 | memcpy(data, raddr, msg->bufs.buflen[1]); | |
1029 | ||
1030 | data += msg->bufs.buflen[1]; | |
1031 | memcpy(data, usr, msg->bufs.buflen[2]); | |
1032 | ||
1033 | data += msg->bufs.buflen[2]; | |
1034 | memcpy(data, &inout, msg->bufs.buflen[3]); | |
1035 | ||
1036 | if (privsep_send(privsep_sock[1], msg, len) != 0) | |
1037 | return -1; | |
1038 | ||
1039 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
1040 | return -1; | |
1041 | ||
1042 | if (msg->hdr.ac_errno != 0) { | |
1043 | errno = msg->hdr.ac_errno; | |
1044 | goto out; | |
1045 | } | |
1046 | ||
1047 | racoon_free(msg); | |
1048 | return 0; | |
1049 | ||
1050 | out: | |
1051 | racoon_free(msg); | |
1052 | return -1; | |
1053 | } | |
1054 | ||
52b7d2ce A |
1055 | static int |
1056 | port_check(port) | |
1057 | int port; | |
1058 | { | |
1059 | if ((port < 0) || (port >= isakmp_cfg_config.pool_size)) { | |
1060 | plog(LLV_ERROR, LOCATION, NULL, | |
1061 | "privsep: port %d outside of allowed range [0,%zu]\n", | |
1062 | port, isakmp_cfg_config.pool_size - 1); | |
1063 | return -1; | |
1064 | } | |
1065 | ||
1066 | return 0; | |
1067 | } | |
1068 | #endif | |
1069 | ||
1070 | static int | |
1071 | safety_check(msg, index) | |
1072 | struct privsep_com_msg *msg; | |
1073 | int index; | |
1074 | { | |
1075 | if (index >= PRIVSEP_NBUF_MAX) { | |
1076 | plog(LLV_ERROR, LOCATION, NULL, | |
1077 | "privsep: Corrupted message, too many buffers\n"); | |
1078 | return -1; | |
1079 | } | |
1080 | ||
1081 | if (msg->bufs.buflen[index] == 0) { | |
1082 | plog(LLV_ERROR, LOCATION, NULL, | |
1083 | "privsep: Corrupted message, unexpected void buffer\n"); | |
1084 | return -1; | |
1085 | } | |
1086 | ||
1087 | return 0; | |
1088 | } | |
1089 | ||
1090 | /* | |
1091 | * Filter unsafe environement variables | |
1092 | */ | |
1093 | static int | |
1094 | unsafe_env(envp) | |
1095 | char *const *envp; | |
1096 | { | |
1097 | char *const *e; | |
1098 | char *const *be; | |
1099 | char *const bad_env[] = { "PATH=", "LD_LIBRARY_PATH=", "IFS=", NULL }; | |
1100 | ||
1101 | for (e = envp; *e; e++) { | |
1102 | for (be = bad_env; *be; be++) { | |
1103 | if (strncmp(*e, *be, strlen(*be)) == 0) { | |
1104 | goto found; | |
1105 | } | |
1106 | } | |
1107 | } | |
1108 | ||
1109 | return 0; | |
1110 | found: | |
1111 | plog(LLV_ERROR, LOCATION, NULL, | |
1112 | "privsep_script_exec: unsafe environement variable\n"); | |
1113 | return -1; | |
1114 | } | |
1115 | ||
d1e348cf A |
1116 | /* |
1117 | * Check path safety | |
1118 | */ | |
1119 | static int | |
52b7d2ce A |
1120 | unsafe_path(script, pathtype) |
1121 | char *script; | |
1122 | int pathtype; | |
1123 | { | |
1124 | char *path; | |
1125 | char rpath[MAXPATHLEN + 1]; | |
1126 | size_t len; | |
1127 | ||
d1e348cf A |
1128 | if (script == NULL) |
1129 | return -1; | |
52b7d2ce A |
1130 | |
1131 | path = lcconf->pathinfo[pathtype]; | |
1132 | ||
1133 | /* No path was given for scripts: skip the check */ | |
1134 | if (path == NULL) | |
1135 | return 0; | |
1136 | ||
1137 | if (realpath(script, rpath) == NULL) { | |
1138 | plog(LLV_ERROR, LOCATION, NULL, | |
1139 | "script path \"%s\" is invalid\n", script); | |
1140 | return -1; | |
1141 | } | |
1142 | ||
1143 | len = strlen(path); | |
1144 | if (strncmp(path, rpath, len) != 0) | |
1145 | return -1; | |
1146 | ||
1147 | return 0; | |
1148 | } | |
1149 | ||
52b7d2ce A |
1150 | static int |
1151 | unknown_name(name) | |
1152 | int name; | |
1153 | { | |
1154 | if ((name < 0) || (name > SCRIPT_MAX)) { | |
1155 | plog(LLV_ERROR, LOCATION, NULL, | |
1156 | "privsep_script_exec: unsafe name index\n"); | |
1157 | return -1; | |
1158 | } | |
1159 | ||
1160 | return 0; | |
1161 | } | |
1162 | ||
1163 | #ifdef HAVE_LIBPAM | |
1164 | int | |
1165 | privsep_accounting_pam(port, inout) | |
1166 | int port; | |
1167 | int inout; | |
1168 | { | |
1169 | struct privsep_com_msg *msg; | |
1170 | size_t len; | |
1171 | int *port_data; | |
1172 | int *inout_data; | |
d1e348cf | 1173 | int *pool_size_data; |
52b7d2ce A |
1174 | int result; |
1175 | ||
1176 | if (geteuid() == 0) | |
1177 | return isakmp_cfg_accounting_pam(port, inout); | |
1178 | ||
d1e348cf A |
1179 | len = sizeof(*msg) |
1180 | + sizeof(port) | |
1181 | + sizeof(inout) | |
1182 | + sizeof(isakmp_cfg_config.pool_size); | |
1183 | ||
52b7d2ce A |
1184 | if ((msg = racoon_malloc(len)) == NULL) { |
1185 | plog(LLV_ERROR, LOCATION, NULL, | |
1186 | "Cannot allocate memory: %s\n", strerror(errno)); | |
1187 | return -1; | |
1188 | } | |
1189 | bzero(msg, len); | |
1190 | msg->hdr.ac_cmd = PRIVSEP_ACCOUNTING_PAM; | |
1191 | msg->hdr.ac_len = len; | |
1192 | msg->bufs.buflen[0] = sizeof(port); | |
1193 | msg->bufs.buflen[1] = sizeof(inout); | |
d1e348cf | 1194 | msg->bufs.buflen[2] = sizeof(isakmp_cfg_config.pool_size); |
52b7d2ce A |
1195 | |
1196 | port_data = (int *)(msg + 1); | |
1197 | inout_data = (int *)(port_data + 1); | |
d1e348cf | 1198 | pool_size_data = (int *)(inout_data + 1); |
52b7d2ce A |
1199 | |
1200 | *port_data = port; | |
1201 | *inout_data = inout; | |
d1e348cf | 1202 | *pool_size_data = isakmp_cfg_config.pool_size; |
52b7d2ce A |
1203 | |
1204 | if (privsep_send(privsep_sock[1], msg, len) != 0) | |
1205 | return -1; | |
1206 | ||
1207 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
1208 | return -1; | |
1209 | ||
1210 | if (msg->hdr.ac_errno != 0) { | |
1211 | errno = msg->hdr.ac_errno; | |
1212 | goto out; | |
1213 | } | |
1214 | ||
1215 | racoon_free(msg); | |
1216 | return 0; | |
1217 | ||
1218 | out: | |
1219 | racoon_free(msg); | |
1220 | return -1; | |
1221 | } | |
1222 | ||
1223 | int | |
1224 | privsep_xauth_login_pam(port, raddr, usr, pwd) | |
1225 | int port; | |
1226 | struct sockaddr *raddr; | |
1227 | char *usr; | |
1228 | char *pwd; | |
1229 | { | |
1230 | struct privsep_com_msg *msg; | |
1231 | size_t len; | |
1232 | char *data; | |
1233 | int result; | |
1234 | ||
1235 | if (geteuid() == 0) | |
1236 | return xauth_login_pam(port, raddr, usr, pwd); | |
1237 | ||
1238 | len = sizeof(*msg) | |
1239 | + sizeof(port) | |
d1e348cf | 1240 | + sizeof(isakmp_cfg_config.pool_size) |
52b7d2ce A |
1241 | + sysdep_sa_len(raddr) |
1242 | + strlen(usr) + 1 | |
1243 | + strlen(pwd) + 1; | |
d1e348cf | 1244 | |
52b7d2ce A |
1245 | if ((msg = racoon_malloc(len)) == NULL) { |
1246 | plog(LLV_ERROR, LOCATION, NULL, | |
1247 | "Cannot allocate memory: %s\n", strerror(errno)); | |
1248 | return -1; | |
1249 | } | |
1250 | bzero(msg, len); | |
1251 | msg->hdr.ac_cmd = PRIVSEP_XAUTH_LOGIN_PAM; | |
1252 | msg->hdr.ac_len = len; | |
1253 | msg->bufs.buflen[0] = sizeof(port); | |
d1e348cf A |
1254 | msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); |
1255 | msg->bufs.buflen[2] = sysdep_sa_len(raddr); | |
1256 | msg->bufs.buflen[3] = strlen(usr) + 1; | |
1257 | msg->bufs.buflen[4] = strlen(pwd) + 1; | |
52b7d2ce A |
1258 | |
1259 | data = (char *)(msg + 1); | |
1260 | memcpy(data, &port, msg->bufs.buflen[0]); | |
1261 | ||
d1e348cf A |
1262 | data += msg->bufs.buflen[0]; |
1263 | memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); | |
52b7d2ce A |
1264 | |
1265 | data += msg->bufs.buflen[1]; | |
d1e348cf | 1266 | memcpy(data, raddr, msg->bufs.buflen[2]); |
52b7d2ce A |
1267 | |
1268 | data += msg->bufs.buflen[2]; | |
d1e348cf A |
1269 | memcpy(data, usr, msg->bufs.buflen[3]); |
1270 | ||
1271 | data += msg->bufs.buflen[3]; | |
1272 | memcpy(data, pwd, msg->bufs.buflen[4]); | |
52b7d2ce A |
1273 | |
1274 | if (privsep_send(privsep_sock[1], msg, len) != 0) | |
1275 | return -1; | |
1276 | ||
1277 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
1278 | return -1; | |
1279 | ||
1280 | if (msg->hdr.ac_errno != 0) { | |
1281 | errno = msg->hdr.ac_errno; | |
1282 | goto out; | |
1283 | } | |
1284 | ||
1285 | racoon_free(msg); | |
1286 | return 0; | |
1287 | ||
1288 | out: | |
1289 | racoon_free(msg); | |
1290 | return -1; | |
1291 | } | |
1292 | ||
1293 | void | |
1294 | privsep_cleanup_pam(port) | |
1295 | int port; | |
1296 | { | |
1297 | struct privsep_com_msg *msg; | |
1298 | size_t len; | |
1299 | char *data; | |
1300 | int result; | |
1301 | ||
1302 | if (geteuid() == 0) | |
1303 | return cleanup_pam(port); | |
1304 | ||
d1e348cf A |
1305 | len = sizeof(*msg) |
1306 | + sizeof(port) | |
1307 | + sizeof(isakmp_cfg_config.pool_size); | |
1308 | ||
52b7d2ce A |
1309 | if ((msg = racoon_malloc(len)) == NULL) { |
1310 | plog(LLV_ERROR, LOCATION, NULL, | |
1311 | "Cannot allocate memory: %s\n", strerror(errno)); | |
1312 | return; | |
1313 | } | |
1314 | bzero(msg, len); | |
1315 | msg->hdr.ac_cmd = PRIVSEP_CLEANUP_PAM; | |
1316 | msg->hdr.ac_len = len; | |
1317 | msg->bufs.buflen[0] = sizeof(port); | |
d1e348cf | 1318 | msg->bufs.buflen[1] = sizeof(isakmp_cfg_config.pool_size); |
52b7d2ce A |
1319 | |
1320 | data = (char *)(msg + 1); | |
1321 | memcpy(data, &port, msg->bufs.buflen[0]); | |
1322 | ||
d1e348cf A |
1323 | data += msg->bufs.buflen[0]; |
1324 | memcpy(data, &isakmp_cfg_config.pool_size, msg->bufs.buflen[1]); | |
1325 | ||
52b7d2ce A |
1326 | if (privsep_send(privsep_sock[1], msg, len) != 0) |
1327 | return; | |
1328 | ||
1329 | if (privsep_recv(privsep_sock[1], &msg, &len) != 0) | |
1330 | return; | |
1331 | ||
1332 | if (msg->hdr.ac_errno != 0) | |
1333 | errno = msg->hdr.ac_errno; | |
1334 | ||
1335 | racoon_free(msg); | |
1336 | return; | |
1337 | } | |
1338 | #endif |