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
static inline BYTE hex( BYTE x )
{
    if( x <= 9 )
        return x + '0';
    return x + 'A' - 10;
}

42
static inline signed char ctox( CHAR x )
43 44 45 46 47 48 49 50 51 52
{
    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
Austin English's avatar
Austin English committed
77
 *	Only the parameter count is verified
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
Austin English's avatar
Austin English committed
224
 *	The parameter count is verified
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
    r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
    if( r )
        return WN_ACCESS_DENIED;

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

    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 )
        {
284
            signed char hi = ctox( val[j] ), lo = ctox( val[j+1] );
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
            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 */
301 302
        size = offsetof( PASSWORD_CACHE_ENTRY, abResource[val_sz + data_sz] );
        entry = HeapAlloc( GetProcessHeap(), 0, size );
303 304 305 306 307 308
        memcpy( entry->abResource, val, val_sz );
        entry->cbEntry = size;
        entry->cbResource = val_sz;
        entry->cbPassword = data_sz;
        entry->iEntry = i;
        entry->nType = nType;
309 310
        size = sizeof val;
        r = RegEnumValueA( hkey, i, val, &size, NULL, &type,
311 312 313 314 315 316 317
                           &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
}