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