Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-python
[samba.git] / source / dsdb / common / sidmap.c
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 "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"
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 */
45 struct sidmap_context {
46         struct ldb_context *samctx;
47 };
48
49 /*
50   open a sidmap context - use talloc_free to close
51 */
52 _PUBLIC_ struct sidmap_context *sidmap_open(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
53 {
54         struct sidmap_context *sidmap;
55         sidmap = talloc(mem_ctx, struct sidmap_context);
56         if (sidmap == NULL) {
57                 return NULL;
58         }
59         sidmap->samctx = samdb_connect(sidmap, lp_ctx, system_session(sidmap, lp_ctx));
60         if (sidmap->samctx == NULL) {
61                 talloc_free(sidmap);
62                 return NULL;
63         }
64
65         return sidmap;
66 }
67
68
69 /*
70   check the sAMAccountType field of a search result to see if
71   the account is a user account
72 */
73 static bool is_user_account(struct ldb_message *res)
74 {
75         uint_t atype = samdb_result_uint(res, "sAMAccountType", 0);
76         if (atype && (!(atype & ATYPE_ACCOUNT))) {
77                 return false;
78         }
79         return true;
80 }
81
82 /*
83   check the sAMAccountType field of a search result to see if
84   the account is a group account
85 */
86 static bool is_group_account(struct ldb_message *res)
87 {
88         uint_t atype = samdb_result_uint(res, "sAMAccountType", 0);
89         if (atype && atype == ATYPE_NORMAL_ACCOUNT) {
90                 return false;
91         }
92         return true;
93 }
94
95
96
97 /*
98   return the dom_sid of our primary domain
99 */
100 static NTSTATUS sidmap_primary_domain_sid(struct sidmap_context *sidmap, 
101                                           TALLOC_CTX *mem_ctx, struct dom_sid **sid)
102 {
103         const char *attrs[] = { "objectSid", NULL };
104         int ret;
105         struct ldb_message **res = NULL;
106
107         ret = gendb_search_dn(sidmap->samctx, mem_ctx, NULL, &res, attrs);
108         if (ret != 1) {
109                 talloc_free(res);
110                 return NT_STATUS_NO_SUCH_DOMAIN;
111         }
112         
113         *sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
114         talloc_free(res);
115         if (*sid == NULL) {
116                 return NT_STATUS_NO_MEMORY;
117         }
118
119         return NT_STATUS_OK;
120 }
121
122
123 /*
124   map a sid to a unix uid
125 */
126 _PUBLIC_ NTSTATUS sidmap_sid_to_unixuid(struct sidmap_context *sidmap, 
127                                         struct dom_sid *sid, uid_t *uid)
128 {
129         const char *attrs[] = { "sAMAccountName", "uidNumber", 
130                                 "sAMAccountType", "unixName", NULL };
131         int ret;
132         const char *s;
133         TALLOC_CTX *tmp_ctx;
134         struct ldb_message **res;
135         struct dom_sid *domain_sid;
136         NTSTATUS status;
137
138         tmp_ctx = talloc_new(sidmap);
139
140         ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, 
141                            "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
142         if (ret != 1) {
143                 goto allocated_sid;
144         }
145
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;
152         }
153
154         /* first try to get the uid directly */
155         s = samdb_result_string(res[0], "uidNumber", NULL);
156         if (s != NULL) {
157                 *uid = strtoul(s, NULL, 0);
158                 talloc_free(tmp_ctx);
159                 return NT_STATUS_OK;
160         }
161
162         /* next try via the UnixName attribute */
163         s = samdb_result_string(res[0], "unixName", NULL);
164         if (s != NULL) {
165                 struct passwd *pwd = getpwnam(s);
166                 if (!pwd) {
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;
171                 }
172                 *uid = pwd->pw_uid;
173                 talloc_free(tmp_ctx);
174                 return NT_STATUS_OK;
175         }
176
177         /* finally try via the sAMAccountName attribute */
178         s = samdb_result_string(res[0], "sAMAccountName", NULL);
179         if (s != NULL) {
180                 struct passwd *pwd = getpwnam(s);
181                 if (!pwd) {
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;
186                 }
187                 *uid = pwd->pw_uid;
188                 talloc_free(tmp_ctx);
189                 return NT_STATUS_OK;
190         }
191
192
193 allocated_sid:
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;
198         }
199
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);
206                         return NT_STATUS_OK;
207                 }
208         }
209         
210
211         DEBUG(0,("sid_to_unixuid: no uidNumber, unixName or sAMAccountName for sid %s\n", 
212                  dom_sid_string(tmp_ctx, sid)));
213
214         talloc_free(tmp_ctx);
215         return NT_STATUS_NONE_MAPPED;
216 }
217
218
219 /*
220   see if a sid is a group - very inefficient!
221 */
222 _PUBLIC_ bool sidmap_sid_is_group(struct sidmap_context *sidmap, struct dom_sid *sid)
223 {
224         const char *attrs[] = { "sAMAccountType", NULL };
225         int ret;
226         TALLOC_CTX *tmp_ctx;
227         struct ldb_message **res;
228         NTSTATUS status;
229         struct dom_sid *domain_sid;
230         bool is_group;
231
232         tmp_ctx = talloc_new(sidmap);
233
234         ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, 
235                            "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
236         if (ret == 1) {
237                 is_group = is_group_account(res[0]);
238                 talloc_free(tmp_ctx);
239                 return is_group;
240         }
241
242         status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
243         if (!NT_STATUS_IS_OK(status)) {
244                 talloc_free(tmp_ctx);
245                 return false;
246         }
247
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);
252                         return true;
253                 }
254         }
255
256         talloc_free(tmp_ctx);
257         return false;
258 }
259
260 /*
261   map a sid to a unix gid
262 */
263 _PUBLIC_ NTSTATUS sidmap_sid_to_unixgid(struct sidmap_context *sidmap,
264                                         struct dom_sid *sid, gid_t *gid)
265 {
266         const char *attrs[] = { "sAMAccountName", "gidNumber", 
267                                 "unixName", "sAMAccountType", NULL };
268         int ret;
269         const char *s;
270         TALLOC_CTX *tmp_ctx;
271         struct ldb_message **res;
272         NTSTATUS status;
273         struct dom_sid *domain_sid;
274
275         tmp_ctx = talloc_new(sidmap);
276
277         ret = gendb_search(sidmap->samctx, tmp_ctx, NULL, &res, attrs, 
278                            "objectSid=%s", ldap_encode_ndr_dom_sid(tmp_ctx, sid));
279         if (ret != 1) {
280                 goto allocated_sid;
281         }
282
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;
289         }
290
291         /* first try to get the gid directly */
292         s = samdb_result_string(res[0], "gidNumber", NULL);
293         if (s != NULL) {
294                 *gid = strtoul(s, NULL, 0);
295                 talloc_free(tmp_ctx);
296                 return NT_STATUS_OK;
297         }
298
299         /* next try via the UnixName attribute */
300         s = samdb_result_string(res[0], "unixName", NULL);
301         if (s != NULL) {
302                 struct group *grp = getgrnam(s);
303                 if (!grp) {
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;
308                 }
309                 *gid = grp->gr_gid;
310                 talloc_free(tmp_ctx);
311                 return NT_STATUS_OK;
312         }
313
314         /* finally try via the sAMAccountName attribute */
315         s = samdb_result_string(res[0], "sAMAccountName", NULL);
316         if (s != NULL) {
317                 struct group *grp = getgrnam(s);
318                 if (!grp) {
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;
322                 }
323                 *gid = grp->gr_gid;
324                 talloc_free(tmp_ctx);
325                 return NT_STATUS_OK;
326         }
327
328 allocated_sid:
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;
333         }
334
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);
340                         return NT_STATUS_OK;
341                 }
342         }
343
344         DEBUG(0,("sid_to_unixgid: no gidNumber, unixName or sAMAccountName for sid %s\n", 
345                  dom_sid_string(tmp_ctx, sid)));
346
347         talloc_free(tmp_ctx);
348         return NT_STATUS_NONE_MAPPED;
349 }
350
351
352 /*
353   map a unix uid to a dom_sid
354   the returned sid is allocated in the supplied mem_ctx
355 */
356 _PUBLIC_ NTSTATUS sidmap_uid_to_sid(struct sidmap_context *sidmap,
357                                     TALLOC_CTX *mem_ctx,
358                                     uid_t uid, struct dom_sid **sid)
359 {
360         const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
361         int ret, i;
362         TALLOC_CTX *tmp_ctx;
363         struct ldb_message **res;
364         struct passwd *pwd;
365         struct dom_sid *domain_sid;
366         NTSTATUS status;
367
368         /*
369           we search for the mapping in the following order:
370
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
375               given uid
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
379               domain
380         */
381
382
383         tmp_ctx = talloc_new(mem_ctx);
384
385
386         /*
387           step 2: look for a user account in samdb that has uidNumber set to the
388                   given uid
389         */
390
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;
395
396                 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
397                 talloc_free(tmp_ctx);
398                 NT_STATUS_HAVE_NO_MEMORY(*sid);
399                 return NT_STATUS_OK;
400         }
401
402         /*
403           step 3: look for a user account in samdb that has unixName
404                   or sAMAccountName set to the name given by getpwuid()
405         */
406         pwd = getpwuid(uid);
407         if (pwd == NULL) {
408                 goto allocate_sid;
409         }
410
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;
416
417                 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
418                 talloc_free(tmp_ctx);
419                 NT_STATUS_HAVE_NO_MEMORY(*sid);
420                 return NT_STATUS_OK;
421         }
422
423
424         /*
425             step 4: assign a SID by adding the uid to
426                     SIDMAP_LOCAL_USER_BASE in the local domain
427         */
428 allocate_sid:
429         if (uid > SIDMAP_MAX_LOCAL_UID) {
430                 return NT_STATUS_NONE_MAPPED;
431         }
432
433         status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
434         if (!NT_STATUS_IS_OK(status)) {
435                 talloc_free(tmp_ctx);
436                 return status;
437         }
438
439         *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_USER_BASE + uid);
440         talloc_free(tmp_ctx);
441
442         if (*sid == NULL) {
443                 return NT_STATUS_NO_MEMORY;
444         }
445
446         return NT_STATUS_OK;
447 }
448
449
450 /*
451   map a unix gid to a dom_sid
452   the returned sid is allocated in the supplied mem_ctx
453 */
454 _PUBLIC_ NTSTATUS sidmap_gid_to_sid(struct sidmap_context *sidmap,
455                                     TALLOC_CTX *mem_ctx,
456                                     gid_t gid, struct dom_sid **sid)
457 {
458         const char *attrs[] = { "sAMAccountName", "objectSid", "sAMAccountType", NULL };
459         int ret, i;
460         TALLOC_CTX *tmp_ctx;
461         struct ldb_message **res;
462         struct group *grp;
463         struct dom_sid *domain_sid;
464         NTSTATUS status;
465
466         /*
467           we search for the mapping in the following order:
468
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
473               given gid
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
477               domain
478         */
479
480
481         tmp_ctx = talloc_new(sidmap);
482
483
484         /*
485           step 2: look for a group account in samdb that has gidNumber set to the
486                   given gid
487         */
488
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;
493
494                 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
495                 talloc_free(tmp_ctx);
496                 NT_STATUS_HAVE_NO_MEMORY(*sid);
497                 return NT_STATUS_OK;
498         }
499
500         /*
501           step 3: look for a group account in samdb that has unixName
502                   or sAMAccountName set to the name given by getgrgid()
503         */
504         grp = getgrgid(gid);
505         if (grp == NULL) {
506                 goto allocate_sid;
507         }
508
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;
514
515                 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
516                 talloc_free(tmp_ctx);
517                 NT_STATUS_HAVE_NO_MEMORY(*sid);
518                 return NT_STATUS_OK;
519         }
520
521
522         /*
523             step 4: assign a SID by adding the gid to
524                     SIDMAP_LOCAL_GROUP_BASE in the local domain
525         */
526 allocate_sid:
527         if (gid > SIDMAP_MAX_LOCAL_GID) {
528                 return NT_STATUS_NONE_MAPPED;
529         }
530
531         status = sidmap_primary_domain_sid(sidmap, tmp_ctx, &domain_sid);
532         if (!NT_STATUS_IS_OK(status)) {
533                 talloc_free(tmp_ctx);
534                 return status;
535         }
536
537         *sid = dom_sid_add_rid(mem_ctx, domain_sid, SIDMAP_LOCAL_GROUP_BASE + gid);
538         talloc_free(tmp_ctx);
539
540         if (*sid == NULL) {
541                 return NT_STATUS_NO_MEMORY;
542         }
543
544         return NT_STATUS_OK;
545 }
546
547 /*
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
550 */
551 _PUBLIC_ NTSTATUS sidmap_allocated_sid_lookup(struct sidmap_context *sidmap, 
552                                               TALLOC_CTX *mem_ctx, 
553                                               const struct dom_sid *sid,
554                                               const char **name,
555                                               enum lsa_SidType *rtype)
556 {
557         NTSTATUS status;
558         struct dom_sid *domain_sid;
559         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
560         uint32_t rid, atype;
561         
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;
565         }
566
567         if (!dom_sid_in_domain(domain_sid, sid)) {
568                 talloc_free(tmp_ctx);
569                 return NT_STATUS_NONE_MAPPED;
570         }
571
572         talloc_free(tmp_ctx);
573
574         rid = sid->sub_auths[sid->num_auths-1];
575         if (rid < SIDMAP_LOCAL_USER_BASE) {
576                 return NT_STATUS_NONE_MAPPED;
577         }
578
579         if (rid < SIDMAP_LOCAL_GROUP_BASE) {
580                 struct passwd *pwd;
581                 uid_t uid = rid - SIDMAP_LOCAL_USER_BASE;
582                 atype = ATYPE_NORMAL_ACCOUNT;
583                 *rtype = samdb_atype_map(atype);
584
585                 pwd = getpwuid(uid);
586                 if (pwd == NULL) {
587                         *name = talloc_asprintf(mem_ctx, "uid%u", uid);
588                 } else {
589                         *name = talloc_strdup(mem_ctx, pwd->pw_name);
590                 }
591         } else {
592                 struct group *grp;
593                 gid_t gid = rid - SIDMAP_LOCAL_GROUP_BASE;
594                 atype = ATYPE_LOCAL_GROUP;
595                 *rtype = samdb_atype_map(atype);
596                 grp = getgrgid(gid);
597                 if (grp == NULL) {
598                         *name = talloc_asprintf(mem_ctx, "gid%u", gid);
599                 } else {
600                         *name = talloc_strdup(mem_ctx, grp->gr_name);
601                 }
602         }
603
604         if (*name == NULL) {
605                 return NT_STATUS_NO_MEMORY;
606         }
607
608         return NT_STATUS_OK;
609 }