/src/samba/source3/auth/token_util.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Unix SMB/CIFS implementation. |
3 | | * Authentication utility functions |
4 | | * Copyright (C) Andrew Tridgell 1992-1998 |
5 | | * Copyright (C) Andrew Bartlett 2001 |
6 | | * Copyright (C) Jeremy Allison 2000-2001 |
7 | | * Copyright (C) Rafal Szczesniak 2002 |
8 | | * Copyright (C) Volker Lendecke 2006 |
9 | | * Copyright (C) Michael Adam 2007 |
10 | | * |
11 | | * This program is free software; you can redistribute it and/or modify |
12 | | * it under the terms of the GNU General Public License as published by |
13 | | * the Free Software Foundation; either version 3 of the License, or |
14 | | * (at your option) any later version. |
15 | | * |
16 | | * This program is distributed in the hope that it will be useful, |
17 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | | * GNU General Public License for more details. |
20 | | * |
21 | | * You should have received a copy of the GNU General Public License |
22 | | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
23 | | */ |
24 | | |
25 | | /* functions moved from auth/auth_util.c to minimize linker deps */ |
26 | | |
27 | | #include "includes.h" |
28 | | #include "lib/util_unixsids.h" |
29 | | #include "system/passwd.h" |
30 | | #include "auth.h" |
31 | | #include "secrets.h" |
32 | | #include "../lib/util/memcache.h" |
33 | | #include "../librpc/gen_ndr/netlogon.h" |
34 | | #include "../libcli/security/security.h" |
35 | | #include "../lib/util/util_pw.h" |
36 | | #include "passdb.h" |
37 | | #include "lib/privileges.h" |
38 | | |
39 | | /**************************************************************************** |
40 | | Check for a SID in an struct security_token |
41 | | ****************************************************************************/ |
42 | | |
43 | | bool nt_token_check_sid ( const struct dom_sid *sid, const struct security_token *token ) |
44 | 0 | { |
45 | 0 | if ( !sid || !token ) |
46 | 0 | return False; |
47 | | |
48 | 0 | return security_token_has_sid(token, sid); |
49 | 0 | } |
50 | | |
51 | | bool nt_token_check_domain_rid( struct security_token *token, uint32_t rid ) |
52 | 0 | { |
53 | 0 | struct dom_sid domain_sid; |
54 | | |
55 | | /* if we are a domain member, the get the domain SID, else for |
56 | | a DC or standalone server, use our own SID */ |
57 | |
|
58 | 0 | if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) { |
59 | 0 | if ( !secrets_fetch_domain_sid( lp_workgroup(), |
60 | 0 | &domain_sid ) ) { |
61 | 0 | DEBUG(1,("nt_token_check_domain_rid: Cannot lookup " |
62 | 0 | "SID for domain [%s]\n", lp_workgroup())); |
63 | 0 | return False; |
64 | 0 | } |
65 | 0 | } |
66 | 0 | else |
67 | 0 | sid_copy( &domain_sid, get_global_sam_sid() ); |
68 | | |
69 | 0 | sid_append_rid( &domain_sid, rid ); |
70 | |
|
71 | 0 | return nt_token_check_sid( &domain_sid, token );\ |
72 | 0 | } |
73 | | |
74 | | /****************************************************************************** |
75 | | Create a token for the root user to be used internally by smbd. |
76 | | This is similar to running under the context of the LOCAL_SYSTEM account |
77 | | in Windows. This is a read-only token. Do not modify it or free() it. |
78 | | Create a copy if you need to change it. |
79 | | ******************************************************************************/ |
80 | | |
81 | | NTSTATUS get_root_nt_token( struct security_token **token ) |
82 | 0 | { |
83 | 0 | struct security_token *for_cache; |
84 | 0 | struct dom_sid u_sid, g_sid; |
85 | 0 | struct passwd *pw; |
86 | 0 | void *cache_data; |
87 | 0 | NTSTATUS status = NT_STATUS_OK; |
88 | |
|
89 | 0 | cache_data = memcache_lookup_talloc( |
90 | 0 | NULL, SINGLETON_CACHE_TALLOC, |
91 | 0 | data_blob_string_const_null("root_nt_token")); |
92 | |
|
93 | 0 | if (cache_data != NULL) { |
94 | 0 | *token = talloc_get_type_abort( |
95 | 0 | cache_data, struct security_token); |
96 | 0 | return NT_STATUS_OK; |
97 | 0 | } |
98 | | |
99 | 0 | if ( !(pw = getpwuid(0)) ) { |
100 | 0 | if ( !(pw = getpwnam("root")) ) { |
101 | 0 | DBG_ERR("get_root_nt_token: both getpwuid(0) " |
102 | 0 | "and getpwnam(\"root\") failed!\n"); |
103 | 0 | return NT_STATUS_NO_SUCH_USER; |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | | /* get the user and primary group SIDs; although the |
108 | | BUILTIN\Administrators SId is really the one that matters here */ |
109 | | |
110 | 0 | uid_to_sid(&u_sid, pw->pw_uid); |
111 | 0 | gid_to_sid(&g_sid, pw->pw_gid); |
112 | |
|
113 | 0 | status = create_local_nt_token(talloc_tos(), &u_sid, False, |
114 | 0 | 1, &global_sid_Builtin_Administrators, token); |
115 | 0 | if (!NT_STATUS_IS_OK(status)) { |
116 | 0 | return status; |
117 | 0 | } |
118 | | |
119 | 0 | security_token_set_privilege(*token, SEC_PRIV_DISK_OPERATOR); |
120 | |
|
121 | 0 | for_cache = *token; |
122 | |
|
123 | 0 | memcache_add_talloc( |
124 | 0 | NULL, SINGLETON_CACHE_TALLOC, |
125 | 0 | data_blob_string_const_null("root_nt_token"), &for_cache); |
126 | |
|
127 | 0 | return status; |
128 | 0 | } |
129 | | |
130 | | |
131 | | /* |
132 | | * Add alias SIDs from memberships within the partially created token SID list |
133 | | */ |
134 | | |
135 | | NTSTATUS add_aliases(const struct dom_sid *domain_sid, |
136 | | struct security_token *token) |
137 | 0 | { |
138 | 0 | uint32_t *aliases; |
139 | 0 | size_t i, num_aliases; |
140 | 0 | NTSTATUS status; |
141 | 0 | TALLOC_CTX *tmp_ctx; |
142 | |
|
143 | 0 | if (!(tmp_ctx = talloc_init("add_aliases"))) { |
144 | 0 | return NT_STATUS_NO_MEMORY; |
145 | 0 | } |
146 | | |
147 | 0 | aliases = NULL; |
148 | 0 | num_aliases = 0; |
149 | |
|
150 | 0 | status = pdb_enum_alias_memberships(tmp_ctx, domain_sid, |
151 | 0 | token->sids, |
152 | 0 | token->num_sids, |
153 | 0 | &aliases, &num_aliases); |
154 | |
|
155 | 0 | if (!NT_STATUS_IS_OK(status)) { |
156 | 0 | DEBUG(10, ("pdb_enum_alias_memberships failed: %s\n", |
157 | 0 | nt_errstr(status))); |
158 | 0 | goto done; |
159 | 0 | } |
160 | | |
161 | 0 | for (i=0; i<num_aliases; i++) { |
162 | 0 | struct dom_sid alias_sid; |
163 | 0 | sid_compose(&alias_sid, domain_sid, aliases[i]); |
164 | 0 | status = add_sid_to_array_unique(token, &alias_sid, |
165 | 0 | &token->sids, |
166 | 0 | &token->num_sids); |
167 | 0 | if (!NT_STATUS_IS_OK(status)) { |
168 | 0 | DEBUG(0, ("add_sid_to_array failed\n")); |
169 | 0 | goto done; |
170 | 0 | } |
171 | 0 | } |
172 | | |
173 | 0 | done: |
174 | 0 | TALLOC_FREE(tmp_ctx); |
175 | 0 | return NT_STATUS_OK; |
176 | 0 | } |
177 | | |
178 | | /******************************************************************* |
179 | | *******************************************************************/ |
180 | | |
181 | | static NTSTATUS add_builtin_administrators(struct security_token *token, |
182 | | const struct dom_sid *dom_sid) |
183 | 0 | { |
184 | 0 | struct dom_sid domadm; |
185 | 0 | NTSTATUS status; |
186 | | |
187 | | /* nothing to do if we aren't in a domain */ |
188 | |
|
189 | 0 | if ( !(IS_DC || lp_server_role()==ROLE_DOMAIN_MEMBER) ) { |
190 | 0 | return NT_STATUS_OK; |
191 | 0 | } |
192 | | |
193 | | /* Find the Domain Admins SID */ |
194 | | |
195 | 0 | if ( IS_DC ) { |
196 | 0 | sid_copy( &domadm, get_global_sam_sid() ); |
197 | 0 | } else { |
198 | 0 | if (dom_sid == NULL) { |
199 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
200 | 0 | } |
201 | 0 | sid_copy(&domadm, dom_sid); |
202 | 0 | } |
203 | 0 | sid_append_rid( &domadm, DOMAIN_RID_ADMINS ); |
204 | | |
205 | | /* Add Administrators if the user beloongs to Domain Admins */ |
206 | |
|
207 | 0 | if ( nt_token_check_sid( &domadm, token ) ) { |
208 | 0 | status = add_sid_to_array(token, |
209 | 0 | &global_sid_Builtin_Administrators, |
210 | 0 | &token->sids, &token->num_sids); |
211 | 0 | if (!NT_STATUS_IS_OK(status)) { |
212 | 0 | return status; |
213 | 0 | } |
214 | 0 | } |
215 | | |
216 | 0 | return NT_STATUS_OK; |
217 | 0 | } |
218 | | |
219 | | static NTSTATUS add_builtin_guests(struct security_token *token, |
220 | | const struct dom_sid *dom_sid) |
221 | 0 | { |
222 | 0 | struct dom_sid tmp_sid; |
223 | 0 | NTSTATUS status; |
224 | | |
225 | | /* |
226 | | * First check the local GUEST account. |
227 | | */ |
228 | 0 | sid_compose(&tmp_sid, get_global_sam_sid(), DOMAIN_RID_GUEST); |
229 | |
|
230 | 0 | if (nt_token_check_sid(&tmp_sid, token)) { |
231 | 0 | status = add_sid_to_array_unique(token, |
232 | 0 | &global_sid_Builtin_Guests, |
233 | 0 | &token->sids, &token->num_sids); |
234 | 0 | if (!NT_STATUS_IS_OK(status)) { |
235 | 0 | return status; |
236 | 0 | } |
237 | | |
238 | 0 | return NT_STATUS_OK; |
239 | 0 | } |
240 | | |
241 | | /* |
242 | | * First check the local GUESTS group. |
243 | | */ |
244 | 0 | sid_compose(&tmp_sid, get_global_sam_sid(), DOMAIN_RID_GUESTS); |
245 | |
|
246 | 0 | if (nt_token_check_sid(&tmp_sid, token)) { |
247 | 0 | status = add_sid_to_array_unique(token, |
248 | 0 | &global_sid_Builtin_Guests, |
249 | 0 | &token->sids, &token->num_sids); |
250 | 0 | if (!NT_STATUS_IS_OK(status)) { |
251 | 0 | return status; |
252 | 0 | } |
253 | | |
254 | 0 | return NT_STATUS_OK; |
255 | 0 | } |
256 | | |
257 | 0 | if (lp_server_role() != ROLE_DOMAIN_MEMBER) { |
258 | 0 | return NT_STATUS_OK; |
259 | 0 | } |
260 | | |
261 | 0 | if (dom_sid == NULL) { |
262 | 0 | return NT_STATUS_INVALID_PARAMETER_MIX; |
263 | 0 | } |
264 | | |
265 | | /* |
266 | | * First check the domain GUESTS group. |
267 | | */ |
268 | 0 | sid_copy(&tmp_sid, dom_sid); |
269 | 0 | sid_append_rid(&tmp_sid, DOMAIN_RID_GUESTS); |
270 | |
|
271 | 0 | if (nt_token_check_sid(&tmp_sid, token)) { |
272 | 0 | status = add_sid_to_array_unique(token, |
273 | 0 | &global_sid_Builtin_Guests, |
274 | 0 | &token->sids, &token->num_sids); |
275 | 0 | if (!NT_STATUS_IS_OK(status)) { |
276 | 0 | return status; |
277 | 0 | } |
278 | | |
279 | 0 | return NT_STATUS_OK; |
280 | 0 | } |
281 | | |
282 | 0 | return NT_STATUS_OK; |
283 | 0 | } |
284 | | |
285 | | static NTSTATUS add_local_groups(struct security_token *result, |
286 | | bool is_guest); |
287 | | |
288 | | NTSTATUS get_user_sid_info3_and_extra(const struct netr_SamInfo3 *info3, |
289 | | const struct extra_auth_info *extra, |
290 | | struct dom_sid *sid) |
291 | 0 | { |
292 | | /* USER SID */ |
293 | 0 | if (info3->base.rid == (uint32_t)(-1)) { |
294 | | /* this is a signal the user was fake and generated, |
295 | | * the actual SID we want to use is stored in the extra |
296 | | * sids */ |
297 | 0 | if (is_null_sid(&extra->user_sid)) { |
298 | | /* we couldn't find the user sid, bail out */ |
299 | 0 | DEBUG(3, ("Invalid user SID\n")); |
300 | 0 | return NT_STATUS_UNSUCCESSFUL; |
301 | 0 | } |
302 | 0 | sid_copy(sid, &extra->user_sid); |
303 | 0 | } else { |
304 | 0 | sid_copy(sid, info3->base.domain_sid); |
305 | 0 | sid_append_rid(sid, info3->base.rid); |
306 | 0 | } |
307 | 0 | return NT_STATUS_OK; |
308 | 0 | } |
309 | | |
310 | | static struct security_token *init_local_nt_token(TALLOC_CTX *mem_ctx) |
311 | 0 | { |
312 | | /* |
313 | | * We do not have a method to populate the claims into this |
314 | | * buffer in the source3/ stack. When that changes, we will |
315 | | * instead make this optional based on lp_acl_claims_evaluation() |
316 | | */ |
317 | |
|
318 | 0 | struct security_token *result |
319 | 0 | = security_token_initialise(mem_ctx, |
320 | 0 | CLAIMS_EVALUATION_NEVER); |
321 | |
|
322 | 0 | if (result == NULL) { |
323 | 0 | DBG_ERR("talloc failed for security_token\n"); |
324 | 0 | return NULL; |
325 | 0 | } |
326 | | |
327 | 0 | return result; |
328 | 0 | } |
329 | | |
330 | | NTSTATUS create_local_nt_token_from_info3(TALLOC_CTX *mem_ctx, |
331 | | bool is_guest, |
332 | | const struct netr_SamInfo3 *info3, |
333 | | const struct extra_auth_info *extra, |
334 | | struct security_token **ntok) |
335 | 0 | { |
336 | 0 | struct security_token *usrtok = NULL; |
337 | 0 | uint32_t session_info_flags = 0; |
338 | 0 | NTSTATUS status; |
339 | 0 | uint32_t i; |
340 | |
|
341 | 0 | DEBUG(10, ("Create local NT token for %s\n", |
342 | 0 | info3->base.account_name.string)); |
343 | |
|
344 | 0 | usrtok = init_local_nt_token(mem_ctx); |
345 | 0 | if (!usrtok) { |
346 | 0 | return NT_STATUS_NO_MEMORY; |
347 | 0 | } |
348 | | |
349 | | /* Add the user and primary group sid FIRST */ |
350 | | /* check if the user rid is the special "Domain Guests" rid. |
351 | | * If so pick the first sid for the extra sids instead as it |
352 | | * is a local fake account */ |
353 | 0 | usrtok->sids = talloc_array(usrtok, struct dom_sid, 2); |
354 | 0 | if (!usrtok->sids) { |
355 | 0 | TALLOC_FREE(usrtok); |
356 | 0 | return NT_STATUS_NO_MEMORY; |
357 | 0 | } |
358 | 0 | usrtok->num_sids = 2; |
359 | |
|
360 | 0 | status = get_user_sid_info3_and_extra(info3, extra, &usrtok->sids[0]); |
361 | 0 | if (!NT_STATUS_IS_OK(status)) { |
362 | 0 | TALLOC_FREE(usrtok); |
363 | 0 | return status; |
364 | 0 | } |
365 | | |
366 | | /* GROUP SID */ |
367 | 0 | if (info3->base.primary_gid == (uint32_t)(-1)) { |
368 | | /* this is a signal the user was fake and generated, |
369 | | * the actual SID we want to use is stored in the extra |
370 | | * sids */ |
371 | 0 | if (is_null_sid(&extra->pgid_sid)) { |
372 | | /* we couldn't find the user sid, bail out */ |
373 | 0 | DEBUG(3, ("Invalid group SID\n")); |
374 | 0 | TALLOC_FREE(usrtok); |
375 | 0 | return NT_STATUS_UNSUCCESSFUL; |
376 | 0 | } |
377 | 0 | sid_copy(&usrtok->sids[1], &extra->pgid_sid); |
378 | 0 | } else { |
379 | 0 | sid_copy(&usrtok->sids[1], info3->base.domain_sid); |
380 | 0 | sid_append_rid(&usrtok->sids[1], |
381 | 0 | info3->base.primary_gid); |
382 | 0 | } |
383 | | |
384 | | /* Now the SIDs we got from authentication. These are the ones from |
385 | | * the info3 struct or from the pdb_enum_group_memberships, depending |
386 | | * on who authenticated the user. |
387 | | * Note that we start the for loop at "1" here, we already added the |
388 | | * first group sid as primary above. */ |
389 | | |
390 | 0 | for (i = 0; i < info3->base.groups.count; i++) { |
391 | 0 | struct dom_sid tmp_sid; |
392 | |
|
393 | 0 | sid_copy(&tmp_sid, info3->base.domain_sid); |
394 | 0 | sid_append_rid(&tmp_sid, info3->base.groups.rids[i].rid); |
395 | |
|
396 | 0 | status = add_sid_to_array_unique(usrtok, &tmp_sid, |
397 | 0 | &usrtok->sids, |
398 | 0 | &usrtok->num_sids); |
399 | 0 | if (!NT_STATUS_IS_OK(status)) { |
400 | 0 | DEBUG(3, ("Failed to add SID to nt token\n")); |
401 | 0 | TALLOC_FREE(usrtok); |
402 | 0 | return status; |
403 | 0 | } |
404 | 0 | } |
405 | | |
406 | | /* now also add extra sids if they are not the special user/group |
407 | | * sids */ |
408 | 0 | for (i = 0; i < info3->sidcount; i++) { |
409 | 0 | status = add_sid_to_array_unique(usrtok, |
410 | 0 | info3->sids[i].sid, |
411 | 0 | &usrtok->sids, |
412 | 0 | &usrtok->num_sids); |
413 | 0 | if (!NT_STATUS_IS_OK(status)) { |
414 | 0 | DEBUG(3, ("Failed to add SID to nt token\n")); |
415 | 0 | TALLOC_FREE(usrtok); |
416 | 0 | return status; |
417 | 0 | } |
418 | 0 | } |
419 | | |
420 | 0 | status = add_local_groups(usrtok, is_guest); |
421 | 0 | if (!NT_STATUS_IS_OK(status)) { |
422 | 0 | DEBUG(3, ("Failed to add local groups\n")); |
423 | 0 | TALLOC_FREE(usrtok); |
424 | 0 | return status; |
425 | 0 | } |
426 | | |
427 | 0 | session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; |
428 | 0 | if (!is_guest) { |
429 | 0 | session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED; |
430 | 0 | } |
431 | |
|
432 | 0 | status = finalize_local_nt_token(usrtok, session_info_flags); |
433 | 0 | if (!NT_STATUS_IS_OK(status)) { |
434 | 0 | DEBUG(3, ("Failed to finalize nt token\n")); |
435 | 0 | TALLOC_FREE(usrtok); |
436 | 0 | return status; |
437 | 0 | } |
438 | | |
439 | 0 | *ntok = usrtok; |
440 | 0 | return NT_STATUS_OK; |
441 | 0 | } |
442 | | |
443 | | /******************************************************************* |
444 | | Create a NT token for the user, expanding local aliases |
445 | | *******************************************************************/ |
446 | | |
447 | | NTSTATUS create_local_nt_token(TALLOC_CTX *mem_ctx, |
448 | | const struct dom_sid *user_sid, |
449 | | bool is_guest, |
450 | | int num_groupsids, |
451 | | const struct dom_sid *groupsids, |
452 | | struct security_token **token) |
453 | 0 | { |
454 | 0 | struct security_token *result = NULL; |
455 | 0 | int i; |
456 | 0 | NTSTATUS status; |
457 | 0 | uint32_t session_info_flags = 0; |
458 | 0 | struct dom_sid_buf buf; |
459 | |
|
460 | 0 | DEBUG(10, ("Create local NT token for %s\n", |
461 | 0 | dom_sid_str_buf(user_sid, &buf))); |
462 | |
|
463 | 0 | result = init_local_nt_token(mem_ctx); |
464 | 0 | if (result == NULL) { |
465 | 0 | status = NT_STATUS_NO_MEMORY; |
466 | 0 | goto err; |
467 | 0 | } |
468 | | |
469 | | /* Add the user and primary group sid */ |
470 | | |
471 | 0 | status = add_sid_to_array(result, user_sid, |
472 | 0 | &result->sids, &result->num_sids); |
473 | 0 | if (!NT_STATUS_IS_OK(status)) { |
474 | 0 | goto err; |
475 | 0 | } |
476 | | |
477 | | /* For guest, num_groupsids may be zero. */ |
478 | 0 | if (num_groupsids) { |
479 | 0 | status = add_sid_to_array(result, &groupsids[0], |
480 | 0 | &result->sids, |
481 | 0 | &result->num_sids); |
482 | 0 | if (!NT_STATUS_IS_OK(status)) { |
483 | 0 | goto err; |
484 | 0 | } |
485 | 0 | } |
486 | | |
487 | | /* Now the SIDs we got from authentication. These are the ones from |
488 | | * the info3 struct or from the pdb_enum_group_memberships, depending |
489 | | * on who authenticated the user. |
490 | | * Note that we start the for loop at "1" here, we already added the |
491 | | * first group sid as primary above. */ |
492 | | |
493 | 0 | for (i=1; i<num_groupsids; i++) { |
494 | 0 | status = add_sid_to_array_unique(result, &groupsids[i], |
495 | 0 | &result->sids, |
496 | 0 | &result->num_sids); |
497 | 0 | if (!NT_STATUS_IS_OK(status)) { |
498 | 0 | goto err; |
499 | 0 | } |
500 | 0 | } |
501 | | |
502 | 0 | status = add_local_groups(result, is_guest); |
503 | 0 | if (!NT_STATUS_IS_OK(status)) { |
504 | 0 | goto err; |
505 | 0 | } |
506 | | |
507 | 0 | session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; |
508 | 0 | if (!is_guest) { |
509 | 0 | session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED; |
510 | 0 | } |
511 | |
|
512 | 0 | status = finalize_local_nt_token(result, session_info_flags); |
513 | 0 | if (!NT_STATUS_IS_OK(status)) { |
514 | 0 | goto err; |
515 | 0 | } |
516 | | |
517 | 0 | if (is_guest) { |
518 | | /* |
519 | | * It's ugly, but for now it's |
520 | | * needed to add Builtin_Guests |
521 | | * here, the "local" token only |
522 | | * consist of S-1-22-* SIDs |
523 | | * and finalize_local_nt_token() |
524 | | * doesn't have the chance to |
525 | | * to detect it need to |
526 | | * add Builtin_Guests via |
527 | | * add_builtin_guests(). |
528 | | */ |
529 | 0 | status = add_sid_to_array_unique(result, |
530 | 0 | &global_sid_Builtin_Guests, |
531 | 0 | &result->sids, |
532 | 0 | &result->num_sids); |
533 | 0 | if (!NT_STATUS_IS_OK(status)) { |
534 | 0 | DEBUG(3, ("Failed to add SID to nt token\n")); |
535 | 0 | goto err; |
536 | 0 | } |
537 | 0 | } |
538 | | |
539 | 0 | *token = result; |
540 | 0 | return NT_STATUS_SUCCESS; |
541 | | |
542 | 0 | err: |
543 | 0 | TALLOC_FREE(result); |
544 | 0 | return status; |
545 | 0 | } |
546 | | |
547 | | /*************************************************** |
548 | | Merge in any groups from /etc/group. |
549 | | ***************************************************/ |
550 | | |
551 | | static NTSTATUS add_local_groups(struct security_token *result, |
552 | | bool is_guest) |
553 | 0 | { |
554 | 0 | gid_t *gids = NULL; |
555 | 0 | uint32_t getgroups_num_group_sids = 0; |
556 | 0 | struct passwd *pass = NULL; |
557 | 0 | TALLOC_CTX *tmp_ctx = talloc_stackframe(); |
558 | 0 | uint32_t i; |
559 | |
|
560 | 0 | if (is_guest) { |
561 | | /* |
562 | | * Guest is a special case. It's always |
563 | | * a user that can be looked up, but |
564 | | * result->sids[0] is set to DOMAIN\Guest. |
565 | | * Lookup by account name instead. |
566 | | */ |
567 | 0 | pass = Get_Pwnam_alloc(tmp_ctx, lp_guest_account()); |
568 | 0 | } else { |
569 | 0 | uid_t uid; |
570 | | |
571 | | /* For non-guest result->sids[0] is always the user sid. */ |
572 | 0 | if (!sid_to_uid(&result->sids[0], &uid)) { |
573 | | /* |
574 | | * Non-mappable SID like SYSTEM. |
575 | | * Can't be in any /etc/group groups. |
576 | | */ |
577 | 0 | TALLOC_FREE(tmp_ctx); |
578 | 0 | return NT_STATUS_OK; |
579 | 0 | } |
580 | | |
581 | 0 | pass = getpwuid_alloc(tmp_ctx, uid); |
582 | 0 | if (pass == NULL) { |
583 | 0 | struct dom_sid_buf buf; |
584 | 0 | DBG_ERR("SID %s -> getpwuid(%u) failed, is nsswitch configured?\n", |
585 | 0 | dom_sid_str_buf(&result->sids[0], &buf), |
586 | 0 | (unsigned int)uid); |
587 | 0 | TALLOC_FREE(tmp_ctx); |
588 | 0 | return NT_STATUS_NO_SUCH_USER; |
589 | 0 | } |
590 | 0 | } |
591 | | |
592 | 0 | if (!pass) { |
593 | 0 | TALLOC_FREE(tmp_ctx); |
594 | 0 | return NT_STATUS_UNSUCCESSFUL; |
595 | 0 | } |
596 | | |
597 | | /* |
598 | | * Now we must get any groups this user has been |
599 | | * added to in /etc/group and merge them in. |
600 | | * This has to be done in every code path |
601 | | * that creates an NT token, as remote users |
602 | | * may have been added to the local /etc/group |
603 | | * database. Tokens created merely from the |
604 | | * info3 structs (via the DC or via the krb5 PAC) |
605 | | * won't have these local groups. Note the |
606 | | * groups added here will only be UNIX groups |
607 | | * (S-1-22-2-XXXX groups) as getgroups_unix_user() |
608 | | * turns off winbindd before calling getgroups(). |
609 | | * |
610 | | * NB. This is duplicating work already |
611 | | * done in the 'unix_user:' case of |
612 | | * create_token_from_sid() but won't |
613 | | * do anything other than be inefficient |
614 | | * in that case. |
615 | | */ |
616 | | |
617 | 0 | if (!getgroups_unix_user(tmp_ctx, pass->pw_name, pass->pw_gid, |
618 | 0 | &gids, &getgroups_num_group_sids)) { |
619 | 0 | DEBUG(1, ("getgroups_unix_user for user %s failed\n", |
620 | 0 | pass->pw_name)); |
621 | 0 | TALLOC_FREE(tmp_ctx); |
622 | 0 | return NT_STATUS_UNSUCCESSFUL; |
623 | 0 | } |
624 | | |
625 | 0 | for (i=0; i<getgroups_num_group_sids; i++) { |
626 | 0 | NTSTATUS status; |
627 | 0 | struct dom_sid grp_sid; |
628 | 0 | gid_to_sid(&grp_sid, gids[i]); |
629 | |
|
630 | 0 | status = add_sid_to_array_unique(result, |
631 | 0 | &grp_sid, |
632 | 0 | &result->sids, |
633 | 0 | &result->num_sids); |
634 | 0 | if (!NT_STATUS_IS_OK(status)) { |
635 | 0 | DEBUG(3, ("Failed to add UNIX SID to nt token\n")); |
636 | 0 | TALLOC_FREE(tmp_ctx); |
637 | 0 | return status; |
638 | 0 | } |
639 | 0 | } |
640 | 0 | TALLOC_FREE(tmp_ctx); |
641 | 0 | return NT_STATUS_OK; |
642 | 0 | } |
643 | | |
644 | | NTSTATUS finalize_local_nt_token(struct security_token *result, |
645 | | uint32_t session_info_flags) |
646 | 0 | { |
647 | 0 | struct dom_sid _dom_sid = { 0, }; |
648 | 0 | struct dom_sid *domain_sid = NULL; |
649 | 0 | NTSTATUS status; |
650 | 0 | struct acct_info *info; |
651 | 0 | bool ok; |
652 | |
|
653 | 0 | result->privilege_mask = 0; |
654 | 0 | result->rights_mask = 0; |
655 | |
|
656 | 0 | if (result->num_sids == 0) { |
657 | 0 | return NT_STATUS_INVALID_TOKEN; |
658 | 0 | } |
659 | | |
660 | 0 | if (session_info_flags & AUTH_SESSION_INFO_DEFAULT_GROUPS) { |
661 | 0 | status = add_sid_to_array(result, &global_sid_World, |
662 | 0 | &result->sids, &result->num_sids); |
663 | 0 | if (!NT_STATUS_IS_OK(status)) { |
664 | 0 | return status; |
665 | 0 | } |
666 | 0 | status = add_sid_to_array(result, &global_sid_Network, |
667 | 0 | &result->sids, &result->num_sids); |
668 | 0 | if (!NT_STATUS_IS_OK(status)) { |
669 | 0 | return status; |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | /* |
674 | | * Don't expand nested groups of system, anonymous etc |
675 | | * |
676 | | * Note that they still get SID_WORLD and SID_NETWORK |
677 | | * for now in order let existing tests pass. |
678 | | * |
679 | | * But SYSTEM doesn't get AUTHENTICATED_USERS |
680 | | * and ANONYMOUS doesn't get BUILTIN GUESTS anymore. |
681 | | */ |
682 | 0 | if (security_token_is_anonymous(result)) { |
683 | 0 | return NT_STATUS_OK; |
684 | 0 | } |
685 | 0 | if (security_token_is_system(result)) { |
686 | 0 | result->privilege_mask = ~0; |
687 | 0 | return NT_STATUS_OK; |
688 | 0 | } |
689 | | |
690 | 0 | if (session_info_flags & AUTH_SESSION_INFO_AUTHENTICATED) { |
691 | 0 | status = add_sid_to_array(result, |
692 | 0 | &global_sid_Authenticated_Users, |
693 | 0 | &result->sids, |
694 | 0 | &result->num_sids); |
695 | 0 | if (!NT_STATUS_IS_OK(status)) { |
696 | 0 | return status; |
697 | 0 | } |
698 | 0 | } |
699 | | |
700 | | /* Add in BUILTIN sids */ |
701 | | |
702 | 0 | become_root(); |
703 | 0 | ok = secrets_fetch_domain_sid(lp_workgroup(), &_dom_sid); |
704 | 0 | if (ok) { |
705 | 0 | domain_sid = &_dom_sid; |
706 | 0 | } else { |
707 | 0 | DEBUG(3, ("Failed to fetch domain sid for %s\n", |
708 | 0 | lp_workgroup())); |
709 | 0 | } |
710 | 0 | unbecome_root(); |
711 | |
|
712 | 0 | info = talloc_zero(talloc_tos(), struct acct_info); |
713 | 0 | if (info == NULL) { |
714 | 0 | DEBUG(0, ("talloc failed!\n")); |
715 | 0 | return NT_STATUS_NO_MEMORY; |
716 | 0 | } |
717 | | |
718 | | /* Deal with the BUILTIN\Administrators group. If the SID can |
719 | | be resolved then assume that the add_aliasmem( S-1-5-32 ) |
720 | | handled it. */ |
721 | | |
722 | 0 | status = pdb_get_aliasinfo(&global_sid_Builtin_Administrators, info); |
723 | 0 | if (!NT_STATUS_IS_OK(status)) { |
724 | |
|
725 | 0 | become_root(); |
726 | 0 | status = create_builtin_administrators(domain_sid); |
727 | 0 | unbecome_root(); |
728 | |
|
729 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) { |
730 | | /* Add BUILTIN\Administrators directly to token. */ |
731 | 0 | status = add_builtin_administrators(result, domain_sid); |
732 | 0 | if ( !NT_STATUS_IS_OK(status) ) { |
733 | 0 | DEBUG(3, ("Failed to check for local " |
734 | 0 | "Administrators membership (%s)\n", |
735 | 0 | nt_errstr(status))); |
736 | 0 | } |
737 | 0 | } else if (!NT_STATUS_IS_OK(status)) { |
738 | 0 | DEBUG(2, ("WARNING: Failed to create " |
739 | 0 | "BUILTIN\\Administrators group! Can " |
740 | 0 | "Winbind allocate gids?\n")); |
741 | 0 | } |
742 | 0 | } |
743 | | |
744 | | /* Deal with the BUILTIN\Users group. If the SID can |
745 | | be resolved then assume that the add_aliasmem( S-1-5-32 ) |
746 | | handled it. */ |
747 | |
|
748 | 0 | status = pdb_get_aliasinfo(&global_sid_Builtin_Users, info); |
749 | 0 | if (!NT_STATUS_IS_OK(status)) { |
750 | |
|
751 | 0 | become_root(); |
752 | 0 | status = create_builtin_users(domain_sid); |
753 | 0 | unbecome_root(); |
754 | |
|
755 | 0 | if (!NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE) && |
756 | 0 | !NT_STATUS_IS_OK(status)) |
757 | 0 | { |
758 | 0 | DEBUG(2, ("WARNING: Failed to create BUILTIN\\Users group! " |
759 | 0 | "Can Winbind allocate gids?\n")); |
760 | 0 | } |
761 | 0 | } |
762 | | |
763 | | /* |
764 | | * Deal with the BUILTIN\Guests group. If the SID can |
765 | | * be resolved then assume that the add_aliasmem( S-1-5-32 ) |
766 | | * handled it. |
767 | | */ |
768 | 0 | status = pdb_get_aliasinfo(&global_sid_Builtin_Guests, info); |
769 | 0 | if (!NT_STATUS_IS_OK(status)) { |
770 | |
|
771 | 0 | become_root(); |
772 | 0 | status = create_builtin_guests(domain_sid); |
773 | 0 | unbecome_root(); |
774 | | |
775 | | /* |
776 | | * NT_STATUS_PROTOCOL_UNREACHABLE: |
777 | | * => winbindd is not running. |
778 | | * |
779 | | * NT_STATUS_ACCESS_DENIED: |
780 | | * => no idmap config at all |
781 | | * and wbint_AllocateGid()/winbind_allocate_gid() |
782 | | * failed. |
783 | | * |
784 | | * NT_STATUS_NO_SUCH_GROUP: |
785 | | * => no idmap config at all and |
786 | | * "tdbsam:map builtin = no" means |
787 | | * wbint_Sids2UnixIDs() fails. |
788 | | */ |
789 | 0 | if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE) || |
790 | 0 | NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) || |
791 | 0 | NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_GROUP)) { |
792 | | /* |
793 | | * Add BUILTIN\Guests directly to token. |
794 | | * But only if the token already indicates |
795 | | * real guest access by: |
796 | | * - local GUEST account |
797 | | * - local GUESTS group |
798 | | * - domain GUESTS group |
799 | | * |
800 | | * Even if a user was authenticated, it |
801 | | * can be member of a guest related group. |
802 | | */ |
803 | 0 | status = add_builtin_guests(result, domain_sid); |
804 | 0 | if (!NT_STATUS_IS_OK(status)) { |
805 | 0 | DEBUG(3, ("Failed to check for local " |
806 | 0 | "Guests membership (%s)\n", |
807 | 0 | nt_errstr(status))); |
808 | | /* |
809 | | * This is a hard error. |
810 | | */ |
811 | 0 | return status; |
812 | 0 | } |
813 | 0 | } else if (!NT_STATUS_IS_OK(status)) { |
814 | 0 | DEBUG(2, ("Failed to create " |
815 | 0 | "BUILTIN\\Guests group %s! Can " |
816 | 0 | "Winbind allocate gids?\n", |
817 | 0 | nt_errstr(status))); |
818 | | /* |
819 | | * This is a hard error. |
820 | | */ |
821 | 0 | return status; |
822 | 0 | } |
823 | 0 | } |
824 | | |
825 | 0 | TALLOC_FREE(info); |
826 | | |
827 | | /* Deal with local groups */ |
828 | |
|
829 | 0 | if (lp_winbind_nested_groups()) { |
830 | |
|
831 | 0 | become_root(); |
832 | | |
833 | | /* Now add the aliases. First the one from our local SAM */ |
834 | |
|
835 | 0 | status = add_aliases(get_global_sam_sid(), result); |
836 | |
|
837 | 0 | if (!NT_STATUS_IS_OK(status)) { |
838 | 0 | unbecome_root(); |
839 | 0 | return status; |
840 | 0 | } |
841 | | |
842 | | /* Finally the builtin ones */ |
843 | | |
844 | 0 | status = add_aliases(&global_sid_Builtin, result); |
845 | |
|
846 | 0 | if (!NT_STATUS_IS_OK(status)) { |
847 | 0 | unbecome_root(); |
848 | 0 | return status; |
849 | 0 | } |
850 | | |
851 | 0 | unbecome_root(); |
852 | 0 | } |
853 | | |
854 | 0 | if (session_info_flags & AUTH_SESSION_INFO_NTLM) { |
855 | 0 | struct dom_sid tmp_sid = { 0, }; |
856 | |
|
857 | 0 | ok = dom_sid_parse(SID_NT_NTLM_AUTHENTICATION, &tmp_sid); |
858 | 0 | if (!ok) { |
859 | 0 | return NT_STATUS_NO_MEMORY; |
860 | 0 | } |
861 | | |
862 | 0 | status = add_sid_to_array(result, |
863 | 0 | &tmp_sid, |
864 | 0 | &result->sids, |
865 | 0 | &result->num_sids); |
866 | 0 | if (!NT_STATUS_IS_OK(status)) { |
867 | 0 | return status; |
868 | 0 | } |
869 | 0 | } |
870 | | |
871 | 0 | if (session_info_flags & AUTH_SESSION_INFO_SIMPLE_PRIVILEGES) { |
872 | 0 | if (security_token_has_builtin_administrators(result)) { |
873 | 0 | result->privilege_mask = ~0; |
874 | 0 | } |
875 | 0 | } else { |
876 | | /* Add privileges based on current user sids */ |
877 | 0 | get_privileges_for_sids(&result->privilege_mask, result->sids, |
878 | 0 | result->num_sids); |
879 | 0 | } |
880 | |
|
881 | 0 | return NT_STATUS_OK; |
882 | 0 | } |
883 | | |
884 | | /**************************************************************************** |
885 | | prints a UNIX 'token' to debug output. |
886 | | ****************************************************************************/ |
887 | | |
888 | | void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid, |
889 | | int n_groups, gid_t *groups) |
890 | 0 | { |
891 | 0 | TALLOC_CTX *frame = NULL; |
892 | 0 | char *s = NULL; |
893 | 0 | int i; |
894 | |
|
895 | 0 | if (!CHECK_DEBUGLVLC(dbg_class, dbg_lev)) { |
896 | 0 | return; |
897 | 0 | } |
898 | | |
899 | 0 | frame = talloc_stackframe(); |
900 | |
|
901 | 0 | s = talloc_asprintf(frame, |
902 | 0 | "UNIX token of user %ld\n", |
903 | 0 | (long int)uid); |
904 | |
|
905 | 0 | talloc_asprintf_addbuf( |
906 | 0 | &s, |
907 | 0 | "Primary group is %ld and contains %i supplementary " |
908 | 0 | "groups\n", |
909 | 0 | (long int)gid, |
910 | 0 | n_groups); |
911 | 0 | for (i = 0; i < n_groups; i++) { |
912 | 0 | talloc_asprintf_addbuf(&s, |
913 | 0 | "Group[%3i]: %ld\n", |
914 | 0 | i, |
915 | 0 | (long int)groups[i]); |
916 | 0 | } |
917 | |
|
918 | 0 | DEBUGC(dbg_class, dbg_lev, ("%s", s ? s : "(NULL)")); |
919 | 0 | TALLOC_FREE(frame); |
920 | 0 | } |
921 | | |
922 | | /* |
923 | | * Create an artificial NT token given just a domain SID. |
924 | | * |
925 | | * We have 3 cases: |
926 | | * |
927 | | * unmapped unix users: Go directly to nss to find the user's group. |
928 | | * |
929 | | * A passdb user: The list of groups is provided by pdb_enum_group_memberships. |
930 | | * |
931 | | * If the user is provided by winbind, the primary gid is set to "domain |
932 | | * users" of the user's domain. For an explanation why this is necessary, see |
933 | | * the thread starting at |
934 | | * http://lists.samba.org/archive/samba-technical/2006-January/044803.html. |
935 | | */ |
936 | | |
937 | | static NTSTATUS create_token_from_sid(TALLOC_CTX *mem_ctx, |
938 | | const struct dom_sid *user_sid, |
939 | | bool is_guest, |
940 | | uid_t *uid, gid_t *gid, |
941 | | char **found_username, |
942 | | struct security_token **token) |
943 | 0 | { |
944 | 0 | NTSTATUS result = NT_STATUS_NO_SUCH_USER; |
945 | 0 | TALLOC_CTX *tmp_ctx = talloc_stackframe(); |
946 | 0 | gid_t *gids; |
947 | 0 | struct dom_sid *group_sids; |
948 | 0 | struct dom_sid tmp_sid; |
949 | 0 | uint32_t num_group_sids; |
950 | 0 | uint32_t num_gids; |
951 | 0 | uint32_t i; |
952 | 0 | uint32_t high, low; |
953 | 0 | bool range_ok; |
954 | 0 | struct dom_sid_buf buf; |
955 | |
|
956 | 0 | if (sid_check_is_in_our_sam(user_sid)) { |
957 | 0 | bool ret; |
958 | 0 | uint32_t pdb_num_group_sids; |
959 | | /* This is a passdb user, so ask passdb */ |
960 | |
|
961 | 0 | struct samu *sam_acct = NULL; |
962 | |
|
963 | 0 | if ( !(sam_acct = samu_new( tmp_ctx )) ) { |
964 | 0 | result = NT_STATUS_NO_MEMORY; |
965 | 0 | goto done; |
966 | 0 | } |
967 | | |
968 | 0 | become_root(); |
969 | 0 | ret = pdb_getsampwsid(sam_acct, user_sid); |
970 | 0 | unbecome_root(); |
971 | |
|
972 | 0 | if (!ret) { |
973 | 0 | DEBUG(1, ("pdb_getsampwsid(%s) failed\n", |
974 | 0 | dom_sid_str_buf(user_sid, &buf))); |
975 | 0 | DEBUGADD(1, ("Fall back to unix user\n")); |
976 | 0 | goto unix_user; |
977 | 0 | } |
978 | | |
979 | 0 | result = pdb_enum_group_memberships(tmp_ctx, sam_acct, |
980 | 0 | &group_sids, &gids, |
981 | 0 | &pdb_num_group_sids); |
982 | 0 | if (!NT_STATUS_IS_OK(result)) { |
983 | 0 | DEBUG(1, ("enum_group_memberships failed for %s: " |
984 | 0 | "%s\n", |
985 | 0 | dom_sid_str_buf(user_sid, &buf), |
986 | 0 | nt_errstr(result))); |
987 | 0 | DEBUGADD(1, ("Fall back to unix uid lookup\n")); |
988 | 0 | goto unix_user; |
989 | 0 | } |
990 | 0 | num_group_sids = pdb_num_group_sids; |
991 | | |
992 | | /* see the smb_panic() in pdb_default_enum_group_memberships */ |
993 | 0 | SMB_ASSERT(num_group_sids > 0); |
994 | | |
995 | | /* Ensure we're returning the found_username on the right context. */ |
996 | 0 | *found_username = talloc_strdup(mem_ctx, |
997 | 0 | pdb_get_username(sam_acct)); |
998 | |
|
999 | 0 | if (*found_username == NULL) { |
1000 | 0 | result = NT_STATUS_NO_MEMORY; |
1001 | 0 | goto done; |
1002 | 0 | } |
1003 | | |
1004 | | /* |
1005 | | * If the SID from lookup_name() was the guest sid, passdb knows |
1006 | | * about the mapping of guest sid to lp_guest_account() |
1007 | | * username and will return the unix_pw info for a guest |
1008 | | * user. Use it if it's there, else lookup the *uid details |
1009 | | * using Get_Pwnam_alloc(). See bug #6291 for details. JRA. |
1010 | | */ |
1011 | | |
1012 | | /* We must always assign the *uid. */ |
1013 | 0 | if (sam_acct->unix_pw == NULL) { |
1014 | 0 | struct passwd *pwd = Get_Pwnam_alloc(sam_acct, *found_username ); |
1015 | 0 | if (!pwd) { |
1016 | 0 | DEBUG(10, ("Get_Pwnam_alloc failed for %s\n", |
1017 | 0 | *found_username)); |
1018 | 0 | result = NT_STATUS_NO_SUCH_USER; |
1019 | 0 | goto done; |
1020 | 0 | } |
1021 | 0 | result = samu_set_unix(sam_acct, pwd ); |
1022 | 0 | if (!NT_STATUS_IS_OK(result)) { |
1023 | 0 | DEBUG(10, ("samu_set_unix failed for %s\n", |
1024 | 0 | *found_username)); |
1025 | 0 | result = NT_STATUS_NO_SUCH_USER; |
1026 | 0 | goto done; |
1027 | 0 | } |
1028 | 0 | } |
1029 | 0 | *uid = sam_acct->unix_pw->pw_uid; |
1030 | |
|
1031 | 0 | } else if (sid_check_is_in_unix_users(user_sid)) { |
1032 | 0 | uint32_t getgroups_num_group_sids; |
1033 | | /* This is a unix user not in passdb. We need to ask nss |
1034 | | * directly, without consulting passdb */ |
1035 | |
|
1036 | 0 | struct passwd *pass; |
1037 | | |
1038 | | /* |
1039 | | * This goto target is used as a fallback for the passdb |
1040 | | * case. The concrete bug report is when passdb gave us an |
1041 | | * unmapped gid. |
1042 | | */ |
1043 | |
|
1044 | 0 | unix_user: |
1045 | |
|
1046 | 0 | if (!sid_to_uid(user_sid, uid)) { |
1047 | 0 | DEBUG(1, ("unix_user case, sid_to_uid for %s failed\n", |
1048 | 0 | dom_sid_str_buf(user_sid, &buf))); |
1049 | 0 | result = NT_STATUS_NO_SUCH_USER; |
1050 | 0 | goto done; |
1051 | 0 | } |
1052 | | |
1053 | 0 | uid_to_unix_users_sid(*uid, &tmp_sid); |
1054 | 0 | user_sid = &tmp_sid; |
1055 | |
|
1056 | 0 | pass = getpwuid_alloc(tmp_ctx, *uid); |
1057 | 0 | if (pass == NULL) { |
1058 | 0 | DEBUG(1, ("getpwuid(%u) failed\n", |
1059 | 0 | (unsigned int)*uid)); |
1060 | 0 | goto done; |
1061 | 0 | } |
1062 | | |
1063 | 0 | if (!getgroups_unix_user(tmp_ctx, pass->pw_name, pass->pw_gid, |
1064 | 0 | &gids, &getgroups_num_group_sids)) { |
1065 | 0 | DEBUG(1, ("getgroups_unix_user for user %s failed\n", |
1066 | 0 | pass->pw_name)); |
1067 | 0 | goto done; |
1068 | 0 | } |
1069 | 0 | num_group_sids = getgroups_num_group_sids; |
1070 | |
|
1071 | 0 | group_sids = talloc_array(tmp_ctx, struct dom_sid, num_group_sids); |
1072 | 0 | if (group_sids == NULL) { |
1073 | 0 | DEBUG(1, ("talloc_array failed\n")); |
1074 | 0 | result = NT_STATUS_NO_MEMORY; |
1075 | 0 | goto done; |
1076 | 0 | } |
1077 | | |
1078 | 0 | for (i=0; i<num_group_sids; i++) { |
1079 | 0 | gid_to_sid(&group_sids[i], gids[i]); |
1080 | 0 | } |
1081 | | |
1082 | | /* In getgroups_unix_user we always set the primary gid */ |
1083 | 0 | SMB_ASSERT(num_group_sids > 0); |
1084 | | |
1085 | | /* Ensure we're returning the found_username on the right context. */ |
1086 | 0 | *found_username = talloc_strdup(mem_ctx, pass->pw_name); |
1087 | 0 | if (*found_username == NULL) { |
1088 | 0 | result = NT_STATUS_NO_MEMORY; |
1089 | 0 | goto done; |
1090 | 0 | } |
1091 | 0 | } else { |
1092 | | |
1093 | | /* This user is from winbind, force the primary gid to the |
1094 | | * user's "domain users" group. Under certain circumstances |
1095 | | * (user comes from NT4), this might be a loss of |
1096 | | * information. But we can not rely on winbind getting the |
1097 | | * correct info. AD might prohibit winbind looking up that |
1098 | | * information. */ |
1099 | | |
1100 | | /* We must always assign the *uid. */ |
1101 | 0 | if (!sid_to_uid(user_sid, uid)) { |
1102 | 0 | DEBUG(1, ("winbindd case, sid_to_uid for %s failed\n", |
1103 | 0 | dom_sid_str_buf(user_sid, &buf))); |
1104 | 0 | result = NT_STATUS_NO_SUCH_USER; |
1105 | 0 | goto done; |
1106 | 0 | } |
1107 | | |
1108 | 0 | num_group_sids = 1; |
1109 | 0 | group_sids = talloc_array(tmp_ctx, struct dom_sid, num_group_sids); |
1110 | 0 | if (group_sids == NULL) { |
1111 | 0 | DEBUG(1, ("talloc_array failed\n")); |
1112 | 0 | result = NT_STATUS_NO_MEMORY; |
1113 | 0 | goto done; |
1114 | 0 | } |
1115 | | |
1116 | 0 | gids = talloc_array(tmp_ctx, gid_t, num_group_sids); |
1117 | 0 | if (gids == NULL) { |
1118 | 0 | result = NT_STATUS_NO_MEMORY; |
1119 | 0 | goto done; |
1120 | 0 | } |
1121 | | |
1122 | 0 | sid_copy(&group_sids[0], user_sid); |
1123 | 0 | sid_split_rid(&group_sids[0], NULL); |
1124 | 0 | sid_append_rid(&group_sids[0], DOMAIN_RID_USERS); |
1125 | |
|
1126 | 0 | if (!sid_to_gid(&group_sids[0], &gids[0])) { |
1127 | 0 | DEBUG(1, ("sid_to_gid(%s) failed\n", |
1128 | 0 | dom_sid_str_buf(&group_sids[0], &buf))); |
1129 | 0 | goto done; |
1130 | 0 | } |
1131 | | |
1132 | 0 | *found_username = NULL; |
1133 | 0 | } |
1134 | | |
1135 | 0 | *gid = gids[0]; |
1136 | | |
1137 | | /* Add the "Unix Group" SID for each gid to catch mapped groups |
1138 | | and their Unix equivalent. This is to solve the backwards |
1139 | | compatibility problem of 'valid users = +ntadmin' where |
1140 | | ntadmin has been paired with "Domain Admins" in the group |
1141 | | mapping table. Otherwise smb.conf would need to be changed |
1142 | | to 'valid user = "Domain Admins"'. --jerry */ |
1143 | |
|
1144 | 0 | num_gids = num_group_sids; |
1145 | 0 | range_ok = lp_idmap_default_range(&low, &high); |
1146 | 0 | for ( i=0; i<num_gids; i++ ) { |
1147 | 0 | struct dom_sid unix_group_sid; |
1148 | | |
1149 | | /* don't pickup anything managed by Winbind */ |
1150 | 0 | if (range_ok && (gids[i] >= low) && (gids[i] <= high)) { |
1151 | 0 | continue; |
1152 | 0 | } |
1153 | | |
1154 | 0 | gid_to_unix_groups_sid(gids[i], &unix_group_sid); |
1155 | |
|
1156 | 0 | result = add_sid_to_array_unique(tmp_ctx, &unix_group_sid, |
1157 | 0 | &group_sids, &num_group_sids); |
1158 | 0 | if (!NT_STATUS_IS_OK(result)) { |
1159 | 0 | goto done; |
1160 | 0 | } |
1161 | 0 | } |
1162 | | |
1163 | | /* Ensure we're creating the nt_token on the right context. */ |
1164 | 0 | result = create_local_nt_token(mem_ctx, user_sid, |
1165 | 0 | is_guest, num_group_sids, group_sids, token); |
1166 | |
|
1167 | 0 | if (!NT_STATUS_IS_OK(result)) { |
1168 | 0 | goto done; |
1169 | 0 | } |
1170 | | |
1171 | 0 | result = NT_STATUS_OK; |
1172 | 0 | done: |
1173 | 0 | TALLOC_FREE(tmp_ctx); |
1174 | 0 | return result; |
1175 | 0 | } |
1176 | | |
1177 | | /* |
1178 | | * Create an artificial NT token given just a username. (Initially intended |
1179 | | * for force user) |
1180 | | * |
1181 | | * We go through lookup_name() to avoid problems we had with 'winbind use |
1182 | | * default domain'. |
1183 | | * |
1184 | | * We have 3 cases: |
1185 | | * |
1186 | | * unmapped unix users: Go directly to nss to find the user's group. |
1187 | | * |
1188 | | * A passdb user: The list of groups is provided by pdb_enum_group_memberships. |
1189 | | * |
1190 | | * If the user is provided by winbind, the primary gid is set to "domain |
1191 | | * users" of the user's domain. For an explanation why this is necessary, see |
1192 | | * the thread starting at |
1193 | | * http://lists.samba.org/archive/samba-technical/2006-January/044803.html. |
1194 | | */ |
1195 | | |
1196 | | NTSTATUS create_token_from_username(TALLOC_CTX *mem_ctx, const char *username, |
1197 | | bool is_guest, |
1198 | | uid_t *uid, gid_t *gid, |
1199 | | char **found_username, |
1200 | | struct security_token **token) |
1201 | 0 | { |
1202 | 0 | NTSTATUS result = NT_STATUS_NO_SUCH_USER; |
1203 | 0 | TALLOC_CTX *tmp_ctx = talloc_stackframe(); |
1204 | 0 | struct dom_sid user_sid; |
1205 | 0 | enum lsa_SidType type; |
1206 | |
|
1207 | 0 | if (!lookup_name_smbconf(tmp_ctx, username, LOOKUP_NAME_ALL, |
1208 | 0 | NULL, NULL, &user_sid, &type)) { |
1209 | 0 | DEBUG(1, ("lookup_name_smbconf for %s failed\n", username)); |
1210 | 0 | goto done; |
1211 | 0 | } |
1212 | | |
1213 | 0 | if (type != SID_NAME_USER) { |
1214 | 0 | DEBUG(1, ("%s is a %s, not a user\n", username, |
1215 | 0 | sid_type_lookup(type))); |
1216 | 0 | goto done; |
1217 | 0 | } |
1218 | | |
1219 | 0 | result = create_token_from_sid(mem_ctx, &user_sid, is_guest, uid, gid, found_username, token); |
1220 | |
|
1221 | 0 | if (!NT_STATUS_IS_OK(result)) { |
1222 | 0 | goto done; |
1223 | 0 | } |
1224 | | |
1225 | | /* |
1226 | | * If result == NT_STATUS_OK then |
1227 | | * we know we have a valid token. Ensure |
1228 | | * we also have a valid username to match. |
1229 | | */ |
1230 | | |
1231 | 0 | if (*found_username == NULL) { |
1232 | 0 | *found_username = talloc_strdup(mem_ctx, username); |
1233 | 0 | if (*found_username == NULL) { |
1234 | 0 | result = NT_STATUS_NO_MEMORY; |
1235 | 0 | } |
1236 | 0 | } |
1237 | |
|
1238 | 0 | done: |
1239 | 0 | TALLOC_FREE(tmp_ctx); |
1240 | 0 | return result; |
1241 | 0 | } |
1242 | | |
1243 | | /*************************************************************************** |
1244 | | Build upon create_token_from_sid: |
1245 | | |
1246 | | Expensive helper function to figure out whether a user given its sid is |
1247 | | member of a particular group. |
1248 | | ***************************************************************************/ |
1249 | | |
1250 | | bool user_sid_in_group_sid(const struct dom_sid *sid, const struct dom_sid *group_sid) |
1251 | 0 | { |
1252 | 0 | NTSTATUS status; |
1253 | 0 | uid_t uid; |
1254 | 0 | gid_t gid; |
1255 | 0 | char *found_username; |
1256 | 0 | struct security_token *token; |
1257 | 0 | bool result = false; |
1258 | 0 | enum lsa_SidType type; |
1259 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1260 | 0 | struct dom_sid_buf buf; |
1261 | |
|
1262 | 0 | if (!lookup_sid(mem_ctx, sid, |
1263 | 0 | NULL, NULL, &type)) { |
1264 | 0 | DEBUG(1, ("lookup_sid for %s failed\n", |
1265 | 0 | dom_sid_str_buf(sid, &buf))); |
1266 | 0 | goto done; |
1267 | 0 | } |
1268 | | |
1269 | 0 | if (type != SID_NAME_USER) { |
1270 | 0 | DEBUG(5, ("%s is a %s, not a user\n", |
1271 | 0 | dom_sid_str_buf(sid, &buf), |
1272 | 0 | sid_type_lookup(type))); |
1273 | 0 | goto done; |
1274 | 0 | } |
1275 | | |
1276 | 0 | status = create_token_from_sid(mem_ctx, sid, False, |
1277 | 0 | &uid, &gid, &found_username, |
1278 | 0 | &token); |
1279 | |
|
1280 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1281 | 0 | DEBUG(10, ("could not create token for %s\n", |
1282 | 0 | dom_sid_str_buf(sid, &buf))); |
1283 | 0 | goto done; |
1284 | 0 | } |
1285 | | |
1286 | 0 | result = security_token_has_sid(token, group_sid); |
1287 | |
|
1288 | 0 | done: |
1289 | 0 | TALLOC_FREE(mem_ctx); |
1290 | 0 | return result; |
1291 | 0 | } |
1292 | | |
1293 | | /*************************************************************************** |
1294 | | Build upon create_token_from_username: |
1295 | | |
1296 | | Expensive helper function to figure out whether a user given its name is |
1297 | | member of a particular group. |
1298 | | ***************************************************************************/ |
1299 | | |
1300 | | bool user_in_group_sid(const char *username, const struct dom_sid *group_sid) |
1301 | 0 | { |
1302 | 0 | NTSTATUS status; |
1303 | 0 | uid_t uid; |
1304 | 0 | gid_t gid; |
1305 | 0 | char *found_username; |
1306 | 0 | struct security_token *token; |
1307 | 0 | bool result; |
1308 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1309 | |
|
1310 | 0 | status = create_token_from_username(mem_ctx, username, False, |
1311 | 0 | &uid, &gid, &found_username, |
1312 | 0 | &token); |
1313 | |
|
1314 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1315 | 0 | DEBUG(10, ("could not create token for %s\n", username)); |
1316 | 0 | TALLOC_FREE(mem_ctx); |
1317 | 0 | return False; |
1318 | 0 | } |
1319 | | |
1320 | 0 | result = security_token_has_sid(token, group_sid); |
1321 | |
|
1322 | 0 | TALLOC_FREE(mem_ctx); |
1323 | 0 | return result; |
1324 | 0 | } |
1325 | | |
1326 | | bool user_in_group(const char *username, const char *groupname) |
1327 | 0 | { |
1328 | 0 | TALLOC_CTX *mem_ctx = talloc_stackframe(); |
1329 | 0 | struct dom_sid group_sid; |
1330 | 0 | bool ret; |
1331 | |
|
1332 | 0 | ret = lookup_name(mem_ctx, groupname, LOOKUP_NAME_ALL, |
1333 | 0 | NULL, NULL, &group_sid, NULL); |
1334 | 0 | TALLOC_FREE(mem_ctx); |
1335 | |
|
1336 | 0 | if (!ret) { |
1337 | 0 | DEBUG(10, ("lookup_name for (%s) failed.\n", groupname)); |
1338 | 0 | return False; |
1339 | 0 | } |
1340 | | |
1341 | 0 | return user_in_group_sid(username, &group_sid); |
1342 | 0 | } |
1343 | | |
1344 | | /* END */ |