user32: Allow alt+space to highlight system menu.
[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 )
60         sprintf( name, "X-%02X-", nType );
61     for(i=0; i<cbResource; i++)
62     {
63         name[5+i*2]=hex((pbResource[i]&0xf0)>>4);
64         name[6+i*2]=hex(pbResource[i]&0x0f);
65     }
66     name[5+i*2]=0;
67     TRACE( "Value is %s\n", name );
68     return name;
69 }
70
71
72 /**************************************************************************
73  * WNetCachePassword [MPR.@]  Saves password in cache
74  *
75  * NOTES
76  *      only the parameter count is verifyed
77  *
78  *      ---- everything below this line might be wrong (js) -----
79  * RETURNS
80  *    Success: WN_SUCCESS
81  *    Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BADVALUE, WN_NET_ERROR,
82  *             WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
83  */
84 DWORD WINAPI WNetCachePassword(
85     LPSTR pbResource, /* [in] Name of workgroup, computer, or resource */
86     WORD cbResource,  /* [in] Size of name */
87     LPSTR pbPassword, /* [in] Buffer containing password */
88     WORD cbPassword,  /* [in] Size of password */
89     BYTE nType,       /* [in] Type of password to cache */
90     WORD x)
91
92 {
93     HKEY hkey;
94     DWORD r;
95     LPSTR valname;
96
97     WARN( "(%p(%s), %d, %p(%s), %d, %d, 0x%08x): totally insecure\n",
98            pbResource, debugstr_a(pbResource), cbResource,
99            pbPassword, debugstr_a(pbPassword), cbPassword,
100            nType, x );
101
102     /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
103     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
104     if( r )
105         return WN_ACCESS_DENIED;
106
107     valname = MPR_GetValueName( pbResource, cbResource, nType );
108     if( valname )
109     {
110         r = RegSetValueExA( hkey, valname, 0, REG_BINARY, 
111                             (LPBYTE)pbPassword, cbPassword );
112         if( r )
113             r = WN_CANCEL;
114         else
115             r = WN_SUCCESS;
116         HeapFree( GetProcessHeap(), 0, valname );
117     }
118     else
119         r = WN_OUT_OF_MEMORY;
120
121     RegCloseKey( hkey );
122
123     return r;
124 }
125
126 /*****************************************************************
127  *  WNetRemoveCachedPassword [MPR.@]
128  */
129 UINT WINAPI WNetRemoveCachedPassword(
130       LPSTR pbResource,   /* [in] resource ID to delete */
131       WORD cbResource,    /* [in] number of bytes in the resource ID */
132       BYTE nType )        /* [in] Type of the resource to delete */
133 {
134     HKEY hkey;
135     DWORD r;
136     LPSTR valname;
137
138     WARN( "(%p(%s), %d, %d): totally insecure\n",
139            pbResource, debugstr_a(pbResource), cbResource, nType );
140
141     /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
142     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
143     if( r )
144         return WN_ACCESS_DENIED;
145
146     valname = MPR_GetValueName( pbResource, cbResource, nType );
147     if( valname )
148     {
149         r = RegDeleteValueA( hkey, valname );
150         if( r )
151             r = WN_ACCESS_DENIED;
152         else
153             r = WN_SUCCESS;
154         HeapFree( GetProcessHeap(), 0, valname );
155     }
156     else
157         r = WN_OUT_OF_MEMORY;
158
159     return r;
160 }
161
162 /*****************************************************************
163  * WNetGetCachedPassword [MPR.@]  Retrieves password from cache
164  *
165  * NOTES
166  *  the stub seems to be wrong:
167  *      arg1:   ptr     0x40xxxxxx -> (no string)
168  *      arg2:   len     36
169  *      arg3:   ptr     0x40xxxxxx -> (no string)
170  *      arg4:   ptr     0x40xxxxxx -> 0xc8
171  *      arg5:   type?   4
172  *
173  *      ---- everything below this line might be wrong (js) -----
174  * RETURNS
175  *    Success: WN_SUCCESS
176  *    Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE,
177  *             WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
178  */
179 DWORD WINAPI WNetGetCachedPassword(
180     LPSTR pbResource,   /* [in]  Name of workgroup, computer, or resource */
181     WORD cbResource,    /* [in]  Size of name */
182     LPSTR pbPassword,   /* [out] Buffer to receive password */
183     LPWORD pcbPassword, /* [out] Receives size of password */
184     BYTE nType)         /* [in]  Type of password to retrieve */
185 {
186     HKEY hkey;
187     DWORD r, type = 0, sz;
188     LPSTR valname;
189
190     WARN( "(%p(%s), %d, %p, %p, %d): totally insecure\n",
191            pbResource, debugstr_a(pbResource), cbResource,
192            pbPassword, pcbPassword, nType );
193
194     memset( pbPassword, 0, *pcbPassword);
195
196     /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
197     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
198     if( r )
199         return WN_ACCESS_DENIED;
200
201     valname = MPR_GetValueName( pbResource, cbResource, nType );
202     if( valname )
203     {
204         sz = *pcbPassword;
205         r = RegQueryValueExA( hkey, valname, 0, &type, (LPBYTE)pbPassword, &sz );
206         *pcbPassword = sz;
207         if( r )
208             r = WN_CANCEL;
209         else
210             r = WN_SUCCESS;
211         HeapFree( GetProcessHeap(), 0, valname );
212     }
213     else
214         r = WN_OUT_OF_MEMORY;
215
216     return r;
217 }
218
219 /*******************************************************************
220  * WNetEnumCachedPasswords [MPR.@]
221  *
222  * NOTES
223  *      the parameter count is verifyed
224  * 
225  *  This function is a huge security risk, as virii and such can use
226  * it to grab all the passwords in the cache.  It's bad enough to 
227  * store the passwords (insecurely).
228  *
229  *  bpPrefix and cbPrefix are used to filter the returned passwords
230  *   the first cbPrefix bytes of the password resource identifier
231  *   should match the same number of bytes in bpPrefix
232  *
233  * RETURNS
234  *   Success: WN_SUCCESS   (even if no entries were enumerated)
235  *   Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE,
236  *             WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY
237  */
238
239 UINT WINAPI WNetEnumCachedPasswords(
240       LPSTR pbPrefix,  /* [in] prefix to filter cache entries */
241       WORD cbPrefix,   /* [in] number of bytes in Prefix substring */
242       BYTE nType,      /* [in] match the Type ID of the entry */
243       ENUMPASSWORDPROC enumPasswordProc,  /* [in] callback function */
244       DWORD param)     /* [in] parameter passed to enum function */
245 {
246     HKEY hkey;
247     DWORD r, type, val_sz, data_sz, i, j, size;
248     PASSWORD_CACHE_ENTRY *entry;
249     CHAR val[256], prefix[6];
250
251     WARN( "(%s, %d, %d, %p, 0x%08x) totally insecure\n",
252            debugstr_an(pbPrefix,cbPrefix), cbPrefix,
253            nType, enumPasswordProc, param );
254
255     /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */
256     r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey );
257     if( r )
258         return WN_ACCESS_DENIED;
259
260     sprintf(prefix, "X-%02X-", nType );
261
262     i = 0;
263     for( i=0;  ; i++ )
264     {
265         val_sz  = sizeof val;
266         data_sz = 0;
267         type    = 0;
268         val[0] = 0;
269         r = RegEnumValueA( hkey, i, val, &val_sz, NULL, &type, NULL, &data_sz );
270         if( r != ERROR_SUCCESS )
271             break;
272         if( type != REG_BINARY )
273             continue;
274
275         /* check the value is in the format we expect */
276         if( val_sz < sizeof prefix )
277             continue;
278         if( memcmp( prefix, val, 5 ) )
279             continue;
280
281         /* decode the value */
282         for(j=5; j<val_sz; j+=2 )
283         {
284             CHAR hi = ctox( val[j] ), lo = ctox( val[j+1] );
285             if( ( hi < 0 ) || ( lo < 0 ) )
286                 break;
287             val[(j-5)/2] = (hi<<4) | lo;
288         }
289
290         /* find the decoded length */
291         val_sz = (j - 5)/2;
292         val[val_sz]=0;
293         if( val_sz < cbPrefix )
294             continue;
295
296         /* check the prefix matches */
297         if( memcmp(val, pbPrefix, cbPrefix) )
298             continue;
299
300         /* read the value data */
301         size = sizeof *entry - sizeof entry->abResource[0] + val_sz + data_sz;
302         entry = HeapAlloc( GetProcessHeap(), 0, sizeof *entry + val_sz + data_sz );
303         memcpy( entry->abResource, val, val_sz );
304         entry->cbEntry = size;
305         entry->cbResource = val_sz;
306         entry->cbPassword = data_sz;
307         entry->iEntry = i;
308         entry->nType = nType;
309         r = RegEnumValueA( hkey, i, NULL, &val_sz, NULL, &type, 
310                            &entry->abResource[val_sz], &data_sz );
311         if( r == ERROR_SUCCESS )
312             enumPasswordProc( entry, param );
313         HeapFree( GetProcessHeap(), 0, entry );
314     }
315
316     RegCloseKey( hkey );
317
318     return WN_SUCCESS;
319 }