pwcache.c 9.39 KB
Newer Older
1 2
/*
 * MPR Password Cache functions
3 4
 *
 * Copyright 1999 Ulrich Weigand
5
 * Copyright 2003,2004 Mike McCormack for CodeWeavers
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22
#include <stdarg.h>
23 24
#include <stdio.h>

25
#include "windef.h"
26 27
#include "winbase.h"
#include "winnetwk.h"
28
#include "winreg.h"
29
#include "wine/debug.h"
30

31
WINE_DEFAULT_DEBUG_CHANNEL(mpr);
32

33 34
static const char mpr_key[] = "Software\\Wine\\Wine\\Mpr\\";

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
static inline BYTE hex( BYTE x )
{
    if( x <= 9 )
        return x + '0';
    return x + 'A' - 10;
}

static inline CHAR ctox( CHAR x )
{
    if( ( x >= '0' ) && ( x <= '9' ) )
        return x - '0';
    if( ( x >= 'A' ) && ( x <= 'F' ) )
        return x - 'A' + 10;
    if( ( x >= 'a' ) && ( x <= 'a' ) )
        return x - 'a' + 10;
    return -1;
}

53
static LPSTR MPR_GetValueName( LPCSTR pbResource, WORD cbResource, BYTE nType )
54 55
{
    LPSTR name;
56
    DWORD  i;
57

58
    name = HeapAlloc( GetProcessHeap(), 0, 6+cbResource*2 );
59 60 61
    if( !name ) return NULL;

    sprintf( name, "X-%02X-", nType );
62 63 64 65 66 67
    for(i=0; i<cbResource; i++)
    {
        name[5+i*2]=hex((pbResource[i]&0xf0)>>4);
        name[6+i*2]=hex(pbResource[i]&0x0f);
    }
    name[5+i*2]=0;
68 69 70 71
    TRACE( "Value is %s\n", name );
    return name;
}

72

73
/**************************************************************************
74
 * WNetCachePassword [MPR.@]  Saves password in cache
75
 *
76
 * NOTES
77
 *	only the parameter count is verifyed
78 79
 *
 *	---- everything below this line might be wrong (js) -----
80 81 82 83 84 85 86 87 88 89
 * RETURNS
 *    Success: WN_SUCCESS
 *    Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BADVALUE, WN_NET_ERROR,
 *             WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
 */
DWORD WINAPI WNetCachePassword(
    LPSTR pbResource, /* [in] Name of workgroup, computer, or resource */
    WORD cbResource,  /* [in] Size of name */
    LPSTR pbPassword, /* [in] Buffer containing password */
    WORD cbPassword,  /* [in] Size of password */
90 91
    BYTE nType,       /* [in] Type of password to cache */
    WORD x)
92

93
{
94 95 96 97 98
    HKEY hkey;
    DWORD r;
    LPSTR valname;

    WARN( "(%p(%s), %d, %p(%s), %d, %d, 0x%08x): totally insecure\n",
99 100 101
           pbResource, debugstr_a(pbResource), cbResource,
	   pbPassword, debugstr_a(pbPassword), cbPassword,
	   nType, x );
102

103
    /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
104 105 106 107 108 109 110 111
    r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
    if( r )
        return WN_ACCESS_DENIED;

    valname = MPR_GetValueName( pbResource, cbResource, nType );
    if( valname )
    {
        r = RegSetValueExA( hkey, valname, 0, REG_BINARY, 
112
                            (LPBYTE)pbPassword, cbPassword );
113
        if( r )
114
            r = WN_CANCEL;
115 116 117 118 119 120 121 122 123 124
        else
            r = WN_SUCCESS;
        HeapFree( GetProcessHeap(), 0, valname );
    }
    else
        r = WN_OUT_OF_MEMORY;

    RegCloseKey( hkey );

    return r;
125 126 127
}

/*****************************************************************
128
 *  WNetRemoveCachedPassword [MPR.@]
129
 */
130 131 132 133
UINT WINAPI WNetRemoveCachedPassword(
      LPSTR pbResource,   /* [in] resource ID to delete */
      WORD cbResource,    /* [in] number of bytes in the resource ID */
      BYTE nType )        /* [in] Type of the resource to delete */
134
{
135 136 137 138 139
    HKEY hkey;
    DWORD r;
    LPSTR valname;

    WARN( "(%p(%s), %d, %d): totally insecure\n",
140
           pbResource, debugstr_a(pbResource), cbResource, nType );
141

142
    /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
    r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
    if( r )
        return WN_ACCESS_DENIED;

    valname = MPR_GetValueName( pbResource, cbResource, nType );
    if( valname )
    {
        r = RegDeleteValueA( hkey, valname );
        if( r )
            r = WN_ACCESS_DENIED;
        else
            r = WN_SUCCESS;
        HeapFree( GetProcessHeap(), 0, valname );
    }
    else
        r = WN_OUT_OF_MEMORY;

    return r;
161 162 163
}

/*****************************************************************
164
 * WNetGetCachedPassword [MPR.@]  Retrieves password from cache
165
 *
166 167 168 169 170 171 172
 * NOTES
 *  the stub seems to be wrong:
 *	arg1:	ptr	0x40xxxxxx -> (no string)
 *	arg2:	len	36
 *	arg3:	ptr	0x40xxxxxx -> (no string)
 *	arg4:	ptr	0x40xxxxxx -> 0xc8
 *	arg5:	type?	4
173
 *
174
 *	---- everything below this line might be wrong (js) -----
175 176
 * RETURNS
 *    Success: WN_SUCCESS
177
 *    Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE,
178 179 180 181 182 183 184 185 186
 *             WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
 */
DWORD WINAPI WNetGetCachedPassword(
    LPSTR pbResource,   /* [in]  Name of workgroup, computer, or resource */
    WORD cbResource,    /* [in]  Size of name */
    LPSTR pbPassword,   /* [out] Buffer to receive password */
    LPWORD pcbPassword, /* [out] Receives size of password */
    BYTE nType)         /* [in]  Type of password to retrieve */
{
187 188 189 190
    HKEY hkey;
    DWORD r, type = 0, sz;
    LPSTR valname;

191
    WARN( "(%p(%s), %d, %p, %p, %d): totally insecure\n",
192 193
           pbResource, debugstr_a(pbResource), cbResource,
	   pbPassword, pcbPassword, nType );
194

195 196
    memset( pbPassword, 0, *pcbPassword);

197
    /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
198 199 200 201 202 203 204 205
    r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
    if( r )
        return WN_ACCESS_DENIED;

    valname = MPR_GetValueName( pbResource, cbResource, nType );
    if( valname )
    {
        sz = *pcbPassword;
206
        r = RegQueryValueExA( hkey, valname, 0, &type, (LPBYTE)pbPassword, &sz );
207 208
        *pcbPassword = sz;
        if( r )
209
            r = WN_CANCEL;
210 211 212 213 214 215 216 217
        else
            r = WN_SUCCESS;
        HeapFree( GetProcessHeap(), 0, valname );
    }
    else
        r = WN_OUT_OF_MEMORY;

    return r;
218 219 220
}

/*******************************************************************
221
 * WNetEnumCachedPasswords [MPR.@]
222 223
 *
 * NOTES
224
 *	the parameter count is verifyed
225 226 227 228
 * 
 *  This function is a huge security risk, as virii and such can use
 * it to grab all the passwords in the cache.  It's bad enough to 
 * store the passwords (insecurely).
229
 *
230 231 232
 *  bpPrefix and cbPrefix are used to filter the returned passwords
 *   the first cbPrefix bytes of the password resource identifier
 *   should match the same number of bytes in bpPrefix
233
 *
234 235 236 237
 * RETURNS
 *   Success: WN_SUCCESS   (even if no entries were enumerated)
 *   Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE,
 *             WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
238
 */
239

240 241 242 243 244 245
UINT WINAPI WNetEnumCachedPasswords(
      LPSTR pbPrefix,  /* [in] prefix to filter cache entries */
      WORD cbPrefix,   /* [in] number of bytes in Prefix substring */
      BYTE nType,      /* [in] match the Type ID of the entry */
      ENUMPASSWORDPROC enumPasswordProc,  /* [in] callback function */
      DWORD param)     /* [in] parameter passed to enum function */
246
{
247 248 249 250 251
    HKEY hkey;
    DWORD r, type, val_sz, data_sz, i, j, size;
    PASSWORD_CACHE_ENTRY *entry;
    CHAR val[256], prefix[6];

252
    WARN( "(%s, %d, %d, %p, 0x%08x) totally insecure\n",
253 254 255
           debugstr_an(pbPrefix,cbPrefix), cbPrefix,
	   nType, enumPasswordProc, param );

256
    /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
    if( r )
        return WN_ACCESS_DENIED;

    sprintf(prefix, "X-%02X-", nType );

    i = 0;
    for( i=0;  ; i++ )
    {
        val_sz  = sizeof val;
        data_sz = 0;
        type    = 0;
        val[0] = 0;
        r = RegEnumValueA( hkey, i, val, &val_sz, NULL, &type, NULL, &data_sz );
        if( r != ERROR_SUCCESS )
            break;
        if( type != REG_BINARY )
            continue;

        /* check the value is in the format we expect */
        if( val_sz < sizeof prefix )
            continue;
        if( memcmp( prefix, val, 5 ) )
            continue;

        /* decode the value */
        for(j=5; j<val_sz; j+=2 )
        {
            CHAR hi = ctox( val[j] ), lo = ctox( val[j+1] );
            if( ( hi < 0 ) || ( lo < 0 ) )
                break;
            val[(j-5)/2] = (hi<<4) | lo;
        }

        /* find the decoded length */
        val_sz = (j - 5)/2;
        val[val_sz]=0;
        if( val_sz < cbPrefix )
            continue;

        /* check the prefix matches */
        if( memcmp(val, pbPrefix, cbPrefix) )
            continue;

        /* read the value data */
        size = sizeof *entry - sizeof entry->abResource[0] + val_sz + data_sz;
        entry = HeapAlloc( GetProcessHeap(), 0, sizeof *entry + val_sz + data_sz );
        memcpy( entry->abResource, val, val_sz );
        entry->cbEntry = size;
        entry->cbResource = val_sz;
        entry->cbPassword = data_sz;
        entry->iEntry = i;
        entry->nType = nType;
        r = RegEnumValueA( hkey, i, NULL, &val_sz, NULL, &type, 
                           &entry->abResource[val_sz], &data_sz );
        if( r == ERROR_SUCCESS )
            enumPasswordProc( entry, param );
        HeapFree( GetProcessHeap(), 0, entry );
    }

    RegCloseKey( hkey );
318

319
    return WN_SUCCESS;
320
}