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