acl_from_text.c revision 71142
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: head/lib/libc/posix1e/acl_from_text.c 71142 2001-01-17 02:40:39Z 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 = 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 = acl_name_to_id(t, qualifier, &id); 197 if (error == -1) 198 goto error_label; 199 break; 200 201 default: 202 errno = EINVAL; 203 goto error_label; 204 } 205 206 error = acl_add_entry(acl, t, id, p); 207 if (error == -1) 208 goto error_label; 209 } 210 } 211 212#if 0 213 /* XXX Should we only return ACLs valid according to acl_valid? */ 214 /* Verify validity of the ACL we read in. */ 215 if (acl_valid(acl) == -1) { 216 errno = EINVAL; 217 goto error_label; 218 } 219#endif 220 221 return(acl); 222 223error_label: 224 acl_free(acl); 225 free(mybuf_p); 226 return(NULL); 227} 228 229 230 231