auth:kerberos: Fix resource leak in parse_principal()
[samba4-gss.git] / source4 / auth / session.c
blob70dc4b19f9da71384f2b43aabdfe9b1f2fe494c4
1 /*
2 Unix SMB/CIFS implementation.
3 Authentication utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001-2010
6 Copyright (C) Jeremy Allison 2000-2001
7 Copyright (C) Rafal Szczesniak 2002
8 Copyright (C) Stefan Metzmacher 2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "auth/auth.h"
26 #include "auth/auth_sam.h"
27 #include "auth/credentials/credentials.h"
28 #include "auth/credentials/credentials_krb5.h"
29 #include "libcli/security/security.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "auth/session_proto.h"
33 #include "system/kerberos.h"
34 #include <gssapi/gssapi.h>
35 #include "libcli/wbclient/wbclient.h"
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_AUTH
40 _PUBLIC_ struct auth_session_info *anonymous_session(TALLOC_CTX *mem_ctx,
41 struct loadparm_context *lp_ctx)
43 NTSTATUS nt_status;
44 struct auth_session_info *session_info = NULL;
45 nt_status = auth_anonymous_session_info(mem_ctx, lp_ctx, &session_info);
46 if (!NT_STATUS_IS_OK(nt_status)) {
47 return NULL;
49 return session_info;
52 _PUBLIC_ NTSTATUS auth_generate_security_token(TALLOC_CTX *mem_ctx,
53 struct loadparm_context *lp_ctx, /* Optional, if you don't want privileges */
54 struct ldb_context *sam_ctx, /* Optional, if you don't want local groups */
55 const struct auth_user_info_dc *user_info_dc,
56 uint32_t session_info_flags,
57 struct security_token **_security_token)
59 struct security_token *security_token = NULL;
60 NTSTATUS nt_status;
61 uint32_t i;
62 uint32_t num_sids = 0;
63 const char *filter = NULL;
64 struct auth_SidAttr *sids = NULL;
65 const struct dom_sid *anonymous_sid = NULL;
66 const struct dom_sid *system_sid = NULL;
68 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
69 if (tmp_ctx == NULL) {
70 return NT_STATUS_NO_MEMORY;
73 anonymous_sid = dom_sid_parse_talloc(tmp_ctx, SID_NT_ANONYMOUS);
74 if (anonymous_sid == NULL) {
75 TALLOC_FREE(tmp_ctx);
76 return NT_STATUS_NO_MEMORY;
79 system_sid = dom_sid_parse_talloc(tmp_ctx, SID_NT_SYSTEM);
80 if (system_sid == NULL) {
81 TALLOC_FREE(tmp_ctx);
82 return NT_STATUS_NO_MEMORY;
85 sids = talloc_array(tmp_ctx, struct auth_SidAttr, user_info_dc->num_sids);
86 if (sids == NULL) {
87 TALLOC_FREE(tmp_ctx);
88 return NT_STATUS_NO_MEMORY;
91 num_sids = user_info_dc->num_sids;
93 for (i=0; i < user_info_dc->num_sids; i++) {
94 sids[i] = user_info_dc->sids[i];
98 * Finally add the "standard" sids.
99 * The only difference between guest and "anonymous"
100 * is the addition of Authenticated_Users.
103 if (session_info_flags & AUTH_SESSION_INFO_DEFAULT_GROUPS) {
104 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 2);
105 if (sids == NULL) {
106 TALLOC_FREE(tmp_ctx);
107 return NT_STATUS_NO_MEMORY;
110 sid_copy(&sids[num_sids].sid, &global_sid_World);
111 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
112 num_sids++;
114 sid_copy(&sids[num_sids].sid, &global_sid_Network);
115 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
116 num_sids++;
119 if (session_info_flags & AUTH_SESSION_INFO_AUTHENTICATED) {
120 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
121 if (sids == NULL) {
122 TALLOC_FREE(tmp_ctx);
123 return NT_STATUS_NO_MEMORY;
126 sid_copy(&sids[num_sids].sid, &global_sid_Authenticated_Users);
127 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
128 num_sids++;
131 if (session_info_flags & AUTH_SESSION_INFO_NTLM) {
132 sids = talloc_realloc(tmp_ctx, sids, struct auth_SidAttr, num_sids + 1);
133 if (sids == NULL) {
134 TALLOC_FREE(tmp_ctx);
135 return NT_STATUS_NO_MEMORY;
138 if (!dom_sid_parse(SID_NT_NTLM_AUTHENTICATION, &sids[num_sids].sid)) {
139 TALLOC_FREE(tmp_ctx);
140 return NT_STATUS_INTERNAL_ERROR;
142 sids[num_sids].attrs = SE_GROUP_DEFAULT_FLAGS;
143 num_sids++;
147 if (num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(anonymous_sid, &sids[PRIMARY_USER_SID_INDEX].sid)) {
148 /* Don't expand nested groups of system, anonymous etc*/
149 } else if (num_sids > PRIMARY_USER_SID_INDEX && dom_sid_equal(system_sid, &sids[PRIMARY_USER_SID_INDEX].sid)) {
150 /* Don't expand nested groups of system, anonymous etc*/
151 } else if (sam_ctx != NULL) {
152 filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:"LDB_OID_COMPARATOR_AND":=%u))",
153 GROUP_TYPE_BUILTIN_LOCAL_GROUP);
155 /* Search for each group in the token */
156 for (i = 0; i < num_sids; i++) {
157 struct dom_sid_buf buf;
158 const char *sid_dn;
159 DATA_BLOB sid_blob;
161 sid_dn = talloc_asprintf(
162 tmp_ctx,
163 "<SID=%s>",
164 dom_sid_str_buf(&sids[i].sid, &buf));
165 if (sid_dn == NULL) {
166 TALLOC_FREE(tmp_ctx);
167 return NT_STATUS_NO_MEMORY;
169 sid_blob = data_blob_string_const(sid_dn);
171 /* This function takes in memberOf values and expands
172 * them, as long as they meet the filter - so only
173 * builtin groups
175 * We already have the SID in the token, so set
176 * 'only childs' flag to true */
177 nt_status = dsdb_expand_nested_groups(sam_ctx, &sid_blob, true, filter,
178 tmp_ctx, &sids, &num_sids);
179 if (!NT_STATUS_IS_OK(nt_status)) {
180 talloc_free(tmp_ctx);
181 return nt_status;
186 nt_status = security_token_create(mem_ctx,
187 lp_ctx,
188 num_sids,
189 sids,
190 session_info_flags,
191 &security_token);
192 if (!NT_STATUS_IS_OK(nt_status)) {
193 TALLOC_FREE(tmp_ctx);
194 return nt_status;
197 talloc_steal(mem_ctx, security_token);
198 *_security_token = security_token;
199 talloc_free(tmp_ctx);
200 return NT_STATUS_OK;
203 _PUBLIC_ NTSTATUS auth_generate_session_info(TALLOC_CTX *mem_ctx,
204 struct loadparm_context *lp_ctx, /* Optional, if you don't want privileges */
205 struct ldb_context *sam_ctx, /* Optional, if you don't want local groups */
206 const struct auth_user_info_dc *user_info_dc,
207 uint32_t session_info_flags,
208 struct auth_session_info **_session_info)
210 struct auth_session_info *session_info;
211 NTSTATUS nt_status;
213 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
214 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
216 session_info = talloc_zero(tmp_ctx, struct auth_session_info);
217 if (session_info == NULL) {
218 TALLOC_FREE(tmp_ctx);
219 return NT_STATUS_NO_MEMORY;
222 session_info->info = talloc_reference(session_info, user_info_dc->info);
224 session_info->torture = talloc_zero(session_info, struct auth_user_info_torture);
225 if (session_info->torture == NULL) {
226 TALLOC_FREE(tmp_ctx);
227 return NT_STATUS_NO_MEMORY;
229 session_info->torture->num_dc_sids = user_info_dc->num_sids;
230 session_info->torture->dc_sids = talloc_reference(session_info, user_info_dc->sids);
231 if (session_info->torture->dc_sids == NULL) {
232 TALLOC_FREE(tmp_ctx);
233 return NT_STATUS_NO_MEMORY;
236 /* unless set otherwise, the session key is the user session
237 * key from the auth subsystem */
238 session_info->session_key = data_blob_talloc(session_info, user_info_dc->user_session_key.data, user_info_dc->user_session_key.length);
239 if (!session_info->session_key.data && session_info->session_key.length) {
240 if (session_info->session_key.data == NULL) {
241 TALLOC_FREE(tmp_ctx);
242 return NT_STATUS_NO_MEMORY;
246 nt_status = auth_generate_security_token(session_info,
247 lp_ctx,
248 sam_ctx,
249 user_info_dc,
250 session_info_flags,
251 &session_info->security_token);
252 if (!NT_STATUS_IS_OK(nt_status)) {
253 TALLOC_FREE(tmp_ctx);
254 return nt_status;
257 session_info->unique_session_token = GUID_random();
259 session_info->credentials = NULL;
261 session_info->ticket_type = user_info_dc->ticket_type;
263 talloc_steal(mem_ctx, session_info);
264 *_session_info = session_info;
265 talloc_free(tmp_ctx);
266 return NT_STATUS_OK;
270 /* Fill out the auth_session_info with a cli_credentials based on the
271 * auth_session_info we were forwarded over named pipe forwarding.
273 * NOTE: The stucture members of session_info_transport are stolen
274 * with talloc_move() into auth_session_info for long term use
276 struct auth_session_info *auth_session_info_from_transport(TALLOC_CTX *mem_ctx,
277 struct auth_session_info_transport *session_info_transport,
278 struct loadparm_context *lp_ctx,
279 const char **reason)
281 struct auth_session_info *session_info;
282 session_info = talloc_steal(mem_ctx, session_info_transport->session_info);
284 * This is to allow us to check the type of this pointer using
285 * talloc_get_type()
287 talloc_set_name(session_info, "struct auth_session_info");
288 #ifdef HAVE_GSS_IMPORT_CRED
289 if (session_info_transport->exported_gssapi_credentials.length) {
290 struct cli_credentials *creds;
291 OM_uint32 minor_status;
292 gss_buffer_desc cred_token;
293 gss_cred_id_t cred_handle;
294 const char *error_string;
295 int ret;
296 bool ok;
298 DEBUG(10, ("Delegated credentials supplied by client\n"));
300 cred_token.value = session_info_transport->exported_gssapi_credentials.data;
301 cred_token.length = session_info_transport->exported_gssapi_credentials.length;
303 ret = gss_import_cred(&minor_status,
304 &cred_token,
305 &cred_handle);
306 if (ret != GSS_S_COMPLETE) {
307 *reason = "Internal error in gss_import_cred()";
308 return NULL;
311 creds = cli_credentials_init(session_info);
312 if (!creds) {
313 *reason = "Out of memory in cli_credentials_init()";
314 return NULL;
316 session_info->credentials = creds;
318 ok = cli_credentials_set_conf(creds, lp_ctx);
319 if (!ok) {
320 *reason = "Failed to load smb.conf";
321 return NULL;
324 /* Just so we don't segfault trying to get at a username */
325 cli_credentials_set_anonymous(creds);
327 ret = cli_credentials_set_client_gss_creds(creds,
328 lp_ctx,
329 cred_handle,
330 CRED_SPECIFIED,
331 &error_string);
332 if (ret) {
333 *reason = talloc_asprintf(mem_ctx,
334 "Failed to set pipe forwarded"
335 "creds: %s\n", error_string);
336 return NULL;
339 /* This credential handle isn't useful for password
340 * authentication, so ensure nobody tries to do that */
341 cli_credentials_set_kerberos_state(creds,
342 CRED_USE_KERBEROS_REQUIRED,
343 CRED_SPECIFIED);
346 #endif
347 return session_info;
351 /* Create a auth_session_info_transport from an auth_session_info.
353 * NOTE: Members of the auth_session_info_transport structure are
354 * talloc_referenced() into this structure, and should not be changed.
356 NTSTATUS auth_session_info_transport_from_session(TALLOC_CTX *mem_ctx,
357 struct auth_session_info *session_info,
358 struct tevent_context *event_ctx,
359 struct loadparm_context *lp_ctx,
360 struct auth_session_info_transport **transport_out)
363 struct auth_session_info_transport *session_info_transport
364 = talloc_zero(mem_ctx, struct auth_session_info_transport);
365 if (!session_info_transport) {
366 return NT_STATUS_NO_MEMORY;
368 session_info_transport->session_info = talloc_reference(session_info_transport, session_info);
369 if (!session_info_transport->session_info) {
370 return NT_STATUS_NO_MEMORY;
372 #ifdef HAVE_GSS_EXPORT_CRED
373 if (session_info->credentials) {
374 struct gssapi_creds_container *gcc;
375 OM_uint32 gret;
376 OM_uint32 minor_status;
377 gss_buffer_desc cred_token;
378 const char *error_string;
379 int ret;
381 ret = cli_credentials_get_client_gss_creds(session_info->credentials,
382 event_ctx,
383 lp_ctx,
384 &gcc, &error_string);
385 if (ret != 0) {
386 *transport_out = session_info_transport;
387 return NT_STATUS_OK;
390 gret = gss_export_cred(&minor_status,
391 gcc->creds,
392 &cred_token);
393 if (gret != GSS_S_COMPLETE) {
394 return NT_STATUS_INTERNAL_ERROR;
397 if (cred_token.length) {
398 session_info_transport->exported_gssapi_credentials
399 = data_blob_talloc(session_info_transport,
400 cred_token.value,
401 cred_token.length);
402 gss_release_buffer(&minor_status, &cred_token);
403 NT_STATUS_HAVE_NO_MEMORY(session_info_transport->exported_gssapi_credentials.data);
406 #endif
407 *transport_out = session_info_transport;
408 return NT_STATUS_OK;
412 /* Produce a session_info for an arbitary DN or principal in the local
413 * DB, assuming the local DB holds all the groups
415 * Supply either a principal or a DN
417 NTSTATUS authsam_get_session_info_principal(TALLOC_CTX *mem_ctx,
418 struct loadparm_context *lp_ctx,
419 struct ldb_context *sam_ctx,
420 const char *principal,
421 struct ldb_dn *user_dn,
422 uint32_t session_info_flags,
423 struct auth_session_info **session_info)
425 NTSTATUS nt_status;
426 struct auth_user_info_dc *user_info_dc;
427 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
428 if (!tmp_ctx) {
429 return NT_STATUS_NO_MEMORY;
431 nt_status = authsam_get_user_info_dc_principal(tmp_ctx, lp_ctx, sam_ctx,
432 principal, user_dn,
433 &user_info_dc);
434 if (!NT_STATUS_IS_OK(nt_status)) {
435 talloc_free(tmp_ctx);
436 return nt_status;
439 nt_status = auth_generate_session_info(tmp_ctx, lp_ctx, sam_ctx,
440 user_info_dc, session_info_flags,
441 session_info);
443 if (NT_STATUS_IS_OK(nt_status)) {
444 talloc_steal(mem_ctx, *session_info);
446 talloc_free(tmp_ctx);
447 return nt_status;
451 * prints a struct auth_session_info security token to debug output.
453 void auth_session_info_debug(int dbg_lev,
454 const struct auth_session_info *session_info)
456 if (!session_info) {
457 DEBUG(dbg_lev, ("Session Info: (NULL)\n"));
458 return;
461 security_token_debug(DBGC_AUTH, dbg_lev,
462 session_info->security_token);