1 /*- 2 * Copyright (c) 1999 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: src/lib/libposix1e/acl_from_text.c,v 1.1 2000/01/15 19:44:24 rwatson Exp $ 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 enum PARSE_MODE { 42 PM_BASE, /* initial, begin line, or after , */ 43 PM_QUALIFIER, /* in qualifier field */ 44 PM_PERM, /* in permission field */ 45 PM_COMMENT, /* in comment */ 46 }; 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 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 cal 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 uid_t id; 121 char *mybuf_p, *line, *cur, *notcomment, *comment, *entry; 122 char *tag, *qualifier, *permission; 123 int error; 124 125 /* local copy we can mess up */ 126 mybuf_p = strdup(buf_p); 127 if (!mybuf_p) { 128 errno = ENOMEM; 129 return(0); 130 } 131 132 acl = acl_init(3); 133 if (!acl) { 134 free(mybuf_p); 135 errno = ENOMEM; 136 return(0); 137 } 138 139 /* outer loop: delimit at \n boundaries */ 140 cur = mybuf_p; 141 while ((line = strsep(&cur, "\n"))) { 142 /* now split the line on the first # to strip out comments */ 143 comment = line; 144 notcomment = strsep(&comment, "#"); 145 146 /* inner loop: delimit at , boundaries */ 147 while ((entry = strsep(¬comment, ","))) { 148 /* now split into three :-delimited fields */ 149 tag = strsep(&entry, ":"); 150 if (!tag) { 151 /* printf("no tag\n"); */ 152 errno = EINVAL; 153 goto error_label; 154 } 155 tag = string_skip_whitespace(tag); 156 if ((*tag == '\0') && (!entry)) { 157 /* 158 * is an entirely comment line, skip to next 159 * comma 160 */ 161 continue; 162 } 163 string_trim_trailing_whitespace(tag); 164 165 qualifier = strsep(&entry, ":"); 166 if (!qualifier) { 167 /* printf("no qualifier\n"); */ 168 errno = EINVAL; 169 goto error_label; 170 } 171 qualifier = string_skip_whitespace(qualifier); 172 string_trim_trailing_whitespace(qualifier); 173 174 permission = strsep(&entry, ":"); 175 if ((!permission) || (entry)) { 176 /* printf("no permission, or more stuff\n"); */ 177 errno = EINVAL; 178 goto error_label; 179 } 180 permission = string_skip_whitespace(permission); 181 string_trim_trailing_whitespace(permission); 182 183 /* printf("[%s/%s/%s]\n", tag, qualifier, 184 permission); */ 185 186 t = acl_string_to_tag(tag, qualifier); 187 if (t == -1) { 188 errno = EINVAL; 189 goto error_label; 190 } 191 192 error = acl_string_to_perm(permission, &p); 193 if (error == -1) { 194 errno = EINVAL; 195 goto error_label; 196 } 197 198 switch(t) { 199 case ACL_USER_OBJ: 200 case ACL_GROUP_OBJ: 201 case ACL_MASK: 202 case ACL_OTHER: 203 if (*qualifier != '\0') { 204 errno = EINVAL; 205 goto error_label; 206 } 207 id = 0; 208 break; 209 210 case ACL_USER: 211 case ACL_GROUP: 212 error = acl_name_to_id(t, qualifier, &id); 213 if (error == -1) 214 goto error_label; 215 break; 216 217 default: 218 errno = EINVAL; 219 goto error_label; 220 } 221 222 error = acl_add_entry(acl, t, id, p); 223 if (error == -1) 224 goto error_label; 225 } 226 } 227 228 #if 0 229 /* XXX should we only return ACLs valid according to acl_valid? */ 230 /* verify validity of the ACL we read in */ 231 if (acl_valid(acl) == -1) { 232 errno = EINVAL; 233 goto error_label; 234 } 235 #endif 236 237 return(acl); 238 239 error_label: 240 acl_free(acl); 241 free(mybuf_p); 242 return(0); 243 } 244 245 246 247