xref: /titanic_44/usr/src/cmd/idmap/idmapd/dbutils.c (revision ee5416c9d7e449233197d5d20bc6b81e4ff091b2)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Database related utility routines
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <rpc/rpc.h>
39 #include <sys/sid.h>
40 #include <time.h>
41 #include <pwd.h>
42 #include <grp.h>
43 #include <pthread.h>
44 #include <assert.h>
45 
46 #include "idmapd.h"
47 #include "adutils.h"
48 #include "string.h"
49 #include "idmap_priv.h"
50 
51 
52 static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
53 		sqlite_vm **, int *, int, const char ***);
54 static idmap_retcode lookup_wksids_name2sid(const char *, char **,
55 		idmap_rid_t *, int *);
56 
57 #define	EMPTY_NAME(name)	(*name == 0 || strcmp(name, "\"\"") == 0)
58 
59 #define	EMPTY_STRING(str)	(str == NULL || *str == 0)
60 
61 #define	DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
62 		(req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
63 
64 #define	AVOID_NAMESERVICE(req)\
65 		(req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
66 
67 #define	IS_EPHEMERAL(pid)	(pid > INT32_MAX)
68 
69 #define	LOCALRID_MIN	1000
70 
71 
72 
73 typedef enum init_db_option {
74 	FAIL_IF_CORRUPT = 0,
75 	REMOVE_IF_CORRUPT = 1
76 } init_db_option_t;
77 
78 /*
79  * Thread specfic data to hold the database handles so that the
80  * databaes are not opened and closed for every request. It also
81  * contains the sqlite busy handler structure.
82  */
83 
84 struct idmap_busy {
85 	const char *name;
86 	const int *delays;
87 	int delay_size;
88 	int total;
89 	int sec;
90 };
91 
92 
93 typedef struct idmap_tsd {
94 	sqlite *db_db;
95 	sqlite *cache_db;
96 	struct idmap_busy cache_busy;
97 	struct idmap_busy db_busy;
98 } idmap_tsd_t;
99 
100 
101 
102 static const int cache_delay_table[] =
103 		{ 1, 2, 5, 10, 15, 20, 25, 30,  35,  40,
104 		50,  50, 60, 70, 80, 90, 100};
105 
106 static const int db_delay_table[] =
107 		{ 5, 10, 15, 20, 30,  40,  55,  70, 100};
108 
109 
110 static pthread_key_t	idmap_tsd_key;
111 
112 void
113 idmap_tsd_destroy(void *key)
114 {
115 
116 	idmap_tsd_t	*tsd = (idmap_tsd_t *)key;
117 	if (tsd) {
118 		if (tsd->db_db)
119 			(void) sqlite_close(tsd->db_db);
120 		if (tsd->cache_db)
121 			(void) sqlite_close(tsd->cache_db);
122 		free(tsd);
123 	}
124 }
125 
126 int
127 idmap_init_tsd_key(void) {
128 
129 	return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy));
130 }
131 
132 
133 
134 idmap_tsd_t *
135 idmap_get_tsd(void)
136 {
137 	idmap_tsd_t	*tsd;
138 
139 	if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) {
140 		/* No thread specific data so create it */
141 		if ((tsd = malloc(sizeof (*tsd))) != NULL) {
142 			/* Initialize thread specific data */
143 			(void) memset(tsd, 0, sizeof (*tsd));
144 			/* save the trhread specific data */
145 			if (pthread_setspecific(idmap_tsd_key, tsd) != 0) {
146 				/* Can't store key */
147 				free(tsd);
148 				tsd = NULL;
149 			}
150 		} else {
151 			tsd = NULL;
152 		}
153 	}
154 
155 	return (tsd);
156 }
157 
158 
159 
160 /*
161  * Initialize 'dbname' using 'sql'
162  */
163 static int
164 init_db_instance(const char *dbname, const char *sql, init_db_option_t opt,
165 		int *new_db_created)
166 {
167 	int rc = 0;
168 	int tries = 0;
169 	sqlite *db = NULL;
170 	char *str = NULL;
171 
172 	if (new_db_created != NULL)
173 		*new_db_created = 0;
174 
175 	db = sqlite_open(dbname, 0600, &str);
176 	while (db == NULL) {
177 		idmapdlog(LOG_ERR,
178 		    "Error creating database %s (%s)",
179 		    dbname, CHECK_NULL(str));
180 		sqlite_freemem(str);
181 		if (opt == FAIL_IF_CORRUPT || opt != REMOVE_IF_CORRUPT ||
182 		    tries > 0)
183 			return (-1);
184 
185 		tries++;
186 		(void) unlink(dbname);
187 		db = sqlite_open(dbname, 0600, &str);
188 	}
189 
190 	sqlite_busy_timeout(db, 3000);
191 	rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &str);
192 	if (SQLITE_OK != rc) {
193 		idmapdlog(LOG_ERR, "Cannot begin database transaction (%s)",
194 		    str);
195 		sqlite_freemem(str);
196 		sqlite_close(db);
197 		return (1);
198 	}
199 
200 	switch (sqlite_exec(db, sql, NULL, NULL, &str)) {
201 	case SQLITE_ERROR:
202 /*
203  * This is the normal situation: CREATE probably failed because tables
204  * already exist. It may indicate an error in SQL as well, but we cannot
205  * tell.
206  */
207 		sqlite_freemem(str);
208 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
209 		    NULL, NULL, &str);
210 		break;
211 	case SQLITE_OK:
212 		rc =  sqlite_exec(db, "COMMIT TRANSACTION",
213 		    NULL, NULL, &str);
214 		idmapdlog(LOG_INFO,
215 		    "Database created at %s", dbname);
216 
217 		if (new_db_created != NULL)
218 			*new_db_created = 1;
219 		break;
220 	default:
221 		idmapdlog(LOG_ERR,
222 		    "Error initializing database %s (%s)",
223 		    dbname, str);
224 		sqlite_freemem(str);
225 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
226 		    NULL, NULL, &str);
227 		break;
228 	}
229 
230 	if (SQLITE_OK != rc) {
231 		/* this is bad - database may be left in a locked state */
232 		idmapdlog(LOG_ERR,
233 		    "Error closing transaction (%s)", str);
234 		sqlite_freemem(str);
235 	}
236 
237 	(void) sqlite_close(db);
238 	return (rc);
239 }
240 
241 
242 /*
243  * This is the SQLite database busy handler that retries the SQL
244  * operation until it is successful.
245  */
246 int
247 /* LINTED E_FUNC_ARG_UNUSED */
248 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count)
249 {
250 	struct idmap_busy	*busy = arg;
251 	int			delay;
252 	struct timespec		rqtp;
253 
254 	if (count == 1)  {
255 		busy->total = 0;
256 		busy->sec = 2;
257 	}
258 	if (busy->total > 1000 * busy->sec) {
259 		idmapdlog(LOG_ERR,
260 		    "Thread %d waited %d sec for the %s database",
261 		    pthread_self(), busy->sec, busy->name);
262 		busy->sec++;
263 	}
264 
265 	if (count <= busy->delay_size) {
266 		delay = busy->delays[count-1];
267 	} else {
268 		delay = busy->delays[busy->delay_size - 1];
269 	}
270 	busy->total += delay;
271 	rqtp.tv_sec = 0;
272 	rqtp.tv_nsec = delay * (NANOSEC / MILLISEC);
273 	(void) nanosleep(&rqtp, NULL);
274 	return (1);
275 }
276 
277 
278 /*
279  * Get the database handle
280  */
281 idmap_retcode
282 get_db_handle(sqlite **db) {
283 	char	*errmsg;
284 	idmap_tsd_t *tsd;
285 
286 	/*
287 	 * Retrieve the db handle from thread-specific storage
288 	 * If none exists, open and store in thread-specific storage.
289 	 */
290 	if ((tsd = idmap_get_tsd()) == NULL) {
291 		idmapdlog(LOG_ERR,
292 			"Error getting thread specific data for %s",
293 			IDMAP_DBNAME);
294 		return (IDMAP_ERR_MEMORY);
295 	}
296 
297 	if (tsd->db_db == NULL) {
298 		tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg);
299 		if (tsd->db_db == NULL) {
300 			idmapdlog(LOG_ERR,
301 				"Error opening database %s (%s)",
302 				IDMAP_DBNAME, CHECK_NULL(errmsg));
303 			sqlite_freemem(errmsg);
304 			return (IDMAP_ERR_INTERNAL);
305 		}
306 		tsd->db_busy.name = IDMAP_DBNAME;
307 		tsd->db_busy.delays = db_delay_table;
308 		tsd->db_busy.delay_size = sizeof (db_delay_table) /
309 		    sizeof (int);
310 		sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler,
311 		    &tsd->db_busy);
312 	}
313 	*db = tsd->db_db;
314 	return (IDMAP_SUCCESS);
315 }
316 
317 /*
318  * Get the cache handle
319  */
320 idmap_retcode
321 get_cache_handle(sqlite **cache) {
322 	char	*errmsg;
323 	idmap_tsd_t *tsd;
324 
325 	/*
326 	 * Retrieve the db handle from thread-specific storage
327 	 * If none exists, open and store in thread-specific storage.
328 	 */
329 	if ((tsd = idmap_get_tsd()) == NULL) {
330 		idmapdlog(LOG_ERR,
331 			"Error getting thread specific data for %s",
332 			IDMAP_DBNAME);
333 		return (IDMAP_ERR_MEMORY);
334 	}
335 
336 	if (tsd->cache_db == NULL) {
337 		tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg);
338 		if (tsd->cache_db == NULL) {
339 			idmapdlog(LOG_ERR,
340 				"Error opening database %s (%s)",
341 				IDMAP_CACHENAME, CHECK_NULL(errmsg));
342 			sqlite_freemem(errmsg);
343 			return (IDMAP_ERR_INTERNAL);
344 		}
345 		tsd->cache_busy.name = IDMAP_CACHENAME;
346 		tsd->cache_busy.delays = cache_delay_table;
347 		tsd->cache_busy.delay_size = sizeof (cache_delay_table) /
348 		    sizeof (int);
349 		sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler,
350 		    &tsd->cache_busy);
351 	}
352 	*cache = tsd->cache_db;
353 	return (IDMAP_SUCCESS);
354 }
355 
356 #define	CACHE_SQL\
357 	"CREATE TABLE idmap_cache ("\
358 	"	sidprefix TEXT,"\
359 	"	rid INTEGER,"\
360 	"	windomain TEXT,"\
361 	"	winname TEXT,"\
362 	"	pid INTEGER,"\
363 	"	unixname TEXT,"\
364 	"	is_user INTEGER,"\
365 	"	w2u INTEGER,"\
366 	"	u2w INTEGER,"\
367 	"	expiration INTEGER"\
368 	");"\
369 	"CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache"\
370 	"		(sidprefix, rid, w2u);"\
371 	"CREATE UNIQUE INDEX idmap_cache_pid_u2w ON idmap_cache"\
372 	"		(pid, is_user, u2w);"\
373 	"CREATE TABLE name_cache ("\
374 	"	sidprefix TEXT,"\
375 	"	rid INTEGER,"\
376 	"	name TEXT,"\
377 	"	domain TEXT,"\
378 	"	type INTEGER,"\
379 	"	expiration INTEGER"\
380 	");"\
381 	"CREATE UNIQUE INDEX name_cache_sid ON name_cache"\
382 	"		(sidprefix, rid);"
383 
384 #define	DB_SQL\
385 	"CREATE TABLE namerules ("\
386 	"	is_user INTEGER NOT NULL,"\
387 	"	windomain TEXT,"\
388 	"	winname TEXT NOT NULL,"\
389 	"	is_nt4 INTEGER NOT NULL,"\
390 	"	unixname NOT NULL,"\
391 	"	w2u_order INTEGER,"\
392 	"	u2w_order INTEGER"\
393 	");"\
394 	"CREATE UNIQUE INDEX namerules_w2u ON namerules"\
395 	"		(winname, windomain, is_user, w2u_order);"\
396 	"CREATE UNIQUE INDEX namerules_u2w ON namerules"\
397 	"		(unixname, is_user, u2w_order);"
398 
399 /*
400  * Initialize cache and db
401  */
402 int
403 init_dbs() {
404 	/* name-based mappings; probably OK to blow away in a pinch(?) */
405 	if (init_db_instance(IDMAP_DBNAME, DB_SQL, FAIL_IF_CORRUPT, NULL) < 0)
406 		return (-1);
407 
408 	/* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
409 	if (init_db_instance(IDMAP_CACHENAME, CACHE_SQL, REMOVE_IF_CORRUPT,
410 			&_idmapdstate.new_eph_db) < 0)
411 		return (-1);
412 
413 	return (0);
414 }
415 
416 /*
417  * Finalize databases
418  */
419 void
420 fini_dbs() {
421 }
422 
423 /*
424  * This table is a listing of status codes that will returned to the
425  * client when a SQL command fails with the corresponding error message.
426  */
427 static msg_table_t sqlmsgtable[] = {
428 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
429 	"columns unixname, is_user, u2w_order are not unique"},
430 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
431 	"columns winname, windomain, is_user, w2u_order are not unique"},
432 	{-1, NULL}
433 };
434 
435 /*
436  * idmapd's version of string2stat to map SQLite messages to
437  * status codes
438  */
439 idmap_retcode
440 idmapd_string2stat(const char *msg) {
441 	int i;
442 	for (i = 0; sqlmsgtable[i].msg; i++) {
443 		if (strcasecmp(sqlmsgtable[i].msg, msg) == 0)
444 			return (sqlmsgtable[i].retcode);
445 	}
446 	return (IDMAP_ERR_OTHER);
447 }
448 
449 /*
450  * Execute the given SQL statment without using any callbacks
451  */
452 idmap_retcode
453 sql_exec_no_cb(sqlite *db, char *sql) {
454 	char		*errmsg = NULL;
455 	int		r;
456 	idmap_retcode	retcode;
457 
458 	r = sqlite_exec(db, sql, NULL, NULL, &errmsg);
459 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
460 
461 	if (r != SQLITE_OK) {
462 		idmapdlog(LOG_ERR, "Database error during %s (%s)",
463 			sql, CHECK_NULL(errmsg));
464 		retcode = idmapd_string2stat(errmsg);
465 		if (errmsg != NULL)
466 			sqlite_freemem(errmsg);
467 		return (retcode);
468 	}
469 
470 	return (IDMAP_SUCCESS);
471 }
472 
473 /*
474  * Generate expression that can be used in WHERE statements.
475  * Examples:
476  * <prefix> <col>      <op> <value>   <suffix>
477  * ""       "unixuser" "="  "foo" "AND"
478  */
479 idmap_retcode
480 gen_sql_expr_from_utf8str(const char *prefix, const char *col,
481 		const char *op, idmap_utf8str *value,
482 		const char *suffix, char **out) {
483 	char		*str;
484 	idmap_stat	retcode;
485 
486 	if (out == NULL)
487 		return (IDMAP_ERR_ARG);
488 
489 	if (value == NULL)
490 		return (IDMAP_SUCCESS);
491 
492 	retcode = idmap_utf82str(&str, 0, value);
493 	if (retcode != IDMAP_SUCCESS)
494 		return (retcode);
495 
496 	if (prefix == NULL)
497 		prefix = "";
498 	if (suffix == NULL)
499 		suffix = "";
500 
501 	*out = sqlite_mprintf("%s %s %s %Q %s",
502 			prefix, col, op, str, suffix);
503 	idmap_free(str);
504 	if (*out == NULL)
505 		return (IDMAP_ERR_MEMORY);
506 	return (IDMAP_SUCCESS);
507 }
508 
509 /*
510  * Generate and execute SQL statement for LIST RPC calls
511  */
512 idmap_retcode
513 process_list_svc_sql(sqlite *db, char *sql, uint64_t limit,
514 		list_svc_cb cb, void *result) {
515 	list_cb_data_t	cb_data;
516 	char		*errmsg = NULL;
517 	int		r;
518 	idmap_retcode	retcode = IDMAP_ERR_INTERNAL;
519 
520 	(void) memset(&cb_data, 0, sizeof (cb_data));
521 	cb_data.result = result;
522 	cb_data.limit = limit;
523 
524 
525 	r = sqlite_exec(db, sql, cb, &cb_data, &errmsg);
526 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
527 	switch (r) {
528 	case SQLITE_OK:
529 		retcode = IDMAP_SUCCESS;
530 		break;
531 
532 	default:
533 		retcode = IDMAP_ERR_INTERNAL;
534 		idmapdlog(LOG_ERR,
535 			"Database error during %s (%s)",
536 			sql, CHECK_NULL(errmsg));
537 		break;
538 	}
539 	if (errmsg != NULL)
540 		sqlite_freemem(errmsg);
541 	return (retcode);
542 }
543 
544 /*
545  * This routine is called by callbacks that process the results of
546  * LIST RPC calls to validate data and to allocate memory for
547  * the result array.
548  */
549 idmap_retcode
550 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv,
551 		int ncol, uchar_t **list, size_t valsize) {
552 	size_t	nsize;
553 	void	*tmplist;
554 
555 	if (cb_data->limit > 0 && cb_data->next == cb_data->limit)
556 		return (IDMAP_NEXT);
557 
558 	if (argc < ncol || argv == NULL) {
559 		idmapdlog(LOG_ERR, "Invalid data");
560 		return (IDMAP_ERR_INTERNAL);
561 	}
562 
563 	/* alloc in bulk to reduce number of reallocs */
564 	if (cb_data->next >= cb_data->len) {
565 		nsize = (cb_data->len + SIZE_INCR) * valsize;
566 		tmplist = realloc(*list, nsize);
567 		if (tmplist == NULL) {
568 			idmapdlog(LOG_ERR, "Out of memory");
569 			return (IDMAP_ERR_MEMORY);
570 		}
571 		*list = tmplist;
572 		(void) memset(*list + (cb_data->len * valsize), 0,
573 			SIZE_INCR * valsize);
574 		cb_data->len += SIZE_INCR;
575 	}
576 	return (IDMAP_SUCCESS);
577 }
578 
579 static idmap_retcode
580 get_namerule_order(char *winname, char *windomain, char *unixname,
581 		int direction, int *w2u_order, int *u2w_order) {
582 
583 	*w2u_order = 0;
584 	*u2w_order = 0;
585 
586 	/*
587 	 * Windows to UNIX lookup order:
588 	 *  1. winname@domain (or winname) to ""
589 	 *  2. winname@domain (or winname) to unixname
590 	 *  3. winname@* to ""
591 	 *  4. winname@* to unixname
592 	 *  5. *@domain (or *) to *
593 	 *  6. *@domain (or *) to ""
594 	 *  7. *@domain (or *) to unixname
595 	 *  8. *@* to *
596 	 *  9. *@* to ""
597 	 * 10. *@* to unixname
598 	 *
599 	 * winname is a special case of winname@domain when domain is the
600 	 * default domain. Similarly * is a special case of *@domain when
601 	 * domain is the default domain.
602 	 *
603 	 * Note that "" has priority over specific names because "" inhibits
604 	 * mappings and traditionally deny rules always had higher priority.
605 	 */
606 	if (direction != IDMAP_DIRECTION_U2W) {
607 		/* bi-directional or from windows to unix */
608 		if (winname == NULL)
609 			return (IDMAP_ERR_W2U_NAMERULE);
610 		else if (unixname == NULL)
611 			return (IDMAP_ERR_W2U_NAMERULE);
612 		else if (EMPTY_NAME(winname))
613 			return (IDMAP_ERR_W2U_NAMERULE);
614 		else if (*winname == '*' && windomain && *windomain == '*') {
615 			if (*unixname == '*')
616 				*w2u_order = 8;
617 			else if (EMPTY_NAME(unixname))
618 				*w2u_order = 9;
619 			else /* unixname == name */
620 				*w2u_order = 10;
621 		} else if (*winname == '*') {
622 			if (*unixname == '*')
623 				*w2u_order = 5;
624 			else if (EMPTY_NAME(unixname))
625 				*w2u_order = 6;
626 			else /* name */
627 				*w2u_order = 7;
628 		} else if (windomain != NULL && *windomain == '*') {
629 			/* winname == name */
630 			if (*unixname == '*')
631 				return (IDMAP_ERR_W2U_NAMERULE);
632 			else if (EMPTY_NAME(unixname))
633 				*w2u_order = 3;
634 			else /* name */
635 				*w2u_order = 4;
636 		} else  {
637 			/* winname == name && windomain == null or name */
638 			if (*unixname == '*')
639 				return (IDMAP_ERR_W2U_NAMERULE);
640 			else if (EMPTY_NAME(unixname))
641 				*w2u_order = 1;
642 			else /* name */
643 				*w2u_order = 2;
644 		}
645 	}
646 
647 	/*
648 	 * 1. unixname to ""
649 	 * 2. unixname to winname@domain (or winname)
650 	 * 3. * to *@domain (or *)
651 	 * 4. * to ""
652 	 * 5. * to winname@domain (or winname)
653 	 */
654 	if (direction != IDMAP_DIRECTION_W2U) {
655 		/* bi-directional or from unix to windows */
656 		if (unixname == NULL || EMPTY_NAME(unixname))
657 			return (IDMAP_ERR_U2W_NAMERULE);
658 		else if (winname == NULL)
659 			return (IDMAP_ERR_U2W_NAMERULE);
660 		else if (windomain != NULL && *windomain == '*')
661 			return (IDMAP_ERR_U2W_NAMERULE);
662 		else if (*unixname == '*') {
663 			if (*winname == '*')
664 				*u2w_order = 3;
665 			else if (EMPTY_NAME(winname))
666 				*u2w_order = 4;
667 			else
668 				*u2w_order = 5;
669 		} else {
670 			if (*winname == '*')
671 				return (IDMAP_ERR_U2W_NAMERULE);
672 			else if (EMPTY_NAME(winname))
673 				*u2w_order = 1;
674 			else
675 				*u2w_order = 2;
676 		}
677 	}
678 	return (IDMAP_SUCCESS);
679 }
680 
681 /*
682  * Generate and execute SQL statement to add name-based mapping rule
683  */
684 idmap_retcode
685 add_namerule(sqlite *db, idmap_namerule *rule) {
686 	char		*sql = NULL;
687 	idmap_stat	retcode;
688 	char		*windomain = NULL, *winname = NULL, *dom = NULL;
689 	char		*unixname = NULL;
690 	int		w2u_order, u2w_order;
691 	char		w2ubuf[11], u2wbuf[11];
692 
693 	retcode = idmap_utf82str(&windomain, 0, &rule->windomain);
694 	if (retcode != IDMAP_SUCCESS)
695 		goto out;
696 	retcode = idmap_utf82str(&winname, 0, &rule->winname);
697 	if (retcode != IDMAP_SUCCESS)
698 		goto out;
699 	retcode = idmap_utf82str(&unixname, 0, &rule->unixname);
700 	if (retcode != IDMAP_SUCCESS)
701 		goto out;
702 
703 	retcode = get_namerule_order(winname, windomain, unixname,
704 			rule->direction, &w2u_order, &u2w_order);
705 	if (retcode != IDMAP_SUCCESS)
706 		goto out;
707 
708 	if (w2u_order)
709 		(void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order);
710 	if (u2w_order)
711 		(void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order);
712 
713 	/*
714 	 * For the triggers on namerules table to work correctly:
715 	 * 1) Use NULL instead of 0 for w2u_order and u2w_order
716 	 * 2) Use "" instead of NULL for "no domain"
717 	 */
718 
719 	if (windomain != NULL)
720 		dom = windomain;
721 	else if (lookup_wksids_name2sid(winname, NULL, NULL, NULL)
722 	    == IDMAP_SUCCESS) {
723 		/* well-known SIDs don't need domain */
724 		dom = "";
725 	}
726 
727 	RDLOCK_CONFIG();
728 	if (dom == NULL) {
729 		if (_idmapdstate.cfg->pgcfg.mapping_domain)
730 			dom = _idmapdstate.cfg->pgcfg.mapping_domain;
731 		else
732 			dom = "";
733 	}
734 	sql = sqlite_mprintf("INSERT into namerules "
735 		"(is_user, windomain, winname, is_nt4, "
736 		"unixname, w2u_order, u2w_order) "
737 		"VALUES(%d, %Q, %Q, %d, %Q, %q, %q);",
738 		rule->is_user?1:0,
739 		dom,
740 		winname, rule->is_nt4?1:0,
741 		unixname,
742 		w2u_order?w2ubuf:NULL,
743 		u2w_order?u2wbuf:NULL);
744 	UNLOCK_CONFIG();
745 
746 	if (sql == NULL) {
747 		retcode = IDMAP_ERR_INTERNAL;
748 		idmapdlog(LOG_ERR, "Out of memory");
749 		goto out;
750 	}
751 
752 	retcode = sql_exec_no_cb(db, sql);
753 
754 	if (retcode == IDMAP_ERR_OTHER)
755 		retcode = IDMAP_ERR_CFG;
756 
757 out:
758 	if (windomain != NULL)
759 		idmap_free(windomain);
760 	if (winname != NULL)
761 		idmap_free(winname);
762 	if (unixname != NULL)
763 		idmap_free(unixname);
764 	if (sql != NULL)
765 		sqlite_freemem(sql);
766 	return (retcode);
767 }
768 
769 /*
770  * Flush name-based mapping rules
771  */
772 idmap_retcode
773 flush_namerules(sqlite *db, bool_t is_user) {
774 	char		*sql = NULL;
775 	idmap_stat	retcode;
776 
777 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
778 		"is_user = %d;", is_user?1:0);
779 
780 	if (sql == NULL) {
781 		idmapdlog(LOG_ERR, "Out of memory");
782 		return (IDMAP_ERR_MEMORY);
783 	}
784 
785 	retcode = sql_exec_no_cb(db, sql);
786 
787 	sqlite_freemem(sql);
788 	return (retcode);
789 }
790 
791 /*
792  * Generate and execute SQL statement to remove a name-based mapping rule
793  */
794 idmap_retcode
795 rm_namerule(sqlite *db, idmap_namerule *rule) {
796 	char		*sql = NULL;
797 	idmap_stat	retcode;
798 	char		*s_windomain = NULL, *s_winname = NULL;
799 	char		*s_unixname = NULL;
800 	char		buf[80];
801 
802 	if (rule->direction < 0 &&
803 			rule->windomain.idmap_utf8str_len < 1 &&
804 			rule->winname.idmap_utf8str_len < 1 &&
805 			rule->unixname.idmap_utf8str_len < 1)
806 		return (IDMAP_SUCCESS);
807 
808 	if (rule->direction < 0) {
809 		buf[0] = 0;
810 	} else if (rule->direction == IDMAP_DIRECTION_BI) {
811 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
812 				" AND u2w_order > 0");
813 	} else if (rule->direction == IDMAP_DIRECTION_W2U) {
814 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
815 				" AND (u2w_order = 0 OR u2w_order ISNULL)");
816 	} else if (rule->direction == IDMAP_DIRECTION_U2W) {
817 		(void) snprintf(buf, sizeof (buf), "AND u2w_order > 0"
818 				" AND (w2u_order = 0 OR w2u_order ISNULL)");
819 	}
820 
821 	retcode = IDMAP_ERR_INTERNAL;
822 	if (rule->windomain.idmap_utf8str_len > 0) {
823 		if (gen_sql_expr_from_utf8str("AND", "windomain", "=",
824 				&rule->windomain,
825 				"", &s_windomain) != IDMAP_SUCCESS)
826 			goto out;
827 	}
828 
829 	if (rule->winname.idmap_utf8str_len > 0) {
830 		if (gen_sql_expr_from_utf8str("AND", "winname", "=",
831 				&rule->winname,
832 				"", &s_winname) != IDMAP_SUCCESS)
833 			goto out;
834 	}
835 
836 	if (rule->unixname.idmap_utf8str_len > 0) {
837 		if (gen_sql_expr_from_utf8str("AND", "unixname", "=",
838 				&rule->unixname,
839 				"", &s_unixname) != IDMAP_SUCCESS)
840 			goto out;
841 	}
842 
843 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
844 		"is_user = %d %s %s %s %s;",
845 		rule->is_user?1:0,
846 		s_windomain?s_windomain:"",
847 		s_winname?s_winname:"",
848 		s_unixname?s_unixname:"",
849 		buf);
850 
851 	if (sql == NULL) {
852 		retcode = IDMAP_ERR_INTERNAL;
853 		idmapdlog(LOG_ERR, "Out of memory");
854 		goto out;
855 	}
856 
857 	retcode = sql_exec_no_cb(db, sql);
858 
859 out:
860 	if (s_windomain != NULL)
861 		sqlite_freemem(s_windomain);
862 	if (s_winname != NULL)
863 		sqlite_freemem(s_winname);
864 	if (s_unixname != NULL)
865 		sqlite_freemem(s_unixname);
866 	if (sql != NULL)
867 		sqlite_freemem(sql);
868 	return (retcode);
869 }
870 
871 /*
872  * Compile the given SQL query and step just once.
873  *
874  * Input:
875  * db  - db handle
876  * sql - SQL statement
877  *
878  * Output:
879  * vm     -  virtual SQL machine
880  * ncol   - number of columns in the result
881  * values - column values
882  *
883  * Return values:
884  * IDMAP_SUCCESS
885  * IDMAP_ERR_NOTFOUND
886  * IDMAP_ERR_INTERNAL
887  */
888 
889 static idmap_retcode
890 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
891 		int reqcol, const char ***values) {
892 	char		*errmsg = NULL;
893 	int		r;
894 
895 	if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) {
896 		idmapdlog(LOG_ERR,
897 			"Database error during %s (%s)",
898 			sql, CHECK_NULL(errmsg));
899 		sqlite_freemem(errmsg);
900 		return (IDMAP_ERR_INTERNAL);
901 	}
902 
903 	r = sqlite_step(*vm, ncol, values, NULL);
904 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
905 
906 	if (r == SQLITE_ROW) {
907 		if (ncol != NULL && *ncol < reqcol) {
908 			(void) sqlite_finalize(*vm, NULL);
909 			*vm = NULL;
910 			return (IDMAP_ERR_INTERNAL);
911 		}
912 		/* Caller will call finalize after using the results */
913 		return (IDMAP_SUCCESS);
914 	} else if (r == SQLITE_DONE) {
915 		(void) sqlite_finalize(*vm, NULL);
916 		*vm = NULL;
917 		return (IDMAP_ERR_NOTFOUND);
918 	}
919 
920 	(void) sqlite_finalize(*vm, &errmsg);
921 	*vm = NULL;
922 	idmapdlog(LOG_ERR, "Database error during %s (%s)",
923 	    sql, CHECK_NULL(errmsg));
924 	sqlite_freemem(errmsg);
925 	return (IDMAP_ERR_INTERNAL);
926 }
927 
928 /*
929  * Table for well-known SIDs.
930  *
931  * Background:
932  *
933  * These well-known principals are stored (as of Windows Server 2003) under:
934  * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
935  * They belong to objectClass "foreignSecurityPrincipal". They don't have
936  * "samAccountName" nor "userPrincipalName" attributes. Their names are
937  * available in "cn" and "name" attributes. Some of these principals have a
938  * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
939  * these duplicate entries have the stringified SID in the "name" and "cn"
940  * attributes instead of the actual name.
941  *
942  * These principals remain constant across all operating systems. Using
943  * a hard-coded table here improves performance and avoids additional
944  * complexity in the AD lookup code in adutils.c
945  *
946  * Currently we don't support localization of well-known SID names,
947  * unlike Windows.
948  *
949  * Note that other well-known SIDs (i.e. S-1-5-<domain>-<w-k RID> and
950  * S-1-5-32-<w-k RID>) are not stored here because AD does have normal
951  * user/group objects for these objects and can be looked up using the
952  * existing AD lookup code.
953  */
954 static wksids_table_t wksids[] = {
955 	{"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1},
956 	{"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 0},
957 	{"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0},
958 	{"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1},
959 	{"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1},
960 	{"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1},
961 	{"S-1-5", 2, "Network", 0, SENTINEL_PID, -1},
962 	{"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1},
963 	{"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1},
964 	{"S-1-5", 6, "Service", 0, SENTINEL_PID, -1},
965 	{"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0},
966 	{"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1},
967 	{"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1},
968 	{"S-1-5", 10, "Self", 0, SENTINEL_PID, -1},
969 	{"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1},
970 	{"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1},
971 	{"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1},
972 	{"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1},
973 	{"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1},
974 	{"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0},
975 	{"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1},
976 	{"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1},
977 	{"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1},
978 	{"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1},
979 	{"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1},
980 	{"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1},
981 	{NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1}
982 };
983 
984 static idmap_retcode
985 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res) {
986 	int i;
987 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
988 		if (wksids[i].rid == req->id1.idmap_id_u.sid.rid &&
989 		    (strcasecmp(wksids[i].sidprefix,
990 		    req->id1.idmap_id_u.sid.prefix) == 0)) {
991 
992 			if (wksids[i].pid == SENTINEL_PID)
993 				/* Not mapped, break */
994 				break;
995 			else if (wksids[i].direction == IDMAP_DIRECTION_U2W)
996 				continue;
997 
998 			switch (req->id2.idtype) {
999 			case IDMAP_UID:
1000 				if (wksids[i].is_user == 0)
1001 					continue;
1002 				res->id.idmap_id_u.uid = wksids[i].pid;
1003 				res->direction = wksids[i].direction;
1004 				return (IDMAP_SUCCESS);
1005 			case IDMAP_GID:
1006 				if (wksids[i].is_user == 1)
1007 					continue;
1008 				res->id.idmap_id_u.gid = wksids[i].pid;
1009 				res->direction = wksids[i].direction;
1010 				return (IDMAP_SUCCESS);
1011 			case IDMAP_POSIXID:
1012 				res->id.idmap_id_u.uid = wksids[i].pid;
1013 				res->id.idtype = (!wksids[i].is_user)?
1014 						IDMAP_GID:IDMAP_UID;
1015 				res->direction = wksids[i].direction;
1016 				return (IDMAP_SUCCESS);
1017 			default:
1018 				return (IDMAP_ERR_NOTSUPPORTED);
1019 			}
1020 		}
1021 	}
1022 	return (IDMAP_ERR_NOTFOUND);
1023 }
1024 
1025 static idmap_retcode
1026 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) {
1027 	int i;
1028 	if (req->id2.idtype != IDMAP_SID)
1029 		return (IDMAP_ERR_NOTSUPPORTED);
1030 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
1031 		if (wksids[i].pid == req->id1.idmap_id_u.uid &&
1032 		    wksids[i].is_user == is_user &&
1033 		    wksids[i].direction != IDMAP_DIRECTION_W2U) {
1034 			res->id.idmap_id_u.sid.rid = wksids[i].rid;
1035 			res->id.idmap_id_u.sid.prefix =
1036 				strdup(wksids[i].sidprefix);
1037 			if (res->id.idmap_id_u.sid.prefix == NULL) {
1038 				idmapdlog(LOG_ERR, "Out of memory");
1039 				return (IDMAP_ERR_MEMORY);
1040 			}
1041 			res->direction = wksids[i].direction;
1042 			return (IDMAP_SUCCESS);
1043 		}
1044 	}
1045 	return (IDMAP_ERR_NOTFOUND);
1046 }
1047 
1048 static idmap_retcode
1049 lookup_wksids_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
1050 		int *type) {
1051 	int i;
1052 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
1053 		if ((strcasecmp(wksids[i].sidprefix, sidprefix) == 0) &&
1054 		    wksids[i].rid == rid) {
1055 			if ((*name = strdup(wksids[i].winname)) == NULL) {
1056 				idmapdlog(LOG_ERR, "Out of memory");
1057 				return (IDMAP_ERR_MEMORY);
1058 			}
1059 			*type = (wksids[i].is_user)?
1060 			    _IDMAP_T_USER:_IDMAP_T_GROUP;
1061 			return (IDMAP_SUCCESS);
1062 		}
1063 	}
1064 	return (IDMAP_ERR_NOTFOUND);
1065 }
1066 
1067 static idmap_retcode
1068 lookup_wksids_name2sid(const char *name, char **sidprefix, idmap_rid_t *rid,
1069 		int *type) {
1070 	int i;
1071 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
1072 		if (strcasecmp(wksids[i].winname, name) == 0) {
1073 			if (sidprefix != NULL && (*sidprefix =
1074 			    strdup(wksids[i].sidprefix)) == NULL) {
1075 				idmapdlog(LOG_ERR, "Out of memory");
1076 				return (IDMAP_ERR_MEMORY);
1077 			}
1078 			if (type != NULL)
1079 				*type = (wksids[i].is_user)?
1080 				    _IDMAP_T_USER:_IDMAP_T_GROUP;
1081 			if (rid != NULL)
1082 				*rid = wksids[i].rid;
1083 			return (IDMAP_SUCCESS);
1084 		}
1085 	}
1086 	return (IDMAP_ERR_NOTFOUND);
1087 }
1088 
1089 static idmap_retcode
1090 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
1091 	char		*end;
1092 	char		*sql = NULL;
1093 	const char	**values;
1094 	sqlite_vm	*vm = NULL;
1095 	int		ncol, is_user;
1096 	uid_t		pid;
1097 	idmap_utf8str	*str;
1098 	time_t		curtime, exp;
1099 	idmap_retcode	retcode;
1100 
1101 	/* Current time */
1102 	errno = 0;
1103 	if ((curtime = time(NULL)) == (time_t)-1) {
1104 		idmapdlog(LOG_ERR,
1105 			"Failed to get current time (%s)",
1106 			strerror(errno));
1107 		retcode = IDMAP_ERR_INTERNAL;
1108 		goto out;
1109 	}
1110 
1111 	/* SQL to lookup the cache */
1112 	sql = sqlite_mprintf("SELECT pid, is_user, expiration, unixname, u2w "
1113 			"FROM idmap_cache WHERE "
1114 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
1115 			"(pid >= 2147483648 OR "
1116 			"(expiration = 0 OR expiration ISNULL OR "
1117 			"expiration > %d));",
1118 			req->id1.idmap_id_u.sid.prefix,
1119 			req->id1.idmap_id_u.sid.rid,
1120 			curtime);
1121 	if (sql == NULL) {
1122 		idmapdlog(LOG_ERR, "Out of memory");
1123 		retcode = IDMAP_ERR_MEMORY;
1124 		goto out;
1125 	}
1126 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
1127 	sqlite_freemem(sql);
1128 
1129 	if (retcode == IDMAP_ERR_NOTFOUND) {
1130 		goto out;
1131 	} else if (retcode == IDMAP_SUCCESS) {
1132 		/* sanity checks */
1133 		if (values[0] == NULL || values[1] == NULL) {
1134 			retcode = IDMAP_ERR_CACHE;
1135 			goto out;
1136 		}
1137 
1138 		pid = strtoul(values[0], &end, 10);
1139 		is_user = strncmp(values[1], "0", 2)?1:0;
1140 
1141 		/*
1142 		 * We may have an expired ephemeral mapping. Consider
1143 		 * the expired entry as valid if we are not going to
1144 		 * perform name-based mapping. But do not renew the
1145 		 * expiration.
1146 		 * If we will be doing name-based mapping then store the
1147 		 * ephemeral pid in the result so that we can use it
1148 		 * if we end up doing dynamic mapping again.
1149 		 */
1150 		if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) &&
1151 				!AVOID_NAMESERVICE(req)) {
1152 			if (IS_EPHEMERAL(pid) && values[2] != NULL) {
1153 				exp = strtoll(values[2], &end, 10);
1154 				if (exp && exp <= curtime) {
1155 					/* Store the ephemeral pid */
1156 					res->id.idmap_id_u.uid = pid;
1157 					res->id.idtype = is_user?
1158 						IDMAP_UID:IDMAP_GID;
1159 					res->direction = IDMAP_DIRECTION_BI;
1160 					req->direction |= is_user?
1161 						_IDMAP_F_EXP_EPH_UID:
1162 						_IDMAP_F_EXP_EPH_GID;
1163 					retcode = IDMAP_ERR_NOTFOUND;
1164 					goto out;
1165 				}
1166 			}
1167 		}
1168 
1169 		switch (req->id2.idtype) {
1170 		case IDMAP_UID:
1171 			if (!is_user)
1172 				retcode = IDMAP_ERR_NOTUSER;
1173 			else
1174 				res->id.idmap_id_u.uid = pid;
1175 			break;
1176 		case IDMAP_GID:
1177 			if (is_user)
1178 				retcode = IDMAP_ERR_NOTGROUP;
1179 			else
1180 				res->id.idmap_id_u.gid = pid;
1181 			break;
1182 		case IDMAP_POSIXID:
1183 			res->id.idmap_id_u.uid = pid;
1184 			res->id.idtype = (is_user)?IDMAP_UID:IDMAP_GID;
1185 			break;
1186 		default:
1187 			retcode = IDMAP_ERR_NOTSUPPORTED;
1188 			break;
1189 		}
1190 	}
1191 
1192 out:
1193 	if (retcode == IDMAP_SUCCESS) {
1194 		if (values[4] != NULL)
1195 			res->direction =
1196 			    (strtol(values[4], &end, 10) == 0)?
1197 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
1198 		else
1199 			res->direction = IDMAP_DIRECTION_W2U;
1200 
1201 		if (values[3] != NULL) {
1202 			str = &req->id2name;
1203 			retcode = idmap_str2utf8(&str, values[3], 0);
1204 			if (retcode != IDMAP_SUCCESS) {
1205 				idmapdlog(LOG_ERR, "Out of memory");
1206 				retcode = IDMAP_ERR_MEMORY;
1207 			}
1208 		}
1209 	}
1210 	if (vm != NULL)
1211 		(void) sqlite_finalize(vm, NULL);
1212 	return (retcode);
1213 }
1214 
1215 static idmap_retcode
1216 lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid,
1217 		char **name, char **domain, int *type) {
1218 	char		*end;
1219 	char		*sql = NULL;
1220 	const char	**values;
1221 	sqlite_vm	*vm = NULL;
1222 	int		ncol;
1223 	time_t		curtime;
1224 	idmap_retcode	retcode = IDMAP_SUCCESS;
1225 
1226 	/* Get current time */
1227 	errno = 0;
1228 	if ((curtime = time(NULL)) == (time_t)-1) {
1229 		idmapdlog(LOG_ERR,
1230 			"Failed to get current time (%s)",
1231 			strerror(errno));
1232 		retcode = IDMAP_ERR_INTERNAL;
1233 		goto out;
1234 	}
1235 
1236 	/* SQL to lookup the cache */
1237 	sql = sqlite_mprintf("SELECT name, domain, type FROM name_cache WHERE "
1238 			"sidprefix = %Q AND rid = %u AND "
1239 			"(expiration = 0 OR expiration ISNULL OR "
1240 			"expiration > %d);",
1241 			sidprefix, rid, curtime);
1242 	if (sql == NULL) {
1243 		idmapdlog(LOG_ERR, "Out of memory");
1244 		retcode = IDMAP_ERR_MEMORY;
1245 		goto out;
1246 	}
1247 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
1248 	sqlite_freemem(sql);
1249 
1250 	if (retcode == IDMAP_SUCCESS) {
1251 		if (type != NULL) {
1252 			if (values[2] == NULL) {
1253 				retcode = IDMAP_ERR_CACHE;
1254 				goto out;
1255 			}
1256 			*type = strtol(values[2], &end, 10);
1257 		}
1258 
1259 		if (name != NULL && values[0] != NULL) {
1260 			if ((*name = strdup(values[0])) == NULL) {
1261 				idmapdlog(LOG_ERR, "Out of memory");
1262 				retcode = IDMAP_ERR_MEMORY;
1263 				goto out;
1264 			}
1265 		}
1266 
1267 		if (domain != NULL && values[1] != NULL) {
1268 			if ((*domain = strdup(values[1])) == NULL) {
1269 				if (name != NULL && *name) {
1270 					free(*name);
1271 					*name = NULL;
1272 				}
1273 				idmapdlog(LOG_ERR, "Out of memory");
1274 				retcode = IDMAP_ERR_MEMORY;
1275 				goto out;
1276 			}
1277 		}
1278 	}
1279 
1280 out:
1281 	if (vm != NULL)
1282 		(void) sqlite_finalize(vm, NULL);
1283 	return (retcode);
1284 }
1285 
1286 static idmap_retcode
1287 verify_type(idmap_id_type idtype, int type, idmap_id_res *res) {
1288 	switch (idtype) {
1289 	case IDMAP_UID:
1290 		if (type != _IDMAP_T_USER)
1291 			return (IDMAP_ERR_NOTUSER);
1292 		res->id.idtype = IDMAP_UID;
1293 		break;
1294 	case IDMAP_GID:
1295 		if (type != _IDMAP_T_GROUP)
1296 			return (IDMAP_ERR_NOTGROUP);
1297 		res->id.idtype = IDMAP_GID;
1298 		break;
1299 	case IDMAP_POSIXID:
1300 		if (type == _IDMAP_T_USER)
1301 			res->id.idtype = IDMAP_UID;
1302 		else if (type == _IDMAP_T_GROUP)
1303 			res->id.idtype = IDMAP_GID;
1304 		else
1305 			return (IDMAP_ERR_SID);
1306 		break;
1307 	default:
1308 		return (IDMAP_ERR_NOTSUPPORTED);
1309 	}
1310 	return (IDMAP_SUCCESS);
1311 }
1312 
1313 /*
1314  * Lookup sid to name locally
1315  */
1316 static idmap_retcode
1317 lookup_local_sid2name(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
1318 	int		type = -1;
1319 	idmap_retcode	retcode;
1320 	char		*sidprefix;
1321 	idmap_rid_t	rid;
1322 	char		*name = NULL, *domain = NULL;
1323 	idmap_utf8str	*str;
1324 
1325 	sidprefix = req->id1.idmap_id_u.sid.prefix;
1326 	rid = req->id1.idmap_id_u.sid.rid;
1327 
1328 	/* Lookup sids to name in well-known sids table */
1329 	retcode = lookup_wksids_sid2name(sidprefix, rid, &name, &type);
1330 	if (retcode != IDMAP_ERR_NOTFOUND)
1331 		goto out;
1332 
1333 	/* Lookup sid to name in cache */
1334 	retcode = lookup_cache_sid2name(cache, sidprefix, rid, &name,
1335 		&domain, &type);
1336 	if (retcode != IDMAP_SUCCESS)
1337 		goto out;
1338 
1339 out:
1340 	if (retcode == IDMAP_SUCCESS) {
1341 		/* Verify that the sid type matches the request */
1342 		retcode = verify_type(req->id2.idtype, type, res);
1343 
1344 		/* update state in 'req' */
1345 		if (name != NULL) {
1346 			str = &req->id1name;
1347 			(void) idmap_str2utf8(&str, name, 1);
1348 		}
1349 		if (domain != NULL) {
1350 			str = &req->id1domain;
1351 			(void) idmap_str2utf8(&str, domain, 1);
1352 		}
1353 	} else {
1354 		if (name != NULL)
1355 			free(name);
1356 		if (domain != NULL)
1357 			free(domain);
1358 	}
1359 	return (retcode);
1360 }
1361 
1362 idmap_retcode
1363 lookup_win_batch_sid2name(lookup_state_t *state, idmap_mapping_batch *batch,
1364 		idmap_ids_res *result) {
1365 	idmap_retcode	retcode;
1366 	int		ret, i;
1367 	int		retries = 0;
1368 	idmap_mapping	*req;
1369 	idmap_id_res	*res;
1370 
1371 	if (state->ad_nqueries == 0)
1372 		return (IDMAP_SUCCESS);
1373 
1374 retry:
1375 	ret = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries,
1376 		&state->ad_lookup);
1377 	if (ret != 0) {
1378 		idmapdlog(LOG_ERR,
1379 		"Failed to create sid2name batch for AD lookup");
1380 		return (IDMAP_ERR_INTERNAL);
1381 	}
1382 
1383 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
1384 		req = &batch->idmap_mapping_batch_val[i];
1385 		res = &result->ids.ids_val[i];
1386 
1387 		if (req->id1.idtype == IDMAP_SID &&
1388 				req->direction & _IDMAP_F_S2N_AD) {
1389 			if (retries == 0)
1390 				res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
1391 			else if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
1392 				continue;
1393 			retcode = idmap_sid2name_batch_add1(
1394 					state->ad_lookup,
1395 					req->id1.idmap_id_u.sid.prefix,
1396 					&req->id1.idmap_id_u.sid.rid,
1397 					&req->id1name.idmap_utf8str_val,
1398 					&req->id1domain.idmap_utf8str_val,
1399 					(int *)&res->id.idtype,
1400 					&res->retcode);
1401 
1402 			if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
1403 				break;
1404 			if (retcode != IDMAP_SUCCESS)
1405 				goto out;
1406 		}
1407 	}
1408 
1409 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
1410 		idmap_lookup_release_batch(&state->ad_lookup);
1411 	else
1412 		retcode = idmap_lookup_batch_end(&state->ad_lookup, NULL);
1413 
1414 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
1415 		goto retry;
1416 
1417 	return (retcode);
1418 
1419 out:
1420 	idmapdlog(LOG_NOTICE, "Windows SID to user/group name lookup failed");
1421 	idmap_lookup_release_batch(&state->ad_lookup);
1422 	return (retcode);
1423 }
1424 
1425 idmap_retcode
1426 sid2pid_first_pass(lookup_state_t *state, sqlite *cache, idmap_mapping *req,
1427 		idmap_id_res *res) {
1428 	idmap_retcode	retcode;
1429 
1430 	/*
1431 	 * The req->direction field is used to maintain state of the
1432 	 * sid2pid request.
1433 	 */
1434 	req->direction = _IDMAP_F_DONE;
1435 
1436 	if (req->id1.idmap_id_u.sid.prefix == NULL) {
1437 		retcode = IDMAP_ERR_SID;
1438 		goto out;
1439 	}
1440 	res->id.idtype = req->id2.idtype;
1441 	res->id.idmap_id_u.uid = UID_NOBODY;
1442 
1443 	/* Lookup well-known sid to pid mapping */
1444 	retcode = lookup_wksids_sid2pid(req, res);
1445 	if (retcode != IDMAP_ERR_NOTFOUND)
1446 		goto out;
1447 
1448 	/* Lookup sid to pid in cache */
1449 	retcode = lookup_cache_sid2pid(cache, req, res);
1450 	if (retcode != IDMAP_ERR_NOTFOUND)
1451 		goto out;
1452 
1453 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
1454 		res->id.idmap_id_u.uid = SENTINEL_PID;
1455 		goto out;
1456 	}
1457 
1458 	/*
1459 	 * Failed to find non-expired entry in cache. Tell the caller
1460 	 * that we are not done yet.
1461 	 */
1462 	state->sid2pid_done = FALSE;
1463 
1464 	/*
1465 	 * Our next step is name-based mapping. To lookup name-based
1466 	 * mapping rules, we need the windows name and domain-name
1467 	 * associated with the SID.
1468 	 */
1469 
1470 	/*
1471 	 * Check if we already have the name (i.e name2pid lookups)
1472 	 */
1473 	if (req->id1name.idmap_utf8str_val != NULL &&
1474 	    req->id1domain.idmap_utf8str_val != NULL) {
1475 		retcode = IDMAP_SUCCESS;
1476 		req->direction |= _IDMAP_F_S2N_CACHE;
1477 		goto out;
1478 	}
1479 
1480 	/* Lookup sid to winname@domain locally first */
1481 	retcode = lookup_local_sid2name(cache, req, res);
1482 	if (retcode == IDMAP_SUCCESS) {
1483 		req->direction |= _IDMAP_F_S2N_CACHE;
1484 	} else if (retcode == IDMAP_ERR_NOTFOUND) {
1485 		/* Batch sid to name AD lookup request */
1486 		retcode = IDMAP_SUCCESS;
1487 		req->direction |= _IDMAP_F_S2N_AD;
1488 		state->ad_nqueries++;
1489 		goto out;
1490 	}
1491 
1492 
1493 out:
1494 	res->retcode = idmap_stat4prot(retcode);
1495 	return (retcode);
1496 }
1497 
1498 /*
1499  * Generate SID using the following convention
1500  * 	<machine-sid-prefix>-<1000 + uid>
1501  * 	<machine-sid-prefix>-<2^31 + gid>
1502  */
1503 static idmap_retcode
1504 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user) {
1505 
1506 	if (_idmapdstate.cfg->pgcfg.machine_sid != NULL) {
1507 		/* Skip 1000 UIDs */
1508 		if (is_user && req->id1.idmap_id_u.uid >
1509 				(INT32_MAX - LOCALRID_MIN))
1510 			return (IDMAP_ERR_NOMAPPING);
1511 
1512 		RDLOCK_CONFIG();
1513 		res->id.idmap_id_u.sid.prefix =
1514 			strdup(_idmapdstate.cfg->pgcfg.machine_sid);
1515 		if (res->id.idmap_id_u.sid.prefix == NULL) {
1516 			UNLOCK_CONFIG();
1517 			idmapdlog(LOG_ERR, "Out of memory");
1518 			return (IDMAP_ERR_MEMORY);
1519 		}
1520 		UNLOCK_CONFIG();
1521 		res->id.idmap_id_u.sid.rid =
1522 			(is_user)?req->id1.idmap_id_u.uid + LOCALRID_MIN:
1523 			req->id1.idmap_id_u.gid + INT32_MAX + 1;
1524 		res->direction = IDMAP_DIRECTION_BI;
1525 
1526 		/*
1527 		 * Don't update name_cache because local sids don't have
1528 		 * valid windows names.
1529 		 * We mark the entry as being found in the namecache so that
1530 		 * the cache update routine doesn't update namecache.
1531 		 */
1532 		req->direction = _IDMAP_F_S2N_CACHE;
1533 		return (IDMAP_SUCCESS);
1534 	}
1535 
1536 	return (IDMAP_ERR_NOMAPPING);
1537 }
1538 
1539 static idmap_retcode
1540 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) {
1541 	char		*sidprefix;
1542 	uint32_t	rid;
1543 	int		s;
1544 
1545 	/*
1546 	 * If the sidprefix == localsid then UID = last RID - 1000 or
1547 	 * GID = last RID - 2^31.
1548 	 */
1549 	sidprefix = req->id1.idmap_id_u.sid.prefix;
1550 	rid = req->id1.idmap_id_u.sid.rid;
1551 
1552 	RDLOCK_CONFIG();
1553 	s = (_idmapdstate.cfg->pgcfg.machine_sid)?
1554 		strcasecmp(sidprefix,
1555 		_idmapdstate.cfg->pgcfg.machine_sid):1;
1556 	UNLOCK_CONFIG();
1557 
1558 	if (s == 0) {
1559 		switch (req->id2.idtype) {
1560 		case IDMAP_UID:
1561 			if (rid > INT32_MAX) {
1562 				return (IDMAP_ERR_NOTUSER);
1563 			} else if (rid < LOCALRID_MIN) {
1564 				return (IDMAP_ERR_NOTFOUND);
1565 			}
1566 			res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
1567 			res->id.idtype = IDMAP_UID;
1568 			break;
1569 		case IDMAP_GID:
1570 			if (rid <= INT32_MAX) {
1571 				return (IDMAP_ERR_NOTGROUP);
1572 			}
1573 			res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
1574 			res->id.idtype = IDMAP_GID;
1575 			break;
1576 		case IDMAP_POSIXID:
1577 			if (rid > INT32_MAX) {
1578 				res->id.idmap_id_u.gid =
1579 					rid - INT32_MAX - 1;
1580 				res->id.idtype = IDMAP_GID;
1581 			} else if (rid < LOCALRID_MIN) {
1582 				return (IDMAP_ERR_NOTFOUND);
1583 			} else {
1584 				res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
1585 				res->id.idtype = IDMAP_UID;
1586 			}
1587 			break;
1588 		default:
1589 			return (IDMAP_ERR_NOTSUPPORTED);
1590 		}
1591 		return (IDMAP_SUCCESS);
1592 	}
1593 
1594 	return (IDMAP_ERR_NOTFOUND);
1595 }
1596 
1597 static idmap_retcode
1598 ns_lookup_byname(int is_user, const char *name, idmap_id_res *res) {
1599 	struct passwd	pwd;
1600 	struct group	grp;
1601 	char		buf[1024];
1602 	int		errnum;
1603 	const char	*me = "ns_lookup_byname";
1604 
1605 	if (is_user) {
1606 		if (getpwnam_r(name, &pwd, buf, sizeof (buf)) == NULL) {
1607 			errnum = errno;
1608 			idmapdlog(LOG_WARNING,
1609 			"%s: getpwnam_r(%s) failed (%s).",
1610 				me, name,
1611 				errnum?strerror(errnum):"not found");
1612 			if (errnum == 0)
1613 				return (IDMAP_ERR_NOTFOUND);
1614 			else
1615 				return (IDMAP_ERR_INTERNAL);
1616 		}
1617 		res->id.idmap_id_u.uid = pwd.pw_uid;
1618 		res->id.idtype = IDMAP_UID;
1619 	} else {
1620 		if (getgrnam_r(name, &grp, buf, sizeof (buf)) == NULL) {
1621 			errnum = errno;
1622 			idmapdlog(LOG_WARNING,
1623 			"%s: getgrnam_r(%s) failed (%s).",
1624 				me, name,
1625 				errnum?strerror(errnum):"not found");
1626 			if (errnum == 0)
1627 				return (IDMAP_ERR_NOTFOUND);
1628 			else
1629 				return (IDMAP_ERR_INTERNAL);
1630 		}
1631 		res->id.idmap_id_u.gid = grp.gr_gid;
1632 		res->id.idtype = IDMAP_GID;
1633 	}
1634 	return (IDMAP_SUCCESS);
1635 }
1636 
1637 /*
1638  * Name-based mapping
1639  *
1640  * Case 1: If no rule matches do ephemeral
1641  *
1642  * Case 2: If rule matches and unixname is "" then return no mapping.
1643  *
1644  * Case 3: If rule matches and unixname is specified then lookup name
1645  *  service using the unixname. If unixname not found then return no mapping.
1646  *
1647  * Case 4: If rule matches and unixname is * then lookup name service
1648  *  using winname as the unixname. If unixname not found then process
1649  *  other rules using the lookup order. If no other rule matches then do
1650  *  ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
1651  *  This allows us to specify a fallback unixname per _domain_ or no mapping
1652  *  instead of the default behaviour of doing ephemeral mapping.
1653  *
1654  * Example 1:
1655  * *@sfbay == *
1656  * If looking up windows users foo@sfbay and foo does not exists in
1657  * the name service then foo@sfbay will be mapped to an ephemeral id.
1658  *
1659  * Example 2:
1660  * *@sfbay == *
1661  * *@sfbay => guest
1662  * If looking up windows users foo@sfbay and foo does not exists in
1663  * the name service then foo@sfbay will be mapped to guest.
1664  *
1665  * Example 3:
1666  * *@sfbay == *
1667  * *@sfbay => ""
1668  * If looking up windows users foo@sfbay and foo does not exists in
1669  * the name service then we will return no mapping for foo@sfbay.
1670  *
1671  */
1672 static idmap_retcode
1673 name_based_mapping_sid2pid(sqlite *db, idmap_mapping *req, idmap_id_res *res) {
1674 	const char	*unixname, *winname, *windomain;
1675 	char		*sql = NULL, *errmsg = NULL;
1676 	idmap_retcode	retcode;
1677 	char		*end;
1678 	const char	**values;
1679 	sqlite_vm	*vm = NULL;
1680 	idmap_utf8str	*str;
1681 	int		ncol, r, i, is_user;
1682 	const char	*me = "name_based_mapping_sid2pid";
1683 
1684 	winname = req->id1name.idmap_utf8str_val;
1685 	windomain = req->id1domain.idmap_utf8str_val;
1686 	is_user = (res->id.idtype == IDMAP_UID)?1:0;
1687 
1688 	i = 0;
1689 	if (windomain == NULL) {
1690 		windomain = "";
1691 	} else {
1692 		RDLOCK_CONFIG();
1693 		if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
1694 			if (strcasecmp(_idmapdstate.cfg->pgcfg.mapping_domain,
1695 			    windomain) == 0)
1696 				i = 1;
1697 		}
1698 		UNLOCK_CONFIG();
1699 	}
1700 
1701 	sql = sqlite_mprintf(
1702 		"SELECT unixname, u2w_order FROM namerules WHERE "
1703 		"w2u_order > 0 AND is_user = %d AND "
1704 		"(winname = %Q OR winname = '*') AND "
1705 		"(windomain = %Q OR windomain = '*' %s) "
1706 		"ORDER BY w2u_order ASC;",
1707 		is_user, winname,
1708 		windomain,
1709 		i?"OR windomain ISNULL OR windomain = ''":"");
1710 	if (sql == NULL) {
1711 		idmapdlog(LOG_ERR, "Out of memory");
1712 		retcode = IDMAP_ERR_MEMORY;
1713 		goto out;
1714 	}
1715 
1716 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
1717 		retcode = IDMAP_ERR_INTERNAL;
1718 		idmapdlog(LOG_ERR,
1719 			"%s: database error (%s)",
1720 			me, CHECK_NULL(errmsg));
1721 		sqlite_freemem(errmsg);
1722 		goto out;
1723 	}
1724 
1725 	for (; ; ) {
1726 		r = sqlite_step(vm, &ncol, &values, NULL);
1727 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
1728 
1729 		if (r == SQLITE_ROW) {
1730 			if (ncol < 2) {
1731 				retcode = IDMAP_ERR_INTERNAL;
1732 				goto out;
1733 			}
1734 			if (values[0] == NULL) {
1735 				retcode = IDMAP_ERR_INTERNAL;
1736 				goto out;
1737 			}
1738 
1739 			if (EMPTY_NAME(values[0])) {
1740 				retcode = IDMAP_ERR_NOMAPPING;
1741 				goto out;
1742 			}
1743 			unixname = (values[0][0] == '*')?winname:values[0];
1744 			retcode = ns_lookup_byname(is_user, unixname, res);
1745 			if (retcode == IDMAP_ERR_NOTFOUND) {
1746 				if (unixname == winname)
1747 					/* Case 4 */
1748 					continue;
1749 				else
1750 					/* Case 3 */
1751 					retcode = IDMAP_ERR_NOMAPPING;
1752 			}
1753 			goto out;
1754 		} else if (r == SQLITE_DONE) {
1755 			retcode = IDMAP_ERR_NOTFOUND;
1756 			goto out;
1757 		} else {
1758 			(void) sqlite_finalize(vm, &errmsg);
1759 			vm = NULL;
1760 			idmapdlog(LOG_ERR,
1761 				"%s: database error (%s)",
1762 				me, CHECK_NULL(errmsg));
1763 			sqlite_freemem(errmsg);
1764 			retcode = IDMAP_ERR_INTERNAL;
1765 			goto out;
1766 		}
1767 	}
1768 
1769 out:
1770 	if (sql != NULL)
1771 		sqlite_freemem(sql);
1772 	if (retcode == IDMAP_SUCCESS) {
1773 		if (values[1] != NULL)
1774 			res->direction =
1775 			    (strtol(values[1], &end, 10) == 0)?
1776 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
1777 		else
1778 			res->direction = IDMAP_DIRECTION_W2U;
1779 		str = &req->id2name;
1780 		retcode = idmap_str2utf8(&str, unixname, 0);
1781 	}
1782 	if (vm != NULL)
1783 		(void) sqlite_finalize(vm, NULL);
1784 	return (retcode);
1785 }
1786 
1787 static
1788 int
1789 get_next_eph_uid(uid_t *next_uid)
1790 {
1791 	uid_t uid;
1792 	gid_t gid;
1793 	int err;
1794 
1795 	*next_uid = (uid_t)-1;
1796 	uid = _idmapdstate.next_uid++;
1797 	if (uid >= _idmapdstate.limit_uid) {
1798 		if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0)
1799 			return (err);
1800 
1801 		_idmapdstate.limit_uid = uid + 8192;
1802 		_idmapdstate.next_uid = uid;
1803 	}
1804 	*next_uid = uid;
1805 
1806 	return (0);
1807 }
1808 
1809 static
1810 int
1811 get_next_eph_gid(gid_t *next_gid)
1812 {
1813 	uid_t uid;
1814 	gid_t gid;
1815 	int err;
1816 
1817 	*next_gid = (uid_t)-1;
1818 	gid = _idmapdstate.next_gid++;
1819 	if (gid >= _idmapdstate.limit_gid) {
1820 		if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0)
1821 			return (err);
1822 
1823 		_idmapdstate.limit_gid = gid + 8192;
1824 		_idmapdstate.next_gid = gid;
1825 	}
1826 	*next_gid = gid;
1827 
1828 	return (0);
1829 }
1830 
1831 static
1832 int
1833 gethash(const char *str, uint32_t num, uint_t htsize) {
1834 	uint_t  hval, i, len;
1835 
1836 	if (str == NULL)
1837 		return (0);
1838 	for (len = strlen(str), hval = 0, i = 0; i < len; i++) {
1839 		hval += str[i];
1840 		hval += (hval << 10);
1841 		hval ^= (hval >> 6);
1842 	}
1843 	for (str = (const char *)&num, i = 0; i < sizeof (num); i++) {
1844 		hval += str[i];
1845 		hval += (hval << 10);
1846 		hval ^= (hval >> 6);
1847 	}
1848 	hval += (hval << 3);
1849 	hval ^= (hval >> 11);
1850 	hval += (hval << 15);
1851 	return (hval % htsize);
1852 }
1853 
1854 static
1855 int
1856 get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid,
1857 		uid_t *pid) {
1858 	uint_t		next, key;
1859 	uint_t		htsize = state->sid_history_size;
1860 	idmap_sid	*sid;
1861 
1862 	next = gethash(prefix, rid, htsize);
1863 	while (next != htsize) {
1864 		key = state->sid_history[next].key;
1865 		if (key == htsize)
1866 			return (0);
1867 		sid = &state->batch->idmap_mapping_batch_val[key].id1.
1868 		    idmap_id_u.sid;
1869 		if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) {
1870 			*pid = state->result->ids.ids_val[key].id.
1871 			    idmap_id_u.uid;
1872 			return (1);
1873 		}
1874 		next = state->sid_history[next].next;
1875 	}
1876 	return (0);
1877 }
1878 
1879 static
1880 void
1881 add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) {
1882 	uint_t		hash, next;
1883 	uint_t		htsize = state->sid_history_size;
1884 
1885 	hash = next = gethash(prefix, rid, htsize);
1886 	while (state->sid_history[next].key != htsize) {
1887 		next++;
1888 		next %= htsize;
1889 	}
1890 	state->sid_history[next].key = state->curpos;
1891 	if (hash == next)
1892 		return;
1893 	state->sid_history[next].next = state->sid_history[hash].next;
1894 	state->sid_history[hash].next = next;
1895 }
1896 
1897 /* ARGSUSED */
1898 static
1899 idmap_retcode
1900 dynamic_ephemeral_mapping(lookup_state_t *state, sqlite *cache,
1901 		idmap_mapping *req, idmap_id_res *res) {
1902 
1903 	uid_t		next_pid;
1904 
1905 	res->direction = IDMAP_DIRECTION_BI;
1906 
1907 	if (IS_EPHEMERAL(res->id.idmap_id_u.uid))
1908 		return (IDMAP_SUCCESS);
1909 
1910 	if (state->sid_history != NULL &&
1911 	    get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix,
1912 	    req->id1.idmap_id_u.sid.rid, &next_pid)) {
1913 		res->id.idmap_id_u.uid = next_pid;
1914 		return (IDMAP_SUCCESS);
1915 	}
1916 
1917 	if (res->id.idtype == IDMAP_UID) {
1918 		if (get_next_eph_uid(&next_pid) != 0)
1919 			return (IDMAP_ERR_INTERNAL);
1920 		res->id.idmap_id_u.uid = next_pid;
1921 	} else {
1922 		if (get_next_eph_gid(&next_pid) != 0)
1923 			return (IDMAP_ERR_INTERNAL);
1924 		res->id.idmap_id_u.gid = next_pid;
1925 	}
1926 
1927 	if (state->sid_history != NULL)
1928 		add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix,
1929 		    req->id1.idmap_id_u.sid.rid);
1930 
1931 	return (IDMAP_SUCCESS);
1932 }
1933 
1934 idmap_retcode
1935 sid2pid_second_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
1936 		idmap_mapping *req, idmap_id_res *res) {
1937 	idmap_retcode	retcode;
1938 
1939 	/*
1940 	 * The req->direction field is used to maintain state of the
1941 	 * sid2pid request.
1942 	 */
1943 
1944 	/* Check if second pass is needed */
1945 	if (req->direction == _IDMAP_F_DONE)
1946 		return (res->retcode);
1947 
1948 	/* Get status from previous pass */
1949 	retcode = (res->retcode == IDMAP_NEXT)?IDMAP_SUCCESS:res->retcode;
1950 
1951 	if (retcode != IDMAP_SUCCESS) {
1952 		/* Reset return type */
1953 		res->id.idtype = req->id2.idtype;
1954 		res->id.idmap_id_u.uid = UID_NOBODY;
1955 
1956 		/* Check if this is a localsid */
1957 		if (retcode == IDMAP_ERR_NOTFOUND &&
1958 		    _idmapdstate.cfg->pgcfg.machine_sid) {
1959 			retcode = lookup_localsid2pid(req, res);
1960 			if (retcode == IDMAP_SUCCESS) {
1961 				state->sid2pid_done = FALSE;
1962 				req->direction = _IDMAP_F_S2N_CACHE;
1963 			}
1964 		}
1965 		goto out;
1966 	}
1967 
1968 	/*
1969 	 * Verify that the sid type matches the request if the
1970 	 * SID was validated by an AD lookup.
1971 	 */
1972 	if (req->direction & _IDMAP_F_S2N_AD) {
1973 		retcode = verify_type(req->id2.idtype,
1974 			(int)res->id.idtype, res);
1975 		if (retcode != IDMAP_SUCCESS) {
1976 			res->id.idtype = req->id2.idtype;
1977 			res->id.idmap_id_u.uid = UID_NOBODY;
1978 			goto out;
1979 		}
1980 	}
1981 
1982 	/* Name-based mapping */
1983 	retcode = name_based_mapping_sid2pid(db, req, res);
1984 	if (retcode == IDMAP_ERR_NOTFOUND)
1985 		/* If not found, do ephemeral mapping */
1986 		goto ephemeral;
1987 	else if (retcode != IDMAP_SUCCESS)
1988 		goto out;
1989 
1990 	state->sid2pid_done = FALSE;
1991 	goto out;
1992 
1993 
1994 ephemeral:
1995 	retcode = dynamic_ephemeral_mapping(state, cache, req, res);
1996 	if (retcode == IDMAP_SUCCESS)
1997 		state->sid2pid_done = FALSE;
1998 
1999 out:
2000 	res->retcode = idmap_stat4prot(retcode);
2001 	return (retcode);
2002 }
2003 
2004 idmap_retcode
2005 update_cache_pid2sid(lookup_state_t *state, sqlite *cache,
2006 		idmap_mapping *req, idmap_id_res *res) {
2007 	char		*sql = NULL;
2008 	idmap_retcode	retcode;
2009 
2010 	/* Check if we need to cache anything */
2011 	if (req->direction == _IDMAP_F_DONE)
2012 		return (IDMAP_SUCCESS);
2013 
2014 	/* We don't cache negative entries */
2015 	if (res->retcode != IDMAP_SUCCESS)
2016 		return (IDMAP_SUCCESS);
2017 
2018 	/*
2019 	 * Using NULL for u2w instead of 0 so that our trigger allows
2020 	 * the same pid to be the destination in multiple entries
2021 	 */
2022 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
2023 		"(sidprefix, rid, windomain, winname, pid, unixname, "
2024 		"is_user, expiration, w2u, u2w) "
2025 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
2026 		"strftime('%%s','now') + 600, %q, 1); ",
2027 		res->id.idmap_id_u.sid.prefix,
2028 		res->id.idmap_id_u.sid.rid,
2029 		req->id2domain.idmap_utf8str_val,
2030 		req->id2name.idmap_utf8str_val,
2031 		req->id1.idmap_id_u.uid,
2032 		req->id1name.idmap_utf8str_val,
2033 		(req->id1.idtype == IDMAP_UID)?1:0,
2034 		(res->direction == 0)?"1":NULL);
2035 
2036 	if (sql == NULL) {
2037 		retcode = IDMAP_ERR_INTERNAL;
2038 		idmapdlog(LOG_ERR, "Out of memory");
2039 		goto out;
2040 	}
2041 
2042 	retcode = sql_exec_no_cb(cache, sql);
2043 	if (retcode != IDMAP_SUCCESS)
2044 		goto out;
2045 
2046 	state->pid2sid_done = FALSE;
2047 	sqlite_freemem(sql);
2048 	sql = NULL;
2049 
2050 	/* If sid2name was found in the cache, no need to update namecache */
2051 	if (req->direction & _IDMAP_F_S2N_CACHE)
2052 		goto out;
2053 
2054 	if (req->id2name.idmap_utf8str_val == NULL)
2055 		goto out;
2056 
2057 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
2058 		"(sidprefix, rid, name, domain, type, expiration) "
2059 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
2060 		res->id.idmap_id_u.sid.prefix,
2061 		res->id.idmap_id_u.sid.rid,
2062 		req->id2name.idmap_utf8str_val,
2063 		req->id2domain.idmap_utf8str_val,
2064 		(req->id1.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
2065 
2066 	if (sql == NULL) {
2067 		retcode = IDMAP_ERR_INTERNAL;
2068 		idmapdlog(LOG_ERR, "Out of memory");
2069 		goto out;
2070 	}
2071 
2072 	retcode = sql_exec_no_cb(cache, sql);
2073 
2074 out:
2075 	if (sql != NULL)
2076 		sqlite_freemem(sql);
2077 	return (retcode);
2078 }
2079 
2080 idmap_retcode
2081 update_cache_sid2pid(lookup_state_t *state, sqlite *cache,
2082 		idmap_mapping *req, idmap_id_res *res) {
2083 	char		*sql = NULL;
2084 	idmap_retcode	retcode;
2085 	int		is_eph_user;
2086 
2087 	/* Check if we need to cache anything */
2088 	if (req->direction == _IDMAP_F_DONE)
2089 		return (IDMAP_SUCCESS);
2090 
2091 	/* We don't cache negative entries */
2092 	if (res->retcode != IDMAP_SUCCESS)
2093 		return (IDMAP_SUCCESS);
2094 
2095 	if (req->direction & _IDMAP_F_EXP_EPH_UID)
2096 		is_eph_user = 1;
2097 	else if (req->direction & _IDMAP_F_EXP_EPH_GID)
2098 		is_eph_user = 0;
2099 	else
2100 		is_eph_user = -1;
2101 
2102 	if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
2103 		sql = sqlite_mprintf("UPDATE idmap_cache "
2104 			"SET w2u = 0 WHERE "
2105 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
2106 			"pid >= 2147483648 AND is_user = %d;",
2107 			req->id1.idmap_id_u.sid.prefix,
2108 			req->id1.idmap_id_u.sid.rid,
2109 			is_eph_user);
2110 		if (sql == NULL) {
2111 			retcode = IDMAP_ERR_INTERNAL;
2112 			idmapdlog(LOG_ERR, "Out of memory");
2113 			goto out;
2114 		}
2115 
2116 		retcode = sql_exec_no_cb(cache, sql);
2117 		if (retcode != IDMAP_SUCCESS)
2118 			goto out;
2119 
2120 		sqlite_freemem(sql);
2121 		sql = NULL;
2122 	}
2123 
2124 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
2125 		"(sidprefix, rid, windomain, winname, pid, unixname, "
2126 		"is_user, expiration, w2u, u2w) "
2127 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
2128 		"strftime('%%s','now') + 600, 1, %q); ",
2129 		req->id1.idmap_id_u.sid.prefix,
2130 		req->id1.idmap_id_u.sid.rid,
2131 		req->id1domain.idmap_utf8str_val,
2132 		req->id1name.idmap_utf8str_val,
2133 		res->id.idmap_id_u.uid,
2134 		req->id2name.idmap_utf8str_val,
2135 		(res->id.idtype == IDMAP_UID)?1:0,
2136 		(res->direction == 0)?"1":NULL);
2137 
2138 	if (sql == NULL) {
2139 		retcode = IDMAP_ERR_INTERNAL;
2140 		idmapdlog(LOG_ERR, "Out of memory");
2141 		goto out;
2142 	}
2143 
2144 	retcode = sql_exec_no_cb(cache, sql);
2145 	if (retcode != IDMAP_SUCCESS)
2146 		goto out;
2147 
2148 	state->sid2pid_done = FALSE;
2149 	sqlite_freemem(sql);
2150 	sql = NULL;
2151 
2152 	/* If name2sid was found in the cache, no need to update namecache */
2153 	if (req->direction & _IDMAP_F_S2N_CACHE)
2154 		goto out;
2155 
2156 	if (req->id1name.idmap_utf8str_val == NULL)
2157 		goto out;
2158 
2159 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
2160 		"(sidprefix, rid, name, domain, type, expiration) "
2161 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
2162 		req->id1.idmap_id_u.sid.prefix,
2163 		req->id1.idmap_id_u.sid.rid,
2164 		req->id1name.idmap_utf8str_val,
2165 		req->id1domain.idmap_utf8str_val,
2166 		(res->id.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
2167 
2168 	if (sql == NULL) {
2169 		retcode = IDMAP_ERR_INTERNAL;
2170 		idmapdlog(LOG_ERR, "Out of memory");
2171 		goto out;
2172 	}
2173 
2174 	retcode = sql_exec_no_cb(cache, sql);
2175 
2176 out:
2177 	if (sql != NULL)
2178 		sqlite_freemem(sql);
2179 	return (retcode);
2180 }
2181 
2182 static idmap_retcode
2183 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
2184 		int is_user, int getname) {
2185 	char		*end;
2186 	char		*sql = NULL;
2187 	const char	**values;
2188 	sqlite_vm	*vm = NULL;
2189 	int		ncol;
2190 	idmap_retcode	retcode = IDMAP_SUCCESS;
2191 	idmap_utf8str	*str;
2192 	time_t		curtime;
2193 
2194 	/* Current time */
2195 	errno = 0;
2196 	if ((curtime = time(NULL)) == (time_t)-1) {
2197 		idmapdlog(LOG_ERR,
2198 			"Failed to get current time (%s)",
2199 			strerror(errno));
2200 		retcode = IDMAP_ERR_INTERNAL;
2201 		goto out;
2202 	}
2203 
2204 	/* SQL to lookup the cache */
2205 	sql = sqlite_mprintf("SELECT sidprefix, rid, winname, windomain, w2u "
2206 			"FROM idmap_cache WHERE "
2207 			"pid = %u AND u2w = 1 AND is_user = %d AND "
2208 			"(pid >= 2147483648 OR "
2209 			"(expiration = 0 OR expiration ISNULL OR "
2210 			"expiration > %d));",
2211 			req->id1.idmap_id_u.uid, is_user, curtime);
2212 	if (sql == NULL) {
2213 		idmapdlog(LOG_ERR, "Out of memory");
2214 		retcode = IDMAP_ERR_MEMORY;
2215 		goto out;
2216 	}
2217 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
2218 	sqlite_freemem(sql);
2219 
2220 	if (retcode == IDMAP_ERR_NOTFOUND)
2221 		goto out;
2222 	else if (retcode == IDMAP_SUCCESS) {
2223 		/* sanity checks */
2224 		if (values[0] == NULL || values[1] == NULL) {
2225 			retcode = IDMAP_ERR_CACHE;
2226 			goto out;
2227 		}
2228 
2229 		switch (req->id2.idtype) {
2230 		case IDMAP_SID:
2231 			res->id.idmap_id_u.sid.rid =
2232 				strtoul(values[1], &end, 10);
2233 			res->id.idmap_id_u.sid.prefix = strdup(values[0]);
2234 			if (res->id.idmap_id_u.sid.prefix == NULL) {
2235 				idmapdlog(LOG_ERR, "Out of memory");
2236 				retcode = IDMAP_ERR_MEMORY;
2237 				goto out;
2238 			}
2239 
2240 			if (values[4] != NULL)
2241 				res->direction =
2242 				    (strtol(values[4], &end, 10) == 0)?
2243 				    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
2244 			else
2245 				res->direction = IDMAP_DIRECTION_U2W;
2246 
2247 			if (getname == 0 || values[2] == NULL)
2248 				break;
2249 			str = &req->id2name;
2250 			retcode = idmap_str2utf8(&str, values[2], 0);
2251 			if (retcode != IDMAP_SUCCESS) {
2252 				idmapdlog(LOG_ERR, "Out of memory");
2253 				retcode = IDMAP_ERR_MEMORY;
2254 				goto out;
2255 			}
2256 
2257 			if (values[3] == NULL)
2258 				break;
2259 			str = &req->id2domain;
2260 			retcode = idmap_str2utf8(&str, values[3], 0);
2261 			if (retcode != IDMAP_SUCCESS) {
2262 				idmapdlog(LOG_ERR, "Out of memory");
2263 				retcode = IDMAP_ERR_MEMORY;
2264 				goto out;
2265 			}
2266 			break;
2267 		default:
2268 			retcode = IDMAP_ERR_NOTSUPPORTED;
2269 			break;
2270 		}
2271 	}
2272 
2273 out:
2274 	if (vm != NULL)
2275 		(void) sqlite_finalize(vm, NULL);
2276 	return (retcode);
2277 }
2278 
2279 static idmap_retcode
2280 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain,
2281 		char **sidprefix, idmap_rid_t *rid, int *type) {
2282 	char		*end;
2283 	char		*sql = NULL;
2284 	const char	**values;
2285 	sqlite_vm	*vm = NULL;
2286 	int		ncol;
2287 	time_t		curtime;
2288 	idmap_retcode	retcode = IDMAP_SUCCESS;
2289 
2290 	/* Get current time */
2291 	errno = 0;
2292 	if ((curtime = time(NULL)) == (time_t)-1) {
2293 		idmapdlog(LOG_ERR,
2294 			"Failed to get current time (%s)",
2295 			strerror(errno));
2296 		retcode = IDMAP_ERR_INTERNAL;
2297 		goto out;
2298 	}
2299 
2300 	/* SQL to lookup the cache */
2301 	sql = sqlite_mprintf("SELECT sidprefix, rid, type FROM name_cache "
2302 			"WHERE name = %Q AND domain = %Q AND "
2303 			"(expiration = 0 OR expiration ISNULL OR "
2304 			"expiration > %d);",
2305 			name, domain, curtime);
2306 	if (sql == NULL) {
2307 		idmapdlog(LOG_ERR, "Out of memory");
2308 		retcode = IDMAP_ERR_MEMORY;
2309 		goto out;
2310 	}
2311 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
2312 	sqlite_freemem(sql);
2313 
2314 	if (retcode == IDMAP_SUCCESS) {
2315 		if (type != NULL) {
2316 			if (values[2] == NULL) {
2317 				retcode = IDMAP_ERR_CACHE;
2318 				goto out;
2319 			}
2320 			*type = strtol(values[2], &end, 10);
2321 		}
2322 
2323 		if (values[0] == NULL || values[1] == NULL) {
2324 			retcode = IDMAP_ERR_CACHE;
2325 			goto out;
2326 		}
2327 		if ((*sidprefix = strdup(values[0])) == NULL) {
2328 			idmapdlog(LOG_ERR, "Out of memory");
2329 			retcode = IDMAP_ERR_MEMORY;
2330 			goto out;
2331 		}
2332 		*rid = strtoul(values[1], &end, 10);
2333 	}
2334 
2335 out:
2336 	if (vm != NULL)
2337 		(void) sqlite_finalize(vm, NULL);
2338 	return (retcode);
2339 }
2340 
2341 static idmap_retcode
2342 lookup_win_name2sid(const char *name, const char *domain, char **sidprefix,
2343 		idmap_rid_t *rid, int *type) {
2344 	int			ret;
2345 	int			retries = 0;
2346 	idmap_query_state_t	*qs = NULL;
2347 	idmap_retcode		rc, retcode;
2348 
2349 	retcode = IDMAP_ERR_NOTFOUND;
2350 
2351 retry:
2352 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
2353 	if (ret != 0) {
2354 		idmapdlog(LOG_ERR,
2355 		"Failed to create name2sid batch for AD lookup");
2356 		return (IDMAP_ERR_INTERNAL);
2357 	}
2358 
2359 	retcode = idmap_name2sid_batch_add1(qs, name, domain, sidprefix,
2360 					rid, type, &rc);
2361 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
2362 		goto out;
2363 
2364 	if (retcode != IDMAP_SUCCESS) {
2365 		idmapdlog(LOG_ERR,
2366 		"Failed to batch name2sid for AD lookup");
2367 		idmap_lookup_release_batch(&qs);
2368 		return (IDMAP_ERR_INTERNAL);
2369 	}
2370 
2371 out:
2372 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
2373 		idmap_lookup_release_batch(&qs);
2374 	else
2375 		retcode = idmap_lookup_batch_end(&qs, NULL);
2376 
2377 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
2378 		goto retry;
2379 
2380 	if (retcode != IDMAP_SUCCESS) {
2381 		idmapdlog(LOG_NOTICE, "Windows user/group name to SID lookup "
2382 		    "failed");
2383 		return (retcode);
2384 	} else
2385 		return (rc);
2386 	/* NOTREACHED */
2387 }
2388 
2389 static idmap_retcode
2390 lookup_name2sid(sqlite *cache, const char *name, const char *domain,
2391 		int *is_user, char **sidprefix, idmap_rid_t *rid,
2392 		idmap_mapping *req) {
2393 	int		type;
2394 	idmap_retcode	retcode;
2395 
2396 	/* Lookup name@domain to sid in the well-known sids table */
2397 	retcode = lookup_wksids_name2sid(name, sidprefix, rid, &type);
2398 	if (retcode == IDMAP_SUCCESS) {
2399 		req->direction |= _IDMAP_F_S2N_CACHE;
2400 		goto out;
2401 	} else if (retcode != IDMAP_ERR_NOTFOUND) {
2402 		return (retcode);
2403 	}
2404 
2405 	/* Lookup name@domain to sid in cache */
2406 	retcode = lookup_cache_name2sid(cache, name, domain, sidprefix,
2407 		rid, &type);
2408 	if (retcode == IDMAP_ERR_NOTFOUND) {
2409 		/* Lookup Windows NT/AD to map name@domain to sid */
2410 		retcode = lookup_win_name2sid(name, domain, sidprefix, rid,
2411 			&type);
2412 		if (retcode != IDMAP_SUCCESS)
2413 			return (retcode);
2414 		req->direction |= _IDMAP_F_S2N_AD;
2415 	} else if (retcode != IDMAP_SUCCESS) {
2416 		return (retcode);
2417 	} else {
2418 		/* Set flag */
2419 		req->direction |= _IDMAP_F_S2N_CACHE;
2420 	}
2421 
2422 out:
2423 	/*
2424 	 * Entry found (cache or Windows lookup)
2425 	 * is_user is both input as well as output parameter
2426 	 */
2427 	if (*is_user == 1) {
2428 		if (type != _IDMAP_T_USER)
2429 			return (IDMAP_ERR_NOTUSER);
2430 	} else if (*is_user == 0) {
2431 		if (type != _IDMAP_T_GROUP)
2432 			return (IDMAP_ERR_NOTGROUP);
2433 	} else if (*is_user == -1) {
2434 		/* Caller wants to know if its user or group */
2435 		if (type == _IDMAP_T_USER)
2436 			*is_user = 1;
2437 		else if (type == _IDMAP_T_GROUP)
2438 			*is_user = 0;
2439 		else
2440 			return (IDMAP_ERR_SID);
2441 	}
2442 
2443 	return (retcode);
2444 }
2445 
2446 static idmap_retcode
2447 name_based_mapping_pid2sid(sqlite *db, sqlite *cache, const char *unixname,
2448 		int is_user, idmap_mapping *req, idmap_id_res *res) {
2449 	const char	*winname, *windomain;
2450 	char		*mapping_domain = NULL;
2451 	char		*sql = NULL, *errmsg = NULL;
2452 	idmap_retcode	retcode;
2453 	char		*end;
2454 	const char	**values;
2455 	sqlite_vm	*vm = NULL;
2456 	idmap_utf8str	*str;
2457 	int		ncol, r;
2458 	const char	*me = "name_based_mapping_pid2sid";
2459 
2460 	RDLOCK_CONFIG();
2461 	if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
2462 		mapping_domain =
2463 			strdup(_idmapdstate.cfg->pgcfg.mapping_domain);
2464 		if (mapping_domain == NULL) {
2465 			UNLOCK_CONFIG();
2466 			idmapdlog(LOG_ERR, "Out of memory");
2467 			retcode = IDMAP_ERR_MEMORY;
2468 			goto out;
2469 		}
2470 	}
2471 	UNLOCK_CONFIG();
2472 
2473 	sql = sqlite_mprintf(
2474 		"SELECT winname, windomain, w2u_order FROM namerules WHERE "
2475 		"u2w_order > 0 AND is_user = %d AND "
2476 		"(unixname = %Q OR unixname = '*') "
2477 		"ORDER BY u2w_order ASC;",
2478 		is_user, unixname);
2479 	if (sql == NULL) {
2480 		idmapdlog(LOG_ERR, "Out of memory");
2481 		retcode = IDMAP_ERR_MEMORY;
2482 		goto out;
2483 	}
2484 
2485 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
2486 		retcode = IDMAP_ERR_INTERNAL;
2487 		idmapdlog(LOG_ERR,
2488 			"%s: database error (%s)",
2489 			me, CHECK_NULL(errmsg));
2490 		sqlite_freemem(errmsg);
2491 		goto out;
2492 	}
2493 
2494 	for (;;) {
2495 		r = sqlite_step(vm, &ncol, &values, NULL);
2496 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
2497 		if (r == SQLITE_ROW) {
2498 			if (ncol < 3) {
2499 				retcode = IDMAP_ERR_INTERNAL;
2500 				goto out;
2501 			}
2502 			if (values[0] == NULL) {
2503 				/* values [1] and [2] can be null */
2504 				retcode = IDMAP_ERR_INTERNAL;
2505 				goto out;
2506 			}
2507 			if (EMPTY_NAME(values[0])) {
2508 				retcode = IDMAP_ERR_NOMAPPING;
2509 				goto out;
2510 			}
2511 			winname = (values[0][0] == '*')?unixname:values[0];
2512 			if (values[1] != NULL)
2513 				windomain = values[1];
2514 			else if (mapping_domain != NULL)
2515 				windomain = mapping_domain;
2516 			else {
2517 				idmapdlog(LOG_ERR,
2518 					"%s: no domain", me);
2519 				retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
2520 				goto out;
2521 			}
2522 			/* Lookup winname@domain to sid */
2523 			retcode = lookup_name2sid(cache, winname, windomain,
2524 				&is_user, &res->id.idmap_id_u.sid.prefix,
2525 				&res->id.idmap_id_u.sid.rid, req);
2526 			if (retcode == IDMAP_ERR_NOTFOUND) {
2527 				if (winname == unixname)
2528 					continue;
2529 				else
2530 					retcode = IDMAP_ERR_NOMAPPING;
2531 			}
2532 			goto out;
2533 		} else if (r == SQLITE_DONE) {
2534 			retcode = IDMAP_ERR_NOTFOUND;
2535 			goto out;
2536 		} else {
2537 			(void) sqlite_finalize(vm, &errmsg);
2538 			vm = NULL;
2539 			idmapdlog(LOG_ERR,
2540 				"%s: database error (%s)",
2541 				me, CHECK_NULL(errmsg));
2542 			sqlite_freemem(errmsg);
2543 			retcode = IDMAP_ERR_INTERNAL;
2544 			goto out;
2545 		}
2546 	}
2547 
2548 out:
2549 	if (sql != NULL)
2550 		sqlite_freemem(sql);
2551 	if (retcode == IDMAP_SUCCESS) {
2552 		if (values[2] != NULL)
2553 			res->direction =
2554 			    (strtol(values[2], &end, 10) == 0)?
2555 			    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
2556 		else
2557 			res->direction = IDMAP_DIRECTION_U2W;
2558 		str = &req->id2name;
2559 		retcode = idmap_str2utf8(&str, winname, 0);
2560 		if (retcode == IDMAP_SUCCESS) {
2561 			str = &req->id2domain;
2562 			if (windomain == mapping_domain) {
2563 				(void) idmap_str2utf8(&str, windomain, 1);
2564 				mapping_domain = NULL;
2565 			} else
2566 				retcode = idmap_str2utf8(&str, windomain, 0);
2567 		}
2568 	}
2569 	if (vm != NULL)
2570 		(void) sqlite_finalize(vm, NULL);
2571 	if (mapping_domain != NULL)
2572 		free(mapping_domain);
2573 	return (retcode);
2574 }
2575 
2576 idmap_retcode
2577 pid2sid_first_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
2578 		idmap_mapping *req, idmap_id_res *res, int is_user,
2579 		int getname) {
2580 	char		*unixname = NULL;
2581 	struct passwd	pwd;
2582 	struct group	grp;
2583 	idmap_utf8str	*str;
2584 	char		buf[1024];
2585 	int		errnum;
2586 	idmap_retcode	retcode = IDMAP_SUCCESS;
2587 	const char	*me = "pid2sid";
2588 
2589 	req->direction = _IDMAP_F_DONE;
2590 	res->id.idtype = req->id2.idtype;
2591 
2592 	/* Lookup well-known SIDs */
2593 	retcode = lookup_wksids_pid2sid(req, res, is_user);
2594 	if (retcode != IDMAP_ERR_NOTFOUND)
2595 		goto out;
2596 
2597 	/* Lookup pid to sid in cache */
2598 	retcode = lookup_cache_pid2sid(cache, req, res, is_user, getname);
2599 	if (retcode != IDMAP_ERR_NOTFOUND)
2600 		goto out;
2601 
2602 	/* Ephemeral ids cannot be allocated during pid2sid */
2603 	if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) {
2604 		retcode = IDMAP_ERR_NOMAPPING;
2605 		goto out;
2606 	}
2607 
2608 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
2609 		retcode = IDMAP_ERR_NOMAPPING;
2610 		goto out;
2611 	}
2612 
2613 	/* uid/gid to name */
2614 	if (req->id1name.idmap_utf8str_val != NULL) {
2615 		unixname = req->id1name.idmap_utf8str_val;
2616 	} if (is_user) {
2617 		errno = 0;
2618 		if (getpwuid_r(req->id1.idmap_id_u.uid, &pwd, buf,
2619 				sizeof (buf)) == NULL) {
2620 			errnum = errno;
2621 			idmapdlog(LOG_WARNING,
2622 			"%s: getpwuid_r(%u) failed (%s).",
2623 				me, req->id1.idmap_id_u.uid,
2624 				errnum?strerror(errnum):"not found");
2625 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
2626 					IDMAP_ERR_INTERNAL;
2627 			goto fallback_localsid;
2628 		}
2629 		unixname = pwd.pw_name;
2630 	} else {
2631 		errno = 0;
2632 		if (getgrgid_r(req->id1.idmap_id_u.gid, &grp, buf,
2633 				sizeof (buf)) == NULL) {
2634 			errnum = errno;
2635 			idmapdlog(LOG_WARNING,
2636 			"%s: getgrgid_r(%u) failed (%s).",
2637 				me, req->id1.idmap_id_u.gid,
2638 				errnum?strerror(errnum):"not found");
2639 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
2640 					IDMAP_ERR_INTERNAL;
2641 			goto fallback_localsid;
2642 		}
2643 		unixname = grp.gr_name;
2644 	}
2645 
2646 	/* Name-based mapping */
2647 	retcode = name_based_mapping_pid2sid(db, cache, unixname, is_user,
2648 		req, res);
2649 	if (retcode == IDMAP_ERR_NOTFOUND) {
2650 		retcode = generate_localsid(req, res, is_user);
2651 		goto out;
2652 	} else if (retcode == IDMAP_SUCCESS)
2653 		goto out;
2654 
2655 fallback_localsid:
2656 	/*
2657 	 * Here we generate localsid as fallback id on errors. Our
2658 	 * return status is the error that's been previously assigned.
2659 	 */
2660 	(void) generate_localsid(req, res, is_user);
2661 
2662 out:
2663 	if (retcode == IDMAP_SUCCESS) {
2664 		if (req->id1name.idmap_utf8str_val == NULL &&
2665 		    unixname != NULL) {
2666 			str = &req->id1name;
2667 			retcode = idmap_str2utf8(&str, unixname, 0);
2668 		}
2669 	}
2670 	if (req->direction != _IDMAP_F_DONE)
2671 		state->pid2sid_done = FALSE;
2672 	res->retcode = idmap_stat4prot(retcode);
2673 	return (retcode);
2674 }
2675 
2676 static idmap_retcode
2677 lookup_win_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
2678 		char **domain, int *type) {
2679 	int			ret;
2680 	idmap_query_state_t	*qs = NULL;
2681 	idmap_retcode		rc, retcode;
2682 
2683 	retcode = IDMAP_ERR_NOTFOUND;
2684 
2685 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
2686 	if (ret != 0) {
2687 		idmapdlog(LOG_ERR,
2688 		"Failed to create sid2name batch for AD lookup");
2689 		retcode = IDMAP_ERR_INTERNAL;
2690 		goto out;
2691 	}
2692 
2693 	ret = idmap_sid2name_batch_add1(
2694 			qs, sidprefix, &rid, name, domain, type, &rc);
2695 	if (ret != 0) {
2696 		idmapdlog(LOG_ERR,
2697 		"Failed to batch sid2name for AD lookup");
2698 		retcode = IDMAP_ERR_INTERNAL;
2699 		goto out;
2700 	}
2701 
2702 out:
2703 	if (qs != NULL) {
2704 		ret = idmap_lookup_batch_end(&qs, NULL);
2705 		if (ret != 0) {
2706 			idmapdlog(LOG_ERR,
2707 			"Failed to execute sid2name AD lookup");
2708 			retcode = IDMAP_ERR_INTERNAL;
2709 		} else
2710 			retcode = rc;
2711 	}
2712 
2713 	return (retcode);
2714 }
2715 
2716 static int
2717 copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request)
2718 {
2719 	(void) memset(mapping, 0, sizeof (*mapping));
2720 
2721 	mapping->flag = request->flag;
2722 	mapping->direction = request->direction;
2723 	mapping->id2.idtype = request->id2.idtype;
2724 
2725 	mapping->id1.idtype = request->id1.idtype;
2726 	if (request->id1.idtype == IDMAP_SID) {
2727 		mapping->id1.idmap_id_u.sid.rid =
2728 		    request->id1.idmap_id_u.sid.rid;
2729 		if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) {
2730 			mapping->id1.idmap_id_u.sid.prefix =
2731 			    strdup(request->id1.idmap_id_u.sid.prefix);
2732 			if (mapping->id1.idmap_id_u.sid.prefix == NULL)
2733 				return (-1);
2734 		}
2735 	} else {
2736 		mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid;
2737 	}
2738 
2739 	mapping->id1domain.idmap_utf8str_len =
2740 	    request->id1domain.idmap_utf8str_len;
2741 	if (mapping->id1domain.idmap_utf8str_len) {
2742 		mapping->id1domain.idmap_utf8str_val =
2743 		    strdup(request->id1domain.idmap_utf8str_val);
2744 		if (mapping->id1domain.idmap_utf8str_val == NULL)
2745 			return (-1);
2746 	}
2747 
2748 	mapping->id1name.idmap_utf8str_len  =
2749 	    request->id1name.idmap_utf8str_len;
2750 	if (mapping->id1name.idmap_utf8str_len) {
2751 		mapping->id1name.idmap_utf8str_val =
2752 		    strdup(request->id1name.idmap_utf8str_val);
2753 		if (mapping->id1name.idmap_utf8str_val == NULL)
2754 			return (-1);
2755 	}
2756 
2757 	/* We don't need the rest of the request i.e request->id2 */
2758 	return (0);
2759 
2760 errout:
2761 	if (mapping->id1.idmap_id_u.sid.prefix != NULL) {
2762 		free(mapping->id1.idmap_id_u.sid.prefix);
2763 		mapping->id1.idmap_id_u.sid.prefix = NULL;
2764 	}
2765 
2766 	if (mapping->id1domain.idmap_utf8str_val != NULL) {
2767 		free(mapping->id1domain.idmap_utf8str_val);
2768 		mapping->id1domain.idmap_utf8str_val = NULL;
2769 		mapping->id1domain.idmap_utf8str_len = 0;
2770 	}
2771 
2772 	if (mapping->id1name.idmap_utf8str_val != NULL) {
2773 		free(mapping->id1name.idmap_utf8str_val);
2774 		mapping->id1name.idmap_utf8str_val = NULL;
2775 		mapping->id1name.idmap_utf8str_len = 0;
2776 	}
2777 
2778 	(void) memset(mapping, 0, sizeof (*mapping));
2779 	return (-1);
2780 }
2781 
2782 
2783 idmap_retcode
2784 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
2785 		idmap_mapping *mapping) {
2786 	idmap_id_res	idres;
2787 	lookup_state_t	state;
2788 	idmap_utf8str	*str;
2789 	char		*cp;
2790 	int		is_user;
2791 	idmap_retcode	retcode;
2792 	const char	*winname, *windomain;
2793 
2794 	(void) memset(&idres, 0, sizeof (idres));
2795 	(void) memset(&state, 0, sizeof (state));
2796 
2797 	if (request->id2.idtype == IDMAP_UID)
2798 		is_user = 1;
2799 	else if (request->id2.idtype == IDMAP_GID)
2800 		is_user = 0;
2801 	else if (request->id2.idtype == IDMAP_POSIXID)
2802 		is_user = -1;
2803 	else {
2804 		retcode = IDMAP_ERR_IDTYPE;
2805 		goto out;
2806 	}
2807 
2808 	/* Copy data from request to result */
2809 	if (copy_mapping_request(mapping, request) < 0) {
2810 		retcode = IDMAP_ERR_MEMORY;
2811 		goto out;
2812 	}
2813 
2814 	winname = mapping->id1name.idmap_utf8str_val;
2815 	windomain = mapping->id1domain.idmap_utf8str_val;
2816 
2817 	if (winname == NULL && windomain != NULL) {
2818 		retcode = IDMAP_ERR_ARG;
2819 		goto out;
2820 	}
2821 
2822 	if (winname != NULL && windomain == NULL) {
2823 		str = &mapping->id1domain;
2824 
2825 		if ((cp = strchr(winname, '@')) != NULL) {
2826 			/*
2827 			 * if winname is qualified with a domain, use it.
2828 			 */
2829 			*cp = '\0';
2830 			retcode = idmap_str2utf8(&str, cp + 1, 0);
2831 		} else if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
2832 			/*
2833 			 * otherwise use the mapping domain
2834 			 */
2835 			RDLOCK_CONFIG();
2836 			retcode = idmap_str2utf8(&str,
2837 				_idmapdstate.cfg->pgcfg.mapping_domain, 0);
2838 			UNLOCK_CONFIG();
2839 		} else
2840 			retcode = IDMAP_SUCCESS;
2841 
2842 		if (retcode != IDMAP_SUCCESS) {
2843 			idmapdlog(LOG_ERR, "Out of memory");
2844 			goto out;
2845 		}
2846 		windomain = mapping->id1domain.idmap_utf8str_val;
2847 	}
2848 
2849 	if (winname != NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) {
2850 		retcode = lookup_name2sid(cache, winname, windomain,
2851 			&is_user, &mapping->id1.idmap_id_u.sid.prefix,
2852 			&mapping->id1.idmap_id_u.sid.rid, mapping);
2853 		if (retcode != IDMAP_SUCCESS)
2854 			goto out;
2855 		if (mapping->id2.idtype == IDMAP_POSIXID)
2856 			mapping->id2.idtype = is_user?IDMAP_UID:IDMAP_GID;
2857 	}
2858 
2859 	state.sid2pid_done = TRUE;
2860 	retcode = sid2pid_first_pass(&state, cache, mapping, &idres);
2861 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
2862 		goto out;
2863 
2864 	if (state.ad_nqueries) {
2865 		/* sid2name AD lookup */
2866 		retcode = lookup_win_sid2name(
2867 			mapping->id1.idmap_id_u.sid.prefix,
2868 			mapping->id1.idmap_id_u.sid.rid,
2869 			&mapping->id1name.idmap_utf8str_val,
2870 			&mapping->id1domain.idmap_utf8str_val,
2871 			(int *)&idres.id.idtype);
2872 
2873 		idres.retcode = retcode;
2874 	}
2875 
2876 	state.sid2pid_done = TRUE;
2877 	retcode = sid2pid_second_pass(&state, cache, db, mapping, &idres);
2878 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
2879 		goto out;
2880 
2881 	/* Update cache */
2882 	(void) update_cache_sid2pid(&state, cache, mapping, &idres);
2883 
2884 out:
2885 	if (retcode == IDMAP_SUCCESS) {
2886 		mapping->direction = idres.direction;
2887 		mapping->id2 = idres.id;
2888 		(void) memset(&idres, 0, sizeof (idres));
2889 	} else {
2890 		mapping->id2.idmap_id_u.uid = UID_NOBODY;
2891 	}
2892 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
2893 	return (retcode);
2894 }
2895 
2896 idmap_retcode
2897 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
2898 		idmap_mapping *mapping, int is_user) {
2899 	idmap_id_res	idres;
2900 	lookup_state_t	state;
2901 	struct passwd	pwd;
2902 	struct group	grp;
2903 	char		buf[1024];
2904 	int		errnum;
2905 	idmap_retcode	retcode;
2906 	const char	*unixname;
2907 	const char	*me = "get_u2w_mapping";
2908 
2909 	/*
2910 	 * In order to re-use the pid2sid code, we convert
2911 	 * our input data into structs that are expected by
2912 	 * pid2sid_first_pass.
2913 	 */
2914 
2915 	(void) memset(&idres, 0, sizeof (idres));
2916 	(void) memset(&state, 0, sizeof (state));
2917 
2918 	/* Copy data from request to result */
2919 	if (copy_mapping_request(mapping, request) < 0) {
2920 		retcode = IDMAP_ERR_MEMORY;
2921 		goto out;
2922 	}
2923 
2924 	unixname = mapping->id1name.idmap_utf8str_val;
2925 
2926 	if (unixname == NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
2927 		retcode = IDMAP_ERR_ARG;
2928 		goto out;
2929 	}
2930 
2931 	if (unixname != NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
2932 		/* Get uid/gid by name */
2933 		if (is_user) {
2934 			errno = 0;
2935 			if (getpwnam_r(unixname, &pwd, buf,
2936 					sizeof (buf)) == NULL) {
2937 				errnum = errno;
2938 				idmapdlog(LOG_WARNING,
2939 				"%s: getpwnam_r(%s) failed (%s).",
2940 					me, unixname,
2941 					errnum?strerror(errnum):"not found");
2942 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
2943 						IDMAP_ERR_INTERNAL;
2944 				goto out;
2945 			}
2946 			mapping->id1.idmap_id_u.uid = pwd.pw_uid;
2947 		} else {
2948 			errno = 0;
2949 			if (getgrnam_r(unixname, &grp, buf,
2950 					sizeof (buf)) == NULL) {
2951 				errnum = errno;
2952 				idmapdlog(LOG_WARNING,
2953 				"%s: getgrnam_r(%s) failed (%s).",
2954 					me, unixname,
2955 					errnum?strerror(errnum):"not found");
2956 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
2957 						IDMAP_ERR_INTERNAL;
2958 				goto out;
2959 			}
2960 			mapping->id1.idmap_id_u.gid = grp.gr_gid;
2961 		}
2962 	}
2963 
2964 	state.pid2sid_done = TRUE;
2965 	retcode = pid2sid_first_pass(&state, cache, db, mapping, &idres,
2966 			is_user, 1);
2967 	if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE)
2968 		goto out;
2969 
2970 	/* Update cache */
2971 	(void) update_cache_pid2sid(&state, cache, mapping, &idres);
2972 
2973 out:
2974 	mapping->direction = idres.direction;
2975 	mapping->id2 = idres.id;
2976 	(void) memset(&idres, 0, sizeof (idres));
2977 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
2978 	return (retcode);
2979 }
2980