static void inserthashindex(struct CACHE_HEADER *cache, struct CACHED_GENERIC *current) { int h; struct HASH_ENTRY *link; struct HASH_ENTRY *first; if (cache->dohash) { h = cache->dohash(current); if ((h >= 0) && (h < cache->max_hash)) { /* get a free link and insert at top of hash list */ link = cache->free_hash; if (link) { cache->free_hash = link->next; first = cache->first_hash[h]; if (first) link->next = first; else link->next = NULL; link->entry = current; cache->first_hash[h] = link; } else { ntfs_log_error("No more hash entries," " cache %s hashing dropped\n", cache->name); cache->dohash = (cache_hash)NULL; } } else { ntfs_log_error("Illegal hash value," " cache %s hashing dropped\n", cache->name); cache->dohash = (cache_hash)NULL; } } }
/** * ntfs_pkcs12_load_pfxfile */ static int ntfs_pkcs12_load_pfxfile(const char *keyfile, u8 **pfx, unsigned *pfx_size) { int f, to_read, total, attempts, br; struct stat key_stat; if (!keyfile || !pfx || !pfx_size) { ntfs_log_error("You have to specify the key file, a pointer " "to hold the key file contents, and a pointer " "to hold the size of the key file contents.\n"); return -1; } f = open(keyfile, O_RDONLY); if (f == -1) { ntfs_log_perror("Failed to open key file"); return -1; } if (fstat(f, &key_stat) == -1) { ntfs_log_perror("Failed to stat key file"); goto file_out; } if (!S_ISREG(key_stat.st_mode)) { ntfs_log_error("Key file is not a regular file, cannot read " "it.\n"); goto file_out; } if (!key_stat.st_size) { ntfs_log_error("Key file has zero size.\n"); goto file_out; } *pfx = malloc(key_stat.st_size + 1); if (!*pfx) { ntfs_log_perror("Failed to allocate buffer for key file " "contents"); goto file_out; } to_read = key_stat.st_size; total = attempts = 0; do { br = read(f, *pfx + total, to_read); if (br == -1) { ntfs_log_perror("Failed to read from key file"); goto free_out; } if (!br) attempts++; to_read -= br; total += br; } while (to_read > 0 && attempts < 3); close(f); /* Make sure it is zero terminated. */ (*pfx)[key_stat.st_size] = 0; *pfx_size = key_stat.st_size; return 0; free_out: free(*pfx); file_out: close(f); return -1; }
static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn) { u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18; ntfs_log_trace("Entering\n"); if (!ntfs_is_indx_record(ib->magic)) { ntfs_log_error("Corrupt index block signature: vcn %lld inode " "%llu\n", (long long)vcn, (unsigned long long)icx->ni->mft_no); return -1; } if (sle64_to_cpu(ib->index_block_vcn) != vcn) { ntfs_log_error("Corrupt index block: VCN (%lld) is different " "from expected VCN (%lld) in inode %llu\n", (long long)sle64_to_cpu(ib->index_block_vcn), (long long)vcn, (unsigned long long)icx->ni->mft_no); return -1; } if (ib_size != icx->block_size) { ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu " "has a size (%u) differing from the index " "specified size (%u)\n", (long long)vcn, (unsigned long long)icx->ni->mft_no, ib_size, icx->block_size); return -1; } return 0; }
static int parse_options(int argc, char *argv[]) { int c; static const char *sopt = "-hrw"; static const struct option lopt[] = { { "readonly", no_argument, NULL, 'r' }, { "readwrite", no_argument, NULL, 'w' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; opterr = 0; /* We handle errors. */ opts.probetype = PROBE_UNSET; while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { switch (c) { case 1: /* A non-option argument */ if (!opts.device) { opts.device = ntfs_malloc(PATH_MAX + 1); if (!opts.device) return -1; strncpy(opts.device, optarg, PATH_MAX); opts.device[PATH_MAX] = 0; } else { ntfs_log_error("%s: You must specify exactly " "one device\n", EXEC_NAME); return -1; } break; case 'h': usage(); exit(0); case 'r': opts.probetype = PROBE_READONLY; break; case 'w': opts.probetype = PROBE_READWRITE; break; default: ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME, argv[optind - 1]); return -1; } } if (!opts.device) { ntfs_log_error("ERROR: %s: Device is missing\n", EXEC_NAME); return -1; } if (opts.probetype == PROBE_UNSET) { ntfs_log_error("ERROR: %s: Probe type is missing\n", EXEC_NAME); return -1; } return 0; }
static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo, const OBJECT_ID_ATTR *value, size_t size) { OBJECT_ID_ATTR old_attr; ntfs_attr *na; int oldsize; int written; int res; res = 0; na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0); if (na) { /* remove the existing index entry */ oldsize = remove_object_id_index(na,xo,&old_attr); if (oldsize < 0) res = -1; else { /* resize attribute */ res = ntfs_attr_truncate(na, (s64)sizeof(GUID)); /* write the object_id in attribute */ if (!res && value) { written = (int)ntfs_attr_pwrite(na, (s64)0, (s64)sizeof(GUID), &value->object_id); if (written != (s64)sizeof(GUID)) { ntfs_log_error("Failed to update " "object id\n"); errno = EIO; res = -1; } } /* write index part if provided */ if (!res && ((size < sizeof(OBJECT_ID_ATTR)) || set_object_id_index(ni,xo,value))) { /* * If cannot index, try to remove the object * id and log the error. There will be an * inconsistency if removal fails. */ ntfs_attr_rm(na); ntfs_log_error("Failed to index object id." " Possible corruption.\n"); } } ntfs_attr_close(na); NInoSetDirty(ni); } else res = -1; return (res); }
void utils_mount_error(const char *volume, const char *mntpoint, int err) { switch (err) { case NTFS_VOLUME_NOT_NTFS: ntfs_log_error(invalid_ntfs_msg, volume); break; case NTFS_VOLUME_CORRUPT: ntfs_log_error("%s", corrupt_volume_msg); break; case NTFS_VOLUME_HIBERNATED: ntfs_log_error(hibernated_volume_msg, volume, mntpoint); break; case NTFS_VOLUME_UNCLEAN_UNMOUNT: ntfs_log_error(unclean_journal_msg); ntfs_log_error(forced_mount_msg, volume, mntpoint, volume, mntpoint); break; case NTFS_VOLUME_LOCKED: ntfs_log_error("%s", opened_volume_msg); break; case NTFS_VOLUME_RAID: ntfs_log_error("%s", fakeraid_msg); break; case NTFS_VOLUME_NO_PRIVILEGE: ntfs_log_error(access_denied_msg, volume); break; } }
static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr, const char *value, size_t size) { int res; int written; int oldsize; ntfs_attr *na; le32 reparse_tag; res = 0; na = ntfs_attr_open(ni, AT_REPARSE_POINT, AT_UNNAMED, 0); if (na) { /* remove the existing reparse data */ oldsize = remove_reparse_index(na,xr,&reparse_tag); if (oldsize < 0) res = -1; else { /* resize attribute */ res = ntfs_attr_truncate(na, (s64)size); /* overwrite value if any */ if (!res && value) { written = (int)ntfs_attr_pwrite(na, (s64)0, (s64)size, value); if (written != (s64)size) { ntfs_log_error("Failed to update " "reparse data\n"); errno = EIO; res = -1; } } if (!res && set_reparse_index(ni,xr, ((const REPARSE_POINT*)value)->reparse_tag) && (oldsize > 0)) { /* * If cannot index, try to remove the reparse * data and log the error. There will be an * inconsistency if removal fails. */ ntfs_attr_rm(na); ntfs_log_error("Failed to index reparse data." " Possible corruption.\n"); } } ntfs_attr_close(na); NInoSetDirty(ni); } else res = -1; return (res); }
/** * ntfs_desx_decrypt */ static void ntfs_desx_decrypt(ntfs_fek *fek, u8 *outbuf, const u8 *inbuf) { gcry_error_t err; ntfs_desx_ctx *ctx = &fek->desx_ctx; err = gcry_cipher_reset(fek->gcry_cipher_hd); if (err != GPG_ERR_NO_ERROR) ntfs_log_error("Failed to reset des cipher (error 0x%x).\n", err); *(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening; err = gcry_cipher_encrypt(fek->gcry_cipher_hd, outbuf, 8, NULL, 0); if (err != GPG_ERR_NO_ERROR) ntfs_log_error("Des decryption failed (error 0x%x).\n", err); *(u64*)outbuf ^= ctx->in_whitening; }
/** * ntfs_rsa_private_key_import_from_gnutls */ static ntfs_rsa_private_key ntfs_rsa_private_key_import_from_gnutls( gnutls_x509_privkey_t priv_key) { int i, j; size_t tmp_size; gnutls_datum_t rd[6]; gcry_mpi_t rm[6]; gcry_sexp_t rsa_key; /* Extract the RSA parameters from the GNU TLS private key. */ if (gnutls_x509_privkey_export_rsa_raw(priv_key, &rd[0], &rd[1], &rd[2], &rd[3], &rd[4], &rd[5])) { ntfs_log_error("Failed to export rsa parameters. (Is the " "key an RSA private key?)\n"); return NULL; } /* Convert each RSA parameter to mpi format. */ for (i = 0; i < 6; i++) { if (gcry_mpi_scan(&rm[i], GCRYMPI_FMT_USG, rd[i].data, rd[i].size, &tmp_size) != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to convert RSA parameter %i " "to mpi format (size %d)\n", i, rd[i].size); rsa_key = NULL; break; } } /* Release the no longer needed datum values. */ for (j = 0; j < 6; j++) { if (rd[j].data && rd[j].size) gnutls_free(rd[j].data); } /* * Build the gcrypt private key, note libgcrypt uses p and q inversed * to what gnutls uses. */ if (i == 6 && gcry_sexp_build(&rsa_key, NULL, "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", rm[0], rm[1], rm[2], rm[4], rm[3], rm[5]) != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to build RSA private key s-exp.\n"); rsa_key = NULL; } /* Release the no longer needed mpi values. */ for (j = 0; j < i; j++) gcry_mpi_release(rm[j]); return (ntfs_rsa_private_key)rsa_key; }
static int ntfs_merge_allocation(ntfs_attr *na, runlist_element *rl, s64 size) { ntfs_volume *vol; int err; err = 0; vol = na->ni->vol; /* Newly allocated clusters before initialized size need be zeroed */ if ((rl->vcn << vol->cluster_size_bits) < na->initialized_size) { err = ntfs_inner_zero(na, rl); } if (!err) { if (na->data_flags & ATTR_IS_SPARSE) { na->compressed_size += size; if (na->compressed_size >= na->allocated_size) { na->data_flags &= ~ATTR_IS_SPARSE; if (na->compressed_size > na->allocated_size) { ntfs_log_error("File size error : " "apparent %lld, " "compressed %lld > " "allocated %lld", (long long)na->data_size, (long long)na->compressed_size, (long long)na->allocated_size); errno = EIO; err = -1; } } } } if (!err) { rl = ntfs_runlists_merge(na->rl, rl); if (!rl) { ntfs_log_error("Failed to merge the new allocation\n"); err = -1; } else { na->rl = rl; /* Update the runlist */ if (ntfs_attr_update_mapping_pairs(na, 0)) { ntfs_log_error( "Failed to update the runlist\n"); err = -1; } } } return (err); }
/** * ntfs_des_test */ static BOOL ntfs_des_test(void) { const u8 known_des_key[8] = { 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f }; const u8 known_des_encrypted_data[8] = { 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f }; const u8 known_decrypted_data[8] = { 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09 }; u8 test_decrypted_data[8]; int res; gcry_error_t err; gcry_cipher_hd_t gcry_cipher_hd; err = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to open des cipher (error 0x%x).\n", err); return FALSE; } err = gcry_cipher_setkey(gcry_cipher_hd, known_des_key, sizeof(known_des_key)); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to set des key (error 0x%x.\n", err); gcry_cipher_close(gcry_cipher_hd); return FALSE; } /* * Apply DES decryption (ntfs actually uses encryption when decrypting). */ err = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data, sizeof(test_decrypted_data), known_des_encrypted_data, sizeof(known_des_encrypted_data)); gcry_cipher_close(gcry_cipher_hd); if (err) { ntfs_log_error("Failed to des decrypt test data (error " "0x%x).\n", err); return FALSE; } res = !memcmp(test_decrypted_data, known_decrypted_data, sizeof(known_decrypted_data)); ntfs_log_error("Testing whether des decryption works: %s\n", res ? "SUCCESS" : "FAILED"); return res; }
/** * ntfs_inode_update_times - update selected time fields for ntfs inode * @ni: ntfs inode for which update time fields * @mask: select which time fields should be updated * * This function updates time fields to current time. Fields to update are * selected using @mask (see enum @ntfs_time_update_flags for posssible values). */ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) { time_t now; if (!ni) { ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__); return; } if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) || NVolReadOnly(ni->vol) || !mask) return; now = time(NULL); if (mask & NTFS_UPDATE_ATIME) ni->last_access_time = now; if (mask & NTFS_UPDATE_MTIME) ni->last_data_change_time = now; if (mask & NTFS_UPDATE_CTIME) ni->last_mft_change_time = now; set_nino_flag(ni, TimesDirty); NInoFileNameSetDirty(ni); NInoSetDirty(ni); }
/** * Assumes mft_bitmap_rl is initialized. * return: 0 ok. * RETURN_OPERATIONAL_ERROR on error. */ static int mft_bitmap_load(ntfs_volume *rawvol) { VCN vcn; u32 mft_bitmap_length; vcn = get_last_vcn(mft_bitmap_rl); if (vcn<=LCN_EINVAL) { mft_bitmap_buf = NULL; /* This case should not happen, not even with on-disk errors */ goto error; } mft_bitmap_length = vcn * rawvol->cluster_size; mft_bitmap_records = 8 * mft_bitmap_length * rawvol->cluster_size / rawvol->mft_record_size; //printf("sizes: %d, %d.\n", mft_bitmap_length, mft_bitmap_records); mft_bitmap_buf = (u8*)ntfs_malloc(mft_bitmap_length); if (!mft_bitmap_buf) goto error; if (ntfs_rl_pread(rawvol, mft_bitmap_rl, 0, mft_bitmap_length, mft_bitmap_buf)!=mft_bitmap_length) goto error; return 0; error: mft_bitmap_records = 0; ntfs_log_error("Could not load $MFT/Bitmap.\n"); return RETURN_OPERATIONAL_ERROR; }
static void ntfs_restore_rl(ntfs_attr *na, runlist_element *oldrl) { runlist_element *brl; /* Pointer to bad runlist */ runlist_element *grl; /* Pointer to good runlist */ ntfs_volume *vol; vol = na->ni->vol; /* Examine allocated entries from the bad runlist */ for (brl=na->rl; brl->length; brl++) { if (brl->lcn != LCN_HOLE) { // TODO improve by examining both list in parallel /* Find the holes in the good runlist which overlap */ for (grl=oldrl; grl->length && (grl->vcn<=(brl->vcn+brl->length)); grl++) { if (grl->lcn == LCN_HOLE) { free_common(vol, brl, brl->length, grl, grl->length); } } /* Free allocations beyond the end of good runlist */ if (grl && !grl->length && ((brl->vcn + brl->length) > grl->vcn)) { free_common(vol, brl, brl->length, grl, brl->vcn + brl->length - grl->vcn); } } } free(na->rl); na->rl = oldrl; if (ntfs_attr_update_mapping_pairs(na, 0)) { ntfs_log_error("Failed to restore the original runlist\n"); } }
status_t fs_read_attrib(fs_volume *_vol, fs_vnode *_node, void *_cookie, off_t pos, void *buffer, size_t *len) { nspace *ns = (nspace *)_vol->private_volume; //vnode *node = (vnode *)_node->private_node; attrcookie *cookie = (attrcookie *)_cookie; ntfs_inode *ni = cookie->inode; ntfs_attr *na = cookie->stream; size_t size = *len; int total = 0; status_t result = B_NO_ERROR; if (pos < 0) { *len = 0; return EINVAL; } LOCK_VOL(ns); TRACE("%s - ENTER\n", __FUNCTION__); // it is a named stream if (na) { if (pos + size > na->data_size) size = na->data_size - pos; while (size) { off_t bytesRead = ntfs_attr_pread(na, pos, size, buffer); if (bytesRead < (s64)size) { ntfs_log_error("ntfs_attr_pread returned less bytes than " "requested.\n"); } if (bytesRead <= 0) { *len = 0; result = EINVAL; goto exit; } size -= bytesRead; pos += bytesRead; total += bytesRead; } *len = total; } else { *len = 0; result = ENOENT; // TODO } fs_ntfs_update_times(_vol, ni, NTFS_UPDATE_ATIME); // XXX needed ? exit: TRACE("%s - EXIT, result is %s\n", __FUNCTION__, strerror(result)); UNLOCK_VOL(ns); return result; }
/** * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute * @mft_no: mft record number where @attr is present * @attr: attribute record used to check for the $Bad attribute * * Check if the mft record given by @mft_no and @attr contains the bad sector * list. Please note that mft record numbers describing $Badclus extent inodes * will not match the current $Badclus:$Bad check. * * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. * On error return -1 with errno set to the error code. */ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) { int len, ret = 0; ntfschar *ustr; if (!attr) { ntfs_log_error("Invalid argument.\n"); errno = EINVAL; return -1; } if (mft_no != FILE_BadClus) return 0; if (attr->type != AT_DATA) return 0; if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) { ntfs_log_perror("Couldn't convert '$Bad' to Unicode"); return -1; } if (ustr && ntfs_names_are_equal(ustr, len, (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)), attr->name_length, 0, NULL, 0)) ret = 1; ntfs_ucsfree(ustr); return ret; }
/** * cat */ static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int namelen) { const int bufsize = 4096; char *buffer; ntfs_attr *attr; s64 bytes_read, written; s64 offset; u32 block_size; buffer = malloc(bufsize); if (!buffer) return 1; attr = ntfs_attr_open(inode, type, name, namelen); if (!attr) { ntfs_log_error("Cannot find attribute type 0x%x.\n", le32_to_cpu(type)); free(buffer); return 1; } if ((inode->mft_no < 2) && (attr->type == AT_DATA)) block_size = vol->mft_record_size; else if (attr->type == AT_INDEX_ALLOCATION) block_size = index_get_size(inode); else block_size = 0; offset = 0; for (;;) { if (!opts.raw && block_size > 0) { // These types have fixup bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer); if (bytes_read > 0) bytes_read *= block_size; } else { bytes_read = ntfs_attr_pread(attr, offset, bufsize, buffer); } //ntfs_log_info("read %lld bytes\n", bytes_read); if (bytes_read == -1) { ntfs_log_perror("ERROR: Couldn't read file"); break; } if (!bytes_read) break; written = fwrite(buffer, 1, bytes_read, stdout); if (written != bytes_read) { ntfs_log_perror("ERROR: Couldn't output all data!"); break; } offset += bytes_read; } ntfs_attr_close(attr); free(buffer); return 0; }
static int missing_option_value(char *val, const char *s) { if (!val) { ntfs_log_error("'%s' option should have a value.\n", s); return -1; } return 0; }
static int bogus_option_value(char *val, const char *s) { if (val) { ntfs_log_error("'%s' option shouldn't have value.\n", s); return -1; } return 0; }
static int ntfs_inner_zero(ntfs_attr *na, runlist_element *rl) { ntfs_volume *vol; char *buf; runlist_element *zrl; s64 cofs; s64 pos; s64 zeroed; int err; err = 0; vol = na->ni->vol; buf = (char*)malloc(vol->cluster_size); if (buf) { memset(buf, 0, vol->cluster_size); zrl = rl; pos = zrl->vcn << vol->cluster_size_bits; while (zrl->length && !err && (pos < na->initialized_size)) { for (cofs=0; cofs<zrl->length && !err; cofs++) { zeroed = ntfs_pwrite(vol->dev, (rl->lcn + cofs) << vol->cluster_size_bits, vol->cluster_size, buf); if (zeroed != vol->cluster_size) { ntfs_log_error("Failed to zero at " "offset %lld\n", (long long)pos); errno = EIO; err = -1; } pos += vol->cluster_size; } zrl++; pos = zrl->vcn << vol->cluster_size_bits; } free(buf); } else { ntfs_log_error("Failed to allocate memory\n"); errno = ENOSPC; err = -1; } return (err); }
/** * ntfs_crypto_init */ static int ntfs_crypto_init(void) { int err; /* Initialize gcrypt library. Note: Must come before GNU TLS init. */ if (gcry_control(GCRYCTL_DISABLE_SECMEM, 0) != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to initialize the gcrypt library.\n"); return -1; } /* Initialize GNU TLS library. Note: Must come after libgcrypt init. */ err = gnutls_global_init(); if (err < 0) { ntfs_log_error("Failed to initialize GNU TLS library: %s\n", gnutls_strerror(err)); return -1; } return 0; }
/** * __ntfs_inode_release - Destroy an NTFS inode object * @ni: * * Description... * * Returns: */ static void __ntfs_inode_release(ntfs_inode *ni) { if (NInoDirty(ni)) ntfs_log_error("Releasing dirty inode %lld!\n", (long long)ni->mft_no); if (NInoAttrList(ni) && ni->attr_list) free(ni->attr_list); free(ni->mrec); free(ni); return; }
/** * main - Begin here * * Start from here. * * Return: 0 Success, the program worked * 1 Error, something went wrong */ int main(int argc, char **argv) { unsigned long mnt_flags = 0; int result = 0; ntfs_volume *vol; ntfs_log_set_handler(ntfs_log_handler_outerr); result = parse_options(argc, argv); if (result >= 0) return (result); result = 0; utils_set_locale(); if ((opts.label || opts.new_serial) && !opts.noaction && !opts.force && !ntfs_check_if_mounted(opts.device, &mnt_flags) && (mnt_flags & NTFS_MF_MOUNTED)) { ntfs_log_error("Cannot make changes to a mounted device\n"); result = 1; goto abort; } if (!opts.label && !opts.new_serial) opts.noaction++; vol = utils_mount_volume(opts.device, (opts.noaction ? NTFS_MNT_RDONLY : 0) | (opts.force ? NTFS_MNT_RECOVER : 0)); if (!vol) return 1; if (opts.new_serial) { result = set_new_serial(vol); if (result) goto unmount; } else { if (opts.verbose) result = print_serial(vol); } if (opts.label) result = change_label(vol, opts.label); else result = print_label(vol, mnt_flags); unmount : ntfs_umount(vol, FALSE); abort : /* "result" may be a negative reply of a library function */ return (result ? 1 : 0); }
/** * utils_set_locale */ int utils_set_locale(void) { const char *locale; locale = setlocale(LC_ALL, ""); if (!locale) { locale = setlocale(LC_ALL, NULL); ntfs_log_error("Couldn't set local environment, using default " "'%s'.\n", locale); return 1; } return 0; }
/** * ntfs_inode_fek_get - */ static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode, ntfs_rsa_private_key rsa_key, char *thumbprint, int thumbprint_size, NTFS_DF_TYPES df_type) { EFS_ATTR_HEADER *efs; EFS_DF_ARRAY_HEADER *df_array = NULL; ntfs_fek *fek = NULL; /* Obtain the $EFS contents. */ efs = ntfs_attr_readall(inode, AT_LOGGED_UTILITY_STREAM, EFS, 4, NULL); if (!efs) { ntfs_log_perror("Failed to read $EFS attribute"); return NULL; } /* * Depending on whether the key is a normal key or a data recovery key, * iterate through the DDF or DRF array, respectively. */ if (df_type == DF_TYPE_DDF) { if (efs->offset_to_ddf_array) df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + le32_to_cpu(efs->offset_to_ddf_array)); else ntfs_log_error("There are no entries in the DDF " "array.\n"); } else if (df_type == DF_TYPE_DRF) { if (efs->offset_to_drf_array) df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + le32_to_cpu(efs->offset_to_drf_array)); else ntfs_log_error("There are no entries in the DRF " "array.\n"); } else ntfs_log_error("Invalid DF type.\n"); if (df_array) fek = ntfs_df_array_fek_get(df_array, rsa_key, thumbprint, thumbprint_size); free(efs); return fek; }
/** * ntfs_desx_key_expand - expand a 128-bit desx key to the needed 192-bit key * @src: source buffer containing 128-bit key * * Expands the on-disk 128-bit desx key to the needed des key, the in-, and the * out-whitening keys required to perform desx {de,en}cryption. */ static gcry_error_t ntfs_desx_key_expand(const u8 *src, u32 *des_key, u64 *out_whitening, u64 *in_whitening) { static const u8 *salt1 = (const u8*)"Dan Simon "; static const u8 *salt2 = (const u8*)"Scott Field"; static const int salt_len = 12; gcry_md_hd_t hd1, hd2; u32 *md; gcry_error_t err; err = gcry_md_open(&hd1, GCRY_MD_MD5, 0); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to open MD5 digest.\n"); return err; } /* Hash the on-disk key. */ gcry_md_write(hd1, src, 128 / 8); /* Copy the current hash for efficiency. */ err = gcry_md_copy(&hd2, hd1); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to copy MD5 digest object.\n"); goto out; } /* Hash with the first salt and store the result. */ gcry_md_write(hd1, salt1, salt_len); md = (u32*)gcry_md_read(hd1, 0); des_key[0] = md[0] ^ md[1]; des_key[1] = md[2] ^ md[3]; /* Hash with the second salt and store the result. */ gcry_md_write(hd2, salt2, salt_len); md = (u32*)gcry_md_read(hd2, 0); *out_whitening = *(u64*)md; *in_whitening = *(u64*)(md + 2); gcry_md_close(hd2); out: gcry_md_close(hd1); return err; }
/** * ntfs_fek_decrypt_sector */ static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset) { gcry_error_t err; err = gcry_cipher_reset(fek->gcry_cipher_hd); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Failed to reset cipher: %s\n", gcry_strerror(err)); return -1; } /* * Note: You may wonder why we are not calling gcry_cipher_setiv() here * instead of doing it by hand after the decryption. The answer is * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give * it a length of 16 for AES256 so it does not like it. */ if (fek->alg_id == CALG_DESX) { int k; for (k=0; k<512; k+=8) { ntfs_desx_decrypt(fek, &data[k], &data[k]); } } else err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0); if (err != GPG_ERR_NO_ERROR) { ntfs_log_error("Decryption failed: %s\n", gcry_strerror(err)); return -1; } /* Apply the IV. */ if (fek->alg_id == CALG_AES_256) { ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset); ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset); } else { /* All other algos (Des, 3Des, DesX) use the same IV. */ ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset); } return 512; }
/** * print_label - display the current label of a mounted ntfs partition. * @dev: device to read the label from * @mnt_flags: mount flags of the device or 0 if not mounted * @mnt_point: mount point of the device or NULL * * Print the label of the device @dev. */ static int print_label(ntfs_volume *vol, unsigned long mnt_flags) { int result = 0; //XXX significant? if ((mnt_flags & (NTFS_MF_MOUNTED | NTFS_MF_READONLY)) == NTFS_MF_MOUNTED) { ntfs_log_error("%s is mounted read-write, results may be " "unreliable.\n", opts.device); result = 1; } ntfs_log_info("%s\n", vol->vol_name); return result; }
static void drophashindex(struct CACHE_HEADER *cache, const struct CACHED_GENERIC *current, int hash) { struct HASH_ENTRY *link; struct HASH_ENTRY *previous; if (cache->dohash) { if ((hash >= 0) && (hash < cache->max_hash)) { /* find the link and unlink */ link = cache->first_hash[hash]; previous = (struct HASH_ENTRY*)NULL; while (link && (link->entry != current)) { previous = link; link = link->next; } if (link) { if (previous) previous->next = link->next; else cache->first_hash[hash] = link->next; link->next = cache->free_hash; cache->free_hash = link; } else { ntfs_log_error("Bad hash list," " cache %s hashing dropped\n", cache->name); cache->dohash = (cache_hash)NULL; } } else { ntfs_log_error("Illegal hash value," " cache %s hashing dropped\n", cache->name); cache->dohash = (cache_hash)NULL; } } }
/** * ntfs_inode_sync_standard_information - update standard information attribute * @ni: ntfs inode to update standard information * * Return 0 on success or -1 on error with errno set to the error code. */ static int ntfs_inode_sync_standard_information(ntfs_inode *ni) { ntfs_attr_search_ctx *ctx; STANDARD_INFORMATION *std_info; u32 lth; le32 lthle; ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { ntfs_log_perror("Failed to sync standard info (inode %lld)", (long long)ni->mft_no); ntfs_attr_put_search_ctx(ctx); return -1; } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); std_info->file_attributes = ni->flags; if (test_nino_flag(ni, TimesDirty)) { std_info->creation_time = utc2ntfs(ni->creation_time); std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time); std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); std_info->last_access_time = utc2ntfs(ni->last_access_time); } /* JPA update v3.x extensions, ensuring consistency */ lthle = ctx->attr->length; lth = le32_to_cpu(lthle); if (test_nino_flag(ni, v3_Extensions) && (lth <= sizeof(STANDARD_INFORMATION))) ntfs_log_error("bad sync of standard information\n"); if (lth > sizeof(STANDARD_INFORMATION)) { std_info->owner_id = ni->owner_id; std_info->security_id = ni->security_id; std_info->quota_charged = ni->quota_charged; std_info->usn = ni->usn; } ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); return 0; }