xref: /openbsd-src/usr.sbin/cron/env.c (revision 39339e78fa3cf6f5639ec222befd248e06ea5b5c)
1*39339e78Sderaadt /*	$OpenBSD: env.c,v 1.34 2022/05/21 01:21:29 deraadt Exp $	*/
2e134e629Smillert 
3df930be7Sderaadt /* Copyright 1988,1990,1993,1994 by Paul Vixie
4a5198fa1Smillert  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5f454ebdeSmillert  * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
6df930be7Sderaadt  *
7f454ebdeSmillert  * Permission to use, copy, modify, and distribute this software for any
8f454ebdeSmillert  * purpose with or without fee is hereby granted, provided that the above
9f454ebdeSmillert  * copyright notice and this permission notice appear in all copies.
10df930be7Sderaadt  *
11a5198fa1Smillert  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12a5198fa1Smillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13a5198fa1Smillert  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14a5198fa1Smillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15a5198fa1Smillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16a5198fa1Smillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17a5198fa1Smillert  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18df930be7Sderaadt  */
19df930be7Sderaadt 
20fa575ea2Smillert #include <sys/types.h>
21fa575ea2Smillert 
22fa575ea2Smillert #include <bitstring.h>		/* for structs.h */
23fa575ea2Smillert #include <ctype.h>
24fa575ea2Smillert #include <errno.h>
25fa575ea2Smillert #include <stdio.h>
26fa575ea2Smillert #include <stdlib.h>
27fa575ea2Smillert #include <string.h>
28fa575ea2Smillert #include <time.h>		/* for structs.h */
29fa575ea2Smillert 
30fa575ea2Smillert #include "macros.h"
31fa575ea2Smillert #include "structs.h"
32fa575ea2Smillert #include "funcs.h"
33fa575ea2Smillert #include "globals.h"
34df930be7Sderaadt 
35df930be7Sderaadt char **
env_init(void)36785ecd14Stedu env_init(void)
37785ecd14Stedu {
383d6ea532Smillert 	char **p = malloc(sizeof(char *));
39df930be7Sderaadt 
40f454ebdeSmillert 	if (p != NULL)
41df930be7Sderaadt 		p[0] = NULL;
42df930be7Sderaadt 	return (p);
43df930be7Sderaadt }
44df930be7Sderaadt 
45df930be7Sderaadt void
env_free(char ** envp)46785ecd14Stedu env_free(char **envp)
47785ecd14Stedu {
48df930be7Sderaadt 	char **p;
49df930be7Sderaadt 
50c95ed473Smillert 	for (p = envp; *p != NULL; p++)
51df930be7Sderaadt 		free(*p);
52df930be7Sderaadt 	free(envp);
53df930be7Sderaadt }
54df930be7Sderaadt 
55df930be7Sderaadt char **
env_copy(char ** envp)56785ecd14Stedu env_copy(char **envp)
57785ecd14Stedu {
58f454ebdeSmillert 	int count, i, save_errno;
59f454ebdeSmillert 	char **p;
60df930be7Sderaadt 
61df930be7Sderaadt 	for (count = 0; envp[count] != NULL; count++)
62e684b8a0Smillert 		continue;
63c1606dc6Smillert 	p = reallocarray(NULL, count+1, sizeof(char *));  /* 1 for the NULL */
64f454ebdeSmillert 	if (p != NULL) {
65df930be7Sderaadt 		for (i = 0; i < count; i++)
66bac4f837Smillert 			if ((p[i] = strdup(envp[i])) == NULL) {
67f454ebdeSmillert 				save_errno = errno;
68bac4f837Smillert 				while (--i >= 0)
69f454ebdeSmillert 					free(p[i]);
70bac4f837Smillert 				free(p);
71f454ebdeSmillert 				errno = save_errno;
72f454ebdeSmillert 				return (NULL);
73bac4f837Smillert 			}
74df930be7Sderaadt 		p[count] = NULL;
75f454ebdeSmillert 	}
76df930be7Sderaadt 	return (p);
77df930be7Sderaadt }
78df930be7Sderaadt 
793d6ea532Smillert static char *
env_find(char * name,char ** envp,size_t * count)803d6ea532Smillert env_find(char *name, char **envp, size_t *count)
813d6ea532Smillert {
823d6ea532Smillert 	char **ep, *p, *q;
833d6ea532Smillert 	size_t len;
843d6ea532Smillert 
853d6ea532Smillert 	/*
863d6ea532Smillert 	 * Find name in envp and return its value along with the
873d6ea532Smillert 	 * index it was found at or the length of envp if not found.
883d6ea532Smillert 	 * We treat a '=' in name as end of string for env_set().
893d6ea532Smillert 	 */
903d6ea532Smillert 	for (p = name; *p && *p != '='; p++)
913d6ea532Smillert 		continue;
923d6ea532Smillert 	len = (size_t)(p - name);
933d6ea532Smillert 	for (ep = envp; (p = *ep) != NULL; ep++) {
943d6ea532Smillert 		if ((q = strchr(p, '=')) == NULL)
953d6ea532Smillert 			continue;
963d6ea532Smillert 		if ((size_t)(q - p) == len && strncmp(p, name, len) == 0) {
973d6ea532Smillert 			p = q + 1;
983d6ea532Smillert 			break;
993d6ea532Smillert 		}
1003d6ea532Smillert 	}
1013d6ea532Smillert 	*count = (size_t)(ep - envp);
1023d6ea532Smillert 	return (p);
1033d6ea532Smillert }
1043d6ea532Smillert 
1053d6ea532Smillert char *
env_get(char * name,char ** envp)1063d6ea532Smillert env_get(char *name, char **envp)
1073d6ea532Smillert {
1083d6ea532Smillert 	size_t count;
1093d6ea532Smillert 
1103d6ea532Smillert 	return (env_find(name, envp, &count));
1113d6ea532Smillert }
1123d6ea532Smillert 
113df930be7Sderaadt char **
env_set(char ** envp,char * envstr)114785ecd14Stedu env_set(char **envp, char *envstr)
115785ecd14Stedu {
11666ca85e4Smillert 	size_t count;
1173d6ea532Smillert 	char **p, *envcopy;
118df930be7Sderaadt 
1193d6ea532Smillert 	if ((envcopy = strdup(envstr)) == NULL)
120f454ebdeSmillert 		return (NULL);
1213d6ea532Smillert 
1223d6ea532Smillert 	/* Replace existing name if found. */
1233d6ea532Smillert 	if (env_find(envstr, envp, &count) != NULL) {
1243d6ea532Smillert 		free(envp[count]);
1253d6ea532Smillert 		envp[count] = envcopy;
126df930be7Sderaadt 		return (envp);
127df930be7Sderaadt 	}
128df930be7Sderaadt 
1293d6ea532Smillert 	/* Realloc envp and append new variable. */
1303d6ea532Smillert 	p = reallocarray(envp, count + 2, sizeof(char **));
131d54c3a7cSmillert 	if (p == NULL) {
1323d6ea532Smillert 		free(envcopy);
133f454ebdeSmillert 		return (NULL);
134d54c3a7cSmillert 	}
1353d6ea532Smillert 	p[count++] = envcopy;
1363d6ea532Smillert 	p[count] = NULL;
137df930be7Sderaadt 	return (p);
138df930be7Sderaadt }
139df930be7Sderaadt 
1402c7f28f2Smillert /* The following states are used by load_env(), traversed in order: */
1412c7f28f2Smillert enum env_state {
1422c7f28f2Smillert 	NAMEI,		/* First char of NAME, may be quote */
1432c7f28f2Smillert 	NAME,		/* Subsequent chars of NAME */
1442c7f28f2Smillert 	EQ1,		/* After end of name, looking for '=' sign */
1452c7f28f2Smillert 	EQ2,		/* After '=', skipping whitespace */
1462c7f28f2Smillert 	VALUEI,		/* First char of VALUE, may be quote */
1472c7f28f2Smillert 	VALUE,		/* Subsequent chars of VALUE */
1482c7f28f2Smillert 	FINI,		/* All done, skipping trailing whitespace */
1492d2b3e00Sderaadt 	ERROR		/* Error */
1502c7f28f2Smillert };
1512c7f28f2Smillert 
152dd2fc19cStedu /* return	-1 = end of file
153df930be7Sderaadt  *		FALSE = not an env setting (file was repositioned)
154df930be7Sderaadt  *		TRUE = was an env setting
155df930be7Sderaadt  */
156df930be7Sderaadt int
load_env(char * envstr,FILE * f)157785ecd14Stedu load_env(char *envstr, FILE *f)
158785ecd14Stedu {
159df930be7Sderaadt 	long filepos;
160df930be7Sderaadt 	int fileline;
1612c7f28f2Smillert 	enum env_state state;
162d8ed82b3Sbitblt 	char name[MAX_ENVSTR], val[MAX_ENVSTR];
1632c7f28f2Smillert 	char quotechar, *c, *str;
164df930be7Sderaadt 
165df930be7Sderaadt 	filepos = ftell(f);
166df930be7Sderaadt 	fileline = LineNumber;
167df930be7Sderaadt 	skip_comments(f);
168*39339e78Sderaadt 	if (get_string(envstr, MAX_ENVSTR, f, "\n") == EOF)
169dd2fc19cStedu 		return (-1);
170df930be7Sderaadt 
1712c7f28f2Smillert 	bzero(name, sizeof name);
1722c7f28f2Smillert 	bzero(val, sizeof val);
1732c7f28f2Smillert 	str = name;
1742c7f28f2Smillert 	state = NAMEI;
1752c7f28f2Smillert 	quotechar = '\0';
1762c7f28f2Smillert 	c = envstr;
1772c7f28f2Smillert 	while (state != ERROR && *c) {
1782c7f28f2Smillert 		switch (state) {
1792c7f28f2Smillert 		case NAMEI:
1802c7f28f2Smillert 		case VALUEI:
1812c7f28f2Smillert 			if (*c == '\'' || *c == '"')
1822c7f28f2Smillert 				quotechar = *c++;
1832c7f28f2Smillert 			state++;
1842c7f28f2Smillert 			/* FALLTHROUGH */
1852c7f28f2Smillert 		case NAME:
1862c7f28f2Smillert 		case VALUE:
1872c7f28f2Smillert 			if (quotechar) {
1882c7f28f2Smillert 				if (*c == quotechar) {
1892c7f28f2Smillert 					state++;
1902c7f28f2Smillert 					c++;
1912c7f28f2Smillert 					break;
1922c7f28f2Smillert 				}
1932c7f28f2Smillert 				if (state == NAME && *c == '=') {
1942c7f28f2Smillert 					state = ERROR;
1952c7f28f2Smillert 					break;
1962c7f28f2Smillert 				}
1972c7f28f2Smillert 			} else {
1982c7f28f2Smillert 				if (state == NAME) {
1992c7f28f2Smillert 					if (isspace((unsigned char)*c)) {
2002c7f28f2Smillert 						c++;
2012c7f28f2Smillert 						state++;
2022c7f28f2Smillert 						break;
2032c7f28f2Smillert 					}
2042c7f28f2Smillert 					if (*c == '=') {
2052c7f28f2Smillert 						state++;
2062c7f28f2Smillert 						break;
2072c7f28f2Smillert 					}
2082c7f28f2Smillert 				}
2092c7f28f2Smillert 			}
2102c7f28f2Smillert 			*str++ = *c++;
2112c7f28f2Smillert 			break;
2122c7f28f2Smillert 		case EQ1:
2132c7f28f2Smillert 			if (*c == '=') {
2142c7f28f2Smillert 				state++;
2152c7f28f2Smillert 				str = val;
2162c7f28f2Smillert 				quotechar = '\0';
2172c7f28f2Smillert 			} else {
2182c7f28f2Smillert 				if (!isspace((unsigned char)*c))
2192c7f28f2Smillert 					state = ERROR;
2202c7f28f2Smillert 			}
2212c7f28f2Smillert 			c++;
2222c7f28f2Smillert 			break;
2232c7f28f2Smillert 		case EQ2:
2242c7f28f2Smillert 		case FINI:
2252c7f28f2Smillert 			if (isspace((unsigned char)*c))
2262c7f28f2Smillert 				c++;
2272c7f28f2Smillert 			else
2282c7f28f2Smillert 				state++;
2292c7f28f2Smillert 			break;
23095bc639aSmillert 		case ERROR:
23195bc639aSmillert 			/* handled below */
23295bc639aSmillert 			break;
2332c7f28f2Smillert 		}
2342c7f28f2Smillert 	}
235a9e807deSmillert 	if (state != FINI && !(state == VALUE && !quotechar))
236a9e807deSmillert 		goto not_env;
2372c7f28f2Smillert 	if (state == VALUE) {
2382c7f28f2Smillert 		/* End of unquoted value: trim trailing whitespace */
2392c7f28f2Smillert 		c = val + strlen(val);
2402c7f28f2Smillert 		while (c > val && isspace((unsigned char)c[-1]))
2412c7f28f2Smillert 			*(--c) = '\0';
2422c7f28f2Smillert 	}
243df930be7Sderaadt 
2442c7f28f2Smillert 	/* 2 fields from parser; looks like an env setting */
245df930be7Sderaadt 
246f454ebdeSmillert 	/*
247f454ebdeSmillert 	 * This can't overflow because get_string() limited the size of the
2482c7f28f2Smillert 	 * name and val fields.  Still, it doesn't hurt to be careful...
249f454ebdeSmillert 	 */
250f624271cSavsm 	if (snprintf(envstr, MAX_ENVSTR, "%s=%s", name, val) >= MAX_ENVSTR)
251a9e807deSmillert 		goto not_env;
252df930be7Sderaadt 	return (TRUE);
253a9e807deSmillert  not_env:
254a9e807deSmillert 	fseek(f, filepos, SEEK_SET);
255a9e807deSmillert 	Set_LineNum(fileline);
256a9e807deSmillert 	return (FALSE);
257df930be7Sderaadt }
258