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