acl_from_text.c revision 74191
1/*-
2 * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/lib/libc/posix1e/acl_from_text.c 74191 2001-03-13 02:31:32Z rwatson $
27 */
28/*
29 * acl_from_text: Convert a text-form ACL from a string to an acl_t.
30 */
31
32#include <sys/types.h>
33#include <sys/acl.h>
34#include <sys/errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include "acl_support.h"
40
41static char *
42string_skip_whitespace(char *string)
43{
44
45	while (*string && ((*string == ' ') || (*string == '\t'))) {
46		string++;
47	}
48	return (string);
49}
50
51static void
52string_trim_trailing_whitespace(char *string)
53{
54	char	*end;
55
56	if (*string == '\0')
57		return;
58
59	end = string + strlen(string) - 1;
60
61	while (end != string) {
62		if ((*end == ' ') || (*end == '\t')) {
63			*end = '\0';
64			end--;
65		} else {
66			return;
67		}
68	}
69
70	return;
71}
72
73acl_tag_t
74acl_string_to_tag(char *tag, char *qualifier)
75{
76
77	if (*qualifier == '\0') {
78		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
79			return (ACL_USER_OBJ);
80		} else
81		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
82			return (ACL_GROUP_OBJ);
83		} else
84		if ((!strcmp(tag, "mask")) || (!strcmp(tag, "m"))) {
85			return (ACL_MASK);
86		} else
87		if ((!strcmp(tag, "other")) || (!strcmp(tag, "o"))) {
88			return (ACL_OTHER);
89		} else
90			return(-1);
91	} else {
92		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
93			return(ACL_USER);
94		} else
95		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
96			return(ACL_GROUP);
97		} else
98			return(-1);
99	}
100}
101
102/*
103 * acl_from_text -- Convert a string into an ACL.
104 * Postpone most validity checking until the end and call acl_valid() to do
105 * that.
106 */
107acl_t
108acl_from_text(const char *buf_p)
109{
110	acl_tag_t	t;
111	acl_perm_t	p;
112	acl_t	acl;
113	uid_t	id;
114	char	*mybuf_p, *line, *cur, *notcomment, *comment, *entry;
115	char	*tag, *qualifier, *permission;
116	int	error;
117
118	/* Local copy we can mess up. */
119	mybuf_p = strdup(buf_p);
120	if (!mybuf_p)
121		return(NULL);
122
123	acl = acl_init(3);
124	if (!acl) {
125		free(mybuf_p);
126		return(NULL);
127	}
128
129	/* Outer loop: delimit at \n boundaries. */
130	cur = mybuf_p;
131	while ((line = strsep(&cur, "\n"))) {
132		/* Now split the line on the first # to strip out comments. */
133		comment = line;
134		notcomment = strsep(&comment, "#");
135
136		/* Inner loop: delimit at ',' boundaries. */
137		while ((entry = strsep(&notcomment, ","))) {
138			/* Now split into three ':' delimited fields. */
139			tag = strsep(&entry, ":");
140			if (!tag) {
141				errno = EINVAL;
142				goto error_label;
143			}
144			tag = string_skip_whitespace(tag);
145			if ((*tag == '\0') && (!entry)) {
146				/*
147				 * Is an entirely comment line, skip to next
148				 * comma.
149				 */
150				continue;
151			}
152			string_trim_trailing_whitespace(tag);
153
154			qualifier = strsep(&entry, ":");
155			if (!qualifier) {
156				errno = EINVAL;
157				goto error_label;
158			}
159			qualifier = string_skip_whitespace(qualifier);
160			string_trim_trailing_whitespace(qualifier);
161
162			permission = strsep(&entry, ":");
163			if ((!permission) || (entry)) {
164				errno = EINVAL;
165				goto error_label;
166			}
167			permission = string_skip_whitespace(permission);
168			string_trim_trailing_whitespace(permission);
169
170			t = acl_string_to_tag(tag, qualifier);
171			if (t == -1) {
172				errno = EINVAL;
173				goto error_label;
174			}
175
176			error = _posix1e_acl_string_to_perm(permission, &p);
177			if (error == -1) {
178				errno = EINVAL;
179				goto error_label;
180			}
181
182			switch(t) {
183			case ACL_USER_OBJ:
184			case ACL_GROUP_OBJ:
185			case ACL_MASK:
186			case ACL_OTHER:
187				if (*qualifier != '\0') {
188					errno = EINVAL;
189					goto error_label;
190				}
191				id = 0;
192				break;
193
194			case ACL_USER:
195			case ACL_GROUP:
196				error = _posix1e_acl_name_to_id(t, qualifier,
197				    &id);
198				if (error == -1)
199					goto error_label;
200				break;
201
202			default:
203				errno = EINVAL;
204				goto error_label;
205			}
206
207			error = _posix1e_acl_add_entry(acl, t, id, p);
208			if (error == -1)
209				goto error_label;
210		}
211	}
212
213#if 0
214	/* XXX Should we only return ACLs valid according to acl_valid? */
215	/* Verify validity of the ACL we read in. */
216	if (acl_valid(acl) == -1) {
217		errno = EINVAL;
218		goto error_label;
219	}
220#endif
221
222	return(acl);
223
224error_label:
225	acl_free(acl);
226	free(mybuf_p);
227	return(NULL);
228}
229
230
231
232