1*9e7c127fSCraig Rodrigues /* $OpenBSD: ypldap.c,v 1.16 2015/11/02 10:06:06 jmatthew Exp $ */ 2*9e7c127fSCraig Rodrigues /* $FreeBSD */ 3*9e7c127fSCraig Rodrigues 4*9e7c127fSCraig Rodrigues /* 5*9e7c127fSCraig Rodrigues * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6*9e7c127fSCraig Rodrigues * 7*9e7c127fSCraig Rodrigues * Permission to use, copy, modify, and distribute this software for any 8*9e7c127fSCraig Rodrigues * purpose with or without fee is hereby granted, provided that the above 9*9e7c127fSCraig Rodrigues * copyright notice and this permission notice appear in all copies. 10*9e7c127fSCraig Rodrigues * 11*9e7c127fSCraig Rodrigues * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12*9e7c127fSCraig Rodrigues * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13*9e7c127fSCraig Rodrigues * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14*9e7c127fSCraig Rodrigues * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15*9e7c127fSCraig Rodrigues * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16*9e7c127fSCraig Rodrigues * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17*9e7c127fSCraig Rodrigues * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18*9e7c127fSCraig Rodrigues */ 19*9e7c127fSCraig Rodrigues 20*9e7c127fSCraig Rodrigues #include <sys/types.h> 21*9e7c127fSCraig Rodrigues #include <sys/queue.h> 22*9e7c127fSCraig Rodrigues #include <sys/socket.h> 23*9e7c127fSCraig Rodrigues #include <sys/signal.h> 24*9e7c127fSCraig Rodrigues #include <sys/tree.h> 25*9e7c127fSCraig Rodrigues #include <sys/wait.h> 26*9e7c127fSCraig Rodrigues 27*9e7c127fSCraig Rodrigues #include <netinet/in.h> 28*9e7c127fSCraig Rodrigues #include <arpa/inet.h> 29*9e7c127fSCraig Rodrigues 30*9e7c127fSCraig Rodrigues #include <err.h> 31*9e7c127fSCraig Rodrigues #include <errno.h> 32*9e7c127fSCraig Rodrigues #include <event.h> 33*9e7c127fSCraig Rodrigues #include <unistd.h> 34*9e7c127fSCraig Rodrigues #include <pwd.h> 35*9e7c127fSCraig Rodrigues #include <stdio.h> 36*9e7c127fSCraig Rodrigues #include <stdlib.h> 37*9e7c127fSCraig Rodrigues #include <string.h> 38*9e7c127fSCraig Rodrigues #include <limits.h> 39*9e7c127fSCraig Rodrigues 40*9e7c127fSCraig Rodrigues #include "ypldap.h" 41*9e7c127fSCraig Rodrigues 42*9e7c127fSCraig Rodrigues __dead void usage(void); 43*9e7c127fSCraig Rodrigues int check_child(pid_t, const char *); 44*9e7c127fSCraig Rodrigues void main_sig_handler(int, short, void *); 45*9e7c127fSCraig Rodrigues void main_shutdown(void); 46*9e7c127fSCraig Rodrigues void main_dispatch_client(int, short, void *); 47*9e7c127fSCraig Rodrigues void main_configure_client(struct env *); 48*9e7c127fSCraig Rodrigues void main_init_timer(int, short, void *); 49*9e7c127fSCraig Rodrigues void main_start_update(struct env *); 50*9e7c127fSCraig Rodrigues void main_trash_update(struct env *); 51*9e7c127fSCraig Rodrigues void main_end_update(struct env *); 52*9e7c127fSCraig Rodrigues int main_create_user_groups(struct env *); 53*9e7c127fSCraig Rodrigues void purge_config(struct env *); 54*9e7c127fSCraig Rodrigues void reconfigure(struct env *); 55*9e7c127fSCraig Rodrigues 56*9e7c127fSCraig Rodrigues int pipe_main2client[2]; 57*9e7c127fSCraig Rodrigues 58*9e7c127fSCraig Rodrigues pid_t client_pid = 0; 59*9e7c127fSCraig Rodrigues char *conffile = YPLDAP_CONF_FILE; 60*9e7c127fSCraig Rodrigues int opts = 0; 61*9e7c127fSCraig Rodrigues 62*9e7c127fSCraig Rodrigues void 63*9e7c127fSCraig Rodrigues usage(void) 64*9e7c127fSCraig Rodrigues { 65*9e7c127fSCraig Rodrigues extern const char *__progname; 66*9e7c127fSCraig Rodrigues 67*9e7c127fSCraig Rodrigues fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 68*9e7c127fSCraig Rodrigues __progname); 69*9e7c127fSCraig Rodrigues exit(1); 70*9e7c127fSCraig Rodrigues } 71*9e7c127fSCraig Rodrigues 72*9e7c127fSCraig Rodrigues int 73*9e7c127fSCraig Rodrigues check_child(pid_t pid, const char *pname) 74*9e7c127fSCraig Rodrigues { 75*9e7c127fSCraig Rodrigues int status; 76*9e7c127fSCraig Rodrigues 77*9e7c127fSCraig Rodrigues if (waitpid(pid, &status, WNOHANG) > 0) { 78*9e7c127fSCraig Rodrigues if (WIFEXITED(status)) { 79*9e7c127fSCraig Rodrigues log_warnx("check_child: lost child %s exited", pname); 80*9e7c127fSCraig Rodrigues return (1); 81*9e7c127fSCraig Rodrigues } 82*9e7c127fSCraig Rodrigues if (WIFSIGNALED(status)) { 83*9e7c127fSCraig Rodrigues log_warnx("check_child: lost child %s terminated; " 84*9e7c127fSCraig Rodrigues "signal %d", pname, WTERMSIG(status)); 85*9e7c127fSCraig Rodrigues return (1); 86*9e7c127fSCraig Rodrigues } 87*9e7c127fSCraig Rodrigues } 88*9e7c127fSCraig Rodrigues return (0); 89*9e7c127fSCraig Rodrigues } 90*9e7c127fSCraig Rodrigues 91*9e7c127fSCraig Rodrigues /* ARGUSED */ 92*9e7c127fSCraig Rodrigues void 93*9e7c127fSCraig Rodrigues main_sig_handler(int sig, short event, void *p) 94*9e7c127fSCraig Rodrigues { 95*9e7c127fSCraig Rodrigues int die = 0; 96*9e7c127fSCraig Rodrigues 97*9e7c127fSCraig Rodrigues switch (sig) { 98*9e7c127fSCraig Rodrigues case SIGTERM: 99*9e7c127fSCraig Rodrigues case SIGINT: 100*9e7c127fSCraig Rodrigues die = 1; 101*9e7c127fSCraig Rodrigues /* FALLTHROUGH */ 102*9e7c127fSCraig Rodrigues case SIGCHLD: 103*9e7c127fSCraig Rodrigues if (check_child(client_pid, "ldap client")) { 104*9e7c127fSCraig Rodrigues client_pid = 0; 105*9e7c127fSCraig Rodrigues die = 1; 106*9e7c127fSCraig Rodrigues } 107*9e7c127fSCraig Rodrigues if (die) 108*9e7c127fSCraig Rodrigues main_shutdown(); 109*9e7c127fSCraig Rodrigues break; 110*9e7c127fSCraig Rodrigues case SIGHUP: 111*9e7c127fSCraig Rodrigues /* reconfigure */ 112*9e7c127fSCraig Rodrigues break; 113*9e7c127fSCraig Rodrigues default: 114*9e7c127fSCraig Rodrigues fatalx("unexpected signal"); 115*9e7c127fSCraig Rodrigues } 116*9e7c127fSCraig Rodrigues } 117*9e7c127fSCraig Rodrigues 118*9e7c127fSCraig Rodrigues void 119*9e7c127fSCraig Rodrigues main_shutdown(void) 120*9e7c127fSCraig Rodrigues { 121*9e7c127fSCraig Rodrigues _exit(0); 122*9e7c127fSCraig Rodrigues } 123*9e7c127fSCraig Rodrigues 124*9e7c127fSCraig Rodrigues void 125*9e7c127fSCraig Rodrigues main_start_update(struct env *env) 126*9e7c127fSCraig Rodrigues { 127*9e7c127fSCraig Rodrigues env->update_trashed = 0; 128*9e7c127fSCraig Rodrigues 129*9e7c127fSCraig Rodrigues log_debug("starting directory update"); 130*9e7c127fSCraig Rodrigues env->sc_user_line_len = 0; 131*9e7c127fSCraig Rodrigues env->sc_group_line_len = 0; 132*9e7c127fSCraig Rodrigues if ((env->sc_user_names_t = calloc(1, 133*9e7c127fSCraig Rodrigues sizeof(*env->sc_user_names_t))) == NULL || 134*9e7c127fSCraig Rodrigues (env->sc_group_names_t = calloc(1, 135*9e7c127fSCraig Rodrigues sizeof(*env->sc_group_names_t))) == NULL) 136*9e7c127fSCraig Rodrigues fatal(NULL); 137*9e7c127fSCraig Rodrigues RB_INIT(env->sc_user_names_t); 138*9e7c127fSCraig Rodrigues RB_INIT(env->sc_group_names_t); 139*9e7c127fSCraig Rodrigues } 140*9e7c127fSCraig Rodrigues 141*9e7c127fSCraig Rodrigues /* 142*9e7c127fSCraig Rodrigues * XXX: Currently this function should only be called when updating is 143*9e7c127fSCraig Rodrigues * finished. A notification should be send to ldapclient that it should stop 144*9e7c127fSCraig Rodrigues * sending new pwd/grp entries before it can be called from different places. 145*9e7c127fSCraig Rodrigues */ 146*9e7c127fSCraig Rodrigues void 147*9e7c127fSCraig Rodrigues main_trash_update(struct env *env) 148*9e7c127fSCraig Rodrigues { 149*9e7c127fSCraig Rodrigues struct userent *ue; 150*9e7c127fSCraig Rodrigues struct groupent *ge; 151*9e7c127fSCraig Rodrigues 152*9e7c127fSCraig Rodrigues env->update_trashed = 1; 153*9e7c127fSCraig Rodrigues 154*9e7c127fSCraig Rodrigues while ((ue = RB_ROOT(env->sc_user_names_t)) != NULL) { 155*9e7c127fSCraig Rodrigues RB_REMOVE(user_name_tree, 156*9e7c127fSCraig Rodrigues env->sc_user_names_t, ue); 157*9e7c127fSCraig Rodrigues free(ue->ue_line); 158*9e7c127fSCraig Rodrigues free(ue->ue_netid_line); 159*9e7c127fSCraig Rodrigues free(ue); 160*9e7c127fSCraig Rodrigues } 161*9e7c127fSCraig Rodrigues free(env->sc_user_names_t); 162*9e7c127fSCraig Rodrigues env->sc_user_names_t = NULL; 163*9e7c127fSCraig Rodrigues while ((ge = RB_ROOT(env->sc_group_names_t)) 164*9e7c127fSCraig Rodrigues != NULL) { 165*9e7c127fSCraig Rodrigues RB_REMOVE(group_name_tree, 166*9e7c127fSCraig Rodrigues env->sc_group_names_t, ge); 167*9e7c127fSCraig Rodrigues free(ge->ge_line); 168*9e7c127fSCraig Rodrigues free(ge); 169*9e7c127fSCraig Rodrigues } 170*9e7c127fSCraig Rodrigues free(env->sc_group_names_t); 171*9e7c127fSCraig Rodrigues env->sc_group_names_t = NULL; 172*9e7c127fSCraig Rodrigues } 173*9e7c127fSCraig Rodrigues 174*9e7c127fSCraig Rodrigues int 175*9e7c127fSCraig Rodrigues main_create_user_groups(struct env *env) 176*9e7c127fSCraig Rodrigues { 177*9e7c127fSCraig Rodrigues struct userent *ue; 178*9e7c127fSCraig Rodrigues struct userent ukey; 179*9e7c127fSCraig Rodrigues struct groupent *ge; 180*9e7c127fSCraig Rodrigues gid_t pw_gid; 181*9e7c127fSCraig Rodrigues char *bp, *cp; 182*9e7c127fSCraig Rodrigues char *p; 183*9e7c127fSCraig Rodrigues const char *errstr = NULL; 184*9e7c127fSCraig Rodrigues size_t len; 185*9e7c127fSCraig Rodrigues 186*9e7c127fSCraig Rodrigues RB_FOREACH(ue, user_name_tree, env->sc_user_names_t) { 187*9e7c127fSCraig Rodrigues bp = cp = ue->ue_line; 188*9e7c127fSCraig Rodrigues 189*9e7c127fSCraig Rodrigues /* name */ 190*9e7c127fSCraig Rodrigues bp += strlen(bp) + 1; 191*9e7c127fSCraig Rodrigues 192*9e7c127fSCraig Rodrigues /* password */ 193*9e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 194*9e7c127fSCraig Rodrigues 195*9e7c127fSCraig Rodrigues /* uid */ 196*9e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 197*9e7c127fSCraig Rodrigues 198*9e7c127fSCraig Rodrigues /* gid */ 199*9e7c127fSCraig Rodrigues bp[strcspn(bp, ":")] = '\0'; 200*9e7c127fSCraig Rodrigues 201*9e7c127fSCraig Rodrigues pw_gid = (gid_t)strtonum(bp, 0, GID_MAX, &errstr); 202*9e7c127fSCraig Rodrigues if (errstr) { 203*9e7c127fSCraig Rodrigues log_warnx("main: failed to parse gid for uid: %d\n", ue->ue_uid); 204*9e7c127fSCraig Rodrigues return (-1); 205*9e7c127fSCraig Rodrigues } 206*9e7c127fSCraig Rodrigues 207*9e7c127fSCraig Rodrigues /* bring gid column back to its proper state */ 208*9e7c127fSCraig Rodrigues bp[strlen(bp)] = ':'; 209*9e7c127fSCraig Rodrigues 210*9e7c127fSCraig Rodrigues if ((ue->ue_netid_line = calloc(1, LINE_WIDTH)) == NULL) { 211*9e7c127fSCraig Rodrigues return (-1); 212*9e7c127fSCraig Rodrigues } 213*9e7c127fSCraig Rodrigues 214*9e7c127fSCraig Rodrigues if (snprintf(ue->ue_netid_line, LINE_WIDTH-1, "%d:%d", ue->ue_uid, pw_gid) >= LINE_WIDTH) { 215*9e7c127fSCraig Rodrigues 216*9e7c127fSCraig Rodrigues return (-1); 217*9e7c127fSCraig Rodrigues } 218*9e7c127fSCraig Rodrigues 219*9e7c127fSCraig Rodrigues ue->ue_gid = pw_gid; 220*9e7c127fSCraig Rodrigues } 221*9e7c127fSCraig Rodrigues 222*9e7c127fSCraig Rodrigues RB_FOREACH(ge, group_name_tree, env->sc_group_names_t) { 223*9e7c127fSCraig Rodrigues bp = cp = ge->ge_line; 224*9e7c127fSCraig Rodrigues 225*9e7c127fSCraig Rodrigues /* name */ 226*9e7c127fSCraig Rodrigues bp += strlen(bp) + 1; 227*9e7c127fSCraig Rodrigues 228*9e7c127fSCraig Rodrigues /* password */ 229*9e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 230*9e7c127fSCraig Rodrigues 231*9e7c127fSCraig Rodrigues /* gid */ 232*9e7c127fSCraig Rodrigues bp += strcspn(bp, ":") + 1; 233*9e7c127fSCraig Rodrigues 234*9e7c127fSCraig Rodrigues cp = bp; 235*9e7c127fSCraig Rodrigues if (*bp == '\0') 236*9e7c127fSCraig Rodrigues continue; 237*9e7c127fSCraig Rodrigues bp = cp; 238*9e7c127fSCraig Rodrigues for (;;) { 239*9e7c127fSCraig Rodrigues if (!(cp = strsep(&bp, ","))) 240*9e7c127fSCraig Rodrigues break; 241*9e7c127fSCraig Rodrigues ukey.ue_line = cp; 242*9e7c127fSCraig Rodrigues if ((ue = RB_FIND(user_name_tree, env->sc_user_names_t, 243*9e7c127fSCraig Rodrigues &ukey)) == NULL) { 244*9e7c127fSCraig Rodrigues /* User not found */ 245*9e7c127fSCraig Rodrigues log_warnx("main: user: %s is referenced as a " 246*9e7c127fSCraig Rodrigues "group member, but can't be found in the " 247*9e7c127fSCraig Rodrigues "users map.\n", ukey.ue_line); 248*9e7c127fSCraig Rodrigues if (bp != NULL) 249*9e7c127fSCraig Rodrigues *(bp-1) = ','; 250*9e7c127fSCraig Rodrigues continue; 251*9e7c127fSCraig Rodrigues } 252*9e7c127fSCraig Rodrigues if (bp != NULL) 253*9e7c127fSCraig Rodrigues *(bp-1) = ','; 254*9e7c127fSCraig Rodrigues 255*9e7c127fSCraig Rodrigues /* Make sure the new group doesn't equal to the main gid */ 256*9e7c127fSCraig Rodrigues if (ge->ge_gid == ue->ue_gid) 257*9e7c127fSCraig Rodrigues continue; 258*9e7c127fSCraig Rodrigues 259*9e7c127fSCraig Rodrigues len = strlen(ue->ue_netid_line); 260*9e7c127fSCraig Rodrigues p = ue->ue_netid_line + len; 261*9e7c127fSCraig Rodrigues 262*9e7c127fSCraig Rodrigues if ((snprintf(p, LINE_WIDTH-len-1, ",%d", 263*9e7c127fSCraig Rodrigues ge->ge_gid)) >= (int)(LINE_WIDTH-len)) { 264*9e7c127fSCraig Rodrigues return (-1); 265*9e7c127fSCraig Rodrigues } 266*9e7c127fSCraig Rodrigues } 267*9e7c127fSCraig Rodrigues } 268*9e7c127fSCraig Rodrigues 269*9e7c127fSCraig Rodrigues return (0); 270*9e7c127fSCraig Rodrigues } 271*9e7c127fSCraig Rodrigues 272*9e7c127fSCraig Rodrigues void 273*9e7c127fSCraig Rodrigues main_end_update(struct env *env) 274*9e7c127fSCraig Rodrigues { 275*9e7c127fSCraig Rodrigues struct userent *ue; 276*9e7c127fSCraig Rodrigues struct groupent *ge; 277*9e7c127fSCraig Rodrigues 278*9e7c127fSCraig Rodrigues if (env->update_trashed) 279*9e7c127fSCraig Rodrigues return; 280*9e7c127fSCraig Rodrigues 281*9e7c127fSCraig Rodrigues log_debug("updates are over, cleaning up trees now"); 282*9e7c127fSCraig Rodrigues 283*9e7c127fSCraig Rodrigues if (main_create_user_groups(env) == -1) { 284*9e7c127fSCraig Rodrigues main_trash_update(env); 285*9e7c127fSCraig Rodrigues return; 286*9e7c127fSCraig Rodrigues } 287*9e7c127fSCraig Rodrigues 288*9e7c127fSCraig Rodrigues if (env->sc_user_names == NULL) { 289*9e7c127fSCraig Rodrigues env->sc_user_names = env->sc_user_names_t; 290*9e7c127fSCraig Rodrigues env->sc_user_lines = NULL; 291*9e7c127fSCraig Rodrigues env->sc_user_names_t = NULL; 292*9e7c127fSCraig Rodrigues 293*9e7c127fSCraig Rodrigues env->sc_group_names = env->sc_group_names_t; 294*9e7c127fSCraig Rodrigues env->sc_group_lines = NULL; 295*9e7c127fSCraig Rodrigues env->sc_group_names_t = NULL; 296*9e7c127fSCraig Rodrigues 297*9e7c127fSCraig Rodrigues flatten_entries(env); 298*9e7c127fSCraig Rodrigues goto make_uids; 299*9e7c127fSCraig Rodrigues } 300*9e7c127fSCraig Rodrigues 301*9e7c127fSCraig Rodrigues /* 302*9e7c127fSCraig Rodrigues * clean previous tree. 303*9e7c127fSCraig Rodrigues */ 304*9e7c127fSCraig Rodrigues while ((ue = RB_ROOT(env->sc_user_names)) != NULL) { 305*9e7c127fSCraig Rodrigues RB_REMOVE(user_name_tree, env->sc_user_names, 306*9e7c127fSCraig Rodrigues ue); 307*9e7c127fSCraig Rodrigues free(ue->ue_netid_line); 308*9e7c127fSCraig Rodrigues free(ue); 309*9e7c127fSCraig Rodrigues } 310*9e7c127fSCraig Rodrigues free(env->sc_user_names); 311*9e7c127fSCraig Rodrigues free(env->sc_user_lines); 312*9e7c127fSCraig Rodrigues 313*9e7c127fSCraig Rodrigues env->sc_user_names = env->sc_user_names_t; 314*9e7c127fSCraig Rodrigues env->sc_user_lines = NULL; 315*9e7c127fSCraig Rodrigues env->sc_user_names_t = NULL; 316*9e7c127fSCraig Rodrigues 317*9e7c127fSCraig Rodrigues while ((ge = RB_ROOT(env->sc_group_names)) != NULL) { 318*9e7c127fSCraig Rodrigues RB_REMOVE(group_name_tree, 319*9e7c127fSCraig Rodrigues env->sc_group_names, ge); 320*9e7c127fSCraig Rodrigues free(ge); 321*9e7c127fSCraig Rodrigues } 322*9e7c127fSCraig Rodrigues free(env->sc_group_names); 323*9e7c127fSCraig Rodrigues free(env->sc_group_lines); 324*9e7c127fSCraig Rodrigues 325*9e7c127fSCraig Rodrigues env->sc_group_names = env->sc_group_names_t; 326*9e7c127fSCraig Rodrigues env->sc_group_lines = NULL; 327*9e7c127fSCraig Rodrigues env->sc_group_names_t = NULL; 328*9e7c127fSCraig Rodrigues 329*9e7c127fSCraig Rodrigues 330*9e7c127fSCraig Rodrigues flatten_entries(env); 331*9e7c127fSCraig Rodrigues 332*9e7c127fSCraig Rodrigues /* 333*9e7c127fSCraig Rodrigues * trees are flat now. build up uid, gid and netid trees. 334*9e7c127fSCraig Rodrigues */ 335*9e7c127fSCraig Rodrigues 336*9e7c127fSCraig Rodrigues make_uids: 337*9e7c127fSCraig Rodrigues RB_INIT(&env->sc_user_uids); 338*9e7c127fSCraig Rodrigues RB_INIT(&env->sc_group_gids); 339*9e7c127fSCraig Rodrigues RB_FOREACH(ue, user_name_tree, env->sc_user_names) 340*9e7c127fSCraig Rodrigues RB_INSERT(user_uid_tree, 341*9e7c127fSCraig Rodrigues &env->sc_user_uids, ue); 342*9e7c127fSCraig Rodrigues RB_FOREACH(ge, group_name_tree, env->sc_group_names) 343*9e7c127fSCraig Rodrigues RB_INSERT(group_gid_tree, 344*9e7c127fSCraig Rodrigues &env->sc_group_gids, ge); 345*9e7c127fSCraig Rodrigues 346*9e7c127fSCraig Rodrigues } 347*9e7c127fSCraig Rodrigues 348*9e7c127fSCraig Rodrigues void 349*9e7c127fSCraig Rodrigues main_dispatch_client(int fd, short events, void *p) 350*9e7c127fSCraig Rodrigues { 351*9e7c127fSCraig Rodrigues int n; 352*9e7c127fSCraig Rodrigues int shut = 0; 353*9e7c127fSCraig Rodrigues struct env *env = p; 354*9e7c127fSCraig Rodrigues struct imsgev *iev = env->sc_iev; 355*9e7c127fSCraig Rodrigues struct imsgbuf *ibuf = &iev->ibuf; 356*9e7c127fSCraig Rodrigues struct idm_req ir; 357*9e7c127fSCraig Rodrigues struct imsg imsg; 358*9e7c127fSCraig Rodrigues 359*9e7c127fSCraig Rodrigues if ((events & (EV_READ | EV_WRITE)) == 0) 360*9e7c127fSCraig Rodrigues fatalx("unknown event"); 361*9e7c127fSCraig Rodrigues 362*9e7c127fSCraig Rodrigues if (events & EV_READ) { 363*9e7c127fSCraig Rodrigues if ((n = imsg_read(ibuf)) == -1) 364*9e7c127fSCraig Rodrigues fatal("imsg_read error"); 365*9e7c127fSCraig Rodrigues if (n == 0) 366*9e7c127fSCraig Rodrigues shut = 1; 367*9e7c127fSCraig Rodrigues } 368*9e7c127fSCraig Rodrigues if (events & EV_WRITE) { 369*9e7c127fSCraig Rodrigues if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 370*9e7c127fSCraig Rodrigues fatal("msgbuf_write"); 371*9e7c127fSCraig Rodrigues if (n == 0) 372*9e7c127fSCraig Rodrigues shut = 1; 373*9e7c127fSCraig Rodrigues goto done; 374*9e7c127fSCraig Rodrigues } 375*9e7c127fSCraig Rodrigues 376*9e7c127fSCraig Rodrigues for (;;) { 377*9e7c127fSCraig Rodrigues if ((n = imsg_get(ibuf, &imsg)) == -1) 378*9e7c127fSCraig Rodrigues fatal("main_dispatch_client: imsg_get error"); 379*9e7c127fSCraig Rodrigues if (n == 0) 380*9e7c127fSCraig Rodrigues break; 381*9e7c127fSCraig Rodrigues 382*9e7c127fSCraig Rodrigues switch (imsg.hdr.type) { 383*9e7c127fSCraig Rodrigues case IMSG_START_UPDATE: 384*9e7c127fSCraig Rodrigues main_start_update(env); 385*9e7c127fSCraig Rodrigues break; 386*9e7c127fSCraig Rodrigues case IMSG_PW_ENTRY: { 387*9e7c127fSCraig Rodrigues struct userent *ue; 388*9e7c127fSCraig Rodrigues size_t len; 389*9e7c127fSCraig Rodrigues 390*9e7c127fSCraig Rodrigues if (env->update_trashed) 391*9e7c127fSCraig Rodrigues break; 392*9e7c127fSCraig Rodrigues 393*9e7c127fSCraig Rodrigues (void)memcpy(&ir, imsg.data, sizeof(ir)); 394*9e7c127fSCraig Rodrigues if ((ue = calloc(1, sizeof(*ue))) == NULL || 395*9e7c127fSCraig Rodrigues (ue->ue_line = strdup(ir.ir_line)) == NULL) { 396*9e7c127fSCraig Rodrigues /* 397*9e7c127fSCraig Rodrigues * should cancel tree update instead. 398*9e7c127fSCraig Rodrigues */ 399*9e7c127fSCraig Rodrigues fatal("out of memory"); 400*9e7c127fSCraig Rodrigues } 401*9e7c127fSCraig Rodrigues ue->ue_uid = ir.ir_key.ik_uid; 402*9e7c127fSCraig Rodrigues len = strlen(ue->ue_line) + 1; 403*9e7c127fSCraig Rodrigues ue->ue_line[strcspn(ue->ue_line, ":")] = '\0'; 404*9e7c127fSCraig Rodrigues if (RB_INSERT(user_name_tree, env->sc_user_names_t, 405*9e7c127fSCraig Rodrigues ue) != NULL) { /* dup */ 406*9e7c127fSCraig Rodrigues free(ue->ue_line); 407*9e7c127fSCraig Rodrigues free(ue); 408*9e7c127fSCraig Rodrigues } else 409*9e7c127fSCraig Rodrigues env->sc_user_line_len += len; 410*9e7c127fSCraig Rodrigues break; 411*9e7c127fSCraig Rodrigues } 412*9e7c127fSCraig Rodrigues case IMSG_GRP_ENTRY: { 413*9e7c127fSCraig Rodrigues struct groupent *ge; 414*9e7c127fSCraig Rodrigues size_t len; 415*9e7c127fSCraig Rodrigues 416*9e7c127fSCraig Rodrigues if (env->update_trashed) 417*9e7c127fSCraig Rodrigues break; 418*9e7c127fSCraig Rodrigues 419*9e7c127fSCraig Rodrigues (void)memcpy(&ir, imsg.data, sizeof(ir)); 420*9e7c127fSCraig Rodrigues if ((ge = calloc(1, sizeof(*ge))) == NULL || 421*9e7c127fSCraig Rodrigues (ge->ge_line = strdup(ir.ir_line)) == NULL) { 422*9e7c127fSCraig Rodrigues /* 423*9e7c127fSCraig Rodrigues * should cancel tree update instead. 424*9e7c127fSCraig Rodrigues */ 425*9e7c127fSCraig Rodrigues fatal("out of memory"); 426*9e7c127fSCraig Rodrigues } 427*9e7c127fSCraig Rodrigues ge->ge_gid = ir.ir_key.ik_gid; 428*9e7c127fSCraig Rodrigues len = strlen(ge->ge_line) + 1; 429*9e7c127fSCraig Rodrigues ge->ge_line[strcspn(ge->ge_line, ":")] = '\0'; 430*9e7c127fSCraig Rodrigues if (RB_INSERT(group_name_tree, env->sc_group_names_t, 431*9e7c127fSCraig Rodrigues ge) != NULL) { /* dup */ 432*9e7c127fSCraig Rodrigues free(ge->ge_line); 433*9e7c127fSCraig Rodrigues free(ge); 434*9e7c127fSCraig Rodrigues } else 435*9e7c127fSCraig Rodrigues env->sc_group_line_len += len; 436*9e7c127fSCraig Rodrigues break; 437*9e7c127fSCraig Rodrigues } 438*9e7c127fSCraig Rodrigues case IMSG_TRASH_UPDATE: 439*9e7c127fSCraig Rodrigues main_trash_update(env); 440*9e7c127fSCraig Rodrigues break; 441*9e7c127fSCraig Rodrigues case IMSG_END_UPDATE: { 442*9e7c127fSCraig Rodrigues main_end_update(env); 443*9e7c127fSCraig Rodrigues break; 444*9e7c127fSCraig Rodrigues } 445*9e7c127fSCraig Rodrigues default: 446*9e7c127fSCraig Rodrigues log_debug("main_dispatch_client: unexpected imsg %d", 447*9e7c127fSCraig Rodrigues imsg.hdr.type); 448*9e7c127fSCraig Rodrigues break; 449*9e7c127fSCraig Rodrigues } 450*9e7c127fSCraig Rodrigues imsg_free(&imsg); 451*9e7c127fSCraig Rodrigues } 452*9e7c127fSCraig Rodrigues 453*9e7c127fSCraig Rodrigues done: 454*9e7c127fSCraig Rodrigues if (!shut) 455*9e7c127fSCraig Rodrigues imsg_event_add(iev); 456*9e7c127fSCraig Rodrigues else { 457*9e7c127fSCraig Rodrigues log_debug("king bula sez: ran into dead pipe"); 458*9e7c127fSCraig Rodrigues event_del(&iev->ev); 459*9e7c127fSCraig Rodrigues event_loopexit(NULL); 460*9e7c127fSCraig Rodrigues } 461*9e7c127fSCraig Rodrigues } 462*9e7c127fSCraig Rodrigues 463*9e7c127fSCraig Rodrigues void 464*9e7c127fSCraig Rodrigues main_configure_client(struct env *env) 465*9e7c127fSCraig Rodrigues { 466*9e7c127fSCraig Rodrigues struct idm *idm; 467*9e7c127fSCraig Rodrigues struct imsgev *iev = env->sc_iev; 468*9e7c127fSCraig Rodrigues 469*9e7c127fSCraig Rodrigues imsg_compose_event(iev, IMSG_CONF_START, 0, 0, -1, env, sizeof(*env)); 470*9e7c127fSCraig Rodrigues TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) { 471*9e7c127fSCraig Rodrigues imsg_compose_event(iev, IMSG_CONF_IDM, 0, 0, -1, 472*9e7c127fSCraig Rodrigues idm, sizeof(*idm)); 473*9e7c127fSCraig Rodrigues } 474*9e7c127fSCraig Rodrigues imsg_compose_event(iev, IMSG_CONF_END, 0, 0, -1, NULL, 0); 475*9e7c127fSCraig Rodrigues } 476*9e7c127fSCraig Rodrigues 477*9e7c127fSCraig Rodrigues void 478*9e7c127fSCraig Rodrigues main_init_timer(int fd, short event, void *p) 479*9e7c127fSCraig Rodrigues { 480*9e7c127fSCraig Rodrigues struct env *env = p; 481*9e7c127fSCraig Rodrigues 482*9e7c127fSCraig Rodrigues main_configure_client(env); 483*9e7c127fSCraig Rodrigues } 484*9e7c127fSCraig Rodrigues 485*9e7c127fSCraig Rodrigues void 486*9e7c127fSCraig Rodrigues purge_config(struct env *env) 487*9e7c127fSCraig Rodrigues { 488*9e7c127fSCraig Rodrigues struct idm *idm; 489*9e7c127fSCraig Rodrigues 490*9e7c127fSCraig Rodrigues while ((idm = TAILQ_FIRST(&env->sc_idms)) != NULL) { 491*9e7c127fSCraig Rodrigues TAILQ_REMOVE(&env->sc_idms, idm, idm_entry); 492*9e7c127fSCraig Rodrigues free(idm); 493*9e7c127fSCraig Rodrigues } 494*9e7c127fSCraig Rodrigues } 495*9e7c127fSCraig Rodrigues 496*9e7c127fSCraig Rodrigues int 497*9e7c127fSCraig Rodrigues main(int argc, char *argv[]) 498*9e7c127fSCraig Rodrigues { 499*9e7c127fSCraig Rodrigues int c; 500*9e7c127fSCraig Rodrigues int debug; 501*9e7c127fSCraig Rodrigues struct passwd *pw; 502*9e7c127fSCraig Rodrigues struct env env; 503*9e7c127fSCraig Rodrigues struct event ev_sigint; 504*9e7c127fSCraig Rodrigues struct event ev_sigterm; 505*9e7c127fSCraig Rodrigues struct event ev_sigchld; 506*9e7c127fSCraig Rodrigues struct event ev_sighup; 507*9e7c127fSCraig Rodrigues struct event ev_timer; 508*9e7c127fSCraig Rodrigues struct timeval tv; 509*9e7c127fSCraig Rodrigues 510*9e7c127fSCraig Rodrigues debug = 0; 511*9e7c127fSCraig Rodrigues ypldap_process = PROC_MAIN; 512*9e7c127fSCraig Rodrigues 513*9e7c127fSCraig Rodrigues log_init(1); 514*9e7c127fSCraig Rodrigues 515*9e7c127fSCraig Rodrigues while ((c = getopt(argc, argv, "dD:nf:v")) != -1) { 516*9e7c127fSCraig Rodrigues switch (c) { 517*9e7c127fSCraig Rodrigues case 'd': 518*9e7c127fSCraig Rodrigues debug = 2; 519*9e7c127fSCraig Rodrigues break; 520*9e7c127fSCraig Rodrigues case 'D': 521*9e7c127fSCraig Rodrigues if (cmdline_symset(optarg) < 0) 522*9e7c127fSCraig Rodrigues log_warnx("could not parse macro definition %s", 523*9e7c127fSCraig Rodrigues optarg); 524*9e7c127fSCraig Rodrigues break; 525*9e7c127fSCraig Rodrigues case 'n': 526*9e7c127fSCraig Rodrigues debug = 2; 527*9e7c127fSCraig Rodrigues opts |= YPLDAP_OPT_NOACTION; 528*9e7c127fSCraig Rodrigues break; 529*9e7c127fSCraig Rodrigues case 'f': 530*9e7c127fSCraig Rodrigues conffile = optarg; 531*9e7c127fSCraig Rodrigues break; 532*9e7c127fSCraig Rodrigues case 'v': 533*9e7c127fSCraig Rodrigues opts |= YPLDAP_OPT_VERBOSE; 534*9e7c127fSCraig Rodrigues break; 535*9e7c127fSCraig Rodrigues default: 536*9e7c127fSCraig Rodrigues usage(); 537*9e7c127fSCraig Rodrigues } 538*9e7c127fSCraig Rodrigues } 539*9e7c127fSCraig Rodrigues 540*9e7c127fSCraig Rodrigues argc -= optind; 541*9e7c127fSCraig Rodrigues argv += optind; 542*9e7c127fSCraig Rodrigues 543*9e7c127fSCraig Rodrigues if (argc) 544*9e7c127fSCraig Rodrigues usage(); 545*9e7c127fSCraig Rodrigues 546*9e7c127fSCraig Rodrigues RB_INIT(&env.sc_user_uids); 547*9e7c127fSCraig Rodrigues RB_INIT(&env.sc_group_gids); 548*9e7c127fSCraig Rodrigues 549*9e7c127fSCraig Rodrigues if (parse_config(&env, conffile, opts)) 550*9e7c127fSCraig Rodrigues exit(1); 551*9e7c127fSCraig Rodrigues if (opts & YPLDAP_OPT_NOACTION) { 552*9e7c127fSCraig Rodrigues fprintf(stderr, "configuration OK\n"); 553*9e7c127fSCraig Rodrigues exit(0); 554*9e7c127fSCraig Rodrigues } 555*9e7c127fSCraig Rodrigues 556*9e7c127fSCraig Rodrigues if (geteuid()) 557*9e7c127fSCraig Rodrigues errx(1, "need root privileges"); 558*9e7c127fSCraig Rodrigues 559*9e7c127fSCraig Rodrigues log_init(debug); 560*9e7c127fSCraig Rodrigues 561*9e7c127fSCraig Rodrigues if (!debug) { 562*9e7c127fSCraig Rodrigues if (daemon(1, 0) == -1) 563*9e7c127fSCraig Rodrigues err(1, "failed to daemonize"); 564*9e7c127fSCraig Rodrigues } 565*9e7c127fSCraig Rodrigues 566*9e7c127fSCraig Rodrigues log_info("startup%s", (debug > 1)?" [debug mode]":""); 567*9e7c127fSCraig Rodrigues 568*9e7c127fSCraig Rodrigues if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, 569*9e7c127fSCraig Rodrigues pipe_main2client) == -1) 570*9e7c127fSCraig Rodrigues fatal("socketpair"); 571*9e7c127fSCraig Rodrigues 572*9e7c127fSCraig Rodrigues client_pid = ldapclient(pipe_main2client); 573*9e7c127fSCraig Rodrigues 574*9e7c127fSCraig Rodrigues setproctitle("parent"); 575*9e7c127fSCraig Rodrigues event_init(); 576*9e7c127fSCraig Rodrigues 577*9e7c127fSCraig Rodrigues signal_set(&ev_sigint, SIGINT, main_sig_handler, &env); 578*9e7c127fSCraig Rodrigues signal_set(&ev_sigterm, SIGTERM, main_sig_handler, &env); 579*9e7c127fSCraig Rodrigues signal_set(&ev_sighup, SIGHUP, main_sig_handler, &env); 580*9e7c127fSCraig Rodrigues signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, &env); 581*9e7c127fSCraig Rodrigues signal_add(&ev_sigint, NULL); 582*9e7c127fSCraig Rodrigues signal_add(&ev_sigterm, NULL); 583*9e7c127fSCraig Rodrigues signal_add(&ev_sighup, NULL); 584*9e7c127fSCraig Rodrigues signal_add(&ev_sigchld, NULL); 585*9e7c127fSCraig Rodrigues 586*9e7c127fSCraig Rodrigues close(pipe_main2client[1]); 587*9e7c127fSCraig Rodrigues if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 588*9e7c127fSCraig Rodrigues fatal(NULL); 589*9e7c127fSCraig Rodrigues imsg_init(&env.sc_iev->ibuf, pipe_main2client[0]); 590*9e7c127fSCraig Rodrigues env.sc_iev->handler = main_dispatch_client; 591*9e7c127fSCraig Rodrigues 592*9e7c127fSCraig Rodrigues env.sc_iev->events = EV_READ; 593*9e7c127fSCraig Rodrigues env.sc_iev->data = &env; 594*9e7c127fSCraig Rodrigues event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 595*9e7c127fSCraig Rodrigues env.sc_iev->handler, &env); 596*9e7c127fSCraig Rodrigues event_add(&env.sc_iev->ev, NULL); 597*9e7c127fSCraig Rodrigues 598*9e7c127fSCraig Rodrigues yp_init(&env); 599*9e7c127fSCraig Rodrigues 600*9e7c127fSCraig Rodrigues if ((pw = getpwnam(YPLDAP_USER)) == NULL) 601*9e7c127fSCraig Rodrigues fatal("getpwnam"); 602*9e7c127fSCraig Rodrigues 603*9e7c127fSCraig Rodrigues #ifndef DEBUG 604*9e7c127fSCraig Rodrigues if (setgroups(1, &pw->pw_gid) || 605*9e7c127fSCraig Rodrigues setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 606*9e7c127fSCraig Rodrigues setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 607*9e7c127fSCraig Rodrigues fatal("cannot drop privileges"); 608*9e7c127fSCraig Rodrigues #else 609*9e7c127fSCraig Rodrigues #warning disabling privilege revocation in debug mode 610*9e7c127fSCraig Rodrigues #endif 611*9e7c127fSCraig Rodrigues 612*9e7c127fSCraig Rodrigues bzero(&tv, sizeof(tv)); 613*9e7c127fSCraig Rodrigues evtimer_set(&ev_timer, main_init_timer, &env); 614*9e7c127fSCraig Rodrigues evtimer_add(&ev_timer, &tv); 615*9e7c127fSCraig Rodrigues 616*9e7c127fSCraig Rodrigues yp_enable_events(); 617*9e7c127fSCraig Rodrigues event_dispatch(); 618*9e7c127fSCraig Rodrigues main_shutdown(); 619*9e7c127fSCraig Rodrigues 620*9e7c127fSCraig Rodrigues return (0); 621*9e7c127fSCraig Rodrigues } 622*9e7c127fSCraig Rodrigues 623*9e7c127fSCraig Rodrigues void 624*9e7c127fSCraig Rodrigues imsg_event_add(struct imsgev *iev) 625*9e7c127fSCraig Rodrigues { 626*9e7c127fSCraig Rodrigues if (iev->handler == NULL) { 627*9e7c127fSCraig Rodrigues imsg_flush(&iev->ibuf); 628*9e7c127fSCraig Rodrigues return; 629*9e7c127fSCraig Rodrigues } 630*9e7c127fSCraig Rodrigues 631*9e7c127fSCraig Rodrigues iev->events = EV_READ; 632*9e7c127fSCraig Rodrigues if (iev->ibuf.w.queued) 633*9e7c127fSCraig Rodrigues iev->events |= EV_WRITE; 634*9e7c127fSCraig Rodrigues 635*9e7c127fSCraig Rodrigues event_del(&iev->ev); 636*9e7c127fSCraig Rodrigues event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 637*9e7c127fSCraig Rodrigues event_add(&iev->ev, NULL); 638*9e7c127fSCraig Rodrigues } 639*9e7c127fSCraig Rodrigues 640*9e7c127fSCraig Rodrigues int 641*9e7c127fSCraig Rodrigues imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 642*9e7c127fSCraig Rodrigues pid_t pid, int fd, void *data, u_int16_t datalen) 643*9e7c127fSCraig Rodrigues { 644*9e7c127fSCraig Rodrigues int ret; 645*9e7c127fSCraig Rodrigues 646*9e7c127fSCraig Rodrigues if ((ret = imsg_compose(&iev->ibuf, type, peerid, 647*9e7c127fSCraig Rodrigues pid, fd, data, datalen)) != -1) 648*9e7c127fSCraig Rodrigues imsg_event_add(iev); 649*9e7c127fSCraig Rodrigues return (ret); 650*9e7c127fSCraig Rodrigues } 651