view usr/src/lib/nsswitch/nisplus/common/getexecattr.c @ 10020:ff5f2b3729b6

6848927 sulogin accepts empty username 6446994 'profiles -l' doesn't list all commands if profile has both solaris and suser policies
author Joep Vesseur <Joep.Vesseur@Sun.COM>
date Thu, 02 Jul 2009 15:13:49 +0200
parents a38e922f22b0
children
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <exec_attr.h>
#include "nisplus_common.h"
#include "nisplus_tables.h"


extern nis_result *__nis_list_localcb(nis_name, uint_t, int (*) (), void *);
/* externs from libnsl */
extern int _doexeclist(nss_XbyY_args_t *);
extern char *_exec_wild_id(char *, const char *);
extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *);


#define	POLICY_LEN	128


typedef struct __exec_nisplus_args {
	int			check_policy;
	nss_status_t		*resp;
	nss_XbyY_args_t		*argp;
	nisplus_backend_t	*be;
} _exec_nisplus_args;


#ifdef	DEBUG
static void
_print_execstr(execstr_t *exec)
{

	(void) fprintf(stdout, "      exec-name: [%s]\n", exec->name);
	if (exec->policy != (char *)NULL) {
		(void) fprintf(stdout, "      policy: [%s]\n", exec->policy);
	}
	if (exec->type != (char *)NULL) {
		(void) fprintf(stdout, "      type: [%s]\n", exec->type);
	}
	if (exec->res1 != (char *)NULL) {
		(void) fprintf(stdout, "      res1: [%s]\n", exec->res1);
	}
	if (exec->res2 != (char *)NULL) {
		(void) fprintf(stdout, "      res2: [%s]\n", exec->res2);
	}
	if (exec->id != (char *)NULL) {
		(void) fprintf(stdout, "      id: [%s]\n", exec->id);
	}
	if (exec->attr != (char *)NULL) {
		(void) fprintf(stdout, "      attr: [%s]\n", exec->attr);
	}
	if (exec->next != (execstr_t *)NULL) {
		(void) fprintf(stdout, "      next: [%s]\n", exec->next->name);
		(void) fprintf(stdout, "\n");
		_print_execstr(exec->next);
	}
}
#endif	/* DEBUG */


static nss_status_t
_exec_process_val(_exec_nisplus_args * eargp, nis_object * obj)
{
	int			parsestat;
	nss_XbyY_args_t		*argp = eargp->argp;
	nisplus_backend_t	*be = eargp->be;
	_priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);

#ifdef	DEBUG
	(void) fprintf(stdout, "\n[getexecattr.c: _exec_process_val]\n");
#endif	/* DEBUG */

	/* passing one obj */
	parsestat = (be->obj2str) (1, obj, be, argp);
	if (parsestat != NSS_STR_PARSE_SUCCESS)
		goto fail;

	/*
	 * If caller is nscd's switch engine, the data
	 * will be in argp->buf.buffer. nscd does not
	 * support GET_ALL at this time so return
	 * success from here.
	 */
	if (argp->buf.result == NULL && be->buffer == NULL) {
		argp->returnval = argp->buf.buffer;
		if (argp->buf.buffer != NULL)
			argp->returnlen = strlen(argp->buf.buffer);
		return (NSS_SUCCESS);
	}

	/*
	 * If the data is in be->buffer it needs
	 * to be marshalled.
	 */
	if (argp->str2ent == NULL) {
		parsestat = NSS_STR_PARSE_PARSE;
		goto fail;
	}
	parsestat = (*argp->str2ent)(be->buffer, be->buflen, argp->buf.result,
	    argp->buf.buffer, argp->buf.buflen);
	if (parsestat == NSS_STR_PARSE_SUCCESS) {
		if (be->buffer != NULL) {
			free(be->buffer);
			be->buffer = NULL;
			be->buflen = 0;
		}
		argp->returnval = argp->buf.result;
		if (argp->buf.result != NULL)
			argp->returnlen = 1;
		else if (argp->buf.buffer != NULL) {
			argp->returnval = argp->buf.buffer;
			argp->returnlen = strlen(argp->buf.buffer);
		}
		if (IS_GET_ALL(_priv_exec->search_flag))
			if (_doexeclist(argp) == 0)
				return (NSS_UNAVAIL);
		return (NSS_SUCCESS);
	}

fail:
	if (be->buffer != NULL) {
		free(be->buffer);
		be->buffer = NULL;
		be->buflen = 0;
	}
	if (parsestat == NSS_STR_PARSE_ERANGE) {
		argp->erange = 1;
		/* We won't find this otherwise, anyway */
		return (NSS_NOTFOUND);
	} else if (parsestat == NSS_STR_PARSE_PARSE) {
		return (NSS_NOTFOUND);
	}
	return (NSS_UNAVAIL);
}


/*
 * check_match: returns 1 if -  matching entry found and no more entries needed,
 *				entry cannot be found because of error;
 *		returns 0 if -  no matching entry found,
 *				matching entry found and next match needed.
 */
/*ARGSUSED*/
static int
check_match(nis_name table, nis_object * obj, void *eargs)
{
	int			len, status = 0;
	char			*val;
	struct entry_col	*ecol;
	nss_status_t		res;
	_exec_nisplus_args	*eargp = (_exec_nisplus_args *)eargs;
	nss_XbyY_args_t		*argp = eargp->argp;
	_priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
	const char		*type = _priv_exec->type;
	const char		*policy = _priv_exec->policy;

#ifdef	DEBUG
	(void) fprintf(stdout, "\n[getexecattr.c: check_match]\n");
#endif	/* DEBUG */

	if (obj->zo_data.zo_type != NIS_ENTRY_OBJ ||
	    obj->EN_data.en_cols.en_cols_len < EXECATTR_COL) {
		/*
		 * found one bad entry. try the next one.
		 */
		return (0);
	}
	ecol = obj->EN_data.en_cols.en_cols_val;

	/*
	 * NSS_DBOP_EXECATTR_BYNAME searched for name, NSS_DBOP_EXECATTR_BYID
	 * searched for id and NSS_DBOP_EXECATTR_BYNAMEID searched for name
	 * and id in _exec_nisplus_lookup already.
	 * If we're talking to pre-Solaris9 nisplus servers, check policy,
	 * as policy was not a searchable column then.
	 */
	if (policy && eargp->check_policy) {
		/*
		 * check policy; it was not a searchable column in old servers.
		 */
		EC_SET(ecol, EXECATTR_NDX_POLICY, len, val);
		if ((len == 0) || (strcmp(val, policy) != 0)) {
			return (0);
		}
	}

	if (type) {
		/*
		 * check type
		 */
		EC_SET(ecol, EXECATTR_NDX_TYPE, len, val);
		if ((len == 0) || (strcmp(val, type) != 0)) {
			return (0);
		}
	}

	res = _exec_process_val(eargp, obj);

	*(eargp->resp) = res;
	switch (res) {
	case NSS_SUCCESS:
		status = IS_GET_ONE(_priv_exec->search_flag);
		break;
	case NSS_UNAVAIL:
		status = 1;
		break;
	default:
		status = 0;
		break;
	}

	return (status);
}


static nss_status_t
_exec_nisplus_lookup(nisplus_backend_t *be,
    nss_XbyY_args_t *argp,
    int getby_flag)
{
	char			key[MAX_INPUT];
	char			policy_key[POLICY_LEN];
	const char		*column1, *key1, *column2, *key2;
	nis_result		*r = NULL;
	nss_status_t		res = NSS_NOTFOUND;
	_exec_nisplus_args	eargs;
	_priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);

	eargs.check_policy = 0;
	eargs.argp = argp;
	eargs.be = be;
	eargs.resp = &res;

#ifdef	DEBUG
	(void) fprintf(stdout, "\n[getexecattr.c: _exec_nisplus_lookup]\n");
#endif	/* DEBUG */

	switch (getby_flag) {
	case NSS_DBOP_EXECATTR_BYNAME:
		column1 = EXECATTR_TAG_NAME;
		key1 = _priv_exec->name;
		column2 = key2 = NULL;
		break;
	case NSS_DBOP_EXECATTR_BYID:
		column1 = EXECATTR_TAG_ID;
		key1 = _priv_exec->id;
		column2 = key2 = NULL;
		break;
	case NSS_DBOP_EXECATTR_BYNAMEID:
		column1 = EXECATTR_TAG_NAME;
		key1 = _priv_exec->name;
		column2 = EXECATTR_TAG_ID;
		key2 = _priv_exec->id;
		break;
	default:
		return (NSS_NOTFOUND);
	}

	if (snprintf(policy_key, POLICY_LEN, "%s=%s", EXECATTR_TAG_POLICY,
	    _priv_exec->policy) >= POLICY_LEN)
		return (NSS_NOTFOUND);

	/*
	 * Try using policy as part of search key. If that fails,
	 * (it will, in case of pre-Solaris9 nis server where policy
	 * was not searchable), try again without using policy.
	 */
	if (((column2 == NULL) && (snprintf(key, MAX_INPUT, "[%s=%s,%s]%s",
	    column1, key1, policy_key, be->table_name) >= MAX_INPUT)) ||
	    ((column2 != NULL) &&
	    (snprintf(key, MAX_INPUT, "[%s=%s,%s,%s=%s]%s",
	    column1, key1, policy_key, column2, key2,
	    be->table_name) >= MAX_INPUT)))
		return (NSS_NOTFOUND);

	do {
		r = __nis_list_localcb(key, NIS_LIST_COMMON, check_match,
		    (void *)&eargs);
		if ((eargs.check_policy == 0) &&
		    (r != NULL) && (r->status == NIS_BADATTRIBUTE)) {
			nis_freeresult(r);
			if (column2 == NULL)
				(void) snprintf(key, MAX_INPUT, "[%s=%s]%s",
				    column1, key1, be->table_name);
			else
				(void) snprintf(key, MAX_INPUT,
				    "[%s=%s,%s=%s]%s", column1, key1, column2,
				    key2, be->table_name);
			eargs.check_policy = 1;
		} else {
			if (r != NULL)
				nis_freeresult(r);
			key[0] = '\0';
			break;
		}
	} while (key[0]);


	return (res);
}


/*
 * If search for exact match for id failed, get_wild checks if we have
 * a wild-card entry for that id.
 */
static nss_status_t
get_wild(nisplus_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
{
	const char	*orig_id = NULL;
	char		*old_id = NULL;
	char		*wild_id = NULL;
	nss_status_t	res = NSS_NOTFOUND;
	_priv_execattr	*_priv_exec = (_priv_execattr *)(argp->key.attrp);

	orig_id = _priv_exec->id;
	old_id = strdup(_priv_exec->id);
	wild_id = old_id;
	while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) {
		_priv_exec->id = wild_id;
		res = _exec_nisplus_lookup(be, argp, getby_flag);
		if (res == NSS_SUCCESS)
			break;
	}
	_priv_exec->id = orig_id;
	if (old_id)
		free(old_id);

	return (res);
}


static nss_status_t
getbynam(nisplus_backend_ptr_t be, void *a)
{
	nss_status_t	res;
	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;

#ifdef	DEBUG
	(void) fprintf(stdout, "\n[getexecattr.c: getbyname]\n");
#endif	/* DEBUG */

	res = _exec_nisplus_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAME);

	_exec_cleanup(res, argp);

	return (res);
}


static nss_status_t
getbyid(nisplus_backend_ptr_t be, void *a)
{
	nss_status_t	res;
	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;

#ifdef	DEBUG
	(void) fprintf(stdout, "\n[getexecattr.c: getbyid]\n");
#endif	/* DEBUG */

	res = _exec_nisplus_lookup(be, argp, NSS_DBOP_EXECATTR_BYID);

	if (res != NSS_SUCCESS)
		res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID);

	_exec_cleanup(res, argp);

	return (res);
}


static nss_status_t
getbynameid(nisplus_backend_ptr_t be, void *a)
{
	nss_status_t	res;
	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;

#ifdef	DEBUG
	(void) fprintf(stdout, "\n[getexecattr.c: getbynameid]\n");
#endif	/* DEBUG */

	res = _exec_nisplus_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);

	if (res != NSS_SUCCESS)
		res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);

	_exec_cleanup(res, argp);

	return (res);
}


/*
 * Returns NSS_STR_PARSE_{SUCCESS, ERANGE, PARSE}
 */
/*ARGSUSED*/
static int
nis_object2execstr(int nobj, nis_object *obj,
		nisplus_backend_ptr_t be,
		nss_XbyY_args_t *argp)
{
	char			*buffer, *name, *type, *policy;
	char			*res1, *res2, *id, *attr;
	int			buflen, namelen, typelen, policylen;
	int			res1len, res2len, idlen, attrlen;
	struct entry_col	*ecol;

	/*
	 * If we got more than one nis_object, we just ignore object(s) except
	 * the first. Although it should never have happened.
	 *
	 * ASSUMPTION: All the columns in the NIS+ tables are null terminated.
	 */
	if (obj->zo_data.zo_type != ENTRY_OBJ ||
	    obj->EN_data.en_cols.en_cols_len < EXECATTR_COL) {
		/* namespace/table/object is curdled */
		return (NSS_STR_PARSE_PARSE);
	}
	ecol = obj->EN_data.en_cols.en_cols_val;

	/* profile name */
	__NISPLUS_GETCOL_OR_RETURN(ecol, EXECATTR_NDX_NAME, namelen, name);

	/* exec type */
	__NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_TYPE, typelen, type);

	/* policy */
	__NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_POLICY, policylen, policy);

	/* reserved field 1 */
	__NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_RES1, res1len, res1);

	/* reserved field 2 */
	__NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_RES2, res2len, res2);

	/* unique id */
	__NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_ID, idlen, id);

	/* key-value pairs of attributes */
	__NISPLUS_GETCOL_OR_EMPTY(ecol, EXECATTR_NDX_ATTR, attrlen, attr);

	buflen = namelen + policylen + typelen + res1len + res2len +
	    idlen + attrlen + 7;
	if (argp->buf.result != NULL) {
		if ((be->buffer = calloc(1, buflen)) == NULL)
			return (NSS_STR_PARSE_PARSE);
		/* exclude trailing null from length */
		be->buflen = buflen - 1;
		buffer = be->buffer;
	} else {
		if (buflen > argp->buf.buflen)
			return (NSS_STR_PARSE_ERANGE);
		buflen = argp->buf.buflen;
		buffer = argp->buf.buffer;
		(void) memset(buffer, 0, buflen);
	}
	(void) snprintf(buffer, buflen, "%s:%s:%s:%s:%s:%s:%s",
	    name, policy, type, res1, res2, id, attr);
#ifdef DEBUG
	(void) fprintf(stdout, "execattr [%s]\n", buffer);
	(void) fflush(stdout);
#endif  /* DEBUG */
	return (NSS_STR_PARSE_SUCCESS);
}

static nisplus_backend_op_t execattr_ops[] = {
	_nss_nisplus_destr,
	_nss_nisplus_endent,
	_nss_nisplus_setent,
	_nss_nisplus_getent,
	getbynam,
	getbyid,
	getbynameid
};

/*ARGSUSED*/
nss_backend_t  *
_nss_nisplus_exec_attr_constr(const char *dummy1,
    const char *dummy2,
    const char *dummy3,
    const char *dummy4,
    const char *dummy5,
    const char *dummy6,
    const char *dummy7)
{
	return (_nss_nisplus_constr(execattr_ops,
	    sizeof (execattr_ops)/sizeof (execattr_ops[0]),
	    EXECATTR_TBLNAME, nis_object2execstr));
}