diff --git a/include/ntfs-3g/index.h b/include/ntfs-3g/index.h index f43504b9..0e129bd2 100644 --- a/include/ntfs-3g/index.h +++ b/include/ntfs-3g/index.h @@ -25,6 +25,34 @@ #ifndef _NTFS_INDEX_H #define _NTFS_INDEX_H +/* Convenience macros to test the versions of gcc. + * Use them like this: + * #if __GNUC_PREREQ (2,8) + * ... code requiring gcc 2.8 or later ... + * #endif + * Note - they won't work for gcc1 or glibc1, since the _MINOR macros + * were not defined then. + */ + +#ifndef __GNUC_PREREQ +# if defined __GNUC__ && defined __GNUC_MINOR__ +# define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +# else +# define __GNUC_PREREQ(maj, min) 0 +# endif +#endif + +/* allows us to warn about unused results of certain function calls */ +#ifndef __attribute_warn_unused_result__ +# if __GNUC_PREREQ (3,4) +# define __attribute_warn_unused_result__ \ + __attribute__ ((__warn_unused_result__)) +# else +# define __attribute_warn_unused_result__ /* empty */ +# endif +#endif + #include "attrib.h" #include "types.h" #include "layout.h" @@ -108,7 +136,7 @@ extern void ntfs_index_ctx_put(ntfs_index_context *ictx); extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx); extern int ntfs_index_lookup(const void *key, const int key_len, - ntfs_index_context *ictx); + ntfs_index_context *ictx) __attribute_warn_unused_result__; extern INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx); diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c index a5a82b55..a86aa237 100644 --- a/libntfs-3g/security.c +++ b/libntfs-3g/security.c @@ -1038,6 +1038,7 @@ static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz, /* * Enter a new security descriptor in $Secure (data and indexes) * Returns id of entry, or zero if there is a problem. + * (should not be called for NTFS version < 3.0) * * important : calls have to be serialized, however no locking is * needed while fuse is not multithreaded @@ -1059,6 +1060,7 @@ static le32 entersecurityattr(ntfs_volume *vol, off_t offs; int gap; int size; + BOOL found; struct SII *psii; INDEX_ENTRY *entry; INDEX_ENTRY *next; @@ -1076,10 +1078,15 @@ static le32 entersecurityattr(ntfs_volume *vol, ntfs_index_ctx_reinit(xsii); offs = size = 0; keyid = cpu_to_le32(-1); - ntfs_index_lookup((char*)&keyid, + found = !ntfs_index_lookup((char*)&keyid, sizeof(SII_INDEX_KEY), xsii); - entry = xsii->entry; - psii = (struct SII*)xsii->entry; + if (!found && (errno != ENOENT)) { + ntfs_log_perror("Inconsistency in index $SII"); + psii = (struct SII*)NULL; + } else { + entry = xsii->entry; + psii = (struct SII*)xsii->entry; + } if (psii) { /* * Get last entry in block, but must get first one @@ -1234,58 +1241,69 @@ static le32 setsecurityattr(ntfs_volume *vol, */ key.hash = hash; key.security_id = cpu_to_le32(0); - ntfs_index_lookup((char*)&key, sizeof(SDH_INDEX_KEY), xsdh); - entry = xsdh->entry; - found = FALSE; - /* lookup() may return a node with no data, if so get next */ - if (entry->ie_flags & INDEX_ENTRY_END) - entry = ntfs_index_next(entry,xsdh); - do { - collision = FALSE; - psdh = (struct SDH*)entry; - if (psdh) - size = (size_t) le32_to_cpu(psdh->datasize) - - sizeof(SECURITY_DESCRIPTOR_HEADER); - else size = 0; - /* if hash is not the same, the key is not present */ - if (psdh && (size > 0) - && (psdh->keyhash == hash)) { - /* if hash is the same */ - /* check the whole record */ - realign.parts.dataoffsh = psdh->dataoffsh; - realign.parts.dataoffsl = psdh->dataoffsl; - offs = le64_to_cpu(realign.all) - + sizeof(SECURITY_DESCRIPTOR_HEADER); - oldattr = (char*)ntfs_malloc(size); - if (oldattr) { - rdsize = ntfs_local_read( - vol->secure_ni, - STREAM_SDS, 4, - oldattr, size, offs); - found = (rdsize == size) - && !memcmp(oldattr,attr,size); - free(oldattr); - /* if the records do not compare */ - /* (hash collision), try next one */ - if (!found) { - entry = ntfs_index_next( - entry,xsdh); - collision = TRUE; - } - } else - res = ENOMEM; - } - } while (collision && entry); - if (found) - securid = psdh->keysecurid; + found = !ntfs_index_lookup((char*)&key, + sizeof(SDH_INDEX_KEY), xsdh); + if (!found && (errno != ENOENT)) + ntfs_log_perror("Inconsistency in index $SDH"); else { - if (res) { - errno = res; - securid = cpu_to_le32(0); - } else { - /* no matching key : have to build a new one */ - securid = entersecurityattr(vol, - attr, attrsz, hash); + entry = xsdh->entry; + found = FALSE; + /* + * lookup() may return a node with no data, + * if so get next + */ + if (entry->ie_flags & INDEX_ENTRY_END) + entry = ntfs_index_next(entry,xsdh); + do { + collision = FALSE; + psdh = (struct SDH*)entry; + if (psdh) + size = (size_t) le32_to_cpu(psdh->datasize) + - sizeof(SECURITY_DESCRIPTOR_HEADER); + else size = 0; + /* if hash is not the same, the key is not present */ + if (psdh && (size > 0) + && (psdh->keyhash == hash)) { + /* if hash is the same */ + /* check the whole record */ + realign.parts.dataoffsh = psdh->dataoffsh; + realign.parts.dataoffsl = psdh->dataoffsl; + offs = le64_to_cpu(realign.all) + + sizeof(SECURITY_DESCRIPTOR_HEADER); + oldattr = (char*)ntfs_malloc(size); + if (oldattr) { + rdsize = ntfs_local_read( + vol->secure_ni, + STREAM_SDS, 4, + oldattr, size, offs); + found = (rdsize == size) + && !memcmp(oldattr,attr,size); + free(oldattr); + /* if the records do not compare */ + /* (hash collision), try next one */ + if (!found) { + entry = ntfs_index_next( + entry,xsdh); + collision = TRUE; + } + } else + res = ENOMEM; + } + } while (collision && entry); + if (found) + securid = psdh->keysecurid; + else { + if (res) { + errno = res; + securid = cpu_to_le32(0); + } else { + /* + * no matching key : + * have to build a new one + */ + securid = entersecurityattr(vol, + attr, attrsz, hash); + } } } } @@ -1942,7 +1960,9 @@ static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id) securattr = (char*)NULL; } } - } + } else + if (errno != ENOENT) + ntfs_log_perror("Inconsistency in index $SII"); } if (!securattr) { ntfs_log_error("Failed to retrieve a security descriptor\n"); @@ -2381,7 +2401,8 @@ static char *getsecurityattr(ntfs_volume *vol, * with a default security descriptor inserted in an * attribute */ - if (test_nino_flag(ni, v3_Extensions) && ni->security_id) { + if (test_nino_flag(ni, v3_Extensions) + && vol->secure_ni && ni->security_id) { /* get v3.x descriptor in $Secure */ securid.security_id = ni->security_id; securattr = retrievesecurityattr(vol,securid); @@ -4337,14 +4358,21 @@ int ntfs_open_secure(ntfs_volume *vol) res = -1; vol->secure_ni = (ntfs_inode*)NULL; - ni = ntfs_pathname_to_inode(vol, NULL, "$Secure"); - if (ni) { - vol->secure_reentry = 0; - vol->secure_xsii = ntfs_index_ctx_get(ni, sii_stream, 4); - vol->secure_xsdh = ntfs_index_ctx_get(ni, sdh_stream, 4); - if (ni && vol->secure_xsii && vol->secure_xsdh) { - vol->secure_ni = ni; - res = 0; + vol->secure_xsii = (ntfs_index_context*)NULL; + vol->secure_xsdh = (ntfs_index_context*)NULL; + if (vol->major_ver >= 3) { + /* make sure this is a genuine $Secure inode 9 */ + ni = ntfs_pathname_to_inode(vol, NULL, "$Secure"); + if (ni && (ni->mft_no == 9)) { + vol->secure_reentry = 0; + vol->secure_xsii = ntfs_index_ctx_get(ni, + sii_stream, 4); + vol->secure_xsdh = ntfs_index_ctx_get(ni, + sdh_stream, 4); + if (ni && vol->secure_xsii && vol->secure_xsdh) { + vol->secure_ni = ni; + res = 0; + } } } return (res); @@ -4799,6 +4827,8 @@ ok = TRUE; /* clarification needed */ /* * read $SDS (for auditing security data) + * + * Returns the number or read bytes, or -1 if there is an error */ int ntfs_read_sds(struct SECURITY_API *scapi, @@ -4806,10 +4836,13 @@ int ntfs_read_sds(struct SECURITY_API *scapi, { int got; - got = 0; /* default return */ + got = -1; /* default return */ if (scapi && (scapi->magic == MAGIC_API)) { - got = ntfs_local_read(scapi->security.vol->secure_ni, - STREAM_SDS, 4, buf, size, offset); + if (scapi->security.vol->secure_ni) + got = ntfs_local_read(scapi->security.vol->secure_ni, + STREAM_SDS, 4, buf, size, offset); + else + errno = EOPNOTSUPP; } else errno = EINVAL; return (got); @@ -4817,58 +4850,67 @@ int ntfs_read_sds(struct SECURITY_API *scapi, /* * read $SII (for auditing security data) + * + * Returns next entry, or NULL if there is an error */ INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi, INDEX_ENTRY *entry) { SII_INDEX_KEY key; + INDEX_ENTRY *ret; ntfs_index_context *xsii; + ret = (INDEX_ENTRY*)NULL; /* default return */ if (scapi && (scapi->magic == MAGIC_API)) { xsii = scapi->security.vol->secure_xsii; - if (!entry) { - key.security_id = cpu_to_le32(0); - ntfs_index_lookup((char*)&key, - sizeof(SII_INDEX_KEY), xsii); - entry = xsii->entry; + if (xsii) { + if (!entry) { + key.security_id = cpu_to_le32(0); + if (!ntfs_index_lookup((char*)&key, + sizeof(SII_INDEX_KEY), xsii)) + ret = xsii->entry; + } else + ret = ntfs_index_next(entry,xsii); + if (!ret) + errno = ENODATA; } else - entry = ntfs_index_next(entry,xsii); - if (!entry) - errno = ENODATA; - } else { - entry = (INDEX_ENTRY*)NULL; + errno = EOPNOTSUPP; + } else errno = EINVAL; - } return (entry); } /* * read $SDH (for auditing security data) + * + * Returns next entry, or NULL if there is an error */ INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi, INDEX_ENTRY *entry) { SDH_INDEX_KEY key; + INDEX_ENTRY *ret; ntfs_index_context *xsdh; + ret = (INDEX_ENTRY*)NULL; /* default return */ if (scapi && (scapi->magic == MAGIC_API)) { xsdh = scapi->security.vol->secure_xsdh; - if (!entry) { - key.hash = cpu_to_le32(0); - key.security_id = cpu_to_le32(0); - ntfs_index_lookup((char*)&key, - sizeof(SDH_INDEX_KEY), xsdh); - entry = xsdh->entry; - } else - entry = ntfs_index_next(entry,xsdh); - if (!entry) - errno = ENODATA; - } else { - entry = (INDEX_ENTRY*)NULL; + if (xsdh) { + if (!entry) { + key.hash = cpu_to_le32(0); + key.security_id = cpu_to_le32(0); + if (!ntfs_index_lookup((char*)&key, + sizeof(SDH_INDEX_KEY), xsdh)) + ret = xsdh->entry; + } else + ret = ntfs_index_next(entry,xsdh); + if (!ret) + errno = ENODATA; + } else errno = ENOTSUP; + } else errno = EINVAL; - } return (entry); } @@ -4906,11 +4948,9 @@ struct SECURITY_API *ntfs_initialize_file_security(const char *device, scx->gid = getgid(); scx->pseccache = &scapi->seccache; scx->vol->secure_flags = 0; - if (ntfs_build_mapping(scx,(const char*)NULL) - || ntfs_open_secure(vol)) { - free(scapi); - scapi = (struct SECURITY_API*)NULL; - } + /* accept no mapping and no $Secure */ + ntfs_build_mapping(scx,(const char*)NULL); + ntfs_open_secure(vol); } else errno = ENOMEM; } diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 86c7a8a7..3decda5b 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -2660,8 +2660,9 @@ int main(int argc, char *argv[]) ctx->vol->secure_flags = 0; if (ctx->addsecurids && !ctx->ro) ctx->vol->secure_flags = (1 << SECURITY_ADDSECURIDS); - /* JPA open $Secure and build user mapping (right place ?) */ - if (ntfs_open_secure(ctx->vol)) + /* JPA open $Secure, (whatever NTFS version !) */ + /* to initialize security data */ + if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3)) ntfs_log_info("Could not open file $Secure\n"); if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path)) ntfs_log_info("User mapping built\n");