root/usr/src/cmd/cmd-inet/usr.lib/inetd/env.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdlib.h>
#include <strings.h>
#include <libintl.h>

#include "inetd_impl.h"

extern char **environ;

static int
valid_env_var(const char *var, const char *instance, const char *method)
{
        char *cp = strchr(var, '=');

        if (cp == NULL || cp == var) {
                if (method == NULL)
                        return (0);
                error_msg(gettext("Invalid environment variable \"%s\" for "
                    "method %s of instance %s.\n"), var, method, instance);
                return (0);
        } else if (strncmp(var, "SMF_", 4) == 0) {
                if (method == NULL)
                        return (0);
                error_msg(gettext("Invalid environment variable \"%s\" for "
                    "method %s of instance %s; \"SMF_\" prefix is reserved.\n"),
                    var, method, instance);
                return (0);
        }

        return (1);
}

static char **
find_dup(const char *var, char **env, const char *instance, const char *method)
{
        char **p;
        char *tmp;

        for (p = env; *p != NULL; p++) {
                tmp = strchr(*p, '=');
                assert(tmp != NULL);
                tmp++;
                if (strncmp(*p, var, tmp - *p) == 0)
                        break;
        }

        if (*p == NULL)
                return (NULL);

        error_msg(gettext("Ignoring duplicate environment variable \"%s\" "
            "for method %s of instance %s.\n"), *p, method, instance);
        return (p);
}

/*
 * Create an environment which is appropriate for spawning an SMF aware
 * process.
 *
 * In order to preserve the correctness of the new environment, various
 * checks are performed:
 *
 * - All SMF_ entries are ignored.  All SMF_ entries should be provided
 *   by this function.
 * - Duplicates in the entry are eliminated.
 * - Malformed entries are eliminated.
 *
 * Detected errors are logged but not fatal, since a single bad entry
 * should not be enough to prevent an SMF_ functional environment from
 * being created.
 */
char **
set_smf_env(struct method_context *mthd_ctxt, instance_t *instance,
    const char *method)
{
        char **nenv;
        char **p, **np;
        size_t nenv_size;

        /*
         * Max. of env, three SMF_ variables, and terminating NULL.
         */
        nenv_size = mthd_ctxt->env_sz + 3 + 1;

        if (instance->config->basic->inherit_env) {
                for (p = environ; *p != NULL; p++)
                        nenv_size++;
        }

        nenv = malloc(sizeof (char *) * nenv_size);
        if (nenv == NULL)
                return (NULL);
        (void) memset(nenv, 0, sizeof (char *) * nenv_size);

        np = nenv;

        *np = uu_msprintf("SMF_RESTARTER=%s", INETD_INSTANCE_FMRI);
        if (*np == NULL)
                goto fail;
        else
                np++;
        *np = uu_msprintf("SMF_FMRI=%s", instance->fmri);
        if (*np == NULL)
                goto fail;
        else
                np++;
        *np = uu_msprintf("SMF_METHOD=%s", method);
        if (*np == NULL)
                goto fail;
        else
                np++;

        if (instance->config->basic->inherit_env) {
                for (p = environ; *p != NULL; p++) {
                        if (!valid_env_var(*p, NULL, NULL))
                                continue;

                        *np = strdup(*p);
                        if (*np == NULL)
                                goto fail;
                        else
                                np++;
                }
        }

        if (mthd_ctxt->env != NULL) {
                for (p = mthd_ctxt->env; *p != NULL; p++) {
                        char **dup_pos;

                        if (!valid_env_var(*p, instance->fmri, method))
                                continue;

                        if ((dup_pos = find_dup(*p, nenv, instance->fmri,
                            method)) != NULL) {
                                free(*dup_pos);
                                *dup_pos = strdup(*p);
                                if (*dup_pos == NULL)
                                        goto fail;
                        } else {
                                *np = strdup(*p);
                                if (*np == NULL)
                                        goto fail;
                                else
                                        np++;
                        }
                }
        }
        *np = NULL;

        return (nenv);
fail:
        p = nenv;
        while (nenv_size--)
                free(*p++);
        free(nenv);
        return (NULL);
}