1/* $NetBSD: extattr.c,v 1.2 2005/02/09 21:35:46 kleink 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.2 2005/02/09 21:35:46 kleink 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 int 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 < 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 if (aval != NULL) 164 free(aval); 165 166 if (alist != NULL) 167 free(alist); 168 169 return error; 170} 171 172int 173extattr_copy_file(const char *from, const char *to, int namespace) 174{ 175 ssize_t llen, vlen, maxvlen; 176 size_t alen; 177 void *alist = NULL; 178 void *aval = NULL; 179 int i; 180 int error = -1; 181 182 llen = extattr_list_file(from, namespace, NULL, 0); 183 if (llen == -1) { 184 /* Silently ignore when EA are not supported */ 185 if (errno == EOPNOTSUPP) 186 error = 0; 187 goto out; 188 } 189 190 if (llen == 0) { 191 error = 0; 192 goto out; 193 } 194 195 if ((alist = malloc((size_t)llen)) == NULL) 196 goto out; 197 198 llen = extattr_list_file(from, namespace, alist, (size_t)llen); 199 if (llen == -1) 200 goto out; 201 202 maxvlen = 1024; 203 if ((aval = malloc((size_t)maxvlen)) == NULL) 204 goto out; 205 206 for (i = 0; i < llen; i += alen + 1) { 207 char aname[NAME_MAX + 1]; 208 char *ap; 209 210 alen = ((uint8_t *)alist)[i]; 211 ap = ((char *)alist) + i + 1; 212 (void)memcpy(aname, ap, alen); 213 aname[alen] = '\0'; 214 215 vlen = extattr_get_file(from, namespace, aname, NULL, 0); 216 if (vlen == -1) 217 goto out; 218 219 if (vlen > maxvlen) { 220 if ((aval = realloc(aval, (size_t)vlen)) == NULL) 221 goto out; 222 maxvlen = vlen; 223 } 224 225 if ((vlen = extattr_get_file(from, namespace, aname, aval, (size_t)vlen)) == -1) 226 goto out; 227 228 if (extattr_set_file(to, namespace, aname, 229 aval, (size_t)vlen) != vlen) 230 goto out; 231 } 232 233 error = 0; 234out: 235 if (aval != NULL) 236 free(aval); 237 238 if (alist != NULL) 239 free(alist); 240 241 return error; 242} 243 244int 245extattr_copy_link(const char *from, const char *to, int namespace) 246{ 247 ssize_t llen, vlen, maxvlen; 248 size_t alen; 249 void *alist = NULL; 250 void *aval = NULL; 251 int i; 252 int error = -1; 253 254 llen = extattr_list_link(from, namespace, NULL, 0); 255 if (llen == -1) { 256 /* Silently ignore when EA are not supported */ 257 if (errno == EOPNOTSUPP) 258 error = 0; 259 goto out; 260 } 261 262 if (llen == 0) { 263 error = 0; 264 goto out; 265 } 266 267 if ((alist = malloc((size_t)llen)) == NULL) 268 goto out; 269 270 llen = extattr_list_link(from, namespace, alist, (size_t)llen); 271 if (llen == -1) 272 goto out; 273 274 maxvlen = 1024; 275 if ((aval = malloc((size_t)maxvlen)) == NULL) 276 goto out; 277 278 for (i = 0; i < llen; i += alen + 1) { 279 char aname[NAME_MAX + 1]; 280 char *ap; 281 282 alen = ((uint8_t *)alist)[i]; 283 ap = ((char *)alist) + i + 1; 284 (void)memcpy(aname, ap, alen); 285 aname[alen] = '\0'; 286 287 vlen = extattr_get_link(from, namespace, aname, NULL, 0); 288 if (vlen == -1) 289 goto out; 290 291 if (vlen > maxvlen) { 292 if ((aval = realloc(aval, (size_t)vlen)) == NULL) 293 goto out; 294 maxvlen = vlen; 295 } 296 297 if ((vlen = extattr_get_link(from, namespace, aname, 298 aval, (size_t)vlen)) == -1) 299 goto out; 300 301 if (extattr_set_link(to, namespace, aname, 302 aval, (size_t)vlen) != vlen) 303 goto out; 304 } 305 306 error = 0; 307out: 308 if (aval != NULL) 309 free(aval); 310 311 if (alist != NULL) 312 free(alist); 313 314 return error; 315} 316 317static int 318extattr_namespace_access(int namespace, int mode) 319{ 320 switch (namespace) { 321 case EXTATTR_NAMESPACE_SYSTEM: 322 if ((mode & (R_OK|W_OK)) && getuid() != 0) 323 return -1; 324 break; 325 default: 326 break; 327 } 328 329 return 0; 330} 331 332int 333fcpxattr(int from_fd, int to_fd) 334{ 335 const int *ns; 336 int error; 337 338 for (ns = extattr_namespaces; *ns; ns++) { 339 if (extattr_namespace_access(*ns, R_OK|W_OK) != 0) 340 continue; 341 342 if ((error = extattr_copy_fd(from_fd, to_fd, *ns)) != 0) 343 return error; 344 } 345 346 return 0; 347} 348 349int 350cpxattr(const char *from, const char *to) 351{ 352 const int *ns; 353 int error; 354 355 for (ns = extattr_namespaces; *ns; ns++) { 356 if (extattr_namespace_access(*ns, R_OK|W_OK) != 0) 357 continue; 358 359 if ((error = extattr_copy_file(from, to, *ns)) != 0) 360 return error; 361 } 362 363 return 0; 364} 365 366int 367lcpxattr(const char *from, const char *to) 368{ 369 const int *ns; 370 int error; 371 372 for (ns = extattr_namespaces; *ns; ns++) { 373 if (extattr_namespace_access(*ns, R_OK|W_OK) != 0) 374 continue; 375 376 if ((error = extattr_copy_link(from, to, *ns)) != 0) 377 return error; 378 } 379 380 return 0; 381} 382