Line data Source code
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 "samba/service_stream.h"
25 : #include "../lib/util/tevent_ntstatus.h"
26 :
27 : struct ldapsrv_starttls_postprocess_context {
28 : struct ldapsrv_connection *conn;
29 : };
30 :
31 : struct ldapsrv_starttls_postprocess_state {
32 : struct ldapsrv_connection *conn;
33 : };
34 :
35 : static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq);
36 :
37 0 : static struct tevent_req *ldapsrv_starttls_postprocess_send(TALLOC_CTX *mem_ctx,
38 : struct tevent_context *ev,
39 : void *private_data)
40 : {
41 0 : struct ldapsrv_starttls_postprocess_context *context =
42 0 : talloc_get_type_abort(private_data,
43 : struct ldapsrv_starttls_postprocess_context);
44 0 : 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 0 : req = tevent_req_create(mem_ctx, &state,
50 : struct ldapsrv_starttls_postprocess_state);
51 0 : if (req == NULL) {
52 0 : return NULL;
53 : }
54 :
55 0 : state->conn = conn;
56 :
57 0 : subreq = tstream_tls_accept_send(conn,
58 : conn->connection->event.ctx,
59 : conn->sockets.raw,
60 : conn->service->tls_params);
61 0 : if (tevent_req_nomem(subreq, req)) {
62 0 : return tevent_req_post(req, ev);
63 : }
64 0 : tevent_req_set_callback(subreq, ldapsrv_starttls_postprocess_done, req);
65 :
66 0 : return req;
67 : }
68 :
69 0 : static void ldapsrv_starttls_postprocess_done(struct tevent_req *subreq)
70 : {
71 0 : struct tevent_req *req =
72 0 : tevent_req_callback_data(subreq,
73 : struct tevent_req);
74 0 : struct ldapsrv_starttls_postprocess_state *state =
75 0 : tevent_req_data(req,
76 : struct ldapsrv_starttls_postprocess_state);
77 0 : struct ldapsrv_connection *conn = state->conn;
78 : int ret;
79 : int sys_errno;
80 :
81 0 : ret = tstream_tls_accept_recv(subreq, &sys_errno,
82 : conn, &conn->sockets.tls);
83 0 : TALLOC_FREE(subreq);
84 0 : if (ret == -1) {
85 0 : NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
86 :
87 0 : 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 0 : tevent_req_nterror(req, status);
92 0 : return;
93 : }
94 :
95 0 : conn->sockets.active = conn->sockets.tls;
96 :
97 0 : tevent_req_done(req);
98 : }
99 :
100 0 : static NTSTATUS ldapsrv_starttls_postprocess_recv(struct tevent_req *req)
101 : {
102 0 : return tevent_req_simple_recv_ntstatus(req);
103 : }
104 :
105 0 : static 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 0 : (*errstr) = NULL;
112 :
113 : /*
114 : * TODO: give LDAP_OPERATIONS_ERROR also when
115 : * there's a SASL bind in progress
116 : * (see rfc4513 section 3.1.1)
117 : */
118 0 : if (call->conn->sockets.tls) {
119 0 : (*errstr) = talloc_asprintf(reply, "START-TLS: TLS is already enabled on this LDAP session");
120 0 : return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
121 : }
122 :
123 0 : if (call->conn->sockets.sasl) {
124 0 : (*errstr) = talloc_asprintf(reply, "START-TLS: SASL is already enabled on this LDAP session");
125 0 : return NT_STATUS_LDAP(LDAP_OPERATIONS_ERROR);
126 : }
127 :
128 0 : if (call->conn->pending_calls != NULL) {
129 0 : (*errstr) = talloc_asprintf(reply, "START-TLS: pending requests on this LDAP session");
130 0 : return NT_STATUS_LDAP(LDAP_BUSY);
131 : }
132 :
133 0 : context = talloc(call, struct ldapsrv_starttls_postprocess_context);
134 0 : NT_STATUS_HAVE_NO_MEMORY(context);
135 :
136 0 : context->conn = call->conn;
137 :
138 0 : call->postprocess_send = ldapsrv_starttls_postprocess_send;
139 0 : call->postprocess_recv = ldapsrv_starttls_postprocess_recv;
140 0 : call->postprocess_private = context;
141 :
142 0 : reply->msg->r.ExtendedResponse.response.resultcode = LDAP_SUCCESS;
143 0 : reply->msg->r.ExtendedResponse.response.errormessage = NULL;
144 :
145 0 : ldapsrv_queue_reply(call, reply);
146 0 : return NT_STATUS_OK;
147 : }
148 :
149 : struct ldapsrv_extended_operation {
150 : const char *oid;
151 : NTSTATUS (*fn)(struct ldapsrv_call *call, struct ldapsrv_reply *reply, const char **errorstr);
152 : };
153 :
154 : static struct ldapsrv_extended_operation extended_ops[] = {
155 : {
156 : .oid = LDB_EXTENDED_START_TLS_OID,
157 : .fn = ldapsrv_StartTLS,
158 : },{
159 : .oid = NULL,
160 : .fn = NULL,
161 : }
162 : };
163 :
164 0 : NTSTATUS ldapsrv_ExtendedRequest(struct ldapsrv_call *call)
165 : {
166 0 : struct ldap_ExtendedRequest *req = &call->request->r.ExtendedRequest;
167 : struct ldapsrv_reply *reply;
168 0 : int result = LDAP_PROTOCOL_ERROR;
169 0 : const char *error_str = NULL;
170 0 : NTSTATUS status = NT_STATUS_OK;
171 : unsigned int i;
172 :
173 0 : DEBUG(10, ("Extended\n"));
174 :
175 0 : reply = ldapsrv_init_reply(call, LDAP_TAG_ExtendedResponse);
176 0 : NT_STATUS_HAVE_NO_MEMORY(reply);
177 :
178 0 : ZERO_STRUCT(reply->msg->r);
179 0 : reply->msg->r.ExtendedResponse.oid = talloc_steal(reply, req->oid);
180 0 : reply->msg->r.ExtendedResponse.response.resultcode = LDAP_PROTOCOL_ERROR;
181 0 : reply->msg->r.ExtendedResponse.response.errormessage = NULL;
182 :
183 0 : for (i=0; extended_ops[i].oid; i++) {
184 0 : if (strcmp(extended_ops[i].oid,req->oid) != 0) continue;
185 :
186 : /*
187 : * if the backend function returns an error we
188 : * need to send the reply otherwise the reply is already
189 : * sent and we need to return directly
190 : */
191 0 : status = extended_ops[i].fn(call, reply, &error_str);
192 0 : if (NT_STATUS_IS_OK(status)) {
193 0 : return status;
194 : }
195 :
196 0 : if (NT_STATUS_IS_LDAP(status)) {
197 0 : result = NT_STATUS_LDAP_CODE(status);
198 : } else {
199 0 : result = LDAP_OPERATIONS_ERROR;
200 0 : error_str = talloc_asprintf(reply, "Extended Operation(%s) failed: %s",
201 : req->oid, nt_errstr(status));
202 : }
203 : }
204 : /* if we haven't found the oid, then status is still NT_STATUS_OK */
205 0 : if (NT_STATUS_IS_OK(status)) {
206 0 : error_str = talloc_asprintf(reply, "Extended Operation(%s) not supported",
207 : req->oid);
208 : }
209 :
210 0 : reply->msg->r.ExtendedResponse.response.resultcode = result;
211 0 : reply->msg->r.ExtendedResponse.response.errormessage = error_str;
212 :
213 0 : ldapsrv_queue_reply(call, reply);
214 0 : return NT_STATUS_OK;
215 : }
|