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