1 | /*
|
---|
2 | Unix SMB/CIFS implementation.
|
---|
3 | Authenticate against Samba4's auth subsystem
|
---|
4 | Copyright (C) Volker Lendecke 2008
|
---|
5 | Copyright (C) Andrew Bartlett 2010
|
---|
6 |
|
---|
7 | This program is free software; you can redistribute it and/or modify
|
---|
8 | it under the terms of the GNU General Public License as published by
|
---|
9 | the Free Software Foundation; either version 3 of the License, or
|
---|
10 | (at your option) any later version.
|
---|
11 |
|
---|
12 | This program is distributed in the hope that it will be useful,
|
---|
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
15 | GNU General Public License for more details.
|
---|
16 |
|
---|
17 | You should have received a copy of the GNU General Public License
|
---|
18 | along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
19 | */
|
---|
20 |
|
---|
21 | #include "includes.h"
|
---|
22 | #include "source3/include/auth.h"
|
---|
23 | #include "source3/include/messages.h"
|
---|
24 | #include "source4/auth/auth.h"
|
---|
25 | #include "auth/auth_sam_reply.h"
|
---|
26 | #include "param/param.h"
|
---|
27 | #include "source4/lib/events/events.h"
|
---|
28 | #include "source4/lib/messaging/messaging.h"
|
---|
29 | #include "auth/gensec/gensec.h"
|
---|
30 | #include "auth/credentials/credentials.h"
|
---|
31 |
|
---|
32 | #undef DBGC_CLASS
|
---|
33 | #define DBGC_CLASS DBGC_AUTH
|
---|
34 |
|
---|
35 | static NTSTATUS make_auth4_context_s4(const struct auth_context *auth_context,
|
---|
36 | TALLOC_CTX *mem_ctx,
|
---|
37 | struct auth4_context **auth4_context);
|
---|
38 |
|
---|
39 | static struct idr_context *task_id_tree;
|
---|
40 |
|
---|
41 | static int free_task_id(struct server_id *server_id)
|
---|
42 | {
|
---|
43 | idr_remove(task_id_tree, server_id->task_id);
|
---|
44 | return 0;
|
---|
45 | }
|
---|
46 |
|
---|
47 | /* Return a server_id with a unique task_id element. Free the
|
---|
48 | * returned pointer to de-allocate the task_id via a talloc destructor
|
---|
49 | * (ie, use talloc_free()) */
|
---|
50 | static struct server_id *new_server_id_task(TALLOC_CTX *mem_ctx)
|
---|
51 | {
|
---|
52 | struct messaging_context *msg_ctx;
|
---|
53 | struct server_id *server_id;
|
---|
54 | int task_id;
|
---|
55 | if (!task_id_tree) {
|
---|
56 | task_id_tree = idr_init(NULL);
|
---|
57 | if (!task_id_tree) {
|
---|
58 | return NULL;
|
---|
59 | }
|
---|
60 | }
|
---|
61 |
|
---|
62 | msg_ctx = server_messaging_context();
|
---|
63 | if (msg_ctx == NULL) {
|
---|
64 | return NULL;
|
---|
65 | }
|
---|
66 |
|
---|
67 | server_id = talloc(mem_ctx, struct server_id);
|
---|
68 |
|
---|
69 | if (!server_id) {
|
---|
70 | return NULL;
|
---|
71 | }
|
---|
72 | *server_id = messaging_server_id(msg_ctx);
|
---|
73 |
|
---|
74 | /* 0 is the default server_id, so we need to start with 1 */
|
---|
75 | task_id = idr_get_new_above(task_id_tree, server_id, 1, INT32_MAX);
|
---|
76 |
|
---|
77 | if (task_id == -1) {
|
---|
78 | talloc_free(server_id);
|
---|
79 | return NULL;
|
---|
80 | }
|
---|
81 |
|
---|
82 | talloc_set_destructor(server_id, free_task_id);
|
---|
83 | server_id->task_id = task_id;
|
---|
84 | return server_id;
|
---|
85 | }
|
---|
86 |
|
---|
87 | /*
|
---|
88 | * This module is not an ordinary authentication module. It is really
|
---|
89 | * a way to redirect the whole authentication and authorization stack
|
---|
90 | * to use the source4 auth code, not a way to just handle NTLM
|
---|
91 | * authentication.
|
---|
92 | *
|
---|
93 | * See the comments above each function for how that hook changes the
|
---|
94 | * behaviour.
|
---|
95 | */
|
---|
96 |
|
---|
97 | /*
|
---|
98 | * This hook is currently used by winbindd only, as all other NTLM
|
---|
99 | * logins go via the hooks provided by make_auth4_context_s4() below.
|
---|
100 | *
|
---|
101 | * This is only left in case we find a way that it might become useful
|
---|
102 | * in future. Importantly, this routine returns the information
|
---|
103 | * needed for a NETLOGON SamLogon, not what is needed to establish a
|
---|
104 | * session.
|
---|
105 | *
|
---|
106 | * We expect we may use this hook in the source3/ winbind when this
|
---|
107 | * services the AD DC. It is tested via pdbtest.
|
---|
108 | */
|
---|
109 |
|
---|
110 | static NTSTATUS check_samba4_security(const struct auth_context *auth_context,
|
---|
111 | void *my_private_data,
|
---|
112 | TALLOC_CTX *mem_ctx,
|
---|
113 | const struct auth_usersupplied_info *user_info,
|
---|
114 | struct auth_serversupplied_info **server_info)
|
---|
115 | {
|
---|
116 | TALLOC_CTX *frame = talloc_stackframe();
|
---|
117 | struct netr_SamInfo3 *info3 = NULL;
|
---|
118 | NTSTATUS nt_status;
|
---|
119 | struct auth_user_info_dc *user_info_dc;
|
---|
120 | struct auth4_context *auth4_context;
|
---|
121 |
|
---|
122 | nt_status = make_auth4_context_s4(auth_context, mem_ctx, &auth4_context);
|
---|
123 | if (!NT_STATUS_IS_OK(nt_status)) {
|
---|
124 | TALLOC_FREE(frame);
|
---|
125 | goto done;
|
---|
126 | }
|
---|
127 |
|
---|
128 | nt_status = auth_context_set_challenge(auth4_context, auth_context->challenge.data, "auth_samba4");
|
---|
129 | if (!NT_STATUS_IS_OK(nt_status)) {
|
---|
130 | TALLOC_FREE(auth4_context);
|
---|
131 | TALLOC_FREE(frame);
|
---|
132 | return nt_status;
|
---|
133 | }
|
---|
134 |
|
---|
135 | nt_status = auth_check_password(auth4_context, auth4_context, user_info, &user_info_dc);
|
---|
136 | if (!NT_STATUS_IS_OK(nt_status)) {
|
---|
137 | TALLOC_FREE(auth4_context);
|
---|
138 | TALLOC_FREE(frame);
|
---|
139 | return nt_status;
|
---|
140 | }
|
---|
141 |
|
---|
142 | nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx,
|
---|
143 | user_info_dc,
|
---|
144 | &info3);
|
---|
145 | if (NT_STATUS_IS_OK(nt_status)) {
|
---|
146 | /* We need the strings from the server_info to be valid as long as the info3 is around */
|
---|
147 | talloc_steal(info3, user_info_dc);
|
---|
148 | }
|
---|
149 | talloc_free(auth4_context);
|
---|
150 |
|
---|
151 | if (!NT_STATUS_IS_OK(nt_status)) {
|
---|
152 | goto done;
|
---|
153 | }
|
---|
154 |
|
---|
155 | if (user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ) {
|
---|
156 | *server_info = make_server_info(mem_ctx);
|
---|
157 | if (*server_info == NULL) {
|
---|
158 | nt_status = NT_STATUS_NO_MEMORY;
|
---|
159 | goto done;
|
---|
160 | }
|
---|
161 | (*server_info)->info3 = talloc_steal(*server_info, info3);
|
---|
162 |
|
---|
163 | } else {
|
---|
164 | nt_status = make_server_info_info3(mem_ctx, user_info->client.account_name,
|
---|
165 | user_info->mapped.domain_name, server_info,
|
---|
166 | info3);
|
---|
167 | if (!NT_STATUS_IS_OK(nt_status)) {
|
---|
168 | DEBUG(10, ("make_server_info_info3 failed: %s\n",
|
---|
169 | nt_errstr(nt_status)));
|
---|
170 | goto done;
|
---|
171 | }
|
---|
172 | }
|
---|
173 |
|
---|
174 | nt_status = NT_STATUS_OK;
|
---|
175 |
|
---|
176 | done:
|
---|
177 | TALLOC_FREE(frame);
|
---|
178 | return nt_status;
|
---|
179 | }
|
---|
180 |
|
---|
181 | /*
|
---|
182 | * Hook to allow the source4 set of GENSEC modules to handle
|
---|
183 | * blob-based authentication mechanisms, without directly linking the
|
---|
184 | * mechanism code.
|
---|
185 | *
|
---|
186 | * This may eventually go away, when the GSSAPI acceptors are merged,
|
---|
187 | * when we will just rely on the make_auth4_context_s4 hook instead.
|
---|
188 | *
|
---|
189 | * Even for NTLMSSP, which has a common module, significant parts of
|
---|
190 | * the behaviour are overridden here, because it uses the source4 NTLM
|
---|
191 | * stack and the source4 mapping between the PAC/SamLogon response and
|
---|
192 | * the local token.
|
---|
193 | *
|
---|
194 | * It is important to override all this to ensure that the exact same
|
---|
195 | * token is generated and used in the SMB and LDAP servers, for NTLM
|
---|
196 | * and for Kerberos.
|
---|
197 | */
|
---|
198 | static NTSTATUS prepare_gensec(const struct auth_context *auth_context,
|
---|
199 | TALLOC_CTX *mem_ctx,
|
---|
200 | struct gensec_security **gensec_context)
|
---|
201 | {
|
---|
202 | NTSTATUS status;
|
---|
203 | struct loadparm_context *lp_ctx;
|
---|
204 | struct tevent_context *event_ctx;
|
---|
205 | TALLOC_CTX *frame = talloc_stackframe();
|
---|
206 | struct gensec_security *gensec_ctx;
|
---|
207 | struct imessaging_context *msg_ctx;
|
---|
208 | struct cli_credentials *server_credentials;
|
---|
209 | struct server_id *server_id;
|
---|
210 |
|
---|
211 | lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
|
---|
212 | if (lp_ctx == NULL) {
|
---|
213 | DEBUG(1, ("loadparm_init_s3 failed\n"));
|
---|
214 | TALLOC_FREE(frame);
|
---|
215 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
216 | }
|
---|
217 | event_ctx = s4_event_context_init(frame);
|
---|
218 | if (event_ctx == NULL) {
|
---|
219 | DEBUG(1, ("s4_event_context_init failed\n"));
|
---|
220 | TALLOC_FREE(frame);
|
---|
221 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
222 | }
|
---|
223 |
|
---|
224 | server_id = new_server_id_task(frame);
|
---|
225 | if (server_id == NULL) {
|
---|
226 | DEBUG(1, ("new_server_id_task failed\n"));
|
---|
227 | TALLOC_FREE(frame);
|
---|
228 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
229 | }
|
---|
230 |
|
---|
231 | msg_ctx = imessaging_init(frame,
|
---|
232 | lp_ctx,
|
---|
233 | *server_id,
|
---|
234 | event_ctx, true);
|
---|
235 | if (msg_ctx == NULL) {
|
---|
236 | DEBUG(1, ("imessaging_init failed\n"));
|
---|
237 | TALLOC_FREE(frame);
|
---|
238 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
239 | }
|
---|
240 |
|
---|
241 | talloc_reparent(frame, msg_ctx, server_id);
|
---|
242 |
|
---|
243 | server_credentials
|
---|
244 | = cli_credentials_init(frame);
|
---|
245 | if (!server_credentials) {
|
---|
246 | DEBUG(1, ("Failed to init server credentials"));
|
---|
247 | TALLOC_FREE(frame);
|
---|
248 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
249 | }
|
---|
250 |
|
---|
251 | cli_credentials_set_conf(server_credentials, lp_ctx);
|
---|
252 | status = cli_credentials_set_machine_account(server_credentials, lp_ctx);
|
---|
253 | if (!NT_STATUS_IS_OK(status)) {
|
---|
254 | DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
|
---|
255 | TALLOC_FREE(frame);
|
---|
256 | return status;
|
---|
257 | }
|
---|
258 |
|
---|
259 | status = samba_server_gensec_start(mem_ctx,
|
---|
260 | event_ctx, msg_ctx,
|
---|
261 | lp_ctx, server_credentials, "cifs",
|
---|
262 | &gensec_ctx);
|
---|
263 | if (!NT_STATUS_IS_OK(status)) {
|
---|
264 | DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
|
---|
265 | TALLOC_FREE(frame);
|
---|
266 | return status;
|
---|
267 | }
|
---|
268 |
|
---|
269 | talloc_reparent(frame, gensec_ctx, msg_ctx);
|
---|
270 | talloc_reparent(frame, gensec_ctx, event_ctx);
|
---|
271 | talloc_reparent(frame, gensec_ctx, lp_ctx);
|
---|
272 | talloc_reparent(frame, gensec_ctx, server_credentials);
|
---|
273 |
|
---|
274 | gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
|
---|
275 | gensec_want_feature(gensec_ctx, GENSEC_FEATURE_UNIX_TOKEN);
|
---|
276 |
|
---|
277 | *gensec_context = gensec_ctx;
|
---|
278 | TALLOC_FREE(frame);
|
---|
279 | return status;
|
---|
280 | }
|
---|
281 |
|
---|
282 | /*
|
---|
283 | * Hook to allow handling of NTLM authentication for AD operation
|
---|
284 | * without directly linking the s4 auth stack
|
---|
285 | *
|
---|
286 | * This ensures we use the source4 authentication stack, as well as
|
---|
287 | * the authorization stack to create the user's token. This ensures
|
---|
288 | * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is
|
---|
289 | * handled by the hook above.
|
---|
290 | */
|
---|
291 | static NTSTATUS make_auth4_context_s4(const struct auth_context *auth_context,
|
---|
292 | TALLOC_CTX *mem_ctx,
|
---|
293 | struct auth4_context **auth4_context)
|
---|
294 | {
|
---|
295 | NTSTATUS status;
|
---|
296 | struct loadparm_context *lp_ctx;
|
---|
297 | struct tevent_context *event_ctx;
|
---|
298 | TALLOC_CTX *frame = talloc_stackframe();
|
---|
299 | struct imessaging_context *msg_ctx;
|
---|
300 | struct server_id *server_id;
|
---|
301 |
|
---|
302 | lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
|
---|
303 | if (lp_ctx == NULL) {
|
---|
304 | DEBUG(1, ("loadparm_init_s3 failed\n"));
|
---|
305 | TALLOC_FREE(frame);
|
---|
306 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
307 | }
|
---|
308 | event_ctx = s4_event_context_init(frame);
|
---|
309 | if (event_ctx == NULL) {
|
---|
310 | DEBUG(1, ("s4_event_context_init failed\n"));
|
---|
311 | TALLOC_FREE(frame);
|
---|
312 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
313 | }
|
---|
314 |
|
---|
315 | server_id = new_server_id_task(frame);
|
---|
316 | if (server_id == NULL) {
|
---|
317 | DEBUG(1, ("new_server_id_task failed\n"));
|
---|
318 | TALLOC_FREE(frame);
|
---|
319 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
320 | }
|
---|
321 |
|
---|
322 | msg_ctx = imessaging_init(frame,
|
---|
323 | lp_ctx,
|
---|
324 | *server_id,
|
---|
325 | event_ctx, true);
|
---|
326 | if (msg_ctx == NULL) {
|
---|
327 | DEBUG(1, ("imessaging_init failed\n"));
|
---|
328 | TALLOC_FREE(frame);
|
---|
329 | return NT_STATUS_INVALID_SERVER_STATE;
|
---|
330 | }
|
---|
331 | talloc_reparent(frame, msg_ctx, server_id);
|
---|
332 |
|
---|
333 | /* Allow forcing a specific auth4 module */
|
---|
334 | if (!auth_context->forced_samba4_methods) {
|
---|
335 | status = auth_context_create(mem_ctx,
|
---|
336 | event_ctx,
|
---|
337 | msg_ctx,
|
---|
338 | lp_ctx,
|
---|
339 | auth4_context);
|
---|
340 | } else {
|
---|
341 | const char * const *forced_auth_methods = (const char * const *)str_list_make(mem_ctx, auth_context->forced_samba4_methods, NULL);
|
---|
342 | status = auth_context_create_methods(mem_ctx, forced_auth_methods, event_ctx, msg_ctx, lp_ctx, NULL, auth4_context);
|
---|
343 | }
|
---|
344 | if (!NT_STATUS_IS_OK(status)) {
|
---|
345 | DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status)));
|
---|
346 | TALLOC_FREE(frame);
|
---|
347 | return status;
|
---|
348 | }
|
---|
349 |
|
---|
350 | talloc_reparent(frame, *auth4_context, msg_ctx);
|
---|
351 | talloc_reparent(frame, *auth4_context, event_ctx);
|
---|
352 | talloc_reparent(frame, *auth4_context, lp_ctx);
|
---|
353 |
|
---|
354 | TALLOC_FREE(frame);
|
---|
355 | return status;
|
---|
356 | }
|
---|
357 |
|
---|
358 | /* module initialisation */
|
---|
359 | static NTSTATUS auth_init_samba4(struct auth_context *auth_context,
|
---|
360 | const char *param,
|
---|
361 | auth_methods **auth_method)
|
---|
362 | {
|
---|
363 | struct auth_methods *result;
|
---|
364 |
|
---|
365 | gensec_init();
|
---|
366 |
|
---|
367 | result = talloc_zero(auth_context, struct auth_methods);
|
---|
368 | if (result == NULL) {
|
---|
369 | return NT_STATUS_NO_MEMORY;
|
---|
370 | }
|
---|
371 | result->name = "samba4";
|
---|
372 | result->auth = check_samba4_security;
|
---|
373 | result->prepare_gensec = prepare_gensec;
|
---|
374 | result->make_auth4_context = make_auth4_context_s4;
|
---|
375 | result->flags = AUTH_METHOD_LOCAL_SAM;
|
---|
376 |
|
---|
377 | if (param && *param) {
|
---|
378 | auth_context->forced_samba4_methods = talloc_strdup(result, param);
|
---|
379 | if (!auth_context->forced_samba4_methods) {
|
---|
380 | return NT_STATUS_NO_MEMORY;
|
---|
381 | }
|
---|
382 | }
|
---|
383 |
|
---|
384 | *auth_method = result;
|
---|
385 | return NT_STATUS_OK;
|
---|
386 | }
|
---|
387 |
|
---|
388 | NTSTATUS auth_samba4_init(void);
|
---|
389 | NTSTATUS auth_samba4_init(void)
|
---|
390 | {
|
---|
391 | smb_register_auth(AUTH_INTERFACE_VERSION, "samba4",
|
---|
392 | auth_init_samba4);
|
---|
393 | return NT_STATUS_OK;
|
---|
394 | }
|
---|