msxml3: Fix for empty node lists.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winerror.h"
26 #include "lmcons.h"
27 #include "lmaccess.h"
28 #include "lmapibuf.h"
29 #include "lmerr.h"
30 #include "netapi32_misc.h"
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(netapi32);
35
36 static const WCHAR sAdminUserName[] = {'A','d','m','i','n','i','s','t','r','a','t',
37                                 'o','r',0};
38 static const WCHAR sGuestUserName[] = {'G','u','e','s','t',0};
39
40 /************************************************************
41  *                NETAPI_ValidateServername
42  *
43  * Validates server name
44  */
45 static NET_API_STATUS NETAPI_ValidateServername(LPCWSTR ServerName)
46 {
47     if (ServerName)
48     {
49         if (ServerName[0] == 0)
50             return ERROR_BAD_NETPATH;
51         else if (
52             ((ServerName[0] == '\\') &&
53              (ServerName[1] != '\\'))
54             ||
55             ((ServerName[0] == '\\') &&
56              (ServerName[1] == '\\') &&
57              (ServerName[2] == 0))
58             )
59             return ERROR_INVALID_NAME;
60     }
61     return NERR_Success;
62 }
63
64 /************************************************************
65  *                NETAPI_IsKnownUser
66  *
67  * Checks whether the user name indicates current user.
68  */
69 static BOOL NETAPI_IsKnownUser(LPCWSTR UserName)
70 {
71     DWORD dwSize = UNLEN + 1;
72     BOOL Result;
73     LPWSTR buf;
74
75     if (!lstrcmpW(UserName, sAdminUserName) ||
76         !lstrcmpW(UserName, sGuestUserName))
77         return TRUE;
78     NetApiBufferAllocate(dwSize * sizeof(WCHAR), (LPVOID *) &buf);
79     Result = GetUserNameW(buf, &dwSize);
80
81     Result = Result && !lstrcmpW(UserName, buf);
82     NetApiBufferFree(buf);
83
84     return Result;
85 }
86
87 #define NETAPI_ForceKnownUser(UserName, FailureCode) \
88     if (!NETAPI_IsKnownUser(UserName)) \
89     { \
90         FIXME("Can't find information for user %s\n", \
91               debugstr_w(UserName)); \
92         return FailureCode; \
93     }
94
95 /************************************************************
96  *                NetUserAdd (NETAPI32.@)
97  */
98 NET_API_STATUS WINAPI NetUserAdd(LPCWSTR servername,
99                   DWORD level, LPBYTE bufptr, LPDWORD parm_err)
100 {
101     NET_API_STATUS status;
102     FIXME("(%s, %ld, %p, %p) stub!\n", debugstr_w(servername), level, bufptr, parm_err);
103
104     status = NETAPI_ValidateServername(servername);
105     if (status != NERR_Success)
106         return status;
107     
108     if ((bufptr != NULL) && (level > 0) && (level <= 4))
109     {
110         PUSER_INFO_1 ui = (PUSER_INFO_1) bufptr;
111         TRACE("usri%ld_name: %s\n", level, debugstr_w(ui->usri1_name));
112         TRACE("usri%ld_password: %s\n", level, debugstr_w(ui->usri1_password));
113         TRACE("usri%ld_comment: %s\n", level, debugstr_w(ui->usri1_comment));
114     }
115     return status;
116 }
117
118 /************************************************************
119  *                NetUserDel  (NETAPI32.@)
120  */
121 NET_API_STATUS WINAPI NetUserDel(LPCWSTR servername, LPCWSTR username)
122 {
123     NET_API_STATUS status;
124     FIXME("(%s, %s) stub!\n", debugstr_w(servername), debugstr_w(username));
125
126     status = NETAPI_ValidateServername(servername);
127     if (status != NERR_Success)
128         return status;
129
130     if (!NETAPI_IsKnownUser(username))
131         return NERR_UserNotFound;
132
133     /* Delete the user here */
134     return status;
135 }
136
137 /************************************************************
138  *                NetUserGetInfo  (NETAPI32.@)
139  */
140 NET_API_STATUS WINAPI
141 NetUserGetInfo(LPCWSTR servername, LPCWSTR username, DWORD level,
142                LPBYTE* bufptr)
143 {
144     NET_API_STATUS status;
145     TRACE("(%s, %s, %ld, %p)\n", debugstr_w(servername), debugstr_w(username),
146           level, bufptr);
147     status = NETAPI_ValidateServername(servername);
148     if (status != NERR_Success)
149         return status;
150     NETAPI_ForceLocalComputer(servername, NERR_InvalidComputer);
151     NETAPI_ForceKnownUser(username, NERR_UserNotFound);
152
153     switch (level)
154     {
155     case 0:
156     {
157         PUSER_INFO_0 ui;
158         int name_sz;
159
160         name_sz = lstrlenW(username) + 1;
161
162         /* set up buffer */
163         NetApiBufferAllocate(sizeof(USER_INFO_0) + name_sz * sizeof(WCHAR),
164                              (LPVOID *) bufptr);
165
166         ui = (PUSER_INFO_0) *bufptr;
167         ui->usri0_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_0));
168
169         /* get data */
170         lstrcpyW(ui->usri0_name, username);
171         break;
172     }
173
174     case 10:
175     {
176         PUSER_INFO_10 ui;
177         PUSER_INFO_0 ui0;
178         NET_API_STATUS status;
179         /* sizes of the field buffers in WCHARS */
180         int name_sz, comment_sz, usr_comment_sz, full_name_sz;
181
182         comment_sz = 1;
183         usr_comment_sz = 1;
184         full_name_sz = 1;
185
186         /* get data */
187         status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0);
188         if (status != NERR_Success)
189         {
190             NetApiBufferFree(ui0);
191             return status;
192         }
193         name_sz = lstrlenW(ui0->usri0_name) + 1;
194
195         /* set up buffer */
196         NetApiBufferAllocate(sizeof(USER_INFO_10) +
197                              (name_sz + comment_sz + usr_comment_sz +
198                               full_name_sz) * sizeof(WCHAR),
199                              (LPVOID *) bufptr);
200         ui = (PUSER_INFO_10) *bufptr;
201         ui->usri10_name = (LPWSTR) (*bufptr + sizeof(USER_INFO_10));
202         ui->usri10_comment = (LPWSTR) (
203             ((PBYTE) ui->usri10_name) + name_sz * sizeof(WCHAR));
204         ui->usri10_usr_comment = (LPWSTR) (
205             ((PBYTE) ui->usri10_comment) + comment_sz * sizeof(WCHAR));
206         ui->usri10_full_name = (LPWSTR) (
207             ((PBYTE) ui->usri10_usr_comment) + usr_comment_sz * sizeof(WCHAR));
208
209         /* set data */
210         lstrcpyW(ui->usri10_name, ui0->usri0_name);
211         NetApiBufferFree(ui0);
212         ui->usri10_comment[0] = 0;
213         ui->usri10_usr_comment[0] = 0;
214         ui->usri10_full_name[0] = 0;
215         break;
216     }
217
218     case 1:
219       {
220         static const WCHAR homedirW[] = {'H','O','M','E',0};
221         PUSER_INFO_1 ui;
222         PUSER_INFO_0 ui0;
223         NET_API_STATUS status;
224         /* sizes of the field buffers in WCHARS */
225         int name_sz, password_sz, home_dir_sz, comment_sz, script_path_sz;
226
227         password_sz = 1; /* not filled out for security reasons for NetUserGetInfo*/
228         comment_sz = 1;
229         script_path_sz = 1;
230
231        /* get data */
232         status = NetUserGetInfo(servername, username, 0, (LPBYTE *) &ui0);
233         if (status != NERR_Success)
234         {
235             NetApiBufferFree(ui0);
236             return status;
237         }
238         name_sz = lstrlenW(ui0->usri0_name) + 1;
239         home_dir_sz = GetEnvironmentVariableW(homedirW, NULL,0);
240         /* set up buffer */
241         NetApiBufferAllocate(sizeof(USER_INFO_1) +
242                              (name_sz + password_sz + home_dir_sz +
243                               comment_sz + script_path_sz) * sizeof(WCHAR),
244                              (LPVOID *) bufptr);
245
246         ui = (PUSER_INFO_1) *bufptr;
247         ui->usri1_name = (LPWSTR) (ui + 1);
248         ui->usri1_password = ui->usri1_name + name_sz;
249         ui->usri1_home_dir = ui->usri1_password + password_sz;
250         ui->usri1_comment = ui->usri1_home_dir + home_dir_sz;
251         ui->usri1_script_path = ui->usri1_comment + comment_sz;
252         /* set data */
253         lstrcpyW(ui->usri1_name, ui0->usri0_name);
254         NetApiBufferFree(ui0);
255         ui->usri1_password[0] = 0;
256         ui->usri1_password_age = 0;
257         ui->usri1_priv = 0;
258         GetEnvironmentVariableW(homedirW, ui->usri1_home_dir,home_dir_sz);
259         ui->usri1_comment[0] = 0;
260         ui->usri1_flags = 0;
261         ui->usri1_script_path[0] = 0;
262         break;
263       }
264     case 2:
265     case 3:
266     case 4:
267     case 11:
268     case 20:
269     case 23:
270     case 1003:
271     case 1005:
272     case 1006:
273     case 1007:
274     case 1008:
275     case 1009:
276     case 1010:
277     case 1011:
278     case 1012:
279     case 1013:
280     case 1014:
281     case 1017:
282     case 1018:
283     case 1020:
284     case 1023:
285     case 1024:
286     case 1025:
287     case 1051:
288     case 1052:
289     case 1053:
290     {
291         FIXME("Level %ld is not implemented\n", level);
292         break;
293     }
294     default:
295         ERR("Invalid level %ld is specified\n", level);
296         return ERROR_INVALID_LEVEL;
297     }
298     return NERR_Success;
299 }
300
301
302
303 /************************************************************
304  *                NetUserEnum  (NETAPI32.@)
305  */
306 NET_API_STATUS WINAPI
307 NetUserEnum(LPCWSTR servername, DWORD level, DWORD filter, LPBYTE* bufptr,
308             DWORD prefmaxlen, LPDWORD entriesread, LPDWORD totalentries,
309             LPDWORD resume_handle)
310 {
311   FIXME("(%s,%ld, 0x%ld,%p,%ld,%p,%p,%p) stub!\n", debugstr_w(servername), level,
312         filter, bufptr, prefmaxlen, entriesread, totalentries, resume_handle);
313
314   return ERROR_ACCESS_DENIED;
315 }
316
317 /************************************************************
318  *                ACCESS_QueryAdminDisplayInformation
319  *
320  *  Creates a buffer with information for the Admin User
321  */
322 static void ACCESS_QueryAdminDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize)
323 {
324     static const WCHAR sAdminUserName[] = {
325         'A','d','m','i','n','i','s','t','r','a','t','o','r',0};
326
327     /* sizes of the field buffers in WCHARS */
328     int name_sz, comment_sz, full_name_sz;
329     PNET_DISPLAY_USER usr;
330
331     /* set up buffer */
332     name_sz = lstrlenW(sAdminUserName);
333     comment_sz = 1;
334     full_name_sz = 1;
335     
336     *pdwSize = sizeof(NET_DISPLAY_USER);
337     *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
338     NetApiBufferAllocate(*pdwSize, (LPVOID *) buf);
339
340     usr = *buf;
341     usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER));
342     usr->usri1_comment = (LPWSTR) (
343         ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR));
344     usr->usri1_full_name = (LPWSTR) (
345         ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR));
346
347     /* set data */
348     lstrcpyW(usr->usri1_name, sAdminUserName);
349     usr->usri1_comment[0] = 0;
350     usr->usri1_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
351     usr->usri1_full_name[0] = 0;
352     usr->usri1_user_id = 500;
353     usr->usri1_next_index = 0;
354 }
355
356 /************************************************************
357  *                ACCESS_QueryGuestDisplayInformation
358  *
359  *  Creates a buffer with information for the Guest User
360  */
361 static void ACCESS_QueryGuestDisplayInformation(PNET_DISPLAY_USER *buf, PDWORD pdwSize)
362 {
363     static const WCHAR sGuestUserName[] = {
364         'G','u','e','s','t',0 };
365
366     /* sizes of the field buffers in WCHARS */
367     int name_sz, comment_sz, full_name_sz;
368     PNET_DISPLAY_USER usr;
369
370     /* set up buffer */
371     name_sz = lstrlenW(sGuestUserName);
372     comment_sz = 1;
373     full_name_sz = 1;
374     
375     *pdwSize = sizeof(NET_DISPLAY_USER);
376     *pdwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
377     NetApiBufferAllocate(*pdwSize, (LPVOID *) buf);
378
379     usr = *buf;
380     usr->usri1_name = (LPWSTR) ((PBYTE) usr + sizeof(NET_DISPLAY_USER));
381     usr->usri1_comment = (LPWSTR) (
382         ((PBYTE) usr->usri1_name) + name_sz * sizeof(WCHAR));
383     usr->usri1_full_name = (LPWSTR) (
384         ((PBYTE) usr->usri1_comment) + comment_sz * sizeof(WCHAR));
385
386     /* set data */
387     lstrcpyW(usr->usri1_name, sGuestUserName);
388     usr->usri1_comment[0] = 0;
389     usr->usri1_flags = UF_ACCOUNTDISABLE | UF_SCRIPT | UF_NORMAL_ACCOUNT |
390         UF_DONT_EXPIRE_PASSWD;
391     usr->usri1_full_name[0] = 0;
392     usr->usri1_user_id = 500;
393     usr->usri1_next_index = 0;
394 }
395
396 /************************************************************
397  *                NetQueryDisplayInformation  (NETAPI32.@)
398  * Copies NET_DISPLAY_USER record.
399  */
400 static void ACCESS_CopyDisplayUser(PNET_DISPLAY_USER dest, LPWSTR *dest_buf,
401                             PNET_DISPLAY_USER src)
402 {
403     LPWSTR str = *dest_buf;
404
405     src->usri1_name = str;
406     lstrcpyW(src->usri1_name, dest->usri1_name);
407     str = (LPWSTR) (
408         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
409
410     src->usri1_comment = str;
411     lstrcpyW(src->usri1_comment, dest->usri1_comment);
412     str = (LPWSTR) (
413         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
414
415     src->usri1_flags = dest->usri1_flags;
416
417     src->usri1_full_name = str;
418     lstrcpyW(src->usri1_full_name, dest->usri1_full_name);
419     str = (LPWSTR) (
420         ((PBYTE) str) + (lstrlenW(str) + 1) * sizeof(WCHAR));
421
422     src->usri1_user_id = dest->usri1_user_id;
423     src->usri1_next_index = dest->usri1_next_index;
424     *dest_buf = str;
425 }
426
427 /************************************************************
428  *                NetQueryDisplayInformation  (NETAPI32.@)
429  *
430  * The buffer structure:
431  * - array of fixed size record of the level type
432  * - strings, referenced by the record of the level type
433  */
434 NET_API_STATUS WINAPI
435 NetQueryDisplayInformation(
436     LPCWSTR ServerName, DWORD Level, DWORD Index, DWORD EntriesRequested,
437     DWORD PreferredMaximumLength, LPDWORD ReturnedEntryCount,
438     PVOID *SortedBuffer)
439 {
440     TRACE("(%s, %ld, %ld, %ld, %ld, %p, %p)\n", debugstr_w(ServerName),
441           Level, Index, EntriesRequested, PreferredMaximumLength,
442           ReturnedEntryCount, SortedBuffer);
443     NETAPI_ForceLocalComputer(ServerName, ERROR_ACCESS_DENIED);
444     switch (Level)
445     {
446     case 1:
447     {
448         /* current record */
449         PNET_DISPLAY_USER inf;
450         /* current available strings buffer */
451         LPWSTR str;
452         PNET_DISPLAY_USER admin, guest;
453         DWORD admin_size, guest_size;
454         LPWSTR name = NULL;
455         DWORD dwSize;
456
457         /* sizes of the field buffers in WCHARS */
458         int name_sz, comment_sz, full_name_sz;
459
460         /* number of the records, returned in SortedBuffer
461            3 - for current user, Administrator and Guest users
462          */
463         int records = 3;
464
465         FIXME("Level %ld partially implemented\n", Level);
466         *ReturnedEntryCount = records;
467         comment_sz = 1;
468         full_name_sz = 1;
469
470         /* get data */
471         dwSize = UNLEN + 1;
472         NetApiBufferAllocate(dwSize, (LPVOID *) &name);
473         if (!GetUserNameW(name, &dwSize))
474         {
475             NetApiBufferFree(name);
476             return ERROR_ACCESS_DENIED;
477         }
478         name_sz = dwSize;
479         ACCESS_QueryAdminDisplayInformation(&admin, &admin_size);
480         ACCESS_QueryGuestDisplayInformation(&guest, &guest_size);
481
482         /* set up buffer */
483         dwSize = sizeof(NET_DISPLAY_USER) * records;
484         dwSize += (name_sz + comment_sz + full_name_sz) * sizeof(WCHAR);
485
486         NetApiBufferAllocate(dwSize +
487                              admin_size - sizeof(NET_DISPLAY_USER) +
488                              guest_size - sizeof(NET_DISPLAY_USER),
489                              (LPVOID *) SortedBuffer);
490         inf = (PNET_DISPLAY_USER) *SortedBuffer;
491         str = (LPWSTR) ((PBYTE) inf + sizeof(NET_DISPLAY_USER) * records);
492         inf->usri1_name = str;
493         str = (LPWSTR) (
494             ((PBYTE) str) + name_sz * sizeof(WCHAR));
495         inf->usri1_comment = str;
496         str = (LPWSTR) (
497             ((PBYTE) str) + comment_sz * sizeof(WCHAR));
498         inf->usri1_full_name = str;
499         str = (LPWSTR) (
500             ((PBYTE) str) + full_name_sz * sizeof(WCHAR));
501
502         /* set data */
503         lstrcpyW(inf->usri1_name, name);
504         NetApiBufferFree(name);
505         inf->usri1_comment[0] = 0;
506         inf->usri1_flags =
507             UF_SCRIPT | UF_NORMAL_ACCOUNT | UF_DONT_EXPIRE_PASSWD;
508         inf->usri1_full_name[0] = 0;
509         inf->usri1_user_id = 0;
510         inf->usri1_next_index = 0;
511
512         inf++;
513         ACCESS_CopyDisplayUser(admin, &str, inf);
514         NetApiBufferFree(admin);
515
516         inf++;
517         ACCESS_CopyDisplayUser(guest, &str, inf);
518         NetApiBufferFree(guest);
519         break;
520     }
521
522     case 2:
523     case 3:
524     {
525         FIXME("Level %ld is not implemented\n", Level);
526         break;
527     }
528
529     default:
530         ERR("Invalid level %ld is specified\n", Level);
531         return ERROR_INVALID_LEVEL;
532     }
533     return NERR_Success;
534 }
535
536 /************************************************************
537  *                NetGetDCName  (NETAPI32.@)
538  *
539  *  Return the name of the primary domain controller (PDC)
540  */
541
542 NET_API_STATUS WINAPI
543 NetGetDCName(LPCWSTR servername, LPCWSTR domainname, LPBYTE *bufptr)
544 {
545   FIXME("(%s, %s, %p) stub!\n", debugstr_w(servername),
546                  debugstr_w(domainname), bufptr);
547   return NERR_DCNotFound; /* say we can't find a domain controller */  
548 }
549
550
551 /************************************************************
552  *                NetUserModalsGet  (NETAPI32.@)
553  */
554 NET_API_STATUS WINAPI NetUserModalsGet(LPCWSTR szServer, DWORD level, LPBYTE *pbuffer)
555 {
556     FIXME("(%s %ld %p) stub!\n", debugstr_w(szServer), level, pbuffer);
557
558     if (level == 2)
559     {
560         *pbuffer = NULL;
561         return NERR_Success;
562     }
563     return NERR_InternalError;
564 }
565
566 /************************************************************
567  *                NetLocalGroupAdd  (NETAPI32.@)
568  */
569 NET_API_STATUS WINAPI NetLocalGroupAdd(LPCWSTR servername, DWORD level,
570                  LPBYTE buf, LPDWORD parm_err)
571 {
572     FIXME("(%s %ld %p %p) stub!\n", debugstr_w(servername), level, buf, parm_err);
573     return NERR_Success;
574 }
575
576 /************************************************************
577  *                NetLocalGroupSetMember (NETAPI32.@)
578  */
579
580 NET_API_STATUS WINAPI NetLocalGroupSetMembers(LPCWSTR servername,
581              LPCWSTR groupname, DWORD level, LPBYTE buf, DWORD totalentries)
582 {
583     FIXME("(%s %s %ld %p %ld) stub!\n", debugstr_w(servername), 
584             debugstr_w(groupname),level, buf, totalentries);
585     return NERR_Success;
586 }