From 351aec3f7ad23a9b1d067d8b0079eee5c0060f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Tue, 26 Oct 2010 08:59:52 +0200 Subject: [PATCH] Enabled renaming of system extended attributes --- configure.ac | 8 + include/ntfs-3g/attrib.h | 7 + include/ntfs-3g/logging.h | 3 + include/ntfs-3g/param.h | 9 +- include/ntfs-3g/volume.h | 5 +- include/ntfs-3g/xattrs.h | 19 ++- libntfs-3g/acls.c | 35 +---- libntfs-3g/attrib.c | 83 ++++++++++ libntfs-3g/logging.c | 24 +++ libntfs-3g/security.c | 101 +------------ libntfs-3g/xattrs.c | 310 +++++++++++++++++++++++++++++++++++++- src/lowntfs-3g.c | 41 ++++- src/ntfs-3g.c | 41 ++++- src/secaudit.c | 27 +++- 14 files changed, 571 insertions(+), 142 deletions(-) diff --git a/configure.ac b/configure.ac index da7205cb..09303c51 100644 --- a/configure.ac +++ b/configure.ac @@ -113,6 +113,13 @@ AC_ARG_ENABLE( [enable_posix_acls="no"] ) +AC_ARG_ENABLE( + [xattr-mappings], + [AS_HELP_STRING([--enable-xattr-mappings],[enable system extended attributes mappings])], + , + [enable_xattr_mappings="no"] +) + AC_ARG_ENABLE( [device-default-io-ops], [AS_HELP_STRING([--disable-device-default-io-ops],[install default IO ops])], @@ -349,6 +356,7 @@ test "${enable_device_default_io_ops}" = "no" && AC_DEFINE( test "${enable_mtab}" = "no" && AC_DEFINE([IGNORE_MTAB], [1], [Don't update /etc/mtab]) test "${enable_posix_acls}" != "no" && AC_DEFINE([POSIXACLS], [1], [POSIX ACL support]) +test "${enable_xattr_mappings}" != "no" && AC_DEFINE([XATTR_MAPPINGS], [1], [system extended attributes mappings]) test "${enable_really_static}" = "yes" && enable_library="no" test "${enable_library}" = "no" && enable_ldconfig="no" diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h index 21b86f03..47c40847 100644 --- a/include/ntfs-3g/attrib.h +++ b/include/ntfs-3g/attrib.h @@ -4,6 +4,7 @@ * Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2004-2005 Yura Pakhuchiy * Copyright (c) 2006-2007 Szabolcs Szakacsits + * Copyright (c) 2010 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -380,6 +381,12 @@ extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, u32 name_len); extern s64 ntfs_attr_get_free_bits(ntfs_attr *na); +extern int ntfs_attr_data_read(ntfs_inode *ni, + ntfschar *stream_name, int stream_name_len, + char *buf, size_t size, off_t offset); +extern int ntfs_attr_data_write(ntfs_inode *ni, + ntfschar *stream_name, int stream_name_len, + char *buf, size_t size, off_t offset); #endif /* defined _NTFS_ATTRIB_H */ diff --git a/include/ntfs-3g/logging.h b/include/ntfs-3g/logging.h index 401f5c97..82f39fe1 100644 --- a/include/ntfs-3g/logging.h +++ b/include/ntfs-3g/logging.h @@ -114,5 +114,8 @@ int ntfs_log_redirect(const char *function, const char *file, int line, #define ntfs_log_leave(FORMAT, ARGS...)do {} while (0) #endif /* DEBUG */ +void ntfs_log_early_error(const char *format, ...) + __attribute__((format(printf, 1, 2))); + #endif /* _LOGGING_H_ */ diff --git a/include/ntfs-3g/param.h b/include/ntfs-3g/param.h index d89b1c4e..57d122e5 100644 --- a/include/ntfs-3g/param.h +++ b/include/ntfs-3g/param.h @@ -1,7 +1,7 @@ /* * param.h - Parameter values for ntfs-3g * - * Copyright (c) 2009 Jean-Pierre Andre + * Copyright (c) 2009-2010 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -57,6 +57,13 @@ enum { /* only update the final extent of a runlist when appending data */ #define PARTIAL_RUNLIST_UPDATING 1 +/* + * Parameters for user and xattr mappings + */ + +#define XATTRMAPPINGFILE ".NTFS-3G/XattrMapping" /* default mapping file */ + + /* * Permission checking modes for high level and low level * diff --git a/include/ntfs-3g/volume.h b/include/ntfs-3g/volume.h index 79193c53..9c8ab14c 100644 --- a/include/ntfs-3g/volume.h +++ b/include/ntfs-3g/volume.h @@ -5,6 +5,7 @@ * Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2005-2009 Szabolcs Szakacsits + * Copyright (c) 2010 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -251,7 +252,9 @@ struct _ntfs_volume { s64 free_mft_records; /* Same for free mft records (see above) */ BOOL efs_raw; /* volume is mounted for raw access to efs-encrypted files */ - +#ifdef XATTR_MAPPINGS + struct XATTRMAPPING *xattr_mapping; +#endif /* XATTR_MAPPINGS */ #if CACHE_INODE_SIZE struct CACHE_HEADER *xinode_cache; #endif diff --git a/include/ntfs-3g/xattrs.h b/include/ntfs-3g/xattrs.h index ca60ba0d..7ebd298c 100644 --- a/include/ntfs-3g/xattrs.h +++ b/include/ntfs-3g/xattrs.h @@ -43,10 +43,25 @@ enum SYSTEMXATTRS { XATTR_POSIX_DEF } ; -enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name); +struct XATTRMAPPING { + struct XATTRMAPPING *next; + enum SYSTEMXATTRS xattr; + char name[1]; /* variable length */ +} ; +#ifdef XATTR_MAPPINGS + +struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol, + const char *path); +void ntfs_xattr_free_mapping(struct XATTRMAPPING*); + +#endif /* XATTR_MAPPINGS */ + +enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name, + ntfs_volume *vol); int ntfs_xattr_listxattr(ntfs_inode *ni, ntfs_attr_search_ctx *actx, - char *list, size_t size, BOOL prefixing); + char *list, size_t size, BOOL prefixing); + int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx, enum SYSTEMXATTRS attr, ntfs_inode *ni, ntfs_inode *dir_ni, diff --git a/libntfs-3g/acls.c b/libntfs-3g/acls.c index 76cc6ce5..63284206 100644 --- a/libntfs-3g/acls.c +++ b/libntfs-3g/acls.c @@ -4,7 +4,7 @@ * This module is part of ntfs-3g library, but may also be * integrated in tools running over Linux or Windows * - * Copyright (c) 2007-2009 Jean-Pierre Andre + * Copyright (c) 2007-2010 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -3956,33 +3956,6 @@ static SID *encodesid(const char *sidstr) return (sid); } -/* - * Early logging before the logs are redirected - * - * (not quite satisfactory : this appears before the ntfs-g banner, - * and with a different pid) - */ - -static void log_early_error(const char *format, ...) - __attribute__((format(printf, 1, 2))); - -static void log_early_error(const char *format, ...) -{ - va_list args; - - va_start(args, format); -#ifdef HAVE_SYSLOG_H - openlog("ntfs-3g", LOG_PID, LOG_USER); - ntfs_log_handler_syslog(NULL, NULL, 0, - NTFS_LOG_LEVEL_ERROR, NULL, - format, args); -#else - vfprintf(stderr,format,args); -#endif - va_end(args); -} - - /* * Get a single mapping item from buffer * @@ -4045,7 +4018,7 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid, if (pu && pg) *pu = *pg = '\0'; else { - log_early_error("Bad mapping item \"%s\"\n", + ntfs_log_early_error("Bad mapping item \"%s\"\n", item->maptext); free(item); item = (struct MAPLIST*)NULL; @@ -4174,7 +4147,7 @@ struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem) if (pwd) uid = pwd->pw_uid; else - log_early_error("Invalid user \"%s\"\n", + ntfs_log_early_error("Invalid user \"%s\"\n", item->uidstr); } } @@ -4254,7 +4227,7 @@ struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem) if (grp) gid = grp->gr_gid; else - log_early_error("Invalid group \"%s\"\n", + ntfs_log_early_error("Invalid group \"%s\"\n", item->gidstr); } } diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index ba9bc184..787f7b64 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -6542,6 +6542,89 @@ err_exit: return ret; } +/* + * Read some data from a data attribute + * + * Returns the amount of data read, negative if there was an error + */ + +int ntfs_attr_data_read(ntfs_inode *ni, + ntfschar *stream_name, int stream_name_len, + char *buf, size_t size, off_t offset) +{ + ntfs_attr *na = NULL; + int res, total = 0; + + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto exit; + } + if ((size_t)offset < (size_t)na->data_size) { + if (offset + size > (size_t)na->data_size) + size = na->data_size - offset; + while (size) { + res = ntfs_attr_pread(na, offset, size, buf + total); + if ((off_t)res < (off_t)size) + ntfs_log_perror("ntfs_attr_pread partial read " + "(%lld : %lld <> %d)", + (long long)offset, + (long long)size, res); + if (res <= 0) { + res = -errno; + goto exit; + } + size -= res; + offset += res; + total += res; + } + } + res = total; +exit: + if (na) + ntfs_attr_close(na); + return res; +} + + +/* + * Write some data into a data attribute + * + * Returns the amount of data written, negative if there was an error + */ + +int ntfs_attr_data_write(ntfs_inode *ni, + ntfschar *stream_name, int stream_name_len, + char *buf, size_t size, off_t offset) +{ + ntfs_attr *na = NULL; + int res, total = 0; + + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + if (!na) { + res = -errno; + goto exit; + } + while (size) { + res = ntfs_attr_pwrite(na, offset, size, buf + total); + if (res < (s64)size) + ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: " + "%lld <> %d)", (long long)offset, + (long long)size, res); + if (res <= 0) { + res = -errno; + goto exit; + } + size -= res; + offset += res; + total += res; + } + res = total; +exit: + if (na) + ntfs_attr_close(na); + return res; +} int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, diff --git a/libntfs-3g/logging.c b/libntfs-3g/logging.c index 385bcaa6..ccccbb8f 100644 --- a/libntfs-3g/logging.c +++ b/libntfs-3g/logging.c @@ -3,6 +3,7 @@ * * Copyright (c) 2005 Richard Russon * Copyright (c) 2005-2008 Szabolcs Szakacsits + * Copyright (c) 2010 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -388,6 +389,29 @@ out: } #endif +/* + * Early logging before the logs are redirected + * + * (not quite satisfactory : this appears before the ntfs-g banner, + * and with a different pid) + */ + +void ntfs_log_early_error(const char *format, ...) +{ + va_list args; + + va_start(args, format); +#ifdef HAVE_SYSLOG_H + openlog("ntfs-3g", LOG_PID, LOG_USER); + ntfs_log_handler_syslog(NULL, NULL, 0, + NTFS_LOG_LEVEL_ERROR, NULL, + format, args); +#else + vfprintf(stderr,format,args); +#endif + va_end(args); +} + /** * ntfs_log_handler_fprintf - Basic logging handler * @function: Function in which the log line occurred diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c index 138764ba..0203ecc2 100644 --- a/libntfs-3g/security.c +++ b/libntfs-3g/security.c @@ -4,7 +4,7 @@ * Copyright (c) 2004 Anton Altaparmakov * Copyright (c) 2005-2006 Szabolcs Szakacsits * Copyright (c) 2006 Yura Pakhuchiy - * Copyright (c) 2007-2009 Jean-Pierre Andre + * Copyright (c) 2007-2010 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -404,91 +404,6 @@ le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len) return cpu_to_le32(hash); } -/* - * Internal read - * copied and pasted from ntfs_fuse_read() and made independent - * of fuse context - */ - -static int ntfs_local_read(ntfs_inode *ni, - ntfschar *stream_name, int stream_name_len, - char *buf, size_t size, off_t offset) -{ - ntfs_attr *na = NULL; - int res, total = 0; - - na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); - if (!na) { - res = -errno; - goto exit; - } - if ((size_t)offset < (size_t)na->data_size) { - if (offset + size > (size_t)na->data_size) - size = na->data_size - offset; - while (size) { - res = ntfs_attr_pread(na, offset, size, buf); - if ((off_t)res < (off_t)size) - ntfs_log_perror("ntfs_attr_pread partial read " - "(%lld : %lld <> %d)", - (long long)offset, - (long long)size, res); - if (res <= 0) { - res = -errno; - goto exit; - } - size -= res; - offset += res; - total += res; - } - } - res = total; -exit: - if (na) - ntfs_attr_close(na); - return res; -} - - -/* - * Internal write - * copied and pasted from ntfs_fuse_write() and made independent - * of fuse context - */ - -static int ntfs_local_write(ntfs_inode *ni, - ntfschar *stream_name, int stream_name_len, - char *buf, size_t size, off_t offset) -{ - ntfs_attr *na = NULL; - int res, total = 0; - - na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); - if (!na) { - res = -errno; - goto exit; - } - while (size) { - res = ntfs_attr_pwrite(na, offset, size, buf); - if (res < (s64)size) - ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: " - "%lld <> %d)", (long long)offset, - (long long)size, res); - if (res <= 0) { - res = -errno; - goto exit; - } - size -= res; - offset += res; - total += res; - } - res = total; -exit: - if (na) - ntfs_attr_close(na); - return res; -} - - /* * Get the first entry of current index block * cut and pasted form ntfs_ie_get_first() in index.c @@ -531,7 +446,7 @@ static int entersecurity_stuff(ntfs_volume *vol, off_t offs) if (stuff) { memset(stuff, 0, STUFFSZ); do { - written = ntfs_local_write(vol->secure_ni, + written = ntfs_attr_data_write(vol->secure_ni, STREAM_SDS, 4, stuff, STUFFSZ, offs); if (written == STUFFSZ) { total += STUFFSZ; @@ -589,10 +504,10 @@ static int entersecurity_data(ntfs_volume *vol, phsds->security_id = keyid; phsds->offset = cpu_to_le64(offs); phsds->length = cpu_to_le32(fullsz - gap); - written1 = ntfs_local_write(vol->secure_ni, + written1 = ntfs_attr_data_write(vol->secure_ni, STREAM_SDS, 4, fullattr, fullsz, offs - gap); - written2 = ntfs_local_write(vol->secure_ni, + written2 = ntfs_attr_data_write(vol->secure_ni, STREAM_SDS, 4, fullattr, fullsz, offs - gap + ALIGN_SDS_BLOCK); if ((written1 == fullsz) @@ -950,7 +865,7 @@ static le32 setsecurityattr(ntfs_volume *vol, + sizeof(SECURITY_DESCRIPTOR_HEADER); oldattr = (char*)ntfs_malloc(size); if (oldattr) { - rdsize = ntfs_local_read( + rdsize = ntfs_attr_data_read( vol->secure_ni, STREAM_SDS, 4, oldattr, size, offs); @@ -1772,7 +1687,7 @@ static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id) securattr = (char*)ntfs_malloc(size); if (securattr) { - rdsize = ntfs_local_read( + rdsize = ntfs_attr_data_read( ni, STREAM_SDS, 4, securattr, size, offs); if ((rdsize != size) @@ -4097,7 +4012,7 @@ static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribut static int localread(void *fileid, char *buf, size_t size, off_t offs) { - return (ntfs_local_read((ntfs_inode*)fileid, + return (ntfs_attr_data_read((ntfs_inode*)fileid, AT_UNNAMED, 0, buf, size, offs)); } @@ -4919,7 +4834,7 @@ int ntfs_read_sds(struct SECURITY_API *scapi, got = -1; /* default return */ if (scapi && (scapi->magic == MAGIC_API)) { if (scapi->security.vol->secure_ni) - got = ntfs_local_read(scapi->security.vol->secure_ni, + got = ntfs_attr_data_read(scapi->security.vol->secure_ni, STREAM_SDS, 4, buf, size, offset); else errno = EOPNOTSUPP; diff --git a/libntfs-3g/xattrs.c b/libntfs-3g/xattrs.c index af0431ca..a2d31e84 100644 --- a/libntfs-3g/xattrs.c +++ b/libntfs-3g/xattrs.c @@ -89,7 +89,7 @@ static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1; static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl"; static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib"; static const char nf_ns_xattr_attrib_be[] = "system.ntfs_attrib_be"; -static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo"; +static const char nf_ns_xattr_efsinfo[] = "system.ntfs_efsinfo"; static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data"; static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id"; static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name"; @@ -202,21 +202,286 @@ int cpu_to_le_acl(const struct POSIX_ACL *acl, size_t size, * internal data (original name in system namespace, or renamed) */ -enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name) +enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name, + ntfs_volume *vol) { struct XATTRNAME *p; + enum SYSTEMXATTRS ret; +#ifdef XATTR_MAPPINGS + const struct XATTRMAPPING *q; +#endif /* XATTR_MAPPINGS */ p = nf_ns_xattr_names; while (p->name && strcmp(p->name,name)) p++; - return (p->xattr); + ret = p->xattr; +#ifdef XATTR_MAPPINGS + if (!p->name && vol && vol->xattr_mapping) { + q = vol->xattr_mapping; + while (q && strcmp(q->name,name)) + q = q->next; + if (q) + ret = q->xattr; + } +#else /* XATTR_MAPPINGS */ + if (!p->name + && vol + && vol->efs_raw + && !strcmp(nf_ns_alt_xattr_efsinfo,name)) + ret = XATTR_NTFS_EFSINFO; +#endif /* XATTR_MAPPINGS */ + return (ret); } +#ifdef XATTR_MAPPINGS + +/* + * Basic read from a user mapping file on another volume + */ + +static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused))) +{ + return (read(*(int*)fileid, buf, size)); +} + + +/* + * Read from a user mapping file on current NTFS partition + */ + +static int localread(void *fileid, char *buf, size_t size, off_t offs) +{ + return (ntfs_attr_data_read((ntfs_inode*)fileid, + AT_UNNAMED, 0, buf, size, offs)); +} + +/* + * Get a single mapping item from buffer + * + * Always reads a full line, truncating long lines + * Refills buffer when exhausted + * Returns pointer to item, or NULL when there is no more + * Note : errors are logged, but not returned +// TODO partially share with acls.c + */ + +static struct XATTRMAPPING *getmappingitem(FILEREADER reader, void *fileid, + off_t *poffs, char *buf, int *psrc, s64 *psize) +{ + int src; + int dst; + char *pe; + char *ps; + char *pu; + enum SYSTEMXATTRS xattr; + int gotend; + char maptext[LINESZ]; + struct XATTRMAPPING *item; + + src = *psrc; + dst = 0; + do { + gotend = 0; + while ((src < *psize) + && (buf[src] != '\n')) { + /* ignore spaces */ + if ((dst < LINESZ) + && (buf[src] != '\r') + && (buf[src] != '\t') + && (buf[src] != ' ')) + maptext[dst++] = buf[src]; + src++; + } + if (src >= *psize) { + *poffs += *psize; + *psize = reader(fileid, buf, (size_t)BUFSZ, *poffs); + src = 0; + } else { + gotend = 1; + src++; + maptext[dst] = '\0'; + dst = 0; + } + } while (*psize && ((maptext[0] == '#') || !gotend)); + item = (struct XATTRMAPPING*)NULL; + if (gotend) { + /* decompose into system name and user name */ + ps = maptext; + pu = strchr(maptext,':'); + if (pu) { + *pu++ = 0; + pe = strchr(pu,':'); + if (pe) + *pe = 0; + /* check name validity */ + if ((strlen(pu) < 6) || strncmp(pu,"user.",5)) + pu = (char*)NULL; + xattr = ntfs_xattr_system_type(ps, + (ntfs_volume*)NULL); + if (xattr == XATTR_UNMAPPED) + pu = (char*)NULL; + } + if (pu) { + item = (struct XATTRMAPPING*)ntfs_malloc( + sizeof(struct XATTRMAPPING) + + strlen(pu)); + if (item) { + item->xattr = xattr; + strcpy(item->name,pu); + item->next = (struct XATTRMAPPING*)NULL; + } + } else { + ntfs_log_early_error("Bad xattr mapping item, aborting\n"); + } + } + *psrc = src; + return (item); +} + +/* + * Read xattr mapping file and split into their attribute. + * Parameters are kept in a chained list. + * Returns the head of list, if any + * Errors are logged, but not returned + * + * If an absolute path is provided, the mapping file is assumed + * to be located in another mounted file system, and plain read() + * are used to get its contents. + * If a relative path is provided, the mapping file is assumed + * to be located on the current file system, and internal IO + * have to be used since we are still mounting and we have not + * entered the fuse loop yet. + */ + +static struct XATTRMAPPING *ntfs_read_xattr_mapping(FILEREADER reader, + void *fileid) +{ + char buf[BUFSZ]; + struct XATTRMAPPING *item; + struct XATTRMAPPING *current; + struct XATTRMAPPING *firstitem; + struct XATTRMAPPING *lastitem; + BOOL duplicated; + int src; + off_t offs; + s64 size; + + firstitem = (struct XATTRMAPPING*)NULL; + lastitem = (struct XATTRMAPPING*)NULL; + offs = 0; + size = reader(fileid, buf, (size_t)BUFSZ, (off_t)0); + if (size > 0) { + src = 0; + do { + item = getmappingitem(reader, fileid, &offs, + buf, &src, &size); + if (item) { + /* check no double mapping */ + duplicated = FALSE; + for (current=firstitem; current; current=current->next) + if ((current->xattr == item->xattr) + || !strcmp(current->name,item->name)) + duplicated = TRUE; + if (duplicated) { + free(item); + ntfs_log_early_error("Conflicting xattr mapping ignored\n"); + } else { + item->next = (struct XATTRMAPPING*)NULL; + if (lastitem) + lastitem->next = item; + else + firstitem = item; + lastitem = item; + } + } + } while (item); + } + return (firstitem); +} + +/* + * Build the extended attribute mappings to user namespace + * + * Note : no error is returned. If we refused mounting when there + * is an error it would be too difficult to fix the offending file + */ + +struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol, + const char *xattrmap_path) +{ + struct XATTRMAPPING *firstmapping; + struct XATTRMAPPING *mapping; + BOOL user_efs; + BOOL notfound; + ntfs_inode *ni; + int fd; + + firstmapping = (struct XATTRMAPPING*)NULL; + notfound = FALSE; + if (!xattrmap_path) + xattrmap_path = XATTRMAPPINGFILE; + if (xattrmap_path[0] == '/') { + fd = open(xattrmap_path,O_RDONLY); + if (fd > 0) { + firstmapping = ntfs_read_xattr_mapping(basicread, (void*)&fd); + close(fd); + } else + notfound = TRUE; + } else { + ni = ntfs_pathname_to_inode(vol, NULL, xattrmap_path); + if (ni) { + firstmapping = ntfs_read_xattr_mapping(localread, ni); + ntfs_inode_close(ni); + } else + notfound = TRUE; + } + if (notfound && strcmp(xattrmap_path, XATTRMAPPINGFILE)) { + ntfs_log_early_error("Could not open \"%s\"\n",xattrmap_path); + } + if (vol->efs_raw) { + user_efs = TRUE; + for (mapping=firstmapping; mapping; mapping=mapping->next) + if (mapping->xattr == XATTR_NTFS_EFSINFO) + user_efs = FALSE; + } else + user_efs = FALSE; + if (user_efs) { + mapping = (struct XATTRMAPPING*)ntfs_malloc( + sizeof(struct XATTRMAPPING) + + strlen(nf_ns_alt_xattr_efsinfo)); + if (mapping) { + mapping->next = firstmapping; + mapping->xattr = XATTR_NTFS_EFSINFO; + strcpy(mapping->name,nf_ns_alt_xattr_efsinfo); + firstmapping = mapping; + } + } + return (firstmapping); +} + +void ntfs_xattr_free_mapping(struct XATTRMAPPING *mapping) +{ + struct XATTRMAPPING *p, *q; + + p = mapping; + while (p) { + q = p->next; + free(p); + p = q; + } +} + +#endif /* XATTR_MAPPINGS */ + int ntfs_xattr_listxattr(ntfs_inode *ni, ntfs_attr_search_ctx *actx, char *list, size_t size, BOOL prefixing) { int ret = 0; char *to = list; +#ifdef XATTR_MAPPINGS + BOOL accepted; + const struct XATTRMAPPING *item; +#endif /* XATTR_MAPPINGS */ /* first list the regular user attributes (ADS) */ while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, @@ -268,13 +533,44 @@ int ntfs_xattr_listxattr(ntfs_inode *ni, ntfs_attr_search_ctx *actx, } free(tmp_name); } +#ifdef XATTR_MAPPINGS + /* now append the system attributes mapped to user space */ + for (item=ni->vol->xattr_mapping; item; item=item->next) { + switch (item->xattr) { + case XATTR_NTFS_EFSINFO : + accepted = ni->vol->efs_raw + && (ni->flags & FILE_ATTR_ENCRYPTED); + break; + case XATTR_NTFS_REPARSE_DATA : + accepted = (ni->flags & FILE_ATTR_REPARSE_POINT) + != const_cpu_to_le32(0); + break; +// TODO : we are supposed to only return xattrs which are set +// this is more complex for OBJECT_ID and DOS_NAME + default : accepted = TRUE; + break; + } + if (accepted) { + ret += strlen(item->name) + 1; + if (size) { + if ((size_t)ret <= size) { + strcpy(to, item->name); + to += strlen(item->name); + *to++ = 0; + } else { + ret = -ERANGE; + goto exit; + } + } +#else /* XATTR_MAPPINGS */ /* List efs info xattr for encrypted files */ if (ni->vol->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) { - ret += sizeof(nf_ns_xattr_efsinfo); + ret += sizeof(nf_ns_alt_xattr_efsinfo); if ((size_t)ret <= size) { - memcpy(to, nf_ns_xattr_efsinfo, - sizeof(nf_ns_xattr_efsinfo)); - to += sizeof(nf_ns_xattr_efsinfo); + memcpy(to, nf_ns_alt_xattr_efsinfo, + sizeof(nf_ns_alt_xattr_efsinfo)); + to += sizeof(nf_ns_alt_xattr_efsinfo); +#endif /* XATTR_MAPPINGS */ } } exit : diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index f74a5b36..bafaec56 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -224,6 +224,9 @@ typedef struct { BOOL mounted; #ifdef HAVE_SETXATTR /* extended attributes interface required */ BOOL efs_raw; +#ifdef XATTR_MAPPINGS + char *xattrmap_path; +#endif /* XATTR_MAPPINGS */ #endif /* HAVE_SETXATTR */ struct fuse_chan *fc; BOOL inherit; @@ -2806,7 +2809,7 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, int namespace; struct SECURITY_CONTEXT security; - attr = ntfs_xattr_system_type(name); + attr = ntfs_xattr_system_type(name,ctx->vol); if (attr != XATTR_UNMAPPED) { /* * hijack internal data and ACL retrieval, whatever @@ -2959,7 +2962,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, int namespace; struct SECURITY_CONTEXT security; - attr = ntfs_xattr_system_type(name); + attr = ntfs_xattr_system_type(name,ctx->vol); if (attr != XATTR_UNMAPPED) { /* * hijack internal data and ACL setting, whatever @@ -3167,7 +3170,7 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na int namespace; struct SECURITY_CONTEXT security; - attr = ntfs_xattr_system_type(name); + attr = ntfs_xattr_system_type(name,ctx->vol); if (attr != XATTR_UNMAPPED) { switch (attr) { /* @@ -3783,6 +3786,20 @@ static char *parse_mount_options(const char *orig_opts) goto err_exit; } #ifdef HAVE_SETXATTR /* extended attributes interface required */ +#ifdef XATTR_MAPPINGS + } else if (!strcmp(opt, "xattrmapping")) { + if (!val) { + ntfs_log_error("'xattrmapping' option should have " + "a value.\n"); + goto err_exit; + } + ctx->xattrmap_path = strdup(val); + if (!ctx->xattrmap_path) { + ntfs_log_error("no more memory to store " + "'xattrmapping' option.\n"); + goto err_exit; + } +#endif /* XATTR_MAPPINGS */ } else if (!strcmp(opt, "efs_raw")) { if (bogus_option_value(val, "efs_raw")) goto err_exit; @@ -4161,6 +4178,9 @@ int main(int argc, char *argv[]) #endif const char *permissions_mode = (const char*)NULL; const char *failed_secure = (const char*)NULL; +#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) + struct XATTRMAPPING *xattr_mapping = (struct XATTRMAPPING*)NULL; +#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ struct stat sbuf; unsigned long existing_mount; int err, fd; @@ -4342,6 +4362,18 @@ int main(int argc, char *argv[]) if (ctx->usermap_path) free (ctx->usermap_path); +#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) + xattr_mapping = ntfs_xattr_build_mapping(ctx->vol, + ctx->xattrmap_path); + ctx->vol->xattr_mapping = xattr_mapping; + /* + * Errors are logged, do not refuse mounting, it would be + * too difficult to fix the unmountable mapping file. + */ + if (ctx->xattrmap_path) + free(ctx->xattrmap_path); +#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ + se = mount_fuse(parsed_options); if (!se) { err = NTFS_VOLUME_FUSE_ERROR; @@ -4372,6 +4404,9 @@ err_out: ntfs_mount_error(opts.device, opts.mnt_point, err); if (ctx->abs_mnt_point) free(ctx->abs_mnt_point); +#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) + ntfs_xattr_free_mapping(xattr_mapping); +#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ err2: ntfs_close(); free(ctx); diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 6458ae12..cee99020 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -185,6 +185,9 @@ typedef struct { BOOL mounted; #ifdef HAVE_SETXATTR /* extended attributes interface required */ BOOL efs_raw; +#ifdef XATTR_MAPPINGS + char *xattrmap_path; +#endif /* XATTR_MAPPINGS */ #endif /* HAVE_SETXATTR */ struct fuse_chan *fc; BOOL inherit; @@ -2752,7 +2755,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, int namespace; struct SECURITY_CONTEXT security; - attr = ntfs_xattr_system_type(name); + attr = ntfs_xattr_system_type(name,ctx->vol); if (attr != XATTR_UNMAPPED) { #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) /* @@ -2884,7 +2887,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, int namespace; struct SECURITY_CONTEXT security; - attr = ntfs_xattr_system_type(name); + attr = ntfs_xattr_system_type(name,ctx->vol); if (attr != XATTR_UNMAPPED) { #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) /* @@ -3078,7 +3081,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) int namespace; struct SECURITY_CONTEXT security; - attr = ntfs_xattr_system_type(name); + attr = ntfs_xattr_system_type(name,ctx->vol); if (attr != XATTR_UNMAPPED) { switch (attr) { /* @@ -3692,6 +3695,20 @@ static char *parse_mount_options(const char *orig_opts) goto err_exit; } #ifdef HAVE_SETXATTR /* extended attributes interface required */ +#ifdef XATTR_MAPPINGS + } else if (!strcmp(opt, "xattrmapping")) { + if (!val) { + ntfs_log_error("'xattrmapping' option should have " + "a value.\n"); + goto err_exit; + } + ctx->xattrmap_path = strdup(val); + if (!ctx->xattrmap_path) { + ntfs_log_error("no more memory to store " + "'xattrmapping' option.\n"); + goto err_exit; + } +#endif /* XATTR_MAPPINGS */ } else if (!strcmp(opt, "efs_raw")) { if (bogus_option_value(val, "efs_raw")) goto err_exit; @@ -4073,6 +4090,9 @@ int main(int argc, char *argv[]) #endif const char *permissions_mode = (const char*)NULL; const char *failed_secure = (const char*)NULL; +#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) + struct XATTRMAPPING *xattr_mapping = (struct XATTRMAPPING*)NULL; +#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ struct stat sbuf; unsigned long existing_mount; int err, fd; @@ -4253,6 +4273,18 @@ int main(int argc, char *argv[]) if (ctx->usermap_path) free (ctx->usermap_path); +#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) + xattr_mapping = ntfs_xattr_build_mapping(ctx->vol, + ctx->xattrmap_path); + ctx->vol->xattr_mapping = xattr_mapping; + /* + * Errors are logged, do not refuse mounting, it would be + * too difficult to fix the unmountable mapping file. + */ + if (ctx->xattrmap_path) + free(ctx->xattrmap_path); +#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ + fh = mount_fuse(parsed_options); if (!fh) { err = NTFS_VOLUME_FUSE_ERROR; @@ -4285,6 +4317,9 @@ err_out: ntfs_mount_error(opts.device, opts.mnt_point, err); if (ctx->abs_mnt_point) free(ctx->abs_mnt_point); +#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) + ntfs_xattr_free_mapping(xattr_mapping); +#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */ err2: ntfs_close(); free(ctx); diff --git a/src/secaudit.c b/src/secaudit.c index a6fbf859..7485d719 100644 --- a/src/secaudit.c +++ b/src/secaudit.c @@ -175,6 +175,9 @@ * Mar 2010, version 1.3.17 * - adapted to new default user mapping * - fixed #ifdef'd code for selftest + * + * May 2010, version 1.3.18 + * - redefined early error logging */ /* @@ -198,7 +201,7 @@ * General parameters which may have to be adapted to needs */ -#define AUDT_VERSION "1.3.17" +#define AUDT_VERSION "1.3.18" #define GET_FILE_SECURITY "ntfs_get_file_security" #define SET_FILE_SECURITY "ntfs_set_file_security" @@ -312,6 +315,11 @@ typedef int (*dircallback)(struct CALLBACK *context, char *ntfsname, int length, int type, long long pos, u64 mft_ref, unsigned int dt_type); +#ifndef HAVE_SYSLOG_H +void ntfs_log_early_error(const char *format, ...) + __attribute__((format(printf, 1, 2))); +#endif + #if USESTUBS | defined(STSC) int ntfs_get_file_security(void *scapi, @@ -1271,6 +1279,23 @@ void printerror(FILE *file) #endif } +#ifndef HAVE_SYSLOG_H + +/* + * Redefine early error messages in stand-alone situations + */ + +void ntfs_log_early_error(const char *format, ...) +{ + va_list args; + + va_start(args, format); + vfprintf(stderr,format,args); + va_end(args); +} + +#endif + /* * Guess whether a security attribute is intended for a directory * based on the presence of inheritable ACE