1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdlib.h>
28 #include <strings.h>
29 #include <libintl.h>
30 
31 #include "inetd_impl.h"
32 
33 extern char **environ;
34 
35 static int
valid_env_var(const char * var,const char * instance,const char * method)36 valid_env_var(const char *var, const char *instance, const char *method)
37 {
38 	char *cp = strchr(var, '=');
39 
40 	if (cp == NULL || cp == var) {
41 		if (method == NULL)
42 			return (0);
43 		error_msg(gettext("Invalid environment variable \"%s\" for "
44 		    "method %s of instance %s.\n"), var, method, instance);
45 		return (0);
46 	} else if (strncmp(var, "SMF_", 4) == 0) {
47 		if (method == NULL)
48 			return (0);
49 		error_msg(gettext("Invalid environment variable \"%s\" for "
50 		    "method %s of instance %s; \"SMF_\" prefix is reserved.\n"),
51 		    var, method, instance);
52 		return (0);
53 	}
54 
55 	return (1);
56 }
57 
58 static char **
find_dup(const char * var,char ** env,const char * instance,const char * method)59 find_dup(const char *var, char **env, const char *instance, const char *method)
60 {
61 	char **p;
62 	char *tmp;
63 
64 	for (p = env; *p != NULL; p++) {
65 		tmp = strchr(*p, '=');
66 		assert(tmp != NULL);
67 		tmp++;
68 		if (strncmp(*p, var, tmp - *p) == 0)
69 			break;
70 	}
71 
72 	if (*p == NULL)
73 		return (NULL);
74 
75 	error_msg(gettext("Ignoring duplicate environment variable \"%s\" "
76 	    "for method %s of instance %s.\n"), *p, method, instance);
77 	return (p);
78 }
79 
80 /*
81  * Create an environment which is appropriate for spawning an SMF aware
82  * process.
83  *
84  * In order to preserve the correctness of the new environment, various
85  * checks are performed:
86  *
87  * - All SMF_ entries are ignored.  All SMF_ entries should be provided
88  *   by this function.
89  * - Duplicates in the entry are eliminated.
90  * - Malformed entries are eliminated.
91  *
92  * Detected errors are logged but not fatal, since a single bad entry
93  * should not be enough to prevent an SMF_ functional environment from
94  * being created.
95  */
96 char **
set_smf_env(struct method_context * mthd_ctxt,instance_t * instance,const char * method)97 set_smf_env(struct method_context *mthd_ctxt, instance_t *instance,
98     const char *method)
99 {
100 	char **nenv;
101 	char **p, **np;
102 	size_t nenv_size;
103 
104 	/*
105 	 * Max. of env, three SMF_ variables, and terminating NULL.
106 	 */
107 	nenv_size = mthd_ctxt->env_sz + 3 + 1;
108 
109 	if (instance->config->basic->inherit_env) {
110 		for (p = environ; *p != NULL; p++)
111 			nenv_size++;
112 	}
113 
114 	nenv = malloc(sizeof (char *) * nenv_size);
115 	if (nenv == NULL)
116 		return (NULL);
117 	(void) memset(nenv, 0, sizeof (char *) * nenv_size);
118 
119 	np = nenv;
120 
121 	*np = uu_msprintf("SMF_RESTARTER=%s", INETD_INSTANCE_FMRI);
122 	if (*np == NULL)
123 		goto fail;
124 	else
125 		np++;
126 	*np = uu_msprintf("SMF_FMRI=%s", instance->fmri);
127 	if (*np == NULL)
128 		goto fail;
129 	else
130 		np++;
131 	*np = uu_msprintf("SMF_METHOD=%s", method);
132 	if (*np == NULL)
133 		goto fail;
134 	else
135 		np++;
136 
137 	if (instance->config->basic->inherit_env) {
138 		for (p = environ; *p != NULL; p++) {
139 			if (!valid_env_var(*p, NULL, NULL))
140 				continue;
141 
142 			*np = strdup(*p);
143 			if (*np == NULL)
144 				goto fail;
145 			else
146 				np++;
147 		}
148 	}
149 
150 	if (mthd_ctxt->env != NULL) {
151 		for (p = mthd_ctxt->env; *p != NULL; p++) {
152 			char **dup_pos;
153 
154 			if (!valid_env_var(*p, instance->fmri, method))
155 				continue;
156 
157 			if ((dup_pos = find_dup(*p, nenv, instance->fmri,
158 			    method)) != NULL) {
159 				free(*dup_pos);
160 				*dup_pos = strdup(*p);
161 				if (*dup_pos == NULL)
162 					goto fail;
163 			} else {
164 				*np = strdup(*p);
165 				if (*np == NULL)
166 					goto fail;
167 				else
168 					np++;
169 			}
170 		}
171 	}
172 	*np = NULL;
173 
174 	return (nenv);
175 fail:
176 	p = nenv;
177 	while (nenv_size--)
178 		free(*p++);
179 	free(nenv);
180 	return (NULL);
181 }
182