1194955Strasz/*- 2194955Strasz * Copyright (c) 2008, 2009 Edward Tomasz Napiera��a <trasz@FreeBSD.org> 3194955Strasz * All rights reserved. 4194955Strasz * 5194955Strasz * Redistribution and use in source and binary forms, with or without 6194955Strasz * modification, are permitted provided that the following conditions 7194955Strasz * are met: 8194955Strasz * 1. Redistributions of source code must retain the above copyright 9194955Strasz * notice, this list of conditions and the following disclaimer. 10194955Strasz * 2. Redistributions in binary form must reproduce the above copyright 11194955Strasz * notice, this list of conditions and the following disclaimer in the 12194955Strasz * documentation and/or other materials provided with the distribution. 13194955Strasz * 14194955Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194955Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194955Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194955Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194955Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194955Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194955Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194955Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194955Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194955Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194955Strasz * SUCH DAMAGE. 25194955Strasz */ 26194955Strasz 27194955Strasz#include <sys/cdefs.h> 28194955Strasz__FBSDID("$FreeBSD$"); 29194955Strasz 30194955Strasz#include <stdio.h> 31194955Strasz#include <stdlib.h> 32194955Strasz#include <unistd.h> 33194955Strasz#include <errno.h> 34194955Strasz#include <assert.h> 35194955Strasz#include <string.h> 36194955Strasz#include <pwd.h> 37194955Strasz#include <grp.h> 38194955Strasz#include <sys/syscall.h> 39194955Strasz#include <sys/types.h> 40194955Strasz#include <sys/acl.h> 41194955Strasz 42194955Strasz#include "acl_support.h" 43194955Strasz 44194955Strasz#define MAX_ENTRY_LENGTH 512 45194955Strasz 46194955Straszstatic int 47194955Straszformat_who(char *str, size_t size, const acl_entry_t entry, int numeric) 48194955Strasz{ 49194955Strasz int error; 50194955Strasz acl_tag_t tag; 51194955Strasz struct passwd *pwd; 52194955Strasz struct group *grp; 53208811Strasz uid_t *id; 54194955Strasz 55194955Strasz error = acl_get_tag_type(entry, &tag); 56194955Strasz if (error) 57194955Strasz return (error); 58194955Strasz 59194955Strasz switch (tag) { 60194955Strasz case ACL_USER_OBJ: 61194955Strasz snprintf(str, size, "owner@"); 62194955Strasz break; 63194955Strasz 64194955Strasz case ACL_USER: 65208811Strasz id = (uid_t *)acl_get_qualifier(entry); 66194955Strasz if (id == NULL) 67194955Strasz return (-1); 68194955Strasz /* XXX: Thread-unsafe. */ 69194955Strasz if (!numeric) 70194955Strasz pwd = getpwuid(*id); 71194955Strasz else 72194955Strasz pwd = NULL; 73194955Strasz if (pwd == NULL) 74194955Strasz snprintf(str, size, "user:%d", (unsigned int)*id); 75194955Strasz else 76194955Strasz snprintf(str, size, "user:%s", pwd->pw_name); 77194955Strasz break; 78194955Strasz 79194955Strasz case ACL_GROUP_OBJ: 80194955Strasz snprintf(str, size, "group@"); 81194955Strasz break; 82194955Strasz 83194955Strasz case ACL_GROUP: 84208811Strasz id = (uid_t *)acl_get_qualifier(entry); 85194955Strasz if (id == NULL) 86194955Strasz return (-1); 87194955Strasz /* XXX: Thread-unsafe. */ 88194955Strasz if (!numeric) 89194955Strasz grp = getgrgid(*id); 90194955Strasz else 91194955Strasz grp = NULL; 92194955Strasz if (grp == NULL) 93194955Strasz snprintf(str, size, "group:%d", (unsigned int)*id); 94194955Strasz else 95194955Strasz snprintf(str, size, "group:%s", grp->gr_name); 96194955Strasz break; 97194955Strasz 98194955Strasz case ACL_EVERYONE: 99194955Strasz snprintf(str, size, "everyone@"); 100194955Strasz break; 101194955Strasz 102194955Strasz default: 103194955Strasz return (-1); 104194955Strasz } 105194955Strasz 106194955Strasz return (0); 107194955Strasz} 108194955Strasz 109194955Straszstatic int 110194955Straszformat_entry_type(char *str, size_t size, const acl_entry_t entry) 111194955Strasz{ 112194955Strasz int error; 113194955Strasz acl_entry_type_t entry_type; 114194955Strasz 115194955Strasz error = acl_get_entry_type_np(entry, &entry_type); 116194955Strasz if (error) 117194955Strasz return (error); 118194955Strasz 119194955Strasz switch (entry_type) { 120194955Strasz case ACL_ENTRY_TYPE_ALLOW: 121194955Strasz snprintf(str, size, "allow"); 122194955Strasz break; 123194955Strasz case ACL_ENTRY_TYPE_DENY: 124194955Strasz snprintf(str, size, "deny"); 125194955Strasz break; 126194955Strasz case ACL_ENTRY_TYPE_AUDIT: 127194955Strasz snprintf(str, size, "audit"); 128194955Strasz break; 129194955Strasz case ACL_ENTRY_TYPE_ALARM: 130194955Strasz snprintf(str, size, "alarm"); 131194955Strasz break; 132194955Strasz default: 133194955Strasz return (-1); 134194955Strasz } 135194955Strasz 136194955Strasz return (0); 137194955Strasz} 138194955Strasz 139194955Straszstatic int 140194955Straszformat_additional_id(char *str, size_t size, const acl_entry_t entry) 141194955Strasz{ 142194955Strasz int error; 143194955Strasz acl_tag_t tag; 144208811Strasz uid_t *id; 145194955Strasz 146194955Strasz error = acl_get_tag_type(entry, &tag); 147194955Strasz if (error) 148194955Strasz return (error); 149194955Strasz 150194955Strasz switch (tag) { 151194955Strasz case ACL_USER_OBJ: 152194955Strasz case ACL_GROUP_OBJ: 153194955Strasz case ACL_EVERYONE: 154194955Strasz str[0] = '\0'; 155194955Strasz break; 156194955Strasz 157194955Strasz default: 158208811Strasz id = (uid_t *)acl_get_qualifier(entry); 159194955Strasz if (id == NULL) 160194955Strasz return (-1); 161194955Strasz snprintf(str, size, ":%d", (unsigned int)*id); 162194955Strasz } 163194955Strasz 164194955Strasz return (0); 165194955Strasz} 166194955Strasz 167194955Straszstatic int 168194955Straszformat_entry(char *str, size_t size, const acl_entry_t entry, int flags) 169194955Strasz{ 170205796Strasz size_t off = 0, min_who_field_length = 18; 171194955Strasz acl_permset_t permset; 172194955Strasz acl_flagset_t flagset; 173194955Strasz int error, len; 174194955Strasz char buf[MAX_ENTRY_LENGTH + 1]; 175194955Strasz 176194955Strasz assert(_entry_brand(entry) == ACL_BRAND_NFS4); 177194955Strasz 178194955Strasz error = acl_get_flagset_np(entry, &flagset); 179194955Strasz if (error) 180194955Strasz return (error); 181194955Strasz 182194955Strasz error = acl_get_permset(entry, &permset); 183194955Strasz if (error) 184194955Strasz return (error); 185194955Strasz 186194955Strasz error = format_who(buf, sizeof(buf), entry, 187194955Strasz flags & ACL_TEXT_NUMERIC_IDS); 188194955Strasz if (error) 189194955Strasz return (error); 190194955Strasz len = strlen(buf); 191205796Strasz if (len < min_who_field_length) 192205796Strasz len = min_who_field_length; 193205796Strasz off += snprintf(str + off, size - off, "%*s:", len, buf); 194194955Strasz 195194955Strasz error = _nfs4_format_access_mask(buf, sizeof(buf), *permset, 196194955Strasz flags & ACL_TEXT_VERBOSE); 197194955Strasz if (error) 198194955Strasz return (error); 199194955Strasz off += snprintf(str + off, size - off, "%s:", buf); 200194955Strasz 201194955Strasz error = _nfs4_format_flags(buf, sizeof(buf), *flagset, 202194955Strasz flags & ACL_TEXT_VERBOSE); 203194955Strasz if (error) 204194955Strasz return (error); 205194955Strasz off += snprintf(str + off, size - off, "%s:", buf); 206194955Strasz 207194955Strasz error = format_entry_type(buf, sizeof(buf), entry); 208194955Strasz if (error) 209194955Strasz return (error); 210194955Strasz off += snprintf(str + off, size - off, "%s", buf); 211194955Strasz 212194955Strasz if (flags & ACL_TEXT_APPEND_ID) { 213194955Strasz error = format_additional_id(buf, sizeof(buf), entry); 214194955Strasz if (error) 215194955Strasz return (error); 216194955Strasz off += snprintf(str + off, size - off, "%s", buf); 217194955Strasz } 218194955Strasz 219194955Strasz off += snprintf(str + off, size - off, "\n"); 220194955Strasz 221194955Strasz /* Make sure we didn't truncate anything. */ 222194955Strasz assert (off < size); 223194955Strasz 224194955Strasz return (0); 225194955Strasz} 226194955Strasz 227194955Straszchar * 228194955Strasz_nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags) 229194955Strasz{ 230194955Strasz int error, off = 0, size, entry_id = ACL_FIRST_ENTRY; 231194955Strasz char *str; 232194955Strasz acl_entry_t entry; 233194955Strasz 234194955Strasz if (aclp->ats_acl.acl_cnt == 0) 235194955Strasz return strdup(""); 236194955Strasz 237194955Strasz size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH; 238194955Strasz str = malloc(size); 239194955Strasz if (str == NULL) 240194955Strasz return (NULL); 241194955Strasz 242194955Strasz while (acl_get_entry(aclp, entry_id, &entry) == 1) { 243194955Strasz entry_id = ACL_NEXT_ENTRY; 244194955Strasz 245194955Strasz assert(off < size); 246194955Strasz 247194955Strasz error = format_entry(str + off, size - off, entry, flags); 248194955Strasz if (error) { 249208786Strasz free(str); 250194955Strasz errno = EINVAL; 251194955Strasz return (NULL); 252194955Strasz } 253194955Strasz 254194955Strasz off = strlen(str); 255194955Strasz } 256194955Strasz 257194955Strasz assert(off < size); 258194955Strasz str[off] = '\0'; 259194955Strasz 260194955Strasz if (len_p != NULL) 261194955Strasz *len_p = off; 262194955Strasz 263194955Strasz return (str); 264194955Strasz} 265