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