static PyObject * llistxattr_wrapper(PyObject *self, PyObject *args) { const char *filename; size_t bufsize; PyObject *o; char* buf; ssize_t n; if (!PyArg_ParseTuple(args, "s", &filename)) return NULL; #ifdef __FreeBSD__ bufsize = extattr_list_link(filename, EXTATTR_NAMESPACE_USER, NULL, 0); buf = malloc(bufsize); if (buf == NULL) { Py_INCREF(Py_None); return Py_None; } n = extattr_list_link(filename, EXTATTR_NAMESPACE_USER, buf, bufsize); if (n >= 0) { /* Convert from length-prefixed BSD style to '\0'-suffixed Linux style. */ size_t i = 0; while (i < n) { unsigned char length = (unsigned char) buf[i]; memmove(buf + i, buf + i + 1, length); buf[i + length] = '\0'; i += length + 1; } o = Py_BuildValue("s#", buf, (int) n); } else { o = Py_BuildValue("i", errno); } free(buf); #else bufsize = 0; o = NULL; do { bufsize += 1024; buf = malloc(bufsize); if (buf == NULL) { Py_INCREF(Py_None); return Py_None; } n = llistxattr(filename, buf, bufsize); if (n >= 0) o = Py_BuildValue("s#", buf, (int) n); else if (n == -1 && errno != ERANGE) o = Py_BuildValue("i", errno); free(buf); } while (o == NULL); #endif return o; }
static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size) { ssize_t list_size; int i, len; switch(type) { #if defined(HAVE_EXTATTR_LIST_FILE) case 0: list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size); break; #endif #if defined(HAVE_EXTATTR_LIST_LINK) case 1: list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size); break; #endif #if defined(HAVE_EXTATTR_LIST_FD) case 2: list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size); break; #endif default: errno = ENOSYS; return -1; } /* Some error happend. Errno should be set by the previous call */ if(list_size < 0) return -1; /* No attributes */ if(list_size == 0) return 0; /* XXX: Call with an empty buffer may be used to calculate necessary buffer size. Unfortunately, we can't say, how many attributes were returned, so here is the potential problem with the emulation. */ if(list == NULL) return list_size; /* Buffer is too small to fit the results */ if(list_size > size) { errno = ERANGE; return -1; } /* Convert from pascal strings to C strings */ len = list[0]; memmove(list, list + 1, list_size); for(i = len; i < list_size; ) { len = list[i]; list[i] = '\0'; i += len + 1; } return list_size; }
ssize_t sys_llistxattr(const char *path, char *list, size_t size) { unsigned char keylen; ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size); if (len <= 0 || (size_t)len > size) return len; /* FreeBSD puts a single-byte length before each string, with no '\0' * terminator. We need to change this into a series of null-terminted * strings. Since the size is the same, we can simply transform the * output in place. */ for (off = 0; off < len; off += keylen + 1) { keylen = ((unsigned char*)list)[off]; if (off + keylen >= len) { /* Should be impossible, but kernel bugs happen! */ errno = EINVAL; return -1; } memmove(list+off, list+off+1, keylen); list[off+keylen] = '\0'; } return len; }
int has_xattr(const char *path) { int i=0; for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++) { if(extattr_list_link(path, namespaces[i], NULL, 0)>0) return 1; } return 0; }
/* @param flag Bitfield for control purposes bit5= in case of symbolic link: inquire link target */ static int aaip_extattr_make_list(char *path, int attrnamespace, char **list, ssize_t *list_size, int flag) { *list= NULL; *list_size= 0; /* man 2 extattr_list_file: If data is NULL in a call to extattr_get_file() and extattr_list_file() then the size of defined extended attribute data will be returned, */ if(flag & 32) /* follow link */ *list_size= extattr_list_file(path, attrnamespace, NULL, (size_t) 0); else *list_size= extattr_list_link(path, attrnamespace, NULL, (size_t) 0); if(*list_size == -1) { if(! aaip_extattr_path_supp(path, 0)) { *list_size = 0; return(2); } return(0); } if(*list_size == 0) return(2); *list= calloc(*list_size, 1); if(*list == NULL) return(-1); if(flag & 32) *list_size= extattr_list_file(path, attrnamespace, *list, (size_t) *list_size); else *list_size= extattr_list_link(path, attrnamespace, *list, (size_t) *list_size); if(*list_size == -1) return(0); return(1); }
static ssize_t xattr_listxattr(const char *path, char *namebuf, size_t size, int options) { ssize_t rv = 0; if (!(options == 0 || options == XATTR_XATTR_NOFOLLOW)) { return -1; } if (options & XATTR_XATTR_NOFOLLOW) { rv = extattr_list_link(path, EXTATTR_NAMESPACE_USER, namebuf, size); } else { rv = extattr_list_file(path, EXTATTR_NAMESPACE_USER, namebuf, size); } if (rv > 0 && namebuf) { convert_bsd_list(namebuf, rv); } return rv; }
int main(int argc, char *argv[]) { char *buf, *visbuf, *p; const char *options, *attrname; size_t len; ssize_t ret; int buflen, visbuflen, ch, error, i, arg_counter, attrnamespace, minargc; int flag_force = 0; int flag_nofollow = 0; int flag_null = 0; int flag_quiet = 0; int flag_string = 0; int flag_hex = 0; visbuflen = buflen = 0; visbuf = buf = NULL; p = basename(argv[0]); if (p == NULL) p = argv[0]; if (!strcmp(p, "getextattr")) { what = EAGET; options = "fhqsx"; minargc = 3; } else if (!strcmp(p, "setextattr")) { what = EASET; options = "fhnq"; minargc = 4; } else if (!strcmp(p, "rmextattr")) { what = EARM; options = "fhq"; minargc = 3; } else if (!strcmp(p, "lsextattr")) { what = EALS; options = "fhq"; minargc = 2; } else { usage(); } while ((ch = getopt(argc, argv, options)) != -1) { switch (ch) { case 'f': flag_force = 1; break; case 'h': flag_nofollow = 1; break; case 'n': flag_null = 1; break; case 'q': flag_quiet = 1; break; case 's': flag_string = 1; break; case 'x': flag_hex = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc < minargc) usage(); error = extattr_string_to_namespace(argv[0], &attrnamespace); if (error) err(-1, "%s", argv[0]); argc--; argv++; if (what != EALS) { attrname = argv[0]; argc--; argv++; } else attrname = NULL; if (what == EASET) { mkbuf(&buf, &buflen, strlen(argv[0]) + 1); strcpy(buf, argv[0]); argc--; argv++; } for (arg_counter = 0; arg_counter < argc; arg_counter++) { switch (what) { case EARM: if (flag_nofollow) error = extattr_delete_link(argv[arg_counter], attrnamespace, attrname); else error = extattr_delete_file(argv[arg_counter], attrnamespace, attrname); if (error >= 0) continue; break; case EASET: len = strlen(buf) + flag_null; if (flag_nofollow) ret = extattr_set_link(argv[arg_counter], attrnamespace, attrname, buf, len); else ret = extattr_set_file(argv[arg_counter], attrnamespace, attrname, buf, len); if (ret >= 0) { if ((size_t)ret != len && !flag_quiet) { warnx("Set %zd bytes of %zu for %s", ret, len, attrname); } continue; } break; case EALS: if (flag_nofollow) ret = extattr_list_link(argv[arg_counter], attrnamespace, NULL, 0); else ret = extattr_list_file(argv[arg_counter], attrnamespace, NULL, 0); if (ret < 0) break; mkbuf(&buf, &buflen, ret); if (flag_nofollow) ret = extattr_list_link(argv[arg_counter], attrnamespace, buf, buflen); else ret = extattr_list_file(argv[arg_counter], attrnamespace, buf, buflen); if (ret < 0) break; if (!flag_quiet) printf("%s\t", argv[arg_counter]); for (i = 0; i < ret; i += ch + 1) { /* The attribute name length is unsigned. */ ch = (unsigned char)buf[i]; printf("%s%*.*s", i ? "\t" : "", ch, ch, buf + i + 1); } if (!flag_quiet || ret > 0) printf("\n"); continue; case EAGET: if (flag_nofollow) ret = extattr_get_link(argv[arg_counter], attrnamespace, attrname, NULL, 0); else ret = extattr_get_file(argv[arg_counter], attrnamespace, attrname, NULL, 0); if (ret < 0) break; mkbuf(&buf, &buflen, ret); if (flag_nofollow) ret = extattr_get_link(argv[arg_counter], attrnamespace, attrname, buf, buflen); else ret = extattr_get_file(argv[arg_counter], attrnamespace, attrname, buf, buflen); if (ret < 0) break; if (!flag_quiet) printf("%s\t", argv[arg_counter]); if (flag_string) { mkbuf(&visbuf, &visbuflen, ret * 4 + 1); strvisx(visbuf, buf, ret, VIS_SAFE | VIS_WHITE); printf("\"%s\"\n", visbuf); continue; } else if (flag_hex) { for (i = 0; i < ret; i++) printf("%s%02x", i ? " " : "", buf[i]); printf("\n"); continue; } else { fwrite(buf, ret, 1, stdout); printf("\n"); continue; } default: break; } if (!flag_quiet) warn("%s: failed", argv[arg_counter]); if (flag_force) continue; return(1); } return (0); }
int get_xattr(struct asfd *asfd, const char *path, char **xattrtext, size_t *xlen, struct cntr *cntr) { int i=0; ssize_t maxlen=0xFFFFFFFF/2; for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++) { int j=0; ssize_t len=0; int have_acl=0; char *xattrlist=NULL; char *cnamespace=NULL; ssize_t totallen=0; char *toappend=NULL; char z[BSD_BUF_SIZE]=""; char cattrname[BSD_BUF_SIZE]=""; if((len=extattr_list_link(path, namespaces[i], NULL, 0))<0) { logw(asfd, cntr, "could not extattr_list_link of '%s': %zd\n", path, len); return 0; // carry on } if(!len) continue; if(xattrtext && *xattrtext) { // Already have some meta text, which means that some // ACLs were set. have_acl++; } if(!(xattrlist=(char *)calloc_w(1, len+1, __func__))) return -1; if((len=extattr_list_link(path, namespaces[i], xattrlist, len))<=0) { logw(asfd, cntr, "could not extattr_list_link '%s': %zd\n", path, len); free_w(&xattrlist); return 0; // carry on } xattrlist[len]='\0'; if(extattr_namespace_to_string(namespaces[i], &cnamespace)) { logp("Failed to convert %d into namespace on '%s'\n", namespaces[i], path); free_w(&xattrlist); return 0; // carry on } for(j=0; j<(int)len; j+=xattrlist[j]+1) { int cnt=0; char tmp1[9]; char tmp2[9]; size_t newlen=0; size_t zlen=0; ssize_t vlen=0; char *val=NULL; cnt=xattrlist[j]; if(cnt>((int)sizeof(cattrname)-1)) cnt=((int)sizeof(cattrname)-1); strncpy(cattrname, xattrlist+(j+1), cnt); cattrname[cnt]='\0'; snprintf(z, sizeof(z), "%s.%s", cnamespace, cattrname); if(have_acl && in_skiplist(z)) continue; zlen=strlen(z); //printf("\ngot: %s (%s)\n", z, path); if((vlen=extattr_list_link(path, namespaces[i], xattrlist, len))<0) { logw(asfd, cntr, "could not extattr_list_link on %s for %s: %zd\n", path, cnamespace, vlen); continue; } if(vlen) { if(!(val=(char *)malloc_w(vlen+1, __func__))) { free_w(&xattrlist); free_w(&toappend); return -1; } if((vlen=extattr_get_link(path, namespaces[i], cattrname, val, vlen))<0) { logw(asfd, cntr, "could not extattr_list_link %s for %s: %zd\n", path, cnamespace, vlen); free_w(&val); continue; } val[vlen]='\0'; if(vlen>maxlen) { logw(asfd, cntr, "xattr value of '%s' too long: %zd\n", path, vlen); free_w(&toappend); free_w(&val); break; } } snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned int)zlen); snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned int)vlen); newlen=totallen+8+zlen+8+vlen; if(!(toappend=(char *)realloc_w(toappend, newlen, __func__))) { free_w(&val); free_w(&xattrlist); return -1; } memcpy(toappend+totallen, tmp1, 8); totallen+=8; memcpy(toappend+totallen, z, zlen); totallen+=zlen; memcpy(toappend+totallen, tmp2, 8); totallen+=8; memcpy(toappend+totallen, val, vlen); totallen+=vlen; free_w(&val); if(totallen>maxlen) { logw(asfd, cntr, "xattr length of '%s' grew too long: %lu\n", path, (unsigned long)totallen); free_w(&val); free_w(&toappend); free_w(&xattrlist); return 0; // carry on } } if(toappend) { if(append_to_extrameta(toappend, META_XATTR_BSD, xattrtext, xlen, totallen)) { free_w(&toappend); free_w(&xattrlist); return -1; } } free_w(&toappend); free_w(&xattrlist); } return 0; }
static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size) { ssize_t list_size, total_size = 0; int i, t, len; char *buf; /* Iterate through extattr(2) namespaces */ for(t = 0; t < ARRAY_SIZE(extattr); t++) { if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) { /* ignore all but user namespace when we are not root, see bug 10247 */ continue; } switch(type) { #if defined(HAVE_EXTATTR_LIST_FILE) case 0: list_size = extattr_list_file(arg.path, extattr[t].space, list, size); break; #endif #if defined(HAVE_EXTATTR_LIST_LINK) case 1: list_size = extattr_list_link(arg.path, extattr[t].space, list, size); break; #endif #if defined(HAVE_EXTATTR_LIST_FD) case 2: list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size); break; #endif default: errno = ENOSYS; return -1; } /* Some error happend. Errno should be set by the previous call */ if(list_size < 0) return -1; /* No attributes */ if(list_size == 0) continue; /* XXX: Call with an empty buffer may be used to calculate necessary buffer size. Unfortunately, we can't say, how many attributes were returned, so here is the potential problem with the emulation. */ if(list == NULL) { /* Take the worse case of one char attribute names - two bytes per name plus one more for sanity. */ total_size += list_size + (list_size/2 + 1)*extattr[t].len; continue; } /* Count necessary offset to fit namespace prefixes */ len = 0; for(i = 0; i < list_size; i += list[i] + 1) len += extattr[t].len; total_size += list_size + len; /* Buffer is too small to fit the results */ if(total_size > size) { errno = ERANGE; return -1; } /* Shift results back, so we can prepend prefixes */ buf = (char *)memmove(list + len, list, list_size); for(i = 0; i < list_size; i += len + 1) { len = buf[i]; strncpy(list, extattr[t].name, extattr[t].len + 1); list += extattr[t].len; strncpy(list, buf + i + 1, len); list[len] = '\0'; list += len + 1; } size -= total_size; } return total_size; }
int get_xattr(const char *path, struct stat *statp, char **xattrtext, size_t *xlen, struct conf *conf) { int i=0; size_t maxlen=0xFFFFFFFF/2; for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++) { int j=0; size_t len=0; int have_acl=0; char *xattrlist=NULL; char *cnamespace=NULL; size_t totallen=0; char *toappend=NULL; char ctuple[BSD_BUF_SIZE]=""; char cattrname[BSD_BUF_SIZE]=""; if((len=extattr_list_link(path, namespaces[i], NULL, 0))<0) { logw(conf, "could not extattr_list_link of '%s': %d\n", path, len); return 0; // carry on } if(!len) continue; if(xattrtext && *xattrtext) { // Already have some meta text, which means that some // ACLs were set. have_acl++; } if(!(xattrlist=(char *)malloc(len+1))) { log_out_of_memory(__func__); return -1; } memset(xattrlist, 0, len+1); if((len=extattr_list_link(path, namespaces[i], xattrlist, len))<=0) { logw(conf, "could not extattr_list_link '%s': %d\n", path, len); free(xattrlist); return 0; // carry on } xattrlist[len]='\0'; // Convert namespace number to string. It has to be freed // later on. if(extattr_namespace_to_string(namespaces[i], &cnamespace)) { logp("Failed to convert %d into namespace on '%s'\n", namespaces[i], path); free(xattrlist); return 0; // carry on } for(j=0; j<(int)len; j+=xattrlist[j]+1) { int cnt=0; char tmp1[9]; char tmp2[9]; size_t zlen=0; size_t vlen=0; char *val=NULL; cnt=xattrlist[j]; if(cnt>((int)sizeof(cattrname)-1)) cnt=((int)sizeof(cattrname)-1); strncpy(cattrname, xattrlist+(j+1), cnt); cattrname[cnt]='\0'; snprintf(ctuple, sizeof(ctuple), "%s.%s", cnamespace, cattrname); if(have_acl) { int c=0; int skip=0; // skip xattr entries that were already saved // as ACLs. for(c=0; acl_skiplist[c]; c++) { if(!strcmp(ctuple, acl_skiplist[c])) { skip++; break; } } if(skip) continue; } zlen=strlen(ctuple); //printf("\ngot: %s (%s)\n", ctuple, path); if((vlen=extattr_list_link(path, namespaces[i], xattrlist, len))<0) { logw(conf, "could not extattr_list_link on %s for %s: %d\n", path, namespaces[i], vlen); continue; } if(!(val=(char *)malloc(vlen+1))) { log_out_of_memory(__func__); free(xattrlist); if(toappend) free(toappend); return -1; } if((vlen=extattr_get_link(path, namespaces[i], cattrname, val, vlen))<0) { logw(conf, "could not extattr_list_link %s for %s: %d\n", path, namespaces[i], vlen); free(val); continue; } val[vlen]='\0'; if(vlen>maxlen) { logw(conf, "xattr value of '%s' too long: %d\n", path, vlen); if(toappend) { free(toappend); toappend=NULL; } free(val); break; } snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned)zlen); snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned)vlen); if(!(toappend=prepend_len(toappend, totallen, tmp1, 8, "", 0, &totallen)) || !(toappend=prepend_len(toappend, totallen, ctuple, zlen, "", 0, &totallen)) || !(toappend=prepend_len(toappend, totallen, tmp2, 8, "", 0, &totallen)) || !(toappend=prepend_len(toappend, totallen, val, vlen, "", 0, &totallen))) { log_out_of_memory(__func__); free(val); free(xattrlist); return -1; } free(val); if(totallen>maxlen) { logw(conf, "xattr length of '%s' grew too long: %d\n", path, totallen); free(val); free(toappend); free(xattrlist); return 0; // carry on } //printf("now: %s\n", toappend); } free(cnamespace); if(toappend) { char tmp3[10]; snprintf(tmp3, sizeof(tmp3), "%c%08X", META_XATTR_BSD, (unsigned)totallen); if(!(*xattrtext=prepend_len(*xattrtext, *xlen, tmp3, 9, "", 0, xlen)) || !(*xattrtext=prepend_len(*xattrtext, *xlen, toappend, totallen, "", 0, xlen))) { log_out_of_memory(__func__); free(toappend); free(xattrlist); return -1; } free(toappend); //printf("and: %s %li\n", *xattrtext, *xlen); } free(xattrlist); } return 0; }