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 signed 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 verified 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 verified 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 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 signed 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 = offsetof( PASSWORD_CACHE_ENTRY, abResource[val_sz + data_sz] ); 302 entry = HeapAlloc( GetProcessHeap(), 0, size ); 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 size = sizeof val; 310 r = RegEnumValueA( hkey, i, val, &size, 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 } 321