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