1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <errno.h> 36 #include <assert.h> 37 #include <string.h> 38 #include <pwd.h> 39 #include <grp.h> 40 #include <sys/syscall.h> 41 #include <sys/types.h> 42 #include <sys/acl.h> 43 44 #include "acl_support.h" 45 46 #define MAX_ENTRY_LENGTH 512 47 48 static int 49 format_who(char *str, size_t size, const acl_entry_t entry, int numeric) 50 { 51 int error; 52 acl_tag_t tag; 53 struct passwd *pwd; 54 struct group *grp; 55 uid_t *id; 56 57 error = acl_get_tag_type(entry, &tag); 58 if (error) 59 return (error); 60 61 switch (tag) { 62 case ACL_USER_OBJ: 63 snprintf(str, size, "owner@"); 64 break; 65 66 case ACL_USER: 67 id = (uid_t *)acl_get_qualifier(entry); 68 if (id == NULL) 69 return (-1); 70 /* XXX: Thread-unsafe. */ 71 if (!numeric) 72 pwd = getpwuid(*id); 73 else 74 pwd = NULL; 75 if (pwd == NULL) 76 snprintf(str, size, "user:%d", (unsigned int)*id); 77 else 78 snprintf(str, size, "user:%s", pwd->pw_name); 79 break; 80 81 case ACL_GROUP_OBJ: 82 snprintf(str, size, "group@"); 83 break; 84 85 case ACL_GROUP: 86 id = (uid_t *)acl_get_qualifier(entry); 87 if (id == NULL) 88 return (-1); 89 /* XXX: Thread-unsafe. */ 90 if (!numeric) 91 grp = getgrgid(*id); 92 else 93 grp = NULL; 94 if (grp == NULL) 95 snprintf(str, size, "group:%d", (unsigned int)*id); 96 else 97 snprintf(str, size, "group:%s", grp->gr_name); 98 break; 99 100 case ACL_EVERYONE: 101 snprintf(str, size, "everyone@"); 102 break; 103 104 default: 105 return (-1); 106 } 107 108 return (0); 109 } 110 111 static int 112 format_entry_type(char *str, size_t size, const acl_entry_t entry) 113 { 114 int error; 115 acl_entry_type_t entry_type; 116 117 error = acl_get_entry_type_np(entry, &entry_type); 118 if (error) 119 return (error); 120 121 switch (entry_type) { 122 case ACL_ENTRY_TYPE_ALLOW: 123 snprintf(str, size, "allow"); 124 break; 125 case ACL_ENTRY_TYPE_DENY: 126 snprintf(str, size, "deny"); 127 break; 128 case ACL_ENTRY_TYPE_AUDIT: 129 snprintf(str, size, "audit"); 130 break; 131 case ACL_ENTRY_TYPE_ALARM: 132 snprintf(str, size, "alarm"); 133 break; 134 default: 135 return (-1); 136 } 137 138 return (0); 139 } 140 141 static int 142 format_additional_id(char *str, size_t size, const acl_entry_t entry) 143 { 144 int error; 145 acl_tag_t tag; 146 uid_t *id; 147 148 error = acl_get_tag_type(entry, &tag); 149 if (error) 150 return (error); 151 152 switch (tag) { 153 case ACL_USER_OBJ: 154 case ACL_GROUP_OBJ: 155 case ACL_EVERYONE: 156 str[0] = '\0'; 157 break; 158 159 default: 160 id = (uid_t *)acl_get_qualifier(entry); 161 if (id == NULL) 162 return (-1); 163 snprintf(str, size, ":%d", (unsigned int)*id); 164 } 165 166 return (0); 167 } 168 169 static int 170 format_entry(char *str, size_t size, const acl_entry_t entry, int flags) 171 { 172 size_t off = 0, min_who_field_length = 18; 173 acl_permset_t permset; 174 acl_flagset_t flagset; 175 int error, len; 176 char buf[MAX_ENTRY_LENGTH + 1]; 177 178 assert(_entry_brand(entry) == ACL_BRAND_NFS4); 179 180 error = acl_get_flagset_np(entry, &flagset); 181 if (error) 182 return (error); 183 184 error = acl_get_permset(entry, &permset); 185 if (error) 186 return (error); 187 188 error = format_who(buf, sizeof(buf), entry, 189 flags & ACL_TEXT_NUMERIC_IDS); 190 if (error) 191 return (error); 192 len = strlen(buf); 193 if (len < min_who_field_length) 194 len = min_who_field_length; 195 off += snprintf(str + off, size - off, "%*s:", len, buf); 196 197 error = _nfs4_format_access_mask(buf, sizeof(buf), *permset, 198 flags & ACL_TEXT_VERBOSE); 199 if (error) 200 return (error); 201 off += snprintf(str + off, size - off, "%s:", buf); 202 203 error = _nfs4_format_flags(buf, sizeof(buf), *flagset, 204 flags & ACL_TEXT_VERBOSE); 205 if (error) 206 return (error); 207 off += snprintf(str + off, size - off, "%s:", buf); 208 209 error = format_entry_type(buf, sizeof(buf), entry); 210 if (error) 211 return (error); 212 off += snprintf(str + off, size - off, "%s", buf); 213 214 if (flags & ACL_TEXT_APPEND_ID) { 215 error = format_additional_id(buf, sizeof(buf), entry); 216 if (error) 217 return (error); 218 off += snprintf(str + off, size - off, "%s", buf); 219 } 220 221 off += snprintf(str + off, size - off, "\n"); 222 223 /* Make sure we didn't truncate anything. */ 224 assert (off < size); 225 226 return (0); 227 } 228 229 char * 230 _nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags) 231 { 232 int error, off = 0, size, entry_id = ACL_FIRST_ENTRY; 233 char *str; 234 acl_entry_t entry; 235 236 if (aclp->ats_acl.acl_cnt == 0) 237 return strdup(""); 238 239 size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH; 240 str = malloc(size); 241 if (str == NULL) 242 return (NULL); 243 244 while (acl_get_entry(aclp, entry_id, &entry) == 1) { 245 entry_id = ACL_NEXT_ENTRY; 246 247 assert(off < size); 248 249 error = format_entry(str + off, size - off, entry, flags); 250 if (error) { 251 free(str); 252 errno = EINVAL; 253 return (NULL); 254 } 255 256 off = strlen(str); 257 } 258 259 assert(off < size); 260 str[off] = '\0'; 261 262 if (len_p != NULL) 263 *len_p = off; 264 265 return (str); 266 } 267