From 4063bde3edd15b241f2b93bb5aedfef57ec4df91 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Tue, 8 Feb 2011 14:17:14 +0100 Subject: s3-rpc_server: move services into individual directories. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guenther Autobuild-User: Günther Deschner Autobuild-Date: Thu Feb 10 22:13:17 CET 2011 on sn-devel-104 --- source3/rpc_server/dfs/srv_dfs_nt.c | 531 + source3/rpc_server/dssetup/srv_dssetup_nt.c | 224 + source3/rpc_server/echo/srv_echo_nt.c | 121 + source3/rpc_server/epmapper/srv_epmapper.c | 1038 ++ source3/rpc_server/eventlog/srv_eventlog_nt.c | 939 ++ source3/rpc_server/eventlog/srv_eventlog_reg.c | 266 + source3/rpc_server/eventlog/srv_eventlog_reg.h | 29 + .../rpc_server/initshutdown/srv_initshutdown_nt.c | 78 + source3/rpc_server/lsa/srv_lsa_nt.c | 2755 +++++ source3/rpc_server/netlogon/srv_netlog_nt.c | 2215 ++++ source3/rpc_server/ntsvcs/srv_ntsvcs_nt.c | 800 ++ source3/rpc_server/samr/srv_samr_chgpasswd.c | 1132 ++ source3/rpc_server/samr/srv_samr_nt.c | 6969 ++++++++++++ source3/rpc_server/samr/srv_samr_util.c | 714 ++ source3/rpc_server/samr/srv_samr_util.h | 77 + source3/rpc_server/spoolss/srv_spoolss_nt.c | 10658 +++++++++++++++++++ source3/rpc_server/spoolss/srv_spoolss_util.c | 4248 ++++++++ source3/rpc_server/spoolss/srv_spoolss_util.h | 590 + source3/rpc_server/srv_dfs_nt.c | 531 - source3/rpc_server/srv_dssetup_nt.c | 225 - source3/rpc_server/srv_echo_nt.c | 121 - source3/rpc_server/srv_epmapper.c | 1038 -- source3/rpc_server/srv_eventlog_nt.c | 939 -- source3/rpc_server/srv_eventlog_reg.c | 266 - source3/rpc_server/srv_eventlog_reg.h | 29 - source3/rpc_server/srv_initshutdown_nt.c | 78 - source3/rpc_server/srv_lsa_nt.c | 2755 ----- source3/rpc_server/srv_netlog_nt.c | 2215 ---- source3/rpc_server/srv_ntsvcs_nt.c | 801 -- source3/rpc_server/srv_rpc_register.c | 4 +- source3/rpc_server/srv_samr_chgpasswd.c | 1132 -- source3/rpc_server/srv_samr_nt.c | 6969 ------------ source3/rpc_server/srv_samr_util.c | 714 -- source3/rpc_server/srv_samr_util.h | 77 - source3/rpc_server/srv_spoolss_nt.c | 10658 ------------------- source3/rpc_server/srv_spoolss_util.c | 4249 -------- source3/rpc_server/srv_spoolss_util.h | 590 - source3/rpc_server/srv_srvsvc_nt.c | 2820 ----- source3/rpc_server/srv_svcctl_nt.c | 1202 --- source3/rpc_server/srv_svcctl_reg.c | 678 -- source3/rpc_server/srv_svcctl_reg.h | 29 - source3/rpc_server/srv_winreg_nt.c | 1142 -- source3/rpc_server/srv_wkssvc_nt.c | 1020 -- source3/rpc_server/srvsvc/srv_srvsvc_nt.c | 2819 +++++ source3/rpc_server/svcctl/srv_svcctl_nt.c | 1201 +++ source3/rpc_server/svcctl/srv_svcctl_reg.c | 678 ++ source3/rpc_server/svcctl/srv_svcctl_reg.h | 29 + source3/rpc_server/winreg/srv_winreg_nt.c | 1142 ++ source3/rpc_server/wkssvc/srv_wkssvc_nt.c | 1019 ++ source3/rpc_server/wscript_build | 36 +- 50 files changed, 40292 insertions(+), 40298 deletions(-) create mode 100644 source3/rpc_server/dfs/srv_dfs_nt.c create mode 100644 source3/rpc_server/dssetup/srv_dssetup_nt.c create mode 100644 source3/rpc_server/echo/srv_echo_nt.c create mode 100644 source3/rpc_server/epmapper/srv_epmapper.c create mode 100644 source3/rpc_server/eventlog/srv_eventlog_nt.c create mode 100644 source3/rpc_server/eventlog/srv_eventlog_reg.c create mode 100644 source3/rpc_server/eventlog/srv_eventlog_reg.h create mode 100644 source3/rpc_server/initshutdown/srv_initshutdown_nt.c create mode 100644 source3/rpc_server/lsa/srv_lsa_nt.c create mode 100644 source3/rpc_server/netlogon/srv_netlog_nt.c create mode 100644 source3/rpc_server/ntsvcs/srv_ntsvcs_nt.c create mode 100644 source3/rpc_server/samr/srv_samr_chgpasswd.c create mode 100644 source3/rpc_server/samr/srv_samr_nt.c create mode 100644 source3/rpc_server/samr/srv_samr_util.c create mode 100644 source3/rpc_server/samr/srv_samr_util.h create mode 100644 source3/rpc_server/spoolss/srv_spoolss_nt.c create mode 100644 source3/rpc_server/spoolss/srv_spoolss_util.c create mode 100644 source3/rpc_server/spoolss/srv_spoolss_util.h delete mode 100644 source3/rpc_server/srv_dfs_nt.c delete mode 100644 source3/rpc_server/srv_dssetup_nt.c delete mode 100644 source3/rpc_server/srv_echo_nt.c delete mode 100644 source3/rpc_server/srv_epmapper.c delete mode 100644 source3/rpc_server/srv_eventlog_nt.c delete mode 100644 source3/rpc_server/srv_eventlog_reg.c delete mode 100644 source3/rpc_server/srv_eventlog_reg.h delete mode 100644 source3/rpc_server/srv_initshutdown_nt.c delete mode 100644 source3/rpc_server/srv_lsa_nt.c delete mode 100644 source3/rpc_server/srv_netlog_nt.c delete mode 100644 source3/rpc_server/srv_ntsvcs_nt.c delete mode 100644 source3/rpc_server/srv_samr_chgpasswd.c delete mode 100644 source3/rpc_server/srv_samr_nt.c delete mode 100644 source3/rpc_server/srv_samr_util.c delete mode 100644 source3/rpc_server/srv_samr_util.h delete mode 100644 source3/rpc_server/srv_spoolss_nt.c delete mode 100644 source3/rpc_server/srv_spoolss_util.c delete mode 100644 source3/rpc_server/srv_spoolss_util.h delete mode 100644 source3/rpc_server/srv_srvsvc_nt.c delete mode 100644 source3/rpc_server/srv_svcctl_nt.c delete mode 100644 source3/rpc_server/srv_svcctl_reg.c delete mode 100644 source3/rpc_server/srv_svcctl_reg.h delete mode 100644 source3/rpc_server/srv_winreg_nt.c delete mode 100644 source3/rpc_server/srv_wkssvc_nt.c create mode 100644 source3/rpc_server/srvsvc/srv_srvsvc_nt.c create mode 100644 source3/rpc_server/svcctl/srv_svcctl_nt.c create mode 100644 source3/rpc_server/svcctl/srv_svcctl_reg.c create mode 100644 source3/rpc_server/svcctl/srv_svcctl_reg.h create mode 100644 source3/rpc_server/winreg/srv_winreg_nt.c create mode 100644 source3/rpc_server/wkssvc/srv_wkssvc_nt.c (limited to 'source3/rpc_server') diff --git a/source3/rpc_server/dfs/srv_dfs_nt.c b/source3/rpc_server/dfs/srv_dfs_nt.c new file mode 100644 index 0000000000..17b90505d6 --- /dev/null +++ b/source3/rpc_server/dfs/srv_dfs_nt.c @@ -0,0 +1,531 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines for Dfs + * Copyright (C) Shirish Kalele 2000. + * Copyright (C) Jeremy Allison 2001-2007. + * Copyright (C) Jelmer Vernooij 2005-2006. + * + * 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 . + */ + +/* This is the implementation of the dfs pipe. */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_dfs.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_MSDFS + +/* This function does not return a WERROR or NTSTATUS code but rather 1 if + dfs exists, or 0 otherwise. */ + +void _dfs_GetManagerVersion(struct pipes_struct *p, struct dfs_GetManagerVersion *r) +{ + if (lp_host_msdfs()) { + *r->out.version = DFS_MANAGER_VERSION_NT4; + } else { + *r->out.version = (enum dfs_ManagerVersion)0; + } +} + +WERROR _dfs_Add(struct pipes_struct *p, struct dfs_Add *r) +{ + struct junction_map *jn = NULL; + struct referral *old_referral_list = NULL; + bool self_ref = False; + int consumedcnt = 0; + char *altpath = NULL; + NTSTATUS status; + TALLOC_CTX *ctx = talloc_tos(); + + if (p->server_info->utok.uid != sec_initial_uid()) { + DEBUG(10,("_dfs_add: uid != 0. Access denied.\n")); + return WERR_ACCESS_DENIED; + } + + jn = TALLOC_ZERO_P(ctx, struct junction_map); + if (!jn) { + return WERR_NOMEM; + } + + DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n", + r->in.path, r->in.server, r->in.share)); + + altpath = talloc_asprintf(ctx, "%s\\%s", + r->in.server, + r->in.share); + if (!altpath) { + return WERR_NOMEM; + } + + /* The following call can change the cwd. */ + status = get_referred_path(ctx, r->in.path, jn, + &consumedcnt, &self_ref); + if(!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + jn->referral_count += 1; + old_referral_list = jn->referral_list; + + if (jn->referral_count < 1) { + return WERR_NOMEM; + } + + jn->referral_list = TALLOC_ARRAY(ctx, struct referral, jn->referral_count); + if(jn->referral_list == NULL) { + DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n")); + return WERR_DFS_INTERNAL_ERROR; + } + + if(old_referral_list && jn->referral_list) { + memcpy(jn->referral_list, old_referral_list, + sizeof(struct referral)*jn->referral_count-1); + } + + jn->referral_list[jn->referral_count-1].proximity = 0; + jn->referral_list[jn->referral_count-1].ttl = REFERRAL_TTL; + jn->referral_list[jn->referral_count-1].alternate_path = altpath; + + if(!create_msdfs_link(jn)) { + return WERR_DFS_CANT_CREATE_JUNCT; + } + + return WERR_OK; +} + +WERROR _dfs_Remove(struct pipes_struct *p, struct dfs_Remove *r) +{ + struct junction_map *jn = NULL; + bool self_ref = False; + int consumedcnt = 0; + bool found = False; + TALLOC_CTX *ctx = talloc_tos(); + char *altpath = NULL; + + if (p->server_info->utok.uid != sec_initial_uid()) { + DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n")); + return WERR_ACCESS_DENIED; + } + + jn = TALLOC_ZERO_P(ctx, struct junction_map); + if (!jn) { + return WERR_NOMEM; + } + + if (r->in.servername && r->in.sharename) { + altpath = talloc_asprintf(ctx, "%s\\%s", + r->in.servername, + r->in.sharename); + if (!altpath) { + return WERR_NOMEM; + } + strlower_m(altpath); + DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n", + r->in.dfs_entry_path, r->in.servername, r->in.sharename)); + } + + if(!NT_STATUS_IS_OK(get_referred_path(ctx, r->in.dfs_entry_path, jn, + &consumedcnt, &self_ref))) { + return WERR_DFS_NO_SUCH_VOL; + } + + /* if no server-share pair given, remove the msdfs link completely */ + if(!r->in.servername && !r->in.sharename) { + if(!remove_msdfs_link(jn)) { + return WERR_DFS_NO_SUCH_VOL; + } + } else { + int i=0; + /* compare each referral in the list with the one to remove */ + DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath, jn->referral_count)); + for(i=0;ireferral_count;i++) { + char *refpath = talloc_strdup(ctx, + jn->referral_list[i].alternate_path); + if (!refpath) { + return WERR_NOMEM; + } + trim_char(refpath, '\\', '\\'); + DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath)); + if(strequal(refpath, altpath)) { + *(jn->referral_list[i].alternate_path)='\0'; + DEBUG(10,("_dfs_remove: Removal request matches referral %s\n", + refpath)); + found = True; + } + } + + if(!found) { + return WERR_DFS_NO_SUCH_SHARE; + } + + /* Only one referral, remove it */ + if(jn->referral_count == 1) { + if(!remove_msdfs_link(jn)) { + return WERR_DFS_NO_SUCH_VOL; + } + } else { + if(!create_msdfs_link(jn)) { + return WERR_DFS_CANT_CREATE_JUNCT; + } + } + } + + return WERR_OK; +} + +static bool init_reply_dfs_info_1(TALLOC_CTX *mem_ctx, struct junction_map* j,struct dfs_Info1* dfs1) +{ + dfs1->path = talloc_asprintf(mem_ctx, + "\\\\%s\\%s\\%s", global_myname(), + j->service_name, j->volume_name); + if (dfs1->path == NULL) + return False; + + DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",dfs1->path)); + return True; +} + +static bool init_reply_dfs_info_2(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info2* dfs2) +{ + dfs2->path = talloc_asprintf(mem_ctx, + "\\\\%s\\%s\\%s", global_myname(), j->service_name, j->volume_name); + if (dfs2->path == NULL) + return False; + dfs2->comment = talloc_strdup(mem_ctx, j->comment); + dfs2->state = 1; /* set up state of dfs junction as OK */ + dfs2->num_stores = j->referral_count; + return True; +} + +static bool init_reply_dfs_info_3(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info3* dfs3) +{ + int ii; + if (j->volume_name[0] == '\0') + dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", + global_myname(), j->service_name); + else + dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s\\%s", global_myname(), + j->service_name, j->volume_name); + + if (dfs3->path == NULL) + return False; + + dfs3->comment = talloc_strdup(mem_ctx, j->comment); + dfs3->state = 1; + dfs3->num_stores = j->referral_count; + + /* also enumerate the stores */ + if (j->referral_count) { + dfs3->stores = TALLOC_ARRAY(mem_ctx, struct dfs_StorageInfo, j->referral_count); + if (!dfs3->stores) + return False; + memset(dfs3->stores, '\0', j->referral_count * sizeof(struct dfs_StorageInfo)); + } else { + dfs3->stores = NULL; + } + + for(ii=0;iireferral_count;ii++) { + char* p; + char *path = NULL; + struct dfs_StorageInfo* stor = &(dfs3->stores[ii]); + struct referral* ref = &(j->referral_list[ii]); + + path = talloc_strdup(mem_ctx, ref->alternate_path); + if (!path) { + return False; + } + trim_char(path,'\\','\0'); + p = strrchr_m(path,'\\'); + if(p==NULL) { + DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path)); + continue; + } + *p = '\0'; + DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1)); + stor->state = 2; /* set all stores as ONLINE */ + stor->server = talloc_strdup(mem_ctx, path); + stor->share = talloc_strdup(mem_ctx, p+1); + } + return True; +} + +static bool init_reply_dfs_info_100(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info100* dfs100) +{ + dfs100->comment = talloc_strdup(mem_ctx, j->comment); + return True; +} + +WERROR _dfs_Enum(struct pipes_struct *p, struct dfs_Enum *r) +{ + struct junction_map *jn = NULL; + size_t num_jn = 0; + size_t i; + TALLOC_CTX *ctx = talloc_tos(); + + jn = enum_msdfs_links(ctx, &num_jn); + if (!jn || num_jn == 0) { + num_jn = 0; + jn = NULL; + } + + DEBUG(5,("_dfs_Enum: %u junctions found in Dfs, doing level %d\n", + (unsigned int)num_jn, r->in.level)); + + *r->out.total = num_jn; + + /* Create the return array */ + switch (r->in.level) { + case 1: + if (num_jn) { + if ((r->out.info->e.info1->s = TALLOC_ARRAY(ctx, struct dfs_Info1, num_jn)) == NULL) { + return WERR_NOMEM; + } + } else { + r->out.info->e.info1->s = NULL; + } + r->out.info->e.info1->count = num_jn; + break; + case 2: + if (num_jn) { + if ((r->out.info->e.info2->s = TALLOC_ARRAY(ctx, struct dfs_Info2, num_jn)) == NULL) { + return WERR_NOMEM; + } + } else { + r->out.info->e.info2->s = NULL; + } + r->out.info->e.info2->count = num_jn; + break; + case 3: + if (num_jn) { + if ((r->out.info->e.info3->s = TALLOC_ARRAY(ctx, struct dfs_Info3, num_jn)) == NULL) { + return WERR_NOMEM; + } + } else { + r->out.info->e.info3->s = NULL; + } + r->out.info->e.info3->count = num_jn; + break; + default: + return WERR_INVALID_PARAM; + } + + for (i = 0; i < num_jn; i++) { + switch (r->in.level) { + case 1: + init_reply_dfs_info_1(ctx, &jn[i], &r->out.info->e.info1->s[i]); + break; + case 2: + init_reply_dfs_info_2(ctx, &jn[i], &r->out.info->e.info2->s[i]); + break; + case 3: + init_reply_dfs_info_3(ctx, &jn[i], &r->out.info->e.info3->s[i]); + break; + default: + return WERR_INVALID_PARAM; + } + } + + return WERR_OK; +} + +WERROR _dfs_GetInfo(struct pipes_struct *p, struct dfs_GetInfo *r) +{ + int consumedcnt = strlen(r->in.dfs_entry_path); + struct junction_map *jn = NULL; + bool self_ref = False; + TALLOC_CTX *ctx = talloc_tos(); + bool ret; + + jn = TALLOC_ZERO_P(ctx, struct junction_map); + if (!jn) { + return WERR_NOMEM; + } + + if(!create_junction(ctx, r->in.dfs_entry_path, jn)) { + return WERR_DFS_NO_SUCH_SERVER; + } + + /* The following call can change the cwd. */ + if(!NT_STATUS_IS_OK(get_referred_path(ctx, r->in.dfs_entry_path, + jn, &consumedcnt, &self_ref)) || + consumedcnt < strlen(r->in.dfs_entry_path)) { + return WERR_DFS_NO_SUCH_VOL; + } + + switch (r->in.level) { + case 1: + r->out.info->info1 = TALLOC_ZERO_P(ctx,struct dfs_Info1); + if (!r->out.info->info1) { + return WERR_NOMEM; + } + ret = init_reply_dfs_info_1(ctx, jn, r->out.info->info1); + break; + case 2: + r->out.info->info2 = TALLOC_ZERO_P(ctx,struct dfs_Info2); + if (!r->out.info->info2) { + return WERR_NOMEM; + } + ret = init_reply_dfs_info_2(ctx, jn, r->out.info->info2); + break; + case 3: + r->out.info->info3 = TALLOC_ZERO_P(ctx,struct dfs_Info3); + if (!r->out.info->info3) { + return WERR_NOMEM; + } + ret = init_reply_dfs_info_3(ctx, jn, r->out.info->info3); + break; + case 100: + r->out.info->info100 = TALLOC_ZERO_P(ctx,struct dfs_Info100); + if (!r->out.info->info100) { + return WERR_NOMEM; + } + ret = init_reply_dfs_info_100(ctx, jn, r->out.info->info100); + break; + default: + r->out.info->info1 = NULL; + return WERR_INVALID_PARAM; + } + + if (!ret) + return WERR_INVALID_PARAM; + + return WERR_OK; +} + +WERROR _dfs_SetInfo(struct pipes_struct *p, struct dfs_SetInfo *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Rename(struct pipes_struct *p, struct dfs_Rename *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Move(struct pipes_struct *p, struct dfs_Move *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_ManagerGetConfigInfo(struct pipes_struct *p, struct dfs_ManagerGetConfigInfo *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_ManagerSendSiteInfo(struct pipes_struct *p, struct dfs_ManagerSendSiteInfo *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_AddFtRoot(struct pipes_struct *p, struct dfs_AddFtRoot *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_RemoveFtRoot(struct pipes_struct *p, struct dfs_RemoveFtRoot *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_AddStdRoot(struct pipes_struct *p, struct dfs_AddStdRoot *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_RemoveStdRoot(struct pipes_struct *p, struct dfs_RemoveStdRoot *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_ManagerInitialize(struct pipes_struct *p, struct dfs_ManagerInitialize *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_AddStdRootForced(struct pipes_struct *p, struct dfs_AddStdRootForced *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_GetDcAddress(struct pipes_struct *p, struct dfs_GetDcAddress *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_SetDcAddress(struct pipes_struct *p, struct dfs_SetDcAddress *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_FlushFtTable(struct pipes_struct *p, struct dfs_FlushFtTable *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Add2(struct pipes_struct *p, struct dfs_Add2 *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_Remove2(struct pipes_struct *p, struct dfs_Remove2 *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_EnumEx(struct pipes_struct *p, struct dfs_EnumEx *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _dfs_SetInfo2(struct pipes_struct *p, struct dfs_SetInfo2 *r) +{ + /* FIXME: Implement your code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} diff --git a/source3/rpc_server/dssetup/srv_dssetup_nt.c b/source3/rpc_server/dssetup/srv_dssetup_nt.c new file mode 100644 index 0000000000..53a3bdd8c4 --- /dev/null +++ b/source3/rpc_server/dssetup/srv_dssetup_nt.c @@ -0,0 +1,224 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997. + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997. + * Copyright (C) Paul Ashton 1997. + * Copyright (C) Jeremy Allison 2001. + * Copyright (C) Gerald Carter 2002. + * Copyright (C) Guenther Deschner 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 . + */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_dssetup.h" +#include "secrets.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +/******************************************************************** + Fill in a dssetup_DsRolePrimaryDomInfoBasic structure + ********************************************************************/ + +static WERROR fill_dsrole_dominfo_basic(TALLOC_CTX *ctx, + struct dssetup_DsRolePrimaryDomInfoBasic **info) +{ + struct dssetup_DsRolePrimaryDomInfoBasic *basic = NULL; + char *dnsdomain = NULL; + + DEBUG(10,("fill_dsrole_dominfo_basic: enter\n")); + + basic = TALLOC_ZERO_P(ctx, struct dssetup_DsRolePrimaryDomInfoBasic); + if (!basic) { + DEBUG(0,("fill_dsrole_dominfo_basic: out of memory\n")); + return WERR_NOMEM; + } + + switch (lp_server_role()) { + case ROLE_STANDALONE: + basic->role = DS_ROLE_STANDALONE_SERVER; + basic->domain = get_global_sam_name(); + break; + case ROLE_DOMAIN_MEMBER: + basic->role = DS_ROLE_MEMBER_SERVER; + basic->domain = lp_workgroup(); + break; + case ROLE_DOMAIN_BDC: + basic->role = DS_ROLE_BACKUP_DC; + basic->domain = get_global_sam_name(); + break; + case ROLE_DOMAIN_PDC: + basic->role = DS_ROLE_PRIMARY_DC; + basic->domain = get_global_sam_name(); + break; + } + + if (secrets_fetch_domain_guid(lp_workgroup(), &basic->domain_guid)) { + basic->flags |= DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT; + } + + /* fill in some additional fields if we are a member of an AD domain */ + + if (lp_security() == SEC_ADS) { + dnsdomain = talloc_strdup(ctx, lp_realm()); + if (!dnsdomain) { + return WERR_NOMEM; + } + strlower_m(dnsdomain); + basic->dns_domain = dnsdomain; + + /* FIXME!! We really should fill in the correct forest + name. Should get this information from winbindd. */ + basic->forest = dnsdomain; + } else { + /* security = domain should not fill in the dns or + forest name */ + basic->dns_domain = NULL; + basic->forest = NULL; + } + + *info = basic; + + return WERR_OK; +} + +/******************************************************************** + Implement the _dssetup_DsRoleGetPrimaryDomainInformation() call + ********************************************************************/ + +WERROR _dssetup_DsRoleGetPrimaryDomainInformation(struct pipes_struct *p, + struct dssetup_DsRoleGetPrimaryDomainInformation *r) +{ + WERROR werr = WERR_OK; + + switch (r->in.level) { + + case DS_ROLE_BASIC_INFORMATION: { + struct dssetup_DsRolePrimaryDomInfoBasic *basic = NULL; + werr = fill_dsrole_dominfo_basic(p->mem_ctx, &basic); + if (W_ERROR_IS_OK(werr)) { + r->out.info->basic = *basic; + } + break; + } + default: + DEBUG(0,("_dssetup_DsRoleGetPrimaryDomainInformation: " + "Unknown info level [%d]!\n", r->in.level)); + werr = WERR_UNKNOWN_LEVEL; + } + + return werr; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleDnsNameToFlatName(struct pipes_struct *p, + struct dssetup_DsRoleDnsNameToFlatName *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleDcAsDc(struct pipes_struct *p, + struct dssetup_DsRoleDcAsDc *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleDcAsReplica(struct pipes_struct *p, + struct dssetup_DsRoleDcAsReplica *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleDemoteDc(struct pipes_struct *p, + struct dssetup_DsRoleDemoteDc *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleGetDcOperationProgress(struct pipes_struct *p, + struct dssetup_DsRoleGetDcOperationProgress *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleGetDcOperationResults(struct pipes_struct *p, + struct dssetup_DsRoleGetDcOperationResults *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleCancel(struct pipes_struct *p, + struct dssetup_DsRoleCancel *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleServerSaveStateForUpgrade(struct pipes_struct *p, + struct dssetup_DsRoleServerSaveStateForUpgrade *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleUpgradeDownlevelServer(struct pipes_struct *p, + struct dssetup_DsRoleUpgradeDownlevelServer *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _dssetup_DsRoleAbortDownlevelServerUpgrade(struct pipes_struct *p, + struct dssetup_DsRoleAbortDownlevelServerUpgrade *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} diff --git a/source3/rpc_server/echo/srv_echo_nt.c b/source3/rpc_server/echo/srv_echo_nt.c new file mode 100644 index 0000000000..47952ef0b8 --- /dev/null +++ b/source3/rpc_server/echo/srv_echo_nt.c @@ -0,0 +1,121 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines for rpcecho + * Copyright (C) Tim Potter 2003 + * Copyright (C) Jelmer Vernooij 2006 + * Copyright (C) Gerald (Jerry) Carter 2007 + * + * 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 . + */ + +/* This is the interface to the rpcecho pipe. */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_echo.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +/* Add one to the input and return it */ + +void _echo_AddOne(struct pipes_struct *p, struct echo_AddOne *r ) +{ + DEBUG(10, ("_echo_AddOne\n")); + + *r->out.out_data = r->in.in_data + 1; +} + +/* Echo back an array of data */ + +void _echo_EchoData(struct pipes_struct *p, struct echo_EchoData *r) +{ + DEBUG(10, ("_echo_EchoData\n")); + + if ( r->in.len == 0 ) { + r->out.out_data = NULL; + return; + } + + r->out.out_data = TALLOC_ARRAY(p->mem_ctx, uint8, r->in.len); + memcpy( r->out.out_data, r->in.in_data, r->in.len ); + return; +} + +/* Sink an array of data */ + +void _echo_SinkData(struct pipes_struct *p, struct echo_SinkData *r) +{ + DEBUG(10, ("_echo_SinkData\n")); + + /* My that was some yummy data! */ + return; +} + +/* Source an array of data */ + +void _echo_SourceData(struct pipes_struct *p, struct echo_SourceData *r) +{ + uint32 i; + + DEBUG(10, ("_echo_SourceData\n")); + + if ( r->in.len == 0 ) { + r->out.data = NULL; + return; + } + + r->out.data = TALLOC_ARRAY(p->mem_ctx, uint8, r->in.len ); + + for (i = 0; i < r->in.len; i++ ) { + r->out.data[i] = i & 0xff; + } + + return; +} + +void _echo_TestCall(struct pipes_struct *p, struct echo_TestCall *r) +{ + p->rng_fault_state = True; + return; +} + +NTSTATUS _echo_TestCall2(struct pipes_struct *p, struct echo_TestCall2 *r) +{ + p->rng_fault_state = True; + return NT_STATUS_OK; +} + +uint32 _echo_TestSleep(struct pipes_struct *p, struct echo_TestSleep *r) +{ + smb_msleep(r->in.seconds * 1000); + return 0; +} + +void _echo_TestEnum(struct pipes_struct *p, struct echo_TestEnum *r) +{ + p->rng_fault_state = True; + return; +} + +void _echo_TestSurrounding(struct pipes_struct *p, struct echo_TestSurrounding *r) +{ + p->rng_fault_state = True; + return; +} + +uint16 _echo_TestDoublePointer(struct pipes_struct *p, struct echo_TestDoublePointer *r) +{ + p->rng_fault_state = True; + return 0; +} diff --git a/source3/rpc_server/epmapper/srv_epmapper.c b/source3/rpc_server/epmapper/srv_epmapper.c new file mode 100644 index 0000000000..5bfb176b84 --- /dev/null +++ b/source3/rpc_server/epmapper/srv_epmapper.c @@ -0,0 +1,1038 @@ +/* + Unix SMB/CIFS implementation. + + Endpoint server for the epmapper pipe + + Copyright (C) 2010-2011 Andreas Schneider + + 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 . +*/ + +#include "includes.h" +#include "../libcli/security/security.h" +#include "librpc/gen_ndr/ndr_epmapper.h" +#include "librpc/gen_ndr/srv_epmapper.h" + +typedef uint32_t error_status_t; + +/* An endpoint combined with an interface description */ +struct dcesrv_ep_iface { + const char *name; + struct ndr_syntax_id syntax_id; + struct epm_tower ep; +}; + +/* A rpc service interface like samr, lsarpc or netlogon */ +struct dcesrv_iface { + const char *name; + struct ndr_syntax_id syntax_id; +}; + +struct dcesrv_iface_list { + struct dcesrv_iface_list *next, *prev; + struct dcesrv_iface *iface; +}; + +/* + * An endpoint can serve multiple rpc services interfaces. + * For example \\pipe\netlogon can be used by lsarpc and netlogon. + */ +struct dcesrv_endpoint { + struct dcesrv_endpoint *next, *prev; + + /* The type and the location of the endpoint */ + struct dcerpc_binding *ep_description; + + /* A list of rpc services able to connect to the endpoint */ + struct dcesrv_iface_list *iface_list; +}; + +struct rpc_eps { + struct dcesrv_ep_iface *e; + uint32_t count; +}; + +static struct dcesrv_endpoint *endpoint_table; + +/* + * Check if the UUID and if_version match to an interface. + */ +static bool interface_match(const struct dcesrv_iface *if1, + const struct dcesrv_iface *if2) +{ + return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid); +} + +/* + * Find the interface operations on an endpoint. + */ +static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint, + const struct dcesrv_iface *iface) +{ + struct dcesrv_iface_list *iflist; + + for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) { + if (interface_match(iflist->iface, iface)) { + return iflist->iface; + } + } + + return NULL; +} + +/* + * See if a uuid and if_version match to an interface + */ +static bool interface_match_by_uuid(const struct dcesrv_iface *iface, + const struct GUID *uuid) +{ + return GUID_equal(&iface->syntax_id.uuid, uuid); +} + +static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint, + const struct dcesrv_iface *iface) +{ + struct dcesrv_iface_list *iflist; + + for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) { + if (interface_match(iflist->iface, iface)) { + return iflist; + } + } + + return NULL; +} + +/* + * Check if two endpoints match. + */ +static bool endpoints_match(const struct dcerpc_binding *ep1, + const struct dcerpc_binding *ep2) +{ + if (ep1->transport != ep2->transport) { + return false; + } + + if (!ep1->endpoint || !ep2->endpoint) { + return ep1->endpoint == ep2->endpoint; + } + + if (!strequal(ep1->endpoint, ep2->endpoint)) { + return false; + } + + return true; +} + +static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list, + struct dcerpc_binding *ep_description) { + struct dcesrv_endpoint *ep; + + for (ep = endpoint_list; ep != NULL; ep = ep->next) { + if (endpoints_match(ep->ep_description, ep_description)) { + return ep; + } + } + + return NULL; +} + +/* + * Build a list of all interfaces handled by all endpoint servers. + */ +static uint32_t build_ep_list(TALLOC_CTX *mem_ctx, + struct dcesrv_endpoint *endpoint_list, + const struct GUID *uuid, + struct dcesrv_ep_iface **peps) +{ + struct dcesrv_ep_iface *eps = NULL; + struct dcesrv_endpoint *d; + uint32_t total = 0; + NTSTATUS status; + + *peps = NULL; + + for (d = endpoint_list; d != NULL; d = d->next) { + struct dcesrv_iface_list *iface; + struct dcerpc_binding *description; + + for (iface = d->iface_list; iface != NULL; iface = iface->next) { + if (uuid && !interface_match_by_uuid(iface->iface, uuid)) { + continue; + } + + eps = talloc_realloc(mem_ctx, + eps, + struct dcesrv_ep_iface, + total + 1); + if (eps == NULL) { + return 0; + } + eps[total].name = talloc_strdup(eps, + iface->iface->name); + eps[total].syntax_id = iface->iface->syntax_id; + + description = d->ep_description; + description->object = iface->iface->syntax_id; + + status = dcerpc_binding_build_tower(eps, + description, + &eps[total].ep); + if (NT_STATUS_IS_ERR(status)) { + DEBUG(1, ("Unable to build tower for %s\n", + iface->iface->name)); + continue; + } + total++; + } + } + + *peps = eps; + + return total; +} + +static bool is_priviledged_pipe(struct auth_serversupplied_info *info) { + /* If the user is not root, or has the system token, fail */ + if ((info->utok.uid != sec_initial_uid()) && + !security_token_is_system(info->security_token)) { + return false; + } + + return true; +} + +/* + * epm_Insert + * + * Add the specified entries to an endpoint map. + */ +error_status_t _epm_Insert(struct pipes_struct *p, + struct epm_Insert *r) +{ + TALLOC_CTX *tmp_ctx; + error_status_t rc; + NTSTATUS status; + uint32_t i; + + /* If this is not a priviledged users, return */ + if (!is_priviledged_pipe(p->server_info)) { + return EPMAPPER_STATUS_CANT_PERFORM_OP; + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return EPMAPPER_STATUS_NO_MEMORY; + } + + DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n", + r->in.num_ents)); + + for (i = 0; i < r->in.num_ents; i++) { + struct dcerpc_binding *b = NULL; + struct dcesrv_endpoint *ep; + struct dcesrv_iface_list *iflist; + struct dcesrv_iface *iface; + bool add_ep = false; + + status = dcerpc_binding_from_tower(tmp_ctx, + &r->in.entries[i].tower->tower, + &b); + if (!NT_STATUS_IS_OK(status)) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n", + derpc_transport_string_by_transport(b->transport), + r->in.entries[i].annotation)); + + /* Check if the entry already exits */ + ep = find_endpoint(endpoint_table, b); + if (ep == NULL) { + /* No entry found, create it */ + ep = talloc_zero(NULL, struct dcesrv_endpoint); + if (ep == NULL) { + rc = EPMAPPER_STATUS_CANT_PERFORM_OP; + goto done; + } + add_ep = true; + + ep->ep_description = talloc_steal(ep, b); + } + + /* TODO Replace the entry if the replace flag is set */ + + /* Create an interface */ + iface = talloc(tmp_ctx, struct dcesrv_iface); + if (iface == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + iface->name = talloc_strdup(iface, r->in.entries[i].annotation); + if (iface->name == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + iface->syntax_id = b->object; + + /* + * Check if the rpc service is alrady registered on the + * endpoint. + */ + if (find_interface(ep, iface) != NULL) { + DEBUG(0, ("dcesrv_interface_register: interface '%s' " + "already registered on endpoint\n", + iface->name)); + /* FIXME wrong error code? */ + rc = EPMAPPER_STATUS_OK; + goto done; + } + + /* Create an entry for the interface */ + iflist = talloc(ep, struct dcesrv_iface_list); + if (iflist == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + iflist->iface = talloc_move(iflist, &iface); + + /* Finally add the interface on the endpoint */ + DLIST_ADD(ep->iface_list, iflist); + + /* If it's a new endpoint add it to the endpoint_table */ + if (add_ep) { + DLIST_ADD(endpoint_table, ep); + } + } + + rc = EPMAPPER_STATUS_OK; +done: + talloc_free(tmp_ctx); + + return rc; +} + + +/* + * epm_Delete + * + * Delete the specified entries from an endpoint map. + */ +error_status_t _epm_Delete(struct pipes_struct *p, + struct epm_Delete *r) +{ + TALLOC_CTX *tmp_ctx; + error_status_t rc; + NTSTATUS status; + uint32_t i; + + DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n", + r->in.num_ents)); + + /* If this is not a priviledged users, return */ + if (!is_priviledged_pipe(p->server_info)) { + return EPMAPPER_STATUS_CANT_PERFORM_OP; + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return EPMAPPER_STATUS_NO_MEMORY; + } + + for (i = 0; i < r->in.num_ents; i++) { + struct dcerpc_binding *b = NULL; + struct dcesrv_endpoint *ep; + struct dcesrv_iface iface; + struct dcesrv_iface_list *iflist; + + status = dcerpc_binding_from_tower(tmp_ctx, + &r->in.entries[i].tower->tower, + &b); + if (!NT_STATUS_IS_OK(status)) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n", + derpc_transport_string_by_transport(b->transport), + r->in.entries[i].annotation)); + + ep = find_endpoint(endpoint_table, b); + if (ep == NULL) { + rc = EPMAPPER_STATUS_OK; + goto done; + } + + iface.name = r->in.entries[i].annotation; + iface.syntax_id = b->object; + + iflist = find_interface_list(ep, &iface); + if (iflist == NULL) { + DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n")); + DLIST_REMOVE(endpoint_table, ep); + talloc_free(ep); + + rc = EPMAPPER_STATUS_OK; + goto done; + } + + DLIST_REMOVE(ep->iface_list, iflist); + + if (ep->iface_list == NULL) { + DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n")); + DLIST_REMOVE(endpoint_table, ep); + talloc_free(ep); + + rc = EPMAPPER_STATUS_OK; + goto done; + } + + } + + rc = EPMAPPER_STATUS_OK; +done: + talloc_free(tmp_ctx); + + return rc; +} + + +/* + * epm_Lookup + * + * Lookup entries in an endpoint map. + */ +error_status_t _epm_Lookup(struct pipes_struct *p, + struct epm_Lookup *r) +{ + struct policy_handle *entry_handle; + struct rpc_eps *eps; + TALLOC_CTX *tmp_ctx; + error_status_t rc; + uint32_t count = 0; + uint32_t num_ents = 0; + uint32_t i; + bool match = false; + bool ok; + + *r->out.num_ents = 0; + r->out.entries = NULL; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return EPMAPPER_STATUS_NO_MEMORY; + } + + DEBUG(3, ("_epm_Lookup: Trying to lookup max. %u entries.\n", + r->in.max_ents)); + + if (r->in.entry_handle == NULL || + policy_handle_empty(r->in.entry_handle)) { + struct GUID *obj; + + DEBUG(5, ("_epm_Lookup: No entry_handle found, creating it.\n")); + + eps = talloc_zero(tmp_ctx, struct rpc_eps); + if (eps == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + if (r->in.object == NULL || GUID_all_zero(r->in.object)) { + obj = NULL; + } else { + obj = r->in.object; + } + + switch (r->in.inquiry_type) { + case RPC_C_EP_ALL_ELTS: + /* + * Return all elements from the endpoint map. The + * interface_id, vers_option, and object parameters MUST + * be ignored. + */ + eps->count = build_ep_list(eps, + endpoint_table, + NULL, + &eps->e); + break; + case RPC_C_EP_MATCH_BY_IF: + /* + * Return endpoint map elements that contain the + * interface identifier specified by the interface_id + * and vers_option values. + * + * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH + * need both the same endpoint list. There is a second + * check for the inquiry_type below which differentiates + * between them. + */ + case RPC_C_EP_MATCH_BY_BOTH: + /* + * Return endpoint map elements that contain the + * interface identifier and object UUID specified by + * interface_id, vers_option, and object. + */ + eps->count = build_ep_list(eps, + endpoint_table, + &r->in.interface_id->uuid, + &eps->e); + break; + case RPC_C_EP_MATCH_BY_OBJ: + /* + * Return endpoint map elements that contain the object + * UUID specified by object. + */ + eps->count = build_ep_list(eps, + endpoint_table, + r->in.object, + &eps->e); + break; + default: + rc = EPMAPPER_STATUS_CANT_PERFORM_OP; + goto done; + } + + if (eps->count == 0) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + ok = create_policy_hnd(p, r->out.entry_handle, eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + entry_handle = r->out.entry_handle; + } else { + DEBUG(5, ("_epm_Lookup: Trying to find entry_handle.\n")); + + ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + entry_handle = r->in.entry_handle; + } + + if (eps == NULL || eps->e == NULL) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + /* return the next N elements */ + count = r->in.max_ents; + if (count > eps->count) { + count = eps->count; + } + + DEBUG(3, ("_epm_Lookup: Find %u entries\n", count)); + + if (count == 0) { + close_policy_hnd(p, entry_handle); + ZERO_STRUCTP(r->out.entry_handle); + + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count); + if (r->out.entries == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < count; i++) { + match = false; + + switch (r->in.inquiry_type) { + case RPC_C_EP_ALL_ELTS: + /* + * Return all elements from the endpoint map. The + * interface_id, vers_option, and object parameters MUST + * be ignored. + */ + match = true; + break; + case RPC_C_EP_MATCH_BY_IF: + /* + * Return endpoint map elements that contain the + * interface identifier specified by the interface_id + * and vers_option values. + */ + if (GUID_equal(&r->in.interface_id->uuid, + &eps->e[i].syntax_id.uuid)) { + match = true; + } + break; + case RPC_C_EP_MATCH_BY_OBJ: + /* + * Return endpoint map elements that contain the object + * UUID specified by object. + */ + if (GUID_equal(r->in.object, + &eps->e[i].syntax_id.uuid)) { + match = true; + } + break; + case RPC_C_EP_MATCH_BY_BOTH: + /* + * Return endpoint map elements that contain the + * interface identifier and object UUID specified by + * interface_id, vers_option, and object. + */ + if (GUID_equal(&r->in.interface_id->uuid, + &eps->e[i].syntax_id.uuid) && + GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) { + match = true; + } + break; + default: + return EPMAPPER_STATUS_CANT_PERFORM_OP; + } + + if (match) { + if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF || + r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) { + /* Check inteface version */ + + match = false; + switch (r->in.vers_option) { + case RPC_C_VERS_ALL: + /* + * Return endpoint map elements that + * contain the specified interface UUID, + * regardless of the version numbers. + */ + match = true; + break; + case RPC_C_VERS_COMPATIBLE: + /* + * Return the endpoint map elements that + * contain the same major versions of + * the specified interface UUID and a + * minor version greater than or equal + * to the minor version of the specified + * UUID. + */ + if (r->in.interface_id->vers_major == + (eps->e[i].syntax_id.if_version >> 16) && + r->in.interface_id->vers_minor <= + (eps->e[i].syntax_id.if_version && 0xFFFF)) { + match = true; + } + break; + case RPC_C_VERS_EXACT: + /* + * Return endpoint map elements that + * contain the specified version of the + * specified interface UUID. + */ + if (r->in.interface_id->vers_major == + (eps->e[i].syntax_id.if_version >> 16) && + r->in.interface_id->vers_minor == + (eps->e[i].syntax_id.if_version && 0xFFFF)) { + match = true; + } + match = true; + break; + case RPC_C_VERS_MAJOR_ONLY: + /* + * Return endpoint map elements that + * contain the same version of the + * specified interface UUID and ignore + * the minor version. + */ + if (r->in.interface_id->vers_major == + (eps->e[i].syntax_id.if_version >> 16)) { + match = true; + } + match = true; + break; + case RPC_C_VERS_UPTO: + /* + * Return endpoint map elements that + * contain a version of the specified + * interface UUID less than or equal to + * the specified major and minor + * version. + */ + if (r->in.interface_id->vers_major > + eps->e[i].syntax_id.if_version >> 16) { + match = true; + } else { + if (r->in.interface_id->vers_major == + (eps->e[i].syntax_id.if_version >> 16) && + r->in.interface_id->vers_minor >= + (eps->e[i].syntax_id.if_version && 0xFFFF)) { + match = true; + } + } + break; + default: + return EPMAPPER_STATUS_CANT_PERFORM_OP; + } + } + } + + if (match) { + ZERO_STRUCT(r->out.entries[num_ents].object); + + DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n", + eps->e[i].name)); + r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries, + eps->e[i].name); + r->out.entries[num_ents].tower = talloc(r->out.entries, + struct epm_twr_t); + if (r->out.entries[num_ents].tower == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors); + r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors; + r->out.entries[num_ents].tower->tower_length = 0; + + num_ents++; + } + } /* end for loop */ + + *r->out.num_ents = num_ents; + + eps->count -= count; + eps->e += count; + if (eps->count == 0) { + close_policy_hnd(p, entry_handle); + ZERO_STRUCTP(r->out.entry_handle); + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + rc = EPMAPPER_STATUS_OK; +done: + talloc_free(tmp_ctx); + + return rc; +} + +/* + * epm_Map + * + * Apply some algorithm (using the fields in the map_tower) to an endpoint map + * to produce a list of protocol towers. + */ +error_status_t _epm_Map(struct pipes_struct *p, + struct epm_Map *r) +{ + struct policy_handle *entry_handle; + enum dcerpc_transport_t transport; + struct ndr_syntax_id ifid; + struct epm_floor *floors; + struct rpc_eps *eps; + TALLOC_CTX *tmp_ctx; + error_status_t rc; + uint32_t count = 0; + uint32_t num_towers = 0; + uint32_t num_floors = 0; + uint32_t i; + bool ok; + + *r->out.num_towers = 0; + r->out.towers = NULL; + + if (r->in.map_tower == NULL || r->in.max_towers == 0 || + r->in.map_tower->tower.num_floors < 3) { + return EPMAPPER_STATUS_NO_MORE_ENTRIES; + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return EPMAPPER_STATUS_NO_MEMORY; + } + + ZERO_STRUCTP(r->out.entry_handle); + + DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n", + r->in.max_towers)); + + /* + * A tower has normally up to 6 floors + * + * +-----------------------------------------------------------------+ + * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for | + * | | netlogon) | + * +---------+-------------------------------------------------------+ + * | Floor 2 | Transfer syntax (NDR endcoded) | + * +---------+-------------------------------------------------------+ + * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) | + * +---------+-------------------------------------------------------+ + * | Floor 4 | Port address (e.g. TCP Port: 49156) | + * +---------+-------------------------------------------------------+ + * | Floor 5 | Transport (e.g. IP:192.168.51.10) | + * +---------+-------------------------------------------------------+ + * | Floor 6 | Routing | + * +---------+-------------------------------------------------------+ + */ + num_floors = r->in.map_tower->tower.num_floors; + floors = r->in.map_tower->tower.floors; + + /* We accept NDR as the transfer syntax */ + dcerpc_floor_get_lhs_data(&floors[1], &ifid); + + if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID || + !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) || + ifid.if_version != ndr_transfer_syntax.if_version) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + /* We only talk to sane transports */ + transport = dcerpc_transport_by_tower(&r->in.map_tower->tower); + if (transport == NCA_UNKNOWN) { + DEBUG(2, ("epm_Map: Client requested unknown transport with" + "levels: ")); + for (i = 2; i < r->in.map_tower->tower.num_floors; i++) { + DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol)); + } + DEBUG(2, ("\n")); + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + if (r->in.entry_handle == NULL || + policy_handle_empty(r->in.entry_handle)) { + struct GUID *obj; + + DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n")); + + eps = talloc_zero(tmp_ctx, struct rpc_eps); + if (eps == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + /* + * *** ATTENTION *** + * CDE 1.1 states: + * + * ept_map() + * Apply some algorithm (using the fields in the map_tower) + * to an endpoint map to produce a list of protocol towers. + * + * The following code is the mysterious "some algorithm"! + */ + + /* Filter by object id if one was given. */ + if (r->in.object == NULL || GUID_all_zero(r->in.object)) { + obj = NULL; + } else { + obj = r->in.object; + } + + eps->count = build_ep_list(eps, + endpoint_table, + obj, + &eps->e); + if (eps->count == 0) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + /* Filter out endpoints which match the interface. */ + { + struct rpc_eps *teps; + uint32_t total = 0; + + teps = talloc_zero(tmp_ctx, struct rpc_eps); + if (teps == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < eps->count; i++) { + if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data, + &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 || + transport != dcerpc_transport_by_tower(&eps->e[i].ep)) { + continue; + } + + teps->e = talloc_realloc(tmp_ctx, + teps->e, + struct dcesrv_ep_iface, + total + 1); + if (teps->e == NULL) { + return 0; + } + + teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors); + teps->e[total].ep.num_floors = eps->e[i].ep.num_floors; + teps->e[total].name = talloc_move(teps, &eps->e[i].name); + teps->e[total].syntax_id = eps->e[i].syntax_id; + + total++; + } + + teps->count = total; + talloc_free(eps); + eps = teps; + } + /* end of "some algorithm" */ + + ok = create_policy_hnd(p, r->out.entry_handle, eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + entry_handle = r->out.entry_handle; + } else { + DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n")); + + ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + entry_handle = r->in.entry_handle; + } + + if (eps == NULL || eps->e == NULL) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + /* return the next N elements */ + count = r->in.max_towers; + if (count > eps->count) { + count = eps->count; + } + + if (count == 0) { + close_policy_hnd(p, entry_handle); + ZERO_STRUCTP(r->out.entry_handle); + + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count); + if (r->out.towers == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < count; i++) { + DEBUG(5, ("_epm_Map: Map tower for '%s'\n", + eps->e[i].name)); + + r->out.towers[num_towers].twr = talloc(r->out.towers, + struct epm_twr_t); + if (r->out.towers[num_towers].twr == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors); + r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors; + r->out.towers[num_towers].twr->tower_length = 0; + + num_towers++; + } + + *r->out.num_towers = num_towers; + + eps->count -= count; + eps->e += count; + if (eps->count == 0) { + close_policy_hnd(p, entry_handle); + ZERO_STRUCTP(r->out.entry_handle); + } + + rc = EPMAPPER_STATUS_OK; +done: + talloc_free(tmp_ctx); + + return rc; +} + +/* + * epm_LookupHandleFree + */ +error_status_t _epm_LookupHandleFree(struct pipes_struct *p, + struct epm_LookupHandleFree *r) +{ + if (r->in.entry_handle == NULL) { + return EPMAPPER_STATUS_OK; + } + + if (is_valid_policy_hnd(r->in.entry_handle)) { + close_policy_hnd(p, r->in.entry_handle); + } + + r->out.entry_handle = r->in.entry_handle; + + return EPMAPPER_STATUS_OK; +} + + +/* + * epm_InqObject + * + * A client implementation SHOULD NOT call this method. These extensions do not + * provide an alternative method. + */ +error_status_t _epm_InqObject(struct pipes_struct *p, + struct epm_InqObject *r) +{ + p->rng_fault_state = true; + return EPMAPPER_STATUS_CANT_PERFORM_OP; +} + + +/* + * epm_MgmtDelete + * + * A client implementation SHOULD NOT call this method. These extensions do not + * provide an alternative method. +*/ +error_status_t _epm_MgmtDelete(struct pipes_struct *p, + struct epm_MgmtDelete *r) +{ + p->rng_fault_state = true; + return EPMAPPER_STATUS_CANT_PERFORM_OP; +} + + +/* + epm_MapAuth +*/ +error_status_t _epm_MapAuth(struct pipes_struct *p, + struct epm_MapAuth *r) +{ + p->rng_fault_state = true; + return EPMAPPER_STATUS_CANT_PERFORM_OP; +} + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/eventlog/srv_eventlog_nt.c b/source3/rpc_server/eventlog/srv_eventlog_nt.c new file mode 100644 index 0000000000..ff8a49526e --- /dev/null +++ b/source3/rpc_server/eventlog/srv_eventlog_nt.c @@ -0,0 +1,939 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Marcin Krzysztof Porwit 2005, + * Copyright (C) Brian Moran 2005, + * Copyright (C) Gerald (Jerry) Carter 2005. + * Copyright (C) Guenther Deschner 2009. + * + * 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 . + */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_eventlog.h" +#include "lib/eventlog/eventlog.h" +#include "registry.h" +#include "../libcli/security/security.h" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "rpc_client/cli_winreg_int.h" +#include "rpc_client/cli_winreg.h" + + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +#define TOP_LEVEL_EVENTLOG_KEY "SYSTEM\\CurrentControlSet\\Services\\Eventlog" + +typedef struct { + char *logname; + ELOG_TDB *etdb; + uint32 current_record; + uint32 num_records; + uint32 oldest_entry; + uint32 flags; + uint32 access_granted; +} EVENTLOG_INFO; + +/******************************************************************** + ********************************************************************/ + +static int eventlog_info_destructor(EVENTLOG_INFO *elog) +{ + if (elog->etdb) { + elog_close_tdb(elog->etdb, false); + } + return 0; +} + +/******************************************************************** + ********************************************************************/ + +static EVENTLOG_INFO *find_eventlog_info_by_hnd( struct pipes_struct * p, + struct policy_handle * handle ) +{ + EVENTLOG_INFO *info; + + if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) { + DEBUG( 2, + ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) ); + return NULL; + } + + return info; +} + +/******************************************************************** +********************************************************************/ + +static bool elog_check_access( EVENTLOG_INFO *info, const struct security_token *token ) +{ + char *tdbname = elog_tdbname(talloc_tos(), info->logname ); + struct security_descriptor *sec_desc; + struct security_ace *ace; + NTSTATUS status; + + if ( !tdbname ) + return False; + + /* get the security descriptor for the file */ + + sec_desc = get_nt_acl_no_snum( info, tdbname ); + TALLOC_FREE( tdbname ); + + if ( !sec_desc ) { + DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n", + tdbname)); + return False; + } + + ace = talloc_zero(sec_desc, struct security_ace); + if (ace == NULL) { + TALLOC_FREE(sec_desc); + return false; + } + + ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED; + ace->flags = 0; + ace->access_mask = REG_KEY_ALL; + ace->trustee = global_sid_System; + + status = security_descriptor_dacl_add(sec_desc, ace); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(sec_desc); + return false; + } + + /* root free pass */ + + if ( geteuid() == sec_initial_uid() ) { + DEBUG(5,("elog_check_access: running as root, using system token\n")); + token = get_system_token(); + } + + /* run the check, try for the max allowed */ + + status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS, + &info->access_granted); + + TALLOC_FREE(sec_desc); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(8,("elog_check_access: se_access_check() return %s\n", + nt_errstr(status))); + return False; + } + + /* we have to have READ permission for a successful open */ + + return ( info->access_granted & SEC_FILE_READ_DATA ); +} + +/******************************************************************** + ********************************************************************/ + +static bool elog_validate_logname( const char *name ) +{ + int i; + const char **elogs = lp_eventlog_list(); + + if (!elogs) { + return False; + } + + for ( i=0; elogs[i]; i++ ) { + if ( strequal( name, elogs[i] ) ) + return True; + } + + return False; +} + +/******************************************************************** +********************************************************************/ + +static bool get_num_records_hook( EVENTLOG_INFO * info ) +{ + int next_record; + int oldest_record; + + if ( !info->etdb ) { + DEBUG( 10, ( "No open tdb for %s\n", info->logname ) ); + return False; + } + + /* lock the tdb since we have to get 2 records */ + + tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 ); + next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD); + oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY); + tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD); + + DEBUG( 8, + ( "Oldest Record %d; Next Record %d\n", oldest_record, + next_record ) ); + + info->num_records = ( next_record - oldest_record ); + info->oldest_entry = oldest_record; + + return True; +} + +/******************************************************************** + ********************************************************************/ + +static bool get_oldest_entry_hook( EVENTLOG_INFO * info ) +{ + /* it's the same thing */ + return get_num_records_hook( info ); +} + +/******************************************************************** + ********************************************************************/ + +static NTSTATUS elog_open( struct pipes_struct * p, const char *logname, struct policy_handle *hnd ) +{ + EVENTLOG_INFO *elog; + + /* first thing is to validate the eventlog name */ + + if ( !elog_validate_logname( logname ) ) + return NT_STATUS_OBJECT_PATH_INVALID; + + if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) ) + return NT_STATUS_NO_MEMORY; + talloc_set_destructor(elog, eventlog_info_destructor); + + elog->logname = talloc_strdup( elog, logname ); + + /* Open the tdb first (so that we can create any new tdbs if necessary). + We have to do this as root and then use an internal access check + on the file permissions since you can only have a tdb open once + in a single process */ + + become_root(); + elog->etdb = elog_open_tdb( elog->logname, False, False ); + unbecome_root(); + + if ( !elog->etdb ) { + /* according to MSDN, if the logfile cannot be found, we should + default to the "Application" log */ + + if ( !strequal( logname, ELOG_APPL ) ) { + + TALLOC_FREE( elog->logname ); + + elog->logname = talloc_strdup( elog, ELOG_APPL ); + + /* do the access check */ + if ( !elog_check_access( elog, p->server_info->security_token ) ) { + TALLOC_FREE( elog ); + return NT_STATUS_ACCESS_DENIED; + } + + become_root(); + elog->etdb = elog_open_tdb( elog->logname, False, False ); + unbecome_root(); + } + + if ( !elog->etdb ) { + TALLOC_FREE( elog ); + return NT_STATUS_ACCESS_DENIED; /* ??? */ + } + } + + /* now do the access check. Close the tdb if we fail here */ + + if ( !elog_check_access( elog, p->server_info->security_token ) ) { + TALLOC_FREE( elog ); + return NT_STATUS_ACCESS_DENIED; + } + + /* create the policy handle */ + + if ( !create_policy_hnd( p, hnd, elog ) ) { + TALLOC_FREE(elog); + return NT_STATUS_NO_MEMORY; + } + + /* set the initial current_record pointer */ + + if ( !get_oldest_entry_hook( elog ) ) { + DEBUG(3,("elog_open: Successfully opened eventlog but can't " + "get any information on internal records!\n")); + } + + elog->current_record = elog->oldest_entry; + + return NT_STATUS_OK; +} + +/******************************************************************** + ********************************************************************/ + +static NTSTATUS elog_close( struct pipes_struct *p, struct policy_handle *hnd ) +{ + if ( !( close_policy_hnd( p, hnd ) ) ) { + return NT_STATUS_INVALID_HANDLE; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + *******************************************************************/ + +static int elog_size( EVENTLOG_INFO *info ) +{ + if ( !info || !info->etdb ) { + DEBUG(0,("elog_size: Invalid info* structure!\n")); + return 0; + } + + return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL ); +} + +/******************************************************************** + note that this can only be called AFTER the table is constructed, + since it uses the table to find the tdb handle + ********************************************************************/ + +static bool sync_eventlog_params(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + EVENTLOG_INFO *info) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + uint32_t uiMaxSize = 0; + uint32_t uiRetention = 0; + char *path = NULL; + NTSTATUS status; + WERROR wresult = WERR_OK; + char *elogname = info->logname; + TALLOC_CTX *ctx; + bool ret = false; + + ctx = talloc_stackframe(); + if (ctx == NULL) { + return false; + } + + DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) ); + + if ( !info->etdb ) { + DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) ); + goto done; + } + /* set resonable defaults. 512Kb on size and 1 week on time */ + + uiMaxSize = 0x80000; + uiRetention = 604800; + + /* the general idea is to internally open the registry + key and retrieve the values. That way we can continue + to use the same fetch/store api that we use in + srv_reg_nt.c */ + path = talloc_asprintf(ctx, "%s\\%s", TOP_LEVEL_EVENTLOG_KEY, elogname); + if (!path) { + goto done; + } + + status = dcerpc_winreg_int_hklm_openkey(ctx, + get_server_info_system(), + msg_ctx, + &h, + path, + false, + access_mask, + &hive_hnd, + &key_hnd, + &wresult); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(4,("sync_eventlog_params: Failed to open key [%s] (%s)\n", + path, nt_errstr(status))); + goto done; + } + if ( !W_ERROR_IS_OK( wresult ) ) { + DEBUG( 4, + ( "sync_eventlog_params: Failed to open key [%s] (%s)\n", + path, win_errstr( wresult ) ) ); + goto done; + } + + status = dcerpc_winreg_query_dword(ctx, + h, + &key_hnd, + "Retention", + &uiRetention, + &wresult); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(4, ("Failed to query value \"Retention\": %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(wresult)) { + DEBUG(4, ("Failed to query value \"Retention\": %s\n", + win_errstr(wresult))); + goto done; + } + + status = dcerpc_winreg_query_dword(ctx, + h, + &key_hnd, + "MaxSize", + &uiMaxSize, + &wresult); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(4, ("Failed to query value \"Retention\": %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(wresult)) { + DEBUG(4, ("Failed to query value \"MaxSize\": %s\n", + win_errstr(wresult))); + goto done; + } + + tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize ); + tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention ); + + ret = true; + +done: + if (h != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(h, ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(ctx); + return ret; +} + +/******************************************************************** + _eventlog_OpenEventLogW + ********************************************************************/ + +NTSTATUS _eventlog_OpenEventLogW(struct pipes_struct *p, + struct eventlog_OpenEventLogW *r) +{ + EVENTLOG_INFO *info; + NTSTATUS result; + + DEBUG( 10,("_eventlog_OpenEventLogW: Server [%s], Log [%s]\n", + r->in.servername->string, r->in.logname->string )); + + /* according to MSDN, if the logfile cannot be found, we should + default to the "Application" log */ + + if ( !NT_STATUS_IS_OK( result = elog_open( p, r->in.logname->string, r->out.handle )) ) + return result; + + if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) { + DEBUG(0,("_eventlog_OpenEventLogW: eventlog (%s) opened but unable to find handle!\n", + r->in.logname->string )); + elog_close( p, r->out.handle ); + return NT_STATUS_INVALID_HANDLE; + } + + DEBUG(10,("_eventlog_OpenEventLogW: Size [%d]\n", elog_size( info ))); + + if (!sync_eventlog_params(p->mem_ctx, + p->msg_ctx, + info)) { + elog_close(p, r->out.handle); + return NT_STATUS_EVENTLOG_FILE_CORRUPT; + } + prune_eventlog( ELOG_TDB_CTX(info->etdb) ); + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_ClearEventLogW + This call still needs some work + ********************************************************************/ +/** The windows client seems to be doing something funny with the file name + A call like + ClearEventLog(handle, "backup_file") + on the client side will result in the backup file name looking like this on the + server side: + \??\${CWD of client}\backup_file + If an absolute path gets specified, such as + ClearEventLog(handle, "C:\\temp\\backup_file") + then it is still mangled by the client into this: + \??\C:\temp\backup_file + when it is on the wire. + I'm not sure where the \?? is coming from, or why the ${CWD} of the client process + would be added in given that the backup file gets written on the server side. */ + +NTSTATUS _eventlog_ClearEventLogW(struct pipes_struct *p, + struct eventlog_ClearEventLogW *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + + if ( !info ) + return NT_STATUS_INVALID_HANDLE; + + if (r->in.backupfile && r->in.backupfile->string) { + + DEBUG(8,( "_eventlog_ClearEventLogW: Using [%s] as the backup " + "file name for log [%s].", + r->in.backupfile->string, info->logname ) ); + } + + /* check for WRITE access to the file */ + + if ( !(info->access_granted & SEC_FILE_WRITE_DATA) ) + return NT_STATUS_ACCESS_DENIED; + + /* Force a close and reopen */ + + elog_close_tdb( info->etdb, True ); + become_root(); + info->etdb = elog_open_tdb( info->logname, True, False ); + unbecome_root(); + + if ( !info->etdb ) + return NT_STATUS_ACCESS_DENIED; + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_CloseEventLog + ********************************************************************/ + +NTSTATUS _eventlog_CloseEventLog(struct pipes_struct * p, + struct eventlog_CloseEventLog *r) +{ + NTSTATUS status; + + status = elog_close( p, r->in.handle ); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + ZERO_STRUCTP(r->out.handle); + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_ReadEventLogW + ********************************************************************/ + +NTSTATUS _eventlog_ReadEventLogW(struct pipes_struct *p, + struct eventlog_ReadEventLogW *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + uint32_t num_records_read = 0; + int bytes_left, record_number; + uint32_t elog_read_type, elog_read_dir; + + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + info->flags = r->in.flags; + bytes_left = r->in.number_of_bytes; + + if (!info->etdb) { + return NT_STATUS_ACCESS_DENIED; + } + + /* check for valid flags. Can't use the sequential and seek flags together */ + + elog_read_type = r->in.flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ); + elog_read_dir = r->in.flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ); + + if (r->in.flags == 0 || + elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) || + elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ)) + { + DEBUG(3,("_eventlog_ReadEventLogW: " + "Invalid flags [0x%08x] for ReadEventLog\n", + r->in.flags)); + return NT_STATUS_INVALID_PARAMETER; + } + + /* a sequential read should ignore the offset */ + + if (elog_read_type & EVENTLOG_SEQUENTIAL_READ) { + record_number = info->current_record; + } else { + record_number = r->in.offset; + } + + if (r->in.number_of_bytes == 0) { + struct EVENTLOGRECORD *e; + e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb), + record_number); + if (!e) { + return NT_STATUS_END_OF_FILE; + } + *r->out.real_size = e->Length; + return NT_STATUS_BUFFER_TOO_SMALL; + } + + while (bytes_left > 0) { + + DATA_BLOB blob; + enum ndr_err_code ndr_err; + struct EVENTLOGRECORD *e; + + e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb), + record_number); + if (!e) { + break; + } + + ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, e, + (ndr_push_flags_fn_t)ndr_push_EVENTLOGRECORD); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(EVENTLOGRECORD, e); + } + + if (blob.length > r->in.number_of_bytes) { + *r->out.real_size = blob.length; + return NT_STATUS_BUFFER_TOO_SMALL; + } + + if (*r->out.sent_size + blob.length > r->in.number_of_bytes) { + break; + } + + bytes_left -= blob.length; + + if (info->flags & EVENTLOG_FORWARDS_READ) { + record_number++; + } else { + record_number--; + } + + /* update the eventlog record pointer */ + + info->current_record = record_number; + + memcpy(&r->out.data[*(r->out.sent_size)], + blob.data, blob.length); + *(r->out.sent_size) += blob.length; + + num_records_read++; + } + + if (r->in.offset == 0 && record_number == 0 && *r->out.sent_size == 0) { + return NT_STATUS_END_OF_FILE; + } + + return NT_STATUS_OK; +} + +/******************************************************************** + _eventlog_GetOldestRecord + ********************************************************************/ + +NTSTATUS _eventlog_GetOldestRecord(struct pipes_struct *p, + struct eventlog_GetOldestRecord *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + + if (info == NULL) { + return NT_STATUS_INVALID_HANDLE; + } + + if ( !( get_oldest_entry_hook( info ) ) ) + return NT_STATUS_ACCESS_DENIED; + + *r->out.oldest_entry = info->oldest_entry; + + return NT_STATUS_OK; +} + +/******************************************************************** +_eventlog_GetNumRecords + ********************************************************************/ + +NTSTATUS _eventlog_GetNumRecords(struct pipes_struct *p, + struct eventlog_GetNumRecords *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); + + if (info == NULL) { + return NT_STATUS_INVALID_HANDLE; + } + + if ( !( get_num_records_hook( info ) ) ) + return NT_STATUS_ACCESS_DENIED; + + *r->out.number = info->num_records; + + return NT_STATUS_OK; +} + +NTSTATUS _eventlog_BackupEventLogW(struct pipes_struct *p, struct eventlog_BackupEventLogW *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/******************************************************************** +_eventlog_GetLogInformation + ********************************************************************/ + +NTSTATUS _eventlog_GetLogInformation(struct pipes_struct *p, + struct eventlog_GetLogInformation *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); + struct EVENTLOG_FULL_INFORMATION f; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + if (r->in.level != 0) { + return NT_STATUS_INVALID_LEVEL; + } + + *r->out.bytes_needed = 4; + + if (r->in.buf_size < 4) { + return NT_STATUS_BUFFER_TOO_SMALL; + } + + /* FIXME: this should be retrieved from the handle */ + f.full = false; + + ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &f, + (ndr_push_flags_fn_t)ndr_push_EVENTLOG_FULL_INFORMATION); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(EVENTLOG_FULL_INFORMATION, &f); + } + + memcpy(r->out.buffer, blob.data, 4); + + return NT_STATUS_OK; +} + +/******************************************************************** +_eventlog_FlushEventLog + ********************************************************************/ + +NTSTATUS _eventlog_FlushEventLog(struct pipes_struct *p, + struct eventlog_FlushEventLog *r) +{ + EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + return NT_STATUS_ACCESS_DENIED; +} + +/******************************************************************** + ********************************************************************/ + +static NTSTATUS evlog_report_to_record(TALLOC_CTX *mem_ctx, + const struct eventlog_ReportEventW *r, + const char *logname, + struct EVENTLOGRECORD *e) +{ + uint32_t i; + ZERO_STRUCTP(e); + + e->TimeGenerated = r->in.timestamp; + e->TimeWritten = time(NULL); + e->EventID = r->in.event_id; + e->EventType = r->in.event_type; + e->NumStrings = r->in.num_of_strings; + e->EventCategory = r->in.event_category; + e->ReservedFlags = r->in.flags; + e->DataLength = r->in.data_size; + e->SourceName = talloc_strdup(mem_ctx, logname); + NT_STATUS_HAVE_NO_MEMORY(e->SourceName); + if (r->in.servername->string) { + e->Computername = r->in.servername->string; + } else { + e->Computername = talloc_strdup(mem_ctx, ""); + NT_STATUS_HAVE_NO_MEMORY(e->Computername); + } + if (r->in.user_sid) { + e->UserSid = *r->in.user_sid; + } + e->Strings = talloc_array(mem_ctx, const char *, e->NumStrings); + NT_STATUS_HAVE_NO_MEMORY(e->Strings); + + for (i=0; i < e->NumStrings; i++) { + e->Strings[i] = talloc_strdup(e->Strings, + r->in.strings[i]->string); + NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]); + } + e->Data = r->in.data; + + return NT_STATUS_OK; +} + +/******************************************************************** +_eventlog_ReportEventW + ********************************************************************/ + +NTSTATUS _eventlog_ReportEventW(struct pipes_struct *p, + struct eventlog_ReportEventW *r) +{ + NTSTATUS status; + struct EVENTLOGRECORD record; + + EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); + if (!info) { + return NT_STATUS_INVALID_HANDLE; + } + + status = evlog_report_to_record(p->mem_ctx, r, info->logname, &record); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = evlog_push_record(p->mem_ctx, + ELOG_TDB_CTX(info->etdb), + &record, + r->out.record_number); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +/******************************************************************** + ********************************************************************/ + +NTSTATUS _eventlog_DeregisterEventSource(struct pipes_struct *p, + struct eventlog_DeregisterEventSource *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ChangeNotify(struct pipes_struct *p, + struct eventlog_ChangeNotify *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_RegisterEventSourceW(struct pipes_struct *p, + struct eventlog_RegisterEventSourceW *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_OpenBackupEventLogW(struct pipes_struct *p, + struct eventlog_OpenBackupEventLogW *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ClearEventLogA(struct pipes_struct *p, + struct eventlog_ClearEventLogA *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_BackupEventLogA(struct pipes_struct *p, + struct eventlog_BackupEventLogA *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_OpenEventLogA(struct pipes_struct *p, + struct eventlog_OpenEventLogA *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_RegisterEventSourceA(struct pipes_struct *p, + struct eventlog_RegisterEventSourceA *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_OpenBackupEventLogA(struct pipes_struct *p, + struct eventlog_OpenBackupEventLogA *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ReadEventLogA(struct pipes_struct *p, + struct eventlog_ReadEventLogA *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ReportEventA(struct pipes_struct *p, + struct eventlog_ReportEventA *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_RegisterClusterSvc(struct pipes_struct *p, + struct eventlog_RegisterClusterSvc *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_DeregisterClusterSvc(struct pipes_struct *p, + struct eventlog_DeregisterClusterSvc *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_WriteClusterEvents(struct pipes_struct *p, + struct eventlog_WriteClusterEvents *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _eventlog_ReportEventAndSourceW(struct pipes_struct *p, + struct eventlog_ReportEventAndSourceW *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} diff --git a/source3/rpc_server/eventlog/srv_eventlog_reg.c b/source3/rpc_server/eventlog/srv_eventlog_reg.c new file mode 100644 index 0000000000..8e85abf488 --- /dev/null +++ b/source3/rpc_server/eventlog/srv_eventlog_reg.c @@ -0,0 +1,266 @@ +/* + * Unix SMB/CIFS implementation. + * + * Eventlog RPC server keys initialization + * + * Copyright (c) 2005 Marcin Krzysztof Porwit + * Copyright (c) 2005 Brian Moran + * Copyright (c) 2005 Gerald (Jerry) Carter + * Copyright (c) 2011 Andreas Schneider + * + * 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 . + */ + +#include "includes.h" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "rpc_client/cli_winreg_int.h" +#include "rpc_client/cli_winreg.h" +#include "rpc_server/eventlog/srv_eventlog_reg.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_REGISTRY + +#define TOP_LEVEL_EVENTLOG_KEY "SYSTEM\\CurrentControlSet\\Services\\Eventlog" + +bool eventlog_init_winreg(struct messaging_context *msg_ctx) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + uint32_t uiMaxSize = 0x00080000; + uint32_t uiRetention = 0x93A80; + const char **elogs = lp_eventlog_list(); + const char **subkeys = NULL; + uint32_t num_subkeys = 0; + uint32_t i; + char *key = NULL; + NTSTATUS status; + WERROR result = WERR_OK; + bool ok = false; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return false; + } + + DEBUG(3, ("Initialise the eventlog registry keys if needed.\n")); + + key = talloc_strdup(tmp_ctx, TOP_LEVEL_EVENTLOG_KEY); + + status = dcerpc_winreg_int_hklm_openkey(tmp_ctx, + get_server_info_system(), + msg_ctx, + &h, + key, + false, + access_mask, + &hive_hnd, + &key_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg: Could not open %s - %s\n", + key, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg: Could not open %s - %s\n", + key, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_enum_keys(tmp_ctx, + h, + &key_hnd, + &num_subkeys, + &subkeys, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg: Could enum keys at %s - %s\n", + key, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg: Could enum keys at %s - %s\n", + key, win_errstr(result))); + goto done; + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + + /* create subkeys if they don't exist */ + while (elogs && *elogs) { + enum winreg_CreateAction action = REG_ACTION_NONE; + char *evt_tdb = NULL; + struct winreg_String wkey; + struct winreg_String wkeyclass; + bool skip = false; + + for (i = 0; i < num_subkeys; i++) { + if (strequal(subkeys[i], *elogs)) { + skip = true; + } + } + + if (skip) { + elogs++; + continue; + } + + ZERO_STRUCT(key_hnd); + ZERO_STRUCT(wkey); + + wkey.name = talloc_asprintf(tmp_ctx, "%s\\%s", key, *elogs); + if (wkey.name == NULL) { + result = WERR_NOMEM; + goto done; + } + + ZERO_STRUCT(wkeyclass); + wkeyclass.name = ""; + + + status = dcerpc_winreg_CreateKey(h, + tmp_ctx, + &hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + h, + &key_hnd, + "MaxSize", + uiMaxSize, + &result); + + status = dcerpc_winreg_set_dword(tmp_ctx, + h, + &key_hnd, + "Retention", + uiRetention, + &result); + + status = dcerpc_winreg_set_sz(tmp_ctx, + h, + &key_hnd, + "PrimaryModule", + *elogs, + &result); + + evt_tdb = talloc_asprintf(tmp_ctx, + "%%SystemRoot%%\\system32\\config\\%s.tdb", + *elogs); + if (evt_tdb == NULL) { + goto done; + } + status = dcerpc_winreg_set_expand_sz(tmp_ctx, + h, + &key_hnd, + "File", + evt_tdb, + &result); + TALLOC_FREE(evt_tdb); + + status = dcerpc_winreg_add_multi_sz(tmp_ctx, + h, + &key_hnd, + "Sources", + *elogs, + &result); + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + + /* sub-subkeys */ + { + uint32_t uiCategoryCount = 0x00000007; + + wkey.name = talloc_asprintf(tmp_ctx, + "%s\\%s", + wkey.name, *elogs); + if (wkey.name == NULL) { + result = WERR_NOMEM; + goto done; + } + + status = dcerpc_winreg_CreateKey(h, + tmp_ctx, + &hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + h, + &key_hnd, + "CategoryCount", + uiCategoryCount, + &result); + + status = dcerpc_winreg_set_expand_sz(tmp_ctx, + h, + &key_hnd, + "CategoryMessageFile", + "%SystemRoot%\\system32\\eventlog.dll", + &result); + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + } + + elogs++; + } /* loop */ + + ok = true; +done: + TALLOC_FREE(tmp_ctx); + return ok; +} + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/eventlog/srv_eventlog_reg.h b/source3/rpc_server/eventlog/srv_eventlog_reg.h new file mode 100644 index 0000000000..02c2792647 --- /dev/null +++ b/source3/rpc_server/eventlog/srv_eventlog_reg.h @@ -0,0 +1,29 @@ +/* + * Unix SMB/CIFS implementation. + * + * WINREG client routines + * + * Copyright (c) 2011 Andreas Schneider + * + * 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 . + */ + +#ifndef SRV_EVENTLOG_REG_H +#define SRV_EVENTLOG_REG_H + +bool eventlog_init_winreg(struct messaging_context *msg_ctx); + +#endif /* SRV_EVENTLOG_REG_H */ + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/initshutdown/srv_initshutdown_nt.c b/source3/rpc_server/initshutdown/srv_initshutdown_nt.c new file mode 100644 index 0000000000..e19ed284bf --- /dev/null +++ b/source3/rpc_server/initshutdown/srv_initshutdown_nt.c @@ -0,0 +1,78 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997. + * Copyright (C) Gerald Carter 2006. + * + * 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 . + */ + +/* Implementation of registry functions. */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_initshutdown.h" +#include "../librpc/gen_ndr/srv_winreg.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + + +/******************************************************************* + ********************************************************************/ +WERROR _initshutdown_Init(struct pipes_struct *p, struct initshutdown_Init *r) +{ + struct winreg_InitiateSystemShutdownEx s; + + s.in.hostname = r->in.hostname; + s.in.message = r->in.message; + s.in.timeout = r->in.timeout; + s.in.force_apps = r->in.force_apps; + s.in.do_reboot = r->in.do_reboot; + s.in.reason = 0; + + /* thunk down to _winreg_InitiateSystemShutdownEx() + (just returns a status) */ + + return _winreg_InitiateSystemShutdownEx( p, &s ); +} + +/******************************************************************* + ********************************************************************/ + +WERROR _initshutdown_InitEx(struct pipes_struct *p, struct initshutdown_InitEx *r) +{ + struct winreg_InitiateSystemShutdownEx s; + s.in.hostname = r->in.hostname; + s.in.message = r->in.message; + s.in.timeout = r->in.timeout; + s.in.force_apps = r->in.force_apps; + s.in.do_reboot = r->in.do_reboot; + s.in.reason = r->in.reason; + + return _winreg_InitiateSystemShutdownEx( p, &s); +} + + + + +/******************************************************************* + reg_abort_shutdwon + ********************************************************************/ + +WERROR _initshutdown_Abort(struct pipes_struct *p, struct initshutdown_Abort *r) +{ + struct winreg_AbortSystemShutdown s; + s.in.server = r->in.server; + return _winreg_AbortSystemShutdown( p, &s ); +} diff --git a/source3/rpc_server/lsa/srv_lsa_nt.c b/source3/rpc_server/lsa/srv_lsa_nt.c new file mode 100644 index 0000000000..985d8df6a9 --- /dev/null +++ b/source3/rpc_server/lsa/srv_lsa_nt.c @@ -0,0 +1,2755 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997, + * Copyright (C) Jeremy Allison 2001, 2006. + * Copyright (C) Rafal Szczesniak 2002, + * Copyright (C) Jim McDonough 2002, + * Copyright (C) Simo Sorce 2003. + * Copyright (C) Gerald (Jerry) Carter 2005. + * Copyright (C) Volker Lendecke 2005. + * Copyright (C) Guenther Deschner 2008. + * Copyright (C) Andrew Bartlett 2010. + * + * 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 . + */ + +/* This is the implementation of the lsa server code. */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_lsa.h" +#include "secrets.h" +#include "../librpc/gen_ndr/netlogon.h" +#include "rpc_client/init_lsa.h" +#include "../libcli/security/security.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +#define MAX_LOOKUP_SIDS 0x5000 /* 20480 */ + +enum lsa_handle_type { LSA_HANDLE_POLICY_TYPE = 1, LSA_HANDLE_ACCOUNT_TYPE }; + +struct lsa_info { + struct dom_sid sid; + const char *name; + uint32 access; + enum lsa_handle_type type; + struct security_descriptor *sd; +}; + +const struct generic_mapping lsa_account_mapping = { + LSA_ACCOUNT_READ, + LSA_ACCOUNT_WRITE, + LSA_ACCOUNT_EXECUTE, + LSA_ACCOUNT_ALL_ACCESS +}; + +const struct generic_mapping lsa_policy_mapping = { + LSA_POLICY_READ, + LSA_POLICY_WRITE, + LSA_POLICY_EXECUTE, + LSA_POLICY_ALL_ACCESS +}; + +const struct generic_mapping lsa_secret_mapping = { + LSA_SECRET_READ, + LSA_SECRET_WRITE, + LSA_SECRET_EXECUTE, + LSA_SECRET_ALL_ACCESS +}; + +const struct generic_mapping lsa_trusted_domain_mapping = { + LSA_TRUSTED_DOMAIN_READ, + LSA_TRUSTED_DOMAIN_WRITE, + LSA_TRUSTED_DOMAIN_EXECUTE, + LSA_TRUSTED_DOMAIN_ALL_ACCESS +}; + +/*************************************************************************** + init_lsa_ref_domain_list - adds a domain if it's not already in, returns the index. +***************************************************************************/ + +static int init_lsa_ref_domain_list(TALLOC_CTX *mem_ctx, + struct lsa_RefDomainList *ref, + const char *dom_name, + struct dom_sid *dom_sid) +{ + int num = 0; + + if (dom_name != NULL) { + for (num = 0; num < ref->count; num++) { + if (dom_sid_equal(dom_sid, ref->domains[num].sid)) { + return num; + } + } + } else { + num = ref->count; + } + + if (num >= LSA_REF_DOMAIN_LIST_MULTIPLIER) { + /* index not found, already at maximum domain limit */ + return -1; + } + + ref->count = num + 1; + ref->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER; + + ref->domains = TALLOC_REALLOC_ARRAY(mem_ctx, ref->domains, + struct lsa_DomainInfo, ref->count); + if (!ref->domains) { + return -1; + } + + ZERO_STRUCT(ref->domains[num]); + + init_lsa_StringLarge(&ref->domains[num].name, dom_name); + ref->domains[num].sid = dom_sid_dup(mem_ctx, dom_sid); + if (!ref->domains[num].sid) { + return -1; + } + + return num; +} + + +/*************************************************************************** + initialize a lsa_DomainInfo structure. + ***************************************************************************/ + +static void init_dom_query_3(struct lsa_DomainInfo *r, + const char *name, + struct dom_sid *sid) +{ + init_lsa_StringLarge(&r->name, name); + r->sid = sid; +} + +/*************************************************************************** + initialize a lsa_DomainInfo structure. + ***************************************************************************/ + +static void init_dom_query_5(struct lsa_DomainInfo *r, + const char *name, + struct dom_sid *sid) +{ + init_lsa_StringLarge(&r->name, name); + r->sid = sid; +} + +/*************************************************************************** + lookup_lsa_rids. Must be called as root for lookup_name to work. + ***************************************************************************/ + +static NTSTATUS lookup_lsa_rids(TALLOC_CTX *mem_ctx, + struct lsa_RefDomainList *ref, + struct lsa_TranslatedSid *prid, + uint32_t num_entries, + struct lsa_String *name, + int flags, + uint32_t *pmapped_count) +{ + uint32 mapped_count, i; + + SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS); + + mapped_count = 0; + *pmapped_count = 0; + + for (i = 0; i < num_entries; i++) { + struct dom_sid sid; + uint32 rid; + int dom_idx; + const char *full_name; + const char *domain; + enum lsa_SidType type = SID_NAME_UNKNOWN; + + /* Split name into domain and user component */ + + /* follow w2k8 behavior and return the builtin domain when no + * input has been passed in */ + + if (name[i].string) { + full_name = name[i].string; + } else { + full_name = "BUILTIN"; + } + + DEBUG(5, ("lookup_lsa_rids: looking up name %s\n", full_name)); + + /* We can ignore the result of lookup_name, it will not touch + "type" if it's not successful */ + + lookup_name(mem_ctx, full_name, flags, &domain, NULL, + &sid, &type); + + switch (type) { + case SID_NAME_USER: + case SID_NAME_DOM_GRP: + case SID_NAME_DOMAIN: + case SID_NAME_ALIAS: + case SID_NAME_WKN_GRP: + DEBUG(5, ("init_lsa_rids: %s found\n", full_name)); + /* Leave these unchanged */ + break; + default: + /* Don't hand out anything but the list above */ + DEBUG(5, ("init_lsa_rids: %s not found\n", full_name)); + type = SID_NAME_UNKNOWN; + break; + } + + rid = 0; + dom_idx = -1; + + if (type != SID_NAME_UNKNOWN) { + if (type == SID_NAME_DOMAIN) { + rid = (uint32_t)-1; + } else { + sid_split_rid(&sid, &rid); + } + dom_idx = init_lsa_ref_domain_list(mem_ctx, ref, domain, &sid); + mapped_count++; + } + + prid[i].sid_type = type; + prid[i].rid = rid; + prid[i].sid_index = dom_idx; + } + + *pmapped_count = mapped_count; + return NT_STATUS_OK; +} + +/*************************************************************************** + lookup_lsa_sids. Must be called as root for lookup_name to work. + ***************************************************************************/ + +static NTSTATUS lookup_lsa_sids(TALLOC_CTX *mem_ctx, + struct lsa_RefDomainList *ref, + struct lsa_TranslatedSid3 *trans_sids, + uint32_t num_entries, + struct lsa_String *name, + int flags, + uint32 *pmapped_count) +{ + uint32 mapped_count, i; + + SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS); + + mapped_count = 0; + *pmapped_count = 0; + + for (i = 0; i < num_entries; i++) { + struct dom_sid sid; + uint32 rid; + int dom_idx; + const char *full_name; + const char *domain; + enum lsa_SidType type = SID_NAME_UNKNOWN; + + ZERO_STRUCT(sid); + + /* Split name into domain and user component */ + + full_name = name[i].string; + if (full_name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(5, ("init_lsa_sids: looking up name %s\n", full_name)); + + /* We can ignore the result of lookup_name, it will not touch + "type" if it's not successful */ + + lookup_name(mem_ctx, full_name, flags, &domain, NULL, + &sid, &type); + + switch (type) { + case SID_NAME_USER: + case SID_NAME_DOM_GRP: + case SID_NAME_DOMAIN: + case SID_NAME_ALIAS: + case SID_NAME_WKN_GRP: + DEBUG(5, ("init_lsa_sids: %s found\n", full_name)); + /* Leave these unchanged */ + break; + default: + /* Don't hand out anything but the list above */ + DEBUG(5, ("init_lsa_sids: %s not found\n", full_name)); + type = SID_NAME_UNKNOWN; + break; + } + + rid = 0; + dom_idx = -1; + + if (type != SID_NAME_UNKNOWN) { + struct dom_sid domain_sid; + sid_copy(&domain_sid, &sid); + sid_split_rid(&domain_sid, &rid); + dom_idx = init_lsa_ref_domain_list(mem_ctx, ref, domain, &domain_sid); + mapped_count++; + } + + /* Initialize the lsa_TranslatedSid3 return. */ + trans_sids[i].sid_type = type; + trans_sids[i].sid = dom_sid_dup(mem_ctx, &sid); + trans_sids[i].sid_index = dom_idx; + } + + *pmapped_count = mapped_count; + return NT_STATUS_OK; +} + +static NTSTATUS make_lsa_object_sd(TALLOC_CTX *mem_ctx, struct security_descriptor **sd, size_t *sd_size, + const struct generic_mapping *map, + struct dom_sid *sid, uint32_t sid_access) +{ + struct dom_sid adm_sid; + struct security_ace ace[5]; + size_t i = 0; + + struct security_acl *psa = NULL; + + /* READ|EXECUTE access for Everyone */ + + init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, + map->generic_execute | map->generic_read, 0); + + /* Add Full Access 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ + + init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); + init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); + + /* Add Full Access for Domain Admins */ + sid_compose(&adm_sid, get_global_sam_sid(), DOMAIN_RID_ADMINS); + init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, + map->generic_all, 0); + + /* If we have a sid, give it some special access */ + + if (sid) { + init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, + sid_access, 0); + } + + if((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) == NULL) + return NT_STATUS_NO_MEMORY; + + if((*sd = make_sec_desc(mem_ctx, SECURITY_DESCRIPTOR_REVISION_1, + SEC_DESC_SELF_RELATIVE, &adm_sid, NULL, NULL, + psa, sd_size)) == NULL) + return NT_STATUS_NO_MEMORY; + + return NT_STATUS_OK; +} + + +/*************************************************************************** + _lsa_OpenPolicy2 + ***************************************************************************/ + +NTSTATUS _lsa_OpenPolicy2(struct pipes_struct *p, + struct lsa_OpenPolicy2 *r) +{ + struct lsa_info *info; + struct security_descriptor *psd = NULL; + size_t sd_size; + uint32 des_access = r->in.access_mask; + uint32 acc_granted; + NTSTATUS status; + + /* Work out max allowed. */ + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + /* map the generic bits to the lsa policy ones */ + se_map_generic(&des_access, &lsa_policy_mapping); + + /* get the generic lsa policy SD until we store it */ + status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, &lsa_policy_mapping, + NULL, 0); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, des_access, + &acc_granted, "_lsa_OpenPolicy2" ); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* associate the domain SID with the (unique) handle. */ + info = TALLOC_ZERO_P(p->mem_ctx, struct lsa_info); + if (info == NULL) { + return NT_STATUS_NO_MEMORY; + } + + sid_copy(&info->sid,get_global_sam_sid()); + info->access = acc_granted; + info->type = LSA_HANDLE_POLICY_TYPE; + + /* set up the LSA QUERY INFO response */ + if (!create_policy_hnd(p, r->out.handle, info)) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_OpenPolicy + ***************************************************************************/ + +NTSTATUS _lsa_OpenPolicy(struct pipes_struct *p, + struct lsa_OpenPolicy *r) +{ + struct lsa_OpenPolicy2 o; + + o.in.system_name = NULL; /* should be ignored */ + o.in.attr = r->in.attr; + o.in.access_mask = r->in.access_mask; + + o.out.handle = r->out.handle; + + return _lsa_OpenPolicy2(p, &o); +} + +/*************************************************************************** + _lsa_EnumTrustDom - this needs fixing to do more than return NULL ! JRA. + ufff, done :) mimir + ***************************************************************************/ + +NTSTATUS _lsa_EnumTrustDom(struct pipes_struct *p, + struct lsa_EnumTrustDom *r) +{ + struct lsa_info *info; + uint32_t count; + struct trustdom_info **domains; + struct lsa_DomainInfo *entries; + int i; + NTSTATUS nt_status; + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights */ + if (!(info->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + become_root(); + nt_status = pdb_enum_trusteddoms(p->mem_ctx, &count, &domains); + unbecome_root(); + + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + entries = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_DomainInfo, count); + if (!entries) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; iname); + entries[i].sid = &domains[i]->sid; + } + + if (*r->in.resume_handle >= count) { + *r->out.resume_handle = -1; + TALLOC_FREE(entries); + return NT_STATUS_NO_MORE_ENTRIES; + } + + /* return the rest, limit by max_size. Note that we + use the w2k3 element size value of 60 */ + r->out.domains->count = count - *r->in.resume_handle; + r->out.domains->count = MIN(r->out.domains->count, + 1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_MULTIPLIER)); + + r->out.domains->domains = entries + *r->in.resume_handle; + + if (r->out.domains->count < count - *r->in.resume_handle) { + *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count; + return STATUS_MORE_ENTRIES; + } + + /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST + * always be larger than the previous input resume handle, in + * particular when hitting the last query it is vital to set the + * resume handle correctly to avoid infinite client loops, as + * seen e.g. with Windows XP SP3 when resume handle is 0 and + * status is NT_STATUS_OK - gd */ + + *r->out.resume_handle = (uint32_t)-1; + + return NT_STATUS_OK; +} + +#define LSA_AUDIT_NUM_CATEGORIES_NT4 7 +#define LSA_AUDIT_NUM_CATEGORIES_WIN2K 9 +#define LSA_AUDIT_NUM_CATEGORIES LSA_AUDIT_NUM_CATEGORIES_NT4 + +/*************************************************************************** + _lsa_QueryInfoPolicy + ***************************************************************************/ + +NTSTATUS _lsa_QueryInfoPolicy(struct pipes_struct *p, + struct lsa_QueryInfoPolicy *r) +{ + NTSTATUS status = NT_STATUS_OK; + struct lsa_info *handle; + struct dom_sid domain_sid; + const char *name; + struct dom_sid *sid = NULL; + union lsa_PolicyInformation *info = NULL; + uint32_t acc_required = 0; + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) + return NT_STATUS_INVALID_HANDLE; + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + switch (r->in.level) { + case LSA_POLICY_INFO_AUDIT_LOG: + case LSA_POLICY_INFO_AUDIT_EVENTS: + acc_required = LSA_POLICY_VIEW_AUDIT_INFORMATION; + break; + case LSA_POLICY_INFO_DOMAIN: + acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; + break; + case LSA_POLICY_INFO_PD: + acc_required = LSA_POLICY_GET_PRIVATE_INFORMATION; + break; + case LSA_POLICY_INFO_ACCOUNT_DOMAIN: + acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; + break; + case LSA_POLICY_INFO_ROLE: + case LSA_POLICY_INFO_REPLICA: + acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; + break; + case LSA_POLICY_INFO_QUOTA: + acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; + break; + case LSA_POLICY_INFO_MOD: + case LSA_POLICY_INFO_AUDIT_FULL_SET: + /* according to MS-LSAD 3.1.4.4.3 */ + return NT_STATUS_INVALID_PARAMETER; + case LSA_POLICY_INFO_AUDIT_FULL_QUERY: + acc_required = LSA_POLICY_VIEW_AUDIT_INFORMATION; + break; + case LSA_POLICY_INFO_DNS: + case LSA_POLICY_INFO_DNS_INT: + case LSA_POLICY_INFO_L_ACCOUNT_DOMAIN: + acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; + break; + default: + break; + } + + if (!(handle->access & acc_required)) { + /* return NT_STATUS_ACCESS_DENIED; */ + } + + info = TALLOC_ZERO_P(p->mem_ctx, union lsa_PolicyInformation); + if (!info) { + return NT_STATUS_NO_MEMORY; + } + + switch (r->in.level) { + /* according to MS-LSAD 3.1.4.4.3 */ + case LSA_POLICY_INFO_MOD: + case LSA_POLICY_INFO_AUDIT_FULL_SET: + case LSA_POLICY_INFO_AUDIT_FULL_QUERY: + return NT_STATUS_INVALID_PARAMETER; + case LSA_POLICY_INFO_AUDIT_LOG: + info->audit_log.percent_full = 0; + info->audit_log.maximum_log_size = 0; + info->audit_log.retention_time = 0; + info->audit_log.shutdown_in_progress = 0; + info->audit_log.time_to_shutdown = 0; + info->audit_log.next_audit_record = 0; + status = NT_STATUS_OK; + break; + case LSA_POLICY_INFO_PD: + info->pd.name.string = NULL; + status = NT_STATUS_OK; + break; + case LSA_POLICY_INFO_REPLICA: + info->replica.source.string = NULL; + info->replica.account.string = NULL; + status = NT_STATUS_OK; + break; + case LSA_POLICY_INFO_QUOTA: + info->quota.paged_pool = 0; + info->quota.non_paged_pool = 0; + info->quota.min_wss = 0; + info->quota.max_wss = 0; + info->quota.pagefile = 0; + info->quota.unknown = 0; + status = NT_STATUS_OK; + break; + case LSA_POLICY_INFO_AUDIT_EVENTS: + { + + uint32 policy_def = LSA_AUDIT_POLICY_ALL; + + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_VIEW_AUDIT_INFORMATION)) { + DEBUG(10,("_lsa_QueryInfoPolicy: insufficient access rights\n")); + return NT_STATUS_ACCESS_DENIED; + } + + /* fake info: We audit everything. ;) */ + + info->audit_events.auditing_mode = true; + info->audit_events.count = LSA_AUDIT_NUM_CATEGORIES; + info->audit_events.settings = TALLOC_ZERO_ARRAY(p->mem_ctx, + enum lsa_PolicyAuditPolicy, + info->audit_events.count); + if (!info->audit_events.settings) { + return NT_STATUS_NO_MEMORY; + } + + info->audit_events.settings[LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT] = policy_def; + info->audit_events.settings[LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS] = policy_def; + info->audit_events.settings[LSA_AUDIT_CATEGORY_LOGON] = policy_def; + info->audit_events.settings[LSA_AUDIT_CATEGORY_PROCCESS_TRACKING] = policy_def; + info->audit_events.settings[LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES] = policy_def; + info->audit_events.settings[LSA_AUDIT_CATEGORY_SYSTEM] = policy_def; + info->audit_events.settings[LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS] = policy_def; + + break; + } + case LSA_POLICY_INFO_DOMAIN: + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + /* Request PolicyPrimaryDomainInformation. */ + switch (lp_server_role()) { + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: + name = get_global_sam_name(); + sid = dom_sid_dup(p->mem_ctx, get_global_sam_sid()); + if (!sid) { + return NT_STATUS_NO_MEMORY; + } + break; + case ROLE_DOMAIN_MEMBER: + name = lp_workgroup(); + /* We need to return the Domain SID here. */ + if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { + sid = dom_sid_dup(p->mem_ctx, &domain_sid); + if (!sid) { + return NT_STATUS_NO_MEMORY; + } + } else { + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + break; + case ROLE_STANDALONE: + name = lp_workgroup(); + sid = NULL; + break; + default: + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + init_dom_query_3(&info->domain, name, sid); + break; + case LSA_POLICY_INFO_ACCOUNT_DOMAIN: + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + /* Request PolicyAccountDomainInformation. */ + name = get_global_sam_name(); + sid = get_global_sam_sid(); + + init_dom_query_5(&info->account_domain, name, sid); + break; + case LSA_POLICY_INFO_ROLE: + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + switch (lp_server_role()) { + case ROLE_DOMAIN_BDC: + /* + * only a BDC is a backup controller + * of the domain, it controls. + */ + info->role.role = LSA_ROLE_BACKUP; + break; + default: + /* + * any other role is a primary + * of the domain, it controls. + */ + info->role.role = LSA_ROLE_PRIMARY; + break; + } + break; + case LSA_POLICY_INFO_DNS: + case LSA_POLICY_INFO_DNS_INT: { + struct pdb_domain_info *dominfo; + + if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { + DEBUG(10, ("Not replying to LSA_POLICY_INFO_DNS " + "without ADS passdb backend\n")); + status = NT_STATUS_INVALID_INFO_CLASS; + break; + } + + dominfo = pdb_get_domain_info(info); + if (dominfo == NULL) { + status = NT_STATUS_NO_MEMORY; + break; + } + + init_lsa_StringLarge(&info->dns.name, + dominfo->name); + init_lsa_StringLarge(&info->dns.dns_domain, + dominfo->dns_domain); + init_lsa_StringLarge(&info->dns.dns_forest, + dominfo->dns_forest); + info->dns.domain_guid = dominfo->guid; + info->dns.sid = &dominfo->sid; + break; + } + default: + DEBUG(0,("_lsa_QueryInfoPolicy: unknown info level in Lsa Query: %d\n", + r->in.level)); + status = NT_STATUS_INVALID_INFO_CLASS; + break; + } + + *r->out.info = info; + + return status; +} + +/*************************************************************************** + _lsa_QueryInfoPolicy2 + ***************************************************************************/ + +NTSTATUS _lsa_QueryInfoPolicy2(struct pipes_struct *p, + struct lsa_QueryInfoPolicy2 *r2) +{ + struct lsa_QueryInfoPolicy r; + + if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; + } + + ZERO_STRUCT(r); + r.in.handle = r2->in.handle; + r.in.level = r2->in.level; + r.out.info = r2->out.info; + + return _lsa_QueryInfoPolicy(p, &r); +} + +/*************************************************************************** + _lsa_lookup_sids_internal + ***************************************************************************/ + +static NTSTATUS _lsa_lookup_sids_internal(struct pipes_struct *p, + TALLOC_CTX *mem_ctx, + uint16_t level, /* input */ + int num_sids, /* input */ + struct lsa_SidPtr *sid, /* input */ + struct lsa_RefDomainList **pp_ref, /* input/output */ + struct lsa_TranslatedName2 **pp_names,/* input/output */ + uint32_t *pp_mapped_count) /* input/output */ +{ + NTSTATUS status; + int i; + const struct dom_sid **sids = NULL; + struct lsa_RefDomainList *ref = NULL; + uint32 mapped_count = 0; + struct lsa_dom_info *dom_infos = NULL; + struct lsa_name_info *name_infos = NULL; + struct lsa_TranslatedName2 *names = NULL; + + *pp_mapped_count = 0; + *pp_names = NULL; + *pp_ref = NULL; + + if (num_sids == 0) { + return NT_STATUS_OK; + } + + sids = TALLOC_ARRAY(p->mem_ctx, const struct dom_sid *, num_sids); + ref = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList); + + if (sids == NULL || ref == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; imem_ctx, num_sids, sids, level, + &dom_infos, &name_infos); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + names = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedName2, num_sids); + if (names == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; itype == SID_NAME_UNKNOWN) { + fstring tmp; + name->dom_idx = -1; + /* Unknown sids should return the string + * representation of the SID. Windows 2003 behaves + * rather erratic here, in many cases it returns the + * RID as 8 bytes hex, in others it returns the full + * SID. We (Jerry/VL) could not figure out which the + * hard cases are, so leave it with the SID. */ + name->name = talloc_asprintf(p->mem_ctx, "%s", + sid_to_fstring(tmp, + sids[i])); + if (name->name == NULL) { + return NT_STATUS_NO_MEMORY; + } + } else { + mapped_count += 1; + } + + names[i].sid_type = name->type; + names[i].name.string = name->name; + names[i].sid_index = name->dom_idx; + names[i].unknown = 0; + } + + status = NT_STATUS_NONE_MAPPED; + if (mapped_count > 0) { + status = (mapped_count < num_sids) ? + STATUS_SOME_UNMAPPED : NT_STATUS_OK; + } + + DEBUG(10, ("num_sids %d, mapped_count %d, status %s\n", + num_sids, mapped_count, nt_errstr(status))); + + *pp_mapped_count = mapped_count; + *pp_names = names; + *pp_ref = ref; + + return status; +} + +/*************************************************************************** + _lsa_LookupSids + ***************************************************************************/ + +NTSTATUS _lsa_LookupSids(struct pipes_struct *p, + struct lsa_LookupSids *r) +{ + NTSTATUS status; + struct lsa_info *handle; + int num_sids = r->in.sids->num_sids; + uint32 mapped_count = 0; + struct lsa_RefDomainList *domains = NULL; + struct lsa_TranslatedName *names_out = NULL; + struct lsa_TranslatedName2 *names = NULL; + int i; + + if ((r->in.level < 1) || (r->in.level > 6)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { + return NT_STATUS_INVALID_HANDLE; + } + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { + return NT_STATUS_ACCESS_DENIED; + } + + if (num_sids > MAX_LOOKUP_SIDS) { + DEBUG(5,("_lsa_LookupSids: limit of %d exceeded, requested %d\n", + MAX_LOOKUP_SIDS, num_sids)); + return NT_STATUS_NONE_MAPPED; + } + + status = _lsa_lookup_sids_internal(p, + p->mem_ctx, + r->in.level, + num_sids, + r->in.sids->sids, + &domains, + &names, + &mapped_count); + + /* Only return here when there is a real error. + NT_STATUS_NONE_MAPPED is a special case as it indicates that none of + the requested sids could be resolved. Older versions of XP (pre SP3) + rely that we return with the string representations of those SIDs in + that case. If we don't, XP crashes - Guenther + */ + + if (NT_STATUS_IS_ERR(status) && + !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + return status; + } + + /* Convert from lsa_TranslatedName2 to lsa_TranslatedName */ + names_out = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedName, + num_sids); + if (!names_out) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; iout.domains = domains; + r->out.names->count = num_sids; + r->out.names->names = names_out; + *r->out.count = mapped_count; + + return status; +} + +/*************************************************************************** + _lsa_LookupSids2 + ***************************************************************************/ + +NTSTATUS _lsa_LookupSids2(struct pipes_struct *p, + struct lsa_LookupSids2 *r) +{ + NTSTATUS status; + struct lsa_info *handle; + int num_sids = r->in.sids->num_sids; + uint32 mapped_count = 0; + struct lsa_RefDomainList *domains = NULL; + struct lsa_TranslatedName2 *names = NULL; + bool check_policy = true; + + switch (p->opnum) { + case NDR_LSA_LOOKUPSIDS3: + check_policy = false; + break; + case NDR_LSA_LOOKUPSIDS2: + default: + check_policy = true; + } + + if ((r->in.level < 1) || (r->in.level > 6)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (check_policy) { + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { + return NT_STATUS_INVALID_HANDLE; + } + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { + return NT_STATUS_ACCESS_DENIED; + } + } + + if (num_sids > MAX_LOOKUP_SIDS) { + DEBUG(5,("_lsa_LookupSids2: limit of %d exceeded, requested %d\n", + MAX_LOOKUP_SIDS, num_sids)); + return NT_STATUS_NONE_MAPPED; + } + + status = _lsa_lookup_sids_internal(p, + p->mem_ctx, + r->in.level, + num_sids, + r->in.sids->sids, + &domains, + &names, + &mapped_count); + + *r->out.domains = domains; + r->out.names->count = num_sids; + r->out.names->names = names; + *r->out.count = mapped_count; + + return status; +} + +/*************************************************************************** + _lsa_LookupSids3 + ***************************************************************************/ + +NTSTATUS _lsa_LookupSids3(struct pipes_struct *p, + struct lsa_LookupSids3 *r) +{ + struct lsa_LookupSids2 q; + + /* No policy handle on this call. Restrict to crypto connections. */ + if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + DEBUG(0,("_lsa_LookupSids3: client %s not using schannel for netlogon\n", + get_remote_machine_name() )); + return NT_STATUS_INVALID_PARAMETER; + } + + q.in.handle = NULL; + q.in.sids = r->in.sids; + q.in.level = r->in.level; + q.in.lookup_options = r->in.lookup_options; + q.in.client_revision = r->in.client_revision; + q.in.names = r->in.names; + q.in.count = r->in.count; + + q.out.domains = r->out.domains; + q.out.names = r->out.names; + q.out.count = r->out.count; + + return _lsa_LookupSids2(p, &q); +} + +/*************************************************************************** + ***************************************************************************/ + +static int lsa_lookup_level_to_flags(enum lsa_LookupNamesLevel level) +{ + int flags; + + switch (level) { + case LSA_LOOKUP_NAMES_ALL: /* 1 */ + flags = LOOKUP_NAME_ALL; + break; + case LSA_LOOKUP_NAMES_DOMAINS_ONLY: /* 2 */ + flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_REMOTE|LOOKUP_NAME_ISOLATED; + break; + case LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY: /* 3 */ + flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED; + break; + case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY: /* 4 */ + case LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY: /* 5 */ + case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2: /* 6 */ + case LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC: /* 7 */ + default: + flags = LOOKUP_NAME_NONE; + break; + } + + return flags; +} + +/*************************************************************************** + _lsa_LookupNames + ***************************************************************************/ + +NTSTATUS _lsa_LookupNames(struct pipes_struct *p, + struct lsa_LookupNames *r) +{ + NTSTATUS status = NT_STATUS_NONE_MAPPED; + struct lsa_info *handle; + struct lsa_String *names = r->in.names; + uint32 num_entries = r->in.num_names; + struct lsa_RefDomainList *domains = NULL; + struct lsa_TranslatedSid *rids = NULL; + uint32 mapped_count = 0; + int flags = 0; + + if (num_entries > MAX_LOOKUP_SIDS) { + num_entries = MAX_LOOKUP_SIDS; + DEBUG(5,("_lsa_LookupNames: truncating name lookup list to %d\n", + num_entries)); + } + + flags = lsa_lookup_level_to_flags(r->in.level); + + domains = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList); + if (!domains) { + return NT_STATUS_NO_MEMORY; + } + + if (num_entries) { + rids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_TranslatedSid, + num_entries); + if (!rids) { + return NT_STATUS_NO_MEMORY; + } + } else { + rids = NULL; + } + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { + status = NT_STATUS_INVALID_HANDLE; + goto done; + } + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { + status = NT_STATUS_ACCESS_DENIED; + goto done; + } + + /* set up the LSA Lookup RIDs response */ + become_root(); /* lookup_name can require root privs */ + status = lookup_lsa_rids(p->mem_ctx, domains, rids, num_entries, + names, flags, &mapped_count); + unbecome_root(); + +done: + + if (NT_STATUS_IS_OK(status) && (num_entries != 0) ) { + if (mapped_count == 0) { + status = NT_STATUS_NONE_MAPPED; + } else if (mapped_count != num_entries) { + status = STATUS_SOME_UNMAPPED; + } + } + + *r->out.count = mapped_count; + *r->out.domains = domains; + r->out.sids->sids = rids; + r->out.sids->count = num_entries; + + return status; +} + +/*************************************************************************** + _lsa_LookupNames2 + ***************************************************************************/ + +NTSTATUS _lsa_LookupNames2(struct pipes_struct *p, + struct lsa_LookupNames2 *r) +{ + NTSTATUS status; + struct lsa_LookupNames q; + struct lsa_TransSidArray2 *sid_array2 = r->in.sids; + struct lsa_TransSidArray *sid_array = NULL; + uint32_t i; + + sid_array = TALLOC_ZERO_P(p->mem_ctx, struct lsa_TransSidArray); + if (!sid_array) { + return NT_STATUS_NO_MEMORY; + } + + q.in.handle = r->in.handle; + q.in.num_names = r->in.num_names; + q.in.names = r->in.names; + q.in.level = r->in.level; + q.in.sids = sid_array; + q.in.count = r->in.count; + /* we do not know what this is for */ + /* = r->in.unknown1; */ + /* = r->in.unknown2; */ + + q.out.domains = r->out.domains; + q.out.sids = sid_array; + q.out.count = r->out.count; + + status = _lsa_LookupNames(p, &q); + + sid_array2->count = sid_array->count; + sid_array2->sids = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedSid2, sid_array->count); + if (!sid_array2->sids) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; icount; i++) { + sid_array2->sids[i].sid_type = sid_array->sids[i].sid_type; + sid_array2->sids[i].rid = sid_array->sids[i].rid; + sid_array2->sids[i].sid_index = sid_array->sids[i].sid_index; + sid_array2->sids[i].unknown = 0; + } + + r->out.sids = sid_array2; + + return status; +} + +/*************************************************************************** + _lsa_LookupNames3 + ***************************************************************************/ + +NTSTATUS _lsa_LookupNames3(struct pipes_struct *p, + struct lsa_LookupNames3 *r) +{ + NTSTATUS status; + struct lsa_info *handle; + struct lsa_String *names = r->in.names; + uint32 num_entries = r->in.num_names; + struct lsa_RefDomainList *domains = NULL; + struct lsa_TranslatedSid3 *trans_sids = NULL; + uint32 mapped_count = 0; + int flags = 0; + bool check_policy = true; + + switch (p->opnum) { + case NDR_LSA_LOOKUPNAMES4: + check_policy = false; + break; + case NDR_LSA_LOOKUPNAMES3: + default: + check_policy = true; + } + + if (num_entries > MAX_LOOKUP_SIDS) { + num_entries = MAX_LOOKUP_SIDS; + DEBUG(5,("_lsa_LookupNames3: truncating name lookup list to %d\n", num_entries)); + } + + /* Probably the lookup_level is some sort of bitmask. */ + if (r->in.level == 1) { + flags = LOOKUP_NAME_ALL; + } + + domains = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList); + if (!domains) { + return NT_STATUS_NO_MEMORY; + } + + if (num_entries) { + trans_sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_TranslatedSid3, + num_entries); + if (!trans_sids) { + return NT_STATUS_NO_MEMORY; + } + } else { + trans_sids = NULL; + } + + if (check_policy) { + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { + status = NT_STATUS_INVALID_HANDLE; + goto done; + } + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights */ + if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { + status = NT_STATUS_ACCESS_DENIED; + goto done; + } + } + + /* set up the LSA Lookup SIDs response */ + become_root(); /* lookup_name can require root privs */ + status = lookup_lsa_sids(p->mem_ctx, domains, trans_sids, num_entries, + names, flags, &mapped_count); + unbecome_root(); + +done: + + if (NT_STATUS_IS_OK(status)) { + if (mapped_count == 0) { + status = NT_STATUS_NONE_MAPPED; + } else if (mapped_count != num_entries) { + status = STATUS_SOME_UNMAPPED; + } + } + + *r->out.count = mapped_count; + *r->out.domains = domains; + r->out.sids->sids = trans_sids; + r->out.sids->count = num_entries; + + return status; +} + +/*************************************************************************** + _lsa_LookupNames4 + ***************************************************************************/ + +NTSTATUS _lsa_LookupNames4(struct pipes_struct *p, + struct lsa_LookupNames4 *r) +{ + struct lsa_LookupNames3 q; + + /* No policy handle on this call. Restrict to crypto connections. */ + if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + DEBUG(0,("_lsa_lookup_names4: client %s not using schannel for netlogon\n", + get_remote_machine_name() )); + return NT_STATUS_INVALID_PARAMETER; + } + + q.in.handle = NULL; + q.in.num_names = r->in.num_names; + q.in.names = r->in.names; + q.in.level = r->in.level; + q.in.lookup_options = r->in.lookup_options; + q.in.client_revision = r->in.client_revision; + q.in.sids = r->in.sids; + q.in.count = r->in.count; + + q.out.domains = r->out.domains; + q.out.sids = r->out.sids; + q.out.count = r->out.count; + + return _lsa_LookupNames3(p, &q); +} + +/*************************************************************************** + _lsa_close. Also weird - needs to check if lsa handle is correct. JRA. + ***************************************************************************/ + +NTSTATUS _lsa_Close(struct pipes_struct *p, struct lsa_Close *r) +{ + if (!find_policy_by_hnd(p, r->in.handle, NULL)) { + return NT_STATUS_INVALID_HANDLE; + } + + close_policy_hnd(p, r->in.handle); + ZERO_STRUCTP(r->out.handle); + return NT_STATUS_OK; +} + +/*************************************************************************** + ***************************************************************************/ + +NTSTATUS _lsa_OpenSecret(struct pipes_struct *p, struct lsa_OpenSecret *r) +{ + return NT_STATUS_OBJECT_NAME_NOT_FOUND; +} + +/*************************************************************************** + ***************************************************************************/ + +NTSTATUS _lsa_OpenTrustedDomain(struct pipes_struct *p, + struct lsa_OpenTrustedDomain *r) +{ + return NT_STATUS_OBJECT_NAME_NOT_FOUND; +} + +/*************************************************************************** + ***************************************************************************/ + +NTSTATUS _lsa_CreateTrustedDomain(struct pipes_struct *p, + struct lsa_CreateTrustedDomain *r) +{ + return NT_STATUS_ACCESS_DENIED; +} + +/*************************************************************************** + ***************************************************************************/ + +NTSTATUS _lsa_CreateSecret(struct pipes_struct *p, struct lsa_CreateSecret *r) +{ + return NT_STATUS_ACCESS_DENIED; +} + +/*************************************************************************** + ***************************************************************************/ + +NTSTATUS _lsa_SetSecret(struct pipes_struct *p, struct lsa_SetSecret *r) +{ + return NT_STATUS_ACCESS_DENIED; +} + +/*************************************************************************** + _lsa_DeleteObject + ***************************************************************************/ + +NTSTATUS _lsa_DeleteObject(struct pipes_struct *p, + struct lsa_DeleteObject *r) +{ + NTSTATUS status; + struct lsa_info *info = NULL; + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & SEC_STD_DELETE)) { + return NT_STATUS_ACCESS_DENIED; + } + + switch (info->type) { + case LSA_HANDLE_ACCOUNT_TYPE: + status = privilege_delete_account(&info->sid); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("_lsa_DeleteObject: privilege_delete_account gave: %s\n", + nt_errstr(status))); + return status; + } + break; + default: + return NT_STATUS_INVALID_HANDLE; + } + + close_policy_hnd(p, r->in.handle); + ZERO_STRUCTP(r->out.handle); + + return status; +} + +/*************************************************************************** + _lsa_EnumPrivs + ***************************************************************************/ + +NTSTATUS _lsa_EnumPrivs(struct pipes_struct *p, + struct lsa_EnumPrivs *r) +{ + struct lsa_info *handle; + uint32 i; + uint32 enum_context = *r->in.resume_handle; + int num_privs = num_privileges_in_short_list(); + struct lsa_PrivEntry *entries = NULL; + + /* remember that the enum_context starts at 0 and not 1 */ + + if ( enum_context >= num_privs ) + return NT_STATUS_NO_MORE_ENTRIES; + + DEBUG(10,("_lsa_EnumPrivs: enum_context:%d total entries:%d\n", + enum_context, num_privs)); + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) + return NT_STATUS_INVALID_HANDLE; + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights + I don't know if it's the right one. not documented. */ + + if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + if (num_privs) { + entries = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_PrivEntry, num_privs); + if (!entries) { + return NT_STATUS_NO_MEMORY; + } + } else { + entries = NULL; + } + + for (i = 0; i < num_privs; i++) { + if( i < enum_context) { + + init_lsa_StringLarge(&entries[i].name, NULL); + + entries[i].luid.low = 0; + entries[i].luid.high = 0; + } else { + + init_lsa_StringLarge(&entries[i].name, sec_privilege_name_from_index(i)); + + entries[i].luid.low = sec_privilege_from_index(i); + entries[i].luid.high = 0; + } + } + + enum_context = num_privs; + + *r->out.resume_handle = enum_context; + r->out.privs->count = num_privs; + r->out.privs->privs = entries; + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_LookupPrivDisplayName + ***************************************************************************/ + +NTSTATUS _lsa_LookupPrivDisplayName(struct pipes_struct *p, + struct lsa_LookupPrivDisplayName *r) +{ + struct lsa_info *handle; + const char *description; + struct lsa_StringLarge *lsa_name; + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) + return NT_STATUS_INVALID_HANDLE; + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights */ + + /* + * I don't know if it's the right one. not documented. + */ + if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + DEBUG(10,("_lsa_LookupPrivDisplayName: name = %s\n", r->in.name->string)); + + description = get_privilege_dispname(r->in.name->string); + if (!description) { + DEBUG(10,("_lsa_LookupPrivDisplayName: doesn't exist\n")); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + + DEBUG(10,("_lsa_LookupPrivDisplayName: display name = %s\n", description)); + + lsa_name = TALLOC_ZERO_P(p->mem_ctx, struct lsa_StringLarge); + if (!lsa_name) { + return NT_STATUS_NO_MEMORY; + } + + init_lsa_StringLarge(lsa_name, description); + + *r->out.returned_language_id = r->in.language_id; + *r->out.disp_name = lsa_name; + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_EnumAccounts + ***************************************************************************/ + +NTSTATUS _lsa_EnumAccounts(struct pipes_struct *p, + struct lsa_EnumAccounts *r) +{ + struct lsa_info *handle; + struct dom_sid *sid_list; + int i, j, num_entries; + NTSTATUS status; + struct lsa_SidPtr *sids = NULL; + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) + return NT_STATUS_INVALID_HANDLE; + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) + return NT_STATUS_ACCESS_DENIED; + + sid_list = NULL; + num_entries = 0; + + /* The only way we can currently find out all the SIDs that have been + privileged is to scan all privileges */ + + status = privilege_enumerate_accounts(&sid_list, &num_entries); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (*r->in.resume_handle >= num_entries) { + return NT_STATUS_NO_MORE_ENTRIES; + } + + if (num_entries - *r->in.resume_handle) { + sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr, + num_entries - *r->in.resume_handle); + if (!sids) { + talloc_free(sid_list); + return NT_STATUS_NO_MEMORY; + } + + for (i = *r->in.resume_handle, j = 0; i < num_entries; i++, j++) { + sids[j].sid = dom_sid_dup(p->mem_ctx, &sid_list[i]); + if (!sids[j].sid) { + talloc_free(sid_list); + return NT_STATUS_NO_MEMORY; + } + } + } + + talloc_free(sid_list); + + *r->out.resume_handle = num_entries; + r->out.sids->num_sids = num_entries; + r->out.sids->sids = sids; + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_GetUserName + ***************************************************************************/ + +NTSTATUS _lsa_GetUserName(struct pipes_struct *p, + struct lsa_GetUserName *r) +{ + const char *username, *domname; + struct lsa_String *account_name = NULL; + struct lsa_String *authority_name = NULL; + + if (r->in.account_name && + *r->in.account_name) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (r->in.authority_name && + *r->in.authority_name) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (p->server_info->guest) { + /* + * I'm 99% sure this is not the right place to do this, + * global_sid_Anonymous should probably be put into the token + * instead of the guest id -- vl + */ + if (!lookup_sid(p->mem_ctx, &global_sid_Anonymous, + &domname, &username, NULL)) { + return NT_STATUS_NO_MEMORY; + } + } else { + username = p->server_info->sanitized_username; + domname = p->server_info->info3->base.domain.string; + } + + account_name = TALLOC_P(p->mem_ctx, struct lsa_String); + if (!account_name) { + return NT_STATUS_NO_MEMORY; + } + init_lsa_String(account_name, username); + + if (r->out.authority_name) { + authority_name = TALLOC_P(p->mem_ctx, struct lsa_String); + if (!authority_name) { + return NT_STATUS_NO_MEMORY; + } + init_lsa_String(authority_name, domname); + } + + *r->out.account_name = account_name; + if (r->out.authority_name) { + *r->out.authority_name = authority_name; + } + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_CreateAccount + ***************************************************************************/ + +NTSTATUS _lsa_CreateAccount(struct pipes_struct *p, + struct lsa_CreateAccount *r) +{ + NTSTATUS status; + struct lsa_info *handle; + struct lsa_info *info; + uint32_t acc_granted; + struct security_descriptor *psd; + size_t sd_size; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) + return NT_STATUS_INVALID_HANDLE; + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* check if the user has enough rights */ + + if (!(handle->access & LSA_POLICY_CREATE_ACCOUNT)) { + return NT_STATUS_ACCESS_DENIED; + } + + /* Work out max allowed. */ + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &r->in.access_mask); + + /* map the generic bits to the lsa policy ones */ + se_map_generic(&r->in.access_mask, &lsa_account_mapping); + + status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, + &lsa_account_mapping, + r->in.sid, LSA_POLICY_ALL_ACCESS); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, r->in.access_mask, + &acc_granted, "_lsa_CreateAccount"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if ( is_privileged_sid( r->in.sid ) ) + return NT_STATUS_OBJECT_NAME_COLLISION; + + /* associate the user/group SID with the (unique) handle. */ + + info = TALLOC_ZERO_P(p->mem_ctx, struct lsa_info); + if (info == NULL) { + return NT_STATUS_NO_MEMORY; + } + + info->sid = *r->in.sid; + info->access = acc_granted; + info->type = LSA_HANDLE_ACCOUNT_TYPE; + + /* get a (unique) handle. open a policy on it. */ + if (!create_policy_hnd(p, r->out.acct_handle, info)) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + + return privilege_create_account( &info->sid ); +} + +/*************************************************************************** + _lsa_OpenAccount + ***************************************************************************/ + +NTSTATUS _lsa_OpenAccount(struct pipes_struct *p, + struct lsa_OpenAccount *r) +{ + struct lsa_info *handle; + struct lsa_info *info; + struct security_descriptor *psd = NULL; + size_t sd_size; + uint32_t des_access = r->in.access_mask; + uint32_t acc_granted; + NTSTATUS status; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) + return NT_STATUS_INVALID_HANDLE; + + if (handle->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* des_access is for the account here, not the policy + * handle - so don't check against policy handle. */ + + /* Work out max allowed. */ + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + /* map the generic bits to the lsa account ones */ + se_map_generic(&des_access, &lsa_account_mapping); + + /* get the generic lsa account SD until we store it */ + status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, + &lsa_account_mapping, + r->in.sid, LSA_ACCOUNT_ALL_ACCESS); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, des_access, + &acc_granted, "_lsa_OpenAccount" ); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* TODO: Fis the parsing routine before reenabling this check! */ + #if 0 + if (!lookup_sid(&handle->sid, dom_name, name, &type)) + return NT_STATUS_ACCESS_DENIED; + #endif + /* associate the user/group SID with the (unique) handle. */ + info = TALLOC_ZERO_P(p->mem_ctx, struct lsa_info); + if (info == NULL) { + return NT_STATUS_NO_MEMORY; + } + + info->sid = *r->in.sid; + info->access = acc_granted; + info->type = LSA_HANDLE_ACCOUNT_TYPE; + + /* get a (unique) handle. open a policy on it. */ + if (!create_policy_hnd(p, r->out.acct_handle, info)) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_EnumPrivsAccount + For a given SID, enumerate all the privilege this account has. + ***************************************************************************/ + +NTSTATUS _lsa_EnumPrivsAccount(struct pipes_struct *p, + struct lsa_EnumPrivsAccount *r) +{ + NTSTATUS status = NT_STATUS_OK; + struct lsa_info *info=NULL; + PRIVILEGE_SET *privileges; + struct lsa_PrivilegeSet *priv_set = NULL; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_ACCOUNT_VIEW)) + return NT_STATUS_ACCESS_DENIED; + + status = get_privileges_for_sid_as_set(p->mem_ctx, &privileges, &info->sid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *r->out.privs = priv_set = TALLOC_ZERO_P(p->mem_ctx, struct lsa_PrivilegeSet); + if (!priv_set) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("_lsa_EnumPrivsAccount: %s has %d privileges\n", + sid_string_dbg(&info->sid), + privileges->count)); + + priv_set->count = privileges->count; + priv_set->unknown = 0; + priv_set->set = talloc_move(priv_set, &privileges->set); + + return status; +} + +/*************************************************************************** + _lsa_GetSystemAccessAccount + ***************************************************************************/ + +NTSTATUS _lsa_GetSystemAccessAccount(struct pipes_struct *p, + struct lsa_GetSystemAccessAccount *r) +{ + NTSTATUS status; + struct lsa_info *info = NULL; + struct lsa_EnumPrivsAccount e; + struct lsa_PrivilegeSet *privset; + + /* find the connection policy handle. */ + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_ACCOUNT_VIEW)) + return NT_STATUS_ACCESS_DENIED; + + privset = talloc_zero(p->mem_ctx, struct lsa_PrivilegeSet); + if (!privset) { + return NT_STATUS_NO_MEMORY; + } + + e.in.handle = r->in.handle; + e.out.privs = &privset; + + status = _lsa_EnumPrivsAccount(p, &e); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("_lsa_GetSystemAccessAccount: " + "failed to call _lsa_EnumPrivsAccount(): %s\n", + nt_errstr(status))); + return status; + } + + /* Samba4 would iterate over the privset to merge the policy mode bits, + * not sure samba3 can do the same here, so just return what we did in + * the past - gd */ + + /* + 0x01 -> Log on locally + 0x02 -> Access this computer from network + 0x04 -> Log on as a batch job + 0x10 -> Log on as a service + + they can be ORed together + */ + + *r->out.access_mask = LSA_POLICY_MODE_INTERACTIVE | + LSA_POLICY_MODE_NETWORK; + + return NT_STATUS_OK; +} + +/*************************************************************************** + update the systemaccount information + ***************************************************************************/ + +NTSTATUS _lsa_SetSystemAccessAccount(struct pipes_struct *p, + struct lsa_SetSystemAccessAccount *r) +{ + struct lsa_info *info=NULL; + GROUP_MAP map; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS)) { + return NT_STATUS_ACCESS_DENIED; + } + + if (!pdb_getgrsid(&map, info->sid)) + return NT_STATUS_NO_SUCH_GROUP; + + return pdb_update_group_mapping_entry(&map); +} + +/*************************************************************************** + _lsa_AddPrivilegesToAccount + For a given SID, add some privileges. + ***************************************************************************/ + +NTSTATUS _lsa_AddPrivilegesToAccount(struct pipes_struct *p, + struct lsa_AddPrivilegesToAccount *r) +{ + struct lsa_info *info = NULL; + struct lsa_PrivilegeSet *set = NULL; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_ACCOUNT_ADJUST_PRIVILEGES)) { + return NT_STATUS_ACCESS_DENIED; + } + + set = r->in.privs; + + if ( !grant_privilege_set( &info->sid, set ) ) { + DEBUG(3,("_lsa_AddPrivilegesToAccount: grant_privilege_set(%s) failed!\n", + sid_string_dbg(&info->sid) )); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_RemovePrivilegesFromAccount + For a given SID, remove some privileges. + ***************************************************************************/ + +NTSTATUS _lsa_RemovePrivilegesFromAccount(struct pipes_struct *p, + struct lsa_RemovePrivilegesFromAccount *r) +{ + struct lsa_info *info = NULL; + struct lsa_PrivilegeSet *set = NULL; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_ACCOUNT_ADJUST_PRIVILEGES)) { + return NT_STATUS_ACCESS_DENIED; + } + + set = r->in.privs; + + if ( !revoke_privilege_set( &info->sid, set) ) { + DEBUG(3,("_lsa_RemovePrivilegesFromAccount: revoke_privilege(%s) failed!\n", + sid_string_dbg(&info->sid) )); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_LookupPrivName + ***************************************************************************/ + +NTSTATUS _lsa_LookupPrivName(struct pipes_struct *p, + struct lsa_LookupPrivName *r) +{ + struct lsa_info *info = NULL; + const char *name; + struct lsa_StringLarge *lsa_name; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) { + return NT_STATUS_INVALID_HANDLE; + } + + if (info->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) { + return NT_STATUS_ACCESS_DENIED; + } + + if (r->in.luid->high != 0) { + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + + name = sec_privilege_name(r->in.luid->low); + if (!name) { + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + + lsa_name = TALLOC_ZERO_P(p->mem_ctx, struct lsa_StringLarge); + if (!lsa_name) { + return NT_STATUS_NO_MEMORY; + } + + lsa_name->string = talloc_strdup(lsa_name, name); + if (!lsa_name->string) { + TALLOC_FREE(lsa_name); + return NT_STATUS_NO_MEMORY; + } + + *r->out.name = lsa_name; + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_QuerySecurity + ***************************************************************************/ + +NTSTATUS _lsa_QuerySecurity(struct pipes_struct *p, + struct lsa_QuerySecurity *r) +{ + struct lsa_info *handle=NULL; + struct security_descriptor *psd = NULL; + size_t sd_size; + NTSTATUS status; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) + return NT_STATUS_INVALID_HANDLE; + + switch (handle->type) { + case LSA_HANDLE_POLICY_TYPE: + status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, + &lsa_policy_mapping, NULL, 0); + break; + case LSA_HANDLE_ACCOUNT_TYPE: + status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, + &lsa_account_mapping, + &handle->sid, LSA_ACCOUNT_ALL_ACCESS); + break; + default: + status = NT_STATUS_INVALID_HANDLE; + break; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *r->out.sdbuf = make_sec_desc_buf(p->mem_ctx, sd_size, psd); + if (!*r->out.sdbuf) { + return NT_STATUS_NO_MEMORY; + } + + return status; +} + +/*************************************************************************** + _lsa_AddAccountRights + ***************************************************************************/ + +NTSTATUS _lsa_AddAccountRights(struct pipes_struct *p, + struct lsa_AddAccountRights *r) +{ + struct lsa_info *info = NULL; + int i = 0; + uint32_t acc_granted = 0; + struct security_descriptor *psd = NULL; + size_t sd_size; + struct dom_sid sid; + NTSTATUS status; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* get the generic lsa account SD for this SID until we store it */ + status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, + &lsa_account_mapping, + r->in.sid, LSA_ACCOUNT_ALL_ACCESS); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * From the MS DOCs. If the sid doesn't exist, ask for LSA_POLICY_CREATE_ACCOUNT + * on the policy handle. If it does, ask for + * LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW, + * on the account sid. We don't check here so just use the latter. JRA. + */ + + status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, + LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW, + &acc_granted, "_lsa_AddAccountRights" ); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* according to an NT4 PDC, you can add privileges to SIDs even without + call_lsa_create_account() first. And you can use any arbitrary SID. */ + + sid_copy( &sid, r->in.sid ); + + for ( i=0; i < r->in.rights->count; i++ ) { + + const char *privname = r->in.rights->names[i].string; + + /* only try to add non-null strings */ + + if ( !privname ) + continue; + + if ( !grant_privilege_by_name( &sid, privname ) ) { + DEBUG(2,("_lsa_AddAccountRights: Failed to add privilege [%s]\n", + privname )); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + } + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_RemoveAccountRights + ***************************************************************************/ + +NTSTATUS _lsa_RemoveAccountRights(struct pipes_struct *p, + struct lsa_RemoveAccountRights *r) +{ + struct lsa_info *info = NULL; + int i = 0; + struct security_descriptor *psd = NULL; + size_t sd_size; + struct dom_sid sid; + const char *privname = NULL; + uint32_t acc_granted = 0; + NTSTATUS status; + + /* find the connection policy handle. */ + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + /* get the generic lsa account SD for this SID until we store it */ + status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, + &lsa_account_mapping, + r->in.sid, LSA_ACCOUNT_ALL_ACCESS); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * From the MS DOCs. We need + * LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW + * and DELETE on the account sid. + */ + + status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, + LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS| + LSA_ACCOUNT_VIEW|SEC_STD_DELETE, + &acc_granted, "_lsa_RemoveAccountRights"); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + sid_copy( &sid, r->in.sid ); + + if ( r->in.remove_all ) { + if ( !revoke_all_privileges( &sid ) ) + return NT_STATUS_ACCESS_DENIED; + + return NT_STATUS_OK; + } + + for ( i=0; i < r->in.rights->count; i++ ) { + + privname = r->in.rights->names[i].string; + + /* only try to add non-null strings */ + + if ( !privname ) + continue; + + if ( !revoke_privilege_by_name( &sid, privname ) ) { + DEBUG(2,("_lsa_RemoveAccountRights: Failed to revoke privilege [%s]\n", + privname )); + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + } + + return NT_STATUS_OK; +} + +/******************************************************************* +********************************************************************/ + +static NTSTATUS init_lsa_right_set(TALLOC_CTX *mem_ctx, + struct lsa_RightSet *r, + PRIVILEGE_SET *privileges) +{ + uint32 i; + const char *privname; + const char **privname_array = NULL; + int num_priv = 0; + + for (i=0; icount; i++) { + if (privileges->set[i].luid.high) { + continue; + } + privname = sec_privilege_name(privileges->set[i].luid.low); + if (privname) { + if (!add_string_to_array(mem_ctx, privname, + &privname_array, &num_priv)) { + return NT_STATUS_NO_MEMORY; + } + } + } + + if (num_priv) { + + r->names = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_StringLarge, + num_priv); + if (!r->names) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; inames[i], privname_array[i]); + } + + r->count = num_priv; + } + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_EnumAccountRights + ***************************************************************************/ + +NTSTATUS _lsa_EnumAccountRights(struct pipes_struct *p, + struct lsa_EnumAccountRights *r) +{ + NTSTATUS status; + struct lsa_info *info = NULL; + PRIVILEGE_SET *privileges; + + /* find the connection policy handle. */ + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_ACCOUNT_VIEW)) { + return NT_STATUS_ACCESS_DENIED; + } + + /* according to an NT4 PDC, you can add privileges to SIDs even without + call_lsa_create_account() first. And you can use any arbitrary SID. */ + + /* according to MS-LSAD 3.1.4.5.10 it is required to return + * NT_STATUS_OBJECT_NAME_NOT_FOUND if the account sid was not found in + * the lsa database */ + + status = get_privileges_for_sid_as_set(p->mem_ctx, &privileges, r->in.sid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10,("_lsa_EnumAccountRights: %s has %d privileges\n", + sid_string_dbg(r->in.sid), privileges->count)); + + status = init_lsa_right_set(p->mem_ctx, r->out.rights, privileges); + + return status; +} + +/*************************************************************************** + _lsa_LookupPrivValue + ***************************************************************************/ + +NTSTATUS _lsa_LookupPrivValue(struct pipes_struct *p, + struct lsa_LookupPrivValue *r) +{ + struct lsa_info *info = NULL; + const char *name = NULL; + + /* find the connection policy handle. */ + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) + return NT_STATUS_INVALID_HANDLE; + + if (info->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_POLICY_LOOKUP_NAMES)) + return NT_STATUS_ACCESS_DENIED; + + name = r->in.name->string; + + DEBUG(10,("_lsa_lookup_priv_value: name = %s\n", name)); + + r->out.luid->low = sec_privilege_id(name); + r->out.luid->high = 0; + if (r->out.luid->low == SEC_PRIV_INVALID) { + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_EnumAccountsWithUserRight + ***************************************************************************/ + +NTSTATUS _lsa_EnumAccountsWithUserRight(struct pipes_struct *p, + struct lsa_EnumAccountsWithUserRight *r) +{ + NTSTATUS status; + struct lsa_info *info = NULL; + struct dom_sid *sids = NULL; + int num_sids = 0; + uint32_t i; + enum sec_privilege privilege; + + if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) { + return NT_STATUS_INVALID_HANDLE; + } + + if (info->type != LSA_HANDLE_POLICY_TYPE) { + return NT_STATUS_INVALID_HANDLE; + } + + if (!(info->access & LSA_POLICY_LOOKUP_NAMES)) { + return NT_STATUS_ACCESS_DENIED; + } + + if (!r->in.name || !r->in.name->string) { + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + + privilege = sec_privilege_id(r->in.name->string); + if (privilege == SEC_PRIV_INVALID) { + return NT_STATUS_NO_SUCH_PRIVILEGE; + } + + status = privilege_enum_sids(privilege, p->mem_ctx, + &sids, &num_sids); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r->out.sids->num_sids = num_sids; + r->out.sids->sids = talloc_array(p->mem_ctx, struct lsa_SidPtr, + r->out.sids->num_sids); + + for (i=0; i < r->out.sids->num_sids; i++) { + r->out.sids->sids[i].sid = dom_sid_dup(r->out.sids->sids, + &sids[i]); + if (!r->out.sids->sids[i].sid) { + TALLOC_FREE(r->out.sids->sids); + r->out.sids->num_sids = 0; + return NT_STATUS_NO_MEMORY; + } + } + + return NT_STATUS_OK; +} + +/*************************************************************************** + _lsa_Delete + ***************************************************************************/ + +NTSTATUS _lsa_Delete(struct pipes_struct *p, + struct lsa_Delete *r) +{ + return NT_STATUS_NOT_SUPPORTED; +} + +/* + * From here on the server routines are just dummy ones to make smbd link with + * librpc/gen_ndr/srv_lsa.c. These routines are actually never called, we are + * pulling the server stubs across one by one. + */ + +NTSTATUS _lsa_SetSecObj(struct pipes_struct *p, struct lsa_SetSecObj *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_ChangePassword(struct pipes_struct *p, + struct lsa_ChangePassword *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_SetInfoPolicy(struct pipes_struct *p, struct lsa_SetInfoPolicy *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_ClearAuditLog(struct pipes_struct *p, struct lsa_ClearAuditLog *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_GetQuotasForAccount(struct pipes_struct *p, + struct lsa_GetQuotasForAccount *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_SetQuotasForAccount(struct pipes_struct *p, + struct lsa_SetQuotasForAccount *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_QueryTrustedDomainInfo(struct pipes_struct *p, + struct lsa_QueryTrustedDomainInfo *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_SetInformationTrustedDomain(struct pipes_struct *p, + struct lsa_SetInformationTrustedDomain *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_QuerySecret(struct pipes_struct *p, struct lsa_QuerySecret *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_QueryTrustedDomainInfoBySid(struct pipes_struct *p, + struct lsa_QueryTrustedDomainInfoBySid *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_SetTrustedDomainInfo(struct pipes_struct *p, + struct lsa_SetTrustedDomainInfo *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_DeleteTrustedDomain(struct pipes_struct *p, + struct lsa_DeleteTrustedDomain *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_StorePrivateData(struct pipes_struct *p, + struct lsa_StorePrivateData *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_RetrievePrivateData(struct pipes_struct *p, + struct lsa_RetrievePrivateData *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_SetInfoPolicy2(struct pipes_struct *p, + struct lsa_SetInfoPolicy2 *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_QueryTrustedDomainInfoByName(struct pipes_struct *p, + struct lsa_QueryTrustedDomainInfoByName *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_SetTrustedDomainInfoByName(struct pipes_struct *p, + struct lsa_SetTrustedDomainInfoByName *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_EnumTrustedDomainsEx(struct pipes_struct *p, + struct lsa_EnumTrustedDomainsEx *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CreateTrustedDomainEx(struct pipes_struct *p, + struct lsa_CreateTrustedDomainEx *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CloseTrustedDomainEx(struct pipes_struct *p, + struct lsa_CloseTrustedDomainEx *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_QueryDomainInformationPolicy(struct pipes_struct *p, + struct lsa_QueryDomainInformationPolicy *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_SetDomainInformationPolicy(struct pipes_struct *p, + struct lsa_SetDomainInformationPolicy *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_OpenTrustedDomainByName(struct pipes_struct *p, + struct lsa_OpenTrustedDomainByName *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_TestCall(struct pipes_struct *p, struct lsa_TestCall *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CreateTrustedDomainEx2(struct pipes_struct *p, + struct lsa_CreateTrustedDomainEx2 *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRWRITE(struct pipes_struct *p, struct lsa_CREDRWRITE *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRREAD(struct pipes_struct *p, struct lsa_CREDRREAD *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRENUMERATE(struct pipes_struct *p, struct lsa_CREDRENUMERATE *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRWRITEDOMAINCREDENTIALS(struct pipes_struct *p, + struct lsa_CREDRWRITEDOMAINCREDENTIALS *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRREADDOMAINCREDENTIALS(struct pipes_struct *p, + struct lsa_CREDRREADDOMAINCREDENTIALS *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRDELETE(struct pipes_struct *p, struct lsa_CREDRDELETE *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRGETTARGETINFO(struct pipes_struct *p, + struct lsa_CREDRGETTARGETINFO *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRPROFILELOADED(struct pipes_struct *p, + struct lsa_CREDRPROFILELOADED *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRGETSESSIONTYPES(struct pipes_struct *p, + struct lsa_CREDRGETSESSIONTYPES *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_LSARREGISTERAUDITEVENT(struct pipes_struct *p, + struct lsa_LSARREGISTERAUDITEVENT *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_LSARGENAUDITEVENT(struct pipes_struct *p, + struct lsa_LSARGENAUDITEVENT *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_LSARUNREGISTERAUDITEVENT(struct pipes_struct *p, + struct lsa_LSARUNREGISTERAUDITEVENT *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_lsaRQueryForestTrustInformation(struct pipes_struct *p, + struct lsa_lsaRQueryForestTrustInformation *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_lsaRSetForestTrustInformation(struct pipes_struct *p, + struct lsa_lsaRSetForestTrustInformation *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_CREDRRENAME(struct pipes_struct *p, + struct lsa_CREDRRENAME *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_LSAROPENPOLICYSCE(struct pipes_struct *p, + struct lsa_LSAROPENPOLICYSCE *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct pipes_struct *p, + struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct pipes_struct *p, + struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS _lsa_LSARADTREPORTSECURITYEVENT(struct pipes_struct *p, + struct lsa_LSARADTREPORTSECURITYEVENT *r) +{ + p->rng_fault_state = True; + return NT_STATUS_NOT_IMPLEMENTED; +} diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c new file mode 100644 index 0000000000..b55c74adfc --- /dev/null +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -0,0 +1,2215 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997. + * Copyright (C) Jeremy Allison 1998-2001. + * Copyright (C) Andrew Bartlett 2001. + * Copyright (C) Guenther Deschner 2008-2009. + * + * 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 . + */ + +/* This is the implementation of the netlogon pipe. */ + +#include "includes.h" +#include "../libcli/auth/schannel.h" +#include "../librpc/gen_ndr/srv_netlogon.h" +#include "../librpc/gen_ndr/srv_samr.h" +#include "../librpc/gen_ndr/srv_lsa.h" +#include "../librpc/gen_ndr/ndr_samr_c.h" +#include "../librpc/gen_ndr/ndr_lsa_c.h" +#include "rpc_client/cli_lsarpc.h" +#include "librpc/gen_ndr/messaging.h" +#include "../lib/crypto/md4.h" +#include "rpc_client/init_lsa.h" +#include "rpc_server/rpc_ncacn_np.h" +#include "../libcli/security/security.h" + +extern userdom_struct current_user_info; + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +struct netlogon_server_pipe_state { + struct netr_Credential client_challenge; + struct netr_Credential server_challenge; +}; + +/************************************************************************* + _netr_LogonControl + *************************************************************************/ + +WERROR _netr_LogonControl(struct pipes_struct *p, + struct netr_LogonControl *r) +{ + struct netr_LogonControl2Ex l; + + switch (r->in.level) { + case 1: + break; + case 2: + return WERR_NOT_SUPPORTED; + default: + return WERR_UNKNOWN_LEVEL; + } + + l.in.logon_server = r->in.logon_server; + l.in.function_code = r->in.function_code; + l.in.level = r->in.level; + l.in.data = NULL; + l.out.query = r->out.query; + + return _netr_LogonControl2Ex(p, &l); +} + +/**************************************************************************** +Send a message to smbd to do a sam synchronisation +**************************************************************************/ + +static void send_sync_message(struct messaging_context *msg_ctx) +{ + DEBUG(3, ("sending sam synchronisation message\n")); + message_send_all(msg_ctx, MSG_SMB_SAM_SYNC, NULL, 0, NULL); +} + +/************************************************************************* + _netr_LogonControl2 + *************************************************************************/ + +WERROR _netr_LogonControl2(struct pipes_struct *p, + struct netr_LogonControl2 *r) +{ + struct netr_LogonControl2Ex l; + + l.in.logon_server = r->in.logon_server; + l.in.function_code = r->in.function_code; + l.in.level = r->in.level; + l.in.data = r->in.data; + l.out.query = r->out.query; + + return _netr_LogonControl2Ex(p, &l); +} + +/************************************************************************* + *************************************************************************/ + +static bool wb_change_trust_creds(const char *domain, WERROR *tc_status) +{ + wbcErr result; + struct wbcAuthErrorInfo *error = NULL; + + result = wbcChangeTrustCredentials(domain, &error); + switch (result) { + case WBC_ERR_WINBIND_NOT_AVAILABLE: + return false; + case WBC_ERR_DOMAIN_NOT_FOUND: + *tc_status = WERR_NO_SUCH_DOMAIN; + return true; + case WBC_ERR_SUCCESS: + *tc_status = WERR_OK; + return true; + default: + break; + } + + if (error && error->nt_status != 0) { + *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status)); + } else { + *tc_status = WERR_TRUST_FAILURE; + } + wbcFreeMemory(error); + return true; +} + +/************************************************************************* + *************************************************************************/ + +static bool wb_check_trust_creds(const char *domain, WERROR *tc_status) +{ + wbcErr result; + struct wbcAuthErrorInfo *error = NULL; + + result = wbcCheckTrustCredentials(domain, &error); + switch (result) { + case WBC_ERR_WINBIND_NOT_AVAILABLE: + return false; + case WBC_ERR_DOMAIN_NOT_FOUND: + *tc_status = WERR_NO_SUCH_DOMAIN; + return true; + case WBC_ERR_SUCCESS: + *tc_status = WERR_OK; + return true; + default: + break; + } + + if (error && error->nt_status != 0) { + *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status)); + } else { + *tc_status = WERR_TRUST_FAILURE; + } + wbcFreeMemory(error); + return true; +} + +/**************************************************************** + _netr_LogonControl2Ex +****************************************************************/ + +WERROR _netr_LogonControl2Ex(struct pipes_struct *p, + struct netr_LogonControl2Ex *r) +{ + uint32_t flags = 0x0; + WERROR pdc_connection_status = WERR_OK; + uint32_t logon_attempts = 0x0; + WERROR tc_status; + fstring dc_name2; + const char *dc_name = NULL; + struct sockaddr_storage dc_ss; + const char *domain = NULL; + struct netr_NETLOGON_INFO_1 *info1; + struct netr_NETLOGON_INFO_2 *info2; + struct netr_NETLOGON_INFO_3 *info3; + struct netr_NETLOGON_INFO_4 *info4; + const char *fn; + uint32_t acct_ctrl; + + switch (p->opnum) { + case NDR_NETR_LOGONCONTROL: + fn = "_netr_LogonControl"; + break; + case NDR_NETR_LOGONCONTROL2: + fn = "_netr_LogonControl2"; + break; + case NDR_NETR_LOGONCONTROL2EX: + fn = "_netr_LogonControl2Ex"; + break; + default: + return WERR_INVALID_PARAM; + } + + acct_ctrl = p->server_info->info3->base.acct_flags; + + switch (r->in.function_code) { + case NETLOGON_CONTROL_TC_VERIFY: + case NETLOGON_CONTROL_CHANGE_PASSWORD: + case NETLOGON_CONTROL_REDISCOVER: + if ((geteuid() != sec_initial_uid()) && + !nt_token_check_domain_rid(p->server_info->security_token, DOMAIN_RID_ADMINS) && + !nt_token_check_sid(&global_sid_Builtin_Administrators, p->server_info->security_token) && + !(acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST))) { + return WERR_ACCESS_DENIED; + } + break; + default: + break; + } + + tc_status = WERR_NO_SUCH_DOMAIN; + + switch (r->in.function_code) { + case NETLOGON_CONTROL_QUERY: + tc_status = WERR_OK; + break; + case NETLOGON_CONTROL_REPLICATE: + case NETLOGON_CONTROL_SYNCHRONIZE: + case NETLOGON_CONTROL_PDC_REPLICATE: + case NETLOGON_CONTROL_BACKUP_CHANGE_LOG: + case NETLOGON_CONTROL_BREAKPOINT: + if (acct_ctrl & ACB_NORMAL) { + return WERR_NOT_SUPPORTED; + } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) { + return WERR_ACCESS_DENIED; + } else { + return WERR_ACCESS_DENIED; + } + case NETLOGON_CONTROL_TRUNCATE_LOG: + if (acct_ctrl & ACB_NORMAL) { + break; + } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) { + return WERR_ACCESS_DENIED; + } else { + return WERR_ACCESS_DENIED; + } + + case NETLOGON_CONTROL_TRANSPORT_NOTIFY: + case NETLOGON_CONTROL_FORCE_DNS_REG: + case NETLOGON_CONTROL_QUERY_DNS_REG: + return WERR_NOT_SUPPORTED; + case NETLOGON_CONTROL_FIND_USER: + if (!r->in.data || !r->in.data->user) { + return WERR_NOT_SUPPORTED; + } + break; + case NETLOGON_CONTROL_SET_DBFLAG: + if (!r->in.data) { + return WERR_NOT_SUPPORTED; + } + break; + case NETLOGON_CONTROL_TC_VERIFY: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } + + if (!wb_check_trust_creds(r->in.data->domain, &tc_status)) { + return WERR_NOT_SUPPORTED; + } + break; + case NETLOGON_CONTROL_TC_QUERY: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } + + domain = r->in.data->domain; + + if (!is_trusted_domain(domain)) { + break; + } + + if (!get_dc_name(domain, NULL, dc_name2, &dc_ss)) { + tc_status = WERR_NO_LOGON_SERVERS; + break; + } + + dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); + if (!dc_name) { + return WERR_NOMEM; + } + + tc_status = WERR_OK; + + break; + + case NETLOGON_CONTROL_REDISCOVER: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } + + domain = r->in.data->domain; + + if (!is_trusted_domain(domain)) { + break; + } + + if (!get_dc_name(domain, NULL, dc_name2, &dc_ss)) { + tc_status = WERR_NO_LOGON_SERVERS; + break; + } + + dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); + if (!dc_name) { + return WERR_NOMEM; + } + + tc_status = WERR_OK; + + break; + + case NETLOGON_CONTROL_CHANGE_PASSWORD: + if (!r->in.data || !r->in.data->domain) { + return WERR_NOT_SUPPORTED; + } + + if (!wb_change_trust_creds(r->in.data->domain, &tc_status)) { + return WERR_NOT_SUPPORTED; + } + break; + + default: + /* no idea what this should be */ + DEBUG(0,("%s: unimplemented function level [%d]\n", + fn, r->in.function_code)); + return WERR_UNKNOWN_LEVEL; + } + + /* prepare the response */ + + switch (r->in.level) { + case 1: + info1 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_1); + W_ERROR_HAVE_NO_MEMORY(info1); + + info1->flags = flags; + info1->pdc_connection_status = pdc_connection_status; + + r->out.query->info1 = info1; + break; + case 2: + info2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_2); + W_ERROR_HAVE_NO_MEMORY(info2); + + info2->flags = flags; + info2->pdc_connection_status = pdc_connection_status; + info2->trusted_dc_name = dc_name; + info2->tc_connection_status = tc_status; + + r->out.query->info2 = info2; + break; + case 3: + info3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_3); + W_ERROR_HAVE_NO_MEMORY(info3); + + info3->flags = flags; + info3->logon_attempts = logon_attempts; + + r->out.query->info3 = info3; + break; + case 4: + info4 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_4); + W_ERROR_HAVE_NO_MEMORY(info4); + + info4->trusted_dc_name = dc_name; + info4->trusted_domain_name = r->in.data->domain; + + r->out.query->info4 = info4; + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + if (lp_server_role() == ROLE_DOMAIN_BDC) { + send_sync_message(p->msg_ctx); + } + + return WERR_OK; +} + +/************************************************************************* + _netr_NetrEnumerateTrustedDomains + *************************************************************************/ + +NTSTATUS _netr_NetrEnumerateTrustedDomains(struct pipes_struct *p, + struct netr_NetrEnumerateTrustedDomains *r) +{ + NTSTATUS status; + NTSTATUS result = NT_STATUS_OK; + DATA_BLOB blob; + int num_domains = 0; + const char **trusted_domains = NULL; + struct lsa_DomainList domain_list; + struct dcerpc_binding_handle *h = NULL; + struct policy_handle pol; + uint32_t enum_ctx = 0; + int i; + uint32_t max_size = (uint32_t)-1; + + DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__)); + + status = rpcint_binding_handle(p->mem_ctx, + &ndr_table_lsarpc, + p->client_id, + p->server_info, + p->msg_ctx, + &h); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcerpc_lsa_open_policy2(h, + p->mem_ctx, + NULL, + true, + LSA_POLICY_VIEW_LOCAL_INFORMATION, + &pol, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + do { + /* Lookup list of trusted domains */ + status = dcerpc_lsa_EnumTrustDom(h, + p->mem_ctx, + &pol, + &enum_ctx, + &domain_list, + max_size, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result) && + !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) && + !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) { + status = result; + goto out; + } + + for (i = 0; i < domain_list.count; i++) { + if (!add_string_to_array(p->mem_ctx, domain_list.domains[i].name.string, + &trusted_domains, &num_domains)) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + } + } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)); + + if (num_domains > 0) { + /* multi sz terminate */ + trusted_domains = talloc_realloc(p->mem_ctx, trusted_domains, const char *, num_domains + 1); + if (trusted_domains == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + trusted_domains[num_domains] = NULL; + } + + if (!push_reg_multi_sz(trusted_domains, &blob, trusted_domains)) { + TALLOC_FREE(trusted_domains); + status = NT_STATUS_NO_MEMORY; + goto out; + } + + r->out.trusted_domains_blob->data = blob.data; + r->out.trusted_domains_blob->length = blob.length; + + DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__)); + + status = NT_STATUS_OK; + + out: + if (h && is_valid_policy_hnd(&pol)) { + dcerpc_lsa_Close(h, p->mem_ctx, &pol, &result); + } + + return status; +} + +/************************************************************************* + *************************************************************************/ + +static NTSTATUS samr_find_machine_account(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *b, + const char *account_name, + uint32_t access_mask, + struct dom_sid2 **domain_sid_p, + uint32_t *user_rid_p, + struct policy_handle *user_handle) +{ + NTSTATUS status; + NTSTATUS result = NT_STATUS_OK; + struct policy_handle connect_handle, domain_handle; + struct lsa_String domain_name; + struct dom_sid2 *domain_sid; + struct lsa_String names; + struct samr_Ids rids; + struct samr_Ids types; + uint32_t rid; + + status = dcerpc_samr_Connect2(b, mem_ctx, + global_myname(), + SAMR_ACCESS_CONNECT_TO_SERVER | + SAMR_ACCESS_ENUM_DOMAINS | + SAMR_ACCESS_LOOKUP_DOMAIN, + &connect_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + init_lsa_String(&domain_name, get_global_sam_name()); + + status = dcerpc_samr_LookupDomain(b, mem_ctx, + &connect_handle, + &domain_name, + &domain_sid, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + status = dcerpc_samr_OpenDomain(b, mem_ctx, + &connect_handle, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, + domain_sid, + &domain_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + init_lsa_String(&names, account_name); + + status = dcerpc_samr_LookupNames(b, mem_ctx, + &domain_handle, + 1, + &names, + &rids, + &types, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + if (rids.count != 1) { + status = NT_STATUS_NO_SUCH_USER; + goto out; + } + if (rids.count != types.count) { + status = NT_STATUS_INVALID_PARAMETER; + goto out; + } + if (types.ids[0] != SID_NAME_USER) { + status = NT_STATUS_NO_SUCH_USER; + goto out; + } + + rid = rids.ids[0]; + + status = dcerpc_samr_OpenUser(b, mem_ctx, + &domain_handle, + access_mask, + rid, + user_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + if (user_rid_p) { + *user_rid_p = rid; + } + + if (domain_sid_p) { + *domain_sid_p = domain_sid; + } + + out: + if (b && is_valid_policy_hnd(&domain_handle)) { + dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result); + } + if (b && is_valid_policy_hnd(&connect_handle)) { + dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result); + } + + return status; +} + +/****************************************************************** + gets a machine password entry. checks access rights of the host. + ******************************************************************/ + +static NTSTATUS get_md4pw(struct samr_Password *md4pw, const char *mach_acct, + enum netr_SchannelType sec_chan_type, + struct dom_sid *sid, + struct messaging_context *msg_ctx) +{ + NTSTATUS status; + NTSTATUS result = NT_STATUS_OK; + TALLOC_CTX *mem_ctx; + struct dcerpc_binding_handle *h = NULL; + static struct client_address client_id; + struct policy_handle user_handle; + uint32_t user_rid; + struct dom_sid *domain_sid; + uint32_t acct_ctrl; + union samr_UserInfo *info; + struct auth_serversupplied_info *server_info; +#if 0 + + /* + * Currently this code is redundent as we already have a filter + * by hostname list. What this code really needs to do is to + * get a hosts allowed/hosts denied list from the SAM database + * on a per user basis, and make the access decision there. + * I will leave this code here for now as a reminder to implement + * this at a later date. JRA. + */ + + if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(), + p->client_id.name, + p->client_id.addr)) { + DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct)); + return False; + } +#endif /* 0 */ + + mem_ctx = talloc_stackframe(); + if (mem_ctx == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + status = make_server_info_system(mem_ctx, &server_info); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + ZERO_STRUCT(user_handle); + + strlcpy(client_id.addr, "127.0.0.1", sizeof(client_id.addr)); + client_id.name = "127.0.0.1"; + + status = rpcint_binding_handle(mem_ctx, + &ndr_table_samr, + &client_id, + server_info, + msg_ctx, + &h); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + become_root(); + status = samr_find_machine_account(mem_ctx, h, mach_acct, + SEC_FLAG_MAXIMUM_ALLOWED, + &domain_sid, &user_rid, + &user_handle); + unbecome_root(); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = dcerpc_samr_QueryUserInfo2(h, + mem_ctx, + &user_handle, + UserControlInformation, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + acct_ctrl = info->info16.acct_flags; + + if (acct_ctrl & ACB_DISABLED) { + DEBUG(0,("get_md4pw: Workstation %s: account is disabled\n", mach_acct)); + status = NT_STATUS_ACCOUNT_DISABLED; + goto out; + } + + if (!(acct_ctrl & ACB_SVRTRUST) && + !(acct_ctrl & ACB_WSTRUST) && + !(acct_ctrl & ACB_DOMTRUST)) + { + DEBUG(0,("get_md4pw: Workstation %s: account is not a trust account\n", mach_acct)); + status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; + goto out; + } + + switch (sec_chan_type) { + case SEC_CHAN_BDC: + if (!(acct_ctrl & ACB_SVRTRUST)) { + DEBUG(0,("get_md4pw: Workstation %s: BDC secure channel requested " + "but not a server trust account\n", mach_acct)); + status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; + goto out; + } + break; + case SEC_CHAN_WKSTA: + if (!(acct_ctrl & ACB_WSTRUST)) { + DEBUG(0,("get_md4pw: Workstation %s: WORKSTATION secure channel requested " + "but not a workstation trust account\n", mach_acct)); + status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; + goto out; + } + break; + case SEC_CHAN_DOMAIN: + if (!(acct_ctrl & ACB_DOMTRUST)) { + DEBUG(0,("get_md4pw: Workstation %s: DOMAIN secure channel requested " + "but not a interdomain trust account\n", mach_acct)); + status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; + goto out; + } + break; + default: + break; + } + + become_root(); + status = dcerpc_samr_QueryUserInfo2(h, + mem_ctx, + &user_handle, + UserInternal1Information, + &info, + &result); + unbecome_root(); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + if (info->info18.nt_pwd_active == 0) { + DEBUG(0,("get_md4pw: Workstation %s: account does not have a password\n", mach_acct)); + status = NT_STATUS_LOGON_FAILURE; + goto out; + } + + /* samr gives out nthash unencrypted (!) */ + memcpy(md4pw->hash, info->info18.nt_pwd.hash, 16); + + sid_compose(sid, domain_sid, user_rid); + + out: + if (h && is_valid_policy_hnd(&user_handle)) { + dcerpc_samr_Close(h, mem_ctx, &user_handle, &result); + } + + talloc_free(mem_ctx); + + return status; +} + +/************************************************************************* + _netr_ServerReqChallenge + *************************************************************************/ + +NTSTATUS _netr_ServerReqChallenge(struct pipes_struct *p, + struct netr_ServerReqChallenge *r) +{ + struct netlogon_server_pipe_state *pipe_state = + talloc_get_type(p->private_data, struct netlogon_server_pipe_state); + + if (pipe_state) { + DEBUG(10,("_netr_ServerReqChallenge: new challenge requested. Clearing old state.\n")); + talloc_free(pipe_state); + p->private_data = NULL; + } + + pipe_state = talloc(p, struct netlogon_server_pipe_state); + NT_STATUS_HAVE_NO_MEMORY(pipe_state); + + pipe_state->client_challenge = *r->in.credentials; + + generate_random_buffer(pipe_state->server_challenge.data, + sizeof(pipe_state->server_challenge.data)); + + *r->out.return_credentials = pipe_state->server_challenge; + + p->private_data = pipe_state; + + return NT_STATUS_OK; +} + +/************************************************************************* + _netr_ServerAuthenticate + Create the initial credentials. + *************************************************************************/ + +NTSTATUS _netr_ServerAuthenticate(struct pipes_struct *p, + struct netr_ServerAuthenticate *r) +{ + struct netr_ServerAuthenticate3 a; + uint32_t negotiate_flags = 0; + uint32_t rid; + + a.in.server_name = r->in.server_name; + a.in.account_name = r->in.account_name; + a.in.secure_channel_type = r->in.secure_channel_type; + a.in.computer_name = r->in.computer_name; + a.in.credentials = r->in.credentials; + a.in.negotiate_flags = &negotiate_flags; + + a.out.return_credentials = r->out.return_credentials; + a.out.rid = &rid; + a.out.negotiate_flags = &negotiate_flags; + + return _netr_ServerAuthenticate3(p, &a); + +} + +/************************************************************************* + _netr_ServerAuthenticate3 + *************************************************************************/ + +NTSTATUS _netr_ServerAuthenticate3(struct pipes_struct *p, + struct netr_ServerAuthenticate3 *r) +{ + NTSTATUS status; + uint32_t srv_flgs; + /* r->in.negotiate_flags is an aliased pointer to r->out.negotiate_flags, + * so use a copy to avoid destroying the client values. */ + uint32_t in_neg_flags = *r->in.negotiate_flags; + const char *fn; + struct dom_sid sid; + struct samr_Password mach_pwd; + struct netlogon_creds_CredentialState *creds; + struct netlogon_server_pipe_state *pipe_state = + talloc_get_type(p->private_data, struct netlogon_server_pipe_state); + + /* According to Microsoft (see bugid #6099) + * Windows 7 looks at the negotiate_flags + * returned in this structure *even if the + * call fails with access denied* ! So in order + * to allow Win7 to connect to a Samba NT style + * PDC we set the flags before we know if it's + * an error or not. + */ + + /* 0x000001ff */ + srv_flgs = NETLOGON_NEG_ACCOUNT_LOCKOUT | + NETLOGON_NEG_PERSISTENT_SAMREPL | + NETLOGON_NEG_ARCFOUR | + NETLOGON_NEG_PROMOTION_COUNT | + NETLOGON_NEG_CHANGELOG_BDC | + NETLOGON_NEG_FULL_SYNC_REPL | + NETLOGON_NEG_MULTIPLE_SIDS | + NETLOGON_NEG_REDO | + NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL | + NETLOGON_NEG_PASSWORD_SET2; + + /* Ensure we support strong (128-bit) keys. */ + if (in_neg_flags & NETLOGON_NEG_STRONG_KEYS) { + srv_flgs |= NETLOGON_NEG_STRONG_KEYS; + } + + if (lp_server_schannel() != false) { + srv_flgs |= NETLOGON_NEG_SCHANNEL; + } + + switch (p->opnum) { + case NDR_NETR_SERVERAUTHENTICATE: + fn = "_netr_ServerAuthenticate"; + break; + case NDR_NETR_SERVERAUTHENTICATE2: + fn = "_netr_ServerAuthenticate2"; + break; + case NDR_NETR_SERVERAUTHENTICATE3: + fn = "_netr_ServerAuthenticate3"; + break; + default: + return NT_STATUS_INTERNAL_ERROR; + } + + /* We use this as the key to store the creds: */ + /* r->in.computer_name */ + + if (!pipe_state) { + DEBUG(0,("%s: no challenge sent to client %s\n", fn, + r->in.computer_name)); + status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + if ( (lp_server_schannel() == true) && + ((in_neg_flags & NETLOGON_NEG_SCHANNEL) == 0) ) { + + /* schannel must be used, but client did not offer it. */ + DEBUG(0,("%s: schannel required but client failed " + "to offer it. Client was %s\n", + fn, r->in.account_name)); + status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + status = get_md4pw(&mach_pwd, + r->in.account_name, + r->in.secure_channel_type, + &sid, p->msg_ctx); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("%s: failed to get machine password for " + "account %s: %s\n", + fn, r->in.account_name, nt_errstr(status) )); + /* always return NT_STATUS_ACCESS_DENIED */ + status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + /* From the client / server challenges and md4 password, generate sess key */ + /* Check client credentials are valid. */ + creds = netlogon_creds_server_init(p->mem_ctx, + r->in.account_name, + r->in.computer_name, + r->in.secure_channel_type, + &pipe_state->client_challenge, + &pipe_state->server_challenge, + &mach_pwd, + r->in.credentials, + r->out.return_credentials, + *r->in.negotiate_flags); + if (!creds) { + DEBUG(0,("%s: netlogon_creds_server_check failed. Rejecting auth " + "request from client %s machine account %s\n", + fn, r->in.computer_name, + r->in.account_name)); + status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + creds->sid = dom_sid_dup(creds, &sid); + if (!creds->sid) { + status = NT_STATUS_NO_MEMORY; + goto out; + } + + /* Store off the state so we can continue after client disconnect. */ + become_root(); + status = schannel_save_creds_state(p->mem_ctx, lp_private_dir(), creds); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + sid_peek_rid(&sid, r->out.rid); + + status = NT_STATUS_OK; + + out: + + *r->out.negotiate_flags = srv_flgs; + return status; +} + +/************************************************************************* + _netr_ServerAuthenticate2 + *************************************************************************/ + +NTSTATUS _netr_ServerAuthenticate2(struct pipes_struct *p, + struct netr_ServerAuthenticate2 *r) +{ + struct netr_ServerAuthenticate3 a; + uint32_t rid; + + a.in.server_name = r->in.server_name; + a.in.account_name = r->in.account_name; + a.in.secure_channel_type = r->in.secure_channel_type; + a.in.computer_name = r->in.computer_name; + a.in.credentials = r->in.credentials; + a.in.negotiate_flags = r->in.negotiate_flags; + + a.out.return_credentials = r->out.return_credentials; + a.out.rid = &rid; + a.out.negotiate_flags = r->out.negotiate_flags; + + return _netr_ServerAuthenticate3(p, &a); +} + +/************************************************************************* + * If schannel is required for this call test that it actually is available. + *************************************************************************/ +static NTSTATUS schannel_check_required(struct pipe_auth_data *auth_info, + const char *computer_name, + bool integrity, bool privacy) +{ + if (auth_info && auth_info->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { + if (!privacy && !integrity) { + return NT_STATUS_OK; + } + + if ((!privacy && integrity) && + auth_info->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + return NT_STATUS_OK; + } + + if ((privacy || integrity) && + auth_info->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + return NT_STATUS_OK; + } + } + + /* test didn't pass */ + DEBUG(0, ("schannel_check_required: [%s] is not using schannel\n", + computer_name)); + + return NT_STATUS_ACCESS_DENIED; +} + +/************************************************************************* + *************************************************************************/ + +static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, + TALLOC_CTX *mem_ctx, + const char *computer_name, + struct netr_Authenticator *received_authenticator, + struct netr_Authenticator *return_authenticator, + struct netlogon_creds_CredentialState **creds_out) +{ + NTSTATUS status; + bool schannel_global_required = (lp_server_schannel() == true) ? true:false; + + if (schannel_global_required) { + status = schannel_check_required(&p->auth, + computer_name, + false, false); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + status = schannel_check_creds_state(mem_ctx, lp_private_dir(), + computer_name, received_authenticator, + return_authenticator, creds_out); + + return status; +} + +/************************************************************************* + *************************************************************************/ + +static NTSTATUS netr_set_machine_account_password(TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *account_name, + struct samr_Password *nt_hash) +{ + NTSTATUS status; + NTSTATUS result = NT_STATUS_OK; + struct dcerpc_binding_handle *h = NULL; + static struct client_address client_id; + struct policy_handle user_handle; + uint32_t acct_ctrl; + union samr_UserInfo *info; + struct samr_UserInfo18 info18; + DATA_BLOB in,out; + + ZERO_STRUCT(user_handle); + + strlcpy(client_id.addr, "127.0.0.1", sizeof(client_id.addr)); + client_id.name = "127.0.0.1"; + + status = rpcint_binding_handle(mem_ctx, + &ndr_table_samr, + &client_id, + server_info, + msg_ctx, + &h); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = samr_find_machine_account(mem_ctx, + h, + account_name, + SEC_FLAG_MAXIMUM_ALLOWED, + NULL, + NULL, + &user_handle); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = dcerpc_samr_QueryUserInfo2(h, + mem_ctx, + &user_handle, + UserControlInformation, + &info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + acct_ctrl = info->info16.acct_flags; + + if (!(acct_ctrl & ACB_WSTRUST || + acct_ctrl & ACB_SVRTRUST || + acct_ctrl & ACB_DOMTRUST)) { + status = NT_STATUS_NO_SUCH_USER; + goto out; + } + + if (acct_ctrl & ACB_DISABLED) { + status = NT_STATUS_ACCOUNT_DISABLED; + goto out; + } + + ZERO_STRUCT(info18); + + in = data_blob_const(nt_hash->hash, 16); + out = data_blob_talloc_zero(mem_ctx, 16); + sess_crypt_blob(&out, &in, &server_info->user_session_key, true); + memcpy(info18.nt_pwd.hash, out.data, out.length); + + info18.nt_pwd_active = true; + + info->info18 = info18; + + status = dcerpc_samr_SetUserInfo2(h, + mem_ctx, + &user_handle, + UserInternal1Information, + info, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + if (!NT_STATUS_IS_OK(result)) { + status = result; + goto out; + } + + out: + if (h && is_valid_policy_hnd(&user_handle)) { + dcerpc_samr_Close(h, mem_ctx, &user_handle, &result); + } + + return status; +} + +/************************************************************************* + _netr_ServerPasswordSet + *************************************************************************/ + +NTSTATUS _netr_ServerPasswordSet(struct pipes_struct *p, + struct netr_ServerPasswordSet *r) +{ + NTSTATUS status = NT_STATUS_OK; + int i; + struct netlogon_creds_CredentialState *creds; + + DEBUG(5,("_netr_ServerPasswordSet: %d\n", __LINE__)); + + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("_netr_ServerPasswordSet: netlogon_creds_server_step failed. Rejecting auth " + "request from client %s machine account %s\n", + r->in.computer_name, creds->computer_name)); + TALLOC_FREE(creds); + return status; + } + + DEBUG(3,("_netr_ServerPasswordSet: Server Password Set by remote machine:[%s] on account [%s]\n", + r->in.computer_name, creds->computer_name)); + + netlogon_creds_des_decrypt(creds, r->in.new_password); + + DEBUG(100,("_netr_ServerPasswordSet: new given value was :\n")); + for(i = 0; i < sizeof(r->in.new_password->hash); i++) + DEBUG(100,("%02X ", r->in.new_password->hash[i])); + DEBUG(100,("\n")); + + status = netr_set_machine_account_password(p->mem_ctx, + p->server_info, + p->msg_ctx, + creds->account_name, + r->in.new_password); + return status; +} + +/**************************************************************** + _netr_ServerPasswordSet2 +****************************************************************/ + +NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, + struct netr_ServerPasswordSet2 *r) +{ + NTSTATUS status; + struct netlogon_creds_CredentialState *creds; + DATA_BLOB plaintext; + struct samr_CryptPassword password_buf; + struct samr_Password nt_hash; + + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("_netr_ServerPasswordSet2: netlogon_creds_server_step " + "failed. Rejecting auth request from client %s machine account %s\n", + r->in.computer_name, creds->computer_name)); + TALLOC_FREE(creds); + return status; + } + + memcpy(password_buf.data, r->in.new_password->data, 512); + SIVAL(password_buf.data, 512, r->in.new_password->length); + netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); + + if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &plaintext)) { + return NT_STATUS_WRONG_PASSWORD; + } + + mdfour(nt_hash.hash, plaintext.data, plaintext.length); + + status = netr_set_machine_account_password(p->mem_ctx, + p->server_info, + p->msg_ctx, + creds->account_name, + &nt_hash); + return status; +} + +/************************************************************************* + _netr_LogonSamLogoff + *************************************************************************/ + +NTSTATUS _netr_LogonSamLogoff(struct pipes_struct *p, + struct netr_LogonSamLogoff *r) +{ + NTSTATUS status; + struct netlogon_creds_CredentialState *creds; + + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); + unbecome_root(); + + return status; +} + +static NTSTATUS _netr_LogonSamLogon_check(const struct netr_LogonSamLogonEx *r) +{ + switch (r->in.logon_level) { + case NetlogonInteractiveInformation: + case NetlogonServiceInformation: + case NetlogonInteractiveTransitiveInformation: + case NetlogonServiceTransitiveInformation: + if (r->in.logon->password == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + switch (r->in.validation_level) { + case NetlogonValidationSamInfo: /* 2 */ + case NetlogonValidationSamInfo2: /* 3 */ + break; + case NetlogonValidationSamInfo4: /* 6 */ + if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { + DEBUG(10,("Not adding validation info level 6 " + "without ADS passdb backend\n")); + return NT_STATUS_INVALID_INFO_CLASS; + } + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + break; + case NetlogonNetworkInformation: + case NetlogonNetworkTransitiveInformation: + if (r->in.logon->network == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + switch (r->in.validation_level) { + case NetlogonValidationSamInfo: /* 2 */ + case NetlogonValidationSamInfo2: /* 3 */ + break; + case NetlogonValidationSamInfo4: /* 6 */ + if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { + DEBUG(10,("Not adding validation info level 6 " + "without ADS passdb backend\n")); + return NT_STATUS_INVALID_INFO_CLASS; + } + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + break; + + case NetlogonGenericInformation: + if (r->in.logon->generic == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* we don't support this here */ + return NT_STATUS_INVALID_PARAMETER; +#if 0 + switch (r->in.validation_level) { + /* TODO: case NetlogonValidationGenericInfo: 4 */ + case NetlogonValidationGenericInfo2: /* 5 */ + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + break; +#endif + default: + return NT_STATUS_INVALID_PARAMETER; + } + + return NT_STATUS_OK; +} + +/************************************************************************* + _netr_LogonSamLogon_base + *************************************************************************/ + +static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, + struct netr_LogonSamLogonEx *r, + struct netlogon_creds_CredentialState *creds) +{ + NTSTATUS status = NT_STATUS_OK; + union netr_LogonLevel *logon = r->in.logon; + const char *nt_username, *nt_domain, *nt_workstation; + struct auth_usersupplied_info *user_info = NULL; + struct auth_serversupplied_info *server_info = NULL; + struct auth_context *auth_context = NULL; + uint8_t pipe_session_key[16]; + bool process_creds = true; + const char *fn; + + switch (p->opnum) { + case NDR_NETR_LOGONSAMLOGON: + process_creds = true; + fn = "_netr_LogonSamLogon"; + break; + case NDR_NETR_LOGONSAMLOGONWITHFLAGS: + process_creds = true; + fn = "_netr_LogonSamLogonWithFlags"; + break; + case NDR_NETR_LOGONSAMLOGONEX: + process_creds = false; + fn = "_netr_LogonSamLogonEx"; + break; + default: + return NT_STATUS_INTERNAL_ERROR; + } + + *r->out.authoritative = true; /* authoritative response */ + + switch (r->in.validation_level) { + case 2: + r->out.validation->sam2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo2); + if (!r->out.validation->sam2) { + return NT_STATUS_NO_MEMORY; + } + break; + case 3: + r->out.validation->sam3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo3); + if (!r->out.validation->sam3) { + return NT_STATUS_NO_MEMORY; + } + break; + case 6: + r->out.validation->sam6 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo6); + if (!r->out.validation->sam6) { + return NT_STATUS_NO_MEMORY; + } + break; + default: + DEBUG(0,("%s: bad validation_level value %d.\n", + fn, (int)r->in.validation_level)); + return NT_STATUS_INVALID_INFO_CLASS; + } + + switch (r->in.logon_level) { + case NetlogonInteractiveInformation: + case NetlogonServiceInformation: + case NetlogonInteractiveTransitiveInformation: + case NetlogonServiceTransitiveInformation: + nt_username = logon->password->identity_info.account_name.string ? + logon->password->identity_info.account_name.string : ""; + nt_domain = logon->password->identity_info.domain_name.string ? + logon->password->identity_info.domain_name.string : ""; + nt_workstation = logon->password->identity_info.workstation.string ? + logon->password->identity_info.workstation.string : ""; + + DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup())); + break; + case NetlogonNetworkInformation: + case NetlogonNetworkTransitiveInformation: + nt_username = logon->network->identity_info.account_name.string ? + logon->network->identity_info.account_name.string : ""; + nt_domain = logon->network->identity_info.domain_name.string ? + logon->network->identity_info.domain_name.string : ""; + nt_workstation = logon->network->identity_info.workstation.string ? + logon->network->identity_info.workstation.string : ""; + + DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup())); + break; + default: + DEBUG(2,("SAM Logon: unsupported switch value\n")); + return NT_STATUS_INVALID_INFO_CLASS; + } /* end switch */ + + DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain)); + fstrcpy(current_user_info.smb_name, nt_username); + sub_set_smb_name(nt_username); + + DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", + r->in.validation_level, nt_username)); + + status = NT_STATUS_OK; + + switch (r->in.logon_level) { + case NetlogonNetworkInformation: + case NetlogonNetworkTransitiveInformation: + { + const char *wksname = nt_workstation; + + status = make_auth_context_fixed(talloc_tos(), &auth_context, + logon->network->challenge); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* For a network logon, the workstation name comes in with two + * backslashes in the front. Strip them if they are there. */ + + if (*wksname == '\\') wksname++; + if (*wksname == '\\') wksname++; + + /* Standard challenge/response authentication */ + if (!make_user_info_netlogon_network(&user_info, + nt_username, nt_domain, + wksname, + logon->network->identity_info.parameter_control, + logon->network->lm.data, + logon->network->lm.length, + logon->network->nt.data, + logon->network->nt.length)) { + status = NT_STATUS_NO_MEMORY; + } + break; + } + case NetlogonInteractiveInformation: + case NetlogonServiceInformation: + case NetlogonInteractiveTransitiveInformation: + case NetlogonServiceTransitiveInformation: + + /* 'Interactive' authentication, supplies the password in its + MD4 form, encrypted with the session key. We will convert + this to challenge/response for the auth subsystem to chew + on */ + { + uint8_t chal[8]; + + status = make_auth_context_subsystem(talloc_tos(), + &auth_context); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + auth_context->get_ntlm_challenge(auth_context, chal); + + if (!make_user_info_netlogon_interactive(&user_info, + nt_username, nt_domain, + nt_workstation, + logon->password->identity_info.parameter_control, + chal, + logon->password->lmpassword.hash, + logon->password->ntpassword.hash, + creds->session_key)) { + status = NT_STATUS_NO_MEMORY; + } + break; + } + default: + DEBUG(2,("SAM Logon: unsupported switch value\n")); + return NT_STATUS_INVALID_INFO_CLASS; + } /* end switch */ + + if ( NT_STATUS_IS_OK(status) ) { + status = auth_context->check_ntlm_password(auth_context, + user_info, &server_info); + } + + TALLOC_FREE(auth_context); + free_user_info(&user_info); + + DEBUG(5,("%s: check_password returned status %s\n", + fn, nt_errstr(status))); + + /* Check account and password */ + + if (!NT_STATUS_IS_OK(status)) { + /* If we don't know what this domain is, we need to + indicate that we are not authoritative. This + allows the client to decide if it needs to try + a local user. Fix by jpjanosi@us.ibm.com, #2976 */ + if ( NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER) + && !strequal(nt_domain, get_global_sam_name()) + && !is_trusted_domain(nt_domain) ) + *r->out.authoritative = false; /* We are not authoritative */ + + TALLOC_FREE(server_info); + return status; + } + + if (server_info->guest) { + /* We don't like guest domain logons... */ + DEBUG(5,("%s: Attempted domain logon as GUEST " + "denied.\n", fn)); + TALLOC_FREE(server_info); + return NT_STATUS_LOGON_FAILURE; + } + + /* This is the point at which, if the login was successful, that + the SAM Local Security Authority should record that the user is + logged in to the domain. */ + + if (process_creds) { + /* Get the pipe session key from the creds. */ + memcpy(pipe_session_key, creds->session_key, 16); + } else { + struct schannel_state *schannel_auth; + /* Get the pipe session key from the schannel. */ + if ((p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) + || (p->auth.auth_ctx == NULL)) { + return NT_STATUS_INVALID_HANDLE; + } + + schannel_auth = talloc_get_type_abort(p->auth.auth_ctx, + struct schannel_state); + memcpy(pipe_session_key, schannel_auth->creds->session_key, 16); + } + + switch (r->in.validation_level) { + case 2: + status = serverinfo_to_SamInfo2(server_info, pipe_session_key, 16, + r->out.validation->sam2); + break; + case 3: + status = serverinfo_to_SamInfo3(server_info, pipe_session_key, 16, + r->out.validation->sam3); + break; + case 6: + status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16, + r->out.validation->sam6); + break; + } + + TALLOC_FREE(server_info); + + return status; +} + +/**************************************************************** + _netr_LogonSamLogonWithFlags +****************************************************************/ + +NTSTATUS _netr_LogonSamLogonWithFlags(struct pipes_struct *p, + struct netr_LogonSamLogonWithFlags *r) +{ + NTSTATUS status; + struct netlogon_creds_CredentialState *creds; + struct netr_LogonSamLogonEx r2; + struct netr_Authenticator return_authenticator; + + *r->out.authoritative = true; + + r2.in.server_name = r->in.server_name; + r2.in.computer_name = r->in.computer_name; + r2.in.logon_level = r->in.logon_level; + r2.in.logon = r->in.logon; + r2.in.validation_level = r->in.validation_level; + r2.in.flags = r->in.flags; + r2.out.validation = r->out.validation; + r2.out.authoritative = r->out.authoritative; + r2.out.flags = r->out.flags; + + status = _netr_LogonSamLogon_check(&r2); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + become_root(); + status = netr_creds_server_step_check(p, p->mem_ctx, + r->in.computer_name, + r->in.credential, + &return_authenticator, + &creds); + unbecome_root(); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = _netr_LogonSamLogon_base(p, &r2, creds); + + *r->out.return_authenticator = return_authenticator; + + return status; +} + +/************************************************************************* + _netr_LogonSamLogon + *************************************************************************/ + +NTSTATUS _netr_LogonSamLogon(struct pipes_struct *p, + struct netr_LogonSamLogon *r) +{ + NTSTATUS status; + struct netr_LogonSamLogonWithFlags r2; + uint32_t flags = 0; + + r2.in.server_name = r->in.server_name; + r2.in.computer_name = r->in.computer_name; + r2.in.credential = r->in.credential; + r2.in.logon_level = r->in.logon_level; + r2.in.logon = r->in.logon; + r2.in.validation_level = r->in.validation_level; + r2.in.return_authenticator = r->in.return_authenticator; + r2.in.flags = &flags; + r2.out.validation = r->out.validation; + r2.out.authoritative = r->out.authoritative; + r2.out.flags = &flags; + r2.out.return_authenticator = r->out.return_authenticator; + + status = _netr_LogonSamLogonWithFlags(p, &r2); + + return status; +} + +/************************************************************************* + _netr_LogonSamLogonEx + - no credential chaining. Map into net sam logon. + *************************************************************************/ + +NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, + struct netr_LogonSamLogonEx *r) +{ + NTSTATUS status; + struct netlogon_creds_CredentialState *creds = NULL; + + *r->out.authoritative = true; + + status = _netr_LogonSamLogon_check(r); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Only allow this if the pipe is protected. */ + if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + DEBUG(0,("_netr_LogonSamLogonEx: client %s not using schannel for netlogon\n", + get_remote_machine_name() )); + return NT_STATUS_INVALID_PARAMETER; + } + + become_root(); + status = schannel_get_creds_state(p->mem_ctx, lp_private_dir(), + r->in.computer_name, &creds); + unbecome_root(); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = _netr_LogonSamLogon_base(p, r, creds); + TALLOC_FREE(creds); + + return status; +} + +/************************************************************************* + _ds_enum_dom_trusts + *************************************************************************/ +#if 0 /* JERRY -- not correct */ + NTSTATUS _ds_enum_dom_trusts(struct pipes_struct *p, DS_Q_ENUM_DOM_TRUSTS *q_u, + DS_R_ENUM_DOM_TRUSTS *r_u) +{ + NTSTATUS status = NT_STATUS_OK; + + /* TODO: According to MSDN, the can only be executed against a + DC or domain member running Windows 2000 or later. Need + to test against a standalone 2k server and see what it + does. A windows 2000 DC includes its own domain in the + list. --jerry */ + + return status; +} +#endif /* JERRY */ + + +/**************************************************************** +****************************************************************/ + +WERROR _netr_LogonUasLogon(struct pipes_struct *p, + struct netr_LogonUasLogon *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_LogonUasLogoff(struct pipes_struct *p, + struct netr_LogonUasLogoff *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_DatabaseDeltas(struct pipes_struct *p, + struct netr_DatabaseDeltas *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_DatabaseSync(struct pipes_struct *p, + struct netr_DatabaseSync *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_AccountDeltas(struct pipes_struct *p, + struct netr_AccountDeltas *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_AccountSync(struct pipes_struct *p, + struct netr_AccountSync *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +static bool wb_getdcname(TALLOC_CTX *mem_ctx, + const char *domain, + const char **dcname, + uint32_t flags, + WERROR *werr) +{ + wbcErr result; + struct wbcDomainControllerInfo *dc_info = NULL; + + result = wbcLookupDomainController(domain, + flags, + &dc_info); + switch (result) { + case WBC_ERR_SUCCESS: + break; + case WBC_ERR_WINBIND_NOT_AVAILABLE: + return false; + case WBC_ERR_DOMAIN_NOT_FOUND: + *werr = WERR_NO_SUCH_DOMAIN; + return true; + default: + *werr = WERR_DOMAIN_CONTROLLER_NOT_FOUND; + return true; + } + + *dcname = talloc_strdup(mem_ctx, dc_info->dc_name); + wbcFreeMemory(dc_info); + if (!*dcname) { + *werr = WERR_NOMEM; + return false; + } + + *werr = WERR_OK; + + return true; +} + +/**************************************************************** + _netr_GetDcName +****************************************************************/ + +WERROR _netr_GetDcName(struct pipes_struct *p, + struct netr_GetDcName *r) +{ + NTSTATUS status; + WERROR werr; + uint32_t flags; + struct netr_DsRGetDCNameInfo *info; + bool ret; + + ret = wb_getdcname(p->mem_ctx, + r->in.domainname, + r->out.dcname, + WBC_LOOKUP_DC_IS_FLAT_NAME | + WBC_LOOKUP_DC_RETURN_FLAT_NAME | + WBC_LOOKUP_DC_PDC_REQUIRED, + &werr); + if (ret == true) { + return werr; + } + + flags = DS_PDC_REQUIRED | DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME; + + status = dsgetdcname(p->mem_ctx, + p->msg_ctx, + r->in.domainname, + NULL, + NULL, + flags, + &info); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc); + talloc_free(info); + if (!*r->out.dcname) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +/**************************************************************** + _netr_GetAnyDCName +****************************************************************/ + +WERROR _netr_GetAnyDCName(struct pipes_struct *p, + struct netr_GetAnyDCName *r) +{ + NTSTATUS status; + WERROR werr; + uint32_t flags; + struct netr_DsRGetDCNameInfo *info; + bool ret; + + ret = wb_getdcname(p->mem_ctx, + r->in.domainname, + r->out.dcname, + WBC_LOOKUP_DC_IS_FLAT_NAME | + WBC_LOOKUP_DC_RETURN_FLAT_NAME, + &werr); + if (ret == true) { + return werr; + } + + flags = DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME; + + status = dsgetdcname(p->mem_ctx, + p->msg_ctx, + r->in.domainname, + NULL, + NULL, + flags, + &info); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc); + talloc_free(info); + if (!*r->out.dcname) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_DatabaseSync2(struct pipes_struct *p, + struct netr_DatabaseSync2 *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_DatabaseRedo(struct pipes_struct *p, + struct netr_DatabaseRedo *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsRGetDCName(struct pipes_struct *p, + struct netr_DsRGetDCName *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_LogonGetCapabilities(struct pipes_struct *p, + struct netr_LogonGetCapabilities *r) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_NETRLOGONSETSERVICEBITS(struct pipes_struct *p, + struct netr_NETRLOGONSETSERVICEBITS *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_LogonGetTrustRid(struct pipes_struct *p, + struct netr_LogonGetTrustRid *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(struct pipes_struct *p, + struct netr_NETRLOGONCOMPUTESERVERDIGEST *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(struct pipes_struct *p, + struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsRGetDCNameEx(struct pipes_struct *p, + struct netr_DsRGetDCNameEx *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsRGetSiteName(struct pipes_struct *p, + struct netr_DsRGetSiteName *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_LogonGetDomainInfo(struct pipes_struct *p, + struct netr_LogonGetDomainInfo *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_ServerPasswordGet(struct pipes_struct *p, + struct netr_ServerPasswordGet *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_NETRLOGONSENDTOSAM(struct pipes_struct *p, + struct netr_NETRLOGONSENDTOSAM *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsRAddressToSitenamesW(struct pipes_struct *p, + struct netr_DsRAddressToSitenamesW *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsRGetDCNameEx2(struct pipes_struct *p, + struct netr_DsRGetDCNameEx2 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct pipes_struct *p, + struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_NetrEnumerateTrustedDomainsEx(struct pipes_struct *p, + struct netr_NetrEnumerateTrustedDomainsEx *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsRAddressToSitenamesExW(struct pipes_struct *p, + struct netr_DsRAddressToSitenamesExW *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsrGetDcSiteCoverageW(struct pipes_struct *p, + struct netr_DsrGetDcSiteCoverageW *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsrEnumerateDomainTrusts(struct pipes_struct *p, + struct netr_DsrEnumerateDomainTrusts *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsrDeregisterDNSHostRecords(struct pipes_struct *p, + struct netr_DsrDeregisterDNSHostRecords *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_ServerTrustPasswordsGet(struct pipes_struct *p, + struct netr_ServerTrustPasswordsGet *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p, + struct netr_DsRGetForestTrustInformation *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p, + struct netr_GetForestTrustInformation *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p, + struct netr_ServerGetTrustInfo *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_Unused47(struct pipes_struct *p, + struct netr_Unused47 *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _netr_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p, + struct netr_DsrUpdateReadOnlyServerDnsRecords *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} diff --git a/source3/rpc_server/ntsvcs/srv_ntsvcs_nt.c b/source3/rpc_server/ntsvcs/srv_ntsvcs_nt.c new file mode 100644 index 0000000000..ad1ba93746 --- /dev/null +++ b/source3/rpc_server/ntsvcs/srv_ntsvcs_nt.c @@ -0,0 +1,800 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * + * Copyright (C) Gerald (Jerry) Carter 2005. + * Copyright (C) Guenther Deschner 2008,2009. + * + * 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 . + */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_ntsvcs.h" +#include "services/svc_winreg_glue.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +/******************************************************************** +********************************************************************/ + +static char* get_device_path(TALLOC_CTX *mem_ctx, const char *device ) +{ + return talloc_asprintf(mem_ctx, "ROOT\\Legacy_%s\\0000", device); +} + +/******************************************************************** +********************************************************************/ + +WERROR _PNP_GetVersion(struct pipes_struct *p, + struct PNP_GetVersion *r) +{ + *r->out.version = 0x0400; /* no idea what this means */ + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +WERROR _PNP_GetDeviceListSize(struct pipes_struct *p, + struct PNP_GetDeviceListSize *r) +{ + char *devicepath; + + if ((r->in.flags & CM_GETIDLIST_FILTER_SERVICE) && + (!r->in.devicename)) { + return WERR_CM_INVALID_POINTER; + } + + if (!(devicepath = get_device_path(p->mem_ctx, r->in.devicename))) { + return WERR_NOMEM; + } + + *r->out.size = strlen(devicepath) + 2; + + TALLOC_FREE(devicepath); + + return WERR_OK; +} + +/**************************************************************** + _PNP_GetDeviceList +****************************************************************/ + +WERROR _PNP_GetDeviceList(struct pipes_struct *p, + struct PNP_GetDeviceList *r) +{ + char *devicepath; + uint32_t size = 0; + const char **multi_sz = NULL; + DATA_BLOB blob; + + if ((r->in.flags & CM_GETIDLIST_FILTER_SERVICE) && + (!r->in.filter)) { + return WERR_CM_INVALID_POINTER; + } + + if (!(devicepath = get_device_path(p->mem_ctx, r->in.filter))) { + return WERR_NOMEM; + } + + size = strlen(devicepath) + 2; + + if (*r->in.length < size) { + return WERR_CM_BUFFER_SMALL; + } + + multi_sz = talloc_zero_array(p->mem_ctx, const char *, 2); + if (!multi_sz) { + return WERR_NOMEM; + } + + multi_sz[0] = devicepath; + + if (!push_reg_multi_sz(multi_sz, &blob, multi_sz)) { + return WERR_NOMEM; + } + + if (*r->in.length < blob.length/2) { + return WERR_CM_BUFFER_SMALL; + } + + memcpy(r->out.buffer, blob.data, blob.length); + + return WERR_OK; +} + +/******************************************************************** +_PNP_GetDeviceRegProp +********************************************************************/ + +WERROR _PNP_GetDeviceRegProp(struct pipes_struct *p, + struct PNP_GetDeviceRegProp *r) +{ + char *ptr; + const char *result; + DATA_BLOB blob; + TALLOC_CTX *mem_ctx = NULL; + + switch( r->in.property ) { + case DEV_REGPROP_DESC: + + /* just parse the service name from the device path and then + lookup the display name */ + if ( !(ptr = strrchr_m( r->in.devicepath, '\\' )) ) + return WERR_GENERAL_FAILURE; + *ptr = '\0'; + + if ( !(ptr = strrchr_m( r->in.devicepath, '_' )) ) + return WERR_GENERAL_FAILURE; + ptr++; + + mem_ctx = talloc_stackframe(); + + result = svcctl_lookup_dispname(mem_ctx, + p->msg_ctx, + p->server_info, + ptr); + if (result == NULL) { + return WERR_GENERAL_FAILURE; + } + + if (!push_reg_sz(mem_ctx, &blob, result)) { + talloc_free(mem_ctx); + return WERR_GENERAL_FAILURE; + } + + if (*r->in.buffer_size < blob.length) { + *r->out.needed = blob.length; + *r->out.buffer_size = 0; + talloc_free(mem_ctx); + return WERR_CM_BUFFER_SMALL; + } + + r->out.buffer = (uint8_t *)talloc_memdup(p->mem_ctx, blob.data, blob.length); + talloc_free(mem_ctx); + if (!r->out.buffer) { + return WERR_NOMEM; + } + + *r->out.reg_data_type = REG_SZ; /* always 1...tested using a remove device manager connection */ + *r->out.buffer_size = blob.length; + *r->out.needed = blob.length; + + break; + + default: + *r->out.reg_data_type = 0x00437c98; /* ??? */ + return WERR_CM_NO_SUCH_VALUE; + } + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +WERROR _PNP_ValidateDeviceInstance(struct pipes_struct *p, + struct PNP_ValidateDeviceInstance *r) +{ + /* whatever dude */ + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +WERROR _PNP_GetHwProfInfo(struct pipes_struct *p, + struct PNP_GetHwProfInfo *r) +{ + /* steal the incoming buffer */ + + r->out.info = r->in.info; + + /* Take the 5th Ammentment */ + + return WERR_CM_NO_MORE_HW_PROFILES; +} + +/******************************************************************** +********************************************************************/ + +WERROR _PNP_HwProfFlags(struct pipes_struct *p, + struct PNP_HwProfFlags *r) +{ + /* just nod your head */ + + return WERR_OK; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_Disconnect(struct pipes_struct *p, + struct PNP_Disconnect *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_Connect(struct pipes_struct *p, + struct PNP_Connect *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetGlobalState(struct pipes_struct *p, + struct PNP_GetGlobalState *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_InitDetection(struct pipes_struct *p, + struct PNP_InitDetection *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_ReportLogOn(struct pipes_struct *p, + struct PNP_ReportLogOn *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetRootDeviceInstance(struct pipes_struct *p, + struct PNP_GetRootDeviceInstance *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetRelatedDeviceInstance(struct pipes_struct *p, + struct PNP_GetRelatedDeviceInstance *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_EnumerateSubKeys(struct pipes_struct *p, + struct PNP_EnumerateSubKeys *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetDepth(struct pipes_struct *p, + struct PNP_GetDepth *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_SetDeviceRegProp(struct pipes_struct *p, + struct PNP_SetDeviceRegProp *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetClassInstance(struct pipes_struct *p, + struct PNP_GetClassInstance *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_CreateKey(struct pipes_struct *p, + struct PNP_CreateKey *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_DeleteRegistryKey(struct pipes_struct *p, + struct PNP_DeleteRegistryKey *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetClassCount(struct pipes_struct *p, + struct PNP_GetClassCount *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetClassName(struct pipes_struct *p, + struct PNP_GetClassName *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_DeleteClassKey(struct pipes_struct *p, + struct PNP_DeleteClassKey *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetInterfaceDeviceAlias(struct pipes_struct *p, + struct PNP_GetInterfaceDeviceAlias *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetInterfaceDeviceList(struct pipes_struct *p, + struct PNP_GetInterfaceDeviceList *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetInterfaceDeviceListSize(struct pipes_struct *p, + struct PNP_GetInterfaceDeviceListSize *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_RegisterDeviceClassAssociation(struct pipes_struct *p, + struct PNP_RegisterDeviceClassAssociation *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_UnregisterDeviceClassAssociation(struct pipes_struct *p, + struct PNP_UnregisterDeviceClassAssociation *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetClassRegProp(struct pipes_struct *p, + struct PNP_GetClassRegProp *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_SetClassRegProp(struct pipes_struct *p, + struct PNP_SetClassRegProp *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_CreateDevInst(struct pipes_struct *p, + struct PNP_CreateDevInst *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_DeviceInstanceAction(struct pipes_struct *p, + struct PNP_DeviceInstanceAction *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetDeviceStatus(struct pipes_struct *p, + struct PNP_GetDeviceStatus *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_SetDeviceProblem(struct pipes_struct *p, + struct PNP_SetDeviceProblem *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_DisableDevInst(struct pipes_struct *p, + struct PNP_DisableDevInst *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_UninstallDevInst(struct pipes_struct *p, + struct PNP_UninstallDevInst *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_AddID(struct pipes_struct *p, + struct PNP_AddID *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_RegisterDriver(struct pipes_struct *p, + struct PNP_RegisterDriver *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_QueryRemove(struct pipes_struct *p, + struct PNP_QueryRemove *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_RequestDeviceEject(struct pipes_struct *p, + struct PNP_RequestDeviceEject *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_IsDockStationPresent(struct pipes_struct *p, + struct PNP_IsDockStationPresent *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_RequestEjectPC(struct pipes_struct *p, + struct PNP_RequestEjectPC *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_AddEmptyLogConf(struct pipes_struct *p, + struct PNP_AddEmptyLogConf *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_FreeLogConf(struct pipes_struct *p, + struct PNP_FreeLogConf *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetFirstLogConf(struct pipes_struct *p, + struct PNP_GetFirstLogConf *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetNextLogConf(struct pipes_struct *p, + struct PNP_GetNextLogConf *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetLogConfPriority(struct pipes_struct *p, + struct PNP_GetLogConfPriority *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_AddResDes(struct pipes_struct *p, + struct PNP_AddResDes *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_FreeResDes(struct pipes_struct *p, + struct PNP_FreeResDes *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetNextResDes(struct pipes_struct *p, + struct PNP_GetNextResDes *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetResDesData(struct pipes_struct *p, + struct PNP_GetResDesData *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetResDesDataSize(struct pipes_struct *p, + struct PNP_GetResDesDataSize *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_ModifyResDes(struct pipes_struct *p, + struct PNP_ModifyResDes *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_DetectResourceLimit(struct pipes_struct *p, + struct PNP_DetectResourceLimit *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_QueryResConfList(struct pipes_struct *p, + struct PNP_QueryResConfList *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_SetHwProf(struct pipes_struct *p, + struct PNP_SetHwProf *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_QueryArbitratorFreeData(struct pipes_struct *p, + struct PNP_QueryArbitratorFreeData *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_QueryArbitratorFreeSize(struct pipes_struct *p, + struct PNP_QueryArbitratorFreeSize *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_RunDetection(struct pipes_struct *p, + struct PNP_RunDetection *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_RegisterNotification(struct pipes_struct *p, + struct PNP_RegisterNotification *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_UnregisterNotification(struct pipes_struct *p, + struct PNP_UnregisterNotification *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetCustomDevProp(struct pipes_struct *p, + struct PNP_GetCustomDevProp *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetVersionInternal(struct pipes_struct *p, + struct PNP_GetVersionInternal *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetBlockedDriverInfo(struct pipes_struct *p, + struct PNP_GetBlockedDriverInfo *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** +****************************************************************/ + +WERROR _PNP_GetServerSideDeviceInstallFlags(struct pipes_struct *p, + struct PNP_GetServerSideDeviceInstallFlags *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c new file mode 100644 index 0000000000..85a63a5630 --- /dev/null +++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c @@ -0,0 +1,1132 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Andrew Bartlett 2001-2004 + + 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 . +*/ + +/* These comments regard the code to change the user's unix password: */ + +/* fork a child process to exec passwd and write to its + * tty to change a users password. This is running as the + * user who is attempting to change the password. + */ + +/* + * This code was copied/borrowed and stolen from various sources. + * The primary source was the poppasswd.c from the authors of POPMail. This software + * was included as a client to change passwords using the 'passwd' program + * on the remote machine. + * + * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson + * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences + * and rights to modify, distribute or incorporate this change to the CAP suite or + * using it for any other reason are granted, so long as this disclaimer is left intact. + */ + +/* + This code was hacked considerably for inclusion in Samba, primarily + by Andrew.Tridgell@anu.edu.au. The biggest change was the addition + of the "password chat" option, which allows the easy runtime + specification of the expected sequence of events to change a + password. + */ + +#include "includes.h" +#include "../libcli/auth/libcli_auth.h" +#include "../lib/crypto/arcfour.h" +#include "rpc_server/samr/srv_samr_util.h" + +#if ALLOW_CHANGE_PASSWORD + +static int findpty(char **slave) +{ + int master = -1; + char *line = NULL; + SMB_STRUCT_DIR *dirp = NULL; + const char *dpname; + + *slave = NULL; + +#if defined(HAVE_GRANTPT) + /* Try to open /dev/ptmx. If that fails, fall through to old method. */ + if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) { + grantpt(master); + unlockpt(master); + line = (char *)ptsname(master); + if (line) { + *slave = SMB_STRDUP(line); + } + + if (*slave == NULL) { + DEBUG(0, + ("findpty: Unable to create master/slave pty pair.\n")); + /* Stop fd leak on error. */ + close(master); + return -1; + } else { + DEBUG(10, + ("findpty: Allocated slave pty %s\n", *slave)); + return (master); + } + } +#endif /* HAVE_GRANTPT */ + + line = SMB_STRDUP("/dev/ptyXX"); + if (!line) { + return (-1); + } + + dirp = sys_opendir("/dev"); + if (!dirp) { + SAFE_FREE(line); + return (-1); + } + + while ((dpname = readdirname(dirp)) != NULL) { + if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) { + DEBUG(3, + ("pty: try to open %s, line was %s\n", dpname, + line)); + line[8] = dpname[3]; + line[9] = dpname[4]; + if ((master = sys_open(line, O_RDWR, 0)) >= 0) { + DEBUG(3, ("pty: opened %s\n", line)); + line[5] = 't'; + *slave = line; + sys_closedir(dirp); + return (master); + } + } + } + sys_closedir(dirp); + SAFE_FREE(line); + return (-1); +} + +static int dochild(int master, const char *slavedev, const struct passwd *pass, + const char *passwordprogram, bool as_root) +{ + int slave; + struct termios stermios; + gid_t gid; + uid_t uid; + char * const eptrs[1] = { NULL }; + + if (pass == NULL) + { + DEBUG(0, + ("dochild: user doesn't exist in the UNIX password database.\n")); + return False; + } + + gid = pass->pw_gid; + uid = pass->pw_uid; + + gain_root_privilege(); + + /* Start new session - gets rid of controlling terminal. */ + if (setsid() < 0) + { + DEBUG(3, + ("Weirdness, couldn't let go of controlling terminal\n")); + return (False); + } + + /* Open slave pty and acquire as new controlling terminal. */ + if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) + { + DEBUG(3, ("More weirdness, could not open %s\n", slavedev)); + return (False); + } +#if defined(TIOCSCTTY) && !defined(SUNOS5) + /* + * On patched Solaris 10 TIOCSCTTY is defined but seems not to work, + * see the discussion under + * https://bugzilla.samba.org/show_bug.cgi?id=5366. + */ + if (ioctl(slave, TIOCSCTTY, 0) < 0) + { + DEBUG(3, ("Error in ioctl call for slave pty\n")); + /* return(False); */ + } +#elif defined(I_PUSH) && defined(I_FIND) + if (ioctl(slave, I_FIND, "ptem") == 0) { + ioctl(slave, I_PUSH, "ptem"); + } + if (ioctl(slave, I_FIND, "ldterm") == 0) { + ioctl(slave, I_PUSH, "ldterm"); + } +#endif + + /* Close master. */ + close(master); + + /* Make slave stdin/out/err of child. */ + + if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) + { + DEBUG(3, ("Could not re-direct stdin\n")); + return (False); + } + if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) + { + DEBUG(3, ("Could not re-direct stdout\n")); + return (False); + } + if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) + { + DEBUG(3, ("Could not re-direct stderr\n")); + return (False); + } + if (slave > 2) + close(slave); + + /* Set proper terminal attributes - no echo, canonical input processing, + no map NL to CR/NL on output. */ + + if (tcgetattr(0, &stermios) < 0) + { + DEBUG(3, + ("could not read default terminal attributes on pty\n")); + return (False); + } + stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + stermios.c_lflag |= ICANON; +#ifdef ONLCR + stermios.c_oflag &= ~(ONLCR); +#endif + if (tcsetattr(0, TCSANOW, &stermios) < 0) + { + DEBUG(3, ("could not set attributes of pty\n")); + return (False); + } + + /* make us completely into the right uid */ + if (!as_root) + { + become_user_permanently(uid, gid); + } + + DEBUG(10, + ("Invoking '%s' as password change program.\n", + passwordprogram)); + + /* execl() password-change application */ + if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0) + { + DEBUG(3, ("Bad status returned from %s\n", passwordprogram)); + return (False); + } + return (True); +} + +static int expect(int master, char *issue, char *expected) +{ + char buffer[1024]; + int attempts, timeout, nread; + size_t len; + bool match = False; + + for (attempts = 0; attempts < 2; attempts++) { + NTSTATUS status; + if (!strequal(issue, ".")) { + if (lp_passwd_chat_debug()) + DEBUG(100, ("expect: sending [%s]\n", issue)); + + if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) { + DEBUG(2,("expect: (short) write returned %d\n", + (int)len )); + return False; + } + } + + if (strequal(expected, ".")) + return True; + + /* Initial timeout. */ + timeout = lp_passwd_chat_timeout() * 1000; + nread = 0; + buffer[nread] = 0; + + while (True) { + status = read_fd_with_timeout( + master, buffer + nread, 1, + sizeof(buffer) - nread - 1, + timeout, &len); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2, ("expect: read error %s\n", + nt_errstr(status))); + break; + } + nread += len; + buffer[nread] = 0; + + { + /* Eat leading/trailing whitespace before match. */ + char *str = SMB_STRDUP(buffer); + if (!str) { + DEBUG(2,("expect: ENOMEM\n")); + return False; + } + trim_char(str, ' ', ' '); + + if ((match = unix_wild_match(expected, str)) == True) { + /* Now data has started to return, lower timeout. */ + timeout = lp_passwd_chat_timeout() * 100; + } + SAFE_FREE(str); + } + } + + if (lp_passwd_chat_debug()) + DEBUG(100, ("expect: expected [%s] received [%s] match %s\n", + expected, buffer, match ? "yes" : "no" )); + + if (match) + break; + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2, ("expect: %s\n", nt_errstr(status))); + return False; + } + } + + DEBUG(10,("expect: returning %s\n", match ? "True" : "False" )); + return match; +} + +static void pwd_sub(char *buf) +{ + all_string_sub(buf, "\\n", "\n", 0); + all_string_sub(buf, "\\r", "\r", 0); + all_string_sub(buf, "\\s", " ", 0); + all_string_sub(buf, "\\t", "\t", 0); +} + +static int talktochild(int master, const char *seq) +{ + TALLOC_CTX *frame = talloc_stackframe(); + int count = 0; + char *issue; + char *expected; + + issue = talloc_strdup(frame, "."); + if (!issue) { + TALLOC_FREE(frame); + return false; + } + + while (next_token_talloc(frame, &seq, &expected, NULL)) { + pwd_sub(expected); + count++; + + if (!expect(master, issue, expected)) { + DEBUG(3, ("Response %d incorrect\n", count)); + TALLOC_FREE(frame); + return false; + } + + if (!next_token_talloc(frame, &seq, &issue, NULL)) { + issue = talloc_strdup(frame, "."); + if (!issue) { + TALLOC_FREE(frame); + return false; + } + } + pwd_sub(issue); + } + + if (!strequal(issue, ".")) { + /* we have one final issue to send */ + expected = talloc_strdup(frame, "."); + if (!expected) { + TALLOC_FREE(frame); + return false; + } + if (!expect(master, issue, expected)) { + TALLOC_FREE(frame); + return False; + } + } + TALLOC_FREE(frame); + return (count > 0); +} + +static bool chat_with_program(char *passwordprogram, const struct passwd *pass, + char *chatsequence, bool as_root) +{ + char *slavedev = NULL; + int master; + pid_t pid, wpid; + int wstat; + bool chstat = False; + + if (pass == NULL) { + DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n")); + return False; + } + + /* allocate a pseudo-terminal device */ + if ((master = findpty(&slavedev)) < 0) { + DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name)); + return (False); + } + + /* + * We need to temporarily stop CatchChild from eating + * SIGCLD signals as it also eats the exit status code. JRA. + */ + + CatchChildLeaveStatus(); + + if ((pid = sys_fork()) < 0) { + DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name)); + SAFE_FREE(slavedev); + close(master); + CatchChild(); + return (False); + } + + /* we now have a pty */ + if (pid > 0) { /* This is the parent process */ + /* Don't need this anymore in parent. */ + SAFE_FREE(slavedev); + + if ((chstat = talktochild(master, chatsequence)) == False) { + DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name)); + kill(pid, SIGKILL); /* be sure to end this process */ + } + + while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { + if (errno == EINTR) { + errno = 0; + continue; + } + break; + } + + if (wpid < 0) { + DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n")); + close(master); + CatchChild(); + return (False); + } + + /* + * Go back to ignoring children. + */ + CatchChild(); + + close(master); + + if (pid != wpid) { + DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n")); + return (False); + } + if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) { + DEBUG(3, ("chat_with_program: The process exited with status %d \ +while we were waiting\n", WEXITSTATUS(wstat))); + return (False); + } +#if defined(WIFSIGNALLED) && defined(WTERMSIG) + else if (WIFSIGNALLED(wstat)) { + DEBUG(3, ("chat_with_program: The process was killed by signal %d \ +while we were waiting\n", WTERMSIG(wstat))); + return (False); + } +#endif + } else { + /* CHILD */ + + /* + * Lose any elevated privileges. + */ + drop_effective_capability(KERNEL_OPLOCK_CAPABILITY); + drop_effective_capability(DMAPI_ACCESS_CAPABILITY); + + /* make sure it doesn't freeze */ + alarm(20); + + if (as_root) + become_root(); + + DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name, + (int)getuid(), (int)getgid(), BOOLSTR(as_root) )); + chstat = dochild(master, slavedev, pass, passwordprogram, as_root); + + if (as_root) + unbecome_root(); + + /* + * The child should never return from dochild() .... + */ + + DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat)); + exit(1); + } + + if (chstat) + DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n", + (chstat ? "" : "un"), pass->pw_name)); + return (chstat); +} + +bool chgpasswd(const char *name, const char *rhost, const struct passwd *pass, + const char *oldpass, const char *newpass, bool as_root) +{ + char *passwordprogram = NULL; + char *chatsequence = NULL; + size_t i; + size_t len; + TALLOC_CTX *ctx = talloc_tos(); + + if (!oldpass) { + oldpass = ""; + } + + DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name)); + +#ifdef DEBUG_PASSWORD + DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass)); +#endif + + /* Take the passed information and test it for minimum criteria */ + + /* Password is same as old password */ + if (strcmp(oldpass, newpass) == 0) { + /* don't allow same password */ + DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */ + return (False); /* inform the user */ + } + + /* + * Check the old and new passwords don't contain any control + * characters. + */ + + len = strlen(oldpass); + for (i = 0; i < len; i++) { + if (iscntrl((int)oldpass[i])) { + DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n")); + return False; + } + } + + len = strlen(newpass); + for (i = 0; i < len; i++) { + if (iscntrl((int)newpass[i])) { + DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n")); + return False; + } + } + +#ifdef WITH_PAM + if (lp_pam_password_change()) { + bool ret; +#ifdef HAVE_SETLOCALE + const char *prevlocale = setlocale(LC_ALL, "C"); +#endif + + if (as_root) + become_root(); + + if (pass) { + ret = smb_pam_passchange(pass->pw_name, rhost, + oldpass, newpass); + } else { + ret = smb_pam_passchange(name, rhost, oldpass, + newpass); + } + + if (as_root) + unbecome_root(); + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, prevlocale); +#endif + + return ret; + } +#endif + + /* A non-PAM password change just doen't make sense without a valid local user */ + + if (pass == NULL) { + DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name)); + return false; + } + + passwordprogram = talloc_strdup(ctx, lp_passwd_program()); + if (!passwordprogram || !*passwordprogram) { + DEBUG(2, ("chgpasswd: Null password program - no password changing\n")); + return false; + } + chatsequence = talloc_strdup(ctx, lp_passwd_chat()); + if (!chatsequence || !*chatsequence) { + DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n")); + return false; + } + + if (as_root) { + /* The password program *must* contain the user name to work. Fail if not. */ + if (strstr_m(passwordprogram, "%u") == NULL) { + DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \ +the string %%u, and the given string %s does not.\n", passwordprogram )); + return false; + } + } + + passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name); + if (!passwordprogram) { + return false; + } + + /* note that we do NOT substitute the %o and %n in the password program + as this would open up a security hole where the user could use + a new password containing shell escape characters */ + + chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name); + if (!chatsequence) { + return false; + } + chatsequence = talloc_all_string_sub(ctx, + chatsequence, + "%o", + oldpass); + if (!chatsequence) { + return false; + } + chatsequence = talloc_all_string_sub(ctx, + chatsequence, + "%n", + newpass); + return chat_with_program(passwordprogram, + pass, + chatsequence, + as_root); +} + +#else /* ALLOW_CHANGE_PASSWORD */ + +bool chgpasswd(const char *name, const struct passwd *pass, + const char *oldpass, const char *newpass, bool as_root) +{ + DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name)); + return (False); +} +#endif /* ALLOW_CHANGE_PASSWORD */ + +/*********************************************************** + Decrypt and verify a user password change. + + The 516 byte long buffers are encrypted with the old NT and + old LM passwords, and if the NT passwords are present, both + buffers contain a unicode string. + + After decrypting the buffers, check the password is correct by + matching the old hashed passwords with the passwords in the passdb. + +************************************************************/ + +static NTSTATUS check_oem_password(const char *user, + uchar password_encrypted_with_lm_hash[516], + const uchar old_lm_hash_encrypted[16], + uchar password_encrypted_with_nt_hash[516], + const uchar old_nt_hash_encrypted[16], + struct samu *sampass, + char **pp_new_passwd) +{ + uchar null_pw[16]; + uchar null_ntpw[16]; + uint8 *password_encrypted; + const uint8 *encryption_key; + const uint8 *lanman_pw, *nt_pw; + uint32 acct_ctrl; + size_t new_pw_len; + uchar new_nt_hash[16]; + uchar new_lm_hash[16]; + uchar verifier[16]; + char no_pw[2]; + + bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted); + bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted); + + acct_ctrl = pdb_get_acct_ctrl(sampass); +#if 0 + /* I am convinced this check here is wrong, it is valid to + * change a password of a user that has a disabled account - gd */ + + if (acct_ctrl & ACB_DISABLED) { + DEBUG(2,("check_lanman_password: account %s disabled.\n", user)); + return NT_STATUS_ACCOUNT_DISABLED; + } +#endif + if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) { + /* construct a null password (in case one is needed */ + no_pw[0] = 0; + no_pw[1] = 0; + nt_lm_owf_gen(no_pw, null_ntpw, null_pw); + lanman_pw = null_pw; + nt_pw = null_pw; + + } else { + /* save pointers to passwords so we don't have to keep looking them up */ + if (lp_lanman_auth()) { + lanman_pw = pdb_get_lanman_passwd(sampass); + } else { + lanman_pw = NULL; + } + nt_pw = pdb_get_nt_passwd(sampass); + } + + if (nt_pw && nt_pass_set) { + /* IDEAL Case: passwords are in unicode, and we can + * read use the password encrypted with the NT hash + */ + password_encrypted = password_encrypted_with_nt_hash; + encryption_key = nt_pw; + } else if (lanman_pw && lm_pass_set) { + /* password may still be in unicode, but use LM hash version */ + password_encrypted = password_encrypted_with_lm_hash; + encryption_key = lanman_pw; + } else if (nt_pass_set) { + DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", + user)); + return NT_STATUS_WRONG_PASSWORD; + } else if (lm_pass_set) { + if (lp_lanman_auth()) { + DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n", + user)); + } else { + DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n", + user)); + } + return NT_STATUS_WRONG_PASSWORD; + } else { + DEBUG(1, ("password change requested for user %s, but no password supplied!\n", + user)); + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * Decrypt the password with the key + */ + arcfour_crypt( password_encrypted, encryption_key, 516); + + if (!decode_pw_buffer(talloc_tos(), + password_encrypted, + pp_new_passwd, + &new_pw_len, + nt_pass_set ? CH_UTF16 : CH_DOS)) { + return NT_STATUS_WRONG_PASSWORD; + } + + /* + * To ensure we got the correct new password, hash it and + * use it as a key to test the passed old password. + */ + + if (nt_pass_set) { + /* NT passwords, verify the NT hash. */ + + /* Calculate the MD4 hash (NT compatible) of the password */ + memset(new_nt_hash, '\0', 16); + E_md4hash(*pp_new_passwd, new_nt_hash); + + if (nt_pw) { + /* + * check the NT verifier + */ + E_old_pw_hash(new_nt_hash, nt_pw, verifier); + if (memcmp(verifier, old_nt_hash_encrypted, 16)) { + DEBUG(0, ("check_oem_password: old nt " + "password doesn't match.\n")); + return NT_STATUS_WRONG_PASSWORD; + } + + /* We could check the LM password here, but there is + * little point, we already know the password is + * correct, and the LM password might not even be + * present. */ + + /* Further, LM hash generation algorithms + * differ with charset, so we could + * incorrectly fail a perfectly valid password + * change */ +#ifdef DEBUG_PASSWORD + DEBUG(100, + ("check_oem_password: password %s ok\n", *pp_new_passwd)); +#endif + return NT_STATUS_OK; + } + + if (lanman_pw) { + /* + * check the lm verifier + */ + E_old_pw_hash(new_nt_hash, lanman_pw, verifier); + if (memcmp(verifier, old_lm_hash_encrypted, 16)) { + DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); + return NT_STATUS_WRONG_PASSWORD; + } +#ifdef DEBUG_PASSWORD + DEBUG(100, + ("check_oem_password: password %s ok\n", *pp_new_passwd)); +#endif + return NT_STATUS_OK; + } + } + + if (lanman_pw && lm_pass_set) { + + E_deshash(*pp_new_passwd, new_lm_hash); + + /* + * check the lm verifier + */ + E_old_pw_hash(new_lm_hash, lanman_pw, verifier); + if (memcmp(verifier, old_lm_hash_encrypted, 16)) { + DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); + return NT_STATUS_WRONG_PASSWORD; + } + +#ifdef DEBUG_PASSWORD + DEBUG(100, + ("check_oem_password: password %s ok\n", *pp_new_passwd)); +#endif + return NT_STATUS_OK; + } + + /* should not be reached */ + return NT_STATUS_WRONG_PASSWORD; +} + +static bool password_in_history(uint8_t nt_pw[NT_HASH_LEN], + uint32_t pw_history_len, + const uint8_t *pw_history) +{ + static const uint8_t zero_md5_nt_pw[SALTED_MD5_HASH_LEN] = { 0, }; + int i; + + dump_data(100, nt_pw, NT_HASH_LEN); + dump_data(100, pw_history, PW_HISTORY_ENTRY_LEN * pw_history_len); + + for (i=0; i 2002, + * Copyright (C) Gerald (Jerry) Carter 2003-2004, + * Copyright (C) Simo Sorce 2003. + * Copyright (C) Volker Lendecke 2005. + * Copyright (C) Guenther Deschner 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 . + */ + +/* + * This is the implementation of the SAMR code. + */ + +#include "includes.h" +#include "smbd/globals.h" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/srv_samr.h" +#include "rpc_server/samr/srv_samr_util.h" +#include "../lib/crypto/arcfour.h" +#include "secrets.h" +#include "rpc_client/init_lsa.h" +#include "../libcli/security/security.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +#define SAMR_USR_RIGHTS_WRITE_PW \ + ( READ_CONTROL_ACCESS | \ + SAMR_USER_ACCESS_CHANGE_PASSWORD | \ + SAMR_USER_ACCESS_SET_LOC_COM) +#define SAMR_USR_RIGHTS_CANT_WRITE_PW \ + ( READ_CONTROL_ACCESS | SAMR_USER_ACCESS_SET_LOC_COM ) + +#define DISP_INFO_CACHE_TIMEOUT 10 + +#define MAX_SAM_ENTRIES_W2K 0x400 /* 1024 */ +#define MAX_SAM_ENTRIES_W95 50 + +struct samr_connect_info { + uint8_t dummy; +}; + +struct samr_domain_info { + struct dom_sid sid; + struct disp_info *disp_info; +}; + +struct samr_user_info { + struct dom_sid sid; +}; + +struct samr_group_info { + struct dom_sid sid; +}; + +struct samr_alias_info { + struct dom_sid sid; +}; + +typedef struct disp_info { + struct dom_sid sid; /* identify which domain this is. */ + struct pdb_search *users; /* querydispinfo 1 and 4 */ + struct pdb_search *machines; /* querydispinfo 2 */ + struct pdb_search *groups; /* querydispinfo 3 and 5, enumgroups */ + struct pdb_search *aliases; /* enumaliases */ + + uint32_t enum_acb_mask; + struct pdb_search *enum_users; /* enumusers with a mask */ + + struct timed_event *cache_timeout_event; /* cache idle timeout + * handler. */ +} DISP_INFO; + +static const struct generic_mapping sam_generic_mapping = { + GENERIC_RIGHTS_SAM_READ, + GENERIC_RIGHTS_SAM_WRITE, + GENERIC_RIGHTS_SAM_EXECUTE, + GENERIC_RIGHTS_SAM_ALL_ACCESS}; +static const struct generic_mapping dom_generic_mapping = { + GENERIC_RIGHTS_DOMAIN_READ, + GENERIC_RIGHTS_DOMAIN_WRITE, + GENERIC_RIGHTS_DOMAIN_EXECUTE, + GENERIC_RIGHTS_DOMAIN_ALL_ACCESS}; +static const struct generic_mapping usr_generic_mapping = { + GENERIC_RIGHTS_USER_READ, + GENERIC_RIGHTS_USER_WRITE, + GENERIC_RIGHTS_USER_EXECUTE, + GENERIC_RIGHTS_USER_ALL_ACCESS}; +static const struct generic_mapping usr_nopwchange_generic_mapping = { + GENERIC_RIGHTS_USER_READ, + GENERIC_RIGHTS_USER_WRITE, + GENERIC_RIGHTS_USER_EXECUTE & ~SAMR_USER_ACCESS_CHANGE_PASSWORD, + GENERIC_RIGHTS_USER_ALL_ACCESS}; +static const struct generic_mapping grp_generic_mapping = { + GENERIC_RIGHTS_GROUP_READ, + GENERIC_RIGHTS_GROUP_WRITE, + GENERIC_RIGHTS_GROUP_EXECUTE, + GENERIC_RIGHTS_GROUP_ALL_ACCESS}; +static const struct generic_mapping ali_generic_mapping = { + GENERIC_RIGHTS_ALIAS_READ, + GENERIC_RIGHTS_ALIAS_WRITE, + GENERIC_RIGHTS_ALIAS_EXECUTE, + GENERIC_RIGHTS_ALIAS_ALL_ACCESS}; + +/******************************************************************* +*******************************************************************/ + +static NTSTATUS make_samr_object_sd( TALLOC_CTX *ctx, struct security_descriptor **psd, size_t *sd_size, + const struct generic_mapping *map, + struct dom_sid *sid, uint32 sid_access ) +{ + struct dom_sid domadmin_sid; + struct security_ace ace[5]; /* at most 5 entries */ + size_t i = 0; + + struct security_acl *psa = NULL; + + /* basic access for Everyone */ + + init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, + map->generic_execute | map->generic_read, 0); + + /* add Full Access 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ + + init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); + init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); + + /* Add Full Access for Domain Admins if we are a DC */ + + if ( IS_DC ) { + sid_compose(&domadmin_sid, get_global_sam_sid(), + DOMAIN_RID_ADMINS); + init_sec_ace(&ace[i++], &domadmin_sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); + } + + /* if we have a sid, give it some special access */ + + if ( sid ) { + init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, sid_access, 0); + } + + /* create the security descriptor */ + + if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) == NULL) + return NT_STATUS_NO_MEMORY; + + if ((*psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1, + SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, + psa, sd_size)) == NULL) + return NT_STATUS_NO_MEMORY; + + return NT_STATUS_OK; +} + +/******************************************************************* + Checks if access to an object should be granted, and returns that + level of access for further checks. + + If the user has either of needed_priv_1 or needed_priv_2 then they + get the rights in rights_mask in addition to any calulated rights. + + This handles the unusual case where we need to allow two different + privileges to obtain exactly the same rights, which occours only in + SAMR. +********************************************************************/ + +NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token, + enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2, + uint32 rights_mask, + uint32 des_access, uint32 *acc_granted, + const char *debug ) +{ + NTSTATUS status = NT_STATUS_ACCESS_DENIED; + uint32 saved_mask = 0; + + /* check privileges; certain SAM access bits should be overridden + by privileges (mostly having to do with creating/modifying/deleting + users and groups) */ + + if ((needed_priv_1 != SEC_PRIV_INVALID && security_token_has_privilege(token, needed_priv_1)) || + (needed_priv_2 != SEC_PRIV_INVALID && security_token_has_privilege(token, needed_priv_2))) { + saved_mask = (des_access & rights_mask); + des_access &= ~saved_mask; + + DEBUG(4,("access_check_object: user rights access mask [0x%x]\n", + rights_mask)); + } + + + /* check the security descriptor first */ + + status = se_access_check(psd, token, des_access, acc_granted); + if (NT_STATUS_IS_OK(status)) { + goto done; + } + + /* give root a free pass */ + + if ( geteuid() == sec_initial_uid() ) { + + DEBUG(4,("%s: ACCESS should be DENIED (requested: %#010x)\n", debug, des_access)); + DEBUGADD(4,("but overritten by euid == sec_initial_uid()\n")); + + *acc_granted = des_access; + + status = NT_STATUS_OK; + goto done; + } + + +done: + /* add in any bits saved during the privilege check (only + matters is status is ok) */ + + *acc_granted |= rights_mask; + + DEBUG(4,("%s: access %s (requested: 0x%08x, granted: 0x%08x)\n", + debug, NT_STATUS_IS_OK(status) ? "GRANTED" : "DENIED", + des_access, *acc_granted)); + + return status; +} + + +/******************************************************************* + Map any MAXIMUM_ALLOWED_ACCESS request to a valid access set. +********************************************************************/ + +void map_max_allowed_access(const struct security_token *nt_token, + const struct unix_user_token *unix_token, + uint32_t *pacc_requested) +{ + if (!((*pacc_requested) & MAXIMUM_ALLOWED_ACCESS)) { + return; + } + *pacc_requested &= ~MAXIMUM_ALLOWED_ACCESS; + + /* At least try for generic read|execute - Everyone gets that. */ + *pacc_requested = GENERIC_READ_ACCESS|GENERIC_EXECUTE_ACCESS; + + /* root gets anything. */ + if (unix_token->uid == sec_initial_uid()) { + *pacc_requested |= GENERIC_ALL_ACCESS; + return; + } + + /* Full Access for 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ + + if (security_token_has_sid(nt_token, &global_sid_Builtin_Administrators) || + security_token_has_sid(nt_token, &global_sid_Builtin_Account_Operators)) { + *pacc_requested |= GENERIC_ALL_ACCESS; + return; + } + + /* Full access for DOMAIN\Domain Admins. */ + if ( IS_DC ) { + struct dom_sid domadmin_sid; + sid_compose(&domadmin_sid, get_global_sam_sid(), + DOMAIN_RID_ADMINS); + if (security_token_has_sid(nt_token, &domadmin_sid)) { + *pacc_requested |= GENERIC_ALL_ACCESS; + return; + } + } + /* TODO ! Check privileges. */ +} + +/******************************************************************* + Fetch or create a dispinfo struct. +********************************************************************/ + +static DISP_INFO *get_samr_dispinfo_by_sid(const struct dom_sid *psid) +{ + /* + * We do a static cache for DISP_INFO's here. Explanation can be found + * in Jeremy's checkin message to r11793: + * + * Fix the SAMR cache so it works across completely insane + * client behaviour (ie.: + * open pipe/open SAMR handle/enumerate 0 - 1024 + * close SAMR handle, close pipe. + * open pipe/open SAMR handle/enumerate 1024 - 2048... + * close SAMR handle, close pipe. + * And on ad-nausium. Amazing.... probably object-oriented + * client side programming in action yet again. + * This change should *massively* improve performance when + * enumerating users from an LDAP database. + * Jeremy. + * + * "Our" and the builtin domain are the only ones where we ever + * enumerate stuff, so just cache 2 entries. + */ + + static struct disp_info *builtin_dispinfo; + static struct disp_info *domain_dispinfo; + + /* There are two cases to consider here: + 1) The SID is a domain SID and we look for an equality match, or + 2) This is an account SID and so we return the DISP_INFO* for our + domain */ + + if (psid == NULL) { + return NULL; + } + + if (sid_check_is_builtin(psid) || sid_check_is_in_builtin(psid)) { + /* + * Necessary only once, but it does not really hurt. + */ + if (builtin_dispinfo == NULL) { + builtin_dispinfo = talloc_zero(NULL, struct disp_info); + if (builtin_dispinfo == NULL) { + return NULL; + } + } + sid_copy(&builtin_dispinfo->sid, &global_sid_Builtin); + + return builtin_dispinfo; + } + + if (sid_check_is_domain(psid) || sid_check_is_in_our_domain(psid)) { + /* + * Necessary only once, but it does not really hurt. + */ + if (domain_dispinfo == NULL) { + domain_dispinfo = talloc_zero(NULL, struct disp_info); + if (domain_dispinfo == NULL) { + return NULL; + } + } + sid_copy(&domain_dispinfo->sid, get_global_sam_sid()); + + return domain_dispinfo; + } + + return NULL; +} + +/******************************************************************* + Function to free the per SID data. + ********************************************************************/ + +static void free_samr_cache(DISP_INFO *disp_info) +{ + DEBUG(10, ("free_samr_cache: deleting cache for SID %s\n", + sid_string_dbg(&disp_info->sid))); + + /* We need to become root here because the paged search might have to + * tell the LDAP server we're not interested in the rest anymore. */ + + become_root(); + + TALLOC_FREE(disp_info->users); + TALLOC_FREE(disp_info->machines); + TALLOC_FREE(disp_info->groups); + TALLOC_FREE(disp_info->aliases); + TALLOC_FREE(disp_info->enum_users); + + unbecome_root(); +} + +/******************************************************************* + Idle event handler. Throw away the disp info cache. + ********************************************************************/ + +static void disp_info_cache_idle_timeout_handler(struct event_context *ev_ctx, + struct timed_event *te, + struct timeval now, + void *private_data) +{ + DISP_INFO *disp_info = (DISP_INFO *)private_data; + + TALLOC_FREE(disp_info->cache_timeout_event); + + DEBUG(10, ("disp_info_cache_idle_timeout_handler: caching timed " + "out\n")); + free_samr_cache(disp_info); +} + +/******************************************************************* + Setup cache removal idle event handler. + ********************************************************************/ + +static void set_disp_info_cache_timeout(DISP_INFO *disp_info, time_t secs_fromnow) +{ + /* Remove any pending timeout and update. */ + + TALLOC_FREE(disp_info->cache_timeout_event); + + DEBUG(10,("set_disp_info_cache_timeout: caching enumeration for " + "SID %s for %u seconds\n", sid_string_dbg(&disp_info->sid), + (unsigned int)secs_fromnow )); + + disp_info->cache_timeout_event = event_add_timed( + server_event_context(), NULL, + timeval_current_ofs(secs_fromnow, 0), + disp_info_cache_idle_timeout_handler, (void *)disp_info); +} + +/******************************************************************* + Force flush any cache. We do this on any samr_set_xxx call. + We must also remove the timeout handler. + ********************************************************************/ + +static void force_flush_samr_cache(const struct dom_sid *sid) +{ + struct disp_info *disp_info = get_samr_dispinfo_by_sid(sid); + + if ((disp_info == NULL) || (disp_info->cache_timeout_event == NULL)) { + return; + } + + DEBUG(10,("force_flush_samr_cache: clearing idle event\n")); + TALLOC_FREE(disp_info->cache_timeout_event); + free_samr_cache(disp_info); +} + +/******************************************************************* + Ensure password info is never given out. Paranioa... JRA. + ********************************************************************/ + +static void samr_clear_sam_passwd(struct samu *sam_pass) +{ + + if (!sam_pass) + return; + + /* These now zero out the old password */ + + pdb_set_lanman_passwd(sam_pass, NULL, PDB_DEFAULT); + pdb_set_nt_passwd(sam_pass, NULL, PDB_DEFAULT); +} + +static uint32 count_sam_users(struct disp_info *info, uint32 acct_flags) +{ + struct samr_displayentry *entry; + + if (sid_check_is_builtin(&info->sid)) { + /* No users in builtin. */ + return 0; + } + + if (info->users == NULL) { + info->users = pdb_search_users(info, acct_flags); + if (info->users == NULL) { + return 0; + } + } + /* Fetch the last possible entry, thus trigger an enumeration */ + pdb_search_entries(info->users, 0xffffffff, 1, &entry); + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT); + + return info->users->num_entries; +} + +static uint32 count_sam_groups(struct disp_info *info) +{ + struct samr_displayentry *entry; + + if (sid_check_is_builtin(&info->sid)) { + /* No groups in builtin. */ + return 0; + } + + if (info->groups == NULL) { + info->groups = pdb_search_groups(info); + if (info->groups == NULL) { + return 0; + } + } + /* Fetch the last possible entry, thus trigger an enumeration */ + pdb_search_entries(info->groups, 0xffffffff, 1, &entry); + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT); + + return info->groups->num_entries; +} + +static uint32 count_sam_aliases(struct disp_info *info) +{ + struct samr_displayentry *entry; + + if (info->aliases == NULL) { + info->aliases = pdb_search_aliases(info, &info->sid); + if (info->aliases == NULL) { + return 0; + } + } + /* Fetch the last possible entry, thus trigger an enumeration */ + pdb_search_entries(info->aliases, 0xffffffff, 1, &entry); + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT); + + return info->aliases->num_entries; +} + +/******************************************************************* + _samr_Close + ********************************************************************/ + +NTSTATUS _samr_Close(struct pipes_struct *p, struct samr_Close *r) +{ + if (!close_policy_hnd(p, r->in.handle)) { + return NT_STATUS_INVALID_HANDLE; + } + + ZERO_STRUCTP(r->out.handle); + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_OpenDomain + ********************************************************************/ + +NTSTATUS _samr_OpenDomain(struct pipes_struct *p, + struct samr_OpenDomain *r) +{ + struct samr_connect_info *cinfo; + struct samr_domain_info *dinfo; + struct security_descriptor *psd = NULL; + uint32 acc_granted; + uint32 des_access = r->in.access_mask; + NTSTATUS status; + size_t sd_size; + uint32_t extra_access = SAMR_DOMAIN_ACCESS_CREATE_USER; + + /* find the connection policy handle. */ + + cinfo = policy_handle_find(p, r->in.connect_handle, 0, NULL, + struct samr_connect_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /*check if access can be granted as requested by client. */ + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + make_samr_object_sd( p->mem_ctx, &psd, &sd_size, &dom_generic_mapping, NULL, 0 ); + se_map_generic( &des_access, &dom_generic_mapping ); + + /* + * Users with SeAddUser get the ability to manipulate groups + * and aliases. + */ + if (security_token_has_privilege(p->server_info->security_token, SEC_PRIV_ADD_USERS)) { + extra_access |= (SAMR_DOMAIN_ACCESS_CREATE_GROUP | + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS | + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT | + SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS | + SAMR_DOMAIN_ACCESS_CREATE_ALIAS); + } + + /* + * Users with SeMachineAccount or SeAddUser get additional + * SAMR_DOMAIN_ACCESS_CREATE_USER access. + */ + + status = access_check_object( psd, p->server_info->security_token, + SEC_PRIV_MACHINE_ACCOUNT, SEC_PRIV_ADD_USERS, + extra_access, des_access, + &acc_granted, "_samr_OpenDomain" ); + + if ( !NT_STATUS_IS_OK(status) ) + return status; + + if (!sid_check_is_domain(r->in.sid) && + !sid_check_is_builtin(r->in.sid)) { + return NT_STATUS_NO_SUCH_DOMAIN; + } + + dinfo = policy_handle_create(p, r->out.domain_handle, acc_granted, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + dinfo->sid = *r->in.sid; + dinfo->disp_info = get_samr_dispinfo_by_sid(r->in.sid); + + DEBUG(5,("_samr_OpenDomain: %d\n", __LINE__)); + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_GetUserPwInfo + ********************************************************************/ + +NTSTATUS _samr_GetUserPwInfo(struct pipes_struct *p, + struct samr_GetUserPwInfo *r) +{ + struct samr_user_info *uinfo; + enum lsa_SidType sid_type; + uint32_t min_password_length = 0; + uint32_t password_properties = 0; + bool ret = false; + NTSTATUS status; + + DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__)); + + uinfo = policy_handle_find(p, r->in.user_handle, + SAMR_USER_ACCESS_GET_ATTRIBUTES, NULL, + struct samr_user_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sid_check_is_in_our_domain(&uinfo->sid)) { + return NT_STATUS_OBJECT_TYPE_MISMATCH; + } + + become_root(); + ret = lookup_sid(p->mem_ctx, &uinfo->sid, NULL, NULL, &sid_type); + unbecome_root(); + if (ret == false) { + return NT_STATUS_NO_SUCH_USER; + } + + switch (sid_type) { + case SID_NAME_USER: + become_root(); + pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, + &min_password_length); + pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, + &password_properties); + unbecome_root(); + + if (lp_check_password_script() && *lp_check_password_script()) { + password_properties |= DOMAIN_PASSWORD_COMPLEX; + } + + break; + default: + break; + } + + r->out.info->min_password_length = min_password_length; + r->out.info->password_properties = password_properties; + + DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__)); + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_SetSecurity + ********************************************************************/ + +NTSTATUS _samr_SetSecurity(struct pipes_struct *p, + struct samr_SetSecurity *r) +{ + struct samr_user_info *uinfo; + uint32 i; + struct security_acl *dacl; + bool ret; + struct samu *sampass=NULL; + NTSTATUS status; + + uinfo = policy_handle_find(p, r->in.handle, + SAMR_USER_ACCESS_SET_ATTRIBUTES, NULL, + struct samr_user_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!(sampass = samu_new( p->mem_ctx))) { + DEBUG(0,("No memory!\n")); + return NT_STATUS_NO_MEMORY; + } + + /* get the user record */ + become_root(); + ret = pdb_getsampwsid(sampass, &uinfo->sid); + unbecome_root(); + + if (!ret) { + DEBUG(4, ("User %s not found\n", + sid_string_dbg(&uinfo->sid))); + TALLOC_FREE(sampass); + return NT_STATUS_INVALID_HANDLE; + } + + dacl = r->in.sdbuf->sd->dacl; + for (i=0; i < dacl->num_aces; i++) { + if (dom_sid_equal(&uinfo->sid, &dacl->aces[i].trustee)) { + ret = pdb_set_pass_can_change(sampass, + (dacl->aces[i].access_mask & + SAMR_USER_ACCESS_CHANGE_PASSWORD) ? + True: False); + break; + } + } + + if (!ret) { + TALLOC_FREE(sampass); + return NT_STATUS_ACCESS_DENIED; + } + + become_root(); + status = pdb_update_sam_account(sampass); + unbecome_root(); + + TALLOC_FREE(sampass); + + return status; +} + +/******************************************************************* + build correct perms based on policies and password times for _samr_query_sec_obj +*******************************************************************/ +static bool check_change_pw_access(TALLOC_CTX *mem_ctx, struct dom_sid *user_sid) +{ + struct samu *sampass=NULL; + bool ret; + + if ( !(sampass = samu_new( mem_ctx )) ) { + DEBUG(0,("No memory!\n")); + return False; + } + + become_root(); + ret = pdb_getsampwsid(sampass, user_sid); + unbecome_root(); + + if (ret == False) { + DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid))); + TALLOC_FREE(sampass); + return False; + } + + DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) )); + + if (pdb_get_pass_can_change(sampass)) { + TALLOC_FREE(sampass); + return True; + } + TALLOC_FREE(sampass); + return False; +} + + +/******************************************************************* + _samr_QuerySecurity + ********************************************************************/ + +NTSTATUS _samr_QuerySecurity(struct pipes_struct *p, + struct samr_QuerySecurity *r) +{ + struct samr_connect_info *cinfo; + struct samr_domain_info *dinfo; + struct samr_user_info *uinfo; + struct samr_group_info *ginfo; + struct samr_alias_info *ainfo; + NTSTATUS status; + struct security_descriptor * psd = NULL; + size_t sd_size = 0; + + cinfo = policy_handle_find(p, r->in.handle, + SEC_STD_READ_CONTROL, NULL, + struct samr_connect_info, &status); + if (NT_STATUS_IS_OK(status)) { + DEBUG(5,("_samr_QuerySecurity: querying security on SAM\n")); + status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, + &sam_generic_mapping, NULL, 0); + goto done; + } + + dinfo = policy_handle_find(p, r->in.handle, + SEC_STD_READ_CONTROL, NULL, + struct samr_domain_info, &status); + if (NT_STATUS_IS_OK(status)) { + DEBUG(5,("_samr_QuerySecurity: querying security on Domain " + "with SID: %s\n", sid_string_dbg(&dinfo->sid))); + /* + * TODO: Builtin probably needs a different SD with restricted + * write access + */ + status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, + &dom_generic_mapping, NULL, 0); + goto done; + } + + uinfo = policy_handle_find(p, r->in.handle, + SEC_STD_READ_CONTROL, NULL, + struct samr_user_info, &status); + if (NT_STATUS_IS_OK(status)) { + DEBUG(10,("_samr_QuerySecurity: querying security on user " + "Object with SID: %s\n", + sid_string_dbg(&uinfo->sid))); + if (check_change_pw_access(p->mem_ctx, &uinfo->sid)) { + status = make_samr_object_sd( + p->mem_ctx, &psd, &sd_size, + &usr_generic_mapping, + &uinfo->sid, SAMR_USR_RIGHTS_WRITE_PW); + } else { + status = make_samr_object_sd( + p->mem_ctx, &psd, &sd_size, + &usr_nopwchange_generic_mapping, + &uinfo->sid, SAMR_USR_RIGHTS_CANT_WRITE_PW); + } + goto done; + } + + ginfo = policy_handle_find(p, r->in.handle, + SEC_STD_READ_CONTROL, NULL, + struct samr_group_info, &status); + if (NT_STATUS_IS_OK(status)) { + /* + * TODO: different SDs have to be generated for aliases groups + * and users. Currently all three get a default user SD + */ + DEBUG(10,("_samr_QuerySecurity: querying security on group " + "Object with SID: %s\n", + sid_string_dbg(&ginfo->sid))); + status = make_samr_object_sd( + p->mem_ctx, &psd, &sd_size, + &usr_nopwchange_generic_mapping, + &ginfo->sid, SAMR_USR_RIGHTS_CANT_WRITE_PW); + goto done; + } + + ainfo = policy_handle_find(p, r->in.handle, + SEC_STD_READ_CONTROL, NULL, + struct samr_alias_info, &status); + if (NT_STATUS_IS_OK(status)) { + /* + * TODO: different SDs have to be generated for aliases groups + * and users. Currently all three get a default user SD + */ + DEBUG(10,("_samr_QuerySecurity: querying security on alias " + "Object with SID: %s\n", + sid_string_dbg(&ainfo->sid))); + status = make_samr_object_sd( + p->mem_ctx, &psd, &sd_size, + &usr_nopwchange_generic_mapping, + &ainfo->sid, SAMR_USR_RIGHTS_CANT_WRITE_PW); + goto done; + } + + return NT_STATUS_OBJECT_TYPE_MISMATCH; +done: + if ((*r->out.sdbuf = make_sec_desc_buf(p->mem_ctx, sd_size, psd)) == NULL) + return NT_STATUS_NO_MEMORY; + + return status; +} + +/******************************************************************* +makes a SAM_ENTRY / UNISTR2* structure from a user list. +********************************************************************/ + +static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, + struct samr_SamEntry **sam_pp, + uint32_t num_entries, + uint32_t start_idx, + struct samr_displayentry *entries) +{ + uint32_t i; + struct samr_SamEntry *sam; + + *sam_pp = NULL; + + if (num_entries == 0) { + return NT_STATUS_OK; + } + + sam = TALLOC_ZERO_ARRAY(ctx, struct samr_SamEntry, num_entries); + if (sam == NULL) { + DEBUG(0, ("make_user_sam_entry_list: TALLOC_ZERO failed!\n")); + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_entries; i++) { +#if 0 + /* + * usrmgr expects a non-NULL terminated string with + * trust relationships + */ + if (entries[i].acct_flags & ACB_DOMTRUST) { + init_unistr2(&uni_temp_name, entries[i].account_name, + UNI_FLAGS_NONE); + } else { + init_unistr2(&uni_temp_name, entries[i].account_name, + UNI_STR_TERMINATE); + } +#endif + init_lsa_String(&sam[i].name, entries[i].account_name); + sam[i].idx = entries[i].rid; + } + + *sam_pp = sam; + + return NT_STATUS_OK; +} + +#define MAX_SAM_ENTRIES MAX_SAM_ENTRIES_W2K + +/******************************************************************* + _samr_EnumDomainUsers + ********************************************************************/ + +NTSTATUS _samr_EnumDomainUsers(struct pipes_struct *p, + struct samr_EnumDomainUsers *r) +{ + NTSTATUS status; + struct samr_domain_info *dinfo; + int num_account; + uint32 enum_context = *r->in.resume_handle; + enum remote_arch_types ra_type = get_remote_arch(); + int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K; + uint32 max_entries = max_sam_entries; + struct samr_displayentry *entries = NULL; + struct samr_SamArray *samr_array = NULL; + struct samr_SamEntry *samr_entries = NULL; + + DEBUG(5,("_samr_EnumDomainUsers: %d\n", __LINE__)); + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); + if (!samr_array) { + return NT_STATUS_NO_MEMORY; + } + *r->out.sam = samr_array; + + if (sid_check_is_builtin(&dinfo->sid)) { + /* No users in builtin. */ + *r->out.resume_handle = *r->in.resume_handle; + DEBUG(5,("_samr_EnumDomainUsers: No users in BUILTIN\n")); + return status; + } + + become_root(); + + /* AS ROOT !!!! */ + + if ((dinfo->disp_info->enum_users != NULL) && + (dinfo->disp_info->enum_acb_mask != r->in.acct_flags)) { + TALLOC_FREE(dinfo->disp_info->enum_users); + } + + if (dinfo->disp_info->enum_users == NULL) { + dinfo->disp_info->enum_users = pdb_search_users( + dinfo->disp_info, r->in.acct_flags); + dinfo->disp_info->enum_acb_mask = r->in.acct_flags; + } + + if (dinfo->disp_info->enum_users == NULL) { + /* END AS ROOT !!!! */ + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + + num_account = pdb_search_entries(dinfo->disp_info->enum_users, + enum_context, max_entries, + &entries); + + /* END AS ROOT !!!! */ + + unbecome_root(); + + if (num_account == 0) { + DEBUG(5, ("_samr_EnumDomainUsers: enumeration handle over " + "total entries\n")); + *r->out.resume_handle = *r->in.resume_handle; + return NT_STATUS_OK; + } + + status = make_user_sam_entry_list(p->mem_ctx, &samr_entries, + num_account, enum_context, + entries); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (max_entries <= num_account) { + status = STATUS_MORE_ENTRIES; + } else { + status = NT_STATUS_OK; + } + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); + + DEBUG(5, ("_samr_EnumDomainUsers: %d\n", __LINE__)); + + samr_array->count = num_account; + samr_array->entries = samr_entries; + + *r->out.resume_handle = *r->in.resume_handle + num_account; + *r->out.num_entries = num_account; + + DEBUG(5,("_samr_EnumDomainUsers: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* +makes a SAM_ENTRY / UNISTR2* structure from a group list. +********************************************************************/ + +static void make_group_sam_entry_list(TALLOC_CTX *ctx, + struct samr_SamEntry **sam_pp, + uint32_t num_sam_entries, + struct samr_displayentry *entries) +{ + struct samr_SamEntry *sam; + uint32_t i; + + *sam_pp = NULL; + + if (num_sam_entries == 0) { + return; + } + + sam = TALLOC_ZERO_ARRAY(ctx, struct samr_SamEntry, num_sam_entries); + if (sam == NULL) { + return; + } + + for (i = 0; i < num_sam_entries; i++) { + /* + * JRA. I think this should include the null. TNG does not. + */ + init_lsa_String(&sam[i].name, entries[i].account_name); + sam[i].idx = entries[i].rid; + } + + *sam_pp = sam; +} + +/******************************************************************* + _samr_EnumDomainGroups + ********************************************************************/ + +NTSTATUS _samr_EnumDomainGroups(struct pipes_struct *p, + struct samr_EnumDomainGroups *r) +{ + NTSTATUS status; + struct samr_domain_info *dinfo; + struct samr_displayentry *groups; + uint32 num_groups; + struct samr_SamArray *samr_array = NULL; + struct samr_SamEntry *samr_entries = NULL; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(5,("_samr_EnumDomainGroups: %d\n", __LINE__)); + + samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); + if (!samr_array) { + return NT_STATUS_NO_MEMORY; + } + *r->out.sam = samr_array; + + if (sid_check_is_builtin(&dinfo->sid)) { + /* No groups in builtin. */ + *r->out.resume_handle = *r->in.resume_handle; + DEBUG(5,("_samr_EnumDomainGroups: No groups in BUILTIN\n")); + return status; + } + + /* the domain group array is being allocated in the function below */ + + become_root(); + + if (dinfo->disp_info->groups == NULL) { + dinfo->disp_info->groups = pdb_search_groups(dinfo->disp_info); + + if (dinfo->disp_info->groups == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + } + + num_groups = pdb_search_entries(dinfo->disp_info->groups, + *r->in.resume_handle, + MAX_SAM_ENTRIES, &groups); + unbecome_root(); + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); + + make_group_sam_entry_list(p->mem_ctx, &samr_entries, + num_groups, groups); + + if (MAX_SAM_ENTRIES <= num_groups) { + status = STATUS_MORE_ENTRIES; + } else { + status = NT_STATUS_OK; + } + + samr_array->count = num_groups; + samr_array->entries = samr_entries; + + *r->out.num_entries = num_groups; + *r->out.resume_handle = num_groups + *r->in.resume_handle; + + DEBUG(5,("_samr_EnumDomainGroups: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* + _samr_EnumDomainAliases + ********************************************************************/ + +NTSTATUS _samr_EnumDomainAliases(struct pipes_struct *p, + struct samr_EnumDomainAliases *r) +{ + NTSTATUS status; + struct samr_domain_info *dinfo; + struct samr_displayentry *aliases; + uint32 num_aliases = 0; + struct samr_SamArray *samr_array = NULL; + struct samr_SamEntry *samr_entries = NULL; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(5,("_samr_EnumDomainAliases: sid %s\n", + sid_string_dbg(&dinfo->sid))); + + samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); + if (!samr_array) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + + if (dinfo->disp_info->aliases == NULL) { + dinfo->disp_info->aliases = pdb_search_aliases( + dinfo->disp_info, &dinfo->sid); + if (dinfo->disp_info->aliases == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + } + + num_aliases = pdb_search_entries(dinfo->disp_info->aliases, + *r->in.resume_handle, + MAX_SAM_ENTRIES, &aliases); + unbecome_root(); + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); + + make_group_sam_entry_list(p->mem_ctx, &samr_entries, + num_aliases, aliases); + + DEBUG(5,("_samr_EnumDomainAliases: %d\n", __LINE__)); + + if (MAX_SAM_ENTRIES <= num_aliases) { + status = STATUS_MORE_ENTRIES; + } else { + status = NT_STATUS_OK; + } + + samr_array->count = num_aliases; + samr_array->entries = samr_entries; + + *r->out.sam = samr_array; + *r->out.num_entries = num_aliases; + *r->out.resume_handle = num_aliases + *r->in.resume_handle; + + return status; +} + +/******************************************************************* + inits a samr_DispInfoGeneral structure. +********************************************************************/ + +static NTSTATUS init_samr_dispinfo_1(TALLOC_CTX *ctx, + struct samr_DispInfoGeneral *r, + uint32_t num_entries, + uint32_t start_idx, + struct samr_displayentry *entries) +{ + uint32 i; + + DEBUG(10, ("init_samr_dispinfo_1: num_entries: %d\n", num_entries)); + + if (num_entries == 0) { + return NT_STATUS_OK; + } + + r->count = num_entries; + + r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryGeneral, num_entries); + if (!r->entries) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_entries ; i++) { + + init_lsa_String(&r->entries[i].account_name, + entries[i].account_name); + + init_lsa_String(&r->entries[i].description, + entries[i].description); + + init_lsa_String(&r->entries[i].full_name, + entries[i].fullname); + + r->entries[i].rid = entries[i].rid; + r->entries[i].acct_flags = entries[i].acct_flags; + r->entries[i].idx = start_idx+i+1; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + inits a samr_DispInfoFull structure. +********************************************************************/ + +static NTSTATUS init_samr_dispinfo_2(TALLOC_CTX *ctx, + struct samr_DispInfoFull *r, + uint32_t num_entries, + uint32_t start_idx, + struct samr_displayentry *entries) +{ + uint32_t i; + + DEBUG(10, ("init_samr_dispinfo_2: num_entries: %d\n", num_entries)); + + if (num_entries == 0) { + return NT_STATUS_OK; + } + + r->count = num_entries; + + r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryFull, num_entries); + if (!r->entries) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_entries ; i++) { + + init_lsa_String(&r->entries[i].account_name, + entries[i].account_name); + + init_lsa_String(&r->entries[i].description, + entries[i].description); + + r->entries[i].rid = entries[i].rid; + r->entries[i].acct_flags = entries[i].acct_flags; + r->entries[i].idx = start_idx+i+1; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + inits a samr_DispInfoFullGroups structure. +********************************************************************/ + +static NTSTATUS init_samr_dispinfo_3(TALLOC_CTX *ctx, + struct samr_DispInfoFullGroups *r, + uint32_t num_entries, + uint32_t start_idx, + struct samr_displayentry *entries) +{ + uint32_t i; + + DEBUG(5, ("init_samr_dispinfo_3: num_entries: %d\n", num_entries)); + + if (num_entries == 0) { + return NT_STATUS_OK; + } + + r->count = num_entries; + + r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryFullGroup, num_entries); + if (!r->entries) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_entries ; i++) { + + init_lsa_String(&r->entries[i].account_name, + entries[i].account_name); + + init_lsa_String(&r->entries[i].description, + entries[i].description); + + r->entries[i].rid = entries[i].rid; + r->entries[i].acct_flags = entries[i].acct_flags; + r->entries[i].idx = start_idx+i+1; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + inits a samr_DispInfoAscii structure. +********************************************************************/ + +static NTSTATUS init_samr_dispinfo_4(TALLOC_CTX *ctx, + struct samr_DispInfoAscii *r, + uint32_t num_entries, + uint32_t start_idx, + struct samr_displayentry *entries) +{ + uint32_t i; + + DEBUG(5, ("init_samr_dispinfo_4: num_entries: %d\n", num_entries)); + + if (num_entries == 0) { + return NT_STATUS_OK; + } + + r->count = num_entries; + + r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryAscii, num_entries); + if (!r->entries) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_entries ; i++) { + + init_lsa_AsciiStringLarge(&r->entries[i].account_name, + entries[i].account_name); + + r->entries[i].idx = start_idx+i+1; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + inits a samr_DispInfoAscii structure. +********************************************************************/ + +static NTSTATUS init_samr_dispinfo_5(TALLOC_CTX *ctx, + struct samr_DispInfoAscii *r, + uint32_t num_entries, + uint32_t start_idx, + struct samr_displayentry *entries) +{ + uint32_t i; + + DEBUG(5, ("init_samr_dispinfo_5: num_entries: %d\n", num_entries)); + + if (num_entries == 0) { + return NT_STATUS_OK; + } + + r->count = num_entries; + + r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryAscii, num_entries); + if (!r->entries) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < num_entries ; i++) { + + init_lsa_AsciiStringLarge(&r->entries[i].account_name, + entries[i].account_name); + + r->entries[i].idx = start_idx+i+1; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_QueryDisplayInfo + ********************************************************************/ + +NTSTATUS _samr_QueryDisplayInfo(struct pipes_struct *p, + struct samr_QueryDisplayInfo *r) +{ + NTSTATUS status; + struct samr_domain_info *dinfo; + uint32 struct_size=0x20; /* W2K always reply that, client doesn't care */ + + uint32 max_entries = r->in.max_entries; + + union samr_DispInfo *disp_info = r->out.info; + + uint32 temp_size=0; + NTSTATUS disp_ret = NT_STATUS_UNSUCCESSFUL; + uint32 num_account = 0; + enum remote_arch_types ra_type = get_remote_arch(); + int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K; + struct samr_displayentry *entries = NULL; + + DEBUG(5,("_samr_QueryDisplayInfo: %d\n", __LINE__)); + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (sid_check_is_builtin(&dinfo->sid)) { + DEBUG(5,("_samr_QueryDisplayInfo: no users in BUILTIN\n")); + return NT_STATUS_OK; + } + + /* + * calculate how many entries we will return. + * based on + * - the number of entries the client asked + * - our limit on that + * - the starting point (enumeration context) + * - the buffer size the client will accept + */ + + /* + * We are a lot more like W2K. Instead of reading the SAM + * each time to find the records we need to send back, + * we read it once and link that copy to the sam handle. + * For large user list (over the MAX_SAM_ENTRIES) + * it's a definitive win. + * second point to notice: between enumerations + * our sam is now the same as it's a snapshoot. + * third point: got rid of the static SAM_USER_21 struct + * no more intermediate. + * con: it uses much more memory, as a full copy is stored + * in memory. + * + * If you want to change it, think twice and think + * of the second point , that's really important. + * + * JFM, 12/20/2001 + */ + + if ((r->in.level < 1) || (r->in.level > 5)) { + DEBUG(0,("_samr_QueryDisplayInfo: Unknown info level (%u)\n", + (unsigned int)r->in.level )); + return NT_STATUS_INVALID_INFO_CLASS; + } + + /* first limit the number of entries we will return */ + if (r->in.max_entries > max_sam_entries) { + DEBUG(5, ("_samr_QueryDisplayInfo: client requested %d " + "entries, limiting to %d\n", r->in.max_entries, + max_sam_entries)); + max_entries = max_sam_entries; + } + + /* calculate the size and limit on the number of entries we will + * return */ + + temp_size=max_entries*struct_size; + + if (temp_size > r->in.buf_size) { + max_entries = MIN((r->in.buf_size / struct_size),max_entries); + DEBUG(5, ("_samr_QueryDisplayInfo: buffer size limits to " + "only %d entries\n", max_entries)); + } + + become_root(); + + /* THe following done as ROOT. Don't return without unbecome_root(). */ + + switch (r->in.level) { + case 1: + case 4: + if (dinfo->disp_info->users == NULL) { + dinfo->disp_info->users = pdb_search_users( + dinfo->disp_info, ACB_NORMAL); + if (dinfo->disp_info->users == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_QueryDisplayInfo: starting user enumeration at index %u\n", + (unsigned int)r->in.start_idx)); + } else { + DEBUG(10,("_samr_QueryDisplayInfo: using cached user enumeration at index %u\n", + (unsigned int)r->in.start_idx)); + } + + num_account = pdb_search_entries(dinfo->disp_info->users, + r->in.start_idx, max_entries, + &entries); + break; + case 2: + if (dinfo->disp_info->machines == NULL) { + dinfo->disp_info->machines = pdb_search_users( + dinfo->disp_info, ACB_WSTRUST|ACB_SVRTRUST); + if (dinfo->disp_info->machines == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_QueryDisplayInfo: starting machine enumeration at index %u\n", + (unsigned int)r->in.start_idx)); + } else { + DEBUG(10,("_samr_QueryDisplayInfo: using cached machine enumeration at index %u\n", + (unsigned int)r->in.start_idx)); + } + + num_account = pdb_search_entries(dinfo->disp_info->machines, + r->in.start_idx, max_entries, + &entries); + break; + case 3: + case 5: + if (dinfo->disp_info->groups == NULL) { + dinfo->disp_info->groups = pdb_search_groups( + dinfo->disp_info); + if (dinfo->disp_info->groups == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_QueryDisplayInfo: starting group enumeration at index %u\n", + (unsigned int)r->in.start_idx)); + } else { + DEBUG(10,("_samr_QueryDisplayInfo: using cached group enumeration at index %u\n", + (unsigned int)r->in.start_idx)); + } + + num_account = pdb_search_entries(dinfo->disp_info->groups, + r->in.start_idx, max_entries, + &entries); + break; + default: + unbecome_root(); + smb_panic("info class changed"); + break; + } + unbecome_root(); + + + /* Now create reply structure */ + switch (r->in.level) { + case 1: + disp_ret = init_samr_dispinfo_1(p->mem_ctx, &disp_info->info1, + num_account, r->in.start_idx, + entries); + break; + case 2: + disp_ret = init_samr_dispinfo_2(p->mem_ctx, &disp_info->info2, + num_account, r->in.start_idx, + entries); + break; + case 3: + disp_ret = init_samr_dispinfo_3(p->mem_ctx, &disp_info->info3, + num_account, r->in.start_idx, + entries); + break; + case 4: + disp_ret = init_samr_dispinfo_4(p->mem_ctx, &disp_info->info4, + num_account, r->in.start_idx, + entries); + break; + case 5: + disp_ret = init_samr_dispinfo_5(p->mem_ctx, &disp_info->info5, + num_account, r->in.start_idx, + entries); + break; + default: + smb_panic("info class changed"); + break; + } + + if (!NT_STATUS_IS_OK(disp_ret)) + return disp_ret; + + if (max_entries <= num_account) { + status = STATUS_MORE_ENTRIES; + } else { + status = NT_STATUS_OK; + } + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); + + DEBUG(5, ("_samr_QueryDisplayInfo: %d\n", __LINE__)); + + *r->out.total_size = num_account * struct_size; + *r->out.returned_size = num_account ? temp_size : 0; + + return status; +} + +/**************************************************************** + _samr_QueryDisplayInfo2 +****************************************************************/ + +NTSTATUS _samr_QueryDisplayInfo2(struct pipes_struct *p, + struct samr_QueryDisplayInfo2 *r) +{ + struct samr_QueryDisplayInfo q; + + q.in.domain_handle = r->in.domain_handle; + q.in.level = r->in.level; + q.in.start_idx = r->in.start_idx; + q.in.max_entries = r->in.max_entries; + q.in.buf_size = r->in.buf_size; + + q.out.total_size = r->out.total_size; + q.out.returned_size = r->out.returned_size; + q.out.info = r->out.info; + + return _samr_QueryDisplayInfo(p, &q); +} + +/**************************************************************** + _samr_QueryDisplayInfo3 +****************************************************************/ + +NTSTATUS _samr_QueryDisplayInfo3(struct pipes_struct *p, + struct samr_QueryDisplayInfo3 *r) +{ + struct samr_QueryDisplayInfo q; + + q.in.domain_handle = r->in.domain_handle; + q.in.level = r->in.level; + q.in.start_idx = r->in.start_idx; + q.in.max_entries = r->in.max_entries; + q.in.buf_size = r->in.buf_size; + + q.out.total_size = r->out.total_size; + q.out.returned_size = r->out.returned_size; + q.out.info = r->out.info; + + return _samr_QueryDisplayInfo(p, &q); +} + +/******************************************************************* + _samr_QueryAliasInfo + ********************************************************************/ + +NTSTATUS _samr_QueryAliasInfo(struct pipes_struct *p, + struct samr_QueryAliasInfo *r) +{ + struct samr_alias_info *ainfo; + struct acct_info info; + NTSTATUS status; + union samr_AliasInfo *alias_info = NULL; + const char *alias_name = NULL; + const char *alias_description = NULL; + + DEBUG(5,("_samr_QueryAliasInfo: %d\n", __LINE__)); + + ainfo = policy_handle_find(p, r->in.alias_handle, + SAMR_ALIAS_ACCESS_LOOKUP_INFO, NULL, + struct samr_alias_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + alias_info = TALLOC_ZERO_P(p->mem_ctx, union samr_AliasInfo); + if (!alias_info) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + status = pdb_get_aliasinfo(&ainfo->sid, &info); + unbecome_root(); + + if ( !NT_STATUS_IS_OK(status)) + return status; + + /* FIXME: info contains fstrings */ + alias_name = talloc_strdup(r, info.acct_name); + alias_description = talloc_strdup(r, info.acct_desc); + + switch (r->in.level) { + case ALIASINFOALL: + alias_info->all.name.string = alias_name; + alias_info->all.num_members = 1; /* ??? */ + alias_info->all.description.string = alias_description; + break; + case ALIASINFONAME: + alias_info->name.string = alias_name; + break; + case ALIASINFODESCRIPTION: + alias_info->description.string = alias_description; + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + *r->out.info = alias_info; + + DEBUG(5,("_samr_QueryAliasInfo: %d\n", __LINE__)); + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_LookupNames + ********************************************************************/ + +NTSTATUS _samr_LookupNames(struct pipes_struct *p, + struct samr_LookupNames *r) +{ + struct samr_domain_info *dinfo; + NTSTATUS status; + uint32 *rid; + enum lsa_SidType *type; + int i; + int num_rids = r->in.num_names; + struct samr_Ids rids, types; + uint32_t num_mapped = 0; + + DEBUG(5,("_samr_LookupNames: %d\n", __LINE__)); + + dinfo = policy_handle_find(p, r->in.domain_handle, + 0 /* Don't know the acc_bits yet */, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (num_rids > MAX_SAM_ENTRIES) { + num_rids = MAX_SAM_ENTRIES; + DEBUG(5,("_samr_LookupNames: truncating entries to %d\n", num_rids)); + } + + rid = talloc_array(p->mem_ctx, uint32, num_rids); + NT_STATUS_HAVE_NO_MEMORY(rid); + + type = talloc_array(p->mem_ctx, enum lsa_SidType, num_rids); + NT_STATUS_HAVE_NO_MEMORY(type); + + DEBUG(5,("_samr_LookupNames: looking name on SID %s\n", + sid_string_dbg(&dinfo->sid))); + + for (i = 0; i < num_rids; i++) { + + status = NT_STATUS_NONE_MAPPED; + type[i] = SID_NAME_UNKNOWN; + + rid[i] = 0xffffffff; + + if (sid_check_is_builtin(&dinfo->sid)) { + if (lookup_builtin_name(r->in.names[i].string, + &rid[i])) + { + type[i] = SID_NAME_ALIAS; + } + } else { + lookup_global_sam_name(r->in.names[i].string, 0, + &rid[i], &type[i]); + } + + if (type[i] != SID_NAME_UNKNOWN) { + num_mapped++; + } + } + + if (num_mapped == num_rids) { + status = NT_STATUS_OK; + } else if (num_mapped == 0) { + status = NT_STATUS_NONE_MAPPED; + } else { + status = STATUS_SOME_UNMAPPED; + } + + rids.count = num_rids; + rids.ids = rid; + + types.count = num_rids; + types.ids = talloc_array(p->mem_ctx, uint32_t, num_rids); + NT_STATUS_HAVE_NO_MEMORY(type); + for (i = 0; i < num_rids; i++) { + types.ids[i] = (type[i] & 0xffffffff); + } + + *r->out.rids = rids; + *r->out.types = types; + + DEBUG(5,("_samr_LookupNames: %d\n", __LINE__)); + + return status; +} + +/**************************************************************** + _samr_ChangePasswordUser +****************************************************************/ + +NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p, + struct samr_ChangePasswordUser *r) +{ + NTSTATUS status; + bool ret = false; + struct samr_user_info *uinfo; + struct samu *pwd; + struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash; + struct samr_Password lm_pwd, nt_pwd; + + uinfo = policy_handle_find(p, r->in.user_handle, + SAMR_USER_ACCESS_SET_PASSWORD, NULL, + struct samr_user_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(5,("_samr_ChangePasswordUser: sid:%s\n", + sid_string_dbg(&uinfo->sid))); + + if (!(pwd = samu_new(NULL))) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + ret = pdb_getsampwsid(pwd, &uinfo->sid); + unbecome_root(); + + if (!ret) { + TALLOC_FREE(pwd); + return NT_STATUS_WRONG_PASSWORD; + } + + { + const uint8_t *lm_pass, *nt_pass; + + lm_pass = pdb_get_lanman_passwd(pwd); + nt_pass = pdb_get_nt_passwd(pwd); + + if (!lm_pass || !nt_pass) { + status = NT_STATUS_WRONG_PASSWORD; + goto out; + } + + memcpy(&lm_pwd.hash, lm_pass, sizeof(lm_pwd.hash)); + memcpy(&nt_pwd.hash, nt_pass, sizeof(nt_pwd.hash)); + } + + /* basic sanity checking on parameters. Do this before any database ops */ + if (!r->in.lm_present || !r->in.nt_present || + !r->in.old_lm_crypted || !r->in.new_lm_crypted || + !r->in.old_nt_crypted || !r->in.new_nt_crypted) { + /* we should really handle a change with lm not + present */ + status = NT_STATUS_INVALID_PARAMETER_MIX; + goto out; + } + + /* decrypt and check the new lm hash */ + D_P16(lm_pwd.hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash); + D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash); + if (memcmp(checkHash.hash, lm_pwd.hash, 16) != 0) { + status = NT_STATUS_WRONG_PASSWORD; + goto out; + } + + /* decrypt and check the new nt hash */ + D_P16(nt_pwd.hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash); + D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash); + if (memcmp(checkHash.hash, nt_pwd.hash, 16) != 0) { + status = NT_STATUS_WRONG_PASSWORD; + goto out; + } + + /* The NT Cross is not required by Win2k3 R2, but if present + check the nt cross hash */ + if (r->in.cross1_present && r->in.nt_cross) { + D_P16(lm_pwd.hash, r->in.nt_cross->hash, checkHash.hash); + if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { + status = NT_STATUS_WRONG_PASSWORD; + goto out; + } + } + + /* The LM Cross is not required by Win2k3 R2, but if present + check the lm cross hash */ + if (r->in.cross2_present && r->in.lm_cross) { + D_P16(nt_pwd.hash, r->in.lm_cross->hash, checkHash.hash); + if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { + status = NT_STATUS_WRONG_PASSWORD; + goto out; + } + } + + if (!pdb_set_nt_passwd(pwd, new_ntPwdHash.hash, PDB_CHANGED) || + !pdb_set_lanman_passwd(pwd, new_lmPwdHash.hash, PDB_CHANGED)) { + status = NT_STATUS_ACCESS_DENIED; + goto out; + } + + status = pdb_update_sam_account(pwd); + out: + TALLOC_FREE(pwd); + + return status; +} + +/******************************************************************* + _samr_ChangePasswordUser2 + ********************************************************************/ + +NTSTATUS _samr_ChangePasswordUser2(struct pipes_struct *p, + struct samr_ChangePasswordUser2 *r) +{ + NTSTATUS status; + char *user_name = NULL; + fstring wks; + + DEBUG(5,("_samr_ChangePasswordUser2: %d\n", __LINE__)); + + if (!r->in.account->string) { + return NT_STATUS_INVALID_PARAMETER; + } + fstrcpy(wks, r->in.server->string); + + DEBUG(5,("_samr_ChangePasswordUser2: user: %s wks: %s\n", user_name, wks)); + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(talloc_tos(), r->in.account->string, &user_name); + if (!user_name) { + return NT_STATUS_NO_MEMORY; + } + + /* + * UNIX username case mangling not required, pass_oem_change + * is case insensitive. + */ + + status = pass_oem_change(user_name, + p->client_id->name, + r->in.lm_password->data, + r->in.lm_verifier->hash, + r->in.nt_password->data, + r->in.nt_verifier->hash, + NULL); + + DEBUG(5,("_samr_ChangePasswordUser2: %d\n", __LINE__)); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { + return NT_STATUS_WRONG_PASSWORD; + } + + return status; +} + +/**************************************************************** + _samr_OemChangePasswordUser2 +****************************************************************/ + +NTSTATUS _samr_OemChangePasswordUser2(struct pipes_struct *p, + struct samr_OemChangePasswordUser2 *r) +{ + NTSTATUS status; + char *user_name = NULL; + const char *wks = NULL; + + DEBUG(5,("_samr_OemChangePasswordUser2: %d\n", __LINE__)); + + if (!r->in.account->string) { + return NT_STATUS_INVALID_PARAMETER; + } + if (r->in.server && r->in.server->string) { + wks = r->in.server->string; + } + + DEBUG(5,("_samr_OemChangePasswordUser2: user: %s wks: %s\n", user_name, wks)); + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(talloc_tos(), r->in.account->string, &user_name); + if (!user_name) { + return NT_STATUS_NO_MEMORY; + } + + /* + * UNIX username case mangling not required, pass_oem_change + * is case insensitive. + */ + + if (!r->in.hash || !r->in.password) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = pass_oem_change(user_name, + p->client_id->name, + r->in.password->data, + r->in.hash->hash, + 0, + 0, + NULL); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { + return NT_STATUS_WRONG_PASSWORD; + } + + DEBUG(5,("_samr_OemChangePasswordUser2: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* + _samr_ChangePasswordUser3 + ********************************************************************/ + +NTSTATUS _samr_ChangePasswordUser3(struct pipes_struct *p, + struct samr_ChangePasswordUser3 *r) +{ + NTSTATUS status; + char *user_name = NULL; + const char *wks = NULL; + enum samPwdChangeReason reject_reason; + struct samr_DomInfo1 *dominfo = NULL; + struct userPwdChangeFailureInformation *reject = NULL; + uint32_t tmp; + + DEBUG(5,("_samr_ChangePasswordUser3: %d\n", __LINE__)); + + if (!r->in.account->string) { + return NT_STATUS_INVALID_PARAMETER; + } + if (r->in.server && r->in.server->string) { + wks = r->in.server->string; + } + + DEBUG(5,("_samr_ChangePasswordUser3: user: %s wks: %s\n", user_name, wks)); + + /* + * Pass the user through the NT -> unix user mapping + * function. + */ + + (void)map_username(talloc_tos(), r->in.account->string, &user_name); + if (!user_name) { + return NT_STATUS_NO_MEMORY; + } + + /* + * UNIX username case mangling not required, pass_oem_change + * is case insensitive. + */ + + status = pass_oem_change(user_name, + p->client_id->name, + r->in.lm_password->data, + r->in.lm_verifier->hash, + r->in.nt_password->data, + r->in.nt_verifier->hash, + &reject_reason); + if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { + return NT_STATUS_WRONG_PASSWORD; + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) || + NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_RESTRICTION)) { + + time_t u_expire, u_min_age; + uint32 account_policy_temp; + + dominfo = TALLOC_ZERO_P(p->mem_ctx, struct samr_DomInfo1); + if (!dominfo) { + return NT_STATUS_NO_MEMORY; + } + + reject = TALLOC_ZERO_P(p->mem_ctx, + struct userPwdChangeFailureInformation); + if (!reject) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + + /* AS ROOT !!! */ + + pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &tmp); + dominfo->min_password_length = tmp; + + pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &tmp); + dominfo->password_history_length = tmp; + + pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, + &dominfo->password_properties); + + pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &account_policy_temp); + u_expire = account_policy_temp; + + pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, &account_policy_temp); + u_min_age = account_policy_temp; + + /* !AS ROOT */ + + unbecome_root(); + + unix_to_nt_time_abs((NTTIME *)&dominfo->max_password_age, u_expire); + unix_to_nt_time_abs((NTTIME *)&dominfo->min_password_age, u_min_age); + + if (lp_check_password_script() && *lp_check_password_script()) { + dominfo->password_properties |= DOMAIN_PASSWORD_COMPLEX; + } + + reject->extendedFailureReason = reject_reason; + + *r->out.dominfo = dominfo; + *r->out.reject = reject; + } + + DEBUG(5,("_samr_ChangePasswordUser3: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* +makes a SAMR_R_LOOKUP_RIDS structure. +********************************************************************/ + +static bool make_samr_lookup_rids(TALLOC_CTX *ctx, uint32 num_names, + const char **names, + struct lsa_String **lsa_name_array_p) +{ + struct lsa_String *lsa_name_array = NULL; + uint32_t i; + + *lsa_name_array_p = NULL; + + if (num_names != 0) { + lsa_name_array = TALLOC_ZERO_ARRAY(ctx, struct lsa_String, num_names); + if (!lsa_name_array) { + return false; + } + } + + for (i = 0; i < num_names; i++) { + DEBUG(10, ("names[%d]:%s\n", i, names[i] && *names[i] ? names[i] : "")); + init_lsa_String(&lsa_name_array[i], names[i]); + } + + *lsa_name_array_p = lsa_name_array; + + return true; +} + +/******************************************************************* + _samr_LookupRids + ********************************************************************/ + +NTSTATUS _samr_LookupRids(struct pipes_struct *p, + struct samr_LookupRids *r) +{ + struct samr_domain_info *dinfo; + NTSTATUS status; + const char **names; + enum lsa_SidType *attrs = NULL; + uint32 *wire_attrs = NULL; + int num_rids = (int)r->in.num_rids; + int i; + struct lsa_Strings names_array; + struct samr_Ids types_array; + struct lsa_String *lsa_names = NULL; + + DEBUG(5,("_samr_LookupRids: %d\n", __LINE__)); + + dinfo = policy_handle_find(p, r->in.domain_handle, + 0 /* Don't know the acc_bits yet */, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (num_rids > 1000) { + DEBUG(0, ("Got asked for %d rids (more than 1000) -- according " + "to samba4 idl this is not possible\n", num_rids)); + return NT_STATUS_UNSUCCESSFUL; + } + + if (num_rids) { + names = TALLOC_ZERO_ARRAY(p->mem_ctx, const char *, num_rids); + attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, enum lsa_SidType, num_rids); + wire_attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_rids); + + if ((names == NULL) || (attrs == NULL) || (wire_attrs==NULL)) + return NT_STATUS_NO_MEMORY; + } else { + names = NULL; + attrs = NULL; + wire_attrs = NULL; + } + + become_root(); /* lookup_sid can require root privs */ + status = pdb_lookup_rids(&dinfo->sid, num_rids, r->in.rids, + names, attrs); + unbecome_root(); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) && (num_rids == 0)) { + status = NT_STATUS_OK; + } + + if (!make_samr_lookup_rids(p->mem_ctx, num_rids, names, + &lsa_names)) { + return NT_STATUS_NO_MEMORY; + } + + /* Convert from enum lsa_SidType to uint32 for wire format. */ + for (i = 0; i < num_rids; i++) { + wire_attrs[i] = (uint32)attrs[i]; + } + + names_array.count = num_rids; + names_array.names = lsa_names; + + types_array.count = num_rids; + types_array.ids = wire_attrs; + + *r->out.names = names_array; + *r->out.types = types_array; + + DEBUG(5,("_samr_LookupRids: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* + _samr_OpenUser +********************************************************************/ + +NTSTATUS _samr_OpenUser(struct pipes_struct *p, + struct samr_OpenUser *r) +{ + struct samu *sampass=NULL; + struct dom_sid sid; + struct samr_domain_info *dinfo; + struct samr_user_info *uinfo; + struct security_descriptor *psd = NULL; + uint32 acc_granted; + uint32 des_access = r->in.access_mask; + uint32_t extra_access = 0; + size_t sd_size; + bool ret; + NTSTATUS nt_status; + + /* These two privileges, if != SEC_PRIV_INVALID, indicate + * privileges that the user must have to complete this + * operation in defience of the fixed ACL */ + enum sec_privilege needed_priv_1, needed_priv_2; + NTSTATUS status; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if ( !(sampass = samu_new( p->mem_ctx )) ) { + return NT_STATUS_NO_MEMORY; + } + + /* append the user's RID to it */ + + if (!sid_compose(&sid, &dinfo->sid, r->in.rid)) + return NT_STATUS_NO_SUCH_USER; + + /* check if access can be granted as requested by client. */ + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &sid, SAMR_USR_RIGHTS_WRITE_PW); + se_map_generic(&des_access, &usr_generic_mapping); + + /* + * Get the sampass first as we need to check privileges + * based on what kind of user object this is. + * But don't reveal info too early if it didn't exist. + */ + + become_root(); + ret=pdb_getsampwsid(sampass, &sid); + unbecome_root(); + + needed_priv_1 = SEC_PRIV_INVALID; + needed_priv_2 = SEC_PRIV_INVALID; + /* + * We do the override access checks on *open*, not at + * SetUserInfo time. + */ + if (ret) { + uint32_t acb_info = pdb_get_acct_ctrl(sampass); + + if (acb_info & ACB_WSTRUST) { + /* + * SeMachineAccount is needed to add + * GENERIC_RIGHTS_USER_WRITE to a machine + * account. + */ + needed_priv_1 = SEC_PRIV_MACHINE_ACCOUNT; + } + if (acb_info & ACB_NORMAL) { + /* + * SeAddUsers is needed to add + * GENERIC_RIGHTS_USER_WRITE to a normal + * account. + */ + needed_priv_1 = SEC_PRIV_ADD_USERS; + } + /* + * Cheat - we have not set a specific privilege for + * server (BDC) or domain trust account, so allow + * GENERIC_RIGHTS_USER_WRITE if pipe user is in + * DOMAIN_RID_ADMINS. + */ + if (acb_info & (ACB_SVRTRUST|ACB_DOMTRUST)) { + if (lp_enable_privileges() && nt_token_check_domain_rid(p->server_info->security_token, + DOMAIN_RID_ADMINS)) { + des_access &= ~GENERIC_RIGHTS_USER_WRITE; + extra_access = GENERIC_RIGHTS_USER_WRITE; + DEBUG(4,("_samr_OpenUser: Allowing " + "GENERIC_RIGHTS_USER_WRITE for " + "rid admins\n")); + } + } + } + + TALLOC_FREE(sampass); + + nt_status = access_check_object(psd, p->server_info->security_token, + needed_priv_1, needed_priv_2, + GENERIC_RIGHTS_USER_WRITE, des_access, + &acc_granted, "_samr_OpenUser"); + + if ( !NT_STATUS_IS_OK(nt_status) ) + return nt_status; + + /* check that the SID exists in our domain. */ + if (ret == False) { + return NT_STATUS_NO_SUCH_USER; + } + + /* If we did the rid admins hack above, allow access. */ + acc_granted |= extra_access; + + uinfo = policy_handle_create(p, r->out.user_handle, acc_granted, + struct samr_user_info, &nt_status); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + uinfo->sid = sid; + + return NT_STATUS_OK; +} + +/************************************************************************* + *************************************************************************/ + +static NTSTATUS init_samr_parameters_string(TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, + struct lsa_BinaryString **_r) +{ + struct lsa_BinaryString *r; + + if (!blob || !_r) { + return NT_STATUS_INVALID_PARAMETER; + } + + r = TALLOC_ZERO_P(mem_ctx, struct lsa_BinaryString); + if (!r) { + return NT_STATUS_NO_MEMORY; + } + + r->array = TALLOC_ZERO_ARRAY(mem_ctx, uint16_t, blob->length/2); + if (!r->array) { + return NT_STATUS_NO_MEMORY; + } + memcpy(r->array, blob->data, blob->length); + r->size = blob->length; + r->length = blob->length; + + if (!r->array) { + return NT_STATUS_NO_MEMORY; + } + + *_r = r; + + return NT_STATUS_OK; +} + +/************************************************************************* + *************************************************************************/ + +static struct samr_LogonHours get_logon_hours_from_pdb(TALLOC_CTX *mem_ctx, + struct samu *pw) +{ + struct samr_LogonHours hours; + const int units_per_week = 168; + + ZERO_STRUCT(hours); + hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week); + if (!hours.bits) { + return hours; + } + + hours.units_per_week = units_per_week; + memset(hours.bits, 0xFF, units_per_week); + + if (pdb_get_hours(pw)) { + memcpy(hours.bits, pdb_get_hours(pw), + MIN(pdb_get_hours_len(pw), units_per_week)); + } + + return hours; +} + +/************************************************************************* + get_user_info_1. + *************************************************************************/ + +static NTSTATUS get_user_info_1(TALLOC_CTX *mem_ctx, + struct samr_UserInfo1 *r, + struct samu *pw, + struct dom_sid *domain_sid) +{ + const struct dom_sid *sid_group; + uint32_t primary_gid; + + become_root(); + sid_group = pdb_get_group_sid(pw); + unbecome_root(); + + if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { + DEBUG(0, ("get_user_info_1: User %s has Primary Group SID %s, \n" + "which conflicts with the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_group), + sid_string_dbg(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); + r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); + r->primary_gid = primary_gid; + r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); + r->comment.string = talloc_strdup(mem_ctx, pdb_get_comment(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_2. + *************************************************************************/ + +static NTSTATUS get_user_info_2(TALLOC_CTX *mem_ctx, + struct samr_UserInfo2 *r, + struct samu *pw) +{ + r->comment.string = talloc_strdup(mem_ctx, pdb_get_comment(pw)); + r->reserved.string = NULL; + r->country_code = 0; + r->code_page = 0; + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_3. + *************************************************************************/ + +static NTSTATUS get_user_info_3(TALLOC_CTX *mem_ctx, + struct samr_UserInfo3 *r, + struct samu *pw, + struct dom_sid *domain_sid) +{ + const struct dom_sid *sid_user, *sid_group; + uint32_t rid, primary_gid; + + sid_user = pdb_get_user_sid(pw); + + if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) { + DEBUG(0, ("get_user_info_3: User %s has SID %s, \nwhich conflicts with " + "the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_user), + sid_string_dbg(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + become_root(); + sid_group = pdb_get_group_sid(pw); + unbecome_root(); + + if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { + DEBUG(0, ("get_user_info_3: User %s has Primary Group SID %s, \n" + "which conflicts with the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_group), + sid_string_dbg(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + unix_to_nt_time(&r->last_logon, pdb_get_logon_time(pw)); + unix_to_nt_time(&r->last_logoff, pdb_get_logoff_time(pw)); + unix_to_nt_time(&r->last_password_change, pdb_get_pass_last_set_time(pw)); + unix_to_nt_time(&r->allow_password_change, pdb_get_pass_can_change_time(pw)); + unix_to_nt_time(&r->force_password_change, pdb_get_pass_must_change_time(pw)); + + r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); + r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); + r->home_directory.string= talloc_strdup(mem_ctx, pdb_get_homedir(pw)); + r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); + r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); + r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); + r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); + + r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); + r->rid = rid; + r->primary_gid = primary_gid; + r->acct_flags = pdb_get_acct_ctrl(pw); + r->bad_password_count = pdb_get_bad_password_count(pw); + r->logon_count = pdb_get_logon_count(pw); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_4. + *************************************************************************/ + +static NTSTATUS get_user_info_4(TALLOC_CTX *mem_ctx, + struct samr_UserInfo4 *r, + struct samu *pw) +{ + r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_5. + *************************************************************************/ + +static NTSTATUS get_user_info_5(TALLOC_CTX *mem_ctx, + struct samr_UserInfo5 *r, + struct samu *pw, + struct dom_sid *domain_sid) +{ + const struct dom_sid *sid_user, *sid_group; + uint32_t rid, primary_gid; + + sid_user = pdb_get_user_sid(pw); + + if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) { + DEBUG(0, ("get_user_info_5: User %s has SID %s, \nwhich conflicts with " + "the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_user), + sid_string_dbg(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + become_root(); + sid_group = pdb_get_group_sid(pw); + unbecome_root(); + + if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { + DEBUG(0, ("get_user_info_5: User %s has Primary Group SID %s, \n" + "which conflicts with the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_group), + sid_string_dbg(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + unix_to_nt_time(&r->last_logon, pdb_get_logon_time(pw)); + unix_to_nt_time(&r->last_logoff, pdb_get_logoff_time(pw)); + unix_to_nt_time(&r->acct_expiry, pdb_get_kickoff_time(pw)); + unix_to_nt_time(&r->last_password_change, pdb_get_pass_last_set_time(pw)); + + r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); + r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); + r->home_directory.string= talloc_strdup(mem_ctx, pdb_get_homedir(pw)); + r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); + r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); + r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); + r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); + r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); + + r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); + r->rid = rid; + r->primary_gid = primary_gid; + r->acct_flags = pdb_get_acct_ctrl(pw); + r->bad_password_count = pdb_get_bad_password_count(pw); + r->logon_count = pdb_get_logon_count(pw); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_6. + *************************************************************************/ + +static NTSTATUS get_user_info_6(TALLOC_CTX *mem_ctx, + struct samr_UserInfo6 *r, + struct samu *pw) +{ + r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); + r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_7. Safe. Only gives out account_name. + *************************************************************************/ + +static NTSTATUS get_user_info_7(TALLOC_CTX *mem_ctx, + struct samr_UserInfo7 *r, + struct samu *smbpass) +{ + r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(smbpass)); + if (!r->account_name.string) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_8. + *************************************************************************/ + +static NTSTATUS get_user_info_8(TALLOC_CTX *mem_ctx, + struct samr_UserInfo8 *r, + struct samu *pw) +{ + r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_9. Only gives out primary group SID. + *************************************************************************/ + +static NTSTATUS get_user_info_9(TALLOC_CTX *mem_ctx, + struct samr_UserInfo9 *r, + struct samu *smbpass) +{ + r->primary_gid = pdb_get_group_rid(smbpass); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_10. + *************************************************************************/ + +static NTSTATUS get_user_info_10(TALLOC_CTX *mem_ctx, + struct samr_UserInfo10 *r, + struct samu *pw) +{ + r->home_directory.string= talloc_strdup(mem_ctx, pdb_get_homedir(pw)); + r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_11. + *************************************************************************/ + +static NTSTATUS get_user_info_11(TALLOC_CTX *mem_ctx, + struct samr_UserInfo11 *r, + struct samu *pw) +{ + r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_12. + *************************************************************************/ + +static NTSTATUS get_user_info_12(TALLOC_CTX *mem_ctx, + struct samr_UserInfo12 *r, + struct samu *pw) +{ + r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_13. + *************************************************************************/ + +static NTSTATUS get_user_info_13(TALLOC_CTX *mem_ctx, + struct samr_UserInfo13 *r, + struct samu *pw) +{ + r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_14. + *************************************************************************/ + +static NTSTATUS get_user_info_14(TALLOC_CTX *mem_ctx, + struct samr_UserInfo14 *r, + struct samu *pw) +{ + r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_16. Safe. Only gives out acb bits. + *************************************************************************/ + +static NTSTATUS get_user_info_16(TALLOC_CTX *mem_ctx, + struct samr_UserInfo16 *r, + struct samu *smbpass) +{ + r->acct_flags = pdb_get_acct_ctrl(smbpass); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_17. + *************************************************************************/ + +static NTSTATUS get_user_info_17(TALLOC_CTX *mem_ctx, + struct samr_UserInfo17 *r, + struct samu *pw) +{ + unix_to_nt_time(&r->acct_expiry, pdb_get_kickoff_time(pw)); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_18. OK - this is the killer as it gives out password info. + Ensure that this is only allowed on an encrypted connection with a root + user. JRA. + *************************************************************************/ + +static NTSTATUS get_user_info_18(struct pipes_struct *p, + TALLOC_CTX *mem_ctx, + struct samr_UserInfo18 *r, + struct dom_sid *user_sid) +{ + struct samu *smbpass=NULL; + bool ret; + const uint8_t *nt_pass = NULL; + const uint8_t *lm_pass = NULL; + + ZERO_STRUCTP(r); + + if (p->server_info->system) { + goto query; + } + + if ((p->auth.auth_type != DCERPC_AUTH_TYPE_NTLMSSP) || + (p->auth.auth_type != DCERPC_AUTH_TYPE_KRB5) || + (p->auth.auth_type != DCERPC_AUTH_TYPE_SPNEGO)) { + return NT_STATUS_ACCESS_DENIED; + } + + if (p->auth.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { + return NT_STATUS_ACCESS_DENIED; + } + + query: + /* + * Do *NOT* do become_root()/unbecome_root() here ! JRA. + */ + + if ( !(smbpass = samu_new( mem_ctx )) ) { + return NT_STATUS_NO_MEMORY; + } + + ret = pdb_getsampwsid(smbpass, user_sid); + + if (ret == False) { + DEBUG(4, ("User %s not found\n", sid_string_dbg(user_sid))); + TALLOC_FREE(smbpass); + return (geteuid() == sec_initial_uid()) ? NT_STATUS_NO_SUCH_USER : NT_STATUS_ACCESS_DENIED; + } + + DEBUG(3,("User:[%s] 0x%x\n", pdb_get_username(smbpass), pdb_get_acct_ctrl(smbpass) )); + + if ( pdb_get_acct_ctrl(smbpass) & ACB_DISABLED) { + TALLOC_FREE(smbpass); + return NT_STATUS_ACCOUNT_DISABLED; + } + + lm_pass = pdb_get_lanman_passwd(smbpass); + if (lm_pass != NULL) { + memcpy(r->lm_pwd.hash, lm_pass, 16); + r->lm_pwd_active = true; + } + + nt_pass = pdb_get_nt_passwd(smbpass); + if (nt_pass != NULL) { + memcpy(r->nt_pwd.hash, nt_pass, 16); + r->nt_pwd_active = true; + } + r->password_expired = 0; /* FIXME */ + + TALLOC_FREE(smbpass); + + return NT_STATUS_OK; +} + +/************************************************************************* + get_user_info_20 + *************************************************************************/ + +static NTSTATUS get_user_info_20(TALLOC_CTX *mem_ctx, + struct samr_UserInfo20 *r, + struct samu *sampass) +{ + const char *munged_dial = NULL; + DATA_BLOB blob; + NTSTATUS status; + struct lsa_BinaryString *parameters = NULL; + + ZERO_STRUCTP(r); + + munged_dial = pdb_get_munged_dial(sampass); + + DEBUG(3,("User:[%s] has [%s] (length: %d)\n", pdb_get_username(sampass), + munged_dial, (int)strlen(munged_dial))); + + if (munged_dial) { + blob = base64_decode_data_blob(munged_dial); + } else { + blob = data_blob_string_const_null(""); + } + + status = init_samr_parameters_string(mem_ctx, &blob, ¶meters); + data_blob_free(&blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r->parameters = *parameters; + + return NT_STATUS_OK; +} + + +/************************************************************************* + get_user_info_21 + *************************************************************************/ + +static NTSTATUS get_user_info_21(TALLOC_CTX *mem_ctx, + struct samr_UserInfo21 *r, + struct samu *pw, + struct dom_sid *domain_sid, + uint32_t acc_granted) +{ + NTSTATUS status; + const struct dom_sid *sid_user, *sid_group; + uint32_t rid, primary_gid; + NTTIME force_password_change; + time_t must_change_time; + struct lsa_BinaryString *parameters = NULL; + const char *munged_dial = NULL; + DATA_BLOB blob; + + ZERO_STRUCTP(r); + + sid_user = pdb_get_user_sid(pw); + + if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) { + DEBUG(0, ("get_user_info_21: User %s has SID %s, \nwhich conflicts with " + "the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_user), + sid_string_dbg(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + become_root(); + sid_group = pdb_get_group_sid(pw); + unbecome_root(); + + if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { + DEBUG(0, ("get_user_info_21: User %s has Primary Group SID %s, \n" + "which conflicts with the domain sid %s. Failing operation.\n", + pdb_get_username(pw), sid_string_dbg(sid_group), + sid_string_dbg(domain_sid))); + return NT_STATUS_UNSUCCESSFUL; + } + + unix_to_nt_time(&r->last_logon, pdb_get_logon_time(pw)); + unix_to_nt_time(&r->last_logoff, pdb_get_logoff_time(pw)); + unix_to_nt_time(&r->acct_expiry, pdb_get_kickoff_time(pw)); + unix_to_nt_time(&r->last_password_change, pdb_get_pass_last_set_time(pw)); + unix_to_nt_time(&r->allow_password_change, pdb_get_pass_can_change_time(pw)); + + must_change_time = pdb_get_pass_must_change_time(pw); + if (must_change_time == get_time_t_max()) { + unix_to_nt_time_abs(&force_password_change, must_change_time); + } else { + unix_to_nt_time(&force_password_change, must_change_time); + } + + munged_dial = pdb_get_munged_dial(pw); + if (munged_dial) { + blob = base64_decode_data_blob(munged_dial); + } else { + blob = data_blob_string_const_null(""); + } + + status = init_samr_parameters_string(mem_ctx, &blob, ¶meters); + data_blob_free(&blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r->force_password_change = force_password_change; + + r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); + r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); + r->home_directory.string = talloc_strdup(mem_ctx, pdb_get_homedir(pw)); + r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); + r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); + r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); + r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); + r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); + r->comment.string = talloc_strdup(mem_ctx, pdb_get_comment(pw)); + + r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); + r->parameters = *parameters; + r->rid = rid; + r->primary_gid = primary_gid; + r->acct_flags = pdb_get_acct_ctrl(pw); + r->bad_password_count = pdb_get_bad_password_count(pw); + r->logon_count = pdb_get_logon_count(pw); + r->fields_present = pdb_build_fields_present(pw); + r->password_expired = (pdb_get_pass_must_change_time(pw) == 0) ? + PASS_MUST_CHANGE_AT_NEXT_LOGON : 0; + r->country_code = 0; + r->code_page = 0; + r->lm_password_set = 0; + r->nt_password_set = 0; + +#if 0 + + /* + Look at a user on a real NT4 PDC with usrmgr, press + 'ok'. Then you will see that fields_present is set to + 0x08f827fa. Look at the user immediately after that again, + and you will see that 0x00fffff is returned. This solves + the problem that you get access denied after having looked + at the user. + -- Volker + */ + +#endif + + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_QueryUserInfo + ********************************************************************/ + +NTSTATUS _samr_QueryUserInfo(struct pipes_struct *p, + struct samr_QueryUserInfo *r) +{ + NTSTATUS status; + union samr_UserInfo *user_info = NULL; + struct samr_user_info *uinfo; + struct dom_sid domain_sid; + uint32 rid; + bool ret = false; + struct samu *pwd = NULL; + uint32_t acc_required, acc_granted; + + switch (r->in.level) { + case 1: /* UserGeneralInformation */ + /* USER_READ_GENERAL */ + acc_required = SAMR_USER_ACCESS_GET_NAME_ETC; + break; + case 2: /* UserPreferencesInformation */ + /* USER_READ_PREFERENCES | USER_READ_GENERAL */ + acc_required = SAMR_USER_ACCESS_GET_LOCALE | + SAMR_USER_ACCESS_GET_NAME_ETC; + break; + case 3: /* UserLogonInformation */ + /* USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT */ + acc_required = SAMR_USER_ACCESS_GET_NAME_ETC | + SAMR_USER_ACCESS_GET_LOCALE | + SAMR_USER_ACCESS_GET_LOGONINFO | + SAMR_USER_ACCESS_GET_ATTRIBUTES; + break; + case 4: /* UserLogonHoursInformation */ + /* USER_READ_LOGON */ + acc_required = SAMR_USER_ACCESS_GET_LOGONINFO; + break; + case 5: /* UserAccountInformation */ + /* USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT */ + acc_required = SAMR_USER_ACCESS_GET_NAME_ETC | + SAMR_USER_ACCESS_GET_LOCALE | + SAMR_USER_ACCESS_GET_LOGONINFO | + SAMR_USER_ACCESS_GET_ATTRIBUTES; + break; + case 6: /* UserNameInformation */ + case 7: /* UserAccountNameInformation */ + case 8: /* UserFullNameInformation */ + case 9: /* UserPrimaryGroupInformation */ + case 13: /* UserAdminCommentInformation */ + /* USER_READ_GENERAL */ + acc_required = SAMR_USER_ACCESS_GET_NAME_ETC; + break; + case 10: /* UserHomeInformation */ + case 11: /* UserScriptInformation */ + case 12: /* UserProfileInformation */ + case 14: /* UserWorkStationsInformation */ + /* USER_READ_LOGON */ + acc_required = SAMR_USER_ACCESS_GET_LOGONINFO; + break; + case 16: /* UserControlInformation */ + case 17: /* UserExpiresInformation */ + case 20: /* UserParametersInformation */ + /* USER_READ_ACCOUNT */ + acc_required = SAMR_USER_ACCESS_GET_ATTRIBUTES; + break; + case 21: /* UserAllInformation */ + /* FIXME! - gd */ + acc_required = SAMR_USER_ACCESS_GET_ATTRIBUTES; + break; + case 18: /* UserInternal1Information */ + /* FIXME! - gd */ + acc_required = SAMR_USER_ACCESS_GET_ATTRIBUTES; + break; + case 23: /* UserInternal4Information */ + case 24: /* UserInternal4InformationNew */ + case 25: /* UserInternal4InformationNew */ + case 26: /* UserInternal5InformationNew */ + default: + return NT_STATUS_INVALID_INFO_CLASS; + break; + } + + uinfo = policy_handle_find(p, r->in.user_handle, + acc_required, &acc_granted, + struct samr_user_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + domain_sid = uinfo->sid; + + sid_split_rid(&domain_sid, &rid); + + if (!sid_check_is_in_our_domain(&uinfo->sid)) + return NT_STATUS_OBJECT_TYPE_MISMATCH; + + DEBUG(5,("_samr_QueryUserInfo: sid:%s\n", + sid_string_dbg(&uinfo->sid))); + + user_info = TALLOC_ZERO_P(p->mem_ctx, union samr_UserInfo); + if (!user_info) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(5,("_samr_QueryUserInfo: user info level: %d\n", r->in.level)); + + if (!(pwd = samu_new(p->mem_ctx))) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + ret = pdb_getsampwsid(pwd, &uinfo->sid); + unbecome_root(); + + if (ret == false) { + DEBUG(4,("User %s not found\n", sid_string_dbg(&uinfo->sid))); + TALLOC_FREE(pwd); + return NT_STATUS_NO_SUCH_USER; + } + + DEBUG(3,("User:[%s]\n", pdb_get_username(pwd))); + + samr_clear_sam_passwd(pwd); + + switch (r->in.level) { + case 1: + status = get_user_info_1(p->mem_ctx, &user_info->info1, pwd, &domain_sid); + break; + case 2: + status = get_user_info_2(p->mem_ctx, &user_info->info2, pwd); + break; + case 3: + status = get_user_info_3(p->mem_ctx, &user_info->info3, pwd, &domain_sid); + break; + case 4: + status = get_user_info_4(p->mem_ctx, &user_info->info4, pwd); + break; + case 5: + status = get_user_info_5(p->mem_ctx, &user_info->info5, pwd, &domain_sid); + break; + case 6: + status = get_user_info_6(p->mem_ctx, &user_info->info6, pwd); + break; + case 7: + status = get_user_info_7(p->mem_ctx, &user_info->info7, pwd); + break; + case 8: + status = get_user_info_8(p->mem_ctx, &user_info->info8, pwd); + break; + case 9: + status = get_user_info_9(p->mem_ctx, &user_info->info9, pwd); + break; + case 10: + status = get_user_info_10(p->mem_ctx, &user_info->info10, pwd); + break; + case 11: + status = get_user_info_11(p->mem_ctx, &user_info->info11, pwd); + break; + case 12: + status = get_user_info_12(p->mem_ctx, &user_info->info12, pwd); + break; + case 13: + status = get_user_info_13(p->mem_ctx, &user_info->info13, pwd); + break; + case 14: + status = get_user_info_14(p->mem_ctx, &user_info->info14, pwd); + break; + case 16: + status = get_user_info_16(p->mem_ctx, &user_info->info16, pwd); + break; + case 17: + status = get_user_info_17(p->mem_ctx, &user_info->info17, pwd); + break; + case 18: + /* level 18 is special */ + status = get_user_info_18(p, p->mem_ctx, &user_info->info18, + &uinfo->sid); + break; + case 20: + status = get_user_info_20(p->mem_ctx, &user_info->info20, pwd); + break; + case 21: + status = get_user_info_21(p->mem_ctx, &user_info->info21, pwd, &domain_sid, acc_granted); + break; + default: + status = NT_STATUS_INVALID_INFO_CLASS; + break; + } + + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + *r->out.info = user_info; + + done: + TALLOC_FREE(pwd); + + DEBUG(5,("_samr_QueryUserInfo: %d\n", __LINE__)); + + return status; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_QueryUserInfo2(struct pipes_struct *p, + struct samr_QueryUserInfo2 *r) +{ + struct samr_QueryUserInfo u; + + u.in.user_handle = r->in.user_handle; + u.in.level = r->in.level; + u.out.info = r->out.info; + + return _samr_QueryUserInfo(p, &u); +} + +/******************************************************************* + _samr_GetGroupsForUser + ********************************************************************/ + +NTSTATUS _samr_GetGroupsForUser(struct pipes_struct *p, + struct samr_GetGroupsForUser *r) +{ + struct samr_user_info *uinfo; + struct samu *sam_pass=NULL; + struct dom_sid *sids; + struct samr_RidWithAttribute dom_gid; + struct samr_RidWithAttribute *gids = NULL; + uint32 primary_group_rid; + size_t num_groups = 0; + gid_t *unix_gids; + size_t i, num_gids; + bool ret; + NTSTATUS result; + bool success = False; + + struct samr_RidWithAttributeArray *rids = NULL; + + /* + * from the SID in the request: + * we should send back the list of DOMAIN GROUPS + * the user is a member of + * + * and only the DOMAIN GROUPS + * no ALIASES !!! neither aliases of the domain + * nor aliases of the builtin SID + * + * JFM, 12/2/2001 + */ + + DEBUG(5,("_samr_GetGroupsForUser: %d\n", __LINE__)); + + uinfo = policy_handle_find(p, r->in.user_handle, + SAMR_USER_ACCESS_GET_GROUPS, NULL, + struct samr_user_info, &result); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + rids = TALLOC_ZERO_P(p->mem_ctx, struct samr_RidWithAttributeArray); + if (!rids) { + return NT_STATUS_NO_MEMORY; + } + + if (!sid_check_is_in_our_domain(&uinfo->sid)) + return NT_STATUS_OBJECT_TYPE_MISMATCH; + + if ( !(sam_pass = samu_new( p->mem_ctx )) ) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + ret = pdb_getsampwsid(sam_pass, &uinfo->sid); + unbecome_root(); + + if (!ret) { + DEBUG(10, ("pdb_getsampwsid failed for %s\n", + sid_string_dbg(&uinfo->sid))); + return NT_STATUS_NO_SUCH_USER; + } + + sids = NULL; + + /* make both calls inside the root block */ + become_root(); + result = pdb_enum_group_memberships(p->mem_ctx, sam_pass, + &sids, &unix_gids, &num_groups); + if ( NT_STATUS_IS_OK(result) ) { + success = sid_peek_check_rid(get_global_sam_sid(), + pdb_get_group_sid(sam_pass), + &primary_group_rid); + } + unbecome_root(); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("pdb_enum_group_memberships failed for %s\n", + sid_string_dbg(&uinfo->sid))); + return result; + } + + if ( !success ) { + DEBUG(5, ("Group sid %s for user %s not in our domain\n", + sid_string_dbg(pdb_get_group_sid(sam_pass)), + pdb_get_username(sam_pass))); + TALLOC_FREE(sam_pass); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + gids = NULL; + num_gids = 0; + + dom_gid.attributes = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT| + SE_GROUP_ENABLED); + dom_gid.rid = primary_group_rid; + ADD_TO_ARRAY(p->mem_ctx, struct samr_RidWithAttribute, dom_gid, &gids, &num_gids); + + for (i=0; imem_ctx, struct samr_RidWithAttribute, dom_gid, &gids, &num_gids); + } + + rids->count = num_gids; + rids->rids = gids; + + *r->out.rids = rids; + + DEBUG(5,("_samr_GetGroupsForUser: %d\n", __LINE__)); + + return result; +} + +/******************************************************************* + ********************************************************************/ + +static uint32_t samr_get_server_role(void) +{ + uint32_t role = ROLE_DOMAIN_PDC; + + if (lp_server_role() == ROLE_DOMAIN_BDC) { + role = ROLE_DOMAIN_BDC; + } + + return role; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_1(TALLOC_CTX *mem_ctx, + struct samr_DomInfo1 *r) +{ + uint32_t account_policy_temp; + time_t u_expire, u_min_age; + + become_root(); + + /* AS ROOT !!! */ + + pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &account_policy_temp); + r->min_password_length = account_policy_temp; + + pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &account_policy_temp); + r->password_history_length = account_policy_temp; + + pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, + &r->password_properties); + + pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &account_policy_temp); + u_expire = account_policy_temp; + + pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, &account_policy_temp); + u_min_age = account_policy_temp; + + /* !AS ROOT */ + + unbecome_root(); + + unix_to_nt_time_abs((NTTIME *)&r->max_password_age, u_expire); + unix_to_nt_time_abs((NTTIME *)&r->min_password_age, u_min_age); + + if (lp_check_password_script() && *lp_check_password_script()) { + r->password_properties |= DOMAIN_PASSWORD_COMPLEX; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_2(TALLOC_CTX *mem_ctx, + struct samr_DomGeneralInformation *r, + struct samr_domain_info *dinfo) +{ + uint32_t u_logout; + time_t seq_num; + + become_root(); + + /* AS ROOT !!! */ + + r->num_users = count_sam_users(dinfo->disp_info, ACB_NORMAL); + r->num_groups = count_sam_groups(dinfo->disp_info); + r->num_aliases = count_sam_aliases(dinfo->disp_info); + + pdb_get_account_policy(PDB_POLICY_TIME_TO_LOGOUT, &u_logout); + + unix_to_nt_time_abs(&r->force_logoff_time, u_logout); + + if (!pdb_get_seq_num(&seq_num)) { + seq_num = time(NULL); + } + + /* !AS ROOT */ + + unbecome_root(); + + r->oem_information.string = lp_serverstring(); + r->domain_name.string = lp_workgroup(); + r->primary.string = global_myname(); + r->sequence_num = seq_num; + r->domain_server_state = DOMAIN_SERVER_ENABLED; + r->role = (enum samr_Role) samr_get_server_role(); + r->unknown3 = 1; + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_3(TALLOC_CTX *mem_ctx, + struct samr_DomInfo3 *r) +{ + uint32_t u_logout; + + become_root(); + + /* AS ROOT !!! */ + + { + uint32_t ul; + pdb_get_account_policy(PDB_POLICY_TIME_TO_LOGOUT, &ul); + u_logout = (time_t)ul; + } + + /* !AS ROOT */ + + unbecome_root(); + + unix_to_nt_time_abs(&r->force_logoff_time, u_logout); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_4(TALLOC_CTX *mem_ctx, + struct samr_DomOEMInformation *r) +{ + r->oem_information.string = lp_serverstring(); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_5(TALLOC_CTX *mem_ctx, + struct samr_DomInfo5 *r) +{ + r->domain_name.string = get_global_sam_name(); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_6(TALLOC_CTX *mem_ctx, + struct samr_DomInfo6 *r) +{ + /* NT returns its own name when a PDC. win2k and later + * only the name of the PDC if itself is a BDC (samba4 + * idl) */ + r->primary.string = global_myname(); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_7(TALLOC_CTX *mem_ctx, + struct samr_DomInfo7 *r) +{ + r->role = (enum samr_Role) samr_get_server_role(); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_8(TALLOC_CTX *mem_ctx, + struct samr_DomInfo8 *r) +{ + time_t seq_num; + + become_root(); + + /* AS ROOT !!! */ + + if (!pdb_get_seq_num(&seq_num)) { + seq_num = time(NULL); + } + + /* !AS ROOT */ + + unbecome_root(); + + r->sequence_num = seq_num; + r->domain_create_time = 0; + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_9(TALLOC_CTX *mem_ctx, + struct samr_DomInfo9 *r) +{ + r->domain_server_state = DOMAIN_SERVER_ENABLED; + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_11(TALLOC_CTX *mem_ctx, + struct samr_DomGeneralInformation2 *r, + struct samr_domain_info *dinfo) +{ + NTSTATUS status; + uint32_t account_policy_temp; + time_t u_lock_duration, u_reset_time; + + status = query_dom_info_2(mem_ctx, &r->general, dinfo); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* AS ROOT !!! */ + + become_root(); + + pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, &account_policy_temp); + u_lock_duration = account_policy_temp; + if (u_lock_duration != -1) { + u_lock_duration *= 60; + } + + pdb_get_account_policy(PDB_POLICY_RESET_COUNT_TIME, &account_policy_temp); + u_reset_time = account_policy_temp * 60; + + pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &account_policy_temp); + r->lockout_threshold = account_policy_temp; + + /* !AS ROOT */ + + unbecome_root(); + + unix_to_nt_time_abs(&r->lockout_duration, u_lock_duration); + unix_to_nt_time_abs(&r->lockout_window, u_reset_time); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_12(TALLOC_CTX *mem_ctx, + struct samr_DomInfo12 *r) +{ + uint32_t account_policy_temp; + time_t u_lock_duration, u_reset_time; + + become_root(); + + /* AS ROOT !!! */ + + pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, &account_policy_temp); + u_lock_duration = account_policy_temp; + if (u_lock_duration != -1) { + u_lock_duration *= 60; + } + + pdb_get_account_policy(PDB_POLICY_RESET_COUNT_TIME, &account_policy_temp); + u_reset_time = account_policy_temp * 60; + + pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &account_policy_temp); + r->lockout_threshold = account_policy_temp; + + /* !AS ROOT */ + + unbecome_root(); + + unix_to_nt_time_abs(&r->lockout_duration, u_lock_duration); + unix_to_nt_time_abs(&r->lockout_window, u_reset_time); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS query_dom_info_13(TALLOC_CTX *mem_ctx, + struct samr_DomInfo13 *r) +{ + time_t seq_num; + + become_root(); + + /* AS ROOT !!! */ + + if (!pdb_get_seq_num(&seq_num)) { + seq_num = time(NULL); + } + + /* !AS ROOT */ + + unbecome_root(); + + r->sequence_num = seq_num; + r->domain_create_time = 0; + r->modified_count_at_last_promotion = 0; + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_QueryDomainInfo + ********************************************************************/ + +NTSTATUS _samr_QueryDomainInfo(struct pipes_struct *p, + struct samr_QueryDomainInfo *r) +{ + NTSTATUS status = NT_STATUS_OK; + struct samr_domain_info *dinfo; + union samr_DomainInfo *dom_info; + + uint32_t acc_required; + + DEBUG(5,("_samr_QueryDomainInfo: %d\n", __LINE__)); + + switch (r->in.level) { + case 1: /* DomainPasswordInformation */ + case 12: /* DomainLockoutInformation */ + /* DOMAIN_READ_PASSWORD_PARAMETERS */ + acc_required = SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1; + break; + case 11: /* DomainGeneralInformation2 */ + /* DOMAIN_READ_PASSWORD_PARAMETERS | + * DOMAIN_READ_OTHER_PARAMETERS */ + acc_required = SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 | + SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2; + break; + case 2: /* DomainGeneralInformation */ + case 3: /* DomainLogoffInformation */ + case 4: /* DomainOemInformation */ + case 5: /* DomainReplicationInformation */ + case 6: /* DomainReplicationInformation */ + case 7: /* DomainServerRoleInformation */ + case 8: /* DomainModifiedInformation */ + case 9: /* DomainStateInformation */ + case 10: /* DomainUasInformation */ + case 13: /* DomainModifiedInformation2 */ + /* DOMAIN_READ_OTHER_PARAMETERS */ + acc_required = SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2; + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + dinfo = policy_handle_find(p, r->in.domain_handle, + acc_required, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + dom_info = TALLOC_ZERO_P(p->mem_ctx, union samr_DomainInfo); + if (!dom_info) { + return NT_STATUS_NO_MEMORY; + } + + switch (r->in.level) { + case 1: + status = query_dom_info_1(p->mem_ctx, &dom_info->info1); + break; + case 2: + status = query_dom_info_2(p->mem_ctx, &dom_info->general, dinfo); + break; + case 3: + status = query_dom_info_3(p->mem_ctx, &dom_info->info3); + break; + case 4: + status = query_dom_info_4(p->mem_ctx, &dom_info->oem); + break; + case 5: + status = query_dom_info_5(p->mem_ctx, &dom_info->info5); + break; + case 6: + status = query_dom_info_6(p->mem_ctx, &dom_info->info6); + break; + case 7: + status = query_dom_info_7(p->mem_ctx, &dom_info->info7); + break; + case 8: + status = query_dom_info_8(p->mem_ctx, &dom_info->info8); + break; + case 9: + status = query_dom_info_9(p->mem_ctx, &dom_info->info9); + break; + case 11: + status = query_dom_info_11(p->mem_ctx, &dom_info->general2, dinfo); + break; + case 12: + status = query_dom_info_12(p->mem_ctx, &dom_info->info12); + break; + case 13: + status = query_dom_info_13(p->mem_ctx, &dom_info->info13); + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *r->out.info = dom_info; + + DEBUG(5,("_samr_QueryDomainInfo: %d\n", __LINE__)); + + return status; +} + +/* W2k3 seems to use the same check for all 3 objects that can be created via + * SAMR, if you try to create for example "Dialup" as an alias it says + * "NT_STATUS_USER_EXISTS". This is racy, but we can't really lock the user + * database. */ + +static NTSTATUS can_create(TALLOC_CTX *mem_ctx, const char *new_name) +{ + enum lsa_SidType type; + bool result; + + DEBUG(10, ("Checking whether [%s] can be created\n", new_name)); + + become_root(); + /* Lookup in our local databases (LOOKUP_NAME_REMOTE not set) + * whether the name already exists */ + result = lookup_name(mem_ctx, new_name, LOOKUP_NAME_LOCAL, + NULL, NULL, NULL, &type); + unbecome_root(); + + if (!result) { + DEBUG(10, ("%s does not exist, can create it\n", new_name)); + return NT_STATUS_OK; + } + + DEBUG(5, ("trying to create %s, exists as %s\n", + new_name, sid_type_lookup(type))); + + if (type == SID_NAME_DOM_GRP) { + return NT_STATUS_GROUP_EXISTS; + } + if (type == SID_NAME_ALIAS) { + return NT_STATUS_ALIAS_EXISTS; + } + + /* Yes, the default is NT_STATUS_USER_EXISTS */ + return NT_STATUS_USER_EXISTS; +} + +/******************************************************************* + _samr_CreateUser2 + ********************************************************************/ + +NTSTATUS _samr_CreateUser2(struct pipes_struct *p, + struct samr_CreateUser2 *r) +{ + const char *account = NULL; + struct dom_sid sid; + uint32_t acb_info = r->in.acct_flags; + struct samr_domain_info *dinfo; + struct samr_user_info *uinfo; + NTSTATUS nt_status; + uint32 acc_granted; + struct security_descriptor *psd; + size_t sd_size; + /* check this, when giving away 'add computer to domain' privs */ + uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS; + bool can_add_account = False; + + /* Which privilege is needed to override the ACL? */ + enum sec_privilege needed_priv = SEC_PRIV_INVALID; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_CREATE_USER, NULL, + struct samr_domain_info, &nt_status); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + if (sid_check_is_builtin(&dinfo->sid)) { + DEBUG(5,("_samr_CreateUser2: Refusing user create in BUILTIN\n")); + return NT_STATUS_ACCESS_DENIED; + } + + if (!(acb_info == ACB_NORMAL || acb_info == ACB_DOMTRUST || + acb_info == ACB_WSTRUST || acb_info == ACB_SVRTRUST)) { + /* Match Win2k, and return NT_STATUS_INVALID_PARAMETER if + this parameter is not an account type */ + return NT_STATUS_INVALID_PARAMETER; + } + + account = r->in.account_name->string; + if (account == NULL) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = can_create(p->mem_ctx, account); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + /* determine which user right we need to check based on the acb_info */ + + if (geteuid() == sec_initial_uid()) { + can_add_account = true; + } else if (acb_info & ACB_WSTRUST) { + needed_priv = SEC_PRIV_MACHINE_ACCOUNT; + can_add_account = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_MACHINE_ACCOUNT); + } else if (acb_info & ACB_NORMAL && + (account[strlen(account)-1] != '$')) { + /* usrmgr.exe (and net rpc trustdom grant) creates a normal user + account for domain trusts and changes the ACB flags later */ + needed_priv = SEC_PRIV_ADD_USERS; + can_add_account = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_ADD_USERS); + } else if (lp_enable_privileges()) { + /* implicit assumption of a BDC or domain trust account here + * (we already check the flags earlier) */ + /* only Domain Admins can add a BDC or domain trust */ + can_add_account = nt_token_check_domain_rid( + p->server_info->security_token, + DOMAIN_RID_ADMINS ); + } + + DEBUG(5, ("_samr_CreateUser2: %s can add this account : %s\n", + uidtoname(p->server_info->utok.uid), + can_add_account ? "True":"False" )); + + if (!can_add_account) { + return NT_STATUS_ACCESS_DENIED; + } + + /********** BEGIN Admin BLOCK **********/ + + become_root(); + nt_status = pdb_create_user(p->mem_ctx, account, acb_info, + r->out.rid); + unbecome_root(); + + /********** END Admin BLOCK **********/ + + /* now check for failure */ + + if ( !NT_STATUS_IS_OK(nt_status) ) + return nt_status; + + /* Get the user's SID */ + + sid_compose(&sid, get_global_sam_sid(), *r->out.rid); + + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, + &sid, SAMR_USR_RIGHTS_WRITE_PW); + se_map_generic(&des_access, &usr_generic_mapping); + + /* + * JRA - TESTME. We just created this user so we + * had rights to create them. Do we need to check + * any further access on this object ? Can't we + * just assume we have all the rights we need ? + */ + + nt_status = access_check_object(psd, p->server_info->security_token, + needed_priv, SEC_PRIV_INVALID, + GENERIC_RIGHTS_USER_WRITE, des_access, + &acc_granted, "_samr_CreateUser2"); + + if ( !NT_STATUS_IS_OK(nt_status) ) { + return nt_status; + } + + uinfo = policy_handle_create(p, r->out.user_handle, acc_granted, + struct samr_user_info, &nt_status); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + uinfo->sid = sid; + + /* After a "set" ensure we have no cached display info. */ + force_flush_samr_cache(&sid); + + *r->out.access_granted = acc_granted; + + return NT_STATUS_OK; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_CreateUser(struct pipes_struct *p, + struct samr_CreateUser *r) +{ + struct samr_CreateUser2 c; + uint32_t access_granted; + + c.in.domain_handle = r->in.domain_handle; + c.in.account_name = r->in.account_name; + c.in.acct_flags = ACB_NORMAL; + c.in.access_mask = r->in.access_mask; + c.out.user_handle = r->out.user_handle; + c.out.access_granted = &access_granted; + c.out.rid = r->out.rid; + + return _samr_CreateUser2(p, &c); +} + +/******************************************************************* + _samr_Connect + ********************************************************************/ + +NTSTATUS _samr_Connect(struct pipes_struct *p, + struct samr_Connect *r) +{ + struct samr_connect_info *info; + uint32_t acc_granted; + struct policy_handle hnd; + uint32 des_access = r->in.access_mask; + NTSTATUS status; + + /* Access check */ + + if (!pipe_access_check(p)) { + DEBUG(3, ("access denied to _samr_Connect\n")); + return NT_STATUS_ACCESS_DENIED; + } + + /* don't give away the farm but this is probably ok. The SAMR_ACCESS_ENUM_DOMAINS + was observed from a win98 client trying to enumerate users (when configured + user level access control on shares) --jerry */ + + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + se_map_generic( &des_access, &sam_generic_mapping ); + + acc_granted = des_access & (SAMR_ACCESS_ENUM_DOMAINS + |SAMR_ACCESS_LOOKUP_DOMAIN); + + /* set up the SAMR connect_anon response */ + + info = policy_handle_create(p, &hnd, acc_granted, + struct samr_connect_info, + &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + *r->out.connect_handle = hnd; + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_Connect2 + ********************************************************************/ + +NTSTATUS _samr_Connect2(struct pipes_struct *p, + struct samr_Connect2 *r) +{ + struct samr_connect_info *info = NULL; + struct policy_handle hnd; + struct security_descriptor *psd = NULL; + uint32 acc_granted; + uint32 des_access = r->in.access_mask; + NTSTATUS nt_status; + size_t sd_size; + const char *fn = "_samr_Connect2"; + + switch (p->opnum) { + case NDR_SAMR_CONNECT2: + fn = "_samr_Connect2"; + break; + case NDR_SAMR_CONNECT3: + fn = "_samr_Connect3"; + break; + case NDR_SAMR_CONNECT4: + fn = "_samr_Connect4"; + break; + case NDR_SAMR_CONNECT5: + fn = "_samr_Connect5"; + break; + } + + DEBUG(5,("%s: %d\n", fn, __LINE__)); + + /* Access check */ + + if (!pipe_access_check(p)) { + DEBUG(3, ("access denied to %s\n", fn)); + return NT_STATUS_ACCESS_DENIED; + } + + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0); + se_map_generic(&des_access, &sam_generic_mapping); + + nt_status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_INVALID, SEC_PRIV_INVALID, + 0, des_access, &acc_granted, fn); + + if ( !NT_STATUS_IS_OK(nt_status) ) + return nt_status; + + info = policy_handle_create(p, &hnd, acc_granted, + struct samr_connect_info, &nt_status); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + DEBUG(5,("%s: %d\n", fn, __LINE__)); + + *r->out.connect_handle = hnd; + return NT_STATUS_OK; +} + +/**************************************************************** + _samr_Connect3 +****************************************************************/ + +NTSTATUS _samr_Connect3(struct pipes_struct *p, + struct samr_Connect3 *r) +{ + struct samr_Connect2 c; + + c.in.system_name = r->in.system_name; + c.in.access_mask = r->in.access_mask; + c.out.connect_handle = r->out.connect_handle; + + return _samr_Connect2(p, &c); +} + +/******************************************************************* + _samr_Connect4 + ********************************************************************/ + +NTSTATUS _samr_Connect4(struct pipes_struct *p, + struct samr_Connect4 *r) +{ + struct samr_Connect2 c; + + c.in.system_name = r->in.system_name; + c.in.access_mask = r->in.access_mask; + c.out.connect_handle = r->out.connect_handle; + + return _samr_Connect2(p, &c); +} + +/******************************************************************* + _samr_Connect5 + ********************************************************************/ + +NTSTATUS _samr_Connect5(struct pipes_struct *p, + struct samr_Connect5 *r) +{ + NTSTATUS status; + struct samr_Connect2 c; + struct samr_ConnectInfo1 info1; + + info1.client_version = SAMR_CONNECT_AFTER_W2K; + info1.unknown2 = 0; + + c.in.system_name = r->in.system_name; + c.in.access_mask = r->in.access_mask; + c.out.connect_handle = r->out.connect_handle; + + *r->out.level_out = 1; + + status = _samr_Connect2(p, &c); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r->out.info_out->info1 = info1; + + return NT_STATUS_OK; +} + +/********************************************************************** + _samr_LookupDomain + **********************************************************************/ + +NTSTATUS _samr_LookupDomain(struct pipes_struct *p, + struct samr_LookupDomain *r) +{ + NTSTATUS status; + struct samr_connect_info *info; + const char *domain_name; + struct dom_sid *sid = NULL; + + /* win9x user manager likes to use SAMR_ACCESS_ENUM_DOMAINS here. + Reverted that change so we will work with RAS servers again */ + + info = policy_handle_find(p, r->in.connect_handle, + SAMR_ACCESS_LOOKUP_DOMAIN, NULL, + struct samr_connect_info, + &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + domain_name = r->in.domain_name->string; + if (!domain_name) { + return NT_STATUS_INVALID_PARAMETER; + } + + sid = TALLOC_ZERO_P(p->mem_ctx, struct dom_sid2); + if (!sid) { + return NT_STATUS_NO_MEMORY; + } + + if (strequal(domain_name, builtin_domain_name())) { + sid_copy(sid, &global_sid_Builtin); + } else { + if (!secrets_fetch_domain_sid(domain_name, sid)) { + status = NT_STATUS_NO_SUCH_DOMAIN; + } + } + + DEBUG(2,("Returning domain sid for domain %s -> %s\n", domain_name, + sid_string_dbg(sid))); + + *r->out.sid = sid; + + return status; +} + +/********************************************************************** + _samr_EnumDomains + **********************************************************************/ + +NTSTATUS _samr_EnumDomains(struct pipes_struct *p, + struct samr_EnumDomains *r) +{ + NTSTATUS status; + struct samr_connect_info *info; + uint32_t num_entries = 2; + struct samr_SamEntry *entry_array = NULL; + struct samr_SamArray *sam; + + info = policy_handle_find(p, r->in.connect_handle, + SAMR_ACCESS_ENUM_DOMAINS, NULL, + struct samr_connect_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + sam = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); + if (!sam) { + return NT_STATUS_NO_MEMORY; + } + + entry_array = TALLOC_ZERO_ARRAY(p->mem_ctx, + struct samr_SamEntry, + num_entries); + if (!entry_array) { + return NT_STATUS_NO_MEMORY; + } + + entry_array[0].idx = 0; + init_lsa_String(&entry_array[0].name, get_global_sam_name()); + + entry_array[1].idx = 1; + init_lsa_String(&entry_array[1].name, "Builtin"); + + sam->count = num_entries; + sam->entries = entry_array; + + *r->out.sam = sam; + *r->out.num_entries = num_entries; + + return status; +} + +/******************************************************************* + _samr_OpenAlias + ********************************************************************/ + +NTSTATUS _samr_OpenAlias(struct pipes_struct *p, + struct samr_OpenAlias *r) +{ + struct dom_sid sid; + uint32 alias_rid = r->in.rid; + struct samr_alias_info *ainfo; + struct samr_domain_info *dinfo; + struct security_descriptor *psd = NULL; + uint32 acc_granted; + uint32 des_access = r->in.access_mask; + size_t sd_size; + NTSTATUS status; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* append the alias' RID to it */ + + if (!sid_compose(&sid, &dinfo->sid, alias_rid)) + return NT_STATUS_NO_SUCH_ALIAS; + + /*check if access can be granted as requested by client. */ + + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &ali_generic_mapping, NULL, 0); + se_map_generic(&des_access,&ali_generic_mapping); + + status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_ADD_USERS, SEC_PRIV_INVALID, + GENERIC_RIGHTS_ALIAS_ALL_ACCESS, + des_access, &acc_granted, "_samr_OpenAlias"); + + if ( !NT_STATUS_IS_OK(status) ) + return status; + + { + /* Check we actually have the requested alias */ + enum lsa_SidType type; + bool result; + gid_t gid; + + become_root(); + result = lookup_sid(NULL, &sid, NULL, NULL, &type); + unbecome_root(); + + if (!result || (type != SID_NAME_ALIAS)) { + return NT_STATUS_NO_SUCH_ALIAS; + } + + /* make sure there is a mapping */ + + if ( !sid_to_gid( &sid, &gid ) ) { + return NT_STATUS_NO_SUCH_ALIAS; + } + + } + + ainfo = policy_handle_create(p, r->out.alias_handle, acc_granted, + struct samr_alias_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ainfo->sid = sid; + + return NT_STATUS_OK; +} + +/******************************************************************* + set_user_info_2 + ********************************************************************/ + +static NTSTATUS set_user_info_2(TALLOC_CTX *mem_ctx, + struct samr_UserInfo2 *id2, + struct samu *pwd) +{ + if (id2 == NULL) { + DEBUG(5,("set_user_info_2: NULL id2\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id2_to_sam_passwd(pwd, id2); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_4 + ********************************************************************/ + +static NTSTATUS set_user_info_4(TALLOC_CTX *mem_ctx, + struct samr_UserInfo4 *id4, + struct samu *pwd) +{ + if (id4 == NULL) { + DEBUG(5,("set_user_info_2: NULL id4\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id4_to_sam_passwd(pwd, id4); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_6 + ********************************************************************/ + +static NTSTATUS set_user_info_6(TALLOC_CTX *mem_ctx, + struct samr_UserInfo6 *id6, + struct samu *pwd) +{ + if (id6 == NULL) { + DEBUG(5,("set_user_info_6: NULL id6\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id6_to_sam_passwd(pwd, id6); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_7 + ********************************************************************/ + +static NTSTATUS set_user_info_7(TALLOC_CTX *mem_ctx, + struct samr_UserInfo7 *id7, + struct samu *pwd) +{ + NTSTATUS rc; + + if (id7 == NULL) { + DEBUG(5, ("set_user_info_7: NULL id7\n")); + return NT_STATUS_ACCESS_DENIED; + } + + if (!id7->account_name.string) { + DEBUG(5, ("set_user_info_7: failed to get new username\n")); + return NT_STATUS_ACCESS_DENIED; + } + + /* check to see if the new username already exists. Note: we can't + reliably lock all backends, so there is potentially the + possibility that a user can be created in between this check and + the rename. The rename should fail, but may not get the + exact same failure status code. I think this is small enough + of a window for this type of operation and the results are + simply that the rename fails with a slightly different status + code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */ + + rc = can_create(mem_ctx, id7->account_name.string); + + /* when there is nothing to change, we're done here */ + if (NT_STATUS_EQUAL(rc, NT_STATUS_USER_EXISTS) && + strequal(id7->account_name.string, pdb_get_username(pwd))) { + return NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(rc)) { + return rc; + } + + rc = pdb_rename_sam_account(pwd, id7->account_name.string); + + return rc; +} + +/******************************************************************* + set_user_info_8 + ********************************************************************/ + +static NTSTATUS set_user_info_8(TALLOC_CTX *mem_ctx, + struct samr_UserInfo8 *id8, + struct samu *pwd) +{ + if (id8 == NULL) { + DEBUG(5,("set_user_info_8: NULL id8\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id8_to_sam_passwd(pwd, id8); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_10 + ********************************************************************/ + +static NTSTATUS set_user_info_10(TALLOC_CTX *mem_ctx, + struct samr_UserInfo10 *id10, + struct samu *pwd) +{ + if (id10 == NULL) { + DEBUG(5,("set_user_info_8: NULL id10\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id10_to_sam_passwd(pwd, id10); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_11 + ********************************************************************/ + +static NTSTATUS set_user_info_11(TALLOC_CTX *mem_ctx, + struct samr_UserInfo11 *id11, + struct samu *pwd) +{ + if (id11 == NULL) { + DEBUG(5,("set_user_info_11: NULL id11\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id11_to_sam_passwd(pwd, id11); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_12 + ********************************************************************/ + +static NTSTATUS set_user_info_12(TALLOC_CTX *mem_ctx, + struct samr_UserInfo12 *id12, + struct samu *pwd) +{ + if (id12 == NULL) { + DEBUG(5,("set_user_info_12: NULL id12\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id12_to_sam_passwd(pwd, id12); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_13 + ********************************************************************/ + +static NTSTATUS set_user_info_13(TALLOC_CTX *mem_ctx, + struct samr_UserInfo13 *id13, + struct samu *pwd) +{ + if (id13 == NULL) { + DEBUG(5,("set_user_info_13: NULL id13\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id13_to_sam_passwd(pwd, id13); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_14 + ********************************************************************/ + +static NTSTATUS set_user_info_14(TALLOC_CTX *mem_ctx, + struct samr_UserInfo14 *id14, + struct samu *pwd) +{ + if (id14 == NULL) { + DEBUG(5,("set_user_info_14: NULL id14\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id14_to_sam_passwd(pwd, id14); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_16 + ********************************************************************/ + +static NTSTATUS set_user_info_16(TALLOC_CTX *mem_ctx, + struct samr_UserInfo16 *id16, + struct samu *pwd) +{ + if (id16 == NULL) { + DEBUG(5,("set_user_info_16: NULL id16\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id16_to_sam_passwd(pwd, id16); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_17 + ********************************************************************/ + +static NTSTATUS set_user_info_17(TALLOC_CTX *mem_ctx, + struct samr_UserInfo17 *id17, + struct samu *pwd) +{ + if (id17 == NULL) { + DEBUG(5,("set_user_info_17: NULL id17\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id17_to_sam_passwd(pwd, id17); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_18 + ********************************************************************/ + +static NTSTATUS set_user_info_18(struct samr_UserInfo18 *id18, + TALLOC_CTX *mem_ctx, + DATA_BLOB *session_key, + struct samu *pwd) +{ + if (id18 == NULL) { + DEBUG(2, ("set_user_info_18: id18 is NULL\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (id18->nt_pwd_active || id18->lm_pwd_active) { + if (!session_key->length) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + } + + if (id18->nt_pwd_active) { + + DATA_BLOB in, out; + + in = data_blob_const(id18->nt_pwd.hash, 16); + out = data_blob_talloc_zero(mem_ctx, 16); + + sess_crypt_blob(&out, &in, session_key, false); + + if (!pdb_set_nt_passwd(pwd, out.data, PDB_CHANGED)) { + return NT_STATUS_ACCESS_DENIED; + } + + pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); + } + + if (id18->lm_pwd_active) { + + DATA_BLOB in, out; + + in = data_blob_const(id18->lm_pwd.hash, 16); + out = data_blob_talloc_zero(mem_ctx, 16); + + sess_crypt_blob(&out, &in, session_key, false); + + if (!pdb_set_lanman_passwd(pwd, out.data, PDB_CHANGED)) { + return NT_STATUS_ACCESS_DENIED; + } + + pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); + } + + copy_id18_to_sam_passwd(pwd, id18); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_20 + ********************************************************************/ + +static NTSTATUS set_user_info_20(TALLOC_CTX *mem_ctx, + struct samr_UserInfo20 *id20, + struct samu *pwd) +{ + if (id20 == NULL) { + DEBUG(5,("set_user_info_20: NULL id20\n")); + return NT_STATUS_ACCESS_DENIED; + } + + copy_id20_to_sam_passwd(pwd, id20); + + return pdb_update_sam_account(pwd); +} + +/******************************************************************* + set_user_info_21 + ********************************************************************/ + +static NTSTATUS set_user_info_21(struct samr_UserInfo21 *id21, + TALLOC_CTX *mem_ctx, + DATA_BLOB *session_key, + struct samu *pwd) +{ + NTSTATUS status; + + if (id21 == NULL) { + DEBUG(5, ("set_user_info_21: NULL id21\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (id21->fields_present == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (id21->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { + return NT_STATUS_ACCESS_DENIED; + } + + if (id21->fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) { + if (id21->nt_password_set) { + DATA_BLOB in, out; + + if ((id21->nt_owf_password.length != 16) || + (id21->nt_owf_password.size != 16)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!session_key->length) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + in = data_blob_const(id21->nt_owf_password.array, 16); + out = data_blob_talloc_zero(mem_ctx, 16); + + sess_crypt_blob(&out, &in, session_key, false); + + pdb_set_nt_passwd(pwd, out.data, PDB_CHANGED); + pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); + } + } + + if (id21->fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) { + if (id21->lm_password_set) { + DATA_BLOB in, out; + + if ((id21->lm_owf_password.length != 16) || + (id21->lm_owf_password.size != 16)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!session_key->length) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + in = data_blob_const(id21->lm_owf_password.array, 16); + out = data_blob_talloc_zero(mem_ctx, 16); + + sess_crypt_blob(&out, &in, session_key, false); + + pdb_set_lanman_passwd(pwd, out.data, PDB_CHANGED); + pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); + } + } + + /* we need to separately check for an account rename first */ + + if (id21->account_name.string && + (!strequal(id21->account_name.string, pdb_get_username(pwd)))) + { + + /* check to see if the new username already exists. Note: we can't + reliably lock all backends, so there is potentially the + possibility that a user can be created in between this check and + the rename. The rename should fail, but may not get the + exact same failure status code. I think this is small enough + of a window for this type of operation and the results are + simply that the rename fails with a slightly different status + code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */ + + status = can_create(mem_ctx, id21->account_name.string); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = pdb_rename_sam_account(pwd, id21->account_name.string); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("set_user_info_21: failed to rename account: %s\n", + nt_errstr(status))); + return status; + } + + /* set the new username so that later + functions can work on the new account */ + pdb_set_username(pwd, id21->account_name.string, PDB_SET); + } + + copy_id21_to_sam_passwd("INFO_21", pwd, id21); + + /* + * The funny part about the previous two calls is + * that pwd still has the password hashes from the + * passdb entry. These have not been updated from + * id21. I don't know if they need to be set. --jerry + */ + + if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) { + status = pdb_set_unix_primary_group(mem_ctx, pwd); + if ( !NT_STATUS_IS_OK(status) ) { + return status; + } + } + + /* Don't worry about writing out the user account since the + primary group SID is generated solely from the user's Unix + primary group. */ + + /* write the change out */ + if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { + return status; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + set_user_info_23 + ********************************************************************/ + +static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, + struct samr_UserInfo23 *id23, + const char *rhost, + struct samu *pwd) +{ + char *plaintext_buf = NULL; + size_t len = 0; + uint32_t acct_ctrl; + NTSTATUS status; + + if (id23 == NULL) { + DEBUG(5, ("set_user_info_23: NULL id23\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (id23->info.fields_present == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (id23->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { + return NT_STATUS_ACCESS_DENIED; + } + + if ((id23->info.fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) || + (id23->info.fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT)) { + + DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n", + pdb_get_username(pwd))); + + if (!decode_pw_buffer(mem_ctx, + id23->password.data, + &plaintext_buf, + &len, + CH_UTF16)) { + return NT_STATUS_WRONG_PASSWORD; + } + + if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { + return NT_STATUS_ACCESS_DENIED; + } + } + + copy_id23_to_sam_passwd(pwd, id23); + + acct_ctrl = pdb_get_acct_ctrl(pwd); + + /* if it's a trust account, don't update /etc/passwd */ + if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) || + ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) || + ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) { + DEBUG(5, ("Changing trust account. Not updating /etc/passwd\n")); + } else if (plaintext_buf) { + /* update the UNIX password */ + if (lp_unix_password_sync() ) { + struct passwd *passwd; + if (pdb_get_username(pwd) == NULL) { + DEBUG(1, ("chgpasswd: User without name???\n")); + return NT_STATUS_ACCESS_DENIED; + } + + passwd = Get_Pwnam_alloc(pwd, pdb_get_username(pwd)); + if (passwd == NULL) { + DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); + } + + if(!chgpasswd(pdb_get_username(pwd), rhost, + passwd, "", plaintext_buf, True)) { + return NT_STATUS_ACCESS_DENIED; + } + TALLOC_FREE(passwd); + } + } + + if (plaintext_buf) { + memset(plaintext_buf, '\0', strlen(plaintext_buf)); + } + + if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) && + (!NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx, + pwd)))) { + return status; + } + + if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { + return status; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + set_user_info_pw + ********************************************************************/ + +static bool set_user_info_pw(uint8 *pass, const char *rhost, struct samu *pwd) +{ + size_t len = 0; + char *plaintext_buf = NULL; + uint32 acct_ctrl; + + DEBUG(5, ("Attempting administrator password change for user %s\n", + pdb_get_username(pwd))); + + acct_ctrl = pdb_get_acct_ctrl(pwd); + + if (!decode_pw_buffer(talloc_tos(), + pass, + &plaintext_buf, + &len, + CH_UTF16)) { + return False; + } + + if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { + return False; + } + + /* if it's a trust account, don't update /etc/passwd */ + if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) || + ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) || + ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) { + DEBUG(5, ("Changing trust account or non-unix-user password, not updating /etc/passwd\n")); + } else { + /* update the UNIX password */ + if (lp_unix_password_sync()) { + struct passwd *passwd; + + if (pdb_get_username(pwd) == NULL) { + DEBUG(1, ("chgpasswd: User without name???\n")); + return False; + } + + passwd = Get_Pwnam_alloc(pwd, pdb_get_username(pwd)); + if (passwd == NULL) { + DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); + } + + if(!chgpasswd(pdb_get_username(pwd), rhost, passwd, + "", plaintext_buf, True)) { + return False; + } + TALLOC_FREE(passwd); + } + } + + memset(plaintext_buf, '\0', strlen(plaintext_buf)); + + DEBUG(5,("set_user_info_pw: pdb_update_pwd()\n")); + + return True; +} + +/******************************************************************* + set_user_info_24 + ********************************************************************/ + +static NTSTATUS set_user_info_24(TALLOC_CTX *mem_ctx, + const char *rhost, + struct samr_UserInfo24 *id24, + struct samu *pwd) +{ + NTSTATUS status; + + if (id24 == NULL) { + DEBUG(5, ("set_user_info_24: NULL id24\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (!set_user_info_pw(id24->password.data, rhost, pwd)) { + return NT_STATUS_WRONG_PASSWORD; + } + + copy_id24_to_sam_passwd(pwd, id24); + + status = pdb_update_sam_account(pwd); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +/******************************************************************* + set_user_info_25 + ********************************************************************/ + +static NTSTATUS set_user_info_25(TALLOC_CTX *mem_ctx, + const char *rhost, + struct samr_UserInfo25 *id25, + struct samu *pwd) +{ + NTSTATUS status; + + if (id25 == NULL) { + DEBUG(5, ("set_user_info_25: NULL id25\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (id25->info.fields_present == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (id25->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { + return NT_STATUS_ACCESS_DENIED; + } + + if ((id25->info.fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) || + (id25->info.fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT)) { + + if (!set_user_info_pw(id25->password.data, rhost, pwd)) { + return NT_STATUS_WRONG_PASSWORD; + } + } + + copy_id25_to_sam_passwd(pwd, id25); + + /* write the change out */ + if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { + return status; + } + + /* + * We need to "pdb_update_sam_account" before the unix primary group + * is set, because the idealx scripts would also change the + * sambaPrimaryGroupSid using the ldap replace method. pdb_ldap uses + * the delete explicit / add explicit, which would then fail to find + * the previous primaryGroupSid value. + */ + + if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) { + status = pdb_set_unix_primary_group(mem_ctx, pwd); + if ( !NT_STATUS_IS_OK(status) ) { + return status; + } + } + + return NT_STATUS_OK; +} + +/******************************************************************* + set_user_info_26 + ********************************************************************/ + +static NTSTATUS set_user_info_26(TALLOC_CTX *mem_ctx, + const char *rhost, + struct samr_UserInfo26 *id26, + struct samu *pwd) +{ + NTSTATUS status; + + if (id26 == NULL) { + DEBUG(5, ("set_user_info_26: NULL id26\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (!set_user_info_pw(id26->password.data, rhost, pwd)) { + return NT_STATUS_WRONG_PASSWORD; + } + + copy_id26_to_sam_passwd(pwd, id26); + + status = pdb_update_sam_account(pwd); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +/************************************************************* +**************************************************************/ + +static uint32_t samr_set_user_info_map_fields_to_access_mask(uint32_t fields) +{ + uint32_t acc_required = 0; + + /* USER_ALL_USERNAME */ + if (fields & SAMR_FIELD_ACCOUNT_NAME) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_FULLNAME */ + if (fields & SAMR_FIELD_FULL_NAME) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_PRIMARYGROUPID */ + if (fields & SAMR_FIELD_PRIMARY_GID) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_HOMEDIRECTORY */ + if (fields & SAMR_FIELD_HOME_DIRECTORY) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_HOMEDIRECTORYDRIVE */ + if (fields & SAMR_FIELD_HOME_DRIVE) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_SCRIPTPATH */ + if (fields & SAMR_FIELD_LOGON_SCRIPT) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_PROFILEPATH */ + if (fields & SAMR_FIELD_PROFILE_PATH) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_ADMINCOMMENT */ + if (fields & SAMR_FIELD_COMMENT) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_WORKSTATIONS */ + if (fields & SAMR_FIELD_WORKSTATIONS) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_LOGONHOURS */ + if (fields & SAMR_FIELD_LOGON_HOURS) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_ACCOUNTEXPIRES */ + if (fields & SAMR_FIELD_ACCT_EXPIRY) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_USERACCOUNTCONTROL */ + if (fields & SAMR_FIELD_ACCT_FLAGS) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_PARAMETERS */ + if (fields & SAMR_FIELD_PARAMETERS) + acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; + /* USER_ALL_USERCOMMENT */ + if (fields & SAMR_FIELD_COMMENT) + acc_required |= SAMR_USER_ACCESS_SET_LOC_COM; + /* USER_ALL_COUNTRYCODE */ + if (fields & SAMR_FIELD_COUNTRY_CODE) + acc_required |= SAMR_USER_ACCESS_SET_LOC_COM; + /* USER_ALL_CODEPAGE */ + if (fields & SAMR_FIELD_CODE_PAGE) + acc_required |= SAMR_USER_ACCESS_SET_LOC_COM; + /* USER_ALL_NTPASSWORDPRESENT */ + if (fields & SAMR_FIELD_NT_PASSWORD_PRESENT) + acc_required |= SAMR_USER_ACCESS_SET_PASSWORD; + /* USER_ALL_LMPASSWORDPRESENT */ + if (fields & SAMR_FIELD_LM_PASSWORD_PRESENT) + acc_required |= SAMR_USER_ACCESS_SET_PASSWORD; + /* USER_ALL_PASSWORDEXPIRED */ + if (fields & SAMR_FIELD_EXPIRED_FLAG) + acc_required |= SAMR_USER_ACCESS_SET_PASSWORD; + + return acc_required; +} + +/******************************************************************* + samr_SetUserInfo + ********************************************************************/ + +NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, + struct samr_SetUserInfo *r) +{ + struct samr_user_info *uinfo; + NTSTATUS status; + struct samu *pwd = NULL; + union samr_UserInfo *info = r->in.info; + uint32_t acc_required = 0; + uint32_t fields = 0; + bool ret; + + DEBUG(5,("_samr_SetUserInfo: %d\n", __LINE__)); + + /* This is tricky. A WinXP domain join sets + (SAMR_USER_ACCESS_SET_PASSWORD|SAMR_USER_ACCESS_SET_ATTRIBUTES|SAMR_USER_ACCESS_GET_ATTRIBUTES) + The MMC lusrmgr plugin includes these perms and more in the SamrOpenUser(). But the + standard Win32 API calls just ask for SAMR_USER_ACCESS_SET_PASSWORD in the SamrOpenUser(). + This should be enough for levels 18, 24, 25,& 26. Info level 23 can set more so + we'll use the set from the WinXP join as the basis. */ + + switch (r->in.level) { + case 2: /* UserPreferencesInformation */ + /* USER_WRITE_ACCOUNT | USER_WRITE_PREFERENCES */ + acc_required = SAMR_USER_ACCESS_SET_ATTRIBUTES | SAMR_USER_ACCESS_SET_LOC_COM; + break; + case 4: /* UserLogonHoursInformation */ + case 6: /* UserNameInformation */ + case 7: /* UserAccountNameInformation */ + case 8: /* UserFullNameInformation */ + case 9: /* UserPrimaryGroupInformation */ + case 10: /* UserHomeInformation */ + case 11: /* UserScriptInformation */ + case 12: /* UserProfileInformation */ + case 13: /* UserAdminCommentInformation */ + case 14: /* UserWorkStationsInformation */ + case 16: /* UserControlInformation */ + case 17: /* UserExpiresInformation */ + case 20: /* UserParametersInformation */ + /* USER_WRITE_ACCOUNT */ + acc_required = SAMR_USER_ACCESS_SET_ATTRIBUTES; + break; + case 18: /* UserInternal1Information */ + /* FIXME: gd, this is a guess */ + acc_required = SAMR_USER_ACCESS_SET_PASSWORD; + break; + case 21: /* UserAllInformation */ + fields = info->info21.fields_present; + acc_required = samr_set_user_info_map_fields_to_access_mask(fields); + break; + case 23: /* UserInternal4Information */ + fields = info->info23.info.fields_present; + acc_required = samr_set_user_info_map_fields_to_access_mask(fields); + break; + case 25: /* UserInternal4InformationNew */ + fields = info->info25.info.fields_present; + acc_required = samr_set_user_info_map_fields_to_access_mask(fields); + break; + case 24: /* UserInternal5Information */ + case 26: /* UserInternal5InformationNew */ + acc_required = SAMR_USER_ACCESS_SET_PASSWORD; + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + uinfo = policy_handle_find(p, r->in.user_handle, acc_required, NULL, + struct samr_user_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(5, ("_samr_SetUserInfo: sid:%s, level:%d\n", + sid_string_dbg(&uinfo->sid), r->in.level)); + + if (info == NULL) { + DEBUG(5, ("_samr_SetUserInfo: NULL info level\n")); + return NT_STATUS_INVALID_INFO_CLASS; + } + + if (!(pwd = samu_new(NULL))) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + ret = pdb_getsampwsid(pwd, &uinfo->sid); + unbecome_root(); + + if (!ret) { + TALLOC_FREE(pwd); + return NT_STATUS_NO_SUCH_USER; + } + + /* ================ BEGIN Privilege BLOCK ================ */ + + become_root(); + + /* ok! user info levels (lots: see MSDEV help), off we go... */ + + switch (r->in.level) { + + case 2: + status = set_user_info_2(p->mem_ctx, + &info->info2, pwd); + break; + + case 4: + status = set_user_info_4(p->mem_ctx, + &info->info4, pwd); + break; + + case 6: + status = set_user_info_6(p->mem_ctx, + &info->info6, pwd); + break; + + case 7: + status = set_user_info_7(p->mem_ctx, + &info->info7, pwd); + break; + + case 8: + status = set_user_info_8(p->mem_ctx, + &info->info8, pwd); + break; + + case 10: + status = set_user_info_10(p->mem_ctx, + &info->info10, pwd); + break; + + case 11: + status = set_user_info_11(p->mem_ctx, + &info->info11, pwd); + break; + + case 12: + status = set_user_info_12(p->mem_ctx, + &info->info12, pwd); + break; + + case 13: + status = set_user_info_13(p->mem_ctx, + &info->info13, pwd); + break; + + case 14: + status = set_user_info_14(p->mem_ctx, + &info->info14, pwd); + break; + + case 16: + status = set_user_info_16(p->mem_ctx, + &info->info16, pwd); + break; + + case 17: + status = set_user_info_17(p->mem_ctx, + &info->info17, pwd); + break; + + case 18: + /* Used by AS/U JRA. */ + status = set_user_info_18(&info->info18, + p->mem_ctx, + &p->server_info->user_session_key, + pwd); + break; + + case 20: + status = set_user_info_20(p->mem_ctx, + &info->info20, pwd); + break; + + case 21: + status = set_user_info_21(&info->info21, + p->mem_ctx, + &p->server_info->user_session_key, + pwd); + break; + + case 23: + if (!p->server_info->user_session_key.length) { + status = NT_STATUS_NO_USER_SESSION_KEY; + } + arcfour_crypt_blob(info->info23.password.data, 516, + &p->server_info->user_session_key); + + dump_data(100, info->info23.password.data, 516); + + status = set_user_info_23(p->mem_ctx, + &info->info23, + p->client_id->name, + pwd); + break; + + case 24: + if (!p->server_info->user_session_key.length) { + status = NT_STATUS_NO_USER_SESSION_KEY; + } + arcfour_crypt_blob(info->info24.password.data, + 516, + &p->server_info->user_session_key); + + dump_data(100, info->info24.password.data, 516); + + status = set_user_info_24(p->mem_ctx, + p->client_id->name, + &info->info24, pwd); + break; + + case 25: + if (!p->server_info->user_session_key.length) { + status = NT_STATUS_NO_USER_SESSION_KEY; + } + encode_or_decode_arc4_passwd_buffer( + info->info25.password.data, + &p->server_info->user_session_key); + + dump_data(100, info->info25.password.data, 532); + + status = set_user_info_25(p->mem_ctx, + p->client_id->name, + &info->info25, pwd); + break; + + case 26: + if (!p->server_info->user_session_key.length) { + status = NT_STATUS_NO_USER_SESSION_KEY; + } + encode_or_decode_arc4_passwd_buffer( + info->info26.password.data, + &p->server_info->user_session_key); + + dump_data(100, info->info26.password.data, 516); + + status = set_user_info_26(p->mem_ctx, + p->client_id->name, + &info->info26, pwd); + break; + + default: + status = NT_STATUS_INVALID_INFO_CLASS; + } + + TALLOC_FREE(pwd); + + unbecome_root(); + + /* ================ END Privilege BLOCK ================ */ + + if (NT_STATUS_IS_OK(status)) { + force_flush_samr_cache(&uinfo->sid); + } + + return status; +} + +/******************************************************************* + _samr_SetUserInfo2 + ********************************************************************/ + +NTSTATUS _samr_SetUserInfo2(struct pipes_struct *p, + struct samr_SetUserInfo2 *r) +{ + struct samr_SetUserInfo q; + + q.in.user_handle = r->in.user_handle; + q.in.level = r->in.level; + q.in.info = r->in.info; + + return _samr_SetUserInfo(p, &q); +} + +/********************************************************************* + _samr_GetAliasMembership +*********************************************************************/ + +NTSTATUS _samr_GetAliasMembership(struct pipes_struct *p, + struct samr_GetAliasMembership *r) +{ + size_t num_alias_rids; + uint32 *alias_rids; + struct samr_domain_info *dinfo; + size_t i; + + NTSTATUS status; + + struct dom_sid *members; + + DEBUG(5,("_samr_GetAliasMembership: %d\n", __LINE__)); + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS + | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sid_check_is_domain(&dinfo->sid) && + !sid_check_is_builtin(&dinfo->sid)) + return NT_STATUS_OBJECT_TYPE_MISMATCH; + + if (r->in.sids->num_sids) { + members = TALLOC_ARRAY(p->mem_ctx, struct dom_sid, r->in.sids->num_sids); + + if (members == NULL) + return NT_STATUS_NO_MEMORY; + } else { + members = NULL; + } + + for (i=0; iin.sids->num_sids; i++) + sid_copy(&members[i], r->in.sids->sids[i].sid); + + alias_rids = NULL; + num_alias_rids = 0; + + become_root(); + status = pdb_enum_alias_memberships(p->mem_ctx, &dinfo->sid, members, + r->in.sids->num_sids, + &alias_rids, &num_alias_rids); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + r->out.rids->count = num_alias_rids; + r->out.rids->ids = alias_rids; + + if (r->out.rids->ids == NULL) { + /* Windows domain clients don't accept a NULL ptr here */ + r->out.rids->ids = talloc_zero(p->mem_ctx, uint32_t); + } + if (r->out.rids->ids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_GetMembersInAlias +*********************************************************************/ + +NTSTATUS _samr_GetMembersInAlias(struct pipes_struct *p, + struct samr_GetMembersInAlias *r) +{ + struct samr_alias_info *ainfo; + NTSTATUS status; + size_t i; + size_t num_sids = 0; + struct lsa_SidPtr *sids = NULL; + struct dom_sid *pdb_sids = NULL; + + ainfo = policy_handle_find(p, r->in.alias_handle, + SAMR_ALIAS_ACCESS_GET_MEMBERS, NULL, + struct samr_alias_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10, ("sid is %s\n", sid_string_dbg(&ainfo->sid))); + + become_root(); + status = pdb_enum_aliasmem(&ainfo->sid, talloc_tos(), &pdb_sids, + &num_sids); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (num_sids) { + sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr, num_sids); + if (sids == NULL) { + TALLOC_FREE(pdb_sids); + return NT_STATUS_NO_MEMORY; + } + } + + for (i = 0; i < num_sids; i++) { + sids[i].sid = dom_sid_dup(p->mem_ctx, &pdb_sids[i]); + if (!sids[i].sid) { + TALLOC_FREE(pdb_sids); + return NT_STATUS_NO_MEMORY; + } + } + + r->out.sids->num_sids = num_sids; + r->out.sids->sids = sids; + + TALLOC_FREE(pdb_sids); + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_QueryGroupMember +*********************************************************************/ + +NTSTATUS _samr_QueryGroupMember(struct pipes_struct *p, + struct samr_QueryGroupMember *r) +{ + struct samr_group_info *ginfo; + size_t i, num_members; + + uint32 *rid=NULL; + uint32 *attr=NULL; + + NTSTATUS status; + struct samr_RidAttrArray *rids = NULL; + + ginfo = policy_handle_find(p, r->in.group_handle, + SAMR_GROUP_ACCESS_GET_MEMBERS, NULL, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + rids = TALLOC_ZERO_P(p->mem_ctx, struct samr_RidAttrArray); + if (!rids) { + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10, ("sid is %s\n", sid_string_dbg(&ginfo->sid))); + + if (!sid_check_is_in_our_domain(&ginfo->sid)) { + DEBUG(3, ("sid %s is not in our domain\n", + sid_string_dbg(&ginfo->sid))); + return NT_STATUS_NO_SUCH_GROUP; + } + + DEBUG(10, ("lookup on Domain SID\n")); + + become_root(); + status = pdb_enum_group_members(p->mem_ctx, &ginfo->sid, + &rid, &num_members); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) + return status; + + if (num_members) { + attr=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_members); + if (attr == NULL) { + return NT_STATUS_NO_MEMORY; + } + } else { + attr = NULL; + } + + for (i=0; icount = num_members; + rids->attributes = attr; + rids->rids = rid; + + *r->out.rids = rids; + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_AddAliasMember +*********************************************************************/ + +NTSTATUS _samr_AddAliasMember(struct pipes_struct *p, + struct samr_AddAliasMember *r) +{ + struct samr_alias_info *ainfo; + NTSTATUS status; + + ainfo = policy_handle_find(p, r->in.alias_handle, + SAMR_ALIAS_ACCESS_ADD_MEMBER, NULL, + struct samr_alias_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10, ("sid is %s\n", sid_string_dbg(&ainfo->sid))); + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_add_aliasmem(&ainfo->sid, r->in.sid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + if (NT_STATUS_IS_OK(status)) { + force_flush_samr_cache(&ainfo->sid); + } + + return status; +} + +/********************************************************************* + _samr_DeleteAliasMember +*********************************************************************/ + +NTSTATUS _samr_DeleteAliasMember(struct pipes_struct *p, + struct samr_DeleteAliasMember *r) +{ + struct samr_alias_info *ainfo; + NTSTATUS status; + + ainfo = policy_handle_find(p, r->in.alias_handle, + SAMR_ALIAS_ACCESS_REMOVE_MEMBER, NULL, + struct samr_alias_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10, ("_samr_del_aliasmem:sid is %s\n", + sid_string_dbg(&ainfo->sid))); + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_del_aliasmem(&ainfo->sid, r->in.sid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + if (NT_STATUS_IS_OK(status)) { + force_flush_samr_cache(&ainfo->sid); + } + + return status; +} + +/********************************************************************* + _samr_AddGroupMember +*********************************************************************/ + +NTSTATUS _samr_AddGroupMember(struct pipes_struct *p, + struct samr_AddGroupMember *r) +{ + struct samr_group_info *ginfo; + NTSTATUS status; + uint32 group_rid; + + ginfo = policy_handle_find(p, r->in.group_handle, + SAMR_GROUP_ACCESS_ADD_MEMBER, NULL, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10, ("sid is %s\n", sid_string_dbg(&ginfo->sid))); + + if (!sid_peek_check_rid(get_global_sam_sid(), &ginfo->sid, + &group_rid)) { + return NT_STATUS_INVALID_HANDLE; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_add_groupmem(p->mem_ctx, group_rid, r->in.rid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + force_flush_samr_cache(&ginfo->sid); + + return status; +} + +/********************************************************************* + _samr_DeleteGroupMember +*********************************************************************/ + +NTSTATUS _samr_DeleteGroupMember(struct pipes_struct *p, + struct samr_DeleteGroupMember *r) + +{ + struct samr_group_info *ginfo; + NTSTATUS status; + uint32 group_rid; + + /* + * delete the group member named r->in.rid + * who is a member of the sid associated with the handle + * the rid is a user's rid as the group is a domain group. + */ + + ginfo = policy_handle_find(p, r->in.group_handle, + SAMR_GROUP_ACCESS_REMOVE_MEMBER, NULL, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sid_peek_check_rid(get_global_sam_sid(), &ginfo->sid, + &group_rid)) { + return NT_STATUS_INVALID_HANDLE; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_del_groupmem(p->mem_ctx, group_rid, r->in.rid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + force_flush_samr_cache(&ginfo->sid); + + return status; +} + +/********************************************************************* + _samr_DeleteUser +*********************************************************************/ + +NTSTATUS _samr_DeleteUser(struct pipes_struct *p, + struct samr_DeleteUser *r) +{ + struct samr_user_info *uinfo; + NTSTATUS status; + struct samu *sam_pass=NULL; + bool ret; + + DEBUG(5, ("_samr_DeleteUser: %d\n", __LINE__)); + + uinfo = policy_handle_find(p, r->in.user_handle, + SEC_STD_DELETE, NULL, + struct samr_user_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sid_check_is_in_our_domain(&uinfo->sid)) + return NT_STATUS_CANNOT_DELETE; + + /* check if the user exists before trying to delete */ + if ( !(sam_pass = samu_new( NULL )) ) { + return NT_STATUS_NO_MEMORY; + } + + become_root(); + ret = pdb_getsampwsid(sam_pass, &uinfo->sid); + unbecome_root(); + + if(!ret) { + DEBUG(5,("_samr_DeleteUser: User %s doesn't exist.\n", + sid_string_dbg(&uinfo->sid))); + TALLOC_FREE(sam_pass); + return NT_STATUS_NO_SUCH_USER; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_delete_user(p->mem_ctx, sam_pass); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(5,("_samr_DeleteUser: Failed to delete entry for " + "user %s: %s.\n", pdb_get_username(sam_pass), + nt_errstr(status))); + TALLOC_FREE(sam_pass); + return status; + } + + + TALLOC_FREE(sam_pass); + + force_flush_samr_cache(&uinfo->sid); + + if (!close_policy_hnd(p, r->in.user_handle)) + return NT_STATUS_OBJECT_NAME_INVALID; + + ZERO_STRUCTP(r->out.user_handle); + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_DeleteDomainGroup +*********************************************************************/ + +NTSTATUS _samr_DeleteDomainGroup(struct pipes_struct *p, + struct samr_DeleteDomainGroup *r) +{ + struct samr_group_info *ginfo; + NTSTATUS status; + uint32 group_rid; + + DEBUG(5, ("samr_DeleteDomainGroup: %d\n", __LINE__)); + + ginfo = policy_handle_find(p, r->in.group_handle, + SEC_STD_DELETE, NULL, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10, ("sid is %s\n", sid_string_dbg(&ginfo->sid))); + + if (!sid_peek_check_rid(get_global_sam_sid(), &ginfo->sid, + &group_rid)) { + return NT_STATUS_NO_SUCH_GROUP; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_delete_dom_group(p->mem_ctx, group_rid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + if ( !NT_STATUS_IS_OK(status) ) { + DEBUG(5,("_samr_DeleteDomainGroup: Failed to delete mapping " + "entry for group %s: %s\n", + sid_string_dbg(&ginfo->sid), + nt_errstr(status))); + return status; + } + + force_flush_samr_cache(&ginfo->sid); + + if (!close_policy_hnd(p, r->in.group_handle)) + return NT_STATUS_OBJECT_NAME_INVALID; + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_DeleteDomAlias +*********************************************************************/ + +NTSTATUS _samr_DeleteDomAlias(struct pipes_struct *p, + struct samr_DeleteDomAlias *r) +{ + struct samr_alias_info *ainfo; + NTSTATUS status; + + DEBUG(5, ("_samr_DeleteDomAlias: %d\n", __LINE__)); + + ainfo = policy_handle_find(p, r->in.alias_handle, + SEC_STD_DELETE, NULL, + struct samr_alias_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(10, ("sid is %s\n", sid_string_dbg(&ainfo->sid))); + + /* Don't let Windows delete builtin groups */ + + if ( sid_check_is_in_builtin( &ainfo->sid ) ) { + return NT_STATUS_SPECIAL_ACCOUNT; + } + + if (!sid_check_is_in_our_domain(&ainfo->sid)) + return NT_STATUS_NO_SUCH_ALIAS; + + DEBUG(10, ("lookup on Local SID\n")); + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + /* Have passdb delete the alias */ + status = pdb_delete_alias(&ainfo->sid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + if ( !NT_STATUS_IS_OK(status)) + return status; + + force_flush_samr_cache(&ainfo->sid); + + if (!close_policy_hnd(p, r->in.alias_handle)) + return NT_STATUS_OBJECT_NAME_INVALID; + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_CreateDomainGroup +*********************************************************************/ + +NTSTATUS _samr_CreateDomainGroup(struct pipes_struct *p, + struct samr_CreateDomainGroup *r) + +{ + NTSTATUS status; + const char *name; + struct samr_domain_info *dinfo; + struct samr_group_info *ginfo; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_CREATE_GROUP, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sid_check_is_domain(&dinfo->sid)) { + return NT_STATUS_ACCESS_DENIED; + } + + name = r->in.name->string; + if (name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = can_create(p->mem_ctx, name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + /* check that we successfully create the UNIX group */ + status = pdb_create_dom_group(p->mem_ctx, name, r->out.rid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + /* check if we should bail out here */ + + if ( !NT_STATUS_IS_OK(status) ) + return status; + + ginfo = policy_handle_create(p, r->out.group_handle, + GENERIC_RIGHTS_GROUP_ALL_ACCESS, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + sid_compose(&ginfo->sid, &dinfo->sid, *r->out.rid); + + force_flush_samr_cache(&dinfo->sid); + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_CreateDomAlias +*********************************************************************/ + +NTSTATUS _samr_CreateDomAlias(struct pipes_struct *p, + struct samr_CreateDomAlias *r) +{ + struct dom_sid info_sid; + const char *name = NULL; + struct samr_domain_info *dinfo; + struct samr_alias_info *ainfo; + gid_t gid; + NTSTATUS result; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_CREATE_ALIAS, NULL, + struct samr_domain_info, &result); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + if (!sid_check_is_domain(&dinfo->sid)) { + return NT_STATUS_ACCESS_DENIED; + } + + name = r->in.alias_name->string; + + result = can_create(p->mem_ctx, name); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + /* Have passdb create the alias */ + result = pdb_create_alias(name, r->out.rid); + unbecome_root(); + + /******** END SeAddUsers BLOCK *********/ + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(10, ("pdb_create_alias failed: %s\n", + nt_errstr(result))); + return result; + } + + sid_compose(&info_sid, &dinfo->sid, *r->out.rid); + + if (!sid_to_gid(&info_sid, &gid)) { + DEBUG(10, ("Could not find alias just created\n")); + return NT_STATUS_ACCESS_DENIED; + } + + /* check if the group has been successfully created */ + if ( getgrgid(gid) == NULL ) { + DEBUG(10, ("getgrgid(%u) of just created alias failed\n", + (unsigned int)gid)); + return NT_STATUS_ACCESS_DENIED; + } + + ainfo = policy_handle_create(p, r->out.alias_handle, + GENERIC_RIGHTS_ALIAS_ALL_ACCESS, + struct samr_alias_info, &result); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + ainfo->sid = info_sid; + + force_flush_samr_cache(&info_sid); + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_QueryGroupInfo +*********************************************************************/ + +NTSTATUS _samr_QueryGroupInfo(struct pipes_struct *p, + struct samr_QueryGroupInfo *r) +{ + struct samr_group_info *ginfo; + NTSTATUS status; + GROUP_MAP map; + union samr_GroupInfo *info = NULL; + bool ret; + uint32_t attributes = SE_GROUP_MANDATORY | + SE_GROUP_ENABLED_BY_DEFAULT | + SE_GROUP_ENABLED; + const char *group_name = NULL; + const char *group_description = NULL; + + ginfo = policy_handle_find(p, r->in.group_handle, + SAMR_GROUP_ACCESS_LOOKUP_INFO, NULL, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + become_root(); + ret = get_domain_group_from_sid(ginfo->sid, &map); + unbecome_root(); + if (!ret) + return NT_STATUS_INVALID_HANDLE; + + /* FIXME: map contains fstrings */ + group_name = talloc_strdup(r, map.nt_name); + group_description = talloc_strdup(r, map.comment); + + info = TALLOC_ZERO_P(p->mem_ctx, union samr_GroupInfo); + if (!info) { + return NT_STATUS_NO_MEMORY; + } + + switch (r->in.level) { + case 1: { + uint32 *members; + size_t num_members; + + become_root(); + status = pdb_enum_group_members( + p->mem_ctx, &ginfo->sid, &members, + &num_members); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + info->all.name.string = group_name; + info->all.attributes = attributes; + info->all.num_members = num_members; + info->all.description.string = group_description; + break; + } + case 2: + info->name.string = group_name; + break; + case 3: + info->attributes.attributes = attributes; + break; + case 4: + info->description.string = group_description; + break; + case 5: { + /* + uint32 *members; + size_t num_members; + */ + + /* + become_root(); + status = pdb_enum_group_members( + p->mem_ctx, &ginfo->sid, &members, + &num_members); + unbecome_root(); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + */ + info->all2.name.string = group_name; + info->all2.attributes = attributes; + info->all2.num_members = 0; /* num_members - in w2k3 this is always 0 */ + info->all2.description.string = group_description; + + break; + } + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + *r->out.info = info; + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_SetGroupInfo +*********************************************************************/ + +NTSTATUS _samr_SetGroupInfo(struct pipes_struct *p, + struct samr_SetGroupInfo *r) +{ + struct samr_group_info *ginfo; + GROUP_MAP map; + NTSTATUS status; + bool ret; + + ginfo = policy_handle_find(p, r->in.group_handle, + SAMR_GROUP_ACCESS_SET_INFO, NULL, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + become_root(); + ret = get_domain_group_from_sid(ginfo->sid, &map); + unbecome_root(); + if (!ret) + return NT_STATUS_NO_SUCH_GROUP; + + switch (r->in.level) { + case 2: + fstrcpy(map.nt_name, r->in.info->name.string); + break; + case 3: + break; + case 4: + fstrcpy(map.comment, r->in.info->description.string); + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_update_group_mapping_entry(&map); + unbecome_root(); + + /******** End SeAddUsers BLOCK *********/ + + if (NT_STATUS_IS_OK(status)) { + force_flush_samr_cache(&ginfo->sid); + } + + return status; +} + +/********************************************************************* + _samr_SetAliasInfo +*********************************************************************/ + +NTSTATUS _samr_SetAliasInfo(struct pipes_struct *p, + struct samr_SetAliasInfo *r) +{ + struct samr_alias_info *ainfo; + struct acct_info info; + NTSTATUS status; + + ainfo = policy_handle_find(p, r->in.alias_handle, + SAMR_ALIAS_ACCESS_SET_INFO, NULL, + struct samr_alias_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* get the current group information */ + + become_root(); + status = pdb_get_aliasinfo( &ainfo->sid, &info ); + unbecome_root(); + + if ( !NT_STATUS_IS_OK(status)) + return status; + + switch (r->in.level) { + case ALIASINFONAME: + { + fstring group_name; + + /* We currently do not support renaming groups in the + the BUILTIN domain. Refer to util_builtin.c to understand + why. The eventually needs to be fixed to be like Windows + where you can rename builtin groups, just not delete them */ + + if ( sid_check_is_in_builtin( &ainfo->sid ) ) { + return NT_STATUS_SPECIAL_ACCOUNT; + } + + /* There has to be a valid name (and it has to be different) */ + + if ( !r->in.info->name.string ) + return NT_STATUS_INVALID_PARAMETER; + + /* If the name is the same just reply "ok". Yes this + doesn't allow you to change the case of a group name. */ + + if ( strequal( r->in.info->name.string, info.acct_name ) ) + return NT_STATUS_OK; + + fstrcpy( info.acct_name, r->in.info->name.string); + + /* make sure the name doesn't already exist as a user + or local group */ + + fstr_sprintf( group_name, "%s\\%s", global_myname(), info.acct_name ); + status = can_create( p->mem_ctx, group_name ); + if ( !NT_STATUS_IS_OK( status ) ) + return status; + break; + } + case ALIASINFODESCRIPTION: + if (r->in.info->description.string) { + fstrcpy(info.acct_desc, + r->in.info->description.string); + } else { + fstrcpy( info.acct_desc, "" ); + } + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + /******** BEGIN SeAddUsers BLOCK *********/ + + become_root(); + status = pdb_set_aliasinfo( &ainfo->sid, &info ); + unbecome_root(); + + /******** End SeAddUsers BLOCK *********/ + + if (NT_STATUS_IS_OK(status)) + force_flush_samr_cache(&ainfo->sid); + + return status; +} + +/**************************************************************** + _samr_GetDomPwInfo +****************************************************************/ + +NTSTATUS _samr_GetDomPwInfo(struct pipes_struct *p, + struct samr_GetDomPwInfo *r) +{ + uint32_t min_password_length = 0; + uint32_t password_properties = 0; + + /* Perform access check. Since this rpc does not require a + policy handle it will not be caught by the access checks on + SAMR_CONNECT or SAMR_CONNECT_ANON. */ + + if (!pipe_access_check(p)) { + DEBUG(3, ("access denied to _samr_GetDomPwInfo\n")); + return NT_STATUS_ACCESS_DENIED; + } + + become_root(); + pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, + &min_password_length); + pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, + &password_properties); + unbecome_root(); + + if (lp_check_password_script() && *lp_check_password_script()) { + password_properties |= DOMAIN_PASSWORD_COMPLEX; + } + + r->out.info->min_password_length = min_password_length; + r->out.info->password_properties = password_properties; + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_OpenGroup +*********************************************************************/ + +NTSTATUS _samr_OpenGroup(struct pipes_struct *p, + struct samr_OpenGroup *r) + +{ + struct dom_sid info_sid; + GROUP_MAP map; + struct samr_domain_info *dinfo; + struct samr_group_info *ginfo; + struct security_descriptor *psd = NULL; + uint32 acc_granted; + uint32 des_access = r->in.access_mask; + size_t sd_size; + NTSTATUS status; + bool ret; + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /*check if access can be granted as requested by client. */ + map_max_allowed_access(p->server_info->security_token, + &p->server_info->utok, + &des_access); + + make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &grp_generic_mapping, NULL, 0); + se_map_generic(&des_access,&grp_generic_mapping); + + status = access_check_object(psd, p->server_info->security_token, + SEC_PRIV_ADD_USERS, SEC_PRIV_INVALID, GENERIC_RIGHTS_GROUP_ALL_ACCESS, + des_access, &acc_granted, "_samr_OpenGroup"); + + if ( !NT_STATUS_IS_OK(status) ) + return status; + + /* this should not be hard-coded like this */ + + if (!sid_check_is_domain(&dinfo->sid)) { + return NT_STATUS_ACCESS_DENIED; + } + + sid_compose(&info_sid, &dinfo->sid, r->in.rid); + + DEBUG(10, ("_samr_OpenGroup:Opening SID: %s\n", + sid_string_dbg(&info_sid))); + + /* check if that group really exists */ + become_root(); + ret = get_domain_group_from_sid(info_sid, &map); + unbecome_root(); + if (!ret) + return NT_STATUS_NO_SUCH_GROUP; + + ginfo = policy_handle_create(p, r->out.group_handle, + acc_granted, + struct samr_group_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ginfo->sid = info_sid; + + return NT_STATUS_OK; +} + +/********************************************************************* + _samr_RemoveMemberFromForeignDomain +*********************************************************************/ + +NTSTATUS _samr_RemoveMemberFromForeignDomain(struct pipes_struct *p, + struct samr_RemoveMemberFromForeignDomain *r) +{ + struct samr_domain_info *dinfo; + NTSTATUS result; + + DEBUG(5,("_samr_RemoveMemberFromForeignDomain: removing SID [%s]\n", + sid_string_dbg(r->in.sid))); + + /* Find the policy handle. Open a policy on it. */ + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, + struct samr_domain_info, &result); + if (!NT_STATUS_IS_OK(result)) { + return result; + } + + DEBUG(8, ("_samr_RemoveMemberFromForeignDomain: sid is %s\n", + sid_string_dbg(&dinfo->sid))); + + /* we can only delete a user from a group since we don't have + nested groups anyways. So in the latter case, just say OK */ + + /* TODO: The above comment nowadays is bogus. Since we have nested + * groups now, and aliases members are never reported out of the unix + * group membership, the "just say OK" makes this call a no-op. For + * us. This needs fixing however. */ + + /* I've only ever seen this in the wild when deleting a user from + * usrmgr.exe. domain_sid is the builtin domain, and the sid to delete + * is the user about to be deleted. I very much suspect this is the + * only application of this call. To verify this, let people report + * other cases. */ + + if (!sid_check_is_builtin(&dinfo->sid)) { + DEBUG(1,("_samr_RemoveMemberFromForeignDomain: domain_sid = %s, " + "global_sam_sid() = %s\n", + sid_string_dbg(&dinfo->sid), + sid_string_dbg(get_global_sam_sid()))); + DEBUGADD(1,("please report to samba-technical@samba.org!\n")); + return NT_STATUS_OK; + } + + force_flush_samr_cache(&dinfo->sid); + + result = NT_STATUS_OK; + + return result; +} + +/******************************************************************* + _samr_QueryDomainInfo2 + ********************************************************************/ + +NTSTATUS _samr_QueryDomainInfo2(struct pipes_struct *p, + struct samr_QueryDomainInfo2 *r) +{ + struct samr_QueryDomainInfo q; + + q.in.domain_handle = r->in.domain_handle; + q.in.level = r->in.level; + + q.out.info = r->out.info; + + return _samr_QueryDomainInfo(p, &q); +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS set_dom_info_1(TALLOC_CTX *mem_ctx, + struct samr_DomInfo1 *r) +{ + time_t u_expire, u_min_age; + + u_expire = nt_time_to_unix_abs((NTTIME *)&r->max_password_age); + u_min_age = nt_time_to_unix_abs((NTTIME *)&r->min_password_age); + + pdb_set_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, + (uint32_t)r->min_password_length); + pdb_set_account_policy(PDB_POLICY_PASSWORD_HISTORY, + (uint32_t)r->password_history_length); + pdb_set_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, + (uint32_t)r->password_properties); + pdb_set_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, (int)u_expire); + pdb_set_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, (int)u_min_age); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS set_dom_info_3(TALLOC_CTX *mem_ctx, + struct samr_DomInfo3 *r) +{ + time_t u_logout; + + u_logout = nt_time_to_unix_abs((NTTIME *)&r->force_logoff_time); + + pdb_set_account_policy(PDB_POLICY_TIME_TO_LOGOUT, (int)u_logout); + + return NT_STATUS_OK; +} + +/******************************************************************* + ********************************************************************/ + +static NTSTATUS set_dom_info_12(TALLOC_CTX *mem_ctx, + struct samr_DomInfo12 *r) +{ + time_t u_lock_duration, u_reset_time; + + u_lock_duration = nt_time_to_unix_abs((NTTIME *)&r->lockout_duration); + if (u_lock_duration != -1) { + u_lock_duration /= 60; + } + + u_reset_time = nt_time_to_unix_abs((NTTIME *)&r->lockout_window)/60; + + pdb_set_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, (int)u_lock_duration); + pdb_set_account_policy(PDB_POLICY_RESET_COUNT_TIME, (int)u_reset_time); + pdb_set_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, + (uint32_t)r->lockout_threshold); + + return NT_STATUS_OK; +} + +/******************************************************************* + _samr_SetDomainInfo + ********************************************************************/ + +NTSTATUS _samr_SetDomainInfo(struct pipes_struct *p, + struct samr_SetDomainInfo *r) +{ + struct samr_domain_info *dinfo; + NTSTATUS status; + uint32_t acc_required = 0; + + DEBUG(5,("_samr_SetDomainInfo: %d\n", __LINE__)); + + switch (r->in.level) { + case 1: /* DomainPasswordInformation */ + case 12: /* DomainLockoutInformation */ + /* DOMAIN_WRITE_PASSWORD_PARAMETERS */ + acc_required = SAMR_DOMAIN_ACCESS_SET_INFO_1; + break; + case 3: /* DomainLogoffInformation */ + case 4: /* DomainOemInformation */ + /* DOMAIN_WRITE_OTHER_PARAMETERS */ + acc_required = SAMR_DOMAIN_ACCESS_SET_INFO_2; + break; + case 6: /* DomainReplicationInformation */ + case 9: /* DomainStateInformation */ + case 7: /* DomainServerRoleInformation */ + /* DOMAIN_ADMINISTER_SERVER */ + acc_required = SAMR_DOMAIN_ACCESS_SET_INFO_3; + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + dinfo = policy_handle_find(p, r->in.domain_handle, + acc_required, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(5,("_samr_SetDomainInfo: level: %d\n", r->in.level)); + + switch (r->in.level) { + case 1: + status = set_dom_info_1(p->mem_ctx, &r->in.info->info1); + break; + case 3: + status = set_dom_info_3(p->mem_ctx, &r->in.info->info3); + break; + case 4: + break; + case 6: + break; + case 7: + break; + case 9: + break; + case 12: + status = set_dom_info_12(p->mem_ctx, &r->in.info->info12); + break; + default: + return NT_STATUS_INVALID_INFO_CLASS; + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + DEBUG(5,("_samr_SetDomainInfo: %d\n", __LINE__)); + + return NT_STATUS_OK; +} + +/**************************************************************** + _samr_GetDisplayEnumerationIndex +****************************************************************/ + +NTSTATUS _samr_GetDisplayEnumerationIndex(struct pipes_struct *p, + struct samr_GetDisplayEnumerationIndex *r) +{ + struct samr_domain_info *dinfo; + uint32_t max_entries = (uint32_t) -1; + uint32_t enum_context = 0; + int i; + uint32_t num_account = 0; + struct samr_displayentry *entries = NULL; + NTSTATUS status; + + DEBUG(5,("_samr_GetDisplayEnumerationIndex: %d\n", __LINE__)); + + dinfo = policy_handle_find(p, r->in.domain_handle, + SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if ((r->in.level < 1) || (r->in.level > 3)) { + DEBUG(0,("_samr_GetDisplayEnumerationIndex: " + "Unknown info level (%u)\n", + r->in.level)); + return NT_STATUS_INVALID_INFO_CLASS; + } + + become_root(); + + /* The following done as ROOT. Don't return without unbecome_root(). */ + + switch (r->in.level) { + case 1: + if (dinfo->disp_info->users == NULL) { + dinfo->disp_info->users = pdb_search_users( + dinfo->disp_info, ACB_NORMAL); + if (dinfo->disp_info->users == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "starting user enumeration at index %u\n", + (unsigned int)enum_context)); + } else { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "using cached user enumeration at index %u\n", + (unsigned int)enum_context)); + } + num_account = pdb_search_entries(dinfo->disp_info->users, + enum_context, max_entries, + &entries); + break; + case 2: + if (dinfo->disp_info->machines == NULL) { + dinfo->disp_info->machines = pdb_search_users( + dinfo->disp_info, ACB_WSTRUST|ACB_SVRTRUST); + if (dinfo->disp_info->machines == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "starting machine enumeration at index %u\n", + (unsigned int)enum_context)); + } else { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "using cached machine enumeration at index %u\n", + (unsigned int)enum_context)); + } + num_account = pdb_search_entries(dinfo->disp_info->machines, + enum_context, max_entries, + &entries); + break; + case 3: + if (dinfo->disp_info->groups == NULL) { + dinfo->disp_info->groups = pdb_search_groups( + dinfo->disp_info); + if (dinfo->disp_info->groups == NULL) { + unbecome_root(); + return NT_STATUS_ACCESS_DENIED; + } + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "starting group enumeration at index %u\n", + (unsigned int)enum_context)); + } else { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "using cached group enumeration at index %u\n", + (unsigned int)enum_context)); + } + num_account = pdb_search_entries(dinfo->disp_info->groups, + enum_context, max_entries, + &entries); + break; + default: + unbecome_root(); + smb_panic("info class changed"); + break; + } + + unbecome_root(); + + /* Ensure we cache this enumeration. */ + set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); + + DEBUG(10,("_samr_GetDisplayEnumerationIndex: looking for :%s\n", + r->in.name->string)); + + for (i=0; iin.name->string)) { + DEBUG(10,("_samr_GetDisplayEnumerationIndex: " + "found %s at idx %d\n", + r->in.name->string, i)); + *r->out.idx = i; + return NT_STATUS_OK; + } + } + + /* assuming account_name lives at the very end */ + *r->out.idx = num_account; + + return NT_STATUS_NO_MORE_ENTRIES; +} + +/**************************************************************** + _samr_GetDisplayEnumerationIndex2 +****************************************************************/ + +NTSTATUS _samr_GetDisplayEnumerationIndex2(struct pipes_struct *p, + struct samr_GetDisplayEnumerationIndex2 *r) +{ + struct samr_GetDisplayEnumerationIndex q; + + q.in.domain_handle = r->in.domain_handle; + q.in.level = r->in.level; + q.in.name = r->in.name; + + q.out.idx = r->out.idx; + + return _samr_GetDisplayEnumerationIndex(p, &q); +} + +/**************************************************************** + _samr_RidToSid +****************************************************************/ + +NTSTATUS _samr_RidToSid(struct pipes_struct *p, + struct samr_RidToSid *r) +{ + struct samr_domain_info *dinfo; + NTSTATUS status; + struct dom_sid sid; + + dinfo = policy_handle_find(p, r->in.domain_handle, + 0, NULL, + struct samr_domain_info, &status); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (!sid_compose(&sid, &dinfo->sid, r->in.rid)) { + return NT_STATUS_NO_MEMORY; + } + + *r->out.sid = dom_sid_dup(p->mem_ctx, &sid); + if (!*r->out.sid) { + return NT_STATUS_NO_MEMORY; + } + + return NT_STATUS_OK; +} + +/**************************************************************** +****************************************************************/ + +static enum samr_ValidationStatus samr_ValidatePassword_Change(TALLOC_CTX *mem_ctx, + const struct samr_PwInfo *dom_pw_info, + const struct samr_ValidatePasswordReq2 *req, + struct samr_ValidatePasswordRepCtr *rep) +{ + NTSTATUS status; + + if (req->password.string == NULL) { + return SAMR_VALIDATION_STATUS_SUCCESS; + } + if (strlen(req->password.string) < dom_pw_info->min_password_length) { + ZERO_STRUCT(rep->info); + return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT; + } + if (dom_pw_info->password_properties & DOMAIN_PASSWORD_COMPLEX) { + status = check_password_complexity(req->account.string, + req->password.string, + NULL); + if (!NT_STATUS_IS_OK(status)) { + ZERO_STRUCT(rep->info); + return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; + } + } + + return SAMR_VALIDATION_STATUS_SUCCESS; +} + +/**************************************************************** +****************************************************************/ + +static enum samr_ValidationStatus samr_ValidatePassword_Reset(TALLOC_CTX *mem_ctx, + const struct samr_PwInfo *dom_pw_info, + const struct samr_ValidatePasswordReq3 *req, + struct samr_ValidatePasswordRepCtr *rep) +{ + NTSTATUS status; + + if (req->password.string == NULL) { + return SAMR_VALIDATION_STATUS_SUCCESS; + } + if (strlen(req->password.string) < dom_pw_info->min_password_length) { + ZERO_STRUCT(rep->info); + return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT; + } + if (dom_pw_info->password_properties & DOMAIN_PASSWORD_COMPLEX) { + status = check_password_complexity(req->account.string, + req->password.string, + NULL); + if (!NT_STATUS_IS_OK(status)) { + ZERO_STRUCT(rep->info); + return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; + } + } + + return SAMR_VALIDATION_STATUS_SUCCESS; +} + +/**************************************************************** + _samr_ValidatePassword +****************************************************************/ + +NTSTATUS _samr_ValidatePassword(struct pipes_struct *p, + struct samr_ValidatePassword *r) +{ + union samr_ValidatePasswordRep *rep; + NTSTATUS status; + struct samr_GetDomPwInfo pw; + struct samr_PwInfo dom_pw_info; + + if (r->in.level < 1 || r->in.level > 3) { + return NT_STATUS_INVALID_INFO_CLASS; + } + + pw.in.domain_name = NULL; + pw.out.info = &dom_pw_info; + + status = _samr_GetDomPwInfo(p, &pw); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + rep = talloc_zero(p->mem_ctx, union samr_ValidatePasswordRep); + if (!rep) { + return NT_STATUS_NO_MEMORY; + } + + switch (r->in.level) { + case 1: + status = NT_STATUS_NOT_SUPPORTED; + break; + case 2: + rep->ctr2.status = samr_ValidatePassword_Change(p->mem_ctx, + &dom_pw_info, + &r->in.req->req2, + &rep->ctr2); + break; + case 3: + rep->ctr3.status = samr_ValidatePassword_Reset(p->mem_ctx, + &dom_pw_info, + &r->in.req->req3, + &rep->ctr3); + break; + default: + status = NT_STATUS_INVALID_INFO_CLASS; + break; + } + + if (!NT_STATUS_IS_OK(status)) { + talloc_free(rep); + return status; + } + + *r->out.rep = rep; + + return NT_STATUS_OK; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_Shutdown(struct pipes_struct *p, + struct samr_Shutdown *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_SetMemberAttributesOfGroup(struct pipes_struct *p, + struct samr_SetMemberAttributesOfGroup *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_TestPrivateFunctionsDomain(struct pipes_struct *p, + struct samr_TestPrivateFunctionsDomain *r) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_TestPrivateFunctionsUser(struct pipes_struct *p, + struct samr_TestPrivateFunctionsUser *r) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_AddMultipleMembersToAlias(struct pipes_struct *p, + struct samr_AddMultipleMembersToAlias *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_RemoveMultipleMembersFromAlias(struct pipes_struct *p, + struct samr_RemoveMultipleMembersFromAlias *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_SetBootKeyInformation(struct pipes_struct *p, + struct samr_SetBootKeyInformation *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_GetBootKeyInformation(struct pipes_struct *p, + struct samr_GetBootKeyInformation *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} + +/**************************************************************** +****************************************************************/ + +NTSTATUS _samr_SetDsrmPassword(struct pipes_struct *p, + struct samr_SetDsrmPassword *r) +{ + p->rng_fault_state = true; + return NT_STATUS_NOT_IMPLEMENTED; +} diff --git a/source3/rpc_server/samr/srv_samr_util.c b/source3/rpc_server/samr/srv_samr_util.c new file mode 100644 index 0000000000..6fc4ade3cf --- /dev/null +++ b/source3/rpc_server/samr/srv_samr_util.c @@ -0,0 +1,714 @@ +/* + Unix SMB/CIFS implementation. + SAMR Pipe utility functions. + + Copyright (C) Luke Kenneth Casson Leighton 1996-1998 + Copyright (C) Gerald (Jerry) Carter 2000-2001 + Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Guenther Deschner 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 . +*/ + +#include "includes.h" +#include "../librpc/gen_ndr/samr.h" +#include "rpc_server/samr/srv_samr_util.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +#define STRING_CHANGED (old_string && !new_string) ||\ + (!old_string && new_string) ||\ + (old_string && new_string && (strcmp(old_string, new_string) != 0)) + +#define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\ + (!(s1) && (s2)) ||\ + ((s1) && (s2) && (strcmp((s1), (s2)) != 0)) + +/************************************************************* + Copies a struct samr_UserInfo2 to a struct samu +**************************************************************/ + +void copy_id2_to_sam_passwd(struct samu *to, + struct samr_UserInfo2 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_COMMENT | + SAMR_FIELD_COUNTRY_CODE | + SAMR_FIELD_CODE_PAGE; + i.comment = from->comment; + i.country_code = from->country_code; + i.code_page = from->code_page; + + copy_id21_to_sam_passwd("INFO_2", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo4 to a struct samu +**************************************************************/ + +void copy_id4_to_sam_passwd(struct samu *to, + struct samr_UserInfo4 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_LOGON_HOURS; + i.logon_hours = from->logon_hours; + + copy_id21_to_sam_passwd("INFO_4", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo6 to a struct samu +**************************************************************/ + +void copy_id6_to_sam_passwd(struct samu *to, + struct samr_UserInfo6 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_ACCOUNT_NAME | + SAMR_FIELD_FULL_NAME; + i.account_name = from->account_name; + i.full_name = from->full_name; + + copy_id21_to_sam_passwd("INFO_6", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo8 to a struct samu +**************************************************************/ + +void copy_id8_to_sam_passwd(struct samu *to, + struct samr_UserInfo8 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_FULL_NAME; + i.full_name = from->full_name; + + copy_id21_to_sam_passwd("INFO_8", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo10 to a struct samu +**************************************************************/ + +void copy_id10_to_sam_passwd(struct samu *to, + struct samr_UserInfo10 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_HOME_DIRECTORY | + SAMR_FIELD_HOME_DRIVE; + i.home_directory = from->home_directory; + i.home_drive = from->home_drive; + + copy_id21_to_sam_passwd("INFO_10", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo11 to a struct samu +**************************************************************/ + +void copy_id11_to_sam_passwd(struct samu *to, + struct samr_UserInfo11 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_LOGON_SCRIPT; + i.logon_script = from->logon_script; + + copy_id21_to_sam_passwd("INFO_11", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo12 to a struct samu +**************************************************************/ + +void copy_id12_to_sam_passwd(struct samu *to, + struct samr_UserInfo12 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_PROFILE_PATH; + i.profile_path = from->profile_path; + + copy_id21_to_sam_passwd("INFO_12", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo13 to a struct samu +**************************************************************/ + +void copy_id13_to_sam_passwd(struct samu *to, + struct samr_UserInfo13 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_DESCRIPTION; + i.description = from->description; + + copy_id21_to_sam_passwd("INFO_13", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo14 to a struct samu +**************************************************************/ + +void copy_id14_to_sam_passwd(struct samu *to, + struct samr_UserInfo14 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_WORKSTATIONS; + i.workstations = from->workstations; + + copy_id21_to_sam_passwd("INFO_14", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo16 to a struct samu +**************************************************************/ + +void copy_id16_to_sam_passwd(struct samu *to, + struct samr_UserInfo16 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_ACCT_FLAGS; + i.acct_flags = from->acct_flags; + + copy_id21_to_sam_passwd("INFO_16", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo17 to a struct samu +**************************************************************/ + +void copy_id17_to_sam_passwd(struct samu *to, + struct samr_UserInfo17 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_ACCT_EXPIRY; + i.acct_expiry = from->acct_expiry; + + copy_id21_to_sam_passwd("INFO_17", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo18 to a struct samu +**************************************************************/ + +void copy_id18_to_sam_passwd(struct samu *to, + struct samr_UserInfo18 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_EXPIRED_FLAG; + i.password_expired = from->password_expired; + + copy_id21_to_sam_passwd("INFO_18", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo20 to a struct samu +**************************************************************/ + +void copy_id20_to_sam_passwd(struct samu *to, + struct samr_UserInfo20 *from) +{ + const char *old_string; + char *new_string; + DATA_BLOB mung; + + if (from == NULL || to == NULL) { + return; + } + + if (from->parameters.array) { + old_string = pdb_get_munged_dial(to); + mung = data_blob_const(from->parameters.array, + from->parameters.length); + new_string = (mung.length == 0) ? + NULL : base64_encode_data_blob(talloc_tos(), mung); + DEBUG(10,("INFO_20 PARAMETERS: %s -> %s\n", + old_string, new_string)); + if (STRING_CHANGED_NC(old_string,new_string)) { + pdb_set_munged_dial(to, new_string, PDB_CHANGED); + } + + TALLOC_FREE(new_string); + } +} + +/************************************************************* + Copies a struct samr_UserInfo21 to a struct samu +**************************************************************/ + +void copy_id21_to_sam_passwd(const char *log_prefix, + struct samu *to, + struct samr_UserInfo21 *from) +{ + time_t unix_time, stored_time; + const char *old_string, *new_string; + const char *l; + + if (from == NULL || to == NULL) { + return; + } + + if (log_prefix) { + l = log_prefix; + } else { + l = "INFO_21"; + } + + if (from->fields_present & SAMR_FIELD_LAST_LOGON) { + unix_time = nt_time_to_unix(from->last_logon); + stored_time = pdb_get_logon_time(to); + DEBUG(10,("%s SAMR_FIELD_LAST_LOGON: %lu -> %lu\n", l, + (long unsigned int)stored_time, + (long unsigned int)unix_time)); + if (stored_time != unix_time) { + pdb_set_logon_time(to, unix_time, PDB_CHANGED); + } + } + + if (from->fields_present & SAMR_FIELD_LAST_LOGOFF) { + unix_time = nt_time_to_unix(from->last_logoff); + stored_time = pdb_get_logoff_time(to); + DEBUG(10,("%s SAMR_FIELD_LAST_LOGOFF: %lu -> %lu\n", l, + (long unsigned int)stored_time, + (long unsigned int)unix_time)); + if (stored_time != unix_time) { + pdb_set_logoff_time(to, unix_time, PDB_CHANGED); + } + } + + if (from->fields_present & SAMR_FIELD_ACCT_EXPIRY) { + unix_time = nt_time_to_unix(from->acct_expiry); + stored_time = pdb_get_kickoff_time(to); + DEBUG(10,("%s SAMR_FIELD_ACCT_EXPIRY: %lu -> %lu\n", l, + (long unsigned int)stored_time, + (long unsigned int)unix_time)); + if (stored_time != unix_time) { + pdb_set_kickoff_time(to, unix_time , PDB_CHANGED); + } + } + + if (from->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { + unix_time = nt_time_to_unix(from->last_password_change); + stored_time = pdb_get_pass_last_set_time(to); + DEBUG(10,("%s SAMR_FIELD_LAST_PWD_CHANGE: %lu -> %lu\n", l, + (long unsigned int)stored_time, + (long unsigned int)unix_time)); + if (stored_time != unix_time) { + pdb_set_pass_last_set_time(to, unix_time, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_ACCOUNT_NAME) && + (from->account_name.string)) { + old_string = pdb_get_username(to); + new_string = from->account_name.string; + DEBUG(10,("%s SAMR_FIELD_ACCOUNT_NAME: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_username(to, new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_FULL_NAME) && + (from->full_name.string)) { + old_string = pdb_get_fullname(to); + new_string = from->full_name.string; + DEBUG(10,("%s SAMR_FIELD_FULL_NAME: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_fullname(to, new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_HOME_DIRECTORY) && + (from->home_directory.string)) { + old_string = pdb_get_homedir(to); + new_string = from->home_directory.string; + DEBUG(10,("%s SAMR_FIELD_HOME_DIRECTORY: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_homedir(to, new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_HOME_DRIVE) && + (from->home_drive.string)) { + old_string = pdb_get_dir_drive(to); + new_string = from->home_drive.string; + DEBUG(10,("%s SAMR_FIELD_HOME_DRIVE: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_dir_drive(to, new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_LOGON_SCRIPT) && + (from->logon_script.string)) { + old_string = pdb_get_logon_script(to); + new_string = from->logon_script.string; + DEBUG(10,("%s SAMR_FIELD_LOGON_SCRIPT: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_logon_script(to , new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_PROFILE_PATH) && + (from->profile_path.string)) { + old_string = pdb_get_profile_path(to); + new_string = from->profile_path.string; + DEBUG(10,("%s SAMR_FIELD_PROFILE_PATH: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_profile_path(to , new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_DESCRIPTION) && + (from->description.string)) { + old_string = pdb_get_acct_desc(to); + new_string = from->description.string; + DEBUG(10,("%s SAMR_FIELD_DESCRIPTION: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_acct_desc(to, new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_WORKSTATIONS) && + (from->workstations.string)) { + old_string = pdb_get_workstations(to); + new_string = from->workstations.string; + DEBUG(10,("%s SAMR_FIELD_WORKSTATIONS: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_workstations(to , new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_COMMENT) && + (from->comment.string)) { + old_string = pdb_get_comment(to); + new_string = from->comment.string; + DEBUG(10,("%s SAMR_FIELD_COMMENT: %s -> %s\n", l, + old_string, new_string)); + if (STRING_CHANGED) { + pdb_set_comment(to, new_string, PDB_CHANGED); + } + } + + if ((from->fields_present & SAMR_FIELD_PARAMETERS) && + (from->parameters.array)) { + char *newstr; + DATA_BLOB mung; + old_string = pdb_get_munged_dial(to); + + mung = data_blob_const(from->parameters.array, + from->parameters.length); + newstr = (mung.length == 0) ? + NULL : base64_encode_data_blob(talloc_tos(), mung); + DEBUG(10,("%s SAMR_FIELD_PARAMETERS: %s -> %s\n", l, + old_string, newstr)); + if (STRING_CHANGED_NC(old_string,newstr)) { + pdb_set_munged_dial(to, newstr, PDB_CHANGED); + } + + TALLOC_FREE(newstr); + } + + if (from->fields_present & SAMR_FIELD_RID) { + if (from->rid == 0) { + DEBUG(10,("%s: Asked to set User RID to 0 !? Skipping change!\n", l)); + } else if (from->rid != pdb_get_user_rid(to)) { + DEBUG(10,("%s SAMR_FIELD_RID: %u -> %u NOT UPDATED!\n", l, + pdb_get_user_rid(to), from->rid)); + } + } + + if (from->fields_present & SAMR_FIELD_PRIMARY_GID) { + if (from->primary_gid == 0) { + DEBUG(10,("%s: Asked to set Group RID to 0 !? Skipping change!\n", l)); + } else if (from->primary_gid != pdb_get_group_rid(to)) { + DEBUG(10,("%s SAMR_FIELD_PRIMARY_GID: %u -> %u\n", l, + pdb_get_group_rid(to), from->primary_gid)); + pdb_set_group_sid_from_rid(to, + from->primary_gid, PDB_CHANGED); + } + } + + if (from->fields_present & SAMR_FIELD_ACCT_FLAGS) { + DEBUG(10,("%s SAMR_FIELD_ACCT_FLAGS: %08X -> %08X\n", l, + pdb_get_acct_ctrl(to), from->acct_flags)); + if (from->acct_flags != pdb_get_acct_ctrl(to)) { + + /* You cannot autolock an unlocked account via + * setuserinfo calls, so make sure to remove the + * ACB_AUTOLOCK bit here - gd */ + + if ((from->acct_flags & ACB_AUTOLOCK) && + !(pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) { + from->acct_flags &= ~ACB_AUTOLOCK; + } + + if (!(from->acct_flags & ACB_AUTOLOCK) && + (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) { + /* We're unlocking a previously locked user. Reset bad password counts. + Patch from Jianliang Lu. */ + pdb_set_bad_password_count(to, 0, PDB_CHANGED); + pdb_set_bad_password_time(to, 0, PDB_CHANGED); + } + pdb_set_acct_ctrl(to, from->acct_flags, PDB_CHANGED); + } + } + + if (from->fields_present & SAMR_FIELD_LOGON_HOURS) { + char oldstr[44]; /* hours strings are 42 bytes. */ + char newstr[44]; + DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week): %08X -> %08X\n", l, + pdb_get_logon_divs(to), from->logon_hours.units_per_week)); + if (from->logon_hours.units_per_week != pdb_get_logon_divs(to)) { + pdb_set_logon_divs(to, + from->logon_hours.units_per_week, PDB_CHANGED); + } + + DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week/8): %08X -> %08X\n", l, + pdb_get_hours_len(to), + from->logon_hours.units_per_week/8)); + if (from->logon_hours.units_per_week/8 != pdb_get_hours_len(to)) { + pdb_set_hours_len(to, + from->logon_hours.units_per_week/8, PDB_CHANGED); + } + + DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (bits): %s -> %s\n", l, + pdb_get_hours(to), from->logon_hours.bits)); + pdb_sethexhours(oldstr, pdb_get_hours(to)); + pdb_sethexhours(newstr, from->logon_hours.bits); + if (!strequal(oldstr, newstr)) { + pdb_set_hours(to, from->logon_hours.bits, PDB_CHANGED); + } + } + + if (from->fields_present & SAMR_FIELD_BAD_PWD_COUNT) { + DEBUG(10,("%s SAMR_FIELD_BAD_PWD_COUNT: %08X -> %08X\n", l, + pdb_get_bad_password_count(to), from->bad_password_count)); + if (from->bad_password_count != pdb_get_bad_password_count(to)) { + pdb_set_bad_password_count(to, + from->bad_password_count, PDB_CHANGED); + } + } + + if (from->fields_present & SAMR_FIELD_NUM_LOGONS) { + DEBUG(10,("%s SAMR_FIELD_NUM_LOGONS: %08X -> %08X\n", l, + pdb_get_logon_count(to), from->logon_count)); + if (from->logon_count != pdb_get_logon_count(to)) { + pdb_set_logon_count(to, from->logon_count, PDB_CHANGED); + } + } + + /* If the must change flag is set, the last set time goes to zero. + the must change and can change fields also do, but they are + calculated from policy, not set from the wire */ + + if (from->fields_present & SAMR_FIELD_EXPIRED_FLAG) { + DEBUG(10,("%s SAMR_FIELD_EXPIRED_FLAG: %02X\n", l, + from->password_expired)); + if (from->password_expired != 0) { + pdb_set_pass_last_set_time(to, 0, PDB_CHANGED); + } else { + /* A subtlety here: some windows commands will + clear the expired flag even though it's not + set, and we don't want to reset the time + in these caess. "net user /dom /active:y" + for example, to clear an autolocked acct. + We must check to see if it's expired first. jmcd */ + + uint32_t pwd_max_age = 0; + time_t now = time(NULL); + + pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &pwd_max_age); + + if (pwd_max_age == (uint32_t)-1 || pwd_max_age == 0) { + pwd_max_age = get_time_t_max(); + } + + stored_time = pdb_get_pass_last_set_time(to); + + /* we will only *set* a pwdlastset date when + a) the last pwdlastset time was 0 (user was forced to + change password). + b) the users password has not expired. gd. */ + + if ((stored_time == 0) || + ((now - stored_time) > pwd_max_age)) { + pdb_set_pass_last_set_time(to, now, PDB_CHANGED); + } + } + } +} + + +/************************************************************* + Copies a struct samr_UserInfo23 to a struct samu +**************************************************************/ + +void copy_id23_to_sam_passwd(struct samu *to, + struct samr_UserInfo23 *from) +{ + if (from == NULL || to == NULL) { + return; + } + + copy_id21_to_sam_passwd("INFO 23", to, &from->info); +} + +/************************************************************* + Copies a struct samr_UserInfo24 to a struct samu +**************************************************************/ + +void copy_id24_to_sam_passwd(struct samu *to, + struct samr_UserInfo24 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_EXPIRED_FLAG; + i.password_expired = from->password_expired; + + copy_id21_to_sam_passwd("INFO_24", to, &i); +} + +/************************************************************* + Copies a struct samr_UserInfo25 to a struct samu +**************************************************************/ + +void copy_id25_to_sam_passwd(struct samu *to, + struct samr_UserInfo25 *from) +{ + if (from == NULL || to == NULL) { + return; + } + + copy_id21_to_sam_passwd("INFO_25", to, &from->info); +} + +/************************************************************* + Copies a struct samr_UserInfo26 to a struct samu +**************************************************************/ + +void copy_id26_to_sam_passwd(struct samu *to, + struct samr_UserInfo26 *from) +{ + struct samr_UserInfo21 i; + + if (from == NULL || to == NULL) { + return; + } + + ZERO_STRUCT(i); + + i.fields_present = SAMR_FIELD_EXPIRED_FLAG; + i.password_expired = from->password_expired; + + copy_id21_to_sam_passwd("INFO_26", to, &i); +} diff --git a/source3/rpc_server/samr/srv_samr_util.h b/source3/rpc_server/samr/srv_samr_util.h new file mode 100644 index 0000000000..e898541559 --- /dev/null +++ b/source3/rpc_server/samr/srv_samr_util.h @@ -0,0 +1,77 @@ +/* + Unix SMB/CIFS implementation. + SAMR Pipe utility functions. + + Copyright (C) Luke Kenneth Casson Leighton 1996-1998 + Copyright (C) Gerald (Jerry) Carter 2000-2001 + Copyright (C) Andrew Bartlett 2001-2002 + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Guenther Deschner 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 . +*/ + +/* The following definitions come from rpc_server/srv_samr_util.c */ + +void copy_id2_to_sam_passwd(struct samu *to, + struct samr_UserInfo2 *from); +void copy_id4_to_sam_passwd(struct samu *to, + struct samr_UserInfo4 *from); +void copy_id6_to_sam_passwd(struct samu *to, + struct samr_UserInfo6 *from); +void copy_id8_to_sam_passwd(struct samu *to, + struct samr_UserInfo8 *from); +void copy_id10_to_sam_passwd(struct samu *to, + struct samr_UserInfo10 *from); +void copy_id11_to_sam_passwd(struct samu *to, + struct samr_UserInfo11 *from); +void copy_id12_to_sam_passwd(struct samu *to, + struct samr_UserInfo12 *from); +void copy_id13_to_sam_passwd(struct samu *to, + struct samr_UserInfo13 *from); +void copy_id14_to_sam_passwd(struct samu *to, + struct samr_UserInfo14 *from); +void copy_id16_to_sam_passwd(struct samu *to, + struct samr_UserInfo16 *from); +void copy_id17_to_sam_passwd(struct samu *to, + struct samr_UserInfo17 *from); +void copy_id18_to_sam_passwd(struct samu *to, + struct samr_UserInfo18 *from); +void copy_id20_to_sam_passwd(struct samu *to, + struct samr_UserInfo20 *from); +void copy_id21_to_sam_passwd(const char *log_prefix, + struct samu *to, + struct samr_UserInfo21 *from); +void copy_id23_to_sam_passwd(struct samu *to, + struct samr_UserInfo23 *from); +void copy_id24_to_sam_passwd(struct samu *to, + struct samr_UserInfo24 *from); +void copy_id25_to_sam_passwd(struct samu *to, + struct samr_UserInfo25 *from); +void copy_id26_to_sam_passwd(struct samu *to, + struct samr_UserInfo26 *from); + +/* The following definitions come from rpc_server/srv_samr_chgpasswd.c */ + +bool chgpasswd(const char *name, const char *rhost, const struct passwd *pass, + const char *oldpass, const char *newpass, bool as_root); +NTSTATUS pass_oem_change(char *user, const char *rhost, + uchar password_encrypted_with_lm_hash[516], + const uchar old_lm_hash_encrypted[16], + uchar password_encrypted_with_nt_hash[516], + const uchar old_nt_hash_encrypted[16], + enum samPwdChangeReason *reject_reason); +NTSTATUS check_password_complexity(const char *username, + const char *password, + enum samPwdChangeReason *samr_reject_reason); diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c new file mode 100644 index 0000000000..d2552ae47b --- /dev/null +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -0,0 +1,10658 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-2000, + * Copyright (C) Luke Kenneth Casson Leighton 1996-2000, + * Copyright (C) Jean François Micouleau 1998-2000, + * Copyright (C) Jeremy Allison 2001-2002, + * Copyright (C) Gerald Carter 2000-2004, + * Copyright (C) Tim Potter 2001-2002. + * Copyright (C) Guenther Deschner 2009-2010. + * Copyright (C) Andreas Schneider 2010. + * + * 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 . + */ + +/* Since the SPOOLSS rpc routines are basically DOS 16-bit calls wrapped + up, all the errors returned are DOS errors, not NT status codes. */ + +#include "includes.h" +#include "nt_printing.h" +#include "srv_spoolss_util.h" +#include "../librpc/gen_ndr/srv_spoolss.h" +#include "../librpc/gen_ndr/ndr_spoolss_c.h" +#include "rpc_client/init_spoolss.h" +#include "librpc/gen_ndr/messaging.h" +#include "../libcli/security/security.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "registry.h" +#include "registry/reg_objects.h" +#include "include/printing.h" +#include "secrets.h" +#include "../librpc/gen_ndr/netlogon.h" +#include "rpc_misc.h" + +/* macros stolen from s4 spoolss server */ +#define SPOOLSS_BUFFER_UNION(fn,info,level) \ + ((info)?ndr_size_##fn(info, level, 0):0) + +#define SPOOLSS_BUFFER_UNION_ARRAY(mem_ctx,fn,info,level,count) \ + ((info)?ndr_size_##fn##_info(mem_ctx, level, count, info):0) + +#define SPOOLSS_BUFFER_ARRAY(mem_ctx,fn,info,count) \ + ((info)?ndr_size_##fn##_info(mem_ctx, count, info):0) + +#define SPOOLSS_BUFFER_OK(val_true,val_false) ((r->in.offered >= *r->out.needed)?val_true:val_false) + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +#ifndef MAX_OPEN_PRINTER_EXS +#define MAX_OPEN_PRINTER_EXS 50 +#endif + +struct notify_back_channel; + +/* structure to store the printer handles */ +/* and a reference to what it's pointing to */ +/* and the notify info asked about */ +/* that's the central struct */ +struct printer_handle { + struct printer_handle *prev, *next; + bool document_started; + bool page_started; + uint32 jobid; /* jobid in printing backend */ + int printer_type; + const char *servername; + fstring sharename; + uint32 type; + uint32 access_granted; + struct { + uint32 flags; + uint32 options; + fstring localmachine; + uint32 printerlocal; + struct spoolss_NotifyOption *option; + struct policy_handle cli_hnd; + struct notify_back_channel *cli_chan; + uint32 change; + /* are we in a FindNextPrinterChangeNotify() call? */ + bool fnpcn; + struct messaging_context *msg_ctx; + } notify; + struct { + fstring machine; + fstring user; + } client; + + /* devmode sent in the OpenPrinter() call */ + struct spoolss_DeviceMode *devmode; + + /* TODO cache the printer info2 structure */ + struct spoolss_PrinterInfo2 *info2; + +}; + +static struct printer_handle *printers_list; + +struct printer_session_counter { + struct printer_session_counter *next; + struct printer_session_counter *prev; + + int snum; + uint32_t counter; +}; + +static struct printer_session_counter *counter_list; + +struct notify_back_channel { + struct notify_back_channel *prev, *next; + + /* associated client */ + struct sockaddr_storage client_address; + + /* print notify back-channel pipe handle*/ + struct rpc_pipe_client *cli_pipe; + struct dcerpc_binding_handle *binding_handle; + uint32_t active_connections; +}; + +static struct notify_back_channel *back_channels; + +/* Map generic permissions to printer object specific permissions */ + +const struct standard_mapping printer_std_mapping = { + PRINTER_READ, + PRINTER_WRITE, + PRINTER_EXECUTE, + PRINTER_ALL_ACCESS +}; + +/* Map generic permissions to print server object specific permissions */ + +const struct standard_mapping printserver_std_mapping = { + SERVER_READ, + SERVER_WRITE, + SERVER_EXECUTE, + SERVER_ALL_ACCESS +}; + +/* API table for Xcv Monitor functions */ + +struct xcv_api_table { + const char *name; + WERROR(*fn) (TALLOC_CTX *mem_ctx, struct security_token *token, DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed); +}; + +static void prune_printername_cache(void); + +/******************************************************************** + * Canonicalize servername. + ********************************************************************/ + +static const char *canon_servername(const char *servername) +{ + const char *pservername = servername; + while (*pservername == '\\') { + pservername++; + } + return pservername; +} + +/* translate between internal status numbers and NT status numbers */ +static int nt_printj_status(int v) +{ + switch (v) { + case LPQ_QUEUED: + return 0; + case LPQ_PAUSED: + return JOB_STATUS_PAUSED; + case LPQ_SPOOLING: + return JOB_STATUS_SPOOLING; + case LPQ_PRINTING: + return JOB_STATUS_PRINTING; + case LPQ_ERROR: + return JOB_STATUS_ERROR; + case LPQ_DELETING: + return JOB_STATUS_DELETING; + case LPQ_OFFLINE: + return JOB_STATUS_OFFLINE; + case LPQ_PAPEROUT: + return JOB_STATUS_PAPEROUT; + case LPQ_PRINTED: + return JOB_STATUS_PRINTED; + case LPQ_DELETED: + return JOB_STATUS_DELETED; + case LPQ_BLOCKED: + return JOB_STATUS_BLOCKED_DEVQ; + case LPQ_USER_INTERVENTION: + return JOB_STATUS_USER_INTERVENTION; + } + return 0; +} + +static int nt_printq_status(int v) +{ + switch (v) { + case LPQ_PAUSED: + return PRINTER_STATUS_PAUSED; + case LPQ_QUEUED: + case LPQ_SPOOLING: + case LPQ_PRINTING: + return 0; + } + return 0; +} + +/*************************************************************************** + Disconnect from the client +****************************************************************************/ + +static void srv_spoolss_replycloseprinter(int snum, + struct printer_handle *prn_hnd) +{ + WERROR result; + NTSTATUS status; + + /* + * Tell the specific printing tdb we no longer want messages for this printer + * by deregistering our PID. + */ + + if (!print_notify_deregister_pid(snum)) { + DEBUG(0, ("Failed to register our pid for printer %s\n", + lp_const_servicename(snum))); + } + + /* weird if the test succeeds !!! */ + if (prn_hnd->notify.cli_chan == NULL || + prn_hnd->notify.cli_chan->active_connections == 0) { + DEBUG(0, ("Trying to close unexisting backchannel!\n")); + DLIST_REMOVE(back_channels, prn_hnd->notify.cli_chan); + TALLOC_FREE(prn_hnd->notify.cli_chan); + return; + } + + status = dcerpc_spoolss_ReplyClosePrinter( + prn_hnd->notify.cli_chan->binding_handle, + talloc_tos(), + &prn_hnd->notify.cli_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("dcerpc_spoolss_ReplyClosePrinter failed [%s].\n", + nt_errstr(status))); + result = ntstatus_to_werror(status); + } else if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("reply_close_printer failed [%s].\n", + win_errstr(result))); + } + + /* if it's the last connection, deconnect the IPC$ share */ + if (prn_hnd->notify.cli_chan->active_connections == 1) { + + prn_hnd->notify.cli_chan->binding_handle = NULL; + cli_shutdown(rpc_pipe_np_smb_conn(prn_hnd->notify.cli_chan->cli_pipe)); + DLIST_REMOVE(back_channels, prn_hnd->notify.cli_chan); + TALLOC_FREE(prn_hnd->notify.cli_chan); + + if (prn_hnd->notify.msg_ctx != NULL) { + messaging_deregister(prn_hnd->notify.msg_ctx, + MSG_PRINTER_NOTIFY2, NULL); + + /* + * Tell the serverid.tdb we're no longer + * interested in printer notify messages. + */ + + serverid_register_msg_flags( + messaging_server_id(prn_hnd->notify.msg_ctx), + false, FLAG_MSG_PRINT_NOTIFY); + } + } + + if (prn_hnd->notify.cli_chan) { + prn_hnd->notify.cli_chan->active_connections--; + } +} + +/**************************************************************************** + Functions to free a printer entry datastruct. +****************************************************************************/ + +static int printer_entry_destructor(struct printer_handle *Printer) +{ + if (Printer->notify.cli_chan != NULL && + Printer->notify.cli_chan->active_connections > 0) { + int snum = -1; + + switch(Printer->printer_type) { + case SPLHND_SERVER: + srv_spoolss_replycloseprinter(snum, Printer); + break; + + case SPLHND_PRINTER: + snum = print_queue_snum(Printer->sharename); + if (snum != -1) { + srv_spoolss_replycloseprinter(snum, Printer); + } + break; + default: + break; + } + } + + Printer->notify.flags=0; + Printer->notify.options=0; + Printer->notify.localmachine[0]='\0'; + Printer->notify.printerlocal=0; + TALLOC_FREE(Printer->notify.option); + TALLOC_FREE(Printer->devmode); + + /* Remove from the internal list. */ + DLIST_REMOVE(printers_list, Printer); + return 0; +} + +/**************************************************************************** + find printer index by handle +****************************************************************************/ + +static struct printer_handle *find_printer_index_by_hnd(struct pipes_struct *p, + struct policy_handle *hnd) +{ + struct printer_handle *find_printer = NULL; + + if(!find_policy_by_hnd(p,hnd,(void **)(void *)&find_printer)) { + DEBUG(2,("find_printer_index_by_hnd: Printer handle not found: ")); + return NULL; + } + + return find_printer; +} + +/**************************************************************************** + Close printer index by handle. +****************************************************************************/ + +static bool close_printer_handle(struct pipes_struct *p, struct policy_handle *hnd) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); + + if (!Printer) { + DEBUG(2,("close_printer_handle: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(hnd))); + return false; + } + + close_policy_hnd(p, hnd); + + return true; +} + +/**************************************************************************** + Delete a printer given a handle. +****************************************************************************/ + +static WERROR delete_printer_hook(TALLOC_CTX *ctx, struct security_token *token, + const char *sharename, + struct messaging_context *msg_ctx) +{ + char *cmd = lp_deleteprinter_cmd(); + char *command = NULL; + int ret; + bool is_print_op = false; + + /* can't fail if we don't try */ + + if ( !*cmd ) + return WERR_OK; + + command = talloc_asprintf(ctx, + "%s \"%s\"", + cmd, sharename); + if (!command) { + return WERR_NOMEM; + } + if ( token ) + is_print_op = security_token_has_privilege(token, SEC_PRIV_PRINT_OPERATOR); + + DEBUG(10,("Running [%s]\n", command)); + + /********** BEGIN SePrintOperatorPrivlege BLOCK **********/ + + if ( is_print_op ) + become_root(); + + if ( (ret = smbrun(command, NULL)) == 0 ) { + /* Tell everyone we updated smb.conf. */ + message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL); + } + + if ( is_print_op ) + unbecome_root(); + + /********** END SePrintOperatorPrivlege BLOCK **********/ + + DEBUGADD(10,("returned [%d]\n", ret)); + + TALLOC_FREE(command); + + if (ret != 0) + return WERR_BADFID; /* What to return here? */ + + /* go ahead and re-read the services immediately */ + become_root(); + reload_services(msg_ctx, -1, false); + unbecome_root(); + + if ( lp_servicenumber( sharename ) >= 0 ) + return WERR_ACCESS_DENIED; + + return WERR_OK; +} + +/**************************************************************************** + Delete a printer given a handle. +****************************************************************************/ + +static WERROR delete_printer_handle(struct pipes_struct *p, struct policy_handle *hnd) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); + WERROR result; + + if (!Printer) { + DEBUG(2,("delete_printer_handle: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(hnd))); + return WERR_BADFID; + } + + /* + * It turns out that Windows allows delete printer on a handle + * opened by an admin user, then used on a pipe handle created + * by an anonymous user..... but they're working on security.... riiight ! + * JRA. + */ + + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { + DEBUG(3, ("delete_printer_handle: denied by handle\n")); + return WERR_ACCESS_DENIED; + } + + /* this does not need a become root since the access check has been + done on the handle already */ + + result = winreg_delete_printer_key(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + Printer->sharename, + ""); + if (!W_ERROR_IS_OK(result)) { + DEBUG(3,("Error deleting printer %s\n", Printer->sharename)); + return WERR_BADFID; + } + + result = delete_printer_hook(p->mem_ctx, p->server_info->security_token, + Printer->sharename, p->msg_ctx); + if (!W_ERROR_IS_OK(result)) { + return result; + } + prune_printername_cache(); + return WERR_OK; +} + +/**************************************************************************** + Return the snum of a printer corresponding to an handle. +****************************************************************************/ + +static bool get_printer_snum(struct pipes_struct *p, struct policy_handle *hnd, + int *number, struct share_params **params) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); + + if (!Printer) { + DEBUG(2,("get_printer_snum: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(hnd))); + return false; + } + + switch (Printer->printer_type) { + case SPLHND_PRINTER: + DEBUG(4,("short name:%s\n", Printer->sharename)); + *number = print_queue_snum(Printer->sharename); + return (*number != -1); + case SPLHND_SERVER: + return false; + default: + return false; + } +} + +/**************************************************************************** + Set printer handle type. + Check if it's \\server or \\server\printer +****************************************************************************/ + +static bool set_printer_hnd_printertype(struct printer_handle *Printer, const char *handlename) +{ + DEBUG(3,("Setting printer type=%s\n", handlename)); + + /* it's a print server */ + if (handlename && *handlename=='\\' && *(handlename+1)=='\\' && !strchr_m(handlename+2, '\\')) { + DEBUGADD(4,("Printer is a print server\n")); + Printer->printer_type = SPLHND_SERVER; + } + /* it's a printer (set_printer_hnd_name() will handle port monitors */ + else { + DEBUGADD(4,("Printer is a printer\n")); + Printer->printer_type = SPLHND_PRINTER; + } + + return true; +} + +static void prune_printername_cache_fn(const char *key, const char *value, + time_t timeout, void *private_data) +{ + gencache_del(key); +} + +static void prune_printername_cache(void) +{ + gencache_iterate(prune_printername_cache_fn, NULL, "PRINTERNAME/*"); +} + +/**************************************************************************** + Set printer handle name.. Accept names like \\server, \\server\printer, + \\server\SHARE, & "\\server\,XcvMonitor Standard TCP/IP Port" See + the MSDN docs regarding OpenPrinter() for details on the XcvData() and + XcvDataPort() interface. +****************************************************************************/ + +static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct printer_handle *Printer, + const char *handlename) +{ + int snum; + int n_services=lp_numservices(); + char *aprinter; + const char *printername; + const char *servername = NULL; + fstring sname; + bool found = false; + struct spoolss_PrinterInfo2 *info2 = NULL; + WERROR result; + char *p; + + /* + * Hopefully nobody names his printers like this. Maybe \ or , + * are illegal in printer names even? + */ + const char printer_not_found[] = "Printer \\, !@#$%^&*( not found"; + char *cache_key; + char *tmp; + + DEBUG(4,("Setting printer name=%s (len=%lu)\n", handlename, + (unsigned long)strlen(handlename))); + + aprinter = CONST_DISCARD(char *, handlename); + if ( *handlename == '\\' ) { + servername = canon_servername(handlename); + if ( (aprinter = strchr_m( servername, '\\' )) != NULL ) { + *aprinter = '\0'; + aprinter++; + } + if (!is_myname_or_ipaddr(servername)) { + return WERR_INVALID_PRINTER_NAME; + } + Printer->servername = talloc_asprintf(Printer, "\\\\%s", servername); + if (Printer->servername == NULL) { + return WERR_NOMEM; + } + } + + if (Printer->printer_type == SPLHND_SERVER) { + return WERR_OK; + } + + if (Printer->printer_type != SPLHND_PRINTER) { + return WERR_INVALID_HANDLE; + } + + DEBUGADD(5, ("searching for [%s]\n", aprinter)); + + p = strchr(aprinter, ','); + if (p != NULL) { + char *p2 = p; + p++; + if (*p == ' ') { + p++; + } + if (strncmp(p, "DrvConvert", strlen("DrvConvert")) == 0) { + *p2 = '\0'; + } else if (strncmp(p, "LocalOnly", strlen("LocalOnly")) == 0) { + *p2 = '\0'; + } + } + + if (p) { + DEBUGADD(5, ("stripped handlename: [%s]\n", aprinter)); + } + + /* check for the Port Monitor Interface */ + if ( strequal( aprinter, SPL_XCV_MONITOR_TCPMON ) ) { + Printer->printer_type = SPLHND_PORTMON_TCP; + fstrcpy(sname, SPL_XCV_MONITOR_TCPMON); + found = true; + } + else if ( strequal( aprinter, SPL_XCV_MONITOR_LOCALMON ) ) { + Printer->printer_type = SPLHND_PORTMON_LOCAL; + fstrcpy(sname, SPL_XCV_MONITOR_LOCALMON); + found = true; + } + + /* + * With hundreds of printers, the "for" loop iterating all + * shares can be quite expensive, as it is done on every + * OpenPrinter. The loop maps "aprinter" to "sname", the + * result of which we cache in gencache. + */ + + cache_key = talloc_asprintf(talloc_tos(), "PRINTERNAME/%s", + aprinter); + if ((cache_key != NULL) && gencache_get(cache_key, &tmp, NULL)) { + + found = (strcmp(tmp, printer_not_found) != 0); + if (!found) { + DEBUG(4, ("Printer %s not found\n", aprinter)); + SAFE_FREE(tmp); + return WERR_INVALID_PRINTER_NAME; + } + fstrcpy(sname, tmp); + SAFE_FREE(tmp); + } + + /* Search all sharenames first as this is easier than pulling + the printer_info_2 off of disk. Don't use find_service() since + that calls out to map_username() */ + + /* do another loop to look for printernames */ + for (snum = 0; !found && snum < n_services; snum++) { + const char *printer = lp_const_servicename(snum); + + /* no point going on if this is not a printer */ + if (!(lp_snum_ok(snum) && lp_print_ok(snum))) { + continue; + } + + /* ignore [printers] share */ + if (strequal(printer, "printers")) { + continue; + } + + fstrcpy(sname, printer); + if (strequal(aprinter, printer)) { + found = true; + break; + } + + /* no point looking up the printer object if + we aren't allowing printername != sharename */ + if (lp_force_printername(snum)) { + continue; + } + + result = winreg_get_printer(mem_ctx, + server_info, + msg_ctx, + sname, + &info2); + if ( !W_ERROR_IS_OK(result) ) { + DEBUG(2,("set_printer_hnd_name: failed to lookup printer [%s] -- result [%s]\n", + sname, win_errstr(result))); + continue; + } + + printername = strrchr(info2->printername, '\\'); + if (printername == NULL) { + printername = info2->printername; + } else { + printername++; + } + + if (strequal(printername, aprinter)) { + found = true; + break; + } + + DEBUGADD(10, ("printername: %s\n", printername)); + + TALLOC_FREE(info2); + } + + if ( !found ) { + if (cache_key != NULL) { + gencache_set(cache_key, printer_not_found, + time(NULL)+300); + TALLOC_FREE(cache_key); + } + DEBUGADD(4,("Printer not found\n")); + return WERR_INVALID_PRINTER_NAME; + } + + if (cache_key != NULL) { + gencache_set(cache_key, sname, time(NULL)+300); + TALLOC_FREE(cache_key); + } + + DEBUGADD(4,("set_printer_hnd_name: Printer found: %s -> %s\n", aprinter, sname)); + + fstrcpy(Printer->sharename, sname); + + return WERR_OK; +} + +/**************************************************************************** + Find first available printer slot. creates a printer handle for you. + ****************************************************************************/ + +static WERROR open_printer_hnd(struct pipes_struct *p, + struct policy_handle *hnd, + const char *name, + uint32_t access_granted) +{ + struct printer_handle *new_printer; + WERROR result; + + DEBUG(10,("open_printer_hnd: name [%s]\n", name)); + + new_printer = talloc_zero(p->mem_ctx, struct printer_handle); + if (new_printer == NULL) { + return WERR_NOMEM; + } + talloc_set_destructor(new_printer, printer_entry_destructor); + + /* This also steals the printer_handle on the policy_handle */ + if (!create_policy_hnd(p, hnd, new_printer)) { + TALLOC_FREE(new_printer); + return WERR_INVALID_HANDLE; + } + + /* Add to the internal list. */ + DLIST_ADD(printers_list, new_printer); + + new_printer->notify.option=NULL; + + if (!set_printer_hnd_printertype(new_printer, name)) { + close_printer_handle(p, hnd); + return WERR_INVALID_HANDLE; + } + + result = set_printer_hnd_name(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + new_printer, name); + if (!W_ERROR_IS_OK(result)) { + close_printer_handle(p, hnd); + return result; + } + + new_printer->access_granted = access_granted; + + DEBUG(5, ("%d printer handles active\n", + (int)num_pipe_handles(p))); + + return WERR_OK; +} + +/*************************************************************************** + check to see if the client motify handle is monitoring the notification + given by (notify_type, notify_field). + **************************************************************************/ + +static bool is_monitoring_event_flags(uint32_t flags, uint16_t notify_type, + uint16_t notify_field) +{ + return true; +} + +static bool is_monitoring_event(struct printer_handle *p, uint16_t notify_type, + uint16_t notify_field) +{ + struct spoolss_NotifyOption *option = p->notify.option; + uint32_t i, j; + + /* + * Flags should always be zero when the change notify + * is registered by the client's spooler. A user Win32 app + * might use the flags though instead of the NOTIFY_OPTION_INFO + * --jerry + */ + + if (!option) { + return false; + } + + if (p->notify.flags) + return is_monitoring_event_flags( + p->notify.flags, notify_type, notify_field); + + for (i = 0; i < option->count; i++) { + + /* Check match for notify_type */ + + if (option->types[i].type != notify_type) + continue; + + /* Check match for field */ + + for (j = 0; j < option->types[i].count; j++) { + if (option->types[i].fields[j].field == notify_field) { + return true; + } + } + } + + DEBUG(10, ("Open handle for \\\\%s\\%s is not monitoring 0x%02x/0x%02x\n", + p->servername, p->sharename, notify_type, notify_field)); + + return false; +} + +#define SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(_data, _integer) \ + _data->data.integer[0] = _integer; \ + _data->data.integer[1] = 0; + + +#define SETUP_SPOOLSS_NOTIFY_DATA_STRING(_data, _p) \ + _data->data.string.string = talloc_strdup(mem_ctx, _p); \ + if (!_data->data.string.string) {\ + _data->data.string.size = 0; \ + } \ + _data->data.string.size = strlen_m_term(_p) * 2; + +#define SETUP_SPOOLSS_NOTIFY_DATA_DEVMODE(_data, _devmode) \ + _data->data.devmode.devmode = _devmode; + +#define SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(_data, _sd) \ + _data->data.sd.sd = dup_sec_desc(mem_ctx, _sd); \ + if (!_data->data.sd.sd) { \ + _data->data.sd.sd_size = 0; \ + } \ + _data->data.sd.sd_size = \ + ndr_size_security_descriptor(_data->data.sd.sd, 0); + +static void init_systemtime_buffer(TALLOC_CTX *mem_ctx, + struct tm *t, + const char **pp, + uint32_t *plen) +{ + struct spoolss_Time st; + uint32_t len = 16; + char *p; + + if (!init_systemtime(&st, t)) { + return; + } + + p = talloc_array(mem_ctx, char, len); + if (!p) { + return; + } + + /* + * Systemtime must be linearized as a set of UINT16's. + * Fix from Benjamin (Bj) Kuit bj@it.uts.edu.au + */ + + SSVAL(p, 0, st.year); + SSVAL(p, 2, st.month); + SSVAL(p, 4, st.day_of_week); + SSVAL(p, 6, st.day); + SSVAL(p, 8, st.hour); + SSVAL(p, 10, st.minute); + SSVAL(p, 12, st.second); + SSVAL(p, 14, st.millisecond); + + *pp = p; + *plen = len; +} + +/* Convert a notification message to a struct spoolss_Notify */ + +static void notify_one_value(struct spoolss_notify_msg *msg, + struct spoolss_Notify *data, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, msg->notify.value[0]); +} + +static void notify_string(struct spoolss_notify_msg *msg, + struct spoolss_Notify *data, + TALLOC_CTX *mem_ctx) +{ + /* The length of the message includes the trailing \0 */ + + data->data.string.size = msg->len * 2; + data->data.string.string = talloc_strdup(mem_ctx, msg->notify.data); + if (!data->data.string.string) { + data->data.string.size = 0; + return; + } +} + +static void notify_system_time(struct spoolss_notify_msg *msg, + struct spoolss_Notify *data, + TALLOC_CTX *mem_ctx) +{ + data->data.string.string = NULL; + data->data.string.size = 0; + + if (msg->len != sizeof(time_t)) { + DEBUG(5, ("notify_system_time: received wrong sized message (%d)\n", + msg->len)); + return; + } + + init_systemtime_buffer(mem_ctx, gmtime((time_t *)msg->notify.data), + &data->data.string.string, + &data->data.string.size); +} + +struct notify2_message_table { + const char *name; + void (*fn)(struct spoolss_notify_msg *msg, + struct spoolss_Notify *data, TALLOC_CTX *mem_ctx); +}; + +static struct notify2_message_table printer_notify_table[] = { + /* 0x00 */ { "PRINTER_NOTIFY_FIELD_SERVER_NAME", notify_string }, + /* 0x01 */ { "PRINTER_NOTIFY_FIELD_PRINTER_NAME", notify_string }, + /* 0x02 */ { "PRINTER_NOTIFY_FIELD_SHARE_NAME", notify_string }, + /* 0x03 */ { "PRINTER_NOTIFY_FIELD_PORT_NAME", notify_string }, + /* 0x04 */ { "PRINTER_NOTIFY_FIELD_DRIVER_NAME", notify_string }, + /* 0x05 */ { "PRINTER_NOTIFY_FIELD_COMMENT", notify_string }, + /* 0x06 */ { "PRINTER_NOTIFY_FIELD_LOCATION", notify_string }, + /* 0x07 */ { "PRINTER_NOTIFY_FIELD_DEVMODE", NULL }, + /* 0x08 */ { "PRINTER_NOTIFY_FIELD_SEPFILE", notify_string }, + /* 0x09 */ { "PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR", notify_string }, + /* 0x0a */ { "PRINTER_NOTIFY_FIELD_PARAMETERS", NULL }, + /* 0x0b */ { "PRINTER_NOTIFY_FIELD_DATATYPE", notify_string }, + /* 0x0c */ { "PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NULL }, + /* 0x0d */ { "PRINTER_NOTIFY_FIELD_ATTRIBUTES", notify_one_value }, + /* 0x0e */ { "PRINTER_NOTIFY_FIELD_PRIORITY", notify_one_value }, + /* 0x0f */ { "PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY", NULL }, + /* 0x10 */ { "PRINTER_NOTIFY_FIELD_START_TIME", NULL }, + /* 0x11 */ { "PRINTER_NOTIFY_FIELD_UNTIL_TIME", NULL }, + /* 0x12 */ { "PRINTER_NOTIFY_FIELD_STATUS", notify_one_value }, +}; + +static struct notify2_message_table job_notify_table[] = { + /* 0x00 */ { "JOB_NOTIFY_FIELD_PRINTER_NAME", NULL }, + /* 0x01 */ { "JOB_NOTIFY_FIELD_MACHINE_NAME", NULL }, + /* 0x02 */ { "JOB_NOTIFY_FIELD_PORT_NAME", NULL }, + /* 0x03 */ { "JOB_NOTIFY_FIELD_USER_NAME", notify_string }, + /* 0x04 */ { "JOB_NOTIFY_FIELD_NOTIFY_NAME", NULL }, + /* 0x05 */ { "JOB_NOTIFY_FIELD_DATATYPE", NULL }, + /* 0x06 */ { "JOB_NOTIFY_FIELD_PRINT_PROCESSOR", NULL }, + /* 0x07 */ { "JOB_NOTIFY_FIELD_PARAMETERS", NULL }, + /* 0x08 */ { "JOB_NOTIFY_FIELD_DRIVER_NAME", NULL }, + /* 0x09 */ { "JOB_NOTIFY_FIELD_DEVMODE", NULL }, + /* 0x0a */ { "JOB_NOTIFY_FIELD_STATUS", notify_one_value }, + /* 0x0b */ { "JOB_NOTIFY_FIELD_STATUS_STRING", NULL }, + /* 0x0c */ { "JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NULL }, + /* 0x0d */ { "JOB_NOTIFY_FIELD_DOCUMENT", notify_string }, + /* 0x0e */ { "JOB_NOTIFY_FIELD_PRIORITY", NULL }, + /* 0x0f */ { "JOB_NOTIFY_FIELD_POSITION", NULL }, + /* 0x10 */ { "JOB_NOTIFY_FIELD_SUBMITTED", notify_system_time }, + /* 0x11 */ { "JOB_NOTIFY_FIELD_START_TIME", NULL }, + /* 0x12 */ { "JOB_NOTIFY_FIELD_UNTIL_TIME", NULL }, + /* 0x13 */ { "JOB_NOTIFY_FIELD_TIME", NULL }, + /* 0x14 */ { "JOB_NOTIFY_FIELD_TOTAL_PAGES", notify_one_value }, + /* 0x15 */ { "JOB_NOTIFY_FIELD_PAGES_PRINTED", NULL }, + /* 0x16 */ { "JOB_NOTIFY_FIELD_TOTAL_BYTES", notify_one_value }, + /* 0x17 */ { "JOB_NOTIFY_FIELD_BYTES_PRINTED", NULL }, +}; + + +/*********************************************************************** + Allocate talloc context for container object + **********************************************************************/ + +static void notify_msg_ctr_init( SPOOLSS_NOTIFY_MSG_CTR *ctr ) +{ + if ( !ctr ) + return; + + ctr->ctx = talloc_init("notify_msg_ctr_init %p", ctr); + + return; +} + +/*********************************************************************** + release all allocated memory and zero out structure + **********************************************************************/ + +static void notify_msg_ctr_destroy( SPOOLSS_NOTIFY_MSG_CTR *ctr ) +{ + if ( !ctr ) + return; + + if ( ctr->ctx ) + talloc_destroy(ctr->ctx); + + ZERO_STRUCTP(ctr); + + return; +} + +/*********************************************************************** + **********************************************************************/ + +static TALLOC_CTX* notify_ctr_getctx( SPOOLSS_NOTIFY_MSG_CTR *ctr ) +{ + if ( !ctr ) + return NULL; + + return ctr->ctx; +} + +/*********************************************************************** + **********************************************************************/ + +static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32_t idx ) +{ + if ( !ctr || !ctr->msg_groups ) + return NULL; + + if ( idx >= ctr->num_groups ) + return NULL; + + return &ctr->msg_groups[idx]; + +} + +/*********************************************************************** + How many groups of change messages do we have ? + **********************************************************************/ + +static int notify_msg_ctr_numgroups( SPOOLSS_NOTIFY_MSG_CTR *ctr ) +{ + if ( !ctr ) + return 0; + + return ctr->num_groups; +} + +/*********************************************************************** + Add a SPOOLSS_NOTIFY_MSG_CTR to the correct group + **********************************************************************/ + +static int notify_msg_ctr_addmsg( SPOOLSS_NOTIFY_MSG_CTR *ctr, SPOOLSS_NOTIFY_MSG *msg ) +{ + SPOOLSS_NOTIFY_MSG_GROUP *groups = NULL; + SPOOLSS_NOTIFY_MSG_GROUP *msg_grp = NULL; + SPOOLSS_NOTIFY_MSG *msg_list = NULL; + int i, new_slot; + + if ( !ctr || !msg ) + return 0; + + /* loop over all groups looking for a matching printer name */ + + for ( i=0; inum_groups; i++ ) { + if ( strcmp(ctr->msg_groups[i].printername, msg->printer) == 0 ) + break; + } + + /* add a new group? */ + + if ( i == ctr->num_groups ) { + ctr->num_groups++; + + if ( !(groups = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->msg_groups, SPOOLSS_NOTIFY_MSG_GROUP, ctr->num_groups)) ) { + DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed!\n")); + return 0; + } + ctr->msg_groups = groups; + + /* clear the new entry and set the printer name */ + + ZERO_STRUCT( ctr->msg_groups[ctr->num_groups-1] ); + fstrcpy( ctr->msg_groups[ctr->num_groups-1].printername, msg->printer ); + } + + /* add the change messages; 'i' is the correct index now regardless */ + + msg_grp = &ctr->msg_groups[i]; + + msg_grp->num_msgs++; + + if ( !(msg_list = TALLOC_REALLOC_ARRAY( ctr->ctx, msg_grp->msgs, SPOOLSS_NOTIFY_MSG, msg_grp->num_msgs )) ) { + DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed for new message [%d]!\n", msg_grp->num_msgs)); + return 0; + } + msg_grp->msgs = msg_list; + + new_slot = msg_grp->num_msgs-1; + memcpy( &msg_grp->msgs[new_slot], msg, sizeof(SPOOLSS_NOTIFY_MSG) ); + + /* need to allocate own copy of data */ + + if ( msg->len != 0 ) + msg_grp->msgs[new_slot].notify.data = (char *) + TALLOC_MEMDUP( ctr->ctx, msg->notify.data, msg->len ); + + return ctr->num_groups; +} + +static void construct_info_data(struct spoolss_Notify *info_data, + enum spoolss_NotifyType type, + uint16_t field, int id); + +/*********************************************************************** + Send a change notication message on all handles which have a call + back registered + **********************************************************************/ + +static int build_notify2_messages(TALLOC_CTX *mem_ctx, + struct printer_handle *prn_hnd, + SPOOLSS_NOTIFY_MSG *messages, + uint32_t num_msgs, + struct spoolss_Notify **_notifies, + int *_count) +{ + struct spoolss_Notify *notifies; + SPOOLSS_NOTIFY_MSG *msg; + int count = 0; + uint32_t id; + int i; + + notifies = talloc_zero_array(mem_ctx, + struct spoolss_Notify, num_msgs); + if (!notifies) { + return ENOMEM; + } + + for (i = 0; i < num_msgs; i++) { + + msg = &messages[i]; + + /* Are we monitoring this event? */ + + if (!is_monitoring_event(prn_hnd, msg->type, msg->field)) { + continue; + } + + DEBUG(10, ("Sending message type [0x%x] field [0x%2x] " + "for printer [%s]\n", + msg->type, msg->field, prn_hnd->sharename)); + + /* + * if the is a printer notification handle and not a job + * notification type, then set the id to 0. + * Otherwise just use what was specified in the message. + * + * When registering change notification on a print server + * handle we always need to send back the id (snum) matching + * the printer for which the change took place. + * For change notify registered on a printer handle, + * this does not matter and the id should be 0. + * + * --jerry + */ + + if ((msg->type == PRINTER_NOTIFY_TYPE) && + (prn_hnd->printer_type == SPLHND_PRINTER)) { + id = 0; + } else { + id = msg->id; + } + + /* Convert unix jobid to smb jobid */ + + if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) { + id = sysjob_to_jobid(msg->id); + + if (id == -1) { + DEBUG(3, ("no such unix jobid %d\n", + msg->id)); + continue; + } + } + + construct_info_data(¬ifies[count], + msg->type, msg->field, id); + + switch(msg->type) { + case PRINTER_NOTIFY_TYPE: + if (printer_notify_table[msg->field].fn) { + printer_notify_table[msg->field].fn(msg, + ¬ifies[count], mem_ctx); + } + break; + + case JOB_NOTIFY_TYPE: + if (job_notify_table[msg->field].fn) { + job_notify_table[msg->field].fn(msg, + ¬ifies[count], mem_ctx); + } + break; + + default: + DEBUG(5, ("Unknown notification type %d\n", + msg->type)); + continue; + } + + count++; + } + + *_notifies = notifies; + *_count = count; + + return 0; +} + +static int send_notify2_printer(TALLOC_CTX *mem_ctx, + struct printer_handle *prn_hnd, + SPOOLSS_NOTIFY_MSG_GROUP *msg_group) +{ + struct spoolss_Notify *notifies; + int count = 0; + union spoolss_ReplyPrinterInfo info; + struct spoolss_NotifyInfo info0; + uint32_t reply_result; + NTSTATUS status; + WERROR werr; + int ret; + + /* Is there notification on this handle? */ + if (prn_hnd->notify.cli_chan == NULL || + prn_hnd->notify.cli_chan->active_connections == 0) { + return 0; + } + + DEBUG(10, ("Client connected! [\\\\%s\\%s]\n", + prn_hnd->servername, prn_hnd->sharename)); + + /* For this printer? Print servers always receive notifications. */ + if ((prn_hnd->printer_type == SPLHND_PRINTER) && + (!strequal(msg_group->printername, prn_hnd->sharename))) { + return 0; + } + + DEBUG(10,("Our printer\n")); + + /* build the array of change notifications */ + ret = build_notify2_messages(mem_ctx, prn_hnd, + msg_group->msgs, + msg_group->num_msgs, + ¬ifies, &count); + if (ret) { + return ret; + } + + info0.version = 0x2; + info0.flags = count ? 0x00020000 /* ??? */ : PRINTER_NOTIFY_INFO_DISCARDED; + info0.count = count; + info0.notifies = notifies; + + info.info0 = &info0; + + status = dcerpc_spoolss_RouterReplyPrinterEx( + prn_hnd->notify.cli_chan->binding_handle, + mem_ctx, + &prn_hnd->notify.cli_hnd, + prn_hnd->notify.change, /* color */ + prn_hnd->notify.flags, + &reply_result, + 0, /* reply_type, must be 0 */ + info, &werr); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("dcerpc_spoolss_RouterReplyPrinterEx to client: %s " + "failed: %s\n", + prn_hnd->notify.cli_chan->cli_pipe->srv_name_slash, + nt_errstr(status))); + werr = ntstatus_to_werror(status); + } else if (!W_ERROR_IS_OK(werr)) { + DEBUG(1, ("RouterReplyPrinterEx to client: %s " + "failed: %s\n", + prn_hnd->notify.cli_chan->cli_pipe->srv_name_slash, + win_errstr(werr))); + } + switch (reply_result) { + case 0: + break; + case PRINTER_NOTIFY_INFO_DISCARDED: + case PRINTER_NOTIFY_INFO_DISCARDNOTED: + case PRINTER_NOTIFY_INFO_COLOR_MISMATCH: + break; + default: + break; + } + + return 0; +} + +static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32_t idx ) +{ + struct printer_handle *p; + TALLOC_CTX *mem_ctx = notify_ctr_getctx( ctr ); + SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx ); + int ret; + + if ( !msg_group ) { + DEBUG(5,("send_notify2_changes() called with no msg group!\n")); + return; + } + + if (!msg_group->msgs) { + DEBUG(5, ("send_notify2_changes() called with no messages!\n")); + return; + } + + DEBUG(8,("send_notify2_changes: Enter...[%s]\n", msg_group->printername)); + + /* loop over all printers */ + + for (p = printers_list; p; p = p->next) { + ret = send_notify2_printer(mem_ctx, p, msg_group); + if (ret) { + goto done; + } + } + +done: + DEBUG(8,("send_notify2_changes: Exit...\n")); + return; +} + +/*********************************************************************** + **********************************************************************/ + +static bool notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, void *buf, size_t len ) +{ + + uint32_t tv_sec, tv_usec; + size_t offset = 0; + + /* Unpack message */ + + offset += tdb_unpack((uint8_t *)buf + offset, len - offset, "f", + msg->printer); + + offset += tdb_unpack((uint8_t *)buf + offset, len - offset, "ddddddd", + &tv_sec, &tv_usec, + &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags); + + if (msg->len == 0) + tdb_unpack((uint8_t *)buf + offset, len - offset, "dd", + &msg->notify.value[0], &msg->notify.value[1]); + else + tdb_unpack((uint8_t *)buf + offset, len - offset, "B", + &msg->len, &msg->notify.data); + + DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message for printer %s, jobid %u type %d, field 0x%02x, flags 0x%04x\n", + msg->printer, (unsigned int)msg->id, msg->type, msg->field, msg->flags)); + + tv->tv_sec = tv_sec; + tv->tv_usec = tv_usec; + + if (msg->len == 0) + DEBUG(3, ("notify2_unpack_msg: value1 = %d, value2 = %d\n", msg->notify.value[0], + msg->notify.value[1])); + else + dump_data(3, (uint8_t *)msg->notify.data, msg->len); + + return true; +} + +/******************************************************************** + Receive a notify2 message list + ********************************************************************/ + +static void receive_notify2_message_list(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data) +{ + size_t msg_count, i; + char *buf = (char *)data->data; + char *msg_ptr; + size_t msg_len; + SPOOLSS_NOTIFY_MSG notify; + SPOOLSS_NOTIFY_MSG_CTR messages; + int num_groups; + + if (data->length < 4) { + DEBUG(0,("receive_notify2_message_list: bad message format (len < 4)!\n")); + return; + } + + msg_count = IVAL(buf, 0); + msg_ptr = buf + 4; + + DEBUG(5, ("receive_notify2_message_list: got %lu messages in list\n", (unsigned long)msg_count)); + + if (msg_count == 0) { + DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n")); + return; + } + + /* initialize the container */ + + ZERO_STRUCT( messages ); + notify_msg_ctr_init( &messages ); + + /* + * build message groups for each printer identified + * in a change_notify msg. Remember that a PCN message + * includes the handle returned for the srv_spoolss_replyopenprinter() + * call. Therefore messages are grouped according to printer handle. + */ + + for ( i=0; i data->length) { + DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n")); + return; + } + + msg_len = IVAL(msg_ptr,0); + msg_ptr += 4; + + if (msg_ptr + msg_len - buf > data->length) { + DEBUG(0,("receive_notify2_message_list: bad message format (bad len) !\n")); + return; + } + + /* unpack messages */ + + ZERO_STRUCT( notify ); + notify2_unpack_msg( ¬ify, &msg_tv, msg_ptr, msg_len ); + msg_ptr += msg_len; + + /* add to correct list in container */ + + notify_msg_ctr_addmsg( &messages, ¬ify ); + + /* free memory that might have been allocated by notify2_unpack_msg() */ + + if ( notify.len != 0 ) + SAFE_FREE( notify.notify.data ); + } + + /* process each group of messages */ + + num_groups = notify_msg_ctr_numgroups( &messages ); + for ( i=0; idata, data->length); + if (!drivername) { + DEBUG(0, ("do_drv_upgrade_printer: Out of memoery ?!\n")); + goto done; + } + + DEBUG(10, ("do_drv_upgrade_printer: " + "Got message for new driver [%s]\n", drivername)); + + /* Iterate the printer list */ + + for (snum = 0; snum < n_services; snum++) { + if (!lp_snum_ok(snum) || !lp_print_ok(snum)) { + continue; + } + + /* ignore [printers] share */ + if (strequal(lp_const_servicename(snum), "printers")) { + continue; + } + + result = winreg_get_printer(tmp_ctx, server_info, msg, + lp_const_servicename(snum), + &pinfo2); + + if (!W_ERROR_IS_OK(result)) { + continue; + } + + if (!pinfo2->drivername) { + continue; + } + + if (strcmp(drivername, pinfo2->drivername) != 0) { + continue; + } + + DEBUG(6,("Updating printer [%s]\n", pinfo2->printername)); + + /* all we care about currently is the change_id */ + result = winreg_printer_update_changeid(tmp_ctx, + server_info, + msg, + pinfo2->printername); + + if (!W_ERROR_IS_OK(result)) { + DEBUG(3, ("do_drv_upgrade_printer: " + "Failed to update changeid [%s]\n", + win_errstr(result))); + } + } + + /* all done */ +done: + talloc_free(tmp_ctx); +} + +/******************************************************************** + Update the cache for all printq's with a registered client + connection + ********************************************************************/ + +void update_monitored_printq_cache(struct messaging_context *msg_ctx) +{ + struct printer_handle *printer = printers_list; + int snum; + + /* loop through all printers and update the cache where + a client is connected */ + while (printer) { + if ((printer->printer_type == SPLHND_PRINTER) && + ((printer->notify.cli_chan != NULL) && + (printer->notify.cli_chan->active_connections > 0))) { + snum = print_queue_snum(printer->sharename); + print_queue_status(msg_ctx, snum, NULL, NULL); + } + + printer = printer->next; + } + + return; +} + +/**************************************************************** + _spoolss_OpenPrinter +****************************************************************/ + +WERROR _spoolss_OpenPrinter(struct pipes_struct *p, + struct spoolss_OpenPrinter *r) +{ + struct spoolss_OpenPrinterEx e; + WERROR werr; + + ZERO_STRUCT(e.in.userlevel); + + e.in.printername = r->in.printername; + e.in.datatype = r->in.datatype; + e.in.devmode_ctr = r->in.devmode_ctr; + e.in.access_mask = r->in.access_mask; + e.in.level = 0; + + e.out.handle = r->out.handle; + + werr = _spoolss_OpenPrinterEx(p, &e); + + if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) { + /* OpenPrinterEx returns this for a bad + * printer name. We must return WERR_INVALID_PRINTER_NAME + * instead. + */ + werr = WERR_INVALID_PRINTER_NAME; + } + + return werr; +} + +static WERROR copy_devicemode(TALLOC_CTX *mem_ctx, + struct spoolss_DeviceMode *orig, + struct spoolss_DeviceMode **dest) +{ + struct spoolss_DeviceMode *dm; + + dm = talloc(mem_ctx, struct spoolss_DeviceMode); + if (!dm) { + return WERR_NOMEM; + } + + /* copy all values, then duplicate strings and structs */ + *dm = *orig; + + dm->devicename = talloc_strdup(dm, orig->devicename); + if (!dm->devicename) { + return WERR_NOMEM; + } + dm->formname = talloc_strdup(dm, orig->formname); + if (!dm->formname) { + return WERR_NOMEM; + } + if (orig->driverextra_data.data) { + dm->driverextra_data.data = + (uint8_t *) talloc_memdup(dm, orig->driverextra_data.data, + orig->driverextra_data.length); + if (!dm->driverextra_data.data) { + return WERR_NOMEM; + } + } + + *dest = dm; + return WERR_OK; +} + +/**************************************************************** + _spoolss_OpenPrinterEx +****************************************************************/ + +WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p, + struct spoolss_OpenPrinterEx *r) +{ + int snum; + struct printer_handle *Printer=NULL; + WERROR result; + + if (!r->in.printername) { + return WERR_INVALID_PARAM; + } + + if (r->in.level < 0 || r->in.level > 3) { + return WERR_INVALID_PARAM; + } + if ((r->in.level == 1 && !r->in.userlevel.level1) || + (r->in.level == 2 && !r->in.userlevel.level2) || + (r->in.level == 3 && !r->in.userlevel.level3)) { + return WERR_INVALID_PARAM; + } + + /* some sanity check because you can open a printer or a print server */ + /* aka: \\server\printer or \\server */ + + DEBUGADD(3,("checking name: %s\n", r->in.printername)); + + result = open_printer_hnd(p, r->out.handle, r->in.printername, 0); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0,("_spoolss_OpenPrinterEx: Cannot open a printer handle " + "for printer %s\n", r->in.printername)); + ZERO_STRUCTP(r->out.handle); + return result; + } + + Printer = find_printer_index_by_hnd(p, r->out.handle); + if ( !Printer ) { + DEBUG(0,("_spoolss_OpenPrinterEx: logic error. Can't find printer " + "handle we created for printer %s\n", r->in.printername)); + close_printer_handle(p, r->out.handle); + ZERO_STRUCTP(r->out.handle); + return WERR_INVALID_PARAM; + } + + /* + * First case: the user is opening the print server: + * + * Disallow MS AddPrinterWizard if parameter disables it. A Win2k + * client 1st tries an OpenPrinterEx with access==0, MUST be allowed. + * + * Then both Win2k and WinNT clients try an OpenPrinterEx with + * SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0) + * or if the user is listed in the smb.conf printer admin parameter. + * + * Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the + * client view printer folder, but does not show the MSAPW. + * + * Note: this test needs code to check access rights here too. Jeremy + * could you look at this? + * + * Second case: the user is opening a printer: + * NT doesn't let us connect to a printer if the connecting user + * doesn't have print permission. + * + * Third case: user is opening a Port Monitor + * access checks same as opening a handle to the print server. + */ + + switch (Printer->printer_type ) + { + case SPLHND_SERVER: + case SPLHND_PORTMON_TCP: + case SPLHND_PORTMON_LOCAL: + /* Printserver handles use global struct... */ + + snum = -1; + + /* Map standard access rights to object specific access rights */ + + se_map_standard(&r->in.access_mask, + &printserver_std_mapping); + + /* Deny any object specific bits that don't apply to print + servers (i.e printer and job specific bits) */ + + r->in.access_mask &= SEC_MASK_SPECIFIC; + + if (r->in.access_mask & + ~(SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)) { + DEBUG(3, ("access DENIED for non-printserver bits\n")); + close_printer_handle(p, r->out.handle); + ZERO_STRUCTP(r->out.handle); + return WERR_ACCESS_DENIED; + } + + /* Allow admin access */ + + if ( r->in.access_mask & SERVER_ACCESS_ADMINISTER ) + { + if (!lp_ms_add_printer_wizard()) { + close_printer_handle(p, r->out.handle); + ZERO_STRUCTP(r->out.handle); + return WERR_ACCESS_DENIED; + } + + /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, + and not a printer admin, then fail */ + + if ((p->server_info->utok.uid != sec_initial_uid()) && + !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && + !nt_token_check_sid(&global_sid_Builtin_Print_Operators, p->server_info->security_token) && + !token_contains_name_in_list( + uidtoname(p->server_info->utok.uid), + p->server_info->info3->base.domain.string, + NULL, + p->server_info->security_token, + lp_printer_admin(snum))) { + close_printer_handle(p, r->out.handle); + ZERO_STRUCTP(r->out.handle); + DEBUG(3,("access DENIED as user is not root, " + "has no printoperator privilege, " + "not a member of the printoperator builtin group and " + "is not in printer admin list")); + return WERR_ACCESS_DENIED; + } + + r->in.access_mask = SERVER_ACCESS_ADMINISTER; + } + else + { + r->in.access_mask = SERVER_ACCESS_ENUMERATE; + } + + DEBUG(4,("Setting print server access = %s\n", (r->in.access_mask == SERVER_ACCESS_ADMINISTER) + ? "SERVER_ACCESS_ADMINISTER" : "SERVER_ACCESS_ENUMERATE" )); + + /* We fall through to return WERR_OK */ + break; + + case SPLHND_PRINTER: + /* NT doesn't let us connect to a printer if the connecting user + doesn't have print permission. */ + + if (!get_printer_snum(p, r->out.handle, &snum, NULL)) { + close_printer_handle(p, r->out.handle); + ZERO_STRUCTP(r->out.handle); + return WERR_BADFID; + } + + if (r->in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED) { + r->in.access_mask = PRINTER_ACCESS_ADMINISTER; + } + + se_map_standard(&r->in.access_mask, &printer_std_mapping); + + /* map an empty access mask to the minimum access mask */ + if (r->in.access_mask == 0x0) + r->in.access_mask = PRINTER_ACCESS_USE; + + /* + * If we are not serving the printer driver for this printer, + * map PRINTER_ACCESS_ADMINISTER to PRINTER_ACCESS_USE. This + * will keep NT clients happy --jerry + */ + + if (lp_use_client_driver(snum) + && (r->in.access_mask & PRINTER_ACCESS_ADMINISTER)) + { + r->in.access_mask = PRINTER_ACCESS_USE; + } + + /* check smb.conf parameters and the the sec_desc */ + + if (!allow_access(lp_hostsdeny(snum), lp_hostsallow(snum), + p->client_id->name, p->client_id->addr)) { + DEBUG(3, ("access DENIED (hosts allow/deny) for printer open\n")); + ZERO_STRUCTP(r->out.handle); + return WERR_ACCESS_DENIED; + } + + if (!user_ok_token(uidtoname(p->server_info->utok.uid), NULL, + p->server_info->security_token, snum) || + !print_access_check(p->server_info, + p->msg_ctx, + snum, + r->in.access_mask)) { + DEBUG(3, ("access DENIED for printer open\n")); + close_printer_handle(p, r->out.handle); + ZERO_STRUCTP(r->out.handle); + return WERR_ACCESS_DENIED; + } + + if ((r->in.access_mask & SEC_MASK_SPECIFIC)& ~(PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE)) { + DEBUG(3, ("access DENIED for printer open - unknown bits\n")); + close_printer_handle(p, r->out.handle); + ZERO_STRUCTP(r->out.handle); + return WERR_ACCESS_DENIED; + } + + if (r->in.access_mask & PRINTER_ACCESS_ADMINISTER) + r->in.access_mask = PRINTER_ACCESS_ADMINISTER; + else + r->in.access_mask = PRINTER_ACCESS_USE; + + DEBUG(4,("Setting printer access = %s\n", (r->in.access_mask == PRINTER_ACCESS_ADMINISTER) + ? "PRINTER_ACCESS_ADMINISTER" : "PRINTER_ACCESS_USE" )); + + winreg_create_printer(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum)); + + break; + + default: + /* sanity check to prevent programmer error */ + ZERO_STRUCTP(r->out.handle); + return WERR_BADFID; + } + + Printer->access_granted = r->in.access_mask; + + /* + * If the client sent a devmode in the OpenPrinter() call, then + * save it here in case we get a job submission on this handle + */ + + if ((Printer->printer_type != SPLHND_SERVER) && + r->in.devmode_ctr.devmode) { + copy_devicemode(NULL, r->in.devmode_ctr.devmode, + &Printer->devmode); + } + +#if 0 /* JERRY -- I'm doubtful this is really effective */ + /* HACK ALERT!!! Sleep for 1/3 of a second to try trigger a LAN/WAN + optimization in Windows 2000 clients --jerry */ + + if ( (r->in.access_mask == PRINTER_ACCESS_ADMINISTER) + && (RA_WIN2K == get_remote_arch()) ) + { + DEBUG(10,("_spoolss_OpenPrinterEx: Enabling LAN/WAN hack for Win2k clients.\n")); + sys_usleep( 500000 ); + } +#endif + + return WERR_OK; +} + +/**************************************************************** + _spoolss_ClosePrinter +****************************************************************/ + +WERROR _spoolss_ClosePrinter(struct pipes_struct *p, + struct spoolss_ClosePrinter *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + if (Printer && Printer->document_started) { + struct spoolss_EndDocPrinter e; + + e.in.handle = r->in.handle; + + _spoolss_EndDocPrinter(p, &e); + } + + if (!close_printer_handle(p, r->in.handle)) + return WERR_BADFID; + + /* clear the returned printer handle. Observed behavior + from Win2k server. Don't think this really matters. + Previous code just copied the value of the closed + handle. --jerry */ + + ZERO_STRUCTP(r->out.handle); + + return WERR_OK; +} + +/**************************************************************** + _spoolss_DeletePrinter +****************************************************************/ + +WERROR _spoolss_DeletePrinter(struct pipes_struct *p, + struct spoolss_DeletePrinter *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + WERROR result; + int snum; + + if (Printer && Printer->document_started) { + struct spoolss_EndDocPrinter e; + + e.in.handle = r->in.handle; + + _spoolss_EndDocPrinter(p, &e); + } + + if (get_printer_snum(p, r->in.handle, &snum, NULL)) { + winreg_delete_printer_key(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + ""); + } + + result = delete_printer_handle(p, r->in.handle); + + return result; +} + +/******************************************************************* + * static function to lookup the version id corresponding to an + * long architecture string + ******************************************************************/ + +static const struct print_architecture_table_node archi_table[]= { + + {"Windows 4.0", SPL_ARCH_WIN40, 0 }, + {"Windows NT x86", SPL_ARCH_W32X86, 2 }, + {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 }, + {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 }, + {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 }, + {"Windows IA64", SPL_ARCH_IA64, 3 }, + {"Windows x64", SPL_ARCH_X64, 3 }, + {NULL, "", -1 } +}; + +static int get_version_id(const char *arch) +{ + int i; + + for (i=0; archi_table[i].long_archi != NULL; i++) + { + if (strcmp(arch, archi_table[i].long_archi) == 0) + return (archi_table[i].version); + } + + return -1; +} + +/**************************************************************** + _spoolss_DeletePrinterDriver +****************************************************************/ + +WERROR _spoolss_DeletePrinterDriver(struct pipes_struct *p, + struct spoolss_DeletePrinterDriver *r) +{ + + struct spoolss_DriverInfo8 *info = NULL; + struct spoolss_DriverInfo8 *info_win2k = NULL; + int version; + WERROR status; + + /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, + and not a printer admin, then fail */ + + if ( (p->server_info->utok.uid != sec_initial_uid()) + && !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) + && !token_contains_name_in_list( + uidtoname(p->server_info->utok.uid), + p->server_info->info3->base.domain.string, + NULL, + p->server_info->security_token, + lp_printer_admin(-1)) ) + { + return WERR_ACCESS_DENIED; + } + + /* check that we have a valid driver name first */ + + if ((version = get_version_id(r->in.architecture)) == -1) + return WERR_INVALID_ENVIRONMENT; + + status = winreg_get_driver(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->in.architecture, r->in.driver, + version, &info); + if (!W_ERROR_IS_OK(status)) { + /* try for Win2k driver if "Windows NT x86" */ + + if ( version == 2 ) { + version = 3; + + status = winreg_get_driver(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->in.architecture, + r->in.driver, + version, &info); + if (!W_ERROR_IS_OK(status)) { + status = WERR_UNKNOWN_PRINTER_DRIVER; + goto done; + } + } + /* otherwise it was a failure */ + else { + status = WERR_UNKNOWN_PRINTER_DRIVER; + goto done; + } + + } + + if (printer_driver_in_use(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + info)) { + status = WERR_PRINTER_DRIVER_IN_USE; + goto done; + } + + if (version == 2) { + status = winreg_get_driver(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->in.architecture, + r->in.driver, 3, &info_win2k); + if (W_ERROR_IS_OK(status)) { + /* if we get to here, we now have 2 driver info structures to remove */ + /* remove the Win2k driver first*/ + + status = winreg_del_driver(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + info_win2k, 3); + talloc_free(info_win2k); + + /* this should not have failed---if it did, report to client */ + if (!W_ERROR_IS_OK(status)) { + goto done; + } + } + } + + status = winreg_del_driver(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + info, version); + +done: + talloc_free(info); + + return status; +} + +/**************************************************************** + _spoolss_DeletePrinterDriverEx +****************************************************************/ + +WERROR _spoolss_DeletePrinterDriverEx(struct pipes_struct *p, + struct spoolss_DeletePrinterDriverEx *r) +{ + struct spoolss_DriverInfo8 *info = NULL; + struct spoolss_DriverInfo8 *info_win2k = NULL; + int version; + bool delete_files; + WERROR status; + + /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, + and not a printer admin, then fail */ + + if ( (p->server_info->utok.uid != sec_initial_uid()) + && !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) + && !token_contains_name_in_list( + uidtoname(p->server_info->utok.uid), + p->server_info->info3->base.domain.string, + NULL, + p->server_info->security_token, lp_printer_admin(-1)) ) + { + return WERR_ACCESS_DENIED; + } + + /* check that we have a valid driver name first */ + if ((version = get_version_id(r->in.architecture)) == -1) { + /* this is what NT returns */ + return WERR_INVALID_ENVIRONMENT; + } + + if (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) + version = r->in.version; + + status = winreg_get_driver(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->in.architecture, + r->in.driver, + version, + &info); + if (!W_ERROR_IS_OK(status)) { + status = WERR_UNKNOWN_PRINTER_DRIVER; + + /* + * if the client asked for a specific version, + * or this is something other than Windows NT x86, + * then we've failed + */ + + if ( (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) || (version !=2) ) + goto done; + + /* try for Win2k driver if "Windows NT x86" */ + + version = 3; + status = winreg_get_driver(info, + get_server_info_system(), + p->msg_ctx, + r->in.architecture, + r->in.driver, + version, &info); + if (!W_ERROR_IS_OK(status)) { + status = WERR_UNKNOWN_PRINTER_DRIVER; + goto done; + } + } + + if (printer_driver_in_use(info, + get_server_info_system(), + p->msg_ctx, + info)) { + status = WERR_PRINTER_DRIVER_IN_USE; + goto done; + } + + /* + * we have a couple of cases to consider. + * (1) Are any files in use? If so and DPD_DELTE_ALL_FILE is set, + * then the delete should fail if **any** files overlap with + * other drivers + * (2) If DPD_DELTE_UNUSED_FILES is sert, then delete all + * non-overlapping files + * (3) If neither DPD_DELTE_ALL_FILE nor DPD_DELTE_ALL_FILES + * is set, the do not delete any files + * Refer to MSDN docs on DeletePrinterDriverEx() for details. + */ + + delete_files = r->in.delete_flags & (DPD_DELETE_ALL_FILES|DPD_DELETE_UNUSED_FILES); + + /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */ + + if (delete_files && + (r->in.delete_flags & DPD_DELETE_ALL_FILES) && + printer_driver_files_in_use(info, + get_server_info_system(), + p->msg_ctx, + info)) { + /* no idea of the correct error here */ + status = WERR_ACCESS_DENIED; + goto done; + } + + + /* also check for W32X86/3 if necessary; maybe we already have? */ + + if ( (version == 2) && ((r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION) ) { + status = winreg_get_driver(info, + get_server_info_system(), + p->msg_ctx, + r->in.architecture, + r->in.driver, 3, &info_win2k); + if (W_ERROR_IS_OK(status)) { + + if (delete_files && + (r->in.delete_flags & DPD_DELETE_ALL_FILES) && + printer_driver_files_in_use(info, + get_server_info_system(), + p->msg_ctx, + info_win2k)) { + /* no idea of the correct error here */ + talloc_free(info_win2k); + status = WERR_ACCESS_DENIED; + goto done; + } + + /* if we get to here, we now have 2 driver info structures to remove */ + /* remove the Win2k driver first*/ + + status = winreg_del_driver(info, + get_server_info_system(), + p->msg_ctx, + info_win2k, + 3); + + /* this should not have failed---if it did, report to client */ + + if (!W_ERROR_IS_OK(status)) { + goto done; + } + + /* + * now delete any associated files if delete_files is + * true. Even if this part failes, we return succes + * because the driver doesn not exist any more + */ + if (delete_files) { + delete_driver_files(get_server_info_system(), + info_win2k); + } + } + } + + status = winreg_del_driver(info, + get_server_info_system(), + p->msg_ctx, + info, + version); + if (!W_ERROR_IS_OK(status)) { + goto done; + } + + /* + * now delete any associated files if delete_files is + * true. Even if this part failes, we return succes + * because the driver doesn not exist any more + */ + if (delete_files) { + delete_driver_files(get_server_info_system(), info); + } + +done: + talloc_free(info); + return status; +} + + +/******************************************************************** + GetPrinterData on a printer server Handle. +********************************************************************/ + +static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx, + const char *value, + enum winreg_Type *type, + union spoolss_PrinterData *data) +{ + DEBUG(8,("getprinterdata_printer_server:%s\n", value)); + + if (!StrCaseCmp(value, "W3SvcInstalled")) { + *type = REG_DWORD; + data->value = 0x00; + return WERR_OK; + } + + if (!StrCaseCmp(value, "BeepEnabled")) { + *type = REG_DWORD; + data->value = 0x00; + return WERR_OK; + } + + if (!StrCaseCmp(value, "EventLog")) { + *type = REG_DWORD; + /* formally was 0x1b */ + data->value = 0x00; + return WERR_OK; + } + + if (!StrCaseCmp(value, "NetPopup")) { + *type = REG_DWORD; + data->value = 0x00; + return WERR_OK; + } + + if (!StrCaseCmp(value, "MajorVersion")) { + *type = REG_DWORD; + + /* Windows NT 4.0 seems to not allow uploading of drivers + to a server that reports 0x3 as the MajorVersion. + need to investigate more how Win2k gets around this . + -- jerry */ + + if (RA_WINNT == get_remote_arch()) { + data->value = 0x02; + } else { + data->value = 0x03; + } + + return WERR_OK; + } + + if (!StrCaseCmp(value, "MinorVersion")) { + *type = REG_DWORD; + data->value = 0x00; + return WERR_OK; + } + + /* REG_BINARY + * uint32_t size = 0x114 + * uint32_t major = 5 + * uint32_t minor = [0|1] + * uint32_t build = [2195|2600] + * extra unicode string = e.g. "Service Pack 3" + */ + if (!StrCaseCmp(value, "OSVersion")) { + DATA_BLOB blob; + enum ndr_err_code ndr_err; + struct spoolss_OSVersion os; + + os.major = 5; /* Windows 2000 == 5.0 */ + os.minor = 0; + os.build = 2195; /* build */ + os.extra_string = ""; /* leave extra string empty */ + + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &os, + (ndr_push_flags_fn_t)ndr_push_spoolss_OSVersion); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_GENERAL_FAILURE; + } + + *type = REG_BINARY; + data->binary = blob; + + return WERR_OK; + } + + + if (!StrCaseCmp(value, "DefaultSpoolDirectory")) { + *type = REG_SZ; + + data->string = talloc_strdup(mem_ctx, "C:\\PRINTERS"); + W_ERROR_HAVE_NO_MEMORY(data->string); + + return WERR_OK; + } + + if (!StrCaseCmp(value, "Architecture")) { + *type = REG_SZ; + data->string = talloc_strdup(mem_ctx, + lp_parm_const_string(GLOBAL_SECTION_SNUM, "spoolss", "architecture", SPOOLSS_ARCHITECTURE_NT_X86)); + W_ERROR_HAVE_NO_MEMORY(data->string); + + return WERR_OK; + } + + if (!StrCaseCmp(value, "DsPresent")) { + *type = REG_DWORD; + + /* only show the publish check box if we are a + member of a AD domain */ + + if (lp_security() == SEC_ADS) { + data->value = 0x01; + } else { + data->value = 0x00; + } + return WERR_OK; + } + + if (!StrCaseCmp(value, "DNSMachineName")) { + const char *hostname = get_mydnsfullname(); + + if (!hostname) { + return WERR_BADFILE; + } + + *type = REG_SZ; + data->string = talloc_strdup(mem_ctx, hostname); + W_ERROR_HAVE_NO_MEMORY(data->string); + + return WERR_OK; + } + + *type = REG_NONE; + + return WERR_INVALID_PARAM; +} + +/**************************************************************** + _spoolss_GetPrinterData +****************************************************************/ + +WERROR _spoolss_GetPrinterData(struct pipes_struct *p, + struct spoolss_GetPrinterData *r) +{ + struct spoolss_GetPrinterDataEx r2; + + r2.in.handle = r->in.handle; + r2.in.key_name = "PrinterDriverData"; + r2.in.value_name = r->in.value_name; + r2.in.offered = r->in.offered; + r2.out.type = r->out.type; + r2.out.data = r->out.data; + r2.out.needed = r->out.needed; + + return _spoolss_GetPrinterDataEx(p, &r2); +} + +/********************************************************* + Connect to the client machine. +**********************************************************/ + +static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe, + struct sockaddr_storage *client_ss, const char *remote_machine) +{ + NTSTATUS ret; + struct cli_state *the_cli; + struct sockaddr_storage rm_addr; + char addr[INET6_ADDRSTRLEN]; + + if ( is_zero_addr((struct sockaddr *)client_ss) ) { + DEBUG(2,("spoolss_connect_to_client: resolving %s\n", + remote_machine)); + if ( !resolve_name( remote_machine, &rm_addr, 0x20, false) ) { + DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine)); + return false; + } + print_sockaddr(addr, sizeof(addr), &rm_addr); + } else { + rm_addr = *client_ss; + print_sockaddr(addr, sizeof(addr), &rm_addr); + DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n", + addr)); + } + + if (ismyaddr((struct sockaddr *)(void *)&rm_addr)) { + DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", + addr)); + return false; + } + + /* setup the connection */ + ret = cli_full_connection( &the_cli, global_myname(), remote_machine, + &rm_addr, 0, "IPC$", "IPC", + "", /* username */ + "", /* domain */ + "", /* password */ + 0, lp_client_signing()); + + if ( !NT_STATUS_IS_OK( ret ) ) { + DEBUG(2,("spoolss_connect_to_client: connection to [%s] failed!\n", + remote_machine )); + return false; + } + + if ( the_cli->protocol != PROTOCOL_NT1 ) { + DEBUG(0,("spoolss_connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine)); + cli_shutdown(the_cli); + return false; + } + + /* + * Ok - we have an anonymous connection to the IPC$ share. + * Now start the NT Domain stuff :-). + */ + + ret = cli_rpc_pipe_open_noauth(the_cli, &ndr_table_spoolss.syntax_id, pp_pipe); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(2,("spoolss_connect_to_client: unable to open the spoolss pipe on machine %s. Error was : %s.\n", + remote_machine, nt_errstr(ret))); + cli_shutdown(the_cli); + return false; + } + + return true; +} + +/*************************************************************************** + Connect to the client. +****************************************************************************/ + +static bool srv_spoolss_replyopenprinter(int snum, const char *printer, + uint32_t localprinter, + enum winreg_Type type, + struct policy_handle *handle, + struct notify_back_channel **_chan, + struct sockaddr_storage *client_ss, + struct messaging_context *msg_ctx) +{ + WERROR result; + NTSTATUS status; + struct notify_back_channel *chan; + + for (chan = back_channels; chan; chan = chan->next) { + if (memcmp(&chan->client_address, client_ss, + sizeof(struct sockaddr_storage)) == 0) { + break; + } + } + + /* + * If it's the first connection, contact the client + * and connect to the IPC$ share anonymously + */ + if (!chan) { + fstring unix_printer; + + /* the +2 is to strip the leading 2 backslashs */ + fstrcpy(unix_printer, printer + 2); + + chan = talloc_zero(back_channels, struct notify_back_channel); + if (!chan) { + return false; + } + chan->client_address = *client_ss; + + if (!spoolss_connect_to_client(&chan->cli_pipe, client_ss, unix_printer)) { + TALLOC_FREE(chan); + return false; + } + chan->binding_handle = chan->cli_pipe->binding_handle; + + DLIST_ADD(back_channels, chan); + + messaging_register(msg_ctx, NULL, MSG_PRINTER_NOTIFY2, + receive_notify2_message_list); + /* Tell the connections db we're now interested in printer + * notify messages. */ + serverid_register_msg_flags(messaging_server_id(msg_ctx), + true, FLAG_MSG_PRINT_NOTIFY); + } + + /* + * Tell the specific printing tdb we want messages for this printer + * by registering our PID. + */ + + if (!print_notify_register_pid(snum)) { + DEBUG(0, ("Failed to register our pid for printer %s\n", + printer)); + } + + status = dcerpc_spoolss_ReplyOpenPrinter(chan->binding_handle, + talloc_tos(), + printer, + localprinter, + type, + 0, + NULL, + handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(5, ("dcerpc_spoolss_ReplyOpenPrinter returned [%s]\n", nt_errstr(status))); + result = ntstatus_to_werror(status); + } else if (!W_ERROR_IS_OK(result)) { + DEBUG(5, ("ReplyOpenPrinter returned [%s]\n", win_errstr(result))); + } + + chan->active_connections++; + *_chan = chan; + + return (W_ERROR_IS_OK(result)); +} + +/**************************************************************** + ****************************************************************/ + +static struct spoolss_NotifyOption *dup_spoolss_NotifyOption(TALLOC_CTX *mem_ctx, + const struct spoolss_NotifyOption *r) +{ + struct spoolss_NotifyOption *option; + uint32_t i,k; + + if (!r) { + return NULL; + } + + option = talloc_zero(mem_ctx, struct spoolss_NotifyOption); + if (!option) { + return NULL; + } + + *option = *r; + + if (!option->count) { + return option; + } + + option->types = talloc_zero_array(option, + struct spoolss_NotifyOptionType, option->count); + if (!option->types) { + talloc_free(option); + return NULL; + } + + for (i=0; i < option->count; i++) { + option->types[i] = r->types[i]; + + if (option->types[i].count) { + option->types[i].fields = talloc_zero_array(option, + union spoolss_Field, option->types[i].count); + if (!option->types[i].fields) { + talloc_free(option); + return NULL; + } + for (k=0; ktypes[i].count; k++) { + option->types[i].fields[k] = + r->types[i].fields[k]; + } + } + } + + return option; +} + +/**************************************************************** + * _spoolss_RemoteFindFirstPrinterChangeNotifyEx + * + * before replying OK: status=0 a rpc call is made to the workstation + * asking ReplyOpenPrinter + * + * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe + * called from api_spoolss_rffpcnex +****************************************************************/ + +WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(struct pipes_struct *p, + struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r) +{ + int snum = -1; + struct spoolss_NotifyOption *option = r->in.notify_options; + struct sockaddr_storage client_ss; + + /* store the notify value in the printer struct */ + + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + if (!Printer) { + DEBUG(2,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: " + "Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + Printer->notify.flags = r->in.flags; + Printer->notify.options = r->in.options; + Printer->notify.printerlocal = r->in.printer_local; + Printer->notify.msg_ctx = p->msg_ctx; + + TALLOC_FREE(Printer->notify.option); + Printer->notify.option = dup_spoolss_NotifyOption(Printer, option); + + fstrcpy(Printer->notify.localmachine, r->in.local_machine); + + /* Connect to the client machine and send a ReplyOpenPrinter */ + + if ( Printer->printer_type == SPLHND_SERVER) + snum = -1; + else if ( (Printer->printer_type == SPLHND_PRINTER) && + !get_printer_snum(p, r->in.handle, &snum, NULL) ) + return WERR_BADFID; + + DEBUG(10,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: " + "client_address is %s\n", p->client_id->addr)); + + if (!interpret_string_addr(&client_ss, p->client_id->addr, + AI_NUMERICHOST)) { + return WERR_SERVER_UNAVAILABLE; + } + + if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine, + Printer->notify.printerlocal, REG_SZ, + &Printer->notify.cli_hnd, + &Printer->notify.cli_chan, + &client_ss, p->msg_ctx)) { + return WERR_SERVER_UNAVAILABLE; + } + + return WERR_OK; +} + +/******************************************************************* + * fill a notify_info_data with the servername + ********************************************************************/ + +static void spoolss_notify_server_name(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->servername); +} + +/******************************************************************* + * fill a notify_info_data with the printername (not including the servername). + ********************************************************************/ + +static void spoolss_notify_printer_name(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + /* the notify name should not contain the \\server\ part */ + const char *p = strrchr(pinfo2->printername, '\\'); + + if (!p) { + p = pinfo2->printername; + } else { + p++; + } + + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p); +} + +/******************************************************************* + * fill a notify_info_data with the servicename + ********************************************************************/ + +static void spoolss_notify_share_name(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, lp_servicename(snum)); +} + +/******************************************************************* + * fill a notify_info_data with the port name + ********************************************************************/ + +static void spoolss_notify_port_name(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->portname); +} + +/******************************************************************* + * fill a notify_info_data with the printername + * but it doesn't exist, have to see what to do + ********************************************************************/ + +static void spoolss_notify_driver_name(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->drivername); +} + +/******************************************************************* + * fill a notify_info_data with the comment + ********************************************************************/ + +static void spoolss_notify_comment(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + const char *p; + + if (*pinfo2->comment == '\0') { + p = lp_comment(snum); + } else { + p = pinfo2->comment; + } + + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p); +} + +/******************************************************************* + * fill a notify_info_data with the comment + * location = "Room 1, floor 2, building 3" + ********************************************************************/ + +static void spoolss_notify_location(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->location); +} + +/******************************************************************* + * fill a notify_info_data with the device mode + * jfm:xxxx don't to it for know but that's a real problem !!! + ********************************************************************/ + +static void spoolss_notify_devmode(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + /* for a dummy implementation we have to zero the fields */ + SETUP_SPOOLSS_NOTIFY_DATA_DEVMODE(data, NULL); +} + +/******************************************************************* + * fill a notify_info_data with the separator file name + ********************************************************************/ + +static void spoolss_notify_sepfile(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->sepfile); +} + +/******************************************************************* + * fill a notify_info_data with the print processor + * jfm:xxxx return always winprint to indicate we don't do anything to it + ********************************************************************/ + +static void spoolss_notify_print_processor(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->printprocessor); +} + +/******************************************************************* + * fill a notify_info_data with the print processor options + * jfm:xxxx send an empty string + ********************************************************************/ + +static void spoolss_notify_parameters(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->parameters); +} + +/******************************************************************* + * fill a notify_info_data with the data type + * jfm:xxxx always send RAW as data type + ********************************************************************/ + +static void spoolss_notify_datatype(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->datatype); +} + +/******************************************************************* + * fill a notify_info_data with the security descriptor + * jfm:xxxx send an null pointer to say no security desc + * have to implement security before ! + ********************************************************************/ + +static void spoolss_notify_security_desc(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(data, pinfo2->secdesc); +} + +/******************************************************************* + * fill a notify_info_data with the attributes + * jfm:xxxx a samba printer is always shared + ********************************************************************/ + +static void spoolss_notify_attributes(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->attributes); +} + +/******************************************************************* + * fill a notify_info_data with the priority + ********************************************************************/ + +static void spoolss_notify_priority(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->priority); +} + +/******************************************************************* + * fill a notify_info_data with the default priority + ********************************************************************/ + +static void spoolss_notify_default_priority(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->defaultpriority); +} + +/******************************************************************* + * fill a notify_info_data with the start time + ********************************************************************/ + +static void spoolss_notify_start_time(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->starttime); +} + +/******************************************************************* + * fill a notify_info_data with the until time + ********************************************************************/ + +static void spoolss_notify_until_time(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->untiltime); +} + +/******************************************************************* + * fill a notify_info_data with the status + ********************************************************************/ + +static void spoolss_notify_status(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + print_status_struct status; + + print_queue_length(msg_ctx, snum, &status); + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, status.status); +} + +/******************************************************************* + * fill a notify_info_data with the number of jobs queued + ********************************************************************/ + +static void spoolss_notify_cjobs(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER( + data, print_queue_length(msg_ctx, snum, NULL)); +} + +/******************************************************************* + * fill a notify_info_data with the average ppm + ********************************************************************/ + +static void spoolss_notify_average_ppm(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + /* always respond 8 pages per minutes */ + /* a little hard ! */ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->averageppm); +} + +/******************************************************************* + * fill a notify_info_data with username + ********************************************************************/ + +static void spoolss_notify_username(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, queue->fs_user); +} + +/******************************************************************* + * fill a notify_info_data with job status + ********************************************************************/ + +static void spoolss_notify_job_status(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, nt_printj_status(queue->status)); +} + +/******************************************************************* + * fill a notify_info_data with job name + ********************************************************************/ + +static void spoolss_notify_job_name(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, queue->fs_file); +} + +/******************************************************************* + * fill a notify_info_data with job status + ********************************************************************/ + +static void spoolss_notify_job_status_string(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + /* + * Now we're returning job status codes we just return a "" here. JRA. + */ + + const char *p = ""; + +#if 0 /* NO LONGER NEEDED - JRA. 02/22/2001 */ + p = "unknown"; + + switch (queue->status) { + case LPQ_QUEUED: + p = "Queued"; + break; + case LPQ_PAUSED: + p = ""; /* NT provides the paused string */ + break; + case LPQ_SPOOLING: + p = "Spooling"; + break; + case LPQ_PRINTING: + p = "Printing"; + break; + } +#endif /* NO LONGER NEEDED. */ + + SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p); +} + +/******************************************************************* + * fill a notify_info_data with job time + ********************************************************************/ + +static void spoolss_notify_job_time(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, 0); +} + +/******************************************************************* + * fill a notify_info_data with job size + ********************************************************************/ + +static void spoolss_notify_job_size(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->size); +} + +/******************************************************************* + * fill a notify_info_data with page info + ********************************************************************/ +static void spoolss_notify_total_pages(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->page_count); +} + +/******************************************************************* + * fill a notify_info_data with pages printed info. + ********************************************************************/ +static void spoolss_notify_pages_printed(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + /* Add code when back-end tracks this */ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, 0); +} + +/******************************************************************* + Fill a notify_info_data with job position. + ********************************************************************/ + +static void spoolss_notify_job_position(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->job); +} + +/******************************************************************* + Fill a notify_info_data with submitted time. + ********************************************************************/ + +static void spoolss_notify_submitted_time(struct messaging_context *msg_ctx, + int snum, + struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx) +{ + data->data.string.string = NULL; + data->data.string.size = 0; + + init_systemtime_buffer(mem_ctx, gmtime(&queue->time), + &data->data.string.string, + &data->data.string.size); + +} + +struct s_notify_info_data_table +{ + enum spoolss_NotifyType type; + uint16_t field; + const char *name; + enum spoolss_NotifyTable variable_type; + void (*fn) (struct messaging_context *msg_ctx, + int snum, struct spoolss_Notify *data, + print_queue_struct *queue, + struct spoolss_PrinterInfo2 *pinfo2, + TALLOC_CTX *mem_ctx); +}; + +/* A table describing the various print notification constants and + whether the notification data is a pointer to a variable sized + buffer, a one value uint32_t or a two value uint32_t. */ + +static const struct s_notify_info_data_table notify_info_data_table[] = +{ +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SERVER_NAME, "PRINTER_NOTIFY_FIELD_SERVER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_server_name }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PRINTER_NAME, "PRINTER_NOTIFY_FIELD_PRINTER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_printer_name }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SHARE_NAME, "PRINTER_NOTIFY_FIELD_SHARE_NAME", NOTIFY_TABLE_STRING, spoolss_notify_share_name }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PORT_NAME, "PRINTER_NOTIFY_FIELD_PORT_NAME", NOTIFY_TABLE_STRING, spoolss_notify_port_name }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DRIVER_NAME, "PRINTER_NOTIFY_FIELD_DRIVER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_driver_name }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_COMMENT, "PRINTER_NOTIFY_FIELD_COMMENT", NOTIFY_TABLE_STRING, spoolss_notify_comment }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_LOCATION, "PRINTER_NOTIFY_FIELD_LOCATION", NOTIFY_TABLE_STRING, spoolss_notify_location }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DEVMODE, "PRINTER_NOTIFY_FIELD_DEVMODE", NOTIFY_TABLE_DEVMODE, spoolss_notify_devmode }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SEPFILE, "PRINTER_NOTIFY_FIELD_SEPFILE", NOTIFY_TABLE_STRING, spoolss_notify_sepfile }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR, "PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR", NOTIFY_TABLE_STRING, spoolss_notify_print_processor }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PARAMETERS, "PRINTER_NOTIFY_FIELD_PARAMETERS", NOTIFY_TABLE_STRING, spoolss_notify_parameters }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DATATYPE, "PRINTER_NOTIFY_FIELD_DATATYPE", NOTIFY_TABLE_STRING, spoolss_notify_datatype }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NOTIFY_TABLE_SECURITYDESCRIPTOR, spoolss_notify_security_desc }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_ATTRIBUTES, "PRINTER_NOTIFY_FIELD_ATTRIBUTES", NOTIFY_TABLE_DWORD, spoolss_notify_attributes }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PRIORITY, "PRINTER_NOTIFY_FIELD_PRIORITY", NOTIFY_TABLE_DWORD, spoolss_notify_priority }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY, "PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY", NOTIFY_TABLE_DWORD, spoolss_notify_default_priority }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_START_TIME, "PRINTER_NOTIFY_FIELD_START_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_start_time }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_UNTIL_TIME, "PRINTER_NOTIFY_FIELD_UNTIL_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_until_time }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_STATUS, "PRINTER_NOTIFY_FIELD_STATUS", NOTIFY_TABLE_DWORD, spoolss_notify_status }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_STATUS_STRING, "PRINTER_NOTIFY_FIELD_STATUS_STRING", NOTIFY_TABLE_STRING, NULL }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_CJOBS, "PRINTER_NOTIFY_FIELD_CJOBS", NOTIFY_TABLE_DWORD, spoolss_notify_cjobs }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_AVERAGE_PPM, "PRINTER_NOTIFY_FIELD_AVERAGE_PPM", NOTIFY_TABLE_DWORD, spoolss_notify_average_ppm }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_TOTAL_PAGES, "PRINTER_NOTIFY_FIELD_TOTAL_PAGES", NOTIFY_TABLE_DWORD, NULL }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PAGES_PRINTED, "PRINTER_NOTIFY_FIELD_PAGES_PRINTED", NOTIFY_TABLE_DWORD, NULL }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_TOTAL_BYTES, "PRINTER_NOTIFY_FIELD_TOTAL_BYTES", NOTIFY_TABLE_DWORD, NULL }, +{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_BYTES_PRINTED, "PRINTER_NOTIFY_FIELD_BYTES_PRINTED", NOTIFY_TABLE_DWORD, NULL }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PRINTER_NAME, "JOB_NOTIFY_FIELD_PRINTER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_printer_name }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_MACHINE_NAME, "JOB_NOTIFY_FIELD_MACHINE_NAME", NOTIFY_TABLE_STRING, spoolss_notify_server_name }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PORT_NAME, "JOB_NOTIFY_FIELD_PORT_NAME", NOTIFY_TABLE_STRING, spoolss_notify_port_name }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_USER_NAME, "JOB_NOTIFY_FIELD_USER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_username }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_NOTIFY_NAME, "JOB_NOTIFY_FIELD_NOTIFY_NAME", NOTIFY_TABLE_STRING, spoolss_notify_username }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DATATYPE, "JOB_NOTIFY_FIELD_DATATYPE", NOTIFY_TABLE_STRING, spoolss_notify_datatype }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PRINT_PROCESSOR, "JOB_NOTIFY_FIELD_PRINT_PROCESSOR", NOTIFY_TABLE_STRING, spoolss_notify_print_processor }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PARAMETERS, "JOB_NOTIFY_FIELD_PARAMETERS", NOTIFY_TABLE_STRING, spoolss_notify_parameters }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DRIVER_NAME, "JOB_NOTIFY_FIELD_DRIVER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_driver_name }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DEVMODE, "JOB_NOTIFY_FIELD_DEVMODE", NOTIFY_TABLE_DEVMODE, spoolss_notify_devmode }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_STATUS, "JOB_NOTIFY_FIELD_STATUS", NOTIFY_TABLE_DWORD, spoolss_notify_job_status }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_STATUS_STRING, "JOB_NOTIFY_FIELD_STATUS_STRING", NOTIFY_TABLE_STRING, spoolss_notify_job_status_string }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR, "JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NOTIFY_TABLE_SECURITYDESCRIPTOR, NULL }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DOCUMENT, "JOB_NOTIFY_FIELD_DOCUMENT", NOTIFY_TABLE_STRING, spoolss_notify_job_name }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PRIORITY, "JOB_NOTIFY_FIELD_PRIORITY", NOTIFY_TABLE_DWORD, spoolss_notify_priority }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_POSITION, "JOB_NOTIFY_FIELD_POSITION", NOTIFY_TABLE_DWORD, spoolss_notify_job_position }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_SUBMITTED, "JOB_NOTIFY_FIELD_SUBMITTED", NOTIFY_TABLE_TIME, spoolss_notify_submitted_time }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_START_TIME, "JOB_NOTIFY_FIELD_START_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_start_time }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_UNTIL_TIME, "JOB_NOTIFY_FIELD_UNTIL_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_until_time }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_TIME, "JOB_NOTIFY_FIELD_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_job_time }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_TOTAL_PAGES, "JOB_NOTIFY_FIELD_TOTAL_PAGES", NOTIFY_TABLE_DWORD, spoolss_notify_total_pages }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PAGES_PRINTED, "JOB_NOTIFY_FIELD_PAGES_PRINTED", NOTIFY_TABLE_DWORD, spoolss_notify_pages_printed }, +{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_TOTAL_BYTES, "JOB_NOTIFY_FIELD_TOTAL_BYTES", NOTIFY_TABLE_DWORD, spoolss_notify_job_size }, +}; + +/******************************************************************* + Return the variable_type of info_data structure. +********************************************************************/ + +static enum spoolss_NotifyTable variable_type_of_notify_info_data(enum spoolss_NotifyType type, + uint16_t field) +{ + int i=0; + + for (i = 0; i < ARRAY_SIZE(notify_info_data_table); i++) { + if ( (notify_info_data_table[i].type == type) && + (notify_info_data_table[i].field == field) ) { + return notify_info_data_table[i].variable_type; + } + } + + DEBUG(5, ("invalid notify data type %d/%d\n", type, field)); + + return (enum spoolss_NotifyTable) 0; +} + +/**************************************************************************** +****************************************************************************/ + +static bool search_notify(enum spoolss_NotifyType type, + uint16_t field, + int *value) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(notify_info_data_table); i++) { + if (notify_info_data_table[i].type == type && + notify_info_data_table[i].field == field && + notify_info_data_table[i].fn != NULL) { + *value = i; + return true; + } + } + + return false; +} + +/**************************************************************************** +****************************************************************************/ + +static void construct_info_data(struct spoolss_Notify *info_data, + enum spoolss_NotifyType type, + uint16_t field, int id) +{ + info_data->type = type; + info_data->field.field = field; + info_data->variable_type = variable_type_of_notify_info_data(type, field); + info_data->job_id = id; +} + +/******************************************************************* + * + * fill a notify_info struct with info asked + * + ********************************************************************/ + +static bool construct_notify_printer_info(struct messaging_context *msg_ctx, + struct printer_handle *print_hnd, + struct spoolss_NotifyInfo *info, + struct spoolss_PrinterInfo2 *pinfo2, + int snum, + const struct spoolss_NotifyOptionType *option_type, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + int field_num,j; + enum spoolss_NotifyType type; + uint16_t field; + + struct spoolss_Notify *current_data; + print_queue_struct *queue=NULL; + + type = option_type->type; + + DEBUG(4,("construct_notify_printer_info: Notify type: [%s], number of notify info: [%d] on printer: [%s]\n", + (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"), + option_type->count, lp_servicename(snum))); + + for(field_num=0; field_num < option_type->count; field_num++) { + field = option_type->fields[field_num].field; + + DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field)); + + if (!search_notify(type, field, &j) ) + continue; + + info->notifies = TALLOC_REALLOC_ARRAY(info, info->notifies, + struct spoolss_Notify, + info->count + 1); + if (info->notifies == NULL) { + DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n")); + return false; + } + + current_data = &info->notifies[info->count]; + + construct_info_data(current_data, type, field, id); + + DEBUG(10, ("construct_notify_printer_info: " + "calling [%s] snum=%d printername=[%s])\n", + notify_info_data_table[j].name, snum, + pinfo2->printername)); + + notify_info_data_table[j].fn(msg_ctx, snum, current_data, + queue, pinfo2, mem_ctx); + + info->count++; + } + + return true; +} + +/******************************************************************* + * + * fill a notify_info struct with info asked + * + ********************************************************************/ + +static bool construct_notify_jobs_info(struct messaging_context *msg_ctx, + print_queue_struct *queue, + struct spoolss_NotifyInfo *info, + struct spoolss_PrinterInfo2 *pinfo2, + int snum, + const struct spoolss_NotifyOptionType *option_type, + uint32_t id, + TALLOC_CTX *mem_ctx) +{ + int field_num,j; + enum spoolss_NotifyType type; + uint16_t field; + struct spoolss_Notify *current_data; + + DEBUG(4,("construct_notify_jobs_info\n")); + + type = option_type->type; + + DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n", + (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"), + option_type->count)); + + for(field_num=0; field_numcount; field_num++) { + field = option_type->fields[field_num].field; + + if (!search_notify(type, field, &j) ) + continue; + + info->notifies = TALLOC_REALLOC_ARRAY(info, info->notifies, + struct spoolss_Notify, + info->count + 1); + if (info->notifies == NULL) { + DEBUG(2,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n")); + return false; + } + + current_data=&(info->notifies[info->count]); + + construct_info_data(current_data, type, field, id); + notify_info_data_table[j].fn(msg_ctx, snum, current_data, + queue, pinfo2, mem_ctx); + info->count++; + } + + return true; +} + +/* + * JFM: The enumeration is not that simple, it's even non obvious. + * + * let's take an example: I want to monitor the PRINTER SERVER for + * the printer's name and the number of jobs currently queued. + * So in the NOTIFY_OPTION, I have one NOTIFY_OPTION_TYPE structure. + * Its type is PRINTER_NOTIFY_TYPE and it has 2 fields NAME and CJOBS. + * + * I have 3 printers on the back of my server. + * + * Now the response is a NOTIFY_INFO structure, with 6 NOTIFY_INFO_DATA + * structures. + * Number Data Id + * 1 printer 1 name 1 + * 2 printer 1 cjob 1 + * 3 printer 2 name 2 + * 4 printer 2 cjob 2 + * 5 printer 3 name 3 + * 6 printer 3 name 3 + * + * that's the print server case, the printer case is even worse. + */ + +/******************************************************************* + * + * enumerate all printers on the printserver + * fill a notify_info struct with info asked + * + ********************************************************************/ + +static WERROR printserver_notify_info(struct pipes_struct *p, + struct policy_handle *hnd, + struct spoolss_NotifyInfo *info, + TALLOC_CTX *mem_ctx) +{ + int snum; + struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); + int n_services=lp_numservices(); + int i; + struct spoolss_NotifyOption *option; + struct spoolss_NotifyOptionType option_type; + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + WERROR result; + + DEBUG(4,("printserver_notify_info\n")); + + if (!Printer) + return WERR_BADFID; + + option = Printer->notify.option; + + info->version = 2; + info->notifies = NULL; + info->count = 0; + + /* a bug in xp sp2 rc2 causes it to send a fnpcn request without + sending a ffpcn() request first */ + + if ( !option ) + return WERR_BADFID; + + for (i=0; icount; i++) { + option_type = option->types[i]; + + if (option_type.type != PRINTER_NOTIFY_TYPE) + continue; + + for (snum = 0; snum < n_services; snum++) { + if (!lp_browseable(snum) || + !lp_snum_ok(snum) || + !lp_print_ok(snum)) { + continue; /* skip */ + } + + /* Maybe we should use the SYSTEM server_info here... */ + result = winreg_get_printer(mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_servicename(snum), + &pinfo2); + if (!W_ERROR_IS_OK(result)) { + DEBUG(4, ("printserver_notify_info: " + "Failed to get printer [%s]\n", + lp_servicename(snum))); + continue; + } + + + construct_notify_printer_info(p->msg_ctx, + Printer, info, + pinfo2, snum, + &option_type, snum, + mem_ctx); + + TALLOC_FREE(pinfo2); + } + } + +#if 0 + /* + * Debugging information, don't delete. + */ + + DEBUG(1,("dumping the NOTIFY_INFO\n")); + DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count)); + DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n")); + + for (i=0; icount; i++) { + DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n", + i, info->data[i].type, info->data[i].field, info->data[i].reserved, + info->data[i].id, info->data[i].size, info->data[i].enc_type)); + } +#endif + + return WERR_OK; +} + +/******************************************************************* + * + * fill a notify_info struct with info asked + * + ********************************************************************/ + +static WERROR printer_notify_info(struct pipes_struct *p, + struct policy_handle *hnd, + struct spoolss_NotifyInfo *info, + TALLOC_CTX *mem_ctx) +{ + int snum; + struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); + int i; + uint32_t id; + struct spoolss_NotifyOption *option; + struct spoolss_NotifyOptionType option_type; + int count,j; + print_queue_struct *queue=NULL; + print_status_struct status; + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + WERROR result; + + DEBUG(4,("printer_notify_info\n")); + + if (!Printer) + return WERR_BADFID; + + option = Printer->notify.option; + id = 0x0; + + info->version = 2; + info->notifies = NULL; + info->count = 0; + + /* a bug in xp sp2 rc2 causes it to send a fnpcn request without + sending a ffpcn() request first */ + + if ( !option ) + return WERR_BADFID; + + get_printer_snum(p, hnd, &snum, NULL); + + /* Maybe we should use the SYSTEM server_info here... */ + result = winreg_get_printer(mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_servicename(snum), &pinfo2); + if (!W_ERROR_IS_OK(result)) { + return WERR_BADFID; + } + + for (i=0; icount; i++) { + option_type = option->types[i]; + + switch (option_type.type) { + case PRINTER_NOTIFY_TYPE: + if (construct_notify_printer_info(p->msg_ctx, + Printer, info, + pinfo2, snum, + &option_type, id, + mem_ctx)) { + id--; + } + break; + + case JOB_NOTIFY_TYPE: + + count = print_queue_status(p->msg_ctx, snum, &queue, + &status); + + for (j=0; jmsg_ctx, + &queue[j], info, + pinfo2, snum, + &option_type, + queue[j].job, + mem_ctx); + } + + SAFE_FREE(queue); + break; + } + } + + /* + * Debugging information, don't delete. + */ + /* + DEBUG(1,("dumping the NOTIFY_INFO\n")); + DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count)); + DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n")); + + for (i=0; icount; i++) { + DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n", + i, info->data[i].type, info->data[i].field, info->data[i].reserved, + info->data[i].id, info->data[i].size, info->data[i].enc_type)); + } + */ + + talloc_free(pinfo2); + return WERR_OK; +} + +/**************************************************************** + _spoolss_RouterRefreshPrinterChangeNotify +****************************************************************/ + +WERROR _spoolss_RouterRefreshPrinterChangeNotify(struct pipes_struct *p, + struct spoolss_RouterRefreshPrinterChangeNotify *r) +{ + struct spoolss_NotifyInfo *info; + + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + WERROR result = WERR_BADFID; + + /* we always have a spoolss_NotifyInfo struct */ + info = talloc_zero(p->mem_ctx, struct spoolss_NotifyInfo); + if (!info) { + result = WERR_NOMEM; + goto done; + } + + *r->out.info = info; + + if (!Printer) { + DEBUG(2,("_spoolss_RouterRefreshPrinterChangeNotify: " + "Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + goto done; + } + + DEBUG(4,("Printer type %x\n",Printer->printer_type)); + + /* + * We are now using the change value, and + * I should check for PRINTER_NOTIFY_OPTIONS_REFRESH but as + * I don't have a global notification system, I'm sending back all the + * informations even when _NOTHING_ has changed. + */ + + /* We need to keep track of the change value to send back in + RRPCN replies otherwise our updates are ignored. */ + + Printer->notify.fnpcn = true; + + if (Printer->notify.cli_chan != NULL && + Printer->notify.cli_chan->active_connections > 0) { + DEBUG(10,("_spoolss_RouterRefreshPrinterChangeNotify: " + "Saving change value in request [%x]\n", + r->in.change_low)); + Printer->notify.change = r->in.change_low; + } + + /* just ignore the spoolss_NotifyOption */ + + switch (Printer->printer_type) { + case SPLHND_SERVER: + result = printserver_notify_info(p, r->in.handle, + info, p->mem_ctx); + break; + + case SPLHND_PRINTER: + result = printer_notify_info(p, r->in.handle, + info, p->mem_ctx); + break; + } + + Printer->notify.fnpcn = false; + +done: + return result; +} + +/******************************************************************** + ********************************************************************/ + +static WERROR create_printername(TALLOC_CTX *mem_ctx, + const char *servername, + const char *printername, + const char **printername_p) +{ + /* FIXME: add lp_force_printername() */ + + if (servername == NULL) { + *printername_p = talloc_strdup(mem_ctx, printername); + W_ERROR_HAVE_NO_MEMORY(*printername_p); + return WERR_OK; + } + + if (servername[0] == '\\' && servername[1] == '\\') { + servername += 2; + } + + *printername_p = talloc_asprintf(mem_ctx, "\\\\%s\\%s", servername, printername); + W_ERROR_HAVE_NO_MEMORY(*printername_p); + + return WERR_OK; +} + +/******************************************************************** + ********************************************************************/ + +static void compose_devicemode_devicename(struct spoolss_DeviceMode *dm, + const char *printername) +{ + if (dm == NULL) { + return; + } + + dm->devicename = talloc_strndup(dm, printername, + MIN(strlen(printername), 31)); +} + +/******************************************************************** + * construct_printer_info_0 + * fill a printer_info_0 struct + ********************************************************************/ + +static WERROR construct_printer_info0(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct spoolss_PrinterInfo2 *info2, + const char *servername, + struct spoolss_PrinterInfo0 *r, + int snum) +{ + int count; + struct printer_session_counter *session_counter; + struct timeval setuptime; + print_status_struct status; + WERROR result; + + result = create_printername(mem_ctx, servername, info2->printername, &r->printername); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + if (servername) { + r->servername = talloc_strdup(mem_ctx, servername); + W_ERROR_HAVE_NO_MEMORY(r->servername); + } else { + r->servername = NULL; + } + + count = print_queue_length(msg_ctx, snum, &status); + + /* check if we already have a counter for this printer */ + for (session_counter = counter_list; session_counter; session_counter = session_counter->next) { + if (session_counter->snum == snum) + break; + } + + /* it's the first time, add it to the list */ + if (session_counter == NULL) { + session_counter = talloc_zero(counter_list, struct printer_session_counter); + W_ERROR_HAVE_NO_MEMORY(session_counter); + session_counter->snum = snum; + session_counter->counter = 0; + DLIST_ADD(counter_list, session_counter); + } + + /* increment it */ + session_counter->counter++; + + r->cjobs = count; + r->total_jobs = 0; + r->total_bytes = 0; + + get_startup_time(&setuptime); + init_systemtime(&r->time, gmtime(&setuptime.tv_sec)); + + /* JFM: + * the global_counter should be stored in a TDB as it's common to all the clients + * and should be zeroed on samba startup + */ + r->global_counter = session_counter->counter; + r->total_pages = 0; + /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */ + SSVAL(&r->version, 0, 0x0005); /* NT 5 */ + SSVAL(&r->version, 2, 0x0893); /* build 2195 */ + r->free_build = SPOOLSS_RELEASE_BUILD; + r->spooling = 0; + r->max_spooling = 0; + r->session_counter = session_counter->counter; + r->num_error_out_of_paper = 0x0; + r->num_error_not_ready = 0x0; /* number of print failure */ + r->job_error = 0x0; + r->number_of_processors = 0x1; + r->processor_type = PROCESSOR_INTEL_PENTIUM; /* 586 Pentium ? */ + r->high_part_total_bytes = 0x0; + + /* ChangeID in milliseconds*/ + winreg_printer_get_changeid(mem_ctx, server_info, msg_ctx, + info2->sharename, &r->change_id); + + r->last_error = WERR_OK; + r->status = nt_printq_status(status.status); + r->enumerate_network_printers = 0x0; + r->c_setprinter = 0x0; + r->processor_architecture = PROCESSOR_ARCHITECTURE_INTEL; + r->processor_level = 0x6; /* 6 ???*/ + r->ref_ic = 0; + r->reserved2 = 0; + r->reserved3 = 0; + + return WERR_OK; +} + + +/******************************************************************** + * construct_printer_info1 + * fill a spoolss_PrinterInfo1 struct +********************************************************************/ + +static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx, + const struct spoolss_PrinterInfo2 *info2, + uint32_t flags, + const char *servername, + struct spoolss_PrinterInfo1 *r, + int snum) +{ + WERROR result; + + r->flags = flags; + + if (info2->comment == NULL || info2->comment[0] == '\0') { + r->comment = talloc_strdup(mem_ctx, lp_comment(snum)); + } else { + r->comment = talloc_strdup(mem_ctx, info2->comment); /* saved comment */ + } + W_ERROR_HAVE_NO_MEMORY(r->comment); + + result = create_printername(mem_ctx, servername, info2->printername, &r->name); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->description = talloc_asprintf(mem_ctx, "%s,%s,%s", + r->name, + info2->drivername, + r->comment); + W_ERROR_HAVE_NO_MEMORY(r->description); + + return WERR_OK; +} + +/******************************************************************** + * construct_printer_info2 + * fill a spoolss_PrinterInfo2 struct +********************************************************************/ + +static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct spoolss_PrinterInfo2 *info2, + const char *servername, + struct spoolss_PrinterInfo2 *r, + int snum) +{ + int count; + print_status_struct status; + WERROR result; + + count = print_queue_length(msg_ctx, snum, &status); + + if (servername) { + r->servername = talloc_strdup(mem_ctx, servername); + W_ERROR_HAVE_NO_MEMORY(r->servername); + } else { + r->servername = NULL; + } + + result = create_printername(mem_ctx, servername, info2->printername, &r->printername); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->sharename = talloc_strdup(mem_ctx, lp_servicename(snum)); + W_ERROR_HAVE_NO_MEMORY(r->sharename); + r->portname = talloc_strdup(mem_ctx, info2->portname); + W_ERROR_HAVE_NO_MEMORY(r->portname); + r->drivername = talloc_strdup(mem_ctx, info2->drivername); + W_ERROR_HAVE_NO_MEMORY(r->drivername); + + if (info2->comment[0] == '\0') { + r->comment = talloc_strdup(mem_ctx, lp_comment(snum)); + } else { + r->comment = talloc_strdup(mem_ctx, info2->comment); + } + W_ERROR_HAVE_NO_MEMORY(r->comment); + + r->location = talloc_strdup(mem_ctx, info2->location); + W_ERROR_HAVE_NO_MEMORY(r->location); + r->sepfile = talloc_strdup(mem_ctx, info2->sepfile); + W_ERROR_HAVE_NO_MEMORY(r->sepfile); + r->printprocessor = talloc_strdup(mem_ctx, info2->printprocessor); + W_ERROR_HAVE_NO_MEMORY(r->printprocessor); + r->datatype = talloc_strdup(mem_ctx, info2->datatype); + W_ERROR_HAVE_NO_MEMORY(r->datatype); + r->parameters = talloc_strdup(mem_ctx, info2->parameters); + W_ERROR_HAVE_NO_MEMORY(r->parameters); + + r->attributes = info2->attributes; + + r->priority = info2->priority; + r->defaultpriority = info2->defaultpriority; + r->starttime = info2->starttime; + r->untiltime = info2->untiltime; + r->status = nt_printq_status(status.status); + r->cjobs = count; + r->averageppm = info2->averageppm; + + copy_devicemode(mem_ctx, info2->devmode, &r->devmode); + if (!r->devmode) { + DEBUG(8,("Returning NULL Devicemode!\n")); + } + + compose_devicemode_devicename(r->devmode, r->printername); + + r->secdesc = NULL; + + if (info2->secdesc != NULL) { + /* don't use talloc_steal() here unless you do a deep steal of all + the SEC_DESC members */ + + r->secdesc = dup_sec_desc(mem_ctx, info2->secdesc); + } + + return WERR_OK; +} + +/******************************************************************** + * construct_printer_info3 + * fill a spoolss_PrinterInfo3 struct + ********************************************************************/ + +static WERROR construct_printer_info3(TALLOC_CTX *mem_ctx, + const struct spoolss_PrinterInfo2 *info2, + const char *servername, + struct spoolss_PrinterInfo3 *r, + int snum) +{ + /* These are the components of the SD we are returning. */ + + if (info2->secdesc != NULL) { + /* don't use talloc_steal() here unless you do a deep steal of all + the SEC_DESC members */ + + r->secdesc = dup_sec_desc(mem_ctx, info2->secdesc); + W_ERROR_HAVE_NO_MEMORY(r->secdesc); + } + + return WERR_OK; +} + +/******************************************************************** + * construct_printer_info4 + * fill a spoolss_PrinterInfo4 struct + ********************************************************************/ + +static WERROR construct_printer_info4(TALLOC_CTX *mem_ctx, + const struct spoolss_PrinterInfo2 *info2, + const char *servername, + struct spoolss_PrinterInfo4 *r, + int snum) +{ + WERROR result; + + result = create_printername(mem_ctx, servername, info2->printername, &r->printername); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + if (servername) { + r->servername = talloc_strdup(mem_ctx, servername); + W_ERROR_HAVE_NO_MEMORY(r->servername); + } else { + r->servername = NULL; + } + + r->attributes = info2->attributes; + + return WERR_OK; +} + +/******************************************************************** + * construct_printer_info5 + * fill a spoolss_PrinterInfo5 struct + ********************************************************************/ + +static WERROR construct_printer_info5(TALLOC_CTX *mem_ctx, + const struct spoolss_PrinterInfo2 *info2, + const char *servername, + struct spoolss_PrinterInfo5 *r, + int snum) +{ + WERROR result; + + result = create_printername(mem_ctx, servername, info2->printername, &r->printername); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->portname = talloc_strdup(mem_ctx, info2->portname); + W_ERROR_HAVE_NO_MEMORY(r->portname); + + r->attributes = info2->attributes; + + /* these two are not used by NT+ according to MSDN */ + r->device_not_selected_timeout = 0x0; /* have seen 0x3a98 */ + r->transmission_retry_timeout = 0x0; /* have seen 0xafc8 */ + + return WERR_OK; +} + +/******************************************************************** + * construct_printer_info_6 + * fill a spoolss_PrinterInfo6 struct + ********************************************************************/ + +static WERROR construct_printer_info6(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const struct spoolss_PrinterInfo2 *info2, + const char *servername, + struct spoolss_PrinterInfo6 *r, + int snum) +{ + int count; + print_status_struct status; + + count = print_queue_length(msg_ctx, snum, &status); + + r->status = nt_printq_status(status.status); + + return WERR_OK; +} + +/******************************************************************** + * construct_printer_info7 + * fill a spoolss_PrinterInfo7 struct + ********************************************************************/ + +static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const char *servername, + struct spoolss_PrinterInfo7 *r, + int snum) +{ + struct auth_serversupplied_info *server_info; + struct GUID guid; + NTSTATUS status; + + status = make_server_info_system(mem_ctx, &server_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("construct_printer_info7: " + "Could not create system server_info\n")); + return WERR_NOMEM; + } + + if (is_printer_published(mem_ctx, server_info, msg_ctx, + servername, + lp_servicename(snum), &guid, NULL)) { + r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid)); + r->action = DSPRINT_PUBLISH; + } else { + r->guid = talloc_strdup(mem_ctx, ""); + r->action = DSPRINT_UNPUBLISH; + } + W_ERROR_HAVE_NO_MEMORY(r->guid); + + TALLOC_FREE(server_info); + return WERR_OK; +} + +/******************************************************************** + * construct_printer_info8 + * fill a spoolss_PrinterInfo8 struct + ********************************************************************/ + +static WERROR construct_printer_info8(TALLOC_CTX *mem_ctx, + const struct spoolss_PrinterInfo2 *info2, + const char *servername, + struct spoolss_DeviceModeInfo *r, + int snum) +{ + WERROR result; + const char *printername; + + result = create_printername(mem_ctx, servername, info2->printername, &printername); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + copy_devicemode(mem_ctx, info2->devmode, &r->devmode); + if (!r->devmode) { + DEBUG(8,("Returning NULL Devicemode!\n")); + } + + compose_devicemode_devicename(r->devmode, printername); + + return WERR_OK; +} + + +/******************************************************************** +********************************************************************/ + +static bool snum_is_shared_printer(int snum) +{ + return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum)); +} + +/******************************************************************** + Spoolss_enumprinters. +********************************************************************/ + +static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *servername, + uint32_t level, + uint32_t flags, + union spoolss_PrinterInfo **info_p, + uint32_t *count_p) +{ + int snum; + int n_services = lp_numservices(); + union spoolss_PrinterInfo *info = NULL; + uint32_t count = 0; + WERROR result = WERR_OK; + + *count_p = 0; + *info_p = NULL; + + for (snum = 0; snum < n_services; snum++) { + + const char *printer; + struct spoolss_PrinterInfo2 *info2; + + if (!snum_is_shared_printer(snum)) { + continue; + } + + printer = lp_const_servicename(snum); + + DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", + printer, snum)); + + result = winreg_create_printer(mem_ctx, + server_info, + msg_ctx, + printer); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + union spoolss_PrinterInfo, + count + 1); + if (!info) { + result = WERR_NOMEM; + goto out; + } + + result = winreg_get_printer(mem_ctx, server_info, msg_ctx, + printer, &info2); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + switch (level) { + case 0: + result = construct_printer_info0(info, server_info, + msg_ctx, info2, + servername, + &info[count].info0, snum); + break; + case 1: + result = construct_printer_info1(info, info2, flags, + servername, + &info[count].info1, snum); + break; + case 2: + result = construct_printer_info2(info, msg_ctx, info2, + servername, + &info[count].info2, snum); + break; + case 4: + result = construct_printer_info4(info, info2, + servername, + &info[count].info4, snum); + break; + case 5: + result = construct_printer_info5(info, info2, + servername, + &info[count].info5, snum); + break; + + default: + result = WERR_UNKNOWN_LEVEL; + goto out; + } + + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + count++; + } + + *count_p = count; + *info_p = info; + + out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/******************************************************************** + * handle enumeration of printers at level 0 + ********************************************************************/ + +static WERROR enumprinters_level0(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t flags, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + DEBUG(4,("enum_all_printers_info_0\n")); + + return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, + servername, 0, flags, info, count); +} + + +/******************************************************************** +********************************************************************/ + +static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *servername, + uint32_t flags, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + DEBUG(4,("enum_all_printers_info_1\n")); + + return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, + servername, 1, flags, info, count); +} + +/******************************************************************** + enum_all_printers_info_1_local. +*********************************************************************/ + +static WERROR enum_all_printers_info_1_local(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + DEBUG(4,("enum_all_printers_info_1_local\n")); + + return enum_all_printers_info_1(mem_ctx, server_info, msg_ctx, + servername, PRINTER_ENUM_ICON8, info, count); +} + +/******************************************************************** + enum_all_printers_info_1_name. +*********************************************************************/ + +static WERROR enum_all_printers_info_1_name(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + const char *s = servername; + + DEBUG(4,("enum_all_printers_info_1_name\n")); + + if ((servername[0] == '\\') && (servername[1] == '\\')) { + s = servername + 2; + } + + if (!is_myname_or_ipaddr(s)) { + return WERR_INVALID_NAME; + } + + return enum_all_printers_info_1(mem_ctx, server_info, msg_ctx, + servername, PRINTER_ENUM_ICON8, info, count); +} + +/******************************************************************** + enum_all_printers_info_1_network. +*********************************************************************/ + +static WERROR enum_all_printers_info_1_network(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + const char *s = servername; + + DEBUG(4,("enum_all_printers_info_1_network\n")); + + /* If we respond to a enum_printers level 1 on our name with flags + set to PRINTER_ENUM_REMOTE with a list of printers then these + printers incorrectly appear in the APW browse list. + Specifically the printers for the server appear at the workgroup + level where all the other servers in the domain are + listed. Windows responds to this call with a + WERR_CAN_NOT_COMPLETE so we should do the same. */ + + if (servername[0] == '\\' && servername[1] == '\\') { + s = servername + 2; + } + + if (is_myname_or_ipaddr(s)) { + return WERR_CAN_NOT_COMPLETE; + } + + return enum_all_printers_info_1(mem_ctx, server_info, msg_ctx, + servername, PRINTER_ENUM_NAME, info, count); +} + +/******************************************************************** + * api_spoolss_enumprinters + * + * called from api_spoolss_enumprinters (see this to understand) + ********************************************************************/ + +static WERROR enum_all_printers_info_2(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + DEBUG(4,("enum_all_printers_info_2\n")); + + return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, + servername, 2, 0, info, count); +} + +/******************************************************************** + * handle enumeration of printers at level 1 + ********************************************************************/ + +static WERROR enumprinters_level1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t flags, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + /* Not all the flags are equals */ + + if (flags & PRINTER_ENUM_LOCAL) { + return enum_all_printers_info_1_local(mem_ctx, server_info, + msg_ctx, servername, info, count); + } + + if (flags & PRINTER_ENUM_NAME) { + return enum_all_printers_info_1_name(mem_ctx, server_info, + msg_ctx, servername, info, + count); + } + + if (flags & PRINTER_ENUM_NETWORK) { + return enum_all_printers_info_1_network(mem_ctx, server_info, + msg_ctx, servername, info, + count); + } + + return WERR_OK; /* NT4sp5 does that */ +} + +/******************************************************************** + * handle enumeration of printers at level 2 + ********************************************************************/ + +static WERROR enumprinters_level2(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t flags, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + if (flags & PRINTER_ENUM_LOCAL) { + + return enum_all_printers_info_2(mem_ctx, server_info, msg_ctx, + servername, + info, count); + } + + if (flags & PRINTER_ENUM_NAME) { + if (servername && !is_myname_or_ipaddr(canon_servername(servername))) { + return WERR_INVALID_NAME; + } + + return enum_all_printers_info_2(mem_ctx, server_info, msg_ctx, + servername, + info, count); + } + + if (flags & PRINTER_ENUM_REMOTE) { + return WERR_UNKNOWN_LEVEL; + } + + return WERR_OK; +} + +/******************************************************************** + * handle enumeration of printers at level 4 + ********************************************************************/ + +static WERROR enumprinters_level4(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t flags, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + DEBUG(4,("enum_all_printers_info_4\n")); + + return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, + servername, 4, flags, info, count); +} + + +/******************************************************************** + * handle enumeration of printers at level 5 + ********************************************************************/ + +static WERROR enumprinters_level5(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t flags, + const char *servername, + union spoolss_PrinterInfo **info, + uint32_t *count) +{ + DEBUG(4,("enum_all_printers_info_5\n")); + + return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, + servername, 5, flags, info, count); +} + +/**************************************************************** + _spoolss_EnumPrinters +****************************************************************/ + +WERROR _spoolss_EnumPrinters(struct pipes_struct *p, + struct spoolss_EnumPrinters *r) +{ + const struct auth_serversupplied_info *server_info = get_server_info_system(); + WERROR result; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(4,("_spoolss_EnumPrinters\n")); + + *r->out.needed = 0; + *r->out.count = 0; + *r->out.info = NULL; + + /* + * Level 1: + * flags==PRINTER_ENUM_NAME + * if name=="" then enumerates all printers + * if name!="" then enumerate the printer + * flags==PRINTER_ENUM_REMOTE + * name is NULL, enumerate printers + * Level 2: name!="" enumerates printers, name can't be NULL + * Level 3: doesn't exist + * Level 4: does a local registry lookup + * Level 5: same as Level 2 + */ + + if (r->in.server && r->in.server[0] == '\0') { + r->in.server = NULL; + } + + switch (r->in.level) { + case 0: + result = enumprinters_level0(p->mem_ctx, server_info, + p->msg_ctx, r->in.flags, + r->in.server, + r->out.info, r->out.count); + break; + case 1: + result = enumprinters_level1(p->mem_ctx, server_info, + p->msg_ctx, r->in.flags, + r->in.server, + r->out.info, r->out.count); + break; + case 2: + result = enumprinters_level2(p->mem_ctx, server_info, + p->msg_ctx, r->in.flags, + r->in.server, + r->out.info, r->out.count); + break; + case 4: + result = enumprinters_level4(p->mem_ctx, server_info, + p->msg_ctx, r->in.flags, + r->in.server, + r->out.info, r->out.count); + break; + case 5: + result = enumprinters_level5(p->mem_ctx, server_info, + p->msg_ctx, r->in.flags, + r->in.server, + r->out.info, r->out.count); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumPrinters, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************** + _spoolss_GetPrinter +****************************************************************/ + +WERROR _spoolss_GetPrinter(struct pipes_struct *p, + struct spoolss_GetPrinter *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + struct spoolss_PrinterInfo2 *info2 = NULL; + WERROR result = WERR_OK; + int snum; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + *r->out.needed = 0; + + if (Printer == NULL) { + return WERR_BADFID; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + result = winreg_get_printer(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + &info2); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + switch (r->in.level) { + case 0: + result = construct_printer_info0(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + info2, + Printer->servername, + &r->out.info->info0, + snum); + break; + case 1: + result = construct_printer_info1(p->mem_ctx, info2, + PRINTER_ENUM_ICON8, + Printer->servername, + &r->out.info->info1, snum); + break; + case 2: + result = construct_printer_info2(p->mem_ctx, p->msg_ctx, info2, + Printer->servername, + &r->out.info->info2, snum); + break; + case 3: + result = construct_printer_info3(p->mem_ctx, info2, + Printer->servername, + &r->out.info->info3, snum); + break; + case 4: + result = construct_printer_info4(p->mem_ctx, info2, + Printer->servername, + &r->out.info->info4, snum); + break; + case 5: + result = construct_printer_info5(p->mem_ctx, info2, + Printer->servername, + &r->out.info->info5, snum); + break; + case 6: + result = construct_printer_info6(p->mem_ctx, p->msg_ctx, info2, + Printer->servername, + &r->out.info->info6, snum); + break; + case 7: + result = construct_printer_info7(p->mem_ctx, p->msg_ctx, + Printer->servername, + &r->out.info->info7, snum); + break; + case 8: + result = construct_printer_info8(p->mem_ctx, info2, + Printer->servername, + &r->out.info->info8, snum); + break; + default: + result = WERR_UNKNOWN_LEVEL; + break; + } + + out: + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("_spoolss_GetPrinter: failed to construct printer info level %d - %s\n", + r->in.level, win_errstr(result))); + TALLOC_FREE(r->out.info); + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_PrinterInfo, + r->out.info, r->in.level); + r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/******************************************************************** + ********************************************************************/ + +#define FILL_DRIVER_STRING(mem_ctx, in, out) \ + do { \ + if (in && strlen(in)) { \ + out = talloc_strdup(mem_ctx, in); \ + } else { \ + out = talloc_strdup(mem_ctx, ""); \ + } \ + W_ERROR_HAVE_NO_MEMORY(out); \ + } while (0); + +#define FILL_DRIVER_UNC_STRING(mem_ctx, server, arch, ver, in, out) \ + do { \ + if (in && strlen(in)) { \ + out = talloc_asprintf(mem_ctx, "\\\\%s\\print$\\%s\\%d\\%s", server, get_short_archi(arch), ver, in); \ + } else { \ + out = talloc_strdup(mem_ctx, ""); \ + } \ + W_ERROR_HAVE_NO_MEMORY(out); \ + } while (0); + +static WERROR string_array_from_driver_info(TALLOC_CTX *mem_ctx, + const char **string_array, + const char ***presult, + const char *cservername, + const char *arch, + int version) +{ + int i, num_strings = 0; + const char **array = NULL; + + if (string_array == NULL) { + return WERR_INVALID_PARAMETER; + } + + for (i=0; string_array[i] && string_array[i][0] != '\0'; i++) { + const char *str = NULL; + + if (cservername == NULL || arch == NULL) { + FILL_DRIVER_STRING(mem_ctx, string_array[i], str); + } else { + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, arch, version, string_array[i], str); + } + + if (!add_string_to_array(mem_ctx, str, &array, &num_strings)) { + TALLOC_FREE(array); + return WERR_NOMEM; + } + } + + if (i > 0) { + ADD_TO_ARRAY(mem_ctx, const char *, NULL, + &array, &num_strings); + } + + if (presult) { + *presult = array; + } + + return WERR_OK; +} + +/******************************************************************** + * fill a spoolss_DriverInfo1 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo1 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) +{ + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + + return WERR_OK; +} + +/******************************************************************** + * fill a spoolss_DriverInfo2 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo2 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) + +{ + const char *cservername = canon_servername(servername); + + r->version = driver->version; + + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->architecture); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->driver_path, + r->driver_path); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->data_file, + r->data_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->config_file, + r->config_file); + + return WERR_OK; +} + +/******************************************************************** + * fill a spoolss_DriverInfo3 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo3 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + + r->version = driver->version; + + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->architecture); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->driver_path, + r->driver_path); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->data_file, + r->data_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->config_file, + r->config_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->help_file, + r->help_file); + + FILL_DRIVER_STRING(mem_ctx, + driver->monitor_name, + r->monitor_name); + + FILL_DRIVER_STRING(mem_ctx, + driver->default_datatype, + r->default_datatype); + + return string_array_from_driver_info(mem_ctx, + driver->dependent_files, + &r->dependent_files, + cservername, + driver->architecture, + driver->version); +} + +/******************************************************************** + * fill a spoolss_DriverInfo4 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info4(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo4 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + WERROR result; + + r->version = driver->version; + + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->architecture); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->driver_path, + r->driver_path); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->data_file, + r->data_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->config_file, + r->config_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->help_file, + r->help_file); + + result = string_array_from_driver_info(mem_ctx, + driver->dependent_files, + &r->dependent_files, + cservername, + driver->architecture, + driver->version); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + FILL_DRIVER_STRING(mem_ctx, + driver->monitor_name, + r->monitor_name); + + FILL_DRIVER_STRING(mem_ctx, + driver->default_datatype, + r->default_datatype); + + + result = string_array_from_driver_info(mem_ctx, + driver->previous_names, + &r->previous_names, + NULL, NULL, 0); + + return result; +} + +/******************************************************************** + * fill a spoolss_DriverInfo5 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info5(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo5 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + + r->version = driver->version; + + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->architecture); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->driver_path, + r->driver_path); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->data_file, + r->data_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->config_file, + r->config_file); + + r->driver_attributes = 0; + r->config_version = 0; + r->driver_version = 0; + + return WERR_OK; +} +/******************************************************************** + * fill a spoolss_DriverInfo6 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo6 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + WERROR result; + + r->version = driver->version; + + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->architecture); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->driver_path, + r->driver_path); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->data_file, + r->data_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->config_file, + r->config_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->help_file, + r->help_file); + + FILL_DRIVER_STRING(mem_ctx, + driver->monitor_name, + r->monitor_name); + + FILL_DRIVER_STRING(mem_ctx, + driver->default_datatype, + r->default_datatype); + + result = string_array_from_driver_info(mem_ctx, + driver->dependent_files, + &r->dependent_files, + cservername, + driver->architecture, + driver->version); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + result = string_array_from_driver_info(mem_ctx, + driver->previous_names, + &r->previous_names, + NULL, NULL, 0); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->driver_date = driver->driver_date; + r->driver_version = driver->driver_version; + + FILL_DRIVER_STRING(mem_ctx, + driver->manufacturer_name, + r->manufacturer_name); + FILL_DRIVER_STRING(mem_ctx, + driver->manufacturer_url, + r->manufacturer_url); + FILL_DRIVER_STRING(mem_ctx, + driver->hardware_id, + r->hardware_id); + FILL_DRIVER_STRING(mem_ctx, + driver->provider, + r->provider); + + return WERR_OK; +} + +/******************************************************************** + * fill a spoolss_DriverInfo8 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info8(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo8 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + WERROR result; + + r->version = driver->version; + + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->architecture); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->driver_path, + r->driver_path); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->data_file, + r->data_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->config_file, + r->config_file); + + FILL_DRIVER_UNC_STRING(mem_ctx, cservername, + driver->architecture, + driver->version, + driver->help_file, + r->help_file); + + FILL_DRIVER_STRING(mem_ctx, + driver->monitor_name, + r->monitor_name); + + FILL_DRIVER_STRING(mem_ctx, + driver->default_datatype, + r->default_datatype); + + result = string_array_from_driver_info(mem_ctx, + driver->dependent_files, + &r->dependent_files, + cservername, + driver->architecture, + driver->version); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + result = string_array_from_driver_info(mem_ctx, + driver->previous_names, + &r->previous_names, + NULL, NULL, 0); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->driver_date = driver->driver_date; + r->driver_version = driver->driver_version; + + FILL_DRIVER_STRING(mem_ctx, + driver->manufacturer_name, + r->manufacturer_name); + FILL_DRIVER_STRING(mem_ctx, + driver->manufacturer_url, + r->manufacturer_url); + FILL_DRIVER_STRING(mem_ctx, + driver->hardware_id, + r->hardware_id); + FILL_DRIVER_STRING(mem_ctx, + driver->provider, + r->provider); + + FILL_DRIVER_STRING(mem_ctx, + driver->print_processor, + r->print_processor); + FILL_DRIVER_STRING(mem_ctx, + driver->vendor_setup, + r->vendor_setup); + + result = string_array_from_driver_info(mem_ctx, + driver->color_profiles, + &r->color_profiles, + NULL, NULL, 0); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + FILL_DRIVER_STRING(mem_ctx, + driver->inf_path, + r->inf_path); + + r->printer_driver_attributes = driver->printer_driver_attributes; + + result = string_array_from_driver_info(mem_ctx, + driver->core_driver_dependencies, + &r->core_driver_dependencies, + NULL, NULL, 0); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->min_inbox_driver_ver_date = driver->min_inbox_driver_ver_date; + r->min_inbox_driver_ver_version = driver->min_inbox_driver_ver_version; + + return WERR_OK; +} + +#if 0 /* disabled until marshalling issues are resolved - gd */ +/******************************************************************** + ********************************************************************/ + +static WERROR fill_spoolss_DriverFileInfo(TALLOC_CTX *mem_ctx, + struct spoolss_DriverFileInfo *r, + const char *cservername, + const char *file_name, + enum spoolss_DriverFileType file_type, + uint32_t file_version) +{ + r->file_name = talloc_asprintf(mem_ctx, "\\\\%s%s", + cservername, file_name); + W_ERROR_HAVE_NO_MEMORY(r->file_name); + r->file_type = file_type; + r->file_version = file_version; + + return WERR_OK; +} + +/******************************************************************** + ********************************************************************/ + +static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx, + const struct spoolss_DriverInfo8 *driver, + const char *cservername, + struct spoolss_DriverFileInfo **info_p, + uint32_t *count_p) +{ + struct spoolss_DriverFileInfo *info = NULL; + uint32_t count = 0; + WERROR result; + uint32_t i; + + *info_p = NULL; + *count_p = 0; + + if (strlen(driver->driver_path)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->driver_path, + SPOOLSS_DRIVER_FILE_TYPE_RENDERING, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->config_file)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->config_file, + SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->data_file)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->data_file, + SPOOLSS_DRIVER_FILE_TYPE_DATA, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->help_file)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->help_file, + SPOOLSS_DRIVER_FILE_TYPE_HELP, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + for (i=0; driver->dependent_files[i] && driver->dependent_files[i][0] != '\0'; i++) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->dependent_files[i], + SPOOLSS_DRIVER_FILE_TYPE_OTHER, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + *info_p = info; + *count_p = count; + + return WERR_OK; +} + +/******************************************************************** + * fill a spoolss_DriverInfo101 struct + ********************************************************************/ + +static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo101 *r, + const struct spoolss_DriverInfo8 *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + WERROR result; + + r->version = driver->version; + + r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->architecture); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + result = spoolss_DriverFileInfo_from_driver(mem_ctx, driver, + cservername, + &r->file_info, + &r->file_count); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + FILL_DRIVER_STRING(mem_ctx, + driver->monitor_name, + r->monitor_name); + + FILL_DRIVER_STRING(mem_ctx, + driver->default_datatype, + r->default_datatype); + + result = string_array_from_driver_info(mem_ctx, + driver->previous_names, + &r->previous_names, + NULL, NULL, 0); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->driver_date = driver->driver_date; + r->driver_version = driver->driver_version; + + FILL_DRIVER_STRING(mem_ctx, + driver->manufacturer_name, + r->manufacturer_name); + FILL_DRIVER_STRING(mem_ctx, + driver->manufacturer_url, + r->manufacturer_url); + FILL_DRIVER_STRING(mem_ctx, + driver->hardware_id, + r->hardware_id); + FILL_DRIVER_STRING(mem_ctx, + driver->provider, + r->provider); + + return WERR_OK; +} +#endif +/******************************************************************** + ********************************************************************/ + +static WERROR construct_printer_driver_info_level(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t level, + union spoolss_DriverInfo *r, + int snum, + const char *servername, + const char *architecture, + uint32_t version) +{ + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + struct spoolss_DriverInfo8 *driver; + WERROR result; + + if (level == 101) { + return WERR_UNKNOWN_LEVEL; + } + + result = winreg_get_printer(mem_ctx, + server_info, + msg_ctx, + lp_const_servicename(snum), + &pinfo2); + + DEBUG(8,("construct_printer_driver_info_level: status: %s\n", + win_errstr(result))); + + if (!W_ERROR_IS_OK(result)) { + return WERR_INVALID_PRINTER_NAME; + } + + result = winreg_get_driver(mem_ctx, server_info, msg_ctx, + architecture, + pinfo2->drivername, version, &driver); + + DEBUG(8,("construct_printer_driver_info_level: status: %s\n", + win_errstr(result))); + + if (!W_ERROR_IS_OK(result)) { + /* + * Is this a W2k client ? + */ + + if (version < 3) { + talloc_free(pinfo2); + return WERR_UNKNOWN_PRINTER_DRIVER; + } + + /* Yes - try again with a WinNT driver. */ + version = 2; + result = winreg_get_driver(mem_ctx, server_info, msg_ctx, + architecture, + pinfo2->drivername, + version, &driver); + DEBUG(8,("construct_printer_driver_level: status: %s\n", + win_errstr(result))); + if (!W_ERROR_IS_OK(result)) { + talloc_free(pinfo2); + return WERR_UNKNOWN_PRINTER_DRIVER; + } + } + + switch (level) { + case 1: + result = fill_printer_driver_info1(mem_ctx, &r->info1, driver, servername); + break; + case 2: + result = fill_printer_driver_info2(mem_ctx, &r->info2, driver, servername); + break; + case 3: + result = fill_printer_driver_info3(mem_ctx, &r->info3, driver, servername); + break; + case 4: + result = fill_printer_driver_info4(mem_ctx, &r->info4, driver, servername); + break; + case 5: + result = fill_printer_driver_info5(mem_ctx, &r->info5, driver, servername); + break; + case 6: + result = fill_printer_driver_info6(mem_ctx, &r->info6, driver, servername); + break; + case 8: + result = fill_printer_driver_info8(mem_ctx, &r->info8, driver, servername); + break; +#if 0 /* disabled until marshalling issues are resolved - gd */ + case 101: + result = fill_printer_driver_info101(mem_ctx, &r->info101, driver, servername); + break; +#endif + default: + result = WERR_UNKNOWN_LEVEL; + break; + } + + talloc_free(pinfo2); + talloc_free(driver); + + return result; +} + +/**************************************************************** + _spoolss_GetPrinterDriver2 +****************************************************************/ + +WERROR _spoolss_GetPrinterDriver2(struct pipes_struct *p, + struct spoolss_GetPrinterDriver2 *r) +{ + struct printer_handle *printer; + WERROR result; + + int snum; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(4,("_spoolss_GetPrinterDriver2\n")); + + if (!(printer = find_printer_index_by_hnd(p, r->in.handle))) { + DEBUG(0,("_spoolss_GetPrinterDriver2: invalid printer handle!\n")); + return WERR_INVALID_PRINTER_NAME; + } + + *r->out.needed = 0; + *r->out.server_major_version = 0; + *r->out.server_minor_version = 0; + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + result = construct_printer_driver_info_level(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->in.level, r->out.info, + snum, printer->servername, + r->in.architecture, + r->in.client_major_version); + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(r->out.info); + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_DriverInfo, + r->out.info, r->in.level); + r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + + +/**************************************************************** + _spoolss_StartPagePrinter +****************************************************************/ + +WERROR _spoolss_StartPagePrinter(struct pipes_struct *p, + struct spoolss_StartPagePrinter *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + if (!Printer) { + DEBUG(3,("_spoolss_StartPagePrinter: " + "Error in startpageprinter printer handle\n")); + return WERR_BADFID; + } + + Printer->page_started = true; + return WERR_OK; +} + +/**************************************************************** + _spoolss_EndPagePrinter +****************************************************************/ + +WERROR _spoolss_EndPagePrinter(struct pipes_struct *p, + struct spoolss_EndPagePrinter *r) +{ + int snum; + + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + if (!Printer) { + DEBUG(2,("_spoolss_EndPagePrinter: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) + return WERR_BADFID; + + Printer->page_started = false; + print_job_endpage(p->msg_ctx, snum, Printer->jobid); + + return WERR_OK; +} + +/**************************************************************** + _spoolss_StartDocPrinter +****************************************************************/ + +WERROR _spoolss_StartDocPrinter(struct pipes_struct *p, + struct spoolss_StartDocPrinter *r) +{ + struct spoolss_DocumentInfo1 *info_1; + int snum; + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + WERROR werr; + + if (!Printer) { + DEBUG(2,("_spoolss_StartDocPrinter: " + "Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (Printer->jobid) { + DEBUG(2, ("_spoolss_StartDocPrinter: " + "StartDocPrinter called twice! " + "(existing jobid = %d)\n", Printer->jobid)); + return WERR_INVALID_HANDLE; + } + + if (r->in.level != 1) { + return WERR_UNKNOWN_LEVEL; + } + + info_1 = r->in.info.info1; + + /* + * a nice thing with NT is it doesn't listen to what you tell it. + * when asked to send _only_ RAW datas, it tries to send datas + * in EMF format. + * + * So I add checks like in NT Server ... + */ + + if (info_1->datatype) { + if (strcmp(info_1->datatype, "RAW") != 0) { + *r->out.job_id = 0; + return WERR_INVALID_DATATYPE; + } + } + + /* get the share number of the printer */ + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + werr = print_job_start(p->server_info, + p->msg_ctx, + p->client_id->name, + snum, + info_1->document_name, + info_1->output_file, + Printer->devmode, + &Printer->jobid); + + /* An error occured in print_job_start() so return an appropriate + NT error code. */ + + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + Printer->document_started = true; + *r->out.job_id = Printer->jobid; + + return WERR_OK; +} + +/**************************************************************** + _spoolss_EndDocPrinter +****************************************************************/ + +WERROR _spoolss_EndDocPrinter(struct pipes_struct *p, + struct spoolss_EndDocPrinter *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + NTSTATUS status; + int snum; + + if (!Printer) { + DEBUG(2,("_spoolss_EndDocPrinter: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + Printer->document_started = false; + status = print_job_end(p->msg_ctx, snum, Printer->jobid, NORMAL_CLOSE); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2, ("_spoolss_EndDocPrinter: " + "print_job_end failed [%s]\n", + nt_errstr(status))); + } + + Printer->jobid = 0; + return ntstatus_to_werror(status); +} + +/**************************************************************** + _spoolss_WritePrinter +****************************************************************/ + +WERROR _spoolss_WritePrinter(struct pipes_struct *p, + struct spoolss_WritePrinter *r) +{ + ssize_t buffer_written; + int snum; + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + if (!Printer) { + DEBUG(2,("_spoolss_WritePrinter: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(r->in.handle))); + *r->out.num_written = r->in._data_size; + return WERR_BADFID; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) + return WERR_BADFID; + + /* print_job_write takes care of checking for PJOB_SMBD_SPOOLING */ + buffer_written = print_job_write(server_event_context(),p->msg_ctx, + snum, Printer->jobid, + (const char *)r->in.data.data, + (size_t)r->in._data_size); + if (buffer_written == (ssize_t)-1) { + *r->out.num_written = 0; + if (errno == ENOSPC) + return WERR_NO_SPOOL_SPACE; + else + return WERR_ACCESS_DENIED; + } + + *r->out.num_written = r->in._data_size; + + return WERR_OK; +} + +/******************************************************************** + * api_spoolss_getprinter + * called from the spoolss dispatcher + * + ********************************************************************/ + +static WERROR control_printer(struct policy_handle *handle, uint32_t command, + struct pipes_struct *p) +{ + const struct auth_serversupplied_info *server_info = p->server_info; + int snum; + WERROR errcode = WERR_BADFUNC; + struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); + + if (!Printer) { + DEBUG(2,("control_printer: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(handle))); + return WERR_BADFID; + } + + if (!get_printer_snum(p, handle, &snum, NULL)) + return WERR_BADFID; + + switch (command) { + case SPOOLSS_PRINTER_CONTROL_PAUSE: + errcode = print_queue_pause(server_info, p->msg_ctx, snum); + break; + case SPOOLSS_PRINTER_CONTROL_RESUME: + case SPOOLSS_PRINTER_CONTROL_UNPAUSE: + errcode = print_queue_resume(server_info, p->msg_ctx, snum); + break; + case SPOOLSS_PRINTER_CONTROL_PURGE: + errcode = print_queue_purge(server_info, p->msg_ctx, snum); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + return errcode; +} + + +/**************************************************************** + _spoolss_AbortPrinter + * From MSDN: "Deletes printer's spool file if printer is configured + * for spooling" +****************************************************************/ + +WERROR _spoolss_AbortPrinter(struct pipes_struct *p, + struct spoolss_AbortPrinter *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + int snum; + WERROR errcode = WERR_OK; + + if (!Printer) { + DEBUG(2,("_spoolss_AbortPrinter: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) + return WERR_BADFID; + + if (!Printer->document_started) { + return WERR_SPL_NO_STARTDOC; + } + + errcode = print_job_delete(p->server_info, + p->msg_ctx, + snum, + Printer->jobid); + + return errcode; +} + +/******************************************************************** + * called by spoolss_api_setprinter + * when updating a printer description + ********************************************************************/ + +static WERROR update_printer_sec(struct policy_handle *handle, + struct pipes_struct *p, + struct sec_desc_buf *secdesc_ctr) +{ + struct spoolss_security_descriptor *new_secdesc = NULL; + struct spoolss_security_descriptor *old_secdesc = NULL; + const char *printer; + WERROR result; + int snum; + + struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); + + if (!Printer || !get_printer_snum(p, handle, &snum, NULL)) { + DEBUG(2,("update_printer_sec: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(handle))); + + result = WERR_BADFID; + goto done; + } + + if (secdesc_ctr == NULL) { + DEBUG(10,("update_printer_sec: secdesc_ctr is NULL !\n")); + result = WERR_INVALID_PARAM; + goto done; + } + printer = lp_const_servicename(snum); + + /* Check the user has permissions to change the security + descriptor. By experimentation with two NT machines, the user + requires Full Access to the printer to change security + information. */ + + if ( Printer->access_granted != PRINTER_ACCESS_ADMINISTER ) { + DEBUG(4,("update_printer_sec: updated denied by printer permissions\n")); + result = WERR_ACCESS_DENIED; + goto done; + } + + /* NT seems to like setting the security descriptor even though + nothing may have actually changed. */ + result = winreg_get_printer_secdesc(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer, + &old_secdesc); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2,("update_printer_sec: winreg_get_printer_secdesc() failed\n")); + result = WERR_BADFID; + goto done; + } + + if (DEBUGLEVEL >= 10) { + struct security_acl *the_acl; + int i; + + the_acl = old_secdesc->dacl; + DEBUG(10, ("old_secdesc_ctr for %s has %d aces:\n", + printer, the_acl->num_aces)); + + for (i = 0; i < the_acl->num_aces; i++) { + DEBUG(10, ("%s 0x%08x\n", sid_string_dbg( + &the_acl->aces[i].trustee), + the_acl->aces[i].access_mask)); + } + + the_acl = secdesc_ctr->sd->dacl; + + if (the_acl) { + DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", + printer, the_acl->num_aces)); + + for (i = 0; i < the_acl->num_aces; i++) { + DEBUG(10, ("%s 0x%08x\n", sid_string_dbg( + &the_acl->aces[i].trustee), + the_acl->aces[i].access_mask)); + } + } else { + DEBUG(10, ("dacl for secdesc_ctr is NULL\n")); + } + } + + new_secdesc = sec_desc_merge(p->mem_ctx, secdesc_ctr->sd, old_secdesc); + if (new_secdesc == NULL) { + result = WERR_NOMEM; + goto done; + } + + if (security_descriptor_equal(new_secdesc, old_secdesc)) { + result = WERR_OK; + goto done; + } + + result = winreg_set_printer_secdesc(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer, + new_secdesc); + + done: + return result; +} + +/******************************************************************** + Canonicalize printer info from a client + ********************************************************************/ + +static bool check_printer_ok(TALLOC_CTX *mem_ctx, + struct spoolss_SetPrinterInfo2 *info2, + int snum) +{ + fstring printername; + const char *p; + + DEBUG(5,("check_printer_ok: servername=%s printername=%s sharename=%s " + "portname=%s drivername=%s comment=%s location=%s\n", + info2->servername, info2->printername, info2->sharename, + info2->portname, info2->drivername, info2->comment, + info2->location)); + + /* we force some elements to "correct" values */ + info2->servername = talloc_asprintf(mem_ctx, "\\\\%s", global_myname()); + if (info2->servername == NULL) { + return false; + } + info2->sharename = talloc_strdup(mem_ctx, lp_const_servicename(snum)); + if (info2->sharename == NULL) { + return false; + } + + /* check to see if we allow printername != sharename */ + if (lp_force_printername(snum)) { + info2->printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", + global_myname(), info2->sharename); + } else { + /* make sure printername is in \\server\printername format */ + fstrcpy(printername, info2->printername); + p = printername; + if ( printername[0] == '\\' && printername[1] == '\\' ) { + if ( (p = strchr_m( &printername[2], '\\' )) != NULL ) + p++; + } + + info2->printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", + global_myname(), p); + } + if (info2->printername == NULL) { + return false; + } + + info2->attributes |= PRINTER_ATTRIBUTE_SAMBA; + info2->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA; + + return true; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR add_port_hook(TALLOC_CTX *ctx, struct security_token *token, const char *portname, const char *uri) +{ + char *cmd = lp_addport_cmd(); + char *command = NULL; + int ret; + bool is_print_op = false; + + if ( !*cmd ) { + return WERR_ACCESS_DENIED; + } + + command = talloc_asprintf(ctx, + "%s \"%s\" \"%s\"", cmd, portname, uri ); + if (!command) { + return WERR_NOMEM; + } + + if ( token ) + is_print_op = security_token_has_privilege(token, SEC_PRIV_PRINT_OPERATOR); + + DEBUG(10,("Running [%s]\n", command)); + + /********* BEGIN SePrintOperatorPrivilege **********/ + + if ( is_print_op ) + become_root(); + + ret = smbrun(command, NULL); + + if ( is_print_op ) + unbecome_root(); + + /********* END SePrintOperatorPrivilege **********/ + + DEBUGADD(10,("returned [%d]\n", ret)); + + TALLOC_FREE(command); + + if ( ret != 0 ) { + return WERR_ACCESS_DENIED; + } + + return WERR_OK; +} + +/**************************************************************************** +****************************************************************************/ + +static bool add_printer_hook(TALLOC_CTX *ctx, struct security_token *token, + struct spoolss_SetPrinterInfo2 *info2, + const char *remote_machine, + struct messaging_context *msg_ctx) +{ + char *cmd = lp_addprinter_cmd(); + char **qlines; + char *command = NULL; + int numlines; + int ret; + int fd; + bool is_print_op = false; + + if (!remote_machine) { + return false; + } + + command = talloc_asprintf(ctx, + "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", + cmd, info2->printername, info2->sharename, + info2->portname, info2->drivername, + info2->location, info2->comment, remote_machine); + if (!command) { + return false; + } + + if ( token ) + is_print_op = security_token_has_privilege(token, SEC_PRIV_PRINT_OPERATOR); + + DEBUG(10,("Running [%s]\n", command)); + + /********* BEGIN SePrintOperatorPrivilege **********/ + + if ( is_print_op ) + become_root(); + + if ( (ret = smbrun(command, &fd)) == 0 ) { + /* Tell everyone we updated smb.conf. */ + message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL); + } + + if ( is_print_op ) + unbecome_root(); + + /********* END SePrintOperatorPrivilege **********/ + + DEBUGADD(10,("returned [%d]\n", ret)); + + TALLOC_FREE(command); + + if ( ret != 0 ) { + if (fd != -1) + close(fd); + return false; + } + + /* reload our services immediately */ + become_root(); + reload_services(msg_ctx, -1, false); + unbecome_root(); + + numlines = 0; + /* Get lines and convert them back to dos-codepage */ + qlines = fd_lines_load(fd, &numlines, 0, NULL); + DEBUGADD(10,("Lines returned = [%d]\n", numlines)); + close(fd); + + /* Set the portname to what the script says the portname should be. */ + /* but don't require anything to be return from the script exit a good error code */ + + if (numlines) { + /* Set the portname to what the script says the portname should be. */ + info2->portname = talloc_strdup(ctx, qlines[0]); + DEBUGADD(6,("Line[0] = [%s]\n", qlines[0])); + } + + TALLOC_FREE(qlines); + return true; +} + +static WERROR update_dsspooler(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + int snum, + struct spoolss_SetPrinterInfo2 *printer, + struct spoolss_PrinterInfo2 *old_printer) +{ + bool force_update = (old_printer == NULL); + const char *dnsdomname; + const char *longname; + const char *uncname; + const char *spooling; + DATA_BLOB buffer; + WERROR result = WERR_OK; + + if (force_update || !strequal(printer->drivername, old_printer->drivername)) { + push_reg_sz(mem_ctx, &buffer, printer->drivername); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_DRIVERNAME, + REG_SZ, + buffer.data, + buffer.length); + + if (!force_update) { + DEBUG(10,("update_printer: changing driver [%s]! Sending event!\n", + printer->drivername)); + + notify_printer_driver(server_event_context(), msg_ctx, + snum, printer->drivername ? + printer->drivername : ""); + } + } + + if (force_update || !strequal(printer->comment, old_printer->comment)) { + push_reg_sz(mem_ctx, &buffer, printer->comment); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_DESCRIPTION, + REG_SZ, + buffer.data, + buffer.length); + + if (!force_update) { + notify_printer_comment(server_event_context(), msg_ctx, + snum, printer->comment ? + printer->comment : ""); + } + } + + if (force_update || !strequal(printer->sharename, old_printer->sharename)) { + push_reg_sz(mem_ctx, &buffer, printer->sharename); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRINTSHARENAME, + REG_SZ, + buffer.data, + buffer.length); + + if (!force_update) { + notify_printer_sharename(server_event_context(), + msg_ctx, + snum, printer->sharename ? + printer->sharename : ""); + } + } + + if (force_update || !strequal(printer->printername, old_printer->printername)) { + const char *p; + + p = strrchr(printer->printername, '\\' ); + if (p != NULL) { + p++; + } else { + p = printer->printername; + } + + push_reg_sz(mem_ctx, &buffer, p); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRINTERNAME, + REG_SZ, + buffer.data, + buffer.length); + + if (!force_update) { + notify_printer_printername(server_event_context(), + msg_ctx, snum, p ? p : ""); + } + } + + if (force_update || !strequal(printer->portname, old_printer->portname)) { + push_reg_sz(mem_ctx, &buffer, printer->portname); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PORTNAME, + REG_SZ, + buffer.data, + buffer.length); + + if (!force_update) { + notify_printer_port(server_event_context(), + msg_ctx, snum, printer->portname ? + printer->portname : ""); + } + } + + if (force_update || !strequal(printer->location, old_printer->location)) { + push_reg_sz(mem_ctx, &buffer, printer->location); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_LOCATION, + REG_SZ, + buffer.data, + buffer.length); + + if (!force_update) { + notify_printer_location(server_event_context(), + msg_ctx, snum, + printer->location ? + printer->location : ""); + } + } + + if (force_update || !strequal(printer->sepfile, old_printer->sepfile)) { + push_reg_sz(mem_ctx, &buffer, printer->sepfile); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRINTSEPARATORFILE, + REG_SZ, + buffer.data, + buffer.length); + + if (!force_update) { + notify_printer_sepfile(server_event_context(), + msg_ctx, snum, + printer->sepfile ? + printer->sepfile : ""); + } + } + + if (force_update || printer->starttime != old_printer->starttime) { + buffer = data_blob_talloc(mem_ctx, NULL, 4); + SIVAL(buffer.data, 0, printer->starttime); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRINTSTARTTIME, + REG_DWORD, + buffer.data, + buffer.length); + } + + if (force_update || printer->untiltime != old_printer->untiltime) { + buffer = data_blob_talloc(mem_ctx, NULL, 4); + SIVAL(buffer.data, 0, printer->untiltime); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRINTENDTIME, + REG_DWORD, + buffer.data, + buffer.length); + } + + if (force_update || printer->priority != old_printer->priority) { + buffer = data_blob_talloc(mem_ctx, NULL, 4); + SIVAL(buffer.data, 0, printer->priority); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRIORITY, + REG_DWORD, + buffer.data, + buffer.length); + } + + if (force_update || printer->attributes != old_printer->attributes) { + buffer = data_blob_talloc(mem_ctx, NULL, 4); + SIVAL(buffer.data, 0, (printer->attributes & + PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS)); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRINTKEEPPRINTEDJOBS, + REG_DWORD, + buffer.data, + buffer.length); + + switch (printer->attributes & 0x3) { + case 0: + spooling = SPOOL_REGVAL_PRINTWHILESPOOLING; + break; + case 1: + spooling = SPOOL_REGVAL_PRINTAFTERSPOOLED; + break; + case 2: + spooling = SPOOL_REGVAL_PRINTDIRECT; + break; + default: + spooling = "unknown"; + } + push_reg_sz(mem_ctx, &buffer, spooling); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_PRINTSPOOLING, + REG_SZ, + buffer.data, + buffer.length); + } + + push_reg_sz(mem_ctx, &buffer, global_myname()); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_SHORTSERVERNAME, + REG_SZ, + buffer.data, + buffer.length); + + dnsdomname = get_mydnsfullname(); + if (dnsdomname != NULL && dnsdomname[0] != '\0') { + longname = talloc_strdup(mem_ctx, dnsdomname); + } else { + longname = talloc_strdup(mem_ctx, global_myname()); + } + if (longname == NULL) { + result = WERR_NOMEM; + goto done; + } + + push_reg_sz(mem_ctx, &buffer, longname); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_SERVERNAME, + REG_SZ, + buffer.data, + buffer.length); + + uncname = talloc_asprintf(mem_ctx, "\\\\%s\\%s", + global_myname(), printer->sharename); + push_reg_sz(mem_ctx, &buffer, uncname); + winreg_set_printer_dataex(mem_ctx, + server_info, + msg_ctx, + printer->sharename, + SPOOL_DSSPOOLER_KEY, + SPOOL_REG_UNCNAME, + REG_SZ, + buffer.data, + buffer.length); + +done: + return result; +} + +/******************************************************************** + * Called by spoolss_api_setprinter + * when updating a printer description. + ********************************************************************/ + +static WERROR update_printer(struct pipes_struct *p, + struct policy_handle *handle, + struct spoolss_SetPrinterInfoCtr *info_ctr, + struct spoolss_DeviceMode *devmode) +{ + uint32_t printer_mask = SPOOLSS_PRINTER_INFO_ALL; + struct spoolss_SetPrinterInfo2 *printer = info_ctr->info.info2; + struct spoolss_PrinterInfo2 *old_printer; + struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); + int snum; + WERROR result = WERR_OK; + TALLOC_CTX *tmp_ctx; + + DEBUG(8,("update_printer\n")); + + tmp_ctx = talloc_new(p->mem_ctx); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + if (!Printer) { + result = WERR_BADFID; + goto done; + } + + if (!get_printer_snum(p, handle, &snum, NULL)) { + result = WERR_BADFID; + goto done; + } + + result = winreg_get_printer(tmp_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + &old_printer); + if (!W_ERROR_IS_OK(result)) { + result = WERR_BADFID; + goto done; + } + + /* Do sanity check on the requested changes for Samba */ + if (!check_printer_ok(tmp_ctx, printer, snum)) { + result = WERR_INVALID_PARAM; + goto done; + } + + /* FIXME!!! If the driver has changed we really should verify that + it is installed before doing much else --jerry */ + + /* Check calling user has permission to update printer description */ + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { + DEBUG(3, ("update_printer: printer property change denied by handle\n")); + result = WERR_ACCESS_DENIED; + goto done; + } + + /* Call addprinter hook */ + /* Check changes to see if this is really needed */ + + if (*lp_addprinter_cmd() && + (!strequal(printer->drivername, old_printer->drivername) || + !strequal(printer->comment, old_printer->comment) || + !strequal(printer->portname, old_printer->portname) || + !strequal(printer->location, old_printer->location)) ) + { + /* add_printer_hook() will call reload_services() */ + if (!add_printer_hook(tmp_ctx, p->server_info->security_token, + printer, p->client_id->addr, + p->msg_ctx)) { + result = WERR_ACCESS_DENIED; + goto done; + } + } + + update_dsspooler(tmp_ctx, + get_server_info_system(), + p->msg_ctx, + snum, + printer, + old_printer); + + printer_mask &= ~SPOOLSS_PRINTER_INFO_SECDESC; + + if (devmode == NULL) { + printer_mask &= ~SPOOLSS_PRINTER_INFO_DEVMODE; + } + result = winreg_update_printer(tmp_ctx, + get_server_info_system(), + p->msg_ctx, + printer->sharename, + printer_mask, + printer, + devmode, + NULL); + +done: + talloc_free(tmp_ctx); + + return result; +} + +/**************************************************************************** +****************************************************************************/ +static WERROR publish_or_unpublish_printer(struct pipes_struct *p, + struct policy_handle *handle, + struct spoolss_SetPrinterInfo7 *info7) +{ +#ifdef HAVE_ADS + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + WERROR result; + int snum; + struct printer_handle *Printer; + + if ( lp_security() != SEC_ADS ) { + return WERR_UNKNOWN_LEVEL; + } + + Printer = find_printer_index_by_hnd(p, handle); + + DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action)); + + if (!Printer) + return WERR_BADFID; + + if (!get_printer_snum(p, handle, &snum, NULL)) + return WERR_BADFID; + + result = winreg_get_printer(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_servicename(snum), + &pinfo2); + if (!W_ERROR_IS_OK(result)) { + return WERR_BADFID; + } + + nt_printer_publish(pinfo2, + get_server_info_system(), + p->msg_ctx, + pinfo2, + info7->action); + + TALLOC_FREE(pinfo2); + return WERR_OK; +#else + return WERR_UNKNOWN_LEVEL; +#endif +} + +/******************************************************************** + ********************************************************************/ + +static WERROR update_printer_devmode(struct pipes_struct *p, + struct policy_handle *handle, + struct spoolss_DeviceMode *devmode) +{ + int snum; + struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); + uint32_t info2_mask = SPOOLSS_PRINTER_INFO_DEVMODE; + + DEBUG(8,("update_printer_devmode\n")); + + if (!Printer) { + return WERR_BADFID; + } + + if (!get_printer_snum(p, handle, &snum, NULL)) { + return WERR_BADFID; + } + + /* Check calling user has permission to update printer description */ + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { + DEBUG(3, ("update_printer: printer property change denied by handle\n")); + return WERR_ACCESS_DENIED; + } + + return winreg_update_printer(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + info2_mask, + NULL, + devmode, + NULL); +} + + +/**************************************************************** + _spoolss_SetPrinter +****************************************************************/ + +WERROR _spoolss_SetPrinter(struct pipes_struct *p, + struct spoolss_SetPrinter *r) +{ + WERROR result; + + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + if (!Printer) { + DEBUG(2,("_spoolss_SetPrinter: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + /* check the level */ + switch (r->in.info_ctr->level) { + case 0: + return control_printer(r->in.handle, r->in.command, p); + case 2: + result = update_printer(p, r->in.handle, + r->in.info_ctr, + r->in.devmode_ctr->devmode); + if (!W_ERROR_IS_OK(result)) + return result; + if (r->in.secdesc_ctr->sd) + result = update_printer_sec(r->in.handle, p, + r->in.secdesc_ctr); + return result; + case 3: + return update_printer_sec(r->in.handle, p, + r->in.secdesc_ctr); + case 7: + return publish_or_unpublish_printer(p, r->in.handle, + r->in.info_ctr->info.info7); + case 8: + return update_printer_devmode(p, r->in.handle, + r->in.devmode_ctr->devmode); + default: + return WERR_UNKNOWN_LEVEL; + } +} + +/**************************************************************** + _spoolss_FindClosePrinterNotify +****************************************************************/ + +WERROR _spoolss_FindClosePrinterNotify(struct pipes_struct *p, + struct spoolss_FindClosePrinterNotify *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + if (!Printer) { + DEBUG(2,("_spoolss_FindClosePrinterNotify: " + "Invalid handle (%s:%u:%u)\n", OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (Printer->notify.cli_chan != NULL && + Printer->notify.cli_chan->active_connections > 0) { + int snum = -1; + + if (Printer->printer_type == SPLHND_PRINTER) { + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + } + + srv_spoolss_replycloseprinter(snum, Printer); + } + + Printer->notify.flags=0; + Printer->notify.options=0; + Printer->notify.localmachine[0]='\0'; + Printer->notify.printerlocal=0; + TALLOC_FREE(Printer->notify.option); + + return WERR_OK; +} + +/**************************************************************** + _spoolss_AddJob +****************************************************************/ + +WERROR _spoolss_AddJob(struct pipes_struct *p, + struct spoolss_AddJob *r) +{ + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + /* this is what a NT server returns for AddJob. AddJob must fail on + * non-local printers */ + + if (r->in.level != 1) { + return WERR_UNKNOWN_LEVEL; + } + + return WERR_INVALID_PARAM; +} + +/**************************************************************************** +fill_job_info1 +****************************************************************************/ + +static WERROR fill_job_info1(TALLOC_CTX *mem_ctx, + struct spoolss_JobInfo1 *r, + const print_queue_struct *queue, + int position, int snum, + struct spoolss_PrinterInfo2 *pinfo2) +{ + struct tm *t; + + t = gmtime(&queue->time); + + r->job_id = queue->job; + + r->printer_name = talloc_strdup(mem_ctx, lp_servicename(snum)); + W_ERROR_HAVE_NO_MEMORY(r->printer_name); + r->server_name = talloc_strdup(mem_ctx, pinfo2->servername); + W_ERROR_HAVE_NO_MEMORY(r->server_name); + r->user_name = talloc_strdup(mem_ctx, queue->fs_user); + W_ERROR_HAVE_NO_MEMORY(r->user_name); + r->document_name = talloc_strdup(mem_ctx, queue->fs_file); + W_ERROR_HAVE_NO_MEMORY(r->document_name); + r->data_type = talloc_strdup(mem_ctx, "RAW"); + W_ERROR_HAVE_NO_MEMORY(r->data_type); + r->text_status = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->text_status); + + r->status = nt_printj_status(queue->status); + r->priority = queue->priority; + r->position = position; + r->total_pages = queue->page_count; + r->pages_printed = 0; /* ??? */ + + init_systemtime(&r->submitted, t); + + return WERR_OK; +} + +/**************************************************************************** +fill_job_info2 +****************************************************************************/ + +static WERROR fill_job_info2(TALLOC_CTX *mem_ctx, + struct spoolss_JobInfo2 *r, + const print_queue_struct *queue, + int position, int snum, + struct spoolss_PrinterInfo2 *pinfo2, + struct spoolss_DeviceMode *devmode) +{ + struct tm *t; + + t = gmtime(&queue->time); + + r->job_id = queue->job; + + r->printer_name = talloc_strdup(mem_ctx, lp_servicename(snum)); + W_ERROR_HAVE_NO_MEMORY(r->printer_name); + r->server_name = talloc_strdup(mem_ctx, pinfo2->servername); + W_ERROR_HAVE_NO_MEMORY(r->server_name); + r->user_name = talloc_strdup(mem_ctx, queue->fs_user); + W_ERROR_HAVE_NO_MEMORY(r->user_name); + r->document_name = talloc_strdup(mem_ctx, queue->fs_file); + W_ERROR_HAVE_NO_MEMORY(r->document_name); + r->notify_name = talloc_strdup(mem_ctx, queue->fs_user); + W_ERROR_HAVE_NO_MEMORY(r->notify_name); + r->data_type = talloc_strdup(mem_ctx, "RAW"); + W_ERROR_HAVE_NO_MEMORY(r->data_type); + r->print_processor = talloc_strdup(mem_ctx, "winprint"); + W_ERROR_HAVE_NO_MEMORY(r->print_processor); + r->parameters = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->parameters); + r->driver_name = talloc_strdup(mem_ctx, pinfo2->drivername); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + + r->devmode = devmode; + + r->text_status = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->text_status); + + r->secdesc = NULL; + + r->status = nt_printj_status(queue->status); + r->priority = queue->priority; + r->position = position; + r->start_time = 0; + r->until_time = 0; + r->total_pages = queue->page_count; + r->size = queue->size; + init_systemtime(&r->submitted, t); + r->time = 0; + r->pages_printed = 0; /* ??? */ + + return WERR_OK; +} + +/**************************************************************************** +fill_job_info3 +****************************************************************************/ + +static WERROR fill_job_info3(TALLOC_CTX *mem_ctx, + struct spoolss_JobInfo3 *r, + const print_queue_struct *queue, + const print_queue_struct *next_queue, + int position, int snum, + struct spoolss_PrinterInfo2 *pinfo2) +{ + r->job_id = queue->job; + r->next_job_id = 0; + if (next_queue) { + r->next_job_id = next_queue->job; + } + r->reserved = 0; + + return WERR_OK; +} + +/**************************************************************************** + Enumjobs at level 1. +****************************************************************************/ + +static WERROR enumjobs_level1(TALLOC_CTX *mem_ctx, + const print_queue_struct *queue, + uint32_t num_queues, int snum, + struct spoolss_PrinterInfo2 *pinfo2, + union spoolss_JobInfo **info_p, + uint32_t *count) +{ + union spoolss_JobInfo *info; + int i; + WERROR result = WERR_OK; + + info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues); + W_ERROR_HAVE_NO_MEMORY(info); + + *count = num_queues; + + for (i=0; i<*count; i++) { + result = fill_job_info1(info, + &info[i].info1, + &queue[i], + i, + snum, + pinfo2); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + } + + out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + *count = 0; + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/**************************************************************************** + Enumjobs at level 2. +****************************************************************************/ + +static WERROR enumjobs_level2(TALLOC_CTX *mem_ctx, + const print_queue_struct *queue, + uint32_t num_queues, int snum, + struct spoolss_PrinterInfo2 *pinfo2, + union spoolss_JobInfo **info_p, + uint32_t *count) +{ + union spoolss_JobInfo *info; + int i; + WERROR result = WERR_OK; + + info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues); + W_ERROR_HAVE_NO_MEMORY(info); + + *count = num_queues; + + for (i=0; i<*count; i++) { + struct spoolss_DeviceMode *devmode; + + result = spoolss_create_default_devmode(info, + pinfo2->printername, + &devmode); + if (!W_ERROR_IS_OK(result)) { + DEBUG(3, ("Can't proceed w/o a devmode!")); + goto out; + } + + result = fill_job_info2(info, + &info[i].info2, + &queue[i], + i, + snum, + pinfo2, + devmode); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + } + + out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + *count = 0; + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/**************************************************************************** + Enumjobs at level 3. +****************************************************************************/ + +static WERROR enumjobs_level3(TALLOC_CTX *mem_ctx, + const print_queue_struct *queue, + uint32_t num_queues, int snum, + struct spoolss_PrinterInfo2 *pinfo2, + union spoolss_JobInfo **info_p, + uint32_t *count) +{ + union spoolss_JobInfo *info; + int i; + WERROR result = WERR_OK; + + info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues); + W_ERROR_HAVE_NO_MEMORY(info); + + *count = num_queues; + + for (i=0; i<*count; i++) { + const print_queue_struct *next_queue = NULL; + + if (i+1 < *count) { + next_queue = &queue[i+1]; + } + + result = fill_job_info3(info, + &info[i].info3, + &queue[i], + next_queue, + i, + snum, + pinfo2); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + } + + out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + *count = 0; + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/**************************************************************** + _spoolss_EnumJobs +****************************************************************/ + +WERROR _spoolss_EnumJobs(struct pipes_struct *p, + struct spoolss_EnumJobs *r) +{ + WERROR result; + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + int snum; + print_status_struct prt_status; + print_queue_struct *queue = NULL; + uint32_t count; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(4,("_spoolss_EnumJobs\n")); + + *r->out.needed = 0; + *r->out.count = 0; + *r->out.info = NULL; + + /* lookup the printer snum and tdb entry */ + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + result = winreg_get_printer(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + &pinfo2); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + count = print_queue_status(p->msg_ctx, snum, &queue, &prt_status); + DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", + count, prt_status.status, prt_status.message)); + + if (count == 0) { + SAFE_FREE(queue); + TALLOC_FREE(pinfo2); + return WERR_OK; + } + + switch (r->in.level) { + case 1: + result = enumjobs_level1(p->mem_ctx, queue, count, snum, + pinfo2, r->out.info, r->out.count); + break; + case 2: + result = enumjobs_level2(p->mem_ctx, queue, count, snum, + pinfo2, r->out.info, r->out.count); + break; + case 3: + result = enumjobs_level3(p->mem_ctx, queue, count, snum, + pinfo2, r->out.info, r->out.count); + break; + default: + result = WERR_UNKNOWN_LEVEL; + break; + } + + SAFE_FREE(queue); + TALLOC_FREE(pinfo2); + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumJobs, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************** + _spoolss_ScheduleJob +****************************************************************/ + +WERROR _spoolss_ScheduleJob(struct pipes_struct *p, + struct spoolss_ScheduleJob *r) +{ + return WERR_OK; +} + +/**************************************************************** +****************************************************************/ + +static WERROR spoolss_setjob_1(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + const char *printer_name, + uint32_t job_id, + struct spoolss_SetJobInfo1 *r) +{ + char *old_doc_name; + + if (!print_job_get_name(mem_ctx, printer_name, job_id, &old_doc_name)) { + return WERR_BADFID; + } + + if (strequal(old_doc_name, r->document_name)) { + return WERR_OK; + } + + if (!print_job_set_name(server_event_context(), msg_ctx, + printer_name, job_id, r->document_name)) { + return WERR_BADFID; + } + + return WERR_OK; +} + +/**************************************************************** + _spoolss_SetJob +****************************************************************/ + +WERROR _spoolss_SetJob(struct pipes_struct *p, + struct spoolss_SetJob *r) +{ + const struct auth_serversupplied_info *server_info = p->server_info; + int snum; + WERROR errcode = WERR_BADFUNC; + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + if (!print_job_exists(lp_const_servicename(snum), r->in.job_id)) { + return WERR_INVALID_PRINTER_NAME; + } + + switch (r->in.command) { + case SPOOLSS_JOB_CONTROL_CANCEL: + case SPOOLSS_JOB_CONTROL_DELETE: + errcode = print_job_delete(server_info, p->msg_ctx, + snum, r->in.job_id); + if (W_ERROR_EQUAL(errcode, WERR_PRINTER_HAS_JOBS_QUEUED)) { + errcode = WERR_OK; + } + break; + case SPOOLSS_JOB_CONTROL_PAUSE: + if (print_job_pause(server_info, p->msg_ctx, + snum, r->in.job_id, &errcode)) { + errcode = WERR_OK; + } + break; + case SPOOLSS_JOB_CONTROL_RESTART: + case SPOOLSS_JOB_CONTROL_RESUME: + if (print_job_resume(server_info, p->msg_ctx, + snum, r->in.job_id, &errcode)) { + errcode = WERR_OK; + } + break; + case 0: + errcode = WERR_OK; + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + if (!W_ERROR_IS_OK(errcode)) { + return errcode; + } + + if (r->in.ctr == NULL) { + return errcode; + } + + switch (r->in.ctr->level) { + case 1: + errcode = spoolss_setjob_1(p->mem_ctx, p->msg_ctx, + lp_const_servicename(snum), + r->in.job_id, + r->in.ctr->info.info1); + break; + case 2: + case 3: + case 4: + default: + return WERR_UNKNOWN_LEVEL; + } + + return errcode; +} + +/**************************************************************************** + Enumerates all printer drivers by level and architecture. +****************************************************************************/ + +static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *servername, + const char *architecture, + uint32_t level, + union spoolss_DriverInfo **info_p, + uint32_t *count_p) +{ + int i; + uint32_t version; + struct spoolss_DriverInfo8 *driver; + union spoolss_DriverInfo *info = NULL; + uint32_t count = 0; + WERROR result = WERR_OK; + uint32_t num_drivers; + const char **drivers; + + *count_p = 0; + *info_p = NULL; + + for (version=0; versionin.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(4,("_spoolss_EnumPrinterDrivers\n")); + + *r->out.needed = 0; + *r->out.count = 0; + *r->out.info = NULL; + + cservername = canon_servername(r->in.server); + + if (!is_myname_or_ipaddr(cservername)) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } + + result = enumprinterdrivers_level(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + cservername, + r->in.environment, + r->in.level, + r->out.info, + r->out.count); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumPrinterDrivers, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************** + _spoolss_EnumForms +****************************************************************/ + +WERROR _spoolss_EnumForms(struct pipes_struct *p, + struct spoolss_EnumForms *r) +{ + WERROR result; + + *r->out.count = 0; + *r->out.needed = 0; + *r->out.info = NULL; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0) ) { + return WERR_INVALID_PARAM; + } + + DEBUG(4,("_spoolss_EnumForms\n")); + DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered)); + DEBUGADD(5,("Info level [%d]\n", r->in.level)); + + switch (r->in.level) { + case 1: + result = winreg_printer_enumforms1(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->out.count, + r->out.info); + break; + default: + result = WERR_UNKNOWN_LEVEL; + break; + } + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + if (*r->out.count == 0) { + return WERR_NO_MORE_ITEMS; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumForms, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************** + _spoolss_GetForm +****************************************************************/ + +WERROR _spoolss_GetForm(struct pipes_struct *p, + struct spoolss_GetForm *r) +{ + WERROR result; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(4,("_spoolss_GetForm\n")); + DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered)); + DEBUGADD(5,("Info level [%d]\n", r->in.level)); + + switch (r->in.level) { + case 1: + result = winreg_printer_getform1(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->in.form_name, + &r->out.info->info1); + break; + default: + result = WERR_UNKNOWN_LEVEL; + break; + } + + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(r->out.info); + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_FormInfo, + r->out.info, r->in.level); + r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR fill_port_1(TALLOC_CTX *mem_ctx, + struct spoolss_PortInfo1 *r, + const char *name) +{ + r->port_name = talloc_strdup(mem_ctx, name); + W_ERROR_HAVE_NO_MEMORY(r->port_name); + + return WERR_OK; +} + +/**************************************************************************** + TODO: This probably needs distinguish between TCP/IP and Local ports + somehow. +****************************************************************************/ + +static WERROR fill_port_2(TALLOC_CTX *mem_ctx, + struct spoolss_PortInfo2 *r, + const char *name) +{ + r->port_name = talloc_strdup(mem_ctx, name); + W_ERROR_HAVE_NO_MEMORY(r->port_name); + + r->monitor_name = talloc_strdup(mem_ctx, "Local Monitor"); + W_ERROR_HAVE_NO_MEMORY(r->monitor_name); + + r->description = talloc_strdup(mem_ctx, SPL_LOCAL_PORT); + W_ERROR_HAVE_NO_MEMORY(r->description); + + r->port_type = SPOOLSS_PORT_TYPE_WRITE; + r->reserved = 0; + + return WERR_OK; +} + + +/**************************************************************************** + wrapper around the enumer ports command +****************************************************************************/ + +static WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines) +{ + char *cmd = lp_enumports_cmd(); + char **qlines = NULL; + char *command = NULL; + int numlines; + int ret; + int fd; + + *count = 0; + *lines = NULL; + + /* if no hook then just fill in the default port */ + + if ( !*cmd ) { + if (!(qlines = TALLOC_ARRAY( NULL, char*, 2 ))) { + return WERR_NOMEM; + } + if (!(qlines[0] = talloc_strdup(qlines, SAMBA_PRINTER_PORT_NAME ))) { + TALLOC_FREE(qlines); + return WERR_NOMEM; + } + qlines[1] = NULL; + numlines = 1; + } + else { + /* we have a valid enumport command */ + + command = talloc_asprintf(ctx, "%s \"%d\"", cmd, 1); + if (!command) { + return WERR_NOMEM; + } + + DEBUG(10,("Running [%s]\n", command)); + ret = smbrun(command, &fd); + DEBUG(10,("Returned [%d]\n", ret)); + TALLOC_FREE(command); + if (ret != 0) { + if (fd != -1) { + close(fd); + } + return WERR_ACCESS_DENIED; + } + + numlines = 0; + qlines = fd_lines_load(fd, &numlines, 0, NULL); + DEBUGADD(10,("Lines returned = [%d]\n", numlines)); + close(fd); + } + + *count = numlines; + *lines = qlines; + + return WERR_OK; +} + +/**************************************************************************** + enumports level 1. +****************************************************************************/ + +static WERROR enumports_level_1(TALLOC_CTX *mem_ctx, + union spoolss_PortInfo **info_p, + uint32_t *count) +{ + union spoolss_PortInfo *info = NULL; + int i=0; + WERROR result = WERR_OK; + char **qlines = NULL; + int numlines = 0; + + result = enumports_hook(talloc_tos(), &numlines, &qlines ); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + if (numlines) { + info = TALLOC_ARRAY(mem_ctx, union spoolss_PortInfo, numlines); + if (!info) { + DEBUG(10,("Returning WERR_NOMEM\n")); + result = WERR_NOMEM; + goto out; + } + + for (i=0; iin.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(4,("_spoolss_EnumPorts\n")); + + *r->out.count = 0; + *r->out.needed = 0; + *r->out.info = NULL; + + switch (r->in.level) { + case 1: + result = enumports_level_1(p->mem_ctx, r->out.info, + r->out.count); + break; + case 2: + result = enumports_level_2(p->mem_ctx, r->out.info, + r->out.count); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumPorts, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR spoolss_addprinterex_level_2(struct pipes_struct *p, + const char *server, + struct spoolss_SetPrinterInfoCtr *info_ctr, + struct spoolss_DeviceMode *devmode, + struct security_descriptor *secdesc, + struct spoolss_UserLevelCtr *user_ctr, + struct policy_handle *handle) +{ + struct spoolss_SetPrinterInfo2 *info2 = info_ctr->info.info2; + uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ALL; + int snum; + WERROR err = WERR_OK; + + /* samba does not have a concept of local, non-shared printers yet, so + * make sure we always setup sharename - gd */ + if ((info2->sharename == NULL || info2->sharename[0] == '\0') && + (info2->printername != NULL && info2->printername[0] != '\0')) { + DEBUG(5, ("spoolss_addprinterex_level_2: " + "no sharename has been set, setting printername %s as sharename\n", + info2->printername)); + info2->sharename = info2->printername; + } + + /* check to see if the printer already exists */ + if ((snum = print_queue_snum(info2->sharename)) != -1) { + DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n", + info2->sharename)); + return WERR_PRINTER_ALREADY_EXISTS; + } + + if (!lp_force_printername(GLOBAL_SECTION_SNUM)) { + if ((snum = print_queue_snum(info2->printername)) != -1) { + DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n", + info2->printername)); + return WERR_PRINTER_ALREADY_EXISTS; + } + } + + /* validate printer info struct */ + if (!info2->printername || strlen(info2->printername) == 0) { + return WERR_INVALID_PRINTER_NAME; + } + if (!info2->portname || strlen(info2->portname) == 0) { + return WERR_UNKNOWN_PORT; + } + if (!info2->drivername || strlen(info2->drivername) == 0) { + return WERR_UNKNOWN_PRINTER_DRIVER; + } + if (!info2->printprocessor || strlen(info2->printprocessor) == 0) { + return WERR_UNKNOWN_PRINTPROCESSOR; + } + + /* FIXME!!! smbd should check to see if the driver is installed before + trying to add a printer like this --jerry */ + + if (*lp_addprinter_cmd() ) { + if ( !add_printer_hook(p->mem_ctx, p->server_info->security_token, + info2, p->client_id->addr, + p->msg_ctx) ) { + return WERR_ACCESS_DENIED; + } + } else { + DEBUG(0,("spoolss_addprinterex_level_2: add printer for printer %s called and no" + "smb.conf parameter \"addprinter command\" is defined. This" + "parameter must exist for this call to succeed\n", + info2->sharename )); + } + + if ((snum = print_queue_snum(info2->sharename)) == -1) { + return WERR_ACCESS_DENIED; + } + + /* you must be a printer admin to add a new printer */ + if (!print_access_check(p->server_info, + p->msg_ctx, + snum, + PRINTER_ACCESS_ADMINISTER)) { + return WERR_ACCESS_DENIED; + } + + /* + * Do sanity check on the requested changes for Samba. + */ + + if (!check_printer_ok(p->mem_ctx, info2, snum)) { + return WERR_INVALID_PARAM; + } + + if (devmode == NULL) { + info2_mask = ~SPOOLSS_PRINTER_INFO_DEVMODE; + } + + update_dsspooler(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + 0, + info2, + NULL); + + err = winreg_update_printer(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + info2->sharename, + info2_mask, + info2, + devmode, + secdesc); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + err = open_printer_hnd(p, handle, info2->printername, PRINTER_ACCESS_ADMINISTER); + if (!W_ERROR_IS_OK(err)) { + /* Handle open failed - remove addition. */ + ZERO_STRUCTP(handle); + return err; + } + + return WERR_OK; +} + +/**************************************************************** + _spoolss_AddPrinterEx +****************************************************************/ + +WERROR _spoolss_AddPrinterEx(struct pipes_struct *p, + struct spoolss_AddPrinterEx *r) +{ + switch (r->in.info_ctr->level) { + case 1: + /* we don't handle yet */ + /* but I know what to do ... */ + return WERR_UNKNOWN_LEVEL; + case 2: + return spoolss_addprinterex_level_2(p, r->in.server, + r->in.info_ctr, + r->in.devmode_ctr->devmode, + r->in.secdesc_ctr->sd, + r->in.userlevel_ctr, + r->out.handle); + default: + return WERR_UNKNOWN_LEVEL; + } +} + +/**************************************************************** + _spoolss_AddPrinter +****************************************************************/ + +WERROR _spoolss_AddPrinter(struct pipes_struct *p, + struct spoolss_AddPrinter *r) +{ + struct spoolss_AddPrinterEx a; + struct spoolss_UserLevelCtr userlevel_ctr; + + ZERO_STRUCT(userlevel_ctr); + + userlevel_ctr.level = 1; + + a.in.server = r->in.server; + a.in.info_ctr = r->in.info_ctr; + a.in.devmode_ctr = r->in.devmode_ctr; + a.in.secdesc_ctr = r->in.secdesc_ctr; + a.in.userlevel_ctr = &userlevel_ctr; + a.out.handle = r->out.handle; + + return _spoolss_AddPrinterEx(p, &a); +} + +/**************************************************************** + _spoolss_AddPrinterDriverEx +****************************************************************/ + +WERROR _spoolss_AddPrinterDriverEx(struct pipes_struct *p, + struct spoolss_AddPrinterDriverEx *r) +{ + WERROR err = WERR_OK; + const char *driver_name = NULL; + uint32_t version; + const char *fn; + + switch (p->opnum) { + case NDR_SPOOLSS_ADDPRINTERDRIVER: + fn = "_spoolss_AddPrinterDriver"; + break; + case NDR_SPOOLSS_ADDPRINTERDRIVEREX: + fn = "_spoolss_AddPrinterDriverEx"; + break; + default: + return WERR_INVALID_PARAM; + } + + /* + * we only support the semantics of AddPrinterDriver() + * i.e. only copy files that are newer than existing ones + */ + + if (r->in.flags == 0) { + return WERR_INVALID_PARAM; + } + + if (r->in.flags != APD_COPY_NEW_FILES) { + return WERR_ACCESS_DENIED; + } + + /* FIXME */ + if (r->in.info_ctr->level != 3 && r->in.info_ctr->level != 6) { + /* Clever hack from Martin Zielinski + * to allow downgrade from level 8 (Vista). + */ + DEBUG(0,("%s: level %d not yet implemented\n", fn, + r->in.info_ctr->level)); + return WERR_UNKNOWN_LEVEL; + } + + DEBUG(5,("Cleaning driver's information\n")); + err = clean_up_driver_struct(p->mem_ctx, p, r->in.info_ctr); + if (!W_ERROR_IS_OK(err)) + goto done; + + DEBUG(5,("Moving driver to final destination\n")); + if( !W_ERROR_IS_OK(err = move_driver_to_download_area(p, r->in.info_ctr, + &err)) ) { + goto done; + } + + err = winreg_add_driver(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + r->in.info_ctr, + &driver_name, + &version); + if (!W_ERROR_IS_OK(err)) { + goto done; + } + + /* + * I think this is where he DrvUpgradePrinter() hook would be + * be called in a driver's interface DLL on a Windows NT 4.0/2k + * server. Right now, we just need to send ourselves a message + * to update each printer bound to this driver. --jerry + */ + + if (!srv_spoolss_drv_upgrade_printer(driver_name, p->msg_ctx)) { + DEBUG(0,("%s: Failed to send message about upgrading driver [%s]!\n", + fn, driver_name)); + } + +done: + return err; +} + +/**************************************************************** + _spoolss_AddPrinterDriver +****************************************************************/ + +WERROR _spoolss_AddPrinterDriver(struct pipes_struct *p, + struct spoolss_AddPrinterDriver *r) +{ + struct spoolss_AddPrinterDriverEx a; + + switch (r->in.info_ctr->level) { + case 2: + case 3: + case 4: + case 5: + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + a.in.servername = r->in.servername; + a.in.info_ctr = r->in.info_ctr; + a.in.flags = APD_COPY_NEW_FILES; + + return _spoolss_AddPrinterDriverEx(p, &a); +} + +/**************************************************************************** +****************************************************************************/ + +struct _spoolss_paths { + int type; + const char *share; + const char *dir; +}; + +enum { SPOOLSS_DRIVER_PATH, SPOOLSS_PRTPROCS_PATH }; + +static const struct _spoolss_paths spoolss_paths[]= { + { SPOOLSS_DRIVER_PATH, "print$", "DRIVERS" }, + { SPOOLSS_PRTPROCS_PATH, "prnproc$", "PRTPROCS" } +}; + +static WERROR compose_spoolss_server_path(TALLOC_CTX *mem_ctx, + const char *servername, + const char *environment, + int component, + char **path) +{ + const char *pservername = NULL; + const char *long_archi = SPOOLSS_ARCHITECTURE_NT_X86; + const char *short_archi; + + *path = NULL; + + /* environment may be empty */ + if (environment && strlen(environment)) { + long_archi = environment; + } + + /* servername may be empty */ + if (servername && strlen(servername)) { + pservername = canon_servername(servername); + + if (!is_myname_or_ipaddr(pservername)) { + return WERR_INVALID_PARAM; + } + } + + if (!(short_archi = get_short_archi(long_archi))) { + return WERR_INVALID_ENVIRONMENT; + } + + switch (component) { + case SPOOLSS_PRTPROCS_PATH: + case SPOOLSS_DRIVER_PATH: + if (pservername) { + *path = talloc_asprintf(mem_ctx, + "\\\\%s\\%s\\%s", + pservername, + spoolss_paths[component].share, + short_archi); + } else { + *path = talloc_asprintf(mem_ctx, "%s\\%s\\%s", + SPOOLSS_DEFAULT_SERVER_PATH, + spoolss_paths[component].dir, + short_archi); + } + break; + default: + return WERR_INVALID_PARAM; + } + + if (!*path) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR getprinterdriverdir_level_1(TALLOC_CTX *mem_ctx, + const char *servername, + const char *environment, + struct spoolss_DriverDirectoryInfo1 *r) +{ + WERROR werr; + char *path = NULL; + + werr = compose_spoolss_server_path(mem_ctx, + servername, + environment, + SPOOLSS_DRIVER_PATH, + &path); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + DEBUG(4,("printer driver directory: [%s]\n", path)); + + r->directory_name = path; + + return WERR_OK; +} + +/**************************************************************** + _spoolss_GetPrinterDriverDirectory +****************************************************************/ + +WERROR _spoolss_GetPrinterDriverDirectory(struct pipes_struct *p, + struct spoolss_GetPrinterDriverDirectory *r) +{ + WERROR werror; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(5,("_spoolss_GetPrinterDriverDirectory: level %d\n", + r->in.level)); + + *r->out.needed = 0; + + /* r->in.level is ignored */ + + werror = getprinterdriverdir_level_1(p->mem_ctx, + r->in.server, + r->in.environment, + &r->out.info->info1); + if (!W_ERROR_IS_OK(werror)) { + TALLOC_FREE(r->out.info); + return werror; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_DriverDirectoryInfo, + r->out.info, r->in.level); + r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************** + _spoolss_EnumPrinterData +****************************************************************/ + +WERROR _spoolss_EnumPrinterData(struct pipes_struct *p, + struct spoolss_EnumPrinterData *r) +{ + WERROR result; + struct spoolss_EnumPrinterDataEx r2; + uint32_t count; + struct spoolss_PrinterEnumValues *info, *val = NULL; + uint32_t needed; + + r2.in.handle = r->in.handle; + r2.in.key_name = "PrinterDriverData"; + r2.in.offered = 0; + r2.out.count = &count; + r2.out.info = &info; + r2.out.needed = &needed; + + result = _spoolss_EnumPrinterDataEx(p, &r2); + if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) { + r2.in.offered = needed; + result = _spoolss_EnumPrinterDataEx(p, &r2); + } + if (!W_ERROR_IS_OK(result)) { + return result; + } + + /* + * The NT machine wants to know the biggest size of value and data + * + * cf: MSDN EnumPrinterData remark section + */ + + if (!r->in.value_offered && !r->in.data_offered) { + uint32_t biggest_valuesize = 0; + uint32_t biggest_datasize = 0; + int i, name_length; + + DEBUGADD(6,("Activating NT mega-hack to find sizes\n")); + + for (i=0; i biggest_valuesize) { + biggest_valuesize = name_length; + } + + if (info[i].data_length > biggest_datasize) { + biggest_datasize = info[i].data_length; + } + + DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize, + biggest_datasize)); + } + + /* the value is an UNICODE string but real_value_size is the length + in bytes including the trailing 0 */ + + *r->out.value_needed = 2 * (1 + biggest_valuesize); + *r->out.data_needed = biggest_datasize; + + DEBUG(6,("final values: [%d], [%d]\n", + *r->out.value_needed, *r->out.data_needed)); + + return WERR_OK; + } + + if (r->in.enum_index < count) { + val = &info[r->in.enum_index]; + } + + if (val == NULL) { + /* out_value should default to "" or else NT4 has + problems unmarshalling the response */ + + if (r->in.value_offered) { + *r->out.value_needed = 1; + r->out.value_name = talloc_strdup(r, ""); + if (!r->out.value_name) { + return WERR_NOMEM; + } + } else { + r->out.value_name = NULL; + *r->out.value_needed = 0; + } + + /* the data is counted in bytes */ + + *r->out.data_needed = r->in.data_offered; + + result = WERR_NO_MORE_ITEMS; + } else { + /* + * the value is: + * - counted in bytes in the request + * - counted in UNICODE chars in the max reply + * - counted in bytes in the real size + * + * take a pause *before* coding not *during* coding + */ + + /* name */ + if (r->in.value_offered) { + r->out.value_name = talloc_strdup(r, val->value_name); + if (!r->out.value_name) { + return WERR_NOMEM; + } + *r->out.value_needed = val->value_name_len; + } else { + r->out.value_name = NULL; + *r->out.value_needed = 0; + } + + /* type */ + + *r->out.type = val->type; + + /* data - counted in bytes */ + + /* + * See the section "Dynamically Typed Query Parameters" + * in MS-RPRN. + */ + + if (r->out.data && val->data && val->data->data && + val->data_length && r->in.data_offered) { + memcpy(r->out.data, val->data->data, + MIN(val->data_length,r->in.data_offered)); + } + + *r->out.data_needed = val->data_length; + + result = WERR_OK; + } + + return result; +} + +/**************************************************************** + _spoolss_SetPrinterData +****************************************************************/ + +WERROR _spoolss_SetPrinterData(struct pipes_struct *p, + struct spoolss_SetPrinterData *r) +{ + struct spoolss_SetPrinterDataEx r2; + + r2.in.handle = r->in.handle; + r2.in.key_name = "PrinterDriverData"; + r2.in.value_name = r->in.value_name; + r2.in.type = r->in.type; + r2.in.data = r->in.data; + r2.in.offered = r->in.offered; + + return _spoolss_SetPrinterDataEx(p, &r2); +} + +/**************************************************************** + _spoolss_ResetPrinter +****************************************************************/ + +WERROR _spoolss_ResetPrinter(struct pipes_struct *p, + struct spoolss_ResetPrinter *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + int snum; + + DEBUG(5,("_spoolss_ResetPrinter\n")); + + /* + * All we do is to check to see if the handle and queue is valid. + * This call really doesn't mean anything to us because we only + * support RAW printing. --jerry + */ + + if (!Printer) { + DEBUG(2,("_spoolss_ResetPrinter: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) + return WERR_BADFID; + + + /* blindly return success */ + return WERR_OK; +} + +/**************************************************************** + _spoolss_DeletePrinterData +****************************************************************/ + +WERROR _spoolss_DeletePrinterData(struct pipes_struct *p, + struct spoolss_DeletePrinterData *r) +{ + struct spoolss_DeletePrinterDataEx r2; + + r2.in.handle = r->in.handle; + r2.in.key_name = "PrinterDriverData"; + r2.in.value_name = r->in.value_name; + + return _spoolss_DeletePrinterDataEx(p, &r2); +} + +/**************************************************************** + _spoolss_AddForm +****************************************************************/ + +WERROR _spoolss_AddForm(struct pipes_struct *p, + struct spoolss_AddForm *r) +{ + struct spoolss_AddFormInfo1 *form = r->in.info.info1; + int snum = -1; + WERROR status = WERR_OK; + + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + DEBUG(5,("_spoolss_AddForm\n")); + + if (!Printer) { + DEBUG(2,("_spoolss_AddForm: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, + and not a printer admin, then fail */ + + if ((p->server_info->utok.uid != sec_initial_uid()) && + !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && + !token_contains_name_in_list(uidtoname(p->server_info->utok.uid), + p->server_info->info3->base.domain.string, + NULL, + p->server_info->security_token, + lp_printer_admin(snum))) { + DEBUG(2,("_spoolss_Addform: denied by insufficient permissions.\n")); + return WERR_ACCESS_DENIED; + } + + switch (form->flags) { + case SPOOLSS_FORM_USER: + case SPOOLSS_FORM_BUILTIN: + case SPOOLSS_FORM_PRINTER: + break; + default: + return WERR_INVALID_PARAM; + } + + status = winreg_printer_addform1(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + form); + if (!W_ERROR_IS_OK(status)) { + return status; + } + + /* + * ChangeID must always be set if this is a printer + */ + if (Printer->printer_type == SPLHND_PRINTER) { + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + status = winreg_printer_update_changeid(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum)); + if (!W_ERROR_IS_OK(status)) { + return status; + } + } + + return status; +} + +/**************************************************************** + _spoolss_DeleteForm +****************************************************************/ + +WERROR _spoolss_DeleteForm(struct pipes_struct *p, + struct spoolss_DeleteForm *r) +{ + const char *form_name = r->in.form_name; + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + int snum = -1; + WERROR status = WERR_OK; + + DEBUG(5,("_spoolss_DeleteForm\n")); + + if (!Printer) { + DEBUG(2,("_spoolss_DeleteForm: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if ((p->server_info->utok.uid != sec_initial_uid()) && + !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && + !token_contains_name_in_list(uidtoname(p->server_info->utok.uid), + p->server_info->info3->base.domain.string, + NULL, + p->server_info->security_token, + lp_printer_admin(snum))) { + DEBUG(2,("_spoolss_DeleteForm: denied by insufficient permissions.\n")); + return WERR_ACCESS_DENIED; + } + + status = winreg_printer_deleteform1(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + form_name); + if (!W_ERROR_IS_OK(status)) { + return status; + } + + /* + * ChangeID must always be set if this is a printer + */ + if (Printer->printer_type == SPLHND_PRINTER) { + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + status = winreg_printer_update_changeid(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum)); + if (!W_ERROR_IS_OK(status)) { + return status; + } + } + + return status; +} + +/**************************************************************** + _spoolss_SetForm +****************************************************************/ + +WERROR _spoolss_SetForm(struct pipes_struct *p, + struct spoolss_SetForm *r) +{ + struct spoolss_AddFormInfo1 *form = r->in.info.info1; + const char *form_name = r->in.form_name; + int snum = -1; + WERROR status = WERR_OK; + + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + DEBUG(5,("_spoolss_SetForm\n")); + + if (!Printer) { + DEBUG(2,("_spoolss_SetForm: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, + and not a printer admin, then fail */ + + if ((p->server_info->utok.uid != sec_initial_uid()) && + !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && + !token_contains_name_in_list(uidtoname(p->server_info->utok.uid), + p->server_info->info3->base.domain.string, + NULL, + p->server_info->security_token, + lp_printer_admin(snum))) { + DEBUG(2,("_spoolss_Setform: denied by insufficient permissions.\n")); + return WERR_ACCESS_DENIED; + } + + status = winreg_printer_setform1(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + form_name, + form); + if (!W_ERROR_IS_OK(status)) { + return status; + } + + /* + * ChangeID must always be set if this is a printer + */ + if (Printer->printer_type == SPLHND_PRINTER) { + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + status = winreg_printer_update_changeid(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum)); + if (!W_ERROR_IS_OK(status)) { + return status; + } + } + + return status; +} + +/**************************************************************************** + fill_print_processor1 +****************************************************************************/ + +static WERROR fill_print_processor1(TALLOC_CTX *mem_ctx, + struct spoolss_PrintProcessorInfo1 *r, + const char *print_processor_name) +{ + r->print_processor_name = talloc_strdup(mem_ctx, print_processor_name); + W_ERROR_HAVE_NO_MEMORY(r->print_processor_name); + + return WERR_OK; +} + +/**************************************************************************** + enumprintprocessors level 1. +****************************************************************************/ + +static WERROR enumprintprocessors_level_1(TALLOC_CTX *mem_ctx, + union spoolss_PrintProcessorInfo **info_p, + uint32_t *count) +{ + union spoolss_PrintProcessorInfo *info; + WERROR result; + + info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcessorInfo, 1); + W_ERROR_HAVE_NO_MEMORY(info); + + *count = 1; + + result = fill_print_processor1(info, &info[0].info1, "winprint"); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + *count = 0; + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/**************************************************************** + _spoolss_EnumPrintProcessors +****************************************************************/ + +WERROR _spoolss_EnumPrintProcessors(struct pipes_struct *p, + struct spoolss_EnumPrintProcessors *r) +{ + WERROR result; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(5,("_spoolss_EnumPrintProcessors\n")); + + /* + * Enumerate the print processors ... + * + * Just reply with "winprint", to keep NT happy + * and I can use my nice printer checker. + */ + + *r->out.count = 0; + *r->out.needed = 0; + *r->out.info = NULL; + + if (!get_short_archi(r->in.environment)) { + return WERR_INVALID_ENVIRONMENT; + } + + switch (r->in.level) { + case 1: + result = enumprintprocessors_level_1(p->mem_ctx, r->out.info, + r->out.count); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumPrintProcessors, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************************** + fill_printprocdatatype1 +****************************************************************************/ + +static WERROR fill_printprocdatatype1(TALLOC_CTX *mem_ctx, + struct spoolss_PrintProcDataTypesInfo1 *r, + const char *name_array) +{ + r->name_array = talloc_strdup(mem_ctx, name_array); + W_ERROR_HAVE_NO_MEMORY(r->name_array); + + return WERR_OK; +} + +/**************************************************************************** + enumprintprocdatatypes level 1. +****************************************************************************/ + +static WERROR enumprintprocdatatypes_level_1(TALLOC_CTX *mem_ctx, + union spoolss_PrintProcDataTypesInfo **info_p, + uint32_t *count) +{ + WERROR result; + union spoolss_PrintProcDataTypesInfo *info; + + info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcDataTypesInfo, 1); + W_ERROR_HAVE_NO_MEMORY(info); + + *count = 1; + + result = fill_printprocdatatype1(info, &info[0].info1, "RAW"); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + *count = 0; + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/**************************************************************** + _spoolss_EnumPrintProcDataTypes +****************************************************************/ + +WERROR _spoolss_EnumPrintProcDataTypes(struct pipes_struct *p, + struct spoolss_EnumPrintProcDataTypes *r) +{ + WERROR result; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(5,("_spoolss_EnumPrintProcDataTypes\n")); + + *r->out.count = 0; + *r->out.needed = 0; + *r->out.info = NULL; + + if (r->in.print_processor_name == NULL || + !strequal(r->in.print_processor_name, "winprint")) { + return WERR_UNKNOWN_PRINTPROCESSOR; + } + + switch (r->in.level) { + case 1: + result = enumprintprocdatatypes_level_1(p->mem_ctx, r->out.info, + r->out.count); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumPrintProcDataTypes, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************************** + fill_monitor_1 +****************************************************************************/ + +static WERROR fill_monitor_1(TALLOC_CTX *mem_ctx, + struct spoolss_MonitorInfo1 *r, + const char *monitor_name) +{ + r->monitor_name = talloc_strdup(mem_ctx, monitor_name); + W_ERROR_HAVE_NO_MEMORY(r->monitor_name); + + return WERR_OK; +} + +/**************************************************************************** + fill_monitor_2 +****************************************************************************/ + +static WERROR fill_monitor_2(TALLOC_CTX *mem_ctx, + struct spoolss_MonitorInfo2 *r, + const char *monitor_name, + const char *environment, + const char *dll_name) +{ + r->monitor_name = talloc_strdup(mem_ctx, monitor_name); + W_ERROR_HAVE_NO_MEMORY(r->monitor_name); + r->environment = talloc_strdup(mem_ctx, environment); + W_ERROR_HAVE_NO_MEMORY(r->environment); + r->dll_name = talloc_strdup(mem_ctx, dll_name); + W_ERROR_HAVE_NO_MEMORY(r->dll_name); + + return WERR_OK; +} + +/**************************************************************************** + enumprintmonitors level 1. +****************************************************************************/ + +static WERROR enumprintmonitors_level_1(TALLOC_CTX *mem_ctx, + union spoolss_MonitorInfo **info_p, + uint32_t *count) +{ + union spoolss_MonitorInfo *info; + WERROR result = WERR_OK; + + info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2); + W_ERROR_HAVE_NO_MEMORY(info); + + *count = 2; + + result = fill_monitor_1(info, &info[0].info1, + SPL_LOCAL_PORT); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + result = fill_monitor_1(info, &info[1].info1, + SPL_TCPIP_PORT); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + +out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + *count = 0; + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/**************************************************************************** + enumprintmonitors level 2. +****************************************************************************/ + +static WERROR enumprintmonitors_level_2(TALLOC_CTX *mem_ctx, + union spoolss_MonitorInfo **info_p, + uint32_t *count) +{ + union spoolss_MonitorInfo *info; + WERROR result = WERR_OK; + + info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2); + W_ERROR_HAVE_NO_MEMORY(info); + + *count = 2; + + result = fill_monitor_2(info, &info[0].info2, + SPL_LOCAL_PORT, + "Windows NT X86", /* FIXME */ + "localmon.dll"); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + + result = fill_monitor_2(info, &info[1].info2, + SPL_TCPIP_PORT, + "Windows NT X86", /* FIXME */ + "tcpmon.dll"); + if (!W_ERROR_IS_OK(result)) { + goto out; + } + +out: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(info); + *count = 0; + return result; + } + + *info_p = info; + + return WERR_OK; +} + +/**************************************************************** + _spoolss_EnumMonitors +****************************************************************/ + +WERROR _spoolss_EnumMonitors(struct pipes_struct *p, + struct spoolss_EnumMonitors *r) +{ + WERROR result; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(5,("_spoolss_EnumMonitors\n")); + + /* + * Enumerate the print monitors ... + * + * Just reply with "Local Port", to keep NT happy + * and I can use my nice printer checker. + */ + + *r->out.count = 0; + *r->out.needed = 0; + *r->out.info = NULL; + + switch (r->in.level) { + case 1: + result = enumprintmonitors_level_1(p->mem_ctx, r->out.info, + r->out.count); + break; + case 2: + result = enumprintmonitors_level_2(p->mem_ctx, r->out.info, + r->out.count); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, + spoolss_EnumMonitors, + *r->out.info, r->in.level, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR getjob_level_1(TALLOC_CTX *mem_ctx, + const print_queue_struct *queue, + int count, int snum, + struct spoolss_PrinterInfo2 *pinfo2, + uint32_t jobid, + struct spoolss_JobInfo1 *r) +{ + int i = 0; + bool found = false; + + for (i=0; iprintername, + &devmode); + if (!W_ERROR_IS_OK(result)) { + DEBUG(3, ("Can't proceed w/o a devmode!")); + return result; + } + } + + return fill_job_info2(mem_ctx, + r, + &queue[i], + i, + snum, + pinfo2, + devmode); +} + +/**************************************************************** + _spoolss_GetJob +****************************************************************/ + +WERROR _spoolss_GetJob(struct pipes_struct *p, + struct spoolss_GetJob *r) +{ + WERROR result = WERR_OK; + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + int snum; + int count; + print_queue_struct *queue = NULL; + print_status_struct prt_status; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(5,("_spoolss_GetJob\n")); + + *r->out.needed = 0; + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + result = winreg_get_printer(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + &pinfo2); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + count = print_queue_status(p->msg_ctx, snum, &queue, &prt_status); + + DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n", + count, prt_status.status, prt_status.message)); + + switch (r->in.level) { + case 1: + result = getjob_level_1(p->mem_ctx, + queue, count, snum, pinfo2, + r->in.job_id, &r->out.info->info1); + break; + case 2: + result = getjob_level_2(p->mem_ctx, + queue, count, snum, pinfo2, + r->in.job_id, &r->out.info->info2); + break; + default: + result = WERR_UNKNOWN_LEVEL; + break; + } + + SAFE_FREE(queue); + TALLOC_FREE(pinfo2); + + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(r->out.info); + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_JobInfo, r->out.info, + r->in.level); + r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/**************************************************************** + _spoolss_GetPrinterDataEx +****************************************************************/ + +WERROR _spoolss_GetPrinterDataEx(struct pipes_struct *p, + struct spoolss_GetPrinterDataEx *r) +{ + + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + const char *printer; + int snum = 0; + WERROR result = WERR_OK; + DATA_BLOB blob; + enum winreg_Type val_type; + uint8_t *val_data; + uint32_t val_size; + + + DEBUG(4,("_spoolss_GetPrinterDataEx\n")); + + DEBUG(10, ("_spoolss_GetPrinterDataEx: key => [%s], value => [%s]\n", + r->in.key_name, r->in.value_name)); + + /* in case of problem, return some default values */ + + *r->out.needed = 0; + *r->out.type = REG_NONE; + + if (!Printer) { + DEBUG(2,("_spoolss_GetPrinterDataEx: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + result = WERR_BADFID; + goto done; + } + + /* Is the handle to a printer or to the server? */ + + if (Printer->printer_type == SPLHND_SERVER) { + + union spoolss_PrinterData data; + + result = getprinterdata_printer_server(p->mem_ctx, + r->in.value_name, + r->out.type, + &data); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + result = push_spoolss_PrinterData(p->mem_ctx, &blob, + *r->out.type, &data); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = blob.length; + + if (r->in.offered >= *r->out.needed) { + memcpy(r->out.data, blob.data, blob.length); + } + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA); + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + printer = lp_const_servicename(snum); + + /* check to see if the keyname is valid */ + if (!strlen(r->in.key_name)) { + return WERR_INVALID_PARAM; + } + + /* XP sends this and wants the ChangeID value from PRINTER_INFO_0 */ + if (strequal(r->in.key_name, SPOOL_PRINTERDATA_KEY) && + strequal(r->in.value_name, "ChangeId")) { + *r->out.type = REG_DWORD; + *r->out.needed = 4; + if (r->in.offered >= *r->out.needed) { + uint32_t changeid = 0; + + result = winreg_printer_get_changeid(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer, + &changeid); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + SIVAL(r->out.data, 0, changeid); + result = WERR_OK; + } + goto done; + } + + result = winreg_get_printer_dataex(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer, + r->in.key_name, + r->in.value_name, + &val_type, + &val_data, + &val_size); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = val_size; + *r->out.type = val_type; + + if (r->in.offered >= *r->out.needed) { + memcpy(r->out.data, val_data, val_size); + } + + done: + /* retain type when returning WERR_MORE_DATA */ + r->out.data = SPOOLSS_BUFFER_OK(r->out.data, r->out.data); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA); +} + +/**************************************************************** + _spoolss_SetPrinterDataEx +****************************************************************/ + +WERROR _spoolss_SetPrinterDataEx(struct pipes_struct *p, + struct spoolss_SetPrinterDataEx *r) +{ + struct spoolss_PrinterInfo2 *pinfo2 = NULL; + int snum = 0; + WERROR result = WERR_OK; + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + char *oid_string; + + DEBUG(4,("_spoolss_SetPrinterDataEx\n")); + + /* From MSDN documentation of SetPrinterDataEx: pass request to + SetPrinterData if key is "PrinterDriverData" */ + + if (!Printer) { + DEBUG(2,("_spoolss_SetPrinterDataEx: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (Printer->printer_type == SPLHND_SERVER) { + DEBUG(10,("_spoolss_SetPrinterDataEx: " + "Not implemented for server handles yet\n")); + return WERR_INVALID_PARAM; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + /* + * Access check : NT returns "access denied" if you make a + * SetPrinterData call without the necessary privildge. + * we were originally returning OK if nothing changed + * which made Win2k issue **a lot** of SetPrinterData + * when connecting to a printer --jerry + */ + + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { + DEBUG(3, ("_spoolss_SetPrinterDataEx: " + "change denied by handle access permissions\n")); + return WERR_ACCESS_DENIED; + } + + result = winreg_get_printer(Printer, + get_server_info_system(), + p->msg_ctx, + lp_servicename(snum), + &pinfo2); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + /* check for OID in valuename */ + + oid_string = strchr(r->in.value_name, ','); + if (oid_string) { + *oid_string = '\0'; + oid_string++; + } + + /* save the registry data */ + + result = winreg_set_printer_dataex(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + pinfo2->sharename, + r->in.key_name, + r->in.value_name, + r->in.type, + r->in.data, + r->in.offered); + + if (W_ERROR_IS_OK(result)) { + /* save the OID if one was specified */ + if (oid_string) { + char *str = talloc_asprintf(p->mem_ctx, "%s\\%s", + r->in.key_name, SPOOL_OID_KEY); + if (!str) { + result = WERR_NOMEM; + goto done; + } + + /* + * I'm not checking the status here on purpose. Don't know + * if this is right, but I'm returning the status from the + * previous set_printer_dataex() call. I have no idea if + * this is right. --jerry + */ + winreg_set_printer_dataex(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + pinfo2->sharename, + str, + r->in.value_name, + REG_SZ, + (uint8_t *) oid_string, + strlen(oid_string) + 1); + } + + result = winreg_printer_update_changeid(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum)); + + } + +done: + talloc_free(pinfo2); + return result; +} + +/**************************************************************** + _spoolss_DeletePrinterDataEx +****************************************************************/ + +WERROR _spoolss_DeletePrinterDataEx(struct pipes_struct *p, + struct spoolss_DeletePrinterDataEx *r) +{ + const char *printer; + int snum=0; + WERROR status = WERR_OK; + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + + DEBUG(5,("_spoolss_DeletePrinterDataEx\n")); + + if (!Printer) { + DEBUG(2,("_spoolss_DeletePrinterDataEx: " + "Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { + DEBUG(3, ("_spoolss_DeletePrinterDataEx: " + "printer properties change denied by handle\n")); + return WERR_ACCESS_DENIED; + } + + if (!r->in.value_name || !r->in.key_name) { + return WERR_NOMEM; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + printer = lp_const_servicename(snum); + + status = winreg_delete_printer_dataex(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer, + r->in.key_name, + r->in.value_name); + if (W_ERROR_IS_OK(status)) { + status = winreg_printer_update_changeid(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer); + } + + return status; +} + +/**************************************************************** + _spoolss_EnumPrinterKey +****************************************************************/ + +WERROR _spoolss_EnumPrinterKey(struct pipes_struct *p, + struct spoolss_EnumPrinterKey *r) +{ + uint32_t num_keys; + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + int snum = 0; + WERROR result = WERR_BADFILE; + const char **array = NULL; + DATA_BLOB blob; + + DEBUG(4,("_spoolss_EnumPrinterKey\n")); + + if (!Printer) { + DEBUG(2,("_spoolss_EnumPrinterKey: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + result = winreg_enum_printer_key(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + r->in.key_name, + &num_keys, + &array); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + if (!push_reg_multi_sz(p->mem_ctx, &blob, array)) { + result = WERR_NOMEM; + goto done; + } + + *r->out._ndr_size = r->in.offered / 2; + *r->out.needed = blob.length; + + if (r->in.offered < *r->out.needed) { + result = WERR_MORE_DATA; + } else { + result = WERR_OK; + r->out.key_buffer->string_array = array; + } + + done: + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(array); + if (!W_ERROR_EQUAL(result, WERR_MORE_DATA)) { + *r->out.needed = 0; + } + } + + return result; +} + +/**************************************************************** + _spoolss_DeletePrinterKey +****************************************************************/ + +WERROR _spoolss_DeletePrinterKey(struct pipes_struct *p, + struct spoolss_DeletePrinterKey *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + int snum=0; + WERROR status; + const char *printer; + + DEBUG(5,("_spoolss_DeletePrinterKey\n")); + + if (!Printer) { + DEBUG(2,("_spoolss_DeletePrinterKey: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + /* if keyname == NULL, return error */ + if ( !r->in.key_name ) + return WERR_INVALID_PARAM; + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { + DEBUG(3, ("_spoolss_DeletePrinterKey: " + "printer properties change denied by handle\n")); + return WERR_ACCESS_DENIED; + } + + printer = lp_const_servicename(snum); + + /* delete the key and all subkeys */ + status = winreg_delete_printer_key(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer, + r->in.key_name); + if (W_ERROR_IS_OK(status)) { + status = winreg_printer_update_changeid(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + printer); + } + + return status; +} + +/**************************************************************** + _spoolss_EnumPrinterDataEx +****************************************************************/ + +WERROR _spoolss_EnumPrinterDataEx(struct pipes_struct *p, + struct spoolss_EnumPrinterDataEx *r) +{ + uint32_t count = 0; + struct spoolss_PrinterEnumValues *info = NULL; + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + int snum; + WERROR result; + + DEBUG(4,("_spoolss_EnumPrinterDataEx\n")); + + *r->out.count = 0; + *r->out.needed = 0; + *r->out.info = NULL; + + if (!Printer) { + DEBUG(2,("_spoolss_EnumPrinterDataEx: Invalid handle (%s:%u:%u1<).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + /* + * first check for a keyname of NULL or "". Win2k seems to send + * this a lot and we should send back WERR_INVALID_PARAM + * no need to spend time looking up the printer in this case. + * --jerry + */ + + if (!strlen(r->in.key_name)) { + result = WERR_INVALID_PARAM; + goto done; + } + + if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { + return WERR_BADFID; + } + + /* now look for a match on the key name */ + result = winreg_enum_printer_dataex(p->mem_ctx, + get_server_info_system(), + p->msg_ctx, + lp_const_servicename(snum), + r->in.key_name, + &count, + &info); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + +#if 0 /* FIXME - gd */ + /* housekeeping information in the reply */ + + /* Fix from Martin Zielinski - ensure + * the hand marshalled container size is a multiple + * of 4 bytes for RPC alignment. + */ + + if (needed % 4) { + needed += 4-(needed % 4); + } +#endif + *r->out.count = count; + *r->out.info = info; + + done: + if (!W_ERROR_IS_OK(result)) { + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_ARRAY(p->mem_ctx, + spoolss_EnumPrinterDataEx, + *r->out.info, + *r->out.count); + *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); + *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, *r->out.count); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA); +} + +/**************************************************************************** +****************************************************************************/ + +static WERROR getprintprocessordirectory_level_1(TALLOC_CTX *mem_ctx, + const char *servername, + const char *environment, + struct spoolss_PrintProcessorDirectoryInfo1 *r) +{ + WERROR werr; + char *path = NULL; + + werr = compose_spoolss_server_path(mem_ctx, + servername, + environment, + SPOOLSS_PRTPROCS_PATH, + &path); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + DEBUG(4,("print processor directory: [%s]\n", path)); + + r->directory_name = path; + + return WERR_OK; +} + +/**************************************************************** + _spoolss_GetPrintProcessorDirectory +****************************************************************/ + +WERROR _spoolss_GetPrintProcessorDirectory(struct pipes_struct *p, + struct spoolss_GetPrintProcessorDirectory *r) +{ + WERROR result; + char *prnproc_share = NULL; + bool prnproc_share_exists = false; + int snum; + + /* that's an [in out] buffer */ + + if (!r->in.buffer && (r->in.offered != 0)) { + return WERR_INVALID_PARAM; + } + + DEBUG(5,("_spoolss_GetPrintProcessorDirectory: level %d\n", + r->in.level)); + + *r->out.needed = 0; + + /* r->in.level is ignored */ + + /* We always should reply with a local print processor directory so that + * users are not forced to have a [prnproc$] share on the Samba spoolss + * server, if users decide to do so, lets announce it though - Guenther */ + + snum = find_service(talloc_tos(), "prnproc$", &prnproc_share); + if (!prnproc_share) { + return WERR_NOMEM; + } + if (snum != -1) { + prnproc_share_exists = true; + } + + result = getprintprocessordirectory_level_1(p->mem_ctx, + prnproc_share_exists ? r->in.server : NULL, + r->in.environment, + &r->out.info->info1); + if (!W_ERROR_IS_OK(result)) { + TALLOC_FREE(r->out.info); + return result; + } + + *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_PrintProcessorDirectoryInfo, + r->out.info, r->in.level); + r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); + + return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); +} + +/******************************************************************* + ********************************************************************/ + +static bool push_monitorui_buf(TALLOC_CTX *mem_ctx, DATA_BLOB *buf, + const char *dllname) +{ + enum ndr_err_code ndr_err; + struct spoolss_MonitorUi ui; + + ui.dll_name = dllname; + + ndr_err = ndr_push_struct_blob(buf, mem_ctx, &ui, + (ndr_push_flags_fn_t)ndr_push_spoolss_MonitorUi); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { + NDR_PRINT_DEBUG(spoolss_MonitorUi, &ui); + } + return NDR_ERR_CODE_IS_SUCCESS(ndr_err); +} + +/******************************************************************* + Streams the monitor UI DLL name in UNICODE +*******************************************************************/ + +static WERROR xcvtcp_monitorui(TALLOC_CTX *mem_ctx, + struct security_token *token, DATA_BLOB *in, + DATA_BLOB *out, uint32_t *needed) +{ + const char *dllname = "tcpmonui.dll"; + + *needed = (strlen(dllname)+1) * 2; + + if (out->length < *needed) { + return WERR_INSUFFICIENT_BUFFER; + } + + if (!push_monitorui_buf(mem_ctx, out, dllname)) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +/******************************************************************* + ********************************************************************/ + +static bool pull_port_data_1(TALLOC_CTX *mem_ctx, + struct spoolss_PortData1 *port1, + const DATA_BLOB *buf) +{ + enum ndr_err_code ndr_err; + ndr_err = ndr_pull_struct_blob(buf, mem_ctx, port1, + (ndr_pull_flags_fn_t)ndr_pull_spoolss_PortData1); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { + NDR_PRINT_DEBUG(spoolss_PortData1, port1); + } + return NDR_ERR_CODE_IS_SUCCESS(ndr_err); +} + +/******************************************************************* + ********************************************************************/ + +static bool pull_port_data_2(TALLOC_CTX *mem_ctx, + struct spoolss_PortData2 *port2, + const DATA_BLOB *buf) +{ + enum ndr_err_code ndr_err; + ndr_err = ndr_pull_struct_blob(buf, mem_ctx, port2, + (ndr_pull_flags_fn_t)ndr_pull_spoolss_PortData2); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { + NDR_PRINT_DEBUG(spoolss_PortData2, port2); + } + return NDR_ERR_CODE_IS_SUCCESS(ndr_err); +} + +/******************************************************************* + Create a new TCP/IP port +*******************************************************************/ + +static WERROR xcvtcp_addport(TALLOC_CTX *mem_ctx, + struct security_token *token, DATA_BLOB *in, + DATA_BLOB *out, uint32_t *needed) +{ + struct spoolss_PortData1 port1; + struct spoolss_PortData2 port2; + char *device_uri = NULL; + uint32_t version; + + const char *portname; + const char *hostaddress; + const char *queue; + uint32_t port_number; + uint32_t protocol; + + /* peek for spoolss_PortData version */ + + if (!in || (in->length < (128 + 4))) { + return WERR_GENERAL_FAILURE; + } + + version = IVAL(in->data, 128); + + switch (version) { + case 1: + ZERO_STRUCT(port1); + + if (!pull_port_data_1(mem_ctx, &port1, in)) { + return WERR_NOMEM; + } + + portname = port1.portname; + hostaddress = port1.hostaddress; + queue = port1.queue; + protocol = port1.protocol; + port_number = port1.port_number; + + break; + case 2: + ZERO_STRUCT(port2); + + if (!pull_port_data_2(mem_ctx, &port2, in)) { + return WERR_NOMEM; + } + + portname = port2.portname; + hostaddress = port2.hostaddress; + queue = port2.queue; + protocol = port2.protocol; + port_number = port2.port_number; + + break; + default: + DEBUG(1,("xcvtcp_addport: " + "unknown version of port_data: %d\n", version)); + return WERR_UNKNOWN_PORT; + } + + /* create the device URI and call the add_port_hook() */ + + switch (protocol) { + case PROTOCOL_RAWTCP_TYPE: + device_uri = talloc_asprintf(mem_ctx, + "socket://%s:%d/", hostaddress, + port_number); + break; + + case PROTOCOL_LPR_TYPE: + device_uri = talloc_asprintf(mem_ctx, + "lpr://%s/%s", hostaddress, queue ); + break; + + default: + return WERR_UNKNOWN_PORT; + } + + if (!device_uri) { + return WERR_NOMEM; + } + + return add_port_hook(mem_ctx, token, portname, device_uri); +} + +/******************************************************************* +*******************************************************************/ + +struct xcv_api_table xcvtcp_cmds[] = { + { "MonitorUI", xcvtcp_monitorui }, + { "AddPort", xcvtcp_addport}, + { NULL, NULL } +}; + +static WERROR process_xcvtcp_command(TALLOC_CTX *mem_ctx, + struct security_token *token, const char *command, + DATA_BLOB *inbuf, + DATA_BLOB *outbuf, + uint32_t *needed ) +{ + int i; + + DEBUG(10,("process_xcvtcp_command: Received command \"%s\"\n", command)); + + for ( i=0; xcvtcp_cmds[i].name; i++ ) { + if ( strcmp( command, xcvtcp_cmds[i].name ) == 0 ) + return xcvtcp_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed); + } + + return WERR_BADFUNC; +} + +/******************************************************************* +*******************************************************************/ +#if 0 /* don't support management using the "Local Port" monitor */ + +static WERROR xcvlocal_monitorui(TALLOC_CTX *mem_ctx, + struct security_token *token, DATA_BLOB *in, + DATA_BLOB *out, uint32_t *needed) +{ + const char *dllname = "localui.dll"; + + *needed = (strlen(dllname)+1) * 2; + + if (out->length < *needed) { + return WERR_INSUFFICIENT_BUFFER; + } + + if (!push_monitorui_buf(mem_ctx, out, dllname)) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +/******************************************************************* +*******************************************************************/ + +struct xcv_api_table xcvlocal_cmds[] = { + { "MonitorUI", xcvlocal_monitorui }, + { NULL, NULL } +}; +#else +struct xcv_api_table xcvlocal_cmds[] = { + { NULL, NULL } +}; +#endif + + + +/******************************************************************* +*******************************************************************/ + +static WERROR process_xcvlocal_command(TALLOC_CTX *mem_ctx, + struct security_token *token, const char *command, + DATA_BLOB *inbuf, DATA_BLOB *outbuf, + uint32_t *needed) +{ + int i; + + DEBUG(10,("process_xcvlocal_command: Received command \"%s\"\n", command)); + + for ( i=0; xcvlocal_cmds[i].name; i++ ) { + if ( strcmp( command, xcvlocal_cmds[i].name ) == 0 ) + return xcvlocal_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed); + } + return WERR_BADFUNC; +} + +/**************************************************************** + _spoolss_XcvData +****************************************************************/ + +WERROR _spoolss_XcvData(struct pipes_struct *p, + struct spoolss_XcvData *r) +{ + struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); + DATA_BLOB out_data = data_blob_null; + WERROR werror; + + if (!Printer) { + DEBUG(2,("_spoolss_XcvData: Invalid handle (%s:%u:%u).\n", + OUR_HANDLE(r->in.handle))); + return WERR_BADFID; + } + + /* Has to be a handle to the TCP/IP port monitor */ + + if ( !(Printer->printer_type & (SPLHND_PORTMON_LOCAL|SPLHND_PORTMON_TCP)) ) { + DEBUG(2,("_spoolss_XcvData: Call only valid for Port Monitors\n")); + return WERR_BADFID; + } + + /* requires administrative access to the server */ + + if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) ) { + DEBUG(2,("_spoolss_XcvData: denied by handle permissions.\n")); + return WERR_ACCESS_DENIED; + } + + /* Allocate the outgoing buffer */ + + if (r->in.out_data_size) { + out_data = data_blob_talloc_zero(p->mem_ctx, r->in.out_data_size); + if (out_data.data == NULL) { + return WERR_NOMEM; + } + } + + switch ( Printer->printer_type ) { + case SPLHND_PORTMON_TCP: + werror = process_xcvtcp_command(p->mem_ctx, + p->server_info->security_token, + r->in.function_name, + &r->in.in_data, &out_data, + r->out.needed); + break; + case SPLHND_PORTMON_LOCAL: + werror = process_xcvlocal_command(p->mem_ctx, + p->server_info->security_token, + r->in.function_name, + &r->in.in_data, &out_data, + r->out.needed); + break; + default: + werror = WERR_INVALID_PRINT_MONITOR; + } + + if (!W_ERROR_IS_OK(werror)) { + return werror; + } + + *r->out.status_code = 0; + + if (r->out.out_data && out_data.data && r->in.out_data_size && out_data.length) { + memcpy(r->out.out_data, out_data.data, + MIN(r->in.out_data_size, out_data.length)); + } + + return WERR_OK; +} + +/**************************************************************** + _spoolss_AddPrintProcessor +****************************************************************/ + +WERROR _spoolss_AddPrintProcessor(struct pipes_struct *p, + struct spoolss_AddPrintProcessor *r) +{ + /* for now, just indicate success and ignore the add. We'll + automatically set the winprint processor for printer + entries later. Used to debug the LexMark Optra S 1855 PCL + driver --jerry */ + + return WERR_OK; +} + +/**************************************************************** + _spoolss_AddPort +****************************************************************/ + +WERROR _spoolss_AddPort(struct pipes_struct *p, + struct spoolss_AddPort *r) +{ + /* do what w2k3 does */ + + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_GetPrinterDriver +****************************************************************/ + +WERROR _spoolss_GetPrinterDriver(struct pipes_struct *p, + struct spoolss_GetPrinterDriver *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_ReadPrinter +****************************************************************/ + +WERROR _spoolss_ReadPrinter(struct pipes_struct *p, + struct spoolss_ReadPrinter *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_WaitForPrinterChange +****************************************************************/ + +WERROR _spoolss_WaitForPrinterChange(struct pipes_struct *p, + struct spoolss_WaitForPrinterChange *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_ConfigurePort +****************************************************************/ + +WERROR _spoolss_ConfigurePort(struct pipes_struct *p, + struct spoolss_ConfigurePort *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_DeletePort +****************************************************************/ + +WERROR _spoolss_DeletePort(struct pipes_struct *p, + struct spoolss_DeletePort *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_CreatePrinterIC +****************************************************************/ + +WERROR _spoolss_CreatePrinterIC(struct pipes_struct *p, + struct spoolss_CreatePrinterIC *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_PlayGDIScriptOnPrinterIC +****************************************************************/ + +WERROR _spoolss_PlayGDIScriptOnPrinterIC(struct pipes_struct *p, + struct spoolss_PlayGDIScriptOnPrinterIC *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_DeletePrinterIC +****************************************************************/ + +WERROR _spoolss_DeletePrinterIC(struct pipes_struct *p, + struct spoolss_DeletePrinterIC *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_AddPrinterConnection +****************************************************************/ + +WERROR _spoolss_AddPrinterConnection(struct pipes_struct *p, + struct spoolss_AddPrinterConnection *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_DeletePrinterConnection +****************************************************************/ + +WERROR _spoolss_DeletePrinterConnection(struct pipes_struct *p, + struct spoolss_DeletePrinterConnection *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_PrinterMessageBox +****************************************************************/ + +WERROR _spoolss_PrinterMessageBox(struct pipes_struct *p, + struct spoolss_PrinterMessageBox *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_AddMonitor +****************************************************************/ + +WERROR _spoolss_AddMonitor(struct pipes_struct *p, + struct spoolss_AddMonitor *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_DeleteMonitor +****************************************************************/ + +WERROR _spoolss_DeleteMonitor(struct pipes_struct *p, + struct spoolss_DeleteMonitor *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_DeletePrintProcessor +****************************************************************/ + +WERROR _spoolss_DeletePrintProcessor(struct pipes_struct *p, + struct spoolss_DeletePrintProcessor *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_AddPrintProvidor +****************************************************************/ + +WERROR _spoolss_AddPrintProvidor(struct pipes_struct *p, + struct spoolss_AddPrintProvidor *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_DeletePrintProvidor +****************************************************************/ + +WERROR _spoolss_DeletePrintProvidor(struct pipes_struct *p, + struct spoolss_DeletePrintProvidor *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_FindFirstPrinterChangeNotification +****************************************************************/ + +WERROR _spoolss_FindFirstPrinterChangeNotification(struct pipes_struct *p, + struct spoolss_FindFirstPrinterChangeNotification *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_FindNextPrinterChangeNotification +****************************************************************/ + +WERROR _spoolss_FindNextPrinterChangeNotification(struct pipes_struct *p, + struct spoolss_FindNextPrinterChangeNotification *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_RouterFindFirstPrinterChangeNotificationOld +****************************************************************/ + +WERROR _spoolss_RouterFindFirstPrinterChangeNotificationOld(struct pipes_struct *p, + struct spoolss_RouterFindFirstPrinterChangeNotificationOld *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_ReplyOpenPrinter +****************************************************************/ + +WERROR _spoolss_ReplyOpenPrinter(struct pipes_struct *p, + struct spoolss_ReplyOpenPrinter *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_RouterReplyPrinter +****************************************************************/ + +WERROR _spoolss_RouterReplyPrinter(struct pipes_struct *p, + struct spoolss_RouterReplyPrinter *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_ReplyClosePrinter +****************************************************************/ + +WERROR _spoolss_ReplyClosePrinter(struct pipes_struct *p, + struct spoolss_ReplyClosePrinter *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_AddPortEx +****************************************************************/ + +WERROR _spoolss_AddPortEx(struct pipes_struct *p, + struct spoolss_AddPortEx *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_RouterFindFirstPrinterChangeNotification +****************************************************************/ + +WERROR _spoolss_RouterFindFirstPrinterChangeNotification(struct pipes_struct *p, + struct spoolss_RouterFindFirstPrinterChangeNotification *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_SpoolerInit +****************************************************************/ + +WERROR _spoolss_SpoolerInit(struct pipes_struct *p, + struct spoolss_SpoolerInit *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_ResetPrinterEx +****************************************************************/ + +WERROR _spoolss_ResetPrinterEx(struct pipes_struct *p, + struct spoolss_ResetPrinterEx *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_RouterReplyPrinterEx +****************************************************************/ + +WERROR _spoolss_RouterReplyPrinterEx(struct pipes_struct *p, + struct spoolss_RouterReplyPrinterEx *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_44 +****************************************************************/ + +WERROR _spoolss_44(struct pipes_struct *p, + struct spoolss_44 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_SetPort +****************************************************************/ + +WERROR _spoolss_SetPort(struct pipes_struct *p, + struct spoolss_SetPort *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_4a +****************************************************************/ + +WERROR _spoolss_4a(struct pipes_struct *p, + struct spoolss_4a *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_4b +****************************************************************/ + +WERROR _spoolss_4b(struct pipes_struct *p, + struct spoolss_4b *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_4c +****************************************************************/ + +WERROR _spoolss_4c(struct pipes_struct *p, + struct spoolss_4c *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_53 +****************************************************************/ + +WERROR _spoolss_53(struct pipes_struct *p, + struct spoolss_53 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_AddPerMachineConnection +****************************************************************/ + +WERROR _spoolss_AddPerMachineConnection(struct pipes_struct *p, + struct spoolss_AddPerMachineConnection *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_DeletePerMachineConnection +****************************************************************/ + +WERROR _spoolss_DeletePerMachineConnection(struct pipes_struct *p, + struct spoolss_DeletePerMachineConnection *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_EnumPerMachineConnections +****************************************************************/ + +WERROR _spoolss_EnumPerMachineConnections(struct pipes_struct *p, + struct spoolss_EnumPerMachineConnections *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_5a +****************************************************************/ + +WERROR _spoolss_5a(struct pipes_struct *p, + struct spoolss_5a *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_5b +****************************************************************/ + +WERROR _spoolss_5b(struct pipes_struct *p, + struct spoolss_5b *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_5c +****************************************************************/ + +WERROR _spoolss_5c(struct pipes_struct *p, + struct spoolss_5c *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_5d +****************************************************************/ + +WERROR _spoolss_5d(struct pipes_struct *p, + struct spoolss_5d *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_5e +****************************************************************/ + +WERROR _spoolss_5e(struct pipes_struct *p, + struct spoolss_5e *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_5f +****************************************************************/ + +WERROR _spoolss_5f(struct pipes_struct *p, + struct spoolss_5f *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_60 +****************************************************************/ + +WERROR _spoolss_60(struct pipes_struct *p, + struct spoolss_60 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_61 +****************************************************************/ + +WERROR _spoolss_61(struct pipes_struct *p, + struct spoolss_61 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_62 +****************************************************************/ + +WERROR _spoolss_62(struct pipes_struct *p, + struct spoolss_62 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_63 +****************************************************************/ + +WERROR _spoolss_63(struct pipes_struct *p, + struct spoolss_63 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_64 +****************************************************************/ + +WERROR _spoolss_64(struct pipes_struct *p, + struct spoolss_64 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_65 +****************************************************************/ + +WERROR _spoolss_65(struct pipes_struct *p, + struct spoolss_65 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_GetCorePrinterDrivers +****************************************************************/ + +WERROR _spoolss_GetCorePrinterDrivers(struct pipes_struct *p, + struct spoolss_GetCorePrinterDrivers *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_67 +****************************************************************/ + +WERROR _spoolss_67(struct pipes_struct *p, + struct spoolss_67 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_GetPrinterDriverPackagePath +****************************************************************/ + +WERROR _spoolss_GetPrinterDriverPackagePath(struct pipes_struct *p, + struct spoolss_GetPrinterDriverPackagePath *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_69 +****************************************************************/ + +WERROR _spoolss_69(struct pipes_struct *p, + struct spoolss_69 *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_6a +****************************************************************/ + +WERROR _spoolss_6a(struct pipes_struct *p, + struct spoolss_6a *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_6b +****************************************************************/ + +WERROR _spoolss_6b(struct pipes_struct *p, + struct spoolss_6b *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_6c +****************************************************************/ + +WERROR _spoolss_6c(struct pipes_struct *p, + struct spoolss_6c *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} + +/**************************************************************** + _spoolss_6d +****************************************************************/ + +WERROR _spoolss_6d(struct pipes_struct *p, + struct spoolss_6d *r) +{ + p->rng_fault_state = true; + return WERR_NOT_SUPPORTED; +} diff --git a/source3/rpc_server/spoolss/srv_spoolss_util.c b/source3/rpc_server/spoolss/srv_spoolss_util.c new file mode 100644 index 0000000000..9d654ec20c --- /dev/null +++ b/source3/rpc_server/spoolss/srv_spoolss_util.c @@ -0,0 +1,4248 @@ +/* + * Unix SMB/CIFS implementation. + * + * SPOOLSS RPC Pipe server / winreg client routines + * + * Copyright (c) 2010 Andreas Schneider + * + * 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 . + */ + +#include "includes.h" +#include "nt_printing.h" +#include "srv_spoolss_util.h" +#include "../librpc/gen_ndr/ndr_spoolss.h" +#include "../librpc/gen_ndr/srv_winreg.h" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "secrets.h" +#include "rpc_server/rpc_ncacn_np.h" +#include "../libcli/security/security.h" +#include "rpc_client/cli_winreg.h" + +#define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print" +#define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers" +#define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print" +#define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms" + +#define EMPTY_STRING "" + +#define FILL_STRING(mem_ctx, in, out) \ + do { \ + if (in && strlen(in)) { \ + out = talloc_strdup(mem_ctx, in); \ + } else { \ + out = talloc_strdup(mem_ctx, ""); \ + } \ + W_ERROR_HAVE_NO_MEMORY(out); \ + } while (0); + +#define CHECK_ERROR(result) \ + if (W_ERROR_IS_OK(result)) continue; \ + if (W_ERROR_EQUAL(result, WERR_NOT_FOUND)) result = WERR_OK; \ + if (!W_ERROR_IS_OK(result)) break + +/* FLAGS, NAME, with, height, left, top, right, bottom */ +static const struct spoolss_FormInfo1 builtin_forms1[] = { + { SPOOLSS_FORM_BUILTIN, "10x11", {0x3e030,0x44368}, {0x0,0x0,0x3e030,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "10x14", {0x3e030,0x56d10}, {0x0,0x0,0x3e030,0x56d10} }, + { SPOOLSS_FORM_BUILTIN, "11x17", {0x44368,0x696b8}, {0x0,0x0,0x44368,0x696b8} }, + { SPOOLSS_FORM_BUILTIN, "12x11", {0x4a724,0x443e1}, {0x0,0x0,0x4a724,0x443e1} }, + { SPOOLSS_FORM_BUILTIN, "15x11", {0x5d048,0x44368}, {0x0,0x0,0x5d048,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "6 3/4 Envelope", {0x167ab,0x284ec}, {0x0,0x0,0x167ab,0x284ec} }, + { SPOOLSS_FORM_BUILTIN, "9x11", {0x37cf8,0x44368}, {0x0,0x0,0x37cf8,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "A0", {0xcd528,0x122488},{0x0,0x0,0xcd528,0x122488} }, + { SPOOLSS_FORM_BUILTIN, "A1", {0x91050,0xcd528}, {0x0,0x0,0x91050,0xcd528} }, + { SPOOLSS_FORM_BUILTIN, "A2", {0x668a0,0x91050}, {0x0,0x0,0x668a0,0x91050} }, + { SPOOLSS_FORM_BUILTIN, "A3 Extra Transverse", {0x4e9d0,0x6ca48}, {0x0,0x0,0x4e9d0,0x6ca48} }, + { SPOOLSS_FORM_BUILTIN, "A3 Extra", {0x4e9d0,0x6ca48}, {0x0,0x0,0x4e9d0,0x6ca48} }, + { SPOOLSS_FORM_BUILTIN, "A3 Rotated", {0x668a0,0x48828}, {0x0,0x0,0x668a0,0x48828} }, + { SPOOLSS_FORM_BUILTIN, "A3 Transverse", {0x48828,0x668a0}, {0x0,0x0,0x48828,0x668a0} }, + { SPOOLSS_FORM_BUILTIN, "A3", {0x48828,0x668a0}, {0x0,0x0,0x48828,0x668a0} }, + { SPOOLSS_FORM_BUILTIN, "A4 Extra", {0x397c2,0x4eb16}, {0x0,0x0,0x397c2,0x4eb16} }, + { SPOOLSS_FORM_BUILTIN, "A4 Plus", {0x33450,0x50910}, {0x0,0x0,0x33450,0x50910} }, + { SPOOLSS_FORM_BUILTIN, "A4 Rotated", {0x48828,0x33450}, {0x0,0x0,0x48828,0x33450} }, + { SPOOLSS_FORM_BUILTIN, "A4 Small", {0x33450,0x48828}, {0x0,0x0,0x33450,0x48828} }, + { SPOOLSS_FORM_BUILTIN, "A4 Transverse", {0x33450,0x48828}, {0x0,0x0,0x33450,0x48828} }, + { SPOOLSS_FORM_BUILTIN, "A4", {0x33450,0x48828}, {0x0,0x0,0x33450,0x48828} }, + { SPOOLSS_FORM_BUILTIN, "A5 Extra", {0x2a7b0,0x395f8}, {0x0,0x0,0x2a7b0,0x395f8} }, + { SPOOLSS_FORM_BUILTIN, "A5 Rotated", {0x33450,0x24220}, {0x0,0x0,0x33450,0x24220} }, + { SPOOLSS_FORM_BUILTIN, "A5 Transverse", {0x24220,0x33450}, {0x0,0x0,0x24220,0x33450} }, + { SPOOLSS_FORM_BUILTIN, "A5", {0x24220,0x33450}, {0x0,0x0,0x24220,0x33450} }, + { SPOOLSS_FORM_BUILTIN, "A6 Rotated", {0x24220,0x19a28}, {0x0,0x0,0x24220,0x19a28} }, + { SPOOLSS_FORM_BUILTIN, "A6", {0x19a28,0x24220}, {0x0,0x0,0x19a28,0x24220} }, + { SPOOLSS_FORM_BUILTIN, "B4 (ISO)", {0x3d090,0x562e8}, {0x0,0x0,0x3d090,0x562e8} }, + { SPOOLSS_FORM_BUILTIN, "B4 (JIS) Rotated", {0x58de0,0x3ebe8}, {0x0,0x0,0x58de0,0x3ebe8} }, + { SPOOLSS_FORM_BUILTIN, "B4 (JIS)", {0x3ebe8,0x58de0}, {0x0,0x0,0x3ebe8,0x58de0} }, + { SPOOLSS_FORM_BUILTIN, "B5 (ISO) Extra", {0x31128,0x43620}, {0x0,0x0,0x31128,0x43620} }, + { SPOOLSS_FORM_BUILTIN, "B5 (JIS) Rotated", {0x3ebe8,0x2c6f0}, {0x0,0x0,0x3ebe8,0x2c6f0} }, + { SPOOLSS_FORM_BUILTIN, "B5 (JIS) Transverse", {0x2c6f0,0x3ebe8}, {0x0,0x0,0x2c6f0,0x3ebe8} }, + { SPOOLSS_FORM_BUILTIN, "B5 (JIS)", {0x2c6f0,0x3ebe8}, {0x0,0x0,0x2c6f0,0x3ebe8} }, + { SPOOLSS_FORM_BUILTIN, "B6 (JIS) Rotated", {0x2c6f0,0x1f400}, {0x0,0x0,0x2c6f0,0x1f400} }, + { SPOOLSS_FORM_BUILTIN, "B6 (JIS)", {0x1f400,0x2c6f0}, {0x0,0x0,0x1f400,0x2c6f0} }, + { SPOOLSS_FORM_BUILTIN, "C size sheet", {0x696b8,0x886d0}, {0x0,0x0,0x696b8,0x886d0} }, + { SPOOLSS_FORM_BUILTIN, "D size sheet", {0x886d0,0xd2d70}, {0x0,0x0,0x886d0,0xd2d70} }, + { SPOOLSS_FORM_BUILTIN, "Double Japan Postcard Rotated", {0x24220,0x30d40}, {0x0,0x0,0x24220,0x30d40} }, + { SPOOLSS_FORM_BUILTIN, "E size sheet", {0xd2d70,0x110da0},{0x0,0x0,0xd2d70,0x110da0} }, + { SPOOLSS_FORM_BUILTIN, "Envelope #10", {0x19947,0x3ae94}, {0x0,0x0,0x19947,0x3ae94} }, + { SPOOLSS_FORM_BUILTIN, "Envelope #11", {0x1be7c,0x40565}, {0x0,0x0,0x1be7c,0x40565} }, + { SPOOLSS_FORM_BUILTIN, "Envelope #12", {0x1d74a,0x44368}, {0x0,0x0,0x1d74a,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "Envelope #14", {0x1f018,0x47504}, {0x0,0x0,0x1f018,0x47504} }, + { SPOOLSS_FORM_BUILTIN, "Envelope #9", {0x18079,0x37091}, {0x0,0x0,0x18079,0x37091} }, + { SPOOLSS_FORM_BUILTIN, "Envelope B4", {0x3d090,0x562e8}, {0x0,0x0,0x3d090,0x562e8} }, + { SPOOLSS_FORM_BUILTIN, "Envelope B5", {0x2af80,0x3d090}, {0x0,0x0,0x2af80,0x3d090} }, + { SPOOLSS_FORM_BUILTIN, "Envelope B6", {0x2af80,0x1e848}, {0x0,0x0,0x2af80,0x1e848} }, + { SPOOLSS_FORM_BUILTIN, "Envelope C3", {0x4f1a0,0x6fd10}, {0x0,0x0,0x4f1a0,0x6fd10} }, + { SPOOLSS_FORM_BUILTIN, "Envelope C4", {0x37e88,0x4f1a0}, {0x0,0x0,0x37e88,0x4f1a0} }, + { SPOOLSS_FORM_BUILTIN, "Envelope C5", {0x278d0,0x37e88}, {0x0,0x0,0x278d0,0x37e88} }, + { SPOOLSS_FORM_BUILTIN, "Envelope C6", {0x1bd50,0x278d0}, {0x0,0x0,0x1bd50,0x278d0} }, + { SPOOLSS_FORM_BUILTIN, "Envelope C65", {0x1bd50,0x37e88}, {0x0,0x0,0x1bd50,0x37e88} }, + { SPOOLSS_FORM_BUILTIN, "Envelope DL", {0x1adb0,0x35b60}, {0x0,0x0,0x1adb0,0x35b60} }, + { SPOOLSS_FORM_BUILTIN, "Envelope Invite", {0x35b60,0x35b60}, {0x0,0x0,0x35b60,0x35b60} }, + { SPOOLSS_FORM_BUILTIN, "Envelope Monarch", {0x18079,0x2e824}, {0x0,0x0,0x18079,0x2e824} }, + { SPOOLSS_FORM_BUILTIN, "Envelope", {0x1adb0,0x38270}, {0x0,0x0,0x1adb0,0x38270} }, + { SPOOLSS_FORM_BUILTIN, "Executive", {0x2cf56,0x411cc}, {0x0,0x0,0x2cf56,0x411cc} }, + { SPOOLSS_FORM_BUILTIN, "Folio", {0x34b5c,0x509d8}, {0x0,0x0,0x34b5c,0x509d8} }, + { SPOOLSS_FORM_BUILTIN, "German Legal Fanfold", {0x34b5c,0x509d8}, {0x0,0x0,0x34b5c,0x509d8} }, + { SPOOLSS_FORM_BUILTIN, "German Std Fanfold", {0x34b5c,0x4a6a0}, {0x0,0x0,0x34b5c,0x4a6a0} }, + { SPOOLSS_FORM_BUILTIN, "Japan Envelope Chou #3 Rotated", {0x395f8,0x1d4c0}, {0x0,0x0,0x395f8,0x1d4c0} }, + { SPOOLSS_FORM_BUILTIN, "Japan Envelope Chou #4 Rotated", {0x320c8,0x15f90}, {0x0,0x0,0x320c8,0x15f90} }, + { SPOOLSS_FORM_BUILTIN, "Japan Envelope Kaku #2 Rotated", {0x510e0,0x3a980}, {0x0,0x0,0x510e0,0x3a980} }, + { SPOOLSS_FORM_BUILTIN, "Japan Envelope Kaku #3 Rotated", {0x43a08,0x34bc0}, {0x0,0x0,0x43a08,0x34bc0} }, + { SPOOLSS_FORM_BUILTIN, "Japan Envelope You #4 Rotated", {0x395f8,0x19a28}, {0x0,0x0,0x395f8,0x19a28} }, + { SPOOLSS_FORM_BUILTIN, "Japan Envelope You #4", {0x19a28,0x395f8}, {0x0,0x0,0x19a28,0x395f8} }, + { SPOOLSS_FORM_BUILTIN, "Japanese Double Postcard", {0x30d40,0x24220}, {0x0,0x0,0x30d40,0x24220} }, + { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Chou #3", {0x1d4c0,0x395f8}, {0x0,0x0,0x1d4c0,0x395f8} }, + { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Chou #4", {0x15f90,0x320c8}, {0x0,0x0,0x15f90,0x320c8} }, + { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Kaku #2", {0x3a980,0x510e0}, {0x0,0x0,0x3a980,0x510e0} }, + { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Kaku #3", {0x34bc0,0x43a08}, {0x0,0x0,0x34bc0,0x43a08} }, + { SPOOLSS_FORM_BUILTIN, "Japanese Postcard Rotated", {0x24220,0x186a0}, {0x0,0x0,0x24220,0x186a0} }, + { SPOOLSS_FORM_BUILTIN, "Japanese Postcard", {0x186a0,0x24220}, {0x0,0x0,0x186a0,0x24220} }, + { SPOOLSS_FORM_BUILTIN, "Ledger", {0x696b8,0x44368}, {0x0,0x0,0x696b8,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "Legal Extra", {0x3ae94,0x5d048}, {0x0,0x0,0x3ae94,0x5d048} }, + { SPOOLSS_FORM_BUILTIN, "Legal", {0x34b5c,0x56d10}, {0x0,0x0,0x34b5c,0x56d10} }, + { SPOOLSS_FORM_BUILTIN, "Letter Extra Transverse", {0x3ae94,0x4a6a0}, {0x0,0x0,0x3ae94,0x4a6a0} }, + { SPOOLSS_FORM_BUILTIN, "Letter Extra", {0x3ae94,0x4a6a0}, {0x0,0x0,0x3ae94,0x4a6a0} }, + { SPOOLSS_FORM_BUILTIN, "Letter Plus", {0x34b5c,0x4eb16}, {0x0,0x0,0x34b5c,0x4eb16} }, + { SPOOLSS_FORM_BUILTIN, "Letter Rotated", {0x44368,0x34b5c}, {0x0,0x0,0x44368,0x34b5c} }, + { SPOOLSS_FORM_BUILTIN, "Letter Small", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "Letter Transverse", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "Letter", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "Note", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, + { SPOOLSS_FORM_BUILTIN, "PRC 16K Rotated", {0x3f7a0,0x2de60}, {0x0,0x0,0x3f7a0,0x2de60} }, + { SPOOLSS_FORM_BUILTIN, "PRC 16K", {0x2de60,0x3f7a0}, {0x0,0x0,0x2de60,0x3f7a0} }, + { SPOOLSS_FORM_BUILTIN, "PRC 32K Rotated", {0x2cec0,0x1fbd0}, {0x0,0x0,0x2cec0,0x1fbd0} }, + { SPOOLSS_FORM_BUILTIN, "PRC 32K", {0x1fbd0,0x2cec0}, {0x0,0x0,0x1fbd0,0x2cec0} }, + { SPOOLSS_FORM_BUILTIN, "PRC 32K(Big) Rotated", {0x318f8,0x222e0}, {0x0,0x0,0x318f8,0x222e0} }, + { SPOOLSS_FORM_BUILTIN, "PRC 32K(Big)", {0x222e0,0x318f8}, {0x0,0x0,0x222e0,0x318f8} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #1 Rotated", {0x28488,0x18e70}, {0x0,0x0,0x28488,0x18e70} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #1", {0x18e70,0x28488}, {0x0,0x0,0x18e70,0x28488} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #10 Rotated", {0x6fd10,0x4f1a0}, {0x0,0x0,0x6fd10,0x4f1a0} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #10", {0x4f1a0,0x6fd10}, {0x0,0x0,0x4f1a0,0x6fd10} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #2 Rotated", {0x2af80,0x18e70}, {0x0,0x0,0x2af80,0x18e70} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #2", {0x18e70,0x2af80}, {0x0,0x0,0x18e70,0x2af80} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #3 Rotated", {0x2af80,0x1e848}, {0x0,0x0,0x2af80,0x1e848} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #3", {0x1e848,0x2af80}, {0x0,0x0,0x1e848,0x2af80} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #4 Rotated", {0x32c80,0x1adb0}, {0x0,0x0,0x32c80,0x1adb0} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #4", {0x1adb0,0x32c80}, {0x0,0x0,0x1adb0,0x32c80} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #5 Rotated", {0x35b60,0x1adb0}, {0x0,0x0,0x35b60,0x1adb0} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #5", {0x1adb0,0x35b60}, {0x0,0x0,0x1adb0,0x35b60} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #6 Rotated", {0x38270,0x1d4c0}, {0x0,0x0,0x38270,0x1d4c0} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #6", {0x1d4c0,0x38270}, {0x0,0x0,0x1d4c0,0x38270} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #7 Rotated", {0x38270,0x27100}, {0x0,0x0,0x38270,0x27100} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #7", {0x27100,0x38270}, {0x0,0x0,0x27100,0x38270} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #8 Rotated", {0x4b708,0x1d4c0}, {0x0,0x0,0x4b708,0x1d4c0} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #8", {0x1d4c0,0x4b708}, {0x0,0x0,0x1d4c0,0x4b708} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #9 Rotated", {0x4f1a0,0x37e88}, {0x0,0x0,0x4f1a0,0x37e88} }, + { SPOOLSS_FORM_BUILTIN, "PRC Envelope #9", {0x37e88,0x4f1a0}, {0x0,0x0,0x37e88,0x4f1a0} }, + { SPOOLSS_FORM_BUILTIN, "Quarto", {0x347d8,0x43238}, {0x0,0x0,0x347d8,0x43238} }, + { SPOOLSS_FORM_BUILTIN, "Reserved48", {0x1,0x1}, {0x0,0x0,0x1,0x1} }, + { SPOOLSS_FORM_BUILTIN, "Reserved49", {0x1,0x1}, {0x0,0x0,0x1,0x1} }, + { SPOOLSS_FORM_BUILTIN, "Statement", {0x221b4,0x34b5c}, {0x0,0x0,0x221b4,0x34b5c} }, + { SPOOLSS_FORM_BUILTIN, "Super A", {0x376b8,0x56ea0}, {0x0,0x0,0x376b8,0x56ea0} }, + { SPOOLSS_FORM_BUILTIN, "Super B", {0x4a768,0x76e58}, {0x0,0x0,0x4a768,0x76e58} }, + { SPOOLSS_FORM_BUILTIN, "Tabloid Extra", {0x4a6a0,0x6f9f0}, {0x0,0x0,0x4a6a0,0x6f9f0} }, + { SPOOLSS_FORM_BUILTIN, "Tabloid", {0x44368,0x696b8}, {0x0,0x0,0x44368,0x696b8} }, + { SPOOLSS_FORM_BUILTIN, "US Std Fanfold", {0x5c3e1,0x44368}, {0x0,0x0,0x5c3e1,0x44368} } +}; + +/******************************************************************** + static helper functions +********************************************************************/ + +/**************************************************************************** + Update the changeid time. +****************************************************************************/ +/** + * @internal + * + * @brief Update the ChangeID time of a printer. + * + * This is SO NASTY as some drivers need this to change, others need it + * static. This value will change every second, and I must hope that this + * is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF + * UTAH ! JRA. + * + * @return The ChangeID. + */ +static uint32_t winreg_printer_rev_changeid(void) +{ + struct timeval tv; + + get_process_uptime(&tv); + +#if 1 /* JERRY */ + /* Return changeid as msec since spooler restart */ + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +#else + /* + * This setting seems to work well but is too untested + * to replace the above calculation. Left in for experimentation + * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002) + */ + return tv.tv_sec * 10 + tv.tv_usec / 100000; +#endif +} + +/** + * @internal + * + * @brief Connect to the interal winreg server and open the given printer key. + * + * The function will create the needed subkeys if they don't exist. + * + * @param[in] mem_ctx The memory context to use. + * + * @param[in] server_info The supplied server info. + * + * @param[out] binding_handle A pointer for the winreg dcerpc binding handle. + * + * @param[in] path The path to the key to open. + * + * @param[in] key The key to open. + * + * @param[in] create_key Set to true if the key should be created if it + * doesn't exist. + * + * @param[in] access_mask The access mask to open the key. + * + * @param[out] hive_handle A policy handle for the opened hive. + * + * @param[out] key_handle A policy handle for the opened key. + * + * @return WERR_OK on success, the corresponding DOS error + * code if something gone wrong. + */ +static WERROR winreg_printer_openkey(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct dcerpc_binding_handle **winreg_binding_handle, + const char *path, + const char *key, + bool create_key, + uint32_t access_mask, + struct policy_handle *hive_handle, + struct policy_handle *key_handle) +{ + static struct client_address client_id; + struct dcerpc_binding_handle *binding_handle; + struct winreg_String wkey, wkeyclass; + char *keyname; + NTSTATUS status; + WERROR result = WERR_OK; + + strlcpy(client_id.addr, "127.0.0.1", sizeof(client_id.addr)); + client_id.name = "127.0.0.1"; + + status = rpcint_binding_handle(mem_ctx, + &ndr_table_winreg, + &client_id, + server_info, + msg_ctx, + &binding_handle); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_openkey: Could not connect to winreg pipe: %s\n", + nt_errstr(status))); + return ntstatus_to_werror(status); + } + + status = dcerpc_winreg_OpenHKLM(binding_handle, + mem_ctx, + NULL, + access_mask, + hive_handle, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_openkey: Could not open HKLM hive: %s\n", + nt_errstr(status))); + talloc_free(binding_handle); + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_openkey: Could not open HKLM hive: %s\n", + win_errstr(result))); + talloc_free(binding_handle); + return result; + } + + if (key && *key) { + keyname = talloc_asprintf(mem_ctx, "%s\\%s", path, key); + } else { + keyname = talloc_strdup(mem_ctx, path); + } + if (keyname == NULL) { + talloc_free(binding_handle); + return WERR_NOMEM; + } + + ZERO_STRUCT(wkey); + wkey.name = keyname; + + if (create_key) { + enum winreg_CreateAction action = REG_ACTION_NONE; + + ZERO_STRUCT(wkeyclass); + wkeyclass.name = ""; + + status = dcerpc_winreg_CreateKey(binding_handle, + mem_ctx, + hive_handle, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + key_handle, + &action, + &result); + switch (action) { + case REG_ACTION_NONE: + DEBUG(8, ("winreg_printer_openkey:createkey did nothing -- huh?\n")); + break; + case REG_CREATED_NEW_KEY: + DEBUG(8, ("winreg_printer_openkey: createkey created %s\n", keyname)); + break; + case REG_OPENED_EXISTING_KEY: + DEBUG(8, ("winreg_printer_openkey: createkey opened existing %s\n", keyname)); + break; + } + } else { + status = dcerpc_winreg_OpenKey(binding_handle, + mem_ctx, + hive_handle, + wkey, + 0, + access_mask, + key_handle, + &result); + } + if (!NT_STATUS_IS_OK(status)) { + talloc_free(binding_handle); + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + talloc_free(binding_handle); + return result; + } + + *winreg_binding_handle = binding_handle; + + return WERR_OK; +} + +/** + * @brief Create the registry keyname for the given printer. + * + * @param[in] mem_ctx The memory context to use. + * + * @param[in] printer The name of the printer to get the registry key. + * + * @return The registry key or NULL on error. + */ +static char *winreg_printer_data_keyname(TALLOC_CTX *mem_ctx, const char *printer) { + return talloc_asprintf(mem_ctx, "%s\\%s", TOP_LEVEL_PRINT_PRINTERS_KEY, printer); +} + +/** + * @internal + * + * @brief Enumerate values of an opened key handle and retrieve the data. + * + * @param[in] mem_ctx The memory context to use. + * + * @param[in] winreg_handle The binding handle for the rpc connection. + * + * @param[in] key_hnd The opened key handle. + * + * @param[out] pnum_values A pointer to store he number of values found. + * + * @param[out] pnum_values A pointer to store the number of values we found. + * + * @return WERR_OK on success, the corresponding DOS error + * code if something gone wrong. + */ +static WERROR winreg_printer_enumvalues(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + struct policy_handle *key_hnd, + uint32_t *pnum_values, + struct spoolss_PrinterEnumValues **penum_values) +{ + TALLOC_CTX *tmp_ctx; + uint32_t num_subkeys, max_subkeylen, max_classlen; + uint32_t num_values, max_valnamelen, max_valbufsize; + uint32_t secdescsize; + uint32_t i; + NTTIME last_changed_time; + struct winreg_String classname; + + struct spoolss_PrinterEnumValues *enum_values; + + WERROR result = WERR_OK; + NTSTATUS status; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + ZERO_STRUCT(classname); + + status = dcerpc_winreg_QueryInfoKey(winreg_handle, + tmp_ctx, + key_hnd, + &classname, + &num_subkeys, + &max_subkeylen, + &max_classlen, + &num_values, + &max_valnamelen, + &max_valbufsize, + &secdescsize, + &last_changed_time, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_enumvalues: Could not query info: %s\n", + nt_errstr(status))); + result = ntstatus_to_werror(status); + goto error; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_enumvalues: Could not query info: %s\n", + win_errstr(result))); + goto error; + } + + if (num_values == 0) { + *pnum_values = 0; + TALLOC_FREE(tmp_ctx); + return WERR_OK; + } + + enum_values = TALLOC_ARRAY(tmp_ctx, struct spoolss_PrinterEnumValues, num_values); + if (enum_values == NULL) { + result = WERR_NOMEM; + goto error; + } + + for (i = 0; i < num_values; i++) { + struct spoolss_PrinterEnumValues val; + struct winreg_ValNameBuf name_buf; + enum winreg_Type type = REG_NONE; + uint8_t *data; + uint32_t data_size; + uint32_t length; + char n = '\0'; + + name_buf.name = &n; + name_buf.size = max_valnamelen + 2; + name_buf.length = 0; + + data_size = max_valbufsize; + data = NULL; + if (data_size) { + data = (uint8_t *) TALLOC(tmp_ctx, data_size); + } + length = 0; + + status = dcerpc_winreg_EnumValue(winreg_handle, + tmp_ctx, + key_hnd, + i, + &name_buf, + &type, + data, + data_size ? &data_size : NULL, + &length, + &result); + if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS) ) { + result = WERR_OK; + status = NT_STATUS_OK; + break; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_enumvalues: Could not enumerate values: %s\n", + nt_errstr(status))); + result = ntstatus_to_werror(status); + goto error; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_enumvalues: Could not enumerate values: %s\n", + win_errstr(result))); + goto error; + } + + if (name_buf.name == NULL) { + result = WERR_INVALID_PARAMETER; + goto error; + } + + val.value_name = talloc_strdup(enum_values, name_buf.name); + if (val.value_name == NULL) { + result = WERR_NOMEM; + goto error; + } + val.value_name_len = strlen_m_term(val.value_name) * 2; + + val.type = type; + val.data_length = length; + val.data = NULL; + if (val.data_length) { + val.data = talloc(enum_values, DATA_BLOB); + if (val.data == NULL) { + result = WERR_NOMEM; + goto error; + } + *val.data = data_blob_talloc(val.data, data, val.data_length); + } + + enum_values[i] = val; + } + + *pnum_values = num_values; + if (penum_values) { + *penum_values = talloc_move(mem_ctx, &enum_values); + } + + result = WERR_OK; + + error: + TALLOC_FREE(tmp_ctx); + return result; +} + +/** + * @internal + * + * @brief A function to delete a key and its subkeys recurively. + * + * @param[in] mem_ctx The memory context to use. + * + * @param[in] winreg_handle The binding handle for the rpc connection. + * + * @param[in] hive_handle A opened hive handle to the key. + * + * @param[in] access_mask The access mask to access the key. + * + * @param[in] key The key to delete + * + * @return WERR_OK on success, the corresponding DOS error + * code if something gone wrong. + */ +static WERROR winreg_printer_delete_subkeys(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + struct policy_handle *hive_handle, + uint32_t access_mask, + const char *key) +{ + const char **subkeys = NULL; + uint32_t num_subkeys = 0; + struct policy_handle key_hnd; + struct winreg_String wkey; + WERROR result = WERR_OK; + NTSTATUS status; + uint32_t i; + + ZERO_STRUCT(key_hnd); + wkey.name = key; + + DEBUG(2, ("winreg_printer_delete_subkeys: delete key %s\n", key)); + /* open the key */ + status = dcerpc_winreg_OpenKey(winreg_handle, + mem_ctx, + hive_handle, + wkey, + 0, + access_mask, + &key_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_delete_subkeys: Could not open key %s: %s\n", + wkey.name, nt_errstr(status))); + return ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_delete_subkeys: Could not open key %s: %s\n", + wkey.name, win_errstr(result))); + return result; + } + + status = dcerpc_winreg_enum_keys(mem_ctx, + winreg_handle, + &key_hnd, + &num_subkeys, + &subkeys, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + for (i = 0; i < num_subkeys; i++) { + /* create key + subkey */ + char *subkey = talloc_asprintf(mem_ctx, "%s\\%s", key, subkeys[i]); + if (subkey == NULL) { + goto done; + } + + DEBUG(2, ("winreg_printer_delete_subkeys: delete subkey %s\n", subkey)); + result = winreg_printer_delete_subkeys(mem_ctx, + winreg_handle, + hive_handle, + access_mask, + subkey); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (is_valid_policy_hnd(&key_hnd)) { + WERROR ignore; + dcerpc_winreg_CloseKey(winreg_handle, mem_ctx, &key_hnd, &ignore); + } + + wkey.name = key; + + status = dcerpc_winreg_DeleteKey(winreg_handle, + mem_ctx, + hive_handle, + wkey, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + +done: + if (is_valid_policy_hnd(&key_hnd)) { + WERROR ignore; + + dcerpc_winreg_CloseKey(winreg_handle, mem_ctx, &key_hnd, &ignore); + } + + return result; +} + +static WERROR winreg_printer_opendriver(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *drivername, + const char *architecture, + uint32_t version, + uint32_t access_mask, + bool create, + struct dcerpc_binding_handle **winreg_binding_handle, + struct policy_handle *hive_hnd, + struct policy_handle *key_hnd) +{ + WERROR result; + char *key_name; + + key_name = talloc_asprintf(mem_ctx, "%s\\Environments\\%s\\Drivers\\Version-%u", + TOP_LEVEL_CONTROL_KEY, + architecture, version); + if (!key_name) { + return WERR_NOMEM; + } + + result = winreg_printer_openkey(mem_ctx, + server_info, + msg_ctx, + winreg_binding_handle, + key_name, + drivername, + create, + access_mask, + hive_hnd, + key_hnd); + return result; +} + +static WERROR winreg_enumval_to_dword(TALLOC_CTX *mem_ctx, + struct spoolss_PrinterEnumValues *v, + const char *valuename, uint32_t *dw) +{ + /* just return if it is not the one we are looking for */ + if (strcmp(valuename, v->value_name) != 0) { + return WERR_NOT_FOUND; + } + + if (v->type != REG_DWORD) { + return WERR_INVALID_DATATYPE; + } + + if (v->data_length != 4) { + *dw = 0; + return WERR_OK; + } + + *dw = IVAL(v->data->data, 0); + return WERR_OK; +} + +static WERROR winreg_enumval_to_sz(TALLOC_CTX *mem_ctx, + struct spoolss_PrinterEnumValues *v, + const char *valuename, const char **_str) +{ + /* just return if it is not the one we are looking for */ + if (strcmp(valuename, v->value_name) != 0) { + return WERR_NOT_FOUND; + } + + if (v->type != REG_SZ) { + return WERR_INVALID_DATATYPE; + } + + if (v->data_length == 0) { + *_str = talloc_strdup(mem_ctx, EMPTY_STRING); + if (*_str == NULL) { + return WERR_NOMEM; + } + return WERR_OK; + } + + if (!pull_reg_sz(mem_ctx, v->data, _str)) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +static WERROR winreg_enumval_to_multi_sz(TALLOC_CTX *mem_ctx, + struct spoolss_PrinterEnumValues *v, + const char *valuename, + const char ***array) +{ + /* just return if it is not the one we are looking for */ + if (strcmp(valuename, v->value_name) != 0) { + return WERR_NOT_FOUND; + } + + if (v->type != REG_MULTI_SZ) { + return WERR_INVALID_DATATYPE; + } + + if (v->data_length == 0) { + *array = talloc_array(mem_ctx, const char *, 1); + if (*array == NULL) { + return WERR_NOMEM; + } + *array[0] = NULL; + return WERR_OK; + } + + if (!pull_reg_multi_sz(mem_ctx, v->data, array)) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +static WERROR winreg_printer_write_date(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + struct policy_handle *key_handle, + const char *value, + NTTIME data) +{ + struct winreg_String wvalue; + DATA_BLOB blob; + WERROR result = WERR_OK; + NTSTATUS status; + const char *str; + struct tm *tm; + time_t t; + + if (data == 0) { + str = talloc_strdup(mem_ctx, "01/01/1601"); + } else { + t = nt_time_to_unix(data); + tm = localtime(&t); + str = talloc_asprintf(mem_ctx, "%02d/%02d/%04d", + tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900); + } + if (!str) { + return WERR_NOMEM; + } + + wvalue.name = value; + if (!push_reg_sz(mem_ctx, &blob, str)) { + return WERR_NOMEM; + } + status = dcerpc_winreg_SetValue(winreg_handle, + mem_ctx, + key_handle, + wvalue, + REG_SZ, + blob.data, + blob.length, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_write_date: Could not set value %s: %s\n", + wvalue.name, win_errstr(result))); + } + + return result; +} + +static WERROR winreg_printer_date_to_NTTIME(const char *str, NTTIME *data) +{ + struct tm tm; + time_t t; + + if (strequal(str, "01/01/1601")) { + *data = 0; + return WERR_OK; + } + + ZERO_STRUCT(tm); + + if (sscanf(str, "%d/%d/%d", + &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3) { + return WERR_INVALID_PARAMETER; + } + tm.tm_mon -= 1; + tm.tm_year -= 1900; + tm.tm_isdst = -1; + + t = mktime(&tm); + unix_to_nt_time(data, t); + + return WERR_OK; +} + +static WERROR winreg_printer_write_ver(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *winreg_handle, + struct policy_handle *key_handle, + const char *value, + uint64_t data) +{ + struct winreg_String wvalue; + DATA_BLOB blob; + WERROR result = WERR_OK; + NTSTATUS status; + char *str; + + /* FIXME: check format is right, + * this needs to be something like: 6.1.7600.16385 */ + str = talloc_asprintf(mem_ctx, "%u.%u.%u.%u", + (unsigned)((data >> 48) & 0xFFFF), + (unsigned)((data >> 32) & 0xFFFF), + (unsigned)((data >> 16) & 0xFFFF), + (unsigned)(data & 0xFFFF)); + if (!str) { + return WERR_NOMEM; + } + + wvalue.name = value; + if (!push_reg_sz(mem_ctx, &blob, str)) { + return WERR_NOMEM; + } + status = dcerpc_winreg_SetValue(winreg_handle, + mem_ctx, + key_handle, + wvalue, + REG_SZ, + blob.data, + blob.length, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_write_date: Could not set value %s: %s\n", + wvalue.name, win_errstr(result))); + } + + return result; +} + +static WERROR winreg_printer_ver_to_dword(const char *str, uint64_t *data) +{ + unsigned int v1, v2, v3, v4; + + if (sscanf(str, "%u.%u.%u.%u", &v1, &v2, &v3, &v4) != 4) { + return WERR_INVALID_PARAMETER; + } + + *data = ((uint64_t)(v1 & 0xFFFF) << 48) + + ((uint64_t)(v2 & 0xFFFF) << 32) + + ((uint64_t)(v3 & 0xFFFF) << 16) + + (uint64_t)(v2 & 0xFFFF); + + return WERR_OK; +} + +/******************************************************************** + Public winreg function for spoolss +********************************************************************/ + +WERROR winreg_create_printer(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct spoolss_SetPrinterInfo2 *info2; + struct security_descriptor *secdesc; + struct winreg_String wkey, wkeyclass; + const char *path; + const char *subkeys[] = { SPOOL_DSDRIVER_KEY, SPOOL_DSSPOOLER_KEY, SPOOL_PRINTERDATA_KEY }; + uint32_t i, count = ARRAY_SIZE(subkeys); + uint32_t info2_mask = 0; + WERROR result = WERR_OK; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, sharename); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_create_printer: Skipping, %s already exists\n", path)); + goto done; + } else if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + DEBUG(2, ("winreg_create_printer: Creating default values in %s\n", path)); + } else if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_create_printer: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + /* Create the main key */ + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_create_printer_keys: Could not create key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); + } + + /* Create subkeys */ + for (i = 0; i < count; i++) { + NTSTATUS status; + enum winreg_CreateAction action = REG_ACTION_NONE; + + ZERO_STRUCT(key_hnd); + ZERO_STRUCT(wkey); + + wkey.name = talloc_asprintf(tmp_ctx, "%s\\%s", path, subkeys[i]); + if (wkey.name == NULL) { + result = WERR_NOMEM; + goto done; + } + + ZERO_STRUCT(wkeyclass); + wkeyclass.name = ""; + + status = dcerpc_winreg_CreateKey(winreg_handle, + tmp_ctx, + &hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_create_printer_keys: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + if (strequal(subkeys[i], SPOOL_DSSPOOLER_KEY)) { + const char *dnssuffix; + const char *longname; + const char *uncname; + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_PRINTERNAME, + sharename, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_SHORTSERVERNAME, + global_myname(), + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* We make the assumption that the netbios name + * is the same as the DNS name since the former + * will be what we used to join the domain + */ + dnssuffix = get_mydnsdomname(tmp_ctx); + if (dnssuffix != NULL && dnssuffix[0] != '\0') { + longname = talloc_asprintf(tmp_ctx, "%s.%s", global_myname(), dnssuffix); + } else { + longname = talloc_strdup(tmp_ctx, global_myname()); + } + if (longname == NULL) { + result = WERR_NOMEM; + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_SERVERNAME, + longname, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + uncname = talloc_asprintf(tmp_ctx, "\\\\%s\\%s", + longname, sharename); + if (uncname == NULL) { + result = WERR_NOMEM; + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_UNCNAME, + uncname, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_VERSIONNUMBER, + 4, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_PRINTSTARTTIME, + 0, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_PRINTENDTIME, + 0, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_PRIORITY, + 1, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + SPOOL_REG_PRINTKEEPPRINTEDJOBS, + 0, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); + } + } + info2 = talloc_zero(tmp_ctx, struct spoolss_SetPrinterInfo2); + if (info2 == NULL) { + result = WERR_NOMEM; + goto done; + } + + info2->printername = sharename; + if (info2->printername == NULL) { + result = WERR_NOMEM; + goto done; + } + info2_mask |= SPOOLSS_PRINTER_INFO_PRINTERNAME; + + info2->sharename = sharename; + info2_mask |= SPOOLSS_PRINTER_INFO_SHARENAME; + + info2->portname = SAMBA_PRINTER_PORT_NAME; + info2_mask |= SPOOLSS_PRINTER_INFO_PORTNAME; + + info2->printprocessor = "winprint"; + info2_mask |= SPOOLSS_PRINTER_INFO_PRINTPROCESSOR; + + info2->datatype = "RAW"; + info2_mask |= SPOOLSS_PRINTER_INFO_DATATYPE; + + info2->comment = ""; + info2_mask |= SPOOLSS_PRINTER_INFO_COMMENT; + + info2->attributes = PRINTER_ATTRIBUTE_SAMBA; + info2_mask |= SPOOLSS_PRINTER_INFO_ATTRIBUTES; + + info2->starttime = 0; /* Minutes since 12:00am GMT */ + info2_mask |= SPOOLSS_PRINTER_INFO_STARTTIME; + + info2->untiltime = 0; /* Minutes since 12:00am GMT */ + info2_mask |= SPOOLSS_PRINTER_INFO_UNTILTIME; + + info2->priority = 1; + info2_mask |= SPOOLSS_PRINTER_INFO_PRIORITY; + + info2->defaultpriority = 1; + info2_mask |= SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY; + + result = spoolss_create_default_secdesc(tmp_ctx, &secdesc); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + info2_mask |= SPOOLSS_PRINTER_INFO_SECDESC; + + /* + * Don't write a default Device Mode to the registry! The Device Mode is + * only written to disk with a SetPrinter level 2 or 8. + */ + + result = winreg_update_printer(tmp_ctx, + server_info, + msg_ctx, + sharename, + info2_mask, + info2, + NULL, + secdesc); + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + talloc_free(tmp_ctx); + return result; +} + +WERROR winreg_update_printer(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename, + uint32_t info2_mask, + struct spoolss_SetPrinterInfo2 *info2, + struct spoolss_DeviceMode *devmode, + struct security_descriptor *secdesc) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + int snum = lp_servicenumber(sharename); + enum ndr_err_code ndr_err; + DATA_BLOB blob; + char *path; + WERROR result = WERR_OK; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, sharename); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_update_printer: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_ATTRIBUTES) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Attributes", + info2->attributes, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + +#if 0 + if (info2_mask & SPOOLSS_PRINTER_INFO_AVERAGEPPM) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "AveragePpm", + info2->attributes, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } +#endif + + if (info2_mask & SPOOLSS_PRINTER_INFO_COMMENT) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Description", + info2->comment, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_DATATYPE) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Datatype", + info2->datatype, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Default Priority", + info2->defaultpriority, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_DEVMODE) { + /* + * Some client drivers freak out if there is a NULL devmode + * (probably the driver is not checking before accessing + * the devmode pointer) --jerry + */ + if (devmode == NULL && lp_default_devmode(snum) && info2 != NULL) { + result = spoolss_create_default_devmode(tmp_ctx, + info2->printername, + &devmode); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (devmode->size != (ndr_size_spoolss_DeviceMode(devmode, 0) - devmode->__driverextra_length)) { + result = WERR_INVALID_PARAM; + goto done; + } + + ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, devmode, + (ndr_push_flags_fn_t) ndr_push_spoolss_DeviceMode); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("winreg_update_printer: Failed to marshall device mode\n")); + result = WERR_NOMEM; + goto done; + } + + status = dcerpc_winreg_set_binary(tmp_ctx, + winreg_handle, + &key_hnd, + "Default DevMode", + &blob, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_DRIVERNAME) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Printer Driver", + info2->drivername, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_LOCATION) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Location", + info2->location, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_PARAMETERS) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Parameters", + info2->parameters, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_PORTNAME) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Port", + info2->portname, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_PRINTERNAME) { + /* + * in addprinter: no servername and the printer is the name + * in setprinter: servername is \\server + * and printer is \\server\\printer + * + * Samba manages only local printers. + * we currently don't support things like i + * path=\\other_server\printer + * + * We only store the printername, not \\server\printername + */ + const char *p = strrchr(info2->printername, '\\'); + if (p == NULL) { + p = info2->printername; + } else { + p++; + } + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Name", + p, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_PRINTPROCESSOR) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Print Processor", + info2->printprocessor, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_PRIORITY) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Priority", + info2->priority, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_SECDESC) { + /* + * We need a security descriptor, if it isn't specified by + * AddPrinter{Ex} then create a default descriptor. + */ + if (secdesc == NULL) { + result = spoolss_create_default_secdesc(tmp_ctx, &secdesc); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + result = winreg_set_printer_secdesc(tmp_ctx, + server_info, + msg_ctx, + sharename, + secdesc); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_SEPFILE) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Separator File", + info2->sepfile, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_SHARENAME) { + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Share Name", + info2->sharename, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_STARTTIME) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "StartTime", + info2->starttime, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_STATUS) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Status", + info2->status, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2_mask & SPOOLSS_PRINTER_INFO_UNTILTIME) { + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "UntilTime", + info2->untiltime, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "ChangeID", + winreg_printer_rev_changeid(), + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_get_printer(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + struct spoolss_PrinterInfo2 **pinfo2) +{ + struct spoolss_PrinterInfo2 *info2; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct spoolss_PrinterEnumValues *enum_values = NULL; + struct spoolss_PrinterEnumValues *v = NULL; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + int snum = lp_servicenumber(printer); + uint32_t num_values = 0; + uint32_t i; + char *path; + NTSTATUS status; + WERROR result = WERR_OK; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_get_printer: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + result = winreg_printer_enumvalues(tmp_ctx, + winreg_handle, + &key_hnd, + &num_values, + &enum_values); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_get_printer: Could not enumerate values in %s: %s\n", + path, win_errstr(result))); + goto done; + } + + info2 = talloc_zero(tmp_ctx, struct spoolss_PrinterInfo2); + if (info2 == NULL) { + result = WERR_NOMEM; + goto done; + } + + FILL_STRING(info2, EMPTY_STRING, info2->servername); + FILL_STRING(info2, EMPTY_STRING, info2->printername); + FILL_STRING(info2, EMPTY_STRING, info2->sharename); + FILL_STRING(info2, EMPTY_STRING, info2->portname); + FILL_STRING(info2, EMPTY_STRING, info2->drivername); + FILL_STRING(info2, EMPTY_STRING, info2->comment); + FILL_STRING(info2, EMPTY_STRING, info2->location); + FILL_STRING(info2, EMPTY_STRING, info2->sepfile); + FILL_STRING(info2, EMPTY_STRING, info2->printprocessor); + FILL_STRING(info2, EMPTY_STRING, info2->datatype); + FILL_STRING(info2, EMPTY_STRING, info2->parameters); + + for (i = 0; i < num_values; i++) { + v = &enum_values[i]; + + result = winreg_enumval_to_sz(info2, + v, + "Name", + &info2->printername); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Share Name", + &info2->sharename); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Port", + &info2->portname); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Description", + &info2->comment); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Location", + &info2->location); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Separator File", + &info2->sepfile); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Print Processor", + &info2->printprocessor); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Datatype", + &info2->datatype); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Parameters", + &info2->parameters); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info2, + v, + "Printer Driver", + &info2->drivername); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info2, + v, + "Attributes", + &info2->attributes); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info2, + v, + "Priority", + &info2->priority); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info2, + v, + "Default Priority", + &info2->defaultpriority); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info2, + v, + "StartTime", + &info2->starttime); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info2, + v, + "UntilTime", + &info2->untiltime); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info2, + v, + "Status", + &info2->status); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info2, + v, + "StartTime", + &info2->starttime); + CHECK_ERROR(result); + } + + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_get_printer: winreg_enumval_to_TYPE() failed " + "for %s: %s\n", + v->value_name, + win_errstr(result))); + goto done; + } + + /* Construct the Device Mode */ + status = dcerpc_winreg_query_binary(tmp_ctx, + winreg_handle, + &key_hnd, + "Default DevMode", + &blob, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (W_ERROR_IS_OK(result)) { + info2->devmode = talloc_zero(info2, struct spoolss_DeviceMode); + if (info2->devmode == NULL) { + result = WERR_NOMEM; + goto done; + } + ndr_err = ndr_pull_struct_blob(&blob, + info2->devmode, + info2->devmode, + (ndr_pull_flags_fn_t) ndr_pull_spoolss_DeviceMode); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0, ("winreg_get_printer: Failed to unmarshall device mode\n")); + result = WERR_NOMEM; + goto done; + } + } + + if (info2->devmode == NULL && lp_default_devmode(snum)) { + result = spoolss_create_default_devmode(info2, + info2->printername, + &info2->devmode); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + } + + if (info2->devmode) { + info2->devmode->size = ndr_size_spoolss_DeviceMode(info2->devmode, 0) - info2->devmode->driverextra_data.length; + } + + result = winreg_get_printer_secdesc(info2, + server_info, + msg_ctx, + printer, + &info2->secdesc); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* Fix for OS/2 drivers. */ + if (get_remote_arch() == RA_OS2) { + spoolss_map_to_os2_driver(info2, &info2->drivername); + } + + if (pinfo2) { + *pinfo2 = talloc_move(mem_ctx, &info2); + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_get_printer_secdesc(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename, + struct spoolss_security_descriptor **psecdesc) +{ + struct spoolss_security_descriptor *secdesc; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + const char *path; + TALLOC_CTX *tmp_ctx; + NTSTATUS status; + WERROR result; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, sharename); + if (path == NULL) { + talloc_free(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + goto create_default; + } + goto done; + } + + status = dcerpc_winreg_query_sd(tmp_ctx, + winreg_handle, + &key_hnd, + "Security", + &secdesc, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + goto create_default; + } + goto done; + } + + if (psecdesc) { + *psecdesc = talloc_move(mem_ctx, &secdesc); + } + + result = WERR_OK; + goto done; + +create_default: + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = spoolss_create_default_secdesc(tmp_ctx, &secdesc); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + /* If security descriptor is owned by S-1-1-0 and winbindd is up, + this security descriptor has been created when winbindd was + down. Take ownership of security descriptor. */ + if (dom_sid_equal(secdesc->owner_sid, &global_sid_World)) { + struct dom_sid owner_sid; + + /* Change sd owner to workgroup administrator */ + + if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) { + struct spoolss_security_descriptor *new_secdesc; + size_t size; + + /* Create new sd */ + sid_append_rid(&owner_sid, DOMAIN_RID_ADMINISTRATOR); + + new_secdesc = make_sec_desc(tmp_ctx, + secdesc->revision, + secdesc->type, + &owner_sid, + secdesc->group_sid, + secdesc->sacl, + secdesc->dacl, + &size); + + if (new_secdesc == NULL) { + result = WERR_NOMEM; + goto done; + } + + /* Swap with other one */ + secdesc = new_secdesc; + } + } + + status = dcerpc_winreg_set_sd(tmp_ctx, + winreg_handle, + &key_hnd, + "Security", + secdesc, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + return result; + } + + if (psecdesc) { + *psecdesc = talloc_move(mem_ctx, &secdesc); + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + talloc_free(tmp_ctx); + return result; +} + +WERROR winreg_set_printer_secdesc(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename, + const struct spoolss_security_descriptor *secdesc) +{ + const struct spoolss_security_descriptor *new_secdesc = secdesc; + struct spoolss_security_descriptor *old_secdesc; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + const char *path; + TALLOC_CTX *tmp_ctx; + NTSTATUS status; + WERROR result; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, sharename); + if (path == NULL) { + talloc_free(tmp_ctx); + return WERR_NOMEM; + } + + /* + * The old owner and group sids of the security descriptor are not + * present when new ACEs are added or removed by changing printer + * permissions through NT. If they are NULL in the new security + * descriptor then copy them over from the old one. + */ + if (!secdesc->owner_sid || !secdesc->group_sid) { + struct dom_sid *owner_sid, *group_sid; + struct security_acl *dacl, *sacl; + size_t size; + + result = winreg_get_printer_secdesc(tmp_ctx, + server_info, + msg_ctx, + sharename, + &old_secdesc); + if (!W_ERROR_IS_OK(result)) { + talloc_free(tmp_ctx); + return result; + } + + /* Pick out correct owner and group sids */ + owner_sid = secdesc->owner_sid ? + secdesc->owner_sid : + old_secdesc->owner_sid; + + group_sid = secdesc->group_sid ? + secdesc->group_sid : + old_secdesc->group_sid; + + dacl = secdesc->dacl ? + secdesc->dacl : + old_secdesc->dacl; + + sacl = secdesc->sacl ? + secdesc->sacl : + old_secdesc->sacl; + + /* Make a deep copy of the security descriptor */ + new_secdesc = make_sec_desc(tmp_ctx, + secdesc->revision, + secdesc->type, + owner_sid, + group_sid, + sacl, + dacl, + &size); + if (new_secdesc == NULL) { + talloc_free(tmp_ctx); + return WERR_NOMEM; + } + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sd(tmp_ctx, + winreg_handle, + &key_hnd, + "Security", + new_secdesc, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + talloc_free(tmp_ctx); + return result; +} + +/* Set printer data over the winreg pipe. */ +WERROR winreg_set_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + const char *value, + enum winreg_Type type, + uint8_t *data, + uint32_t data_size) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct winreg_String wvalue; + char *path; + WERROR result = WERR_OK; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + DEBUG(8, ("winreg_set_printer_dataex: Open printer key %s, value %s, access_mask: 0x%05x for [%s]\n", + key, value, access_mask, printer)); + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + key, + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_set_printer_dataex: Could not open key %s: %s\n", + key, win_errstr(result))); + goto done; + } + + wvalue.name = value; + status = dcerpc_winreg_SetValue(winreg_handle, + tmp_ctx, + &key_hnd, + wvalue, + type, + data, + data_size, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_set_printer_dataex: Could not set value %s: %s\n", + value, nt_errstr(status))); + result = ntstatus_to_werror(status); + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +/* Get printer data over a winreg pipe. */ +WERROR winreg_get_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + const char *value, + enum winreg_Type *type, + uint8_t **data, + uint32_t *data_size) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct winreg_String wvalue; + enum winreg_Type type_in; + char *path; + uint8_t *data_in; + uint32_t data_in_size = 0; + uint32_t value_len = 0; + WERROR result = WERR_OK; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + key, + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_get_printer_dataex: Could not open key %s: %s\n", + key, win_errstr(result))); + goto done; + } + + wvalue.name = value; + + /* + * call QueryValue once with data == NULL to get the + * needed memory size to be allocated, then allocate + * data buffer and call again. + */ + status = dcerpc_winreg_QueryValue(winreg_handle, + tmp_ctx, + &key_hnd, + &wvalue, + &type_in, + NULL, + &data_in_size, + &value_len, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_get_printer_dataex: Could not query value %s: %s\n", + value, nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + data_in = (uint8_t *) TALLOC(tmp_ctx, data_in_size); + if (data_in == NULL) { + result = WERR_NOMEM; + goto done; + } + value_len = 0; + + status = dcerpc_winreg_QueryValue(winreg_handle, + tmp_ctx, + &key_hnd, + &wvalue, + &type_in, + data_in, + &data_in_size, + &value_len, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_get_printer_dataex: Could not query value %s: %s\n", + value, nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + *type = type_in; + *data_size = data_in_size; + if (data_in_size) { + *data = talloc_move(mem_ctx, &data_in); + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +/* Enumerate on the values of a given key and provide the data. */ +WERROR winreg_enum_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + uint32_t *pnum_values, + struct spoolss_PrinterEnumValues **penum_values) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + + struct spoolss_PrinterEnumValues *enum_values = NULL; + uint32_t num_values = 0; + char *path; + WERROR result = WERR_OK; + + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + key, + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_enum_printer_dataex: Could not open key %s: %s\n", + key, win_errstr(result))); + goto done; + } + + result = winreg_printer_enumvalues(tmp_ctx, + winreg_handle, + &key_hnd, + &num_values, + &enum_values); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_enum_printer_dataex: Could not enumerate values in %s: %s\n", + key, win_errstr(result))); + goto done; + } + + *pnum_values = num_values; + if (penum_values) { + *penum_values = talloc_move(mem_ctx, &enum_values); + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +/* Delete printer data over a winreg pipe. */ +WERROR winreg_delete_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + const char *value) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct winreg_String wvalue; + char *path; + WERROR result = WERR_OK; + NTSTATUS status; + + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + key, + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_delete_printer_dataex: Could not open key %s: %s\n", + key, win_errstr(result))); + goto done; + } + + wvalue.name = value; + status = dcerpc_winreg_DeleteValue(winreg_handle, + tmp_ctx, + &key_hnd, + wvalue, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_delete_printer_dataex: Could not delete value %s: %s\n", + value, nt_errstr(status))); + result = ntstatus_to_werror(status); + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +/* Enumerate on the subkeys of a given key and provide the data. */ +WERROR winreg_enum_printer_key(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + uint32_t *pnum_subkeys, + const char ***psubkeys) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + char *path; + const char **subkeys = NULL; + uint32_t num_subkeys = -1; + + WERROR result = WERR_OK; + NTSTATUS status; + + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + key, + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_enum_printer_key: Could not open key %s: %s\n", + key, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_enum_keys(tmp_ctx, + winreg_handle, + &key_hnd, + &num_subkeys, + &subkeys, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_enum_printer_key: Could not enumerate subkeys in %s: %s\n", + key, win_errstr(result))); + goto done; + } + + *pnum_subkeys = num_subkeys; + if (psubkeys) { + *psubkeys = talloc_move(mem_ctx, &subkeys); + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +/* Delete a key with subkeys of a given printer. */ +WERROR winreg_delete_printer_key(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + char *keyname; + char *path; + WERROR result; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + key, + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + /* key doesn't exist */ + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + result = WERR_OK; + goto done; + } + + DEBUG(0, ("winreg_delete_printer_key: Could not open key %s: %s\n", + key, win_errstr(result))); + goto done; + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); + } + + if (key == NULL || key[0] == '\0') { + keyname = path; + } else { + keyname = talloc_asprintf(tmp_ctx, + "%s\\%s", + path, + key); + if (keyname == NULL) { + result = WERR_NOMEM; + goto done; + } + } + + result = winreg_printer_delete_subkeys(tmp_ctx, + winreg_handle, + &hive_hnd, + access_mask, + keyname); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_delete_printer_key: Could not delete key %s: %s\n", + key, win_errstr(result))); + goto done; + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_printer_update_changeid(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + char *path; + NTSTATUS status; + WERROR result; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_update_changeid: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "ChangeID", + winreg_printer_rev_changeid(), + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_printer_get_changeid(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + uint32_t *pchangeid) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + uint32_t changeid = 0; + char *path; + NTSTATUS status; + WERROR result; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + path = winreg_printer_data_keyname(tmp_ctx, printer); + if (path == NULL) { + TALLOC_FREE(tmp_ctx); + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + path, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_printer_get_changeid: Could not open key %s: %s\n", + path, win_errstr(result))); + goto done; + } + + DEBUG(10, ("winreg_printer_get_changeid: get changeid from %s\n", path)); + + status = dcerpc_winreg_query_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "ChangeID", + &changeid, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + if (pchangeid) { + *pchangeid = changeid; + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +/* + * The special behaviour of the spoolss forms is documented at the website: + * + * Managing Win32 Printserver Forms + * http://unixwiz.net/techtips/winspooler-forms.html + */ + +WERROR winreg_printer_addform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct spoolss_AddFormInfo1 *form) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct winreg_String wvalue; + DATA_BLOB blob; + uint32_t num_info = 0; + union spoolss_FormInfo *info = NULL; + uint32_t i; + WERROR result; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + TOP_LEVEL_CONTROL_FORMS_KEY, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_addform1: Could not open key %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + goto done; + } + + result = winreg_printer_enumforms1(tmp_ctx, server_info, msg_ctx, + &num_info, &info); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_addform: Could not enum keys %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + goto done; + } + + /* If form name already exists or is builtin return ALREADY_EXISTS */ + for (i = 0; i < num_info; i++) { + if (strequal(info[i].info1.form_name, form->form_name)) { + result = WERR_FILE_EXISTS; + goto done; + } + } + + wvalue.name = form->form_name; + + blob = data_blob_talloc(tmp_ctx, NULL, 32); + SIVAL(blob.data, 0, form->size.width); + SIVAL(blob.data, 4, form->size.height); + SIVAL(blob.data, 8, form->area.left); + SIVAL(blob.data, 12, form->area.top); + SIVAL(blob.data, 16, form->area.right); + SIVAL(blob.data, 20, form->area.bottom); + SIVAL(blob.data, 24, num_info + 1); /* FIXME */ + SIVAL(blob.data, 28, form->flags); + + status = dcerpc_winreg_SetValue(winreg_handle, + tmp_ctx, + &key_hnd, + wvalue, + REG_BINARY, + blob.data, + blob.length, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_addform1: Could not set value %s: %s\n", + wvalue.name, nt_errstr(status))); + result = ntstatus_to_werror(status); + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(info); + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_printer_enumforms1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t *pnum_info, + union spoolss_FormInfo **pinfo) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + union spoolss_FormInfo *info; + struct spoolss_PrinterEnumValues *enum_values = NULL; + uint32_t num_values = 0; + uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); + uint32_t i; + WERROR result; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + TOP_LEVEL_CONTROL_FORMS_KEY, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + /* key doesn't exist */ + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + result = WERR_OK; + goto done; + } + + DEBUG(0, ("winreg_printer_enumforms1: Could not open key %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + goto done; + } + + result = winreg_printer_enumvalues(tmp_ctx, + winreg_handle, + &key_hnd, + &num_values, + &enum_values); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_enumforms1: Could not enumerate values in %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + goto done; + } + + info = TALLOC_ARRAY(tmp_ctx, union spoolss_FormInfo, num_builtin + num_values); + if (info == NULL) { + result = WERR_NOMEM; + goto done; + } + + /* Enumerate BUILTIN forms */ + for (i = 0; i < num_builtin; i++) { + info[i].info1 = builtin_forms1[i]; + } + + /* Enumerate registry forms */ + for (i = 0; i < num_values; i++) { + union spoolss_FormInfo val; + + if (enum_values[i].type != REG_BINARY || + enum_values[i].data_length != 32) { + continue; + } + + val.info1.form_name = talloc_strdup(info, enum_values[i].value_name); + if (val.info1.form_name == NULL) { + result = WERR_NOMEM; + goto done; + } + + val.info1.size.width = IVAL(enum_values[i].data->data, 0); + val.info1.size.height = IVAL(enum_values[i].data->data, 4); + val.info1.area.left = IVAL(enum_values[i].data->data, 8); + val.info1.area.top = IVAL(enum_values[i].data->data, 12); + val.info1.area.right = IVAL(enum_values[i].data->data, 16); + val.info1.area.bottom = IVAL(enum_values[i].data->data, 20); + /* skip form index IVAL(enum_values[i].data->data, 24)));*/ + val.info1.flags = (enum spoolss_FormFlags) IVAL(enum_values[i].data->data, 28); + + info[i + num_builtin] = val; + } + + *pnum_info = num_builtin + num_values; + if (pinfo) { + *pinfo = talloc_move(mem_ctx, &info); + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(enum_values); + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_printer_deleteform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *form_name) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct winreg_String wvalue; + uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); + uint32_t i; + WERROR result = WERR_OK; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + for (i = 0; i < num_builtin; i++) { + if (strequal(builtin_forms1[i].form_name, form_name)) { + return WERR_INVALID_PARAMETER; + } + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + TOP_LEVEL_CONTROL_FORMS_KEY, + "", + false, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_deleteform1: Could not open key %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + result = WERR_INVALID_FORM_NAME; + } + goto done; + } + + wvalue.name = form_name; + status = dcerpc_winreg_DeleteValue(winreg_handle, + tmp_ctx, + &key_hnd, + wvalue, + &result); + if (!NT_STATUS_IS_OK(status)) { + /* If the value doesn't exist, return WERR_INVALID_FORM_NAME */ + DEBUG(0, ("winreg_printer_delteform1: Could not delete value %s: %s\n", + wvalue.name, nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + result = WERR_INVALID_FORM_NAME; + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_printer_setform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *form_name, + struct spoolss_AddFormInfo1 *form) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct winreg_String wvalue; + DATA_BLOB blob; + uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); + uint32_t i; + WERROR result; + NTSTATUS status; + TALLOC_CTX *tmp_ctx = NULL; + + for (i = 0; i < num_builtin; i++) { + if (strequal(builtin_forms1[i].form_name, form->form_name)) { + result = WERR_INVALID_PARAM; + goto done; + } + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + TOP_LEVEL_CONTROL_FORMS_KEY, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_setform1: Could not open key %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + goto done; + } + + /* If form_name != form->form_name then we renamed the form */ + if (strequal(form_name, form->form_name)) { + result = winreg_printer_deleteform1(tmp_ctx, server_info, + msg_ctx, form_name); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_printer_setform1: Could not open key %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + goto done; + } + } + + wvalue.name = form->form_name; + + blob = data_blob_talloc(tmp_ctx, NULL, 32); + SIVAL(blob.data, 0, form->size.width); + SIVAL(blob.data, 4, form->size.height); + SIVAL(blob.data, 8, form->area.left); + SIVAL(blob.data, 12, form->area.top); + SIVAL(blob.data, 16, form->area.right); + SIVAL(blob.data, 20, form->area.bottom); + SIVAL(blob.data, 24, 42); + SIVAL(blob.data, 28, form->flags); + + status = dcerpc_winreg_SetValue(winreg_handle, + tmp_ctx, + &key_hnd, + wvalue, + REG_BINARY, + blob.data, + blob.length, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_setform1: Could not set value %s: %s\n", + wvalue.name, nt_errstr(status))); + result = ntstatus_to_werror(status); + } + +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_printer_getform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *form_name, + struct spoolss_FormInfo1 *r) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct winreg_String wvalue; + enum winreg_Type type_in; + uint8_t *data_in; + uint32_t data_in_size = 0; + uint32_t value_len = 0; + uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); + uint32_t i; + WERROR result; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + /* check builtin forms first */ + for (i = 0; i < num_builtin; i++) { + if (strequal(builtin_forms1[i].form_name, form_name)) { + *r = builtin_forms1[i]; + return WERR_OK; + } + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + result = winreg_printer_openkey(tmp_ctx, + server_info, + msg_ctx, + &winreg_handle, + TOP_LEVEL_CONTROL_FORMS_KEY, + "", + true, + access_mask, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(2, ("winreg_printer_getform1: Could not open key %s: %s\n", + TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); + goto done; + } + + wvalue.name = form_name; + + /* + * call QueryValue once with data == NULL to get the + * needed memory size to be allocated, then allocate + * data buffer and call again. + */ + status = dcerpc_winreg_QueryValue(winreg_handle, + tmp_ctx, + &key_hnd, + &wvalue, + &type_in, + NULL, + &data_in_size, + &value_len, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_getform1: Could not query value %s: %s\n", + wvalue.name, nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + data_in = (uint8_t *) TALLOC(tmp_ctx, data_in_size); + if (data_in == NULL) { + result = WERR_NOMEM; + goto done; + } + value_len = 0; + + status = dcerpc_winreg_QueryValue(winreg_handle, + tmp_ctx, + &key_hnd, + &wvalue, + &type_in, + data_in, + &data_in_size, + &value_len, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("winreg_printer_getform1: Could not query value %s: %s\n", + wvalue.name, nt_errstr(status))); + result = ntstatus_to_werror(status); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + r->form_name = talloc_strdup(mem_ctx, form_name); + if (r->form_name == NULL) { + result = WERR_NOMEM; + goto done; + } + + r->size.width = IVAL(data_in, 0); + r->size.height = IVAL(data_in, 4); + r->area.left = IVAL(data_in, 8); + r->area.top = IVAL(data_in, 12); + r->area.right = IVAL(data_in, 16); + r->area.bottom = IVAL(data_in, 20); + /* skip index IVAL(data_in, 24)));*/ + r->flags = (enum spoolss_FormFlags) IVAL(data_in, 28); + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_add_driver(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct spoolss_AddDriverInfoCtr *r, + const char **driver_name, + uint32_t *driver_version) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct spoolss_DriverInfo8 info8; + TALLOC_CTX *tmp_ctx = NULL; + NTSTATUS status; + WERROR result; + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + ZERO_STRUCT(info8); + + if (!driver_info_ctr_to_info8(r, &info8)) { + result = WERR_INVALID_PARAMETER; + goto done; + } + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + result = winreg_printer_opendriver(tmp_ctx, + server_info, + msg_ctx, + info8.driver_name, + info8.architecture, + info8.version, + access_mask, true, + &winreg_handle, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_add_driver: " + "Could not open driver key (%s,%s,%d): %s\n", + info8.driver_name, info8.architecture, + info8.version, win_errstr(result))); + goto done; + } + + /* TODO: "Attributes" ? */ + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "Version", + info8.version, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Driver", + info8.driver_path, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Data File", + info8.data_file, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Configuration File", + info8.config_file, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Help File", + info8.help_file, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_multi_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Dependent Files", + info8.dependent_files, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Monitor", + info8.monitor_name, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Datatype", + info8.default_datatype, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_multi_sz(tmp_ctx, + winreg_handle, + &key_hnd, "Previous Names", + info8.previous_names, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = winreg_printer_write_date(tmp_ctx, winreg_handle, + &key_hnd, "DriverDate", + info8.driver_date); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = winreg_printer_write_ver(tmp_ctx, winreg_handle, + &key_hnd, "DriverVersion", + info8.driver_version); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Manufacturer", + info8.manufacturer_name, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "OEM URL", + info8.manufacturer_url, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "HardwareID", + info8.hardware_id, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Provider", + info8.provider, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Print Processor", + info8.print_processor, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "VendorSetup", + info8.vendor_setup, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_multi_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "Color Profiles", + info8.color_profiles, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "InfPath", + info8.inf_path, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_dword(tmp_ctx, + winreg_handle, + &key_hnd, + "PrinterDriverAttributes", + info8.printer_driver_attributes, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + status = dcerpc_winreg_set_multi_sz(tmp_ctx, + winreg_handle, + &key_hnd, + "CoreDependencies", + info8.core_driver_dependencies, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = winreg_printer_write_date(tmp_ctx, winreg_handle, + &key_hnd, "MinInboxDriverVerDate", + info8.min_inbox_driver_ver_date); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + result = winreg_printer_write_ver(tmp_ctx, winreg_handle, &key_hnd, + "MinInboxDriverVerVersion", + info8.min_inbox_driver_ver_version); + if (!W_ERROR_IS_OK(result)) { + goto done; + } + + *driver_name = info8.driver_name; + *driver_version = info8.version; + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_get_driver(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *architecture, + const char *driver_name, + uint32_t driver_version, + struct spoolss_DriverInfo8 **_info8) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + struct spoolss_DriverInfo8 i8, *info8; + struct spoolss_PrinterEnumValues *enum_values = NULL; + struct spoolss_PrinterEnumValues *v; + uint32_t num_values = 0; + TALLOC_CTX *tmp_ctx; + WERROR result; + uint32_t i; + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + ZERO_STRUCT(i8); + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + if (driver_version == DRIVER_ANY_VERSION) { + /* look for Win2k first and then for NT4 */ + result = winreg_printer_opendriver(tmp_ctx, + server_info, + msg_ctx, + driver_name, + architecture, + 3, + access_mask, false, + &winreg_handle, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + result = winreg_printer_opendriver(tmp_ctx, + server_info, + msg_ctx, + driver_name, + architecture, + 2, + access_mask, false, + &winreg_handle, + &hive_hnd, + &key_hnd); + } + } else { + /* ok normal case */ + result = winreg_printer_opendriver(tmp_ctx, + server_info, + msg_ctx, + driver_name, + architecture, + driver_version, + access_mask, false, + &winreg_handle, + &hive_hnd, + &key_hnd); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(5, ("winreg_get_driver: " + "Could not open driver key (%s,%s,%d): %s\n", + driver_name, architecture, + driver_version, win_errstr(result))); + goto done; + } + + result = winreg_printer_enumvalues(tmp_ctx, + winreg_handle, + &key_hnd, + &num_values, + &enum_values); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_get_driver: " + "Could not enumerate values for (%s,%s,%d): %s\n", + driver_name, architecture, + driver_version, win_errstr(result))); + goto done; + } + + info8 = talloc_zero(tmp_ctx, struct spoolss_DriverInfo8); + if (info8 == NULL) { + result = WERR_NOMEM; + goto done; + } + + info8->driver_name = talloc_strdup(info8, driver_name); + if (info8->driver_name == NULL) { + result = WERR_NOMEM; + goto done; + } + + info8->architecture = talloc_strdup(info8, architecture); + if (info8->architecture == NULL) { + result = WERR_NOMEM; + goto done; + } + + result = WERR_OK; + + for (i = 0; i < num_values; i++) { + const char *tmp_str; + uint32_t tmp = 0; + + v = &enum_values[i]; + + result = winreg_enumval_to_dword(info8, v, + "Version", + &tmp); + if (NT_STATUS_IS_OK(result)) { + info8->version = (enum spoolss_DriverOSVersion) tmp; + } + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Driver", + &info8->driver_path); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Data File", + &info8->data_file); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Configuration File", + &info8->config_file); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Help File", + &info8->help_file); + CHECK_ERROR(result); + + result = winreg_enumval_to_multi_sz(info8, v, + "Dependent Files", + &info8->dependent_files); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Monitor", + &info8->monitor_name); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Datatype", + &info8->default_datatype); + CHECK_ERROR(result); + + result = winreg_enumval_to_multi_sz(info8, v, + "Previous Names", + &info8->previous_names); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "DriverDate", + &tmp_str); + if (W_ERROR_IS_OK(result)) { + result = winreg_printer_date_to_NTTIME(tmp_str, + &info8->driver_date); + } + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "DriverVersion", + &tmp_str); + if (W_ERROR_IS_OK(result)) { + result = winreg_printer_ver_to_dword(tmp_str, + &info8->driver_version); + } + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Manufacturer", + &info8->manufacturer_name); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "OEM URL", + &info8->manufacturer_url); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "HardwareID", + &info8->hardware_id); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Provider", + &info8->provider); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "Print Processor", + &info8->print_processor); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "VendorSetup", + &info8->vendor_setup); + CHECK_ERROR(result); + + result = winreg_enumval_to_multi_sz(info8, v, + "Color Profiles", + &info8->color_profiles); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "InfPath", + &info8->inf_path); + CHECK_ERROR(result); + + result = winreg_enumval_to_dword(info8, v, + "PrinterDriverAttributes", + &info8->printer_driver_attributes); + CHECK_ERROR(result); + + result = winreg_enumval_to_multi_sz(info8, v, + "CoreDependencies", + &info8->core_driver_dependencies); + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "MinInboxDriverVerDate", + &tmp_str); + if (W_ERROR_IS_OK(result)) { + result = winreg_printer_date_to_NTTIME(tmp_str, + &info8->min_inbox_driver_ver_date); + } + CHECK_ERROR(result); + + result = winreg_enumval_to_sz(info8, v, + "MinInboxDriverVerVersion", + &tmp_str); + if (W_ERROR_IS_OK(result)) { + result = winreg_printer_ver_to_dword(tmp_str, + &info8->min_inbox_driver_ver_version); + } + CHECK_ERROR(result); + } + + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_enumval_to_TYPE() failed " + "for %s: %s\n", v->value_name, + win_errstr(result))); + goto done; + } + + *_info8 = talloc_steal(mem_ctx, info8); + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_del_driver(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct spoolss_DriverInfo8 *info8, + uint32_t version) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + TALLOC_CTX *tmp_ctx; + char *key_name; + WERROR result; + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + /* test that the key exists */ + result = winreg_printer_opendriver(tmp_ctx, + server_info, + msg_ctx, + info8->driver_name, + info8->architecture, + version, + access_mask, false, + &winreg_handle, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + /* key doesn't exist */ + if (W_ERROR_EQUAL(result, WERR_BADFILE)) { + result = WERR_OK; + goto done; + } + + DEBUG(5, ("winreg_del_driver: " + "Could not open driver (%s,%s,%u): %s\n", + info8->driver_name, info8->architecture, + version, win_errstr(result))); + goto done; + } + + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); + } + + key_name = talloc_asprintf(tmp_ctx, + "%s\\Environments\\%s\\Drivers\\Version-%u\\%s", + TOP_LEVEL_CONTROL_KEY, + info8->architecture, version, + info8->driver_name); + if (key_name == NULL) { + result = WERR_NOMEM; + goto done; + } + + result = winreg_printer_delete_subkeys(tmp_ctx, + winreg_handle, + &hive_hnd, + access_mask, + key_name); + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_del_driver: " + "Could not open driver (%s,%s,%u): %s\n", + info8->driver_name, info8->architecture, + version, win_errstr(result))); + goto done; + } + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} + +WERROR winreg_get_driver_list(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *architecture, + uint32_t version, + uint32_t *num_drivers, + const char ***drivers_p) +{ + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct dcerpc_binding_handle *winreg_handle = NULL; + struct policy_handle hive_hnd, key_hnd; + const char **drivers; + TALLOC_CTX *tmp_ctx; + WERROR result; + NTSTATUS status; + + *num_drivers = 0; + *drivers_p = NULL; + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return WERR_NOMEM; + } + + /* use NULL for the driver name so we open the key that is + * parent of all drivers for this architecture and version */ + result = winreg_printer_opendriver(tmp_ctx, + server_info, + msg_ctx, + NULL, + architecture, + version, + access_mask, false, + &winreg_handle, + &hive_hnd, + &key_hnd); + if (!W_ERROR_IS_OK(result)) { + DEBUG(5, ("winreg_get_driver_list: " + "Could not open key (%s,%u): %s\n", + architecture, version, win_errstr(result))); + result = WERR_OK; + goto done; + } + + status = dcerpc_winreg_enum_keys(tmp_ctx, + winreg_handle, + &key_hnd, + num_drivers, + &drivers, + &result); + if (!NT_STATUS_IS_OK(status)) { + result = ntstatus_to_werror(status); + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("winreg_get_driver_list: " + "Could not enumerate drivers for (%s,%u): %s\n", + architecture, version, win_errstr(result))); + goto done; + } + + *drivers_p = talloc_steal(mem_ctx, drivers); + + result = WERR_OK; +done: + if (winreg_handle != NULL) { + WERROR ignore; + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); + } + if (is_valid_policy_hnd(&hive_hnd)) { + dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); + } + } + + TALLOC_FREE(tmp_ctx); + return result; +} diff --git a/source3/rpc_server/spoolss/srv_spoolss_util.h b/source3/rpc_server/spoolss/srv_spoolss_util.h new file mode 100644 index 0000000000..d425bd1bba --- /dev/null +++ b/source3/rpc_server/spoolss/srv_spoolss_util.h @@ -0,0 +1,590 @@ +/* + * Unix SMB/CIFS implementation. + * + * SPOOLSS RPC Pipe server / winreg client routines + * + * Copyright (c) 2010 Andreas Schneider + * + * 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 . + */ + +#ifndef _SRV_SPOOLSS_UITL_H +#define _SRV_SPOOLSS_UITL_H + + +enum spoolss_PrinterInfo2Mask { + SPOOLSS_PRINTER_INFO_ATTRIBUTES = (int)(0x00000001), + SPOOLSS_PRINTER_INFO_AVERAGEPPM = (int)(0x00000002), + SPOOLSS_PRINTER_INFO_CJOBS = (int)(0x00000004), + SPOOLSS_PRINTER_INFO_COMMENT = (int)(0x00000008), + SPOOLSS_PRINTER_INFO_DATATYPE = (int)(0x00000010), + SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY = (int)(0x00000020), + SPOOLSS_PRINTER_INFO_DEVMODE = (int)(0x00000040), + SPOOLSS_PRINTER_INFO_DRIVERNAME = (int)(0x00000080), + SPOOLSS_PRINTER_INFO_LOCATION = (int)(0x00000100), + SPOOLSS_PRINTER_INFO_NAME = (int)(0x00000200), + SPOOLSS_PRINTER_INFO_PARAMETERS = (int)(0x00000400), + SPOOLSS_PRINTER_INFO_PORTNAME = (int)(0x00000800), + SPOOLSS_PRINTER_INFO_PRINTERNAME = (int)(0x00001000), + SPOOLSS_PRINTER_INFO_PRINTPROCESSOR = (int)(0x00002000), + SPOOLSS_PRINTER_INFO_PRIORITY = (int)(0x00004000), + SPOOLSS_PRINTER_INFO_SECDESC = (int)(0x00008000), + SPOOLSS_PRINTER_INFO_SEPFILE = (int)(0x00010000), + SPOOLSS_PRINTER_INFO_SERVERNAME = (int)(0x00020000), + SPOOLSS_PRINTER_INFO_SHARENAME = (int)(0x00040000), + SPOOLSS_PRINTER_INFO_STARTTIME = (int)(0x00080000), + SPOOLSS_PRINTER_INFO_STATUS = (int)(0x00100000), + SPOOLSS_PRINTER_INFO_UNTILTIME = (int)(0x00200000) +}; + +#define SPOOLSS_PRINTER_INFO_ALL SPOOLSS_PRINTER_INFO_ATTRIBUTES | \ + SPOOLSS_PRINTER_INFO_AVERAGEPPM | \ + SPOOLSS_PRINTER_INFO_CJOBS | \ + SPOOLSS_PRINTER_INFO_COMMENT | \ + SPOOLSS_PRINTER_INFO_DATATYPE | \ + SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY | \ + SPOOLSS_PRINTER_INFO_DEVMODE | \ + SPOOLSS_PRINTER_INFO_DRIVERNAME | \ + SPOOLSS_PRINTER_INFO_LOCATION | \ + SPOOLSS_PRINTER_INFO_NAME | \ + SPOOLSS_PRINTER_INFO_PARAMETERS | \ + SPOOLSS_PRINTER_INFO_PORTNAME | \ + SPOOLSS_PRINTER_INFO_PRINTERNAME | \ + SPOOLSS_PRINTER_INFO_PRINTPROCESSOR | \ + SPOOLSS_PRINTER_INFO_PRIORITY | \ + SPOOLSS_PRINTER_INFO_SECDESC | \ + SPOOLSS_PRINTER_INFO_SEPFILE | \ + SPOOLSS_PRINTER_INFO_SERVERNAME | \ + SPOOLSS_PRINTER_INFO_SHARENAME | \ + SPOOLSS_PRINTER_INFO_STARTTIME | \ + SPOOLSS_PRINTER_INFO_STATUS | \ + SPOOLSS_PRINTER_INFO_UNTILTIME + +WERROR winreg_create_printer(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename); + +/** + * @internal + * + * @brief Update the information of a printer in the registry. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] sharename The share name. + * + * @param[in] info2_mask A bitmask which defines which values should be set. + * + * @param[in] info2 A SetPrinterInfo2 structure with the data to set. + * + * @param[in] devmode A device mode structure with the data to set. + * + * @param[in] secdesc A security descriptor structure with the data to set. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_update_printer(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename, + uint32_t info2_mask, + struct spoolss_SetPrinterInfo2 *info2, + struct spoolss_DeviceMode *devmode, + struct security_descriptor *secdesc); + + +/** + * @brief Get the inforamtion of a printer stored in the registry. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The name of the printer to get. + * + * @param[out] pinfo2 A pointer to store a PRINTER_INFO_2 structure. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_get_printer(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + struct spoolss_PrinterInfo2 **pinfo2); + +/** + * @brief Get the security descriptor for a printer. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] sharename The share name. + * + * @param[out] psecdesc A pointer to store the security descriptor. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_get_printer_secdesc(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename, + struct spoolss_security_descriptor **psecdesc); + +/** + * @brief Set the security descriptor for a printer. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] sharename The share name. + * + * @param[in] secdesc The security descriptor to save. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_set_printer_secdesc(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *sharename, + const struct spoolss_security_descriptor *secdesc); + +/** + * @internal + * + * @brief Set printer data over the winreg pipe. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @param[in] key The key of the printer data to store the value. + * + * @param[in] value The value name to save. + * + * @param[in] type The type of the value to use. + * + * @param[in] data The data which sould be saved under the given value. + * + * @param[in] data_size The size of the data. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_set_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + const char *value, + enum winreg_Type type, + uint8_t *data, + uint32_t data_size); + +/** + * @internal + * + * @brief Get printer data over a winreg pipe. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @param[in] key The key of the printer data to get the value. + * + * @param[in] value The name of the value to query. + * + * @param[in] type The type of the value to query. + * + * @param[out] data A pointer to store the data. + * + * @param[out] data_size A pointer to store the size of the data. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_get_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + const char *value, + enum winreg_Type *type, + uint8_t **data, + uint32_t *data_size); + +/** + * @internal + * + * @brief Enumerate on the values of a given key and provide the data. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @param[in] key The key of the printer data to get the value. + * + * @param[out] pnum_values A pointer to store the number of values we found. + * + * @param[out] penum_values A pointer to store the values and its data. + * + * @return WERR_OK on success, the corresponding DOS error + * code if something gone wrong. + */ +WERROR winreg_enum_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + uint32_t *pnum_values, + struct spoolss_PrinterEnumValues **penum_values); + +/** + * @internal + * + * @brief Delete printer data over a winreg pipe. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @param[in] key The key of the printer data to delete. + * + * @param[in] value The name of the value to delete. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_delete_printer_dataex(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + const char *value); + +/** + * @internal + * + * @brief Enumerate on the subkeys of a given key and provide the data. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @param[in] key The key of the printer data to get the value. + * + * @param[out] pnum_subkeys A pointer to store the number of subkeys found. + * + * @param[in] psubkeys A pointer to an array to store the names of the subkeys + * found. + * + * @return WERR_OK on success, the corresponding DOS error + * code if something gone wrong. + */ +WERROR winreg_enum_printer_key(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key, + uint32_t *pnum_subkeys, + const char ***psubkeys); + +/** + * @internal + * + * @brief Delete a key with subkeys of a given printer. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @param[in] key The key of the printer to delete. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_delete_printer_key(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + const char *key); + +/** + * @brief Update the ChangeID of a printer. + * + * The ChangeID **must** be increasing over the lifetime of client's spoolss + * service in order for the client's cache to show updates. + * + * If a form is updated of a printer, the we need to update the ChangeID of the + * pritner. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_printer_update_changeid(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer); + +/** + * @brief Get the ChangeID of the given printer. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] printer The printer name. + * + * @param[in] changeid A pointer to store the changeid. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_printer_get_changeid(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *printer, + uint32_t *pchangeid); + +/** + * @internal + * + * @brief This function adds a form to the list of available forms that can be + * selected for the specified printer. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] form The form to add. + * + * @return WERR_OK on success. + * WERR_ALREADY_EXISTS if the form already exists or is a + * builtin form. + * A corresponding DOS error is something went wrong. + */ +WERROR winreg_printer_addform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct spoolss_AddFormInfo1 *form); + +/* + * @brief This function enumerates the forms supported by the specified printer. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[out] pnum_info A pointer to store the FormInfo count. + * + * @param[out] pinfo A pointer to store an array with FormInfo. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_printer_enumforms1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + uint32_t *pnum_info, + union spoolss_FormInfo **pinfo); + +/** + * @brief This function removes a form name from the list of supported forms. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] form_name The name of the form to delete. + * + * @return WERR_OK on success. + * WERR_INVALID_PARAM if the form is a builtin form. + * WERR_INVALID_FORM_NAME if the form or key doesn't exist. + * A corresponding DOS error is something went wrong. + */ +WERROR winreg_printer_deleteform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *form_name); + +/** + * @brief This function sets the form information for the specified printer. + * + * If one provides both the name in the API call and inside the FormInfo + * structure, then the form gets renamed. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] form_name The name of the form to set or rename. + * + * @param[in] form The FormInfo structure to save. + * + * @return WERR_OK on success. + * WERR_INVALID_PARAM if the form is a builtin form. + * A corresponding DOS error is something went wrong. + */ +WERROR winreg_printer_setform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *form_name, + struct spoolss_AddFormInfo1 *form); + +/** + * @brief This function retrieves information about a specified form. + * + * @param[in] mem_ctx The talloc memory context to use. + * + * @param[in] server_info The server supplied session info. + * + * @param[in] form_name The name of the form to query. + * + * @param[out] form A pointer to a form structure to fill out. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_printer_getform1(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *form_name, + struct spoolss_FormInfo1 *form); + +/** + * @brief This function adds a new spool driver + * + * @param[in] mem_ctx A talloc memory context. + * + * @param[in] server_info Auth info to open the pipe. + * + * @param[in] r The structure containing the new driver data. + * + * @param[out] driver_name Returns the driver name. + * + * @param[out] driver_version Returns the driver version. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ +WERROR winreg_add_driver(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct spoolss_AddDriverInfoCtr *r, + const char **driver_name, + uint32_t *driver_version); + +/** + * @brief This function gets printer driver information + * + * @param[in] mem_ctx A talloc memory context. + * + * @param[in] server_info Auth info to open the pipe. + * + * @param[in] architecture The architecture type. + * + * @param[in] driver_name The driver name. + * + * @param[in] driver_version The driver version. + * + * @param[out] _info8 The structure that holds the full driver information. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ + +WERROR winreg_get_driver(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *architecture, + const char *driver_name, + uint32_t driver_version, + struct spoolss_DriverInfo8 **_info8); + +/** + * @brief This function deletes a printer driver information + * + * @param[in] mem_ctx A talloc memory context. + * + * @param[in] server_info Auth info to open the pipe. + * + * @param[out] info8 The structure that holds the full driver information. + * + * @param[in] version The driver type version. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ + +WERROR winreg_del_driver(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + struct spoolss_DriverInfo8 *info8, + uint32_t version); + +/** + * @brief This function gets printer drivers list for the specified + * architecture and type version + * + * @param[in] mem_ctx A talloc memory context. + * + * @param[in] server_info Auth info to open the pipe. + * + * @param[in] architecture The architecture type. + * + * @param[in] version The driver version. + * + * @param[out] num_drivers The number of drivers. + * + * @param[out] version The drivers names. + * + * @return On success WERR_OK, a corresponding DOS error is + * something went wrong. + */ + +WERROR winreg_get_driver_list(TALLOC_CTX *mem_ctx, + const struct auth_serversupplied_info *server_info, + struct messaging_context *msg_ctx, + const char *architecture, + uint32_t version, + uint32_t *num_drivers, + const char ***drivers); + +#endif /* _SRV_SPOOLSS_UITL_H */ diff --git a/source3/rpc_server/srv_dfs_nt.c b/source3/rpc_server/srv_dfs_nt.c deleted file mode 100644 index 940f79d195..0000000000 --- a/source3/rpc_server/srv_dfs_nt.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines for Dfs - * Copyright (C) Shirish Kalele 2000. - * Copyright (C) Jeremy Allison 2001-2007. - * Copyright (C) Jelmer Vernooij 2005-2006. - * - * 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 . - */ - -/* This is the implementation of the dfs pipe. */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_dfs.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_MSDFS - -/* This function does not return a WERROR or NTSTATUS code but rather 1 if - dfs exists, or 0 otherwise. */ - -void _dfs_GetManagerVersion(struct pipes_struct *p, struct dfs_GetManagerVersion *r) -{ - if (lp_host_msdfs()) { - *r->out.version = DFS_MANAGER_VERSION_NT4; - } else { - *r->out.version = (enum dfs_ManagerVersion)0; - } -} - -WERROR _dfs_Add(struct pipes_struct *p, struct dfs_Add *r) -{ - struct junction_map *jn = NULL; - struct referral *old_referral_list = NULL; - bool self_ref = False; - int consumedcnt = 0; - char *altpath = NULL; - NTSTATUS status; - TALLOC_CTX *ctx = talloc_tos(); - - if (p->server_info->utok.uid != sec_initial_uid()) { - DEBUG(10,("_dfs_add: uid != 0. Access denied.\n")); - return WERR_ACCESS_DENIED; - } - - jn = TALLOC_ZERO_P(ctx, struct junction_map); - if (!jn) { - return WERR_NOMEM; - } - - DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n", - r->in.path, r->in.server, r->in.share)); - - altpath = talloc_asprintf(ctx, "%s\\%s", - r->in.server, - r->in.share); - if (!altpath) { - return WERR_NOMEM; - } - - /* The following call can change the cwd. */ - status = get_referred_path(ctx, r->in.path, jn, - &consumedcnt, &self_ref); - if(!NT_STATUS_IS_OK(status)) { - return ntstatus_to_werror(status); - } - - jn->referral_count += 1; - old_referral_list = jn->referral_list; - - if (jn->referral_count < 1) { - return WERR_NOMEM; - } - - jn->referral_list = TALLOC_ARRAY(ctx, struct referral, jn->referral_count); - if(jn->referral_list == NULL) { - DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n")); - return WERR_DFS_INTERNAL_ERROR; - } - - if(old_referral_list && jn->referral_list) { - memcpy(jn->referral_list, old_referral_list, - sizeof(struct referral)*jn->referral_count-1); - } - - jn->referral_list[jn->referral_count-1].proximity = 0; - jn->referral_list[jn->referral_count-1].ttl = REFERRAL_TTL; - jn->referral_list[jn->referral_count-1].alternate_path = altpath; - - if(!create_msdfs_link(jn)) { - return WERR_DFS_CANT_CREATE_JUNCT; - } - - return WERR_OK; -} - -WERROR _dfs_Remove(struct pipes_struct *p, struct dfs_Remove *r) -{ - struct junction_map *jn = NULL; - bool self_ref = False; - int consumedcnt = 0; - bool found = False; - TALLOC_CTX *ctx = talloc_tos(); - char *altpath = NULL; - - if (p->server_info->utok.uid != sec_initial_uid()) { - DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n")); - return WERR_ACCESS_DENIED; - } - - jn = TALLOC_ZERO_P(ctx, struct junction_map); - if (!jn) { - return WERR_NOMEM; - } - - if (r->in.servername && r->in.sharename) { - altpath = talloc_asprintf(ctx, "%s\\%s", - r->in.servername, - r->in.sharename); - if (!altpath) { - return WERR_NOMEM; - } - strlower_m(altpath); - DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n", - r->in.dfs_entry_path, r->in.servername, r->in.sharename)); - } - - if(!NT_STATUS_IS_OK(get_referred_path(ctx, r->in.dfs_entry_path, jn, - &consumedcnt, &self_ref))) { - return WERR_DFS_NO_SUCH_VOL; - } - - /* if no server-share pair given, remove the msdfs link completely */ - if(!r->in.servername && !r->in.sharename) { - if(!remove_msdfs_link(jn)) { - return WERR_DFS_NO_SUCH_VOL; - } - } else { - int i=0; - /* compare each referral in the list with the one to remove */ - DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath, jn->referral_count)); - for(i=0;ireferral_count;i++) { - char *refpath = talloc_strdup(ctx, - jn->referral_list[i].alternate_path); - if (!refpath) { - return WERR_NOMEM; - } - trim_char(refpath, '\\', '\\'); - DEBUG(10,("_dfs_remove: refpath: .%s.\n", refpath)); - if(strequal(refpath, altpath)) { - *(jn->referral_list[i].alternate_path)='\0'; - DEBUG(10,("_dfs_remove: Removal request matches referral %s\n", - refpath)); - found = True; - } - } - - if(!found) { - return WERR_DFS_NO_SUCH_SHARE; - } - - /* Only one referral, remove it */ - if(jn->referral_count == 1) { - if(!remove_msdfs_link(jn)) { - return WERR_DFS_NO_SUCH_VOL; - } - } else { - if(!create_msdfs_link(jn)) { - return WERR_DFS_CANT_CREATE_JUNCT; - } - } - } - - return WERR_OK; -} - -static bool init_reply_dfs_info_1(TALLOC_CTX *mem_ctx, struct junction_map* j,struct dfs_Info1* dfs1) -{ - dfs1->path = talloc_asprintf(mem_ctx, - "\\\\%s\\%s\\%s", global_myname(), - j->service_name, j->volume_name); - if (dfs1->path == NULL) - return False; - - DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",dfs1->path)); - return True; -} - -static bool init_reply_dfs_info_2(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info2* dfs2) -{ - dfs2->path = talloc_asprintf(mem_ctx, - "\\\\%s\\%s\\%s", global_myname(), j->service_name, j->volume_name); - if (dfs2->path == NULL) - return False; - dfs2->comment = talloc_strdup(mem_ctx, j->comment); - dfs2->state = 1; /* set up state of dfs junction as OK */ - dfs2->num_stores = j->referral_count; - return True; -} - -static bool init_reply_dfs_info_3(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info3* dfs3) -{ - int ii; - if (j->volume_name[0] == '\0') - dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s", - global_myname(), j->service_name); - else - dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s\\%s", global_myname(), - j->service_name, j->volume_name); - - if (dfs3->path == NULL) - return False; - - dfs3->comment = talloc_strdup(mem_ctx, j->comment); - dfs3->state = 1; - dfs3->num_stores = j->referral_count; - - /* also enumerate the stores */ - if (j->referral_count) { - dfs3->stores = TALLOC_ARRAY(mem_ctx, struct dfs_StorageInfo, j->referral_count); - if (!dfs3->stores) - return False; - memset(dfs3->stores, '\0', j->referral_count * sizeof(struct dfs_StorageInfo)); - } else { - dfs3->stores = NULL; - } - - for(ii=0;iireferral_count;ii++) { - char* p; - char *path = NULL; - struct dfs_StorageInfo* stor = &(dfs3->stores[ii]); - struct referral* ref = &(j->referral_list[ii]); - - path = talloc_strdup(mem_ctx, ref->alternate_path); - if (!path) { - return False; - } - trim_char(path,'\\','\0'); - p = strrchr_m(path,'\\'); - if(p==NULL) { - DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path)); - continue; - } - *p = '\0'; - DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1)); - stor->state = 2; /* set all stores as ONLINE */ - stor->server = talloc_strdup(mem_ctx, path); - stor->share = talloc_strdup(mem_ctx, p+1); - } - return True; -} - -static bool init_reply_dfs_info_100(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info100* dfs100) -{ - dfs100->comment = talloc_strdup(mem_ctx, j->comment); - return True; -} - -WERROR _dfs_Enum(struct pipes_struct *p, struct dfs_Enum *r) -{ - struct junction_map *jn = NULL; - size_t num_jn = 0; - size_t i; - TALLOC_CTX *ctx = talloc_tos(); - - jn = enum_msdfs_links(ctx, &num_jn); - if (!jn || num_jn == 0) { - num_jn = 0; - jn = NULL; - } - - DEBUG(5,("_dfs_Enum: %u junctions found in Dfs, doing level %d\n", - (unsigned int)num_jn, r->in.level)); - - *r->out.total = num_jn; - - /* Create the return array */ - switch (r->in.level) { - case 1: - if (num_jn) { - if ((r->out.info->e.info1->s = TALLOC_ARRAY(ctx, struct dfs_Info1, num_jn)) == NULL) { - return WERR_NOMEM; - } - } else { - r->out.info->e.info1->s = NULL; - } - r->out.info->e.info1->count = num_jn; - break; - case 2: - if (num_jn) { - if ((r->out.info->e.info2->s = TALLOC_ARRAY(ctx, struct dfs_Info2, num_jn)) == NULL) { - return WERR_NOMEM; - } - } else { - r->out.info->e.info2->s = NULL; - } - r->out.info->e.info2->count = num_jn; - break; - case 3: - if (num_jn) { - if ((r->out.info->e.info3->s = TALLOC_ARRAY(ctx, struct dfs_Info3, num_jn)) == NULL) { - return WERR_NOMEM; - } - } else { - r->out.info->e.info3->s = NULL; - } - r->out.info->e.info3->count = num_jn; - break; - default: - return WERR_INVALID_PARAM; - } - - for (i = 0; i < num_jn; i++) { - switch (r->in.level) { - case 1: - init_reply_dfs_info_1(ctx, &jn[i], &r->out.info->e.info1->s[i]); - break; - case 2: - init_reply_dfs_info_2(ctx, &jn[i], &r->out.info->e.info2->s[i]); - break; - case 3: - init_reply_dfs_info_3(ctx, &jn[i], &r->out.info->e.info3->s[i]); - break; - default: - return WERR_INVALID_PARAM; - } - } - - return WERR_OK; -} - -WERROR _dfs_GetInfo(struct pipes_struct *p, struct dfs_GetInfo *r) -{ - int consumedcnt = strlen(r->in.dfs_entry_path); - struct junction_map *jn = NULL; - bool self_ref = False; - TALLOC_CTX *ctx = talloc_tos(); - bool ret; - - jn = TALLOC_ZERO_P(ctx, struct junction_map); - if (!jn) { - return WERR_NOMEM; - } - - if(!create_junction(ctx, r->in.dfs_entry_path, jn)) { - return WERR_DFS_NO_SUCH_SERVER; - } - - /* The following call can change the cwd. */ - if(!NT_STATUS_IS_OK(get_referred_path(ctx, r->in.dfs_entry_path, - jn, &consumedcnt, &self_ref)) || - consumedcnt < strlen(r->in.dfs_entry_path)) { - return WERR_DFS_NO_SUCH_VOL; - } - - switch (r->in.level) { - case 1: - r->out.info->info1 = TALLOC_ZERO_P(ctx,struct dfs_Info1); - if (!r->out.info->info1) { - return WERR_NOMEM; - } - ret = init_reply_dfs_info_1(ctx, jn, r->out.info->info1); - break; - case 2: - r->out.info->info2 = TALLOC_ZERO_P(ctx,struct dfs_Info2); - if (!r->out.info->info2) { - return WERR_NOMEM; - } - ret = init_reply_dfs_info_2(ctx, jn, r->out.info->info2); - break; - case 3: - r->out.info->info3 = TALLOC_ZERO_P(ctx,struct dfs_Info3); - if (!r->out.info->info3) { - return WERR_NOMEM; - } - ret = init_reply_dfs_info_3(ctx, jn, r->out.info->info3); - break; - case 100: - r->out.info->info100 = TALLOC_ZERO_P(ctx,struct dfs_Info100); - if (!r->out.info->info100) { - return WERR_NOMEM; - } - ret = init_reply_dfs_info_100(ctx, jn, r->out.info->info100); - break; - default: - r->out.info->info1 = NULL; - return WERR_INVALID_PARAM; - } - - if (!ret) - return WERR_INVALID_PARAM; - - return WERR_OK; -} - -WERROR _dfs_SetInfo(struct pipes_struct *p, struct dfs_SetInfo *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_Rename(struct pipes_struct *p, struct dfs_Rename *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_Move(struct pipes_struct *p, struct dfs_Move *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_ManagerGetConfigInfo(struct pipes_struct *p, struct dfs_ManagerGetConfigInfo *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_ManagerSendSiteInfo(struct pipes_struct *p, struct dfs_ManagerSendSiteInfo *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_AddFtRoot(struct pipes_struct *p, struct dfs_AddFtRoot *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_RemoveFtRoot(struct pipes_struct *p, struct dfs_RemoveFtRoot *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_AddStdRoot(struct pipes_struct *p, struct dfs_AddStdRoot *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_RemoveStdRoot(struct pipes_struct *p, struct dfs_RemoveStdRoot *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_ManagerInitialize(struct pipes_struct *p, struct dfs_ManagerInitialize *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_AddStdRootForced(struct pipes_struct *p, struct dfs_AddStdRootForced *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_GetDcAddress(struct pipes_struct *p, struct dfs_GetDcAddress *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_SetDcAddress(struct pipes_struct *p, struct dfs_SetDcAddress *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_FlushFtTable(struct pipes_struct *p, struct dfs_FlushFtTable *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_Add2(struct pipes_struct *p, struct dfs_Add2 *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_Remove2(struct pipes_struct *p, struct dfs_Remove2 *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_EnumEx(struct pipes_struct *p, struct dfs_EnumEx *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _dfs_SetInfo2(struct pipes_struct *p, struct dfs_SetInfo2 *r) -{ - /* FIXME: Implement your code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} diff --git a/source3/rpc_server/srv_dssetup_nt.c b/source3/rpc_server/srv_dssetup_nt.c deleted file mode 100644 index cbc08c0880..0000000000 --- a/source3/rpc_server/srv_dssetup_nt.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1997. - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997. - * Copyright (C) Paul Ashton 1997. - * Copyright (C) Jeremy Allison 2001. - * Copyright (C) Gerald Carter 2002. - * Copyright (C) Guenther Deschner 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 . - */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_dssetup.h" -#include "secrets.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -/******************************************************************** - Fill in a dssetup_DsRolePrimaryDomInfoBasic structure - ********************************************************************/ - -static WERROR fill_dsrole_dominfo_basic(TALLOC_CTX *ctx, - struct dssetup_DsRolePrimaryDomInfoBasic **info) -{ - struct dssetup_DsRolePrimaryDomInfoBasic *basic = NULL; - char *dnsdomain = NULL; - - DEBUG(10,("fill_dsrole_dominfo_basic: enter\n")); - - basic = TALLOC_ZERO_P(ctx, struct dssetup_DsRolePrimaryDomInfoBasic); - if (!basic) { - DEBUG(0,("fill_dsrole_dominfo_basic: out of memory\n")); - return WERR_NOMEM; - } - - switch (lp_server_role()) { - case ROLE_STANDALONE: - basic->role = DS_ROLE_STANDALONE_SERVER; - basic->domain = get_global_sam_name(); - break; - case ROLE_DOMAIN_MEMBER: - basic->role = DS_ROLE_MEMBER_SERVER; - basic->domain = lp_workgroup(); - break; - case ROLE_DOMAIN_BDC: - basic->role = DS_ROLE_BACKUP_DC; - basic->domain = get_global_sam_name(); - break; - case ROLE_DOMAIN_PDC: - basic->role = DS_ROLE_PRIMARY_DC; - basic->domain = get_global_sam_name(); - break; - } - - if (secrets_fetch_domain_guid(lp_workgroup(), &basic->domain_guid)) { - basic->flags |= DS_ROLE_PRIMARY_DOMAIN_GUID_PRESENT; - } - - /* fill in some additional fields if we are a member of an AD domain */ - - if (lp_security() == SEC_ADS) { - dnsdomain = talloc_strdup(ctx, lp_realm()); - if (!dnsdomain) { - return WERR_NOMEM; - } - strlower_m(dnsdomain); - basic->dns_domain = dnsdomain; - - /* FIXME!! We really should fill in the correct forest - name. Should get this information from winbindd. */ - basic->forest = dnsdomain; - } else { - /* security = domain should not fill in the dns or - forest name */ - basic->dns_domain = NULL; - basic->forest = NULL; - } - - *info = basic; - - return WERR_OK; -} - -/******************************************************************** - Implement the _dssetup_DsRoleGetPrimaryDomainInformation() call - ********************************************************************/ - -WERROR _dssetup_DsRoleGetPrimaryDomainInformation(struct pipes_struct *p, - struct dssetup_DsRoleGetPrimaryDomainInformation *r) -{ - WERROR werr = WERR_OK; - - switch (r->in.level) { - - case DS_ROLE_BASIC_INFORMATION: { - struct dssetup_DsRolePrimaryDomInfoBasic *basic = NULL; - werr = fill_dsrole_dominfo_basic(p->mem_ctx, &basic); - if (W_ERROR_IS_OK(werr)) { - r->out.info->basic = *basic; - } - break; - } - default: - DEBUG(0,("_dssetup_DsRoleGetPrimaryDomainInformation: " - "Unknown info level [%d]!\n", r->in.level)); - werr = WERR_UNKNOWN_LEVEL; - } - - return werr; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleDnsNameToFlatName(struct pipes_struct *p, - struct dssetup_DsRoleDnsNameToFlatName *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleDcAsDc(struct pipes_struct *p, - struct dssetup_DsRoleDcAsDc *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleDcAsReplica(struct pipes_struct *p, - struct dssetup_DsRoleDcAsReplica *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleDemoteDc(struct pipes_struct *p, - struct dssetup_DsRoleDemoteDc *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleGetDcOperationProgress(struct pipes_struct *p, - struct dssetup_DsRoleGetDcOperationProgress *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleGetDcOperationResults(struct pipes_struct *p, - struct dssetup_DsRoleGetDcOperationResults *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleCancel(struct pipes_struct *p, - struct dssetup_DsRoleCancel *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleServerSaveStateForUpgrade(struct pipes_struct *p, - struct dssetup_DsRoleServerSaveStateForUpgrade *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleUpgradeDownlevelServer(struct pipes_struct *p, - struct dssetup_DsRoleUpgradeDownlevelServer *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _dssetup_DsRoleAbortDownlevelServerUpgrade(struct pipes_struct *p, - struct dssetup_DsRoleAbortDownlevelServerUpgrade *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - diff --git a/source3/rpc_server/srv_echo_nt.c b/source3/rpc_server/srv_echo_nt.c deleted file mode 100644 index ef6204f4c4..0000000000 --- a/source3/rpc_server/srv_echo_nt.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines for rpcecho - * Copyright (C) Tim Potter 2003 - * Copyright (C) Jelmer Vernooij 2006 - * Copyright (C) Gerald (Jerry) Carter 2007 - * - * 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 . - */ - -/* This is the interface to the rpcecho pipe. */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_echo.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -/* Add one to the input and return it */ - -void _echo_AddOne(struct pipes_struct *p, struct echo_AddOne *r ) -{ - DEBUG(10, ("_echo_AddOne\n")); - - *r->out.out_data = r->in.in_data + 1; -} - -/* Echo back an array of data */ - -void _echo_EchoData(struct pipes_struct *p, struct echo_EchoData *r) -{ - DEBUG(10, ("_echo_EchoData\n")); - - if ( r->in.len == 0 ) { - r->out.out_data = NULL; - return; - } - - r->out.out_data = TALLOC_ARRAY(p->mem_ctx, uint8, r->in.len); - memcpy( r->out.out_data, r->in.in_data, r->in.len ); - return; -} - -/* Sink an array of data */ - -void _echo_SinkData(struct pipes_struct *p, struct echo_SinkData *r) -{ - DEBUG(10, ("_echo_SinkData\n")); - - /* My that was some yummy data! */ - return; -} - -/* Source an array of data */ - -void _echo_SourceData(struct pipes_struct *p, struct echo_SourceData *r) -{ - uint32 i; - - DEBUG(10, ("_echo_SourceData\n")); - - if ( r->in.len == 0 ) { - r->out.data = NULL; - return; - } - - r->out.data = TALLOC_ARRAY(p->mem_ctx, uint8, r->in.len ); - - for (i = 0; i < r->in.len; i++ ) { - r->out.data[i] = i & 0xff; - } - - return; -} - -void _echo_TestCall(struct pipes_struct *p, struct echo_TestCall *r) -{ - p->rng_fault_state = True; - return; -} - -NTSTATUS _echo_TestCall2(struct pipes_struct *p, struct echo_TestCall2 *r) -{ - p->rng_fault_state = True; - return NT_STATUS_OK; -} - -uint32 _echo_TestSleep(struct pipes_struct *p, struct echo_TestSleep *r) -{ - smb_msleep(r->in.seconds * 1000); - return 0; -} - -void _echo_TestEnum(struct pipes_struct *p, struct echo_TestEnum *r) -{ - p->rng_fault_state = True; - return; -} - -void _echo_TestSurrounding(struct pipes_struct *p, struct echo_TestSurrounding *r) -{ - p->rng_fault_state = True; - return; -} - -uint16 _echo_TestDoublePointer(struct pipes_struct *p, struct echo_TestDoublePointer *r) -{ - p->rng_fault_state = True; - return 0; -} diff --git a/source3/rpc_server/srv_epmapper.c b/source3/rpc_server/srv_epmapper.c deleted file mode 100644 index 5bfb176b84..0000000000 --- a/source3/rpc_server/srv_epmapper.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Endpoint server for the epmapper pipe - - Copyright (C) 2010-2011 Andreas Schneider - - 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 . -*/ - -#include "includes.h" -#include "../libcli/security/security.h" -#include "librpc/gen_ndr/ndr_epmapper.h" -#include "librpc/gen_ndr/srv_epmapper.h" - -typedef uint32_t error_status_t; - -/* An endpoint combined with an interface description */ -struct dcesrv_ep_iface { - const char *name; - struct ndr_syntax_id syntax_id; - struct epm_tower ep; -}; - -/* A rpc service interface like samr, lsarpc or netlogon */ -struct dcesrv_iface { - const char *name; - struct ndr_syntax_id syntax_id; -}; - -struct dcesrv_iface_list { - struct dcesrv_iface_list *next, *prev; - struct dcesrv_iface *iface; -}; - -/* - * An endpoint can serve multiple rpc services interfaces. - * For example \\pipe\netlogon can be used by lsarpc and netlogon. - */ -struct dcesrv_endpoint { - struct dcesrv_endpoint *next, *prev; - - /* The type and the location of the endpoint */ - struct dcerpc_binding *ep_description; - - /* A list of rpc services able to connect to the endpoint */ - struct dcesrv_iface_list *iface_list; -}; - -struct rpc_eps { - struct dcesrv_ep_iface *e; - uint32_t count; -}; - -static struct dcesrv_endpoint *endpoint_table; - -/* - * Check if the UUID and if_version match to an interface. - */ -static bool interface_match(const struct dcesrv_iface *if1, - const struct dcesrv_iface *if2) -{ - return GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid); -} - -/* - * Find the interface operations on an endpoint. - */ -static const struct dcesrv_iface *find_interface(const struct dcesrv_endpoint *endpoint, - const struct dcesrv_iface *iface) -{ - struct dcesrv_iface_list *iflist; - - for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) { - if (interface_match(iflist->iface, iface)) { - return iflist->iface; - } - } - - return NULL; -} - -/* - * See if a uuid and if_version match to an interface - */ -static bool interface_match_by_uuid(const struct dcesrv_iface *iface, - const struct GUID *uuid) -{ - return GUID_equal(&iface->syntax_id.uuid, uuid); -} - -static struct dcesrv_iface_list *find_interface_list(const struct dcesrv_endpoint *endpoint, - const struct dcesrv_iface *iface) -{ - struct dcesrv_iface_list *iflist; - - for (iflist = endpoint->iface_list; iflist; iflist = iflist->next) { - if (interface_match(iflist->iface, iface)) { - return iflist; - } - } - - return NULL; -} - -/* - * Check if two endpoints match. - */ -static bool endpoints_match(const struct dcerpc_binding *ep1, - const struct dcerpc_binding *ep2) -{ - if (ep1->transport != ep2->transport) { - return false; - } - - if (!ep1->endpoint || !ep2->endpoint) { - return ep1->endpoint == ep2->endpoint; - } - - if (!strequal(ep1->endpoint, ep2->endpoint)) { - return false; - } - - return true; -} - -static struct dcesrv_endpoint *find_endpoint(struct dcesrv_endpoint *endpoint_list, - struct dcerpc_binding *ep_description) { - struct dcesrv_endpoint *ep; - - for (ep = endpoint_list; ep != NULL; ep = ep->next) { - if (endpoints_match(ep->ep_description, ep_description)) { - return ep; - } - } - - return NULL; -} - -/* - * Build a list of all interfaces handled by all endpoint servers. - */ -static uint32_t build_ep_list(TALLOC_CTX *mem_ctx, - struct dcesrv_endpoint *endpoint_list, - const struct GUID *uuid, - struct dcesrv_ep_iface **peps) -{ - struct dcesrv_ep_iface *eps = NULL; - struct dcesrv_endpoint *d; - uint32_t total = 0; - NTSTATUS status; - - *peps = NULL; - - for (d = endpoint_list; d != NULL; d = d->next) { - struct dcesrv_iface_list *iface; - struct dcerpc_binding *description; - - for (iface = d->iface_list; iface != NULL; iface = iface->next) { - if (uuid && !interface_match_by_uuid(iface->iface, uuid)) { - continue; - } - - eps = talloc_realloc(mem_ctx, - eps, - struct dcesrv_ep_iface, - total + 1); - if (eps == NULL) { - return 0; - } - eps[total].name = talloc_strdup(eps, - iface->iface->name); - eps[total].syntax_id = iface->iface->syntax_id; - - description = d->ep_description; - description->object = iface->iface->syntax_id; - - status = dcerpc_binding_build_tower(eps, - description, - &eps[total].ep); - if (NT_STATUS_IS_ERR(status)) { - DEBUG(1, ("Unable to build tower for %s\n", - iface->iface->name)); - continue; - } - total++; - } - } - - *peps = eps; - - return total; -} - -static bool is_priviledged_pipe(struct auth_serversupplied_info *info) { - /* If the user is not root, or has the system token, fail */ - if ((info->utok.uid != sec_initial_uid()) && - !security_token_is_system(info->security_token)) { - return false; - } - - return true; -} - -/* - * epm_Insert - * - * Add the specified entries to an endpoint map. - */ -error_status_t _epm_Insert(struct pipes_struct *p, - struct epm_Insert *r) -{ - TALLOC_CTX *tmp_ctx; - error_status_t rc; - NTSTATUS status; - uint32_t i; - - /* If this is not a priviledged users, return */ - if (!is_priviledged_pipe(p->server_info)) { - return EPMAPPER_STATUS_CANT_PERFORM_OP; - } - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return EPMAPPER_STATUS_NO_MEMORY; - } - - DEBUG(3, ("_epm_Insert: Trying to add %u new entries.\n", - r->in.num_ents)); - - for (i = 0; i < r->in.num_ents; i++) { - struct dcerpc_binding *b = NULL; - struct dcesrv_endpoint *ep; - struct dcesrv_iface_list *iflist; - struct dcesrv_iface *iface; - bool add_ep = false; - - status = dcerpc_binding_from_tower(tmp_ctx, - &r->in.entries[i].tower->tower, - &b); - if (!NT_STATUS_IS_OK(status)) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - DEBUG(3, ("_epm_Insert: Adding transport %s for %s\n", - derpc_transport_string_by_transport(b->transport), - r->in.entries[i].annotation)); - - /* Check if the entry already exits */ - ep = find_endpoint(endpoint_table, b); - if (ep == NULL) { - /* No entry found, create it */ - ep = talloc_zero(NULL, struct dcesrv_endpoint); - if (ep == NULL) { - rc = EPMAPPER_STATUS_CANT_PERFORM_OP; - goto done; - } - add_ep = true; - - ep->ep_description = talloc_steal(ep, b); - } - - /* TODO Replace the entry if the replace flag is set */ - - /* Create an interface */ - iface = talloc(tmp_ctx, struct dcesrv_iface); - if (iface == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - iface->name = talloc_strdup(iface, r->in.entries[i].annotation); - if (iface->name == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - iface->syntax_id = b->object; - - /* - * Check if the rpc service is alrady registered on the - * endpoint. - */ - if (find_interface(ep, iface) != NULL) { - DEBUG(0, ("dcesrv_interface_register: interface '%s' " - "already registered on endpoint\n", - iface->name)); - /* FIXME wrong error code? */ - rc = EPMAPPER_STATUS_OK; - goto done; - } - - /* Create an entry for the interface */ - iflist = talloc(ep, struct dcesrv_iface_list); - if (iflist == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - iflist->iface = talloc_move(iflist, &iface); - - /* Finally add the interface on the endpoint */ - DLIST_ADD(ep->iface_list, iflist); - - /* If it's a new endpoint add it to the endpoint_table */ - if (add_ep) { - DLIST_ADD(endpoint_table, ep); - } - } - - rc = EPMAPPER_STATUS_OK; -done: - talloc_free(tmp_ctx); - - return rc; -} - - -/* - * epm_Delete - * - * Delete the specified entries from an endpoint map. - */ -error_status_t _epm_Delete(struct pipes_struct *p, - struct epm_Delete *r) -{ - TALLOC_CTX *tmp_ctx; - error_status_t rc; - NTSTATUS status; - uint32_t i; - - DEBUG(3, ("_epm_Delete: Trying to delete %u entries.\n", - r->in.num_ents)); - - /* If this is not a priviledged users, return */ - if (!is_priviledged_pipe(p->server_info)) { - return EPMAPPER_STATUS_CANT_PERFORM_OP; - } - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return EPMAPPER_STATUS_NO_MEMORY; - } - - for (i = 0; i < r->in.num_ents; i++) { - struct dcerpc_binding *b = NULL; - struct dcesrv_endpoint *ep; - struct dcesrv_iface iface; - struct dcesrv_iface_list *iflist; - - status = dcerpc_binding_from_tower(tmp_ctx, - &r->in.entries[i].tower->tower, - &b); - if (!NT_STATUS_IS_OK(status)) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - DEBUG(3, ("_epm_Delete: Deleting transport '%s' for '%s'\n", - derpc_transport_string_by_transport(b->transport), - r->in.entries[i].annotation)); - - ep = find_endpoint(endpoint_table, b); - if (ep == NULL) { - rc = EPMAPPER_STATUS_OK; - goto done; - } - - iface.name = r->in.entries[i].annotation; - iface.syntax_id = b->object; - - iflist = find_interface_list(ep, &iface); - if (iflist == NULL) { - DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n")); - DLIST_REMOVE(endpoint_table, ep); - talloc_free(ep); - - rc = EPMAPPER_STATUS_OK; - goto done; - } - - DLIST_REMOVE(ep->iface_list, iflist); - - if (ep->iface_list == NULL) { - DEBUG(0, ("_epm_Delete: No interfaces left, delete endpoint\n")); - DLIST_REMOVE(endpoint_table, ep); - talloc_free(ep); - - rc = EPMAPPER_STATUS_OK; - goto done; - } - - } - - rc = EPMAPPER_STATUS_OK; -done: - talloc_free(tmp_ctx); - - return rc; -} - - -/* - * epm_Lookup - * - * Lookup entries in an endpoint map. - */ -error_status_t _epm_Lookup(struct pipes_struct *p, - struct epm_Lookup *r) -{ - struct policy_handle *entry_handle; - struct rpc_eps *eps; - TALLOC_CTX *tmp_ctx; - error_status_t rc; - uint32_t count = 0; - uint32_t num_ents = 0; - uint32_t i; - bool match = false; - bool ok; - - *r->out.num_ents = 0; - r->out.entries = NULL; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return EPMAPPER_STATUS_NO_MEMORY; - } - - DEBUG(3, ("_epm_Lookup: Trying to lookup max. %u entries.\n", - r->in.max_ents)); - - if (r->in.entry_handle == NULL || - policy_handle_empty(r->in.entry_handle)) { - struct GUID *obj; - - DEBUG(5, ("_epm_Lookup: No entry_handle found, creating it.\n")); - - eps = talloc_zero(tmp_ctx, struct rpc_eps); - if (eps == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - if (r->in.object == NULL || GUID_all_zero(r->in.object)) { - obj = NULL; - } else { - obj = r->in.object; - } - - switch (r->in.inquiry_type) { - case RPC_C_EP_ALL_ELTS: - /* - * Return all elements from the endpoint map. The - * interface_id, vers_option, and object parameters MUST - * be ignored. - */ - eps->count = build_ep_list(eps, - endpoint_table, - NULL, - &eps->e); - break; - case RPC_C_EP_MATCH_BY_IF: - /* - * Return endpoint map elements that contain the - * interface identifier specified by the interface_id - * and vers_option values. - * - * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH - * need both the same endpoint list. There is a second - * check for the inquiry_type below which differentiates - * between them. - */ - case RPC_C_EP_MATCH_BY_BOTH: - /* - * Return endpoint map elements that contain the - * interface identifier and object UUID specified by - * interface_id, vers_option, and object. - */ - eps->count = build_ep_list(eps, - endpoint_table, - &r->in.interface_id->uuid, - &eps->e); - break; - case RPC_C_EP_MATCH_BY_OBJ: - /* - * Return endpoint map elements that contain the object - * UUID specified by object. - */ - eps->count = build_ep_list(eps, - endpoint_table, - r->in.object, - &eps->e); - break; - default: - rc = EPMAPPER_STATUS_CANT_PERFORM_OP; - goto done; - } - - if (eps->count == 0) { - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - ok = create_policy_hnd(p, r->out.entry_handle, eps); - if (!ok) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps); - if (!ok) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - entry_handle = r->out.entry_handle; - } else { - DEBUG(5, ("_epm_Lookup: Trying to find entry_handle.\n")); - - ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps); - if (!ok) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - entry_handle = r->in.entry_handle; - } - - if (eps == NULL || eps->e == NULL) { - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - /* return the next N elements */ - count = r->in.max_ents; - if (count > eps->count) { - count = eps->count; - } - - DEBUG(3, ("_epm_Lookup: Find %u entries\n", count)); - - if (count == 0) { - close_policy_hnd(p, entry_handle); - ZERO_STRUCTP(r->out.entry_handle); - - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count); - if (r->out.entries == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - for (i = 0; i < count; i++) { - match = false; - - switch (r->in.inquiry_type) { - case RPC_C_EP_ALL_ELTS: - /* - * Return all elements from the endpoint map. The - * interface_id, vers_option, and object parameters MUST - * be ignored. - */ - match = true; - break; - case RPC_C_EP_MATCH_BY_IF: - /* - * Return endpoint map elements that contain the - * interface identifier specified by the interface_id - * and vers_option values. - */ - if (GUID_equal(&r->in.interface_id->uuid, - &eps->e[i].syntax_id.uuid)) { - match = true; - } - break; - case RPC_C_EP_MATCH_BY_OBJ: - /* - * Return endpoint map elements that contain the object - * UUID specified by object. - */ - if (GUID_equal(r->in.object, - &eps->e[i].syntax_id.uuid)) { - match = true; - } - break; - case RPC_C_EP_MATCH_BY_BOTH: - /* - * Return endpoint map elements that contain the - * interface identifier and object UUID specified by - * interface_id, vers_option, and object. - */ - if (GUID_equal(&r->in.interface_id->uuid, - &eps->e[i].syntax_id.uuid) && - GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) { - match = true; - } - break; - default: - return EPMAPPER_STATUS_CANT_PERFORM_OP; - } - - if (match) { - if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF || - r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) { - /* Check inteface version */ - - match = false; - switch (r->in.vers_option) { - case RPC_C_VERS_ALL: - /* - * Return endpoint map elements that - * contain the specified interface UUID, - * regardless of the version numbers. - */ - match = true; - break; - case RPC_C_VERS_COMPATIBLE: - /* - * Return the endpoint map elements that - * contain the same major versions of - * the specified interface UUID and a - * minor version greater than or equal - * to the minor version of the specified - * UUID. - */ - if (r->in.interface_id->vers_major == - (eps->e[i].syntax_id.if_version >> 16) && - r->in.interface_id->vers_minor <= - (eps->e[i].syntax_id.if_version && 0xFFFF)) { - match = true; - } - break; - case RPC_C_VERS_EXACT: - /* - * Return endpoint map elements that - * contain the specified version of the - * specified interface UUID. - */ - if (r->in.interface_id->vers_major == - (eps->e[i].syntax_id.if_version >> 16) && - r->in.interface_id->vers_minor == - (eps->e[i].syntax_id.if_version && 0xFFFF)) { - match = true; - } - match = true; - break; - case RPC_C_VERS_MAJOR_ONLY: - /* - * Return endpoint map elements that - * contain the same version of the - * specified interface UUID and ignore - * the minor version. - */ - if (r->in.interface_id->vers_major == - (eps->e[i].syntax_id.if_version >> 16)) { - match = true; - } - match = true; - break; - case RPC_C_VERS_UPTO: - /* - * Return endpoint map elements that - * contain a version of the specified - * interface UUID less than or equal to - * the specified major and minor - * version. - */ - if (r->in.interface_id->vers_major > - eps->e[i].syntax_id.if_version >> 16) { - match = true; - } else { - if (r->in.interface_id->vers_major == - (eps->e[i].syntax_id.if_version >> 16) && - r->in.interface_id->vers_minor >= - (eps->e[i].syntax_id.if_version && 0xFFFF)) { - match = true; - } - } - break; - default: - return EPMAPPER_STATUS_CANT_PERFORM_OP; - } - } - } - - if (match) { - ZERO_STRUCT(r->out.entries[num_ents].object); - - DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n", - eps->e[i].name)); - r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries, - eps->e[i].name); - r->out.entries[num_ents].tower = talloc(r->out.entries, - struct epm_twr_t); - if (r->out.entries[num_ents].tower == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors); - r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors; - r->out.entries[num_ents].tower->tower_length = 0; - - num_ents++; - } - } /* end for loop */ - - *r->out.num_ents = num_ents; - - eps->count -= count; - eps->e += count; - if (eps->count == 0) { - close_policy_hnd(p, entry_handle); - ZERO_STRUCTP(r->out.entry_handle); - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - rc = EPMAPPER_STATUS_OK; -done: - talloc_free(tmp_ctx); - - return rc; -} - -/* - * epm_Map - * - * Apply some algorithm (using the fields in the map_tower) to an endpoint map - * to produce a list of protocol towers. - */ -error_status_t _epm_Map(struct pipes_struct *p, - struct epm_Map *r) -{ - struct policy_handle *entry_handle; - enum dcerpc_transport_t transport; - struct ndr_syntax_id ifid; - struct epm_floor *floors; - struct rpc_eps *eps; - TALLOC_CTX *tmp_ctx; - error_status_t rc; - uint32_t count = 0; - uint32_t num_towers = 0; - uint32_t num_floors = 0; - uint32_t i; - bool ok; - - *r->out.num_towers = 0; - r->out.towers = NULL; - - if (r->in.map_tower == NULL || r->in.max_towers == 0 || - r->in.map_tower->tower.num_floors < 3) { - return EPMAPPER_STATUS_NO_MORE_ENTRIES; - } - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return EPMAPPER_STATUS_NO_MEMORY; - } - - ZERO_STRUCTP(r->out.entry_handle); - - DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n", - r->in.max_towers)); - - /* - * A tower has normally up to 6 floors - * - * +-----------------------------------------------------------------+ - * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for | - * | | netlogon) | - * +---------+-------------------------------------------------------+ - * | Floor 2 | Transfer syntax (NDR endcoded) | - * +---------+-------------------------------------------------------+ - * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) | - * +---------+-------------------------------------------------------+ - * | Floor 4 | Port address (e.g. TCP Port: 49156) | - * +---------+-------------------------------------------------------+ - * | Floor 5 | Transport (e.g. IP:192.168.51.10) | - * +---------+-------------------------------------------------------+ - * | Floor 6 | Routing | - * +---------+-------------------------------------------------------+ - */ - num_floors = r->in.map_tower->tower.num_floors; - floors = r->in.map_tower->tower.floors; - - /* We accept NDR as the transfer syntax */ - dcerpc_floor_get_lhs_data(&floors[1], &ifid); - - if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID || - !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) || - ifid.if_version != ndr_transfer_syntax.if_version) { - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - /* We only talk to sane transports */ - transport = dcerpc_transport_by_tower(&r->in.map_tower->tower); - if (transport == NCA_UNKNOWN) { - DEBUG(2, ("epm_Map: Client requested unknown transport with" - "levels: ")); - for (i = 2; i < r->in.map_tower->tower.num_floors; i++) { - DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol)); - } - DEBUG(2, ("\n")); - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - if (r->in.entry_handle == NULL || - policy_handle_empty(r->in.entry_handle)) { - struct GUID *obj; - - DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n")); - - eps = talloc_zero(tmp_ctx, struct rpc_eps); - if (eps == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - /* - * *** ATTENTION *** - * CDE 1.1 states: - * - * ept_map() - * Apply some algorithm (using the fields in the map_tower) - * to an endpoint map to produce a list of protocol towers. - * - * The following code is the mysterious "some algorithm"! - */ - - /* Filter by object id if one was given. */ - if (r->in.object == NULL || GUID_all_zero(r->in.object)) { - obj = NULL; - } else { - obj = r->in.object; - } - - eps->count = build_ep_list(eps, - endpoint_table, - obj, - &eps->e); - if (eps->count == 0) { - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - /* Filter out endpoints which match the interface. */ - { - struct rpc_eps *teps; - uint32_t total = 0; - - teps = talloc_zero(tmp_ctx, struct rpc_eps); - if (teps == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - for (i = 0; i < eps->count; i++) { - if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data, - &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 || - transport != dcerpc_transport_by_tower(&eps->e[i].ep)) { - continue; - } - - teps->e = talloc_realloc(tmp_ctx, - teps->e, - struct dcesrv_ep_iface, - total + 1); - if (teps->e == NULL) { - return 0; - } - - teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors); - teps->e[total].ep.num_floors = eps->e[i].ep.num_floors; - teps->e[total].name = talloc_move(teps, &eps->e[i].name); - teps->e[total].syntax_id = eps->e[i].syntax_id; - - total++; - } - - teps->count = total; - talloc_free(eps); - eps = teps; - } - /* end of "some algorithm" */ - - ok = create_policy_hnd(p, r->out.entry_handle, eps); - if (!ok) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps); - if (!ok) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - entry_handle = r->out.entry_handle; - } else { - DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n")); - - ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps); - if (!ok) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - entry_handle = r->in.entry_handle; - } - - if (eps == NULL || eps->e == NULL) { - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - /* return the next N elements */ - count = r->in.max_towers; - if (count > eps->count) { - count = eps->count; - } - - if (count == 0) { - close_policy_hnd(p, entry_handle); - ZERO_STRUCTP(r->out.entry_handle); - - rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; - goto done; - } - - r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count); - if (r->out.towers == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - - for (i = 0; i < count; i++) { - DEBUG(5, ("_epm_Map: Map tower for '%s'\n", - eps->e[i].name)); - - r->out.towers[num_towers].twr = talloc(r->out.towers, - struct epm_twr_t); - if (r->out.towers[num_towers].twr == NULL) { - rc = EPMAPPER_STATUS_NO_MEMORY; - goto done; - } - r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors); - r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors; - r->out.towers[num_towers].twr->tower_length = 0; - - num_towers++; - } - - *r->out.num_towers = num_towers; - - eps->count -= count; - eps->e += count; - if (eps->count == 0) { - close_policy_hnd(p, entry_handle); - ZERO_STRUCTP(r->out.entry_handle); - } - - rc = EPMAPPER_STATUS_OK; -done: - talloc_free(tmp_ctx); - - return rc; -} - -/* - * epm_LookupHandleFree - */ -error_status_t _epm_LookupHandleFree(struct pipes_struct *p, - struct epm_LookupHandleFree *r) -{ - if (r->in.entry_handle == NULL) { - return EPMAPPER_STATUS_OK; - } - - if (is_valid_policy_hnd(r->in.entry_handle)) { - close_policy_hnd(p, r->in.entry_handle); - } - - r->out.entry_handle = r->in.entry_handle; - - return EPMAPPER_STATUS_OK; -} - - -/* - * epm_InqObject - * - * A client implementation SHOULD NOT call this method. These extensions do not - * provide an alternative method. - */ -error_status_t _epm_InqObject(struct pipes_struct *p, - struct epm_InqObject *r) -{ - p->rng_fault_state = true; - return EPMAPPER_STATUS_CANT_PERFORM_OP; -} - - -/* - * epm_MgmtDelete - * - * A client implementation SHOULD NOT call this method. These extensions do not - * provide an alternative method. -*/ -error_status_t _epm_MgmtDelete(struct pipes_struct *p, - struct epm_MgmtDelete *r) -{ - p->rng_fault_state = true; - return EPMAPPER_STATUS_CANT_PERFORM_OP; -} - - -/* - epm_MapAuth -*/ -error_status_t _epm_MapAuth(struct pipes_struct *p, - struct epm_MapAuth *r) -{ - p->rng_fault_state = true; - return EPMAPPER_STATUS_CANT_PERFORM_OP; -} - -/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/srv_eventlog_nt.c b/source3/rpc_server/srv_eventlog_nt.c deleted file mode 100644 index ff8a49526e..0000000000 --- a/source3/rpc_server/srv_eventlog_nt.c +++ /dev/null @@ -1,939 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Marcin Krzysztof Porwit 2005, - * Copyright (C) Brian Moran 2005, - * Copyright (C) Gerald (Jerry) Carter 2005. - * Copyright (C) Guenther Deschner 2009. - * - * 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 . - */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_eventlog.h" -#include "lib/eventlog/eventlog.h" -#include "registry.h" -#include "../libcli/security/security.h" -#include "../librpc/gen_ndr/ndr_winreg_c.h" -#include "rpc_client/cli_winreg_int.h" -#include "rpc_client/cli_winreg.h" - - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -#define TOP_LEVEL_EVENTLOG_KEY "SYSTEM\\CurrentControlSet\\Services\\Eventlog" - -typedef struct { - char *logname; - ELOG_TDB *etdb; - uint32 current_record; - uint32 num_records; - uint32 oldest_entry; - uint32 flags; - uint32 access_granted; -} EVENTLOG_INFO; - -/******************************************************************** - ********************************************************************/ - -static int eventlog_info_destructor(EVENTLOG_INFO *elog) -{ - if (elog->etdb) { - elog_close_tdb(elog->etdb, false); - } - return 0; -} - -/******************************************************************** - ********************************************************************/ - -static EVENTLOG_INFO *find_eventlog_info_by_hnd( struct pipes_struct * p, - struct policy_handle * handle ) -{ - EVENTLOG_INFO *info; - - if ( !find_policy_by_hnd( p, handle, (void **)(void *)&info ) ) { - DEBUG( 2, - ( "find_eventlog_info_by_hnd: eventlog not found.\n" ) ); - return NULL; - } - - return info; -} - -/******************************************************************** -********************************************************************/ - -static bool elog_check_access( EVENTLOG_INFO *info, const struct security_token *token ) -{ - char *tdbname = elog_tdbname(talloc_tos(), info->logname ); - struct security_descriptor *sec_desc; - struct security_ace *ace; - NTSTATUS status; - - if ( !tdbname ) - return False; - - /* get the security descriptor for the file */ - - sec_desc = get_nt_acl_no_snum( info, tdbname ); - TALLOC_FREE( tdbname ); - - if ( !sec_desc ) { - DEBUG(5,("elog_check_access: Unable to get NT ACL for %s\n", - tdbname)); - return False; - } - - ace = talloc_zero(sec_desc, struct security_ace); - if (ace == NULL) { - TALLOC_FREE(sec_desc); - return false; - } - - ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED; - ace->flags = 0; - ace->access_mask = REG_KEY_ALL; - ace->trustee = global_sid_System; - - status = security_descriptor_dacl_add(sec_desc, ace); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(sec_desc); - return false; - } - - /* root free pass */ - - if ( geteuid() == sec_initial_uid() ) { - DEBUG(5,("elog_check_access: running as root, using system token\n")); - token = get_system_token(); - } - - /* run the check, try for the max allowed */ - - status = se_access_check( sec_desc, token, MAXIMUM_ALLOWED_ACCESS, - &info->access_granted); - - TALLOC_FREE(sec_desc); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(8,("elog_check_access: se_access_check() return %s\n", - nt_errstr(status))); - return False; - } - - /* we have to have READ permission for a successful open */ - - return ( info->access_granted & SEC_FILE_READ_DATA ); -} - -/******************************************************************** - ********************************************************************/ - -static bool elog_validate_logname( const char *name ) -{ - int i; - const char **elogs = lp_eventlog_list(); - - if (!elogs) { - return False; - } - - for ( i=0; elogs[i]; i++ ) { - if ( strequal( name, elogs[i] ) ) - return True; - } - - return False; -} - -/******************************************************************** -********************************************************************/ - -static bool get_num_records_hook( EVENTLOG_INFO * info ) -{ - int next_record; - int oldest_record; - - if ( !info->etdb ) { - DEBUG( 10, ( "No open tdb for %s\n", info->logname ) ); - return False; - } - - /* lock the tdb since we have to get 2 records */ - - tdb_lock_bystring_with_timeout( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD, 1 ); - next_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD); - oldest_record = tdb_fetch_int32( ELOG_TDB_CTX(info->etdb), EVT_OLDEST_ENTRY); - tdb_unlock_bystring( ELOG_TDB_CTX(info->etdb), EVT_NEXT_RECORD); - - DEBUG( 8, - ( "Oldest Record %d; Next Record %d\n", oldest_record, - next_record ) ); - - info->num_records = ( next_record - oldest_record ); - info->oldest_entry = oldest_record; - - return True; -} - -/******************************************************************** - ********************************************************************/ - -static bool get_oldest_entry_hook( EVENTLOG_INFO * info ) -{ - /* it's the same thing */ - return get_num_records_hook( info ); -} - -/******************************************************************** - ********************************************************************/ - -static NTSTATUS elog_open( struct pipes_struct * p, const char *logname, struct policy_handle *hnd ) -{ - EVENTLOG_INFO *elog; - - /* first thing is to validate the eventlog name */ - - if ( !elog_validate_logname( logname ) ) - return NT_STATUS_OBJECT_PATH_INVALID; - - if ( !(elog = TALLOC_ZERO_P( NULL, EVENTLOG_INFO )) ) - return NT_STATUS_NO_MEMORY; - talloc_set_destructor(elog, eventlog_info_destructor); - - elog->logname = talloc_strdup( elog, logname ); - - /* Open the tdb first (so that we can create any new tdbs if necessary). - We have to do this as root and then use an internal access check - on the file permissions since you can only have a tdb open once - in a single process */ - - become_root(); - elog->etdb = elog_open_tdb( elog->logname, False, False ); - unbecome_root(); - - if ( !elog->etdb ) { - /* according to MSDN, if the logfile cannot be found, we should - default to the "Application" log */ - - if ( !strequal( logname, ELOG_APPL ) ) { - - TALLOC_FREE( elog->logname ); - - elog->logname = talloc_strdup( elog, ELOG_APPL ); - - /* do the access check */ - if ( !elog_check_access( elog, p->server_info->security_token ) ) { - TALLOC_FREE( elog ); - return NT_STATUS_ACCESS_DENIED; - } - - become_root(); - elog->etdb = elog_open_tdb( elog->logname, False, False ); - unbecome_root(); - } - - if ( !elog->etdb ) { - TALLOC_FREE( elog ); - return NT_STATUS_ACCESS_DENIED; /* ??? */ - } - } - - /* now do the access check. Close the tdb if we fail here */ - - if ( !elog_check_access( elog, p->server_info->security_token ) ) { - TALLOC_FREE( elog ); - return NT_STATUS_ACCESS_DENIED; - } - - /* create the policy handle */ - - if ( !create_policy_hnd( p, hnd, elog ) ) { - TALLOC_FREE(elog); - return NT_STATUS_NO_MEMORY; - } - - /* set the initial current_record pointer */ - - if ( !get_oldest_entry_hook( elog ) ) { - DEBUG(3,("elog_open: Successfully opened eventlog but can't " - "get any information on internal records!\n")); - } - - elog->current_record = elog->oldest_entry; - - return NT_STATUS_OK; -} - -/******************************************************************** - ********************************************************************/ - -static NTSTATUS elog_close( struct pipes_struct *p, struct policy_handle *hnd ) -{ - if ( !( close_policy_hnd( p, hnd ) ) ) { - return NT_STATUS_INVALID_HANDLE; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - *******************************************************************/ - -static int elog_size( EVENTLOG_INFO *info ) -{ - if ( !info || !info->etdb ) { - DEBUG(0,("elog_size: Invalid info* structure!\n")); - return 0; - } - - return elog_tdb_size( ELOG_TDB_CTX(info->etdb), NULL, NULL ); -} - -/******************************************************************** - note that this can only be called AFTER the table is constructed, - since it uses the table to find the tdb handle - ********************************************************************/ - -static bool sync_eventlog_params(TALLOC_CTX *mem_ctx, - struct messaging_context *msg_ctx, - EVENTLOG_INFO *info) -{ - struct dcerpc_binding_handle *h = NULL; - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct policy_handle hive_hnd, key_hnd; - uint32_t uiMaxSize = 0; - uint32_t uiRetention = 0; - char *path = NULL; - NTSTATUS status; - WERROR wresult = WERR_OK; - char *elogname = info->logname; - TALLOC_CTX *ctx; - bool ret = false; - - ctx = talloc_stackframe(); - if (ctx == NULL) { - return false; - } - - DEBUG( 4, ( "sync_eventlog_params with %s\n", elogname ) ); - - if ( !info->etdb ) { - DEBUG( 4, ( "No open tdb! (%s)\n", info->logname ) ); - goto done; - } - /* set resonable defaults. 512Kb on size and 1 week on time */ - - uiMaxSize = 0x80000; - uiRetention = 604800; - - /* the general idea is to internally open the registry - key and retrieve the values. That way we can continue - to use the same fetch/store api that we use in - srv_reg_nt.c */ - path = talloc_asprintf(ctx, "%s\\%s", TOP_LEVEL_EVENTLOG_KEY, elogname); - if (!path) { - goto done; - } - - status = dcerpc_winreg_int_hklm_openkey(ctx, - get_server_info_system(), - msg_ctx, - &h, - path, - false, - access_mask, - &hive_hnd, - &key_hnd, - &wresult); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(4,("sync_eventlog_params: Failed to open key [%s] (%s)\n", - path, nt_errstr(status))); - goto done; - } - if ( !W_ERROR_IS_OK( wresult ) ) { - DEBUG( 4, - ( "sync_eventlog_params: Failed to open key [%s] (%s)\n", - path, win_errstr( wresult ) ) ); - goto done; - } - - status = dcerpc_winreg_query_dword(ctx, - h, - &key_hnd, - "Retention", - &uiRetention, - &wresult); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(4, ("Failed to query value \"Retention\": %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(wresult)) { - DEBUG(4, ("Failed to query value \"Retention\": %s\n", - win_errstr(wresult))); - goto done; - } - - status = dcerpc_winreg_query_dword(ctx, - h, - &key_hnd, - "MaxSize", - &uiMaxSize, - &wresult); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(4, ("Failed to query value \"Retention\": %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(wresult)) { - DEBUG(4, ("Failed to query value \"MaxSize\": %s\n", - win_errstr(wresult))); - goto done; - } - - tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_MAXSIZE, uiMaxSize ); - tdb_store_int32( ELOG_TDB_CTX(info->etdb), EVT_RETENTION, uiRetention ); - - ret = true; - -done: - if (h != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(h, ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(ctx); - return ret; -} - -/******************************************************************** - _eventlog_OpenEventLogW - ********************************************************************/ - -NTSTATUS _eventlog_OpenEventLogW(struct pipes_struct *p, - struct eventlog_OpenEventLogW *r) -{ - EVENTLOG_INFO *info; - NTSTATUS result; - - DEBUG( 10,("_eventlog_OpenEventLogW: Server [%s], Log [%s]\n", - r->in.servername->string, r->in.logname->string )); - - /* according to MSDN, if the logfile cannot be found, we should - default to the "Application" log */ - - if ( !NT_STATUS_IS_OK( result = elog_open( p, r->in.logname->string, r->out.handle )) ) - return result; - - if ( !(info = find_eventlog_info_by_hnd( p, r->out.handle )) ) { - DEBUG(0,("_eventlog_OpenEventLogW: eventlog (%s) opened but unable to find handle!\n", - r->in.logname->string )); - elog_close( p, r->out.handle ); - return NT_STATUS_INVALID_HANDLE; - } - - DEBUG(10,("_eventlog_OpenEventLogW: Size [%d]\n", elog_size( info ))); - - if (!sync_eventlog_params(p->mem_ctx, - p->msg_ctx, - info)) { - elog_close(p, r->out.handle); - return NT_STATUS_EVENTLOG_FILE_CORRUPT; - } - prune_eventlog( ELOG_TDB_CTX(info->etdb) ); - - return NT_STATUS_OK; -} - -/******************************************************************** - _eventlog_ClearEventLogW - This call still needs some work - ********************************************************************/ -/** The windows client seems to be doing something funny with the file name - A call like - ClearEventLog(handle, "backup_file") - on the client side will result in the backup file name looking like this on the - server side: - \??\${CWD of client}\backup_file - If an absolute path gets specified, such as - ClearEventLog(handle, "C:\\temp\\backup_file") - then it is still mangled by the client into this: - \??\C:\temp\backup_file - when it is on the wire. - I'm not sure where the \?? is coming from, or why the ${CWD} of the client process - would be added in given that the backup file gets written on the server side. */ - -NTSTATUS _eventlog_ClearEventLogW(struct pipes_struct *p, - struct eventlog_ClearEventLogW *r) -{ - EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); - - if ( !info ) - return NT_STATUS_INVALID_HANDLE; - - if (r->in.backupfile && r->in.backupfile->string) { - - DEBUG(8,( "_eventlog_ClearEventLogW: Using [%s] as the backup " - "file name for log [%s].", - r->in.backupfile->string, info->logname ) ); - } - - /* check for WRITE access to the file */ - - if ( !(info->access_granted & SEC_FILE_WRITE_DATA) ) - return NT_STATUS_ACCESS_DENIED; - - /* Force a close and reopen */ - - elog_close_tdb( info->etdb, True ); - become_root(); - info->etdb = elog_open_tdb( info->logname, True, False ); - unbecome_root(); - - if ( !info->etdb ) - return NT_STATUS_ACCESS_DENIED; - - return NT_STATUS_OK; -} - -/******************************************************************** - _eventlog_CloseEventLog - ********************************************************************/ - -NTSTATUS _eventlog_CloseEventLog(struct pipes_struct * p, - struct eventlog_CloseEventLog *r) -{ - NTSTATUS status; - - status = elog_close( p, r->in.handle ); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - ZERO_STRUCTP(r->out.handle); - - return NT_STATUS_OK; -} - -/******************************************************************** - _eventlog_ReadEventLogW - ********************************************************************/ - -NTSTATUS _eventlog_ReadEventLogW(struct pipes_struct *p, - struct eventlog_ReadEventLogW *r) -{ - EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); - uint32_t num_records_read = 0; - int bytes_left, record_number; - uint32_t elog_read_type, elog_read_dir; - - if (!info) { - return NT_STATUS_INVALID_HANDLE; - } - - info->flags = r->in.flags; - bytes_left = r->in.number_of_bytes; - - if (!info->etdb) { - return NT_STATUS_ACCESS_DENIED; - } - - /* check for valid flags. Can't use the sequential and seek flags together */ - - elog_read_type = r->in.flags & (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ); - elog_read_dir = r->in.flags & (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ); - - if (r->in.flags == 0 || - elog_read_type == (EVENTLOG_SEQUENTIAL_READ|EVENTLOG_SEEK_READ) || - elog_read_dir == (EVENTLOG_FORWARDS_READ|EVENTLOG_BACKWARDS_READ)) - { - DEBUG(3,("_eventlog_ReadEventLogW: " - "Invalid flags [0x%08x] for ReadEventLog\n", - r->in.flags)); - return NT_STATUS_INVALID_PARAMETER; - } - - /* a sequential read should ignore the offset */ - - if (elog_read_type & EVENTLOG_SEQUENTIAL_READ) { - record_number = info->current_record; - } else { - record_number = r->in.offset; - } - - if (r->in.number_of_bytes == 0) { - struct EVENTLOGRECORD *e; - e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb), - record_number); - if (!e) { - return NT_STATUS_END_OF_FILE; - } - *r->out.real_size = e->Length; - return NT_STATUS_BUFFER_TOO_SMALL; - } - - while (bytes_left > 0) { - - DATA_BLOB blob; - enum ndr_err_code ndr_err; - struct EVENTLOGRECORD *e; - - e = evlog_pull_record(p->mem_ctx, ELOG_TDB_CTX(info->etdb), - record_number); - if (!e) { - break; - } - - ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, e, - (ndr_push_flags_fn_t)ndr_push_EVENTLOGRECORD); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(EVENTLOGRECORD, e); - } - - if (blob.length > r->in.number_of_bytes) { - *r->out.real_size = blob.length; - return NT_STATUS_BUFFER_TOO_SMALL; - } - - if (*r->out.sent_size + blob.length > r->in.number_of_bytes) { - break; - } - - bytes_left -= blob.length; - - if (info->flags & EVENTLOG_FORWARDS_READ) { - record_number++; - } else { - record_number--; - } - - /* update the eventlog record pointer */ - - info->current_record = record_number; - - memcpy(&r->out.data[*(r->out.sent_size)], - blob.data, blob.length); - *(r->out.sent_size) += blob.length; - - num_records_read++; - } - - if (r->in.offset == 0 && record_number == 0 && *r->out.sent_size == 0) { - return NT_STATUS_END_OF_FILE; - } - - return NT_STATUS_OK; -} - -/******************************************************************** - _eventlog_GetOldestRecord - ********************************************************************/ - -NTSTATUS _eventlog_GetOldestRecord(struct pipes_struct *p, - struct eventlog_GetOldestRecord *r) -{ - EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); - - if (info == NULL) { - return NT_STATUS_INVALID_HANDLE; - } - - if ( !( get_oldest_entry_hook( info ) ) ) - return NT_STATUS_ACCESS_DENIED; - - *r->out.oldest_entry = info->oldest_entry; - - return NT_STATUS_OK; -} - -/******************************************************************** -_eventlog_GetNumRecords - ********************************************************************/ - -NTSTATUS _eventlog_GetNumRecords(struct pipes_struct *p, - struct eventlog_GetNumRecords *r) -{ - EVENTLOG_INFO *info = find_eventlog_info_by_hnd( p, r->in.handle ); - - if (info == NULL) { - return NT_STATUS_INVALID_HANDLE; - } - - if ( !( get_num_records_hook( info ) ) ) - return NT_STATUS_ACCESS_DENIED; - - *r->out.number = info->num_records; - - return NT_STATUS_OK; -} - -NTSTATUS _eventlog_BackupEventLogW(struct pipes_struct *p, struct eventlog_BackupEventLogW *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/******************************************************************** -_eventlog_GetLogInformation - ********************************************************************/ - -NTSTATUS _eventlog_GetLogInformation(struct pipes_struct *p, - struct eventlog_GetLogInformation *r) -{ - EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); - struct EVENTLOG_FULL_INFORMATION f; - enum ndr_err_code ndr_err; - DATA_BLOB blob; - - if (!info) { - return NT_STATUS_INVALID_HANDLE; - } - - if (r->in.level != 0) { - return NT_STATUS_INVALID_LEVEL; - } - - *r->out.bytes_needed = 4; - - if (r->in.buf_size < 4) { - return NT_STATUS_BUFFER_TOO_SMALL; - } - - /* FIXME: this should be retrieved from the handle */ - f.full = false; - - ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &f, - (ndr_push_flags_fn_t)ndr_push_EVENTLOG_FULL_INFORMATION); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(EVENTLOG_FULL_INFORMATION, &f); - } - - memcpy(r->out.buffer, blob.data, 4); - - return NT_STATUS_OK; -} - -/******************************************************************** -_eventlog_FlushEventLog - ********************************************************************/ - -NTSTATUS _eventlog_FlushEventLog(struct pipes_struct *p, - struct eventlog_FlushEventLog *r) -{ - EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); - if (!info) { - return NT_STATUS_INVALID_HANDLE; - } - - return NT_STATUS_ACCESS_DENIED; -} - -/******************************************************************** - ********************************************************************/ - -static NTSTATUS evlog_report_to_record(TALLOC_CTX *mem_ctx, - const struct eventlog_ReportEventW *r, - const char *logname, - struct EVENTLOGRECORD *e) -{ - uint32_t i; - ZERO_STRUCTP(e); - - e->TimeGenerated = r->in.timestamp; - e->TimeWritten = time(NULL); - e->EventID = r->in.event_id; - e->EventType = r->in.event_type; - e->NumStrings = r->in.num_of_strings; - e->EventCategory = r->in.event_category; - e->ReservedFlags = r->in.flags; - e->DataLength = r->in.data_size; - e->SourceName = talloc_strdup(mem_ctx, logname); - NT_STATUS_HAVE_NO_MEMORY(e->SourceName); - if (r->in.servername->string) { - e->Computername = r->in.servername->string; - } else { - e->Computername = talloc_strdup(mem_ctx, ""); - NT_STATUS_HAVE_NO_MEMORY(e->Computername); - } - if (r->in.user_sid) { - e->UserSid = *r->in.user_sid; - } - e->Strings = talloc_array(mem_ctx, const char *, e->NumStrings); - NT_STATUS_HAVE_NO_MEMORY(e->Strings); - - for (i=0; i < e->NumStrings; i++) { - e->Strings[i] = talloc_strdup(e->Strings, - r->in.strings[i]->string); - NT_STATUS_HAVE_NO_MEMORY(e->Strings[i]); - } - e->Data = r->in.data; - - return NT_STATUS_OK; -} - -/******************************************************************** -_eventlog_ReportEventW - ********************************************************************/ - -NTSTATUS _eventlog_ReportEventW(struct pipes_struct *p, - struct eventlog_ReportEventW *r) -{ - NTSTATUS status; - struct EVENTLOGRECORD record; - - EVENTLOG_INFO *info = find_eventlog_info_by_hnd(p, r->in.handle); - if (!info) { - return NT_STATUS_INVALID_HANDLE; - } - - status = evlog_report_to_record(p->mem_ctx, r, info->logname, &record); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = evlog_push_record(p->mem_ctx, - ELOG_TDB_CTX(info->etdb), - &record, - r->out.record_number); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - return NT_STATUS_OK; -} - -/******************************************************************** - ********************************************************************/ - -NTSTATUS _eventlog_DeregisterEventSource(struct pipes_struct *p, - struct eventlog_DeregisterEventSource *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_ChangeNotify(struct pipes_struct *p, - struct eventlog_ChangeNotify *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_RegisterEventSourceW(struct pipes_struct *p, - struct eventlog_RegisterEventSourceW *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_OpenBackupEventLogW(struct pipes_struct *p, - struct eventlog_OpenBackupEventLogW *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_ClearEventLogA(struct pipes_struct *p, - struct eventlog_ClearEventLogA *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_BackupEventLogA(struct pipes_struct *p, - struct eventlog_BackupEventLogA *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_OpenEventLogA(struct pipes_struct *p, - struct eventlog_OpenEventLogA *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_RegisterEventSourceA(struct pipes_struct *p, - struct eventlog_RegisterEventSourceA *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_OpenBackupEventLogA(struct pipes_struct *p, - struct eventlog_OpenBackupEventLogA *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_ReadEventLogA(struct pipes_struct *p, - struct eventlog_ReadEventLogA *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_ReportEventA(struct pipes_struct *p, - struct eventlog_ReportEventA *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_RegisterClusterSvc(struct pipes_struct *p, - struct eventlog_RegisterClusterSvc *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_DeregisterClusterSvc(struct pipes_struct *p, - struct eventlog_DeregisterClusterSvc *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_WriteClusterEvents(struct pipes_struct *p, - struct eventlog_WriteClusterEvents *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _eventlog_ReportEventAndSourceW(struct pipes_struct *p, - struct eventlog_ReportEventAndSourceW *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} diff --git a/source3/rpc_server/srv_eventlog_reg.c b/source3/rpc_server/srv_eventlog_reg.c deleted file mode 100644 index 7336c31c76..0000000000 --- a/source3/rpc_server/srv_eventlog_reg.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * Eventlog RPC server keys initialization - * - * Copyright (c) 2005 Marcin Krzysztof Porwit - * Copyright (c) 2005 Brian Moran - * Copyright (c) 2005 Gerald (Jerry) Carter - * Copyright (c) 2011 Andreas Schneider - * - * 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 . - */ - -#include "includes.h" -#include "../librpc/gen_ndr/ndr_winreg_c.h" -#include "rpc_client/cli_winreg_int.h" -#include "rpc_client/cli_winreg.h" -#include "rpc_server/srv_eventlog_reg.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_REGISTRY - -#define TOP_LEVEL_EVENTLOG_KEY "SYSTEM\\CurrentControlSet\\Services\\Eventlog" - -bool eventlog_init_winreg(struct messaging_context *msg_ctx) -{ - struct dcerpc_binding_handle *h = NULL; - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct policy_handle hive_hnd, key_hnd; - uint32_t uiMaxSize = 0x00080000; - uint32_t uiRetention = 0x93A80; - const char **elogs = lp_eventlog_list(); - const char **subkeys = NULL; - uint32_t num_subkeys = 0; - uint32_t i; - char *key = NULL; - NTSTATUS status; - WERROR result = WERR_OK; - bool ok = false; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return false; - } - - DEBUG(3, ("Initialise the eventlog registry keys if needed.\n")); - - key = talloc_strdup(tmp_ctx, TOP_LEVEL_EVENTLOG_KEY); - - status = dcerpc_winreg_int_hklm_openkey(tmp_ctx, - get_server_info_system(), - msg_ctx, - &h, - key, - false, - access_mask, - &hive_hnd, - &key_hnd, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("eventlog_init_winreg: Could not open %s - %s\n", - key, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("eventlog_init_winreg: Could not open %s - %s\n", - key, win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_enum_keys(tmp_ctx, - h, - &key_hnd, - &num_subkeys, - &subkeys, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("eventlog_init_winreg: Could enum keys at %s - %s\n", - key, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("eventlog_init_winreg: Could enum keys at %s - %s\n", - key, win_errstr(result))); - goto done; - } - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); - } - - /* create subkeys if they don't exist */ - while (elogs && *elogs) { - enum winreg_CreateAction action = REG_ACTION_NONE; - char *evt_tdb = NULL; - struct winreg_String wkey; - struct winreg_String wkeyclass; - bool skip = false; - - for (i = 0; i < num_subkeys; i++) { - if (strequal(subkeys[i], *elogs)) { - skip = true; - } - } - - if (skip) { - elogs++; - continue; - } - - ZERO_STRUCT(key_hnd); - ZERO_STRUCT(wkey); - - wkey.name = talloc_asprintf(tmp_ctx, "%s\\%s", key, *elogs); - if (wkey.name == NULL) { - result = WERR_NOMEM; - goto done; - } - - ZERO_STRUCT(wkeyclass); - wkeyclass.name = ""; - - - status = dcerpc_winreg_CreateKey(h, - tmp_ctx, - &hive_hnd, - wkey, - wkeyclass, - 0, - access_mask, - NULL, - &key_hnd, - &action, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - h, - &key_hnd, - "MaxSize", - uiMaxSize, - &result); - - status = dcerpc_winreg_set_dword(tmp_ctx, - h, - &key_hnd, - "Retention", - uiRetention, - &result); - - status = dcerpc_winreg_set_sz(tmp_ctx, - h, - &key_hnd, - "PrimaryModule", - *elogs, - &result); - - evt_tdb = talloc_asprintf(tmp_ctx, - "%%SystemRoot%%\\system32\\config\\%s.tdb", - *elogs); - if (evt_tdb == NULL) { - goto done; - } - status = dcerpc_winreg_set_expand_sz(tmp_ctx, - h, - &key_hnd, - "File", - evt_tdb, - &result); - TALLOC_FREE(evt_tdb); - - status = dcerpc_winreg_add_multi_sz(tmp_ctx, - h, - &key_hnd, - "Sources", - *elogs, - &result); - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); - } - - /* sub-subkeys */ - { - uint32_t uiCategoryCount = 0x00000007; - - wkey.name = talloc_asprintf(tmp_ctx, - "%s\\%s", - wkey.name, *elogs); - if (wkey.name == NULL) { - result = WERR_NOMEM; - goto done; - } - - status = dcerpc_winreg_CreateKey(h, - tmp_ctx, - &hive_hnd, - wkey, - wkeyclass, - 0, - access_mask, - NULL, - &key_hnd, - &action, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - h, - &key_hnd, - "CategoryCount", - uiCategoryCount, - &result); - - status = dcerpc_winreg_set_expand_sz(tmp_ctx, - h, - &key_hnd, - "CategoryMessageFile", - "%SystemRoot%\\system32\\eventlog.dll", - &result); - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); - } - } - - elogs++; - } /* loop */ - - ok = true; -done: - TALLOC_FREE(tmp_ctx); - return ok; -} - -/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/srv_eventlog_reg.h b/source3/rpc_server/srv_eventlog_reg.h deleted file mode 100644 index 02c2792647..0000000000 --- a/source3/rpc_server/srv_eventlog_reg.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * WINREG client routines - * - * Copyright (c) 2011 Andreas Schneider - * - * 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 . - */ - -#ifndef SRV_EVENTLOG_REG_H -#define SRV_EVENTLOG_REG_H - -bool eventlog_init_winreg(struct messaging_context *msg_ctx); - -#endif /* SRV_EVENTLOG_REG_H */ - -/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/srv_initshutdown_nt.c b/source3/rpc_server/srv_initshutdown_nt.c deleted file mode 100644 index 225f7b3b9b..0000000000 --- a/source3/rpc_server/srv_initshutdown_nt.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1997. - * Copyright (C) Gerald Carter 2006. - * - * 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 . - */ - -/* Implementation of registry functions. */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_initshutdown.h" -#include "../librpc/gen_ndr/srv_winreg.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - - -/******************************************************************* - ********************************************************************/ -WERROR _initshutdown_Init(struct pipes_struct *p, struct initshutdown_Init *r) -{ - struct winreg_InitiateSystemShutdownEx s; - - s.in.hostname = r->in.hostname; - s.in.message = r->in.message; - s.in.timeout = r->in.timeout; - s.in.force_apps = r->in.force_apps; - s.in.do_reboot = r->in.do_reboot; - s.in.reason = 0; - - /* thunk down to _winreg_InitiateSystemShutdownEx() - (just returns a status) */ - - return _winreg_InitiateSystemShutdownEx( p, &s ); -} - -/******************************************************************* - ********************************************************************/ - -WERROR _initshutdown_InitEx(struct pipes_struct *p, struct initshutdown_InitEx *r) -{ - struct winreg_InitiateSystemShutdownEx s; - s.in.hostname = r->in.hostname; - s.in.message = r->in.message; - s.in.timeout = r->in.timeout; - s.in.force_apps = r->in.force_apps; - s.in.do_reboot = r->in.do_reboot; - s.in.reason = r->in.reason; - - return _winreg_InitiateSystemShutdownEx( p, &s); -} - - - - -/******************************************************************* - reg_abort_shutdwon - ********************************************************************/ - -WERROR _initshutdown_Abort(struct pipes_struct *p, struct initshutdown_Abort *r) -{ - struct winreg_AbortSystemShutdown s; - s.in.server = r->in.server; - return _winreg_AbortSystemShutdown( p, &s ); -} diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c deleted file mode 100644 index 53baba31ca..0000000000 --- a/source3/rpc_server/srv_lsa_nt.c +++ /dev/null @@ -1,2755 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, - * Copyright (C) Paul Ashton 1997, - * Copyright (C) Jeremy Allison 2001, 2006. - * Copyright (C) Rafal Szczesniak 2002, - * Copyright (C) Jim McDonough 2002, - * Copyright (C) Simo Sorce 2003. - * Copyright (C) Gerald (Jerry) Carter 2005. - * Copyright (C) Volker Lendecke 2005. - * Copyright (C) Guenther Deschner 2008. - * Copyright (C) Andrew Bartlett 2010. - * - * 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 . - */ - -/* This is the implementation of the lsa server code. */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_lsa.h" -#include "secrets.h" -#include "../librpc/gen_ndr/netlogon.h" -#include "rpc_client/init_lsa.h" -#include "../libcli/security/security.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -#define MAX_LOOKUP_SIDS 0x5000 /* 20480 */ - -enum lsa_handle_type { LSA_HANDLE_POLICY_TYPE = 1, LSA_HANDLE_ACCOUNT_TYPE }; - -struct lsa_info { - struct dom_sid sid; - const char *name; - uint32 access; - enum lsa_handle_type type; - struct security_descriptor *sd; -}; - -const struct generic_mapping lsa_account_mapping = { - LSA_ACCOUNT_READ, - LSA_ACCOUNT_WRITE, - LSA_ACCOUNT_EXECUTE, - LSA_ACCOUNT_ALL_ACCESS -}; - -const struct generic_mapping lsa_policy_mapping = { - LSA_POLICY_READ, - LSA_POLICY_WRITE, - LSA_POLICY_EXECUTE, - LSA_POLICY_ALL_ACCESS -}; - -const struct generic_mapping lsa_secret_mapping = { - LSA_SECRET_READ, - LSA_SECRET_WRITE, - LSA_SECRET_EXECUTE, - LSA_SECRET_ALL_ACCESS -}; - -const struct generic_mapping lsa_trusted_domain_mapping = { - LSA_TRUSTED_DOMAIN_READ, - LSA_TRUSTED_DOMAIN_WRITE, - LSA_TRUSTED_DOMAIN_EXECUTE, - LSA_TRUSTED_DOMAIN_ALL_ACCESS -}; - -/*************************************************************************** - init_lsa_ref_domain_list - adds a domain if it's not already in, returns the index. -***************************************************************************/ - -static int init_lsa_ref_domain_list(TALLOC_CTX *mem_ctx, - struct lsa_RefDomainList *ref, - const char *dom_name, - struct dom_sid *dom_sid) -{ - int num = 0; - - if (dom_name != NULL) { - for (num = 0; num < ref->count; num++) { - if (dom_sid_equal(dom_sid, ref->domains[num].sid)) { - return num; - } - } - } else { - num = ref->count; - } - - if (num >= LSA_REF_DOMAIN_LIST_MULTIPLIER) { - /* index not found, already at maximum domain limit */ - return -1; - } - - ref->count = num + 1; - ref->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER; - - ref->domains = TALLOC_REALLOC_ARRAY(mem_ctx, ref->domains, - struct lsa_DomainInfo, ref->count); - if (!ref->domains) { - return -1; - } - - ZERO_STRUCT(ref->domains[num]); - - init_lsa_StringLarge(&ref->domains[num].name, dom_name); - ref->domains[num].sid = dom_sid_dup(mem_ctx, dom_sid); - if (!ref->domains[num].sid) { - return -1; - } - - return num; -} - - -/*************************************************************************** - initialize a lsa_DomainInfo structure. - ***************************************************************************/ - -static void init_dom_query_3(struct lsa_DomainInfo *r, - const char *name, - struct dom_sid *sid) -{ - init_lsa_StringLarge(&r->name, name); - r->sid = sid; -} - -/*************************************************************************** - initialize a lsa_DomainInfo structure. - ***************************************************************************/ - -static void init_dom_query_5(struct lsa_DomainInfo *r, - const char *name, - struct dom_sid *sid) -{ - init_lsa_StringLarge(&r->name, name); - r->sid = sid; -} - -/*************************************************************************** - lookup_lsa_rids. Must be called as root for lookup_name to work. - ***************************************************************************/ - -static NTSTATUS lookup_lsa_rids(TALLOC_CTX *mem_ctx, - struct lsa_RefDomainList *ref, - struct lsa_TranslatedSid *prid, - uint32_t num_entries, - struct lsa_String *name, - int flags, - uint32_t *pmapped_count) -{ - uint32 mapped_count, i; - - SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS); - - mapped_count = 0; - *pmapped_count = 0; - - for (i = 0; i < num_entries; i++) { - struct dom_sid sid; - uint32 rid; - int dom_idx; - const char *full_name; - const char *domain; - enum lsa_SidType type = SID_NAME_UNKNOWN; - - /* Split name into domain and user component */ - - /* follow w2k8 behavior and return the builtin domain when no - * input has been passed in */ - - if (name[i].string) { - full_name = name[i].string; - } else { - full_name = "BUILTIN"; - } - - DEBUG(5, ("lookup_lsa_rids: looking up name %s\n", full_name)); - - /* We can ignore the result of lookup_name, it will not touch - "type" if it's not successful */ - - lookup_name(mem_ctx, full_name, flags, &domain, NULL, - &sid, &type); - - switch (type) { - case SID_NAME_USER: - case SID_NAME_DOM_GRP: - case SID_NAME_DOMAIN: - case SID_NAME_ALIAS: - case SID_NAME_WKN_GRP: - DEBUG(5, ("init_lsa_rids: %s found\n", full_name)); - /* Leave these unchanged */ - break; - default: - /* Don't hand out anything but the list above */ - DEBUG(5, ("init_lsa_rids: %s not found\n", full_name)); - type = SID_NAME_UNKNOWN; - break; - } - - rid = 0; - dom_idx = -1; - - if (type != SID_NAME_UNKNOWN) { - if (type == SID_NAME_DOMAIN) { - rid = (uint32_t)-1; - } else { - sid_split_rid(&sid, &rid); - } - dom_idx = init_lsa_ref_domain_list(mem_ctx, ref, domain, &sid); - mapped_count++; - } - - prid[i].sid_type = type; - prid[i].rid = rid; - prid[i].sid_index = dom_idx; - } - - *pmapped_count = mapped_count; - return NT_STATUS_OK; -} - -/*************************************************************************** - lookup_lsa_sids. Must be called as root for lookup_name to work. - ***************************************************************************/ - -static NTSTATUS lookup_lsa_sids(TALLOC_CTX *mem_ctx, - struct lsa_RefDomainList *ref, - struct lsa_TranslatedSid3 *trans_sids, - uint32_t num_entries, - struct lsa_String *name, - int flags, - uint32 *pmapped_count) -{ - uint32 mapped_count, i; - - SMB_ASSERT(num_entries <= MAX_LOOKUP_SIDS); - - mapped_count = 0; - *pmapped_count = 0; - - for (i = 0; i < num_entries; i++) { - struct dom_sid sid; - uint32 rid; - int dom_idx; - const char *full_name; - const char *domain; - enum lsa_SidType type = SID_NAME_UNKNOWN; - - ZERO_STRUCT(sid); - - /* Split name into domain and user component */ - - full_name = name[i].string; - if (full_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - - DEBUG(5, ("init_lsa_sids: looking up name %s\n", full_name)); - - /* We can ignore the result of lookup_name, it will not touch - "type" if it's not successful */ - - lookup_name(mem_ctx, full_name, flags, &domain, NULL, - &sid, &type); - - switch (type) { - case SID_NAME_USER: - case SID_NAME_DOM_GRP: - case SID_NAME_DOMAIN: - case SID_NAME_ALIAS: - case SID_NAME_WKN_GRP: - DEBUG(5, ("init_lsa_sids: %s found\n", full_name)); - /* Leave these unchanged */ - break; - default: - /* Don't hand out anything but the list above */ - DEBUG(5, ("init_lsa_sids: %s not found\n", full_name)); - type = SID_NAME_UNKNOWN; - break; - } - - rid = 0; - dom_idx = -1; - - if (type != SID_NAME_UNKNOWN) { - struct dom_sid domain_sid; - sid_copy(&domain_sid, &sid); - sid_split_rid(&domain_sid, &rid); - dom_idx = init_lsa_ref_domain_list(mem_ctx, ref, domain, &domain_sid); - mapped_count++; - } - - /* Initialize the lsa_TranslatedSid3 return. */ - trans_sids[i].sid_type = type; - trans_sids[i].sid = dom_sid_dup(mem_ctx, &sid); - trans_sids[i].sid_index = dom_idx; - } - - *pmapped_count = mapped_count; - return NT_STATUS_OK; -} - -static NTSTATUS make_lsa_object_sd(TALLOC_CTX *mem_ctx, struct security_descriptor **sd, size_t *sd_size, - const struct generic_mapping *map, - struct dom_sid *sid, uint32_t sid_access) -{ - struct dom_sid adm_sid; - struct security_ace ace[5]; - size_t i = 0; - - struct security_acl *psa = NULL; - - /* READ|EXECUTE access for Everyone */ - - init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, - map->generic_execute | map->generic_read, 0); - - /* Add Full Access 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ - - init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, - SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); - init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, - SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); - - /* Add Full Access for Domain Admins */ - sid_compose(&adm_sid, get_global_sam_sid(), DOMAIN_RID_ADMINS); - init_sec_ace(&ace[i++], &adm_sid, SEC_ACE_TYPE_ACCESS_ALLOWED, - map->generic_all, 0); - - /* If we have a sid, give it some special access */ - - if (sid) { - init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, - sid_access, 0); - } - - if((psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, i, ace)) == NULL) - return NT_STATUS_NO_MEMORY; - - if((*sd = make_sec_desc(mem_ctx, SECURITY_DESCRIPTOR_REVISION_1, - SEC_DESC_SELF_RELATIVE, &adm_sid, NULL, NULL, - psa, sd_size)) == NULL) - return NT_STATUS_NO_MEMORY; - - return NT_STATUS_OK; -} - - -/*************************************************************************** - _lsa_OpenPolicy2 - ***************************************************************************/ - -NTSTATUS _lsa_OpenPolicy2(struct pipes_struct *p, - struct lsa_OpenPolicy2 *r) -{ - struct lsa_info *info; - struct security_descriptor *psd = NULL; - size_t sd_size; - uint32 des_access = r->in.access_mask; - uint32 acc_granted; - NTSTATUS status; - - /* Work out max allowed. */ - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - /* map the generic bits to the lsa policy ones */ - se_map_generic(&des_access, &lsa_policy_mapping); - - /* get the generic lsa policy SD until we store it */ - status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, &lsa_policy_mapping, - NULL, 0); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, des_access, - &acc_granted, "_lsa_OpenPolicy2" ); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* associate the domain SID with the (unique) handle. */ - info = TALLOC_ZERO_P(p->mem_ctx, struct lsa_info); - if (info == NULL) { - return NT_STATUS_NO_MEMORY; - } - - sid_copy(&info->sid,get_global_sam_sid()); - info->access = acc_granted; - info->type = LSA_HANDLE_POLICY_TYPE; - - /* set up the LSA QUERY INFO response */ - if (!create_policy_hnd(p, r->out.handle, info)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_OpenPolicy - ***************************************************************************/ - -NTSTATUS _lsa_OpenPolicy(struct pipes_struct *p, - struct lsa_OpenPolicy *r) -{ - struct lsa_OpenPolicy2 o; - - o.in.system_name = NULL; /* should be ignored */ - o.in.attr = r->in.attr; - o.in.access_mask = r->in.access_mask; - - o.out.handle = r->out.handle; - - return _lsa_OpenPolicy2(p, &o); -} - -/*************************************************************************** - _lsa_EnumTrustDom - this needs fixing to do more than return NULL ! JRA. - ufff, done :) mimir - ***************************************************************************/ - -NTSTATUS _lsa_EnumTrustDom(struct pipes_struct *p, - struct lsa_EnumTrustDom *r) -{ - struct lsa_info *info; - uint32_t count; - struct trustdom_info **domains; - struct lsa_DomainInfo *entries; - int i; - NTSTATUS nt_status; - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights */ - if (!(info->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) - return NT_STATUS_ACCESS_DENIED; - - become_root(); - nt_status = pdb_enum_trusteddoms(p->mem_ctx, &count, &domains); - unbecome_root(); - - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - entries = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_DomainInfo, count); - if (!entries) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0; iname); - entries[i].sid = &domains[i]->sid; - } - - if (*r->in.resume_handle >= count) { - *r->out.resume_handle = -1; - TALLOC_FREE(entries); - return NT_STATUS_NO_MORE_ENTRIES; - } - - /* return the rest, limit by max_size. Note that we - use the w2k3 element size value of 60 */ - r->out.domains->count = count - *r->in.resume_handle; - r->out.domains->count = MIN(r->out.domains->count, - 1+(r->in.max_size/LSA_ENUM_TRUST_DOMAIN_MULTIPLIER)); - - r->out.domains->domains = entries + *r->in.resume_handle; - - if (r->out.domains->count < count - *r->in.resume_handle) { - *r->out.resume_handle = *r->in.resume_handle + r->out.domains->count; - return STATUS_MORE_ENTRIES; - } - - /* according to MS-LSAD 3.1.4.7.8 output resume handle MUST - * always be larger than the previous input resume handle, in - * particular when hitting the last query it is vital to set the - * resume handle correctly to avoid infinite client loops, as - * seen e.g. with Windows XP SP3 when resume handle is 0 and - * status is NT_STATUS_OK - gd */ - - *r->out.resume_handle = (uint32_t)-1; - - return NT_STATUS_OK; -} - -#define LSA_AUDIT_NUM_CATEGORIES_NT4 7 -#define LSA_AUDIT_NUM_CATEGORIES_WIN2K 9 -#define LSA_AUDIT_NUM_CATEGORIES LSA_AUDIT_NUM_CATEGORIES_NT4 - -/*************************************************************************** - _lsa_QueryInfoPolicy - ***************************************************************************/ - -NTSTATUS _lsa_QueryInfoPolicy(struct pipes_struct *p, - struct lsa_QueryInfoPolicy *r) -{ - NTSTATUS status = NT_STATUS_OK; - struct lsa_info *handle; - struct dom_sid domain_sid; - const char *name; - struct dom_sid *sid = NULL; - union lsa_PolicyInformation *info = NULL; - uint32_t acc_required = 0; - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) - return NT_STATUS_INVALID_HANDLE; - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - switch (r->in.level) { - case LSA_POLICY_INFO_AUDIT_LOG: - case LSA_POLICY_INFO_AUDIT_EVENTS: - acc_required = LSA_POLICY_VIEW_AUDIT_INFORMATION; - break; - case LSA_POLICY_INFO_DOMAIN: - acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; - break; - case LSA_POLICY_INFO_PD: - acc_required = LSA_POLICY_GET_PRIVATE_INFORMATION; - break; - case LSA_POLICY_INFO_ACCOUNT_DOMAIN: - acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; - break; - case LSA_POLICY_INFO_ROLE: - case LSA_POLICY_INFO_REPLICA: - acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; - break; - case LSA_POLICY_INFO_QUOTA: - acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; - break; - case LSA_POLICY_INFO_MOD: - case LSA_POLICY_INFO_AUDIT_FULL_SET: - /* according to MS-LSAD 3.1.4.4.3 */ - return NT_STATUS_INVALID_PARAMETER; - case LSA_POLICY_INFO_AUDIT_FULL_QUERY: - acc_required = LSA_POLICY_VIEW_AUDIT_INFORMATION; - break; - case LSA_POLICY_INFO_DNS: - case LSA_POLICY_INFO_DNS_INT: - case LSA_POLICY_INFO_L_ACCOUNT_DOMAIN: - acc_required = LSA_POLICY_VIEW_LOCAL_INFORMATION; - break; - default: - break; - } - - if (!(handle->access & acc_required)) { - /* return NT_STATUS_ACCESS_DENIED; */ - } - - info = TALLOC_ZERO_P(p->mem_ctx, union lsa_PolicyInformation); - if (!info) { - return NT_STATUS_NO_MEMORY; - } - - switch (r->in.level) { - /* according to MS-LSAD 3.1.4.4.3 */ - case LSA_POLICY_INFO_MOD: - case LSA_POLICY_INFO_AUDIT_FULL_SET: - case LSA_POLICY_INFO_AUDIT_FULL_QUERY: - return NT_STATUS_INVALID_PARAMETER; - case LSA_POLICY_INFO_AUDIT_LOG: - info->audit_log.percent_full = 0; - info->audit_log.maximum_log_size = 0; - info->audit_log.retention_time = 0; - info->audit_log.shutdown_in_progress = 0; - info->audit_log.time_to_shutdown = 0; - info->audit_log.next_audit_record = 0; - status = NT_STATUS_OK; - break; - case LSA_POLICY_INFO_PD: - info->pd.name.string = NULL; - status = NT_STATUS_OK; - break; - case LSA_POLICY_INFO_REPLICA: - info->replica.source.string = NULL; - info->replica.account.string = NULL; - status = NT_STATUS_OK; - break; - case LSA_POLICY_INFO_QUOTA: - info->quota.paged_pool = 0; - info->quota.non_paged_pool = 0; - info->quota.min_wss = 0; - info->quota.max_wss = 0; - info->quota.pagefile = 0; - info->quota.unknown = 0; - status = NT_STATUS_OK; - break; - case LSA_POLICY_INFO_AUDIT_EVENTS: - { - - uint32 policy_def = LSA_AUDIT_POLICY_ALL; - - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_VIEW_AUDIT_INFORMATION)) { - DEBUG(10,("_lsa_QueryInfoPolicy: insufficient access rights\n")); - return NT_STATUS_ACCESS_DENIED; - } - - /* fake info: We audit everything. ;) */ - - info->audit_events.auditing_mode = true; - info->audit_events.count = LSA_AUDIT_NUM_CATEGORIES; - info->audit_events.settings = TALLOC_ZERO_ARRAY(p->mem_ctx, - enum lsa_PolicyAuditPolicy, - info->audit_events.count); - if (!info->audit_events.settings) { - return NT_STATUS_NO_MEMORY; - } - - info->audit_events.settings[LSA_AUDIT_CATEGORY_ACCOUNT_MANAGEMENT] = policy_def; - info->audit_events.settings[LSA_AUDIT_CATEGORY_FILE_AND_OBJECT_ACCESS] = policy_def; - info->audit_events.settings[LSA_AUDIT_CATEGORY_LOGON] = policy_def; - info->audit_events.settings[LSA_AUDIT_CATEGORY_PROCCESS_TRACKING] = policy_def; - info->audit_events.settings[LSA_AUDIT_CATEGORY_SECURITY_POLICY_CHANGES] = policy_def; - info->audit_events.settings[LSA_AUDIT_CATEGORY_SYSTEM] = policy_def; - info->audit_events.settings[LSA_AUDIT_CATEGORY_USE_OF_USER_RIGHTS] = policy_def; - - break; - } - case LSA_POLICY_INFO_DOMAIN: - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) - return NT_STATUS_ACCESS_DENIED; - - /* Request PolicyPrimaryDomainInformation. */ - switch (lp_server_role()) { - case ROLE_DOMAIN_PDC: - case ROLE_DOMAIN_BDC: - name = get_global_sam_name(); - sid = dom_sid_dup(p->mem_ctx, get_global_sam_sid()); - if (!sid) { - return NT_STATUS_NO_MEMORY; - } - break; - case ROLE_DOMAIN_MEMBER: - name = lp_workgroup(); - /* We need to return the Domain SID here. */ - if (secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { - sid = dom_sid_dup(p->mem_ctx, &domain_sid); - if (!sid) { - return NT_STATUS_NO_MEMORY; - } - } else { - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - break; - case ROLE_STANDALONE: - name = lp_workgroup(); - sid = NULL; - break; - default: - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - init_dom_query_3(&info->domain, name, sid); - break; - case LSA_POLICY_INFO_ACCOUNT_DOMAIN: - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) - return NT_STATUS_ACCESS_DENIED; - - /* Request PolicyAccountDomainInformation. */ - name = get_global_sam_name(); - sid = get_global_sam_sid(); - - init_dom_query_5(&info->account_domain, name, sid); - break; - case LSA_POLICY_INFO_ROLE: - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) - return NT_STATUS_ACCESS_DENIED; - - switch (lp_server_role()) { - case ROLE_DOMAIN_BDC: - /* - * only a BDC is a backup controller - * of the domain, it controls. - */ - info->role.role = LSA_ROLE_BACKUP; - break; - default: - /* - * any other role is a primary - * of the domain, it controls. - */ - info->role.role = LSA_ROLE_PRIMARY; - break; - } - break; - case LSA_POLICY_INFO_DNS: - case LSA_POLICY_INFO_DNS_INT: { - struct pdb_domain_info *dominfo; - - if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { - DEBUG(10, ("Not replying to LSA_POLICY_INFO_DNS " - "without ADS passdb backend\n")); - status = NT_STATUS_INVALID_INFO_CLASS; - break; - } - - dominfo = pdb_get_domain_info(info); - if (dominfo == NULL) { - status = NT_STATUS_NO_MEMORY; - break; - } - - init_lsa_StringLarge(&info->dns.name, - dominfo->name); - init_lsa_StringLarge(&info->dns.dns_domain, - dominfo->dns_domain); - init_lsa_StringLarge(&info->dns.dns_forest, - dominfo->dns_forest); - info->dns.domain_guid = dominfo->guid; - info->dns.sid = &dominfo->sid; - break; - } - default: - DEBUG(0,("_lsa_QueryInfoPolicy: unknown info level in Lsa Query: %d\n", - r->in.level)); - status = NT_STATUS_INVALID_INFO_CLASS; - break; - } - - *r->out.info = info; - - return status; -} - -/*************************************************************************** - _lsa_QueryInfoPolicy2 - ***************************************************************************/ - -NTSTATUS _lsa_QueryInfoPolicy2(struct pipes_struct *p, - struct lsa_QueryInfoPolicy2 *r2) -{ - struct lsa_QueryInfoPolicy r; - - if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; - } - - ZERO_STRUCT(r); - r.in.handle = r2->in.handle; - r.in.level = r2->in.level; - r.out.info = r2->out.info; - - return _lsa_QueryInfoPolicy(p, &r); -} - -/*************************************************************************** - _lsa_lookup_sids_internal - ***************************************************************************/ - -static NTSTATUS _lsa_lookup_sids_internal(struct pipes_struct *p, - TALLOC_CTX *mem_ctx, - uint16_t level, /* input */ - int num_sids, /* input */ - struct lsa_SidPtr *sid, /* input */ - struct lsa_RefDomainList **pp_ref, /* input/output */ - struct lsa_TranslatedName2 **pp_names,/* input/output */ - uint32_t *pp_mapped_count) /* input/output */ -{ - NTSTATUS status; - int i; - const struct dom_sid **sids = NULL; - struct lsa_RefDomainList *ref = NULL; - uint32 mapped_count = 0; - struct lsa_dom_info *dom_infos = NULL; - struct lsa_name_info *name_infos = NULL; - struct lsa_TranslatedName2 *names = NULL; - - *pp_mapped_count = 0; - *pp_names = NULL; - *pp_ref = NULL; - - if (num_sids == 0) { - return NT_STATUS_OK; - } - - sids = TALLOC_ARRAY(p->mem_ctx, const struct dom_sid *, num_sids); - ref = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList); - - if (sids == NULL || ref == NULL) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0; imem_ctx, num_sids, sids, level, - &dom_infos, &name_infos); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - names = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedName2, num_sids); - if (names == NULL) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0; itype == SID_NAME_UNKNOWN) { - fstring tmp; - name->dom_idx = -1; - /* Unknown sids should return the string - * representation of the SID. Windows 2003 behaves - * rather erratic here, in many cases it returns the - * RID as 8 bytes hex, in others it returns the full - * SID. We (Jerry/VL) could not figure out which the - * hard cases are, so leave it with the SID. */ - name->name = talloc_asprintf(p->mem_ctx, "%s", - sid_to_fstring(tmp, - sids[i])); - if (name->name == NULL) { - return NT_STATUS_NO_MEMORY; - } - } else { - mapped_count += 1; - } - - names[i].sid_type = name->type; - names[i].name.string = name->name; - names[i].sid_index = name->dom_idx; - names[i].unknown = 0; - } - - status = NT_STATUS_NONE_MAPPED; - if (mapped_count > 0) { - status = (mapped_count < num_sids) ? - STATUS_SOME_UNMAPPED : NT_STATUS_OK; - } - - DEBUG(10, ("num_sids %d, mapped_count %d, status %s\n", - num_sids, mapped_count, nt_errstr(status))); - - *pp_mapped_count = mapped_count; - *pp_names = names; - *pp_ref = ref; - - return status; -} - -/*************************************************************************** - _lsa_LookupSids - ***************************************************************************/ - -NTSTATUS _lsa_LookupSids(struct pipes_struct *p, - struct lsa_LookupSids *r) -{ - NTSTATUS status; - struct lsa_info *handle; - int num_sids = r->in.sids->num_sids; - uint32 mapped_count = 0; - struct lsa_RefDomainList *domains = NULL; - struct lsa_TranslatedName *names_out = NULL; - struct lsa_TranslatedName2 *names = NULL; - int i; - - if ((r->in.level < 1) || (r->in.level > 6)) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { - return NT_STATUS_INVALID_HANDLE; - } - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (num_sids > MAX_LOOKUP_SIDS) { - DEBUG(5,("_lsa_LookupSids: limit of %d exceeded, requested %d\n", - MAX_LOOKUP_SIDS, num_sids)); - return NT_STATUS_NONE_MAPPED; - } - - status = _lsa_lookup_sids_internal(p, - p->mem_ctx, - r->in.level, - num_sids, - r->in.sids->sids, - &domains, - &names, - &mapped_count); - - /* Only return here when there is a real error. - NT_STATUS_NONE_MAPPED is a special case as it indicates that none of - the requested sids could be resolved. Older versions of XP (pre SP3) - rely that we return with the string representations of those SIDs in - that case. If we don't, XP crashes - Guenther - */ - - if (NT_STATUS_IS_ERR(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { - return status; - } - - /* Convert from lsa_TranslatedName2 to lsa_TranslatedName */ - names_out = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedName, - num_sids); - if (!names_out) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0; iout.domains = domains; - r->out.names->count = num_sids; - r->out.names->names = names_out; - *r->out.count = mapped_count; - - return status; -} - -/*************************************************************************** - _lsa_LookupSids2 - ***************************************************************************/ - -NTSTATUS _lsa_LookupSids2(struct pipes_struct *p, - struct lsa_LookupSids2 *r) -{ - NTSTATUS status; - struct lsa_info *handle; - int num_sids = r->in.sids->num_sids; - uint32 mapped_count = 0; - struct lsa_RefDomainList *domains = NULL; - struct lsa_TranslatedName2 *names = NULL; - bool check_policy = true; - - switch (p->opnum) { - case NDR_LSA_LOOKUPSIDS3: - check_policy = false; - break; - case NDR_LSA_LOOKUPSIDS2: - default: - check_policy = true; - } - - if ((r->in.level < 1) || (r->in.level > 6)) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (check_policy) { - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { - return NT_STATUS_INVALID_HANDLE; - } - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { - return NT_STATUS_ACCESS_DENIED; - } - } - - if (num_sids > MAX_LOOKUP_SIDS) { - DEBUG(5,("_lsa_LookupSids2: limit of %d exceeded, requested %d\n", - MAX_LOOKUP_SIDS, num_sids)); - return NT_STATUS_NONE_MAPPED; - } - - status = _lsa_lookup_sids_internal(p, - p->mem_ctx, - r->in.level, - num_sids, - r->in.sids->sids, - &domains, - &names, - &mapped_count); - - *r->out.domains = domains; - r->out.names->count = num_sids; - r->out.names->names = names; - *r->out.count = mapped_count; - - return status; -} - -/*************************************************************************** - _lsa_LookupSids3 - ***************************************************************************/ - -NTSTATUS _lsa_LookupSids3(struct pipes_struct *p, - struct lsa_LookupSids3 *r) -{ - struct lsa_LookupSids2 q; - - /* No policy handle on this call. Restrict to crypto connections. */ - if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0,("_lsa_LookupSids3: client %s not using schannel for netlogon\n", - get_remote_machine_name() )); - return NT_STATUS_INVALID_PARAMETER; - } - - q.in.handle = NULL; - q.in.sids = r->in.sids; - q.in.level = r->in.level; - q.in.lookup_options = r->in.lookup_options; - q.in.client_revision = r->in.client_revision; - q.in.names = r->in.names; - q.in.count = r->in.count; - - q.out.domains = r->out.domains; - q.out.names = r->out.names; - q.out.count = r->out.count; - - return _lsa_LookupSids2(p, &q); -} - -/*************************************************************************** - ***************************************************************************/ - -static int lsa_lookup_level_to_flags(enum lsa_LookupNamesLevel level) -{ - int flags; - - switch (level) { - case LSA_LOOKUP_NAMES_ALL: /* 1 */ - flags = LOOKUP_NAME_ALL; - break; - case LSA_LOOKUP_NAMES_DOMAINS_ONLY: /* 2 */ - flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_REMOTE|LOOKUP_NAME_ISOLATED; - break; - case LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY: /* 3 */ - flags = LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED; - break; - case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY: /* 4 */ - case LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY: /* 5 */ - case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2: /* 6 */ - case LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC: /* 7 */ - default: - flags = LOOKUP_NAME_NONE; - break; - } - - return flags; -} - -/*************************************************************************** - _lsa_LookupNames - ***************************************************************************/ - -NTSTATUS _lsa_LookupNames(struct pipes_struct *p, - struct lsa_LookupNames *r) -{ - NTSTATUS status = NT_STATUS_NONE_MAPPED; - struct lsa_info *handle; - struct lsa_String *names = r->in.names; - uint32 num_entries = r->in.num_names; - struct lsa_RefDomainList *domains = NULL; - struct lsa_TranslatedSid *rids = NULL; - uint32 mapped_count = 0; - int flags = 0; - - if (num_entries > MAX_LOOKUP_SIDS) { - num_entries = MAX_LOOKUP_SIDS; - DEBUG(5,("_lsa_LookupNames: truncating name lookup list to %d\n", - num_entries)); - } - - flags = lsa_lookup_level_to_flags(r->in.level); - - domains = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList); - if (!domains) { - return NT_STATUS_NO_MEMORY; - } - - if (num_entries) { - rids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_TranslatedSid, - num_entries); - if (!rids) { - return NT_STATUS_NO_MEMORY; - } - } else { - rids = NULL; - } - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { - status = NT_STATUS_INVALID_HANDLE; - goto done; - } - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - - /* set up the LSA Lookup RIDs response */ - become_root(); /* lookup_name can require root privs */ - status = lookup_lsa_rids(p->mem_ctx, domains, rids, num_entries, - names, flags, &mapped_count); - unbecome_root(); - -done: - - if (NT_STATUS_IS_OK(status) && (num_entries != 0) ) { - if (mapped_count == 0) { - status = NT_STATUS_NONE_MAPPED; - } else if (mapped_count != num_entries) { - status = STATUS_SOME_UNMAPPED; - } - } - - *r->out.count = mapped_count; - *r->out.domains = domains; - r->out.sids->sids = rids; - r->out.sids->count = num_entries; - - return status; -} - -/*************************************************************************** - _lsa_LookupNames2 - ***************************************************************************/ - -NTSTATUS _lsa_LookupNames2(struct pipes_struct *p, - struct lsa_LookupNames2 *r) -{ - NTSTATUS status; - struct lsa_LookupNames q; - struct lsa_TransSidArray2 *sid_array2 = r->in.sids; - struct lsa_TransSidArray *sid_array = NULL; - uint32_t i; - - sid_array = TALLOC_ZERO_P(p->mem_ctx, struct lsa_TransSidArray); - if (!sid_array) { - return NT_STATUS_NO_MEMORY; - } - - q.in.handle = r->in.handle; - q.in.num_names = r->in.num_names; - q.in.names = r->in.names; - q.in.level = r->in.level; - q.in.sids = sid_array; - q.in.count = r->in.count; - /* we do not know what this is for */ - /* = r->in.unknown1; */ - /* = r->in.unknown2; */ - - q.out.domains = r->out.domains; - q.out.sids = sid_array; - q.out.count = r->out.count; - - status = _lsa_LookupNames(p, &q); - - sid_array2->count = sid_array->count; - sid_array2->sids = TALLOC_ARRAY(p->mem_ctx, struct lsa_TranslatedSid2, sid_array->count); - if (!sid_array2->sids) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0; icount; i++) { - sid_array2->sids[i].sid_type = sid_array->sids[i].sid_type; - sid_array2->sids[i].rid = sid_array->sids[i].rid; - sid_array2->sids[i].sid_index = sid_array->sids[i].sid_index; - sid_array2->sids[i].unknown = 0; - } - - r->out.sids = sid_array2; - - return status; -} - -/*************************************************************************** - _lsa_LookupNames3 - ***************************************************************************/ - -NTSTATUS _lsa_LookupNames3(struct pipes_struct *p, - struct lsa_LookupNames3 *r) -{ - NTSTATUS status; - struct lsa_info *handle; - struct lsa_String *names = r->in.names; - uint32 num_entries = r->in.num_names; - struct lsa_RefDomainList *domains = NULL; - struct lsa_TranslatedSid3 *trans_sids = NULL; - uint32 mapped_count = 0; - int flags = 0; - bool check_policy = true; - - switch (p->opnum) { - case NDR_LSA_LOOKUPNAMES4: - check_policy = false; - break; - case NDR_LSA_LOOKUPNAMES3: - default: - check_policy = true; - } - - if (num_entries > MAX_LOOKUP_SIDS) { - num_entries = MAX_LOOKUP_SIDS; - DEBUG(5,("_lsa_LookupNames3: truncating name lookup list to %d\n", num_entries)); - } - - /* Probably the lookup_level is some sort of bitmask. */ - if (r->in.level == 1) { - flags = LOOKUP_NAME_ALL; - } - - domains = TALLOC_ZERO_P(p->mem_ctx, struct lsa_RefDomainList); - if (!domains) { - return NT_STATUS_NO_MEMORY; - } - - if (num_entries) { - trans_sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_TranslatedSid3, - num_entries); - if (!trans_sids) { - return NT_STATUS_NO_MEMORY; - } - } else { - trans_sids = NULL; - } - - if (check_policy) { - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) { - status = NT_STATUS_INVALID_HANDLE; - goto done; - } - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights */ - if (!(handle->access & LSA_POLICY_LOOKUP_NAMES)) { - status = NT_STATUS_ACCESS_DENIED; - goto done; - } - } - - /* set up the LSA Lookup SIDs response */ - become_root(); /* lookup_name can require root privs */ - status = lookup_lsa_sids(p->mem_ctx, domains, trans_sids, num_entries, - names, flags, &mapped_count); - unbecome_root(); - -done: - - if (NT_STATUS_IS_OK(status)) { - if (mapped_count == 0) { - status = NT_STATUS_NONE_MAPPED; - } else if (mapped_count != num_entries) { - status = STATUS_SOME_UNMAPPED; - } - } - - *r->out.count = mapped_count; - *r->out.domains = domains; - r->out.sids->sids = trans_sids; - r->out.sids->count = num_entries; - - return status; -} - -/*************************************************************************** - _lsa_LookupNames4 - ***************************************************************************/ - -NTSTATUS _lsa_LookupNames4(struct pipes_struct *p, - struct lsa_LookupNames4 *r) -{ - struct lsa_LookupNames3 q; - - /* No policy handle on this call. Restrict to crypto connections. */ - if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0,("_lsa_lookup_names4: client %s not using schannel for netlogon\n", - get_remote_machine_name() )); - return NT_STATUS_INVALID_PARAMETER; - } - - q.in.handle = NULL; - q.in.num_names = r->in.num_names; - q.in.names = r->in.names; - q.in.level = r->in.level; - q.in.lookup_options = r->in.lookup_options; - q.in.client_revision = r->in.client_revision; - q.in.sids = r->in.sids; - q.in.count = r->in.count; - - q.out.domains = r->out.domains; - q.out.sids = r->out.sids; - q.out.count = r->out.count; - - return _lsa_LookupNames3(p, &q); -} - -/*************************************************************************** - _lsa_close. Also weird - needs to check if lsa handle is correct. JRA. - ***************************************************************************/ - -NTSTATUS _lsa_Close(struct pipes_struct *p, struct lsa_Close *r) -{ - if (!find_policy_by_hnd(p, r->in.handle, NULL)) { - return NT_STATUS_INVALID_HANDLE; - } - - close_policy_hnd(p, r->in.handle); - ZERO_STRUCTP(r->out.handle); - return NT_STATUS_OK; -} - -/*************************************************************************** - ***************************************************************************/ - -NTSTATUS _lsa_OpenSecret(struct pipes_struct *p, struct lsa_OpenSecret *r) -{ - return NT_STATUS_OBJECT_NAME_NOT_FOUND; -} - -/*************************************************************************** - ***************************************************************************/ - -NTSTATUS _lsa_OpenTrustedDomain(struct pipes_struct *p, - struct lsa_OpenTrustedDomain *r) -{ - return NT_STATUS_OBJECT_NAME_NOT_FOUND; -} - -/*************************************************************************** - ***************************************************************************/ - -NTSTATUS _lsa_CreateTrustedDomain(struct pipes_struct *p, - struct lsa_CreateTrustedDomain *r) -{ - return NT_STATUS_ACCESS_DENIED; -} - -/*************************************************************************** - ***************************************************************************/ - -NTSTATUS _lsa_CreateSecret(struct pipes_struct *p, struct lsa_CreateSecret *r) -{ - return NT_STATUS_ACCESS_DENIED; -} - -/*************************************************************************** - ***************************************************************************/ - -NTSTATUS _lsa_SetSecret(struct pipes_struct *p, struct lsa_SetSecret *r) -{ - return NT_STATUS_ACCESS_DENIED; -} - -/*************************************************************************** - _lsa_DeleteObject - ***************************************************************************/ - -NTSTATUS _lsa_DeleteObject(struct pipes_struct *p, - struct lsa_DeleteObject *r) -{ - NTSTATUS status; - struct lsa_info *info = NULL; - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & SEC_STD_DELETE)) { - return NT_STATUS_ACCESS_DENIED; - } - - switch (info->type) { - case LSA_HANDLE_ACCOUNT_TYPE: - status = privilege_delete_account(&info->sid); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("_lsa_DeleteObject: privilege_delete_account gave: %s\n", - nt_errstr(status))); - return status; - } - break; - default: - return NT_STATUS_INVALID_HANDLE; - } - - close_policy_hnd(p, r->in.handle); - ZERO_STRUCTP(r->out.handle); - - return status; -} - -/*************************************************************************** - _lsa_EnumPrivs - ***************************************************************************/ - -NTSTATUS _lsa_EnumPrivs(struct pipes_struct *p, - struct lsa_EnumPrivs *r) -{ - struct lsa_info *handle; - uint32 i; - uint32 enum_context = *r->in.resume_handle; - int num_privs = num_privileges_in_short_list(); - struct lsa_PrivEntry *entries = NULL; - - /* remember that the enum_context starts at 0 and not 1 */ - - if ( enum_context >= num_privs ) - return NT_STATUS_NO_MORE_ENTRIES; - - DEBUG(10,("_lsa_EnumPrivs: enum_context:%d total entries:%d\n", - enum_context, num_privs)); - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) - return NT_STATUS_INVALID_HANDLE; - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights - I don't know if it's the right one. not documented. */ - - if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) - return NT_STATUS_ACCESS_DENIED; - - if (num_privs) { - entries = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_PrivEntry, num_privs); - if (!entries) { - return NT_STATUS_NO_MEMORY; - } - } else { - entries = NULL; - } - - for (i = 0; i < num_privs; i++) { - if( i < enum_context) { - - init_lsa_StringLarge(&entries[i].name, NULL); - - entries[i].luid.low = 0; - entries[i].luid.high = 0; - } else { - - init_lsa_StringLarge(&entries[i].name, sec_privilege_name_from_index(i)); - - entries[i].luid.low = sec_privilege_from_index(i); - entries[i].luid.high = 0; - } - } - - enum_context = num_privs; - - *r->out.resume_handle = enum_context; - r->out.privs->count = num_privs; - r->out.privs->privs = entries; - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_LookupPrivDisplayName - ***************************************************************************/ - -NTSTATUS _lsa_LookupPrivDisplayName(struct pipes_struct *p, - struct lsa_LookupPrivDisplayName *r) -{ - struct lsa_info *handle; - const char *description; - struct lsa_StringLarge *lsa_name; - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) - return NT_STATUS_INVALID_HANDLE; - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights */ - - /* - * I don't know if it's the right one. not documented. - */ - if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) - return NT_STATUS_ACCESS_DENIED; - - DEBUG(10,("_lsa_LookupPrivDisplayName: name = %s\n", r->in.name->string)); - - description = get_privilege_dispname(r->in.name->string); - if (!description) { - DEBUG(10,("_lsa_LookupPrivDisplayName: doesn't exist\n")); - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - DEBUG(10,("_lsa_LookupPrivDisplayName: display name = %s\n", description)); - - lsa_name = TALLOC_ZERO_P(p->mem_ctx, struct lsa_StringLarge); - if (!lsa_name) { - return NT_STATUS_NO_MEMORY; - } - - init_lsa_StringLarge(lsa_name, description); - - *r->out.returned_language_id = r->in.language_id; - *r->out.disp_name = lsa_name; - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_EnumAccounts - ***************************************************************************/ - -NTSTATUS _lsa_EnumAccounts(struct pipes_struct *p, - struct lsa_EnumAccounts *r) -{ - struct lsa_info *handle; - struct dom_sid *sid_list; - int i, j, num_entries; - NTSTATUS status; - struct lsa_SidPtr *sids = NULL; - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) - return NT_STATUS_INVALID_HANDLE; - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(handle->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) - return NT_STATUS_ACCESS_DENIED; - - sid_list = NULL; - num_entries = 0; - - /* The only way we can currently find out all the SIDs that have been - privileged is to scan all privileges */ - - status = privilege_enumerate_accounts(&sid_list, &num_entries); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (*r->in.resume_handle >= num_entries) { - return NT_STATUS_NO_MORE_ENTRIES; - } - - if (num_entries - *r->in.resume_handle) { - sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr, - num_entries - *r->in.resume_handle); - if (!sids) { - talloc_free(sid_list); - return NT_STATUS_NO_MEMORY; - } - - for (i = *r->in.resume_handle, j = 0; i < num_entries; i++, j++) { - sids[j].sid = dom_sid_dup(p->mem_ctx, &sid_list[i]); - if (!sids[j].sid) { - talloc_free(sid_list); - return NT_STATUS_NO_MEMORY; - } - } - } - - talloc_free(sid_list); - - *r->out.resume_handle = num_entries; - r->out.sids->num_sids = num_entries; - r->out.sids->sids = sids; - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_GetUserName - ***************************************************************************/ - -NTSTATUS _lsa_GetUserName(struct pipes_struct *p, - struct lsa_GetUserName *r) -{ - const char *username, *domname; - struct lsa_String *account_name = NULL; - struct lsa_String *authority_name = NULL; - - if (r->in.account_name && - *r->in.account_name) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (r->in.authority_name && - *r->in.authority_name) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (p->server_info->guest) { - /* - * I'm 99% sure this is not the right place to do this, - * global_sid_Anonymous should probably be put into the token - * instead of the guest id -- vl - */ - if (!lookup_sid(p->mem_ctx, &global_sid_Anonymous, - &domname, &username, NULL)) { - return NT_STATUS_NO_MEMORY; - } - } else { - username = p->server_info->sanitized_username; - domname = p->server_info->info3->base.domain.string; - } - - account_name = TALLOC_P(p->mem_ctx, struct lsa_String); - if (!account_name) { - return NT_STATUS_NO_MEMORY; - } - init_lsa_String(account_name, username); - - if (r->out.authority_name) { - authority_name = TALLOC_P(p->mem_ctx, struct lsa_String); - if (!authority_name) { - return NT_STATUS_NO_MEMORY; - } - init_lsa_String(authority_name, domname); - } - - *r->out.account_name = account_name; - if (r->out.authority_name) { - *r->out.authority_name = authority_name; - } - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_CreateAccount - ***************************************************************************/ - -NTSTATUS _lsa_CreateAccount(struct pipes_struct *p, - struct lsa_CreateAccount *r) -{ - NTSTATUS status; - struct lsa_info *handle; - struct lsa_info *info; - uint32_t acc_granted; - struct security_descriptor *psd; - size_t sd_size; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) - return NT_STATUS_INVALID_HANDLE; - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* check if the user has enough rights */ - - if (!(handle->access & LSA_POLICY_CREATE_ACCOUNT)) { - return NT_STATUS_ACCESS_DENIED; - } - - /* Work out max allowed. */ - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &r->in.access_mask); - - /* map the generic bits to the lsa policy ones */ - se_map_generic(&r->in.access_mask, &lsa_account_mapping); - - status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, - &lsa_account_mapping, - r->in.sid, LSA_POLICY_ALL_ACCESS); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, r->in.access_mask, - &acc_granted, "_lsa_CreateAccount"); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if ( is_privileged_sid( r->in.sid ) ) - return NT_STATUS_OBJECT_NAME_COLLISION; - - /* associate the user/group SID with the (unique) handle. */ - - info = TALLOC_ZERO_P(p->mem_ctx, struct lsa_info); - if (info == NULL) { - return NT_STATUS_NO_MEMORY; - } - - info->sid = *r->in.sid; - info->access = acc_granted; - info->type = LSA_HANDLE_ACCOUNT_TYPE; - - /* get a (unique) handle. open a policy on it. */ - if (!create_policy_hnd(p, r->out.acct_handle, info)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - - return privilege_create_account( &info->sid ); -} - -/*************************************************************************** - _lsa_OpenAccount - ***************************************************************************/ - -NTSTATUS _lsa_OpenAccount(struct pipes_struct *p, - struct lsa_OpenAccount *r) -{ - struct lsa_info *handle; - struct lsa_info *info; - struct security_descriptor *psd = NULL; - size_t sd_size; - uint32_t des_access = r->in.access_mask; - uint32_t acc_granted; - NTSTATUS status; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) - return NT_STATUS_INVALID_HANDLE; - - if (handle->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* des_access is for the account here, not the policy - * handle - so don't check against policy handle. */ - - /* Work out max allowed. */ - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - /* map the generic bits to the lsa account ones */ - se_map_generic(&des_access, &lsa_account_mapping); - - /* get the generic lsa account SD until we store it */ - status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, - &lsa_account_mapping, - r->in.sid, LSA_ACCOUNT_ALL_ACCESS); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, des_access, - &acc_granted, "_lsa_OpenAccount" ); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* TODO: Fis the parsing routine before reenabling this check! */ - #if 0 - if (!lookup_sid(&handle->sid, dom_name, name, &type)) - return NT_STATUS_ACCESS_DENIED; - #endif - /* associate the user/group SID with the (unique) handle. */ - info = TALLOC_ZERO_P(p->mem_ctx, struct lsa_info); - if (info == NULL) { - return NT_STATUS_NO_MEMORY; - } - - info->sid = *r->in.sid; - info->access = acc_granted; - info->type = LSA_HANDLE_ACCOUNT_TYPE; - - /* get a (unique) handle. open a policy on it. */ - if (!create_policy_hnd(p, r->out.acct_handle, info)) - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_EnumPrivsAccount - For a given SID, enumerate all the privilege this account has. - ***************************************************************************/ - -NTSTATUS _lsa_EnumPrivsAccount(struct pipes_struct *p, - struct lsa_EnumPrivsAccount *r) -{ - NTSTATUS status = NT_STATUS_OK; - struct lsa_info *info=NULL; - PRIVILEGE_SET *privileges; - struct lsa_PrivilegeSet *priv_set = NULL; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_ACCOUNT_VIEW)) - return NT_STATUS_ACCESS_DENIED; - - status = get_privileges_for_sid_as_set(p->mem_ctx, &privileges, &info->sid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - *r->out.privs = priv_set = TALLOC_ZERO_P(p->mem_ctx, struct lsa_PrivilegeSet); - if (!priv_set) { - return NT_STATUS_NO_MEMORY; - } - - DEBUG(10,("_lsa_EnumPrivsAccount: %s has %d privileges\n", - sid_string_dbg(&info->sid), - privileges->count)); - - priv_set->count = privileges->count; - priv_set->unknown = 0; - priv_set->set = talloc_move(priv_set, &privileges->set); - - return status; -} - -/*************************************************************************** - _lsa_GetSystemAccessAccount - ***************************************************************************/ - -NTSTATUS _lsa_GetSystemAccessAccount(struct pipes_struct *p, - struct lsa_GetSystemAccessAccount *r) -{ - NTSTATUS status; - struct lsa_info *info = NULL; - struct lsa_EnumPrivsAccount e; - struct lsa_PrivilegeSet *privset; - - /* find the connection policy handle. */ - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_ACCOUNT_VIEW)) - return NT_STATUS_ACCESS_DENIED; - - privset = talloc_zero(p->mem_ctx, struct lsa_PrivilegeSet); - if (!privset) { - return NT_STATUS_NO_MEMORY; - } - - e.in.handle = r->in.handle; - e.out.privs = &privset; - - status = _lsa_EnumPrivsAccount(p, &e); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("_lsa_GetSystemAccessAccount: " - "failed to call _lsa_EnumPrivsAccount(): %s\n", - nt_errstr(status))); - return status; - } - - /* Samba4 would iterate over the privset to merge the policy mode bits, - * not sure samba3 can do the same here, so just return what we did in - * the past - gd */ - - /* - 0x01 -> Log on locally - 0x02 -> Access this computer from network - 0x04 -> Log on as a batch job - 0x10 -> Log on as a service - - they can be ORed together - */ - - *r->out.access_mask = LSA_POLICY_MODE_INTERACTIVE | - LSA_POLICY_MODE_NETWORK; - - return NT_STATUS_OK; -} - -/*************************************************************************** - update the systemaccount information - ***************************************************************************/ - -NTSTATUS _lsa_SetSystemAccessAccount(struct pipes_struct *p, - struct lsa_SetSystemAccessAccount *r) -{ - struct lsa_info *info=NULL; - GROUP_MAP map; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (!pdb_getgrsid(&map, info->sid)) - return NT_STATUS_NO_SUCH_GROUP; - - return pdb_update_group_mapping_entry(&map); -} - -/*************************************************************************** - _lsa_AddPrivilegesToAccount - For a given SID, add some privileges. - ***************************************************************************/ - -NTSTATUS _lsa_AddPrivilegesToAccount(struct pipes_struct *p, - struct lsa_AddPrivilegesToAccount *r) -{ - struct lsa_info *info = NULL; - struct lsa_PrivilegeSet *set = NULL; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_ACCOUNT_ADJUST_PRIVILEGES)) { - return NT_STATUS_ACCESS_DENIED; - } - - set = r->in.privs; - - if ( !grant_privilege_set( &info->sid, set ) ) { - DEBUG(3,("_lsa_AddPrivilegesToAccount: grant_privilege_set(%s) failed!\n", - sid_string_dbg(&info->sid) )); - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_RemovePrivilegesFromAccount - For a given SID, remove some privileges. - ***************************************************************************/ - -NTSTATUS _lsa_RemovePrivilegesFromAccount(struct pipes_struct *p, - struct lsa_RemovePrivilegesFromAccount *r) -{ - struct lsa_info *info = NULL; - struct lsa_PrivilegeSet *set = NULL; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_ACCOUNT_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_ACCOUNT_ADJUST_PRIVILEGES)) { - return NT_STATUS_ACCESS_DENIED; - } - - set = r->in.privs; - - if ( !revoke_privilege_set( &info->sid, set) ) { - DEBUG(3,("_lsa_RemovePrivilegesFromAccount: revoke_privilege(%s) failed!\n", - sid_string_dbg(&info->sid) )); - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_LookupPrivName - ***************************************************************************/ - -NTSTATUS _lsa_LookupPrivName(struct pipes_struct *p, - struct lsa_LookupPrivName *r) -{ - struct lsa_info *info = NULL; - const char *name; - struct lsa_StringLarge *lsa_name; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) { - return NT_STATUS_INVALID_HANDLE; - } - - if (info->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_POLICY_VIEW_LOCAL_INFORMATION)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (r->in.luid->high != 0) { - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - name = sec_privilege_name(r->in.luid->low); - if (!name) { - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - lsa_name = TALLOC_ZERO_P(p->mem_ctx, struct lsa_StringLarge); - if (!lsa_name) { - return NT_STATUS_NO_MEMORY; - } - - lsa_name->string = talloc_strdup(lsa_name, name); - if (!lsa_name->string) { - TALLOC_FREE(lsa_name); - return NT_STATUS_NO_MEMORY; - } - - *r->out.name = lsa_name; - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_QuerySecurity - ***************************************************************************/ - -NTSTATUS _lsa_QuerySecurity(struct pipes_struct *p, - struct lsa_QuerySecurity *r) -{ - struct lsa_info *handle=NULL; - struct security_descriptor *psd = NULL; - size_t sd_size; - NTSTATUS status; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&handle)) - return NT_STATUS_INVALID_HANDLE; - - switch (handle->type) { - case LSA_HANDLE_POLICY_TYPE: - status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, - &lsa_policy_mapping, NULL, 0); - break; - case LSA_HANDLE_ACCOUNT_TYPE: - status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, - &lsa_account_mapping, - &handle->sid, LSA_ACCOUNT_ALL_ACCESS); - break; - default: - status = NT_STATUS_INVALID_HANDLE; - break; - } - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - *r->out.sdbuf = make_sec_desc_buf(p->mem_ctx, sd_size, psd); - if (!*r->out.sdbuf) { - return NT_STATUS_NO_MEMORY; - } - - return status; -} - -/*************************************************************************** - _lsa_AddAccountRights - ***************************************************************************/ - -NTSTATUS _lsa_AddAccountRights(struct pipes_struct *p, - struct lsa_AddAccountRights *r) -{ - struct lsa_info *info = NULL; - int i = 0; - uint32_t acc_granted = 0; - struct security_descriptor *psd = NULL; - size_t sd_size; - struct dom_sid sid; - NTSTATUS status; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* get the generic lsa account SD for this SID until we store it */ - status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, - &lsa_account_mapping, - r->in.sid, LSA_ACCOUNT_ALL_ACCESS); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* - * From the MS DOCs. If the sid doesn't exist, ask for LSA_POLICY_CREATE_ACCOUNT - * on the policy handle. If it does, ask for - * LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW, - * on the account sid. We don't check here so just use the latter. JRA. - */ - - status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, - LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW, - &acc_granted, "_lsa_AddAccountRights" ); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* according to an NT4 PDC, you can add privileges to SIDs even without - call_lsa_create_account() first. And you can use any arbitrary SID. */ - - sid_copy( &sid, r->in.sid ); - - for ( i=0; i < r->in.rights->count; i++ ) { - - const char *privname = r->in.rights->names[i].string; - - /* only try to add non-null strings */ - - if ( !privname ) - continue; - - if ( !grant_privilege_by_name( &sid, privname ) ) { - DEBUG(2,("_lsa_AddAccountRights: Failed to add privilege [%s]\n", - privname )); - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - } - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_RemoveAccountRights - ***************************************************************************/ - -NTSTATUS _lsa_RemoveAccountRights(struct pipes_struct *p, - struct lsa_RemoveAccountRights *r) -{ - struct lsa_info *info = NULL; - int i = 0; - struct security_descriptor *psd = NULL; - size_t sd_size; - struct dom_sid sid; - const char *privname = NULL; - uint32_t acc_granted = 0; - NTSTATUS status; - - /* find the connection policy handle. */ - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - /* get the generic lsa account SD for this SID until we store it */ - status = make_lsa_object_sd(p->mem_ctx, &psd, &sd_size, - &lsa_account_mapping, - r->in.sid, LSA_ACCOUNT_ALL_ACCESS); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* - * From the MS DOCs. We need - * LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS|LSA_ACCOUNT_VIEW - * and DELETE on the account sid. - */ - - status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_INVALID, SEC_PRIV_INVALID, 0, - LSA_ACCOUNT_ADJUST_PRIVILEGES|LSA_ACCOUNT_ADJUST_SYSTEM_ACCESS| - LSA_ACCOUNT_VIEW|SEC_STD_DELETE, - &acc_granted, "_lsa_RemoveAccountRights"); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - sid_copy( &sid, r->in.sid ); - - if ( r->in.remove_all ) { - if ( !revoke_all_privileges( &sid ) ) - return NT_STATUS_ACCESS_DENIED; - - return NT_STATUS_OK; - } - - for ( i=0; i < r->in.rights->count; i++ ) { - - privname = r->in.rights->names[i].string; - - /* only try to add non-null strings */ - - if ( !privname ) - continue; - - if ( !revoke_privilege_by_name( &sid, privname ) ) { - DEBUG(2,("_lsa_RemoveAccountRights: Failed to revoke privilege [%s]\n", - privname )); - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - } - - return NT_STATUS_OK; -} - -/******************************************************************* -********************************************************************/ - -static NTSTATUS init_lsa_right_set(TALLOC_CTX *mem_ctx, - struct lsa_RightSet *r, - PRIVILEGE_SET *privileges) -{ - uint32 i; - const char *privname; - const char **privname_array = NULL; - int num_priv = 0; - - for (i=0; icount; i++) { - if (privileges->set[i].luid.high) { - continue; - } - privname = sec_privilege_name(privileges->set[i].luid.low); - if (privname) { - if (!add_string_to_array(mem_ctx, privname, - &privname_array, &num_priv)) { - return NT_STATUS_NO_MEMORY; - } - } - } - - if (num_priv) { - - r->names = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_StringLarge, - num_priv); - if (!r->names) { - return NT_STATUS_NO_MEMORY; - } - - for (i=0; inames[i], privname_array[i]); - } - - r->count = num_priv; - } - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_EnumAccountRights - ***************************************************************************/ - -NTSTATUS _lsa_EnumAccountRights(struct pipes_struct *p, - struct lsa_EnumAccountRights *r) -{ - NTSTATUS status; - struct lsa_info *info = NULL; - PRIVILEGE_SET *privileges; - - /* find the connection policy handle. */ - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_ACCOUNT_VIEW)) { - return NT_STATUS_ACCESS_DENIED; - } - - /* according to an NT4 PDC, you can add privileges to SIDs even without - call_lsa_create_account() first. And you can use any arbitrary SID. */ - - /* according to MS-LSAD 3.1.4.5.10 it is required to return - * NT_STATUS_OBJECT_NAME_NOT_FOUND if the account sid was not found in - * the lsa database */ - - status = get_privileges_for_sid_as_set(p->mem_ctx, &privileges, r->in.sid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(10,("_lsa_EnumAccountRights: %s has %d privileges\n", - sid_string_dbg(r->in.sid), privileges->count)); - - status = init_lsa_right_set(p->mem_ctx, r->out.rights, privileges); - - return status; -} - -/*************************************************************************** - _lsa_LookupPrivValue - ***************************************************************************/ - -NTSTATUS _lsa_LookupPrivValue(struct pipes_struct *p, - struct lsa_LookupPrivValue *r) -{ - struct lsa_info *info = NULL; - const char *name = NULL; - - /* find the connection policy handle. */ - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) - return NT_STATUS_INVALID_HANDLE; - - if (info->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_POLICY_LOOKUP_NAMES)) - return NT_STATUS_ACCESS_DENIED; - - name = r->in.name->string; - - DEBUG(10,("_lsa_lookup_priv_value: name = %s\n", name)); - - r->out.luid->low = sec_privilege_id(name); - r->out.luid->high = 0; - if (r->out.luid->low == SEC_PRIV_INVALID) { - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_EnumAccountsWithUserRight - ***************************************************************************/ - -NTSTATUS _lsa_EnumAccountsWithUserRight(struct pipes_struct *p, - struct lsa_EnumAccountsWithUserRight *r) -{ - NTSTATUS status; - struct lsa_info *info = NULL; - struct dom_sid *sids = NULL; - int num_sids = 0; - uint32_t i; - enum sec_privilege privilege; - - if (!find_policy_by_hnd(p, r->in.handle, (void **)(void *)&info)) { - return NT_STATUS_INVALID_HANDLE; - } - - if (info->type != LSA_HANDLE_POLICY_TYPE) { - return NT_STATUS_INVALID_HANDLE; - } - - if (!(info->access & LSA_POLICY_LOOKUP_NAMES)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (!r->in.name || !r->in.name->string) { - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - privilege = sec_privilege_id(r->in.name->string); - if (privilege == SEC_PRIV_INVALID) { - return NT_STATUS_NO_SUCH_PRIVILEGE; - } - - status = privilege_enum_sids(privilege, p->mem_ctx, - &sids, &num_sids); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - r->out.sids->num_sids = num_sids; - r->out.sids->sids = talloc_array(p->mem_ctx, struct lsa_SidPtr, - r->out.sids->num_sids); - - for (i=0; i < r->out.sids->num_sids; i++) { - r->out.sids->sids[i].sid = dom_sid_dup(r->out.sids->sids, - &sids[i]); - if (!r->out.sids->sids[i].sid) { - TALLOC_FREE(r->out.sids->sids); - r->out.sids->num_sids = 0; - return NT_STATUS_NO_MEMORY; - } - } - - return NT_STATUS_OK; -} - -/*************************************************************************** - _lsa_Delete - ***************************************************************************/ - -NTSTATUS _lsa_Delete(struct pipes_struct *p, - struct lsa_Delete *r) -{ - return NT_STATUS_NOT_SUPPORTED; -} - -/* - * From here on the server routines are just dummy ones to make smbd link with - * librpc/gen_ndr/srv_lsa.c. These routines are actually never called, we are - * pulling the server stubs across one by one. - */ - -NTSTATUS _lsa_SetSecObj(struct pipes_struct *p, struct lsa_SetSecObj *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_ChangePassword(struct pipes_struct *p, - struct lsa_ChangePassword *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_SetInfoPolicy(struct pipes_struct *p, struct lsa_SetInfoPolicy *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_ClearAuditLog(struct pipes_struct *p, struct lsa_ClearAuditLog *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_GetQuotasForAccount(struct pipes_struct *p, - struct lsa_GetQuotasForAccount *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_SetQuotasForAccount(struct pipes_struct *p, - struct lsa_SetQuotasForAccount *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_QueryTrustedDomainInfo(struct pipes_struct *p, - struct lsa_QueryTrustedDomainInfo *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_SetInformationTrustedDomain(struct pipes_struct *p, - struct lsa_SetInformationTrustedDomain *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_QuerySecret(struct pipes_struct *p, struct lsa_QuerySecret *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_QueryTrustedDomainInfoBySid(struct pipes_struct *p, - struct lsa_QueryTrustedDomainInfoBySid *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_SetTrustedDomainInfo(struct pipes_struct *p, - struct lsa_SetTrustedDomainInfo *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_DeleteTrustedDomain(struct pipes_struct *p, - struct lsa_DeleteTrustedDomain *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_StorePrivateData(struct pipes_struct *p, - struct lsa_StorePrivateData *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_RetrievePrivateData(struct pipes_struct *p, - struct lsa_RetrievePrivateData *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_SetInfoPolicy2(struct pipes_struct *p, - struct lsa_SetInfoPolicy2 *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_QueryTrustedDomainInfoByName(struct pipes_struct *p, - struct lsa_QueryTrustedDomainInfoByName *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_SetTrustedDomainInfoByName(struct pipes_struct *p, - struct lsa_SetTrustedDomainInfoByName *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_EnumTrustedDomainsEx(struct pipes_struct *p, - struct lsa_EnumTrustedDomainsEx *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CreateTrustedDomainEx(struct pipes_struct *p, - struct lsa_CreateTrustedDomainEx *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CloseTrustedDomainEx(struct pipes_struct *p, - struct lsa_CloseTrustedDomainEx *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_QueryDomainInformationPolicy(struct pipes_struct *p, - struct lsa_QueryDomainInformationPolicy *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_SetDomainInformationPolicy(struct pipes_struct *p, - struct lsa_SetDomainInformationPolicy *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_OpenTrustedDomainByName(struct pipes_struct *p, - struct lsa_OpenTrustedDomainByName *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_TestCall(struct pipes_struct *p, struct lsa_TestCall *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CreateTrustedDomainEx2(struct pipes_struct *p, - struct lsa_CreateTrustedDomainEx2 *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRWRITE(struct pipes_struct *p, struct lsa_CREDRWRITE *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRREAD(struct pipes_struct *p, struct lsa_CREDRREAD *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRENUMERATE(struct pipes_struct *p, struct lsa_CREDRENUMERATE *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRWRITEDOMAINCREDENTIALS(struct pipes_struct *p, - struct lsa_CREDRWRITEDOMAINCREDENTIALS *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRREADDOMAINCREDENTIALS(struct pipes_struct *p, - struct lsa_CREDRREADDOMAINCREDENTIALS *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRDELETE(struct pipes_struct *p, struct lsa_CREDRDELETE *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRGETTARGETINFO(struct pipes_struct *p, - struct lsa_CREDRGETTARGETINFO *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRPROFILELOADED(struct pipes_struct *p, - struct lsa_CREDRPROFILELOADED *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRGETSESSIONTYPES(struct pipes_struct *p, - struct lsa_CREDRGETSESSIONTYPES *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_LSARREGISTERAUDITEVENT(struct pipes_struct *p, - struct lsa_LSARREGISTERAUDITEVENT *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_LSARGENAUDITEVENT(struct pipes_struct *p, - struct lsa_LSARGENAUDITEVENT *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_LSARUNREGISTERAUDITEVENT(struct pipes_struct *p, - struct lsa_LSARUNREGISTERAUDITEVENT *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_lsaRQueryForestTrustInformation(struct pipes_struct *p, - struct lsa_lsaRQueryForestTrustInformation *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_lsaRSetForestTrustInformation(struct pipes_struct *p, - struct lsa_lsaRSetForestTrustInformation *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_CREDRRENAME(struct pipes_struct *p, - struct lsa_CREDRRENAME *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_LSAROPENPOLICYSCE(struct pipes_struct *p, - struct lsa_LSAROPENPOLICYSCE *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_LSARADTREGISTERSECURITYEVENTSOURCE(struct pipes_struct *p, - struct lsa_LSARADTREGISTERSECURITYEVENTSOURCE *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE(struct pipes_struct *p, - struct lsa_LSARADTUNREGISTERSECURITYEVENTSOURCE *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} - -NTSTATUS _lsa_LSARADTREPORTSECURITYEVENT(struct pipes_struct *p, - struct lsa_LSARADTREPORTSECURITYEVENT *r) -{ - p->rng_fault_state = True; - return NT_STATUS_NOT_IMPLEMENTED; -} diff --git a/source3/rpc_server/srv_netlog_nt.c b/source3/rpc_server/srv_netlog_nt.c deleted file mode 100644 index b55c74adfc..0000000000 --- a/source3/rpc_server/srv_netlog_nt.c +++ /dev/null @@ -1,2215 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, - * Copyright (C) Paul Ashton 1997. - * Copyright (C) Jeremy Allison 1998-2001. - * Copyright (C) Andrew Bartlett 2001. - * Copyright (C) Guenther Deschner 2008-2009. - * - * 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 . - */ - -/* This is the implementation of the netlogon pipe. */ - -#include "includes.h" -#include "../libcli/auth/schannel.h" -#include "../librpc/gen_ndr/srv_netlogon.h" -#include "../librpc/gen_ndr/srv_samr.h" -#include "../librpc/gen_ndr/srv_lsa.h" -#include "../librpc/gen_ndr/ndr_samr_c.h" -#include "../librpc/gen_ndr/ndr_lsa_c.h" -#include "rpc_client/cli_lsarpc.h" -#include "librpc/gen_ndr/messaging.h" -#include "../lib/crypto/md4.h" -#include "rpc_client/init_lsa.h" -#include "rpc_server/rpc_ncacn_np.h" -#include "../libcli/security/security.h" - -extern userdom_struct current_user_info; - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -struct netlogon_server_pipe_state { - struct netr_Credential client_challenge; - struct netr_Credential server_challenge; -}; - -/************************************************************************* - _netr_LogonControl - *************************************************************************/ - -WERROR _netr_LogonControl(struct pipes_struct *p, - struct netr_LogonControl *r) -{ - struct netr_LogonControl2Ex l; - - switch (r->in.level) { - case 1: - break; - case 2: - return WERR_NOT_SUPPORTED; - default: - return WERR_UNKNOWN_LEVEL; - } - - l.in.logon_server = r->in.logon_server; - l.in.function_code = r->in.function_code; - l.in.level = r->in.level; - l.in.data = NULL; - l.out.query = r->out.query; - - return _netr_LogonControl2Ex(p, &l); -} - -/**************************************************************************** -Send a message to smbd to do a sam synchronisation -**************************************************************************/ - -static void send_sync_message(struct messaging_context *msg_ctx) -{ - DEBUG(3, ("sending sam synchronisation message\n")); - message_send_all(msg_ctx, MSG_SMB_SAM_SYNC, NULL, 0, NULL); -} - -/************************************************************************* - _netr_LogonControl2 - *************************************************************************/ - -WERROR _netr_LogonControl2(struct pipes_struct *p, - struct netr_LogonControl2 *r) -{ - struct netr_LogonControl2Ex l; - - l.in.logon_server = r->in.logon_server; - l.in.function_code = r->in.function_code; - l.in.level = r->in.level; - l.in.data = r->in.data; - l.out.query = r->out.query; - - return _netr_LogonControl2Ex(p, &l); -} - -/************************************************************************* - *************************************************************************/ - -static bool wb_change_trust_creds(const char *domain, WERROR *tc_status) -{ - wbcErr result; - struct wbcAuthErrorInfo *error = NULL; - - result = wbcChangeTrustCredentials(domain, &error); - switch (result) { - case WBC_ERR_WINBIND_NOT_AVAILABLE: - return false; - case WBC_ERR_DOMAIN_NOT_FOUND: - *tc_status = WERR_NO_SUCH_DOMAIN; - return true; - case WBC_ERR_SUCCESS: - *tc_status = WERR_OK; - return true; - default: - break; - } - - if (error && error->nt_status != 0) { - *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status)); - } else { - *tc_status = WERR_TRUST_FAILURE; - } - wbcFreeMemory(error); - return true; -} - -/************************************************************************* - *************************************************************************/ - -static bool wb_check_trust_creds(const char *domain, WERROR *tc_status) -{ - wbcErr result; - struct wbcAuthErrorInfo *error = NULL; - - result = wbcCheckTrustCredentials(domain, &error); - switch (result) { - case WBC_ERR_WINBIND_NOT_AVAILABLE: - return false; - case WBC_ERR_DOMAIN_NOT_FOUND: - *tc_status = WERR_NO_SUCH_DOMAIN; - return true; - case WBC_ERR_SUCCESS: - *tc_status = WERR_OK; - return true; - default: - break; - } - - if (error && error->nt_status != 0) { - *tc_status = ntstatus_to_werror(NT_STATUS(error->nt_status)); - } else { - *tc_status = WERR_TRUST_FAILURE; - } - wbcFreeMemory(error); - return true; -} - -/**************************************************************** - _netr_LogonControl2Ex -****************************************************************/ - -WERROR _netr_LogonControl2Ex(struct pipes_struct *p, - struct netr_LogonControl2Ex *r) -{ - uint32_t flags = 0x0; - WERROR pdc_connection_status = WERR_OK; - uint32_t logon_attempts = 0x0; - WERROR tc_status; - fstring dc_name2; - const char *dc_name = NULL; - struct sockaddr_storage dc_ss; - const char *domain = NULL; - struct netr_NETLOGON_INFO_1 *info1; - struct netr_NETLOGON_INFO_2 *info2; - struct netr_NETLOGON_INFO_3 *info3; - struct netr_NETLOGON_INFO_4 *info4; - const char *fn; - uint32_t acct_ctrl; - - switch (p->opnum) { - case NDR_NETR_LOGONCONTROL: - fn = "_netr_LogonControl"; - break; - case NDR_NETR_LOGONCONTROL2: - fn = "_netr_LogonControl2"; - break; - case NDR_NETR_LOGONCONTROL2EX: - fn = "_netr_LogonControl2Ex"; - break; - default: - return WERR_INVALID_PARAM; - } - - acct_ctrl = p->server_info->info3->base.acct_flags; - - switch (r->in.function_code) { - case NETLOGON_CONTROL_TC_VERIFY: - case NETLOGON_CONTROL_CHANGE_PASSWORD: - case NETLOGON_CONTROL_REDISCOVER: - if ((geteuid() != sec_initial_uid()) && - !nt_token_check_domain_rid(p->server_info->security_token, DOMAIN_RID_ADMINS) && - !nt_token_check_sid(&global_sid_Builtin_Administrators, p->server_info->security_token) && - !(acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST))) { - return WERR_ACCESS_DENIED; - } - break; - default: - break; - } - - tc_status = WERR_NO_SUCH_DOMAIN; - - switch (r->in.function_code) { - case NETLOGON_CONTROL_QUERY: - tc_status = WERR_OK; - break; - case NETLOGON_CONTROL_REPLICATE: - case NETLOGON_CONTROL_SYNCHRONIZE: - case NETLOGON_CONTROL_PDC_REPLICATE: - case NETLOGON_CONTROL_BACKUP_CHANGE_LOG: - case NETLOGON_CONTROL_BREAKPOINT: - if (acct_ctrl & ACB_NORMAL) { - return WERR_NOT_SUPPORTED; - } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) { - return WERR_ACCESS_DENIED; - } else { - return WERR_ACCESS_DENIED; - } - case NETLOGON_CONTROL_TRUNCATE_LOG: - if (acct_ctrl & ACB_NORMAL) { - break; - } else if (acct_ctrl & (ACB_WSTRUST | ACB_SVRTRUST)) { - return WERR_ACCESS_DENIED; - } else { - return WERR_ACCESS_DENIED; - } - - case NETLOGON_CONTROL_TRANSPORT_NOTIFY: - case NETLOGON_CONTROL_FORCE_DNS_REG: - case NETLOGON_CONTROL_QUERY_DNS_REG: - return WERR_NOT_SUPPORTED; - case NETLOGON_CONTROL_FIND_USER: - if (!r->in.data || !r->in.data->user) { - return WERR_NOT_SUPPORTED; - } - break; - case NETLOGON_CONTROL_SET_DBFLAG: - if (!r->in.data) { - return WERR_NOT_SUPPORTED; - } - break; - case NETLOGON_CONTROL_TC_VERIFY: - if (!r->in.data || !r->in.data->domain) { - return WERR_NOT_SUPPORTED; - } - - if (!wb_check_trust_creds(r->in.data->domain, &tc_status)) { - return WERR_NOT_SUPPORTED; - } - break; - case NETLOGON_CONTROL_TC_QUERY: - if (!r->in.data || !r->in.data->domain) { - return WERR_NOT_SUPPORTED; - } - - domain = r->in.data->domain; - - if (!is_trusted_domain(domain)) { - break; - } - - if (!get_dc_name(domain, NULL, dc_name2, &dc_ss)) { - tc_status = WERR_NO_LOGON_SERVERS; - break; - } - - dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); - if (!dc_name) { - return WERR_NOMEM; - } - - tc_status = WERR_OK; - - break; - - case NETLOGON_CONTROL_REDISCOVER: - if (!r->in.data || !r->in.data->domain) { - return WERR_NOT_SUPPORTED; - } - - domain = r->in.data->domain; - - if (!is_trusted_domain(domain)) { - break; - } - - if (!get_dc_name(domain, NULL, dc_name2, &dc_ss)) { - tc_status = WERR_NO_LOGON_SERVERS; - break; - } - - dc_name = talloc_asprintf(p->mem_ctx, "\\\\%s", dc_name2); - if (!dc_name) { - return WERR_NOMEM; - } - - tc_status = WERR_OK; - - break; - - case NETLOGON_CONTROL_CHANGE_PASSWORD: - if (!r->in.data || !r->in.data->domain) { - return WERR_NOT_SUPPORTED; - } - - if (!wb_change_trust_creds(r->in.data->domain, &tc_status)) { - return WERR_NOT_SUPPORTED; - } - break; - - default: - /* no idea what this should be */ - DEBUG(0,("%s: unimplemented function level [%d]\n", - fn, r->in.function_code)); - return WERR_UNKNOWN_LEVEL; - } - - /* prepare the response */ - - switch (r->in.level) { - case 1: - info1 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_1); - W_ERROR_HAVE_NO_MEMORY(info1); - - info1->flags = flags; - info1->pdc_connection_status = pdc_connection_status; - - r->out.query->info1 = info1; - break; - case 2: - info2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_2); - W_ERROR_HAVE_NO_MEMORY(info2); - - info2->flags = flags; - info2->pdc_connection_status = pdc_connection_status; - info2->trusted_dc_name = dc_name; - info2->tc_connection_status = tc_status; - - r->out.query->info2 = info2; - break; - case 3: - info3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_3); - W_ERROR_HAVE_NO_MEMORY(info3); - - info3->flags = flags; - info3->logon_attempts = logon_attempts; - - r->out.query->info3 = info3; - break; - case 4: - info4 = TALLOC_ZERO_P(p->mem_ctx, struct netr_NETLOGON_INFO_4); - W_ERROR_HAVE_NO_MEMORY(info4); - - info4->trusted_dc_name = dc_name; - info4->trusted_domain_name = r->in.data->domain; - - r->out.query->info4 = info4; - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - if (lp_server_role() == ROLE_DOMAIN_BDC) { - send_sync_message(p->msg_ctx); - } - - return WERR_OK; -} - -/************************************************************************* - _netr_NetrEnumerateTrustedDomains - *************************************************************************/ - -NTSTATUS _netr_NetrEnumerateTrustedDomains(struct pipes_struct *p, - struct netr_NetrEnumerateTrustedDomains *r) -{ - NTSTATUS status; - NTSTATUS result = NT_STATUS_OK; - DATA_BLOB blob; - int num_domains = 0; - const char **trusted_domains = NULL; - struct lsa_DomainList domain_list; - struct dcerpc_binding_handle *h = NULL; - struct policy_handle pol; - uint32_t enum_ctx = 0; - int i; - uint32_t max_size = (uint32_t)-1; - - DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__)); - - status = rpcint_binding_handle(p->mem_ctx, - &ndr_table_lsarpc, - p->client_id, - p->server_info, - p->msg_ctx, - &h); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = dcerpc_lsa_open_policy2(h, - p->mem_ctx, - NULL, - true, - LSA_POLICY_VIEW_LOCAL_INFORMATION, - &pol, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - do { - /* Lookup list of trusted domains */ - status = dcerpc_lsa_EnumTrustDom(h, - p->mem_ctx, - &pol, - &enum_ctx, - &domain_list, - max_size, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result) && - !NT_STATUS_EQUAL(result, NT_STATUS_NO_MORE_ENTRIES) && - !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) { - status = result; - goto out; - } - - for (i = 0; i < domain_list.count; i++) { - if (!add_string_to_array(p->mem_ctx, domain_list.domains[i].name.string, - &trusted_domains, &num_domains)) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - } - } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)); - - if (num_domains > 0) { - /* multi sz terminate */ - trusted_domains = talloc_realloc(p->mem_ctx, trusted_domains, const char *, num_domains + 1); - if (trusted_domains == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - - trusted_domains[num_domains] = NULL; - } - - if (!push_reg_multi_sz(trusted_domains, &blob, trusted_domains)) { - TALLOC_FREE(trusted_domains); - status = NT_STATUS_NO_MEMORY; - goto out; - } - - r->out.trusted_domains_blob->data = blob.data; - r->out.trusted_domains_blob->length = blob.length; - - DEBUG(6,("_netr_NetrEnumerateTrustedDomains: %d\n", __LINE__)); - - status = NT_STATUS_OK; - - out: - if (h && is_valid_policy_hnd(&pol)) { - dcerpc_lsa_Close(h, p->mem_ctx, &pol, &result); - } - - return status; -} - -/************************************************************************* - *************************************************************************/ - -static NTSTATUS samr_find_machine_account(TALLOC_CTX *mem_ctx, - struct dcerpc_binding_handle *b, - const char *account_name, - uint32_t access_mask, - struct dom_sid2 **domain_sid_p, - uint32_t *user_rid_p, - struct policy_handle *user_handle) -{ - NTSTATUS status; - NTSTATUS result = NT_STATUS_OK; - struct policy_handle connect_handle, domain_handle; - struct lsa_String domain_name; - struct dom_sid2 *domain_sid; - struct lsa_String names; - struct samr_Ids rids; - struct samr_Ids types; - uint32_t rid; - - status = dcerpc_samr_Connect2(b, mem_ctx, - global_myname(), - SAMR_ACCESS_CONNECT_TO_SERVER | - SAMR_ACCESS_ENUM_DOMAINS | - SAMR_ACCESS_LOOKUP_DOMAIN, - &connect_handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - init_lsa_String(&domain_name, get_global_sam_name()); - - status = dcerpc_samr_LookupDomain(b, mem_ctx, - &connect_handle, - &domain_name, - &domain_sid, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - status = dcerpc_samr_OpenDomain(b, mem_ctx, - &connect_handle, - SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, - domain_sid, - &domain_handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - init_lsa_String(&names, account_name); - - status = dcerpc_samr_LookupNames(b, mem_ctx, - &domain_handle, - 1, - &names, - &rids, - &types, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - if (rids.count != 1) { - status = NT_STATUS_NO_SUCH_USER; - goto out; - } - if (rids.count != types.count) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - if (types.ids[0] != SID_NAME_USER) { - status = NT_STATUS_NO_SUCH_USER; - goto out; - } - - rid = rids.ids[0]; - - status = dcerpc_samr_OpenUser(b, mem_ctx, - &domain_handle, - access_mask, - rid, - user_handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - if (user_rid_p) { - *user_rid_p = rid; - } - - if (domain_sid_p) { - *domain_sid_p = domain_sid; - } - - out: - if (b && is_valid_policy_hnd(&domain_handle)) { - dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result); - } - if (b && is_valid_policy_hnd(&connect_handle)) { - dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result); - } - - return status; -} - -/****************************************************************** - gets a machine password entry. checks access rights of the host. - ******************************************************************/ - -static NTSTATUS get_md4pw(struct samr_Password *md4pw, const char *mach_acct, - enum netr_SchannelType sec_chan_type, - struct dom_sid *sid, - struct messaging_context *msg_ctx) -{ - NTSTATUS status; - NTSTATUS result = NT_STATUS_OK; - TALLOC_CTX *mem_ctx; - struct dcerpc_binding_handle *h = NULL; - static struct client_address client_id; - struct policy_handle user_handle; - uint32_t user_rid; - struct dom_sid *domain_sid; - uint32_t acct_ctrl; - union samr_UserInfo *info; - struct auth_serversupplied_info *server_info; -#if 0 - - /* - * Currently this code is redundent as we already have a filter - * by hostname list. What this code really needs to do is to - * get a hosts allowed/hosts denied list from the SAM database - * on a per user basis, and make the access decision there. - * I will leave this code here for now as a reminder to implement - * this at a later date. JRA. - */ - - if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(), - p->client_id.name, - p->client_id.addr)) { - DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct)); - return False; - } -#endif /* 0 */ - - mem_ctx = talloc_stackframe(); - if (mem_ctx == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - - status = make_server_info_system(mem_ctx, &server_info); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - ZERO_STRUCT(user_handle); - - strlcpy(client_id.addr, "127.0.0.1", sizeof(client_id.addr)); - client_id.name = "127.0.0.1"; - - status = rpcint_binding_handle(mem_ctx, - &ndr_table_samr, - &client_id, - server_info, - msg_ctx, - &h); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - become_root(); - status = samr_find_machine_account(mem_ctx, h, mach_acct, - SEC_FLAG_MAXIMUM_ALLOWED, - &domain_sid, &user_rid, - &user_handle); - unbecome_root(); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = dcerpc_samr_QueryUserInfo2(h, - mem_ctx, - &user_handle, - UserControlInformation, - &info, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - acct_ctrl = info->info16.acct_flags; - - if (acct_ctrl & ACB_DISABLED) { - DEBUG(0,("get_md4pw: Workstation %s: account is disabled\n", mach_acct)); - status = NT_STATUS_ACCOUNT_DISABLED; - goto out; - } - - if (!(acct_ctrl & ACB_SVRTRUST) && - !(acct_ctrl & ACB_WSTRUST) && - !(acct_ctrl & ACB_DOMTRUST)) - { - DEBUG(0,("get_md4pw: Workstation %s: account is not a trust account\n", mach_acct)); - status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; - goto out; - } - - switch (sec_chan_type) { - case SEC_CHAN_BDC: - if (!(acct_ctrl & ACB_SVRTRUST)) { - DEBUG(0,("get_md4pw: Workstation %s: BDC secure channel requested " - "but not a server trust account\n", mach_acct)); - status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; - goto out; - } - break; - case SEC_CHAN_WKSTA: - if (!(acct_ctrl & ACB_WSTRUST)) { - DEBUG(0,("get_md4pw: Workstation %s: WORKSTATION secure channel requested " - "but not a workstation trust account\n", mach_acct)); - status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; - goto out; - } - break; - case SEC_CHAN_DOMAIN: - if (!(acct_ctrl & ACB_DOMTRUST)) { - DEBUG(0,("get_md4pw: Workstation %s: DOMAIN secure channel requested " - "but not a interdomain trust account\n", mach_acct)); - status = NT_STATUS_NO_TRUST_SAM_ACCOUNT; - goto out; - } - break; - default: - break; - } - - become_root(); - status = dcerpc_samr_QueryUserInfo2(h, - mem_ctx, - &user_handle, - UserInternal1Information, - &info, - &result); - unbecome_root(); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - if (info->info18.nt_pwd_active == 0) { - DEBUG(0,("get_md4pw: Workstation %s: account does not have a password\n", mach_acct)); - status = NT_STATUS_LOGON_FAILURE; - goto out; - } - - /* samr gives out nthash unencrypted (!) */ - memcpy(md4pw->hash, info->info18.nt_pwd.hash, 16); - - sid_compose(sid, domain_sid, user_rid); - - out: - if (h && is_valid_policy_hnd(&user_handle)) { - dcerpc_samr_Close(h, mem_ctx, &user_handle, &result); - } - - talloc_free(mem_ctx); - - return status; -} - -/************************************************************************* - _netr_ServerReqChallenge - *************************************************************************/ - -NTSTATUS _netr_ServerReqChallenge(struct pipes_struct *p, - struct netr_ServerReqChallenge *r) -{ - struct netlogon_server_pipe_state *pipe_state = - talloc_get_type(p->private_data, struct netlogon_server_pipe_state); - - if (pipe_state) { - DEBUG(10,("_netr_ServerReqChallenge: new challenge requested. Clearing old state.\n")); - talloc_free(pipe_state); - p->private_data = NULL; - } - - pipe_state = talloc(p, struct netlogon_server_pipe_state); - NT_STATUS_HAVE_NO_MEMORY(pipe_state); - - pipe_state->client_challenge = *r->in.credentials; - - generate_random_buffer(pipe_state->server_challenge.data, - sizeof(pipe_state->server_challenge.data)); - - *r->out.return_credentials = pipe_state->server_challenge; - - p->private_data = pipe_state; - - return NT_STATUS_OK; -} - -/************************************************************************* - _netr_ServerAuthenticate - Create the initial credentials. - *************************************************************************/ - -NTSTATUS _netr_ServerAuthenticate(struct pipes_struct *p, - struct netr_ServerAuthenticate *r) -{ - struct netr_ServerAuthenticate3 a; - uint32_t negotiate_flags = 0; - uint32_t rid; - - a.in.server_name = r->in.server_name; - a.in.account_name = r->in.account_name; - a.in.secure_channel_type = r->in.secure_channel_type; - a.in.computer_name = r->in.computer_name; - a.in.credentials = r->in.credentials; - a.in.negotiate_flags = &negotiate_flags; - - a.out.return_credentials = r->out.return_credentials; - a.out.rid = &rid; - a.out.negotiate_flags = &negotiate_flags; - - return _netr_ServerAuthenticate3(p, &a); - -} - -/************************************************************************* - _netr_ServerAuthenticate3 - *************************************************************************/ - -NTSTATUS _netr_ServerAuthenticate3(struct pipes_struct *p, - struct netr_ServerAuthenticate3 *r) -{ - NTSTATUS status; - uint32_t srv_flgs; - /* r->in.negotiate_flags is an aliased pointer to r->out.negotiate_flags, - * so use a copy to avoid destroying the client values. */ - uint32_t in_neg_flags = *r->in.negotiate_flags; - const char *fn; - struct dom_sid sid; - struct samr_Password mach_pwd; - struct netlogon_creds_CredentialState *creds; - struct netlogon_server_pipe_state *pipe_state = - talloc_get_type(p->private_data, struct netlogon_server_pipe_state); - - /* According to Microsoft (see bugid #6099) - * Windows 7 looks at the negotiate_flags - * returned in this structure *even if the - * call fails with access denied* ! So in order - * to allow Win7 to connect to a Samba NT style - * PDC we set the flags before we know if it's - * an error or not. - */ - - /* 0x000001ff */ - srv_flgs = NETLOGON_NEG_ACCOUNT_LOCKOUT | - NETLOGON_NEG_PERSISTENT_SAMREPL | - NETLOGON_NEG_ARCFOUR | - NETLOGON_NEG_PROMOTION_COUNT | - NETLOGON_NEG_CHANGELOG_BDC | - NETLOGON_NEG_FULL_SYNC_REPL | - NETLOGON_NEG_MULTIPLE_SIDS | - NETLOGON_NEG_REDO | - NETLOGON_NEG_PASSWORD_CHANGE_REFUSAL | - NETLOGON_NEG_PASSWORD_SET2; - - /* Ensure we support strong (128-bit) keys. */ - if (in_neg_flags & NETLOGON_NEG_STRONG_KEYS) { - srv_flgs |= NETLOGON_NEG_STRONG_KEYS; - } - - if (lp_server_schannel() != false) { - srv_flgs |= NETLOGON_NEG_SCHANNEL; - } - - switch (p->opnum) { - case NDR_NETR_SERVERAUTHENTICATE: - fn = "_netr_ServerAuthenticate"; - break; - case NDR_NETR_SERVERAUTHENTICATE2: - fn = "_netr_ServerAuthenticate2"; - break; - case NDR_NETR_SERVERAUTHENTICATE3: - fn = "_netr_ServerAuthenticate3"; - break; - default: - return NT_STATUS_INTERNAL_ERROR; - } - - /* We use this as the key to store the creds: */ - /* r->in.computer_name */ - - if (!pipe_state) { - DEBUG(0,("%s: no challenge sent to client %s\n", fn, - r->in.computer_name)); - status = NT_STATUS_ACCESS_DENIED; - goto out; - } - - if ( (lp_server_schannel() == true) && - ((in_neg_flags & NETLOGON_NEG_SCHANNEL) == 0) ) { - - /* schannel must be used, but client did not offer it. */ - DEBUG(0,("%s: schannel required but client failed " - "to offer it. Client was %s\n", - fn, r->in.account_name)); - status = NT_STATUS_ACCESS_DENIED; - goto out; - } - - status = get_md4pw(&mach_pwd, - r->in.account_name, - r->in.secure_channel_type, - &sid, p->msg_ctx); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("%s: failed to get machine password for " - "account %s: %s\n", - fn, r->in.account_name, nt_errstr(status) )); - /* always return NT_STATUS_ACCESS_DENIED */ - status = NT_STATUS_ACCESS_DENIED; - goto out; - } - - /* From the client / server challenges and md4 password, generate sess key */ - /* Check client credentials are valid. */ - creds = netlogon_creds_server_init(p->mem_ctx, - r->in.account_name, - r->in.computer_name, - r->in.secure_channel_type, - &pipe_state->client_challenge, - &pipe_state->server_challenge, - &mach_pwd, - r->in.credentials, - r->out.return_credentials, - *r->in.negotiate_flags); - if (!creds) { - DEBUG(0,("%s: netlogon_creds_server_check failed. Rejecting auth " - "request from client %s machine account %s\n", - fn, r->in.computer_name, - r->in.account_name)); - status = NT_STATUS_ACCESS_DENIED; - goto out; - } - - creds->sid = dom_sid_dup(creds, &sid); - if (!creds->sid) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - - /* Store off the state so we can continue after client disconnect. */ - become_root(); - status = schannel_save_creds_state(p->mem_ctx, lp_private_dir(), creds); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - sid_peek_rid(&sid, r->out.rid); - - status = NT_STATUS_OK; - - out: - - *r->out.negotiate_flags = srv_flgs; - return status; -} - -/************************************************************************* - _netr_ServerAuthenticate2 - *************************************************************************/ - -NTSTATUS _netr_ServerAuthenticate2(struct pipes_struct *p, - struct netr_ServerAuthenticate2 *r) -{ - struct netr_ServerAuthenticate3 a; - uint32_t rid; - - a.in.server_name = r->in.server_name; - a.in.account_name = r->in.account_name; - a.in.secure_channel_type = r->in.secure_channel_type; - a.in.computer_name = r->in.computer_name; - a.in.credentials = r->in.credentials; - a.in.negotiate_flags = r->in.negotiate_flags; - - a.out.return_credentials = r->out.return_credentials; - a.out.rid = &rid; - a.out.negotiate_flags = r->out.negotiate_flags; - - return _netr_ServerAuthenticate3(p, &a); -} - -/************************************************************************* - * If schannel is required for this call test that it actually is available. - *************************************************************************/ -static NTSTATUS schannel_check_required(struct pipe_auth_data *auth_info, - const char *computer_name, - bool integrity, bool privacy) -{ - if (auth_info && auth_info->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - if (!privacy && !integrity) { - return NT_STATUS_OK; - } - - if ((!privacy && integrity) && - auth_info->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { - return NT_STATUS_OK; - } - - if ((privacy || integrity) && - auth_info->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - return NT_STATUS_OK; - } - } - - /* test didn't pass */ - DEBUG(0, ("schannel_check_required: [%s] is not using schannel\n", - computer_name)); - - return NT_STATUS_ACCESS_DENIED; -} - -/************************************************************************* - *************************************************************************/ - -static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - TALLOC_CTX *mem_ctx, - const char *computer_name, - struct netr_Authenticator *received_authenticator, - struct netr_Authenticator *return_authenticator, - struct netlogon_creds_CredentialState **creds_out) -{ - NTSTATUS status; - bool schannel_global_required = (lp_server_schannel() == true) ? true:false; - - if (schannel_global_required) { - status = schannel_check_required(&p->auth, - computer_name, - false, false); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - } - - status = schannel_check_creds_state(mem_ctx, lp_private_dir(), - computer_name, received_authenticator, - return_authenticator, creds_out); - - return status; -} - -/************************************************************************* - *************************************************************************/ - -static NTSTATUS netr_set_machine_account_password(TALLOC_CTX *mem_ctx, - struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *account_name, - struct samr_Password *nt_hash) -{ - NTSTATUS status; - NTSTATUS result = NT_STATUS_OK; - struct dcerpc_binding_handle *h = NULL; - static struct client_address client_id; - struct policy_handle user_handle; - uint32_t acct_ctrl; - union samr_UserInfo *info; - struct samr_UserInfo18 info18; - DATA_BLOB in,out; - - ZERO_STRUCT(user_handle); - - strlcpy(client_id.addr, "127.0.0.1", sizeof(client_id.addr)); - client_id.name = "127.0.0.1"; - - status = rpcint_binding_handle(mem_ctx, - &ndr_table_samr, - &client_id, - server_info, - msg_ctx, - &h); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = samr_find_machine_account(mem_ctx, - h, - account_name, - SEC_FLAG_MAXIMUM_ALLOWED, - NULL, - NULL, - &user_handle); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - status = dcerpc_samr_QueryUserInfo2(h, - mem_ctx, - &user_handle, - UserControlInformation, - &info, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - acct_ctrl = info->info16.acct_flags; - - if (!(acct_ctrl & ACB_WSTRUST || - acct_ctrl & ACB_SVRTRUST || - acct_ctrl & ACB_DOMTRUST)) { - status = NT_STATUS_NO_SUCH_USER; - goto out; - } - - if (acct_ctrl & ACB_DISABLED) { - status = NT_STATUS_ACCOUNT_DISABLED; - goto out; - } - - ZERO_STRUCT(info18); - - in = data_blob_const(nt_hash->hash, 16); - out = data_blob_talloc_zero(mem_ctx, 16); - sess_crypt_blob(&out, &in, &server_info->user_session_key, true); - memcpy(info18.nt_pwd.hash, out.data, out.length); - - info18.nt_pwd_active = true; - - info->info18 = info18; - - status = dcerpc_samr_SetUserInfo2(h, - mem_ctx, - &user_handle, - UserInternal1Information, - info, - &result); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - if (!NT_STATUS_IS_OK(result)) { - status = result; - goto out; - } - - out: - if (h && is_valid_policy_hnd(&user_handle)) { - dcerpc_samr_Close(h, mem_ctx, &user_handle, &result); - } - - return status; -} - -/************************************************************************* - _netr_ServerPasswordSet - *************************************************************************/ - -NTSTATUS _netr_ServerPasswordSet(struct pipes_struct *p, - struct netr_ServerPasswordSet *r) -{ - NTSTATUS status = NT_STATUS_OK; - int i; - struct netlogon_creds_CredentialState *creds; - - DEBUG(5,("_netr_ServerPasswordSet: %d\n", __LINE__)); - - become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(2,("_netr_ServerPasswordSet: netlogon_creds_server_step failed. Rejecting auth " - "request from client %s machine account %s\n", - r->in.computer_name, creds->computer_name)); - TALLOC_FREE(creds); - return status; - } - - DEBUG(3,("_netr_ServerPasswordSet: Server Password Set by remote machine:[%s] on account [%s]\n", - r->in.computer_name, creds->computer_name)); - - netlogon_creds_des_decrypt(creds, r->in.new_password); - - DEBUG(100,("_netr_ServerPasswordSet: new given value was :\n")); - for(i = 0; i < sizeof(r->in.new_password->hash); i++) - DEBUG(100,("%02X ", r->in.new_password->hash[i])); - DEBUG(100,("\n")); - - status = netr_set_machine_account_password(p->mem_ctx, - p->server_info, - p->msg_ctx, - creds->account_name, - r->in.new_password); - return status; -} - -/**************************************************************** - _netr_ServerPasswordSet2 -****************************************************************/ - -NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, - struct netr_ServerPasswordSet2 *r) -{ - NTSTATUS status; - struct netlogon_creds_CredentialState *creds; - DATA_BLOB plaintext; - struct samr_CryptPassword password_buf; - struct samr_Password nt_hash; - - become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(2,("_netr_ServerPasswordSet2: netlogon_creds_server_step " - "failed. Rejecting auth request from client %s machine account %s\n", - r->in.computer_name, creds->computer_name)); - TALLOC_FREE(creds); - return status; - } - - memcpy(password_buf.data, r->in.new_password->data, 512); - SIVAL(password_buf.data, 512, r->in.new_password->length); - netlogon_creds_arcfour_crypt(creds, password_buf.data, 516); - - if (!extract_pw_from_buffer(p->mem_ctx, password_buf.data, &plaintext)) { - return NT_STATUS_WRONG_PASSWORD; - } - - mdfour(nt_hash.hash, plaintext.data, plaintext.length); - - status = netr_set_machine_account_password(p->mem_ctx, - p->server_info, - p->msg_ctx, - creds->account_name, - &nt_hash); - return status; -} - -/************************************************************************* - _netr_LogonSamLogoff - *************************************************************************/ - -NTSTATUS _netr_LogonSamLogoff(struct pipes_struct *p, - struct netr_LogonSamLogoff *r) -{ - NTSTATUS status; - struct netlogon_creds_CredentialState *creds; - - become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); - unbecome_root(); - - return status; -} - -static NTSTATUS _netr_LogonSamLogon_check(const struct netr_LogonSamLogonEx *r) -{ - switch (r->in.logon_level) { - case NetlogonInteractiveInformation: - case NetlogonServiceInformation: - case NetlogonInteractiveTransitiveInformation: - case NetlogonServiceTransitiveInformation: - if (r->in.logon->password == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - switch (r->in.validation_level) { - case NetlogonValidationSamInfo: /* 2 */ - case NetlogonValidationSamInfo2: /* 3 */ - break; - case NetlogonValidationSamInfo4: /* 6 */ - if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { - DEBUG(10,("Not adding validation info level 6 " - "without ADS passdb backend\n")); - return NT_STATUS_INVALID_INFO_CLASS; - } - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - break; - case NetlogonNetworkInformation: - case NetlogonNetworkTransitiveInformation: - if (r->in.logon->network == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - switch (r->in.validation_level) { - case NetlogonValidationSamInfo: /* 2 */ - case NetlogonValidationSamInfo2: /* 3 */ - break; - case NetlogonValidationSamInfo4: /* 6 */ - if ((pdb_capabilities() & PDB_CAP_ADS) == 0) { - DEBUG(10,("Not adding validation info level 6 " - "without ADS passdb backend\n")); - return NT_STATUS_INVALID_INFO_CLASS; - } - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - break; - - case NetlogonGenericInformation: - if (r->in.logon->generic == NULL) { - return NT_STATUS_INVALID_PARAMETER; - } - - /* we don't support this here */ - return NT_STATUS_INVALID_PARAMETER; -#if 0 - switch (r->in.validation_level) { - /* TODO: case NetlogonValidationGenericInfo: 4 */ - case NetlogonValidationGenericInfo2: /* 5 */ - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - break; -#endif - default: - return NT_STATUS_INVALID_PARAMETER; - } - - return NT_STATUS_OK; -} - -/************************************************************************* - _netr_LogonSamLogon_base - *************************************************************************/ - -static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, - struct netr_LogonSamLogonEx *r, - struct netlogon_creds_CredentialState *creds) -{ - NTSTATUS status = NT_STATUS_OK; - union netr_LogonLevel *logon = r->in.logon; - const char *nt_username, *nt_domain, *nt_workstation; - struct auth_usersupplied_info *user_info = NULL; - struct auth_serversupplied_info *server_info = NULL; - struct auth_context *auth_context = NULL; - uint8_t pipe_session_key[16]; - bool process_creds = true; - const char *fn; - - switch (p->opnum) { - case NDR_NETR_LOGONSAMLOGON: - process_creds = true; - fn = "_netr_LogonSamLogon"; - break; - case NDR_NETR_LOGONSAMLOGONWITHFLAGS: - process_creds = true; - fn = "_netr_LogonSamLogonWithFlags"; - break; - case NDR_NETR_LOGONSAMLOGONEX: - process_creds = false; - fn = "_netr_LogonSamLogonEx"; - break; - default: - return NT_STATUS_INTERNAL_ERROR; - } - - *r->out.authoritative = true; /* authoritative response */ - - switch (r->in.validation_level) { - case 2: - r->out.validation->sam2 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo2); - if (!r->out.validation->sam2) { - return NT_STATUS_NO_MEMORY; - } - break; - case 3: - r->out.validation->sam3 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo3); - if (!r->out.validation->sam3) { - return NT_STATUS_NO_MEMORY; - } - break; - case 6: - r->out.validation->sam6 = TALLOC_ZERO_P(p->mem_ctx, struct netr_SamInfo6); - if (!r->out.validation->sam6) { - return NT_STATUS_NO_MEMORY; - } - break; - default: - DEBUG(0,("%s: bad validation_level value %d.\n", - fn, (int)r->in.validation_level)); - return NT_STATUS_INVALID_INFO_CLASS; - } - - switch (r->in.logon_level) { - case NetlogonInteractiveInformation: - case NetlogonServiceInformation: - case NetlogonInteractiveTransitiveInformation: - case NetlogonServiceTransitiveInformation: - nt_username = logon->password->identity_info.account_name.string ? - logon->password->identity_info.account_name.string : ""; - nt_domain = logon->password->identity_info.domain_name.string ? - logon->password->identity_info.domain_name.string : ""; - nt_workstation = logon->password->identity_info.workstation.string ? - logon->password->identity_info.workstation.string : ""; - - DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup())); - break; - case NetlogonNetworkInformation: - case NetlogonNetworkTransitiveInformation: - nt_username = logon->network->identity_info.account_name.string ? - logon->network->identity_info.account_name.string : ""; - nt_domain = logon->network->identity_info.domain_name.string ? - logon->network->identity_info.domain_name.string : ""; - nt_workstation = logon->network->identity_info.workstation.string ? - logon->network->identity_info.workstation.string : ""; - - DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup())); - break; - default: - DEBUG(2,("SAM Logon: unsupported switch value\n")); - return NT_STATUS_INVALID_INFO_CLASS; - } /* end switch */ - - DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain)); - fstrcpy(current_user_info.smb_name, nt_username); - sub_set_smb_name(nt_username); - - DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", - r->in.validation_level, nt_username)); - - status = NT_STATUS_OK; - - switch (r->in.logon_level) { - case NetlogonNetworkInformation: - case NetlogonNetworkTransitiveInformation: - { - const char *wksname = nt_workstation; - - status = make_auth_context_fixed(talloc_tos(), &auth_context, - logon->network->challenge); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* For a network logon, the workstation name comes in with two - * backslashes in the front. Strip them if they are there. */ - - if (*wksname == '\\') wksname++; - if (*wksname == '\\') wksname++; - - /* Standard challenge/response authentication */ - if (!make_user_info_netlogon_network(&user_info, - nt_username, nt_domain, - wksname, - logon->network->identity_info.parameter_control, - logon->network->lm.data, - logon->network->lm.length, - logon->network->nt.data, - logon->network->nt.length)) { - status = NT_STATUS_NO_MEMORY; - } - break; - } - case NetlogonInteractiveInformation: - case NetlogonServiceInformation: - case NetlogonInteractiveTransitiveInformation: - case NetlogonServiceTransitiveInformation: - - /* 'Interactive' authentication, supplies the password in its - MD4 form, encrypted with the session key. We will convert - this to challenge/response for the auth subsystem to chew - on */ - { - uint8_t chal[8]; - - status = make_auth_context_subsystem(talloc_tos(), - &auth_context); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - auth_context->get_ntlm_challenge(auth_context, chal); - - if (!make_user_info_netlogon_interactive(&user_info, - nt_username, nt_domain, - nt_workstation, - logon->password->identity_info.parameter_control, - chal, - logon->password->lmpassword.hash, - logon->password->ntpassword.hash, - creds->session_key)) { - status = NT_STATUS_NO_MEMORY; - } - break; - } - default: - DEBUG(2,("SAM Logon: unsupported switch value\n")); - return NT_STATUS_INVALID_INFO_CLASS; - } /* end switch */ - - if ( NT_STATUS_IS_OK(status) ) { - status = auth_context->check_ntlm_password(auth_context, - user_info, &server_info); - } - - TALLOC_FREE(auth_context); - free_user_info(&user_info); - - DEBUG(5,("%s: check_password returned status %s\n", - fn, nt_errstr(status))); - - /* Check account and password */ - - if (!NT_STATUS_IS_OK(status)) { - /* If we don't know what this domain is, we need to - indicate that we are not authoritative. This - allows the client to decide if it needs to try - a local user. Fix by jpjanosi@us.ibm.com, #2976 */ - if ( NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER) - && !strequal(nt_domain, get_global_sam_name()) - && !is_trusted_domain(nt_domain) ) - *r->out.authoritative = false; /* We are not authoritative */ - - TALLOC_FREE(server_info); - return status; - } - - if (server_info->guest) { - /* We don't like guest domain logons... */ - DEBUG(5,("%s: Attempted domain logon as GUEST " - "denied.\n", fn)); - TALLOC_FREE(server_info); - return NT_STATUS_LOGON_FAILURE; - } - - /* This is the point at which, if the login was successful, that - the SAM Local Security Authority should record that the user is - logged in to the domain. */ - - if (process_creds) { - /* Get the pipe session key from the creds. */ - memcpy(pipe_session_key, creds->session_key, 16); - } else { - struct schannel_state *schannel_auth; - /* Get the pipe session key from the schannel. */ - if ((p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) - || (p->auth.auth_ctx == NULL)) { - return NT_STATUS_INVALID_HANDLE; - } - - schannel_auth = talloc_get_type_abort(p->auth.auth_ctx, - struct schannel_state); - memcpy(pipe_session_key, schannel_auth->creds->session_key, 16); - } - - switch (r->in.validation_level) { - case 2: - status = serverinfo_to_SamInfo2(server_info, pipe_session_key, 16, - r->out.validation->sam2); - break; - case 3: - status = serverinfo_to_SamInfo3(server_info, pipe_session_key, 16, - r->out.validation->sam3); - break; - case 6: - status = serverinfo_to_SamInfo6(server_info, pipe_session_key, 16, - r->out.validation->sam6); - break; - } - - TALLOC_FREE(server_info); - - return status; -} - -/**************************************************************** - _netr_LogonSamLogonWithFlags -****************************************************************/ - -NTSTATUS _netr_LogonSamLogonWithFlags(struct pipes_struct *p, - struct netr_LogonSamLogonWithFlags *r) -{ - NTSTATUS status; - struct netlogon_creds_CredentialState *creds; - struct netr_LogonSamLogonEx r2; - struct netr_Authenticator return_authenticator; - - *r->out.authoritative = true; - - r2.in.server_name = r->in.server_name; - r2.in.computer_name = r->in.computer_name; - r2.in.logon_level = r->in.logon_level; - r2.in.logon = r->in.logon; - r2.in.validation_level = r->in.validation_level; - r2.in.flags = r->in.flags; - r2.out.validation = r->out.validation; - r2.out.authoritative = r->out.authoritative; - r2.out.flags = r->out.flags; - - status = _netr_LogonSamLogon_check(&r2); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - &return_authenticator, - &creds); - unbecome_root(); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = _netr_LogonSamLogon_base(p, &r2, creds); - - *r->out.return_authenticator = return_authenticator; - - return status; -} - -/************************************************************************* - _netr_LogonSamLogon - *************************************************************************/ - -NTSTATUS _netr_LogonSamLogon(struct pipes_struct *p, - struct netr_LogonSamLogon *r) -{ - NTSTATUS status; - struct netr_LogonSamLogonWithFlags r2; - uint32_t flags = 0; - - r2.in.server_name = r->in.server_name; - r2.in.computer_name = r->in.computer_name; - r2.in.credential = r->in.credential; - r2.in.logon_level = r->in.logon_level; - r2.in.logon = r->in.logon; - r2.in.validation_level = r->in.validation_level; - r2.in.return_authenticator = r->in.return_authenticator; - r2.in.flags = &flags; - r2.out.validation = r->out.validation; - r2.out.authoritative = r->out.authoritative; - r2.out.flags = &flags; - r2.out.return_authenticator = r->out.return_authenticator; - - status = _netr_LogonSamLogonWithFlags(p, &r2); - - return status; -} - -/************************************************************************* - _netr_LogonSamLogonEx - - no credential chaining. Map into net sam logon. - *************************************************************************/ - -NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, - struct netr_LogonSamLogonEx *r) -{ - NTSTATUS status; - struct netlogon_creds_CredentialState *creds = NULL; - - *r->out.authoritative = true; - - status = _netr_LogonSamLogon_check(r); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* Only allow this if the pipe is protected. */ - if (p->auth.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0,("_netr_LogonSamLogonEx: client %s not using schannel for netlogon\n", - get_remote_machine_name() )); - return NT_STATUS_INVALID_PARAMETER; - } - - become_root(); - status = schannel_get_creds_state(p->mem_ctx, lp_private_dir(), - r->in.computer_name, &creds); - unbecome_root(); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = _netr_LogonSamLogon_base(p, r, creds); - TALLOC_FREE(creds); - - return status; -} - -/************************************************************************* - _ds_enum_dom_trusts - *************************************************************************/ -#if 0 /* JERRY -- not correct */ - NTSTATUS _ds_enum_dom_trusts(struct pipes_struct *p, DS_Q_ENUM_DOM_TRUSTS *q_u, - DS_R_ENUM_DOM_TRUSTS *r_u) -{ - NTSTATUS status = NT_STATUS_OK; - - /* TODO: According to MSDN, the can only be executed against a - DC or domain member running Windows 2000 or later. Need - to test against a standalone 2k server and see what it - does. A windows 2000 DC includes its own domain in the - list. --jerry */ - - return status; -} -#endif /* JERRY */ - - -/**************************************************************** -****************************************************************/ - -WERROR _netr_LogonUasLogon(struct pipes_struct *p, - struct netr_LogonUasLogon *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_LogonUasLogoff(struct pipes_struct *p, - struct netr_LogonUasLogoff *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_DatabaseDeltas(struct pipes_struct *p, - struct netr_DatabaseDeltas *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_DatabaseSync(struct pipes_struct *p, - struct netr_DatabaseSync *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_AccountDeltas(struct pipes_struct *p, - struct netr_AccountDeltas *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_AccountSync(struct pipes_struct *p, - struct netr_AccountSync *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -static bool wb_getdcname(TALLOC_CTX *mem_ctx, - const char *domain, - const char **dcname, - uint32_t flags, - WERROR *werr) -{ - wbcErr result; - struct wbcDomainControllerInfo *dc_info = NULL; - - result = wbcLookupDomainController(domain, - flags, - &dc_info); - switch (result) { - case WBC_ERR_SUCCESS: - break; - case WBC_ERR_WINBIND_NOT_AVAILABLE: - return false; - case WBC_ERR_DOMAIN_NOT_FOUND: - *werr = WERR_NO_SUCH_DOMAIN; - return true; - default: - *werr = WERR_DOMAIN_CONTROLLER_NOT_FOUND; - return true; - } - - *dcname = talloc_strdup(mem_ctx, dc_info->dc_name); - wbcFreeMemory(dc_info); - if (!*dcname) { - *werr = WERR_NOMEM; - return false; - } - - *werr = WERR_OK; - - return true; -} - -/**************************************************************** - _netr_GetDcName -****************************************************************/ - -WERROR _netr_GetDcName(struct pipes_struct *p, - struct netr_GetDcName *r) -{ - NTSTATUS status; - WERROR werr; - uint32_t flags; - struct netr_DsRGetDCNameInfo *info; - bool ret; - - ret = wb_getdcname(p->mem_ctx, - r->in.domainname, - r->out.dcname, - WBC_LOOKUP_DC_IS_FLAT_NAME | - WBC_LOOKUP_DC_RETURN_FLAT_NAME | - WBC_LOOKUP_DC_PDC_REQUIRED, - &werr); - if (ret == true) { - return werr; - } - - flags = DS_PDC_REQUIRED | DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME; - - status = dsgetdcname(p->mem_ctx, - p->msg_ctx, - r->in.domainname, - NULL, - NULL, - flags, - &info); - if (!NT_STATUS_IS_OK(status)) { - return ntstatus_to_werror(status); - } - - *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc); - talloc_free(info); - if (!*r->out.dcname) { - return WERR_NOMEM; - } - - return WERR_OK; -} - -/**************************************************************** - _netr_GetAnyDCName -****************************************************************/ - -WERROR _netr_GetAnyDCName(struct pipes_struct *p, - struct netr_GetAnyDCName *r) -{ - NTSTATUS status; - WERROR werr; - uint32_t flags; - struct netr_DsRGetDCNameInfo *info; - bool ret; - - ret = wb_getdcname(p->mem_ctx, - r->in.domainname, - r->out.dcname, - WBC_LOOKUP_DC_IS_FLAT_NAME | - WBC_LOOKUP_DC_RETURN_FLAT_NAME, - &werr); - if (ret == true) { - return werr; - } - - flags = DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME; - - status = dsgetdcname(p->mem_ctx, - p->msg_ctx, - r->in.domainname, - NULL, - NULL, - flags, - &info); - if (!NT_STATUS_IS_OK(status)) { - return ntstatus_to_werror(status); - } - - *r->out.dcname = talloc_strdup(p->mem_ctx, info->dc_unc); - talloc_free(info); - if (!*r->out.dcname) { - return WERR_NOMEM; - } - - return WERR_OK; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_DatabaseSync2(struct pipes_struct *p, - struct netr_DatabaseSync2 *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_DatabaseRedo(struct pipes_struct *p, - struct netr_DatabaseRedo *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsRGetDCName(struct pipes_struct *p, - struct netr_DsRGetDCName *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_LogonGetCapabilities(struct pipes_struct *p, - struct netr_LogonGetCapabilities *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_NETRLOGONSETSERVICEBITS(struct pipes_struct *p, - struct netr_NETRLOGONSETSERVICEBITS *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_LogonGetTrustRid(struct pipes_struct *p, - struct netr_LogonGetTrustRid *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_NETRLOGONCOMPUTESERVERDIGEST(struct pipes_struct *p, - struct netr_NETRLOGONCOMPUTESERVERDIGEST *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_NETRLOGONCOMPUTECLIENTDIGEST(struct pipes_struct *p, - struct netr_NETRLOGONCOMPUTECLIENTDIGEST *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsRGetDCNameEx(struct pipes_struct *p, - struct netr_DsRGetDCNameEx *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsRGetSiteName(struct pipes_struct *p, - struct netr_DsRGetSiteName *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_LogonGetDomainInfo(struct pipes_struct *p, - struct netr_LogonGetDomainInfo *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_ServerPasswordGet(struct pipes_struct *p, - struct netr_ServerPasswordGet *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_NETRLOGONSENDTOSAM(struct pipes_struct *p, - struct netr_NETRLOGONSENDTOSAM *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsRAddressToSitenamesW(struct pipes_struct *p, - struct netr_DsRAddressToSitenamesW *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsRGetDCNameEx2(struct pipes_struct *p, - struct netr_DsRGetDCNameEx2 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN(struct pipes_struct *p, - struct netr_NETRLOGONGETTIMESERVICEPARENTDOMAIN *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_NetrEnumerateTrustedDomainsEx(struct pipes_struct *p, - struct netr_NetrEnumerateTrustedDomainsEx *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsRAddressToSitenamesExW(struct pipes_struct *p, - struct netr_DsRAddressToSitenamesExW *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsrGetDcSiteCoverageW(struct pipes_struct *p, - struct netr_DsrGetDcSiteCoverageW *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsrEnumerateDomainTrusts(struct pipes_struct *p, - struct netr_DsrEnumerateDomainTrusts *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsrDeregisterDNSHostRecords(struct pipes_struct *p, - struct netr_DsrDeregisterDNSHostRecords *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_ServerTrustPasswordsGet(struct pipes_struct *p, - struct netr_ServerTrustPasswordsGet *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _netr_DsRGetForestTrustInformation(struct pipes_struct *p, - struct netr_DsRGetForestTrustInformation *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p, - struct netr_GetForestTrustInformation *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p, - struct netr_ServerGetTrustInfo *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_Unused47(struct pipes_struct *p, - struct netr_Unused47 *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _netr_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p, - struct netr_DsrUpdateReadOnlyServerDnsRecords *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} diff --git a/source3/rpc_server/srv_ntsvcs_nt.c b/source3/rpc_server/srv_ntsvcs_nt.c deleted file mode 100644 index 4933cb31a5..0000000000 --- a/source3/rpc_server/srv_ntsvcs_nt.c +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * - * Copyright (C) Gerald (Jerry) Carter 2005. - * Copyright (C) Guenther Deschner 2008,2009. - * - * 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 . - */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_ntsvcs.h" -#include "services/svc_winreg_glue.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -/******************************************************************** -********************************************************************/ - -static char* get_device_path(TALLOC_CTX *mem_ctx, const char *device ) -{ - return talloc_asprintf(mem_ctx, "ROOT\\Legacy_%s\\0000", device); -} - -/******************************************************************** -********************************************************************/ - -WERROR _PNP_GetVersion(struct pipes_struct *p, - struct PNP_GetVersion *r) -{ - *r->out.version = 0x0400; /* no idea what this means */ - - return WERR_OK; -} - -/******************************************************************** -********************************************************************/ - -WERROR _PNP_GetDeviceListSize(struct pipes_struct *p, - struct PNP_GetDeviceListSize *r) -{ - char *devicepath; - - if ((r->in.flags & CM_GETIDLIST_FILTER_SERVICE) && - (!r->in.devicename)) { - return WERR_CM_INVALID_POINTER; - } - - if (!(devicepath = get_device_path(p->mem_ctx, r->in.devicename))) { - return WERR_NOMEM; - } - - *r->out.size = strlen(devicepath) + 2; - - TALLOC_FREE(devicepath); - - return WERR_OK; -} - -/**************************************************************** - _PNP_GetDeviceList -****************************************************************/ - -WERROR _PNP_GetDeviceList(struct pipes_struct *p, - struct PNP_GetDeviceList *r) -{ - char *devicepath; - uint32_t size = 0; - const char **multi_sz = NULL; - DATA_BLOB blob; - - if ((r->in.flags & CM_GETIDLIST_FILTER_SERVICE) && - (!r->in.filter)) { - return WERR_CM_INVALID_POINTER; - } - - if (!(devicepath = get_device_path(p->mem_ctx, r->in.filter))) { - return WERR_NOMEM; - } - - size = strlen(devicepath) + 2; - - if (*r->in.length < size) { - return WERR_CM_BUFFER_SMALL; - } - - multi_sz = talloc_zero_array(p->mem_ctx, const char *, 2); - if (!multi_sz) { - return WERR_NOMEM; - } - - multi_sz[0] = devicepath; - - if (!push_reg_multi_sz(multi_sz, &blob, multi_sz)) { - return WERR_NOMEM; - } - - if (*r->in.length < blob.length/2) { - return WERR_CM_BUFFER_SMALL; - } - - memcpy(r->out.buffer, blob.data, blob.length); - - return WERR_OK; -} - -/******************************************************************** -_PNP_GetDeviceRegProp -********************************************************************/ - -WERROR _PNP_GetDeviceRegProp(struct pipes_struct *p, - struct PNP_GetDeviceRegProp *r) -{ - char *ptr; - const char *result; - DATA_BLOB blob; - TALLOC_CTX *mem_ctx = NULL; - - switch( r->in.property ) { - case DEV_REGPROP_DESC: - - /* just parse the service name from the device path and then - lookup the display name */ - if ( !(ptr = strrchr_m( r->in.devicepath, '\\' )) ) - return WERR_GENERAL_FAILURE; - *ptr = '\0'; - - if ( !(ptr = strrchr_m( r->in.devicepath, '_' )) ) - return WERR_GENERAL_FAILURE; - ptr++; - - mem_ctx = talloc_stackframe(); - - result = svcctl_lookup_dispname(mem_ctx, - p->msg_ctx, - p->server_info, - ptr); - if (result == NULL) { - return WERR_GENERAL_FAILURE; - } - - if (!push_reg_sz(mem_ctx, &blob, result)) { - talloc_free(mem_ctx); - return WERR_GENERAL_FAILURE; - } - - if (*r->in.buffer_size < blob.length) { - *r->out.needed = blob.length; - *r->out.buffer_size = 0; - talloc_free(mem_ctx); - return WERR_CM_BUFFER_SMALL; - } - - r->out.buffer = (uint8_t *)talloc_memdup(p->mem_ctx, blob.data, blob.length); - talloc_free(mem_ctx); - if (!r->out.buffer) { - return WERR_NOMEM; - } - - *r->out.reg_data_type = REG_SZ; /* always 1...tested using a remove device manager connection */ - *r->out.buffer_size = blob.length; - *r->out.needed = blob.length; - - break; - - default: - *r->out.reg_data_type = 0x00437c98; /* ??? */ - return WERR_CM_NO_SUCH_VALUE; - } - - return WERR_OK; -} - -/******************************************************************** -********************************************************************/ - -WERROR _PNP_ValidateDeviceInstance(struct pipes_struct *p, - struct PNP_ValidateDeviceInstance *r) -{ - /* whatever dude */ - return WERR_OK; -} - -/******************************************************************** -********************************************************************/ - -WERROR _PNP_GetHwProfInfo(struct pipes_struct *p, - struct PNP_GetHwProfInfo *r) -{ - /* steal the incoming buffer */ - - r->out.info = r->in.info; - - /* Take the 5th Ammentment */ - - return WERR_CM_NO_MORE_HW_PROFILES; -} - -/******************************************************************** -********************************************************************/ - -WERROR _PNP_HwProfFlags(struct pipes_struct *p, - struct PNP_HwProfFlags *r) -{ - /* just nod your head */ - - return WERR_OK; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_Disconnect(struct pipes_struct *p, - struct PNP_Disconnect *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_Connect(struct pipes_struct *p, - struct PNP_Connect *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetGlobalState(struct pipes_struct *p, - struct PNP_GetGlobalState *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_InitDetection(struct pipes_struct *p, - struct PNP_InitDetection *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_ReportLogOn(struct pipes_struct *p, - struct PNP_ReportLogOn *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetRootDeviceInstance(struct pipes_struct *p, - struct PNP_GetRootDeviceInstance *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetRelatedDeviceInstance(struct pipes_struct *p, - struct PNP_GetRelatedDeviceInstance *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_EnumerateSubKeys(struct pipes_struct *p, - struct PNP_EnumerateSubKeys *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetDepth(struct pipes_struct *p, - struct PNP_GetDepth *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_SetDeviceRegProp(struct pipes_struct *p, - struct PNP_SetDeviceRegProp *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetClassInstance(struct pipes_struct *p, - struct PNP_GetClassInstance *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_CreateKey(struct pipes_struct *p, - struct PNP_CreateKey *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_DeleteRegistryKey(struct pipes_struct *p, - struct PNP_DeleteRegistryKey *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetClassCount(struct pipes_struct *p, - struct PNP_GetClassCount *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetClassName(struct pipes_struct *p, - struct PNP_GetClassName *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_DeleteClassKey(struct pipes_struct *p, - struct PNP_DeleteClassKey *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetInterfaceDeviceAlias(struct pipes_struct *p, - struct PNP_GetInterfaceDeviceAlias *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetInterfaceDeviceList(struct pipes_struct *p, - struct PNP_GetInterfaceDeviceList *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetInterfaceDeviceListSize(struct pipes_struct *p, - struct PNP_GetInterfaceDeviceListSize *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_RegisterDeviceClassAssociation(struct pipes_struct *p, - struct PNP_RegisterDeviceClassAssociation *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_UnregisterDeviceClassAssociation(struct pipes_struct *p, - struct PNP_UnregisterDeviceClassAssociation *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetClassRegProp(struct pipes_struct *p, - struct PNP_GetClassRegProp *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_SetClassRegProp(struct pipes_struct *p, - struct PNP_SetClassRegProp *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_CreateDevInst(struct pipes_struct *p, - struct PNP_CreateDevInst *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_DeviceInstanceAction(struct pipes_struct *p, - struct PNP_DeviceInstanceAction *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetDeviceStatus(struct pipes_struct *p, - struct PNP_GetDeviceStatus *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_SetDeviceProblem(struct pipes_struct *p, - struct PNP_SetDeviceProblem *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_DisableDevInst(struct pipes_struct *p, - struct PNP_DisableDevInst *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_UninstallDevInst(struct pipes_struct *p, - struct PNP_UninstallDevInst *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_AddID(struct pipes_struct *p, - struct PNP_AddID *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_RegisterDriver(struct pipes_struct *p, - struct PNP_RegisterDriver *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_QueryRemove(struct pipes_struct *p, - struct PNP_QueryRemove *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_RequestDeviceEject(struct pipes_struct *p, - struct PNP_RequestDeviceEject *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_IsDockStationPresent(struct pipes_struct *p, - struct PNP_IsDockStationPresent *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_RequestEjectPC(struct pipes_struct *p, - struct PNP_RequestEjectPC *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_AddEmptyLogConf(struct pipes_struct *p, - struct PNP_AddEmptyLogConf *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_FreeLogConf(struct pipes_struct *p, - struct PNP_FreeLogConf *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetFirstLogConf(struct pipes_struct *p, - struct PNP_GetFirstLogConf *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetNextLogConf(struct pipes_struct *p, - struct PNP_GetNextLogConf *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetLogConfPriority(struct pipes_struct *p, - struct PNP_GetLogConfPriority *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_AddResDes(struct pipes_struct *p, - struct PNP_AddResDes *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_FreeResDes(struct pipes_struct *p, - struct PNP_FreeResDes *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetNextResDes(struct pipes_struct *p, - struct PNP_GetNextResDes *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetResDesData(struct pipes_struct *p, - struct PNP_GetResDesData *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetResDesDataSize(struct pipes_struct *p, - struct PNP_GetResDesDataSize *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_ModifyResDes(struct pipes_struct *p, - struct PNP_ModifyResDes *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_DetectResourceLimit(struct pipes_struct *p, - struct PNP_DetectResourceLimit *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_QueryResConfList(struct pipes_struct *p, - struct PNP_QueryResConfList *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_SetHwProf(struct pipes_struct *p, - struct PNP_SetHwProf *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_QueryArbitratorFreeData(struct pipes_struct *p, - struct PNP_QueryArbitratorFreeData *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_QueryArbitratorFreeSize(struct pipes_struct *p, - struct PNP_QueryArbitratorFreeSize *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_RunDetection(struct pipes_struct *p, - struct PNP_RunDetection *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_RegisterNotification(struct pipes_struct *p, - struct PNP_RegisterNotification *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_UnregisterNotification(struct pipes_struct *p, - struct PNP_UnregisterNotification *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetCustomDevProp(struct pipes_struct *p, - struct PNP_GetCustomDevProp *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetVersionInternal(struct pipes_struct *p, - struct PNP_GetVersionInternal *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetBlockedDriverInfo(struct pipes_struct *p, - struct PNP_GetBlockedDriverInfo *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** -****************************************************************/ - -WERROR _PNP_GetServerSideDeviceInstallFlags(struct pipes_struct *p, - struct PNP_GetServerSideDeviceInstallFlags *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - diff --git a/source3/rpc_server/srv_rpc_register.c b/source3/rpc_server/srv_rpc_register.c index 8cb6e8e334..634adfdd78 100644 --- a/source3/rpc_server/srv_rpc_register.c +++ b/source3/rpc_server/srv_rpc_register.c @@ -38,8 +38,8 @@ #include "../librpc/gen_ndr/srv_wkssvc.h" #include "printing/nt_printing_migrate.h" -#include "rpc_server/srv_eventlog_reg.h" -#include "rpc_server/srv_svcctl_reg.h" +#include "rpc_server/eventlog/srv_eventlog_reg.h" +#include "rpc_server/svcctl/srv_svcctl_reg.h" #include "librpc/rpc/dcerpc_ep.h" diff --git a/source3/rpc_server/srv_samr_chgpasswd.c b/source3/rpc_server/srv_samr_chgpasswd.c deleted file mode 100644 index d31215b321..0000000000 --- a/source3/rpc_server/srv_samr_chgpasswd.c +++ /dev/null @@ -1,1132 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Samba utility functions - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Andrew Bartlett 2001-2004 - - 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 . -*/ - -/* These comments regard the code to change the user's unix password: */ - -/* fork a child process to exec passwd and write to its - * tty to change a users password. This is running as the - * user who is attempting to change the password. - */ - -/* - * This code was copied/borrowed and stolen from various sources. - * The primary source was the poppasswd.c from the authors of POPMail. This software - * was included as a client to change passwords using the 'passwd' program - * on the remote machine. - * - * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson - * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences - * and rights to modify, distribute or incorporate this change to the CAP suite or - * using it for any other reason are granted, so long as this disclaimer is left intact. - */ - -/* - This code was hacked considerably for inclusion in Samba, primarily - by Andrew.Tridgell@anu.edu.au. The biggest change was the addition - of the "password chat" option, which allows the easy runtime - specification of the expected sequence of events to change a - password. - */ - -#include "includes.h" -#include "../libcli/auth/libcli_auth.h" -#include "../lib/crypto/arcfour.h" -#include "rpc_server/srv_samr_util.h" - -#if ALLOW_CHANGE_PASSWORD - -static int findpty(char **slave) -{ - int master = -1; - char *line = NULL; - SMB_STRUCT_DIR *dirp = NULL; - const char *dpname; - - *slave = NULL; - -#if defined(HAVE_GRANTPT) - /* Try to open /dev/ptmx. If that fails, fall through to old method. */ - if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) { - grantpt(master); - unlockpt(master); - line = (char *)ptsname(master); - if (line) { - *slave = SMB_STRDUP(line); - } - - if (*slave == NULL) { - DEBUG(0, - ("findpty: Unable to create master/slave pty pair.\n")); - /* Stop fd leak on error. */ - close(master); - return -1; - } else { - DEBUG(10, - ("findpty: Allocated slave pty %s\n", *slave)); - return (master); - } - } -#endif /* HAVE_GRANTPT */ - - line = SMB_STRDUP("/dev/ptyXX"); - if (!line) { - return (-1); - } - - dirp = sys_opendir("/dev"); - if (!dirp) { - SAFE_FREE(line); - return (-1); - } - - while ((dpname = readdirname(dirp)) != NULL) { - if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) { - DEBUG(3, - ("pty: try to open %s, line was %s\n", dpname, - line)); - line[8] = dpname[3]; - line[9] = dpname[4]; - if ((master = sys_open(line, O_RDWR, 0)) >= 0) { - DEBUG(3, ("pty: opened %s\n", line)); - line[5] = 't'; - *slave = line; - sys_closedir(dirp); - return (master); - } - } - } - sys_closedir(dirp); - SAFE_FREE(line); - return (-1); -} - -static int dochild(int master, const char *slavedev, const struct passwd *pass, - const char *passwordprogram, bool as_root) -{ - int slave; - struct termios stermios; - gid_t gid; - uid_t uid; - char * const eptrs[1] = { NULL }; - - if (pass == NULL) - { - DEBUG(0, - ("dochild: user doesn't exist in the UNIX password database.\n")); - return False; - } - - gid = pass->pw_gid; - uid = pass->pw_uid; - - gain_root_privilege(); - - /* Start new session - gets rid of controlling terminal. */ - if (setsid() < 0) - { - DEBUG(3, - ("Weirdness, couldn't let go of controlling terminal\n")); - return (False); - } - - /* Open slave pty and acquire as new controlling terminal. */ - if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) - { - DEBUG(3, ("More weirdness, could not open %s\n", slavedev)); - return (False); - } -#if defined(TIOCSCTTY) && !defined(SUNOS5) - /* - * On patched Solaris 10 TIOCSCTTY is defined but seems not to work, - * see the discussion under - * https://bugzilla.samba.org/show_bug.cgi?id=5366. - */ - if (ioctl(slave, TIOCSCTTY, 0) < 0) - { - DEBUG(3, ("Error in ioctl call for slave pty\n")); - /* return(False); */ - } -#elif defined(I_PUSH) && defined(I_FIND) - if (ioctl(slave, I_FIND, "ptem") == 0) { - ioctl(slave, I_PUSH, "ptem"); - } - if (ioctl(slave, I_FIND, "ldterm") == 0) { - ioctl(slave, I_PUSH, "ldterm"); - } -#endif - - /* Close master. */ - close(master); - - /* Make slave stdin/out/err of child. */ - - if (dup2(slave, STDIN_FILENO) != STDIN_FILENO) - { - DEBUG(3, ("Could not re-direct stdin\n")); - return (False); - } - if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) - { - DEBUG(3, ("Could not re-direct stdout\n")); - return (False); - } - if (dup2(slave, STDERR_FILENO) != STDERR_FILENO) - { - DEBUG(3, ("Could not re-direct stderr\n")); - return (False); - } - if (slave > 2) - close(slave); - - /* Set proper terminal attributes - no echo, canonical input processing, - no map NL to CR/NL on output. */ - - if (tcgetattr(0, &stermios) < 0) - { - DEBUG(3, - ("could not read default terminal attributes on pty\n")); - return (False); - } - stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); - stermios.c_lflag |= ICANON; -#ifdef ONLCR - stermios.c_oflag &= ~(ONLCR); -#endif - if (tcsetattr(0, TCSANOW, &stermios) < 0) - { - DEBUG(3, ("could not set attributes of pty\n")); - return (False); - } - - /* make us completely into the right uid */ - if (!as_root) - { - become_user_permanently(uid, gid); - } - - DEBUG(10, - ("Invoking '%s' as password change program.\n", - passwordprogram)); - - /* execl() password-change application */ - if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0) - { - DEBUG(3, ("Bad status returned from %s\n", passwordprogram)); - return (False); - } - return (True); -} - -static int expect(int master, char *issue, char *expected) -{ - char buffer[1024]; - int attempts, timeout, nread; - size_t len; - bool match = False; - - for (attempts = 0; attempts < 2; attempts++) { - NTSTATUS status; - if (!strequal(issue, ".")) { - if (lp_passwd_chat_debug()) - DEBUG(100, ("expect: sending [%s]\n", issue)); - - if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) { - DEBUG(2,("expect: (short) write returned %d\n", - (int)len )); - return False; - } - } - - if (strequal(expected, ".")) - return True; - - /* Initial timeout. */ - timeout = lp_passwd_chat_timeout() * 1000; - nread = 0; - buffer[nread] = 0; - - while (True) { - status = read_fd_with_timeout( - master, buffer + nread, 1, - sizeof(buffer) - nread - 1, - timeout, &len); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(2, ("expect: read error %s\n", - nt_errstr(status))); - break; - } - nread += len; - buffer[nread] = 0; - - { - /* Eat leading/trailing whitespace before match. */ - char *str = SMB_STRDUP(buffer); - if (!str) { - DEBUG(2,("expect: ENOMEM\n")); - return False; - } - trim_char(str, ' ', ' '); - - if ((match = unix_wild_match(expected, str)) == True) { - /* Now data has started to return, lower timeout. */ - timeout = lp_passwd_chat_timeout() * 100; - } - SAFE_FREE(str); - } - } - - if (lp_passwd_chat_debug()) - DEBUG(100, ("expect: expected [%s] received [%s] match %s\n", - expected, buffer, match ? "yes" : "no" )); - - if (match) - break; - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(2, ("expect: %s\n", nt_errstr(status))); - return False; - } - } - - DEBUG(10,("expect: returning %s\n", match ? "True" : "False" )); - return match; -} - -static void pwd_sub(char *buf) -{ - all_string_sub(buf, "\\n", "\n", 0); - all_string_sub(buf, "\\r", "\r", 0); - all_string_sub(buf, "\\s", " ", 0); - all_string_sub(buf, "\\t", "\t", 0); -} - -static int talktochild(int master, const char *seq) -{ - TALLOC_CTX *frame = talloc_stackframe(); - int count = 0; - char *issue; - char *expected; - - issue = talloc_strdup(frame, "."); - if (!issue) { - TALLOC_FREE(frame); - return false; - } - - while (next_token_talloc(frame, &seq, &expected, NULL)) { - pwd_sub(expected); - count++; - - if (!expect(master, issue, expected)) { - DEBUG(3, ("Response %d incorrect\n", count)); - TALLOC_FREE(frame); - return false; - } - - if (!next_token_talloc(frame, &seq, &issue, NULL)) { - issue = talloc_strdup(frame, "."); - if (!issue) { - TALLOC_FREE(frame); - return false; - } - } - pwd_sub(issue); - } - - if (!strequal(issue, ".")) { - /* we have one final issue to send */ - expected = talloc_strdup(frame, "."); - if (!expected) { - TALLOC_FREE(frame); - return false; - } - if (!expect(master, issue, expected)) { - TALLOC_FREE(frame); - return False; - } - } - TALLOC_FREE(frame); - return (count > 0); -} - -static bool chat_with_program(char *passwordprogram, const struct passwd *pass, - char *chatsequence, bool as_root) -{ - char *slavedev = NULL; - int master; - pid_t pid, wpid; - int wstat; - bool chstat = False; - - if (pass == NULL) { - DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n")); - return False; - } - - /* allocate a pseudo-terminal device */ - if ((master = findpty(&slavedev)) < 0) { - DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name)); - return (False); - } - - /* - * We need to temporarily stop CatchChild from eating - * SIGCLD signals as it also eats the exit status code. JRA. - */ - - CatchChildLeaveStatus(); - - if ((pid = sys_fork()) < 0) { - DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name)); - SAFE_FREE(slavedev); - close(master); - CatchChild(); - return (False); - } - - /* we now have a pty */ - if (pid > 0) { /* This is the parent process */ - /* Don't need this anymore in parent. */ - SAFE_FREE(slavedev); - - if ((chstat = talktochild(master, chatsequence)) == False) { - DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name)); - kill(pid, SIGKILL); /* be sure to end this process */ - } - - while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { - if (errno == EINTR) { - errno = 0; - continue; - } - break; - } - - if (wpid < 0) { - DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n")); - close(master); - CatchChild(); - return (False); - } - - /* - * Go back to ignoring children. - */ - CatchChild(); - - close(master); - - if (pid != wpid) { - DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n")); - return (False); - } - if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) { - DEBUG(3, ("chat_with_program: The process exited with status %d \ -while we were waiting\n", WEXITSTATUS(wstat))); - return (False); - } -#if defined(WIFSIGNALLED) && defined(WTERMSIG) - else if (WIFSIGNALLED(wstat)) { - DEBUG(3, ("chat_with_program: The process was killed by signal %d \ -while we were waiting\n", WTERMSIG(wstat))); - return (False); - } -#endif - } else { - /* CHILD */ - - /* - * Lose any elevated privileges. - */ - drop_effective_capability(KERNEL_OPLOCK_CAPABILITY); - drop_effective_capability(DMAPI_ACCESS_CAPABILITY); - - /* make sure it doesn't freeze */ - alarm(20); - - if (as_root) - become_root(); - - DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name, - (int)getuid(), (int)getgid(), BOOLSTR(as_root) )); - chstat = dochild(master, slavedev, pass, passwordprogram, as_root); - - if (as_root) - unbecome_root(); - - /* - * The child should never return from dochild() .... - */ - - DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat)); - exit(1); - } - - if (chstat) - DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n", - (chstat ? "" : "un"), pass->pw_name)); - return (chstat); -} - -bool chgpasswd(const char *name, const char *rhost, const struct passwd *pass, - const char *oldpass, const char *newpass, bool as_root) -{ - char *passwordprogram = NULL; - char *chatsequence = NULL; - size_t i; - size_t len; - TALLOC_CTX *ctx = talloc_tos(); - - if (!oldpass) { - oldpass = ""; - } - - DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name)); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass)); -#endif - - /* Take the passed information and test it for minimum criteria */ - - /* Password is same as old password */ - if (strcmp(oldpass, newpass) == 0) { - /* don't allow same password */ - DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */ - return (False); /* inform the user */ - } - - /* - * Check the old and new passwords don't contain any control - * characters. - */ - - len = strlen(oldpass); - for (i = 0; i < len; i++) { - if (iscntrl((int)oldpass[i])) { - DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n")); - return False; - } - } - - len = strlen(newpass); - for (i = 0; i < len; i++) { - if (iscntrl((int)newpass[i])) { - DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n")); - return False; - } - } - -#ifdef WITH_PAM - if (lp_pam_password_change()) { - bool ret; -#ifdef HAVE_SETLOCALE - const char *prevlocale = setlocale(LC_ALL, "C"); -#endif - - if (as_root) - become_root(); - - if (pass) { - ret = smb_pam_passchange(pass->pw_name, rhost, - oldpass, newpass); - } else { - ret = smb_pam_passchange(name, rhost, oldpass, - newpass); - } - - if (as_root) - unbecome_root(); - -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL, prevlocale); -#endif - - return ret; - } -#endif - - /* A non-PAM password change just doen't make sense without a valid local user */ - - if (pass == NULL) { - DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name)); - return false; - } - - passwordprogram = talloc_strdup(ctx, lp_passwd_program()); - if (!passwordprogram || !*passwordprogram) { - DEBUG(2, ("chgpasswd: Null password program - no password changing\n")); - return false; - } - chatsequence = talloc_strdup(ctx, lp_passwd_chat()); - if (!chatsequence || !*chatsequence) { - DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n")); - return false; - } - - if (as_root) { - /* The password program *must* contain the user name to work. Fail if not. */ - if (strstr_m(passwordprogram, "%u") == NULL) { - DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \ -the string %%u, and the given string %s does not.\n", passwordprogram )); - return false; - } - } - - passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name); - if (!passwordprogram) { - return false; - } - - /* note that we do NOT substitute the %o and %n in the password program - as this would open up a security hole where the user could use - a new password containing shell escape characters */ - - chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name); - if (!chatsequence) { - return false; - } - chatsequence = talloc_all_string_sub(ctx, - chatsequence, - "%o", - oldpass); - if (!chatsequence) { - return false; - } - chatsequence = talloc_all_string_sub(ctx, - chatsequence, - "%n", - newpass); - return chat_with_program(passwordprogram, - pass, - chatsequence, - as_root); -} - -#else /* ALLOW_CHANGE_PASSWORD */ - -bool chgpasswd(const char *name, const struct passwd *pass, - const char *oldpass, const char *newpass, bool as_root) -{ - DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name)); - return (False); -} -#endif /* ALLOW_CHANGE_PASSWORD */ - -/*********************************************************** - Decrypt and verify a user password change. - - The 516 byte long buffers are encrypted with the old NT and - old LM passwords, and if the NT passwords are present, both - buffers contain a unicode string. - - After decrypting the buffers, check the password is correct by - matching the old hashed passwords with the passwords in the passdb. - -************************************************************/ - -static NTSTATUS check_oem_password(const char *user, - uchar password_encrypted_with_lm_hash[516], - const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], - const uchar old_nt_hash_encrypted[16], - struct samu *sampass, - char **pp_new_passwd) -{ - uchar null_pw[16]; - uchar null_ntpw[16]; - uint8 *password_encrypted; - const uint8 *encryption_key; - const uint8 *lanman_pw, *nt_pw; - uint32 acct_ctrl; - size_t new_pw_len; - uchar new_nt_hash[16]; - uchar new_lm_hash[16]; - uchar verifier[16]; - char no_pw[2]; - - bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted); - bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted); - - acct_ctrl = pdb_get_acct_ctrl(sampass); -#if 0 - /* I am convinced this check here is wrong, it is valid to - * change a password of a user that has a disabled account - gd */ - - if (acct_ctrl & ACB_DISABLED) { - DEBUG(2,("check_lanman_password: account %s disabled.\n", user)); - return NT_STATUS_ACCOUNT_DISABLED; - } -#endif - if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) { - /* construct a null password (in case one is needed */ - no_pw[0] = 0; - no_pw[1] = 0; - nt_lm_owf_gen(no_pw, null_ntpw, null_pw); - lanman_pw = null_pw; - nt_pw = null_pw; - - } else { - /* save pointers to passwords so we don't have to keep looking them up */ - if (lp_lanman_auth()) { - lanman_pw = pdb_get_lanman_passwd(sampass); - } else { - lanman_pw = NULL; - } - nt_pw = pdb_get_nt_passwd(sampass); - } - - if (nt_pw && nt_pass_set) { - /* IDEAL Case: passwords are in unicode, and we can - * read use the password encrypted with the NT hash - */ - password_encrypted = password_encrypted_with_nt_hash; - encryption_key = nt_pw; - } else if (lanman_pw && lm_pass_set) { - /* password may still be in unicode, but use LM hash version */ - password_encrypted = password_encrypted_with_lm_hash; - encryption_key = lanman_pw; - } else if (nt_pass_set) { - DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", - user)); - return NT_STATUS_WRONG_PASSWORD; - } else if (lm_pass_set) { - if (lp_lanman_auth()) { - DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n", - user)); - } else { - DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n", - user)); - } - return NT_STATUS_WRONG_PASSWORD; - } else { - DEBUG(1, ("password change requested for user %s, but no password supplied!\n", - user)); - return NT_STATUS_WRONG_PASSWORD; - } - - /* - * Decrypt the password with the key - */ - arcfour_crypt( password_encrypted, encryption_key, 516); - - if (!decode_pw_buffer(talloc_tos(), - password_encrypted, - pp_new_passwd, - &new_pw_len, - nt_pass_set ? CH_UTF16 : CH_DOS)) { - return NT_STATUS_WRONG_PASSWORD; - } - - /* - * To ensure we got the correct new password, hash it and - * use it as a key to test the passed old password. - */ - - if (nt_pass_set) { - /* NT passwords, verify the NT hash. */ - - /* Calculate the MD4 hash (NT compatible) of the password */ - memset(new_nt_hash, '\0', 16); - E_md4hash(*pp_new_passwd, new_nt_hash); - - if (nt_pw) { - /* - * check the NT verifier - */ - E_old_pw_hash(new_nt_hash, nt_pw, verifier); - if (memcmp(verifier, old_nt_hash_encrypted, 16)) { - DEBUG(0, ("check_oem_password: old nt " - "password doesn't match.\n")); - return NT_STATUS_WRONG_PASSWORD; - } - - /* We could check the LM password here, but there is - * little point, we already know the password is - * correct, and the LM password might not even be - * present. */ - - /* Further, LM hash generation algorithms - * differ with charset, so we could - * incorrectly fail a perfectly valid password - * change */ -#ifdef DEBUG_PASSWORD - DEBUG(100, - ("check_oem_password: password %s ok\n", *pp_new_passwd)); -#endif - return NT_STATUS_OK; - } - - if (lanman_pw) { - /* - * check the lm verifier - */ - E_old_pw_hash(new_nt_hash, lanman_pw, verifier); - if (memcmp(verifier, old_lm_hash_encrypted, 16)) { - DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); - return NT_STATUS_WRONG_PASSWORD; - } -#ifdef DEBUG_PASSWORD - DEBUG(100, - ("check_oem_password: password %s ok\n", *pp_new_passwd)); -#endif - return NT_STATUS_OK; - } - } - - if (lanman_pw && lm_pass_set) { - - E_deshash(*pp_new_passwd, new_lm_hash); - - /* - * check the lm verifier - */ - E_old_pw_hash(new_lm_hash, lanman_pw, verifier); - if (memcmp(verifier, old_lm_hash_encrypted, 16)) { - DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); - return NT_STATUS_WRONG_PASSWORD; - } - -#ifdef DEBUG_PASSWORD - DEBUG(100, - ("check_oem_password: password %s ok\n", *pp_new_passwd)); -#endif - return NT_STATUS_OK; - } - - /* should not be reached */ - return NT_STATUS_WRONG_PASSWORD; -} - -static bool password_in_history(uint8_t nt_pw[NT_HASH_LEN], - uint32_t pw_history_len, - const uint8_t *pw_history) -{ - static const uint8_t zero_md5_nt_pw[SALTED_MD5_HASH_LEN] = { 0, }; - int i; - - dump_data(100, nt_pw, NT_HASH_LEN); - dump_data(100, pw_history, PW_HISTORY_ENTRY_LEN * pw_history_len); - - for (i=0; i 2002, - * Copyright (C) Gerald (Jerry) Carter 2003-2004, - * Copyright (C) Simo Sorce 2003. - * Copyright (C) Volker Lendecke 2005. - * Copyright (C) Guenther Deschner 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 . - */ - -/* - * This is the implementation of the SAMR code. - */ - -#include "includes.h" -#include "smbd/globals.h" -#include "../libcli/auth/libcli_auth.h" -#include "../librpc/gen_ndr/srv_samr.h" -#include "rpc_server/srv_samr_util.h" -#include "../lib/crypto/arcfour.h" -#include "secrets.h" -#include "rpc_client/init_lsa.h" -#include "../libcli/security/security.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -#define SAMR_USR_RIGHTS_WRITE_PW \ - ( READ_CONTROL_ACCESS | \ - SAMR_USER_ACCESS_CHANGE_PASSWORD | \ - SAMR_USER_ACCESS_SET_LOC_COM) -#define SAMR_USR_RIGHTS_CANT_WRITE_PW \ - ( READ_CONTROL_ACCESS | SAMR_USER_ACCESS_SET_LOC_COM ) - -#define DISP_INFO_CACHE_TIMEOUT 10 - -#define MAX_SAM_ENTRIES_W2K 0x400 /* 1024 */ -#define MAX_SAM_ENTRIES_W95 50 - -struct samr_connect_info { - uint8_t dummy; -}; - -struct samr_domain_info { - struct dom_sid sid; - struct disp_info *disp_info; -}; - -struct samr_user_info { - struct dom_sid sid; -}; - -struct samr_group_info { - struct dom_sid sid; -}; - -struct samr_alias_info { - struct dom_sid sid; -}; - -typedef struct disp_info { - struct dom_sid sid; /* identify which domain this is. */ - struct pdb_search *users; /* querydispinfo 1 and 4 */ - struct pdb_search *machines; /* querydispinfo 2 */ - struct pdb_search *groups; /* querydispinfo 3 and 5, enumgroups */ - struct pdb_search *aliases; /* enumaliases */ - - uint32_t enum_acb_mask; - struct pdb_search *enum_users; /* enumusers with a mask */ - - struct timed_event *cache_timeout_event; /* cache idle timeout - * handler. */ -} DISP_INFO; - -static const struct generic_mapping sam_generic_mapping = { - GENERIC_RIGHTS_SAM_READ, - GENERIC_RIGHTS_SAM_WRITE, - GENERIC_RIGHTS_SAM_EXECUTE, - GENERIC_RIGHTS_SAM_ALL_ACCESS}; -static const struct generic_mapping dom_generic_mapping = { - GENERIC_RIGHTS_DOMAIN_READ, - GENERIC_RIGHTS_DOMAIN_WRITE, - GENERIC_RIGHTS_DOMAIN_EXECUTE, - GENERIC_RIGHTS_DOMAIN_ALL_ACCESS}; -static const struct generic_mapping usr_generic_mapping = { - GENERIC_RIGHTS_USER_READ, - GENERIC_RIGHTS_USER_WRITE, - GENERIC_RIGHTS_USER_EXECUTE, - GENERIC_RIGHTS_USER_ALL_ACCESS}; -static const struct generic_mapping usr_nopwchange_generic_mapping = { - GENERIC_RIGHTS_USER_READ, - GENERIC_RIGHTS_USER_WRITE, - GENERIC_RIGHTS_USER_EXECUTE & ~SAMR_USER_ACCESS_CHANGE_PASSWORD, - GENERIC_RIGHTS_USER_ALL_ACCESS}; -static const struct generic_mapping grp_generic_mapping = { - GENERIC_RIGHTS_GROUP_READ, - GENERIC_RIGHTS_GROUP_WRITE, - GENERIC_RIGHTS_GROUP_EXECUTE, - GENERIC_RIGHTS_GROUP_ALL_ACCESS}; -static const struct generic_mapping ali_generic_mapping = { - GENERIC_RIGHTS_ALIAS_READ, - GENERIC_RIGHTS_ALIAS_WRITE, - GENERIC_RIGHTS_ALIAS_EXECUTE, - GENERIC_RIGHTS_ALIAS_ALL_ACCESS}; - -/******************************************************************* -*******************************************************************/ - -static NTSTATUS make_samr_object_sd( TALLOC_CTX *ctx, struct security_descriptor **psd, size_t *sd_size, - const struct generic_mapping *map, - struct dom_sid *sid, uint32 sid_access ) -{ - struct dom_sid domadmin_sid; - struct security_ace ace[5]; /* at most 5 entries */ - size_t i = 0; - - struct security_acl *psa = NULL; - - /* basic access for Everyone */ - - init_sec_ace(&ace[i++], &global_sid_World, SEC_ACE_TYPE_ACCESS_ALLOWED, - map->generic_execute | map->generic_read, 0); - - /* add Full Access 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ - - init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, - SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); - init_sec_ace(&ace[i++], &global_sid_Builtin_Account_Operators, - SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); - - /* Add Full Access for Domain Admins if we are a DC */ - - if ( IS_DC ) { - sid_compose(&domadmin_sid, get_global_sam_sid(), - DOMAIN_RID_ADMINS); - init_sec_ace(&ace[i++], &domadmin_sid, - SEC_ACE_TYPE_ACCESS_ALLOWED, map->generic_all, 0); - } - - /* if we have a sid, give it some special access */ - - if ( sid ) { - init_sec_ace(&ace[i++], sid, SEC_ACE_TYPE_ACCESS_ALLOWED, sid_access, 0); - } - - /* create the security descriptor */ - - if ((psa = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) == NULL) - return NT_STATUS_NO_MEMORY; - - if ((*psd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1, - SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, - psa, sd_size)) == NULL) - return NT_STATUS_NO_MEMORY; - - return NT_STATUS_OK; -} - -/******************************************************************* - Checks if access to an object should be granted, and returns that - level of access for further checks. - - If the user has either of needed_priv_1 or needed_priv_2 then they - get the rights in rights_mask in addition to any calulated rights. - - This handles the unusual case where we need to allow two different - privileges to obtain exactly the same rights, which occours only in - SAMR. -********************************************************************/ - -NTSTATUS access_check_object( struct security_descriptor *psd, struct security_token *token, - enum sec_privilege needed_priv_1, enum sec_privilege needed_priv_2, - uint32 rights_mask, - uint32 des_access, uint32 *acc_granted, - const char *debug ) -{ - NTSTATUS status = NT_STATUS_ACCESS_DENIED; - uint32 saved_mask = 0; - - /* check privileges; certain SAM access bits should be overridden - by privileges (mostly having to do with creating/modifying/deleting - users and groups) */ - - if ((needed_priv_1 != SEC_PRIV_INVALID && security_token_has_privilege(token, needed_priv_1)) || - (needed_priv_2 != SEC_PRIV_INVALID && security_token_has_privilege(token, needed_priv_2))) { - saved_mask = (des_access & rights_mask); - des_access &= ~saved_mask; - - DEBUG(4,("access_check_object: user rights access mask [0x%x]\n", - rights_mask)); - } - - - /* check the security descriptor first */ - - status = se_access_check(psd, token, des_access, acc_granted); - if (NT_STATUS_IS_OK(status)) { - goto done; - } - - /* give root a free pass */ - - if ( geteuid() == sec_initial_uid() ) { - - DEBUG(4,("%s: ACCESS should be DENIED (requested: %#010x)\n", debug, des_access)); - DEBUGADD(4,("but overritten by euid == sec_initial_uid()\n")); - - *acc_granted = des_access; - - status = NT_STATUS_OK; - goto done; - } - - -done: - /* add in any bits saved during the privilege check (only - matters is status is ok) */ - - *acc_granted |= rights_mask; - - DEBUG(4,("%s: access %s (requested: 0x%08x, granted: 0x%08x)\n", - debug, NT_STATUS_IS_OK(status) ? "GRANTED" : "DENIED", - des_access, *acc_granted)); - - return status; -} - - -/******************************************************************* - Map any MAXIMUM_ALLOWED_ACCESS request to a valid access set. -********************************************************************/ - -void map_max_allowed_access(const struct security_token *nt_token, - const struct unix_user_token *unix_token, - uint32_t *pacc_requested) -{ - if (!((*pacc_requested) & MAXIMUM_ALLOWED_ACCESS)) { - return; - } - *pacc_requested &= ~MAXIMUM_ALLOWED_ACCESS; - - /* At least try for generic read|execute - Everyone gets that. */ - *pacc_requested = GENERIC_READ_ACCESS|GENERIC_EXECUTE_ACCESS; - - /* root gets anything. */ - if (unix_token->uid == sec_initial_uid()) { - *pacc_requested |= GENERIC_ALL_ACCESS; - return; - } - - /* Full Access for 'BUILTIN\Administrators' and 'BUILTIN\Account Operators */ - - if (security_token_has_sid(nt_token, &global_sid_Builtin_Administrators) || - security_token_has_sid(nt_token, &global_sid_Builtin_Account_Operators)) { - *pacc_requested |= GENERIC_ALL_ACCESS; - return; - } - - /* Full access for DOMAIN\Domain Admins. */ - if ( IS_DC ) { - struct dom_sid domadmin_sid; - sid_compose(&domadmin_sid, get_global_sam_sid(), - DOMAIN_RID_ADMINS); - if (security_token_has_sid(nt_token, &domadmin_sid)) { - *pacc_requested |= GENERIC_ALL_ACCESS; - return; - } - } - /* TODO ! Check privileges. */ -} - -/******************************************************************* - Fetch or create a dispinfo struct. -********************************************************************/ - -static DISP_INFO *get_samr_dispinfo_by_sid(const struct dom_sid *psid) -{ - /* - * We do a static cache for DISP_INFO's here. Explanation can be found - * in Jeremy's checkin message to r11793: - * - * Fix the SAMR cache so it works across completely insane - * client behaviour (ie.: - * open pipe/open SAMR handle/enumerate 0 - 1024 - * close SAMR handle, close pipe. - * open pipe/open SAMR handle/enumerate 1024 - 2048... - * close SAMR handle, close pipe. - * And on ad-nausium. Amazing.... probably object-oriented - * client side programming in action yet again. - * This change should *massively* improve performance when - * enumerating users from an LDAP database. - * Jeremy. - * - * "Our" and the builtin domain are the only ones where we ever - * enumerate stuff, so just cache 2 entries. - */ - - static struct disp_info *builtin_dispinfo; - static struct disp_info *domain_dispinfo; - - /* There are two cases to consider here: - 1) The SID is a domain SID and we look for an equality match, or - 2) This is an account SID and so we return the DISP_INFO* for our - domain */ - - if (psid == NULL) { - return NULL; - } - - if (sid_check_is_builtin(psid) || sid_check_is_in_builtin(psid)) { - /* - * Necessary only once, but it does not really hurt. - */ - if (builtin_dispinfo == NULL) { - builtin_dispinfo = talloc_zero(NULL, struct disp_info); - if (builtin_dispinfo == NULL) { - return NULL; - } - } - sid_copy(&builtin_dispinfo->sid, &global_sid_Builtin); - - return builtin_dispinfo; - } - - if (sid_check_is_domain(psid) || sid_check_is_in_our_domain(psid)) { - /* - * Necessary only once, but it does not really hurt. - */ - if (domain_dispinfo == NULL) { - domain_dispinfo = talloc_zero(NULL, struct disp_info); - if (domain_dispinfo == NULL) { - return NULL; - } - } - sid_copy(&domain_dispinfo->sid, get_global_sam_sid()); - - return domain_dispinfo; - } - - return NULL; -} - -/******************************************************************* - Function to free the per SID data. - ********************************************************************/ - -static void free_samr_cache(DISP_INFO *disp_info) -{ - DEBUG(10, ("free_samr_cache: deleting cache for SID %s\n", - sid_string_dbg(&disp_info->sid))); - - /* We need to become root here because the paged search might have to - * tell the LDAP server we're not interested in the rest anymore. */ - - become_root(); - - TALLOC_FREE(disp_info->users); - TALLOC_FREE(disp_info->machines); - TALLOC_FREE(disp_info->groups); - TALLOC_FREE(disp_info->aliases); - TALLOC_FREE(disp_info->enum_users); - - unbecome_root(); -} - -/******************************************************************* - Idle event handler. Throw away the disp info cache. - ********************************************************************/ - -static void disp_info_cache_idle_timeout_handler(struct event_context *ev_ctx, - struct timed_event *te, - struct timeval now, - void *private_data) -{ - DISP_INFO *disp_info = (DISP_INFO *)private_data; - - TALLOC_FREE(disp_info->cache_timeout_event); - - DEBUG(10, ("disp_info_cache_idle_timeout_handler: caching timed " - "out\n")); - free_samr_cache(disp_info); -} - -/******************************************************************* - Setup cache removal idle event handler. - ********************************************************************/ - -static void set_disp_info_cache_timeout(DISP_INFO *disp_info, time_t secs_fromnow) -{ - /* Remove any pending timeout and update. */ - - TALLOC_FREE(disp_info->cache_timeout_event); - - DEBUG(10,("set_disp_info_cache_timeout: caching enumeration for " - "SID %s for %u seconds\n", sid_string_dbg(&disp_info->sid), - (unsigned int)secs_fromnow )); - - disp_info->cache_timeout_event = event_add_timed( - server_event_context(), NULL, - timeval_current_ofs(secs_fromnow, 0), - disp_info_cache_idle_timeout_handler, (void *)disp_info); -} - -/******************************************************************* - Force flush any cache. We do this on any samr_set_xxx call. - We must also remove the timeout handler. - ********************************************************************/ - -static void force_flush_samr_cache(const struct dom_sid *sid) -{ - struct disp_info *disp_info = get_samr_dispinfo_by_sid(sid); - - if ((disp_info == NULL) || (disp_info->cache_timeout_event == NULL)) { - return; - } - - DEBUG(10,("force_flush_samr_cache: clearing idle event\n")); - TALLOC_FREE(disp_info->cache_timeout_event); - free_samr_cache(disp_info); -} - -/******************************************************************* - Ensure password info is never given out. Paranioa... JRA. - ********************************************************************/ - -static void samr_clear_sam_passwd(struct samu *sam_pass) -{ - - if (!sam_pass) - return; - - /* These now zero out the old password */ - - pdb_set_lanman_passwd(sam_pass, NULL, PDB_DEFAULT); - pdb_set_nt_passwd(sam_pass, NULL, PDB_DEFAULT); -} - -static uint32 count_sam_users(struct disp_info *info, uint32 acct_flags) -{ - struct samr_displayentry *entry; - - if (sid_check_is_builtin(&info->sid)) { - /* No users in builtin. */ - return 0; - } - - if (info->users == NULL) { - info->users = pdb_search_users(info, acct_flags); - if (info->users == NULL) { - return 0; - } - } - /* Fetch the last possible entry, thus trigger an enumeration */ - pdb_search_entries(info->users, 0xffffffff, 1, &entry); - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT); - - return info->users->num_entries; -} - -static uint32 count_sam_groups(struct disp_info *info) -{ - struct samr_displayentry *entry; - - if (sid_check_is_builtin(&info->sid)) { - /* No groups in builtin. */ - return 0; - } - - if (info->groups == NULL) { - info->groups = pdb_search_groups(info); - if (info->groups == NULL) { - return 0; - } - } - /* Fetch the last possible entry, thus trigger an enumeration */ - pdb_search_entries(info->groups, 0xffffffff, 1, &entry); - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT); - - return info->groups->num_entries; -} - -static uint32 count_sam_aliases(struct disp_info *info) -{ - struct samr_displayentry *entry; - - if (info->aliases == NULL) { - info->aliases = pdb_search_aliases(info, &info->sid); - if (info->aliases == NULL) { - return 0; - } - } - /* Fetch the last possible entry, thus trigger an enumeration */ - pdb_search_entries(info->aliases, 0xffffffff, 1, &entry); - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(info, DISP_INFO_CACHE_TIMEOUT); - - return info->aliases->num_entries; -} - -/******************************************************************* - _samr_Close - ********************************************************************/ - -NTSTATUS _samr_Close(struct pipes_struct *p, struct samr_Close *r) -{ - if (!close_policy_hnd(p, r->in.handle)) { - return NT_STATUS_INVALID_HANDLE; - } - - ZERO_STRUCTP(r->out.handle); - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_OpenDomain - ********************************************************************/ - -NTSTATUS _samr_OpenDomain(struct pipes_struct *p, - struct samr_OpenDomain *r) -{ - struct samr_connect_info *cinfo; - struct samr_domain_info *dinfo; - struct security_descriptor *psd = NULL; - uint32 acc_granted; - uint32 des_access = r->in.access_mask; - NTSTATUS status; - size_t sd_size; - uint32_t extra_access = SAMR_DOMAIN_ACCESS_CREATE_USER; - - /* find the connection policy handle. */ - - cinfo = policy_handle_find(p, r->in.connect_handle, 0, NULL, - struct samr_connect_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /*check if access can be granted as requested by client. */ - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - make_samr_object_sd( p->mem_ctx, &psd, &sd_size, &dom_generic_mapping, NULL, 0 ); - se_map_generic( &des_access, &dom_generic_mapping ); - - /* - * Users with SeAddUser get the ability to manipulate groups - * and aliases. - */ - if (security_token_has_privilege(p->server_info->security_token, SEC_PRIV_ADD_USERS)) { - extra_access |= (SAMR_DOMAIN_ACCESS_CREATE_GROUP | - SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS | - SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT | - SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS | - SAMR_DOMAIN_ACCESS_CREATE_ALIAS); - } - - /* - * Users with SeMachineAccount or SeAddUser get additional - * SAMR_DOMAIN_ACCESS_CREATE_USER access. - */ - - status = access_check_object( psd, p->server_info->security_token, - SEC_PRIV_MACHINE_ACCOUNT, SEC_PRIV_ADD_USERS, - extra_access, des_access, - &acc_granted, "_samr_OpenDomain" ); - - if ( !NT_STATUS_IS_OK(status) ) - return status; - - if (!sid_check_is_domain(r->in.sid) && - !sid_check_is_builtin(r->in.sid)) { - return NT_STATUS_NO_SUCH_DOMAIN; - } - - dinfo = policy_handle_create(p, r->out.domain_handle, acc_granted, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - dinfo->sid = *r->in.sid; - dinfo->disp_info = get_samr_dispinfo_by_sid(r->in.sid); - - DEBUG(5,("_samr_OpenDomain: %d\n", __LINE__)); - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_GetUserPwInfo - ********************************************************************/ - -NTSTATUS _samr_GetUserPwInfo(struct pipes_struct *p, - struct samr_GetUserPwInfo *r) -{ - struct samr_user_info *uinfo; - enum lsa_SidType sid_type; - uint32_t min_password_length = 0; - uint32_t password_properties = 0; - bool ret = false; - NTSTATUS status; - - DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__)); - - uinfo = policy_handle_find(p, r->in.user_handle, - SAMR_USER_ACCESS_GET_ATTRIBUTES, NULL, - struct samr_user_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!sid_check_is_in_our_domain(&uinfo->sid)) { - return NT_STATUS_OBJECT_TYPE_MISMATCH; - } - - become_root(); - ret = lookup_sid(p->mem_ctx, &uinfo->sid, NULL, NULL, &sid_type); - unbecome_root(); - if (ret == false) { - return NT_STATUS_NO_SUCH_USER; - } - - switch (sid_type) { - case SID_NAME_USER: - become_root(); - pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, - &min_password_length); - pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, - &password_properties); - unbecome_root(); - - if (lp_check_password_script() && *lp_check_password_script()) { - password_properties |= DOMAIN_PASSWORD_COMPLEX; - } - - break; - default: - break; - } - - r->out.info->min_password_length = min_password_length; - r->out.info->password_properties = password_properties; - - DEBUG(5,("_samr_GetUserPwInfo: %d\n", __LINE__)); - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_SetSecurity - ********************************************************************/ - -NTSTATUS _samr_SetSecurity(struct pipes_struct *p, - struct samr_SetSecurity *r) -{ - struct samr_user_info *uinfo; - uint32 i; - struct security_acl *dacl; - bool ret; - struct samu *sampass=NULL; - NTSTATUS status; - - uinfo = policy_handle_find(p, r->in.handle, - SAMR_USER_ACCESS_SET_ATTRIBUTES, NULL, - struct samr_user_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!(sampass = samu_new( p->mem_ctx))) { - DEBUG(0,("No memory!\n")); - return NT_STATUS_NO_MEMORY; - } - - /* get the user record */ - become_root(); - ret = pdb_getsampwsid(sampass, &uinfo->sid); - unbecome_root(); - - if (!ret) { - DEBUG(4, ("User %s not found\n", - sid_string_dbg(&uinfo->sid))); - TALLOC_FREE(sampass); - return NT_STATUS_INVALID_HANDLE; - } - - dacl = r->in.sdbuf->sd->dacl; - for (i=0; i < dacl->num_aces; i++) { - if (dom_sid_equal(&uinfo->sid, &dacl->aces[i].trustee)) { - ret = pdb_set_pass_can_change(sampass, - (dacl->aces[i].access_mask & - SAMR_USER_ACCESS_CHANGE_PASSWORD) ? - True: False); - break; - } - } - - if (!ret) { - TALLOC_FREE(sampass); - return NT_STATUS_ACCESS_DENIED; - } - - become_root(); - status = pdb_update_sam_account(sampass); - unbecome_root(); - - TALLOC_FREE(sampass); - - return status; -} - -/******************************************************************* - build correct perms based on policies and password times for _samr_query_sec_obj -*******************************************************************/ -static bool check_change_pw_access(TALLOC_CTX *mem_ctx, struct dom_sid *user_sid) -{ - struct samu *sampass=NULL; - bool ret; - - if ( !(sampass = samu_new( mem_ctx )) ) { - DEBUG(0,("No memory!\n")); - return False; - } - - become_root(); - ret = pdb_getsampwsid(sampass, user_sid); - unbecome_root(); - - if (ret == False) { - DEBUG(4,("User %s not found\n", sid_string_dbg(user_sid))); - TALLOC_FREE(sampass); - return False; - } - - DEBUG(3,("User:[%s]\n", pdb_get_username(sampass) )); - - if (pdb_get_pass_can_change(sampass)) { - TALLOC_FREE(sampass); - return True; - } - TALLOC_FREE(sampass); - return False; -} - - -/******************************************************************* - _samr_QuerySecurity - ********************************************************************/ - -NTSTATUS _samr_QuerySecurity(struct pipes_struct *p, - struct samr_QuerySecurity *r) -{ - struct samr_connect_info *cinfo; - struct samr_domain_info *dinfo; - struct samr_user_info *uinfo; - struct samr_group_info *ginfo; - struct samr_alias_info *ainfo; - NTSTATUS status; - struct security_descriptor * psd = NULL; - size_t sd_size = 0; - - cinfo = policy_handle_find(p, r->in.handle, - SEC_STD_READ_CONTROL, NULL, - struct samr_connect_info, &status); - if (NT_STATUS_IS_OK(status)) { - DEBUG(5,("_samr_QuerySecurity: querying security on SAM\n")); - status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, - &sam_generic_mapping, NULL, 0); - goto done; - } - - dinfo = policy_handle_find(p, r->in.handle, - SEC_STD_READ_CONTROL, NULL, - struct samr_domain_info, &status); - if (NT_STATUS_IS_OK(status)) { - DEBUG(5,("_samr_QuerySecurity: querying security on Domain " - "with SID: %s\n", sid_string_dbg(&dinfo->sid))); - /* - * TODO: Builtin probably needs a different SD with restricted - * write access - */ - status = make_samr_object_sd(p->mem_ctx, &psd, &sd_size, - &dom_generic_mapping, NULL, 0); - goto done; - } - - uinfo = policy_handle_find(p, r->in.handle, - SEC_STD_READ_CONTROL, NULL, - struct samr_user_info, &status); - if (NT_STATUS_IS_OK(status)) { - DEBUG(10,("_samr_QuerySecurity: querying security on user " - "Object with SID: %s\n", - sid_string_dbg(&uinfo->sid))); - if (check_change_pw_access(p->mem_ctx, &uinfo->sid)) { - status = make_samr_object_sd( - p->mem_ctx, &psd, &sd_size, - &usr_generic_mapping, - &uinfo->sid, SAMR_USR_RIGHTS_WRITE_PW); - } else { - status = make_samr_object_sd( - p->mem_ctx, &psd, &sd_size, - &usr_nopwchange_generic_mapping, - &uinfo->sid, SAMR_USR_RIGHTS_CANT_WRITE_PW); - } - goto done; - } - - ginfo = policy_handle_find(p, r->in.handle, - SEC_STD_READ_CONTROL, NULL, - struct samr_group_info, &status); - if (NT_STATUS_IS_OK(status)) { - /* - * TODO: different SDs have to be generated for aliases groups - * and users. Currently all three get a default user SD - */ - DEBUG(10,("_samr_QuerySecurity: querying security on group " - "Object with SID: %s\n", - sid_string_dbg(&ginfo->sid))); - status = make_samr_object_sd( - p->mem_ctx, &psd, &sd_size, - &usr_nopwchange_generic_mapping, - &ginfo->sid, SAMR_USR_RIGHTS_CANT_WRITE_PW); - goto done; - } - - ainfo = policy_handle_find(p, r->in.handle, - SEC_STD_READ_CONTROL, NULL, - struct samr_alias_info, &status); - if (NT_STATUS_IS_OK(status)) { - /* - * TODO: different SDs have to be generated for aliases groups - * and users. Currently all three get a default user SD - */ - DEBUG(10,("_samr_QuerySecurity: querying security on alias " - "Object with SID: %s\n", - sid_string_dbg(&ainfo->sid))); - status = make_samr_object_sd( - p->mem_ctx, &psd, &sd_size, - &usr_nopwchange_generic_mapping, - &ainfo->sid, SAMR_USR_RIGHTS_CANT_WRITE_PW); - goto done; - } - - return NT_STATUS_OBJECT_TYPE_MISMATCH; -done: - if ((*r->out.sdbuf = make_sec_desc_buf(p->mem_ctx, sd_size, psd)) == NULL) - return NT_STATUS_NO_MEMORY; - - return status; -} - -/******************************************************************* -makes a SAM_ENTRY / UNISTR2* structure from a user list. -********************************************************************/ - -static NTSTATUS make_user_sam_entry_list(TALLOC_CTX *ctx, - struct samr_SamEntry **sam_pp, - uint32_t num_entries, - uint32_t start_idx, - struct samr_displayentry *entries) -{ - uint32_t i; - struct samr_SamEntry *sam; - - *sam_pp = NULL; - - if (num_entries == 0) { - return NT_STATUS_OK; - } - - sam = TALLOC_ZERO_ARRAY(ctx, struct samr_SamEntry, num_entries); - if (sam == NULL) { - DEBUG(0, ("make_user_sam_entry_list: TALLOC_ZERO failed!\n")); - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < num_entries; i++) { -#if 0 - /* - * usrmgr expects a non-NULL terminated string with - * trust relationships - */ - if (entries[i].acct_flags & ACB_DOMTRUST) { - init_unistr2(&uni_temp_name, entries[i].account_name, - UNI_FLAGS_NONE); - } else { - init_unistr2(&uni_temp_name, entries[i].account_name, - UNI_STR_TERMINATE); - } -#endif - init_lsa_String(&sam[i].name, entries[i].account_name); - sam[i].idx = entries[i].rid; - } - - *sam_pp = sam; - - return NT_STATUS_OK; -} - -#define MAX_SAM_ENTRIES MAX_SAM_ENTRIES_W2K - -/******************************************************************* - _samr_EnumDomainUsers - ********************************************************************/ - -NTSTATUS _samr_EnumDomainUsers(struct pipes_struct *p, - struct samr_EnumDomainUsers *r) -{ - NTSTATUS status; - struct samr_domain_info *dinfo; - int num_account; - uint32 enum_context = *r->in.resume_handle; - enum remote_arch_types ra_type = get_remote_arch(); - int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K; - uint32 max_entries = max_sam_entries; - struct samr_displayentry *entries = NULL; - struct samr_SamArray *samr_array = NULL; - struct samr_SamEntry *samr_entries = NULL; - - DEBUG(5,("_samr_EnumDomainUsers: %d\n", __LINE__)); - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); - if (!samr_array) { - return NT_STATUS_NO_MEMORY; - } - *r->out.sam = samr_array; - - if (sid_check_is_builtin(&dinfo->sid)) { - /* No users in builtin. */ - *r->out.resume_handle = *r->in.resume_handle; - DEBUG(5,("_samr_EnumDomainUsers: No users in BUILTIN\n")); - return status; - } - - become_root(); - - /* AS ROOT !!!! */ - - if ((dinfo->disp_info->enum_users != NULL) && - (dinfo->disp_info->enum_acb_mask != r->in.acct_flags)) { - TALLOC_FREE(dinfo->disp_info->enum_users); - } - - if (dinfo->disp_info->enum_users == NULL) { - dinfo->disp_info->enum_users = pdb_search_users( - dinfo->disp_info, r->in.acct_flags); - dinfo->disp_info->enum_acb_mask = r->in.acct_flags; - } - - if (dinfo->disp_info->enum_users == NULL) { - /* END AS ROOT !!!! */ - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - - num_account = pdb_search_entries(dinfo->disp_info->enum_users, - enum_context, max_entries, - &entries); - - /* END AS ROOT !!!! */ - - unbecome_root(); - - if (num_account == 0) { - DEBUG(5, ("_samr_EnumDomainUsers: enumeration handle over " - "total entries\n")); - *r->out.resume_handle = *r->in.resume_handle; - return NT_STATUS_OK; - } - - status = make_user_sam_entry_list(p->mem_ctx, &samr_entries, - num_account, enum_context, - entries); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (max_entries <= num_account) { - status = STATUS_MORE_ENTRIES; - } else { - status = NT_STATUS_OK; - } - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); - - DEBUG(5, ("_samr_EnumDomainUsers: %d\n", __LINE__)); - - samr_array->count = num_account; - samr_array->entries = samr_entries; - - *r->out.resume_handle = *r->in.resume_handle + num_account; - *r->out.num_entries = num_account; - - DEBUG(5,("_samr_EnumDomainUsers: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* -makes a SAM_ENTRY / UNISTR2* structure from a group list. -********************************************************************/ - -static void make_group_sam_entry_list(TALLOC_CTX *ctx, - struct samr_SamEntry **sam_pp, - uint32_t num_sam_entries, - struct samr_displayentry *entries) -{ - struct samr_SamEntry *sam; - uint32_t i; - - *sam_pp = NULL; - - if (num_sam_entries == 0) { - return; - } - - sam = TALLOC_ZERO_ARRAY(ctx, struct samr_SamEntry, num_sam_entries); - if (sam == NULL) { - return; - } - - for (i = 0; i < num_sam_entries; i++) { - /* - * JRA. I think this should include the null. TNG does not. - */ - init_lsa_String(&sam[i].name, entries[i].account_name); - sam[i].idx = entries[i].rid; - } - - *sam_pp = sam; -} - -/******************************************************************* - _samr_EnumDomainGroups - ********************************************************************/ - -NTSTATUS _samr_EnumDomainGroups(struct pipes_struct *p, - struct samr_EnumDomainGroups *r) -{ - NTSTATUS status; - struct samr_domain_info *dinfo; - struct samr_displayentry *groups; - uint32 num_groups; - struct samr_SamArray *samr_array = NULL; - struct samr_SamEntry *samr_entries = NULL; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(5,("_samr_EnumDomainGroups: %d\n", __LINE__)); - - samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); - if (!samr_array) { - return NT_STATUS_NO_MEMORY; - } - *r->out.sam = samr_array; - - if (sid_check_is_builtin(&dinfo->sid)) { - /* No groups in builtin. */ - *r->out.resume_handle = *r->in.resume_handle; - DEBUG(5,("_samr_EnumDomainGroups: No groups in BUILTIN\n")); - return status; - } - - /* the domain group array is being allocated in the function below */ - - become_root(); - - if (dinfo->disp_info->groups == NULL) { - dinfo->disp_info->groups = pdb_search_groups(dinfo->disp_info); - - if (dinfo->disp_info->groups == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - } - - num_groups = pdb_search_entries(dinfo->disp_info->groups, - *r->in.resume_handle, - MAX_SAM_ENTRIES, &groups); - unbecome_root(); - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); - - make_group_sam_entry_list(p->mem_ctx, &samr_entries, - num_groups, groups); - - if (MAX_SAM_ENTRIES <= num_groups) { - status = STATUS_MORE_ENTRIES; - } else { - status = NT_STATUS_OK; - } - - samr_array->count = num_groups; - samr_array->entries = samr_entries; - - *r->out.num_entries = num_groups; - *r->out.resume_handle = num_groups + *r->in.resume_handle; - - DEBUG(5,("_samr_EnumDomainGroups: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* - _samr_EnumDomainAliases - ********************************************************************/ - -NTSTATUS _samr_EnumDomainAliases(struct pipes_struct *p, - struct samr_EnumDomainAliases *r) -{ - NTSTATUS status; - struct samr_domain_info *dinfo; - struct samr_displayentry *aliases; - uint32 num_aliases = 0; - struct samr_SamArray *samr_array = NULL; - struct samr_SamEntry *samr_entries = NULL; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(5,("_samr_EnumDomainAliases: sid %s\n", - sid_string_dbg(&dinfo->sid))); - - samr_array = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); - if (!samr_array) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - - if (dinfo->disp_info->aliases == NULL) { - dinfo->disp_info->aliases = pdb_search_aliases( - dinfo->disp_info, &dinfo->sid); - if (dinfo->disp_info->aliases == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - } - - num_aliases = pdb_search_entries(dinfo->disp_info->aliases, - *r->in.resume_handle, - MAX_SAM_ENTRIES, &aliases); - unbecome_root(); - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); - - make_group_sam_entry_list(p->mem_ctx, &samr_entries, - num_aliases, aliases); - - DEBUG(5,("_samr_EnumDomainAliases: %d\n", __LINE__)); - - if (MAX_SAM_ENTRIES <= num_aliases) { - status = STATUS_MORE_ENTRIES; - } else { - status = NT_STATUS_OK; - } - - samr_array->count = num_aliases; - samr_array->entries = samr_entries; - - *r->out.sam = samr_array; - *r->out.num_entries = num_aliases; - *r->out.resume_handle = num_aliases + *r->in.resume_handle; - - return status; -} - -/******************************************************************* - inits a samr_DispInfoGeneral structure. -********************************************************************/ - -static NTSTATUS init_samr_dispinfo_1(TALLOC_CTX *ctx, - struct samr_DispInfoGeneral *r, - uint32_t num_entries, - uint32_t start_idx, - struct samr_displayentry *entries) -{ - uint32 i; - - DEBUG(10, ("init_samr_dispinfo_1: num_entries: %d\n", num_entries)); - - if (num_entries == 0) { - return NT_STATUS_OK; - } - - r->count = num_entries; - - r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryGeneral, num_entries); - if (!r->entries) { - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < num_entries ; i++) { - - init_lsa_String(&r->entries[i].account_name, - entries[i].account_name); - - init_lsa_String(&r->entries[i].description, - entries[i].description); - - init_lsa_String(&r->entries[i].full_name, - entries[i].fullname); - - r->entries[i].rid = entries[i].rid; - r->entries[i].acct_flags = entries[i].acct_flags; - r->entries[i].idx = start_idx+i+1; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - inits a samr_DispInfoFull structure. -********************************************************************/ - -static NTSTATUS init_samr_dispinfo_2(TALLOC_CTX *ctx, - struct samr_DispInfoFull *r, - uint32_t num_entries, - uint32_t start_idx, - struct samr_displayentry *entries) -{ - uint32_t i; - - DEBUG(10, ("init_samr_dispinfo_2: num_entries: %d\n", num_entries)); - - if (num_entries == 0) { - return NT_STATUS_OK; - } - - r->count = num_entries; - - r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryFull, num_entries); - if (!r->entries) { - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < num_entries ; i++) { - - init_lsa_String(&r->entries[i].account_name, - entries[i].account_name); - - init_lsa_String(&r->entries[i].description, - entries[i].description); - - r->entries[i].rid = entries[i].rid; - r->entries[i].acct_flags = entries[i].acct_flags; - r->entries[i].idx = start_idx+i+1; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - inits a samr_DispInfoFullGroups structure. -********************************************************************/ - -static NTSTATUS init_samr_dispinfo_3(TALLOC_CTX *ctx, - struct samr_DispInfoFullGroups *r, - uint32_t num_entries, - uint32_t start_idx, - struct samr_displayentry *entries) -{ - uint32_t i; - - DEBUG(5, ("init_samr_dispinfo_3: num_entries: %d\n", num_entries)); - - if (num_entries == 0) { - return NT_STATUS_OK; - } - - r->count = num_entries; - - r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryFullGroup, num_entries); - if (!r->entries) { - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < num_entries ; i++) { - - init_lsa_String(&r->entries[i].account_name, - entries[i].account_name); - - init_lsa_String(&r->entries[i].description, - entries[i].description); - - r->entries[i].rid = entries[i].rid; - r->entries[i].acct_flags = entries[i].acct_flags; - r->entries[i].idx = start_idx+i+1; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - inits a samr_DispInfoAscii structure. -********************************************************************/ - -static NTSTATUS init_samr_dispinfo_4(TALLOC_CTX *ctx, - struct samr_DispInfoAscii *r, - uint32_t num_entries, - uint32_t start_idx, - struct samr_displayentry *entries) -{ - uint32_t i; - - DEBUG(5, ("init_samr_dispinfo_4: num_entries: %d\n", num_entries)); - - if (num_entries == 0) { - return NT_STATUS_OK; - } - - r->count = num_entries; - - r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryAscii, num_entries); - if (!r->entries) { - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < num_entries ; i++) { - - init_lsa_AsciiStringLarge(&r->entries[i].account_name, - entries[i].account_name); - - r->entries[i].idx = start_idx+i+1; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - inits a samr_DispInfoAscii structure. -********************************************************************/ - -static NTSTATUS init_samr_dispinfo_5(TALLOC_CTX *ctx, - struct samr_DispInfoAscii *r, - uint32_t num_entries, - uint32_t start_idx, - struct samr_displayentry *entries) -{ - uint32_t i; - - DEBUG(5, ("init_samr_dispinfo_5: num_entries: %d\n", num_entries)); - - if (num_entries == 0) { - return NT_STATUS_OK; - } - - r->count = num_entries; - - r->entries = TALLOC_ZERO_ARRAY(ctx, struct samr_DispEntryAscii, num_entries); - if (!r->entries) { - return NT_STATUS_NO_MEMORY; - } - - for (i = 0; i < num_entries ; i++) { - - init_lsa_AsciiStringLarge(&r->entries[i].account_name, - entries[i].account_name); - - r->entries[i].idx = start_idx+i+1; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_QueryDisplayInfo - ********************************************************************/ - -NTSTATUS _samr_QueryDisplayInfo(struct pipes_struct *p, - struct samr_QueryDisplayInfo *r) -{ - NTSTATUS status; - struct samr_domain_info *dinfo; - uint32 struct_size=0x20; /* W2K always reply that, client doesn't care */ - - uint32 max_entries = r->in.max_entries; - - union samr_DispInfo *disp_info = r->out.info; - - uint32 temp_size=0; - NTSTATUS disp_ret = NT_STATUS_UNSUCCESSFUL; - uint32 num_account = 0; - enum remote_arch_types ra_type = get_remote_arch(); - int max_sam_entries = (ra_type == RA_WIN95) ? MAX_SAM_ENTRIES_W95 : MAX_SAM_ENTRIES_W2K; - struct samr_displayentry *entries = NULL; - - DEBUG(5,("_samr_QueryDisplayInfo: %d\n", __LINE__)); - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (sid_check_is_builtin(&dinfo->sid)) { - DEBUG(5,("_samr_QueryDisplayInfo: no users in BUILTIN\n")); - return NT_STATUS_OK; - } - - /* - * calculate how many entries we will return. - * based on - * - the number of entries the client asked - * - our limit on that - * - the starting point (enumeration context) - * - the buffer size the client will accept - */ - - /* - * We are a lot more like W2K. Instead of reading the SAM - * each time to find the records we need to send back, - * we read it once and link that copy to the sam handle. - * For large user list (over the MAX_SAM_ENTRIES) - * it's a definitive win. - * second point to notice: between enumerations - * our sam is now the same as it's a snapshoot. - * third point: got rid of the static SAM_USER_21 struct - * no more intermediate. - * con: it uses much more memory, as a full copy is stored - * in memory. - * - * If you want to change it, think twice and think - * of the second point , that's really important. - * - * JFM, 12/20/2001 - */ - - if ((r->in.level < 1) || (r->in.level > 5)) { - DEBUG(0,("_samr_QueryDisplayInfo: Unknown info level (%u)\n", - (unsigned int)r->in.level )); - return NT_STATUS_INVALID_INFO_CLASS; - } - - /* first limit the number of entries we will return */ - if (r->in.max_entries > max_sam_entries) { - DEBUG(5, ("_samr_QueryDisplayInfo: client requested %d " - "entries, limiting to %d\n", r->in.max_entries, - max_sam_entries)); - max_entries = max_sam_entries; - } - - /* calculate the size and limit on the number of entries we will - * return */ - - temp_size=max_entries*struct_size; - - if (temp_size > r->in.buf_size) { - max_entries = MIN((r->in.buf_size / struct_size),max_entries); - DEBUG(5, ("_samr_QueryDisplayInfo: buffer size limits to " - "only %d entries\n", max_entries)); - } - - become_root(); - - /* THe following done as ROOT. Don't return without unbecome_root(). */ - - switch (r->in.level) { - case 1: - case 4: - if (dinfo->disp_info->users == NULL) { - dinfo->disp_info->users = pdb_search_users( - dinfo->disp_info, ACB_NORMAL); - if (dinfo->disp_info->users == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - DEBUG(10,("_samr_QueryDisplayInfo: starting user enumeration at index %u\n", - (unsigned int)r->in.start_idx)); - } else { - DEBUG(10,("_samr_QueryDisplayInfo: using cached user enumeration at index %u\n", - (unsigned int)r->in.start_idx)); - } - - num_account = pdb_search_entries(dinfo->disp_info->users, - r->in.start_idx, max_entries, - &entries); - break; - case 2: - if (dinfo->disp_info->machines == NULL) { - dinfo->disp_info->machines = pdb_search_users( - dinfo->disp_info, ACB_WSTRUST|ACB_SVRTRUST); - if (dinfo->disp_info->machines == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - DEBUG(10,("_samr_QueryDisplayInfo: starting machine enumeration at index %u\n", - (unsigned int)r->in.start_idx)); - } else { - DEBUG(10,("_samr_QueryDisplayInfo: using cached machine enumeration at index %u\n", - (unsigned int)r->in.start_idx)); - } - - num_account = pdb_search_entries(dinfo->disp_info->machines, - r->in.start_idx, max_entries, - &entries); - break; - case 3: - case 5: - if (dinfo->disp_info->groups == NULL) { - dinfo->disp_info->groups = pdb_search_groups( - dinfo->disp_info); - if (dinfo->disp_info->groups == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - DEBUG(10,("_samr_QueryDisplayInfo: starting group enumeration at index %u\n", - (unsigned int)r->in.start_idx)); - } else { - DEBUG(10,("_samr_QueryDisplayInfo: using cached group enumeration at index %u\n", - (unsigned int)r->in.start_idx)); - } - - num_account = pdb_search_entries(dinfo->disp_info->groups, - r->in.start_idx, max_entries, - &entries); - break; - default: - unbecome_root(); - smb_panic("info class changed"); - break; - } - unbecome_root(); - - - /* Now create reply structure */ - switch (r->in.level) { - case 1: - disp_ret = init_samr_dispinfo_1(p->mem_ctx, &disp_info->info1, - num_account, r->in.start_idx, - entries); - break; - case 2: - disp_ret = init_samr_dispinfo_2(p->mem_ctx, &disp_info->info2, - num_account, r->in.start_idx, - entries); - break; - case 3: - disp_ret = init_samr_dispinfo_3(p->mem_ctx, &disp_info->info3, - num_account, r->in.start_idx, - entries); - break; - case 4: - disp_ret = init_samr_dispinfo_4(p->mem_ctx, &disp_info->info4, - num_account, r->in.start_idx, - entries); - break; - case 5: - disp_ret = init_samr_dispinfo_5(p->mem_ctx, &disp_info->info5, - num_account, r->in.start_idx, - entries); - break; - default: - smb_panic("info class changed"); - break; - } - - if (!NT_STATUS_IS_OK(disp_ret)) - return disp_ret; - - if (max_entries <= num_account) { - status = STATUS_MORE_ENTRIES; - } else { - status = NT_STATUS_OK; - } - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); - - DEBUG(5, ("_samr_QueryDisplayInfo: %d\n", __LINE__)); - - *r->out.total_size = num_account * struct_size; - *r->out.returned_size = num_account ? temp_size : 0; - - return status; -} - -/**************************************************************** - _samr_QueryDisplayInfo2 -****************************************************************/ - -NTSTATUS _samr_QueryDisplayInfo2(struct pipes_struct *p, - struct samr_QueryDisplayInfo2 *r) -{ - struct samr_QueryDisplayInfo q; - - q.in.domain_handle = r->in.domain_handle; - q.in.level = r->in.level; - q.in.start_idx = r->in.start_idx; - q.in.max_entries = r->in.max_entries; - q.in.buf_size = r->in.buf_size; - - q.out.total_size = r->out.total_size; - q.out.returned_size = r->out.returned_size; - q.out.info = r->out.info; - - return _samr_QueryDisplayInfo(p, &q); -} - -/**************************************************************** - _samr_QueryDisplayInfo3 -****************************************************************/ - -NTSTATUS _samr_QueryDisplayInfo3(struct pipes_struct *p, - struct samr_QueryDisplayInfo3 *r) -{ - struct samr_QueryDisplayInfo q; - - q.in.domain_handle = r->in.domain_handle; - q.in.level = r->in.level; - q.in.start_idx = r->in.start_idx; - q.in.max_entries = r->in.max_entries; - q.in.buf_size = r->in.buf_size; - - q.out.total_size = r->out.total_size; - q.out.returned_size = r->out.returned_size; - q.out.info = r->out.info; - - return _samr_QueryDisplayInfo(p, &q); -} - -/******************************************************************* - _samr_QueryAliasInfo - ********************************************************************/ - -NTSTATUS _samr_QueryAliasInfo(struct pipes_struct *p, - struct samr_QueryAliasInfo *r) -{ - struct samr_alias_info *ainfo; - struct acct_info info; - NTSTATUS status; - union samr_AliasInfo *alias_info = NULL; - const char *alias_name = NULL; - const char *alias_description = NULL; - - DEBUG(5,("_samr_QueryAliasInfo: %d\n", __LINE__)); - - ainfo = policy_handle_find(p, r->in.alias_handle, - SAMR_ALIAS_ACCESS_LOOKUP_INFO, NULL, - struct samr_alias_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - alias_info = TALLOC_ZERO_P(p->mem_ctx, union samr_AliasInfo); - if (!alias_info) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - status = pdb_get_aliasinfo(&ainfo->sid, &info); - unbecome_root(); - - if ( !NT_STATUS_IS_OK(status)) - return status; - - /* FIXME: info contains fstrings */ - alias_name = talloc_strdup(r, info.acct_name); - alias_description = talloc_strdup(r, info.acct_desc); - - switch (r->in.level) { - case ALIASINFOALL: - alias_info->all.name.string = alias_name; - alias_info->all.num_members = 1; /* ??? */ - alias_info->all.description.string = alias_description; - break; - case ALIASINFONAME: - alias_info->name.string = alias_name; - break; - case ALIASINFODESCRIPTION: - alias_info->description.string = alias_description; - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - *r->out.info = alias_info; - - DEBUG(5,("_samr_QueryAliasInfo: %d\n", __LINE__)); - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_LookupNames - ********************************************************************/ - -NTSTATUS _samr_LookupNames(struct pipes_struct *p, - struct samr_LookupNames *r) -{ - struct samr_domain_info *dinfo; - NTSTATUS status; - uint32 *rid; - enum lsa_SidType *type; - int i; - int num_rids = r->in.num_names; - struct samr_Ids rids, types; - uint32_t num_mapped = 0; - - DEBUG(5,("_samr_LookupNames: %d\n", __LINE__)); - - dinfo = policy_handle_find(p, r->in.domain_handle, - 0 /* Don't know the acc_bits yet */, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (num_rids > MAX_SAM_ENTRIES) { - num_rids = MAX_SAM_ENTRIES; - DEBUG(5,("_samr_LookupNames: truncating entries to %d\n", num_rids)); - } - - rid = talloc_array(p->mem_ctx, uint32, num_rids); - NT_STATUS_HAVE_NO_MEMORY(rid); - - type = talloc_array(p->mem_ctx, enum lsa_SidType, num_rids); - NT_STATUS_HAVE_NO_MEMORY(type); - - DEBUG(5,("_samr_LookupNames: looking name on SID %s\n", - sid_string_dbg(&dinfo->sid))); - - for (i = 0; i < num_rids; i++) { - - status = NT_STATUS_NONE_MAPPED; - type[i] = SID_NAME_UNKNOWN; - - rid[i] = 0xffffffff; - - if (sid_check_is_builtin(&dinfo->sid)) { - if (lookup_builtin_name(r->in.names[i].string, - &rid[i])) - { - type[i] = SID_NAME_ALIAS; - } - } else { - lookup_global_sam_name(r->in.names[i].string, 0, - &rid[i], &type[i]); - } - - if (type[i] != SID_NAME_UNKNOWN) { - num_mapped++; - } - } - - if (num_mapped == num_rids) { - status = NT_STATUS_OK; - } else if (num_mapped == 0) { - status = NT_STATUS_NONE_MAPPED; - } else { - status = STATUS_SOME_UNMAPPED; - } - - rids.count = num_rids; - rids.ids = rid; - - types.count = num_rids; - types.ids = talloc_array(p->mem_ctx, uint32_t, num_rids); - NT_STATUS_HAVE_NO_MEMORY(type); - for (i = 0; i < num_rids; i++) { - types.ids[i] = (type[i] & 0xffffffff); - } - - *r->out.rids = rids; - *r->out.types = types; - - DEBUG(5,("_samr_LookupNames: %d\n", __LINE__)); - - return status; -} - -/**************************************************************** - _samr_ChangePasswordUser -****************************************************************/ - -NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p, - struct samr_ChangePasswordUser *r) -{ - NTSTATUS status; - bool ret = false; - struct samr_user_info *uinfo; - struct samu *pwd; - struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash; - struct samr_Password lm_pwd, nt_pwd; - - uinfo = policy_handle_find(p, r->in.user_handle, - SAMR_USER_ACCESS_SET_PASSWORD, NULL, - struct samr_user_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(5,("_samr_ChangePasswordUser: sid:%s\n", - sid_string_dbg(&uinfo->sid))); - - if (!(pwd = samu_new(NULL))) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - ret = pdb_getsampwsid(pwd, &uinfo->sid); - unbecome_root(); - - if (!ret) { - TALLOC_FREE(pwd); - return NT_STATUS_WRONG_PASSWORD; - } - - { - const uint8_t *lm_pass, *nt_pass; - - lm_pass = pdb_get_lanman_passwd(pwd); - nt_pass = pdb_get_nt_passwd(pwd); - - if (!lm_pass || !nt_pass) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - - memcpy(&lm_pwd.hash, lm_pass, sizeof(lm_pwd.hash)); - memcpy(&nt_pwd.hash, nt_pass, sizeof(nt_pwd.hash)); - } - - /* basic sanity checking on parameters. Do this before any database ops */ - if (!r->in.lm_present || !r->in.nt_present || - !r->in.old_lm_crypted || !r->in.new_lm_crypted || - !r->in.old_nt_crypted || !r->in.new_nt_crypted) { - /* we should really handle a change with lm not - present */ - status = NT_STATUS_INVALID_PARAMETER_MIX; - goto out; - } - - /* decrypt and check the new lm hash */ - D_P16(lm_pwd.hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash); - D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash); - if (memcmp(checkHash.hash, lm_pwd.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - - /* decrypt and check the new nt hash */ - D_P16(nt_pwd.hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash); - D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash); - if (memcmp(checkHash.hash, nt_pwd.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - - /* The NT Cross is not required by Win2k3 R2, but if present - check the nt cross hash */ - if (r->in.cross1_present && r->in.nt_cross) { - D_P16(lm_pwd.hash, r->in.nt_cross->hash, checkHash.hash); - if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - } - - /* The LM Cross is not required by Win2k3 R2, but if present - check the lm cross hash */ - if (r->in.cross2_present && r->in.lm_cross) { - D_P16(nt_pwd.hash, r->in.lm_cross->hash, checkHash.hash); - if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { - status = NT_STATUS_WRONG_PASSWORD; - goto out; - } - } - - if (!pdb_set_nt_passwd(pwd, new_ntPwdHash.hash, PDB_CHANGED) || - !pdb_set_lanman_passwd(pwd, new_lmPwdHash.hash, PDB_CHANGED)) { - status = NT_STATUS_ACCESS_DENIED; - goto out; - } - - status = pdb_update_sam_account(pwd); - out: - TALLOC_FREE(pwd); - - return status; -} - -/******************************************************************* - _samr_ChangePasswordUser2 - ********************************************************************/ - -NTSTATUS _samr_ChangePasswordUser2(struct pipes_struct *p, - struct samr_ChangePasswordUser2 *r) -{ - NTSTATUS status; - char *user_name = NULL; - fstring wks; - - DEBUG(5,("_samr_ChangePasswordUser2: %d\n", __LINE__)); - - if (!r->in.account->string) { - return NT_STATUS_INVALID_PARAMETER; - } - fstrcpy(wks, r->in.server->string); - - DEBUG(5,("_samr_ChangePasswordUser2: user: %s wks: %s\n", user_name, wks)); - - /* - * Pass the user through the NT -> unix user mapping - * function. - */ - - (void)map_username(talloc_tos(), r->in.account->string, &user_name); - if (!user_name) { - return NT_STATUS_NO_MEMORY; - } - - /* - * UNIX username case mangling not required, pass_oem_change - * is case insensitive. - */ - - status = pass_oem_change(user_name, - p->client_id->name, - r->in.lm_password->data, - r->in.lm_verifier->hash, - r->in.nt_password->data, - r->in.nt_verifier->hash, - NULL); - - DEBUG(5,("_samr_ChangePasswordUser2: %d\n", __LINE__)); - - if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { - return NT_STATUS_WRONG_PASSWORD; - } - - return status; -} - -/**************************************************************** - _samr_OemChangePasswordUser2 -****************************************************************/ - -NTSTATUS _samr_OemChangePasswordUser2(struct pipes_struct *p, - struct samr_OemChangePasswordUser2 *r) -{ - NTSTATUS status; - char *user_name = NULL; - const char *wks = NULL; - - DEBUG(5,("_samr_OemChangePasswordUser2: %d\n", __LINE__)); - - if (!r->in.account->string) { - return NT_STATUS_INVALID_PARAMETER; - } - if (r->in.server && r->in.server->string) { - wks = r->in.server->string; - } - - DEBUG(5,("_samr_OemChangePasswordUser2: user: %s wks: %s\n", user_name, wks)); - - /* - * Pass the user through the NT -> unix user mapping - * function. - */ - - (void)map_username(talloc_tos(), r->in.account->string, &user_name); - if (!user_name) { - return NT_STATUS_NO_MEMORY; - } - - /* - * UNIX username case mangling not required, pass_oem_change - * is case insensitive. - */ - - if (!r->in.hash || !r->in.password) { - return NT_STATUS_INVALID_PARAMETER; - } - - status = pass_oem_change(user_name, - p->client_id->name, - r->in.password->data, - r->in.hash->hash, - 0, - 0, - NULL); - - if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { - return NT_STATUS_WRONG_PASSWORD; - } - - DEBUG(5,("_samr_OemChangePasswordUser2: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* - _samr_ChangePasswordUser3 - ********************************************************************/ - -NTSTATUS _samr_ChangePasswordUser3(struct pipes_struct *p, - struct samr_ChangePasswordUser3 *r) -{ - NTSTATUS status; - char *user_name = NULL; - const char *wks = NULL; - enum samPwdChangeReason reject_reason; - struct samr_DomInfo1 *dominfo = NULL; - struct userPwdChangeFailureInformation *reject = NULL; - uint32_t tmp; - - DEBUG(5,("_samr_ChangePasswordUser3: %d\n", __LINE__)); - - if (!r->in.account->string) { - return NT_STATUS_INVALID_PARAMETER; - } - if (r->in.server && r->in.server->string) { - wks = r->in.server->string; - } - - DEBUG(5,("_samr_ChangePasswordUser3: user: %s wks: %s\n", user_name, wks)); - - /* - * Pass the user through the NT -> unix user mapping - * function. - */ - - (void)map_username(talloc_tos(), r->in.account->string, &user_name); - if (!user_name) { - return NT_STATUS_NO_MEMORY; - } - - /* - * UNIX username case mangling not required, pass_oem_change - * is case insensitive. - */ - - status = pass_oem_change(user_name, - p->client_id->name, - r->in.lm_password->data, - r->in.lm_verifier->hash, - r->in.nt_password->data, - r->in.nt_verifier->hash, - &reject_reason); - if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { - return NT_STATUS_WRONG_PASSWORD; - } - - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) || - NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_RESTRICTION)) { - - time_t u_expire, u_min_age; - uint32 account_policy_temp; - - dominfo = TALLOC_ZERO_P(p->mem_ctx, struct samr_DomInfo1); - if (!dominfo) { - return NT_STATUS_NO_MEMORY; - } - - reject = TALLOC_ZERO_P(p->mem_ctx, - struct userPwdChangeFailureInformation); - if (!reject) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - - /* AS ROOT !!! */ - - pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &tmp); - dominfo->min_password_length = tmp; - - pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &tmp); - dominfo->password_history_length = tmp; - - pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, - &dominfo->password_properties); - - pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &account_policy_temp); - u_expire = account_policy_temp; - - pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, &account_policy_temp); - u_min_age = account_policy_temp; - - /* !AS ROOT */ - - unbecome_root(); - - unix_to_nt_time_abs((NTTIME *)&dominfo->max_password_age, u_expire); - unix_to_nt_time_abs((NTTIME *)&dominfo->min_password_age, u_min_age); - - if (lp_check_password_script() && *lp_check_password_script()) { - dominfo->password_properties |= DOMAIN_PASSWORD_COMPLEX; - } - - reject->extendedFailureReason = reject_reason; - - *r->out.dominfo = dominfo; - *r->out.reject = reject; - } - - DEBUG(5,("_samr_ChangePasswordUser3: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* -makes a SAMR_R_LOOKUP_RIDS structure. -********************************************************************/ - -static bool make_samr_lookup_rids(TALLOC_CTX *ctx, uint32 num_names, - const char **names, - struct lsa_String **lsa_name_array_p) -{ - struct lsa_String *lsa_name_array = NULL; - uint32_t i; - - *lsa_name_array_p = NULL; - - if (num_names != 0) { - lsa_name_array = TALLOC_ZERO_ARRAY(ctx, struct lsa_String, num_names); - if (!lsa_name_array) { - return false; - } - } - - for (i = 0; i < num_names; i++) { - DEBUG(10, ("names[%d]:%s\n", i, names[i] && *names[i] ? names[i] : "")); - init_lsa_String(&lsa_name_array[i], names[i]); - } - - *lsa_name_array_p = lsa_name_array; - - return true; -} - -/******************************************************************* - _samr_LookupRids - ********************************************************************/ - -NTSTATUS _samr_LookupRids(struct pipes_struct *p, - struct samr_LookupRids *r) -{ - struct samr_domain_info *dinfo; - NTSTATUS status; - const char **names; - enum lsa_SidType *attrs = NULL; - uint32 *wire_attrs = NULL; - int num_rids = (int)r->in.num_rids; - int i; - struct lsa_Strings names_array; - struct samr_Ids types_array; - struct lsa_String *lsa_names = NULL; - - DEBUG(5,("_samr_LookupRids: %d\n", __LINE__)); - - dinfo = policy_handle_find(p, r->in.domain_handle, - 0 /* Don't know the acc_bits yet */, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (num_rids > 1000) { - DEBUG(0, ("Got asked for %d rids (more than 1000) -- according " - "to samba4 idl this is not possible\n", num_rids)); - return NT_STATUS_UNSUCCESSFUL; - } - - if (num_rids) { - names = TALLOC_ZERO_ARRAY(p->mem_ctx, const char *, num_rids); - attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, enum lsa_SidType, num_rids); - wire_attrs = TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_rids); - - if ((names == NULL) || (attrs == NULL) || (wire_attrs==NULL)) - return NT_STATUS_NO_MEMORY; - } else { - names = NULL; - attrs = NULL; - wire_attrs = NULL; - } - - become_root(); /* lookup_sid can require root privs */ - status = pdb_lookup_rids(&dinfo->sid, num_rids, r->in.rids, - names, attrs); - unbecome_root(); - - if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) && (num_rids == 0)) { - status = NT_STATUS_OK; - } - - if (!make_samr_lookup_rids(p->mem_ctx, num_rids, names, - &lsa_names)) { - return NT_STATUS_NO_MEMORY; - } - - /* Convert from enum lsa_SidType to uint32 for wire format. */ - for (i = 0; i < num_rids; i++) { - wire_attrs[i] = (uint32)attrs[i]; - } - - names_array.count = num_rids; - names_array.names = lsa_names; - - types_array.count = num_rids; - types_array.ids = wire_attrs; - - *r->out.names = names_array; - *r->out.types = types_array; - - DEBUG(5,("_samr_LookupRids: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* - _samr_OpenUser -********************************************************************/ - -NTSTATUS _samr_OpenUser(struct pipes_struct *p, - struct samr_OpenUser *r) -{ - struct samu *sampass=NULL; - struct dom_sid sid; - struct samr_domain_info *dinfo; - struct samr_user_info *uinfo; - struct security_descriptor *psd = NULL; - uint32 acc_granted; - uint32 des_access = r->in.access_mask; - uint32_t extra_access = 0; - size_t sd_size; - bool ret; - NTSTATUS nt_status; - - /* These two privileges, if != SEC_PRIV_INVALID, indicate - * privileges that the user must have to complete this - * operation in defience of the fixed ACL */ - enum sec_privilege needed_priv_1, needed_priv_2; - NTSTATUS status; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if ( !(sampass = samu_new( p->mem_ctx )) ) { - return NT_STATUS_NO_MEMORY; - } - - /* append the user's RID to it */ - - if (!sid_compose(&sid, &dinfo->sid, r->in.rid)) - return NT_STATUS_NO_SUCH_USER; - - /* check if access can be granted as requested by client. */ - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, &sid, SAMR_USR_RIGHTS_WRITE_PW); - se_map_generic(&des_access, &usr_generic_mapping); - - /* - * Get the sampass first as we need to check privileges - * based on what kind of user object this is. - * But don't reveal info too early if it didn't exist. - */ - - become_root(); - ret=pdb_getsampwsid(sampass, &sid); - unbecome_root(); - - needed_priv_1 = SEC_PRIV_INVALID; - needed_priv_2 = SEC_PRIV_INVALID; - /* - * We do the override access checks on *open*, not at - * SetUserInfo time. - */ - if (ret) { - uint32_t acb_info = pdb_get_acct_ctrl(sampass); - - if (acb_info & ACB_WSTRUST) { - /* - * SeMachineAccount is needed to add - * GENERIC_RIGHTS_USER_WRITE to a machine - * account. - */ - needed_priv_1 = SEC_PRIV_MACHINE_ACCOUNT; - } - if (acb_info & ACB_NORMAL) { - /* - * SeAddUsers is needed to add - * GENERIC_RIGHTS_USER_WRITE to a normal - * account. - */ - needed_priv_1 = SEC_PRIV_ADD_USERS; - } - /* - * Cheat - we have not set a specific privilege for - * server (BDC) or domain trust account, so allow - * GENERIC_RIGHTS_USER_WRITE if pipe user is in - * DOMAIN_RID_ADMINS. - */ - if (acb_info & (ACB_SVRTRUST|ACB_DOMTRUST)) { - if (lp_enable_privileges() && nt_token_check_domain_rid(p->server_info->security_token, - DOMAIN_RID_ADMINS)) { - des_access &= ~GENERIC_RIGHTS_USER_WRITE; - extra_access = GENERIC_RIGHTS_USER_WRITE; - DEBUG(4,("_samr_OpenUser: Allowing " - "GENERIC_RIGHTS_USER_WRITE for " - "rid admins\n")); - } - } - } - - TALLOC_FREE(sampass); - - nt_status = access_check_object(psd, p->server_info->security_token, - needed_priv_1, needed_priv_2, - GENERIC_RIGHTS_USER_WRITE, des_access, - &acc_granted, "_samr_OpenUser"); - - if ( !NT_STATUS_IS_OK(nt_status) ) - return nt_status; - - /* check that the SID exists in our domain. */ - if (ret == False) { - return NT_STATUS_NO_SUCH_USER; - } - - /* If we did the rid admins hack above, allow access. */ - acc_granted |= extra_access; - - uinfo = policy_handle_create(p, r->out.user_handle, acc_granted, - struct samr_user_info, &nt_status); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - uinfo->sid = sid; - - return NT_STATUS_OK; -} - -/************************************************************************* - *************************************************************************/ - -static NTSTATUS init_samr_parameters_string(TALLOC_CTX *mem_ctx, - DATA_BLOB *blob, - struct lsa_BinaryString **_r) -{ - struct lsa_BinaryString *r; - - if (!blob || !_r) { - return NT_STATUS_INVALID_PARAMETER; - } - - r = TALLOC_ZERO_P(mem_ctx, struct lsa_BinaryString); - if (!r) { - return NT_STATUS_NO_MEMORY; - } - - r->array = TALLOC_ZERO_ARRAY(mem_ctx, uint16_t, blob->length/2); - if (!r->array) { - return NT_STATUS_NO_MEMORY; - } - memcpy(r->array, blob->data, blob->length); - r->size = blob->length; - r->length = blob->length; - - if (!r->array) { - return NT_STATUS_NO_MEMORY; - } - - *_r = r; - - return NT_STATUS_OK; -} - -/************************************************************************* - *************************************************************************/ - -static struct samr_LogonHours get_logon_hours_from_pdb(TALLOC_CTX *mem_ctx, - struct samu *pw) -{ - struct samr_LogonHours hours; - const int units_per_week = 168; - - ZERO_STRUCT(hours); - hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week); - if (!hours.bits) { - return hours; - } - - hours.units_per_week = units_per_week; - memset(hours.bits, 0xFF, units_per_week); - - if (pdb_get_hours(pw)) { - memcpy(hours.bits, pdb_get_hours(pw), - MIN(pdb_get_hours_len(pw), units_per_week)); - } - - return hours; -} - -/************************************************************************* - get_user_info_1. - *************************************************************************/ - -static NTSTATUS get_user_info_1(TALLOC_CTX *mem_ctx, - struct samr_UserInfo1 *r, - struct samu *pw, - struct dom_sid *domain_sid) -{ - const struct dom_sid *sid_group; - uint32_t primary_gid; - - become_root(); - sid_group = pdb_get_group_sid(pw); - unbecome_root(); - - if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { - DEBUG(0, ("get_user_info_1: User %s has Primary Group SID %s, \n" - "which conflicts with the domain sid %s. Failing operation.\n", - pdb_get_username(pw), sid_string_dbg(sid_group), - sid_string_dbg(domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); - r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); - r->primary_gid = primary_gid; - r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); - r->comment.string = talloc_strdup(mem_ctx, pdb_get_comment(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_2. - *************************************************************************/ - -static NTSTATUS get_user_info_2(TALLOC_CTX *mem_ctx, - struct samr_UserInfo2 *r, - struct samu *pw) -{ - r->comment.string = talloc_strdup(mem_ctx, pdb_get_comment(pw)); - r->reserved.string = NULL; - r->country_code = 0; - r->code_page = 0; - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_3. - *************************************************************************/ - -static NTSTATUS get_user_info_3(TALLOC_CTX *mem_ctx, - struct samr_UserInfo3 *r, - struct samu *pw, - struct dom_sid *domain_sid) -{ - const struct dom_sid *sid_user, *sid_group; - uint32_t rid, primary_gid; - - sid_user = pdb_get_user_sid(pw); - - if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) { - DEBUG(0, ("get_user_info_3: User %s has SID %s, \nwhich conflicts with " - "the domain sid %s. Failing operation.\n", - pdb_get_username(pw), sid_string_dbg(sid_user), - sid_string_dbg(domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - become_root(); - sid_group = pdb_get_group_sid(pw); - unbecome_root(); - - if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { - DEBUG(0, ("get_user_info_3: User %s has Primary Group SID %s, \n" - "which conflicts with the domain sid %s. Failing operation.\n", - pdb_get_username(pw), sid_string_dbg(sid_group), - sid_string_dbg(domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - unix_to_nt_time(&r->last_logon, pdb_get_logon_time(pw)); - unix_to_nt_time(&r->last_logoff, pdb_get_logoff_time(pw)); - unix_to_nt_time(&r->last_password_change, pdb_get_pass_last_set_time(pw)); - unix_to_nt_time(&r->allow_password_change, pdb_get_pass_can_change_time(pw)); - unix_to_nt_time(&r->force_password_change, pdb_get_pass_must_change_time(pw)); - - r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); - r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); - r->home_directory.string= talloc_strdup(mem_ctx, pdb_get_homedir(pw)); - r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); - r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); - r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); - r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); - - r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); - r->rid = rid; - r->primary_gid = primary_gid; - r->acct_flags = pdb_get_acct_ctrl(pw); - r->bad_password_count = pdb_get_bad_password_count(pw); - r->logon_count = pdb_get_logon_count(pw); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_4. - *************************************************************************/ - -static NTSTATUS get_user_info_4(TALLOC_CTX *mem_ctx, - struct samr_UserInfo4 *r, - struct samu *pw) -{ - r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_5. - *************************************************************************/ - -static NTSTATUS get_user_info_5(TALLOC_CTX *mem_ctx, - struct samr_UserInfo5 *r, - struct samu *pw, - struct dom_sid *domain_sid) -{ - const struct dom_sid *sid_user, *sid_group; - uint32_t rid, primary_gid; - - sid_user = pdb_get_user_sid(pw); - - if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) { - DEBUG(0, ("get_user_info_5: User %s has SID %s, \nwhich conflicts with " - "the domain sid %s. Failing operation.\n", - pdb_get_username(pw), sid_string_dbg(sid_user), - sid_string_dbg(domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - become_root(); - sid_group = pdb_get_group_sid(pw); - unbecome_root(); - - if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { - DEBUG(0, ("get_user_info_5: User %s has Primary Group SID %s, \n" - "which conflicts with the domain sid %s. Failing operation.\n", - pdb_get_username(pw), sid_string_dbg(sid_group), - sid_string_dbg(domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - unix_to_nt_time(&r->last_logon, pdb_get_logon_time(pw)); - unix_to_nt_time(&r->last_logoff, pdb_get_logoff_time(pw)); - unix_to_nt_time(&r->acct_expiry, pdb_get_kickoff_time(pw)); - unix_to_nt_time(&r->last_password_change, pdb_get_pass_last_set_time(pw)); - - r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); - r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); - r->home_directory.string= talloc_strdup(mem_ctx, pdb_get_homedir(pw)); - r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); - r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); - r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); - r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); - r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); - - r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); - r->rid = rid; - r->primary_gid = primary_gid; - r->acct_flags = pdb_get_acct_ctrl(pw); - r->bad_password_count = pdb_get_bad_password_count(pw); - r->logon_count = pdb_get_logon_count(pw); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_6. - *************************************************************************/ - -static NTSTATUS get_user_info_6(TALLOC_CTX *mem_ctx, - struct samr_UserInfo6 *r, - struct samu *pw) -{ - r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); - r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_7. Safe. Only gives out account_name. - *************************************************************************/ - -static NTSTATUS get_user_info_7(TALLOC_CTX *mem_ctx, - struct samr_UserInfo7 *r, - struct samu *smbpass) -{ - r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(smbpass)); - if (!r->account_name.string) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_8. - *************************************************************************/ - -static NTSTATUS get_user_info_8(TALLOC_CTX *mem_ctx, - struct samr_UserInfo8 *r, - struct samu *pw) -{ - r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_9. Only gives out primary group SID. - *************************************************************************/ - -static NTSTATUS get_user_info_9(TALLOC_CTX *mem_ctx, - struct samr_UserInfo9 *r, - struct samu *smbpass) -{ - r->primary_gid = pdb_get_group_rid(smbpass); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_10. - *************************************************************************/ - -static NTSTATUS get_user_info_10(TALLOC_CTX *mem_ctx, - struct samr_UserInfo10 *r, - struct samu *pw) -{ - r->home_directory.string= talloc_strdup(mem_ctx, pdb_get_homedir(pw)); - r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_11. - *************************************************************************/ - -static NTSTATUS get_user_info_11(TALLOC_CTX *mem_ctx, - struct samr_UserInfo11 *r, - struct samu *pw) -{ - r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_12. - *************************************************************************/ - -static NTSTATUS get_user_info_12(TALLOC_CTX *mem_ctx, - struct samr_UserInfo12 *r, - struct samu *pw) -{ - r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_13. - *************************************************************************/ - -static NTSTATUS get_user_info_13(TALLOC_CTX *mem_ctx, - struct samr_UserInfo13 *r, - struct samu *pw) -{ - r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_14. - *************************************************************************/ - -static NTSTATUS get_user_info_14(TALLOC_CTX *mem_ctx, - struct samr_UserInfo14 *r, - struct samu *pw) -{ - r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_16. Safe. Only gives out acb bits. - *************************************************************************/ - -static NTSTATUS get_user_info_16(TALLOC_CTX *mem_ctx, - struct samr_UserInfo16 *r, - struct samu *smbpass) -{ - r->acct_flags = pdb_get_acct_ctrl(smbpass); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_17. - *************************************************************************/ - -static NTSTATUS get_user_info_17(TALLOC_CTX *mem_ctx, - struct samr_UserInfo17 *r, - struct samu *pw) -{ - unix_to_nt_time(&r->acct_expiry, pdb_get_kickoff_time(pw)); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_18. OK - this is the killer as it gives out password info. - Ensure that this is only allowed on an encrypted connection with a root - user. JRA. - *************************************************************************/ - -static NTSTATUS get_user_info_18(struct pipes_struct *p, - TALLOC_CTX *mem_ctx, - struct samr_UserInfo18 *r, - struct dom_sid *user_sid) -{ - struct samu *smbpass=NULL; - bool ret; - const uint8_t *nt_pass = NULL; - const uint8_t *lm_pass = NULL; - - ZERO_STRUCTP(r); - - if (p->server_info->system) { - goto query; - } - - if ((p->auth.auth_type != DCERPC_AUTH_TYPE_NTLMSSP) || - (p->auth.auth_type != DCERPC_AUTH_TYPE_KRB5) || - (p->auth.auth_type != DCERPC_AUTH_TYPE_SPNEGO)) { - return NT_STATUS_ACCESS_DENIED; - } - - if (p->auth.auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { - return NT_STATUS_ACCESS_DENIED; - } - - query: - /* - * Do *NOT* do become_root()/unbecome_root() here ! JRA. - */ - - if ( !(smbpass = samu_new( mem_ctx )) ) { - return NT_STATUS_NO_MEMORY; - } - - ret = pdb_getsampwsid(smbpass, user_sid); - - if (ret == False) { - DEBUG(4, ("User %s not found\n", sid_string_dbg(user_sid))); - TALLOC_FREE(smbpass); - return (geteuid() == sec_initial_uid()) ? NT_STATUS_NO_SUCH_USER : NT_STATUS_ACCESS_DENIED; - } - - DEBUG(3,("User:[%s] 0x%x\n", pdb_get_username(smbpass), pdb_get_acct_ctrl(smbpass) )); - - if ( pdb_get_acct_ctrl(smbpass) & ACB_DISABLED) { - TALLOC_FREE(smbpass); - return NT_STATUS_ACCOUNT_DISABLED; - } - - lm_pass = pdb_get_lanman_passwd(smbpass); - if (lm_pass != NULL) { - memcpy(r->lm_pwd.hash, lm_pass, 16); - r->lm_pwd_active = true; - } - - nt_pass = pdb_get_nt_passwd(smbpass); - if (nt_pass != NULL) { - memcpy(r->nt_pwd.hash, nt_pass, 16); - r->nt_pwd_active = true; - } - r->password_expired = 0; /* FIXME */ - - TALLOC_FREE(smbpass); - - return NT_STATUS_OK; -} - -/************************************************************************* - get_user_info_20 - *************************************************************************/ - -static NTSTATUS get_user_info_20(TALLOC_CTX *mem_ctx, - struct samr_UserInfo20 *r, - struct samu *sampass) -{ - const char *munged_dial = NULL; - DATA_BLOB blob; - NTSTATUS status; - struct lsa_BinaryString *parameters = NULL; - - ZERO_STRUCTP(r); - - munged_dial = pdb_get_munged_dial(sampass); - - DEBUG(3,("User:[%s] has [%s] (length: %d)\n", pdb_get_username(sampass), - munged_dial, (int)strlen(munged_dial))); - - if (munged_dial) { - blob = base64_decode_data_blob(munged_dial); - } else { - blob = data_blob_string_const_null(""); - } - - status = init_samr_parameters_string(mem_ctx, &blob, ¶meters); - data_blob_free(&blob); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - r->parameters = *parameters; - - return NT_STATUS_OK; -} - - -/************************************************************************* - get_user_info_21 - *************************************************************************/ - -static NTSTATUS get_user_info_21(TALLOC_CTX *mem_ctx, - struct samr_UserInfo21 *r, - struct samu *pw, - struct dom_sid *domain_sid, - uint32_t acc_granted) -{ - NTSTATUS status; - const struct dom_sid *sid_user, *sid_group; - uint32_t rid, primary_gid; - NTTIME force_password_change; - time_t must_change_time; - struct lsa_BinaryString *parameters = NULL; - const char *munged_dial = NULL; - DATA_BLOB blob; - - ZERO_STRUCTP(r); - - sid_user = pdb_get_user_sid(pw); - - if (!sid_peek_check_rid(domain_sid, sid_user, &rid)) { - DEBUG(0, ("get_user_info_21: User %s has SID %s, \nwhich conflicts with " - "the domain sid %s. Failing operation.\n", - pdb_get_username(pw), sid_string_dbg(sid_user), - sid_string_dbg(domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - become_root(); - sid_group = pdb_get_group_sid(pw); - unbecome_root(); - - if (!sid_peek_check_rid(domain_sid, sid_group, &primary_gid)) { - DEBUG(0, ("get_user_info_21: User %s has Primary Group SID %s, \n" - "which conflicts with the domain sid %s. Failing operation.\n", - pdb_get_username(pw), sid_string_dbg(sid_group), - sid_string_dbg(domain_sid))); - return NT_STATUS_UNSUCCESSFUL; - } - - unix_to_nt_time(&r->last_logon, pdb_get_logon_time(pw)); - unix_to_nt_time(&r->last_logoff, pdb_get_logoff_time(pw)); - unix_to_nt_time(&r->acct_expiry, pdb_get_kickoff_time(pw)); - unix_to_nt_time(&r->last_password_change, pdb_get_pass_last_set_time(pw)); - unix_to_nt_time(&r->allow_password_change, pdb_get_pass_can_change_time(pw)); - - must_change_time = pdb_get_pass_must_change_time(pw); - if (must_change_time == get_time_t_max()) { - unix_to_nt_time_abs(&force_password_change, must_change_time); - } else { - unix_to_nt_time(&force_password_change, must_change_time); - } - - munged_dial = pdb_get_munged_dial(pw); - if (munged_dial) { - blob = base64_decode_data_blob(munged_dial); - } else { - blob = data_blob_string_const_null(""); - } - - status = init_samr_parameters_string(mem_ctx, &blob, ¶meters); - data_blob_free(&blob); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - r->force_password_change = force_password_change; - - r->account_name.string = talloc_strdup(mem_ctx, pdb_get_username(pw)); - r->full_name.string = talloc_strdup(mem_ctx, pdb_get_fullname(pw)); - r->home_directory.string = talloc_strdup(mem_ctx, pdb_get_homedir(pw)); - r->home_drive.string = talloc_strdup(mem_ctx, pdb_get_dir_drive(pw)); - r->logon_script.string = talloc_strdup(mem_ctx, pdb_get_logon_script(pw)); - r->profile_path.string = talloc_strdup(mem_ctx, pdb_get_profile_path(pw)); - r->description.string = talloc_strdup(mem_ctx, pdb_get_acct_desc(pw)); - r->workstations.string = talloc_strdup(mem_ctx, pdb_get_workstations(pw)); - r->comment.string = talloc_strdup(mem_ctx, pdb_get_comment(pw)); - - r->logon_hours = get_logon_hours_from_pdb(mem_ctx, pw); - r->parameters = *parameters; - r->rid = rid; - r->primary_gid = primary_gid; - r->acct_flags = pdb_get_acct_ctrl(pw); - r->bad_password_count = pdb_get_bad_password_count(pw); - r->logon_count = pdb_get_logon_count(pw); - r->fields_present = pdb_build_fields_present(pw); - r->password_expired = (pdb_get_pass_must_change_time(pw) == 0) ? - PASS_MUST_CHANGE_AT_NEXT_LOGON : 0; - r->country_code = 0; - r->code_page = 0; - r->lm_password_set = 0; - r->nt_password_set = 0; - -#if 0 - - /* - Look at a user on a real NT4 PDC with usrmgr, press - 'ok'. Then you will see that fields_present is set to - 0x08f827fa. Look at the user immediately after that again, - and you will see that 0x00fffff is returned. This solves - the problem that you get access denied after having looked - at the user. - -- Volker - */ - -#endif - - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_QueryUserInfo - ********************************************************************/ - -NTSTATUS _samr_QueryUserInfo(struct pipes_struct *p, - struct samr_QueryUserInfo *r) -{ - NTSTATUS status; - union samr_UserInfo *user_info = NULL; - struct samr_user_info *uinfo; - struct dom_sid domain_sid; - uint32 rid; - bool ret = false; - struct samu *pwd = NULL; - uint32_t acc_required, acc_granted; - - switch (r->in.level) { - case 1: /* UserGeneralInformation */ - /* USER_READ_GENERAL */ - acc_required = SAMR_USER_ACCESS_GET_NAME_ETC; - break; - case 2: /* UserPreferencesInformation */ - /* USER_READ_PREFERENCES | USER_READ_GENERAL */ - acc_required = SAMR_USER_ACCESS_GET_LOCALE | - SAMR_USER_ACCESS_GET_NAME_ETC; - break; - case 3: /* UserLogonInformation */ - /* USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT */ - acc_required = SAMR_USER_ACCESS_GET_NAME_ETC | - SAMR_USER_ACCESS_GET_LOCALE | - SAMR_USER_ACCESS_GET_LOGONINFO | - SAMR_USER_ACCESS_GET_ATTRIBUTES; - break; - case 4: /* UserLogonHoursInformation */ - /* USER_READ_LOGON */ - acc_required = SAMR_USER_ACCESS_GET_LOGONINFO; - break; - case 5: /* UserAccountInformation */ - /* USER_READ_GENERAL | USER_READ_PREFERENCES | USER_READ_LOGON | USER_READ_ACCOUNT */ - acc_required = SAMR_USER_ACCESS_GET_NAME_ETC | - SAMR_USER_ACCESS_GET_LOCALE | - SAMR_USER_ACCESS_GET_LOGONINFO | - SAMR_USER_ACCESS_GET_ATTRIBUTES; - break; - case 6: /* UserNameInformation */ - case 7: /* UserAccountNameInformation */ - case 8: /* UserFullNameInformation */ - case 9: /* UserPrimaryGroupInformation */ - case 13: /* UserAdminCommentInformation */ - /* USER_READ_GENERAL */ - acc_required = SAMR_USER_ACCESS_GET_NAME_ETC; - break; - case 10: /* UserHomeInformation */ - case 11: /* UserScriptInformation */ - case 12: /* UserProfileInformation */ - case 14: /* UserWorkStationsInformation */ - /* USER_READ_LOGON */ - acc_required = SAMR_USER_ACCESS_GET_LOGONINFO; - break; - case 16: /* UserControlInformation */ - case 17: /* UserExpiresInformation */ - case 20: /* UserParametersInformation */ - /* USER_READ_ACCOUNT */ - acc_required = SAMR_USER_ACCESS_GET_ATTRIBUTES; - break; - case 21: /* UserAllInformation */ - /* FIXME! - gd */ - acc_required = SAMR_USER_ACCESS_GET_ATTRIBUTES; - break; - case 18: /* UserInternal1Information */ - /* FIXME! - gd */ - acc_required = SAMR_USER_ACCESS_GET_ATTRIBUTES; - break; - case 23: /* UserInternal4Information */ - case 24: /* UserInternal4InformationNew */ - case 25: /* UserInternal4InformationNew */ - case 26: /* UserInternal5InformationNew */ - default: - return NT_STATUS_INVALID_INFO_CLASS; - break; - } - - uinfo = policy_handle_find(p, r->in.user_handle, - acc_required, &acc_granted, - struct samr_user_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - domain_sid = uinfo->sid; - - sid_split_rid(&domain_sid, &rid); - - if (!sid_check_is_in_our_domain(&uinfo->sid)) - return NT_STATUS_OBJECT_TYPE_MISMATCH; - - DEBUG(5,("_samr_QueryUserInfo: sid:%s\n", - sid_string_dbg(&uinfo->sid))); - - user_info = TALLOC_ZERO_P(p->mem_ctx, union samr_UserInfo); - if (!user_info) { - return NT_STATUS_NO_MEMORY; - } - - DEBUG(5,("_samr_QueryUserInfo: user info level: %d\n", r->in.level)); - - if (!(pwd = samu_new(p->mem_ctx))) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - ret = pdb_getsampwsid(pwd, &uinfo->sid); - unbecome_root(); - - if (ret == false) { - DEBUG(4,("User %s not found\n", sid_string_dbg(&uinfo->sid))); - TALLOC_FREE(pwd); - return NT_STATUS_NO_SUCH_USER; - } - - DEBUG(3,("User:[%s]\n", pdb_get_username(pwd))); - - samr_clear_sam_passwd(pwd); - - switch (r->in.level) { - case 1: - status = get_user_info_1(p->mem_ctx, &user_info->info1, pwd, &domain_sid); - break; - case 2: - status = get_user_info_2(p->mem_ctx, &user_info->info2, pwd); - break; - case 3: - status = get_user_info_3(p->mem_ctx, &user_info->info3, pwd, &domain_sid); - break; - case 4: - status = get_user_info_4(p->mem_ctx, &user_info->info4, pwd); - break; - case 5: - status = get_user_info_5(p->mem_ctx, &user_info->info5, pwd, &domain_sid); - break; - case 6: - status = get_user_info_6(p->mem_ctx, &user_info->info6, pwd); - break; - case 7: - status = get_user_info_7(p->mem_ctx, &user_info->info7, pwd); - break; - case 8: - status = get_user_info_8(p->mem_ctx, &user_info->info8, pwd); - break; - case 9: - status = get_user_info_9(p->mem_ctx, &user_info->info9, pwd); - break; - case 10: - status = get_user_info_10(p->mem_ctx, &user_info->info10, pwd); - break; - case 11: - status = get_user_info_11(p->mem_ctx, &user_info->info11, pwd); - break; - case 12: - status = get_user_info_12(p->mem_ctx, &user_info->info12, pwd); - break; - case 13: - status = get_user_info_13(p->mem_ctx, &user_info->info13, pwd); - break; - case 14: - status = get_user_info_14(p->mem_ctx, &user_info->info14, pwd); - break; - case 16: - status = get_user_info_16(p->mem_ctx, &user_info->info16, pwd); - break; - case 17: - status = get_user_info_17(p->mem_ctx, &user_info->info17, pwd); - break; - case 18: - /* level 18 is special */ - status = get_user_info_18(p, p->mem_ctx, &user_info->info18, - &uinfo->sid); - break; - case 20: - status = get_user_info_20(p->mem_ctx, &user_info->info20, pwd); - break; - case 21: - status = get_user_info_21(p->mem_ctx, &user_info->info21, pwd, &domain_sid, acc_granted); - break; - default: - status = NT_STATUS_INVALID_INFO_CLASS; - break; - } - - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - - *r->out.info = user_info; - - done: - TALLOC_FREE(pwd); - - DEBUG(5,("_samr_QueryUserInfo: %d\n", __LINE__)); - - return status; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_QueryUserInfo2(struct pipes_struct *p, - struct samr_QueryUserInfo2 *r) -{ - struct samr_QueryUserInfo u; - - u.in.user_handle = r->in.user_handle; - u.in.level = r->in.level; - u.out.info = r->out.info; - - return _samr_QueryUserInfo(p, &u); -} - -/******************************************************************* - _samr_GetGroupsForUser - ********************************************************************/ - -NTSTATUS _samr_GetGroupsForUser(struct pipes_struct *p, - struct samr_GetGroupsForUser *r) -{ - struct samr_user_info *uinfo; - struct samu *sam_pass=NULL; - struct dom_sid *sids; - struct samr_RidWithAttribute dom_gid; - struct samr_RidWithAttribute *gids = NULL; - uint32 primary_group_rid; - size_t num_groups = 0; - gid_t *unix_gids; - size_t i, num_gids; - bool ret; - NTSTATUS result; - bool success = False; - - struct samr_RidWithAttributeArray *rids = NULL; - - /* - * from the SID in the request: - * we should send back the list of DOMAIN GROUPS - * the user is a member of - * - * and only the DOMAIN GROUPS - * no ALIASES !!! neither aliases of the domain - * nor aliases of the builtin SID - * - * JFM, 12/2/2001 - */ - - DEBUG(5,("_samr_GetGroupsForUser: %d\n", __LINE__)); - - uinfo = policy_handle_find(p, r->in.user_handle, - SAMR_USER_ACCESS_GET_GROUPS, NULL, - struct samr_user_info, &result); - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - rids = TALLOC_ZERO_P(p->mem_ctx, struct samr_RidWithAttributeArray); - if (!rids) { - return NT_STATUS_NO_MEMORY; - } - - if (!sid_check_is_in_our_domain(&uinfo->sid)) - return NT_STATUS_OBJECT_TYPE_MISMATCH; - - if ( !(sam_pass = samu_new( p->mem_ctx )) ) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - ret = pdb_getsampwsid(sam_pass, &uinfo->sid); - unbecome_root(); - - if (!ret) { - DEBUG(10, ("pdb_getsampwsid failed for %s\n", - sid_string_dbg(&uinfo->sid))); - return NT_STATUS_NO_SUCH_USER; - } - - sids = NULL; - - /* make both calls inside the root block */ - become_root(); - result = pdb_enum_group_memberships(p->mem_ctx, sam_pass, - &sids, &unix_gids, &num_groups); - if ( NT_STATUS_IS_OK(result) ) { - success = sid_peek_check_rid(get_global_sam_sid(), - pdb_get_group_sid(sam_pass), - &primary_group_rid); - } - unbecome_root(); - - if (!NT_STATUS_IS_OK(result)) { - DEBUG(10, ("pdb_enum_group_memberships failed for %s\n", - sid_string_dbg(&uinfo->sid))); - return result; - } - - if ( !success ) { - DEBUG(5, ("Group sid %s for user %s not in our domain\n", - sid_string_dbg(pdb_get_group_sid(sam_pass)), - pdb_get_username(sam_pass))); - TALLOC_FREE(sam_pass); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - gids = NULL; - num_gids = 0; - - dom_gid.attributes = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT| - SE_GROUP_ENABLED); - dom_gid.rid = primary_group_rid; - ADD_TO_ARRAY(p->mem_ctx, struct samr_RidWithAttribute, dom_gid, &gids, &num_gids); - - for (i=0; imem_ctx, struct samr_RidWithAttribute, dom_gid, &gids, &num_gids); - } - - rids->count = num_gids; - rids->rids = gids; - - *r->out.rids = rids; - - DEBUG(5,("_samr_GetGroupsForUser: %d\n", __LINE__)); - - return result; -} - -/******************************************************************* - ********************************************************************/ - -static uint32_t samr_get_server_role(void) -{ - uint32_t role = ROLE_DOMAIN_PDC; - - if (lp_server_role() == ROLE_DOMAIN_BDC) { - role = ROLE_DOMAIN_BDC; - } - - return role; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_1(TALLOC_CTX *mem_ctx, - struct samr_DomInfo1 *r) -{ - uint32_t account_policy_temp; - time_t u_expire, u_min_age; - - become_root(); - - /* AS ROOT !!! */ - - pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &account_policy_temp); - r->min_password_length = account_policy_temp; - - pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &account_policy_temp); - r->password_history_length = account_policy_temp; - - pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, - &r->password_properties); - - pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &account_policy_temp); - u_expire = account_policy_temp; - - pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, &account_policy_temp); - u_min_age = account_policy_temp; - - /* !AS ROOT */ - - unbecome_root(); - - unix_to_nt_time_abs((NTTIME *)&r->max_password_age, u_expire); - unix_to_nt_time_abs((NTTIME *)&r->min_password_age, u_min_age); - - if (lp_check_password_script() && *lp_check_password_script()) { - r->password_properties |= DOMAIN_PASSWORD_COMPLEX; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_2(TALLOC_CTX *mem_ctx, - struct samr_DomGeneralInformation *r, - struct samr_domain_info *dinfo) -{ - uint32_t u_logout; - time_t seq_num; - - become_root(); - - /* AS ROOT !!! */ - - r->num_users = count_sam_users(dinfo->disp_info, ACB_NORMAL); - r->num_groups = count_sam_groups(dinfo->disp_info); - r->num_aliases = count_sam_aliases(dinfo->disp_info); - - pdb_get_account_policy(PDB_POLICY_TIME_TO_LOGOUT, &u_logout); - - unix_to_nt_time_abs(&r->force_logoff_time, u_logout); - - if (!pdb_get_seq_num(&seq_num)) { - seq_num = time(NULL); - } - - /* !AS ROOT */ - - unbecome_root(); - - r->oem_information.string = lp_serverstring(); - r->domain_name.string = lp_workgroup(); - r->primary.string = global_myname(); - r->sequence_num = seq_num; - r->domain_server_state = DOMAIN_SERVER_ENABLED; - r->role = (enum samr_Role) samr_get_server_role(); - r->unknown3 = 1; - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_3(TALLOC_CTX *mem_ctx, - struct samr_DomInfo3 *r) -{ - uint32_t u_logout; - - become_root(); - - /* AS ROOT !!! */ - - { - uint32_t ul; - pdb_get_account_policy(PDB_POLICY_TIME_TO_LOGOUT, &ul); - u_logout = (time_t)ul; - } - - /* !AS ROOT */ - - unbecome_root(); - - unix_to_nt_time_abs(&r->force_logoff_time, u_logout); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_4(TALLOC_CTX *mem_ctx, - struct samr_DomOEMInformation *r) -{ - r->oem_information.string = lp_serverstring(); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_5(TALLOC_CTX *mem_ctx, - struct samr_DomInfo5 *r) -{ - r->domain_name.string = get_global_sam_name(); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_6(TALLOC_CTX *mem_ctx, - struct samr_DomInfo6 *r) -{ - /* NT returns its own name when a PDC. win2k and later - * only the name of the PDC if itself is a BDC (samba4 - * idl) */ - r->primary.string = global_myname(); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_7(TALLOC_CTX *mem_ctx, - struct samr_DomInfo7 *r) -{ - r->role = (enum samr_Role) samr_get_server_role(); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_8(TALLOC_CTX *mem_ctx, - struct samr_DomInfo8 *r) -{ - time_t seq_num; - - become_root(); - - /* AS ROOT !!! */ - - if (!pdb_get_seq_num(&seq_num)) { - seq_num = time(NULL); - } - - /* !AS ROOT */ - - unbecome_root(); - - r->sequence_num = seq_num; - r->domain_create_time = 0; - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_9(TALLOC_CTX *mem_ctx, - struct samr_DomInfo9 *r) -{ - r->domain_server_state = DOMAIN_SERVER_ENABLED; - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_11(TALLOC_CTX *mem_ctx, - struct samr_DomGeneralInformation2 *r, - struct samr_domain_info *dinfo) -{ - NTSTATUS status; - uint32_t account_policy_temp; - time_t u_lock_duration, u_reset_time; - - status = query_dom_info_2(mem_ctx, &r->general, dinfo); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* AS ROOT !!! */ - - become_root(); - - pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, &account_policy_temp); - u_lock_duration = account_policy_temp; - if (u_lock_duration != -1) { - u_lock_duration *= 60; - } - - pdb_get_account_policy(PDB_POLICY_RESET_COUNT_TIME, &account_policy_temp); - u_reset_time = account_policy_temp * 60; - - pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &account_policy_temp); - r->lockout_threshold = account_policy_temp; - - /* !AS ROOT */ - - unbecome_root(); - - unix_to_nt_time_abs(&r->lockout_duration, u_lock_duration); - unix_to_nt_time_abs(&r->lockout_window, u_reset_time); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_12(TALLOC_CTX *mem_ctx, - struct samr_DomInfo12 *r) -{ - uint32_t account_policy_temp; - time_t u_lock_duration, u_reset_time; - - become_root(); - - /* AS ROOT !!! */ - - pdb_get_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, &account_policy_temp); - u_lock_duration = account_policy_temp; - if (u_lock_duration != -1) { - u_lock_duration *= 60; - } - - pdb_get_account_policy(PDB_POLICY_RESET_COUNT_TIME, &account_policy_temp); - u_reset_time = account_policy_temp * 60; - - pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &account_policy_temp); - r->lockout_threshold = account_policy_temp; - - /* !AS ROOT */ - - unbecome_root(); - - unix_to_nt_time_abs(&r->lockout_duration, u_lock_duration); - unix_to_nt_time_abs(&r->lockout_window, u_reset_time); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS query_dom_info_13(TALLOC_CTX *mem_ctx, - struct samr_DomInfo13 *r) -{ - time_t seq_num; - - become_root(); - - /* AS ROOT !!! */ - - if (!pdb_get_seq_num(&seq_num)) { - seq_num = time(NULL); - } - - /* !AS ROOT */ - - unbecome_root(); - - r->sequence_num = seq_num; - r->domain_create_time = 0; - r->modified_count_at_last_promotion = 0; - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_QueryDomainInfo - ********************************************************************/ - -NTSTATUS _samr_QueryDomainInfo(struct pipes_struct *p, - struct samr_QueryDomainInfo *r) -{ - NTSTATUS status = NT_STATUS_OK; - struct samr_domain_info *dinfo; - union samr_DomainInfo *dom_info; - - uint32_t acc_required; - - DEBUG(5,("_samr_QueryDomainInfo: %d\n", __LINE__)); - - switch (r->in.level) { - case 1: /* DomainPasswordInformation */ - case 12: /* DomainLockoutInformation */ - /* DOMAIN_READ_PASSWORD_PARAMETERS */ - acc_required = SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1; - break; - case 11: /* DomainGeneralInformation2 */ - /* DOMAIN_READ_PASSWORD_PARAMETERS | - * DOMAIN_READ_OTHER_PARAMETERS */ - acc_required = SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 | - SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2; - break; - case 2: /* DomainGeneralInformation */ - case 3: /* DomainLogoffInformation */ - case 4: /* DomainOemInformation */ - case 5: /* DomainReplicationInformation */ - case 6: /* DomainReplicationInformation */ - case 7: /* DomainServerRoleInformation */ - case 8: /* DomainModifiedInformation */ - case 9: /* DomainStateInformation */ - case 10: /* DomainUasInformation */ - case 13: /* DomainModifiedInformation2 */ - /* DOMAIN_READ_OTHER_PARAMETERS */ - acc_required = SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2; - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - dinfo = policy_handle_find(p, r->in.domain_handle, - acc_required, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - dom_info = TALLOC_ZERO_P(p->mem_ctx, union samr_DomainInfo); - if (!dom_info) { - return NT_STATUS_NO_MEMORY; - } - - switch (r->in.level) { - case 1: - status = query_dom_info_1(p->mem_ctx, &dom_info->info1); - break; - case 2: - status = query_dom_info_2(p->mem_ctx, &dom_info->general, dinfo); - break; - case 3: - status = query_dom_info_3(p->mem_ctx, &dom_info->info3); - break; - case 4: - status = query_dom_info_4(p->mem_ctx, &dom_info->oem); - break; - case 5: - status = query_dom_info_5(p->mem_ctx, &dom_info->info5); - break; - case 6: - status = query_dom_info_6(p->mem_ctx, &dom_info->info6); - break; - case 7: - status = query_dom_info_7(p->mem_ctx, &dom_info->info7); - break; - case 8: - status = query_dom_info_8(p->mem_ctx, &dom_info->info8); - break; - case 9: - status = query_dom_info_9(p->mem_ctx, &dom_info->info9); - break; - case 11: - status = query_dom_info_11(p->mem_ctx, &dom_info->general2, dinfo); - break; - case 12: - status = query_dom_info_12(p->mem_ctx, &dom_info->info12); - break; - case 13: - status = query_dom_info_13(p->mem_ctx, &dom_info->info13); - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - *r->out.info = dom_info; - - DEBUG(5,("_samr_QueryDomainInfo: %d\n", __LINE__)); - - return status; -} - -/* W2k3 seems to use the same check for all 3 objects that can be created via - * SAMR, if you try to create for example "Dialup" as an alias it says - * "NT_STATUS_USER_EXISTS". This is racy, but we can't really lock the user - * database. */ - -static NTSTATUS can_create(TALLOC_CTX *mem_ctx, const char *new_name) -{ - enum lsa_SidType type; - bool result; - - DEBUG(10, ("Checking whether [%s] can be created\n", new_name)); - - become_root(); - /* Lookup in our local databases (LOOKUP_NAME_REMOTE not set) - * whether the name already exists */ - result = lookup_name(mem_ctx, new_name, LOOKUP_NAME_LOCAL, - NULL, NULL, NULL, &type); - unbecome_root(); - - if (!result) { - DEBUG(10, ("%s does not exist, can create it\n", new_name)); - return NT_STATUS_OK; - } - - DEBUG(5, ("trying to create %s, exists as %s\n", - new_name, sid_type_lookup(type))); - - if (type == SID_NAME_DOM_GRP) { - return NT_STATUS_GROUP_EXISTS; - } - if (type == SID_NAME_ALIAS) { - return NT_STATUS_ALIAS_EXISTS; - } - - /* Yes, the default is NT_STATUS_USER_EXISTS */ - return NT_STATUS_USER_EXISTS; -} - -/******************************************************************* - _samr_CreateUser2 - ********************************************************************/ - -NTSTATUS _samr_CreateUser2(struct pipes_struct *p, - struct samr_CreateUser2 *r) -{ - const char *account = NULL; - struct dom_sid sid; - uint32_t acb_info = r->in.acct_flags; - struct samr_domain_info *dinfo; - struct samr_user_info *uinfo; - NTSTATUS nt_status; - uint32 acc_granted; - struct security_descriptor *psd; - size_t sd_size; - /* check this, when giving away 'add computer to domain' privs */ - uint32 des_access = GENERIC_RIGHTS_USER_ALL_ACCESS; - bool can_add_account = False; - - /* Which privilege is needed to override the ACL? */ - enum sec_privilege needed_priv = SEC_PRIV_INVALID; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_CREATE_USER, NULL, - struct samr_domain_info, &nt_status); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - if (sid_check_is_builtin(&dinfo->sid)) { - DEBUG(5,("_samr_CreateUser2: Refusing user create in BUILTIN\n")); - return NT_STATUS_ACCESS_DENIED; - } - - if (!(acb_info == ACB_NORMAL || acb_info == ACB_DOMTRUST || - acb_info == ACB_WSTRUST || acb_info == ACB_SVRTRUST)) { - /* Match Win2k, and return NT_STATUS_INVALID_PARAMETER if - this parameter is not an account type */ - return NT_STATUS_INVALID_PARAMETER; - } - - account = r->in.account_name->string; - if (account == NULL) { - return NT_STATUS_NO_MEMORY; - } - - nt_status = can_create(p->mem_ctx, account); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - /* determine which user right we need to check based on the acb_info */ - - if (geteuid() == sec_initial_uid()) { - can_add_account = true; - } else if (acb_info & ACB_WSTRUST) { - needed_priv = SEC_PRIV_MACHINE_ACCOUNT; - can_add_account = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_MACHINE_ACCOUNT); - } else if (acb_info & ACB_NORMAL && - (account[strlen(account)-1] != '$')) { - /* usrmgr.exe (and net rpc trustdom grant) creates a normal user - account for domain trusts and changes the ACB flags later */ - needed_priv = SEC_PRIV_ADD_USERS; - can_add_account = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_ADD_USERS); - } else if (lp_enable_privileges()) { - /* implicit assumption of a BDC or domain trust account here - * (we already check the flags earlier) */ - /* only Domain Admins can add a BDC or domain trust */ - can_add_account = nt_token_check_domain_rid( - p->server_info->security_token, - DOMAIN_RID_ADMINS ); - } - - DEBUG(5, ("_samr_CreateUser2: %s can add this account : %s\n", - uidtoname(p->server_info->utok.uid), - can_add_account ? "True":"False" )); - - if (!can_add_account) { - return NT_STATUS_ACCESS_DENIED; - } - - /********** BEGIN Admin BLOCK **********/ - - become_root(); - nt_status = pdb_create_user(p->mem_ctx, account, acb_info, - r->out.rid); - unbecome_root(); - - /********** END Admin BLOCK **********/ - - /* now check for failure */ - - if ( !NT_STATUS_IS_OK(nt_status) ) - return nt_status; - - /* Get the user's SID */ - - sid_compose(&sid, get_global_sam_sid(), *r->out.rid); - - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &usr_generic_mapping, - &sid, SAMR_USR_RIGHTS_WRITE_PW); - se_map_generic(&des_access, &usr_generic_mapping); - - /* - * JRA - TESTME. We just created this user so we - * had rights to create them. Do we need to check - * any further access on this object ? Can't we - * just assume we have all the rights we need ? - */ - - nt_status = access_check_object(psd, p->server_info->security_token, - needed_priv, SEC_PRIV_INVALID, - GENERIC_RIGHTS_USER_WRITE, des_access, - &acc_granted, "_samr_CreateUser2"); - - if ( !NT_STATUS_IS_OK(nt_status) ) { - return nt_status; - } - - uinfo = policy_handle_create(p, r->out.user_handle, acc_granted, - struct samr_user_info, &nt_status); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - uinfo->sid = sid; - - /* After a "set" ensure we have no cached display info. */ - force_flush_samr_cache(&sid); - - *r->out.access_granted = acc_granted; - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_CreateUser(struct pipes_struct *p, - struct samr_CreateUser *r) -{ - struct samr_CreateUser2 c; - uint32_t access_granted; - - c.in.domain_handle = r->in.domain_handle; - c.in.account_name = r->in.account_name; - c.in.acct_flags = ACB_NORMAL; - c.in.access_mask = r->in.access_mask; - c.out.user_handle = r->out.user_handle; - c.out.access_granted = &access_granted; - c.out.rid = r->out.rid; - - return _samr_CreateUser2(p, &c); -} - -/******************************************************************* - _samr_Connect - ********************************************************************/ - -NTSTATUS _samr_Connect(struct pipes_struct *p, - struct samr_Connect *r) -{ - struct samr_connect_info *info; - uint32_t acc_granted; - struct policy_handle hnd; - uint32 des_access = r->in.access_mask; - NTSTATUS status; - - /* Access check */ - - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to _samr_Connect\n")); - return NT_STATUS_ACCESS_DENIED; - } - - /* don't give away the farm but this is probably ok. The SAMR_ACCESS_ENUM_DOMAINS - was observed from a win98 client trying to enumerate users (when configured - user level access control on shares) --jerry */ - - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - se_map_generic( &des_access, &sam_generic_mapping ); - - acc_granted = des_access & (SAMR_ACCESS_ENUM_DOMAINS - |SAMR_ACCESS_LOOKUP_DOMAIN); - - /* set up the SAMR connect_anon response */ - - info = policy_handle_create(p, &hnd, acc_granted, - struct samr_connect_info, - &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - *r->out.connect_handle = hnd; - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_Connect2 - ********************************************************************/ - -NTSTATUS _samr_Connect2(struct pipes_struct *p, - struct samr_Connect2 *r) -{ - struct samr_connect_info *info = NULL; - struct policy_handle hnd; - struct security_descriptor *psd = NULL; - uint32 acc_granted; - uint32 des_access = r->in.access_mask; - NTSTATUS nt_status; - size_t sd_size; - const char *fn = "_samr_Connect2"; - - switch (p->opnum) { - case NDR_SAMR_CONNECT2: - fn = "_samr_Connect2"; - break; - case NDR_SAMR_CONNECT3: - fn = "_samr_Connect3"; - break; - case NDR_SAMR_CONNECT4: - fn = "_samr_Connect4"; - break; - case NDR_SAMR_CONNECT5: - fn = "_samr_Connect5"; - break; - } - - DEBUG(5,("%s: %d\n", fn, __LINE__)); - - /* Access check */ - - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to %s\n", fn)); - return NT_STATUS_ACCESS_DENIED; - } - - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &sam_generic_mapping, NULL, 0); - se_map_generic(&des_access, &sam_generic_mapping); - - nt_status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_INVALID, SEC_PRIV_INVALID, - 0, des_access, &acc_granted, fn); - - if ( !NT_STATUS_IS_OK(nt_status) ) - return nt_status; - - info = policy_handle_create(p, &hnd, acc_granted, - struct samr_connect_info, &nt_status); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - DEBUG(5,("%s: %d\n", fn, __LINE__)); - - *r->out.connect_handle = hnd; - return NT_STATUS_OK; -} - -/**************************************************************** - _samr_Connect3 -****************************************************************/ - -NTSTATUS _samr_Connect3(struct pipes_struct *p, - struct samr_Connect3 *r) -{ - struct samr_Connect2 c; - - c.in.system_name = r->in.system_name; - c.in.access_mask = r->in.access_mask; - c.out.connect_handle = r->out.connect_handle; - - return _samr_Connect2(p, &c); -} - -/******************************************************************* - _samr_Connect4 - ********************************************************************/ - -NTSTATUS _samr_Connect4(struct pipes_struct *p, - struct samr_Connect4 *r) -{ - struct samr_Connect2 c; - - c.in.system_name = r->in.system_name; - c.in.access_mask = r->in.access_mask; - c.out.connect_handle = r->out.connect_handle; - - return _samr_Connect2(p, &c); -} - -/******************************************************************* - _samr_Connect5 - ********************************************************************/ - -NTSTATUS _samr_Connect5(struct pipes_struct *p, - struct samr_Connect5 *r) -{ - NTSTATUS status; - struct samr_Connect2 c; - struct samr_ConnectInfo1 info1; - - info1.client_version = SAMR_CONNECT_AFTER_W2K; - info1.unknown2 = 0; - - c.in.system_name = r->in.system_name; - c.in.access_mask = r->in.access_mask; - c.out.connect_handle = r->out.connect_handle; - - *r->out.level_out = 1; - - status = _samr_Connect2(p, &c); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - r->out.info_out->info1 = info1; - - return NT_STATUS_OK; -} - -/********************************************************************** - _samr_LookupDomain - **********************************************************************/ - -NTSTATUS _samr_LookupDomain(struct pipes_struct *p, - struct samr_LookupDomain *r) -{ - NTSTATUS status; - struct samr_connect_info *info; - const char *domain_name; - struct dom_sid *sid = NULL; - - /* win9x user manager likes to use SAMR_ACCESS_ENUM_DOMAINS here. - Reverted that change so we will work with RAS servers again */ - - info = policy_handle_find(p, r->in.connect_handle, - SAMR_ACCESS_LOOKUP_DOMAIN, NULL, - struct samr_connect_info, - &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - domain_name = r->in.domain_name->string; - if (!domain_name) { - return NT_STATUS_INVALID_PARAMETER; - } - - sid = TALLOC_ZERO_P(p->mem_ctx, struct dom_sid2); - if (!sid) { - return NT_STATUS_NO_MEMORY; - } - - if (strequal(domain_name, builtin_domain_name())) { - sid_copy(sid, &global_sid_Builtin); - } else { - if (!secrets_fetch_domain_sid(domain_name, sid)) { - status = NT_STATUS_NO_SUCH_DOMAIN; - } - } - - DEBUG(2,("Returning domain sid for domain %s -> %s\n", domain_name, - sid_string_dbg(sid))); - - *r->out.sid = sid; - - return status; -} - -/********************************************************************** - _samr_EnumDomains - **********************************************************************/ - -NTSTATUS _samr_EnumDomains(struct pipes_struct *p, - struct samr_EnumDomains *r) -{ - NTSTATUS status; - struct samr_connect_info *info; - uint32_t num_entries = 2; - struct samr_SamEntry *entry_array = NULL; - struct samr_SamArray *sam; - - info = policy_handle_find(p, r->in.connect_handle, - SAMR_ACCESS_ENUM_DOMAINS, NULL, - struct samr_connect_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - sam = TALLOC_ZERO_P(p->mem_ctx, struct samr_SamArray); - if (!sam) { - return NT_STATUS_NO_MEMORY; - } - - entry_array = TALLOC_ZERO_ARRAY(p->mem_ctx, - struct samr_SamEntry, - num_entries); - if (!entry_array) { - return NT_STATUS_NO_MEMORY; - } - - entry_array[0].idx = 0; - init_lsa_String(&entry_array[0].name, get_global_sam_name()); - - entry_array[1].idx = 1; - init_lsa_String(&entry_array[1].name, "Builtin"); - - sam->count = num_entries; - sam->entries = entry_array; - - *r->out.sam = sam; - *r->out.num_entries = num_entries; - - return status; -} - -/******************************************************************* - _samr_OpenAlias - ********************************************************************/ - -NTSTATUS _samr_OpenAlias(struct pipes_struct *p, - struct samr_OpenAlias *r) -{ - struct dom_sid sid; - uint32 alias_rid = r->in.rid; - struct samr_alias_info *ainfo; - struct samr_domain_info *dinfo; - struct security_descriptor *psd = NULL; - uint32 acc_granted; - uint32 des_access = r->in.access_mask; - size_t sd_size; - NTSTATUS status; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* append the alias' RID to it */ - - if (!sid_compose(&sid, &dinfo->sid, alias_rid)) - return NT_STATUS_NO_SUCH_ALIAS; - - /*check if access can be granted as requested by client. */ - - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &ali_generic_mapping, NULL, 0); - se_map_generic(&des_access,&ali_generic_mapping); - - status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_ADD_USERS, SEC_PRIV_INVALID, - GENERIC_RIGHTS_ALIAS_ALL_ACCESS, - des_access, &acc_granted, "_samr_OpenAlias"); - - if ( !NT_STATUS_IS_OK(status) ) - return status; - - { - /* Check we actually have the requested alias */ - enum lsa_SidType type; - bool result; - gid_t gid; - - become_root(); - result = lookup_sid(NULL, &sid, NULL, NULL, &type); - unbecome_root(); - - if (!result || (type != SID_NAME_ALIAS)) { - return NT_STATUS_NO_SUCH_ALIAS; - } - - /* make sure there is a mapping */ - - if ( !sid_to_gid( &sid, &gid ) ) { - return NT_STATUS_NO_SUCH_ALIAS; - } - - } - - ainfo = policy_handle_create(p, r->out.alias_handle, acc_granted, - struct samr_alias_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - ainfo->sid = sid; - - return NT_STATUS_OK; -} - -/******************************************************************* - set_user_info_2 - ********************************************************************/ - -static NTSTATUS set_user_info_2(TALLOC_CTX *mem_ctx, - struct samr_UserInfo2 *id2, - struct samu *pwd) -{ - if (id2 == NULL) { - DEBUG(5,("set_user_info_2: NULL id2\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id2_to_sam_passwd(pwd, id2); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_4 - ********************************************************************/ - -static NTSTATUS set_user_info_4(TALLOC_CTX *mem_ctx, - struct samr_UserInfo4 *id4, - struct samu *pwd) -{ - if (id4 == NULL) { - DEBUG(5,("set_user_info_2: NULL id4\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id4_to_sam_passwd(pwd, id4); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_6 - ********************************************************************/ - -static NTSTATUS set_user_info_6(TALLOC_CTX *mem_ctx, - struct samr_UserInfo6 *id6, - struct samu *pwd) -{ - if (id6 == NULL) { - DEBUG(5,("set_user_info_6: NULL id6\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id6_to_sam_passwd(pwd, id6); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_7 - ********************************************************************/ - -static NTSTATUS set_user_info_7(TALLOC_CTX *mem_ctx, - struct samr_UserInfo7 *id7, - struct samu *pwd) -{ - NTSTATUS rc; - - if (id7 == NULL) { - DEBUG(5, ("set_user_info_7: NULL id7\n")); - return NT_STATUS_ACCESS_DENIED; - } - - if (!id7->account_name.string) { - DEBUG(5, ("set_user_info_7: failed to get new username\n")); - return NT_STATUS_ACCESS_DENIED; - } - - /* check to see if the new username already exists. Note: we can't - reliably lock all backends, so there is potentially the - possibility that a user can be created in between this check and - the rename. The rename should fail, but may not get the - exact same failure status code. I think this is small enough - of a window for this type of operation and the results are - simply that the rename fails with a slightly different status - code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */ - - rc = can_create(mem_ctx, id7->account_name.string); - - /* when there is nothing to change, we're done here */ - if (NT_STATUS_EQUAL(rc, NT_STATUS_USER_EXISTS) && - strequal(id7->account_name.string, pdb_get_username(pwd))) { - return NT_STATUS_OK; - } - if (!NT_STATUS_IS_OK(rc)) { - return rc; - } - - rc = pdb_rename_sam_account(pwd, id7->account_name.string); - - return rc; -} - -/******************************************************************* - set_user_info_8 - ********************************************************************/ - -static NTSTATUS set_user_info_8(TALLOC_CTX *mem_ctx, - struct samr_UserInfo8 *id8, - struct samu *pwd) -{ - if (id8 == NULL) { - DEBUG(5,("set_user_info_8: NULL id8\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id8_to_sam_passwd(pwd, id8); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_10 - ********************************************************************/ - -static NTSTATUS set_user_info_10(TALLOC_CTX *mem_ctx, - struct samr_UserInfo10 *id10, - struct samu *pwd) -{ - if (id10 == NULL) { - DEBUG(5,("set_user_info_8: NULL id10\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id10_to_sam_passwd(pwd, id10); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_11 - ********************************************************************/ - -static NTSTATUS set_user_info_11(TALLOC_CTX *mem_ctx, - struct samr_UserInfo11 *id11, - struct samu *pwd) -{ - if (id11 == NULL) { - DEBUG(5,("set_user_info_11: NULL id11\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id11_to_sam_passwd(pwd, id11); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_12 - ********************************************************************/ - -static NTSTATUS set_user_info_12(TALLOC_CTX *mem_ctx, - struct samr_UserInfo12 *id12, - struct samu *pwd) -{ - if (id12 == NULL) { - DEBUG(5,("set_user_info_12: NULL id12\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id12_to_sam_passwd(pwd, id12); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_13 - ********************************************************************/ - -static NTSTATUS set_user_info_13(TALLOC_CTX *mem_ctx, - struct samr_UserInfo13 *id13, - struct samu *pwd) -{ - if (id13 == NULL) { - DEBUG(5,("set_user_info_13: NULL id13\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id13_to_sam_passwd(pwd, id13); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_14 - ********************************************************************/ - -static NTSTATUS set_user_info_14(TALLOC_CTX *mem_ctx, - struct samr_UserInfo14 *id14, - struct samu *pwd) -{ - if (id14 == NULL) { - DEBUG(5,("set_user_info_14: NULL id14\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id14_to_sam_passwd(pwd, id14); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_16 - ********************************************************************/ - -static NTSTATUS set_user_info_16(TALLOC_CTX *mem_ctx, - struct samr_UserInfo16 *id16, - struct samu *pwd) -{ - if (id16 == NULL) { - DEBUG(5,("set_user_info_16: NULL id16\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id16_to_sam_passwd(pwd, id16); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_17 - ********************************************************************/ - -static NTSTATUS set_user_info_17(TALLOC_CTX *mem_ctx, - struct samr_UserInfo17 *id17, - struct samu *pwd) -{ - if (id17 == NULL) { - DEBUG(5,("set_user_info_17: NULL id17\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id17_to_sam_passwd(pwd, id17); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_18 - ********************************************************************/ - -static NTSTATUS set_user_info_18(struct samr_UserInfo18 *id18, - TALLOC_CTX *mem_ctx, - DATA_BLOB *session_key, - struct samu *pwd) -{ - if (id18 == NULL) { - DEBUG(2, ("set_user_info_18: id18 is NULL\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - if (id18->nt_pwd_active || id18->lm_pwd_active) { - if (!session_key->length) { - return NT_STATUS_NO_USER_SESSION_KEY; - } - } - - if (id18->nt_pwd_active) { - - DATA_BLOB in, out; - - in = data_blob_const(id18->nt_pwd.hash, 16); - out = data_blob_talloc_zero(mem_ctx, 16); - - sess_crypt_blob(&out, &in, session_key, false); - - if (!pdb_set_nt_passwd(pwd, out.data, PDB_CHANGED)) { - return NT_STATUS_ACCESS_DENIED; - } - - pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); - } - - if (id18->lm_pwd_active) { - - DATA_BLOB in, out; - - in = data_blob_const(id18->lm_pwd.hash, 16); - out = data_blob_talloc_zero(mem_ctx, 16); - - sess_crypt_blob(&out, &in, session_key, false); - - if (!pdb_set_lanman_passwd(pwd, out.data, PDB_CHANGED)) { - return NT_STATUS_ACCESS_DENIED; - } - - pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); - } - - copy_id18_to_sam_passwd(pwd, id18); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_20 - ********************************************************************/ - -static NTSTATUS set_user_info_20(TALLOC_CTX *mem_ctx, - struct samr_UserInfo20 *id20, - struct samu *pwd) -{ - if (id20 == NULL) { - DEBUG(5,("set_user_info_20: NULL id20\n")); - return NT_STATUS_ACCESS_DENIED; - } - - copy_id20_to_sam_passwd(pwd, id20); - - return pdb_update_sam_account(pwd); -} - -/******************************************************************* - set_user_info_21 - ********************************************************************/ - -static NTSTATUS set_user_info_21(struct samr_UserInfo21 *id21, - TALLOC_CTX *mem_ctx, - DATA_BLOB *session_key, - struct samu *pwd) -{ - NTSTATUS status; - - if (id21 == NULL) { - DEBUG(5, ("set_user_info_21: NULL id21\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - if (id21->fields_present == 0) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (id21->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { - return NT_STATUS_ACCESS_DENIED; - } - - if (id21->fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) { - if (id21->nt_password_set) { - DATA_BLOB in, out; - - if ((id21->nt_owf_password.length != 16) || - (id21->nt_owf_password.size != 16)) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!session_key->length) { - return NT_STATUS_NO_USER_SESSION_KEY; - } - - in = data_blob_const(id21->nt_owf_password.array, 16); - out = data_blob_talloc_zero(mem_ctx, 16); - - sess_crypt_blob(&out, &in, session_key, false); - - pdb_set_nt_passwd(pwd, out.data, PDB_CHANGED); - pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); - } - } - - if (id21->fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) { - if (id21->lm_password_set) { - DATA_BLOB in, out; - - if ((id21->lm_owf_password.length != 16) || - (id21->lm_owf_password.size != 16)) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (!session_key->length) { - return NT_STATUS_NO_USER_SESSION_KEY; - } - - in = data_blob_const(id21->lm_owf_password.array, 16); - out = data_blob_talloc_zero(mem_ctx, 16); - - sess_crypt_blob(&out, &in, session_key, false); - - pdb_set_lanman_passwd(pwd, out.data, PDB_CHANGED); - pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); - } - } - - /* we need to separately check for an account rename first */ - - if (id21->account_name.string && - (!strequal(id21->account_name.string, pdb_get_username(pwd)))) - { - - /* check to see if the new username already exists. Note: we can't - reliably lock all backends, so there is potentially the - possibility that a user can be created in between this check and - the rename. The rename should fail, but may not get the - exact same failure status code. I think this is small enough - of a window for this type of operation and the results are - simply that the rename fails with a slightly different status - code (like UNSUCCESSFUL instead of ALREADY_EXISTS). */ - - status = can_create(mem_ctx, id21->account_name.string); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = pdb_rename_sam_account(pwd, id21->account_name.string); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("set_user_info_21: failed to rename account: %s\n", - nt_errstr(status))); - return status; - } - - /* set the new username so that later - functions can work on the new account */ - pdb_set_username(pwd, id21->account_name.string, PDB_SET); - } - - copy_id21_to_sam_passwd("INFO_21", pwd, id21); - - /* - * The funny part about the previous two calls is - * that pwd still has the password hashes from the - * passdb entry. These have not been updated from - * id21. I don't know if they need to be set. --jerry - */ - - if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) { - status = pdb_set_unix_primary_group(mem_ctx, pwd); - if ( !NT_STATUS_IS_OK(status) ) { - return status; - } - } - - /* Don't worry about writing out the user account since the - primary group SID is generated solely from the user's Unix - primary group. */ - - /* write the change out */ - if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { - return status; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - set_user_info_23 - ********************************************************************/ - -static NTSTATUS set_user_info_23(TALLOC_CTX *mem_ctx, - struct samr_UserInfo23 *id23, - const char *rhost, - struct samu *pwd) -{ - char *plaintext_buf = NULL; - size_t len = 0; - uint32_t acct_ctrl; - NTSTATUS status; - - if (id23 == NULL) { - DEBUG(5, ("set_user_info_23: NULL id23\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - if (id23->info.fields_present == 0) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (id23->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { - return NT_STATUS_ACCESS_DENIED; - } - - if ((id23->info.fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) || - (id23->info.fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT)) { - - DEBUG(5, ("Attempting administrator password change (level 23) for user %s\n", - pdb_get_username(pwd))); - - if (!decode_pw_buffer(mem_ctx, - id23->password.data, - &plaintext_buf, - &len, - CH_UTF16)) { - return NT_STATUS_WRONG_PASSWORD; - } - - if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { - return NT_STATUS_ACCESS_DENIED; - } - } - - copy_id23_to_sam_passwd(pwd, id23); - - acct_ctrl = pdb_get_acct_ctrl(pwd); - - /* if it's a trust account, don't update /etc/passwd */ - if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) || - ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) || - ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) { - DEBUG(5, ("Changing trust account. Not updating /etc/passwd\n")); - } else if (plaintext_buf) { - /* update the UNIX password */ - if (lp_unix_password_sync() ) { - struct passwd *passwd; - if (pdb_get_username(pwd) == NULL) { - DEBUG(1, ("chgpasswd: User without name???\n")); - return NT_STATUS_ACCESS_DENIED; - } - - passwd = Get_Pwnam_alloc(pwd, pdb_get_username(pwd)); - if (passwd == NULL) { - DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); - } - - if(!chgpasswd(pdb_get_username(pwd), rhost, - passwd, "", plaintext_buf, True)) { - return NT_STATUS_ACCESS_DENIED; - } - TALLOC_FREE(passwd); - } - } - - if (plaintext_buf) { - memset(plaintext_buf, '\0', strlen(plaintext_buf)); - } - - if (IS_SAM_CHANGED(pwd, PDB_GROUPSID) && - (!NT_STATUS_IS_OK(status = pdb_set_unix_primary_group(mem_ctx, - pwd)))) { - return status; - } - - if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { - return status; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - set_user_info_pw - ********************************************************************/ - -static bool set_user_info_pw(uint8 *pass, const char *rhost, struct samu *pwd) -{ - size_t len = 0; - char *plaintext_buf = NULL; - uint32 acct_ctrl; - - DEBUG(5, ("Attempting administrator password change for user %s\n", - pdb_get_username(pwd))); - - acct_ctrl = pdb_get_acct_ctrl(pwd); - - if (!decode_pw_buffer(talloc_tos(), - pass, - &plaintext_buf, - &len, - CH_UTF16)) { - return False; - } - - if (!pdb_set_plaintext_passwd (pwd, plaintext_buf)) { - return False; - } - - /* if it's a trust account, don't update /etc/passwd */ - if ( ( (acct_ctrl & ACB_DOMTRUST) == ACB_DOMTRUST ) || - ( (acct_ctrl & ACB_WSTRUST) == ACB_WSTRUST) || - ( (acct_ctrl & ACB_SVRTRUST) == ACB_SVRTRUST) ) { - DEBUG(5, ("Changing trust account or non-unix-user password, not updating /etc/passwd\n")); - } else { - /* update the UNIX password */ - if (lp_unix_password_sync()) { - struct passwd *passwd; - - if (pdb_get_username(pwd) == NULL) { - DEBUG(1, ("chgpasswd: User without name???\n")); - return False; - } - - passwd = Get_Pwnam_alloc(pwd, pdb_get_username(pwd)); - if (passwd == NULL) { - DEBUG(1, ("chgpasswd: Username does not exist in system !?!\n")); - } - - if(!chgpasswd(pdb_get_username(pwd), rhost, passwd, - "", plaintext_buf, True)) { - return False; - } - TALLOC_FREE(passwd); - } - } - - memset(plaintext_buf, '\0', strlen(plaintext_buf)); - - DEBUG(5,("set_user_info_pw: pdb_update_pwd()\n")); - - return True; -} - -/******************************************************************* - set_user_info_24 - ********************************************************************/ - -static NTSTATUS set_user_info_24(TALLOC_CTX *mem_ctx, - const char *rhost, - struct samr_UserInfo24 *id24, - struct samu *pwd) -{ - NTSTATUS status; - - if (id24 == NULL) { - DEBUG(5, ("set_user_info_24: NULL id24\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - if (!set_user_info_pw(id24->password.data, rhost, pwd)) { - return NT_STATUS_WRONG_PASSWORD; - } - - copy_id24_to_sam_passwd(pwd, id24); - - status = pdb_update_sam_account(pwd); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - return NT_STATUS_OK; -} - -/******************************************************************* - set_user_info_25 - ********************************************************************/ - -static NTSTATUS set_user_info_25(TALLOC_CTX *mem_ctx, - const char *rhost, - struct samr_UserInfo25 *id25, - struct samu *pwd) -{ - NTSTATUS status; - - if (id25 == NULL) { - DEBUG(5, ("set_user_info_25: NULL id25\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - if (id25->info.fields_present == 0) { - return NT_STATUS_INVALID_PARAMETER; - } - - if (id25->info.fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { - return NT_STATUS_ACCESS_DENIED; - } - - if ((id25->info.fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) || - (id25->info.fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT)) { - - if (!set_user_info_pw(id25->password.data, rhost, pwd)) { - return NT_STATUS_WRONG_PASSWORD; - } - } - - copy_id25_to_sam_passwd(pwd, id25); - - /* write the change out */ - if(!NT_STATUS_IS_OK(status = pdb_update_sam_account(pwd))) { - return status; - } - - /* - * We need to "pdb_update_sam_account" before the unix primary group - * is set, because the idealx scripts would also change the - * sambaPrimaryGroupSid using the ldap replace method. pdb_ldap uses - * the delete explicit / add explicit, which would then fail to find - * the previous primaryGroupSid value. - */ - - if ( IS_SAM_CHANGED(pwd, PDB_GROUPSID) ) { - status = pdb_set_unix_primary_group(mem_ctx, pwd); - if ( !NT_STATUS_IS_OK(status) ) { - return status; - } - } - - return NT_STATUS_OK; -} - -/******************************************************************* - set_user_info_26 - ********************************************************************/ - -static NTSTATUS set_user_info_26(TALLOC_CTX *mem_ctx, - const char *rhost, - struct samr_UserInfo26 *id26, - struct samu *pwd) -{ - NTSTATUS status; - - if (id26 == NULL) { - DEBUG(5, ("set_user_info_26: NULL id26\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - if (!set_user_info_pw(id26->password.data, rhost, pwd)) { - return NT_STATUS_WRONG_PASSWORD; - } - - copy_id26_to_sam_passwd(pwd, id26); - - status = pdb_update_sam_account(pwd); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - return NT_STATUS_OK; -} - -/************************************************************* -**************************************************************/ - -static uint32_t samr_set_user_info_map_fields_to_access_mask(uint32_t fields) -{ - uint32_t acc_required = 0; - - /* USER_ALL_USERNAME */ - if (fields & SAMR_FIELD_ACCOUNT_NAME) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_FULLNAME */ - if (fields & SAMR_FIELD_FULL_NAME) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_PRIMARYGROUPID */ - if (fields & SAMR_FIELD_PRIMARY_GID) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_HOMEDIRECTORY */ - if (fields & SAMR_FIELD_HOME_DIRECTORY) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_HOMEDIRECTORYDRIVE */ - if (fields & SAMR_FIELD_HOME_DRIVE) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_SCRIPTPATH */ - if (fields & SAMR_FIELD_LOGON_SCRIPT) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_PROFILEPATH */ - if (fields & SAMR_FIELD_PROFILE_PATH) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_ADMINCOMMENT */ - if (fields & SAMR_FIELD_COMMENT) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_WORKSTATIONS */ - if (fields & SAMR_FIELD_WORKSTATIONS) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_LOGONHOURS */ - if (fields & SAMR_FIELD_LOGON_HOURS) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_ACCOUNTEXPIRES */ - if (fields & SAMR_FIELD_ACCT_EXPIRY) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_USERACCOUNTCONTROL */ - if (fields & SAMR_FIELD_ACCT_FLAGS) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_PARAMETERS */ - if (fields & SAMR_FIELD_PARAMETERS) - acc_required |= SAMR_USER_ACCESS_SET_ATTRIBUTES; - /* USER_ALL_USERCOMMENT */ - if (fields & SAMR_FIELD_COMMENT) - acc_required |= SAMR_USER_ACCESS_SET_LOC_COM; - /* USER_ALL_COUNTRYCODE */ - if (fields & SAMR_FIELD_COUNTRY_CODE) - acc_required |= SAMR_USER_ACCESS_SET_LOC_COM; - /* USER_ALL_CODEPAGE */ - if (fields & SAMR_FIELD_CODE_PAGE) - acc_required |= SAMR_USER_ACCESS_SET_LOC_COM; - /* USER_ALL_NTPASSWORDPRESENT */ - if (fields & SAMR_FIELD_NT_PASSWORD_PRESENT) - acc_required |= SAMR_USER_ACCESS_SET_PASSWORD; - /* USER_ALL_LMPASSWORDPRESENT */ - if (fields & SAMR_FIELD_LM_PASSWORD_PRESENT) - acc_required |= SAMR_USER_ACCESS_SET_PASSWORD; - /* USER_ALL_PASSWORDEXPIRED */ - if (fields & SAMR_FIELD_EXPIRED_FLAG) - acc_required |= SAMR_USER_ACCESS_SET_PASSWORD; - - return acc_required; -} - -/******************************************************************* - samr_SetUserInfo - ********************************************************************/ - -NTSTATUS _samr_SetUserInfo(struct pipes_struct *p, - struct samr_SetUserInfo *r) -{ - struct samr_user_info *uinfo; - NTSTATUS status; - struct samu *pwd = NULL; - union samr_UserInfo *info = r->in.info; - uint32_t acc_required = 0; - uint32_t fields = 0; - bool ret; - - DEBUG(5,("_samr_SetUserInfo: %d\n", __LINE__)); - - /* This is tricky. A WinXP domain join sets - (SAMR_USER_ACCESS_SET_PASSWORD|SAMR_USER_ACCESS_SET_ATTRIBUTES|SAMR_USER_ACCESS_GET_ATTRIBUTES) - The MMC lusrmgr plugin includes these perms and more in the SamrOpenUser(). But the - standard Win32 API calls just ask for SAMR_USER_ACCESS_SET_PASSWORD in the SamrOpenUser(). - This should be enough for levels 18, 24, 25,& 26. Info level 23 can set more so - we'll use the set from the WinXP join as the basis. */ - - switch (r->in.level) { - case 2: /* UserPreferencesInformation */ - /* USER_WRITE_ACCOUNT | USER_WRITE_PREFERENCES */ - acc_required = SAMR_USER_ACCESS_SET_ATTRIBUTES | SAMR_USER_ACCESS_SET_LOC_COM; - break; - case 4: /* UserLogonHoursInformation */ - case 6: /* UserNameInformation */ - case 7: /* UserAccountNameInformation */ - case 8: /* UserFullNameInformation */ - case 9: /* UserPrimaryGroupInformation */ - case 10: /* UserHomeInformation */ - case 11: /* UserScriptInformation */ - case 12: /* UserProfileInformation */ - case 13: /* UserAdminCommentInformation */ - case 14: /* UserWorkStationsInformation */ - case 16: /* UserControlInformation */ - case 17: /* UserExpiresInformation */ - case 20: /* UserParametersInformation */ - /* USER_WRITE_ACCOUNT */ - acc_required = SAMR_USER_ACCESS_SET_ATTRIBUTES; - break; - case 18: /* UserInternal1Information */ - /* FIXME: gd, this is a guess */ - acc_required = SAMR_USER_ACCESS_SET_PASSWORD; - break; - case 21: /* UserAllInformation */ - fields = info->info21.fields_present; - acc_required = samr_set_user_info_map_fields_to_access_mask(fields); - break; - case 23: /* UserInternal4Information */ - fields = info->info23.info.fields_present; - acc_required = samr_set_user_info_map_fields_to_access_mask(fields); - break; - case 25: /* UserInternal4InformationNew */ - fields = info->info25.info.fields_present; - acc_required = samr_set_user_info_map_fields_to_access_mask(fields); - break; - case 24: /* UserInternal5Information */ - case 26: /* UserInternal5InformationNew */ - acc_required = SAMR_USER_ACCESS_SET_PASSWORD; - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - uinfo = policy_handle_find(p, r->in.user_handle, acc_required, NULL, - struct samr_user_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(5, ("_samr_SetUserInfo: sid:%s, level:%d\n", - sid_string_dbg(&uinfo->sid), r->in.level)); - - if (info == NULL) { - DEBUG(5, ("_samr_SetUserInfo: NULL info level\n")); - return NT_STATUS_INVALID_INFO_CLASS; - } - - if (!(pwd = samu_new(NULL))) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - ret = pdb_getsampwsid(pwd, &uinfo->sid); - unbecome_root(); - - if (!ret) { - TALLOC_FREE(pwd); - return NT_STATUS_NO_SUCH_USER; - } - - /* ================ BEGIN Privilege BLOCK ================ */ - - become_root(); - - /* ok! user info levels (lots: see MSDEV help), off we go... */ - - switch (r->in.level) { - - case 2: - status = set_user_info_2(p->mem_ctx, - &info->info2, pwd); - break; - - case 4: - status = set_user_info_4(p->mem_ctx, - &info->info4, pwd); - break; - - case 6: - status = set_user_info_6(p->mem_ctx, - &info->info6, pwd); - break; - - case 7: - status = set_user_info_7(p->mem_ctx, - &info->info7, pwd); - break; - - case 8: - status = set_user_info_8(p->mem_ctx, - &info->info8, pwd); - break; - - case 10: - status = set_user_info_10(p->mem_ctx, - &info->info10, pwd); - break; - - case 11: - status = set_user_info_11(p->mem_ctx, - &info->info11, pwd); - break; - - case 12: - status = set_user_info_12(p->mem_ctx, - &info->info12, pwd); - break; - - case 13: - status = set_user_info_13(p->mem_ctx, - &info->info13, pwd); - break; - - case 14: - status = set_user_info_14(p->mem_ctx, - &info->info14, pwd); - break; - - case 16: - status = set_user_info_16(p->mem_ctx, - &info->info16, pwd); - break; - - case 17: - status = set_user_info_17(p->mem_ctx, - &info->info17, pwd); - break; - - case 18: - /* Used by AS/U JRA. */ - status = set_user_info_18(&info->info18, - p->mem_ctx, - &p->server_info->user_session_key, - pwd); - break; - - case 20: - status = set_user_info_20(p->mem_ctx, - &info->info20, pwd); - break; - - case 21: - status = set_user_info_21(&info->info21, - p->mem_ctx, - &p->server_info->user_session_key, - pwd); - break; - - case 23: - if (!p->server_info->user_session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } - arcfour_crypt_blob(info->info23.password.data, 516, - &p->server_info->user_session_key); - - dump_data(100, info->info23.password.data, 516); - - status = set_user_info_23(p->mem_ctx, - &info->info23, - p->client_id->name, - pwd); - break; - - case 24: - if (!p->server_info->user_session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } - arcfour_crypt_blob(info->info24.password.data, - 516, - &p->server_info->user_session_key); - - dump_data(100, info->info24.password.data, 516); - - status = set_user_info_24(p->mem_ctx, - p->client_id->name, - &info->info24, pwd); - break; - - case 25: - if (!p->server_info->user_session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } - encode_or_decode_arc4_passwd_buffer( - info->info25.password.data, - &p->server_info->user_session_key); - - dump_data(100, info->info25.password.data, 532); - - status = set_user_info_25(p->mem_ctx, - p->client_id->name, - &info->info25, pwd); - break; - - case 26: - if (!p->server_info->user_session_key.length) { - status = NT_STATUS_NO_USER_SESSION_KEY; - } - encode_or_decode_arc4_passwd_buffer( - info->info26.password.data, - &p->server_info->user_session_key); - - dump_data(100, info->info26.password.data, 516); - - status = set_user_info_26(p->mem_ctx, - p->client_id->name, - &info->info26, pwd); - break; - - default: - status = NT_STATUS_INVALID_INFO_CLASS; - } - - TALLOC_FREE(pwd); - - unbecome_root(); - - /* ================ END Privilege BLOCK ================ */ - - if (NT_STATUS_IS_OK(status)) { - force_flush_samr_cache(&uinfo->sid); - } - - return status; -} - -/******************************************************************* - _samr_SetUserInfo2 - ********************************************************************/ - -NTSTATUS _samr_SetUserInfo2(struct pipes_struct *p, - struct samr_SetUserInfo2 *r) -{ - struct samr_SetUserInfo q; - - q.in.user_handle = r->in.user_handle; - q.in.level = r->in.level; - q.in.info = r->in.info; - - return _samr_SetUserInfo(p, &q); -} - -/********************************************************************* - _samr_GetAliasMembership -*********************************************************************/ - -NTSTATUS _samr_GetAliasMembership(struct pipes_struct *p, - struct samr_GetAliasMembership *r) -{ - size_t num_alias_rids; - uint32 *alias_rids; - struct samr_domain_info *dinfo; - size_t i; - - NTSTATUS status; - - struct dom_sid *members; - - DEBUG(5,("_samr_GetAliasMembership: %d\n", __LINE__)); - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS - | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!sid_check_is_domain(&dinfo->sid) && - !sid_check_is_builtin(&dinfo->sid)) - return NT_STATUS_OBJECT_TYPE_MISMATCH; - - if (r->in.sids->num_sids) { - members = TALLOC_ARRAY(p->mem_ctx, struct dom_sid, r->in.sids->num_sids); - - if (members == NULL) - return NT_STATUS_NO_MEMORY; - } else { - members = NULL; - } - - for (i=0; iin.sids->num_sids; i++) - sid_copy(&members[i], r->in.sids->sids[i].sid); - - alias_rids = NULL; - num_alias_rids = 0; - - become_root(); - status = pdb_enum_alias_memberships(p->mem_ctx, &dinfo->sid, members, - r->in.sids->num_sids, - &alias_rids, &num_alias_rids); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - r->out.rids->count = num_alias_rids; - r->out.rids->ids = alias_rids; - - if (r->out.rids->ids == NULL) { - /* Windows domain clients don't accept a NULL ptr here */ - r->out.rids->ids = talloc_zero(p->mem_ctx, uint32_t); - } - if (r->out.rids->ids == NULL) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_GetMembersInAlias -*********************************************************************/ - -NTSTATUS _samr_GetMembersInAlias(struct pipes_struct *p, - struct samr_GetMembersInAlias *r) -{ - struct samr_alias_info *ainfo; - NTSTATUS status; - size_t i; - size_t num_sids = 0; - struct lsa_SidPtr *sids = NULL; - struct dom_sid *pdb_sids = NULL; - - ainfo = policy_handle_find(p, r->in.alias_handle, - SAMR_ALIAS_ACCESS_GET_MEMBERS, NULL, - struct samr_alias_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(10, ("sid is %s\n", sid_string_dbg(&ainfo->sid))); - - become_root(); - status = pdb_enum_aliasmem(&ainfo->sid, talloc_tos(), &pdb_sids, - &num_sids); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (num_sids) { - sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr, num_sids); - if (sids == NULL) { - TALLOC_FREE(pdb_sids); - return NT_STATUS_NO_MEMORY; - } - } - - for (i = 0; i < num_sids; i++) { - sids[i].sid = dom_sid_dup(p->mem_ctx, &pdb_sids[i]); - if (!sids[i].sid) { - TALLOC_FREE(pdb_sids); - return NT_STATUS_NO_MEMORY; - } - } - - r->out.sids->num_sids = num_sids; - r->out.sids->sids = sids; - - TALLOC_FREE(pdb_sids); - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_QueryGroupMember -*********************************************************************/ - -NTSTATUS _samr_QueryGroupMember(struct pipes_struct *p, - struct samr_QueryGroupMember *r) -{ - struct samr_group_info *ginfo; - size_t i, num_members; - - uint32 *rid=NULL; - uint32 *attr=NULL; - - NTSTATUS status; - struct samr_RidAttrArray *rids = NULL; - - ginfo = policy_handle_find(p, r->in.group_handle, - SAMR_GROUP_ACCESS_GET_MEMBERS, NULL, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - rids = TALLOC_ZERO_P(p->mem_ctx, struct samr_RidAttrArray); - if (!rids) { - return NT_STATUS_NO_MEMORY; - } - - DEBUG(10, ("sid is %s\n", sid_string_dbg(&ginfo->sid))); - - if (!sid_check_is_in_our_domain(&ginfo->sid)) { - DEBUG(3, ("sid %s is not in our domain\n", - sid_string_dbg(&ginfo->sid))); - return NT_STATUS_NO_SUCH_GROUP; - } - - DEBUG(10, ("lookup on Domain SID\n")); - - become_root(); - status = pdb_enum_group_members(p->mem_ctx, &ginfo->sid, - &rid, &num_members); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) - return status; - - if (num_members) { - attr=TALLOC_ZERO_ARRAY(p->mem_ctx, uint32, num_members); - if (attr == NULL) { - return NT_STATUS_NO_MEMORY; - } - } else { - attr = NULL; - } - - for (i=0; icount = num_members; - rids->attributes = attr; - rids->rids = rid; - - *r->out.rids = rids; - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_AddAliasMember -*********************************************************************/ - -NTSTATUS _samr_AddAliasMember(struct pipes_struct *p, - struct samr_AddAliasMember *r) -{ - struct samr_alias_info *ainfo; - NTSTATUS status; - - ainfo = policy_handle_find(p, r->in.alias_handle, - SAMR_ALIAS_ACCESS_ADD_MEMBER, NULL, - struct samr_alias_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(10, ("sid is %s\n", sid_string_dbg(&ainfo->sid))); - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_add_aliasmem(&ainfo->sid, r->in.sid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - if (NT_STATUS_IS_OK(status)) { - force_flush_samr_cache(&ainfo->sid); - } - - return status; -} - -/********************************************************************* - _samr_DeleteAliasMember -*********************************************************************/ - -NTSTATUS _samr_DeleteAliasMember(struct pipes_struct *p, - struct samr_DeleteAliasMember *r) -{ - struct samr_alias_info *ainfo; - NTSTATUS status; - - ainfo = policy_handle_find(p, r->in.alias_handle, - SAMR_ALIAS_ACCESS_REMOVE_MEMBER, NULL, - struct samr_alias_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(10, ("_samr_del_aliasmem:sid is %s\n", - sid_string_dbg(&ainfo->sid))); - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_del_aliasmem(&ainfo->sid, r->in.sid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - if (NT_STATUS_IS_OK(status)) { - force_flush_samr_cache(&ainfo->sid); - } - - return status; -} - -/********************************************************************* - _samr_AddGroupMember -*********************************************************************/ - -NTSTATUS _samr_AddGroupMember(struct pipes_struct *p, - struct samr_AddGroupMember *r) -{ - struct samr_group_info *ginfo; - NTSTATUS status; - uint32 group_rid; - - ginfo = policy_handle_find(p, r->in.group_handle, - SAMR_GROUP_ACCESS_ADD_MEMBER, NULL, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(10, ("sid is %s\n", sid_string_dbg(&ginfo->sid))); - - if (!sid_peek_check_rid(get_global_sam_sid(), &ginfo->sid, - &group_rid)) { - return NT_STATUS_INVALID_HANDLE; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_add_groupmem(p->mem_ctx, group_rid, r->in.rid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - force_flush_samr_cache(&ginfo->sid); - - return status; -} - -/********************************************************************* - _samr_DeleteGroupMember -*********************************************************************/ - -NTSTATUS _samr_DeleteGroupMember(struct pipes_struct *p, - struct samr_DeleteGroupMember *r) - -{ - struct samr_group_info *ginfo; - NTSTATUS status; - uint32 group_rid; - - /* - * delete the group member named r->in.rid - * who is a member of the sid associated with the handle - * the rid is a user's rid as the group is a domain group. - */ - - ginfo = policy_handle_find(p, r->in.group_handle, - SAMR_GROUP_ACCESS_REMOVE_MEMBER, NULL, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!sid_peek_check_rid(get_global_sam_sid(), &ginfo->sid, - &group_rid)) { - return NT_STATUS_INVALID_HANDLE; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_del_groupmem(p->mem_ctx, group_rid, r->in.rid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - force_flush_samr_cache(&ginfo->sid); - - return status; -} - -/********************************************************************* - _samr_DeleteUser -*********************************************************************/ - -NTSTATUS _samr_DeleteUser(struct pipes_struct *p, - struct samr_DeleteUser *r) -{ - struct samr_user_info *uinfo; - NTSTATUS status; - struct samu *sam_pass=NULL; - bool ret; - - DEBUG(5, ("_samr_DeleteUser: %d\n", __LINE__)); - - uinfo = policy_handle_find(p, r->in.user_handle, - SEC_STD_DELETE, NULL, - struct samr_user_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!sid_check_is_in_our_domain(&uinfo->sid)) - return NT_STATUS_CANNOT_DELETE; - - /* check if the user exists before trying to delete */ - if ( !(sam_pass = samu_new( NULL )) ) { - return NT_STATUS_NO_MEMORY; - } - - become_root(); - ret = pdb_getsampwsid(sam_pass, &uinfo->sid); - unbecome_root(); - - if(!ret) { - DEBUG(5,("_samr_DeleteUser: User %s doesn't exist.\n", - sid_string_dbg(&uinfo->sid))); - TALLOC_FREE(sam_pass); - return NT_STATUS_NO_SUCH_USER; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_delete_user(p->mem_ctx, sam_pass); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(5,("_samr_DeleteUser: Failed to delete entry for " - "user %s: %s.\n", pdb_get_username(sam_pass), - nt_errstr(status))); - TALLOC_FREE(sam_pass); - return status; - } - - - TALLOC_FREE(sam_pass); - - force_flush_samr_cache(&uinfo->sid); - - if (!close_policy_hnd(p, r->in.user_handle)) - return NT_STATUS_OBJECT_NAME_INVALID; - - ZERO_STRUCTP(r->out.user_handle); - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_DeleteDomainGroup -*********************************************************************/ - -NTSTATUS _samr_DeleteDomainGroup(struct pipes_struct *p, - struct samr_DeleteDomainGroup *r) -{ - struct samr_group_info *ginfo; - NTSTATUS status; - uint32 group_rid; - - DEBUG(5, ("samr_DeleteDomainGroup: %d\n", __LINE__)); - - ginfo = policy_handle_find(p, r->in.group_handle, - SEC_STD_DELETE, NULL, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(10, ("sid is %s\n", sid_string_dbg(&ginfo->sid))); - - if (!sid_peek_check_rid(get_global_sam_sid(), &ginfo->sid, - &group_rid)) { - return NT_STATUS_NO_SUCH_GROUP; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_delete_dom_group(p->mem_ctx, group_rid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - if ( !NT_STATUS_IS_OK(status) ) { - DEBUG(5,("_samr_DeleteDomainGroup: Failed to delete mapping " - "entry for group %s: %s\n", - sid_string_dbg(&ginfo->sid), - nt_errstr(status))); - return status; - } - - force_flush_samr_cache(&ginfo->sid); - - if (!close_policy_hnd(p, r->in.group_handle)) - return NT_STATUS_OBJECT_NAME_INVALID; - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_DeleteDomAlias -*********************************************************************/ - -NTSTATUS _samr_DeleteDomAlias(struct pipes_struct *p, - struct samr_DeleteDomAlias *r) -{ - struct samr_alias_info *ainfo; - NTSTATUS status; - - DEBUG(5, ("_samr_DeleteDomAlias: %d\n", __LINE__)); - - ainfo = policy_handle_find(p, r->in.alias_handle, - SEC_STD_DELETE, NULL, - struct samr_alias_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(10, ("sid is %s\n", sid_string_dbg(&ainfo->sid))); - - /* Don't let Windows delete builtin groups */ - - if ( sid_check_is_in_builtin( &ainfo->sid ) ) { - return NT_STATUS_SPECIAL_ACCOUNT; - } - - if (!sid_check_is_in_our_domain(&ainfo->sid)) - return NT_STATUS_NO_SUCH_ALIAS; - - DEBUG(10, ("lookup on Local SID\n")); - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - /* Have passdb delete the alias */ - status = pdb_delete_alias(&ainfo->sid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - if ( !NT_STATUS_IS_OK(status)) - return status; - - force_flush_samr_cache(&ainfo->sid); - - if (!close_policy_hnd(p, r->in.alias_handle)) - return NT_STATUS_OBJECT_NAME_INVALID; - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_CreateDomainGroup -*********************************************************************/ - -NTSTATUS _samr_CreateDomainGroup(struct pipes_struct *p, - struct samr_CreateDomainGroup *r) - -{ - NTSTATUS status; - const char *name; - struct samr_domain_info *dinfo; - struct samr_group_info *ginfo; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_CREATE_GROUP, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!sid_check_is_domain(&dinfo->sid)) { - return NT_STATUS_ACCESS_DENIED; - } - - name = r->in.name->string; - if (name == NULL) { - return NT_STATUS_NO_MEMORY; - } - - status = can_create(p->mem_ctx, name); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - /* check that we successfully create the UNIX group */ - status = pdb_create_dom_group(p->mem_ctx, name, r->out.rid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - /* check if we should bail out here */ - - if ( !NT_STATUS_IS_OK(status) ) - return status; - - ginfo = policy_handle_create(p, r->out.group_handle, - GENERIC_RIGHTS_GROUP_ALL_ACCESS, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - sid_compose(&ginfo->sid, &dinfo->sid, *r->out.rid); - - force_flush_samr_cache(&dinfo->sid); - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_CreateDomAlias -*********************************************************************/ - -NTSTATUS _samr_CreateDomAlias(struct pipes_struct *p, - struct samr_CreateDomAlias *r) -{ - struct dom_sid info_sid; - const char *name = NULL; - struct samr_domain_info *dinfo; - struct samr_alias_info *ainfo; - gid_t gid; - NTSTATUS result; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_CREATE_ALIAS, NULL, - struct samr_domain_info, &result); - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - if (!sid_check_is_domain(&dinfo->sid)) { - return NT_STATUS_ACCESS_DENIED; - } - - name = r->in.alias_name->string; - - result = can_create(p->mem_ctx, name); - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - /* Have passdb create the alias */ - result = pdb_create_alias(name, r->out.rid); - unbecome_root(); - - /******** END SeAddUsers BLOCK *********/ - - if (!NT_STATUS_IS_OK(result)) { - DEBUG(10, ("pdb_create_alias failed: %s\n", - nt_errstr(result))); - return result; - } - - sid_compose(&info_sid, &dinfo->sid, *r->out.rid); - - if (!sid_to_gid(&info_sid, &gid)) { - DEBUG(10, ("Could not find alias just created\n")); - return NT_STATUS_ACCESS_DENIED; - } - - /* check if the group has been successfully created */ - if ( getgrgid(gid) == NULL ) { - DEBUG(10, ("getgrgid(%u) of just created alias failed\n", - (unsigned int)gid)); - return NT_STATUS_ACCESS_DENIED; - } - - ainfo = policy_handle_create(p, r->out.alias_handle, - GENERIC_RIGHTS_ALIAS_ALL_ACCESS, - struct samr_alias_info, &result); - if (!NT_STATUS_IS_OK(result)) { - return result; - } - ainfo->sid = info_sid; - - force_flush_samr_cache(&info_sid); - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_QueryGroupInfo -*********************************************************************/ - -NTSTATUS _samr_QueryGroupInfo(struct pipes_struct *p, - struct samr_QueryGroupInfo *r) -{ - struct samr_group_info *ginfo; - NTSTATUS status; - GROUP_MAP map; - union samr_GroupInfo *info = NULL; - bool ret; - uint32_t attributes = SE_GROUP_MANDATORY | - SE_GROUP_ENABLED_BY_DEFAULT | - SE_GROUP_ENABLED; - const char *group_name = NULL; - const char *group_description = NULL; - - ginfo = policy_handle_find(p, r->in.group_handle, - SAMR_GROUP_ACCESS_LOOKUP_INFO, NULL, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - become_root(); - ret = get_domain_group_from_sid(ginfo->sid, &map); - unbecome_root(); - if (!ret) - return NT_STATUS_INVALID_HANDLE; - - /* FIXME: map contains fstrings */ - group_name = talloc_strdup(r, map.nt_name); - group_description = talloc_strdup(r, map.comment); - - info = TALLOC_ZERO_P(p->mem_ctx, union samr_GroupInfo); - if (!info) { - return NT_STATUS_NO_MEMORY; - } - - switch (r->in.level) { - case 1: { - uint32 *members; - size_t num_members; - - become_root(); - status = pdb_enum_group_members( - p->mem_ctx, &ginfo->sid, &members, - &num_members); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - info->all.name.string = group_name; - info->all.attributes = attributes; - info->all.num_members = num_members; - info->all.description.string = group_description; - break; - } - case 2: - info->name.string = group_name; - break; - case 3: - info->attributes.attributes = attributes; - break; - case 4: - info->description.string = group_description; - break; - case 5: { - /* - uint32 *members; - size_t num_members; - */ - - /* - become_root(); - status = pdb_enum_group_members( - p->mem_ctx, &ginfo->sid, &members, - &num_members); - unbecome_root(); - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - */ - info->all2.name.string = group_name; - info->all2.attributes = attributes; - info->all2.num_members = 0; /* num_members - in w2k3 this is always 0 */ - info->all2.description.string = group_description; - - break; - } - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - *r->out.info = info; - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_SetGroupInfo -*********************************************************************/ - -NTSTATUS _samr_SetGroupInfo(struct pipes_struct *p, - struct samr_SetGroupInfo *r) -{ - struct samr_group_info *ginfo; - GROUP_MAP map; - NTSTATUS status; - bool ret; - - ginfo = policy_handle_find(p, r->in.group_handle, - SAMR_GROUP_ACCESS_SET_INFO, NULL, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - become_root(); - ret = get_domain_group_from_sid(ginfo->sid, &map); - unbecome_root(); - if (!ret) - return NT_STATUS_NO_SUCH_GROUP; - - switch (r->in.level) { - case 2: - fstrcpy(map.nt_name, r->in.info->name.string); - break; - case 3: - break; - case 4: - fstrcpy(map.comment, r->in.info->description.string); - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_update_group_mapping_entry(&map); - unbecome_root(); - - /******** End SeAddUsers BLOCK *********/ - - if (NT_STATUS_IS_OK(status)) { - force_flush_samr_cache(&ginfo->sid); - } - - return status; -} - -/********************************************************************* - _samr_SetAliasInfo -*********************************************************************/ - -NTSTATUS _samr_SetAliasInfo(struct pipes_struct *p, - struct samr_SetAliasInfo *r) -{ - struct samr_alias_info *ainfo; - struct acct_info info; - NTSTATUS status; - - ainfo = policy_handle_find(p, r->in.alias_handle, - SAMR_ALIAS_ACCESS_SET_INFO, NULL, - struct samr_alias_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* get the current group information */ - - become_root(); - status = pdb_get_aliasinfo( &ainfo->sid, &info ); - unbecome_root(); - - if ( !NT_STATUS_IS_OK(status)) - return status; - - switch (r->in.level) { - case ALIASINFONAME: - { - fstring group_name; - - /* We currently do not support renaming groups in the - the BUILTIN domain. Refer to util_builtin.c to understand - why. The eventually needs to be fixed to be like Windows - where you can rename builtin groups, just not delete them */ - - if ( sid_check_is_in_builtin( &ainfo->sid ) ) { - return NT_STATUS_SPECIAL_ACCOUNT; - } - - /* There has to be a valid name (and it has to be different) */ - - if ( !r->in.info->name.string ) - return NT_STATUS_INVALID_PARAMETER; - - /* If the name is the same just reply "ok". Yes this - doesn't allow you to change the case of a group name. */ - - if ( strequal( r->in.info->name.string, info.acct_name ) ) - return NT_STATUS_OK; - - fstrcpy( info.acct_name, r->in.info->name.string); - - /* make sure the name doesn't already exist as a user - or local group */ - - fstr_sprintf( group_name, "%s\\%s", global_myname(), info.acct_name ); - status = can_create( p->mem_ctx, group_name ); - if ( !NT_STATUS_IS_OK( status ) ) - return status; - break; - } - case ALIASINFODESCRIPTION: - if (r->in.info->description.string) { - fstrcpy(info.acct_desc, - r->in.info->description.string); - } else { - fstrcpy( info.acct_desc, "" ); - } - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - /******** BEGIN SeAddUsers BLOCK *********/ - - become_root(); - status = pdb_set_aliasinfo( &ainfo->sid, &info ); - unbecome_root(); - - /******** End SeAddUsers BLOCK *********/ - - if (NT_STATUS_IS_OK(status)) - force_flush_samr_cache(&ainfo->sid); - - return status; -} - -/**************************************************************** - _samr_GetDomPwInfo -****************************************************************/ - -NTSTATUS _samr_GetDomPwInfo(struct pipes_struct *p, - struct samr_GetDomPwInfo *r) -{ - uint32_t min_password_length = 0; - uint32_t password_properties = 0; - - /* Perform access check. Since this rpc does not require a - policy handle it will not be caught by the access checks on - SAMR_CONNECT or SAMR_CONNECT_ANON. */ - - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to _samr_GetDomPwInfo\n")); - return NT_STATUS_ACCESS_DENIED; - } - - become_root(); - pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, - &min_password_length); - pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, - &password_properties); - unbecome_root(); - - if (lp_check_password_script() && *lp_check_password_script()) { - password_properties |= DOMAIN_PASSWORD_COMPLEX; - } - - r->out.info->min_password_length = min_password_length; - r->out.info->password_properties = password_properties; - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_OpenGroup -*********************************************************************/ - -NTSTATUS _samr_OpenGroup(struct pipes_struct *p, - struct samr_OpenGroup *r) - -{ - struct dom_sid info_sid; - GROUP_MAP map; - struct samr_domain_info *dinfo; - struct samr_group_info *ginfo; - struct security_descriptor *psd = NULL; - uint32 acc_granted; - uint32 des_access = r->in.access_mask; - size_t sd_size; - NTSTATUS status; - bool ret; - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /*check if access can be granted as requested by client. */ - map_max_allowed_access(p->server_info->security_token, - &p->server_info->utok, - &des_access); - - make_samr_object_sd(p->mem_ctx, &psd, &sd_size, &grp_generic_mapping, NULL, 0); - se_map_generic(&des_access,&grp_generic_mapping); - - status = access_check_object(psd, p->server_info->security_token, - SEC_PRIV_ADD_USERS, SEC_PRIV_INVALID, GENERIC_RIGHTS_GROUP_ALL_ACCESS, - des_access, &acc_granted, "_samr_OpenGroup"); - - if ( !NT_STATUS_IS_OK(status) ) - return status; - - /* this should not be hard-coded like this */ - - if (!sid_check_is_domain(&dinfo->sid)) { - return NT_STATUS_ACCESS_DENIED; - } - - sid_compose(&info_sid, &dinfo->sid, r->in.rid); - - DEBUG(10, ("_samr_OpenGroup:Opening SID: %s\n", - sid_string_dbg(&info_sid))); - - /* check if that group really exists */ - become_root(); - ret = get_domain_group_from_sid(info_sid, &map); - unbecome_root(); - if (!ret) - return NT_STATUS_NO_SUCH_GROUP; - - ginfo = policy_handle_create(p, r->out.group_handle, - acc_granted, - struct samr_group_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - ginfo->sid = info_sid; - - return NT_STATUS_OK; -} - -/********************************************************************* - _samr_RemoveMemberFromForeignDomain -*********************************************************************/ - -NTSTATUS _samr_RemoveMemberFromForeignDomain(struct pipes_struct *p, - struct samr_RemoveMemberFromForeignDomain *r) -{ - struct samr_domain_info *dinfo; - NTSTATUS result; - - DEBUG(5,("_samr_RemoveMemberFromForeignDomain: removing SID [%s]\n", - sid_string_dbg(r->in.sid))); - - /* Find the policy handle. Open a policy on it. */ - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, NULL, - struct samr_domain_info, &result); - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - DEBUG(8, ("_samr_RemoveMemberFromForeignDomain: sid is %s\n", - sid_string_dbg(&dinfo->sid))); - - /* we can only delete a user from a group since we don't have - nested groups anyways. So in the latter case, just say OK */ - - /* TODO: The above comment nowadays is bogus. Since we have nested - * groups now, and aliases members are never reported out of the unix - * group membership, the "just say OK" makes this call a no-op. For - * us. This needs fixing however. */ - - /* I've only ever seen this in the wild when deleting a user from - * usrmgr.exe. domain_sid is the builtin domain, and the sid to delete - * is the user about to be deleted. I very much suspect this is the - * only application of this call. To verify this, let people report - * other cases. */ - - if (!sid_check_is_builtin(&dinfo->sid)) { - DEBUG(1,("_samr_RemoveMemberFromForeignDomain: domain_sid = %s, " - "global_sam_sid() = %s\n", - sid_string_dbg(&dinfo->sid), - sid_string_dbg(get_global_sam_sid()))); - DEBUGADD(1,("please report to samba-technical@samba.org!\n")); - return NT_STATUS_OK; - } - - force_flush_samr_cache(&dinfo->sid); - - result = NT_STATUS_OK; - - return result; -} - -/******************************************************************* - _samr_QueryDomainInfo2 - ********************************************************************/ - -NTSTATUS _samr_QueryDomainInfo2(struct pipes_struct *p, - struct samr_QueryDomainInfo2 *r) -{ - struct samr_QueryDomainInfo q; - - q.in.domain_handle = r->in.domain_handle; - q.in.level = r->in.level; - - q.out.info = r->out.info; - - return _samr_QueryDomainInfo(p, &q); -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS set_dom_info_1(TALLOC_CTX *mem_ctx, - struct samr_DomInfo1 *r) -{ - time_t u_expire, u_min_age; - - u_expire = nt_time_to_unix_abs((NTTIME *)&r->max_password_age); - u_min_age = nt_time_to_unix_abs((NTTIME *)&r->min_password_age); - - pdb_set_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, - (uint32_t)r->min_password_length); - pdb_set_account_policy(PDB_POLICY_PASSWORD_HISTORY, - (uint32_t)r->password_history_length); - pdb_set_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS, - (uint32_t)r->password_properties); - pdb_set_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, (int)u_expire); - pdb_set_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, (int)u_min_age); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS set_dom_info_3(TALLOC_CTX *mem_ctx, - struct samr_DomInfo3 *r) -{ - time_t u_logout; - - u_logout = nt_time_to_unix_abs((NTTIME *)&r->force_logoff_time); - - pdb_set_account_policy(PDB_POLICY_TIME_TO_LOGOUT, (int)u_logout); - - return NT_STATUS_OK; -} - -/******************************************************************* - ********************************************************************/ - -static NTSTATUS set_dom_info_12(TALLOC_CTX *mem_ctx, - struct samr_DomInfo12 *r) -{ - time_t u_lock_duration, u_reset_time; - - u_lock_duration = nt_time_to_unix_abs((NTTIME *)&r->lockout_duration); - if (u_lock_duration != -1) { - u_lock_duration /= 60; - } - - u_reset_time = nt_time_to_unix_abs((NTTIME *)&r->lockout_window)/60; - - pdb_set_account_policy(PDB_POLICY_LOCK_ACCOUNT_DURATION, (int)u_lock_duration); - pdb_set_account_policy(PDB_POLICY_RESET_COUNT_TIME, (int)u_reset_time); - pdb_set_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, - (uint32_t)r->lockout_threshold); - - return NT_STATUS_OK; -} - -/******************************************************************* - _samr_SetDomainInfo - ********************************************************************/ - -NTSTATUS _samr_SetDomainInfo(struct pipes_struct *p, - struct samr_SetDomainInfo *r) -{ - struct samr_domain_info *dinfo; - NTSTATUS status; - uint32_t acc_required = 0; - - DEBUG(5,("_samr_SetDomainInfo: %d\n", __LINE__)); - - switch (r->in.level) { - case 1: /* DomainPasswordInformation */ - case 12: /* DomainLockoutInformation */ - /* DOMAIN_WRITE_PASSWORD_PARAMETERS */ - acc_required = SAMR_DOMAIN_ACCESS_SET_INFO_1; - break; - case 3: /* DomainLogoffInformation */ - case 4: /* DomainOemInformation */ - /* DOMAIN_WRITE_OTHER_PARAMETERS */ - acc_required = SAMR_DOMAIN_ACCESS_SET_INFO_2; - break; - case 6: /* DomainReplicationInformation */ - case 9: /* DomainStateInformation */ - case 7: /* DomainServerRoleInformation */ - /* DOMAIN_ADMINISTER_SERVER */ - acc_required = SAMR_DOMAIN_ACCESS_SET_INFO_3; - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - dinfo = policy_handle_find(p, r->in.domain_handle, - acc_required, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(5,("_samr_SetDomainInfo: level: %d\n", r->in.level)); - - switch (r->in.level) { - case 1: - status = set_dom_info_1(p->mem_ctx, &r->in.info->info1); - break; - case 3: - status = set_dom_info_3(p->mem_ctx, &r->in.info->info3); - break; - case 4: - break; - case 6: - break; - case 7: - break; - case 9: - break; - case 12: - status = set_dom_info_12(p->mem_ctx, &r->in.info->info12); - break; - default: - return NT_STATUS_INVALID_INFO_CLASS; - } - - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - DEBUG(5,("_samr_SetDomainInfo: %d\n", __LINE__)); - - return NT_STATUS_OK; -} - -/**************************************************************** - _samr_GetDisplayEnumerationIndex -****************************************************************/ - -NTSTATUS _samr_GetDisplayEnumerationIndex(struct pipes_struct *p, - struct samr_GetDisplayEnumerationIndex *r) -{ - struct samr_domain_info *dinfo; - uint32_t max_entries = (uint32_t) -1; - uint32_t enum_context = 0; - int i; - uint32_t num_account = 0; - struct samr_displayentry *entries = NULL; - NTSTATUS status; - - DEBUG(5,("_samr_GetDisplayEnumerationIndex: %d\n", __LINE__)); - - dinfo = policy_handle_find(p, r->in.domain_handle, - SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if ((r->in.level < 1) || (r->in.level > 3)) { - DEBUG(0,("_samr_GetDisplayEnumerationIndex: " - "Unknown info level (%u)\n", - r->in.level)); - return NT_STATUS_INVALID_INFO_CLASS; - } - - become_root(); - - /* The following done as ROOT. Don't return without unbecome_root(). */ - - switch (r->in.level) { - case 1: - if (dinfo->disp_info->users == NULL) { - dinfo->disp_info->users = pdb_search_users( - dinfo->disp_info, ACB_NORMAL); - if (dinfo->disp_info->users == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - DEBUG(10,("_samr_GetDisplayEnumerationIndex: " - "starting user enumeration at index %u\n", - (unsigned int)enum_context)); - } else { - DEBUG(10,("_samr_GetDisplayEnumerationIndex: " - "using cached user enumeration at index %u\n", - (unsigned int)enum_context)); - } - num_account = pdb_search_entries(dinfo->disp_info->users, - enum_context, max_entries, - &entries); - break; - case 2: - if (dinfo->disp_info->machines == NULL) { - dinfo->disp_info->machines = pdb_search_users( - dinfo->disp_info, ACB_WSTRUST|ACB_SVRTRUST); - if (dinfo->disp_info->machines == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - DEBUG(10,("_samr_GetDisplayEnumerationIndex: " - "starting machine enumeration at index %u\n", - (unsigned int)enum_context)); - } else { - DEBUG(10,("_samr_GetDisplayEnumerationIndex: " - "using cached machine enumeration at index %u\n", - (unsigned int)enum_context)); - } - num_account = pdb_search_entries(dinfo->disp_info->machines, - enum_context, max_entries, - &entries); - break; - case 3: - if (dinfo->disp_info->groups == NULL) { - dinfo->disp_info->groups = pdb_search_groups( - dinfo->disp_info); - if (dinfo->disp_info->groups == NULL) { - unbecome_root(); - return NT_STATUS_ACCESS_DENIED; - } - DEBUG(10,("_samr_GetDisplayEnumerationIndex: " - "starting group enumeration at index %u\n", - (unsigned int)enum_context)); - } else { - DEBUG(10,("_samr_GetDisplayEnumerationIndex: " - "using cached group enumeration at index %u\n", - (unsigned int)enum_context)); - } - num_account = pdb_search_entries(dinfo->disp_info->groups, - enum_context, max_entries, - &entries); - break; - default: - unbecome_root(); - smb_panic("info class changed"); - break; - } - - unbecome_root(); - - /* Ensure we cache this enumeration. */ - set_disp_info_cache_timeout(dinfo->disp_info, DISP_INFO_CACHE_TIMEOUT); - - DEBUG(10,("_samr_GetDisplayEnumerationIndex: looking for :%s\n", - r->in.name->string)); - - for (i=0; iin.name->string)) { - DEBUG(10,("_samr_GetDisplayEnumerationIndex: " - "found %s at idx %d\n", - r->in.name->string, i)); - *r->out.idx = i; - return NT_STATUS_OK; - } - } - - /* assuming account_name lives at the very end */ - *r->out.idx = num_account; - - return NT_STATUS_NO_MORE_ENTRIES; -} - -/**************************************************************** - _samr_GetDisplayEnumerationIndex2 -****************************************************************/ - -NTSTATUS _samr_GetDisplayEnumerationIndex2(struct pipes_struct *p, - struct samr_GetDisplayEnumerationIndex2 *r) -{ - struct samr_GetDisplayEnumerationIndex q; - - q.in.domain_handle = r->in.domain_handle; - q.in.level = r->in.level; - q.in.name = r->in.name; - - q.out.idx = r->out.idx; - - return _samr_GetDisplayEnumerationIndex(p, &q); -} - -/**************************************************************** - _samr_RidToSid -****************************************************************/ - -NTSTATUS _samr_RidToSid(struct pipes_struct *p, - struct samr_RidToSid *r) -{ - struct samr_domain_info *dinfo; - NTSTATUS status; - struct dom_sid sid; - - dinfo = policy_handle_find(p, r->in.domain_handle, - 0, NULL, - struct samr_domain_info, &status); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!sid_compose(&sid, &dinfo->sid, r->in.rid)) { - return NT_STATUS_NO_MEMORY; - } - - *r->out.sid = dom_sid_dup(p->mem_ctx, &sid); - if (!*r->out.sid) { - return NT_STATUS_NO_MEMORY; - } - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -static enum samr_ValidationStatus samr_ValidatePassword_Change(TALLOC_CTX *mem_ctx, - const struct samr_PwInfo *dom_pw_info, - const struct samr_ValidatePasswordReq2 *req, - struct samr_ValidatePasswordRepCtr *rep) -{ - NTSTATUS status; - - if (req->password.string == NULL) { - return SAMR_VALIDATION_STATUS_SUCCESS; - } - if (strlen(req->password.string) < dom_pw_info->min_password_length) { - ZERO_STRUCT(rep->info); - return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT; - } - if (dom_pw_info->password_properties & DOMAIN_PASSWORD_COMPLEX) { - status = check_password_complexity(req->account.string, - req->password.string, - NULL); - if (!NT_STATUS_IS_OK(status)) { - ZERO_STRUCT(rep->info); - return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; - } - } - - return SAMR_VALIDATION_STATUS_SUCCESS; -} - -/**************************************************************** -****************************************************************/ - -static enum samr_ValidationStatus samr_ValidatePassword_Reset(TALLOC_CTX *mem_ctx, - const struct samr_PwInfo *dom_pw_info, - const struct samr_ValidatePasswordReq3 *req, - struct samr_ValidatePasswordRepCtr *rep) -{ - NTSTATUS status; - - if (req->password.string == NULL) { - return SAMR_VALIDATION_STATUS_SUCCESS; - } - if (strlen(req->password.string) < dom_pw_info->min_password_length) { - ZERO_STRUCT(rep->info); - return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT; - } - if (dom_pw_info->password_properties & DOMAIN_PASSWORD_COMPLEX) { - status = check_password_complexity(req->account.string, - req->password.string, - NULL); - if (!NT_STATUS_IS_OK(status)) { - ZERO_STRUCT(rep->info); - return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; - } - } - - return SAMR_VALIDATION_STATUS_SUCCESS; -} - -/**************************************************************** - _samr_ValidatePassword -****************************************************************/ - -NTSTATUS _samr_ValidatePassword(struct pipes_struct *p, - struct samr_ValidatePassword *r) -{ - union samr_ValidatePasswordRep *rep; - NTSTATUS status; - struct samr_GetDomPwInfo pw; - struct samr_PwInfo dom_pw_info; - - if (r->in.level < 1 || r->in.level > 3) { - return NT_STATUS_INVALID_INFO_CLASS; - } - - pw.in.domain_name = NULL; - pw.out.info = &dom_pw_info; - - status = _samr_GetDomPwInfo(p, &pw); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - rep = talloc_zero(p->mem_ctx, union samr_ValidatePasswordRep); - if (!rep) { - return NT_STATUS_NO_MEMORY; - } - - switch (r->in.level) { - case 1: - status = NT_STATUS_NOT_SUPPORTED; - break; - case 2: - rep->ctr2.status = samr_ValidatePassword_Change(p->mem_ctx, - &dom_pw_info, - &r->in.req->req2, - &rep->ctr2); - break; - case 3: - rep->ctr3.status = samr_ValidatePassword_Reset(p->mem_ctx, - &dom_pw_info, - &r->in.req->req3, - &rep->ctr3); - break; - default: - status = NT_STATUS_INVALID_INFO_CLASS; - break; - } - - if (!NT_STATUS_IS_OK(status)) { - talloc_free(rep); - return status; - } - - *r->out.rep = rep; - - return NT_STATUS_OK; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_Shutdown(struct pipes_struct *p, - struct samr_Shutdown *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_SetMemberAttributesOfGroup(struct pipes_struct *p, - struct samr_SetMemberAttributesOfGroup *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_TestPrivateFunctionsDomain(struct pipes_struct *p, - struct samr_TestPrivateFunctionsDomain *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_TestPrivateFunctionsUser(struct pipes_struct *p, - struct samr_TestPrivateFunctionsUser *r) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_AddMultipleMembersToAlias(struct pipes_struct *p, - struct samr_AddMultipleMembersToAlias *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_RemoveMultipleMembersFromAlias(struct pipes_struct *p, - struct samr_RemoveMultipleMembersFromAlias *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_SetBootKeyInformation(struct pipes_struct *p, - struct samr_SetBootKeyInformation *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_GetBootKeyInformation(struct pipes_struct *p, - struct samr_GetBootKeyInformation *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - -NTSTATUS _samr_SetDsrmPassword(struct pipes_struct *p, - struct samr_SetDsrmPassword *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} diff --git a/source3/rpc_server/srv_samr_util.c b/source3/rpc_server/srv_samr_util.c deleted file mode 100644 index 8bbcc1a5ee..0000000000 --- a/source3/rpc_server/srv_samr_util.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SAMR Pipe utility functions. - - Copyright (C) Luke Kenneth Casson Leighton 1996-1998 - Copyright (C) Gerald (Jerry) Carter 2000-2001 - Copyright (C) Andrew Bartlett 2001-2002 - Copyright (C) Stefan (metze) Metzmacher 2002 - Copyright (C) Guenther Deschner 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 . -*/ - -#include "includes.h" -#include "../librpc/gen_ndr/samr.h" -#include "rpc_server/srv_samr_util.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -#define STRING_CHANGED (old_string && !new_string) ||\ - (!old_string && new_string) ||\ - (old_string && new_string && (strcmp(old_string, new_string) != 0)) - -#define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\ - (!(s1) && (s2)) ||\ - ((s1) && (s2) && (strcmp((s1), (s2)) != 0)) - -/************************************************************* - Copies a struct samr_UserInfo2 to a struct samu -**************************************************************/ - -void copy_id2_to_sam_passwd(struct samu *to, - struct samr_UserInfo2 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_COMMENT | - SAMR_FIELD_COUNTRY_CODE | - SAMR_FIELD_CODE_PAGE; - i.comment = from->comment; - i.country_code = from->country_code; - i.code_page = from->code_page; - - copy_id21_to_sam_passwd("INFO_2", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo4 to a struct samu -**************************************************************/ - -void copy_id4_to_sam_passwd(struct samu *to, - struct samr_UserInfo4 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_LOGON_HOURS; - i.logon_hours = from->logon_hours; - - copy_id21_to_sam_passwd("INFO_4", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo6 to a struct samu -**************************************************************/ - -void copy_id6_to_sam_passwd(struct samu *to, - struct samr_UserInfo6 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_ACCOUNT_NAME | - SAMR_FIELD_FULL_NAME; - i.account_name = from->account_name; - i.full_name = from->full_name; - - copy_id21_to_sam_passwd("INFO_6", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo8 to a struct samu -**************************************************************/ - -void copy_id8_to_sam_passwd(struct samu *to, - struct samr_UserInfo8 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_FULL_NAME; - i.full_name = from->full_name; - - copy_id21_to_sam_passwd("INFO_8", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo10 to a struct samu -**************************************************************/ - -void copy_id10_to_sam_passwd(struct samu *to, - struct samr_UserInfo10 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_HOME_DIRECTORY | - SAMR_FIELD_HOME_DRIVE; - i.home_directory = from->home_directory; - i.home_drive = from->home_drive; - - copy_id21_to_sam_passwd("INFO_10", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo11 to a struct samu -**************************************************************/ - -void copy_id11_to_sam_passwd(struct samu *to, - struct samr_UserInfo11 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_LOGON_SCRIPT; - i.logon_script = from->logon_script; - - copy_id21_to_sam_passwd("INFO_11", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo12 to a struct samu -**************************************************************/ - -void copy_id12_to_sam_passwd(struct samu *to, - struct samr_UserInfo12 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_PROFILE_PATH; - i.profile_path = from->profile_path; - - copy_id21_to_sam_passwd("INFO_12", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo13 to a struct samu -**************************************************************/ - -void copy_id13_to_sam_passwd(struct samu *to, - struct samr_UserInfo13 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_DESCRIPTION; - i.description = from->description; - - copy_id21_to_sam_passwd("INFO_13", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo14 to a struct samu -**************************************************************/ - -void copy_id14_to_sam_passwd(struct samu *to, - struct samr_UserInfo14 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_WORKSTATIONS; - i.workstations = from->workstations; - - copy_id21_to_sam_passwd("INFO_14", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo16 to a struct samu -**************************************************************/ - -void copy_id16_to_sam_passwd(struct samu *to, - struct samr_UserInfo16 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_ACCT_FLAGS; - i.acct_flags = from->acct_flags; - - copy_id21_to_sam_passwd("INFO_16", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo17 to a struct samu -**************************************************************/ - -void copy_id17_to_sam_passwd(struct samu *to, - struct samr_UserInfo17 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_ACCT_EXPIRY; - i.acct_expiry = from->acct_expiry; - - copy_id21_to_sam_passwd("INFO_17", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo18 to a struct samu -**************************************************************/ - -void copy_id18_to_sam_passwd(struct samu *to, - struct samr_UserInfo18 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_EXPIRED_FLAG; - i.password_expired = from->password_expired; - - copy_id21_to_sam_passwd("INFO_18", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo20 to a struct samu -**************************************************************/ - -void copy_id20_to_sam_passwd(struct samu *to, - struct samr_UserInfo20 *from) -{ - const char *old_string; - char *new_string; - DATA_BLOB mung; - - if (from == NULL || to == NULL) { - return; - } - - if (from->parameters.array) { - old_string = pdb_get_munged_dial(to); - mung = data_blob_const(from->parameters.array, - from->parameters.length); - new_string = (mung.length == 0) ? - NULL : base64_encode_data_blob(talloc_tos(), mung); - DEBUG(10,("INFO_20 PARAMETERS: %s -> %s\n", - old_string, new_string)); - if (STRING_CHANGED_NC(old_string,new_string)) { - pdb_set_munged_dial(to, new_string, PDB_CHANGED); - } - - TALLOC_FREE(new_string); - } -} - -/************************************************************* - Copies a struct samr_UserInfo21 to a struct samu -**************************************************************/ - -void copy_id21_to_sam_passwd(const char *log_prefix, - struct samu *to, - struct samr_UserInfo21 *from) -{ - time_t unix_time, stored_time; - const char *old_string, *new_string; - const char *l; - - if (from == NULL || to == NULL) { - return; - } - - if (log_prefix) { - l = log_prefix; - } else { - l = "INFO_21"; - } - - if (from->fields_present & SAMR_FIELD_LAST_LOGON) { - unix_time = nt_time_to_unix(from->last_logon); - stored_time = pdb_get_logon_time(to); - DEBUG(10,("%s SAMR_FIELD_LAST_LOGON: %lu -> %lu\n", l, - (long unsigned int)stored_time, - (long unsigned int)unix_time)); - if (stored_time != unix_time) { - pdb_set_logon_time(to, unix_time, PDB_CHANGED); - } - } - - if (from->fields_present & SAMR_FIELD_LAST_LOGOFF) { - unix_time = nt_time_to_unix(from->last_logoff); - stored_time = pdb_get_logoff_time(to); - DEBUG(10,("%s SAMR_FIELD_LAST_LOGOFF: %lu -> %lu\n", l, - (long unsigned int)stored_time, - (long unsigned int)unix_time)); - if (stored_time != unix_time) { - pdb_set_logoff_time(to, unix_time, PDB_CHANGED); - } - } - - if (from->fields_present & SAMR_FIELD_ACCT_EXPIRY) { - unix_time = nt_time_to_unix(from->acct_expiry); - stored_time = pdb_get_kickoff_time(to); - DEBUG(10,("%s SAMR_FIELD_ACCT_EXPIRY: %lu -> %lu\n", l, - (long unsigned int)stored_time, - (long unsigned int)unix_time)); - if (stored_time != unix_time) { - pdb_set_kickoff_time(to, unix_time , PDB_CHANGED); - } - } - - if (from->fields_present & SAMR_FIELD_LAST_PWD_CHANGE) { - unix_time = nt_time_to_unix(from->last_password_change); - stored_time = pdb_get_pass_last_set_time(to); - DEBUG(10,("%s SAMR_FIELD_LAST_PWD_CHANGE: %lu -> %lu\n", l, - (long unsigned int)stored_time, - (long unsigned int)unix_time)); - if (stored_time != unix_time) { - pdb_set_pass_last_set_time(to, unix_time, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_ACCOUNT_NAME) && - (from->account_name.string)) { - old_string = pdb_get_username(to); - new_string = from->account_name.string; - DEBUG(10,("%s SAMR_FIELD_ACCOUNT_NAME: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_username(to, new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_FULL_NAME) && - (from->full_name.string)) { - old_string = pdb_get_fullname(to); - new_string = from->full_name.string; - DEBUG(10,("%s SAMR_FIELD_FULL_NAME: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_fullname(to, new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_HOME_DIRECTORY) && - (from->home_directory.string)) { - old_string = pdb_get_homedir(to); - new_string = from->home_directory.string; - DEBUG(10,("%s SAMR_FIELD_HOME_DIRECTORY: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_homedir(to, new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_HOME_DRIVE) && - (from->home_drive.string)) { - old_string = pdb_get_dir_drive(to); - new_string = from->home_drive.string; - DEBUG(10,("%s SAMR_FIELD_HOME_DRIVE: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_dir_drive(to, new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_LOGON_SCRIPT) && - (from->logon_script.string)) { - old_string = pdb_get_logon_script(to); - new_string = from->logon_script.string; - DEBUG(10,("%s SAMR_FIELD_LOGON_SCRIPT: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_logon_script(to , new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_PROFILE_PATH) && - (from->profile_path.string)) { - old_string = pdb_get_profile_path(to); - new_string = from->profile_path.string; - DEBUG(10,("%s SAMR_FIELD_PROFILE_PATH: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_profile_path(to , new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_DESCRIPTION) && - (from->description.string)) { - old_string = pdb_get_acct_desc(to); - new_string = from->description.string; - DEBUG(10,("%s SAMR_FIELD_DESCRIPTION: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_acct_desc(to, new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_WORKSTATIONS) && - (from->workstations.string)) { - old_string = pdb_get_workstations(to); - new_string = from->workstations.string; - DEBUG(10,("%s SAMR_FIELD_WORKSTATIONS: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_workstations(to , new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_COMMENT) && - (from->comment.string)) { - old_string = pdb_get_comment(to); - new_string = from->comment.string; - DEBUG(10,("%s SAMR_FIELD_COMMENT: %s -> %s\n", l, - old_string, new_string)); - if (STRING_CHANGED) { - pdb_set_comment(to, new_string, PDB_CHANGED); - } - } - - if ((from->fields_present & SAMR_FIELD_PARAMETERS) && - (from->parameters.array)) { - char *newstr; - DATA_BLOB mung; - old_string = pdb_get_munged_dial(to); - - mung = data_blob_const(from->parameters.array, - from->parameters.length); - newstr = (mung.length == 0) ? - NULL : base64_encode_data_blob(talloc_tos(), mung); - DEBUG(10,("%s SAMR_FIELD_PARAMETERS: %s -> %s\n", l, - old_string, newstr)); - if (STRING_CHANGED_NC(old_string,newstr)) { - pdb_set_munged_dial(to, newstr, PDB_CHANGED); - } - - TALLOC_FREE(newstr); - } - - if (from->fields_present & SAMR_FIELD_RID) { - if (from->rid == 0) { - DEBUG(10,("%s: Asked to set User RID to 0 !? Skipping change!\n", l)); - } else if (from->rid != pdb_get_user_rid(to)) { - DEBUG(10,("%s SAMR_FIELD_RID: %u -> %u NOT UPDATED!\n", l, - pdb_get_user_rid(to), from->rid)); - } - } - - if (from->fields_present & SAMR_FIELD_PRIMARY_GID) { - if (from->primary_gid == 0) { - DEBUG(10,("%s: Asked to set Group RID to 0 !? Skipping change!\n", l)); - } else if (from->primary_gid != pdb_get_group_rid(to)) { - DEBUG(10,("%s SAMR_FIELD_PRIMARY_GID: %u -> %u\n", l, - pdb_get_group_rid(to), from->primary_gid)); - pdb_set_group_sid_from_rid(to, - from->primary_gid, PDB_CHANGED); - } - } - - if (from->fields_present & SAMR_FIELD_ACCT_FLAGS) { - DEBUG(10,("%s SAMR_FIELD_ACCT_FLAGS: %08X -> %08X\n", l, - pdb_get_acct_ctrl(to), from->acct_flags)); - if (from->acct_flags != pdb_get_acct_ctrl(to)) { - - /* You cannot autolock an unlocked account via - * setuserinfo calls, so make sure to remove the - * ACB_AUTOLOCK bit here - gd */ - - if ((from->acct_flags & ACB_AUTOLOCK) && - !(pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) { - from->acct_flags &= ~ACB_AUTOLOCK; - } - - if (!(from->acct_flags & ACB_AUTOLOCK) && - (pdb_get_acct_ctrl(to) & ACB_AUTOLOCK)) { - /* We're unlocking a previously locked user. Reset bad password counts. - Patch from Jianliang Lu. */ - pdb_set_bad_password_count(to, 0, PDB_CHANGED); - pdb_set_bad_password_time(to, 0, PDB_CHANGED); - } - pdb_set_acct_ctrl(to, from->acct_flags, PDB_CHANGED); - } - } - - if (from->fields_present & SAMR_FIELD_LOGON_HOURS) { - char oldstr[44]; /* hours strings are 42 bytes. */ - char newstr[44]; - DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week): %08X -> %08X\n", l, - pdb_get_logon_divs(to), from->logon_hours.units_per_week)); - if (from->logon_hours.units_per_week != pdb_get_logon_divs(to)) { - pdb_set_logon_divs(to, - from->logon_hours.units_per_week, PDB_CHANGED); - } - - DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (units_per_week/8): %08X -> %08X\n", l, - pdb_get_hours_len(to), - from->logon_hours.units_per_week/8)); - if (from->logon_hours.units_per_week/8 != pdb_get_hours_len(to)) { - pdb_set_hours_len(to, - from->logon_hours.units_per_week/8, PDB_CHANGED); - } - - DEBUG(15,("%s SAMR_FIELD_LOGON_HOURS (bits): %s -> %s\n", l, - pdb_get_hours(to), from->logon_hours.bits)); - pdb_sethexhours(oldstr, pdb_get_hours(to)); - pdb_sethexhours(newstr, from->logon_hours.bits); - if (!strequal(oldstr, newstr)) { - pdb_set_hours(to, from->logon_hours.bits, PDB_CHANGED); - } - } - - if (from->fields_present & SAMR_FIELD_BAD_PWD_COUNT) { - DEBUG(10,("%s SAMR_FIELD_BAD_PWD_COUNT: %08X -> %08X\n", l, - pdb_get_bad_password_count(to), from->bad_password_count)); - if (from->bad_password_count != pdb_get_bad_password_count(to)) { - pdb_set_bad_password_count(to, - from->bad_password_count, PDB_CHANGED); - } - } - - if (from->fields_present & SAMR_FIELD_NUM_LOGONS) { - DEBUG(10,("%s SAMR_FIELD_NUM_LOGONS: %08X -> %08X\n", l, - pdb_get_logon_count(to), from->logon_count)); - if (from->logon_count != pdb_get_logon_count(to)) { - pdb_set_logon_count(to, from->logon_count, PDB_CHANGED); - } - } - - /* If the must change flag is set, the last set time goes to zero. - the must change and can change fields also do, but they are - calculated from policy, not set from the wire */ - - if (from->fields_present & SAMR_FIELD_EXPIRED_FLAG) { - DEBUG(10,("%s SAMR_FIELD_EXPIRED_FLAG: %02X\n", l, - from->password_expired)); - if (from->password_expired != 0) { - pdb_set_pass_last_set_time(to, 0, PDB_CHANGED); - } else { - /* A subtlety here: some windows commands will - clear the expired flag even though it's not - set, and we don't want to reset the time - in these caess. "net user /dom /active:y" - for example, to clear an autolocked acct. - We must check to see if it's expired first. jmcd */ - - uint32_t pwd_max_age = 0; - time_t now = time(NULL); - - pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &pwd_max_age); - - if (pwd_max_age == (uint32_t)-1 || pwd_max_age == 0) { - pwd_max_age = get_time_t_max(); - } - - stored_time = pdb_get_pass_last_set_time(to); - - /* we will only *set* a pwdlastset date when - a) the last pwdlastset time was 0 (user was forced to - change password). - b) the users password has not expired. gd. */ - - if ((stored_time == 0) || - ((now - stored_time) > pwd_max_age)) { - pdb_set_pass_last_set_time(to, now, PDB_CHANGED); - } - } - } -} - - -/************************************************************* - Copies a struct samr_UserInfo23 to a struct samu -**************************************************************/ - -void copy_id23_to_sam_passwd(struct samu *to, - struct samr_UserInfo23 *from) -{ - if (from == NULL || to == NULL) { - return; - } - - copy_id21_to_sam_passwd("INFO 23", to, &from->info); -} - -/************************************************************* - Copies a struct samr_UserInfo24 to a struct samu -**************************************************************/ - -void copy_id24_to_sam_passwd(struct samu *to, - struct samr_UserInfo24 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_EXPIRED_FLAG; - i.password_expired = from->password_expired; - - copy_id21_to_sam_passwd("INFO_24", to, &i); -} - -/************************************************************* - Copies a struct samr_UserInfo25 to a struct samu -**************************************************************/ - -void copy_id25_to_sam_passwd(struct samu *to, - struct samr_UserInfo25 *from) -{ - if (from == NULL || to == NULL) { - return; - } - - copy_id21_to_sam_passwd("INFO_25", to, &from->info); -} - -/************************************************************* - Copies a struct samr_UserInfo26 to a struct samu -**************************************************************/ - -void copy_id26_to_sam_passwd(struct samu *to, - struct samr_UserInfo26 *from) -{ - struct samr_UserInfo21 i; - - if (from == NULL || to == NULL) { - return; - } - - ZERO_STRUCT(i); - - i.fields_present = SAMR_FIELD_EXPIRED_FLAG; - i.password_expired = from->password_expired; - - copy_id21_to_sam_passwd("INFO_26", to, &i); -} diff --git a/source3/rpc_server/srv_samr_util.h b/source3/rpc_server/srv_samr_util.h deleted file mode 100644 index e898541559..0000000000 --- a/source3/rpc_server/srv_samr_util.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SAMR Pipe utility functions. - - Copyright (C) Luke Kenneth Casson Leighton 1996-1998 - Copyright (C) Gerald (Jerry) Carter 2000-2001 - Copyright (C) Andrew Bartlett 2001-2002 - Copyright (C) Stefan (metze) Metzmacher 2002 - Copyright (C) Guenther Deschner 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 . -*/ - -/* The following definitions come from rpc_server/srv_samr_util.c */ - -void copy_id2_to_sam_passwd(struct samu *to, - struct samr_UserInfo2 *from); -void copy_id4_to_sam_passwd(struct samu *to, - struct samr_UserInfo4 *from); -void copy_id6_to_sam_passwd(struct samu *to, - struct samr_UserInfo6 *from); -void copy_id8_to_sam_passwd(struct samu *to, - struct samr_UserInfo8 *from); -void copy_id10_to_sam_passwd(struct samu *to, - struct samr_UserInfo10 *from); -void copy_id11_to_sam_passwd(struct samu *to, - struct samr_UserInfo11 *from); -void copy_id12_to_sam_passwd(struct samu *to, - struct samr_UserInfo12 *from); -void copy_id13_to_sam_passwd(struct samu *to, - struct samr_UserInfo13 *from); -void copy_id14_to_sam_passwd(struct samu *to, - struct samr_UserInfo14 *from); -void copy_id16_to_sam_passwd(struct samu *to, - struct samr_UserInfo16 *from); -void copy_id17_to_sam_passwd(struct samu *to, - struct samr_UserInfo17 *from); -void copy_id18_to_sam_passwd(struct samu *to, - struct samr_UserInfo18 *from); -void copy_id20_to_sam_passwd(struct samu *to, - struct samr_UserInfo20 *from); -void copy_id21_to_sam_passwd(const char *log_prefix, - struct samu *to, - struct samr_UserInfo21 *from); -void copy_id23_to_sam_passwd(struct samu *to, - struct samr_UserInfo23 *from); -void copy_id24_to_sam_passwd(struct samu *to, - struct samr_UserInfo24 *from); -void copy_id25_to_sam_passwd(struct samu *to, - struct samr_UserInfo25 *from); -void copy_id26_to_sam_passwd(struct samu *to, - struct samr_UserInfo26 *from); - -/* The following definitions come from rpc_server/srv_samr_chgpasswd.c */ - -bool chgpasswd(const char *name, const char *rhost, const struct passwd *pass, - const char *oldpass, const char *newpass, bool as_root); -NTSTATUS pass_oem_change(char *user, const char *rhost, - uchar password_encrypted_with_lm_hash[516], - const uchar old_lm_hash_encrypted[16], - uchar password_encrypted_with_nt_hash[516], - const uchar old_nt_hash_encrypted[16], - enum samPwdChangeReason *reject_reason); -NTSTATUS check_password_complexity(const char *username, - const char *password, - enum samPwdChangeReason *samr_reject_reason); diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c deleted file mode 100644 index e2fc670d50..0000000000 --- a/source3/rpc_server/srv_spoolss_nt.c +++ /dev/null @@ -1,10658 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-2000, - * Copyright (C) Luke Kenneth Casson Leighton 1996-2000, - * Copyright (C) Jean François Micouleau 1998-2000, - * Copyright (C) Jeremy Allison 2001-2002, - * Copyright (C) Gerald Carter 2000-2004, - * Copyright (C) Tim Potter 2001-2002. - * Copyright (C) Guenther Deschner 2009-2010. - * Copyright (C) Andreas Schneider 2010. - * - * 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 . - */ - -/* Since the SPOOLSS rpc routines are basically DOS 16-bit calls wrapped - up, all the errors returned are DOS errors, not NT status codes. */ - -#include "includes.h" -#include "nt_printing.h" -#include "srv_spoolss_util.h" -#include "../librpc/gen_ndr/srv_spoolss.h" -#include "../librpc/gen_ndr/ndr_spoolss_c.h" -#include "rpc_client/init_spoolss.h" -#include "librpc/gen_ndr/messaging.h" -#include "../libcli/security/security.h" -#include "librpc/gen_ndr/ndr_security.h" -#include "registry.h" -#include "registry/reg_objects.h" -#include "include/printing.h" -#include "secrets.h" -#include "../librpc/gen_ndr/netlogon.h" -#include "rpc_misc.h" - -/* macros stolen from s4 spoolss server */ -#define SPOOLSS_BUFFER_UNION(fn,info,level) \ - ((info)?ndr_size_##fn(info, level, 0):0) - -#define SPOOLSS_BUFFER_UNION_ARRAY(mem_ctx,fn,info,level,count) \ - ((info)?ndr_size_##fn##_info(mem_ctx, level, count, info):0) - -#define SPOOLSS_BUFFER_ARRAY(mem_ctx,fn,info,count) \ - ((info)?ndr_size_##fn##_info(mem_ctx, count, info):0) - -#define SPOOLSS_BUFFER_OK(val_true,val_false) ((r->in.offered >= *r->out.needed)?val_true:val_false) - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -#ifndef MAX_OPEN_PRINTER_EXS -#define MAX_OPEN_PRINTER_EXS 50 -#endif - -struct notify_back_channel; - -/* structure to store the printer handles */ -/* and a reference to what it's pointing to */ -/* and the notify info asked about */ -/* that's the central struct */ -struct printer_handle { - struct printer_handle *prev, *next; - bool document_started; - bool page_started; - uint32 jobid; /* jobid in printing backend */ - int printer_type; - const char *servername; - fstring sharename; - uint32 type; - uint32 access_granted; - struct { - uint32 flags; - uint32 options; - fstring localmachine; - uint32 printerlocal; - struct spoolss_NotifyOption *option; - struct policy_handle cli_hnd; - struct notify_back_channel *cli_chan; - uint32 change; - /* are we in a FindNextPrinterChangeNotify() call? */ - bool fnpcn; - struct messaging_context *msg_ctx; - } notify; - struct { - fstring machine; - fstring user; - } client; - - /* devmode sent in the OpenPrinter() call */ - struct spoolss_DeviceMode *devmode; - - /* TODO cache the printer info2 structure */ - struct spoolss_PrinterInfo2 *info2; - -}; - -static struct printer_handle *printers_list; - -struct printer_session_counter { - struct printer_session_counter *next; - struct printer_session_counter *prev; - - int snum; - uint32_t counter; -}; - -static struct printer_session_counter *counter_list; - -struct notify_back_channel { - struct notify_back_channel *prev, *next; - - /* associated client */ - struct sockaddr_storage client_address; - - /* print notify back-channel pipe handle*/ - struct rpc_pipe_client *cli_pipe; - struct dcerpc_binding_handle *binding_handle; - uint32_t active_connections; -}; - -static struct notify_back_channel *back_channels; - -/* Map generic permissions to printer object specific permissions */ - -const struct standard_mapping printer_std_mapping = { - PRINTER_READ, - PRINTER_WRITE, - PRINTER_EXECUTE, - PRINTER_ALL_ACCESS -}; - -/* Map generic permissions to print server object specific permissions */ - -const struct standard_mapping printserver_std_mapping = { - SERVER_READ, - SERVER_WRITE, - SERVER_EXECUTE, - SERVER_ALL_ACCESS -}; - -/* API table for Xcv Monitor functions */ - -struct xcv_api_table { - const char *name; - WERROR(*fn) (TALLOC_CTX *mem_ctx, struct security_token *token, DATA_BLOB *in, DATA_BLOB *out, uint32_t *needed); -}; - -static void prune_printername_cache(void); - -/******************************************************************** - * Canonicalize servername. - ********************************************************************/ - -static const char *canon_servername(const char *servername) -{ - const char *pservername = servername; - while (*pservername == '\\') { - pservername++; - } - return pservername; -} - -/* translate between internal status numbers and NT status numbers */ -static int nt_printj_status(int v) -{ - switch (v) { - case LPQ_QUEUED: - return 0; - case LPQ_PAUSED: - return JOB_STATUS_PAUSED; - case LPQ_SPOOLING: - return JOB_STATUS_SPOOLING; - case LPQ_PRINTING: - return JOB_STATUS_PRINTING; - case LPQ_ERROR: - return JOB_STATUS_ERROR; - case LPQ_DELETING: - return JOB_STATUS_DELETING; - case LPQ_OFFLINE: - return JOB_STATUS_OFFLINE; - case LPQ_PAPEROUT: - return JOB_STATUS_PAPEROUT; - case LPQ_PRINTED: - return JOB_STATUS_PRINTED; - case LPQ_DELETED: - return JOB_STATUS_DELETED; - case LPQ_BLOCKED: - return JOB_STATUS_BLOCKED_DEVQ; - case LPQ_USER_INTERVENTION: - return JOB_STATUS_USER_INTERVENTION; - } - return 0; -} - -static int nt_printq_status(int v) -{ - switch (v) { - case LPQ_PAUSED: - return PRINTER_STATUS_PAUSED; - case LPQ_QUEUED: - case LPQ_SPOOLING: - case LPQ_PRINTING: - return 0; - } - return 0; -} - -/*************************************************************************** - Disconnect from the client -****************************************************************************/ - -static void srv_spoolss_replycloseprinter(int snum, - struct printer_handle *prn_hnd) -{ - WERROR result; - NTSTATUS status; - - /* - * Tell the specific printing tdb we no longer want messages for this printer - * by deregistering our PID. - */ - - if (!print_notify_deregister_pid(snum)) { - DEBUG(0, ("Failed to register our pid for printer %s\n", - lp_const_servicename(snum))); - } - - /* weird if the test succeeds !!! */ - if (prn_hnd->notify.cli_chan == NULL || - prn_hnd->notify.cli_chan->active_connections == 0) { - DEBUG(0, ("Trying to close unexisting backchannel!\n")); - DLIST_REMOVE(back_channels, prn_hnd->notify.cli_chan); - TALLOC_FREE(prn_hnd->notify.cli_chan); - return; - } - - status = dcerpc_spoolss_ReplyClosePrinter( - prn_hnd->notify.cli_chan->binding_handle, - talloc_tos(), - &prn_hnd->notify.cli_hnd, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("dcerpc_spoolss_ReplyClosePrinter failed [%s].\n", - nt_errstr(status))); - result = ntstatus_to_werror(status); - } else if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("reply_close_printer failed [%s].\n", - win_errstr(result))); - } - - /* if it's the last connection, deconnect the IPC$ share */ - if (prn_hnd->notify.cli_chan->active_connections == 1) { - - prn_hnd->notify.cli_chan->binding_handle = NULL; - cli_shutdown(rpc_pipe_np_smb_conn(prn_hnd->notify.cli_chan->cli_pipe)); - DLIST_REMOVE(back_channels, prn_hnd->notify.cli_chan); - TALLOC_FREE(prn_hnd->notify.cli_chan); - - if (prn_hnd->notify.msg_ctx != NULL) { - messaging_deregister(prn_hnd->notify.msg_ctx, - MSG_PRINTER_NOTIFY2, NULL); - - /* - * Tell the serverid.tdb we're no longer - * interested in printer notify messages. - */ - - serverid_register_msg_flags( - messaging_server_id(prn_hnd->notify.msg_ctx), - false, FLAG_MSG_PRINT_NOTIFY); - } - } - - if (prn_hnd->notify.cli_chan) { - prn_hnd->notify.cli_chan->active_connections--; - } -} - -/**************************************************************************** - Functions to free a printer entry datastruct. -****************************************************************************/ - -static int printer_entry_destructor(struct printer_handle *Printer) -{ - if (Printer->notify.cli_chan != NULL && - Printer->notify.cli_chan->active_connections > 0) { - int snum = -1; - - switch(Printer->printer_type) { - case SPLHND_SERVER: - srv_spoolss_replycloseprinter(snum, Printer); - break; - - case SPLHND_PRINTER: - snum = print_queue_snum(Printer->sharename); - if (snum != -1) { - srv_spoolss_replycloseprinter(snum, Printer); - } - break; - default: - break; - } - } - - Printer->notify.flags=0; - Printer->notify.options=0; - Printer->notify.localmachine[0]='\0'; - Printer->notify.printerlocal=0; - TALLOC_FREE(Printer->notify.option); - TALLOC_FREE(Printer->devmode); - - /* Remove from the internal list. */ - DLIST_REMOVE(printers_list, Printer); - return 0; -} - -/**************************************************************************** - find printer index by handle -****************************************************************************/ - -static struct printer_handle *find_printer_index_by_hnd(struct pipes_struct *p, - struct policy_handle *hnd) -{ - struct printer_handle *find_printer = NULL; - - if(!find_policy_by_hnd(p,hnd,(void **)(void *)&find_printer)) { - DEBUG(2,("find_printer_index_by_hnd: Printer handle not found: ")); - return NULL; - } - - return find_printer; -} - -/**************************************************************************** - Close printer index by handle. -****************************************************************************/ - -static bool close_printer_handle(struct pipes_struct *p, struct policy_handle *hnd) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); - - if (!Printer) { - DEBUG(2,("close_printer_handle: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(hnd))); - return false; - } - - close_policy_hnd(p, hnd); - - return true; -} - -/**************************************************************************** - Delete a printer given a handle. -****************************************************************************/ - -static WERROR delete_printer_hook(TALLOC_CTX *ctx, struct security_token *token, - const char *sharename, - struct messaging_context *msg_ctx) -{ - char *cmd = lp_deleteprinter_cmd(); - char *command = NULL; - int ret; - bool is_print_op = false; - - /* can't fail if we don't try */ - - if ( !*cmd ) - return WERR_OK; - - command = talloc_asprintf(ctx, - "%s \"%s\"", - cmd, sharename); - if (!command) { - return WERR_NOMEM; - } - if ( token ) - is_print_op = security_token_has_privilege(token, SEC_PRIV_PRINT_OPERATOR); - - DEBUG(10,("Running [%s]\n", command)); - - /********** BEGIN SePrintOperatorPrivlege BLOCK **********/ - - if ( is_print_op ) - become_root(); - - if ( (ret = smbrun(command, NULL)) == 0 ) { - /* Tell everyone we updated smb.conf. */ - message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL); - } - - if ( is_print_op ) - unbecome_root(); - - /********** END SePrintOperatorPrivlege BLOCK **********/ - - DEBUGADD(10,("returned [%d]\n", ret)); - - TALLOC_FREE(command); - - if (ret != 0) - return WERR_BADFID; /* What to return here? */ - - /* go ahead and re-read the services immediately */ - become_root(); - reload_services(msg_ctx, -1, false); - unbecome_root(); - - if ( lp_servicenumber( sharename ) >= 0 ) - return WERR_ACCESS_DENIED; - - return WERR_OK; -} - -/**************************************************************************** - Delete a printer given a handle. -****************************************************************************/ - -static WERROR delete_printer_handle(struct pipes_struct *p, struct policy_handle *hnd) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); - WERROR result; - - if (!Printer) { - DEBUG(2,("delete_printer_handle: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(hnd))); - return WERR_BADFID; - } - - /* - * It turns out that Windows allows delete printer on a handle - * opened by an admin user, then used on a pipe handle created - * by an anonymous user..... but they're working on security.... riiight ! - * JRA. - */ - - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("delete_printer_handle: denied by handle\n")); - return WERR_ACCESS_DENIED; - } - - /* this does not need a become root since the access check has been - done on the handle already */ - - result = winreg_delete_printer_key(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - Printer->sharename, - ""); - if (!W_ERROR_IS_OK(result)) { - DEBUG(3,("Error deleting printer %s\n", Printer->sharename)); - return WERR_BADFID; - } - - result = delete_printer_hook(p->mem_ctx, p->server_info->security_token, - Printer->sharename, p->msg_ctx); - if (!W_ERROR_IS_OK(result)) { - return result; - } - prune_printername_cache(); - return WERR_OK; -} - -/**************************************************************************** - Return the snum of a printer corresponding to an handle. -****************************************************************************/ - -static bool get_printer_snum(struct pipes_struct *p, struct policy_handle *hnd, - int *number, struct share_params **params) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); - - if (!Printer) { - DEBUG(2,("get_printer_snum: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(hnd))); - return false; - } - - switch (Printer->printer_type) { - case SPLHND_PRINTER: - DEBUG(4,("short name:%s\n", Printer->sharename)); - *number = print_queue_snum(Printer->sharename); - return (*number != -1); - case SPLHND_SERVER: - return false; - default: - return false; - } -} - -/**************************************************************************** - Set printer handle type. - Check if it's \\server or \\server\printer -****************************************************************************/ - -static bool set_printer_hnd_printertype(struct printer_handle *Printer, const char *handlename) -{ - DEBUG(3,("Setting printer type=%s\n", handlename)); - - /* it's a print server */ - if (handlename && *handlename=='\\' && *(handlename+1)=='\\' && !strchr_m(handlename+2, '\\')) { - DEBUGADD(4,("Printer is a print server\n")); - Printer->printer_type = SPLHND_SERVER; - } - /* it's a printer (set_printer_hnd_name() will handle port monitors */ - else { - DEBUGADD(4,("Printer is a printer\n")); - Printer->printer_type = SPLHND_PRINTER; - } - - return true; -} - -static void prune_printername_cache_fn(const char *key, const char *value, - time_t timeout, void *private_data) -{ - gencache_del(key); -} - -static void prune_printername_cache(void) -{ - gencache_iterate(prune_printername_cache_fn, NULL, "PRINTERNAME/*"); -} - -/**************************************************************************** - Set printer handle name.. Accept names like \\server, \\server\printer, - \\server\SHARE, & "\\server\,XcvMonitor Standard TCP/IP Port" See - the MSDN docs regarding OpenPrinter() for details on the XcvData() and - XcvDataPort() interface. -****************************************************************************/ - -static WERROR set_printer_hnd_name(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct printer_handle *Printer, - const char *handlename) -{ - int snum; - int n_services=lp_numservices(); - char *aprinter; - const char *printername; - const char *servername = NULL; - fstring sname; - bool found = false; - struct spoolss_PrinterInfo2 *info2 = NULL; - WERROR result; - char *p; - - /* - * Hopefully nobody names his printers like this. Maybe \ or , - * are illegal in printer names even? - */ - const char printer_not_found[] = "Printer \\, !@#$%^&*( not found"; - char *cache_key; - char *tmp; - - DEBUG(4,("Setting printer name=%s (len=%lu)\n", handlename, - (unsigned long)strlen(handlename))); - - aprinter = CONST_DISCARD(char *, handlename); - if ( *handlename == '\\' ) { - servername = canon_servername(handlename); - if ( (aprinter = strchr_m( servername, '\\' )) != NULL ) { - *aprinter = '\0'; - aprinter++; - } - if (!is_myname_or_ipaddr(servername)) { - return WERR_INVALID_PRINTER_NAME; - } - Printer->servername = talloc_asprintf(Printer, "\\\\%s", servername); - if (Printer->servername == NULL) { - return WERR_NOMEM; - } - } - - if (Printer->printer_type == SPLHND_SERVER) { - return WERR_OK; - } - - if (Printer->printer_type != SPLHND_PRINTER) { - return WERR_INVALID_HANDLE; - } - - DEBUGADD(5, ("searching for [%s]\n", aprinter)); - - p = strchr(aprinter, ','); - if (p != NULL) { - char *p2 = p; - p++; - if (*p == ' ') { - p++; - } - if (strncmp(p, "DrvConvert", strlen("DrvConvert")) == 0) { - *p2 = '\0'; - } else if (strncmp(p, "LocalOnly", strlen("LocalOnly")) == 0) { - *p2 = '\0'; - } - } - - if (p) { - DEBUGADD(5, ("stripped handlename: [%s]\n", aprinter)); - } - - /* check for the Port Monitor Interface */ - if ( strequal( aprinter, SPL_XCV_MONITOR_TCPMON ) ) { - Printer->printer_type = SPLHND_PORTMON_TCP; - fstrcpy(sname, SPL_XCV_MONITOR_TCPMON); - found = true; - } - else if ( strequal( aprinter, SPL_XCV_MONITOR_LOCALMON ) ) { - Printer->printer_type = SPLHND_PORTMON_LOCAL; - fstrcpy(sname, SPL_XCV_MONITOR_LOCALMON); - found = true; - } - - /* - * With hundreds of printers, the "for" loop iterating all - * shares can be quite expensive, as it is done on every - * OpenPrinter. The loop maps "aprinter" to "sname", the - * result of which we cache in gencache. - */ - - cache_key = talloc_asprintf(talloc_tos(), "PRINTERNAME/%s", - aprinter); - if ((cache_key != NULL) && gencache_get(cache_key, &tmp, NULL)) { - - found = (strcmp(tmp, printer_not_found) != 0); - if (!found) { - DEBUG(4, ("Printer %s not found\n", aprinter)); - SAFE_FREE(tmp); - return WERR_INVALID_PRINTER_NAME; - } - fstrcpy(sname, tmp); - SAFE_FREE(tmp); - } - - /* Search all sharenames first as this is easier than pulling - the printer_info_2 off of disk. Don't use find_service() since - that calls out to map_username() */ - - /* do another loop to look for printernames */ - for (snum = 0; !found && snum < n_services; snum++) { - const char *printer = lp_const_servicename(snum); - - /* no point going on if this is not a printer */ - if (!(lp_snum_ok(snum) && lp_print_ok(snum))) { - continue; - } - - /* ignore [printers] share */ - if (strequal(printer, "printers")) { - continue; - } - - fstrcpy(sname, printer); - if (strequal(aprinter, printer)) { - found = true; - break; - } - - /* no point looking up the printer object if - we aren't allowing printername != sharename */ - if (lp_force_printername(snum)) { - continue; - } - - result = winreg_get_printer(mem_ctx, - server_info, - msg_ctx, - sname, - &info2); - if ( !W_ERROR_IS_OK(result) ) { - DEBUG(2,("set_printer_hnd_name: failed to lookup printer [%s] -- result [%s]\n", - sname, win_errstr(result))); - continue; - } - - printername = strrchr(info2->printername, '\\'); - if (printername == NULL) { - printername = info2->printername; - } else { - printername++; - } - - if (strequal(printername, aprinter)) { - found = true; - break; - } - - DEBUGADD(10, ("printername: %s\n", printername)); - - TALLOC_FREE(info2); - } - - if ( !found ) { - if (cache_key != NULL) { - gencache_set(cache_key, printer_not_found, - time(NULL)+300); - TALLOC_FREE(cache_key); - } - DEBUGADD(4,("Printer not found\n")); - return WERR_INVALID_PRINTER_NAME; - } - - if (cache_key != NULL) { - gencache_set(cache_key, sname, time(NULL)+300); - TALLOC_FREE(cache_key); - } - - DEBUGADD(4,("set_printer_hnd_name: Printer found: %s -> %s\n", aprinter, sname)); - - fstrcpy(Printer->sharename, sname); - - return WERR_OK; -} - -/**************************************************************************** - Find first available printer slot. creates a printer handle for you. - ****************************************************************************/ - -static WERROR open_printer_hnd(struct pipes_struct *p, - struct policy_handle *hnd, - const char *name, - uint32_t access_granted) -{ - struct printer_handle *new_printer; - WERROR result; - - DEBUG(10,("open_printer_hnd: name [%s]\n", name)); - - new_printer = talloc_zero(p->mem_ctx, struct printer_handle); - if (new_printer == NULL) { - return WERR_NOMEM; - } - talloc_set_destructor(new_printer, printer_entry_destructor); - - /* This also steals the printer_handle on the policy_handle */ - if (!create_policy_hnd(p, hnd, new_printer)) { - TALLOC_FREE(new_printer); - return WERR_INVALID_HANDLE; - } - - /* Add to the internal list. */ - DLIST_ADD(printers_list, new_printer); - - new_printer->notify.option=NULL; - - if (!set_printer_hnd_printertype(new_printer, name)) { - close_printer_handle(p, hnd); - return WERR_INVALID_HANDLE; - } - - result = set_printer_hnd_name(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - new_printer, name); - if (!W_ERROR_IS_OK(result)) { - close_printer_handle(p, hnd); - return result; - } - - new_printer->access_granted = access_granted; - - DEBUG(5, ("%d printer handles active\n", - (int)num_pipe_handles(p))); - - return WERR_OK; -} - -/*************************************************************************** - check to see if the client motify handle is monitoring the notification - given by (notify_type, notify_field). - **************************************************************************/ - -static bool is_monitoring_event_flags(uint32_t flags, uint16_t notify_type, - uint16_t notify_field) -{ - return true; -} - -static bool is_monitoring_event(struct printer_handle *p, uint16_t notify_type, - uint16_t notify_field) -{ - struct spoolss_NotifyOption *option = p->notify.option; - uint32_t i, j; - - /* - * Flags should always be zero when the change notify - * is registered by the client's spooler. A user Win32 app - * might use the flags though instead of the NOTIFY_OPTION_INFO - * --jerry - */ - - if (!option) { - return false; - } - - if (p->notify.flags) - return is_monitoring_event_flags( - p->notify.flags, notify_type, notify_field); - - for (i = 0; i < option->count; i++) { - - /* Check match for notify_type */ - - if (option->types[i].type != notify_type) - continue; - - /* Check match for field */ - - for (j = 0; j < option->types[i].count; j++) { - if (option->types[i].fields[j].field == notify_field) { - return true; - } - } - } - - DEBUG(10, ("Open handle for \\\\%s\\%s is not monitoring 0x%02x/0x%02x\n", - p->servername, p->sharename, notify_type, notify_field)); - - return false; -} - -#define SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(_data, _integer) \ - _data->data.integer[0] = _integer; \ - _data->data.integer[1] = 0; - - -#define SETUP_SPOOLSS_NOTIFY_DATA_STRING(_data, _p) \ - _data->data.string.string = talloc_strdup(mem_ctx, _p); \ - if (!_data->data.string.string) {\ - _data->data.string.size = 0; \ - } \ - _data->data.string.size = strlen_m_term(_p) * 2; - -#define SETUP_SPOOLSS_NOTIFY_DATA_DEVMODE(_data, _devmode) \ - _data->data.devmode.devmode = _devmode; - -#define SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(_data, _sd) \ - _data->data.sd.sd = dup_sec_desc(mem_ctx, _sd); \ - if (!_data->data.sd.sd) { \ - _data->data.sd.sd_size = 0; \ - } \ - _data->data.sd.sd_size = \ - ndr_size_security_descriptor(_data->data.sd.sd, 0); - -static void init_systemtime_buffer(TALLOC_CTX *mem_ctx, - struct tm *t, - const char **pp, - uint32_t *plen) -{ - struct spoolss_Time st; - uint32_t len = 16; - char *p; - - if (!init_systemtime(&st, t)) { - return; - } - - p = talloc_array(mem_ctx, char, len); - if (!p) { - return; - } - - /* - * Systemtime must be linearized as a set of UINT16's. - * Fix from Benjamin (Bj) Kuit bj@it.uts.edu.au - */ - - SSVAL(p, 0, st.year); - SSVAL(p, 2, st.month); - SSVAL(p, 4, st.day_of_week); - SSVAL(p, 6, st.day); - SSVAL(p, 8, st.hour); - SSVAL(p, 10, st.minute); - SSVAL(p, 12, st.second); - SSVAL(p, 14, st.millisecond); - - *pp = p; - *plen = len; -} - -/* Convert a notification message to a struct spoolss_Notify */ - -static void notify_one_value(struct spoolss_notify_msg *msg, - struct spoolss_Notify *data, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, msg->notify.value[0]); -} - -static void notify_string(struct spoolss_notify_msg *msg, - struct spoolss_Notify *data, - TALLOC_CTX *mem_ctx) -{ - /* The length of the message includes the trailing \0 */ - - data->data.string.size = msg->len * 2; - data->data.string.string = talloc_strdup(mem_ctx, msg->notify.data); - if (!data->data.string.string) { - data->data.string.size = 0; - return; - } -} - -static void notify_system_time(struct spoolss_notify_msg *msg, - struct spoolss_Notify *data, - TALLOC_CTX *mem_ctx) -{ - data->data.string.string = NULL; - data->data.string.size = 0; - - if (msg->len != sizeof(time_t)) { - DEBUG(5, ("notify_system_time: received wrong sized message (%d)\n", - msg->len)); - return; - } - - init_systemtime_buffer(mem_ctx, gmtime((time_t *)msg->notify.data), - &data->data.string.string, - &data->data.string.size); -} - -struct notify2_message_table { - const char *name; - void (*fn)(struct spoolss_notify_msg *msg, - struct spoolss_Notify *data, TALLOC_CTX *mem_ctx); -}; - -static struct notify2_message_table printer_notify_table[] = { - /* 0x00 */ { "PRINTER_NOTIFY_FIELD_SERVER_NAME", notify_string }, - /* 0x01 */ { "PRINTER_NOTIFY_FIELD_PRINTER_NAME", notify_string }, - /* 0x02 */ { "PRINTER_NOTIFY_FIELD_SHARE_NAME", notify_string }, - /* 0x03 */ { "PRINTER_NOTIFY_FIELD_PORT_NAME", notify_string }, - /* 0x04 */ { "PRINTER_NOTIFY_FIELD_DRIVER_NAME", notify_string }, - /* 0x05 */ { "PRINTER_NOTIFY_FIELD_COMMENT", notify_string }, - /* 0x06 */ { "PRINTER_NOTIFY_FIELD_LOCATION", notify_string }, - /* 0x07 */ { "PRINTER_NOTIFY_FIELD_DEVMODE", NULL }, - /* 0x08 */ { "PRINTER_NOTIFY_FIELD_SEPFILE", notify_string }, - /* 0x09 */ { "PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR", notify_string }, - /* 0x0a */ { "PRINTER_NOTIFY_FIELD_PARAMETERS", NULL }, - /* 0x0b */ { "PRINTER_NOTIFY_FIELD_DATATYPE", notify_string }, - /* 0x0c */ { "PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NULL }, - /* 0x0d */ { "PRINTER_NOTIFY_FIELD_ATTRIBUTES", notify_one_value }, - /* 0x0e */ { "PRINTER_NOTIFY_FIELD_PRIORITY", notify_one_value }, - /* 0x0f */ { "PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY", NULL }, - /* 0x10 */ { "PRINTER_NOTIFY_FIELD_START_TIME", NULL }, - /* 0x11 */ { "PRINTER_NOTIFY_FIELD_UNTIL_TIME", NULL }, - /* 0x12 */ { "PRINTER_NOTIFY_FIELD_STATUS", notify_one_value }, -}; - -static struct notify2_message_table job_notify_table[] = { - /* 0x00 */ { "JOB_NOTIFY_FIELD_PRINTER_NAME", NULL }, - /* 0x01 */ { "JOB_NOTIFY_FIELD_MACHINE_NAME", NULL }, - /* 0x02 */ { "JOB_NOTIFY_FIELD_PORT_NAME", NULL }, - /* 0x03 */ { "JOB_NOTIFY_FIELD_USER_NAME", notify_string }, - /* 0x04 */ { "JOB_NOTIFY_FIELD_NOTIFY_NAME", NULL }, - /* 0x05 */ { "JOB_NOTIFY_FIELD_DATATYPE", NULL }, - /* 0x06 */ { "JOB_NOTIFY_FIELD_PRINT_PROCESSOR", NULL }, - /* 0x07 */ { "JOB_NOTIFY_FIELD_PARAMETERS", NULL }, - /* 0x08 */ { "JOB_NOTIFY_FIELD_DRIVER_NAME", NULL }, - /* 0x09 */ { "JOB_NOTIFY_FIELD_DEVMODE", NULL }, - /* 0x0a */ { "JOB_NOTIFY_FIELD_STATUS", notify_one_value }, - /* 0x0b */ { "JOB_NOTIFY_FIELD_STATUS_STRING", NULL }, - /* 0x0c */ { "JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NULL }, - /* 0x0d */ { "JOB_NOTIFY_FIELD_DOCUMENT", notify_string }, - /* 0x0e */ { "JOB_NOTIFY_FIELD_PRIORITY", NULL }, - /* 0x0f */ { "JOB_NOTIFY_FIELD_POSITION", NULL }, - /* 0x10 */ { "JOB_NOTIFY_FIELD_SUBMITTED", notify_system_time }, - /* 0x11 */ { "JOB_NOTIFY_FIELD_START_TIME", NULL }, - /* 0x12 */ { "JOB_NOTIFY_FIELD_UNTIL_TIME", NULL }, - /* 0x13 */ { "JOB_NOTIFY_FIELD_TIME", NULL }, - /* 0x14 */ { "JOB_NOTIFY_FIELD_TOTAL_PAGES", notify_one_value }, - /* 0x15 */ { "JOB_NOTIFY_FIELD_PAGES_PRINTED", NULL }, - /* 0x16 */ { "JOB_NOTIFY_FIELD_TOTAL_BYTES", notify_one_value }, - /* 0x17 */ { "JOB_NOTIFY_FIELD_BYTES_PRINTED", NULL }, -}; - - -/*********************************************************************** - Allocate talloc context for container object - **********************************************************************/ - -static void notify_msg_ctr_init( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return; - - ctr->ctx = talloc_init("notify_msg_ctr_init %p", ctr); - - return; -} - -/*********************************************************************** - release all allocated memory and zero out structure - **********************************************************************/ - -static void notify_msg_ctr_destroy( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return; - - if ( ctr->ctx ) - talloc_destroy(ctr->ctx); - - ZERO_STRUCTP(ctr); - - return; -} - -/*********************************************************************** - **********************************************************************/ - -static TALLOC_CTX* notify_ctr_getctx( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return NULL; - - return ctr->ctx; -} - -/*********************************************************************** - **********************************************************************/ - -static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32_t idx ) -{ - if ( !ctr || !ctr->msg_groups ) - return NULL; - - if ( idx >= ctr->num_groups ) - return NULL; - - return &ctr->msg_groups[idx]; - -} - -/*********************************************************************** - How many groups of change messages do we have ? - **********************************************************************/ - -static int notify_msg_ctr_numgroups( SPOOLSS_NOTIFY_MSG_CTR *ctr ) -{ - if ( !ctr ) - return 0; - - return ctr->num_groups; -} - -/*********************************************************************** - Add a SPOOLSS_NOTIFY_MSG_CTR to the correct group - **********************************************************************/ - -static int notify_msg_ctr_addmsg( SPOOLSS_NOTIFY_MSG_CTR *ctr, SPOOLSS_NOTIFY_MSG *msg ) -{ - SPOOLSS_NOTIFY_MSG_GROUP *groups = NULL; - SPOOLSS_NOTIFY_MSG_GROUP *msg_grp = NULL; - SPOOLSS_NOTIFY_MSG *msg_list = NULL; - int i, new_slot; - - if ( !ctr || !msg ) - return 0; - - /* loop over all groups looking for a matching printer name */ - - for ( i=0; inum_groups; i++ ) { - if ( strcmp(ctr->msg_groups[i].printername, msg->printer) == 0 ) - break; - } - - /* add a new group? */ - - if ( i == ctr->num_groups ) { - ctr->num_groups++; - - if ( !(groups = TALLOC_REALLOC_ARRAY( ctr->ctx, ctr->msg_groups, SPOOLSS_NOTIFY_MSG_GROUP, ctr->num_groups)) ) { - DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed!\n")); - return 0; - } - ctr->msg_groups = groups; - - /* clear the new entry and set the printer name */ - - ZERO_STRUCT( ctr->msg_groups[ctr->num_groups-1] ); - fstrcpy( ctr->msg_groups[ctr->num_groups-1].printername, msg->printer ); - } - - /* add the change messages; 'i' is the correct index now regardless */ - - msg_grp = &ctr->msg_groups[i]; - - msg_grp->num_msgs++; - - if ( !(msg_list = TALLOC_REALLOC_ARRAY( ctr->ctx, msg_grp->msgs, SPOOLSS_NOTIFY_MSG, msg_grp->num_msgs )) ) { - DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed for new message [%d]!\n", msg_grp->num_msgs)); - return 0; - } - msg_grp->msgs = msg_list; - - new_slot = msg_grp->num_msgs-1; - memcpy( &msg_grp->msgs[new_slot], msg, sizeof(SPOOLSS_NOTIFY_MSG) ); - - /* need to allocate own copy of data */ - - if ( msg->len != 0 ) - msg_grp->msgs[new_slot].notify.data = (char *) - TALLOC_MEMDUP( ctr->ctx, msg->notify.data, msg->len ); - - return ctr->num_groups; -} - -static void construct_info_data(struct spoolss_Notify *info_data, - enum spoolss_NotifyType type, - uint16_t field, int id); - -/*********************************************************************** - Send a change notication message on all handles which have a call - back registered - **********************************************************************/ - -static int build_notify2_messages(TALLOC_CTX *mem_ctx, - struct printer_handle *prn_hnd, - SPOOLSS_NOTIFY_MSG *messages, - uint32_t num_msgs, - struct spoolss_Notify **_notifies, - int *_count) -{ - struct spoolss_Notify *notifies; - SPOOLSS_NOTIFY_MSG *msg; - int count = 0; - uint32_t id; - int i; - - notifies = talloc_zero_array(mem_ctx, - struct spoolss_Notify, num_msgs); - if (!notifies) { - return ENOMEM; - } - - for (i = 0; i < num_msgs; i++) { - - msg = &messages[i]; - - /* Are we monitoring this event? */ - - if (!is_monitoring_event(prn_hnd, msg->type, msg->field)) { - continue; - } - - DEBUG(10, ("Sending message type [0x%x] field [0x%2x] " - "for printer [%s]\n", - msg->type, msg->field, prn_hnd->sharename)); - - /* - * if the is a printer notification handle and not a job - * notification type, then set the id to 0. - * Otherwise just use what was specified in the message. - * - * When registering change notification on a print server - * handle we always need to send back the id (snum) matching - * the printer for which the change took place. - * For change notify registered on a printer handle, - * this does not matter and the id should be 0. - * - * --jerry - */ - - if ((msg->type == PRINTER_NOTIFY_TYPE) && - (prn_hnd->printer_type == SPLHND_PRINTER)) { - id = 0; - } else { - id = msg->id; - } - - /* Convert unix jobid to smb jobid */ - - if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) { - id = sysjob_to_jobid(msg->id); - - if (id == -1) { - DEBUG(3, ("no such unix jobid %d\n", - msg->id)); - continue; - } - } - - construct_info_data(¬ifies[count], - msg->type, msg->field, id); - - switch(msg->type) { - case PRINTER_NOTIFY_TYPE: - if (printer_notify_table[msg->field].fn) { - printer_notify_table[msg->field].fn(msg, - ¬ifies[count], mem_ctx); - } - break; - - case JOB_NOTIFY_TYPE: - if (job_notify_table[msg->field].fn) { - job_notify_table[msg->field].fn(msg, - ¬ifies[count], mem_ctx); - } - break; - - default: - DEBUG(5, ("Unknown notification type %d\n", - msg->type)); - continue; - } - - count++; - } - - *_notifies = notifies; - *_count = count; - - return 0; -} - -static int send_notify2_printer(TALLOC_CTX *mem_ctx, - struct printer_handle *prn_hnd, - SPOOLSS_NOTIFY_MSG_GROUP *msg_group) -{ - struct spoolss_Notify *notifies; - int count = 0; - union spoolss_ReplyPrinterInfo info; - struct spoolss_NotifyInfo info0; - uint32_t reply_result; - NTSTATUS status; - WERROR werr; - int ret; - - /* Is there notification on this handle? */ - if (prn_hnd->notify.cli_chan == NULL || - prn_hnd->notify.cli_chan->active_connections == 0) { - return 0; - } - - DEBUG(10, ("Client connected! [\\\\%s\\%s]\n", - prn_hnd->servername, prn_hnd->sharename)); - - /* For this printer? Print servers always receive notifications. */ - if ((prn_hnd->printer_type == SPLHND_PRINTER) && - (!strequal(msg_group->printername, prn_hnd->sharename))) { - return 0; - } - - DEBUG(10,("Our printer\n")); - - /* build the array of change notifications */ - ret = build_notify2_messages(mem_ctx, prn_hnd, - msg_group->msgs, - msg_group->num_msgs, - ¬ifies, &count); - if (ret) { - return ret; - } - - info0.version = 0x2; - info0.flags = count ? 0x00020000 /* ??? */ : PRINTER_NOTIFY_INFO_DISCARDED; - info0.count = count; - info0.notifies = notifies; - - info.info0 = &info0; - - status = dcerpc_spoolss_RouterReplyPrinterEx( - prn_hnd->notify.cli_chan->binding_handle, - mem_ctx, - &prn_hnd->notify.cli_hnd, - prn_hnd->notify.change, /* color */ - prn_hnd->notify.flags, - &reply_result, - 0, /* reply_type, must be 0 */ - info, &werr); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("dcerpc_spoolss_RouterReplyPrinterEx to client: %s " - "failed: %s\n", - prn_hnd->notify.cli_chan->cli_pipe->srv_name_slash, - nt_errstr(status))); - werr = ntstatus_to_werror(status); - } else if (!W_ERROR_IS_OK(werr)) { - DEBUG(1, ("RouterReplyPrinterEx to client: %s " - "failed: %s\n", - prn_hnd->notify.cli_chan->cli_pipe->srv_name_slash, - win_errstr(werr))); - } - switch (reply_result) { - case 0: - break; - case PRINTER_NOTIFY_INFO_DISCARDED: - case PRINTER_NOTIFY_INFO_DISCARDNOTED: - case PRINTER_NOTIFY_INFO_COLOR_MISMATCH: - break; - default: - break; - } - - return 0; -} - -static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32_t idx ) -{ - struct printer_handle *p; - TALLOC_CTX *mem_ctx = notify_ctr_getctx( ctr ); - SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, idx ); - int ret; - - if ( !msg_group ) { - DEBUG(5,("send_notify2_changes() called with no msg group!\n")); - return; - } - - if (!msg_group->msgs) { - DEBUG(5, ("send_notify2_changes() called with no messages!\n")); - return; - } - - DEBUG(8,("send_notify2_changes: Enter...[%s]\n", msg_group->printername)); - - /* loop over all printers */ - - for (p = printers_list; p; p = p->next) { - ret = send_notify2_printer(mem_ctx, p, msg_group); - if (ret) { - goto done; - } - } - -done: - DEBUG(8,("send_notify2_changes: Exit...\n")); - return; -} - -/*********************************************************************** - **********************************************************************/ - -static bool notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, void *buf, size_t len ) -{ - - uint32_t tv_sec, tv_usec; - size_t offset = 0; - - /* Unpack message */ - - offset += tdb_unpack((uint8_t *)buf + offset, len - offset, "f", - msg->printer); - - offset += tdb_unpack((uint8_t *)buf + offset, len - offset, "ddddddd", - &tv_sec, &tv_usec, - &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags); - - if (msg->len == 0) - tdb_unpack((uint8_t *)buf + offset, len - offset, "dd", - &msg->notify.value[0], &msg->notify.value[1]); - else - tdb_unpack((uint8_t *)buf + offset, len - offset, "B", - &msg->len, &msg->notify.data); - - DEBUG(3, ("notify2_unpack_msg: got NOTIFY2 message for printer %s, jobid %u type %d, field 0x%02x, flags 0x%04x\n", - msg->printer, (unsigned int)msg->id, msg->type, msg->field, msg->flags)); - - tv->tv_sec = tv_sec; - tv->tv_usec = tv_usec; - - if (msg->len == 0) - DEBUG(3, ("notify2_unpack_msg: value1 = %d, value2 = %d\n", msg->notify.value[0], - msg->notify.value[1])); - else - dump_data(3, (uint8_t *)msg->notify.data, msg->len); - - return true; -} - -/******************************************************************** - Receive a notify2 message list - ********************************************************************/ - -static void receive_notify2_message_list(struct messaging_context *msg, - void *private_data, - uint32_t msg_type, - struct server_id server_id, - DATA_BLOB *data) -{ - size_t msg_count, i; - char *buf = (char *)data->data; - char *msg_ptr; - size_t msg_len; - SPOOLSS_NOTIFY_MSG notify; - SPOOLSS_NOTIFY_MSG_CTR messages; - int num_groups; - - if (data->length < 4) { - DEBUG(0,("receive_notify2_message_list: bad message format (len < 4)!\n")); - return; - } - - msg_count = IVAL(buf, 0); - msg_ptr = buf + 4; - - DEBUG(5, ("receive_notify2_message_list: got %lu messages in list\n", (unsigned long)msg_count)); - - if (msg_count == 0) { - DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n")); - return; - } - - /* initialize the container */ - - ZERO_STRUCT( messages ); - notify_msg_ctr_init( &messages ); - - /* - * build message groups for each printer identified - * in a change_notify msg. Remember that a PCN message - * includes the handle returned for the srv_spoolss_replyopenprinter() - * call. Therefore messages are grouped according to printer handle. - */ - - for ( i=0; i data->length) { - DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n")); - return; - } - - msg_len = IVAL(msg_ptr,0); - msg_ptr += 4; - - if (msg_ptr + msg_len - buf > data->length) { - DEBUG(0,("receive_notify2_message_list: bad message format (bad len) !\n")); - return; - } - - /* unpack messages */ - - ZERO_STRUCT( notify ); - notify2_unpack_msg( ¬ify, &msg_tv, msg_ptr, msg_len ); - msg_ptr += msg_len; - - /* add to correct list in container */ - - notify_msg_ctr_addmsg( &messages, ¬ify ); - - /* free memory that might have been allocated by notify2_unpack_msg() */ - - if ( notify.len != 0 ) - SAFE_FREE( notify.notify.data ); - } - - /* process each group of messages */ - - num_groups = notify_msg_ctr_numgroups( &messages ); - for ( i=0; idata, data->length); - if (!drivername) { - DEBUG(0, ("do_drv_upgrade_printer: Out of memoery ?!\n")); - goto done; - } - - DEBUG(10, ("do_drv_upgrade_printer: " - "Got message for new driver [%s]\n", drivername)); - - /* Iterate the printer list */ - - for (snum = 0; snum < n_services; snum++) { - if (!lp_snum_ok(snum) || !lp_print_ok(snum)) { - continue; - } - - /* ignore [printers] share */ - if (strequal(lp_const_servicename(snum), "printers")) { - continue; - } - - result = winreg_get_printer(tmp_ctx, server_info, msg, - lp_const_servicename(snum), - &pinfo2); - - if (!W_ERROR_IS_OK(result)) { - continue; - } - - if (!pinfo2->drivername) { - continue; - } - - if (strcmp(drivername, pinfo2->drivername) != 0) { - continue; - } - - DEBUG(6,("Updating printer [%s]\n", pinfo2->printername)); - - /* all we care about currently is the change_id */ - result = winreg_printer_update_changeid(tmp_ctx, - server_info, - msg, - pinfo2->printername); - - if (!W_ERROR_IS_OK(result)) { - DEBUG(3, ("do_drv_upgrade_printer: " - "Failed to update changeid [%s]\n", - win_errstr(result))); - } - } - - /* all done */ -done: - talloc_free(tmp_ctx); -} - -/******************************************************************** - Update the cache for all printq's with a registered client - connection - ********************************************************************/ - -void update_monitored_printq_cache(struct messaging_context *msg_ctx) -{ - struct printer_handle *printer = printers_list; - int snum; - - /* loop through all printers and update the cache where - a client is connected */ - while (printer) { - if ((printer->printer_type == SPLHND_PRINTER) && - ((printer->notify.cli_chan != NULL) && - (printer->notify.cli_chan->active_connections > 0))) { - snum = print_queue_snum(printer->sharename); - print_queue_status(msg_ctx, snum, NULL, NULL); - } - - printer = printer->next; - } - - return; -} - -/**************************************************************** - _spoolss_OpenPrinter -****************************************************************/ - -WERROR _spoolss_OpenPrinter(struct pipes_struct *p, - struct spoolss_OpenPrinter *r) -{ - struct spoolss_OpenPrinterEx e; - WERROR werr; - - ZERO_STRUCT(e.in.userlevel); - - e.in.printername = r->in.printername; - e.in.datatype = r->in.datatype; - e.in.devmode_ctr = r->in.devmode_ctr; - e.in.access_mask = r->in.access_mask; - e.in.level = 0; - - e.out.handle = r->out.handle; - - werr = _spoolss_OpenPrinterEx(p, &e); - - if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) { - /* OpenPrinterEx returns this for a bad - * printer name. We must return WERR_INVALID_PRINTER_NAME - * instead. - */ - werr = WERR_INVALID_PRINTER_NAME; - } - - return werr; -} - -static WERROR copy_devicemode(TALLOC_CTX *mem_ctx, - struct spoolss_DeviceMode *orig, - struct spoolss_DeviceMode **dest) -{ - struct spoolss_DeviceMode *dm; - - dm = talloc(mem_ctx, struct spoolss_DeviceMode); - if (!dm) { - return WERR_NOMEM; - } - - /* copy all values, then duplicate strings and structs */ - *dm = *orig; - - dm->devicename = talloc_strdup(dm, orig->devicename); - if (!dm->devicename) { - return WERR_NOMEM; - } - dm->formname = talloc_strdup(dm, orig->formname); - if (!dm->formname) { - return WERR_NOMEM; - } - if (orig->driverextra_data.data) { - dm->driverextra_data.data = - (uint8_t *) talloc_memdup(dm, orig->driverextra_data.data, - orig->driverextra_data.length); - if (!dm->driverextra_data.data) { - return WERR_NOMEM; - } - } - - *dest = dm; - return WERR_OK; -} - -/**************************************************************** - _spoolss_OpenPrinterEx -****************************************************************/ - -WERROR _spoolss_OpenPrinterEx(struct pipes_struct *p, - struct spoolss_OpenPrinterEx *r) -{ - int snum; - struct printer_handle *Printer=NULL; - WERROR result; - - if (!r->in.printername) { - return WERR_INVALID_PARAM; - } - - if (r->in.level < 0 || r->in.level > 3) { - return WERR_INVALID_PARAM; - } - if ((r->in.level == 1 && !r->in.userlevel.level1) || - (r->in.level == 2 && !r->in.userlevel.level2) || - (r->in.level == 3 && !r->in.userlevel.level3)) { - return WERR_INVALID_PARAM; - } - - /* some sanity check because you can open a printer or a print server */ - /* aka: \\server\printer or \\server */ - - DEBUGADD(3,("checking name: %s\n", r->in.printername)); - - result = open_printer_hnd(p, r->out.handle, r->in.printername, 0); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0,("_spoolss_OpenPrinterEx: Cannot open a printer handle " - "for printer %s\n", r->in.printername)); - ZERO_STRUCTP(r->out.handle); - return result; - } - - Printer = find_printer_index_by_hnd(p, r->out.handle); - if ( !Printer ) { - DEBUG(0,("_spoolss_OpenPrinterEx: logic error. Can't find printer " - "handle we created for printer %s\n", r->in.printername)); - close_printer_handle(p, r->out.handle); - ZERO_STRUCTP(r->out.handle); - return WERR_INVALID_PARAM; - } - - /* - * First case: the user is opening the print server: - * - * Disallow MS AddPrinterWizard if parameter disables it. A Win2k - * client 1st tries an OpenPrinterEx with access==0, MUST be allowed. - * - * Then both Win2k and WinNT clients try an OpenPrinterEx with - * SERVER_ALL_ACCESS, which we allow only if the user is root (uid=0) - * or if the user is listed in the smb.conf printer admin parameter. - * - * Then they try OpenPrinterEx with SERVER_READ which we allow. This lets the - * client view printer folder, but does not show the MSAPW. - * - * Note: this test needs code to check access rights here too. Jeremy - * could you look at this? - * - * Second case: the user is opening a printer: - * NT doesn't let us connect to a printer if the connecting user - * doesn't have print permission. - * - * Third case: user is opening a Port Monitor - * access checks same as opening a handle to the print server. - */ - - switch (Printer->printer_type ) - { - case SPLHND_SERVER: - case SPLHND_PORTMON_TCP: - case SPLHND_PORTMON_LOCAL: - /* Printserver handles use global struct... */ - - snum = -1; - - /* Map standard access rights to object specific access rights */ - - se_map_standard(&r->in.access_mask, - &printserver_std_mapping); - - /* Deny any object specific bits that don't apply to print - servers (i.e printer and job specific bits) */ - - r->in.access_mask &= SEC_MASK_SPECIFIC; - - if (r->in.access_mask & - ~(SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)) { - DEBUG(3, ("access DENIED for non-printserver bits\n")); - close_printer_handle(p, r->out.handle); - ZERO_STRUCTP(r->out.handle); - return WERR_ACCESS_DENIED; - } - - /* Allow admin access */ - - if ( r->in.access_mask & SERVER_ACCESS_ADMINISTER ) - { - if (!lp_ms_add_printer_wizard()) { - close_printer_handle(p, r->out.handle); - ZERO_STRUCTP(r->out.handle); - return WERR_ACCESS_DENIED; - } - - /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, - and not a printer admin, then fail */ - - if ((p->server_info->utok.uid != sec_initial_uid()) && - !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && - !nt_token_check_sid(&global_sid_Builtin_Print_Operators, p->server_info->security_token) && - !token_contains_name_in_list( - uidtoname(p->server_info->utok.uid), - p->server_info->info3->base.domain.string, - NULL, - p->server_info->security_token, - lp_printer_admin(snum))) { - close_printer_handle(p, r->out.handle); - ZERO_STRUCTP(r->out.handle); - DEBUG(3,("access DENIED as user is not root, " - "has no printoperator privilege, " - "not a member of the printoperator builtin group and " - "is not in printer admin list")); - return WERR_ACCESS_DENIED; - } - - r->in.access_mask = SERVER_ACCESS_ADMINISTER; - } - else - { - r->in.access_mask = SERVER_ACCESS_ENUMERATE; - } - - DEBUG(4,("Setting print server access = %s\n", (r->in.access_mask == SERVER_ACCESS_ADMINISTER) - ? "SERVER_ACCESS_ADMINISTER" : "SERVER_ACCESS_ENUMERATE" )); - - /* We fall through to return WERR_OK */ - break; - - case SPLHND_PRINTER: - /* NT doesn't let us connect to a printer if the connecting user - doesn't have print permission. */ - - if (!get_printer_snum(p, r->out.handle, &snum, NULL)) { - close_printer_handle(p, r->out.handle); - ZERO_STRUCTP(r->out.handle); - return WERR_BADFID; - } - - if (r->in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED) { - r->in.access_mask = PRINTER_ACCESS_ADMINISTER; - } - - se_map_standard(&r->in.access_mask, &printer_std_mapping); - - /* map an empty access mask to the minimum access mask */ - if (r->in.access_mask == 0x0) - r->in.access_mask = PRINTER_ACCESS_USE; - - /* - * If we are not serving the printer driver for this printer, - * map PRINTER_ACCESS_ADMINISTER to PRINTER_ACCESS_USE. This - * will keep NT clients happy --jerry - */ - - if (lp_use_client_driver(snum) - && (r->in.access_mask & PRINTER_ACCESS_ADMINISTER)) - { - r->in.access_mask = PRINTER_ACCESS_USE; - } - - /* check smb.conf parameters and the the sec_desc */ - - if (!allow_access(lp_hostsdeny(snum), lp_hostsallow(snum), - p->client_id->name, p->client_id->addr)) { - DEBUG(3, ("access DENIED (hosts allow/deny) for printer open\n")); - ZERO_STRUCTP(r->out.handle); - return WERR_ACCESS_DENIED; - } - - if (!user_ok_token(uidtoname(p->server_info->utok.uid), NULL, - p->server_info->security_token, snum) || - !print_access_check(p->server_info, - p->msg_ctx, - snum, - r->in.access_mask)) { - DEBUG(3, ("access DENIED for printer open\n")); - close_printer_handle(p, r->out.handle); - ZERO_STRUCTP(r->out.handle); - return WERR_ACCESS_DENIED; - } - - if ((r->in.access_mask & SEC_MASK_SPECIFIC)& ~(PRINTER_ACCESS_ADMINISTER|PRINTER_ACCESS_USE)) { - DEBUG(3, ("access DENIED for printer open - unknown bits\n")); - close_printer_handle(p, r->out.handle); - ZERO_STRUCTP(r->out.handle); - return WERR_ACCESS_DENIED; - } - - if (r->in.access_mask & PRINTER_ACCESS_ADMINISTER) - r->in.access_mask = PRINTER_ACCESS_ADMINISTER; - else - r->in.access_mask = PRINTER_ACCESS_USE; - - DEBUG(4,("Setting printer access = %s\n", (r->in.access_mask == PRINTER_ACCESS_ADMINISTER) - ? "PRINTER_ACCESS_ADMINISTER" : "PRINTER_ACCESS_USE" )); - - winreg_create_printer(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum)); - - break; - - default: - /* sanity check to prevent programmer error */ - ZERO_STRUCTP(r->out.handle); - return WERR_BADFID; - } - - Printer->access_granted = r->in.access_mask; - - /* - * If the client sent a devmode in the OpenPrinter() call, then - * save it here in case we get a job submission on this handle - */ - - if ((Printer->printer_type != SPLHND_SERVER) && - r->in.devmode_ctr.devmode) { - copy_devicemode(NULL, r->in.devmode_ctr.devmode, - &Printer->devmode); - } - -#if 0 /* JERRY -- I'm doubtful this is really effective */ - /* HACK ALERT!!! Sleep for 1/3 of a second to try trigger a LAN/WAN - optimization in Windows 2000 clients --jerry */ - - if ( (r->in.access_mask == PRINTER_ACCESS_ADMINISTER) - && (RA_WIN2K == get_remote_arch()) ) - { - DEBUG(10,("_spoolss_OpenPrinterEx: Enabling LAN/WAN hack for Win2k clients.\n")); - sys_usleep( 500000 ); - } -#endif - - return WERR_OK; -} - -/**************************************************************** - _spoolss_ClosePrinter -****************************************************************/ - -WERROR _spoolss_ClosePrinter(struct pipes_struct *p, - struct spoolss_ClosePrinter *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - if (Printer && Printer->document_started) { - struct spoolss_EndDocPrinter e; - - e.in.handle = r->in.handle; - - _spoolss_EndDocPrinter(p, &e); - } - - if (!close_printer_handle(p, r->in.handle)) - return WERR_BADFID; - - /* clear the returned printer handle. Observed behavior - from Win2k server. Don't think this really matters. - Previous code just copied the value of the closed - handle. --jerry */ - - ZERO_STRUCTP(r->out.handle); - - return WERR_OK; -} - -/**************************************************************** - _spoolss_DeletePrinter -****************************************************************/ - -WERROR _spoolss_DeletePrinter(struct pipes_struct *p, - struct spoolss_DeletePrinter *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - WERROR result; - int snum; - - if (Printer && Printer->document_started) { - struct spoolss_EndDocPrinter e; - - e.in.handle = r->in.handle; - - _spoolss_EndDocPrinter(p, &e); - } - - if (get_printer_snum(p, r->in.handle, &snum, NULL)) { - winreg_delete_printer_key(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - ""); - } - - result = delete_printer_handle(p, r->in.handle); - - return result; -} - -/******************************************************************* - * static function to lookup the version id corresponding to an - * long architecture string - ******************************************************************/ - -static const struct print_architecture_table_node archi_table[]= { - - {"Windows 4.0", SPL_ARCH_WIN40, 0 }, - {"Windows NT x86", SPL_ARCH_W32X86, 2 }, - {"Windows NT R4000", SPL_ARCH_W32MIPS, 2 }, - {"Windows NT Alpha_AXP", SPL_ARCH_W32ALPHA, 2 }, - {"Windows NT PowerPC", SPL_ARCH_W32PPC, 2 }, - {"Windows IA64", SPL_ARCH_IA64, 3 }, - {"Windows x64", SPL_ARCH_X64, 3 }, - {NULL, "", -1 } -}; - -static int get_version_id(const char *arch) -{ - int i; - - for (i=0; archi_table[i].long_archi != NULL; i++) - { - if (strcmp(arch, archi_table[i].long_archi) == 0) - return (archi_table[i].version); - } - - return -1; -} - -/**************************************************************** - _spoolss_DeletePrinterDriver -****************************************************************/ - -WERROR _spoolss_DeletePrinterDriver(struct pipes_struct *p, - struct spoolss_DeletePrinterDriver *r) -{ - - struct spoolss_DriverInfo8 *info = NULL; - struct spoolss_DriverInfo8 *info_win2k = NULL; - int version; - WERROR status; - - /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, - and not a printer admin, then fail */ - - if ( (p->server_info->utok.uid != sec_initial_uid()) - && !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) - && !token_contains_name_in_list( - uidtoname(p->server_info->utok.uid), - p->server_info->info3->base.domain.string, - NULL, - p->server_info->security_token, - lp_printer_admin(-1)) ) - { - return WERR_ACCESS_DENIED; - } - - /* check that we have a valid driver name first */ - - if ((version = get_version_id(r->in.architecture)) == -1) - return WERR_INVALID_ENVIRONMENT; - - status = winreg_get_driver(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->in.architecture, r->in.driver, - version, &info); - if (!W_ERROR_IS_OK(status)) { - /* try for Win2k driver if "Windows NT x86" */ - - if ( version == 2 ) { - version = 3; - - status = winreg_get_driver(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->in.architecture, - r->in.driver, - version, &info); - if (!W_ERROR_IS_OK(status)) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - goto done; - } - } - /* otherwise it was a failure */ - else { - status = WERR_UNKNOWN_PRINTER_DRIVER; - goto done; - } - - } - - if (printer_driver_in_use(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - info)) { - status = WERR_PRINTER_DRIVER_IN_USE; - goto done; - } - - if (version == 2) { - status = winreg_get_driver(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->in.architecture, - r->in.driver, 3, &info_win2k); - if (W_ERROR_IS_OK(status)) { - /* if we get to here, we now have 2 driver info structures to remove */ - /* remove the Win2k driver first*/ - - status = winreg_del_driver(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - info_win2k, 3); - talloc_free(info_win2k); - - /* this should not have failed---if it did, report to client */ - if (!W_ERROR_IS_OK(status)) { - goto done; - } - } - } - - status = winreg_del_driver(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - info, version); - -done: - talloc_free(info); - - return status; -} - -/**************************************************************** - _spoolss_DeletePrinterDriverEx -****************************************************************/ - -WERROR _spoolss_DeletePrinterDriverEx(struct pipes_struct *p, - struct spoolss_DeletePrinterDriverEx *r) -{ - struct spoolss_DriverInfo8 *info = NULL; - struct spoolss_DriverInfo8 *info_win2k = NULL; - int version; - bool delete_files; - WERROR status; - - /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, - and not a printer admin, then fail */ - - if ( (p->server_info->utok.uid != sec_initial_uid()) - && !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) - && !token_contains_name_in_list( - uidtoname(p->server_info->utok.uid), - p->server_info->info3->base.domain.string, - NULL, - p->server_info->security_token, lp_printer_admin(-1)) ) - { - return WERR_ACCESS_DENIED; - } - - /* check that we have a valid driver name first */ - if ((version = get_version_id(r->in.architecture)) == -1) { - /* this is what NT returns */ - return WERR_INVALID_ENVIRONMENT; - } - - if (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) - version = r->in.version; - - status = winreg_get_driver(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->in.architecture, - r->in.driver, - version, - &info); - if (!W_ERROR_IS_OK(status)) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - - /* - * if the client asked for a specific version, - * or this is something other than Windows NT x86, - * then we've failed - */ - - if ( (r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) || (version !=2) ) - goto done; - - /* try for Win2k driver if "Windows NT x86" */ - - version = 3; - status = winreg_get_driver(info, - get_server_info_system(), - p->msg_ctx, - r->in.architecture, - r->in.driver, - version, &info); - if (!W_ERROR_IS_OK(status)) { - status = WERR_UNKNOWN_PRINTER_DRIVER; - goto done; - } - } - - if (printer_driver_in_use(info, - get_server_info_system(), - p->msg_ctx, - info)) { - status = WERR_PRINTER_DRIVER_IN_USE; - goto done; - } - - /* - * we have a couple of cases to consider. - * (1) Are any files in use? If so and DPD_DELTE_ALL_FILE is set, - * then the delete should fail if **any** files overlap with - * other drivers - * (2) If DPD_DELTE_UNUSED_FILES is sert, then delete all - * non-overlapping files - * (3) If neither DPD_DELTE_ALL_FILE nor DPD_DELTE_ALL_FILES - * is set, the do not delete any files - * Refer to MSDN docs on DeletePrinterDriverEx() for details. - */ - - delete_files = r->in.delete_flags & (DPD_DELETE_ALL_FILES|DPD_DELETE_UNUSED_FILES); - - /* fail if any files are in use and DPD_DELETE_ALL_FILES is set */ - - if (delete_files && - (r->in.delete_flags & DPD_DELETE_ALL_FILES) && - printer_driver_files_in_use(info, - get_server_info_system(), - p->msg_ctx, - info)) { - /* no idea of the correct error here */ - status = WERR_ACCESS_DENIED; - goto done; - } - - - /* also check for W32X86/3 if necessary; maybe we already have? */ - - if ( (version == 2) && ((r->in.delete_flags & DPD_DELETE_SPECIFIC_VERSION) != DPD_DELETE_SPECIFIC_VERSION) ) { - status = winreg_get_driver(info, - get_server_info_system(), - p->msg_ctx, - r->in.architecture, - r->in.driver, 3, &info_win2k); - if (W_ERROR_IS_OK(status)) { - - if (delete_files && - (r->in.delete_flags & DPD_DELETE_ALL_FILES) && - printer_driver_files_in_use(info, - get_server_info_system(), - p->msg_ctx, - info_win2k)) { - /* no idea of the correct error here */ - talloc_free(info_win2k); - status = WERR_ACCESS_DENIED; - goto done; - } - - /* if we get to here, we now have 2 driver info structures to remove */ - /* remove the Win2k driver first*/ - - status = winreg_del_driver(info, - get_server_info_system(), - p->msg_ctx, - info_win2k, - 3); - - /* this should not have failed---if it did, report to client */ - - if (!W_ERROR_IS_OK(status)) { - goto done; - } - - /* - * now delete any associated files if delete_files is - * true. Even if this part failes, we return succes - * because the driver doesn not exist any more - */ - if (delete_files) { - delete_driver_files(get_server_info_system(), - info_win2k); - } - } - } - - status = winreg_del_driver(info, - get_server_info_system(), - p->msg_ctx, - info, - version); - if (!W_ERROR_IS_OK(status)) { - goto done; - } - - /* - * now delete any associated files if delete_files is - * true. Even if this part failes, we return succes - * because the driver doesn not exist any more - */ - if (delete_files) { - delete_driver_files(get_server_info_system(), info); - } - -done: - talloc_free(info); - return status; -} - - -/******************************************************************** - GetPrinterData on a printer server Handle. -********************************************************************/ - -static WERROR getprinterdata_printer_server(TALLOC_CTX *mem_ctx, - const char *value, - enum winreg_Type *type, - union spoolss_PrinterData *data) -{ - DEBUG(8,("getprinterdata_printer_server:%s\n", value)); - - if (!StrCaseCmp(value, "W3SvcInstalled")) { - *type = REG_DWORD; - data->value = 0x00; - return WERR_OK; - } - - if (!StrCaseCmp(value, "BeepEnabled")) { - *type = REG_DWORD; - data->value = 0x00; - return WERR_OK; - } - - if (!StrCaseCmp(value, "EventLog")) { - *type = REG_DWORD; - /* formally was 0x1b */ - data->value = 0x00; - return WERR_OK; - } - - if (!StrCaseCmp(value, "NetPopup")) { - *type = REG_DWORD; - data->value = 0x00; - return WERR_OK; - } - - if (!StrCaseCmp(value, "MajorVersion")) { - *type = REG_DWORD; - - /* Windows NT 4.0 seems to not allow uploading of drivers - to a server that reports 0x3 as the MajorVersion. - need to investigate more how Win2k gets around this . - -- jerry */ - - if (RA_WINNT == get_remote_arch()) { - data->value = 0x02; - } else { - data->value = 0x03; - } - - return WERR_OK; - } - - if (!StrCaseCmp(value, "MinorVersion")) { - *type = REG_DWORD; - data->value = 0x00; - return WERR_OK; - } - - /* REG_BINARY - * uint32_t size = 0x114 - * uint32_t major = 5 - * uint32_t minor = [0|1] - * uint32_t build = [2195|2600] - * extra unicode string = e.g. "Service Pack 3" - */ - if (!StrCaseCmp(value, "OSVersion")) { - DATA_BLOB blob; - enum ndr_err_code ndr_err; - struct spoolss_OSVersion os; - - os.major = 5; /* Windows 2000 == 5.0 */ - os.minor = 0; - os.build = 2195; /* build */ - os.extra_string = ""; /* leave extra string empty */ - - ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &os, - (ndr_push_flags_fn_t)ndr_push_spoolss_OSVersion); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return WERR_GENERAL_FAILURE; - } - - *type = REG_BINARY; - data->binary = blob; - - return WERR_OK; - } - - - if (!StrCaseCmp(value, "DefaultSpoolDirectory")) { - *type = REG_SZ; - - data->string = talloc_strdup(mem_ctx, "C:\\PRINTERS"); - W_ERROR_HAVE_NO_MEMORY(data->string); - - return WERR_OK; - } - - if (!StrCaseCmp(value, "Architecture")) { - *type = REG_SZ; - data->string = talloc_strdup(mem_ctx, - lp_parm_const_string(GLOBAL_SECTION_SNUM, "spoolss", "architecture", SPOOLSS_ARCHITECTURE_NT_X86)); - W_ERROR_HAVE_NO_MEMORY(data->string); - - return WERR_OK; - } - - if (!StrCaseCmp(value, "DsPresent")) { - *type = REG_DWORD; - - /* only show the publish check box if we are a - member of a AD domain */ - - if (lp_security() == SEC_ADS) { - data->value = 0x01; - } else { - data->value = 0x00; - } - return WERR_OK; - } - - if (!StrCaseCmp(value, "DNSMachineName")) { - const char *hostname = get_mydnsfullname(); - - if (!hostname) { - return WERR_BADFILE; - } - - *type = REG_SZ; - data->string = talloc_strdup(mem_ctx, hostname); - W_ERROR_HAVE_NO_MEMORY(data->string); - - return WERR_OK; - } - - *type = REG_NONE; - - return WERR_INVALID_PARAM; -} - -/**************************************************************** - _spoolss_GetPrinterData -****************************************************************/ - -WERROR _spoolss_GetPrinterData(struct pipes_struct *p, - struct spoolss_GetPrinterData *r) -{ - struct spoolss_GetPrinterDataEx r2; - - r2.in.handle = r->in.handle; - r2.in.key_name = "PrinterDriverData"; - r2.in.value_name = r->in.value_name; - r2.in.offered = r->in.offered; - r2.out.type = r->out.type; - r2.out.data = r->out.data; - r2.out.needed = r->out.needed; - - return _spoolss_GetPrinterDataEx(p, &r2); -} - -/********************************************************* - Connect to the client machine. -**********************************************************/ - -static bool spoolss_connect_to_client(struct rpc_pipe_client **pp_pipe, - struct sockaddr_storage *client_ss, const char *remote_machine) -{ - NTSTATUS ret; - struct cli_state *the_cli; - struct sockaddr_storage rm_addr; - char addr[INET6_ADDRSTRLEN]; - - if ( is_zero_addr((struct sockaddr *)client_ss) ) { - DEBUG(2,("spoolss_connect_to_client: resolving %s\n", - remote_machine)); - if ( !resolve_name( remote_machine, &rm_addr, 0x20, false) ) { - DEBUG(2,("spoolss_connect_to_client: Can't resolve address for %s\n", remote_machine)); - return false; - } - print_sockaddr(addr, sizeof(addr), &rm_addr); - } else { - rm_addr = *client_ss; - print_sockaddr(addr, sizeof(addr), &rm_addr); - DEBUG(5,("spoolss_connect_to_client: Using address %s (no name resolution necessary)\n", - addr)); - } - - if (ismyaddr((struct sockaddr *)(void *)&rm_addr)) { - DEBUG(0,("spoolss_connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", - addr)); - return false; - } - - /* setup the connection */ - ret = cli_full_connection( &the_cli, global_myname(), remote_machine, - &rm_addr, 0, "IPC$", "IPC", - "", /* username */ - "", /* domain */ - "", /* password */ - 0, lp_client_signing()); - - if ( !NT_STATUS_IS_OK( ret ) ) { - DEBUG(2,("spoolss_connect_to_client: connection to [%s] failed!\n", - remote_machine )); - return false; - } - - if ( the_cli->protocol != PROTOCOL_NT1 ) { - DEBUG(0,("spoolss_connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine)); - cli_shutdown(the_cli); - return false; - } - - /* - * Ok - we have an anonymous connection to the IPC$ share. - * Now start the NT Domain stuff :-). - */ - - ret = cli_rpc_pipe_open_noauth(the_cli, &ndr_table_spoolss.syntax_id, pp_pipe); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(2,("spoolss_connect_to_client: unable to open the spoolss pipe on machine %s. Error was : %s.\n", - remote_machine, nt_errstr(ret))); - cli_shutdown(the_cli); - return false; - } - - return true; -} - -/*************************************************************************** - Connect to the client. -****************************************************************************/ - -static bool srv_spoolss_replyopenprinter(int snum, const char *printer, - uint32_t localprinter, - enum winreg_Type type, - struct policy_handle *handle, - struct notify_back_channel **_chan, - struct sockaddr_storage *client_ss, - struct messaging_context *msg_ctx) -{ - WERROR result; - NTSTATUS status; - struct notify_back_channel *chan; - - for (chan = back_channels; chan; chan = chan->next) { - if (memcmp(&chan->client_address, client_ss, - sizeof(struct sockaddr_storage)) == 0) { - break; - } - } - - /* - * If it's the first connection, contact the client - * and connect to the IPC$ share anonymously - */ - if (!chan) { - fstring unix_printer; - - /* the +2 is to strip the leading 2 backslashs */ - fstrcpy(unix_printer, printer + 2); - - chan = talloc_zero(back_channels, struct notify_back_channel); - if (!chan) { - return false; - } - chan->client_address = *client_ss; - - if (!spoolss_connect_to_client(&chan->cli_pipe, client_ss, unix_printer)) { - TALLOC_FREE(chan); - return false; - } - chan->binding_handle = chan->cli_pipe->binding_handle; - - DLIST_ADD(back_channels, chan); - - messaging_register(msg_ctx, NULL, MSG_PRINTER_NOTIFY2, - receive_notify2_message_list); - /* Tell the connections db we're now interested in printer - * notify messages. */ - serverid_register_msg_flags(messaging_server_id(msg_ctx), - true, FLAG_MSG_PRINT_NOTIFY); - } - - /* - * Tell the specific printing tdb we want messages for this printer - * by registering our PID. - */ - - if (!print_notify_register_pid(snum)) { - DEBUG(0, ("Failed to register our pid for printer %s\n", - printer)); - } - - status = dcerpc_spoolss_ReplyOpenPrinter(chan->binding_handle, - talloc_tos(), - printer, - localprinter, - type, - 0, - NULL, - handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(5, ("dcerpc_spoolss_ReplyOpenPrinter returned [%s]\n", nt_errstr(status))); - result = ntstatus_to_werror(status); - } else if (!W_ERROR_IS_OK(result)) { - DEBUG(5, ("ReplyOpenPrinter returned [%s]\n", win_errstr(result))); - } - - chan->active_connections++; - *_chan = chan; - - return (W_ERROR_IS_OK(result)); -} - -/**************************************************************** - ****************************************************************/ - -static struct spoolss_NotifyOption *dup_spoolss_NotifyOption(TALLOC_CTX *mem_ctx, - const struct spoolss_NotifyOption *r) -{ - struct spoolss_NotifyOption *option; - uint32_t i,k; - - if (!r) { - return NULL; - } - - option = talloc_zero(mem_ctx, struct spoolss_NotifyOption); - if (!option) { - return NULL; - } - - *option = *r; - - if (!option->count) { - return option; - } - - option->types = talloc_zero_array(option, - struct spoolss_NotifyOptionType, option->count); - if (!option->types) { - talloc_free(option); - return NULL; - } - - for (i=0; i < option->count; i++) { - option->types[i] = r->types[i]; - - if (option->types[i].count) { - option->types[i].fields = talloc_zero_array(option, - union spoolss_Field, option->types[i].count); - if (!option->types[i].fields) { - talloc_free(option); - return NULL; - } - for (k=0; ktypes[i].count; k++) { - option->types[i].fields[k] = - r->types[i].fields[k]; - } - } - } - - return option; -} - -/**************************************************************** - * _spoolss_RemoteFindFirstPrinterChangeNotifyEx - * - * before replying OK: status=0 a rpc call is made to the workstation - * asking ReplyOpenPrinter - * - * in fact ReplyOpenPrinter is the changenotify equivalent on the spoolss pipe - * called from api_spoolss_rffpcnex -****************************************************************/ - -WERROR _spoolss_RemoteFindFirstPrinterChangeNotifyEx(struct pipes_struct *p, - struct spoolss_RemoteFindFirstPrinterChangeNotifyEx *r) -{ - int snum = -1; - struct spoolss_NotifyOption *option = r->in.notify_options; - struct sockaddr_storage client_ss; - - /* store the notify value in the printer struct */ - - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - if (!Printer) { - DEBUG(2,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: " - "Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - Printer->notify.flags = r->in.flags; - Printer->notify.options = r->in.options; - Printer->notify.printerlocal = r->in.printer_local; - Printer->notify.msg_ctx = p->msg_ctx; - - TALLOC_FREE(Printer->notify.option); - Printer->notify.option = dup_spoolss_NotifyOption(Printer, option); - - fstrcpy(Printer->notify.localmachine, r->in.local_machine); - - /* Connect to the client machine and send a ReplyOpenPrinter */ - - if ( Printer->printer_type == SPLHND_SERVER) - snum = -1; - else if ( (Printer->printer_type == SPLHND_PRINTER) && - !get_printer_snum(p, r->in.handle, &snum, NULL) ) - return WERR_BADFID; - - DEBUG(10,("_spoolss_RemoteFindFirstPrinterChangeNotifyEx: " - "client_address is %s\n", p->client_id->addr)); - - if (!interpret_string_addr(&client_ss, p->client_id->addr, - AI_NUMERICHOST)) { - return WERR_SERVER_UNAVAILABLE; - } - - if(!srv_spoolss_replyopenprinter(snum, Printer->notify.localmachine, - Printer->notify.printerlocal, REG_SZ, - &Printer->notify.cli_hnd, - &Printer->notify.cli_chan, - &client_ss, p->msg_ctx)) { - return WERR_SERVER_UNAVAILABLE; - } - - return WERR_OK; -} - -/******************************************************************* - * fill a notify_info_data with the servername - ********************************************************************/ - -static void spoolss_notify_server_name(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->servername); -} - -/******************************************************************* - * fill a notify_info_data with the printername (not including the servername). - ********************************************************************/ - -static void spoolss_notify_printer_name(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - /* the notify name should not contain the \\server\ part */ - const char *p = strrchr(pinfo2->printername, '\\'); - - if (!p) { - p = pinfo2->printername; - } else { - p++; - } - - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p); -} - -/******************************************************************* - * fill a notify_info_data with the servicename - ********************************************************************/ - -static void spoolss_notify_share_name(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, lp_servicename(snum)); -} - -/******************************************************************* - * fill a notify_info_data with the port name - ********************************************************************/ - -static void spoolss_notify_port_name(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->portname); -} - -/******************************************************************* - * fill a notify_info_data with the printername - * but it doesn't exist, have to see what to do - ********************************************************************/ - -static void spoolss_notify_driver_name(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->drivername); -} - -/******************************************************************* - * fill a notify_info_data with the comment - ********************************************************************/ - -static void spoolss_notify_comment(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - const char *p; - - if (*pinfo2->comment == '\0') { - p = lp_comment(snum); - } else { - p = pinfo2->comment; - } - - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p); -} - -/******************************************************************* - * fill a notify_info_data with the comment - * location = "Room 1, floor 2, building 3" - ********************************************************************/ - -static void spoolss_notify_location(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->location); -} - -/******************************************************************* - * fill a notify_info_data with the device mode - * jfm:xxxx don't to it for know but that's a real problem !!! - ********************************************************************/ - -static void spoolss_notify_devmode(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - /* for a dummy implementation we have to zero the fields */ - SETUP_SPOOLSS_NOTIFY_DATA_DEVMODE(data, NULL); -} - -/******************************************************************* - * fill a notify_info_data with the separator file name - ********************************************************************/ - -static void spoolss_notify_sepfile(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->sepfile); -} - -/******************************************************************* - * fill a notify_info_data with the print processor - * jfm:xxxx return always winprint to indicate we don't do anything to it - ********************************************************************/ - -static void spoolss_notify_print_processor(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->printprocessor); -} - -/******************************************************************* - * fill a notify_info_data with the print processor options - * jfm:xxxx send an empty string - ********************************************************************/ - -static void spoolss_notify_parameters(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->parameters); -} - -/******************************************************************* - * fill a notify_info_data with the data type - * jfm:xxxx always send RAW as data type - ********************************************************************/ - -static void spoolss_notify_datatype(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, pinfo2->datatype); -} - -/******************************************************************* - * fill a notify_info_data with the security descriptor - * jfm:xxxx send an null pointer to say no security desc - * have to implement security before ! - ********************************************************************/ - -static void spoolss_notify_security_desc(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_SECDESC(data, pinfo2->secdesc); -} - -/******************************************************************* - * fill a notify_info_data with the attributes - * jfm:xxxx a samba printer is always shared - ********************************************************************/ - -static void spoolss_notify_attributes(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->attributes); -} - -/******************************************************************* - * fill a notify_info_data with the priority - ********************************************************************/ - -static void spoolss_notify_priority(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->priority); -} - -/******************************************************************* - * fill a notify_info_data with the default priority - ********************************************************************/ - -static void spoolss_notify_default_priority(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->defaultpriority); -} - -/******************************************************************* - * fill a notify_info_data with the start time - ********************************************************************/ - -static void spoolss_notify_start_time(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->starttime); -} - -/******************************************************************* - * fill a notify_info_data with the until time - ********************************************************************/ - -static void spoolss_notify_until_time(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->untiltime); -} - -/******************************************************************* - * fill a notify_info_data with the status - ********************************************************************/ - -static void spoolss_notify_status(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - print_status_struct status; - - print_queue_length(msg_ctx, snum, &status); - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, status.status); -} - -/******************************************************************* - * fill a notify_info_data with the number of jobs queued - ********************************************************************/ - -static void spoolss_notify_cjobs(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER( - data, print_queue_length(msg_ctx, snum, NULL)); -} - -/******************************************************************* - * fill a notify_info_data with the average ppm - ********************************************************************/ - -static void spoolss_notify_average_ppm(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - /* always respond 8 pages per minutes */ - /* a little hard ! */ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, pinfo2->averageppm); -} - -/******************************************************************* - * fill a notify_info_data with username - ********************************************************************/ - -static void spoolss_notify_username(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, queue->fs_user); -} - -/******************************************************************* - * fill a notify_info_data with job status - ********************************************************************/ - -static void spoolss_notify_job_status(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, nt_printj_status(queue->status)); -} - -/******************************************************************* - * fill a notify_info_data with job name - ********************************************************************/ - -static void spoolss_notify_job_name(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, queue->fs_file); -} - -/******************************************************************* - * fill a notify_info_data with job status - ********************************************************************/ - -static void spoolss_notify_job_status_string(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - /* - * Now we're returning job status codes we just return a "" here. JRA. - */ - - const char *p = ""; - -#if 0 /* NO LONGER NEEDED - JRA. 02/22/2001 */ - p = "unknown"; - - switch (queue->status) { - case LPQ_QUEUED: - p = "Queued"; - break; - case LPQ_PAUSED: - p = ""; /* NT provides the paused string */ - break; - case LPQ_SPOOLING: - p = "Spooling"; - break; - case LPQ_PRINTING: - p = "Printing"; - break; - } -#endif /* NO LONGER NEEDED. */ - - SETUP_SPOOLSS_NOTIFY_DATA_STRING(data, p); -} - -/******************************************************************* - * fill a notify_info_data with job time - ********************************************************************/ - -static void spoolss_notify_job_time(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, 0); -} - -/******************************************************************* - * fill a notify_info_data with job size - ********************************************************************/ - -static void spoolss_notify_job_size(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->size); -} - -/******************************************************************* - * fill a notify_info_data with page info - ********************************************************************/ -static void spoolss_notify_total_pages(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->page_count); -} - -/******************************************************************* - * fill a notify_info_data with pages printed info. - ********************************************************************/ -static void spoolss_notify_pages_printed(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - /* Add code when back-end tracks this */ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, 0); -} - -/******************************************************************* - Fill a notify_info_data with job position. - ********************************************************************/ - -static void spoolss_notify_job_position(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - SETUP_SPOOLSS_NOTIFY_DATA_INTEGER(data, queue->job); -} - -/******************************************************************* - Fill a notify_info_data with submitted time. - ********************************************************************/ - -static void spoolss_notify_submitted_time(struct messaging_context *msg_ctx, - int snum, - struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx) -{ - data->data.string.string = NULL; - data->data.string.size = 0; - - init_systemtime_buffer(mem_ctx, gmtime(&queue->time), - &data->data.string.string, - &data->data.string.size); - -} - -struct s_notify_info_data_table -{ - enum spoolss_NotifyType type; - uint16_t field; - const char *name; - enum spoolss_NotifyTable variable_type; - void (*fn) (struct messaging_context *msg_ctx, - int snum, struct spoolss_Notify *data, - print_queue_struct *queue, - struct spoolss_PrinterInfo2 *pinfo2, - TALLOC_CTX *mem_ctx); -}; - -/* A table describing the various print notification constants and - whether the notification data is a pointer to a variable sized - buffer, a one value uint32_t or a two value uint32_t. */ - -static const struct s_notify_info_data_table notify_info_data_table[] = -{ -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SERVER_NAME, "PRINTER_NOTIFY_FIELD_SERVER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_server_name }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PRINTER_NAME, "PRINTER_NOTIFY_FIELD_PRINTER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_printer_name }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SHARE_NAME, "PRINTER_NOTIFY_FIELD_SHARE_NAME", NOTIFY_TABLE_STRING, spoolss_notify_share_name }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PORT_NAME, "PRINTER_NOTIFY_FIELD_PORT_NAME", NOTIFY_TABLE_STRING, spoolss_notify_port_name }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DRIVER_NAME, "PRINTER_NOTIFY_FIELD_DRIVER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_driver_name }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_COMMENT, "PRINTER_NOTIFY_FIELD_COMMENT", NOTIFY_TABLE_STRING, spoolss_notify_comment }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_LOCATION, "PRINTER_NOTIFY_FIELD_LOCATION", NOTIFY_TABLE_STRING, spoolss_notify_location }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DEVMODE, "PRINTER_NOTIFY_FIELD_DEVMODE", NOTIFY_TABLE_DEVMODE, spoolss_notify_devmode }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SEPFILE, "PRINTER_NOTIFY_FIELD_SEPFILE", NOTIFY_TABLE_STRING, spoolss_notify_sepfile }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR, "PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR", NOTIFY_TABLE_STRING, spoolss_notify_print_processor }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PARAMETERS, "PRINTER_NOTIFY_FIELD_PARAMETERS", NOTIFY_TABLE_STRING, spoolss_notify_parameters }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DATATYPE, "PRINTER_NOTIFY_FIELD_DATATYPE", NOTIFY_TABLE_STRING, spoolss_notify_datatype }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NOTIFY_TABLE_SECURITYDESCRIPTOR, spoolss_notify_security_desc }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_ATTRIBUTES, "PRINTER_NOTIFY_FIELD_ATTRIBUTES", NOTIFY_TABLE_DWORD, spoolss_notify_attributes }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PRIORITY, "PRINTER_NOTIFY_FIELD_PRIORITY", NOTIFY_TABLE_DWORD, spoolss_notify_priority }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY, "PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY", NOTIFY_TABLE_DWORD, spoolss_notify_default_priority }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_START_TIME, "PRINTER_NOTIFY_FIELD_START_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_start_time }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_UNTIL_TIME, "PRINTER_NOTIFY_FIELD_UNTIL_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_until_time }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_STATUS, "PRINTER_NOTIFY_FIELD_STATUS", NOTIFY_TABLE_DWORD, spoolss_notify_status }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_STATUS_STRING, "PRINTER_NOTIFY_FIELD_STATUS_STRING", NOTIFY_TABLE_STRING, NULL }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_CJOBS, "PRINTER_NOTIFY_FIELD_CJOBS", NOTIFY_TABLE_DWORD, spoolss_notify_cjobs }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_AVERAGE_PPM, "PRINTER_NOTIFY_FIELD_AVERAGE_PPM", NOTIFY_TABLE_DWORD, spoolss_notify_average_ppm }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_TOTAL_PAGES, "PRINTER_NOTIFY_FIELD_TOTAL_PAGES", NOTIFY_TABLE_DWORD, NULL }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_PAGES_PRINTED, "PRINTER_NOTIFY_FIELD_PAGES_PRINTED", NOTIFY_TABLE_DWORD, NULL }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_TOTAL_BYTES, "PRINTER_NOTIFY_FIELD_TOTAL_BYTES", NOTIFY_TABLE_DWORD, NULL }, -{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_FIELD_BYTES_PRINTED, "PRINTER_NOTIFY_FIELD_BYTES_PRINTED", NOTIFY_TABLE_DWORD, NULL }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PRINTER_NAME, "JOB_NOTIFY_FIELD_PRINTER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_printer_name }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_MACHINE_NAME, "JOB_NOTIFY_FIELD_MACHINE_NAME", NOTIFY_TABLE_STRING, spoolss_notify_server_name }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PORT_NAME, "JOB_NOTIFY_FIELD_PORT_NAME", NOTIFY_TABLE_STRING, spoolss_notify_port_name }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_USER_NAME, "JOB_NOTIFY_FIELD_USER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_username }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_NOTIFY_NAME, "JOB_NOTIFY_FIELD_NOTIFY_NAME", NOTIFY_TABLE_STRING, spoolss_notify_username }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DATATYPE, "JOB_NOTIFY_FIELD_DATATYPE", NOTIFY_TABLE_STRING, spoolss_notify_datatype }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PRINT_PROCESSOR, "JOB_NOTIFY_FIELD_PRINT_PROCESSOR", NOTIFY_TABLE_STRING, spoolss_notify_print_processor }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PARAMETERS, "JOB_NOTIFY_FIELD_PARAMETERS", NOTIFY_TABLE_STRING, spoolss_notify_parameters }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DRIVER_NAME, "JOB_NOTIFY_FIELD_DRIVER_NAME", NOTIFY_TABLE_STRING, spoolss_notify_driver_name }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DEVMODE, "JOB_NOTIFY_FIELD_DEVMODE", NOTIFY_TABLE_DEVMODE, spoolss_notify_devmode }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_STATUS, "JOB_NOTIFY_FIELD_STATUS", NOTIFY_TABLE_DWORD, spoolss_notify_job_status }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_STATUS_STRING, "JOB_NOTIFY_FIELD_STATUS_STRING", NOTIFY_TABLE_STRING, spoolss_notify_job_status_string }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR, "JOB_NOTIFY_FIELD_SECURITY_DESCRIPTOR", NOTIFY_TABLE_SECURITYDESCRIPTOR, NULL }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_DOCUMENT, "JOB_NOTIFY_FIELD_DOCUMENT", NOTIFY_TABLE_STRING, spoolss_notify_job_name }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PRIORITY, "JOB_NOTIFY_FIELD_PRIORITY", NOTIFY_TABLE_DWORD, spoolss_notify_priority }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_POSITION, "JOB_NOTIFY_FIELD_POSITION", NOTIFY_TABLE_DWORD, spoolss_notify_job_position }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_SUBMITTED, "JOB_NOTIFY_FIELD_SUBMITTED", NOTIFY_TABLE_TIME, spoolss_notify_submitted_time }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_START_TIME, "JOB_NOTIFY_FIELD_START_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_start_time }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_UNTIL_TIME, "JOB_NOTIFY_FIELD_UNTIL_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_until_time }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_TIME, "JOB_NOTIFY_FIELD_TIME", NOTIFY_TABLE_DWORD, spoolss_notify_job_time }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_TOTAL_PAGES, "JOB_NOTIFY_FIELD_TOTAL_PAGES", NOTIFY_TABLE_DWORD, spoolss_notify_total_pages }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_PAGES_PRINTED, "JOB_NOTIFY_FIELD_PAGES_PRINTED", NOTIFY_TABLE_DWORD, spoolss_notify_pages_printed }, -{ JOB_NOTIFY_TYPE, JOB_NOTIFY_FIELD_TOTAL_BYTES, "JOB_NOTIFY_FIELD_TOTAL_BYTES", NOTIFY_TABLE_DWORD, spoolss_notify_job_size }, -}; - -/******************************************************************* - Return the variable_type of info_data structure. -********************************************************************/ - -static enum spoolss_NotifyTable variable_type_of_notify_info_data(enum spoolss_NotifyType type, - uint16_t field) -{ - int i=0; - - for (i = 0; i < ARRAY_SIZE(notify_info_data_table); i++) { - if ( (notify_info_data_table[i].type == type) && - (notify_info_data_table[i].field == field) ) { - return notify_info_data_table[i].variable_type; - } - } - - DEBUG(5, ("invalid notify data type %d/%d\n", type, field)); - - return (enum spoolss_NotifyTable) 0; -} - -/**************************************************************************** -****************************************************************************/ - -static bool search_notify(enum spoolss_NotifyType type, - uint16_t field, - int *value) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(notify_info_data_table); i++) { - if (notify_info_data_table[i].type == type && - notify_info_data_table[i].field == field && - notify_info_data_table[i].fn != NULL) { - *value = i; - return true; - } - } - - return false; -} - -/**************************************************************************** -****************************************************************************/ - -static void construct_info_data(struct spoolss_Notify *info_data, - enum spoolss_NotifyType type, - uint16_t field, int id) -{ - info_data->type = type; - info_data->field.field = field; - info_data->variable_type = variable_type_of_notify_info_data(type, field); - info_data->job_id = id; -} - -/******************************************************************* - * - * fill a notify_info struct with info asked - * - ********************************************************************/ - -static bool construct_notify_printer_info(struct messaging_context *msg_ctx, - struct printer_handle *print_hnd, - struct spoolss_NotifyInfo *info, - struct spoolss_PrinterInfo2 *pinfo2, - int snum, - const struct spoolss_NotifyOptionType *option_type, - uint32_t id, - TALLOC_CTX *mem_ctx) -{ - int field_num,j; - enum spoolss_NotifyType type; - uint16_t field; - - struct spoolss_Notify *current_data; - print_queue_struct *queue=NULL; - - type = option_type->type; - - DEBUG(4,("construct_notify_printer_info: Notify type: [%s], number of notify info: [%d] on printer: [%s]\n", - (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"), - option_type->count, lp_servicename(snum))); - - for(field_num=0; field_num < option_type->count; field_num++) { - field = option_type->fields[field_num].field; - - DEBUG(4,("construct_notify_printer_info: notify [%d]: type [%x], field [%x]\n", field_num, type, field)); - - if (!search_notify(type, field, &j) ) - continue; - - info->notifies = TALLOC_REALLOC_ARRAY(info, info->notifies, - struct spoolss_Notify, - info->count + 1); - if (info->notifies == NULL) { - DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n")); - return false; - } - - current_data = &info->notifies[info->count]; - - construct_info_data(current_data, type, field, id); - - DEBUG(10, ("construct_notify_printer_info: " - "calling [%s] snum=%d printername=[%s])\n", - notify_info_data_table[j].name, snum, - pinfo2->printername)); - - notify_info_data_table[j].fn(msg_ctx, snum, current_data, - queue, pinfo2, mem_ctx); - - info->count++; - } - - return true; -} - -/******************************************************************* - * - * fill a notify_info struct with info asked - * - ********************************************************************/ - -static bool construct_notify_jobs_info(struct messaging_context *msg_ctx, - print_queue_struct *queue, - struct spoolss_NotifyInfo *info, - struct spoolss_PrinterInfo2 *pinfo2, - int snum, - const struct spoolss_NotifyOptionType *option_type, - uint32_t id, - TALLOC_CTX *mem_ctx) -{ - int field_num,j; - enum spoolss_NotifyType type; - uint16_t field; - struct spoolss_Notify *current_data; - - DEBUG(4,("construct_notify_jobs_info\n")); - - type = option_type->type; - - DEBUGADD(4,("Notify type: [%s], number of notify info: [%d]\n", - (type == PRINTER_NOTIFY_TYPE ? "PRINTER_NOTIFY_TYPE" : "JOB_NOTIFY_TYPE"), - option_type->count)); - - for(field_num=0; field_numcount; field_num++) { - field = option_type->fields[field_num].field; - - if (!search_notify(type, field, &j) ) - continue; - - info->notifies = TALLOC_REALLOC_ARRAY(info, info->notifies, - struct spoolss_Notify, - info->count + 1); - if (info->notifies == NULL) { - DEBUG(2,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n")); - return false; - } - - current_data=&(info->notifies[info->count]); - - construct_info_data(current_data, type, field, id); - notify_info_data_table[j].fn(msg_ctx, snum, current_data, - queue, pinfo2, mem_ctx); - info->count++; - } - - return true; -} - -/* - * JFM: The enumeration is not that simple, it's even non obvious. - * - * let's take an example: I want to monitor the PRINTER SERVER for - * the printer's name and the number of jobs currently queued. - * So in the NOTIFY_OPTION, I have one NOTIFY_OPTION_TYPE structure. - * Its type is PRINTER_NOTIFY_TYPE and it has 2 fields NAME and CJOBS. - * - * I have 3 printers on the back of my server. - * - * Now the response is a NOTIFY_INFO structure, with 6 NOTIFY_INFO_DATA - * structures. - * Number Data Id - * 1 printer 1 name 1 - * 2 printer 1 cjob 1 - * 3 printer 2 name 2 - * 4 printer 2 cjob 2 - * 5 printer 3 name 3 - * 6 printer 3 name 3 - * - * that's the print server case, the printer case is even worse. - */ - -/******************************************************************* - * - * enumerate all printers on the printserver - * fill a notify_info struct with info asked - * - ********************************************************************/ - -static WERROR printserver_notify_info(struct pipes_struct *p, - struct policy_handle *hnd, - struct spoolss_NotifyInfo *info, - TALLOC_CTX *mem_ctx) -{ - int snum; - struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); - int n_services=lp_numservices(); - int i; - struct spoolss_NotifyOption *option; - struct spoolss_NotifyOptionType option_type; - struct spoolss_PrinterInfo2 *pinfo2 = NULL; - WERROR result; - - DEBUG(4,("printserver_notify_info\n")); - - if (!Printer) - return WERR_BADFID; - - option = Printer->notify.option; - - info->version = 2; - info->notifies = NULL; - info->count = 0; - - /* a bug in xp sp2 rc2 causes it to send a fnpcn request without - sending a ffpcn() request first */ - - if ( !option ) - return WERR_BADFID; - - for (i=0; icount; i++) { - option_type = option->types[i]; - - if (option_type.type != PRINTER_NOTIFY_TYPE) - continue; - - for (snum = 0; snum < n_services; snum++) { - if (!lp_browseable(snum) || - !lp_snum_ok(snum) || - !lp_print_ok(snum)) { - continue; /* skip */ - } - - /* Maybe we should use the SYSTEM server_info here... */ - result = winreg_get_printer(mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_servicename(snum), - &pinfo2); - if (!W_ERROR_IS_OK(result)) { - DEBUG(4, ("printserver_notify_info: " - "Failed to get printer [%s]\n", - lp_servicename(snum))); - continue; - } - - - construct_notify_printer_info(p->msg_ctx, - Printer, info, - pinfo2, snum, - &option_type, snum, - mem_ctx); - - TALLOC_FREE(pinfo2); - } - } - -#if 0 - /* - * Debugging information, don't delete. - */ - - DEBUG(1,("dumping the NOTIFY_INFO\n")); - DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count)); - DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n")); - - for (i=0; icount; i++) { - DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n", - i, info->data[i].type, info->data[i].field, info->data[i].reserved, - info->data[i].id, info->data[i].size, info->data[i].enc_type)); - } -#endif - - return WERR_OK; -} - -/******************************************************************* - * - * fill a notify_info struct with info asked - * - ********************************************************************/ - -static WERROR printer_notify_info(struct pipes_struct *p, - struct policy_handle *hnd, - struct spoolss_NotifyInfo *info, - TALLOC_CTX *mem_ctx) -{ - int snum; - struct printer_handle *Printer = find_printer_index_by_hnd(p, hnd); - int i; - uint32_t id; - struct spoolss_NotifyOption *option; - struct spoolss_NotifyOptionType option_type; - int count,j; - print_queue_struct *queue=NULL; - print_status_struct status; - struct spoolss_PrinterInfo2 *pinfo2 = NULL; - WERROR result; - - DEBUG(4,("printer_notify_info\n")); - - if (!Printer) - return WERR_BADFID; - - option = Printer->notify.option; - id = 0x0; - - info->version = 2; - info->notifies = NULL; - info->count = 0; - - /* a bug in xp sp2 rc2 causes it to send a fnpcn request without - sending a ffpcn() request first */ - - if ( !option ) - return WERR_BADFID; - - get_printer_snum(p, hnd, &snum, NULL); - - /* Maybe we should use the SYSTEM server_info here... */ - result = winreg_get_printer(mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_servicename(snum), &pinfo2); - if (!W_ERROR_IS_OK(result)) { - return WERR_BADFID; - } - - for (i=0; icount; i++) { - option_type = option->types[i]; - - switch (option_type.type) { - case PRINTER_NOTIFY_TYPE: - if (construct_notify_printer_info(p->msg_ctx, - Printer, info, - pinfo2, snum, - &option_type, id, - mem_ctx)) { - id--; - } - break; - - case JOB_NOTIFY_TYPE: - - count = print_queue_status(p->msg_ctx, snum, &queue, - &status); - - for (j=0; jmsg_ctx, - &queue[j], info, - pinfo2, snum, - &option_type, - queue[j].job, - mem_ctx); - } - - SAFE_FREE(queue); - break; - } - } - - /* - * Debugging information, don't delete. - */ - /* - DEBUG(1,("dumping the NOTIFY_INFO\n")); - DEBUGADD(1,("info->version:[%d], info->flags:[%d], info->count:[%d]\n", info->version, info->flags, info->count)); - DEBUGADD(1,("num\ttype\tfield\tres\tid\tsize\tenc_type\n")); - - for (i=0; icount; i++) { - DEBUGADD(1,("[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\t[%d]\n", - i, info->data[i].type, info->data[i].field, info->data[i].reserved, - info->data[i].id, info->data[i].size, info->data[i].enc_type)); - } - */ - - talloc_free(pinfo2); - return WERR_OK; -} - -/**************************************************************** - _spoolss_RouterRefreshPrinterChangeNotify -****************************************************************/ - -WERROR _spoolss_RouterRefreshPrinterChangeNotify(struct pipes_struct *p, - struct spoolss_RouterRefreshPrinterChangeNotify *r) -{ - struct spoolss_NotifyInfo *info; - - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - WERROR result = WERR_BADFID; - - /* we always have a spoolss_NotifyInfo struct */ - info = talloc_zero(p->mem_ctx, struct spoolss_NotifyInfo); - if (!info) { - result = WERR_NOMEM; - goto done; - } - - *r->out.info = info; - - if (!Printer) { - DEBUG(2,("_spoolss_RouterRefreshPrinterChangeNotify: " - "Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - goto done; - } - - DEBUG(4,("Printer type %x\n",Printer->printer_type)); - - /* - * We are now using the change value, and - * I should check for PRINTER_NOTIFY_OPTIONS_REFRESH but as - * I don't have a global notification system, I'm sending back all the - * informations even when _NOTHING_ has changed. - */ - - /* We need to keep track of the change value to send back in - RRPCN replies otherwise our updates are ignored. */ - - Printer->notify.fnpcn = true; - - if (Printer->notify.cli_chan != NULL && - Printer->notify.cli_chan->active_connections > 0) { - DEBUG(10,("_spoolss_RouterRefreshPrinterChangeNotify: " - "Saving change value in request [%x]\n", - r->in.change_low)); - Printer->notify.change = r->in.change_low; - } - - /* just ignore the spoolss_NotifyOption */ - - switch (Printer->printer_type) { - case SPLHND_SERVER: - result = printserver_notify_info(p, r->in.handle, - info, p->mem_ctx); - break; - - case SPLHND_PRINTER: - result = printer_notify_info(p, r->in.handle, - info, p->mem_ctx); - break; - } - - Printer->notify.fnpcn = false; - -done: - return result; -} - -/******************************************************************** - ********************************************************************/ - -static WERROR create_printername(TALLOC_CTX *mem_ctx, - const char *servername, - const char *printername, - const char **printername_p) -{ - /* FIXME: add lp_force_printername() */ - - if (servername == NULL) { - *printername_p = talloc_strdup(mem_ctx, printername); - W_ERROR_HAVE_NO_MEMORY(*printername_p); - return WERR_OK; - } - - if (servername[0] == '\\' && servername[1] == '\\') { - servername += 2; - } - - *printername_p = talloc_asprintf(mem_ctx, "\\\\%s\\%s", servername, printername); - W_ERROR_HAVE_NO_MEMORY(*printername_p); - - return WERR_OK; -} - -/******************************************************************** - ********************************************************************/ - -static void compose_devicemode_devicename(struct spoolss_DeviceMode *dm, - const char *printername) -{ - if (dm == NULL) { - return; - } - - dm->devicename = talloc_strndup(dm, printername, - MIN(strlen(printername), 31)); -} - -/******************************************************************** - * construct_printer_info_0 - * fill a printer_info_0 struct - ********************************************************************/ - -static WERROR construct_printer_info0(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct spoolss_PrinterInfo2 *info2, - const char *servername, - struct spoolss_PrinterInfo0 *r, - int snum) -{ - int count; - struct printer_session_counter *session_counter; - struct timeval setuptime; - print_status_struct status; - WERROR result; - - result = create_printername(mem_ctx, servername, info2->printername, &r->printername); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - if (servername) { - r->servername = talloc_strdup(mem_ctx, servername); - W_ERROR_HAVE_NO_MEMORY(r->servername); - } else { - r->servername = NULL; - } - - count = print_queue_length(msg_ctx, snum, &status); - - /* check if we already have a counter for this printer */ - for (session_counter = counter_list; session_counter; session_counter = session_counter->next) { - if (session_counter->snum == snum) - break; - } - - /* it's the first time, add it to the list */ - if (session_counter == NULL) { - session_counter = talloc_zero(counter_list, struct printer_session_counter); - W_ERROR_HAVE_NO_MEMORY(session_counter); - session_counter->snum = snum; - session_counter->counter = 0; - DLIST_ADD(counter_list, session_counter); - } - - /* increment it */ - session_counter->counter++; - - r->cjobs = count; - r->total_jobs = 0; - r->total_bytes = 0; - - get_startup_time(&setuptime); - init_systemtime(&r->time, gmtime(&setuptime.tv_sec)); - - /* JFM: - * the global_counter should be stored in a TDB as it's common to all the clients - * and should be zeroed on samba startup - */ - r->global_counter = session_counter->counter; - r->total_pages = 0; - /* in 2.2 we reported ourselves as 0x0004 and 0x0565 */ - SSVAL(&r->version, 0, 0x0005); /* NT 5 */ - SSVAL(&r->version, 2, 0x0893); /* build 2195 */ - r->free_build = SPOOLSS_RELEASE_BUILD; - r->spooling = 0; - r->max_spooling = 0; - r->session_counter = session_counter->counter; - r->num_error_out_of_paper = 0x0; - r->num_error_not_ready = 0x0; /* number of print failure */ - r->job_error = 0x0; - r->number_of_processors = 0x1; - r->processor_type = PROCESSOR_INTEL_PENTIUM; /* 586 Pentium ? */ - r->high_part_total_bytes = 0x0; - - /* ChangeID in milliseconds*/ - winreg_printer_get_changeid(mem_ctx, server_info, msg_ctx, - info2->sharename, &r->change_id); - - r->last_error = WERR_OK; - r->status = nt_printq_status(status.status); - r->enumerate_network_printers = 0x0; - r->c_setprinter = 0x0; - r->processor_architecture = PROCESSOR_ARCHITECTURE_INTEL; - r->processor_level = 0x6; /* 6 ???*/ - r->ref_ic = 0; - r->reserved2 = 0; - r->reserved3 = 0; - - return WERR_OK; -} - - -/******************************************************************** - * construct_printer_info1 - * fill a spoolss_PrinterInfo1 struct -********************************************************************/ - -static WERROR construct_printer_info1(TALLOC_CTX *mem_ctx, - const struct spoolss_PrinterInfo2 *info2, - uint32_t flags, - const char *servername, - struct spoolss_PrinterInfo1 *r, - int snum) -{ - WERROR result; - - r->flags = flags; - - if (info2->comment == NULL || info2->comment[0] == '\0') { - r->comment = talloc_strdup(mem_ctx, lp_comment(snum)); - } else { - r->comment = talloc_strdup(mem_ctx, info2->comment); /* saved comment */ - } - W_ERROR_HAVE_NO_MEMORY(r->comment); - - result = create_printername(mem_ctx, servername, info2->printername, &r->name); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - r->description = talloc_asprintf(mem_ctx, "%s,%s,%s", - r->name, - info2->drivername, - r->comment); - W_ERROR_HAVE_NO_MEMORY(r->description); - - return WERR_OK; -} - -/******************************************************************** - * construct_printer_info2 - * fill a spoolss_PrinterInfo2 struct -********************************************************************/ - -static WERROR construct_printer_info2(TALLOC_CTX *mem_ctx, - struct messaging_context *msg_ctx, - const struct spoolss_PrinterInfo2 *info2, - const char *servername, - struct spoolss_PrinterInfo2 *r, - int snum) -{ - int count; - print_status_struct status; - WERROR result; - - count = print_queue_length(msg_ctx, snum, &status); - - if (servername) { - r->servername = talloc_strdup(mem_ctx, servername); - W_ERROR_HAVE_NO_MEMORY(r->servername); - } else { - r->servername = NULL; - } - - result = create_printername(mem_ctx, servername, info2->printername, &r->printername); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - r->sharename = talloc_strdup(mem_ctx, lp_servicename(snum)); - W_ERROR_HAVE_NO_MEMORY(r->sharename); - r->portname = talloc_strdup(mem_ctx, info2->portname); - W_ERROR_HAVE_NO_MEMORY(r->portname); - r->drivername = talloc_strdup(mem_ctx, info2->drivername); - W_ERROR_HAVE_NO_MEMORY(r->drivername); - - if (info2->comment[0] == '\0') { - r->comment = talloc_strdup(mem_ctx, lp_comment(snum)); - } else { - r->comment = talloc_strdup(mem_ctx, info2->comment); - } - W_ERROR_HAVE_NO_MEMORY(r->comment); - - r->location = talloc_strdup(mem_ctx, info2->location); - W_ERROR_HAVE_NO_MEMORY(r->location); - r->sepfile = talloc_strdup(mem_ctx, info2->sepfile); - W_ERROR_HAVE_NO_MEMORY(r->sepfile); - r->printprocessor = talloc_strdup(mem_ctx, info2->printprocessor); - W_ERROR_HAVE_NO_MEMORY(r->printprocessor); - r->datatype = talloc_strdup(mem_ctx, info2->datatype); - W_ERROR_HAVE_NO_MEMORY(r->datatype); - r->parameters = talloc_strdup(mem_ctx, info2->parameters); - W_ERROR_HAVE_NO_MEMORY(r->parameters); - - r->attributes = info2->attributes; - - r->priority = info2->priority; - r->defaultpriority = info2->defaultpriority; - r->starttime = info2->starttime; - r->untiltime = info2->untiltime; - r->status = nt_printq_status(status.status); - r->cjobs = count; - r->averageppm = info2->averageppm; - - copy_devicemode(mem_ctx, info2->devmode, &r->devmode); - if (!r->devmode) { - DEBUG(8,("Returning NULL Devicemode!\n")); - } - - compose_devicemode_devicename(r->devmode, r->printername); - - r->secdesc = NULL; - - if (info2->secdesc != NULL) { - /* don't use talloc_steal() here unless you do a deep steal of all - the SEC_DESC members */ - - r->secdesc = dup_sec_desc(mem_ctx, info2->secdesc); - } - - return WERR_OK; -} - -/******************************************************************** - * construct_printer_info3 - * fill a spoolss_PrinterInfo3 struct - ********************************************************************/ - -static WERROR construct_printer_info3(TALLOC_CTX *mem_ctx, - const struct spoolss_PrinterInfo2 *info2, - const char *servername, - struct spoolss_PrinterInfo3 *r, - int snum) -{ - /* These are the components of the SD we are returning. */ - - if (info2->secdesc != NULL) { - /* don't use talloc_steal() here unless you do a deep steal of all - the SEC_DESC members */ - - r->secdesc = dup_sec_desc(mem_ctx, info2->secdesc); - W_ERROR_HAVE_NO_MEMORY(r->secdesc); - } - - return WERR_OK; -} - -/******************************************************************** - * construct_printer_info4 - * fill a spoolss_PrinterInfo4 struct - ********************************************************************/ - -static WERROR construct_printer_info4(TALLOC_CTX *mem_ctx, - const struct spoolss_PrinterInfo2 *info2, - const char *servername, - struct spoolss_PrinterInfo4 *r, - int snum) -{ - WERROR result; - - result = create_printername(mem_ctx, servername, info2->printername, &r->printername); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - if (servername) { - r->servername = talloc_strdup(mem_ctx, servername); - W_ERROR_HAVE_NO_MEMORY(r->servername); - } else { - r->servername = NULL; - } - - r->attributes = info2->attributes; - - return WERR_OK; -} - -/******************************************************************** - * construct_printer_info5 - * fill a spoolss_PrinterInfo5 struct - ********************************************************************/ - -static WERROR construct_printer_info5(TALLOC_CTX *mem_ctx, - const struct spoolss_PrinterInfo2 *info2, - const char *servername, - struct spoolss_PrinterInfo5 *r, - int snum) -{ - WERROR result; - - result = create_printername(mem_ctx, servername, info2->printername, &r->printername); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - r->portname = talloc_strdup(mem_ctx, info2->portname); - W_ERROR_HAVE_NO_MEMORY(r->portname); - - r->attributes = info2->attributes; - - /* these two are not used by NT+ according to MSDN */ - r->device_not_selected_timeout = 0x0; /* have seen 0x3a98 */ - r->transmission_retry_timeout = 0x0; /* have seen 0xafc8 */ - - return WERR_OK; -} - -/******************************************************************** - * construct_printer_info_6 - * fill a spoolss_PrinterInfo6 struct - ********************************************************************/ - -static WERROR construct_printer_info6(TALLOC_CTX *mem_ctx, - struct messaging_context *msg_ctx, - const struct spoolss_PrinterInfo2 *info2, - const char *servername, - struct spoolss_PrinterInfo6 *r, - int snum) -{ - int count; - print_status_struct status; - - count = print_queue_length(msg_ctx, snum, &status); - - r->status = nt_printq_status(status.status); - - return WERR_OK; -} - -/******************************************************************** - * construct_printer_info7 - * fill a spoolss_PrinterInfo7 struct - ********************************************************************/ - -static WERROR construct_printer_info7(TALLOC_CTX *mem_ctx, - struct messaging_context *msg_ctx, - const char *servername, - struct spoolss_PrinterInfo7 *r, - int snum) -{ - struct auth_serversupplied_info *server_info; - struct GUID guid; - NTSTATUS status; - - status = make_server_info_system(mem_ctx, &server_info); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("construct_printer_info7: " - "Could not create system server_info\n")); - return WERR_NOMEM; - } - - if (is_printer_published(mem_ctx, server_info, msg_ctx, - servername, - lp_servicename(snum), &guid, NULL)) { - r->guid = talloc_strdup_upper(mem_ctx, GUID_string2(mem_ctx, &guid)); - r->action = DSPRINT_PUBLISH; - } else { - r->guid = talloc_strdup(mem_ctx, ""); - r->action = DSPRINT_UNPUBLISH; - } - W_ERROR_HAVE_NO_MEMORY(r->guid); - - TALLOC_FREE(server_info); - return WERR_OK; -} - -/******************************************************************** - * construct_printer_info8 - * fill a spoolss_PrinterInfo8 struct - ********************************************************************/ - -static WERROR construct_printer_info8(TALLOC_CTX *mem_ctx, - const struct spoolss_PrinterInfo2 *info2, - const char *servername, - struct spoolss_DeviceModeInfo *r, - int snum) -{ - WERROR result; - const char *printername; - - result = create_printername(mem_ctx, servername, info2->printername, &printername); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - copy_devicemode(mem_ctx, info2->devmode, &r->devmode); - if (!r->devmode) { - DEBUG(8,("Returning NULL Devicemode!\n")); - } - - compose_devicemode_devicename(r->devmode, printername); - - return WERR_OK; -} - - -/******************************************************************** -********************************************************************/ - -static bool snum_is_shared_printer(int snum) -{ - return (lp_browseable(snum) && lp_snum_ok(snum) && lp_print_ok(snum)); -} - -/******************************************************************** - Spoolss_enumprinters. -********************************************************************/ - -static WERROR enum_all_printers_info_level(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *servername, - uint32_t level, - uint32_t flags, - union spoolss_PrinterInfo **info_p, - uint32_t *count_p) -{ - int snum; - int n_services = lp_numservices(); - union spoolss_PrinterInfo *info = NULL; - uint32_t count = 0; - WERROR result = WERR_OK; - - *count_p = 0; - *info_p = NULL; - - for (snum = 0; snum < n_services; snum++) { - - const char *printer; - struct spoolss_PrinterInfo2 *info2; - - if (!snum_is_shared_printer(snum)) { - continue; - } - - printer = lp_const_servicename(snum); - - DEBUG(4,("Found a printer in smb.conf: %s[%x]\n", - printer, snum)); - - result = winreg_create_printer(mem_ctx, - server_info, - msg_ctx, - printer); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - info = TALLOC_REALLOC_ARRAY(mem_ctx, info, - union spoolss_PrinterInfo, - count + 1); - if (!info) { - result = WERR_NOMEM; - goto out; - } - - result = winreg_get_printer(mem_ctx, server_info, msg_ctx, - printer, &info2); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - switch (level) { - case 0: - result = construct_printer_info0(info, server_info, - msg_ctx, info2, - servername, - &info[count].info0, snum); - break; - case 1: - result = construct_printer_info1(info, info2, flags, - servername, - &info[count].info1, snum); - break; - case 2: - result = construct_printer_info2(info, msg_ctx, info2, - servername, - &info[count].info2, snum); - break; - case 4: - result = construct_printer_info4(info, info2, - servername, - &info[count].info4, snum); - break; - case 5: - result = construct_printer_info5(info, info2, - servername, - &info[count].info5, snum); - break; - - default: - result = WERR_UNKNOWN_LEVEL; - goto out; - } - - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - count++; - } - - *count_p = count; - *info_p = info; - - out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/******************************************************************** - * handle enumeration of printers at level 0 - ********************************************************************/ - -static WERROR enumprinters_level0(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t flags, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - DEBUG(4,("enum_all_printers_info_0\n")); - - return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, - servername, 0, flags, info, count); -} - - -/******************************************************************** -********************************************************************/ - -static WERROR enum_all_printers_info_1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *servername, - uint32_t flags, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - DEBUG(4,("enum_all_printers_info_1\n")); - - return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, - servername, 1, flags, info, count); -} - -/******************************************************************** - enum_all_printers_info_1_local. -*********************************************************************/ - -static WERROR enum_all_printers_info_1_local(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - DEBUG(4,("enum_all_printers_info_1_local\n")); - - return enum_all_printers_info_1(mem_ctx, server_info, msg_ctx, - servername, PRINTER_ENUM_ICON8, info, count); -} - -/******************************************************************** - enum_all_printers_info_1_name. -*********************************************************************/ - -static WERROR enum_all_printers_info_1_name(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - const char *s = servername; - - DEBUG(4,("enum_all_printers_info_1_name\n")); - - if ((servername[0] == '\\') && (servername[1] == '\\')) { - s = servername + 2; - } - - if (!is_myname_or_ipaddr(s)) { - return WERR_INVALID_NAME; - } - - return enum_all_printers_info_1(mem_ctx, server_info, msg_ctx, - servername, PRINTER_ENUM_ICON8, info, count); -} - -/******************************************************************** - enum_all_printers_info_1_network. -*********************************************************************/ - -static WERROR enum_all_printers_info_1_network(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - const char *s = servername; - - DEBUG(4,("enum_all_printers_info_1_network\n")); - - /* If we respond to a enum_printers level 1 on our name with flags - set to PRINTER_ENUM_REMOTE with a list of printers then these - printers incorrectly appear in the APW browse list. - Specifically the printers for the server appear at the workgroup - level where all the other servers in the domain are - listed. Windows responds to this call with a - WERR_CAN_NOT_COMPLETE so we should do the same. */ - - if (servername[0] == '\\' && servername[1] == '\\') { - s = servername + 2; - } - - if (is_myname_or_ipaddr(s)) { - return WERR_CAN_NOT_COMPLETE; - } - - return enum_all_printers_info_1(mem_ctx, server_info, msg_ctx, - servername, PRINTER_ENUM_NAME, info, count); -} - -/******************************************************************** - * api_spoolss_enumprinters - * - * called from api_spoolss_enumprinters (see this to understand) - ********************************************************************/ - -static WERROR enum_all_printers_info_2(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - DEBUG(4,("enum_all_printers_info_2\n")); - - return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, - servername, 2, 0, info, count); -} - -/******************************************************************** - * handle enumeration of printers at level 1 - ********************************************************************/ - -static WERROR enumprinters_level1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t flags, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - /* Not all the flags are equals */ - - if (flags & PRINTER_ENUM_LOCAL) { - return enum_all_printers_info_1_local(mem_ctx, server_info, - msg_ctx, servername, info, count); - } - - if (flags & PRINTER_ENUM_NAME) { - return enum_all_printers_info_1_name(mem_ctx, server_info, - msg_ctx, servername, info, - count); - } - - if (flags & PRINTER_ENUM_NETWORK) { - return enum_all_printers_info_1_network(mem_ctx, server_info, - msg_ctx, servername, info, - count); - } - - return WERR_OK; /* NT4sp5 does that */ -} - -/******************************************************************** - * handle enumeration of printers at level 2 - ********************************************************************/ - -static WERROR enumprinters_level2(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t flags, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - if (flags & PRINTER_ENUM_LOCAL) { - - return enum_all_printers_info_2(mem_ctx, server_info, msg_ctx, - servername, - info, count); - } - - if (flags & PRINTER_ENUM_NAME) { - if (servername && !is_myname_or_ipaddr(canon_servername(servername))) { - return WERR_INVALID_NAME; - } - - return enum_all_printers_info_2(mem_ctx, server_info, msg_ctx, - servername, - info, count); - } - - if (flags & PRINTER_ENUM_REMOTE) { - return WERR_UNKNOWN_LEVEL; - } - - return WERR_OK; -} - -/******************************************************************** - * handle enumeration of printers at level 4 - ********************************************************************/ - -static WERROR enumprinters_level4(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t flags, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - DEBUG(4,("enum_all_printers_info_4\n")); - - return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, - servername, 4, flags, info, count); -} - - -/******************************************************************** - * handle enumeration of printers at level 5 - ********************************************************************/ - -static WERROR enumprinters_level5(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t flags, - const char *servername, - union spoolss_PrinterInfo **info, - uint32_t *count) -{ - DEBUG(4,("enum_all_printers_info_5\n")); - - return enum_all_printers_info_level(mem_ctx, server_info, msg_ctx, - servername, 5, flags, info, count); -} - -/**************************************************************** - _spoolss_EnumPrinters -****************************************************************/ - -WERROR _spoolss_EnumPrinters(struct pipes_struct *p, - struct spoolss_EnumPrinters *r) -{ - const struct auth_serversupplied_info *server_info = get_server_info_system(); - WERROR result; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(4,("_spoolss_EnumPrinters\n")); - - *r->out.needed = 0; - *r->out.count = 0; - *r->out.info = NULL; - - /* - * Level 1: - * flags==PRINTER_ENUM_NAME - * if name=="" then enumerates all printers - * if name!="" then enumerate the printer - * flags==PRINTER_ENUM_REMOTE - * name is NULL, enumerate printers - * Level 2: name!="" enumerates printers, name can't be NULL - * Level 3: doesn't exist - * Level 4: does a local registry lookup - * Level 5: same as Level 2 - */ - - if (r->in.server && r->in.server[0] == '\0') { - r->in.server = NULL; - } - - switch (r->in.level) { - case 0: - result = enumprinters_level0(p->mem_ctx, server_info, - p->msg_ctx, r->in.flags, - r->in.server, - r->out.info, r->out.count); - break; - case 1: - result = enumprinters_level1(p->mem_ctx, server_info, - p->msg_ctx, r->in.flags, - r->in.server, - r->out.info, r->out.count); - break; - case 2: - result = enumprinters_level2(p->mem_ctx, server_info, - p->msg_ctx, r->in.flags, - r->in.server, - r->out.info, r->out.count); - break; - case 4: - result = enumprinters_level4(p->mem_ctx, server_info, - p->msg_ctx, r->in.flags, - r->in.server, - r->out.info, r->out.count); - break; - case 5: - result = enumprinters_level5(p->mem_ctx, server_info, - p->msg_ctx, r->in.flags, - r->in.server, - r->out.info, r->out.count); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumPrinters, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************** - _spoolss_GetPrinter -****************************************************************/ - -WERROR _spoolss_GetPrinter(struct pipes_struct *p, - struct spoolss_GetPrinter *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - struct spoolss_PrinterInfo2 *info2 = NULL; - WERROR result = WERR_OK; - int snum; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - *r->out.needed = 0; - - if (Printer == NULL) { - return WERR_BADFID; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - result = winreg_get_printer(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - &info2); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - switch (r->in.level) { - case 0: - result = construct_printer_info0(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - info2, - Printer->servername, - &r->out.info->info0, - snum); - break; - case 1: - result = construct_printer_info1(p->mem_ctx, info2, - PRINTER_ENUM_ICON8, - Printer->servername, - &r->out.info->info1, snum); - break; - case 2: - result = construct_printer_info2(p->mem_ctx, p->msg_ctx, info2, - Printer->servername, - &r->out.info->info2, snum); - break; - case 3: - result = construct_printer_info3(p->mem_ctx, info2, - Printer->servername, - &r->out.info->info3, snum); - break; - case 4: - result = construct_printer_info4(p->mem_ctx, info2, - Printer->servername, - &r->out.info->info4, snum); - break; - case 5: - result = construct_printer_info5(p->mem_ctx, info2, - Printer->servername, - &r->out.info->info5, snum); - break; - case 6: - result = construct_printer_info6(p->mem_ctx, p->msg_ctx, info2, - Printer->servername, - &r->out.info->info6, snum); - break; - case 7: - result = construct_printer_info7(p->mem_ctx, p->msg_ctx, - Printer->servername, - &r->out.info->info7, snum); - break; - case 8: - result = construct_printer_info8(p->mem_ctx, info2, - Printer->servername, - &r->out.info->info8, snum); - break; - default: - result = WERR_UNKNOWN_LEVEL; - break; - } - - out: - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("_spoolss_GetPrinter: failed to construct printer info level %d - %s\n", - r->in.level, win_errstr(result))); - TALLOC_FREE(r->out.info); - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_PrinterInfo, - r->out.info, r->in.level); - r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/******************************************************************** - ********************************************************************/ - -#define FILL_DRIVER_STRING(mem_ctx, in, out) \ - do { \ - if (in && strlen(in)) { \ - out = talloc_strdup(mem_ctx, in); \ - } else { \ - out = talloc_strdup(mem_ctx, ""); \ - } \ - W_ERROR_HAVE_NO_MEMORY(out); \ - } while (0); - -#define FILL_DRIVER_UNC_STRING(mem_ctx, server, arch, ver, in, out) \ - do { \ - if (in && strlen(in)) { \ - out = talloc_asprintf(mem_ctx, "\\\\%s\\print$\\%s\\%d\\%s", server, get_short_archi(arch), ver, in); \ - } else { \ - out = talloc_strdup(mem_ctx, ""); \ - } \ - W_ERROR_HAVE_NO_MEMORY(out); \ - } while (0); - -static WERROR string_array_from_driver_info(TALLOC_CTX *mem_ctx, - const char **string_array, - const char ***presult, - const char *cservername, - const char *arch, - int version) -{ - int i, num_strings = 0; - const char **array = NULL; - - if (string_array == NULL) { - return WERR_INVALID_PARAMETER; - } - - for (i=0; string_array[i] && string_array[i][0] != '\0'; i++) { - const char *str = NULL; - - if (cservername == NULL || arch == NULL) { - FILL_DRIVER_STRING(mem_ctx, string_array[i], str); - } else { - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, arch, version, string_array[i], str); - } - - if (!add_string_to_array(mem_ctx, str, &array, &num_strings)) { - TALLOC_FREE(array); - return WERR_NOMEM; - } - } - - if (i > 0) { - ADD_TO_ARRAY(mem_ctx, const char *, NULL, - &array, &num_strings); - } - - if (presult) { - *presult = array; - } - - return WERR_OK; -} - -/******************************************************************** - * fill a spoolss_DriverInfo1 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info1(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo1 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) -{ - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - - return WERR_OK; -} - -/******************************************************************** - * fill a spoolss_DriverInfo2 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info2(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo2 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) - -{ - const char *cservername = canon_servername(servername); - - r->version = driver->version; - - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - r->architecture = talloc_strdup(mem_ctx, driver->architecture); - W_ERROR_HAVE_NO_MEMORY(r->architecture); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->driver_path, - r->driver_path); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->data_file, - r->data_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->config_file, - r->config_file); - - return WERR_OK; -} - -/******************************************************************** - * fill a spoolss_DriverInfo3 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info3(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo3 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) -{ - const char *cservername = canon_servername(servername); - - r->version = driver->version; - - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - r->architecture = talloc_strdup(mem_ctx, driver->architecture); - W_ERROR_HAVE_NO_MEMORY(r->architecture); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->driver_path, - r->driver_path); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->data_file, - r->data_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->config_file, - r->config_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->help_file, - r->help_file); - - FILL_DRIVER_STRING(mem_ctx, - driver->monitor_name, - r->monitor_name); - - FILL_DRIVER_STRING(mem_ctx, - driver->default_datatype, - r->default_datatype); - - return string_array_from_driver_info(mem_ctx, - driver->dependent_files, - &r->dependent_files, - cservername, - driver->architecture, - driver->version); -} - -/******************************************************************** - * fill a spoolss_DriverInfo4 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info4(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo4 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) -{ - const char *cservername = canon_servername(servername); - WERROR result; - - r->version = driver->version; - - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - r->architecture = talloc_strdup(mem_ctx, driver->architecture); - W_ERROR_HAVE_NO_MEMORY(r->architecture); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->driver_path, - r->driver_path); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->data_file, - r->data_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->config_file, - r->config_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->help_file, - r->help_file); - - result = string_array_from_driver_info(mem_ctx, - driver->dependent_files, - &r->dependent_files, - cservername, - driver->architecture, - driver->version); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - FILL_DRIVER_STRING(mem_ctx, - driver->monitor_name, - r->monitor_name); - - FILL_DRIVER_STRING(mem_ctx, - driver->default_datatype, - r->default_datatype); - - - result = string_array_from_driver_info(mem_ctx, - driver->previous_names, - &r->previous_names, - NULL, NULL, 0); - - return result; -} - -/******************************************************************** - * fill a spoolss_DriverInfo5 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info5(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo5 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) -{ - const char *cservername = canon_servername(servername); - - r->version = driver->version; - - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - r->architecture = talloc_strdup(mem_ctx, driver->architecture); - W_ERROR_HAVE_NO_MEMORY(r->architecture); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->driver_path, - r->driver_path); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->data_file, - r->data_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->config_file, - r->config_file); - - r->driver_attributes = 0; - r->config_version = 0; - r->driver_version = 0; - - return WERR_OK; -} -/******************************************************************** - * fill a spoolss_DriverInfo6 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo6 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) -{ - const char *cservername = canon_servername(servername); - WERROR result; - - r->version = driver->version; - - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - r->architecture = talloc_strdup(mem_ctx, driver->architecture); - W_ERROR_HAVE_NO_MEMORY(r->architecture); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->driver_path, - r->driver_path); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->data_file, - r->data_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->config_file, - r->config_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->help_file, - r->help_file); - - FILL_DRIVER_STRING(mem_ctx, - driver->monitor_name, - r->monitor_name); - - FILL_DRIVER_STRING(mem_ctx, - driver->default_datatype, - r->default_datatype); - - result = string_array_from_driver_info(mem_ctx, - driver->dependent_files, - &r->dependent_files, - cservername, - driver->architecture, - driver->version); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - result = string_array_from_driver_info(mem_ctx, - driver->previous_names, - &r->previous_names, - NULL, NULL, 0); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - r->driver_date = driver->driver_date; - r->driver_version = driver->driver_version; - - FILL_DRIVER_STRING(mem_ctx, - driver->manufacturer_name, - r->manufacturer_name); - FILL_DRIVER_STRING(mem_ctx, - driver->manufacturer_url, - r->manufacturer_url); - FILL_DRIVER_STRING(mem_ctx, - driver->hardware_id, - r->hardware_id); - FILL_DRIVER_STRING(mem_ctx, - driver->provider, - r->provider); - - return WERR_OK; -} - -/******************************************************************** - * fill a spoolss_DriverInfo8 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info8(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo8 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) -{ - const char *cservername = canon_servername(servername); - WERROR result; - - r->version = driver->version; - - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - r->architecture = talloc_strdup(mem_ctx, driver->architecture); - W_ERROR_HAVE_NO_MEMORY(r->architecture); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->driver_path, - r->driver_path); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->data_file, - r->data_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->config_file, - r->config_file); - - FILL_DRIVER_UNC_STRING(mem_ctx, cservername, - driver->architecture, - driver->version, - driver->help_file, - r->help_file); - - FILL_DRIVER_STRING(mem_ctx, - driver->monitor_name, - r->monitor_name); - - FILL_DRIVER_STRING(mem_ctx, - driver->default_datatype, - r->default_datatype); - - result = string_array_from_driver_info(mem_ctx, - driver->dependent_files, - &r->dependent_files, - cservername, - driver->architecture, - driver->version); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - result = string_array_from_driver_info(mem_ctx, - driver->previous_names, - &r->previous_names, - NULL, NULL, 0); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - r->driver_date = driver->driver_date; - r->driver_version = driver->driver_version; - - FILL_DRIVER_STRING(mem_ctx, - driver->manufacturer_name, - r->manufacturer_name); - FILL_DRIVER_STRING(mem_ctx, - driver->manufacturer_url, - r->manufacturer_url); - FILL_DRIVER_STRING(mem_ctx, - driver->hardware_id, - r->hardware_id); - FILL_DRIVER_STRING(mem_ctx, - driver->provider, - r->provider); - - FILL_DRIVER_STRING(mem_ctx, - driver->print_processor, - r->print_processor); - FILL_DRIVER_STRING(mem_ctx, - driver->vendor_setup, - r->vendor_setup); - - result = string_array_from_driver_info(mem_ctx, - driver->color_profiles, - &r->color_profiles, - NULL, NULL, 0); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - FILL_DRIVER_STRING(mem_ctx, - driver->inf_path, - r->inf_path); - - r->printer_driver_attributes = driver->printer_driver_attributes; - - result = string_array_from_driver_info(mem_ctx, - driver->core_driver_dependencies, - &r->core_driver_dependencies, - NULL, NULL, 0); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - r->min_inbox_driver_ver_date = driver->min_inbox_driver_ver_date; - r->min_inbox_driver_ver_version = driver->min_inbox_driver_ver_version; - - return WERR_OK; -} - -#if 0 /* disabled until marshalling issues are resolved - gd */ -/******************************************************************** - ********************************************************************/ - -static WERROR fill_spoolss_DriverFileInfo(TALLOC_CTX *mem_ctx, - struct spoolss_DriverFileInfo *r, - const char *cservername, - const char *file_name, - enum spoolss_DriverFileType file_type, - uint32_t file_version) -{ - r->file_name = talloc_asprintf(mem_ctx, "\\\\%s%s", - cservername, file_name); - W_ERROR_HAVE_NO_MEMORY(r->file_name); - r->file_type = file_type; - r->file_version = file_version; - - return WERR_OK; -} - -/******************************************************************** - ********************************************************************/ - -static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx, - const struct spoolss_DriverInfo8 *driver, - const char *cservername, - struct spoolss_DriverFileInfo **info_p, - uint32_t *count_p) -{ - struct spoolss_DriverFileInfo *info = NULL; - uint32_t count = 0; - WERROR result; - uint32_t i; - - *info_p = NULL; - *count_p = 0; - - if (strlen(driver->driver_path)) { - info = TALLOC_REALLOC_ARRAY(mem_ctx, info, - struct spoolss_DriverFileInfo, - count + 1); - W_ERROR_HAVE_NO_MEMORY(info); - result = fill_spoolss_DriverFileInfo(info, - &info[count], - cservername, - driver->driver_path, - SPOOLSS_DRIVER_FILE_TYPE_RENDERING, - 0); - W_ERROR_NOT_OK_RETURN(result); - count++; - } - - if (strlen(driver->config_file)) { - info = TALLOC_REALLOC_ARRAY(mem_ctx, info, - struct spoolss_DriverFileInfo, - count + 1); - W_ERROR_HAVE_NO_MEMORY(info); - result = fill_spoolss_DriverFileInfo(info, - &info[count], - cservername, - driver->config_file, - SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION, - 0); - W_ERROR_NOT_OK_RETURN(result); - count++; - } - - if (strlen(driver->data_file)) { - info = TALLOC_REALLOC_ARRAY(mem_ctx, info, - struct spoolss_DriverFileInfo, - count + 1); - W_ERROR_HAVE_NO_MEMORY(info); - result = fill_spoolss_DriverFileInfo(info, - &info[count], - cservername, - driver->data_file, - SPOOLSS_DRIVER_FILE_TYPE_DATA, - 0); - W_ERROR_NOT_OK_RETURN(result); - count++; - } - - if (strlen(driver->help_file)) { - info = TALLOC_REALLOC_ARRAY(mem_ctx, info, - struct spoolss_DriverFileInfo, - count + 1); - W_ERROR_HAVE_NO_MEMORY(info); - result = fill_spoolss_DriverFileInfo(info, - &info[count], - cservername, - driver->help_file, - SPOOLSS_DRIVER_FILE_TYPE_HELP, - 0); - W_ERROR_NOT_OK_RETURN(result); - count++; - } - - for (i=0; driver->dependent_files[i] && driver->dependent_files[i][0] != '\0'; i++) { - info = TALLOC_REALLOC_ARRAY(mem_ctx, info, - struct spoolss_DriverFileInfo, - count + 1); - W_ERROR_HAVE_NO_MEMORY(info); - result = fill_spoolss_DriverFileInfo(info, - &info[count], - cservername, - driver->dependent_files[i], - SPOOLSS_DRIVER_FILE_TYPE_OTHER, - 0); - W_ERROR_NOT_OK_RETURN(result); - count++; - } - - *info_p = info; - *count_p = count; - - return WERR_OK; -} - -/******************************************************************** - * fill a spoolss_DriverInfo101 struct - ********************************************************************/ - -static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx, - struct spoolss_DriverInfo101 *r, - const struct spoolss_DriverInfo8 *driver, - const char *servername) -{ - const char *cservername = canon_servername(servername); - WERROR result; - - r->version = driver->version; - - r->driver_name = talloc_strdup(mem_ctx, driver->driver_name); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - r->architecture = talloc_strdup(mem_ctx, driver->architecture); - W_ERROR_HAVE_NO_MEMORY(r->architecture); - - result = spoolss_DriverFileInfo_from_driver(mem_ctx, driver, - cservername, - &r->file_info, - &r->file_count); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - FILL_DRIVER_STRING(mem_ctx, - driver->monitor_name, - r->monitor_name); - - FILL_DRIVER_STRING(mem_ctx, - driver->default_datatype, - r->default_datatype); - - result = string_array_from_driver_info(mem_ctx, - driver->previous_names, - &r->previous_names, - NULL, NULL, 0); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - r->driver_date = driver->driver_date; - r->driver_version = driver->driver_version; - - FILL_DRIVER_STRING(mem_ctx, - driver->manufacturer_name, - r->manufacturer_name); - FILL_DRIVER_STRING(mem_ctx, - driver->manufacturer_url, - r->manufacturer_url); - FILL_DRIVER_STRING(mem_ctx, - driver->hardware_id, - r->hardware_id); - FILL_DRIVER_STRING(mem_ctx, - driver->provider, - r->provider); - - return WERR_OK; -} -#endif -/******************************************************************** - ********************************************************************/ - -static WERROR construct_printer_driver_info_level(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t level, - union spoolss_DriverInfo *r, - int snum, - const char *servername, - const char *architecture, - uint32_t version) -{ - struct spoolss_PrinterInfo2 *pinfo2 = NULL; - struct spoolss_DriverInfo8 *driver; - WERROR result; - - if (level == 101) { - return WERR_UNKNOWN_LEVEL; - } - - result = winreg_get_printer(mem_ctx, - server_info, - msg_ctx, - lp_const_servicename(snum), - &pinfo2); - - DEBUG(8,("construct_printer_driver_info_level: status: %s\n", - win_errstr(result))); - - if (!W_ERROR_IS_OK(result)) { - return WERR_INVALID_PRINTER_NAME; - } - - result = winreg_get_driver(mem_ctx, server_info, msg_ctx, - architecture, - pinfo2->drivername, version, &driver); - - DEBUG(8,("construct_printer_driver_info_level: status: %s\n", - win_errstr(result))); - - if (!W_ERROR_IS_OK(result)) { - /* - * Is this a W2k client ? - */ - - if (version < 3) { - talloc_free(pinfo2); - return WERR_UNKNOWN_PRINTER_DRIVER; - } - - /* Yes - try again with a WinNT driver. */ - version = 2; - result = winreg_get_driver(mem_ctx, server_info, msg_ctx, - architecture, - pinfo2->drivername, - version, &driver); - DEBUG(8,("construct_printer_driver_level: status: %s\n", - win_errstr(result))); - if (!W_ERROR_IS_OK(result)) { - talloc_free(pinfo2); - return WERR_UNKNOWN_PRINTER_DRIVER; - } - } - - switch (level) { - case 1: - result = fill_printer_driver_info1(mem_ctx, &r->info1, driver, servername); - break; - case 2: - result = fill_printer_driver_info2(mem_ctx, &r->info2, driver, servername); - break; - case 3: - result = fill_printer_driver_info3(mem_ctx, &r->info3, driver, servername); - break; - case 4: - result = fill_printer_driver_info4(mem_ctx, &r->info4, driver, servername); - break; - case 5: - result = fill_printer_driver_info5(mem_ctx, &r->info5, driver, servername); - break; - case 6: - result = fill_printer_driver_info6(mem_ctx, &r->info6, driver, servername); - break; - case 8: - result = fill_printer_driver_info8(mem_ctx, &r->info8, driver, servername); - break; -#if 0 /* disabled until marshalling issues are resolved - gd */ - case 101: - result = fill_printer_driver_info101(mem_ctx, &r->info101, driver, servername); - break; -#endif - default: - result = WERR_UNKNOWN_LEVEL; - break; - } - - talloc_free(pinfo2); - talloc_free(driver); - - return result; -} - -/**************************************************************** - _spoolss_GetPrinterDriver2 -****************************************************************/ - -WERROR _spoolss_GetPrinterDriver2(struct pipes_struct *p, - struct spoolss_GetPrinterDriver2 *r) -{ - struct printer_handle *printer; - WERROR result; - - int snum; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(4,("_spoolss_GetPrinterDriver2\n")); - - if (!(printer = find_printer_index_by_hnd(p, r->in.handle))) { - DEBUG(0,("_spoolss_GetPrinterDriver2: invalid printer handle!\n")); - return WERR_INVALID_PRINTER_NAME; - } - - *r->out.needed = 0; - *r->out.server_major_version = 0; - *r->out.server_minor_version = 0; - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - result = construct_printer_driver_info_level(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->in.level, r->out.info, - snum, printer->servername, - r->in.architecture, - r->in.client_major_version); - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(r->out.info); - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_DriverInfo, - r->out.info, r->in.level); - r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - - -/**************************************************************** - _spoolss_StartPagePrinter -****************************************************************/ - -WERROR _spoolss_StartPagePrinter(struct pipes_struct *p, - struct spoolss_StartPagePrinter *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - if (!Printer) { - DEBUG(3,("_spoolss_StartPagePrinter: " - "Error in startpageprinter printer handle\n")); - return WERR_BADFID; - } - - Printer->page_started = true; - return WERR_OK; -} - -/**************************************************************** - _spoolss_EndPagePrinter -****************************************************************/ - -WERROR _spoolss_EndPagePrinter(struct pipes_struct *p, - struct spoolss_EndPagePrinter *r) -{ - int snum; - - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - if (!Printer) { - DEBUG(2,("_spoolss_EndPagePrinter: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) - return WERR_BADFID; - - Printer->page_started = false; - print_job_endpage(p->msg_ctx, snum, Printer->jobid); - - return WERR_OK; -} - -/**************************************************************** - _spoolss_StartDocPrinter -****************************************************************/ - -WERROR _spoolss_StartDocPrinter(struct pipes_struct *p, - struct spoolss_StartDocPrinter *r) -{ - struct spoolss_DocumentInfo1 *info_1; - int snum; - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - WERROR werr; - - if (!Printer) { - DEBUG(2,("_spoolss_StartDocPrinter: " - "Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (Printer->jobid) { - DEBUG(2, ("_spoolss_StartDocPrinter: " - "StartDocPrinter called twice! " - "(existing jobid = %d)\n", Printer->jobid)); - return WERR_INVALID_HANDLE; - } - - if (r->in.level != 1) { - return WERR_UNKNOWN_LEVEL; - } - - info_1 = r->in.info.info1; - - /* - * a nice thing with NT is it doesn't listen to what you tell it. - * when asked to send _only_ RAW datas, it tries to send datas - * in EMF format. - * - * So I add checks like in NT Server ... - */ - - if (info_1->datatype) { - if (strcmp(info_1->datatype, "RAW") != 0) { - *r->out.job_id = 0; - return WERR_INVALID_DATATYPE; - } - } - - /* get the share number of the printer */ - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - werr = print_job_start(p->server_info, - p->msg_ctx, - p->client_id->name, - snum, - info_1->document_name, - info_1->output_file, - Printer->devmode, - &Printer->jobid); - - /* An error occured in print_job_start() so return an appropriate - NT error code. */ - - if (!W_ERROR_IS_OK(werr)) { - return werr; - } - - Printer->document_started = true; - *r->out.job_id = Printer->jobid; - - return WERR_OK; -} - -/**************************************************************** - _spoolss_EndDocPrinter -****************************************************************/ - -WERROR _spoolss_EndDocPrinter(struct pipes_struct *p, - struct spoolss_EndDocPrinter *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - NTSTATUS status; - int snum; - - if (!Printer) { - DEBUG(2,("_spoolss_EndDocPrinter: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - Printer->document_started = false; - status = print_job_end(p->msg_ctx, snum, Printer->jobid, NORMAL_CLOSE); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(2, ("_spoolss_EndDocPrinter: " - "print_job_end failed [%s]\n", - nt_errstr(status))); - } - - Printer->jobid = 0; - return ntstatus_to_werror(status); -} - -/**************************************************************** - _spoolss_WritePrinter -****************************************************************/ - -WERROR _spoolss_WritePrinter(struct pipes_struct *p, - struct spoolss_WritePrinter *r) -{ - ssize_t buffer_written; - int snum; - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - if (!Printer) { - DEBUG(2,("_spoolss_WritePrinter: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(r->in.handle))); - *r->out.num_written = r->in._data_size; - return WERR_BADFID; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) - return WERR_BADFID; - - /* print_job_write takes care of checking for PJOB_SMBD_SPOOLING */ - buffer_written = print_job_write(server_event_context(),p->msg_ctx, - snum, Printer->jobid, - (const char *)r->in.data.data, - (size_t)r->in._data_size); - if (buffer_written == (ssize_t)-1) { - *r->out.num_written = 0; - if (errno == ENOSPC) - return WERR_NO_SPOOL_SPACE; - else - return WERR_ACCESS_DENIED; - } - - *r->out.num_written = r->in._data_size; - - return WERR_OK; -} - -/******************************************************************** - * api_spoolss_getprinter - * called from the spoolss dispatcher - * - ********************************************************************/ - -static WERROR control_printer(struct policy_handle *handle, uint32_t command, - struct pipes_struct *p) -{ - const struct auth_serversupplied_info *server_info = p->server_info; - int snum; - WERROR errcode = WERR_BADFUNC; - struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); - - if (!Printer) { - DEBUG(2,("control_printer: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, handle, &snum, NULL)) - return WERR_BADFID; - - switch (command) { - case SPOOLSS_PRINTER_CONTROL_PAUSE: - errcode = print_queue_pause(server_info, p->msg_ctx, snum); - break; - case SPOOLSS_PRINTER_CONTROL_RESUME: - case SPOOLSS_PRINTER_CONTROL_UNPAUSE: - errcode = print_queue_resume(server_info, p->msg_ctx, snum); - break; - case SPOOLSS_PRINTER_CONTROL_PURGE: - errcode = print_queue_purge(server_info, p->msg_ctx, snum); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - return errcode; -} - - -/**************************************************************** - _spoolss_AbortPrinter - * From MSDN: "Deletes printer's spool file if printer is configured - * for spooling" -****************************************************************/ - -WERROR _spoolss_AbortPrinter(struct pipes_struct *p, - struct spoolss_AbortPrinter *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - int snum; - WERROR errcode = WERR_OK; - - if (!Printer) { - DEBUG(2,("_spoolss_AbortPrinter: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) - return WERR_BADFID; - - if (!Printer->document_started) { - return WERR_SPL_NO_STARTDOC; - } - - errcode = print_job_delete(p->server_info, - p->msg_ctx, - snum, - Printer->jobid); - - return errcode; -} - -/******************************************************************** - * called by spoolss_api_setprinter - * when updating a printer description - ********************************************************************/ - -static WERROR update_printer_sec(struct policy_handle *handle, - struct pipes_struct *p, - struct sec_desc_buf *secdesc_ctr) -{ - struct spoolss_security_descriptor *new_secdesc = NULL; - struct spoolss_security_descriptor *old_secdesc = NULL; - const char *printer; - WERROR result; - int snum; - - struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); - - if (!Printer || !get_printer_snum(p, handle, &snum, NULL)) { - DEBUG(2,("update_printer_sec: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(handle))); - - result = WERR_BADFID; - goto done; - } - - if (secdesc_ctr == NULL) { - DEBUG(10,("update_printer_sec: secdesc_ctr is NULL !\n")); - result = WERR_INVALID_PARAM; - goto done; - } - printer = lp_const_servicename(snum); - - /* Check the user has permissions to change the security - descriptor. By experimentation with two NT machines, the user - requires Full Access to the printer to change security - information. */ - - if ( Printer->access_granted != PRINTER_ACCESS_ADMINISTER ) { - DEBUG(4,("update_printer_sec: updated denied by printer permissions\n")); - result = WERR_ACCESS_DENIED; - goto done; - } - - /* NT seems to like setting the security descriptor even though - nothing may have actually changed. */ - result = winreg_get_printer_secdesc(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer, - &old_secdesc); - if (!W_ERROR_IS_OK(result)) { - DEBUG(2,("update_printer_sec: winreg_get_printer_secdesc() failed\n")); - result = WERR_BADFID; - goto done; - } - - if (DEBUGLEVEL >= 10) { - struct security_acl *the_acl; - int i; - - the_acl = old_secdesc->dacl; - DEBUG(10, ("old_secdesc_ctr for %s has %d aces:\n", - printer, the_acl->num_aces)); - - for (i = 0; i < the_acl->num_aces; i++) { - DEBUG(10, ("%s 0x%08x\n", sid_string_dbg( - &the_acl->aces[i].trustee), - the_acl->aces[i].access_mask)); - } - - the_acl = secdesc_ctr->sd->dacl; - - if (the_acl) { - DEBUG(10, ("secdesc_ctr for %s has %d aces:\n", - printer, the_acl->num_aces)); - - for (i = 0; i < the_acl->num_aces; i++) { - DEBUG(10, ("%s 0x%08x\n", sid_string_dbg( - &the_acl->aces[i].trustee), - the_acl->aces[i].access_mask)); - } - } else { - DEBUG(10, ("dacl for secdesc_ctr is NULL\n")); - } - } - - new_secdesc = sec_desc_merge(p->mem_ctx, secdesc_ctr->sd, old_secdesc); - if (new_secdesc == NULL) { - result = WERR_NOMEM; - goto done; - } - - if (security_descriptor_equal(new_secdesc, old_secdesc)) { - result = WERR_OK; - goto done; - } - - result = winreg_set_printer_secdesc(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer, - new_secdesc); - - done: - return result; -} - -/******************************************************************** - Canonicalize printer info from a client - ********************************************************************/ - -static bool check_printer_ok(TALLOC_CTX *mem_ctx, - struct spoolss_SetPrinterInfo2 *info2, - int snum) -{ - fstring printername; - const char *p; - - DEBUG(5,("check_printer_ok: servername=%s printername=%s sharename=%s " - "portname=%s drivername=%s comment=%s location=%s\n", - info2->servername, info2->printername, info2->sharename, - info2->portname, info2->drivername, info2->comment, - info2->location)); - - /* we force some elements to "correct" values */ - info2->servername = talloc_asprintf(mem_ctx, "\\\\%s", global_myname()); - if (info2->servername == NULL) { - return false; - } - info2->sharename = talloc_strdup(mem_ctx, lp_const_servicename(snum)); - if (info2->sharename == NULL) { - return false; - } - - /* check to see if we allow printername != sharename */ - if (lp_force_printername(snum)) { - info2->printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", - global_myname(), info2->sharename); - } else { - /* make sure printername is in \\server\printername format */ - fstrcpy(printername, info2->printername); - p = printername; - if ( printername[0] == '\\' && printername[1] == '\\' ) { - if ( (p = strchr_m( &printername[2], '\\' )) != NULL ) - p++; - } - - info2->printername = talloc_asprintf(mem_ctx, "\\\\%s\\%s", - global_myname(), p); - } - if (info2->printername == NULL) { - return false; - } - - info2->attributes |= PRINTER_ATTRIBUTE_SAMBA; - info2->attributes &= ~PRINTER_ATTRIBUTE_NOT_SAMBA; - - return true; -} - -/**************************************************************************** -****************************************************************************/ - -static WERROR add_port_hook(TALLOC_CTX *ctx, struct security_token *token, const char *portname, const char *uri) -{ - char *cmd = lp_addport_cmd(); - char *command = NULL; - int ret; - bool is_print_op = false; - - if ( !*cmd ) { - return WERR_ACCESS_DENIED; - } - - command = talloc_asprintf(ctx, - "%s \"%s\" \"%s\"", cmd, portname, uri ); - if (!command) { - return WERR_NOMEM; - } - - if ( token ) - is_print_op = security_token_has_privilege(token, SEC_PRIV_PRINT_OPERATOR); - - DEBUG(10,("Running [%s]\n", command)); - - /********* BEGIN SePrintOperatorPrivilege **********/ - - if ( is_print_op ) - become_root(); - - ret = smbrun(command, NULL); - - if ( is_print_op ) - unbecome_root(); - - /********* END SePrintOperatorPrivilege **********/ - - DEBUGADD(10,("returned [%d]\n", ret)); - - TALLOC_FREE(command); - - if ( ret != 0 ) { - return WERR_ACCESS_DENIED; - } - - return WERR_OK; -} - -/**************************************************************************** -****************************************************************************/ - -static bool add_printer_hook(TALLOC_CTX *ctx, struct security_token *token, - struct spoolss_SetPrinterInfo2 *info2, - const char *remote_machine, - struct messaging_context *msg_ctx) -{ - char *cmd = lp_addprinter_cmd(); - char **qlines; - char *command = NULL; - int numlines; - int ret; - int fd; - bool is_print_op = false; - - if (!remote_machine) { - return false; - } - - command = talloc_asprintf(ctx, - "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", - cmd, info2->printername, info2->sharename, - info2->portname, info2->drivername, - info2->location, info2->comment, remote_machine); - if (!command) { - return false; - } - - if ( token ) - is_print_op = security_token_has_privilege(token, SEC_PRIV_PRINT_OPERATOR); - - DEBUG(10,("Running [%s]\n", command)); - - /********* BEGIN SePrintOperatorPrivilege **********/ - - if ( is_print_op ) - become_root(); - - if ( (ret = smbrun(command, &fd)) == 0 ) { - /* Tell everyone we updated smb.conf. */ - message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL); - } - - if ( is_print_op ) - unbecome_root(); - - /********* END SePrintOperatorPrivilege **********/ - - DEBUGADD(10,("returned [%d]\n", ret)); - - TALLOC_FREE(command); - - if ( ret != 0 ) { - if (fd != -1) - close(fd); - return false; - } - - /* reload our services immediately */ - become_root(); - reload_services(msg_ctx, -1, false); - unbecome_root(); - - numlines = 0; - /* Get lines and convert them back to dos-codepage */ - qlines = fd_lines_load(fd, &numlines, 0, NULL); - DEBUGADD(10,("Lines returned = [%d]\n", numlines)); - close(fd); - - /* Set the portname to what the script says the portname should be. */ - /* but don't require anything to be return from the script exit a good error code */ - - if (numlines) { - /* Set the portname to what the script says the portname should be. */ - info2->portname = talloc_strdup(ctx, qlines[0]); - DEBUGADD(6,("Line[0] = [%s]\n", qlines[0])); - } - - TALLOC_FREE(qlines); - return true; -} - -static WERROR update_dsspooler(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - int snum, - struct spoolss_SetPrinterInfo2 *printer, - struct spoolss_PrinterInfo2 *old_printer) -{ - bool force_update = (old_printer == NULL); - const char *dnsdomname; - const char *longname; - const char *uncname; - const char *spooling; - DATA_BLOB buffer; - WERROR result = WERR_OK; - - if (force_update || !strequal(printer->drivername, old_printer->drivername)) { - push_reg_sz(mem_ctx, &buffer, printer->drivername); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_DRIVERNAME, - REG_SZ, - buffer.data, - buffer.length); - - if (!force_update) { - DEBUG(10,("update_printer: changing driver [%s]! Sending event!\n", - printer->drivername)); - - notify_printer_driver(server_event_context(), msg_ctx, - snum, printer->drivername ? - printer->drivername : ""); - } - } - - if (force_update || !strequal(printer->comment, old_printer->comment)) { - push_reg_sz(mem_ctx, &buffer, printer->comment); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_DESCRIPTION, - REG_SZ, - buffer.data, - buffer.length); - - if (!force_update) { - notify_printer_comment(server_event_context(), msg_ctx, - snum, printer->comment ? - printer->comment : ""); - } - } - - if (force_update || !strequal(printer->sharename, old_printer->sharename)) { - push_reg_sz(mem_ctx, &buffer, printer->sharename); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRINTSHARENAME, - REG_SZ, - buffer.data, - buffer.length); - - if (!force_update) { - notify_printer_sharename(server_event_context(), - msg_ctx, - snum, printer->sharename ? - printer->sharename : ""); - } - } - - if (force_update || !strequal(printer->printername, old_printer->printername)) { - const char *p; - - p = strrchr(printer->printername, '\\' ); - if (p != NULL) { - p++; - } else { - p = printer->printername; - } - - push_reg_sz(mem_ctx, &buffer, p); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRINTERNAME, - REG_SZ, - buffer.data, - buffer.length); - - if (!force_update) { - notify_printer_printername(server_event_context(), - msg_ctx, snum, p ? p : ""); - } - } - - if (force_update || !strequal(printer->portname, old_printer->portname)) { - push_reg_sz(mem_ctx, &buffer, printer->portname); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PORTNAME, - REG_SZ, - buffer.data, - buffer.length); - - if (!force_update) { - notify_printer_port(server_event_context(), - msg_ctx, snum, printer->portname ? - printer->portname : ""); - } - } - - if (force_update || !strequal(printer->location, old_printer->location)) { - push_reg_sz(mem_ctx, &buffer, printer->location); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_LOCATION, - REG_SZ, - buffer.data, - buffer.length); - - if (!force_update) { - notify_printer_location(server_event_context(), - msg_ctx, snum, - printer->location ? - printer->location : ""); - } - } - - if (force_update || !strequal(printer->sepfile, old_printer->sepfile)) { - push_reg_sz(mem_ctx, &buffer, printer->sepfile); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRINTSEPARATORFILE, - REG_SZ, - buffer.data, - buffer.length); - - if (!force_update) { - notify_printer_sepfile(server_event_context(), - msg_ctx, snum, - printer->sepfile ? - printer->sepfile : ""); - } - } - - if (force_update || printer->starttime != old_printer->starttime) { - buffer = data_blob_talloc(mem_ctx, NULL, 4); - SIVAL(buffer.data, 0, printer->starttime); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRINTSTARTTIME, - REG_DWORD, - buffer.data, - buffer.length); - } - - if (force_update || printer->untiltime != old_printer->untiltime) { - buffer = data_blob_talloc(mem_ctx, NULL, 4); - SIVAL(buffer.data, 0, printer->untiltime); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRINTENDTIME, - REG_DWORD, - buffer.data, - buffer.length); - } - - if (force_update || printer->priority != old_printer->priority) { - buffer = data_blob_talloc(mem_ctx, NULL, 4); - SIVAL(buffer.data, 0, printer->priority); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRIORITY, - REG_DWORD, - buffer.data, - buffer.length); - } - - if (force_update || printer->attributes != old_printer->attributes) { - buffer = data_blob_talloc(mem_ctx, NULL, 4); - SIVAL(buffer.data, 0, (printer->attributes & - PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS)); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRINTKEEPPRINTEDJOBS, - REG_DWORD, - buffer.data, - buffer.length); - - switch (printer->attributes & 0x3) { - case 0: - spooling = SPOOL_REGVAL_PRINTWHILESPOOLING; - break; - case 1: - spooling = SPOOL_REGVAL_PRINTAFTERSPOOLED; - break; - case 2: - spooling = SPOOL_REGVAL_PRINTDIRECT; - break; - default: - spooling = "unknown"; - } - push_reg_sz(mem_ctx, &buffer, spooling); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_PRINTSPOOLING, - REG_SZ, - buffer.data, - buffer.length); - } - - push_reg_sz(mem_ctx, &buffer, global_myname()); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_SHORTSERVERNAME, - REG_SZ, - buffer.data, - buffer.length); - - dnsdomname = get_mydnsfullname(); - if (dnsdomname != NULL && dnsdomname[0] != '\0') { - longname = talloc_strdup(mem_ctx, dnsdomname); - } else { - longname = talloc_strdup(mem_ctx, global_myname()); - } - if (longname == NULL) { - result = WERR_NOMEM; - goto done; - } - - push_reg_sz(mem_ctx, &buffer, longname); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_SERVERNAME, - REG_SZ, - buffer.data, - buffer.length); - - uncname = talloc_asprintf(mem_ctx, "\\\\%s\\%s", - global_myname(), printer->sharename); - push_reg_sz(mem_ctx, &buffer, uncname); - winreg_set_printer_dataex(mem_ctx, - server_info, - msg_ctx, - printer->sharename, - SPOOL_DSSPOOLER_KEY, - SPOOL_REG_UNCNAME, - REG_SZ, - buffer.data, - buffer.length); - -done: - return result; -} - -/******************************************************************** - * Called by spoolss_api_setprinter - * when updating a printer description. - ********************************************************************/ - -static WERROR update_printer(struct pipes_struct *p, - struct policy_handle *handle, - struct spoolss_SetPrinterInfoCtr *info_ctr, - struct spoolss_DeviceMode *devmode) -{ - uint32_t printer_mask = SPOOLSS_PRINTER_INFO_ALL; - struct spoolss_SetPrinterInfo2 *printer = info_ctr->info.info2; - struct spoolss_PrinterInfo2 *old_printer; - struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); - int snum; - WERROR result = WERR_OK; - TALLOC_CTX *tmp_ctx; - - DEBUG(8,("update_printer\n")); - - tmp_ctx = talloc_new(p->mem_ctx); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - if (!Printer) { - result = WERR_BADFID; - goto done; - } - - if (!get_printer_snum(p, handle, &snum, NULL)) { - result = WERR_BADFID; - goto done; - } - - result = winreg_get_printer(tmp_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - &old_printer); - if (!W_ERROR_IS_OK(result)) { - result = WERR_BADFID; - goto done; - } - - /* Do sanity check on the requested changes for Samba */ - if (!check_printer_ok(tmp_ctx, printer, snum)) { - result = WERR_INVALID_PARAM; - goto done; - } - - /* FIXME!!! If the driver has changed we really should verify that - it is installed before doing much else --jerry */ - - /* Check calling user has permission to update printer description */ - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("update_printer: printer property change denied by handle\n")); - result = WERR_ACCESS_DENIED; - goto done; - } - - /* Call addprinter hook */ - /* Check changes to see if this is really needed */ - - if (*lp_addprinter_cmd() && - (!strequal(printer->drivername, old_printer->drivername) || - !strequal(printer->comment, old_printer->comment) || - !strequal(printer->portname, old_printer->portname) || - !strequal(printer->location, old_printer->location)) ) - { - /* add_printer_hook() will call reload_services() */ - if (!add_printer_hook(tmp_ctx, p->server_info->security_token, - printer, p->client_id->addr, - p->msg_ctx)) { - result = WERR_ACCESS_DENIED; - goto done; - } - } - - update_dsspooler(tmp_ctx, - get_server_info_system(), - p->msg_ctx, - snum, - printer, - old_printer); - - printer_mask &= ~SPOOLSS_PRINTER_INFO_SECDESC; - - if (devmode == NULL) { - printer_mask &= ~SPOOLSS_PRINTER_INFO_DEVMODE; - } - result = winreg_update_printer(tmp_ctx, - get_server_info_system(), - p->msg_ctx, - printer->sharename, - printer_mask, - printer, - devmode, - NULL); - -done: - talloc_free(tmp_ctx); - - return result; -} - -/**************************************************************************** -****************************************************************************/ -static WERROR publish_or_unpublish_printer(struct pipes_struct *p, - struct policy_handle *handle, - struct spoolss_SetPrinterInfo7 *info7) -{ -#ifdef HAVE_ADS - struct spoolss_PrinterInfo2 *pinfo2 = NULL; - WERROR result; - int snum; - struct printer_handle *Printer; - - if ( lp_security() != SEC_ADS ) { - return WERR_UNKNOWN_LEVEL; - } - - Printer = find_printer_index_by_hnd(p, handle); - - DEBUG(5,("publish_or_unpublish_printer, action = %d\n",info7->action)); - - if (!Printer) - return WERR_BADFID; - - if (!get_printer_snum(p, handle, &snum, NULL)) - return WERR_BADFID; - - result = winreg_get_printer(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_servicename(snum), - &pinfo2); - if (!W_ERROR_IS_OK(result)) { - return WERR_BADFID; - } - - nt_printer_publish(pinfo2, - get_server_info_system(), - p->msg_ctx, - pinfo2, - info7->action); - - TALLOC_FREE(pinfo2); - return WERR_OK; -#else - return WERR_UNKNOWN_LEVEL; -#endif -} - -/******************************************************************** - ********************************************************************/ - -static WERROR update_printer_devmode(struct pipes_struct *p, - struct policy_handle *handle, - struct spoolss_DeviceMode *devmode) -{ - int snum; - struct printer_handle *Printer = find_printer_index_by_hnd(p, handle); - uint32_t info2_mask = SPOOLSS_PRINTER_INFO_DEVMODE; - - DEBUG(8,("update_printer_devmode\n")); - - if (!Printer) { - return WERR_BADFID; - } - - if (!get_printer_snum(p, handle, &snum, NULL)) { - return WERR_BADFID; - } - - /* Check calling user has permission to update printer description */ - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("update_printer: printer property change denied by handle\n")); - return WERR_ACCESS_DENIED; - } - - return winreg_update_printer(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - info2_mask, - NULL, - devmode, - NULL); -} - - -/**************************************************************** - _spoolss_SetPrinter -****************************************************************/ - -WERROR _spoolss_SetPrinter(struct pipes_struct *p, - struct spoolss_SetPrinter *r) -{ - WERROR result; - - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - if (!Printer) { - DEBUG(2,("_spoolss_SetPrinter: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - /* check the level */ - switch (r->in.info_ctr->level) { - case 0: - return control_printer(r->in.handle, r->in.command, p); - case 2: - result = update_printer(p, r->in.handle, - r->in.info_ctr, - r->in.devmode_ctr->devmode); - if (!W_ERROR_IS_OK(result)) - return result; - if (r->in.secdesc_ctr->sd) - result = update_printer_sec(r->in.handle, p, - r->in.secdesc_ctr); - return result; - case 3: - return update_printer_sec(r->in.handle, p, - r->in.secdesc_ctr); - case 7: - return publish_or_unpublish_printer(p, r->in.handle, - r->in.info_ctr->info.info7); - case 8: - return update_printer_devmode(p, r->in.handle, - r->in.devmode_ctr->devmode); - default: - return WERR_UNKNOWN_LEVEL; - } -} - -/**************************************************************** - _spoolss_FindClosePrinterNotify -****************************************************************/ - -WERROR _spoolss_FindClosePrinterNotify(struct pipes_struct *p, - struct spoolss_FindClosePrinterNotify *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - if (!Printer) { - DEBUG(2,("_spoolss_FindClosePrinterNotify: " - "Invalid handle (%s:%u:%u)\n", OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (Printer->notify.cli_chan != NULL && - Printer->notify.cli_chan->active_connections > 0) { - int snum = -1; - - if (Printer->printer_type == SPLHND_PRINTER) { - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - } - - srv_spoolss_replycloseprinter(snum, Printer); - } - - Printer->notify.flags=0; - Printer->notify.options=0; - Printer->notify.localmachine[0]='\0'; - Printer->notify.printerlocal=0; - TALLOC_FREE(Printer->notify.option); - - return WERR_OK; -} - -/**************************************************************** - _spoolss_AddJob -****************************************************************/ - -WERROR _spoolss_AddJob(struct pipes_struct *p, - struct spoolss_AddJob *r) -{ - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - /* this is what a NT server returns for AddJob. AddJob must fail on - * non-local printers */ - - if (r->in.level != 1) { - return WERR_UNKNOWN_LEVEL; - } - - return WERR_INVALID_PARAM; -} - -/**************************************************************************** -fill_job_info1 -****************************************************************************/ - -static WERROR fill_job_info1(TALLOC_CTX *mem_ctx, - struct spoolss_JobInfo1 *r, - const print_queue_struct *queue, - int position, int snum, - struct spoolss_PrinterInfo2 *pinfo2) -{ - struct tm *t; - - t = gmtime(&queue->time); - - r->job_id = queue->job; - - r->printer_name = talloc_strdup(mem_ctx, lp_servicename(snum)); - W_ERROR_HAVE_NO_MEMORY(r->printer_name); - r->server_name = talloc_strdup(mem_ctx, pinfo2->servername); - W_ERROR_HAVE_NO_MEMORY(r->server_name); - r->user_name = talloc_strdup(mem_ctx, queue->fs_user); - W_ERROR_HAVE_NO_MEMORY(r->user_name); - r->document_name = talloc_strdup(mem_ctx, queue->fs_file); - W_ERROR_HAVE_NO_MEMORY(r->document_name); - r->data_type = talloc_strdup(mem_ctx, "RAW"); - W_ERROR_HAVE_NO_MEMORY(r->data_type); - r->text_status = talloc_strdup(mem_ctx, ""); - W_ERROR_HAVE_NO_MEMORY(r->text_status); - - r->status = nt_printj_status(queue->status); - r->priority = queue->priority; - r->position = position; - r->total_pages = queue->page_count; - r->pages_printed = 0; /* ??? */ - - init_systemtime(&r->submitted, t); - - return WERR_OK; -} - -/**************************************************************************** -fill_job_info2 -****************************************************************************/ - -static WERROR fill_job_info2(TALLOC_CTX *mem_ctx, - struct spoolss_JobInfo2 *r, - const print_queue_struct *queue, - int position, int snum, - struct spoolss_PrinterInfo2 *pinfo2, - struct spoolss_DeviceMode *devmode) -{ - struct tm *t; - - t = gmtime(&queue->time); - - r->job_id = queue->job; - - r->printer_name = talloc_strdup(mem_ctx, lp_servicename(snum)); - W_ERROR_HAVE_NO_MEMORY(r->printer_name); - r->server_name = talloc_strdup(mem_ctx, pinfo2->servername); - W_ERROR_HAVE_NO_MEMORY(r->server_name); - r->user_name = talloc_strdup(mem_ctx, queue->fs_user); - W_ERROR_HAVE_NO_MEMORY(r->user_name); - r->document_name = talloc_strdup(mem_ctx, queue->fs_file); - W_ERROR_HAVE_NO_MEMORY(r->document_name); - r->notify_name = talloc_strdup(mem_ctx, queue->fs_user); - W_ERROR_HAVE_NO_MEMORY(r->notify_name); - r->data_type = talloc_strdup(mem_ctx, "RAW"); - W_ERROR_HAVE_NO_MEMORY(r->data_type); - r->print_processor = talloc_strdup(mem_ctx, "winprint"); - W_ERROR_HAVE_NO_MEMORY(r->print_processor); - r->parameters = talloc_strdup(mem_ctx, ""); - W_ERROR_HAVE_NO_MEMORY(r->parameters); - r->driver_name = talloc_strdup(mem_ctx, pinfo2->drivername); - W_ERROR_HAVE_NO_MEMORY(r->driver_name); - - r->devmode = devmode; - - r->text_status = talloc_strdup(mem_ctx, ""); - W_ERROR_HAVE_NO_MEMORY(r->text_status); - - r->secdesc = NULL; - - r->status = nt_printj_status(queue->status); - r->priority = queue->priority; - r->position = position; - r->start_time = 0; - r->until_time = 0; - r->total_pages = queue->page_count; - r->size = queue->size; - init_systemtime(&r->submitted, t); - r->time = 0; - r->pages_printed = 0; /* ??? */ - - return WERR_OK; -} - -/**************************************************************************** -fill_job_info3 -****************************************************************************/ - -static WERROR fill_job_info3(TALLOC_CTX *mem_ctx, - struct spoolss_JobInfo3 *r, - const print_queue_struct *queue, - const print_queue_struct *next_queue, - int position, int snum, - struct spoolss_PrinterInfo2 *pinfo2) -{ - r->job_id = queue->job; - r->next_job_id = 0; - if (next_queue) { - r->next_job_id = next_queue->job; - } - r->reserved = 0; - - return WERR_OK; -} - -/**************************************************************************** - Enumjobs at level 1. -****************************************************************************/ - -static WERROR enumjobs_level1(TALLOC_CTX *mem_ctx, - const print_queue_struct *queue, - uint32_t num_queues, int snum, - struct spoolss_PrinterInfo2 *pinfo2, - union spoolss_JobInfo **info_p, - uint32_t *count) -{ - union spoolss_JobInfo *info; - int i; - WERROR result = WERR_OK; - - info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues); - W_ERROR_HAVE_NO_MEMORY(info); - - *count = num_queues; - - for (i=0; i<*count; i++) { - result = fill_job_info1(info, - &info[i].info1, - &queue[i], - i, - snum, - pinfo2); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - } - - out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - *count = 0; - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/**************************************************************************** - Enumjobs at level 2. -****************************************************************************/ - -static WERROR enumjobs_level2(TALLOC_CTX *mem_ctx, - const print_queue_struct *queue, - uint32_t num_queues, int snum, - struct spoolss_PrinterInfo2 *pinfo2, - union spoolss_JobInfo **info_p, - uint32_t *count) -{ - union spoolss_JobInfo *info; - int i; - WERROR result = WERR_OK; - - info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues); - W_ERROR_HAVE_NO_MEMORY(info); - - *count = num_queues; - - for (i=0; i<*count; i++) { - struct spoolss_DeviceMode *devmode; - - result = spoolss_create_default_devmode(info, - pinfo2->printername, - &devmode); - if (!W_ERROR_IS_OK(result)) { - DEBUG(3, ("Can't proceed w/o a devmode!")); - goto out; - } - - result = fill_job_info2(info, - &info[i].info2, - &queue[i], - i, - snum, - pinfo2, - devmode); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - } - - out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - *count = 0; - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/**************************************************************************** - Enumjobs at level 3. -****************************************************************************/ - -static WERROR enumjobs_level3(TALLOC_CTX *mem_ctx, - const print_queue_struct *queue, - uint32_t num_queues, int snum, - struct spoolss_PrinterInfo2 *pinfo2, - union spoolss_JobInfo **info_p, - uint32_t *count) -{ - union spoolss_JobInfo *info; - int i; - WERROR result = WERR_OK; - - info = TALLOC_ARRAY(mem_ctx, union spoolss_JobInfo, num_queues); - W_ERROR_HAVE_NO_MEMORY(info); - - *count = num_queues; - - for (i=0; i<*count; i++) { - const print_queue_struct *next_queue = NULL; - - if (i+1 < *count) { - next_queue = &queue[i+1]; - } - - result = fill_job_info3(info, - &info[i].info3, - &queue[i], - next_queue, - i, - snum, - pinfo2); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - } - - out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - *count = 0; - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/**************************************************************** - _spoolss_EnumJobs -****************************************************************/ - -WERROR _spoolss_EnumJobs(struct pipes_struct *p, - struct spoolss_EnumJobs *r) -{ - WERROR result; - struct spoolss_PrinterInfo2 *pinfo2 = NULL; - int snum; - print_status_struct prt_status; - print_queue_struct *queue = NULL; - uint32_t count; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(4,("_spoolss_EnumJobs\n")); - - *r->out.needed = 0; - *r->out.count = 0; - *r->out.info = NULL; - - /* lookup the printer snum and tdb entry */ - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - result = winreg_get_printer(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - &pinfo2); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - count = print_queue_status(p->msg_ctx, snum, &queue, &prt_status); - DEBUGADD(4,("count:[%d], status:[%d], [%s]\n", - count, prt_status.status, prt_status.message)); - - if (count == 0) { - SAFE_FREE(queue); - TALLOC_FREE(pinfo2); - return WERR_OK; - } - - switch (r->in.level) { - case 1: - result = enumjobs_level1(p->mem_ctx, queue, count, snum, - pinfo2, r->out.info, r->out.count); - break; - case 2: - result = enumjobs_level2(p->mem_ctx, queue, count, snum, - pinfo2, r->out.info, r->out.count); - break; - case 3: - result = enumjobs_level3(p->mem_ctx, queue, count, snum, - pinfo2, r->out.info, r->out.count); - break; - default: - result = WERR_UNKNOWN_LEVEL; - break; - } - - SAFE_FREE(queue); - TALLOC_FREE(pinfo2); - - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumJobs, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************** - _spoolss_ScheduleJob -****************************************************************/ - -WERROR _spoolss_ScheduleJob(struct pipes_struct *p, - struct spoolss_ScheduleJob *r) -{ - return WERR_OK; -} - -/**************************************************************** -****************************************************************/ - -static WERROR spoolss_setjob_1(TALLOC_CTX *mem_ctx, - struct messaging_context *msg_ctx, - const char *printer_name, - uint32_t job_id, - struct spoolss_SetJobInfo1 *r) -{ - char *old_doc_name; - - if (!print_job_get_name(mem_ctx, printer_name, job_id, &old_doc_name)) { - return WERR_BADFID; - } - - if (strequal(old_doc_name, r->document_name)) { - return WERR_OK; - } - - if (!print_job_set_name(server_event_context(), msg_ctx, - printer_name, job_id, r->document_name)) { - return WERR_BADFID; - } - - return WERR_OK; -} - -/**************************************************************** - _spoolss_SetJob -****************************************************************/ - -WERROR _spoolss_SetJob(struct pipes_struct *p, - struct spoolss_SetJob *r) -{ - const struct auth_serversupplied_info *server_info = p->server_info; - int snum; - WERROR errcode = WERR_BADFUNC; - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - if (!print_job_exists(lp_const_servicename(snum), r->in.job_id)) { - return WERR_INVALID_PRINTER_NAME; - } - - switch (r->in.command) { - case SPOOLSS_JOB_CONTROL_CANCEL: - case SPOOLSS_JOB_CONTROL_DELETE: - errcode = print_job_delete(server_info, p->msg_ctx, - snum, r->in.job_id); - if (W_ERROR_EQUAL(errcode, WERR_PRINTER_HAS_JOBS_QUEUED)) { - errcode = WERR_OK; - } - break; - case SPOOLSS_JOB_CONTROL_PAUSE: - if (print_job_pause(server_info, p->msg_ctx, - snum, r->in.job_id, &errcode)) { - errcode = WERR_OK; - } - break; - case SPOOLSS_JOB_CONTROL_RESTART: - case SPOOLSS_JOB_CONTROL_RESUME: - if (print_job_resume(server_info, p->msg_ctx, - snum, r->in.job_id, &errcode)) { - errcode = WERR_OK; - } - break; - case 0: - errcode = WERR_OK; - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - if (!W_ERROR_IS_OK(errcode)) { - return errcode; - } - - if (r->in.ctr == NULL) { - return errcode; - } - - switch (r->in.ctr->level) { - case 1: - errcode = spoolss_setjob_1(p->mem_ctx, p->msg_ctx, - lp_const_servicename(snum), - r->in.job_id, - r->in.ctr->info.info1); - break; - case 2: - case 3: - case 4: - default: - return WERR_UNKNOWN_LEVEL; - } - - return errcode; -} - -/**************************************************************************** - Enumerates all printer drivers by level and architecture. -****************************************************************************/ - -static WERROR enumprinterdrivers_level_by_architecture(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *servername, - const char *architecture, - uint32_t level, - union spoolss_DriverInfo **info_p, - uint32_t *count_p) -{ - int i; - uint32_t version; - struct spoolss_DriverInfo8 *driver; - union spoolss_DriverInfo *info = NULL; - uint32_t count = 0; - WERROR result = WERR_OK; - uint32_t num_drivers; - const char **drivers; - - *count_p = 0; - *info_p = NULL; - - for (version=0; versionin.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(4,("_spoolss_EnumPrinterDrivers\n")); - - *r->out.needed = 0; - *r->out.count = 0; - *r->out.info = NULL; - - cservername = canon_servername(r->in.server); - - if (!is_myname_or_ipaddr(cservername)) { - return WERR_UNKNOWN_PRINTER_DRIVER; - } - - result = enumprinterdrivers_level(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - cservername, - r->in.environment, - r->in.level, - r->out.info, - r->out.count); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumPrinterDrivers, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************** - _spoolss_EnumForms -****************************************************************/ - -WERROR _spoolss_EnumForms(struct pipes_struct *p, - struct spoolss_EnumForms *r) -{ - WERROR result; - - *r->out.count = 0; - *r->out.needed = 0; - *r->out.info = NULL; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0) ) { - return WERR_INVALID_PARAM; - } - - DEBUG(4,("_spoolss_EnumForms\n")); - DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered)); - DEBUGADD(5,("Info level [%d]\n", r->in.level)); - - switch (r->in.level) { - case 1: - result = winreg_printer_enumforms1(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->out.count, - r->out.info); - break; - default: - result = WERR_UNKNOWN_LEVEL; - break; - } - - if (!W_ERROR_IS_OK(result)) { - return result; - } - - if (*r->out.count == 0) { - return WERR_NO_MORE_ITEMS; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumForms, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************** - _spoolss_GetForm -****************************************************************/ - -WERROR _spoolss_GetForm(struct pipes_struct *p, - struct spoolss_GetForm *r) -{ - WERROR result; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(4,("_spoolss_GetForm\n")); - DEBUGADD(5,("Offered buffer size [%d]\n", r->in.offered)); - DEBUGADD(5,("Info level [%d]\n", r->in.level)); - - switch (r->in.level) { - case 1: - result = winreg_printer_getform1(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->in.form_name, - &r->out.info->info1); - break; - default: - result = WERR_UNKNOWN_LEVEL; - break; - } - - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(r->out.info); - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_FormInfo, - r->out.info, r->in.level); - r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************************** -****************************************************************************/ - -static WERROR fill_port_1(TALLOC_CTX *mem_ctx, - struct spoolss_PortInfo1 *r, - const char *name) -{ - r->port_name = talloc_strdup(mem_ctx, name); - W_ERROR_HAVE_NO_MEMORY(r->port_name); - - return WERR_OK; -} - -/**************************************************************************** - TODO: This probably needs distinguish between TCP/IP and Local ports - somehow. -****************************************************************************/ - -static WERROR fill_port_2(TALLOC_CTX *mem_ctx, - struct spoolss_PortInfo2 *r, - const char *name) -{ - r->port_name = talloc_strdup(mem_ctx, name); - W_ERROR_HAVE_NO_MEMORY(r->port_name); - - r->monitor_name = talloc_strdup(mem_ctx, "Local Monitor"); - W_ERROR_HAVE_NO_MEMORY(r->monitor_name); - - r->description = talloc_strdup(mem_ctx, SPL_LOCAL_PORT); - W_ERROR_HAVE_NO_MEMORY(r->description); - - r->port_type = SPOOLSS_PORT_TYPE_WRITE; - r->reserved = 0; - - return WERR_OK; -} - - -/**************************************************************************** - wrapper around the enumer ports command -****************************************************************************/ - -static WERROR enumports_hook(TALLOC_CTX *ctx, int *count, char ***lines) -{ - char *cmd = lp_enumports_cmd(); - char **qlines = NULL; - char *command = NULL; - int numlines; - int ret; - int fd; - - *count = 0; - *lines = NULL; - - /* if no hook then just fill in the default port */ - - if ( !*cmd ) { - if (!(qlines = TALLOC_ARRAY( NULL, char*, 2 ))) { - return WERR_NOMEM; - } - if (!(qlines[0] = talloc_strdup(qlines, SAMBA_PRINTER_PORT_NAME ))) { - TALLOC_FREE(qlines); - return WERR_NOMEM; - } - qlines[1] = NULL; - numlines = 1; - } - else { - /* we have a valid enumport command */ - - command = talloc_asprintf(ctx, "%s \"%d\"", cmd, 1); - if (!command) { - return WERR_NOMEM; - } - - DEBUG(10,("Running [%s]\n", command)); - ret = smbrun(command, &fd); - DEBUG(10,("Returned [%d]\n", ret)); - TALLOC_FREE(command); - if (ret != 0) { - if (fd != -1) { - close(fd); - } - return WERR_ACCESS_DENIED; - } - - numlines = 0; - qlines = fd_lines_load(fd, &numlines, 0, NULL); - DEBUGADD(10,("Lines returned = [%d]\n", numlines)); - close(fd); - } - - *count = numlines; - *lines = qlines; - - return WERR_OK; -} - -/**************************************************************************** - enumports level 1. -****************************************************************************/ - -static WERROR enumports_level_1(TALLOC_CTX *mem_ctx, - union spoolss_PortInfo **info_p, - uint32_t *count) -{ - union spoolss_PortInfo *info = NULL; - int i=0; - WERROR result = WERR_OK; - char **qlines = NULL; - int numlines = 0; - - result = enumports_hook(talloc_tos(), &numlines, &qlines ); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - if (numlines) { - info = TALLOC_ARRAY(mem_ctx, union spoolss_PortInfo, numlines); - if (!info) { - DEBUG(10,("Returning WERR_NOMEM\n")); - result = WERR_NOMEM; - goto out; - } - - for (i=0; iin.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(4,("_spoolss_EnumPorts\n")); - - *r->out.count = 0; - *r->out.needed = 0; - *r->out.info = NULL; - - switch (r->in.level) { - case 1: - result = enumports_level_1(p->mem_ctx, r->out.info, - r->out.count); - break; - case 2: - result = enumports_level_2(p->mem_ctx, r->out.info, - r->out.count); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumPorts, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************************** -****************************************************************************/ - -static WERROR spoolss_addprinterex_level_2(struct pipes_struct *p, - const char *server, - struct spoolss_SetPrinterInfoCtr *info_ctr, - struct spoolss_DeviceMode *devmode, - struct security_descriptor *secdesc, - struct spoolss_UserLevelCtr *user_ctr, - struct policy_handle *handle) -{ - struct spoolss_SetPrinterInfo2 *info2 = info_ctr->info.info2; - uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ALL; - int snum; - WERROR err = WERR_OK; - - /* samba does not have a concept of local, non-shared printers yet, so - * make sure we always setup sharename - gd */ - if ((info2->sharename == NULL || info2->sharename[0] == '\0') && - (info2->printername != NULL && info2->printername[0] != '\0')) { - DEBUG(5, ("spoolss_addprinterex_level_2: " - "no sharename has been set, setting printername %s as sharename\n", - info2->printername)); - info2->sharename = info2->printername; - } - - /* check to see if the printer already exists */ - if ((snum = print_queue_snum(info2->sharename)) != -1) { - DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n", - info2->sharename)); - return WERR_PRINTER_ALREADY_EXISTS; - } - - if (!lp_force_printername(GLOBAL_SECTION_SNUM)) { - if ((snum = print_queue_snum(info2->printername)) != -1) { - DEBUG(5, ("spoolss_addprinterex_level_2: Attempted to add a printer named [%s] when one already existed!\n", - info2->printername)); - return WERR_PRINTER_ALREADY_EXISTS; - } - } - - /* validate printer info struct */ - if (!info2->printername || strlen(info2->printername) == 0) { - return WERR_INVALID_PRINTER_NAME; - } - if (!info2->portname || strlen(info2->portname) == 0) { - return WERR_UNKNOWN_PORT; - } - if (!info2->drivername || strlen(info2->drivername) == 0) { - return WERR_UNKNOWN_PRINTER_DRIVER; - } - if (!info2->printprocessor || strlen(info2->printprocessor) == 0) { - return WERR_UNKNOWN_PRINTPROCESSOR; - } - - /* FIXME!!! smbd should check to see if the driver is installed before - trying to add a printer like this --jerry */ - - if (*lp_addprinter_cmd() ) { - if ( !add_printer_hook(p->mem_ctx, p->server_info->security_token, - info2, p->client_id->addr, - p->msg_ctx) ) { - return WERR_ACCESS_DENIED; - } - } else { - DEBUG(0,("spoolss_addprinterex_level_2: add printer for printer %s called and no" - "smb.conf parameter \"addprinter command\" is defined. This" - "parameter must exist for this call to succeed\n", - info2->sharename )); - } - - if ((snum = print_queue_snum(info2->sharename)) == -1) { - return WERR_ACCESS_DENIED; - } - - /* you must be a printer admin to add a new printer */ - if (!print_access_check(p->server_info, - p->msg_ctx, - snum, - PRINTER_ACCESS_ADMINISTER)) { - return WERR_ACCESS_DENIED; - } - - /* - * Do sanity check on the requested changes for Samba. - */ - - if (!check_printer_ok(p->mem_ctx, info2, snum)) { - return WERR_INVALID_PARAM; - } - - if (devmode == NULL) { - info2_mask = ~SPOOLSS_PRINTER_INFO_DEVMODE; - } - - update_dsspooler(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - 0, - info2, - NULL); - - err = winreg_update_printer(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - info2->sharename, - info2_mask, - info2, - devmode, - secdesc); - if (!W_ERROR_IS_OK(err)) { - return err; - } - - err = open_printer_hnd(p, handle, info2->printername, PRINTER_ACCESS_ADMINISTER); - if (!W_ERROR_IS_OK(err)) { - /* Handle open failed - remove addition. */ - ZERO_STRUCTP(handle); - return err; - } - - return WERR_OK; -} - -/**************************************************************** - _spoolss_AddPrinterEx -****************************************************************/ - -WERROR _spoolss_AddPrinterEx(struct pipes_struct *p, - struct spoolss_AddPrinterEx *r) -{ - switch (r->in.info_ctr->level) { - case 1: - /* we don't handle yet */ - /* but I know what to do ... */ - return WERR_UNKNOWN_LEVEL; - case 2: - return spoolss_addprinterex_level_2(p, r->in.server, - r->in.info_ctr, - r->in.devmode_ctr->devmode, - r->in.secdesc_ctr->sd, - r->in.userlevel_ctr, - r->out.handle); - default: - return WERR_UNKNOWN_LEVEL; - } -} - -/**************************************************************** - _spoolss_AddPrinter -****************************************************************/ - -WERROR _spoolss_AddPrinter(struct pipes_struct *p, - struct spoolss_AddPrinter *r) -{ - struct spoolss_AddPrinterEx a; - struct spoolss_UserLevelCtr userlevel_ctr; - - ZERO_STRUCT(userlevel_ctr); - - userlevel_ctr.level = 1; - - a.in.server = r->in.server; - a.in.info_ctr = r->in.info_ctr; - a.in.devmode_ctr = r->in.devmode_ctr; - a.in.secdesc_ctr = r->in.secdesc_ctr; - a.in.userlevel_ctr = &userlevel_ctr; - a.out.handle = r->out.handle; - - return _spoolss_AddPrinterEx(p, &a); -} - -/**************************************************************** - _spoolss_AddPrinterDriverEx -****************************************************************/ - -WERROR _spoolss_AddPrinterDriverEx(struct pipes_struct *p, - struct spoolss_AddPrinterDriverEx *r) -{ - WERROR err = WERR_OK; - const char *driver_name = NULL; - uint32_t version; - const char *fn; - - switch (p->opnum) { - case NDR_SPOOLSS_ADDPRINTERDRIVER: - fn = "_spoolss_AddPrinterDriver"; - break; - case NDR_SPOOLSS_ADDPRINTERDRIVEREX: - fn = "_spoolss_AddPrinterDriverEx"; - break; - default: - return WERR_INVALID_PARAM; - } - - /* - * we only support the semantics of AddPrinterDriver() - * i.e. only copy files that are newer than existing ones - */ - - if (r->in.flags == 0) { - return WERR_INVALID_PARAM; - } - - if (r->in.flags != APD_COPY_NEW_FILES) { - return WERR_ACCESS_DENIED; - } - - /* FIXME */ - if (r->in.info_ctr->level != 3 && r->in.info_ctr->level != 6) { - /* Clever hack from Martin Zielinski - * to allow downgrade from level 8 (Vista). - */ - DEBUG(0,("%s: level %d not yet implemented\n", fn, - r->in.info_ctr->level)); - return WERR_UNKNOWN_LEVEL; - } - - DEBUG(5,("Cleaning driver's information\n")); - err = clean_up_driver_struct(p->mem_ctx, p, r->in.info_ctr); - if (!W_ERROR_IS_OK(err)) - goto done; - - DEBUG(5,("Moving driver to final destination\n")); - if( !W_ERROR_IS_OK(err = move_driver_to_download_area(p, r->in.info_ctr, - &err)) ) { - goto done; - } - - err = winreg_add_driver(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - r->in.info_ctr, - &driver_name, - &version); - if (!W_ERROR_IS_OK(err)) { - goto done; - } - - /* - * I think this is where he DrvUpgradePrinter() hook would be - * be called in a driver's interface DLL on a Windows NT 4.0/2k - * server. Right now, we just need to send ourselves a message - * to update each printer bound to this driver. --jerry - */ - - if (!srv_spoolss_drv_upgrade_printer(driver_name, p->msg_ctx)) { - DEBUG(0,("%s: Failed to send message about upgrading driver [%s]!\n", - fn, driver_name)); - } - -done: - return err; -} - -/**************************************************************** - _spoolss_AddPrinterDriver -****************************************************************/ - -WERROR _spoolss_AddPrinterDriver(struct pipes_struct *p, - struct spoolss_AddPrinterDriver *r) -{ - struct spoolss_AddPrinterDriverEx a; - - switch (r->in.info_ctr->level) { - case 2: - case 3: - case 4: - case 5: - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - a.in.servername = r->in.servername; - a.in.info_ctr = r->in.info_ctr; - a.in.flags = APD_COPY_NEW_FILES; - - return _spoolss_AddPrinterDriverEx(p, &a); -} - -/**************************************************************************** -****************************************************************************/ - -struct _spoolss_paths { - int type; - const char *share; - const char *dir; -}; - -enum { SPOOLSS_DRIVER_PATH, SPOOLSS_PRTPROCS_PATH }; - -static const struct _spoolss_paths spoolss_paths[]= { - { SPOOLSS_DRIVER_PATH, "print$", "DRIVERS" }, - { SPOOLSS_PRTPROCS_PATH, "prnproc$", "PRTPROCS" } -}; - -static WERROR compose_spoolss_server_path(TALLOC_CTX *mem_ctx, - const char *servername, - const char *environment, - int component, - char **path) -{ - const char *pservername = NULL; - const char *long_archi = SPOOLSS_ARCHITECTURE_NT_X86; - const char *short_archi; - - *path = NULL; - - /* environment may be empty */ - if (environment && strlen(environment)) { - long_archi = environment; - } - - /* servername may be empty */ - if (servername && strlen(servername)) { - pservername = canon_servername(servername); - - if (!is_myname_or_ipaddr(pservername)) { - return WERR_INVALID_PARAM; - } - } - - if (!(short_archi = get_short_archi(long_archi))) { - return WERR_INVALID_ENVIRONMENT; - } - - switch (component) { - case SPOOLSS_PRTPROCS_PATH: - case SPOOLSS_DRIVER_PATH: - if (pservername) { - *path = talloc_asprintf(mem_ctx, - "\\\\%s\\%s\\%s", - pservername, - spoolss_paths[component].share, - short_archi); - } else { - *path = talloc_asprintf(mem_ctx, "%s\\%s\\%s", - SPOOLSS_DEFAULT_SERVER_PATH, - spoolss_paths[component].dir, - short_archi); - } - break; - default: - return WERR_INVALID_PARAM; - } - - if (!*path) { - return WERR_NOMEM; - } - - return WERR_OK; -} - -/**************************************************************************** -****************************************************************************/ - -static WERROR getprinterdriverdir_level_1(TALLOC_CTX *mem_ctx, - const char *servername, - const char *environment, - struct spoolss_DriverDirectoryInfo1 *r) -{ - WERROR werr; - char *path = NULL; - - werr = compose_spoolss_server_path(mem_ctx, - servername, - environment, - SPOOLSS_DRIVER_PATH, - &path); - if (!W_ERROR_IS_OK(werr)) { - return werr; - } - - DEBUG(4,("printer driver directory: [%s]\n", path)); - - r->directory_name = path; - - return WERR_OK; -} - -/**************************************************************** - _spoolss_GetPrinterDriverDirectory -****************************************************************/ - -WERROR _spoolss_GetPrinterDriverDirectory(struct pipes_struct *p, - struct spoolss_GetPrinterDriverDirectory *r) -{ - WERROR werror; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(5,("_spoolss_GetPrinterDriverDirectory: level %d\n", - r->in.level)); - - *r->out.needed = 0; - - /* r->in.level is ignored */ - - werror = getprinterdriverdir_level_1(p->mem_ctx, - r->in.server, - r->in.environment, - &r->out.info->info1); - if (!W_ERROR_IS_OK(werror)) { - TALLOC_FREE(r->out.info); - return werror; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_DriverDirectoryInfo, - r->out.info, r->in.level); - r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************** - _spoolss_EnumPrinterData -****************************************************************/ - -WERROR _spoolss_EnumPrinterData(struct pipes_struct *p, - struct spoolss_EnumPrinterData *r) -{ - WERROR result; - struct spoolss_EnumPrinterDataEx r2; - uint32_t count; - struct spoolss_PrinterEnumValues *info, *val = NULL; - uint32_t needed; - - r2.in.handle = r->in.handle; - r2.in.key_name = "PrinterDriverData"; - r2.in.offered = 0; - r2.out.count = &count; - r2.out.info = &info; - r2.out.needed = &needed; - - result = _spoolss_EnumPrinterDataEx(p, &r2); - if (W_ERROR_EQUAL(result, WERR_MORE_DATA)) { - r2.in.offered = needed; - result = _spoolss_EnumPrinterDataEx(p, &r2); - } - if (!W_ERROR_IS_OK(result)) { - return result; - } - - /* - * The NT machine wants to know the biggest size of value and data - * - * cf: MSDN EnumPrinterData remark section - */ - - if (!r->in.value_offered && !r->in.data_offered) { - uint32_t biggest_valuesize = 0; - uint32_t biggest_datasize = 0; - int i, name_length; - - DEBUGADD(6,("Activating NT mega-hack to find sizes\n")); - - for (i=0; i biggest_valuesize) { - biggest_valuesize = name_length; - } - - if (info[i].data_length > biggest_datasize) { - biggest_datasize = info[i].data_length; - } - - DEBUG(6,("current values: [%d], [%d]\n", biggest_valuesize, - biggest_datasize)); - } - - /* the value is an UNICODE string but real_value_size is the length - in bytes including the trailing 0 */ - - *r->out.value_needed = 2 * (1 + biggest_valuesize); - *r->out.data_needed = biggest_datasize; - - DEBUG(6,("final values: [%d], [%d]\n", - *r->out.value_needed, *r->out.data_needed)); - - return WERR_OK; - } - - if (r->in.enum_index < count) { - val = &info[r->in.enum_index]; - } - - if (val == NULL) { - /* out_value should default to "" or else NT4 has - problems unmarshalling the response */ - - if (r->in.value_offered) { - *r->out.value_needed = 1; - r->out.value_name = talloc_strdup(r, ""); - if (!r->out.value_name) { - return WERR_NOMEM; - } - } else { - r->out.value_name = NULL; - *r->out.value_needed = 0; - } - - /* the data is counted in bytes */ - - *r->out.data_needed = r->in.data_offered; - - result = WERR_NO_MORE_ITEMS; - } else { - /* - * the value is: - * - counted in bytes in the request - * - counted in UNICODE chars in the max reply - * - counted in bytes in the real size - * - * take a pause *before* coding not *during* coding - */ - - /* name */ - if (r->in.value_offered) { - r->out.value_name = talloc_strdup(r, val->value_name); - if (!r->out.value_name) { - return WERR_NOMEM; - } - *r->out.value_needed = val->value_name_len; - } else { - r->out.value_name = NULL; - *r->out.value_needed = 0; - } - - /* type */ - - *r->out.type = val->type; - - /* data - counted in bytes */ - - /* - * See the section "Dynamically Typed Query Parameters" - * in MS-RPRN. - */ - - if (r->out.data && val->data && val->data->data && - val->data_length && r->in.data_offered) { - memcpy(r->out.data, val->data->data, - MIN(val->data_length,r->in.data_offered)); - } - - *r->out.data_needed = val->data_length; - - result = WERR_OK; - } - - return result; -} - -/**************************************************************** - _spoolss_SetPrinterData -****************************************************************/ - -WERROR _spoolss_SetPrinterData(struct pipes_struct *p, - struct spoolss_SetPrinterData *r) -{ - struct spoolss_SetPrinterDataEx r2; - - r2.in.handle = r->in.handle; - r2.in.key_name = "PrinterDriverData"; - r2.in.value_name = r->in.value_name; - r2.in.type = r->in.type; - r2.in.data = r->in.data; - r2.in.offered = r->in.offered; - - return _spoolss_SetPrinterDataEx(p, &r2); -} - -/**************************************************************** - _spoolss_ResetPrinter -****************************************************************/ - -WERROR _spoolss_ResetPrinter(struct pipes_struct *p, - struct spoolss_ResetPrinter *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - int snum; - - DEBUG(5,("_spoolss_ResetPrinter\n")); - - /* - * All we do is to check to see if the handle and queue is valid. - * This call really doesn't mean anything to us because we only - * support RAW printing. --jerry - */ - - if (!Printer) { - DEBUG(2,("_spoolss_ResetPrinter: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) - return WERR_BADFID; - - - /* blindly return success */ - return WERR_OK; -} - -/**************************************************************** - _spoolss_DeletePrinterData -****************************************************************/ - -WERROR _spoolss_DeletePrinterData(struct pipes_struct *p, - struct spoolss_DeletePrinterData *r) -{ - struct spoolss_DeletePrinterDataEx r2; - - r2.in.handle = r->in.handle; - r2.in.key_name = "PrinterDriverData"; - r2.in.value_name = r->in.value_name; - - return _spoolss_DeletePrinterDataEx(p, &r2); -} - -/**************************************************************** - _spoolss_AddForm -****************************************************************/ - -WERROR _spoolss_AddForm(struct pipes_struct *p, - struct spoolss_AddForm *r) -{ - struct spoolss_AddFormInfo1 *form = r->in.info.info1; - int snum = -1; - WERROR status = WERR_OK; - - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - DEBUG(5,("_spoolss_AddForm\n")); - - if (!Printer) { - DEBUG(2,("_spoolss_AddForm: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, - and not a printer admin, then fail */ - - if ((p->server_info->utok.uid != sec_initial_uid()) && - !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && - !token_contains_name_in_list(uidtoname(p->server_info->utok.uid), - p->server_info->info3->base.domain.string, - NULL, - p->server_info->security_token, - lp_printer_admin(snum))) { - DEBUG(2,("_spoolss_Addform: denied by insufficient permissions.\n")); - return WERR_ACCESS_DENIED; - } - - switch (form->flags) { - case SPOOLSS_FORM_USER: - case SPOOLSS_FORM_BUILTIN: - case SPOOLSS_FORM_PRINTER: - break; - default: - return WERR_INVALID_PARAM; - } - - status = winreg_printer_addform1(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - form); - if (!W_ERROR_IS_OK(status)) { - return status; - } - - /* - * ChangeID must always be set if this is a printer - */ - if (Printer->printer_type == SPLHND_PRINTER) { - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - status = winreg_printer_update_changeid(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum)); - if (!W_ERROR_IS_OK(status)) { - return status; - } - } - - return status; -} - -/**************************************************************** - _spoolss_DeleteForm -****************************************************************/ - -WERROR _spoolss_DeleteForm(struct pipes_struct *p, - struct spoolss_DeleteForm *r) -{ - const char *form_name = r->in.form_name; - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - int snum = -1; - WERROR status = WERR_OK; - - DEBUG(5,("_spoolss_DeleteForm\n")); - - if (!Printer) { - DEBUG(2,("_spoolss_DeleteForm: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if ((p->server_info->utok.uid != sec_initial_uid()) && - !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && - !token_contains_name_in_list(uidtoname(p->server_info->utok.uid), - p->server_info->info3->base.domain.string, - NULL, - p->server_info->security_token, - lp_printer_admin(snum))) { - DEBUG(2,("_spoolss_DeleteForm: denied by insufficient permissions.\n")); - return WERR_ACCESS_DENIED; - } - - status = winreg_printer_deleteform1(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - form_name); - if (!W_ERROR_IS_OK(status)) { - return status; - } - - /* - * ChangeID must always be set if this is a printer - */ - if (Printer->printer_type == SPLHND_PRINTER) { - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - status = winreg_printer_update_changeid(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum)); - if (!W_ERROR_IS_OK(status)) { - return status; - } - } - - return status; -} - -/**************************************************************** - _spoolss_SetForm -****************************************************************/ - -WERROR _spoolss_SetForm(struct pipes_struct *p, - struct spoolss_SetForm *r) -{ - struct spoolss_AddFormInfo1 *form = r->in.info.info1; - const char *form_name = r->in.form_name; - int snum = -1; - WERROR status = WERR_OK; - - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - DEBUG(5,("_spoolss_SetForm\n")); - - if (!Printer) { - DEBUG(2,("_spoolss_SetForm: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - /* if the user is not root, doesn't have SE_PRINT_OPERATOR privilege, - and not a printer admin, then fail */ - - if ((p->server_info->utok.uid != sec_initial_uid()) && - !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_PRINT_OPERATOR) && - !token_contains_name_in_list(uidtoname(p->server_info->utok.uid), - p->server_info->info3->base.domain.string, - NULL, - p->server_info->security_token, - lp_printer_admin(snum))) { - DEBUG(2,("_spoolss_Setform: denied by insufficient permissions.\n")); - return WERR_ACCESS_DENIED; - } - - status = winreg_printer_setform1(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - form_name, - form); - if (!W_ERROR_IS_OK(status)) { - return status; - } - - /* - * ChangeID must always be set if this is a printer - */ - if (Printer->printer_type == SPLHND_PRINTER) { - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - status = winreg_printer_update_changeid(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum)); - if (!W_ERROR_IS_OK(status)) { - return status; - } - } - - return status; -} - -/**************************************************************************** - fill_print_processor1 -****************************************************************************/ - -static WERROR fill_print_processor1(TALLOC_CTX *mem_ctx, - struct spoolss_PrintProcessorInfo1 *r, - const char *print_processor_name) -{ - r->print_processor_name = talloc_strdup(mem_ctx, print_processor_name); - W_ERROR_HAVE_NO_MEMORY(r->print_processor_name); - - return WERR_OK; -} - -/**************************************************************************** - enumprintprocessors level 1. -****************************************************************************/ - -static WERROR enumprintprocessors_level_1(TALLOC_CTX *mem_ctx, - union spoolss_PrintProcessorInfo **info_p, - uint32_t *count) -{ - union spoolss_PrintProcessorInfo *info; - WERROR result; - - info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcessorInfo, 1); - W_ERROR_HAVE_NO_MEMORY(info); - - *count = 1; - - result = fill_print_processor1(info, &info[0].info1, "winprint"); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - *count = 0; - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/**************************************************************** - _spoolss_EnumPrintProcessors -****************************************************************/ - -WERROR _spoolss_EnumPrintProcessors(struct pipes_struct *p, - struct spoolss_EnumPrintProcessors *r) -{ - WERROR result; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(5,("_spoolss_EnumPrintProcessors\n")); - - /* - * Enumerate the print processors ... - * - * Just reply with "winprint", to keep NT happy - * and I can use my nice printer checker. - */ - - *r->out.count = 0; - *r->out.needed = 0; - *r->out.info = NULL; - - if (!get_short_archi(r->in.environment)) { - return WERR_INVALID_ENVIRONMENT; - } - - switch (r->in.level) { - case 1: - result = enumprintprocessors_level_1(p->mem_ctx, r->out.info, - r->out.count); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumPrintProcessors, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************************** - fill_printprocdatatype1 -****************************************************************************/ - -static WERROR fill_printprocdatatype1(TALLOC_CTX *mem_ctx, - struct spoolss_PrintProcDataTypesInfo1 *r, - const char *name_array) -{ - r->name_array = talloc_strdup(mem_ctx, name_array); - W_ERROR_HAVE_NO_MEMORY(r->name_array); - - return WERR_OK; -} - -/**************************************************************************** - enumprintprocdatatypes level 1. -****************************************************************************/ - -static WERROR enumprintprocdatatypes_level_1(TALLOC_CTX *mem_ctx, - union spoolss_PrintProcDataTypesInfo **info_p, - uint32_t *count) -{ - WERROR result; - union spoolss_PrintProcDataTypesInfo *info; - - info = TALLOC_ARRAY(mem_ctx, union spoolss_PrintProcDataTypesInfo, 1); - W_ERROR_HAVE_NO_MEMORY(info); - - *count = 1; - - result = fill_printprocdatatype1(info, &info[0].info1, "RAW"); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - *count = 0; - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/**************************************************************** - _spoolss_EnumPrintProcDataTypes -****************************************************************/ - -WERROR _spoolss_EnumPrintProcDataTypes(struct pipes_struct *p, - struct spoolss_EnumPrintProcDataTypes *r) -{ - WERROR result; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(5,("_spoolss_EnumPrintProcDataTypes\n")); - - *r->out.count = 0; - *r->out.needed = 0; - *r->out.info = NULL; - - if (r->in.print_processor_name == NULL || - !strequal(r->in.print_processor_name, "winprint")) { - return WERR_UNKNOWN_PRINTPROCESSOR; - } - - switch (r->in.level) { - case 1: - result = enumprintprocdatatypes_level_1(p->mem_ctx, r->out.info, - r->out.count); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumPrintProcDataTypes, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************************** - fill_monitor_1 -****************************************************************************/ - -static WERROR fill_monitor_1(TALLOC_CTX *mem_ctx, - struct spoolss_MonitorInfo1 *r, - const char *monitor_name) -{ - r->monitor_name = talloc_strdup(mem_ctx, monitor_name); - W_ERROR_HAVE_NO_MEMORY(r->monitor_name); - - return WERR_OK; -} - -/**************************************************************************** - fill_monitor_2 -****************************************************************************/ - -static WERROR fill_monitor_2(TALLOC_CTX *mem_ctx, - struct spoolss_MonitorInfo2 *r, - const char *monitor_name, - const char *environment, - const char *dll_name) -{ - r->monitor_name = talloc_strdup(mem_ctx, monitor_name); - W_ERROR_HAVE_NO_MEMORY(r->monitor_name); - r->environment = talloc_strdup(mem_ctx, environment); - W_ERROR_HAVE_NO_MEMORY(r->environment); - r->dll_name = talloc_strdup(mem_ctx, dll_name); - W_ERROR_HAVE_NO_MEMORY(r->dll_name); - - return WERR_OK; -} - -/**************************************************************************** - enumprintmonitors level 1. -****************************************************************************/ - -static WERROR enumprintmonitors_level_1(TALLOC_CTX *mem_ctx, - union spoolss_MonitorInfo **info_p, - uint32_t *count) -{ - union spoolss_MonitorInfo *info; - WERROR result = WERR_OK; - - info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2); - W_ERROR_HAVE_NO_MEMORY(info); - - *count = 2; - - result = fill_monitor_1(info, &info[0].info1, - SPL_LOCAL_PORT); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - result = fill_monitor_1(info, &info[1].info1, - SPL_TCPIP_PORT); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - -out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - *count = 0; - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/**************************************************************************** - enumprintmonitors level 2. -****************************************************************************/ - -static WERROR enumprintmonitors_level_2(TALLOC_CTX *mem_ctx, - union spoolss_MonitorInfo **info_p, - uint32_t *count) -{ - union spoolss_MonitorInfo *info; - WERROR result = WERR_OK; - - info = TALLOC_ARRAY(mem_ctx, union spoolss_MonitorInfo, 2); - W_ERROR_HAVE_NO_MEMORY(info); - - *count = 2; - - result = fill_monitor_2(info, &info[0].info2, - SPL_LOCAL_PORT, - "Windows NT X86", /* FIXME */ - "localmon.dll"); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - - result = fill_monitor_2(info, &info[1].info2, - SPL_TCPIP_PORT, - "Windows NT X86", /* FIXME */ - "tcpmon.dll"); - if (!W_ERROR_IS_OK(result)) { - goto out; - } - -out: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(info); - *count = 0; - return result; - } - - *info_p = info; - - return WERR_OK; -} - -/**************************************************************** - _spoolss_EnumMonitors -****************************************************************/ - -WERROR _spoolss_EnumMonitors(struct pipes_struct *p, - struct spoolss_EnumMonitors *r) -{ - WERROR result; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(5,("_spoolss_EnumMonitors\n")); - - /* - * Enumerate the print monitors ... - * - * Just reply with "Local Port", to keep NT happy - * and I can use my nice printer checker. - */ - - *r->out.count = 0; - *r->out.needed = 0; - *r->out.info = NULL; - - switch (r->in.level) { - case 1: - result = enumprintmonitors_level_1(p->mem_ctx, r->out.info, - r->out.count); - break; - case 2: - result = enumprintmonitors_level_2(p->mem_ctx, r->out.info, - r->out.count); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION_ARRAY(p->mem_ctx, - spoolss_EnumMonitors, - *r->out.info, r->in.level, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, 0); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************************** -****************************************************************************/ - -static WERROR getjob_level_1(TALLOC_CTX *mem_ctx, - const print_queue_struct *queue, - int count, int snum, - struct spoolss_PrinterInfo2 *pinfo2, - uint32_t jobid, - struct spoolss_JobInfo1 *r) -{ - int i = 0; - bool found = false; - - for (i=0; iprintername, - &devmode); - if (!W_ERROR_IS_OK(result)) { - DEBUG(3, ("Can't proceed w/o a devmode!")); - return result; - } - } - - return fill_job_info2(mem_ctx, - r, - &queue[i], - i, - snum, - pinfo2, - devmode); -} - -/**************************************************************** - _spoolss_GetJob -****************************************************************/ - -WERROR _spoolss_GetJob(struct pipes_struct *p, - struct spoolss_GetJob *r) -{ - WERROR result = WERR_OK; - struct spoolss_PrinterInfo2 *pinfo2 = NULL; - int snum; - int count; - print_queue_struct *queue = NULL; - print_status_struct prt_status; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(5,("_spoolss_GetJob\n")); - - *r->out.needed = 0; - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - result = winreg_get_printer(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - &pinfo2); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - count = print_queue_status(p->msg_ctx, snum, &queue, &prt_status); - - DEBUGADD(4,("count:[%d], prt_status:[%d], [%s]\n", - count, prt_status.status, prt_status.message)); - - switch (r->in.level) { - case 1: - result = getjob_level_1(p->mem_ctx, - queue, count, snum, pinfo2, - r->in.job_id, &r->out.info->info1); - break; - case 2: - result = getjob_level_2(p->mem_ctx, - queue, count, snum, pinfo2, - r->in.job_id, &r->out.info->info2); - break; - default: - result = WERR_UNKNOWN_LEVEL; - break; - } - - SAFE_FREE(queue); - TALLOC_FREE(pinfo2); - - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(r->out.info); - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_JobInfo, r->out.info, - r->in.level); - r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/**************************************************************** - _spoolss_GetPrinterDataEx -****************************************************************/ - -WERROR _spoolss_GetPrinterDataEx(struct pipes_struct *p, - struct spoolss_GetPrinterDataEx *r) -{ - - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - const char *printer; - int snum = 0; - WERROR result = WERR_OK; - DATA_BLOB blob; - enum winreg_Type val_type; - uint8_t *val_data; - uint32_t val_size; - - - DEBUG(4,("_spoolss_GetPrinterDataEx\n")); - - DEBUG(10, ("_spoolss_GetPrinterDataEx: key => [%s], value => [%s]\n", - r->in.key_name, r->in.value_name)); - - /* in case of problem, return some default values */ - - *r->out.needed = 0; - *r->out.type = REG_NONE; - - if (!Printer) { - DEBUG(2,("_spoolss_GetPrinterDataEx: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - result = WERR_BADFID; - goto done; - } - - /* Is the handle to a printer or to the server? */ - - if (Printer->printer_type == SPLHND_SERVER) { - - union spoolss_PrinterData data; - - result = getprinterdata_printer_server(p->mem_ctx, - r->in.value_name, - r->out.type, - &data); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - result = push_spoolss_PrinterData(p->mem_ctx, &blob, - *r->out.type, &data); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = blob.length; - - if (r->in.offered >= *r->out.needed) { - memcpy(r->out.data, blob.data, blob.length); - } - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA); - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - printer = lp_const_servicename(snum); - - /* check to see if the keyname is valid */ - if (!strlen(r->in.key_name)) { - return WERR_INVALID_PARAM; - } - - /* XP sends this and wants the ChangeID value from PRINTER_INFO_0 */ - if (strequal(r->in.key_name, SPOOL_PRINTERDATA_KEY) && - strequal(r->in.value_name, "ChangeId")) { - *r->out.type = REG_DWORD; - *r->out.needed = 4; - if (r->in.offered >= *r->out.needed) { - uint32_t changeid = 0; - - result = winreg_printer_get_changeid(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer, - &changeid); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - SIVAL(r->out.data, 0, changeid); - result = WERR_OK; - } - goto done; - } - - result = winreg_get_printer_dataex(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer, - r->in.key_name, - r->in.value_name, - &val_type, - &val_data, - &val_size); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = val_size; - *r->out.type = val_type; - - if (r->in.offered >= *r->out.needed) { - memcpy(r->out.data, val_data, val_size); - } - - done: - /* retain type when returning WERR_MORE_DATA */ - r->out.data = SPOOLSS_BUFFER_OK(r->out.data, r->out.data); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA); -} - -/**************************************************************** - _spoolss_SetPrinterDataEx -****************************************************************/ - -WERROR _spoolss_SetPrinterDataEx(struct pipes_struct *p, - struct spoolss_SetPrinterDataEx *r) -{ - struct spoolss_PrinterInfo2 *pinfo2 = NULL; - int snum = 0; - WERROR result = WERR_OK; - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - char *oid_string; - - DEBUG(4,("_spoolss_SetPrinterDataEx\n")); - - /* From MSDN documentation of SetPrinterDataEx: pass request to - SetPrinterData if key is "PrinterDriverData" */ - - if (!Printer) { - DEBUG(2,("_spoolss_SetPrinterDataEx: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (Printer->printer_type == SPLHND_SERVER) { - DEBUG(10,("_spoolss_SetPrinterDataEx: " - "Not implemented for server handles yet\n")); - return WERR_INVALID_PARAM; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - /* - * Access check : NT returns "access denied" if you make a - * SetPrinterData call without the necessary privildge. - * we were originally returning OK if nothing changed - * which made Win2k issue **a lot** of SetPrinterData - * when connecting to a printer --jerry - */ - - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("_spoolss_SetPrinterDataEx: " - "change denied by handle access permissions\n")); - return WERR_ACCESS_DENIED; - } - - result = winreg_get_printer(Printer, - get_server_info_system(), - p->msg_ctx, - lp_servicename(snum), - &pinfo2); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - /* check for OID in valuename */ - - oid_string = strchr(r->in.value_name, ','); - if (oid_string) { - *oid_string = '\0'; - oid_string++; - } - - /* save the registry data */ - - result = winreg_set_printer_dataex(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - pinfo2->sharename, - r->in.key_name, - r->in.value_name, - r->in.type, - r->in.data, - r->in.offered); - - if (W_ERROR_IS_OK(result)) { - /* save the OID if one was specified */ - if (oid_string) { - char *str = talloc_asprintf(p->mem_ctx, "%s\\%s", - r->in.key_name, SPOOL_OID_KEY); - if (!str) { - result = WERR_NOMEM; - goto done; - } - - /* - * I'm not checking the status here on purpose. Don't know - * if this is right, but I'm returning the status from the - * previous set_printer_dataex() call. I have no idea if - * this is right. --jerry - */ - winreg_set_printer_dataex(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - pinfo2->sharename, - str, - r->in.value_name, - REG_SZ, - (uint8_t *) oid_string, - strlen(oid_string) + 1); - } - - result = winreg_printer_update_changeid(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum)); - - } - -done: - talloc_free(pinfo2); - return result; -} - -/**************************************************************** - _spoolss_DeletePrinterDataEx -****************************************************************/ - -WERROR _spoolss_DeletePrinterDataEx(struct pipes_struct *p, - struct spoolss_DeletePrinterDataEx *r) -{ - const char *printer; - int snum=0; - WERROR status = WERR_OK; - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - - DEBUG(5,("_spoolss_DeletePrinterDataEx\n")); - - if (!Printer) { - DEBUG(2,("_spoolss_DeletePrinterDataEx: " - "Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("_spoolss_DeletePrinterDataEx: " - "printer properties change denied by handle\n")); - return WERR_ACCESS_DENIED; - } - - if (!r->in.value_name || !r->in.key_name) { - return WERR_NOMEM; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - printer = lp_const_servicename(snum); - - status = winreg_delete_printer_dataex(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer, - r->in.key_name, - r->in.value_name); - if (W_ERROR_IS_OK(status)) { - status = winreg_printer_update_changeid(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer); - } - - return status; -} - -/**************************************************************** - _spoolss_EnumPrinterKey -****************************************************************/ - -WERROR _spoolss_EnumPrinterKey(struct pipes_struct *p, - struct spoolss_EnumPrinterKey *r) -{ - uint32_t num_keys; - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - int snum = 0; - WERROR result = WERR_BADFILE; - const char **array = NULL; - DATA_BLOB blob; - - DEBUG(4,("_spoolss_EnumPrinterKey\n")); - - if (!Printer) { - DEBUG(2,("_spoolss_EnumPrinterKey: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - result = winreg_enum_printer_key(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - r->in.key_name, - &num_keys, - &array); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - if (!push_reg_multi_sz(p->mem_ctx, &blob, array)) { - result = WERR_NOMEM; - goto done; - } - - *r->out._ndr_size = r->in.offered / 2; - *r->out.needed = blob.length; - - if (r->in.offered < *r->out.needed) { - result = WERR_MORE_DATA; - } else { - result = WERR_OK; - r->out.key_buffer->string_array = array; - } - - done: - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(array); - if (!W_ERROR_EQUAL(result, WERR_MORE_DATA)) { - *r->out.needed = 0; - } - } - - return result; -} - -/**************************************************************** - _spoolss_DeletePrinterKey -****************************************************************/ - -WERROR _spoolss_DeletePrinterKey(struct pipes_struct *p, - struct spoolss_DeletePrinterKey *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - int snum=0; - WERROR status; - const char *printer; - - DEBUG(5,("_spoolss_DeletePrinterKey\n")); - - if (!Printer) { - DEBUG(2,("_spoolss_DeletePrinterKey: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - /* if keyname == NULL, return error */ - if ( !r->in.key_name ) - return WERR_INVALID_PARAM; - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - if (Printer->access_granted != PRINTER_ACCESS_ADMINISTER) { - DEBUG(3, ("_spoolss_DeletePrinterKey: " - "printer properties change denied by handle\n")); - return WERR_ACCESS_DENIED; - } - - printer = lp_const_servicename(snum); - - /* delete the key and all subkeys */ - status = winreg_delete_printer_key(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer, - r->in.key_name); - if (W_ERROR_IS_OK(status)) { - status = winreg_printer_update_changeid(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - printer); - } - - return status; -} - -/**************************************************************** - _spoolss_EnumPrinterDataEx -****************************************************************/ - -WERROR _spoolss_EnumPrinterDataEx(struct pipes_struct *p, - struct spoolss_EnumPrinterDataEx *r) -{ - uint32_t count = 0; - struct spoolss_PrinterEnumValues *info = NULL; - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - int snum; - WERROR result; - - DEBUG(4,("_spoolss_EnumPrinterDataEx\n")); - - *r->out.count = 0; - *r->out.needed = 0; - *r->out.info = NULL; - - if (!Printer) { - DEBUG(2,("_spoolss_EnumPrinterDataEx: Invalid handle (%s:%u:%u1<).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - /* - * first check for a keyname of NULL or "". Win2k seems to send - * this a lot and we should send back WERR_INVALID_PARAM - * no need to spend time looking up the printer in this case. - * --jerry - */ - - if (!strlen(r->in.key_name)) { - result = WERR_INVALID_PARAM; - goto done; - } - - if (!get_printer_snum(p, r->in.handle, &snum, NULL)) { - return WERR_BADFID; - } - - /* now look for a match on the key name */ - result = winreg_enum_printer_dataex(p->mem_ctx, - get_server_info_system(), - p->msg_ctx, - lp_const_servicename(snum), - r->in.key_name, - &count, - &info); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - -#if 0 /* FIXME - gd */ - /* housekeeping information in the reply */ - - /* Fix from Martin Zielinski - ensure - * the hand marshalled container size is a multiple - * of 4 bytes for RPC alignment. - */ - - if (needed % 4) { - needed += 4-(needed % 4); - } -#endif - *r->out.count = count; - *r->out.info = info; - - done: - if (!W_ERROR_IS_OK(result)) { - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_ARRAY(p->mem_ctx, - spoolss_EnumPrinterDataEx, - *r->out.info, - *r->out.count); - *r->out.info = SPOOLSS_BUFFER_OK(*r->out.info, NULL); - *r->out.count = SPOOLSS_BUFFER_OK(*r->out.count, *r->out.count); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_MORE_DATA); -} - -/**************************************************************************** -****************************************************************************/ - -static WERROR getprintprocessordirectory_level_1(TALLOC_CTX *mem_ctx, - const char *servername, - const char *environment, - struct spoolss_PrintProcessorDirectoryInfo1 *r) -{ - WERROR werr; - char *path = NULL; - - werr = compose_spoolss_server_path(mem_ctx, - servername, - environment, - SPOOLSS_PRTPROCS_PATH, - &path); - if (!W_ERROR_IS_OK(werr)) { - return werr; - } - - DEBUG(4,("print processor directory: [%s]\n", path)); - - r->directory_name = path; - - return WERR_OK; -} - -/**************************************************************** - _spoolss_GetPrintProcessorDirectory -****************************************************************/ - -WERROR _spoolss_GetPrintProcessorDirectory(struct pipes_struct *p, - struct spoolss_GetPrintProcessorDirectory *r) -{ - WERROR result; - char *prnproc_share = NULL; - bool prnproc_share_exists = false; - int snum; - - /* that's an [in out] buffer */ - - if (!r->in.buffer && (r->in.offered != 0)) { - return WERR_INVALID_PARAM; - } - - DEBUG(5,("_spoolss_GetPrintProcessorDirectory: level %d\n", - r->in.level)); - - *r->out.needed = 0; - - /* r->in.level is ignored */ - - /* We always should reply with a local print processor directory so that - * users are not forced to have a [prnproc$] share on the Samba spoolss - * server, if users decide to do so, lets announce it though - Guenther */ - - snum = find_service(talloc_tos(), "prnproc$", &prnproc_share); - if (!prnproc_share) { - return WERR_NOMEM; - } - if (snum != -1) { - prnproc_share_exists = true; - } - - result = getprintprocessordirectory_level_1(p->mem_ctx, - prnproc_share_exists ? r->in.server : NULL, - r->in.environment, - &r->out.info->info1); - if (!W_ERROR_IS_OK(result)) { - TALLOC_FREE(r->out.info); - return result; - } - - *r->out.needed = SPOOLSS_BUFFER_UNION(spoolss_PrintProcessorDirectoryInfo, - r->out.info, r->in.level); - r->out.info = SPOOLSS_BUFFER_OK(r->out.info, NULL); - - return SPOOLSS_BUFFER_OK(WERR_OK, WERR_INSUFFICIENT_BUFFER); -} - -/******************************************************************* - ********************************************************************/ - -static bool push_monitorui_buf(TALLOC_CTX *mem_ctx, DATA_BLOB *buf, - const char *dllname) -{ - enum ndr_err_code ndr_err; - struct spoolss_MonitorUi ui; - - ui.dll_name = dllname; - - ndr_err = ndr_push_struct_blob(buf, mem_ctx, &ui, - (ndr_push_flags_fn_t)ndr_push_spoolss_MonitorUi); - if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { - NDR_PRINT_DEBUG(spoolss_MonitorUi, &ui); - } - return NDR_ERR_CODE_IS_SUCCESS(ndr_err); -} - -/******************************************************************* - Streams the monitor UI DLL name in UNICODE -*******************************************************************/ - -static WERROR xcvtcp_monitorui(TALLOC_CTX *mem_ctx, - struct security_token *token, DATA_BLOB *in, - DATA_BLOB *out, uint32_t *needed) -{ - const char *dllname = "tcpmonui.dll"; - - *needed = (strlen(dllname)+1) * 2; - - if (out->length < *needed) { - return WERR_INSUFFICIENT_BUFFER; - } - - if (!push_monitorui_buf(mem_ctx, out, dllname)) { - return WERR_NOMEM; - } - - return WERR_OK; -} - -/******************************************************************* - ********************************************************************/ - -static bool pull_port_data_1(TALLOC_CTX *mem_ctx, - struct spoolss_PortData1 *port1, - const DATA_BLOB *buf) -{ - enum ndr_err_code ndr_err; - ndr_err = ndr_pull_struct_blob(buf, mem_ctx, port1, - (ndr_pull_flags_fn_t)ndr_pull_spoolss_PortData1); - if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { - NDR_PRINT_DEBUG(spoolss_PortData1, port1); - } - return NDR_ERR_CODE_IS_SUCCESS(ndr_err); -} - -/******************************************************************* - ********************************************************************/ - -static bool pull_port_data_2(TALLOC_CTX *mem_ctx, - struct spoolss_PortData2 *port2, - const DATA_BLOB *buf) -{ - enum ndr_err_code ndr_err; - ndr_err = ndr_pull_struct_blob(buf, mem_ctx, port2, - (ndr_pull_flags_fn_t)ndr_pull_spoolss_PortData2); - if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && (DEBUGLEVEL >= 10)) { - NDR_PRINT_DEBUG(spoolss_PortData2, port2); - } - return NDR_ERR_CODE_IS_SUCCESS(ndr_err); -} - -/******************************************************************* - Create a new TCP/IP port -*******************************************************************/ - -static WERROR xcvtcp_addport(TALLOC_CTX *mem_ctx, - struct security_token *token, DATA_BLOB *in, - DATA_BLOB *out, uint32_t *needed) -{ - struct spoolss_PortData1 port1; - struct spoolss_PortData2 port2; - char *device_uri = NULL; - uint32_t version; - - const char *portname; - const char *hostaddress; - const char *queue; - uint32_t port_number; - uint32_t protocol; - - /* peek for spoolss_PortData version */ - - if (!in || (in->length < (128 + 4))) { - return WERR_GENERAL_FAILURE; - } - - version = IVAL(in->data, 128); - - switch (version) { - case 1: - ZERO_STRUCT(port1); - - if (!pull_port_data_1(mem_ctx, &port1, in)) { - return WERR_NOMEM; - } - - portname = port1.portname; - hostaddress = port1.hostaddress; - queue = port1.queue; - protocol = port1.protocol; - port_number = port1.port_number; - - break; - case 2: - ZERO_STRUCT(port2); - - if (!pull_port_data_2(mem_ctx, &port2, in)) { - return WERR_NOMEM; - } - - portname = port2.portname; - hostaddress = port2.hostaddress; - queue = port2.queue; - protocol = port2.protocol; - port_number = port2.port_number; - - break; - default: - DEBUG(1,("xcvtcp_addport: " - "unknown version of port_data: %d\n", version)); - return WERR_UNKNOWN_PORT; - } - - /* create the device URI and call the add_port_hook() */ - - switch (protocol) { - case PROTOCOL_RAWTCP_TYPE: - device_uri = talloc_asprintf(mem_ctx, - "socket://%s:%d/", hostaddress, - port_number); - break; - - case PROTOCOL_LPR_TYPE: - device_uri = talloc_asprintf(mem_ctx, - "lpr://%s/%s", hostaddress, queue ); - break; - - default: - return WERR_UNKNOWN_PORT; - } - - if (!device_uri) { - return WERR_NOMEM; - } - - return add_port_hook(mem_ctx, token, portname, device_uri); -} - -/******************************************************************* -*******************************************************************/ - -struct xcv_api_table xcvtcp_cmds[] = { - { "MonitorUI", xcvtcp_monitorui }, - { "AddPort", xcvtcp_addport}, - { NULL, NULL } -}; - -static WERROR process_xcvtcp_command(TALLOC_CTX *mem_ctx, - struct security_token *token, const char *command, - DATA_BLOB *inbuf, - DATA_BLOB *outbuf, - uint32_t *needed ) -{ - int i; - - DEBUG(10,("process_xcvtcp_command: Received command \"%s\"\n", command)); - - for ( i=0; xcvtcp_cmds[i].name; i++ ) { - if ( strcmp( command, xcvtcp_cmds[i].name ) == 0 ) - return xcvtcp_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed); - } - - return WERR_BADFUNC; -} - -/******************************************************************* -*******************************************************************/ -#if 0 /* don't support management using the "Local Port" monitor */ - -static WERROR xcvlocal_monitorui(TALLOC_CTX *mem_ctx, - struct security_token *token, DATA_BLOB *in, - DATA_BLOB *out, uint32_t *needed) -{ - const char *dllname = "localui.dll"; - - *needed = (strlen(dllname)+1) * 2; - - if (out->length < *needed) { - return WERR_INSUFFICIENT_BUFFER; - } - - if (!push_monitorui_buf(mem_ctx, out, dllname)) { - return WERR_NOMEM; - } - - return WERR_OK; -} - -/******************************************************************* -*******************************************************************/ - -struct xcv_api_table xcvlocal_cmds[] = { - { "MonitorUI", xcvlocal_monitorui }, - { NULL, NULL } -}; -#else -struct xcv_api_table xcvlocal_cmds[] = { - { NULL, NULL } -}; -#endif - - - -/******************************************************************* -*******************************************************************/ - -static WERROR process_xcvlocal_command(TALLOC_CTX *mem_ctx, - struct security_token *token, const char *command, - DATA_BLOB *inbuf, DATA_BLOB *outbuf, - uint32_t *needed) -{ - int i; - - DEBUG(10,("process_xcvlocal_command: Received command \"%s\"\n", command)); - - for ( i=0; xcvlocal_cmds[i].name; i++ ) { - if ( strcmp( command, xcvlocal_cmds[i].name ) == 0 ) - return xcvlocal_cmds[i].fn(mem_ctx, token, inbuf, outbuf, needed); - } - return WERR_BADFUNC; -} - -/**************************************************************** - _spoolss_XcvData -****************************************************************/ - -WERROR _spoolss_XcvData(struct pipes_struct *p, - struct spoolss_XcvData *r) -{ - struct printer_handle *Printer = find_printer_index_by_hnd(p, r->in.handle); - DATA_BLOB out_data = data_blob_null; - WERROR werror; - - if (!Printer) { - DEBUG(2,("_spoolss_XcvData: Invalid handle (%s:%u:%u).\n", - OUR_HANDLE(r->in.handle))); - return WERR_BADFID; - } - - /* Has to be a handle to the TCP/IP port monitor */ - - if ( !(Printer->printer_type & (SPLHND_PORTMON_LOCAL|SPLHND_PORTMON_TCP)) ) { - DEBUG(2,("_spoolss_XcvData: Call only valid for Port Monitors\n")); - return WERR_BADFID; - } - - /* requires administrative access to the server */ - - if ( !(Printer->access_granted & SERVER_ACCESS_ADMINISTER) ) { - DEBUG(2,("_spoolss_XcvData: denied by handle permissions.\n")); - return WERR_ACCESS_DENIED; - } - - /* Allocate the outgoing buffer */ - - if (r->in.out_data_size) { - out_data = data_blob_talloc_zero(p->mem_ctx, r->in.out_data_size); - if (out_data.data == NULL) { - return WERR_NOMEM; - } - } - - switch ( Printer->printer_type ) { - case SPLHND_PORTMON_TCP: - werror = process_xcvtcp_command(p->mem_ctx, - p->server_info->security_token, - r->in.function_name, - &r->in.in_data, &out_data, - r->out.needed); - break; - case SPLHND_PORTMON_LOCAL: - werror = process_xcvlocal_command(p->mem_ctx, - p->server_info->security_token, - r->in.function_name, - &r->in.in_data, &out_data, - r->out.needed); - break; - default: - werror = WERR_INVALID_PRINT_MONITOR; - } - - if (!W_ERROR_IS_OK(werror)) { - return werror; - } - - *r->out.status_code = 0; - - if (r->out.out_data && out_data.data && r->in.out_data_size && out_data.length) { - memcpy(r->out.out_data, out_data.data, - MIN(r->in.out_data_size, out_data.length)); - } - - return WERR_OK; -} - -/**************************************************************** - _spoolss_AddPrintProcessor -****************************************************************/ - -WERROR _spoolss_AddPrintProcessor(struct pipes_struct *p, - struct spoolss_AddPrintProcessor *r) -{ - /* for now, just indicate success and ignore the add. We'll - automatically set the winprint processor for printer - entries later. Used to debug the LexMark Optra S 1855 PCL - driver --jerry */ - - return WERR_OK; -} - -/**************************************************************** - _spoolss_AddPort -****************************************************************/ - -WERROR _spoolss_AddPort(struct pipes_struct *p, - struct spoolss_AddPort *r) -{ - /* do what w2k3 does */ - - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_GetPrinterDriver -****************************************************************/ - -WERROR _spoolss_GetPrinterDriver(struct pipes_struct *p, - struct spoolss_GetPrinterDriver *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_ReadPrinter -****************************************************************/ - -WERROR _spoolss_ReadPrinter(struct pipes_struct *p, - struct spoolss_ReadPrinter *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_WaitForPrinterChange -****************************************************************/ - -WERROR _spoolss_WaitForPrinterChange(struct pipes_struct *p, - struct spoolss_WaitForPrinterChange *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_ConfigurePort -****************************************************************/ - -WERROR _spoolss_ConfigurePort(struct pipes_struct *p, - struct spoolss_ConfigurePort *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_DeletePort -****************************************************************/ - -WERROR _spoolss_DeletePort(struct pipes_struct *p, - struct spoolss_DeletePort *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_CreatePrinterIC -****************************************************************/ - -WERROR _spoolss_CreatePrinterIC(struct pipes_struct *p, - struct spoolss_CreatePrinterIC *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_PlayGDIScriptOnPrinterIC -****************************************************************/ - -WERROR _spoolss_PlayGDIScriptOnPrinterIC(struct pipes_struct *p, - struct spoolss_PlayGDIScriptOnPrinterIC *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_DeletePrinterIC -****************************************************************/ - -WERROR _spoolss_DeletePrinterIC(struct pipes_struct *p, - struct spoolss_DeletePrinterIC *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_AddPrinterConnection -****************************************************************/ - -WERROR _spoolss_AddPrinterConnection(struct pipes_struct *p, - struct spoolss_AddPrinterConnection *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_DeletePrinterConnection -****************************************************************/ - -WERROR _spoolss_DeletePrinterConnection(struct pipes_struct *p, - struct spoolss_DeletePrinterConnection *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_PrinterMessageBox -****************************************************************/ - -WERROR _spoolss_PrinterMessageBox(struct pipes_struct *p, - struct spoolss_PrinterMessageBox *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_AddMonitor -****************************************************************/ - -WERROR _spoolss_AddMonitor(struct pipes_struct *p, - struct spoolss_AddMonitor *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_DeleteMonitor -****************************************************************/ - -WERROR _spoolss_DeleteMonitor(struct pipes_struct *p, - struct spoolss_DeleteMonitor *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_DeletePrintProcessor -****************************************************************/ - -WERROR _spoolss_DeletePrintProcessor(struct pipes_struct *p, - struct spoolss_DeletePrintProcessor *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_AddPrintProvidor -****************************************************************/ - -WERROR _spoolss_AddPrintProvidor(struct pipes_struct *p, - struct spoolss_AddPrintProvidor *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_DeletePrintProvidor -****************************************************************/ - -WERROR _spoolss_DeletePrintProvidor(struct pipes_struct *p, - struct spoolss_DeletePrintProvidor *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_FindFirstPrinterChangeNotification -****************************************************************/ - -WERROR _spoolss_FindFirstPrinterChangeNotification(struct pipes_struct *p, - struct spoolss_FindFirstPrinterChangeNotification *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_FindNextPrinterChangeNotification -****************************************************************/ - -WERROR _spoolss_FindNextPrinterChangeNotification(struct pipes_struct *p, - struct spoolss_FindNextPrinterChangeNotification *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_RouterFindFirstPrinterChangeNotificationOld -****************************************************************/ - -WERROR _spoolss_RouterFindFirstPrinterChangeNotificationOld(struct pipes_struct *p, - struct spoolss_RouterFindFirstPrinterChangeNotificationOld *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_ReplyOpenPrinter -****************************************************************/ - -WERROR _spoolss_ReplyOpenPrinter(struct pipes_struct *p, - struct spoolss_ReplyOpenPrinter *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_RouterReplyPrinter -****************************************************************/ - -WERROR _spoolss_RouterReplyPrinter(struct pipes_struct *p, - struct spoolss_RouterReplyPrinter *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_ReplyClosePrinter -****************************************************************/ - -WERROR _spoolss_ReplyClosePrinter(struct pipes_struct *p, - struct spoolss_ReplyClosePrinter *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_AddPortEx -****************************************************************/ - -WERROR _spoolss_AddPortEx(struct pipes_struct *p, - struct spoolss_AddPortEx *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_RouterFindFirstPrinterChangeNotification -****************************************************************/ - -WERROR _spoolss_RouterFindFirstPrinterChangeNotification(struct pipes_struct *p, - struct spoolss_RouterFindFirstPrinterChangeNotification *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_SpoolerInit -****************************************************************/ - -WERROR _spoolss_SpoolerInit(struct pipes_struct *p, - struct spoolss_SpoolerInit *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_ResetPrinterEx -****************************************************************/ - -WERROR _spoolss_ResetPrinterEx(struct pipes_struct *p, - struct spoolss_ResetPrinterEx *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_RouterReplyPrinterEx -****************************************************************/ - -WERROR _spoolss_RouterReplyPrinterEx(struct pipes_struct *p, - struct spoolss_RouterReplyPrinterEx *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_44 -****************************************************************/ - -WERROR _spoolss_44(struct pipes_struct *p, - struct spoolss_44 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_SetPort -****************************************************************/ - -WERROR _spoolss_SetPort(struct pipes_struct *p, - struct spoolss_SetPort *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_4a -****************************************************************/ - -WERROR _spoolss_4a(struct pipes_struct *p, - struct spoolss_4a *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_4b -****************************************************************/ - -WERROR _spoolss_4b(struct pipes_struct *p, - struct spoolss_4b *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_4c -****************************************************************/ - -WERROR _spoolss_4c(struct pipes_struct *p, - struct spoolss_4c *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_53 -****************************************************************/ - -WERROR _spoolss_53(struct pipes_struct *p, - struct spoolss_53 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_AddPerMachineConnection -****************************************************************/ - -WERROR _spoolss_AddPerMachineConnection(struct pipes_struct *p, - struct spoolss_AddPerMachineConnection *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_DeletePerMachineConnection -****************************************************************/ - -WERROR _spoolss_DeletePerMachineConnection(struct pipes_struct *p, - struct spoolss_DeletePerMachineConnection *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_EnumPerMachineConnections -****************************************************************/ - -WERROR _spoolss_EnumPerMachineConnections(struct pipes_struct *p, - struct spoolss_EnumPerMachineConnections *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_5a -****************************************************************/ - -WERROR _spoolss_5a(struct pipes_struct *p, - struct spoolss_5a *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_5b -****************************************************************/ - -WERROR _spoolss_5b(struct pipes_struct *p, - struct spoolss_5b *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_5c -****************************************************************/ - -WERROR _spoolss_5c(struct pipes_struct *p, - struct spoolss_5c *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_5d -****************************************************************/ - -WERROR _spoolss_5d(struct pipes_struct *p, - struct spoolss_5d *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_5e -****************************************************************/ - -WERROR _spoolss_5e(struct pipes_struct *p, - struct spoolss_5e *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_5f -****************************************************************/ - -WERROR _spoolss_5f(struct pipes_struct *p, - struct spoolss_5f *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_60 -****************************************************************/ - -WERROR _spoolss_60(struct pipes_struct *p, - struct spoolss_60 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_61 -****************************************************************/ - -WERROR _spoolss_61(struct pipes_struct *p, - struct spoolss_61 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_62 -****************************************************************/ - -WERROR _spoolss_62(struct pipes_struct *p, - struct spoolss_62 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_63 -****************************************************************/ - -WERROR _spoolss_63(struct pipes_struct *p, - struct spoolss_63 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_64 -****************************************************************/ - -WERROR _spoolss_64(struct pipes_struct *p, - struct spoolss_64 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_65 -****************************************************************/ - -WERROR _spoolss_65(struct pipes_struct *p, - struct spoolss_65 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_GetCorePrinterDrivers -****************************************************************/ - -WERROR _spoolss_GetCorePrinterDrivers(struct pipes_struct *p, - struct spoolss_GetCorePrinterDrivers *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_67 -****************************************************************/ - -WERROR _spoolss_67(struct pipes_struct *p, - struct spoolss_67 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_GetPrinterDriverPackagePath -****************************************************************/ - -WERROR _spoolss_GetPrinterDriverPackagePath(struct pipes_struct *p, - struct spoolss_GetPrinterDriverPackagePath *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_69 -****************************************************************/ - -WERROR _spoolss_69(struct pipes_struct *p, - struct spoolss_69 *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_6a -****************************************************************/ - -WERROR _spoolss_6a(struct pipes_struct *p, - struct spoolss_6a *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_6b -****************************************************************/ - -WERROR _spoolss_6b(struct pipes_struct *p, - struct spoolss_6b *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_6c -****************************************************************/ - -WERROR _spoolss_6c(struct pipes_struct *p, - struct spoolss_6c *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} - -/**************************************************************** - _spoolss_6d -****************************************************************/ - -WERROR _spoolss_6d(struct pipes_struct *p, - struct spoolss_6d *r) -{ - p->rng_fault_state = true; - return WERR_NOT_SUPPORTED; -} diff --git a/source3/rpc_server/srv_spoolss_util.c b/source3/rpc_server/srv_spoolss_util.c deleted file mode 100644 index db575746f8..0000000000 --- a/source3/rpc_server/srv_spoolss_util.c +++ /dev/null @@ -1,4249 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * SPOOLSS RPC Pipe server / winreg client routines - * - * Copyright (c) 2010 Andreas Schneider - * - * 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 . - */ - -#include "includes.h" -#include "nt_printing.h" -#include "srv_spoolss_util.h" -#include "../librpc/gen_ndr/ndr_spoolss.h" -#include "../librpc/gen_ndr/srv_winreg.h" -#include "../librpc/gen_ndr/ndr_winreg_c.h" -#include "../librpc/gen_ndr/ndr_security.h" -#include "secrets.h" -#include "rpc_server/rpc_ncacn_np.h" -#include "../libcli/security/security.h" -#include "rpc_client/cli_winreg.h" - -#define TOP_LEVEL_PRINT_KEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print" -#define TOP_LEVEL_PRINT_PRINTERS_KEY TOP_LEVEL_PRINT_KEY "\\Printers" -#define TOP_LEVEL_CONTROL_KEY "SYSTEM\\CurrentControlSet\\Control\\Print" -#define TOP_LEVEL_CONTROL_FORMS_KEY TOP_LEVEL_CONTROL_KEY "\\Forms" - -#define EMPTY_STRING "" - -#define FILL_STRING(mem_ctx, in, out) \ - do { \ - if (in && strlen(in)) { \ - out = talloc_strdup(mem_ctx, in); \ - } else { \ - out = talloc_strdup(mem_ctx, ""); \ - } \ - W_ERROR_HAVE_NO_MEMORY(out); \ - } while (0); - -#define CHECK_ERROR(result) \ - if (W_ERROR_IS_OK(result)) continue; \ - if (W_ERROR_EQUAL(result, WERR_NOT_FOUND)) result = WERR_OK; \ - if (!W_ERROR_IS_OK(result)) break - -/* FLAGS, NAME, with, height, left, top, right, bottom */ -static const struct spoolss_FormInfo1 builtin_forms1[] = { - { SPOOLSS_FORM_BUILTIN, "10x11", {0x3e030,0x44368}, {0x0,0x0,0x3e030,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "10x14", {0x3e030,0x56d10}, {0x0,0x0,0x3e030,0x56d10} }, - { SPOOLSS_FORM_BUILTIN, "11x17", {0x44368,0x696b8}, {0x0,0x0,0x44368,0x696b8} }, - { SPOOLSS_FORM_BUILTIN, "12x11", {0x4a724,0x443e1}, {0x0,0x0,0x4a724,0x443e1} }, - { SPOOLSS_FORM_BUILTIN, "15x11", {0x5d048,0x44368}, {0x0,0x0,0x5d048,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "6 3/4 Envelope", {0x167ab,0x284ec}, {0x0,0x0,0x167ab,0x284ec} }, - { SPOOLSS_FORM_BUILTIN, "9x11", {0x37cf8,0x44368}, {0x0,0x0,0x37cf8,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "A0", {0xcd528,0x122488},{0x0,0x0,0xcd528,0x122488} }, - { SPOOLSS_FORM_BUILTIN, "A1", {0x91050,0xcd528}, {0x0,0x0,0x91050,0xcd528} }, - { SPOOLSS_FORM_BUILTIN, "A2", {0x668a0,0x91050}, {0x0,0x0,0x668a0,0x91050} }, - { SPOOLSS_FORM_BUILTIN, "A3 Extra Transverse", {0x4e9d0,0x6ca48}, {0x0,0x0,0x4e9d0,0x6ca48} }, - { SPOOLSS_FORM_BUILTIN, "A3 Extra", {0x4e9d0,0x6ca48}, {0x0,0x0,0x4e9d0,0x6ca48} }, - { SPOOLSS_FORM_BUILTIN, "A3 Rotated", {0x668a0,0x48828}, {0x0,0x0,0x668a0,0x48828} }, - { SPOOLSS_FORM_BUILTIN, "A3 Transverse", {0x48828,0x668a0}, {0x0,0x0,0x48828,0x668a0} }, - { SPOOLSS_FORM_BUILTIN, "A3", {0x48828,0x668a0}, {0x0,0x0,0x48828,0x668a0} }, - { SPOOLSS_FORM_BUILTIN, "A4 Extra", {0x397c2,0x4eb16}, {0x0,0x0,0x397c2,0x4eb16} }, - { SPOOLSS_FORM_BUILTIN, "A4 Plus", {0x33450,0x50910}, {0x0,0x0,0x33450,0x50910} }, - { SPOOLSS_FORM_BUILTIN, "A4 Rotated", {0x48828,0x33450}, {0x0,0x0,0x48828,0x33450} }, - { SPOOLSS_FORM_BUILTIN, "A4 Small", {0x33450,0x48828}, {0x0,0x0,0x33450,0x48828} }, - { SPOOLSS_FORM_BUILTIN, "A4 Transverse", {0x33450,0x48828}, {0x0,0x0,0x33450,0x48828} }, - { SPOOLSS_FORM_BUILTIN, "A4", {0x33450,0x48828}, {0x0,0x0,0x33450,0x48828} }, - { SPOOLSS_FORM_BUILTIN, "A5 Extra", {0x2a7b0,0x395f8}, {0x0,0x0,0x2a7b0,0x395f8} }, - { SPOOLSS_FORM_BUILTIN, "A5 Rotated", {0x33450,0x24220}, {0x0,0x0,0x33450,0x24220} }, - { SPOOLSS_FORM_BUILTIN, "A5 Transverse", {0x24220,0x33450}, {0x0,0x0,0x24220,0x33450} }, - { SPOOLSS_FORM_BUILTIN, "A5", {0x24220,0x33450}, {0x0,0x0,0x24220,0x33450} }, - { SPOOLSS_FORM_BUILTIN, "A6 Rotated", {0x24220,0x19a28}, {0x0,0x0,0x24220,0x19a28} }, - { SPOOLSS_FORM_BUILTIN, "A6", {0x19a28,0x24220}, {0x0,0x0,0x19a28,0x24220} }, - { SPOOLSS_FORM_BUILTIN, "B4 (ISO)", {0x3d090,0x562e8}, {0x0,0x0,0x3d090,0x562e8} }, - { SPOOLSS_FORM_BUILTIN, "B4 (JIS) Rotated", {0x58de0,0x3ebe8}, {0x0,0x0,0x58de0,0x3ebe8} }, - { SPOOLSS_FORM_BUILTIN, "B4 (JIS)", {0x3ebe8,0x58de0}, {0x0,0x0,0x3ebe8,0x58de0} }, - { SPOOLSS_FORM_BUILTIN, "B5 (ISO) Extra", {0x31128,0x43620}, {0x0,0x0,0x31128,0x43620} }, - { SPOOLSS_FORM_BUILTIN, "B5 (JIS) Rotated", {0x3ebe8,0x2c6f0}, {0x0,0x0,0x3ebe8,0x2c6f0} }, - { SPOOLSS_FORM_BUILTIN, "B5 (JIS) Transverse", {0x2c6f0,0x3ebe8}, {0x0,0x0,0x2c6f0,0x3ebe8} }, - { SPOOLSS_FORM_BUILTIN, "B5 (JIS)", {0x2c6f0,0x3ebe8}, {0x0,0x0,0x2c6f0,0x3ebe8} }, - { SPOOLSS_FORM_BUILTIN, "B6 (JIS) Rotated", {0x2c6f0,0x1f400}, {0x0,0x0,0x2c6f0,0x1f400} }, - { SPOOLSS_FORM_BUILTIN, "B6 (JIS)", {0x1f400,0x2c6f0}, {0x0,0x0,0x1f400,0x2c6f0} }, - { SPOOLSS_FORM_BUILTIN, "C size sheet", {0x696b8,0x886d0}, {0x0,0x0,0x696b8,0x886d0} }, - { SPOOLSS_FORM_BUILTIN, "D size sheet", {0x886d0,0xd2d70}, {0x0,0x0,0x886d0,0xd2d70} }, - { SPOOLSS_FORM_BUILTIN, "Double Japan Postcard Rotated", {0x24220,0x30d40}, {0x0,0x0,0x24220,0x30d40} }, - { SPOOLSS_FORM_BUILTIN, "E size sheet", {0xd2d70,0x110da0},{0x0,0x0,0xd2d70,0x110da0} }, - { SPOOLSS_FORM_BUILTIN, "Envelope #10", {0x19947,0x3ae94}, {0x0,0x0,0x19947,0x3ae94} }, - { SPOOLSS_FORM_BUILTIN, "Envelope #11", {0x1be7c,0x40565}, {0x0,0x0,0x1be7c,0x40565} }, - { SPOOLSS_FORM_BUILTIN, "Envelope #12", {0x1d74a,0x44368}, {0x0,0x0,0x1d74a,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "Envelope #14", {0x1f018,0x47504}, {0x0,0x0,0x1f018,0x47504} }, - { SPOOLSS_FORM_BUILTIN, "Envelope #9", {0x18079,0x37091}, {0x0,0x0,0x18079,0x37091} }, - { SPOOLSS_FORM_BUILTIN, "Envelope B4", {0x3d090,0x562e8}, {0x0,0x0,0x3d090,0x562e8} }, - { SPOOLSS_FORM_BUILTIN, "Envelope B5", {0x2af80,0x3d090}, {0x0,0x0,0x2af80,0x3d090} }, - { SPOOLSS_FORM_BUILTIN, "Envelope B6", {0x2af80,0x1e848}, {0x0,0x0,0x2af80,0x1e848} }, - { SPOOLSS_FORM_BUILTIN, "Envelope C3", {0x4f1a0,0x6fd10}, {0x0,0x0,0x4f1a0,0x6fd10} }, - { SPOOLSS_FORM_BUILTIN, "Envelope C4", {0x37e88,0x4f1a0}, {0x0,0x0,0x37e88,0x4f1a0} }, - { SPOOLSS_FORM_BUILTIN, "Envelope C5", {0x278d0,0x37e88}, {0x0,0x0,0x278d0,0x37e88} }, - { SPOOLSS_FORM_BUILTIN, "Envelope C6", {0x1bd50,0x278d0}, {0x0,0x0,0x1bd50,0x278d0} }, - { SPOOLSS_FORM_BUILTIN, "Envelope C65", {0x1bd50,0x37e88}, {0x0,0x0,0x1bd50,0x37e88} }, - { SPOOLSS_FORM_BUILTIN, "Envelope DL", {0x1adb0,0x35b60}, {0x0,0x0,0x1adb0,0x35b60} }, - { SPOOLSS_FORM_BUILTIN, "Envelope Invite", {0x35b60,0x35b60}, {0x0,0x0,0x35b60,0x35b60} }, - { SPOOLSS_FORM_BUILTIN, "Envelope Monarch", {0x18079,0x2e824}, {0x0,0x0,0x18079,0x2e824} }, - { SPOOLSS_FORM_BUILTIN, "Envelope", {0x1adb0,0x38270}, {0x0,0x0,0x1adb0,0x38270} }, - { SPOOLSS_FORM_BUILTIN, "Executive", {0x2cf56,0x411cc}, {0x0,0x0,0x2cf56,0x411cc} }, - { SPOOLSS_FORM_BUILTIN, "Folio", {0x34b5c,0x509d8}, {0x0,0x0,0x34b5c,0x509d8} }, - { SPOOLSS_FORM_BUILTIN, "German Legal Fanfold", {0x34b5c,0x509d8}, {0x0,0x0,0x34b5c,0x509d8} }, - { SPOOLSS_FORM_BUILTIN, "German Std Fanfold", {0x34b5c,0x4a6a0}, {0x0,0x0,0x34b5c,0x4a6a0} }, - { SPOOLSS_FORM_BUILTIN, "Japan Envelope Chou #3 Rotated", {0x395f8,0x1d4c0}, {0x0,0x0,0x395f8,0x1d4c0} }, - { SPOOLSS_FORM_BUILTIN, "Japan Envelope Chou #4 Rotated", {0x320c8,0x15f90}, {0x0,0x0,0x320c8,0x15f90} }, - { SPOOLSS_FORM_BUILTIN, "Japan Envelope Kaku #2 Rotated", {0x510e0,0x3a980}, {0x0,0x0,0x510e0,0x3a980} }, - { SPOOLSS_FORM_BUILTIN, "Japan Envelope Kaku #3 Rotated", {0x43a08,0x34bc0}, {0x0,0x0,0x43a08,0x34bc0} }, - { SPOOLSS_FORM_BUILTIN, "Japan Envelope You #4 Rotated", {0x395f8,0x19a28}, {0x0,0x0,0x395f8,0x19a28} }, - { SPOOLSS_FORM_BUILTIN, "Japan Envelope You #4", {0x19a28,0x395f8}, {0x0,0x0,0x19a28,0x395f8} }, - { SPOOLSS_FORM_BUILTIN, "Japanese Double Postcard", {0x30d40,0x24220}, {0x0,0x0,0x30d40,0x24220} }, - { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Chou #3", {0x1d4c0,0x395f8}, {0x0,0x0,0x1d4c0,0x395f8} }, - { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Chou #4", {0x15f90,0x320c8}, {0x0,0x0,0x15f90,0x320c8} }, - { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Kaku #2", {0x3a980,0x510e0}, {0x0,0x0,0x3a980,0x510e0} }, - { SPOOLSS_FORM_BUILTIN, "Japanese Envelope Kaku #3", {0x34bc0,0x43a08}, {0x0,0x0,0x34bc0,0x43a08} }, - { SPOOLSS_FORM_BUILTIN, "Japanese Postcard Rotated", {0x24220,0x186a0}, {0x0,0x0,0x24220,0x186a0} }, - { SPOOLSS_FORM_BUILTIN, "Japanese Postcard", {0x186a0,0x24220}, {0x0,0x0,0x186a0,0x24220} }, - { SPOOLSS_FORM_BUILTIN, "Ledger", {0x696b8,0x44368}, {0x0,0x0,0x696b8,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "Legal Extra", {0x3ae94,0x5d048}, {0x0,0x0,0x3ae94,0x5d048} }, - { SPOOLSS_FORM_BUILTIN, "Legal", {0x34b5c,0x56d10}, {0x0,0x0,0x34b5c,0x56d10} }, - { SPOOLSS_FORM_BUILTIN, "Letter Extra Transverse", {0x3ae94,0x4a6a0}, {0x0,0x0,0x3ae94,0x4a6a0} }, - { SPOOLSS_FORM_BUILTIN, "Letter Extra", {0x3ae94,0x4a6a0}, {0x0,0x0,0x3ae94,0x4a6a0} }, - { SPOOLSS_FORM_BUILTIN, "Letter Plus", {0x34b5c,0x4eb16}, {0x0,0x0,0x34b5c,0x4eb16} }, - { SPOOLSS_FORM_BUILTIN, "Letter Rotated", {0x44368,0x34b5c}, {0x0,0x0,0x44368,0x34b5c} }, - { SPOOLSS_FORM_BUILTIN, "Letter Small", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "Letter Transverse", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "Letter", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "Note", {0x34b5c,0x44368}, {0x0,0x0,0x34b5c,0x44368} }, - { SPOOLSS_FORM_BUILTIN, "PRC 16K Rotated", {0x3f7a0,0x2de60}, {0x0,0x0,0x3f7a0,0x2de60} }, - { SPOOLSS_FORM_BUILTIN, "PRC 16K", {0x2de60,0x3f7a0}, {0x0,0x0,0x2de60,0x3f7a0} }, - { SPOOLSS_FORM_BUILTIN, "PRC 32K Rotated", {0x2cec0,0x1fbd0}, {0x0,0x0,0x2cec0,0x1fbd0} }, - { SPOOLSS_FORM_BUILTIN, "PRC 32K", {0x1fbd0,0x2cec0}, {0x0,0x0,0x1fbd0,0x2cec0} }, - { SPOOLSS_FORM_BUILTIN, "PRC 32K(Big) Rotated", {0x318f8,0x222e0}, {0x0,0x0,0x318f8,0x222e0} }, - { SPOOLSS_FORM_BUILTIN, "PRC 32K(Big)", {0x222e0,0x318f8}, {0x0,0x0,0x222e0,0x318f8} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #1 Rotated", {0x28488,0x18e70}, {0x0,0x0,0x28488,0x18e70} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #1", {0x18e70,0x28488}, {0x0,0x0,0x18e70,0x28488} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #10 Rotated", {0x6fd10,0x4f1a0}, {0x0,0x0,0x6fd10,0x4f1a0} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #10", {0x4f1a0,0x6fd10}, {0x0,0x0,0x4f1a0,0x6fd10} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #2 Rotated", {0x2af80,0x18e70}, {0x0,0x0,0x2af80,0x18e70} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #2", {0x18e70,0x2af80}, {0x0,0x0,0x18e70,0x2af80} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #3 Rotated", {0x2af80,0x1e848}, {0x0,0x0,0x2af80,0x1e848} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #3", {0x1e848,0x2af80}, {0x0,0x0,0x1e848,0x2af80} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #4 Rotated", {0x32c80,0x1adb0}, {0x0,0x0,0x32c80,0x1adb0} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #4", {0x1adb0,0x32c80}, {0x0,0x0,0x1adb0,0x32c80} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #5 Rotated", {0x35b60,0x1adb0}, {0x0,0x0,0x35b60,0x1adb0} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #5", {0x1adb0,0x35b60}, {0x0,0x0,0x1adb0,0x35b60} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #6 Rotated", {0x38270,0x1d4c0}, {0x0,0x0,0x38270,0x1d4c0} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #6", {0x1d4c0,0x38270}, {0x0,0x0,0x1d4c0,0x38270} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #7 Rotated", {0x38270,0x27100}, {0x0,0x0,0x38270,0x27100} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #7", {0x27100,0x38270}, {0x0,0x0,0x27100,0x38270} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #8 Rotated", {0x4b708,0x1d4c0}, {0x0,0x0,0x4b708,0x1d4c0} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #8", {0x1d4c0,0x4b708}, {0x0,0x0,0x1d4c0,0x4b708} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #9 Rotated", {0x4f1a0,0x37e88}, {0x0,0x0,0x4f1a0,0x37e88} }, - { SPOOLSS_FORM_BUILTIN, "PRC Envelope #9", {0x37e88,0x4f1a0}, {0x0,0x0,0x37e88,0x4f1a0} }, - { SPOOLSS_FORM_BUILTIN, "Quarto", {0x347d8,0x43238}, {0x0,0x0,0x347d8,0x43238} }, - { SPOOLSS_FORM_BUILTIN, "Reserved48", {0x1,0x1}, {0x0,0x0,0x1,0x1} }, - { SPOOLSS_FORM_BUILTIN, "Reserved49", {0x1,0x1}, {0x0,0x0,0x1,0x1} }, - { SPOOLSS_FORM_BUILTIN, "Statement", {0x221b4,0x34b5c}, {0x0,0x0,0x221b4,0x34b5c} }, - { SPOOLSS_FORM_BUILTIN, "Super A", {0x376b8,0x56ea0}, {0x0,0x0,0x376b8,0x56ea0} }, - { SPOOLSS_FORM_BUILTIN, "Super B", {0x4a768,0x76e58}, {0x0,0x0,0x4a768,0x76e58} }, - { SPOOLSS_FORM_BUILTIN, "Tabloid Extra", {0x4a6a0,0x6f9f0}, {0x0,0x0,0x4a6a0,0x6f9f0} }, - { SPOOLSS_FORM_BUILTIN, "Tabloid", {0x44368,0x696b8}, {0x0,0x0,0x44368,0x696b8} }, - { SPOOLSS_FORM_BUILTIN, "US Std Fanfold", {0x5c3e1,0x44368}, {0x0,0x0,0x5c3e1,0x44368} } -}; - -/******************************************************************** - static helper functions -********************************************************************/ - -/**************************************************************************** - Update the changeid time. -****************************************************************************/ -/** - * @internal - * - * @brief Update the ChangeID time of a printer. - * - * This is SO NASTY as some drivers need this to change, others need it - * static. This value will change every second, and I must hope that this - * is enough..... DON'T CHANGE THIS CODE WITHOUT A TEST MATRIX THE SIZE OF - * UTAH ! JRA. - * - * @return The ChangeID. - */ -static uint32_t winreg_printer_rev_changeid(void) -{ - struct timeval tv; - - get_process_uptime(&tv); - -#if 1 /* JERRY */ - /* Return changeid as msec since spooler restart */ - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -#else - /* - * This setting seems to work well but is too untested - * to replace the above calculation. Left in for experimentation - * of the reader --jerry (Tue Mar 12 09:15:05 CST 2002) - */ - return tv.tv_sec * 10 + tv.tv_usec / 100000; -#endif -} - -/** - * @internal - * - * @brief Connect to the interal winreg server and open the given printer key. - * - * The function will create the needed subkeys if they don't exist. - * - * @param[in] mem_ctx The memory context to use. - * - * @param[in] server_info The supplied server info. - * - * @param[out] binding_handle A pointer for the winreg dcerpc binding handle. - * - * @param[in] path The path to the key to open. - * - * @param[in] key The key to open. - * - * @param[in] create_key Set to true if the key should be created if it - * doesn't exist. - * - * @param[in] access_mask The access mask to open the key. - * - * @param[out] hive_handle A policy handle for the opened hive. - * - * @param[out] key_handle A policy handle for the opened key. - * - * @return WERR_OK on success, the corresponding DOS error - * code if something gone wrong. - */ -static WERROR winreg_printer_openkey(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct dcerpc_binding_handle **winreg_binding_handle, - const char *path, - const char *key, - bool create_key, - uint32_t access_mask, - struct policy_handle *hive_handle, - struct policy_handle *key_handle) -{ - static struct client_address client_id; - struct dcerpc_binding_handle *binding_handle; - struct winreg_String wkey, wkeyclass; - char *keyname; - NTSTATUS status; - WERROR result = WERR_OK; - - strlcpy(client_id.addr, "127.0.0.1", sizeof(client_id.addr)); - client_id.name = "127.0.0.1"; - - status = rpcint_binding_handle(mem_ctx, - &ndr_table_winreg, - &client_id, - server_info, - msg_ctx, - &binding_handle); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_openkey: Could not connect to winreg pipe: %s\n", - nt_errstr(status))); - return ntstatus_to_werror(status); - } - - status = dcerpc_winreg_OpenHKLM(binding_handle, - mem_ctx, - NULL, - access_mask, - hive_handle, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_openkey: Could not open HKLM hive: %s\n", - nt_errstr(status))); - talloc_free(binding_handle); - return ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_openkey: Could not open HKLM hive: %s\n", - win_errstr(result))); - talloc_free(binding_handle); - return result; - } - - if (key && *key) { - keyname = talloc_asprintf(mem_ctx, "%s\\%s", path, key); - } else { - keyname = talloc_strdup(mem_ctx, path); - } - if (keyname == NULL) { - talloc_free(binding_handle); - return WERR_NOMEM; - } - - ZERO_STRUCT(wkey); - wkey.name = keyname; - - if (create_key) { - enum winreg_CreateAction action = REG_ACTION_NONE; - - ZERO_STRUCT(wkeyclass); - wkeyclass.name = ""; - - status = dcerpc_winreg_CreateKey(binding_handle, - mem_ctx, - hive_handle, - wkey, - wkeyclass, - 0, - access_mask, - NULL, - key_handle, - &action, - &result); - switch (action) { - case REG_ACTION_NONE: - DEBUG(8, ("winreg_printer_openkey:createkey did nothing -- huh?\n")); - break; - case REG_CREATED_NEW_KEY: - DEBUG(8, ("winreg_printer_openkey: createkey created %s\n", keyname)); - break; - case REG_OPENED_EXISTING_KEY: - DEBUG(8, ("winreg_printer_openkey: createkey opened existing %s\n", keyname)); - break; - } - } else { - status = dcerpc_winreg_OpenKey(binding_handle, - mem_ctx, - hive_handle, - wkey, - 0, - access_mask, - key_handle, - &result); - } - if (!NT_STATUS_IS_OK(status)) { - talloc_free(binding_handle); - return ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - talloc_free(binding_handle); - return result; - } - - *winreg_binding_handle = binding_handle; - - return WERR_OK; -} - -/** - * @brief Create the registry keyname for the given printer. - * - * @param[in] mem_ctx The memory context to use. - * - * @param[in] printer The name of the printer to get the registry key. - * - * @return The registry key or NULL on error. - */ -static char *winreg_printer_data_keyname(TALLOC_CTX *mem_ctx, const char *printer) { - return talloc_asprintf(mem_ctx, "%s\\%s", TOP_LEVEL_PRINT_PRINTERS_KEY, printer); -} - -/** - * @internal - * - * @brief Enumerate values of an opened key handle and retrieve the data. - * - * @param[in] mem_ctx The memory context to use. - * - * @param[in] winreg_handle The binding handle for the rpc connection. - * - * @param[in] key_hnd The opened key handle. - * - * @param[out] pnum_values A pointer to store he number of values found. - * - * @param[out] pnum_values A pointer to store the number of values we found. - * - * @return WERR_OK on success, the corresponding DOS error - * code if something gone wrong. - */ -static WERROR winreg_printer_enumvalues(TALLOC_CTX *mem_ctx, - struct dcerpc_binding_handle *winreg_handle, - struct policy_handle *key_hnd, - uint32_t *pnum_values, - struct spoolss_PrinterEnumValues **penum_values) -{ - TALLOC_CTX *tmp_ctx; - uint32_t num_subkeys, max_subkeylen, max_classlen; - uint32_t num_values, max_valnamelen, max_valbufsize; - uint32_t secdescsize; - uint32_t i; - NTTIME last_changed_time; - struct winreg_String classname; - - struct spoolss_PrinterEnumValues *enum_values; - - WERROR result = WERR_OK; - NTSTATUS status; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - ZERO_STRUCT(classname); - - status = dcerpc_winreg_QueryInfoKey(winreg_handle, - tmp_ctx, - key_hnd, - &classname, - &num_subkeys, - &max_subkeylen, - &max_classlen, - &num_values, - &max_valnamelen, - &max_valbufsize, - &secdescsize, - &last_changed_time, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_enumvalues: Could not query info: %s\n", - nt_errstr(status))); - result = ntstatus_to_werror(status); - goto error; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_enumvalues: Could not query info: %s\n", - win_errstr(result))); - goto error; - } - - if (num_values == 0) { - *pnum_values = 0; - TALLOC_FREE(tmp_ctx); - return WERR_OK; - } - - enum_values = TALLOC_ARRAY(tmp_ctx, struct spoolss_PrinterEnumValues, num_values); - if (enum_values == NULL) { - result = WERR_NOMEM; - goto error; - } - - for (i = 0; i < num_values; i++) { - struct spoolss_PrinterEnumValues val; - struct winreg_ValNameBuf name_buf; - enum winreg_Type type = REG_NONE; - uint8_t *data; - uint32_t data_size; - uint32_t length; - char n = '\0'; - - name_buf.name = &n; - name_buf.size = max_valnamelen + 2; - name_buf.length = 0; - - data_size = max_valbufsize; - data = NULL; - if (data_size) { - data = (uint8_t *) TALLOC(tmp_ctx, data_size); - } - length = 0; - - status = dcerpc_winreg_EnumValue(winreg_handle, - tmp_ctx, - key_hnd, - i, - &name_buf, - &type, - data, - data_size ? &data_size : NULL, - &length, - &result); - if (W_ERROR_EQUAL(result, WERR_NO_MORE_ITEMS) ) { - result = WERR_OK; - status = NT_STATUS_OK; - break; - } - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_enumvalues: Could not enumerate values: %s\n", - nt_errstr(status))); - result = ntstatus_to_werror(status); - goto error; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_enumvalues: Could not enumerate values: %s\n", - win_errstr(result))); - goto error; - } - - if (name_buf.name == NULL) { - result = WERR_INVALID_PARAMETER; - goto error; - } - - val.value_name = talloc_strdup(enum_values, name_buf.name); - if (val.value_name == NULL) { - result = WERR_NOMEM; - goto error; - } - val.value_name_len = strlen_m_term(val.value_name) * 2; - - val.type = type; - val.data_length = length; - val.data = NULL; - if (val.data_length) { - val.data = talloc(enum_values, DATA_BLOB); - if (val.data == NULL) { - result = WERR_NOMEM; - goto error; - } - *val.data = data_blob_talloc(val.data, data, val.data_length); - } - - enum_values[i] = val; - } - - *pnum_values = num_values; - if (penum_values) { - *penum_values = talloc_move(mem_ctx, &enum_values); - } - - result = WERR_OK; - - error: - TALLOC_FREE(tmp_ctx); - return result; -} - -/** - * @internal - * - * @brief A function to delete a key and its subkeys recurively. - * - * @param[in] mem_ctx The memory context to use. - * - * @param[in] winreg_handle The binding handle for the rpc connection. - * - * @param[in] hive_handle A opened hive handle to the key. - * - * @param[in] access_mask The access mask to access the key. - * - * @param[in] key The key to delete - * - * @return WERR_OK on success, the corresponding DOS error - * code if something gone wrong. - */ -static WERROR winreg_printer_delete_subkeys(TALLOC_CTX *mem_ctx, - struct dcerpc_binding_handle *winreg_handle, - struct policy_handle *hive_handle, - uint32_t access_mask, - const char *key) -{ - const char **subkeys = NULL; - uint32_t num_subkeys = 0; - struct policy_handle key_hnd; - struct winreg_String wkey; - WERROR result = WERR_OK; - NTSTATUS status; - uint32_t i; - - ZERO_STRUCT(key_hnd); - wkey.name = key; - - DEBUG(2, ("winreg_printer_delete_subkeys: delete key %s\n", key)); - /* open the key */ - status = dcerpc_winreg_OpenKey(winreg_handle, - mem_ctx, - hive_handle, - wkey, - 0, - access_mask, - &key_hnd, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_delete_subkeys: Could not open key %s: %s\n", - wkey.name, nt_errstr(status))); - return ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_delete_subkeys: Could not open key %s: %s\n", - wkey.name, win_errstr(result))); - return result; - } - - status = dcerpc_winreg_enum_keys(mem_ctx, - winreg_handle, - &key_hnd, - &num_subkeys, - &subkeys, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - for (i = 0; i < num_subkeys; i++) { - /* create key + subkey */ - char *subkey = talloc_asprintf(mem_ctx, "%s\\%s", key, subkeys[i]); - if (subkey == NULL) { - goto done; - } - - DEBUG(2, ("winreg_printer_delete_subkeys: delete subkey %s\n", subkey)); - result = winreg_printer_delete_subkeys(mem_ctx, - winreg_handle, - hive_handle, - access_mask, - subkey); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (is_valid_policy_hnd(&key_hnd)) { - WERROR ignore; - dcerpc_winreg_CloseKey(winreg_handle, mem_ctx, &key_hnd, &ignore); - } - - wkey.name = key; - - status = dcerpc_winreg_DeleteKey(winreg_handle, - mem_ctx, - hive_handle, - wkey, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - -done: - if (is_valid_policy_hnd(&key_hnd)) { - WERROR ignore; - - dcerpc_winreg_CloseKey(winreg_handle, mem_ctx, &key_hnd, &ignore); - } - - return result; -} - -static WERROR winreg_printer_opendriver(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *drivername, - const char *architecture, - uint32_t version, - uint32_t access_mask, - bool create, - struct dcerpc_binding_handle **winreg_binding_handle, - struct policy_handle *hive_hnd, - struct policy_handle *key_hnd) -{ - WERROR result; - char *key_name; - - key_name = talloc_asprintf(mem_ctx, "%s\\Environments\\%s\\Drivers\\Version-%u", - TOP_LEVEL_CONTROL_KEY, - architecture, version); - if (!key_name) { - return WERR_NOMEM; - } - - result = winreg_printer_openkey(mem_ctx, - server_info, - msg_ctx, - winreg_binding_handle, - key_name, - drivername, - create, - access_mask, - hive_hnd, - key_hnd); - return result; -} - -static WERROR winreg_enumval_to_dword(TALLOC_CTX *mem_ctx, - struct spoolss_PrinterEnumValues *v, - const char *valuename, uint32_t *dw) -{ - /* just return if it is not the one we are looking for */ - if (strcmp(valuename, v->value_name) != 0) { - return WERR_NOT_FOUND; - } - - if (v->type != REG_DWORD) { - return WERR_INVALID_DATATYPE; - } - - if (v->data_length != 4) { - *dw = 0; - return WERR_OK; - } - - *dw = IVAL(v->data->data, 0); - return WERR_OK; -} - -static WERROR winreg_enumval_to_sz(TALLOC_CTX *mem_ctx, - struct spoolss_PrinterEnumValues *v, - const char *valuename, const char **_str) -{ - /* just return if it is not the one we are looking for */ - if (strcmp(valuename, v->value_name) != 0) { - return WERR_NOT_FOUND; - } - - if (v->type != REG_SZ) { - return WERR_INVALID_DATATYPE; - } - - if (v->data_length == 0) { - *_str = talloc_strdup(mem_ctx, EMPTY_STRING); - if (*_str == NULL) { - return WERR_NOMEM; - } - return WERR_OK; - } - - if (!pull_reg_sz(mem_ctx, v->data, _str)) { - return WERR_NOMEM; - } - - return WERR_OK; -} - -static WERROR winreg_enumval_to_multi_sz(TALLOC_CTX *mem_ctx, - struct spoolss_PrinterEnumValues *v, - const char *valuename, - const char ***array) -{ - /* just return if it is not the one we are looking for */ - if (strcmp(valuename, v->value_name) != 0) { - return WERR_NOT_FOUND; - } - - if (v->type != REG_MULTI_SZ) { - return WERR_INVALID_DATATYPE; - } - - if (v->data_length == 0) { - *array = talloc_array(mem_ctx, const char *, 1); - if (*array == NULL) { - return WERR_NOMEM; - } - *array[0] = NULL; - return WERR_OK; - } - - if (!pull_reg_multi_sz(mem_ctx, v->data, array)) { - return WERR_NOMEM; - } - - return WERR_OK; -} - -static WERROR winreg_printer_write_date(TALLOC_CTX *mem_ctx, - struct dcerpc_binding_handle *winreg_handle, - struct policy_handle *key_handle, - const char *value, - NTTIME data) -{ - struct winreg_String wvalue; - DATA_BLOB blob; - WERROR result = WERR_OK; - NTSTATUS status; - const char *str; - struct tm *tm; - time_t t; - - if (data == 0) { - str = talloc_strdup(mem_ctx, "01/01/1601"); - } else { - t = nt_time_to_unix(data); - tm = localtime(&t); - str = talloc_asprintf(mem_ctx, "%02d/%02d/%04d", - tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900); - } - if (!str) { - return WERR_NOMEM; - } - - wvalue.name = value; - if (!push_reg_sz(mem_ctx, &blob, str)) { - return WERR_NOMEM; - } - status = dcerpc_winreg_SetValue(winreg_handle, - mem_ctx, - key_handle, - wvalue, - REG_SZ, - blob.data, - blob.length, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_write_date: Could not set value %s: %s\n", - wvalue.name, win_errstr(result))); - } - - return result; -} - -static WERROR winreg_printer_date_to_NTTIME(const char *str, NTTIME *data) -{ - struct tm tm; - time_t t; - - if (strequal(str, "01/01/1601")) { - *data = 0; - return WERR_OK; - } - - ZERO_STRUCT(tm); - - if (sscanf(str, "%d/%d/%d", - &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3) { - return WERR_INVALID_PARAMETER; - } - tm.tm_mon -= 1; - tm.tm_year -= 1900; - tm.tm_isdst = -1; - - t = mktime(&tm); - unix_to_nt_time(data, t); - - return WERR_OK; -} - -static WERROR winreg_printer_write_ver(TALLOC_CTX *mem_ctx, - struct dcerpc_binding_handle *winreg_handle, - struct policy_handle *key_handle, - const char *value, - uint64_t data) -{ - struct winreg_String wvalue; - DATA_BLOB blob; - WERROR result = WERR_OK; - NTSTATUS status; - char *str; - - /* FIXME: check format is right, - * this needs to be something like: 6.1.7600.16385 */ - str = talloc_asprintf(mem_ctx, "%u.%u.%u.%u", - (unsigned)((data >> 48) & 0xFFFF), - (unsigned)((data >> 32) & 0xFFFF), - (unsigned)((data >> 16) & 0xFFFF), - (unsigned)(data & 0xFFFF)); - if (!str) { - return WERR_NOMEM; - } - - wvalue.name = value; - if (!push_reg_sz(mem_ctx, &blob, str)) { - return WERR_NOMEM; - } - status = dcerpc_winreg_SetValue(winreg_handle, - mem_ctx, - key_handle, - wvalue, - REG_SZ, - blob.data, - blob.length, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_write_date: Could not set value %s: %s\n", - wvalue.name, win_errstr(result))); - } - - return result; -} - -static WERROR winreg_printer_ver_to_dword(const char *str, uint64_t *data) -{ - unsigned int v1, v2, v3, v4; - - if (sscanf(str, "%u.%u.%u.%u", &v1, &v2, &v3, &v4) != 4) { - return WERR_INVALID_PARAMETER; - } - - *data = ((uint64_t)(v1 & 0xFFFF) << 48) + - ((uint64_t)(v2 & 0xFFFF) << 32) + - ((uint64_t)(v3 & 0xFFFF) << 16) + - (uint64_t)(v2 & 0xFFFF); - - return WERR_OK; -} - -/******************************************************************** - Public winreg function for spoolss -********************************************************************/ - -WERROR winreg_create_printer(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct spoolss_SetPrinterInfo2 *info2; - struct security_descriptor *secdesc; - struct winreg_String wkey, wkeyclass; - const char *path; - const char *subkeys[] = { SPOOL_DSDRIVER_KEY, SPOOL_DSSPOOLER_KEY, SPOOL_PRINTERDATA_KEY }; - uint32_t i, count = ARRAY_SIZE(subkeys); - uint32_t info2_mask = 0; - WERROR result = WERR_OK; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, sharename); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - false, - access_mask, - &hive_hnd, - &key_hnd); - if (W_ERROR_IS_OK(result)) { - DEBUG(2, ("winreg_create_printer: Skipping, %s already exists\n", path)); - goto done; - } else if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - DEBUG(2, ("winreg_create_printer: Creating default values in %s\n", path)); - } else if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_create_printer: Could not open key %s: %s\n", - path, win_errstr(result))); - goto done; - } - - /* Create the main key */ - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_create_printer_keys: Could not create key %s: %s\n", - path, win_errstr(result))); - goto done; - } - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); - } - - /* Create subkeys */ - for (i = 0; i < count; i++) { - NTSTATUS status; - enum winreg_CreateAction action = REG_ACTION_NONE; - - ZERO_STRUCT(key_hnd); - ZERO_STRUCT(wkey); - - wkey.name = talloc_asprintf(tmp_ctx, "%s\\%s", path, subkeys[i]); - if (wkey.name == NULL) { - result = WERR_NOMEM; - goto done; - } - - ZERO_STRUCT(wkeyclass); - wkeyclass.name = ""; - - status = dcerpc_winreg_CreateKey(winreg_handle, - tmp_ctx, - &hive_hnd, - wkey, - wkeyclass, - 0, - access_mask, - NULL, - &key_hnd, - &action, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_create_printer_keys: Could not create key %s: %s\n", - wkey.name, win_errstr(result))); - goto done; - } - - if (strequal(subkeys[i], SPOOL_DSSPOOLER_KEY)) { - const char *dnssuffix; - const char *longname; - const char *uncname; - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_PRINTERNAME, - sharename, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_SHORTSERVERNAME, - global_myname(), - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - /* We make the assumption that the netbios name - * is the same as the DNS name since the former - * will be what we used to join the domain - */ - dnssuffix = get_mydnsdomname(tmp_ctx); - if (dnssuffix != NULL && dnssuffix[0] != '\0') { - longname = talloc_asprintf(tmp_ctx, "%s.%s", global_myname(), dnssuffix); - } else { - longname = talloc_strdup(tmp_ctx, global_myname()); - } - if (longname == NULL) { - result = WERR_NOMEM; - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_SERVERNAME, - longname, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - uncname = talloc_asprintf(tmp_ctx, "\\\\%s\\%s", - longname, sharename); - if (uncname == NULL) { - result = WERR_NOMEM; - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_UNCNAME, - uncname, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_VERSIONNUMBER, - 4, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_PRINTSTARTTIME, - 0, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_PRINTENDTIME, - 0, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_PRIORITY, - 1, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - SPOOL_REG_PRINTKEEPPRINTEDJOBS, - 0, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); - } - } - info2 = talloc_zero(tmp_ctx, struct spoolss_SetPrinterInfo2); - if (info2 == NULL) { - result = WERR_NOMEM; - goto done; - } - - info2->printername = sharename; - if (info2->printername == NULL) { - result = WERR_NOMEM; - goto done; - } - info2_mask |= SPOOLSS_PRINTER_INFO_PRINTERNAME; - - info2->sharename = sharename; - info2_mask |= SPOOLSS_PRINTER_INFO_SHARENAME; - - info2->portname = SAMBA_PRINTER_PORT_NAME; - info2_mask |= SPOOLSS_PRINTER_INFO_PORTNAME; - - info2->printprocessor = "winprint"; - info2_mask |= SPOOLSS_PRINTER_INFO_PRINTPROCESSOR; - - info2->datatype = "RAW"; - info2_mask |= SPOOLSS_PRINTER_INFO_DATATYPE; - - info2->comment = ""; - info2_mask |= SPOOLSS_PRINTER_INFO_COMMENT; - - info2->attributes = PRINTER_ATTRIBUTE_SAMBA; - info2_mask |= SPOOLSS_PRINTER_INFO_ATTRIBUTES; - - info2->starttime = 0; /* Minutes since 12:00am GMT */ - info2_mask |= SPOOLSS_PRINTER_INFO_STARTTIME; - - info2->untiltime = 0; /* Minutes since 12:00am GMT */ - info2_mask |= SPOOLSS_PRINTER_INFO_UNTILTIME; - - info2->priority = 1; - info2_mask |= SPOOLSS_PRINTER_INFO_PRIORITY; - - info2->defaultpriority = 1; - info2_mask |= SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY; - - result = spoolss_create_default_secdesc(tmp_ctx, &secdesc); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - info2_mask |= SPOOLSS_PRINTER_INFO_SECDESC; - - /* - * Don't write a default Device Mode to the registry! The Device Mode is - * only written to disk with a SetPrinter level 2 or 8. - */ - - result = winreg_update_printer(tmp_ctx, - server_info, - msg_ctx, - sharename, - info2_mask, - info2, - NULL, - secdesc); - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - talloc_free(tmp_ctx); - return result; -} - -WERROR winreg_update_printer(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename, - uint32_t info2_mask, - struct spoolss_SetPrinterInfo2 *info2, - struct spoolss_DeviceMode *devmode, - struct security_descriptor *secdesc) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - int snum = lp_servicenumber(sharename); - enum ndr_err_code ndr_err; - DATA_BLOB blob; - char *path; - WERROR result = WERR_OK; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, sharename); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_update_printer: Could not open key %s: %s\n", - path, win_errstr(result))); - goto done; - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_ATTRIBUTES) { - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "Attributes", - info2->attributes, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - -#if 0 - if (info2_mask & SPOOLSS_PRINTER_INFO_AVERAGEPPM) { - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "AveragePpm", - info2->attributes, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } -#endif - - if (info2_mask & SPOOLSS_PRINTER_INFO_COMMENT) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Description", - info2->comment, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_DATATYPE) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Datatype", - info2->datatype, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY) { - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "Default Priority", - info2->defaultpriority, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_DEVMODE) { - /* - * Some client drivers freak out if there is a NULL devmode - * (probably the driver is not checking before accessing - * the devmode pointer) --jerry - */ - if (devmode == NULL && lp_default_devmode(snum) && info2 != NULL) { - result = spoolss_create_default_devmode(tmp_ctx, - info2->printername, - &devmode); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (devmode->size != (ndr_size_spoolss_DeviceMode(devmode, 0) - devmode->__driverextra_length)) { - result = WERR_INVALID_PARAM; - goto done; - } - - ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, devmode, - (ndr_push_flags_fn_t) ndr_push_spoolss_DeviceMode); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0, ("winreg_update_printer: Failed to marshall device mode\n")); - result = WERR_NOMEM; - goto done; - } - - status = dcerpc_winreg_set_binary(tmp_ctx, - winreg_handle, - &key_hnd, - "Default DevMode", - &blob, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_DRIVERNAME) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Printer Driver", - info2->drivername, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_LOCATION) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Location", - info2->location, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_PARAMETERS) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Parameters", - info2->parameters, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_PORTNAME) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Port", - info2->portname, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_PRINTERNAME) { - /* - * in addprinter: no servername and the printer is the name - * in setprinter: servername is \\server - * and printer is \\server\\printer - * - * Samba manages only local printers. - * we currently don't support things like i - * path=\\other_server\printer - * - * We only store the printername, not \\server\printername - */ - const char *p = strrchr(info2->printername, '\\'); - if (p == NULL) { - p = info2->printername; - } else { - p++; - } - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Name", - p, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_PRINTPROCESSOR) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Print Processor", - info2->printprocessor, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_PRIORITY) { - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "Priority", - info2->priority, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_SECDESC) { - /* - * We need a security descriptor, if it isn't specified by - * AddPrinter{Ex} then create a default descriptor. - */ - if (secdesc == NULL) { - result = spoolss_create_default_secdesc(tmp_ctx, &secdesc); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - result = winreg_set_printer_secdesc(tmp_ctx, - server_info, - msg_ctx, - sharename, - secdesc); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_SEPFILE) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Separator File", - info2->sepfile, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_SHARENAME) { - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Share Name", - info2->sharename, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_STARTTIME) { - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "StartTime", - info2->starttime, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_STATUS) { - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "Status", - info2->status, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2_mask & SPOOLSS_PRINTER_INFO_UNTILTIME) { - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "UntilTime", - info2->untiltime, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "ChangeID", - winreg_printer_rev_changeid(), - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_get_printer(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - struct spoolss_PrinterInfo2 **pinfo2) -{ - struct spoolss_PrinterInfo2 *info2; - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct spoolss_PrinterEnumValues *enum_values = NULL; - struct spoolss_PrinterEnumValues *v = NULL; - enum ndr_err_code ndr_err; - DATA_BLOB blob; - int snum = lp_servicenumber(printer); - uint32_t num_values = 0; - uint32_t i; - char *path; - NTSTATUS status; - WERROR result = WERR_OK; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(2, ("winreg_get_printer: Could not open key %s: %s\n", - path, win_errstr(result))); - goto done; - } - - result = winreg_printer_enumvalues(tmp_ctx, - winreg_handle, - &key_hnd, - &num_values, - &enum_values); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_get_printer: Could not enumerate values in %s: %s\n", - path, win_errstr(result))); - goto done; - } - - info2 = talloc_zero(tmp_ctx, struct spoolss_PrinterInfo2); - if (info2 == NULL) { - result = WERR_NOMEM; - goto done; - } - - FILL_STRING(info2, EMPTY_STRING, info2->servername); - FILL_STRING(info2, EMPTY_STRING, info2->printername); - FILL_STRING(info2, EMPTY_STRING, info2->sharename); - FILL_STRING(info2, EMPTY_STRING, info2->portname); - FILL_STRING(info2, EMPTY_STRING, info2->drivername); - FILL_STRING(info2, EMPTY_STRING, info2->comment); - FILL_STRING(info2, EMPTY_STRING, info2->location); - FILL_STRING(info2, EMPTY_STRING, info2->sepfile); - FILL_STRING(info2, EMPTY_STRING, info2->printprocessor); - FILL_STRING(info2, EMPTY_STRING, info2->datatype); - FILL_STRING(info2, EMPTY_STRING, info2->parameters); - - for (i = 0; i < num_values; i++) { - v = &enum_values[i]; - - result = winreg_enumval_to_sz(info2, - v, - "Name", - &info2->printername); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Share Name", - &info2->sharename); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Port", - &info2->portname); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Description", - &info2->comment); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Location", - &info2->location); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Separator File", - &info2->sepfile); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Print Processor", - &info2->printprocessor); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Datatype", - &info2->datatype); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Parameters", - &info2->parameters); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info2, - v, - "Printer Driver", - &info2->drivername); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info2, - v, - "Attributes", - &info2->attributes); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info2, - v, - "Priority", - &info2->priority); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info2, - v, - "Default Priority", - &info2->defaultpriority); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info2, - v, - "StartTime", - &info2->starttime); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info2, - v, - "UntilTime", - &info2->untiltime); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info2, - v, - "Status", - &info2->status); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info2, - v, - "StartTime", - &info2->starttime); - CHECK_ERROR(result); - } - - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_get_printer: winreg_enumval_to_TYPE() failed " - "for %s: %s\n", - v->value_name, - win_errstr(result))); - goto done; - } - - /* Construct the Device Mode */ - status = dcerpc_winreg_query_binary(tmp_ctx, - winreg_handle, - &key_hnd, - "Default DevMode", - &blob, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (W_ERROR_IS_OK(result)) { - info2->devmode = talloc_zero(info2, struct spoolss_DeviceMode); - if (info2->devmode == NULL) { - result = WERR_NOMEM; - goto done; - } - ndr_err = ndr_pull_struct_blob(&blob, - info2->devmode, - info2->devmode, - (ndr_pull_flags_fn_t) ndr_pull_spoolss_DeviceMode); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0, ("winreg_get_printer: Failed to unmarshall device mode\n")); - result = WERR_NOMEM; - goto done; - } - } - - if (info2->devmode == NULL && lp_default_devmode(snum)) { - result = spoolss_create_default_devmode(info2, - info2->printername, - &info2->devmode); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - } - - if (info2->devmode) { - info2->devmode->size = ndr_size_spoolss_DeviceMode(info2->devmode, 0) - info2->devmode->driverextra_data.length; - } - - result = winreg_get_printer_secdesc(info2, - server_info, - msg_ctx, - printer, - &info2->secdesc); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - /* Fix for OS/2 drivers. */ - if (get_remote_arch() == RA_OS2) { - spoolss_map_to_os2_driver(info2, &info2->drivername); - } - - if (pinfo2) { - *pinfo2 = talloc_move(mem_ctx, &info2); - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_get_printer_secdesc(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename, - struct spoolss_security_descriptor **psecdesc) -{ - struct spoolss_security_descriptor *secdesc; - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - const char *path; - TALLOC_CTX *tmp_ctx; - NTSTATUS status; - WERROR result; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, sharename); - if (path == NULL) { - talloc_free(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - goto create_default; - } - goto done; - } - - status = dcerpc_winreg_query_sd(tmp_ctx, - winreg_handle, - &key_hnd, - "Security", - &secdesc, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - goto create_default; - } - goto done; - } - - if (psecdesc) { - *psecdesc = talloc_move(mem_ctx, &secdesc); - } - - result = WERR_OK; - goto done; - -create_default: - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - result = spoolss_create_default_secdesc(tmp_ctx, &secdesc); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - /* If security descriptor is owned by S-1-1-0 and winbindd is up, - this security descriptor has been created when winbindd was - down. Take ownership of security descriptor. */ - if (dom_sid_equal(secdesc->owner_sid, &global_sid_World)) { - struct dom_sid owner_sid; - - /* Change sd owner to workgroup administrator */ - - if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) { - struct spoolss_security_descriptor *new_secdesc; - size_t size; - - /* Create new sd */ - sid_append_rid(&owner_sid, DOMAIN_RID_ADMINISTRATOR); - - new_secdesc = make_sec_desc(tmp_ctx, - secdesc->revision, - secdesc->type, - &owner_sid, - secdesc->group_sid, - secdesc->sacl, - secdesc->dacl, - &size); - - if (new_secdesc == NULL) { - result = WERR_NOMEM; - goto done; - } - - /* Swap with other one */ - secdesc = new_secdesc; - } - } - - status = dcerpc_winreg_set_sd(tmp_ctx, - winreg_handle, - &key_hnd, - "Security", - secdesc, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - return result; - } - - if (psecdesc) { - *psecdesc = talloc_move(mem_ctx, &secdesc); - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - talloc_free(tmp_ctx); - return result; -} - -WERROR winreg_set_printer_secdesc(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename, - const struct spoolss_security_descriptor *secdesc) -{ - const struct spoolss_security_descriptor *new_secdesc = secdesc; - struct spoolss_security_descriptor *old_secdesc; - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - const char *path; - TALLOC_CTX *tmp_ctx; - NTSTATUS status; - WERROR result; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, sharename); - if (path == NULL) { - talloc_free(tmp_ctx); - return WERR_NOMEM; - } - - /* - * The old owner and group sids of the security descriptor are not - * present when new ACEs are added or removed by changing printer - * permissions through NT. If they are NULL in the new security - * descriptor then copy them over from the old one. - */ - if (!secdesc->owner_sid || !secdesc->group_sid) { - struct dom_sid *owner_sid, *group_sid; - struct security_acl *dacl, *sacl; - size_t size; - - result = winreg_get_printer_secdesc(tmp_ctx, - server_info, - msg_ctx, - sharename, - &old_secdesc); - if (!W_ERROR_IS_OK(result)) { - talloc_free(tmp_ctx); - return result; - } - - /* Pick out correct owner and group sids */ - owner_sid = secdesc->owner_sid ? - secdesc->owner_sid : - old_secdesc->owner_sid; - - group_sid = secdesc->group_sid ? - secdesc->group_sid : - old_secdesc->group_sid; - - dacl = secdesc->dacl ? - secdesc->dacl : - old_secdesc->dacl; - - sacl = secdesc->sacl ? - secdesc->sacl : - old_secdesc->sacl; - - /* Make a deep copy of the security descriptor */ - new_secdesc = make_sec_desc(tmp_ctx, - secdesc->revision, - secdesc->type, - owner_sid, - group_sid, - sacl, - dacl, - &size); - if (new_secdesc == NULL) { - talloc_free(tmp_ctx); - return WERR_NOMEM; - } - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sd(tmp_ctx, - winreg_handle, - &key_hnd, - "Security", - new_secdesc, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - talloc_free(tmp_ctx); - return result; -} - -/* Set printer data over the winreg pipe. */ -WERROR winreg_set_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - const char *value, - enum winreg_Type type, - uint8_t *data, - uint32_t data_size) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct winreg_String wvalue; - char *path; - WERROR result = WERR_OK; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - DEBUG(8, ("winreg_set_printer_dataex: Open printer key %s, value %s, access_mask: 0x%05x for [%s]\n", - key, value, access_mask, printer)); - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - key, - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_set_printer_dataex: Could not open key %s: %s\n", - key, win_errstr(result))); - goto done; - } - - wvalue.name = value; - status = dcerpc_winreg_SetValue(winreg_handle, - tmp_ctx, - &key_hnd, - wvalue, - type, - data, - data_size, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_set_printer_dataex: Could not set value %s: %s\n", - value, nt_errstr(status))); - result = ntstatus_to_werror(status); - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -/* Get printer data over a winreg pipe. */ -WERROR winreg_get_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - const char *value, - enum winreg_Type *type, - uint8_t **data, - uint32_t *data_size) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct winreg_String wvalue; - enum winreg_Type type_in; - char *path; - uint8_t *data_in; - uint32_t data_in_size = 0; - uint32_t value_len = 0; - WERROR result = WERR_OK; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - key, - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(2, ("winreg_get_printer_dataex: Could not open key %s: %s\n", - key, win_errstr(result))); - goto done; - } - - wvalue.name = value; - - /* - * call QueryValue once with data == NULL to get the - * needed memory size to be allocated, then allocate - * data buffer and call again. - */ - status = dcerpc_winreg_QueryValue(winreg_handle, - tmp_ctx, - &key_hnd, - &wvalue, - &type_in, - NULL, - &data_in_size, - &value_len, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_get_printer_dataex: Could not query value %s: %s\n", - value, nt_errstr(status))); - result = ntstatus_to_werror(status); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - data_in = (uint8_t *) TALLOC(tmp_ctx, data_in_size); - if (data_in == NULL) { - result = WERR_NOMEM; - goto done; - } - value_len = 0; - - status = dcerpc_winreg_QueryValue(winreg_handle, - tmp_ctx, - &key_hnd, - &wvalue, - &type_in, - data_in, - &data_in_size, - &value_len, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_get_printer_dataex: Could not query value %s: %s\n", - value, nt_errstr(status))); - result = ntstatus_to_werror(status); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - *type = type_in; - *data_size = data_in_size; - if (data_in_size) { - *data = talloc_move(mem_ctx, &data_in); - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -/* Enumerate on the values of a given key and provide the data. */ -WERROR winreg_enum_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - uint32_t *pnum_values, - struct spoolss_PrinterEnumValues **penum_values) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - - struct spoolss_PrinterEnumValues *enum_values = NULL; - uint32_t num_values = 0; - char *path; - WERROR result = WERR_OK; - - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - key, - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(2, ("winreg_enum_printer_dataex: Could not open key %s: %s\n", - key, win_errstr(result))); - goto done; - } - - result = winreg_printer_enumvalues(tmp_ctx, - winreg_handle, - &key_hnd, - &num_values, - &enum_values); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_enum_printer_dataex: Could not enumerate values in %s: %s\n", - key, win_errstr(result))); - goto done; - } - - *pnum_values = num_values; - if (penum_values) { - *penum_values = talloc_move(mem_ctx, &enum_values); - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -/* Delete printer data over a winreg pipe. */ -WERROR winreg_delete_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - const char *value) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct winreg_String wvalue; - char *path; - WERROR result = WERR_OK; - NTSTATUS status; - - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - key, - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_delete_printer_dataex: Could not open key %s: %s\n", - key, win_errstr(result))); - goto done; - } - - wvalue.name = value; - status = dcerpc_winreg_DeleteValue(winreg_handle, - tmp_ctx, - &key_hnd, - wvalue, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_delete_printer_dataex: Could not delete value %s: %s\n", - value, nt_errstr(status))); - result = ntstatus_to_werror(status); - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -/* Enumerate on the subkeys of a given key and provide the data. */ -WERROR winreg_enum_printer_key(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - uint32_t *pnum_subkeys, - const char ***psubkeys) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - char *path; - const char **subkeys = NULL; - uint32_t num_subkeys = -1; - - WERROR result = WERR_OK; - NTSTATUS status; - - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - key, - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(2, ("winreg_enum_printer_key: Could not open key %s: %s\n", - key, win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_enum_keys(tmp_ctx, - winreg_handle, - &key_hnd, - &num_subkeys, - &subkeys, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_enum_printer_key: Could not enumerate subkeys in %s: %s\n", - key, win_errstr(result))); - goto done; - } - - *pnum_subkeys = num_subkeys; - if (psubkeys) { - *psubkeys = talloc_move(mem_ctx, &subkeys); - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -/* Delete a key with subkeys of a given printer. */ -WERROR winreg_delete_printer_key(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - char *keyname; - char *path; - WERROR result; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - key, - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - /* key doesn't exist */ - if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - result = WERR_OK; - goto done; - } - - DEBUG(0, ("winreg_delete_printer_key: Could not open key %s: %s\n", - key, win_errstr(result))); - goto done; - } - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); - } - - if (key == NULL || key[0] == '\0') { - keyname = path; - } else { - keyname = talloc_asprintf(tmp_ctx, - "%s\\%s", - path, - key); - if (keyname == NULL) { - result = WERR_NOMEM; - goto done; - } - } - - result = winreg_printer_delete_subkeys(tmp_ctx, - winreg_handle, - &hive_hnd, - access_mask, - keyname); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_delete_printer_key: Could not delete key %s: %s\n", - key, win_errstr(result))); - goto done; - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_printer_update_changeid(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - char *path; - NTSTATUS status; - WERROR result; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_update_changeid: Could not open key %s: %s\n", - path, win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "ChangeID", - winreg_printer_rev_changeid(), - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_printer_get_changeid(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - uint32_t *pchangeid) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - uint32_t changeid = 0; - char *path; - NTSTATUS status; - WERROR result; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - path = winreg_printer_data_keyname(tmp_ctx, printer); - if (path == NULL) { - TALLOC_FREE(tmp_ctx); - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - path, - "", - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(2, ("winreg_printer_get_changeid: Could not open key %s: %s\n", - path, win_errstr(result))); - goto done; - } - - DEBUG(10, ("winreg_printer_get_changeid: get changeid from %s\n", path)); - - status = dcerpc_winreg_query_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "ChangeID", - &changeid, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - if (pchangeid) { - *pchangeid = changeid; - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -/* - * The special behaviour of the spoolss forms is documented at the website: - * - * Managing Win32 Printserver Forms - * http://unixwiz.net/techtips/winspooler-forms.html - */ - -WERROR winreg_printer_addform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct spoolss_AddFormInfo1 *form) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct winreg_String wvalue; - DATA_BLOB blob; - uint32_t num_info = 0; - union spoolss_FormInfo *info = NULL; - uint32_t i; - WERROR result; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - TOP_LEVEL_CONTROL_FORMS_KEY, - "", - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_addform1: Could not open key %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - goto done; - } - - result = winreg_printer_enumforms1(tmp_ctx, server_info, msg_ctx, - &num_info, &info); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_addform: Could not enum keys %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - goto done; - } - - /* If form name already exists or is builtin return ALREADY_EXISTS */ - for (i = 0; i < num_info; i++) { - if (strequal(info[i].info1.form_name, form->form_name)) { - result = WERR_FILE_EXISTS; - goto done; - } - } - - wvalue.name = form->form_name; - - blob = data_blob_talloc(tmp_ctx, NULL, 32); - SIVAL(blob.data, 0, form->size.width); - SIVAL(blob.data, 4, form->size.height); - SIVAL(blob.data, 8, form->area.left); - SIVAL(blob.data, 12, form->area.top); - SIVAL(blob.data, 16, form->area.right); - SIVAL(blob.data, 20, form->area.bottom); - SIVAL(blob.data, 24, num_info + 1); /* FIXME */ - SIVAL(blob.data, 28, form->flags); - - status = dcerpc_winreg_SetValue(winreg_handle, - tmp_ctx, - &key_hnd, - wvalue, - REG_BINARY, - blob.data, - blob.length, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_addform1: Could not set value %s: %s\n", - wvalue.name, nt_errstr(status))); - result = ntstatus_to_werror(status); - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(info); - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_printer_enumforms1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t *pnum_info, - union spoolss_FormInfo **pinfo) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - union spoolss_FormInfo *info; - struct spoolss_PrinterEnumValues *enum_values = NULL; - uint32_t num_values = 0; - uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); - uint32_t i; - WERROR result; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - TOP_LEVEL_CONTROL_FORMS_KEY, - "", - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - /* key doesn't exist */ - if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - result = WERR_OK; - goto done; - } - - DEBUG(0, ("winreg_printer_enumforms1: Could not open key %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - goto done; - } - - result = winreg_printer_enumvalues(tmp_ctx, - winreg_handle, - &key_hnd, - &num_values, - &enum_values); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_enumforms1: Could not enumerate values in %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - goto done; - } - - info = TALLOC_ARRAY(tmp_ctx, union spoolss_FormInfo, num_builtin + num_values); - if (info == NULL) { - result = WERR_NOMEM; - goto done; - } - - /* Enumerate BUILTIN forms */ - for (i = 0; i < num_builtin; i++) { - info[i].info1 = builtin_forms1[i]; - } - - /* Enumerate registry forms */ - for (i = 0; i < num_values; i++) { - union spoolss_FormInfo val; - - if (enum_values[i].type != REG_BINARY || - enum_values[i].data_length != 32) { - continue; - } - - val.info1.form_name = talloc_strdup(info, enum_values[i].value_name); - if (val.info1.form_name == NULL) { - result = WERR_NOMEM; - goto done; - } - - val.info1.size.width = IVAL(enum_values[i].data->data, 0); - val.info1.size.height = IVAL(enum_values[i].data->data, 4); - val.info1.area.left = IVAL(enum_values[i].data->data, 8); - val.info1.area.top = IVAL(enum_values[i].data->data, 12); - val.info1.area.right = IVAL(enum_values[i].data->data, 16); - val.info1.area.bottom = IVAL(enum_values[i].data->data, 20); - /* skip form index IVAL(enum_values[i].data->data, 24)));*/ - val.info1.flags = (enum spoolss_FormFlags) IVAL(enum_values[i].data->data, 28); - - info[i + num_builtin] = val; - } - - *pnum_info = num_builtin + num_values; - if (pinfo) { - *pinfo = talloc_move(mem_ctx, &info); - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(enum_values); - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_printer_deleteform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *form_name) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct winreg_String wvalue; - uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); - uint32_t i; - WERROR result = WERR_OK; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - for (i = 0; i < num_builtin; i++) { - if (strequal(builtin_forms1[i].form_name, form_name)) { - return WERR_INVALID_PARAMETER; - } - } - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - TOP_LEVEL_CONTROL_FORMS_KEY, - "", - false, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_deleteform1: Could not open key %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - result = WERR_INVALID_FORM_NAME; - } - goto done; - } - - wvalue.name = form_name; - status = dcerpc_winreg_DeleteValue(winreg_handle, - tmp_ctx, - &key_hnd, - wvalue, - &result); - if (!NT_STATUS_IS_OK(status)) { - /* If the value doesn't exist, return WERR_INVALID_FORM_NAME */ - DEBUG(0, ("winreg_printer_delteform1: Could not delete value %s: %s\n", - wvalue.name, nt_errstr(status))); - result = ntstatus_to_werror(status); - goto done; - } - - if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - result = WERR_INVALID_FORM_NAME; - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_printer_setform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *form_name, - struct spoolss_AddFormInfo1 *form) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct winreg_String wvalue; - DATA_BLOB blob; - uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); - uint32_t i; - WERROR result; - NTSTATUS status; - TALLOC_CTX *tmp_ctx = NULL; - - for (i = 0; i < num_builtin; i++) { - if (strequal(builtin_forms1[i].form_name, form->form_name)) { - result = WERR_INVALID_PARAM; - goto done; - } - } - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - TOP_LEVEL_CONTROL_FORMS_KEY, - "", - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_setform1: Could not open key %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - goto done; - } - - /* If form_name != form->form_name then we renamed the form */ - if (strequal(form_name, form->form_name)) { - result = winreg_printer_deleteform1(tmp_ctx, server_info, - msg_ctx, form_name); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_printer_setform1: Could not open key %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - goto done; - } - } - - wvalue.name = form->form_name; - - blob = data_blob_talloc(tmp_ctx, NULL, 32); - SIVAL(blob.data, 0, form->size.width); - SIVAL(blob.data, 4, form->size.height); - SIVAL(blob.data, 8, form->area.left); - SIVAL(blob.data, 12, form->area.top); - SIVAL(blob.data, 16, form->area.right); - SIVAL(blob.data, 20, form->area.bottom); - SIVAL(blob.data, 24, 42); - SIVAL(blob.data, 28, form->flags); - - status = dcerpc_winreg_SetValue(winreg_handle, - tmp_ctx, - &key_hnd, - wvalue, - REG_BINARY, - blob.data, - blob.length, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_setform1: Could not set value %s: %s\n", - wvalue.name, nt_errstr(status))); - result = ntstatus_to_werror(status); - } - -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_printer_getform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *form_name, - struct spoolss_FormInfo1 *r) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct winreg_String wvalue; - enum winreg_Type type_in; - uint8_t *data_in; - uint32_t data_in_size = 0; - uint32_t value_len = 0; - uint32_t num_builtin = ARRAY_SIZE(builtin_forms1); - uint32_t i; - WERROR result; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; - - /* check builtin forms first */ - for (i = 0; i < num_builtin; i++) { - if (strequal(builtin_forms1[i].form_name, form_name)) { - *r = builtin_forms1[i]; - return WERR_OK; - } - } - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - result = winreg_printer_openkey(tmp_ctx, - server_info, - msg_ctx, - &winreg_handle, - TOP_LEVEL_CONTROL_FORMS_KEY, - "", - true, - access_mask, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(2, ("winreg_printer_getform1: Could not open key %s: %s\n", - TOP_LEVEL_CONTROL_FORMS_KEY, win_errstr(result))); - goto done; - } - - wvalue.name = form_name; - - /* - * call QueryValue once with data == NULL to get the - * needed memory size to be allocated, then allocate - * data buffer and call again. - */ - status = dcerpc_winreg_QueryValue(winreg_handle, - tmp_ctx, - &key_hnd, - &wvalue, - &type_in, - NULL, - &data_in_size, - &value_len, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_getform1: Could not query value %s: %s\n", - wvalue.name, nt_errstr(status))); - result = ntstatus_to_werror(status); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - data_in = (uint8_t *) TALLOC(tmp_ctx, data_in_size); - if (data_in == NULL) { - result = WERR_NOMEM; - goto done; - } - value_len = 0; - - status = dcerpc_winreg_QueryValue(winreg_handle, - tmp_ctx, - &key_hnd, - &wvalue, - &type_in, - data_in, - &data_in_size, - &value_len, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("winreg_printer_getform1: Could not query value %s: %s\n", - wvalue.name, nt_errstr(status))); - result = ntstatus_to_werror(status); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - r->form_name = talloc_strdup(mem_ctx, form_name); - if (r->form_name == NULL) { - result = WERR_NOMEM; - goto done; - } - - r->size.width = IVAL(data_in, 0); - r->size.height = IVAL(data_in, 4); - r->area.left = IVAL(data_in, 8); - r->area.top = IVAL(data_in, 12); - r->area.right = IVAL(data_in, 16); - r->area.bottom = IVAL(data_in, 20); - /* skip index IVAL(data_in, 24)));*/ - r->flags = (enum spoolss_FormFlags) IVAL(data_in, 28); - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_add_driver(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct spoolss_AddDriverInfoCtr *r, - const char **driver_name, - uint32_t *driver_version) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct spoolss_DriverInfo8 info8; - TALLOC_CTX *tmp_ctx = NULL; - NTSTATUS status; - WERROR result; - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - ZERO_STRUCT(info8); - - if (!driver_info_ctr_to_info8(r, &info8)) { - result = WERR_INVALID_PARAMETER; - goto done; - } - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - result = winreg_printer_opendriver(tmp_ctx, - server_info, - msg_ctx, - info8.driver_name, - info8.architecture, - info8.version, - access_mask, true, - &winreg_handle, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_add_driver: " - "Could not open driver key (%s,%s,%d): %s\n", - info8.driver_name, info8.architecture, - info8.version, win_errstr(result))); - goto done; - } - - /* TODO: "Attributes" ? */ - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "Version", - info8.version, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Driver", - info8.driver_path, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Data File", - info8.data_file, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Configuration File", - info8.config_file, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Help File", - info8.help_file, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_multi_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Dependent Files", - info8.dependent_files, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Monitor", - info8.monitor_name, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Datatype", - info8.default_datatype, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_multi_sz(tmp_ctx, - winreg_handle, - &key_hnd, "Previous Names", - info8.previous_names, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - result = winreg_printer_write_date(tmp_ctx, winreg_handle, - &key_hnd, "DriverDate", - info8.driver_date); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - result = winreg_printer_write_ver(tmp_ctx, winreg_handle, - &key_hnd, "DriverVersion", - info8.driver_version); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Manufacturer", - info8.manufacturer_name, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "OEM URL", - info8.manufacturer_url, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "HardwareID", - info8.hardware_id, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Provider", - info8.provider, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Print Processor", - info8.print_processor, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "VendorSetup", - info8.vendor_setup, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_multi_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "Color Profiles", - info8.color_profiles, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "InfPath", - info8.inf_path, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_dword(tmp_ctx, - winreg_handle, - &key_hnd, - "PrinterDriverAttributes", - info8.printer_driver_attributes, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - status = dcerpc_winreg_set_multi_sz(tmp_ctx, - winreg_handle, - &key_hnd, - "CoreDependencies", - info8.core_driver_dependencies, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - result = winreg_printer_write_date(tmp_ctx, winreg_handle, - &key_hnd, "MinInboxDriverVerDate", - info8.min_inbox_driver_ver_date); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - result = winreg_printer_write_ver(tmp_ctx, winreg_handle, &key_hnd, - "MinInboxDriverVerVersion", - info8.min_inbox_driver_ver_version); - if (!W_ERROR_IS_OK(result)) { - goto done; - } - - *driver_name = info8.driver_name; - *driver_version = info8.version; - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_get_driver(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *architecture, - const char *driver_name, - uint32_t driver_version, - struct spoolss_DriverInfo8 **_info8) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - struct spoolss_DriverInfo8 i8, *info8; - struct spoolss_PrinterEnumValues *enum_values = NULL; - struct spoolss_PrinterEnumValues *v; - uint32_t num_values = 0; - TALLOC_CTX *tmp_ctx; - WERROR result; - uint32_t i; - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - ZERO_STRUCT(i8); - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - if (driver_version == DRIVER_ANY_VERSION) { - /* look for Win2k first and then for NT4 */ - result = winreg_printer_opendriver(tmp_ctx, - server_info, - msg_ctx, - driver_name, - architecture, - 3, - access_mask, false, - &winreg_handle, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - result = winreg_printer_opendriver(tmp_ctx, - server_info, - msg_ctx, - driver_name, - architecture, - 2, - access_mask, false, - &winreg_handle, - &hive_hnd, - &key_hnd); - } - } else { - /* ok normal case */ - result = winreg_printer_opendriver(tmp_ctx, - server_info, - msg_ctx, - driver_name, - architecture, - driver_version, - access_mask, false, - &winreg_handle, - &hive_hnd, - &key_hnd); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(5, ("winreg_get_driver: " - "Could not open driver key (%s,%s,%d): %s\n", - driver_name, architecture, - driver_version, win_errstr(result))); - goto done; - } - - result = winreg_printer_enumvalues(tmp_ctx, - winreg_handle, - &key_hnd, - &num_values, - &enum_values); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_get_driver: " - "Could not enumerate values for (%s,%s,%d): %s\n", - driver_name, architecture, - driver_version, win_errstr(result))); - goto done; - } - - info8 = talloc_zero(tmp_ctx, struct spoolss_DriverInfo8); - if (info8 == NULL) { - result = WERR_NOMEM; - goto done; - } - - info8->driver_name = talloc_strdup(info8, driver_name); - if (info8->driver_name == NULL) { - result = WERR_NOMEM; - goto done; - } - - info8->architecture = talloc_strdup(info8, architecture); - if (info8->architecture == NULL) { - result = WERR_NOMEM; - goto done; - } - - result = WERR_OK; - - for (i = 0; i < num_values; i++) { - const char *tmp_str; - uint32_t tmp = 0; - - v = &enum_values[i]; - - result = winreg_enumval_to_dword(info8, v, - "Version", - &tmp); - if (NT_STATUS_IS_OK(result)) { - info8->version = (enum spoolss_DriverOSVersion) tmp; - } - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Driver", - &info8->driver_path); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Data File", - &info8->data_file); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Configuration File", - &info8->config_file); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Help File", - &info8->help_file); - CHECK_ERROR(result); - - result = winreg_enumval_to_multi_sz(info8, v, - "Dependent Files", - &info8->dependent_files); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Monitor", - &info8->monitor_name); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Datatype", - &info8->default_datatype); - CHECK_ERROR(result); - - result = winreg_enumval_to_multi_sz(info8, v, - "Previous Names", - &info8->previous_names); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "DriverDate", - &tmp_str); - if (W_ERROR_IS_OK(result)) { - result = winreg_printer_date_to_NTTIME(tmp_str, - &info8->driver_date); - } - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "DriverVersion", - &tmp_str); - if (W_ERROR_IS_OK(result)) { - result = winreg_printer_ver_to_dword(tmp_str, - &info8->driver_version); - } - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Manufacturer", - &info8->manufacturer_name); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "OEM URL", - &info8->manufacturer_url); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "HardwareID", - &info8->hardware_id); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Provider", - &info8->provider); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "Print Processor", - &info8->print_processor); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "VendorSetup", - &info8->vendor_setup); - CHECK_ERROR(result); - - result = winreg_enumval_to_multi_sz(info8, v, - "Color Profiles", - &info8->color_profiles); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "InfPath", - &info8->inf_path); - CHECK_ERROR(result); - - result = winreg_enumval_to_dword(info8, v, - "PrinterDriverAttributes", - &info8->printer_driver_attributes); - CHECK_ERROR(result); - - result = winreg_enumval_to_multi_sz(info8, v, - "CoreDependencies", - &info8->core_driver_dependencies); - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "MinInboxDriverVerDate", - &tmp_str); - if (W_ERROR_IS_OK(result)) { - result = winreg_printer_date_to_NTTIME(tmp_str, - &info8->min_inbox_driver_ver_date); - } - CHECK_ERROR(result); - - result = winreg_enumval_to_sz(info8, v, - "MinInboxDriverVerVersion", - &tmp_str); - if (W_ERROR_IS_OK(result)) { - result = winreg_printer_ver_to_dword(tmp_str, - &info8->min_inbox_driver_ver_version); - } - CHECK_ERROR(result); - } - - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_enumval_to_TYPE() failed " - "for %s: %s\n", v->value_name, - win_errstr(result))); - goto done; - } - - *_info8 = talloc_steal(mem_ctx, info8); - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_del_driver(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct spoolss_DriverInfo8 *info8, - uint32_t version) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - TALLOC_CTX *tmp_ctx; - char *key_name; - WERROR result; - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - /* test that the key exists */ - result = winreg_printer_opendriver(tmp_ctx, - server_info, - msg_ctx, - info8->driver_name, - info8->architecture, - version, - access_mask, false, - &winreg_handle, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - /* key doesn't exist */ - if (W_ERROR_EQUAL(result, WERR_BADFILE)) { - result = WERR_OK; - goto done; - } - - DEBUG(5, ("winreg_del_driver: " - "Could not open driver (%s,%s,%u): %s\n", - info8->driver_name, info8->architecture, - version, win_errstr(result))); - goto done; - } - - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &result); - } - - key_name = talloc_asprintf(tmp_ctx, - "%s\\Environments\\%s\\Drivers\\Version-%u\\%s", - TOP_LEVEL_CONTROL_KEY, - info8->architecture, version, - info8->driver_name); - if (key_name == NULL) { - result = WERR_NOMEM; - goto done; - } - - result = winreg_printer_delete_subkeys(tmp_ctx, - winreg_handle, - &hive_hnd, - access_mask, - key_name); - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_del_driver: " - "Could not open driver (%s,%s,%u): %s\n", - info8->driver_name, info8->architecture, - version, win_errstr(result))); - goto done; - } - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - -WERROR winreg_get_driver_list(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *architecture, - uint32_t version, - uint32_t *num_drivers, - const char ***drivers_p) -{ - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct dcerpc_binding_handle *winreg_handle = NULL; - struct policy_handle hive_hnd, key_hnd; - const char **drivers; - TALLOC_CTX *tmp_ctx; - WERROR result; - NTSTATUS status; - - *num_drivers = 0; - *drivers_p = NULL; - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return WERR_NOMEM; - } - - /* use NULL for the driver name so we open the key that is - * parent of all drivers for this architecture and version */ - result = winreg_printer_opendriver(tmp_ctx, - server_info, - msg_ctx, - NULL, - architecture, - version, - access_mask, false, - &winreg_handle, - &hive_hnd, - &key_hnd); - if (!W_ERROR_IS_OK(result)) { - DEBUG(5, ("winreg_get_driver_list: " - "Could not open key (%s,%u): %s\n", - architecture, version, win_errstr(result))); - result = WERR_OK; - goto done; - } - - status = dcerpc_winreg_enum_keys(tmp_ctx, - winreg_handle, - &key_hnd, - num_drivers, - &drivers, - &result); - if (!NT_STATUS_IS_OK(status)) { - result = ntstatus_to_werror(status); - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("winreg_get_driver_list: " - "Could not enumerate drivers for (%s,%u): %s\n", - architecture, version, win_errstr(result))); - goto done; - } - - *drivers_p = talloc_steal(mem_ctx, drivers); - - result = WERR_OK; -done: - if (winreg_handle != NULL) { - WERROR ignore; - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &key_hnd, &ignore); - } - if (is_valid_policy_hnd(&hive_hnd)) { - dcerpc_winreg_CloseKey(winreg_handle, tmp_ctx, &hive_hnd, &ignore); - } - } - - TALLOC_FREE(tmp_ctx); - return result; -} - diff --git a/source3/rpc_server/srv_spoolss_util.h b/source3/rpc_server/srv_spoolss_util.h deleted file mode 100644 index d425bd1bba..0000000000 --- a/source3/rpc_server/srv_spoolss_util.h +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * SPOOLSS RPC Pipe server / winreg client routines - * - * Copyright (c) 2010 Andreas Schneider - * - * 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 . - */ - -#ifndef _SRV_SPOOLSS_UITL_H -#define _SRV_SPOOLSS_UITL_H - - -enum spoolss_PrinterInfo2Mask { - SPOOLSS_PRINTER_INFO_ATTRIBUTES = (int)(0x00000001), - SPOOLSS_PRINTER_INFO_AVERAGEPPM = (int)(0x00000002), - SPOOLSS_PRINTER_INFO_CJOBS = (int)(0x00000004), - SPOOLSS_PRINTER_INFO_COMMENT = (int)(0x00000008), - SPOOLSS_PRINTER_INFO_DATATYPE = (int)(0x00000010), - SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY = (int)(0x00000020), - SPOOLSS_PRINTER_INFO_DEVMODE = (int)(0x00000040), - SPOOLSS_PRINTER_INFO_DRIVERNAME = (int)(0x00000080), - SPOOLSS_PRINTER_INFO_LOCATION = (int)(0x00000100), - SPOOLSS_PRINTER_INFO_NAME = (int)(0x00000200), - SPOOLSS_PRINTER_INFO_PARAMETERS = (int)(0x00000400), - SPOOLSS_PRINTER_INFO_PORTNAME = (int)(0x00000800), - SPOOLSS_PRINTER_INFO_PRINTERNAME = (int)(0x00001000), - SPOOLSS_PRINTER_INFO_PRINTPROCESSOR = (int)(0x00002000), - SPOOLSS_PRINTER_INFO_PRIORITY = (int)(0x00004000), - SPOOLSS_PRINTER_INFO_SECDESC = (int)(0x00008000), - SPOOLSS_PRINTER_INFO_SEPFILE = (int)(0x00010000), - SPOOLSS_PRINTER_INFO_SERVERNAME = (int)(0x00020000), - SPOOLSS_PRINTER_INFO_SHARENAME = (int)(0x00040000), - SPOOLSS_PRINTER_INFO_STARTTIME = (int)(0x00080000), - SPOOLSS_PRINTER_INFO_STATUS = (int)(0x00100000), - SPOOLSS_PRINTER_INFO_UNTILTIME = (int)(0x00200000) -}; - -#define SPOOLSS_PRINTER_INFO_ALL SPOOLSS_PRINTER_INFO_ATTRIBUTES | \ - SPOOLSS_PRINTER_INFO_AVERAGEPPM | \ - SPOOLSS_PRINTER_INFO_CJOBS | \ - SPOOLSS_PRINTER_INFO_COMMENT | \ - SPOOLSS_PRINTER_INFO_DATATYPE | \ - SPOOLSS_PRINTER_INFO_DEFAULTPRIORITY | \ - SPOOLSS_PRINTER_INFO_DEVMODE | \ - SPOOLSS_PRINTER_INFO_DRIVERNAME | \ - SPOOLSS_PRINTER_INFO_LOCATION | \ - SPOOLSS_PRINTER_INFO_NAME | \ - SPOOLSS_PRINTER_INFO_PARAMETERS | \ - SPOOLSS_PRINTER_INFO_PORTNAME | \ - SPOOLSS_PRINTER_INFO_PRINTERNAME | \ - SPOOLSS_PRINTER_INFO_PRINTPROCESSOR | \ - SPOOLSS_PRINTER_INFO_PRIORITY | \ - SPOOLSS_PRINTER_INFO_SECDESC | \ - SPOOLSS_PRINTER_INFO_SEPFILE | \ - SPOOLSS_PRINTER_INFO_SERVERNAME | \ - SPOOLSS_PRINTER_INFO_SHARENAME | \ - SPOOLSS_PRINTER_INFO_STARTTIME | \ - SPOOLSS_PRINTER_INFO_STATUS | \ - SPOOLSS_PRINTER_INFO_UNTILTIME - -WERROR winreg_create_printer(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename); - -/** - * @internal - * - * @brief Update the information of a printer in the registry. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] sharename The share name. - * - * @param[in] info2_mask A bitmask which defines which values should be set. - * - * @param[in] info2 A SetPrinterInfo2 structure with the data to set. - * - * @param[in] devmode A device mode structure with the data to set. - * - * @param[in] secdesc A security descriptor structure with the data to set. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_update_printer(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename, - uint32_t info2_mask, - struct spoolss_SetPrinterInfo2 *info2, - struct spoolss_DeviceMode *devmode, - struct security_descriptor *secdesc); - - -/** - * @brief Get the inforamtion of a printer stored in the registry. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The name of the printer to get. - * - * @param[out] pinfo2 A pointer to store a PRINTER_INFO_2 structure. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_get_printer(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - struct spoolss_PrinterInfo2 **pinfo2); - -/** - * @brief Get the security descriptor for a printer. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] sharename The share name. - * - * @param[out] psecdesc A pointer to store the security descriptor. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_get_printer_secdesc(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename, - struct spoolss_security_descriptor **psecdesc); - -/** - * @brief Set the security descriptor for a printer. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] sharename The share name. - * - * @param[in] secdesc The security descriptor to save. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_set_printer_secdesc(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *sharename, - const struct spoolss_security_descriptor *secdesc); - -/** - * @internal - * - * @brief Set printer data over the winreg pipe. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @param[in] key The key of the printer data to store the value. - * - * @param[in] value The value name to save. - * - * @param[in] type The type of the value to use. - * - * @param[in] data The data which sould be saved under the given value. - * - * @param[in] data_size The size of the data. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_set_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - const char *value, - enum winreg_Type type, - uint8_t *data, - uint32_t data_size); - -/** - * @internal - * - * @brief Get printer data over a winreg pipe. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @param[in] key The key of the printer data to get the value. - * - * @param[in] value The name of the value to query. - * - * @param[in] type The type of the value to query. - * - * @param[out] data A pointer to store the data. - * - * @param[out] data_size A pointer to store the size of the data. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_get_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - const char *value, - enum winreg_Type *type, - uint8_t **data, - uint32_t *data_size); - -/** - * @internal - * - * @brief Enumerate on the values of a given key and provide the data. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @param[in] key The key of the printer data to get the value. - * - * @param[out] pnum_values A pointer to store the number of values we found. - * - * @param[out] penum_values A pointer to store the values and its data. - * - * @return WERR_OK on success, the corresponding DOS error - * code if something gone wrong. - */ -WERROR winreg_enum_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - uint32_t *pnum_values, - struct spoolss_PrinterEnumValues **penum_values); - -/** - * @internal - * - * @brief Delete printer data over a winreg pipe. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @param[in] key The key of the printer data to delete. - * - * @param[in] value The name of the value to delete. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_delete_printer_dataex(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - const char *value); - -/** - * @internal - * - * @brief Enumerate on the subkeys of a given key and provide the data. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @param[in] key The key of the printer data to get the value. - * - * @param[out] pnum_subkeys A pointer to store the number of subkeys found. - * - * @param[in] psubkeys A pointer to an array to store the names of the subkeys - * found. - * - * @return WERR_OK on success, the corresponding DOS error - * code if something gone wrong. - */ -WERROR winreg_enum_printer_key(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key, - uint32_t *pnum_subkeys, - const char ***psubkeys); - -/** - * @internal - * - * @brief Delete a key with subkeys of a given printer. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @param[in] key The key of the printer to delete. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_delete_printer_key(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - const char *key); - -/** - * @brief Update the ChangeID of a printer. - * - * The ChangeID **must** be increasing over the lifetime of client's spoolss - * service in order for the client's cache to show updates. - * - * If a form is updated of a printer, the we need to update the ChangeID of the - * pritner. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_printer_update_changeid(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer); - -/** - * @brief Get the ChangeID of the given printer. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] printer The printer name. - * - * @param[in] changeid A pointer to store the changeid. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_printer_get_changeid(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *printer, - uint32_t *pchangeid); - -/** - * @internal - * - * @brief This function adds a form to the list of available forms that can be - * selected for the specified printer. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] form The form to add. - * - * @return WERR_OK on success. - * WERR_ALREADY_EXISTS if the form already exists or is a - * builtin form. - * A corresponding DOS error is something went wrong. - */ -WERROR winreg_printer_addform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct spoolss_AddFormInfo1 *form); - -/* - * @brief This function enumerates the forms supported by the specified printer. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[out] pnum_info A pointer to store the FormInfo count. - * - * @param[out] pinfo A pointer to store an array with FormInfo. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_printer_enumforms1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - uint32_t *pnum_info, - union spoolss_FormInfo **pinfo); - -/** - * @brief This function removes a form name from the list of supported forms. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] form_name The name of the form to delete. - * - * @return WERR_OK on success. - * WERR_INVALID_PARAM if the form is a builtin form. - * WERR_INVALID_FORM_NAME if the form or key doesn't exist. - * A corresponding DOS error is something went wrong. - */ -WERROR winreg_printer_deleteform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *form_name); - -/** - * @brief This function sets the form information for the specified printer. - * - * If one provides both the name in the API call and inside the FormInfo - * structure, then the form gets renamed. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] form_name The name of the form to set or rename. - * - * @param[in] form The FormInfo structure to save. - * - * @return WERR_OK on success. - * WERR_INVALID_PARAM if the form is a builtin form. - * A corresponding DOS error is something went wrong. - */ -WERROR winreg_printer_setform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *form_name, - struct spoolss_AddFormInfo1 *form); - -/** - * @brief This function retrieves information about a specified form. - * - * @param[in] mem_ctx The talloc memory context to use. - * - * @param[in] server_info The server supplied session info. - * - * @param[in] form_name The name of the form to query. - * - * @param[out] form A pointer to a form structure to fill out. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_printer_getform1(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *form_name, - struct spoolss_FormInfo1 *form); - -/** - * @brief This function adds a new spool driver - * - * @param[in] mem_ctx A talloc memory context. - * - * @param[in] server_info Auth info to open the pipe. - * - * @param[in] r The structure containing the new driver data. - * - * @param[out] driver_name Returns the driver name. - * - * @param[out] driver_version Returns the driver version. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ -WERROR winreg_add_driver(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct spoolss_AddDriverInfoCtr *r, - const char **driver_name, - uint32_t *driver_version); - -/** - * @brief This function gets printer driver information - * - * @param[in] mem_ctx A talloc memory context. - * - * @param[in] server_info Auth info to open the pipe. - * - * @param[in] architecture The architecture type. - * - * @param[in] driver_name The driver name. - * - * @param[in] driver_version The driver version. - * - * @param[out] _info8 The structure that holds the full driver information. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ - -WERROR winreg_get_driver(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *architecture, - const char *driver_name, - uint32_t driver_version, - struct spoolss_DriverInfo8 **_info8); - -/** - * @brief This function deletes a printer driver information - * - * @param[in] mem_ctx A talloc memory context. - * - * @param[in] server_info Auth info to open the pipe. - * - * @param[out] info8 The structure that holds the full driver information. - * - * @param[in] version The driver type version. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ - -WERROR winreg_del_driver(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - struct spoolss_DriverInfo8 *info8, - uint32_t version); - -/** - * @brief This function gets printer drivers list for the specified - * architecture and type version - * - * @param[in] mem_ctx A talloc memory context. - * - * @param[in] server_info Auth info to open the pipe. - * - * @param[in] architecture The architecture type. - * - * @param[in] version The driver version. - * - * @param[out] num_drivers The number of drivers. - * - * @param[out] version The drivers names. - * - * @return On success WERR_OK, a corresponding DOS error is - * something went wrong. - */ - -WERROR winreg_get_driver_list(TALLOC_CTX *mem_ctx, - const struct auth_serversupplied_info *server_info, - struct messaging_context *msg_ctx, - const char *architecture, - uint32_t version, - uint32_t *num_drivers, - const char ***drivers); - -#endif /* _SRV_SPOOLSS_UITL_H */ diff --git a/source3/rpc_server/srv_srvsvc_nt.c b/source3/rpc_server/srv_srvsvc_nt.c deleted file mode 100644 index d5858ca418..0000000000 --- a/source3/rpc_server/srv_srvsvc_nt.c +++ /dev/null @@ -1,2820 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1997, - * Copyright (C) Jeremy Allison 2001. - * Copyright (C) Nigel Williams 2001. - * Copyright (C) Gerald (Jerry) Carter 2006. - * Copyright (C) Guenther Deschner 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 . - */ - -/* This is the implementation of the srvsvc pipe. */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_srvsvc.h" -#include "librpc/gen_ndr/messaging.h" -#include "../libcli/security/security.h" -#include "../librpc/gen_ndr/ndr_security.h" -#include "dbwrap.h" - -extern const struct generic_mapping file_generic_mapping; - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -#define MAX_SERVER_DISK_ENTRIES 15 - -/* Use for enumerating connections, pipes, & files */ - -struct file_enum_count { - TALLOC_CTX *ctx; - const char *username; - struct srvsvc_NetFileCtr3 *ctr3; -}; - -struct sess_file_count { - struct server_id pid; - uid_t uid; - int count; -}; - -/**************************************************************************** - Count the entries belonging to a service in the connection db. -****************************************************************************/ - -static int pipe_enum_fn( struct db_record *rec, void *p) -{ - struct pipe_open_rec prec; - struct file_enum_count *fenum = (struct file_enum_count *)p; - struct srvsvc_NetFileInfo3 *f; - int i = fenum->ctr3->count; - char *fullpath = NULL; - const char *username; - - if (rec->value.dsize != sizeof(struct pipe_open_rec)) - return 0; - - memcpy(&prec, rec->value.dptr, sizeof(struct pipe_open_rec)); - - if ( !process_exists(prec.pid) ) { - return 0; - } - - username = uidtoname(prec.uid); - - if ((fenum->username != NULL) - && !strequal(username, fenum->username)) { - return 0; - } - - fullpath = talloc_asprintf(fenum->ctx, "\\PIPE\\%s", prec.name ); - if (!fullpath) { - return 1; - } - - f = TALLOC_REALLOC_ARRAY(fenum->ctx, fenum->ctr3->array, - struct srvsvc_NetFileInfo3, i+1); - if ( !f ) { - DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1)); - return 1; - } - fenum->ctr3->array = f; - - fenum->ctr3->array[i].fid = - (((uint32_t)(procid_to_pid(&prec.pid))<<16) | prec.pnum); - fenum->ctr3->array[i].permissions = - (FILE_READ_DATA|FILE_WRITE_DATA); - fenum->ctr3->array[i].num_locks = 0; - fenum->ctr3->array[i].path = fullpath; - fenum->ctr3->array[i].user = username; - - fenum->ctr3->count++; - - return 0; -} - -/******************************************************************* -********************************************************************/ - -static WERROR net_enum_pipes(TALLOC_CTX *ctx, - const char *username, - struct srvsvc_NetFileCtr3 **ctr3, - uint32_t resume ) -{ - struct file_enum_count fenum; - - fenum.ctx = ctx; - fenum.username = username; - fenum.ctr3 = *ctr3; - - if (connections_traverse(pipe_enum_fn, &fenum) == -1) { - DEBUG(0,("net_enum_pipes: traverse of connections.tdb " - "failed\n")); - return WERR_NOMEM; - } - - *ctr3 = fenum.ctr3; - - return WERR_OK; -} - -/******************************************************************* -********************************************************************/ - -static void enum_file_fn( const struct share_mode_entry *e, - const char *sharepath, const char *fname, - void *private_data ) -{ - struct file_enum_count *fenum = - (struct file_enum_count *)private_data; - - struct srvsvc_NetFileInfo3 *f; - int i = fenum->ctr3->count; - files_struct fsp; - struct byte_range_lock *brl; - int num_locks = 0; - char *fullpath = NULL; - uint32 permissions; - const char *username; - - /* If the pid was not found delete the entry from connections.tdb */ - - if ( !process_exists(e->pid) ) { - return; - } - - username = uidtoname(e->uid); - - if ((fenum->username != NULL) - && !strequal(username, fenum->username)) { - return; - } - - f = TALLOC_REALLOC_ARRAY(fenum->ctx, fenum->ctr3->array, - struct srvsvc_NetFileInfo3, i+1); - if ( !f ) { - DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1)); - return; - } - fenum->ctr3->array = f; - - /* need to count the number of locks on a file */ - - ZERO_STRUCT( fsp ); - fsp.file_id = e->id; - - if ( (brl = brl_get_locks(talloc_tos(), &fsp)) != NULL ) { - num_locks = brl->num_locks; - TALLOC_FREE(brl); - } - - if ( strcmp( fname, "." ) == 0 ) { - fullpath = talloc_asprintf(fenum->ctx, "C:%s", sharepath ); - } else { - fullpath = talloc_asprintf(fenum->ctx, "C:%s/%s", - sharepath, fname ); - } - if (!fullpath) { - return; - } - string_replace( fullpath, '/', '\\' ); - - /* mask out create (what ever that is) */ - permissions = e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA); - - /* now fill in the srvsvc_NetFileInfo3 struct */ - - fenum->ctr3->array[i].fid = - (((uint32_t)(procid_to_pid(&e->pid))<<16) | e->share_file_id); - fenum->ctr3->array[i].permissions = permissions; - fenum->ctr3->array[i].num_locks = num_locks; - fenum->ctr3->array[i].path = fullpath; - fenum->ctr3->array[i].user = username; - - fenum->ctr3->count++; -} - -/******************************************************************* -********************************************************************/ - -static WERROR net_enum_files(TALLOC_CTX *ctx, - const char *username, - struct srvsvc_NetFileCtr3 **ctr3, - uint32_t resume) -{ - struct file_enum_count f_enum_cnt; - - f_enum_cnt.ctx = ctx; - f_enum_cnt.username = username; - f_enum_cnt.ctr3 = *ctr3; - - share_mode_forall( enum_file_fn, (void *)&f_enum_cnt ); - - *ctr3 = f_enum_cnt.ctr3; - - return WERR_OK; -} - -/******************************************************************* - Utility function to get the 'type' of a share from an snum. - ********************************************************************/ -static uint32 get_share_type(int snum) -{ - /* work out the share type */ - uint32 type = STYPE_DISKTREE; - - if (lp_print_ok(snum)) - type = STYPE_PRINTQ; - if (strequal(lp_fstype(snum), "IPC")) - type = STYPE_IPC; - if (lp_administrative_share(snum)) - type |= STYPE_HIDDEN; - - return type; -} - -/******************************************************************* - Fill in a share info level 0 structure. - ********************************************************************/ - -static void init_srv_share_info_0(struct pipes_struct *p, - struct srvsvc_NetShareInfo0 *r, int snum) -{ - r->name = lp_servicename(snum); -} - -/******************************************************************* - Fill in a share info level 1 structure. - ********************************************************************/ - -static void init_srv_share_info_1(struct pipes_struct *p, - struct srvsvc_NetShareInfo1 *r, - int snum) -{ - char *net_name = lp_servicename(snum); - char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); - - if (remark) { - remark = talloc_sub_advanced( - p->mem_ctx, lp_servicename(snum), - get_current_username(), lp_pathname(snum), - p->server_info->utok.uid, get_current_username(), - "", remark); - } - - r->name = net_name; - r->type = get_share_type(snum); - r->comment = remark ? remark : ""; -} - -/******************************************************************* - Fill in a share info level 2 structure. - ********************************************************************/ - -static void init_srv_share_info_2(struct pipes_struct *p, - struct srvsvc_NetShareInfo2 *r, - int snum) -{ - char *remark = NULL; - char *path = NULL; - int max_connections = lp_max_connections(snum); - uint32_t max_uses = max_connections!=0 ? max_connections : (uint32_t)-1; - char *net_name = lp_servicename(snum); - - remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); - if (remark) { - remark = talloc_sub_advanced( - p->mem_ctx, lp_servicename(snum), - get_current_username(), lp_pathname(snum), - p->server_info->utok.uid, get_current_username(), - "", remark); - } - path = talloc_asprintf(p->mem_ctx, - "C:%s", lp_pathname(snum)); - - if (path) { - /* - * Change / to \\ so that win2k will see it as a valid path. - * This was added to enable use of browsing in win2k add - * share dialog. - */ - - string_replace(path, '/', '\\'); - } - - r->name = net_name; - r->type = get_share_type(snum); - r->comment = remark ? remark : ""; - r->permissions = 0; - r->max_users = max_uses; - r->current_users = count_current_connections(net_name, false); - r->path = path ? path : ""; - r->password = ""; -} - -/******************************************************************* - Map any generic bits to file specific bits. -********************************************************************/ - -static void map_generic_share_sd_bits(struct security_descriptor *psd) -{ - int i; - struct security_acl *ps_dacl = NULL; - - if (!psd) - return; - - ps_dacl = psd->dacl; - if (!ps_dacl) - return; - - for (i = 0; i < ps_dacl->num_aces; i++) { - struct security_ace *psa = &ps_dacl->aces[i]; - uint32 orig_mask = psa->access_mask; - - se_map_generic(&psa->access_mask, &file_generic_mapping); - psa->access_mask |= orig_mask; - } -} - -/******************************************************************* - Fill in a share info level 501 structure. -********************************************************************/ - -static void init_srv_share_info_501(struct pipes_struct *p, - struct srvsvc_NetShareInfo501 *r, int snum) -{ - const char *net_name = lp_servicename(snum); - char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); - - if (remark) { - remark = talloc_sub_advanced( - p->mem_ctx, lp_servicename(snum), - get_current_username(), lp_pathname(snum), - p->server_info->utok.uid, get_current_username(), - "", remark); - } - - r->name = net_name; - r->type = get_share_type(snum); - r->comment = remark ? remark : ""; - r->csc_policy = (lp_csc_policy(snum) << 4); -} - -/******************************************************************* - Fill in a share info level 502 structure. - ********************************************************************/ - -static void init_srv_share_info_502(struct pipes_struct *p, - struct srvsvc_NetShareInfo502 *r, int snum) -{ - const char *net_name = lp_servicename(snum); - char *path = NULL; - struct security_descriptor *sd = NULL; - struct sec_desc_buf *sd_buf = NULL; - size_t sd_size = 0; - TALLOC_CTX *ctx = p->mem_ctx; - char *remark = talloc_strdup(ctx, lp_comment(snum)); - - if (remark) { - remark = talloc_sub_advanced( - p->mem_ctx, lp_servicename(snum), - get_current_username(), lp_pathname(snum), - p->server_info->utok.uid, get_current_username(), - "", remark); - } - path = talloc_asprintf(ctx, "C:%s", lp_pathname(snum)); - if (path) { - /* - * Change / to \\ so that win2k will see it as a valid path. This was added to - * enable use of browsing in win2k add share dialog. - */ - string_replace(path, '/', '\\'); - } - - sd = get_share_security(ctx, lp_servicename(snum), &sd_size); - - sd_buf = make_sec_desc_buf(p->mem_ctx, sd_size, sd); - - r->name = net_name; - r->type = get_share_type(snum); - r->comment = remark ? remark : ""; - r->permissions = 0; - r->max_users = (uint32_t)-1; - r->current_users = 1; /* ??? */ - r->path = path ? path : ""; - r->password = ""; - r->sd_buf = *sd_buf; -} - -/*************************************************************************** - Fill in a share info level 1004 structure. - ***************************************************************************/ - -static void init_srv_share_info_1004(struct pipes_struct *p, - struct srvsvc_NetShareInfo1004 *r, - int snum) -{ - char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); - - if (remark) { - remark = talloc_sub_advanced( - p->mem_ctx, lp_servicename(snum), - get_current_username(), lp_pathname(snum), - p->server_info->utok.uid, get_current_username(), - "", remark); - } - - r->comment = remark ? remark : ""; -} - -/*************************************************************************** - Fill in a share info level 1005 structure. - ***************************************************************************/ - -static void init_srv_share_info_1005(struct pipes_struct *p, - struct srvsvc_NetShareInfo1005 *r, - int snum) -{ - uint32_t dfs_flags = 0; - - if (lp_host_msdfs() && lp_msdfs_root(snum)) { - dfs_flags |= SHARE_1005_IN_DFS | SHARE_1005_DFS_ROOT; - } - - dfs_flags |= lp_csc_policy(snum) << SHARE_1005_CSC_POLICY_SHIFT; - - r->dfs_flags = dfs_flags; -} - -/*************************************************************************** - Fill in a share info level 1006 structure. - ***************************************************************************/ - -static void init_srv_share_info_1006(struct pipes_struct *p, - struct srvsvc_NetShareInfo1006 *r, - int snum) -{ - r->max_users = (uint32_t)-1; -} - -/*************************************************************************** - Fill in a share info level 1007 structure. - ***************************************************************************/ - -static void init_srv_share_info_1007(struct pipes_struct *p, - struct srvsvc_NetShareInfo1007 *r, - int snum) -{ - r->flags = 0; - r->alternate_directory_name = ""; -} - -/******************************************************************* - Fill in a share info level 1501 structure. - ********************************************************************/ - -static void init_srv_share_info_1501(struct pipes_struct *p, - struct sec_desc_buf *r, - int snum) -{ - struct security_descriptor *sd; - size_t sd_size; - TALLOC_CTX *ctx = p->mem_ctx; - - sd = get_share_security(ctx, lp_servicename(snum), &sd_size); - - r = make_sec_desc_buf(p->mem_ctx, sd_size, sd); -} - -/******************************************************************* - True if it ends in '$'. - ********************************************************************/ - -static bool is_hidden_share(int snum) -{ - const char *net_name = lp_servicename(snum); - - return (net_name[strlen(net_name) - 1] == '$') ? True : False; -} - -/******************************************************************* - Verify user is allowed to view share, access based enumeration -********************************************************************/ -static bool is_enumeration_allowed(struct pipes_struct *p, - int snum) -{ - if (!lp_access_based_share_enum(snum)) - return true; - - return share_access_check(p->server_info->security_token, lp_servicename(snum), - FILE_READ_DATA); -} - -/******************************************************************* - Fill in a share info structure. - ********************************************************************/ - -static WERROR init_srv_share_info_ctr(struct pipes_struct *p, - struct srvsvc_NetShareInfoCtr *info_ctr, - uint32_t *resume_handle_p, - uint32_t *total_entries, - bool all_shares) -{ - int num_entries = 0; - int alloc_entries = 0; - int num_services = 0; - int snum; - TALLOC_CTX *ctx = p->mem_ctx; - int i = 0; - int valid_share_count = 0; - bool *allowed = 0; - union srvsvc_NetShareCtr ctr; - uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; - - DEBUG(5,("init_srv_share_info_ctr\n")); - - /* Ensure all the usershares are loaded. */ - become_root(); - load_usershare_shares(); - load_registry_shares(); - num_services = lp_numservices(); - unbecome_root(); - - allowed = TALLOC_ZERO_ARRAY(ctx, bool, num_services); - W_ERROR_HAVE_NO_MEMORY(allowed); - - /* Count the number of entries. */ - for (snum = 0; snum < num_services; snum++) { - if (lp_browseable(snum) && lp_snum_ok(snum) && - is_enumeration_allowed(p, snum) && - (all_shares || !is_hidden_share(snum)) ) { - DEBUG(10, ("counting service %s\n", - lp_servicename(snum) ? lp_servicename(snum) : "(null)")); - allowed[snum] = true; - num_entries++; - } else { - DEBUG(10, ("NOT counting service %s\n", - lp_servicename(snum) ? lp_servicename(snum) : "(null)")); - } - } - - if (!num_entries || (resume_handle >= num_entries)) { - return WERR_OK; - } - - /* Calculate alloc entries. */ - alloc_entries = num_entries - resume_handle; - switch (info_ctr->level) { - case 0: - ctr.ctr0 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr0); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr0); - - ctr.ctr0->count = alloc_entries; - ctr.ctr0->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo0, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr0->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_0(p, &ctr.ctr0->array[i++], snum); - } - } - - break; - - case 1: - ctr.ctr1 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1); - - ctr.ctr1->count = alloc_entries; - ctr.ctr1->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_1(p, &ctr.ctr1->array[i++], snum); - } - } - - break; - - case 2: - ctr.ctr2 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr2); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr2); - - ctr.ctr2->count = alloc_entries; - ctr.ctr2->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo2, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr2->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_2(p, &ctr.ctr2->array[i++], snum); - } - } - - break; - - case 501: - ctr.ctr501 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr501); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr501); - - ctr.ctr501->count = alloc_entries; - ctr.ctr501->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo501, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr501->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_501(p, &ctr.ctr501->array[i++], snum); - } - } - - break; - - case 502: - ctr.ctr502 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr502); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr502); - - ctr.ctr502->count = alloc_entries; - ctr.ctr502->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo502, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr502->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_502(p, &ctr.ctr502->array[i++], snum); - } - } - - break; - - case 1004: - ctr.ctr1004 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1004); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1004); - - ctr.ctr1004->count = alloc_entries; - ctr.ctr1004->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1004, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1004->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_1004(p, &ctr.ctr1004->array[i++], snum); - } - } - - break; - - case 1005: - ctr.ctr1005 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1005); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1005); - - ctr.ctr1005->count = alloc_entries; - ctr.ctr1005->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1005, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1005->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_1005(p, &ctr.ctr1005->array[i++], snum); - } - } - - break; - - case 1006: - ctr.ctr1006 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1006); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1006); - - ctr.ctr1006->count = alloc_entries; - ctr.ctr1006->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1006, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1006->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_1006(p, &ctr.ctr1006->array[i++], snum); - } - } - - break; - - case 1007: - ctr.ctr1007 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1007); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1007); - - ctr.ctr1007->count = alloc_entries; - ctr.ctr1007->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1007, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1007->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_1007(p, &ctr.ctr1007->array[i++], snum); - } - } - - break; - - case 1501: - ctr.ctr1501 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1501); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1501); - - ctr.ctr1501->count = alloc_entries; - ctr.ctr1501->array = TALLOC_ZERO_ARRAY(ctx, struct sec_desc_buf, alloc_entries); - W_ERROR_HAVE_NO_MEMORY(ctr.ctr1501->array); - - for (snum = 0; snum < num_services; snum++) { - if (allowed[snum] && - (resume_handle <= (i + valid_share_count++)) ) { - init_srv_share_info_1501(p, &ctr.ctr1501->array[i++], snum); - } - } - - break; - - default: - DEBUG(5,("init_srv_share_info_ctr: unsupported switch value %d\n", - info_ctr->level)); - return WERR_UNKNOWN_LEVEL; - } - - *total_entries = alloc_entries; - if (resume_handle_p) { - if (all_shares) { - *resume_handle_p = (num_entries == 0) ? *resume_handle_p : 0; - } else { - *resume_handle_p = num_entries; - } - } - - info_ctr->ctr = ctr; - - return WERR_OK; -} - -/******************************************************************* - fill in a sess info level 0 structure. - ********************************************************************/ - -static WERROR init_srv_sess_info_0(struct pipes_struct *p, - struct srvsvc_NetSessCtr0 *ctr0, - uint32_t *resume_handle_p, - uint32_t *total_entries) -{ - struct sessionid *session_list; - uint32_t num_entries = 0; - uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; - *total_entries = list_sessions(p->mem_ctx, &session_list); - - DEBUG(5,("init_srv_sess_info_0\n")); - - if (ctr0 == NULL) { - if (resume_handle_p) { - *resume_handle_p = 0; - } - return WERR_OK; - } - - for (; resume_handle < *total_entries; resume_handle++) { - - ctr0->array = TALLOC_REALLOC_ARRAY(p->mem_ctx, - ctr0->array, - struct srvsvc_NetSessInfo0, - num_entries+1); - W_ERROR_HAVE_NO_MEMORY(ctr0->array); - - ctr0->array[num_entries].client = - session_list[resume_handle].remote_machine; - - num_entries++; - } - - ctr0->count = num_entries; - - if (resume_handle_p) { - if (*resume_handle_p >= *total_entries) { - *resume_handle_p = 0; - } else { - *resume_handle_p = resume_handle; - } - } - - return WERR_OK; -} - -/******************************************************************* -********************************************************************/ - -static void sess_file_fn( const struct share_mode_entry *e, - const char *sharepath, const char *fname, - void *data ) -{ - struct sess_file_count *sess = (struct sess_file_count *)data; - - if ( procid_equal(&e->pid, &sess->pid) && (sess->uid == e->uid) ) { - sess->count++; - } - - return; -} - -/******************************************************************* -********************************************************************/ - -static int net_count_files( uid_t uid, struct server_id pid ) -{ - struct sess_file_count s_file_cnt; - - s_file_cnt.count = 0; - s_file_cnt.uid = uid; - s_file_cnt.pid = pid; - - share_mode_forall( sess_file_fn, &s_file_cnt ); - - return s_file_cnt.count; -} - -/******************************************************************* - fill in a sess info level 1 structure. - ********************************************************************/ - -static WERROR init_srv_sess_info_1(struct pipes_struct *p, - struct srvsvc_NetSessCtr1 *ctr1, - uint32_t *resume_handle_p, - uint32_t *total_entries) -{ - struct sessionid *session_list; - uint32_t num_entries = 0; - time_t now = time(NULL); - uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; - - ZERO_STRUCTP(ctr1); - - if (ctr1 == NULL) { - if (resume_handle_p) { - *resume_handle_p = 0; - } - return WERR_OK; - } - - *total_entries = list_sessions(p->mem_ctx, &session_list); - - for (; resume_handle < *total_entries; resume_handle++) { - uint32 num_files; - uint32 connect_time; - struct passwd *pw = sys_getpwnam(session_list[resume_handle].username); - bool guest; - - if ( !pw ) { - DEBUG(10,("init_srv_sess_info_1: failed to find owner: %s\n", - session_list[resume_handle].username)); - continue; - } - - connect_time = (uint32_t)(now - session_list[resume_handle].connect_start); - num_files = net_count_files(pw->pw_uid, session_list[resume_handle].pid); - guest = strequal( session_list[resume_handle].username, lp_guestaccount() ); - - ctr1->array = TALLOC_REALLOC_ARRAY(p->mem_ctx, - ctr1->array, - struct srvsvc_NetSessInfo1, - num_entries+1); - W_ERROR_HAVE_NO_MEMORY(ctr1->array); - - ctr1->array[num_entries].client = session_list[resume_handle].remote_machine; - ctr1->array[num_entries].user = session_list[resume_handle].username; - ctr1->array[num_entries].num_open = num_files; - ctr1->array[num_entries].time = connect_time; - ctr1->array[num_entries].idle_time = 0; - ctr1->array[num_entries].user_flags = guest; - - num_entries++; - } - - ctr1->count = num_entries; - - if (resume_handle_p) { - if (*resume_handle_p >= *total_entries) { - *resume_handle_p = 0; - } else { - *resume_handle_p = resume_handle; - } - } - - return WERR_OK; -} - -/******************************************************************* - fill in a conn info level 0 structure. - ********************************************************************/ - -static WERROR init_srv_conn_info_0(struct srvsvc_NetConnCtr0 *ctr0, - uint32_t *resume_handle_p, - uint32_t *total_entries) -{ - uint32_t num_entries = 0; - uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; - - DEBUG(5,("init_srv_conn_info_0\n")); - - if (ctr0 == NULL) { - if (resume_handle_p) { - *resume_handle_p = 0; - } - return WERR_OK; - } - - *total_entries = 1; - - ZERO_STRUCTP(ctr0); - - for (; resume_handle < *total_entries; resume_handle++) { - - ctr0->array = TALLOC_REALLOC_ARRAY(talloc_tos(), - ctr0->array, - struct srvsvc_NetConnInfo0, - num_entries+1); - if (!ctr0->array) { - return WERR_NOMEM; - } - - ctr0->array[num_entries].conn_id = *total_entries; - - /* move on to creating next connection */ - num_entries++; - } - - ctr0->count = num_entries; - *total_entries = num_entries; - - if (resume_handle_p) { - if (*resume_handle_p >= *total_entries) { - *resume_handle_p = 0; - } else { - *resume_handle_p = resume_handle; - } - } - - return WERR_OK; -} - -/******************************************************************* - fill in a conn info level 1 structure. - ********************************************************************/ - -static WERROR init_srv_conn_info_1(struct srvsvc_NetConnCtr1 *ctr1, - uint32_t *resume_handle_p, - uint32_t *total_entries) -{ - uint32_t num_entries = 0; - uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; - - DEBUG(5,("init_srv_conn_info_1\n")); - - if (ctr1 == NULL) { - if (resume_handle_p) { - *resume_handle_p = 0; - } - return WERR_OK; - } - - *total_entries = 1; - - ZERO_STRUCTP(ctr1); - - for (; resume_handle < *total_entries; resume_handle++) { - - ctr1->array = TALLOC_REALLOC_ARRAY(talloc_tos(), - ctr1->array, - struct srvsvc_NetConnInfo1, - num_entries+1); - if (!ctr1->array) { - return WERR_NOMEM; - } - - ctr1->array[num_entries].conn_id = *total_entries; - ctr1->array[num_entries].conn_type = 0x3; - ctr1->array[num_entries].num_open = 1; - ctr1->array[num_entries].num_users = 1; - ctr1->array[num_entries].conn_time = 3; - ctr1->array[num_entries].user = "dummy_user"; - ctr1->array[num_entries].share = "IPC$"; - - /* move on to creating next connection */ - num_entries++; - } - - ctr1->count = num_entries; - *total_entries = num_entries; - - if (resume_handle_p) { - if (*resume_handle_p >= *total_entries) { - *resume_handle_p = 0; - } else { - *resume_handle_p = resume_handle; - } - } - - return WERR_OK; -} - -/******************************************************************* - _srvsvc_NetFileEnum -*******************************************************************/ - -WERROR _srvsvc_NetFileEnum(struct pipes_struct *p, - struct srvsvc_NetFileEnum *r) -{ - TALLOC_CTX *ctx = NULL; - struct srvsvc_NetFileCtr3 *ctr3; - uint32_t resume_hnd = 0; - WERROR werr; - - switch (r->in.info_ctr->level) { - case 3: - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - if (!nt_token_check_sid(&global_sid_Builtin_Administrators, - p->server_info->security_token)) { - DEBUG(1, ("Enumerating files only allowed for " - "administrators\n")); - return WERR_ACCESS_DENIED; - } - - ctx = talloc_tos(); - ctr3 = r->in.info_ctr->ctr.ctr3; - if (!ctr3) { - werr = WERR_INVALID_PARAM; - goto done; - } - - /* TODO -- Windows enumerates - (b) active pipes - (c) open directories and files */ - - werr = net_enum_files(ctx, r->in.user, &ctr3, resume_hnd); - if (!W_ERROR_IS_OK(werr)) { - goto done; - } - - werr = net_enum_pipes(ctx, r->in.user, &ctr3, resume_hnd); - if (!W_ERROR_IS_OK(werr)) { - goto done; - } - - *r->out.totalentries = ctr3->count; - r->out.info_ctr->ctr.ctr3->array = ctr3->array; - r->out.info_ctr->ctr.ctr3->count = ctr3->count; - - werr = WERR_OK; - - done: - return werr; -} - -/******************************************************************* - _srvsvc_NetSrvGetInfo -********************************************************************/ - -WERROR _srvsvc_NetSrvGetInfo(struct pipes_struct *p, - struct srvsvc_NetSrvGetInfo *r) -{ - WERROR status = WERR_OK; - - DEBUG(5,("_srvsvc_NetSrvGetInfo: %d\n", __LINE__)); - - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to _srvsvc_NetSrvGetInfo\n")); - return WERR_ACCESS_DENIED; - } - - switch (r->in.level) { - - /* Technically level 102 should only be available to - Administrators but there isn't anything super-secret - here, as most of it is made up. */ - - case 102: { - struct srvsvc_NetSrvInfo102 *info102; - - info102 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo102); - if (!info102) { - return WERR_NOMEM; - } - - info102->platform_id = PLATFORM_ID_NT; - info102->server_name = global_myname(); - info102->version_major = lp_major_announce_version(); - info102->version_minor = lp_minor_announce_version(); - info102->server_type = lp_default_server_announce(); - info102->comment = string_truncate(lp_serverstring(), - MAX_SERVER_STRING_LENGTH); - info102->users = 0xffffffff; - info102->disc = 0xf; - info102->hidden = 0; - info102->announce = 240; - info102->anndelta = 3000; - info102->licenses = 100000; - info102->userpath = "C:\\"; - - r->out.info->info102 = info102; - break; - } - case 101: { - struct srvsvc_NetSrvInfo101 *info101; - - info101 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo101); - if (!info101) { - return WERR_NOMEM; - } - - info101->platform_id = PLATFORM_ID_NT; - info101->server_name = global_myname(); - info101->version_major = lp_major_announce_version(); - info101->version_minor = lp_minor_announce_version(); - info101->server_type = lp_default_server_announce(); - info101->comment = string_truncate(lp_serverstring(), - MAX_SERVER_STRING_LENGTH); - - r->out.info->info101 = info101; - break; - } - case 100: { - struct srvsvc_NetSrvInfo100 *info100; - - info100 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo100); - if (!info100) { - return WERR_NOMEM; - } - - info100->platform_id = PLATFORM_ID_NT; - info100->server_name = global_myname(); - - r->out.info->info100 = info100; - - break; - } - default: - status = WERR_UNKNOWN_LEVEL; - break; - } - - DEBUG(5,("_srvsvc_NetSrvGetInfo: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* - _srvsvc_NetSrvSetInfo -********************************************************************/ - -WERROR _srvsvc_NetSrvSetInfo(struct pipes_struct *p, - struct srvsvc_NetSrvSetInfo *r) -{ - WERROR status = WERR_OK; - - DEBUG(5,("_srvsvc_NetSrvSetInfo: %d\n", __LINE__)); - - /* Set up the net server set info structure. */ - - DEBUG(5,("_srvsvc_NetSrvSetInfo: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* - _srvsvc_NetConnEnum -********************************************************************/ - -WERROR _srvsvc_NetConnEnum(struct pipes_struct *p, - struct srvsvc_NetConnEnum *r) -{ - WERROR werr; - - DEBUG(5,("_srvsvc_NetConnEnum: %d\n", __LINE__)); - - if (!nt_token_check_sid(&global_sid_Builtin_Administrators, - p->server_info->security_token)) { - DEBUG(1, ("Enumerating connections only allowed for " - "administrators\n")); - return WERR_ACCESS_DENIED; - } - - switch (r->in.info_ctr->level) { - case 0: - werr = init_srv_conn_info_0(r->in.info_ctr->ctr.ctr0, - r->in.resume_handle, - r->out.totalentries); - break; - case 1: - werr = init_srv_conn_info_1(r->in.info_ctr->ctr.ctr1, - r->in.resume_handle, - r->out.totalentries); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - DEBUG(5,("_srvsvc_NetConnEnum: %d\n", __LINE__)); - - return werr; -} - -/******************************************************************* - _srvsvc_NetSessEnum -********************************************************************/ - -WERROR _srvsvc_NetSessEnum(struct pipes_struct *p, - struct srvsvc_NetSessEnum *r) -{ - WERROR werr; - - DEBUG(5,("_srvsvc_NetSessEnum: %d\n", __LINE__)); - - if (!nt_token_check_sid(&global_sid_Builtin_Administrators, - p->server_info->security_token)) { - DEBUG(1, ("Enumerating sessions only allowed for " - "administrators\n")); - return WERR_ACCESS_DENIED; - } - - switch (r->in.info_ctr->level) { - case 0: - werr = init_srv_sess_info_0(p, - r->in.info_ctr->ctr.ctr0, - r->in.resume_handle, - r->out.totalentries); - break; - case 1: - werr = init_srv_sess_info_1(p, - r->in.info_ctr->ctr.ctr1, - r->in.resume_handle, - r->out.totalentries); - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - DEBUG(5,("_srvsvc_NetSessEnum: %d\n", __LINE__)); - - return werr; -} - -/******************************************************************* - _srvsvc_NetSessDel -********************************************************************/ - -WERROR _srvsvc_NetSessDel(struct pipes_struct *p, - struct srvsvc_NetSessDel *r) -{ - struct sessionid *session_list; - int num_sessions, snum; - const char *username; - const char *machine; - bool not_root = False; - WERROR werr; - - username = r->in.user; - machine = r->in.client; - - /* strip leading backslashes if any */ - if (machine && machine[0] == '\\' && machine[1] == '\\') { - machine += 2; - } - - num_sessions = list_sessions(p->mem_ctx, &session_list); - - DEBUG(5,("_srvsvc_NetSessDel: %d\n", __LINE__)); - - werr = WERR_ACCESS_DENIED; - - /* fail out now if you are not root or not a domain admin */ - - if ((p->server_info->utok.uid != sec_initial_uid()) && - ( ! nt_token_check_domain_rid(p->server_info->security_token, - DOMAIN_RID_ADMINS))) { - - goto done; - } - - for (snum = 0; snum < num_sessions; snum++) { - - if ((strequal(session_list[snum].username, username) || username[0] == '\0' ) && - strequal(session_list[snum].remote_machine, machine)) { - - NTSTATUS ntstat; - - if (p->server_info->utok.uid != sec_initial_uid()) { - not_root = True; - become_root(); - } - - ntstat = messaging_send(p->msg_ctx, - session_list[snum].pid, - MSG_SHUTDOWN, &data_blob_null); - - if (NT_STATUS_IS_OK(ntstat)) - werr = WERR_OK; - - if (not_root) - unbecome_root(); - } - } - - DEBUG(5,("_srvsvc_NetSessDel: %d\n", __LINE__)); - -done: - - return werr; -} - -/******************************************************************* - _srvsvc_NetShareEnumAll -********************************************************************/ - -WERROR _srvsvc_NetShareEnumAll(struct pipes_struct *p, - struct srvsvc_NetShareEnumAll *r) -{ - WERROR werr; - - DEBUG(5,("_srvsvc_NetShareEnumAll: %d\n", __LINE__)); - - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to _srvsvc_NetShareEnumAll\n")); - return WERR_ACCESS_DENIED; - } - - /* Create the list of shares for the response. */ - werr = init_srv_share_info_ctr(p, - r->in.info_ctr, - r->in.resume_handle, - r->out.totalentries, - true); - - DEBUG(5,("_srvsvc_NetShareEnumAll: %d\n", __LINE__)); - - return werr; -} - -/******************************************************************* - _srvsvc_NetShareEnum -********************************************************************/ - -WERROR _srvsvc_NetShareEnum(struct pipes_struct *p, - struct srvsvc_NetShareEnum *r) -{ - WERROR werr; - - DEBUG(5,("_srvsvc_NetShareEnum: %d\n", __LINE__)); - - if (!pipe_access_check(p)) { - DEBUG(3, ("access denied to _srvsvc_NetShareEnum\n")); - return WERR_ACCESS_DENIED; - } - - /* Create the list of shares for the response. */ - werr = init_srv_share_info_ctr(p, - r->in.info_ctr, - r->in.resume_handle, - r->out.totalentries, - false); - - DEBUG(5,("_srvsvc_NetShareEnum: %d\n", __LINE__)); - - return werr; -} - -/******************************************************************* - _srvsvc_NetShareGetInfo -********************************************************************/ - -WERROR _srvsvc_NetShareGetInfo(struct pipes_struct *p, - struct srvsvc_NetShareGetInfo *r) -{ - WERROR status = WERR_OK; - char *share_name = NULL; - int snum; - union srvsvc_NetShareInfo *info = r->out.info; - - DEBUG(5,("_srvsvc_NetShareGetInfo: %d\n", __LINE__)); - - if (!r->in.share_name) { - return WERR_INVALID_NAME; - } - - snum = find_service(talloc_tos(), r->in.share_name, &share_name); - if (!share_name) { - return WERR_NOMEM; - } - if (snum < 0) { - return WERR_INVALID_NAME; - } - - switch (r->in.level) { - case 0: - info->info0 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo0); - W_ERROR_HAVE_NO_MEMORY(info->info0); - init_srv_share_info_0(p, info->info0, snum); - break; - case 1: - info->info1 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1); - W_ERROR_HAVE_NO_MEMORY(info->info1); - init_srv_share_info_1(p, info->info1, snum); - break; - case 2: - info->info2 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo2); - W_ERROR_HAVE_NO_MEMORY(info->info2); - init_srv_share_info_2(p, info->info2, snum); - break; - case 501: - info->info501 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo501); - W_ERROR_HAVE_NO_MEMORY(info->info501); - init_srv_share_info_501(p, info->info501, snum); - break; - case 502: - info->info502 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo502); - W_ERROR_HAVE_NO_MEMORY(info->info502); - init_srv_share_info_502(p, info->info502, snum); - break; - case 1004: - info->info1004 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1004); - W_ERROR_HAVE_NO_MEMORY(info->info1004); - init_srv_share_info_1004(p, info->info1004, snum); - break; - case 1005: - info->info1005 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1005); - W_ERROR_HAVE_NO_MEMORY(info->info1005); - init_srv_share_info_1005(p, info->info1005, snum); - break; - case 1006: - info->info1006 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1006); - W_ERROR_HAVE_NO_MEMORY(info->info1006); - init_srv_share_info_1006(p, info->info1006, snum); - break; - case 1007: - info->info1007 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1007); - W_ERROR_HAVE_NO_MEMORY(info->info1007); - init_srv_share_info_1007(p, info->info1007, snum); - break; - case 1501: - init_srv_share_info_1501(p, info->info1501, snum); - break; - default: - DEBUG(5,("_srvsvc_NetShareGetInfo: unsupported switch value %d\n", - r->in.level)); - status = WERR_UNKNOWN_LEVEL; - break; - } - - DEBUG(5,("_srvsvc_NetShareGetInfo: %d\n", __LINE__)); - - return status; -} - -/******************************************************************* - Check a given DOS pathname is valid for a share. -********************************************************************/ - -char *valid_share_pathname(TALLOC_CTX *ctx, const char *dos_pathname) -{ - char *ptr = NULL; - - if (!dos_pathname) { - return NULL; - } - - ptr = talloc_strdup(ctx, dos_pathname); - if (!ptr) { - return NULL; - } - /* Convert any '\' paths to '/' */ - unix_format(ptr); - ptr = unix_clean_name(ctx, ptr); - if (!ptr) { - return NULL; - } - - /* NT is braindead - it wants a C: prefix to a pathname ! So strip it. */ - if (strlen(ptr) > 2 && ptr[1] == ':' && ptr[0] != '/') - ptr += 2; - - /* Only absolute paths allowed. */ - if (*ptr != '/') - return NULL; - - return ptr; -} - -/******************************************************************* - _srvsvc_NetShareSetInfo. Modify share details. -********************************************************************/ - -WERROR _srvsvc_NetShareSetInfo(struct pipes_struct *p, - struct srvsvc_NetShareSetInfo *r) -{ - char *command = NULL; - char *share_name = NULL; - char *comment = NULL; - const char *pathname = NULL; - int type; - int snum; - int ret; - char *path = NULL; - struct security_descriptor *psd = NULL; - bool is_disk_op = False; - int max_connections = 0; - TALLOC_CTX *ctx = p->mem_ctx; - union srvsvc_NetShareInfo *info = r->in.info; - - DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__)); - - if (!r->in.share_name) { - return WERR_INVALID_NAME; - } - - if (r->out.parm_error) { - *r->out.parm_error = 0; - } - - if ( strequal(r->in.share_name,"IPC$") - || ( lp_enable_asu_support() && strequal(r->in.share_name,"ADMIN$") ) - || strequal(r->in.share_name,"global") ) - { - DEBUG(5,("_srvsvc_NetShareSetInfo: share %s cannot be " - "modified by a remote user.\n", - r->in.share_name )); - return WERR_ACCESS_DENIED; - } - - snum = find_service(talloc_tos(), r->in.share_name, &share_name); - if (!share_name) { - return WERR_NOMEM; - } - - /* Does this share exist ? */ - if (snum < 0) - return WERR_NET_NAME_NOT_FOUND; - - /* No change to printer shares. */ - if (lp_print_ok(snum)) - return WERR_ACCESS_DENIED; - - is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); - - /* fail out now if you are not root and not a disk op */ - - if ( p->server_info->utok.uid != sec_initial_uid() && !is_disk_op ) { - DEBUG(2,("_srvsvc_NetShareSetInfo: uid %u doesn't have the " - "SeDiskOperatorPrivilege privilege needed to modify " - "share %s\n", - (unsigned int)p->server_info->utok.uid, - share_name )); - return WERR_ACCESS_DENIED; - } - - switch (r->in.level) { - case 1: - pathname = talloc_strdup(ctx, lp_pathname(snum)); - comment = talloc_strdup(ctx, info->info1->comment); - type = info->info1->type; - psd = NULL; - break; - case 2: - comment = talloc_strdup(ctx, info->info2->comment); - pathname = info->info2->path; - type = info->info2->type; - max_connections = (info->info2->max_users == (uint32_t)-1) ? - 0 : info->info2->max_users; - psd = NULL; - break; -#if 0 - /* not supported on set but here for completeness */ - case 501: - comment = talloc_strdup(ctx, info->info501->comment); - type = info->info501->type; - psd = NULL; - break; -#endif - case 502: - comment = talloc_strdup(ctx, info->info502->comment); - pathname = info->info502->path; - type = info->info502->type; - psd = info->info502->sd_buf.sd; - map_generic_share_sd_bits(psd); - break; - case 1004: - pathname = talloc_strdup(ctx, lp_pathname(snum)); - comment = talloc_strdup(ctx, info->info1004->comment); - type = STYPE_DISKTREE; - break; - case 1005: - /* XP re-sets the csc policy even if it wasn't changed by the - user, so we must compare it to see if it's what is set in - smb.conf, so that we can contine other ops like setting - ACLs on a share */ - if (((info->info1005->dfs_flags & - SHARE_1005_CSC_POLICY_MASK) >> - SHARE_1005_CSC_POLICY_SHIFT) == lp_csc_policy(snum)) - return WERR_OK; - else { - DEBUG(3, ("_srvsvc_NetShareSetInfo: client is trying to change csc policy from the network; must be done with smb.conf\n")); - return WERR_ACCESS_DENIED; - } - case 1006: - case 1007: - return WERR_ACCESS_DENIED; - case 1501: - pathname = talloc_strdup(ctx, lp_pathname(snum)); - comment = talloc_strdup(ctx, lp_comment(snum)); - psd = info->info1501->sd; - map_generic_share_sd_bits(psd); - type = STYPE_DISKTREE; - break; - default: - DEBUG(5,("_srvsvc_NetShareSetInfo: unsupported switch value %d\n", - r->in.level)); - return WERR_UNKNOWN_LEVEL; - } - - /* We can only modify disk shares. */ - if (type != STYPE_DISKTREE) { - DEBUG(5,("_srvsvc_NetShareSetInfo: share %s is not a " - "disk share\n", - share_name )); - return WERR_ACCESS_DENIED; - } - - if (comment == NULL) { - return WERR_NOMEM; - } - - /* Check if the pathname is valid. */ - if (!(path = valid_share_pathname(p->mem_ctx, pathname ))) { - DEBUG(5,("_srvsvc_NetShareSetInfo: invalid pathname %s\n", - pathname )); - return WERR_OBJECT_PATH_INVALID; - } - - /* Ensure share name, pathname and comment don't contain '"' characters. */ - string_replace(share_name, '"', ' '); - string_replace(path, '"', ' '); - string_replace(comment, '"', ' '); - - DEBUG(10,("_srvsvc_NetShareSetInfo: change share command = %s\n", - lp_change_share_cmd() ? lp_change_share_cmd() : "NULL" )); - - /* Only call modify function if something changed. */ - - if (strcmp(path, lp_pathname(snum)) || strcmp(comment, lp_comment(snum)) - || (lp_max_connections(snum) != max_connections)) { - if (!lp_change_share_cmd() || !*lp_change_share_cmd()) { - DEBUG(10,("_srvsvc_NetShareSetInfo: No change share command\n")); - return WERR_ACCESS_DENIED; - } - - command = talloc_asprintf(p->mem_ctx, - "%s \"%s\" \"%s\" \"%s\" \"%s\" %d", - lp_change_share_cmd(), - get_dyn_CONFIGFILE(), - share_name, - path, - comment ? comment : "", - max_connections); - if (!command) { - return WERR_NOMEM; - } - - DEBUG(10,("_srvsvc_NetShareSetInfo: Running [%s]\n", command )); - - /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/ - - if (is_disk_op) - become_root(); - - if ( (ret = smbrun(command, NULL)) == 0 ) { - /* Tell everyone we updated smb.conf. */ - message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, - NULL, 0, NULL); - } - - if ( is_disk_op ) - unbecome_root(); - - /********* END SeDiskOperatorPrivilege BLOCK *********/ - - DEBUG(3,("_srvsvc_NetShareSetInfo: Running [%s] returned (%d)\n", - command, ret )); - - TALLOC_FREE(command); - - if ( ret != 0 ) - return WERR_ACCESS_DENIED; - } else { - DEBUG(10,("_srvsvc_NetShareSetInfo: No change to share name (%s)\n", - share_name )); - } - - /* Replace SD if changed. */ - if (psd) { - struct security_descriptor *old_sd; - size_t sd_size; - - old_sd = get_share_security(p->mem_ctx, lp_servicename(snum), &sd_size); - - if (old_sd && !security_descriptor_equal(old_sd, psd)) { - if (!set_share_security(share_name, psd)) - DEBUG(0,("_srvsvc_NetShareSetInfo: Failed to change security info in share %s.\n", - share_name )); - } - } - - DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__)); - - return WERR_OK; -} - -/******************************************************************* - _srvsvc_NetShareAdd. - Call 'add_share_command "sharename" "pathname" - "comment" "max connections = " -********************************************************************/ - -WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, - struct srvsvc_NetShareAdd *r) -{ - char *command = NULL; - char *share_name_in = NULL; - char *share_name = NULL; - char *comment = NULL; - char *pathname = NULL; - int type; - int snum; - int ret; - char *path; - struct security_descriptor *psd = NULL; - bool is_disk_op; - int max_connections = 0; - TALLOC_CTX *ctx = p->mem_ctx; - - DEBUG(5,("_srvsvc_NetShareAdd: %d\n", __LINE__)); - - if (r->out.parm_error) { - *r->out.parm_error = 0; - } - - is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); - - if (p->server_info->utok.uid != sec_initial_uid() && !is_disk_op ) - return WERR_ACCESS_DENIED; - - if (!lp_add_share_cmd() || !*lp_add_share_cmd()) { - DEBUG(10,("_srvsvc_NetShareAdd: No add share command\n")); - return WERR_ACCESS_DENIED; - } - - switch (r->in.level) { - case 0: - /* No path. Not enough info in a level 0 to do anything. */ - return WERR_ACCESS_DENIED; - case 1: - /* Not enough info in a level 1 to do anything. */ - return WERR_ACCESS_DENIED; - case 2: - share_name_in = talloc_strdup(ctx, r->in.info->info2->name); - comment = talloc_strdup(ctx, r->in.info->info2->comment); - pathname = talloc_strdup(ctx, r->in.info->info2->path); - max_connections = (r->in.info->info2->max_users == (uint32_t)-1) ? - 0 : r->in.info->info2->max_users; - type = r->in.info->info2->type; - break; - case 501: - /* No path. Not enough info in a level 501 to do anything. */ - return WERR_ACCESS_DENIED; - case 502: - share_name_in = talloc_strdup(ctx, r->in.info->info502->name); - comment = talloc_strdup(ctx, r->in.info->info502->comment); - pathname = talloc_strdup(ctx, r->in.info->info502->path); - max_connections = (r->in.info->info502->max_users == (uint32_t)-1) ? - 0 : r->in.info->info502->max_users; - type = r->in.info->info502->type; - psd = r->in.info->info502->sd_buf.sd; - map_generic_share_sd_bits(psd); - break; - - /* none of the following contain share names. NetShareAdd does not have a separate parameter for the share name */ - - case 1004: - case 1005: - case 1006: - case 1007: - return WERR_ACCESS_DENIED; - case 1501: - /* DFS only level. */ - return WERR_ACCESS_DENIED; - default: - DEBUG(5,("_srvsvc_NetShareAdd: unsupported switch value %d\n", - r->in.level)); - return WERR_UNKNOWN_LEVEL; - } - - /* check for invalid share names */ - - if (!share_name_in || !validate_net_name(share_name_in, - INVALID_SHARENAME_CHARS, - strlen(share_name_in))) { - DEBUG(5,("_srvsvc_NetShareAdd: Bad sharename \"%s\"\n", - share_name_in ? share_name_in : "")); - return WERR_INVALID_NAME; - } - - if (strequal(share_name_in,"IPC$") || strequal(share_name_in,"global") - || (lp_enable_asu_support() && - strequal(share_name_in,"ADMIN$"))) { - return WERR_ACCESS_DENIED; - } - - snum = find_service(ctx, share_name_in, &share_name); - if (!share_name) { - return WERR_NOMEM; - } - - /* Share already exists. */ - if (snum >= 0) { - return WERR_FILE_EXISTS; - } - - /* We can only add disk shares. */ - if (type != STYPE_DISKTREE) { - return WERR_ACCESS_DENIED; - } - - /* Check if the pathname is valid. */ - if (!(path = valid_share_pathname(p->mem_ctx, pathname))) { - return WERR_OBJECT_PATH_INVALID; - } - - /* Ensure share name, pathname and comment don't contain '"' characters. */ - string_replace(share_name_in, '"', ' '); - string_replace(share_name, '"', ' '); - string_replace(path, '"', ' '); - if (comment) { - string_replace(comment, '"', ' '); - } - - command = talloc_asprintf(ctx, - "%s \"%s\" \"%s\" \"%s\" \"%s\" %d", - lp_add_share_cmd(), - get_dyn_CONFIGFILE(), - share_name_in, - path, - comment ? comment : "", - max_connections); - if (!command) { - return WERR_NOMEM; - } - - DEBUG(10,("_srvsvc_NetShareAdd: Running [%s]\n", command )); - - /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/ - - if ( is_disk_op ) - become_root(); - - /* FIXME: use libnetconf here - gd */ - - if ( (ret = smbrun(command, NULL)) == 0 ) { - /* Tell everyone we updated smb.conf. */ - message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, - NULL); - } - - if ( is_disk_op ) - unbecome_root(); - - /********* END SeDiskOperatorPrivilege BLOCK *********/ - - DEBUG(3,("_srvsvc_NetShareAdd: Running [%s] returned (%d)\n", - command, ret )); - - TALLOC_FREE(command); - - if ( ret != 0 ) - return WERR_ACCESS_DENIED; - - if (psd) { - /* Note we use share_name here, not share_name_in as - we need a canonicalized name for setting security. */ - if (!set_share_security(share_name, psd)) { - DEBUG(0,("_srvsvc_NetShareAdd: Failed to add security info to share %s.\n", - share_name )); - } - } - - /* - * We don't call reload_services() here, the message will - * cause this to be done before the next packet is read - * from the client. JRA. - */ - - DEBUG(5,("_srvsvc_NetShareAdd: %d\n", __LINE__)); - - return WERR_OK; -} - -/******************************************************************* - _srvsvc_NetShareDel - Call "delete share command" with the share name as - a parameter. -********************************************************************/ - -WERROR _srvsvc_NetShareDel(struct pipes_struct *p, - struct srvsvc_NetShareDel *r) -{ - char *command = NULL; - char *share_name = NULL; - int ret; - int snum; - bool is_disk_op; - struct share_params *params; - TALLOC_CTX *ctx = p->mem_ctx; - - DEBUG(5,("_srvsvc_NetShareDel: %d\n", __LINE__)); - - if (!r->in.share_name) { - return WERR_NET_NAME_NOT_FOUND; - } - - if ( strequal(r->in.share_name,"IPC$") - || ( lp_enable_asu_support() && strequal(r->in.share_name,"ADMIN$") ) - || strequal(r->in.share_name,"global") ) - { - return WERR_ACCESS_DENIED; - } - - snum = find_service(talloc_tos(), r->in.share_name, &share_name); - if (!share_name) { - return WERR_NOMEM; - } - - if (snum < 0) { - return WERR_NO_SUCH_SHARE; - } - - if (!(params = get_share_params(p->mem_ctx, share_name))) { - return WERR_NO_SUCH_SHARE; - } - - /* No change to printer shares. */ - if (lp_print_ok(snum)) - return WERR_ACCESS_DENIED; - - is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); - - if (p->server_info->utok.uid != sec_initial_uid() && !is_disk_op ) - return WERR_ACCESS_DENIED; - - if (!lp_delete_share_cmd() || !*lp_delete_share_cmd()) { - DEBUG(10,("_srvsvc_NetShareDel: No delete share command\n")); - return WERR_ACCESS_DENIED; - } - - command = talloc_asprintf(ctx, - "%s \"%s\" \"%s\"", - lp_delete_share_cmd(), - get_dyn_CONFIGFILE(), - lp_servicename(snum)); - if (!command) { - return WERR_NOMEM; - } - - DEBUG(10,("_srvsvc_NetShareDel: Running [%s]\n", command )); - - /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/ - - if ( is_disk_op ) - become_root(); - - if ( (ret = smbrun(command, NULL)) == 0 ) { - /* Tell everyone we updated smb.conf. */ - message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, - NULL); - } - - if ( is_disk_op ) - unbecome_root(); - - /********* END SeDiskOperatorPrivilege BLOCK *********/ - - DEBUG(3,("_srvsvc_NetShareDel: Running [%s] returned (%d)\n", command, ret )); - - if ( ret != 0 ) - return WERR_ACCESS_DENIED; - - /* Delete the SD in the database. */ - delete_share_security(lp_servicename(params->service)); - - lp_killservice(params->service); - - return WERR_OK; -} - -/******************************************************************* - _srvsvc_NetShareDelSticky -********************************************************************/ - -WERROR _srvsvc_NetShareDelSticky(struct pipes_struct *p, - struct srvsvc_NetShareDelSticky *r) -{ - struct srvsvc_NetShareDel q; - - DEBUG(5,("_srvsvc_NetShareDelSticky: %d\n", __LINE__)); - - q.in.server_unc = r->in.server_unc; - q.in.share_name = r->in.share_name; - q.in.reserved = r->in.reserved; - - return _srvsvc_NetShareDel(p, &q); -} - -/******************************************************************* - _srvsvc_NetRemoteTOD -********************************************************************/ - -WERROR _srvsvc_NetRemoteTOD(struct pipes_struct *p, - struct srvsvc_NetRemoteTOD *r) -{ - struct srvsvc_NetRemoteTODInfo *tod; - struct tm *t; - time_t unixdate = time(NULL); - - /* We do this call first as if we do it *after* the gmtime call - it overwrites the pointed-to values. JRA */ - - uint32 zone = get_time_zone(unixdate)/60; - - DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__)); - - if ( !(tod = TALLOC_ZERO_P(p->mem_ctx, struct srvsvc_NetRemoteTODInfo)) ) - return WERR_NOMEM; - - *r->out.info = tod; - - DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__)); - - t = gmtime(&unixdate); - - /* set up the */ - tod->elapsed = unixdate; - tod->msecs = 0; - tod->hours = t->tm_hour; - tod->mins = t->tm_min; - tod->secs = t->tm_sec; - tod->hunds = 0; - tod->timezone = zone; - tod->tinterval = 10000; - tod->day = t->tm_mday; - tod->month = t->tm_mon + 1; - tod->year = 1900+t->tm_year; - tod->weekday = t->tm_wday; - - DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__)); - - return WERR_OK; -} - -/*********************************************************************************** - _srvsvc_NetGetFileSecurity - Win9x NT tools get security descriptor. -***********************************************************************************/ - -WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p, - struct srvsvc_NetGetFileSecurity *r) -{ - struct smb_filename *smb_fname = NULL; - struct security_descriptor *psd = NULL; - size_t sd_size; - char *servicename = NULL; - SMB_STRUCT_STAT st; - NTSTATUS nt_status; - WERROR werr; - connection_struct *conn = NULL; - struct sec_desc_buf *sd_buf = NULL; - files_struct *fsp = NULL; - int snum; - char *oldcwd = NULL; - - ZERO_STRUCT(st); - - if (!r->in.share) { - werr = WERR_NET_NAME_NOT_FOUND; - goto error_exit; - } - snum = find_service(talloc_tos(), r->in.share, &servicename); - if (!servicename) { - werr = WERR_NOMEM; - goto error_exit; - } - if (snum == -1) { - DEBUG(10, ("Could not find service %s\n", servicename)); - werr = WERR_NET_NAME_NOT_FOUND; - goto error_exit; - } - - nt_status = create_conn_struct(talloc_tos(), &conn, snum, - lp_pathname(snum), p->server_info, - &oldcwd); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(10, ("create_conn_struct failed: %s\n", - nt_errstr(nt_status))); - werr = ntstatus_to_werror(nt_status); - goto error_exit; - } - - nt_status = filename_convert(talloc_tos(), - conn, - false, - r->in.file, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(nt_status)) { - werr = ntstatus_to_werror(nt_status); - goto error_exit; - } - - nt_status = SMB_VFS_CREATE_FILE( - conn, /* conn */ - NULL, /* req */ - 0, /* root_dir_fid */ - smb_fname, /* fname */ - FILE_READ_ATTRIBUTES, /* access_mask */ - FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ - FILE_OPEN, /* create_disposition*/ - 0, /* create_options */ - 0, /* file_attributes */ - INTERNAL_OPEN_ONLY, /* oplock_request */ - 0, /* allocation_size */ - 0, /* private_flags */ - NULL, /* sd */ - NULL, /* ea_list */ - &fsp, /* result */ - NULL); /* pinfo */ - - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srvsvc_NetGetFileSecurity: can't open %s\n", - smb_fname_str_dbg(smb_fname))); - werr = ntstatus_to_werror(nt_status); - goto error_exit; - } - - nt_status = SMB_VFS_FGET_NT_ACL(fsp, - (SECINFO_OWNER - |SECINFO_GROUP - |SECINFO_DACL), &psd); - - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srvsvc_NetGetFileSecurity: Unable to get NT ACL " - "for file %s\n", smb_fname_str_dbg(smb_fname))); - werr = ntstatus_to_werror(nt_status); - goto error_exit; - } - - sd_size = ndr_size_security_descriptor(psd, 0); - - sd_buf = TALLOC_ZERO_P(p->mem_ctx, struct sec_desc_buf); - if (!sd_buf) { - werr = WERR_NOMEM; - goto error_exit; - } - - sd_buf->sd_size = sd_size; - sd_buf->sd = psd; - - *r->out.sd_buf = sd_buf; - - psd->dacl->revision = NT4_ACL_REVISION; - - close_file(NULL, fsp, NORMAL_CLOSE); - vfs_ChDir(conn, oldcwd); - conn_free(conn); - werr = WERR_OK; - goto done; - -error_exit: - - if (fsp) { - close_file(NULL, fsp, NORMAL_CLOSE); - } - - if (oldcwd) { - vfs_ChDir(conn, oldcwd); - } - - if (conn) { - conn_free(conn); - } - - done: - TALLOC_FREE(smb_fname); - - return werr; -} - -/*********************************************************************************** - _srvsvc_NetSetFileSecurity - Win9x NT tools set security descriptor. -***********************************************************************************/ - -WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p, - struct srvsvc_NetSetFileSecurity *r) -{ - struct smb_filename *smb_fname = NULL; - char *servicename = NULL; - files_struct *fsp = NULL; - SMB_STRUCT_STAT st; - NTSTATUS nt_status; - WERROR werr; - connection_struct *conn = NULL; - int snum; - char *oldcwd = NULL; - struct security_descriptor *psd = NULL; - uint32_t security_info_sent = 0; - - ZERO_STRUCT(st); - - if (!r->in.share) { - werr = WERR_NET_NAME_NOT_FOUND; - goto error_exit; - } - - snum = find_service(talloc_tos(), r->in.share, &servicename); - if (!servicename) { - werr = WERR_NOMEM; - goto error_exit; - } - - if (snum == -1) { - DEBUG(10, ("Could not find service %s\n", servicename)); - werr = WERR_NET_NAME_NOT_FOUND; - goto error_exit; - } - - nt_status = create_conn_struct(talloc_tos(), &conn, snum, - lp_pathname(snum), p->server_info, - &oldcwd); - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(10, ("create_conn_struct failed: %s\n", - nt_errstr(nt_status))); - werr = ntstatus_to_werror(nt_status); - goto error_exit; - } - - nt_status = filename_convert(talloc_tos(), - conn, - false, - r->in.file, - 0, - NULL, - &smb_fname); - if (!NT_STATUS_IS_OK(nt_status)) { - werr = ntstatus_to_werror(nt_status); - goto error_exit; - } - - nt_status = SMB_VFS_CREATE_FILE( - conn, /* conn */ - NULL, /* req */ - 0, /* root_dir_fid */ - smb_fname, /* fname */ - FILE_WRITE_ATTRIBUTES, /* access_mask */ - FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ - FILE_OPEN, /* create_disposition*/ - 0, /* create_options */ - 0, /* file_attributes */ - INTERNAL_OPEN_ONLY, /* oplock_request */ - 0, /* allocation_size */ - 0, /* private_flags */ - NULL, /* sd */ - NULL, /* ea_list */ - &fsp, /* result */ - NULL); /* pinfo */ - - if (!NT_STATUS_IS_OK(nt_status)) { - DEBUG(3,("_srvsvc_NetSetFileSecurity: can't open %s\n", - smb_fname_str_dbg(smb_fname))); - werr = ntstatus_to_werror(nt_status); - goto error_exit; - } - - psd = r->in.sd_buf->sd; - security_info_sent = r->in.securityinformation; - - if (psd->owner_sid==0) { - security_info_sent &= ~SECINFO_OWNER; - } - if (psd->group_sid==0) { - security_info_sent &= ~SECINFO_GROUP; - } - if (psd->sacl==0) { - security_info_sent &= ~SECINFO_SACL; - } - if (psd->dacl==0) { - security_info_sent &= ~SECINFO_DACL; - } - - /* Convert all the generic bits. */ - security_acl_map_generic(psd->dacl, &file_generic_mapping); - security_acl_map_generic(psd->sacl, &file_generic_mapping); - - nt_status = SMB_VFS_FSET_NT_ACL(fsp, - security_info_sent, - psd); - - if (!NT_STATUS_IS_OK(nt_status) ) { - DEBUG(3,("_srvsvc_NetSetFileSecurity: Unable to set NT ACL " - "on file %s\n", r->in.share)); - werr = WERR_ACCESS_DENIED; - goto error_exit; - } - - close_file(NULL, fsp, NORMAL_CLOSE); - vfs_ChDir(conn, oldcwd); - conn_free(conn); - werr = WERR_OK; - goto done; - -error_exit: - - if (fsp) { - close_file(NULL, fsp, NORMAL_CLOSE); - } - - if (oldcwd) { - vfs_ChDir(conn, oldcwd); - } - - if (conn) { - conn_free(conn); - } - - done: - TALLOC_FREE(smb_fname); - - return werr; -} - -/*********************************************************************************** - It may be that we want to limit users to creating shares on certain areas of the UNIX file area. - We could define areas by mapping Windows style disks to points on the UNIX directory hierarchy. - These disks would the disks listed by this function. - Users could then create shares relative to these disks. Watch out for moving these disks around. - "Nigel Williams" . -***********************************************************************************/ - -static const char *server_disks[] = {"C:"}; - -static uint32 get_server_disk_count(void) -{ - return sizeof(server_disks)/sizeof(server_disks[0]); -} - -static uint32 init_server_disk_enum(uint32 *resume) -{ - uint32 server_disk_count = get_server_disk_count(); - - /*resume can be an offset into the list for now*/ - - if(*resume & 0x80000000) - *resume = 0; - - if(*resume > server_disk_count) - *resume = server_disk_count; - - return server_disk_count - *resume; -} - -static const char *next_server_disk_enum(uint32 *resume) -{ - const char *disk; - - if(init_server_disk_enum(resume) == 0) - return NULL; - - disk = server_disks[*resume]; - - (*resume)++; - - DEBUG(10, ("next_server_disk_enum: reporting disk %s. resume handle %d.\n", disk, *resume)); - - return disk; -} - -/******************************************************************** - _srvsvc_NetDiskEnum -********************************************************************/ - -WERROR _srvsvc_NetDiskEnum(struct pipes_struct *p, - struct srvsvc_NetDiskEnum *r) -{ - uint32 i; - const char *disk_name; - TALLOC_CTX *ctx = p->mem_ctx; - WERROR werr; - uint32_t resume = r->in.resume_handle ? *r->in.resume_handle : 0; - - werr = WERR_OK; - - *r->out.totalentries = init_server_disk_enum(&resume); - - r->out.info->disks = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetDiskInfo0, - MAX_SERVER_DISK_ENTRIES); - W_ERROR_HAVE_NO_MEMORY(r->out.info->disks); - - /*allow one struct srvsvc_NetDiskInfo0 for null terminator*/ - - r->out.info->count = 0; - - for(i = 0; i < MAX_SERVER_DISK_ENTRIES -1 && (disk_name = next_server_disk_enum(&resume)); i++) { - - r->out.info->count++; - - /*copy disk name into a unicode string*/ - - r->out.info->disks[i].disk = talloc_strdup(ctx, disk_name); - W_ERROR_HAVE_NO_MEMORY(r->out.info->disks[i].disk); - } - - /* add a terminating null string. Is this there if there is more data to come? */ - - r->out.info->count++; - - r->out.info->disks[i].disk = talloc_strdup(ctx, ""); - W_ERROR_HAVE_NO_MEMORY(r->out.info->disks[i].disk); - - if (r->out.resume_handle) { - *r->out.resume_handle = resume; - } - - return werr; -} - -/******************************************************************** - _srvsvc_NetNameValidate -********************************************************************/ - -WERROR _srvsvc_NetNameValidate(struct pipes_struct *p, - struct srvsvc_NetNameValidate *r) -{ - switch (r->in.name_type) { - case 0x9: - if (!validate_net_name(r->in.name, INVALID_SHARENAME_CHARS, - strlen_m(r->in.name))) - { - DEBUG(5,("_srvsvc_NetNameValidate: Bad sharename \"%s\"\n", - r->in.name)); - return WERR_INVALID_NAME; - } - break; - - default: - return WERR_UNKNOWN_LEVEL; - } - - return WERR_OK; -} - -/******************************************************************* -********************************************************************/ - -struct enum_file_close_state { - struct srvsvc_NetFileClose *r; - struct messaging_context *msg_ctx; -}; - -static void enum_file_close_fn( const struct share_mode_entry *e, - const char *sharepath, const char *fname, - void *private_data ) -{ - char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; - struct enum_file_close_state *state = - (struct enum_file_close_state *)private_data; - uint32_t fid = (((uint32_t)(procid_to_pid(&e->pid))<<16) | e->share_file_id); - - if (fid != state->r->in.fid) { - return; /* Not this file. */ - } - - if (!process_exists(e->pid) ) { - return; - } - - /* Ok - send the close message. */ - DEBUG(10,("enum_file_close_fn: request to close file %s, %s\n", - sharepath, - share_mode_str(talloc_tos(), 0, e) )); - - share_mode_entry_to_message(msg, e); - - state->r->out.result = ntstatus_to_werror( - messaging_send_buf(state->msg_ctx, - e->pid, MSG_SMB_CLOSE_FILE, - (uint8 *)msg, - MSG_SMB_SHARE_MODE_ENTRY_SIZE)); -} - -/******************************************************************** - Close a file given a 32-bit file id. -********************************************************************/ - -WERROR _srvsvc_NetFileClose(struct pipes_struct *p, - struct srvsvc_NetFileClose *r) -{ - struct enum_file_close_state state; - bool is_disk_op; - - DEBUG(5,("_srvsvc_NetFileClose: %d\n", __LINE__)); - - is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); - - if (p->server_info->utok.uid != sec_initial_uid() && !is_disk_op) { - return WERR_ACCESS_DENIED; - } - - /* enum_file_close_fn sends the close message to - * the relevent smbd process. */ - - r->out.result = WERR_BADFILE; - state.r = r; - state.msg_ctx = p->msg_ctx; - share_mode_forall(enum_file_close_fn, &state); - return r->out.result; -} - -/******************************************************************** -********************************************************************/ - -WERROR _srvsvc_NetCharDevEnum(struct pipes_struct *p, - struct srvsvc_NetCharDevEnum *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetCharDevGetInfo(struct pipes_struct *p, - struct srvsvc_NetCharDevGetInfo *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetCharDevControl(struct pipes_struct *p, - struct srvsvc_NetCharDevControl *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetCharDevQEnum(struct pipes_struct *p, - struct srvsvc_NetCharDevQEnum *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetCharDevQGetInfo(struct pipes_struct *p, - struct srvsvc_NetCharDevQGetInfo *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetCharDevQSetInfo(struct pipes_struct *p, - struct srvsvc_NetCharDevQSetInfo *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetCharDevQPurge(struct pipes_struct *p, - struct srvsvc_NetCharDevQPurge *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetCharDevQPurgeSelf(struct pipes_struct *p, - struct srvsvc_NetCharDevQPurgeSelf *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetFileGetInfo(struct pipes_struct *p, - struct srvsvc_NetFileGetInfo *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetShareCheck(struct pipes_struct *p, - struct srvsvc_NetShareCheck *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetServerStatisticsGet(struct pipes_struct *p, - struct srvsvc_NetServerStatisticsGet *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetTransportAdd(struct pipes_struct *p, - struct srvsvc_NetTransportAdd *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetTransportEnum(struct pipes_struct *p, - struct srvsvc_NetTransportEnum *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetTransportDel(struct pipes_struct *p, - struct srvsvc_NetTransportDel *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetSetServiceBits(struct pipes_struct *p, - struct srvsvc_NetSetServiceBits *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetPathType(struct pipes_struct *p, - struct srvsvc_NetPathType *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetPathCanonicalize(struct pipes_struct *p, - struct srvsvc_NetPathCanonicalize *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetPathCompare(struct pipes_struct *p, - struct srvsvc_NetPathCompare *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRPRNAMECANONICALIZE(struct pipes_struct *p, - struct srvsvc_NETRPRNAMECANONICALIZE *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetPRNameCompare(struct pipes_struct *p, - struct srvsvc_NetPRNameCompare *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetShareDelStart(struct pipes_struct *p, - struct srvsvc_NetShareDelStart *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetShareDelCommit(struct pipes_struct *p, - struct srvsvc_NetShareDelCommit *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetServerTransportAddEx(struct pipes_struct *p, - struct srvsvc_NetServerTransportAddEx *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NetServerSetServiceBitsEx(struct pipes_struct *p, - struct srvsvc_NetServerSetServiceBitsEx *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSGETVERSION(struct pipes_struct *p, - struct srvsvc_NETRDFSGETVERSION *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSCREATELOCALPARTITION(struct pipes_struct *p, - struct srvsvc_NETRDFSCREATELOCALPARTITION *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSDELETELOCALPARTITION(struct pipes_struct *p, - struct srvsvc_NETRDFSDELETELOCALPARTITION *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct pipes_struct *p, - struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSSETSERVERINFO(struct pipes_struct *p, - struct srvsvc_NETRDFSSETSERVERINFO *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSCREATEEXITPOINT(struct pipes_struct *p, - struct srvsvc_NETRDFSCREATEEXITPOINT *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSDELETEEXITPOINT(struct pipes_struct *p, - struct srvsvc_NETRDFSDELETEEXITPOINT *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSMODIFYPREFIX(struct pipes_struct *p, - struct srvsvc_NETRDFSMODIFYPREFIX *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSFIXLOCALVOLUME(struct pipes_struct *p, - struct srvsvc_NETRDFSFIXLOCALVOLUME *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct pipes_struct *p, - struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _srvsvc_NETRSERVERTRANSPORTDELEX(struct pipes_struct *p, - struct srvsvc_NETRSERVERTRANSPORTDELEX *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c deleted file mode 100644 index b6984d0c5f..0000000000 --- a/source3/rpc_server/srv_svcctl_nt.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * - * Copyright (C) Marcin Krzysztof Porwit 2005. - * - * Largely Rewritten (Again) by: - * Copyright (C) Gerald (Jerry) Carter 2005. - * Copyright (C) Guenther Deschner 2008,2009. - * - * 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 . - */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_svcctl.h" -#include "../libcli/security/security.h" -#include "../librpc/gen_ndr/ndr_security.h" -#include "services/services.h" -#include "services/svc_winreg_glue.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -struct service_control_op { - const char *name; - SERVICE_CONTROL_OPS *ops; -}; - -/* handle external services */ -extern SERVICE_CONTROL_OPS rcinit_svc_ops; - -/* builtin services (see service_db.c and services/svc_*.c */ -extern SERVICE_CONTROL_OPS spoolss_svc_ops; -extern SERVICE_CONTROL_OPS netlogon_svc_ops; -extern SERVICE_CONTROL_OPS winreg_svc_ops; -extern SERVICE_CONTROL_OPS wins_svc_ops; - -/* make sure this number patches the number of builtin - SERVICE_CONTROL_OPS structure listed above */ - -#define SVCCTL_NUM_INTERNAL_SERVICES 4 - -struct service_control_op *svcctl_ops; - -static const struct generic_mapping scm_generic_map = - { SC_MANAGER_READ_ACCESS, SC_MANAGER_WRITE_ACCESS, SC_MANAGER_EXECUTE_ACCESS, SC_MANAGER_ALL_ACCESS }; -static const struct generic_mapping svc_generic_map = - { SERVICE_READ_ACCESS, SERVICE_WRITE_ACCESS, SERVICE_EXECUTE_ACCESS, SERVICE_ALL_ACCESS }; - - -/******************************************************************** -********************************************************************/ - -bool init_service_op_table( void ) -{ - const char **service_list = lp_svcctl_list(); - int num_services = SVCCTL_NUM_INTERNAL_SERVICES + str_list_length( service_list ); - int i; - - if ( !(svcctl_ops = TALLOC_ARRAY( NULL, struct service_control_op, num_services+1)) ) { - DEBUG(0,("init_service_op_table: talloc() failed!\n")); - return False; - } - - /* services listed in smb.conf get the rc.init interface */ - - for ( i=0; service_list && service_list[i]; i++ ) { - svcctl_ops[i].name = talloc_strdup( svcctl_ops, service_list[i] ); - svcctl_ops[i].ops = &rcinit_svc_ops; - } - - /* add builtin services */ - - svcctl_ops[i].name = talloc_strdup( svcctl_ops, "Spooler" ); - svcctl_ops[i].ops = &spoolss_svc_ops; - i++; - - svcctl_ops[i].name = talloc_strdup( svcctl_ops, "NETLOGON" ); - svcctl_ops[i].ops = &netlogon_svc_ops; - i++; - - svcctl_ops[i].name = talloc_strdup( svcctl_ops, "RemoteRegistry" ); - svcctl_ops[i].ops = &winreg_svc_ops; - i++; - - svcctl_ops[i].name = talloc_strdup( svcctl_ops, "WINS" ); - svcctl_ops[i].ops = &wins_svc_ops; - i++; - - /* NULL terminate the array */ - - svcctl_ops[i].name = NULL; - svcctl_ops[i].ops = NULL; - - return True; -} - -bool shutdown_service_op_table(void) -{ - TALLOC_FREE(svcctl_ops); - - return true; -} - -/******************************************************************** -********************************************************************/ - -static struct service_control_op* find_service_by_name( const char *name ) -{ - int i; - - for ( i=0; svcctl_ops[i].name; i++ ) { - if ( strequal( name, svcctl_ops[i].name ) ) - return &svcctl_ops[i]; - } - - return NULL; -} -/******************************************************************** -********************************************************************/ - -static NTSTATUS svcctl_access_check( struct security_descriptor *sec_desc, struct security_token *token, - uint32 access_desired, uint32 *access_granted ) -{ - if ( geteuid() == sec_initial_uid() ) { - DEBUG(5,("svcctl_access_check: using root's token\n")); - token = get_root_nt_token(); - } - - return se_access_check( sec_desc, token, access_desired, access_granted); -} - -/******************************************************************** -********************************************************************/ - -static struct security_descriptor* construct_scm_sd( TALLOC_CTX *ctx ) -{ - struct security_ace ace[2]; - size_t i = 0; - struct security_descriptor *sd; - struct security_acl *theacl; - size_t sd_size; - - /* basic access for Everyone */ - - init_sec_ace(&ace[i++], &global_sid_World, - SEC_ACE_TYPE_ACCESS_ALLOWED, SC_MANAGER_READ_ACCESS, 0); - - /* Full Access 'BUILTIN\Administrators' */ - - init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, - SEC_ACE_TYPE_ACCESS_ALLOWED, SC_MANAGER_ALL_ACCESS, 0); - - - /* create the security descriptor */ - - if ( !(theacl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) ) - return NULL; - - if ( !(sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1, - SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, - theacl, &sd_size)) ) - return NULL; - - return sd; -} - -/****************************************************************** - Find a registry key handle and return a SERVICE_INFO - *****************************************************************/ - -static SERVICE_INFO *find_service_info_by_hnd(struct pipes_struct *p, - struct policy_handle *hnd) -{ - SERVICE_INFO *service_info = NULL; - - if( !find_policy_by_hnd( p, hnd, (void **)(void *)&service_info) ) { - DEBUG(2,("find_service_info_by_hnd: handle not found\n")); - return NULL; - } - - return service_info; -} - -/****************************************************************** - *****************************************************************/ - -static WERROR create_open_service_handle(struct pipes_struct *p, - struct policy_handle *handle, - uint32_t type, - const char *service, - uint32_t access_granted) -{ - SERVICE_INFO *info = NULL; - WERROR result = WERR_OK; - struct service_control_op *s_op; - - if ( !(info = TALLOC_ZERO_P( NULL, SERVICE_INFO )) ) - return WERR_NOMEM; - - /* the Service Manager has a NULL name */ - - info->type = SVC_HANDLE_IS_SCM; - - switch ( type ) { - case SVC_HANDLE_IS_SCM: - info->type = SVC_HANDLE_IS_SCM; - break; - - case SVC_HANDLE_IS_DBLOCK: - info->type = SVC_HANDLE_IS_DBLOCK; - break; - - case SVC_HANDLE_IS_SERVICE: - info->type = SVC_HANDLE_IS_SERVICE; - - /* lookup the SERVICE_CONTROL_OPS */ - - if ( !(s_op = find_service_by_name( service )) ) { - result = WERR_NO_SUCH_SERVICE; - goto done; - } - - info->ops = s_op->ops; - - if ( !(info->name = talloc_strdup( info, s_op->name )) ) { - result = WERR_NOMEM; - goto done; - } - break; - - default: - result = WERR_NO_SUCH_SERVICE; - goto done; - } - - info->access_granted = access_granted; - - /* store the SERVICE_INFO and create an open handle */ - - if ( !create_policy_hnd( p, handle, info ) ) { - result = WERR_ACCESS_DENIED; - goto done; - } - -done: - if ( !W_ERROR_IS_OK(result) ) - TALLOC_FREE(info); - - return result; -} - -/******************************************************************** - _svcctl_OpenSCManagerW -********************************************************************/ - -WERROR _svcctl_OpenSCManagerW(struct pipes_struct *p, - struct svcctl_OpenSCManagerW *r) -{ - struct security_descriptor *sec_desc; - uint32 access_granted = 0; - NTSTATUS status; - - /* perform access checks */ - - if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) ) - return WERR_NOMEM; - - se_map_generic( &r->in.access_mask, &scm_generic_map ); - status = svcctl_access_check( sec_desc, p->server_info->security_token, - r->in.access_mask, &access_granted ); - if ( !NT_STATUS_IS_OK(status) ) - return ntstatus_to_werror( status ); - - return create_open_service_handle( p, r->out.handle, SVC_HANDLE_IS_SCM, NULL, access_granted ); -} - -/******************************************************************** - _svcctl_OpenServiceW -********************************************************************/ - -WERROR _svcctl_OpenServiceW(struct pipes_struct *p, - struct svcctl_OpenServiceW *r) -{ - struct security_descriptor *sec_desc; - uint32 access_granted = 0; - NTSTATUS status; - const char *service = NULL; - - service = r->in.ServiceName; - if (!service) { - return WERR_NOMEM; - } - DEBUG(5, ("_svcctl_OpenServiceW: Attempting to open Service [%s], \n", service)); - - /* based on my tests you can open a service if you have a valid scm handle */ - - if ( !find_service_info_by_hnd( p, r->in.scmanager_handle) ) - return WERR_BADFID; - - /* - * Perform access checks. Use the system server_info in order to ensure - * that we retrieve the security descriptor - */ - sec_desc = svcctl_get_secdesc(p->mem_ctx, - p->msg_ctx, - get_server_info_system(), - service); - if (sec_desc == NULL) { - DEBUG(0, ("_svcctl_OpenServiceW: Failed to get a valid security " - "descriptor")); - return WERR_NOMEM; - } - - se_map_generic( &r->in.access_mask, &svc_generic_map ); - status = svcctl_access_check( sec_desc, p->server_info->security_token, - r->in.access_mask, &access_granted ); - if ( !NT_STATUS_IS_OK(status) ) - return ntstatus_to_werror( status ); - - return create_open_service_handle( p, r->out.handle, SVC_HANDLE_IS_SERVICE, service, access_granted ); -} - -/******************************************************************** - _svcctl_CloseServiceHandle -********************************************************************/ - -WERROR _svcctl_CloseServiceHandle(struct pipes_struct *p, - struct svcctl_CloseServiceHandle *r) -{ - if ( !close_policy_hnd( p, r->in.handle ) ) - return WERR_BADFID; - - ZERO_STRUCTP(r->out.handle); - - return WERR_OK; -} - -/******************************************************************** - _svcctl_GetServiceDisplayNameW -********************************************************************/ - -WERROR _svcctl_GetServiceDisplayNameW(struct pipes_struct *p, - struct svcctl_GetServiceDisplayNameW *r) -{ - const char *service; - const char *display_name; - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - - /* can only use an SCM handle here */ - - if ( !info || (info->type != SVC_HANDLE_IS_SCM) ) - return WERR_BADFID; - - service = r->in.service_name; - - display_name = svcctl_lookup_dispname(p->mem_ctx, - p->msg_ctx, - p->server_info, - service); - if (!display_name) { - display_name = ""; - } - - *r->out.display_name = display_name; - *r->out.display_name_length = strlen(display_name); - - return WERR_OK; -} - -/******************************************************************** - _svcctl_QueryServiceStatus -********************************************************************/ - -WERROR _svcctl_QueryServiceStatus(struct pipes_struct *p, - struct svcctl_QueryServiceStatus *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) ) - return WERR_ACCESS_DENIED; - - /* try the service specific status call */ - - return info->ops->service_status( info->name, r->out.service_status ); -} - -/******************************************************************** -********************************************************************/ - -static int enumerate_status(TALLOC_CTX *ctx, - struct messaging_context *msg_ctx, - struct auth_serversupplied_info *server_info, - struct ENUM_SERVICE_STATUSW **status) -{ - int num_services = 0; - int i; - struct ENUM_SERVICE_STATUSW *st; - const char *display_name; - - /* just count */ - while ( svcctl_ops[num_services].name ) - num_services++; - - if ( !(st = TALLOC_ARRAY( ctx, struct ENUM_SERVICE_STATUSW, num_services )) ) { - DEBUG(0,("enumerate_status: talloc() failed!\n")); - return -1; - } - - for ( i=0; iservice_status( svcctl_ops[i].name, &st[i].status ); - } - - *status = st; - - return num_services; -} - -/******************************************************************** - _svcctl_EnumServicesStatusW -********************************************************************/ - -WERROR _svcctl_EnumServicesStatusW(struct pipes_struct *p, - struct svcctl_EnumServicesStatusW *r) -{ - struct ENUM_SERVICE_STATUSW *services = NULL; - int num_services; - int i = 0; - size_t buffer_size = 0; - WERROR result = WERR_OK; - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - DATA_BLOB blob = data_blob_null; - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SCM) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) ) { - return WERR_ACCESS_DENIED; - } - - num_services = enumerate_status(p->mem_ctx, - p->msg_ctx, - p->server_info, - &services); - if (num_services == -1 ) { - return WERR_NOMEM; - } - - for ( i=0; i r->in.offered) { - num_services = 0; - result = WERR_MORE_DATA; - } - - if ( W_ERROR_IS_OK(result) ) { - - enum ndr_err_code ndr_err; - struct ndr_push *ndr; - - ndr = ndr_push_init_ctx(p->mem_ctx); - if (ndr == NULL) { - return WERR_INVALID_PARAM; - } - - ndr_err = ndr_push_ENUM_SERVICE_STATUSW_array( - ndr, num_services, services); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ntstatus_to_werror(ndr_map_error2ntstatus(ndr_err)); - } - blob = ndr_push_blob(ndr); - memcpy(r->out.service, blob.data, MIN(blob.length, r->in.offered)); - } - - *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; - *r->out.services_returned = (uint32)num_services; - if (r->out.resume_handle) { - *r->out.resume_handle = 0; - } - - return result; -} - -/******************************************************************** - _svcctl_StartServiceW -********************************************************************/ - -WERROR _svcctl_StartServiceW(struct pipes_struct *p, - struct svcctl_StartServiceW *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_SVC_START) ) - return WERR_ACCESS_DENIED; - - return info->ops->start_service( info->name ); -} - -/******************************************************************** - _svcctl_ControlService -********************************************************************/ - -WERROR _svcctl_ControlService(struct pipes_struct *p, - struct svcctl_ControlService *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) - return WERR_BADFID; - - switch ( r->in.control ) { - case SVCCTL_CONTROL_STOP: - if ( !(info->access_granted & SC_RIGHT_SVC_STOP) ) - return WERR_ACCESS_DENIED; - - return info->ops->stop_service( info->name, - r->out.service_status ); - - case SVCCTL_CONTROL_INTERROGATE: - if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) ) - return WERR_ACCESS_DENIED; - - return info->ops->service_status( info->name, - r->out.service_status ); - default: - return WERR_INVALID_PARAM; - } -} - -/******************************************************************** - _svcctl_EnumDependentServicesW -********************************************************************/ - -WERROR _svcctl_EnumDependentServicesW(struct pipes_struct *p, - struct svcctl_EnumDependentServicesW *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.service ); - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) ) - return WERR_ACCESS_DENIED; - - switch (r->in.state) { - case SERVICE_STATE_ACTIVE: - case SERVICE_STATE_INACTIVE: - case SERVICE_STATE_ALL: - break; - default: - return WERR_INVALID_PARAM; - } - - /* we have to set the outgoing buffer size to the same as the - incoming buffer size (even in the case of failure */ - /* this is done in the autogenerated server already - gd */ - - *r->out.needed = r->in.offered; - - /* no dependent services...basically a stub function */ - *r->out.services_returned = 0; - - return WERR_OK; -} - -/******************************************************************** - _svcctl_QueryServiceStatusEx -********************************************************************/ - -WERROR _svcctl_QueryServiceStatusEx(struct pipes_struct *p, - struct svcctl_QueryServiceStatusEx *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - uint32 buffer_size; - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) ) - return WERR_ACCESS_DENIED; - - /* we have to set the outgoing buffer size to the same as the - incoming buffer size (even in the case of failure) */ - *r->out.needed = r->in.offered; - - switch ( r->in.info_level ) { - case SVC_STATUS_PROCESS_INFO: - { - struct SERVICE_STATUS_PROCESS svc_stat_proc; - enum ndr_err_code ndr_err; - DATA_BLOB blob; - - /* Get the status of the service.. */ - info->ops->service_status( info->name, &svc_stat_proc.status ); - svc_stat_proc.process_id = sys_getpid(); - svc_stat_proc.service_flags = 0x0; - - ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &svc_stat_proc, - (ndr_push_flags_fn_t)ndr_push_SERVICE_STATUS_PROCESS); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return WERR_INVALID_PARAM; - } - - r->out.buffer = blob.data; - buffer_size = sizeof(struct SERVICE_STATUS_PROCESS); - break; - } - - default: - return WERR_UNKNOWN_LEVEL; - } - - - buffer_size += buffer_size % 4; - *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; - - if (buffer_size > r->in.offered ) { - return WERR_INSUFFICIENT_BUFFER; - } - - return WERR_OK; -} - -/******************************************************************** -********************************************************************/ - -static WERROR fill_svc_config(TALLOC_CTX *ctx, - struct messaging_context *msg_ctx, - struct auth_serversupplied_info *server_info, - const char *name, - struct QUERY_SERVICE_CONFIG *config) -{ - TALLOC_CTX *mem_ctx = talloc_stackframe(); - const char *result = NULL; - - /* now fill in the individual values */ - - config->displayname = svcctl_lookup_dispname(mem_ctx, - msg_ctx, - server_info, - name); - - result = svcctl_get_string_value(mem_ctx, - msg_ctx, - server_info, - name, - "ObjectName"); - if (result != NULL) { - config->startname = result; - } - - result = svcctl_get_string_value(mem_ctx, - msg_ctx, - server_info, - name, - "ImagePath"); - if (result != NULL) { - config->executablepath = result; - } - - /* a few hard coded values */ - /* loadordergroup and dependencies are empty */ - - config->tag_id = 0x00000000; /* unassigned loadorder group */ - config->service_type = SERVICE_TYPE_WIN32_OWN_PROCESS; - config->error_control = SVCCTL_SVC_ERROR_NORMAL; - - /* set the start type. NetLogon and WINS are disabled to prevent - the client from showing the "Start" button (if of course the services - are not running */ - - if ( strequal( name, "NETLOGON" ) && ( lp_servicenumber(name) == -1 ) ) - config->start_type = SVCCTL_DISABLED; - else if ( strequal( name, "WINS" ) && ( !lp_wins_support() )) - config->start_type = SVCCTL_DISABLED; - else - config->start_type = SVCCTL_DEMAND_START; - - - talloc_free(mem_ctx); - - return WERR_OK; -} - -/******************************************************************** - _svcctl_QueryServiceConfigW -********************************************************************/ - -WERROR _svcctl_QueryServiceConfigW(struct pipes_struct *p, - struct svcctl_QueryServiceConfigW *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - uint32 buffer_size; - WERROR wresult; - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) ) - return WERR_ACCESS_DENIED; - - /* we have to set the outgoing buffer size to the same as the - incoming buffer size (even in the case of failure */ - - *r->out.needed = r->in.offered; - - wresult = fill_svc_config(p->mem_ctx, - p->msg_ctx, - p->server_info, - info->name, - r->out.query); - if ( !W_ERROR_IS_OK(wresult) ) - return wresult; - - buffer_size = ndr_size_QUERY_SERVICE_CONFIG(r->out.query, 0); - *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; - - if (buffer_size > r->in.offered ) { - ZERO_STRUCTP(r->out.query); - return WERR_INSUFFICIENT_BUFFER; - } - - return WERR_OK; -} - -/******************************************************************** - _svcctl_QueryServiceConfig2W -********************************************************************/ - -WERROR _svcctl_QueryServiceConfig2W(struct pipes_struct *p, - struct svcctl_QueryServiceConfig2W *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - uint32 buffer_size; - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) ) - return WERR_ACCESS_DENIED; - - /* we have to set the outgoing buffer size to the same as the - incoming buffer size (even in the case of failure */ - *r->out.needed = r->in.offered; - - switch ( r->in.info_level ) { - case SERVICE_CONFIG_DESCRIPTION: - { - struct SERVICE_DESCRIPTION desc_buf; - const char *description; - enum ndr_err_code ndr_err; - DATA_BLOB blob; - - description = svcctl_lookup_description(p->mem_ctx, - p->msg_ctx, - p->server_info, - info->name); - - desc_buf.description = description; - - ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &desc_buf, - (ndr_push_flags_fn_t)ndr_push_SERVICE_DESCRIPTION); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return WERR_INVALID_PARAM; - } - - buffer_size = ndr_size_SERVICE_DESCRIPTION(&desc_buf, 0); - r->out.buffer = blob.data; - - break; - } - break; - case SERVICE_CONFIG_FAILURE_ACTIONS: - { - struct SERVICE_FAILURE_ACTIONS actions; - enum ndr_err_code ndr_err; - DATA_BLOB blob; - - /* nothing to say...just service the request */ - - ZERO_STRUCT( actions ); - - ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &actions, - (ndr_push_flags_fn_t)ndr_push_SERVICE_FAILURE_ACTIONS); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return WERR_INVALID_PARAM; - } - - buffer_size = ndr_size_SERVICE_FAILURE_ACTIONS(&actions, 0); - r->out.buffer = blob.data; - - break; - } - break; - - default: - return WERR_UNKNOWN_LEVEL; - } - - buffer_size += buffer_size % 4; - *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; - - if (buffer_size > r->in.offered) - return WERR_INSUFFICIENT_BUFFER; - - return WERR_OK; -} - -/******************************************************************** - _svcctl_LockServiceDatabase -********************************************************************/ - -WERROR _svcctl_LockServiceDatabase(struct pipes_struct *p, - struct svcctl_LockServiceDatabase *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - - /* perform access checks */ - - if ( !info || (info->type != SVC_HANDLE_IS_SCM) ) - return WERR_BADFID; - - if ( !(info->access_granted & SC_RIGHT_MGR_LOCK) ) - return WERR_ACCESS_DENIED; - - /* Just open a handle. Doesn't actually lock anything */ - - return create_open_service_handle( p, r->out.lock, SVC_HANDLE_IS_DBLOCK, NULL, 0 ); -} - -/******************************************************************** - _svcctl_UnlockServiceDatabase -********************************************************************/ - -WERROR _svcctl_UnlockServiceDatabase(struct pipes_struct *p, - struct svcctl_UnlockServiceDatabase *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.lock ); - - - if ( !info || (info->type != SVC_HANDLE_IS_DBLOCK) ) - return WERR_BADFID; - - return close_policy_hnd( p, r->out.lock) ? WERR_OK : WERR_BADFID; -} - -/******************************************************************** - _svcctl_QueryServiceObjectSecurity -********************************************************************/ - -WERROR _svcctl_QueryServiceObjectSecurity(struct pipes_struct *p, - struct svcctl_QueryServiceObjectSecurity *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - struct security_descriptor *sec_desc; - NTSTATUS status; - uint8_t *buffer = NULL; - size_t len = 0; - - - /* only support the SCM and individual services */ - - if ( !info || !(info->type & (SVC_HANDLE_IS_SERVICE|SVC_HANDLE_IS_SCM)) ) - return WERR_BADFID; - - /* check access reights (according to MSDN) */ - - if ( !(info->access_granted & SEC_STD_READ_CONTROL) ) - return WERR_ACCESS_DENIED; - - /* TODO: handle something besides SECINFO_DACL */ - - if ( (r->in.security_flags & SECINFO_DACL) != SECINFO_DACL ) - return WERR_INVALID_PARAM; - - /* Lookup the security descriptor and marshall it up for a reply */ - sec_desc = svcctl_get_secdesc(p->mem_ctx, - p->msg_ctx, - get_server_info_system(), - info->name); - if (sec_desc == NULL) { - return WERR_NOMEM; - } - - *r->out.needed = ndr_size_security_descriptor(sec_desc, 0); - - if ( *r->out.needed > r->in.offered) { - return WERR_INSUFFICIENT_BUFFER; - } - - status = marshall_sec_desc(p->mem_ctx, sec_desc, &buffer, &len); - if (!NT_STATUS_IS_OK(status)) { - return ntstatus_to_werror(status); - } - - *r->out.needed = len; - r->out.buffer = buffer; - - return WERR_OK; -} - -/******************************************************************** - _svcctl_SetServiceObjectSecurity -********************************************************************/ - -WERROR _svcctl_SetServiceObjectSecurity(struct pipes_struct *p, - struct svcctl_SetServiceObjectSecurity *r) -{ - SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); - struct security_descriptor *sec_desc = NULL; - uint32 required_access; - NTSTATUS status; - - if ( !info || !(info->type & (SVC_HANDLE_IS_SERVICE|SVC_HANDLE_IS_SCM)) ) - return WERR_BADFID; - - /* can't set the security de4scriptor on the ServiceControlManager */ - - if ( info->type == SVC_HANDLE_IS_SCM ) - return WERR_ACCESS_DENIED; - - /* check the access on the open handle */ - - switch ( r->in.security_flags ) { - case SECINFO_DACL: - required_access = SEC_STD_WRITE_DAC; - break; - - case SECINFO_OWNER: - case SECINFO_GROUP: - required_access = SEC_STD_WRITE_OWNER; - break; - - case SECINFO_SACL: - return WERR_INVALID_PARAM; - default: - return WERR_INVALID_PARAM; - } - - if ( !(info->access_granted & required_access) ) - return WERR_ACCESS_DENIED; - - /* read the security descfriptor */ - - status = unmarshall_sec_desc(p->mem_ctx, - r->in.buffer, - r->in.offered, - &sec_desc); - if (!NT_STATUS_IS_OK(status)) { - return ntstatus_to_werror(status); - } - - /* store the new SD */ - - if (!svcctl_set_secdesc(p->msg_ctx, p->server_info, info->name, sec_desc)) - return WERR_ACCESS_DENIED; - - return WERR_OK; -} - - -WERROR _svcctl_DeleteService(struct pipes_struct *p, - struct svcctl_DeleteService *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_SetServiceStatus(struct pipes_struct *p, - struct svcctl_SetServiceStatus *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_NotifyBootConfigStatus(struct pipes_struct *p, - struct svcctl_NotifyBootConfigStatus *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_SCSetServiceBitsW(struct pipes_struct *p, - struct svcctl_SCSetServiceBitsW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_ChangeServiceConfigW(struct pipes_struct *p, - struct svcctl_ChangeServiceConfigW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_CreateServiceW(struct pipes_struct *p, - struct svcctl_CreateServiceW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_QueryServiceLockStatusW(struct pipes_struct *p, - struct svcctl_QueryServiceLockStatusW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_GetServiceKeyNameW(struct pipes_struct *p, - struct svcctl_GetServiceKeyNameW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_SCSetServiceBitsA(struct pipes_struct *p, - struct svcctl_SCSetServiceBitsA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_ChangeServiceConfigA(struct pipes_struct *p, - struct svcctl_ChangeServiceConfigA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_CreateServiceA(struct pipes_struct *p, - struct svcctl_CreateServiceA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_EnumDependentServicesA(struct pipes_struct *p, - struct svcctl_EnumDependentServicesA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_EnumServicesStatusA(struct pipes_struct *p, - struct svcctl_EnumServicesStatusA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_OpenSCManagerA(struct pipes_struct *p, - struct svcctl_OpenSCManagerA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_OpenServiceA(struct pipes_struct *p, - struct svcctl_OpenServiceA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_QueryServiceConfigA(struct pipes_struct *p, - struct svcctl_QueryServiceConfigA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_QueryServiceLockStatusA(struct pipes_struct *p, - struct svcctl_QueryServiceLockStatusA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_StartServiceA(struct pipes_struct *p, - struct svcctl_StartServiceA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_GetServiceDisplayNameA(struct pipes_struct *p, - struct svcctl_GetServiceDisplayNameA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_GetServiceKeyNameA(struct pipes_struct *p, - struct svcctl_GetServiceKeyNameA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_GetCurrentGroupeStateW(struct pipes_struct *p, - struct svcctl_GetCurrentGroupeStateW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_EnumServiceGroupW(struct pipes_struct *p, - struct svcctl_EnumServiceGroupW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_ChangeServiceConfig2A(struct pipes_struct *p, - struct svcctl_ChangeServiceConfig2A *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_ChangeServiceConfig2W(struct pipes_struct *p, - struct svcctl_ChangeServiceConfig2W *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_QueryServiceConfig2A(struct pipes_struct *p, - struct svcctl_QueryServiceConfig2A *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _EnumServicesStatusExA(struct pipes_struct *p, - struct EnumServicesStatusExA *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _EnumServicesStatusExW(struct pipes_struct *p, - struct EnumServicesStatusExW *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -WERROR _svcctl_SCSendTSMessage(struct pipes_struct *p, - struct svcctl_SCSendTSMessage *r) -{ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - diff --git a/source3/rpc_server/srv_svcctl_reg.c b/source3/rpc_server/srv_svcctl_reg.c deleted file mode 100644 index ca6a68a2fd..0000000000 --- a/source3/rpc_server/srv_svcctl_reg.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * SVCCTL RPC server keys initialization - * - * Copyright (c) 2005 Marcin Krzysztof Porwit - * Copyright (c) 2005 Gerald (Jerry) Carter - * Copyright (c) 2011 Andreas Schneider - * - * 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 . - */ - -#include "includes.h" -#include "services/services.h" -#include "services/svc_winreg_glue.h" -#include "../librpc/gen_ndr/ndr_winreg_c.h" -#include "rpc_client/cli_winreg_int.h" -#include "rpc_client/cli_winreg.h" -#include "rpc_server/srv_svcctl_reg.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_REGISTRY - -#define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services" - -struct rcinit_file_information { - char *description; -}; - -struct service_display_info { - const char *servicename; - const char *daemon; - const char *dispname; - const char *description; -}; - -static struct service_display_info builtin_svcs[] = { - { - "Spooler", - "smbd", - "Print Spooler", - "Internal service for spooling files to print devices" - }, - { - "NETLOGON", - "smbd", - "Net Logon", - "File service providing access to policy and profile data (not" - "remotely manageable)" - }, - { - "RemoteRegistry", - "smbd", - "Remote Registry Service", - "Internal service providing remote access to the Samba registry" - }, - { - "WINS", - "nmbd", - "Windows Internet Name Service (WINS)", - "Internal service providing a NetBIOS point-to-point name server" - "(not remotely manageable)" - }, - { NULL, NULL, NULL, NULL } -}; - -static struct service_display_info common_unix_svcs[] = { - { "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" }, - { "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" }, - { "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" }, - { "portmap", NULL, "TCP Port to RPC PortMapper",NULL }, - { "xinetd", NULL, "Internet Meta-Daemon", NULL }, - { "inet", NULL, "Internet Meta-Daemon", NULL }, - { "xntpd", NULL, "Network Time Service", NULL }, - { "ntpd", NULL, "Network Time Service", NULL }, - { "lpd", NULL, "BSD Print Spooler", NULL }, - { "nfsserver", NULL, "Network File Service", NULL }, - { "cron", NULL, "Scheduling Service", NULL }, - { "at", NULL, "Scheduling Service", NULL }, - { "nscd", NULL, "Name Service Cache Daemon", NULL }, - { "slapd", NULL, "LDAP Directory Service", NULL }, - { "ldap", NULL, "LDAP DIrectory Service", NULL }, - { "ypbind", NULL, "NIS Directory Service", NULL }, - { "courier-imap", NULL, "IMAP4 Mail Service", NULL }, - { "courier-pop3", NULL, "POP3 Mail Service", NULL }, - { "named", NULL, "Domain Name Service", NULL }, - { "bind", NULL, "Domain Name Service", NULL }, - { "httpd", NULL, "HTTP Server", NULL }, - { "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server " - "capable of implementing various protocols incluing " - "but not limited to HTTP" }, - { "autofs", NULL, "Automounter", NULL }, - { "squid", NULL, "Web Cache Proxy ", NULL }, - { "perfcountd", NULL, "Performance Monitoring Daemon", NULL }, - { "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" }, - { "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" }, - { "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" }, - { "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" }, - { "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and " - "file transferring" }, - { "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" }, - { "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" }, - { NULL, NULL, NULL, NULL } -}; - -/******************************************************************** - This is where we do the dirty work of filling in things like the - Display name, Description, etc... -********************************************************************/ -static char *svcctl_get_common_service_dispname(TALLOC_CTX *mem_ctx, - const char *servicename) -{ - uint32_t i; - - for (i = 0; common_unix_svcs[i].servicename; i++) { - if (strequal(servicename, common_unix_svcs[i].servicename)) { - char *dispname; - dispname = talloc_asprintf(mem_ctx, "%s (%s)", - common_unix_svcs[i].dispname, - common_unix_svcs[i].servicename); - if (dispname == NULL) { - return NULL; - } - return dispname; - } - } - - return talloc_strdup(mem_ctx, servicename); -} - -/******************************************************************** -********************************************************************/ -static char *svcctl_cleanup_string(TALLOC_CTX *mem_ctx, - const char *string) -{ - char *clean = NULL; - char *begin, *end; - - clean = talloc_strdup(mem_ctx, string); - if (clean == NULL) { - return NULL; - } - begin = clean; - - /* trim any beginning whilespace */ - while (isspace(*begin)) { - begin++; - } - - if (*begin == '\0') { - return NULL; - } - - /* trim any trailing whitespace or carriage returns. - Start at the end and move backwards */ - - end = begin + strlen(begin) - 1; - - while (isspace(*end) || *end=='\n' || *end=='\r') { - *end = '\0'; - end--; - } - - return begin; -} - -/******************************************************************** -********************************************************************/ -static bool read_init_file(TALLOC_CTX *mem_ctx, - const char *servicename, - struct rcinit_file_information **service_info) -{ - struct rcinit_file_information *info = NULL; - char *filepath = NULL; - char str[1024]; - XFILE *f = NULL; - char *p = NULL; - - info = talloc_zero(mem_ctx, struct rcinit_file_information); - if (info == NULL) { - return false; - } - - /* attempt the file open */ - - filepath = talloc_asprintf(mem_ctx, - "%s/%s/%s", - get_dyn_MODULESDIR(), - SVCCTL_SCRIPT_DIR, - servicename); - if (filepath == NULL) { - return false; - } - f = x_fopen( filepath, O_RDONLY, 0 ); - if (f == NULL) { - DEBUG(0,("read_init_file: failed to open [%s]\n", filepath)); - return false; - } - - while ((x_fgets(str, sizeof(str) - 1, f)) != NULL) { - /* ignore everything that is not a full line - comment starting with a '#' */ - - if (str[0] != '#') { - continue; - } - - /* Look for a line like '^#.*Description:' */ - - p = strstr(str, "Description:"); - if (p != NULL) { - char *desc; - - p += strlen( "Description:" ) + 1; - if (p == NULL) { - break; - } - - desc = svcctl_cleanup_string(mem_ctx, p); - if (desc != NULL) { - info->description = talloc_strdup(info, desc); - } - } - } - - x_fclose(f); - - if (info->description == NULL) { - info->description = talloc_strdup(info, - "External Unix Service"); - if (info->description == NULL) { - return false; - } - } - - *service_info = info; - - return true; -} - -static bool svcctl_add_service(TALLOC_CTX *mem_ctx, - struct dcerpc_binding_handle *h, - struct policy_handle *hive_hnd, - const char *key, - uint32_t access_mask, - const char *name) -{ - enum winreg_CreateAction action = REG_ACTION_NONE; - struct security_descriptor *sd = NULL; - struct policy_handle key_hnd; - struct winreg_String wkey; - struct winreg_String wkeyclass; - char *description = NULL; - char *dname = NULL; - char *ipath = NULL; - bool ok = false; - uint32_t i; - NTSTATUS status; - WERROR result = WERR_OK; - - ZERO_STRUCT(key_hnd); - - ZERO_STRUCT(wkey); - wkey.name = talloc_asprintf(mem_ctx, "%s\\%s", key, name); - if (wkey.name == NULL) { - goto done; - } - - ZERO_STRUCT(wkeyclass); - wkeyclass.name = ""; - - status = dcerpc_winreg_CreateKey(h, - mem_ctx, - hive_hnd, - wkey, - wkeyclass, - 0, - access_mask, - NULL, - &key_hnd, - &action, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, win_errstr(result))); - goto done; - } - - /* These values are hardcoded in all QueryServiceConfig() replies. - I'm just storing them here for cosmetic purposes */ - status = dcerpc_winreg_set_dword(mem_ctx, - h, - &key_hnd, - "Start", - SVCCTL_AUTO_START, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_dword(mem_ctx, - h, - &key_hnd, - "Type", - SERVICE_TYPE_WIN32_OWN_PROCESS, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_dword(mem_ctx, - h, - &key_hnd, - "ErrorControl", - SVCCTL_SVC_ERROR_NORMAL, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_sz(mem_ctx, - h, - &key_hnd, - "ObjectName", - "LocalSystem", - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - /* - * Special considerations for internal services and the DisplayName - * value. - */ - for (i = 0; builtin_svcs[i].servicename; i++) { - if (strequal(name, builtin_svcs[i].servicename)) { - ipath = talloc_asprintf(mem_ctx, - "%s/%s/%s", - get_dyn_MODULESDIR(), - SVCCTL_SCRIPT_DIR, - builtin_svcs[i].daemon); - description = talloc_strdup(mem_ctx, builtin_svcs[i].description); - dname = talloc_strdup(mem_ctx, builtin_svcs[i].dispname); - break; - } - } - - if (ipath == NULL || dname == NULL || description == NULL) { - goto done; - } - - /* Default to an external service if we haven't found a match */ - if (builtin_svcs[i].servicename == NULL) { - struct rcinit_file_information *init_info = NULL; - char *dispname = NULL; - - ipath = talloc_asprintf(mem_ctx, - "%s/%s/%s", - get_dyn_MODULESDIR(), - SVCCTL_SCRIPT_DIR, - name); - - /* lookup common unix display names */ - dispname = svcctl_get_common_service_dispname(mem_ctx, name); - dname = talloc_strdup(mem_ctx, dispname ? dispname : ""); - - /* get info from init file itself */ - if (read_init_file(mem_ctx, name, &init_info)) { - description = talloc_strdup(mem_ctx, - init_info->description); - } else { - description = talloc_strdup(mem_ctx, - "External Unix Service"); - } - } - - if (ipath == NULL || dname == NULL || description == NULL) { - goto done; - } - - status = dcerpc_winreg_set_sz(mem_ctx, - h, - &key_hnd, - "DisplayName", - dname, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_sz(mem_ctx, - h, - &key_hnd, - "ImagePath", - ipath, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_sz(mem_ctx, - h, - &key_hnd, - "Description", - description, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - sd = svcctl_gen_service_sd(mem_ctx); - if (sd == NULL) { - DEBUG(0, ("add_new_svc_name: Failed to create default " - "sec_desc!\n")); - goto done; - } - - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result); - } - ZERO_STRUCT(key_hnd); - - ZERO_STRUCT(wkey); - wkey.name = talloc_asprintf(mem_ctx, "%s\\%s\\Security", key, name); - if (wkey.name == NULL) { - result = WERR_NOMEM; - goto done; - } - - ZERO_STRUCT(wkeyclass); - wkeyclass.name = ""; - - status = dcerpc_winreg_CreateKey(h, - mem_ctx, - hive_hnd, - wkey, - wkeyclass, - 0, - access_mask, - NULL, - &key_hnd, - &action, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", - wkey.name, win_errstr(result))); - goto done; - } - - status = dcerpc_winreg_set_sd(mem_ctx, - h, - &key_hnd, - "Security", - sd, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", - win_errstr(result))); - goto done; - } - - ok = true; -done: - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result); - } - - return ok; -} - -bool svcctl_init_winreg(struct messaging_context *msg_ctx) -{ - struct dcerpc_binding_handle *h = NULL; - uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; - struct policy_handle hive_hnd, key_hnd; - const char **service_list = lp_svcctl_list(); - const char **subkeys = NULL; - uint32_t num_subkeys = 0; - char *key = NULL; - uint32_t i; - NTSTATUS status; - WERROR result = WERR_OK; - bool ok = false; - TALLOC_CTX *tmp_ctx; - - tmp_ctx = talloc_stackframe(); - if (tmp_ctx == NULL) { - return false; - } - - DEBUG(3, ("Initialise the svcctl registry keys if needed.\n")); - - ZERO_STRUCT(hive_hnd); - ZERO_STRUCT(key_hnd); - - key = talloc_strdup(tmp_ctx, TOP_LEVEL_SERVICES_KEY); - if (key == NULL) { - goto done; - } - - status = dcerpc_winreg_int_hklm_openkey(tmp_ctx, - get_server_info_system(), - msg_ctx, - &h, - key, - false, - access_mask, - &hive_hnd, - &key_hnd, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n", - key, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n", - key, win_errstr(result))); - goto done; - } - - /* get all subkeys */ - status = dcerpc_winreg_enum_keys(tmp_ctx, - h, - &key_hnd, - &num_subkeys, - &subkeys, - &result); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n", - key, nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(result)) { - DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n", - key, win_errstr(result))); - goto done; - } - - for (i = 0; builtin_svcs[i].servicename != NULL; i++) { - uint32_t j; - bool skip = false; - - for (j = 0; j < num_subkeys; j++) { - if (strequal(subkeys[i], builtin_svcs[i].servicename)) { - skip = true; - } - } - - if (skip) { - continue; - } - - ok = svcctl_add_service(tmp_ctx, - h, - &hive_hnd, - key, - access_mask, - builtin_svcs[i].servicename); - if (!ok) { - goto done; - } - } - - for (i = 0; service_list && service_list[i]; i++) { - uint32_t j; - bool skip = false; - - for (j = 0; j < num_subkeys; j++) { - if (strequal(subkeys[i], service_list[i])) { - skip = true; - } - } - - if (skip) { - continue; - } - - ok = svcctl_add_service(tmp_ctx, - h, - &hive_hnd, - key, - access_mask, - service_list[i]); - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); - } - ZERO_STRUCT(key_hnd); - - if (!ok) { - goto done; - } - } - -done: - if (is_valid_policy_hnd(&key_hnd)) { - dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); - } - - return ok; -} - -/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/srv_svcctl_reg.h b/source3/rpc_server/srv_svcctl_reg.h deleted file mode 100644 index ab12a03b7b..0000000000 --- a/source3/rpc_server/srv_svcctl_reg.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * SVCCTL RPC server keys initialization - * - * Copyright (c) 2011 Andreas Schneider - * - * 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 . - */ - -#ifndef SRV_SERVICES_REG_H -#define SRV_SERVICES_REG_H - -bool svcctl_init_winreg(struct messaging_context *msg_ctx); - -#endif /* SRV_SERVICES_REG_H */ - -/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/srv_winreg_nt.c b/source3/rpc_server/srv_winreg_nt.c deleted file mode 100644 index 91f050a099..0000000000 --- a/source3/rpc_server/srv_winreg_nt.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * - * Copyright (C) Gerald Carter 2002-2006. - * - * 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 . - */ - -/* Implementation of registry functions. */ - -#include "includes.h" -#include "../librpc/gen_ndr/srv_winreg.h" -#include "registry/reg_parse_prs.h" -#include "registry.h" -#include "registry/reg_api.h" -#include "registry/reg_api_regf.h" -#include "registry/reg_perfcount.h" -#include "rpc_misc.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -/****************************************************************** - Find a registry key handle and return a struct registry_key * - *****************************************************************/ - -static struct registry_key *find_regkey_by_hnd(struct pipes_struct *p, - struct policy_handle *hnd) -{ - struct registry_key *regkey = NULL; - - if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { - DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); - return NULL; - } - - return regkey; -} - -/******************************************************************* - Function for open a new registry handle and creating a handle - Note that P should be valid & hnd should already have space - - When we open a key, we store the full path to the key as - HK[LM|U]\\\... - *******************************************************************/ - -static WERROR open_registry_key(struct pipes_struct *p, - struct policy_handle *hnd, - struct registry_key *parent, - const char *subkeyname, - uint32_t access_desired) -{ - WERROR result = WERR_OK; - struct registry_key *key; - - if (parent == NULL) { - result = reg_openhive(p->mem_ctx, subkeyname, access_desired, - p->server_info->security_token, &key); - } - else { - result = reg_openkey(p->mem_ctx, parent, subkeyname, - access_desired, &key); - } - - if ( !W_ERROR_IS_OK(result) ) { - return result; - } - - if ( !create_policy_hnd( p, hnd, key ) ) { - return WERR_BADFILE; - } - - return WERR_OK; -} - -/******************************************************************* - Function for open a new registry handle and creating a handle - Note that P should be valid & hnd should already have space - *******************************************************************/ - -static bool close_registry_key(struct pipes_struct *p, - struct policy_handle *hnd) -{ - struct registry_key *regkey = find_regkey_by_hnd(p, hnd); - - if ( !regkey ) { - DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", - OUR_HANDLE(hnd))); - return False; - } - - close_policy_hnd(p, hnd); - - return True; -} - -/******************************************************************** - _winreg_CloseKey - ********************************************************************/ - -WERROR _winreg_CloseKey(struct pipes_struct *p, - struct winreg_CloseKey *r) -{ - /* close the policy handle */ - - if (!close_registry_key(p, r->in.handle)) - return WERR_BADFID; - - ZERO_STRUCTP(r->out.handle); - - return WERR_OK; -} - -/******************************************************************* - _winreg_OpenHKLM - ********************************************************************/ - -WERROR _winreg_OpenHKLM(struct pipes_struct *p, - struct winreg_OpenHKLM *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKLM, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKPD - ********************************************************************/ - -WERROR _winreg_OpenHKPD(struct pipes_struct *p, - struct winreg_OpenHKPD *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKPD, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKPT - ********************************************************************/ - -WERROR _winreg_OpenHKPT(struct pipes_struct *p, - struct winreg_OpenHKPT *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKPT, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKCR - ********************************************************************/ - -WERROR _winreg_OpenHKCR(struct pipes_struct *p, - struct winreg_OpenHKCR *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKCR, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKU - ********************************************************************/ - -WERROR _winreg_OpenHKU(struct pipes_struct *p, - struct winreg_OpenHKU *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKU, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKCU - ********************************************************************/ - -WERROR _winreg_OpenHKCU(struct pipes_struct *p, - struct winreg_OpenHKCU *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKCU, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKCC - ********************************************************************/ - -WERROR _winreg_OpenHKCC(struct pipes_struct *p, - struct winreg_OpenHKCC *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKCC, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKDD - ********************************************************************/ - -WERROR _winreg_OpenHKDD(struct pipes_struct *p, - struct winreg_OpenHKDD *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKDD, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenHKPN - ********************************************************************/ - -WERROR _winreg_OpenHKPN(struct pipes_struct *p, - struct winreg_OpenHKPN *r) -{ - return open_registry_key(p, r->out.handle, NULL, KEY_HKPN, r->in.access_mask); -} - -/******************************************************************* - _winreg_OpenKey - ********************************************************************/ - -WERROR _winreg_OpenKey(struct pipes_struct *p, - struct winreg_OpenKey *r) -{ - struct registry_key *parent = find_regkey_by_hnd(p, r->in.parent_handle ); - - if ( !parent ) - return WERR_BADFID; - - return open_registry_key(p, r->out.handle, parent, r->in.keyname.name, r->in.access_mask); -} - -/******************************************************************* - _winreg_QueryValue - ********************************************************************/ - -WERROR _winreg_QueryValue(struct pipes_struct *p, - struct winreg_QueryValue *r) -{ - WERROR status = WERR_BADFILE; - struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); - prs_struct prs_hkpd; - - uint8_t *outbuf = NULL; - uint32_t outbuf_size = 0; - - bool free_buf = False; - bool free_prs = False; - - if ( !regkey ) - return WERR_BADFID; - - if (r->in.value_name->name == NULL) { - return WERR_INVALID_PARAM; - } - - if ((r->out.data_length == NULL) || (r->out.type == NULL) || (r->out.data_size == NULL)) { - return WERR_INVALID_PARAM; - } - - DEBUG(7,("_winreg_QueryValue: policy key name = [%s]\n", regkey->key->name)); - DEBUG(7,("_winreg_QueryValue: policy key type = [%08x]\n", regkey->key->type)); - - /* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */ - if(regkey->key->type == REG_KEY_HKPD) - { - if (strequal(r->in.value_name->name, "Global")) { - if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL)) - return WERR_NOMEM; - status = reg_perfcount_get_hkpd( - &prs_hkpd, *r->in.data_size, &outbuf_size, NULL); - outbuf = (uint8_t *)prs_hkpd.data_p; - free_prs = True; - } - else if (strequal(r->in.value_name->name, "Counter 009")) { - outbuf_size = reg_perfcount_get_counter_names( - reg_perfcount_get_base_index(), - (char **)(void *)&outbuf); - free_buf = True; - } - else if (strequal(r->in.value_name->name, "Explain 009")) { - outbuf_size = reg_perfcount_get_counter_help( - reg_perfcount_get_base_index(), - (char **)(void *)&outbuf); - free_buf = True; - } - else if (isdigit(r->in.value_name->name[0])) { - /* we probably have a request for a specific object - * here */ - if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL)) - return WERR_NOMEM; - status = reg_perfcount_get_hkpd( - &prs_hkpd, *r->in.data_size, &outbuf_size, - r->in.value_name->name); - outbuf = (uint8_t *)prs_hkpd.data_p; - free_prs = True; - } - else { - DEBUG(3,("Unsupported key name [%s] for HKPD.\n", - r->in.value_name->name)); - return WERR_BADFILE; - } - - *r->out.type = REG_BINARY; - } - else { - struct registry_value *val; - - status = reg_queryvalue(p->mem_ctx, regkey, r->in.value_name->name, - &val); - if (!W_ERROR_IS_OK(status)) { - - DEBUG(10,("_winreg_QueryValue: reg_queryvalue failed with: %s\n", - win_errstr(status))); - - if (r->out.data_size) { - *r->out.data_size = 0; - } - if (r->out.data_length) { - *r->out.data_length = 0; - } - return status; - } - - outbuf = val->data.data; - outbuf_size = val->data.length; - *r->out.type = val->type; - } - - status = WERR_BADFILE; - - if (*r->in.data_size < outbuf_size) { - *r->out.data_size = outbuf_size; - status = r->in.data ? WERR_MORE_DATA : WERR_OK; - } else { - *r->out.data_length = outbuf_size; - *r->out.data_size = outbuf_size; - if (r->out.data) { - memcpy(r->out.data, outbuf, outbuf_size); - } - status = WERR_OK; - } - - if (free_prs) prs_mem_free(&prs_hkpd); - if (free_buf) SAFE_FREE(outbuf); - - return status; -} - -/***************************************************************************** - _winreg_QueryInfoKey - ****************************************************************************/ - -WERROR _winreg_QueryInfoKey(struct pipes_struct *p, - struct winreg_QueryInfoKey *r) -{ - WERROR status = WERR_OK; - struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); - - if ( !regkey ) - return WERR_BADFID; - - r->out.classname->name = NULL; - - status = reg_queryinfokey(regkey, r->out.num_subkeys, r->out.max_subkeylen, - r->out.max_classlen, r->out.num_values, r->out.max_valnamelen, - r->out.max_valbufsize, r->out.secdescsize, - r->out.last_changed_time); - if (!W_ERROR_IS_OK(status)) { - return status; - } - - /* - * These calculations account for the registry buffers being - * UTF-16. They are inexact at best, but so far they worked. - */ - - *r->out.max_subkeylen *= 2; - - *r->out.max_valnamelen += 1; - *r->out.max_valnamelen *= 2; - - return WERR_OK; -} - - -/***************************************************************************** - _winreg_GetVersion - ****************************************************************************/ - -WERROR _winreg_GetVersion(struct pipes_struct *p, - struct winreg_GetVersion *r) -{ - struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); - - if ( !regkey ) - return WERR_BADFID; - - return reg_getversion(r->out.version); -} - - -/***************************************************************************** - _winreg_EnumKey - ****************************************************************************/ - -WERROR _winreg_EnumKey(struct pipes_struct *p, - struct winreg_EnumKey *r) -{ - WERROR err = WERR_OK; - struct registry_key *key = find_regkey_by_hnd( p, r->in.handle ); - - if ( !key ) - return WERR_BADFID; - - if ( !r->in.name || !r->in.keyclass ) - return WERR_INVALID_PARAM; - - DEBUG(8,("_winreg_EnumKey: enumerating key [%s]\n", key->key->name)); - - err = reg_enumkey(p->mem_ctx, key, r->in.enum_index, (char **)&r->out.name->name, - r->out.last_changed_time); - if (!W_ERROR_IS_OK(err)) { - return err; - } - r->out.keyclass->name = ""; - return WERR_OK; -} - -/***************************************************************************** - _winreg_EnumValue - ****************************************************************************/ - -WERROR _winreg_EnumValue(struct pipes_struct *p, - struct winreg_EnumValue *r) -{ - WERROR err = WERR_OK; - struct registry_key *key = find_regkey_by_hnd( p, r->in.handle ); - char *valname = NULL; - struct registry_value *val = NULL; - - if ( !key ) - return WERR_BADFID; - - if ( !r->in.name ) - return WERR_INVALID_PARAM; - - DEBUG(8,("_winreg_EnumValue: enumerating values for key [%s]\n", - key->key->name)); - - err = reg_enumvalue(p->mem_ctx, key, r->in.enum_index, &valname, &val); - if (!W_ERROR_IS_OK(err)) { - return err; - } - - if (r->out.name != NULL) { - r->out.name->name = valname; - } - - if (r->out.type != NULL) { - *r->out.type = val->type; - } - - if (r->out.value != NULL) { - if ((r->out.size == NULL) || (r->out.length == NULL)) { - return WERR_INVALID_PARAM; - } - - if (val->data.length > *r->out.size) { - return WERR_MORE_DATA; - } - - memcpy( r->out.value, val->data.data, val->data.length ); - } - - if (r->out.length != NULL) { - *r->out.length = val->data.length; - } - if (r->out.size != NULL) { - *r->out.size = val->data.length; - } - - return WERR_OK; -} - -/******************************************************************* - _winreg_InitiateSystemShutdown - ********************************************************************/ - -WERROR _winreg_InitiateSystemShutdown(struct pipes_struct *p, - struct winreg_InitiateSystemShutdown *r) -{ - struct winreg_InitiateSystemShutdownEx s; - - s.in.hostname = r->in.hostname; - s.in.message = r->in.message; - s.in.timeout = r->in.timeout; - s.in.force_apps = r->in.force_apps; - s.in.do_reboot = r->in.do_reboot; - s.in.reason = 0; - - /* thunk down to _winreg_InitiateSystemShutdownEx() - (just returns a status) */ - - return _winreg_InitiateSystemShutdownEx( p, &s ); -} - -/******************************************************************* - _winreg_InitiateSystemShutdownEx - ********************************************************************/ - -#define SHUTDOWN_R_STRING "-r" -#define SHUTDOWN_F_STRING "-f" - - -WERROR _winreg_InitiateSystemShutdownEx(struct pipes_struct *p, - struct winreg_InitiateSystemShutdownEx *r) -{ - char *shutdown_script = NULL; - char *msg = NULL; - char *chkmsg = NULL; - fstring str_timeout; - fstring str_reason; - fstring do_reboot; - fstring f; - int ret = -1; - bool can_shutdown = false; - - shutdown_script = talloc_strdup(p->mem_ctx, lp_shutdown_script()); - if (!shutdown_script) { - return WERR_NOMEM; - } - if (!*shutdown_script) { - return WERR_ACCESS_DENIED; - } - - /* pull the message string and perform necessary sanity checks on it */ - - if ( r->in.message && r->in.message->string ) { - if ( (msg = talloc_strdup(p->mem_ctx, r->in.message->string )) == NULL ) { - return WERR_NOMEM; - } - chkmsg = TALLOC_ARRAY(p->mem_ctx, char, strlen(msg)+1); - if (!chkmsg) { - return WERR_NOMEM; - } - alpha_strcpy(chkmsg, msg, NULL, strlen(msg)+1); - } - - fstr_sprintf(str_timeout, "%d", r->in.timeout); - fstr_sprintf(do_reboot, r->in.do_reboot ? SHUTDOWN_R_STRING : ""); - fstr_sprintf(f, r->in.force_apps ? SHUTDOWN_F_STRING : ""); - fstr_sprintf(str_reason, "%d", r->in.reason ); - - shutdown_script = talloc_all_string_sub(p->mem_ctx, - shutdown_script, "%z", chkmsg ? chkmsg : ""); - if (!shutdown_script) { - return WERR_NOMEM; - } - shutdown_script = talloc_all_string_sub(p->mem_ctx, - shutdown_script, "%t", str_timeout); - if (!shutdown_script) { - return WERR_NOMEM; - } - shutdown_script = talloc_all_string_sub(p->mem_ctx, - shutdown_script, "%r", do_reboot); - if (!shutdown_script) { - return WERR_NOMEM; - } - shutdown_script = talloc_all_string_sub(p->mem_ctx, - shutdown_script, "%f", f); - if (!shutdown_script) { - return WERR_NOMEM; - } - shutdown_script = talloc_all_string_sub(p->mem_ctx, - shutdown_script, "%x", str_reason); - if (!shutdown_script) { - return WERR_NOMEM; - } - - can_shutdown = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_REMOTE_SHUTDOWN); - - /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root - Take the error return from the script and provide it as the Windows return code. */ - - /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ - - if ( can_shutdown ) - become_root(); - - ret = smbrun( shutdown_script, NULL ); - - if ( can_shutdown ) - unbecome_root(); - - /********** END SeRemoteShutdownPrivilege BLOCK **********/ - - DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n", - shutdown_script, ret)); - - return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED; -} - -/******************************************************************* - _winreg_AbortSystemShutdown - ********************************************************************/ - -WERROR _winreg_AbortSystemShutdown(struct pipes_struct *p, - struct winreg_AbortSystemShutdown *r) -{ - const char *abort_shutdown_script = lp_abort_shutdown_script(); - int ret = -1; - bool can_shutdown = false; - - if (!*abort_shutdown_script) - return WERR_ACCESS_DENIED; - - can_shutdown = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_REMOTE_SHUTDOWN); - - /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ - - if ( can_shutdown ) - become_root(); - - ret = smbrun( abort_shutdown_script, NULL ); - - if ( can_shutdown ) - unbecome_root(); - - /********** END SeRemoteShutdownPrivilege BLOCK **********/ - - DEBUG(3,("_winreg_AbortSystemShutdown: Running the command `%s' gave %d\n", - abort_shutdown_script, ret)); - - return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED; -} - -/******************************************************************* - ********************************************************************/ - -static int validate_reg_filename(TALLOC_CTX *ctx, char **pp_fname ) -{ - char *p = NULL; - int num_services = lp_numservices(); - int snum = -1; - const char *share_path = NULL; - char *fname = *pp_fname; - - /* convert to a unix path, stripping the C:\ along the way */ - - if (!(p = valid_share_pathname(ctx, fname))) { - return -1; - } - - /* has to exist within a valid file share */ - - for (snum=0; snumin.handle ); - char *fname = NULL; - int snum = -1; - - if ( !regkey ) - return WERR_BADFID; - - if ( !r->in.filename || !r->in.filename->name ) - return WERR_INVALID_PARAM; - - fname = talloc_strdup(p->mem_ctx, r->in.filename->name); - if (!fname) { - return WERR_NOMEM; - } - - DEBUG(8,("_winreg_RestoreKey: verifying restore of key [%s] from " - "\"%s\"\n", regkey->key->name, fname)); - - if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1) - return WERR_OBJECT_PATH_INVALID; - - /* user must posses SeRestorePrivilege for this this proceed */ - - if ( !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_RESTORE)) { - return WERR_ACCESS_DENIED; - } - - DEBUG(2,("_winreg_RestoreKey: Restoring [%s] from %s in share %s\n", - regkey->key->name, fname, lp_servicename(snum) )); - - return reg_restorekey(regkey, fname); -} - -/******************************************************************* - _winreg_SaveKey - ********************************************************************/ - -WERROR _winreg_SaveKey(struct pipes_struct *p, - struct winreg_SaveKey *r) -{ - struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); - char *fname = NULL; - int snum = -1; - - if ( !regkey ) - return WERR_BADFID; - - if ( !r->in.filename || !r->in.filename->name ) - return WERR_INVALID_PARAM; - - fname = talloc_strdup(p->mem_ctx, r->in.filename->name); - if (!fname) { - return WERR_NOMEM; - } - - DEBUG(8,("_winreg_SaveKey: verifying backup of key [%s] to \"%s\"\n", - regkey->key->name, fname)); - - if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1 ) - return WERR_OBJECT_PATH_INVALID; - - DEBUG(2,("_winreg_SaveKey: Saving [%s] to %s in share %s\n", - regkey->key->name, fname, lp_servicename(snum) )); - - return reg_savekey(regkey, fname); -} - -/******************************************************************* - _winreg_SaveKeyEx - ********************************************************************/ - -WERROR _winreg_SaveKeyEx(struct pipes_struct *p, - struct winreg_SaveKeyEx *r) -{ - /* fill in your code here if you think this call should - do anything */ - - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************* - _winreg_CreateKey - ********************************************************************/ - -WERROR _winreg_CreateKey(struct pipes_struct *p, - struct winreg_CreateKey *r) -{ - struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle); - struct registry_key *new_key = NULL; - WERROR result = WERR_OK; - - if ( !parent ) - return WERR_BADFID; - - DEBUG(10, ("_winreg_CreateKey called with parent key '%s' and " - "subkey name '%s'\n", parent->key->name, r->in.name.name)); - - result = reg_createkey(NULL, parent, r->in.name.name, r->in.access_mask, - &new_key, r->out.action_taken); - if (!W_ERROR_IS_OK(result)) { - return result; - } - - if (!create_policy_hnd(p, r->out.new_handle, new_key)) { - TALLOC_FREE(new_key); - return WERR_BADFILE; - } - - return WERR_OK; -} - -/******************************************************************* - _winreg_SetValue - ********************************************************************/ - -WERROR _winreg_SetValue(struct pipes_struct *p, - struct winreg_SetValue *r) -{ - struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); - struct registry_value *val = NULL; - - if ( !key ) - return WERR_BADFID; - - DEBUG(8,("_winreg_SetValue: Setting value for [%s:%s]\n", - key->key->name, r->in.name.name)); - - val = talloc_zero(p->mem_ctx, struct registry_value); - if (val == NULL) { - return WERR_NOMEM; - } - - val->type = r->in.type; - val->data = data_blob_talloc(p->mem_ctx, r->in.data, r->in.size); - - return reg_setvalue(key, r->in.name.name, val); -} - -/******************************************************************* - _winreg_DeleteKey - ********************************************************************/ - -WERROR _winreg_DeleteKey(struct pipes_struct *p, - struct winreg_DeleteKey *r) -{ - struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle); - - if ( !parent ) - return WERR_BADFID; - - return reg_deletekey(parent, r->in.key.name); -} - - -/******************************************************************* - _winreg_DeleteValue - ********************************************************************/ - -WERROR _winreg_DeleteValue(struct pipes_struct *p, - struct winreg_DeleteValue *r) -{ - struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); - - if ( !key ) - return WERR_BADFID; - - return reg_deletevalue(key, r->in.value.name); -} - -/******************************************************************* - _winreg_GetKeySecurity - ********************************************************************/ - -WERROR _winreg_GetKeySecurity(struct pipes_struct *p, - struct winreg_GetKeySecurity *r) -{ - struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); - WERROR err = WERR_OK; - struct security_descriptor *secdesc = NULL; - uint8 *data = NULL; - size_t len = 0; - - if ( !key ) - return WERR_BADFID; - - /* access checks first */ - - if ( !(key->key->access_granted & SEC_STD_READ_CONTROL) ) - return WERR_ACCESS_DENIED; - - err = reg_getkeysecurity(p->mem_ctx, key, &secdesc); - if (!W_ERROR_IS_OK(err)) { - return err; - } - - err = ntstatus_to_werror(marshall_sec_desc(p->mem_ctx, secdesc, - &data, &len)); - if (!W_ERROR_IS_OK(err)) { - return err; - } - - if (len > r->out.sd->size) { - r->out.sd->size = len; - return WERR_INSUFFICIENT_BUFFER; - } - - r->out.sd->size = len; - r->out.sd->len = len; - r->out.sd->data = data; - - return WERR_OK; -} - -/******************************************************************* - _winreg_SetKeySecurity - ********************************************************************/ - -WERROR _winreg_SetKeySecurity(struct pipes_struct *p, - struct winreg_SetKeySecurity *r) -{ - struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); - struct security_descriptor *secdesc = NULL; - WERROR err = WERR_OK; - - if ( !key ) - return WERR_BADFID; - - /* access checks first */ - - if ( !(key->key->access_granted & SEC_STD_WRITE_DAC) ) - return WERR_ACCESS_DENIED; - - err = ntstatus_to_werror(unmarshall_sec_desc(p->mem_ctx, r->in.sd->data, - r->in.sd->len, &secdesc)); - if (!W_ERROR_IS_OK(err)) { - return err; - } - - return reg_setkeysecurity(key, secdesc); -} - -/******************************************************************* - _winreg_FlushKey - ********************************************************************/ - -WERROR _winreg_FlushKey(struct pipes_struct *p, - struct winreg_FlushKey *r) -{ - /* I'm just replying OK because there's not a lot - here I see to do i --jerry */ - - return WERR_OK; -} - -/******************************************************************* - _winreg_UnLoadKey - ********************************************************************/ - -WERROR _winreg_UnLoadKey(struct pipes_struct *p, - struct winreg_UnLoadKey *r) -{ - /* fill in your code here if you think this call should - do anything */ - - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************* - _winreg_ReplaceKey - ********************************************************************/ - -WERROR _winreg_ReplaceKey(struct pipes_struct *p, - struct winreg_ReplaceKey *r) -{ - /* fill in your code here if you think this call should - do anything */ - - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************* - _winreg_LoadKey - ********************************************************************/ - -WERROR _winreg_LoadKey(struct pipes_struct *p, - struct winreg_LoadKey *r) -{ - /* fill in your code here if you think this call should - do anything */ - - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************* - _winreg_NotifyChangeKeyValue - ********************************************************************/ - -WERROR _winreg_NotifyChangeKeyValue(struct pipes_struct *p, - struct winreg_NotifyChangeKeyValue *r) -{ - return WERR_NOT_SUPPORTED; -} - -/******************************************************************* - _winreg_QueryMultipleValues - ********************************************************************/ - -WERROR _winreg_QueryMultipleValues(struct pipes_struct *p, - struct winreg_QueryMultipleValues *r) -{ - struct winreg_QueryMultipleValues2 r2; - uint32_t needed = 0; - - r2.in.key_handle = r->in.key_handle; - r2.in.values_in = r->in.values_in; - r2.in.num_values = r->in.num_values; - r2.in.offered = r->in.buffer_size; - r2.in.buffer = r->in.buffer; - r2.out.values_out = r->out.values_out; - r2.out.needed = &needed; - r2.out.buffer = r->out.buffer; - - return _winreg_QueryMultipleValues2(p, &r2); -} - -/******************************************************************* - ********************************************************************/ - -static WERROR construct_multiple_entry(TALLOC_CTX *mem_ctx, - const char *valuename, - uint32_t value_length, - uint32_t offset, - enum winreg_Type type, - struct QueryMultipleValue *r) -{ - r->ve_valuename = talloc_zero(mem_ctx, struct winreg_ValNameBuf); - if (r->ve_valuename == NULL) { - return WERR_NOMEM; - } - - r->ve_valuename->name = talloc_strdup(r->ve_valuename, valuename ? valuename : ""); - if (r->ve_valuename->name == NULL) { - return WERR_NOMEM; - } - - r->ve_valuename->size = strlen_m_term(r->ve_valuename->name)*2; - r->ve_valuelen = value_length; - r->ve_valueptr = offset; - r->ve_type = type; - - return WERR_OK; -} - -/******************************************************************* - _winreg_QueryMultipleValues2 - ********************************************************************/ - -WERROR _winreg_QueryMultipleValues2(struct pipes_struct *p, - struct winreg_QueryMultipleValues2 *r) -{ - struct registry_key *regkey = find_regkey_by_hnd(p, r->in.key_handle); - struct registry_value *vals = NULL; - const char **names = NULL; - uint32_t offset = 0, num_vals = 0; - DATA_BLOB result = data_blob_null; - int i = 0; - WERROR err = WERR_OK; - - if (!regkey) { - return WERR_BADFID; - } - - names = talloc_zero_array(p->mem_ctx, const char *, r->in.num_values); - if (names == NULL) { - return WERR_NOMEM; - } - - for (i=0; i < r->in.num_values; i++) { - if (r->in.values_in[i].ve_valuename && - r->in.values_in[i].ve_valuename->name) { - names[i] = talloc_strdup(names, - r->in.values_in[i].ve_valuename->name); - if (names[i] == NULL) { - return WERR_NOMEM; - } - } - } - - err = reg_querymultiplevalues(p->mem_ctx, regkey, - r->in.num_values, names, - &num_vals, &vals); - if (!W_ERROR_IS_OK(err)) { - return err; - } - - result = data_blob_talloc(p->mem_ctx, NULL, 0); - - for (i=0; i < r->in.num_values; i++) { - const char *valuename = NULL; - - if (vals[i].data.length > 0) { - if (!data_blob_append(p->mem_ctx, &result, - vals[i].data.data, - vals[i].data.length)) { - return WERR_NOMEM; - } - } - - if (r->in.values_in[i].ve_valuename && - r->in.values_in[i].ve_valuename->name) { - valuename = r->in.values_in[i].ve_valuename->name; - } - - err = construct_multiple_entry(r->out.values_out, - valuename, - vals[i].data.length, - offset, - vals[i].type, - &r->out.values_out[i]); - if (!W_ERROR_IS_OK(err)) { - return err; - } - - offset += vals[i].data.length; - } - - *r->out.needed = result.length; - - if (r->in.num_values != num_vals) { - return WERR_BADFILE; - } - - if (*r->in.offered >= *r->out.needed) { - if (r->out.buffer) { - memcpy(r->out.buffer, result.data, MIN(result.length, *r->in.offered)); - } - return WERR_OK; - } else { - return WERR_MORE_DATA; - } -} - -/******************************************************************* - _winreg_DeleteKeyEx - ********************************************************************/ - -WERROR _winreg_DeleteKeyEx(struct pipes_struct *p, - struct winreg_DeleteKeyEx *r) -{ - /* fill in your code here if you think this call should - do anything */ - - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} diff --git a/source3/rpc_server/srv_wkssvc_nt.c b/source3/rpc_server/srv_wkssvc_nt.c deleted file mode 100644 index 3926ceb27a..0000000000 --- a/source3/rpc_server/srv_wkssvc_nt.c +++ /dev/null @@ -1,1020 +0,0 @@ -/* - * 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 . - */ - -/* This is the implementation of the wks interface. */ - -#include "includes.h" -#include "librpc/gen_ndr/libnet_join.h" -#include "libnet/libnet_join.h" -#include "../libcli/auth/libcli_auth.h" -#include "../librpc/gen_ndr/srv_wkssvc.h" -#include "../libcli/security/security.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -struct dom_usr { - char *name; - char *domain; - time_t login_time; -}; - -#ifdef HAVE_GETUTXENT - -#include - -struct usrinfo { - char *name; - struct timeval login_time; -}; - -static int usr_info_cmp(const struct usrinfo *usr1, const struct usrinfo *usr2) -{ - /* Called from qsort to compare two users in a usrinfo_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 timeval_compare(&usr1->login_time, &usr2->login_time); -} - -/******************************************************************* - Get a list of the names of all users logged into this machine - ********************************************************************/ - -static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) -{ - char **users; - int i, num_users = 0; - struct usrinfo *usr_infos = NULL; - struct utmpx *u; - - while ((u = getutxent()) != NULL) { - struct usrinfo *tmp; - if (u->ut_type != USER_PROCESS) { - continue; - } - for (i = 0; i < num_users; i++) { - /* getutxent can return multiple user entries for the - * same user, so ignore any dups */ - if (strcmp(u->ut_user, usr_infos[i].name) == 0) { - break; - } - } - if (i < num_users) { - continue; - } - - tmp = talloc_realloc(mem_ctx, usr_infos, struct usrinfo, - num_users+1); - if (tmp == NULL) { - TALLOC_FREE(tmp); - endutxent(); - return NULL; - } - usr_infos = tmp; - usr_infos[num_users].name = talloc_strdup(usr_infos, - u->ut_user); - if (usr_infos[num_users].name == NULL) { - TALLOC_FREE(usr_infos); - endutxent(); - return NULL; - } - usr_infos[num_users].login_time.tv_sec = u->ut_tv.tv_sec; - usr_infos[num_users].login_time.tv_usec = u->ut_tv.tv_usec; - num_users += 1; - } - - /* Sort the user list by time, oldest first */ - TYPESAFE_QSORT(usr_infos, num_users, usr_info_cmp); - - users = (char**)talloc_array(mem_ctx, char*, num_users); - if (users) { - for (i = 0; i < num_users; i++) { - users[i] = talloc_move(users, &usr_infos[i].name); - } - } - TALLOC_FREE(usr_infos); - endutxent(); - errno = 0; - return users; -} - -#else - -static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) -{ - return NULL; -} - -#endif - -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 struct dom_usr *get_domain_userlist(TALLOC_CTX *mem_ctx) -{ - 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) { - errno = 0; - return NULL; - } - - users = talloc_array(mem_ctx, struct dom_usr, num_sessions); - if (users == NULL) { - TALLOC_FREE(session_list); - return NULL; - } - - for (i=num_users=0; iplatform_id = PLATFORM_ID_NT; /* unknown */ - info100->version_major = lp_major_announce_version(); - info100->version_minor = lp_minor_announce_version(); - - info100->server_name = talloc_asprintf_strupper_m( - info100, "%s", global_myname()); - 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 = lp_major_announce_version(); - info101->version_minor = lp_minor_announce_version(); - - info101->server_name = talloc_asprintf_strupper_m( - info101, "%s", global_myname()); - 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; - char **users; - - info102 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo102); - if (info102 == NULL) { - return NULL; - } - - info102->platform_id = PLATFORM_ID_NT; /* unknown */ - info102->version_major = lp_major_announce_version(); - info102->version_minor = lp_minor_announce_version(); - - info102->server_name = talloc_asprintf_strupper_m( - info102, "%s", global_myname()); - info102->domain_name = talloc_asprintf_strupper_m( - info102, "%s", lp_workgroup()); - info102->lan_root = ""; - - users = get_logged_on_userlist(talloc_tos()); - info102->logged_on_users = talloc_array_length(users); - - TALLOC_FREE(users); - - return info102; -} - -/******************************************************************** - Handling for RPC Workstation Service request NetWkstaGetInfo - ********************************************************************/ - -WERROR _wkssvc_NetWkstaGetInfo(struct pipes_struct *p, - struct wkssvc_NetWkstaGetInfo *r) -{ - 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_NOMEM; - } - break; - case 101: - /* Level 101 can be allowed from any logged in user */ - if (!nt_token_check_sid(&global_sid_Authenticated_Users, - p->server_info->security_token)) { - DEBUG(1,("User not allowed for NetWkstaGetInfo level " - "101\n")); - DEBUGADD(3,(" - does not have sid for Authenticated " - "Users %s:\n", - sid_string_dbg( - &global_sid_Authenticated_Users))); - security_token_debug(DBGC_CLASS, 3, - p->server_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_NOMEM; - } - break; - case 102: - /* Level 102 Should only be allowed from a domain administrator */ - if (!nt_token_check_sid(&global_sid_Builtin_Administrators, - p->server_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", - sid_string_dbg(&global_sid_Builtin_Administrators))); - security_token_debug(DBGC_CLASS, 3, - p->server_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_NOMEM; - } - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - return WERR_OK; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetWkstaSetInfo(struct pipes_struct *p, - struct wkssvc_NetWkstaSetInfo *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - 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; - char **users; - int i, num_users; - - ctr0 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr0); - if (ctr0 == NULL) { - return NULL; - } - - users = get_logged_on_userlist(talloc_tos()); - if (users == NULL && errno != 0) { - DEBUG(1,("get_logged_on_userlist error %d: %s\n", - errno, strerror(errno))); - TALLOC_FREE(ctr0); - return NULL; - } - - num_users = talloc_array_length(users); - ctr0->entries_read = num_users; - ctr0->user0 = talloc_array(ctr0, struct wkssvc_NetrWkstaUserInfo0, - num_users); - if (ctr0->user0 == NULL) { - TALLOC_FREE(ctr0); - TALLOC_FREE(users); - return NULL; - } - - for (i=0; iuser0[i].user_name = talloc_move(ctr0->user0, &users[i]); - } - TALLOC_FREE(users); - 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; - char **users; - struct dom_usr *dom_users; - const char *pwd_server; - char *pwd_tmp; - int i, j, num_users, num_dom_users; - - ctr1 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr1); - if (ctr1 == NULL) { - return NULL; - } - - users = get_logged_on_userlist(talloc_tos()); - if (users == NULL && errno != 0) { - DEBUG(1,("get_logged_on_userlist error %d: %s\n", - errno, strerror(errno))); - TALLOC_FREE(ctr1); - return NULL; - } - num_users = talloc_array_length(users); - - dom_users = get_domain_userlist(talloc_tos()); - if (dom_users == NULL && errno != 0) { - TALLOC_FREE(ctr1); - TALLOC_FREE(users); - return NULL; - } - num_dom_users = talloc_array_length(dom_users); - - ctr1->user1 = talloc_array(ctr1, struct wkssvc_NetrWkstaUserInfo1, - num_users+num_dom_users); - if (ctr1->user1 == NULL) { - TALLOC_FREE(ctr1); - TALLOC_FREE(users); - TALLOC_FREE(dom_users); - return NULL; - } - - pwd_server = ""; - - if ((pwd_tmp = talloc_strdup(ctr1->user1, lp_passwordserver()))) { - /* 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; - } - - /* Put in local users first */ - for (i=0; iuser1[i].user_name = talloc_move(ctr1->user1, &users[i]); - - /* For a local user the domain name and logon server are - * both returned as the local machine's NetBIOS name */ - ctr1->user1[i].logon_domain = ctr1->user1[i].logon_server = - talloc_asprintf_strupper_m(ctr1->user1, "%s", global_myname()); - - ctr1->user1[i].other_domains = NULL; /* Maybe in future? */ - } - - /* Now domain users */ - for (j=0; juser1[i].user_name = - talloc_strdup(ctr1->user1, dom_users[j].name); - ctr1->user1[i].logon_domain = - talloc_strdup(ctr1->user1, dom_users[j].domain); - ctr1->user1[i].logon_server = pwd_server; - - ctr1->user1[i++].other_domains = NULL; /* Maybe in future? */ - } - - ctr1->entries_read = i; - - TALLOC_FREE(users); - 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) -{ - /* This with any level should only be allowed from a domain administrator */ - if (!nt_token_check_sid(&global_sid_Builtin_Administrators, - p->server_info->security_token)) { - DEBUG(1,("User not allowed for NetWkstaEnumUsers\n")); - DEBUGADD(3,(" - does not have sid for Administrators group " - "%s\n", sid_string_dbg( - &global_sid_Builtin_Administrators))); - security_token_debug(DBGC_CLASS, 3, p->server_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_NOMEM; - } - r->out.info->level = r->in.info->level; - *r->out.entries_read = r->out.info->ctr.user0->entries_read; - *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_NOMEM; - } - r->out.info->level = r->in.info->level; - *r->out.entries_read = r->out.info->ctr.user1->entries_read; - *r->out.resume_handle = 0; - break; - default: - return WERR_UNKNOWN_LEVEL; - } - - return WERR_OK; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrWkstaUserGetInfo(struct pipes_struct *p, - struct wkssvc_NetrWkstaUserGetInfo *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrWkstaUserSetInfo(struct pipes_struct *p, - struct wkssvc_NetrWkstaUserSetInfo *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetWkstaTransportEnum(struct pipes_struct *p, - struct wkssvc_NetWkstaTransportEnum *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrWkstaTransportAdd(struct pipes_struct *p, - struct wkssvc_NetrWkstaTransportAdd *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrWkstaTransportDel(struct pipes_struct *p, - struct wkssvc_NetrWkstaTransportDel *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrUseAdd(struct pipes_struct *p, - struct wkssvc_NetrUseAdd *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrUseGetInfo(struct pipes_struct *p, - struct wkssvc_NetrUseGetInfo *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrUseDel(struct pipes_struct *p, - struct wkssvc_NetrUseDel *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrUseEnum(struct pipes_struct *p, - struct wkssvc_NetrUseEnum *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrMessageBufferSend(struct pipes_struct *p, - struct wkssvc_NetrMessageBufferSend *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrWorkstationStatisticsGet(struct pipes_struct *p, - struct wkssvc_NetrWorkstationStatisticsGet *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrLogonDomainNameAdd(struct pipes_struct *p, - struct wkssvc_NetrLogonDomainNameAdd *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrLogonDomainNameDel(struct pipes_struct *p, - struct wkssvc_NetrLogonDomainNameDel *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrJoinDomain(struct pipes_struct *p, - struct wkssvc_NetrJoinDomain *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrUnjoinDomain(struct pipes_struct *p, - struct wkssvc_NetrUnjoinDomain *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrRenameMachineInDomain(struct pipes_struct *p, - struct wkssvc_NetrRenameMachineInDomain *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrValidateName(struct pipes_struct *p, - struct wkssvc_NetrValidateName *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrGetJoinInformation(struct pipes_struct *p, - struct wkssvc_NetrGetJoinInformation *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrGetJoinableOus(struct pipes_struct *p, - struct wkssvc_NetrGetJoinableOus *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - _wkssvc_NetrJoinDomain2 - ********************************************************************/ - -WERROR _wkssvc_NetrJoinDomain2(struct pipes_struct *p, - struct wkssvc_NetrJoinDomain2 *r) -{ - struct libnet_JoinCtx *j = NULL; - char *cleartext_pwd = NULL; - char *admin_domain = NULL; - char *admin_account = NULL; - WERROR werr; - struct security_token *token = p->server_info->security_token; - - if (!r->in.domain_name) { - return WERR_INVALID_PARAM; - } - - if (!r->in.admin_account || !r->in.encrypted_password) { - return WERR_INVALID_PARAM; - } - - 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; - } - - werr = decode_wkssvc_join_password_buffer( - p->mem_ctx, r->in.encrypted_password, - &p->server_info->user_session_key, &cleartext_pwd); - if (!W_ERROR_IS_OK(werr)) { - return werr; - } - - split_domain_user(p->mem_ctx, - r->in.admin_account, - &admin_domain, - &admin_account); - - 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(); - werr = libnet_Join(p->mem_ctx, j); - 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 libnet_UnjoinCtx *u = NULL; - char *cleartext_pwd = NULL; - char *admin_domain = NULL; - char *admin_account = NULL; - WERROR werr; - struct security_token *token = p->server_info->security_token; - - if (!r->in.account || !r->in.encrypted_password) { - return WERR_INVALID_PARAM; - } - - 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; - } - - werr = decode_wkssvc_join_password_buffer( - p->mem_ctx, r->in.encrypted_password, - &p->server_info->user_session_key, &cleartext_pwd); - if (!W_ERROR_IS_OK(werr)) { - return werr; - } - - split_domain_user(p->mem_ctx, - r->in.account, - &admin_domain, - &admin_account); - - 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(); - werr = libnet_Unjoin(p->mem_ctx, u); - 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 */ - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrValidateName2(struct pipes_struct *p, - struct wkssvc_NetrValidateName2 *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrGetJoinableOus2(struct pipes_struct *p, - struct wkssvc_NetrGetJoinableOus2 *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrAddAlternateComputerName(struct pipes_struct *p, - struct wkssvc_NetrAddAlternateComputerName *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrRemoveAlternateComputerName(struct pipes_struct *p, - struct wkssvc_NetrRemoveAlternateComputerName *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrSetPrimaryComputername(struct pipes_struct *p, - struct wkssvc_NetrSetPrimaryComputername *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - -/******************************************************************** - ********************************************************************/ - -WERROR _wkssvc_NetrEnumerateComputerNames(struct pipes_struct *p, - struct wkssvc_NetrEnumerateComputerNames *r) -{ - /* FIXME: Add implementation code here */ - p->rng_fault_state = True; - return WERR_NOT_SUPPORTED; -} - diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c new file mode 100644 index 0000000000..cd4ada1b90 --- /dev/null +++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c @@ -0,0 +1,2819 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Jeremy Allison 2001. + * Copyright (C) Nigel Williams 2001. + * Copyright (C) Gerald (Jerry) Carter 2006. + * Copyright (C) Guenther Deschner 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 . + */ + +/* This is the implementation of the srvsvc pipe. */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_srvsvc.h" +#include "librpc/gen_ndr/messaging.h" +#include "../libcli/security/security.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "dbwrap.h" + +extern const struct generic_mapping file_generic_mapping; + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +#define MAX_SERVER_DISK_ENTRIES 15 + +/* Use for enumerating connections, pipes, & files */ + +struct file_enum_count { + TALLOC_CTX *ctx; + const char *username; + struct srvsvc_NetFileCtr3 *ctr3; +}; + +struct sess_file_count { + struct server_id pid; + uid_t uid; + int count; +}; + +/**************************************************************************** + Count the entries belonging to a service in the connection db. +****************************************************************************/ + +static int pipe_enum_fn( struct db_record *rec, void *p) +{ + struct pipe_open_rec prec; + struct file_enum_count *fenum = (struct file_enum_count *)p; + struct srvsvc_NetFileInfo3 *f; + int i = fenum->ctr3->count; + char *fullpath = NULL; + const char *username; + + if (rec->value.dsize != sizeof(struct pipe_open_rec)) + return 0; + + memcpy(&prec, rec->value.dptr, sizeof(struct pipe_open_rec)); + + if ( !process_exists(prec.pid) ) { + return 0; + } + + username = uidtoname(prec.uid); + + if ((fenum->username != NULL) + && !strequal(username, fenum->username)) { + return 0; + } + + fullpath = talloc_asprintf(fenum->ctx, "\\PIPE\\%s", prec.name ); + if (!fullpath) { + return 1; + } + + f = TALLOC_REALLOC_ARRAY(fenum->ctx, fenum->ctr3->array, + struct srvsvc_NetFileInfo3, i+1); + if ( !f ) { + DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1)); + return 1; + } + fenum->ctr3->array = f; + + fenum->ctr3->array[i].fid = + (((uint32_t)(procid_to_pid(&prec.pid))<<16) | prec.pnum); + fenum->ctr3->array[i].permissions = + (FILE_READ_DATA|FILE_WRITE_DATA); + fenum->ctr3->array[i].num_locks = 0; + fenum->ctr3->array[i].path = fullpath; + fenum->ctr3->array[i].user = username; + + fenum->ctr3->count++; + + return 0; +} + +/******************************************************************* +********************************************************************/ + +static WERROR net_enum_pipes(TALLOC_CTX *ctx, + const char *username, + struct srvsvc_NetFileCtr3 **ctr3, + uint32_t resume ) +{ + struct file_enum_count fenum; + + fenum.ctx = ctx; + fenum.username = username; + fenum.ctr3 = *ctr3; + + if (connections_traverse(pipe_enum_fn, &fenum) == -1) { + DEBUG(0,("net_enum_pipes: traverse of connections.tdb " + "failed\n")); + return WERR_NOMEM; + } + + *ctr3 = fenum.ctr3; + + return WERR_OK; +} + +/******************************************************************* +********************************************************************/ + +static void enum_file_fn( const struct share_mode_entry *e, + const char *sharepath, const char *fname, + void *private_data ) +{ + struct file_enum_count *fenum = + (struct file_enum_count *)private_data; + + struct srvsvc_NetFileInfo3 *f; + int i = fenum->ctr3->count; + files_struct fsp; + struct byte_range_lock *brl; + int num_locks = 0; + char *fullpath = NULL; + uint32 permissions; + const char *username; + + /* If the pid was not found delete the entry from connections.tdb */ + + if ( !process_exists(e->pid) ) { + return; + } + + username = uidtoname(e->uid); + + if ((fenum->username != NULL) + && !strequal(username, fenum->username)) { + return; + } + + f = TALLOC_REALLOC_ARRAY(fenum->ctx, fenum->ctr3->array, + struct srvsvc_NetFileInfo3, i+1); + if ( !f ) { + DEBUG(0,("conn_enum_fn: realloc failed for %d items\n", i+1)); + return; + } + fenum->ctr3->array = f; + + /* need to count the number of locks on a file */ + + ZERO_STRUCT( fsp ); + fsp.file_id = e->id; + + if ( (brl = brl_get_locks(talloc_tos(), &fsp)) != NULL ) { + num_locks = brl->num_locks; + TALLOC_FREE(brl); + } + + if ( strcmp( fname, "." ) == 0 ) { + fullpath = talloc_asprintf(fenum->ctx, "C:%s", sharepath ); + } else { + fullpath = talloc_asprintf(fenum->ctx, "C:%s/%s", + sharepath, fname ); + } + if (!fullpath) { + return; + } + string_replace( fullpath, '/', '\\' ); + + /* mask out create (what ever that is) */ + permissions = e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA); + + /* now fill in the srvsvc_NetFileInfo3 struct */ + + fenum->ctr3->array[i].fid = + (((uint32_t)(procid_to_pid(&e->pid))<<16) | e->share_file_id); + fenum->ctr3->array[i].permissions = permissions; + fenum->ctr3->array[i].num_locks = num_locks; + fenum->ctr3->array[i].path = fullpath; + fenum->ctr3->array[i].user = username; + + fenum->ctr3->count++; +} + +/******************************************************************* +********************************************************************/ + +static WERROR net_enum_files(TALLOC_CTX *ctx, + const char *username, + struct srvsvc_NetFileCtr3 **ctr3, + uint32_t resume) +{ + struct file_enum_count f_enum_cnt; + + f_enum_cnt.ctx = ctx; + f_enum_cnt.username = username; + f_enum_cnt.ctr3 = *ctr3; + + share_mode_forall( enum_file_fn, (void *)&f_enum_cnt ); + + *ctr3 = f_enum_cnt.ctr3; + + return WERR_OK; +} + +/******************************************************************* + Utility function to get the 'type' of a share from an snum. + ********************************************************************/ +static uint32 get_share_type(int snum) +{ + /* work out the share type */ + uint32 type = STYPE_DISKTREE; + + if (lp_print_ok(snum)) + type = STYPE_PRINTQ; + if (strequal(lp_fstype(snum), "IPC")) + type = STYPE_IPC; + if (lp_administrative_share(snum)) + type |= STYPE_HIDDEN; + + return type; +} + +/******************************************************************* + Fill in a share info level 0 structure. + ********************************************************************/ + +static void init_srv_share_info_0(struct pipes_struct *p, + struct srvsvc_NetShareInfo0 *r, int snum) +{ + r->name = lp_servicename(snum); +} + +/******************************************************************* + Fill in a share info level 1 structure. + ********************************************************************/ + +static void init_srv_share_info_1(struct pipes_struct *p, + struct srvsvc_NetShareInfo1 *r, + int snum) +{ + char *net_name = lp_servicename(snum); + char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); + + if (remark) { + remark = talloc_sub_advanced( + p->mem_ctx, lp_servicename(snum), + get_current_username(), lp_pathname(snum), + p->server_info->utok.uid, get_current_username(), + "", remark); + } + + r->name = net_name; + r->type = get_share_type(snum); + r->comment = remark ? remark : ""; +} + +/******************************************************************* + Fill in a share info level 2 structure. + ********************************************************************/ + +static void init_srv_share_info_2(struct pipes_struct *p, + struct srvsvc_NetShareInfo2 *r, + int snum) +{ + char *remark = NULL; + char *path = NULL; + int max_connections = lp_max_connections(snum); + uint32_t max_uses = max_connections!=0 ? max_connections : (uint32_t)-1; + char *net_name = lp_servicename(snum); + + remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); + if (remark) { + remark = talloc_sub_advanced( + p->mem_ctx, lp_servicename(snum), + get_current_username(), lp_pathname(snum), + p->server_info->utok.uid, get_current_username(), + "", remark); + } + path = talloc_asprintf(p->mem_ctx, + "C:%s", lp_pathname(snum)); + + if (path) { + /* + * Change / to \\ so that win2k will see it as a valid path. + * This was added to enable use of browsing in win2k add + * share dialog. + */ + + string_replace(path, '/', '\\'); + } + + r->name = net_name; + r->type = get_share_type(snum); + r->comment = remark ? remark : ""; + r->permissions = 0; + r->max_users = max_uses; + r->current_users = count_current_connections(net_name, false); + r->path = path ? path : ""; + r->password = ""; +} + +/******************************************************************* + Map any generic bits to file specific bits. +********************************************************************/ + +static void map_generic_share_sd_bits(struct security_descriptor *psd) +{ + int i; + struct security_acl *ps_dacl = NULL; + + if (!psd) + return; + + ps_dacl = psd->dacl; + if (!ps_dacl) + return; + + for (i = 0; i < ps_dacl->num_aces; i++) { + struct security_ace *psa = &ps_dacl->aces[i]; + uint32 orig_mask = psa->access_mask; + + se_map_generic(&psa->access_mask, &file_generic_mapping); + psa->access_mask |= orig_mask; + } +} + +/******************************************************************* + Fill in a share info level 501 structure. +********************************************************************/ + +static void init_srv_share_info_501(struct pipes_struct *p, + struct srvsvc_NetShareInfo501 *r, int snum) +{ + const char *net_name = lp_servicename(snum); + char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); + + if (remark) { + remark = talloc_sub_advanced( + p->mem_ctx, lp_servicename(snum), + get_current_username(), lp_pathname(snum), + p->server_info->utok.uid, get_current_username(), + "", remark); + } + + r->name = net_name; + r->type = get_share_type(snum); + r->comment = remark ? remark : ""; + r->csc_policy = (lp_csc_policy(snum) << 4); +} + +/******************************************************************* + Fill in a share info level 502 structure. + ********************************************************************/ + +static void init_srv_share_info_502(struct pipes_struct *p, + struct srvsvc_NetShareInfo502 *r, int snum) +{ + const char *net_name = lp_servicename(snum); + char *path = NULL; + struct security_descriptor *sd = NULL; + struct sec_desc_buf *sd_buf = NULL; + size_t sd_size = 0; + TALLOC_CTX *ctx = p->mem_ctx; + char *remark = talloc_strdup(ctx, lp_comment(snum)); + + if (remark) { + remark = talloc_sub_advanced( + p->mem_ctx, lp_servicename(snum), + get_current_username(), lp_pathname(snum), + p->server_info->utok.uid, get_current_username(), + "", remark); + } + path = talloc_asprintf(ctx, "C:%s", lp_pathname(snum)); + if (path) { + /* + * Change / to \\ so that win2k will see it as a valid path. This was added to + * enable use of browsing in win2k add share dialog. + */ + string_replace(path, '/', '\\'); + } + + sd = get_share_security(ctx, lp_servicename(snum), &sd_size); + + sd_buf = make_sec_desc_buf(p->mem_ctx, sd_size, sd); + + r->name = net_name; + r->type = get_share_type(snum); + r->comment = remark ? remark : ""; + r->permissions = 0; + r->max_users = (uint32_t)-1; + r->current_users = 1; /* ??? */ + r->path = path ? path : ""; + r->password = ""; + r->sd_buf = *sd_buf; +} + +/*************************************************************************** + Fill in a share info level 1004 structure. + ***************************************************************************/ + +static void init_srv_share_info_1004(struct pipes_struct *p, + struct srvsvc_NetShareInfo1004 *r, + int snum) +{ + char *remark = talloc_strdup(p->mem_ctx, lp_comment(snum)); + + if (remark) { + remark = talloc_sub_advanced( + p->mem_ctx, lp_servicename(snum), + get_current_username(), lp_pathname(snum), + p->server_info->utok.uid, get_current_username(), + "", remark); + } + + r->comment = remark ? remark : ""; +} + +/*************************************************************************** + Fill in a share info level 1005 structure. + ***************************************************************************/ + +static void init_srv_share_info_1005(struct pipes_struct *p, + struct srvsvc_NetShareInfo1005 *r, + int snum) +{ + uint32_t dfs_flags = 0; + + if (lp_host_msdfs() && lp_msdfs_root(snum)) { + dfs_flags |= SHARE_1005_IN_DFS | SHARE_1005_DFS_ROOT; + } + + dfs_flags |= lp_csc_policy(snum) << SHARE_1005_CSC_POLICY_SHIFT; + + r->dfs_flags = dfs_flags; +} + +/*************************************************************************** + Fill in a share info level 1006 structure. + ***************************************************************************/ + +static void init_srv_share_info_1006(struct pipes_struct *p, + struct srvsvc_NetShareInfo1006 *r, + int snum) +{ + r->max_users = (uint32_t)-1; +} + +/*************************************************************************** + Fill in a share info level 1007 structure. + ***************************************************************************/ + +static void init_srv_share_info_1007(struct pipes_struct *p, + struct srvsvc_NetShareInfo1007 *r, + int snum) +{ + r->flags = 0; + r->alternate_directory_name = ""; +} + +/******************************************************************* + Fill in a share info level 1501 structure. + ********************************************************************/ + +static void init_srv_share_info_1501(struct pipes_struct *p, + struct sec_desc_buf *r, + int snum) +{ + struct security_descriptor *sd; + size_t sd_size; + TALLOC_CTX *ctx = p->mem_ctx; + + sd = get_share_security(ctx, lp_servicename(snum), &sd_size); + + r = make_sec_desc_buf(p->mem_ctx, sd_size, sd); +} + +/******************************************************************* + True if it ends in '$'. + ********************************************************************/ + +static bool is_hidden_share(int snum) +{ + const char *net_name = lp_servicename(snum); + + return (net_name[strlen(net_name) - 1] == '$') ? True : False; +} + +/******************************************************************* + Verify user is allowed to view share, access based enumeration +********************************************************************/ +static bool is_enumeration_allowed(struct pipes_struct *p, + int snum) +{ + if (!lp_access_based_share_enum(snum)) + return true; + + return share_access_check(p->server_info->security_token, lp_servicename(snum), + FILE_READ_DATA); +} + +/******************************************************************* + Fill in a share info structure. + ********************************************************************/ + +static WERROR init_srv_share_info_ctr(struct pipes_struct *p, + struct srvsvc_NetShareInfoCtr *info_ctr, + uint32_t *resume_handle_p, + uint32_t *total_entries, + bool all_shares) +{ + int num_entries = 0; + int alloc_entries = 0; + int num_services = 0; + int snum; + TALLOC_CTX *ctx = p->mem_ctx; + int i = 0; + int valid_share_count = 0; + bool *allowed = 0; + union srvsvc_NetShareCtr ctr; + uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; + + DEBUG(5,("init_srv_share_info_ctr\n")); + + /* Ensure all the usershares are loaded. */ + become_root(); + load_usershare_shares(); + load_registry_shares(); + num_services = lp_numservices(); + unbecome_root(); + + allowed = TALLOC_ZERO_ARRAY(ctx, bool, num_services); + W_ERROR_HAVE_NO_MEMORY(allowed); + + /* Count the number of entries. */ + for (snum = 0; snum < num_services; snum++) { + if (lp_browseable(snum) && lp_snum_ok(snum) && + is_enumeration_allowed(p, snum) && + (all_shares || !is_hidden_share(snum)) ) { + DEBUG(10, ("counting service %s\n", + lp_servicename(snum) ? lp_servicename(snum) : "(null)")); + allowed[snum] = true; + num_entries++; + } else { + DEBUG(10, ("NOT counting service %s\n", + lp_servicename(snum) ? lp_servicename(snum) : "(null)")); + } + } + + if (!num_entries || (resume_handle >= num_entries)) { + return WERR_OK; + } + + /* Calculate alloc entries. */ + alloc_entries = num_entries - resume_handle; + switch (info_ctr->level) { + case 0: + ctr.ctr0 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr0); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr0); + + ctr.ctr0->count = alloc_entries; + ctr.ctr0->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo0, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr0->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_0(p, &ctr.ctr0->array[i++], snum); + } + } + + break; + + case 1: + ctr.ctr1 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1); + + ctr.ctr1->count = alloc_entries; + ctr.ctr1->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_1(p, &ctr.ctr1->array[i++], snum); + } + } + + break; + + case 2: + ctr.ctr2 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr2); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr2); + + ctr.ctr2->count = alloc_entries; + ctr.ctr2->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo2, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr2->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_2(p, &ctr.ctr2->array[i++], snum); + } + } + + break; + + case 501: + ctr.ctr501 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr501); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr501); + + ctr.ctr501->count = alloc_entries; + ctr.ctr501->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo501, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr501->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_501(p, &ctr.ctr501->array[i++], snum); + } + } + + break; + + case 502: + ctr.ctr502 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr502); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr502); + + ctr.ctr502->count = alloc_entries; + ctr.ctr502->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo502, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr502->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_502(p, &ctr.ctr502->array[i++], snum); + } + } + + break; + + case 1004: + ctr.ctr1004 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1004); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1004); + + ctr.ctr1004->count = alloc_entries; + ctr.ctr1004->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1004, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1004->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_1004(p, &ctr.ctr1004->array[i++], snum); + } + } + + break; + + case 1005: + ctr.ctr1005 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1005); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1005); + + ctr.ctr1005->count = alloc_entries; + ctr.ctr1005->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1005, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1005->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_1005(p, &ctr.ctr1005->array[i++], snum); + } + } + + break; + + case 1006: + ctr.ctr1006 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1006); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1006); + + ctr.ctr1006->count = alloc_entries; + ctr.ctr1006->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1006, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1006->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_1006(p, &ctr.ctr1006->array[i++], snum); + } + } + + break; + + case 1007: + ctr.ctr1007 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1007); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1007); + + ctr.ctr1007->count = alloc_entries; + ctr.ctr1007->array = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetShareInfo1007, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1007->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_1007(p, &ctr.ctr1007->array[i++], snum); + } + } + + break; + + case 1501: + ctr.ctr1501 = TALLOC_ZERO_P(ctx, struct srvsvc_NetShareCtr1501); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1501); + + ctr.ctr1501->count = alloc_entries; + ctr.ctr1501->array = TALLOC_ZERO_ARRAY(ctx, struct sec_desc_buf, alloc_entries); + W_ERROR_HAVE_NO_MEMORY(ctr.ctr1501->array); + + for (snum = 0; snum < num_services; snum++) { + if (allowed[snum] && + (resume_handle <= (i + valid_share_count++)) ) { + init_srv_share_info_1501(p, &ctr.ctr1501->array[i++], snum); + } + } + + break; + + default: + DEBUG(5,("init_srv_share_info_ctr: unsupported switch value %d\n", + info_ctr->level)); + return WERR_UNKNOWN_LEVEL; + } + + *total_entries = alloc_entries; + if (resume_handle_p) { + if (all_shares) { + *resume_handle_p = (num_entries == 0) ? *resume_handle_p : 0; + } else { + *resume_handle_p = num_entries; + } + } + + info_ctr->ctr = ctr; + + return WERR_OK; +} + +/******************************************************************* + fill in a sess info level 0 structure. + ********************************************************************/ + +static WERROR init_srv_sess_info_0(struct pipes_struct *p, + struct srvsvc_NetSessCtr0 *ctr0, + uint32_t *resume_handle_p, + uint32_t *total_entries) +{ + struct sessionid *session_list; + uint32_t num_entries = 0; + uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; + *total_entries = list_sessions(p->mem_ctx, &session_list); + + DEBUG(5,("init_srv_sess_info_0\n")); + + if (ctr0 == NULL) { + if (resume_handle_p) { + *resume_handle_p = 0; + } + return WERR_OK; + } + + for (; resume_handle < *total_entries; resume_handle++) { + + ctr0->array = TALLOC_REALLOC_ARRAY(p->mem_ctx, + ctr0->array, + struct srvsvc_NetSessInfo0, + num_entries+1); + W_ERROR_HAVE_NO_MEMORY(ctr0->array); + + ctr0->array[num_entries].client = + session_list[resume_handle].remote_machine; + + num_entries++; + } + + ctr0->count = num_entries; + + if (resume_handle_p) { + if (*resume_handle_p >= *total_entries) { + *resume_handle_p = 0; + } else { + *resume_handle_p = resume_handle; + } + } + + return WERR_OK; +} + +/******************************************************************* +********************************************************************/ + +static void sess_file_fn( const struct share_mode_entry *e, + const char *sharepath, const char *fname, + void *data ) +{ + struct sess_file_count *sess = (struct sess_file_count *)data; + + if ( procid_equal(&e->pid, &sess->pid) && (sess->uid == e->uid) ) { + sess->count++; + } + + return; +} + +/******************************************************************* +********************************************************************/ + +static int net_count_files( uid_t uid, struct server_id pid ) +{ + struct sess_file_count s_file_cnt; + + s_file_cnt.count = 0; + s_file_cnt.uid = uid; + s_file_cnt.pid = pid; + + share_mode_forall( sess_file_fn, &s_file_cnt ); + + return s_file_cnt.count; +} + +/******************************************************************* + fill in a sess info level 1 structure. + ********************************************************************/ + +static WERROR init_srv_sess_info_1(struct pipes_struct *p, + struct srvsvc_NetSessCtr1 *ctr1, + uint32_t *resume_handle_p, + uint32_t *total_entries) +{ + struct sessionid *session_list; + uint32_t num_entries = 0; + time_t now = time(NULL); + uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; + + ZERO_STRUCTP(ctr1); + + if (ctr1 == NULL) { + if (resume_handle_p) { + *resume_handle_p = 0; + } + return WERR_OK; + } + + *total_entries = list_sessions(p->mem_ctx, &session_list); + + for (; resume_handle < *total_entries; resume_handle++) { + uint32 num_files; + uint32 connect_time; + struct passwd *pw = sys_getpwnam(session_list[resume_handle].username); + bool guest; + + if ( !pw ) { + DEBUG(10,("init_srv_sess_info_1: failed to find owner: %s\n", + session_list[resume_handle].username)); + continue; + } + + connect_time = (uint32_t)(now - session_list[resume_handle].connect_start); + num_files = net_count_files(pw->pw_uid, session_list[resume_handle].pid); + guest = strequal( session_list[resume_handle].username, lp_guestaccount() ); + + ctr1->array = TALLOC_REALLOC_ARRAY(p->mem_ctx, + ctr1->array, + struct srvsvc_NetSessInfo1, + num_entries+1); + W_ERROR_HAVE_NO_MEMORY(ctr1->array); + + ctr1->array[num_entries].client = session_list[resume_handle].remote_machine; + ctr1->array[num_entries].user = session_list[resume_handle].username; + ctr1->array[num_entries].num_open = num_files; + ctr1->array[num_entries].time = connect_time; + ctr1->array[num_entries].idle_time = 0; + ctr1->array[num_entries].user_flags = guest; + + num_entries++; + } + + ctr1->count = num_entries; + + if (resume_handle_p) { + if (*resume_handle_p >= *total_entries) { + *resume_handle_p = 0; + } else { + *resume_handle_p = resume_handle; + } + } + + return WERR_OK; +} + +/******************************************************************* + fill in a conn info level 0 structure. + ********************************************************************/ + +static WERROR init_srv_conn_info_0(struct srvsvc_NetConnCtr0 *ctr0, + uint32_t *resume_handle_p, + uint32_t *total_entries) +{ + uint32_t num_entries = 0; + uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; + + DEBUG(5,("init_srv_conn_info_0\n")); + + if (ctr0 == NULL) { + if (resume_handle_p) { + *resume_handle_p = 0; + } + return WERR_OK; + } + + *total_entries = 1; + + ZERO_STRUCTP(ctr0); + + for (; resume_handle < *total_entries; resume_handle++) { + + ctr0->array = TALLOC_REALLOC_ARRAY(talloc_tos(), + ctr0->array, + struct srvsvc_NetConnInfo0, + num_entries+1); + if (!ctr0->array) { + return WERR_NOMEM; + } + + ctr0->array[num_entries].conn_id = *total_entries; + + /* move on to creating next connection */ + num_entries++; + } + + ctr0->count = num_entries; + *total_entries = num_entries; + + if (resume_handle_p) { + if (*resume_handle_p >= *total_entries) { + *resume_handle_p = 0; + } else { + *resume_handle_p = resume_handle; + } + } + + return WERR_OK; +} + +/******************************************************************* + fill in a conn info level 1 structure. + ********************************************************************/ + +static WERROR init_srv_conn_info_1(struct srvsvc_NetConnCtr1 *ctr1, + uint32_t *resume_handle_p, + uint32_t *total_entries) +{ + uint32_t num_entries = 0; + uint32_t resume_handle = resume_handle_p ? *resume_handle_p : 0; + + DEBUG(5,("init_srv_conn_info_1\n")); + + if (ctr1 == NULL) { + if (resume_handle_p) { + *resume_handle_p = 0; + } + return WERR_OK; + } + + *total_entries = 1; + + ZERO_STRUCTP(ctr1); + + for (; resume_handle < *total_entries; resume_handle++) { + + ctr1->array = TALLOC_REALLOC_ARRAY(talloc_tos(), + ctr1->array, + struct srvsvc_NetConnInfo1, + num_entries+1); + if (!ctr1->array) { + return WERR_NOMEM; + } + + ctr1->array[num_entries].conn_id = *total_entries; + ctr1->array[num_entries].conn_type = 0x3; + ctr1->array[num_entries].num_open = 1; + ctr1->array[num_entries].num_users = 1; + ctr1->array[num_entries].conn_time = 3; + ctr1->array[num_entries].user = "dummy_user"; + ctr1->array[num_entries].share = "IPC$"; + + /* move on to creating next connection */ + num_entries++; + } + + ctr1->count = num_entries; + *total_entries = num_entries; + + if (resume_handle_p) { + if (*resume_handle_p >= *total_entries) { + *resume_handle_p = 0; + } else { + *resume_handle_p = resume_handle; + } + } + + return WERR_OK; +} + +/******************************************************************* + _srvsvc_NetFileEnum +*******************************************************************/ + +WERROR _srvsvc_NetFileEnum(struct pipes_struct *p, + struct srvsvc_NetFileEnum *r) +{ + TALLOC_CTX *ctx = NULL; + struct srvsvc_NetFileCtr3 *ctr3; + uint32_t resume_hnd = 0; + WERROR werr; + + switch (r->in.info_ctr->level) { + case 3: + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + if (!nt_token_check_sid(&global_sid_Builtin_Administrators, + p->server_info->security_token)) { + DEBUG(1, ("Enumerating files only allowed for " + "administrators\n")); + return WERR_ACCESS_DENIED; + } + + ctx = talloc_tos(); + ctr3 = r->in.info_ctr->ctr.ctr3; + if (!ctr3) { + werr = WERR_INVALID_PARAM; + goto done; + } + + /* TODO -- Windows enumerates + (b) active pipes + (c) open directories and files */ + + werr = net_enum_files(ctx, r->in.user, &ctr3, resume_hnd); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = net_enum_pipes(ctx, r->in.user, &ctr3, resume_hnd); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + *r->out.totalentries = ctr3->count; + r->out.info_ctr->ctr.ctr3->array = ctr3->array; + r->out.info_ctr->ctr.ctr3->count = ctr3->count; + + werr = WERR_OK; + + done: + return werr; +} + +/******************************************************************* + _srvsvc_NetSrvGetInfo +********************************************************************/ + +WERROR _srvsvc_NetSrvGetInfo(struct pipes_struct *p, + struct srvsvc_NetSrvGetInfo *r) +{ + WERROR status = WERR_OK; + + DEBUG(5,("_srvsvc_NetSrvGetInfo: %d\n", __LINE__)); + + if (!pipe_access_check(p)) { + DEBUG(3, ("access denied to _srvsvc_NetSrvGetInfo\n")); + return WERR_ACCESS_DENIED; + } + + switch (r->in.level) { + + /* Technically level 102 should only be available to + Administrators but there isn't anything super-secret + here, as most of it is made up. */ + + case 102: { + struct srvsvc_NetSrvInfo102 *info102; + + info102 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo102); + if (!info102) { + return WERR_NOMEM; + } + + info102->platform_id = PLATFORM_ID_NT; + info102->server_name = global_myname(); + info102->version_major = lp_major_announce_version(); + info102->version_minor = lp_minor_announce_version(); + info102->server_type = lp_default_server_announce(); + info102->comment = string_truncate(lp_serverstring(), + MAX_SERVER_STRING_LENGTH); + info102->users = 0xffffffff; + info102->disc = 0xf; + info102->hidden = 0; + info102->announce = 240; + info102->anndelta = 3000; + info102->licenses = 100000; + info102->userpath = "C:\\"; + + r->out.info->info102 = info102; + break; + } + case 101: { + struct srvsvc_NetSrvInfo101 *info101; + + info101 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo101); + if (!info101) { + return WERR_NOMEM; + } + + info101->platform_id = PLATFORM_ID_NT; + info101->server_name = global_myname(); + info101->version_major = lp_major_announce_version(); + info101->version_minor = lp_minor_announce_version(); + info101->server_type = lp_default_server_announce(); + info101->comment = string_truncate(lp_serverstring(), + MAX_SERVER_STRING_LENGTH); + + r->out.info->info101 = info101; + break; + } + case 100: { + struct srvsvc_NetSrvInfo100 *info100; + + info100 = TALLOC_P(p->mem_ctx, struct srvsvc_NetSrvInfo100); + if (!info100) { + return WERR_NOMEM; + } + + info100->platform_id = PLATFORM_ID_NT; + info100->server_name = global_myname(); + + r->out.info->info100 = info100; + + break; + } + default: + status = WERR_UNKNOWN_LEVEL; + break; + } + + DEBUG(5,("_srvsvc_NetSrvGetInfo: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* + _srvsvc_NetSrvSetInfo +********************************************************************/ + +WERROR _srvsvc_NetSrvSetInfo(struct pipes_struct *p, + struct srvsvc_NetSrvSetInfo *r) +{ + WERROR status = WERR_OK; + + DEBUG(5,("_srvsvc_NetSrvSetInfo: %d\n", __LINE__)); + + /* Set up the net server set info structure. */ + + DEBUG(5,("_srvsvc_NetSrvSetInfo: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* + _srvsvc_NetConnEnum +********************************************************************/ + +WERROR _srvsvc_NetConnEnum(struct pipes_struct *p, + struct srvsvc_NetConnEnum *r) +{ + WERROR werr; + + DEBUG(5,("_srvsvc_NetConnEnum: %d\n", __LINE__)); + + if (!nt_token_check_sid(&global_sid_Builtin_Administrators, + p->server_info->security_token)) { + DEBUG(1, ("Enumerating connections only allowed for " + "administrators\n")); + return WERR_ACCESS_DENIED; + } + + switch (r->in.info_ctr->level) { + case 0: + werr = init_srv_conn_info_0(r->in.info_ctr->ctr.ctr0, + r->in.resume_handle, + r->out.totalentries); + break; + case 1: + werr = init_srv_conn_info_1(r->in.info_ctr->ctr.ctr1, + r->in.resume_handle, + r->out.totalentries); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + DEBUG(5,("_srvsvc_NetConnEnum: %d\n", __LINE__)); + + return werr; +} + +/******************************************************************* + _srvsvc_NetSessEnum +********************************************************************/ + +WERROR _srvsvc_NetSessEnum(struct pipes_struct *p, + struct srvsvc_NetSessEnum *r) +{ + WERROR werr; + + DEBUG(5,("_srvsvc_NetSessEnum: %d\n", __LINE__)); + + if (!nt_token_check_sid(&global_sid_Builtin_Administrators, + p->server_info->security_token)) { + DEBUG(1, ("Enumerating sessions only allowed for " + "administrators\n")); + return WERR_ACCESS_DENIED; + } + + switch (r->in.info_ctr->level) { + case 0: + werr = init_srv_sess_info_0(p, + r->in.info_ctr->ctr.ctr0, + r->in.resume_handle, + r->out.totalentries); + break; + case 1: + werr = init_srv_sess_info_1(p, + r->in.info_ctr->ctr.ctr1, + r->in.resume_handle, + r->out.totalentries); + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + DEBUG(5,("_srvsvc_NetSessEnum: %d\n", __LINE__)); + + return werr; +} + +/******************************************************************* + _srvsvc_NetSessDel +********************************************************************/ + +WERROR _srvsvc_NetSessDel(struct pipes_struct *p, + struct srvsvc_NetSessDel *r) +{ + struct sessionid *session_list; + int num_sessions, snum; + const char *username; + const char *machine; + bool not_root = False; + WERROR werr; + + username = r->in.user; + machine = r->in.client; + + /* strip leading backslashes if any */ + if (machine && machine[0] == '\\' && machine[1] == '\\') { + machine += 2; + } + + num_sessions = list_sessions(p->mem_ctx, &session_list); + + DEBUG(5,("_srvsvc_NetSessDel: %d\n", __LINE__)); + + werr = WERR_ACCESS_DENIED; + + /* fail out now if you are not root or not a domain admin */ + + if ((p->server_info->utok.uid != sec_initial_uid()) && + ( ! nt_token_check_domain_rid(p->server_info->security_token, + DOMAIN_RID_ADMINS))) { + + goto done; + } + + for (snum = 0; snum < num_sessions; snum++) { + + if ((strequal(session_list[snum].username, username) || username[0] == '\0' ) && + strequal(session_list[snum].remote_machine, machine)) { + + NTSTATUS ntstat; + + if (p->server_info->utok.uid != sec_initial_uid()) { + not_root = True; + become_root(); + } + + ntstat = messaging_send(p->msg_ctx, + session_list[snum].pid, + MSG_SHUTDOWN, &data_blob_null); + + if (NT_STATUS_IS_OK(ntstat)) + werr = WERR_OK; + + if (not_root) + unbecome_root(); + } + } + + DEBUG(5,("_srvsvc_NetSessDel: %d\n", __LINE__)); + +done: + + return werr; +} + +/******************************************************************* + _srvsvc_NetShareEnumAll +********************************************************************/ + +WERROR _srvsvc_NetShareEnumAll(struct pipes_struct *p, + struct srvsvc_NetShareEnumAll *r) +{ + WERROR werr; + + DEBUG(5,("_srvsvc_NetShareEnumAll: %d\n", __LINE__)); + + if (!pipe_access_check(p)) { + DEBUG(3, ("access denied to _srvsvc_NetShareEnumAll\n")); + return WERR_ACCESS_DENIED; + } + + /* Create the list of shares for the response. */ + werr = init_srv_share_info_ctr(p, + r->in.info_ctr, + r->in.resume_handle, + r->out.totalentries, + true); + + DEBUG(5,("_srvsvc_NetShareEnumAll: %d\n", __LINE__)); + + return werr; +} + +/******************************************************************* + _srvsvc_NetShareEnum +********************************************************************/ + +WERROR _srvsvc_NetShareEnum(struct pipes_struct *p, + struct srvsvc_NetShareEnum *r) +{ + WERROR werr; + + DEBUG(5,("_srvsvc_NetShareEnum: %d\n", __LINE__)); + + if (!pipe_access_check(p)) { + DEBUG(3, ("access denied to _srvsvc_NetShareEnum\n")); + return WERR_ACCESS_DENIED; + } + + /* Create the list of shares for the response. */ + werr = init_srv_share_info_ctr(p, + r->in.info_ctr, + r->in.resume_handle, + r->out.totalentries, + false); + + DEBUG(5,("_srvsvc_NetShareEnum: %d\n", __LINE__)); + + return werr; +} + +/******************************************************************* + _srvsvc_NetShareGetInfo +********************************************************************/ + +WERROR _srvsvc_NetShareGetInfo(struct pipes_struct *p, + struct srvsvc_NetShareGetInfo *r) +{ + WERROR status = WERR_OK; + char *share_name = NULL; + int snum; + union srvsvc_NetShareInfo *info = r->out.info; + + DEBUG(5,("_srvsvc_NetShareGetInfo: %d\n", __LINE__)); + + if (!r->in.share_name) { + return WERR_INVALID_NAME; + } + + snum = find_service(talloc_tos(), r->in.share_name, &share_name); + if (!share_name) { + return WERR_NOMEM; + } + if (snum < 0) { + return WERR_INVALID_NAME; + } + + switch (r->in.level) { + case 0: + info->info0 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo0); + W_ERROR_HAVE_NO_MEMORY(info->info0); + init_srv_share_info_0(p, info->info0, snum); + break; + case 1: + info->info1 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1); + W_ERROR_HAVE_NO_MEMORY(info->info1); + init_srv_share_info_1(p, info->info1, snum); + break; + case 2: + info->info2 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo2); + W_ERROR_HAVE_NO_MEMORY(info->info2); + init_srv_share_info_2(p, info->info2, snum); + break; + case 501: + info->info501 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo501); + W_ERROR_HAVE_NO_MEMORY(info->info501); + init_srv_share_info_501(p, info->info501, snum); + break; + case 502: + info->info502 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo502); + W_ERROR_HAVE_NO_MEMORY(info->info502); + init_srv_share_info_502(p, info->info502, snum); + break; + case 1004: + info->info1004 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1004); + W_ERROR_HAVE_NO_MEMORY(info->info1004); + init_srv_share_info_1004(p, info->info1004, snum); + break; + case 1005: + info->info1005 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1005); + W_ERROR_HAVE_NO_MEMORY(info->info1005); + init_srv_share_info_1005(p, info->info1005, snum); + break; + case 1006: + info->info1006 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1006); + W_ERROR_HAVE_NO_MEMORY(info->info1006); + init_srv_share_info_1006(p, info->info1006, snum); + break; + case 1007: + info->info1007 = TALLOC_P(p->mem_ctx, struct srvsvc_NetShareInfo1007); + W_ERROR_HAVE_NO_MEMORY(info->info1007); + init_srv_share_info_1007(p, info->info1007, snum); + break; + case 1501: + init_srv_share_info_1501(p, info->info1501, snum); + break; + default: + DEBUG(5,("_srvsvc_NetShareGetInfo: unsupported switch value %d\n", + r->in.level)); + status = WERR_UNKNOWN_LEVEL; + break; + } + + DEBUG(5,("_srvsvc_NetShareGetInfo: %d\n", __LINE__)); + + return status; +} + +/******************************************************************* + Check a given DOS pathname is valid for a share. +********************************************************************/ + +char *valid_share_pathname(TALLOC_CTX *ctx, const char *dos_pathname) +{ + char *ptr = NULL; + + if (!dos_pathname) { + return NULL; + } + + ptr = talloc_strdup(ctx, dos_pathname); + if (!ptr) { + return NULL; + } + /* Convert any '\' paths to '/' */ + unix_format(ptr); + ptr = unix_clean_name(ctx, ptr); + if (!ptr) { + return NULL; + } + + /* NT is braindead - it wants a C: prefix to a pathname ! So strip it. */ + if (strlen(ptr) > 2 && ptr[1] == ':' && ptr[0] != '/') + ptr += 2; + + /* Only absolute paths allowed. */ + if (*ptr != '/') + return NULL; + + return ptr; +} + +/******************************************************************* + _srvsvc_NetShareSetInfo. Modify share details. +********************************************************************/ + +WERROR _srvsvc_NetShareSetInfo(struct pipes_struct *p, + struct srvsvc_NetShareSetInfo *r) +{ + char *command = NULL; + char *share_name = NULL; + char *comment = NULL; + const char *pathname = NULL; + int type; + int snum; + int ret; + char *path = NULL; + struct security_descriptor *psd = NULL; + bool is_disk_op = False; + int max_connections = 0; + TALLOC_CTX *ctx = p->mem_ctx; + union srvsvc_NetShareInfo *info = r->in.info; + + DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__)); + + if (!r->in.share_name) { + return WERR_INVALID_NAME; + } + + if (r->out.parm_error) { + *r->out.parm_error = 0; + } + + if ( strequal(r->in.share_name,"IPC$") + || ( lp_enable_asu_support() && strequal(r->in.share_name,"ADMIN$") ) + || strequal(r->in.share_name,"global") ) + { + DEBUG(5,("_srvsvc_NetShareSetInfo: share %s cannot be " + "modified by a remote user.\n", + r->in.share_name )); + return WERR_ACCESS_DENIED; + } + + snum = find_service(talloc_tos(), r->in.share_name, &share_name); + if (!share_name) { + return WERR_NOMEM; + } + + /* Does this share exist ? */ + if (snum < 0) + return WERR_NET_NAME_NOT_FOUND; + + /* No change to printer shares. */ + if (lp_print_ok(snum)) + return WERR_ACCESS_DENIED; + + is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); + + /* fail out now if you are not root and not a disk op */ + + if ( p->server_info->utok.uid != sec_initial_uid() && !is_disk_op ) { + DEBUG(2,("_srvsvc_NetShareSetInfo: uid %u doesn't have the " + "SeDiskOperatorPrivilege privilege needed to modify " + "share %s\n", + (unsigned int)p->server_info->utok.uid, + share_name )); + return WERR_ACCESS_DENIED; + } + + switch (r->in.level) { + case 1: + pathname = talloc_strdup(ctx, lp_pathname(snum)); + comment = talloc_strdup(ctx, info->info1->comment); + type = info->info1->type; + psd = NULL; + break; + case 2: + comment = talloc_strdup(ctx, info->info2->comment); + pathname = info->info2->path; + type = info->info2->type; + max_connections = (info->info2->max_users == (uint32_t)-1) ? + 0 : info->info2->max_users; + psd = NULL; + break; +#if 0 + /* not supported on set but here for completeness */ + case 501: + comment = talloc_strdup(ctx, info->info501->comment); + type = info->info501->type; + psd = NULL; + break; +#endif + case 502: + comment = talloc_strdup(ctx, info->info502->comment); + pathname = info->info502->path; + type = info->info502->type; + psd = info->info502->sd_buf.sd; + map_generic_share_sd_bits(psd); + break; + case 1004: + pathname = talloc_strdup(ctx, lp_pathname(snum)); + comment = talloc_strdup(ctx, info->info1004->comment); + type = STYPE_DISKTREE; + break; + case 1005: + /* XP re-sets the csc policy even if it wasn't changed by the + user, so we must compare it to see if it's what is set in + smb.conf, so that we can contine other ops like setting + ACLs on a share */ + if (((info->info1005->dfs_flags & + SHARE_1005_CSC_POLICY_MASK) >> + SHARE_1005_CSC_POLICY_SHIFT) == lp_csc_policy(snum)) + return WERR_OK; + else { + DEBUG(3, ("_srvsvc_NetShareSetInfo: client is trying to change csc policy from the network; must be done with smb.conf\n")); + return WERR_ACCESS_DENIED; + } + case 1006: + case 1007: + return WERR_ACCESS_DENIED; + case 1501: + pathname = talloc_strdup(ctx, lp_pathname(snum)); + comment = talloc_strdup(ctx, lp_comment(snum)); + psd = info->info1501->sd; + map_generic_share_sd_bits(psd); + type = STYPE_DISKTREE; + break; + default: + DEBUG(5,("_srvsvc_NetShareSetInfo: unsupported switch value %d\n", + r->in.level)); + return WERR_UNKNOWN_LEVEL; + } + + /* We can only modify disk shares. */ + if (type != STYPE_DISKTREE) { + DEBUG(5,("_srvsvc_NetShareSetInfo: share %s is not a " + "disk share\n", + share_name )); + return WERR_ACCESS_DENIED; + } + + if (comment == NULL) { + return WERR_NOMEM; + } + + /* Check if the pathname is valid. */ + if (!(path = valid_share_pathname(p->mem_ctx, pathname ))) { + DEBUG(5,("_srvsvc_NetShareSetInfo: invalid pathname %s\n", + pathname )); + return WERR_OBJECT_PATH_INVALID; + } + + /* Ensure share name, pathname and comment don't contain '"' characters. */ + string_replace(share_name, '"', ' '); + string_replace(path, '"', ' '); + string_replace(comment, '"', ' '); + + DEBUG(10,("_srvsvc_NetShareSetInfo: change share command = %s\n", + lp_change_share_cmd() ? lp_change_share_cmd() : "NULL" )); + + /* Only call modify function if something changed. */ + + if (strcmp(path, lp_pathname(snum)) || strcmp(comment, lp_comment(snum)) + || (lp_max_connections(snum) != max_connections)) { + if (!lp_change_share_cmd() || !*lp_change_share_cmd()) { + DEBUG(10,("_srvsvc_NetShareSetInfo: No change share command\n")); + return WERR_ACCESS_DENIED; + } + + command = talloc_asprintf(p->mem_ctx, + "%s \"%s\" \"%s\" \"%s\" \"%s\" %d", + lp_change_share_cmd(), + get_dyn_CONFIGFILE(), + share_name, + path, + comment ? comment : "", + max_connections); + if (!command) { + return WERR_NOMEM; + } + + DEBUG(10,("_srvsvc_NetShareSetInfo: Running [%s]\n", command )); + + /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/ + + if (is_disk_op) + become_root(); + + if ( (ret = smbrun(command, NULL)) == 0 ) { + /* Tell everyone we updated smb.conf. */ + message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, + NULL, 0, NULL); + } + + if ( is_disk_op ) + unbecome_root(); + + /********* END SeDiskOperatorPrivilege BLOCK *********/ + + DEBUG(3,("_srvsvc_NetShareSetInfo: Running [%s] returned (%d)\n", + command, ret )); + + TALLOC_FREE(command); + + if ( ret != 0 ) + return WERR_ACCESS_DENIED; + } else { + DEBUG(10,("_srvsvc_NetShareSetInfo: No change to share name (%s)\n", + share_name )); + } + + /* Replace SD if changed. */ + if (psd) { + struct security_descriptor *old_sd; + size_t sd_size; + + old_sd = get_share_security(p->mem_ctx, lp_servicename(snum), &sd_size); + + if (old_sd && !security_descriptor_equal(old_sd, psd)) { + if (!set_share_security(share_name, psd)) + DEBUG(0,("_srvsvc_NetShareSetInfo: Failed to change security info in share %s.\n", + share_name )); + } + } + + DEBUG(5,("_srvsvc_NetShareSetInfo: %d\n", __LINE__)); + + return WERR_OK; +} + +/******************************************************************* + _srvsvc_NetShareAdd. + Call 'add_share_command "sharename" "pathname" + "comment" "max connections = " +********************************************************************/ + +WERROR _srvsvc_NetShareAdd(struct pipes_struct *p, + struct srvsvc_NetShareAdd *r) +{ + char *command = NULL; + char *share_name_in = NULL; + char *share_name = NULL; + char *comment = NULL; + char *pathname = NULL; + int type; + int snum; + int ret; + char *path; + struct security_descriptor *psd = NULL; + bool is_disk_op; + int max_connections = 0; + TALLOC_CTX *ctx = p->mem_ctx; + + DEBUG(5,("_srvsvc_NetShareAdd: %d\n", __LINE__)); + + if (r->out.parm_error) { + *r->out.parm_error = 0; + } + + is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); + + if (p->server_info->utok.uid != sec_initial_uid() && !is_disk_op ) + return WERR_ACCESS_DENIED; + + if (!lp_add_share_cmd() || !*lp_add_share_cmd()) { + DEBUG(10,("_srvsvc_NetShareAdd: No add share command\n")); + return WERR_ACCESS_DENIED; + } + + switch (r->in.level) { + case 0: + /* No path. Not enough info in a level 0 to do anything. */ + return WERR_ACCESS_DENIED; + case 1: + /* Not enough info in a level 1 to do anything. */ + return WERR_ACCESS_DENIED; + case 2: + share_name_in = talloc_strdup(ctx, r->in.info->info2->name); + comment = talloc_strdup(ctx, r->in.info->info2->comment); + pathname = talloc_strdup(ctx, r->in.info->info2->path); + max_connections = (r->in.info->info2->max_users == (uint32_t)-1) ? + 0 : r->in.info->info2->max_users; + type = r->in.info->info2->type; + break; + case 501: + /* No path. Not enough info in a level 501 to do anything. */ + return WERR_ACCESS_DENIED; + case 502: + share_name_in = talloc_strdup(ctx, r->in.info->info502->name); + comment = talloc_strdup(ctx, r->in.info->info502->comment); + pathname = talloc_strdup(ctx, r->in.info->info502->path); + max_connections = (r->in.info->info502->max_users == (uint32_t)-1) ? + 0 : r->in.info->info502->max_users; + type = r->in.info->info502->type; + psd = r->in.info->info502->sd_buf.sd; + map_generic_share_sd_bits(psd); + break; + + /* none of the following contain share names. NetShareAdd does not have a separate parameter for the share name */ + + case 1004: + case 1005: + case 1006: + case 1007: + return WERR_ACCESS_DENIED; + case 1501: + /* DFS only level. */ + return WERR_ACCESS_DENIED; + default: + DEBUG(5,("_srvsvc_NetShareAdd: unsupported switch value %d\n", + r->in.level)); + return WERR_UNKNOWN_LEVEL; + } + + /* check for invalid share names */ + + if (!share_name_in || !validate_net_name(share_name_in, + INVALID_SHARENAME_CHARS, + strlen(share_name_in))) { + DEBUG(5,("_srvsvc_NetShareAdd: Bad sharename \"%s\"\n", + share_name_in ? share_name_in : "")); + return WERR_INVALID_NAME; + } + + if (strequal(share_name_in,"IPC$") || strequal(share_name_in,"global") + || (lp_enable_asu_support() && + strequal(share_name_in,"ADMIN$"))) { + return WERR_ACCESS_DENIED; + } + + snum = find_service(ctx, share_name_in, &share_name); + if (!share_name) { + return WERR_NOMEM; + } + + /* Share already exists. */ + if (snum >= 0) { + return WERR_FILE_EXISTS; + } + + /* We can only add disk shares. */ + if (type != STYPE_DISKTREE) { + return WERR_ACCESS_DENIED; + } + + /* Check if the pathname is valid. */ + if (!(path = valid_share_pathname(p->mem_ctx, pathname))) { + return WERR_OBJECT_PATH_INVALID; + } + + /* Ensure share name, pathname and comment don't contain '"' characters. */ + string_replace(share_name_in, '"', ' '); + string_replace(share_name, '"', ' '); + string_replace(path, '"', ' '); + if (comment) { + string_replace(comment, '"', ' '); + } + + command = talloc_asprintf(ctx, + "%s \"%s\" \"%s\" \"%s\" \"%s\" %d", + lp_add_share_cmd(), + get_dyn_CONFIGFILE(), + share_name_in, + path, + comment ? comment : "", + max_connections); + if (!command) { + return WERR_NOMEM; + } + + DEBUG(10,("_srvsvc_NetShareAdd: Running [%s]\n", command )); + + /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/ + + if ( is_disk_op ) + become_root(); + + /* FIXME: use libnetconf here - gd */ + + if ( (ret = smbrun(command, NULL)) == 0 ) { + /* Tell everyone we updated smb.conf. */ + message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, + NULL); + } + + if ( is_disk_op ) + unbecome_root(); + + /********* END SeDiskOperatorPrivilege BLOCK *********/ + + DEBUG(3,("_srvsvc_NetShareAdd: Running [%s] returned (%d)\n", + command, ret )); + + TALLOC_FREE(command); + + if ( ret != 0 ) + return WERR_ACCESS_DENIED; + + if (psd) { + /* Note we use share_name here, not share_name_in as + we need a canonicalized name for setting security. */ + if (!set_share_security(share_name, psd)) { + DEBUG(0,("_srvsvc_NetShareAdd: Failed to add security info to share %s.\n", + share_name )); + } + } + + /* + * We don't call reload_services() here, the message will + * cause this to be done before the next packet is read + * from the client. JRA. + */ + + DEBUG(5,("_srvsvc_NetShareAdd: %d\n", __LINE__)); + + return WERR_OK; +} + +/******************************************************************* + _srvsvc_NetShareDel + Call "delete share command" with the share name as + a parameter. +********************************************************************/ + +WERROR _srvsvc_NetShareDel(struct pipes_struct *p, + struct srvsvc_NetShareDel *r) +{ + char *command = NULL; + char *share_name = NULL; + int ret; + int snum; + bool is_disk_op; + struct share_params *params; + TALLOC_CTX *ctx = p->mem_ctx; + + DEBUG(5,("_srvsvc_NetShareDel: %d\n", __LINE__)); + + if (!r->in.share_name) { + return WERR_NET_NAME_NOT_FOUND; + } + + if ( strequal(r->in.share_name,"IPC$") + || ( lp_enable_asu_support() && strequal(r->in.share_name,"ADMIN$") ) + || strequal(r->in.share_name,"global") ) + { + return WERR_ACCESS_DENIED; + } + + snum = find_service(talloc_tos(), r->in.share_name, &share_name); + if (!share_name) { + return WERR_NOMEM; + } + + if (snum < 0) { + return WERR_NO_SUCH_SHARE; + } + + if (!(params = get_share_params(p->mem_ctx, share_name))) { + return WERR_NO_SUCH_SHARE; + } + + /* No change to printer shares. */ + if (lp_print_ok(snum)) + return WERR_ACCESS_DENIED; + + is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); + + if (p->server_info->utok.uid != sec_initial_uid() && !is_disk_op ) + return WERR_ACCESS_DENIED; + + if (!lp_delete_share_cmd() || !*lp_delete_share_cmd()) { + DEBUG(10,("_srvsvc_NetShareDel: No delete share command\n")); + return WERR_ACCESS_DENIED; + } + + command = talloc_asprintf(ctx, + "%s \"%s\" \"%s\"", + lp_delete_share_cmd(), + get_dyn_CONFIGFILE(), + lp_servicename(snum)); + if (!command) { + return WERR_NOMEM; + } + + DEBUG(10,("_srvsvc_NetShareDel: Running [%s]\n", command )); + + /********* BEGIN SeDiskOperatorPrivilege BLOCK *********/ + + if ( is_disk_op ) + become_root(); + + if ( (ret = smbrun(command, NULL)) == 0 ) { + /* Tell everyone we updated smb.conf. */ + message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, + NULL); + } + + if ( is_disk_op ) + unbecome_root(); + + /********* END SeDiskOperatorPrivilege BLOCK *********/ + + DEBUG(3,("_srvsvc_NetShareDel: Running [%s] returned (%d)\n", command, ret )); + + if ( ret != 0 ) + return WERR_ACCESS_DENIED; + + /* Delete the SD in the database. */ + delete_share_security(lp_servicename(params->service)); + + lp_killservice(params->service); + + return WERR_OK; +} + +/******************************************************************* + _srvsvc_NetShareDelSticky +********************************************************************/ + +WERROR _srvsvc_NetShareDelSticky(struct pipes_struct *p, + struct srvsvc_NetShareDelSticky *r) +{ + struct srvsvc_NetShareDel q; + + DEBUG(5,("_srvsvc_NetShareDelSticky: %d\n", __LINE__)); + + q.in.server_unc = r->in.server_unc; + q.in.share_name = r->in.share_name; + q.in.reserved = r->in.reserved; + + return _srvsvc_NetShareDel(p, &q); +} + +/******************************************************************* + _srvsvc_NetRemoteTOD +********************************************************************/ + +WERROR _srvsvc_NetRemoteTOD(struct pipes_struct *p, + struct srvsvc_NetRemoteTOD *r) +{ + struct srvsvc_NetRemoteTODInfo *tod; + struct tm *t; + time_t unixdate = time(NULL); + + /* We do this call first as if we do it *after* the gmtime call + it overwrites the pointed-to values. JRA */ + + uint32 zone = get_time_zone(unixdate)/60; + + DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__)); + + if ( !(tod = TALLOC_ZERO_P(p->mem_ctx, struct srvsvc_NetRemoteTODInfo)) ) + return WERR_NOMEM; + + *r->out.info = tod; + + DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__)); + + t = gmtime(&unixdate); + + /* set up the */ + tod->elapsed = unixdate; + tod->msecs = 0; + tod->hours = t->tm_hour; + tod->mins = t->tm_min; + tod->secs = t->tm_sec; + tod->hunds = 0; + tod->timezone = zone; + tod->tinterval = 10000; + tod->day = t->tm_mday; + tod->month = t->tm_mon + 1; + tod->year = 1900+t->tm_year; + tod->weekday = t->tm_wday; + + DEBUG(5,("_srvsvc_NetRemoteTOD: %d\n", __LINE__)); + + return WERR_OK; +} + +/*********************************************************************************** + _srvsvc_NetGetFileSecurity + Win9x NT tools get security descriptor. +***********************************************************************************/ + +WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p, + struct srvsvc_NetGetFileSecurity *r) +{ + struct smb_filename *smb_fname = NULL; + struct security_descriptor *psd = NULL; + size_t sd_size; + char *servicename = NULL; + SMB_STRUCT_STAT st; + NTSTATUS nt_status; + WERROR werr; + connection_struct *conn = NULL; + struct sec_desc_buf *sd_buf = NULL; + files_struct *fsp = NULL; + int snum; + char *oldcwd = NULL; + + ZERO_STRUCT(st); + + if (!r->in.share) { + werr = WERR_NET_NAME_NOT_FOUND; + goto error_exit; + } + snum = find_service(talloc_tos(), r->in.share, &servicename); + if (!servicename) { + werr = WERR_NOMEM; + goto error_exit; + } + if (snum == -1) { + DEBUG(10, ("Could not find service %s\n", servicename)); + werr = WERR_NET_NAME_NOT_FOUND; + goto error_exit; + } + + nt_status = create_conn_struct(talloc_tos(), &conn, snum, + lp_pathname(snum), p->server_info, + &oldcwd); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(10, ("create_conn_struct failed: %s\n", + nt_errstr(nt_status))); + werr = ntstatus_to_werror(nt_status); + goto error_exit; + } + + nt_status = filename_convert(talloc_tos(), + conn, + false, + r->in.file, + 0, + NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(nt_status)) { + werr = ntstatus_to_werror(nt_status); + goto error_exit; + } + + nt_status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + NULL, /* req */ + 0, /* root_dir_fid */ + smb_fname, /* fname */ + FILE_READ_ATTRIBUTES, /* access_mask */ + FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ + FILE_OPEN, /* create_disposition*/ + 0, /* create_options */ + 0, /* file_attributes */ + INTERNAL_OPEN_ONLY, /* oplock_request */ + 0, /* allocation_size */ + 0, /* private_flags */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp, /* result */ + NULL); /* pinfo */ + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(3,("_srvsvc_NetGetFileSecurity: can't open %s\n", + smb_fname_str_dbg(smb_fname))); + werr = ntstatus_to_werror(nt_status); + goto error_exit; + } + + nt_status = SMB_VFS_FGET_NT_ACL(fsp, + (SECINFO_OWNER + |SECINFO_GROUP + |SECINFO_DACL), &psd); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(3,("_srvsvc_NetGetFileSecurity: Unable to get NT ACL " + "for file %s\n", smb_fname_str_dbg(smb_fname))); + werr = ntstatus_to_werror(nt_status); + goto error_exit; + } + + sd_size = ndr_size_security_descriptor(psd, 0); + + sd_buf = TALLOC_ZERO_P(p->mem_ctx, struct sec_desc_buf); + if (!sd_buf) { + werr = WERR_NOMEM; + goto error_exit; + } + + sd_buf->sd_size = sd_size; + sd_buf->sd = psd; + + *r->out.sd_buf = sd_buf; + + psd->dacl->revision = NT4_ACL_REVISION; + + close_file(NULL, fsp, NORMAL_CLOSE); + vfs_ChDir(conn, oldcwd); + conn_free(conn); + werr = WERR_OK; + goto done; + +error_exit: + + if (fsp) { + close_file(NULL, fsp, NORMAL_CLOSE); + } + + if (oldcwd) { + vfs_ChDir(conn, oldcwd); + } + + if (conn) { + conn_free(conn); + } + + done: + TALLOC_FREE(smb_fname); + + return werr; +} + +/*********************************************************************************** + _srvsvc_NetSetFileSecurity + Win9x NT tools set security descriptor. +***********************************************************************************/ + +WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p, + struct srvsvc_NetSetFileSecurity *r) +{ + struct smb_filename *smb_fname = NULL; + char *servicename = NULL; + files_struct *fsp = NULL; + SMB_STRUCT_STAT st; + NTSTATUS nt_status; + WERROR werr; + connection_struct *conn = NULL; + int snum; + char *oldcwd = NULL; + struct security_descriptor *psd = NULL; + uint32_t security_info_sent = 0; + + ZERO_STRUCT(st); + + if (!r->in.share) { + werr = WERR_NET_NAME_NOT_FOUND; + goto error_exit; + } + + snum = find_service(talloc_tos(), r->in.share, &servicename); + if (!servicename) { + werr = WERR_NOMEM; + goto error_exit; + } + + if (snum == -1) { + DEBUG(10, ("Could not find service %s\n", servicename)); + werr = WERR_NET_NAME_NOT_FOUND; + goto error_exit; + } + + nt_status = create_conn_struct(talloc_tos(), &conn, snum, + lp_pathname(snum), p->server_info, + &oldcwd); + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(10, ("create_conn_struct failed: %s\n", + nt_errstr(nt_status))); + werr = ntstatus_to_werror(nt_status); + goto error_exit; + } + + nt_status = filename_convert(talloc_tos(), + conn, + false, + r->in.file, + 0, + NULL, + &smb_fname); + if (!NT_STATUS_IS_OK(nt_status)) { + werr = ntstatus_to_werror(nt_status); + goto error_exit; + } + + nt_status = SMB_VFS_CREATE_FILE( + conn, /* conn */ + NULL, /* req */ + 0, /* root_dir_fid */ + smb_fname, /* fname */ + FILE_WRITE_ATTRIBUTES, /* access_mask */ + FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ + FILE_OPEN, /* create_disposition*/ + 0, /* create_options */ + 0, /* file_attributes */ + INTERNAL_OPEN_ONLY, /* oplock_request */ + 0, /* allocation_size */ + 0, /* private_flags */ + NULL, /* sd */ + NULL, /* ea_list */ + &fsp, /* result */ + NULL); /* pinfo */ + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(3,("_srvsvc_NetSetFileSecurity: can't open %s\n", + smb_fname_str_dbg(smb_fname))); + werr = ntstatus_to_werror(nt_status); + goto error_exit; + } + + psd = r->in.sd_buf->sd; + security_info_sent = r->in.securityinformation; + + if (psd->owner_sid==0) { + security_info_sent &= ~SECINFO_OWNER; + } + if (psd->group_sid==0) { + security_info_sent &= ~SECINFO_GROUP; + } + if (psd->sacl==0) { + security_info_sent &= ~SECINFO_SACL; + } + if (psd->dacl==0) { + security_info_sent &= ~SECINFO_DACL; + } + + /* Convert all the generic bits. */ + security_acl_map_generic(psd->dacl, &file_generic_mapping); + security_acl_map_generic(psd->sacl, &file_generic_mapping); + + nt_status = SMB_VFS_FSET_NT_ACL(fsp, + security_info_sent, + psd); + + if (!NT_STATUS_IS_OK(nt_status) ) { + DEBUG(3,("_srvsvc_NetSetFileSecurity: Unable to set NT ACL " + "on file %s\n", r->in.share)); + werr = WERR_ACCESS_DENIED; + goto error_exit; + } + + close_file(NULL, fsp, NORMAL_CLOSE); + vfs_ChDir(conn, oldcwd); + conn_free(conn); + werr = WERR_OK; + goto done; + +error_exit: + + if (fsp) { + close_file(NULL, fsp, NORMAL_CLOSE); + } + + if (oldcwd) { + vfs_ChDir(conn, oldcwd); + } + + if (conn) { + conn_free(conn); + } + + done: + TALLOC_FREE(smb_fname); + + return werr; +} + +/*********************************************************************************** + It may be that we want to limit users to creating shares on certain areas of the UNIX file area. + We could define areas by mapping Windows style disks to points on the UNIX directory hierarchy. + These disks would the disks listed by this function. + Users could then create shares relative to these disks. Watch out for moving these disks around. + "Nigel Williams" . +***********************************************************************************/ + +static const char *server_disks[] = {"C:"}; + +static uint32 get_server_disk_count(void) +{ + return sizeof(server_disks)/sizeof(server_disks[0]); +} + +static uint32 init_server_disk_enum(uint32 *resume) +{ + uint32 server_disk_count = get_server_disk_count(); + + /*resume can be an offset into the list for now*/ + + if(*resume & 0x80000000) + *resume = 0; + + if(*resume > server_disk_count) + *resume = server_disk_count; + + return server_disk_count - *resume; +} + +static const char *next_server_disk_enum(uint32 *resume) +{ + const char *disk; + + if(init_server_disk_enum(resume) == 0) + return NULL; + + disk = server_disks[*resume]; + + (*resume)++; + + DEBUG(10, ("next_server_disk_enum: reporting disk %s. resume handle %d.\n", disk, *resume)); + + return disk; +} + +/******************************************************************** + _srvsvc_NetDiskEnum +********************************************************************/ + +WERROR _srvsvc_NetDiskEnum(struct pipes_struct *p, + struct srvsvc_NetDiskEnum *r) +{ + uint32 i; + const char *disk_name; + TALLOC_CTX *ctx = p->mem_ctx; + WERROR werr; + uint32_t resume = r->in.resume_handle ? *r->in.resume_handle : 0; + + werr = WERR_OK; + + *r->out.totalentries = init_server_disk_enum(&resume); + + r->out.info->disks = TALLOC_ZERO_ARRAY(ctx, struct srvsvc_NetDiskInfo0, + MAX_SERVER_DISK_ENTRIES); + W_ERROR_HAVE_NO_MEMORY(r->out.info->disks); + + /*allow one struct srvsvc_NetDiskInfo0 for null terminator*/ + + r->out.info->count = 0; + + for(i = 0; i < MAX_SERVER_DISK_ENTRIES -1 && (disk_name = next_server_disk_enum(&resume)); i++) { + + r->out.info->count++; + + /*copy disk name into a unicode string*/ + + r->out.info->disks[i].disk = talloc_strdup(ctx, disk_name); + W_ERROR_HAVE_NO_MEMORY(r->out.info->disks[i].disk); + } + + /* add a terminating null string. Is this there if there is more data to come? */ + + r->out.info->count++; + + r->out.info->disks[i].disk = talloc_strdup(ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->out.info->disks[i].disk); + + if (r->out.resume_handle) { + *r->out.resume_handle = resume; + } + + return werr; +} + +/******************************************************************** + _srvsvc_NetNameValidate +********************************************************************/ + +WERROR _srvsvc_NetNameValidate(struct pipes_struct *p, + struct srvsvc_NetNameValidate *r) +{ + switch (r->in.name_type) { + case 0x9: + if (!validate_net_name(r->in.name, INVALID_SHARENAME_CHARS, + strlen_m(r->in.name))) + { + DEBUG(5,("_srvsvc_NetNameValidate: Bad sharename \"%s\"\n", + r->in.name)); + return WERR_INVALID_NAME; + } + break; + + default: + return WERR_UNKNOWN_LEVEL; + } + + return WERR_OK; +} + +/******************************************************************* +********************************************************************/ + +struct enum_file_close_state { + struct srvsvc_NetFileClose *r; + struct messaging_context *msg_ctx; +}; + +static void enum_file_close_fn( const struct share_mode_entry *e, + const char *sharepath, const char *fname, + void *private_data ) +{ + char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; + struct enum_file_close_state *state = + (struct enum_file_close_state *)private_data; + uint32_t fid = (((uint32_t)(procid_to_pid(&e->pid))<<16) | e->share_file_id); + + if (fid != state->r->in.fid) { + return; /* Not this file. */ + } + + if (!process_exists(e->pid) ) { + return; + } + + /* Ok - send the close message. */ + DEBUG(10,("enum_file_close_fn: request to close file %s, %s\n", + sharepath, + share_mode_str(talloc_tos(), 0, e) )); + + share_mode_entry_to_message(msg, e); + + state->r->out.result = ntstatus_to_werror( + messaging_send_buf(state->msg_ctx, + e->pid, MSG_SMB_CLOSE_FILE, + (uint8 *)msg, + MSG_SMB_SHARE_MODE_ENTRY_SIZE)); +} + +/******************************************************************** + Close a file given a 32-bit file id. +********************************************************************/ + +WERROR _srvsvc_NetFileClose(struct pipes_struct *p, + struct srvsvc_NetFileClose *r) +{ + struct enum_file_close_state state; + bool is_disk_op; + + DEBUG(5,("_srvsvc_NetFileClose: %d\n", __LINE__)); + + is_disk_op = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_DISK_OPERATOR); + + if (p->server_info->utok.uid != sec_initial_uid() && !is_disk_op) { + return WERR_ACCESS_DENIED; + } + + /* enum_file_close_fn sends the close message to + * the relevent smbd process. */ + + r->out.result = WERR_BADFILE; + state.r = r; + state.msg_ctx = p->msg_ctx; + share_mode_forall(enum_file_close_fn, &state); + return r->out.result; +} + +/******************************************************************** +********************************************************************/ + +WERROR _srvsvc_NetCharDevEnum(struct pipes_struct *p, + struct srvsvc_NetCharDevEnum *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetCharDevGetInfo(struct pipes_struct *p, + struct srvsvc_NetCharDevGetInfo *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetCharDevControl(struct pipes_struct *p, + struct srvsvc_NetCharDevControl *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetCharDevQEnum(struct pipes_struct *p, + struct srvsvc_NetCharDevQEnum *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetCharDevQGetInfo(struct pipes_struct *p, + struct srvsvc_NetCharDevQGetInfo *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetCharDevQSetInfo(struct pipes_struct *p, + struct srvsvc_NetCharDevQSetInfo *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetCharDevQPurge(struct pipes_struct *p, + struct srvsvc_NetCharDevQPurge *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetCharDevQPurgeSelf(struct pipes_struct *p, + struct srvsvc_NetCharDevQPurgeSelf *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetFileGetInfo(struct pipes_struct *p, + struct srvsvc_NetFileGetInfo *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetShareCheck(struct pipes_struct *p, + struct srvsvc_NetShareCheck *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetServerStatisticsGet(struct pipes_struct *p, + struct srvsvc_NetServerStatisticsGet *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetTransportAdd(struct pipes_struct *p, + struct srvsvc_NetTransportAdd *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetTransportEnum(struct pipes_struct *p, + struct srvsvc_NetTransportEnum *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetTransportDel(struct pipes_struct *p, + struct srvsvc_NetTransportDel *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetSetServiceBits(struct pipes_struct *p, + struct srvsvc_NetSetServiceBits *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetPathType(struct pipes_struct *p, + struct srvsvc_NetPathType *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetPathCanonicalize(struct pipes_struct *p, + struct srvsvc_NetPathCanonicalize *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetPathCompare(struct pipes_struct *p, + struct srvsvc_NetPathCompare *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRPRNAMECANONICALIZE(struct pipes_struct *p, + struct srvsvc_NETRPRNAMECANONICALIZE *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetPRNameCompare(struct pipes_struct *p, + struct srvsvc_NetPRNameCompare *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetShareDelStart(struct pipes_struct *p, + struct srvsvc_NetShareDelStart *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetShareDelCommit(struct pipes_struct *p, + struct srvsvc_NetShareDelCommit *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetServerTransportAddEx(struct pipes_struct *p, + struct srvsvc_NetServerTransportAddEx *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NetServerSetServiceBitsEx(struct pipes_struct *p, + struct srvsvc_NetServerSetServiceBitsEx *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSGETVERSION(struct pipes_struct *p, + struct srvsvc_NETRDFSGETVERSION *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSCREATELOCALPARTITION(struct pipes_struct *p, + struct srvsvc_NETRDFSCREATELOCALPARTITION *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSDELETELOCALPARTITION(struct pipes_struct *p, + struct srvsvc_NETRDFSDELETELOCALPARTITION *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSSETLOCALVOLUMESTATE(struct pipes_struct *p, + struct srvsvc_NETRDFSSETLOCALVOLUMESTATE *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSSETSERVERINFO(struct pipes_struct *p, + struct srvsvc_NETRDFSSETSERVERINFO *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSCREATEEXITPOINT(struct pipes_struct *p, + struct srvsvc_NETRDFSCREATEEXITPOINT *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSDELETEEXITPOINT(struct pipes_struct *p, + struct srvsvc_NETRDFSDELETEEXITPOINT *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSMODIFYPREFIX(struct pipes_struct *p, + struct srvsvc_NETRDFSMODIFYPREFIX *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSFIXLOCALVOLUME(struct pipes_struct *p, + struct srvsvc_NETRDFSFIXLOCALVOLUME *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRDFSMANAGERREPORTSITEINFO(struct pipes_struct *p, + struct srvsvc_NETRDFSMANAGERREPORTSITEINFO *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _srvsvc_NETRSERVERTRANSPORTDELEX(struct pipes_struct *p, + struct srvsvc_NETRSERVERTRANSPORTDELEX *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} diff --git a/source3/rpc_server/svcctl/srv_svcctl_nt.c b/source3/rpc_server/svcctl/srv_svcctl_nt.c new file mode 100644 index 0000000000..a7af089e7e --- /dev/null +++ b/source3/rpc_server/svcctl/srv_svcctl_nt.c @@ -0,0 +1,1201 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * + * Copyright (C) Marcin Krzysztof Porwit 2005. + * + * Largely Rewritten (Again) by: + * Copyright (C) Gerald (Jerry) Carter 2005. + * Copyright (C) Guenther Deschner 2008,2009. + * + * 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 . + */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_svcctl.h" +#include "../libcli/security/security.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "services/services.h" +#include "services/svc_winreg_glue.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +struct service_control_op { + const char *name; + SERVICE_CONTROL_OPS *ops; +}; + +/* handle external services */ +extern SERVICE_CONTROL_OPS rcinit_svc_ops; + +/* builtin services (see service_db.c and services/svc_*.c */ +extern SERVICE_CONTROL_OPS spoolss_svc_ops; +extern SERVICE_CONTROL_OPS netlogon_svc_ops; +extern SERVICE_CONTROL_OPS winreg_svc_ops; +extern SERVICE_CONTROL_OPS wins_svc_ops; + +/* make sure this number patches the number of builtin + SERVICE_CONTROL_OPS structure listed above */ + +#define SVCCTL_NUM_INTERNAL_SERVICES 4 + +struct service_control_op *svcctl_ops; + +static const struct generic_mapping scm_generic_map = + { SC_MANAGER_READ_ACCESS, SC_MANAGER_WRITE_ACCESS, SC_MANAGER_EXECUTE_ACCESS, SC_MANAGER_ALL_ACCESS }; +static const struct generic_mapping svc_generic_map = + { SERVICE_READ_ACCESS, SERVICE_WRITE_ACCESS, SERVICE_EXECUTE_ACCESS, SERVICE_ALL_ACCESS }; + + +/******************************************************************** +********************************************************************/ + +bool init_service_op_table( void ) +{ + const char **service_list = lp_svcctl_list(); + int num_services = SVCCTL_NUM_INTERNAL_SERVICES + str_list_length( service_list ); + int i; + + if ( !(svcctl_ops = TALLOC_ARRAY( NULL, struct service_control_op, num_services+1)) ) { + DEBUG(0,("init_service_op_table: talloc() failed!\n")); + return False; + } + + /* services listed in smb.conf get the rc.init interface */ + + for ( i=0; service_list && service_list[i]; i++ ) { + svcctl_ops[i].name = talloc_strdup( svcctl_ops, service_list[i] ); + svcctl_ops[i].ops = &rcinit_svc_ops; + } + + /* add builtin services */ + + svcctl_ops[i].name = talloc_strdup( svcctl_ops, "Spooler" ); + svcctl_ops[i].ops = &spoolss_svc_ops; + i++; + + svcctl_ops[i].name = talloc_strdup( svcctl_ops, "NETLOGON" ); + svcctl_ops[i].ops = &netlogon_svc_ops; + i++; + + svcctl_ops[i].name = talloc_strdup( svcctl_ops, "RemoteRegistry" ); + svcctl_ops[i].ops = &winreg_svc_ops; + i++; + + svcctl_ops[i].name = talloc_strdup( svcctl_ops, "WINS" ); + svcctl_ops[i].ops = &wins_svc_ops; + i++; + + /* NULL terminate the array */ + + svcctl_ops[i].name = NULL; + svcctl_ops[i].ops = NULL; + + return True; +} + +bool shutdown_service_op_table(void) +{ + TALLOC_FREE(svcctl_ops); + + return true; +} + +/******************************************************************** +********************************************************************/ + +static struct service_control_op* find_service_by_name( const char *name ) +{ + int i; + + for ( i=0; svcctl_ops[i].name; i++ ) { + if ( strequal( name, svcctl_ops[i].name ) ) + return &svcctl_ops[i]; + } + + return NULL; +} +/******************************************************************** +********************************************************************/ + +static NTSTATUS svcctl_access_check( struct security_descriptor *sec_desc, struct security_token *token, + uint32 access_desired, uint32 *access_granted ) +{ + if ( geteuid() == sec_initial_uid() ) { + DEBUG(5,("svcctl_access_check: using root's token\n")); + token = get_root_nt_token(); + } + + return se_access_check( sec_desc, token, access_desired, access_granted); +} + +/******************************************************************** +********************************************************************/ + +static struct security_descriptor* construct_scm_sd( TALLOC_CTX *ctx ) +{ + struct security_ace ace[2]; + size_t i = 0; + struct security_descriptor *sd; + struct security_acl *theacl; + size_t sd_size; + + /* basic access for Everyone */ + + init_sec_ace(&ace[i++], &global_sid_World, + SEC_ACE_TYPE_ACCESS_ALLOWED, SC_MANAGER_READ_ACCESS, 0); + + /* Full Access 'BUILTIN\Administrators' */ + + init_sec_ace(&ace[i++], &global_sid_Builtin_Administrators, + SEC_ACE_TYPE_ACCESS_ALLOWED, SC_MANAGER_ALL_ACCESS, 0); + + + /* create the security descriptor */ + + if ( !(theacl = make_sec_acl(ctx, NT4_ACL_REVISION, i, ace)) ) + return NULL; + + if ( !(sd = make_sec_desc(ctx, SECURITY_DESCRIPTOR_REVISION_1, + SEC_DESC_SELF_RELATIVE, NULL, NULL, NULL, + theacl, &sd_size)) ) + return NULL; + + return sd; +} + +/****************************************************************** + Find a registry key handle and return a SERVICE_INFO + *****************************************************************/ + +static SERVICE_INFO *find_service_info_by_hnd(struct pipes_struct *p, + struct policy_handle *hnd) +{ + SERVICE_INFO *service_info = NULL; + + if( !find_policy_by_hnd( p, hnd, (void **)(void *)&service_info) ) { + DEBUG(2,("find_service_info_by_hnd: handle not found\n")); + return NULL; + } + + return service_info; +} + +/****************************************************************** + *****************************************************************/ + +static WERROR create_open_service_handle(struct pipes_struct *p, + struct policy_handle *handle, + uint32_t type, + const char *service, + uint32_t access_granted) +{ + SERVICE_INFO *info = NULL; + WERROR result = WERR_OK; + struct service_control_op *s_op; + + if ( !(info = TALLOC_ZERO_P( NULL, SERVICE_INFO )) ) + return WERR_NOMEM; + + /* the Service Manager has a NULL name */ + + info->type = SVC_HANDLE_IS_SCM; + + switch ( type ) { + case SVC_HANDLE_IS_SCM: + info->type = SVC_HANDLE_IS_SCM; + break; + + case SVC_HANDLE_IS_DBLOCK: + info->type = SVC_HANDLE_IS_DBLOCK; + break; + + case SVC_HANDLE_IS_SERVICE: + info->type = SVC_HANDLE_IS_SERVICE; + + /* lookup the SERVICE_CONTROL_OPS */ + + if ( !(s_op = find_service_by_name( service )) ) { + result = WERR_NO_SUCH_SERVICE; + goto done; + } + + info->ops = s_op->ops; + + if ( !(info->name = talloc_strdup( info, s_op->name )) ) { + result = WERR_NOMEM; + goto done; + } + break; + + default: + result = WERR_NO_SUCH_SERVICE; + goto done; + } + + info->access_granted = access_granted; + + /* store the SERVICE_INFO and create an open handle */ + + if ( !create_policy_hnd( p, handle, info ) ) { + result = WERR_ACCESS_DENIED; + goto done; + } + +done: + if ( !W_ERROR_IS_OK(result) ) + TALLOC_FREE(info); + + return result; +} + +/******************************************************************** + _svcctl_OpenSCManagerW +********************************************************************/ + +WERROR _svcctl_OpenSCManagerW(struct pipes_struct *p, + struct svcctl_OpenSCManagerW *r) +{ + struct security_descriptor *sec_desc; + uint32 access_granted = 0; + NTSTATUS status; + + /* perform access checks */ + + if ( !(sec_desc = construct_scm_sd( p->mem_ctx )) ) + return WERR_NOMEM; + + se_map_generic( &r->in.access_mask, &scm_generic_map ); + status = svcctl_access_check( sec_desc, p->server_info->security_token, + r->in.access_mask, &access_granted ); + if ( !NT_STATUS_IS_OK(status) ) + return ntstatus_to_werror( status ); + + return create_open_service_handle( p, r->out.handle, SVC_HANDLE_IS_SCM, NULL, access_granted ); +} + +/******************************************************************** + _svcctl_OpenServiceW +********************************************************************/ + +WERROR _svcctl_OpenServiceW(struct pipes_struct *p, + struct svcctl_OpenServiceW *r) +{ + struct security_descriptor *sec_desc; + uint32 access_granted = 0; + NTSTATUS status; + const char *service = NULL; + + service = r->in.ServiceName; + if (!service) { + return WERR_NOMEM; + } + DEBUG(5, ("_svcctl_OpenServiceW: Attempting to open Service [%s], \n", service)); + + /* based on my tests you can open a service if you have a valid scm handle */ + + if ( !find_service_info_by_hnd( p, r->in.scmanager_handle) ) + return WERR_BADFID; + + /* + * Perform access checks. Use the system server_info in order to ensure + * that we retrieve the security descriptor + */ + sec_desc = svcctl_get_secdesc(p->mem_ctx, + p->msg_ctx, + get_server_info_system(), + service); + if (sec_desc == NULL) { + DEBUG(0, ("_svcctl_OpenServiceW: Failed to get a valid security " + "descriptor")); + return WERR_NOMEM; + } + + se_map_generic( &r->in.access_mask, &svc_generic_map ); + status = svcctl_access_check( sec_desc, p->server_info->security_token, + r->in.access_mask, &access_granted ); + if ( !NT_STATUS_IS_OK(status) ) + return ntstatus_to_werror( status ); + + return create_open_service_handle( p, r->out.handle, SVC_HANDLE_IS_SERVICE, service, access_granted ); +} + +/******************************************************************** + _svcctl_CloseServiceHandle +********************************************************************/ + +WERROR _svcctl_CloseServiceHandle(struct pipes_struct *p, + struct svcctl_CloseServiceHandle *r) +{ + if ( !close_policy_hnd( p, r->in.handle ) ) + return WERR_BADFID; + + ZERO_STRUCTP(r->out.handle); + + return WERR_OK; +} + +/******************************************************************** + _svcctl_GetServiceDisplayNameW +********************************************************************/ + +WERROR _svcctl_GetServiceDisplayNameW(struct pipes_struct *p, + struct svcctl_GetServiceDisplayNameW *r) +{ + const char *service; + const char *display_name; + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + + /* can only use an SCM handle here */ + + if ( !info || (info->type != SVC_HANDLE_IS_SCM) ) + return WERR_BADFID; + + service = r->in.service_name; + + display_name = svcctl_lookup_dispname(p->mem_ctx, + p->msg_ctx, + p->server_info, + service); + if (!display_name) { + display_name = ""; + } + + *r->out.display_name = display_name; + *r->out.display_name_length = strlen(display_name); + + return WERR_OK; +} + +/******************************************************************** + _svcctl_QueryServiceStatus +********************************************************************/ + +WERROR _svcctl_QueryServiceStatus(struct pipes_struct *p, + struct svcctl_QueryServiceStatus *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) ) + return WERR_ACCESS_DENIED; + + /* try the service specific status call */ + + return info->ops->service_status( info->name, r->out.service_status ); +} + +/******************************************************************** +********************************************************************/ + +static int enumerate_status(TALLOC_CTX *ctx, + struct messaging_context *msg_ctx, + struct auth_serversupplied_info *server_info, + struct ENUM_SERVICE_STATUSW **status) +{ + int num_services = 0; + int i; + struct ENUM_SERVICE_STATUSW *st; + const char *display_name; + + /* just count */ + while ( svcctl_ops[num_services].name ) + num_services++; + + if ( !(st = TALLOC_ARRAY( ctx, struct ENUM_SERVICE_STATUSW, num_services )) ) { + DEBUG(0,("enumerate_status: talloc() failed!\n")); + return -1; + } + + for ( i=0; iservice_status( svcctl_ops[i].name, &st[i].status ); + } + + *status = st; + + return num_services; +} + +/******************************************************************** + _svcctl_EnumServicesStatusW +********************************************************************/ + +WERROR _svcctl_EnumServicesStatusW(struct pipes_struct *p, + struct svcctl_EnumServicesStatusW *r) +{ + struct ENUM_SERVICE_STATUSW *services = NULL; + int num_services; + int i = 0; + size_t buffer_size = 0; + WERROR result = WERR_OK; + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + DATA_BLOB blob = data_blob_null; + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SCM) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_MGR_ENUMERATE_SERVICE) ) { + return WERR_ACCESS_DENIED; + } + + num_services = enumerate_status(p->mem_ctx, + p->msg_ctx, + p->server_info, + &services); + if (num_services == -1 ) { + return WERR_NOMEM; + } + + for ( i=0; i r->in.offered) { + num_services = 0; + result = WERR_MORE_DATA; + } + + if ( W_ERROR_IS_OK(result) ) { + + enum ndr_err_code ndr_err; + struct ndr_push *ndr; + + ndr = ndr_push_init_ctx(p->mem_ctx); + if (ndr == NULL) { + return WERR_INVALID_PARAM; + } + + ndr_err = ndr_push_ENUM_SERVICE_STATUSW_array( + ndr, num_services, services); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ntstatus_to_werror(ndr_map_error2ntstatus(ndr_err)); + } + blob = ndr_push_blob(ndr); + memcpy(r->out.service, blob.data, MIN(blob.length, r->in.offered)); + } + + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; + *r->out.services_returned = (uint32)num_services; + if (r->out.resume_handle) { + *r->out.resume_handle = 0; + } + + return result; +} + +/******************************************************************** + _svcctl_StartServiceW +********************************************************************/ + +WERROR _svcctl_StartServiceW(struct pipes_struct *p, + struct svcctl_StartServiceW *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_SVC_START) ) + return WERR_ACCESS_DENIED; + + return info->ops->start_service( info->name ); +} + +/******************************************************************** + _svcctl_ControlService +********************************************************************/ + +WERROR _svcctl_ControlService(struct pipes_struct *p, + struct svcctl_ControlService *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) + return WERR_BADFID; + + switch ( r->in.control ) { + case SVCCTL_CONTROL_STOP: + if ( !(info->access_granted & SC_RIGHT_SVC_STOP) ) + return WERR_ACCESS_DENIED; + + return info->ops->stop_service( info->name, + r->out.service_status ); + + case SVCCTL_CONTROL_INTERROGATE: + if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) ) + return WERR_ACCESS_DENIED; + + return info->ops->service_status( info->name, + r->out.service_status ); + default: + return WERR_INVALID_PARAM; + } +} + +/******************************************************************** + _svcctl_EnumDependentServicesW +********************************************************************/ + +WERROR _svcctl_EnumDependentServicesW(struct pipes_struct *p, + struct svcctl_EnumDependentServicesW *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.service ); + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) ) + return WERR_ACCESS_DENIED; + + switch (r->in.state) { + case SERVICE_STATE_ACTIVE: + case SERVICE_STATE_INACTIVE: + case SERVICE_STATE_ALL: + break; + default: + return WERR_INVALID_PARAM; + } + + /* we have to set the outgoing buffer size to the same as the + incoming buffer size (even in the case of failure */ + /* this is done in the autogenerated server already - gd */ + + *r->out.needed = r->in.offered; + + /* no dependent services...basically a stub function */ + *r->out.services_returned = 0; + + return WERR_OK; +} + +/******************************************************************** + _svcctl_QueryServiceStatusEx +********************************************************************/ + +WERROR _svcctl_QueryServiceStatusEx(struct pipes_struct *p, + struct svcctl_QueryServiceStatusEx *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + uint32 buffer_size; + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_STATUS) ) + return WERR_ACCESS_DENIED; + + /* we have to set the outgoing buffer size to the same as the + incoming buffer size (even in the case of failure) */ + *r->out.needed = r->in.offered; + + switch ( r->in.info_level ) { + case SVC_STATUS_PROCESS_INFO: + { + struct SERVICE_STATUS_PROCESS svc_stat_proc; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + /* Get the status of the service.. */ + info->ops->service_status( info->name, &svc_stat_proc.status ); + svc_stat_proc.process_id = sys_getpid(); + svc_stat_proc.service_flags = 0x0; + + ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &svc_stat_proc, + (ndr_push_flags_fn_t)ndr_push_SERVICE_STATUS_PROCESS); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_INVALID_PARAM; + } + + r->out.buffer = blob.data; + buffer_size = sizeof(struct SERVICE_STATUS_PROCESS); + break; + } + + default: + return WERR_UNKNOWN_LEVEL; + } + + + buffer_size += buffer_size % 4; + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; + + if (buffer_size > r->in.offered ) { + return WERR_INSUFFICIENT_BUFFER; + } + + return WERR_OK; +} + +/******************************************************************** +********************************************************************/ + +static WERROR fill_svc_config(TALLOC_CTX *ctx, + struct messaging_context *msg_ctx, + struct auth_serversupplied_info *server_info, + const char *name, + struct QUERY_SERVICE_CONFIG *config) +{ + TALLOC_CTX *mem_ctx = talloc_stackframe(); + const char *result = NULL; + + /* now fill in the individual values */ + + config->displayname = svcctl_lookup_dispname(mem_ctx, + msg_ctx, + server_info, + name); + + result = svcctl_get_string_value(mem_ctx, + msg_ctx, + server_info, + name, + "ObjectName"); + if (result != NULL) { + config->startname = result; + } + + result = svcctl_get_string_value(mem_ctx, + msg_ctx, + server_info, + name, + "ImagePath"); + if (result != NULL) { + config->executablepath = result; + } + + /* a few hard coded values */ + /* loadordergroup and dependencies are empty */ + + config->tag_id = 0x00000000; /* unassigned loadorder group */ + config->service_type = SERVICE_TYPE_WIN32_OWN_PROCESS; + config->error_control = SVCCTL_SVC_ERROR_NORMAL; + + /* set the start type. NetLogon and WINS are disabled to prevent + the client from showing the "Start" button (if of course the services + are not running */ + + if ( strequal( name, "NETLOGON" ) && ( lp_servicenumber(name) == -1 ) ) + config->start_type = SVCCTL_DISABLED; + else if ( strequal( name, "WINS" ) && ( !lp_wins_support() )) + config->start_type = SVCCTL_DISABLED; + else + config->start_type = SVCCTL_DEMAND_START; + + + talloc_free(mem_ctx); + + return WERR_OK; +} + +/******************************************************************** + _svcctl_QueryServiceConfigW +********************************************************************/ + +WERROR _svcctl_QueryServiceConfigW(struct pipes_struct *p, + struct svcctl_QueryServiceConfigW *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + uint32 buffer_size; + WERROR wresult; + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) ) + return WERR_ACCESS_DENIED; + + /* we have to set the outgoing buffer size to the same as the + incoming buffer size (even in the case of failure */ + + *r->out.needed = r->in.offered; + + wresult = fill_svc_config(p->mem_ctx, + p->msg_ctx, + p->server_info, + info->name, + r->out.query); + if ( !W_ERROR_IS_OK(wresult) ) + return wresult; + + buffer_size = ndr_size_QUERY_SERVICE_CONFIG(r->out.query, 0); + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; + + if (buffer_size > r->in.offered ) { + ZERO_STRUCTP(r->out.query); + return WERR_INSUFFICIENT_BUFFER; + } + + return WERR_OK; +} + +/******************************************************************** + _svcctl_QueryServiceConfig2W +********************************************************************/ + +WERROR _svcctl_QueryServiceConfig2W(struct pipes_struct *p, + struct svcctl_QueryServiceConfig2W *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + uint32 buffer_size; + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SERVICE) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_SVC_QUERY_CONFIG) ) + return WERR_ACCESS_DENIED; + + /* we have to set the outgoing buffer size to the same as the + incoming buffer size (even in the case of failure */ + *r->out.needed = r->in.offered; + + switch ( r->in.info_level ) { + case SERVICE_CONFIG_DESCRIPTION: + { + struct SERVICE_DESCRIPTION desc_buf; + const char *description; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + description = svcctl_lookup_description(p->mem_ctx, + p->msg_ctx, + p->server_info, + info->name); + + desc_buf.description = description; + + ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &desc_buf, + (ndr_push_flags_fn_t)ndr_push_SERVICE_DESCRIPTION); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_INVALID_PARAM; + } + + buffer_size = ndr_size_SERVICE_DESCRIPTION(&desc_buf, 0); + r->out.buffer = blob.data; + + break; + } + break; + case SERVICE_CONFIG_FAILURE_ACTIONS: + { + struct SERVICE_FAILURE_ACTIONS actions; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + /* nothing to say...just service the request */ + + ZERO_STRUCT( actions ); + + ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, &actions, + (ndr_push_flags_fn_t)ndr_push_SERVICE_FAILURE_ACTIONS); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return WERR_INVALID_PARAM; + } + + buffer_size = ndr_size_SERVICE_FAILURE_ACTIONS(&actions, 0); + r->out.buffer = blob.data; + + break; + } + break; + + default: + return WERR_UNKNOWN_LEVEL; + } + + buffer_size += buffer_size % 4; + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; + + if (buffer_size > r->in.offered) + return WERR_INSUFFICIENT_BUFFER; + + return WERR_OK; +} + +/******************************************************************** + _svcctl_LockServiceDatabase +********************************************************************/ + +WERROR _svcctl_LockServiceDatabase(struct pipes_struct *p, + struct svcctl_LockServiceDatabase *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + + /* perform access checks */ + + if ( !info || (info->type != SVC_HANDLE_IS_SCM) ) + return WERR_BADFID; + + if ( !(info->access_granted & SC_RIGHT_MGR_LOCK) ) + return WERR_ACCESS_DENIED; + + /* Just open a handle. Doesn't actually lock anything */ + + return create_open_service_handle( p, r->out.lock, SVC_HANDLE_IS_DBLOCK, NULL, 0 ); +} + +/******************************************************************** + _svcctl_UnlockServiceDatabase +********************************************************************/ + +WERROR _svcctl_UnlockServiceDatabase(struct pipes_struct *p, + struct svcctl_UnlockServiceDatabase *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.lock ); + + + if ( !info || (info->type != SVC_HANDLE_IS_DBLOCK) ) + return WERR_BADFID; + + return close_policy_hnd( p, r->out.lock) ? WERR_OK : WERR_BADFID; +} + +/******************************************************************** + _svcctl_QueryServiceObjectSecurity +********************************************************************/ + +WERROR _svcctl_QueryServiceObjectSecurity(struct pipes_struct *p, + struct svcctl_QueryServiceObjectSecurity *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + struct security_descriptor *sec_desc; + NTSTATUS status; + uint8_t *buffer = NULL; + size_t len = 0; + + + /* only support the SCM and individual services */ + + if ( !info || !(info->type & (SVC_HANDLE_IS_SERVICE|SVC_HANDLE_IS_SCM)) ) + return WERR_BADFID; + + /* check access reights (according to MSDN) */ + + if ( !(info->access_granted & SEC_STD_READ_CONTROL) ) + return WERR_ACCESS_DENIED; + + /* TODO: handle something besides SECINFO_DACL */ + + if ( (r->in.security_flags & SECINFO_DACL) != SECINFO_DACL ) + return WERR_INVALID_PARAM; + + /* Lookup the security descriptor and marshall it up for a reply */ + sec_desc = svcctl_get_secdesc(p->mem_ctx, + p->msg_ctx, + get_server_info_system(), + info->name); + if (sec_desc == NULL) { + return WERR_NOMEM; + } + + *r->out.needed = ndr_size_security_descriptor(sec_desc, 0); + + if ( *r->out.needed > r->in.offered) { + return WERR_INSUFFICIENT_BUFFER; + } + + status = marshall_sec_desc(p->mem_ctx, sec_desc, &buffer, &len); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + *r->out.needed = len; + r->out.buffer = buffer; + + return WERR_OK; +} + +/******************************************************************** + _svcctl_SetServiceObjectSecurity +********************************************************************/ + +WERROR _svcctl_SetServiceObjectSecurity(struct pipes_struct *p, + struct svcctl_SetServiceObjectSecurity *r) +{ + SERVICE_INFO *info = find_service_info_by_hnd( p, r->in.handle ); + struct security_descriptor *sec_desc = NULL; + uint32 required_access; + NTSTATUS status; + + if ( !info || !(info->type & (SVC_HANDLE_IS_SERVICE|SVC_HANDLE_IS_SCM)) ) + return WERR_BADFID; + + /* can't set the security de4scriptor on the ServiceControlManager */ + + if ( info->type == SVC_HANDLE_IS_SCM ) + return WERR_ACCESS_DENIED; + + /* check the access on the open handle */ + + switch ( r->in.security_flags ) { + case SECINFO_DACL: + required_access = SEC_STD_WRITE_DAC; + break; + + case SECINFO_OWNER: + case SECINFO_GROUP: + required_access = SEC_STD_WRITE_OWNER; + break; + + case SECINFO_SACL: + return WERR_INVALID_PARAM; + default: + return WERR_INVALID_PARAM; + } + + if ( !(info->access_granted & required_access) ) + return WERR_ACCESS_DENIED; + + /* read the security descfriptor */ + + status = unmarshall_sec_desc(p->mem_ctx, + r->in.buffer, + r->in.offered, + &sec_desc); + if (!NT_STATUS_IS_OK(status)) { + return ntstatus_to_werror(status); + } + + /* store the new SD */ + + if (!svcctl_set_secdesc(p->msg_ctx, p->server_info, info->name, sec_desc)) + return WERR_ACCESS_DENIED; + + return WERR_OK; +} + + +WERROR _svcctl_DeleteService(struct pipes_struct *p, + struct svcctl_DeleteService *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_SetServiceStatus(struct pipes_struct *p, + struct svcctl_SetServiceStatus *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_NotifyBootConfigStatus(struct pipes_struct *p, + struct svcctl_NotifyBootConfigStatus *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_SCSetServiceBitsW(struct pipes_struct *p, + struct svcctl_SCSetServiceBitsW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_ChangeServiceConfigW(struct pipes_struct *p, + struct svcctl_ChangeServiceConfigW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_CreateServiceW(struct pipes_struct *p, + struct svcctl_CreateServiceW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_QueryServiceLockStatusW(struct pipes_struct *p, + struct svcctl_QueryServiceLockStatusW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_GetServiceKeyNameW(struct pipes_struct *p, + struct svcctl_GetServiceKeyNameW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_SCSetServiceBitsA(struct pipes_struct *p, + struct svcctl_SCSetServiceBitsA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_ChangeServiceConfigA(struct pipes_struct *p, + struct svcctl_ChangeServiceConfigA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_CreateServiceA(struct pipes_struct *p, + struct svcctl_CreateServiceA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_EnumDependentServicesA(struct pipes_struct *p, + struct svcctl_EnumDependentServicesA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_EnumServicesStatusA(struct pipes_struct *p, + struct svcctl_EnumServicesStatusA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_OpenSCManagerA(struct pipes_struct *p, + struct svcctl_OpenSCManagerA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_OpenServiceA(struct pipes_struct *p, + struct svcctl_OpenServiceA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_QueryServiceConfigA(struct pipes_struct *p, + struct svcctl_QueryServiceConfigA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_QueryServiceLockStatusA(struct pipes_struct *p, + struct svcctl_QueryServiceLockStatusA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_StartServiceA(struct pipes_struct *p, + struct svcctl_StartServiceA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_GetServiceDisplayNameA(struct pipes_struct *p, + struct svcctl_GetServiceDisplayNameA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_GetServiceKeyNameA(struct pipes_struct *p, + struct svcctl_GetServiceKeyNameA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_GetCurrentGroupeStateW(struct pipes_struct *p, + struct svcctl_GetCurrentGroupeStateW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_EnumServiceGroupW(struct pipes_struct *p, + struct svcctl_EnumServiceGroupW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_ChangeServiceConfig2A(struct pipes_struct *p, + struct svcctl_ChangeServiceConfig2A *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_ChangeServiceConfig2W(struct pipes_struct *p, + struct svcctl_ChangeServiceConfig2W *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_QueryServiceConfig2A(struct pipes_struct *p, + struct svcctl_QueryServiceConfig2A *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _EnumServicesStatusExA(struct pipes_struct *p, + struct EnumServicesStatusExA *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _EnumServicesStatusExW(struct pipes_struct *p, + struct EnumServicesStatusExW *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +WERROR _svcctl_SCSendTSMessage(struct pipes_struct *p, + struct svcctl_SCSendTSMessage *r) +{ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} diff --git a/source3/rpc_server/svcctl/srv_svcctl_reg.c b/source3/rpc_server/svcctl/srv_svcctl_reg.c new file mode 100644 index 0000000000..84c5f434ee --- /dev/null +++ b/source3/rpc_server/svcctl/srv_svcctl_reg.c @@ -0,0 +1,678 @@ +/* + * Unix SMB/CIFS implementation. + * + * SVCCTL RPC server keys initialization + * + * Copyright (c) 2005 Marcin Krzysztof Porwit + * Copyright (c) 2005 Gerald (Jerry) Carter + * Copyright (c) 2011 Andreas Schneider + * + * 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 . + */ + +#include "includes.h" +#include "services/services.h" +#include "services/svc_winreg_glue.h" +#include "../librpc/gen_ndr/ndr_winreg_c.h" +#include "rpc_client/cli_winreg_int.h" +#include "rpc_client/cli_winreg.h" +#include "rpc_server/svcctl/srv_svcctl_reg.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_REGISTRY + +#define TOP_LEVEL_SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services" + +struct rcinit_file_information { + char *description; +}; + +struct service_display_info { + const char *servicename; + const char *daemon; + const char *dispname; + const char *description; +}; + +static struct service_display_info builtin_svcs[] = { + { + "Spooler", + "smbd", + "Print Spooler", + "Internal service for spooling files to print devices" + }, + { + "NETLOGON", + "smbd", + "Net Logon", + "File service providing access to policy and profile data (not" + "remotely manageable)" + }, + { + "RemoteRegistry", + "smbd", + "Remote Registry Service", + "Internal service providing remote access to the Samba registry" + }, + { + "WINS", + "nmbd", + "Windows Internet Name Service (WINS)", + "Internal service providing a NetBIOS point-to-point name server" + "(not remotely manageable)" + }, + { NULL, NULL, NULL, NULL } +}; + +static struct service_display_info common_unix_svcs[] = { + { "cups", NULL, "Common Unix Printing System","Provides unified printing support for all operating systems" }, + { "postfix", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" }, + { "sendmail", NULL, "Internet Mail Service", "Provides support for sending and receiving electonic mail" }, + { "portmap", NULL, "TCP Port to RPC PortMapper",NULL }, + { "xinetd", NULL, "Internet Meta-Daemon", NULL }, + { "inet", NULL, "Internet Meta-Daemon", NULL }, + { "xntpd", NULL, "Network Time Service", NULL }, + { "ntpd", NULL, "Network Time Service", NULL }, + { "lpd", NULL, "BSD Print Spooler", NULL }, + { "nfsserver", NULL, "Network File Service", NULL }, + { "cron", NULL, "Scheduling Service", NULL }, + { "at", NULL, "Scheduling Service", NULL }, + { "nscd", NULL, "Name Service Cache Daemon", NULL }, + { "slapd", NULL, "LDAP Directory Service", NULL }, + { "ldap", NULL, "LDAP DIrectory Service", NULL }, + { "ypbind", NULL, "NIS Directory Service", NULL }, + { "courier-imap", NULL, "IMAP4 Mail Service", NULL }, + { "courier-pop3", NULL, "POP3 Mail Service", NULL }, + { "named", NULL, "Domain Name Service", NULL }, + { "bind", NULL, "Domain Name Service", NULL }, + { "httpd", NULL, "HTTP Server", NULL }, + { "apache", NULL, "HTTP Server", "Provides s highly scalable and flexible web server " + "capable of implementing various protocols incluing " + "but not limited to HTTP" }, + { "autofs", NULL, "Automounter", NULL }, + { "squid", NULL, "Web Cache Proxy ", NULL }, + { "perfcountd", NULL, "Performance Monitoring Daemon", NULL }, + { "pgsql", NULL, "PgSQL Database Server", "Provides service for SQL database from Postgresql.org" }, + { "arpwatch", NULL, "ARP Tables watcher", "Provides service for monitoring ARP tables for changes" }, + { "dhcpd", NULL, "DHCP Server", "Provides service for dynamic host configuration and IP assignment" }, + { "nwserv", NULL, "NetWare Server Emulator", "Provides service for emulating Novell NetWare 3.12 server" }, + { "proftpd", NULL, "Professional FTP Server", "Provides high configurable service for FTP connection and " + "file transferring" }, + { "ssh2", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" }, + { "sshd", NULL, "SSH Secure Shell", "Provides service for secure connection for remote administration" }, + { NULL, NULL, NULL, NULL } +}; + +/******************************************************************** + This is where we do the dirty work of filling in things like the + Display name, Description, etc... +********************************************************************/ +static char *svcctl_get_common_service_dispname(TALLOC_CTX *mem_ctx, + const char *servicename) +{ + uint32_t i; + + for (i = 0; common_unix_svcs[i].servicename; i++) { + if (strequal(servicename, common_unix_svcs[i].servicename)) { + char *dispname; + dispname = talloc_asprintf(mem_ctx, "%s (%s)", + common_unix_svcs[i].dispname, + common_unix_svcs[i].servicename); + if (dispname == NULL) { + return NULL; + } + return dispname; + } + } + + return talloc_strdup(mem_ctx, servicename); +} + +/******************************************************************** +********************************************************************/ +static char *svcctl_cleanup_string(TALLOC_CTX *mem_ctx, + const char *string) +{ + char *clean = NULL; + char *begin, *end; + + clean = talloc_strdup(mem_ctx, string); + if (clean == NULL) { + return NULL; + } + begin = clean; + + /* trim any beginning whilespace */ + while (isspace(*begin)) { + begin++; + } + + if (*begin == '\0') { + return NULL; + } + + /* trim any trailing whitespace or carriage returns. + Start at the end and move backwards */ + + end = begin + strlen(begin) - 1; + + while (isspace(*end) || *end=='\n' || *end=='\r') { + *end = '\0'; + end--; + } + + return begin; +} + +/******************************************************************** +********************************************************************/ +static bool read_init_file(TALLOC_CTX *mem_ctx, + const char *servicename, + struct rcinit_file_information **service_info) +{ + struct rcinit_file_information *info = NULL; + char *filepath = NULL; + char str[1024]; + XFILE *f = NULL; + char *p = NULL; + + info = talloc_zero(mem_ctx, struct rcinit_file_information); + if (info == NULL) { + return false; + } + + /* attempt the file open */ + + filepath = talloc_asprintf(mem_ctx, + "%s/%s/%s", + get_dyn_MODULESDIR(), + SVCCTL_SCRIPT_DIR, + servicename); + if (filepath == NULL) { + return false; + } + f = x_fopen( filepath, O_RDONLY, 0 ); + if (f == NULL) { + DEBUG(0,("read_init_file: failed to open [%s]\n", filepath)); + return false; + } + + while ((x_fgets(str, sizeof(str) - 1, f)) != NULL) { + /* ignore everything that is not a full line + comment starting with a '#' */ + + if (str[0] != '#') { + continue; + } + + /* Look for a line like '^#.*Description:' */ + + p = strstr(str, "Description:"); + if (p != NULL) { + char *desc; + + p += strlen( "Description:" ) + 1; + if (p == NULL) { + break; + } + + desc = svcctl_cleanup_string(mem_ctx, p); + if (desc != NULL) { + info->description = talloc_strdup(info, desc); + } + } + } + + x_fclose(f); + + if (info->description == NULL) { + info->description = talloc_strdup(info, + "External Unix Service"); + if (info->description == NULL) { + return false; + } + } + + *service_info = info; + + return true; +} + +static bool svcctl_add_service(TALLOC_CTX *mem_ctx, + struct dcerpc_binding_handle *h, + struct policy_handle *hive_hnd, + const char *key, + uint32_t access_mask, + const char *name) +{ + enum winreg_CreateAction action = REG_ACTION_NONE; + struct security_descriptor *sd = NULL; + struct policy_handle key_hnd; + struct winreg_String wkey; + struct winreg_String wkeyclass; + char *description = NULL; + char *dname = NULL; + char *ipath = NULL; + bool ok = false; + uint32_t i; + NTSTATUS status; + WERROR result = WERR_OK; + + ZERO_STRUCT(key_hnd); + + ZERO_STRUCT(wkey); + wkey.name = talloc_asprintf(mem_ctx, "%s\\%s", key, name); + if (wkey.name == NULL) { + goto done; + } + + ZERO_STRUCT(wkeyclass); + wkeyclass.name = ""; + + status = dcerpc_winreg_CreateKey(h, + mem_ctx, + hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + /* These values are hardcoded in all QueryServiceConfig() replies. + I'm just storing them here for cosmetic purposes */ + status = dcerpc_winreg_set_dword(mem_ctx, + h, + &key_hnd, + "Start", + SVCCTL_AUTO_START, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_dword(mem_ctx, + h, + &key_hnd, + "Type", + SERVICE_TYPE_WIN32_OWN_PROCESS, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_dword(mem_ctx, + h, + &key_hnd, + "ErrorControl", + SVCCTL_SVC_ERROR_NORMAL, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_sz(mem_ctx, + h, + &key_hnd, + "ObjectName", + "LocalSystem", + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + /* + * Special considerations for internal services and the DisplayName + * value. + */ + for (i = 0; builtin_svcs[i].servicename; i++) { + if (strequal(name, builtin_svcs[i].servicename)) { + ipath = talloc_asprintf(mem_ctx, + "%s/%s/%s", + get_dyn_MODULESDIR(), + SVCCTL_SCRIPT_DIR, + builtin_svcs[i].daemon); + description = talloc_strdup(mem_ctx, builtin_svcs[i].description); + dname = talloc_strdup(mem_ctx, builtin_svcs[i].dispname); + break; + } + } + + if (ipath == NULL || dname == NULL || description == NULL) { + goto done; + } + + /* Default to an external service if we haven't found a match */ + if (builtin_svcs[i].servicename == NULL) { + struct rcinit_file_information *init_info = NULL; + char *dispname = NULL; + + ipath = talloc_asprintf(mem_ctx, + "%s/%s/%s", + get_dyn_MODULESDIR(), + SVCCTL_SCRIPT_DIR, + name); + + /* lookup common unix display names */ + dispname = svcctl_get_common_service_dispname(mem_ctx, name); + dname = talloc_strdup(mem_ctx, dispname ? dispname : ""); + + /* get info from init file itself */ + if (read_init_file(mem_ctx, name, &init_info)) { + description = talloc_strdup(mem_ctx, + init_info->description); + } else { + description = talloc_strdup(mem_ctx, + "External Unix Service"); + } + } + + if (ipath == NULL || dname == NULL || description == NULL) { + goto done; + } + + status = dcerpc_winreg_set_sz(mem_ctx, + h, + &key_hnd, + "DisplayName", + dname, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_sz(mem_ctx, + h, + &key_hnd, + "ImagePath", + ipath, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_sz(mem_ctx, + h, + &key_hnd, + "Description", + description, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + sd = svcctl_gen_service_sd(mem_ctx); + if (sd == NULL) { + DEBUG(0, ("add_new_svc_name: Failed to create default " + "sec_desc!\n")); + goto done; + } + + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result); + } + ZERO_STRUCT(key_hnd); + + ZERO_STRUCT(wkey); + wkey.name = talloc_asprintf(mem_ctx, "%s\\%s\\Security", key, name); + if (wkey.name == NULL) { + result = WERR_NOMEM; + goto done; + } + + ZERO_STRUCT(wkeyclass); + wkeyclass.name = ""; + + status = dcerpc_winreg_CreateKey(h, + mem_ctx, + hive_hnd, + wkey, + wkeyclass, + 0, + access_mask, + NULL, + &key_hnd, + &action, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("eventlog_init_winreg_keys: Could not create key %s: %s\n", + wkey.name, win_errstr(result))); + goto done; + } + + status = dcerpc_winreg_set_sd(mem_ctx, + h, + &key_hnd, + "Security", + sd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg_keys: Could not create value: %s\n", + win_errstr(result))); + goto done; + } + + ok = true; +done: + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, mem_ctx, &key_hnd, &result); + } + + return ok; +} + +bool svcctl_init_winreg(struct messaging_context *msg_ctx) +{ + struct dcerpc_binding_handle *h = NULL; + uint32_t access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + struct policy_handle hive_hnd, key_hnd; + const char **service_list = lp_svcctl_list(); + const char **subkeys = NULL; + uint32_t num_subkeys = 0; + char *key = NULL; + uint32_t i; + NTSTATUS status; + WERROR result = WERR_OK; + bool ok = false; + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + return false; + } + + DEBUG(3, ("Initialise the svcctl registry keys if needed.\n")); + + ZERO_STRUCT(hive_hnd); + ZERO_STRUCT(key_hnd); + + key = talloc_strdup(tmp_ctx, TOP_LEVEL_SERVICES_KEY); + if (key == NULL) { + goto done; + } + + status = dcerpc_winreg_int_hklm_openkey(tmp_ctx, + get_server_info_system(), + msg_ctx, + &h, + key, + false, + access_mask, + &hive_hnd, + &key_hnd, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n", + key, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg: Could not open %s - %s\n", + key, win_errstr(result))); + goto done; + } + + /* get all subkeys */ + status = dcerpc_winreg_enum_keys(tmp_ctx, + h, + &key_hnd, + &num_subkeys, + &subkeys, + &result); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n", + key, nt_errstr(status))); + goto done; + } + if (!W_ERROR_IS_OK(result)) { + DEBUG(0, ("svcctl_init_winreg: Could enum keys at %s - %s\n", + key, win_errstr(result))); + goto done; + } + + for (i = 0; builtin_svcs[i].servicename != NULL; i++) { + uint32_t j; + bool skip = false; + + for (j = 0; j < num_subkeys; j++) { + if (strequal(subkeys[i], builtin_svcs[i].servicename)) { + skip = true; + } + } + + if (skip) { + continue; + } + + ok = svcctl_add_service(tmp_ctx, + h, + &hive_hnd, + key, + access_mask, + builtin_svcs[i].servicename); + if (!ok) { + goto done; + } + } + + for (i = 0; service_list && service_list[i]; i++) { + uint32_t j; + bool skip = false; + + for (j = 0; j < num_subkeys; j++) { + if (strequal(subkeys[i], service_list[i])) { + skip = true; + } + } + + if (skip) { + continue; + } + + ok = svcctl_add_service(tmp_ctx, + h, + &hive_hnd, + key, + access_mask, + service_list[i]); + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + ZERO_STRUCT(key_hnd); + + if (!ok) { + goto done; + } + } + +done: + if (is_valid_policy_hnd(&key_hnd)) { + dcerpc_winreg_CloseKey(h, tmp_ctx, &key_hnd, &result); + } + + return ok; +} + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/svcctl/srv_svcctl_reg.h b/source3/rpc_server/svcctl/srv_svcctl_reg.h new file mode 100644 index 0000000000..ab12a03b7b --- /dev/null +++ b/source3/rpc_server/svcctl/srv_svcctl_reg.h @@ -0,0 +1,29 @@ +/* + * Unix SMB/CIFS implementation. + * + * SVCCTL RPC server keys initialization + * + * Copyright (c) 2011 Andreas Schneider + * + * 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 . + */ + +#ifndef SRV_SERVICES_REG_H +#define SRV_SERVICES_REG_H + +bool svcctl_init_winreg(struct messaging_context *msg_ctx); + +#endif /* SRV_SERVICES_REG_H */ + +/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */ diff --git a/source3/rpc_server/winreg/srv_winreg_nt.c b/source3/rpc_server/winreg/srv_winreg_nt.c new file mode 100644 index 0000000000..379fe57c38 --- /dev/null +++ b/source3/rpc_server/winreg/srv_winreg_nt.c @@ -0,0 +1,1142 @@ +/* + * Unix SMB/CIFS implementation. + * RPC Pipe client / server routines + * + * Copyright (C) Gerald Carter 2002-2006. + * + * 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 . + */ + +/* Implementation of registry functions. */ + +#include "includes.h" +#include "../librpc/gen_ndr/srv_winreg.h" +#include "registry/reg_parse_prs.h" +#include "registry.h" +#include "registry/reg_api.h" +#include "registry/reg_api_regf.h" +#include "registry/reg_perfcount.h" +#include "rpc_misc.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +/****************************************************************** + Find a registry key handle and return a struct registry_key * + *****************************************************************/ + +static struct registry_key *find_regkey_by_hnd(struct pipes_struct *p, + struct policy_handle *hnd) +{ + struct registry_key *regkey = NULL; + + if(!find_policy_by_hnd(p,hnd,(void **)(void *)®key)) { + DEBUG(2,("find_regkey_index_by_hnd: Registry Key not found: ")); + return NULL; + } + + return regkey; +} + +/******************************************************************* + Function for open a new registry handle and creating a handle + Note that P should be valid & hnd should already have space + + When we open a key, we store the full path to the key as + HK[LM|U]\\\... + *******************************************************************/ + +static WERROR open_registry_key(struct pipes_struct *p, + struct policy_handle *hnd, + struct registry_key *parent, + const char *subkeyname, + uint32_t access_desired) +{ + WERROR result = WERR_OK; + struct registry_key *key; + + if (parent == NULL) { + result = reg_openhive(p->mem_ctx, subkeyname, access_desired, + p->server_info->security_token, &key); + } + else { + result = reg_openkey(p->mem_ctx, parent, subkeyname, + access_desired, &key); + } + + if ( !W_ERROR_IS_OK(result) ) { + return result; + } + + if ( !create_policy_hnd( p, hnd, key ) ) { + return WERR_BADFILE; + } + + return WERR_OK; +} + +/******************************************************************* + Function for open a new registry handle and creating a handle + Note that P should be valid & hnd should already have space + *******************************************************************/ + +static bool close_registry_key(struct pipes_struct *p, + struct policy_handle *hnd) +{ + struct registry_key *regkey = find_regkey_by_hnd(p, hnd); + + if ( !regkey ) { + DEBUG(2,("close_registry_key: Invalid handle (%s:%u:%u)\n", + OUR_HANDLE(hnd))); + return False; + } + + close_policy_hnd(p, hnd); + + return True; +} + +/******************************************************************** + _winreg_CloseKey + ********************************************************************/ + +WERROR _winreg_CloseKey(struct pipes_struct *p, + struct winreg_CloseKey *r) +{ + /* close the policy handle */ + + if (!close_registry_key(p, r->in.handle)) + return WERR_BADFID; + + ZERO_STRUCTP(r->out.handle); + + return WERR_OK; +} + +/******************************************************************* + _winreg_OpenHKLM + ********************************************************************/ + +WERROR _winreg_OpenHKLM(struct pipes_struct *p, + struct winreg_OpenHKLM *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKLM, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKPD + ********************************************************************/ + +WERROR _winreg_OpenHKPD(struct pipes_struct *p, + struct winreg_OpenHKPD *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKPD, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKPT + ********************************************************************/ + +WERROR _winreg_OpenHKPT(struct pipes_struct *p, + struct winreg_OpenHKPT *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKPT, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKCR + ********************************************************************/ + +WERROR _winreg_OpenHKCR(struct pipes_struct *p, + struct winreg_OpenHKCR *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKCR, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKU + ********************************************************************/ + +WERROR _winreg_OpenHKU(struct pipes_struct *p, + struct winreg_OpenHKU *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKU, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKCU + ********************************************************************/ + +WERROR _winreg_OpenHKCU(struct pipes_struct *p, + struct winreg_OpenHKCU *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKCU, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKCC + ********************************************************************/ + +WERROR _winreg_OpenHKCC(struct pipes_struct *p, + struct winreg_OpenHKCC *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKCC, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKDD + ********************************************************************/ + +WERROR _winreg_OpenHKDD(struct pipes_struct *p, + struct winreg_OpenHKDD *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKDD, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenHKPN + ********************************************************************/ + +WERROR _winreg_OpenHKPN(struct pipes_struct *p, + struct winreg_OpenHKPN *r) +{ + return open_registry_key(p, r->out.handle, NULL, KEY_HKPN, r->in.access_mask); +} + +/******************************************************************* + _winreg_OpenKey + ********************************************************************/ + +WERROR _winreg_OpenKey(struct pipes_struct *p, + struct winreg_OpenKey *r) +{ + struct registry_key *parent = find_regkey_by_hnd(p, r->in.parent_handle ); + + if ( !parent ) + return WERR_BADFID; + + return open_registry_key(p, r->out.handle, parent, r->in.keyname.name, r->in.access_mask); +} + +/******************************************************************* + _winreg_QueryValue + ********************************************************************/ + +WERROR _winreg_QueryValue(struct pipes_struct *p, + struct winreg_QueryValue *r) +{ + WERROR status = WERR_BADFILE; + struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); + prs_struct prs_hkpd; + + uint8_t *outbuf = NULL; + uint32_t outbuf_size = 0; + + bool free_buf = False; + bool free_prs = False; + + if ( !regkey ) + return WERR_BADFID; + + if (r->in.value_name->name == NULL) { + return WERR_INVALID_PARAM; + } + + if ((r->out.data_length == NULL) || (r->out.type == NULL) || (r->out.data_size == NULL)) { + return WERR_INVALID_PARAM; + } + + DEBUG(7,("_winreg_QueryValue: policy key name = [%s]\n", regkey->key->name)); + DEBUG(7,("_winreg_QueryValue: policy key type = [%08x]\n", regkey->key->type)); + + /* Handle QueryValue calls on HKEY_PERFORMANCE_DATA */ + if(regkey->key->type == REG_KEY_HKPD) + { + if (strequal(r->in.value_name->name, "Global")) { + if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL)) + return WERR_NOMEM; + status = reg_perfcount_get_hkpd( + &prs_hkpd, *r->in.data_size, &outbuf_size, NULL); + outbuf = (uint8_t *)prs_hkpd.data_p; + free_prs = True; + } + else if (strequal(r->in.value_name->name, "Counter 009")) { + outbuf_size = reg_perfcount_get_counter_names( + reg_perfcount_get_base_index(), + (char **)(void *)&outbuf); + free_buf = True; + } + else if (strequal(r->in.value_name->name, "Explain 009")) { + outbuf_size = reg_perfcount_get_counter_help( + reg_perfcount_get_base_index(), + (char **)(void *)&outbuf); + free_buf = True; + } + else if (isdigit(r->in.value_name->name[0])) { + /* we probably have a request for a specific object + * here */ + if (!prs_init(&prs_hkpd, *r->in.data_size, p->mem_ctx, MARSHALL)) + return WERR_NOMEM; + status = reg_perfcount_get_hkpd( + &prs_hkpd, *r->in.data_size, &outbuf_size, + r->in.value_name->name); + outbuf = (uint8_t *)prs_hkpd.data_p; + free_prs = True; + } + else { + DEBUG(3,("Unsupported key name [%s] for HKPD.\n", + r->in.value_name->name)); + return WERR_BADFILE; + } + + *r->out.type = REG_BINARY; + } + else { + struct registry_value *val; + + status = reg_queryvalue(p->mem_ctx, regkey, r->in.value_name->name, + &val); + if (!W_ERROR_IS_OK(status)) { + + DEBUG(10,("_winreg_QueryValue: reg_queryvalue failed with: %s\n", + win_errstr(status))); + + if (r->out.data_size) { + *r->out.data_size = 0; + } + if (r->out.data_length) { + *r->out.data_length = 0; + } + return status; + } + + outbuf = val->data.data; + outbuf_size = val->data.length; + *r->out.type = val->type; + } + + status = WERR_BADFILE; + + if (*r->in.data_size < outbuf_size) { + *r->out.data_size = outbuf_size; + status = r->in.data ? WERR_MORE_DATA : WERR_OK; + } else { + *r->out.data_length = outbuf_size; + *r->out.data_size = outbuf_size; + if (r->out.data) { + memcpy(r->out.data, outbuf, outbuf_size); + } + status = WERR_OK; + } + + if (free_prs) prs_mem_free(&prs_hkpd); + if (free_buf) SAFE_FREE(outbuf); + + return status; +} + +/***************************************************************************** + _winreg_QueryInfoKey + ****************************************************************************/ + +WERROR _winreg_QueryInfoKey(struct pipes_struct *p, + struct winreg_QueryInfoKey *r) +{ + WERROR status = WERR_OK; + struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); + + if ( !regkey ) + return WERR_BADFID; + + r->out.classname->name = NULL; + + status = reg_queryinfokey(regkey, r->out.num_subkeys, r->out.max_subkeylen, + r->out.max_classlen, r->out.num_values, r->out.max_valnamelen, + r->out.max_valbufsize, r->out.secdescsize, + r->out.last_changed_time); + if (!W_ERROR_IS_OK(status)) { + return status; + } + + /* + * These calculations account for the registry buffers being + * UTF-16. They are inexact at best, but so far they worked. + */ + + *r->out.max_subkeylen *= 2; + + *r->out.max_valnamelen += 1; + *r->out.max_valnamelen *= 2; + + return WERR_OK; +} + + +/***************************************************************************** + _winreg_GetVersion + ****************************************************************************/ + +WERROR _winreg_GetVersion(struct pipes_struct *p, + struct winreg_GetVersion *r) +{ + struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); + + if ( !regkey ) + return WERR_BADFID; + + return reg_getversion(r->out.version); +} + + +/***************************************************************************** + _winreg_EnumKey + ****************************************************************************/ + +WERROR _winreg_EnumKey(struct pipes_struct *p, + struct winreg_EnumKey *r) +{ + WERROR err = WERR_OK; + struct registry_key *key = find_regkey_by_hnd( p, r->in.handle ); + + if ( !key ) + return WERR_BADFID; + + if ( !r->in.name || !r->in.keyclass ) + return WERR_INVALID_PARAM; + + DEBUG(8,("_winreg_EnumKey: enumerating key [%s]\n", key->key->name)); + + err = reg_enumkey(p->mem_ctx, key, r->in.enum_index, (char **)&r->out.name->name, + r->out.last_changed_time); + if (!W_ERROR_IS_OK(err)) { + return err; + } + r->out.keyclass->name = ""; + return WERR_OK; +} + +/***************************************************************************** + _winreg_EnumValue + ****************************************************************************/ + +WERROR _winreg_EnumValue(struct pipes_struct *p, + struct winreg_EnumValue *r) +{ + WERROR err = WERR_OK; + struct registry_key *key = find_regkey_by_hnd( p, r->in.handle ); + char *valname = NULL; + struct registry_value *val = NULL; + + if ( !key ) + return WERR_BADFID; + + if ( !r->in.name ) + return WERR_INVALID_PARAM; + + DEBUG(8,("_winreg_EnumValue: enumerating values for key [%s]\n", + key->key->name)); + + err = reg_enumvalue(p->mem_ctx, key, r->in.enum_index, &valname, &val); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + if (r->out.name != NULL) { + r->out.name->name = valname; + } + + if (r->out.type != NULL) { + *r->out.type = val->type; + } + + if (r->out.value != NULL) { + if ((r->out.size == NULL) || (r->out.length == NULL)) { + return WERR_INVALID_PARAM; + } + + if (val->data.length > *r->out.size) { + return WERR_MORE_DATA; + } + + memcpy( r->out.value, val->data.data, val->data.length ); + } + + if (r->out.length != NULL) { + *r->out.length = val->data.length; + } + if (r->out.size != NULL) { + *r->out.size = val->data.length; + } + + return WERR_OK; +} + +/******************************************************************* + _winreg_InitiateSystemShutdown + ********************************************************************/ + +WERROR _winreg_InitiateSystemShutdown(struct pipes_struct *p, + struct winreg_InitiateSystemShutdown *r) +{ + struct winreg_InitiateSystemShutdownEx s; + + s.in.hostname = r->in.hostname; + s.in.message = r->in.message; + s.in.timeout = r->in.timeout; + s.in.force_apps = r->in.force_apps; + s.in.do_reboot = r->in.do_reboot; + s.in.reason = 0; + + /* thunk down to _winreg_InitiateSystemShutdownEx() + (just returns a status) */ + + return _winreg_InitiateSystemShutdownEx( p, &s ); +} + +/******************************************************************* + _winreg_InitiateSystemShutdownEx + ********************************************************************/ + +#define SHUTDOWN_R_STRING "-r" +#define SHUTDOWN_F_STRING "-f" + + +WERROR _winreg_InitiateSystemShutdownEx(struct pipes_struct *p, + struct winreg_InitiateSystemShutdownEx *r) +{ + char *shutdown_script = NULL; + char *msg = NULL; + char *chkmsg = NULL; + fstring str_timeout; + fstring str_reason; + fstring do_reboot; + fstring f; + int ret = -1; + bool can_shutdown = false; + + shutdown_script = talloc_strdup(p->mem_ctx, lp_shutdown_script()); + if (!shutdown_script) { + return WERR_NOMEM; + } + if (!*shutdown_script) { + return WERR_ACCESS_DENIED; + } + + /* pull the message string and perform necessary sanity checks on it */ + + if ( r->in.message && r->in.message->string ) { + if ( (msg = talloc_strdup(p->mem_ctx, r->in.message->string )) == NULL ) { + return WERR_NOMEM; + } + chkmsg = TALLOC_ARRAY(p->mem_ctx, char, strlen(msg)+1); + if (!chkmsg) { + return WERR_NOMEM; + } + alpha_strcpy(chkmsg, msg, NULL, strlen(msg)+1); + } + + fstr_sprintf(str_timeout, "%d", r->in.timeout); + fstr_sprintf(do_reboot, r->in.do_reboot ? SHUTDOWN_R_STRING : ""); + fstr_sprintf(f, r->in.force_apps ? SHUTDOWN_F_STRING : ""); + fstr_sprintf(str_reason, "%d", r->in.reason ); + + shutdown_script = talloc_all_string_sub(p->mem_ctx, + shutdown_script, "%z", chkmsg ? chkmsg : ""); + if (!shutdown_script) { + return WERR_NOMEM; + } + shutdown_script = talloc_all_string_sub(p->mem_ctx, + shutdown_script, "%t", str_timeout); + if (!shutdown_script) { + return WERR_NOMEM; + } + shutdown_script = talloc_all_string_sub(p->mem_ctx, + shutdown_script, "%r", do_reboot); + if (!shutdown_script) { + return WERR_NOMEM; + } + shutdown_script = talloc_all_string_sub(p->mem_ctx, + shutdown_script, "%f", f); + if (!shutdown_script) { + return WERR_NOMEM; + } + shutdown_script = talloc_all_string_sub(p->mem_ctx, + shutdown_script, "%x", str_reason); + if (!shutdown_script) { + return WERR_NOMEM; + } + + can_shutdown = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_REMOTE_SHUTDOWN); + + /* IF someone has privs, run the shutdown script as root. OTHERWISE run it as not root + Take the error return from the script and provide it as the Windows return code. */ + + /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ + + if ( can_shutdown ) + become_root(); + + ret = smbrun( shutdown_script, NULL ); + + if ( can_shutdown ) + unbecome_root(); + + /********** END SeRemoteShutdownPrivilege BLOCK **********/ + + DEBUG(3,("_reg_shutdown_ex: Running the command `%s' gave %d\n", + shutdown_script, ret)); + + return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED; +} + +/******************************************************************* + _winreg_AbortSystemShutdown + ********************************************************************/ + +WERROR _winreg_AbortSystemShutdown(struct pipes_struct *p, + struct winreg_AbortSystemShutdown *r) +{ + const char *abort_shutdown_script = lp_abort_shutdown_script(); + int ret = -1; + bool can_shutdown = false; + + if (!*abort_shutdown_script) + return WERR_ACCESS_DENIED; + + can_shutdown = security_token_has_privilege(p->server_info->security_token, SEC_PRIV_REMOTE_SHUTDOWN); + + /********** BEGIN SeRemoteShutdownPrivilege BLOCK **********/ + + if ( can_shutdown ) + become_root(); + + ret = smbrun( abort_shutdown_script, NULL ); + + if ( can_shutdown ) + unbecome_root(); + + /********** END SeRemoteShutdownPrivilege BLOCK **********/ + + DEBUG(3,("_winreg_AbortSystemShutdown: Running the command `%s' gave %d\n", + abort_shutdown_script, ret)); + + return (ret == 0) ? WERR_OK : WERR_ACCESS_DENIED; +} + +/******************************************************************* + ********************************************************************/ + +static int validate_reg_filename(TALLOC_CTX *ctx, char **pp_fname ) +{ + char *p = NULL; + int num_services = lp_numservices(); + int snum = -1; + const char *share_path = NULL; + char *fname = *pp_fname; + + /* convert to a unix path, stripping the C:\ along the way */ + + if (!(p = valid_share_pathname(ctx, fname))) { + return -1; + } + + /* has to exist within a valid file share */ + + for (snum=0; snumin.handle ); + char *fname = NULL; + int snum = -1; + + if ( !regkey ) + return WERR_BADFID; + + if ( !r->in.filename || !r->in.filename->name ) + return WERR_INVALID_PARAM; + + fname = talloc_strdup(p->mem_ctx, r->in.filename->name); + if (!fname) { + return WERR_NOMEM; + } + + DEBUG(8,("_winreg_RestoreKey: verifying restore of key [%s] from " + "\"%s\"\n", regkey->key->name, fname)); + + if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1) + return WERR_OBJECT_PATH_INVALID; + + /* user must posses SeRestorePrivilege for this this proceed */ + + if ( !security_token_has_privilege(p->server_info->security_token, SEC_PRIV_RESTORE)) { + return WERR_ACCESS_DENIED; + } + + DEBUG(2,("_winreg_RestoreKey: Restoring [%s] from %s in share %s\n", + regkey->key->name, fname, lp_servicename(snum) )); + + return reg_restorekey(regkey, fname); +} + +/******************************************************************* + _winreg_SaveKey + ********************************************************************/ + +WERROR _winreg_SaveKey(struct pipes_struct *p, + struct winreg_SaveKey *r) +{ + struct registry_key *regkey = find_regkey_by_hnd( p, r->in.handle ); + char *fname = NULL; + int snum = -1; + + if ( !regkey ) + return WERR_BADFID; + + if ( !r->in.filename || !r->in.filename->name ) + return WERR_INVALID_PARAM; + + fname = talloc_strdup(p->mem_ctx, r->in.filename->name); + if (!fname) { + return WERR_NOMEM; + } + + DEBUG(8,("_winreg_SaveKey: verifying backup of key [%s] to \"%s\"\n", + regkey->key->name, fname)); + + if ((snum = validate_reg_filename(p->mem_ctx, &fname)) == -1 ) + return WERR_OBJECT_PATH_INVALID; + + DEBUG(2,("_winreg_SaveKey: Saving [%s] to %s in share %s\n", + regkey->key->name, fname, lp_servicename(snum) )); + + return reg_savekey(regkey, fname); +} + +/******************************************************************* + _winreg_SaveKeyEx + ********************************************************************/ + +WERROR _winreg_SaveKeyEx(struct pipes_struct *p, + struct winreg_SaveKeyEx *r) +{ + /* fill in your code here if you think this call should + do anything */ + + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************* + _winreg_CreateKey + ********************************************************************/ + +WERROR _winreg_CreateKey(struct pipes_struct *p, + struct winreg_CreateKey *r) +{ + struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle); + struct registry_key *new_key = NULL; + WERROR result = WERR_OK; + + if ( !parent ) + return WERR_BADFID; + + DEBUG(10, ("_winreg_CreateKey called with parent key '%s' and " + "subkey name '%s'\n", parent->key->name, r->in.name.name)); + + result = reg_createkey(NULL, parent, r->in.name.name, r->in.access_mask, + &new_key, r->out.action_taken); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + if (!create_policy_hnd(p, r->out.new_handle, new_key)) { + TALLOC_FREE(new_key); + return WERR_BADFILE; + } + + return WERR_OK; +} + +/******************************************************************* + _winreg_SetValue + ********************************************************************/ + +WERROR _winreg_SetValue(struct pipes_struct *p, + struct winreg_SetValue *r) +{ + struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); + struct registry_value *val = NULL; + + if ( !key ) + return WERR_BADFID; + + DEBUG(8,("_winreg_SetValue: Setting value for [%s:%s]\n", + key->key->name, r->in.name.name)); + + val = talloc_zero(p->mem_ctx, struct registry_value); + if (val == NULL) { + return WERR_NOMEM; + } + + val->type = r->in.type; + val->data = data_blob_talloc(p->mem_ctx, r->in.data, r->in.size); + + return reg_setvalue(key, r->in.name.name, val); +} + +/******************************************************************* + _winreg_DeleteKey + ********************************************************************/ + +WERROR _winreg_DeleteKey(struct pipes_struct *p, + struct winreg_DeleteKey *r) +{ + struct registry_key *parent = find_regkey_by_hnd(p, r->in.handle); + + if ( !parent ) + return WERR_BADFID; + + return reg_deletekey(parent, r->in.key.name); +} + + +/******************************************************************* + _winreg_DeleteValue + ********************************************************************/ + +WERROR _winreg_DeleteValue(struct pipes_struct *p, + struct winreg_DeleteValue *r) +{ + struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); + + if ( !key ) + return WERR_BADFID; + + return reg_deletevalue(key, r->in.value.name); +} + +/******************************************************************* + _winreg_GetKeySecurity + ********************************************************************/ + +WERROR _winreg_GetKeySecurity(struct pipes_struct *p, + struct winreg_GetKeySecurity *r) +{ + struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); + WERROR err = WERR_OK; + struct security_descriptor *secdesc = NULL; + uint8 *data = NULL; + size_t len = 0; + + if ( !key ) + return WERR_BADFID; + + /* access checks first */ + + if ( !(key->key->access_granted & SEC_STD_READ_CONTROL) ) + return WERR_ACCESS_DENIED; + + err = reg_getkeysecurity(p->mem_ctx, key, &secdesc); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + err = ntstatus_to_werror(marshall_sec_desc(p->mem_ctx, secdesc, + &data, &len)); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + if (len > r->out.sd->size) { + r->out.sd->size = len; + return WERR_INSUFFICIENT_BUFFER; + } + + r->out.sd->size = len; + r->out.sd->len = len; + r->out.sd->data = data; + + return WERR_OK; +} + +/******************************************************************* + _winreg_SetKeySecurity + ********************************************************************/ + +WERROR _winreg_SetKeySecurity(struct pipes_struct *p, + struct winreg_SetKeySecurity *r) +{ + struct registry_key *key = find_regkey_by_hnd(p, r->in.handle); + struct security_descriptor *secdesc = NULL; + WERROR err = WERR_OK; + + if ( !key ) + return WERR_BADFID; + + /* access checks first */ + + if ( !(key->key->access_granted & SEC_STD_WRITE_DAC) ) + return WERR_ACCESS_DENIED; + + err = ntstatus_to_werror(unmarshall_sec_desc(p->mem_ctx, r->in.sd->data, + r->in.sd->len, &secdesc)); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + return reg_setkeysecurity(key, secdesc); +} + +/******************************************************************* + _winreg_FlushKey + ********************************************************************/ + +WERROR _winreg_FlushKey(struct pipes_struct *p, + struct winreg_FlushKey *r) +{ + /* I'm just replying OK because there's not a lot + here I see to do i --jerry */ + + return WERR_OK; +} + +/******************************************************************* + _winreg_UnLoadKey + ********************************************************************/ + +WERROR _winreg_UnLoadKey(struct pipes_struct *p, + struct winreg_UnLoadKey *r) +{ + /* fill in your code here if you think this call should + do anything */ + + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************* + _winreg_ReplaceKey + ********************************************************************/ + +WERROR _winreg_ReplaceKey(struct pipes_struct *p, + struct winreg_ReplaceKey *r) +{ + /* fill in your code here if you think this call should + do anything */ + + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************* + _winreg_LoadKey + ********************************************************************/ + +WERROR _winreg_LoadKey(struct pipes_struct *p, + struct winreg_LoadKey *r) +{ + /* fill in your code here if you think this call should + do anything */ + + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************* + _winreg_NotifyChangeKeyValue + ********************************************************************/ + +WERROR _winreg_NotifyChangeKeyValue(struct pipes_struct *p, + struct winreg_NotifyChangeKeyValue *r) +{ + return WERR_NOT_SUPPORTED; +} + +/******************************************************************* + _winreg_QueryMultipleValues + ********************************************************************/ + +WERROR _winreg_QueryMultipleValues(struct pipes_struct *p, + struct winreg_QueryMultipleValues *r) +{ + struct winreg_QueryMultipleValues2 r2; + uint32_t needed = 0; + + r2.in.key_handle = r->in.key_handle; + r2.in.values_in = r->in.values_in; + r2.in.num_values = r->in.num_values; + r2.in.offered = r->in.buffer_size; + r2.in.buffer = r->in.buffer; + r2.out.values_out = r->out.values_out; + r2.out.needed = &needed; + r2.out.buffer = r->out.buffer; + + return _winreg_QueryMultipleValues2(p, &r2); +} + +/******************************************************************* + ********************************************************************/ + +static WERROR construct_multiple_entry(TALLOC_CTX *mem_ctx, + const char *valuename, + uint32_t value_length, + uint32_t offset, + enum winreg_Type type, + struct QueryMultipleValue *r) +{ + r->ve_valuename = talloc_zero(mem_ctx, struct winreg_ValNameBuf); + if (r->ve_valuename == NULL) { + return WERR_NOMEM; + } + + r->ve_valuename->name = talloc_strdup(r->ve_valuename, valuename ? valuename : ""); + if (r->ve_valuename->name == NULL) { + return WERR_NOMEM; + } + + r->ve_valuename->size = strlen_m_term(r->ve_valuename->name)*2; + r->ve_valuelen = value_length; + r->ve_valueptr = offset; + r->ve_type = type; + + return WERR_OK; +} + +/******************************************************************* + _winreg_QueryMultipleValues2 + ********************************************************************/ + +WERROR _winreg_QueryMultipleValues2(struct pipes_struct *p, + struct winreg_QueryMultipleValues2 *r) +{ + struct registry_key *regkey = find_regkey_by_hnd(p, r->in.key_handle); + struct registry_value *vals = NULL; + const char **names = NULL; + uint32_t offset = 0, num_vals = 0; + DATA_BLOB result = data_blob_null; + int i = 0; + WERROR err = WERR_OK; + + if (!regkey) { + return WERR_BADFID; + } + + names = talloc_zero_array(p->mem_ctx, const char *, r->in.num_values); + if (names == NULL) { + return WERR_NOMEM; + } + + for (i=0; i < r->in.num_values; i++) { + if (r->in.values_in[i].ve_valuename && + r->in.values_in[i].ve_valuename->name) { + names[i] = talloc_strdup(names, + r->in.values_in[i].ve_valuename->name); + if (names[i] == NULL) { + return WERR_NOMEM; + } + } + } + + err = reg_querymultiplevalues(p->mem_ctx, regkey, + r->in.num_values, names, + &num_vals, &vals); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + result = data_blob_talloc(p->mem_ctx, NULL, 0); + + for (i=0; i < r->in.num_values; i++) { + const char *valuename = NULL; + + if (vals[i].data.length > 0) { + if (!data_blob_append(p->mem_ctx, &result, + vals[i].data.data, + vals[i].data.length)) { + return WERR_NOMEM; + } + } + + if (r->in.values_in[i].ve_valuename && + r->in.values_in[i].ve_valuename->name) { + valuename = r->in.values_in[i].ve_valuename->name; + } + + err = construct_multiple_entry(r->out.values_out, + valuename, + vals[i].data.length, + offset, + vals[i].type, + &r->out.values_out[i]); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + offset += vals[i].data.length; + } + + *r->out.needed = result.length; + + if (r->in.num_values != num_vals) { + return WERR_BADFILE; + } + + if (*r->in.offered >= *r->out.needed) { + if (r->out.buffer) { + memcpy(r->out.buffer, result.data, MIN(result.length, *r->in.offered)); + } + return WERR_OK; + } else { + return WERR_MORE_DATA; + } +} + +/******************************************************************* + _winreg_DeleteKeyEx + ********************************************************************/ + +WERROR _winreg_DeleteKeyEx(struct pipes_struct *p, + struct winreg_DeleteKeyEx *r) +{ + /* fill in your code here if you think this call should + do anything */ + + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} 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 0000000000..4cbf70c80f --- /dev/null +++ b/source3/rpc_server/wkssvc/srv_wkssvc_nt.c @@ -0,0 +1,1019 @@ +/* + * 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 . + */ + +/* This is the implementation of the wks interface. */ + +#include "includes.h" +#include "librpc/gen_ndr/libnet_join.h" +#include "libnet/libnet_join.h" +#include "../libcli/auth/libcli_auth.h" +#include "../librpc/gen_ndr/srv_wkssvc.h" +#include "../libcli/security/security.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_SRV + +struct dom_usr { + char *name; + char *domain; + time_t login_time; +}; + +#ifdef HAVE_GETUTXENT + +#include + +struct usrinfo { + char *name; + struct timeval login_time; +}; + +static int usr_info_cmp(const struct usrinfo *usr1, const struct usrinfo *usr2) +{ + /* Called from qsort to compare two users in a usrinfo_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 timeval_compare(&usr1->login_time, &usr2->login_time); +} + +/******************************************************************* + Get a list of the names of all users logged into this machine + ********************************************************************/ + +static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) +{ + char **users; + int i, num_users = 0; + struct usrinfo *usr_infos = NULL; + struct utmpx *u; + + while ((u = getutxent()) != NULL) { + struct usrinfo *tmp; + if (u->ut_type != USER_PROCESS) { + continue; + } + for (i = 0; i < num_users; i++) { + /* getutxent can return multiple user entries for the + * same user, so ignore any dups */ + if (strcmp(u->ut_user, usr_infos[i].name) == 0) { + break; + } + } + if (i < num_users) { + continue; + } + + tmp = talloc_realloc(mem_ctx, usr_infos, struct usrinfo, + num_users+1); + if (tmp == NULL) { + TALLOC_FREE(tmp); + endutxent(); + return NULL; + } + usr_infos = tmp; + usr_infos[num_users].name = talloc_strdup(usr_infos, + u->ut_user); + if (usr_infos[num_users].name == NULL) { + TALLOC_FREE(usr_infos); + endutxent(); + return NULL; + } + usr_infos[num_users].login_time.tv_sec = u->ut_tv.tv_sec; + usr_infos[num_users].login_time.tv_usec = u->ut_tv.tv_usec; + num_users += 1; + } + + /* Sort the user list by time, oldest first */ + TYPESAFE_QSORT(usr_infos, num_users, usr_info_cmp); + + users = (char**)talloc_array(mem_ctx, char*, num_users); + if (users) { + for (i = 0; i < num_users; i++) { + users[i] = talloc_move(users, &usr_infos[i].name); + } + } + TALLOC_FREE(usr_infos); + endutxent(); + errno = 0; + return users; +} + +#else + +static char **get_logged_on_userlist(TALLOC_CTX *mem_ctx) +{ + return NULL; +} + +#endif + +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 struct dom_usr *get_domain_userlist(TALLOC_CTX *mem_ctx) +{ + 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) { + errno = 0; + return NULL; + } + + users = talloc_array(mem_ctx, struct dom_usr, num_sessions); + if (users == NULL) { + TALLOC_FREE(session_list); + return NULL; + } + + for (i=num_users=0; iplatform_id = PLATFORM_ID_NT; /* unknown */ + info100->version_major = lp_major_announce_version(); + info100->version_minor = lp_minor_announce_version(); + + info100->server_name = talloc_asprintf_strupper_m( + info100, "%s", global_myname()); + 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 = lp_major_announce_version(); + info101->version_minor = lp_minor_announce_version(); + + info101->server_name = talloc_asprintf_strupper_m( + info101, "%s", global_myname()); + 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; + char **users; + + info102 = talloc(mem_ctx, struct wkssvc_NetWkstaInfo102); + if (info102 == NULL) { + return NULL; + } + + info102->platform_id = PLATFORM_ID_NT; /* unknown */ + info102->version_major = lp_major_announce_version(); + info102->version_minor = lp_minor_announce_version(); + + info102->server_name = talloc_asprintf_strupper_m( + info102, "%s", global_myname()); + info102->domain_name = talloc_asprintf_strupper_m( + info102, "%s", lp_workgroup()); + info102->lan_root = ""; + + users = get_logged_on_userlist(talloc_tos()); + info102->logged_on_users = talloc_array_length(users); + + TALLOC_FREE(users); + + return info102; +} + +/******************************************************************** + Handling for RPC Workstation Service request NetWkstaGetInfo + ********************************************************************/ + +WERROR _wkssvc_NetWkstaGetInfo(struct pipes_struct *p, + struct wkssvc_NetWkstaGetInfo *r) +{ + 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_NOMEM; + } + break; + case 101: + /* Level 101 can be allowed from any logged in user */ + if (!nt_token_check_sid(&global_sid_Authenticated_Users, + p->server_info->security_token)) { + DEBUG(1,("User not allowed for NetWkstaGetInfo level " + "101\n")); + DEBUGADD(3,(" - does not have sid for Authenticated " + "Users %s:\n", + sid_string_dbg( + &global_sid_Authenticated_Users))); + security_token_debug(DBGC_CLASS, 3, + p->server_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_NOMEM; + } + break; + case 102: + /* Level 102 Should only be allowed from a domain administrator */ + if (!nt_token_check_sid(&global_sid_Builtin_Administrators, + p->server_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", + sid_string_dbg(&global_sid_Builtin_Administrators))); + security_token_debug(DBGC_CLASS, 3, + p->server_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_NOMEM; + } + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + return WERR_OK; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetWkstaSetInfo(struct pipes_struct *p, + struct wkssvc_NetWkstaSetInfo *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + 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; + char **users; + int i, num_users; + + ctr0 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr0); + if (ctr0 == NULL) { + return NULL; + } + + users = get_logged_on_userlist(talloc_tos()); + if (users == NULL && errno != 0) { + DEBUG(1,("get_logged_on_userlist error %d: %s\n", + errno, strerror(errno))); + TALLOC_FREE(ctr0); + return NULL; + } + + num_users = talloc_array_length(users); + ctr0->entries_read = num_users; + ctr0->user0 = talloc_array(ctr0, struct wkssvc_NetrWkstaUserInfo0, + num_users); + if (ctr0->user0 == NULL) { + TALLOC_FREE(ctr0); + TALLOC_FREE(users); + return NULL; + } + + for (i=0; iuser0[i].user_name = talloc_move(ctr0->user0, &users[i]); + } + TALLOC_FREE(users); + 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; + char **users; + struct dom_usr *dom_users; + const char *pwd_server; + char *pwd_tmp; + int i, j, num_users, num_dom_users; + + ctr1 = talloc(mem_ctx, struct wkssvc_NetWkstaEnumUsersCtr1); + if (ctr1 == NULL) { + return NULL; + } + + users = get_logged_on_userlist(talloc_tos()); + if (users == NULL && errno != 0) { + DEBUG(1,("get_logged_on_userlist error %d: %s\n", + errno, strerror(errno))); + TALLOC_FREE(ctr1); + return NULL; + } + num_users = talloc_array_length(users); + + dom_users = get_domain_userlist(talloc_tos()); + if (dom_users == NULL && errno != 0) { + TALLOC_FREE(ctr1); + TALLOC_FREE(users); + return NULL; + } + num_dom_users = talloc_array_length(dom_users); + + ctr1->user1 = talloc_array(ctr1, struct wkssvc_NetrWkstaUserInfo1, + num_users+num_dom_users); + if (ctr1->user1 == NULL) { + TALLOC_FREE(ctr1); + TALLOC_FREE(users); + TALLOC_FREE(dom_users); + return NULL; + } + + pwd_server = ""; + + if ((pwd_tmp = talloc_strdup(ctr1->user1, lp_passwordserver()))) { + /* 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; + } + + /* Put in local users first */ + for (i=0; iuser1[i].user_name = talloc_move(ctr1->user1, &users[i]); + + /* For a local user the domain name and logon server are + * both returned as the local machine's NetBIOS name */ + ctr1->user1[i].logon_domain = ctr1->user1[i].logon_server = + talloc_asprintf_strupper_m(ctr1->user1, "%s", global_myname()); + + ctr1->user1[i].other_domains = NULL; /* Maybe in future? */ + } + + /* Now domain users */ + for (j=0; juser1[i].user_name = + talloc_strdup(ctr1->user1, dom_users[j].name); + ctr1->user1[i].logon_domain = + talloc_strdup(ctr1->user1, dom_users[j].domain); + ctr1->user1[i].logon_server = pwd_server; + + ctr1->user1[i++].other_domains = NULL; /* Maybe in future? */ + } + + ctr1->entries_read = i; + + TALLOC_FREE(users); + 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) +{ + /* This with any level should only be allowed from a domain administrator */ + if (!nt_token_check_sid(&global_sid_Builtin_Administrators, + p->server_info->security_token)) { + DEBUG(1,("User not allowed for NetWkstaEnumUsers\n")); + DEBUGADD(3,(" - does not have sid for Administrators group " + "%s\n", sid_string_dbg( + &global_sid_Builtin_Administrators))); + security_token_debug(DBGC_CLASS, 3, p->server_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_NOMEM; + } + r->out.info->level = r->in.info->level; + *r->out.entries_read = r->out.info->ctr.user0->entries_read; + *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_NOMEM; + } + r->out.info->level = r->in.info->level; + *r->out.entries_read = r->out.info->ctr.user1->entries_read; + *r->out.resume_handle = 0; + break; + default: + return WERR_UNKNOWN_LEVEL; + } + + return WERR_OK; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrWkstaUserGetInfo(struct pipes_struct *p, + struct wkssvc_NetrWkstaUserGetInfo *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrWkstaUserSetInfo(struct pipes_struct *p, + struct wkssvc_NetrWkstaUserSetInfo *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetWkstaTransportEnum(struct pipes_struct *p, + struct wkssvc_NetWkstaTransportEnum *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrWkstaTransportAdd(struct pipes_struct *p, + struct wkssvc_NetrWkstaTransportAdd *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrWkstaTransportDel(struct pipes_struct *p, + struct wkssvc_NetrWkstaTransportDel *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrUseAdd(struct pipes_struct *p, + struct wkssvc_NetrUseAdd *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrUseGetInfo(struct pipes_struct *p, + struct wkssvc_NetrUseGetInfo *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrUseDel(struct pipes_struct *p, + struct wkssvc_NetrUseDel *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrUseEnum(struct pipes_struct *p, + struct wkssvc_NetrUseEnum *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrMessageBufferSend(struct pipes_struct *p, + struct wkssvc_NetrMessageBufferSend *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrWorkstationStatisticsGet(struct pipes_struct *p, + struct wkssvc_NetrWorkstationStatisticsGet *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrLogonDomainNameAdd(struct pipes_struct *p, + struct wkssvc_NetrLogonDomainNameAdd *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrLogonDomainNameDel(struct pipes_struct *p, + struct wkssvc_NetrLogonDomainNameDel *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrJoinDomain(struct pipes_struct *p, + struct wkssvc_NetrJoinDomain *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrUnjoinDomain(struct pipes_struct *p, + struct wkssvc_NetrUnjoinDomain *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrRenameMachineInDomain(struct pipes_struct *p, + struct wkssvc_NetrRenameMachineInDomain *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrValidateName(struct pipes_struct *p, + struct wkssvc_NetrValidateName *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrGetJoinInformation(struct pipes_struct *p, + struct wkssvc_NetrGetJoinInformation *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrGetJoinableOus(struct pipes_struct *p, + struct wkssvc_NetrGetJoinableOus *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + _wkssvc_NetrJoinDomain2 + ********************************************************************/ + +WERROR _wkssvc_NetrJoinDomain2(struct pipes_struct *p, + struct wkssvc_NetrJoinDomain2 *r) +{ + struct libnet_JoinCtx *j = NULL; + char *cleartext_pwd = NULL; + char *admin_domain = NULL; + char *admin_account = NULL; + WERROR werr; + struct security_token *token = p->server_info->security_token; + + if (!r->in.domain_name) { + return WERR_INVALID_PARAM; + } + + if (!r->in.admin_account || !r->in.encrypted_password) { + return WERR_INVALID_PARAM; + } + + 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; + } + + werr = decode_wkssvc_join_password_buffer( + p->mem_ctx, r->in.encrypted_password, + &p->server_info->user_session_key, &cleartext_pwd); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + split_domain_user(p->mem_ctx, + r->in.admin_account, + &admin_domain, + &admin_account); + + 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(); + werr = libnet_Join(p->mem_ctx, j); + 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 libnet_UnjoinCtx *u = NULL; + char *cleartext_pwd = NULL; + char *admin_domain = NULL; + char *admin_account = NULL; + WERROR werr; + struct security_token *token = p->server_info->security_token; + + if (!r->in.account || !r->in.encrypted_password) { + return WERR_INVALID_PARAM; + } + + 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; + } + + werr = decode_wkssvc_join_password_buffer( + p->mem_ctx, r->in.encrypted_password, + &p->server_info->user_session_key, &cleartext_pwd); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + split_domain_user(p->mem_ctx, + r->in.account, + &admin_domain, + &admin_account); + + 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(); + werr = libnet_Unjoin(p->mem_ctx, u); + 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 */ + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrValidateName2(struct pipes_struct *p, + struct wkssvc_NetrValidateName2 *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrGetJoinableOus2(struct pipes_struct *p, + struct wkssvc_NetrGetJoinableOus2 *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrAddAlternateComputerName(struct pipes_struct *p, + struct wkssvc_NetrAddAlternateComputerName *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrRemoveAlternateComputerName(struct pipes_struct *p, + struct wkssvc_NetrRemoveAlternateComputerName *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrSetPrimaryComputername(struct pipes_struct *p, + struct wkssvc_NetrSetPrimaryComputername *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} + +/******************************************************************** + ********************************************************************/ + +WERROR _wkssvc_NetrEnumerateComputerNames(struct pipes_struct *p, + struct wkssvc_NetrEnumerateComputerNames *r) +{ + /* FIXME: Add implementation code here */ + p->rng_fault_state = True; + return WERR_NOT_SUPPORTED; +} diff --git a/source3/rpc_server/wscript_build b/source3/rpc_server/wscript_build index 8534141a1a..2eb5b3af0a 100644 --- a/source3/rpc_server/wscript_build +++ b/source3/rpc_server/wscript_build @@ -1,24 +1,24 @@ #!/usr/bin/env python -RPC_LSARPC_SRC = '''srv_lsa_nt.c ../../librpc/gen_ndr/srv_lsa.c''' -RPC_NETLOGON_SRC = '''srv_netlog_nt.c ../../librpc/gen_ndr/srv_netlogon.c''' -RPC_SAMR_SRC = '''srv_samr_nt.c - srv_samr_util.c - srv_samr_chgpasswd.c +RPC_LSARPC_SRC = '''lsa/srv_lsa_nt.c ../../librpc/gen_ndr/srv_lsa.c''' +RPC_NETLOGON_SRC = '''netlogon/srv_netlog_nt.c ../../librpc/gen_ndr/srv_netlogon.c''' +RPC_SAMR_SRC = '''samr/srv_samr_nt.c + samr/srv_samr_util.c + samr/srv_samr_chgpasswd.c ../../librpc/gen_ndr/srv_samr.c''' -RPC_INITSHUTDOWN_SRC = '''srv_initshutdown_nt.c ../../librpc/gen_ndr/srv_initshutdown.c''' -RPC_WINREG_SRC = '''srv_winreg_nt.c ../../librpc/gen_ndr/srv_winreg.c''' -RPC_DSSETUP_SRC = '''srv_dssetup_nt.c ../../librpc/gen_ndr/srv_dssetup.c''' -RPC_SRVSVC_SRC = '''srv_srvsvc_nt.c ../../librpc/gen_ndr/srv_srvsvc.c''' -RPC_WKSSVC_SRC = '''srv_wkssvc_nt.c ../../librpc/gen_ndr/srv_wkssvc.c''' -RPC_SVCCTL_SRC = '''srv_svcctl_nt.c srv_svcctl_reg.c ../../librpc/gen_ndr/srv_svcctl.c''' -RPC_NTSVCS_SRC = '''srv_ntsvcs_nt.c ../../librpc/gen_ndr/srv_ntsvcs.c''' -RPC_NETDFS_SRC = '''srv_dfs_nt.c ../../librpc/gen_ndr/srv_dfs.c''' -RPC_SPOOLSS_SRC = '''srv_spoolss_nt.c ../../librpc/gen_ndr/srv_spoolss.c - srv_spoolss_util.c''' -RPC_EVENTLOG_SRC = '''srv_eventlog_nt.c srv_eventlog_reg.c ../../librpc/gen_ndr/srv_eventlog.c''' -RPC_RPCECHO_SRC = '''srv_echo_nt.c ../../librpc/gen_ndr/srv_echo.c''' -RPC_EPMAPPER_SRC = '''srv_epmapper.c ../../librpc/gen_ndr/srv_epmapper.c''' +RPC_INITSHUTDOWN_SRC = '''initshutdown/srv_initshutdown_nt.c ../../librpc/gen_ndr/srv_initshutdown.c''' +RPC_WINREG_SRC = '''winreg/srv_winreg_nt.c ../../librpc/gen_ndr/srv_winreg.c''' +RPC_DSSETUP_SRC = '''dssetup/srv_dssetup_nt.c ../../librpc/gen_ndr/srv_dssetup.c''' +RPC_SRVSVC_SRC = '''srvsvc/srv_srvsvc_nt.c ../../librpc/gen_ndr/srv_srvsvc.c''' +RPC_WKSSVC_SRC = '''wkssvc/srv_wkssvc_nt.c ../../librpc/gen_ndr/srv_wkssvc.c''' +RPC_SVCCTL_SRC = '''svcctl/srv_svcctl_nt.c svcctl/srv_svcctl_reg.c ../../librpc/gen_ndr/srv_svcctl.c''' +RPC_NTSVCS_SRC = '''ntsvcs/srv_ntsvcs_nt.c ../../librpc/gen_ndr/srv_ntsvcs.c''' +RPC_NETDFS_SRC = '''dfs/srv_dfs_nt.c ../../librpc/gen_ndr/srv_dfs.c''' +RPC_SPOOLSS_SRC = '''spoolss/srv_spoolss_nt.c ../../librpc/gen_ndr/srv_spoolss.c + spoolss/srv_spoolss_util.c''' +RPC_EVENTLOG_SRC = '''eventlog/srv_eventlog_nt.c eventlog/srv_eventlog_reg.c ../../librpc/gen_ndr/srv_eventlog.c''' +RPC_RPCECHO_SRC = '''echo/srv_echo_nt.c ../../librpc/gen_ndr/srv_echo.c''' +RPC_EPMAPPER_SRC = '''epmapper/srv_epmapper.c ../../librpc/gen_ndr/srv_epmapper.c''' bld.SAMBA_SUBSYSTEM('rpc', source='', -- cgit