source: trunk/server/source4/ldap_server/ldap_extended.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 6.3 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 LDAP server
4 Copyright (C) Stefan Metzmacher 2004
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "includes.h"
21#include "ldap_server/ldap_server.h"
22#include "../lib/util/dlinklist.h"
23#include "lib/tls/tls.h"
24#include "smbd/service_stream.h"
25#include "../lib/util/tevent_ntstatus.h"
26
27struct ldapsrv_starttls_postprocess_context {
28 struct ldapsrv_connection *conn;
29};
30
31struct ldapsrv_starttls_postprocess_state {
32 struct ldapsrv_connection *conn;
33};
34
35static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq);
36
37static struct tevent_req *ldapsrv_starttls_postprocess_send(TALLOC_CTX *mem_ctx,
38 struct tevent_context *ev,
39 void *private_data)
40{
41 struct ldapsrv_starttls_postprocess_context *context =
42 talloc_get_type_abort(private_data,
43 struct ldapsrv_starttls_postprocess_context);
44 struct ldapsrv_connection *conn = context->conn;
45 struct tevent_req *req;
46 struct ldapsrv_starttls_postprocess_state *state;
47 struct tevent_req *subreq;
48
49 req = tevent_req_create(mem_ctx, &state,
50 struct ldapsrv_starttls_postprocess_state);
51 if (req == NULL) {
52 return NULL;
53 }
54
55 state->conn = conn;
56
57 subreq = tstream_tls_accept_send(conn,
58 conn->connection->event.ctx,
59 conn->sockets.raw,
60 conn->service->tls_params);
61 if (tevent_req_nomem(subreq, req)) {
62 return tevent_req_post(req, ev);
63 }
64 tevent_req_set_callback(subreq, ldapsrv_starttls_postprocess_done, req);
65
66 return req;
67}
68
69static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq)
70{
71 struct tevent_req *req =
72 tevent_req_callback_data(subreq,
73 struct tevent_req);
74 struct ldapsrv_starttls_postprocess_state *state =
75 tevent_req_data(req,
76 struct ldapsrv_starttls_postprocess_state);
77 struct ldapsrv_connection *conn = state->conn;
78 int ret;
79 int sys_errno;
80
81 ret = tstream_tls_accept_recv(subreq, &sys_errno,
82 conn, &conn->sockets.tls);
83 TALLOC_FREE(subreq);
84 if (ret == -1) {
85 NTSTATUS status = map_nt_error_from_unix(sys_errno);
86
87 DEBUG(1,("ldapsrv_starttls_postprocess_done: accept_tls_loop: "
88 "tstream_tls_accept_recv() - %d:%s => %s",
89 sys_errno, strerror(sys_errno), nt_errstr(status)));
90
91 tevent_req_nterror(req, status);
92 return;
93 }
94
95 conn->sockets.active = conn->sockets.tls;
96
97 tevent_req_done(req);
98}
99
100static NTSTATUS ldapsrv_starttls_postprocess_recv(struct tevent_req *req)
101{
102 return tevent_req_simple_recv_ntstatus(req);
103}
104
105static NTSTATUS ldapsrv_StartTLS(struct ldapsrv_call *call,
106 struct ldapsrv_reply *reply,
107 const char **errstr)
108{
109 struct ldapsrv_starttls_postprocess_context *context;
110
111 (*errstr) = NULL;
112
113 /*
114 * TODO: give LDAP_OPERATIONS_ERROR also when
115 * there're pending requests or there's
116 * a SASL bind in progress
117 * (see rfc4513 section 3.1.1)
118 */
119 if (call->conn->sockets.tls) {
120 (*errstr) = talloc_asprintf(reply, "START-TLS: TLS is already enabled on this LDAP session");
121 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
122 }
123
124 if (call->conn->sockets.sasl) {
125 (*errstr) = talloc_asprintf(reply, "START-TLS: SASL is already enabled on this LDAP session");
126 return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
127 }
128
129 context = talloc(call, struct ldapsrv_starttls_postprocess_context);
130 NT_STATUS_HAVE_NO_MEMORY(context);
131
132 context->conn = call->conn;
133
134 call->postprocess_send = ldapsrv_starttls_postprocess_send;
135 call->postprocess_recv = ldapsrv_starttls_postprocess_recv;
136 call->postprocess_private = context;
137
138 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_SUCCESS;
139 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
140
141 ldapsrv_queue_reply(call, reply);
142 return NT_STATUS_OK;
143}
144
145struct ldapsrv_extended_operation {
146 const char *oid;
147 NTSTATUS (*fn)(struct ldapsrv_call *call, struct ldapsrv_reply *reply, const char **errorstr);
148};
149
150static struct ldapsrv_extended_operation extended_ops[] = {
151 {
152 .oid = LDB_EXTENDED_START_TLS_OID,
153 .fn = ldapsrv_StartTLS,
154 },{
155 .oid = NULL,
156 .fn = NULL,
157 }
158};
159
160NTSTATUS ldapsrv_ExtendedRequest(struct ldapsrv_call *call)
161{
162 struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
163 struct ldapsrv_reply *reply;
164 int result = LDAP_PROTOCOL_ERROR;
165 const char *error_str = NULL;
166 NTSTATUS status = NT_STATUS_OK;
167 unsigned int i;
168
169 DEBUG(10, ("Extended\n"));
170
171 reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
172 NT_STATUS_HAVE_NO_MEMORY(reply);
173
174 ZERO_STRUCT(reply->msg->r);
175 reply->msg->r.ExtendedResponse.oid = talloc_steal(reply, req->oid);
176 reply->msg->r.ExtendedResponse.response.resultcode = LDAP_PROTOCOL_ERROR;
177 reply->msg->r.ExtendedResponse.response.errormessage = NULL;
178
179 for (i=0; extended_ops[i].oid; i++) {
180 if (strcmp(extended_ops[i].oid,req->oid) != 0) continue;
181
182 /*
183 * if the backend function returns an error we
184 * need to send the reply otherwise the reply is already
185 * send and we need to return directly
186 */
187 status = extended_ops[i].fn(call, reply, &error_str);
188 NT_STATUS_IS_OK_RETURN(status);
189
190 if (NT_STATUS_IS_LDAP(status)) {
191 result = NT_STATUS_LDAP_CODE(status);
192 } else {
193 result = LDAP_OPERATIONS_ERROR;
194 error_str = talloc_asprintf(reply, "Extended Operation(%s) failed: %s",
195 req->oid, nt_errstr(status));
196 }
197 }
198 /* if we haven't found the oid, then status is still NT_STATUS_OK */
199 if (NT_STATUS_IS_OK(status)) {
200 error_str = talloc_asprintf(reply, "Extended Operation(%s) not supported",
201 req->oid);
202 }
203
204 reply->msg->r.ExtendedResponse.response.resultcode = result;
205 reply->msg->r.ExtendedResponse.response.errormessage = error_str;
206
207 ldapsrv_queue_reply(call, reply);
208 return NT_STATUS_OK;
209}
Note: See TracBrowser for help on using the repository browser.