static void mount_item_proc(mount_ctx *mnt) { dev_hook *hook; int resl; hook = mnt->hook; resl = dc_mount_device(hook->dev_name, NULL, 0); if ( (resl != ST_RW_ERR) && (resl != ST_MEDIA_CHANGED) && (resl != ST_NO_MEDIA) ) { hook->mnt_probed = 1; } if (resl != ST_OK) { if (lock_inc(&hook->mnt_probe_cnt) > MAX_MNT_PROBES) { hook->mnt_probed = 1; } } if (hook->flags & F_ENABLED) { io_read_write_irp(hook, mnt->irp); } else { if (IS_DEVICE_BLOCKED(hook) != 0) { dc_release_irp(hook, mnt->irp, STATUS_ACCESS_DENIED); } else { dc_forward_irp(hook, mnt->irp); } } mm_pool_free(mnt); }
int dc_mount_device(wchar_t *dev_name, dc_pass *password, u32 mnt_flags) { dc_header *hcopy = NULL; dev_hook *hook = NULL; xts_key *hdr_key = NULL; int resl; DbgMsg("dc_mount_device %ws\n", dev_name); do { if ( (hook = dc_find_hook(dev_name)) == NULL ) { resl = ST_NF_DEVICE; break; } wait_object_infinity(&hook->busy_lock); if (hook->flags & F_ENABLED) { resl = ST_ALR_MOUNT; break; } if (hook->flags & (F_UNSUPRT | F_DISABLE | F_FORMATTING)) { resl = ST_ERROR; break; } if ( !NT_SUCCESS(dc_fill_device_info(hook)) ) { resl = ST_IO_ERROR; break; } if ( ( (hook->flags & F_CDROM) && (hook->bps != CD_SECTOR_SIZE) ) || (!(hook->flags & F_CDROM) && IS_INVALID_SECTOR_SIZE(hook->bps) ) ) { hook->flags |= F_UNSUPRT; resl = ST_ERROR; break; } if ( (resl = dc_probe_decrypt(hook, &hcopy, &hdr_key, password)) != ST_OK ) { break; } /* check volume header */ if ( (IS_INVALID_VOL_FLAGS(hcopy->flags) != 0) || ( (hcopy->flags & VF_STORAGE_FILE) && (hcopy->stor_off == 0) ) || (hcopy->alg_1 >= CF_CIPHERS_NUM) || (hcopy->alg_2 >= CF_CIPHERS_NUM) || (hcopy->tmp_wp_mode >= WP_NUM) || ( (hook->flags & F_CDROM) && (hcopy->flags & (VF_TMP_MODE | VF_STORAGE_FILE)) ) ) { resl = ST_INV_VOLUME; break; } if (hcopy->version > DC_HDR_VERSION) { resl = ST_VOLUME_TOO_NEW; break; } #if 0 /* update volume header if needed */ if ( (hcopy->version < DC_HDR_VERSION) && !(hook->flags & F_CDROM) ) { hcopy->version = DC_HDR_VERSION; memset(hcopy->deprecated, 0, sizeof(hcopy->deprecated)); io_write_header(hook, hcopy, hdr_key, NULL); } #endif DbgMsg("hdr_key=%p, dsk_key=%p\n", hdr_key, hook->dsk_key); // initialize volume key if ( (hook->dsk_key = (xts_key*)mm_secure_alloc(sizeof(xts_key))) == NULL ) { resl = ST_NOMEM; break; } xts_set_key(hcopy->key_1, hcopy->alg_1, hook->dsk_key); DbgMsg("device mounted\n"); if (hcopy->flags & VF_STORAGE_FILE) { hook->use_size = hook->dsk_size; hook->stor_off = hcopy->stor_off; } else { hook->use_size = hook->dsk_size - hook->head_len; hook->stor_off = hook->use_size; } hook->crypt.cipher_id = d8(hcopy->alg_1); hook->disk_id = hcopy->disk_id; hook->vf_version = hcopy->version; hook->tmp_size = 0; hook->mnt_flags = mnt_flags; DbgMsg("hook->vf_version %d\n", hook->vf_version); DbgMsg("hook->bps %d\n", hook->bps); DbgMsg("hook->head_len %d\n", hook->head_len); DbgMsg("flags %x\n", hcopy->flags); if (hcopy->flags & VF_STORAGE_FILE) { hook->flags |= F_PROTECT_DCSYS; } if (hcopy->flags & VF_NO_REDIR) { hook->flags |= F_NO_REDIRECT; hook->stor_off = 0; } if (hcopy->flags & VF_TMP_MODE) { hook->tmp_size = hcopy->tmp_size; hook->hdr_key = hdr_key; hook->crypt.wp_mode = hcopy->tmp_wp_mode; if (hcopy->flags & VF_REENCRYPT) { hook->sync_init_type = S_CONTINUE_RE_ENC; } else { hook->sync_init_type = S_CONTINUE_ENC; } /* copy decrypted header to device data */ memcpy(&hook->tmp_header, hcopy, sizeof(dc_header)); if ( (resl = dc_enable_sync_mode(hook)) != ST_OK ) { burn(&hook->tmp_header, sizeof(dc_header)); hdr_key = hook->hdr_key; } else { hdr_key = NULL; /* prevent key wiping */ } } else { hook->flags |= F_ENABLED; resl = ST_OK; } if (resl == ST_OK) { /* increment mount changes counter */ lock_inc(&hook->chg_mount); } } while (0); if (hdr_key != NULL) mm_secure_free(hdr_key); if (hcopy != NULL) mm_secure_free(hcopy); if (hook != NULL) { if ((hook->flags & F_ENABLED) == 0 && hook->dsk_key != NULL) { mm_secure_free(hook->dsk_key); hook->dsk_key = NULL; } KeReleaseMutex(&hook->busy_lock, FALSE); dc_deref_hook(hook); } return resl; }
/* this routine process unmounting the device unmount options: UM_NOFSCTL - unmount without reporting to FS UM_FORCE - force unmounting */ int dc_process_unmount(dev_hook *hook, int opt) { IO_STATUS_BLOCK iosb; NTSTATUS status; HANDLE h_dev = NULL; int locked = 0; int resl; DbgMsg("dc_process_unmount, dev=%ws\n", hook->dev_name); if ((hook->flags & F_ENABLED) == 0) { return ST_NO_MOUNT; } wait_object_infinity(&hook->busy_lock); if ((hook->flags & F_ENABLED) == 0) { resl = ST_NO_MOUNT; goto cleanup; } do { if (hook->flags & F_FORMATTING) { dc_format_done(hook->dev_name); } if ( !(hook->flags & F_SYSTEM) && !(opt & MF_NOFSCTL) ) { h_dev = io_open_device(hook->dev_name); if ( (h_dev == NULL) && !(opt & MF_FORCE) ) { resl = ST_LOCK_ERR; break; } if (h_dev != NULL) { status = ZwFsControlFile(h_dev, NULL, NULL, NULL, &iosb, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); if ( (NT_SUCCESS(status) == FALSE) && !(opt & MF_FORCE) ) { resl = ST_LOCK_ERR; break; } locked = (NT_SUCCESS(status) != FALSE); ZwFsControlFile(h_dev, NULL, NULL, NULL, &iosb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); } } if ((opt & MF_NOSYNC) == 0) { // temporary disable IRP processing hook->flags |= F_DISABLE; // wait for pending IRPs completion if ((opt & MF_NOWAIT_IO) == 0) { while (hook->remove_lock.Common.IoCount > 1) dc_delay(20); } if (hook->flags & F_SYNC) { // send signal to syncronous mode thread dc_send_sync_packet(hook->dev_name, S_OP_FINALIZE, 0); } } hook->flags &= ~F_CLEAR_ON_UNMOUNT; hook->use_size = hook->dsk_size; hook->tmp_size = 0; hook->mnt_flags = 0; resl = ST_OK; // increment mount changes counter lock_inc(&hook->chg_mount); // free encryption key if (hook->dsk_key != NULL) { mm_secure_free(hook->dsk_key); hook->dsk_key = NULL; } if ( !(opt & MF_NOSYNC) ) { /* enable IRP processing */ hook->flags &= ~F_DISABLE; } } while (0); if (h_dev != NULL) { if (locked != 0) { ZwFsControlFile(h_dev, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); } ZwClose(h_dev); } cleanup: KeReleaseMutex(&hook->busy_lock, FALSE); return resl; }
NTSTATUS dc_drv_control_irp(PDEVICE_OBJECT dev_obj, PIRP irp) { PIO_STACK_LOCATION irp_sp = IoGetCurrentIrpStackLocation(irp); NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; void *data = irp->AssociatedIrp.SystemBuffer; u32 in_len = irp_sp->Parameters.DeviceIoControl.InputBufferLength; u32 out_len = irp_sp->Parameters.DeviceIoControl.OutputBufferLength; u32 code = irp_sp->Parameters.DeviceIoControl.IoControlCode; u32 bytes = 0; switch (code) { case DC_GET_VERSION: { if (out_len == sizeof(u32)) { p32(data)[0] = DC_DRIVER_VER; bytes = sizeof(u32); status = STATUS_SUCCESS; } } break; case DC_CTL_CLEAR_PASS: { dc_clean_pass_cache(); status = STATUS_SUCCESS; } break; case DC_CTL_STATUS: { dc_ioctl *dctl = data; dc_status *stat = data; dev_hook *hook; if ( (in_len == sizeof(dc_ioctl)) && (out_len == sizeof(dc_status)) ) { dctl->device[MAX_DEVICE] = 0; if (hook = dc_find_hook(dctl->device)) { if (hook->pdo_dev->Flags & DO_SYSTEM_BOOT_PARTITION) { hook->flags |= F_SYSTEM; } dc_get_mount_point(hook, stat->mnt_point, sizeof(stat->mnt_point)); stat->crypt = hook->crypt; stat->dsk_size = hook->dsk_size; stat->tmp_size = hook->tmp_size; stat->flags = hook->flags; stat->mnt_flags = hook->mnt_flags; stat->disk_id = hook->disk_id; stat->paging_count = hook->paging_count; stat->vf_version = hook->vf_version; status = STATUS_SUCCESS; bytes = sizeof(dc_status); dc_deref_hook(hook); } } } break; case DC_CTL_ADD_SEED: { if (in_len != 0) { cp_rand_add_seed(data, in_len); status = STATUS_SUCCESS; /* prevent leaks */ burn(data, in_len); } } break; case DC_CTL_GET_RAND: { dc_rand_ctl *rctl = data; if (in_len == sizeof(dc_rand_ctl)) { __try { ProbeForWrite(rctl->buff, rctl->size, sizeof(u8)); if (cp_rand_bytes(rctl->buff, rctl->size) != 0) { status = STATUS_SUCCESS; } } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); } } } break; case DC_CTL_BENCHMARK: { if ( (in_len == sizeof(int)) && (out_len == sizeof(dc_bench_info)) ) { if (dc_k_benchmark(p32(data)[0], pv(data)) == ST_OK) { status = STATUS_SUCCESS; bytes = sizeof(dc_bench_info); } } } break; case DC_CTL_BSOD: { lock_inc(&dc_dump_disable); dc_clean_pass_cache(); mm_unlock_user_memory(NULL, NULL); dc_clean_keys(); KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); } break; case DC_CTL_GET_CONF: { dc_conf *conf = data; if (out_len == sizeof(dc_conf)) { conf->conf_flags = dc_conf_flags; conf->load_flags = dc_load_flags; status = STATUS_SUCCESS; bytes = sizeof(dc_conf); } } break; case DC_CTL_SET_CONF: { dc_conf *conf = data; if (in_len == sizeof(dc_conf)) { dc_conf_flags = conf->conf_flags; status = STATUS_SUCCESS; if ( !(dc_conf_flags & CONF_CACHE_PASSWORD) ) { dc_clean_pass_cache(); } dc_init_encryption(); } } break; case DC_CTL_LOCK_MEM: { PEPROCESS process = IoGetRequestorProcess(irp); dc_lock_ctl *smem = data; if ( (process != NULL) && (in_len == sizeof(dc_lock_ctl)) && (out_len == in_len) ) { smem->resl = mm_lock_user_memory(smem->data, smem->size, process); status = STATUS_SUCCESS; bytes = sizeof(dc_lock_ctl); } } break; case DC_CTL_UNLOCK_MEM: { PEPROCESS process = IoGetRequestorProcess(irp); dc_lock_ctl *smem = data; if ( (process != NULL) && (in_len == sizeof(dc_lock_ctl)) && (out_len == in_len) ) { mm_unlock_user_memory(smem->data, process); status = STATUS_SUCCESS; bytes = sizeof(dc_lock_ctl); smem->resl = ST_OK; } } break; case DC_BACKUP_HEADER: { dc_backup_ctl *back = data; if ( (in_len == sizeof(dc_backup_ctl)) && (out_len == in_len) ) { back->device[MAX_DEVICE] = 0; back->status = dc_backup_header(back->device, &back->pass, back->backup); /* prevent leaks */ burn(&back->pass, sizeof(back->pass)); status = STATUS_SUCCESS; bytes = sizeof(dc_backup_ctl); } } break; case DC_RESTORE_HEADER: { dc_backup_ctl *back = data; if ( (in_len == sizeof(dc_backup_ctl)) && (out_len == in_len) ) { back->device[MAX_DEVICE] = 0; back->status = dc_restore_header(back->device, &back->pass, back->backup); /* prevent leaks */ burn(&back->pass, sizeof(back->pass)); status = STATUS_SUCCESS; bytes = sizeof(dc_backup_ctl); } } break; default: { dc_ioctl *dctl = data; if ( (in_len == sizeof(dc_ioctl)) && (out_len == sizeof(dc_ioctl)) ) { /* limit null-terminated string length */ dctl->device[MAX_DEVICE] = 0; /* process IOCTL */ dctl->status = dc_ioctl_process(code, dctl); /* prevent leaks */ burn(&dctl->passw1, sizeof(dctl->passw1)); burn(&dctl->passw2, sizeof(dctl->passw2)); status = STATUS_SUCCESS; bytes = sizeof(dc_ioctl); } } break; }