1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Windows to Solaris Identity Mapping kernel API
  29  * This module provides an API to map Windows SIDs to
  30  * Solaris UID and GIDs.
  31  */
  32 
  33 
  34 #include <sys/types.h>
  35 #include <sys/ksynch.h>
  36 #include <sys/door.h>
  37 #include <rpc/rpc_msg.h>
  38 #include <rpc/xdr.h>
  39 #include <rpc/auth.h>
  40 #include <rpc/rpc_sztypes.h>
  41 #ifdef  DEBUG
  42 #include <sys/cmn_err.h>
  43 #endif  /* DEBUG */
  44 #include <sys/proc.h>
  45 #include <sys/sunddi.h>
  46 #include <sys/param.h>
  47 #include <sys/atomic.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/disp.h>
  50 #include <sys/kidmap.h>
  51 #include <sys/zone.h>
  52 #include <rpcsvc/idmap_prot.h>
  53 #include "kidmap_priv.h"
  54 
  55 
  56 /*
  57  * Defined types
  58  */
  59 
  60 
  61 /*
  62  * This structure holds pointers for the
  63  * batch mapping results.
  64  */
  65 typedef struct idmap_get_res {
  66         idmap_id_type   idtype;
  67         uid_t           *uid;
  68         gid_t           *gid;
  69         uid_t           *pid;
  70         int             *is_user;
  71         const char      **sid_prefix;
  72         uint32_t        *rid;
  73         idmap_stat      *stat;
  74 } idmap_get_res;
  75 
  76 /* Batch mapping handle structure */
  77 struct idmap_get_handle {
  78         struct idmap_zone_specific *zs;
  79         int             mapping_num;
  80         int             mapping_size;
  81         idmap_mapping   *mapping;
  82         idmap_get_res   *result;
  83 };
  84 
  85 
  86 /* Zone specific data */
  87 typedef struct idmap_zone_specific {
  88         zoneid_t        zone_id;
  89         kmutex_t        zone_mutex;
  90         idmap_cache_t   cache;
  91         door_handle_t   door_handle;
  92         int             door_valid;
  93         int             door_retried;
  94         uint32_t        message_id;
  95 } idmap_zone_specific_t;
  96 
  97 
  98 
  99 /*
 100  * Module global data
 101  */
 102 
 103 static kmutex_t         idmap_zone_mutex;
 104 static zone_key_t       idmap_zone_key;
 105 
 106 
 107 /*
 108  * Local function definitions
 109  */
 110 
 111 
 112 static int
 113 kidmap_rpc_call(idmap_zone_specific_t *zs, uint32_t op,
 114     xdrproc_t xdr_args, caddr_t args, xdrproc_t xdr_res, caddr_t res);
 115 
 116 static int
 117 kidmap_call_door(idmap_zone_specific_t *zs, door_arg_t *arg);
 118 
 119 static idmap_zone_specific_t *
 120 idmap_get_zone_specific(zone_t *zone);
 121 
 122 
 123 
 124 int
 125 idmap_reg_dh(zone_t *zone, door_handle_t dh)
 126 {
 127         idmap_zone_specific_t *zs;
 128 
 129         zs = idmap_get_zone_specific(zone);
 130 
 131         mutex_enter(&zs->zone_mutex);
 132 
 133         if (zs->door_valid)
 134                 door_ki_rele(zs->door_handle);
 135 
 136         zs->door_handle = dh;
 137         zs->door_valid = 1;
 138 
 139         mutex_exit(&zs->zone_mutex);
 140 
 141         return (0);
 142 }
 143 
 144 /*
 145  * idmap_unreg_dh
 146  *
 147  * This routine is called by system call idmap_unreg().
 148  * idmap_unreg() calls door_ki_rele() on the supplied
 149  * door handle after this routine returns. We only
 150  * need to perform one door release on zs->door_handle
 151  */
 152 int
 153 idmap_unreg_dh(zone_t *zone, door_handle_t dh)
 154 {
 155         idmap_zone_specific_t *zs;
 156 
 157         zs = idmap_get_zone_specific(zone);
 158 
 159         kidmap_cache_purge(&zs->cache);
 160 
 161         mutex_enter(&zs->zone_mutex);
 162 
 163         if (!zs->door_valid || zs->door_handle != dh) {
 164                 mutex_exit(&zs->zone_mutex);
 165                 return (EINVAL);
 166         }
 167 
 168         door_ki_rele(zs->door_handle);
 169 
 170         zs->door_valid = 0;
 171         zs->door_retried = 0;
 172         mutex_exit(&zs->zone_mutex);
 173 
 174         return (0);
 175 }
 176 
 177 
 178 /*
 179  * IMPORTANT. This function idmap_get_cache_data() is project
 180  * private and is for use of the test system only and should
 181  * not be used for other purposes.
 182  */
 183 void
 184 idmap_get_cache_data(zone_t *zone, size_t *uidbysid, size_t *gidbysid,
 185     size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid)
 186 {
 187         idmap_zone_specific_t *zs;
 188 
 189         zs = idmap_get_zone_specific(zone);
 190 
 191         kidmap_cache_get_data(&zs->cache, uidbysid, gidbysid,
 192             pidbysid, sidbyuid, sidbygid);
 193 }
 194 
 195 static int
 196 kidmap_call_door(idmap_zone_specific_t *zs, door_arg_t *arg)
 197 {
 198         door_handle_t   dh;
 199         door_info_t     di;
 200         int             status = 0;
 201         int             num_retries = 5;
 202         int             door_retried = 0;
 203 
 204 retry:
 205         mutex_enter(&zs->zone_mutex);
 206         if (zs->door_valid) {
 207                 dh = zs->door_handle;
 208                 door_ki_hold(dh);
 209         } else {
 210                 dh = NULL;
 211                 door_retried = zs->door_retried;
 212         }
 213         mutex_exit(&zs->zone_mutex);
 214 
 215         if (dh == NULL) {
 216                 /* The door has been retried before so dont wait */
 217                 if (door_retried)
 218                         return (-1);
 219 
 220                 /*
 221                  * There is no door handle yet. Give
 222                  * smf a chance to restart idmapd
 223                  */
 224                 if (num_retries-- > 0) {
 225                         delay(hz);
 226                         goto retry;
 227                 }
 228 
 229 #ifdef  DEBUG
 230                 zcmn_err(zs->zone_id, CE_WARN,
 231                     "idmap: Error no registered door to call the "
 232                     "idmap daemon\n");
 233 #endif
 234                 mutex_enter(&zs->zone_mutex);
 235                 if (!zs->door_valid)
 236                         zs->door_retried = 1;
 237                 mutex_exit(&zs->zone_mutex);
 238 
 239                 return (-1);
 240         }
 241 
 242         status = door_ki_upcall_limited(dh, arg, NULL, SIZE_MAX, 0);
 243 
 244         switch (status) {
 245         case 0: /* Success */
 246                 door_ki_rele(dh);
 247                 return (0);
 248 
 249         case EINTR:
 250                 /* If we took an interrupt we have to bail out. */
 251                 if (ttolwp(curthread) && ISSIG(curthread, JUSTLOOKING)) {
 252                         door_ki_rele(dh);
 253 #ifdef  DEBUG
 254                         zcmn_err(zs->zone_id, CE_WARN,
 255                             "idmap: Interrupted\n");
 256 #endif
 257                         return (-1);
 258                 }
 259                 /*
 260                  * Just retry and see what happens.
 261                  */
 262                 /* FALLTHROUGH */
 263 
 264         case EAGAIN:
 265                 /* A resouce problem */
 266                 door_ki_rele(dh);
 267                 /* Back off before retrying */
 268 #ifdef  DEBUG
 269                 zcmn_err(zs->zone_id, CE_WARN,
 270                     "idmap: Door call returned error %d. Retrying\n", status);
 271 #endif  /* DEBUG */
 272                 delay(hz);
 273                 goto retry;
 274 
 275         case EBADF:
 276                 /* Stale door handle. See if smf restarts the daemon. */
 277                 door_ki_rele(dh);
 278                 mutex_enter(&zs->zone_mutex);
 279                 if (zs->door_valid && dh == zs->door_handle) {
 280                         zs->door_valid = 0;
 281                         zs->door_retried = 0;
 282                         door_ki_rele(zs->door_handle);
 283                 }
 284                 mutex_exit(&zs->zone_mutex);
 285                 /* Back off before retrying */
 286 #ifdef  DEBUG
 287                 zcmn_err(zs->zone_id, CE_WARN,
 288                     "idmap: Door call returned error %d. Retrying\n", status);
 289 #endif  /* DEBUG */
 290                 delay(hz);
 291                 goto retry;
 292 
 293         default:
 294                 /* Unknown error */
 295 #ifdef  DEBUG
 296                 zcmn_err(zs->zone_id, CE_WARN,
 297                     "idmap: Door call returned error %d.\n", status);
 298 #endif  /* DEBUG */
 299                 door_ki_rele(dh);
 300                 return (-1);
 301         }
 302 }
 303 
 304 
 305 static idmap_zone_specific_t *
 306 idmap_get_zone_specific(zone_t *zone)
 307 {
 308         idmap_zone_specific_t *zs;
 309 
 310         ASSERT(zone != NULL);
 311 
 312         zs = zone_getspecific(idmap_zone_key, zone);
 313         if (zs != NULL)
 314                 return (zs);
 315 
 316         mutex_enter(&idmap_zone_mutex);
 317         zs = zone_getspecific(idmap_zone_key, zone);
 318         if (zs == NULL) {
 319                 zs = kmem_zalloc(sizeof (idmap_zone_specific_t), KM_SLEEP);
 320                 mutex_init(&zs->zone_mutex, NULL, MUTEX_DEFAULT, NULL);
 321                 kidmap_cache_create(&zs->cache);
 322                 zs->zone_id = zone->zone_id;
 323                 (void) zone_setspecific(idmap_zone_key, zone, zs);
 324                 mutex_exit(&idmap_zone_mutex);
 325                 return (zs);
 326         }
 327         mutex_exit(&idmap_zone_mutex);
 328 
 329         return (zs);
 330 }
 331 
 332 
 333 static void
 334 /* ARGSUSED */
 335 idmap_zone_destroy(zoneid_t zone_id, void *arg)
 336 {
 337         idmap_zone_specific_t *zs = arg;
 338         if (zs != NULL) {
 339                 kidmap_cache_delete(&zs->cache);
 340                 if (zs->door_valid) {
 341                         door_ki_rele(zs->door_handle);
 342                 }
 343                 mutex_destroy(&zs->zone_mutex);
 344                 kmem_free(zs, sizeof (idmap_zone_specific_t));
 345         }
 346 }
 347 
 348 
 349 int
 350 kidmap_start(void)
 351 {
 352         mutex_init(&idmap_zone_mutex, NULL, MUTEX_DEFAULT, NULL);
 353         zone_key_create(&idmap_zone_key, NULL, NULL, idmap_zone_destroy);
 354         kidmap_sid_prefix_store_init();
 355 
 356         return (0);
 357 }
 358 
 359 
 360 int
 361 kidmap_stop(void)
 362 {
 363         return (EBUSY);
 364 }
 365 
 366 
 367 /*
 368  * idmap_get_door
 369  *
 370  * This is called by the system call allocids() to get the door for the
 371  * given zone.
 372  */
 373 door_handle_t
 374 idmap_get_door(zone_t *zone)
 375 {
 376         door_handle_t dh = NULL;
 377         idmap_zone_specific_t *zs;
 378 
 379         zs = idmap_get_zone_specific(zone);
 380 
 381         mutex_enter(&zs->zone_mutex);
 382         if (zs->door_valid) {
 383                 dh = zs->door_handle;
 384                 door_ki_hold(dh);
 385         }
 386         mutex_exit(&zs->zone_mutex);
 387         return (dh);
 388 }
 389 
 390 
 391 /*
 392  * idmap_purge_cache
 393  *
 394  * This is called by the system call allocids() to purge the cache for the
 395  * given zone.
 396  */
 397 void
 398 idmap_purge_cache(zone_t *zone)
 399 {
 400         idmap_zone_specific_t *zs;
 401 
 402         zs = idmap_get_zone_specific(zone);
 403 
 404         kidmap_cache_purge(&zs->cache);
 405 }
 406 
 407 
 408 
 409 
 410 /*
 411  * Given Domain SID and RID, get UID
 412  *
 413  * Input:
 414  * sid_prefix   - Domain SID in canonical form
 415  * rid  - RID
 416  *
 417  * Output:
 418  * uid  - POSIX UID if return == IDMAP_SUCCESS
 419  *
 420  * Return:
 421  * Success return IDMAP_SUCCESS else IDMAP error
 422  */
 423 idmap_stat
 424 kidmap_getuidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
 425     uid_t *uid)
 426 {
 427         idmap_zone_specific_t   *zs;
 428         idmap_mapping_batch     args;
 429         idmap_mapping           mapping;
 430         idmap_ids_res           results;
 431         uint32_t                op = IDMAP_GET_MAPPED_IDS;
 432         const char              *new_sid_prefix;
 433         idmap_stat              status;
 434 
 435         if (sid_prefix == NULL || uid == NULL)
 436                 return (IDMAP_ERR_ARG);
 437 
 438         zs = idmap_get_zone_specific(zone);
 439 
 440         if (kidmap_cache_lookup_uidbysid(&zs->cache, sid_prefix, rid, uid)
 441             == IDMAP_SUCCESS)
 442                 return (IDMAP_SUCCESS);
 443 
 444         bzero(&mapping, sizeof (idmap_mapping));
 445         mapping.id1.idtype = IDMAP_SID;
 446         mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
 447         mapping.id1.idmap_id_u.sid.rid = rid;
 448         mapping.id2.idtype = IDMAP_UID;
 449 
 450         bzero(&results, sizeof (idmap_ids_res));
 451 
 452         args.idmap_mapping_batch_len = 1;
 453         args.idmap_mapping_batch_val = &mapping;
 454 
 455         if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
 456             (caddr_t)&args, xdr_idmap_ids_res,
 457             (caddr_t)&results) == 0) {
 458                 /* Door call succeded */
 459                 if (results.retcode != IDMAP_SUCCESS) {
 460                         status = results.retcode;
 461                         *uid = UID_NOBODY;
 462                 } else if (results.ids.ids_len >= 1 &&
 463                     results.ids.ids_val[0].id.idtype == IDMAP_UID) {
 464                         status = results.ids.ids_val[0].retcode;
 465                         *uid = results.ids.ids_val[0].id.idmap_id_u.uid;
 466                         if (status == IDMAP_SUCCESS) {
 467                                 new_sid_prefix = kidmap_find_sid_prefix(
 468                                     sid_prefix);
 469                                 kidmap_cache_add_sid2uid(&zs->cache,
 470                                     new_sid_prefix, rid, *uid,
 471                                     results.ids.ids_val[0].direction);
 472                         }
 473                 } else {
 474                         status = IDMAP_ERR_NOMAPPING;
 475                         *uid = UID_NOBODY;
 476                 }
 477                 xdr_free(xdr_idmap_ids_res, (char *)&results);
 478         } else {
 479                 /* Door call failed */
 480                 status = IDMAP_ERR_NOMAPPING;
 481                 *uid = UID_NOBODY;
 482         }
 483         return (status);
 484 }
 485 
 486 
 487 /*
 488  * Given Domain SID and RID, get GID
 489  *
 490  * Input:
 491  * sid_prefix   - Domain SID in canonical form
 492  * rid  - RID
 493  *
 494  * Output:
 495  * gid  - POSIX UID if return == IDMAP_SUCCESS
 496  *
 497  * Return:
 498  * Success return IDMAP_SUCCESS else IDMAP error
 499  */
 500 idmap_stat
 501 kidmap_getgidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
 502     gid_t *gid)
 503 {
 504         idmap_zone_specific_t   *zs;
 505         idmap_mapping_batch     args;
 506         idmap_mapping           mapping;
 507         idmap_ids_res           results;
 508         uint32_t                op = IDMAP_GET_MAPPED_IDS;
 509         const char              *new_sid_prefix;
 510         idmap_stat              status;
 511 
 512         if (sid_prefix == NULL || gid == NULL)
 513                 return (IDMAP_ERR_ARG);
 514 
 515         zs = idmap_get_zone_specific(zone);
 516 
 517         if (kidmap_cache_lookup_gidbysid(&zs->cache, sid_prefix, rid, gid)
 518             == IDMAP_SUCCESS)
 519                 return (IDMAP_SUCCESS);
 520 
 521         bzero(&mapping, sizeof (idmap_mapping));
 522         mapping.id1.idtype = IDMAP_SID;
 523         mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
 524         mapping.id1.idmap_id_u.sid.rid = rid;
 525         mapping.id2.idtype = IDMAP_GID;
 526 
 527         bzero(&results, sizeof (idmap_ids_res));
 528 
 529         args.idmap_mapping_batch_len = 1;
 530         args.idmap_mapping_batch_val = &mapping;
 531 
 532         if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
 533             (caddr_t)&args, xdr_idmap_ids_res,
 534             (caddr_t)&results) == 0) {
 535                 /* Door call succeded */
 536                 if (results.retcode != IDMAP_SUCCESS) {
 537                         status = results.retcode;
 538                         *gid = GID_NOBODY;
 539                 } else if (results.ids.ids_len >= 1 &&
 540                     results.ids.ids_val[0].id.idtype == IDMAP_GID) {
 541                         status = results.ids.ids_val[0].retcode;
 542                         *gid = results.ids.ids_val[0].id.idmap_id_u.gid;
 543                         if (status == IDMAP_SUCCESS) {
 544                                 new_sid_prefix = kidmap_find_sid_prefix(
 545                                     sid_prefix);
 546                                 kidmap_cache_add_sid2gid(&zs->cache,
 547                                     new_sid_prefix, rid, *gid,
 548                                     results.ids.ids_val[0].direction);
 549                         }
 550                 } else {
 551                         status = IDMAP_ERR_NOMAPPING;
 552                         *gid = GID_NOBODY;
 553                 }
 554                 xdr_free(xdr_idmap_ids_res, (char *)&results);
 555         } else {
 556                 /* Door call failed */
 557                 status = IDMAP_ERR_NOMAPPING;
 558                 *gid = GID_NOBODY;
 559         }
 560         return (status);
 561 }
 562 
 563 /*
 564  * Given Domain SID and RID, get Posix ID
 565  *
 566  * Input:
 567  * sid_prefix   - Domain SID in canonical form
 568  * rid  - RID
 569  *
 570  * Output:
 571  * pid  - POSIX ID if return == IDMAP_SUCCESS
 572  * is_user - 1 == UID, 0 == GID  if return == IDMAP_SUCCESS
 573  *
 574  * Return:
 575  * Success return IDMAP_SUCCESS else IDMAP error
 576  */
 577 idmap_stat
 578 kidmap_getpidbysid(zone_t *zone, const char *sid_prefix, uint32_t rid,
 579     uid_t *pid, int *is_user)
 580 {
 581         idmap_zone_specific_t   *zs;
 582         idmap_mapping_batch     args;
 583         idmap_mapping           mapping;
 584         idmap_ids_res           results;
 585         uint32_t                op = IDMAP_GET_MAPPED_IDS;
 586         const char              *new_sid_prefix;
 587         idmap_stat              status;
 588 
 589         if (sid_prefix == NULL || pid == NULL || is_user == NULL)
 590                 return (IDMAP_ERR_ARG);
 591 
 592         zs = idmap_get_zone_specific(zone);
 593 
 594         if (kidmap_cache_lookup_pidbysid(&zs->cache, sid_prefix, rid, pid,
 595             is_user) == IDMAP_SUCCESS)
 596                 return (IDMAP_SUCCESS);
 597 
 598         bzero(&mapping, sizeof (idmap_mapping));
 599         mapping.id1.idtype = IDMAP_SID;
 600         mapping.id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
 601         mapping.id1.idmap_id_u.sid.rid = rid;
 602         mapping.id2.idtype = IDMAP_POSIXID;
 603 
 604         bzero(&results, sizeof (idmap_ids_res));
 605 
 606         args.idmap_mapping_batch_len = 1;
 607         args.idmap_mapping_batch_val = &mapping;
 608 
 609         if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
 610             (caddr_t)&args, xdr_idmap_ids_res,
 611             (caddr_t)&results) == 0) {
 612                 /* Door call succeded */
 613                 if (results.retcode != IDMAP_SUCCESS) {
 614                         status = results.retcode;
 615                         *is_user = 1;
 616                         *pid = UID_NOBODY;
 617                 } else if (results.ids.ids_len >= 1 && (
 618                     results.ids.ids_val[0].id.idtype == IDMAP_UID ||
 619                     results.ids.ids_val[0].id.idtype == IDMAP_GID)) {
 620                         status = results.ids.ids_val[0].retcode;
 621                         if (results.ids.ids_val[0].id.idtype == IDMAP_UID) {
 622                                 *is_user = 1;
 623                                 *pid = results.ids.ids_val[0].id.idmap_id_u.uid;
 624                         } else {
 625                                 *is_user = 0;
 626                                 *pid = results.ids.ids_val[0].id.idmap_id_u.gid;
 627                         }
 628                         if (status == IDMAP_SUCCESS) {
 629                                 new_sid_prefix = kidmap_find_sid_prefix(
 630                                     sid_prefix);
 631                                 kidmap_cache_add_sid2pid(&zs->cache,
 632                                     new_sid_prefix, rid, *pid,
 633                                     *is_user,
 634                                     results.ids.ids_val[0].direction);
 635                         }
 636                 } else {
 637                         status = IDMAP_ERR_NOMAPPING;
 638                         *is_user = 1;
 639                         *pid = UID_NOBODY;
 640                 }
 641                 xdr_free(xdr_idmap_ids_res, (char *)&results);
 642         } else {
 643                 /* Door call failed */
 644                 status = IDMAP_ERR_NOMAPPING;
 645                 *is_user = 1;
 646                 *pid = UID_NOBODY;
 647         }
 648         return (status);
 649 }
 650 
 651 
 652 /*
 653  * Given UID, get Domain SID and RID
 654  *
 655  * Input:
 656  * uid - Posix UID
 657  *
 658  * Output:
 659  * sid_prefix   - Domain SID if return == IDMAP_SUCCESS
 660  * rid  - RID if return == IDMAP_SUCCESS
 661  *
 662  * Return:
 663  * Success return IDMAP_SUCCESS else IDMAP error
 664  */
 665 idmap_stat
 666 kidmap_getsidbyuid(zone_t *zone, uid_t uid, const char **sid_prefix,
 667     uint32_t *rid)
 668 {
 669         idmap_zone_specific_t   *zs;
 670         idmap_mapping_batch     args;
 671         idmap_mapping           mapping;
 672         idmap_ids_res           results;
 673         uint32_t                op = IDMAP_GET_MAPPED_IDS;
 674         idmap_stat              status;
 675         time_t                  entry_ttl;
 676         idmap_id                *id;
 677 
 678         if (sid_prefix == NULL || rid == NULL)
 679                 return (IDMAP_ERR_ARG);
 680 
 681         zs = idmap_get_zone_specific(zone);
 682 
 683         if (kidmap_cache_lookup_sidbyuid(&zs->cache, sid_prefix, rid, uid)
 684             == IDMAP_SUCCESS) {
 685                 return (IDMAP_SUCCESS);
 686         }
 687 
 688         bzero(&mapping, sizeof (idmap_mapping));
 689         mapping.id1.idtype = IDMAP_UID;
 690         mapping.id1.idmap_id_u.uid = uid;
 691         mapping.id2.idtype = IDMAP_SID;
 692 
 693         bzero(&results, sizeof (idmap_ids_res));
 694 
 695         args.idmap_mapping_batch_len = 1;
 696         args.idmap_mapping_batch_val = &mapping;
 697 
 698         if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
 699             (caddr_t)&args, xdr_idmap_ids_res,
 700             (caddr_t)&results) == 0) {
 701                 /* Door call succeded */
 702                 if (results.retcode != IDMAP_SUCCESS) {
 703                         status = results.retcode;
 704                         *rid = 0;
 705                         *sid_prefix = NULL;
 706                 } else if (results.ids.ids_len >= 1 &&
 707                     (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
 708                     results.ids.ids_val[0].id.idtype == IDMAP_USID ||
 709                     results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
 710                         status = results.ids.ids_val[0].retcode;
 711                         id = &results.ids.ids_val[0].id;
 712                         *sid_prefix = kidmap_find_sid_prefix(
 713                             id->idmap_id_u.sid.prefix);
 714                         *rid = id->idmap_id_u.sid.rid;
 715                         if (status == IDMAP_SUCCESS) {
 716                                 kidmap_cache_add_sid2uid(&zs->cache,
 717                                     *sid_prefix, *rid, uid,
 718                                     results.ids.ids_val[0].direction);
 719                         }
 720                 } else {
 721                         status = IDMAP_ERR_NOMAPPING;
 722                         *rid = 0;
 723                         *sid_prefix = NULL;
 724                 }
 725                 xdr_free(xdr_idmap_ids_res, (char *)&results);
 726         } else {
 727                 /* Door call failed */
 728                 status = IDMAP_ERR_NOMAPPING;
 729                 *rid = 0;
 730                 *sid_prefix = NULL;
 731         }
 732         return (status);
 733 }
 734 
 735 
 736 /*
 737  * Given GID, get Domain SID and RID
 738  *
 739  * Input:
 740  * gid - Posix GID
 741  *
 742  * Output:
 743  * sid_prefix   - Domain SID if return == IDMAP_SUCCESS
 744  * rid  - RID if return == IDMAP_SUCCESS
 745  *
 746  * Return:
 747  * Success return IDMAP_SUCCESS else IDMAP error
 748  */
 749 idmap_stat
 750 kidmap_getsidbygid(zone_t *zone, gid_t gid, const char **sid_prefix,
 751     uint32_t *rid)
 752 {
 753         idmap_zone_specific_t   *zs;
 754         idmap_mapping_batch     args;
 755         idmap_mapping           mapping;
 756         idmap_ids_res           results;
 757         uint32_t                op = IDMAP_GET_MAPPED_IDS;
 758         idmap_stat              status;
 759         idmap_id                *id;
 760 
 761         if (sid_prefix == NULL || rid == NULL)
 762                 return (IDMAP_ERR_ARG);
 763 
 764         zs = idmap_get_zone_specific(zone);
 765 
 766         if (kidmap_cache_lookup_sidbygid(&zs->cache, sid_prefix, rid, gid)
 767             == IDMAP_SUCCESS) {
 768                 return (IDMAP_SUCCESS);
 769         }
 770 
 771         bzero(&mapping, sizeof (idmap_mapping));
 772         mapping.id1.idtype = IDMAP_GID;
 773         mapping.id1.idmap_id_u.uid = gid;
 774         mapping.id2.idtype = IDMAP_SID;
 775 
 776         bzero(&results, sizeof (idmap_ids_res));
 777 
 778         args.idmap_mapping_batch_len = 1;
 779         args.idmap_mapping_batch_val = &mapping;
 780 
 781         if (kidmap_rpc_call(zs, op, xdr_idmap_mapping_batch,
 782             (caddr_t)&args, xdr_idmap_ids_res,
 783             (caddr_t)&results) == 0) {
 784                 /* Door call succeded */
 785                 if (results.retcode != IDMAP_SUCCESS) {
 786                         status = results.retcode;
 787                         *rid = 0;
 788                         *sid_prefix = NULL;
 789                 } else if (results.ids.ids_len >= 1 &&
 790                     (results.ids.ids_val[0].id.idtype == IDMAP_SID ||
 791                     results.ids.ids_val[0].id.idtype == IDMAP_USID ||
 792                     results.ids.ids_val[0].id.idtype == IDMAP_GSID)) {
 793                         status = results.ids.ids_val[0].retcode;
 794                         id = &results.ids.ids_val[0].id;
 795                         *sid_prefix = kidmap_find_sid_prefix(
 796                             id->idmap_id_u.sid.prefix);
 797                         *rid = id->idmap_id_u.sid.rid;
 798                         if (status == IDMAP_SUCCESS) {
 799                                 kidmap_cache_add_sid2gid(&zs->cache,
 800                                     *sid_prefix, *rid, gid,
 801                                     results.ids.ids_val[0].direction);
 802                         }
 803                 } else {
 804                         status = IDMAP_ERR_NOMAPPING;
 805                         *rid = 0;
 806                         *sid_prefix = NULL;
 807                 }
 808                 xdr_free(xdr_idmap_ids_res, (char *)&results);
 809         } else {
 810                 /* Door call failed */
 811                 status = IDMAP_ERR_NOMAPPING;
 812                 *rid = 0;
 813                 *sid_prefix = NULL;
 814         }
 815         return (status);
 816 }
 817 
 818 /*
 819  * Create handle to get SID to UID/GID mapping entries
 820  *
 821  * Input:
 822  *      none
 823  * Return:
 824  *      get_handle
 825  *
 826  */
 827 idmap_get_handle_t *
 828 kidmap_get_create(zone_t *zone)
 829 {
 830         idmap_zone_specific_t   *zs;
 831         idmap_get_handle_t      *handle;
 832 #define INIT_MAPPING_SIZE       32
 833 
 834         zs = idmap_get_zone_specific(zone);
 835 
 836         handle = kmem_zalloc(sizeof (idmap_get_handle_t), KM_SLEEP);
 837 
 838         handle->mapping = kmem_zalloc((sizeof (idmap_mapping)) *
 839             INIT_MAPPING_SIZE, KM_SLEEP);
 840 
 841         handle->result = kmem_zalloc((sizeof (idmap_get_res)) *
 842             INIT_MAPPING_SIZE, KM_SLEEP);
 843         handle->mapping_size = INIT_MAPPING_SIZE;
 844         handle->zs = zs;
 845 
 846         return (handle);
 847 }
 848 
 849 /*
 850  * Internal routine to extend a "get_handle"
 851  */
 852 static void
 853 kidmap_get_extend(idmap_get_handle_t *get_handle)
 854 {
 855         idmap_mapping *mapping;
 856         idmap_get_res *result;
 857         int new_size = get_handle->mapping_size + INIT_MAPPING_SIZE;
 858 
 859         mapping = kmem_zalloc((sizeof (idmap_mapping)) *
 860             new_size, KM_SLEEP);
 861         (void) memcpy(mapping, get_handle->mapping,
 862             (sizeof (idmap_mapping)) * get_handle->mapping_size);
 863 
 864         result = kmem_zalloc((sizeof (idmap_get_res)) *
 865             new_size, KM_SLEEP);
 866         (void) memcpy(result, get_handle->result,
 867             (sizeof (idmap_get_res)) * get_handle->mapping_size);
 868 
 869         kmem_free(get_handle->mapping,
 870             (sizeof (idmap_mapping)) * get_handle->mapping_size);
 871         get_handle->mapping = mapping;
 872 
 873         kmem_free(get_handle->result,
 874             (sizeof (idmap_get_res)) * get_handle->mapping_size);
 875         get_handle->result = result;
 876 
 877         get_handle->mapping_size = new_size;
 878 }
 879 
 880 
 881 /*
 882  * Given Domain SID and RID, get UID
 883  *
 884  * Input:
 885  * sid_prefix   - Domain SID in canonical form
 886  * rid  - RID
 887  *
 888  * Output:
 889  * stat - status of the get request
 890  * uid  - POSIX UID if stat == IDMAP_SUCCESS
 891  *
 892  * Notes:
 893  * The output parameters will be set by idmap_get_mappings()
 894  * The sid_prefix is copied.
 895  */
 896 idmap_stat
 897 kidmap_batch_getuidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
 898     uint32_t rid, uid_t *uid, idmap_stat *stat)
 899 {
 900         idmap_mapping   *mapping;
 901         idmap_get_res   *result;
 902 
 903         if (get_handle == NULL || sid_prefix == NULL ||
 904             uid == NULL || stat == NULL)
 905                 return (IDMAP_ERR_ARG);
 906 
 907         if (kidmap_cache_lookup_uidbysid(&get_handle->zs->cache, sid_prefix,
 908             rid, uid) == IDMAP_SUCCESS) {
 909                 *stat = IDMAP_SUCCESS;
 910                 return (IDMAP_SUCCESS);
 911         }
 912 
 913         /* Get a copy of sid_prefix */
 914         sid_prefix = kidmap_find_sid_prefix(sid_prefix);
 915 
 916         if (get_handle->mapping_num >= get_handle->mapping_size)
 917                 kidmap_get_extend(get_handle);
 918 
 919         mapping = &get_handle->mapping[get_handle->mapping_num];
 920         mapping->flag = 0;
 921         mapping->id1.idtype = IDMAP_SID;
 922         mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
 923         mapping->id1.idmap_id_u.sid.rid = rid;
 924         mapping->id2.idtype = IDMAP_UID;
 925 
 926         result = &get_handle->result[get_handle->mapping_num];
 927         result->idtype = IDMAP_UID;
 928         result->uid = uid;
 929         result->gid = NULL;
 930         result->pid = NULL;
 931         result->sid_prefix = NULL;
 932         result->rid = NULL;
 933         result->is_user = NULL;
 934         result->stat = stat;
 935 
 936         get_handle->mapping_num++;
 937 
 938         return (IDMAP_SUCCESS);
 939 }
 940 
 941 
 942 /*
 943  * Given Domain SID and RID, get GID
 944  *
 945  * Input:
 946  * sid_prefix   - Domain SID in canonical form
 947  * rid  - RID
 948  *
 949  * Output:
 950  * stat - status of the get request
 951  * gid  - POSIX GID if stat == IDMAP_SUCCESS
 952  *
 953  * Notes:
 954  * The output parameters will be set by idmap_get_mappings()
 955  * The sid_prefix is copied.
 956  */
 957 idmap_stat
 958 kidmap_batch_getgidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
 959     uint32_t rid, uid_t *gid, idmap_stat *stat)
 960 {
 961         idmap_mapping   *mapping;
 962         idmap_get_res   *result;
 963 
 964         if (get_handle == NULL || sid_prefix == NULL ||
 965             gid == NULL || stat == NULL)
 966                 return (IDMAP_ERR_ARG);
 967 
 968         if (kidmap_cache_lookup_gidbysid(&get_handle->zs->cache, sid_prefix,
 969             rid, gid) == IDMAP_SUCCESS) {
 970                 *stat = IDMAP_SUCCESS;
 971                 return (IDMAP_SUCCESS);
 972         }
 973 
 974         /* Get a copy of sid_prefix */
 975         sid_prefix = kidmap_find_sid_prefix(sid_prefix);
 976 
 977         if (get_handle->mapping_num >= get_handle->mapping_size)
 978                 kidmap_get_extend(get_handle);
 979 
 980         mapping = &get_handle->mapping[get_handle->mapping_num];
 981         mapping->flag = 0;
 982         mapping->id1.idtype = IDMAP_SID;
 983         mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
 984         mapping->id1.idmap_id_u.sid.rid = rid;
 985         mapping->id2.idtype = IDMAP_GID;
 986 
 987         result = &get_handle->result[get_handle->mapping_num];
 988         result->idtype = IDMAP_GID;
 989         result->uid = NULL;
 990         result->gid = gid;
 991         result->pid = NULL;
 992         result->sid_prefix = NULL;
 993         result->rid = NULL;
 994         result->is_user = NULL;
 995         result->stat = stat;
 996 
 997         get_handle->mapping_num++;
 998 
 999         return (IDMAP_SUCCESS);
1000 }
1001 
1002 
1003 /*
1004  * Given Domain SID and RID, get Posix ID
1005  *
1006  * Input:
1007  * sid_prefix   - Domain SID in canonical form
1008  * rid  - RID
1009  *
1010  * Output:
1011  * stat    - status of the get request
1012  * is_user - user or group
1013  * pid     - POSIX UID if stat == IDMAP_SUCCESS and is_user == 1
1014  *           POSIX GID if stat == IDMAP_SUCCESS and is_user == 0
1015  *
1016  * Notes:
1017  * The output parameters will be set by idmap_get_mappings()
1018  * The sid_prefix is copied.
1019  */
1020 idmap_stat
1021 kidmap_batch_getpidbysid(idmap_get_handle_t *get_handle, const char *sid_prefix,
1022     uint32_t rid, uid_t *pid, int *is_user, idmap_stat *stat)
1023 {
1024         idmap_mapping   *mapping;
1025         idmap_get_res   *result;
1026 
1027         if (get_handle == NULL || sid_prefix == NULL || pid == NULL ||
1028             is_user == NULL || stat == NULL)
1029                 return (IDMAP_ERR_ARG);
1030 
1031         if (kidmap_cache_lookup_pidbysid(&get_handle->zs->cache, sid_prefix,
1032             rid, pid, is_user) == IDMAP_SUCCESS) {
1033                 *stat = IDMAP_SUCCESS;
1034                 return (IDMAP_SUCCESS);
1035         }
1036 
1037         /* Get a copy of sid_prefix */
1038         sid_prefix = kidmap_find_sid_prefix(sid_prefix);
1039 
1040         if (get_handle->mapping_num >= get_handle->mapping_size)
1041                 kidmap_get_extend(get_handle);
1042 
1043         mapping = &get_handle->mapping[get_handle->mapping_num];
1044         mapping->flag = 0;
1045         mapping->id1.idtype = IDMAP_SID;
1046         mapping->id1.idmap_id_u.sid.prefix = (char *)sid_prefix;
1047         mapping->id1.idmap_id_u.sid.rid = rid;
1048         mapping->id2.idtype = IDMAP_POSIXID;
1049 
1050         result = &get_handle->result[get_handle->mapping_num];
1051         result->idtype = IDMAP_POSIXID;
1052         result->uid = NULL;
1053         result->gid = NULL;
1054         result->pid = pid;
1055         result->sid_prefix = NULL;
1056         result->rid = NULL;
1057         result->is_user = is_user;
1058         result->stat = stat;
1059 
1060         get_handle->mapping_num++;
1061 
1062         return (IDMAP_SUCCESS);
1063 }
1064 
1065 
1066 /*
1067  * Given UID, get SID and RID
1068  *
1069  * Input:
1070  * uid  - POSIX UID
1071  *
1072  * Output:
1073  * stat - status of the get request
1074  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
1075  * rid  - RID (if stat == IDMAP_SUCCESS)
1076  *
1077  * Note: The output parameters will be set by idmap_get_mappings()
1078  */
1079 idmap_stat
1080 kidmap_batch_getsidbyuid(idmap_get_handle_t *get_handle, uid_t uid,
1081     const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
1082 {
1083         idmap_mapping   *mapping;
1084         idmap_get_res   *result;
1085 
1086         if (get_handle == NULL || sid_prefix == NULL ||
1087             rid == NULL || stat == NULL)
1088                 return (IDMAP_ERR_ARG);
1089 
1090         if (kidmap_cache_lookup_sidbyuid(&get_handle->zs->cache,
1091             sid_prefix, rid, uid) == IDMAP_SUCCESS) {
1092                 *stat = IDMAP_SUCCESS;
1093                 return (IDMAP_SUCCESS);
1094         }
1095 
1096         if (get_handle->mapping_num >= get_handle->mapping_size)
1097                 kidmap_get_extend(get_handle);
1098 
1099         mapping = &get_handle->mapping[get_handle->mapping_num];
1100         mapping->flag = 0;
1101         mapping->id1.idtype = IDMAP_UID;
1102         mapping->id1.idmap_id_u.uid = uid;
1103         mapping->id2.idtype = IDMAP_SID;
1104 
1105         result = &get_handle->result[get_handle->mapping_num];
1106         result->idtype = IDMAP_SID;
1107         result->uid = NULL;
1108         result->gid = NULL;
1109         result->pid = NULL;
1110         result->sid_prefix = sid_prefix;
1111         result->rid = rid;
1112         result->is_user = NULL;
1113         result->stat = stat;
1114 
1115         get_handle->mapping_num++;
1116 
1117         return (IDMAP_SUCCESS);
1118 }
1119 
1120 
1121 /*
1122  * Given GID, get SID and RID
1123  *
1124  * Input:
1125  * gid  - POSIX GID
1126  *
1127  * Output:
1128  * stat - status of the get request
1129  * sid  - SID in canonical form (if stat == IDMAP_SUCCESS)
1130  * rid  - RID (if stat == IDMAP_SUCCESS)
1131  *
1132  * Note: The output parameters will be set by idmap_get_mappings()
1133  */
1134 idmap_stat
1135 kidmap_batch_getsidbygid(idmap_get_handle_t *get_handle, gid_t gid,
1136     const char **sid_prefix, uint32_t *rid, idmap_stat *stat)
1137 {
1138         idmap_mapping   *mapping;
1139         idmap_get_res   *result;
1140 
1141         if (get_handle == NULL || sid_prefix == NULL ||
1142             rid == NULL || stat == NULL)
1143                 return (IDMAP_ERR_ARG);
1144 
1145         if (kidmap_cache_lookup_sidbygid(&get_handle->zs->cache,
1146             sid_prefix, rid, gid) == IDMAP_SUCCESS) {
1147                 *stat = IDMAP_SUCCESS;
1148                 return (IDMAP_SUCCESS);
1149         }
1150 
1151         if (get_handle->mapping_num >= get_handle->mapping_size)
1152                 kidmap_get_extend(get_handle);
1153 
1154         mapping = &get_handle->mapping[get_handle->mapping_num];
1155         mapping->flag = 0;
1156         mapping->id1.idtype = IDMAP_GID;
1157         mapping->id1.idmap_id_u.gid = gid;
1158         mapping->id2.idtype = IDMAP_SID;
1159 
1160         result = &get_handle->result[get_handle->mapping_num];
1161         result->idtype = IDMAP_SID;
1162         result->uid = NULL;
1163         result->gid = NULL;
1164         result->pid = NULL;
1165         result->sid_prefix = sid_prefix;
1166         result->rid = rid;
1167         result->is_user = NULL;
1168         result->stat = stat;
1169 
1170         get_handle->mapping_num++;
1171 
1172         return (IDMAP_SUCCESS);
1173 }
1174 
1175 
1176 /*
1177  * Process the batched "get mapping" requests. The results (i.e.
1178  * status and identity) will be available in the data areas
1179  * provided by individual requests.
1180  *
1181  * If the door call fails the status IDMAP_ERR_NOMAPPING is
1182  * return and the UID or UID result is set to "nobody"
1183  */
1184 
1185 idmap_stat
1186 kidmap_get_mappings(idmap_get_handle_t *get_handle)
1187 {
1188         idmap_mapping_batch     rpc_args;
1189         idmap_ids_res           rpc_res;
1190         uint32_t                op = IDMAP_GET_MAPPED_IDS;
1191         idmap_mapping           *request;
1192         idmap_get_res           *result;
1193         idmap_id                *id;
1194         int                     status;
1195         int                     i;
1196         const char              *sid_prefix;
1197         int                     is_user;
1198         idmap_cache_t           *cache;
1199         int                     direction;
1200 
1201         if (get_handle == NULL)
1202                 return (IDMAP_ERR_ARG);
1203 
1204         if (get_handle->mapping_num == 0)
1205                 return (IDMAP_SUCCESS);
1206         cache = &get_handle->zs->cache;
1207 
1208         bzero(&rpc_res, sizeof (idmap_ids_res));
1209 
1210         rpc_args.idmap_mapping_batch_len = get_handle->mapping_num;
1211         rpc_args.idmap_mapping_batch_val = get_handle->mapping;
1212 
1213         if (kidmap_rpc_call(get_handle->zs, op, xdr_idmap_mapping_batch,
1214             (caddr_t)&rpc_args, xdr_idmap_ids_res,
1215             (caddr_t)&rpc_res) != 0) {
1216                 /* Door call failed */
1217                 status = IDMAP_ERR_NOMAPPING;
1218                 goto error;
1219         }
1220 
1221         status = rpc_res.retcode;
1222         if (status != IDMAP_SUCCESS) {
1223                 /* RPC returned idmap error code */
1224                 xdr_free(xdr_idmap_ids_res, (char *)&rpc_res);
1225                 goto error;
1226         }
1227 
1228         for (i = 0; i < get_handle->mapping_num; i++) {
1229                 request = &get_handle->mapping[i];
1230                 result =  &get_handle->result[i];
1231 
1232                 if (i >= rpc_res.ids.ids_len) {
1233                         *result->stat =      IDMAP_ERR_NOMAPPING;
1234                         if (result->uid)
1235                                 *result->uid = UID_NOBODY;
1236                         if (result->gid)
1237                                 *result->gid = GID_NOBODY;
1238                         if (result->pid)
1239                                 *result->pid = UID_NOBODY;
1240                         if (result->is_user)
1241                                 *result->is_user = 1;
1242                         if (result->sid_prefix)
1243                                 *result->sid_prefix = NULL;
1244                         if (result->rid)
1245                                 *result->rid = 0;
1246                         continue;
1247                 }
1248 
1249                 *result->stat = rpc_res.ids.ids_val[i].retcode;
1250 
1251                 id = &rpc_res.ids.ids_val[i].id;
1252                 direction = rpc_res.ids.ids_val[i].direction;
1253 
1254                 switch (id->idtype) {
1255                 case IDMAP_UID:
1256                         if (result->uid)
1257                                 *result->uid = id->idmap_id_u.uid;
1258                         if (result->pid)
1259                                 *result->pid = id->idmap_id_u.uid;
1260                         if (result->is_user)
1261                                 *result->is_user = 1;
1262                         sid_prefix = kidmap_find_sid_prefix(
1263                             request->id1.idmap_id_u.sid.prefix);
1264                         if (*result->stat == IDMAP_SUCCESS && result->uid)
1265                                 kidmap_cache_add_sid2uid(
1266                                     cache, sid_prefix,
1267                                     request->id1.idmap_id_u.sid.rid,
1268                                     id->idmap_id_u.uid,
1269                                     direction);
1270                         else if (*result->stat == IDMAP_SUCCESS && result->pid)
1271                                 kidmap_cache_add_sid2pid(
1272                                     cache, sid_prefix,
1273                                     request->id1.idmap_id_u.sid.rid,
1274                                     id->idmap_id_u.uid, 1,
1275                                     direction);
1276                         break;
1277 
1278                 case IDMAP_GID:
1279                         if (result->gid)
1280                                 *result->gid = id->idmap_id_u.gid;
1281                         if (result->pid)
1282                                 *result->pid = id->idmap_id_u.gid;
1283                         if (result->is_user)
1284                                 *result->is_user = 0;
1285                         sid_prefix = kidmap_find_sid_prefix(
1286                             request->id1.idmap_id_u.sid.prefix);
1287                         if (*result->stat == IDMAP_SUCCESS && result->gid)
1288                                 kidmap_cache_add_sid2gid(
1289                                     cache, sid_prefix,
1290                                     request->id1.idmap_id_u.sid.rid,
1291                                     id->idmap_id_u.gid,
1292                                     direction);
1293                         else if (*result->stat == IDMAP_SUCCESS && result->pid)
1294                                 kidmap_cache_add_sid2pid(
1295                                     cache, sid_prefix,
1296                                     request->id1.idmap_id_u.sid.rid,
1297                                     id->idmap_id_u.gid, 0,
1298                                     direction);
1299                         break;
1300 
1301                 case IDMAP_SID:
1302                 case IDMAP_USID:
1303                 case IDMAP_GSID:
1304                         sid_prefix = kidmap_find_sid_prefix(
1305                             id->idmap_id_u.sid.prefix);
1306                         if (result->sid_prefix && result->rid) {
1307                                 *result->sid_prefix = sid_prefix;
1308                                 *result->rid = id->idmap_id_u.sid.rid;
1309                         }
1310                         if (*result->stat == IDMAP_SUCCESS &&
1311                             request->id1.idtype == IDMAP_UID)
1312                                 kidmap_cache_add_sid2uid(
1313                                     cache, sid_prefix,
1314                                     id->idmap_id_u.sid.rid,
1315                                     request->id1.idmap_id_u.uid,
1316                                     direction);
1317                         else if (*result->stat == IDMAP_SUCCESS &&
1318                             request->id1.idtype == IDMAP_GID)
1319                                 kidmap_cache_add_sid2gid(
1320                                     cache, sid_prefix,
1321                                     id->idmap_id_u.sid.rid,
1322                                     request->id1.idmap_id_u.gid,
1323                                     direction);
1324                         break;
1325 
1326                 default:
1327                         *result->stat = IDMAP_ERR_NORESULT;
1328                         if (result->uid)
1329                                 *result->uid = UID_NOBODY;
1330                         if (result->gid)
1331                                 *result->gid = GID_NOBODY;
1332                         if (result->pid)
1333                                 *result->pid = UID_NOBODY;
1334                         if (result->is_user)
1335                                 *result->is_user = 1;
1336                         if (result->sid_prefix)
1337                                 *result->sid_prefix = NULL;
1338                         if (result->rid)
1339                                 *result->rid = 0;
1340                         break;
1341                 }
1342         }
1343         xdr_free(xdr_idmap_ids_res, (char *)&rpc_res);
1344 
1345         /* Reset get_handle for new resquests */
1346         get_handle->mapping_num = 0;
1347         return (status);
1348 
1349 error:
1350         for (i = 0; i < get_handle->mapping_num; i++) {
1351                 result =  &get_handle->result[i];
1352 
1353                 *result->stat = status;
1354                 if (result->uid)
1355                         *result->uid = UID_NOBODY;
1356                 if (result->gid)
1357                         *result->gid = GID_NOBODY;
1358                 if (result->pid)
1359                         *result->pid = UID_NOBODY;
1360                 if (result->is_user)
1361                         *result->is_user = 1;
1362                 if (result->sid_prefix)
1363                         *result->sid_prefix = NULL;
1364                 if (result->rid)
1365                         *result->rid = 0;
1366         }
1367 
1368         /* Reset get_handle for new resquests */
1369         get_handle->mapping_num = 0;
1370         return (status);
1371 }
1372 
1373 
1374 /*
1375  * Destroy the "get mapping" handle
1376  */
1377 void
1378 kidmap_get_destroy(idmap_get_handle_t *get_handle)
1379 {
1380         if (get_handle == NULL)
1381                 return;
1382 
1383         kmem_free(get_handle->mapping,
1384             (sizeof (idmap_mapping)) * get_handle->mapping_size);
1385         get_handle->mapping = NULL;
1386 
1387         kmem_free(get_handle->result,
1388             (sizeof (idmap_get_res)) * get_handle->mapping_size);
1389         get_handle->result = NULL;
1390 
1391         kmem_free(get_handle, sizeof (idmap_get_handle_t));
1392 }
1393 
1394 
1395 static int
1396 kidmap_rpc_call(idmap_zone_specific_t *zs, uint32_t op, xdrproc_t xdr_args,
1397     caddr_t args, xdrproc_t xdr_res, caddr_t res)
1398 {
1399         XDR             xdr_ctx;
1400         struct  rpc_msg reply_msg;
1401         char            *inbuf_ptr = NULL;
1402         size_t          inbuf_size = 4096;
1403         char            *outbuf_ptr = NULL;
1404         size_t          outbuf_size = 4096;
1405         size_t          size;
1406         int             status = 0;
1407         door_arg_t      params;
1408         int             retry = 0;
1409         struct rpc_msg  call_msg;
1410 
1411         params.rbuf = NULL;
1412         params.rsize = 0;
1413 
1414 retry:
1415         inbuf_ptr = kmem_alloc(inbuf_size, KM_SLEEP);
1416         outbuf_ptr = kmem_alloc(outbuf_size, KM_SLEEP);
1417 
1418         xdrmem_create(&xdr_ctx, inbuf_ptr, inbuf_size, XDR_ENCODE);
1419 
1420         call_msg.rm_call.cb_prog = IDMAP_PROG;
1421         call_msg.rm_call.cb_vers = IDMAP_V1;
1422         call_msg.rm_xid = atomic_inc_32_nv(&zs->message_id);
1423 
1424         if (!xdr_callhdr(&xdr_ctx, &call_msg)) {
1425 #ifdef  DEBUG
1426                 zcmn_err(zs->zone_id, CE_WARN,
1427                     "idmap: xdr encoding header error");
1428 #endif  /* DEBUG */
1429                 status = -1;
1430                 goto exit;
1431         }
1432 
1433         if (!xdr_uint32(&xdr_ctx, &op) ||
1434             /* Auth none */
1435             !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1436             !xdr_opaque_auth(&xdr_ctx, &_null_auth) ||
1437             /* RPC args */
1438             !xdr_args(&xdr_ctx, args)) {
1439 #ifdef  DEBUG
1440                 zcmn_err(zs->zone_id, CE_WARN, "idmap: xdr encoding error");
1441 #endif  /* DEBUG */
1442                 if (retry > 2) {
1443                         status = -1;
1444                         goto exit;
1445                 }
1446                 retry++;
1447                 if (inbuf_ptr) {
1448                         kmem_free(inbuf_ptr, inbuf_size);
1449                         inbuf_ptr = NULL;
1450                 }
1451                 if (outbuf_ptr) {
1452                         kmem_free(outbuf_ptr, outbuf_size);
1453                         outbuf_ptr = NULL;
1454                 }
1455                 if ((size = xdr_sizeof(xdr_args, args)) == 0) {
1456 #ifdef  DEBUG
1457                         zcmn_err(zs->zone_id, CE_WARN,
1458                             "idmap: xdr_sizeof error");
1459 #endif  /* DEBUG */
1460                         status = -1;
1461                         goto exit;
1462                 }
1463                 inbuf_size = size + 1024;
1464                 outbuf_size = size + 1024;
1465                 goto retry;
1466         }
1467 
1468         params.data_ptr = inbuf_ptr;
1469         params.data_size = XDR_GETPOS(&xdr_ctx);
1470         params.desc_ptr = NULL;
1471         params.desc_num = 0;
1472         params.rbuf = outbuf_ptr;
1473         params.rsize = outbuf_size;
1474 
1475         if (kidmap_call_door(zs, ¶ms) != 0) {
1476                 status = -1;
1477                 goto exit;
1478         }
1479 
1480         reply_msg.acpted_rply.ar_verf = _null_auth;
1481         reply_msg.acpted_rply.ar_results.where = res;
1482         reply_msg.acpted_rply.ar_results.proc = xdr_res;
1483         xdrmem_create(&xdr_ctx, params.data_ptr, params.data_size, XDR_DECODE);
1484         if (xdr_replymsg(&xdr_ctx, &reply_msg)) {
1485                 if (reply_msg.rm_reply.rp_stat != MSG_ACCEPTED ||
1486                     reply_msg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
1487                         status = -1;
1488                         goto exit;
1489                 }
1490         } else {
1491 #ifdef  DEBUG
1492                 zcmn_err(zs->zone_id, CE_WARN,
1493                     "idmap: xdr decoding reply message error");
1494 #endif  /* DEBUG */
1495                 status = -1;
1496         }
1497 
1498 exit:
1499         if (outbuf_ptr != params.rbuf && params.rbuf != NULL)
1500                 kmem_free(params.rbuf, params.rsize);
1501         if (inbuf_ptr)
1502                 kmem_free(inbuf_ptr, inbuf_size);
1503         if (outbuf_ptr)
1504                 kmem_free(outbuf_ptr, outbuf_size);
1505         return (status);
1506 }