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