1 /* $NetBSD: getextattr.c,v 1.11 2014/06/20 14:55:31 manu Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2003 Networks Associates Technology, Inc. 5 * Copyright (c) 2002 Poul-Henning Kamp. 6 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 7 * All rights reserved. 8 * 9 * This software was developed for the FreeBSD Project by Poul-Henning 10 * Kamp and Network Associates Laboratories, the Security Research Division 11 * of Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 12 * ("CBOSS"), as part of the DARPA CHATS research program 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. The names of the authors may not be used to endorse or promote 23 * products derived from this software without specific prior written 24 * permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * FreeBSD: src/usr.sbin/extattr/rmextattr.c,v 1.6 2003/06/05 04:30:00 rwatson Exp 39 */ 40 41 #include <sys/types.h> 42 #include <sys/uio.h> 43 #include <sys/extattr.h> 44 45 #include <err.h> 46 #include <errno.h> 47 //#include <libgen.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include <vis.h> 53 #include <fcntl.h> 54 #include <sys/stat.h> 55 //#include <util.h> 56 57 static enum { EADUNNO, EAGET, EASET, EARM, EALS } what = EADUNNO; 58 59 __dead static void 60 usage(void) 61 { 62 63 switch (what) { 64 case EAGET: 65 fprintf(stderr, "usage: %s [-fhq] [-s | -x | -v style] " 66 "attrnamespace attrname filename ...\n", getprogname()); 67 exit(1); 68 69 case EASET: 70 fprintf(stderr, "usage: %s [-fhnq] " 71 "attrnamespace attrname attrvalue filename ...\n", 72 getprogname()); 73 fprintf(stderr, "usage: %s [-fhnq] -i attrvalue_file " 74 "attrnamespace attrname filename ...\n", 75 getprogname()); 76 exit(1); 77 78 case EARM: 79 fprintf(stderr, "usage: %s [-fhq] " 80 "attrnamespace attrname filename ...\n", getprogname()); 81 exit(1); 82 83 case EALS: 84 fprintf(stderr, "usage: %s [-fhq] " 85 "attrnamespace filename ...\n", getprogname()); 86 exit(1); 87 88 case EADUNNO: 89 default: 90 fprintf(stderr, 91 "usage: (getextattr|lsextattr|rmextattr|setextattr)\n"); 92 exit (1); 93 } 94 } 95 96 static void 97 mkbuf(char **buf, int *oldlen, int newlen) 98 { 99 100 if (*oldlen >= newlen) 101 return; 102 if (*buf != NULL) 103 free(*buf); 104 *buf = malloc(newlen); 105 if (*buf == NULL) 106 err(1, "malloc"); 107 *oldlen = newlen; 108 return; 109 } 110 111 static int 112 parse_flag_vis(const char *opt) 113 { 114 if (strcmp(opt, "default") == 0) 115 return 0; 116 else if (strcmp(opt, "cstyle") == 0) 117 return VIS_CSTYLE; 118 else if (strcmp(opt, "octal") == 0) 119 return VIS_OCTAL; 120 else if (strcmp(opt, "httpstyle") == 0) 121 return VIS_HTTPSTYLE; 122 123 /* Convenient aliases */ 124 else if (strcmp(opt, "vis") == 0) 125 return 0; 126 else if (strcmp(opt, "c") == 0) 127 return VIS_CSTYLE; 128 else if (strcmp(opt, "http") == 0) 129 return VIS_HTTPSTYLE; 130 else 131 fprintf(stderr, "%s: invalid -s option \"%s\"", 132 getprogname(), opt); 133 134 return -1; 135 } 136 137 #define HEXDUMP_PRINT(x) ((uint8_t)x >= 32 && (uint8_t)x < 128) ? x : '.' 138 static void 139 hexdump(const char *addr, size_t len) 140 { 141 unsigned int i, j; 142 143 for (i = 0; i < len; i += 16) { 144 printf(" %03x ", i); 145 for (j = 0; j < 16; j++) { 146 if (i + j >= len) 147 printf(" "); 148 else 149 printf("%02x ", addr[i + j] & 0xff); 150 } 151 printf(" "); 152 for (j = 0; j < 16; j++) { 153 if (i + j >= len) 154 printf(" "); 155 else 156 printf("%c", HEXDUMP_PRINT(addr[i + j])); 157 } 158 printf("\n"); 159 } 160 } 161 #undef HEXDUMP_PRINT 162 163 int 164 main(int argc, char *argv[]) 165 { 166 char *buf, *visbuf; 167 const char *p; 168 169 const char *options, *attrname; 170 int buflen, visbuflen, ch, error, i, arg_counter, attrnamespace, 171 minargc, val_len = 0; 172 173 int flag_force = 0; 174 int flag_nofollow = 0; 175 int flag_null = 0; 176 int flag_quiet = 0; 177 int flag_vis = -1; 178 int flag_hex = 0; 179 char *filename = NULL; 180 181 options = NULL; 182 minargc = 0; 183 visbuflen = buflen = 0; 184 visbuf = buf = NULL; 185 186 p = getprogname(); 187 if (strcmp(p, "getextattr") == 0) { 188 what = EAGET; 189 options = "fhqsxv:"; 190 minargc = 2; 191 } else if (strcmp(p, "setextattr") == 0) { 192 what = EASET; 193 options = "fhnqi:"; 194 minargc = 3; 195 } else if (strcmp(p, "rmextattr") == 0) { 196 what = EARM; 197 options = "fhq"; 198 minargc = 2; 199 } else if (strcmp(p, "lsextattr") == 0) { 200 what = EALS; 201 options = "fhq"; 202 minargc = 2; 203 } else 204 usage(); 205 206 while ((ch = getopt(argc, argv, options)) != -1) { 207 switch (ch) { 208 case 'f': 209 flag_force = 1; 210 break; 211 case 'h': 212 flag_nofollow = 1; 213 break; 214 case 'n': 215 flag_null = 1; 216 break; 217 case 'q': 218 flag_quiet = 1; 219 break; 220 case 's': 221 flag_vis = VIS_SAFE | VIS_WHITE; 222 break; 223 case 'v': 224 flag_vis = parse_flag_vis(optarg); 225 break; 226 case 'x': 227 flag_hex = 1; 228 break; 229 case 'i': 230 filename = optarg; 231 minargc--; 232 break; 233 default: 234 usage(); 235 } 236 } 237 238 argc -= optind; 239 argv += optind; 240 241 /* 242 * Check for missing argument. 243 */ 244 if (argc < minargc) 245 usage(); 246 247 /* 248 * Normal case "namespace attribute". 249 */ 250 error = extattr_string_to_namespace(argv[0], &attrnamespace); 251 if (error == 0) { 252 /* 253 * Namespace was specified, so we need one more argument 254 * for the attribute (except for listing) 255 */ 256 if ((what != EALS) && (argc < minargc + 1)) 257 usage(); 258 argc--; argv++; 259 } else { 260 /* 261 * The namespace was not valid. Perhaps it was omited. 262 * Try to guess a missing namespace by using 263 * linux layout "namespace.attribute". While 264 * we are here, also test the Linux namespaces. 265 */ 266 if (strstr(argv[0], "user.") == argv[0]) { 267 attrnamespace = EXTATTR_NAMESPACE_USER; 268 } else 269 if ((strstr(argv[0], "system.") == argv[0]) || 270 (strstr(argv[0], "trusted.") == argv[0]) || 271 (strstr(argv[0], "security.") == argv[0])) { 272 attrnamespace = EXTATTR_NAMESPACE_SYSTEM; 273 } else { 274 err(1, "%s", argv[0]); 275 } 276 } 277 278 279 if (what != EALS) { 280 attrname = argv[0]; 281 argc--; argv++; 282 } else 283 attrname = NULL; 284 285 if (what == EASET) { 286 /* 287 * Handle -i option, reading value from a file. 288 */ 289 if (filename != NULL) { 290 int fd; 291 struct stat st; 292 ssize_t readen, remain; 293 294 if ((fd = open(filename, O_RDONLY, 0)) == -1) 295 err(1, "%s: cannot open \"%s\"", 296 getprogname(), filename); 297 298 if (fstat(fd, &st) != 0) 299 err(1, "%s: cannot stat \"%s\"", 300 getprogname(), filename); 301 302 val_len = st.st_size; 303 mkbuf(&buf, &buflen, val_len); 304 305 for (remain = val_len; remain > 0; remain -= readen) { 306 if ((readen = read(fd, buf, remain)) == -1) 307 err(1, "%s: cannot read \"%s\"", 308 getprogname(), filename); 309 } 310 311 (void)close(fd); 312 } else { 313 val_len = strlen(argv[0]); 314 mkbuf(&buf, &buflen, val_len + 1); 315 strcpy(buf, argv[0]); /* safe */ 316 argc--; argv++; 317 } 318 } 319 320 for (arg_counter = 0; arg_counter < argc; arg_counter++) { 321 switch (what) { 322 case EARM: 323 if (flag_nofollow) 324 error = extattr_delete_link(argv[arg_counter], 325 attrnamespace, attrname); 326 else 327 error = extattr_delete_file(argv[arg_counter], 328 attrnamespace, attrname); 329 if (error >= 0) 330 continue; 331 break; 332 case EASET: 333 if (flag_nofollow) 334 error = extattr_set_link(argv[arg_counter], 335 attrnamespace, attrname, buf, 336 val_len + flag_null); 337 else 338 error = extattr_set_file(argv[arg_counter], 339 attrnamespace, attrname, buf, 340 val_len + flag_null); 341 if (error >= 0) 342 continue; 343 break; 344 case EALS: 345 if (flag_nofollow) 346 error = extattr_list_link(argv[arg_counter], 347 attrnamespace, NULL, 0); 348 else 349 error = extattr_list_file(argv[arg_counter], 350 attrnamespace, NULL, 0); 351 if (error < 0) 352 break; 353 mkbuf(&buf, &buflen, error); 354 if (flag_nofollow) 355 error = extattr_list_link(argv[arg_counter], 356 attrnamespace, buf, buflen); 357 else 358 error = extattr_list_file(argv[arg_counter], 359 attrnamespace, buf, buflen); 360 if (error < 0) 361 break; 362 if (!flag_quiet) 363 printf("%s\t", argv[arg_counter]); 364 for (i = 0; i < error; i += buf[i] + 1) 365 printf("%s%*.*s", i ? "\t" : "", 366 buf[i], buf[i], buf + i + 1); 367 printf("\n"); 368 continue; 369 case EAGET: 370 if (flag_nofollow) 371 error = extattr_get_link(argv[arg_counter], 372 attrnamespace, attrname, NULL, 0); 373 else 374 error = extattr_get_file(argv[arg_counter], 375 attrnamespace, attrname, NULL, 0); 376 if (error < 0) 377 break; 378 mkbuf(&buf, &buflen, error); 379 if (flag_nofollow) 380 error = extattr_get_link(argv[arg_counter], 381 attrnamespace, attrname, buf, buflen); 382 else 383 error = extattr_get_file(argv[arg_counter], 384 attrnamespace, attrname, buf, buflen); 385 if (error < 0) 386 break; 387 if (!flag_quiet) 388 printf("%s\t", argv[arg_counter]); 389 390 /* 391 * Check for binary string and terminal output 392 */ 393 #if 0 394 for (i = 0; i < error; i++) 395 if (!isprint((int)buf[i])) 396 err(1, "binary data, use -x flag"); 397 #endif 398 399 if (flag_vis != -1) { 400 mkbuf(&visbuf, &visbuflen, error * 4 + 1); 401 strvisx(visbuf, buf, error, flag_vis); 402 printf("\"%s\"\n", visbuf); 403 continue; 404 } else if (flag_hex) { 405 printf("\n"); 406 hexdump(buf, error); 407 continue; 408 } else { 409 fwrite(buf, buflen, 1, stdout); 410 printf("\n"); 411 continue; 412 } 413 default: 414 break; 415 } 416 if (!flag_quiet) 417 warn("%s: failed", argv[arg_counter]); 418 if (flag_force) 419 continue; 420 return(1); 421 } 422 return (0); 423 } 424