xref: /freebsd/lib/libc/posix1e/acl_from_text.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*-
2  * Copyright (c) 1999, 2000 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 <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 
41 static char *
42 string_skip_whitespace(char *string)
43 {
44 
45 	while (*string && ((*string == ' ') || (*string == '\t'))) {
46 		string++;
47 	}
48 	return (string);
49 }
50 
51 static void
52 string_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 
73 acl_tag_t
74 acl_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  */
107 acl_t
108 acl_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 		errno = ENOMEM;
122 		return(0);
123 	}
124 
125 	acl = acl_init(3);
126 	if (!acl) {
127 		free(mybuf_p);
128 		errno = ENOMEM;
129 		return(0);
130 	}
131 
132 	/* Outer loop: delimit at \n boundaries. */
133 	cur = mybuf_p;
134 	while ((line = strsep(&cur, "\n"))) {
135 		/* Now split the line on the first # to strip out comments. */
136 		comment = line;
137 		notcomment = strsep(&comment, "#");
138 
139 		/* Inner loop: delimit at ',' boundaries. */
140 		while ((entry = strsep(&notcomment, ","))) {
141 			/* Now split into three ':' delimited fields. */
142 			tag = strsep(&entry, ":");
143 			if (!tag) {
144 				errno = EINVAL;
145 				goto error_label;
146 			}
147 			tag = string_skip_whitespace(tag);
148 			if ((*tag == '\0') && (!entry)) {
149 				/*
150 				 * Is an entirely comment line, skip to next
151 				 * comma.
152 				 */
153 				continue;
154 			}
155 			string_trim_trailing_whitespace(tag);
156 
157 			qualifier = strsep(&entry, ":");
158 			if (!qualifier) {
159 				errno = EINVAL;
160 				goto error_label;
161 			}
162 			qualifier = string_skip_whitespace(qualifier);
163 			string_trim_trailing_whitespace(qualifier);
164 
165 			permission = strsep(&entry, ":");
166 			if ((!permission) || (entry)) {
167 				errno = EINVAL;
168 				goto error_label;
169 			}
170 			permission = string_skip_whitespace(permission);
171 			string_trim_trailing_whitespace(permission);
172 
173 			t = acl_string_to_tag(tag, qualifier);
174 			if (t == -1) {
175 				errno = EINVAL;
176 				goto error_label;
177 			}
178 
179 			error = acl_string_to_perm(permission, &p);
180 			if (error == -1) {
181 				errno = EINVAL;
182 				goto error_label;
183 			}
184 
185 			switch(t) {
186 			case ACL_USER_OBJ:
187 			case ACL_GROUP_OBJ:
188 			case ACL_MASK:
189 			case ACL_OTHER:
190 				if (*qualifier != '\0') {
191 					errno = EINVAL;
192 					goto error_label;
193 				}
194 				id = 0;
195 				break;
196 
197 			case ACL_USER:
198 			case ACL_GROUP:
199 				error = acl_name_to_id(t, qualifier, &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 = 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(0);
230 }
231 
232 
233 
234