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