Exemplo n.º 1
0
/*
 *  reparsed_doorfunc
 *
 *  argp:  "service_type:service_data" string
 *  dp & n_desc: not used.
 */
static void
reparsed_doorfunc(void *cookie, char *argp, size_t arg_size,
    door_desc_t *dp, uint_t n_desc)
{
	int err;
	size_t bufsz;
	char *svc_type, *svc_data;
	char *cp, *buf, *sbuf, res_buf[DOOR_RESULT_BUFSZ];
	reparsed_door_res_t *resp;

	if ((argp == NULL) || (arg_size == 0)) {
		reparsed_door_call_error(EINVAL, 0);
		/* NOTREACHED */
	}

	if (verbose)
		syslog(LOG_NOTICE, "reparsed_door: [%s, %d]", argp, arg_size);

	if ((svc_type = strdup(argp)) == NULL) {
		reparsed_door_call_error(ENOMEM, 0);
		/* NOTREACHED */
	}

	/*
	 * Door argument string comes in "service_type:service_data" format.
	 * Need to break it into separate "service_type" and "service_data"
	 * string before passing them to reparse_deref() to process them.
	 */
	if ((cp = strchr(svc_type, ':')) == NULL) {
		free(svc_type);
		reparsed_door_call_error(EINVAL, 0);
		/* NOTREACHED */
	}
	*cp++ = '\0';
	svc_data = cp;

	/*
	 * Setup buffer for reparse_deref(). 'bufsz' is the actual
	 * buffer size to hold the result returned by reparse_deref().
	 */
	resp = (reparsed_door_res_t *)res_buf;
	buf = resp->res_data;
	bufsz = sizeof (res_buf) - sizeof (reparsed_door_res_t);

	/*
	 * reparse_deref() calls the service type plugin library to process
	 * the service data. The plugin library function should understand
	 * the context of the service data and should be the one to XDR the
	 * results before returning it to the caller.
	 */
	err = reparse_deref(svc_type, svc_data, buf, &bufsz);

	if (verbose)
		syslog(LOG_NOTICE,
		    "reparsed_deref(svc_type: %s, data: %s, size: %d) -> %d",
		    svc_type, svc_data, bufsz, err);

	switch (err) {
	case 0:
		break;

	case EOVERFLOW:
		/*
		 * bufsz was returned with size needed by reparse_deref().
		 *
		 * We cannot use malloc() here because door_return() never
		 * returns, and memory allocated by malloc() would get leaked.
		 */
		sbuf = alloca(bufsz + sizeof (reparsed_door_res_t));
		if (sbuf == NULL || stack_inbounds(buf) == 0 ||
		    stack_inbounds(buf + sizeof (reparsed_door_res_t) +
		    SAFETY_BUFFER - 1) == 0) {
			free(svc_type);
			reparsed_door_call_error(ENOMEM, 0);
			/* NOTREACHED */
		}

		resp = (reparsed_door_res_t *)sbuf;
		if ((err = reparse_deref(svc_type, svc_data, resp->res_data,
		    &bufsz)) == 0)
			break;

		/* fall through */

	default:
		free(svc_type);
		reparsed_door_call_error(err, 0);
		/* NOTREACHED */
	}

	free(svc_type);

	if (verbose)
		syslog(LOG_NOTICE, "reparsed_door_return <buf=%s> size=%d",
		    buf, bufsz);

	resp->res_status = 0;
	resp->res_len = bufsz;
	(void) door_return((char *)resp, bufsz + sizeof (reparsed_door_res_t),
	    NULL, 0);

	(void) door_return(NULL, 0, NULL, 0);
	/* NOTREACHED */
}
Exemplo n.º 2
0
int
main(int argc, char ** argv)
{
	int			did;
	int			opt;
	int			errflg = 0;
	int			showstats = 0;
	int			doset = 0;
	int			dofg = 0;
	struct stat		buf;
	sigset_t		myset;
	struct sigaction	sighupaction;
	static void		client_killserver();
	int			debug_level = 0;

	/* setup for localization */
	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	openlog("ldap_cachemgr", LOG_PID, LOG_DAEMON);

	if (chdir(NSLDAPDIRECTORY) < 0) {
		(void) fprintf(stderr, gettext("chdir(\"%s\") failed: %s\n"),
		    NSLDAPDIRECTORY, strerror(errno));
		exit(1);
	}

	/*
	 * Correctly set file mode creation mask, so to make the new files
	 * created for door calls being readable by all.
	 */
	(void) umask(0);

	/*
	 *  Special case non-root user here -	he/she/they/it can just print
	 *					stats
	 */

	if (geteuid()) {
		if (argc != 2 || strcmp(argv[1], "-g")) {
			(void) fprintf(stderr,
			    gettext("Must be root to use any option "
			    "other than -g.\n\n"));
			usage(argv[0]);
		}

		if ((__ns_ldap_cache_ping() != SUCCESS) ||
		    (client_getadmin(&current_admin) != 0)) {
			(void) fprintf(stderr,
			    gettext("%s doesn't appear to be running.\n"),
			    argv[0]);
			exit(1);
		}
		(void) client_showstats(&current_admin);
		exit(0);
	}



	/*
	 *  Determine if there is already a daemon running
	 */

	will_become_server = (__ns_ldap_cache_ping() != SUCCESS);

	/*
	 *  load normal config file
	 */

	if (will_become_server) {
		static const ldap_stat_t defaults = {
			0,		/* stat */
			DEFAULTTTL};	/* ttl */

		current_admin.ldap_stat = defaults;
		(void) strcpy(current_admin.logfile, LOGFILE);
	} else {
		if (client_getadmin(&current_admin)) {
			(void) fprintf(stderr, gettext("Cannot contact %s "
			    "properly(?)\n"), argv[0]);
			exit(1);
		}
	}

#ifndef SLP
	while ((opt = getopt(argc, argv, "fKgl:r:d:")) != EOF) {
#else
	while ((opt = getopt(argc, argv, "fKgs:l:r:d:")) != EOF) {
#endif /* SLP */
		ldap_stat_t	*cache;

		switch (opt) {
		case 'K':
			client_killserver();
			exit(0);
			break;
		case 'g':
			showstats++;
			break;
		case 'f':
			dofg++;
			break;
		case 'r':
			doset++;
			cache = getcacheptr("ldap");
			if (!optarg) {
				errflg++;
				break;
			}
			cache->ldap_ttl = atoi(optarg);
			break;
		case 'l':
			doset++;
			(void) strlcpy(current_admin.logfile,
			    optarg, sizeof (current_admin.logfile));
			break;
		case 'd':
			doset++;
			debug_level = atoi(optarg);
			break;
#ifdef SLP
		case 's':	/* undocumented: use dynamic (SLP) config */
			use_slp = 1;
			break;
#endif /* SLP */
		default:
			errflg++;
			break;
		}
	}

	if (errflg)
		usage(argv[0]);

	/*
	 * will not show statistics if no daemon running
	 */
	if (will_become_server && showstats) {
		(void) fprintf(stderr,
		    gettext("%s doesn't appear to be running.\n"),
		    argv[0]);
		exit(1);
	}

	if (!will_become_server) {
		if (showstats) {
			(void) client_showstats(&current_admin);
		}
		if (doset) {
			current_admin.debug_level = debug_level;
			if (client_setadmin(&current_admin) < 0) {
				(void) fprintf(stderr,
				    gettext("Error during admin call\n"));
				exit(1);
			}
		}
		if (!showstats && !doset) {
			(void) fprintf(stderr,
			gettext("%s already running....use '%s "
			    "-K' to stop\n"), argv[0], argv[0]);
		}
		exit(0);
	}

	/*
	 *   daemon from here on
	 */

	if (debug_level) {
		/*
		 * we're debugging...
		 */
		if (strlen(current_admin.logfile) == 0)
			/*
			 * no specified log file
			 */
			(void) strcpy(current_admin.logfile, LOGFILE);
		else
			(void) cachemgr_set_lf(&current_admin,
			    current_admin.logfile);
		/*
		 * validate the range of debug level number
		 * and set the number to current_admin.debug_level
		 */
		if (cachemgr_set_dl(&current_admin, debug_level) < 0) {
				/*
				 * print error messages to the screen
				 * cachemgr_set_dl prints msgs to cachemgr.log
				 * only
				 */
				(void) fprintf(stderr,
				gettext("Incorrect Debug Level: %d\n"
				"It should be between %d and %d\n"),
				    debug_level, DBG_OFF, MAXDEBUG);
			exit(-1);
		}
	} else {
		if (strlen(current_admin.logfile) == 0)
			(void) strcpy(current_admin.logfile, "/dev/null");
			(void) cachemgr_set_lf(&current_admin,
			    current_admin.logfile);
	}

	if (dofg == 0)
		detachfromtty(argv[0]);

	/*
	 * perform some initialization
	 */

	initialize_lookup_clearance();

	if (getldap_init() != 0)
		exit(-1);

	/*
	 * Establish our own server thread pool
	 */

	(void) door_server_create(server_create);
	if (thr_keycreate(&server_key, server_destroy) != 0) {
		logit("thr_keycreate() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_keycreate() call failed"));
		perror("thr_keycreate");
		exit(-1);
	}

	/*
	 * Create a door
	 */

	if ((did = door_create(switcher, LDAP_CACHE_DOOR_COOKIE,
	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
		logit("door_create() call failed\n");
		syslog(LOG_ERR, gettext(
		    "ldap_cachemgr: door_create() call failed"));
		perror("door_create");
		exit(-1);
	}

	/*
	 * bind to file system
	 */

	if (stat(LDAP_CACHE_DOOR, &buf) < 0) {
		int	newfd;

		if ((newfd = creat(LDAP_CACHE_DOOR, 0444)) < 0) {
			logit("Cannot create %s:%s\n",
			    LDAP_CACHE_DOOR,
			    strerror(errno));
			exit(1);
		}
		(void) close(newfd);
	}

	if (fattach(did, LDAP_CACHE_DOOR) < 0) {
		if ((errno != EBUSY) ||
		    (fdetach(LDAP_CACHE_DOOR) <  0) ||
		    (fattach(did, LDAP_CACHE_DOOR) < 0)) {
			logit("fattach() call failed\n");
			syslog(LOG_ERR, gettext(
			    "ldap_cachemgr: fattach() call failed"));
			perror("fattach");
			exit(2);
		}
	}

	/* catch SIGHUP revalid signals */
	sighupaction.sa_handler = getldap_revalidate;
	sighupaction.sa_flags = 0;
	(void) sigemptyset(&sighupaction.sa_mask);
	(void) sigemptyset(&myset);
	(void) sigaddset(&myset, SIGHUP);

	if (sigaction(SIGHUP, &sighupaction, NULL) < 0) {
		logit("sigaction() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: sigaction() call failed"));
		perror("sigaction");
		exit(1);
	}

	if (thr_sigsetmask(SIG_BLOCK, &myset, NULL) < 0) {
		logit("thr_sigsetmask() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_sigsetmask() call failed"));
		perror("thr_sigsetmask");
		exit(1);
	}

	/*
	 *  kick off revalidate threads only if ttl != 0
	 */

	if (thr_create(NULL, NULL, (void *(*)(void*))getldap_refresh,
	    0, 0, NULL) != 0) {
		logit("thr_create() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_create() call failed"));
		perror("thr_create");
		exit(1);
	}

	/*
	 *  kick off the thread which refreshes the server info
	 */

	if (thr_create(NULL, NULL, (void *(*)(void*))getldap_serverInfo_refresh,
	    0, 0, NULL) != 0) {
		logit("thr_create() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: thr_create() call failed"));
		perror("thr_create");
		exit(1);
	}

#ifdef SLP
	if (use_slp) {
		/* kick off SLP discovery thread */
		if (thr_create(NULL, NULL, (void *(*)(void *))discover,
		    (void *)&refresh, 0, NULL) != 0) {
			logit("thr_create() call failed\n");
			syslog(LOG_ERR, gettext("ldap_cachemgr: thr_create() "
			    "call failed"));
			perror("thr_create");
			exit(1);
		}
	}
#endif /* SLP */

	if (thr_sigsetmask(SIG_UNBLOCK, &myset, NULL) < 0) {
		logit("thr_sigsetmask() call failed\n");
		syslog(LOG_ERR,
		    gettext("ldap_cachemgr: the_sigsetmask() call failed"));
		perror("thr_sigsetmask");
		exit(1);
	}

	/*CONSTCOND*/
	while (1) {
		(void) pause();
	}
	/* NOTREACHED */
	/*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
}


/*
 * Before calling the alloca() function we have to be sure that we won't get
 * beyond the stack. Since we don't know the precise layout of the stack,
 * the address of an automatic of the function gives us a rough idea, plus/minus
 * a bit. We also need a bit more of stackspace after the call to be able
 * to call further functions. Even something as simple as making a system call
 * from within this function can take ~100 Bytes of stackspace.
 */
#define	SAFETY_BUFFER 32 * 1024 /* 32KB */

static
size_t
get_data_size(LineBuf *config_info, int *err_code)
{
	size_t		configSize = sizeof (ldap_return_t);
	dataunion	*buf = NULL; /* For the 'sizeof' purpose */

	if (config_info->str != NULL &&
	    config_info->len >= sizeof (buf->data.ldap_ret.ldap_u.config)) {
		configSize = sizeof (buf->space) +
		    config_info->len -
		    sizeof (buf->data.ldap_ret.ldap_u.config);

		if (!stack_inbounds((char *)&buf -
		    (configSize + SAFETY_BUFFER))) {
			/*
			 * We do not have enough space on the stack
			 * to accomodate the whole DUAProfile
			 */
			logit("The DUAProfile is too big. There is not enough "
			    "space to process it. Ignoring it.\n");
			syslog(LOG_ERR, gettext("ldap_cachemgr: The DUAProfile "
			    "is too big. There is not enough space "
			    "to process it. Ignoring it."));

			*err_code = SERVERERROR;

			free(config_info->str);
			config_info->str = NULL;
			config_info->len = 0;
			configSize = sizeof (ldap_return_t);
		}
	}

	return (configSize);
}