summaryrefslogtreecommitdiff
path: root/source/rpc_server/srv_samr_nt.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2001-02-17 00:54:58 +0000
committerJeremy Allison <jra@samba.org>2001-02-17 00:54:58 +0000
commit45e4bde098eceb79323fe29987c01be6dbbacda4 (patch)
treebb07c66fb0ee430c4b2f3515a6c0a3ea055e9ecd /source/rpc_server/srv_samr_nt.c
parent4c4c64c0296e8302f6f5841ee3726b5e6830a94f (diff)
downloadsamba-45e4bde098eceb79323fe29987c01be6dbbacda4.tar.gz
Getting ready to split samr into interface and implementation, as has
been done with spoolss. Changes will be made to lsa and spoolss also....... Jeremy.
Diffstat (limited to 'source/rpc_server/srv_samr_nt.c')
-rw-r--r--source/rpc_server/srv_samr_nt.c612
1 files changed, 612 insertions, 0 deletions
diff --git a/source/rpc_server/srv_samr_nt.c b/source/rpc_server/srv_samr_nt.c
new file mode 100644
index 00000000000..29ba76e2020
--- /dev/null
+++ b/source/rpc_server/srv_samr_nt.c
@@ -0,0 +1,612 @@
+/*
+ * 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.
+ * Copyright (C) Hewlett-Packard Company 1999.
+ * Copyright (C) Jeremy Allison 2001.
+ *
+ * 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;
+
+extern fstring global_myworkgroup;
+extern pstring global_myname;
+extern DOM_SID global_sam_sid;
+
+extern rid_name domain_group_rids[];
+extern rid_name domain_alias_rids[];
+extern rid_name builtin_alias_rids[];
+
+/*******************************************************************
+ This next function should be replaced with something that
+ dynamically returns the correct user info..... JRA.
+ ********************************************************************/
+
+static BOOL get_sampwd_entries(SAM_USER_INFO_21 *pw_buf, int start_idx,
+ int *total_entries, int *num_entries,
+ int max_num_entries, uint16 acb_mask)
+{
+ void *vp = NULL;
+ struct sam_passwd *pwd = NULL;
+
+ (*num_entries) = 0;
+ (*total_entries) = 0;
+
+ if (pw_buf == NULL)
+ return False;
+
+ vp = startsmbpwent(False);
+ if (!vp) {
+ DEBUG(0, ("get_sampwd_entries: Unable to open SMB password database.\n"));
+ return False;
+ }
+
+ while (((pwd = getsam21pwent(vp)) != NULL) && (*num_entries) < max_num_entries) {
+ int user_name_len;
+
+ if (start_idx > 0) {
+ /* skip the requested number of entries.
+ not very efficient, but hey...
+ */
+ start_idx--;
+ continue;
+ }
+
+ user_name_len = strlen(pwd->smb_name)+1;
+ init_unistr2(&(pw_buf[(*num_entries)].uni_user_name), pwd->smb_name, user_name_len);
+ init_uni_hdr(&(pw_buf[(*num_entries)].hdr_user_name), user_name_len);
+ pw_buf[(*num_entries)].user_rid = pwd->user_rid;
+ memset((char *)pw_buf[(*num_entries)].nt_pwd, '\0', 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, ("entry idx: %d user %s, rid 0x%x, acb %x",
+ (*num_entries), pwd->smb_name,
+ pwd->user_rid, pwd->acct_ctrl));
+
+ if (acb_mask == 0 || (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(vp);
+
+ return (*num_entries) > 0;
+}
+
+/*******************************************************************
+ This function uses the username map file and tries to map a UNIX
+ user name to an DOS name. (Sort of the reverse of the
+ map_username() function.) Since more than one DOS name can map
+ to the UNIX name, to reverse the mapping you have to specify
+ which corresponding DOS name you want; that's where the name_idx
+ parameter comes in. Returns the string requested or NULL if it
+ fails or can't complete the request for any reason. This doesn't
+ handle group names (starting with '@') or names starting with
+ '+' or '&'. If they are encountered, they are skipped.
+********************************************************************/
+
+static char *unmap_unixname(char *unix_user_name, int name_idx)
+{
+ char *mapfile = lp_username_map();
+ char **lines;
+ static pstring tok;
+ int i;
+
+ if (!*unix_user_name) return NULL;
+ if (!*mapfile) return NULL;
+
+ lines = file_lines_load(mapfile, NULL,False);
+ if (!lines) {
+ DEBUG(0,("unmap_unixname: can't open username map %s\n", mapfile));
+ return NULL;
+ }
+
+ DEBUG(5,("unmap_unixname: scanning username map %s, index: %d\n", mapfile, name_idx));
+
+ for (i=0; lines[i]; i++) {
+ char *unixname = lines[i];
+ char *dosname = strchr(unixname,'=');
+
+ if (!dosname)
+ continue;
+
+ *dosname++ = 0;
+
+ while (isspace(*unixname))
+ unixname++;
+ if ('!' == *unixname) {
+ unixname++;
+ while (*unixname && isspace(*unixname))
+ unixname++;
+ }
+
+ if (!*unixname || strchr("#;",*unixname))
+ continue;
+
+ if (strncmp(unixname, unix_user_name, strlen(unix_user_name)))
+ continue;
+
+ /* We have matched the UNIX user name */
+
+ while(next_token(&dosname, tok, LIST_SEP, sizeof(tok))) {
+ if (!strchr("@&+", *tok)) {
+ name_idx--;
+ if (name_idx < 0 ) {
+ break;
+ }
+ }
+ }
+
+ if (name_idx >= 0) {
+ DEBUG(0,("unmap_unixname: index too high - not that many DOS names\n"));
+ file_lines_free(lines);
+ return NULL;
+ } else {
+ file_lines_free(lines);
+ return tok;
+ }
+ }
+
+ DEBUG(0,("unmap_unixname: Couldn't find the UNIX user name\n"));
+ file_lines_free(lines);
+ return NULL;
+}
+
+/*******************************************************************
+ This function sets up a list of users taken from the list of
+ users that UNIX knows about, as well as all the user names that
+ Samba maps to a valid UNIX user name. (This should work with
+ /etc/passwd or NIS.)
+********************************************************************/
+
+static BOOL get_passwd_entries(SAM_USER_INFO_21 *pw_buf,
+ int start_idx,
+ int *total_entries, int *num_entries,
+ int max_num_entries,
+ uint16 acb_mask)
+{
+ static struct passwd *pwd = NULL;
+ static uint32 pw_rid;
+ static BOOL orig_done = False;
+ static int current_idx = 0;
+ static int mapped_idx = 0;
+ char *sep;
+
+ DEBUG(5, ("get_passwd_entries: retrieving a list of UNIX users\n"));
+
+ (*num_entries) = 0;
+ (*total_entries) = 0;
+
+ /* Skip all this stuff if we're in appliance mode */
+
+ if (lp_hide_local_users()) goto done;
+
+ if (pw_buf == NULL) return False;
+
+ if (current_idx == 0) {
+ sys_setpwent();
+ }
+
+ /* These two cases are inefficient, but should be called very rarely */
+ /* they are the cases where the starting index isn't picking up */
+ /* where we left off last time. It is efficient when it starts over */
+ /* at zero though. */
+ if (start_idx > current_idx) {
+ /* We aren't far enough; advance to start_idx */
+ while (current_idx < start_idx) {
+ char *unmap_name;
+
+ if(!orig_done) {
+ if ((pwd = sys_getpwent()) == NULL) break;
+ current_idx++;
+ orig_done = True;
+ }
+
+ while (((unmap_name = unmap_unixname(pwd->pw_name, mapped_idx)) != NULL) &&
+ (current_idx < start_idx)) {
+ current_idx++;
+ mapped_idx++;
+ }
+
+ if (unmap_name == NULL) {
+ orig_done = False;
+ mapped_idx = 0;
+ }
+ }
+ } else if (start_idx < current_idx) {
+ /* We are already too far; start over and advance to start_idx */
+ sys_endpwent();
+ sys_setpwent();
+ current_idx = 0;
+ mapped_idx = 0;
+ orig_done = False;
+ while (current_idx < start_idx) {
+ char *unmap_name;
+
+ if(!orig_done) {
+ if ((pwd = sys_getpwent()) == NULL) break;
+ current_idx++;
+ orig_done = True;
+ }
+
+ while (((unmap_name = unmap_unixname(pwd->pw_name, mapped_idx)) != NULL) &&
+ (current_idx < start_idx)) {
+ current_idx++;
+ mapped_idx++;
+ }
+
+ if (unmap_name == NULL) {
+ orig_done = False;
+ mapped_idx = 0;
+ }
+ }
+ }
+
+ sep = lp_winbind_separator();
+
+ /* now current_idx == start_idx */
+ while ((*num_entries) < max_num_entries) {
+ int user_name_len;
+ char *unmap_name;
+
+ /* This does the original UNIX user itself */
+ if(!orig_done) {
+ if ((pwd = sys_getpwent()) == NULL) break;
+
+ /* Don't enumerate winbind users as they are not local */
+
+ if (strchr(pwd->pw_name, *sep) != NULL) {
+ continue;
+ }
+
+ user_name_len = strlen(pwd->pw_name);
+
+ /* skip the trust account stored in the /etc/passwd file */
+ if (pwd->pw_name[user_name_len-1]=='$')
+ continue;
+
+ pw_rid = pdb_uid_to_user_rid(pwd->pw_uid);
+ ZERO_STRUCTP(&pw_buf[(*num_entries)]);
+ init_unistr2(&(pw_buf[(*num_entries)].uni_user_name), pwd->pw_name, user_name_len);
+ init_uni_hdr(&(pw_buf[(*num_entries)].hdr_user_name), user_name_len);
+ pw_buf[(*num_entries)].user_rid = pw_rid;
+ memset((char *)pw_buf[(*num_entries)].nt_pwd, '\0', 16);
+
+ pw_buf[(*num_entries)].acb_info = ACB_NORMAL;
+
+ DEBUG(5, ("get_passwd_entries: entry idx %d user %s, rid 0x%x\n", (*num_entries), pwd->pw_name, pw_rid));
+
+ (*num_entries)++;
+ (*total_entries)++;
+ current_idx++;
+ orig_done = True;
+ }
+
+ /* This does all the user names that map to the UNIX user */
+ while (((unmap_name = unmap_unixname(pwd->pw_name, mapped_idx)) != NULL) &&
+ (*num_entries < max_num_entries)) {
+ user_name_len = strlen(unmap_name);
+ ZERO_STRUCTP(&pw_buf[(*num_entries)]);
+ init_unistr2(&(pw_buf[(*num_entries)].uni_user_name), unmap_name, user_name_len);
+ init_uni_hdr(&(pw_buf[(*num_entries)].hdr_user_name), user_name_len);
+ pw_buf[(*num_entries)].user_rid = pw_rid;
+ memset((char *)pw_buf[(*num_entries)].nt_pwd, '\0', 16);
+
+ pw_buf[(*num_entries)].acb_info = ACB_NORMAL;
+
+ DEBUG(5, ("get_passwd_entries: entry idx %d user %s, rid 0x%x\n", (*num_entries), pwd->pw_name, pw_rid));
+
+ (*num_entries)++;
+ (*total_entries)++;
+ current_idx++;
+ mapped_idx++;
+ }
+
+ if (unmap_name == NULL) {
+ /* done with 'aliases', go on to next UNIX user */
+ orig_done = False;
+ mapped_idx = 0;
+ }
+ }
+
+ if (pwd == NULL) {
+ /* totally done, reset everything */
+ sys_endpwent();
+ current_idx = 0;
+ mapped_idx = 0;
+ }
+
+done:
+ return (*num_entries) > 0;
+}
+
+/*******************************************************************
+ _samr_close_hnd
+ ********************************************************************/
+
+uint32 _samr_close_hnd(pipes_struct *p, SAMR_Q_CLOSE_HND *q_u, SAMR_R_CLOSE_HND *r_u)
+{
+ /* close the policy handle */
+ if (!close_lsa_policy_hnd(&q_u->pol))
+ return NT_STATUS_OBJECT_NAME_INVALID;
+
+ DEBUG(5,("samr_reply_close_hnd: %d\n", __LINE__));
+
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/*******************************************************************
+ samr_reply_open_domain
+ ********************************************************************/
+
+uint32 _samr_open_domain(pipes_struct *p, SAMR_Q_OPEN_DOMAIN *q_u, SAMR_R_OPEN_DOMAIN *r_u)
+{
+ /* find the connection policy handle. */
+ if (find_lsa_policy_by_hnd(q_u->pol) == -1))
+ return NT_STATUS_INVALID_HANDLE;
+
+ /* get a (unique) handle. open a policy on it. */
+ if (!open_lsa_policy_hnd(&r_u->domain_pol))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ /* associate the domain SID with the (unique) handle. */
+ if (!set_lsa_policy_samr_sid(&r_u->domain_pol, &q_u->dom_sid.sid))
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+
+ close_lsa_policy_hnd(&r_u->domain_pol);
+
+ DEBUG(5,("samr_open_domain: %d\n", __LINE__));
+
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/*******************************************************************
+ _samr_get_usrdom_pwinfo
+ ********************************************************************/
+
+uint32 _samr_get_usrdom_pwinfo(pipes_struct *p, SAMR_Q_GET_USRDOM_PWINFO *q_u, SAMR_R_GET_USRDOM_PWINFO *r_u)
+{
+ /* find the policy handle. open a policy on it. */
+ if (find_lsa_policy_by_hnd(&q_u->user_pol) == -1)) {
+ return NT_STATUS_INVALID_HANDLE;
+ }
+
+ /* find the user's rid */
+ if (get_lsa_policy_samr_rid(&q_u->user_pol) == 0xffffffff)) {
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+ }
+
+ init_samr_r_get_usrdom_pwinfo(&r_u, NT_STATUS_NOPROBLEMO);
+
+ DEBUG(5,("_samr_get_usrdom_pwinfo: %d\n", __LINE__));
+
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/*******************************************************************
+ _samr_query_sec_obj
+ ********************************************************************/
+
+uint32 _samr_query_sec_obj(pipes_struct *p, SAMR_Q_QUERY_SEC_OBJ *q_u, SAMR_R_QUERY_SEC_OBJ *r_u)
+{
+ prs_struct *rdata = &p->out_data.rdata;
+ DOM_SID pol_sid;
+
+ /* find the policy handle. open a policy on it. */
+ if ((find_lsa_policy_by_hnd(&q_u->user_pol)) == -1))
+ return NT_STATUS_INVALID_HANDLE;
+
+HERE !!!
+
+ /* Get the SID. */
+ if (!get_lsa_policy_samr_sid(&q_u->user_pol, &pol_sid))
+ return NT_STATUS_OBJECT_TYPE_MISMATCH;
+
+ {
+ DOM_SID user_sid;
+ DOM_SID everyone_sid;
+
+ user_sid = global_sam_sid;
+
+ SMB_ASSERT_ARRAY(user_sid.sub_auths, user_sid.num_auths+1);
+
+ /*
+ * Add the user RID.
+ */
+ user_sid.sub_auths[user_sid.num_auths++] = rid;
+
+ string_to_sid(&everyone_sid, "S-1-1");
+
+ /* maybe need another 1 or 2 (S-1-5-0x20-0x220 and S-1-5-20-0x224) */
+ /* these two are DOMAIN_ADMIN and DOMAIN_ACCT_OP group RIDs */
+ init_dom_sid3(&(sid[0]), 0x035b, 0x0002, &everyone_sid);
+ init_dom_sid3(&(sid[1]), 0x0044, 0x0002, &user_sid);
+ }
+
+ init_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 */
+ if(!samr_io_r_unknown_3("", &r_u, rdata, 0))
+ return False;
+
+ DEBUG(5,("samr_unknown_3: %d\n", __LINE__));
+
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/*******************************************************************
+ samr_reply_enum_dom_users
+ ********************************************************************/
+
+static uint32 _samr_enum_dom_users(pipes_struct *p, SAMR_Q_ENUM_DOM_USERS *q_u, SAMR_R_ENUM_DOM_USERS *r_u)
+{
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries;
+ int total_entries;
+
+ r_u->total_num_entries = 0;
+
+ /* find the policy handle. open a policy on it. */
+ if (find_lsa_policy_by_hnd(&q_u->pol) == -1))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__));
+
+ become_root();
+ get_sampwd_entries(pass, 0, &total_entries, &num_entries, MAX_SAM_ENTRIES, q_u->acb_mask);
+ unbecome_root();
+
+ init_samr_r_enum_dom_users(r_u, total_entries,
+ q_u->unknown_0, num_entries,
+ pass, r_u->status);
+
+ DEBUG(5,("_samr_enum_dom_users: %d\n", __LINE__));
+
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/*******************************************************************
+ samr_reply_enum_dom_groups
+ ********************************************************************/
+
+static uint32 _samr_enum_dom_groups(pipes_struct *p, SAMR_Q_ENUM_DOM_GROUPS *q_u, SAMR_R_ENUM_DOM_GROUPS *r_u)
+{
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries;
+ BOOL got_grps;
+ char *dummy_group = "Domain Admins";
+
+ r_u->num_entries = 0;
+
+ /* find the policy handle. open a policy on it. */
+ if (find_lsa_policy_by_hnd(&q_u->pol) == -1))
+ return NT_STATUS_INVALID_HANDLE;
+
+ DEBUG(5,("samr_reply_enum_dom_groups: %d\n", __LINE__));
+
+ got_grps = True;
+ num_entries = 1;
+ ZERO_STRUCTP(&pass[0]);
+ init_unistr2(&pass[0].uni_user_name, dummy_group, strlen(dummy_group)+1);
+ pass[0].user_rid = DOMAIN_GROUP_RID_ADMINS;
+
+ if (got_grps)
+ init_samr_r_enum_dom_groups(r_u, q_u->start_idx, num_entries, pass, NT_STATUS_NOPROBLEMO);
+
+ DEBUG(5,("samr_enum_dom_groups: %d\n", __LINE__));
+
+ return NT_STATUS_NOPROBLEMO;
+}
+
+/*******************************************************************
+ samr_reply_enum_dom_aliases
+ ********************************************************************/
+
+static uint32 _samr_enum_dom_aliases(pipes_struct *p, SAMR_Q_ENUM_DOM_ALIASES *q_u, SAMR_R_ENUM_DOM_ALIASES *r_u)
+{
+ SAM_USER_INFO_21 pass[MAX_SAM_ENTRIES];
+ int num_entries = 0;
+ DOM_SID sid;
+ fstring sid_str;
+ fstring sam_sid_str;
+ struct group *grp;
+
+ /* find the policy handle. open a policy on it. */
+ if (!get_lsa_policy_samr_sid(&q_u->pol, &sid))
+ return NT_STATUS_INVALID_HANDLE;
+
+ sid_to_string(sid_str, &sid);
+ sid_to_string(sam_sid_str, &global_sam_sid);
+
+ DEBUG(5,("samr_reply_enum_dom_aliases: sid %s\n", sid_str));
+
+ /* well-known aliases */
+ if (strequal(sid_str, "S-1-5-32")) {
+ char *name;
+ while (!lp_hide_local_users() &&
+ num_entries < MAX_SAM_ENTRIES &&
+ ((name = builtin_alias_rids[num_entries].name) != NULL)) {
+ init_unistr2(&pass[num_entries].uni_user_name, name, strlen(name)+1);
+ pass[num_entries].user_rid = builtin_alias_rids[num_entries].rid;
+ num_entries++;
+ }
+ } else if (strequal(sid_str, sam_sid_str) && !lp_hide_local_users()) {
+ char *name;
+ char *sep;
+
+ sep = lp_winbind_separator();
+
+ /* local aliases */
+ /* we return the UNIX groups here. This seems to be the right */
+ /* thing to do, since NT member servers return their local */
+ /* groups in the same situation. */
+ setgrent();
+
+ while (num_entries < MAX_SAM_ENTRIES && ((grp = getgrent()) != NULL)) {
+ int i;
+ uint32 trid;
+ name = grp->gr_name;
+
+ /* Don't return winbind groups as they are not local! */
+
+ if (strchr(name, *sep) != NULL)
+ continue;
+
+ trid = pdb_gid_to_group_rid(grp->gr_gid);
+ for( i = 0; i < num_entries; i++)
+ if ( pass[i].user_rid == trid ) break;
+
+ if ( i < num_entries )
+ continue; /* rid was there, dup! */
+
+ init_unistr2(&(pass[num_entries].uni_user_name), name, strlen(name)+1);
+ pass[num_entries].user_rid = trid;
+ num_entries++;
+ }
+
+ endgrent();
+ }
+
+ init_samr_r_enum_dom_aliases(r_u, num_entries, pass, NT_STATUS_NOPROBLEMO);
+
+ DEBUG(5,("samr_enum_dom_aliases: %d\n", __LINE__));
+
+ return NT_STATUS_NOPROBLEMO;
+}
+