19e7c127fSCraig Rodrigues /* $OpenBSD: ypldap.c,v 1.16 2015/11/02 10:06:06 jmatthew Exp $ */ 29e7c127fSCraig Rodrigues /* $FreeBSD */ 39e7c127fSCraig Rodrigues 49e7c127fSCraig Rodrigues /* 59e7c127fSCraig Rodrigues * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 69e7c127fSCraig Rodrigues * 79e7c127fSCraig Rodrigues * Permission to use, copy, modify, and distribute this software for any 89e7c127fSCraig Rodrigues * purpose with or without fee is hereby granted, provided that the above 99e7c127fSCraig Rodrigues * copyright notice and this permission notice appear in all copies. 109e7c127fSCraig Rodrigues * 119e7c127fSCraig Rodrigues * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 129e7c127fSCraig Rodrigues * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 139e7c127fSCraig Rodrigues * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 149e7c127fSCraig Rodrigues * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 159e7c127fSCraig Rodrigues * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 169e7c127fSCraig Rodrigues * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 179e7c127fSCraig Rodrigues * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 189e7c127fSCraig Rodrigues */ 199e7c127fSCraig Rodrigues 209e7c127fSCraig Rodrigues #include <sys/types.h> 2166b5c05dSCraig Rodrigues #include <sys/param.h> 229e7c127fSCraig Rodrigues #include <sys/queue.h> 239e7c127fSCraig Rodrigues #include <sys/socket.h> 249e7c127fSCraig Rodrigues #include <sys/signal.h> 259e7c127fSCraig Rodrigues #include <sys/tree.h> 269e7c127fSCraig Rodrigues #include <sys/wait.h> 279e7c127fSCraig Rodrigues 289e7c127fSCraig Rodrigues #include <netinet/in.h> 299e7c127fSCraig Rodrigues #include <arpa/inet.h> 309e7c127fSCraig Rodrigues 319e7c127fSCraig Rodrigues #include <err.h> 329e7c127fSCraig Rodrigues #include <errno.h> 339e7c127fSCraig Rodrigues #include <event.h> 349e7c127fSCraig Rodrigues #include <unistd.h> 359e7c127fSCraig Rodrigues #include <pwd.h> 369e7c127fSCraig Rodrigues #include <stdio.h> 379e7c127fSCraig Rodrigues #include <stdlib.h> 389e7c127fSCraig Rodrigues #include <string.h> 399e7c127fSCraig Rodrigues #include <limits.h> 409e7c127fSCraig Rodrigues 419e7c127fSCraig Rodrigues #include "ypldap.h" 429e7c127fSCraig Rodrigues 43*350ed599SCraig Rodrigues __dead2 void usage(void); 449e7c127fSCraig Rodrigues int check_child(pid_t, const char *); 459e7c127fSCraig Rodrigues void main_sig_handler(int, short, void *); 469e7c127fSCraig Rodrigues void main_shutdown(void); 479e7c127fSCraig Rodrigues void main_dispatch_client(int, short, void *); 489e7c127fSCraig Rodrigues void main_configure_client(struct env *); 499e7c127fSCraig Rodrigues void main_init_timer(int, short, void *); 509e7c127fSCraig Rodrigues void main_start_update(struct env *); 519e7c127fSCraig Rodrigues void main_trash_update(struct env *); 529e7c127fSCraig Rodrigues void main_end_update(struct env *); 539e7c127fSCraig Rodrigues int main_create_user_groups(struct env *); 549e7c127fSCraig Rodrigues void purge_config(struct env *); 559e7c127fSCraig Rodrigues void reconfigure(struct env *); 569e7c127fSCraig Rodrigues 579e7c127fSCraig Rodrigues int pipe_main2client[2]; 589e7c127fSCraig Rodrigues 599e7c127fSCraig Rodrigues pid_t client_pid = 0; 609e7c127fSCraig Rodrigues char *conffile = YPLDAP_CONF_FILE; 619e7c127fSCraig Rodrigues int opts = 0; 629e7c127fSCraig Rodrigues 639e7c127fSCraig Rodrigues void 649e7c127fSCraig Rodrigues usage(void) 659e7c127fSCraig Rodrigues { 669e7c127fSCraig Rodrigues extern const char *__progname; 679e7c127fSCraig Rodrigues 689e7c127fSCraig Rodrigues fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 699e7c127fSCraig Rodrigues __progname); 709e7c127fSCraig Rodrigues exit(1); 719e7c127fSCraig Rodrigues } 729e7c127fSCraig Rodrigues 739e7c127fSCraig Rodrigues int 749e7c127fSCraig Rodrigues check_child(pid_t pid, const char *pname) 759e7c127fSCraig Rodrigues { 769e7c127fSCraig Rodrigues int status; 779e7c127fSCraig Rodrigues 789e7c127fSCraig Rodrigues if (waitpid(pid, &status, WNOHANG) > 0) { 799e7c127fSCraig Rodrigues if (WIFEXITED(status)) { 809e7c127fSCraig Rodrigues log_warnx("check_child: lost child %s exited", pname); 819e7c127fSCraig Rodrigues return (1); 829e7c127fSCraig Rodrigues } 839e7c127fSCraig Rodrigues if (WIFSIGNALED(status)) { 849e7c127fSCraig Rodrigues log_warnx("check_child: lost child %s terminated; " 859e7c127fSCraig Rodrigues "signal %d", pname, WTERMSIG(status)); 869e7c127fSCraig Rodrigues return (1); 879e7c127fSCraig Rodrigues } 889e7c127fSCraig Rodrigues } 899e7c127fSCraig Rodrigues return (0); 909e7c127fSCraig Rodrigues } 919e7c127fSCraig Rodrigues 929e7c127fSCraig Rodrigues /* ARGUSED */ 939e7c127fSCraig Rodrigues void 949e7c127fSCraig Rodrigues main_sig_handler(int sig, short event, void *p) 959e7c127fSCraig Rodrigues { 969e7c127fSCraig Rodrigues int die = 0; 979e7c127fSCraig Rodrigues 989e7c127fSCraig Rodrigues switch (sig) { 999e7c127fSCraig Rodrigues case SIGTERM: 1009e7c127fSCraig Rodrigues case SIGINT: 1019e7c127fSCraig Rodrigues die = 1; 1029e7c127fSCraig Rodrigues /* FALLTHROUGH */ 1039e7c127fSCraig Rodrigues case SIGCHLD: 1049e7c127fSCraig Rodrigues if (check_child(client_pid, "ldap client")) { 1059e7c127fSCraig Rodrigues client_pid = 0; 1069e7c127fSCraig Rodrigues die = 1; 1079e7c127fSCraig Rodrigues } 1089e7c127fSCraig Rodrigues if (die) 1099e7c127fSCraig Rodrigues main_shutdown(); 1109e7c127fSCraig Rodrigues break; 1119e7c127fSCraig Rodrigues case SIGHUP: 1129e7c127fSCraig Rodrigues /* reconfigure */ 1139e7c127fSCraig Rodrigues break; 1149e7c127fSCraig Rodrigues default: 1159e7c127fSCraig Rodrigues fatalx("unexpected signal"); 1169e7c127fSCraig Rodrigues } 1179e7c127fSCraig Rodrigues } 1189e7c127fSCraig Rodrigues 1199e7c127fSCraig Rodrigues void 1209e7c127fSCraig Rodrigues main_shutdown(void) 1219e7c127fSCraig Rodrigues { 1229e7c127fSCraig Rodrigues _exit(0); 1239e7c127fSCraig Rodrigues } 1249e7c127fSCraig Rodrigues 1259e7c127fSCraig Rodrigues void 1269e7c127fSCraig Rodrigues main_start_update(struct env *env) 1279e7c127fSCraig Rodrigues { 1289e7c127fSCraig Rodrigues env->update_trashed = 0; 1299e7c127fSCraig Rodrigues 1309e7c127fSCraig Rodrigues log_debug("starting directory update"); 1319e7c127fSCraig Rodrigues env->sc_user_line_len = 0; 1329e7c127fSCraig Rodrigues env->sc_group_line_len = 0; 1339e7c127fSCraig Rodrigues if ((env->sc_user_names_t = calloc(1, 1349e7c127fSCraig Rodrigues sizeof(*env->sc_user_names_t))) == NULL || 1359e7c127fSCraig Rodrigues (env->sc_group_names_t = calloc(1, 1369e7c127fSCraig Rodrigues sizeof(*env->sc_group_names_t))) == NULL) 1379e7c127fSCraig Rodrigues fatal(NULL); 1389e7c127fSCraig Rodrigues RB_INIT(env->sc_user_names_t); 1399e7c127fSCraig Rodrigues RB_INIT(env->sc_group_names_t); 1409e7c127fSCraig Rodrigues } 1419e7c127fSCraig Rodrigues 1429e7c127fSCraig Rodrigues /* 1439e7c127fSCraig Rodrigues * XXX: Currently this function should only be called when updating is 1449e7c127fSCraig Rodrigues * finished. A notification should be send to ldapclient that it should stop 1459e7c127fSCraig Rodrigues * sending new pwd/grp entries before it can be called from different places. 1469e7c127fSCraig Rodrigues */ 1479e7c127fSCraig Rodrigues void 1489e7c127fSCraig Rodrigues main_trash_update(struct env *env) 1499e7c127fSCraig Rodrigues { 1509e7c127fSCraig Rodrigues struct userent *ue; 1519e7c127fSCraig Rodrigues struct groupent *ge; 1529e7c127fSCraig Rodrigues 1539e7c127fSCraig Rodrigues env->update_trashed = 1; 1549e7c127fSCraig Rodrigues 1559e7c127fSCraig Rodrigues while ((ue = RB_ROOT(env->sc_user_names_t)) != NULL) { 1569e7c127fSCraig Rodrigues RB_REMOVE(user_name_tree, 1579e7c127fSCraig Rodrigues env->sc_user_names_t, ue); 1589e7c127fSCraig Rodrigues free(ue->ue_line); 1599e7c127fSCraig Rodrigues free(ue->ue_netid_line); 1609e7c127fSCraig Rodrigues free(ue); 1619e7c127fSCraig Rodrigues } 1629e7c127fSCraig Rodrigues free(env->sc_user_names_t); 1639e7c127fSCraig Rodrigues env->sc_user_names_t = NULL; 1649e7c127fSCraig Rodrigues while ((ge = RB_ROOT(env->sc_group_names_t)) 1659e7c127fSCraig Rodrigues != NULL) { 1669e7c127fSCraig Rodrigues RB_REMOVE(group_name_tree, 1679e7c127fSCraig Rodrigues env->sc_group_names_t, ge); 1689e7c127fSCraig Rodrigues free(ge->ge_line); 1699e7c127fSCraig Rodrigues free(ge); 1709e7c127fSCraig Rodrigues } 1719e7c127fSCraig Rodrigues free(env->sc_group_names_t); 1729e7c127fSCraig Rodrigues env->sc_group_names_t = NULL; 1739e7c127fSCraig Rodrigues } 1749e7c127fSCraig Rodrigues 1759e7c127fSCraig Rodrigues int 1769e7c127fSCraig Rodrigues main_create_user_groups(struct env *env) 1779e7c127fSCraig Rodrigues { 1789e7c127fSCraig Rodrigues struct userent *ue; 1799e7c127fSCraig Rodrigues struct userent ukey; 1809e7c127fSCraig Rodrigues struct groupent *ge; 1819e7c127fSCraig Rodrigues gid_t pw_gid; 1829e7c127fSCraig Rodrigues char *bp, *cp; 1839e7c127fSCraig Rodrigues char *p; 1849e7c127fSCraig Rodrigues const char *errstr = NULL; 1859e7c127fSCraig Rodrigues size_t len; 1869e7c127fSCraig Rodrigues 1879e7c127fSCraig Rodrigues RB_FOREACH(ue, user_name_tree, env->sc_user_names_t) { 1889e7c127fSCraig Rodrigues bp = cp = ue->ue_line; 1899e7c127fSCraig Rodrigues 1909e7c127fSCraig Rodrigues /* name */ 1919e7c127fSCraig Rodrigues bp += strlen(bp) + 1; 1929e7c127fSCraig Rodrigues 1939e7c127fSCraig Rodrigues /* password */ 1949e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 1959e7c127fSCraig Rodrigues 1969e7c127fSCraig Rodrigues /* uid */ 1979e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 1989e7c127fSCraig Rodrigues 1999e7c127fSCraig Rodrigues /* gid */ 2009e7c127fSCraig Rodrigues bp[strcspn(bp, ":")] = '\0'; 2019e7c127fSCraig Rodrigues 2029e7c127fSCraig Rodrigues pw_gid = (gid_t)strtonum(bp, 0, GID_MAX, &errstr); 2039e7c127fSCraig Rodrigues if (errstr) { 2049e7c127fSCraig Rodrigues log_warnx("main: failed to parse gid for uid: %d\n", ue->ue_uid); 2059e7c127fSCraig Rodrigues return (-1); 2069e7c127fSCraig Rodrigues } 2079e7c127fSCraig Rodrigues 2089e7c127fSCraig Rodrigues /* bring gid column back to its proper state */ 2099e7c127fSCraig Rodrigues bp[strlen(bp)] = ':'; 2109e7c127fSCraig Rodrigues 2119e7c127fSCraig Rodrigues if ((ue->ue_netid_line = calloc(1, LINE_WIDTH)) == NULL) { 2129e7c127fSCraig Rodrigues return (-1); 2139e7c127fSCraig Rodrigues } 2149e7c127fSCraig Rodrigues 2159e7c127fSCraig Rodrigues if (snprintf(ue->ue_netid_line, LINE_WIDTH-1, "%d:%d", ue->ue_uid, pw_gid) >= LINE_WIDTH) { 2169e7c127fSCraig Rodrigues 2179e7c127fSCraig Rodrigues return (-1); 2189e7c127fSCraig Rodrigues } 2199e7c127fSCraig Rodrigues 2209e7c127fSCraig Rodrigues ue->ue_gid = pw_gid; 2219e7c127fSCraig Rodrigues } 2229e7c127fSCraig Rodrigues 2239e7c127fSCraig Rodrigues RB_FOREACH(ge, group_name_tree, env->sc_group_names_t) { 2249e7c127fSCraig Rodrigues bp = cp = ge->ge_line; 2259e7c127fSCraig Rodrigues 2269e7c127fSCraig Rodrigues /* name */ 2279e7c127fSCraig Rodrigues bp += strlen(bp) + 1; 2289e7c127fSCraig Rodrigues 2299e7c127fSCraig Rodrigues /* password */ 2309e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 2319e7c127fSCraig Rodrigues 2329e7c127fSCraig Rodrigues /* gid */ 2339e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 2349e7c127fSCraig Rodrigues 2359e7c127fSCraig Rodrigues cp = bp; 2369e7c127fSCraig Rodrigues if (*bp == '\0') 2379e7c127fSCraig Rodrigues continue; 2389e7c127fSCraig Rodrigues bp = cp; 2399e7c127fSCraig Rodrigues for (;;) { 2409e7c127fSCraig Rodrigues if (!(cp = strsep(&bp, ","))) 2419e7c127fSCraig Rodrigues break; 2429e7c127fSCraig Rodrigues ukey.ue_line = cp; 2439e7c127fSCraig Rodrigues if ((ue = RB_FIND(user_name_tree, env->sc_user_names_t, 2449e7c127fSCraig Rodrigues &ukey)) == NULL) { 2459e7c127fSCraig Rodrigues /* User not found */ 2469e7c127fSCraig Rodrigues log_warnx("main: user: %s is referenced as a " 2479e7c127fSCraig Rodrigues "group member, but can't be found in the " 2489e7c127fSCraig Rodrigues "users map.\n", ukey.ue_line); 2499e7c127fSCraig Rodrigues if (bp != NULL) 2509e7c127fSCraig Rodrigues *(bp-1) = ','; 2519e7c127fSCraig Rodrigues continue; 2529e7c127fSCraig Rodrigues } 2539e7c127fSCraig Rodrigues if (bp != NULL) 2549e7c127fSCraig Rodrigues *(bp-1) = ','; 2559e7c127fSCraig Rodrigues 2569e7c127fSCraig Rodrigues /* Make sure the new group doesn't equal to the main gid */ 2579e7c127fSCraig Rodrigues if (ge->ge_gid == ue->ue_gid) 2589e7c127fSCraig Rodrigues continue; 2599e7c127fSCraig Rodrigues 2609e7c127fSCraig Rodrigues len = strlen(ue->ue_netid_line); 2619e7c127fSCraig Rodrigues p = ue->ue_netid_line + len; 2629e7c127fSCraig Rodrigues 2639e7c127fSCraig Rodrigues if ((snprintf(p, LINE_WIDTH-len-1, ",%d", 2649e7c127fSCraig Rodrigues ge->ge_gid)) >= (int)(LINE_WIDTH-len)) { 2659e7c127fSCraig Rodrigues return (-1); 2669e7c127fSCraig Rodrigues } 2679e7c127fSCraig Rodrigues } 2689e7c127fSCraig Rodrigues } 2699e7c127fSCraig Rodrigues 2709e7c127fSCraig Rodrigues return (0); 2719e7c127fSCraig Rodrigues } 2729e7c127fSCraig Rodrigues 2739e7c127fSCraig Rodrigues void 2749e7c127fSCraig Rodrigues main_end_update(struct env *env) 2759e7c127fSCraig Rodrigues { 2769e7c127fSCraig Rodrigues struct userent *ue; 2779e7c127fSCraig Rodrigues struct groupent *ge; 2789e7c127fSCraig Rodrigues 2799e7c127fSCraig Rodrigues if (env->update_trashed) 2809e7c127fSCraig Rodrigues return; 2819e7c127fSCraig Rodrigues 2829e7c127fSCraig Rodrigues log_debug("updates are over, cleaning up trees now"); 2839e7c127fSCraig Rodrigues 2849e7c127fSCraig Rodrigues if (main_create_user_groups(env) == -1) { 2859e7c127fSCraig Rodrigues main_trash_update(env); 2869e7c127fSCraig Rodrigues return; 2879e7c127fSCraig Rodrigues } 2889e7c127fSCraig Rodrigues 2899e7c127fSCraig Rodrigues if (env->sc_user_names == NULL) { 2909e7c127fSCraig Rodrigues env->sc_user_names = env->sc_user_names_t; 2919e7c127fSCraig Rodrigues env->sc_user_lines = NULL; 2929e7c127fSCraig Rodrigues env->sc_user_names_t = NULL; 2939e7c127fSCraig Rodrigues 2949e7c127fSCraig Rodrigues env->sc_group_names = env->sc_group_names_t; 2959e7c127fSCraig Rodrigues env->sc_group_lines = NULL; 2969e7c127fSCraig Rodrigues env->sc_group_names_t = NULL; 2979e7c127fSCraig Rodrigues 2989e7c127fSCraig Rodrigues flatten_entries(env); 2999e7c127fSCraig Rodrigues goto make_uids; 3009e7c127fSCraig Rodrigues } 3019e7c127fSCraig Rodrigues 3029e7c127fSCraig Rodrigues /* 3039e7c127fSCraig Rodrigues * clean previous tree. 3049e7c127fSCraig Rodrigues */ 3059e7c127fSCraig Rodrigues while ((ue = RB_ROOT(env->sc_user_names)) != NULL) { 3069e7c127fSCraig Rodrigues RB_REMOVE(user_name_tree, env->sc_user_names, 3079e7c127fSCraig Rodrigues ue); 3089e7c127fSCraig Rodrigues free(ue->ue_netid_line); 3099e7c127fSCraig Rodrigues free(ue); 3109e7c127fSCraig Rodrigues } 3119e7c127fSCraig Rodrigues free(env->sc_user_names); 3129e7c127fSCraig Rodrigues free(env->sc_user_lines); 3139e7c127fSCraig Rodrigues 3149e7c127fSCraig Rodrigues env->sc_user_names = env->sc_user_names_t; 3159e7c127fSCraig Rodrigues env->sc_user_lines = NULL; 3169e7c127fSCraig Rodrigues env->sc_user_names_t = NULL; 3179e7c127fSCraig Rodrigues 3189e7c127fSCraig Rodrigues while ((ge = RB_ROOT(env->sc_group_names)) != NULL) { 3199e7c127fSCraig Rodrigues RB_REMOVE(group_name_tree, 3209e7c127fSCraig Rodrigues env->sc_group_names, ge); 3219e7c127fSCraig Rodrigues free(ge); 3229e7c127fSCraig Rodrigues } 3239e7c127fSCraig Rodrigues free(env->sc_group_names); 3249e7c127fSCraig Rodrigues free(env->sc_group_lines); 3259e7c127fSCraig Rodrigues 3269e7c127fSCraig Rodrigues env->sc_group_names = env->sc_group_names_t; 3279e7c127fSCraig Rodrigues env->sc_group_lines = NULL; 3289e7c127fSCraig Rodrigues env->sc_group_names_t = NULL; 3299e7c127fSCraig Rodrigues 3309e7c127fSCraig Rodrigues 3319e7c127fSCraig Rodrigues flatten_entries(env); 3329e7c127fSCraig Rodrigues 3339e7c127fSCraig Rodrigues /* 3349e7c127fSCraig Rodrigues * trees are flat now. build up uid, gid and netid trees. 3359e7c127fSCraig Rodrigues */ 3369e7c127fSCraig Rodrigues 3379e7c127fSCraig Rodrigues make_uids: 3389e7c127fSCraig Rodrigues RB_INIT(&env->sc_user_uids); 3399e7c127fSCraig Rodrigues RB_INIT(&env->sc_group_gids); 3409e7c127fSCraig Rodrigues RB_FOREACH(ue, user_name_tree, env->sc_user_names) 3419e7c127fSCraig Rodrigues RB_INSERT(user_uid_tree, 3429e7c127fSCraig Rodrigues &env->sc_user_uids, ue); 3439e7c127fSCraig Rodrigues RB_FOREACH(ge, group_name_tree, env->sc_group_names) 3449e7c127fSCraig Rodrigues RB_INSERT(group_gid_tree, 3459e7c127fSCraig Rodrigues &env->sc_group_gids, ge); 3469e7c127fSCraig Rodrigues 3479e7c127fSCraig Rodrigues } 3489e7c127fSCraig Rodrigues 3499e7c127fSCraig Rodrigues void 3509e7c127fSCraig Rodrigues main_dispatch_client(int fd, short events, void *p) 3519e7c127fSCraig Rodrigues { 3529e7c127fSCraig Rodrigues int n; 3539e7c127fSCraig Rodrigues int shut = 0; 3549e7c127fSCraig Rodrigues struct env *env = p; 3559e7c127fSCraig Rodrigues struct imsgev *iev = env->sc_iev; 3569e7c127fSCraig Rodrigues struct imsgbuf *ibuf = &iev->ibuf; 3579e7c127fSCraig Rodrigues struct idm_req ir; 3589e7c127fSCraig Rodrigues struct imsg imsg; 3599e7c127fSCraig Rodrigues 3609e7c127fSCraig Rodrigues if ((events & (EV_READ | EV_WRITE)) == 0) 3619e7c127fSCraig Rodrigues fatalx("unknown event"); 3629e7c127fSCraig Rodrigues 3639e7c127fSCraig Rodrigues if (events & EV_READ) { 3649e7c127fSCraig Rodrigues if ((n = imsg_read(ibuf)) == -1) 3659e7c127fSCraig Rodrigues fatal("imsg_read error"); 3669e7c127fSCraig Rodrigues if (n == 0) 3679e7c127fSCraig Rodrigues shut = 1; 3689e7c127fSCraig Rodrigues } 3699e7c127fSCraig Rodrigues if (events & EV_WRITE) { 3709e7c127fSCraig Rodrigues if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 3719e7c127fSCraig Rodrigues fatal("msgbuf_write"); 3729e7c127fSCraig Rodrigues if (n == 0) 3739e7c127fSCraig Rodrigues shut = 1; 3749e7c127fSCraig Rodrigues goto done; 3759e7c127fSCraig Rodrigues } 3769e7c127fSCraig Rodrigues 3779e7c127fSCraig Rodrigues for (;;) { 3789e7c127fSCraig Rodrigues if ((n = imsg_get(ibuf, &imsg)) == -1) 3799e7c127fSCraig Rodrigues fatal("main_dispatch_client: imsg_get error"); 3809e7c127fSCraig Rodrigues if (n == 0) 3819e7c127fSCraig Rodrigues break; 3829e7c127fSCraig Rodrigues 3839e7c127fSCraig Rodrigues switch (imsg.hdr.type) { 3849e7c127fSCraig Rodrigues case IMSG_START_UPDATE: 3859e7c127fSCraig Rodrigues main_start_update(env); 3869e7c127fSCraig Rodrigues break; 3879e7c127fSCraig Rodrigues case IMSG_PW_ENTRY: { 3889e7c127fSCraig Rodrigues struct userent *ue; 3899e7c127fSCraig Rodrigues size_t len; 3909e7c127fSCraig Rodrigues 3919e7c127fSCraig Rodrigues if (env->update_trashed) 3929e7c127fSCraig Rodrigues break; 3939e7c127fSCraig Rodrigues 3949e7c127fSCraig Rodrigues (void)memcpy(&ir, imsg.data, sizeof(ir)); 3959e7c127fSCraig Rodrigues if ((ue = calloc(1, sizeof(*ue))) == NULL || 3969e7c127fSCraig Rodrigues (ue->ue_line = strdup(ir.ir_line)) == NULL) { 3979e7c127fSCraig Rodrigues /* 3989e7c127fSCraig Rodrigues * should cancel tree update instead. 3999e7c127fSCraig Rodrigues */ 4009e7c127fSCraig Rodrigues fatal("out of memory"); 4019e7c127fSCraig Rodrigues } 4029e7c127fSCraig Rodrigues ue->ue_uid = ir.ir_key.ik_uid; 4039e7c127fSCraig Rodrigues len = strlen(ue->ue_line) + 1; 4049e7c127fSCraig Rodrigues ue->ue_line[strcspn(ue->ue_line, ":")] = '\0'; 4059e7c127fSCraig Rodrigues if (RB_INSERT(user_name_tree, env->sc_user_names_t, 4069e7c127fSCraig Rodrigues ue) != NULL) { /* dup */ 4079e7c127fSCraig Rodrigues free(ue->ue_line); 4089e7c127fSCraig Rodrigues free(ue); 4099e7c127fSCraig Rodrigues } else 4109e7c127fSCraig Rodrigues env->sc_user_line_len += len; 4119e7c127fSCraig Rodrigues break; 4129e7c127fSCraig Rodrigues } 4139e7c127fSCraig Rodrigues case IMSG_GRP_ENTRY: { 4149e7c127fSCraig Rodrigues struct groupent *ge; 4159e7c127fSCraig Rodrigues size_t len; 4169e7c127fSCraig Rodrigues 4179e7c127fSCraig Rodrigues if (env->update_trashed) 4189e7c127fSCraig Rodrigues break; 4199e7c127fSCraig Rodrigues 4209e7c127fSCraig Rodrigues (void)memcpy(&ir, imsg.data, sizeof(ir)); 4219e7c127fSCraig Rodrigues if ((ge = calloc(1, sizeof(*ge))) == NULL || 4229e7c127fSCraig Rodrigues (ge->ge_line = strdup(ir.ir_line)) == NULL) { 4239e7c127fSCraig Rodrigues /* 4249e7c127fSCraig Rodrigues * should cancel tree update instead. 4259e7c127fSCraig Rodrigues */ 4269e7c127fSCraig Rodrigues fatal("out of memory"); 4279e7c127fSCraig Rodrigues } 4289e7c127fSCraig Rodrigues ge->ge_gid = ir.ir_key.ik_gid; 4299e7c127fSCraig Rodrigues len = strlen(ge->ge_line) + 1; 4309e7c127fSCraig Rodrigues ge->ge_line[strcspn(ge->ge_line, ":")] = '\0'; 4319e7c127fSCraig Rodrigues if (RB_INSERT(group_name_tree, env->sc_group_names_t, 4329e7c127fSCraig Rodrigues ge) != NULL) { /* dup */ 4339e7c127fSCraig Rodrigues free(ge->ge_line); 4349e7c127fSCraig Rodrigues free(ge); 4359e7c127fSCraig Rodrigues } else 4369e7c127fSCraig Rodrigues env->sc_group_line_len += len; 4379e7c127fSCraig Rodrigues break; 4389e7c127fSCraig Rodrigues } 4399e7c127fSCraig Rodrigues case IMSG_TRASH_UPDATE: 4409e7c127fSCraig Rodrigues main_trash_update(env); 4419e7c127fSCraig Rodrigues break; 4429e7c127fSCraig Rodrigues case IMSG_END_UPDATE: { 4439e7c127fSCraig Rodrigues main_end_update(env); 4449e7c127fSCraig Rodrigues break; 4459e7c127fSCraig Rodrigues } 4469e7c127fSCraig Rodrigues default: 4479e7c127fSCraig Rodrigues log_debug("main_dispatch_client: unexpected imsg %d", 4489e7c127fSCraig Rodrigues imsg.hdr.type); 4499e7c127fSCraig Rodrigues break; 4509e7c127fSCraig Rodrigues } 4519e7c127fSCraig Rodrigues imsg_free(&imsg); 4529e7c127fSCraig Rodrigues } 4539e7c127fSCraig Rodrigues 4549e7c127fSCraig Rodrigues done: 4559e7c127fSCraig Rodrigues if (!shut) 4569e7c127fSCraig Rodrigues imsg_event_add(iev); 4579e7c127fSCraig Rodrigues else { 4589e7c127fSCraig Rodrigues log_debug("king bula sez: ran into dead pipe"); 4599e7c127fSCraig Rodrigues event_del(&iev->ev); 4609e7c127fSCraig Rodrigues event_loopexit(NULL); 4619e7c127fSCraig Rodrigues } 4629e7c127fSCraig Rodrigues } 4639e7c127fSCraig Rodrigues 4649e7c127fSCraig Rodrigues void 4659e7c127fSCraig Rodrigues main_configure_client(struct env *env) 4669e7c127fSCraig Rodrigues { 4679e7c127fSCraig Rodrigues struct idm *idm; 4689e7c127fSCraig Rodrigues struct imsgev *iev = env->sc_iev; 4699e7c127fSCraig Rodrigues 4709e7c127fSCraig Rodrigues imsg_compose_event(iev, IMSG_CONF_START, 0, 0, -1, env, sizeof(*env)); 4719e7c127fSCraig Rodrigues TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) { 4729e7c127fSCraig Rodrigues imsg_compose_event(iev, IMSG_CONF_IDM, 0, 0, -1, 4739e7c127fSCraig Rodrigues idm, sizeof(*idm)); 4749e7c127fSCraig Rodrigues } 4759e7c127fSCraig Rodrigues imsg_compose_event(iev, IMSG_CONF_END, 0, 0, -1, NULL, 0); 4769e7c127fSCraig Rodrigues } 4779e7c127fSCraig Rodrigues 4789e7c127fSCraig Rodrigues void 4799e7c127fSCraig Rodrigues main_init_timer(int fd, short event, void *p) 4809e7c127fSCraig Rodrigues { 4819e7c127fSCraig Rodrigues struct env *env = p; 4829e7c127fSCraig Rodrigues 4839e7c127fSCraig Rodrigues main_configure_client(env); 4849e7c127fSCraig Rodrigues } 4859e7c127fSCraig Rodrigues 4869e7c127fSCraig Rodrigues void 4879e7c127fSCraig Rodrigues purge_config(struct env *env) 4889e7c127fSCraig Rodrigues { 4899e7c127fSCraig Rodrigues struct idm *idm; 4909e7c127fSCraig Rodrigues 4919e7c127fSCraig Rodrigues while ((idm = TAILQ_FIRST(&env->sc_idms)) != NULL) { 4929e7c127fSCraig Rodrigues TAILQ_REMOVE(&env->sc_idms, idm, idm_entry); 4939e7c127fSCraig Rodrigues free(idm); 4949e7c127fSCraig Rodrigues } 4959e7c127fSCraig Rodrigues } 4969e7c127fSCraig Rodrigues 4979e7c127fSCraig Rodrigues int 4989e7c127fSCraig Rodrigues main(int argc, char *argv[]) 4999e7c127fSCraig Rodrigues { 5009e7c127fSCraig Rodrigues int c; 5019e7c127fSCraig Rodrigues int debug; 5029e7c127fSCraig Rodrigues struct passwd *pw; 5039e7c127fSCraig Rodrigues struct env env; 5049e7c127fSCraig Rodrigues struct event ev_sigint; 5059e7c127fSCraig Rodrigues struct event ev_sigterm; 5069e7c127fSCraig Rodrigues struct event ev_sigchld; 5079e7c127fSCraig Rodrigues struct event ev_sighup; 5089e7c127fSCraig Rodrigues struct event ev_timer; 5099e7c127fSCraig Rodrigues struct timeval tv; 5109e7c127fSCraig Rodrigues 5119e7c127fSCraig Rodrigues debug = 0; 5129e7c127fSCraig Rodrigues ypldap_process = PROC_MAIN; 5139e7c127fSCraig Rodrigues 5149e7c127fSCraig Rodrigues log_init(1); 5159e7c127fSCraig Rodrigues 5169e7c127fSCraig Rodrigues while ((c = getopt(argc, argv, "dD:nf:v")) != -1) { 5179e7c127fSCraig Rodrigues switch (c) { 5189e7c127fSCraig Rodrigues case 'd': 5199e7c127fSCraig Rodrigues debug = 2; 5209e7c127fSCraig Rodrigues break; 5219e7c127fSCraig Rodrigues case 'D': 5229e7c127fSCraig Rodrigues if (cmdline_symset(optarg) < 0) 5239e7c127fSCraig Rodrigues log_warnx("could not parse macro definition %s", 5249e7c127fSCraig Rodrigues optarg); 5259e7c127fSCraig Rodrigues break; 5269e7c127fSCraig Rodrigues case 'n': 5279e7c127fSCraig Rodrigues debug = 2; 5289e7c127fSCraig Rodrigues opts |= YPLDAP_OPT_NOACTION; 5299e7c127fSCraig Rodrigues break; 5309e7c127fSCraig Rodrigues case 'f': 5319e7c127fSCraig Rodrigues conffile = optarg; 5329e7c127fSCraig Rodrigues break; 5339e7c127fSCraig Rodrigues case 'v': 5349e7c127fSCraig Rodrigues opts |= YPLDAP_OPT_VERBOSE; 5359e7c127fSCraig Rodrigues break; 5369e7c127fSCraig Rodrigues default: 5379e7c127fSCraig Rodrigues usage(); 5389e7c127fSCraig Rodrigues } 5399e7c127fSCraig Rodrigues } 5409e7c127fSCraig Rodrigues 5419e7c127fSCraig Rodrigues argc -= optind; 5429e7c127fSCraig Rodrigues argv += optind; 5439e7c127fSCraig Rodrigues 5449e7c127fSCraig Rodrigues if (argc) 5459e7c127fSCraig Rodrigues usage(); 5469e7c127fSCraig Rodrigues 5479e7c127fSCraig Rodrigues RB_INIT(&env.sc_user_uids); 5489e7c127fSCraig Rodrigues RB_INIT(&env.sc_group_gids); 5499e7c127fSCraig Rodrigues 5509e7c127fSCraig Rodrigues if (parse_config(&env, conffile, opts)) 5519e7c127fSCraig Rodrigues exit(1); 5529e7c127fSCraig Rodrigues if (opts & YPLDAP_OPT_NOACTION) { 5539e7c127fSCraig Rodrigues fprintf(stderr, "configuration OK\n"); 5549e7c127fSCraig Rodrigues exit(0); 5559e7c127fSCraig Rodrigues } 5569e7c127fSCraig Rodrigues 5579e7c127fSCraig Rodrigues if (geteuid()) 5589e7c127fSCraig Rodrigues errx(1, "need root privileges"); 5599e7c127fSCraig Rodrigues 5609e7c127fSCraig Rodrigues log_init(debug); 5619e7c127fSCraig Rodrigues 5629e7c127fSCraig Rodrigues if (!debug) { 5639e7c127fSCraig Rodrigues if (daemon(1, 0) == -1) 5649e7c127fSCraig Rodrigues err(1, "failed to daemonize"); 5659e7c127fSCraig Rodrigues } 5669e7c127fSCraig Rodrigues 5679e7c127fSCraig Rodrigues log_info("startup%s", (debug > 1)?" [debug mode]":""); 5689e7c127fSCraig Rodrigues 5699e7c127fSCraig Rodrigues if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, 5709e7c127fSCraig Rodrigues pipe_main2client) == -1) 5719e7c127fSCraig Rodrigues fatal("socketpair"); 5729e7c127fSCraig Rodrigues 5739e7c127fSCraig Rodrigues client_pid = ldapclient(pipe_main2client); 5749e7c127fSCraig Rodrigues 5759e7c127fSCraig Rodrigues setproctitle("parent"); 5769e7c127fSCraig Rodrigues event_init(); 5779e7c127fSCraig Rodrigues 5789e7c127fSCraig Rodrigues signal_set(&ev_sigint, SIGINT, main_sig_handler, &env); 5799e7c127fSCraig Rodrigues signal_set(&ev_sigterm, SIGTERM, main_sig_handler, &env); 5809e7c127fSCraig Rodrigues signal_set(&ev_sighup, SIGHUP, main_sig_handler, &env); 5819e7c127fSCraig Rodrigues signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, &env); 5829e7c127fSCraig Rodrigues signal_add(&ev_sigint, NULL); 5839e7c127fSCraig Rodrigues signal_add(&ev_sigterm, NULL); 5849e7c127fSCraig Rodrigues signal_add(&ev_sighup, NULL); 5859e7c127fSCraig Rodrigues signal_add(&ev_sigchld, NULL); 5869e7c127fSCraig Rodrigues 5879e7c127fSCraig Rodrigues close(pipe_main2client[1]); 5889e7c127fSCraig Rodrigues if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 5899e7c127fSCraig Rodrigues fatal(NULL); 5909e7c127fSCraig Rodrigues imsg_init(&env.sc_iev->ibuf, pipe_main2client[0]); 5919e7c127fSCraig Rodrigues env.sc_iev->handler = main_dispatch_client; 5929e7c127fSCraig Rodrigues 5939e7c127fSCraig Rodrigues env.sc_iev->events = EV_READ; 5949e7c127fSCraig Rodrigues env.sc_iev->data = &env; 5959e7c127fSCraig Rodrigues event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 5969e7c127fSCraig Rodrigues env.sc_iev->handler, &env); 5979e7c127fSCraig Rodrigues event_add(&env.sc_iev->ev, NULL); 5989e7c127fSCraig Rodrigues 5999e7c127fSCraig Rodrigues yp_init(&env); 6009e7c127fSCraig Rodrigues 6019e7c127fSCraig Rodrigues if ((pw = getpwnam(YPLDAP_USER)) == NULL) 6029e7c127fSCraig Rodrigues fatal("getpwnam"); 6039e7c127fSCraig Rodrigues 6049e7c127fSCraig Rodrigues #ifndef DEBUG 6059e7c127fSCraig Rodrigues if (setgroups(1, &pw->pw_gid) || 6069e7c127fSCraig Rodrigues setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 6079e7c127fSCraig Rodrigues setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 6089e7c127fSCraig Rodrigues fatal("cannot drop privileges"); 6099e7c127fSCraig Rodrigues #else 6109e7c127fSCraig Rodrigues #warning disabling privilege revocation in debug mode 6119e7c127fSCraig Rodrigues #endif 6129e7c127fSCraig Rodrigues 6139e7c127fSCraig Rodrigues bzero(&tv, sizeof(tv)); 6149e7c127fSCraig Rodrigues evtimer_set(&ev_timer, main_init_timer, &env); 6159e7c127fSCraig Rodrigues evtimer_add(&ev_timer, &tv); 6169e7c127fSCraig Rodrigues 6179e7c127fSCraig Rodrigues yp_enable_events(); 6189e7c127fSCraig Rodrigues event_dispatch(); 6199e7c127fSCraig Rodrigues main_shutdown(); 6209e7c127fSCraig Rodrigues 6219e7c127fSCraig Rodrigues return (0); 6229e7c127fSCraig Rodrigues } 6239e7c127fSCraig Rodrigues 6249e7c127fSCraig Rodrigues void 6259e7c127fSCraig Rodrigues imsg_event_add(struct imsgev *iev) 6269e7c127fSCraig Rodrigues { 6279e7c127fSCraig Rodrigues if (iev->handler == NULL) { 6289e7c127fSCraig Rodrigues imsg_flush(&iev->ibuf); 6299e7c127fSCraig Rodrigues return; 6309e7c127fSCraig Rodrigues } 6319e7c127fSCraig Rodrigues 6329e7c127fSCraig Rodrigues iev->events = EV_READ; 6339e7c127fSCraig Rodrigues if (iev->ibuf.w.queued) 6349e7c127fSCraig Rodrigues iev->events |= EV_WRITE; 6359e7c127fSCraig Rodrigues 6369e7c127fSCraig Rodrigues event_del(&iev->ev); 6379e7c127fSCraig Rodrigues event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 6389e7c127fSCraig Rodrigues event_add(&iev->ev, NULL); 6399e7c127fSCraig Rodrigues } 6409e7c127fSCraig Rodrigues 6419e7c127fSCraig Rodrigues int 6429e7c127fSCraig Rodrigues imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 6439e7c127fSCraig Rodrigues pid_t pid, int fd, void *data, u_int16_t datalen) 6449e7c127fSCraig Rodrigues { 6459e7c127fSCraig Rodrigues int ret; 6469e7c127fSCraig Rodrigues 6479e7c127fSCraig Rodrigues if ((ret = imsg_compose(&iev->ibuf, type, peerid, 6489e7c127fSCraig Rodrigues pid, fd, data, datalen)) != -1) 6499e7c127fSCraig Rodrigues imsg_event_add(iev); 6509e7c127fSCraig Rodrigues return (ret); 6519e7c127fSCraig Rodrigues } 652