s3: Complete support for NetWkstaGetInfo/NetWkstaEnumUsers
[amitay/samba.git] / source3 / rpc_server / srv_wkssvc_nt.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *
5  *  Copyright (C) Andrew Tridgell               1992-1997,
6  *  Copyright (C) Gerald (Jerry) Carter         2006.
7  *  Copyright (C) Guenther Deschner             2007-2008.
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 3 of the License, or
12  *  (at your option) any later version.
13  *  
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *  
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22
23 /* This is the implementation of the wks interface. */
24
25 #include "includes.h"
26 #include "libnet/libnet.h"
27 #include "../libcli/auth/libcli_auth.h"
28 #include "../librpc/gen_ndr/srv_wkssvc.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
32
33 struct dom_usr {
34         char *name;
35         char *domain;
36         time_t login_time;
37 };
38
39 #ifdef HAVE_GETUTXENT
40
41 #include <utmpx.h>
42
43 struct usrinfo {
44         char *name;
45         struct timeval login_time;
46 };
47
48 static int usr_info_cmp(const void *p1, const void *p2)
49 {
50         const struct usrinfo *usr1 = (const struct usrinfo *)p1;
51         const struct usrinfo *usr2 = (const struct usrinfo *)p2;
52
53         /* Called from qsort to compare two users in a usrinfo_t array for
54          * sorting by login time. Return >0 if usr1 login time was later than
55          * usr2 login time, <0 if it was earlier */
56         return ((usr1->login_time.tv_sec == usr2->login_time.tv_sec)
57                 ? usr1->login_time.tv_usec - usr2->login_time.tv_usec
58                 : usr1->login_time.tv_sec - usr2->login_time.tv_sec);
59 }
60
61 /*******************************************************************
62  Get a list of the names of all users logged into this machine
63  ********************************************************************/
64
65 static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx)
66 {
67         char **users;
68         int i, num_users = 0;
69         struct usrinfo *usr_infos = NULL;
70         struct utmpx *u;
71
72         while ((u = getutxent()) != NULL) {
73                 struct usrinfo *tmp;
74                 if (u->ut_type != USER_PROCESS) {
75                         continue;
76                 }
77                 for (i = 0; i < num_users; i++) {
78                         /* getutxent can return multiple user entries for the
79                          * same user, so ignore any dups */
80                         if (strcmp(u->ut_user, usr_infos[i].name) == 0) {
81                                 break;
82                         }
83                 }
84                 if (i < num_users) {
85                         continue;
86                 }
87
88                 tmp = talloc_realloc(mem_ctx, usr_infos, struct usrinfo,
89                                      num_users+1);
90                 if (tmp == NULL) {
91                         TALLOC_FREE(tmp);
92                         endutxent();
93                         return NULL;
94                 }
95                 usr_infos = tmp;
96                 usr_infos[num_users].name = talloc_strdup(usr_infos,
97                                                           u->ut_user);
98                 if (usr_infos[num_users].name == NULL) {
99                         TALLOC_FREE(usr_infos);
100                         endutxent();
101                         return NULL;
102                 }
103                 usr_infos[num_users].login_time.tv_sec = u->ut_tv.tv_sec;
104                 usr_infos[num_users].login_time.tv_usec = u->ut_tv.tv_usec;
105                 num_users += 1;
106         }
107
108         /* Sort the user list by time, oldest first */
109         if (num_users > 1) {
110                 qsort(usr_infos, num_users, sizeof(struct usrinfo),
111                       usr_info_cmp);
112         }
113
114         users = (char**)talloc_array(mem_ctx, char*, num_users);
115         if (users) {
116                 for (i = 0; i < num_users; i++) {
117                         users[i] = talloc_move(users, &usr_infos[i].name);
118                 }
119         }
120         TALLOC_FREE(usr_infos);
121         endutxent();
122         errno = 0;
123         return users;
124 }
125
126 #else
127
128 static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx)
129 {
130         return NULL;
131 }
132
133 #endif
134
135 static int dom_user_cmp(const void *p1, const void *p2)
136 {
137         /* Called from qsort to compare two domain users in a dom_usr_t array
138          * for sorting by login time. Return >0 if usr1 login time was later
139          * than usr2 login time, <0 if it was earlier */
140         const struct dom_usr *usr1 = (const struct dom_usr *)p1;
141         const struct dom_usr *usr2 = (const struct dom_usr *)p2;
142
143         return (usr1->login_time - usr2->login_time);
144 }
145
146 /*******************************************************************
147  Get a list of the names of all users of this machine who are
148  logged into the domain.
149
150  This should return a list of the users on this machine who are
151  logged into the domain (i.e. have been authenticated by the domain's
152  password server) but that doesn't fit well with the normal Samba
153  scenario where accesses out to the domain are made through smbclient
154  with each such session individually authenticated. So about the best
155  we can do currently is to list sessions of local users connected to
156  this server, which means that to get themself included in the list a
157  local user must create a session to the local samba server by running:
158      smbclient \\\\localhost\\share
159
160  FIXME: find a better way to get local users logged into the domain
161  in this list.
162  ********************************************************************/
163
164 static struct dom_usr *get_domain_userlist(TALLOC_CTX *mem_ctx)
165 {
166         struct sessionid *session_list = NULL;
167         char *machine_name, *p, *nm;
168         const char *sep;
169         struct dom_usr *users, *tmp;
170         int i, num_users, num_sessions;
171
172         sep = lp_winbind_separator();
173         if (!sep) {
174                 sep = "\\";
175         }
176
177         num_sessions = list_sessions(mem_ctx, &session_list);
178         if (num_sessions == 0) {
179                 errno = 0;
180                 return NULL;
181         }
182
183         users = talloc_array(mem_ctx, struct dom_usr, num_sessions);
184         if (users == NULL) {
185                 TALLOC_FREE(session_list);
186                 return NULL;
187         }
188
189         for (i=num_users=0; i<num_sessions; i++) {
190                 if (!session_list[i].username
191                     || !session_list[i].remote_machine) {
192                         continue;
193                 }
194                 p = strpbrk(session_list[i].remote_machine, "./");
195                 if (p) {
196                         *p = '\0';
197                 }
198                 machine_name = talloc_asprintf_strupper_m(
199                         users, "%s", session_list[i].remote_machine);
200                 if (machine_name == NULL) {
201                         DEBUG(10, ("talloc_asprintf failed\n"));
202                         continue;
203                 }
204                 if (strcmp(machine_name, global_myname()) == 0) {
205                         p = session_list[i].username;
206                         nm = strstr(p, sep);
207                         if (nm) {
208                                 /*
209                                  * "domain+name" format so split domain and
210                                  * name components
211                                  */
212                                 *nm = '\0';
213                                 nm += strlen(sep);
214                                 users[num_users].domain =
215                                         talloc_asprintf_strupper_m(users,
216                                                                    "%s", p);
217                                 users[num_users].name = talloc_strdup(users,
218                                                                       nm);
219                         } else {
220                                 /*
221                                  * Simple user name so get domain from smb.conf
222                                  */
223                                 users[num_users].domain =
224                                         talloc_strdup(users, lp_workgroup());
225                                 users[num_users].name = talloc_strdup(users,
226                                                                       p);
227                         }
228                         users[num_users].login_time =
229                                 session_list[i].connect_start;
230                         num_users++;
231                 }
232                 TALLOC_FREE(machine_name);
233         }
234         TALLOC_FREE(session_list);
235
236         tmp = talloc_realloc(mem_ctx, users, struct dom_usr, num_users);
237         if (tmp == NULL) {
238                 return NULL;
239         }
240         users = tmp;
241
242         /* Sort the user list by time, oldest first */
243         if (num_users > 1) {
244                 qsort(users, num_users, sizeof(struct dom_usr), dom_user_cmp);
245         }
246
247         errno = 0;
248         return users;
249 }
250
251 /*******************************************************************
252  RPC Workstation Service request NetWkstaGetInfo with level 100.
253  Returns to the requester:
254   - The machine name.
255   - The smb version number
256   - The domain name.
257  Returns a filled in wkssvc_NetWkstaInfo100 struct.
258  ********************************************************************/
259
260 static struct wkssvc_NetWkstaInfo100 *create_wks_info_100(TALLOC_CTX *mem_ctx)
261 {
262         struct wkssvc_NetWkstaInfo100 *info100;
263
264         info100 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo100);
265         if (info100 == NULL) {
266                 return NULL;
267         }
268
269         info100->platform_id     = PLATFORM_ID_NT;      /* unknown */
270         info100->version_major   = lp_major_announce_version();
271         info100->version_minor   = lp_minor_announce_version();
272
273         info100->server_name = talloc_asprintf_strupper_m(
274                 info100, "%s", global_myname());
275         info100->domain_name = talloc_asprintf_strupper_m(
276                 info100, "%s", lp_workgroup());
277
278         return info100;
279 }
280
281 /*******************************************************************
282  RPC Workstation Service request NetWkstaGetInfo with level 101.
283  Returns to the requester:
284   - As per NetWkstaGetInfo with level 100, plus:
285   - The LANMAN directory path (not currently supported).
286  Returns a filled in wkssvc_NetWkstaInfo101 struct.
287  ********************************************************************/
288
289 static struct wkssvc_NetWkstaInfo101 *create_wks_info_101(TALLOC_CTX *mem_ctx)
290 {
291         struct wkssvc_NetWkstaInfo101 *info101;
292
293         info101 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo101);
294         if (info101 == NULL) {
295                 return NULL;
296         }
297
298         info101->platform_id     = PLATFORM_ID_NT;      /* unknown */
299         info101->version_major   = lp_major_announce_version();
300         info101->version_minor   = lp_minor_announce_version();
301
302         info101->server_name = talloc_asprintf_strupper_m(
303                 info101, "%s", global_myname());
304         info101->domain_name = talloc_asprintf_strupper_m(
305                 info101, "%s", lp_workgroup());
306         info101->lan_root = "";
307
308         return info101;
309 }
310
311 /*******************************************************************
312  RPC Workstation Service request NetWkstaGetInfo with level 102.
313  Returns to the requester:
314   - As per NetWkstaGetInfo with level 101, plus:
315   - The number of logged in users.
316  Returns a filled in wkssvc_NetWkstaInfo102 struct.
317  ********************************************************************/
318
319 static struct wkssvc_NetWkstaInfo102 *create_wks_info_102(TALLOC_CTX *mem_ctx)
320 {
321         struct wkssvc_NetWkstaInfo102 *info102;
322         char **users;
323
324         info102 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo102);
325         if (info102 == NULL) {
326                 return NULL;
327         }
328
329         info102->platform_id     = PLATFORM_ID_NT;      /* unknown */
330         info102->version_major   = lp_major_announce_version();
331         info102->version_minor   = lp_minor_announce_version();
332
333         info102->server_name = talloc_asprintf_strupper_m(
334                 info102, "%s", global_myname());
335         info102->domain_name = talloc_asprintf_strupper_m(
336                 info102, "%s", lp_workgroup());
337         info102->lan_root = "";
338
339         users = get_logged_on_userlist(talloc_tos());
340         info102->logged_on_users = talloc_array_length(users);
341
342         TALLOC_FREE(users);
343
344         return info102;
345 }
346
347 /********************************************************************
348  Handling for RPC Workstation Service request NetWkstaGetInfo
349  ********************************************************************/
350
351 WERROR _wkssvc_NetWkstaGetInfo(pipes_struct *p, struct wkssvc_NetWkstaGetInfo *r)
352 {
353         switch (r->in.level) {
354         case 100:
355                 /* Level 100 can be allowed from anyone including anonymous
356                  * so no access checks are needed for this case */
357                 r->out.info->info100 = create_wks_info_100(p->mem_ctx);
358                 if (r->out.info->info100 == NULL) {
359                         return WERR_NOMEM;
360                 }
361                 break;
362         case 101:
363                 /* Level 101 can be allowed from any logged in user */
364                 if (!nt_token_check_sid(&global_sid_Authenticated_Users,
365                                         p->server_info->ptok)) {
366                         DEBUG(1,("User not allowed for NetWkstaGetInfo level "
367                                  "101\n"));
368                         DEBUGADD(3,(" - does not have sid for Authenticated "
369                                     "Users %s:\n",
370                                     sid_string_dbg(
371                                             &global_sid_Authenticated_Users)));
372                         debug_nt_user_token(DBGC_CLASS, 3,
373                                             p->server_info->ptok);
374                         return WERR_ACCESS_DENIED;
375                 }
376                 r->out.info->info101 = create_wks_info_101(p->mem_ctx);
377                 if (r->out.info->info101 == NULL) {
378                         return WERR_NOMEM;
379                 }
380                 break;
381         case 102:
382                 /* Level 102 Should only be allowed from a domain administrator */
383                 if (!nt_token_check_sid(&global_sid_Builtin_Administrators,
384                                         p->server_info->ptok)) {
385                         DEBUG(1,("User not allowed for NetWkstaGetInfo level "
386                                  "102\n"));
387                         DEBUGADD(3,(" - does not have sid for Administrators "
388                                     "group %s, sids are:\n",
389                                     sid_string_dbg(&global_sid_Builtin_Administrators)));
390                         debug_nt_user_token(DBGC_CLASS, 3,
391                                             p->server_info->ptok);
392                         return WERR_ACCESS_DENIED;
393                 }
394                 r->out.info->info102 = create_wks_info_102(p->mem_ctx);
395                 if (r->out.info->info102 == NULL) {
396                         return WERR_NOMEM;
397                 }
398                 break;
399         default:
400                 return WERR_UNKNOWN_LEVEL;
401         }
402
403         return WERR_OK;
404 }
405
406 /********************************************************************
407  ********************************************************************/
408
409 WERROR _wkssvc_NetWkstaSetInfo(pipes_struct *p, struct wkssvc_NetWkstaSetInfo *r)
410 {
411         /* FIXME: Add implementation code here */
412         p->rng_fault_state = True;
413         return WERR_NOT_SUPPORTED;
414 }
415
416 /********************************************************************
417  RPC Workstation Service request NetWkstaEnumUsers with level 0:
418  Returns to the requester:
419   - the user names of the logged in users.
420  Returns a filled in wkssvc_NetWkstaEnumUsersCtr0 struct.
421  ********************************************************************/
422
423 static struct wkssvc_NetWkstaEnumUsersCtr0 *create_enum_users0(
424         TALLOC_CTX *mem_ctx)
425 {
426         struct wkssvc_NetWkstaEnumUsersCtr0 *ctr0;
427         char **users;
428         int i, num_users;
429
430         ctr0 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr0);
431         if (ctr0 == NULL) {
432                 return NULL;
433         }
434
435         users = get_logged_on_userlist(talloc_tos());
436         if (users == NULL && errno != 0) {
437                 DEBUG(1,("get_logged_on_userlist error %d: %s\n",
438                         errno, strerror(errno)));
439                 TALLOC_FREE(ctr0);
440                 return NULL;
441         }
442
443         num_users = (users) ? talloc_array_length(users) : 0;
444         ctr0->entries_read = num_users;
445         ctr0->user0 = talloc_array(ctr0, struct wkssvc_NetrWkstaUserInfo0,
446                                    num_users);
447         if (ctr0->user0 == NULL) {
448                 TALLOC_FREE(ctr0);
449                 TALLOC_FREE(users);
450                 return NULL;
451         }
452
453         for (i=0; i<num_users; i++) {
454                 ctr0->user0[i].user_name = talloc_move(ctr0->user0, &users[i]);
455         }
456         TALLOC_FREE(users);
457         return ctr0;
458 }
459
460 /********************************************************************
461  RPC Workstation Service request NetWkstaEnumUsers with level 1.
462  Returns to the requester:
463   - the user names of the logged in users,
464   - the domain or machine each is logged into,
465   - the password server that was used to authenticate each,
466   - other domains each user is logged into (not currently supported).
467  Returns a filled in wkssvc_NetWkstaEnumUsersCtr1 struct.
468  ********************************************************************/
469
470 static struct wkssvc_NetWkstaEnumUsersCtr1 *create_enum_users1(
471         TALLOC_CTX *mem_ctx)
472 {
473         struct wkssvc_NetWkstaEnumUsersCtr1 *ctr1;
474         char **users;
475         struct dom_usr *dom_users;
476         char *pwd_server;
477         int i, j, num_users, num_dom_users;
478
479         ctr1 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr1);
480         if (ctr1 == NULL) {
481                 return NULL;
482         }
483
484         users = get_logged_on_userlist(talloc_tos());
485         if (users == NULL && errno != 0) {
486                 DEBUG(1,("get_logged_on_userlist error %d: %s\n",
487                         errno, strerror(errno)));
488                 TALLOC_FREE(ctr1);
489                 return NULL;
490         }
491         num_users = (users) ? talloc_array_length(users) : 0;
492
493         dom_users = get_domain_userlist(talloc_tos());
494         if (dom_users == NULL && errno != 0) {
495                 TALLOC_FREE(ctr1);
496                 TALLOC_FREE(users);
497                 return NULL;
498         }
499         num_dom_users = (dom_users) ? talloc_array_length(dom_users) : 0;
500
501         ctr1->user1 = talloc_array(ctr1, struct wkssvc_NetrWkstaUserInfo1,
502                                    num_users+num_dom_users);
503         if (ctr1->user1 == NULL) {
504                 TALLOC_FREE(ctr1);
505                 TALLOC_FREE(users);
506                 TALLOC_FREE(dom_users);
507                 return NULL;
508         }
509
510         if ((pwd_server = talloc_strdup(ctr1->user1, lp_passwordserver()))) {
511                 /* The configured password server is a full DNS name but
512                  * for the logon server we need to return just the first
513                  * component (machine name) of it in upper-case */
514                 char *p = strchr(pwd_server, '.');
515                 if (p) {
516                         *p = '\0';
517                 } else {
518                         p = pwd_server + strlen(pwd_server);
519                 }
520                 while (--p >= pwd_server) {
521                         *p = toupper(*p);
522                 }
523         } else {
524                 pwd_server = "";
525         }
526
527         /* Put in local users first */
528         for (i=0; i<num_users; i++) {
529                 ctr1->user1[i].user_name = talloc_move(ctr1->user1, &users[i]);
530
531                 /* For a local user the domain name and logon server are
532                  * both returned as the local machine's NetBIOS name */
533                 ctr1->user1[i].logon_domain = ctr1->user1[i].logon_server =
534                         talloc_asprintf_strupper_m(ctr1->user1, "%s", global_myname());
535
536                 ctr1->user1[i].other_domains = NULL;    /* Maybe in future? */
537         }
538
539         /* Now domain users */
540         for (j=0; j<num_dom_users; j++) {
541                 ctr1->user1[i].user_name =
542                                 talloc_strdup(ctr1->user1, dom_users[j].name);
543                 ctr1->user1[i].logon_domain =
544                                 talloc_strdup(ctr1->user1, dom_users[j].domain);
545                 ctr1->user1[i].logon_server = pwd_server;
546
547                 ctr1->user1[i++].other_domains = NULL;  /* Maybe in future? */
548         }
549
550         ctr1->entries_read = i;
551
552         TALLOC_FREE(users);
553         TALLOC_FREE(dom_users);
554         return ctr1;
555 }
556
557 /********************************************************************
558  Handling for RPC Workstation Service request NetWkstaEnumUsers
559  (a.k.a Windows NetWkstaUserEnum)
560  ********************************************************************/
561
562 WERROR _wkssvc_NetWkstaEnumUsers(pipes_struct *p, struct wkssvc_NetWkstaEnumUsers *r)
563 {
564         /* This with any level should only be allowed from a domain administrator */
565         if (!nt_token_check_sid(&global_sid_Builtin_Administrators,
566                                 p->server_info->ptok)) {
567                 DEBUG(1,("User not allowed for NetWkstaEnumUsers\n"));
568                 DEBUGADD(3,(" - does not have sid for Administrators group "
569                             "%s\n", sid_string_dbg(
570                                     &global_sid_Builtin_Administrators)));
571                 debug_nt_user_token(DBGC_CLASS, 3, p->server_info->ptok);
572                 return WERR_ACCESS_DENIED;
573         }
574
575         switch (r->in.info->level) {
576         case 0:
577                 r->out.info->ctr.user0 = create_enum_users0(p->mem_ctx);
578                 if (r->out.info->ctr.user0 == NULL) {
579                         return WERR_NOMEM;
580                 }
581                 r->out.info->level = r->in.info->level;
582                 *r->out.entries_read = r->out.info->ctr.user0->entries_read;
583                 *r->out.resume_handle = 0;
584                 break;
585         case 1:
586                 r->out.info->ctr.user1 = create_enum_users1(p->mem_ctx);
587                 if (r->out.info->ctr.user1 == NULL) {
588                         return WERR_NOMEM;
589                 }
590                 r->out.info->level = r->in.info->level;
591                 *r->out.entries_read = r->out.info->ctr.user1->entries_read;
592                 *r->out.resume_handle = 0;
593                 break;
594         default:
595                 return WERR_UNKNOWN_LEVEL;
596         }
597
598         return WERR_OK;
599 }
600
601 /********************************************************************
602  ********************************************************************/
603
604 WERROR _wkssvc_NetrWkstaUserGetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserGetInfo *r)
605 {
606         /* FIXME: Add implementation code here */
607         p->rng_fault_state = True;
608         return WERR_NOT_SUPPORTED;
609 }
610
611 /********************************************************************
612  ********************************************************************/
613
614 WERROR _wkssvc_NetrWkstaUserSetInfo(pipes_struct *p, struct wkssvc_NetrWkstaUserSetInfo *r)
615 {
616         /* FIXME: Add implementation code here */
617         p->rng_fault_state = True;
618         return WERR_NOT_SUPPORTED;
619 }
620
621 /********************************************************************
622  ********************************************************************/
623
624 WERROR _wkssvc_NetWkstaTransportEnum(pipes_struct *p, struct wkssvc_NetWkstaTransportEnum *r)
625 {
626         /* FIXME: Add implementation code here */
627         p->rng_fault_state = True;
628         return WERR_NOT_SUPPORTED;
629 }
630
631 /********************************************************************
632  ********************************************************************/
633
634 WERROR _wkssvc_NetrWkstaTransportAdd(pipes_struct *p, struct wkssvc_NetrWkstaTransportAdd *r)
635 {
636         /* FIXME: Add implementation code here */
637         p->rng_fault_state = True;
638         return WERR_NOT_SUPPORTED;
639 }
640
641 /********************************************************************
642  ********************************************************************/
643
644 WERROR _wkssvc_NetrWkstaTransportDel(pipes_struct *p, struct wkssvc_NetrWkstaTransportDel *r)
645 {
646         /* FIXME: Add implementation code here */
647         p->rng_fault_state = True;
648         return WERR_NOT_SUPPORTED;
649 }
650
651 /********************************************************************
652  ********************************************************************/
653
654 WERROR _wkssvc_NetrUseAdd(pipes_struct *p, struct wkssvc_NetrUseAdd *r)
655 {
656         /* FIXME: Add implementation code here */
657         p->rng_fault_state = True;
658         return WERR_NOT_SUPPORTED;
659 }
660
661 /********************************************************************
662  ********************************************************************/
663
664 WERROR _wkssvc_NetrUseGetInfo(pipes_struct *p, struct wkssvc_NetrUseGetInfo *r)
665 {
666         /* FIXME: Add implementation code here */
667         p->rng_fault_state = True;
668         return WERR_NOT_SUPPORTED;
669 }
670
671 /********************************************************************
672  ********************************************************************/
673
674 WERROR _wkssvc_NetrUseDel(pipes_struct *p, struct wkssvc_NetrUseDel *r)
675 {
676         /* FIXME: Add implementation code here */
677         p->rng_fault_state = True;
678         return WERR_NOT_SUPPORTED;
679 }
680
681 /********************************************************************
682  ********************************************************************/
683
684 WERROR _wkssvc_NetrUseEnum(pipes_struct *p, struct wkssvc_NetrUseEnum *r)
685 {
686         /* FIXME: Add implementation code here */
687         p->rng_fault_state = True;
688         return WERR_NOT_SUPPORTED;
689 }
690
691 /********************************************************************
692  ********************************************************************/
693
694 WERROR _wkssvc_NetrMessageBufferSend(pipes_struct *p, struct wkssvc_NetrMessageBufferSend *r)
695 {
696         /* FIXME: Add implementation code here */
697         p->rng_fault_state = True;
698         return WERR_NOT_SUPPORTED;
699 }
700
701 /********************************************************************
702  ********************************************************************/
703
704 WERROR _wkssvc_NetrWorkstationStatisticsGet(pipes_struct *p, struct wkssvc_NetrWorkstationStatisticsGet *r) 
705 {
706         /* FIXME: Add implementation code here */
707         p->rng_fault_state = True;
708         return WERR_NOT_SUPPORTED;
709 }
710
711 /********************************************************************
712  ********************************************************************/
713
714 WERROR _wkssvc_NetrLogonDomainNameAdd(pipes_struct *p, struct wkssvc_NetrLogonDomainNameAdd *r)
715 {
716         /* FIXME: Add implementation code here */
717         p->rng_fault_state = True;
718         return WERR_NOT_SUPPORTED;
719 }
720
721 /********************************************************************
722  ********************************************************************/
723
724 WERROR _wkssvc_NetrLogonDomainNameDel(pipes_struct *p, struct wkssvc_NetrLogonDomainNameDel *r)
725 {
726         /* FIXME: Add implementation code here */
727         p->rng_fault_state = True;
728         return WERR_NOT_SUPPORTED;
729 }
730
731 /********************************************************************
732  ********************************************************************/
733
734 WERROR _wkssvc_NetrJoinDomain(pipes_struct *p, struct wkssvc_NetrJoinDomain *r)
735 {
736         /* FIXME: Add implementation code here */
737         p->rng_fault_state = True;
738         return WERR_NOT_SUPPORTED;
739 }
740
741 /********************************************************************
742  ********************************************************************/
743
744 WERROR _wkssvc_NetrUnjoinDomain(pipes_struct *p, struct wkssvc_NetrUnjoinDomain *r)
745 {
746         /* FIXME: Add implementation code here */
747         p->rng_fault_state = True;
748         return WERR_NOT_SUPPORTED;
749 }
750
751 /********************************************************************
752  ********************************************************************/
753
754 WERROR _wkssvc_NetrRenameMachineInDomain(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain *r)
755 {
756         /* FIXME: Add implementation code here */
757         p->rng_fault_state = True;
758         return WERR_NOT_SUPPORTED;
759 }
760
761 /********************************************************************
762  ********************************************************************/
763
764 WERROR _wkssvc_NetrValidateName(pipes_struct *p, struct wkssvc_NetrValidateName *r)
765 {
766         /* FIXME: Add implementation code here */
767         p->rng_fault_state = True;
768         return WERR_NOT_SUPPORTED;
769 }
770
771 /********************************************************************
772  ********************************************************************/
773
774 WERROR _wkssvc_NetrGetJoinInformation(pipes_struct *p, struct wkssvc_NetrGetJoinInformation *r)
775 {
776         /* FIXME: Add implementation code here */
777         p->rng_fault_state = True;
778         return WERR_NOT_SUPPORTED;
779 }
780
781 /********************************************************************
782  ********************************************************************/
783
784 WERROR _wkssvc_NetrGetJoinableOus(pipes_struct *p, struct wkssvc_NetrGetJoinableOus *r)
785 {
786         /* FIXME: Add implementation code here */
787         p->rng_fault_state = True;
788         return WERR_NOT_SUPPORTED;
789 }
790
791 /********************************************************************
792  _wkssvc_NetrJoinDomain2
793  ********************************************************************/
794
795 WERROR _wkssvc_NetrJoinDomain2(pipes_struct *p,
796                                struct wkssvc_NetrJoinDomain2 *r)
797 {
798         struct libnet_JoinCtx *j = NULL;
799         char *cleartext_pwd = NULL;
800         char *admin_domain = NULL;
801         char *admin_account = NULL;
802         WERROR werr;
803         struct nt_user_token *token = p->server_info->ptok;
804
805         if (!r->in.domain_name) {
806                 return WERR_INVALID_PARAM;
807         }
808
809         if (!r->in.admin_account || !r->in.encrypted_password) {
810                 return WERR_INVALID_PARAM;
811         }
812
813         if (!user_has_privileges(token, &se_machine_account) &&
814             !nt_token_check_domain_rid(token, DOMAIN_GROUP_RID_ADMINS) &&
815             !nt_token_check_sid(&global_sid_Builtin_Administrators, token)) {
816                 DEBUG(5,("_wkssvc_NetrJoinDomain2: account doesn't have "
817                         "sufficient privileges\n"));
818                 return WERR_ACCESS_DENIED;
819         }
820
821         if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED) ||
822             (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
823                 return WERR_NOT_SUPPORTED;
824         }
825
826         werr = decode_wkssvc_join_password_buffer(
827                 p->mem_ctx, r->in.encrypted_password,
828                 &p->server_info->user_session_key, &cleartext_pwd);
829         if (!W_ERROR_IS_OK(werr)) {
830                 return werr;
831         }
832
833         split_domain_user(p->mem_ctx,
834                           r->in.admin_account,
835                           &admin_domain,
836                           &admin_account);
837
838         werr = libnet_init_JoinCtx(p->mem_ctx, &j);
839         if (!W_ERROR_IS_OK(werr)) {
840                 return werr;
841         }
842
843         j->in.domain_name       = r->in.domain_name;
844         j->in.account_ou        = r->in.account_ou;
845         j->in.join_flags        = r->in.join_flags;
846         j->in.admin_account     = admin_account;
847         j->in.admin_password    = cleartext_pwd;
848         j->in.debug             = true;
849         j->in.modify_config     = lp_config_backend_is_registry();
850         j->in.msg_ctx           = smbd_messaging_context();
851
852         become_root();
853         werr = libnet_Join(p->mem_ctx, j);
854         unbecome_root();
855
856         if (!W_ERROR_IS_OK(werr)) {
857                 DEBUG(5,("_wkssvc_NetrJoinDomain2: libnet_Join failed with: %s\n",
858                         j->out.error_string ? j->out.error_string :
859                         win_errstr(werr)));
860         }
861
862         TALLOC_FREE(j);
863         return werr;
864 }
865
866 /********************************************************************
867  _wkssvc_NetrUnjoinDomain2
868  ********************************************************************/
869
870 WERROR _wkssvc_NetrUnjoinDomain2(pipes_struct *p,
871                                  struct wkssvc_NetrUnjoinDomain2 *r)
872 {
873         struct libnet_UnjoinCtx *u = NULL;
874         char *cleartext_pwd = NULL;
875         char *admin_domain = NULL;
876         char *admin_account = NULL;
877         WERROR werr;
878         struct nt_user_token *token = p->server_info->ptok;
879
880         if (!r->in.account || !r->in.encrypted_password) {
881                 return WERR_INVALID_PARAM;
882         }
883
884         if (!user_has_privileges(token, &se_machine_account) &&
885             !nt_token_check_domain_rid(token, DOMAIN_GROUP_RID_ADMINS) &&
886             !nt_token_check_sid(&global_sid_Builtin_Administrators, token)) {
887                 DEBUG(5,("_wkssvc_NetrUnjoinDomain2: account doesn't have "
888                         "sufficient privileges\n"));
889                 return WERR_ACCESS_DENIED;
890         }
891
892         werr = decode_wkssvc_join_password_buffer(
893                 p->mem_ctx, r->in.encrypted_password,
894                 &p->server_info->user_session_key, &cleartext_pwd);
895         if (!W_ERROR_IS_OK(werr)) {
896                 return werr;
897         }
898
899         split_domain_user(p->mem_ctx,
900                           r->in.account,
901                           &admin_domain,
902                           &admin_account);
903
904         werr = libnet_init_UnjoinCtx(p->mem_ctx, &u);
905         if (!W_ERROR_IS_OK(werr)) {
906                 return werr;
907         }
908
909         u->in.domain_name       = lp_realm();
910         u->in.unjoin_flags      = r->in.unjoin_flags |
911                                   WKSSVC_JOIN_FLAGS_JOIN_TYPE;
912         u->in.admin_account     = admin_account;
913         u->in.admin_password    = cleartext_pwd;
914         u->in.debug             = true;
915         u->in.modify_config     = lp_config_backend_is_registry();
916         u->in.msg_ctx           = smbd_messaging_context();
917
918         become_root();
919         werr = libnet_Unjoin(p->mem_ctx, u);
920         unbecome_root();
921
922         if (!W_ERROR_IS_OK(werr)) {
923                 DEBUG(5,("_wkssvc_NetrUnjoinDomain2: libnet_Unjoin failed with: %s\n",
924                         u->out.error_string ? u->out.error_string :
925                         win_errstr(werr)));
926         }
927
928         TALLOC_FREE(u);
929         return werr;
930 }
931
932 /********************************************************************
933  ********************************************************************/
934
935 WERROR _wkssvc_NetrRenameMachineInDomain2(pipes_struct *p, struct wkssvc_NetrRenameMachineInDomain2 *r)
936 {
937         /* for now just return not supported */
938         return WERR_NOT_SUPPORTED;
939 }
940
941 /********************************************************************
942  ********************************************************************/
943
944 WERROR _wkssvc_NetrValidateName2(pipes_struct *p, struct wkssvc_NetrValidateName2 *r)
945 {
946         /* FIXME: Add implementation code here */
947         p->rng_fault_state = True;
948         return WERR_NOT_SUPPORTED;
949 }
950
951 /********************************************************************
952  ********************************************************************/
953
954 WERROR _wkssvc_NetrGetJoinableOus2(pipes_struct *p, struct wkssvc_NetrGetJoinableOus2 *r)
955 {
956         /* FIXME: Add implementation code here */
957         p->rng_fault_state = True;
958         return WERR_NOT_SUPPORTED;
959 }
960
961 /********************************************************************
962  ********************************************************************/
963
964 WERROR _wkssvc_NetrAddAlternateComputerName(pipes_struct *p, struct wkssvc_NetrAddAlternateComputerName *r)
965 {
966         /* FIXME: Add implementation code here */
967         p->rng_fault_state = True;
968         return WERR_NOT_SUPPORTED;
969 }
970
971 /********************************************************************
972  ********************************************************************/
973
974 WERROR _wkssvc_NetrRemoveAlternateComputerName(pipes_struct *p, struct wkssvc_NetrRemoveAlternateComputerName *r)
975 {
976         /* FIXME: Add implementation code here */
977         p->rng_fault_state = True;
978         return WERR_NOT_SUPPORTED;
979 }
980
981 /********************************************************************
982  ********************************************************************/
983
984 WERROR _wkssvc_NetrSetPrimaryComputername(pipes_struct *p, struct wkssvc_NetrSetPrimaryComputername *r)
985 {
986         /* FIXME: Add implementation code here */
987         p->rng_fault_state = True;
988         return WERR_NOT_SUPPORTED;
989 }
990
991 /********************************************************************
992  ********************************************************************/
993
994 WERROR _wkssvc_NetrEnumerateComputerNames(pipes_struct *p, struct wkssvc_NetrEnumerateComputerNames *r)
995 {
996         /* FIXME: Add implementation code here */
997         p->rng_fault_state = True;
998         return WERR_NOT_SUPPORTED;
999 }
1000