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