source: branches/samba-3.5.x/source4/dsdb/common/sidmap.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 15.1 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 mapping routines for SID <-> unix uid/gid
5
6 Copyright (C) Andrew Tridgell 2004
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "system/passwd.h"
24#include "../libds/common/flags.h"
25#include "dsdb/samdb/samdb.h"
26#include "auth/auth.h"
27#include "libcli/ldap/ldap_ndr.h"
28#include "lib/ldb/include/ldb.h"
29#include "../lib/util/util_ldb.h"
30#include "libcli/security/security.h"
31#include "param/param.h"
32
33/*
34 these are used for the fallback local uid/gid to sid mapping
35 code.
36*/
37#define SIDMAP_LOCAL_USER_BASE 0x80000000
38#define SIDMAP_LOCAL_GROUP_BASE 0xC0000000
39#define SIDMAP_MAX_LOCAL_UID 0x3fffffff
40#define SIDMAP_MAX_LOCAL_GID 0x3fffffff
41
42/*
43 private context for sid mapping routines
44*/
45struct sidmap_context {
46 struct ldb_context *samctx;
47};
48
49/*
50 open a sidmap context - use talloc_free to close
51*/
52struct sidmap_context *sidmap_open(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx,
53 struct loadparm_context *lp_ctx)
54{
55 struct sidmap_context *sidmap;
56 sidmap = talloc(mem_ctx, struct sidmap_context);
57 if (sidmap == NULL) {
58 return NULL;
59 }
60 sidmap->samctx = samdb_connect(sidmap, ev_ctx, lp_ctx, system_session(sidmap, lp_ctx));
61 if (sidmap->samctx == NULL) {
62 talloc_free(sidmap);
63 return NULL;
64 }
65
66 return sidmap;
67}
68
69
70/*
71 check the sAMAccountType field of a search result to see if
72 the account is a user account
73*/
74static bool is_user_account(struct ldb_message *res)
75{
76 uint_t atype = samdb_result_uint(res, "sAMAccountType", 0);
77 if (atype && (!(atype & ATYPE_ACCOUNT))) {
78 return false;
79 }
80 return true;
81}
82
83/*
84 check the sAMAccountType field of a search result to see if
85 the account is a group account
86*/
87static bool is_group_account(struct ldb_message *res)
88{
89 uint_t atype = samdb_result_uint(res, "sAMAccountType", 0);
90 if (atype && atype == ATYPE_NORMAL_ACCOUNT) {
91 return false;
92 }
93 return true;
94}
95
96
97
98/*
99 return the dom_sid of our primary domain
100*/
101static NTSTATUS sidmap_primary_domain_sid(struct sidmap_context *sidmap,
102 TALLOC_CTX *mem_ctx, struct dom_sid **sid)
103{
104 const char *attrs[] = { "objectSid", NULL };
105 int ret;
106 struct ldb_message **res = NULL;
107
108 ret = gendb_search_dn(sidmap->samctx, mem_ctx, NULL, &res, attrs);
109 if (ret != 1) {
110 talloc_free(res);
111 return NT_STATUS_NO_SUCH_DOMAIN;
112 }
113
114 *sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
115 talloc_free(res);
116 if (*sid == NULL) {
117 return NT_STATUS_NO_MEMORY;
118 }
119
120 return NT_STATUS_OK;
121}
122
123
124/*
125 map a sid to a unix uid
126*/
127NTSTATUS sidmap_sid_to_unixuid(struct sidmap_context *sidmap,
128 const struct dom_sid *sid, uid_t *uid)
129{
130 const char *attrs[] = { "sAMAccountName", "uidNumber",
131 "sAMAccountType", "unixName", NULL };
132 int ret;
133 const char *s;
134 TALLOC_CTX *tmp_ctx;
135 struct ldb_message **res;
136 struct dom_sid *domain_sid;
137 NTSTATUS status;
138
139 tmp_ctx = talloc_new(sidmap);
140
141 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
142 "objectSid=%s",
143 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
144
145 if (ret != 1) {
146 goto allocated_sid;
147 }
148
149 /* make sure its a user, not a group */
150 if (!is_user_account(res[0])) {
151 DEBUG(0,("sid_to_unixuid: sid %s is not an account!\n",
152 dom_sid_string(tmp_ctx, sid)));
153 talloc_free(tmp_ctx);
154 return NT_STATUS_INVALID_SID;
155 }
156
157 /* first try to get the uid directly */
158 s = samdb_result_string(res[0], "uidNumber", NULL);
159 if (s != NULL) {
160 *uid = strtoul(s, NULL, 0);
161 talloc_free(tmp_ctx);
162 return NT_STATUS_OK;
163 }
164
165 /* next try via the UnixName attribute */
166 s = samdb_result_string(res[0], "unixName", NULL);
167 if (s != NULL) {
168 struct passwd *pwd = getpwnam(s);
169 if (!pwd) {
170 DEBUG(0,("unixName %s for sid %s does not exist as a local user\n", s,
171 dom_sid_string(tmp_ctx, sid)));
172 talloc_free(tmp_ctx);
173 return NT_STATUS_NO_SUCH_USER;
174 }
175 *uid = pwd->pw_uid;
176 talloc_free(tmp_ctx);
177 return NT_STATUS_OK;
178 }
179
180 /* finally try via the sAMAccountName attribute */
181 s = samdb_result_string(res[0], "sAMAccountName", NULL);
182 if (s != NULL) {
183 struct passwd *pwd = getpwnam(s);
184 if (!pwd) {
185 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n",
186 s, dom_sid_string(tmp_ctx, sid)));
187 talloc_free(tmp_ctx);
188 return NT_STATUS_NO_SUCH_USER;
189 }
190 *uid = pwd->pw_uid;
191 talloc_free(tmp_ctx);
192 return NT_STATUS_OK;
193 }
194
195
196allocated_sid:
197 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
198 if (!NT_STATUS_IS_OK(status)) {
199 talloc_free(tmp_ctx);
200 return NT_STATUS_NO_SUCH_DOMAIN;
201 }
202
203 if (dom_sid_in_domain(domain_sid, sid)) {
204 uint32_t rid = sid->sub_auths[sid->num_auths-1];
205 if (rid >= SIDMAP_LOCAL_USER_BASE &&
206 rid < SIDMAP_LOCAL_GROUP_BASE) {
207 *uid = rid - SIDMAP_LOCAL_USER_BASE;
208 talloc_free(tmp_ctx);
209 return NT_STATUS_OK;
210 }
211 }
212
213
214 DEBUG(0,("sid_to_unixuid: no uidNumber, unixName or sAMAccountName for sid %s\n",
215 dom_sid_string(tmp_ctx, sid)));
216
217 talloc_free(tmp_ctx);
218 return NT_STATUS_NONE_MAPPED;
219}
220
221
222/*
223 see if a sid is a group - very inefficient!
224*/
225bool sidmap_sid_is_group(struct sidmap_context *sidmap, struct dom_sid *sid)
226{
227 const char *attrs[] = { "sAMAccountType", NULL };
228 int ret;
229 TALLOC_CTX *tmp_ctx;
230 struct ldb_message **res;
231 NTSTATUS status;
232 struct dom_sid *domain_sid;
233 bool is_group;
234
235 tmp_ctx = talloc_new(sidmap);
236
237 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
238 "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
239 if (ret == 1) {
240 is_group = is_group_account(res[0]);
241 talloc_free(tmp_ctx);
242 return is_group;
243 }
244
245 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
246 if (!NT_STATUS_IS_OK(status)) {
247 talloc_free(tmp_ctx);
248 return false;
249 }
250
251 if (dom_sid_in_domain(domain_sid, sid)) {
252 uint32_t rid = sid->sub_auths[sid->num_auths-1];
253 if (rid >= SIDMAP_LOCAL_GROUP_BASE) {
254 talloc_free(tmp_ctx);
255 return true;
256 }
257 }
258
259 talloc_free(tmp_ctx);
260 return false;
261}
262
263/*
264 map a sid to a unix gid
265*/
266NTSTATUS sidmap_sid_to_unixgid(struct sidmap_context *sidmap,
267 const struct dom_sid *sid, gid_t *gid)
268{
269 const char *attrs[] = { "sAMAccountName", "gidNumber",
270 "unixName", "sAMAccountType", NULL };
271 int ret;
272 const char *s;
273 TALLOC_CTX *tmp_ctx;
274 struct ldb_message **res;
275 NTSTATUS status;
276 struct dom_sid *domain_sid;
277
278 tmp_ctx = talloc_new(sidmap);
279
280 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
281 "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
282 if (ret != 1) {
283 goto allocated_sid;
284 }
285
286 /* make sure its not a user */
287 if (!is_group_account(res[0])) {
288 DEBUG(0,("sid_to_unixgid: sid %s is a ATYPE_NORMAL_ACCOUNT\n",
289 dom_sid_string(tmp_ctx, sid)));
290 talloc_free(tmp_ctx);
291 return NT_STATUS_INVALID_SID;
292 }
293
294 /* first try to get the gid directly */
295 s = samdb_result_string(res[0], "gidNumber", NULL);
296 if (s != NULL) {
297 *gid = strtoul(s, NULL, 0);
298 talloc_free(tmp_ctx);
299 return NT_STATUS_OK;
300 }
301
302 /* next try via the UnixName attribute */
303 s = samdb_result_string(res[0], "unixName", NULL);
304 if (s != NULL) {
305 struct group *grp = getgrnam(s);
306 if (!grp) {
307 DEBUG(0,("unixName '%s' for sid %s does not exist as a local group\n",
308 s, dom_sid_string(tmp_ctx, sid)));
309 talloc_free(tmp_ctx);
310 return NT_STATUS_NO_SUCH_GROUP;
311 }
312 *gid = grp->gr_gid;
313 talloc_free(tmp_ctx);
314 return NT_STATUS_OK;
315 }
316
317 /* finally try via the sAMAccountName attribute */
318 s = samdb_result_string(res[0], "sAMAccountName", NULL);
319 if (s != NULL) {
320 struct group *grp = getgrnam(s);
321 if (!grp) {
322 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s, dom_sid_string(tmp_ctx, sid)));
323 talloc_free(tmp_ctx);
324 return NT_STATUS_NO_SUCH_GROUP;
325 }
326 *gid = grp->gr_gid;
327 talloc_free(tmp_ctx);
328 return NT_STATUS_OK;
329 }
330
331allocated_sid:
332 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
333 if (!NT_STATUS_IS_OK(status)) {
334 talloc_free(tmp_ctx);
335 return NT_STATUS_NO_SUCH_DOMAIN;
336 }
337
338 if (dom_sid_in_domain(domain_sid, sid)) {
339 uint32_t rid = sid->sub_auths[sid->num_auths-1];
340 if (rid >= SIDMAP_LOCAL_GROUP_BASE) {
341 *gid = rid - SIDMAP_LOCAL_GROUP_BASE;
342 talloc_free(tmp_ctx);
343 return NT_STATUS_OK;
344 }
345 }
346
347 DEBUG(0,("sid_to_unixgid: no gidNumber, unixName or sAMAccountName for sid %s\n",
348 dom_sid_string(tmp_ctx, sid)));
349
350 talloc_free(tmp_ctx);
351 return NT_STATUS_NONE_MAPPED;
352}
353
354
355/*
356 map a unix uid to a dom_sid
357 the returned sid is allocated in the supplied mem_ctx
358*/
359NTSTATUS sidmap_uid_to_sid(struct sidmap_context *sidmap,
360 TALLOC_CTX *mem_ctx,
361 const uid_t uid, struct dom_sid **sid)
362{
363 const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
364 int ret, i;
365 TALLOC_CTX *tmp_ctx;
366 struct ldb_message **res;
367 struct passwd *pwd;
368 struct dom_sid *domain_sid;
369 NTSTATUS status;
370
371 /*
372 we search for the mapping in the following order:
373
374 - check if the uid is in the dynamic uid range assigned for winbindd
375 use. If it is, then look in winbindd sid mapping
376 database (not implemented yet)
377 - look for a user account in samdb that has uidNumber set to the
378 given uid
379 - look for a user account in samdb that has unixName or
380 sAMAccountName set to the name given by getpwuid()
381 - assign a SID by adding the uid to SIDMAP_LOCAL_USER_BASE in the local
382 domain
383 */
384
385
386 tmp_ctx = talloc_new(mem_ctx);
387
388
389 /*
390 step 2: look for a user account in samdb that has uidNumber set to the
391 given uid
392 */
393
394 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
395 "uidNumber=%u", (unsigned int)uid);
396 for (i=0;i<ret;i++) {
397 if (!is_user_account(res[i])) continue;
398
399 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
400 talloc_free(tmp_ctx);
401 NT_STATUS_HAVE_NO_MEMORY(*sid);
402 return NT_STATUS_OK;
403 }
404
405 /*
406 step 3: look for a user account in samdb that has unixName
407 or sAMAccountName set to the name given by getpwuid()
408 */
409 pwd = getpwuid(uid);
410 if (pwd == NULL) {
411 goto allocate_sid;
412 }
413
414 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
415 "(|(unixName=%s)(sAMAccountName=%s))",
416 pwd->pw_name, pwd->pw_name);
417 for (i=0;i<ret;i++) {
418 if (!is_user_account(res[i])) continue;
419
420 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
421 talloc_free(tmp_ctx);
422 NT_STATUS_HAVE_NO_MEMORY(*sid);
423 return NT_STATUS_OK;
424 }
425
426
427 /*
428 step 4: assign a SID by adding the uid to
429 SIDMAP_LOCAL_USER_BASE in the local domain
430 */
431allocate_sid:
432 if (uid > SIDMAP_MAX_LOCAL_UID) {
433 return NT_STATUS_NONE_MAPPED;
434 }
435
436 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
437 if (!NT_STATUS_IS_OK(status)) {
438 talloc_free(tmp_ctx);
439 return status;
440 }
441
442 *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_USER_BASE + uid);
443 talloc_free(tmp_ctx);
444
445 if (*sid == NULL) {
446 return NT_STATUS_NO_MEMORY;
447 }
448
449 return NT_STATUS_OK;
450}
451
452
453/*
454 map a unix gid to a dom_sid
455 the returned sid is allocated in the supplied mem_ctx
456*/
457NTSTATUS sidmap_gid_to_sid(struct sidmap_context *sidmap,
458 TALLOC_CTX *mem_ctx,
459 const gid_t gid, struct dom_sid **sid)
460{
461 const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
462 int ret, i;
463 TALLOC_CTX *tmp_ctx;
464 struct ldb_message **res;
465 struct group *grp;
466 struct dom_sid *domain_sid;
467 NTSTATUS status;
468
469 /*
470 we search for the mapping in the following order:
471
472 - check if the gid is in the dynamic gid range assigned for winbindd
473 use. If it is, then look in winbindd sid mapping
474 database (not implemented yet)
475 - look for a group account in samdb that has gidNumber set to the
476 given gid
477 - look for a group account in samdb that has unixName or
478 sAMAccountName set to the name given by getgrgid()
479 - assign a SID by adding the gid to SIDMAP_LOCAL_GROUP_BASE in the local
480 domain
481 */
482
483
484 tmp_ctx = talloc_new(sidmap);
485
486
487 /*
488 step 2: look for a group account in samdb that has gidNumber set to the
489 given gid
490 */
491
492 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
493 "gidNumber=%u", (unsigned int)gid);
494 for (i=0;i<ret;i++) {
495 if (!is_group_account(res[i])) continue;
496
497 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
498 talloc_free(tmp_ctx);
499 NT_STATUS_HAVE_NO_MEMORY(*sid);
500 return NT_STATUS_OK;
501 }
502
503 /*
504 step 3: look for a group account in samdb that has unixName
505 or sAMAccountName set to the name given by getgrgid()
506 */
507 grp = getgrgid(gid);
508 if (grp == NULL) {
509 goto allocate_sid;
510 }
511
512 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
513 "(|(unixName=%s)(sAMAccountName=%s))",
514 grp->gr_name, grp->gr_name);
515 for (i=0;i<ret;i++) {
516 if (!is_group_account(res[i])) continue;
517
518 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
519 talloc_free(tmp_ctx);
520 NT_STATUS_HAVE_NO_MEMORY(*sid);
521 return NT_STATUS_OK;
522 }
523
524
525 /*
526 step 4: assign a SID by adding the gid to
527 SIDMAP_LOCAL_GROUP_BASE in the local domain
528 */
529allocate_sid:
530 if (gid > SIDMAP_MAX_LOCAL_GID) {
531 return NT_STATUS_NONE_MAPPED;
532 }
533
534 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
535 if (!NT_STATUS_IS_OK(status)) {
536 talloc_free(tmp_ctx);
537 return status;
538 }
539
540 *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_GROUP_BASE + gid);
541 talloc_free(tmp_ctx);
542
543 if (*sid == NULL) {
544 return NT_STATUS_NO_MEMORY;
545 }
546
547 return NT_STATUS_OK;
548}
549
550/*
551 check if a sid is in the range of auto-allocated SIDs from our primary domain,
552 and if it is, then return the name and atype
553*/
554NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap,
555 TALLOC_CTX *mem_ctx,
556 const struct dom_sid *sid,
557 const char **name,
558 enum lsa_SidType *rtype)
559{
560 NTSTATUS status;
561 struct dom_sid *domain_sid;
562 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
563 uint32_t rid, atype;
564
565 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
566 if (!NT_STATUS_IS_OK(status)) {
567 return NT_STATUS_NO_SUCH_DOMAIN;
568 }
569
570 if (!dom_sid_in_domain(domain_sid, sid)) {
571 talloc_free(tmp_ctx);
572 return NT_STATUS_NONE_MAPPED;
573 }
574
575 talloc_free(tmp_ctx);
576
577 rid = sid->sub_auths[sid->num_auths-1];
578 if (rid < SIDMAP_LOCAL_USER_BASE) {
579 return NT_STATUS_NONE_MAPPED;
580 }
581
582 if (rid < SIDMAP_LOCAL_GROUP_BASE) {
583 struct passwd *pwd;
584 uid_t uid = rid - SIDMAP_LOCAL_USER_BASE;
585 atype = ATYPE_NORMAL_ACCOUNT;
586 *rtype = ds_atype_map(atype);
587
588 pwd = getpwuid(uid);
589 if (pwd == NULL) {
590 *name = talloc_asprintf(mem_ctx, "uid%u", uid);
591 } else {
592 *name = talloc_strdup(mem_ctx, pwd->pw_name);
593 }
594 } else {
595 struct group *grp;
596 gid_t gid = rid - SIDMAP_LOCAL_GROUP_BASE;
597 atype = ATYPE_LOCAL_GROUP;
598 *rtype = ds_atype_map(atype);
599 grp = getgrgid(gid);
600 if (grp == NULL) {
601 *name = talloc_asprintf(mem_ctx, "gid%u", gid);
602 } else {
603 *name = talloc_strdup(mem_ctx, grp->gr_name);
604 }
605 }
606
607 if (*name == NULL) {
608 return NT_STATUS_NO_MEMORY;
609 }
610
611 return NT_STATUS_OK;
612}
Note: See TracBrowser for help on using the repository browser.