acl_from_text.c revision 91032
18729Sserb/*-
29330Slana * Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
38729Sserb * All rights reserved.
48729Sserb *
58729Sserb * Redistribution and use in source and binary forms, with or without
68729Sserb * modification, are permitted provided that the following conditions
78729Sserb * are met:
88729Sserb * 1. Redistributions of source code must retain the above copyright
98729Sserb *    notice, this list of conditions and the following disclaimer.
108729Sserb * 2. Redistributions in binary form must reproduce the above copyright
118729Sserb *    notice, this list of conditions and the following disclaimer in the
128729Sserb *    documentation and/or other materials provided with the distribution.
138729Sserb *
148729Sserb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158729Sserb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168729Sserb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178729Sserb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
188729Sserb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198729Sserb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
208729Sserb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
218729Sserb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228729Sserb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
238729Sserb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
240Sduke * SUCH DAMAGE.
250Sduke *
260Sduke * $FreeBSD: head/lib/libc/posix1e/acl_from_text.c 91032 2002-02-21 23:12:25Z jedgar $
270Sduke */
280Sduke/*
290Sduke * acl_from_text: Convert a text-form ACL from a string to an acl_t.
300Sduke */
310Sduke
320Sduke#include <sys/types.h>
330Sduke#include "namespace.h"
340Sduke#include <sys/acl.h>
350Sduke#include "un-namespace.h"
360Sduke#include <sys/errno.h>
370Sduke#include <stdio.h>
380Sduke#include <stdlib.h>
390Sduke#include <string.h>
400Sduke
410Sduke#include "acl_support.h"
420Sduke
430Sdukestatic 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)
127		return(NULL);
128
129	acl = acl_init(3);
130	if (!acl) {
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) {
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) {
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) || (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