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