Signed-off-by: Hans Leidekker hans@codeweavers.com --- dlls/mountmgr.sys/mountmgr.c | 99 ++++++++++++++++++++++++++++++++++++ include/ddk/mountmgr.h | 1 + 2 files changed, 100 insertions(+)
diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c index d55ca643018..c3b9135ce10 100644 --- a/dlls/mountmgr.sys/mountmgr.c +++ b/dlls/mountmgr.sys/mountmgr.c @@ -731,6 +731,94 @@ static NTSTATUS read_credential( void *buff, SIZE_T insize, SIZE_T outsize, IO_S iosb->Information = size; return (size > outsize) ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; } + +static NTSTATUS write_credential( void *buff, SIZE_T insize, SIZE_T outsize, IO_STATUS_BLOCK *iosb ) +{ + const struct mountmgr_credential *cred = buff; + int status, len, len_password = 0; + const WCHAR *ptr; + SecKeychainItemRef keychain_item; + char *targetname, *username = NULL, *password = NULL; + SecKeychainAttribute attrs[1]; + SecKeychainAttributeList attr_list; + NTSTATUS ret = STATUS_NO_MEMORY; + + if (!check_credential_string( buff, insize, cred->targetname_size, cred->targetname_offset ) || + !check_credential_string( buff, insize, cred->username_size, cred->username_offset ) || + ((cred->blob_size && cred->blob_size % sizeof(WCHAR)) || cred->blob_offset + cred->blob_size > insize) || + (cred->comment_size && !check_credential_string( buff, insize, cred->comment_size, cred->comment_offset )) || + sizeof(*cred) + cred->targetname_size + cred->username_size + cred->blob_size + cred->comment_size > insize) + { + return STATUS_INVALID_PARAMETER; + } + + ptr = (const WCHAR *)((const char *)cred + cred->targetname_offset); + len = WideCharToMultiByte( CP_UTF8, 0, ptr, -1, NULL, 0, NULL, NULL ); + if (!(targetname = RtlAllocateHeap( GetProcessHeap(), 0, len ))) goto error; + WideCharToMultiByte( CP_UTF8, 0, ptr, -1, targetname, len, NULL, NULL ); + + ptr = (const WCHAR *)((const char *)cred + cred->username_offset); + len = WideCharToMultiByte( CP_UTF8, 0, ptr, -1, NULL, 0, NULL, NULL ); + if (!(username = RtlAllocateHeap( GetProcessHeap(), 0, len ))) goto error; + WideCharToMultiByte( CP_UTF8, 0, ptr, -1, username, len, NULL, NULL ); + + if (cred->blob_size) + { + ptr = (const WCHAR *)((const char *)cred + cred->blob_offset); + len_password = WideCharToMultiByte( CP_UTF8, 0, ptr, cred->blob_size / sizeof(WCHAR), NULL, 0, NULL, NULL ); + if (!(password = RtlAllocateHeap( GetProcessHeap(), 0, len_password ))) goto error; + WideCharToMultiByte( CP_UTF8, 0, ptr, cred->blob_size / sizeof(WCHAR), password, len_password, NULL, NULL ); + } + + TRACE("adding target %s, username %s using Keychain\n", targetname, username ); + status = SecKeychainAddGenericPassword( NULL, strlen(targetname), targetname, strlen(username), username, + len_password, password, &keychain_item ); + if (status != noErr) ERR( "SecKeychainAddGenericPassword returned %d\n", status ); + if (status == errSecDuplicateItem) + { + status = SecKeychainFindGenericPassword( NULL, strlen(targetname), targetname, strlen(username), username, NULL, + NULL, &keychain_item ); + if (status != noErr) ERR( "SecKeychainFindGenericPassword returned %d\n", status ); + } + RtlFreeHeap( GetProcessHeap(), 0, username ); + RtlFreeHeap( GetProcessHeap(), 0, targetname ); + if (status != noErr) + { + RtlFreeHeap( GetProcessHeap(), 0, password ); + return STATUS_UNSUCCESSFUL; + } + if (cred->comment_size) + { + attr_list.count = 1; + attr_list.attr = attrs; + attrs[0].tag = kSecCommentItemAttr; + ptr = (const WCHAR *)((const char *)cred + cred->comment_offset); + attrs[0].length = WideCharToMultiByte( CP_UTF8, 0, ptr, -1, NULL, 0, NULL, NULL ); + if (attrs[0].length) attrs[0].length--; + if (!(attrs[0].data = RtlAllocateHeap( GetProcessHeap(), 0, attrs[0].length ))) goto error; + WideCharToMultiByte( CP_UTF8, 0, ptr, -1, attrs[0].data, attrs[0].length, NULL, NULL ); + } + else + { + attr_list.count = 0; + attr_list.attr = NULL; + } + status = SecKeychainItemModifyAttributesAndData( keychain_item, &attr_list, cred->blob_preserve ? 0 : len_password, + cred->blob_preserve ? NULL : password ); + + if (cred->comment_size) RtlFreeHeap( GetProcessHeap(), 0, attrs[0].data ); + RtlFreeHeap( GetProcessHeap(), 0, password ); + /* FIXME: set TargetAlias attribute */ + CFRelease( keychain_item ); + if (status != noErr) return STATUS_UNSUCCESSFUL; + return STATUS_SUCCESS; + +error: + RtlFreeHeap( GetProcessHeap(), 0, username ); + RtlFreeHeap( GetProcessHeap(), 0, targetname ); + RtlFreeHeap( GetProcessHeap(), 0, password ); + return ret; +} #endif /* __APPLE__ */
/* handler for ioctls on the mount manager device */ @@ -810,6 +898,17 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp ) irpsp->Parameters.DeviceIoControl.OutputBufferLength, &irp->IoStatus ); break; + case IOCTL_MOUNTMGR_WRITE_CREDENTIAL: + if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_credential)) + { + irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER; + break; + } + irp->IoStatus.u.Status = write_credential( irp->AssociatedIrp.SystemBuffer, + irpsp->Parameters.DeviceIoControl.InputBufferLength, + irpsp->Parameters.DeviceIoControl.OutputBufferLength, + &irp->IoStatus ); + break; #endif default: FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode ); diff --git a/include/ddk/mountmgr.h b/include/ddk/mountmgr.h index c3d94078197..162bbf71076 100644 --- a/include/ddk/mountmgr.h +++ b/include/ddk/mountmgr.h @@ -75,6 +75,7 @@ struct mountmgr_unix_drive };
#define IOCTL_MOUNTMGR_READ_CREDENTIAL CTL_CODE(MOUNTMGRCONTROLTYPE, 48, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_WRITE_CREDENTIAL CTL_CODE(MOUNTMGRCONTROLTYPE, 49, METHOD_BUFFERED, FILE_WRITE_ACCESS)
struct mountmgr_credential {