1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1999-2002 Robert N. M. Watson 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 * acl_to_text - return a text string with a text representation of the acl 30 * in it. 31 */ 32 33 #include <sys/cdefs.h> 34 #if 0 35 __FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_to_text.c 326193 2017-11-25 17:12:48Z pfg $"); 36 #else 37 __RCSID("$NetBSD: acl_to_text.c,v 1.1 2020/05/16 18:31:47 christos Exp $"); 38 #endif 39 40 #include "namespace.h" 41 #include <sys/types.h> 42 #include <sys/acl.h> 43 #include <errno.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 48 #include "acl_support.h" 49 50 /* 51 * acl_to_text - generate a text form of an acl 52 * spec says nothing about output ordering, so leave in acl order 53 * 54 * This function will not produce nice results if it is called with 55 * a non-POSIX.1e semantics ACL. 56 */ 57 58 char *_nfs4_acl_to_text_np(const acl_t acl, ssize_t *len_p, int flags); 59 60 static char * 61 _posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags) 62 { 63 struct acl *acl_int; 64 char *buf, *tmpbuf; 65 char name_buf[MAXLOGNAME]; 66 char perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1], 67 effective_perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1]; 68 size_t i; 69 int error, len; 70 uid_t ae_id; 71 acl_tag_t ae_tag; 72 acl_perm_t ae_perm, effective_perm, mask_perm; 73 74 buf = strdup(""); 75 if (buf == NULL) 76 return(NULL); 77 78 acl_int = &acl->ats_acl; 79 80 mask_perm = ACL_PERM_BITS; /* effective is regular if no mask */ 81 for (i = 0; i < acl_int->acl_cnt; i++) 82 if (acl_int->acl_entry[i].ae_tag == ACL_MASK) 83 mask_perm = acl_int->acl_entry[i].ae_perm; 84 85 for (i = 0; i < acl_int->acl_cnt; i++) { 86 ae_tag = acl_int->acl_entry[i].ae_tag; 87 ae_id = acl_int->acl_entry[i].ae_id; 88 ae_perm = acl_int->acl_entry[i].ae_perm; 89 90 switch(ae_tag) { 91 case ACL_USER_OBJ: 92 error = _posix1e_acl_perm_to_string(ae_perm, 93 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf); 94 if (error) 95 goto error_label; 96 len = asprintf(&tmpbuf, "%suser::%s\n", buf, 97 perm_buf); 98 if (len == -1) 99 goto error_label; 100 free(buf); 101 buf = tmpbuf; 102 break; 103 104 case ACL_USER: 105 error = _posix1e_acl_perm_to_string(ae_perm, 106 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf); 107 if (error) 108 goto error_label; 109 110 error = _posix1e_acl_id_to_name(ae_tag, ae_id, 111 MAXLOGNAME, name_buf, flags); 112 if (error) 113 goto error_label; 114 115 effective_perm = ae_perm & mask_perm; 116 if (effective_perm != ae_perm) { 117 error = _posix1e_acl_perm_to_string( 118 effective_perm, 119 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, 120 effective_perm_buf); 121 if (error) 122 goto error_label; 123 len = asprintf(&tmpbuf, "%suser:%s:%s\t\t# " 124 "effective: %s\n", 125 buf, name_buf, perm_buf, 126 effective_perm_buf); 127 } else { 128 len = asprintf(&tmpbuf, "%suser:%s:%s\n", buf, 129 name_buf, perm_buf); 130 } 131 if (len == -1) 132 goto error_label; 133 free(buf); 134 buf = tmpbuf; 135 break; 136 137 case ACL_GROUP_OBJ: 138 error = _posix1e_acl_perm_to_string(ae_perm, 139 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf); 140 if (error) 141 goto error_label; 142 143 effective_perm = ae_perm & mask_perm; 144 if (effective_perm != ae_perm) { 145 error = _posix1e_acl_perm_to_string( 146 effective_perm, 147 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, 148 effective_perm_buf); 149 if (error) 150 goto error_label; 151 len = asprintf(&tmpbuf, "%sgroup::%s\t\t# " 152 "effective: %s\n", 153 buf, perm_buf, effective_perm_buf); 154 } else { 155 len = asprintf(&tmpbuf, "%sgroup::%s\n", buf, 156 perm_buf); 157 } 158 if (len == -1) 159 goto error_label; 160 free(buf); 161 buf = tmpbuf; 162 break; 163 164 case ACL_GROUP: 165 error = _posix1e_acl_perm_to_string(ae_perm, 166 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf); 167 if (error) 168 goto error_label; 169 170 error = _posix1e_acl_id_to_name(ae_tag, ae_id, 171 MAXLOGNAME, name_buf, flags); 172 if (error) 173 goto error_label; 174 175 effective_perm = ae_perm & mask_perm; 176 if (effective_perm != ae_perm) { 177 error = _posix1e_acl_perm_to_string( 178 effective_perm, 179 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, 180 effective_perm_buf); 181 if (error) 182 goto error_label; 183 len = asprintf(&tmpbuf, "%sgroup:%s:%s\t\t# " 184 "effective: %s\n", 185 buf, name_buf, perm_buf, 186 effective_perm_buf); 187 } else { 188 len = asprintf(&tmpbuf, "%sgroup:%s:%s\n", buf, 189 name_buf, perm_buf); 190 } 191 if (len == -1) 192 goto error_label; 193 free(buf); 194 buf = tmpbuf; 195 break; 196 197 case ACL_MASK: 198 error = _posix1e_acl_perm_to_string(ae_perm, 199 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf); 200 if (error) 201 goto error_label; 202 203 len = asprintf(&tmpbuf, "%smask::%s\n", buf, 204 perm_buf); 205 if (len == -1) 206 goto error_label; 207 free(buf); 208 buf = tmpbuf; 209 break; 210 211 case ACL_OTHER: 212 error = _posix1e_acl_perm_to_string(ae_perm, 213 _POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf); 214 if (error) 215 goto error_label; 216 217 len = asprintf(&tmpbuf, "%sother::%s\n", buf, 218 perm_buf); 219 if (len == -1) 220 goto error_label; 221 free(buf); 222 buf = tmpbuf; 223 break; 224 225 default: 226 errno = EINVAL; 227 goto error_label; 228 } 229 } 230 231 if (len_p) { 232 *len_p = strlen(buf); 233 } 234 return (buf); 235 236 error_label: 237 /* jump to here sets errno already, we just clean up */ 238 if (buf) free(buf); 239 return (NULL); 240 } 241 242 char * 243 acl_to_text_np(acl_t acl, ssize_t *len_p, int flags) 244 { 245 246 if (acl == NULL) { 247 errno = EINVAL; 248 return(NULL); 249 } 250 251 switch (_acl_brand(acl)) { 252 case ACL_BRAND_POSIX: 253 return (_posix1e_acl_to_text(acl, len_p, flags)); 254 case ACL_BRAND_NFS4: 255 return (_nfs4_acl_to_text_np(acl, len_p, flags)); 256 default: 257 errno = EINVAL; 258 return (NULL); 259 } 260 } 261 262 char * 263 acl_to_text(acl_t acl, ssize_t *len_p) 264 { 265 266 return (acl_to_text_np(acl, len_p, 0)); 267 } 268