1/*	$OpenBSD: stringlist.c,v 1.4 2023/01/04 13:00:11 jsg Exp $	*/
2
3/*
4 * Copyright (c) 1994 Christos Zoulas
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/types.h>
30#include <stdio.h>
31#include <netgroup.h>
32#include <string.h>
33#include <stdlib.h>
34#include <ctype.h>
35#include "stringlist.h"
36
37static const char _ngstar[] = "*";
38
39static int		getstring(char **, int, char **);
40static struct netgroup	*getnetgroup(char **);
41
42/*
43 * _ng_sl_init(): Initialize a string list
44 */
45struct stringlist *
46_ng_sl_init(void)
47{
48	struct stringlist *sl = malloc(sizeof(struct stringlist));
49	if (sl == NULL)
50		return NULL;
51
52	sl->sl_cur = 0;
53	sl->sl_max = 20;
54	sl->sl_str = calloc(sl->sl_max, sizeof(char *));
55	if (sl->sl_str == NULL) {
56		free(sl);
57		return NULL;
58	}
59	return sl;
60}
61
62
63/*
64 * _ng_sl_add(): Add an item to the string list
65 */
66int
67_ng_sl_add(struct stringlist *sl, char *name)
68{
69	if (sl->sl_cur == sl->sl_max - 1) {
70		char **slstr;
71
72		sl->sl_max += 20;
73		slstr = reallocarray(sl->sl_str, sl->sl_max, sizeof(char *));
74		if (slstr == NULL) {
75			free(sl->sl_str);
76			sl->sl_str = NULL;
77			return -1;
78		}
79		sl->sl_str = slstr;
80	}
81	sl->sl_str[sl->sl_cur++] = name;
82	return 0;
83}
84
85
86/*
87 * _ng_sl_free(): Free a stringlist
88 */
89void
90_ng_sl_free(struct stringlist *sl, int all)
91{
92	size_t	i;
93
94	if (all)
95		for (i = 0; i < sl->sl_cur; i++)
96			free(sl->sl_str[i]);
97	free(sl->sl_str);
98	free(sl);
99}
100
101
102/*
103 * sl_find(): Find a name in the string list
104 */
105char *
106_ng_sl_find(struct stringlist *sl, char *name)
107{
108	size_t	i;
109
110	for (i = 0; i < sl->sl_cur; i++)
111		if (strcmp(sl->sl_str[i], name) == 0)
112			return sl->sl_str[i];
113
114	return NULL;
115}
116
117/*
118 * _ng_parse(): Parse a line and return: _NG_ERROR: Syntax Error _NG_NONE:
119 * line was empty or a comment _NG_GROUP: line had a netgroup definition,
120 * returned in ng _NG_NAME:  line had a netgroup name, returned in name
121 *
122 * Public since used by netgroup_mkdb
123 */
124int
125_ng_parse(char **p, char **name, struct netgroup **ng)
126{
127	while (**p) {
128		if (**p == '#')
129			/* comment */
130			return _NG_NONE;
131
132		while (**p && _NG_ISSPACE(**p))
133			/* skipblank */
134			(*p)++;
135
136		if (**p == '(') {
137			if ((*ng = getnetgroup(p)) == NULL)
138				return _NG_ERROR;
139			return _NG_GROUP;
140		} else {
141			char	*np;
142			int	i;
143
144			for (np = *p; **p && !_NG_ISSPACE(**p); (*p)++)
145				continue;
146			if (np != *p) {
147				i = (*p - np) + 1;
148				*name = malloc(i);
149				if (*name == NULL)
150					return _NG_ERROR;
151				memcpy(*name, np, i);
152				(*name)[i - 1] = '\0';
153				return _NG_NAME;
154			}
155		}
156	}
157	return _NG_NONE;
158}
159
160/*
161 * _ng_makekey(): Make a key from the two names given. The key is of the form
162 * <name1>.<name2> Names strings are replaced with * if they are empty;
163 */
164char *
165_ng_makekey(const char *s1, const char *s2, size_t len)
166{
167	char *buf = malloc(len);
168	int ret;
169
170	if (buf == NULL)
171		return NULL;
172	ret = snprintf(buf, len, "%s.%s", _NG_STAR(s1), _NG_STAR(s2));
173	if (ret < 0 || ret >= len) {
174		free(buf);
175		return NULL;
176	}
177
178	return buf;
179}
180
181void
182_ng_print(char *buf, size_t len, const struct netgroup *ng)
183{
184	(void) snprintf(buf, len, "(%s,%s,%s)", _NG_EMPTY(ng->ng_host),
185	    _NG_EMPTY(ng->ng_user), _NG_EMPTY(ng->ng_domain));
186}
187
188/*
189 * getnetgroup(): Parse a netgroup, and advance the pointer
190 */
191static struct netgroup *
192getnetgroup(char **pp)
193{
194	struct netgroup *ng = malloc(sizeof(struct netgroup));
195
196	if (ng == NULL)
197		return NULL;
198
199	(*pp)++;	/* skip '(' */
200	if (!getstring(pp, ',', &ng->ng_host))
201		goto badhost;
202
203	if (!getstring(pp, ',', &ng->ng_user))
204		goto baduser;
205
206	if (!getstring(pp, ')', &ng->ng_domain))
207		goto baddomain;
208
209#ifdef DEBUG_NG
210	{
211		char buf[1024];
212		_ng_print(buf, sizeof(buf), ng);
213		fprintf(stderr, "netgroup %s\n", buf);
214	}
215#endif
216	return ng;
217
218baddomain:
219	free(ng->ng_user);
220baduser:
221	free(ng->ng_host);
222badhost:
223	free(ng);
224	return NULL;
225}
226
227/*
228 * getstring(): Get a string delimited by the character, skipping leading and
229 * trailing blanks and advancing the pointer
230 */
231static int
232getstring(char **pp, int del, char **str)
233{
234	char *sp, *ep, *dp;
235
236	/* skip leading blanks */
237	for (sp = *pp; *sp && _NG_ISSPACE(*sp); sp++)
238		continue;
239
240	/* accumulate till delimiter or space */
241	for (ep = sp; *ep && *ep != del && !_NG_ISSPACE(*ep); ep++)
242		continue;
243
244	/* hunt for the delimiter */
245	for (dp = ep; *dp && *dp != del && _NG_ISSPACE(*dp); dp++)
246		continue;
247
248	if (*dp != del) {
249		*str = NULL;
250		return 0;
251	}
252
253	*pp = ++dp;
254
255	del = (ep - sp) + 1;
256	if (del > 1) {
257		dp = malloc(del);
258		if (dp == NULL)
259			return 0;
260		memcpy(dp, sp, del);
261		dp[del - 1] = '\0';
262	} else
263		dp = NULL;
264
265	*str = dp;
266	return 1;
267}
268