root/usr/src/cmd/fs.d/autofs/ns_generic.c
/*
 * 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
 */
/*
 *      ns_generic.c
 *
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
#include <nsswitch.h>
#include <sys/param.h>
#include <netdb.h>
#include <errno.h>
#include <assert.h>
#include <rpc/rpc.h>
#include <rpcsvc/nfs_prot.h>
#include "automount.h"

/*
 * Each name service is represented by a ns_info structure.
 */
struct ns_info {
        char    *ns_name;               /* service name */
        void    (*ns_init)();           /* initialization routine */
        int     (*ns_getmapent)();      /* get map entry given key */
        int     (*ns_loadmaster)();     /* load master map */
        int     (*ns_loaddirect)();     /* load direct map */
        int     (*ns_getmapkeys)();     /* readdir */
};

static struct ns_info ns_info[] = {

        "files",   init_files,  getmapent_files,
        loadmaster_files, loaddirect_files,
        getmapkeys_files,

        "ldap",   init_ldap,  getmapent_ldap,
        loadmaster_ldap, loaddirect_ldap,
        getmapkeys_ldap,

        "nis",     init_nis,    getmapent_nis,
        loadmaster_nis,   loaddirect_nis,
        getmapkeys_nis,

        NULL, NULL, NULL, NULL, NULL, NULL, NULL
};

static struct ns_info *get_next_ns(struct __nsw_lookup **, int);

void
ns_setup(char **stack, char ***stkptr)
{
        struct ns_info *nsp;

        for (nsp = ns_info; nsp->ns_name; nsp++) {
                nsp->ns_init(stack, stkptr);
        }
}

static struct ns_info *
get_next_ns(curr_ns, curr_nserr)
        struct __nsw_lookup **curr_ns;
        int curr_nserr;
{
        static struct __nsw_switchconfig *conf = NULL;
        enum __nsw_parse_err pserr;
        struct __nsw_lookup *lkp;
        struct ns_info *nsp;

        if (conf == NULL) {
                /* __nsw_getconfig() is protected by a lock */
                conf = __nsw_getconfig("automount", &pserr);
                if (conf == NULL) {
                        return (NULL);
                }
        }

        if (*curr_ns == NULL)
                /* first time */
                lkp = conf->lookups;
        else {
                lkp = *curr_ns;
                /* __NSW_ACTION is MT-Safe */
                if (__NSW_ACTION(lkp, curr_nserr) == __NSW_RETURN)
                        return (NULL);
                lkp = lkp->next;
        }

        for (; lkp; lkp = lkp->next) {
                for (nsp = ns_info; nsp->ns_name; nsp++) {
                        if (strcmp(lkp->service_name, nsp->ns_name) == 0) {
                                *curr_ns = lkp;
                                return (nsp);
                        }
                }
                /*
                 * Note: if we get here then we've found
                 * an unsupported name service.
                 */
        }

        return (NULL);
}

int
getmapent(key, mapname, ml, stack, stkptr, iswildcard, isrestricted)
        char *key, *mapname;
        struct mapline *ml;
        char **stack, ***stkptr;
        bool_t *iswildcard;
        bool_t isrestricted;
{
        struct __nsw_lookup *curr_ns = NULL;
        int ns_err = __NSW_SUCCESS;
        struct ns_info *nsp;

        if (strcmp(mapname, "-hosts") == 0) {
                (void) strcpy(ml->linebuf, "-hosts");
                return (__NSW_SUCCESS);
        }

        if (*mapname == '/')            /* must be a file */
                return (getmapent_files(key, mapname, ml, stack, stkptr,
                                        iswildcard, isrestricted));

        while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
                ns_err = nsp->ns_getmapent(key, mapname, ml, stack, stkptr,
                                                iswildcard, isrestricted);
                if (ns_err == __NSW_SUCCESS)
                        return (__NSW_SUCCESS);
        }

        return (__NSW_UNAVAIL);
}

int
loadmaster_map(mapname, defopts, stack, stkptr)
        char *mapname, *defopts;
        char **stack, ***stkptr;
{
        struct __nsw_lookup *curr_ns = NULL;
        int ns_err = __NSW_SUCCESS;
        struct ns_info *nsp;

        if (*mapname == '/')            /* must be a file */
                return (loadmaster_files(mapname, defopts, stack, stkptr));

        while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
                ns_err = nsp->ns_loadmaster(mapname, defopts, stack, stkptr);
                if (ns_err == __NSW_SUCCESS)
                        return (__NSW_SUCCESS);
        }

        return (__NSW_UNAVAIL);
}

int
loaddirect_map(mapname, localmap, defopts, stack, stkptr)
        char *mapname, *localmap, *defopts;
        char **stack, ***stkptr;
{
        struct __nsw_lookup *curr_ns = NULL;
        int ns_err = __NSW_SUCCESS;
        struct ns_info *nsp;

        if (*mapname == '/')            /* must be a file */
                return (loaddirect_files(mapname, localmap, defopts,
                                stack, stkptr));

        while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
                ns_err = nsp->ns_loaddirect(mapname, localmap, defopts, stack,
                                        stkptr);
                if (ns_err == __NSW_SUCCESS)
                        return (__NSW_SUCCESS);
        }

        return (__NSW_UNAVAIL);
}

int
gethostkeys(mapname, list, error, cache_time)
        char *mapname;
        struct dir_entry **list;
        int *error;
        int *cache_time;
{
        char *buffer, **p;
        int bufferlen = 1000;
        struct dir_entry *last = NULL;
        struct hostent ent;

#ifdef lint
        mapname = mapname;
#endif

        *cache_time = RDDIR_CACHE_TIME * 2;
        *error = 0;
        if (trace  > 1)
                trace_prt(1, "gethostkeys called\n");

        if (sethostent(1)) {
                syslog(LOG_ERR, "gethostkeys: sethostent failed");
                *error = EIO;
                return (__NSW_UNAVAIL);
        }

        buffer = (char *)malloc(bufferlen);
        if (buffer == NULL) {
                syslog(LOG_ERR, "gethostkeys: malloc of buffer failed");
                *error = ENOMEM;
                return (__NSW_UNAVAIL);
        }

        while (gethostent_r(&ent, buffer, bufferlen, error)) {
                /*
                 * add canonical name
                 */
                if (add_dir_entry(ent.h_name, list, &last)) {
                        *error = ENOMEM;
                        goto done;
                }
                if (ent.h_aliases == NULL)
                        goto done;      /* no aliases */
                for (p = ent.h_aliases; *p != 0; p++) {
                        if (strcmp(*p, ent.h_name) != 0) {
                                /*
                                 * add alias only if different
                                 * from canonical name
                                 */
                                if (add_dir_entry(*p, list, &last)) {
                                        *error = ENOMEM;
                                        goto done;
                                }
                        }
                }
                assert(last != NULL);
        }
done:   if (*list != NULL) {
                /*
                 * list of entries found
                 */
                *error = 0;
        }
        endhostent();

        return (__NSW_SUCCESS);
}

/*
 * enumerate all entries in the map in the various name services.
 */
int
getmapkeys(mapname, list, error, cache_time, stack, stkptr, uid)
        char *mapname;
        struct dir_entry **list;
        int *error;
        int *cache_time;
        char **stack, ***stkptr;
        uid_t uid;

{
        struct __nsw_lookup *curr_ns = NULL;
        int ns_err = __NSW_SUCCESS;
        int success = 0;
        struct ns_info *nsp;

        if (*mapname == '/')            /* must be a file */
                return (getmapkeys_files(mapname, list, error, cache_time,
                                stack, stkptr));
        if (strcmp(mapname, "-hosts") == 0) {
                return (gethostkeys(mapname, list, error, cache_time));
        }

        while ((nsp = get_next_ns(&curr_ns, ns_err)) != NULL) {
                ns_err = nsp->ns_getmapkeys(mapname, list, error,
                                cache_time, stack, stkptr);
                if (*error == 0) {
                        /*
                         * return success if listing was successful
                         * for at least one name service
                         */
                        success++;
                }

                /*
                 * XXX force next name service
                 */
                if (ns_err != __NSW_UNAVAIL)
                        ns_err = __NSW_NOTFOUND;
        }
        if (success) {
                /*
                 * if succeeded at least once, return error=0
                 */
                *error = 0;
        };

        return (success ? __NSW_SUCCESS : __NSW_NOTFOUND);
}