/*
 * Copyright 2016 Hans Leidekker for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
#include "rpc.h"
#include "sspi.h"
#include "wincred.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(sspicli);

/***********************************************************************
 *		SspiEncodeStringsAsAuthIdentity (SECUR32.0)
 */
SECURITY_STATUS SEC_ENTRY SspiEncodeStringsAsAuthIdentity(
    const WCHAR *username, const WCHAR *domainname, const WCHAR *creds,
    PSEC_WINNT_AUTH_IDENTITY_OPAQUE *opaque_id )
{
    SEC_WINNT_AUTH_IDENTITY_W *id;
    DWORD len_username = 0, len_domainname = 0, len_password = 0, size;
    WCHAR *ptr;

    FIXME( "%s %s %s %p\n", debugstr_w(username), debugstr_w(domainname),
           debugstr_w(creds), opaque_id );

    if (!username && !domainname && !creds) return SEC_E_INVALID_TOKEN;

    if (username) len_username = lstrlenW( username );
    if (domainname) len_domainname = lstrlenW( domainname );
    if (creds) len_password = lstrlenW( creds );

    size = sizeof(*id);
    if (username) size += (len_username + 1) * sizeof(WCHAR);
    if (domainname) size += (len_domainname + 1) * sizeof(WCHAR);
    if (creds) size += (len_password + 1) * sizeof(WCHAR);
    if (!(id = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) return ERROR_OUTOFMEMORY;
    ptr = (WCHAR *)(id + 1);

    if (username)
    {
        memcpy( ptr, username, (len_username + 1) * sizeof(WCHAR) );
        id->User       = ptr;
        id->UserLength = len_username;
        ptr += len_username + 1;
    }
    if (domainname)
    {
        memcpy( ptr, domainname, (len_domainname + 1) * sizeof(WCHAR) );
        id->Domain       = ptr;
        id->DomainLength = len_domainname;
        ptr += len_domainname + 1;
    }
    if (creds)
    {
        memcpy( ptr, creds, (len_password + 1) * sizeof(WCHAR) );
        id->Password       = ptr;
        id->PasswordLength = len_password;
    }

    *opaque_id = id;
    return SEC_E_OK;
}

/***********************************************************************
 *		SspiZeroAuthIdentity (SECUR32.0)
 */
void SEC_ENTRY SspiZeroAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE opaque_id )
{
    SEC_WINNT_AUTH_IDENTITY_W *id = (SEC_WINNT_AUTH_IDENTITY_W *)opaque_id;

    TRACE( "%p\n", opaque_id );

    if (!id) return;
    if (id->User) memset( id->User, 0, id->UserLength * sizeof(WCHAR) );
    if (id->Domain) memset( id->Domain, 0, id->DomainLength * sizeof(WCHAR) );
    if (id->Password) memset( id->Password, 0, id->PasswordLength * sizeof(WCHAR) );
    memset( id, 0, sizeof(*id) );
}

static inline WCHAR *strdupW( const WCHAR *src )
{
    WCHAR *dst;
    if (!src) return NULL;
    if ((dst = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( src ) + 1) * sizeof(WCHAR) )))
        lstrcpyW( dst, src );
    return dst;
}

/***********************************************************************
 *		SspiEncodeAuthIdentityAsStrings (SECUR32.0)
 */
SECURITY_STATUS SEC_ENTRY SspiEncodeAuthIdentityAsStrings(
    PSEC_WINNT_AUTH_IDENTITY_OPAQUE opaque_id, PCWSTR *username,
    PCWSTR *domainname, PCWSTR *creds )
{
    SEC_WINNT_AUTH_IDENTITY_W *id = (SEC_WINNT_AUTH_IDENTITY_W *)opaque_id;

    FIXME("%p %p %p %p\n", opaque_id, username, domainname, creds);

    *username = strdupW( id->User );
    *domainname = strdupW( id->Domain );
    *creds = strdupW( id->Password );

    return SEC_E_OK;
}

/***********************************************************************
 *		SspiFreeAuthIdentity (SECUR32.0)
 */
void SEC_ENTRY SspiFreeAuthIdentity( PSEC_WINNT_AUTH_IDENTITY_OPAQUE opaque_id )
{
    TRACE( "%p\n", opaque_id );
    HeapFree( GetProcessHeap(), 0, opaque_id );
}

/***********************************************************************
 *		SspiLocalFree (SECUR32.0)
 */
void SEC_ENTRY SspiLocalFree( void *ptr )
{
    TRACE( "%p\n", ptr );
    HeapFree( GetProcessHeap(), 0, ptr );
}

/***********************************************************************
 *		SspiPrepareForCredWrite (SECUR32.0)
 */
SECURITY_STATUS SEC_ENTRY SspiPrepareForCredWrite( PSEC_WINNT_AUTH_IDENTITY_OPAQUE opaque_id,
    PCWSTR target, PULONG type, PCWSTR *targetname, PCWSTR *username, PUCHAR *blob, PULONG size )
{
    SEC_WINNT_AUTH_IDENTITY_W *id = (SEC_WINNT_AUTH_IDENTITY_W *)opaque_id;
    WCHAR *str, *str2;
    UCHAR *password;
    ULONG len;

    FIXME( "%p %s %p %p %p %p %p\n", opaque_id, debugstr_w(target), type, targetname, username,
           blob, size );

    if (id->DomainLength)
    {
        len = (id->DomainLength + id->UserLength + 2) * sizeof(WCHAR);
        if (!(str = HeapAlloc(GetProcessHeap(), 0 , len ))) return SEC_E_INSUFFICIENT_MEMORY;
        memcpy( str, id->Domain, id->DomainLength * sizeof(WCHAR) );
        str[id->DomainLength] = '\\';
        memcpy( str + id->DomainLength + 1, id->User, id->UserLength * sizeof(WCHAR) );
        str[id->DomainLength + 1 + id->UserLength] = 0;
    }
    else
    {
        len = (id->UserLength + 1) * sizeof(WCHAR);
        if (!(str = HeapAlloc(GetProcessHeap(), 0 , len ))) return SEC_E_INSUFFICIENT_MEMORY;
        memcpy( str, id->User, id->UserLength * sizeof(WCHAR) );
        str[id->UserLength] = 0;
    }

    str2 = target ? strdupW( target ) : strdupW( str );
    if (!str2)
    {
        HeapFree( GetProcessHeap(), 0, str );
        return SEC_E_INSUFFICIENT_MEMORY;
    }

    len = id->PasswordLength * sizeof(WCHAR);
    if (!(password = HeapAlloc(GetProcessHeap(), 0 , len )))
    {
        HeapFree( GetProcessHeap(), 0, str );
        HeapFree( GetProcessHeap(), 0, str2 );
        return SEC_E_INSUFFICIENT_MEMORY;
    }
    memcpy( password, id->Password, len );

    *type = CRED_TYPE_DOMAIN_PASSWORD;
    *username = str;
    *targetname = str2;
    *blob = password;
    *size = len;

    return SEC_E_OK;
}
