acl_from_text.c revision 91034
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 91034 2002-02-21 23:17:19Z jedgar $
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 "namespace.h"
34#include <sys/acl.h>
35#include "un-namespace.h"
36#include <sys/errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include "acl_support.h"
42
43static acl_tag_t acl_string_to_tag(char *tag, char *qualifier);
44static char *string_skip_whitespace(char *string);
45static void string_trim_trailing_whitespace(char *string);
46
47static char *
48string_skip_whitespace(char *string)
49{
50
51	while (*string && ((*string == ' ') || (*string == '\t'))) {
52		string++;
53	}
54	return (string);
55}
56
57static void
58string_trim_trailing_whitespace(char *string)
59{
60	char	*end;
61
62	if (*string == '\0')
63		return;
64
65	end = string + strlen(string) - 1;
66
67	while (end != string) {
68		if ((*end == ' ') || (*end == '\t')) {
69			*end = '\0';
70			end--;
71		} else {
72			return;
73		}
74	}
75
76	return;
77}
78
79static acl_tag_t
80acl_string_to_tag(char *tag, char *qualifier)
81{
82
83	if (*qualifier == '\0') {
84		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
85			return (ACL_USER_OBJ);
86		} else
87		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
88			return (ACL_GROUP_OBJ);
89		} else
90		if ((!strcmp(tag, "mask")) || (!strcmp(tag, "m"))) {
91			return (ACL_MASK);
92		} else
93		if ((!strcmp(tag, "other")) || (!strcmp(tag, "o"))) {
94			return (ACL_OTHER);
95		} else
96			return(-1);
97	} else {
98		if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
99			return(ACL_USER);
100		} else
101		if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
102			return(ACL_GROUP);
103		} else
104			return(-1);
105	}
106}
107
108/*
109 * acl_from_text -- Convert a string into an ACL.
110 * Postpone most validity checking until the end and call acl_valid() to do
111 * that.
112 */
113acl_t
114acl_from_text(const char *buf_p)
115{
116	acl_tag_t	 t;
117	acl_perm_t	 p;
118	acl_t		 acl;
119	char		*mybuf_p, *line, *cur, *notcomment, *comment, *entry;
120	char		*tag, *qualifier, *permission;
121	int		 error;
122	uid_t		 id;
123
124	/* Local copy we can mess up. */
125	mybuf_p = strdup(buf_p);
126	if (mybuf_p == NULL)
127		return(NULL);
128
129	acl = acl_init(3);
130	if (acl == NULL) {
131		free(mybuf_p);
132		return(NULL);
133	}
134
135	/* Outer loop: delimit at \n boundaries. */
136	cur = mybuf_p;
137	while ((line = strsep(&cur, "\n"))) {
138		/* Now split the line on the first # to strip out comments. */
139		comment = line;
140		notcomment = strsep(&comment, "#");
141
142		/* Inner loop: delimit at ',' boundaries. */
143		while ((entry = strsep(&notcomment, ","))) {
144			/* Now split into three ':' delimited fields. */
145			tag = strsep(&entry, ":");
146			if (tag == NULL) {
147				errno = EINVAL;
148				goto error_label;
149			}
150			tag = string_skip_whitespace(tag);
151			if ((*tag == '\0') && (!entry)) {
152				/*
153				 * Is an entirely comment line, skip to next
154				 * comma.
155				 */
156				continue;
157			}
158			string_trim_trailing_whitespace(tag);
159
160			qualifier = strsep(&entry, ":");
161			if (qualifier == NULL) {
162				errno = EINVAL;
163				goto error_label;
164			}
165			qualifier = string_skip_whitespace(qualifier);
166			string_trim_trailing_whitespace(qualifier);
167
168			permission = strsep(&entry, ":");
169			if (permission == NULL || entry) {
170				errno = EINVAL;
171				goto error_label;
172			}
173			permission = string_skip_whitespace(permission);
174			string_trim_trailing_whitespace(permission);
175
176			t = acl_string_to_tag(tag, qualifier);
177			if (t == -1) {
178				errno = EINVAL;
179				goto error_label;
180			}
181
182			error = _posix1e_acl_string_to_perm(permission, &p);
183			if (error == -1) {
184				errno = EINVAL;
185				goto error_label;
186			}
187
188			switch(t) {
189			case ACL_USER_OBJ:
190			case ACL_GROUP_OBJ:
191			case ACL_MASK:
192			case ACL_OTHER:
193				if (*qualifier != '\0') {
194					errno = EINVAL;
195					goto error_label;
196				}
197				id = 0;
198				break;
199
200			case ACL_USER:
201			case ACL_GROUP:
202				error = _posix1e_acl_name_to_id(t, qualifier,
203				    &id);
204				if (error == -1)
205					goto error_label;
206				break;
207
208			default:
209				errno = EINVAL;
210				goto error_label;
211			}
212
213			error = _posix1e_acl_add_entry(acl, t, id, p);
214			if (error == -1)
215				goto error_label;
216		}
217	}
218
219#if 0
220	/* XXX Should we only return ACLs valid according to acl_valid? */
221	/* Verify validity of the ACL we read in. */
222	if (acl_valid(acl) == -1) {
223		errno = EINVAL;
224		goto error_label;
225	}
226#endif
227
228	return(acl);
229
230error_label:
231	acl_free(acl);
232	free(mybuf_p);
233	return(NULL);
234}
235
236
237
238