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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright Milan Jurik 2012. All rights reserved.
  24  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  25  * Copyright 2015 Joyent, Inc.
  26  */
  27 
  28 
  29 /*
  30  * libidmap API
  31  */
  32 
  33 #include <stdlib.h>
  34 #include <sys/varargs.h>
  35 #include <inttypes.h>
  36 #include <errno.h>
  37 #include <strings.h>
  38 #include <ctype.h>
  39 #include <sys/param.h>
  40 #include <sys/types.h>
  41 #include <sys/stat.h>
  42 #include <dlfcn.h>
  43 #include <libintl.h>
  44 #include <syslog.h>
  45 #include <assert.h>
  46 #include "idmap_impl.h"
  47 #include "idmap_cache.h"
  48 
  49 static struct timeval TIMEOUT = { 25, 0 };
  50 
  51 static int idmap_stat2errno(idmap_stat);
  52 static idmap_stat       idmap_strdupnull(char **, const char *);
  53 
  54 #define __ITER_CREATE(itera, argu, ityp)\
  55         itera = calloc(1, sizeof (*itera));\
  56         if (itera == NULL) {\
  57                 errno = ENOMEM;\
  58                 return (IDMAP_ERR_MEMORY);\
  59         }\
  60         argu = calloc(1, sizeof (*argu));\
  61         if (argu == NULL) {\
  62                 free(itera);\
  63                 errno = ENOMEM;\
  64                 return (IDMAP_ERR_MEMORY);\
  65         }\
  66         itera->type = ityp;\
  67         itera->retcode = IDMAP_NEXT;\
  68         itera->limit = 1024;\
  69         itera->arg = argu;
  70 
  71 #define __ITER_CHECK(itera, ityp)\
  72         if (itera == NULL) {\
  73                 errno = EINVAL;\
  74                 return (IDMAP_ERR_ARG);\
  75         }\
  76         if (itera->type != ityp) {\
  77                 errno = EINVAL;\
  78                 return (IDMAP_ERR_ARG);\
  79         }
  80 
  81 /*
  82  * Free memory allocated by libidmap API
  83  *
  84  * Input:
  85  * ptr - memory to be freed
  86  */
  87 void
  88 idmap_free(void *ptr)
  89 {
  90         free(ptr);
  91 }
  92 
  93 
  94 static idmap_stat
  95 idmap_get_prop(idmap_prop_type pr, idmap_prop_res *res)
  96 {
  97         idmap_stat retcode;
  98 
  99         (void) memset(res, 0, sizeof (*res));
 100 
 101         retcode = _idmap_clnt_call(IDMAP_GET_PROP,
 102             (xdrproc_t)xdr_idmap_prop_type, (caddr_t)&pr,
 103             (xdrproc_t)xdr_idmap_prop_res, (caddr_t)res, TIMEOUT);
 104         if (retcode != IDMAP_SUCCESS)
 105                 return (retcode);
 106 
 107         return (res->retcode); /* This might not be IDMAP_SUCCESS! */
 108 }
 109 
 110 
 111 idmap_stat
 112 idmap_get_prop_ds(idmap_prop_type pr, idmap_ad_disc_ds_t *dc)
 113 {
 114         idmap_prop_res res;
 115         idmap_stat rc = IDMAP_SUCCESS;
 116 
 117         rc = idmap_get_prop(pr, &res);
 118         if (rc < 0)
 119                 return (rc);
 120 
 121         dc->port = res.value.idmap_prop_val_u.dsval.port;
 122         (void) strlcpy(dc->host, res.value.idmap_prop_val_u.dsval.host,
 123             AD_DISC_MAXHOSTNAME);
 124 
 125         /* xdr doesn't guarantee 0-termination of char[]: */
 126         dc->host[AD_DISC_MAXHOSTNAME - 1] = '\0';
 127 
 128         return (rc);
 129 }
 130 
 131 
 132 /*
 133  * Sometimes the property is not set. In that case, str is set to NULL but
 134  * otherwise IDMAP_SUCCESS is returned.
 135  */
 136 idmap_stat
 137 idmap_get_prop_str(idmap_prop_type pr, char **str)
 138 {
 139         idmap_prop_res res;
 140         idmap_stat rc = IDMAP_SUCCESS;
 141 
 142         rc = idmap_get_prop(pr, &res);
 143         if (rc < 0)
 144                 return (rc);
 145 
 146         rc = idmap_strdupnull(str, res.value.idmap_prop_val_u.utf8val);
 147         return (rc);
 148 }
 149 
 150 /*
 151  * Create/Initialize handle for updates
 152  *
 153  * Output:
 154  * udthandle - update handle
 155  */
 156 idmap_stat
 157 idmap_udt_create(idmap_udt_handle_t **udthandle)
 158 {
 159         idmap_udt_handle_t      *tmp;
 160 
 161         if (udthandle == NULL) {
 162                 errno = EINVAL;
 163                 return (IDMAP_ERR_ARG);
 164         }
 165         if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
 166                 errno = ENOMEM;
 167                 return (IDMAP_ERR_MEMORY);
 168         }
 169 
 170         *udthandle = tmp;
 171         return (IDMAP_SUCCESS);
 172 }
 173 
 174 
 175 /*
 176  * All the updates specified by the update handle are committed
 177  * in a single transaction. i.e either all succeed or none.
 178  *
 179  * Input:
 180  * udthandle - update handle with the update requests
 181  *
 182  * Return value:
 183  * Status of the commit
 184  */
 185 idmap_stat
 186 idmap_udt_commit(idmap_udt_handle_t *udthandle)
 187 {
 188         idmap_update_res        res;
 189         idmap_stat              retcode;
 190 
 191         if (udthandle == NULL) {
 192                 errno = EINVAL;
 193                 return (IDMAP_ERR_ARG);
 194         }
 195 
 196         (void) memset(&res, 0, sizeof (res));
 197 
 198         retcode = _idmap_clnt_call(IDMAP_UPDATE,
 199             (xdrproc_t)xdr_idmap_update_batch, (caddr_t)&udthandle->batch,
 200             (xdrproc_t)xdr_idmap_update_res, (caddr_t)&res,
 201             TIMEOUT);
 202         if (retcode != IDMAP_SUCCESS)
 203                 goto out;
 204 
 205         retcode = udthandle->commit_stat = res.retcode;
 206         udthandle->error_index = res.error_index;
 207 
 208         if (retcode != IDMAP_SUCCESS) {
 209 
 210                 if (udthandle->error_index < 0)
 211                         goto out;
 212 
 213                 retcode = idmap_namerule_cpy(&udthandle->error_rule,
 214                     &res.error_rule);
 215                 if (retcode != IDMAP_SUCCESS) {
 216                         udthandle->error_index = -2;
 217                         goto out;
 218                 }
 219 
 220                 retcode = idmap_namerule_cpy(&udthandle->conflict_rule,
 221                     &res.conflict_rule);
 222                 if (retcode != IDMAP_SUCCESS) {
 223                         udthandle->error_index = -2;
 224                         goto out;
 225                 }
 226         }
 227 
 228         retcode = res.retcode;
 229 
 230 
 231 out:
 232         /* reset handle so that it can be used again */
 233         if (retcode == IDMAP_SUCCESS) {
 234                 _IDMAP_RESET_UDT_HANDLE(udthandle);
 235         }
 236 
 237         xdr_free(xdr_idmap_update_res, (caddr_t)&res);
 238         errno = idmap_stat2errno(retcode);
 239         return (retcode);
 240 }
 241 
 242 
 243 static void
 244 idmap_namerule_parts_clear(char **windomain, char **winname,
 245     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
 246     boolean_t *is_nt4, int *direction)
 247 {
 248         if (windomain)
 249                 *windomain = NULL;
 250         if (winname)
 251                 *winname = NULL;
 252         if (unixname)
 253                 *unixname = NULL;
 254 
 255         if (is_nt4)
 256                 *is_nt4 = 0;
 257         if (is_user)
 258                 *is_user = -1;
 259         if (is_wuser)
 260                 *is_wuser = -1;
 261         if (direction)
 262                 *direction = IDMAP_DIRECTION_UNDEF;
 263 }
 264 
 265 static idmap_stat
 266 idmap_namerule2parts(idmap_namerule *rule,
 267     char **windomain, char **winname,
 268     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
 269     boolean_t *is_nt4, int *direction)
 270 {
 271         idmap_stat retcode;
 272 
 273         if (EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
 274                 return (IDMAP_ERR_NORESULT);
 275 
 276 
 277         retcode = idmap_strdupnull(windomain, rule->windomain);
 278         if (retcode != IDMAP_SUCCESS)
 279                 goto errout;
 280 
 281         retcode = idmap_strdupnull(winname, rule->winname);
 282         if (retcode != IDMAP_SUCCESS)
 283                 goto errout;
 284 
 285         retcode = idmap_strdupnull(unixname, rule->unixname);
 286         if (retcode != IDMAP_SUCCESS)
 287                 goto errout;
 288 
 289 
 290         if (is_user)
 291                 *is_user = rule->is_user;
 292         if (is_wuser)
 293                 *is_wuser = rule->is_wuser;
 294         if (is_nt4)
 295                 *is_nt4 = rule->is_nt4;
 296         if (direction)
 297                 *direction = rule->direction;
 298 
 299 
 300         return (IDMAP_SUCCESS);
 301 
 302 errout:
 303         if (windomain && *windomain)
 304                 free(*windomain);
 305         if (winname && *winname)
 306                 free(*winname);
 307         if (unixname && *unixname)
 308                 free(*unixname);
 309 
 310         idmap_namerule_parts_clear(windomain, winname,
 311             unixname, is_user, is_wuser, is_nt4, direction);
 312 
 313         return (retcode);
 314 
 315 }
 316 
 317 /*
 318  * Retrieve the index of the failed batch element. error_index == -1
 319  * indicates failure at the beginning, -2 at the end.
 320  *
 321  * If idmap_udt_commit didn't return error, the returned value is undefined.
 322  *
 323  * Return value:
 324  * IDMAP_SUCCESS
 325  */
 326 
 327 idmap_stat
 328 idmap_udt_get_error_index(idmap_udt_handle_t *udthandle,
 329     int64_t *error_index)
 330 {
 331         if (error_index)
 332                 *error_index = udthandle->error_index;
 333 
 334         return (IDMAP_SUCCESS);
 335 }
 336 
 337 
 338 /*
 339  * Retrieve the rule which caused the batch to fail. If
 340  * idmap_udt_commit didn't return error or if error_index is < 0, the
 341  * retrieved rule is undefined.
 342  *
 343  * Return value:
 344  * IDMAP_ERR_NORESULT if there is no error rule.
 345  * IDMAP_SUCCESS if the rule was obtained OK.
 346  * other error code (IDMAP_ERR_NOMEMORY etc)
 347  */
 348 
 349 idmap_stat
 350 idmap_udt_get_error_rule(idmap_udt_handle_t *udthandle,
 351     char **windomain, char **winname,
 352     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
 353     boolean_t *is_nt4, int *direction)
 354 {
 355         idmap_namerule_parts_clear(windomain, winname,
 356             unixname, is_user, is_wuser, is_nt4, direction);
 357 
 358         if (udthandle->commit_stat == IDMAP_SUCCESS ||
 359             udthandle->error_index < 0)
 360                 return (IDMAP_ERR_NORESULT);
 361 
 362         return (idmap_namerule2parts(
 363             &udthandle->error_rule,
 364             windomain,
 365             winname,
 366             unixname,
 367             is_user,
 368             is_wuser,
 369             is_nt4,
 370             direction));
 371 }
 372 
 373 /*
 374  * Retrieve the rule with which there was a conflict. TODO: retrieve
 375  * the value.
 376  *
 377  * Return value:
 378  * IDMAP_ERR_NORESULT if there is no error rule.
 379  * IDMAP_SUCCESS if the rule was obtained OK.
 380  * other error code (IDMAP_ERR_NOMEMORY etc)
 381  */
 382 
 383 idmap_stat
 384 idmap_udt_get_conflict_rule(idmap_udt_handle_t *udthandle,
 385     char **windomain, char **winname,
 386     char **unixname, boolean_t *is_user, boolean_t *is_wuser,
 387     boolean_t *is_nt4, int *direction)
 388 {
 389         idmap_namerule_parts_clear(windomain, winname,
 390             unixname, is_user, is_wuser, is_nt4, direction);
 391 
 392         if (udthandle->commit_stat != IDMAP_ERR_W2U_NAMERULE_CONFLICT &&
 393             udthandle->commit_stat != IDMAP_ERR_U2W_NAMERULE_CONFLICT) {
 394                 return (IDMAP_ERR_NORESULT);
 395         }
 396 
 397         return (idmap_namerule2parts(
 398             &udthandle->conflict_rule,
 399             windomain,
 400             winname,
 401             unixname,
 402             is_user,
 403             is_wuser,
 404             is_nt4,
 405             direction));
 406 }
 407 
 408 
 409 /*
 410  * Destroy the update handle
 411  */
 412 void
 413 idmap_udt_destroy(idmap_udt_handle_t *udthandle)
 414 {
 415         if (udthandle == NULL)
 416                 return;
 417         xdr_free(xdr_idmap_update_batch, (caddr_t)&udthandle->batch);
 418         xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->error_rule);
 419         xdr_free(xdr_idmap_namerule, (caddr_t)&udthandle->conflict_rule);
 420         free(udthandle);
 421 }
 422 
 423 
 424 idmap_stat
 425 idmap_udt_add_namerule(idmap_udt_handle_t *udthandle, const char *windomain,
 426     boolean_t is_user, boolean_t is_wuser, const char *winname,
 427     const char *unixname, boolean_t is_nt4, int direction)
 428 {
 429         idmap_retcode   retcode;
 430         idmap_namerule  *rule = NULL;
 431 
 432         retcode = _udt_extend_batch(udthandle);
 433         if (retcode != IDMAP_SUCCESS)
 434                 goto errout;
 435 
 436         rule = &udthandle->batch.
 437             idmap_update_batch_val[udthandle->next].
 438             idmap_update_op_u.rule;
 439         rule->is_user = is_user;
 440         rule->is_wuser = is_wuser;
 441         rule->direction = direction;
 442         rule->is_nt4 = is_nt4;
 443 
 444         retcode = idmap_strdupnull(&rule->windomain, windomain);
 445         if (retcode != IDMAP_SUCCESS)
 446                 goto errout;
 447 
 448         retcode = idmap_strdupnull(&rule->winname, winname);
 449         if (retcode != IDMAP_SUCCESS)
 450                 goto errout;
 451 
 452         retcode = idmap_strdupnull(&rule->unixname, unixname);
 453         if (retcode != IDMAP_SUCCESS)
 454                 goto errout;
 455 
 456         udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
 457             OP_ADD_NAMERULE;
 458         udthandle->next++;
 459         return (IDMAP_SUCCESS);
 460 
 461 errout:
 462         /* The batch should still be usable */
 463         if (rule)
 464                 xdr_free(xdr_idmap_namerule, (caddr_t)rule);
 465         errno = idmap_stat2errno(retcode);
 466         return (retcode);
 467 }
 468 
 469 
 470 /* ARGSUSED */
 471 idmap_stat
 472 idmap_udt_rm_namerule(idmap_udt_handle_t *udthandle, boolean_t is_user,
 473     boolean_t is_wuser, const char *windomain, const char *winname,
 474     const char *unixname, int direction)
 475 {
 476         idmap_retcode   retcode;
 477         idmap_namerule  *rule = NULL;
 478 
 479         retcode = _udt_extend_batch(udthandle);
 480         if (retcode != IDMAP_SUCCESS)
 481                 goto errout;
 482 
 483         rule = &udthandle->batch.
 484             idmap_update_batch_val[udthandle->next].
 485             idmap_update_op_u.rule;
 486         rule->is_user = is_user;
 487         rule->is_wuser = is_wuser;
 488         rule->direction = direction;
 489 
 490         retcode = idmap_strdupnull(&rule->windomain, windomain);
 491         if (retcode != IDMAP_SUCCESS)
 492                 goto errout;
 493 
 494         retcode = idmap_strdupnull(&rule->winname, winname);
 495         if (retcode != IDMAP_SUCCESS)
 496                 goto errout;
 497 
 498         retcode = idmap_strdupnull(&rule->unixname, unixname);
 499         if (retcode != IDMAP_SUCCESS)
 500                 goto errout;
 501 
 502         udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
 503             OP_RM_NAMERULE;
 504         udthandle->next++;
 505         return (IDMAP_SUCCESS);
 506 
 507 errout:
 508         if (rule)
 509                 xdr_free(xdr_idmap_namerule, (caddr_t)rule);
 510         errno = idmap_stat2errno(retcode);
 511         return (retcode);
 512 }
 513 
 514 
 515 /* ARGSUSED */
 516 idmap_stat
 517 idmap_udt_flush_namerules(idmap_udt_handle_t *udthandle)
 518 {
 519         idmap_retcode   retcode;
 520 
 521         retcode = _udt_extend_batch(udthandle);
 522         if (retcode != IDMAP_SUCCESS)
 523                 goto errout;
 524 
 525         udthandle->batch.idmap_update_batch_val[udthandle->next].opnum =
 526             OP_FLUSH_NAMERULES;
 527         udthandle->next++;
 528         return (IDMAP_SUCCESS);
 529 
 530 errout:
 531         errno = idmap_stat2errno(retcode);
 532         return (retcode);
 533 }
 534 
 535 
 536 /*
 537  * Set the number of entries requested per batch by the iterator
 538  *
 539  * Input:
 540  * iter  - iterator
 541  * limit - number of entries requested per batch
 542  */
 543 idmap_stat
 544 idmap_iter_set_limit(idmap_iter_t *iter, uint64_t limit)
 545 {
 546         if (iter == NULL) {
 547                 errno = EINVAL;
 548                 return (IDMAP_ERR_ARG);
 549         }
 550         iter->limit = limit;
 551         return (IDMAP_SUCCESS);
 552 }
 553 
 554 
 555 /*
 556  * Create iterator to get name-based mapping rules
 557  *
 558  * Input:
 559  * windomain - Windows domain
 560  * is_user   - user or group rules
 561  * winname   - Windows user or group name
 562  * unixname  - Unix user or group name
 563  *
 564  * Output:
 565  * iter - iterator
 566  */
 567 idmap_stat
 568 idmap_iter_namerules(const char *windomain, boolean_t is_user,
 569     boolean_t is_wuser, const char *winname, const char *unixname,
 570     idmap_iter_t **iter)
 571 {
 572 
 573         idmap_iter_t                    *tmpiter;
 574         idmap_list_namerules_1_argument *arg = NULL;
 575         idmap_namerule                  *rule;
 576         idmap_retcode                   retcode;
 577 
 578         __ITER_CREATE(tmpiter, arg, IDMAP_LIST_NAMERULES);
 579 
 580         rule = &arg->rule;
 581         rule->is_user = is_user;
 582         rule->is_wuser = is_wuser;
 583         rule->direction = IDMAP_DIRECTION_UNDEF;
 584 
 585         retcode = idmap_strdupnull(&rule->windomain, windomain);
 586         if (retcode != IDMAP_SUCCESS)
 587                 goto errout;
 588 
 589         retcode = idmap_strdupnull(&rule->winname, winname);
 590         if (retcode != IDMAP_SUCCESS)
 591                 goto errout;
 592 
 593         retcode = idmap_strdupnull(&rule->unixname, unixname);
 594         if (retcode != IDMAP_SUCCESS)
 595                 goto errout;
 596 
 597         *iter = tmpiter;
 598         return (IDMAP_SUCCESS);
 599 
 600 errout:
 601         if (arg) {
 602                 xdr_free(xdr_idmap_list_namerules_1_argument, (char *)arg);
 603                 free(arg);
 604         }
 605         if (tmpiter)
 606                 free(tmpiter);
 607 
 608         return (retcode);
 609 }
 610 
 611 
 612 /*
 613  * Iterate through the name-based mapping rules
 614  *
 615  * Input:
 616  * iter - iterator
 617  *
 618  * Output:
 619  * windomain - Windows domain
 620  * winname   - Windows user or group name
 621  * unixname  - Unix user or group name
 622  * is_nt4    - NT4 or AD
 623  * direction - bi(0), win2unix(1), unix2win(2)
 624  *
 625  * Return value:
 626  * 0   - done
 627  * 1   - more results available
 628  * < 0 - error
 629  */
 630 idmap_stat
 631 idmap_iter_next_namerule(idmap_iter_t *iter, char **windomain,
 632     char **winname, char **unixname,  boolean_t *is_user,
 633     boolean_t *is_wuser, boolean_t *is_nt4, int *direction)
 634 {
 635         idmap_namerules_res             *namerules;
 636         idmap_list_namerules_1_argument *arg;
 637         idmap_retcode                   retcode;
 638 
 639         idmap_namerule_parts_clear(windomain, winname,
 640             unixname, is_user, is_wuser, is_nt4, direction);
 641 
 642 
 643         __ITER_CHECK(iter, IDMAP_LIST_NAMERULES);
 644 
 645         namerules = (idmap_namerules_res *)iter->retlist;
 646         if (iter->retcode == IDMAP_NEXT && (namerules == NULL ||
 647             iter->next >= namerules->rules.rules_len)) {
 648 
 649                 if ((arg = iter->arg) == NULL) {
 650                         errno = EINVAL;
 651                         return (IDMAP_ERR_ARG);
 652                 }
 653                 arg->limit = iter->limit;
 654 
 655                 retcode = _iter_get_next_list(IDMAP_LIST_NAMERULES,
 656                     iter, arg,
 657                     (uchar_t **)&namerules, sizeof (*namerules),
 658                     (xdrproc_t)xdr_idmap_list_namerules_1_argument,
 659                     (xdrproc_t)xdr_idmap_namerules_res);
 660                 if (retcode != IDMAP_SUCCESS)
 661                         return (retcode);
 662 
 663                 if (IDMAP_ERROR(namerules->retcode)) {
 664                         retcode  = namerules->retcode;
 665                         xdr_free(xdr_idmap_namerules_res, (caddr_t)namerules);
 666                         free(namerules);
 667                         iter->retlist = NULL;
 668                         return (retcode);
 669                 }
 670                 iter->retcode = namerules->retcode;
 671                 arg->lastrowid = namerules->lastrowid;
 672         }
 673 
 674         if (namerules == NULL || namerules->rules.rules_len == 0)
 675                 return (IDMAP_SUCCESS);
 676 
 677         if (iter->next >= namerules->rules.rules_len) {
 678                 return (IDMAP_ERR_ARG);
 679         }
 680 
 681         retcode = idmap_strdupnull(windomain,
 682             namerules->rules.rules_val[iter->next].windomain);
 683         if (retcode != IDMAP_SUCCESS)
 684                 goto errout;
 685 
 686         retcode = idmap_strdupnull(winname,
 687             namerules->rules.rules_val[iter->next].winname);
 688         if (retcode != IDMAP_SUCCESS)
 689                 goto errout;
 690 
 691         retcode = idmap_strdupnull(unixname,
 692             namerules->rules.rules_val[iter->next].unixname);
 693         if (retcode != IDMAP_SUCCESS)
 694                 goto errout;
 695 
 696         if (is_nt4)
 697                 *is_nt4 = namerules->rules.rules_val[iter->next].is_nt4;
 698         if (is_user)
 699                 *is_user = namerules->rules.rules_val[iter->next].is_user;
 700         if (is_wuser)
 701                 *is_wuser = namerules->rules.rules_val[iter->next].is_wuser;
 702         if (direction)
 703                 *direction = namerules->rules.rules_val[iter->next].direction;
 704         iter->next++;
 705 
 706         if (iter->next == namerules->rules.rules_len)
 707                 return (iter->retcode);
 708         else
 709                 return (IDMAP_NEXT);
 710 
 711 errout:
 712         if (windomain && *windomain)
 713                 free(*windomain);
 714         if (winname && *winname)
 715                 free(*winname);
 716         if (unixname && *unixname)
 717                 free(*unixname);
 718         return (retcode);
 719 }
 720 
 721 
 722 /*
 723  * Create iterator to get SID to UID/GID mappings
 724  *
 725  * Output:
 726  * iter - iterator
 727  */
 728 idmap_stat
 729 idmap_iter_mappings(idmap_iter_t **iter, int flag)
 730 {
 731         idmap_iter_t                    *tmpiter;
 732         idmap_list_mappings_1_argument  *arg = NULL;
 733 
 734         __ITER_CREATE(tmpiter, arg, IDMAP_LIST_MAPPINGS);
 735 
 736         arg->flag = flag;
 737         *iter = tmpiter;
 738         return (IDMAP_SUCCESS);
 739 }
 740 
 741 
 742 /*
 743  * Iterate through the SID to UID/GID mappings
 744  *
 745  * Input:
 746  * iter - iterator
 747  *
 748  * Output:
 749  * sid - SID in canonical form
 750  * pid - UID or GID
 751  *
 752  * Return value:
 753  * 0   - done
 754  * 1   - more results available
 755  * < 0 - error
 756  */
 757 idmap_stat
 758 idmap_iter_next_mapping(idmap_iter_t *iter, char **sidprefix,
 759     idmap_rid_t *rid, uid_t *pid, char **winname,
 760     char **windomain, char **unixname, boolean_t *is_user,
 761     boolean_t *is_wuser, int *direction, idmap_info *info)
 762 {
 763         idmap_mappings_res              *mappings;
 764         idmap_list_mappings_1_argument  *arg;
 765         idmap_retcode                   retcode;
 766         char                            *str;
 767 
 768         if (sidprefix)
 769                 *sidprefix = NULL;
 770         if (rid)
 771                 *rid = UINT32_MAX;
 772         if (winname)
 773                 *winname = NULL;
 774         if (windomain)
 775                 *windomain = NULL;
 776         if (unixname)
 777                 *unixname = NULL;
 778         if (pid)
 779                 *pid = UINT32_MAX;
 780         if (is_user)
 781                 *is_user = -1;
 782         if (is_wuser)
 783                 *is_wuser = -1;
 784         if (direction)
 785                 *direction = IDMAP_DIRECTION_UNDEF;
 786 
 787         __ITER_CHECK(iter, IDMAP_LIST_MAPPINGS);
 788 
 789         mappings = (idmap_mappings_res *)iter->retlist;
 790         if (iter->retcode == IDMAP_NEXT && (mappings == NULL ||
 791             iter->next >= mappings->mappings.mappings_len)) {
 792 
 793                 if ((arg = iter->arg) == NULL) {
 794                         errno = EINVAL;
 795                         return (IDMAP_ERR_ARG);
 796                 }
 797                 arg->limit = iter->limit;
 798 
 799                 retcode = _iter_get_next_list(IDMAP_LIST_MAPPINGS,
 800                     iter, arg,
 801                     (uchar_t **)&mappings, sizeof (*mappings),
 802                     (xdrproc_t)xdr_idmap_list_mappings_1_argument,
 803                     (xdrproc_t)xdr_idmap_mappings_res);
 804                 if (retcode != IDMAP_SUCCESS)
 805                         return (retcode);
 806 
 807                 if (IDMAP_ERROR(mappings->retcode)) {
 808                         retcode  = mappings->retcode;
 809                         xdr_free(xdr_idmap_mappings_res, (caddr_t)mappings);
 810                         free(mappings);
 811                         iter->retlist = NULL;
 812                         return (retcode);
 813                 }
 814                 iter->retcode = mappings->retcode;
 815                 arg->lastrowid = mappings->lastrowid;
 816         }
 817 
 818         if (mappings == NULL || mappings->mappings.mappings_len == 0)
 819                 return (IDMAP_SUCCESS);
 820 
 821         if (iter->next >= mappings->mappings.mappings_len) {
 822                 return (IDMAP_ERR_ARG);
 823         }
 824 
 825         if (sidprefix) {
 826                 str = mappings->mappings.mappings_val[iter->next].id1.
 827                     idmap_id_u.sid.prefix;
 828                 if (str && *str != '\0') {
 829                         *sidprefix = strdup(str);
 830                         if (*sidprefix == NULL) {
 831                                 retcode = IDMAP_ERR_MEMORY;
 832                                 goto errout;
 833                         }
 834                 }
 835         }
 836         if (rid)
 837                 *rid = mappings->mappings.mappings_val[iter->next].id1.
 838                     idmap_id_u.sid.rid;
 839 
 840         retcode = idmap_strdupnull(windomain,
 841             mappings->mappings.mappings_val[iter->next].id1domain);
 842         if (retcode != IDMAP_SUCCESS)
 843                 goto errout;
 844 
 845         retcode = idmap_strdupnull(winname,
 846             mappings->mappings.mappings_val[iter->next].id1name);
 847         if (retcode != IDMAP_SUCCESS)
 848                 goto errout;
 849 
 850         retcode = idmap_strdupnull(unixname,
 851             mappings->mappings.mappings_val[iter->next].id2name);
 852         if (retcode != IDMAP_SUCCESS)
 853                 goto errout;
 854 
 855 
 856         if (pid)
 857                 *pid = mappings->mappings.mappings_val[iter->next].id2.
 858                     idmap_id_u.uid;
 859         if (direction)
 860                 *direction = mappings->mappings.mappings_val[iter->next].
 861                     direction;
 862         if (is_user)
 863                 *is_user = (mappings->mappings.mappings_val[iter->next].id2
 864                     .idtype == IDMAP_UID)?1:0;
 865         if (is_wuser)
 866                 *is_wuser = (mappings->mappings.mappings_val[iter->next].id1
 867                     .idtype == IDMAP_USID)?1:0;
 868 
 869         if (info) {
 870                 idmap_info_mov(info,
 871                     &mappings->mappings.mappings_val[iter->next].info);
 872         }
 873         iter->next++;
 874 
 875         if (iter->next == mappings->mappings.mappings_len)
 876                 return (iter->retcode);
 877         else
 878                 return (IDMAP_NEXT);
 879 
 880 errout:
 881         if (sidprefix && *sidprefix)
 882                 free(*sidprefix);
 883         if (winname && *winname)
 884                 free(*winname);
 885         if (windomain && *windomain)
 886                 free(*windomain);
 887         if (unixname && *unixname)
 888                 free(*unixname);
 889         return (retcode);
 890 }
 891 
 892 
 893 /*
 894  * Destroy the iterator
 895  */
 896 void
 897 idmap_iter_destroy(idmap_iter_t *iter)
 898 {
 899         xdrproc_t _xdr_argument, _xdr_result;
 900 
 901         if (iter == NULL)
 902                 return;
 903 
 904         switch (iter->type) {
 905         case IDMAP_LIST_NAMERULES:
 906                 _xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
 907                 _xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
 908                 break;
 909         case IDMAP_LIST_MAPPINGS:
 910                 _xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
 911                 _xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
 912                 break;
 913         default:
 914                 free(iter);
 915                 return;
 916         };
 917 
 918         if (iter->arg) {
 919                 xdr_free(_xdr_argument, (caddr_t)iter->arg);
 920                 free(iter->arg);
 921         }
 922         if (iter->retlist) {
 923                 xdr_free(_xdr_result, (caddr_t)iter->retlist);
 924                 free(iter->retlist);
 925         }
 926         free(iter);
 927 }
 928 
 929 
 930 /*
 931  * Create handle to get SID to UID/GID mapping entries
 932  *
 933  * Input:
 934  * gh - "get mapping" handle
 935  */
 936 idmap_stat
 937 idmap_get_create(idmap_get_handle_t **gh)
 938 {
 939         idmap_get_handle_t      *tmp;
 940 
 941         /* allocate the handle */
 942         if ((tmp = calloc(1, sizeof (*tmp))) == NULL) {
 943                 errno = ENOMEM;
 944                 return (IDMAP_ERR_MEMORY);
 945         }
 946 
 947         *gh = tmp;
 948         return (IDMAP_SUCCESS);
 949 }
 950 
 951 
 952 /*
 953  * Given SID, get UID
 954  *
 955  * Input:
 956  * sidprefix  - SID prefix
 957  * rid        - RID
 958  * flag       - flag
 959  *
 960  * Output:
 961  * stat - status of the get request
 962  * uid  - POSIX UID if stat = 0
 963  *
 964  * Note: The output parameters will be set by idmap_get_mappings()
 965  */
 966 idmap_stat
 967 idmap_get_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
 968     int flag, uid_t *uid, idmap_stat *stat)
 969 {
 970         return (idmap_getext_uidbysid(gh, sidprefix, rid, flag, uid,
 971             NULL, stat));
 972 }
 973 
 974 /*
 975  * Given SID, get UID
 976  *
 977  * Input:
 978  * sidprefix  - SID prefix
 979  * rid        - RID
 980  * flag       - flag
 981  *
 982  * Output:
 983  * stat - status of the get request
 984  * uid  - POSIX UID if stat = 0
 985  * how  - mapping type if stat = 0
 986  *
 987  * Note: The output parameters will be set by idmap_get_mappings()
 988  */
 989 
 990 idmap_stat
 991 idmap_getext_uidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
 992     int flag, uid_t *uid, idmap_info *info, idmap_stat *stat)
 993 {
 994         idmap_retcode   retcode;
 995         idmap_mapping   *mapping = NULL;
 996 
 997         /* sanity checks */
 998         if (gh == NULL)
 999                 return (IDMAP_ERR_ARG);
1000         if (uid == NULL || sidprefix == NULL)
1001                 return (IDMAP_ERR_ARG);
1002 
1003         if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1004             !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1005                 retcode = idmap_cache_lookup_uidbysid(sidprefix, rid, uid);
1006                 if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1007                         *stat = retcode;
1008                         return (retcode);
1009                 }
1010         }
1011 
1012         /* Extend the request array and the return list */
1013         if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1014                 goto errout;
1015 
1016         /* Setup the request */
1017         mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1018         mapping->flag = flag;
1019         mapping->id1.idtype = IDMAP_SID;
1020         mapping->id1.idmap_id_u.sid.rid = rid;
1021         if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1022                 retcode = IDMAP_ERR_MEMORY;
1023                 goto errout;
1024         }
1025         mapping->id2.idtype = IDMAP_UID;
1026 
1027         /* Setup pointers for the result */
1028         gh->retlist[gh->next].idtype = IDMAP_UID;
1029         gh->retlist[gh->next].uid = uid;
1030         gh->retlist[gh->next].stat = stat;
1031         gh->retlist[gh->next].info = info;
1032         gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1033 
1034         gh->next++;
1035         return (IDMAP_SUCCESS);
1036 
1037 errout:
1038         /* Batch created so far should still be usable */
1039         if (mapping)
1040                 (void) memset(mapping, 0, sizeof (*mapping));
1041         errno = idmap_stat2errno(retcode);
1042         return (retcode);
1043 }
1044 
1045 
1046 /*
1047  * Given SID, get GID
1048  *
1049  * Input:
1050  * sidprefix  - SID prefix
1051  * rid        - rid
1052  * flag       - flag
1053  *
1054  * Output:
1055  * stat - status of the get request
1056  * gid  - POSIX GID if stat = 0
1057  *
1058  * Note: The output parameters will be set by idmap_get_mappings()
1059  */
1060 idmap_stat
1061 idmap_get_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1062     int flag, gid_t *gid, idmap_stat *stat)
1063 {
1064         return (idmap_getext_gidbysid(gh, sidprefix, rid, flag, gid,
1065             NULL, stat));
1066 }
1067 
1068 
1069 /*
1070  * Given SID, get GID
1071  *
1072  * Input:
1073  * sidprefix  - SID prefix
1074  * rid        - rid
1075  * flag       - flag
1076  *
1077  * Output:
1078  * stat - status of the get request
1079  * gid  - POSIX GID if stat = 0
1080  * how  - mapping type if stat = 0
1081  *
1082  * Note: The output parameters will be set by idmap_get_mappings()
1083  */
1084 idmap_stat
1085 idmap_getext_gidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1086     int flag, gid_t *gid, idmap_info *info, idmap_stat *stat)
1087 {
1088 
1089         idmap_retcode   retcode;
1090         idmap_mapping   *mapping = NULL;
1091 
1092         /* sanity checks */
1093         if (gh == NULL)
1094                 return (IDMAP_ERR_ARG);
1095         if (gid == NULL || sidprefix == NULL)
1096                 return (IDMAP_ERR_ARG);
1097 
1098         if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1099             !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1100                 retcode = idmap_cache_lookup_gidbysid(sidprefix, rid, gid);
1101                 if (retcode == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1102                         *stat = retcode;
1103                         return (retcode);
1104                 }
1105         }
1106 
1107         /* Extend the request array and the return list */
1108         if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1109                 goto errout;
1110 
1111         /* Setup the request */
1112         mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1113         mapping->flag = flag;
1114         mapping->id1.idtype = IDMAP_SID;
1115         mapping->id1.idmap_id_u.sid.rid = rid;
1116         if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1117                 retcode = IDMAP_ERR_MEMORY;
1118                 goto errout;
1119         }
1120         mapping->id2.idtype = IDMAP_GID;
1121 
1122         /* Setup pointers for the result */
1123         gh->retlist[gh->next].idtype = IDMAP_GID;
1124         gh->retlist[gh->next].gid = gid;
1125         gh->retlist[gh->next].stat = stat;
1126         gh->retlist[gh->next].info = info;
1127         gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1128 
1129         gh->next++;
1130         return (IDMAP_SUCCESS);
1131 
1132 errout:
1133         if (mapping)
1134                 (void) memset(mapping, 0, sizeof (*mapping));
1135         errno = idmap_stat2errno(retcode);
1136         return (retcode);
1137 }
1138 
1139 
1140 
1141 /*
1142  * Given SID, get POSIX ID i.e. UID/GID
1143  *
1144  * Input:
1145  * sidprefix  - SID prefix
1146  * rid        - rid
1147  * flag       - flag
1148  *
1149  * Output:
1150  * stat    - status of the get request
1151  * is_user - user or group
1152  * pid     - POSIX UID if stat = 0 and is_user = 1
1153  *           POSIX GID if stat = 0 and is_user = 0
1154  *
1155  * Note: The output parameters will be set by idmap_get_mappings()
1156  */
1157 idmap_stat
1158 idmap_get_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1159     int flag, uid_t *pid, int *is_user, idmap_stat *stat)
1160 {
1161         return (idmap_getext_pidbysid(gh, sidprefix, rid, flag, pid, is_user,
1162             NULL, stat));
1163 }
1164 
1165 
1166 
1167 /*
1168  * Given SID, get POSIX ID i.e. UID/GID
1169  *
1170  * Input:
1171  * sidprefix  - SID prefix
1172  * rid        - rid
1173  * flag       - flag
1174  *
1175  * Output:
1176  * stat    - status of the get request
1177  * is_user - user or group
1178  * pid     - POSIX UID if stat = 0 and is_user = 1
1179  *           POSIX GID if stat = 0 and is_user = 0
1180  * how     - mapping type if stat = 0
1181  *
1182  * Note: The output parameters will be set by idmap_get_mappings()
1183  */
1184 idmap_stat
1185 idmap_getext_pidbysid(idmap_get_handle_t *gh, char *sidprefix, idmap_rid_t rid,
1186     int flag, uid_t *pid, int *is_user, idmap_info *info, idmap_stat *stat)
1187 {
1188         idmap_retcode   retcode;
1189         idmap_mapping   *mapping = NULL;
1190 
1191         /* sanity checks */
1192         if (gh == NULL)
1193                 return (IDMAP_ERR_ARG);
1194         if (pid == NULL || sidprefix == NULL || is_user == NULL)
1195                 return (IDMAP_ERR_ARG);
1196 
1197         if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1198             !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1199                 retcode = idmap_cache_lookup_pidbysid(sidprefix, rid, pid,
1200                     is_user);
1201                 if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1202                         *stat = retcode;
1203                         return (retcode);
1204                 }
1205         }
1206 
1207         /* Extend the request array and the return list */
1208         if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1209                 goto errout;
1210 
1211         /* Setup the request */
1212         mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1213         mapping->flag = flag;
1214         mapping->id1.idtype = IDMAP_SID;
1215         mapping->id1.idmap_id_u.sid.rid = rid;
1216         if ((mapping->id1.idmap_id_u.sid.prefix = strdup(sidprefix)) == NULL) {
1217                 retcode = IDMAP_ERR_MEMORY;
1218                 goto errout;
1219         }
1220         mapping->id2.idtype = IDMAP_POSIXID;
1221 
1222         /* Setup pointers for the result */
1223         gh->retlist[gh->next].idtype = IDMAP_POSIXID;
1224         gh->retlist[gh->next].uid = pid;
1225         gh->retlist[gh->next].gid = pid;
1226         gh->retlist[gh->next].is_user = is_user;
1227         gh->retlist[gh->next].stat = stat;
1228         gh->retlist[gh->next].info = info;
1229         gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1230 
1231         gh->next++;
1232         return (IDMAP_SUCCESS);
1233 
1234 errout:
1235         if (mapping)
1236                 (void) memset(mapping, 0, sizeof (*mapping));
1237         errno = idmap_stat2errno(retcode);
1238         return (retcode);
1239 }
1240 
1241 
1242 /*
1243  * Given UID, get SID
1244  *
1245  * Input:
1246  * uid  - POSIX UID
1247  * flag - flag
1248  *
1249  * Output:
1250  * stat - status of the get request
1251  * sid  - SID prefix (if stat == 0)
1252  * rid  - rid
1253  *
1254  * Note: The output parameters will be set by idmap_get_mappings()
1255  */
1256 idmap_stat
1257 idmap_get_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
1258     char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
1259 {
1260         return (idmap_getext_sidbyuid(gh, uid, flag, sidprefix, rid,
1261             NULL, stat));
1262 }
1263 
1264 
1265 /*
1266  * Given UID, get SID
1267  *
1268  * Input:
1269  * uid  - POSIX UID
1270  * flag - flag
1271  *
1272  * Output:
1273  * stat - status of the get request
1274  * sid  - SID prefix (if stat == 0)
1275  * rid  - rid
1276  * how  - mapping type if stat = 0
1277  *
1278  * Note: The output parameters will be set by idmap_get_mappings()
1279  */
1280 idmap_stat
1281 idmap_getext_sidbyuid(idmap_get_handle_t *gh, uid_t uid, int flag,
1282     char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
1283 {
1284 
1285         idmap_retcode   retcode;
1286         idmap_mapping   *mapping = NULL;
1287 
1288         /* sanity checks */
1289         if (gh == NULL)
1290                 return (IDMAP_ERR_ARG);
1291         if (sidprefix == NULL)
1292                 return (IDMAP_ERR_ARG);
1293 
1294         if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1295             !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1296                 retcode = idmap_cache_lookup_sidbyuid(sidprefix, rid, uid);
1297                 if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1298                         *stat = retcode;
1299                         return (retcode);
1300                 }
1301         }
1302 
1303         /* Extend the request array and the return list */
1304         if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1305                 goto errout;
1306 
1307         /* Setup the request */
1308         mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1309         mapping->flag = flag;
1310         mapping->id1.idtype = IDMAP_UID;
1311         mapping->id1.idmap_id_u.uid = uid;
1312         mapping->id2.idtype = IDMAP_SID;
1313 
1314         /* Setup pointers for the result */
1315         gh->retlist[gh->next].idtype = IDMAP_SID;
1316         gh->retlist[gh->next].sidprefix = sidprefix;
1317         gh->retlist[gh->next].rid = rid;
1318         gh->retlist[gh->next].stat = stat;
1319         gh->retlist[gh->next].info = info;
1320         gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1321 
1322         gh->next++;
1323         return (IDMAP_SUCCESS);
1324 
1325 errout:
1326         if (mapping)
1327                 (void) memset(mapping, 0, sizeof (*mapping));
1328         errno = idmap_stat2errno(retcode);
1329         return (retcode);
1330 }
1331 
1332 
1333 /*
1334  * Given GID, get SID
1335  *
1336  * Input:
1337  * gid  - POSIX GID
1338  * flag - flag
1339  *
1340  * Output:
1341  * stat       - status of the get request
1342  * sidprefix  - SID prefix (if stat == 0)
1343  * rid        - rid
1344  *
1345  * Note: The output parameters will be set by idmap_get_mappings()
1346  */
1347 idmap_stat
1348 idmap_get_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
1349     char **sidprefix, idmap_rid_t *rid, idmap_stat *stat)
1350 {
1351         return (idmap_getext_sidbygid(gh, gid, flag, sidprefix, rid,
1352             NULL, stat));
1353 }
1354 
1355 
1356 /*
1357  * Given GID, get SID
1358  *
1359  * Input:
1360  * gid  - POSIX GID
1361  * flag - flag
1362  *
1363  * Output:
1364  * stat       - status of the get request
1365  * sidprefix  - SID prefix (if stat == 0)
1366  * rid        - rid
1367  * how        - mapping type if stat = 0
1368  *
1369  * Note: The output parameters will be set by idmap_get_mappings()
1370  */
1371 idmap_stat
1372 idmap_getext_sidbygid(idmap_get_handle_t *gh, gid_t gid, int flag,
1373     char **sidprefix, idmap_rid_t *rid, idmap_info *info, idmap_stat *stat)
1374 {
1375 
1376         idmap_retcode   retcode;
1377         idmap_mapping   *mapping = NULL;
1378 
1379         /* sanity checks */
1380         if (gh == NULL)
1381                 return (IDMAP_ERR_ARG);
1382         if (sidprefix == NULL)
1383                 return (IDMAP_ERR_ARG);
1384 
1385         if ((flag & IDMAP_REQ_FLG_USE_CACHE) &&
1386             !(flag & IDMAP_REQ_FLG_MAPPING_INFO)) {
1387                 retcode = idmap_cache_lookup_sidbygid(sidprefix, rid, gid);
1388                 if (retcode  == IDMAP_SUCCESS || retcode == IDMAP_ERR_MEMORY) {
1389                         *stat = retcode;
1390                         return (retcode);
1391                 }
1392         }
1393 
1394         /* Extend the request array and the return list */
1395         if ((retcode = _get_ids_extend_batch(gh)) != IDMAP_SUCCESS)
1396                 goto errout;
1397 
1398         /* Setup the request */
1399         mapping = &gh->batch.idmap_mapping_batch_val[gh->next];
1400         mapping->flag = flag;
1401         mapping->id1.idtype = IDMAP_GID;
1402         mapping->id1.idmap_id_u.gid = gid;
1403         mapping->id2.idtype = IDMAP_SID;
1404 
1405         /* Setup pointers for the result */
1406         gh->retlist[gh->next].idtype = IDMAP_SID;
1407         gh->retlist[gh->next].sidprefix = sidprefix;
1408         gh->retlist[gh->next].rid = rid;
1409         gh->retlist[gh->next].stat = stat;
1410         gh->retlist[gh->next].info = info;
1411         gh->retlist[gh->next].cache_res = flag & IDMAP_REQ_FLG_USE_CACHE;
1412 
1413         gh->next++;
1414         return (IDMAP_SUCCESS);
1415 
1416 errout:
1417         if (mapping)
1418                 (void) memset(mapping, 0, sizeof (*mapping));
1419         errno = idmap_stat2errno(retcode);
1420         return (retcode);
1421 }
1422 
1423 
1424 /*
1425  * Process the batched "get mapping" requests. The results (i.e.
1426  * status and identity) will be available in the data areas
1427  * provided by individual requests.
1428  */
1429 idmap_stat
1430 idmap_get_mappings(idmap_get_handle_t *gh)
1431 {
1432         idmap_retcode   retcode;
1433         idmap_ids_res   res;
1434         idmap_id        *res_id;
1435         int             i;
1436         idmap_id        *req_id;
1437         int             direction;
1438 
1439         if (gh == NULL) {
1440                 errno = EINVAL;
1441                 return (IDMAP_ERR_ARG);
1442         }
1443 
1444         (void) memset(&res, 0, sizeof (idmap_ids_res));
1445         retcode = _idmap_clnt_call(IDMAP_GET_MAPPED_IDS,
1446             (xdrproc_t)xdr_idmap_mapping_batch,
1447             (caddr_t)&gh->batch,
1448             (xdrproc_t)xdr_idmap_ids_res,
1449             (caddr_t)&res,
1450             TIMEOUT);
1451         if (retcode != IDMAP_SUCCESS) {
1452                 goto out;
1453         }
1454         if (res.retcode != IDMAP_SUCCESS) {
1455                 retcode = res.retcode;
1456                 goto out;
1457         }
1458         for (i = 0; i < gh->next; i++) {
1459                 if (i >= res.ids.ids_len) {
1460                         *gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1461                         continue;
1462                 }
1463                 *gh->retlist[i].stat = res.ids.ids_val[i].retcode;
1464                 res_id = &res.ids.ids_val[i].id;
1465                 direction = res.ids.ids_val[i].direction;
1466                 req_id = &gh->batch.idmap_mapping_batch_val[i].id1;
1467                 switch (res_id->idtype) {
1468                 case IDMAP_UID:
1469                         if (gh->retlist[i].uid)
1470                                 *gh->retlist[i].uid = res_id->idmap_id_u.uid;
1471                         if (gh->retlist[i].is_user)
1472                                 *gh->retlist[i].is_user = 1;
1473 
1474                         if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1475                             gh->retlist[i].cache_res) {
1476                                 if (gh->retlist[i].is_user != NULL)
1477                                         idmap_cache_add_sid2pid(
1478                                             req_id->idmap_id_u.sid.prefix,
1479                                             req_id->idmap_id_u.sid.rid,
1480                                             res_id->idmap_id_u.uid, 1,
1481                                             direction);
1482                                 else
1483                                         idmap_cache_add_sid2uid(
1484                                             req_id->idmap_id_u.sid.prefix,
1485                                             req_id->idmap_id_u.sid.rid,
1486                                             res_id->idmap_id_u.uid,
1487                                             direction);
1488                         }
1489                         break;
1490 
1491                 case IDMAP_GID:
1492                         if (gh->retlist[i].gid)
1493                                 *gh->retlist[i].gid = res_id->idmap_id_u.gid;
1494                         if (gh->retlist[i].is_user)
1495                                 *gh->retlist[i].is_user = 0;
1496 
1497                         if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1498                             gh->retlist[i].cache_res) {
1499                                 if (gh->retlist[i].is_user != NULL)
1500                                         idmap_cache_add_sid2pid(
1501                                             req_id->idmap_id_u.sid.prefix,
1502                                             req_id->idmap_id_u.sid.rid,
1503                                             res_id->idmap_id_u.gid, 0,
1504                                             direction);
1505                                 else
1506                                         idmap_cache_add_sid2gid(
1507                                             req_id->idmap_id_u.sid.prefix,
1508                                             req_id->idmap_id_u.sid.rid,
1509                                             res_id->idmap_id_u.gid,
1510                                             direction);
1511                         }
1512                         break;
1513 
1514                 case IDMAP_POSIXID:
1515                         if (gh->retlist[i].uid)
1516                                 *gh->retlist[i].uid = 60001;
1517                         if (gh->retlist[i].is_user)
1518                                 *gh->retlist[i].is_user = -1;
1519                         break;
1520 
1521                 case IDMAP_SID:
1522                 case IDMAP_USID:
1523                 case IDMAP_GSID:
1524                         if (gh->retlist[i].rid)
1525                                 *gh->retlist[i].rid =
1526                                     res_id->idmap_id_u.sid.rid;
1527                         if (gh->retlist[i].sidprefix) {
1528                                 if (res_id->idmap_id_u.sid.prefix == NULL ||
1529                                     *res_id->idmap_id_u.sid.prefix == '\0') {
1530                                         *gh->retlist[i].sidprefix = NULL;
1531                                         break;
1532                                 }
1533                                 *gh->retlist[i].sidprefix =
1534                                     strdup(res_id->idmap_id_u.sid.prefix);
1535                                 if (*gh->retlist[i].sidprefix == NULL)
1536                                         *gh->retlist[i].stat =
1537                                             IDMAP_ERR_MEMORY;
1538                         }
1539                         if (res.ids.ids_val[i].retcode == IDMAP_SUCCESS &&
1540                             gh->retlist[i].cache_res) {
1541                                 if (req_id->idtype == IDMAP_UID)
1542                                         idmap_cache_add_sid2uid(
1543                                             res_id->idmap_id_u.sid.prefix,
1544                                             res_id->idmap_id_u.sid.rid,
1545                                             req_id->idmap_id_u.uid,
1546                                             direction);
1547                                 else /* req_id->idtype == IDMAP_GID */
1548                                         idmap_cache_add_sid2gid(
1549                                             res_id->idmap_id_u.sid.prefix,
1550                                             res_id->idmap_id_u.sid.rid,
1551                                             req_id->idmap_id_u.gid,
1552                                             direction);
1553                         }
1554                         break;
1555 
1556                 case IDMAP_NONE:
1557                         break;
1558 
1559                 default:
1560                         *gh->retlist[i].stat = IDMAP_ERR_NORESULT;
1561                         break;
1562                 }
1563                 if (gh->retlist[i].info != NULL) {
1564                         idmap_info_mov(gh->retlist[i].info,
1565                             &res.ids.ids_val[i].info);
1566                 }
1567         }
1568         retcode = IDMAP_SUCCESS;
1569 
1570 out:
1571         _IDMAP_RESET_GET_HANDLE(gh);
1572         xdr_free(xdr_idmap_ids_res, (caddr_t)&res);
1573         errno = idmap_stat2errno(retcode);
1574         return (retcode);
1575 }
1576 
1577 
1578 /*
1579  * Destroy the "get mapping" handle
1580  */
1581 void
1582 idmap_get_destroy(idmap_get_handle_t *gh)
1583 {
1584         if (gh == NULL)
1585                 return;
1586         xdr_free(xdr_idmap_mapping_batch, (caddr_t)&gh->batch);
1587         if (gh->retlist)
1588                 free(gh->retlist);
1589         free(gh);
1590 }
1591 
1592 
1593 /*
1594  * Get windows to unix mapping
1595  */
1596 idmap_stat
1597 idmap_get_w2u_mapping(
1598                 const char *sidprefix, idmap_rid_t *rid,
1599                 const char *winname, const char *windomain,
1600                 int flag, int *is_user, int *is_wuser,
1601                 uid_t *pid, char **unixname, int *direction, idmap_info *info)
1602 {
1603         idmap_mapping           request, *mapping;
1604         idmap_mappings_res      result;
1605         idmap_retcode           retcode, rc;
1606 
1607         (void) memset(&request, 0, sizeof (request));
1608         (void) memset(&result, 0, sizeof (result));
1609 
1610         if (pid)
1611                 *pid = UINT32_MAX;
1612         if (unixname)
1613                 *unixname = NULL;
1614         if (direction)
1615                 *direction = IDMAP_DIRECTION_UNDEF;
1616 
1617         request.flag = flag;
1618         request.id1.idtype = IDMAP_SID;
1619         if (sidprefix && rid) {
1620                 request.id1.idmap_id_u.sid.prefix = (char *)sidprefix;
1621                 request.id1.idmap_id_u.sid.rid = *rid;
1622         } else if (winname) {
1623                 retcode = idmap_strdupnull(&request.id1name, winname);
1624                 if (retcode != IDMAP_SUCCESS)
1625                         goto out;
1626 
1627                 retcode = idmap_strdupnull(&request.id1domain, windomain);
1628                 if (retcode != IDMAP_SUCCESS)
1629                         goto out;
1630 
1631                 request.id1.idmap_id_u.sid.prefix = NULL;
1632         } else {
1633                 errno = EINVAL;
1634                 return (IDMAP_ERR_ARG);
1635         }
1636 
1637         if (*is_user == 1)
1638                 request.id2.idtype = IDMAP_UID;
1639         else if (*is_user == 0)
1640                 request.id2.idtype = IDMAP_GID;
1641         else
1642                 request.id2.idtype = IDMAP_POSIXID;
1643 
1644         if (*is_wuser == 1)
1645                 request.id1.idtype = IDMAP_USID;
1646         else if (*is_wuser == 0)
1647                 request.id1.idtype = IDMAP_GSID;
1648         else
1649                 request.id1.idtype = IDMAP_SID;
1650 
1651         retcode = _idmap_clnt_call(IDMAP_GET_MAPPED_ID_BY_NAME,
1652             (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1653             (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1654             TIMEOUT);
1655 
1656         if (retcode != IDMAP_SUCCESS)
1657                 goto out;
1658 
1659         retcode = result.retcode;
1660 
1661         if ((mapping = result.mappings.mappings_val) == NULL) {
1662                 if (retcode == IDMAP_SUCCESS)
1663                         retcode = IDMAP_ERR_NORESULT;
1664                 goto out;
1665         }
1666 
1667         if (info != NULL)
1668                 idmap_info_mov(info, &mapping->info);
1669 
1670         if (mapping->id2.idtype == IDMAP_UID) {
1671                 *is_user = 1;
1672         } else if (mapping->id2.idtype == IDMAP_GID) {
1673                 *is_user = 0;
1674         } else {
1675                 goto out;
1676         }
1677 
1678         if (mapping->id1.idtype == IDMAP_USID) {
1679                 *is_wuser = 1;
1680         } else if (mapping->id1.idtype == IDMAP_GSID) {
1681                 *is_wuser = 0;
1682         } else {
1683                 goto out;
1684         }
1685 
1686         if (direction)
1687                 *direction = mapping->direction;
1688         if (pid)
1689                 *pid = mapping->id2.idmap_id_u.uid;
1690 
1691         rc = idmap_strdupnull(unixname, mapping->id2name);
1692         if (rc != IDMAP_SUCCESS)
1693                 retcode = rc;
1694 
1695 out:
1696         if (request.id1name != NULL)
1697                 free(request.id1name);
1698         if (request.id1domain != NULL)
1699                 free(request.id1domain);
1700         xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1701         if (retcode != IDMAP_SUCCESS)
1702                 errno = idmap_stat2errno(retcode);
1703         return (retcode);
1704 }
1705 
1706 
1707 /*
1708  * Get unix to windows mapping
1709  */
1710 idmap_stat
1711 idmap_get_u2w_mapping(
1712                 uid_t *pid, const char *unixname,
1713                 int flag, int is_user, int *is_wuser,
1714                 char **sidprefix, idmap_rid_t *rid,
1715                 char **winname, char **windomain,
1716                 int *direction, idmap_info *info)
1717 {
1718         idmap_mapping           request, *mapping;
1719         idmap_mappings_res      result;
1720         idmap_retcode           retcode, rc;
1721 
1722         if (sidprefix)
1723                 *sidprefix = NULL;
1724         if (winname)
1725                 *winname = NULL;
1726         if (windomain)
1727                 *windomain = NULL;
1728         if (rid)
1729                 *rid = UINT32_MAX;
1730         if (direction)
1731                 *direction = IDMAP_DIRECTION_UNDEF;
1732 
1733         (void) memset(&request, 0, sizeof (request));
1734         (void) memset(&result, 0, sizeof (result));
1735 
1736         request.flag = flag;
1737         request.id1.idtype = is_user?IDMAP_UID:IDMAP_GID;
1738 
1739         if (pid && *pid != UINT32_MAX) {
1740                 request.id1.idmap_id_u.uid = *pid;
1741         } else if (unixname) {
1742                 request.id1name = (char *)unixname;
1743                 request.id1.idmap_id_u.uid = UINT32_MAX;
1744         } else {
1745                 errno = EINVAL;
1746                 return (IDMAP_ERR_ARG);
1747         }
1748 
1749         if (is_wuser == NULL)
1750                 request.id2.idtype = IDMAP_SID;
1751         else if (*is_wuser == -1)
1752                 request.id2.idtype = IDMAP_SID;
1753         else if (*is_wuser == 0)
1754                 request.id2.idtype = IDMAP_GSID;
1755         else if (*is_wuser == 1)
1756                 request.id2.idtype = IDMAP_USID;
1757 
1758         retcode = _idmap_clnt_call(IDMAP_GET_MAPPED_ID_BY_NAME,
1759             (xdrproc_t)xdr_idmap_mapping, (caddr_t)&request,
1760             (xdrproc_t)xdr_idmap_mappings_res, (caddr_t)&result,
1761             TIMEOUT);
1762 
1763         if (retcode != IDMAP_SUCCESS)
1764                 return (retcode);
1765 
1766         retcode = result.retcode;
1767 
1768         if ((mapping = result.mappings.mappings_val) == NULL) {
1769                 if (retcode == IDMAP_SUCCESS)
1770                         retcode = IDMAP_ERR_NORESULT;
1771                 goto out;
1772         }
1773 
1774         if (info != NULL)
1775                 idmap_info_mov(info, &mapping->info);
1776 
1777         if (direction != NULL)
1778                 *direction = mapping->direction;
1779 
1780         if (is_wuser != NULL) {
1781                 if (mapping->id2.idtype == IDMAP_USID)
1782                         *is_wuser = 1;
1783                 else if (mapping->id2.idtype == IDMAP_GSID)
1784                         *is_wuser = 0;
1785                 else
1786                         *is_wuser = -1;
1787         }
1788 
1789         if (sidprefix && mapping->id2.idmap_id_u.sid.prefix &&
1790             *mapping->id2.idmap_id_u.sid.prefix != '\0') {
1791                 *sidprefix = strdup(mapping->id2.idmap_id_u.sid.prefix);
1792                 if (*sidprefix == NULL) {
1793                         retcode = IDMAP_ERR_MEMORY;
1794                         goto errout;
1795                 }
1796         }
1797         if (rid)
1798                 *rid = mapping->id2.idmap_id_u.sid.rid;
1799 
1800         rc = idmap_strdupnull(winname, mapping->id2name);
1801         if (rc != IDMAP_SUCCESS)
1802                 retcode = rc;
1803 
1804         rc = idmap_strdupnull(windomain, mapping->id2domain);
1805         if (rc != IDMAP_SUCCESS)
1806                 retcode = rc;
1807 
1808         goto out;
1809 
1810 errout:
1811         if (sidprefix && *sidprefix) {
1812                 free(*sidprefix);
1813                 *sidprefix = NULL;
1814         }
1815         if (winname && *winname) {
1816                 free(*winname);
1817                 *winname = NULL;
1818         }
1819         if (windomain && *windomain) {
1820                 free(*windomain);
1821                 *windomain = NULL;
1822         }
1823 
1824 out:
1825         xdr_free(xdr_idmap_mappings_res, (caddr_t)&result);
1826         if (retcode != IDMAP_SUCCESS)
1827                 errno = idmap_stat2errno(retcode);
1828         return (retcode);
1829 }
1830 
1831 
1832 
1833 #define gettext(s)      s
1834 static stat_table_t stattable[] = {
1835         {IDMAP_SUCCESS, gettext("Success"), 0},
1836         {IDMAP_NEXT, gettext("More results available"), 0},
1837         {IDMAP_ERR_OTHER, gettext("Undefined error"), EINVAL},
1838         {IDMAP_ERR_INTERNAL, gettext("Internal error"), EINVAL},
1839         {IDMAP_ERR_MEMORY, gettext("Out of memory"), ENOMEM},
1840         {IDMAP_ERR_NORESULT, gettext("No results available"), EINVAL},
1841         {IDMAP_ERR_NOTUSER, gettext("Not a user"), EINVAL},
1842         {IDMAP_ERR_NOTGROUP, gettext("Not a group"), EINVAL},
1843         {IDMAP_ERR_NOTSUPPORTED, gettext("Operation not supported"), ENOTSUP},
1844         {IDMAP_ERR_W2U_NAMERULE,
1845                 gettext("Invalid Windows to UNIX name-based rule"), EINVAL},
1846         {IDMAP_ERR_U2W_NAMERULE,
1847                 gettext("Invalid UNIX to Windows name-based rule"), EINVAL},
1848         {IDMAP_ERR_CACHE, gettext("Invalid cache"), EINVAL},
1849         {IDMAP_ERR_DB, gettext("Invalid database"), EINVAL},
1850         {IDMAP_ERR_ARG, gettext("Invalid argument"), EINVAL},
1851         {IDMAP_ERR_SID, gettext("Invalid SID"), EINVAL},
1852         {IDMAP_ERR_IDTYPE, gettext("Invalid identity type"), EINVAL},
1853         {IDMAP_ERR_RPC_HANDLE, gettext("Bad RPC handle"), EBADF},
1854         {IDMAP_ERR_RPC, gettext("RPC error"), EINVAL},
1855         {IDMAP_ERR_CLIENT_HANDLE, gettext("Bad client handle"), EINVAL},
1856         {IDMAP_ERR_BUSY, gettext("Server is busy"), EBUSY},
1857         {IDMAP_ERR_PERMISSION_DENIED, gettext("Permission denied"), EACCES},
1858         {IDMAP_ERR_NOMAPPING,
1859                 gettext("Mapping not found or inhibited"), EINVAL},
1860         {IDMAP_ERR_NEW_ID_ALLOC_REQD,
1861                 gettext("New mapping needs to be created"), EINVAL},
1862         {IDMAP_ERR_DOMAIN, gettext("Invalid domain"), EINVAL},
1863         {IDMAP_ERR_SECURITY, gettext("Security issue"), EINVAL},
1864         {IDMAP_ERR_NOTFOUND, gettext("Not found"), EINVAL},
1865         {IDMAP_ERR_DOMAIN_NOTFOUND, gettext("Domain not found"), EINVAL},
1866         {IDMAP_ERR_UPDATE_NOTALLOWED, gettext("Update not allowed"), EINVAL},
1867         {IDMAP_ERR_CFG, gettext("Configuration error"), EINVAL},
1868         {IDMAP_ERR_CFG_CHANGE, gettext("Invalid configuration change"), EINVAL},
1869         {IDMAP_ERR_NOTMAPPED_WELLKNOWN,
1870                 gettext("No mapping for well-known SID"), EINVAL},
1871         {IDMAP_ERR_RETRIABLE_NET_ERR,
1872                 gettext("Windows lookup failed"), EINVAL},
1873         {IDMAP_ERR_W2U_NAMERULE_CONFLICT,
1874                 gettext("Duplicate rule or conflicts with an existing "
1875                 "Windows to UNIX name-based rule"), EINVAL},
1876         {IDMAP_ERR_U2W_NAMERULE_CONFLICT,
1877                 gettext("Duplicate rule or conflicts with an existing "
1878                 "Unix to Windows name-based rule"), EINVAL},
1879         {IDMAP_ERR_BAD_UTF8,
1880                 gettext("Invalid or illegal UTF-8 sequence found in "
1881                 "a given Windows entity name or domain name"), EINVAL},
1882         {IDMAP_ERR_NONE_GENERATED,
1883                 gettext("Mapping not found and none created (see -c option)"),
1884                 EINVAL},
1885         {IDMAP_ERR_PROP_UNKNOWN,
1886                 gettext("Undefined property"),
1887                 EINVAL},
1888         {IDMAP_ERR_NS_LDAP_CFG,
1889                 gettext("Native LDAP configuration error"), EINVAL},
1890         {IDMAP_ERR_NS_LDAP_PARTIAL,
1891                 gettext("Partial result from Native LDAP"), EINVAL},
1892         {IDMAP_ERR_NS_LDAP_OP_FAILED,
1893                 gettext("Native LDAP operation failed"), EINVAL},
1894         {IDMAP_ERR_NS_LDAP_BAD_WINNAME,
1895                 gettext("Improper winname form found in Native LDAP"), EINVAL},
1896         {IDMAP_ERR_NO_ACTIVEDIRECTORY,
1897                 gettext("No AD servers"),
1898                 EINVAL},
1899         {-1, NULL, 0}
1900 };
1901 #undef  gettext
1902 
1903 
1904 /*
1905  * Get description of status code
1906  *
1907  * Input:
1908  * status - Status code returned by libidmap API call
1909  *
1910  * Return Value:
1911  * human-readable localized description of idmap_stat
1912  */
1913 const char *
1914 idmap_stat2string(idmap_stat status)
1915 {
1916         int i;
1917 
1918         for (i = 0; stattable[i].msg; i++) {
1919                 if (stattable[i].retcode == status)
1920                         return (dgettext(TEXT_DOMAIN, stattable[i].msg));
1921         }
1922         return (dgettext(TEXT_DOMAIN, "Unknown error"));
1923 }
1924 
1925 
1926 static int
1927 idmap_stat2errno(idmap_stat stat)
1928 {
1929         int i;
1930         for (i = 0; stattable[i].msg; i++) {
1931                 if (stattable[i].retcode == stat)
1932                         return (stattable[i].errnum);
1933         }
1934         return (EINVAL);
1935 }
1936 
1937 
1938 /*
1939  * Get status code from string
1940  */
1941 idmap_stat
1942 idmap_string2stat(const char *str)
1943 {
1944         if (str == NULL)
1945                 return (IDMAP_ERR_INTERNAL);
1946 
1947 #define return_cmp(a) \
1948         if (0 == strcmp(str, "IDMAP_ERR_" #a)) \
1949                 return (IDMAP_ERR_ ## a);
1950 
1951         return_cmp(OTHER);
1952         return_cmp(INTERNAL);
1953         return_cmp(MEMORY);
1954         return_cmp(NORESULT);
1955         return_cmp(NOTUSER);
1956         return_cmp(NOTGROUP);
1957         return_cmp(NOTSUPPORTED);
1958         return_cmp(W2U_NAMERULE);
1959         return_cmp(U2W_NAMERULE);
1960         return_cmp(CACHE);
1961         return_cmp(DB);
1962         return_cmp(ARG);
1963         return_cmp(SID);
1964         return_cmp(IDTYPE);
1965         return_cmp(RPC_HANDLE);
1966         return_cmp(RPC);
1967         return_cmp(CLIENT_HANDLE);
1968         return_cmp(BUSY);
1969         return_cmp(PERMISSION_DENIED);
1970         return_cmp(NOMAPPING);
1971         return_cmp(NEW_ID_ALLOC_REQD);
1972         return_cmp(DOMAIN);
1973         return_cmp(SECURITY);
1974         return_cmp(NOTFOUND);
1975         return_cmp(DOMAIN_NOTFOUND);
1976         return_cmp(MEMORY);
1977         return_cmp(UPDATE_NOTALLOWED);
1978         return_cmp(CFG);
1979         return_cmp(CFG_CHANGE);
1980         return_cmp(NOTMAPPED_WELLKNOWN);
1981         return_cmp(RETRIABLE_NET_ERR);
1982         return_cmp(W2U_NAMERULE_CONFLICT);
1983         return_cmp(U2W_NAMERULE_CONFLICT);
1984         return_cmp(BAD_UTF8);
1985         return_cmp(NONE_GENERATED);
1986         return_cmp(PROP_UNKNOWN);
1987         return_cmp(NS_LDAP_CFG);
1988         return_cmp(NS_LDAP_PARTIAL);
1989         return_cmp(NS_LDAP_OP_FAILED);
1990         return_cmp(NS_LDAP_BAD_WINNAME);
1991         return_cmp(NO_ACTIVEDIRECTORY);
1992 #undef return_cmp
1993 
1994         return (IDMAP_ERR_OTHER);
1995 }
1996 
1997 
1998 /*
1999  * Map the given status to one that can be returned by the protocol
2000  */
2001 idmap_stat
2002 idmap_stat4prot(idmap_stat status)
2003 {
2004         switch (status) {
2005         case IDMAP_ERR_MEMORY:
2006         case IDMAP_ERR_CACHE:
2007                 return (IDMAP_ERR_INTERNAL);
2008         }
2009         return (status);
2010 }
2011 
2012 
2013 /*
2014  * This is a convenience routine which duplicates a string after
2015  * checking for NULL pointers. This function will return success if
2016  * either the 'to' OR 'from' pointers are NULL.
2017  */
2018 static idmap_stat
2019 idmap_strdupnull(char **to, const char *from)
2020 {
2021         if (to == NULL)
2022                 return (IDMAP_SUCCESS);
2023 
2024         if (from == NULL || *from == '\0') {
2025                 *to = NULL;
2026                 return (IDMAP_SUCCESS);
2027         }
2028 
2029         *to = strdup(from);
2030         if (*to == NULL)
2031                 return (IDMAP_ERR_MEMORY);
2032         return (IDMAP_SUCCESS);
2033 }
2034 
2035 
2036 idmap_stat
2037 idmap_namerule_cpy(idmap_namerule *to, idmap_namerule *from)
2038 {
2039         idmap_stat retval;
2040 
2041         if (to == NULL)
2042                 return (IDMAP_SUCCESS);
2043 
2044         (void) memcpy(to, from, sizeof (idmap_namerule));
2045         to->windomain = NULL;
2046         to->winname = NULL;
2047         to->unixname = NULL;
2048 
2049         retval = idmap_strdupnull(&to->windomain, from->windomain);
2050         if (retval != IDMAP_SUCCESS)
2051                 return (retval);
2052 
2053         retval = idmap_strdupnull(&to->winname, from->winname);
2054         if (retval != IDMAP_SUCCESS) {
2055                 free(to->windomain);
2056                 to->windomain = NULL;
2057                 return (retval);
2058         }
2059 
2060         retval = idmap_strdupnull(&to->unixname, from->unixname);
2061         if (retval != IDMAP_SUCCESS) {
2062                 free(to->windomain);
2063                 to->windomain = NULL;
2064                 free(to->winname);
2065                 to->winname = NULL;
2066                 return (retval);
2067         }
2068 
2069         return (retval);
2070 }
2071 
2072 
2073 /*
2074  * Move the contents of the "info" structure from "from" to "to".
2075  */
2076 void
2077 idmap_info_mov(idmap_info *to, idmap_info *from)
2078 {
2079         (void) memcpy(to, from, sizeof (idmap_info));
2080         (void) memset(from, 0, sizeof (idmap_info));
2081 }
2082 
2083 
2084 void
2085 idmap_info_free(idmap_info *info)
2086 {
2087         if (info == NULL)
2088                 return;
2089 
2090         xdr_free(xdr_idmap_info, (caddr_t)info);
2091         (void) memset(info, 0, sizeof (idmap_info));
2092 }
2093 
2094 
2095 void
2096 idmap_how_clear(idmap_how *how)
2097 {
2098         xdr_free(xdr_idmap_how, (caddr_t)how);
2099         (void) memset(how, 0, sizeof (*how));
2100 }
2101 
2102 
2103 /*
2104  * Get uid given Windows name
2105  */
2106 idmap_stat
2107 idmap_getuidbywinname(const char *name, const char *domain, int flag,
2108     uid_t *uid)
2109 {
2110         idmap_retcode   rc;
2111         int             is_user = 1;
2112         int             is_wuser = -1;
2113         int             direction;
2114 
2115         if (uid == NULL)
2116                 return (IDMAP_ERR_ARG);
2117 
2118         if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2119                 rc = idmap_cache_lookup_uidbywinname(name, domain, uid);
2120                 if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
2121                         return (rc);
2122         }
2123         /* Get mapping */
2124         rc = idmap_get_w2u_mapping(NULL, NULL, name, domain, flag,
2125             &is_user, &is_wuser, uid, NULL, &direction, NULL);
2126 
2127         if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
2128                 /* If we have not got the domain don't store UID to winname */
2129                 if (domain == NULL)
2130                         direction = IDMAP_DIRECTION_W2U;
2131                 idmap_cache_add_winname2uid(name, domain, *uid, direction);
2132         }
2133 
2134         return (rc);
2135 }
2136 
2137 
2138 /*
2139  * Get gid given Windows name
2140  */
2141 idmap_stat
2142 idmap_getgidbywinname(const char *name, const char *domain, int flag,
2143     gid_t *gid)
2144 {
2145         idmap_retcode   rc;
2146         int             is_user = 0;
2147         int             is_wuser = -1;
2148         int             direction;
2149 
2150         if (gid == NULL)
2151                 return (IDMAP_ERR_ARG);
2152 
2153         if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2154                 rc = idmap_cache_lookup_gidbywinname(name, domain, gid);
2155                 if (rc == IDMAP_SUCCESS || rc == IDMAP_ERR_MEMORY)
2156                         return (rc);
2157         }
2158 
2159         /* Get mapping */
2160         rc = idmap_get_w2u_mapping(NULL, NULL, name, domain, flag,
2161             &is_user, &is_wuser, gid, NULL, &direction, NULL);
2162 
2163         if (rc == IDMAP_SUCCESS && (flag & IDMAP_REQ_FLG_USE_CACHE)) {
2164                 /* If we have not got the domain don't store GID to winname */
2165                 if (domain == NULL)
2166                         direction = IDMAP_DIRECTION_W2U;
2167                 idmap_cache_add_winname2gid(name, domain, *gid, direction);
2168         }
2169 
2170         return (rc);
2171 }
2172 
2173 
2174 /*
2175  * Get winname given pid
2176  */
2177 idmap_stat
2178 idmap_getwinnamebypid(uid_t pid, int is_user, int flag, char **name,
2179     char **domain)
2180 {
2181         idmap_retcode   rc;
2182         int             len;
2183         char            *winname, *windomain;
2184         int             direction;
2185 
2186         if (name == NULL)
2187                 return (IDMAP_ERR_ARG);
2188 
2189         if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2190                 if (is_user)
2191                         rc = idmap_cache_lookup_winnamebyuid(&winname,
2192                             &windomain, pid);
2193                 else
2194                         rc = idmap_cache_lookup_winnamebygid(&winname,
2195                             &windomain, pid);
2196                 if (rc == IDMAP_SUCCESS)
2197                         goto out;
2198                 if (rc == IDMAP_ERR_MEMORY)
2199                         return (rc);
2200         }
2201 
2202         /* Get mapping */
2203         rc = idmap_get_u2w_mapping(&pid, NULL, flag, is_user, NULL,
2204             NULL, NULL, &winname, &windomain, &direction, NULL);
2205 
2206         /* Return on error */
2207         if (rc != IDMAP_SUCCESS)
2208                 return (rc);
2209 
2210         /*
2211          * The given PID may have been mapped to a locally
2212          * generated SID in which case there isn't any
2213          * Windows name
2214          */
2215         if (winname == NULL) {
2216                 idmap_free(windomain);
2217                 return (IDMAP_ERR_NORESULT);
2218         }
2219 
2220         if (flag & IDMAP_REQ_FLG_USE_CACHE) {
2221                 if (is_user)
2222                         idmap_cache_add_winname2uid(winname, windomain,
2223                             pid, direction);
2224                 else
2225                         idmap_cache_add_winname2gid(winname, windomain,
2226                             pid, direction);
2227         }
2228 
2229 out:
2230         if (domain != NULL) {
2231                 *name = winname;
2232                 *domain = windomain;
2233         } else {
2234                 char *wd = windomain != NULL ? windomain : "";
2235                 len = snprintf(NULL, 0, "%s@%s", winname, wd) + 1;
2236                 if ((*name = malloc(len)) != NULL)
2237                         (void) snprintf(*name, len, "%s@%s", winname, wd);
2238                 else
2239                         rc = IDMAP_ERR_MEMORY;
2240                 idmap_free(winname);
2241                 idmap_free(windomain);
2242         }
2243 
2244         return (rc);
2245 }
2246 
2247 
2248 /*
2249  * Get winname given uid
2250  */
2251 idmap_stat
2252 idmap_getwinnamebyuid(uid_t uid, int flag, char **name, char **domain)
2253 {
2254         return (idmap_getwinnamebypid(uid, 1, flag, name, domain));
2255 }
2256 
2257 
2258 /*
2259  * Get winname given gid
2260  */
2261 idmap_stat
2262 idmap_getwinnamebygid(gid_t gid, int flag, char **name, char **domain)
2263 {
2264         return (idmap_getwinnamebypid(gid, 0, flag, name, domain));
2265 }
2266 
2267 idmap_stat
2268 idmap_flush(idmap_flush_op op)
2269 {
2270         idmap_retcode           rc1, rc2;
2271 
2272         rc1 = _idmap_clnt_call(IDMAP_FLUSH,
2273             (xdrproc_t)xdr_idmap_flush_op, (caddr_t)&op,
2274             (xdrproc_t)xdr_idmap_retcode, (caddr_t)&rc2, TIMEOUT);
2275 
2276         if (rc1 != IDMAP_SUCCESS)
2277                 return (rc1);
2278         return (rc2);
2279 }
2280 
2281 
2282 /*
2283  * syslog is the default logger.
2284  * It can be overwritten by supplying a logger
2285  * with  idmap_set_logger()
2286  */
2287 idmap_logger_t logger = syslog;
2288 
2289 
2290 void
2291 idmap_set_logger(idmap_logger_t funct)
2292 {
2293         logger = funct;
2294 }
2295 
2296 /*
2297  * Helper functions that concatenate two parts of a name and then
2298  * look up a value, so that the same set of functions can be used to
2299  * process both "in" and "out" parameters.
2300  */
2301 static
2302 boolean_t
2303 idmap_trace_get_str(nvlist_t *entry, char *n1, char *n2, char **ret)
2304 {
2305         char name[IDMAP_TRACE_NAME_MAX+1];      /* Max used is about 11 */
2306         int err;
2307 
2308         (void) strlcpy(name, n1, sizeof (name));
2309         if (n2 != NULL)
2310                 (void) strlcat(name, n2, sizeof (name));
2311 
2312         err = nvlist_lookup_string(entry, name, ret);
2313         return (err == 0);
2314 }
2315 
2316 static
2317 boolean_t
2318 idmap_trace_get_int(nvlist_t *entry, char *n1, char *n2, int64_t *ret)
2319 {
2320         char name[IDMAP_TRACE_NAME_MAX+1];      /* Max used is about 11 */
2321         int err;
2322 
2323         (void) strlcpy(name, n1, sizeof (name));
2324         if (n2 != NULL)
2325                 (void) strlcat(name, n2, sizeof (name));
2326 
2327         err = nvlist_lookup_int64(entry, name, ret);
2328         return (err == 0);
2329 }
2330 
2331 static
2332 void
2333 idmap_trace_print_id(FILE *out, nvlist_t *entry, char *fromto)
2334 {
2335         char *s;
2336         int64_t i64;
2337 
2338         if (idmap_trace_get_int(entry, fromto, IDMAP_TRACE_TYPE, &i64)) {
2339                 switch (i64) {
2340                 case IDMAP_POSIXID:
2341                         (void) fprintf(out, "unixname ");
2342                         break;
2343                 case IDMAP_UID:
2344                         (void) fprintf(out, "unixuser ");
2345                         break;
2346                 case IDMAP_GID:
2347                         (void) fprintf(out, "unixgroup ");
2348                         break;
2349                 case IDMAP_SID:
2350                         (void) fprintf(out, "winname ");
2351                         break;
2352                 case IDMAP_USID:
2353                         (void) fprintf(out, "winuser ");
2354                         break;
2355                 case IDMAP_GSID:
2356                         (void) fprintf(out, "wingroup ");
2357                         break;
2358                 case IDMAP_NONE:
2359                         (void) fprintf(out, gettext("unknown "));
2360                         break;
2361                 default:
2362                         (void) fprintf(out, gettext("bad %d "), (int)i64);
2363                         break;
2364                 }
2365         }
2366 
2367         if (idmap_trace_get_str(entry, fromto, IDMAP_TRACE_NAME, &s))
2368                 (void) fprintf(out, "%s ", s);
2369 
2370         if (idmap_trace_get_str(entry, fromto, IDMAP_TRACE_SID, &s))
2371                 (void) fprintf(out, "%s ", s);
2372 
2373         if (idmap_trace_get_int(entry, fromto, IDMAP_TRACE_UNIXID, &i64))
2374                 (void) fprintf(out, "%u ", (uid_t)i64);
2375 }
2376 
2377 void
2378 idmap_trace_print_1(FILE *out, char *prefix, nvlist_t *entry)
2379 {
2380         char *s;
2381         int64_t i64;
2382 
2383         (void) fprintf(out, "%s", prefix);
2384         idmap_trace_print_id(out, entry, "from");
2385         (void) fprintf(out, "-> ");
2386         idmap_trace_print_id(out, entry, "to");
2387         if (idmap_trace_get_int(entry, IDMAP_TRACE_ERROR, NULL, &i64))
2388                 (void) fprintf(out, gettext("Error %d "), (int)i64);
2389         (void) fprintf(out, "-");
2390         if (idmap_trace_get_str(entry, IDMAP_TRACE_MESSAGE, NULL, &s))
2391                 (void) fprintf(out, " %s", s);
2392         (void) fprintf(out, "\n");
2393 }
2394 
2395 void
2396 idmap_trace_print(FILE *out, char *prefix, nvlist_t *trace)
2397 {
2398         nvpair_t *nvp;
2399 
2400         for (nvp = nvlist_next_nvpair(trace, NULL);
2401             nvp != NULL;
2402             nvp = nvlist_next_nvpair(trace, nvp)) {
2403                 nvlist_t *entry;
2404                 int err;
2405 
2406                 err = nvpair_value_nvlist(nvp, &entry);
2407                 assert(err == 0);
2408 
2409                 idmap_trace_print_1(out, prefix, entry);
2410         }
2411 }