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