xref: /reactos/base/services/wkssvc/rpcserver.c (revision cc3672cb)
1 /*
2  *  ReactOS Services
3  *  Copyright (C) 2015 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:        See COPYING in the top level directory
21  * PROJECT:          ReactOS Services
22  * FILE:             base/services/wkssvc/rpcserver.c
23  * PURPOSE:          Workstation service
24  * PROGRAMMER:       Eric Kohl
25  */
26 
27 /* INCLUDES *****************************************************************/
28 
29 #include "precomp.h"
30 
31 #include "lmerr.h"
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(wkssvc);
34 
35 /* FUNCTIONS *****************************************************************/
36 
37 DWORD
38 WINAPI
39 RpcThreadRoutine(
40     LPVOID lpParameter)
41 {
42     RPC_STATUS Status;
43 
44     Status = RpcServerUseProtseqEpW(L"ncacn_np", 20, L"\\pipe\\wkssvc", NULL);
45     if (Status != RPC_S_OK)
46     {
47         ERR("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
48         return 0;
49     }
50 
51     Status = RpcServerRegisterIf(wkssvc_v1_0_s_ifspec, NULL, NULL);
52     if (Status != RPC_S_OK)
53     {
54         ERR("RpcServerRegisterIf() failed (Status %lx)\n", Status);
55         return 0;
56     }
57 
58     Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
59     if (Status != RPC_S_OK)
60     {
61         ERR("RpcServerListen() failed (Status %lx)\n", Status);
62     }
63 
64     return 0;
65 }
66 
67 
68 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
69 {
70     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
71 }
72 
73 
74 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
75 {
76     HeapFree(GetProcessHeap(), 0, ptr);
77 }
78 
79 
80 /* Function 0 */
81 unsigned long
82 __stdcall
83 NetrWkstaGetInfo(
84     WKSSVC_IDENTIFY_HANDLE ServerName,
85     unsigned long Level,
86     LPWKSTA_INFO *WkstaInfo)
87 {
88     WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
89     DWORD dwComputerNameLength;
90     LPCWSTR pszLanRoot = L"";
91     PWKSTA_INFO pWkstaInfo = NULL;
92     LSA_OBJECT_ATTRIBUTES ObjectAttributes;
93     LSA_HANDLE PolicyHandle;
94     PPOLICY_PRIMARY_DOMAIN_INFO DomainInfo = NULL;
95     NTSTATUS NtStatus;
96     DWORD dwResult = NERR_Success;
97 
98     TRACE("NetrWkstaGetInfo level %lu\n", Level);
99 
100     dwComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
101     GetComputerNameW(szComputerName, &dwComputerNameLength);
102     dwComputerNameLength++; /* include NULL terminator */
103 
104     ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
105     NtStatus = LsaOpenPolicy(NULL,
106                              &ObjectAttributes,
107                              POLICY_VIEW_LOCAL_INFORMATION,
108                              &PolicyHandle);
109     if (NtStatus != STATUS_SUCCESS)
110     {
111         WARN("LsaOpenPolicy() failed (Status 0x%08lx)\n", NtStatus);
112         return LsaNtStatusToWinError(NtStatus);
113     }
114 
115     NtStatus = LsaQueryInformationPolicy(PolicyHandle,
116                                          PolicyPrimaryDomainInformation,
117                                          (PVOID*)&DomainInfo);
118 
119     LsaClose(PolicyHandle);
120 
121     if (NtStatus != STATUS_SUCCESS)
122     {
123         WARN("LsaQueryInformationPolicy() failed (Status 0x%08lx)\n", NtStatus);
124         return LsaNtStatusToWinError(NtStatus);
125     }
126 
127     switch (Level)
128     {
129         case 100:
130             pWkstaInfo = midl_user_allocate(sizeof(WKSTA_INFO_100));
131             if (pWkstaInfo == NULL)
132             {
133                 dwResult = ERROR_NOT_ENOUGH_MEMORY;
134                 break;
135             }
136 
137             pWkstaInfo->WkstaInfo100.wki100_platform_id = PLATFORM_ID_NT;
138 
139             pWkstaInfo->WkstaInfo100.wki100_computername = midl_user_allocate(dwComputerNameLength * sizeof(WCHAR));
140             if (pWkstaInfo->WkstaInfo100.wki100_computername != NULL)
141                 wcscpy(pWkstaInfo->WkstaInfo100.wki100_computername, szComputerName);
142 
143             pWkstaInfo->WkstaInfo100.wki100_langroup = midl_user_allocate((wcslen(DomainInfo->Name.Buffer) + 1) * sizeof(WCHAR));
144             if (pWkstaInfo->WkstaInfo100.wki100_langroup != NULL)
145                 wcscpy(pWkstaInfo->WkstaInfo100.wki100_langroup, DomainInfo->Name.Buffer);
146 
147             pWkstaInfo->WkstaInfo100.wki100_ver_major = VersionInfo.dwMajorVersion;
148             pWkstaInfo->WkstaInfo100.wki100_ver_minor = VersionInfo.dwMinorVersion;
149 
150             *WkstaInfo = pWkstaInfo;
151             break;
152 
153         case 101:
154             pWkstaInfo = midl_user_allocate(sizeof(WKSTA_INFO_101));
155             if (pWkstaInfo == NULL)
156             {
157                 dwResult = ERROR_NOT_ENOUGH_MEMORY;
158                 break;
159             }
160 
161             pWkstaInfo->WkstaInfo101.wki101_platform_id = PLATFORM_ID_NT;
162 
163             pWkstaInfo->WkstaInfo101.wki101_computername = midl_user_allocate(dwComputerNameLength * sizeof(WCHAR));
164             if (pWkstaInfo->WkstaInfo101.wki101_computername != NULL)
165                 wcscpy(pWkstaInfo->WkstaInfo101.wki101_computername, szComputerName);
166 
167             pWkstaInfo->WkstaInfo101.wki101_langroup = midl_user_allocate((wcslen(DomainInfo->Name.Buffer) + 1) * sizeof(WCHAR));
168             if (pWkstaInfo->WkstaInfo101.wki101_langroup != NULL)
169                 wcscpy(pWkstaInfo->WkstaInfo101.wki101_langroup, DomainInfo->Name.Buffer);
170 
171             pWkstaInfo->WkstaInfo101.wki101_ver_major = VersionInfo.dwMajorVersion;
172             pWkstaInfo->WkstaInfo101.wki101_ver_minor = VersionInfo.dwMinorVersion;
173 
174             pWkstaInfo->WkstaInfo101.wki101_lanroot = midl_user_allocate((wcslen(pszLanRoot) + 1) * sizeof(WCHAR));
175             if (pWkstaInfo->WkstaInfo101.wki101_lanroot != NULL)
176                 wcscpy(pWkstaInfo->WkstaInfo101.wki101_lanroot, pszLanRoot);
177 
178             *WkstaInfo = pWkstaInfo;
179             break;
180 
181         case 102:
182             pWkstaInfo = midl_user_allocate(sizeof(WKSTA_INFO_102));
183             if (pWkstaInfo == NULL)
184             {
185                 dwResult = ERROR_NOT_ENOUGH_MEMORY;
186                 break;
187             }
188 
189             pWkstaInfo->WkstaInfo102.wki102_platform_id = PLATFORM_ID_NT;
190 
191             pWkstaInfo->WkstaInfo102.wki102_computername = midl_user_allocate(dwComputerNameLength * sizeof(WCHAR));
192             if (pWkstaInfo->WkstaInfo102.wki102_computername != NULL)
193                 wcscpy(pWkstaInfo->WkstaInfo102.wki102_computername, szComputerName);
194 
195             pWkstaInfo->WkstaInfo102.wki102_langroup = midl_user_allocate((wcslen(DomainInfo->Name.Buffer) + 1) * sizeof(WCHAR));
196             if (pWkstaInfo->WkstaInfo102.wki102_langroup != NULL)
197                 wcscpy(pWkstaInfo->WkstaInfo102.wki102_langroup, DomainInfo->Name.Buffer);
198 
199             pWkstaInfo->WkstaInfo102.wki102_ver_major = VersionInfo.dwMajorVersion;
200             pWkstaInfo->WkstaInfo102.wki102_ver_minor = VersionInfo.dwMinorVersion;
201 
202             pWkstaInfo->WkstaInfo102.wki102_lanroot = midl_user_allocate((wcslen(pszLanRoot) + 1) * sizeof(WCHAR));
203             if (pWkstaInfo->WkstaInfo102.wki102_lanroot != NULL)
204                 wcscpy(pWkstaInfo->WkstaInfo102.wki102_lanroot, pszLanRoot);
205 
206             pWkstaInfo->WkstaInfo102.wki102_logged_on_users = 1; /* FIXME */
207 
208             *WkstaInfo = pWkstaInfo;
209             break;
210 
211         case 502:
212             pWkstaInfo = midl_user_allocate(sizeof(WKSTA_INFO_502));
213             if (pWkstaInfo == NULL)
214             {
215                 dwResult = ERROR_NOT_ENOUGH_MEMORY;
216                 break;
217             }
218 
219             CopyMemory(&pWkstaInfo->WkstaInfo502, &WkstaInfo502, sizeof(WKSTA_INFO_502));
220 
221             *WkstaInfo = pWkstaInfo;
222             break;
223 
224         default:
225             FIXME("Level %lu unimplemented\n", Level);
226             dwResult = ERROR_INVALID_LEVEL;
227             break;
228     }
229 
230     if (DomainInfo != NULL)
231         LsaFreeMemory(DomainInfo);
232 
233     return dwResult;
234 }
235 
236 
237 /* Function 1 */
238 unsigned long
239 __stdcall
240 NetrWkstaSetInfo(
241     WKSSVC_IDENTIFY_HANDLE ServerName,
242     unsigned long Level,
243     LPWKSTA_INFO WkstaInfo,
244     unsigned long *ErrorParameter)
245 {
246     DWORD dwErrParam = 0;
247     DWORD dwResult = NERR_Success;
248 
249     TRACE("NetrWkstaSetInfo(%lu %p %p)\n",
250           Level, WkstaInfo, ErrorParameter);
251 
252     switch (Level)
253     {
254         case 502:
255             if (WkstaInfo->WkstaInfo502.wki502_keep_conn >= 1 && WkstaInfo->WkstaInfo502.wki502_keep_conn <= 65535)
256             {
257                 WkstaInfo502.wki502_keep_conn = WkstaInfo->WkstaInfo502.wki502_keep_conn;
258             }
259             else
260             {
261                 dwErrParam = WKSTA_KEEPCONN_PARMNUM;
262                 dwResult = ERROR_INVALID_PARAMETER;
263             }
264 
265             if (dwResult == NERR_Success)
266             {
267                 if (WkstaInfo->WkstaInfo502.wki502_max_cmds >= 50 && WkstaInfo->WkstaInfo502.wki502_max_cmds <= 65535)
268                 {
269                     WkstaInfo502.wki502_max_cmds = WkstaInfo->WkstaInfo502.wki502_max_cmds;
270                 }
271                 else
272                 {
273                     dwErrParam = WKSTA_MAXCMDS_PARMNUM;
274                     dwResult = ERROR_INVALID_PARAMETER;
275                 }
276             }
277 
278             if (dwResult == NERR_Success)
279             {
280                 if (WkstaInfo->WkstaInfo502.wki502_sess_timeout >= 60 && WkstaInfo->WkstaInfo502.wki502_sess_timeout <= 65535)
281                 {
282                     WkstaInfo502.wki502_sess_timeout = WkstaInfo->WkstaInfo502.wki502_sess_timeout;
283                 }
284                 else
285                 {
286                     dwErrParam = WKSTA_SESSTIMEOUT_PARMNUM;
287                     dwResult = ERROR_INVALID_PARAMETER;
288                 }
289             }
290 
291             if (dwResult == NERR_Success)
292             {
293                 if (WkstaInfo->WkstaInfo502.wki502_dormant_file_limit != 0)
294                 {
295                     WkstaInfo502.wki502_dormant_file_limit = WkstaInfo->WkstaInfo502.wki502_dormant_file_limit;
296                 }
297                 else
298                 {
299                     dwErrParam = WKSTA_DORMANTFILELIMIT_PARMNUM;
300                     dwResult = ERROR_INVALID_PARAMETER;
301                 }
302             }
303             break;
304 
305         case 1013:
306             if (WkstaInfo->WkstaInfo1013.wki1013_keep_conn >= 1 && WkstaInfo->WkstaInfo1013.wki1013_keep_conn <= 65535)
307             {
308                 WkstaInfo502.wki502_keep_conn = WkstaInfo->WkstaInfo1013.wki1013_keep_conn;
309             }
310             else
311             {
312                 dwErrParam = WKSTA_KEEPCONN_PARMNUM;
313                 dwResult = ERROR_INVALID_PARAMETER;
314             }
315             break;
316 
317         case 1018:
318             if (WkstaInfo->WkstaInfo1018.wki1018_sess_timeout >= 60 && WkstaInfo->WkstaInfo1018.wki1018_sess_timeout <= 65535)
319             {
320                 WkstaInfo502.wki502_sess_timeout = WkstaInfo->WkstaInfo1018.wki1018_sess_timeout;
321             }
322             else
323             {
324                 dwErrParam = WKSTA_SESSTIMEOUT_PARMNUM;
325                 dwResult = ERROR_INVALID_PARAMETER;
326             }
327             break;
328 
329         case 1046:
330             if (WkstaInfo->WkstaInfo1046.wki1046_dormant_file_limit != 0)
331             {
332                 WkstaInfo502.wki502_dormant_file_limit = WkstaInfo->WkstaInfo1046.wki1046_dormant_file_limit;
333             }
334             else
335             {
336                 dwErrParam = WKSTA_DORMANTFILELIMIT_PARMNUM;
337                 dwResult = ERROR_INVALID_PARAMETER;
338             }
339             break;
340 
341         default:
342             ERR("Invalid Level %lu\n", Level);
343             dwResult = ERROR_INVALID_LEVEL;
344             break;
345     }
346 
347     /* Save the workstation in the registry */
348     if (dwResult == NERR_Success)
349     {
350         SaveWorkstationInfo(Level);
351 
352         /* FIXME: Notify the redirector */
353     }
354 
355     if ((dwResult == ERROR_INVALID_PARAMETER) && (ErrorParameter != NULL))
356         *ErrorParameter = dwErrParam;
357 
358     return dwResult;
359 }
360 
361 
362 /* Function 2 */
363 unsigned long
364 __stdcall
365 NetrWkstaUserEnum(
366     WKSSVC_IDENTIFY_HANDLE ServerName,
367     LPWKSTA_USER_ENUM_STRUCT UserInfo,
368     unsigned long PreferredMaximumLength,
369     unsigned long *TotalEntries,
370     unsigned long *ResumeHandle)
371 {
372     ERR("NetrWkstaUserEnum(%p %p 0x%lx %p %p)\n",
373         ServerName, UserInfo, PreferredMaximumLength, TotalEntries, ResumeHandle);
374 
375 
376     UNIMPLEMENTED;
377     return 0;
378 }
379 
380 
381 /* Function 3 */
382 unsigned long
383 __stdcall
384 NetrWkstaUserGetInfo(
385     WKSSVC_IDENTIFY_HANDLE Unused,
386     unsigned long Level,
387     LPWKSTA_USER_INFO UserInfo)
388 {
389     FIXME("(%s, %d, %p)\n", debugstr_w(Unused), Level, UserInfo);
390 
391     UNIMPLEMENTED;
392     return 0;
393 }
394 
395 
396 /* Function 4 */
397 unsigned long
398 __stdcall
399 NetrWkstaUserSetInfo (
400     WKSSVC_IDENTIFY_HANDLE Unused,
401     unsigned long Level,
402     LPWKSTA_USER_INFO UserInfo,
403     unsigned long *ErrorParameter)
404 {
405     UNIMPLEMENTED;
406     return 0;
407 }
408 
409 
410 /* Function 5 */
411 unsigned long
412 __stdcall
413 NetrWkstaTransportEnum(
414     WKSSVC_IDENTIFY_HANDLE ServerName,
415     LPWKSTA_TRANSPORT_ENUM_STRUCT TransportInfo,
416     unsigned long PreferredMaximumLength,
417     unsigned long* TotalEntries,
418     unsigned long *ResumeHandle)
419 {
420     UNIMPLEMENTED;
421     return 0;
422 }
423 
424 
425 /* Function 6 */
426 unsigned long
427 __stdcall
428 NetrWkstaTransportAdd(
429     WKSSVC_IDENTIFY_HANDLE ServerName,
430     unsigned long Level,
431     LPWKSTA_TRANSPORT_INFO_0 TransportInfo,
432     unsigned long *ErrorParameter)
433 {
434     UNIMPLEMENTED;
435     return 0;
436 }
437 
438 
439 /* Function 7 */
440 unsigned long
441 __stdcall
442 NetrWkstaTransportDel(
443     WKSSVC_IDENTIFY_HANDLE ServerName,
444     wchar_t *TransportName,
445     unsigned long ForceLevel)
446 {
447     UNIMPLEMENTED;
448     return 0;
449 }
450 
451 
452 /* Function 8 */
453 unsigned long
454 __stdcall
455 NetrUseAdd(
456     WKSSVC_IMPERSONATE_HANDLE ServerName,
457     unsigned long Level,
458     LPUSE_INFO InfoStruct,
459     unsigned long *ErrorParameter)
460 {
461     UNIMPLEMENTED;
462     return 0;
463 }
464 
465 
466 /* Function 9 */
467 unsigned long
468 __stdcall
469 NetrUseGetInfo(
470     WKSSVC_IMPERSONATE_HANDLE ServerName,
471     wchar_t *UseName,
472     unsigned long Level,
473     LPUSE_INFO InfoStruct)
474 {
475     UNIMPLEMENTED;
476     return 0;
477 }
478 
479 
480 /* Function 10 */
481 unsigned long
482 __stdcall
483 NetrUseDel(
484     WKSSVC_IMPERSONATE_HANDLE ServerName,
485     wchar_t *UseName,
486     unsigned long ForceLevel)
487 {
488     UNIMPLEMENTED;
489     return 0;
490 }
491 
492 
493 /* Function 11 */
494 unsigned long
495 __stdcall
496 NetrUseEnum(
497     WKSSVC_IDENTIFY_HANDLE ServerName,
498     LPUSE_ENUM_STRUCT InfoStruct,
499     unsigned long PreferredMaximumLength,
500     unsigned long *TotalEntries,
501     unsigned long *ResumeHandle)
502 {
503     UNIMPLEMENTED;
504     return 0;
505 }
506 
507 
508 /* Function 12 - Not used on wire */
509 unsigned long
510 __stdcall
511 NetrMessageBufferSend(void)
512 {
513     TRACE("NetrMessageBufferSend()\n");
514     return ERROR_NOT_SUPPORTED;
515 }
516 
517 
518 /* Function 13 */
519 unsigned long
520 __stdcall
521 NetrWorkstationStatisticsGet(
522     WKSSVC_IDENTIFY_HANDLE ServerName,
523     wchar_t *ServiceName,
524     unsigned long Level,
525     unsigned long Options,
526     LPSTAT_WORKSTATION_0 *Buffer)
527 {
528     PSTAT_WORKSTATION_0 pStatBuffer;
529 
530     TRACE("NetrWorkstationStatisticsGet(%p %p %lu 0x%lx %p)\n",
531           ServerName, ServiceName, Level, Options, Buffer);
532 
533     if (Level != 0)
534         return ERROR_INVALID_LEVEL;
535 
536     if (Options != 0)
537         return ERROR_INVALID_PARAMETER;
538 
539     pStatBuffer = midl_user_allocate(sizeof(STAT_WORKSTATION_0));
540     if (pStatBuffer == NULL)
541         return ERROR_NOT_ENOUGH_MEMORY;
542 
543     ZeroMemory(pStatBuffer, sizeof(STAT_WORKSTATION_0));
544 
545     // FIXME: Return the actual statistcs data!
546 
547     *Buffer = pStatBuffer;
548 
549     return NERR_Success;
550 }
551 
552 
553 /* Function 14 - Not used on wire */
554 unsigned long
555 __stdcall
556 NetrLogonDomainNameAdd(
557     WKSSVC_IDENTIFY_HANDLE DomainName)
558 {
559     TRACE("NetrLogonDomainNameAdd(%s)\n",
560           debugstr_w(DomainName));
561     return ERROR_NOT_SUPPORTED;
562 }
563 
564 
565 /* Function 15 - Not used on wire */
566 unsigned long
567 __stdcall
568 NetrLogonDomainNameDel(
569     WKSSVC_IDENTIFY_HANDLE DomainName)
570 {
571     TRACE("NetrLogonDomainNameDel(%s)\n",
572           debugstr_w(DomainName));
573     return ERROR_NOT_SUPPORTED;
574 }
575 
576 
577 /* Function 16 - Not used on wire */
578 unsigned long
579 __stdcall
580 NetrJoinDomain(void)
581 {
582     TRACE("NetrJoinDomain()\n");
583     return ERROR_NOT_SUPPORTED;
584 }
585 
586 
587 /* Function 17 - Not used on wire */
588 unsigned long
589 __stdcall
590 NetrUnjoinDomain(void)
591 {
592     TRACE("NetrUnjoinDomain()\n");
593     return ERROR_NOT_SUPPORTED;
594 }
595 
596 
597 /* Function 18 - Not used on wire */
598 unsigned long
599 __stdcall
600 NetrValidateName(void)
601 {
602     TRACE("NetrValidateName()\n");
603     return ERROR_NOT_SUPPORTED;
604 }
605 
606 
607 /* Function 19 - Not used on wire */
608 unsigned long
609 __stdcall
610 NetrRenameMachineInDomain(void)
611 {
612     TRACE("NetrRenameMachineInDomain()\n");
613     return ERROR_NOT_SUPPORTED;
614 }
615 
616 
617 /* Function 20 */
618 unsigned long
619 __stdcall
620 NetrGetJoinInformation(
621     WKSSVC_IMPERSONATE_HANDLE ServerName,
622     wchar_t **NameBuffer,
623     PNETSETUP_JOIN_STATUS BufferType)
624 {
625     TRACE("NetrGetJoinInformation(%p %p %p)\n",
626           ServerName, NameBuffer, BufferType);
627 
628     if (NameBuffer == NULL)
629         return ERROR_INVALID_PARAMETER;
630 
631     return NetpGetJoinInformation(NameBuffer,
632                                   BufferType);
633 }
634 
635 
636 /* Function 21 - Not used on wire */
637 unsigned long
638 __stdcall
639 NetrGetJoinableOUs(void)
640 {
641     TRACE("NetrGetJoinableOUs()\n");
642     return ERROR_NOT_SUPPORTED;
643 }
644 
645 
646 /* Function 22 */
647 unsigned long
648 __stdcall
649 NetrJoinDomain2(
650     handle_t RpcBindingHandle,
651     wchar_t *ServerName,
652     wchar_t *DomainNameParam,
653     wchar_t *MachineAccountOU,
654     wchar_t *AccountName,
655     PJOINPR_ENCRYPTED_USER_PASSWORD Password,
656     unsigned long Options)
657 {
658     NET_API_STATUS status;
659 
660     FIXME("NetrJoinDomain2(%p %S %S %S %S %p 0x%lx)\n",
661           RpcBindingHandle, ServerName, DomainNameParam, MachineAccountOU,
662           AccountName, Password, Options);
663 
664     if (DomainNameParam == NULL)
665         return ERROR_INVALID_PARAMETER;
666 
667     if (Options & NETSETUP_JOIN_DOMAIN)
668     {
669         FIXME("NetrJoinDomain2: NETSETUP_JOIN_DOMAIN is not supported yet!\n");
670         status = ERROR_CALL_NOT_IMPLEMENTED;
671     }
672     else
673     {
674         status = NetpJoinWorkgroup(DomainNameParam);
675     }
676 
677     return status;
678 }
679 
680 
681 /* Function 23 */
682 unsigned long
683 __stdcall
684 NetrUnjoinDomain2(
685     handle_t RpcBindingHandle,
686     wchar_t *ServerName,
687     wchar_t *AccountName,
688     PJOINPR_ENCRYPTED_USER_PASSWORD Password,
689     unsigned long Options)
690 {
691     UNIMPLEMENTED;
692     return 0;
693 }
694 
695 
696 /* Function 24 */
697 unsigned long
698 __stdcall
699 NetrRenameMachineInDomain2(
700     handle_t RpcBindingHandle,
701     wchar_t *ServerName,
702     wchar_t *MachineName,
703     wchar_t *AccountName,
704     PJOINPR_ENCRYPTED_USER_PASSWORD Password,
705     unsigned long Options)
706 {
707     UNIMPLEMENTED;
708     return 0;
709 }
710 
711 
712 /* Function 25 */
713 unsigned long
714 __stdcall
715 NetrValidateName2(
716     handle_t RpcBindingHandle,
717     wchar_t *ServerName,
718     wchar_t *NameToValidate,
719     wchar_t *AccountName,
720     PJOINPR_ENCRYPTED_USER_PASSWORD Password,
721     NETSETUP_NAME_TYPE NameType)
722 {
723     UNIMPLEMENTED;
724     return 0;
725 }
726 
727 
728 /* Function 26 */
729 unsigned long
730 __stdcall
731 NetrGetJoinableOUs2(
732     handle_t RpcBindingHandle,
733     wchar_t *ServerName,
734     wchar_t *DomainNameParam,
735     wchar_t *AccountName,
736     PJOINPR_ENCRYPTED_USER_PASSWORD Password,
737     unsigned long* OUCount,
738     wchar_t ***OUs)
739 {
740     UNIMPLEMENTED;
741     return 0;
742 }
743 
744 
745 /* Function 27 */
746 unsigned long
747 __stdcall
748 NetrAddAlternateComputerName(
749     handle_t RpcBindingHandle,
750     wchar_t *ServerName,
751     wchar_t *AlternateName,
752     wchar_t *DomainAccount,
753     PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedPassword,
754     unsigned long Reserved)
755 {
756     UNIMPLEMENTED;
757     return 0;
758 }
759 
760 
761 /* Function 28 */
762 unsigned long
763 __stdcall
764 NetrRemoveAlternateComputerName(
765     handle_t RpcBindingHandle,
766     wchar_t *ServerName,
767     wchar_t *AlternateName,
768     wchar_t *DomainAccount,
769     PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedPassword,
770     unsigned long Reserved)
771 {
772     UNIMPLEMENTED;
773     return 0;
774 }
775 
776 
777 /* Function 29 */
778 unsigned long
779 __stdcall
780 NetrSetPrimaryComputerName(
781     handle_t RpcBindingHandle,
782     wchar_t *ServerName,
783     wchar_t *PrimaryName,
784     wchar_t *DomainAccount,
785     PJOINPR_ENCRYPTED_USER_PASSWORD EncryptedPassword,
786     unsigned long Reserved)
787 {
788     UNIMPLEMENTED;
789     return 0;
790 }
791 
792 
793 /* Function 30 */
794 unsigned long
795 __stdcall
796 NetrEnumerateComputerNames(
797     WKSSVC_IMPERSONATE_HANDLE ServerName,
798     NET_COMPUTER_NAME_TYPE NameType,
799     unsigned long Reserved,
800     PNET_COMPUTER_NAME_ARRAY *ComputerNames)
801 {
802     UNIMPLEMENTED;
803     return 0;
804 }
805 
806 /* EOF */
807