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