1/*
2 * Copyright (c) 1996, 1998-2005, 2007-2011
3 *	Todd C. Miller <Todd.Miller@courtesan.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
17 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
18 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19 *
20 * Sponsored in part by the Defense Advanced Research Projects
21 * Agency (DARPA) and Air Force Research Laboratory, Air Force
22 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
23 */
24
25#include <config.h>
26
27#include <sys/types.h>
28#include <sys/param.h>
29#include <stdio.h>
30#ifdef STDC_HEADERS
31# include <stdlib.h>
32# include <stddef.h>
33#else
34# ifdef HAVE_STDLIB_H
35#  include <stdlib.h>
36# endif
37#endif /* STDC_HEADERS */
38#ifdef HAVE_STRING_H
39# include <string.h>
40#endif /* HAVE_STRING_H */
41#ifdef HAVE_STRINGS_H
42# include <strings.h>
43#endif /* HAVE_STRINGS_H */
44#ifdef HAVE_UNISTD_H
45# include <unistd.h>
46#endif /* HAVE_UNISTD_H */
47#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
48# include <malloc.h>
49#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
50#include <ctype.h>
51#include "sudo.h"
52#include "parse.h"
53#include "toke.h"
54#include <gram.h>
55
56static int arg_len = 0;
57static int arg_size = 0;
58
59static unsigned char
60hexchar(s)
61    const char *s;
62{
63    int i;
64    int result = 0;
65
66    s += 2; /* skip \\x */
67    for (i = 0; i < 2; i++) {
68	switch (*s) {
69	case 'A':
70	case 'a':
71	    result += 10;
72	    break;
73	case 'B':
74	case 'b':
75	    result += 11;
76	    break;
77	case 'C':
78	case 'c':
79	    result += 12;
80	    break;
81	case 'D':
82	case 'd':
83	    result += 13;
84	    break;
85	case 'E':
86	case 'e':
87	    result += 14;
88	    break;
89	case 'F':
90	case 'f':
91	    result += 15;
92	    break;
93	default:
94	    result += *s - '0';
95	    break;
96	}
97	if (i == 0) {
98	    result *= 16;
99	    s++;
100	}
101    }
102    return (unsigned char)result;
103}
104
105int
106fill_txt(src, len, olen)
107    char *src;
108    int len, olen;
109{
110    char *dst;
111
112    dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1);
113    if (dst == NULL) {
114	yyerror("unable to allocate memory");
115	return FALSE;
116    }
117    yylval.string = dst;
118
119    /* Copy the string and collapse any escaped characters. */
120    dst += olen;
121    while (len--) {
122	if (*src == '\\' && len) {
123	    if (src[1] == 'x' && len >= 3 &&
124		isxdigit((unsigned char) src[2]) &&
125		isxdigit((unsigned char) src[3])) {
126		*dst++ = hexchar(src);
127		src += 4;
128		len -= 3;
129	    } else {
130		src++;
131		len--;
132		*dst++ = *src++;
133	    }
134	} else {
135	    *dst++ = *src++;
136	}
137    }
138    *dst = '\0';
139    return TRUE;
140}
141
142int
143append(src, len)
144    char *src;
145    int len;
146{
147    int olen = 0;
148
149    if (yylval.string != NULL)
150	olen = strlen(yylval.string);
151
152    return fill_txt(src, len, olen);
153}
154
155#define SPECIAL(c) \
156    ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#')
157
158int
159fill_cmnd(src, len)
160    char *src;
161    int len;
162{
163    char *dst;
164    int i;
165
166    arg_len = arg_size = 0;
167
168    dst = yylval.command.cmnd = (char *) malloc(len + 1);
169    if (yylval.command.cmnd == NULL) {
170	yyerror("unable to allocate memory");
171	return FALSE;
172    }
173
174    /* Copy the string and collapse any escaped sudo-specific characters. */
175    for (i = 0; i < len; i++) {
176	if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1]))
177	    *dst++ = src[++i];
178	else
179	    *dst++ = src[i];
180    }
181    *dst = '\0';
182
183    yylval.command.args = NULL;
184    return TRUE;
185}
186
187int
188fill_args(s, len, addspace)
189    char *s;
190    int len;
191    int addspace;
192{
193    int new_len;
194    char *p;
195
196    if (yylval.command.args == NULL) {
197	addspace = 0;
198	new_len = len;
199    } else
200	new_len = arg_len + len + addspace;
201
202    if (new_len >= arg_size) {
203	/* Allocate more space than we need for subsequent args */
204	while (new_len >= (arg_size += COMMANDARGINC))
205	    ;
206
207	p = yylval.command.args ?
208	    (char *) realloc(yylval.command.args, arg_size) :
209	    (char *) malloc(arg_size);
210	if (p == NULL) {
211	    efree(yylval.command.args);
212	    yyerror("unable to allocate memory");
213	    return FALSE;
214	} else
215	    yylval.command.args = p;
216    }
217
218    /* Efficiently append the arg (with a leading space if needed). */
219    p = yylval.command.args + arg_len;
220    if (addspace)
221	*p++ = ' ';
222    if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) {
223	yyerror("fill_args: buffer overflow");	/* paranoia */
224	return FALSE;
225    }
226    arg_len = new_len;
227    return TRUE;
228}
229
230/*
231 * Check to make sure an IPv6 address does not contain multiple instances
232 * of the string "::".  Assumes strlen(s) >= 1.
233 * Returns TRUE if address is valid else FALSE.
234 */
235int
236ipv6_valid(s)
237    const char *s;
238{
239    int nmatch = 0;
240
241    for (; *s != '\0'; s++) {
242	if (s[0] == ':' && s[1] == ':') {
243	    if (++nmatch > 1)
244		break;
245	}
246	if (s[0] == '/')
247	    nmatch = 0;			/* reset if we hit netmask */
248    }
249
250    return nmatch <= 1;
251}
252