summaryrefslogtreecommitdiff
path: root/source3/rpc_server
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>1998-03-11 21:11:04 +0000
committerJeremy Allison <jra@samba.org>1998-03-11 21:11:04 +0000
commitfdeea341ed1bae670382e45eb731db1b5838ad21 (patch)
treebdbc5138a9340bdbd5c12cee243e6acfb2e64daf /source3/rpc_server
parent4c6230afd2f144322c07c7e4c46147d3e5d2ddde (diff)
downloadsamba-fdeea341ed1bae670382e45eb731db1b5838ad21.tar.gz
samba-fdeea341ed1bae670382e45eb731db1b5838ad21.tar.bz2
samba-fdeea341ed1bae670382e45eb731db1b5838ad21.zip
"For I have laboured mightily on Luke's code, and hath broken
all I saw" - the book of Jeremy, chapter 1 :-). So here is the mega-merge of the NTDOM branch server code. It doesn't include the new client side pieces, we'll look at that later. This should give the same functionality, server wise, as the NTDOM branch does, only merged into the main branch. Any fixes to domain controler functionality should be added to the main branch, not the NTDOM branch. This code compiles without warnings on gcc2.8, but will need further testing before we are sure all the working functionality of the NTDOM server branch has been correctly carried over. I hereby declare the server side of the NTDOM branch dead (and all who sail in her :-). Jeremy. (This used to be commit 118ba4d77a33248e762a2cf843fb7cbc906ee6e7)
Diffstat (limited to 'source3/rpc_server')
-rw-r--r--source3/rpc_server/srv_lsa.c444
-rw-r--r--source3/rpc_server/srv_lsa_hnd.c316
-rw-r--r--source3/rpc_server/srv_netlog.c832
-rw-r--r--source3/rpc_server/srv_pipe_hnd.c315
-rw-r--r--source3/rpc_server/srv_reg.c240
-rw-r--r--source3/rpc_server/srv_samr.c1352
-rw-r--r--source3/rpc_server/srv_srvsvc.c1015
-rw-r--r--source3/rpc_server/srv_util.c477
-rw-r--r--source3/rpc_server/srv_wkssvc.c113
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);
+}
+