2 Unix SMB/CIFS implementation.
4 mapping routines for SID <-> unix uid/gid
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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/>.
23 #include "system/passwd.h"
24 #include "dsdb/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 "util/util_ldb.h"
30 #include "libcli/security/security.h"
31 #include "param/param.h"
34 these are used for the fallback local uid/gid to sid mapping
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
43 private context for sid mapping routines
45 struct sidmap_context {
46 struct ldb_context *samctx;
50 open a sidmap context - use talloc_free to close
52 _PUBLIC_ struct sidmap_context *sidmap_open(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
54 struct sidmap_context *sidmap;
55 sidmap = talloc(mem_ctx, struct sidmap_context);
59 sidmap->samctx = samdb_connect(sidmap, lp_ctx, system_session(sidmap, lp_ctx));
60 if (sidmap->samctx == NULL) {
70 check the sAMAccountType field of a search result to see if
71 the account is a user account
73 static bool is_user_account(struct ldb_message *res)
75 uint_t atype = samdb_result_uint(res, "sAMAccountType", 0);
76 if (atype && (!(atype & ATYPE_ACCOUNT))) {
83 check the sAMAccountType field of a search result to see if
84 the account is a group account
86 static bool is_group_account(struct ldb_message *res)
88 uint_t atype = samdb_result_uint(res, "sAMAccountType", 0);
89 if (atype && atype == ATYPE_NORMAL_ACCOUNT) {
98 return the dom_sid of our primary domain
100 static NTSTATUS sidmap_primary_domain_sid(struct sidmap_context *sidmap,
101 TALLOC_CTX *mem_ctx, struct dom_sid **sid)
103 const char *attrs[] = { "objectSid", NULL };
105 struct ldb_message **res = NULL;
107 ret = gendb_search_dn(sidmap->samctx, mem_ctx, NULL, &res, attrs);
110 return NT_STATUS_NO_SUCH_DOMAIN;
113 *sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
116 return NT_STATUS_NO_MEMORY;
124 map a sid to a unix uid
126 _PUBLIC_ NTSTATUS sidmap_sid_to_unixuid(struct sidmap_context *sidmap,
127 struct dom_sid *sid, uid_t *uid)
129 const char *attrs[] = { "sAMAccountName", "uidNumber",
130 "sAMAccountType", "unixName", NULL };
134 struct ldb_message **res;
135 struct dom_sid *domain_sid;
138 tmp_ctx = talloc_new(sidmap);
140 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
141 "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
146 /* make sure its a user, not a group */
147 if (!is_user_account(res[0])) {
148 DEBUG(0,("sid_to_unixuid: sid %s is not an account!\n",
149 dom_sid_string(tmp_ctx, sid)));
150 talloc_free(tmp_ctx);
151 return NT_STATUS_INVALID_SID;
154 /* first try to get the uid directly */
155 s = samdb_result_string(res[0], "uidNumber", NULL);
157 *uid = strtoul(s, NULL, 0);
158 talloc_free(tmp_ctx);
162 /* next try via the UnixName attribute */
163 s = samdb_result_string(res[0], "unixName", NULL);
165 struct passwd *pwd = getpwnam(s);
167 DEBUG(0,("unixName %s for sid %s does not exist as a local user\n", s,
168 dom_sid_string(tmp_ctx, sid)));
169 talloc_free(tmp_ctx);
170 return NT_STATUS_NO_SUCH_USER;
173 talloc_free(tmp_ctx);
177 /* finally try via the sAMAccountName attribute */
178 s = samdb_result_string(res[0], "sAMAccountName", NULL);
180 struct passwd *pwd = getpwnam(s);
182 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n",
183 s, dom_sid_string(tmp_ctx, sid)));
184 talloc_free(tmp_ctx);
185 return NT_STATUS_NO_SUCH_USER;
188 talloc_free(tmp_ctx);
194 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
195 if (!NT_STATUS_IS_OK(status)) {
196 talloc_free(tmp_ctx);
197 return NT_STATUS_NO_SUCH_DOMAIN;
200 if (dom_sid_in_domain(domain_sid, sid)) {
201 uint32_t rid = sid->sub_auths[sid->num_auths-1];
202 if (rid >= SIDMAP_LOCAL_USER_BASE &&
203 rid < SIDMAP_LOCAL_GROUP_BASE) {
204 *uid = rid - SIDMAP_LOCAL_USER_BASE;
205 talloc_free(tmp_ctx);
211 DEBUG(0,("sid_to_unixuid: no uidNumber, unixName or sAMAccountName for sid %s\n",
212 dom_sid_string(tmp_ctx, sid)));
214 talloc_free(tmp_ctx);
215 return NT_STATUS_NONE_MAPPED;
220 see if a sid is a group - very inefficient!
222 _PUBLIC_ bool sidmap_sid_is_group(struct sidmap_context *sidmap, struct dom_sid *sid)
224 const char *attrs[] = { "sAMAccountType", NULL };
227 struct ldb_message **res;
229 struct dom_sid *domain_sid;
232 tmp_ctx = talloc_new(sidmap);
234 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
235 "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
237 is_group = is_group_account(res[0]);
238 talloc_free(tmp_ctx);
242 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
243 if (!NT_STATUS_IS_OK(status)) {
244 talloc_free(tmp_ctx);
248 if (dom_sid_in_domain(domain_sid, sid)) {
249 uint32_t rid = sid->sub_auths[sid->num_auths-1];
250 if (rid >= SIDMAP_LOCAL_GROUP_BASE) {
251 talloc_free(tmp_ctx);
256 talloc_free(tmp_ctx);
261 map a sid to a unix gid
263 _PUBLIC_ NTSTATUS sidmap_sid_to_unixgid(struct sidmap_context *sidmap,
264 struct dom_sid *sid, gid_t *gid)
266 const char *attrs[] = { "sAMAccountName", "gidNumber",
267 "unixName", "sAMAccountType", NULL };
271 struct ldb_message **res;
273 struct dom_sid *domain_sid;
275 tmp_ctx = talloc_new(sidmap);
277 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
278 "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
283 /* make sure its not a user */
284 if (!is_group_account(res[0])) {
285 DEBUG(0,("sid_to_unixgid: sid %s is a ATYPE_NORMAL_ACCOUNT\n",
286 dom_sid_string(tmp_ctx, sid)));
287 talloc_free(tmp_ctx);
288 return NT_STATUS_INVALID_SID;
291 /* first try to get the gid directly */
292 s = samdb_result_string(res[0], "gidNumber", NULL);
294 *gid = strtoul(s, NULL, 0);
295 talloc_free(tmp_ctx);
299 /* next try via the UnixName attribute */
300 s = samdb_result_string(res[0], "unixName", NULL);
302 struct group *grp = getgrnam(s);
304 DEBUG(0,("unixName '%s' for sid %s does not exist as a local group\n",
305 s, dom_sid_string(tmp_ctx, sid)));
306 talloc_free(tmp_ctx);
307 return NT_STATUS_NO_SUCH_GROUP;
310 talloc_free(tmp_ctx);
314 /* finally try via the sAMAccountName attribute */
315 s = samdb_result_string(res[0], "sAMAccountName", NULL);
317 struct group *grp = getgrnam(s);
319 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s, dom_sid_string(tmp_ctx, sid)));
320 talloc_free(tmp_ctx);
321 return NT_STATUS_NO_SUCH_GROUP;
324 talloc_free(tmp_ctx);
329 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
330 if (!NT_STATUS_IS_OK(status)) {
331 talloc_free(tmp_ctx);
332 return NT_STATUS_NO_SUCH_DOMAIN;
335 if (dom_sid_in_domain(domain_sid, sid)) {
336 uint32_t rid = sid->sub_auths[sid->num_auths-1];
337 if (rid >= SIDMAP_LOCAL_GROUP_BASE) {
338 *gid = rid - SIDMAP_LOCAL_GROUP_BASE;
339 talloc_free(tmp_ctx);
344 DEBUG(0,("sid_to_unixgid: no gidNumber, unixName or sAMAccountName for sid %s\n",
345 dom_sid_string(tmp_ctx, sid)));
347 talloc_free(tmp_ctx);
348 return NT_STATUS_NONE_MAPPED;
353 map a unix uid to a dom_sid
354 the returned sid is allocated in the supplied mem_ctx
356 _PUBLIC_ NTSTATUS sidmap_uid_to_sid(struct sidmap_context *sidmap,
358 uid_t uid, struct dom_sid **sid)
360 const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
363 struct ldb_message **res;
365 struct dom_sid *domain_sid;
369 we search for the mapping in the following order:
371 - check if the uid is in the dynamic uid range assigned for winbindd
372 use. If it is, then look in winbindd sid mapping
373 database (not implemented yet)
374 - look for a user account in samdb that has uidNumber set to the
376 - look for a user account in samdb that has unixName or
377 sAMAccountName set to the name given by getpwuid()
378 - assign a SID by adding the uid to SIDMAP_LOCAL_USER_BASE in the local
383 tmp_ctx = talloc_new(mem_ctx);
387 step 2: look for a user account in samdb that has uidNumber set to the
391 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
392 "uidNumber=%u", (unsigned int)uid);
393 for (i=0;i<ret;i++) {
394 if (!is_user_account(res[i])) continue;
396 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
397 talloc_free(tmp_ctx);
398 NT_STATUS_HAVE_NO_MEMORY(*sid);
403 step 3: look for a user account in samdb that has unixName
404 or sAMAccountName set to the name given by getpwuid()
411 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
412 "(|(unixName=%s)(sAMAccountName=%s))",
413 pwd->pw_name, pwd->pw_name);
414 for (i=0;i<ret;i++) {
415 if (!is_user_account(res[i])) continue;
417 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
418 talloc_free(tmp_ctx);
419 NT_STATUS_HAVE_NO_MEMORY(*sid);
425 step 4: assign a SID by adding the uid to
426 SIDMAP_LOCAL_USER_BASE in the local domain
429 if (uid > SIDMAP_MAX_LOCAL_UID) {
430 return NT_STATUS_NONE_MAPPED;
433 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
434 if (!NT_STATUS_IS_OK(status)) {
435 talloc_free(tmp_ctx);
439 *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_USER_BASE + uid);
440 talloc_free(tmp_ctx);
443 return NT_STATUS_NO_MEMORY;
451 map a unix gid to a dom_sid
452 the returned sid is allocated in the supplied mem_ctx
454 _PUBLIC_ NTSTATUS sidmap_gid_to_sid(struct sidmap_context *sidmap,
456 gid_t gid, struct dom_sid **sid)
458 const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
461 struct ldb_message **res;
463 struct dom_sid *domain_sid;
467 we search for the mapping in the following order:
469 - check if the gid is in the dynamic gid range assigned for winbindd
470 use. If it is, then look in winbindd sid mapping
471 database (not implemented yet)
472 - look for a group account in samdb that has gidNumber set to the
474 - look for a group account in samdb that has unixName or
475 sAMAccountName set to the name given by getgrgid()
476 - assign a SID by adding the gid to SIDMAP_LOCAL_GROUP_BASE in the local
481 tmp_ctx = talloc_new(sidmap);
485 step 2: look for a group account in samdb that has gidNumber set to the
489 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
490 "gidNumber=%u", (unsigned int)gid);
491 for (i=0;i<ret;i++) {
492 if (!is_group_account(res[i])) continue;
494 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
495 talloc_free(tmp_ctx);
496 NT_STATUS_HAVE_NO_MEMORY(*sid);
501 step 3: look for a group account in samdb that has unixName
502 or sAMAccountName set to the name given by getgrgid()
509 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
510 "(|(unixName=%s)(sAMAccountName=%s))",
511 grp->gr_name, grp->gr_name);
512 for (i=0;i<ret;i++) {
513 if (!is_group_account(res[i])) continue;
515 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
516 talloc_free(tmp_ctx);
517 NT_STATUS_HAVE_NO_MEMORY(*sid);
523 step 4: assign a SID by adding the gid to
524 SIDMAP_LOCAL_GROUP_BASE in the local domain
527 if (gid > SIDMAP_MAX_LOCAL_GID) {
528 return NT_STATUS_NONE_MAPPED;
531 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
532 if (!NT_STATUS_IS_OK(status)) {
533 talloc_free(tmp_ctx);
537 *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_GROUP_BASE + gid);
538 talloc_free(tmp_ctx);
541 return NT_STATUS_NO_MEMORY;
548 check if a sid is in the range of auto-allocated SIDs from our primary domain,
549 and if it is, then return the name and atype
551 _PUBLIC_ NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap,
553 const struct dom_sid *sid,
555 enum lsa_SidType *rtype)
558 struct dom_sid *domain_sid;
559 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
562 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
563 if (!NT_STATUS_IS_OK(status)) {
564 return NT_STATUS_NO_SUCH_DOMAIN;
567 if (!dom_sid_in_domain(domain_sid, sid)) {
568 talloc_free(tmp_ctx);
569 return NT_STATUS_NONE_MAPPED;
572 talloc_free(tmp_ctx);
574 rid = sid->sub_auths[sid->num_auths-1];
575 if (rid < SIDMAP_LOCAL_USER_BASE) {
576 return NT_STATUS_NONE_MAPPED;
579 if (rid < SIDMAP_LOCAL_GROUP_BASE) {
581 uid_t uid = rid - SIDMAP_LOCAL_USER_BASE;
582 atype = ATYPE_NORMAL_ACCOUNT;
583 *rtype = samdb_atype_map(atype);
587 *name = talloc_asprintf(mem_ctx, "uid%u", uid);
589 *name = talloc_strdup(mem_ctx, pwd->pw_name);
593 gid_t gid = rid - SIDMAP_LOCAL_GROUP_BASE;
594 atype = ATYPE_LOCAL_GROUP;
595 *rtype = samdb_atype_map(atype);
598 *name = talloc_asprintf(mem_ctx, "gid%u", gid);
600 *name = talloc_strdup(mem_ctx, grp->gr_name);
605 return NT_STATUS_NO_MEMORY;