2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <sys/types.h>
2N/A#include <exec_attr.h>
2N/A#include <secdb.h>
2N/A#include <rpcsvc/ypclnt.h>
2N/A#include <rpcsvc/yp_prot.h>
2N/A#include "nis_common.h"
2N/A
2N/A
2N/A/* extern from nis_common.c */
2N/Aextern void massage_netdb(const char **, int *);
2N/A/* externs from libc */
2N/Aextern int _doexeclist(nss_XbyY_args_t *);
2N/Aextern char *_exec_wild_id(char *, const char *);
2N/Aextern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *);
2N/A
2N/Atypedef struct __exec_nis_args {
2N/A int *yp_status;
2N/A nss_XbyY_args_t *argp;
2N/A} _exec_nis_args;
2N/A
2N/A
2N/A/*
2N/A * check_match: returns 1 if - matching entry found and no more entries needed,
2N/A * or, entry cannot be found because of error;
2N/A * returns 0 if - no matching entry found, or,
2N/A * matching entry found and next match needed.
2N/A */
2N/Astatic int
2N/Acheck_match(nss_XbyY_args_t *argp, int check_policy)
2N/A{
2N/A execstr_t *exec = (execstr_t *)(argp->returnval);
2N/A _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
2N/A const char *name = _priv_exec->name;
2N/A const char *type = _priv_exec->type;
2N/A const char *id = _priv_exec->id;
2N/A const char *policy = _priv_exec->policy;
2N/A
2N/A if (name && id) {
2N/A /*
2N/A * NSS_DBOP_EXECATTR_BYNAMEID searched for name and id in
2N/A * _exec_nis_lookup already.
2N/A * If we're talking to pre-Solaris9 nis servers, check policy,
2N/A * as policy was not a searchable column then.
2N/A */
2N/A if ((check_policy && policy &&
2N/A (strcmp(policy, exec->policy) != 0)) ||
2N/A (type && (strcmp(type, exec->type) != 0))) {
2N/A return (0);
2N/A }
2N/A } else if ((policy && exec->policy &&
2N/A (strcmp(policy, exec->policy) != 0)) ||
2N/A (name && exec->name && (strcmp(name, exec->name) != 0)) ||
2N/A (type && exec->type && (strcmp(type, exec->type) != 0)) ||
2N/A (id && exec->id && (strcmp(id, exec->id) != 0))) {
2N/A return (0);
2N/A }
2N/A
2N/A return (1);
2N/A}
2N/A
2N/A/*
2N/A * check_match_strbuf: set up the data needed by check_match()
2N/A * and call it to match exec_attr data in strbuf and argp->key.attrp
2N/A */
2N/Astatic int
2N/Acheck_match_strbuf(nss_XbyY_args_t *argp, char *strbuf, int check_policy)
2N/A{
2N/A char *last = NULL;
2N/A char *sep = KV_TOKEN_DELIMIT;
2N/A execstr_t exec;
2N/A execstr_t *execp = &exec;
2N/A void *sp;
2N/A int rc;
2N/A
2N/A /*
2N/A * Remove newline that yp_match puts at the
2N/A * end of the entry it retrieves from the map.
2N/A */
2N/A if (strbuf[argp->returnlen] == '\n') {
2N/A strbuf[argp->returnlen] = '\0';
2N/A }
2N/A
2N/A execp->name = _strtok_escape(strbuf, sep, &last);
2N/A execp->policy = _strtok_escape(NULL, sep, &last);
2N/A execp->type = _strtok_escape(NULL, sep, &last);
2N/A execp->res1 = _strtok_escape(NULL, sep, &last);
2N/A execp->res2 = _strtok_escape(NULL, sep, &last);
2N/A execp->id = _strtok_escape(NULL, sep, &last);
2N/A
2N/A sp = argp->returnval;
2N/A argp->returnval = execp;
2N/A rc = check_match(argp, check_policy);
2N/A argp->returnval = sp;
2N/A free(strbuf);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/Astatic nss_status_t
2N/A_exec_nis_parse(const char *instr,
2N/A int instr_len,
2N/A nss_XbyY_args_t *argp,
2N/A int check_policy)
2N/A{
2N/A int parse_stat;
2N/A nss_status_t res;
2N/A _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
2N/A char *strbuf;
2N/A int check_matched;
2N/A
2N/A argp->returnval = NULL;
2N/A argp->returnlen = 0;
2N/A parse_stat = (*argp->str2ent)(instr, instr_len, argp->buf.result,
2N/A argp->buf.buffer, argp->buf.buflen);
2N/A switch (parse_stat) {
2N/A case NSS_STR_PARSE_SUCCESS:
2N/A argp->returnlen = instr_len;
2N/A /* if exec_attr file format requested */
2N/A if (argp->buf.result == NULL) {
2N/A argp->returnval = argp->buf.buffer;
2N/A if ((strbuf = strdup(instr)) == NULL)
2N/A res = NSS_UNAVAIL;
2N/A check_matched = check_match_strbuf(argp,
2N/A strbuf, check_policy);
2N/A } else {
2N/A argp->returnval = argp->buf.result;
2N/A check_matched = check_match(argp, check_policy);
2N/A }
2N/A if (check_matched) {
2N/A res = NSS_SUCCESS;
2N/A if (IS_GET_ALL(_priv_exec->search_flag)) {
2N/A if (_doexeclist(argp) == 0) {
2N/A res = NSS_UNAVAIL;
2N/A }
2N/A }
2N/A } else {
2N/A res = NSS_NOTFOUND;
2N/A }
2N/A break;
2N/A case NSS_STR_PARSE_ERANGE:
2N/A argp->erange = 1;
2N/A res = NSS_NOTFOUND;
2N/A break;
2N/A default:
2N/A res = NSS_UNAVAIL;
2N/A break;
2N/A }
2N/A
2N/A return (res);
2N/A}
2N/A
2N/A/*
2N/A * This is the callback for yp_all. It returns 0 to indicate that it wants to
2N/A * be called again for further key-value pairs, or returns non-zero to stop the
2N/A * flow of key-value pairs. If it returns a non-zero value, it is not called
2N/A * again. The functional value of yp_all is then 0.
2N/A */
2N/A/*ARGSUSED*/
2N/Astatic int
2N/A_exec_nis_cb(int instatus,
2N/A char *inkey,
2N/A int inkeylen,
2N/A char *inval,
2N/A int invallen,
2N/A void *indata)
2N/A{
2N/A int check_policy = 1; /* always check policy for yp_all */
2N/A int stop_cb;
2N/A const char *filter;
2N/A nss_status_t res;
2N/A _exec_nis_args *eargp = (_exec_nis_args *)indata;
2N/A nss_XbyY_args_t *argp = eargp->argp;
2N/A _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
2N/A
2N/A if (instatus != YP_TRUE) {
2N/A /*
2N/A * If we have no more data to look at, we want to
2N/A * keep yp_status from previous key/value pair
2N/A * that we processed.
2N/A * If this is the 1st time we enter this callback,
2N/A * yp_status is already set to YPERR_YPERR
2N/A * (see _exec_nis_lookup() for when this callback
2N/A * and arguments are set initially).
2N/A */
2N/A if (instatus != YP_NOMORE) {
2N/A *(eargp->yp_status) = YPERR_YPERR;
2N/A }
2N/A return (0); /* yp_all may decide otherwise... */
2N/A }
2N/A
2N/A filter = (_priv_exec->name) ? _priv_exec->name : _priv_exec->id;
2N/A
2N/A /*
2N/A * yp_all does not null terminate the entry it retrieves from the
2N/A * map, unlike yp_match. so we do it explicitly here.
2N/A */
2N/A inval[invallen] = '\0';
2N/A
2N/A /*
2N/A * Optimization: if the entry doesn't contain the filter string then
2N/A * it can't be the entry we want, so don't bother looking more closely
2N/A * at it.
2N/A */
2N/A if ((_priv_exec->policy &&
2N/A (strstr(inval, _priv_exec->policy) == NULL)) ||
2N/A (strstr(inval, filter) == NULL)) {
2N/A *(eargp->yp_status) = YPERR_KEY;
2N/A return (0);
2N/A }
2N/A
2N/A res = _exec_nis_parse(inval, invallen, argp, check_policy);
2N/A
2N/A switch (res) {
2N/A case NSS_SUCCESS:
2N/A *(eargp->yp_status) = 0;
2N/A stop_cb = IS_GET_ONE(_priv_exec->search_flag);
2N/A break;
2N/A case NSS_UNAVAIL:
2N/A *(eargp->yp_status) = YPERR_KEY;
2N/A stop_cb = 1;
2N/A break;
2N/A default:
2N/A *(eargp->yp_status) = YPERR_YPERR;
2N/A stop_cb = 0;
2N/A break;
2N/A }
2N/A
2N/A return (stop_cb);
2N/A}
2N/A
2N/Astatic nss_status_t
2N/A_exec_nis_lookup(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
2N/A{
2N/A int ypstatus;
2N/A nss_status_t res = NSS_SUCCESS;
2N/A nss_status_t ypres;
2N/A _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
2N/A
2N/A if (getby_flag == NSS_DBOP_EXECATTR_BYNAMEID) {
2N/A int check_policy = 0;
2N/A int vallen;
2N/A char *val;
2N/A char key[MAX_INPUT];
2N/A
2N/A /*
2N/A * Try using policy as part of search key. If that fails,
2N/A * (it will, in case of pre-Solaris9 nis server where policy
2N/A * was not searchable), try again without using policy.
2N/A */
2N/A if (snprintf(key, MAX_INPUT, "%s%s%s%s%s", _priv_exec->name,
2N/A KV_TOKEN_DELIMIT, _priv_exec->policy, KV_TOKEN_DELIMIT,
2N/A _priv_exec->id) >= MAX_INPUT)
2N/A return (NSS_NOTFOUND);
2N/A do {
2N/A ypres = _nss_nis_ypmatch(be->domain, NIS_MAP_EXECATTR,
2N/A key, &val, &vallen, &ypstatus);
2N/A if ((check_policy == 0) && (ypstatus == YPERR_KEY)) {
2N/A (void) snprintf(key, MAX_INPUT, "%s%s%s",
2N/A _priv_exec->name, KV_TOKEN_DELIMIT,
2N/A _priv_exec->id);
2N/A check_policy = 1;
2N/A continue;
2N/A } else if (ypres != NSS_SUCCESS) {
2N/A res = ypres;
2N/A break;
2N/A } else {
2N/A char *val_save = val;
2N/A
2N/A massage_netdb((const char **)&val, &vallen);
2N/A res = _exec_nis_parse((const char *)val,
2N/A vallen, argp, check_policy);
2N/A free(val_save);
2N/A break;
2N/A }
2N/A } while (res == NSS_SUCCESS);
2N/A } else {
2N/A int ypstat = YPERR_YPERR;
2N/A struct ypall_callback cback;
2N/A _exec_nis_args eargs;
2N/A
2N/A eargs.yp_status = &ypstat;
2N/A eargs.argp = argp;
2N/A
2N/A cback.foreach = _exec_nis_cb;
2N/A cback.data = (void *)&eargs;
2N/A
2N/A /*
2N/A * Instead of calling yp_all() doing hard lookup, we use
2N/A * the alternative function, __yp_all_cflookup(), to
2N/A * perform soft lookup when binding to nis servers with
2N/A * time-out control. Other than that, these two functions
2N/A * do exactly the same thing.
2N/A */
2N/A ypstatus = __yp_all_cflookup((char *)(be->domain),
2N/A (char *)(be->enum_map), &cback, 0);
2N/A
2N/A /*
2N/A * For GET_ALL, check if we found anything at all.
2N/A */
2N/A if (_priv_exec->head_exec != NULL)
2N/A return (NSS_SUCCESS);
2N/A
2N/A switch (ypstat) {
2N/A case 0:
2N/A res = NSS_SUCCESS;
2N/A break;
2N/A case YPERR_BUSY:
2N/A res = NSS_TRYAGAIN;
2N/A break;
2N/A case YPERR_KEY:
2N/A /*
2N/A * If no such key, return NSS_NOTFOUND
2N/A * as this looks more relevant; it will
2N/A * also help libnsl to try with another
2N/A * policy (see _getexecprof()).
2N/A */
2N/A res = NSS_NOTFOUND;
2N/A break;
2N/A default:
2N/A res = NSS_UNAVAIL;
2N/A break;
2N/A }
2N/A
2N/A }
2N/A
2N/A return (res);
2N/A}
2N/A
2N/A/*
2N/A * If search for exact match for id failed, get_wild checks if we have
2N/A * a wild-card entry for that id.
2N/A */
2N/Astatic nss_status_t
2N/Aget_wild(nis_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag)
2N/A{
2N/A const char *orig_id;
2N/A char *old_id = NULL;
2N/A char *wild_id = NULL;
2N/A nss_status_t res = NSS_NOTFOUND;
2N/A _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
2N/A
2N/A orig_id = _priv_exec->id;
2N/A old_id = strdup(_priv_exec->id);
2N/A wild_id = old_id;
2N/A while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) {
2N/A _priv_exec->id = wild_id;
2N/A res = _exec_nis_lookup(be, argp, getby_flag);
2N/A if (res == NSS_SUCCESS)
2N/A break;
2N/A }
2N/A _priv_exec->id = orig_id;
2N/A if (old_id)
2N/A free(old_id);
2N/A
2N/A return (res);
2N/A}
2N/A
2N/A
2N/Astatic nss_status_t
2N/Agetbynam(nis_backend_ptr_t be, void *a)
2N/A{
2N/A nss_status_t res;
2N/A nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
2N/A
2N/A res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAME);
2N/A
2N/A _exec_cleanup(res, argp);
2N/A
2N/A return (res);
2N/A}
2N/A
2N/Astatic nss_status_t
2N/Agetbyid(nis_backend_ptr_t be, void *a)
2N/A{
2N/A nss_status_t res;
2N/A nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
2N/A /*LINTED*/
2N/A _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
2N/A
2N/A res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYID);
2N/A
2N/A if (res != NSS_SUCCESS)
2N/A res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID);
2N/A
2N/A _exec_cleanup(res, argp);
2N/A
2N/A return (res);
2N/A}
2N/A
2N/A
2N/Astatic nss_status_t
2N/Agetbynameid(nis_backend_ptr_t be, void *a)
2N/A{
2N/A nss_status_t res;
2N/A nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a;
2N/A /*LINTED*/
2N/A _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp);
2N/A
2N/A res = _exec_nis_lookup(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
2N/A
2N/A if (res != NSS_SUCCESS)
2N/A res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID);
2N/A
2N/A _exec_cleanup(res, argp);
2N/A
2N/A return (res);
2N/A}
2N/A
2N/A
2N/Astatic nis_backend_op_t execattr_ops[] = {
2N/A _nss_nis_destr,
2N/A _nss_nis_endent,
2N/A _nss_nis_setent,
2N/A _nss_nis_getent_netdb,
2N/A getbynam,
2N/A getbyid,
2N/A getbynameid
2N/A};
2N/A
2N/A/*ARGSUSED*/
2N/Anss_backend_t *
2N/A_nss_nis_exec_attr_constr(const char *dummy1,
2N/A const char *dummy2,
2N/A const char *dummy3,
2N/A const char *dummy4,
2N/A const char *dummy5,
2N/A const char *dummy6,
2N/A const char *dummy7)
2N/A{
2N/A return (_nss_nis_constr(execattr_ops,
2N/A sizeof (execattr_ops)/sizeof (execattr_ops[0]),
2N/A NIS_MAP_EXECATTR));
2N/A}