PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/external/ipsec-tools/src/racoon/privsep.c

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