mpr: Check for out of memory condition.
[wine] / dlls / mpr / pwcache.c
1 /*
2  * MPR Password Cache functions
3  *
4  * Copyright 1999 Ulrich Weigand
5  * Copyright 2003,2004 Mike McCormack for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * 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 #include <stdio.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnetwk.h"
28 #include "winreg.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(mpr);
32
33 static const char mpr_key[] = "Software\\Wine\\Wine\\Mpr\\";
34
35 static inline BYTE hex( BYTE x )
36 {
37     if( x <= 9 )
38         return x + '0';
39     return x + 'A' - 10;
40 }
41
42 static inline CHAR ctox( CHAR x )
43 {
44     if( ( x >= '0' ) && ( x <= '9' ) )
45         return x - '0';
46     if( ( x >= 'A' ) && ( x <= 'F' ) )
47         return x - 'A' + 10;
48     if( ( x >= 'a' ) && ( x <= 'a' ) )
49         return x - 'a' + 10;
50     return -1;
51 }
52
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     if( !name ) return NULL;
60
61     sprintf( name, "X-%02X-", nType );
62     for(i=0; i<cbResource; i++)
63     {
64         name[5+i*2]=hex((pbResource[i]&0xf0)>>4);
65         name[6+i*2]=hex(pbResource[i]&0x0f);
66     }
67     name[5+i*2]=0;
68     TRACE( "Value is %s\n", name );
69     return name;
70 }
71
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  * RETURNS
81  *    Success: WN_SUCCESS
82  *    Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BADVALUE, WN_NET_ERROR,
83  *             WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
84  */
85 DWORD WINAPI WNetCachePassword(
86     LPSTR pbResource, /* [in] Name of workgroup, computer, or resource */
87     WORD cbResource,  /* [in] Size of name */
88     LPSTR pbPassword, /* [in] Buffer containing password */
89     WORD cbPassword,  /* [in] Size of password */
90     BYTE nType,       /* [in] Type of password to cache */
91     WORD x)
92
93 {
94     HKEY hkey;
95     DWORD r;
96     LPSTR valname;
97
98     WARN( "(%p(%s), %d, %p(%s), %d, %d, 0x%08x): totally insecure\n",
99            pbResource, debugstr_a(pbResource), cbResource,
100            pbPassword, debugstr_a(pbPassword), cbPassword,
101            nType, x );
102
103     /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
104     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
105     if( r )
106         return WN_ACCESS_DENIED;
107
108     valname = MPR_GetValueName( pbResource, cbResource, nType );
109     if( valname )
110     {
111         r = RegSetValueExA( hkey, valname, 0, REG_BINARY, 
112                             (LPBYTE)pbPassword, cbPassword );
113         if( r )
114             r = WN_CANCEL;
115         else
116             r = WN_SUCCESS;
117         HeapFree( GetProcessHeap(), 0, valname );
118     }
119     else
120         r = WN_OUT_OF_MEMORY;
121
122     RegCloseKey( hkey );
123
124     return r;
125 }
126
127 /*****************************************************************
128  *  WNetRemoveCachedPassword [MPR.@]
129  */
130 UINT WINAPI WNetRemoveCachedPassword(
131       LPSTR pbResource,   /* [in] resource ID to delete */
132       WORD cbResource,    /* [in] number of bytes in the resource ID */
133       BYTE nType )        /* [in] Type of the resource to delete */
134 {
135     HKEY hkey;
136     DWORD r;
137     LPSTR valname;
138
139     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     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
144     if( r )
145         return WN_ACCESS_DENIED;
146
147     valname = MPR_GetValueName( pbResource, cbResource, nType );
148     if( valname )
149     {
150         r = RegDeleteValueA( hkey, valname );
151         if( r )
152             r = WN_ACCESS_DENIED;
153         else
154             r = WN_SUCCESS;
155         HeapFree( GetProcessHeap(), 0, valname );
156     }
157     else
158         r = WN_OUT_OF_MEMORY;
159
160     return r;
161 }
162
163 /*****************************************************************
164  * WNetGetCachedPassword [MPR.@]  Retrieves password from cache
165  *
166  * NOTES
167  *  the stub seems to be wrong:
168  *      arg1:   ptr     0x40xxxxxx -> (no string)
169  *      arg2:   len     36
170  *      arg3:   ptr     0x40xxxxxx -> (no string)
171  *      arg4:   ptr     0x40xxxxxx -> 0xc8
172  *      arg5:   type?   4
173  *
174  *      ---- everything below this line might be wrong (js) -----
175  * RETURNS
176  *    Success: WN_SUCCESS
177  *    Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE,
178  *             WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
179  */
180 DWORD WINAPI WNetGetCachedPassword(
181     LPSTR pbResource,   /* [in]  Name of workgroup, computer, or resource */
182     WORD cbResource,    /* [in]  Size of name */
183     LPSTR pbPassword,   /* [out] Buffer to receive password */
184     LPWORD pcbPassword, /* [out] Receives size of password */
185     BYTE nType)         /* [in]  Type of password to retrieve */
186 {
187     HKEY hkey;
188     DWORD r, type = 0, sz;
189     LPSTR valname;
190
191     WARN( "(%p(%s), %d, %p, %p, %d): totally insecure\n",
192            pbResource, debugstr_a(pbResource), cbResource,
193            pbPassword, pcbPassword, nType );
194
195     memset( pbPassword, 0, *pcbPassword);
196
197     /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
198     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
199     if( r )
200         return WN_ACCESS_DENIED;
201
202     valname = MPR_GetValueName( pbResource, cbResource, nType );
203     if( valname )
204     {
205         sz = *pcbPassword;
206         r = RegQueryValueExA( hkey, valname, 0, &type, (LPBYTE)pbPassword, &sz );
207         *pcbPassword = sz;
208         if( r )
209             r = WN_CANCEL;
210         else
211             r = WN_SUCCESS;
212         HeapFree( GetProcessHeap(), 0, valname );
213     }
214     else
215         r = WN_OUT_OF_MEMORY;
216
217     return r;
218 }
219
220 /*******************************************************************
221  * WNetEnumCachedPasswords [MPR.@]
222  *
223  * NOTES
224  *      the parameter count is verifyed
225  * 
226  *  This function is a huge security risk, as virii and such can use
227  * it to grab all the passwords in the cache.  It's bad enough to 
228  * store the passwords (insecurely).
229  *
230  *  bpPrefix and cbPrefix are used to filter the returned passwords
231  *   the first cbPrefix bytes of the password resource identifier
232  *   should match the same number of bytes in bpPrefix
233  *
234  * RETURNS
235  *   Success: WN_SUCCESS   (even if no entries were enumerated)
236  *   Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE,
237  *             WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
238  */
239
240 UINT WINAPI WNetEnumCachedPasswords(
241       LPSTR pbPrefix,  /* [in] prefix to filter cache entries */
242       WORD cbPrefix,   /* [in] number of bytes in Prefix substring */
243       BYTE nType,      /* [in] match the Type ID of the entry */
244       ENUMPASSWORDPROC enumPasswordProc,  /* [in] callback function */
245       DWORD param)     /* [in] parameter passed to enum function */
246 {
247     HKEY hkey;
248     DWORD r, type, val_sz, data_sz, i, j, size;
249     PASSWORD_CACHE_ENTRY *entry;
250     CHAR val[256], prefix[6];
251
252     WARN( "(%s, %d, %d, %p, 0x%08x) totally insecure\n",
253            debugstr_an(pbPrefix,cbPrefix), cbPrefix,
254            nType, enumPasswordProc, param );
255
256     /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
257     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
258     if( r )
259         return WN_ACCESS_DENIED;
260
261     sprintf(prefix, "X-%02X-", nType );
262
263     i = 0;
264     for( i=0;  ; i++ )
265     {
266         val_sz  = sizeof val;
267         data_sz = 0;
268         type    = 0;
269         val[0] = 0;
270         r = RegEnumValueA( hkey, i, val, &val_sz, NULL, &type, NULL, &data_sz );
271         if( r != ERROR_SUCCESS )
272             break;
273         if( type != REG_BINARY )
274             continue;
275
276         /* check the value is in the format we expect */
277         if( val_sz < sizeof prefix )
278             continue;
279         if( memcmp( prefix, val, 5 ) )
280             continue;
281
282         /* decode the value */
283         for(j=5; j<val_sz; j+=2 )
284         {
285             CHAR hi = ctox( val[j] ), lo = ctox( val[j+1] );
286             if( ( hi < 0 ) || ( lo < 0 ) )
287                 break;
288             val[(j-5)/2] = (hi<<4) | lo;
289         }
290
291         /* find the decoded length */
292         val_sz = (j - 5)/2;
293         val[val_sz]=0;
294         if( val_sz < cbPrefix )
295             continue;
296
297         /* check the prefix matches */
298         if( memcmp(val, pbPrefix, cbPrefix) )
299             continue;
300
301         /* read the value data */
302         size = sizeof *entry - sizeof entry->abResource[0] + val_sz + data_sz;
303         entry = HeapAlloc( GetProcessHeap(), 0, sizeof *entry + val_sz + data_sz );
304         memcpy( entry->abResource, val, val_sz );
305         entry->cbEntry = size;
306         entry->cbResource = val_sz;
307         entry->cbPassword = data_sz;
308         entry->iEntry = i;
309         entry->nType = nType;
310         r = RegEnumValueA( hkey, i, NULL, &val_sz, NULL, &type, 
311                            &entry->abResource[val_sz], &data_sz );
312         if( r == ERROR_SUCCESS )
313             enumPasswordProc( entry, param );
314         HeapFree( GetProcessHeap(), 0, entry );
315     }
316
317     RegCloseKey( hkey );
318
319     return WN_SUCCESS;
320 }