1/* $NetBSD: extattr.c,v 1.5 2017/03/09 11:39:41 maya Exp $ */ 2 3/*- 4 * Copyright (c) 2001 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/* 30 * TrustedBSD: Utility functions for extended attributes. 31 */ 32 33#include <sys/cdefs.h> 34#if defined(LIBC_SCCS) && !defined(lint) 35__RCSID("$NetBSD: extattr.c,v 1.5 2017/03/09 11:39:41 maya Exp $"); 36#endif /* LIBC_SCCS and not lint */ 37 38#include "namespace.h" 39#include <sys/types.h> 40#include <sys/param.h> 41#include <sys/extattr.h> 42 43#include <errno.h> 44#include <unistd.h> 45#include <stdlib.h> 46#include <string.h> 47 48const int extattr_namespaces[] = { 49 EXTATTR_NAMESPACE_USER, 50 EXTATTR_NAMESPACE_SYSTEM, 51 0, 52}; 53 54int 55extattr_namespace_to_string(int attrnamespace, char **string) 56{ 57 58 switch(attrnamespace) { 59 case EXTATTR_NAMESPACE_USER: 60 if (string != NULL) { 61 if ((*string = 62 strdup(EXTATTR_NAMESPACE_USER_STRING)) == NULL) 63 return (-1); 64 } 65 return (0); 66 67 case EXTATTR_NAMESPACE_SYSTEM: 68 if (string != NULL) 69 if ((*string = 70 strdup(EXTATTR_NAMESPACE_SYSTEM_STRING)) == NULL) 71 return (-1); 72 return (0); 73 74 default: 75 errno = EINVAL; 76 return (-1); 77 } 78} 79 80int 81extattr_string_to_namespace(const char *string, int *attrnamespace) 82{ 83 84 if (strcmp(string, EXTATTR_NAMESPACE_USER_STRING) == 0) { 85 if (attrnamespace != NULL) 86 *attrnamespace = EXTATTR_NAMESPACE_USER; 87 return (0); 88 } else if (strcmp(string, EXTATTR_NAMESPACE_SYSTEM_STRING) == 0) { 89 if (attrnamespace != NULL) 90 *attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 91 return (0); 92 } else { 93 errno = EINVAL; 94 return (-1); 95 } 96} 97 98 99int 100extattr_copy_fd(int from_fd, int to_fd, int namespace) 101{ 102 ssize_t llen, vlen, maxvlen; 103 size_t alen; 104 void *alist = NULL; 105 void *aval = NULL; 106 size_t i; 107 int error = -1; 108 109 llen = extattr_list_fd(from_fd, namespace, NULL, 0); 110 if (llen == -1) { 111 /* Silently ignore when EA are not supported */ 112 if (errno == EOPNOTSUPP) 113 error = 0; 114 goto out; 115 } 116 117 if (llen == 0) { 118 error = 0; 119 goto out; 120 } 121 122 if ((alist = malloc((size_t)llen)) == NULL) 123 goto out; 124 125 llen = extattr_list_fd(from_fd, namespace, alist, (size_t)llen); 126 if (llen == -1) 127 goto out; 128 129 maxvlen = 1024; 130 if ((aval = malloc((size_t)maxvlen)) == NULL) 131 goto out; 132 133 for (i = 0; i < (size_t)llen; i += alen + 1) { 134 char aname[NAME_MAX + 1]; 135 char *ap; 136 137 alen = ((uint8_t *)alist)[i]; 138 ap = ((char *)alist) + i + 1; 139 (void)memcpy(aname, ap, alen); 140 aname[alen] = '\0'; 141 142 vlen = extattr_get_fd(from_fd, namespace, aname, NULL, 0); 143 if (vlen == -1) 144 goto out; 145 146 if (vlen > maxvlen) { 147 if ((aval = realloc(aval, (size_t)vlen)) == NULL) 148 goto out; 149 maxvlen = vlen; 150 } 151 152 if ((vlen = extattr_get_fd(from_fd, namespace, aname, 153 aval, (size_t)vlen)) == -1) 154 goto out; 155 156 if (extattr_set_fd(to_fd, namespace, aname, 157 aval, (size_t)vlen) != vlen) 158 goto out; 159 } 160 161 error = 0; 162out: 163 free(aval); 164 free(alist); 165 166 return error; 167} 168 169int 170extattr_copy_file(const char *from, const char *to, int namespace) 171{ 172 ssize_t llen, vlen, maxvlen; 173 size_t alen; 174 void *alist = NULL; 175 void *aval = NULL; 176 size_t i; 177 int error = -1; 178 179 llen = extattr_list_file(from, namespace, NULL, 0); 180 if (llen == -1) { 181 /* Silently ignore when EA are not supported */ 182 if (errno == EOPNOTSUPP) 183 error = 0; 184 goto out; 185 } 186 187 if (llen == 0) { 188 error = 0; 189 goto out; 190 } 191 192 if ((alist = malloc((size_t)llen)) == NULL) 193 goto out; 194 195 llen = extattr_list_file(from, namespace, alist, (size_t)llen); 196 if (llen == -1) 197 goto out; 198 199 maxvlen = 1024; 200 if ((aval = malloc((size_t)maxvlen)) == NULL) 201 goto out; 202 203 for (i = 0; i < (size_t)llen; i += alen + 1) { 204 char aname[NAME_MAX + 1]; 205 char *ap; 206 207 alen = ((uint8_t *)alist)[i]; 208 ap = ((char *)alist) + i + 1; 209 (void)memcpy(aname, ap, alen); 210 aname[alen] = '\0'; 211 212 vlen = extattr_get_file(from, namespace, aname, NULL, 0); 213 if (vlen == -1) 214 goto out; 215 216 if (vlen > maxvlen) { 217 if ((aval = realloc(aval, (size_t)vlen)) == NULL) 218 goto out; 219 maxvlen = vlen; 220 } 221 222 if ((vlen = extattr_get_file(from, namespace, aname, 223 aval, (size_t)vlen)) == -1) 224 goto out; 225 226 if (extattr_set_file(to, namespace, aname, 227 aval, (size_t)vlen) != vlen) 228 goto out; 229 } 230 231 error = 0; 232out: 233 free(aval); 234 free(alist); 235 236 return error; 237} 238 239int 240extattr_copy_link(const char *from, const char *to, int namespace) 241{ 242 ssize_t llen, vlen, maxvlen; 243 size_t alen; 244 void *alist = NULL; 245 void *aval = NULL; 246 size_t i; 247 int error = -1; 248 249 llen = extattr_list_link(from, namespace, NULL, 0); 250 if (llen == -1) { 251 /* Silently ignore when EA are not supported */ 252 if (errno == EOPNOTSUPP) 253 error = 0; 254 goto out; 255 } 256 257 if (llen == 0) { 258 error = 0; 259 goto out; 260 } 261 262 if ((alist = malloc((size_t)llen)) == NULL) 263 goto out; 264 265 llen = extattr_list_link(from, namespace, alist, (size_t)llen); 266 if (llen == -1) 267 goto out; 268 269 maxvlen = 1024; 270 if ((aval = malloc((size_t)maxvlen)) == NULL) 271 goto out; 272 273 for (i = 0; i < (size_t)llen; i += alen + 1) { 274 char aname[NAME_MAX + 1]; 275 char *ap; 276 277 alen = ((uint8_t *)alist)[i]; 278 ap = ((char *)alist) + i + 1; 279 (void)memcpy(aname, ap, alen); 280 aname[alen] = '\0'; 281 282 vlen = extattr_get_link(from, namespace, aname, NULL, 0); 283 if (vlen == -1) 284 goto out; 285 286 if (vlen > maxvlen) { 287 if ((aval = realloc(aval, (size_t)vlen)) == NULL) 288 goto out; 289 maxvlen = vlen; 290 } 291 292 if ((vlen = extattr_get_link(from, namespace, aname, 293 aval, (size_t)vlen)) == -1) 294 goto out; 295 296 if (extattr_set_link(to, namespace, aname, 297 aval, (size_t)vlen) != vlen) 298 goto out; 299 } 300 301 error = 0; 302out: 303 free(aval); 304 free(alist); 305 306 return error; 307} 308 309static int 310extattr_namespace_access(int namespace, int mode) 311{ 312 switch (namespace) { 313 case EXTATTR_NAMESPACE_SYSTEM: 314 if ((mode & (R_OK|W_OK)) && getuid() != 0) 315 return -1; 316 break; 317 default: 318 break; 319 } 320 321 return 0; 322} 323 324int 325fcpxattr(int from_fd, int to_fd) 326{ 327 const int *ns; 328 int error; 329 330 for (ns = extattr_namespaces; *ns; ns++) { 331 if (extattr_namespace_access(*ns, R_OK|W_OK) != 0) 332 continue; 333 334 if ((error = extattr_copy_fd(from_fd, to_fd, *ns)) != 0) 335 return error; 336 } 337 338 return 0; 339} 340 341int 342cpxattr(const char *from, const char *to) 343{ 344 const int *ns; 345 int error; 346 347 for (ns = extattr_namespaces; *ns; ns++) { 348 if (extattr_namespace_access(*ns, R_OK|W_OK) != 0) 349 continue; 350 351 if ((error = extattr_copy_file(from, to, *ns)) != 0) 352 return error; 353 } 354 355 return 0; 356} 357 358int 359lcpxattr(const char *from, const char *to) 360{ 361 const int *ns; 362 int error; 363 364 for (ns = extattr_namespaces; *ns; ns++) { 365 if (extattr_namespace_access(*ns, R_OK|W_OK) != 0) 366 continue; 367 368 if ((error = extattr_copy_link(from, to, *ns)) != 0) 369 return error; 370 } 371 372 return 0; 373} 374