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