diff options
Diffstat (limited to 'source3/rpc_server')
-rw-r--r-- | source3/rpc_server/srv_lsa.c | 444 | ||||
-rw-r--r-- | source3/rpc_server/srv_lsa_hnd.c | 316 | ||||
-rw-r--r-- | source3/rpc_server/srv_netlog.c | 832 | ||||
-rw-r--r-- | source3/rpc_server/srv_pipe_hnd.c | 315 | ||||
-rw-r--r-- | source3/rpc_server/srv_reg.c | 240 | ||||
-rw-r--r-- | source3/rpc_server/srv_samr.c | 1352 | ||||
-rw-r--r-- | source3/rpc_server/srv_srvsvc.c | 1015 | ||||
-rw-r--r-- | source3/rpc_server/srv_util.c | 477 | ||||
-rw-r--r-- | source3/rpc_server/srv_wkssvc.c | 113 |
9 files changed, 5104 insertions, 0 deletions
diff --git a/source3/rpc_server/srv_lsa.c b/source3/rpc_server/srv_lsa.c new file mode 100644 index 0000000000..60b74cf599 --- /dev/null +++ b/source3/rpc_server/srv_lsa.c @@ -0,0 +1,444 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + + +/*************************************************************************** +lsa_reply_open_policy + ***************************************************************************/ +static void lsa_reply_open_policy(prs_struct *rdata) +{ + int i; + LSA_R_OPEN_POL r_o; + + /* set up the LSA QUERY INFO response */ + bzero(&(r_o.pol.data), POL_HND_SIZE); + for (i = 4; i < POL_HND_SIZE; i++) + { + r_o.pol.data[i] = i; + } + r_o.status = 0x0; + + /* store the response in the SMB stream */ + lsa_io_r_open_pol("", &r_o, rdata, 0); +} + +/*************************************************************************** +make_dom_query + ***************************************************************************/ +static void make_dom_query(DOM_QUERY *d_q, char *dom_name, char *dom_sid) +{ + int domlen = strlen(dom_name); + + d_q->uni_dom_max_len = domlen * 2; + d_q->uni_dom_str_len = domlen * 2; + + d_q->buffer_dom_name = 4; /* domain buffer pointer */ + d_q->buffer_dom_sid = 2; /* domain sid pointer */ + + /* this string is supposed to be character short */ + make_unistr2(&(d_q->uni_domain_name), dom_name, domlen); + + make_dom_sid2(&(d_q->dom_sid), dom_sid); +} + +/*************************************************************************** +lsa_reply_query_info + ***************************************************************************/ +static void lsa_reply_enum_trust_dom(LSA_Q_ENUM_TRUST_DOM *q_e, + prs_struct *rdata, + uint32 enum_context, char *dom_name, char *dom_sid) +{ + LSA_R_ENUM_TRUST_DOM r_e; + + /* set up the LSA QUERY INFO response */ + make_r_enum_trust_dom(&r_e, enum_context, dom_name, dom_sid, + dom_name != NULL ? 0x0 : 0x80000000 | NT_STATUS_UNABLE_TO_FREE_VM); + + /* store the response in the SMB stream */ + lsa_io_r_enum_trust_dom("", &r_e, rdata, 0); +} + +/*************************************************************************** +lsa_reply_query_info + ***************************************************************************/ +static void lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, prs_struct *rdata, + char *dom_name, char *dom_sid) +{ + LSA_R_QUERY_INFO r_q; + + /* set up the LSA QUERY INFO response */ + + r_q.undoc_buffer = 0x22000000; /* bizarre */ + r_q.info_class = q_q->info_class; + + make_dom_query(&r_q.dom.id5, dom_name, dom_sid); + + r_q.status = 0x0; + + /* store the response in the SMB stream */ + lsa_io_r_query("", &r_q, rdata, 0); +} + +/*************************************************************************** +make_dom_ref + + pretty much hard-coded choice of "other" sids, unfortunately... + + ***************************************************************************/ +static void make_dom_ref(DOM_R_REF *ref, + char *dom_name, char *dom_sid, + char *other_sid1, char *other_sid2, char *other_sid3) +{ + int len_dom_name = strlen(dom_name); + int len_other_sid1 = strlen(other_sid1); + int len_other_sid2 = strlen(other_sid2); + int len_other_sid3 = strlen(other_sid3); + + ref->undoc_buffer = 1; + ref->num_ref_doms_1 = 4; + ref->buffer_dom_name = 1; + ref->max_entries = 32; + ref->num_ref_doms_2 = 4; + + make_uni_hdr2(&(ref->hdr_dom_name ), len_dom_name , len_dom_name , 0); + make_uni_hdr2(&(ref->hdr_ref_dom[0]), len_other_sid1, len_other_sid1, 0); + make_uni_hdr2(&(ref->hdr_ref_dom[1]), len_other_sid2, len_other_sid2, 0); + make_uni_hdr2(&(ref->hdr_ref_dom[2]), len_other_sid3, len_other_sid3, 0); + + if (dom_name != NULL) + { + make_unistr(&(ref->uni_dom_name), dom_name); + } + + make_dom_sid2(&(ref->ref_dom[0]), dom_sid ); + make_dom_sid2(&(ref->ref_dom[1]), other_sid1); + make_dom_sid2(&(ref->ref_dom[2]), other_sid2); + make_dom_sid2(&(ref->ref_dom[3]), other_sid3); +} + +/*************************************************************************** +make_reply_lookup_rids + ***************************************************************************/ +static void make_reply_lookup_rids(LSA_R_LOOKUP_RIDS *r_l, + int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS], + char *dom_name, char *dom_sid, + char *other_sid1, char *other_sid2, char *other_sid3) +{ + int i; + + make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid, + other_sid1, other_sid2, other_sid3); + + r_l->num_entries = num_entries; + r_l->undoc_buffer = 1; + r_l->num_entries2 = num_entries; + + for (i = 0; i < num_entries; i++) + { + make_dom_rid2(&(r_l->dom_rid[i]), dom_rids[i]); + } + + r_l->num_entries3 = num_entries; +} + +/*************************************************************************** +make_lsa_trans_names + ***************************************************************************/ +static void make_lsa_trans_names(LSA_TRANS_NAME_ENUM *trn, + int num_entries, DOM_SID2 sid[MAX_LOOKUP_SIDS], + uint32 *total) +{ + uint32 status = 0x0; + int i; + (*total) = 0; + + for (i = 0; i < num_entries; i++) + { + uint32 rid = 0xffffffff; + uint8 num_auths = sid[i].sid.num_auths; + fstring name; + uint32 type; + + trn->ptr_name[i] = 0; + trn->ptr_name[(*total)] = 0; + + /* find the rid to look up */ + if (num_auths != 0) + { + rid = sid[i].sid.sub_auths[num_auths-1]; + + status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_user_name (rid, name, &type) : status; + status = (status != 0x0) ? lookup_group_name(rid, name, &type) : status; + status = (status != 0x0) ? lookup_alias_name(rid, name, &type) : status; + } + + if (status == 0x0) + { + trn->ptr_name[i] = 1; + make_lsa_trans_name(&(trn->name[(*total)]), type, name, (*total)); + (*total)++; + } + } + + trn->num_entries = (*total); + trn->ptr_trans_names = 1; + trn->num_entries2 = (*total); +} + +/*************************************************************************** +make_reply_lookup_sids + ***************************************************************************/ +static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l, + DOM_R_REF *ref, LSA_TRANS_NAME_ENUM *names, + uint32 mapped_count, uint32 status) +{ + r_l->dom_ref = ref; + r_l->names = names; + r_l->mapped_count = mapped_count; + r_l->status = status; +} + +/*************************************************************************** +lsa_reply_lookup_sids + ***************************************************************************/ +static void lsa_reply_lookup_sids(prs_struct *rdata, + int num_entries, DOM_SID2 sid[MAX_LOOKUP_SIDS], + char *dom_name, char *dom_sid, + char *other_sid1, char *other_sid2, char *other_sid3) +{ + LSA_R_LOOKUP_SIDS r_l; + DOM_R_REF ref; + LSA_TRANS_NAME_ENUM names; + uint32 mapped_count = 0; + + /* set up the LSA Lookup SIDs response */ + make_dom_ref(&ref, dom_name, dom_sid, other_sid1, other_sid2, other_sid3); + make_lsa_trans_names(&names, num_entries, sid, &mapped_count); + make_reply_lookup_sids(&r_l, &ref, &names, mapped_count, 0x0); + + /* store the response in the SMB stream */ + lsa_io_r_lookup_sids("", &r_l, rdata, 0); +} + +/*************************************************************************** +lsa_reply_lookup_rids + ***************************************************************************/ +static void lsa_reply_lookup_rids(prs_struct *rdata, + int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS], + char *dom_name, char *dom_sid, + char *other_sid1, char *other_sid2, char *other_sid3) +{ + LSA_R_LOOKUP_RIDS r_l; + + /* set up the LSA Lookup RIDs response */ + make_reply_lookup_rids(&r_l, num_entries, dom_rids, + dom_name, dom_sid, other_sid1, other_sid2, other_sid3); + r_l.status = 0x0; + + /* store the response in the SMB stream */ + lsa_io_r_lookup_rids("", &r_l, rdata, 0); +} + +/*************************************************************************** +api_lsa_open_policy + ***************************************************************************/ +static void api_lsa_open_policy( int uid, prs_struct *data, + prs_struct *rdata ) +{ + LSA_Q_OPEN_POL q_o; + + /* grab the server, object attributes and desired access flag...*/ + lsa_io_q_open_pol("", &q_o, data, 0); + + /* lkclXXXX having decoded it, ignore all fields in the open policy! */ + + /* return a 20 byte policy handle */ + lsa_reply_open_policy(rdata); +} + +/*************************************************************************** +api_lsa_enum_trust_dom + ***************************************************************************/ +static void api_lsa_enum_trust_dom( int uid, prs_struct *data, + prs_struct *rdata ) +{ + LSA_Q_ENUM_TRUST_DOM q_e; + + /* grab the enum trust domain context etc. */ + lsa_io_q_enum_trust_dom("", &q_e, data, 0); + + /* construct reply. return status is always 0x0 */ + lsa_reply_enum_trust_dom(&q_e, rdata, + 0, NULL, NULL); +} + +/*************************************************************************** +api_lsa_query_info + ***************************************************************************/ +static void api_lsa_query_info( int uid, prs_struct *data, + prs_struct *rdata ) +{ + LSA_Q_QUERY_INFO q_i; + pstring dom_name; + pstring dom_sid; + + /* grab the info class and policy handle */ + lsa_io_q_query("", &q_i, data, 0); + + pstrcpy(dom_name, lp_workgroup()); + pstrcpy(dom_sid , lp_domain_sid()); + + /* construct reply. return status is always 0x0 */ + lsa_reply_query_info(&q_i, rdata, dom_name, dom_sid); +} + +/*************************************************************************** +api_lsa_lookup_sids + ***************************************************************************/ +static void api_lsa_lookup_sids( int uid, prs_struct *data, + prs_struct *rdata ) +{ + LSA_Q_LOOKUP_SIDS q_l; + pstring dom_name; + pstring dom_sid; + + /* grab the info class and policy handle */ + lsa_io_q_lookup_sids("", &q_l, data, 0); + + pstrcpy(dom_name, lp_workgroup()); + pstrcpy(dom_sid , lp_domain_sid()); + + /* construct reply. return status is always 0x0 */ + lsa_reply_lookup_sids(rdata, + q_l.sids.num_entries, q_l.sids.sid, /* SIDs */ + dom_name, dom_sid, /* domain name, domain SID */ + "S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */ +} + +/*************************************************************************** +api_lsa_lookup_names + ***************************************************************************/ +static void api_lsa_lookup_names( int uid, prs_struct *data, + prs_struct *rdata ) +{ + int i; + LSA_Q_LOOKUP_RIDS q_l; + pstring dom_name; + pstring dom_sid; + uint32 dom_rids[MAX_LOOKUP_SIDS]; + uint32 dummy_g_rid; + + /* grab the info class and policy handle */ + lsa_io_q_lookup_rids("", &q_l, data, 0); + + pstrcpy(dom_name, lp_workgroup()); + pstrcpy(dom_sid , lp_domain_sid()); + + /* convert received RIDs to strings, so we can do them. */ + for (i = 0; i < q_l.num_entries; i++) + { + char *user_name = unistr2(q_l.lookup_name[i].str.buffer); + if (!name_to_rid(user_name, &dom_rids[i], &dummy_g_rid)) + { + /* WHOOPS! we should really do something about this... */ + dom_rids[i] = 0; + } + } + + /* construct reply. return status is always 0x0 */ + lsa_reply_lookup_rids(rdata, + q_l.num_entries, dom_rids, /* text-converted SIDs */ + dom_name, dom_sid, /* domain name, domain SID */ + "S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */ +} + +/*************************************************************************** + api_lsa_close + ***************************************************************************/ +static void api_lsa_close( int uid, prs_struct *data, + prs_struct *rdata) +{ + /* XXXX this is NOT good */ + char *q = mem_data(&(rdata->data), rdata->offset); + + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + + rdata->offset += 24; +} + +/*************************************************************************** + api_lsa_open_secret + ***************************************************************************/ +static void api_lsa_open_secret( int uid, prs_struct *data, + prs_struct *rdata) +{ + /* XXXX this is NOT good */ + char *q = mem_data(&(rdata->data), rdata->offset); + + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0); q += 4; + SIVAL(q, 0, 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND); q += 4; + + rdata->offset += 24; +} + +/*************************************************************************** + \PIPE\ntlsa commands + ***************************************************************************/ +static struct api_struct api_lsa_cmds[] = +{ + { "LSA_OPENPOLICY" , LSA_OPENPOLICY , api_lsa_open_policy }, + { "LSA_QUERYINFOPOLICY" , LSA_QUERYINFOPOLICY , api_lsa_query_info }, + { "LSA_ENUMTRUSTDOM" , LSA_ENUMTRUSTDOM , api_lsa_enum_trust_dom }, + { "LSA_CLOSE" , LSA_CLOSE , api_lsa_close }, + { "LSA_OPENSECRET" , LSA_OPENSECRET , api_lsa_open_secret }, + { "LSA_LOOKUPSIDS" , LSA_LOOKUPSIDS , api_lsa_lookup_sids }, + { "LSA_LOOKUPNAMES" , LSA_LOOKUPNAMES , api_lsa_lookup_names }, + { NULL , 0 , NULL } +}; + +/*************************************************************************** + api_ntLsarpcTNP + ***************************************************************************/ +BOOL api_ntlsa_rpc(pipes_struct *p, prs_struct *data) +{ + return api_rpcTNP(p, "api_ntlsa_rpc", api_lsa_cmds, data); +} + diff --git a/source3/rpc_server/srv_lsa_hnd.c b/source3/rpc_server/srv_lsa_hnd.c new file mode 100644 index 0000000000..c8eabf35b4 --- /dev/null +++ b/source3/rpc_server/srv_lsa_hnd.c @@ -0,0 +1,316 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" + + +extern int DEBUGLEVEL; + +#ifndef MAX_OPEN_POLS +#define MAX_OPEN_POLS 50 +#endif + +struct reg_info +{ + /* for use by \PIPE\winreg */ + fstring name; /* name of registry key */ +}; + +struct samr_info +{ + /* for use by the \PIPE\samr policy */ + DOM_SID sid; + uint32 rid; /* relative id associated with the pol_hnd */ + uint32 status; /* some sort of flag. best to record it. comes from opnum 0x39 */ +}; + +static struct +{ + BOOL open; + POLICY_HND pol_hnd; + + union + { + struct samr_info samr; + struct reg_info reg; + + } dev; + +} Policy[MAX_OPEN_POLS]; + + +#define VALID_POL(pnum) (((pnum) >= 0) && ((pnum) < MAX_OPEN_POLS)) +#define OPEN_POL(pnum) (VALID_POL(pnum) && Policy[pnum].open) + +/**************************************************************************** + create a unique policy handle +****************************************************************************/ +void create_pol_hnd(POLICY_HND *hnd) +{ + static uint32 pol_hnd_low = 0; + static uint32 pol_hnd_high = 0; + + if (hnd == NULL) return; + + /* i severely doubt that pol_hnd_high will ever be non-zero... */ + pol_hnd_low++; + if (pol_hnd_low == 0) pol_hnd_high++; + + SIVAL(hnd->data, 0 , 0x0); /* first bit must be null */ + SIVAL(hnd->data, 4 , pol_hnd_low ); /* second bit is incrementing */ + SIVAL(hnd->data, 8 , pol_hnd_high); /* second bit is incrementing */ + SIVAL(hnd->data, 12, time(NULL)); /* something random */ + SIVAL(hnd->data, 16, getpid()); /* something more random */ +} + +/**************************************************************************** + initialise policy handle states... +****************************************************************************/ +void init_lsa_policy_hnd(void) +{ + int i; + for (i = 0; i < MAX_OPEN_POLS; i++) + { + Policy[i].open = False; + } + + return; +} + +/**************************************************************************** + find first available policy slot. creates a policy handle for you. +****************************************************************************/ +BOOL open_lsa_policy_hnd(POLICY_HND *hnd) +{ + int i; + + for (i = 0; i < MAX_OPEN_POLS; i++) + { + if (!Policy[i].open) + { + Policy[i].open = True; + + create_pol_hnd(hnd); + memcpy(&(Policy[i].pol_hnd), hnd, sizeof(*hnd)); + + DEBUG(4,("Opened policy hnd[%x] ", i)); + dump_data(4, hnd->data, sizeof(hnd->data)); + + return True; + } + } + + /* i love obscure error messages. */ +#if TERRY_PRATCHET_INTERESTING_TIMES + DEBUG(1,("+++ OUT OF CHEESE ERROR +++ REDO FROM START ... @?!*@@\n")); +#else + DEBUG(1,("ERROR - open_lsa_policy_hnd: out of Policy Handles!\n")); +#endif + + return False; +} + +/**************************************************************************** + find policy index by handle +****************************************************************************/ +int find_lsa_policy_by_hnd(POLICY_HND *hnd) +{ + int i; + + for (i = 0; i < MAX_OPEN_POLS; i++) + { + if (memcmp(&(Policy[i].pol_hnd), hnd, sizeof(*hnd)) == 0) + { + DEBUG(4,("Found policy hnd[%x] ", i)); + dump_data(4, hnd->data, sizeof(hnd->data)); + + return i; + } + } + + DEBUG(4,("Policy not found: ")); + dump_data(4, hnd->data, sizeof(hnd->data)); + + return -1; +} + +/**************************************************************************** + set samr rid +****************************************************************************/ +BOOL set_lsa_policy_samr_rid(POLICY_HND *hnd, uint32 rid) +{ + int pnum = find_lsa_policy_by_hnd(hnd); + + if (OPEN_POL(pnum)) + { + DEBUG(3,("%s Setting policy device rid=%x pnum=%x\n", + timestring(), rid, pnum)); + + Policy[pnum].dev.samr.rid = rid; + return True; + } + else + { + DEBUG(3,("%s Error setting policy rid=%x (pnum=%x)\n", + timestring(), rid, pnum)); + return False; + } +} + +/**************************************************************************** + set samr pol status. absolutely no idea what this is. +****************************************************************************/ +BOOL set_lsa_policy_samr_pol_status(POLICY_HND *hnd, uint32 pol_status) +{ + int pnum = find_lsa_policy_by_hnd(hnd); + + if (OPEN_POL(pnum)) + { + DEBUG(3,("%s Setting policy status=%x pnum=%x\n", + timestring(), pol_status, pnum)); + + Policy[pnum].dev.samr.status = pol_status; + return True; + } + else + { + DEBUG(3,("%s Error setting policy status=%x (pnum=%x)\n", + timestring(), pol_status, pnum)); + return False; + } +} + +/**************************************************************************** + set samr sid +****************************************************************************/ +BOOL set_lsa_policy_samr_sid(POLICY_HND *hnd, DOM_SID *sid) +{ + int pnum = find_lsa_policy_by_hnd(hnd); + + if (OPEN_POL(pnum)) + { + DEBUG(3,("%s Setting policy sid=%s pnum=%x\n", + timestring(), dom_sid_to_string(sid), pnum)); + + memcpy(&(Policy[pnum].dev.samr.sid), sid, sizeof(*sid)); + return True; + } + else + { + DEBUG(3,("%s Error setting policy sid=%s (pnum=%x)\n", + timestring(), dom_sid_to_string(sid), pnum)); + return False; + } +} + +/**************************************************************************** + set samr rid +****************************************************************************/ +uint32 get_lsa_policy_samr_rid(POLICY_HND *hnd) +{ + int pnum = find_lsa_policy_by_hnd(hnd); + + if (OPEN_POL(pnum)) + { + uint32 rid = Policy[pnum].dev.samr.rid; + DEBUG(3,("%s Getting policy device rid=%x pnum=%x\n", + timestring(), rid, pnum)); + + return rid; + } + else + { + DEBUG(3,("%s Error getting policy (pnum=%x)\n", + timestring(), pnum)); + return 0xffffffff; + } +} + +/**************************************************************************** + set reg name +****************************************************************************/ +BOOL set_lsa_policy_reg_name(POLICY_HND *hnd, fstring name) +{ + int pnum = find_lsa_policy_by_hnd(hnd); + + if (OPEN_POL(pnum)) + { + DEBUG(3,("%s Setting policy pnum=%x name=%s\n", + timestring(), pnum, name)); + + fstrcpy(Policy[pnum].dev.reg.name, name); + return True; + } + else + { + DEBUG(3,("%s Error setting policy (pnum=%x) name=%s\n", + timestring(), pnum, name)); + return False; + } +} + +/**************************************************************************** + get reg name +****************************************************************************/ +BOOL get_lsa_policy_reg_name(POLICY_HND *hnd, fstring name) +{ + int pnum = find_lsa_policy_by_hnd(hnd); + + if (OPEN_POL(pnum)) + { + fstrcpy(name, Policy[pnum].dev.reg.name); + + DEBUG(3,("%s Getting policy pnum=%x name=%s\n", + timestring(), pnum, name)); + + return True; + } + else + { + DEBUG(3,("%s Error getting policy (pnum=%x)\n", + timestring(), pnum)); + return False; + } +} + +/**************************************************************************** + close an lsa policy +****************************************************************************/ +BOOL close_lsa_policy_hnd(POLICY_HND *hnd) +{ + int pnum = find_lsa_policy_by_hnd(hnd); + + if (OPEN_POL(pnum)) + { + DEBUG(3,("%s Closed policy name pnum=%x\n", timestring(), pnum)); + Policy[pnum].open = False; + return True; + } + else + { + DEBUG(3,("%s Error closing policy pnum=%x\n", timestring(), pnum)); + return False; + } +} + diff --git a/source3/rpc_server/srv_netlog.c b/source3/rpc_server/srv_netlog.c new file mode 100644 index 0000000000..94d6faa992 --- /dev/null +++ b/source3/rpc_server/srv_netlog.c @@ -0,0 +1,832 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +extern BOOL sam_logon_in_ssb; +extern pstring samlogon_user; + + + +/************************************************************************* + make_net_r_req_chal: + *************************************************************************/ +static void make_net_r_req_chal(NET_R_REQ_CHAL *r_c, + DOM_CHAL *srv_chal, int status) +{ + DEBUG(6,("make_net_r_req_chal: %d\n", __LINE__)); + memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data)); + r_c->status = status; +} + +/************************************************************************* + net_reply_req_chal: + *************************************************************************/ +static void net_reply_req_chal(NET_Q_REQ_CHAL *q_c, prs_struct *rdata, + DOM_CHAL *srv_chal, uint32 srv_time) +{ + NET_R_REQ_CHAL r_c; + + DEBUG(6,("net_reply_req_chal: %d\n", __LINE__)); + + /* set up the LSA REQUEST CHALLENGE response */ + make_net_r_req_chal(&r_c, srv_chal, srv_time); + + /* store the response in the SMB stream */ + net_io_r_req_chal("", &r_c, rdata, 0); + + DEBUG(6,("net_reply_req_chal: %d\n", __LINE__)); + +} + +/************************************************************************* + net_reply_logon_ctrl2: + *************************************************************************/ +static void net_reply_logon_ctrl2(NET_Q_LOGON_CTRL2 *q_l, prs_struct *rdata, + uint32 flags, uint32 pdc_status, uint32 logon_attempts, + uint32 tc_status, char *trust_domain_name) +{ + NET_R_LOGON_CTRL2 r_l; + + DEBUG(6,("net_reply_logon_ctrl2: %d\n", __LINE__)); + + /* set up the Logon Control2 response */ + make_r_logon_ctrl2(&r_l, q_l->query_level, + flags, pdc_status, logon_attempts, + tc_status, trust_domain_name); + + /* store the response in the SMB stream */ + net_io_r_logon_ctrl2("", &r_l, rdata, 0); + + DEBUG(6,("net_reply_logon_ctrl2: %d\n", __LINE__)); + +} + +/************************************************************************* + net_reply_trust_dom_list: + *************************************************************************/ +static void net_reply_trust_dom_list(NET_Q_TRUST_DOM_LIST *q_t, prs_struct *rdata, + uint32 num_trust_domains, char *trust_domain_name) +{ + NET_R_TRUST_DOM_LIST r_t; + + DEBUG(6,("net_reply_trust_dom_list: %d\n", __LINE__)); + + /* set up the Trusted Domain List response */ + make_r_trust_dom(&r_t, num_trust_domains, trust_domain_name); + + /* store the response in the SMB stream */ + net_io_r_trust_dom("", &r_t, rdata, 0); + + DEBUG(6,("net_reply_trust_dom_listlogon_ctrl2: %d\n", __LINE__)); + +} + +/************************************************************************* + make_net_r_auth_2: + *************************************************************************/ +static void make_net_r_auth_2(NET_R_AUTH_2 *r_a, + DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status) +{ + memcpy( r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data)); + memcpy(&(r_a->srv_flgs) , flgs , sizeof(r_a->srv_flgs)); + r_a->status = status; +} + +/************************************************************************* + net_reply_auth_2: + *************************************************************************/ +static void net_reply_auth_2(NET_Q_AUTH_2 *q_a, prs_struct *rdata, + DOM_CHAL *resp_cred, int status) +{ + NET_R_AUTH_2 r_a; + + /* set up the LSA AUTH 2 response */ + + make_net_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status); + + /* store the response in the SMB stream */ + net_io_r_auth_2("", &r_a, rdata, 0); + +} + +/*********************************************************************************** + make_net_r_srv_pwset: + ***********************************************************************************/ +static void make_net_r_srv_pwset(NET_R_SRV_PWSET *r_s, + DOM_CRED *srv_cred, int status) +{ + DEBUG(5,("make_net_r_srv_pwset: %d\n", __LINE__)); + + memcpy(&(r_s->srv_cred), srv_cred, sizeof(r_s->srv_cred)); + r_s->status = status; + + DEBUG(5,("make_net_r_srv_pwset: %d\n", __LINE__)); +} + +/************************************************************************* + net_reply_srv_pwset: + *************************************************************************/ +static void net_reply_srv_pwset(NET_Q_SRV_PWSET *q_s, prs_struct *rdata, + DOM_CRED *srv_cred, int status) +{ + NET_R_SRV_PWSET r_s; + + DEBUG(5,("net_srv_pwset: %d\n", __LINE__)); + + /* set up the LSA Server Password Set response */ + make_net_r_srv_pwset(&r_s, srv_cred, status); + + /* store the response in the SMB stream */ + net_io_r_srv_pwset("", &r_s, rdata, 0); + + DEBUG(5,("net_srv_pwset: %d\n", __LINE__)); + +} + +/************************************************************************* + net_reply_sam_logon: + *************************************************************************/ +static void net_reply_sam_logon(NET_Q_SAM_LOGON *q_s, prs_struct *rdata, + DOM_CRED *srv_cred, NET_USER_INFO_3 *user_info, + uint32 status) +{ + NET_R_SAM_LOGON r_s; + + /* XXXX maybe we want to say 'no', reject the client's credentials */ + r_s.buffer_creds = 1; /* yes, we have valid server credentials */ + memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds)); + + /* store the user information, if there is any. */ + r_s.user = user_info; + if (status == 0x0 && user_info != NULL && user_info->ptr_user_info != 0) + { + r_s.switch_value = 3; /* indicates type of validation user info */ + } + else + { + r_s.switch_value = 0; /* indicates no info */ + } + + r_s.status = status; + r_s.auth_resp = 1; /* authoritative response */ + + /* store the response in the SMB stream */ + net_io_r_sam_logon("", &r_s, rdata, 0); + +} + + +/************************************************************************* + net_reply_sam_logoff: + *************************************************************************/ +static void net_reply_sam_logoff(NET_Q_SAM_LOGOFF *q_s, prs_struct *rdata, + DOM_CRED *srv_cred, + uint32 status) +{ + NET_R_SAM_LOGOFF r_s; + + /* XXXX maybe we want to say 'no', reject the client's credentials */ + r_s.buffer_creds = 1; /* yes, we have valid server credentials */ + memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds)); + + r_s.status = status; + + /* store the response in the SMB stream */ + net_io_r_sam_logoff("", &r_s, rdata, 0); + +} + +/****************************************************************** + gets a machine password entry. checks access rights of the host. + ******************************************************************/ +static BOOL get_md4pw(char *md4pw, char *mach_name, char *mach_acct) +{ + struct smb_passwd *smb_pass; + + if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(), + client_name(), client_addr())) + { + DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct)); + return False; + } + + become_root(True); + smb_pass = get_smbpwd_entry(mach_acct, 0); + unbecome_root(True); + + if (smb_pass != NULL) + { + memcpy(md4pw, smb_pass->smb_nt_passwd, 16); + dump_data(5, md4pw, 16); + + return True; + } + DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct)); + return False; +} + +/************************************************************************* + api_net_req_chal: + *************************************************************************/ +static void api_net_req_chal( int uid, + prs_struct *data, + prs_struct *rdata) +{ + NET_Q_REQ_CHAL q_r; + uint32 status = 0x0; + + fstring mach_acct; + fstring mach_name; + + user_struct *vuser; + + DEBUG(5,("api_net_req_chal(%d): vuid %d\n", __LINE__, uid)); + + if ((vuser = get_valid_user_struct(uid)) == NULL) return; + + /* grab the challenge... */ + net_io_q_req_chal("", &q_r, data, 0); + + fstrcpy(mach_acct, unistrn2(q_r.uni_logon_clnt.buffer, + q_r.uni_logon_clnt.uni_str_len)); + + fstrcpy(mach_name, mach_acct); + strlower(mach_name); + + strcat(mach_acct, "$"); + + if (get_md4pw(vuser->dc.md4pw, mach_name, mach_acct)) + { + /* copy the client credentials */ + memcpy(vuser->dc.clnt_chal.data , q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data)); + memcpy(vuser->dc.clnt_cred.challenge.data, q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data)); + + /* create a server challenge for the client */ + /* PAXX: set these to random values. */ + /* lkcl: paul, you mentioned that it doesn't really matter much */ + SIVAL(vuser->dc.srv_chal.data, 0, 0x11111111); + SIVAL(vuser->dc.srv_chal.data, 4, 0x11111111); + memcpy(vuser->dc.srv_cred.challenge.data, vuser->dc.srv_chal.data, 8); + + bzero(vuser->dc.sess_key, sizeof(vuser->dc.sess_key)); + + /* from client / server challenges and md4 password, generate sess key */ + cred_session_key(&(vuser->dc.clnt_chal), &(vuser->dc.srv_chal), + vuser->dc.md4pw, vuser->dc.sess_key); + } + else + { + /* lkclXXXX take a guess at a good error message to return :-) */ + status = 0xC0000000 | NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT; + } + + /* construct reply. */ + net_reply_req_chal(&q_r, rdata, + &(vuser->dc.srv_chal), status); + +} + +/************************************************************************* + api_net_auth_2: + *************************************************************************/ +static void api_net_auth_2( int uid, + prs_struct *data, + prs_struct *rdata) +{ + NET_Q_AUTH_2 q_a; + uint32 status = 0x0; + + DOM_CHAL srv_cred; + UTIME srv_time; + + user_struct *vuser; + + if ((vuser = get_valid_user_struct(uid)) == NULL) return; + + srv_time.time = 0; + + /* grab the challenge... */ + net_io_q_auth_2("", &q_a, data, 0); + + /* check that the client credentials are valid */ + if (cred_assert(&(q_a.clnt_chal), vuser->dc.sess_key, + &(vuser->dc.clnt_cred.challenge), srv_time)) + { + + /* create server challenge for inclusion in the reply */ + cred_create(vuser->dc.sess_key, &(vuser->dc.srv_cred.challenge), srv_time, &srv_cred); + + /* copy the received client credentials for use next time */ + memcpy(vuser->dc.clnt_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data)); + memcpy(vuser->dc.srv_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data)); + } + else + { + status = NT_STATUS_ACCESS_DENIED | 0xC0000000; + } + + /* construct reply. */ + net_reply_auth_2(&q_a, rdata, &srv_cred, status); +} + + +/************************************************************************* + api_net_srv_pwset: + *************************************************************************/ +static void api_net_srv_pwset( int uid, + prs_struct *data, + prs_struct *rdata) +{ + NET_Q_SRV_PWSET q_a; + uint32 status = NT_STATUS_WRONG_PASSWORD|0xC0000000; + DOM_CRED srv_cred; +#ifdef ALLOW_SRV_PWSET + pstring mach_acct; + struct smb_passwd *smb_pass; + BOOL ret; +#endif + user_struct *vuser; + + if ((vuser = get_valid_user_struct(uid)) == NULL) return; + + /* grab the challenge and encrypted password ... */ + net_io_q_srv_pwset("", &q_a, data, 0); + + /* checks and updates credentials. creates reply credentials */ + if (deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred), + &(q_a.clnt_id.cred), &srv_cred)) + { + memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred)); + + DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__)); + +#ifdef ALLOW_SRV_PWSET + + pstrcpy(mach_acct, unistrn2(q_a.clnt_id.login.uni_acct_name.buffer, + q_a.clnt_id.login.uni_acct_name.uni_str_len)); + + DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct)); + + become_root(True); + smb_pass = get_smbpwd_entry(mach_acct, 0); + unbecome_root(True); + + if (smb_pass != NULL) + { + unsigned char pwd[16]; + uint8 mode = 2; + + memcpy(pwd, q_a.pwd, 16); + + if (obfuscate_pwd(pwd, vuser->dc.sess_key, mode)) + { + /* lies! nt and lm passwords are _not_ the same: don't care */ + smb_pass->smb_passwd = pwd; + smb_pass->smb_nt_passwd = pwd; + smb_pass->acct_ctrl = ACB_WSTRUST; + + become_root(True); + ret = mod_smbpwd_entry(smb_pass); + unbecome_root(True); + + if (ret) + { + /* hooray! */ + status = 0x0; + } + } + } + + DEBUG(5,("api_net_srv_pwset: %d\n", __LINE__)); +#else + DEBUG(5,("api_net_srv_pwset: server password set being denied\n")); +#endif + + } + else + { + /* lkclXXXX take a guess at a sensible error code to return... */ + status = 0xC0000000 | NT_STATUS_NETWORK_CREDENTIAL_CONFLICT; + } + + /* construct reply. always indicate failure. nt keeps going... */ + net_reply_srv_pwset(&q_a, rdata, + &srv_cred, status); +} + + +/************************************************************************* + api_net_sam_logoff: + *************************************************************************/ +static void api_net_sam_logoff( int uid, + prs_struct *data, + prs_struct *rdata) +{ + NET_Q_SAM_LOGOFF q_l; + NET_ID_INFO_CTR ctr; + + DOM_CRED srv_cred; + + user_struct *vuser; + + if ((vuser = get_valid_user_struct(uid)) == NULL) return; + + /* the DOM_ID_INFO_1 structure is a bit big. plus we might want to + dynamically allocate it inside net_io_q_sam_logon, at some point */ + q_l.sam_id.ctr = &ctr; + + /* grab the challenge... */ + net_io_q_sam_logoff("", &q_l, data, 0); + + /* checks and updates credentials. creates reply credentials */ + deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred), + &(q_l.sam_id.client.cred), &srv_cred); + memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred)); + + /* construct reply. always indicate success */ + net_reply_sam_logoff(&q_l, rdata, + &srv_cred, + 0x0); +} + +/************************************************************************* + net_login_interactive: + *************************************************************************/ +static uint32 net_login_interactive(NET_ID_INFO_1 *id1, + struct smb_passwd *smb_pass, + user_struct *vuser) +{ + uint32 status = 0x0; + +#ifdef USE_ARCFOUR + extern void arcfour(uint8 key[16], uint8 out[16], uint8 in[16]); + char nt_pwd[16]; + char lm_pwd[16]; + unsigned char arc4_key[16]; + memset(arc4_key, 0, 16); + memcpy(arc4_key, vuser->dc.sess_key, 8); + + arcfour(arc4_key, lm_pwd, id1->arc4_lm_owf.data); + arcfour(arc4_key, nt_pwd, id1->arc4_nt_owf.data); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("arcfour decrypt of lm owf password:")); + dump_data(100, lm_pwd, 16); + + DEBUG(100,("arcfour decrypt of nt owf password:")); + dump_data(100, nt_pwd, 16); +#endif + + if (memcmp(smb_pass->smb_passwd , lm_pwd, 16) != 0 && + memcmp(smb_pass->smb_nt_passwd, nt_pwd, 16) != 0) + { + status = 0xC0000000 | NT_STATUS_WRONG_PASSWORD; + } +#else +/* sorry. have to assume that the password is always ok. + this _is_ ok, because the LSA SAM Logon is nothing to do + with SMB connections to shares. + */ +DEBUG(3,("SAM Logon. Password not being checked\n")); +#endif + + return status; +} + +/************************************************************************* + net_login_network: + *************************************************************************/ +static uint32 net_login_network(NET_ID_INFO_2 *id2, + struct smb_passwd *smb_pass, + user_struct *vuser) +{ + if ((id2->lm_chal_resp.str_str_len == 24 || + id2->lm_chal_resp.str_str_len == 0) && + id2->nt_chal_resp.str_str_len == 24 && + (((smb_pass->smb_nt_passwd != NULL) && + smb_password_check(id2->nt_chal_resp.buffer, smb_pass->smb_nt_passwd, + id2->lm_chal)) || + smb_password_check(id2->lm_chal_resp.buffer, smb_pass->smb_passwd, + id2->lm_chal))) + { + return 0x0; + } + return 0xC0000000 | NT_STATUS_WRONG_PASSWORD; +} + +/************************************************************************* + api_net_sam_logon: + *************************************************************************/ +static void api_net_sam_logon( int uid, + prs_struct *data, + prs_struct *rdata) +{ + NET_Q_SAM_LOGON q_l; + NET_ID_INFO_CTR ctr; + NET_USER_INFO_3 usr_info; + uint32 status = 0x0; + DOM_CRED srv_cred; + struct smb_passwd *smb_pass = NULL; + UNISTR2 *uni_samlogon_user = NULL; + + user_struct *vuser = NULL; + + if ((vuser = get_valid_user_struct(uid)) == NULL) return; + + q_l.sam_id.ctr = &ctr; + + net_io_q_sam_logon("", &q_l, data, 0); + + /* checks and updates credentials. creates reply credentials */ + if (!deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred), + &(q_l.sam_id.client.cred), &srv_cred)) + { + status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + else + { + memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred)); + } + + /* find the username */ + + if (status == 0x0) + { + switch (q_l.sam_id.logon_level) + { + case 1: + { + uni_samlogon_user = &(q_l.sam_id.ctr->auth.id1.uni_user_name); + pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer, + uni_samlogon_user->uni_str_len)); + + DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. User:[%s]\n", + lp_workgroup(), samlogon_user)); + break; + } + case 2: + { + uni_samlogon_user = &(q_l.sam_id.ctr->auth.id2.uni_user_name); + pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer, + uni_samlogon_user->uni_str_len)); + + DEBUG(3,("SAM Logon (Network). Domain:[%s]. User:[%s]\n", + lp_workgroup(), samlogon_user)); + break; + } + default: + { + DEBUG(2,("SAM Logon: unsupported switch value\n")); + status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + break; + } + } + } + + /* check username exists */ + + if (status == 0x0) + { + pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer, + uni_samlogon_user->uni_str_len)); + + become_root(True); + smb_pass = get_smbpwd_entry(samlogon_user, 0); + unbecome_root(True); + + if (smb_pass == NULL) + { + status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; + } + } + + /* validate password. */ + + if (status == 0x0) + { + switch (q_l.sam_id.logon_level) + { + case 1: + { + /* interactive login. passwords arcfour'd with session key */ + status = net_login_interactive(&q_l.sam_id.ctr->auth.id1, + smb_pass, vuser); + break; + } + case 2: + { + /* network login. lm challenge and 24 byte responses */ + status = net_login_network(&q_l.sam_id.ctr->auth.id2, + smb_pass, vuser); + break; + } + } + } + + /* lkclXXXX 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. + */ + + /* return the profile plus other bits :-) */ + + if (status == 0x0) + { + DOM_GID gids[LSA_MAX_GROUPS]; + int num_gids = 0; + NTTIME dummy_time; + pstring logon_script; + pstring profile_path; + pstring home_dir; + pstring home_drive; + pstring my_name; + pstring my_workgroup; + pstring domain_groups; + pstring dom_sid; + pstring other_sids; + extern pstring myname; + uint32 r_uid; + uint32 r_gid; + + /* set up pointer indicating user/password failed to be found */ + usr_info.ptr_user_info = 0; + + dummy_time.low = 0xffffffff; + dummy_time.high = 0x7fffffff; + + get_myname(myname, NULL); + + /* XXXX hack to get standard_sub_basic() to use sam logon username */ + /* possibly a better way would be to do a become_user() call */ + sam_logon_in_ssb = True; + + pstrcpy(logon_script, lp_logon_script ()); + pstrcpy(profile_path, lp_logon_path ()); + pstrcpy(dom_sid , lp_domain_sid ()); + pstrcpy(other_sids , lp_domain_other_sids()); + pstrcpy(my_workgroup, lp_workgroup ()); + + pstrcpy(home_drive , lp_logon_drive ()); + pstrcpy(home_dir , lp_logon_home ()); + + pstrcpy(my_name , myname ); + strupper(my_name); + + get_domain_user_groups(domain_groups, samlogon_user); + + num_gids = make_dom_gids(domain_groups, gids); + + sam_logon_in_ssb = False; + + if (name_to_rid(samlogon_user, &r_uid, &r_gid)) + { + make_net_user_info3(&usr_info, + + &dummy_time, /* logon_time */ + &dummy_time, /* logoff_time */ + &dummy_time, /* kickoff_time */ + &dummy_time, /* pass_last_set_time */ + &dummy_time, /* pass_can_change_time */ + &dummy_time, /* pass_must_change_time */ + + samlogon_user , /* user_name */ + vuser->real_name, /* full_name */ + logon_script , /* logon_script */ + profile_path , /* profile_path */ + home_dir , /* home_dir */ + home_drive , /* dir_drive */ + + 0, /* logon_count */ + 0, /* bad_pw_count */ + + r_uid , /* RID user_id */ + r_gid , /* RID group_id */ + num_gids, /* uint32 num_groups */ + gids , /* DOM_GID *gids */ + 0x20 , /* uint32 user_flgs (?) */ + + NULL, /* char sess_key[16] */ + + my_name , /* char *logon_srv */ + my_workgroup, /* char *logon_dom */ + + dom_sid, /* char *dom_sid */ + other_sids); /* char *other_sids */ + } + else + { + status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; + } + } + + net_reply_sam_logon(&q_l, rdata, &srv_cred, &usr_info, status); +} + + +/************************************************************************* + api_net_trust_dom_list: + *************************************************************************/ +static void api_net_trust_dom_list( int uid, + prs_struct *data, + prs_struct *rdata) +{ + NET_Q_TRUST_DOM_LIST q_t; + + char *trusted_domain = "test_domain"; + + DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__)); + + /* grab the lsa trusted domain list query... */ + net_io_q_trust_dom("", &q_t, data, 0); + + /* construct reply. */ + net_reply_trust_dom_list(&q_t, rdata, + 1, trusted_domain); + + DEBUG(6,("api_net_trust_dom_list: %d\n", __LINE__)); +} + + +/************************************************************************* + error messages cropping up when using nltest.exe... + *************************************************************************/ +#define ERROR_NO_SUCH_DOMAIN 0x54b +#define ERROR_NO_LOGON_SERVERS 0x51f + +/************************************************************************* + api_net_logon_ctrl2: + *************************************************************************/ +static void api_net_logon_ctrl2( int uid, + prs_struct *data, + prs_struct *rdata) +{ + NET_Q_LOGON_CTRL2 q_l; + + /* lkclXXXX - guess what - absolutely no idea what these are! */ + uint32 flags = 0x0; + uint32 pdc_connection_status = 0x0; + uint32 logon_attempts = 0x0; + uint32 tc_status = ERROR_NO_LOGON_SERVERS; + char *trusted_domain = "test_domain"; + + DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__)); + + /* grab the lsa netlogon ctrl2 query... */ + net_io_q_logon_ctrl2("", &q_l, data, 0); + + /* construct reply. */ + net_reply_logon_ctrl2(&q_l, rdata, + flags, pdc_connection_status, logon_attempts, + tc_status, trusted_domain); + + DEBUG(6,("api_net_logon_ctrl2: %d\n", __LINE__)); +} + +/******************************************************************* + array of \PIPE\NETLOGON operations + ********************************************************************/ +static struct api_struct api_net_cmds [] = +{ + { "NET_REQCHAL" , NET_REQCHAL , api_net_req_chal }, + { "NET_AUTH2" , NET_AUTH2 , api_net_auth_2 }, + { "NET_SRVPWSET" , NET_SRVPWSET , api_net_srv_pwset }, + { "NET_SAMLOGON" , NET_SAMLOGON , api_net_sam_logon }, + { "NET_SAMLOGOFF" , NET_SAMLOGOFF , api_net_sam_logoff }, + { "NET_LOGON_CTRL2" , NET_LOGON_CTRL2 , api_net_logon_ctrl2 }, + { "NET_TRUST_DOM_LIST", NET_TRUST_DOM_LIST, api_net_trust_dom_list }, + { NULL , 0 , NULL } +}; + +/******************************************************************* + receives a netlogon pipe and responds. + ********************************************************************/ +BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data) +{ + return api_rpcTNP(p, "api_netlog_rpc", api_net_cmds, data); +} diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c new file mode 100644 index 0000000000..e4893fee89 --- /dev/null +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -0,0 +1,315 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" + + +#define PIPE "\\PIPE\\" +#define PIPELEN strlen(PIPE) + +extern int DEBUGLEVEL; +static int chain_pnum = -1; + +#ifndef MAX_OPEN_PIPES +#define MAX_OPEN_PIPES 50 +#endif + +#define PIPE_HANDLE_OFFSET 0x800 + +pipes_struct Pipes[MAX_OPEN_PIPES]; + +#define P_OPEN(p) ((p)->open) +#define P_OK(p,c) (P_OPEN(p) && (c)==((p)->cnum)) +#define VALID_PNUM(pnum) (((pnum) >= 0) && ((pnum) < MAX_OPEN_PIPES)) +#define OPEN_PNUM(pnum) (VALID_PNUM(pnum) && P_OPEN(&(Pipes[pnum]))) +#define PNUM_OK(pnum,c) (OPEN_PNUM(pnum) && (c)==Pipes[pnum].cnum) + + +/**************************************************************************** + reset pipe chain handle number +****************************************************************************/ +void reset_chain_pnum(void) +{ + chain_pnum = -1; +} + +/**************************************************************************** + sets chain pipe-file handle +****************************************************************************/ +void set_chain_pnum(int new_pnum) +{ + chain_pnum = new_pnum; +} + +/**************************************************************************** + initialise pipe handle states... +****************************************************************************/ +void init_rpc_pipe_hnd(void) +{ + int i; + /* we start at 1 here for an obscure reason I can't now remember, + but I think is important :-) */ + for (i = 1; i < MAX_OPEN_PIPES; i++) + { + Pipes[i].open = False; + Pipes[i].name[0] = 0; + Pipes[i].pipe_srv_name[0] = 0; + + Pipes[i].rhdr.data = NULL; + Pipes[i].rdata.data = NULL; + Pipes[i].rhdr.offset = 0; + Pipes[i].rdata.offset = 0; + + Pipes[i].max_rdata_len = 0; + Pipes[i].hdr_offsets = 0; + } + + return; +} + +/**************************************************************************** + find first available file slot +****************************************************************************/ +int open_rpc_pipe_hnd(char *pipe_name, int cnum, uint16 vuid) +{ + int i; + /* we start at 1 here for an obscure reason I can't now remember, + but I think is important :-) */ + for (i = 1; i < MAX_OPEN_PIPES; i++) + { + if (!Pipes[i].open) + { + Pipes[i].open = True; + Pipes[i].device_state = 0; + Pipes[i].cnum = cnum; + Pipes[i].uid = vuid; + + Pipes[i].rhdr.data = NULL; + Pipes[i].rdata.data = NULL; + Pipes[i].rhdr.offset = 0; + Pipes[i].rdata.offset = 0; + + Pipes[i].max_rdata_len = 0; + Pipes[i].hdr_offsets = 0; + + fstrcpy(Pipes[i].name, pipe_name); + + DEBUG(4,("Opened pipe %s with handle %x\n", + pipe_name, i + PIPE_HANDLE_OFFSET)); + + set_chain_pnum(i); + + return(i); + } + } + + DEBUG(1,("ERROR! Out of pipe structures - perhaps increase MAX_OPEN_PIPES?\n")); + + return(-1); +} + +/**************************************************************************** + reads data from a pipe. + + headers are interspersed with the data at regular intervals. by the time + this function is called, the start of the data could possibly have been + read by an SMBtrans (max_rdata_len != 0). + + calling create_rpc_request() here is a fudge. the data should already + have been prepared into arrays of headers + data stream sections. + + ****************************************************************************/ +int read_pipe(uint16 pnum, char *data, uint32 pos, int n) +{ + int data_pos = pos; + pipes_struct *p = &Pipes[pnum - PIPE_HANDLE_OFFSET]; + DEBUG(6,("read_pipe: %x", pnum)); + + if (VALID_PNUM(pnum - PIPE_HANDLE_OFFSET)) + { + DEBUG(6,("name: %s cnum: %d open: %s data_pos: %lx len: %lx", + p->name, + p->cnum, + BOOLSTR(p->open), + data_pos, n)); + } + + if (OPEN_PNUM(pnum - PIPE_HANDLE_OFFSET)) + { + int num; + int len; + uint32 rpc_frag_pos; + + DEBUG(6,("OK\n")); + + if (p->rhdr.data == NULL || p->rhdr.data->data == NULL || + p->rhdr.data->data_used == 0) + { + return 0; + } + + /* the read request starts from where the SMBtrans2 left off. */ + data_pos += p->max_rdata_len; + + /* headers accumulate an offset */ + data_pos -= p->hdr_offsets; + + len = mem_buf_len(p->rhdr.data); + num = len - (int)data_pos; + + if (num > n) num = n; + + if (!IS_BITS_SET_ALL(p->hdr.flags, RPC_FLG_LAST)) + { + rpc_frag_pos = data_pos % p->hdr.frag_len; + + if (rpc_frag_pos == 0) + { + /* create and copy in a new header. */ + create_rpc_reply(p, data_pos, p->rdata.offset); + mem_buf_copy(data, p->rhdr.data, 0, 0x18); + + /* make room in data stream for header */ + p->hdr_offsets += 0x18; + } + } + + if (num > 0) + { + mem_buf_copy(data, p->rhdr.data, data_pos, num); + return num; + } + + return 0; + + } + else + { + DEBUG(6,("NOT\n")); + return -1; + } +} + +/**************************************************************************** + gets the name of a pipe +****************************************************************************/ +BOOL get_rpc_pipe(int pnum, pipes_struct **p) +{ + DEBUG(6,("get_rpc_pipe: ")); + + /* mapping is PIPE_HANDLE_OFFSET up... */ + + if (VALID_PNUM(pnum - PIPE_HANDLE_OFFSET)) + { + DEBUG(6,("name: %s cnum: %d open: %s ", + Pipes[pnum - PIPE_HANDLE_OFFSET].name, + Pipes[pnum - PIPE_HANDLE_OFFSET].cnum, + BOOLSTR(Pipes[pnum - PIPE_HANDLE_OFFSET].open))); + } + if (OPEN_PNUM(pnum - PIPE_HANDLE_OFFSET)) + { + DEBUG(6,("OK\n")); + (*p) = &(Pipes[pnum - PIPE_HANDLE_OFFSET]); + return True; + } + else + { + DEBUG(6,("NOT\n")); + return False; + } +} + +/**************************************************************************** + gets the name of a pipe +****************************************************************************/ +char *get_rpc_pipe_hnd_name(int pnum) +{ + pipes_struct *p = NULL; + get_rpc_pipe(pnum, &p); + return p != NULL ? p->name : NULL; +} + +/**************************************************************************** + set device state on a pipe. exactly what this is for is unknown... +****************************************************************************/ +BOOL set_rpc_pipe_hnd_state(pipes_struct *p, uint16 device_state) +{ + if (p == NULL) return False; + + if (P_OPEN(p)) + { + DEBUG(3,("%s Setting pipe device state=%x on pipe (name=%s cnum=%d)\n", + timestring(), device_state, p->name, p->cnum)); + + p->device_state = device_state; + + return True; + } + else + { + DEBUG(3,("%s Error setting pipe device state=%x (name=%s cnum=%d)\n", + timestring(), device_state, p->name, p->cnum)); + return False; + } +} + +/**************************************************************************** + close an rpc pipe +****************************************************************************/ +BOOL close_rpc_pipe_hnd(int pnum, int cnum) +{ + pipes_struct *p = NULL; + get_rpc_pipe(pnum, &p); + /* mapping is PIPE_HANDLE_OFFSET up... */ + + if (p != NULL && P_OK(p, cnum)) + { + DEBUG(3,("%s Closed pipe name %s pnum=%x cnum=%d\n", + timestring(),Pipes[pnum-PIPE_HANDLE_OFFSET].name, pnum,cnum)); + + p->open = False; + + p->rdata.offset = 0; + p->rhdr.offset = 0; + mem_buf_free(&(p->rdata.data)); + mem_buf_free(&(p->rhdr .data)); + + return True; + } + else + { + DEBUG(3,("%s Error closing pipe pnum=%x cnum=%d\n", + timestring(),pnum, cnum)); + return False; + } +} + +/**************************************************************************** + close an rpc pipe +****************************************************************************/ +int get_rpc_pipe_num(char *buf, int where) +{ + return (chain_pnum != -1 ? chain_pnum : SVAL(buf,where)); +} + diff --git a/source3/rpc_server/srv_reg.c b/source3/rpc_server/srv_reg.c new file mode 100644 index 0000000000..fa856f6983 --- /dev/null +++ b/source3/rpc_server/srv_reg.c @@ -0,0 +1,240 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + + +/******************************************************************* + reg_reply_unknown_1 + ********************************************************************/ +static void reg_reply_close(REG_Q_CLOSE *q_r, + prs_struct *rdata) +{ + REG_R_CLOSE r_u; + + /* set up the REG unknown_1 response */ + bzero(&(r_u.pol.data), POL_HND_SIZE); + + /* close the policy handle */ + if (close_lsa_policy_hnd(&(q_r->pol))) + { + r_u.status = 0; + } + else + { + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_INVALID; + } + + DEBUG(5,("reg_unknown_1: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + reg_io_r_close("", &r_u, rdata, 0); + + DEBUG(5,("reg_unknown_1: %d\n", __LINE__)); +} + +/******************************************************************* + api_reg_close + ********************************************************************/ +static void api_reg_close( int uid, prs_struct *data, + prs_struct *rdata ) +{ + REG_Q_CLOSE q_r; + + /* grab the reg unknown 1 */ + reg_io_q_close("", &q_r, data, 0); + + /* construct reply. always indicate success */ + reg_reply_close(&q_r, rdata); +} + + +/******************************************************************* + reg_reply_open + ********************************************************************/ +static void reg_reply_open(REG_Q_OPEN_POLICY *q_r, + prs_struct *rdata) +{ + REG_R_OPEN_POLICY r_u; + + r_u.status = 0x0; + /* get a (unique) handle. open a policy on it. */ + if (r_u.status == 0x0 && !open_lsa_policy_hnd(&(r_u.pol))) + { + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + DEBUG(5,("reg_open: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + reg_io_r_open_policy("", &r_u, rdata, 0); + + DEBUG(5,("reg_open: %d\n", __LINE__)); +} + +/******************************************************************* + api_reg_open + ********************************************************************/ +static void api_reg_open( int uid, prs_struct *data, + prs_struct *rdata ) +{ + REG_Q_OPEN_POLICY q_u; + + /* grab the reg open */ + reg_io_q_open_policy("", &q_u, data, 0); + + /* construct reply. always indicate success */ + reg_reply_open(&q_u, rdata); +} + + +/******************************************************************* + reg_reply_open_entry + ********************************************************************/ +static void reg_reply_open_entry(REG_Q_OPEN_ENTRY *q_u, + prs_struct *rdata) +{ + uint32 status = 0; + POLICY_HND pol; + REG_R_OPEN_ENTRY r_u; + fstring name; + + DEBUG(5,("reg_open_entry: %d\n", __LINE__)); + + if (status == 0 && find_lsa_policy_by_hnd(&(q_u->pol)) == -1) + { + status = 0xC000000 | NT_STATUS_INVALID_HANDLE; + } + + if (status == 0x0 && !open_lsa_policy_hnd(&pol)) + { + status = 0xC000000 | NT_STATUS_TOO_MANY_SECRETS; /* ha ha very droll */ + } + + fstrcpy(name, unistrn2(q_u->uni_name.buffer, q_u->uni_name.uni_str_len)); + + if (status == 0x0) + { + DEBUG(5,("reg_open_entry: %s\n", name)); + /* lkcl XXXX do a check on the name, here */ + } + + if (status == 0x0 && !set_lsa_policy_reg_name(&pol, name)) + { + status = 0xC000000 | NT_STATUS_TOO_MANY_SECRETS; /* ha ha very droll */ + } + + make_reg_r_open_entry(&r_u, &pol, status); + + /* store the response in the SMB stream */ + reg_io_r_open_entry("", &r_u, rdata, 0); + + DEBUG(5,("reg_open_entry: %d\n", __LINE__)); +} + +/******************************************************************* + api_reg_open_entry + ********************************************************************/ +static void api_reg_open_entry( int uid, prs_struct *data, + prs_struct *rdata ) +{ + REG_Q_OPEN_ENTRY q_u; + + /* grab the reg open entry */ + reg_io_q_open_entry("", &q_u, data, 0); + + /* construct reply. */ + reg_reply_open_entry(&q_u, rdata); +} + + +/******************************************************************* + reg_reply_info + ********************************************************************/ +static void reg_reply_info(REG_Q_INFO *q_u, + prs_struct *rdata) +{ + uint32 status = 0; + + REG_R_INFO r_u; + + DEBUG(5,("reg_info: %d\n", __LINE__)); + + if (status == 0 && find_lsa_policy_by_hnd(&(q_u->pol)) == -1) + { + status = 0xC000000 | NT_STATUS_INVALID_HANDLE; + } + + if (status == 0) + { + } + + make_reg_r_info(&r_u, 1, "LanmanNT", 0x12, 0x12, status); + + /* store the response in the SMB stream */ + reg_io_r_info("", &r_u, rdata, 0); + + DEBUG(5,("reg_open_entry: %d\n", __LINE__)); +} + +/******************************************************************* + api_reg_info + ********************************************************************/ +static void api_reg_info( int uid, prs_struct *data, + prs_struct *rdata ) +{ + REG_Q_INFO q_u; + + /* grab the reg unknown 0x11*/ + reg_io_q_info("", &q_u, data, 0); + + /* construct reply. always indicate success */ + reg_reply_info(&q_u, rdata); +} + + +/******************************************************************* + array of \PIPE\reg operations + ********************************************************************/ +static struct api_struct api_reg_cmds[] = +{ + { "REG_CLOSE" , REG_CLOSE , api_reg_close }, + { "REG_OPEN_ENTRY" , REG_OPEN_ENTRY , api_reg_open_entry }, + { "REG_OPEN" , REG_OPEN_POLICY , api_reg_open }, + { "REG_INFO" , REG_INFO , api_reg_info }, + { NULL, 0 , NULL } +}; + +/******************************************************************* + receives a reg pipe and responds. + ********************************************************************/ +BOOL api_reg_rpc(pipes_struct *p, prs_struct *data) +{ + return api_rpcTNP(p, "api_reg_rpc", api_reg_cmds, data); +} + diff --git a/source3/rpc_server/srv_samr.c b/source3/rpc_server/srv_samr.c new file mode 100644 index 0000000000..02c8cb0ffe --- /dev/null +++ b/source3/rpc_server/srv_samr.c @@ -0,0 +1,1352 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +extern BOOL sam_logon_in_ssb; +extern pstring samlogon_user; +extern rid_name domain_group_rids[]; +extern rid_name domain_alias_rids[]; + +/******************************************************************* + This next function should be replaced with something that + dynamically returns the correct user info..... JRA. + ********************************************************************/ + +static BOOL get_smbpwd_entries(SAM_USER_INFO_21 *pw_buf, + int *total_entries, int *num_entries, + int max_num_entries, + uint16 acb_mask) +{ + FILE *fp = NULL; + struct smb_passwd *pwd = NULL; + + (*num_entries) = 0; + (*total_entries) = 0; + + if (pw_buf == NULL) return False; + + fp = startsmbpwent(False); + if (!fp) + { + DEBUG(0, ("get_smbpwd_entries: Unable to open SMB password file.\n")); + return False; + } + + while (((pwd = getsmbpwent(fp)) != NULL) && (*num_entries) < max_num_entries) + { + int user_name_len = strlen(pwd->smb_name); + make_unistr2(&(pw_buf[(*num_entries)].uni_user_name), pwd->smb_name, user_name_len); + make_uni_hdr(&(pw_buf[(*num_entries)].hdr_user_name), user_name_len, + user_name_len, 1); + pw_buf[(*num_entries)].user_rid = pwd->smb_userid; + bzero( pw_buf[(*num_entries)].nt_pwd , 16); + + /* Now check if the NT compatible password is available. */ + if (pwd->smb_nt_passwd != NULL) + { + memcpy( pw_buf[(*num_entries)].nt_pwd , pwd->smb_nt_passwd, 16); + } + + pw_buf[(*num_entries)].acb_info = (uint16)pwd->acct_ctrl; + + DEBUG(5, ("get_smbpwd_entries: idx: %d user %s, uid %d, acb %x", + (*num_entries), pwd->smb_name, pwd->smb_userid, pwd->acct_ctrl)); + + if (acb_mask == 0 || IS_BITS_SET_SOME(pwd->acct_ctrl, acb_mask)) + { + DEBUG(5,(" acb_mask %x accepts\n", acb_mask)); + (*num_entries)++; + } + else + { + DEBUG(5,(" acb_mask %x rejects\n", acb_mask)); + } + + (*total_entries)++; + } + + endsmbpwent(fp); + + return (*num_entries) > 0; +} + +/******************************************************************* + samr_reply_unknown_1 + ********************************************************************/ +static void samr_reply_close_hnd(SAMR_Q_CLOSE_HND *q_u, + prs_struct *rdata) +{ + SAMR_R_CLOSE_HND r_u; + + /* set up the SAMR unknown_1 response */ + bzero(&(r_u.pol.data), POL_HND_SIZE); + + /* close the policy handle */ + if (close_lsa_policy_hnd(&(q_u->pol))) + { + r_u.status = 0; + } + else + { + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_INVALID; + } + + DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + samr_io_r_close_hnd("", &r_u, rdata, 0); + + DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_close_hnd + ********************************************************************/ +static void api_samr_close_hnd( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_CLOSE_HND q_u; + + /* grab the samr unknown 1 */ + samr_io_q_close_hnd("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_close_hnd(&q_u, rdata); +} + + +/******************************************************************* + samr_reply_open_domain + ********************************************************************/ +static void samr_reply_open_domain(SAMR_Q_OPEN_DOMAIN *q_u, + prs_struct *rdata) +{ + SAMR_R_OPEN_DOMAIN r_u; + BOOL pol_open = False; + int pol_idx; + + r_u.status = 0x0; + + /* find the connection policy handle. */ + if (r_u.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->connect_pol))) == -1)) + { + r_u.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + /* get a (unique) handle. open a policy on it. */ + if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.domain_pol)))) + { + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* associate the domain SID with the (unique) handle. */ + if (r_u.status == 0x0 && !set_lsa_policy_samr_sid(&(r_u.domain_pol), &(q_u->dom_sid.sid))) + { + /* oh, whoops. don't know what error message to return, here */ + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (r_u.status != 0 && pol_open) + { + close_lsa_policy_hnd(&(r_u.domain_pol)); + } + + DEBUG(5,("samr_open_domain: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + samr_io_r_open_domain("", &r_u, rdata, 0); + + DEBUG(5,("samr_open_domain: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_open_domain + ********************************************************************/ +static void api_samr_open_domain( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_OPEN_DOMAIN q_u; + + /* grab the samr open */ + samr_io_q_open_domain("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_open_domain(&q_u, rdata); +} + + +/******************************************************************* + samr_reply_unknown_3 + ********************************************************************/ +static void samr_reply_unknown_3(SAMR_Q_UNKNOWN_3 *q_u, + prs_struct *rdata) +{ + SAMR_R_UNKNOWN_3 r_u; + DOM_SID3 sid[MAX_SAM_SIDS]; + fstring user_sid; + fstring user_rid; + int pol_idx; + uint32 rid; + uint32 status; + + status = 0x0; + + /* find the policy handle. open a policy on it. */ + if (status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->user_pol))) == -1)) + { + status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + /* find the user's rid */ + if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->user_pol))) == 0xffffffff) + { + status = NT_STATUS_OBJECT_TYPE_MISMATCH; + } + + if (status == 0x0) + { + strcpy(user_sid, lp_domain_sid()); + sprintf(user_rid, "-%x", rid); + strcat(user_sid, user_rid); + + /* maybe need another 1 or 2 (S-1-5-20-0x220 and S-1-5-20-0x224) */ + /* these two are DOMAIN_ADMIN and DOMAIN_ACCT_OP group RIDs */ + make_dom_sid3(&(sid[0]), 0x035b, 0x0002, "S-1-1"); + make_dom_sid3(&(sid[1]), 0x0044, 0x0002, user_sid); + } + + make_samr_r_unknown_3(&r_u, + 0x0001, 0x8004, + 0x00000014, 0x0002, 0x0070, + 2, sid, status); + + DEBUG(5,("samr_unknown_3: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + samr_io_r_unknown_3("", &r_u, rdata, 0); + + DEBUG(5,("samr_unknown_3: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_unknown_3 + ********************************************************************/ +static void api_samr_unknown_3( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_UNKNOWN_3 q_u; + + /* grab the samr open */ + samr_io_q_unknown_3("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_unknown_3(&q_u, rdata); +} + + +/******************************************************************* + samr_reply_enum_dom_users + ********************************************************************/ +static void samr_reply_enum_dom_users(SAMR_Q_ENUM_DOM_USERS *q_u, + prs_struct *rdata) +{ + SAMR_R_ENUM_DOM_USERS r_e; + SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES]; + int num_entries; + int total_entries; + int pol_idx; + BOOL got_pwds; + + r_e.status = 0x0; + r_e.total_num_entries = 0; + + /* find the policy handle. open a policy on it. */ + if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)) + { + r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + DEBUG(5,("samr_reply_enum_dom_users: %d\n", __LINE__)); + + become_root(True); + got_pwds = get_smbpwd_entries(pass, &total_entries, &num_entries, MAX_SAM_ENTRIES, q_u->acb_mask); + unbecome_root(True); + + make_samr_r_enum_dom_users(&r_e, total_entries, + q_u->unknown_0, num_entries, + pass, r_e.status); + + /* store the response in the SMB stream */ + samr_io_r_enum_dom_users("", &r_e, rdata, 0); + + DEBUG(5,("samr_enum_dom_users: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_enum_dom_users + ********************************************************************/ +static void api_samr_enum_dom_users( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_ENUM_DOM_USERS q_e; + + /* grab the samr open */ + samr_io_q_enum_dom_users("", &q_e, data, 0); + + /* construct reply. */ + samr_reply_enum_dom_users(&q_e, rdata); +} + + +/******************************************************************* + samr_reply_enum_dom_groups + ********************************************************************/ +static void samr_reply_enum_dom_groups(SAMR_Q_ENUM_DOM_GROUPS *q_u, + prs_struct *rdata) +{ + SAMR_R_ENUM_DOM_GROUPS r_e; + SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES]; + int num_entries; + int pol_idx; + BOOL got_grps; + char *dummy_group = "Domain Admins"; + + r_e.status = 0x0; + r_e.num_entries = 0; + + /* find the policy handle. open a policy on it. */ + if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)) + { + r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + DEBUG(5,("samr_reply_enum_dom_groups: %d\n", __LINE__)); + + got_grps = True; + num_entries = 1; + make_unistr2(&(pass[0].uni_user_name), dummy_group, strlen(dummy_group)); + pass[0].user_rid = DOMAIN_GROUP_RID_ADMINS; + + if (r_e.status == 0 && got_grps) + { + make_samr_r_enum_dom_groups(&r_e, q_u->start_idx, num_entries, pass, r_e.status); + } + + /* store the response in the SMB stream */ + samr_io_r_enum_dom_groups("", &r_e, rdata, 0); + + DEBUG(5,("samr_enum_dom_groups: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_enum_dom_groups + ********************************************************************/ +static void api_samr_enum_dom_groups( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_ENUM_DOM_GROUPS q_e; + + /* grab the samr open */ + samr_io_q_enum_dom_groups("", &q_e, data, 0); + + /* construct reply. */ + samr_reply_enum_dom_groups(&q_e, rdata); +} + + +/******************************************************************* + samr_reply_enum_dom_aliases + ********************************************************************/ +static void samr_reply_enum_dom_aliases(SAMR_Q_ENUM_DOM_ALIASES *q_u, + prs_struct *rdata) +{ + SAMR_R_ENUM_DOM_ALIASES r_e; + SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES]; + int num_entries; + int pol_idx; + BOOL got_aliases; + char *dummy_alias = "admins"; + + r_e.status = 0x0; + r_e.num_entries = 0; + + /* find the policy handle. open a policy on it. */ + if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)) + { + r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + DEBUG(5,("samr_reply_enum_dom_aliases: %d\n", __LINE__)); + + got_aliases = True; + num_entries = 1; + make_unistr2(&(pass[0].uni_user_name), dummy_alias, strlen(dummy_alias)); + pass[0].user_rid = DOMAIN_ALIAS_RID_ADMINS; + + if (r_e.status == 0 && got_aliases) + { + make_samr_r_enum_dom_aliases(&r_e, num_entries, pass, r_e.status); + } + + /* store the response in the SMB stream */ + samr_io_r_enum_dom_aliases("", &r_e, rdata, 0); + + DEBUG(5,("samr_enum_dom_aliases: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_enum_dom_aliases + ********************************************************************/ +static void api_samr_enum_dom_aliases( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_ENUM_DOM_ALIASES q_e; + + /* grab the samr open */ + samr_io_q_enum_dom_aliases("", &q_e, data, 0); + + /* construct reply. */ + samr_reply_enum_dom_aliases(&q_e, rdata); +} + + +/******************************************************************* + samr_reply_query_dispinfo + ********************************************************************/ +static void samr_reply_query_dispinfo(SAMR_Q_QUERY_DISPINFO *q_u, + prs_struct *rdata) +{ + SAMR_R_QUERY_DISPINFO r_e; + SAM_INFO_CTR ctr; + SAM_INFO_1 info1; + SAM_INFO_2 info2; + SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES]; + int num_entries; + int total_entries; + int pol_idx; + BOOL got_pwds; + uint16 switch_level = 0x0; + + r_e.status = 0x0; + + /* find the policy handle. open a policy on it. */ + if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)) + { + r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + DEBUG(5,("samr_reply_query_dispinfo: %d\n", __LINE__)); + + become_root(True); + + got_pwds = get_smbpwd_entries(pass, &total_entries, &num_entries, MAX_SAM_ENTRIES, 0); + + unbecome_root(True); + + switch (q_u->switch_level) + { + case 0x1: + { + /* query disp info is for users */ + make_sam_info_1(&info1, ACB_NORMAL, + q_u->start_idx, num_entries, pass); + + ctr.sam.info1 = &info1; + switch_level = 0x1; + + break; + } + case 0x2: + { + /* query disp info is for servers */ + make_sam_info_2(&info2, ACB_WSTRUST, + q_u->start_idx, num_entries, pass); + + ctr.sam.info2 = &info2; + switch_level = 0x2; + + break; + } + } + + if (r_e.status == 0 && got_pwds) + { + make_samr_r_query_dispinfo(&r_e, switch_level, &ctr, r_e.status); + } + + /* store the response in the SMB stream */ + samr_io_r_query_dispinfo("", &r_e, rdata, 0); + + DEBUG(5,("samr_query_dispinfo: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_query_dispinfo + ********************************************************************/ +static void api_samr_query_dispinfo( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_QUERY_DISPINFO q_e; + + /* grab the samr open */ + samr_io_q_query_dispinfo("", &q_e, data, 0); + + /* construct reply. */ + samr_reply_query_dispinfo(&q_e, rdata); +} + + +/******************************************************************* + samr_reply_query_aliasinfo + ********************************************************************/ +static void samr_reply_query_aliasinfo(SAMR_Q_QUERY_ALIASINFO *q_u, + prs_struct *rdata) +{ + SAMR_R_QUERY_ALIASINFO r_e; + int pol_idx; + BOOL got_alias; + + r_e.status = 0x0; + r_e.ptr = 0; + + /* find the policy handle. open a policy on it. */ + if (r_e.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)) + { + r_e.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + DEBUG(5,("samr_reply_query_aliasinfo: %d\n", __LINE__)); + + if (r_e.status == 0x0) + { + if (q_u->switch_level != 3) + { + r_e.status = NT_STATUS_INVALID_INFO_CLASS; + } + } + + if (r_e.status == 0x0) + { + got_alias = True; + } + + make_samr_r_query_aliasinfo(&r_e, q_u->switch_level, + "<account description>", + r_e.status); + + /* store the response in the SMB stream */ + samr_io_r_query_aliasinfo("", &r_e, rdata, 0); + + DEBUG(5,("samr_query_aliasinfo: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_query_aliasinfo + ********************************************************************/ +static void api_samr_query_aliasinfo( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_QUERY_ALIASINFO q_e; + + /* grab the samr open */ + samr_io_q_query_aliasinfo("", &q_e, data, 0); + + /* construct reply. */ + samr_reply_query_aliasinfo(&q_e, rdata); +} + + +/******************************************************************* + samr_reply_lookup_ids + ********************************************************************/ +static void samr_reply_lookup_ids(SAMR_Q_LOOKUP_IDS *q_u, + prs_struct *rdata) +{ + uint32 rid[MAX_SAM_ENTRIES]; + uint32 status = 0; + int num_rids = q_u->num_sids1; + + SAMR_R_LOOKUP_IDS r_u; + + DEBUG(5,("samr_lookup_ids: %d\n", __LINE__)); + + if (num_rids > MAX_SAM_ENTRIES) + { + num_rids = MAX_SAM_ENTRIES; + DEBUG(5,("samr_lookup_ids: truncating entries to %d\n", num_rids)); + } + +#if 0 + int i; + for (i = 0; i < num_rids && status == 0; i++) + { + struct smb_passwd *smb_pass; + fstring user_name; + + fstrcpy(user_name, unistrn2(q_u->uni_user_name[i].buffer, + q_u->uni_user_name[i].uni_str_len)); + + /* find the user account */ + become_root(True); + smb_pass = get_smbpwd_entry(user_name, 0); + unbecome_root(True); + + if (smb_pass == NULL) + { + status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; + rid[i] = 0; + } + else + { + /* lkclXXXX SHOULD use name_to_rid() here! */ + rid[i] = smb_pass->smb_userid; + } + } +#endif + + num_rids = 1; + rid[0] = DOMAIN_ALIAS_RID_USERS; + + make_samr_r_lookup_ids(&r_u, num_rids, rid, status); + + /* store the response in the SMB stream */ + samr_io_r_lookup_ids("", &r_u, rdata, 0); + + DEBUG(5,("samr_lookup_ids: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_lookup_ids + ********************************************************************/ +static void api_samr_lookup_ids( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_LOOKUP_IDS q_u; + + /* grab the samr 0x10 */ + samr_io_q_lookup_ids("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_lookup_ids(&q_u, rdata); +} + +/******************************************************************* + samr_reply_lookup_names + ********************************************************************/ +static void samr_reply_lookup_names(SAMR_Q_LOOKUP_NAMES *q_u, + prs_struct *rdata) +{ + uint32 rid[MAX_SAM_ENTRIES]; + uint32 status = 0; + int i; + int num_rids = q_u->num_rids1; + + SAMR_R_LOOKUP_NAMES r_u; + + DEBUG(5,("samr_lookup_names: %d\n", __LINE__)); + + if (num_rids > MAX_SAM_ENTRIES) + { + num_rids = MAX_SAM_ENTRIES; + DEBUG(5,("samr_lookup_names: truncating entries to %d\n", num_rids)); + } + + for (i = 0; i < num_rids && status == 0; i++) + { + fstring name; + + status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + fstrcpy(name, unistrn2(q_u->uni_user_name[i].buffer, q_u->uni_user_name[i].uni_str_len)); + + status = (status != 0x0) ? lookup_user_rid (name, &(rid[i])) : status; + status = (status != 0x0) ? lookup_group_rid(name, &(rid[i])) : status; + status = (status != 0x0) ? lookup_alias_rid(name, &(rid[i])) : status; + } + + make_samr_r_lookup_names(&r_u, num_rids, rid, status); + + /* store the response in the SMB stream */ + samr_io_r_lookup_names("", &r_u, rdata, 0); + + DEBUG(5,("samr_lookup_names: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_lookup_names + ********************************************************************/ +static void api_samr_lookup_names( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_LOOKUP_NAMES q_u; + + /* grab the samr lookup names */ + samr_io_q_lookup_names("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_lookup_names(&q_u, rdata); +} + + +/******************************************************************* + samr_reply_unknown_12 + ********************************************************************/ +static void samr_reply_unknown_12(SAMR_Q_UNKNOWN_12 *q_u, + prs_struct *rdata) +{ + fstring group_names[MAX_SAM_ENTRIES]; + uint32 group_attrs[MAX_SAM_ENTRIES]; + uint32 status = 0; + int num_gids = q_u->num_gids1; + uint32 pol_idx; + + SAMR_R_UNKNOWN_12 r_u; + + DEBUG(5,("samr_unknown_12: %d\n", __LINE__)); + + /* find the policy handle. open a policy on it. */ + if (status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)) + { + status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + if (status == 0x0) + { + int i; + if (num_gids > MAX_SAM_ENTRIES) + { + num_gids = MAX_SAM_ENTRIES; + DEBUG(5,("samr_unknown_12: truncating entries to %d\n", num_gids)); + } + + for (i = 0; i < num_gids && status == 0; i++) + { + fstrcpy(group_names[i], "dummy group"); + group_attrs[i] = 0x2; + } + } + + make_samr_r_unknown_12(&r_u, num_gids, group_names, group_attrs, status); + + /* store the response in the SMB stream */ + samr_io_r_unknown_12("", &r_u, rdata, 0); + + DEBUG(5,("samr_unknown_12: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_unknown_12 + ********************************************************************/ +static void api_samr_unknown_12( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_UNKNOWN_12 q_u; + + /* grab the samr lookup names */ + samr_io_q_unknown_12("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_unknown_12(&q_u, rdata); +} + + +/******************************************************************* + samr_reply_open_user + ********************************************************************/ +static void samr_reply_open_user(SAMR_Q_OPEN_USER *q_u, + prs_struct *rdata, + int status) +{ + SAMR_R_OPEN_USER r_u; + struct smb_passwd *smb_pass; + int pol_idx; + BOOL pol_open = False; + + /* set up the SAMR open_user response */ + bzero(&(r_u.user_pol.data), POL_HND_SIZE); + + r_u.status = 0x0; + + /* find the policy handle. open a policy on it. */ + if (r_u.status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->domain_pol))) == -1)) + { + r_u.status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + /* get a (unique) handle. open a policy on it. */ + if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.user_pol)))) + { + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + become_root(True); + smb_pass = get_smbpwd_entry(NULL, q_u->user_rid); + unbecome_root(True); + + /* check that the RID exists in our domain. */ + if (r_u.status == 0x0 && smb_pass == NULL) + { + r_u.status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; + } + + /* associate the RID with the (unique) handle. */ + if (r_u.status == 0x0 && !set_lsa_policy_samr_rid(&(r_u.user_pol), q_u->user_rid)) + { + /* oh, whoops. don't know what error message to return, here */ + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (r_u.status != 0 && pol_open) + { + close_lsa_policy_hnd(&(r_u.user_pol)); + } + + DEBUG(5,("samr_open_user: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + samr_io_r_open_user("", &r_u, rdata, 0); + + DEBUG(5,("samr_open_user: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_open_user + ********************************************************************/ +static void api_samr_open_user( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_OPEN_USER q_u; + + /* grab the samr unknown 22 */ + samr_io_q_open_user("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_open_user(&q_u, rdata, 0x0); +} + + +/************************************************************************* + get_user_info_21 + *************************************************************************/ +static BOOL get_user_info_21(SAM_USER_INFO_21 *id21, uint32 rid) +{ + NTTIME dummy_time; + + pstring logon_script; + pstring profile_path; + pstring home_drive; + pstring home_dir; + pstring description; + pstring workstations; + pstring full_name; + pstring munged_dialin; + pstring unknown_str; + + uint32 r_uid; + uint32 r_gid; + + LOGON_HRS hrs; + int i; + + struct smb_passwd *smb_pass; + + become_root(True); + smb_pass = get_smbpwd_entry(NULL, rid); + unbecome_root(True); + + if (smb_pass == NULL) + { + return False; + } + + DEBUG(3,("User:[%s]\n", smb_pass->smb_name)); + + dummy_time.low = 0xffffffff; + dummy_time.high = 0x7fffffff; + + pstrcpy(samlogon_user, smb_pass->smb_name); + + if (samlogon_user[strlen(samlogon_user)-1] != '$') + { + if (!name_to_rid(samlogon_user, &r_uid, &r_gid)) + { + return False; + } + + /* XXXX hack to get standard_sub_basic() to use sam logon username */ + /* possibly a better way would be to do a become_user() call */ + sam_logon_in_ssb = True; + + pstrcpy(full_name , "<Full Name>"); + pstrcpy(logon_script , lp_logon_script ()); + pstrcpy(profile_path , lp_logon_path ()); + pstrcpy(home_drive , lp_logon_drive ()); + pstrcpy(home_dir , lp_logon_home ()); + pstrcpy(description , "<Description>"); + pstrcpy(workstations , ""); + pstrcpy(unknown_str , ""); + pstrcpy(munged_dialin, ""); + + sam_logon_in_ssb = False; + } + else + { + r_uid = smb_pass->smb_userid; + r_gid = DOMAIN_GROUP_RID_USERS; + + pstrcpy(samlogon_user, smb_pass->smb_name); + + pstrcpy(full_name , ""); + pstrcpy(logon_script , ""); + pstrcpy(profile_path , ""); + pstrcpy(home_drive , ""); + pstrcpy(home_dir , ""); + pstrcpy(description , ""); + pstrcpy(workstations , ""); + pstrcpy(unknown_str , ""); + pstrcpy(munged_dialin, ""); + } + + hrs.len = 21; + for (i = 0; i < hrs.len; i++) + { + hrs.hours[i] = 0xff; + } + make_sam_user_info21(id21, + + &dummy_time, /* logon_time */ + &dummy_time, /* logoff_time */ + &dummy_time, /* kickoff_time */ + &dummy_time, /* pass_last_set_time */ + &dummy_time, /* pass_can_change_time */ + &dummy_time, /* pass_must_change_time */ + + samlogon_user, /* user_name */ + full_name, /* full_name */ + home_dir, /* home_dir */ + home_drive, /* dir_drive */ + logon_script, /* logon_script */ + profile_path, /* profile_path */ + description, /* description */ + workstations, /* workstations user can log in from */ + unknown_str, /* don't know, yet */ + munged_dialin, /* dialin info. contains dialin path and tel no */ + + r_uid, /* RID user_id */ + r_gid, /* RID group_id */ + smb_pass->acct_ctrl, + + 0x00ffffff, /* unknown_3 */ + 168, /* divisions per week */ + &hrs, /* logon hours */ + 0x00020000, + 0x000004ec); + + return True; +} + +/******************************************************************* + samr_reply_query_userinfo + ********************************************************************/ +static void samr_reply_query_userinfo(SAMR_Q_QUERY_USERINFO *q_u, + prs_struct *rdata) +{ + SAMR_R_QUERY_USERINFO r_u; +#if 0 + SAM_USER_INFO_11 id11; +#endif + SAM_USER_INFO_21 id21; + void *info = NULL; + + uint32 status = 0x0; + uint32 rid; + int obj_idx; + + DEBUG(5,("samr_reply_query_userinfo: %d\n", __LINE__)); + + /* search for the handle */ + if (status == 0x0 && (obj_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1) + { + status = NT_STATUS_INVALID_HANDLE; + } + + /* find the user's rid */ + if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->pol))) == 0xffffffff) + { + status = NT_STATUS_OBJECT_TYPE_MISMATCH; + } + + /* ok! user info levels (there are lots: see MSDEV help), off we go... */ + if (status == 0x0) + { + switch (q_u->switch_value) + { +#if 0 +/* whoops - got this wrong. i think. or don't understand what's happening. */ + case 0x11: + { + NTTIME expire; + info = (void*)&id11; + + expire.low = 0xffffffff; + expire.high = 0x7fffffff; + + make_sam_user_info11(&id11, &expire, "BROOKFIELDS$", 0x03ef, 0x201, 0x0080); + + break; + } +#endif + case 21: + { + info = (void*)&id21; + status = get_user_info_21(&id21, rid) ? 0 : NT_STATUS_NO_SUCH_USER; + + break; + } + + default: + { + status = NT_STATUS_INVALID_INFO_CLASS; + + break; + } + } + } + + make_samr_r_query_userinfo(&r_u, q_u->switch_value, info, status); + + /* store the response in the SMB stream */ + samr_io_r_query_userinfo("", &r_u, rdata, 0); + + DEBUG(5,("samr_reply_query_userinfo: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_query_userinfo + ********************************************************************/ +static void api_samr_query_userinfo( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_QUERY_USERINFO q_u; + + /* grab the samr unknown 24 */ + samr_io_q_query_userinfo("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_query_userinfo(&q_u, rdata); +} + + +/******************************************************************* + samr_reply_query_usergroups + ********************************************************************/ +static void samr_reply_query_usergroups(SAMR_Q_QUERY_USERGROUPS *q_u, + prs_struct *rdata) +{ + SAMR_R_QUERY_USERGROUPS r_u; + uint32 status = 0x0; + + struct smb_passwd *smb_pass; + DOM_GID gids[LSA_MAX_GROUPS]; + int num_groups = 0; + int pol_idx; + uint32 rid; + + DEBUG(5,("samr_query_usergroups: %d\n", __LINE__)); + + /* find the policy handle. open a policy on it. */ + if (status == 0x0 && ((pol_idx = find_lsa_policy_by_hnd(&(q_u->pol))) == -1)) + { + status = 0xC0000000 | NT_STATUS_INVALID_HANDLE; + } + + /* find the user's rid */ + if (status == 0x0 && (rid = get_lsa_policy_samr_rid(&(q_u->pol))) == 0xffffffff) + { + status = NT_STATUS_OBJECT_TYPE_MISMATCH; + } + + if (status == 0x0) + { + become_root(True); + smb_pass = get_smbpwd_entry(NULL, rid); + unbecome_root(True); + + if (smb_pass == NULL) + { + status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; + } + } + + if (status == 0x0) + { + pstring groups; + get_domain_user_groups(groups, smb_pass->smb_name); + num_groups = make_dom_gids(groups, gids); + } + + /* construct the response. lkclXXXX: gids are not copied! */ + make_samr_r_query_usergroups(&r_u, num_groups, gids, status); + + /* store the response in the SMB stream */ + samr_io_r_query_usergroups("", &r_u, rdata, 0); + + DEBUG(5,("samr_query_usergroups: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_query_usergroups + ********************************************************************/ +static void api_samr_query_usergroups( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_QUERY_USERGROUPS q_u; + /* grab the samr unknown 32 */ + samr_io_q_query_usergroups("", &q_u, data, 0); + + /* construct reply. */ + samr_reply_query_usergroups(&q_u, rdata); +} + + +/******************************************************************* + samr_reply_unknown_32 + ********************************************************************/ +static void samr_reply_unknown_32(SAMR_Q_UNKNOWN_32 *q_u, + prs_struct *rdata, + int status) +{ + int i; + SAMR_R_UNKNOWN_32 r_u; + + /* set up the SAMR unknown_32 response */ + bzero(&(r_u.pol.data), POL_HND_SIZE); + if (status == 0) + { + for (i = 4; i < POL_HND_SIZE; i++) + { + r_u.pol.data[i] = i+1; + } + } + + make_dom_rid4(&(r_u.rid4), 0x0030, 0, 0); + r_u.status = status; + + DEBUG(5,("samr_unknown_32: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + samr_io_r_unknown_32("", &r_u, rdata, 0); + + DEBUG(5,("samr_unknown_32: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_unknown_32 + ********************************************************************/ +static void api_samr_unknown_32( int uid, prs_struct *data, prs_struct *rdata) +{ + uint32 status = 0; + struct smb_passwd *smb_pass; + fstring mach_acct; + + SAMR_Q_UNKNOWN_32 q_u; + + /* grab the samr unknown 32 */ + samr_io_q_unknown_32("", &q_u, data, 0); + + /* find the machine account: tell the caller if it exists. + lkclXXXX i have *no* idea if this is a problem or not + or even if you are supposed to construct a different + reply if the account already exists... + */ + + fstrcpy(mach_acct, unistrn2(q_u.uni_mach_acct.buffer, + q_u.uni_mach_acct.uni_str_len)); + + become_root(True); + smb_pass = get_smbpwd_entry(mach_acct, 0); + unbecome_root(True); + + if (smb_pass != NULL) + { + /* machine account exists: say so */ + status = 0xC0000000 | NT_STATUS_USER_EXISTS; + } + else + { + /* this could cause trouble... */ + status = 0; + } + + /* construct reply. */ + samr_reply_unknown_32(&q_u, rdata, status); +} + + +/******************************************************************* + samr_reply_connect + ********************************************************************/ +static void samr_reply_connect(SAMR_Q_CONNECT *q_u, + prs_struct *rdata) +{ + SAMR_R_CONNECT r_u; + BOOL pol_open = False; + + /* set up the SAMR connect response */ + + r_u.status = 0x0; + /* get a (unique) handle. open a policy on it. */ + if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.connect_pol)))) + { + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* associate the domain SID with the (unique) handle. */ + if (r_u.status == 0x0 && !set_lsa_policy_samr_pol_status(&(r_u.connect_pol), q_u->unknown_0)) + { + /* oh, whoops. don't know what error message to return, here */ + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (r_u.status != 0 && pol_open) + { + close_lsa_policy_hnd(&(r_u.connect_pol)); + } + + DEBUG(5,("samr_connect: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + samr_io_r_connect("", &r_u, rdata, 0); + + DEBUG(5,("samr_connect: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_connect + ********************************************************************/ +static void api_samr_connect( int uid, prs_struct *data, prs_struct *rdata) +{ + SAMR_Q_CONNECT q_u; + + /* grab the samr open policy */ + samr_io_q_connect("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_connect(&q_u, rdata); +} + +/******************************************************************* + samr_reply_open_alias + ********************************************************************/ +static void samr_reply_open_alias(SAMR_Q_OPEN_ALIAS *q_u, + prs_struct *rdata) +{ + SAMR_R_OPEN_ALIAS r_u; + BOOL pol_open = False; + + /* set up the SAMR open_alias response */ + + r_u.status = 0x0; + /* get a (unique) handle. open a policy on it. */ + if (r_u.status == 0x0 && !(pol_open = open_lsa_policy_hnd(&(r_u.pol)))) + { + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* associate a RID with the (unique) handle. */ + if (r_u.status == 0x0 && !set_lsa_policy_samr_rid(&(r_u.pol), q_u->rid_alias)) + { + /* oh, whoops. don't know what error message to return, here */ + r_u.status = 0xC0000000 | NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (r_u.status != 0 && pol_open) + { + close_lsa_policy_hnd(&(r_u.pol)); + } + + DEBUG(5,("samr_open_alias: %d\n", __LINE__)); + + /* store the response in the SMB stream */ + samr_io_r_open_alias("", &r_u, rdata, 0); + + DEBUG(5,("samr_open_alias: %d\n", __LINE__)); + +} + +/******************************************************************* + api_samr_open_alias + ********************************************************************/ +static void api_samr_open_alias( int uid, prs_struct *data, prs_struct *rdata) + +{ + SAMR_Q_OPEN_ALIAS q_u; + + /* grab the samr open policy */ + samr_io_q_open_alias("", &q_u, data, 0); + + /* construct reply. always indicate success */ + samr_reply_open_alias(&q_u, rdata); +} + +/******************************************************************* + array of \PIPE\samr operations + ********************************************************************/ +static struct api_struct api_samr_cmds [] = +{ + { "SAMR_CLOSE_HND" , SAMR_CLOSE_HND , api_samr_close_hnd }, + { "SAMR_CONNECT" , SAMR_CONNECT , api_samr_connect }, + { "SAMR_ENUM_DOM_USERS" , SAMR_ENUM_DOM_USERS , api_samr_enum_dom_users }, + { "SAMR_ENUM_DOM_GROUPS" , SAMR_ENUM_DOM_GROUPS , api_samr_enum_dom_groups }, + { "SAMR_ENUM_DOM_ALIASES" , SAMR_ENUM_DOM_ALIASES , api_samr_enum_dom_aliases }, + { "SAMR_LOOKUP_IDS" , SAMR_LOOKUP_IDS , api_samr_lookup_ids }, + { "SAMR_LOOKUP_NAMES" , SAMR_LOOKUP_NAMES , api_samr_lookup_names }, + { "SAMR_OPEN_USER" , SAMR_OPEN_USER , api_samr_open_user }, + { "SAMR_QUERY_USERINFO" , SAMR_QUERY_USERINFO , api_samr_query_userinfo }, + { "SAMR_QUERY_USERGROUPS" , SAMR_QUERY_USERGROUPS , api_samr_query_usergroups }, + { "SAMR_QUERY_DISPINFO" , SAMR_QUERY_DISPINFO , api_samr_query_dispinfo }, + { "SAMR_QUERY_ALIASINFO" , SAMR_QUERY_ALIASINFO , api_samr_query_aliasinfo }, + { "SAMR_0x32" , 0x32 , api_samr_unknown_32 }, + { "SAMR_UNKNOWN_12" , SAMR_UNKNOWN_12 , api_samr_unknown_12 }, + { "SAMR_OPEN_ALIAS" , SAMR_OPEN_ALIAS , api_samr_open_alias }, + { "SAMR_OPEN_DOMAIN" , SAMR_OPEN_DOMAIN , api_samr_open_domain }, + { "SAMR_UNKNOWN_3" , SAMR_UNKNOWN_3 , api_samr_unknown_3 }, + { NULL , 0 , NULL } +}; + +/******************************************************************* + receives a samr pipe and responds. + ********************************************************************/ +BOOL api_samr_rpc(pipes_struct *p, prs_struct *data) +{ + return api_rpcTNP(p, "api_samr_rpc", api_samr_cmds, data); +} + diff --git a/source3/rpc_server/srv_srvsvc.c b/source3/rpc_server/srv_srvsvc.c new file mode 100644 index 0000000000..285ea89657 --- /dev/null +++ b/source3/rpc_server/srv_srvsvc.c @@ -0,0 +1,1015 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + + +/******************************************************************* + fill in a share info level 1 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + see ipc.c:fill_share_info() + + ********************************************************************/ +static void make_srv_share_1_info(SH_INFO_1 *sh1, + SH_INFO_1_STR *str1, int snum) +{ + int len_net_name; + pstring net_name; + pstring remark; + uint32 type; + + pstrcpy(net_name, lp_servicename(snum)); + strupper(net_name); + pstrcpy(remark , lp_comment (snum)); + len_net_name = strlen(net_name); + + /* work out the share type */ + type = STYPE_DISKTREE; + + if (lp_print_ok(snum)) type = STYPE_PRINTQ; + if (strequal("IPC$", net_name)) type = STYPE_IPC; + if (net_name[len_net_name] == '$') type |= STYPE_HIDDEN; + + make_srv_share_info1 (sh1 , net_name, type, remark); + make_srv_share_info1_str(str1, net_name, remark); +} + +/******************************************************************* + fill in a share info level 1 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_share_info_1(SRV_SHARE_INFO_1 *sh1, uint32 *snum, uint32 *svcs) +{ + uint32 num_entries = 0; + (*svcs) = lp_numservices(); + + if (sh1 == NULL) + { + (*snum) = 0; + return; + } + + DEBUG(5,("make_srv_share_1_sh1\n")); + + for (; (*snum) < (*svcs) && num_entries < MAX_SHARE_ENTRIES; (*snum)++) + { + if (lp_browseable((*snum)) && lp_snum_ok((*snum))) + { + make_srv_share_1_info(&(sh1->info_1 [num_entries]), + &(sh1->info_1_str[num_entries]), (*snum)); + + /* move on to creating next share */ + num_entries++; + } + } + + sh1->num_entries_read = num_entries; + sh1->ptr_share_info = num_entries > 0 ? 1 : 0; + sh1->num_entries_read2 = num_entries; + + if ((*snum) >= (*svcs)) + { + (*snum) = 0; + } +} + +/******************************************************************* + fill in a share info level 2 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + see ipc.c:fill_share_info() + + ********************************************************************/ +static void make_srv_share_2_info(SH_INFO_2 *sh2, + SH_INFO_2_STR *str2, int snum) +{ + int len_net_name; + pstring net_name; + pstring remark; + pstring path; + pstring passwd; + uint32 type; + + pstrcpy(net_name, lp_servicename(snum)); + pstrcpy(remark , lp_comment (snum)); + pstrcpy(path , lp_pathname (snum)); + pstrcpy(passwd , ""); + len_net_name = strlen(net_name); + + /* work out the share type */ + type = STYPE_DISKTREE; + + if (lp_print_ok(snum)) type = STYPE_PRINTQ; + if (strequal("IPC$", net_name)) type = STYPE_IPC; + if (net_name[len_net_name] == '$') type |= STYPE_HIDDEN; + + make_srv_share_info2 (sh2 , net_name, type, remark, 0, 0xffffffff, 1, path, passwd); + make_srv_share_info2_str(str2, net_name, remark, path, passwd); +} + +/******************************************************************* + fill in a share info level 2 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_share_info_2(SRV_SHARE_INFO_2 *sh2, uint32 *snum, uint32 *svcs) +{ + uint32 num_entries = 0; + (*svcs) = lp_numservices(); + + if (sh2 == NULL) + { + (*snum) = 0; + return; + } + + DEBUG(5,("make_srv_share_2_sh1\n")); + + for (; (*snum) < (*svcs) && num_entries < MAX_SHARE_ENTRIES; (*snum)++) + { + if (lp_browseable((*snum)) && lp_snum_ok((*snum))) + { + make_srv_share_2_info(&(sh2->info_2 [num_entries]), + &(sh2->info_2_str[num_entries]), (*snum)); + + /* move on to creating next share */ + num_entries++; + } + } + + sh2->num_entries_read = num_entries; + sh2->ptr_share_info = num_entries > 0 ? 1 : 0; + sh2->num_entries_read2 = num_entries; + + if ((*snum) >= (*svcs)) + { + (*snum) = 0; + } +} + +/******************************************************************* + makes a SRV_R_NET_SHARE_ENUM structure. +********************************************************************/ +static uint32 make_srv_share_info_ctr(SRV_SHARE_INFO_CTR *ctr, + int switch_value, uint32 *resume_hnd, uint32 *total_entries) +{ + uint32 status = 0x0; + DEBUG(5,("make_srv_share_info_ctr: %d\n", __LINE__)); + + ctr->switch_value = switch_value; + + switch (switch_value) + { + case 1: + { + make_srv_share_info_1(&(ctr->share.info1), resume_hnd, total_entries); + ctr->ptr_share_ctr = 1; + break; + } + case 2: + { + make_srv_share_info_2(&(ctr->share.info2), resume_hnd, total_entries); + ctr->ptr_share_ctr = 2; + break; + } + default: + { + DEBUG(5,("make_srv_share_info_ctr: unsupported switch value %d\n", + switch_value)); + (*resume_hnd = 0); + (*total_entries) = 0; + ctr->ptr_share_ctr = 0; + status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + break; + } + } + + return status; +} + +/******************************************************************* + makes a SRV_R_NET_SHARE_ENUM structure. +********************************************************************/ +static void make_srv_r_net_share_enum(SRV_R_NET_SHARE_ENUM *r_n, + uint32 resume_hnd, int share_level, int switch_value) +{ + DEBUG(5,("make_srv_r_net_share_enum: %d\n", __LINE__)); + + r_n->share_level = share_level; + if (share_level == 0) + { + r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + } + else + { + r_n->status = make_srv_share_info_ctr(r_n->ctr, switch_value, &resume_hnd, &(r_n->total_entries)); + } + if (r_n->status != 0x0) + { + resume_hnd = 0; + } + make_enum_hnd(&(r_n->enum_hnd), resume_hnd); +} + +/******************************************************************* +net share enum +********************************************************************/ +static void srv_reply_net_share_enum(SRV_Q_NET_SHARE_ENUM *q_n, + prs_struct *rdata) +{ + SRV_R_NET_SHARE_ENUM r_n; + SRV_SHARE_INFO_CTR ctr; + + r_n.ctr = &ctr; + + DEBUG(5,("srv_net_share_enum: %d\n", __LINE__)); + + /* set up the */ + make_srv_r_net_share_enum(&r_n, + get_enum_hnd(&q_n->enum_hnd), + q_n->share_level, + q_n->ctr->switch_value); + + /* store the response in the SMB stream */ + srv_io_r_net_share_enum("", &r_n, rdata, 0); + + DEBUG(5,("srv_net_share_enum: %d\n", __LINE__)); +} + +/******************************************************************* + fill in a sess info level 1 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_sess_0_info(SESS_INFO_0 *se0, SESS_INFO_0_STR *str0, + char *name) +{ + make_srv_sess_info0 (se0 , name); + make_srv_sess_info0_str(str0, name); +} + +/******************************************************************* + fill in a sess info level 0 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_sess_info_0(SRV_SESS_INFO_0 *ss0, uint32 *snum, uint32 *stot) +{ + uint32 num_entries = 0; + (*stot) = 1; + + if (ss0 == NULL) + { + (*snum) = 0; + return; + } + + DEBUG(5,("make_srv_sess_0_ss0\n")); + + if (snum) + { + for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++) + { + make_srv_sess_0_info(&(ss0->info_0 [num_entries]), + &(ss0->info_0_str[num_entries]), "MACHINE"); + + /* move on to creating next session */ + /* move on to creating next sess */ + num_entries++; + } + + ss0->num_entries_read = num_entries; + ss0->ptr_sess_info = num_entries > 0 ? 1 : 0; + ss0->num_entries_read2 = num_entries; + + if ((*snum) >= (*stot)) + { + (*snum) = 0; + } + } + else + { + ss0->num_entries_read = 0; + ss0->ptr_sess_info = 0; + ss0->num_entries_read2 = 0; + } +} + +/******************************************************************* + fill in a sess info level 1 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_sess_1_info(SESS_INFO_1 *se1, SESS_INFO_1_STR *str1, + char *name, char *user, + uint32 num_opens, + uint32 open_time, uint32 idle_time, + uint32 usr_flgs) +{ + make_srv_sess_info1 (se1 , name, user, num_opens, open_time, idle_time, usr_flgs); + make_srv_sess_info1_str(str1, name, user); +} + +/******************************************************************* + fill in a sess info level 1 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_sess_info_1(SRV_SESS_INFO_1 *ss1, uint32 *snum, uint32 *stot) +{ + uint32 num_entries = 0; + (*stot) = 1; + + if (ss1 == NULL) + { + (*snum) = 0; + return; + } + + DEBUG(5,("make_srv_sess_1_ss1\n")); + + if (snum) + { + for (; (*snum) < (*stot) && num_entries < MAX_SESS_ENTRIES; (*snum)++) + { + make_srv_sess_1_info(&(ss1->info_1 [num_entries]), + &(ss1->info_1_str[num_entries]), + "MACHINE", "dummy_user", 1, 10, 5, 0); + + /* move on to creating next session */ + /* move on to creating next sess */ + num_entries++; + } + + ss1->num_entries_read = num_entries; + ss1->ptr_sess_info = num_entries > 0 ? 1 : 0; + ss1->num_entries_read2 = num_entries; + + if ((*snum) >= (*stot)) + { + (*snum) = 0; + } + } + else + { + ss1->num_entries_read = 0; + ss1->ptr_sess_info = 0; + ss1->num_entries_read2 = 0; + + (*stot) = 0; + } +} + +/******************************************************************* + makes a SRV_R_NET_SESS_ENUM structure. +********************************************************************/ +static uint32 make_srv_sess_info_ctr(SRV_SESS_INFO_CTR *ctr, + int switch_value, uint32 *resume_hnd, uint32 *total_entries) +{ + uint32 status = 0x0; + DEBUG(5,("make_srv_sess_info_ctr: %d\n", __LINE__)); + + ctr->switch_value = switch_value; + + switch (switch_value) + { + case 0: + { + make_srv_sess_info_0(&(ctr->sess.info0), resume_hnd, total_entries); + ctr->ptr_sess_ctr = 1; + break; + } + case 1: + { + make_srv_sess_info_1(&(ctr->sess.info1), resume_hnd, total_entries); + ctr->ptr_sess_ctr = 1; + break; + } + default: + { + DEBUG(5,("make_srv_sess_info_ctr: unsupported switch value %d\n", + switch_value)); + (*resume_hnd) = 0; + (*total_entries) = 0; + ctr->ptr_sess_ctr = 0; + status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + break; + } + } + + return status; +} + +/******************************************************************* + makes a SRV_R_NET_SESS_ENUM structure. +********************************************************************/ +static void make_srv_r_net_sess_enum(SRV_R_NET_SESS_ENUM *r_n, + uint32 resume_hnd, int sess_level, int switch_value) +{ + DEBUG(5,("make_srv_r_net_sess_enum: %d\n", __LINE__)); + + r_n->sess_level = sess_level; + if (sess_level == -1) + { + r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + } + else + { + r_n->status = make_srv_sess_info_ctr(r_n->ctr, switch_value, &resume_hnd, &r_n->total_entries); + } + if (r_n->status != 0x0) + { + resume_hnd = 0; + } + make_enum_hnd(&(r_n->enum_hnd), resume_hnd); +} + +/******************************************************************* +net sess enum +********************************************************************/ +static void srv_reply_net_sess_enum(SRV_Q_NET_SESS_ENUM *q_n, + prs_struct *rdata) +{ + SRV_R_NET_SESS_ENUM r_n; + SRV_SESS_INFO_CTR ctr; + + r_n.ctr = &ctr; + + DEBUG(5,("srv_net_sess_enum: %d\n", __LINE__)); + + /* set up the */ + make_srv_r_net_sess_enum(&r_n, + get_enum_hnd(&q_n->enum_hnd), + q_n->sess_level, + q_n->ctr->switch_value); + + /* store the response in the SMB stream */ + srv_io_r_net_sess_enum("", &r_n, rdata, 0); + + DEBUG(5,("srv_net_sess_enum: %d\n", __LINE__)); +} + +/******************************************************************* + fill in a conn info level 0 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_conn_info_0(SRV_CONN_INFO_0 *ss0, uint32 *snum, uint32 *stot) +{ + uint32 num_entries = 0; + (*stot) = 1; + + if (ss0 == NULL) + { + (*snum) = 0; + return; + } + + DEBUG(5,("make_srv_conn_0_ss0\n")); + + if (snum) + { + for (; (*snum) < (*stot) && num_entries < MAX_CONN_ENTRIES; (*snum)++) + { + make_srv_conn_info0(&(ss0->info_0 [num_entries]), (*stot)); + + /* move on to creating next connection */ + /* move on to creating next conn */ + num_entries++; + } + + ss0->num_entries_read = num_entries; + ss0->ptr_conn_info = num_entries > 0 ? 1 : 0; + ss0->num_entries_read2 = num_entries; + + + + if ((*snum) >= (*stot)) + { + (*snum) = 0; + } + } + else + { + ss0->num_entries_read = 0; + ss0->ptr_conn_info = 0; + ss0->num_entries_read2 = 0; + + (*stot) = 0; + } +} + +/******************************************************************* + fill in a conn info level 1 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_conn_1_info(CONN_INFO_1 *se1, CONN_INFO_1_STR *str1, + uint32 id, uint32 type, + uint32 num_opens, uint32 num_users, uint32 open_time, + char *usr_name, char *net_name) +{ + make_srv_conn_info1 (se1 , id, type, num_opens, num_users, open_time, usr_name, net_name); + make_srv_conn_info1_str(str1, usr_name, net_name); +} + +/******************************************************************* + fill in a conn info level 1 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_conn_info_1(SRV_CONN_INFO_1 *ss1, uint32 *snum, uint32 *stot) +{ + uint32 num_entries = 0; + (*stot) = 1; + + if (ss1 == NULL) + { + (*snum) = 0; + return; + } + + DEBUG(5,("make_srv_conn_1_ss1\n")); + + if (snum) + { + for (; (*snum) < (*stot) && num_entries < MAX_CONN_ENTRIES; (*snum)++) + { + make_srv_conn_1_info(&(ss1->info_1 [num_entries]), + &(ss1->info_1_str[num_entries]), + (*stot), 0x3, 1, 1, 3,"dummy_user", "IPC$"); + + /* move on to creating next connection */ + /* move on to creating next conn */ + num_entries++; + } + + ss1->num_entries_read = num_entries; + ss1->ptr_conn_info = num_entries > 0 ? 1 : 0; + ss1->num_entries_read2 = num_entries; + + + if ((*snum) >= (*stot)) + { + (*snum) = 0; + } + } + else + { + ss1->num_entries_read = 0; + ss1->ptr_conn_info = 0; + ss1->num_entries_read2 = 0; + + (*stot) = 0; + } +} + +/******************************************************************* + makes a SRV_R_NET_CONN_ENUM structure. +********************************************************************/ +static uint32 make_srv_conn_info_ctr(SRV_CONN_INFO_CTR *ctr, + int switch_value, uint32 *resume_hnd, uint32 *total_entries) +{ + uint32 status = 0x0; + DEBUG(5,("make_srv_conn_info_ctr: %d\n", __LINE__)); + + ctr->switch_value = switch_value; + + switch (switch_value) + { + case 0: + { + make_srv_conn_info_0(&(ctr->conn.info0), resume_hnd, total_entries); + ctr->ptr_conn_ctr = 1; + break; + } + case 1: + { + make_srv_conn_info_1(&(ctr->conn.info1), resume_hnd, total_entries); + ctr->ptr_conn_ctr = 1; + break; + } + default: + { + DEBUG(5,("make_srv_conn_info_ctr: unsupported switch value %d\n", + switch_value)); + (*resume_hnd = 0); + (*total_entries) = 0; + ctr->ptr_conn_ctr = 0; + status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + break; + } + } + + return status; +} + +/******************************************************************* + makes a SRV_R_NET_CONN_ENUM structure. +********************************************************************/ +static void make_srv_r_net_conn_enum(SRV_R_NET_CONN_ENUM *r_n, + uint32 resume_hnd, int conn_level, int switch_value) +{ + DEBUG(5,("make_srv_r_net_conn_enum: %d\n", __LINE__)); + + r_n->conn_level = conn_level; + if (conn_level == -1) + { + r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + } + else + { + r_n->status = make_srv_conn_info_ctr(r_n->ctr, switch_value, &resume_hnd, &r_n->total_entries); + } + if (r_n->status != 0x0) + { + resume_hnd = 0; + } + make_enum_hnd(&(r_n->enum_hnd), resume_hnd); +} + +/******************************************************************* +net conn enum +********************************************************************/ +static void srv_reply_net_conn_enum(SRV_Q_NET_CONN_ENUM *q_n, + prs_struct *rdata) +{ + SRV_R_NET_CONN_ENUM r_n; + SRV_CONN_INFO_CTR ctr; + + r_n.ctr = &ctr; + + DEBUG(5,("srv_net_conn_enum: %d\n", __LINE__)); + + /* set up the */ + make_srv_r_net_conn_enum(&r_n, + get_enum_hnd(&q_n->enum_hnd), + q_n->conn_level, + q_n->ctr->switch_value); + + /* store the response in the SMB stream */ + srv_io_r_net_conn_enum("", &r_n, rdata, 0); + + DEBUG(5,("srv_net_conn_enum: %d\n", __LINE__)); +} + +/******************************************************************* + fill in a file info level 3 structure. + ********************************************************************/ +static void make_srv_file_3_info(FILE_INFO_3 *fl3, FILE_INFO_3_STR *str3, + uint32 fnum, uint32 perms, uint32 num_locks, + char *path_name, char *user_name) +{ + make_srv_file_info3 (fl3 , fnum, perms, num_locks, path_name, user_name); + make_srv_file_info3_str(str3, path_name, user_name); +} + +/******************************************************************* + fill in a file info level 3 structure. + + this function breaks the rule that i'd like to be in place, namely + it doesn't receive its data as arguments: it has to call lp_xxxx() + functions itself. yuck. + + ********************************************************************/ +static void make_srv_file_info_3(SRV_FILE_INFO_3 *fl3, uint32 *fnum, uint32 *ftot) +{ + uint32 num_entries = 0; + (*ftot) = 1; + + if (fl3 == NULL) + { + (*fnum) = 0; + return; + } + + DEBUG(5,("make_srv_file_3_fl3\n")); + + for (; (*fnum) < (*ftot) && num_entries < MAX_FILE_ENTRIES; (*fnum)++) + { + make_srv_file_3_info(&(fl3->info_3 [num_entries]), + &(fl3->info_3_str[num_entries]), + (*fnum), 0x35, 0, "\\PIPE\\samr", "dummy user"); + + /* move on to creating next file */ + num_entries++; + } + + fl3->num_entries_read = num_entries; + fl3->ptr_file_info = num_entries > 0 ? 1 : 0; + fl3->num_entries_read2 = num_entries; + + if ((*fnum) >= (*ftot)) + { + (*fnum) = 0; + } +} + +/******************************************************************* + makes a SRV_R_NET_FILE_ENUM structure. +********************************************************************/ +static uint32 make_srv_file_info_ctr(SRV_FILE_INFO_CTR *ctr, + int switch_value, uint32 *resume_hnd, uint32 *total_entries) +{ + uint32 status = 0x0; + DEBUG(5,("make_srv_file_info_ctr: %d\n", __LINE__)); + + ctr->switch_value = switch_value; + + switch (switch_value) + { + case 3: + { + make_srv_file_info_3(&(ctr->file.info3), resume_hnd, total_entries); + ctr->ptr_file_ctr = 1; + break; + } + default: + { + DEBUG(5,("make_srv_file_info_ctr: unsupported switch value %d\n", + switch_value)); + (*resume_hnd = 0); + (*total_entries) = 0; + ctr->ptr_file_ctr = 0; + status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + break; + } + } + + return status; +} + +/******************************************************************* + makes a SRV_R_NET_FILE_ENUM structure. +********************************************************************/ +static void make_srv_r_net_file_enum(SRV_R_NET_FILE_ENUM *r_n, + uint32 resume_hnd, int file_level, int switch_value) +{ + DEBUG(5,("make_srv_r_net_file_enum: %d\n", __LINE__)); + + r_n->file_level = file_level; + if (file_level == 0) + { + r_n->status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + } + else + { + r_n->status = make_srv_file_info_ctr(r_n->ctr, switch_value, &resume_hnd, &(r_n->total_entries)); + } + if (r_n->status != 0x0) + { + resume_hnd = 0; + } + make_enum_hnd(&(r_n->enum_hnd), resume_hnd); +} + +/******************************************************************* +net file enum +********************************************************************/ +static void srv_reply_net_file_enum(SRV_Q_NET_FILE_ENUM *q_n, + prs_struct *rdata) +{ + SRV_R_NET_FILE_ENUM r_n; + SRV_FILE_INFO_CTR ctr; + + r_n.ctr = &ctr; + + DEBUG(5,("srv_net_file_enum: %d\n", __LINE__)); + + /* set up the */ + make_srv_r_net_file_enum(&r_n, + get_enum_hnd(&q_n->enum_hnd), + q_n->file_level, + q_n->ctr->switch_value); + + /* store the response in the SMB stream */ + srv_io_r_net_file_enum("", &r_n, rdata, 0); + + DEBUG(5,("srv_net_file_enum: %d\n", __LINE__)); +} + +/******************************************************************* +net server get info +********************************************************************/ +static void srv_reply_net_srv_get_info(SRV_Q_NET_SRV_GET_INFO *q_n, + prs_struct *rdata) +{ + SRV_R_NET_SRV_GET_INFO r_n; + uint32 status = 0x0; + SRV_INFO_CTR ctr; + + extern pstring myname; + get_myname(myname,NULL); + + DEBUG(5,("srv_net_srv_get_info: %d\n", __LINE__)); + + switch (q_n->switch_value) + { + case 102: + { + make_srv_info_102(&ctr.srv.sv102, + 500, myname, lp_serverstring(), + 5, 4, /* major/minor version - NT 5.4 :-) */ + 0x4100b, /* browsing stuff SV_TYPE_XXXX */ + 0xffffffff, /* users */ + 0xf, /* disc */ + 0, /* hidden */ + 240, /* announce */ + 3000, /* announce delta */ + 100000, /* licenses */ + "c:\\"); /* user path */ + break; + } + case 101: + { + make_srv_info_101(&ctr.srv.sv101, + 500, myname, + 5, 4, /* major/minor version - NT 5.4 :-) */ + 0x4100b, /* browsing stuff SV_TYPE_XXXX */ + lp_serverstring()); + break; + } + default: + { + status = 0xC0000000 | NT_STATUS_INVALID_INFO_CLASS; + break; + } + } + + /* set up the net server get info structure */ + make_srv_r_net_srv_get_info(&r_n, q_n->switch_value, &ctr, status); + + /* store the response in the SMB stream */ + srv_io_r_net_srv_get_info("", &r_n, rdata, 0); + + DEBUG(5,("srv_net_srv_get_info: %d\n", __LINE__)); +} + +/******************************************************************* +********************************************************************/ +static void api_srv_net_srv_get_info( int uid, prs_struct *data, + prs_struct *rdata ) +{ + SRV_Q_NET_SRV_GET_INFO q_n; + + /* grab the net server get info */ + srv_io_q_net_srv_get_info("", &q_n, data, 0); + + /* construct reply. always indicate success */ + srv_reply_net_srv_get_info(&q_n, rdata); +} + + +/******************************************************************* +********************************************************************/ +static void api_srv_net_file_enum( int uid, prs_struct *data, + prs_struct *rdata ) +{ + SRV_Q_NET_FILE_ENUM q_n; + SRV_FILE_INFO_CTR ctr; + + q_n.ctr = &ctr; + + /* grab the net file enum */ + srv_io_q_net_file_enum("", &q_n, data, 0); + + /* construct reply. always indicate success */ + srv_reply_net_file_enum(&q_n, rdata); +} + + +/******************************************************************* +********************************************************************/ +static void api_srv_net_conn_enum( int uid, prs_struct *data, + prs_struct *rdata ) +{ + SRV_Q_NET_CONN_ENUM q_n; + SRV_CONN_INFO_CTR ctr; + + q_n.ctr = &ctr; + + /* grab the net server get enum */ + srv_io_q_net_conn_enum("", &q_n, data, 0); + + /* construct reply. always indicate success */ + srv_reply_net_conn_enum(&q_n, rdata); +} + + +/******************************************************************* +********************************************************************/ +static void api_srv_net_sess_enum( int uid, prs_struct *data, + prs_struct *rdata ) +{ + SRV_Q_NET_SESS_ENUM q_n; + SRV_SESS_INFO_CTR ctr; + + q_n.ctr = &ctr; + + /* grab the net server get enum */ + srv_io_q_net_sess_enum("", &q_n, data, 0); + + /* construct reply. always indicate success */ + srv_reply_net_sess_enum(&q_n, rdata); +} + + +/******************************************************************* +********************************************************************/ +static void api_srv_net_share_enum( int uid, prs_struct *data, + prs_struct *rdata ) +{ + SRV_Q_NET_SHARE_ENUM q_n; + SRV_SHARE_INFO_CTR ctr; + + q_n.ctr = &ctr; + + /* grab the net server get enum */ + srv_io_q_net_share_enum("", &q_n, data, 0); + + /* construct reply. always indicate success */ + srv_reply_net_share_enum(&q_n, rdata); +} + + +/******************************************************************* +\PIPE\srvsvc commands +********************************************************************/ +struct api_struct api_srv_cmds[] = +{ + { "SRV_NETCONNENUM" , SRV_NETCONNENUM , api_srv_net_conn_enum }, + { "SRV_NETSESSENUM" , SRV_NETSESSENUM , api_srv_net_sess_enum }, + { "SRV_NETSHAREENUM" , SRV_NETSHAREENUM , api_srv_net_share_enum }, + { "SRV_NETFILEENUM" , SRV_NETFILEENUM , api_srv_net_file_enum }, + { "SRV_NET_SRV_GET_INFO", SRV_NET_SRV_GET_INFO, api_srv_net_srv_get_info }, + { NULL , 0 , NULL } +}; + +/******************************************************************* +receives a srvsvc pipe and responds. +********************************************************************/ +BOOL api_srvsvc_rpc(pipes_struct *p, prs_struct *data) +{ + return api_rpcTNP(p, "api_srvsvc_rpc", api_srv_cmds, data); +} + diff --git a/source3/rpc_server/srv_util.c b/source3/rpc_server/srv_util.c new file mode 100644 index 0000000000..7be259029a --- /dev/null +++ b/source3/rpc_server/srv_util.c @@ -0,0 +1,477 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1998 + * Copyright (C) Luke Kenneth Casson Leighton 1996-1998, + * Copyright (C) Paul Ashton 1997-1998. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* this module apparently provides an implementation of DCE/RPC over a + * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC + * documentation are available (in on-line form) from the X-Open group. + * + * this module should provide a level of abstraction between SMB + * and DCE/RPC, while minimising the amount of mallocs, unnecessary + * data copies, and network traffic. + * + * in this version, which takes a "let's learn what's going on and + * get something running" approach, there is additional network + * traffic generated, but the code should be easier to understand... + * + * ... if you read the docs. or stare at packets for weeks on end. + * + */ + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +/* array lookup of well-known RID aliases. the purpose of these escapes me.. */ +/* XXXX this structure should not have the well-known RID groups added to it, + i.e the DOMAIN_GROUP_RID_ADMIN/USER/GUEST. */ +rid_name domain_alias_rids[] = +{ + { DOMAIN_ALIAS_RID_ADMINS , "admins" }, + { DOMAIN_ALIAS_RID_USERS , "users" }, + { DOMAIN_ALIAS_RID_GUESTS , "guests" }, + { DOMAIN_ALIAS_RID_POWER_USERS , "power_users" }, + + { DOMAIN_ALIAS_RID_ACCOUNT_OPS , "account_ops" }, + { DOMAIN_ALIAS_RID_SYSTEM_OPS , "system_ops" }, + { DOMAIN_ALIAS_RID_PRINT_OPS , "print_ops" }, + { DOMAIN_ALIAS_RID_BACKUP_OPS , "backup_ops" }, + { DOMAIN_ALIAS_RID_REPLICATOR , "replicator" }, + { 0 , NULL } +}; + +/* array lookup of well-known Domain RID groups. */ +rid_name domain_group_rids[] = +{ + { DOMAIN_GROUP_RID_ADMINS , "domain admins" }, + { DOMAIN_GROUP_RID_USERS , "domain users" }, + { DOMAIN_GROUP_RID_GUESTS , "domain guests" }, + { 0 , NULL } +}; + + + +int make_dom_gids(char *gids_str, DOM_GID *gids) +{ + char *ptr; + pstring s2; + int count; + + DEBUG(4,("make_dom_gids: %s\n", gids_str)); + + if (gids_str == NULL || *gids_str == 0) return 0; + + for (count = 0, ptr = gids_str; next_token(&ptr, s2, NULL) && count < LSA_MAX_GROUPS; count++) + { + /* the entries are of the form GID/ATTR, ATTR being optional.*/ + char *attr; + uint32 rid = 0; + int i; + + attr = strchr(s2,'/'); + if (attr) *attr++ = 0; + if (!attr || !*attr) attr = "7"; /* default value for attribute is 7 */ + + /* look up the RID string and see if we can turn it into a rid number */ + for (i = 0; domain_alias_rids[i].name != NULL; i++) + { + if (strequal(domain_alias_rids[i].name, s2)) + { + rid = domain_alias_rids[i].rid; + break; + } + } + + if (rid == 0) rid = atoi(s2); + + if (rid == 0) + { + DEBUG(1,("make_dom_gids: unknown well-known alias RID %s/%s\n", + s2, attr)); + count--; + } + else + { + gids[count].g_rid = rid; + gids[count].attr = atoi(attr); + + DEBUG(5,("group id: %d attr: %d\n", + gids[count].g_rid, + gids[count].attr)); + } + } + + return count; +} + +/******************************************************************* + gets a domain user's groups + ********************************************************************/ +void get_domain_user_groups(char *domain_groups, char *user) +{ + pstring tmp; + + if (domain_groups == NULL || user == NULL) return; + + /* any additional groups this user is in. e.g power users */ + pstrcpy(domain_groups, lp_domain_groups()); + + /* can only be a user or a guest. cannot be guest _and_ admin */ + if (user_in_list(user, lp_domain_guest_users())) + { + sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_GUESTS); + strcat(domain_groups, tmp); + + DEBUG(3,("domain guest access %s granted\n", tmp)); + } + else + { + sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_USERS); + strcat(domain_groups, tmp); + + DEBUG(3,("domain user access %s granted\n", tmp)); + + if (user_in_list(user, lp_domain_admin_users())) + { + sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_ADMINS); + strcat(domain_groups, tmp); + + DEBUG(3,("domain admin access %s granted\n", tmp)); + } + } +} + + +/******************************************************************* + turns a DCE/RPC request into a DCE/RPC reply + + this is where the data really should be split up into an array of + headers and data sections. + + ********************************************************************/ +BOOL create_rpc_reply(pipes_struct *p, + uint32 data_start, uint32 data_end) +{ + mem_buf_init(&(p->rhdr.data), 0); + mem_alloc_data(p->rhdr.data, 0x18); + + p->rhdr.align = 4; + p->rhdr.io = False; + + p->hdr_rr.alloc_hint = data_end - data_start; /* calculate remaining data to be sent */ + p->hdr.pkt_type = RPC_RESPONSE; /* mark header as an rpc response */ + + /* set up rpc header (fragmentation issues) */ + if (data_start == 0) + { + p->hdr.flags = RPC_FLG_FIRST; + } + else + { + p->hdr.flags = 0; + } + + if (p->hdr_rr.alloc_hint + 0x18 <= p->hdr_ba.bba.max_tsize) + { + p->hdr.flags |= RPC_FLG_LAST; + p->hdr.frag_len = p->hdr_rr.alloc_hint + 0x18; + } + else + { + p->hdr.frag_len = p->hdr_ba.bba.max_tsize; + } + + p->rhdr.data->offset.start = 0; + p->rhdr.data->offset.end = 0x18; + + /* store the header in the data stream */ + p->rhdr.offset = 0; + smb_io_rpc_hdr ("hdr", &(p->hdr ), &(p->rhdr), 0); + smb_io_rpc_hdr_rr("rr" , &(p->hdr_rr), &(p->rhdr), 0); + + return p->rhdr.data != NULL && p->rhdr.offset == 0x18; +} + + +/******************************************************************* + receives a netlogon pipe and responds. + ********************************************************************/ +static BOOL api_rpc_command(pipes_struct *p, + char *rpc_name, struct api_struct *api_rpc_cmds, + prs_struct *data) +{ + int fn_num; + DEBUG(4,("api_rpc_command: %s op 0x%x - ", rpc_name, p->hdr_rr.opnum)); + + for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++) + { + if (api_rpc_cmds[fn_num].opnum == p->hdr_rr.opnum && api_rpc_cmds[fn_num].fn != NULL) + { + DEBUG(3,("api_rpc_command: %s\n", api_rpc_cmds[fn_num].name)); + break; + } + } + + if (api_rpc_cmds[fn_num].name == NULL) + { + DEBUG(4, ("unknown\n")); + return False; + } + + /* start off with 1024 bytes, and a large safety margin too */ + mem_buf_init(&(p->rdata.data), SAFETY_MARGIN); + mem_alloc_data(p->rdata.data, 1024); + + p->rdata.io = False; + p->rdata.align = 4; + + p->rdata.data->offset.start = 0; + p->rdata.data->offset.end = 0xffffffff; + + /* do the actual command */ + p->rdata.offset = 0; + api_rpc_cmds[fn_num].fn(p->uid, data, &(p->rdata)); + + if (p->rdata.data == NULL || p->rdata.offset == 0) + { + mem_free_data(p->rdata.data); + return False; + } + + mem_realloc_data(p->rdata.data, p->rdata.offset); + + DEBUG(10,("called %s\n", rpc_name)); + + return True; +} + + +/******************************************************************* + receives a netlogon pipe and responds. + ********************************************************************/ +BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, + prs_struct *data) +{ + if (data == NULL || data->data == NULL) + { + DEBUG(2,("%s: NULL data received\n", rpc_name)); + return False; + } + + /* read the rpc header */ + smb_io_rpc_hdr_rr("", &(p->hdr_rr), data, 0); + + /* interpret the command */ + if (!api_rpc_command(p, rpc_name, api_rpc_cmds, data)) + { + return False; + } + + /* create the rpc header */ + if (!create_rpc_reply(p, 0, p->rdata.offset)) + { + return False; + } + + /* set up the data chain */ + p->rhdr.data->offset.start = 0; + p->rhdr.data->offset.end = p->rhdr.offset; + p->rhdr.data->next = p->rdata.data; + + p->rdata.data->offset.start = p->rhdr.data->offset.end; + p->rdata.data->offset.end = p->rhdr.data->offset.end + p->rdata.offset; + p->rdata.data->next = NULL; + + return True; +} + +extern rid_name domain_group_rids[]; + +/******************************************************************* + lookup_group_name + ********************************************************************/ +uint32 lookup_group_name(uint32 rid, char *group_name, uint32 *type) +{ + int i = 0; + (*type) = SID_NAME_DOM_GRP; + + while (domain_group_rids[i].rid != rid && domain_group_rids[i].rid != 0) + { + i++; + } + + if (domain_group_rids[i].rid != 0) + { + fstrcpy(group_name, domain_group_rids[i].name); + return 0x0; + } + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +extern rid_name domain_alias_rids[]; + +/******************************************************************* + lookup_alias_name + ********************************************************************/ +uint32 lookup_alias_name(uint32 rid, char *alias_name, uint32 *type) +{ + int i = 0; + (*type) = SID_NAME_WKN_GRP; + + while (domain_alias_rids[i].rid != rid && domain_alias_rids[i].rid != 0) + { + i++; + } + + if (domain_alias_rids[i].rid != 0) + { + fstrcpy(alias_name, domain_alias_rids[i].name); + return 0x0; + } + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_user_name + ********************************************************************/ +uint32 lookup_user_name(uint32 rid, char *user_name, uint32 *type) +{ + struct smb_passwd *smb_pass; + (*type) = SID_NAME_USER; + + /* find the user account */ + become_root(True); + smb_pass = get_smbpwd_entry(NULL, rid); /* lkclXXXX SHOULD use rid mapping here! */ + unbecome_root(True); + + if (smb_pass != NULL) + { + fstrcpy(user_name, smb_pass->smb_name); + return 0x0; + } + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_group_rid + ********************************************************************/ +uint32 lookup_group_rid(char *group_name, uint32 *rid) +{ + char *grp_name; + int i = -1; /* start do loop at -1 */ + + do /* find, if it exists, a group rid for the group name*/ + { + i++; + (*rid) = domain_group_rids[i].rid; + grp_name = domain_group_rids[i].name; + + } while (grp_name != NULL && !strequal(grp_name, group_name)); + + return (grp_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_alias_rid + ********************************************************************/ +uint32 lookup_alias_rid(char *alias_name, uint32 *rid) +{ + char *als_name; + int i = -1; /* start do loop at -1 */ + + do /* find, if it exists, a alias rid for the alias name*/ + { + i++; + (*rid) = domain_alias_rids[i].rid; + als_name = domain_alias_rids[i].name; + + } while (als_name != NULL && !strequal(als_name, alias_name)); + + return (als_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_user_rid + ********************************************************************/ +uint32 lookup_user_rid(char *user_name, uint32 *rid) +{ + struct smb_passwd *smb_pass; + (*rid) = 0; + + /* find the user account */ + become_root(True); + smb_pass = get_smbpwd_entry(user_name, 0); + unbecome_root(True); + + if (smb_pass != NULL) + { + /* lkclXXXX SHOULD use name_to_rid() here! */ + (*rid) = smb_pass->smb_userid; + return 0x0; + } + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + Group and User RID username mapping function + ********************************************************************/ +BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid) +{ + struct passwd *pw = Get_Pwnam(user_name, False); + + if (u_rid == NULL || g_rid == NULL || user_name == NULL) + { + return False; + } + + if (!pw) + { + DEBUG(1,("Username %s is invalid on this system\n", user_name)); + return False; + } + + if (user_in_list(user_name, lp_domain_guest_users())) + { + *u_rid = DOMAIN_USER_RID_GUEST; + } + else if (user_in_list(user_name, lp_domain_admin_users())) + { + *u_rid = DOMAIN_USER_RID_ADMIN; + } + else + { + /* turn the unix UID into a Domain RID. this is what the posix + sub-system does (adds 1000 to the uid) */ + *u_rid = (uint32)(pw->pw_uid + 1000); + } + + /* absolutely no idea what to do about the unix GID to Domain RID mapping */ + *g_rid = (uint32)(pw->pw_gid + 1000); + + return True; +} diff --git a/source3/rpc_server/srv_wkssvc.c b/source3/rpc_server/srv_wkssvc.c new file mode 100644 index 0000000000..3dd273f784 --- /dev/null +++ b/source3/rpc_server/srv_wkssvc.c @@ -0,0 +1,113 @@ + +/* + * Unix SMB/Netbios implementation. + * Version 1.9. + * RPC Pipe client / server routines + * Copyright (C) Andrew Tridgell 1992-1997, + * Copyright (C) Luke Kenneth Casson Leighton 1996-1997, + * Copyright (C) Paul Ashton 1997. + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + + +/******************************************************************* + create_wks_info_100 + ********************************************************************/ +static void create_wks_info_100(WKS_INFO_100 *inf) +{ + extern pstring myname; + pstring my_name; + pstring domain; + + DEBUG(5,("create_wks_info_100: %d\n", __LINE__)); + + get_myname(myname, NULL); + pstrcpy (my_name, myname); + strupper(my_name); + + pstrcpy (domain , lp_workgroup()); + strupper(domain); + + make_wks_info_100(inf, + 0x000001f4, /* platform id info */ + lp_major_announce_version(), + lp_minor_announce_version(), + my_name, domain); +} + +/******************************************************************* + wks_reply_query_info + + only supports info level 100 at the moment. + + ********************************************************************/ +static void wks_reply_query_info(WKS_Q_QUERY_INFO *q_u, + prs_struct *rdata, + int status) +{ + WKS_R_QUERY_INFO r_u; + WKS_INFO_100 wks100; + + DEBUG(5,("wks_query_info: %d\n", __LINE__)); + + create_wks_info_100(&wks100); + make_wks_r_query_info(&r_u, q_u->switch_value, &wks100, status); + + /* store the response in the SMB stream */ + wks_io_r_query_info("", &r_u, rdata, 0); + + DEBUG(5,("wks_query_info: %d\n", __LINE__)); +} + +/******************************************************************* + api_wks_query_info + ********************************************************************/ +static void api_wks_query_info( int uid, prs_struct *data, + prs_struct *rdata ) +{ + WKS_Q_QUERY_INFO q_u; + + /* grab the net share enum */ + wks_io_q_query_info("", &q_u, data, 0); + + /* construct reply. always indicate success */ + wks_reply_query_info(&q_u, rdata, 0x0); +} + + +/******************************************************************* + \PIPE\wkssvc commands + ********************************************************************/ +struct api_struct api_wks_cmds[] = +{ + { "WKS_Q_QUERY_INFO", WKS_QUERY_INFO, api_wks_query_info }, + { NULL , 0 , NULL } +}; + +/******************************************************************* + receives a wkssvc pipe and responds. + ********************************************************************/ +BOOL api_wkssvc_rpc(pipes_struct *p, prs_struct *data) +{ + return api_rpcTNP(p, "api_wkssvc_rpc", api_wks_cmds, data); +} + |