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