diff options
Diffstat (limited to 'source4/rpc_server')
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 62 | ||||
-rw-r--r-- | source4/rpc_server/dcesrv_auth.c | 71 |
2 files changed, 133 insertions, 0 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index d11d5dddd8..3afe5f1dc5 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -564,6 +564,65 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call) return NT_STATUS_OK; } +/* + handle a bind request +*/ +static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call) +{ + struct dcerpc_packet pkt; + struct dcesrv_call_reply *rep; + NTSTATUS status; + uint32_t result=0, reason=0; + + /* handle any authentication that is being requested */ + if (!dcesrv_auth_alter(call)) { + /* TODO: work out the right reject code */ + return dcesrv_bind_nak(call, 0); + } + + /* setup a alter_ack */ + dcesrv_init_hdr(&pkt); + pkt.auth_length = 0; + pkt.call_id = call->pkt.call_id; + pkt.ptype = DCERPC_PKT_ALTER_ACK; + pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST; + pkt.u.alter_ack.max_xmit_frag = 0x2000; + pkt.u.alter_ack.max_recv_frag = 0x2000; + pkt.u.alter_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id; + pkt.u.alter_ack.secondary_address = NULL; + pkt.u.alter_ack.num_results = 1; + pkt.u.alter_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx); + if (!pkt.u.alter_ack.ctx_list) { + return NT_STATUS_NO_MEMORY; + } + pkt.u.alter_ack.ctx_list[0].result = result; + pkt.u.alter_ack.ctx_list[0].reason = reason; + GUID_from_string(NDR_GUID, &pkt.u.alter_ack.ctx_list[0].syntax.uuid); + pkt.u.alter_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION; + pkt.u.alter_ack.auth_info = data_blob(NULL, 0); + + if (!dcesrv_auth_alter_ack(call, &pkt)) { + return dcesrv_bind_nak(call, 0); + } + + rep = talloc_p(call, struct dcesrv_call_reply); + if (!rep) { + return NT_STATUS_NO_MEMORY; + } + + status = dcerpc_push_auth(&rep->data, call, &pkt, + call->conn->auth_state.auth_info); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + dcerpc_set_frag_length(&rep->data, rep->data.length); + + DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *); + DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *); + + return NT_STATUS_OK; +} /* handle a dcerpc request packet @@ -848,6 +907,9 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn) case DCERPC_PKT_AUTH3: status = dcesrv_auth3(call); break; + case DCERPC_PKT_ALTER: + status = dcesrv_alter(call); + break; case DCERPC_PKT_REQUEST: status = dcesrv_request(call); break; diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c index f546e8d6e1..71332b557d 100644 --- a/source4/rpc_server/dcesrv_auth.c +++ b/source4/rpc_server/dcesrv_auth.c @@ -193,6 +193,77 @@ BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call) return True; } +/* + parse any auth information from a dcerpc alter request + return False if we can't handle the auth request for some + reason (in which case we send a bind_nak (is this true for here?)) +*/ +BOOL dcesrv_auth_alter(struct dcesrv_call_state *call) +{ + struct dcerpc_packet *pkt = &call->pkt; + struct dcesrv_connection *dce_conn = call->conn; + NTSTATUS status; + + /* We can't work without an existing gensec state, and an new blob to feed it */ + if (!dce_conn->auth_state.gensec_security || + pkt->u.alter.auth_info.length == 0) { + return False; + } + + dce_conn->auth_state.auth_info = talloc_p(dce_conn, struct dcerpc_auth); + if (!dce_conn->auth_state.auth_info) { + return False; + } + + status = ndr_pull_struct_blob(&pkt->u.alter.auth_info, + call, + dce_conn->auth_state.auth_info, + (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth); + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + return True; +} + +/* + add any auth information needed in a alter ack, and process the authentication + information found in the alter. +*/ +BOOL dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt) +{ + struct dcesrv_connection *dce_conn = call->conn; + NTSTATUS status; + + if (!call->conn->auth_state.gensec_security) { + return False; + } + + status = gensec_update(dce_conn->auth_state.gensec_security, + call, + dce_conn->auth_state.auth_info->credentials, + &dce_conn->auth_state.auth_info->credentials); + + if (NT_STATUS_IS_OK(status)) { + status = gensec_session_info(dce_conn->auth_state.gensec_security, + &dce_conn->auth_state.session_info); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status))); + return False; + } + + /* Now that we are authenticated, got back to the generic session key... */ + dce_conn->auth_state.session_key = dcesrv_generic_session_key; + return True; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + dce_conn->auth_state.auth_info->auth_pad_length = 0; + dce_conn->auth_state.auth_info->auth_reserved = 0; + return True; + } else { + DEBUG(2, ("Failed to finish dcesrv auth alter_ack: %s\n", nt_errstr(status))); + return True; + } +} /* generate a CONNECT level verifier |