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(¬comment, ","))) { 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