ypldap.c revision 290931
1290931Srodrigc/* $OpenBSD: ypldap.c,v 1.16 2015/11/02 10:06:06 jmatthew Exp $ */ 2290931Srodrigc/* $FreeBSD */ 3290931Srodrigc 4290931Srodrigc/* 5290931Srodrigc * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6290931Srodrigc * 7290931Srodrigc * Permission to use, copy, modify, and distribute this software for any 8290931Srodrigc * purpose with or without fee is hereby granted, provided that the above 9290931Srodrigc * copyright notice and this permission notice appear in all copies. 10290931Srodrigc * 11290931Srodrigc * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12290931Srodrigc * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13290931Srodrigc * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14290931Srodrigc * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15290931Srodrigc * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16290931Srodrigc * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17290931Srodrigc * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18290931Srodrigc */ 19290931Srodrigc 20290931Srodrigc#include <sys/types.h> 21290931Srodrigc#include <sys/queue.h> 22290931Srodrigc#include <sys/socket.h> 23290931Srodrigc#include <sys/signal.h> 24290931Srodrigc#include <sys/tree.h> 25290931Srodrigc#include <sys/wait.h> 26290931Srodrigc 27290931Srodrigc#include <netinet/in.h> 28290931Srodrigc#include <arpa/inet.h> 29290931Srodrigc 30290931Srodrigc#include <err.h> 31290931Srodrigc#include <errno.h> 32290931Srodrigc#include <event.h> 33290931Srodrigc#include <unistd.h> 34290931Srodrigc#include <pwd.h> 35290931Srodrigc#include <stdio.h> 36290931Srodrigc#include <stdlib.h> 37290931Srodrigc#include <string.h> 38290931Srodrigc#include <limits.h> 39290931Srodrigc 40290931Srodrigc#include "ypldap.h" 41290931Srodrigc 42290931Srodrigc__dead void usage(void); 43290931Srodrigcint check_child(pid_t, const char *); 44290931Srodrigcvoid main_sig_handler(int, short, void *); 45290931Srodrigcvoid main_shutdown(void); 46290931Srodrigcvoid main_dispatch_client(int, short, void *); 47290931Srodrigcvoid main_configure_client(struct env *); 48290931Srodrigcvoid main_init_timer(int, short, void *); 49290931Srodrigcvoid main_start_update(struct env *); 50290931Srodrigcvoid main_trash_update(struct env *); 51290931Srodrigcvoid main_end_update(struct env *); 52290931Srodrigcint main_create_user_groups(struct env *); 53290931Srodrigcvoid purge_config(struct env *); 54290931Srodrigcvoid reconfigure(struct env *); 55290931Srodrigc 56290931Srodrigcint pipe_main2client[2]; 57290931Srodrigc 58290931Srodrigcpid_t client_pid = 0; 59290931Srodrigcchar *conffile = YPLDAP_CONF_FILE; 60290931Srodrigcint opts = 0; 61290931Srodrigc 62290931Srodrigcvoid 63290931Srodrigcusage(void) 64290931Srodrigc{ 65290931Srodrigc extern const char *__progname; 66290931Srodrigc 67290931Srodrigc fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 68290931Srodrigc __progname); 69290931Srodrigc exit(1); 70290931Srodrigc} 71290931Srodrigc 72290931Srodrigcint 73290931Srodrigccheck_child(pid_t pid, const char *pname) 74290931Srodrigc{ 75290931Srodrigc int status; 76290931Srodrigc 77290931Srodrigc if (waitpid(pid, &status, WNOHANG) > 0) { 78290931Srodrigc if (WIFEXITED(status)) { 79290931Srodrigc log_warnx("check_child: lost child %s exited", pname); 80290931Srodrigc return (1); 81290931Srodrigc } 82290931Srodrigc if (WIFSIGNALED(status)) { 83290931Srodrigc log_warnx("check_child: lost child %s terminated; " 84290931Srodrigc "signal %d", pname, WTERMSIG(status)); 85290931Srodrigc return (1); 86290931Srodrigc } 87290931Srodrigc } 88290931Srodrigc return (0); 89290931Srodrigc} 90290931Srodrigc 91290931Srodrigc/* ARGUSED */ 92290931Srodrigcvoid 93290931Srodrigcmain_sig_handler(int sig, short event, void *p) 94290931Srodrigc{ 95290931Srodrigc int die = 0; 96290931Srodrigc 97290931Srodrigc switch (sig) { 98290931Srodrigc case SIGTERM: 99290931Srodrigc case SIGINT: 100290931Srodrigc die = 1; 101290931Srodrigc /* FALLTHROUGH */ 102290931Srodrigc case SIGCHLD: 103290931Srodrigc if (check_child(client_pid, "ldap client")) { 104290931Srodrigc client_pid = 0; 105290931Srodrigc die = 1; 106290931Srodrigc } 107290931Srodrigc if (die) 108290931Srodrigc main_shutdown(); 109290931Srodrigc break; 110290931Srodrigc case SIGHUP: 111290931Srodrigc /* reconfigure */ 112290931Srodrigc break; 113290931Srodrigc default: 114290931Srodrigc fatalx("unexpected signal"); 115290931Srodrigc } 116290931Srodrigc} 117290931Srodrigc 118290931Srodrigcvoid 119290931Srodrigcmain_shutdown(void) 120290931Srodrigc{ 121290931Srodrigc _exit(0); 122290931Srodrigc} 123290931Srodrigc 124290931Srodrigcvoid 125290931Srodrigcmain_start_update(struct env *env) 126290931Srodrigc{ 127290931Srodrigc env->update_trashed = 0; 128290931Srodrigc 129290931Srodrigc log_debug("starting directory update"); 130290931Srodrigc env->sc_user_line_len = 0; 131290931Srodrigc env->sc_group_line_len = 0; 132290931Srodrigc if ((env->sc_user_names_t = calloc(1, 133290931Srodrigc sizeof(*env->sc_user_names_t))) == NULL || 134290931Srodrigc (env->sc_group_names_t = calloc(1, 135290931Srodrigc sizeof(*env->sc_group_names_t))) == NULL) 136290931Srodrigc fatal(NULL); 137290931Srodrigc RB_INIT(env->sc_user_names_t); 138290931Srodrigc RB_INIT(env->sc_group_names_t); 139290931Srodrigc} 140290931Srodrigc 141290931Srodrigc/* 142290931Srodrigc * XXX: Currently this function should only be called when updating is 143290931Srodrigc * finished. A notification should be send to ldapclient that it should stop 144290931Srodrigc * sending new pwd/grp entries before it can be called from different places. 145290931Srodrigc */ 146290931Srodrigcvoid 147290931Srodrigcmain_trash_update(struct env *env) 148290931Srodrigc{ 149290931Srodrigc struct userent *ue; 150290931Srodrigc struct groupent *ge; 151290931Srodrigc 152290931Srodrigc env->update_trashed = 1; 153290931Srodrigc 154290931Srodrigc while ((ue = RB_ROOT(env->sc_user_names_t)) != NULL) { 155290931Srodrigc RB_REMOVE(user_name_tree, 156290931Srodrigc env->sc_user_names_t, ue); 157290931Srodrigc free(ue->ue_line); 158290931Srodrigc free(ue->ue_netid_line); 159290931Srodrigc free(ue); 160290931Srodrigc } 161290931Srodrigc free(env->sc_user_names_t); 162290931Srodrigc env->sc_user_names_t = NULL; 163290931Srodrigc while ((ge = RB_ROOT(env->sc_group_names_t)) 164290931Srodrigc != NULL) { 165290931Srodrigc RB_REMOVE(group_name_tree, 166290931Srodrigc env->sc_group_names_t, ge); 167290931Srodrigc free(ge->ge_line); 168290931Srodrigc free(ge); 169290931Srodrigc } 170290931Srodrigc free(env->sc_group_names_t); 171290931Srodrigc env->sc_group_names_t = NULL; 172290931Srodrigc} 173290931Srodrigc 174290931Srodrigcint 175290931Srodrigcmain_create_user_groups(struct env *env) 176290931Srodrigc{ 177290931Srodrigc struct userent *ue; 178290931Srodrigc struct userent ukey; 179290931Srodrigc struct groupent *ge; 180290931Srodrigc gid_t pw_gid; 181290931Srodrigc char *bp, *cp; 182290931Srodrigc char *p; 183290931Srodrigc const char *errstr = NULL; 184290931Srodrigc size_t len; 185290931Srodrigc 186290931Srodrigc RB_FOREACH(ue, user_name_tree, env->sc_user_names_t) { 187290931Srodrigc bp = cp = ue->ue_line; 188290931Srodrigc 189290931Srodrigc /* name */ 190290931Srodrigc bp += strlen(bp) + 1; 191290931Srodrigc 192290931Srodrigc /* password */ 193290931Srodrigc bp += strcspn(bp, ":") + 1; 194290931Srodrigc 195290931Srodrigc /* uid */ 196290931Srodrigc bp += strcspn(bp, ":") + 1; 197290931Srodrigc 198290931Srodrigc /* gid */ 199290931Srodrigc bp[strcspn(bp, ":")] = '\0'; 200290931Srodrigc 201290931Srodrigc pw_gid = (gid_t)strtonum(bp, 0, GID_MAX, &errstr); 202290931Srodrigc if (errstr) { 203290931Srodrigc log_warnx("main: failed to parse gid for uid: %d\n", ue->ue_uid); 204290931Srodrigc return (-1); 205290931Srodrigc } 206290931Srodrigc 207290931Srodrigc /* bring gid column back to its proper state */ 208290931Srodrigc bp[strlen(bp)] = ':'; 209290931Srodrigc 210290931Srodrigc if ((ue->ue_netid_line = calloc(1, LINE_WIDTH)) == NULL) { 211290931Srodrigc return (-1); 212290931Srodrigc } 213290931Srodrigc 214290931Srodrigc if (snprintf(ue->ue_netid_line, LINE_WIDTH-1, "%d:%d", ue->ue_uid, pw_gid) >= LINE_WIDTH) { 215290931Srodrigc 216290931Srodrigc return (-1); 217290931Srodrigc } 218290931Srodrigc 219290931Srodrigc ue->ue_gid = pw_gid; 220290931Srodrigc } 221290931Srodrigc 222290931Srodrigc RB_FOREACH(ge, group_name_tree, env->sc_group_names_t) { 223290931Srodrigc bp = cp = ge->ge_line; 224290931Srodrigc 225290931Srodrigc /* name */ 226290931Srodrigc bp += strlen(bp) + 1; 227290931Srodrigc 228290931Srodrigc /* password */ 229290931Srodrigc bp += strcspn(bp, ":") + 1; 230290931Srodrigc 231290931Srodrigc /* gid */ 232290931Srodrigc bp += strcspn(bp, ":") + 1; 233290931Srodrigc 234290931Srodrigc cp = bp; 235290931Srodrigc if (*bp == '\0') 236290931Srodrigc continue; 237290931Srodrigc bp = cp; 238290931Srodrigc for (;;) { 239290931Srodrigc if (!(cp = strsep(&bp, ","))) 240290931Srodrigc break; 241290931Srodrigc ukey.ue_line = cp; 242290931Srodrigc if ((ue = RB_FIND(user_name_tree, env->sc_user_names_t, 243290931Srodrigc &ukey)) == NULL) { 244290931Srodrigc /* User not found */ 245290931Srodrigc log_warnx("main: user: %s is referenced as a " 246290931Srodrigc "group member, but can't be found in the " 247290931Srodrigc "users map.\n", ukey.ue_line); 248290931Srodrigc if (bp != NULL) 249290931Srodrigc *(bp-1) = ','; 250290931Srodrigc continue; 251290931Srodrigc } 252290931Srodrigc if (bp != NULL) 253290931Srodrigc *(bp-1) = ','; 254290931Srodrigc 255290931Srodrigc /* Make sure the new group doesn't equal to the main gid */ 256290931Srodrigc if (ge->ge_gid == ue->ue_gid) 257290931Srodrigc continue; 258290931Srodrigc 259290931Srodrigc len = strlen(ue->ue_netid_line); 260290931Srodrigc p = ue->ue_netid_line + len; 261290931Srodrigc 262290931Srodrigc if ((snprintf(p, LINE_WIDTH-len-1, ",%d", 263290931Srodrigc ge->ge_gid)) >= (int)(LINE_WIDTH-len)) { 264290931Srodrigc return (-1); 265290931Srodrigc } 266290931Srodrigc } 267290931Srodrigc } 268290931Srodrigc 269290931Srodrigc return (0); 270290931Srodrigc} 271290931Srodrigc 272290931Srodrigcvoid 273290931Srodrigcmain_end_update(struct env *env) 274290931Srodrigc{ 275290931Srodrigc struct userent *ue; 276290931Srodrigc struct groupent *ge; 277290931Srodrigc 278290931Srodrigc if (env->update_trashed) 279290931Srodrigc return; 280290931Srodrigc 281290931Srodrigc log_debug("updates are over, cleaning up trees now"); 282290931Srodrigc 283290931Srodrigc if (main_create_user_groups(env) == -1) { 284290931Srodrigc main_trash_update(env); 285290931Srodrigc return; 286290931Srodrigc } 287290931Srodrigc 288290931Srodrigc if (env->sc_user_names == NULL) { 289290931Srodrigc env->sc_user_names = env->sc_user_names_t; 290290931Srodrigc env->sc_user_lines = NULL; 291290931Srodrigc env->sc_user_names_t = NULL; 292290931Srodrigc 293290931Srodrigc env->sc_group_names = env->sc_group_names_t; 294290931Srodrigc env->sc_group_lines = NULL; 295290931Srodrigc env->sc_group_names_t = NULL; 296290931Srodrigc 297290931Srodrigc flatten_entries(env); 298290931Srodrigc goto make_uids; 299290931Srodrigc } 300290931Srodrigc 301290931Srodrigc /* 302290931Srodrigc * clean previous tree. 303290931Srodrigc */ 304290931Srodrigc while ((ue = RB_ROOT(env->sc_user_names)) != NULL) { 305290931Srodrigc RB_REMOVE(user_name_tree, env->sc_user_names, 306290931Srodrigc ue); 307290931Srodrigc free(ue->ue_netid_line); 308290931Srodrigc free(ue); 309290931Srodrigc } 310290931Srodrigc free(env->sc_user_names); 311290931Srodrigc free(env->sc_user_lines); 312290931Srodrigc 313290931Srodrigc env->sc_user_names = env->sc_user_names_t; 314290931Srodrigc env->sc_user_lines = NULL; 315290931Srodrigc env->sc_user_names_t = NULL; 316290931Srodrigc 317290931Srodrigc while ((ge = RB_ROOT(env->sc_group_names)) != NULL) { 318290931Srodrigc RB_REMOVE(group_name_tree, 319290931Srodrigc env->sc_group_names, ge); 320290931Srodrigc free(ge); 321290931Srodrigc } 322290931Srodrigc free(env->sc_group_names); 323290931Srodrigc free(env->sc_group_lines); 324290931Srodrigc 325290931Srodrigc env->sc_group_names = env->sc_group_names_t; 326290931Srodrigc env->sc_group_lines = NULL; 327290931Srodrigc env->sc_group_names_t = NULL; 328290931Srodrigc 329290931Srodrigc 330290931Srodrigc flatten_entries(env); 331290931Srodrigc 332290931Srodrigc /* 333290931Srodrigc * trees are flat now. build up uid, gid and netid trees. 334290931Srodrigc */ 335290931Srodrigc 336290931Srodrigcmake_uids: 337290931Srodrigc RB_INIT(&env->sc_user_uids); 338290931Srodrigc RB_INIT(&env->sc_group_gids); 339290931Srodrigc RB_FOREACH(ue, user_name_tree, env->sc_user_names) 340290931Srodrigc RB_INSERT(user_uid_tree, 341290931Srodrigc &env->sc_user_uids, ue); 342290931Srodrigc RB_FOREACH(ge, group_name_tree, env->sc_group_names) 343290931Srodrigc RB_INSERT(group_gid_tree, 344290931Srodrigc &env->sc_group_gids, ge); 345290931Srodrigc 346290931Srodrigc} 347290931Srodrigc 348290931Srodrigcvoid 349290931Srodrigcmain_dispatch_client(int fd, short events, void *p) 350290931Srodrigc{ 351290931Srodrigc int n; 352290931Srodrigc int shut = 0; 353290931Srodrigc struct env *env = p; 354290931Srodrigc struct imsgev *iev = env->sc_iev; 355290931Srodrigc struct imsgbuf *ibuf = &iev->ibuf; 356290931Srodrigc struct idm_req ir; 357290931Srodrigc struct imsg imsg; 358290931Srodrigc 359290931Srodrigc if ((events & (EV_READ | EV_WRITE)) == 0) 360290931Srodrigc fatalx("unknown event"); 361290931Srodrigc 362290931Srodrigc if (events & EV_READ) { 363290931Srodrigc if ((n = imsg_read(ibuf)) == -1) 364290931Srodrigc fatal("imsg_read error"); 365290931Srodrigc if (n == 0) 366290931Srodrigc shut = 1; 367290931Srodrigc } 368290931Srodrigc if (events & EV_WRITE) { 369290931Srodrigc if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 370290931Srodrigc fatal("msgbuf_write"); 371290931Srodrigc if (n == 0) 372290931Srodrigc shut = 1; 373290931Srodrigc goto done; 374290931Srodrigc } 375290931Srodrigc 376290931Srodrigc for (;;) { 377290931Srodrigc if ((n = imsg_get(ibuf, &imsg)) == -1) 378290931Srodrigc fatal("main_dispatch_client: imsg_get error"); 379290931Srodrigc if (n == 0) 380290931Srodrigc break; 381290931Srodrigc 382290931Srodrigc switch (imsg.hdr.type) { 383290931Srodrigc case IMSG_START_UPDATE: 384290931Srodrigc main_start_update(env); 385290931Srodrigc break; 386290931Srodrigc case IMSG_PW_ENTRY: { 387290931Srodrigc struct userent *ue; 388290931Srodrigc size_t len; 389290931Srodrigc 390290931Srodrigc if (env->update_trashed) 391290931Srodrigc break; 392290931Srodrigc 393290931Srodrigc (void)memcpy(&ir, imsg.data, sizeof(ir)); 394290931Srodrigc if ((ue = calloc(1, sizeof(*ue))) == NULL || 395290931Srodrigc (ue->ue_line = strdup(ir.ir_line)) == NULL) { 396290931Srodrigc /* 397290931Srodrigc * should cancel tree update instead. 398290931Srodrigc */ 399290931Srodrigc fatal("out of memory"); 400290931Srodrigc } 401290931Srodrigc ue->ue_uid = ir.ir_key.ik_uid; 402290931Srodrigc len = strlen(ue->ue_line) + 1; 403290931Srodrigc ue->ue_line[strcspn(ue->ue_line, ":")] = '\0'; 404290931Srodrigc if (RB_INSERT(user_name_tree, env->sc_user_names_t, 405290931Srodrigc ue) != NULL) { /* dup */ 406290931Srodrigc free(ue->ue_line); 407290931Srodrigc free(ue); 408290931Srodrigc } else 409290931Srodrigc env->sc_user_line_len += len; 410290931Srodrigc break; 411290931Srodrigc } 412290931Srodrigc case IMSG_GRP_ENTRY: { 413290931Srodrigc struct groupent *ge; 414290931Srodrigc size_t len; 415290931Srodrigc 416290931Srodrigc if (env->update_trashed) 417290931Srodrigc break; 418290931Srodrigc 419290931Srodrigc (void)memcpy(&ir, imsg.data, sizeof(ir)); 420290931Srodrigc if ((ge = calloc(1, sizeof(*ge))) == NULL || 421290931Srodrigc (ge->ge_line = strdup(ir.ir_line)) == NULL) { 422290931Srodrigc /* 423290931Srodrigc * should cancel tree update instead. 424290931Srodrigc */ 425290931Srodrigc fatal("out of memory"); 426290931Srodrigc } 427290931Srodrigc ge->ge_gid = ir.ir_key.ik_gid; 428290931Srodrigc len = strlen(ge->ge_line) + 1; 429290931Srodrigc ge->ge_line[strcspn(ge->ge_line, ":")] = '\0'; 430290931Srodrigc if (RB_INSERT(group_name_tree, env->sc_group_names_t, 431290931Srodrigc ge) != NULL) { /* dup */ 432290931Srodrigc free(ge->ge_line); 433290931Srodrigc free(ge); 434290931Srodrigc } else 435290931Srodrigc env->sc_group_line_len += len; 436290931Srodrigc break; 437290931Srodrigc } 438290931Srodrigc case IMSG_TRASH_UPDATE: 439290931Srodrigc main_trash_update(env); 440290931Srodrigc break; 441290931Srodrigc case IMSG_END_UPDATE: { 442290931Srodrigc main_end_update(env); 443290931Srodrigc break; 444290931Srodrigc } 445290931Srodrigc default: 446290931Srodrigc log_debug("main_dispatch_client: unexpected imsg %d", 447290931Srodrigc imsg.hdr.type); 448290931Srodrigc break; 449290931Srodrigc } 450290931Srodrigc imsg_free(&imsg); 451290931Srodrigc } 452290931Srodrigc 453290931Srodrigcdone: 454290931Srodrigc if (!shut) 455290931Srodrigc imsg_event_add(iev); 456290931Srodrigc else { 457290931Srodrigc log_debug("king bula sez: ran into dead pipe"); 458290931Srodrigc event_del(&iev->ev); 459290931Srodrigc event_loopexit(NULL); 460290931Srodrigc } 461290931Srodrigc} 462290931Srodrigc 463290931Srodrigcvoid 464290931Srodrigcmain_configure_client(struct env *env) 465290931Srodrigc{ 466290931Srodrigc struct idm *idm; 467290931Srodrigc struct imsgev *iev = env->sc_iev; 468290931Srodrigc 469290931Srodrigc imsg_compose_event(iev, IMSG_CONF_START, 0, 0, -1, env, sizeof(*env)); 470290931Srodrigc TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) { 471290931Srodrigc imsg_compose_event(iev, IMSG_CONF_IDM, 0, 0, -1, 472290931Srodrigc idm, sizeof(*idm)); 473290931Srodrigc } 474290931Srodrigc imsg_compose_event(iev, IMSG_CONF_END, 0, 0, -1, NULL, 0); 475290931Srodrigc} 476290931Srodrigc 477290931Srodrigcvoid 478290931Srodrigcmain_init_timer(int fd, short event, void *p) 479290931Srodrigc{ 480290931Srodrigc struct env *env = p; 481290931Srodrigc 482290931Srodrigc main_configure_client(env); 483290931Srodrigc} 484290931Srodrigc 485290931Srodrigcvoid 486290931Srodrigcpurge_config(struct env *env) 487290931Srodrigc{ 488290931Srodrigc struct idm *idm; 489290931Srodrigc 490290931Srodrigc while ((idm = TAILQ_FIRST(&env->sc_idms)) != NULL) { 491290931Srodrigc TAILQ_REMOVE(&env->sc_idms, idm, idm_entry); 492290931Srodrigc free(idm); 493290931Srodrigc } 494290931Srodrigc} 495290931Srodrigc 496290931Srodrigcint 497290931Srodrigcmain(int argc, char *argv[]) 498290931Srodrigc{ 499290931Srodrigc int c; 500290931Srodrigc int debug; 501290931Srodrigc struct passwd *pw; 502290931Srodrigc struct env env; 503290931Srodrigc struct event ev_sigint; 504290931Srodrigc struct event ev_sigterm; 505290931Srodrigc struct event ev_sigchld; 506290931Srodrigc struct event ev_sighup; 507290931Srodrigc struct event ev_timer; 508290931Srodrigc struct timeval tv; 509290931Srodrigc 510290931Srodrigc debug = 0; 511290931Srodrigc ypldap_process = PROC_MAIN; 512290931Srodrigc 513290931Srodrigc log_init(1); 514290931Srodrigc 515290931Srodrigc while ((c = getopt(argc, argv, "dD:nf:v")) != -1) { 516290931Srodrigc switch (c) { 517290931Srodrigc case 'd': 518290931Srodrigc debug = 2; 519290931Srodrigc break; 520290931Srodrigc case 'D': 521290931Srodrigc if (cmdline_symset(optarg) < 0) 522290931Srodrigc log_warnx("could not parse macro definition %s", 523290931Srodrigc optarg); 524290931Srodrigc break; 525290931Srodrigc case 'n': 526290931Srodrigc debug = 2; 527290931Srodrigc opts |= YPLDAP_OPT_NOACTION; 528290931Srodrigc break; 529290931Srodrigc case 'f': 530290931Srodrigc conffile = optarg; 531290931Srodrigc break; 532290931Srodrigc case 'v': 533290931Srodrigc opts |= YPLDAP_OPT_VERBOSE; 534290931Srodrigc break; 535290931Srodrigc default: 536290931Srodrigc usage(); 537290931Srodrigc } 538290931Srodrigc } 539290931Srodrigc 540290931Srodrigc argc -= optind; 541290931Srodrigc argv += optind; 542290931Srodrigc 543290931Srodrigc if (argc) 544290931Srodrigc usage(); 545290931Srodrigc 546290931Srodrigc RB_INIT(&env.sc_user_uids); 547290931Srodrigc RB_INIT(&env.sc_group_gids); 548290931Srodrigc 549290931Srodrigc if (parse_config(&env, conffile, opts)) 550290931Srodrigc exit(1); 551290931Srodrigc if (opts & YPLDAP_OPT_NOACTION) { 552290931Srodrigc fprintf(stderr, "configuration OK\n"); 553290931Srodrigc exit(0); 554290931Srodrigc } 555290931Srodrigc 556290931Srodrigc if (geteuid()) 557290931Srodrigc errx(1, "need root privileges"); 558290931Srodrigc 559290931Srodrigc log_init(debug); 560290931Srodrigc 561290931Srodrigc if (!debug) { 562290931Srodrigc if (daemon(1, 0) == -1) 563290931Srodrigc err(1, "failed to daemonize"); 564290931Srodrigc } 565290931Srodrigc 566290931Srodrigc log_info("startup%s", (debug > 1)?" [debug mode]":""); 567290931Srodrigc 568290931Srodrigc if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, 569290931Srodrigc pipe_main2client) == -1) 570290931Srodrigc fatal("socketpair"); 571290931Srodrigc 572290931Srodrigc client_pid = ldapclient(pipe_main2client); 573290931Srodrigc 574290931Srodrigc setproctitle("parent"); 575290931Srodrigc event_init(); 576290931Srodrigc 577290931Srodrigc signal_set(&ev_sigint, SIGINT, main_sig_handler, &env); 578290931Srodrigc signal_set(&ev_sigterm, SIGTERM, main_sig_handler, &env); 579290931Srodrigc signal_set(&ev_sighup, SIGHUP, main_sig_handler, &env); 580290931Srodrigc signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, &env); 581290931Srodrigc signal_add(&ev_sigint, NULL); 582290931Srodrigc signal_add(&ev_sigterm, NULL); 583290931Srodrigc signal_add(&ev_sighup, NULL); 584290931Srodrigc signal_add(&ev_sigchld, NULL); 585290931Srodrigc 586290931Srodrigc close(pipe_main2client[1]); 587290931Srodrigc if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL) 588290931Srodrigc fatal(NULL); 589290931Srodrigc imsg_init(&env.sc_iev->ibuf, pipe_main2client[0]); 590290931Srodrigc env.sc_iev->handler = main_dispatch_client; 591290931Srodrigc 592290931Srodrigc env.sc_iev->events = EV_READ; 593290931Srodrigc env.sc_iev->data = &env; 594290931Srodrigc event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events, 595290931Srodrigc env.sc_iev->handler, &env); 596290931Srodrigc event_add(&env.sc_iev->ev, NULL); 597290931Srodrigc 598290931Srodrigc yp_init(&env); 599290931Srodrigc 600290931Srodrigc if ((pw = getpwnam(YPLDAP_USER)) == NULL) 601290931Srodrigc fatal("getpwnam"); 602290931Srodrigc 603290931Srodrigc#ifndef DEBUG 604290931Srodrigc if (setgroups(1, &pw->pw_gid) || 605290931Srodrigc setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 606290931Srodrigc setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 607290931Srodrigc fatal("cannot drop privileges"); 608290931Srodrigc#else 609290931Srodrigc#warning disabling privilege revocation in debug mode 610290931Srodrigc#endif 611290931Srodrigc 612290931Srodrigc bzero(&tv, sizeof(tv)); 613290931Srodrigc evtimer_set(&ev_timer, main_init_timer, &env); 614290931Srodrigc evtimer_add(&ev_timer, &tv); 615290931Srodrigc 616290931Srodrigc yp_enable_events(); 617290931Srodrigc event_dispatch(); 618290931Srodrigc main_shutdown(); 619290931Srodrigc 620290931Srodrigc return (0); 621290931Srodrigc} 622290931Srodrigc 623290931Srodrigcvoid 624290931Srodrigcimsg_event_add(struct imsgev *iev) 625290931Srodrigc{ 626290931Srodrigc if (iev->handler == NULL) { 627290931Srodrigc imsg_flush(&iev->ibuf); 628290931Srodrigc return; 629290931Srodrigc } 630290931Srodrigc 631290931Srodrigc iev->events = EV_READ; 632290931Srodrigc if (iev->ibuf.w.queued) 633290931Srodrigc iev->events |= EV_WRITE; 634290931Srodrigc 635290931Srodrigc event_del(&iev->ev); 636290931Srodrigc event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 637290931Srodrigc event_add(&iev->ev, NULL); 638290931Srodrigc} 639290931Srodrigc 640290931Srodrigcint 641290931Srodrigcimsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 642290931Srodrigc pid_t pid, int fd, void *data, u_int16_t datalen) 643290931Srodrigc{ 644290931Srodrigc int ret; 645290931Srodrigc 646290931Srodrigc if ((ret = imsg_compose(&iev->ibuf, type, peerid, 647290931Srodrigc pid, fd, data, datalen)) != -1) 648290931Srodrigc imsg_event_add(iev); 649290931Srodrigc return (ret); 650290931Srodrigc} 651