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