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 const 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,
142 ldap_encode_ndr_dom_sid(tmp_ctx, sid));
148 /* make sure its a user, not a group */
149 if (!is_user_account(res[0])) {
150 DEBUG(0,("sid_to_unixuid: sid %s is not an account!\n",
151 dom_sid_string(tmp_ctx, sid)));
152 talloc_free(tmp_ctx);
153 return NT_STATUS_INVALID_SID;
156 /* first try to get the uid directly */
157 s = samdb_result_string(res[0], "uidNumber", NULL);
159 *uid = strtoul(s, NULL, 0);
160 talloc_free(tmp_ctx);
164 /* next try via the UnixName attribute */
165 s = samdb_result_string(res[0], "unixName", NULL);
167 struct passwd *pwd = getpwnam(s);
169 DEBUG(0,("unixName %s for sid %s does not exist as a local user\n", s,
170 dom_sid_string(tmp_ctx, sid)));
171 talloc_free(tmp_ctx);
172 return NT_STATUS_NO_SUCH_USER;
175 talloc_free(tmp_ctx);
179 /* finally try via the sAMAccountName attribute */
180 s = samdb_result_string(res[0], "sAMAccountName", NULL);
182 struct passwd *pwd = getpwnam(s);
184 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n",
185 s, dom_sid_string(tmp_ctx, sid)));
186 talloc_free(tmp_ctx);
187 return NT_STATUS_NO_SUCH_USER;
190 talloc_free(tmp_ctx);
196 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
197 if (!NT_STATUS_IS_OK(status)) {
198 talloc_free(tmp_ctx);
199 return NT_STATUS_NO_SUCH_DOMAIN;
202 if (dom_sid_in_domain(domain_sid, sid)) {
203 uint32_t rid = sid->sub_auths[sid->num_auths-1];
204 if (rid >= SIDMAP_LOCAL_USER_BASE &&
205 rid < SIDMAP_LOCAL_GROUP_BASE) {
206 *uid = rid - SIDMAP_LOCAL_USER_BASE;
207 talloc_free(tmp_ctx);
213 DEBUG(0,("sid_to_unixuid: no uidNumber, unixName or sAMAccountName for sid %s\n",
214 dom_sid_string(tmp_ctx, sid)));
216 talloc_free(tmp_ctx);
217 return NT_STATUS_NONE_MAPPED;
222 see if a sid is a group - very inefficient!
224 _PUBLIC_ bool sidmap_sid_is_group(struct sidmap_context *sidmap, struct dom_sid *sid)
226 const char *attrs[] = { "sAMAccountType", NULL };
229 struct ldb_message **res;
231 struct dom_sid *domain_sid;
234 tmp_ctx = talloc_new(sidmap);
236 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
237 "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
239 is_group = is_group_account(res[0]);
240 talloc_free(tmp_ctx);
244 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
245 if (!NT_STATUS_IS_OK(status)) {
246 talloc_free(tmp_ctx);
250 if (dom_sid_in_domain(domain_sid, sid)) {
251 uint32_t rid = sid->sub_auths[sid->num_auths-1];
252 if (rid >= SIDMAP_LOCAL_GROUP_BASE) {
253 talloc_free(tmp_ctx);
258 talloc_free(tmp_ctx);
263 map a sid to a unix gid
265 _PUBLIC_ NTSTATUS sidmap_sid_to_unixgid(struct sidmap_context *sidmap,
266 const struct dom_sid *sid, gid_t *gid)
268 const char *attrs[] = { "sAMAccountName", "gidNumber",
269 "unixName", "sAMAccountType", NULL };
273 struct ldb_message **res;
275 struct dom_sid *domain_sid;
277 tmp_ctx = talloc_new(sidmap);
279 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
280 "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
285 /* make sure its not a user */
286 if (!is_group_account(res[0])) {
287 DEBUG(0,("sid_to_unixgid: sid %s is a ATYPE_NORMAL_ACCOUNT\n",
288 dom_sid_string(tmp_ctx, sid)));
289 talloc_free(tmp_ctx);
290 return NT_STATUS_INVALID_SID;
293 /* first try to get the gid directly */
294 s = samdb_result_string(res[0], "gidNumber", NULL);
296 *gid = strtoul(s, NULL, 0);
297 talloc_free(tmp_ctx);
301 /* next try via the UnixName attribute */
302 s = samdb_result_string(res[0], "unixName", NULL);
304 struct group *grp = getgrnam(s);
306 DEBUG(0,("unixName '%s' for sid %s does not exist as a local group\n",
307 s, dom_sid_string(tmp_ctx, sid)));
308 talloc_free(tmp_ctx);
309 return NT_STATUS_NO_SUCH_GROUP;
312 talloc_free(tmp_ctx);
316 /* finally try via the sAMAccountName attribute */
317 s = samdb_result_string(res[0], "sAMAccountName", NULL);
319 struct group *grp = getgrnam(s);
321 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s, dom_sid_string(tmp_ctx, sid)));
322 talloc_free(tmp_ctx);
323 return NT_STATUS_NO_SUCH_GROUP;
326 talloc_free(tmp_ctx);
331 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
332 if (!NT_STATUS_IS_OK(status)) {
333 talloc_free(tmp_ctx);
334 return NT_STATUS_NO_SUCH_DOMAIN;
337 if (dom_sid_in_domain(domain_sid, sid)) {
338 uint32_t rid = sid->sub_auths[sid->num_auths-1];
339 if (rid >= SIDMAP_LOCAL_GROUP_BASE) {
340 *gid = rid - SIDMAP_LOCAL_GROUP_BASE;
341 talloc_free(tmp_ctx);
346 DEBUG(0,("sid_to_unixgid: no gidNumber, unixName or sAMAccountName for sid %s\n",
347 dom_sid_string(tmp_ctx, sid)));
349 talloc_free(tmp_ctx);
350 return NT_STATUS_NONE_MAPPED;
355 map a unix uid to a dom_sid
356 the returned sid is allocated in the supplied mem_ctx
358 _PUBLIC_ NTSTATUS sidmap_uid_to_sid(struct sidmap_context *sidmap,
360 const uid_t uid, struct dom_sid **sid)
362 const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
365 struct ldb_message **res;
367 struct dom_sid *domain_sid;
371 we search for the mapping in the following order:
373 - check if the uid is in the dynamic uid range assigned for winbindd
374 use. If it is, then look in winbindd sid mapping
375 database (not implemented yet)
376 - look for a user account in samdb that has uidNumber set to the
378 - look for a user account in samdb that has unixName or
379 sAMAccountName set to the name given by getpwuid()
380 - assign a SID by adding the uid to SIDMAP_LOCAL_USER_BASE in the local
385 tmp_ctx = talloc_new(mem_ctx);
389 step 2: look for a user account in samdb that has uidNumber set to the
393 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
394 "uidNumber=%u", (unsigned int)uid);
395 for (i=0;i<ret;i++) {
396 if (!is_user_account(res[i])) continue;
398 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
399 talloc_free(tmp_ctx);
400 NT_STATUS_HAVE_NO_MEMORY(*sid);
405 step 3: look for a user account in samdb that has unixName
406 or sAMAccountName set to the name given by getpwuid()
413 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
414 "(|(unixName=%s)(sAMAccountName=%s))",
415 pwd->pw_name, pwd->pw_name);
416 for (i=0;i<ret;i++) {
417 if (!is_user_account(res[i])) continue;
419 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
420 talloc_free(tmp_ctx);
421 NT_STATUS_HAVE_NO_MEMORY(*sid);
427 step 4: assign a SID by adding the uid to
428 SIDMAP_LOCAL_USER_BASE in the local domain
431 if (uid > SIDMAP_MAX_LOCAL_UID) {
432 return NT_STATUS_NONE_MAPPED;
435 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
436 if (!NT_STATUS_IS_OK(status)) {
437 talloc_free(tmp_ctx);
441 *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_USER_BASE + uid);
442 talloc_free(tmp_ctx);
445 return NT_STATUS_NO_MEMORY;
453 map a unix gid to a dom_sid
454 the returned sid is allocated in the supplied mem_ctx
456 _PUBLIC_ NTSTATUS sidmap_gid_to_sid(struct sidmap_context *sidmap,
458 const gid_t gid, struct dom_sid **sid)
460 const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
463 struct ldb_message **res;
465 struct dom_sid *domain_sid;
469 we search for the mapping in the following order:
471 - check if the gid is in the dynamic gid range assigned for winbindd
472 use. If it is, then look in winbindd sid mapping
473 database (not implemented yet)
474 - look for a group account in samdb that has gidNumber set to the
476 - look for a group account in samdb that has unixName or
477 sAMAccountName set to the name given by getgrgid()
478 - assign a SID by adding the gid to SIDMAP_LOCAL_GROUP_BASE in the local
483 tmp_ctx = talloc_new(sidmap);
487 step 2: look for a group account in samdb that has gidNumber set to the
491 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
492 "gidNumber=%u", (unsigned int)gid);
493 for (i=0;i<ret;i++) {
494 if (!is_group_account(res[i])) continue;
496 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
497 talloc_free(tmp_ctx);
498 NT_STATUS_HAVE_NO_MEMORY(*sid);
503 step 3: look for a group account in samdb that has unixName
504 or sAMAccountName set to the name given by getgrgid()
511 ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs,
512 "(|(unixName=%s)(sAMAccountName=%s))",
513 grp->gr_name, grp->gr_name);
514 for (i=0;i<ret;i++) {
515 if (!is_group_account(res[i])) continue;
517 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
518 talloc_free(tmp_ctx);
519 NT_STATUS_HAVE_NO_MEMORY(*sid);
525 step 4: assign a SID by adding the gid to
526 SIDMAP_LOCAL_GROUP_BASE in the local domain
529 if (gid > SIDMAP_MAX_LOCAL_GID) {
530 return NT_STATUS_NONE_MAPPED;
533 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
534 if (!NT_STATUS_IS_OK(status)) {
535 talloc_free(tmp_ctx);
539 *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_GROUP_BASE + gid);
540 talloc_free(tmp_ctx);
543 return NT_STATUS_NO_MEMORY;
550 check if a sid is in the range of auto-allocated SIDs from our primary domain,
551 and if it is, then return the name and atype
553 _PUBLIC_ NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap,
555 const struct dom_sid *sid,
557 enum lsa_SidType *rtype)
560 struct dom_sid *domain_sid;
561 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
564 status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
565 if (!NT_STATUS_IS_OK(status)) {
566 return NT_STATUS_NO_SUCH_DOMAIN;
569 if (!dom_sid_in_domain(domain_sid, sid)) {
570 talloc_free(tmp_ctx);
571 return NT_STATUS_NONE_MAPPED;
574 talloc_free(tmp_ctx);
576 rid = sid->sub_auths[sid->num_auths-1];
577 if (rid < SIDMAP_LOCAL_USER_BASE) {
578 return NT_STATUS_NONE_MAPPED;
581 if (rid < SIDMAP_LOCAL_GROUP_BASE) {
583 uid_t uid = rid - SIDMAP_LOCAL_USER_BASE;
584 atype = ATYPE_NORMAL_ACCOUNT;
585 *rtype = samdb_atype_map(atype);
589 *name = talloc_asprintf(mem_ctx, "uid%u", uid);
591 *name = talloc_strdup(mem_ctx, pwd->pw_name);
595 gid_t gid = rid - SIDMAP_LOCAL_GROUP_BASE;
596 atype = ATYPE_LOCAL_GROUP;
597 *rtype = samdb_atype_map(atype);
600 *name = talloc_asprintf(mem_ctx, "gid%u", gid);
602 *name = talloc_strdup(mem_ctx, grp->gr_name);
607 return NT_STATUS_NO_MEMORY;