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