libds: merge the UF<->ACB flag mapping functions.
[gd/samba-autobuild/.git] / source4 / 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 "../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 */
45 struct sidmap_context {
46         struct ldb_context *samctx;
47 };
48
49 /*
50   open a sidmap context - use talloc_free to close
51 */
52 struct 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 */
74 static 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 */
87 static 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 */
101 static 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 */
127 NTSTATUS 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
196 allocated_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 */
225 bool 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 */
266 NTSTATUS 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
331 allocated_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 */
359 NTSTATUS 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         */
431 allocate_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 */
457 NTSTATUS 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         */
529 allocate_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 */
554 NTSTATUS 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 }