wined3d: Use the proper drawable size when setting the scissor rect.
[wine] / dlls / netapi32 / access.c
1 /*
2  * Copyright 2002 Andriy Palamarchuk
3  *
4  * netapi32 access functions
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "lmcons.h"
29 #include "lmaccess.h"
30 #include "lmapibuf.h"
31 #include "lmerr.h"
32 #include "lmuse.h"
33 #include "ntsecapi.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36 #include "wine/list.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
39
40 /* NOTE: So far, this is implemented to support tests that require user logins,
41  *       but not designed to handle real user databases. Those should probably
42  *       be synced with either the host's user database or with Samba.
43  *
44  * FIXME: The user database should hold all the information the USER_INFO_4 struct
45  * needs, but for the first try, I will just implement the USER_INFO_1 fields.
46  */
47
48 struct sam_user
49 {
50     struct list entry;
51     WCHAR user_name[LM20_UNLEN+1];
52     WCHAR user_password[PWLEN + 1];
53     DWORD sec_since_passwd_change;
54     DWORD user_priv;
55     LPWSTR home_dir;
56     LPWSTR user_comment;
57     DWORD user_flags;
58     LPWSTR user_logon_script_path;
59 };
60
61 static const WCHAR sAdminUserName[] = {'A','d','m','i','n','i','s','t','r','a','t',
62                                 'o','r',0};
63 static const WCHAR sGuestUserName[] = {'G','u','e','s','t',0};
64
65 static struct list user_list = LIST_INIT( user_list );
66
67 BOOL NETAPI_IsLocalComputer(LPCWSTR ServerName);
68
69 /************************************************************
70  *                NETAPI_ValidateServername
71  *
72  * Validates server name
73  */
74 static NET_API_STATUS NETAPI_ValidateServername(LPCWSTR ServerName)
75 {
76     if (ServerName)
77     {
78         if (ServerName[0] == 0)
79             return ERROR_BAD_NETPATH;
80         else if (
81             ((ServerName[0] == '\\') &&
82              (ServerName[1] != '\\'))
83             ||
84             ((ServerName[0] == '\\') &&
85              (ServerName[1] == '\\') &&
86              (ServerName[2] == 0))
87             )
88             return ERROR_INVALID_NAME;
89     }
90     return NERR_Success;
91 }
92
93 /************************************************************
94  *                NETAPI_FindUser
95  *
96  * Looks for a user in the user database.
97  * Returns a pointer to the entry in the user list when the user
98  * is found, NULL otherwise.
99  */
100 static struct sam_user* NETAPI_FindUser(LPCWSTR UserName)
101 {
102     struct sam_user *user;
103
104     LIST_FOR_EACH_ENTRY(user, &user_list, struct sam_user, entry)
105     {
106         if(lstrcmpW(user->user_name, UserName) == 0)
107             return user;
108     }
109     return NULL;
110 }
111
112 /************************************************************
113  *                NetUserAdd (NETAPI32.@)
114  */
115 NET_API_STATUS WINAPI NetUserAdd(LPCWSTR servername,
116                   DWORD level, LPBYTE bufptr, LPDWORD parm_err)
117 {
118     NET_API_STATUS status;
119     struct sam_user * su = NULL;
120
121     FIXME("(%s, %d, %p, %p) stub!\n", debugstr_w(servername), level, bufptr, parm_err);
122
123     if((status = NETAPI_ValidateServername(servername)) != NERR_Success)
124         return status;
125
126     switch(level)
127     {
128     /* Level 3 and 4 are identical for the purposes of NetUserAdd */
129     case 4:
130     case 3:
131         FIXME("Level 3 and 4 not implemented.\n");
132         /* Fall through */
133     case 2:
134         FIXME("Level 2 not implemented.\n");
135         /* Fall through */
136     case 1:
137     {
138         PUSER_INFO_1 ui = (PUSER_INFO_1) bufptr;
139         su = HeapAlloc(GetProcessHeap(), 0, sizeof(struct sam_user));
140         if(!su)
141         {
142             status = NERR_InternalError;
143             break;
144         }
145
146         if(lstrlenW(ui->usri1_name) > LM20_UNLEN)
147         {
148             status = NERR_BadUsername;
149             break;
150         }
151
152         /*FIXME: do other checks for a valid username */
153         lstrcpyW(su->user_name, ui->usri1_name);
154
155         if(lstrlenW(ui->usri1_password) > PWLEN)
156         {
157             /* Always return PasswordTooShort on invalid passwords. */
158             status = NERR_PasswordTooShort;
159             break;
160         }
161         lstrcpyW(su->user_password, ui->usri1_password);
162
163         su->sec_since_passwd_change = ui->usri1_password_age;
164         su->user_priv = ui->usri1_priv;
165         su->user_flags = ui->usri1_flags;
166
167         /*FIXME: set the other LPWSTRs to NULL for now */
168         su->home_dir = NULL;
169         su->user_comment = NULL;
170         su->user_logon_script_path = NULL;
171
172         list_add_head(&user_list, &su->entry);
173         return NERR_Success;
174     }
175     default:
176         TRACE("Invalid level %d specified.\n", level);
177         status = ERROR_INVALID_LEVEL;
178         break;
179     }
180
181     HeapFree(GetProcessHeap(), 0, su);
182
183     return status;
184 }
185
186 /************************************************************
187  *                NetUserDel  (NETAPI32.@)
188  */
189 NET_API_STATUS WINAPI NetUserDel(LPCWSTR servername, LPCWSTR username)
190 {
191     NET_API_STATUS status;
192     struct sam_user *user;
193
194     TRACE("(%s, %s)\n", debugstr_w(servername), debugstr_w(username));
195
196     if((status = NETAPI_ValidateServername(servername))!= NERR_Success)
197         return status;
198
199     if ((user = NETAPI_FindUser(username)) == NULL)
200         return NERR_UserNotFound;
201
202     list_remove(&user->entry);
203
204     HeapFree(GetProcessHeap(), 0, user->home_dir);
205     HeapFree(GetProcessHeap(), 0, user->user_comment);
206     HeapFree(GetProcessHeap(), 0, user->user_logon_script_path);
207     HeapFree(GetProcessHeap(), 0, user);
208
209     return NERR_Success;
210 }
211
212 /************************************************************
213  *                NetUserGetInfo  (NETAPI32.@)
214  */
215 NET_API_STATUS WINAPI
216 NetUserGetInfo(LPCWSTR servername, LPCWSTR username, DWORD level,
217                LPBYTE* bufptr)
218 {
219     NET_API_STATUS status;
220     TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername), debugstr_w(username),
221           level, bufptr);
222     status = NETAPI_ValidateServername(servername);
223     if (status != NERR_Success)
224         return status;
225
226     if(!NETAPI_IsLocalComputer(servername))
227     {
228         FIXME("Only implemented for local computer, but remote server"
229               "%s was requested.\n", debugstr_w(servername));
230         return NERR_InvalidComputer;
231     }
232
233     if(!NETAPI_FindUser(username))
234     {
235         TRACE("User %s is unknown.\n", debugstr_w(username));
236         return NERR_UserNotFound;
237     }
238
239     switch (level)
240     {
241     case 0:
242     {
243         PUSER_INFO_0 ui;
244         int name_sz;
245
246         name_sz = lstrlenW(username) + 1;
247
248         /* set up buffer */
249         NetApiBufferAllocate(sizeof(USER_INFO_0) + name_sz * sizeof(WCHAR),
250                              (LPVOID *) bufptr);
251
252         ui = (PUSER_INFO_0) *bufptr;
253         ui->usri0_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_0));
254
255         /* get data */
256         lstrcpyW(ui->usri0_name, username);
257         break;
258     }
259
260     case 10:
261     {
262         PUSER_INFO_10 ui;
263         PUSER_INFO_0 ui0;
264         NET_API_STATUS status;
265         /* sizes of the field buffers in WCHARS */
266         int name_sz, comment_sz, usr_comment_sz, full_name_sz;
267
268         comment_sz = 1;
269         usr_comment_sz = 1;
270         full_name_sz = 1;
271
272         /* get data */
273         status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0);
274         if (status != NERR_Success)
275         {
276             NetApiBufferFree(ui0);
277             return status;
278         }
279         name_sz = lstrlenW(ui0->usri0_name) + 1;
280
281         /* set up buffer */
282         NetApiBufferAllocate(sizeof(USER_INFO_10) +
283                              (name_sz + comment_sz + usr_comment_sz +
284                               full_name_sz) * sizeof(WCHAR),
285                              (LPVOID *) bufptr);
286         ui = (PUSER_INFO_10) *bufptr;
287         ui->usri10_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_10));
288         ui->usri10_comment = (LPWSTR) (
289             ((PBYTE) ui->usri10_name) + name_sz * sizeof(WCHAR));
290         ui->usri10_usr_comment = (LPWSTR) (
291             ((PBYTE) ui->usri10_comment) + comment_sz * sizeof(WCHAR));
292         ui->usri10_full_name = (LPWSTR) (
293             ((PBYTE) ui->usri10_usr_comment) + usr_comment_sz * sizeof(WCHAR));
294
295         /* set data */
296         lstrcpyW(ui->usri10_name, ui0->usri0_name);
297         NetApiBufferFree(ui0);
298         ui->usri10_comment[0] = 0;
299         ui->usri10_usr_comment[0] = 0;
300         ui->usri10_full_name[0] = 0;
301         break;
302     }
303
304     case 1:
305       {
306         static const WCHAR homedirW[] = {'H','O','M','E',0};
307         PUSER_INFO_1 ui;
308         PUSER_INFO_0 ui0;
309         NET_API_STATUS status;
310         /* sizes of the field buffers in WCHARS */
311         int name_sz, password_sz, home_dir_sz, comment_sz, script_path_sz;
312
313         password_sz = 1; /* not filled out for security reasons for NetUserGetInfo*/
314         comment_sz = 1;
315         script_path_sz = 1;
316
317        /* get data */
318         status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0);
319         if (status != NERR_Success)
320         {
321             NetApiBufferFree(ui0);
322             return status;
323         }
324         name_sz = lstrlenW(ui0->usri0_name) + 1;
325         home_dir_sz = GetEnvironmentVariableW(homedirW, NULL,0);
326         /* set up buffer */
327         NetApiBufferAllocate(sizeof(USER_INFO_1) +
328                              (name_sz + password_sz + home_dir_sz +
329                               comment_sz + script_path_sz) * sizeof(WCHAR),
330                              (LPVOID *) bufptr);
331
332         ui = (PUSER_INFO_1) *bufptr;
333         ui->usri1_name = (LPWSTR) (ui + 1);
334         ui->usri1_password = ui->usri1_name + name_sz;
335         ui->usri1_home_dir = ui->usri1_password + password_sz;
336         ui->usri1_comment = ui->usri1_home_dir + home_dir_sz;
337         ui->usri1_script_path = ui->usri1_comment + comment_sz;
338         /* set data */
339         lstrcpyW(ui->usri1_name, ui0->usri0_name);
340         NetApiBufferFree(ui0);
341         ui->usri1_password[0] = 0;
342         ui->usri1_password_age = 0;
343         ui->usri1_priv = 0;
344         GetEnvironmentVariableW(homedirW, ui->usri1_home_dir,home_dir_sz);
345         ui->usri1_comment[0] = 0;
346         ui->usri1_flags = 0;
347         ui->usri1_script_path[0] = 0;
348         break;
349       }
350     case 2:
351     case 3:
352     case 4:
353     case 11:
354     case 20:
355     case 23:
356     case 1003:
357     case 1005:
358     case 1006:
359     case 1007:
360     case 1008:
361     case 1009:
362     case 1010:
363     case 1011:
364     case 1012:
365     case 1013:
366     case 1014:
367     case 1017:
368     case 1018:
369     case 1020:
370     case 1023:
371     case 1024:
372     case 1025:
373     case 1051:
374     case 1052:
375     case 1053:
376     {
377         FIXME("Level %d is not implemented\n", level);
378         return NERR_InternalError;
379     }
380     default:
381         TRACE("Invalid level %d is specified\n", level);
382         return ERROR_INVALID_LEVEL;
383     }
384     return NERR_Success;
385 }
386
387 /************************************************************
388  *                NetUserGetLocalGroups  (NETAPI32.@)
389  */
390 NET_API_STATUS WINAPI
391 NetUserGetLocalGroups(LPCWSTR servername, LPCWSTR username, DWORD level,
392                       DWORD flags, LPBYTE* bufptr, DWORD prefmaxlen,
393                       LPDWORD entriesread, LPDWORD totalentries)
394 {
395     NET_API_STATUS status;
396
397     FIXME("(%s, %s, %d, %08x, %p %d, %p, %p) stub!\n",
398           debugstr_w(servername), debugstr_w(username), level, flags, bufptr,
399           prefmaxlen, entriesread, totalentries);
400
401     status = NETAPI_ValidateServername(servername);
402     if (status != NERR_Success)
403         return status;
404
405     if (!NETAPI_FindUser(username))
406         return NERR_UserNotFound;
407
408     if (bufptr) *bufptr = NULL;
409     if (entriesread) *entriesread = 0;
410     if (totalentries) *totalentries = 0;
411
412     return NERR_Success;
413 }
414
415 /************************************************************
416  *                NetUserEnum  (NETAPI32.@)
417  */
418 NET_API_STATUS WINAPI
419 NetUserEnum(LPCWSTR servername, DWORD level, DWORD filter, LPBYTE* bufptr,
420             DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries,
421             LPDWORD resume_handle)
422 {
423   FIXME("(%s,%d, 0x%d,%p,%d,%p,%p,%p) stub!\n", debugstr_w(servername), level,
424         filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
425
426   return ERROR_ACCESS_DENIED;
427 }
428
429 /************************************************************
430  *                ACCESS_QueryAdminDisplayInformation
431  *
432  *  Creates a buffer with information for the Admin User
433  */
434 static void ACCESS_QueryAdminDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize)
435 {
436     static const WCHAR sAdminUserName[] = {
437         'A','d','m','i','n','i','s','t','r','a','t','o','r',0};
438
439     /* sizes of the field buffers in WCHARS */
440     int name_sz, comment_sz, full_name_sz;
441     PNET_DISPLAY_USER usr;
442
443     /* set up buffer */
444     name_sz = lstrlenW(sAdminUserName);
445     comment_sz = 1;
446     full_name_sz = 1;
447     
448     *pdwSize = sizeof(NET_DISPLAY_USER);
449     *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
450     NetApiBufferAllocate(*pdwSize, (LPVOID *) buf);
451
452     usr = *buf;
453     usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER));
454     usr->usri1_comment = (LPWSTR) (
455         ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR));
456     usr->usri1_full_name = (LPWSTR) (
457         ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR));
458
459     /* set data */
460     lstrcpyW(usr->usri1_name, sAdminUserName);
461     usr->usri1_comment[0] = 0;
462     usr->usri1_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
463     usr->usri1_full_name[0] = 0;
464     usr->usri1_user_id = 500;
465     usr->usri1_next_index = 0;
466 }
467
468 /************************************************************
469  *                ACCESS_QueryGuestDisplayInformation
470  *
471  *  Creates a buffer with information for the Guest User
472  */
473 static void ACCESS_QueryGuestDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize)
474 {
475     static const WCHAR sGuestUserName[] = {
476         'G','u','e','s','t',0 };
477
478     /* sizes of the field buffers in WCHARS */
479     int name_sz, comment_sz, full_name_sz;
480     PNET_DISPLAY_USER usr;
481
482     /* set up buffer */
483     name_sz = lstrlenW(sGuestUserName);
484     comment_sz = 1;
485     full_name_sz = 1;
486     
487     *pdwSize = sizeof(NET_DISPLAY_USER);
488     *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
489     NetApiBufferAllocate(*pdwSize, (LPVOID *) buf);
490
491     usr = *buf;
492     usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER));
493     usr->usri1_comment = (LPWSTR) (
494         ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR));
495     usr->usri1_full_name = (LPWSTR) (
496         ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR));
497
498     /* set data */
499     lstrcpyW(usr->usri1_name, sGuestUserName);
500     usr->usri1_comment[0] = 0;
501     usr->usri1_flags = UF_ACCOUNTDISABLE | UF_SCRIPT | UF_NORMAL_ACCOUNT |
502         UF_DONT_EXPIRE_PASSWD;
503     usr->usri1_full_name[0] = 0;
504     usr->usri1_user_id = 500;
505     usr->usri1_next_index = 0;
506 }
507
508 /************************************************************
509  * Copies NET_DISPLAY_USER record.
510  */
511 static void ACCESS_CopyDisplayUser(const NET_DISPLAY_USER *dest, LPWSTR *dest_buf,
512                             PNET_DISPLAY_USER src)
513 {
514     LPWSTR str = *dest_buf;
515
516     src->usri1_name = str;
517     lstrcpyW(src->usri1_name, dest->usri1_name);
518     str = (LPWSTR) (
519         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
520
521     src->usri1_comment = str;
522     lstrcpyW(src->usri1_comment, dest->usri1_comment);
523     str = (LPWSTR) (
524         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
525
526     src->usri1_flags = dest->usri1_flags;
527
528     src->usri1_full_name = str;
529     lstrcpyW(src->usri1_full_name, dest->usri1_full_name);
530     str = (LPWSTR) (
531         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
532
533     src->usri1_user_id = dest->usri1_user_id;
534     src->usri1_next_index = dest->usri1_next_index;
535     *dest_buf = str;
536 }
537
538 /************************************************************
539  *                NetQueryDisplayInformation  (NETAPI32.@)
540  *
541  * The buffer structure:
542  * - array of fixed size record of the level type
543  * - strings, referenced by the record of the level type
544  */
545 NET_API_STATUS WINAPI
546 NetQueryDisplayInformation(
547     LPCWSTR ServerName, DWORD Level, DWORD Index, DWORD EntriesRequested,
548     DWORD PreferredMaximumLength, LPDWORD ReturnedEntryCount,
549     PVOID *SortedBuffer)
550 {
551     TRACE("(%s, %d, %d, %d, %d, %p, %p)\n", debugstr_w(ServerName),
552           Level, Index, EntriesRequested, PreferredMaximumLength,
553           ReturnedEntryCount, SortedBuffer);
554
555     if(!NETAPI_IsLocalComputer(ServerName))
556     {
557         FIXME("Only implemented on local computer, but requested for "
558               "remote server %s\n", debugstr_w(ServerName));
559         return ERROR_ACCESS_DENIED;
560     }
561
562     switch (Level)
563     {
564     case 1:
565     {
566         /* current record */
567         PNET_DISPLAY_USER inf;
568         /* current available strings buffer */
569         LPWSTR str;
570         PNET_DISPLAY_USER admin, guest;
571         DWORD admin_size, guest_size;
572         LPWSTR name = NULL;
573         DWORD dwSize;
574
575         /* sizes of the field buffers in WCHARS */
576         int name_sz, comment_sz, full_name_sz;
577
578         /* number of the records, returned in SortedBuffer
579            3 - for current user, Administrator and Guest users
580          */
581         int records = 3;
582
583         FIXME("Level %d partially implemented\n", Level);
584         *ReturnedEntryCount = records;
585         comment_sz = 1;
586         full_name_sz = 1;
587
588         /* get data */
589         dwSize = UNLEN + 1;
590         NetApiBufferAllocate(dwSize, (LPVOID *) &name);
591         if (!GetUserNameW(name, &dwSize))
592         {
593             NetApiBufferFree(name);
594             return ERROR_ACCESS_DENIED;
595         }
596         name_sz = dwSize;
597         ACCESS_QueryAdminDisplayInformation(&admin, &admin_size);
598         ACCESS_QueryGuestDisplayInformation(&guest, &guest_size);
599
600         /* set up buffer */
601         dwSize = sizeof(NET_DISPLAY_USER) * records;
602         dwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
603
604         NetApiBufferAllocate(dwSize +
605                              admin_size - sizeof(NET_DISPLAY_USER) +
606                              guest_size - sizeof(NET_DISPLAY_USER),
607                              (LPVOID *) SortedBuffer);
608         inf = (PNET_DISPLAY_USER) *SortedBuffer;
609         str = (LPWSTR) ((PBYTE) inf + sizeof(NET_DISPLAY_USER) * records);
610         inf->usri1_name = str;
611         str = (LPWSTR) (
612             ((PBYTE) str) + name_sz * sizeof(WCHAR));
613         inf->usri1_comment = str;
614         str = (LPWSTR) (
615             ((PBYTE) str) + comment_sz * sizeof(WCHAR));
616         inf->usri1_full_name = str;
617         str = (LPWSTR) (
618             ((PBYTE) str) + full_name_sz * sizeof(WCHAR));
619
620         /* set data */
621         lstrcpyW(inf->usri1_name, name);
622         NetApiBufferFree(name);
623         inf->usri1_comment[0] = 0;
624         inf->usri1_flags =
625             UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
626         inf->usri1_full_name[0] = 0;
627         inf->usri1_user_id = 0;
628         inf->usri1_next_index = 0;
629
630         inf++;
631         ACCESS_CopyDisplayUser(admin, &str, inf);
632         NetApiBufferFree(admin);
633
634         inf++;
635         ACCESS_CopyDisplayUser(guest, &str, inf);
636         NetApiBufferFree(guest);
637         break;
638     }
639
640     case 2:
641     case 3:
642     {
643         FIXME("Level %d is not implemented\n", Level);
644         break;
645     }
646
647     default:
648         TRACE("Invalid level %d is specified\n", Level);
649         return ERROR_INVALID_LEVEL;
650     }
651     return NERR_Success;
652 }
653
654 /************************************************************
655  *                NetGetDCName  (NETAPI32.@)
656  *
657  *  Return the name of the primary domain controller (PDC)
658  */
659
660 NET_API_STATUS WINAPI
661 NetGetDCName(LPCWSTR servername, LPCWSTR domainname, LPBYTE *bufptr)
662 {
663   FIXME("(%s, %s, %p) stub!\n", debugstr_w(servername),
664                  debugstr_w(domainname), bufptr);
665   return NERR_DCNotFound; /* say we can't find a domain controller */  
666 }
667
668
669 /******************************************************************************
670  * NetUserModalsGet  (NETAPI32.@)
671  *
672  * Retrieves global information for all users and global groups in the security
673  * database.
674  *
675  * PARAMS
676  *  szServer   [I] Specifies the DNS or the NetBIOS name of the remote server
677  *                 on which the function is to execute.
678  *  level      [I] Information level of the data.
679  *     0   Return global passwords parameters. bufptr points to a
680  *         USER_MODALS_INFO_0 struct.
681  *     1   Return logon server and domain controller information. bufptr
682  *         points to a USER_MODALS_INFO_1 struct.
683  *     2   Return domain name and identifier. bufptr points to a 
684  *         USER_MODALS_INFO_2 struct.
685  *     3   Return lockout information. bufptr points to a USER_MODALS_INFO_3
686  *         struct.
687  *  pbuffer    [I] Buffer that receives the data.
688  *
689  * RETURNS
690  *  Success: NERR_Success.
691  *  Failure: 
692  *     ERROR_ACCESS_DENIED - the user does not have access to the info.
693  *     NERR_InvalidComputer - computer name is invalid.
694  */
695 NET_API_STATUS WINAPI NetUserModalsGet(
696     LPCWSTR szServer, DWORD level, LPBYTE *pbuffer)
697 {
698     TRACE("(%s %d %p)\n", debugstr_w(szServer), level, pbuffer);
699     
700     switch (level)
701     {
702         case 0:
703             /* return global passwords parameters */
704             FIXME("level 0 not implemented!\n");
705             *pbuffer = NULL;
706             return NERR_InternalError;
707         case 1:
708             /* return logon server and domain controller info */
709             FIXME("level 1 not implemented!\n");
710             *pbuffer = NULL;
711             return NERR_InternalError;
712         case 2:
713         {
714             /* return domain name and identifier */
715             PUSER_MODALS_INFO_2 umi;
716             LSA_HANDLE policyHandle;
717             LSA_OBJECT_ATTRIBUTES objectAttributes;
718             PPOLICY_ACCOUNT_DOMAIN_INFO domainInfo;
719             NTSTATUS ntStatus;
720             PSID domainIdentifier = NULL;
721             int domainNameLen;
722
723             ZeroMemory(&objectAttributes, sizeof(objectAttributes));
724             objectAttributes.Length = sizeof(objectAttributes);
725
726             ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
727                                      POLICY_VIEW_LOCAL_INFORMATION,
728                                      &policyHandle);
729             if (ntStatus != STATUS_SUCCESS)
730             {
731                 WARN("LsaOpenPolicy failed with NT status %x\n",
732                      LsaNtStatusToWinError(ntStatus));
733                 return ntStatus;
734             }
735
736             ntStatus = LsaQueryInformationPolicy(policyHandle,
737                                                  PolicyAccountDomainInformation,
738                                                  (PVOID *)&domainInfo);
739             if (ntStatus != STATUS_SUCCESS)
740             {
741                 WARN("LsaQueryInformationPolicy failed with NT status %x\n",
742                      LsaNtStatusToWinError(ntStatus));
743                 LsaClose(policyHandle);
744                 return ntStatus;
745             }
746
747             domainIdentifier = domainInfo->DomainSid;
748             domainNameLen = lstrlenW(domainInfo->DomainName.Buffer) + 1;
749             LsaClose(policyHandle);
750
751             ntStatus = NetApiBufferAllocate(sizeof(USER_MODALS_INFO_2) +
752                                             GetLengthSid(domainIdentifier) +
753                                             domainNameLen * sizeof(WCHAR),
754                                             (LPVOID *)pbuffer);
755
756             if (ntStatus != NERR_Success)
757             {
758                 WARN("NetApiBufferAllocate() failed\n");
759                 LsaFreeMemory(domainInfo);
760                 return ntStatus;
761             }
762
763             umi = (USER_MODALS_INFO_2 *) *pbuffer;
764             umi->usrmod2_domain_id = (PSID)(*pbuffer +
765                 sizeof(USER_MODALS_INFO_2));
766             umi->usrmod2_domain_name = (LPWSTR)(*pbuffer +
767                 sizeof(USER_MODALS_INFO_2) + GetLengthSid(domainIdentifier));
768
769             lstrcpynW(umi->usrmod2_domain_name,
770                       domainInfo->DomainName.Buffer,
771                       domainNameLen);
772             CopySid(GetLengthSid(domainIdentifier), umi->usrmod2_domain_id,
773                     domainIdentifier);
774
775             LsaFreeMemory(domainInfo);
776
777             break;
778         } 
779         case 3:
780             /* return lockout information */
781             FIXME("level 3 not implemented!\n");
782             *pbuffer = NULL;
783             return NERR_InternalError;
784         default:
785             TRACE("Invalid level %d is specified\n", level);
786             *pbuffer = NULL;
787             return ERROR_INVALID_LEVEL;
788     }
789
790     return NERR_Success;
791 }
792
793 /******************************************************************************
794  *                NetUserChangePassword  (NETAPI32.@)
795  * PARAMS
796  *  domainname  [I] Optional. Domain on which the user resides or the logon
797  *                  domain of the current user if NULL.
798  *  username    [I] Optional. Username to change the password for or the name
799  *                  of the current user if NULL.
800  *  oldpassword [I] The user's current password.
801  *  newpassword [I] The password that the user will be changed to using.
802  *
803  * RETURNS
804  *  Success: NERR_Success.
805  *  Failure: NERR_* failure code or win error code.
806  *
807  */
808 NET_API_STATUS WINAPI NetUserChangePassword(LPCWSTR domainname, LPCWSTR username,
809     LPCWSTR oldpassword, LPCWSTR newpassword)
810 {
811     struct sam_user *user;
812
813     TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname), debugstr_w(username));
814
815     if(domainname)
816         FIXME("Ignoring domainname %s.\n", debugstr_w(domainname));
817
818     if((user = NETAPI_FindUser(username)) == NULL)
819         return NERR_UserNotFound;
820
821     if(lstrcmpW(user->user_password, oldpassword) != 0)
822         return ERROR_INVALID_PASSWORD;
823
824     if(lstrlenW(newpassword) > PWLEN)
825         return ERROR_PASSWORD_RESTRICTION;
826
827     lstrcpyW(user->user_password, newpassword);
828
829     return NERR_Success;
830 }
831
832 NET_API_STATUS WINAPI NetUseAdd(LMSTR servername, DWORD level, LPBYTE bufptr, LPDWORD parm_err)
833 {
834     FIXME("%s %d %p %p stub\n", debugstr_w(servername), level, bufptr, parm_err);
835     return NERR_Success;
836 }