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