1*882428cdSclaudio /* $OpenBSD: radiusd_bsdauth.c,v 1.19 2024/11/21 13:43:10 claudio Exp $ */ 2a7ca44b8Syasuoka 3a7ca44b8Syasuoka /* 4a7ca44b8Syasuoka * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net> 5a7ca44b8Syasuoka * 6a7ca44b8Syasuoka * Permission to use, copy, modify, and distribute this software for any 7a7ca44b8Syasuoka * purpose with or without fee is hereby granted, provided that the above 8a7ca44b8Syasuoka * copyright notice and this permission notice appear in all copies. 9a7ca44b8Syasuoka * 10a7ca44b8Syasuoka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11a7ca44b8Syasuoka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12a7ca44b8Syasuoka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13a7ca44b8Syasuoka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14a7ca44b8Syasuoka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15a7ca44b8Syasuoka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16a7ca44b8Syasuoka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17a7ca44b8Syasuoka */ 18a7ca44b8Syasuoka 19a7ca44b8Syasuoka #include <sys/types.h> 20a7ca44b8Syasuoka #include <sys/queue.h> 213d3cf35cSyasuoka #include <sys/socket.h> 223d3cf35cSyasuoka #include <sys/uio.h> 233d3cf35cSyasuoka #include <sys/wait.h> 24a7ca44b8Syasuoka 25a7ca44b8Syasuoka #include <bsd_auth.h> 26a7ca44b8Syasuoka #include <err.h> 275ae85b70Sclaudio #include <errno.h> 28f1312718Syasuoka #include <fcntl.h> 29a7ca44b8Syasuoka #include <grp.h> 303d3cf35cSyasuoka #include <imsg.h> 31a7ca44b8Syasuoka #include <login_cap.h> 32a7ca44b8Syasuoka #include <pwd.h> 33a7ca44b8Syasuoka #include <stdbool.h> 343d3cf35cSyasuoka #include <stdio.h> 35a7ca44b8Syasuoka #include <stdlib.h> 36a7ca44b8Syasuoka #include <string.h> 37a7ca44b8Syasuoka #include <syslog.h> 38a7ca44b8Syasuoka #include <unistd.h> 39a7ca44b8Syasuoka 40a7ca44b8Syasuoka #include "radiusd.h" 41a7ca44b8Syasuoka #include "radiusd_module.h" 42a7ca44b8Syasuoka 43a7ca44b8Syasuoka struct module_bsdauth { 44a7ca44b8Syasuoka struct module_base *base; 453d3cf35cSyasuoka struct imsgbuf ibuf; 46a7ca44b8Syasuoka char **okgroups; 47a7ca44b8Syasuoka }; 48a7ca44b8Syasuoka 493d3cf35cSyasuoka /* IPC between priv and main */ 503d3cf35cSyasuoka enum { 513d3cf35cSyasuoka IMSG_BSDAUTH_OK = 1000, 523d3cf35cSyasuoka IMSG_BSDAUTH_NG, 533d3cf35cSyasuoka IMSG_BSDAUTH_USERCHECK, 543d3cf35cSyasuoka IMSG_BSDAUTH_GROUPCHECK 553d3cf35cSyasuoka }; 563d3cf35cSyasuoka struct auth_usercheck_args { 573d3cf35cSyasuoka size_t userlen; 583d3cf35cSyasuoka size_t passlen; 593d3cf35cSyasuoka }; 603d3cf35cSyasuoka struct auth_groupcheck_args { 613d3cf35cSyasuoka size_t userlen; 623d3cf35cSyasuoka size_t grouplen; 633d3cf35cSyasuoka }; 643d3cf35cSyasuoka 65f1312718Syasuoka __dead static void 66f1312718Syasuoka module_bsdauth_main(void); 67a7ca44b8Syasuoka static void module_bsdauth_config_set(void *, const char *, int, 68a7ca44b8Syasuoka char * const *); 693d3cf35cSyasuoka static void module_bsdauth_userpass(void *, u_int, const char *, 703d3cf35cSyasuoka const char *); 71f1312718Syasuoka static pid_t start_child(char *, int); 723d3cf35cSyasuoka __dead static void 733d3cf35cSyasuoka fatal(const char *); 74a7ca44b8Syasuoka 75a7ca44b8Syasuoka static struct module_handlers module_bsdauth_handlers = { 76a7ca44b8Syasuoka .userpass = module_bsdauth_userpass, 77a7ca44b8Syasuoka .config_set = module_bsdauth_config_set 78a7ca44b8Syasuoka }; 79a7ca44b8Syasuoka 80a7ca44b8Syasuoka int 81a7ca44b8Syasuoka main(int argc, char *argv[]) 82a7ca44b8Syasuoka { 83f1312718Syasuoka int ch, pairsock[2], status; 843d3cf35cSyasuoka struct imsgbuf ibuf; 853d3cf35cSyasuoka struct imsg imsg; 863d3cf35cSyasuoka ssize_t n; 873d3cf35cSyasuoka size_t datalen; 882aeb6b04Sderaadt pid_t pid; 89f1312718Syasuoka char *saved_argv0; 903d3cf35cSyasuoka 91f1312718Syasuoka while ((ch = getopt(argc, argv, "M")) != -1) 92f1312718Syasuoka switch (ch) { 93f1312718Syasuoka case 'M': 94f1312718Syasuoka module_bsdauth_main(); 957a016c8eSyasuoka /* never return, not rearched here */ 96f1312718Syasuoka break; 97f1312718Syasuoka default: 98f1312718Syasuoka break; 99f1312718Syasuoka } 100f1312718Syasuoka saved_argv0 = argv[0]; 101f1312718Syasuoka argc -= optind; 102f1312718Syasuoka argv += optind; 103f1312718Syasuoka 1047a016c8eSyasuoka if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC, 1057a016c8eSyasuoka pairsock) == -1) 1063d3cf35cSyasuoka err(EXIT_FAILURE, "socketpair"); 1073d3cf35cSyasuoka 108f1312718Syasuoka openlog(NULL, LOG_PID, LOG_DAEMON); 109f1312718Syasuoka 110f1312718Syasuoka pid = start_child(saved_argv0, pairsock[1]); 1113d3cf35cSyasuoka 1123d3cf35cSyasuoka /* 113be657a2dSyasuoka * Privileged process 1143d3cf35cSyasuoka */ 1153d3cf35cSyasuoka setproctitle("[priv]"); 116*882428cdSclaudio if (imsgbuf_init(&ibuf, pairsock[0]) == 1) 117*882428cdSclaudio err(EXIT_FAILURE, "imsgbuf_init"); 11804581dc7Syasuoka 11904581dc7Syasuoka if (pledge("stdio getpw rpath proc exec", NULL) == -1) 12004581dc7Syasuoka err(EXIT_FAILURE, "pledge"); 12104581dc7Syasuoka 1223d3cf35cSyasuoka for (;;) { 1234f3fb1ffSclaudio if (imsgbuf_read(&ibuf) != 1) 1243d3cf35cSyasuoka break; 1253d3cf35cSyasuoka for (;;) { 1263d3cf35cSyasuoka if ((n = imsg_get(&ibuf, &imsg)) == -1) 1273d3cf35cSyasuoka break; 1283d3cf35cSyasuoka if (n == 0) 1293d3cf35cSyasuoka break; 1303d3cf35cSyasuoka datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 1313d3cf35cSyasuoka switch (imsg.hdr.type) { 1323d3cf35cSyasuoka case IMSG_BSDAUTH_USERCHECK: 1333d3cf35cSyasuoka { 1343d3cf35cSyasuoka char *user, *pass; 1353d3cf35cSyasuoka bool authok = false; 1363d3cf35cSyasuoka struct auth_usercheck_args 1373d3cf35cSyasuoka *args; 1383d3cf35cSyasuoka 1393d3cf35cSyasuoka if (datalen < sizeof( 1403d3cf35cSyasuoka struct auth_usercheck_args)) { 1413d3cf35cSyasuoka syslog(LOG_ERR, "Short message"); 1423d3cf35cSyasuoka break; 1433d3cf35cSyasuoka } 1443d3cf35cSyasuoka args = (struct auth_usercheck_args *)imsg.data; 1453d3cf35cSyasuoka 1463d3cf35cSyasuoka if (datalen < sizeof(struct auth_usercheck_args) 1473d3cf35cSyasuoka + args->userlen + args->passlen) { 1483d3cf35cSyasuoka syslog(LOG_ERR, "Short message"); 1493d3cf35cSyasuoka break; 1503d3cf35cSyasuoka } 1513d3cf35cSyasuoka user = (char *)(args + 1); 1523d3cf35cSyasuoka user[args->userlen - 1] = '\0'; 1533d3cf35cSyasuoka pass = user + args->userlen; 1543d3cf35cSyasuoka pass[args->passlen - 1] = '\0'; 1553d3cf35cSyasuoka 1563d3cf35cSyasuoka if (auth_userokay(user, NULL, NULL, pass)) 1573d3cf35cSyasuoka authok = true; 1583d3cf35cSyasuoka explicit_bzero(pass, args->passlen); 1593d3cf35cSyasuoka 1603d3cf35cSyasuoka imsg_compose(&ibuf, (authok) 1613d3cf35cSyasuoka ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG, 1623d3cf35cSyasuoka 0, 0, -1, NULL, 0); 1633d3cf35cSyasuoka break; 1643d3cf35cSyasuoka } 1653d3cf35cSyasuoka case IMSG_BSDAUTH_GROUPCHECK: 1663d3cf35cSyasuoka { 1673d3cf35cSyasuoka int i; 1683d3cf35cSyasuoka char *user, *group; 1693d3cf35cSyasuoka struct passwd *pw; 1703d3cf35cSyasuoka struct group gr0, *gr; 1713d3cf35cSyasuoka char g_buf[4096]; 1723d3cf35cSyasuoka bool group_ok = false; 1733d3cf35cSyasuoka struct auth_groupcheck_args 1743d3cf35cSyasuoka *args; 1753d3cf35cSyasuoka 1763d3cf35cSyasuoka if (datalen < sizeof( 1773d3cf35cSyasuoka struct auth_groupcheck_args)) { 1783d3cf35cSyasuoka syslog(LOG_ERR, "Short message"); 1793d3cf35cSyasuoka break; 1803d3cf35cSyasuoka } 1813d3cf35cSyasuoka args = (struct auth_groupcheck_args *)imsg.data; 1827a016c8eSyasuoka if (datalen < 1837a016c8eSyasuoka sizeof(struct auth_groupcheck_args) + 1843d3cf35cSyasuoka args->userlen + args->grouplen) { 1853d3cf35cSyasuoka syslog(LOG_ERR, "Short message"); 1863d3cf35cSyasuoka break; 1873d3cf35cSyasuoka } 1883d3cf35cSyasuoka user = (char *)(args + 1); 1893d3cf35cSyasuoka user[args->userlen - 1] = '\0'; 1903d3cf35cSyasuoka group = user + args->userlen; 1913d3cf35cSyasuoka group[args->grouplen - 1] = '\0'; 1923d3cf35cSyasuoka 1930914537fSmillert user[strcspn(user, ":")] = '\0'; 1943d3cf35cSyasuoka pw = getpwnam(user); 195502b49aaSderaadt if (pw == NULL) 196502b49aaSderaadt goto invalid; 1973d3cf35cSyasuoka if (getgrnam_r(group, &gr0, g_buf, 198f6b02885Syasuoka sizeof(g_buf), &gr) == -1 || gr == NULL) 199502b49aaSderaadt goto invalid; 2003d3cf35cSyasuoka 2013d3cf35cSyasuoka if (gr->gr_gid == pw->pw_gid) { 2023d3cf35cSyasuoka group_ok = true; 203502b49aaSderaadt goto invalid; 2043d3cf35cSyasuoka } 2053d3cf35cSyasuoka for (i = 0; gr->gr_mem[i] != NULL; i++) { 2063d3cf35cSyasuoka if (strcmp(gr->gr_mem[i], pw->pw_name) 2073d3cf35cSyasuoka == 0) { 2083d3cf35cSyasuoka group_ok = true; 209502b49aaSderaadt goto invalid; 2103d3cf35cSyasuoka } 2113d3cf35cSyasuoka } 212502b49aaSderaadt invalid: 2133d3cf35cSyasuoka endgrent(); 2143d3cf35cSyasuoka 2153d3cf35cSyasuoka imsg_compose(&ibuf, (group_ok) 2163d3cf35cSyasuoka ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG, 2173d3cf35cSyasuoka 0, 0, -1, NULL, 0); 2183d3cf35cSyasuoka break; 2193d3cf35cSyasuoka } 2203d3cf35cSyasuoka } 2216da13141Syasuoka imsg_free(&imsg); 222dd7efffeSclaudio imsgbuf_flush(&ibuf); 2233d3cf35cSyasuoka } 224dd7efffeSclaudio imsgbuf_flush(&ibuf); 2253d3cf35cSyasuoka } 226dd7efffeSclaudio imsgbuf_clear(&ibuf); 2273d3cf35cSyasuoka 2282aeb6b04Sderaadt while (waitpid(pid, &status, 0) == -1) { 2292aeb6b04Sderaadt if (errno != EINTR) 2302aeb6b04Sderaadt break; 2312aeb6b04Sderaadt } 2323d3cf35cSyasuoka exit(WEXITSTATUS(status)); 2333d3cf35cSyasuoka } 2343d3cf35cSyasuoka 235f1312718Syasuoka static void 236f1312718Syasuoka module_bsdauth_main(void) 2373d3cf35cSyasuoka { 2383d3cf35cSyasuoka int i; 239a7ca44b8Syasuoka struct module_bsdauth module_bsdauth; 240a7ca44b8Syasuoka 241f1312718Syasuoka /* 242f1312718Syasuoka * main process 243f1312718Syasuoka */ 2443d3cf35cSyasuoka setproctitle("[main]"); 245a7ca44b8Syasuoka openlog(NULL, LOG_PID, LOG_DAEMON); 2463d3cf35cSyasuoka memset(&module_bsdauth, 0, sizeof(module_bsdauth)); 247a7ca44b8Syasuoka if ((module_bsdauth.base = module_create(STDIN_FILENO, &module_bsdauth, 248a7ca44b8Syasuoka &module_bsdauth_handlers)) == NULL) 249a7ca44b8Syasuoka err(1, "Could not create a module instance"); 250a7ca44b8Syasuoka 251edd79a0eSyasuoka module_drop_privilege(module_bsdauth.base, 0); 2523d3cf35cSyasuoka 253a7ca44b8Syasuoka module_load(module_bsdauth.base); 254*882428cdSclaudio if (imsgbuf_init(&module_bsdauth.ibuf, 3) == -1) 255*882428cdSclaudio err(EXIT_FAILURE, "imsgbuf_init"); 25604581dc7Syasuoka 25704581dc7Syasuoka if (pledge("stdio proc", NULL) == -1) 25804581dc7Syasuoka err(EXIT_FAILURE, "pledge"); 25904581dc7Syasuoka 260a7ca44b8Syasuoka while (module_run(module_bsdauth.base) == 0) 261a7ca44b8Syasuoka ; 262a7ca44b8Syasuoka 263a7ca44b8Syasuoka module_destroy(module_bsdauth.base); 264dd7efffeSclaudio imsgbuf_clear(&module_bsdauth.ibuf); 265a7ca44b8Syasuoka 2663d3cf35cSyasuoka if (module_bsdauth.okgroups) { 2673d3cf35cSyasuoka for (i = 0; module_bsdauth.okgroups[i] != NULL; i++) 2683d3cf35cSyasuoka free(module_bsdauth.okgroups[i]); 2693d3cf35cSyasuoka } 2703d3cf35cSyasuoka free(module_bsdauth.okgroups); 2713d3cf35cSyasuoka 272f1312718Syasuoka exit(EXIT_SUCCESS); 273a7ca44b8Syasuoka } 274a7ca44b8Syasuoka 275a7ca44b8Syasuoka static void 276a7ca44b8Syasuoka module_bsdauth_config_set(void *ctx, const char *name, int argc, 277a7ca44b8Syasuoka char * const * argv) 278a7ca44b8Syasuoka { 27958e9bc95Syasuoka struct module_bsdauth *module = ctx; 280a7ca44b8Syasuoka int i; 281a7ca44b8Syasuoka char **groups = NULL; 282a7ca44b8Syasuoka 283a7ca44b8Syasuoka if (strcmp(name, "restrict-group") == 0) { 28458e9bc95Syasuoka if (module->okgroups != NULL) { 28558e9bc95Syasuoka module_send_message(module->base, IMSG_NG, 286a7ca44b8Syasuoka "`restrict-group' is already defined"); 287a7ca44b8Syasuoka goto on_error; 288a7ca44b8Syasuoka } 289a7ca44b8Syasuoka if ((groups = calloc(sizeof(char *), argc + 1)) == NULL) { 29058e9bc95Syasuoka module_send_message(module->base, IMSG_NG, 291a7ca44b8Syasuoka "Out of memory"); 292a7ca44b8Syasuoka goto on_error; 293a7ca44b8Syasuoka } 294a7ca44b8Syasuoka for (i = 0; i < argc; i++) { 295a7ca44b8Syasuoka if ((groups[i] = strdup(argv[i])) == NULL) { 29658e9bc95Syasuoka module_send_message(module->base, 297a7ca44b8Syasuoka IMSG_NG, "Out of memory"); 298a7ca44b8Syasuoka goto on_error; 299a7ca44b8Syasuoka } 300a7ca44b8Syasuoka } 301a7ca44b8Syasuoka groups[i] = NULL; 30258e9bc95Syasuoka module->okgroups = groups; 30358e9bc95Syasuoka module_send_message(module->base, IMSG_OK, NULL); 30416971584Syasuoka } else if (strncmp(name, "_", 1) == 0) 30516971584Syasuoka /* ignore all internal messages */ 30616971584Syasuoka module_send_message(module->base, IMSG_OK, NULL); 30716971584Syasuoka else 30858e9bc95Syasuoka module_send_message(module->base, IMSG_NG, 309a7ca44b8Syasuoka "Unknown config parameter `%s'", name); 310a7ca44b8Syasuoka return; 311a7ca44b8Syasuoka on_error: 312a7ca44b8Syasuoka if (groups != NULL) { 313a7ca44b8Syasuoka for (i = 0; groups[i] != NULL; i++) 314a7ca44b8Syasuoka free(groups[i]); 315a7ca44b8Syasuoka free(groups); 316a7ca44b8Syasuoka } 317a7ca44b8Syasuoka return; 318a7ca44b8Syasuoka } 319a7ca44b8Syasuoka 320a7ca44b8Syasuoka 321a7ca44b8Syasuoka static void 322a7ca44b8Syasuoka module_bsdauth_userpass(void *ctx, u_int q_id, const char *user, 323a7ca44b8Syasuoka const char *pass) 324a7ca44b8Syasuoka { 32558e9bc95Syasuoka struct module_bsdauth *module = ctx; 3263d3cf35cSyasuoka struct auth_usercheck_args 3273d3cf35cSyasuoka usercheck; 3283d3cf35cSyasuoka struct auth_groupcheck_args 3293d3cf35cSyasuoka groupcheck; 3303d3cf35cSyasuoka struct iovec iov[4]; 3313d3cf35cSyasuoka const char *group; 3323d3cf35cSyasuoka u_int i; 333a7ca44b8Syasuoka const char *reason; 3343d3cf35cSyasuoka struct imsg imsg; 3353d3cf35cSyasuoka ssize_t n; 336a7ca44b8Syasuoka 3373d3cf35cSyasuoka memset(&imsg, 0, sizeof(imsg)); 338a7ca44b8Syasuoka if (pass == NULL) 339a7ca44b8Syasuoka pass = ""; 340a7ca44b8Syasuoka 3413d3cf35cSyasuoka usercheck.userlen = strlen(user) + 1; 3423d3cf35cSyasuoka usercheck.passlen = strlen(pass) + 1; 3433d3cf35cSyasuoka iov[0].iov_base = &usercheck; 3443d3cf35cSyasuoka iov[0].iov_len = sizeof(usercheck); 3453d3cf35cSyasuoka iov[1].iov_base = (char *)user; 3463d3cf35cSyasuoka iov[1].iov_len = usercheck.userlen; 3473d3cf35cSyasuoka iov[2].iov_base = (char *)pass; 3483d3cf35cSyasuoka iov[2].iov_len = usercheck.passlen; 3493d3cf35cSyasuoka 35058e9bc95Syasuoka imsg_composev(&module->ibuf, IMSG_BSDAUTH_USERCHECK, 0, 0, -1, iov, 3); 351dd7efffeSclaudio imsgbuf_flush(&module->ibuf); 3524f3fb1ffSclaudio if (imsgbuf_read(&module->ibuf) != 1) 353dd7efffeSclaudio fatal("imsgbuf_read() failed in module_bsdauth_userpass()"); 35458e9bc95Syasuoka if ((n = imsg_get(&module->ibuf, &imsg)) <= 0) 3553d3cf35cSyasuoka fatal("imsg_get() failed in module_bsdauth_userpass()"); 3563d3cf35cSyasuoka 3573d3cf35cSyasuoka if (imsg.hdr.type != IMSG_BSDAUTH_OK) { 358a7ca44b8Syasuoka reason = "Authentication failed"; 359a7ca44b8Syasuoka goto auth_ng; 360a7ca44b8Syasuoka } 36158e9bc95Syasuoka if (module->okgroups != NULL) { 362a7ca44b8Syasuoka reason = "Group restriction is not allowed"; 36358e9bc95Syasuoka for (i = 0; module->okgroups[i] != NULL; i++) { 36458e9bc95Syasuoka group = module->okgroups[i]; 3653d3cf35cSyasuoka 3663d3cf35cSyasuoka groupcheck.userlen = strlen(user) + 1; 3673d3cf35cSyasuoka groupcheck.grouplen = strlen(group) + 1; 3683d3cf35cSyasuoka iov[0].iov_base = &groupcheck; 3693d3cf35cSyasuoka iov[0].iov_len = sizeof(groupcheck); 3703d3cf35cSyasuoka iov[1].iov_base = (char *)user; 3713d3cf35cSyasuoka iov[1].iov_len = groupcheck.userlen; 3723d3cf35cSyasuoka iov[2].iov_base = (char *)group; 3733d3cf35cSyasuoka iov[2].iov_len = groupcheck.grouplen; 37458e9bc95Syasuoka imsg_composev(&module->ibuf, IMSG_BSDAUTH_GROUPCHECK, 3753d3cf35cSyasuoka 0, 0, -1, iov, 3); 376dd7efffeSclaudio imsgbuf_flush(&module->ibuf); 3774f3fb1ffSclaudio if (imsgbuf_read(&module->ibuf) != 1) 378dd7efffeSclaudio fatal("imsgbuf_read() failed in " 3793d3cf35cSyasuoka "module_bsdauth_userpass()"); 38058e9bc95Syasuoka if ((n = imsg_get(&module->ibuf, &imsg)) <= 0) 3813d3cf35cSyasuoka fatal("imsg_get() failed in " 3823d3cf35cSyasuoka "module_bsdauth_userpass()"); 3833d3cf35cSyasuoka if (imsg.hdr.type == IMSG_BSDAUTH_OK) 384a7ca44b8Syasuoka goto group_ok; 385a7ca44b8Syasuoka } 386a7ca44b8Syasuoka goto auth_ng; 387a7ca44b8Syasuoka } 3883d3cf35cSyasuoka group_ok: 38958e9bc95Syasuoka module_userpass_ok(module->base, q_id, "Authentication succeeded"); 3903d3cf35cSyasuoka imsg_free(&imsg); 391a7ca44b8Syasuoka return; 392a7ca44b8Syasuoka auth_ng: 39358e9bc95Syasuoka module_userpass_fail(module->base, q_id, reason); 3943d3cf35cSyasuoka imsg_free(&imsg); 395a7ca44b8Syasuoka return; 396a7ca44b8Syasuoka } 3973d3cf35cSyasuoka 398f1312718Syasuoka pid_t 399f1312718Syasuoka start_child(char *argv0, int fd) 400f1312718Syasuoka { 401f1312718Syasuoka char *argv[5]; 402f1312718Syasuoka int argc = 0; 403f1312718Syasuoka pid_t pid; 404f1312718Syasuoka 405f1312718Syasuoka switch (pid = fork()) { 406f1312718Syasuoka case -1: 407f1312718Syasuoka fatal("cannot fork"); 408f1312718Syasuoka case 0: 409f1312718Syasuoka break; 410f1312718Syasuoka default: 411f1312718Syasuoka close(fd); 412f1312718Syasuoka return (pid); 413f1312718Syasuoka } 414f1312718Syasuoka 415f1312718Syasuoka if (fd != 3) { 416f1312718Syasuoka if (dup2(fd, 3) == -1) 417f1312718Syasuoka fatal("cannot setup imsg fd"); 418f1312718Syasuoka } else if (fcntl(fd, F_SETFD, 0) == -1) 419f1312718Syasuoka fatal("cannot setup imsg fd"); 420f1312718Syasuoka 421f1312718Syasuoka argv[argc++] = argv0; 422f1312718Syasuoka argv[argc++] = "-M"; /* main proc */ 42375c5cf40Syasuoka argv[argc++] = NULL; 424f1312718Syasuoka execvp(argv0, argv); 425f1312718Syasuoka fatal("execvp"); 426f1312718Syasuoka } 427f1312718Syasuoka 4283d3cf35cSyasuoka static void 4293d3cf35cSyasuoka fatal(const char *msg) 4303d3cf35cSyasuoka { 4313d3cf35cSyasuoka syslog(LOG_ERR, "%s: %m", msg); 4323d3cf35cSyasuoka abort(); 4333d3cf35cSyasuoka } 434