root/source4/dsdb/common/sidmap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sidmap_open
  2. is_user_account
  3. is_group_account
  4. sidmap_primary_domain_sid
  5. sidmap_sid_to_unixuid
  6. sidmap_sid_is_group
  7. sidmap_sid_to_unixgid
  8. sidmap_uid_to_sid
  9. sidmap_gid_to_sid
  10. sidmap_allocated_sid_lookup

   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 "../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, 
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
  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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 = samdb_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 = samdb_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 }

/* [<][>][^][v][top][bottom][index][help] */