From 5b863af4c0179f0bee17e77690d99a54cc762531 Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Thu, 12 Nov 1998 16:07:00 +0000 Subject: cleaning up conflicts between group code not yet committed and changes from yesterday by me, jeremy and andrew. jeremy, your ACB_PWNOTREQ mod would have caused a crash if the user didn't exist (first check should be for smb_pass != NULL) (This used to be commit cbac0f165d351ba9497c222e55e453d781376e58) --- source3/Makefile.in | 3 +- source3/include/proto.h | 24 +- source3/rpc_client/cli_pipe.c | 2 +- source3/rpc_client/cli_reg.c | 54 ++- source3/rpc_server/srv_lookup.c | 710 ++++++++++++++++++++++++++++++++++++++ source3/rpc_server/srv_netlog.c | 6 +- source3/rpc_server/srv_pipe.c | 731 ++++++++++++++++++++++++++++++++++++++++ source3/rpc_server/srv_sid.c | 484 ++++++++++++++++++++++++++ source3/rpc_server/srv_util.c | 687 ------------------------------------- 9 files changed, 2000 insertions(+), 701 deletions(-) create mode 100644 source3/rpc_server/srv_lookup.c create mode 100644 source3/rpc_server/srv_pipe.c create mode 100644 source3/rpc_server/srv_sid.c (limited to 'source3') diff --git a/source3/Makefile.in b/source3/Makefile.in index 4dde76a60c..5ce12efa42 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -110,7 +110,8 @@ RPC_SERVER_OBJ = rpc_server/srv_lsa.o \ rpc_server/srv_lsa_hnd.o rpc_server/srv_netlog.o \ rpc_server/srv_pipe_hnd.o rpc_server/srv_reg.o \ rpc_server/srv_samr.o rpc_server/srv_srvsvc.o \ - rpc_server/srv_util.o rpc_server/srv_wkssvc.o + rpc_server/srv_util.o rpc_server/srv_wkssvc.o \ + rpc_server/srv_pipe.o RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_misc.o \ rpc_parse/parse_net.o rpc_parse/parse_prs.o \ diff --git a/source3/include/proto.h b/source3/include/proto.h index 2580491976..dc36273fc8 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -283,6 +283,7 @@ void zero_free(void *p, size_t size); int set_maxfiles(int requested_max); void reg_get_subkey(char *full_keyname, char *key_name, char *subkey_name); BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name); +BOOL become_user_permanently(uid_t uid, gid_t gid); /*The following definitions come from lib/util_file.c */ @@ -1325,6 +1326,8 @@ BOOL do_reg_query_key(struct cli_state *cli, POLICY_HND *hnd, BOOL do_reg_unknown_1a(struct cli_state *cli, POLICY_HND *hnd, uint32 *unk); BOOL do_reg_query_info(struct cli_state *cli, POLICY_HND *hnd, char *type, uint32 *unk_0, uint32 *unk_1); +BOOL do_reg_set_key_sec(struct cli_state *cli, POLICY_HND *hnd, + uint32 sec_buf_size, SEC_DESC *sec_buf); BOOL do_reg_get_key_sec(struct cli_state *cli, POLICY_HND *hnd, uint32 *sec_buf_size, SEC_DESC_BUF *sec_buf); BOOL do_reg_delete_val(struct cli_state *cli, POLICY_HND *hnd, char *val_name); @@ -1475,6 +1478,9 @@ void smb_io_strhdr(char *desc, STRHDR *hdr, prs_struct *ps, int depth); void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint32 buffer); void smb_io_unihdr(char *desc, UNIHDR *hdr, prs_struct *ps, int depth); void make_buf_hdr(BUFHDR *hdr, int max_len, int len); +void smb_io_hdrbuf_pre(char *desc, BUFHDR *hdr, prs_struct *ps, int depth, uint32 *offset); +void smb_io_hdrbuf_post(char *desc, BUFHDR *hdr, prs_struct *ps, int depth, + uint32 ptr_hdrbuf, uint32 start_offset); void smb_io_hdrbuf(char *desc, BUFHDR *hdr, prs_struct *ps, int depth); void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate); void smb_io_unihdr2(char *desc, UNIHDR2 *hdr2, prs_struct *ps, int depth); @@ -1663,6 +1669,10 @@ void reg_io_r_open_hku(char *desc, REG_R_OPEN_HKU *r_r, prs_struct *ps, int dep void make_reg_q_close(REG_Q_CLOSE *q_c, POLICY_HND *hnd); void reg_io_q_close(char *desc, REG_Q_CLOSE *q_u, prs_struct *ps, int depth); void reg_io_r_close(char *desc, REG_R_CLOSE *r_u, prs_struct *ps, int depth); +void make_reg_q_set_key_sec(REG_Q_SET_KEY_SEC *q_i, POLICY_HND *pol, + uint32 buf_len, SEC_DESC *sec_desc); +void reg_io_q_set_key_sec(char *desc, REG_Q_SET_KEY_SEC *r_q, prs_struct *ps, int depth); +void reg_io_r_set_key_sec(char *desc, REG_R_SET_KEY_SEC *r_q, prs_struct *ps, int depth); void make_reg_q_get_key_sec(REG_Q_GET_KEY_SEC *q_i, POLICY_HND *pol, uint32 buf_len, SEC_DESC_BUF *sec_buf); void reg_io_q_get_key_sec(char *desc, REG_Q_GET_KEY_SEC *r_q, prs_struct *ps, int depth); @@ -2047,6 +2057,14 @@ BOOL close_lsa_policy_hnd(POLICY_HND *hnd); BOOL api_netlog_rpc(pipes_struct *p, prs_struct *data); +/*The following definitions come from rpc_server/srv_pipe.c */ + +BOOL create_rpc_reply(pipes_struct *p, + uint32 data_start, uint32 data_end); +BOOL rpc_command(pipes_struct *p, prs_struct *pd); +BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, + prs_struct *data); + /*The following definitions come from rpc_server/srv_pipe_hnd.c */ void set_pipe_handle_offset(int max_open_files); @@ -2077,11 +2095,6 @@ BOOL api_srvsvc_rpc(pipes_struct *p, prs_struct *data); /*The following definitions come from rpc_server/srv_util.c */ int make_dom_gids(char *gids_str, DOM_GID **ppgids); -BOOL create_rpc_reply(pipes_struct *p, - uint32 data_start, uint32 data_end); -BOOL rpc_command(pipes_struct *p, prs_struct *pd); -BOOL api_rpcTNP(pipes_struct *p, char *rpc_name, struct api_struct *api_rpc_cmds, - prs_struct *data); void get_domain_user_groups(char *domain_groups, char *user); uint32 lookup_group_name(uint32 rid, char *group_name, uint32 *type); uint32 lookup_alias_name(uint32 rid, char *alias_name, uint32 *type); @@ -2667,5 +2680,4 @@ void status_page(void); /*The following definitions come from web/swat.c */ -BOOL become_user_permanently(uid_t uid, gid_t gid); #endif /* _PROTO_H_ */ diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index b899c6e08e..cb93f61b2d 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -130,7 +130,7 @@ static BOOL rpc_check_hdr(prs_struct *rdata, RPC_HDR *rhdr, (*last ) = IS_BITS_SET_ALL(rhdr->flags, RPC_FLG_LAST ); (*len ) = rhdr->frag_len - rdata->data->data_used; - return True; + return rhdr->pkt_type != RPC_FAULT; } static void NTLMSSPcalc_ap( struct cli_state *cli, unsigned char *data, int len) diff --git a/source3/rpc_client/cli_reg.c b/source3/rpc_client/cli_reg.c index 69982a8d44..5eccdc7826 100644 --- a/source3/rpc_client/cli_reg.c +++ b/source3/rpc_client/cli_reg.c @@ -3,9 +3,9 @@ * 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) 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 @@ -437,6 +437,54 @@ BOOL do_reg_query_info(struct cli_state *cli, POLICY_HND *hnd, return valid_query; } +/**************************************************************************** +do a REG Set Key Security +****************************************************************************/ +BOOL do_reg_set_key_sec(struct cli_state *cli, POLICY_HND *hnd, + uint32 sec_buf_size, SEC_DESC *sec_buf) +{ + prs_struct rbuf; + prs_struct buf; + REG_Q_SET_KEY_SEC q_o; + BOOL valid_query = False; + + if (hnd == NULL) return False; + + prs_init(&buf , 1024, 4, SAFETY_MARGIN, False); + prs_init(&rbuf, 0 , 4, SAFETY_MARGIN, True ); + + /* create and send a MSRPC command with api REG_SET_KEY_SEC */ + + DEBUG(4,("REG Set Key security.\n")); + + make_reg_q_set_key_sec(&q_o, hnd, sec_buf_size, sec_buf); + + /* turn parameters into data stream */ + reg_io_q_set_key_sec("", &q_o, &buf, 0); + + /* send the data on \PIPE\ */ + if (rpc_api_pipe_req(cli, REG_SET_KEY_SEC, &buf, &rbuf)) + { + REG_R_SET_KEY_SEC r_o; + BOOL p; + + ZERO_STRUCT(r_o); + + reg_io_r_set_key_sec("", &r_o, &rbuf, 0); + p = rbuf.offset != 0; + + if (p && r_o.status != 0) + { + valid_query = True; + } + } + + prs_mem_free(&rbuf); + prs_mem_free(&buf ); + + return valid_query; +} + /**************************************************************************** do a REG Query Key Security ****************************************************************************/ diff --git a/source3/rpc_server/srv_lookup.c b/source3/rpc_server/srv_lookup.c new file mode 100644 index 0000000000..e6df9933bf --- /dev/null +++ b/source3/rpc_server/srv_lookup.c @@ -0,0 +1,710 @@ + +/* + * 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 provides nt user / nt rid lookup functions. + users, local groups, domain groups. + + no unix / samba functions should be called in this module: + it should purely provide a gateway to the password database API, + the local group database API or the domain group database API, + but first checking built-in rids. + + did i say rids? oops, what about "S-1-1" the "Everyone" group + and other such well-known sids... + + speed is not of the essence: no particular optimisation is in place. + + * + * + */ + +#include "includes.h" +#include "nterr.h" + +extern int DEBUGLEVEL; + +extern fstring global_sam_name; +extern DOM_SID global_sam_sid; +extern DOM_SID global_sid_S_1_5_20; + +/* + * A list of the rids of well known BUILTIN and Domain users + * and groups. + */ + +rid_name builtin_alias_rids[] = +{ + { BUILTIN_ALIAS_RID_ADMINS , "Administrators" }, + { BUILTIN_ALIAS_RID_USERS , "Users" }, + { BUILTIN_ALIAS_RID_GUESTS , "Guests" }, + { BUILTIN_ALIAS_RID_POWER_USERS , "Power Users" }, + + { BUILTIN_ALIAS_RID_ACCOUNT_OPS , "Account Operators" }, + { BUILTIN_ALIAS_RID_SYSTEM_OPS , "System Operators" }, + { BUILTIN_ALIAS_RID_PRINT_OPS , "Print Operators" }, + { BUILTIN_ALIAS_RID_BACKUP_OPS , "Backup Operators" }, + { BUILTIN_ALIAS_RID_REPLICATOR , "Replicator" }, + { 0 , NULL } +}; + +/* array lookup of well-known Domain RID users. */ +rid_name domain_user_rids[] = +{ + { DOMAIN_USER_RID_ADMIN , "Administrator" }, + { DOMAIN_USER_RID_GUEST , "Guest" }, + { 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(DOMAIN_GRP *mem, int num_members, DOM_GID **ppgids) +{ + int count; + int i; + DOM_GID *gids = NULL; + + *ppgids = NULL; + + DEBUG(4,("make_dom_gids: %d\n", num_members)); + + if (mem == NULL || num_members == 0) + { + return 0; + } + + for (i = 0, count = 0; i < num_members && count < LSA_MAX_GROUPS; i++) + { + uint32 status; + + uint32 rid; + uint8 type; + + uint8 attr = mem[count].attr; + char *name = mem[count].name; + + become_root(True); + status = lookup_grp_rid(name, &rid, &type); + unbecome_root(True); + + if (status == 0x0) + { + gids = (DOM_GID *)Realloc( gids, sizeof(DOM_GID) * (count+1) ); + + if (gids == NULL) + { + DEBUG(0,("make_dom_gids: Realloc fail !\n")); + return 0; + } + + gids[count].g_rid = rid; + gids[count].attr = attr; + + DEBUG(5,("group name: %s rid: %d attr: %d\n", + name, rid, attr)); + count++; + } + else + { + DEBUG(1,("make_dom_gids: unknown group name %s\n", name)); + } + } + + *ppgids = gids; + return count; +} + +/******************************************************************* + gets a domain user's groups + ********************************************************************/ +int get_domain_user_groups(DOMAIN_GRP_MEMBER **grp_members, uint32 group_rid) +{ + DOMAIN_GRP *grp; + int num_mem; + + if (grp_members == NULL) return 0; + + grp = getgrouprid(group_rid, grp_members, &num_mem); + + if (grp == NULL) + { + return 0; + } + + return num_mem; +} + + +/******************************************************************* + lookup_builtin_names + ********************************************************************/ +uint32 lookup_builtin_names(uint32 rid, char *name, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_wk_user_name (rid, name, type) : status; + status = (status != 0x0) ? lookup_wk_group_name(rid, name, type) : status; + status = (status != 0x0) ? lookup_wk_alias_name(rid, name, type) : status; + + return status; +} + + +/******************************************************************* + lookup_added_name - names that have been added to the SAM database by admins. + ********************************************************************/ +uint32 lookup_added_name(uint32 rid, char *name, uint8 *type) +{ + uint32 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; + + return status; +} + + +/******************************************************************* + lookup_name + ********************************************************************/ +uint32 lookup_name(uint32 rid, char *name, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_builtin_names(rid, name, type) : status; + status = (status != 0x0) ? lookup_added_name (rid, name, type) : status; + + return status; +} + + +/******************************************************************* + lookup_wk_group_name + ********************************************************************/ +uint32 lookup_wk_group_name(uint32 rid, char *group_name, uint8 *type) +{ + int i = 0; + (*type) = SID_NAME_WKN_GRP; + + DEBUG(5,("lookup_wk_group_name: rid: %d", rid)); + + 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); + DEBUG(5,(" = %s\n", group_name)); + return 0x0; + } + + DEBUG(5,(" none mapped\n")); + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_group_name + ********************************************************************/ +uint32 lookup_group_name(uint32 rid, char *group_name, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + DOM_SID sid; + + DEBUG(5,("lookup_group_name: rid: 0x%x", rid)); + + sid_copy (&sid, &global_sam_sid); + sid_append_rid(&sid, rid); + + (*type) = SID_NAME_DOM_GRP; + + if (map_group_sid_to_name(&sid, group_name, NULL)) + { + status = 0x0; + } + + if (status == 0x0) + { + DEBUG(5,(" = %s\n", group_name)); + } + else + { + DEBUG(5,(" none mapped\n")); + } + + return status; +} + +/******************************************************************* + lookup_wk_alias_name + ********************************************************************/ +uint32 lookup_wk_alias_name(uint32 rid, char *alias_name, uint8 *type) +{ + int i = 0; + (*type) = SID_NAME_ALIAS; + + DEBUG(5,("lookup_wk_alias_name: rid: %d", rid)); + + while (builtin_alias_rids[i].rid != rid && builtin_alias_rids[i].rid != 0) + { + i++; + } + + if (builtin_alias_rids[i].rid != 0) + { + fstrcpy(alias_name, builtin_alias_rids[i].name); + DEBUG(5,(" = %s\n", alias_name)); + return 0x0; + } + + DEBUG(5,(" none mapped\n")); + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_alias_name + ********************************************************************/ +uint32 lookup_alias_name(uint32 rid, char *alias_name, uint8 *type) +{ + (*type) = SID_NAME_ALIAS; + + DEBUG(2,("lookup_alias_name: rid: %d\n", rid)); + DEBUG(2,(" NOT IMPLEMENTED\n")); + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup well-known user name + ********************************************************************/ +uint32 lookup_wk_user_name(uint32 rid, char *user_name, uint8 *type) +{ + int i = 0; + (*type) = SID_NAME_USER; + + DEBUG(5,("lookup_wk_user_name: rid: %d", rid)); + + /* look up the well-known domain user rids first */ + while (domain_user_rids[i].rid != rid && domain_user_rids[i].rid != 0) + { + i++; + } + + if (domain_user_rids[i].rid != 0) + { + fstrcpy(user_name, domain_user_rids[i].name); + DEBUG(5,(" = %s\n", user_name)); + return 0x0; + } + + DEBUG(5,(" none mapped\n")); + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup user name + ********************************************************************/ +uint32 lookup_user_name(uint32 rid, char *user_name, uint8 *type) +{ + struct sam_disp_info *disp_info; + (*type) = SID_NAME_USER; + + DEBUG(5,("lookup_user_name: rid: %d", rid)); + + /* find the user account */ + become_root(True); + disp_info = getsamdisprid(rid); + unbecome_root(True); + + if (disp_info != NULL) + { + fstrcpy(user_name, disp_info->smb_name); + DEBUG(5,(" = %s\n", user_name)); + return 0x0; + } + + DEBUG(5,(" none mapped\n")); + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_group_rid + ********************************************************************/ +uint32 lookup_group_rid(char *group_name, uint32 *rid, uint8 *type) +{ + DOM_SID sid; + + (*rid) = 0; + (*type) = SID_NAME_DOM_GRP; + + DEBUG(5,("lookup_group_rid: name: %s", group_name)); + + if (map_group_name_to_sid(group_name, &sid) && + sid_split_rid(&sid, rid) && + sid_equal(&sid, &global_sam_sid)) + { + DEBUG(5,(" = 0x%x\n", (*rid))); + return 0x0; + } + + DEBUG(5,(" none mapped\n")); + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_wk_group_rid + ********************************************************************/ +uint32 lookup_wk_group_rid(char *group_name, uint32 *rid, uint8 *type) +{ + char *grp_name; + int i = -1; /* start do loop at -1 */ + (*rid) = 0; + (*type) = SID_NAME_WKN_GRP; + + 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_sid + ********************************************************************/ +uint32 lookup_alias_sid(char *alias_name, DOM_SID *sid, uint8 *type) +{ + (*type) = SID_NAME_ALIAS; + + DEBUG(5,("lookup_alias_rid: name: %s", alias_name)); + + if (map_alias_name_to_sid(alias_name, sid)) + { + fstring sid_str; + sid_to_string(sid_str, sid); + DEBUG(5,(" = %s\n", sid_str)); + return 0x0; + } + + DEBUG(5,(" none mapped\n")); + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_alias_rid + ********************************************************************/ +uint32 lookup_alias_rid(char *alias_name, uint32 *rid, uint8 *type) +{ + DOM_SID sid; + + (*rid) = 0; + (*type) = SID_NAME_ALIAS; + + DEBUG(5,("lookup_alias_rid: name: %s", alias_name)); + + if (map_alias_name_to_sid(alias_name, &sid) && + sid_split_rid(&sid, rid) && + sid_equal(&sid, &global_sam_sid)) + { + DEBUG(5,(" = 0x%x\n", (*rid))); + return 0x0; + } + + DEBUG(5,(" none mapped\n")); + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_wk_alias_sid + ********************************************************************/ +uint32 lookup_wk_alias_sid(char *alias_name, DOM_SID *sid, uint8 *type) +{ + char *als_name; + int i = 0; + uint32 rid; + (*type) = SID_NAME_ALIAS; + + do /* find, if it exists, a alias rid for the alias name*/ + { + rid = builtin_alias_rids[i].rid; + als_name = builtin_alias_rids[i].name; + + i++; + + if (strequal(als_name, alias_name)) + { + sid_copy(sid, &global_sid_S_1_5_20); + sid_append_rid(sid, rid); + + return 0x0; + } + + } while (als_name != NULL); + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_wk_alias_rid + ********************************************************************/ +uint32 lookup_wk_alias_rid(char *alias_name, uint32 *rid, uint8 *type) +{ + char *als_name; + int i = -1; /* start do loop at -1 */ + (*rid) = 0; + (*type) = SID_NAME_ALIAS; + + do /* find, if it exists, a alias rid for the alias name*/ + { + i++; + (*rid) = builtin_alias_rids[i].rid; + als_name = builtin_alias_rids[i].name; + + } while (als_name != NULL && !strequal(als_name, alias_name)); + + return (als_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_sid + ********************************************************************/ +uint32 lookup_sid(char *name, DOM_SID *sid, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + fstring domain; + fstring user; + + split_domain_name(name, domain, user); + + if (!strequal(domain, global_sam_name)) + { + DEBUG(0,("lookup_sid: remote domain %s not supported\n", domain)); + return status; + } + + status = (status != 0x0) ? lookup_wk_alias_sid(user, sid, type) : status; + status = (status != 0x0) ? lookup_alias_sid (user, sid, type) : status; +#if 0 + status = (status != 0x0) ? lookup_domain_sid (user, sid, type) : status; +#endif + + return status; +} + +/******************************************************************* + lookup_added_user_rid + ********************************************************************/ +uint32 lookup_added_user_rids(char *user_name, + uint32 *usr_rid, uint32 *grp_rid) +{ + struct sam_passwd *sam_pass; + (*usr_rid) = 0; + (*grp_rid) = 0; + + /* find the user account */ + become_root(True); + sam_pass = getsam21pwnam(user_name); + unbecome_root(True); + + if (sam_pass != NULL) + { + (*usr_rid) = sam_pass->user_rid ; + (*grp_rid) = sam_pass->group_rid; + return 0x0; + } + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_added_user_rid + ********************************************************************/ +uint32 lookup_added_user_rid(char *user_name, uint32 *rid, uint8 *type) +{ + struct sam_passwd *sam_pass; + (*rid) = 0; + (*type) = SID_NAME_USER; + + /* find the user account */ + become_root(True); + sam_pass = getsam21pwnam(user_name); + unbecome_root(True); + + if (sam_pass != NULL) + { + (*rid) = sam_pass->user_rid; + return 0x0; + } + + return 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_wk_user_rid + ********************************************************************/ +uint32 lookup_wk_user_rid(char *user_name, uint32 *rid, uint8 *type) +{ + char *usr_name; + int i = -1; /* start do loop at -1 */ + (*rid) = 0; + (*type) = SID_NAME_USER; + + do /* find, if it exists, a alias rid for the alias name*/ + { + i++; + (*rid) = domain_user_rids[i].rid; + usr_name = domain_user_rids[i].name; + + } while (usr_name != NULL && !strequal(usr_name, user_name)); + + return (usr_name != NULL) ? 0 : 0xC0000000 | NT_STATUS_NONE_MAPPED; +} + +/******************************************************************* + lookup_added_grp_rid + ********************************************************************/ +uint32 lookup_added_grp_rid(char *name, uint32 *rid, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_group_rid(name, rid, type) : status; + status = (status != 0x0) ? lookup_alias_rid(name, rid, type) : status; + + return status; +} + +/******************************************************************* + lookup_builtin_grp_rid + ********************************************************************/ +uint32 lookup_builtin_grp_rid(char *name, uint32 *rid, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_wk_group_rid(name, rid, type) : status; + status = (status != 0x0) ? lookup_wk_alias_rid(name, rid, type) : status; + + return status; +} + +/******************************************************************* + lookup_grp_rid + ********************************************************************/ +uint32 lookup_grp_rid(char *name, uint32 *rid, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_builtin_grp_rid(name, rid, type) : status; + status = (status != 0x0) ? lookup_added_grp_rid (name, rid, type) : status; + + return status; +} + +/******************************************************************* + lookup_user_rid + ********************************************************************/ +uint32 lookup_user_rid(char *name, uint32 *rid, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_wk_user_rid (name, rid, type) : status; + status = (status != 0x0) ? lookup_added_user_rid(name, rid, type) : status; + + return status; +} + +/******************************************************************* + lookup_rid + ********************************************************************/ +uint32 lookup_rid(char *name, uint32 *rid, uint8 *type) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + + status = (status != 0x0) ? lookup_user_rid(name, rid, type) : status; + status = (status != 0x0) ? lookup_grp_rid (name, rid, type) : status; + + return status; +} + +/******************************************************************* + lookup_user_rids + ********************************************************************/ +uint32 lookup_user_rids(char *name, uint32 *usr_rid, uint32 *grp_rid) +{ + uint32 status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + uint8 type; + + /* + * try an ordinary user lookup + */ + + status = lookup_added_user_rids(name, usr_rid, grp_rid); + if (status == 0) + { + return status; + } + + /* + * hm. must be a well-known user, in a well-known group. + */ + + status = lookup_wk_user_rid(name, usr_rid, &type); + if (status != 0 || type != SID_NAME_USER) + { + return status; /* ok, maybe not! */ + } + if (type != SID_NAME_USER) + { + return 0xC0000000 | NT_STATUS_NONE_MAPPED; /* users only... */ + } + + /* + * ok, got the user rid: now try the group rid + */ + + status = lookup_builtin_grp_rid(name, grp_rid, &type); + if (type == SID_NAME_DOM_GRP || + type == SID_NAME_ALIAS || + type == SID_NAME_WKN_GRP) + { + status = 0xC0000000 | NT_STATUS_NONE_MAPPED; + } + + return status; +} diff --git a/source3/rpc_server/srv_netlog.c b/source3/rpc_server/srv_netlog.c index f93d09b3ba..04118800e2 100644 --- a/source3/rpc_server/srv_netlog.c +++ b/source3/rpc_server/srv_netlog.c @@ -673,10 +673,10 @@ static void api_net_sam_logon( uint16 vuid, smb_pass = getsmbpwnam(samlogon_user); unbecome_root(True); - if (smb_pass->acct_ctrl & ACB_PWNOTREQ) - status = 0; - else if (smb_pass == NULL) + if (smb_pass == NULL) status = 0xC0000000 | NT_STATUS_NO_SUCH_USER; + else if (smb_pass->acct_ctrl & ACB_PWNOTREQ) + status = 0; else if (smb_pass->acct_ctrl & ACB_DISABLED) status = 0xC0000000 | NT_STATUS_ACCOUNT_DISABLED; } diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c new file mode 100644 index 0000000000..94a7ebc838 --- /dev/null +++ b/source3/rpc_server/srv_pipe.c @@ -0,0 +1,731 @@ + +/* + * 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; + +static void NTLMSSPcalc_p( pipes_struct *p, unsigned char *data, int len) +{ + unsigned char *hash = p->ntlmssp_hash; + unsigned char index_i = hash[256]; + unsigned char index_j = hash[257]; + int ind; + + for( ind = 0; ind < len; ind++) + { + unsigned char tc; + unsigned char t; + + index_i++; + index_j += hash[index_i]; + + tc = hash[index_i]; + hash[index_i] = hash[index_j]; + hash[index_j] = tc; + + t = hash[index_i] + hash[index_j]; + data[ind] = data[ind] ^ hash[t]; + } + + hash[256] = index_i; + hash[257] = index_j; +} + +/******************************************************************* + 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) +{ + char *data; + BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SIGN); + BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SEAL); + uint32 data_len; + uint32 auth_len; + + DEBUG(5,("create_rpc_reply: data_start: %d data_end: %d max_tsize: %d\n", + data_start, data_end, p->hdr_ba.bba.max_tsize)); + + auth_len = p->hdr.auth_len; + + if (p->ntlmssp_auth) + { + DEBUG(10,("create_rpc_reply: auth\n")); + if (auth_len != 16) + { + return False; + } + } + + prs_init(&p->rhdr , 0x18, 4, 0, False); + prs_init(&p->rauth, 1024, 4, 0, False); + prs_init(&p->rverf, 0x08, 4, 0, False); + + 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; + } + + p->hdr_resp.alloc_hint = data_end - data_start; /* calculate remaining data to be sent */ + + if (p->hdr_resp.alloc_hint + 0x18 <= p->hdr_ba.bba.max_tsize) + { + p->hdr.flags |= RPC_FLG_LAST; + p->hdr.frag_len = p->hdr_resp.alloc_hint + 0x18; + } + else + { + p->hdr.frag_len = p->hdr_ba.bba.max_tsize; + } + + if (p->ntlmssp_auth) + { + p->hdr_resp.alloc_hint -= auth_len + 8; + } + + if (p->ntlmssp_auth) + { + data_len = p->hdr.frag_len - auth_len - (auth_verify ? 8 : 0) - 0x18; + } + else + { + data_len = p->hdr.frag_len - 0x18; + } + + p->rhdr.data->offset.start = 0; + p->rhdr.data->offset.end = 0x18; + + /* store the header in the data stream */ + smb_io_rpc_hdr ("hdr" , &(p->hdr ), &(p->rhdr), 0); + smb_io_rpc_hdr_resp("resp", &(p->hdr_resp), &(p->rhdr), 0); + + /* don't use rdata: use rdata_i instead, which moves... */ + /* make a pointer to the rdata data, NOT A COPY */ + + p->rdata_i.data = NULL; + prs_init(&p->rdata_i, 0, p->rdata.align, p->rdata.data->margin, p->rdata.io); + data = mem_data(&(p->rdata.data), data_start); + mem_create(p->rdata_i.data, data, 0, data_len, 0, False); + p->rdata_i.offset = data_len; + + if (auth_len > 0) + { + uint32 crc32; + + DEBUG(5,("create_rpc_reply: sign: %s seal: %s data %d auth %d\n", + BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len)); + + if (auth_seal) + { + crc32 = crc32_calc_buffer(data_len, data); + NTLMSSPcalc_p(p, (uchar*)data, data_len); + } + + if (auth_seal || auth_verify) + { + make_rpc_hdr_auth(&p->auth_info, 0x0a, 0x06, 0x08, (auth_verify ? 1 : 0)); + smb_io_rpc_hdr_auth("hdr_auth", &p->auth_info, &p->rauth, 0); + } + + if (auth_verify) + { + char *auth_data; + p->ntlmssp_seq_num++; + make_rpc_auth_ntlmssp_chk(&p->ntlmssp_chk, NTLMSSP_SIGN_VERSION, crc32, p->ntlmssp_seq_num++); + smb_io_rpc_auth_ntlmssp_chk("auth_sign", &(p->ntlmssp_chk), &p->rverf, 0); + auth_data = mem_data(&p->rverf.data, 4); + NTLMSSPcalc_p(p, (uchar*)auth_data, 12); + } + } + + /* set up the data chain */ + if (p->ntlmssp_auth) + { + prs_link(NULL , &p->rhdr , &p->rdata_i); + prs_link(&p->rhdr , &p->rdata_i, &p->rauth ); + prs_link(&p->rdata_i, &p->rauth , &p->rverf ); + prs_link(&p->rauth , &p->rverf , NULL ); + } + else + { + prs_link(NULL , &p->rhdr , &p->rdata_i); + prs_link(&p->rhdr, &p->rdata_i, NULL ); + } + + /* indicate to subsequent data reads where we are up to */ + p->frag_len_left = p->hdr.frag_len - p->file_offset; + p->next_frag_start = p->hdr.frag_len; + + return p->rhdr.data != NULL && p->rhdr.offset == 0x18; +} + +static BOOL api_pipe_ntlmssp_verify(pipes_struct *p) +{ + uchar lm_owf[24]; + uchar nt_owf[24]; + struct smb_passwd *smb_pass = NULL; + + DEBUG(5,("api_pipe_ntlmssp_verify: checking user details\n")); + + if (p->ntlmssp_resp.hdr_lm_resp.str_str_len == 0) return False; + if (p->ntlmssp_resp.hdr_nt_resp.str_str_len == 0) return False; + if (p->ntlmssp_resp.hdr_usr .str_str_len == 0) return False; + if (p->ntlmssp_resp.hdr_domain .str_str_len == 0) return False; + if (p->ntlmssp_resp.hdr_wks .str_str_len == 0) return False; + + memset(p->user_name, 0, sizeof(p->user_name)); + memset(p->domain , 0, sizeof(p->domain )); + memset(p->wks , 0, sizeof(p->wks )); + + if (IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_UNICODE)) + { + fstrcpy(p->user_name, unistrn2((uint16*)p->ntlmssp_resp.user , p->ntlmssp_resp.hdr_usr .str_str_len/2)); + fstrcpy(p->domain , unistrn2((uint16*)p->ntlmssp_resp.domain, p->ntlmssp_resp.hdr_domain.str_str_len/2)); + fstrcpy(p->wks , unistrn2((uint16*)p->ntlmssp_resp.wks , p->ntlmssp_resp.hdr_wks .str_str_len/2)); + } + else + { + fstrcpy(p->user_name, p->ntlmssp_resp.user ); + fstrcpy(p->domain , p->ntlmssp_resp.domain); + fstrcpy(p->wks , p->ntlmssp_resp.wks ); + } + + DEBUG(5,("user: %s domain: %s wks: %s\n", p->user_name, p->domain, p->wks)); + + memcpy(lm_owf, p->ntlmssp_resp.lm_resp, sizeof(lm_owf)); + memcpy(nt_owf, p->ntlmssp_resp.nt_resp, sizeof(nt_owf)); + +#ifdef DEBUG_PASSWORD + DEBUG(100,("lm, nt owfs, chal\n")); + dump_data(100, lm_owf, sizeof(lm_owf)); + dump_data(100, nt_owf, sizeof(nt_owf)); + dump_data(100, p->ntlmssp_chal.challenge, 8); +#endif + become_root(True); + p->ntlmssp_validated = pass_check_smb(p->user_name, p->domain, + (uchar*)p->ntlmssp_chal.challenge, + lm_owf, nt_owf, NULL); + smb_pass = getsmbpwnam(p->user_name); + unbecome_root(True); + + if (p->ntlmssp_validated && smb_pass != NULL && smb_pass->smb_passwd) + { + uchar p24[24]; + NTLMSSPOWFencrypt(smb_pass->smb_passwd, lm_owf, p24); + { + unsigned char j = 0; + int ind; + + unsigned char k2[8]; + + memcpy(k2, p24, 5); + k2[5] = 0xe5; + k2[6] = 0x38; + k2[7] = 0xb0; + + for (ind = 0; ind < 256; ind++) + { + p->ntlmssp_hash[ind] = (unsigned char)ind; + } + + for( ind = 0; ind < 256; ind++) + { + unsigned char tc; + + j += (p->ntlmssp_hash[ind] + k2[ind%8]); + + tc = p->ntlmssp_hash[ind]; + p->ntlmssp_hash[ind] = p->ntlmssp_hash[j]; + p->ntlmssp_hash[j] = tc; + } + + p->ntlmssp_hash[256] = 0; + p->ntlmssp_hash[257] = 0; + } +/* NTLMSSPhash(p->ntlmssp_hash, p24); */ + p->ntlmssp_seq_num = 0; + } + else + { + p->ntlmssp_validated = False; + } + + return p->ntlmssp_validated; +} + +static BOOL api_pipe_ntlmssp(pipes_struct *p, prs_struct *pd) +{ + /* receive a negotiate; send a challenge; receive a response */ + switch (p->auth_verifier.msg_type) + { + case NTLMSSP_NEGOTIATE: + { + smb_io_rpc_auth_ntlmssp_neg("", &p->ntlmssp_neg, pd, 0); + break; + } + case NTLMSSP_AUTH: + { + smb_io_rpc_auth_ntlmssp_resp("", &p->ntlmssp_resp, pd, 0); + if (!api_pipe_ntlmssp_verify(p)) + { + pd->offset = 0; + } + break; + } + default: + { + /* NTLMSSP expected: unexpected message type */ + DEBUG(3,("unexpected message type in NTLMSSP %d\n", + p->auth_verifier.msg_type)); + return False; + } + } + + return (pd->offset != 0); +} + +struct api_cmd +{ + char * pipe_clnt_name; + char * pipe_srv_name; + BOOL (*fn) (pipes_struct *, prs_struct *); +}; + +static struct api_cmd api_fd_commands[] = +{ + { "lsarpc", "lsass", api_ntlsa_rpc }, + { "samr", "lsass", api_samr_rpc }, + { "srvsvc", "ntsvcs", api_srvsvc_rpc }, + { "wkssvc", "ntsvcs", api_wkssvc_rpc }, + { "NETLOGON", "lsass", api_netlog_rpc }, + { "winreg", "winreg", api_reg_rpc }, + { NULL, NULL, NULL } +}; + +static BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *pd) +{ + DEBUG(5,("api_pipe_bind_auth_resp: decode request. %d\n", __LINE__)); + + if (p->hdr.auth_len == 0) return False; + + /* decode the authentication verifier response */ + smb_io_rpc_hdr_autha("", &p->autha_info, pd, 0); + if (pd->offset == 0) return False; + + if (!rpc_hdr_auth_chk(&(p->auth_info))) return False; + + smb_io_rpc_auth_verifier("", &p->auth_verifier, pd, 0); + if (pd->offset == 0) return False; + + if (!rpc_auth_verifier_chk(&(p->auth_verifier), "NTLMSSP", NTLMSSP_AUTH)) return False; + + return api_pipe_ntlmssp(p, pd); +} + +static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd) +{ + uint16 assoc_gid; + fstring ack_pipe_name; + int i = 0; + + p->ntlmssp_auth = False; + + DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__)); + + for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) + { + if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && + api_fd_commands[i].fn != NULL) + { + DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n", + api_fd_commands[i].pipe_clnt_name, + api_fd_commands[i].pipe_srv_name)); + fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name); + break; + } + } + + if (api_fd_commands[i].fn == NULL) return False; + + /* decode the bind request */ + smb_io_rpc_hdr_rb("", &p->hdr_rb, pd, 0); + + if (pd->offset == 0) return False; + + if (p->hdr.auth_len != 0) + { + /* decode the authentication verifier */ + smb_io_rpc_hdr_auth ("", &p->auth_info , pd, 0); + if (pd->offset == 0) return False; + + p->ntlmssp_auth = p->auth_info.auth_type = 0x0a; + + if (p->ntlmssp_auth) + { + smb_io_rpc_auth_verifier("", &p->auth_verifier, pd, 0); + if (pd->offset == 0) return False; + + p->ntlmssp_auth = strequal(p->auth_verifier.signature, "NTLMSSP"); + } + + if (p->ntlmssp_auth) + { + if (!api_pipe_ntlmssp(p, pd)) return False; + } + } + + /* name has to be \PIPE\xxxxx */ + fstrcpy(ack_pipe_name, "\\PIPE\\"); + fstrcat(ack_pipe_name, p->pipe_srv_name); + + DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__)); + + prs_init(&(p->rdata), 1024, 4, 0, False); + prs_init(&(p->rhdr ), 0x18, 4, 0, False); + prs_init(&(p->rauth), 1024, 4, 0, False); + prs_init(&(p->rverf), 0x08, 4, 0, False); + prs_init(&(p->rntlm), 1024, 4, 0, False); + + /***/ + /*** do the bind ack first ***/ + /***/ + + if (p->ntlmssp_auth) + { + assoc_gid = 0x7a77; + } + else + { + assoc_gid = p->hdr_rb.bba.assoc_gid; + } + + make_rpc_hdr_ba(&p->hdr_ba, + p->hdr_rb.bba.max_tsize, + p->hdr_rb.bba.max_rsize, + assoc_gid, + ack_pipe_name, + 0x1, 0x0, 0x0, + &(p->hdr_rb.transfer)); + + smb_io_rpc_hdr_ba("", &p->hdr_ba, &p->rdata, 0); + mem_realloc_data(p->rdata.data, p->rdata.offset); + + /***/ + /*** now the authentication ***/ + /***/ + + if (p->ntlmssp_auth) + { + uint8 challenge[8]; + generate_random_buffer(challenge, 8, False); + + /*** authentication info ***/ + + make_rpc_hdr_auth(&p->auth_info, 0x0a, 0x06, 0, 1); + smb_io_rpc_hdr_auth("", &p->auth_info, &p->rverf, 0); + mem_realloc_data(p->rverf.data, p->rverf.offset); + + /*** NTLMSSP verifier ***/ + + make_rpc_auth_verifier(&p->auth_verifier, + "NTLMSSP", NTLMSSP_CHALLENGE); + smb_io_rpc_auth_verifier("", &p->auth_verifier, &p->rauth, 0); + mem_realloc_data(p->rauth.data, p->rauth.offset); + + /* NTLMSSP challenge ***/ + + make_rpc_auth_ntlmssp_chal(&p->ntlmssp_chal, + 0x000082b1, challenge); + smb_io_rpc_auth_ntlmssp_chal("", &p->ntlmssp_chal, &p->rntlm, 0); + mem_realloc_data(p->rntlm.data, p->rntlm.offset); + } + + /***/ + /*** then do the header, now we know the length ***/ + /***/ + + make_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST, + p->hdr.call_id, + p->rdata.offset + p->rverf.offset + p->rauth.offset + p->rntlm.offset + 0x10, + p->rauth.offset + p->rntlm.offset); + + smb_io_rpc_hdr("", &p->hdr, &p->rhdr, 0); + mem_realloc_data(p->rhdr.data, p->rdata.offset); + + /***/ + /*** link rpc header, bind acknowledgment and authentication responses ***/ + /***/ + + if (p->ntlmssp_auth) + { + prs_link(NULL , &p->rhdr , &p->rdata); + prs_link(&p->rhdr , &p->rdata, &p->rverf); + prs_link(&p->rdata, &p->rverf, &p->rauth); + prs_link(&p->rverf, &p->rauth, &p->rntlm); + prs_link(&p->rauth, &p->rntlm, NULL ); + } + else + { + prs_link(NULL , &p->rhdr , &p->rdata); + prs_link(&p->rhdr, &p->rdata, NULL ); + } + + return True; +} + + +static BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *pd) +{ + BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SIGN); + BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SEAL); + int data_len; + int auth_len; + uint32 old_offset; + uint32 crc32; + + auth_len = p->hdr.auth_len; + + if (auth_len != 16 && auth_verify) + { + return False; + } + + data_len = p->hdr.frag_len - auth_len - (auth_verify ? 8 : 0) - 0x18; + + DEBUG(5,("api_pipe_auth_process: sign: %s seal: %s data %d auth %d\n", + BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len)); + + if (auth_seal) + { + char *data = mem_data(&pd->data, pd->offset); + DEBUG(5,("api_pipe_auth_process: data %d\n", pd->offset)); + NTLMSSPcalc_p(p, (uchar*)data, data_len); + crc32 = crc32_calc_buffer(data_len, data); + } + + /*** skip the data, record the offset so we can restore it again */ + old_offset = pd->offset; + + if (auth_seal || auth_verify) + { + pd->offset += data_len; + smb_io_rpc_hdr_auth("hdr_auth", &p->auth_info, pd, 0); + } + + if (auth_verify) + { + char *req_data = mem_data(&pd->data, pd->offset + 4); + DEBUG(5,("api_pipe_auth_process: auth %d\n", pd->offset + 4)); + NTLMSSPcalc_p(p, (uchar*)req_data, 12); + smb_io_rpc_auth_ntlmssp_chk("auth_sign", &(p->ntlmssp_chk), pd, 0); + + if (!rpc_auth_ntlmssp_chk(&(p->ntlmssp_chk), crc32, + p->ntlmssp_seq_num)) + { + return False; + } + } + + pd->offset = old_offset; + + return True; +} + +static BOOL api_pipe_request(pipes_struct *p, prs_struct *pd) +{ + int i = 0; + + if (p->ntlmssp_auth && p->ntlmssp_validated) + { + if (!api_pipe_auth_process(p, pd)) return False; + + DEBUG(0,("api_pipe_request: **** MUST CALL become_user() HERE **** \n")); +#if 0 + become_user(); +#endif + } + + for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) + { + if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && + api_fd_commands[i].fn != NULL) + { + DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name)); + return api_fd_commands[i].fn(p, pd); + } + } + return False; +} + +BOOL rpc_command(pipes_struct *p, prs_struct *pd) +{ + BOOL reply = False; + if (pd->data == NULL) return False; + + /* process the rpc header */ + smb_io_rpc_hdr("", &p->hdr, pd, 0); + + if (pd->offset == 0) return False; + + switch (p->hdr.pkt_type) + { + case RPC_BIND : + { + reply = api_pipe_bind_req(p, pd); + break; + } + case RPC_REQUEST: + { + if (p->ntlmssp_auth && !p->ntlmssp_validated) + { + /* authentication _was_ requested + and it failed. sorry, no deal! + */ + reply = False; + } + else + { + /* read the rpc header */ + smb_io_rpc_hdr_req("req", &(p->hdr_req), pd, 0); + reply = api_pipe_request(p, pd); + } + break; + } + case RPC_BINDRESP: /* not the real name! */ + { + reply = api_pipe_bind_auth_resp(p, pd); + p->ntlmssp_auth = reply; + break; + } + } + + if (!reply) + { + DEBUG(3,("rpc_command: DCE/RPC fault should be sent here\n")); + } + + return reply; +} + + +/******************************************************************* + 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_req.opnum)); + + for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++) + { + if (api_rpc_cmds[fn_num].opnum == p->hdr_req.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 */ + prs_init(&p->rdata, 1024, 4, SAFETY_MARGIN, False); + + /* do the actual command */ + api_rpc_cmds[fn_num].fn(p->vuid, 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; + } + + /* 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 + (p->ntlmssp_auth ? (16 + 8) : 0))) + { + return False; + } + + return True; +} diff --git a/source3/rpc_server/srv_sid.c b/source3/rpc_server/srv_sid.c new file mode 100644 index 0000000000..b80902dbaa --- /dev/null +++ b/source3/rpc_server/srv_sid.c @@ -0,0 +1,484 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Samba utility functions + Copyright (C) Andrew Tridgell 1992-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. +*/ + +#include "includes.h" + + +extern int DEBUGLEVEL; +extern pstring scope; +extern pstring global_myname; + +/* + * This is set on startup - it defines the SID for this + * machine, and therefore the SAM database for which it is + * responsible. + */ + +DOM_SID global_sam_sid; + +/* + * This is the name associated with the SAM database for + * which this machine is responsible. In the case of a PDC + * or PDC, this name is the same as the workgroup. In the + * case of "security = domain" mode, this is the same as + * the name of the server (global_myname). + */ + +fstring global_sam_name; + +/* + * This is obtained on startup - it defines the SID for which + * this machine is a member. It is therefore only set, and + * used, in "security = domain" mode. + */ + +DOM_SID global_member_sid; + +/* + * note the lack of a "global_member_name" - this is because + * this is the same as "global_myworkgroup". + */ + +/* + * some useful sids + */ + +DOM_SID global_sid_S_1_5_20; /* local well-known domain */ +DOM_SID global_sid_S_1_1; /* everyone */ +DOM_SID global_sid_S_1_3; /* */ +DOM_SID global_sid_S_1_5; /* NT Authority */ + +extern pstring global_myworkgroup; +/* extern fstring global_member_dom_name; */ + +static struct sid_name_map_info +{ + DOM_SID *sid; + char *name; + +} +sid_name_map[] = +{ + { &global_sid_S_1_5_20, "BUILTIN" }, + { &global_sid_S_1_1 , "Everyone" }, + { &global_sid_S_1_3 , "don't know" }, + { &global_sid_S_1_5 , "NT Authority" }, + { &global_sam_sid , global_sam_name }, + { &global_member_sid , global_myworkgroup }, + { NULL , NULL } +}; + +/**************************************************************************** + Read the machine SID from a file. +****************************************************************************/ + +static BOOL read_sid_from_file(int fd, char *sid_file) +{ + fstring fline; + + memset(fline, '\0', sizeof(fline)); + + if (read(fd, fline, sizeof(fline) -1 ) < 0) { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + return False; + } + + /* + * Convert to the machine SID. + */ + + fline[sizeof(fline)-1] = '\0'; + if (!string_to_sid( &global_sam_sid, fline)) { + DEBUG(0,("unable to generate machine SID.\n")); + return False; + } + + return True; +} + +/**************************************************************************** + Generate the global machine sid. Look for the MACHINE.SID file first, if + not found then look in smb.conf and use it to create the MACHINE.SID file. +****************************************************************************/ +BOOL get_member_domain_sid(void) +{ + POLICY_HND pol; + fstring srv_name; + struct cli_state cli; + BOOL res = True; + DOM_SID sid3; + DOM_SID sid5; + fstring dom3; + fstring dom5; + + if (!cli_connect_serverlist(&cli, lp_passwordserver())) + { + DEBUG(0,("get_member_domain_sid: unable to initialize client connection.\n")); + return False; + } + + /* + * Ok - we have an anonymous connection to the IPC$ share. + * Now start the NT Domain stuff :-). + */ + + fstrcpy(dom3, ""); + fstrcpy(dom5, ""); + ZERO_STRUCT(sid3); + ZERO_STRUCT(sid5); + + fstrcpy(srv_name, "\\\\"); + fstrcat(srv_name, global_myname); + strupper(srv_name); + + /* open LSARPC session. */ + res = res ? cli_nt_session_open(&cli, PIPE_LSARPC) : False; + + /* lookup domain controller; receive a policy handle */ + res = res ? do_lsa_open_policy(&cli, srv_name, &pol, False) : False; + + /* send client info query, level 3. receive domain name and sid */ + res = res ? do_lsa_query_info_pol(&cli, &pol, 3, dom3, &sid3) : False; + + /* send client info query, level 5. receive domain name and sid */ + res = res ? do_lsa_query_info_pol(&cli, &pol, 5, dom5, &sid5) : False; + + /* close policy handle */ + res = res ? do_lsa_close(&cli, &pol) : False; + + /* close the session */ + cli_nt_session_close(&cli); + cli_ulogoff(&cli); + cli_shutdown(&cli); + + if (res) + { + pstring sid; + DEBUG(5,("LSA Query Info Policy\n")); + sid_to_string(sid, &sid3); + DEBUG(5,("Domain Member - Domain: %s SID: %s\n", dom3, sid)); + sid_to_string(sid, &sid5); + DEBUG(5,("Domain Controller - Domain: %s SID: %s\n", dom5, sid)); + + if (!strequal(dom3, global_myworkgroup) || + !strequal(dom5, global_myworkgroup)) + { + DEBUG(0,("get_member_domain_sid: %s is a DC for %s not %s\n", + cli.desthost, dom5, global_myworkgroup)); + res = False; + } + } + else + { + DEBUG(5,("lsa query info failed\n")); + } + if (!res) + { + DEBUG(0,("get_member_domain_sid: unable to obtain Domain member SID\n")); + } + else + { + /* this is a _lot_ of trouble to go to for just this info: */ + global_member_sid = sid5; + } + + return res; +} + +/**************************************************************************** + creates some useful well known sids +****************************************************************************/ +void generate_wellknown_sids(void) +{ + string_to_sid(&global_sid_S_1_5_20, "S-1-5-32"); + string_to_sid(&global_sid_S_1_1 , "S-1-1" ); + string_to_sid(&global_sid_S_1_3 , "S-1-3" ); + string_to_sid(&global_sid_S_1_5 , "S-1-5" ); +} + +/**************************************************************************** + Generate the global machine sid. Look for the MACHINE.SID file first, if + not found then look in smb.conf and use it to create the MACHINE.SID file. +****************************************************************************/ +BOOL generate_sam_sid(void) +{ + int fd; + int i; + char *p; + pstring sid_file; + fstring sid_string; + SMB_STRUCT_STAT st; + uchar raw_sid_data[12]; + + pstrcpy(sid_file, lp_smb_passwd_file()); + p = strrchr(sid_file, '/'); + if (p != NULL) { + *++p = '\0'; + } + + if (!directory_exist(sid_file, NULL)) { + if (dos_mkdir(sid_file, 0700) != 0) { + DEBUG(0,("can't create private directory %s : %s\n", + sid_file, strerror(errno))); + return False; + } + } + + pstrcat(sid_file, "MACHINE.SID"); + + if ((fd = open(sid_file, O_RDWR | O_CREAT, 0644)) == -1) { + DEBUG(0,("unable to open or create file %s. Error was %s\n", + sid_file, strerror(errno) )); + return False; + } + + /* + * Check if the file contains data. + */ + + if (sys_fstat( fd, &st) < 0) { + DEBUG(0,("unable to stat file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if (st.st_size > 0) { + /* + * We have a valid SID - read it. + */ + if (!read_sid_from_file( fd, sid_file)) { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + close(fd); + return True; + } + + /* + * Generate the new sid data & turn it into a string. + */ + generate_random_buffer( raw_sid_data, 12, True); + + fstrcpy( sid_string, "S-1-5-21"); + for( i = 0; i < 3; i++) { + fstring tmp_string; + slprintf( tmp_string, sizeof(tmp_string) - 1, "-%u", IVAL(raw_sid_data, i*4)); + fstrcat( sid_string, tmp_string); + } + + fstrcat(sid_string, "\n"); + + /* + * Ensure our new SID is valid. + */ + + if (!string_to_sid( &global_sam_sid, sid_string)) { + DEBUG(0,("unable to generate machine SID.\n")); + return False; + } + + /* + * Do an exclusive blocking lock on the file. + */ + + if (!do_file_lock( fd, 60, F_WRLCK)) { + DEBUG(0,("unable to lock file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + /* + * At this point we have a blocking lock on the SID + * file - check if in the meantime someone else wrote + * SID data into the file. If so - they were here first, + * use their data. + */ + + if (sys_fstat( fd, &st) < 0) { + DEBUG(0,("unable to stat file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + if (st.st_size > 0) { + /* + * Unlock as soon as possible to reduce + * contention on the exclusive lock. + */ + do_file_lock( fd, 60, F_UNLCK); + + /* + * We have a valid SID - read it. + */ + + if (!read_sid_from_file( fd, sid_file)) { + DEBUG(0,("unable to read file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + close(fd); + return True; + } + + /* + * The file is still empty and we have an exlusive lock on it. + * Write out out SID data into the file. + */ + + if (fchmod(fd, 0644) < 0) { + DEBUG(0,("unable to set correct permissions on file %s. \ +Error was %s\n", sid_file, strerror(errno) )); + close(fd); + return False; + } + + if (write( fd, sid_string, strlen(sid_string)) != strlen(sid_string)) { + DEBUG(0,("unable to write file %s. Error was %s\n", + sid_file, strerror(errno) )); + close(fd); + return False; + } + + /* + * Unlock & exit. + */ + + do_file_lock( fd, 60, F_UNLCK); + close(fd); + return True; +} + +/************************************************************************** + turns a domain name into a SID. + + *** side-effect: if the domain name is NULL, it is set to our domain *** + +***************************************************************************/ +BOOL map_domain_name_to_sid(DOM_SID *sid, char **nt_domain) +{ + fstring sid_str; + sid_to_string(sid_str, sid); + DEBUG(5,("map_domain_name_to_sid: %s\n", sid_str)); + + if (nt_domain == NULL) + { + *sid = global_sam_sid; + return True; + } + + if ((*nt_domain) == NULL) + { + DEBUG(5,("map_domain_name_to_sid: overriding NULL name to %s\n", + global_sam_name)); + (*nt_domain) = strdup(global_sam_name); + *sid = global_sam_sid; + return True; + } + + if (strequal((*nt_domain), global_sam_name)) + { + *sid = global_sam_sid; + return True; + } + + DEBUG(0,("map_domain_name_to_sid: mapping to %s NOT IMPLEMENTED\n", + (*nt_domain))); + return False; +} + +/************************************************************************** + turns a domain SID into a name. + +***************************************************************************/ +BOOL map_domain_sid_to_name(DOM_SID *sid, char *nt_domain) +{ + fstring sid_str; + int i = 0; + sid_to_string(sid_str, sid); + + DEBUG(5,("map_domain_sid_to_name: %s\n", sid_str)); + + if (nt_domain == NULL) + { + return False; + } + + while (sid_name_map[i].sid != NULL) + { + sid_to_string(sid_str, sid_name_map[i].sid); + DEBUG(5,("compare: %s\n", sid_str)); + if (sid_equal(sid_name_map[i].sid, sid)) + { + fstrcpy(nt_domain, sid_name_map[i].name); + DEBUG(5,("found %s\n", nt_domain)); + return True; + } + i++; + } + + DEBUG(0,("map_domain_sid_to_name: mapping NOT IMPLEMENTED\n")); + + return False; +} + +/************************************************************************** + splits a name of format \DOMAIN\name into its two components. + sets the DOMAIN name to global_sam_name if it has not been specified. +***************************************************************************/ +BOOL split_domain_name(char *fullname, char *domain, char *name) +{ + fstring full_name; + char *p; + + if (fullname == NULL || domain == NULL || name == NULL) + { + return False; + } + + if (fullname[0] == '\\') + { + fullname++; + } + fstrcpy(full_name, fullname); + p = strchr(full_name+1, '\\'); + + if (p == NULL) + { + *p = 0; + fstrcpy(domain, full_name); + fstrcpy(name, p+1); + } + else + { + fstrcpy(domain, global_sam_name); + fstrcpy(name, full_name); + } + + DEBUG(5,("name '%s' split into '\\%s\\%s'\n", fullname, domain, name)); + return True; +} diff --git a/source3/rpc_server/srv_util.c b/source3/rpc_server/srv_util.c index 161f845af3..097ab92d76 100644 --- a/source3/rpc_server/srv_util.c +++ b/source3/rpc_server/srv_util.c @@ -154,693 +154,6 @@ int make_dom_gids(char *gids_str, DOM_GID **ppgids) return count; } -static void NTLMSSPcalc_p( pipes_struct *p, unsigned char *data, int len) -{ - unsigned char *hash = p->ntlmssp_hash; - unsigned char index_i = hash[256]; - unsigned char index_j = hash[257]; - int ind; - - for( ind = 0; ind < len; ind++) - { - unsigned char tc; - unsigned char t; - - index_i++; - index_j += hash[index_i]; - - tc = hash[index_i]; - hash[index_i] = hash[index_j]; - hash[index_j] = tc; - - t = hash[index_i] + hash[index_j]; - data[ind] = data[ind] ^ hash[t]; - } - - hash[256] = index_i; - hash[257] = index_j; -} - -/******************************************************************* - 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) -{ - char *data; - BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SIGN); - BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SEAL); - uint32 data_len; - uint32 auth_len; - - DEBUG(5,("create_rpc_reply: data_start: %d data_end: %d max_tsize: %d\n", - data_start, data_end, p->hdr_ba.bba.max_tsize)); - - auth_len = p->hdr.auth_len; - - if (p->ntlmssp_auth) - { - DEBUG(10,("create_rpc_reply: auth\n")); - if (auth_len != 16) - { - return False; - } - } - - prs_init(&p->rhdr , 0x18, 4, 0, False); - prs_init(&p->rauth, 1024, 4, 0, False); - prs_init(&p->rverf, 0x08, 4, 0, False); - - 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; - } - - p->hdr_resp.alloc_hint = data_end - data_start; /* calculate remaining data to be sent */ - - if (p->hdr_resp.alloc_hint + 0x18 <= p->hdr_ba.bba.max_tsize) - { - p->hdr.flags |= RPC_FLG_LAST; - p->hdr.frag_len = p->hdr_resp.alloc_hint + 0x18; - } - else - { - p->hdr.frag_len = p->hdr_ba.bba.max_tsize; - } - - if (p->ntlmssp_auth) - { - p->hdr_resp.alloc_hint -= auth_len + 8; - } - - if (p->ntlmssp_auth) - { - data_len = p->hdr.frag_len - auth_len - (auth_verify ? 8 : 0) - 0x18; - } - else - { - data_len = p->hdr.frag_len - 0x18; - } - - p->rhdr.data->offset.start = 0; - p->rhdr.data->offset.end = 0x18; - - /* store the header in the data stream */ - smb_io_rpc_hdr ("hdr" , &(p->hdr ), &(p->rhdr), 0); - smb_io_rpc_hdr_resp("resp", &(p->hdr_resp), &(p->rhdr), 0); - - /* don't use rdata: use rdata_i instead, which moves... */ - /* make a pointer to the rdata data, NOT A COPY */ - - p->rdata_i.data = NULL; - prs_init(&p->rdata_i, 0, p->rdata.align, p->rdata.data->margin, p->rdata.io); - data = mem_data(&(p->rdata.data), data_start); - mem_create(p->rdata_i.data, data, 0, data_len, 0, False); - p->rdata_i.offset = data_len; - - if (auth_len > 0) - { - uint32 crc32; - - DEBUG(5,("create_rpc_reply: sign: %s seal: %s data %d auth %d\n", - BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len)); - - if (auth_seal) - { - crc32 = crc32_calc_buffer(data_len, data); - NTLMSSPcalc_p(p, (uchar*)data, data_len); - } - - if (auth_seal || auth_verify) - { - make_rpc_hdr_auth(&p->auth_info, 0x0a, 0x06, 0x08, (auth_verify ? 1 : 0)); - smb_io_rpc_hdr_auth("hdr_auth", &p->auth_info, &p->rauth, 0); - } - - if (auth_verify) - { - char *auth_data; - p->ntlmssp_seq_num++; - make_rpc_auth_ntlmssp_chk(&p->ntlmssp_chk, NTLMSSP_SIGN_VERSION, crc32, p->ntlmssp_seq_num++); - smb_io_rpc_auth_ntlmssp_chk("auth_sign", &(p->ntlmssp_chk), &p->rverf, 0); - auth_data = mem_data(&p->rverf.data, 4); - NTLMSSPcalc_p(p, (uchar*)auth_data, 12); - } - } - - /* set up the data chain */ - if (p->ntlmssp_auth) - { - prs_link(NULL , &p->rhdr , &p->rdata_i); - prs_link(&p->rhdr , &p->rdata_i, &p->rauth ); - prs_link(&p->rdata_i, &p->rauth , &p->rverf ); - prs_link(&p->rauth , &p->rverf , NULL ); - } - else - { - prs_link(NULL , &p->rhdr , &p->rdata_i); - prs_link(&p->rhdr, &p->rdata_i, NULL ); - } - - /* indicate to subsequent data reads where we are up to */ - p->frag_len_left = p->hdr.frag_len - p->file_offset; - p->next_frag_start = p->hdr.frag_len; - - return p->rhdr.data != NULL && p->rhdr.offset == 0x18; -} - -static BOOL api_pipe_ntlmssp_verify(pipes_struct *p) -{ - uchar lm_owf[24]; - uchar nt_owf[24]; - struct smb_passwd *smb_pass = NULL; - - DEBUG(5,("api_pipe_ntlmssp_verify: checking user details\n")); - - if (p->ntlmssp_resp.hdr_lm_resp.str_str_len == 0) return False; - if (p->ntlmssp_resp.hdr_nt_resp.str_str_len == 0) return False; - if (p->ntlmssp_resp.hdr_usr .str_str_len == 0) return False; - if (p->ntlmssp_resp.hdr_domain .str_str_len == 0) return False; - if (p->ntlmssp_resp.hdr_wks .str_str_len == 0) return False; - - memset(p->user_name, 0, sizeof(p->user_name)); - memset(p->domain , 0, sizeof(p->domain )); - memset(p->wks , 0, sizeof(p->wks )); - - if (IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_UNICODE)) - { - fstrcpy(p->user_name, unistrn2((uint16*)p->ntlmssp_resp.user , p->ntlmssp_resp.hdr_usr .str_str_len/2)); - fstrcpy(p->domain , unistrn2((uint16*)p->ntlmssp_resp.domain, p->ntlmssp_resp.hdr_domain.str_str_len/2)); - fstrcpy(p->wks , unistrn2((uint16*)p->ntlmssp_resp.wks , p->ntlmssp_resp.hdr_wks .str_str_len/2)); - } - else - { - fstrcpy(p->user_name, p->ntlmssp_resp.user ); - fstrcpy(p->domain , p->ntlmssp_resp.domain); - fstrcpy(p->wks , p->ntlmssp_resp.wks ); - } - - DEBUG(5,("user: %s domain: %s wks: %s\n", p->user_name, p->domain, p->wks)); - - memcpy(lm_owf, p->ntlmssp_resp.lm_resp, sizeof(lm_owf)); - memcpy(nt_owf, p->ntlmssp_resp.nt_resp, sizeof(nt_owf)); - -#ifdef DEBUG_PASSWORD - DEBUG(100,("lm, nt owfs, chal\n")); - dump_data(100, lm_owf, sizeof(lm_owf)); - dump_data(100, nt_owf, sizeof(nt_owf)); - dump_data(100, p->ntlmssp_chal.challenge, 8); -#endif - become_root(True); - p->ntlmssp_validated = pass_check_smb(p->user_name, p->domain, - (uchar*)p->ntlmssp_chal.challenge, - lm_owf, nt_owf, NULL); - smb_pass = getsmbpwnam(p->user_name); - unbecome_root(True); - - if (p->ntlmssp_validated && smb_pass != NULL && smb_pass->smb_passwd) - { - uchar p24[24]; - NTLMSSPOWFencrypt(smb_pass->smb_passwd, lm_owf, p24); - { - unsigned char j = 0; - int ind; - - unsigned char k2[8]; - - memcpy(k2, p24, 5); - k2[5] = 0xe5; - k2[6] = 0x38; - k2[7] = 0xb0; - - for (ind = 0; ind < 256; ind++) - { - p->ntlmssp_hash[ind] = (unsigned char)ind; - } - - for( ind = 0; ind < 256; ind++) - { - unsigned char tc; - - j += (p->ntlmssp_hash[ind] + k2[ind%8]); - - tc = p->ntlmssp_hash[ind]; - p->ntlmssp_hash[ind] = p->ntlmssp_hash[j]; - p->ntlmssp_hash[j] = tc; - } - - p->ntlmssp_hash[256] = 0; - p->ntlmssp_hash[257] = 0; - } -/* NTLMSSPhash(p->ntlmssp_hash, p24); */ - p->ntlmssp_seq_num = 0; - } - else - { - p->ntlmssp_validated = False; - } - - return p->ntlmssp_validated; -} - -static BOOL api_pipe_ntlmssp(pipes_struct *p, prs_struct *pd) -{ - /* receive a negotiate; send a challenge; receive a response */ - switch (p->auth_verifier.msg_type) - { - case NTLMSSP_NEGOTIATE: - { - smb_io_rpc_auth_ntlmssp_neg("", &p->ntlmssp_neg, pd, 0); - break; - } - case NTLMSSP_AUTH: - { - smb_io_rpc_auth_ntlmssp_resp("", &p->ntlmssp_resp, pd, 0); - if (!api_pipe_ntlmssp_verify(p)) - { - pd->offset = 0; - } - break; - } - default: - { - /* NTLMSSP expected: unexpected message type */ - DEBUG(3,("unexpected message type in NTLMSSP %d\n", - p->auth_verifier.msg_type)); - return False; - } - } - - return (pd->offset != 0); -} - -struct api_cmd -{ - char * pipe_clnt_name; - char * pipe_srv_name; - BOOL (*fn) (pipes_struct *, prs_struct *); -}; - -static struct api_cmd api_fd_commands[] = -{ - { "lsarpc", "lsass", api_ntlsa_rpc }, - { "samr", "lsass", api_samr_rpc }, - { "srvsvc", "ntsvcs", api_srvsvc_rpc }, - { "wkssvc", "ntsvcs", api_wkssvc_rpc }, - { "NETLOGON", "lsass", api_netlog_rpc }, - { "winreg", "winreg", api_reg_rpc }, - { NULL, NULL, NULL } -}; - -static BOOL api_pipe_bind_auth_resp(pipes_struct *p, prs_struct *pd) -{ - DEBUG(5,("api_pipe_bind_auth_resp: decode request. %d\n", __LINE__)); - - if (p->hdr.auth_len == 0) return False; - - /* decode the authentication verifier response */ - smb_io_rpc_hdr_autha("", &p->autha_info, pd, 0); - if (pd->offset == 0) return False; - - if (!rpc_hdr_auth_chk(&(p->auth_info))) return False; - - smb_io_rpc_auth_verifier("", &p->auth_verifier, pd, 0); - if (pd->offset == 0) return False; - - if (!rpc_auth_verifier_chk(&(p->auth_verifier), "NTLMSSP", NTLMSSP_AUTH)) return False; - - return api_pipe_ntlmssp(p, pd); -} - -static BOOL api_pipe_bind_req(pipes_struct *p, prs_struct *pd) -{ - uint16 assoc_gid; - fstring ack_pipe_name; - int i = 0; - - p->ntlmssp_auth = False; - - DEBUG(5,("api_pipe_bind_req: decode request. %d\n", __LINE__)); - - for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) - { - if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && - api_fd_commands[i].fn != NULL) - { - DEBUG(3,("api_pipe_bind_req: \\PIPE\\%s -> \\PIPE\\%s\n", - api_fd_commands[i].pipe_clnt_name, - api_fd_commands[i].pipe_srv_name)); - fstrcpy(p->pipe_srv_name, api_fd_commands[i].pipe_srv_name); - break; - } - } - - if (api_fd_commands[i].fn == NULL) return False; - - /* decode the bind request */ - smb_io_rpc_hdr_rb("", &p->hdr_rb, pd, 0); - - if (pd->offset == 0) return False; - - if (p->hdr.auth_len != 0) - { - /* decode the authentication verifier */ - smb_io_rpc_hdr_auth ("", &p->auth_info , pd, 0); - if (pd->offset == 0) return False; - - p->ntlmssp_auth = p->auth_info.auth_type = 0x0a; - - if (p->ntlmssp_auth) - { - smb_io_rpc_auth_verifier("", &p->auth_verifier, pd, 0); - if (pd->offset == 0) return False; - - p->ntlmssp_auth = strequal(p->auth_verifier.signature, "NTLMSSP"); - } - - if (p->ntlmssp_auth) - { - if (!api_pipe_ntlmssp(p, pd)) return False; - } - } - - /* name has to be \PIPE\xxxxx */ - fstrcpy(ack_pipe_name, "\\PIPE\\"); - fstrcat(ack_pipe_name, p->pipe_srv_name); - - DEBUG(5,("api_pipe_bind_req: make response. %d\n", __LINE__)); - - prs_init(&(p->rdata), 1024, 4, 0, False); - prs_init(&(p->rhdr ), 0x18, 4, 0, False); - prs_init(&(p->rauth), 1024, 4, 0, False); - prs_init(&(p->rverf), 0x08, 4, 0, False); - prs_init(&(p->rntlm), 1024, 4, 0, False); - - /***/ - /*** do the bind ack first ***/ - /***/ - - if (p->ntlmssp_auth) - { - assoc_gid = 0x7a77; - } - else - { - assoc_gid = p->hdr_rb.bba.assoc_gid; - } - - make_rpc_hdr_ba(&p->hdr_ba, - p->hdr_rb.bba.max_tsize, - p->hdr_rb.bba.max_rsize, - assoc_gid, - ack_pipe_name, - 0x1, 0x0, 0x0, - &(p->hdr_rb.transfer)); - - smb_io_rpc_hdr_ba("", &p->hdr_ba, &p->rdata, 0); - mem_realloc_data(p->rdata.data, p->rdata.offset); - - /***/ - /*** now the authentication ***/ - /***/ - - if (p->ntlmssp_auth) - { - uint8 challenge[8]; - generate_random_buffer(challenge, 8, False); - - /*** authentication info ***/ - - make_rpc_hdr_auth(&p->auth_info, 0x0a, 0x06, 0, 1); - smb_io_rpc_hdr_auth("", &p->auth_info, &p->rverf, 0); - mem_realloc_data(p->rverf.data, p->rverf.offset); - - /*** NTLMSSP verifier ***/ - - make_rpc_auth_verifier(&p->auth_verifier, - "NTLMSSP", NTLMSSP_CHALLENGE); - smb_io_rpc_auth_verifier("", &p->auth_verifier, &p->rauth, 0); - mem_realloc_data(p->rauth.data, p->rauth.offset); - - /* NTLMSSP challenge ***/ - - make_rpc_auth_ntlmssp_chal(&p->ntlmssp_chal, - 0x000082b1, challenge); - smb_io_rpc_auth_ntlmssp_chal("", &p->ntlmssp_chal, &p->rntlm, 0); - mem_realloc_data(p->rntlm.data, p->rntlm.offset); - } - - /***/ - /*** then do the header, now we know the length ***/ - /***/ - - make_rpc_hdr(&p->hdr, RPC_BINDACK, RPC_FLG_FIRST | RPC_FLG_LAST, - p->hdr.call_id, - p->rdata.offset + p->rverf.offset + p->rauth.offset + p->rntlm.offset + 0x10, - p->rauth.offset + p->rntlm.offset); - - smb_io_rpc_hdr("", &p->hdr, &p->rhdr, 0); - mem_realloc_data(p->rhdr.data, p->rdata.offset); - - /***/ - /*** link rpc header, bind acknowledgment and authentication responses ***/ - /***/ - - if (p->ntlmssp_auth) - { - prs_link(NULL , &p->rhdr , &p->rdata); - prs_link(&p->rhdr , &p->rdata, &p->rverf); - prs_link(&p->rdata, &p->rverf, &p->rauth); - prs_link(&p->rverf, &p->rauth, &p->rntlm); - prs_link(&p->rauth, &p->rntlm, NULL ); - } - else - { - prs_link(NULL , &p->rhdr , &p->rdata); - prs_link(&p->rhdr, &p->rdata, NULL ); - } - - return True; -} - - -static BOOL api_pipe_auth_process(pipes_struct *p, prs_struct *pd) -{ - BOOL auth_verify = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SIGN); - BOOL auth_seal = IS_BITS_SET_ALL(p->ntlmssp_chal.neg_flags, NTLMSSP_NEGOTIATE_SEAL); - int data_len; - int auth_len; - uint32 old_offset; - uint32 crc32; - - auth_len = p->hdr.auth_len; - - if (auth_len != 16 && auth_verify) - { - return False; - } - - data_len = p->hdr.frag_len - auth_len - (auth_verify ? 8 : 0) - 0x18; - - DEBUG(5,("api_pipe_auth_process: sign: %s seal: %s data %d auth %d\n", - BOOLSTR(auth_verify), BOOLSTR(auth_seal), data_len, auth_len)); - - if (auth_seal) - { - char *data = mem_data(&pd->data, pd->offset); - DEBUG(5,("api_pipe_auth_process: data %d\n", pd->offset)); - NTLMSSPcalc_p(p, (uchar*)data, data_len); - crc32 = crc32_calc_buffer(data_len, data); - } - - /*** skip the data, record the offset so we can restore it again */ - old_offset = pd->offset; - - if (auth_seal || auth_verify) - { - pd->offset += data_len; - smb_io_rpc_hdr_auth("hdr_auth", &p->auth_info, pd, 0); - } - - if (auth_verify) - { - char *req_data = mem_data(&pd->data, pd->offset + 4); - DEBUG(5,("api_pipe_auth_process: auth %d\n", pd->offset + 4)); - NTLMSSPcalc_p(p, (uchar*)req_data, 12); - smb_io_rpc_auth_ntlmssp_chk("auth_sign", &(p->ntlmssp_chk), pd, 0); - - if (!rpc_auth_ntlmssp_chk(&(p->ntlmssp_chk), crc32, - p->ntlmssp_seq_num)) - { - return False; - } - } - - pd->offset = old_offset; - - return True; -} - -static BOOL api_pipe_request(pipes_struct *p, prs_struct *pd) -{ - int i = 0; - - if (p->ntlmssp_auth && p->ntlmssp_validated) - { - if (!api_pipe_auth_process(p, pd)) return False; - - DEBUG(0,("api_pipe_request: **** MUST CALL become_user() HERE **** \n")); -#if 0 - become_user(); -#endif - } - - for (i = 0; api_fd_commands[i].pipe_clnt_name; i++) - { - if (strequal(api_fd_commands[i].pipe_clnt_name, p->name) && - api_fd_commands[i].fn != NULL) - { - DEBUG(3,("Doing \\PIPE\\%s\n", api_fd_commands[i].pipe_clnt_name)); - return api_fd_commands[i].fn(p, pd); - } - } - return False; -} - -BOOL rpc_command(pipes_struct *p, prs_struct *pd) -{ - BOOL reply = False; - if (pd->data == NULL) return False; - - /* process the rpc header */ - smb_io_rpc_hdr("", &p->hdr, pd, 0); - - if (pd->offset == 0) return False; - - switch (p->hdr.pkt_type) - { - case RPC_BIND : - { - reply = api_pipe_bind_req(p, pd); - break; - } - case RPC_REQUEST: - { - if (p->ntlmssp_auth && !p->ntlmssp_validated) - { - /* authentication _was_ requested - and it failed. sorry, no deal! - */ - reply = False; - } - else - { - /* read the rpc header */ - smb_io_rpc_hdr_req("req", &(p->hdr_req), pd, 0); - reply = api_pipe_request(p, pd); - } - break; - } - case RPC_BINDRESP: /* not the real name! */ - { - reply = api_pipe_bind_auth_resp(p, pd); - p->ntlmssp_auth = reply; - break; - } - } - - if (!reply) - { - DEBUG(3,("rpc_command: DCE/RPC fault should be sent here\n")); - } - - return reply; -} - - -/******************************************************************* - 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_req.opnum)); - - for (fn_num = 0; api_rpc_cmds[fn_num].name; fn_num++) - { - if (api_rpc_cmds[fn_num].opnum == p->hdr_req.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 */ - prs_init(&p->rdata, 1024, 4, SAFETY_MARGIN, False); - - /* do the actual command */ - api_rpc_cmds[fn_num].fn(p->vuid, 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; - } - - /* 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 + (p->ntlmssp_auth ? (16 + 8) : 0))) - { - return False; - } - - return True; -} - /******************************************************************* gets a domain user's groups -- cgit