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