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