msi: Simplify ready_media.
[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     if(su)
182     {
183         HeapFree(GetProcessHeap(), 0, su);
184     }
185     return status;
186 }
187
188 /************************************************************
189  *                NetUserDel  (NETAPI32.@)
190  */
191 NET_API_STATUS WINAPI NetUserDel(LPCWSTR servername, LPCWSTR username)
192 {
193     NET_API_STATUS status;
194     struct sam_user *user;
195
196     TRACE("(%s, %s)\n", debugstr_w(servername), debugstr_w(username));
197
198     if((status = NETAPI_ValidateServername(servername))!= NERR_Success)
199         return status;
200
201     if ((user = NETAPI_FindUser(username)) == NULL)
202         return NERR_UserNotFound;
203
204     list_remove(&user->entry);
205
206     HeapFree(GetProcessHeap(), 0, user->home_dir);
207     HeapFree(GetProcessHeap(), 0, user->user_comment);
208     HeapFree(GetProcessHeap(), 0, user->user_logon_script_path);
209     HeapFree(GetProcessHeap(), 0, user);
210
211     return NERR_Success;
212 }
213
214 /************************************************************
215  *                NetUserGetInfo  (NETAPI32.@)
216  */
217 NET_API_STATUS WINAPI
218 NetUserGetInfo(LPCWSTR servername, LPCWSTR username, DWORD level,
219                LPBYTE* bufptr)
220 {
221     NET_API_STATUS status;
222     TRACE("(%s, %s, %d, %p)\n", debugstr_w(servername), debugstr_w(username),
223           level, bufptr);
224     status = NETAPI_ValidateServername(servername);
225     if (status != NERR_Success)
226         return status;
227
228     if(!NETAPI_IsLocalComputer(servername))
229     {
230         FIXME("Only implemented for local computer, but remote server"
231               "%s was requested.\n", debugstr_w(servername));
232         return NERR_InvalidComputer;
233     }
234
235     if(!NETAPI_FindUser(username))
236     {
237         TRACE("User %s is unknown.\n", debugstr_w(username));
238         return NERR_UserNotFound;
239     }
240
241     switch (level)
242     {
243     case 0:
244     {
245         PUSER_INFO_0 ui;
246         int name_sz;
247
248         name_sz = lstrlenW(username) + 1;
249
250         /* set up buffer */
251         NetApiBufferAllocate(sizeof(USER_INFO_0) + name_sz * sizeof(WCHAR),
252                              (LPVOID *) bufptr);
253
254         ui = (PUSER_INFO_0) *bufptr;
255         ui->usri0_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_0));
256
257         /* get data */
258         lstrcpyW(ui->usri0_name, username);
259         break;
260     }
261
262     case 10:
263     {
264         PUSER_INFO_10 ui;
265         PUSER_INFO_0 ui0;
266         NET_API_STATUS status;
267         /* sizes of the field buffers in WCHARS */
268         int name_sz, comment_sz, usr_comment_sz, full_name_sz;
269
270         comment_sz = 1;
271         usr_comment_sz = 1;
272         full_name_sz = 1;
273
274         /* get data */
275         status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0);
276         if (status != NERR_Success)
277         {
278             NetApiBufferFree(ui0);
279             return status;
280         }
281         name_sz = lstrlenW(ui0->usri0_name) + 1;
282
283         /* set up buffer */
284         NetApiBufferAllocate(sizeof(USER_INFO_10) +
285                              (name_sz + comment_sz + usr_comment_sz +
286                               full_name_sz) * sizeof(WCHAR),
287                              (LPVOID *) bufptr);
288         ui = (PUSER_INFO_10) *bufptr;
289         ui->usri10_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_10));
290         ui->usri10_comment = (LPWSTR) (
291             ((PBYTE) ui->usri10_name) + name_sz * sizeof(WCHAR));
292         ui->usri10_usr_comment = (LPWSTR) (
293             ((PBYTE) ui->usri10_comment) + comment_sz * sizeof(WCHAR));
294         ui->usri10_full_name = (LPWSTR) (
295             ((PBYTE) ui->usri10_usr_comment) + usr_comment_sz * sizeof(WCHAR));
296
297         /* set data */
298         lstrcpyW(ui->usri10_name, ui0->usri0_name);
299         NetApiBufferFree(ui0);
300         ui->usri10_comment[0] = 0;
301         ui->usri10_usr_comment[0] = 0;
302         ui->usri10_full_name[0] = 0;
303         break;
304     }
305
306     case 1:
307       {
308         static const WCHAR homedirW[] = {'H','O','M','E',0};
309         PUSER_INFO_1 ui;
310         PUSER_INFO_0 ui0;
311         NET_API_STATUS status;
312         /* sizes of the field buffers in WCHARS */
313         int name_sz, password_sz, home_dir_sz, comment_sz, script_path_sz;
314
315         password_sz = 1; /* not filled out for security reasons for NetUserGetInfo*/
316         comment_sz = 1;
317         script_path_sz = 1;
318
319        /* get data */
320         status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0);
321         if (status != NERR_Success)
322         {
323             NetApiBufferFree(ui0);
324             return status;
325         }
326         name_sz = lstrlenW(ui0->usri0_name) + 1;
327         home_dir_sz = GetEnvironmentVariableW(homedirW, NULL,0);
328         /* set up buffer */
329         NetApiBufferAllocate(sizeof(USER_INFO_1) +
330                              (name_sz + password_sz + home_dir_sz +
331                               comment_sz + script_path_sz) * sizeof(WCHAR),
332                              (LPVOID *) bufptr);
333
334         ui = (PUSER_INFO_1) *bufptr;
335         ui->usri1_name = (LPWSTR) (ui + 1);
336         ui->usri1_password = ui->usri1_name + name_sz;
337         ui->usri1_home_dir = ui->usri1_password + password_sz;
338         ui->usri1_comment = ui->usri1_home_dir + home_dir_sz;
339         ui->usri1_script_path = ui->usri1_comment + comment_sz;
340         /* set data */
341         lstrcpyW(ui->usri1_name, ui0->usri0_name);
342         NetApiBufferFree(ui0);
343         ui->usri1_password[0] = 0;
344         ui->usri1_password_age = 0;
345         ui->usri1_priv = 0;
346         GetEnvironmentVariableW(homedirW, ui->usri1_home_dir,home_dir_sz);
347         ui->usri1_comment[0] = 0;
348         ui->usri1_flags = 0;
349         ui->usri1_script_path[0] = 0;
350         break;
351       }
352     case 2:
353     case 3:
354     case 4:
355     case 11:
356     case 20:
357     case 23:
358     case 1003:
359     case 1005:
360     case 1006:
361     case 1007:
362     case 1008:
363     case 1009:
364     case 1010:
365     case 1011:
366     case 1012:
367     case 1013:
368     case 1014:
369     case 1017:
370     case 1018:
371     case 1020:
372     case 1023:
373     case 1024:
374     case 1025:
375     case 1051:
376     case 1052:
377     case 1053:
378     {
379         FIXME("Level %d is not implemented\n", level);
380         return NERR_InternalError;
381     }
382     default:
383         TRACE("Invalid level %d is specified\n", level);
384         return ERROR_INVALID_LEVEL;
385     }
386     return NERR_Success;
387 }
388
389 /************************************************************
390  *                NetUserGetLocalGroups  (NETAPI32.@)
391  */
392 NET_API_STATUS WINAPI
393 NetUserGetLocalGroups(LPCWSTR servername, LPCWSTR username, DWORD level,
394                       DWORD flags, LPBYTE* bufptr, DWORD prefmaxlen,
395                       LPDWORD entriesread, LPDWORD totalentries)
396 {
397     NET_API_STATUS status;
398
399     FIXME("(%s, %s, %d, %08x, %p %d, %p, %p) stub!\n",
400           debugstr_w(servername), debugstr_w(username), level, flags, bufptr,
401           prefmaxlen, entriesread, totalentries);
402
403     status = NETAPI_ValidateServername(servername);
404     if (status != NERR_Success)
405         return status;
406
407     if (!NETAPI_FindUser(username))
408         return NERR_UserNotFound;
409
410     if (bufptr) *bufptr = NULL;
411     if (entriesread) *entriesread = 0;
412     if (totalentries) *totalentries = 0;
413
414     return NERR_Success;
415 }
416
417 /************************************************************
418  *                NetUserEnum  (NETAPI32.@)
419  */
420 NET_API_STATUS WINAPI
421 NetUserEnum(LPCWSTR servername, DWORD level, DWORD filter, LPBYTE* bufptr,
422             DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries,
423             LPDWORD resume_handle)
424 {
425   FIXME("(%s,%d, 0x%d,%p,%d,%p,%p,%p) stub!\n", debugstr_w(servername), level,
426         filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
427
428   return ERROR_ACCESS_DENIED;
429 }
430
431 /************************************************************
432  *                ACCESS_QueryAdminDisplayInformation
433  *
434  *  Creates a buffer with information for the Admin User
435  */
436 static void ACCESS_QueryAdminDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize)
437 {
438     static const WCHAR sAdminUserName[] = {
439         'A','d','m','i','n','i','s','t','r','a','t','o','r',0};
440
441     /* sizes of the field buffers in WCHARS */
442     int name_sz, comment_sz, full_name_sz;
443     PNET_DISPLAY_USER usr;
444
445     /* set up buffer */
446     name_sz = lstrlenW(sAdminUserName);
447     comment_sz = 1;
448     full_name_sz = 1;
449     
450     *pdwSize = sizeof(NET_DISPLAY_USER);
451     *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
452     NetApiBufferAllocate(*pdwSize, (LPVOID *) buf);
453
454     usr = *buf;
455     usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER));
456     usr->usri1_comment = (LPWSTR) (
457         ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR));
458     usr->usri1_full_name = (LPWSTR) (
459         ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR));
460
461     /* set data */
462     lstrcpyW(usr->usri1_name, sAdminUserName);
463     usr->usri1_comment[0] = 0;
464     usr->usri1_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
465     usr->usri1_full_name[0] = 0;
466     usr->usri1_user_id = 500;
467     usr->usri1_next_index = 0;
468 }
469
470 /************************************************************
471  *                ACCESS_QueryGuestDisplayInformation
472  *
473  *  Creates a buffer with information for the Guest User
474  */
475 static void ACCESS_QueryGuestDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize)
476 {
477     static const WCHAR sGuestUserName[] = {
478         'G','u','e','s','t',0 };
479
480     /* sizes of the field buffers in WCHARS */
481     int name_sz, comment_sz, full_name_sz;
482     PNET_DISPLAY_USER usr;
483
484     /* set up buffer */
485     name_sz = lstrlenW(sGuestUserName);
486     comment_sz = 1;
487     full_name_sz = 1;
488     
489     *pdwSize = sizeof(NET_DISPLAY_USER);
490     *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
491     NetApiBufferAllocate(*pdwSize, (LPVOID *) buf);
492
493     usr = *buf;
494     usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER));
495     usr->usri1_comment = (LPWSTR) (
496         ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR));
497     usr->usri1_full_name = (LPWSTR) (
498         ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR));
499
500     /* set data */
501     lstrcpyW(usr->usri1_name, sGuestUserName);
502     usr->usri1_comment[0] = 0;
503     usr->usri1_flags = UF_ACCOUNTDISABLE | UF_SCRIPT | UF_NORMAL_ACCOUNT |
504         UF_DONT_EXPIRE_PASSWD;
505     usr->usri1_full_name[0] = 0;
506     usr->usri1_user_id = 500;
507     usr->usri1_next_index = 0;
508 }
509
510 /************************************************************
511  * Copies NET_DISPLAY_USER record.
512  */
513 static void ACCESS_CopyDisplayUser(const NET_DISPLAY_USER *dest, LPWSTR *dest_buf,
514                             PNET_DISPLAY_USER src)
515 {
516     LPWSTR str = *dest_buf;
517
518     src->usri1_name = str;
519     lstrcpyW(src->usri1_name, dest->usri1_name);
520     str = (LPWSTR) (
521         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
522
523     src->usri1_comment = str;
524     lstrcpyW(src->usri1_comment, dest->usri1_comment);
525     str = (LPWSTR) (
526         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
527
528     src->usri1_flags = dest->usri1_flags;
529
530     src->usri1_full_name = str;
531     lstrcpyW(src->usri1_full_name, dest->usri1_full_name);
532     str = (LPWSTR) (
533         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
534
535     src->usri1_user_id = dest->usri1_user_id;
536     src->usri1_next_index = dest->usri1_next_index;
537     *dest_buf = str;
538 }
539
540 /************************************************************
541  *                NetQueryDisplayInformation  (NETAPI32.@)
542  *
543  * The buffer structure:
544  * - array of fixed size record of the level type
545  * - strings, referenced by the record of the level type
546  */
547 NET_API_STATUS WINAPI
548 NetQueryDisplayInformation(
549     LPCWSTR ServerName, DWORD Level, DWORD Index, DWORD EntriesRequested,
550     DWORD PreferredMaximumLength, LPDWORD ReturnedEntryCount,
551     PVOID *SortedBuffer)
552 {
553     TRACE("(%s, %d, %d, %d, %d, %p, %p)\n", debugstr_w(ServerName),
554           Level, Index, EntriesRequested, PreferredMaximumLength,
555           ReturnedEntryCount, SortedBuffer);
556
557     if(!NETAPI_IsLocalComputer(ServerName))
558     {
559         FIXME("Only implemented on local computer, but requested for "
560               "remote server %s\n", debugstr_w(ServerName));
561         return ERROR_ACCESS_DENIED;
562     }
563
564     switch (Level)
565     {
566     case 1:
567     {
568         /* current record */
569         PNET_DISPLAY_USER inf;
570         /* current available strings buffer */
571         LPWSTR str;
572         PNET_DISPLAY_USER admin, guest;
573         DWORD admin_size, guest_size;
574         LPWSTR name = NULL;
575         DWORD dwSize;
576
577         /* sizes of the field buffers in WCHARS */
578         int name_sz, comment_sz, full_name_sz;
579
580         /* number of the records, returned in SortedBuffer
581            3 - for current user, Administrator and Guest users
582          */
583         int records = 3;
584
585         FIXME("Level %d partially implemented\n", Level);
586         *ReturnedEntryCount = records;
587         comment_sz = 1;
588         full_name_sz = 1;
589
590         /* get data */
591         dwSize = UNLEN + 1;
592         NetApiBufferAllocate(dwSize, (LPVOID *) &name);
593         if (!GetUserNameW(name, &dwSize))
594         {
595             NetApiBufferFree(name);
596             return ERROR_ACCESS_DENIED;
597         }
598         name_sz = dwSize;
599         ACCESS_QueryAdminDisplayInformation(&admin, &admin_size);
600         ACCESS_QueryGuestDisplayInformation(&guest, &guest_size);
601
602         /* set up buffer */
603         dwSize = sizeof(NET_DISPLAY_USER) * records;
604         dwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
605
606         NetApiBufferAllocate(dwSize +
607                              admin_size - sizeof(NET_DISPLAY_USER) +
608                              guest_size - sizeof(NET_DISPLAY_USER),
609                              (LPVOID *) SortedBuffer);
610         inf = (PNET_DISPLAY_USER) *SortedBuffer;
611         str = (LPWSTR) ((PBYTE) inf + sizeof(NET_DISPLAY_USER) * records);
612         inf->usri1_name = str;
613         str = (LPWSTR) (
614             ((PBYTE) str) + name_sz * sizeof(WCHAR));
615         inf->usri1_comment = str;
616         str = (LPWSTR) (
617             ((PBYTE) str) + comment_sz * sizeof(WCHAR));
618         inf->usri1_full_name = str;
619         str = (LPWSTR) (
620             ((PBYTE) str) + full_name_sz * sizeof(WCHAR));
621
622         /* set data */
623         lstrcpyW(inf->usri1_name, name);
624         NetApiBufferFree(name);
625         inf->usri1_comment[0] = 0;
626         inf->usri1_flags =
627             UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
628         inf->usri1_full_name[0] = 0;
629         inf->usri1_user_id = 0;
630         inf->usri1_next_index = 0;
631
632         inf++;
633         ACCESS_CopyDisplayUser(admin, &str, inf);
634         NetApiBufferFree(admin);
635
636         inf++;
637         ACCESS_CopyDisplayUser(guest, &str, inf);
638         NetApiBufferFree(guest);
639         break;
640     }
641
642     case 2:
643     case 3:
644     {
645         FIXME("Level %d is not implemented\n", Level);
646         break;
647     }
648
649     default:
650         TRACE("Invalid level %d is specified\n", Level);
651         return ERROR_INVALID_LEVEL;
652     }
653     return NERR_Success;
654 }
655
656 /************************************************************
657  *                NetGetDCName  (NETAPI32.@)
658  *
659  *  Return the name of the primary domain controller (PDC)
660  */
661
662 NET_API_STATUS WINAPI
663 NetGetDCName(LPCWSTR servername, LPCWSTR domainname, LPBYTE *bufptr)
664 {
665   FIXME("(%s, %s, %p) stub!\n", debugstr_w(servername),
666                  debugstr_w(domainname), bufptr);
667   return NERR_DCNotFound; /* say we can't find a domain controller */  
668 }
669
670
671 /******************************************************************************
672  * NetUserModalsGet  (NETAPI32.@)
673  *
674  * Retrieves global information for all users and global groups in the security
675  * database.
676  *
677  * PARAMS
678  *  szServer   [I] Specifies the DNS or the NetBIOS name of the remote server
679  *                 on which the function is to execute.
680  *  level      [I] Information level of the data.
681  *     0   Return global passwords parameters. bufptr points to a
682  *         USER_MODALS_INFO_0 struct.
683  *     1   Return logon server and domain controller information. bufptr
684  *         points to a USER_MODALS_INFO_1 struct.
685  *     2   Return domain name and identifier. bufptr points to a 
686  *         USER_MODALS_INFO_2 struct.
687  *     3   Return lockout information. bufptr points to a USER_MODALS_INFO_3
688  *         struct.
689  *  pbuffer    [I] Buffer that receives the data.
690  *
691  * RETURNS
692  *  Success: NERR_Success.
693  *  Failure: 
694  *     ERROR_ACCESS_DENIED - the user does not have access to the info.
695  *     NERR_InvalidComputer - computer name is invalid.
696  */
697 NET_API_STATUS WINAPI NetUserModalsGet(
698     LPCWSTR szServer, DWORD level, LPBYTE *pbuffer)
699 {
700     TRACE("(%s %d %p)\n", debugstr_w(szServer), level, pbuffer);
701     
702     switch (level)
703     {
704         case 0:
705             /* return global passwords parameters */
706             FIXME("level 0 not implemented!\n");
707             *pbuffer = NULL;
708             return NERR_InternalError;
709         case 1:
710             /* return logon server and domain controller info */
711             FIXME("level 1 not implemented!\n");
712             *pbuffer = NULL;
713             return NERR_InternalError;
714         case 2:
715         {
716             /* return domain name and identifier */
717             PUSER_MODALS_INFO_2 umi;
718             LSA_HANDLE policyHandle;
719             LSA_OBJECT_ATTRIBUTES objectAttributes;
720             PPOLICY_ACCOUNT_DOMAIN_INFO domainInfo;
721             NTSTATUS ntStatus;
722             PSID domainIdentifier = NULL;
723             int domainNameLen;
724
725             ZeroMemory(&objectAttributes, sizeof(objectAttributes));
726             objectAttributes.Length = sizeof(objectAttributes);
727
728             ntStatus = LsaOpenPolicy(NULL, &objectAttributes,
729                                      POLICY_VIEW_LOCAL_INFORMATION,
730                                      &policyHandle);
731             if (ntStatus != STATUS_SUCCESS)
732             {
733                 WARN("LsaOpenPolicy failed with NT status %x\n",
734                      LsaNtStatusToWinError(ntStatus));
735                 return ntStatus;
736             }
737
738             ntStatus = LsaQueryInformationPolicy(policyHandle,
739                                                  PolicyAccountDomainInformation,
740                                                  (PVOID *)&domainInfo);
741             if (ntStatus != STATUS_SUCCESS)
742             {
743                 WARN("LsaQueryInformationPolicy failed with NT status %x\n",
744                      LsaNtStatusToWinError(ntStatus));
745                 LsaClose(policyHandle);
746                 return ntStatus;
747             }
748
749             domainIdentifier = domainInfo->DomainSid;
750             domainNameLen = lstrlenW(domainInfo->DomainName.Buffer) + 1;
751             LsaClose(policyHandle);
752
753             ntStatus = NetApiBufferAllocate(sizeof(USER_MODALS_INFO_2) +
754                                             GetLengthSid(domainIdentifier) +
755                                             domainNameLen * sizeof(WCHAR),
756                                             (LPVOID *)pbuffer);
757
758             if (ntStatus != NERR_Success)
759             {
760                 WARN("NetApiBufferAllocate() failed\n");
761                 LsaFreeMemory(domainInfo);
762                 return ntStatus;
763             }
764
765             umi = (USER_MODALS_INFO_2 *) *pbuffer;
766             umi->usrmod2_domain_id = (PSID)(*pbuffer +
767                 sizeof(USER_MODALS_INFO_2));
768             umi->usrmod2_domain_name = (LPWSTR)(*pbuffer +
769                 sizeof(USER_MODALS_INFO_2) + GetLengthSid(domainIdentifier));
770
771             lstrcpynW(umi->usrmod2_domain_name,
772                       domainInfo->DomainName.Buffer,
773                       domainNameLen);
774             CopySid(GetLengthSid(domainIdentifier), umi->usrmod2_domain_id,
775                     domainIdentifier);
776
777             LsaFreeMemory(domainInfo);
778
779             break;
780         } 
781         case 3:
782             /* return lockout information */
783             FIXME("level 3 not implemented!\n");
784             *pbuffer = NULL;
785             return NERR_InternalError;
786         default:
787             TRACE("Invalid level %d is specified\n", level);
788             *pbuffer = NULL;
789             return ERROR_INVALID_LEVEL;
790     }
791
792     return NERR_Success;
793 }
794
795 /******************************************************************************
796  *                NetUserChangePassword  (NETAPI32.@)
797  * PARAMS
798  *  domainname  [I] Optional. Domain on which the user resides or the logon
799  *                  domain of the current user if NULL.
800  *  username    [I] Optional. Username to change the password for or the name
801  *                  of the current user if NULL.
802  *  oldpassword [I] The user's current password.
803  *  newpassword [I] The password that the user will be changed to using.
804  *
805  * RETURNS
806  *  Success: NERR_Success.
807  *  Failure: NERR_* failure code or win error code.
808  *
809  */
810 NET_API_STATUS WINAPI NetUserChangePassword(LPCWSTR domainname, LPCWSTR username,
811     LPCWSTR oldpassword, LPCWSTR newpassword)
812 {
813     struct sam_user *user;
814
815     TRACE("(%s, %s, ..., ...)\n", debugstr_w(domainname), debugstr_w(username));
816
817     if(domainname)
818         FIXME("Ignoring domainname %s.\n", debugstr_w(domainname));
819
820     if((user = NETAPI_FindUser(username)) == NULL)
821         return NERR_UserNotFound;
822
823     if(lstrcmpW(user->user_password, oldpassword) != 0)
824         return ERROR_INVALID_PASSWORD;
825
826     if(lstrlenW(newpassword) > PWLEN)
827         return ERROR_PASSWORD_RESTRICTION;
828
829     lstrcpyW(user->user_password, newpassword);
830
831     return NERR_Success;
832 }
833
834 NET_API_STATUS WINAPI NetUseAdd(LMSTR servername, DWORD level, LPBYTE bufptr, LPDWORD parm_err)
835 {
836     FIXME("%s %d %p %p stub\n", debugstr_w(servername), level, bufptr, parm_err);
837     return NERR_Success;
838 }