acl_from_text.c revision 74191
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: head/lib/libc/posix1e/acl_from_text.c 74191 2001-03-13 02:31:32Z rwatson $ 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 41static char * 42string_skip_whitespace(char *string) 43{ 44 45 while (*string && ((*string == ' ') || (*string == '\t'))) { 46 string++; 47 } 48 return (string); 49} 50 51static void 52string_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 73acl_tag_t 74acl_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 */ 107acl_t 108acl_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 return(NULL); 122 123 acl = acl_init(3); 124 if (!acl) { 125 free(mybuf_p); 126 return(NULL); 127 } 128 129 /* Outer loop: delimit at \n boundaries. */ 130 cur = mybuf_p; 131 while ((line = strsep(&cur, "\n"))) { 132 /* Now split the line on the first # to strip out comments. */ 133 comment = line; 134 notcomment = strsep(&comment, "#"); 135 136 /* Inner loop: delimit at ',' boundaries. */ 137 while ((entry = strsep(¬comment, ","))) { 138 /* Now split into three ':' delimited fields. */ 139 tag = strsep(&entry, ":"); 140 if (!tag) { 141 errno = EINVAL; 142 goto error_label; 143 } 144 tag = string_skip_whitespace(tag); 145 if ((*tag == '\0') && (!entry)) { 146 /* 147 * Is an entirely comment line, skip to next 148 * comma. 149 */ 150 continue; 151 } 152 string_trim_trailing_whitespace(tag); 153 154 qualifier = strsep(&entry, ":"); 155 if (!qualifier) { 156 errno = EINVAL; 157 goto error_label; 158 } 159 qualifier = string_skip_whitespace(qualifier); 160 string_trim_trailing_whitespace(qualifier); 161 162 permission = strsep(&entry, ":"); 163 if ((!permission) || (entry)) { 164 errno = EINVAL; 165 goto error_label; 166 } 167 permission = string_skip_whitespace(permission); 168 string_trim_trailing_whitespace(permission); 169 170 t = acl_string_to_tag(tag, qualifier); 171 if (t == -1) { 172 errno = EINVAL; 173 goto error_label; 174 } 175 176 error = _posix1e_acl_string_to_perm(permission, &p); 177 if (error == -1) { 178 errno = EINVAL; 179 goto error_label; 180 } 181 182 switch(t) { 183 case ACL_USER_OBJ: 184 case ACL_GROUP_OBJ: 185 case ACL_MASK: 186 case ACL_OTHER: 187 if (*qualifier != '\0') { 188 errno = EINVAL; 189 goto error_label; 190 } 191 id = 0; 192 break; 193 194 case ACL_USER: 195 case ACL_GROUP: 196 error = _posix1e_acl_name_to_id(t, qualifier, 197 &id); 198 if (error == -1) 199 goto error_label; 200 break; 201 202 default: 203 errno = EINVAL; 204 goto error_label; 205 } 206 207 error = _posix1e_acl_add_entry(acl, t, id, p); 208 if (error == -1) 209 goto error_label; 210 } 211 } 212 213#if 0 214 /* XXX Should we only return ACLs valid according to acl_valid? */ 215 /* Verify validity of the ACL we read in. */ 216 if (acl_valid(acl) == -1) { 217 errno = EINVAL; 218 goto error_label; 219 } 220#endif 221 222 return(acl); 223 224error_label: 225 acl_free(acl); 226 free(mybuf_p); 227 return(NULL); 228} 229 230 231 232