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.2 2024/01/20 14:52:48 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 52static int 53format_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 115static int 116format_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 145static int 146format_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 173static int 174format_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 size_t 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:", (int)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 234char * 235_nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags) 236{ 237 int error, entry_id = ACL_FIRST_ENTRY; 238 size_t off = 0, size; 239 char *str; 240 acl_entry_t entry; 241 242 if (aclp->ats_acl.acl_cnt == 0) 243 return strdup(""); 244 245 size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH; 246 str = malloc(size); 247 if (str == NULL) 248 return (NULL); 249 250 while (acl_get_entry(aclp, entry_id, &entry) == 1) { 251 entry_id = ACL_NEXT_ENTRY; 252 253 assert(off < size); 254 255 error = format_entry(str + off, size - off, entry, flags); 256 if (error) { 257 free(str); 258 errno = EINVAL; 259 return (NULL); 260 } 261 262 off = strlen(str); 263 } 264 265 assert(off < size); 266 str[off] = '\0'; 267 268 if (len_p != NULL) 269 *len_p = off; 270 271 return (str); 272} 273