1 /*- 2 * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org> 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 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <errno.h> 34 #include <assert.h> 35 #include <string.h> 36 #include <pwd.h> 37 #include <grp.h> 38 #include <sys/syscall.h> 39 #include <sys/types.h> 40 #include <sys/acl.h> 41 42 #include "acl_support.h" 43 44 #define MAX_ENTRY_LENGTH 512 45 46 static int 47 format_who(char *str, size_t size, const acl_entry_t entry, int numeric) 48 { 49 int error; 50 acl_tag_t tag; 51 struct passwd *pwd; 52 struct group *grp; 53 uid_t *id; 54 55 error = acl_get_tag_type(entry, &tag); 56 if (error) 57 return (error); 58 59 switch (tag) { 60 case ACL_USER_OBJ: 61 snprintf(str, size, "owner@"); 62 break; 63 64 case ACL_USER: 65 id = (uid_t *)acl_get_qualifier(entry); 66 if (id == NULL) 67 return (-1); 68 /* XXX: Thread-unsafe. */ 69 if (!numeric) 70 pwd = getpwuid(*id); 71 else 72 pwd = NULL; 73 if (pwd == NULL) 74 snprintf(str, size, "user:%d", (unsigned int)*id); 75 else 76 snprintf(str, size, "user:%s", pwd->pw_name); 77 break; 78 79 case ACL_GROUP_OBJ: 80 snprintf(str, size, "group@"); 81 break; 82 83 case ACL_GROUP: 84 id = (uid_t *)acl_get_qualifier(entry); 85 if (id == NULL) 86 return (-1); 87 /* XXX: Thread-unsafe. */ 88 if (!numeric) 89 grp = getgrgid(*id); 90 else 91 grp = NULL; 92 if (grp == NULL) 93 snprintf(str, size, "group:%d", (unsigned int)*id); 94 else 95 snprintf(str, size, "group:%s", grp->gr_name); 96 break; 97 98 case ACL_EVERYONE: 99 snprintf(str, size, "everyone@"); 100 break; 101 102 default: 103 return (-1); 104 } 105 106 return (0); 107 } 108 109 static int 110 format_entry_type(char *str, size_t size, const acl_entry_t entry) 111 { 112 int error; 113 acl_entry_type_t entry_type; 114 115 error = acl_get_entry_type_np(entry, &entry_type); 116 if (error) 117 return (error); 118 119 switch (entry_type) { 120 case ACL_ENTRY_TYPE_ALLOW: 121 snprintf(str, size, "allow"); 122 break; 123 case ACL_ENTRY_TYPE_DENY: 124 snprintf(str, size, "deny"); 125 break; 126 case ACL_ENTRY_TYPE_AUDIT: 127 snprintf(str, size, "audit"); 128 break; 129 case ACL_ENTRY_TYPE_ALARM: 130 snprintf(str, size, "alarm"); 131 break; 132 default: 133 return (-1); 134 } 135 136 return (0); 137 } 138 139 static int 140 format_additional_id(char *str, size_t size, const acl_entry_t entry) 141 { 142 int error; 143 acl_tag_t tag; 144 uid_t *id; 145 146 error = acl_get_tag_type(entry, &tag); 147 if (error) 148 return (error); 149 150 switch (tag) { 151 case ACL_USER_OBJ: 152 case ACL_GROUP_OBJ: 153 case ACL_EVERYONE: 154 str[0] = '\0'; 155 break; 156 157 default: 158 id = (uid_t *)acl_get_qualifier(entry); 159 if (id == NULL) 160 return (-1); 161 snprintf(str, size, ":%d", (unsigned int)*id); 162 } 163 164 return (0); 165 } 166 167 static int 168 format_entry(char *str, size_t size, const acl_entry_t entry, int flags) 169 { 170 size_t off = 0, min_who_field_length = 18; 171 acl_permset_t permset; 172 acl_flagset_t flagset; 173 int error, len; 174 char buf[MAX_ENTRY_LENGTH + 1]; 175 176 assert(_entry_brand(entry) == ACL_BRAND_NFS4); 177 178 error = acl_get_flagset_np(entry, &flagset); 179 if (error) 180 return (error); 181 182 error = acl_get_permset(entry, &permset); 183 if (error) 184 return (error); 185 186 error = format_who(buf, sizeof(buf), entry, 187 flags & ACL_TEXT_NUMERIC_IDS); 188 if (error) 189 return (error); 190 len = strlen(buf); 191 if (len < min_who_field_length) 192 len = min_who_field_length; 193 off += snprintf(str + off, size - off, "%*s:", len, buf); 194 195 error = _nfs4_format_access_mask(buf, sizeof(buf), *permset, 196 flags & ACL_TEXT_VERBOSE); 197 if (error) 198 return (error); 199 off += snprintf(str + off, size - off, "%s:", buf); 200 201 error = _nfs4_format_flags(buf, sizeof(buf), *flagset, 202 flags & ACL_TEXT_VERBOSE); 203 if (error) 204 return (error); 205 off += snprintf(str + off, size - off, "%s:", buf); 206 207 error = format_entry_type(buf, sizeof(buf), entry); 208 if (error) 209 return (error); 210 off += snprintf(str + off, size - off, "%s", buf); 211 212 if (flags & ACL_TEXT_APPEND_ID) { 213 error = format_additional_id(buf, sizeof(buf), entry); 214 if (error) 215 return (error); 216 off += snprintf(str + off, size - off, "%s", buf); 217 } 218 219 off += snprintf(str + off, size - off, "\n"); 220 221 /* Make sure we didn't truncate anything. */ 222 assert (off < size); 223 224 return (0); 225 } 226 227 char * 228 _nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags) 229 { 230 int error, off = 0, size, entry_id = ACL_FIRST_ENTRY; 231 char *str; 232 acl_entry_t entry; 233 234 if (aclp->ats_acl.acl_cnt == 0) 235 return strdup(""); 236 237 size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH; 238 str = malloc(size); 239 if (str == NULL) 240 return (NULL); 241 242 while (acl_get_entry(aclp, entry_id, &entry) == 1) { 243 entry_id = ACL_NEXT_ENTRY; 244 245 assert(off < size); 246 247 error = format_entry(str + off, size - off, entry, flags); 248 if (error) { 249 free(str); 250 errno = EINVAL; 251 return (NULL); 252 } 253 254 off = strlen(str); 255 } 256 257 assert(off < size); 258 str[off] = '\0'; 259 260 if (len_p != NULL) 261 *len_p = off; 262 263 return (str); 264 } 265