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