xref: /titanic_41/usr/src/cmd/idmap/idmapd/dbutils.c (revision f34a71784df3fbc5d1227a7b6201fd318ad1667e)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Database related utility routines
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <rpc/rpc.h>
37 #include <sys/sid.h>
38 #include <time.h>
39 #include <pwd.h>
40 #include <grp.h>
41 #include <pthread.h>
42 #include <assert.h>
43 #include <sys/u8_textprep.h>
44 #include <alloca.h>
45 
46 #include "idmapd.h"
47 #include "adutils.h"
48 #include "string.h"
49 #include "idmap_priv.h"
50 #include "schema.h"
51 #include "nldaputils.h"
52 
53 
54 static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
55 		sqlite_vm **, int *, int, const char ***);
56 static idmap_retcode ad_lookup_one(lookup_state_t *, idmap_mapping *,
57 		idmap_id_res *);
58 static idmap_retcode lookup_localsid2pid(idmap_mapping *, idmap_id_res *);
59 static idmap_retcode lookup_cache_name2sid(sqlite *, const char *,
60 		const char *, char **, char **, idmap_rid_t *, int *);
61 
62 #define	NELEM(a)	(sizeof (a) / sizeof ((a)[0]))
63 
64 #define	EMPTY_NAME(name)	(*name == 0 || strcmp(name, "\"\"") == 0)
65 
66 #define	DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
67 		(req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
68 
69 #define	AVOID_NAMESERVICE(req)\
70 		(req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
71 
72 #define	ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)\
73 		(req->flag & IDMAP_REQ_FLG_WK_OR_LOCAL_SIDS_ONLY)
74 
75 #define	IS_EPHEMERAL(pid)	(pid > INT32_MAX && pid != SENTINEL_PID)
76 
77 #define	LOCALRID_MIN	1000
78 
79 
80 typedef enum init_db_option {
81 	FAIL_IF_CORRUPT = 0,
82 	REMOVE_IF_CORRUPT = 1
83 } init_db_option_t;
84 
85 /*
86  * Data structure to store well-known SIDs and
87  * associated mappings (if any)
88  */
89 typedef struct wksids_table {
90 	const char	*sidprefix;
91 	uint32_t	rid;
92 	const char	*domain;
93 	const char	*winname;
94 	int		is_wuser;
95 	uid_t		pid;
96 	int		is_user;
97 	int		direction;
98 } wksids_table_t;
99 
100 /*
101  * Thread specific data to hold the database handles so that the
102  * databases are not opened and closed for every request. It also
103  * contains the sqlite busy handler structure.
104  */
105 
106 struct idmap_busy {
107 	const char *name;
108 	const int *delays;
109 	int delay_size;
110 	int total;
111 	int sec;
112 };
113 
114 
115 typedef struct idmap_tsd {
116 	sqlite *db_db;
117 	sqlite *cache_db;
118 	struct idmap_busy cache_busy;
119 	struct idmap_busy db_busy;
120 } idmap_tsd_t;
121 
122 
123 
124 static const int cache_delay_table[] =
125 		{ 1, 2, 5, 10, 15, 20, 25, 30,  35,  40,
126 		50,  50, 60, 70, 80, 90, 100};
127 
128 static const int db_delay_table[] =
129 		{ 5, 10, 15, 20, 30,  40,  55,  70, 100};
130 
131 
132 static pthread_key_t	idmap_tsd_key;
133 
134 static const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user);
135 static const wksids_table_t *find_wksid_by_sid(const char *sid, int rid,
136     int type);
137 static const wksids_table_t *find_wksid_by_name(const char *name,
138     const char *domain, int type);
139 
140 void
141 idmap_tsd_destroy(void *key)
142 {
143 
144 	idmap_tsd_t	*tsd = (idmap_tsd_t *)key;
145 	if (tsd) {
146 		if (tsd->db_db)
147 			(void) sqlite_close(tsd->db_db);
148 		if (tsd->cache_db)
149 			(void) sqlite_close(tsd->cache_db);
150 		free(tsd);
151 	}
152 }
153 
154 int
155 idmap_init_tsd_key(void)
156 {
157 	return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy));
158 }
159 
160 
161 
162 idmap_tsd_t *
163 idmap_get_tsd(void)
164 {
165 	idmap_tsd_t	*tsd;
166 
167 	if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) {
168 		/* No thread specific data so create it */
169 		if ((tsd = malloc(sizeof (*tsd))) != NULL) {
170 			/* Initialize thread specific data */
171 			(void) memset(tsd, 0, sizeof (*tsd));
172 			/* save the trhread specific data */
173 			if (pthread_setspecific(idmap_tsd_key, tsd) != 0) {
174 				/* Can't store key */
175 				free(tsd);
176 				tsd = NULL;
177 			}
178 		} else {
179 			tsd = NULL;
180 		}
181 	}
182 
183 	return (tsd);
184 }
185 
186 /*
187  * A simple wrapper around u8_textprep_str() that returns the Unicode
188  * lower-case version of some string.  The result must be freed.
189  */
190 char *
191 tolower_u8(const char *s)
192 {
193 	char *res = NULL;
194 	char *outs;
195 	size_t inlen, outlen, inbytesleft, outbytesleft;
196 	int rc, err;
197 
198 	/*
199 	 * u8_textprep_str() does not allocate memory.  The input and
200 	 * output buffers may differ in size (though that would be more
201 	 * likely when normalization is done).  We have to loop over it...
202 	 *
203 	 * To improve the chances that we can avoid looping we add 10
204 	 * bytes of output buffer room the first go around.
205 	 */
206 	inlen = inbytesleft = strlen(s);
207 	outlen = outbytesleft = inlen + 10;
208 	if ((res = malloc(outlen)) == NULL)
209 		return (NULL);
210 	outs = res;
211 
212 	while ((rc = u8_textprep_str((char *)s, &inbytesleft, outs,
213 	    &outbytesleft, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST, &err)) < 0 &&
214 	    err == E2BIG) {
215 		if ((res = realloc(res, outlen + inbytesleft)) == NULL)
216 			return (NULL);
217 		/* adjust input/output buffer pointers */
218 		s += (inlen - inbytesleft);
219 		outs = res + outlen - outbytesleft;
220 		/* adjust outbytesleft and outlen */
221 		outlen += inbytesleft;
222 		outbytesleft += inbytesleft;
223 	}
224 
225 	if (rc < 0) {
226 		free(res);
227 		res = NULL;
228 		return (NULL);
229 	}
230 
231 	res[outlen - outbytesleft] = '\0';
232 
233 	return (res);
234 }
235 
236 static int sql_exec_tran_no_cb(sqlite *db, char *sql, const char *dbname,
237 	const char *while_doing);
238 
239 
240 /*
241  * Initialize 'dbname' using 'sql'
242  */
243 static
244 int
245 init_db_instance(const char *dbname, int version,
246 	const char *detect_version_sql, char * const *sql,
247 	init_db_option_t opt, int *created, int *upgraded)
248 {
249 	int rc, curr_version;
250 	int tries = 1;
251 	int prio = LOG_NOTICE;
252 	sqlite *db = NULL;
253 	char *errmsg = NULL;
254 
255 	*created = 0;
256 	*upgraded = 0;
257 
258 	if (opt == REMOVE_IF_CORRUPT)
259 		tries = 3;
260 
261 rinse_repeat:
262 	if (tries == 0) {
263 		idmapdlog(LOG_ERR, "Failed to initialize db %s", dbname);
264 		return (-1);
265 	}
266 	if (tries-- == 1)
267 		/* Last try, log errors */
268 		prio = LOG_ERR;
269 
270 	db = sqlite_open(dbname, 0600, &errmsg);
271 	if (db == NULL) {
272 		idmapdlog(prio, "Error creating database %s (%s)",
273 		    dbname, CHECK_NULL(errmsg));
274 		sqlite_freemem(errmsg);
275 		if (opt == REMOVE_IF_CORRUPT)
276 			(void) unlink(dbname);
277 		goto rinse_repeat;
278 	}
279 
280 	sqlite_busy_timeout(db, 3000);
281 
282 	/* Detect current version of schema in the db, if any */
283 	curr_version = 0;
284 	if (detect_version_sql != NULL) {
285 		char *end, **results;
286 		int nrow;
287 
288 #ifdef	IDMAPD_DEBUG
289 		(void) fprintf(stderr, "Schema version detection SQL: %s\n",
290 		    detect_version_sql);
291 #endif	/* IDMAPD_DEBUG */
292 		rc = sqlite_get_table(db, detect_version_sql, &results,
293 		    &nrow, NULL, &errmsg);
294 		if (rc != SQLITE_OK) {
295 			idmapdlog(prio,
296 			    "Error detecting schema version of db %s (%s)",
297 			    dbname, errmsg);
298 			sqlite_freemem(errmsg);
299 			sqlite_free_table(results);
300 			sqlite_close(db);
301 			return (-1);
302 		}
303 		if (nrow != 1) {
304 			idmapdlog(prio,
305 			    "Error detecting schema version of db %s", dbname);
306 			sqlite_close(db);
307 			sqlite_free_table(results);
308 			return (-1);
309 		}
310 		curr_version = strtol(results[1], &end, 10);
311 		sqlite_free_table(results);
312 	}
313 
314 	if (curr_version < 0) {
315 		if (opt == REMOVE_IF_CORRUPT)
316 			(void) unlink(dbname);
317 		goto rinse_repeat;
318 	}
319 
320 	if (curr_version == version)
321 		goto done;
322 
323 	/* Install or upgrade schema */
324 #ifdef	IDMAPD_DEBUG
325 	(void) fprintf(stderr, "Schema init/upgrade SQL: %s\n",
326 	    sql[curr_version]);
327 #endif	/* IDMAPD_DEBUG */
328 	rc = sql_exec_tran_no_cb(db, sql[curr_version], dbname,
329 	    (curr_version == 0) ? "installing schema" : "upgrading schema");
330 	if (rc != 0) {
331 		idmapdlog(prio, "Error %s schema for db %s", dbname,
332 		    (curr_version == 0) ? "installing schema" :
333 		    "upgrading schema");
334 		if (opt == REMOVE_IF_CORRUPT)
335 			(void) unlink(dbname);
336 		goto rinse_repeat;
337 	}
338 
339 	*upgraded = (curr_version > 0);
340 	*created = (curr_version == 0);
341 
342 done:
343 	(void) sqlite_close(db);
344 	return (0);
345 }
346 
347 
348 /*
349  * This is the SQLite database busy handler that retries the SQL
350  * operation until it is successful.
351  */
352 int
353 /* LINTED E_FUNC_ARG_UNUSED */
354 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count)
355 {
356 	struct idmap_busy	*busy = arg;
357 	int			delay;
358 	struct timespec		rqtp;
359 
360 	if (count == 1)  {
361 		busy->total = 0;
362 		busy->sec = 2;
363 	}
364 	if (busy->total > 1000 * busy->sec) {
365 		idmapdlog(LOG_DEBUG,
366 		    "Thread %d waited %d sec for the %s database",
367 		    pthread_self(), busy->sec, busy->name);
368 		busy->sec++;
369 	}
370 
371 	if (count <= busy->delay_size) {
372 		delay = busy->delays[count-1];
373 	} else {
374 		delay = busy->delays[busy->delay_size - 1];
375 	}
376 	busy->total += delay;
377 	rqtp.tv_sec = 0;
378 	rqtp.tv_nsec = delay * (NANOSEC / MILLISEC);
379 	(void) nanosleep(&rqtp, NULL);
380 	return (1);
381 }
382 
383 
384 /*
385  * Get the database handle
386  */
387 idmap_retcode
388 get_db_handle(sqlite **db)
389 {
390 	char		*errmsg;
391 	idmap_tsd_t	*tsd;
392 
393 	/*
394 	 * Retrieve the db handle from thread-specific storage
395 	 * If none exists, open and store in thread-specific storage.
396 	 */
397 	if ((tsd = idmap_get_tsd()) == NULL) {
398 		idmapdlog(LOG_ERR,
399 		    "Error getting thread specific data for %s", IDMAP_DBNAME);
400 		return (IDMAP_ERR_MEMORY);
401 	}
402 
403 	if (tsd->db_db == NULL) {
404 		tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg);
405 		if (tsd->db_db == NULL) {
406 			idmapdlog(LOG_ERR, "Error opening database %s (%s)",
407 			    IDMAP_DBNAME, CHECK_NULL(errmsg));
408 			sqlite_freemem(errmsg);
409 			return (IDMAP_ERR_DB);
410 		}
411 
412 		tsd->db_busy.name = IDMAP_DBNAME;
413 		tsd->db_busy.delays = db_delay_table;
414 		tsd->db_busy.delay_size = sizeof (db_delay_table) /
415 		    sizeof (int);
416 		sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler,
417 		    &tsd->db_busy);
418 	}
419 	*db = tsd->db_db;
420 	return (IDMAP_SUCCESS);
421 }
422 
423 /*
424  * Get the cache handle
425  */
426 idmap_retcode
427 get_cache_handle(sqlite **cache)
428 {
429 	char		*errmsg;
430 	idmap_tsd_t	*tsd;
431 
432 	/*
433 	 * Retrieve the db handle from thread-specific storage
434 	 * If none exists, open and store in thread-specific storage.
435 	 */
436 	if ((tsd = idmap_get_tsd()) == NULL) {
437 		idmapdlog(LOG_ERR, "Error getting thread specific data for %s",
438 		    IDMAP_DBNAME);
439 		return (IDMAP_ERR_MEMORY);
440 	}
441 
442 	if (tsd->cache_db == NULL) {
443 		tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg);
444 		if (tsd->cache_db == NULL) {
445 			idmapdlog(LOG_ERR, "Error opening database %s (%s)",
446 			    IDMAP_CACHENAME, CHECK_NULL(errmsg));
447 			sqlite_freemem(errmsg);
448 			return (IDMAP_ERR_DB);
449 		}
450 
451 		tsd->cache_busy.name = IDMAP_CACHENAME;
452 		tsd->cache_busy.delays = cache_delay_table;
453 		tsd->cache_busy.delay_size = sizeof (cache_delay_table) /
454 		    sizeof (int);
455 		sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler,
456 		    &tsd->cache_busy);
457 	}
458 	*cache = tsd->cache_db;
459 	return (IDMAP_SUCCESS);
460 }
461 
462 /*
463  * Initialize cache and db
464  */
465 int
466 init_dbs()
467 {
468 	char *sql[4];
469 	int created, upgraded;
470 
471 	/* name-based mappings; probably OK to blow away in a pinch(?) */
472 	sql[0] = DB_INSTALL_SQL;
473 	sql[1] = DB_UPGRADE_FROM_v1_SQL;
474 	sql[2] = NULL;
475 
476 	if (init_db_instance(IDMAP_DBNAME, DB_VERSION, DB_VERSION_SQL, sql,
477 	    FAIL_IF_CORRUPT, &created, &upgraded) < 0)
478 		return (-1);
479 
480 	/* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
481 	sql[0] = CACHE_INSTALL_SQL;
482 	sql[1] = CACHE_UPGRADE_FROM_v1_SQL;
483 	sql[2] = CACHE_UPGRADE_FROM_v2_SQL;
484 	sql[3] = NULL;
485 
486 	if (init_db_instance(IDMAP_CACHENAME, CACHE_VERSION, CACHE_VERSION_SQL,
487 	    sql, REMOVE_IF_CORRUPT, &created, &upgraded) < 0)
488 		return (-1);
489 
490 	_idmapdstate.new_eph_db = (created || upgraded) ? 1 : 0;
491 
492 	return (0);
493 }
494 
495 /*
496  * Finalize databases
497  */
498 void
499 fini_dbs()
500 {
501 }
502 
503 /*
504  * This table is a listing of status codes that will be returned to the
505  * client when a SQL command fails with the corresponding error message.
506  */
507 static msg_table_t sqlmsgtable[] = {
508 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
509 	"columns unixname, is_user, u2w_order are not unique"},
510 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
511 	"columns winname, windomain, is_user, is_wuser, w2u_order are not"
512 	" unique"},
513 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT, "Conflicting w2u namerules"},
514 	{-1, NULL}
515 };
516 
517 /*
518  * idmapd's version of string2stat to map SQLite messages to
519  * status codes
520  */
521 idmap_retcode
522 idmapd_string2stat(const char *msg)
523 {
524 	int i;
525 	for (i = 0; sqlmsgtable[i].msg; i++) {
526 		if (strcasecmp(sqlmsgtable[i].msg, msg) == 0)
527 			return (sqlmsgtable[i].retcode);
528 	}
529 	return (IDMAP_ERR_OTHER);
530 }
531 
532 /*
533  * Executes some SQL in a transaction.
534  *
535  * Returns 0 on success, -1 if it failed but the rollback succeeded, -2
536  * if the rollback failed.
537  */
538 static
539 int
540 sql_exec_tran_no_cb(sqlite *db, char *sql, const char *dbname,
541 	const char *while_doing)
542 {
543 	char		*errmsg = NULL;
544 	int		rc;
545 
546 	rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &errmsg);
547 	if (rc != SQLITE_OK) {
548 		idmapdlog(LOG_ERR, "Begin transaction failed (%s) "
549 		    "while %s (%s)", errmsg, while_doing, dbname);
550 		sqlite_freemem(errmsg);
551 		return (-1);
552 	}
553 
554 	rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
555 	if (rc != SQLITE_OK) {
556 		idmapdlog(LOG_ERR, "Database error (%s) while %s (%s)", errmsg,
557 		    while_doing, dbname);
558 		sqlite_freemem(errmsg);
559 		errmsg = NULL;
560 		goto rollback;
561 	}
562 
563 	rc = sqlite_exec(db, "COMMIT TRANSACTION", NULL, NULL, &errmsg);
564 	if (rc == SQLITE_OK) {
565 		sqlite_freemem(errmsg);
566 		return (0);
567 	}
568 
569 	idmapdlog(LOG_ERR, "Database commit error (%s) while s (%s)",
570 	    errmsg, while_doing, dbname);
571 	sqlite_freemem(errmsg);
572 	errmsg = NULL;
573 
574 rollback:
575 	rc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, &errmsg);
576 	if (rc != SQLITE_OK) {
577 		idmapdlog(LOG_ERR, "Rollback failed (%s) while %s (%s)",
578 		    errmsg, while_doing, dbname);
579 		sqlite_freemem(errmsg);
580 		return (-2);
581 	}
582 	sqlite_freemem(errmsg);
583 
584 	return (-1);
585 }
586 
587 /*
588  * Execute the given SQL statment without using any callbacks
589  */
590 idmap_retcode
591 sql_exec_no_cb(sqlite *db, const char *dbname, char *sql)
592 {
593 	char		*errmsg = NULL;
594 	int		r;
595 	idmap_retcode	retcode;
596 
597 	r = sqlite_exec(db, sql, NULL, NULL, &errmsg);
598 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
599 
600 	if (r != SQLITE_OK) {
601 		idmapdlog(LOG_ERR, "Database error on %s while executing %s "
602 		    "(%s)", dbname, sql, CHECK_NULL(errmsg));
603 		retcode = idmapd_string2stat(errmsg);
604 		if (errmsg != NULL)
605 			sqlite_freemem(errmsg);
606 		return (retcode);
607 	}
608 
609 	return (IDMAP_SUCCESS);
610 }
611 
612 /*
613  * Generate expression that can be used in WHERE statements.
614  * Examples:
615  * <prefix> <col>      <op> <value>   <suffix>
616  * ""       "unixuser" "="  "foo" "AND"
617  */
618 idmap_retcode
619 gen_sql_expr_from_rule(idmap_namerule *rule, char **out)
620 {
621 	char	*s_windomain = NULL, *s_winname = NULL;
622 	char	*s_unixname = NULL;
623 	char	*lower_winname;
624 	int	retcode = IDMAP_SUCCESS;
625 
626 	if (out == NULL)
627 		return (IDMAP_ERR_ARG);
628 
629 
630 	if (!EMPTY_STRING(rule->windomain)) {
631 		s_windomain =  sqlite_mprintf("AND windomain = %Q ",
632 		    rule->windomain);
633 		if (s_windomain == NULL) {
634 			retcode = IDMAP_ERR_MEMORY;
635 			goto out;
636 		}
637 	}
638 
639 	if (!EMPTY_STRING(rule->winname)) {
640 		if ((lower_winname = tolower_u8(rule->winname)) == NULL)
641 			lower_winname = rule->winname;
642 		s_winname = sqlite_mprintf(
643 		    "AND winname = %Q AND is_wuser = %d ",
644 		    lower_winname, rule->is_wuser ? 1 : 0);
645 		if (lower_winname != rule->winname)
646 			free(lower_winname);
647 		if (s_winname == NULL) {
648 			retcode = IDMAP_ERR_MEMORY;
649 			goto out;
650 		}
651 	}
652 
653 	if (!EMPTY_STRING(rule->unixname)) {
654 		s_unixname = sqlite_mprintf(
655 		    "AND unixname = %Q AND is_user = %d ",
656 		    rule->unixname, rule->is_user ? 1 : 0);
657 		if (s_unixname == NULL) {
658 			retcode = IDMAP_ERR_MEMORY;
659 			goto out;
660 		}
661 	}
662 
663 	*out = sqlite_mprintf("%s %s %s",
664 	    s_windomain ? s_windomain : "",
665 	    s_winname ? s_winname : "",
666 	    s_unixname ? s_unixname : "");
667 
668 	if (*out == NULL) {
669 		retcode = IDMAP_ERR_MEMORY;
670 		idmapdlog(LOG_ERR, "Out of memory");
671 		goto out;
672 	}
673 
674 out:
675 	if (s_windomain != NULL)
676 		sqlite_freemem(s_windomain);
677 	if (s_winname != NULL)
678 		sqlite_freemem(s_winname);
679 	if (s_unixname != NULL)
680 		sqlite_freemem(s_unixname);
681 
682 	return (retcode);
683 }
684 
685 
686 
687 /*
688  * Generate and execute SQL statement for LIST RPC calls
689  */
690 idmap_retcode
691 process_list_svc_sql(sqlite *db, const char *dbname, char *sql, uint64_t limit,
692 		int flag, list_svc_cb cb, void *result)
693 {
694 	list_cb_data_t	cb_data;
695 	char		*errmsg = NULL;
696 	int		r;
697 	idmap_retcode	retcode = IDMAP_ERR_INTERNAL;
698 
699 	(void) memset(&cb_data, 0, sizeof (cb_data));
700 	cb_data.result = result;
701 	cb_data.limit = limit;
702 	cb_data.flag = flag;
703 
704 
705 	r = sqlite_exec(db, sql, cb, &cb_data, &errmsg);
706 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
707 	switch (r) {
708 	case SQLITE_OK:
709 		retcode = IDMAP_SUCCESS;
710 		break;
711 
712 	default:
713 		retcode = IDMAP_ERR_INTERNAL;
714 		idmapdlog(LOG_ERR, "Database error on %s while executing "
715 		    "%s (%s)", dbname, sql, CHECK_NULL(errmsg));
716 		break;
717 	}
718 	if (errmsg != NULL)
719 		sqlite_freemem(errmsg);
720 	return (retcode);
721 }
722 
723 /*
724  * This routine is called by callbacks that process the results of
725  * LIST RPC calls to validate data and to allocate memory for
726  * the result array.
727  */
728 idmap_retcode
729 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv,
730 		int ncol, uchar_t **list, size_t valsize)
731 {
732 	size_t	nsize;
733 	void	*tmplist;
734 
735 	if (cb_data->limit > 0 && cb_data->next == cb_data->limit)
736 		return (IDMAP_NEXT);
737 
738 	if (argc < ncol || argv == NULL) {
739 		idmapdlog(LOG_ERR, "Invalid data");
740 		return (IDMAP_ERR_INTERNAL);
741 	}
742 
743 	/* alloc in bulk to reduce number of reallocs */
744 	if (cb_data->next >= cb_data->len) {
745 		nsize = (cb_data->len + SIZE_INCR) * valsize;
746 		tmplist = realloc(*list, nsize);
747 		if (tmplist == NULL) {
748 			idmapdlog(LOG_ERR, "Out of memory");
749 			return (IDMAP_ERR_MEMORY);
750 		}
751 		*list = tmplist;
752 		(void) memset(*list + (cb_data->len * valsize), 0,
753 		    SIZE_INCR * valsize);
754 		cb_data->len += SIZE_INCR;
755 	}
756 	return (IDMAP_SUCCESS);
757 }
758 
759 static
760 idmap_retcode
761 get_namerule_order(char *winname, char *windomain, char *unixname,
762 	int direction, int is_diagonal, int *w2u_order, int *u2w_order)
763 {
764 	*w2u_order = 0;
765 	*u2w_order = 0;
766 
767 	/*
768 	 * Windows to UNIX lookup order:
769 	 *  1. winname@domain (or winname) to ""
770 	 *  2. winname@domain (or winname) to unixname
771 	 *  3. winname@* to ""
772 	 *  4. winname@* to unixname
773 	 *  5. *@domain (or *) to *
774 	 *  6. *@domain (or *) to ""
775 	 *  7. *@domain (or *) to unixname
776 	 *  8. *@* to *
777 	 *  9. *@* to ""
778 	 * 10. *@* to unixname
779 	 *
780 	 * winname is a special case of winname@domain when domain is the
781 	 * default domain. Similarly * is a special case of *@domain when
782 	 * domain is the default domain.
783 	 *
784 	 * Note that "" has priority over specific names because "" inhibits
785 	 * mappings and traditionally deny rules always had higher priority.
786 	 */
787 	if (direction != IDMAP_DIRECTION_U2W) {
788 		/* bi-directional or from windows to unix */
789 		if (winname == NULL)
790 			return (IDMAP_ERR_W2U_NAMERULE);
791 		else if (unixname == NULL)
792 			return (IDMAP_ERR_W2U_NAMERULE);
793 		else if (EMPTY_NAME(winname))
794 			return (IDMAP_ERR_W2U_NAMERULE);
795 		else if (*winname == '*' && windomain && *windomain == '*') {
796 			if (*unixname == '*')
797 				*w2u_order = 8;
798 			else if (EMPTY_NAME(unixname))
799 				*w2u_order = 9;
800 			else /* unixname == name */
801 				*w2u_order = 10;
802 		} else if (*winname == '*') {
803 			if (*unixname == '*')
804 				*w2u_order = 5;
805 			else if (EMPTY_NAME(unixname))
806 				*w2u_order = 6;
807 			else /* name */
808 				*w2u_order = 7;
809 		} else if (windomain != NULL && *windomain == '*') {
810 			/* winname == name */
811 			if (*unixname == '*')
812 				return (IDMAP_ERR_W2U_NAMERULE);
813 			else if (EMPTY_NAME(unixname))
814 				*w2u_order = 3;
815 			else /* name */
816 				*w2u_order = 4;
817 		} else  {
818 			/* winname == name && windomain == null or name */
819 			if (*unixname == '*')
820 				return (IDMAP_ERR_W2U_NAMERULE);
821 			else if (EMPTY_NAME(unixname))
822 				*w2u_order = 1;
823 			else /* name */
824 				*w2u_order = 2;
825 		}
826 
827 	}
828 
829 	/*
830 	 * 1. unixname to "", non-diagonal
831 	 * 2. unixname to winname@domain (or winname), non-diagonal
832 	 * 3. unixname to "", diagonal
833 	 * 4. unixname to winname@domain (or winname), diagonal
834 	 * 5. * to *@domain (or *), non-diagonal
835 	 * 5. * to *@domain (or *), diagonal
836 	 * 7. * to ""
837 	 * 8. * to winname@domain (or winname)
838 	 * 9. * to "", non-diagonal
839 	 * 10. * to winname@domain (or winname), diagonal
840 	 */
841 	if (direction != IDMAP_DIRECTION_W2U) {
842 		int diagonal = is_diagonal ? 1 : 0;
843 
844 		/* bi-directional or from unix to windows */
845 		if (unixname == NULL || EMPTY_NAME(unixname))
846 			return (IDMAP_ERR_U2W_NAMERULE);
847 		else if (winname == NULL)
848 			return (IDMAP_ERR_U2W_NAMERULE);
849 		else if (windomain != NULL && *windomain == '*')
850 			return (IDMAP_ERR_U2W_NAMERULE);
851 		else if (*unixname == '*') {
852 			if (*winname == '*')
853 				*u2w_order = 5 + diagonal;
854 			else if (EMPTY_NAME(winname))
855 				*u2w_order = 7 + 2 * diagonal;
856 			else
857 				*u2w_order = 8 + 2 * diagonal;
858 		} else {
859 			if (*winname == '*')
860 				return (IDMAP_ERR_U2W_NAMERULE);
861 			else if (EMPTY_NAME(winname))
862 				*u2w_order = 1 + 2 * diagonal;
863 			else
864 				*u2w_order = 2 + 2 * diagonal;
865 		}
866 	}
867 	return (IDMAP_SUCCESS);
868 }
869 
870 /*
871  * Generate and execute SQL statement to add name-based mapping rule
872  */
873 idmap_retcode
874 add_namerule(sqlite *db, idmap_namerule *rule)
875 {
876 	char		*sql = NULL;
877 	idmap_stat	retcode;
878 	char		*dom = NULL;
879 	char		*name;
880 	int		w2u_order, u2w_order;
881 	char		w2ubuf[11], u2wbuf[11];
882 	char		*canonname = NULL;
883 	char		*canondomain = NULL;
884 
885 	retcode = get_namerule_order(rule->winname, rule->windomain,
886 	    rule->unixname, rule->direction,
887 	    rule->is_user == rule->is_wuser ? 0 : 1, &w2u_order, &u2w_order);
888 	if (retcode != IDMAP_SUCCESS)
889 		goto out;
890 
891 	if (w2u_order)
892 		(void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order);
893 	if (u2w_order)
894 		(void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order);
895 
896 	/*
897 	 * For the triggers on namerules table to work correctly:
898 	 * 1) Use NULL instead of 0 for w2u_order and u2w_order
899 	 * 2) Use "" instead of NULL for "no domain"
900 	 */
901 
902 	name = rule->winname;
903 	dom = rule->windomain;
904 
905 	RDLOCK_CONFIG();
906 	if (lookup_wksids_name2sid(name, dom,
907 	    &canonname, &canondomain,
908 	    NULL, NULL, NULL) == IDMAP_SUCCESS) {
909 		name = canonname;
910 		dom = canondomain;
911 	} else if (EMPTY_STRING(dom)) {
912 		if (_idmapdstate.cfg->pgcfg.default_domain)
913 			dom = _idmapdstate.cfg->pgcfg.default_domain;
914 		else
915 			dom = "";
916 	}
917 	sql = sqlite_mprintf("INSERT into namerules "
918 	    "(is_user, is_wuser, windomain, winname_display, is_nt4, "
919 	    "unixname, w2u_order, u2w_order) "
920 	    "VALUES(%d, %d, %Q, %Q, %d, %Q, %q, %q);",
921 	    rule->is_user ? 1 : 0, rule->is_wuser ? 1 : 0, dom,
922 	    name, rule->is_nt4 ? 1 : 0, rule->unixname,
923 	    w2u_order ? w2ubuf : NULL, u2w_order ? u2wbuf : NULL);
924 	UNLOCK_CONFIG();
925 
926 	if (sql == NULL) {
927 		retcode = IDMAP_ERR_INTERNAL;
928 		idmapdlog(LOG_ERR, "Out of memory");
929 		goto out;
930 	}
931 
932 	retcode = sql_exec_no_cb(db, IDMAP_DBNAME, sql);
933 
934 	if (retcode == IDMAP_ERR_OTHER)
935 		retcode = IDMAP_ERR_CFG;
936 
937 out:
938 	free(canonname);
939 	free(canondomain);
940 	if (sql != NULL)
941 		sqlite_freemem(sql);
942 	return (retcode);
943 }
944 
945 /*
946  * Flush name-based mapping rules
947  */
948 idmap_retcode
949 flush_namerules(sqlite *db)
950 {
951 	idmap_stat	retcode;
952 
953 	retcode = sql_exec_no_cb(db, IDMAP_DBNAME, "DELETE FROM namerules;");
954 
955 	return (retcode);
956 }
957 
958 /*
959  * Generate and execute SQL statement to remove a name-based mapping rule
960  */
961 idmap_retcode
962 rm_namerule(sqlite *db, idmap_namerule *rule)
963 {
964 	char		*sql = NULL;
965 	idmap_stat	retcode;
966 	char		buf[80];
967 	char		*expr = NULL;
968 
969 	if (rule->direction < 0 && EMPTY_STRING(rule->windomain) &&
970 	    EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
971 		return (IDMAP_SUCCESS);
972 
973 	buf[0] = 0;
974 
975 	if (rule->direction == IDMAP_DIRECTION_BI)
976 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
977 		    " AND u2w_order > 0");
978 	else if (rule->direction == IDMAP_DIRECTION_W2U)
979 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
980 		    " AND (u2w_order = 0 OR u2w_order ISNULL)");
981 	else if (rule->direction == IDMAP_DIRECTION_U2W)
982 		(void) snprintf(buf, sizeof (buf), "AND u2w_order > 0"
983 		    " AND (w2u_order = 0 OR w2u_order ISNULL)");
984 
985 	retcode = gen_sql_expr_from_rule(rule, &expr);
986 	if (retcode != IDMAP_SUCCESS)
987 		goto out;
988 
989 	sql = sqlite_mprintf("DELETE FROM namerules WHERE 1 %s %s;", expr,
990 	    buf);
991 
992 	if (sql == NULL) {
993 		retcode = IDMAP_ERR_INTERNAL;
994 		idmapdlog(LOG_ERR, "Out of memory");
995 		goto out;
996 	}
997 
998 
999 	retcode = sql_exec_no_cb(db, IDMAP_DBNAME, sql);
1000 
1001 out:
1002 	if (expr != NULL)
1003 		sqlite_freemem(expr);
1004 	if (sql != NULL)
1005 		sqlite_freemem(sql);
1006 	return (retcode);
1007 }
1008 
1009 /*
1010  * Compile the given SQL query and step just once.
1011  *
1012  * Input:
1013  * db  - db handle
1014  * sql - SQL statement
1015  *
1016  * Output:
1017  * vm     -  virtual SQL machine
1018  * ncol   - number of columns in the result
1019  * values - column values
1020  *
1021  * Return values:
1022  * IDMAP_SUCCESS
1023  * IDMAP_ERR_NOTFOUND
1024  * IDMAP_ERR_INTERNAL
1025  */
1026 
1027 static
1028 idmap_retcode
1029 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
1030 		int reqcol, const char ***values)
1031 {
1032 	char		*errmsg = NULL;
1033 	int		r;
1034 
1035 	if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) {
1036 		idmapdlog(LOG_ERR, "Database error during %s (%s)", sql,
1037 		    CHECK_NULL(errmsg));
1038 		sqlite_freemem(errmsg);
1039 		return (IDMAP_ERR_INTERNAL);
1040 	}
1041 
1042 	r = sqlite_step(*vm, ncol, values, NULL);
1043 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
1044 
1045 	if (r == SQLITE_ROW) {
1046 		if (ncol != NULL && *ncol < reqcol) {
1047 			(void) sqlite_finalize(*vm, NULL);
1048 			*vm = NULL;
1049 			return (IDMAP_ERR_INTERNAL);
1050 		}
1051 		/* Caller will call finalize after using the results */
1052 		return (IDMAP_SUCCESS);
1053 	} else if (r == SQLITE_DONE) {
1054 		(void) sqlite_finalize(*vm, NULL);
1055 		*vm = NULL;
1056 		return (IDMAP_ERR_NOTFOUND);
1057 	}
1058 
1059 	(void) sqlite_finalize(*vm, &errmsg);
1060 	*vm = NULL;
1061 	idmapdlog(LOG_ERR, "Database error during %s (%s)", sql,
1062 	    CHECK_NULL(errmsg));
1063 	sqlite_freemem(errmsg);
1064 	return (IDMAP_ERR_INTERNAL);
1065 }
1066 
1067 /*
1068  * Load config in the state.
1069  *
1070  * nm_siduid and nm_sidgid fields:
1071  * state->nm_siduid represents mode used by sid2uid and uid2sid
1072  * requests for directory-based name mappings. Similarly,
1073  * state->nm_sidgid represents mode used by sid2gid and gid2sid
1074  * requests.
1075  *
1076  * sid2uid/uid2sid:
1077  * none       -> ds_name_mapping_enabled != true
1078  * AD-mode    -> !nldap_winname_attr && ad_unixuser_attr
1079  * nldap-mode -> nldap_winname_attr && !ad_unixuser_attr
1080  * mixed-mode -> nldap_winname_attr && ad_unixuser_attr
1081  *
1082  * sid2gid/gid2sid:
1083  * none       -> ds_name_mapping_enabled != true
1084  * AD-mode    -> !nldap_winname_attr && ad_unixgroup_attr
1085  * nldap-mode -> nldap_winname_attr && !ad_unixgroup_attr
1086  * mixed-mode -> nldap_winname_attr && ad_unixgroup_attr
1087  */
1088 idmap_retcode
1089 load_cfg_in_state(lookup_state_t *state)
1090 {
1091 	state->nm_siduid = IDMAP_NM_NONE;
1092 	state->nm_sidgid = IDMAP_NM_NONE;
1093 	RDLOCK_CONFIG();
1094 
1095 	state->eph_map_unres_sids = 0;
1096 	if (_idmapdstate.cfg->pgcfg.eph_map_unres_sids)
1097 		state->eph_map_unres_sids = 1;
1098 
1099 	if (_idmapdstate.cfg->pgcfg.default_domain != NULL) {
1100 		state->defdom =
1101 		    strdup(_idmapdstate.cfg->pgcfg.default_domain);
1102 		if (state->defdom == NULL) {
1103 			UNLOCK_CONFIG();
1104 			return (IDMAP_ERR_MEMORY);
1105 		}
1106 	} else {
1107 		UNLOCK_CONFIG();
1108 		return (IDMAP_SUCCESS);
1109 	}
1110 	if (!_idmapdstate.cfg->pgcfg.ds_name_mapping_enabled) {
1111 		UNLOCK_CONFIG();
1112 		return (IDMAP_SUCCESS);
1113 	}
1114 	if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) {
1115 		state->nm_siduid =
1116 		    (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL)
1117 		    ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP;
1118 		state->nm_sidgid =
1119 		    (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL)
1120 		    ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP;
1121 	} else {
1122 		state->nm_siduid =
1123 		    (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL)
1124 		    ? IDMAP_NM_AD : IDMAP_NM_NONE;
1125 		state->nm_sidgid =
1126 		    (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL)
1127 		    ? IDMAP_NM_AD : IDMAP_NM_NONE;
1128 	}
1129 	if (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) {
1130 		state->ad_unixuser_attr =
1131 		    strdup(_idmapdstate.cfg->pgcfg.ad_unixuser_attr);
1132 		if (state->ad_unixuser_attr == NULL) {
1133 			UNLOCK_CONFIG();
1134 			return (IDMAP_ERR_MEMORY);
1135 		}
1136 	}
1137 	if (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) {
1138 		state->ad_unixgroup_attr =
1139 		    strdup(_idmapdstate.cfg->pgcfg.ad_unixgroup_attr);
1140 		if (state->ad_unixgroup_attr == NULL) {
1141 			UNLOCK_CONFIG();
1142 			return (IDMAP_ERR_MEMORY);
1143 		}
1144 	}
1145 	if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) {
1146 		state->nldap_winname_attr =
1147 		    strdup(_idmapdstate.cfg->pgcfg.nldap_winname_attr);
1148 		if (state->nldap_winname_attr == NULL) {
1149 			UNLOCK_CONFIG();
1150 			return (IDMAP_ERR_MEMORY);
1151 		}
1152 	}
1153 	UNLOCK_CONFIG();
1154 	return (IDMAP_SUCCESS);
1155 }
1156 
1157 /*
1158  * Set the rule with specified values.
1159  * All the strings are copied.
1160  */
1161 static void
1162 idmap_namerule_set(idmap_namerule *rule, const char *windomain,
1163 		const char *winname, const char *unixname, boolean_t is_user,
1164 		boolean_t is_wuser, boolean_t is_nt4, int direction)
1165 {
1166 	/*
1167 	 * Only update if they differ because we have to free
1168 	 * and duplicate the strings
1169 	 */
1170 	if (rule->windomain == NULL || windomain == NULL ||
1171 	    strcmp(rule->windomain, windomain) != 0) {
1172 		if (rule->windomain != NULL) {
1173 			free(rule->windomain);
1174 			rule->windomain = NULL;
1175 		}
1176 		if (windomain != NULL)
1177 			rule->windomain = strdup(windomain);
1178 	}
1179 
1180 	if (rule->winname == NULL || winname == NULL ||
1181 	    strcmp(rule->winname, winname) != 0) {
1182 		if (rule->winname != NULL) {
1183 			free(rule->winname);
1184 			rule->winname = NULL;
1185 		}
1186 		if (winname != NULL)
1187 			rule->winname = strdup(winname);
1188 	}
1189 
1190 	if (rule->unixname == NULL || unixname == NULL ||
1191 	    strcmp(rule->unixname, unixname) != 0) {
1192 		if (rule->unixname != NULL) {
1193 			free(rule->unixname);
1194 			rule->unixname = NULL;
1195 		}
1196 		if (unixname != NULL)
1197 			rule->unixname = strdup(unixname);
1198 	}
1199 
1200 	rule->is_user = is_user;
1201 	rule->is_wuser = is_wuser;
1202 	rule->is_nt4 = is_nt4;
1203 	rule->direction = direction;
1204 }
1205 
1206 
1207 /*
1208  * Table for well-known SIDs.
1209  *
1210  * Background:
1211  *
1212  * Some of the well-known principals are stored under:
1213  * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
1214  * They belong to objectClass "foreignSecurityPrincipal". They don't have
1215  * "samAccountName" nor "userPrincipalName" attributes. Their names are
1216  * available in "cn" and "name" attributes. Some of these principals have a
1217  * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
1218  * these duplicate entries have the stringified SID in the "name" and "cn"
1219  * attributes instead of the actual name.
1220  *
1221  * Those of the form S-1-5-32-X are Builtin groups and are stored in the
1222  * cn=builtin container (except, Power Users which is not stored in AD)
1223  *
1224  * These principals are and will remain constant. Therefore doing AD lookups
1225  * provides no benefit. Also, using hard-coded table (and thus avoiding AD
1226  * lookup) improves performance and avoids additional complexity in the
1227  * adutils.c code. Moreover these SIDs can be used when no Active Directory
1228  * is available (such as the CIFS server's "workgroup" mode).
1229  *
1230  * Notes:
1231  * 1. Currently we don't support localization of well-known SID names,
1232  * unlike Windows.
1233  *
1234  * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored
1235  * here. AD does have normal user/group objects for these objects and
1236  * can be looked up using the existing AD lookup code.
1237  *
1238  * 3. See comments above lookup_wksids_sid2pid() for more information
1239  * on how we lookup the wksids table.
1240  *
1241  * 4. If this table contains two entries for a particular Windows name,
1242  * so as to offer both UID and GID mappings, the preferred mapping (the
1243  * one that matches Windows usage) must be listed first.  That is the
1244  * entry that will be used when the caller specifies IDMAP_POSIXID
1245  * ("don't care") as the target.
1246  *
1247  * Entries here come from KB243330, MS-LSAT, and
1248  * http://technet.microsoft.com/en-us/library/cc755854.aspx
1249  * http://technet.microsoft.com/en-us/library/cc755925.aspx
1250  * http://msdn.microsoft.com/en-us/library/cc980032(PROT.10).aspx
1251  */
1252 static wksids_table_t wksids[] = {
1253 	/* S-1-0	Null Authority */
1254 	{"S-1-0", 0, "", "Nobody", 1, SENTINEL_PID, -1, 1},
1255 
1256 	/* S-1-1	World Authority */
1257 	{"S-1-1", 0, "", "Everyone", 0, SENTINEL_PID, -1, -1},
1258 
1259 	/* S-1-2	Local Authority */
1260 	{"S-1-2", 0, "", "Local", 0, SENTINEL_PID, -1, -1},
1261 	{"S-1-2", 1, "", "Console Logon", 0, SENTINEL_PID, -1, -1},
1262 
1263 	/* S-1-3	Creator Authority */
1264 	{"S-1-3", 0, "", "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0},
1265 	{"S-1-3", 1, "", "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0},
1266 	{"S-1-3", 2, "", "Creator Owner Server", 1, SENTINEL_PID, -1, -1},
1267 	{"S-1-3", 3, "", "Creator Group Server", 0, SENTINEL_PID, -1, 1},
1268 	{"S-1-3", 4, "", "Owner Rights", 0, SENTINEL_PID, -1, -1},
1269 
1270 	/* S-1-4	Non-unique Authority */
1271 
1272 	/* S-1-5	NT Authority */
1273 	{"S-1-5", 1, "", "Dialup", 0, SENTINEL_PID, -1, -1},
1274 	{"S-1-5", 2, "", "Network", 0, SENTINEL_PID, -1, -1},
1275 	{"S-1-5", 3, "", "Batch", 0, SENTINEL_PID, -1, -1},
1276 	{"S-1-5", 4, "", "Interactive", 0, SENTINEL_PID, -1, -1},
1277 	/* S-1-5-5-X-Y	Logon Session */
1278 	{"S-1-5", 6, "", "Service", 0, SENTINEL_PID, -1, -1},
1279 	{"S-1-5", 7, "", "Anonymous Logon", 0, GID_NOBODY, 0, 0},
1280 	{"S-1-5", 7, "", "Anonymous Logon", 0, UID_NOBODY, 1, 0},
1281 	{"S-1-5", 8, "", "Proxy", 0, SENTINEL_PID, -1, -1},
1282 	{"S-1-5", 9, "", "Enterprise Domain Controllers", 0,
1283 	    SENTINEL_PID, -1, -1},
1284 	{"S-1-5", 10, "", "Self", 0, SENTINEL_PID, -1, -1},
1285 	{"S-1-5", 11, "", "Authenticated Users", 0, SENTINEL_PID, -1, -1},
1286 	{"S-1-5", 12, "", "Restricted", 0, SENTINEL_PID, -1, -1},
1287 	{"S-1-5", 13, "", "Terminal Server Users", 0, SENTINEL_PID, -1, -1},
1288 	{"S-1-5", 14, "", "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1},
1289 	{"S-1-5", 15, "", "This Organization", 0, SENTINEL_PID, -1, -1},
1290 	{"S-1-5", 17, "", "IUSR", 0, SENTINEL_PID, -1, -1},
1291 	{"S-1-5", 18, "", "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0},
1292 	{"S-1-5", 19, "", "Local Service", 0, SENTINEL_PID, -1, -1},
1293 	{"S-1-5", 20, "", "Network Service", 0, SENTINEL_PID, -1, -1},
1294 
1295 	/* S-1-5-21-<domain>	Machine-local definitions */
1296 	{NULL, 498, NULL, "Enterprise Read-only Domain Controllers", 0,
1297 	    SENTINEL_PID, -1, -1},
1298 	{NULL, 500, NULL, "Administrator", 1, SENTINEL_PID, 1, -1},
1299 	{NULL, 501, NULL, "Guest", 1, SENTINEL_PID, 1, -1},
1300 	{NULL, 502, NULL, "KRBTGT", 1, SENTINEL_PID, 1, -1},
1301 	{NULL, 512, NULL, "Domain Admins", 0, SENTINEL_PID, -1, -1},
1302 	{NULL, 513, NULL, "Domain Users", 0, SENTINEL_PID, -1, -1},
1303 	{NULL, 514, NULL, "Domain Guests", 0, SENTINEL_PID, -1, -1},
1304 	{NULL, 515, NULL, "Domain Computers", 0, SENTINEL_PID, -1, -1},
1305 	{NULL, 516, NULL, "Domain Controllers", 0, SENTINEL_PID, -1, -1},
1306 	{NULL, 517, NULL, "Cert Publishers", 0, SENTINEL_PID, -1, -1},
1307 	{NULL, 518, NULL, "Schema Admins", 0, SENTINEL_PID, -1, -1},
1308 	{NULL, 519, NULL, "Enterprise Admins", 0, SENTINEL_PID, -1, -1},
1309 	{NULL, 520, NULL, "Global Policy Creator Owners", 0,
1310 	    SENTINEL_PID, -1, -1},
1311 	{NULL, 533, NULL, "RAS and IAS Servers", 0, SENTINEL_PID, -1, -1},
1312 
1313 	/* S-1-5-32	BUILTIN */
1314 	{"S-1-5-32", 544, "BUILTIN", "Administrators", 0, SENTINEL_PID, -1, -1},
1315 	{"S-1-5-32", 545, "BUILTIN", "Users", 0, SENTINEL_PID, -1, -1},
1316 	{"S-1-5-32", 546, "BUILTIN", "Guests", 0, SENTINEL_PID, -1, -1},
1317 	{"S-1-5-32", 547, "BUILTIN", "Power Users", 0, SENTINEL_PID, -1, -1},
1318 	{"S-1-5-32", 548, "BUILTIN", "Account Operators", 0,
1319 	    SENTINEL_PID, -1, -1},
1320 	{"S-1-5-32", 549, "BUILTIN", "Server Operators", 0,
1321 	    SENTINEL_PID, -1, -1},
1322 	{"S-1-5-32", 550, "BUILTIN", "Print Operators", 0,
1323 	    SENTINEL_PID, -1, -1},
1324 	{"S-1-5-32", 551, "BUILTIN", "Backup Operators", 0,
1325 	    SENTINEL_PID, -1, -1},
1326 	{"S-1-5-32", 552, "BUILTIN", "Replicator", 0, SENTINEL_PID, -1, -1},
1327 	{"S-1-5-32", 554, "BUILTIN", "Pre-Windows 2000 Compatible Access", 0,
1328 	    SENTINEL_PID, -1, -1},
1329 	{"S-1-5-32", 555, "BUILTIN", "Remote Desktop Users", 0,
1330 	    SENTINEL_PID, -1, -1},
1331 	{"S-1-5-32", 556, "BUILTIN", "Network Configuration Operators", 0,
1332 	    SENTINEL_PID, -1, -1},
1333 	{"S-1-5-32", 557, "BUILTIN", "Incoming Forest Trust Builders", 0,
1334 	    SENTINEL_PID, -1, -1},
1335 	{"S-1-5-32", 558, "BUILTIN", "Performance Monitor Users", 0,
1336 	    SENTINEL_PID, -1, -1},
1337 	{"S-1-5-32", 559, "BUILTIN", "Performance Log Users", 0,
1338 	    SENTINEL_PID, -1, -1},
1339 	{"S-1-5-32", 560, "BUILTIN", "Windows Authorization Access Group", 0,
1340 	    SENTINEL_PID, -1, -1},
1341 	{"S-1-5-32", 561, "BUILTIN", "Terminal Server License Servers", 0,
1342 	    SENTINEL_PID, -1, -1},
1343 	{"S-1-5-32", 562, "BUILTIN", "Distributed COM Users", 0,
1344 	    SENTINEL_PID, -1, -1},
1345 	{"S-1-5-32", 568, "BUILTIN", "IIS_IUSRS", 0, SENTINEL_PID, -1, -1},
1346 	{"S-1-5-32", 569, "BUILTIN", "Cryptographic Operators", 0,
1347 	    SENTINEL_PID, -1, -1},
1348 	{"S-1-5-32", 573, "BUILTIN", "Event Log Readers", 0,
1349 	    SENTINEL_PID, -1, -1},
1350 	{"S-1-5-32", 574, "BUILTIN", "Certificate Service DCOM Access", 0,
1351 	    SENTINEL_PID, -1, -1},
1352 
1353 	{"S-1-5", 33, "", "Write Restricted", 0, SENTINEL_PID, -1, -1},
1354 
1355 	/* S-1-5-64	NT Authority */
1356 	{"S-1-5-64", 10, "", "NTLM Authentication", 0, SENTINEL_PID, -1, -1},
1357 	{"S-1-5-64", 14, "", "SChannel Authentication", 0,
1358 	    SENTINEL_PID, -1, -1},
1359 	{"S-1-5-64", 21, "", "Digest Authentication", 0, SENTINEL_PID, -1, -1},
1360 
1361 	/* S-1-5-80-a-b-c-d NT Service */
1362 
1363 	{"S-1-5", 1000, "", "Other Organization", 0, SENTINEL_PID, -1, -1},
1364 
1365 	/* S-1-7 Internet$ */
1366 
1367 	/*
1368 	 * S-1-16	Mandatory Label
1369 	 * S-1-16-0	Untrusted Mandatory Level
1370 	 * S-1-16-4096	Low Mandatory Level
1371 	 * S-1-16-8192	Medium Mandatory Level
1372 	 * S-1-16-8448	Medium Plus Mandatory Level
1373 	 * S-1-16-12288	High Mandatory Level
1374 	 * S-1-16-16384	System Mandatory Level
1375 	 * S-1-16-20480	Protected Process Mandatory Level
1376 	 */
1377 };
1378 
1379 /*
1380  * Lookup well-known SIDs table either by winname or by SID.
1381  *
1382  * If the given winname or SID is a well-known SID then we set is_wksid
1383  * variable and then proceed to see if the SID has a hard mapping to
1384  * a particular UID/GID (Ex: Creator Owner/Creator Group mapped to
1385  * fixed ephemeral ids). The direction flag indicates whether we have
1386  * a mapping; UNDEF indicates that we do not.
1387  *
1388  * If we find a mapping then we return success, except for the
1389  * special case of SENTINEL_PID which indicates an inhibited mapping.
1390  *
1391  * If we find a matching entry, but no mapping, we supply SID, name, and type
1392  * information and return "not found".  Higher layers will probably
1393  * do ephemeral mapping.
1394  *
1395  * If we do not find a match, we return "not found" and leave the question
1396  * to higher layers.
1397  */
1398 static
1399 idmap_retcode
1400 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res, int *is_wksid)
1401 {
1402 	const wksids_table_t *wksid;
1403 
1404 	*is_wksid = 0;
1405 
1406 	assert(req->id1.idmap_id_u.sid.prefix != NULL ||
1407 	    req->id1name != NULL);
1408 
1409 	if (req->id1.idmap_id_u.sid.prefix != NULL) {
1410 		wksid = find_wksid_by_sid(req->id1.idmap_id_u.sid.prefix,
1411 		    req->id1.idmap_id_u.sid.rid, res->id.idtype);
1412 	} else {
1413 		wksid = find_wksid_by_name(req->id1name, req->id1domain,
1414 		    res->id.idtype);
1415 	}
1416 	if (wksid == NULL)
1417 		return (IDMAP_ERR_NOTFOUND);
1418 
1419 	/* Found matching entry. */
1420 
1421 	/* Fill in name if it was not already there. */
1422 	if (req->id1name == NULL) {
1423 		req->id1name = strdup(wksid->winname);
1424 		if (req->id1name == NULL)
1425 			return (IDMAP_ERR_MEMORY);
1426 	}
1427 
1428 	/* Fill in SID if it was not already there */
1429 	if (req->id1.idmap_id_u.sid.prefix == NULL) {
1430 		if (wksid->sidprefix != NULL) {
1431 			req->id1.idmap_id_u.sid.prefix =
1432 			    strdup(wksid->sidprefix);
1433 		} else {
1434 			RDLOCK_CONFIG();
1435 			req->id1.idmap_id_u.sid.prefix =
1436 			    strdup(_idmapdstate.cfg->pgcfg.machine_sid);
1437 			UNLOCK_CONFIG();
1438 		}
1439 		if (req->id1.idmap_id_u.sid.prefix == NULL)
1440 			return (IDMAP_ERR_MEMORY);
1441 		req->id1.idmap_id_u.sid.rid = wksid->rid;
1442 	}
1443 
1444 	/* Fill in the canonical domain if not already there */
1445 	if (req->id1domain == NULL) {
1446 		const char *dom;
1447 
1448 		RDLOCK_CONFIG();
1449 		if (wksid->domain != NULL) {
1450 			dom = wksid->domain;
1451 		} else {
1452 			dom = _idmapdstate.hostname;
1453 		}
1454 		req->id1domain = strdup(dom);
1455 		UNLOCK_CONFIG();
1456 		if (req->id1domain == NULL)
1457 			return (IDMAP_ERR_MEMORY);
1458 	}
1459 
1460 	*is_wksid = 1;
1461 	req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
1462 
1463 	req->id1.idtype = wksid->is_wuser ? IDMAP_USID : IDMAP_GSID;
1464 
1465 	if (res->id.idtype == IDMAP_POSIXID) {
1466 		res->id.idtype = wksid->is_wuser ? IDMAP_UID : IDMAP_GID;
1467 	}
1468 
1469 	if (wksid->direction == IDMAP_DIRECTION_UNDEF) {
1470 		/*
1471 		 * We don't have a mapping
1472 		 * (But note that we may have supplied SID, name, or type
1473 		 * information.)
1474 		 */
1475 		return (IDMAP_ERR_NOTFOUND);
1476 	}
1477 
1478 	/*
1479 	 * We have an explicit mapping.
1480 	 */
1481 	if (wksid->pid == SENTINEL_PID) {
1482 		/*
1483 		 * ... which is that mapping is inhibited.
1484 		 */
1485 		return (IDMAP_ERR_NOMAPPING);
1486 	}
1487 
1488 	switch (res->id.idtype) {
1489 	case IDMAP_UID:
1490 		res->id.idmap_id_u.uid = wksid->pid;
1491 		break;
1492 	case IDMAP_GID:
1493 		res->id.idmap_id_u.gid = wksid->pid;
1494 		break;
1495 	default:
1496 		/* IDMAP_POSIXID is eliminated above */
1497 		return (IDMAP_ERR_NOTSUPPORTED);
1498 	}
1499 
1500 	res->direction = wksid->direction;
1501 	res->info.how.map_type = IDMAP_MAP_TYPE_KNOWN_SID;
1502 	res->info.src = IDMAP_MAP_SRC_HARD_CODED;
1503 	return (IDMAP_SUCCESS);
1504 }
1505 
1506 
1507 /*
1508  * Look for an entry mapping a PID to a SID.
1509  *
1510  * Note that direction=UNDEF entries do not specify a mapping,
1511  * and that SENTINEL_PID entries represent either an inhibited
1512  * mapping or an ephemeral mapping.  We don't handle either here;
1513  * they are filtered out by find_wksid_by_pid.
1514  */
1515 static
1516 idmap_retcode
1517 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user)
1518 {
1519 	const wksids_table_t *wksid;
1520 
1521 	wksid = find_wksid_by_pid(req->id1.idmap_id_u.uid, is_user);
1522 	if (wksid == NULL)
1523 		return (IDMAP_ERR_NOTFOUND);
1524 
1525 	if (res->id.idtype == IDMAP_SID) {
1526 		res->id.idtype = wksid->is_wuser ? IDMAP_USID : IDMAP_GSID;
1527 	}
1528 	res->id.idmap_id_u.sid.rid = wksid->rid;
1529 
1530 	if (wksid->sidprefix != NULL) {
1531 		res->id.idmap_id_u.sid.prefix =
1532 		    strdup(wksid->sidprefix);
1533 	} else {
1534 		RDLOCK_CONFIG();
1535 		res->id.idmap_id_u.sid.prefix =
1536 		    strdup(_idmapdstate.cfg->pgcfg.machine_sid);
1537 		UNLOCK_CONFIG();
1538 	}
1539 
1540 	if (res->id.idmap_id_u.sid.prefix == NULL) {
1541 		idmapdlog(LOG_ERR, "Out of memory");
1542 		return (IDMAP_ERR_MEMORY);
1543 	}
1544 
1545 	res->direction = wksid->direction;
1546 	res->info.how.map_type = IDMAP_MAP_TYPE_KNOWN_SID;
1547 	res->info.src = IDMAP_MAP_SRC_HARD_CODED;
1548 	return (IDMAP_SUCCESS);
1549 }
1550 
1551 /*
1552  * Look up a name in the wksids list, matching name and, if supplied, domain,
1553  * and extract data.
1554  *
1555  * Given:
1556  * name		Windows user name
1557  * domain	Windows domain name (or NULL)
1558  *
1559  * Return:  Error code
1560  *
1561  * *canonname	canonical name (if canonname non-NULL) [1]
1562  * *canondomain	canonical domain (if canondomain non-NULL) [1]
1563  * *sidprefix	SID prefix (if sidprefix non-NULL) [1]
1564  * *rid		RID (if rid non-NULL) [2]
1565  * *type	Type (if type non-NULL) [2]
1566  *
1567  * [1] malloc'ed, NULL on error
1568  * [2] Undefined on error
1569  */
1570 idmap_retcode
1571 lookup_wksids_name2sid(
1572     const char *name,
1573     const char *domain,
1574     char **canonname,
1575     char **canondomain,
1576     char **sidprefix,
1577     idmap_rid_t *rid,
1578     int *type)
1579 {
1580 	const wksids_table_t *wksid;
1581 
1582 	if (sidprefix != NULL)
1583 		*sidprefix = NULL;
1584 	if (canonname != NULL)
1585 		*canonname = NULL;
1586 	if (canondomain != NULL)
1587 		*canondomain = NULL;
1588 
1589 	wksid = find_wksid_by_name(name, domain, IDMAP_POSIXID);
1590 	if (wksid == NULL)
1591 		return (IDMAP_ERR_NOTFOUND);
1592 
1593 	if (sidprefix != NULL) {
1594 		if (wksid->sidprefix != NULL) {
1595 			*sidprefix = strdup(wksid->sidprefix);
1596 		} else {
1597 			RDLOCK_CONFIG();
1598 			*sidprefix = strdup(
1599 			    _idmapdstate.cfg->pgcfg.machine_sid);
1600 			UNLOCK_CONFIG();
1601 		}
1602 		if (*sidprefix == NULL)
1603 			goto nomem;
1604 	}
1605 
1606 	if (rid != NULL)
1607 		*rid = wksid->rid;
1608 
1609 	if (canonname != NULL) {
1610 		*canonname = strdup(wksid->winname);
1611 		if (*canonname == NULL)
1612 			goto nomem;
1613 	}
1614 
1615 	if (canondomain != NULL) {
1616 		if (wksid->domain != NULL) {
1617 			*canondomain = strdup(wksid->domain);
1618 		} else {
1619 			RDLOCK_CONFIG();
1620 			*canondomain = strdup(_idmapdstate.hostname);
1621 			UNLOCK_CONFIG();
1622 		}
1623 		if (*canondomain == NULL)
1624 			goto nomem;
1625 	}
1626 
1627 	if (type != NULL)
1628 		*type = (wksid->is_wuser) ?
1629 		    _IDMAP_T_USER : _IDMAP_T_GROUP;
1630 
1631 	return (IDMAP_SUCCESS);
1632 
1633 nomem:
1634 	idmapdlog(LOG_ERR, "Out of memory");
1635 
1636 	if (sidprefix != NULL) {
1637 		free(*sidprefix);
1638 		*sidprefix = NULL;
1639 	}
1640 
1641 	if (canonname != NULL) {
1642 		free(*canonname);
1643 		*canonname = NULL;
1644 	}
1645 
1646 	if (canondomain != NULL) {
1647 		free(*canondomain);
1648 		*canondomain = NULL;
1649 	}
1650 
1651 	return (IDMAP_ERR_MEMORY);
1652 }
1653 
1654 static
1655 idmap_retcode
1656 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res)
1657 {
1658 	char		*end;
1659 	char		*sql = NULL;
1660 	const char	**values;
1661 	sqlite_vm	*vm = NULL;
1662 	int		ncol, is_user;
1663 	uid_t		pid;
1664 	time_t		curtime, exp;
1665 	idmap_retcode	retcode;
1666 	char		*is_user_string, *lower_name;
1667 
1668 	/* Current time */
1669 	errno = 0;
1670 	if ((curtime = time(NULL)) == (time_t)-1) {
1671 		idmapdlog(LOG_ERR, "Failed to get current time (%s)",
1672 		    strerror(errno));
1673 		retcode = IDMAP_ERR_INTERNAL;
1674 		goto out;
1675 	}
1676 
1677 	switch (res->id.idtype) {
1678 	case IDMAP_UID:
1679 		is_user_string = "1";
1680 		break;
1681 	case IDMAP_GID:
1682 		is_user_string = "0";
1683 		break;
1684 	case IDMAP_POSIXID:
1685 		/* the non-diagonal mapping */
1686 		is_user_string = "is_wuser";
1687 		break;
1688 	default:
1689 		retcode = IDMAP_ERR_NOTSUPPORTED;
1690 		goto out;
1691 	}
1692 
1693 	/* SQL to lookup the cache */
1694 
1695 	if (req->id1.idmap_id_u.sid.prefix != NULL) {
1696 		sql = sqlite_mprintf("SELECT pid, is_user, expiration, "
1697 		    "unixname, u2w, is_wuser, "
1698 		    "map_type, map_dn, map_attr, map_value, "
1699 		    "map_windomain, map_winname, map_unixname, map_is_nt4 "
1700 		    "FROM idmap_cache WHERE is_user = %s AND "
1701 		    "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
1702 		    "(pid >= 2147483648 OR "
1703 		    "(expiration = 0 OR expiration ISNULL OR "
1704 		    "expiration > %d));",
1705 		    is_user_string, req->id1.idmap_id_u.sid.prefix,
1706 		    req->id1.idmap_id_u.sid.rid, curtime);
1707 	} else if (req->id1name != NULL) {
1708 		if ((lower_name = tolower_u8(req->id1name)) == NULL)
1709 			lower_name = req->id1name;
1710 		sql = sqlite_mprintf("SELECT pid, is_user, expiration, "
1711 		    "unixname, u2w, is_wuser, "
1712 		    "map_type, map_dn, map_attr, map_value, "
1713 		    "map_windomain, map_winname, map_unixname, map_is_nt4 "
1714 		    "FROM idmap_cache WHERE is_user = %s AND "
1715 		    "winname = %Q AND windomain = %Q AND w2u = 1 AND "
1716 		    "(pid >= 2147483648 OR "
1717 		    "(expiration = 0 OR expiration ISNULL OR "
1718 		    "expiration > %d));",
1719 		    is_user_string, lower_name, req->id1domain,
1720 		    curtime);
1721 		if (lower_name != req->id1name)
1722 			free(lower_name);
1723 	} else {
1724 		retcode = IDMAP_ERR_ARG;
1725 		goto out;
1726 	}
1727 	if (sql == NULL) {
1728 		idmapdlog(LOG_ERR, "Out of memory");
1729 		retcode = IDMAP_ERR_MEMORY;
1730 		goto out;
1731 	}
1732 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol,
1733 	    14, &values);
1734 	sqlite_freemem(sql);
1735 
1736 	if (retcode == IDMAP_ERR_NOTFOUND) {
1737 		goto out;
1738 	} else if (retcode == IDMAP_SUCCESS) {
1739 		/* sanity checks */
1740 		if (values[0] == NULL || values[1] == NULL) {
1741 			retcode = IDMAP_ERR_CACHE;
1742 			goto out;
1743 		}
1744 
1745 		pid = strtoul(values[0], &end, 10);
1746 		is_user = strncmp(values[1], "0", 2) ? 1 : 0;
1747 
1748 		if (is_user) {
1749 			res->id.idtype = IDMAP_UID;
1750 			res->id.idmap_id_u.uid = pid;
1751 		} else {
1752 			res->id.idtype = IDMAP_GID;
1753 			res->id.idmap_id_u.gid = pid;
1754 		}
1755 
1756 		/*
1757 		 * We may have an expired ephemeral mapping. Consider
1758 		 * the expired entry as valid if we are not going to
1759 		 * perform name-based mapping. But do not renew the
1760 		 * expiration.
1761 		 * If we will be doing name-based mapping then store the
1762 		 * ephemeral pid in the result so that we can use it
1763 		 * if we end up doing dynamic mapping again.
1764 		 */
1765 		if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) &&
1766 		    !AVOID_NAMESERVICE(req) &&
1767 		    IS_EPHEMERAL(pid) && values[2] != NULL) {
1768 			exp = strtoll(values[2], &end, 10);
1769 			if (exp && exp <= curtime) {
1770 				/* Store the ephemeral pid */
1771 				res->direction = IDMAP_DIRECTION_BI;
1772 				req->direction |= is_user
1773 				    ? _IDMAP_F_EXP_EPH_UID
1774 				    : _IDMAP_F_EXP_EPH_GID;
1775 				retcode = IDMAP_ERR_NOTFOUND;
1776 			}
1777 		}
1778 	}
1779 
1780 out:
1781 	if (retcode == IDMAP_SUCCESS) {
1782 		if (values[4] != NULL)
1783 			res->direction =
1784 			    (strtol(values[4], &end, 10) == 0)?
1785 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
1786 		else
1787 			res->direction = IDMAP_DIRECTION_W2U;
1788 
1789 		if (values[3] != NULL) {
1790 			if (req->id2name != NULL)
1791 				free(req->id2name);
1792 			req->id2name = strdup(values[3]);
1793 			if (req->id2name == NULL) {
1794 				idmapdlog(LOG_ERR, "Out of memory");
1795 				retcode = IDMAP_ERR_MEMORY;
1796 			}
1797 		}
1798 
1799 		req->id1.idtype = strncmp(values[5], "0", 2) ?
1800 		    IDMAP_USID : IDMAP_GSID;
1801 
1802 		if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) {
1803 			res->info.src = IDMAP_MAP_SRC_CACHE;
1804 			res->info.how.map_type = strtoul(values[6], &end, 10);
1805 			switch (res->info.how.map_type) {
1806 			case IDMAP_MAP_TYPE_DS_AD:
1807 				res->info.how.idmap_how_u.ad.dn =
1808 				    strdup(values[7]);
1809 				res->info.how.idmap_how_u.ad.attr =
1810 				    strdup(values[8]);
1811 				res->info.how.idmap_how_u.ad.value =
1812 				    strdup(values[9]);
1813 				break;
1814 
1815 			case IDMAP_MAP_TYPE_DS_NLDAP:
1816 				res->info.how.idmap_how_u.nldap.dn =
1817 				    strdup(values[7]);
1818 				res->info.how.idmap_how_u.nldap.attr =
1819 				    strdup(values[8]);
1820 				res->info.how.idmap_how_u.nldap.value =
1821 				    strdup(values[9]);
1822 				break;
1823 
1824 			case IDMAP_MAP_TYPE_RULE_BASED:
1825 				res->info.how.idmap_how_u.rule.windomain =
1826 				    strdup(values[10]);
1827 				res->info.how.idmap_how_u.rule.winname =
1828 				    strdup(values[11]);
1829 				res->info.how.idmap_how_u.rule.unixname =
1830 				    strdup(values[12]);
1831 				res->info.how.idmap_how_u.rule.is_nt4 =
1832 				    strtoul(values[13], &end, 1);
1833 				res->info.how.idmap_how_u.rule.is_user =
1834 				    is_user;
1835 				res->info.how.idmap_how_u.rule.is_wuser =
1836 				    strtoul(values[5], &end, 1);
1837 				break;
1838 
1839 			case IDMAP_MAP_TYPE_EPHEMERAL:
1840 				break;
1841 
1842 			case IDMAP_MAP_TYPE_LOCAL_SID:
1843 				break;
1844 
1845 			case IDMAP_MAP_TYPE_KNOWN_SID:
1846 				break;
1847 
1848 			default:
1849 				/* Unknow mapping type */
1850 				assert(FALSE);
1851 			}
1852 		}
1853 	}
1854 	if (vm != NULL)
1855 		(void) sqlite_finalize(vm, NULL);
1856 	return (retcode);
1857 }
1858 
1859 static
1860 idmap_retcode
1861 lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid,
1862 		char **canonname, char **canondomain, int *type)
1863 {
1864 	char		*end;
1865 	char		*sql = NULL;
1866 	const char	**values;
1867 	sqlite_vm	*vm = NULL;
1868 	int		ncol;
1869 	time_t		curtime;
1870 	idmap_retcode	retcode = IDMAP_SUCCESS;
1871 
1872 	/* Get current time */
1873 	errno = 0;
1874 	if ((curtime = time(NULL)) == (time_t)-1) {
1875 		idmapdlog(LOG_ERR, "Failed to get current time (%s)",
1876 		    strerror(errno));
1877 		retcode = IDMAP_ERR_INTERNAL;
1878 		goto out;
1879 	}
1880 
1881 	/* SQL to lookup the cache */
1882 	sql = sqlite_mprintf("SELECT canon_name, domain, type "
1883 	    "FROM name_cache WHERE "
1884 	    "sidprefix = %Q AND rid = %u AND "
1885 	    "(expiration = 0 OR expiration ISNULL OR "
1886 	    "expiration > %d);",
1887 	    sidprefix, rid, curtime);
1888 	if (sql == NULL) {
1889 		idmapdlog(LOG_ERR, "Out of memory");
1890 		retcode = IDMAP_ERR_MEMORY;
1891 		goto out;
1892 	}
1893 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
1894 	sqlite_freemem(sql);
1895 
1896 	if (retcode == IDMAP_SUCCESS) {
1897 		if (type != NULL) {
1898 			if (values[2] == NULL) {
1899 				retcode = IDMAP_ERR_CACHE;
1900 				goto out;
1901 			}
1902 			*type = strtol(values[2], &end, 10);
1903 		}
1904 
1905 		if (canonname != NULL && values[0] != NULL) {
1906 			if ((*canonname = strdup(values[0])) == NULL) {
1907 				idmapdlog(LOG_ERR, "Out of memory");
1908 				retcode = IDMAP_ERR_MEMORY;
1909 				goto out;
1910 			}
1911 		}
1912 
1913 		if (canondomain != NULL && values[1] != NULL) {
1914 			if ((*canondomain = strdup(values[1])) == NULL) {
1915 				if (canonname != NULL) {
1916 					free(*canonname);
1917 					*canonname = NULL;
1918 				}
1919 				idmapdlog(LOG_ERR, "Out of memory");
1920 				retcode = IDMAP_ERR_MEMORY;
1921 				goto out;
1922 			}
1923 		}
1924 	}
1925 
1926 out:
1927 	if (vm != NULL)
1928 		(void) sqlite_finalize(vm, NULL);
1929 	return (retcode);
1930 }
1931 
1932 /*
1933  * Given SID, find winname using name_cache OR
1934  * Given winname, find SID using name_cache.
1935  * Used when mapping win to unix i.e. req->id1 is windows id and
1936  * req->id2 is unix id
1937  */
1938 static
1939 idmap_retcode
1940 lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res)
1941 {
1942 	int		type = -1;
1943 	idmap_retcode	retcode;
1944 	char		*sidprefix = NULL;
1945 	idmap_rid_t	rid;
1946 	char		*name = NULL, *domain = NULL;
1947 
1948 	/* Done if we've both sid and winname */
1949 	if (req->id1.idmap_id_u.sid.prefix != NULL && req->id1name != NULL)
1950 		return (IDMAP_SUCCESS);
1951 
1952 	if (req->id1.idmap_id_u.sid.prefix != NULL) {
1953 		/* Lookup sid to winname */
1954 		retcode = lookup_cache_sid2name(cache,
1955 		    req->id1.idmap_id_u.sid.prefix,
1956 		    req->id1.idmap_id_u.sid.rid, &name, &domain, &type);
1957 	} else {
1958 		/* Lookup winame to sid */
1959 		retcode = lookup_cache_name2sid(cache, req->id1name,
1960 		    req->id1domain, &name, &sidprefix, &rid, &type);
1961 	}
1962 
1963 	if (retcode != IDMAP_SUCCESS) {
1964 		free(name);
1965 		free(domain);
1966 		free(sidprefix);
1967 		return (retcode);
1968 	}
1969 
1970 	if (res->id.idtype == IDMAP_POSIXID) {
1971 		res->id.idtype = (type == _IDMAP_T_USER) ?
1972 		    IDMAP_UID : IDMAP_GID;
1973 	}
1974 	req->id1.idtype = (type == _IDMAP_T_USER) ?
1975 	    IDMAP_USID : IDMAP_GSID;
1976 
1977 	req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
1978 
1979 	/*
1980 	 * If we found canonical names or domain, use them instead of
1981 	 * the existing values.
1982 	 */
1983 	if (name != NULL) {
1984 		free(req->id1name);
1985 		req->id1name = name;
1986 	}
1987 	if (domain != NULL) {
1988 		free(req->id1domain);
1989 		req->id1domain = domain;
1990 	}
1991 
1992 	if (req->id1.idmap_id_u.sid.prefix == NULL) {
1993 		req->id1.idmap_id_u.sid.prefix = sidprefix;
1994 		req->id1.idmap_id_u.sid.rid = rid;
1995 	}
1996 	return (retcode);
1997 }
1998 
1999 
2000 
2001 static int
2002 ad_lookup_batch_int(lookup_state_t *state, idmap_mapping_batch *batch,
2003 		idmap_ids_res *result, int index, int *num_processed)
2004 {
2005 	idmap_retcode	retcode;
2006 	int		i,  num_queued, type, is_wuser, is_user;
2007 	int		next_request;
2008 	int		retries = 0, eunixtype;
2009 	char		**unixname;
2010 	idmap_mapping	*req;
2011 	idmap_id_res	*res;
2012 	idmap_query_state_t	*qs = NULL;
2013 	idmap_how	*how;
2014 	char		**dn, **attr, **value;
2015 
2016 	*num_processed = 0;
2017 
2018 	/*
2019 	 * Since req->id2.idtype is unused, we will use it here
2020 	 * to retrieve the value of sid_type. But it needs to be
2021 	 * reset to IDMAP_NONE before we return to prevent xdr
2022 	 * from mis-interpreting req->id2 when it tries to free
2023 	 * the input argument. Other option is to allocate an
2024 	 * array of integers and use it instead for the batched
2025 	 * call. But why un-necessarily allocate memory. That may
2026 	 * be an option if req->id2.idtype cannot be re-used in
2027 	 * future.
2028 	 */
2029 retry:
2030 	retcode = idmap_lookup_batch_start(_idmapdstate.ads[index],
2031 	    state->ad_nqueries, &qs);
2032 	if (retcode != IDMAP_SUCCESS) {
2033 		if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
2034 		    retries++ < ADUTILS_DEF_NUM_RETRIES)
2035 			goto retry;
2036 		degrade_svc(1, "failed to create batch for AD lookup");
2037 			goto out;
2038 	}
2039 	num_queued = 0;
2040 
2041 	restore_svc();
2042 
2043 	if (index == 0) {
2044 		/*
2045 		 * Directory based name mapping is only performed within the
2046 		 * joined forest (index == 0).  We don't trust other "trusted"
2047 		 * forests to provide DS-based name mapping information because
2048 		 * AD's definition of "cross-forest trust" does not encompass
2049 		 * this sort of behavior.
2050 		 */
2051 		idmap_lookup_batch_set_unixattr(qs,
2052 		    state->ad_unixuser_attr, state->ad_unixgroup_attr);
2053 	}
2054 
2055 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
2056 		req = &batch->idmap_mapping_batch_val[i];
2057 		res = &result->ids.ids_val[i];
2058 		how = &res->info.how;
2059 
2060 		retcode = IDMAP_SUCCESS;
2061 		req->id2.idtype = IDMAP_NONE;
2062 
2063 		/* Skip if not marked for this AD lookup */
2064 		if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
2065 		    (req->direction & _IDMAP_F_LOOKUP_OTHER_AD))
2066 			continue;
2067 
2068 		if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
2069 			continue;
2070 
2071 		if (IS_REQUEST_SID(*req, 1)) {
2072 
2073 			/* win2unix request: */
2074 
2075 			unixname = dn = attr = value = NULL;
2076 			eunixtype = _IDMAP_T_UNDEF;
2077 			if (req->id2name == NULL) {
2078 				if (res->id.idtype == IDMAP_UID &&
2079 				    AD_OR_MIXED(state->nm_siduid)) {
2080 					eunixtype = _IDMAP_T_USER;
2081 					unixname = &req->id2name;
2082 				} else if (res->id.idtype == IDMAP_GID &&
2083 				    AD_OR_MIXED(state->nm_sidgid)) {
2084 					eunixtype = _IDMAP_T_GROUP;
2085 					unixname = &req->id2name;
2086 				} else if (AD_OR_MIXED(state->nm_siduid) ||
2087 				    AD_OR_MIXED(state->nm_sidgid)) {
2088 					unixname = &req->id2name;
2089 				}
2090 			}
2091 
2092 			if (unixname != NULL) {
2093 				/*
2094 				 * Get how info for DS-based name
2095 				 * mapping only if AD or MIXED
2096 				 * mode is enabled.
2097 				 */
2098 				idmap_info_free(&res->info);
2099 				res->info.src = IDMAP_MAP_SRC_NEW;
2100 				how->map_type = IDMAP_MAP_TYPE_DS_AD;
2101 				dn = &how->idmap_how_u.ad.dn;
2102 				attr = &how->idmap_how_u.ad.attr;
2103 				value = &how->idmap_how_u.ad.value;
2104 			}
2105 			if (req->id1.idmap_id_u.sid.prefix != NULL) {
2106 				/* Lookup AD by SID */
2107 				retcode = idmap_sid2name_batch_add1(
2108 				    qs, req->id1.idmap_id_u.sid.prefix,
2109 				    &req->id1.idmap_id_u.sid.rid, eunixtype,
2110 				    dn, attr, value,
2111 				    (req->id1name == NULL) ?
2112 				    &req->id1name : NULL,
2113 				    (req->id1domain == NULL) ?
2114 				    &req->id1domain : NULL,
2115 				    (int *)&req->id2.idtype, unixname,
2116 				    &res->retcode);
2117 				if (retcode == IDMAP_SUCCESS)
2118 					num_queued++;
2119 			} else {
2120 				/* Lookup AD by winname */
2121 				assert(req->id1name != NULL);
2122 				retcode = idmap_name2sid_batch_add1(
2123 				    qs, req->id1name, req->id1domain,
2124 				    eunixtype,
2125 				    dn, attr, value,
2126 				    &req->id1name,
2127 				    &req->id1.idmap_id_u.sid.prefix,
2128 				    &req->id1.idmap_id_u.sid.rid,
2129 				    (int *)&req->id2.idtype, unixname,
2130 				    &res->retcode);
2131 				if (retcode == IDMAP_SUCCESS)
2132 					num_queued++;
2133 			}
2134 
2135 		} else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) {
2136 
2137 			/* unix2win request: */
2138 
2139 			if (res->id.idmap_id_u.sid.prefix != NULL &&
2140 			    req->id2name != NULL) {
2141 				/* Already have SID and winname. done */
2142 				res->retcode = IDMAP_SUCCESS;
2143 				continue;
2144 			}
2145 
2146 			if (res->id.idmap_id_u.sid.prefix != NULL) {
2147 				/*
2148 				 * SID but no winname -- lookup AD by
2149 				 * SID to get winname.
2150 				 * how info is not needed here because
2151 				 * we are not retrieving unixname from
2152 				 * AD.
2153 				 */
2154 
2155 				retcode = idmap_sid2name_batch_add1(
2156 				    qs, res->id.idmap_id_u.sid.prefix,
2157 				    &res->id.idmap_id_u.sid.rid,
2158 				    _IDMAP_T_UNDEF,
2159 				    NULL, NULL, NULL,
2160 				    &req->id2name,
2161 				    &req->id2domain, (int *)&req->id2.idtype,
2162 				    NULL, &res->retcode);
2163 				if (retcode == IDMAP_SUCCESS)
2164 					num_queued++;
2165 			} else if (req->id2name != NULL) {
2166 				/*
2167 				 * winname but no SID -- lookup AD by
2168 				 * winname to get SID.
2169 				 * how info is not needed here because
2170 				 * we are not retrieving unixname from
2171 				 * AD.
2172 				 */
2173 				retcode = idmap_name2sid_batch_add1(
2174 				    qs, req->id2name, req->id2domain,
2175 				    _IDMAP_T_UNDEF,
2176 				    NULL, NULL, NULL, NULL,
2177 				    &res->id.idmap_id_u.sid.prefix,
2178 				    &res->id.idmap_id_u.sid.rid,
2179 				    (int *)&req->id2.idtype, NULL,
2180 				    &res->retcode);
2181 				if (retcode == IDMAP_SUCCESS)
2182 					num_queued++;
2183 			} else if (req->id1name != NULL) {
2184 				/*
2185 				 * No SID and no winname but we've unixname.
2186 				 * Lookup AD by unixname to get SID.
2187 				 */
2188 				is_user = (IS_REQUEST_UID(*req)) ? 1 : 0;
2189 				if (res->id.idtype == IDMAP_USID)
2190 					is_wuser = 1;
2191 				else if (res->id.idtype == IDMAP_GSID)
2192 					is_wuser = 0;
2193 				else
2194 					is_wuser = is_user;
2195 
2196 				idmap_info_free(&res->info);
2197 				res->info.src = IDMAP_MAP_SRC_NEW;
2198 				how->map_type = IDMAP_MAP_TYPE_DS_AD;
2199 				retcode = idmap_unixname2sid_batch_add1(
2200 				    qs, req->id1name, is_user, is_wuser,
2201 				    &how->idmap_how_u.ad.dn,
2202 				    &how->idmap_how_u.ad.attr,
2203 				    &how->idmap_how_u.ad.value,
2204 				    &res->id.idmap_id_u.sid.prefix,
2205 				    &res->id.idmap_id_u.sid.rid,
2206 				    &req->id2name, &req->id2domain,
2207 				    (int *)&req->id2.idtype, &res->retcode);
2208 				if (retcode == IDMAP_SUCCESS)
2209 					num_queued++;
2210 			}
2211 		}
2212 
2213 		if (retcode == IDMAP_ERR_DOMAIN_NOTFOUND) {
2214 			req->direction |= _IDMAP_F_LOOKUP_OTHER_AD;
2215 			retcode = IDMAP_SUCCESS;
2216 		} else if (retcode != IDMAP_SUCCESS) {
2217 			idmap_lookup_release_batch(&qs);
2218 			num_queued = 0;
2219 			next_request = i + 1;
2220 			break;
2221 		}
2222 	} /* End of for loop */
2223 
2224 	if (retcode == IDMAP_SUCCESS) {
2225 		/* add keeps track if we added an entry to the batch */
2226 		if (num_queued > 0)
2227 			retcode = idmap_lookup_batch_end(&qs);
2228 		else
2229 			idmap_lookup_release_batch(&qs);
2230 	}
2231 
2232 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
2233 	    retries++ < ADUTILS_DEF_NUM_RETRIES)
2234 		goto retry;
2235 	else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
2236 		degrade_svc(1, "some AD lookups timed out repeatedly");
2237 
2238 	if (retcode != IDMAP_SUCCESS) {
2239 		/* Mark any unproccessed requests for an other AD */
2240 		for (i = next_request; i < batch->idmap_mapping_batch_len;
2241 		    i++) {
2242 			req = &batch->idmap_mapping_batch_val[i];
2243 			req->direction |= _IDMAP_F_LOOKUP_OTHER_AD;
2244 
2245 		}
2246 	}
2247 
2248 	if (retcode != IDMAP_SUCCESS)
2249 		idmapdlog(LOG_NOTICE, "Failed to batch AD lookup requests");
2250 
2251 out:
2252 	/*
2253 	 * This loop does the following:
2254 	 * 1. Reset _IDMAP_F_LOOKUP_AD flag from the request.
2255 	 * 2. Reset req->id2.idtype to IDMAP_NONE
2256 	 * 3. If batch_start or batch_add failed then set the status
2257 	 *    of each request marked for AD lookup to that error.
2258 	 * 4. Evaluate the type of the AD object (i.e. user or group)
2259 	 *    and update the idtype in request.
2260 	 */
2261 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
2262 		req = &batch->idmap_mapping_batch_val[i];
2263 		type = req->id2.idtype;
2264 		req->id2.idtype = IDMAP_NONE;
2265 		res = &result->ids.ids_val[i];
2266 		how = &res->info.how;
2267 		if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
2268 		    (req->direction & _IDMAP_F_LOOKUP_OTHER_AD))
2269 			continue;
2270 
2271 		/* Count number processed */
2272 		(*num_processed)++;
2273 
2274 		/* Reset AD lookup flag */
2275 		req->direction &= ~(_IDMAP_F_LOOKUP_AD);
2276 
2277 		/*
2278 		 * If batch_start or batch_add failed then set the
2279 		 * status of each request marked for AD lookup to
2280 		 * that error.
2281 		 */
2282 		if (retcode != IDMAP_SUCCESS) {
2283 			res->retcode = retcode;
2284 			continue;
2285 		}
2286 
2287 		if (res->retcode == IDMAP_ERR_NOTFOUND) {
2288 			/* Nothing found - remove the preset info */
2289 			idmap_info_free(&res->info);
2290 		}
2291 
2292 		if (IS_REQUEST_SID(*req, 1)) {
2293 			if (res->retcode != IDMAP_SUCCESS)
2294 				continue;
2295 			/* Evaluate result type */
2296 			switch (type) {
2297 			case _IDMAP_T_USER:
2298 				if (res->id.idtype == IDMAP_POSIXID)
2299 					res->id.idtype = IDMAP_UID;
2300 				req->id1.idtype = IDMAP_USID;
2301 				break;
2302 
2303 			case _IDMAP_T_GROUP:
2304 				if (res->id.idtype == IDMAP_POSIXID)
2305 					res->id.idtype = IDMAP_GID;
2306 				req->id1.idtype = IDMAP_GSID;
2307 				break;
2308 
2309 			default:
2310 				res->retcode = IDMAP_ERR_SID;
2311 				break;
2312 			}
2313 			if (res->retcode == IDMAP_SUCCESS &&
2314 			    req->id1name != NULL &&
2315 			    (req->id2name == NULL ||
2316 			    res->id.idmap_id_u.uid == SENTINEL_PID) &&
2317 			    NLDAP_MODE(res->id.idtype, state)) {
2318 				req->direction |= _IDMAP_F_LOOKUP_NLDAP;
2319 				state->nldap_nqueries++;
2320 			}
2321 		} else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) {
2322 			if (res->retcode != IDMAP_SUCCESS) {
2323 				if ((!(IDMAP_FATAL_ERROR(res->retcode))) &&
2324 				    res->id.idmap_id_u.sid.prefix == NULL &&
2325 				    req->id2name == NULL && /* no winname */
2326 				    req->id1name != NULL) /* unixname */
2327 					/*
2328 					 * If AD lookup by unixname
2329 					 * failed with non fatal error
2330 					 * then clear the error (ie set
2331 					 * res->retcode to success).
2332 					 * This allows the next pass to
2333 					 * process other mapping
2334 					 * mechanisms for this request.
2335 					 */
2336 					res->retcode = IDMAP_SUCCESS;
2337 				continue;
2338 			}
2339 			/* Evaluate result type */
2340 			switch (type) {
2341 			case _IDMAP_T_USER:
2342 				if (res->id.idtype == IDMAP_SID)
2343 					res->id.idtype = IDMAP_USID;
2344 				break;
2345 
2346 			case _IDMAP_T_GROUP:
2347 				if (res->id.idtype == IDMAP_SID)
2348 					res->id.idtype = IDMAP_GSID;
2349 				break;
2350 
2351 			default:
2352 				res->retcode = IDMAP_ERR_SID;
2353 				break;
2354 			}
2355 		}
2356 	}
2357 
2358 	return (retcode);
2359 }
2360 
2361 
2362 
2363 /*
2364  * Batch AD lookups
2365  */
2366 idmap_retcode
2367 ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
2368 		idmap_ids_res *result)
2369 {
2370 	idmap_retcode	retcode;
2371 	int		i, j;
2372 	idmap_mapping	*req;
2373 	idmap_id_res	*res;
2374 	int		num_queries;
2375 	int		num_processed;
2376 
2377 	if (state->ad_nqueries == 0)
2378 		return (IDMAP_SUCCESS);
2379 
2380 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
2381 		req = &batch->idmap_mapping_batch_val[i];
2382 		res = &result->ids.ids_val[i];
2383 
2384 		/* Skip if not marked for AD lookup or already in error. */
2385 		if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
2386 		    res->retcode != IDMAP_SUCCESS)
2387 			continue;
2388 
2389 		/* Init status */
2390 		res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
2391 	}
2392 
2393 	RDLOCK_CONFIG();
2394 	num_queries = state->ad_nqueries;
2395 	if (_idmapdstate.num_ads > 0) {
2396 		for (i = 0; i < _idmapdstate.num_ads && num_queries > 0; i++) {
2397 
2398 			retcode = ad_lookup_batch_int(state, batch, result, i,
2399 			    &num_processed);
2400 			num_queries -= num_processed;
2401 
2402 			if (num_queries > 0) {
2403 				for (j = 0; j < batch->idmap_mapping_batch_len;
2404 				    j++) {
2405 					req =
2406 					    &batch->idmap_mapping_batch_val[j];
2407 					res = &result->ids.ids_val[j];
2408 					if (!(req->direction &
2409 					    _IDMAP_F_LOOKUP_AD))
2410 						continue;
2411 					/*
2412 					 * Reset the other AD lookup flag so
2413 					 * that we can try the next AD
2414 					 */
2415 					req->direction &=
2416 					    ~(_IDMAP_F_LOOKUP_OTHER_AD);
2417 
2418 					if ((i + 1) >= _idmapdstate.num_ads) {
2419 						/*
2420 						 * There are no more ADs to try
2421 						 */
2422 						req->direction &=
2423 						    ~(_IDMAP_F_LOOKUP_AD);
2424 						res->retcode =
2425 						    IDMAP_ERR_DOMAIN_NOTFOUND;
2426 					}
2427 				}
2428 			}
2429 		}
2430 	} else {
2431 		/* Case of no ADs */
2432 		retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
2433 		for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
2434 			req = &batch->idmap_mapping_batch_val[i];
2435 			res = &result->ids.ids_val[i];
2436 			if (!(req->direction & _IDMAP_F_LOOKUP_AD))
2437 				continue;
2438 			req->direction &= ~(_IDMAP_F_LOOKUP_AD);
2439 			res->retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
2440 		}
2441 	}
2442 	UNLOCK_CONFIG();
2443 
2444 	/* AD lookups done. Reset state->ad_nqueries and return */
2445 	state->ad_nqueries = 0;
2446 	return (retcode);
2447 }
2448 
2449 /*
2450  * Convention when processing win2unix requests:
2451  *
2452  * Windows identity:
2453  * req->id1name =
2454  *              winname if given otherwise winname found will be placed
2455  *              here.
2456  * req->id1domain =
2457  *              windomain if given otherwise windomain found will be
2458  *              placed here.
2459  * req->id1.idtype =
2460  *              Either IDMAP_SID/USID/GSID. If this is IDMAP_SID then it'll
2461  *              be set to IDMAP_USID/GSID depending upon whether the
2462  *              given SID is user or group respectively. The user/group-ness
2463  *              is determined either when looking up well-known SIDs table OR
2464  *              if the SID is found in namecache OR by ad_lookup_one() OR by
2465  *              ad_lookup_batch().
2466  * req->id1..sid.[prefix, rid] =
2467  *              SID if given otherwise SID found will be placed here.
2468  *
2469  * Unix identity:
2470  * req->id2name =
2471  *              unixname found will be placed here.
2472  * req->id2domain =
2473  *              NOT USED
2474  * res->id.idtype =
2475  *              Target type initialized from req->id2.idtype. If
2476  *              it is IDMAP_POSIXID then actual type (IDMAP_UID/GID) found
2477  *              will be placed here.
2478  * res->id..[uid or gid] =
2479  *              UID/GID found will be placed here.
2480  *
2481  * Others:
2482  * res->retcode =
2483  *              Return status for this request will be placed here.
2484  * res->direction =
2485  *              Direction found will be placed here. Direction
2486  *              meaning whether the resultant mapping is valid
2487  *              only from win2unix or bi-directional.
2488  * req->direction =
2489  *              INTERNAL USE. Used by idmapd to set various
2490  *              flags (_IDMAP_F_xxxx) to aid in processing
2491  *              of the request.
2492  * req->id2.idtype =
2493  *              INTERNAL USE. Initially this is the requested target
2494  *              type and is used to initialize res->id.idtype.
2495  *              ad_lookup_batch() uses this field temporarily to store
2496  *              sid_type obtained by the batched AD lookups and after
2497  *              use resets it to IDMAP_NONE to prevent xdr from
2498  *              mis-interpreting the contents of req->id2.
2499  * req->id2..[uid or gid or sid] =
2500  *              NOT USED
2501  */
2502 
2503 /*
2504  * This function does the following:
2505  * 1. Lookup well-known SIDs table.
2506  * 2. Check if the given SID is a local-SID and if so extract UID/GID from it.
2507  * 3. Lookup cache.
2508  * 4. Check if the client does not want new mapping to be allocated
2509  *    in which case this pass is the final pass.
2510  * 5. Set AD lookup flag if it determines that the next stage needs
2511  *    to do AD lookup.
2512  */
2513 idmap_retcode
2514 sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req,
2515 		idmap_id_res *res)
2516 {
2517 	idmap_retcode	retcode;
2518 	int		wksid;
2519 
2520 	/* Initialize result */
2521 	res->id.idtype = req->id2.idtype;
2522 	res->id.idmap_id_u.uid = SENTINEL_PID;
2523 	res->direction = IDMAP_DIRECTION_UNDEF;
2524 	wksid = 0;
2525 
2526 	if (EMPTY_STRING(req->id1.idmap_id_u.sid.prefix)) {
2527 		if (req->id1name == NULL) {
2528 			retcode = IDMAP_ERR_ARG;
2529 			goto out;
2530 		}
2531 		/* sanitize sidprefix */
2532 		free(req->id1.idmap_id_u.sid.prefix);
2533 		req->id1.idmap_id_u.sid.prefix = NULL;
2534 	}
2535 
2536 	/* Lookup well-known SIDs table */
2537 	retcode = lookup_wksids_sid2pid(req, res, &wksid);
2538 	if (retcode != IDMAP_ERR_NOTFOUND)
2539 		goto out;
2540 
2541 	if (!wksid) {
2542 		/* Check if this is a localsid */
2543 		retcode = lookup_localsid2pid(req, res);
2544 		if (retcode != IDMAP_ERR_NOTFOUND)
2545 			goto out;
2546 
2547 		if (ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)) {
2548 			retcode = IDMAP_ERR_NONE_GENERATED;
2549 			goto out;
2550 		}
2551 	}
2552 
2553 	/* Lookup cache */
2554 	retcode = lookup_cache_sid2pid(state->cache, req, res);
2555 	if (retcode != IDMAP_ERR_NOTFOUND)
2556 		goto out;
2557 
2558 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
2559 		retcode = IDMAP_ERR_NONE_GENERATED;
2560 		goto out;
2561 	}
2562 
2563 	/*
2564 	 * Failed to find non-expired entry in cache. Next step is
2565 	 * to determine if this request needs to be batched for AD lookup.
2566 	 *
2567 	 * At this point we have either sid or winname or both. If we don't
2568 	 * have both then lookup name_cache for the sid or winname
2569 	 * whichever is missing. If not found then this request will be
2570 	 * batched for AD lookup.
2571 	 */
2572 	retcode = lookup_name_cache(state->cache, req, res);
2573 	if (retcode != IDMAP_SUCCESS && retcode != IDMAP_ERR_NOTFOUND)
2574 		goto out;
2575 
2576 	/*
2577 	 * Set the flag to indicate that we are not done yet so that
2578 	 * subsequent passes considers this request for name-based
2579 	 * mapping and ephemeral mapping.
2580 	 */
2581 	state->sid2pid_done = FALSE;
2582 	req->direction |= _IDMAP_F_NOTDONE;
2583 
2584 	/*
2585 	 * Even if we have both sid and winname, we still may need to batch
2586 	 * this request for AD lookup if we don't have unixname and
2587 	 * directory-based name mapping (AD or mixed) is enabled.
2588 	 * We avoid AD lookup for well-known SIDs because they don't have
2589 	 * regular AD objects.
2590 	 */
2591 	if (retcode != IDMAP_SUCCESS ||
2592 	    (!wksid && req->id2name == NULL &&
2593 	    AD_OR_MIXED_MODE(res->id.idtype, state))) {
2594 		retcode = IDMAP_SUCCESS;
2595 		req->direction |= _IDMAP_F_LOOKUP_AD;
2596 		state->ad_nqueries++;
2597 	} else if (NLDAP_MODE(res->id.idtype, state)) {
2598 		req->direction |= _IDMAP_F_LOOKUP_NLDAP;
2599 		state->nldap_nqueries++;
2600 	}
2601 
2602 
2603 out:
2604 	res->retcode = idmap_stat4prot(retcode);
2605 	/*
2606 	 * If we are done and there was an error then set fallback pid
2607 	 * in the result.
2608 	 */
2609 	if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS)
2610 		res->id.idmap_id_u.uid = UID_NOBODY;
2611 	return (retcode);
2612 }
2613 
2614 /*
2615  * Generate SID using the following convention
2616  * 	<machine-sid-prefix>-<1000 + uid>
2617  * 	<machine-sid-prefix>-<2^31 + gid>
2618  */
2619 static
2620 idmap_retcode
2621 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user,
2622 		int fallback)
2623 {
2624 	free(res->id.idmap_id_u.sid.prefix);
2625 	res->id.idmap_id_u.sid.prefix = NULL;
2626 
2627 	/*
2628 	 * Diagonal mapping for localSIDs not supported because of the
2629 	 * way we generate localSIDs.
2630 	 */
2631 	if (is_user && res->id.idtype == IDMAP_GSID)
2632 		return (IDMAP_ERR_NOMAPPING);
2633 	if (!is_user && res->id.idtype == IDMAP_USID)
2634 		return (IDMAP_ERR_NOMAPPING);
2635 
2636 	/* Skip 1000 UIDs */
2637 	if (is_user && req->id1.idmap_id_u.uid >
2638 	    (INT32_MAX - LOCALRID_MIN))
2639 		return (IDMAP_ERR_NOMAPPING);
2640 
2641 	RDLOCK_CONFIG();
2642 	/*
2643 	 * machine_sid is never NULL because if it is we won't be here.
2644 	 * No need to assert because stdrup(NULL) will core anyways.
2645 	 */
2646 	res->id.idmap_id_u.sid.prefix =
2647 	    strdup(_idmapdstate.cfg->pgcfg.machine_sid);
2648 	if (res->id.idmap_id_u.sid.prefix == NULL) {
2649 		UNLOCK_CONFIG();
2650 		idmapdlog(LOG_ERR, "Out of memory");
2651 		return (IDMAP_ERR_MEMORY);
2652 	}
2653 	UNLOCK_CONFIG();
2654 	res->id.idmap_id_u.sid.rid =
2655 	    (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_MIN :
2656 	    req->id1.idmap_id_u.gid + INT32_MAX + 1;
2657 	res->direction = IDMAP_DIRECTION_BI;
2658 	if (res->id.idtype == IDMAP_SID)
2659 		res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID;
2660 
2661 	if (!fallback) {
2662 		res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID;
2663 		res->info.src = IDMAP_MAP_SRC_ALGORITHMIC;
2664 	}
2665 
2666 	/*
2667 	 * Don't update name_cache because local sids don't have
2668 	 * valid windows names.
2669 	 */
2670 	req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
2671 	return (IDMAP_SUCCESS);
2672 }
2673 
2674 static
2675 idmap_retcode
2676 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res)
2677 {
2678 	char		*sidprefix;
2679 	uint32_t	rid;
2680 	int		s;
2681 
2682 	/*
2683 	 * If the sidprefix == localsid then UID = last RID - 1000 or
2684 	 * GID = last RID - 2^31.
2685 	 */
2686 	if ((sidprefix = req->id1.idmap_id_u.sid.prefix) == NULL)
2687 		/* This means we are looking up by winname */
2688 		return (IDMAP_ERR_NOTFOUND);
2689 	rid = req->id1.idmap_id_u.sid.rid;
2690 
2691 	RDLOCK_CONFIG();
2692 	s = (_idmapdstate.cfg->pgcfg.machine_sid) ?
2693 	    strcasecmp(sidprefix, _idmapdstate.cfg->pgcfg.machine_sid) : 1;
2694 	UNLOCK_CONFIG();
2695 
2696 	/*
2697 	 * If the given sidprefix does not match machine_sid then this is
2698 	 * not a local SID.
2699 	 */
2700 	if (s != 0)
2701 		return (IDMAP_ERR_NOTFOUND);
2702 
2703 	switch (res->id.idtype) {
2704 	case IDMAP_UID:
2705 		if (rid > INT32_MAX || rid < LOCALRID_MIN)
2706 			return (IDMAP_ERR_ARG);
2707 		res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
2708 		break;
2709 	case IDMAP_GID:
2710 		if (rid <= INT32_MAX)
2711 			return (IDMAP_ERR_ARG);
2712 		res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
2713 		break;
2714 	case IDMAP_POSIXID:
2715 		if (rid > INT32_MAX) {
2716 			res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
2717 			res->id.idtype = IDMAP_GID;
2718 		} else if (rid < LOCALRID_MIN) {
2719 			return (IDMAP_ERR_ARG);
2720 		} else {
2721 			res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
2722 			res->id.idtype = IDMAP_UID;
2723 		}
2724 		break;
2725 	default:
2726 		return (IDMAP_ERR_NOTSUPPORTED);
2727 	}
2728 	res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID;
2729 	res->info.src = IDMAP_MAP_SRC_ALGORITHMIC;
2730 	return (IDMAP_SUCCESS);
2731 }
2732 
2733 /*
2734  * Name service lookup by unixname to get pid
2735  */
2736 static
2737 idmap_retcode
2738 ns_lookup_byname(const char *name, const char *lower_name, idmap_id *id)
2739 {
2740 	struct passwd	pwd, *pwdp;
2741 	struct group	grp, *grpp;
2742 	char		*buf;
2743 	int		errnum;
2744 	const char	*me = "ns_lookup_byname";
2745 	static size_t	pwdbufsiz = 0;
2746 	static size_t	grpbufsiz = 0;
2747 
2748 	switch (id->idtype) {
2749 	case IDMAP_UID:
2750 		if (pwdbufsiz == 0)
2751 			pwdbufsiz = sysconf(_SC_GETPW_R_SIZE_MAX);
2752 		buf = alloca(pwdbufsiz);
2753 		pwdp = getpwnam_r(name, &pwd, buf, pwdbufsiz);
2754 		if (pwdp == NULL && errno == 0 && lower_name != NULL &&
2755 		    name != lower_name && strcmp(name, lower_name) != 0)
2756 			pwdp = getpwnam_r(lower_name, &pwd, buf, pwdbufsiz);
2757 		if (pwdp == NULL) {
2758 			errnum = errno;
2759 			idmapdlog(LOG_WARNING,
2760 			    "%s: getpwnam_r(%s) failed (%s).",
2761 			    me, name, errnum ? strerror(errnum) : "not found");
2762 			if (errnum == 0)
2763 				return (IDMAP_ERR_NOTFOUND);
2764 			else
2765 				return (IDMAP_ERR_INTERNAL);
2766 		}
2767 		id->idmap_id_u.uid = pwd.pw_uid;
2768 		break;
2769 	case IDMAP_GID:
2770 		if (grpbufsiz == 0)
2771 			grpbufsiz = sysconf(_SC_GETGR_R_SIZE_MAX);
2772 		buf = alloca(grpbufsiz);
2773 		grpp = getgrnam_r(name, &grp, buf, grpbufsiz);
2774 		if (grpp == NULL && errno == 0 && lower_name != NULL &&
2775 		    name != lower_name && strcmp(name, lower_name) != 0)
2776 			grpp = getgrnam_r(lower_name, &grp, buf, grpbufsiz);
2777 		if (grpp == NULL) {
2778 			errnum = errno;
2779 			idmapdlog(LOG_WARNING,
2780 			    "%s: getgrnam_r(%s) failed (%s).",
2781 			    me, name, errnum ? strerror(errnum) : "not found");
2782 			if (errnum == 0)
2783 				return (IDMAP_ERR_NOTFOUND);
2784 			else
2785 				return (IDMAP_ERR_INTERNAL);
2786 		}
2787 		id->idmap_id_u.gid = grp.gr_gid;
2788 		break;
2789 	default:
2790 		return (IDMAP_ERR_ARG);
2791 	}
2792 	return (IDMAP_SUCCESS);
2793 }
2794 
2795 
2796 /*
2797  * Name service lookup by pid to get unixname
2798  */
2799 static
2800 idmap_retcode
2801 ns_lookup_bypid(uid_t pid, int is_user, char **unixname)
2802 {
2803 	struct passwd	pwd;
2804 	struct group	grp;
2805 	char		*buf;
2806 	int		errnum;
2807 	const char	*me = "ns_lookup_bypid";
2808 	static size_t	pwdbufsiz = 0;
2809 	static size_t	grpbufsiz = 0;
2810 
2811 	if (is_user) {
2812 		if (pwdbufsiz == 0)
2813 			pwdbufsiz = sysconf(_SC_GETPW_R_SIZE_MAX);
2814 		buf = alloca(pwdbufsiz);
2815 		errno = 0;
2816 		if (getpwuid_r(pid, &pwd, buf, pwdbufsiz) == NULL) {
2817 			errnum = errno;
2818 			idmapdlog(LOG_WARNING,
2819 			    "%s: getpwuid_r(%u) failed (%s).",
2820 			    me, pid, errnum ? strerror(errnum) : "not found");
2821 			if (errnum == 0)
2822 				return (IDMAP_ERR_NOTFOUND);
2823 			else
2824 				return (IDMAP_ERR_INTERNAL);
2825 		}
2826 		*unixname = strdup(pwd.pw_name);
2827 	} else {
2828 		if (grpbufsiz == 0)
2829 			grpbufsiz = sysconf(_SC_GETGR_R_SIZE_MAX);
2830 		buf = alloca(grpbufsiz);
2831 		errno = 0;
2832 		if (getgrgid_r(pid, &grp, buf, grpbufsiz) == NULL) {
2833 			errnum = errno;
2834 			idmapdlog(LOG_WARNING,
2835 			    "%s: getgrgid_r(%u) failed (%s).",
2836 			    me, pid, errnum ? strerror(errnum) : "not found");
2837 			if (errnum == 0)
2838 				return (IDMAP_ERR_NOTFOUND);
2839 			else
2840 				return (IDMAP_ERR_INTERNAL);
2841 		}
2842 		*unixname = strdup(grp.gr_name);
2843 	}
2844 	if (*unixname == NULL)
2845 		return (IDMAP_ERR_MEMORY);
2846 	return (IDMAP_SUCCESS);
2847 }
2848 
2849 /*
2850  * Name-based mapping
2851  *
2852  * Case 1: If no rule matches do ephemeral
2853  *
2854  * Case 2: If rule matches and unixname is "" then return no mapping.
2855  *
2856  * Case 3: If rule matches and unixname is specified then lookup name
2857  *  service using the unixname. If unixname not found then return no mapping.
2858  *
2859  * Case 4: If rule matches and unixname is * then lookup name service
2860  *  using winname as the unixname. If unixname not found then process
2861  *  other rules using the lookup order. If no other rule matches then do
2862  *  ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
2863  *  This allows us to specify a fallback unixname per _domain_ or no mapping
2864  *  instead of the default behaviour of doing ephemeral mapping.
2865  *
2866  * Example 1:
2867  * *@sfbay == *
2868  * If looking up windows users foo@sfbay and foo does not exists in
2869  * the name service then foo@sfbay will be mapped to an ephemeral id.
2870  *
2871  * Example 2:
2872  * *@sfbay == *
2873  * *@sfbay => guest
2874  * If looking up windows users foo@sfbay and foo does not exists in
2875  * the name service then foo@sfbay will be mapped to guest.
2876  *
2877  * Example 3:
2878  * *@sfbay == *
2879  * *@sfbay => ""
2880  * If looking up windows users foo@sfbay and foo does not exists in
2881  * the name service then we will return no mapping for foo@sfbay.
2882  *
2883  */
2884 static
2885 idmap_retcode
2886 name_based_mapping_sid2pid(lookup_state_t *state,
2887 		idmap_mapping *req, idmap_id_res *res)
2888 {
2889 	const char	*unixname, *windomain;
2890 	char		*sql = NULL, *errmsg = NULL, *lower_winname = NULL;
2891 	idmap_retcode	retcode;
2892 	char		*end, *lower_unixname, *winname;
2893 	const char	**values;
2894 	sqlite_vm	*vm = NULL;
2895 	int		ncol, r, is_user, is_wuser;
2896 	idmap_namerule	*rule = &res->info.how.idmap_how_u.rule;
2897 	int		direction;
2898 	const char	*me = "name_based_mapping_sid2pid";
2899 
2900 	assert(req->id1name != NULL); /* We have winname */
2901 	assert(req->id2name == NULL); /* We don't have unixname */
2902 
2903 	winname = req->id1name;
2904 	windomain = req->id1domain;
2905 
2906 	switch (req->id1.idtype) {
2907 	case IDMAP_USID:
2908 		is_wuser = 1;
2909 		break;
2910 	case IDMAP_GSID:
2911 		is_wuser = 0;
2912 		break;
2913 	default:
2914 		idmapdlog(LOG_ERR, "%s: Unable to determine if the "
2915 		    "given Windows id is user or group.", me);
2916 		return (IDMAP_ERR_INTERNAL);
2917 	}
2918 
2919 	switch (res->id.idtype) {
2920 	case IDMAP_UID:
2921 		is_user = 1;
2922 		break;
2923 	case IDMAP_GID:
2924 		is_user = 0;
2925 		break;
2926 	case IDMAP_POSIXID:
2927 		is_user = is_wuser;
2928 		res->id.idtype = is_user ? IDMAP_UID : IDMAP_GID;
2929 		break;
2930 	}
2931 
2932 	if (windomain == NULL)
2933 		windomain = "";
2934 
2935 	if ((lower_winname = tolower_u8(winname)) == NULL)
2936 		lower_winname = winname;    /* hope for the best */
2937 	sql = sqlite_mprintf(
2938 	    "SELECT unixname, u2w_order, winname_display, windomain, is_nt4 "
2939 	    "FROM namerules WHERE "
2940 	    "w2u_order > 0 AND is_user = %d AND is_wuser = %d AND "
2941 	    "(winname = %Q OR winname = '*') AND "
2942 	    "(windomain = %Q OR windomain = '*') "
2943 	    "ORDER BY w2u_order ASC;",
2944 	    is_user, is_wuser, lower_winname, windomain);
2945 	if (sql == NULL) {
2946 		idmapdlog(LOG_ERR, "Out of memory");
2947 		retcode = IDMAP_ERR_MEMORY;
2948 		goto out;
2949 	}
2950 
2951 	if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
2952 		retcode = IDMAP_ERR_INTERNAL;
2953 		idmapdlog(LOG_ERR, "%s: database error (%s)", me,
2954 		    CHECK_NULL(errmsg));
2955 		sqlite_freemem(errmsg);
2956 		goto out;
2957 	}
2958 
2959 	for (;;) {
2960 		r = sqlite_step(vm, &ncol, &values, NULL);
2961 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
2962 
2963 		if (r == SQLITE_ROW) {
2964 			if (ncol < 5) {
2965 				retcode = IDMAP_ERR_INTERNAL;
2966 				goto out;
2967 			}
2968 			if (values[0] == NULL) {
2969 				retcode = IDMAP_ERR_INTERNAL;
2970 				goto out;
2971 			}
2972 
2973 			if (values[1] != NULL)
2974 				direction =
2975 				    (strtol(values[1], &end, 10) == 0)?
2976 				    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
2977 			else
2978 				direction = IDMAP_DIRECTION_W2U;
2979 
2980 			if (EMPTY_NAME(values[0])) {
2981 				idmap_namerule_set(rule, values[3], values[2],
2982 				    values[0], is_wuser, is_user,
2983 				    strtol(values[4], &end, 10),
2984 				    direction);
2985 				retcode = IDMAP_ERR_NOMAPPING;
2986 				goto out;
2987 			}
2988 
2989 			if (values[0][0] == '*') {
2990 				unixname = winname;
2991 				lower_unixname = lower_winname;
2992 			} else {
2993 				unixname = values[0];
2994 				lower_unixname = NULL;
2995 			}
2996 
2997 			retcode = ns_lookup_byname(unixname, lower_unixname,
2998 			    &res->id);
2999 			if (retcode == IDMAP_ERR_NOTFOUND) {
3000 				if (values[0][0] == '*')
3001 					/* Case 4 */
3002 					continue;
3003 				else {
3004 					/* Case 3 */
3005 					idmap_namerule_set(rule, values[3],
3006 					    values[2], values[0], is_wuser,
3007 					    is_user,
3008 					    strtol(values[4], &end, 10),
3009 					    direction);
3010 					retcode = IDMAP_ERR_NOMAPPING;
3011 				}
3012 			}
3013 			goto out;
3014 		} else if (r == SQLITE_DONE) {
3015 			retcode = IDMAP_ERR_NOTFOUND;
3016 			goto out;
3017 		} else {
3018 			(void) sqlite_finalize(vm, &errmsg);
3019 			vm = NULL;
3020 			idmapdlog(LOG_ERR, "%s: database error (%s)", me,
3021 			    CHECK_NULL(errmsg));
3022 			sqlite_freemem(errmsg);
3023 			retcode = IDMAP_ERR_INTERNAL;
3024 			goto out;
3025 		}
3026 	}
3027 
3028 out:
3029 	if (sql != NULL)
3030 		sqlite_freemem(sql);
3031 	if (retcode == IDMAP_SUCCESS) {
3032 		if (values[1] != NULL)
3033 			res->direction =
3034 			    (strtol(values[1], &end, 10) == 0)?
3035 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
3036 		else
3037 			res->direction = IDMAP_DIRECTION_W2U;
3038 
3039 		req->id2name = strdup(unixname);
3040 		if (req->id2name == NULL) {
3041 			retcode = IDMAP_ERR_MEMORY;
3042 		}
3043 	}
3044 
3045 	if (retcode == IDMAP_SUCCESS) {
3046 		idmap_namerule_set(rule, values[3], values[2],
3047 		    values[0], is_wuser, is_user, strtol(values[4], &end, 10),
3048 		    res->direction);
3049 	}
3050 
3051 	if (retcode != IDMAP_ERR_NOTFOUND) {
3052 		res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED;
3053 		res->info.src = IDMAP_MAP_SRC_NEW;
3054 	}
3055 
3056 	if (lower_winname != NULL && lower_winname != winname)
3057 		free(lower_winname);
3058 	if (vm != NULL)
3059 		(void) sqlite_finalize(vm, NULL);
3060 	return (retcode);
3061 }
3062 
3063 static
3064 int
3065 get_next_eph_uid(uid_t *next_uid)
3066 {
3067 	uid_t uid;
3068 	gid_t gid;
3069 	int err;
3070 
3071 	*next_uid = (uid_t)-1;
3072 	uid = _idmapdstate.next_uid++;
3073 	if (uid >= _idmapdstate.limit_uid) {
3074 		if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0)
3075 			return (err);
3076 
3077 		_idmapdstate.limit_uid = uid + 8192;
3078 		_idmapdstate.next_uid = uid;
3079 	}
3080 	*next_uid = uid;
3081 
3082 	return (0);
3083 }
3084 
3085 static
3086 int
3087 get_next_eph_gid(gid_t *next_gid)
3088 {
3089 	uid_t uid;
3090 	gid_t gid;
3091 	int err;
3092 
3093 	*next_gid = (uid_t)-1;
3094 	gid = _idmapdstate.next_gid++;
3095 	if (gid >= _idmapdstate.limit_gid) {
3096 		if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0)
3097 			return (err);
3098 
3099 		_idmapdstate.limit_gid = gid + 8192;
3100 		_idmapdstate.next_gid = gid;
3101 	}
3102 	*next_gid = gid;
3103 
3104 	return (0);
3105 }
3106 
3107 static
3108 int
3109 gethash(const char *str, uint32_t num, uint_t htsize)
3110 {
3111 	uint_t  hval, i, len;
3112 
3113 	if (str == NULL)
3114 		return (0);
3115 	for (len = strlen(str), hval = 0, i = 0; i < len; i++) {
3116 		hval += str[i];
3117 		hval += (hval << 10);
3118 		hval ^= (hval >> 6);
3119 	}
3120 	for (str = (const char *)&num, i = 0; i < sizeof (num); i++) {
3121 		hval += str[i];
3122 		hval += (hval << 10);
3123 		hval ^= (hval >> 6);
3124 	}
3125 	hval += (hval << 3);
3126 	hval ^= (hval >> 11);
3127 	hval += (hval << 15);
3128 	return (hval % htsize);
3129 }
3130 
3131 static
3132 int
3133 get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid,
3134 		uid_t *pid)
3135 {
3136 	uint_t		next, key;
3137 	uint_t		htsize = state->sid_history_size;
3138 	idmap_sid	*sid;
3139 
3140 	next = gethash(prefix, rid, htsize);
3141 	while (next != htsize) {
3142 		key = state->sid_history[next].key;
3143 		if (key == htsize)
3144 			return (0);
3145 		sid = &state->batch->idmap_mapping_batch_val[key].id1.
3146 		    idmap_id_u.sid;
3147 		if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) {
3148 			*pid = state->result->ids.ids_val[key].id.
3149 			    idmap_id_u.uid;
3150 			return (1);
3151 		}
3152 		next = state->sid_history[next].next;
3153 	}
3154 	return (0);
3155 }
3156 
3157 static
3158 void
3159 add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid)
3160 {
3161 	uint_t		hash, next;
3162 	uint_t		htsize = state->sid_history_size;
3163 
3164 	hash = next = gethash(prefix, rid, htsize);
3165 	while (state->sid_history[next].key != htsize) {
3166 		next++;
3167 		next %= htsize;
3168 	}
3169 	state->sid_history[next].key = state->curpos;
3170 	if (hash == next)
3171 		return;
3172 	state->sid_history[next].next = state->sid_history[hash].next;
3173 	state->sid_history[hash].next = next;
3174 }
3175 
3176 void
3177 cleanup_lookup_state(lookup_state_t *state)
3178 {
3179 	free(state->sid_history);
3180 	free(state->ad_unixuser_attr);
3181 	free(state->ad_unixgroup_attr);
3182 	free(state->nldap_winname_attr);
3183 	free(state->defdom);
3184 }
3185 
3186 /* ARGSUSED */
3187 static
3188 idmap_retcode
3189 dynamic_ephemeral_mapping(lookup_state_t *state,
3190 		idmap_mapping *req, idmap_id_res *res)
3191 {
3192 
3193 	uid_t		next_pid;
3194 
3195 	res->direction = IDMAP_DIRECTION_BI;
3196 
3197 	if (IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
3198 		res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL;
3199 		res->info.src = IDMAP_MAP_SRC_CACHE;
3200 		return (IDMAP_SUCCESS);
3201 	}
3202 
3203 	if (state->sid_history != NULL &&
3204 	    get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix,
3205 	    req->id1.idmap_id_u.sid.rid, &next_pid)) {
3206 		res->id.idmap_id_u.uid = next_pid;
3207 		res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL;
3208 		res->info.src = IDMAP_MAP_SRC_NEW;
3209 		return (IDMAP_SUCCESS);
3210 	}
3211 
3212 	if (res->id.idtype == IDMAP_UID) {
3213 		if (get_next_eph_uid(&next_pid) != 0)
3214 			return (IDMAP_ERR_INTERNAL);
3215 		res->id.idmap_id_u.uid = next_pid;
3216 	} else {
3217 		if (get_next_eph_gid(&next_pid) != 0)
3218 			return (IDMAP_ERR_INTERNAL);
3219 		res->id.idmap_id_u.gid = next_pid;
3220 	}
3221 
3222 	res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL;
3223 	res->info.src = IDMAP_MAP_SRC_NEW;
3224 	if (state->sid_history != NULL)
3225 		add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix,
3226 		    req->id1.idmap_id_u.sid.rid);
3227 
3228 	return (IDMAP_SUCCESS);
3229 }
3230 
3231 idmap_retcode
3232 sid2pid_second_pass(lookup_state_t *state,
3233 		idmap_mapping *req, idmap_id_res *res)
3234 {
3235 	idmap_retcode	retcode;
3236 
3237 	/* Check if second pass is needed */
3238 	if (ARE_WE_DONE(req->direction))
3239 		return (res->retcode);
3240 
3241 	/* Get status from previous pass */
3242 	retcode = res->retcode;
3243 	if (retcode != IDMAP_SUCCESS && state->eph_map_unres_sids &&
3244 	    !EMPTY_STRING(req->id1.idmap_id_u.sid.prefix) &&
3245 	    EMPTY_STRING(req->id1name)) {
3246 		/*
3247 		 * We are asked to map an unresolvable SID to a UID or
3248 		 * GID, but, which?  We'll treat all unresolvable SIDs
3249 		 * as users unless the caller specified which of a UID
3250 		 * or GID they want.
3251 		 */
3252 		if (req->id1.idtype == IDMAP_SID)
3253 			req->id1.idtype = IDMAP_USID;
3254 		if (res->id.idtype == IDMAP_POSIXID)
3255 			res->id.idtype = IDMAP_UID;
3256 		goto do_eph;
3257 	}
3258 	if (retcode != IDMAP_SUCCESS)
3259 		goto out;
3260 
3261 	/*
3262 	 * If directory-based name mapping is enabled then the unixname
3263 	 * may already have been retrieved from the AD object (AD-mode or
3264 	 * mixed-mode) or from native LDAP object (nldap-mode) -- done.
3265 	 */
3266 	if (req->id2name != NULL) {
3267 		assert(res->id.idtype != IDMAP_POSIXID);
3268 		if (AD_MODE(res->id.idtype, state))
3269 			res->direction = IDMAP_DIRECTION_BI;
3270 		else if (NLDAP_MODE(res->id.idtype, state))
3271 			res->direction = IDMAP_DIRECTION_BI;
3272 		else if (MIXED_MODE(res->id.idtype, state))
3273 			res->direction = IDMAP_DIRECTION_W2U;
3274 
3275 		/*
3276 		 * Special case: (1) If the ad_unixuser_attr and
3277 		 * ad_unixgroup_attr uses the same attribute
3278 		 * name and (2) if this is a diagonal mapping
3279 		 * request and (3) the unixname has been retrieved
3280 		 * from the AD object -- then we ignore it and fallback
3281 		 * to name-based mapping rules and ephemeral mapping
3282 		 *
3283 		 * Example:
3284 		 *  Properties:
3285 		 *    config/ad_unixuser_attr = "unixname"
3286 		 *    config/ad_unixgroup_attr = "unixname"
3287 		 *  AD user object:
3288 		 *    dn: cn=bob ...
3289 		 *    objectclass: user
3290 		 *    sam: bob
3291 		 *    unixname: bob1234
3292 		 *  AD group object:
3293 		 *    dn: cn=winadmins ...
3294 		 *    objectclass: group
3295 		 *    sam: winadmins
3296 		 *    unixname: unixadmins
3297 		 *
3298 		 *  In this example whether "unixname" refers to a unixuser
3299 		 *  or unixgroup depends upon the AD object.
3300 		 *
3301 		 * $idmap show -c winname:bob gid
3302 		 *    AD lookup by "samAccountName=bob" for
3303 		 *    "ad_unixgroup_attr (i.e unixname)" for directory-based
3304 		 *    mapping would get "bob1234" which is not what we want.
3305 		 *    Now why not getgrnam_r("bob1234") and use it if it
3306 		 *    is indeed a unixgroup? That's because Unix can have
3307 		 *    users and groups with the same name and we clearly
3308 		 *    don't know the intention of the admin here.
3309 		 *    Therefore we ignore this and fallback to name-based
3310 		 *    mapping rules or ephemeral mapping.
3311 		 */
3312 		if ((AD_MODE(res->id.idtype, state) ||
3313 		    MIXED_MODE(res->id.idtype, state)) &&
3314 		    state->ad_unixuser_attr != NULL &&
3315 		    state->ad_unixgroup_attr != NULL &&
3316 		    strcasecmp(state->ad_unixuser_attr,
3317 		    state->ad_unixgroup_attr) == 0 &&
3318 		    ((req->id1.idtype == IDMAP_USID &&
3319 		    res->id.idtype == IDMAP_GID) ||
3320 		    (req->id1.idtype == IDMAP_GSID &&
3321 		    res->id.idtype == IDMAP_UID))) {
3322 			free(req->id2name);
3323 			req->id2name = NULL;
3324 			res->id.idmap_id_u.uid = SENTINEL_PID;
3325 			/* fallback */
3326 		} else {
3327 			if (res->id.idmap_id_u.uid == SENTINEL_PID)
3328 				retcode = ns_lookup_byname(req->id2name,
3329 				    NULL, &res->id);
3330 			/*
3331 			 * If ns_lookup_byname() fails that means the
3332 			 * unixname (req->id2name), which was obtained
3333 			 * from the AD object by directory-based mapping,
3334 			 * is not a valid Unix user/group and therefore
3335 			 * we return the error to the client instead of
3336 			 * doing rule-based mapping or ephemeral mapping.
3337 			 * This way the client can detect the issue.
3338 			 */
3339 			goto out;
3340 		}
3341 	}
3342 
3343 	/* Free any mapping info from Directory based mapping */
3344 	if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN)
3345 		idmap_info_free(&res->info);
3346 
3347 	/*
3348 	 * If we don't have unixname then evaluate local name-based
3349 	 * mapping rules.
3350 	 */
3351 	retcode = name_based_mapping_sid2pid(state, req, res);
3352 	if (retcode != IDMAP_ERR_NOTFOUND)
3353 		goto out;
3354 
3355 do_eph:
3356 	/* If not found, do ephemeral mapping */
3357 	retcode = dynamic_ephemeral_mapping(state, req, res);
3358 
3359 out:
3360 	res->retcode = idmap_stat4prot(retcode);
3361 	if (res->retcode != IDMAP_SUCCESS) {
3362 		req->direction = _IDMAP_F_DONE;
3363 		res->id.idmap_id_u.uid = UID_NOBODY;
3364 	}
3365 	if (!ARE_WE_DONE(req->direction))
3366 		state->sid2pid_done = FALSE;
3367 	return (retcode);
3368 }
3369 
3370 idmap_retcode
3371 update_cache_pid2sid(lookup_state_t *state,
3372 		idmap_mapping *req, idmap_id_res *res)
3373 {
3374 	char		*sql = NULL;
3375 	idmap_retcode	retcode;
3376 	char		*map_dn = NULL;
3377 	char		*map_attr = NULL;
3378 	char		*map_value = NULL;
3379 	char 		*map_windomain = NULL;
3380 	char		*map_winname = NULL;
3381 	char		*map_unixname = NULL;
3382 	int		map_is_nt4 = FALSE;
3383 
3384 	/* Check if we need to cache anything */
3385 	if (ARE_WE_DONE(req->direction))
3386 		return (IDMAP_SUCCESS);
3387 
3388 	/* We don't cache negative entries */
3389 	if (res->retcode != IDMAP_SUCCESS)
3390 		return (IDMAP_SUCCESS);
3391 
3392 	assert(res->direction != IDMAP_DIRECTION_UNDEF);
3393 	assert(req->id1.idmap_id_u.uid != SENTINEL_PID);
3394 	assert(res->id.idtype != IDMAP_SID);
3395 
3396 	assert(res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN);
3397 	switch (res->info.how.map_type) {
3398 	case IDMAP_MAP_TYPE_DS_AD:
3399 		map_dn = res->info.how.idmap_how_u.ad.dn;
3400 		map_attr = res->info.how.idmap_how_u.ad.attr;
3401 		map_value = res->info.how.idmap_how_u.ad.value;
3402 		break;
3403 
3404 	case IDMAP_MAP_TYPE_DS_NLDAP:
3405 		map_dn = res->info.how.idmap_how_u.nldap.dn;
3406 		map_attr = res->info.how.idmap_how_u.nldap.attr;
3407 		map_value = res->info.how.idmap_how_u.nldap.value;
3408 		break;
3409 
3410 	case IDMAP_MAP_TYPE_RULE_BASED:
3411 		map_windomain = res->info.how.idmap_how_u.rule.windomain;
3412 		map_winname = res->info.how.idmap_how_u.rule.winname;
3413 		map_unixname = res->info.how.idmap_how_u.rule.unixname;
3414 		map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4;
3415 		break;
3416 
3417 	case IDMAP_MAP_TYPE_EPHEMERAL:
3418 		break;
3419 
3420 	case IDMAP_MAP_TYPE_LOCAL_SID:
3421 		break;
3422 
3423 	default:
3424 		/* Dont cache other mapping types */
3425 		assert(FALSE);
3426 	}
3427 
3428 	/*
3429 	 * Using NULL for u2w instead of 0 so that our trigger allows
3430 	 * the same pid to be the destination in multiple entries
3431 	 */
3432 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3433 	    "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3434 	    "is_user, is_wuser, expiration, w2u, u2w, "
3435 	    "map_type, map_dn, map_attr, map_value, map_windomain, "
3436 	    "map_winname, map_unixname, map_is_nt4) "
3437 	    "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3438 	    "strftime('%%s','now') + 600, %q, 1, "
3439 	    "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d); ",
3440 	    res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid,
3441 	    req->id2domain, req->id2name, req->id1.idmap_id_u.uid,
3442 	    req->id1name, (req->id1.idtype == IDMAP_UID) ? 1 : 0,
3443 	    (res->id.idtype == IDMAP_USID) ? 1 : 0,
3444 	    (res->direction == 0) ? "1" : NULL,
3445 	    res->info.how.map_type, map_dn, map_attr, map_value,
3446 	    map_windomain, map_winname, map_unixname, map_is_nt4);
3447 
3448 	if (sql == NULL) {
3449 		retcode = IDMAP_ERR_INTERNAL;
3450 		idmapdlog(LOG_ERR, "Out of memory");
3451 		goto out;
3452 	}
3453 
3454 	retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3455 	if (retcode != IDMAP_SUCCESS)
3456 		goto out;
3457 
3458 	state->pid2sid_done = FALSE;
3459 	sqlite_freemem(sql);
3460 	sql = NULL;
3461 
3462 	/* Check if we need to update namecache */
3463 	if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE)
3464 		goto out;
3465 
3466 	if (req->id2name == NULL)
3467 		goto out;
3468 
3469 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
3470 	    "(sidprefix, rid, canon_name, domain, type, expiration) "
3471 	    "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
3472 	    res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid,
3473 	    req->id2name, req->id2domain,
3474 	    (res->id.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP);
3475 
3476 	if (sql == NULL) {
3477 		retcode = IDMAP_ERR_INTERNAL;
3478 		idmapdlog(LOG_ERR, "Out of memory");
3479 		goto out;
3480 	}
3481 
3482 	retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3483 
3484 out:
3485 	if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO))
3486 		idmap_info_free(&res->info);
3487 	if (sql != NULL)
3488 		sqlite_freemem(sql);
3489 	return (retcode);
3490 }
3491 
3492 idmap_retcode
3493 update_cache_sid2pid(lookup_state_t *state,
3494 		idmap_mapping *req, idmap_id_res *res)
3495 {
3496 	char		*sql = NULL;
3497 	idmap_retcode	retcode;
3498 	int		is_eph_user;
3499 	char		*map_dn = NULL;
3500 	char		*map_attr = NULL;
3501 	char		*map_value = NULL;
3502 	char 		*map_windomain = NULL;
3503 	char		*map_winname = NULL;
3504 	char		*map_unixname = NULL;
3505 	int		map_is_nt4 = FALSE;
3506 
3507 	/* Check if we need to cache anything */
3508 	if (ARE_WE_DONE(req->direction))
3509 		return (IDMAP_SUCCESS);
3510 
3511 	/* We don't cache negative entries */
3512 	if (res->retcode != IDMAP_SUCCESS)
3513 		return (IDMAP_SUCCESS);
3514 
3515 	if (req->direction & _IDMAP_F_EXP_EPH_UID)
3516 		is_eph_user = 1;
3517 	else if (req->direction & _IDMAP_F_EXP_EPH_GID)
3518 		is_eph_user = 0;
3519 	else
3520 		is_eph_user = -1;
3521 
3522 	if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
3523 		sql = sqlite_mprintf("UPDATE idmap_cache "
3524 		    "SET w2u = 0 WHERE "
3525 		    "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
3526 		    "pid >= 2147483648 AND is_user = %d;",
3527 		    req->id1.idmap_id_u.sid.prefix,
3528 		    req->id1.idmap_id_u.sid.rid,
3529 		    is_eph_user);
3530 		if (sql == NULL) {
3531 			retcode = IDMAP_ERR_INTERNAL;
3532 			idmapdlog(LOG_ERR, "Out of memory");
3533 			goto out;
3534 		}
3535 
3536 		retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3537 		if (retcode != IDMAP_SUCCESS)
3538 			goto out;
3539 
3540 		sqlite_freemem(sql);
3541 		sql = NULL;
3542 	}
3543 
3544 	assert(res->direction != IDMAP_DIRECTION_UNDEF);
3545 	assert(res->id.idmap_id_u.uid != SENTINEL_PID);
3546 
3547 	switch (res->info.how.map_type) {
3548 	case IDMAP_MAP_TYPE_DS_AD:
3549 		map_dn = res->info.how.idmap_how_u.ad.dn;
3550 		map_attr = res->info.how.idmap_how_u.ad.attr;
3551 		map_value = res->info.how.idmap_how_u.ad.value;
3552 		break;
3553 
3554 	case IDMAP_MAP_TYPE_DS_NLDAP:
3555 		map_dn = res->info.how.idmap_how_u.nldap.dn;
3556 		map_attr = res->info.how.idmap_how_u.ad.attr;
3557 		map_value = res->info.how.idmap_how_u.nldap.value;
3558 		break;
3559 
3560 	case IDMAP_MAP_TYPE_RULE_BASED:
3561 		map_windomain = res->info.how.idmap_how_u.rule.windomain;
3562 		map_winname = res->info.how.idmap_how_u.rule.winname;
3563 		map_unixname = res->info.how.idmap_how_u.rule.unixname;
3564 		map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4;
3565 		break;
3566 
3567 	case IDMAP_MAP_TYPE_EPHEMERAL:
3568 		break;
3569 
3570 	default:
3571 		/* Dont cache other mapping types */
3572 		assert(FALSE);
3573 	}
3574 
3575 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3576 	    "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3577 	    "is_user, is_wuser, expiration, w2u, u2w, "
3578 	    "map_type, map_dn, map_attr, map_value, map_windomain, "
3579 	    "map_winname, map_unixname, map_is_nt4) "
3580 	    "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3581 	    "strftime('%%s','now') + 600, 1, %q, "
3582 	    "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d);",
3583 	    req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid,
3584 	    (req->id1domain != NULL) ? req->id1domain : "", req->id1name,
3585 	    res->id.idmap_id_u.uid, req->id2name,
3586 	    (res->id.idtype == IDMAP_UID) ? 1 : 0,
3587 	    (req->id1.idtype == IDMAP_USID) ? 1 : 0,
3588 	    (res->direction == 0) ? "1" : NULL,
3589 	    res->info.how.map_type, map_dn, map_attr, map_value,
3590 	    map_windomain, map_winname, map_unixname, map_is_nt4);
3591 
3592 	if (sql == NULL) {
3593 		retcode = IDMAP_ERR_INTERNAL;
3594 		idmapdlog(LOG_ERR, "Out of memory");
3595 		goto out;
3596 	}
3597 
3598 	retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3599 	if (retcode != IDMAP_SUCCESS)
3600 		goto out;
3601 
3602 	state->sid2pid_done = FALSE;
3603 	sqlite_freemem(sql);
3604 	sql = NULL;
3605 
3606 	/* Check if we need to update namecache */
3607 	if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE)
3608 		goto out;
3609 
3610 	if (EMPTY_STRING(req->id1name))
3611 		goto out;
3612 
3613 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
3614 	    "(sidprefix, rid, canon_name, domain, type, expiration) "
3615 	    "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
3616 	    req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid,
3617 	    req->id1name, req->id1domain,
3618 	    (req->id1.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP);
3619 
3620 	if (sql == NULL) {
3621 		retcode = IDMAP_ERR_INTERNAL;
3622 		idmapdlog(LOG_ERR, "Out of memory");
3623 		goto out;
3624 	}
3625 
3626 	retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3627 
3628 out:
3629 	if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO))
3630 		idmap_info_free(&res->info);
3631 
3632 	if (sql != NULL)
3633 		sqlite_freemem(sql);
3634 	return (retcode);
3635 }
3636 
3637 static
3638 idmap_retcode
3639 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
3640 		int is_user, int getname)
3641 {
3642 	char		*end;
3643 	char		*sql = NULL;
3644 	const char	**values;
3645 	sqlite_vm	*vm = NULL;
3646 	int		ncol;
3647 	idmap_retcode	retcode = IDMAP_SUCCESS;
3648 	time_t		curtime;
3649 	idmap_id_type	idtype;
3650 
3651 	/* Current time */
3652 	errno = 0;
3653 	if ((curtime = time(NULL)) == (time_t)-1) {
3654 		idmapdlog(LOG_ERR, "Failed to get current time (%s)",
3655 		    strerror(errno));
3656 		retcode = IDMAP_ERR_INTERNAL;
3657 		goto out;
3658 	}
3659 
3660 	/* SQL to lookup the cache by pid or by unixname */
3661 	if (req->id1.idmap_id_u.uid != SENTINEL_PID) {
3662 		sql = sqlite_mprintf("SELECT sidprefix, rid, "
3663 		    "canon_winname, windomain, w2u, is_wuser, "
3664 		    "map_type, map_dn, map_attr, map_value, map_windomain, "
3665 		    "map_winname, map_unixname, map_is_nt4 "
3666 		    "FROM idmap_cache WHERE "
3667 		    "pid = %u AND u2w = 1 AND is_user = %d AND "
3668 		    "(pid >= 2147483648 OR "
3669 		    "(expiration = 0 OR expiration ISNULL OR "
3670 		    "expiration > %d));",
3671 		    req->id1.idmap_id_u.uid, is_user, curtime);
3672 	} else if (req->id1name != NULL) {
3673 		sql = sqlite_mprintf("SELECT sidprefix, rid, "
3674 		    "canon_winname, windomain, w2u, is_wuser, "
3675 		    "map_type, map_dn, map_attr, map_value, map_windomain, "
3676 		    "map_winname, map_unixname, map_is_nt4 "
3677 		    "FROM idmap_cache WHERE "
3678 		    "unixname = %Q AND u2w = 1 AND is_user = %d AND "
3679 		    "(pid >= 2147483648 OR "
3680 		    "(expiration = 0 OR expiration ISNULL OR "
3681 		    "expiration > %d));",
3682 		    req->id1name, is_user, curtime);
3683 	} else {
3684 		retcode = IDMAP_ERR_ARG;
3685 		goto out;
3686 	}
3687 
3688 	if (sql == NULL) {
3689 		idmapdlog(LOG_ERR, "Out of memory");
3690 		retcode = IDMAP_ERR_MEMORY;
3691 		goto out;
3692 	}
3693 	retcode = sql_compile_n_step_once(
3694 	    cache, sql, &vm, &ncol, 14, &values);
3695 	sqlite_freemem(sql);
3696 
3697 	if (retcode == IDMAP_ERR_NOTFOUND)
3698 		goto out;
3699 	else if (retcode == IDMAP_SUCCESS) {
3700 		/* sanity checks */
3701 		if (values[0] == NULL || values[1] == NULL) {
3702 			retcode = IDMAP_ERR_CACHE;
3703 			goto out;
3704 		}
3705 
3706 		switch (res->id.idtype) {
3707 		case IDMAP_SID:
3708 		case IDMAP_USID:
3709 		case IDMAP_GSID:
3710 			idtype = strtol(values[5], &end, 10) == 1
3711 			    ? IDMAP_USID : IDMAP_GSID;
3712 
3713 			if (res->id.idtype == IDMAP_USID &&
3714 			    idtype != IDMAP_USID) {
3715 				retcode = IDMAP_ERR_NOTUSER;
3716 				goto out;
3717 			} else if (res->id.idtype == IDMAP_GSID &&
3718 			    idtype != IDMAP_GSID) {
3719 				retcode = IDMAP_ERR_NOTGROUP;
3720 				goto out;
3721 			}
3722 			res->id.idtype = idtype;
3723 
3724 			res->id.idmap_id_u.sid.rid =
3725 			    strtoul(values[1], &end, 10);
3726 			res->id.idmap_id_u.sid.prefix = strdup(values[0]);
3727 			if (res->id.idmap_id_u.sid.prefix == NULL) {
3728 				idmapdlog(LOG_ERR, "Out of memory");
3729 				retcode = IDMAP_ERR_MEMORY;
3730 				goto out;
3731 			}
3732 
3733 			if (values[4] != NULL)
3734 				res->direction =
3735 				    (strtol(values[4], &end, 10) == 0)?
3736 				    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
3737 			else
3738 				res->direction = IDMAP_DIRECTION_U2W;
3739 
3740 			if (getname == 0 || values[2] == NULL)
3741 				break;
3742 			req->id2name = strdup(values[2]);
3743 			if (req->id2name == NULL) {
3744 				idmapdlog(LOG_ERR, "Out of memory");
3745 				retcode = IDMAP_ERR_MEMORY;
3746 				goto out;
3747 			}
3748 
3749 			if (values[3] == NULL)
3750 				break;
3751 			req->id2domain = strdup(values[3]);
3752 			if (req->id2domain == NULL) {
3753 				idmapdlog(LOG_ERR, "Out of memory");
3754 				retcode = IDMAP_ERR_MEMORY;
3755 				goto out;
3756 			}
3757 
3758 			break;
3759 		default:
3760 			retcode = IDMAP_ERR_NOTSUPPORTED;
3761 			break;
3762 		}
3763 		if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) {
3764 			res->info.src = IDMAP_MAP_SRC_CACHE;
3765 			res->info.how.map_type = strtoul(values[6], &end, 10);
3766 			switch (res->info.how.map_type) {
3767 			case IDMAP_MAP_TYPE_DS_AD:
3768 				res->info.how.idmap_how_u.ad.dn =
3769 				    strdup(values[7]);
3770 				res->info.how.idmap_how_u.ad.attr =
3771 				    strdup(values[8]);
3772 				res->info.how.idmap_how_u.ad.value =
3773 				    strdup(values[9]);
3774 				break;
3775 
3776 			case IDMAP_MAP_TYPE_DS_NLDAP:
3777 				res->info.how.idmap_how_u.nldap.dn =
3778 				    strdup(values[7]);
3779 				res->info.how.idmap_how_u.nldap.attr =
3780 				    strdup(values[8]);
3781 				res->info.how.idmap_how_u.nldap.value =
3782 				    strdup(values[9]);
3783 				break;
3784 
3785 			case IDMAP_MAP_TYPE_RULE_BASED:
3786 				res->info.how.idmap_how_u.rule.windomain =
3787 				    strdup(values[10]);
3788 				res->info.how.idmap_how_u.rule.winname =
3789 				    strdup(values[11]);
3790 				res->info.how.idmap_how_u.rule.unixname =
3791 				    strdup(values[12]);
3792 				res->info.how.idmap_how_u.rule.is_nt4 =
3793 				    strtoul(values[13], &end, 10);
3794 				res->info.how.idmap_how_u.rule.is_user =
3795 				    is_user;
3796 				res->info.how.idmap_how_u.rule.is_wuser =
3797 				    strtol(values[5], &end, 10);
3798 				break;
3799 
3800 			case IDMAP_MAP_TYPE_EPHEMERAL:
3801 				break;
3802 
3803 			case IDMAP_MAP_TYPE_LOCAL_SID:
3804 				break;
3805 
3806 			case IDMAP_MAP_TYPE_KNOWN_SID:
3807 				break;
3808 
3809 			default:
3810 				/* Unknow mapping type */
3811 				assert(FALSE);
3812 			}
3813 		}
3814 	}
3815 
3816 out:
3817 	if (vm != NULL)
3818 		(void) sqlite_finalize(vm, NULL);
3819 	return (retcode);
3820 }
3821 
3822 /*
3823  * Given:
3824  * cache	sqlite handle
3825  * name		Windows user name
3826  * domain	Windows domain name
3827  *
3828  * Return:  Error code
3829  *
3830  * *canonname	Canonical name (if canonname is non-NULL) [1]
3831  * *sidprefix	SID prefix [1]
3832  * *rid		RID
3833  * *type	Type of name
3834  *
3835  * [1] malloc'ed, NULL on error
3836  */
3837 static
3838 idmap_retcode
3839 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain,
3840 	char **canonname, char **sidprefix, idmap_rid_t *rid, int *type)
3841 {
3842 	char		*end, *lower_name;
3843 	char		*sql;
3844 	const char	**values;
3845 	sqlite_vm	*vm = NULL;
3846 	int		ncol;
3847 	time_t		curtime;
3848 	idmap_retcode	retcode;
3849 
3850 	*sidprefix = NULL;
3851 	if (canonname != NULL)
3852 		*canonname = NULL;
3853 
3854 	/* Get current time */
3855 	errno = 0;
3856 	if ((curtime = time(NULL)) == (time_t)-1) {
3857 		idmapdlog(LOG_ERR, "Failed to get current time (%s)",
3858 		    strerror(errno));
3859 		retcode = IDMAP_ERR_INTERNAL;
3860 		goto out;
3861 	}
3862 
3863 	/* SQL to lookup the cache */
3864 	if ((lower_name = tolower_u8(name)) == NULL)
3865 		lower_name = (char *)name;
3866 	sql = sqlite_mprintf("SELECT sidprefix, rid, type, canon_name "
3867 	    "FROM name_cache WHERE name = %Q AND domain = %Q AND "
3868 	    "(expiration = 0 OR expiration ISNULL OR "
3869 	    "expiration > %d);", lower_name, domain, curtime);
3870 	if (lower_name != name)
3871 		free(lower_name);
3872 	if (sql == NULL) {
3873 		idmapdlog(LOG_ERR, "Out of memory");
3874 		retcode = IDMAP_ERR_MEMORY;
3875 		goto out;
3876 	}
3877 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 4, &values);
3878 
3879 	sqlite_freemem(sql);
3880 
3881 	if (retcode != IDMAP_SUCCESS)
3882 		goto out;
3883 
3884 	if (type != NULL) {
3885 		if (values[2] == NULL) {
3886 			retcode = IDMAP_ERR_CACHE;
3887 			goto out;
3888 		}
3889 		*type = strtol(values[2], &end, 10);
3890 	}
3891 
3892 	if (values[0] == NULL || values[1] == NULL) {
3893 		retcode = IDMAP_ERR_CACHE;
3894 		goto out;
3895 	}
3896 
3897 	if (canonname != NULL) {
3898 		assert(values[3] != NULL);
3899 		*canonname = strdup(values[3]);
3900 		if (*canonname == NULL) {
3901 			idmapdlog(LOG_ERR, "Out of memory");
3902 			retcode = IDMAP_ERR_MEMORY;
3903 			goto out;
3904 		}
3905 	}
3906 
3907 	*sidprefix = strdup(values[0]);
3908 	if (*sidprefix == NULL) {
3909 		idmapdlog(LOG_ERR, "Out of memory");
3910 		retcode = IDMAP_ERR_MEMORY;
3911 		goto out;
3912 	}
3913 	*rid = strtoul(values[1], &end, 10);
3914 
3915 	retcode = IDMAP_SUCCESS;
3916 
3917 out:
3918 	if (vm != NULL)
3919 		(void) sqlite_finalize(vm, NULL);
3920 
3921 	if (retcode != IDMAP_SUCCESS) {
3922 		free(*sidprefix);
3923 		*sidprefix = NULL;
3924 		if (canonname != NULL) {
3925 			free(*canonname);
3926 			*canonname = NULL;
3927 		}
3928 	}
3929 	return (retcode);
3930 }
3931 
3932 static
3933 idmap_retcode
3934 ad_lookup_by_winname(lookup_state_t *state,
3935 		const char *name, const char *domain, int eunixtype,
3936 		char **dn, char **attr, char **value, char **canonname,
3937 		char **sidprefix, idmap_rid_t *rid, int *wintype,
3938 		char **unixname)
3939 {
3940 	int			retries;
3941 	idmap_query_state_t	*qs = NULL;
3942 	idmap_retcode		rc, retcode;
3943 	int			i;
3944 	int			found_ad = 0;
3945 
3946 	RDLOCK_CONFIG();
3947 	if (_idmapdstate.num_ads > 0) {
3948 		for (i = 0; i < _idmapdstate.num_ads && !found_ad; i++) {
3949 			retries = 0;
3950 retry:
3951 			retcode = idmap_lookup_batch_start(_idmapdstate.ads[i],
3952 			    1, &qs);
3953 			if (retcode != IDMAP_SUCCESS) {
3954 				if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
3955 				    retries++ < ADUTILS_DEF_NUM_RETRIES)
3956 					goto retry;
3957 				degrade_svc(1, "failed to create request for "
3958 				    "AD lookup by winname");
3959 				return (retcode);
3960 			}
3961 
3962 			restore_svc();
3963 
3964 			if (state != NULL && i == 0) {
3965 				/*
3966 				 * Directory based name mapping is only
3967 				 * performed within the joined forest (i == 0).
3968 				 * We don't trust other "trusted" forests to
3969 				 * provide DS-based name mapping information
3970 				 * because AD's definition of "cross-forest
3971 				 * trust" does not encompass this sort of
3972 				 * behavior.
3973 				 */
3974 				idmap_lookup_batch_set_unixattr(qs,
3975 				    state->ad_unixuser_attr,
3976 				    state->ad_unixgroup_attr);
3977 			}
3978 
3979 			retcode = idmap_name2sid_batch_add1(qs, name, domain,
3980 			    eunixtype, dn, attr, value, canonname, sidprefix,
3981 			    rid, wintype, unixname, &rc);
3982 			if (retcode == IDMAP_ERR_DOMAIN_NOTFOUND) {
3983 				idmap_lookup_release_batch(&qs);
3984 				continue;
3985 			}
3986 			found_ad = 1;
3987 			if (retcode != IDMAP_SUCCESS)
3988 				idmap_lookup_release_batch(&qs);
3989 			else
3990 				retcode = idmap_lookup_batch_end(&qs);
3991 
3992 			if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
3993 			    retries++ < ADUTILS_DEF_NUM_RETRIES)
3994 				goto retry;
3995 			else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
3996 				degrade_svc(1,
3997 				    "some AD lookups timed out repeatedly");
3998 		}
3999 	} else {
4000 		/* No AD case */
4001 		retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
4002 	}
4003 	UNLOCK_CONFIG();
4004 
4005 	if (retcode != IDMAP_SUCCESS) {
4006 		idmapdlog(LOG_NOTICE, "AD lookup by winname failed");
4007 		return (retcode);
4008 	}
4009 	return (rc);
4010 }
4011 
4012 /*
4013  * Given:
4014  * cache	sqlite handle to cache
4015  * name		Windows user name
4016  * domain	Windows domain name
4017  * local_only	if true, don't try AD lookups
4018  *
4019  * Returns: Error code
4020  *
4021  * *canonname	Canonical name (if non-NULL) [1]
4022  * *canondomain	Canonical domain (if non-NULL) [1]
4023  * *sidprefix	SID prefix [1]
4024  * *rid		RID
4025  * *req		Request (direction is updated)
4026  *
4027  * [1] malloc'ed, NULL on error
4028  */
4029 idmap_retcode
4030 lookup_name2sid(
4031     sqlite *cache,
4032     const char *name,
4033     const char *domain,
4034     int *is_wuser,
4035     char **canonname,
4036     char **canondomain,
4037     char **sidprefix,
4038     idmap_rid_t *rid,
4039     idmap_mapping *req,
4040     int local_only)
4041 {
4042 	int		type;
4043 	idmap_retcode	retcode;
4044 
4045 	*sidprefix = NULL;
4046 	if (canonname != NULL)
4047 		*canonname = NULL;
4048 	if (canondomain != NULL)
4049 		*canondomain = NULL;
4050 
4051 	/* Lookup well-known SIDs table */
4052 	retcode = lookup_wksids_name2sid(name, domain, canonname, canondomain,
4053 	    sidprefix, rid, &type);
4054 	if (retcode == IDMAP_SUCCESS) {
4055 		req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
4056 		goto out;
4057 	} else if (retcode != IDMAP_ERR_NOTFOUND) {
4058 		return (retcode);
4059 	}
4060 
4061 	/* Lookup cache */
4062 	retcode = lookup_cache_name2sid(cache, name, domain, canonname,
4063 	    sidprefix, rid, &type);
4064 	if (retcode == IDMAP_SUCCESS) {
4065 		req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
4066 		goto out;
4067 	} else if (retcode != IDMAP_ERR_NOTFOUND) {
4068 		return (retcode);
4069 	}
4070 
4071 	/*
4072 	 * The caller may be using this function to determine if this
4073 	 * request needs to be marked for AD lookup or not
4074 	 * (i.e. _IDMAP_F_LOOKUP_AD) and therefore may not want this
4075 	 * function to AD lookup now.
4076 	 */
4077 	if (local_only)
4078 		return (retcode);
4079 
4080 	/* Lookup AD */
4081 	retcode = ad_lookup_by_winname(NULL, name, domain, _IDMAP_T_UNDEF,
4082 	    NULL, NULL, NULL, canonname, sidprefix, rid, &type, NULL);
4083 	if (retcode != IDMAP_SUCCESS)
4084 		return (retcode);
4085 
4086 out:
4087 	/*
4088 	 * Entry found (cache or Windows lookup)
4089 	 * is_wuser is both input as well as output parameter
4090 	 */
4091 	if (*is_wuser == 1 && type != _IDMAP_T_USER)
4092 		retcode = IDMAP_ERR_NOTUSER;
4093 	else if (*is_wuser == 0 && type != _IDMAP_T_GROUP)
4094 		retcode = IDMAP_ERR_NOTGROUP;
4095 	else if (*is_wuser == -1) {
4096 		/* Caller wants to know if its user or group */
4097 		if (type == _IDMAP_T_USER)
4098 			*is_wuser = 1;
4099 		else if (type == _IDMAP_T_GROUP)
4100 			*is_wuser = 0;
4101 		else
4102 			retcode = IDMAP_ERR_SID;
4103 	}
4104 
4105 	if (retcode == IDMAP_SUCCESS) {
4106 		/*
4107 		 * If we were asked for a canonical domain and none
4108 		 * of the searches have provided one, assume it's the
4109 		 * supplied domain.
4110 		 */
4111 		if (canondomain != NULL && *canondomain == NULL) {
4112 			*canondomain = strdup(domain);
4113 			if (*canondomain == NULL)
4114 				retcode = IDMAP_ERR_MEMORY;
4115 		}
4116 	}
4117 	if (retcode != IDMAP_SUCCESS) {
4118 		free(*sidprefix);
4119 		*sidprefix = NULL;
4120 		if (canonname != NULL) {
4121 			free(*canonname);
4122 			*canonname = NULL;
4123 		}
4124 		if (canondomain != NULL) {
4125 			free(*canondomain);
4126 			*canondomain = NULL;
4127 		}
4128 	}
4129 	return (retcode);
4130 }
4131 
4132 static
4133 idmap_retcode
4134 name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname,
4135 		int is_user, idmap_mapping *req, idmap_id_res *res)
4136 {
4137 	const char	*winname, *windomain;
4138 	char		*canonname;
4139 	char		*canondomain;
4140 	char		*sql = NULL, *errmsg = NULL;
4141 	idmap_retcode	retcode;
4142 	char		*end;
4143 	const char	**values;
4144 	sqlite_vm	*vm = NULL;
4145 	int		ncol, r;
4146 	int		is_wuser;
4147 	const char	*me = "name_based_mapping_pid2sid";
4148 	int 		non_wild_match = FALSE;
4149 	idmap_namerule	*rule = &res->info.how.idmap_how_u.rule;
4150 	int direction;
4151 
4152 	assert(unixname != NULL); /* We have unixname */
4153 	assert(req->id2name == NULL); /* We don't have winname */
4154 	assert(res->id.idmap_id_u.sid.prefix == NULL); /* No SID either */
4155 
4156 	sql = sqlite_mprintf(
4157 	    "SELECT winname_display, windomain, w2u_order, "
4158 	    "is_wuser, unixname, is_nt4 "
4159 	    "FROM namerules WHERE "
4160 	    "u2w_order > 0 AND is_user = %d AND "
4161 	    "(unixname = %Q OR unixname = '*') "
4162 	    "ORDER BY u2w_order ASC;", is_user, unixname);
4163 	if (sql == NULL) {
4164 		idmapdlog(LOG_ERR, "Out of memory");
4165 		retcode = IDMAP_ERR_MEMORY;
4166 		goto out;
4167 	}
4168 
4169 	if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
4170 		retcode = IDMAP_ERR_INTERNAL;
4171 		idmapdlog(LOG_ERR, "%s: database error (%s)", me,
4172 		    CHECK_NULL(errmsg));
4173 		sqlite_freemem(errmsg);
4174 		goto out;
4175 	}
4176 
4177 	for (;;) {
4178 		r = sqlite_step(vm, &ncol, &values, NULL);
4179 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
4180 		if (r == SQLITE_ROW) {
4181 			if (ncol < 6) {
4182 				retcode = IDMAP_ERR_INTERNAL;
4183 				goto out;
4184 			}
4185 			if (values[0] == NULL) {
4186 				/* values [1] and [2] can be null */
4187 				retcode = IDMAP_ERR_INTERNAL;
4188 				goto out;
4189 			}
4190 
4191 			if (values[2] != NULL)
4192 				direction =
4193 				    (strtol(values[2], &end, 10) == 0)?
4194 				    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
4195 			else
4196 				direction = IDMAP_DIRECTION_U2W;
4197 
4198 			if (EMPTY_NAME(values[0])) {
4199 				idmap_namerule_set(rule, values[1], values[0],
4200 				    values[4], is_user,
4201 				    strtol(values[3], &end, 10),
4202 				    strtol(values[5], &end, 10),
4203 				    direction);
4204 				retcode = IDMAP_ERR_NOMAPPING;
4205 				goto out;
4206 			}
4207 
4208 			if (values[0][0] == '*') {
4209 				winname = unixname;
4210 				if (non_wild_match) {
4211 					/*
4212 					 * There were non-wildcard rules
4213 					 * where the Windows identity doesn't
4214 					 * exist. Return no mapping.
4215 					 */
4216 					retcode = IDMAP_ERR_NOMAPPING;
4217 					goto out;
4218 				}
4219 			} else {
4220 				/* Save first non-wild match rule */
4221 				if (!non_wild_match) {
4222 					idmap_namerule_set(rule, values[1],
4223 					    values[0], values[4],
4224 					    is_user,
4225 					    strtol(values[3], &end, 10),
4226 					    strtol(values[5], &end, 10),
4227 					    direction);
4228 					non_wild_match = TRUE;
4229 				}
4230 				winname = values[0];
4231 			}
4232 			is_wuser = res->id.idtype == IDMAP_USID ? 1
4233 			    : res->id.idtype == IDMAP_GSID ? 0
4234 			    : -1;
4235 			if (values[1] != NULL)
4236 				windomain = values[1];
4237 			else if (state->defdom != NULL)
4238 				windomain = state->defdom;
4239 			else {
4240 				idmapdlog(LOG_ERR, "%s: no domain", me);
4241 				retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
4242 				goto out;
4243 			}
4244 
4245 			retcode = lookup_name2sid(state->cache,
4246 			    winname, windomain,
4247 			    &is_wuser, &canonname, &canondomain,
4248 			    &res->id.idmap_id_u.sid.prefix,
4249 			    &res->id.idmap_id_u.sid.rid, req, 0);
4250 
4251 			if (retcode == IDMAP_ERR_NOTFOUND) {
4252 				continue;
4253 			}
4254 			goto out;
4255 
4256 		} else if (r == SQLITE_DONE) {
4257 			/*
4258 			 * If there were non-wildcard rules where
4259 			 * Windows identity doesn't exist
4260 			 * return no mapping.
4261 			 */
4262 			if (non_wild_match)
4263 				retcode = IDMAP_ERR_NOMAPPING;
4264 			else
4265 				retcode = IDMAP_ERR_NOTFOUND;
4266 			goto out;
4267 		} else {
4268 			(void) sqlite_finalize(vm, &errmsg);
4269 			vm = NULL;
4270 			idmapdlog(LOG_ERR, "%s: database error (%s)", me,
4271 			    CHECK_NULL(errmsg));
4272 			sqlite_freemem(errmsg);
4273 			retcode = IDMAP_ERR_INTERNAL;
4274 			goto out;
4275 		}
4276 	}
4277 
4278 out:
4279 	if (sql != NULL)
4280 		sqlite_freemem(sql);
4281 	if (retcode == IDMAP_SUCCESS) {
4282 		res->id.idtype = is_wuser ? IDMAP_USID : IDMAP_GSID;
4283 
4284 		if (values[2] != NULL)
4285 			res->direction =
4286 			    (strtol(values[2], &end, 10) == 0)?
4287 			    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
4288 		else
4289 			res->direction = IDMAP_DIRECTION_U2W;
4290 
4291 		req->id2name = canonname;
4292 		req->id2domain = canondomain;
4293 	}
4294 
4295 	if (retcode == IDMAP_SUCCESS) {
4296 		idmap_namerule_set(rule, values[1], values[0], values[4],
4297 		    is_user, strtol(values[3], &end, 10),
4298 		    strtol(values[5], &end, 10),
4299 		    rule->direction);
4300 	}
4301 
4302 	if (retcode != IDMAP_ERR_NOTFOUND) {
4303 		res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED;
4304 		res->info.src = IDMAP_MAP_SRC_NEW;
4305 	}
4306 
4307 	if (vm != NULL)
4308 		(void) sqlite_finalize(vm, NULL);
4309 	return (retcode);
4310 }
4311 
4312 /*
4313  * Convention when processing unix2win requests:
4314  *
4315  * Unix identity:
4316  * req->id1name =
4317  *              unixname if given otherwise unixname found will be placed
4318  *              here.
4319  * req->id1domain =
4320  *              NOT USED
4321  * req->id1.idtype =
4322  *              Given type (IDMAP_UID or IDMAP_GID)
4323  * req->id1..[uid or gid] =
4324  *              UID/GID if given otherwise UID/GID found will be placed here.
4325  *
4326  * Windows identity:
4327  * req->id2name =
4328  *              winname found will be placed here.
4329  * req->id2domain =
4330  *              windomain found will be placed here.
4331  * res->id.idtype =
4332  *              Target type initialized from req->id2.idtype. If
4333  *              it is IDMAP_SID then actual type (IDMAP_USID/GSID) found
4334  *              will be placed here.
4335  * req->id..sid.[prefix, rid] =
4336  *              SID found will be placed here.
4337  *
4338  * Others:
4339  * res->retcode =
4340  *              Return status for this request will be placed here.
4341  * res->direction =
4342  *              Direction found will be placed here. Direction
4343  *              meaning whether the resultant mapping is valid
4344  *              only from unix2win or bi-directional.
4345  * req->direction =
4346  *              INTERNAL USE. Used by idmapd to set various
4347  *              flags (_IDMAP_F_xxxx) to aid in processing
4348  *              of the request.
4349  * req->id2.idtype =
4350  *              INTERNAL USE. Initially this is the requested target
4351  *              type and is used to initialize res->id.idtype.
4352  *              ad_lookup_batch() uses this field temporarily to store
4353  *              sid_type obtained by the batched AD lookups and after
4354  *              use resets it to IDMAP_NONE to prevent xdr from
4355  *              mis-interpreting the contents of req->id2.
4356  * req->id2..[uid or gid or sid] =
4357  *              NOT USED
4358  */
4359 
4360 /*
4361  * This function does the following:
4362  * 1. Lookup well-known SIDs table.
4363  * 2. Lookup cache.
4364  * 3. Check if the client does not want new mapping to be allocated
4365  *    in which case this pass is the final pass.
4366  * 4. Set AD/NLDAP lookup flags if it determines that the next stage needs
4367  *    to do AD/NLDAP lookup.
4368  */
4369 idmap_retcode
4370 pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req,
4371 		idmap_id_res *res, int is_user, int getname)
4372 {
4373 	idmap_retcode	retcode;
4374 	bool_t		gen_localsid_on_err = FALSE;
4375 
4376 	/* Initialize result */
4377 	res->id.idtype = req->id2.idtype;
4378 	res->direction = IDMAP_DIRECTION_UNDEF;
4379 
4380 	if (req->id2.idmap_id_u.sid.prefix != NULL) {
4381 		/* sanitize sidprefix */
4382 		free(req->id2.idmap_id_u.sid.prefix);
4383 		req->id2.idmap_id_u.sid.prefix = NULL;
4384 	}
4385 
4386 	/* Find pid */
4387 	if (req->id1.idmap_id_u.uid == SENTINEL_PID) {
4388 		if (ns_lookup_byname(req->id1name, NULL, &req->id1)
4389 		    != IDMAP_SUCCESS) {
4390 			retcode = IDMAP_ERR_NOMAPPING;
4391 			goto out;
4392 		}
4393 	}
4394 
4395 	/* Lookup in well-known SIDs table */
4396 	retcode = lookup_wksids_pid2sid(req, res, is_user);
4397 	if (retcode != IDMAP_ERR_NOTFOUND)
4398 		goto out;
4399 
4400 	/* Lookup in cache */
4401 	retcode = lookup_cache_pid2sid(state->cache, req, res, is_user,
4402 	    getname);
4403 	if (retcode != IDMAP_ERR_NOTFOUND)
4404 		goto out;
4405 
4406 	/* Ephemeral ids cannot be allocated during pid2sid */
4407 	if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) {
4408 		retcode = IDMAP_ERR_NOMAPPING;
4409 		goto out;
4410 	}
4411 
4412 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req)) {
4413 		retcode = IDMAP_ERR_NONE_GENERATED;
4414 		goto out;
4415 	}
4416 
4417 	if (AVOID_NAMESERVICE(req)) {
4418 		gen_localsid_on_err = TRUE;
4419 		retcode = IDMAP_ERR_NOMAPPING;
4420 		goto out;
4421 	}
4422 
4423 	/* Set flags for the next stage */
4424 	if (AD_MODE(req->id1.idtype, state)) {
4425 		/*
4426 		 * If AD-based name mapping is enabled then the next stage
4427 		 * will need to lookup AD using unixname to get the
4428 		 * corresponding winname.
4429 		 */
4430 		if (req->id1name == NULL) {
4431 			/* Get unixname if only pid is given. */
4432 			retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid,
4433 			    is_user, &req->id1name);
4434 			if (retcode != IDMAP_SUCCESS) {
4435 				gen_localsid_on_err = TRUE;
4436 				goto out;
4437 			}
4438 		}
4439 		req->direction |= _IDMAP_F_LOOKUP_AD;
4440 		state->ad_nqueries++;
4441 	} else if (NLDAP_OR_MIXED_MODE(req->id1.idtype, state)) {
4442 		/*
4443 		 * If native LDAP or mixed mode is enabled for name mapping
4444 		 * then the next stage will need to lookup native LDAP using
4445 		 * unixname/pid to get the corresponding winname.
4446 		 */
4447 		req->direction |= _IDMAP_F_LOOKUP_NLDAP;
4448 		state->nldap_nqueries++;
4449 	}
4450 
4451 	/*
4452 	 * Failed to find non-expired entry in cache. Set the flag to
4453 	 * indicate that we are not done yet.
4454 	 */
4455 	state->pid2sid_done = FALSE;
4456 	req->direction |= _IDMAP_F_NOTDONE;
4457 	retcode = IDMAP_SUCCESS;
4458 
4459 out:
4460 	res->retcode = idmap_stat4prot(retcode);
4461 	if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS)
4462 		if (gen_localsid_on_err == TRUE)
4463 			(void) generate_localsid(req, res, is_user, TRUE);
4464 	return (retcode);
4465 }
4466 
4467 idmap_retcode
4468 pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req,
4469 	idmap_id_res *res, int is_user)
4470 {
4471 	bool_t		gen_localsid_on_err = TRUE;
4472 	idmap_retcode	retcode = IDMAP_SUCCESS;
4473 
4474 	/* Check if second pass is needed */
4475 	if (ARE_WE_DONE(req->direction))
4476 		return (res->retcode);
4477 
4478 	/* Get status from previous pass */
4479 	retcode = res->retcode;
4480 	if (retcode != IDMAP_SUCCESS)
4481 		goto out;
4482 
4483 	/*
4484 	 * If directory-based name mapping is enabled then the winname
4485 	 * may already have been retrieved from the AD object (AD-mode)
4486 	 * or from native LDAP object (nldap-mode or mixed-mode).
4487 	 * Note that if we have winname but no SID then it's an error
4488 	 * because this implies that the Native LDAP entry contains
4489 	 * winname which does not exist and it's better that we return
4490 	 * an error instead of doing rule-based mapping so that the user
4491 	 * can detect the issue and take appropriate action.
4492 	 */
4493 	if (req->id2name != NULL) {
4494 		/* Return notfound if we've winname but no SID. */
4495 		if (res->id.idmap_id_u.sid.prefix == NULL) {
4496 			retcode = IDMAP_ERR_NOTFOUND;
4497 			goto out;
4498 		}
4499 		if (AD_MODE(req->id1.idtype, state))
4500 			res->direction = IDMAP_DIRECTION_BI;
4501 		else if (NLDAP_MODE(req->id1.idtype, state))
4502 			res->direction = IDMAP_DIRECTION_BI;
4503 		else if (MIXED_MODE(req->id1.idtype, state))
4504 			res->direction = IDMAP_DIRECTION_W2U;
4505 		goto out;
4506 	} else if (res->id.idmap_id_u.sid.prefix != NULL) {
4507 		/*
4508 		 * We've SID but no winname. This is fine because
4509 		 * the caller may have only requested SID.
4510 		 */
4511 		goto out;
4512 	}
4513 
4514 	/* Free any mapping info from Directory based mapping */
4515 	if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN)
4516 		idmap_info_free(&res->info);
4517 
4518 	if (req->id1name == NULL) {
4519 		/* Get unixname from name service */
4520 		retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, is_user,
4521 		    &req->id1name);
4522 		if (retcode != IDMAP_SUCCESS)
4523 			goto out;
4524 	} else if (req->id1.idmap_id_u.uid == SENTINEL_PID) {
4525 		/* Get pid from name service */
4526 		retcode = ns_lookup_byname(req->id1name, NULL, &req->id1);
4527 		if (retcode != IDMAP_SUCCESS) {
4528 			gen_localsid_on_err = FALSE;
4529 			goto out;
4530 		}
4531 	}
4532 
4533 	/* Use unixname to evaluate local name-based mapping rules */
4534 	retcode = name_based_mapping_pid2sid(state, req->id1name, is_user,
4535 	    req, res);
4536 	if (retcode == IDMAP_ERR_NOTFOUND) {
4537 		retcode = generate_localsid(req, res, is_user, FALSE);
4538 		gen_localsid_on_err = FALSE;
4539 	}
4540 
4541 out:
4542 	res->retcode = idmap_stat4prot(retcode);
4543 	if (res->retcode != IDMAP_SUCCESS) {
4544 		req->direction = _IDMAP_F_DONE;
4545 		free(req->id2name);
4546 		req->id2name = NULL;
4547 		free(req->id2domain);
4548 		req->id2domain = NULL;
4549 		if (gen_localsid_on_err == TRUE)
4550 			(void) generate_localsid(req, res, is_user, TRUE);
4551 		else
4552 			res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID;
4553 	}
4554 	if (!ARE_WE_DONE(req->direction))
4555 		state->pid2sid_done = FALSE;
4556 	return (retcode);
4557 }
4558 
4559 static
4560 int
4561 copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request)
4562 {
4563 	(void) memset(mapping, 0, sizeof (*mapping));
4564 
4565 	mapping->flag = request->flag;
4566 	mapping->direction = _IDMAP_F_DONE;
4567 	mapping->id2.idtype = request->id2.idtype;
4568 
4569 	mapping->id1.idtype = request->id1.idtype;
4570 	if (IS_REQUEST_SID(*request, 1)) {
4571 		mapping->id1.idmap_id_u.sid.rid =
4572 		    request->id1.idmap_id_u.sid.rid;
4573 		if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) {
4574 			mapping->id1.idmap_id_u.sid.prefix =
4575 			    strdup(request->id1.idmap_id_u.sid.prefix);
4576 			if (mapping->id1.idmap_id_u.sid.prefix == NULL)
4577 				goto errout;
4578 		}
4579 	} else {
4580 		mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid;
4581 	}
4582 
4583 	if (!EMPTY_STRING(request->id1domain)) {
4584 		mapping->id1domain = strdup(request->id1domain);
4585 		if (mapping->id1domain == NULL)
4586 			goto errout;
4587 	}
4588 
4589 	if (!EMPTY_STRING(request->id1name)) {
4590 		mapping->id1name = strdup(request->id1name);
4591 		if (mapping->id1name == NULL)
4592 			goto errout;
4593 	}
4594 
4595 	/* We don't need the rest of the request i.e request->id2 */
4596 	return (0);
4597 
4598 errout:
4599 	if (mapping->id1.idmap_id_u.sid.prefix != NULL)
4600 		free(mapping->id1.idmap_id_u.sid.prefix);
4601 	if (mapping->id1domain != NULL)
4602 		free(mapping->id1domain);
4603 	if (mapping->id1name != NULL)
4604 		free(mapping->id1name);
4605 
4606 	(void) memset(mapping, 0, sizeof (*mapping));
4607 	return (-1);
4608 }
4609 
4610 
4611 idmap_retcode
4612 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
4613 		idmap_mapping *mapping)
4614 {
4615 	idmap_id_res	idres;
4616 	lookup_state_t	state;
4617 	char		*cp;
4618 	idmap_retcode	retcode;
4619 	const char	*winname, *windomain;
4620 
4621 	(void) memset(&idres, 0, sizeof (idres));
4622 	(void) memset(&state, 0, sizeof (state));
4623 	state.cache = cache;
4624 	state.db = db;
4625 
4626 	/* Get directory-based name mapping info */
4627 	retcode = load_cfg_in_state(&state);
4628 	if (retcode != IDMAP_SUCCESS)
4629 		goto out;
4630 
4631 	/*
4632 	 * Copy data from "request" to "mapping". Note that
4633 	 * empty strings are not copied from "request" to
4634 	 * "mapping" and therefore the coresponding strings in
4635 	 * "mapping" will be NULL. This eliminates having to
4636 	 * check for empty strings henceforth.
4637 	 */
4638 	if (copy_mapping_request(mapping, request) < 0) {
4639 		retcode = IDMAP_ERR_MEMORY;
4640 		goto out;
4641 	}
4642 
4643 	winname = mapping->id1name;
4644 	windomain = mapping->id1domain;
4645 
4646 	if (winname == NULL && windomain != NULL) {
4647 		retcode = IDMAP_ERR_ARG;
4648 		goto out;
4649 	}
4650 
4651 	/* Need atleast winname or sid to proceed */
4652 	if (winname == NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) {
4653 		retcode = IDMAP_ERR_ARG;
4654 		goto out;
4655 	}
4656 
4657 	/*
4658 	 * If domainname is not given but we have a fully qualified
4659 	 * winname then extract the domainname from the winname,
4660 	 * otherwise use the default_domain from the config
4661 	 */
4662 	if (winname != NULL && windomain == NULL) {
4663 		retcode = IDMAP_SUCCESS;
4664 		if ((cp = strchr(winname, '@')) != NULL) {
4665 			*cp = '\0';
4666 			mapping->id1domain = strdup(cp + 1);
4667 			if (mapping->id1domain == NULL)
4668 				retcode = IDMAP_ERR_MEMORY;
4669 		} else if (lookup_wksids_name2sid(winname, NULL, NULL, NULL,
4670 		    NULL, NULL, NULL) != IDMAP_SUCCESS) {
4671 			if (state.defdom == NULL) {
4672 				/*
4673 				 * We have a non-qualified winname which is
4674 				 * neither the name of a well-known SID nor
4675 				 * there is a default domain with which we can
4676 				 * qualify it.
4677 				 */
4678 				retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
4679 			} else {
4680 				mapping->id1domain = strdup(state.defdom);
4681 				if (mapping->id1domain == NULL)
4682 					retcode = IDMAP_ERR_MEMORY;
4683 			}
4684 		}
4685 		if (retcode != IDMAP_SUCCESS)
4686 			goto out;
4687 	}
4688 
4689 	/*
4690 	 * First pass looks up the well-known SIDs table and cache
4691 	 * and handles localSIDs
4692 	 */
4693 	state.sid2pid_done = TRUE;
4694 	retcode = sid2pid_first_pass(&state, mapping, &idres);
4695 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
4696 		goto out;
4697 
4698 	/* AD lookup */
4699 	if (state.ad_nqueries > 0) {
4700 		retcode = ad_lookup_one(&state, mapping, &idres);
4701 		if (IDMAP_ERROR(retcode))
4702 			goto out;
4703 	}
4704 
4705 	/* nldap lookup */
4706 	if (state.nldap_nqueries > 0) {
4707 		retcode = nldap_lookup_one(&state, mapping, &idres);
4708 		if (IDMAP_FATAL_ERROR(retcode))
4709 			goto out;
4710 	}
4711 
4712 	/* Next pass performs name-based mapping and ephemeral mapping. */
4713 	state.sid2pid_done = TRUE;
4714 	retcode = sid2pid_second_pass(&state, mapping, &idres);
4715 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
4716 		goto out;
4717 
4718 	/* Update cache */
4719 	(void) update_cache_sid2pid(&state, mapping, &idres);
4720 
4721 out:
4722 	/*
4723 	 * Note that "mapping" is returned to the client. Therefore
4724 	 * copy whatever we have in "idres" to mapping->id2 and
4725 	 * free idres.
4726 	 */
4727 	mapping->direction = idres.direction;
4728 	mapping->id2 = idres.id;
4729 	if (mapping->flag & IDMAP_REQ_FLG_MAPPING_INFO ||
4730 	    retcode != IDMAP_SUCCESS)
4731 		(void) idmap_info_mov(&mapping->info, &idres.info);
4732 	else
4733 		idmap_info_free(&idres.info);
4734 	(void) memset(&idres, 0, sizeof (idres));
4735 	if (retcode != IDMAP_SUCCESS)
4736 		mapping->id2.idmap_id_u.uid = UID_NOBODY;
4737 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
4738 	cleanup_lookup_state(&state);
4739 	return (retcode);
4740 }
4741 
4742 idmap_retcode
4743 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
4744 		idmap_mapping *mapping, int is_user)
4745 {
4746 	idmap_id_res	idres;
4747 	lookup_state_t	state;
4748 	idmap_retcode	retcode;
4749 
4750 	/*
4751 	 * In order to re-use the pid2sid code, we convert
4752 	 * our input data into structs that are expected by
4753 	 * pid2sid_first_pass.
4754 	 */
4755 
4756 	(void) memset(&idres, 0, sizeof (idres));
4757 	(void) memset(&state, 0, sizeof (state));
4758 	state.cache = cache;
4759 	state.db = db;
4760 
4761 	/* Get directory-based name mapping info */
4762 	retcode = load_cfg_in_state(&state);
4763 	if (retcode != IDMAP_SUCCESS)
4764 		goto out;
4765 
4766 	/*
4767 	 * Copy data from "request" to "mapping". Note that
4768 	 * empty strings are not copied from "request" to
4769 	 * "mapping" and therefore the coresponding strings in
4770 	 * "mapping" will be NULL. This eliminates having to
4771 	 * check for empty strings henceforth.
4772 	 */
4773 	if (copy_mapping_request(mapping, request) < 0) {
4774 		retcode = IDMAP_ERR_MEMORY;
4775 		goto out;
4776 	}
4777 
4778 	/*
4779 	 * For unix to windows mapping request, we need atleast a
4780 	 * unixname or uid/gid to proceed
4781 	 */
4782 	if (mapping->id1name == NULL &&
4783 	    mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
4784 		retcode = IDMAP_ERR_ARG;
4785 		goto out;
4786 	}
4787 
4788 	/* First pass looks up cache and well-known SIDs */
4789 	state.pid2sid_done = TRUE;
4790 	retcode = pid2sid_first_pass(&state, mapping, &idres, is_user, 1);
4791 	if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE)
4792 		goto out;
4793 
4794 	/* nldap lookup */
4795 	if (state.nldap_nqueries > 0) {
4796 		retcode = nldap_lookup_one(&state, mapping, &idres);
4797 		if (IDMAP_FATAL_ERROR(retcode))
4798 			goto out;
4799 	}
4800 
4801 	/* AD lookup */
4802 	if (state.ad_nqueries > 0) {
4803 		retcode = ad_lookup_one(&state, mapping, &idres);
4804 		if (IDMAP_FATAL_ERROR(retcode))
4805 			goto out;
4806 	}
4807 
4808 	/*
4809 	 * Next pass processes the result of the preceding passes/lookups.
4810 	 * It returns if there's nothing more to be done otherwise it
4811 	 * evaluates local name-based mapping rules
4812 	 */
4813 	state.pid2sid_done = TRUE;
4814 	retcode = pid2sid_second_pass(&state, mapping, &idres, is_user);
4815 	if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE)
4816 		goto out;
4817 
4818 	/* Update cache */
4819 	(void) update_cache_pid2sid(&state, mapping, &idres);
4820 
4821 out:
4822 	/*
4823 	 * Note that "mapping" is returned to the client. Therefore
4824 	 * copy whatever we have in "idres" to mapping->id2 and
4825 	 * free idres.
4826 	 */
4827 	mapping->direction = idres.direction;
4828 	mapping->id2 = idres.id;
4829 	if (mapping->flag & IDMAP_REQ_FLG_MAPPING_INFO ||
4830 	    retcode != IDMAP_SUCCESS)
4831 		(void) idmap_info_mov(&mapping->info, &idres.info);
4832 	else
4833 		idmap_info_free(&idres.info);
4834 	(void) memset(&idres, 0, sizeof (idres));
4835 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
4836 	cleanup_lookup_state(&state);
4837 	return (retcode);
4838 }
4839 
4840 /*ARGSUSED*/
4841 static
4842 idmap_retcode
4843 ad_lookup_one(lookup_state_t *state, idmap_mapping *req, idmap_id_res *res)
4844 {
4845 	idmap_mapping_batch	batch;
4846 	idmap_ids_res		result;
4847 
4848 	batch.idmap_mapping_batch_len = 1;
4849 	batch.idmap_mapping_batch_val = req;
4850 	result.ids.ids_len = 1;
4851 	result.ids.ids_val = res;
4852 	return (ad_lookup_batch(state, &batch, &result));
4853 }
4854 
4855 /*
4856  * Find a wksid entry for the specified Windows name and domain, of the
4857  * specified type.
4858  *
4859  * Ignore entries intended only for U2W use.
4860  */
4861 static
4862 const
4863 wksids_table_t *
4864 find_wksid_by_name(const char *name, const char *domain, int type)
4865 {
4866 	int i;
4867 	char *myhostname;
4868 	int len;
4869 
4870 	RDLOCK_CONFIG();
4871 	len = strlen(_idmapdstate.hostname) + 1;
4872 	myhostname = alloca(len);
4873 	(void) memcpy(myhostname, _idmapdstate.hostname, len);
4874 	UNLOCK_CONFIG();
4875 
4876 	for (i = 0; i < NELEM(wksids); i++) {
4877 		/* Check to see if this entry yields the desired type */
4878 		switch (type) {
4879 		case IDMAP_UID:
4880 			if (wksids[i].is_user == 0)
4881 				continue;
4882 			break;
4883 		case IDMAP_GID:
4884 			if (wksids[i].is_user == 1)
4885 				continue;
4886 			break;
4887 		case IDMAP_POSIXID:
4888 			break;
4889 		default:
4890 			assert(FALSE);
4891 		}
4892 
4893 		if (strcasecmp(wksids[i].winname, name) != 0)
4894 			continue;
4895 
4896 		if (!EMPTY_STRING(domain)) {
4897 			const char *dom;
4898 
4899 			if (wksids[i].domain != NULL) {
4900 				dom = wksids[i].domain;
4901 			} else {
4902 				dom = myhostname;
4903 			}
4904 			if (strcasecmp(dom, domain) != 0) {
4905 				/* this is not our domain */
4906 				continue;
4907 			}
4908 		}
4909 
4910 		/*
4911 		 * We have a Windows name, so ignore entries that are only
4912 		 * usable for mapping UNIX->Windows.  (Note:  the current
4913 		 * table does not have any such entries.)
4914 		 */
4915 		if (wksids[i].direction == IDMAP_DIRECTION_U2W)
4916 			continue;
4917 
4918 		return (&wksids[i]);
4919 	}
4920 
4921 	return (NULL);
4922 }
4923 
4924 /*
4925  * Find a wksid entry for the specified SID, of the specified type.
4926  *
4927  * Ignore entries intended only for U2W use.
4928  */
4929 static
4930 const
4931 wksids_table_t *
4932 find_wksid_by_sid(const char *sid, int rid, int type)
4933 {
4934 	int i;
4935 	char *mymachinesid;
4936 	int len;
4937 
4938 	RDLOCK_CONFIG();
4939 	len = strlen(_idmapdstate.cfg->pgcfg.machine_sid) + 1;
4940 	mymachinesid = alloca(len);
4941 	(void) memcpy(mymachinesid, _idmapdstate.cfg->pgcfg.machine_sid, len);
4942 	UNLOCK_CONFIG();
4943 
4944 	for (i = 0; i < NELEM(wksids); i++) {
4945 		int sidcmp;
4946 
4947 		/* Check to see if this entry yields the desired type */
4948 		switch (type) {
4949 		case IDMAP_UID:
4950 			if (wksids[i].is_user == 0)
4951 				continue;
4952 			break;
4953 		case IDMAP_GID:
4954 			if (wksids[i].is_user == 1)
4955 				continue;
4956 			break;
4957 		case IDMAP_POSIXID:
4958 			break;
4959 		default:
4960 			assert(FALSE);
4961 		}
4962 
4963 		if (wksids[i].sidprefix != NULL) {
4964 			sidcmp = strcasecmp(wksids[i].sidprefix, sid);
4965 		} else {
4966 			sidcmp = strcasecmp(mymachinesid, sid);
4967 		}
4968 
4969 		if (sidcmp != 0)
4970 			continue;
4971 		if (wksids[i].rid != rid)
4972 			continue;
4973 
4974 		/*
4975 		 * We have a SID, so ignore entries that are only usable
4976 		 * for mapping UNIX->Windows.  (Note:  the current table
4977 		 * does not have any such entries.)
4978 		 */
4979 		if (wksids[i].direction == IDMAP_DIRECTION_U2W)
4980 			continue;
4981 
4982 		return (&wksids[i]);
4983 	}
4984 
4985 	return (NULL);
4986 }
4987 
4988 /*
4989  * Find a wksid entry for the specified pid, of the specified type.
4990  * Ignore entries that do not specify U2W mappings.
4991  */
4992 static
4993 const
4994 wksids_table_t *
4995 find_wksid_by_pid(uid_t pid, int is_user)
4996 {
4997 	int i;
4998 
4999 	if (pid == SENTINEL_PID)
5000 		return (NULL);
5001 
5002 	for (i = 0; i < NELEM(wksids); i++) {
5003 		if (wksids[i].pid == pid &&
5004 		    wksids[i].is_user == is_user &&
5005 		    (wksids[i].direction == IDMAP_DIRECTION_BI ||
5006 		    wksids[i].direction == IDMAP_DIRECTION_U2W)) {
5007 			return (&wksids[i]);
5008 		}
5009 	}
5010 	return (NULL);
5011 }
5012