summaryrefslogtreecommitdiffstats
path: root/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/rpc_server/wkssvc/srv_wkssvc_nt.c')
-rw-r--r--source3/rpc_server/wkssvc/srv_wkssvc_nt.c964
1 files changed, 964 insertions, 0 deletions
diff --git a/source3/rpc_server/wkssvc/srv_wkssvc_nt.c b/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
new file mode 100644
index 0000000..0724dd0
--- /dev/null
+++ b/source3/rpc_server/wkssvc/srv_wkssvc_nt.c
@@ -0,0 +1,964 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC Pipe client / server routines
+ *
+ * Copyright (C) Andrew Tridgell 1992-1997,
+ * Copyright (C) Gerald (Jerry) Carter 2006.
+ * Copyright (C) Guenther Deschner 2007-2008.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This is the implementation of the wks interface. */
+
+#include "includes.h"
+#include "ntdomain.h"
+#include "librpc/rpc/dcesrv_core.h"
+#include "librpc/gen_ndr/libnet_join.h"
+#include "libnet/libnet_join.h"
+#include "../libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_wkssvc.h"
+#include "librpc/gen_ndr/ndr_wkssvc_scompat.h"
+#include "../libcli/security/security.h"
+#include "session.h"
+#include "smbd/smbd.h"
+#include "auth.h"
+#include "krb5_env.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
+
+struct dom_usr {
+ char *name;
+ char *domain;
+ time_t login_time;
+};
+
+static int dom_user_cmp(const struct dom_usr *usr1, const struct dom_usr *usr2)
+{
+ /* Called from qsort to compare two domain users in a dom_usr_t array
+ * for sorting by login time. Return >0 if usr1 login time was later
+ * than usr2 login time, <0 if it was earlier */
+ return (usr1->login_time - usr2->login_time);
+}
+
+/*******************************************************************
+ Get a list of the names of all users of this machine who are
+ logged into the domain.
+
+ This should return a list of the users on this machine who are
+ logged into the domain (i.e. have been authenticated by the domain's
+ password server) but that doesn't fit well with the normal Samba
+ scenario where accesses out to the domain are made through smbclient
+ with each such session individually authenticated. So about the best
+ we can do currently is to list sessions of local users connected to
+ this server, which means that to get themself included in the list a
+ local user must create a session to the local samba server by running:
+ smbclient \\\\localhost\\share
+
+ FIXME: find a better way to get local users logged into the domain
+ in this list.
+ ********************************************************************/
+
+static int get_domain_userlist(TALLOC_CTX *mem_ctx, struct dom_usr **pusers)
+{
+ struct sessionid *session_list = NULL;
+ char *machine_name, *p, *nm;
+ const char *sep;
+ struct dom_usr *users, *tmp;
+ int i, num_users, num_sessions;
+
+ sep = lp_winbind_separator();
+ if (!sep) {
+ sep = "\\";
+ }
+
+ num_sessions = list_sessions(mem_ctx, &session_list);
+ if (num_sessions == 0) {
+ *pusers = NULL;
+ return 0;
+ }
+
+ users = talloc_array(mem_ctx, struct dom_usr, num_sessions);
+ if (users == NULL) {
+ TALLOC_FREE(session_list);
+ return ENOMEM;
+ }
+
+ for (i=num_users=0; i<num_sessions; i++) {
+ if (session_list[i].username[0] == '\0' ||
+ session_list[i].remote_machine[0] == '\0') {
+ continue;
+ }
+ p = strpbrk(session_list[i].remote_machine, "./");
+ if (p) {
+ *p = '\0';
+ }
+ machine_name = talloc_asprintf_strupper_m(
+ users, "%s", session_list[i].remote_machine);
+ if (machine_name == NULL) {
+ DEBUG(10, ("talloc_asprintf failed\n"));
+ continue;
+ }
+ if (strcmp(machine_name, lp_netbios_name()) == 0) {
+ p = session_list[i].username;
+ nm = strstr(p, sep);
+ if (nm) {
+ /*
+ * "domain+name" format so split domain and
+ * name components
+ */
+ *nm = '\0';
+ nm += strlen(sep);
+ users[num_users].domain =
+ talloc_asprintf_strupper_m(users,
+ "%s", p);
+ users[num_users].name = talloc_strdup(users,
+ nm);
+ } else {
+ /*
+ * Simple user name so get domain from smb.conf
+ */
+ users[num_users].domain =
+ talloc_strdup(users, lp_workgroup());
+ users[num_users].name = talloc_strdup(users,
+ p);
+ }
+ users[num_users].login_time =
+ session_list[i].connect_start;
+ num_users++;
+ }
+ TALLOC_FREE(machine_name);
+ }
+ TALLOC_FREE(session_list);
+
+ if (num_users == 0) {
+ TALLOC_FREE(users);
+ *pusers = NULL;
+ return 0;
+ }
+
+ tmp = talloc_realloc(mem_ctx, users, struct dom_usr, num_users);
+ if (tmp == NULL) {
+ TALLOC_FREE(users);
+ return ENOMEM;
+ }
+ users = tmp;
+
+ /* Sort the user list by time, oldest first */
+ TYPESAFE_QSORT(users, num_users, dom_user_cmp);
+
+ *pusers = users;
+ return 0;
+}
+
+/*******************************************************************
+ RPC Workstation Service request NetWkstaGetInfo with level 100.
+ Returns to the requester:
+ - The machine name.
+ - The smb version number
+ - The domain name.
+ Returns a filled in wkssvc_NetWkstaInfo100 struct.
+ ********************************************************************/
+
+static struct wkssvc_NetWkstaInfo100 *create_wks_info_100(TALLOC_CTX *mem_ctx)
+{
+ struct wkssvc_NetWkstaInfo100 *info100;
+
+ info100 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo100);
+ if (info100 == NULL) {
+ return NULL;
+ }
+
+ info100->platform_id = PLATFORM_ID_NT; /* unknown */
+ info100->version_major = SAMBA_MAJOR_NBT_ANNOUNCE_VERSION;
+ info100->version_minor = SAMBA_MINOR_NBT_ANNOUNCE_VERSION;
+
+ info100->server_name = talloc_asprintf_strupper_m(
+ info100, "%s", lp_netbios_name());
+ info100->domain_name = talloc_asprintf_strupper_m(
+ info100, "%s", lp_workgroup());
+
+ return info100;
+}
+
+/*******************************************************************
+ RPC Workstation Service request NetWkstaGetInfo with level 101.
+ Returns to the requester:
+ - As per NetWkstaGetInfo with level 100, plus:
+ - The LANMAN directory path (not currently supported).
+ Returns a filled in wkssvc_NetWkstaInfo101 struct.
+ ********************************************************************/
+
+static struct wkssvc_NetWkstaInfo101 *create_wks_info_101(TALLOC_CTX *mem_ctx)
+{
+ struct wkssvc_NetWkstaInfo101 *info101;
+
+ info101 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo101);
+ if (info101 == NULL) {
+ return NULL;
+ }
+
+ info101->platform_id = PLATFORM_ID_NT; /* unknown */
+ info101->version_major = SAMBA_MAJOR_NBT_ANNOUNCE_VERSION;
+ info101->version_minor = SAMBA_MINOR_NBT_ANNOUNCE_VERSION;
+
+ info101->server_name = talloc_asprintf_strupper_m(
+ info101, "%s", lp_netbios_name());
+ info101->domain_name = talloc_asprintf_strupper_m(
+ info101, "%s", lp_workgroup());
+ info101->lan_root = "";
+
+ return info101;
+}
+
+/*******************************************************************
+ RPC Workstation Service request NetWkstaGetInfo with level 102.
+ Returns to the requester:
+ - As per NetWkstaGetInfo with level 101, plus:
+ - The number of logged in users.
+ Returns a filled in wkssvc_NetWkstaInfo102 struct.
+ ********************************************************************/
+
+static struct wkssvc_NetWkstaInfo102 *create_wks_info_102(TALLOC_CTX *mem_ctx)
+{
+ struct wkssvc_NetWkstaInfo102 *info102;
+
+ info102 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo102);
+ if (info102 == NULL) {
+ return NULL;
+ }
+
+ info102->platform_id = PLATFORM_ID_NT; /* unknown */
+ info102->version_major = SAMBA_MAJOR_NBT_ANNOUNCE_VERSION;
+ info102->version_minor = SAMBA_MINOR_NBT_ANNOUNCE_VERSION;
+
+ info102->server_name = talloc_asprintf_strupper_m(
+ info102, "%s", lp_netbios_name());
+ info102->domain_name = talloc_asprintf_strupper_m(
+ info102, "%s", lp_workgroup());
+ info102->lan_root = "";
+ info102->logged_on_users = 0;
+
+ return info102;
+}
+
+/********************************************************************
+ Handling for RPC Workstation Service request NetWkstaGetInfo
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaGetInfo(struct pipes_struct *p,
+ struct wkssvc_NetWkstaGetInfo *r)
+{
+ struct dcesrv_call_state *dce_call = p->dce_call;
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(dce_call);
+ struct dom_sid_buf buf;
+
+ switch (r->in.level) {
+ case 100:
+ /* Level 100 can be allowed from anyone including anonymous
+ * so no access checks are needed for this case */
+ r->out.info->info100 = create_wks_info_100(p->mem_ctx);
+ if (r->out.info->info100 == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ break;
+ case 101:
+ /* Level 101 can be allowed from any logged in user */
+ if (!nt_token_check_sid(&global_sid_Authenticated_Users,
+ session_info->security_token)) {
+ DEBUG(1,("User not allowed for NetWkstaGetInfo level "
+ "101\n"));
+ DEBUGADD(3,(" - does not have sid for Authenticated "
+ "Users %s:\n",
+ dom_sid_str_buf(
+ &global_sid_Authenticated_Users,
+ &buf)));
+ security_token_debug(DBGC_CLASS, 3,
+ session_info->security_token);
+ return WERR_ACCESS_DENIED;
+ }
+ r->out.info->info101 = create_wks_info_101(p->mem_ctx);
+ if (r->out.info->info101 == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ break;
+ case 102:
+ /* Level 102 Should only be allowed from a domain administrator */
+ if (!nt_token_check_sid(&global_sid_Builtin_Administrators,
+ session_info->security_token)) {
+ DEBUG(1,("User not allowed for NetWkstaGetInfo level "
+ "102\n"));
+ DEBUGADD(3,(" - does not have sid for Administrators "
+ "group %s, sids are:\n",
+ dom_sid_str_buf(
+ &global_sid_Builtin_Administrators,
+ &buf)));
+ security_token_debug(DBGC_CLASS, 3,
+ session_info->security_token);
+ return WERR_ACCESS_DENIED;
+ }
+ r->out.info->info102 = create_wks_info_102(p->mem_ctx);
+ if (r->out.info->info102 == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ break;
+ default:
+ return WERR_INVALID_LEVEL;
+ }
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaSetInfo(struct pipes_struct *p,
+ struct wkssvc_NetWkstaSetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ RPC Workstation Service request NetWkstaEnumUsers with level 0:
+ Returns to the requester:
+ - the user names of the logged in users.
+ Returns a filled in wkssvc_NetWkstaEnumUsersCtr0 struct.
+ ********************************************************************/
+
+static struct wkssvc_NetWkstaEnumUsersCtr0 *create_enum_users0(
+ TALLOC_CTX *mem_ctx)
+{
+ struct wkssvc_NetWkstaEnumUsersCtr0 *ctr0;
+
+ ctr0 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr0);
+ if (ctr0 == NULL) {
+ return NULL;
+ }
+
+ ctr0->entries_read = 0;
+ ctr0->user0 = talloc_array(ctr0, struct wkssvc_NetrWkstaUserInfo0, 0);
+ if (ctr0->user0 == NULL) {
+ TALLOC_FREE(ctr0);
+ return NULL;
+ }
+
+ return ctr0;
+}
+
+/********************************************************************
+ RPC Workstation Service request NetWkstaEnumUsers with level 1.
+ Returns to the requester:
+ - the user names of the logged in users,
+ - the domain or machine each is logged into,
+ - the password server that was used to authenticate each,
+ - other domains each user is logged into (not currently supported).
+ Returns a filled in wkssvc_NetWkstaEnumUsersCtr1 struct.
+ ********************************************************************/
+
+static struct wkssvc_NetWkstaEnumUsersCtr1 *create_enum_users1(
+ TALLOC_CTX *mem_ctx)
+{
+ struct wkssvc_NetWkstaEnumUsersCtr1 *ctr1;
+ struct dom_usr *dom_users;
+ const char *pwd_server;
+ char *pwd_tmp;
+ int i, num_dom_users, ret;
+
+ ctr1 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr1);
+ if (ctr1 == NULL) {
+ return NULL;
+ }
+
+ ret = get_domain_userlist(talloc_tos(), &dom_users);
+ if (ret != 0) {
+ TALLOC_FREE(ctr1);
+ errno = ret;
+ return NULL;
+ }
+ num_dom_users = talloc_array_length(dom_users);
+
+ ctr1->user1 = talloc_array(ctr1, struct wkssvc_NetrWkstaUserInfo1,
+ num_dom_users);
+ if (ctr1->user1 == NULL) {
+ TALLOC_FREE(ctr1);
+ TALLOC_FREE(dom_users);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ pwd_server = "";
+
+ if ((pwd_tmp = talloc_strdup(ctr1->user1, lp_password_server()))) {
+ /* The configured password server is a full DNS name but
+ * for the logon server we need to return just the first
+ * component (machine name) of it in upper-case */
+ char *p = strchr(pwd_tmp, '.');
+ if (p) {
+ *p = '\0';
+ } else {
+ p = pwd_tmp + strlen(pwd_tmp);
+ }
+ while (--p >= pwd_tmp) {
+ *p = toupper(*p);
+ }
+ pwd_server = pwd_tmp;
+ }
+
+ /* Now domain users */
+ for (i=0; i<num_dom_users; i++) {
+ ctr1->user1[i].user_name =
+ talloc_strdup(ctr1->user1, dom_users[i].name);
+ ctr1->user1[i].logon_domain =
+ talloc_strdup(ctr1->user1, dom_users[i].domain);
+ ctr1->user1[i].logon_server = pwd_server;
+
+ ctr1->user1[i++].other_domains = NULL; /* Maybe in future? */
+ }
+
+ ctr1->entries_read = i;
+
+ TALLOC_FREE(dom_users);
+ return ctr1;
+}
+
+/********************************************************************
+ Handling for RPC Workstation Service request NetWkstaEnumUsers
+ (a.k.a Windows NetWkstaUserEnum)
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaEnumUsers(struct pipes_struct *p,
+ struct wkssvc_NetWkstaEnumUsers *r)
+{
+ struct dcesrv_call_state *dce_call = p->dce_call;
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(dce_call);
+
+ /* This with any level should only be allowed from a domain administrator */
+ if (!nt_token_check_sid(&global_sid_Builtin_Administrators,
+ session_info->security_token)) {
+ struct dom_sid_buf buf;
+ DEBUG(1,("User not allowed for NetWkstaEnumUsers\n"));
+ DEBUGADD(3,(" - does not have sid for Administrators group "
+ "%s\n",
+ dom_sid_str_buf(
+ &global_sid_Builtin_Administrators,
+ &buf)));
+ security_token_debug(
+ DBGC_CLASS, 3, session_info->security_token);
+ return WERR_ACCESS_DENIED;
+ }
+
+ switch (r->in.info->level) {
+ case 0:
+ r->out.info->ctr.user0 = create_enum_users0(p->mem_ctx);
+ if (r->out.info->ctr.user0 == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ r->out.info->level = r->in.info->level;
+ *r->out.entries_read = r->out.info->ctr.user0->entries_read;
+ if (r->out.resume_handle != NULL) {
+ *r->out.resume_handle = 0;
+ }
+ break;
+ case 1:
+ r->out.info->ctr.user1 = create_enum_users1(p->mem_ctx);
+ if (r->out.info->ctr.user1 == NULL) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+ r->out.info->level = r->in.info->level;
+ *r->out.entries_read = r->out.info->ctr.user1->entries_read;
+ if (r->out.resume_handle != NULL) {
+ *r->out.resume_handle = 0;
+ }
+ break;
+ default:
+ return WERR_INVALID_LEVEL;
+ }
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaUserGetInfo(struct pipes_struct *p,
+ struct wkssvc_NetrWkstaUserGetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaUserSetInfo(struct pipes_struct *p,
+ struct wkssvc_NetrWkstaUserSetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetWkstaTransportEnum(struct pipes_struct *p,
+ struct wkssvc_NetWkstaTransportEnum *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaTransportAdd(struct pipes_struct *p,
+ struct wkssvc_NetrWkstaTransportAdd *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWkstaTransportDel(struct pipes_struct *p,
+ struct wkssvc_NetrWkstaTransportDel *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseAdd(struct pipes_struct *p,
+ struct wkssvc_NetrUseAdd *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseGetInfo(struct pipes_struct *p,
+ struct wkssvc_NetrUseGetInfo *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseDel(struct pipes_struct *p,
+ struct wkssvc_NetrUseDel *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUseEnum(struct pipes_struct *p,
+ struct wkssvc_NetrUseEnum *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrMessageBufferSend(struct pipes_struct *p,
+ struct wkssvc_NetrMessageBufferSend *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrWorkstationStatisticsGet(struct pipes_struct *p,
+ struct wkssvc_NetrWorkstationStatisticsGet *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrLogonDomainNameAdd(struct pipes_struct *p,
+ struct wkssvc_NetrLogonDomainNameAdd *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrLogonDomainNameDel(struct pipes_struct *p,
+ struct wkssvc_NetrLogonDomainNameDel *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrJoinDomain(struct pipes_struct *p,
+ struct wkssvc_NetrJoinDomain *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUnjoinDomain(struct pipes_struct *p,
+ struct wkssvc_NetrUnjoinDomain *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrRenameMachineInDomain(struct pipes_struct *p,
+ struct wkssvc_NetrRenameMachineInDomain *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrValidateName(struct pipes_struct *p,
+ struct wkssvc_NetrValidateName *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrGetJoinInformation(struct pipes_struct *p,
+ struct wkssvc_NetrGetJoinInformation *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrGetJoinableOus(struct pipes_struct *p,
+ struct wkssvc_NetrGetJoinableOus *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ _wkssvc_NetrJoinDomain2
+ ********************************************************************/
+
+WERROR _wkssvc_NetrJoinDomain2(struct pipes_struct *p,
+ struct wkssvc_NetrJoinDomain2 *r)
+{
+ struct dcesrv_call_state *dce_call = p->dce_call;
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(dce_call);
+ struct libnet_JoinCtx *j = NULL;
+ char *cleartext_pwd = NULL;
+ char *admin_domain = NULL;
+ char *admin_account = NULL;
+ WERROR werr;
+ struct security_token *token = session_info->security_token;
+ NTSTATUS status;
+ DATA_BLOB session_key;
+ bool ok;
+
+ if (!r->in.domain_name) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ if (!r->in.admin_account || !r->in.encrypted_password) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ if (!security_token_has_privilege(token, SEC_PRIV_MACHINE_ACCOUNT) &&
+ !nt_token_check_domain_rid(token, DOMAIN_RID_ADMINS) &&
+ !nt_token_check_sid(&global_sid_Builtin_Administrators, token)) {
+ DEBUG(5,("_wkssvc_NetrJoinDomain2: account doesn't have "
+ "sufficient privileges\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED) ||
+ (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
+ return WERR_NOT_SUPPORTED;
+ }
+
+ status = session_extract_session_key(session_info,
+ &session_key,
+ KEY_USE_16BYTES);
+ if(!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("_wkssvc_NetrJoinDomain2: no session key %s\n",
+ nt_errstr(status)));
+ return WERR_NO_USER_SESSION_KEY;
+ }
+
+ werr = decode_wkssvc_join_password_buffer(
+ p->mem_ctx, r->in.encrypted_password,
+ &session_key, &cleartext_pwd);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ ok = split_domain_user(p->mem_ctx,
+ r->in.admin_account,
+ &admin_domain,
+ &admin_account);
+ if (!ok) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ werr = libnet_init_JoinCtx(p->mem_ctx, &j);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ j->in.domain_name = r->in.domain_name;
+ j->in.account_ou = r->in.account_ou;
+ j->in.join_flags = r->in.join_flags;
+ j->in.admin_account = admin_account;
+ j->in.admin_password = cleartext_pwd;
+ j->in.debug = true;
+ j->in.modify_config = lp_config_backend_is_registry();
+ j->in.msg_ctx = p->msg_ctx;
+
+ become_root();
+ setenv(KRB5_ENV_CCNAME, "MEMORY:_wkssvc_NetrJoinDomain2", 1);
+ werr = libnet_Join(p->mem_ctx, j);
+ unsetenv(KRB5_ENV_CCNAME);
+ unbecome_root();
+
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5,("_wkssvc_NetrJoinDomain2: libnet_Join failed with: %s\n",
+ j->out.error_string ? j->out.error_string :
+ win_errstr(werr)));
+ }
+
+ TALLOC_FREE(j);
+ return werr;
+}
+
+/********************************************************************
+ _wkssvc_NetrUnjoinDomain2
+ ********************************************************************/
+
+WERROR _wkssvc_NetrUnjoinDomain2(struct pipes_struct *p,
+ struct wkssvc_NetrUnjoinDomain2 *r)
+{
+ struct dcesrv_call_state *dce_call = p->dce_call;
+ struct auth_session_info *session_info =
+ dcesrv_call_session_info(dce_call);
+ struct libnet_UnjoinCtx *u = NULL;
+ char *cleartext_pwd = NULL;
+ char *admin_domain = NULL;
+ char *admin_account = NULL;
+ WERROR werr;
+ struct security_token *token = session_info->security_token;
+ NTSTATUS status;
+ DATA_BLOB session_key;
+ bool ok;
+
+ if (!r->in.account || !r->in.encrypted_password) {
+ return WERR_INVALID_PARAMETER;
+ }
+
+ if (!security_token_has_privilege(token, SEC_PRIV_MACHINE_ACCOUNT) &&
+ !nt_token_check_domain_rid(token, DOMAIN_RID_ADMINS) &&
+ !nt_token_check_sid(&global_sid_Builtin_Administrators, token)) {
+ DEBUG(5,("_wkssvc_NetrUnjoinDomain2: account doesn't have "
+ "sufficient privileges\n"));
+ return WERR_ACCESS_DENIED;
+ }
+
+ status = session_extract_session_key(session_info,
+ &session_key,
+ KEY_USE_16BYTES);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("_wkssvc_NetrUnjoinDomain2: no session key %s\n",
+ nt_errstr(status)));
+ return WERR_NO_USER_SESSION_KEY;
+ }
+
+ werr = decode_wkssvc_join_password_buffer(
+ p->mem_ctx, r->in.encrypted_password,
+ &session_key, &cleartext_pwd);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ ok = split_domain_user(p->mem_ctx,
+ r->in.account,
+ &admin_domain,
+ &admin_account);
+ if (!ok) {
+ return WERR_NOT_ENOUGH_MEMORY;
+ }
+
+ werr = libnet_init_UnjoinCtx(p->mem_ctx, &u);
+ if (!W_ERROR_IS_OK(werr)) {
+ return werr;
+ }
+
+ u->in.domain_name = lp_realm();
+ u->in.unjoin_flags = r->in.unjoin_flags |
+ WKSSVC_JOIN_FLAGS_JOIN_TYPE;
+ u->in.admin_account = admin_account;
+ u->in.admin_password = cleartext_pwd;
+ u->in.debug = true;
+ u->in.modify_config = lp_config_backend_is_registry();
+ u->in.msg_ctx = p->msg_ctx;
+
+ become_root();
+ setenv(KRB5_ENV_CCNAME, "MEMORY:_wkssvc_NetrUnjoinDomain2", 1);
+ werr = libnet_Unjoin(p->mem_ctx, u);
+ unsetenv(KRB5_ENV_CCNAME);
+ unbecome_root();
+
+ if (!W_ERROR_IS_OK(werr)) {
+ DEBUG(5,("_wkssvc_NetrUnjoinDomain2: libnet_Unjoin failed with: %s\n",
+ u->out.error_string ? u->out.error_string :
+ win_errstr(werr)));
+ }
+
+ TALLOC_FREE(u);
+ return werr;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrRenameMachineInDomain2(struct pipes_struct *p,
+ struct wkssvc_NetrRenameMachineInDomain2 *r)
+{
+ /* for now just return not supported */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrValidateName2(struct pipes_struct *p,
+ struct wkssvc_NetrValidateName2 *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrGetJoinableOus2(struct pipes_struct *p,
+ struct wkssvc_NetrGetJoinableOus2 *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrAddAlternateComputerName(struct pipes_struct *p,
+ struct wkssvc_NetrAddAlternateComputerName *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrRemoveAlternateComputerName(struct pipes_struct *p,
+ struct wkssvc_NetrRemoveAlternateComputerName *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrSetPrimaryComputername(struct pipes_struct *p,
+ struct wkssvc_NetrSetPrimaryComputername *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+WERROR _wkssvc_NetrEnumerateComputerNames(struct pipes_struct *p,
+ struct wkssvc_NetrEnumerateComputerNames *r)
+{
+ /* FIXME: Add implementation code here */
+ p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
+ return WERR_NOT_SUPPORTED;
+}
+
+/* include the generated boilerplate */
+#include "librpc/gen_ndr/ndr_wkssvc_scompat.c"