xref: /onnv-gate/usr/src/cmd/idmap/idmapd/dbutils.c (revision 4884:a15ef4eea444)
14520Snw141292 /*
24520Snw141292  * CDDL HEADER START
34520Snw141292  *
44520Snw141292  * The contents of this file are subject to the terms of the
54520Snw141292  * Common Development and Distribution License (the "License").
64520Snw141292  * You may not use this file except in compliance with the License.
74520Snw141292  *
84520Snw141292  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94520Snw141292  * or http://www.opensolaris.org/os/licensing.
104520Snw141292  * See the License for the specific language governing permissions
114520Snw141292  * and limitations under the License.
124520Snw141292  *
134520Snw141292  * When distributing Covered Code, include this CDDL HEADER in each
144520Snw141292  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154520Snw141292  * If applicable, add the following below this CDDL HEADER, with the
164520Snw141292  * fields enclosed by brackets "[]" replaced with your own identifying
174520Snw141292  * information: Portions Copyright [yyyy] [name of copyright owner]
184520Snw141292  *
194520Snw141292  * CDDL HEADER END
204520Snw141292  */
214520Snw141292 /*
224520Snw141292  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
234520Snw141292  * Use is subject to license terms.
244520Snw141292  */
254520Snw141292 
264520Snw141292 #pragma ident	"%Z%%M%	%I%	%E% SMI"
274520Snw141292 
284520Snw141292 /*
294520Snw141292  * Database related utility routines
304520Snw141292  */
314520Snw141292 
324520Snw141292 #include <stdio.h>
334520Snw141292 #include <stdlib.h>
344520Snw141292 #include <string.h>
354520Snw141292 #include <errno.h>
364520Snw141292 #include <sys/types.h>
374520Snw141292 #include <sys/stat.h>
384520Snw141292 #include <rpc/rpc.h>
394520Snw141292 #include <sys/sid.h>
404520Snw141292 #include <time.h>
414520Snw141292 #include <pwd.h>
424520Snw141292 #include <grp.h>
43*4884Sjp151216 #include <pthread.h>
44*4884Sjp151216 #include <assert.h>
454520Snw141292 
464520Snw141292 #include "idmapd.h"
474520Snw141292 #include "adutils.h"
484520Snw141292 #include "string.h"
494520Snw141292 #include "idmap_priv.h"
504520Snw141292 
51*4884Sjp151216 
524520Snw141292 static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
534520Snw141292 		sqlite_vm **, int *, int, const char ***);
544864Sbaban static idmap_retcode lookup_wksids_name2sid(const char *, char **,
554864Sbaban 		idmap_rid_t *, int *);
564520Snw141292 
574520Snw141292 #define	EMPTY_NAME(name)	(*name == 0 || strcmp(name, "\"\"") == 0)
584520Snw141292 
594520Snw141292 #define	EMPTY_STRING(str)	(str == NULL || *str == 0)
604520Snw141292 
614520Snw141292 #define	DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
624520Snw141292 		(req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
634520Snw141292 
644520Snw141292 #define	AVOID_NAMESERVICE(req)\
654520Snw141292 		(req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
664520Snw141292 
674520Snw141292 #define	IS_EPHEMERAL(pid)	(pid > INT32_MAX)
684520Snw141292 
694520Snw141292 #define	LOCALRID_MIN	1000
704520Snw141292 
714520Snw141292 
724520Snw141292 
734520Snw141292 typedef enum init_db_option {
744520Snw141292 	FAIL_IF_CORRUPT = 0,
754520Snw141292 	REMOVE_IF_CORRUPT = 1
764520Snw141292 } init_db_option_t;
774520Snw141292 
78*4884Sjp151216 /*
79*4884Sjp151216  * Thread specfic data to hold the database handles so that the
80*4884Sjp151216  * databaes are not opened and closed for every request. It also
81*4884Sjp151216  * contains the sqlite busy handler structure.
82*4884Sjp151216  */
83*4884Sjp151216 
84*4884Sjp151216 struct idmap_busy {
85*4884Sjp151216 	const char *name;
86*4884Sjp151216 	const int *delays;
87*4884Sjp151216 	int delay_size;
88*4884Sjp151216 	int total;
89*4884Sjp151216 	int sec;
90*4884Sjp151216 };
91*4884Sjp151216 
92*4884Sjp151216 
93*4884Sjp151216 typedef struct idmap_tsd {
94*4884Sjp151216 	sqlite *db_db;
95*4884Sjp151216 	sqlite *cache_db;
96*4884Sjp151216 	struct idmap_busy cache_busy;
97*4884Sjp151216 	struct idmap_busy db_busy;
98*4884Sjp151216 } idmap_tsd_t;
99*4884Sjp151216 
100*4884Sjp151216 
101*4884Sjp151216 
102*4884Sjp151216 static const int cache_delay_table[] =
103*4884Sjp151216 		{ 1, 2, 5, 10, 15, 20, 25, 30,  35,  40,
104*4884Sjp151216 		50,  50, 60, 70, 80, 90, 100};
105*4884Sjp151216 
106*4884Sjp151216 static const int db_delay_table[] =
107*4884Sjp151216 		{ 5, 10, 15, 20, 30,  40,  55,  70, 100};
108*4884Sjp151216 
109*4884Sjp151216 
110*4884Sjp151216 static pthread_key_t	idmap_tsd_key;
111*4884Sjp151216 
112*4884Sjp151216 void
113*4884Sjp151216 idmap_tsd_destroy(void *key)
114*4884Sjp151216 {
115*4884Sjp151216 
116*4884Sjp151216 	idmap_tsd_t	*tsd = (idmap_tsd_t *)key;
117*4884Sjp151216 	if (tsd) {
118*4884Sjp151216 		if (tsd->db_db)
119*4884Sjp151216 			(void) sqlite_close(tsd->db_db);
120*4884Sjp151216 		if (tsd->cache_db)
121*4884Sjp151216 			(void) sqlite_close(tsd->cache_db);
122*4884Sjp151216 		free(tsd);
123*4884Sjp151216 	}
124*4884Sjp151216 }
125*4884Sjp151216 
126*4884Sjp151216 int
127*4884Sjp151216 idmap_init_tsd_key(void) {
128*4884Sjp151216 
129*4884Sjp151216 	return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy));
130*4884Sjp151216 }
131*4884Sjp151216 
132*4884Sjp151216 
133*4884Sjp151216 
134*4884Sjp151216 idmap_tsd_t *
135*4884Sjp151216 idmap_get_tsd(void)
136*4884Sjp151216 {
137*4884Sjp151216 	idmap_tsd_t	*tsd;
138*4884Sjp151216 
139*4884Sjp151216 	if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) {
140*4884Sjp151216 		/* No thread specific data so create it */
141*4884Sjp151216 		if ((tsd = malloc(sizeof (*tsd))) != NULL) {
142*4884Sjp151216 			/* Initialize thread specific data */
143*4884Sjp151216 			(void) memset(tsd, 0, sizeof (*tsd));
144*4884Sjp151216 			/* save the trhread specific data */
145*4884Sjp151216 			if (pthread_setspecific(idmap_tsd_key, tsd) != 0) {
146*4884Sjp151216 				/* Can't store key */
147*4884Sjp151216 				free(tsd);
148*4884Sjp151216 				tsd = NULL;
149*4884Sjp151216 			}
150*4884Sjp151216 		} else {
151*4884Sjp151216 			tsd = NULL;
152*4884Sjp151216 		}
153*4884Sjp151216 	}
154*4884Sjp151216 
155*4884Sjp151216 	return (tsd);
156*4884Sjp151216 }
157*4884Sjp151216 
158*4884Sjp151216 
1594520Snw141292 
1604520Snw141292 /*
1614520Snw141292  * Initialize 'dbname' using 'sql'
1624520Snw141292  */
1634520Snw141292 static int
1644520Snw141292 init_db_instance(const char *dbname, const char *sql, init_db_option_t opt,
1654520Snw141292 		int *new_db_created)
1664520Snw141292 {
1674520Snw141292 	int rc = 0;
1684520Snw141292 	int tries = 0;
1694520Snw141292 	sqlite *db = NULL;
1704520Snw141292 	char *str = NULL;
1714520Snw141292 
1724520Snw141292 	if (new_db_created != NULL)
1734520Snw141292 		*new_db_created = 0;
1744520Snw141292 
1754520Snw141292 	db = sqlite_open(dbname, 0600, &str);
1764520Snw141292 	while (db == NULL) {
1774520Snw141292 		idmapdlog(LOG_ERR,
1784520Snw141292 		    "Error creating database %s (%s)",
1794520Snw141292 		    dbname, CHECK_NULL(str));
1804520Snw141292 		sqlite_freemem(str);
1814520Snw141292 		if (opt == FAIL_IF_CORRUPT || opt != REMOVE_IF_CORRUPT ||
1824520Snw141292 		    tries > 0)
1834520Snw141292 			return (-1);
1844520Snw141292 
1854520Snw141292 		tries++;
1864520Snw141292 		(void) unlink(dbname);
1874520Snw141292 		db = sqlite_open(dbname, 0600, &str);
1884520Snw141292 	}
1894520Snw141292 
1904520Snw141292 	sqlite_busy_timeout(db, 3000);
1914520Snw141292 	rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &str);
1924520Snw141292 	if (SQLITE_OK != rc) {
1934520Snw141292 		idmapdlog(LOG_ERR, "Cannot begin database transaction (%s)",
1944520Snw141292 		    str);
1954520Snw141292 		sqlite_freemem(str);
1964520Snw141292 		sqlite_close(db);
1974520Snw141292 		return (1);
1984520Snw141292 	}
1994520Snw141292 
2004520Snw141292 	switch (sqlite_exec(db, sql, NULL, NULL, &str)) {
2014520Snw141292 	case SQLITE_ERROR:
2024520Snw141292 /*
2034520Snw141292  * This is the normal situation: CREATE probably failed because tables
2044520Snw141292  * already exist. It may indicate an error in SQL as well, but we cannot
2054520Snw141292  * tell.
2064520Snw141292  */
2074520Snw141292 		sqlite_freemem(str);
2084520Snw141292 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
2094520Snw141292 		    NULL, NULL, &str);
2104520Snw141292 		break;
2114520Snw141292 	case SQLITE_OK:
2124520Snw141292 		rc =  sqlite_exec(db, "COMMIT TRANSACTION",
2134520Snw141292 		    NULL, NULL, &str);
2144520Snw141292 		idmapdlog(LOG_INFO,
2154520Snw141292 		    "Database created at %s", dbname);
2164520Snw141292 
2174520Snw141292 		if (new_db_created != NULL)
2184520Snw141292 			*new_db_created = 1;
2194520Snw141292 		break;
2204520Snw141292 	default:
2214520Snw141292 		idmapdlog(LOG_ERR,
2224520Snw141292 		    "Error initializing database %s (%s)",
2234520Snw141292 		    dbname, str);
2244520Snw141292 		sqlite_freemem(str);
2254520Snw141292 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
2264520Snw141292 		    NULL, NULL, &str);
2274520Snw141292 		break;
2284520Snw141292 	}
2294520Snw141292 
2304520Snw141292 	if (SQLITE_OK != rc) {
2314520Snw141292 		/* this is bad - database may be left in a locked state */
2324520Snw141292 		idmapdlog(LOG_ERR,
2334520Snw141292 		    "Error closing transaction (%s)", str);
2344520Snw141292 		sqlite_freemem(str);
2354520Snw141292 	}
2364520Snw141292 
2374520Snw141292 	(void) sqlite_close(db);
2384520Snw141292 	return (rc);
2394520Snw141292 }
2404520Snw141292 
241*4884Sjp151216 
242*4884Sjp151216 /*
243*4884Sjp151216  * This is the SQLite database busy handler that retries the SQL
244*4884Sjp151216  * operation until it is successful.
245*4884Sjp151216  */
246*4884Sjp151216 int
247*4884Sjp151216 /* LINTED E_FUNC_ARG_UNUSED */
248*4884Sjp151216 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count)
249*4884Sjp151216 {
250*4884Sjp151216 	struct idmap_busy	*busy = arg;
251*4884Sjp151216 	int			delay;
252*4884Sjp151216 	struct timespec		rqtp;
253*4884Sjp151216 
254*4884Sjp151216 	if (count == 1)  {
255*4884Sjp151216 		busy->total = 0;
256*4884Sjp151216 		busy->sec = 2;
257*4884Sjp151216 	}
258*4884Sjp151216 	if (busy->total > 1000 * busy->sec) {
259*4884Sjp151216 		idmapdlog(LOG_ERR,
260*4884Sjp151216 		    "Thread %d waited %d sec for the %s database",
261*4884Sjp151216 		    pthread_self(), busy->sec, busy->name);
262*4884Sjp151216 		busy->sec++;
263*4884Sjp151216 	}
264*4884Sjp151216 
265*4884Sjp151216 	if (count <= busy->delay_size) {
266*4884Sjp151216 		delay = busy->delays[count-1];
267*4884Sjp151216 	} else {
268*4884Sjp151216 		delay = busy->delays[busy->delay_size - 1];
269*4884Sjp151216 	}
270*4884Sjp151216 	busy->total += delay;
271*4884Sjp151216 	rqtp.tv_sec = 0;
272*4884Sjp151216 	rqtp.tv_nsec = delay * (NANOSEC / MILLISEC);
273*4884Sjp151216 	(void) nanosleep(&rqtp, NULL);
274*4884Sjp151216 	return (1);
275*4884Sjp151216 }
276*4884Sjp151216 
277*4884Sjp151216 
2784520Snw141292 /*
2794520Snw141292  * Get the database handle
2804520Snw141292  */
2814520Snw141292 idmap_retcode
2824520Snw141292 get_db_handle(sqlite **db) {
2834520Snw141292 	char	*errmsg;
284*4884Sjp151216 	idmap_tsd_t *tsd;
2854520Snw141292 
2864520Snw141292 	/*
287*4884Sjp151216 	 * Retrieve the db handle from thread-specific storage
2884520Snw141292 	 * If none exists, open and store in thread-specific storage.
2894520Snw141292 	 */
290*4884Sjp151216 	if ((tsd = idmap_get_tsd()) == NULL) {
2914520Snw141292 		idmapdlog(LOG_ERR,
292*4884Sjp151216 			"Error getting thread specific data for %s",
293*4884Sjp151216 			IDMAP_DBNAME);
294*4884Sjp151216 		return (IDMAP_ERR_MEMORY);
2954520Snw141292 	}
296*4884Sjp151216 
297*4884Sjp151216 	if (tsd->db_db == NULL) {
298*4884Sjp151216 		tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg);
299*4884Sjp151216 		if (tsd->db_db == NULL) {
300*4884Sjp151216 			idmapdlog(LOG_ERR,
301*4884Sjp151216 				"Error opening database %s (%s)",
302*4884Sjp151216 				IDMAP_DBNAME, CHECK_NULL(errmsg));
303*4884Sjp151216 			sqlite_freemem(errmsg);
304*4884Sjp151216 			return (IDMAP_ERR_INTERNAL);
305*4884Sjp151216 		}
306*4884Sjp151216 		tsd->db_busy.name = IDMAP_DBNAME;
307*4884Sjp151216 		tsd->db_busy.delays = db_delay_table;
308*4884Sjp151216 		tsd->db_busy.delay_size = sizeof (db_delay_table) /
309*4884Sjp151216 		    sizeof (int);
310*4884Sjp151216 		sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler,
311*4884Sjp151216 		    &tsd->db_busy);
312*4884Sjp151216 	}
313*4884Sjp151216 	*db = tsd->db_db;
3144520Snw141292 	return (IDMAP_SUCCESS);
3154520Snw141292 }
3164520Snw141292 
3174520Snw141292 /*
3184520Snw141292  * Get the cache handle
3194520Snw141292  */
3204520Snw141292 idmap_retcode
321*4884Sjp151216 get_cache_handle(sqlite **cache) {
3224520Snw141292 	char	*errmsg;
323*4884Sjp151216 	idmap_tsd_t *tsd;
3244520Snw141292 
3254520Snw141292 	/*
326*4884Sjp151216 	 * Retrieve the db handle from thread-specific storage
3274520Snw141292 	 * If none exists, open and store in thread-specific storage.
3284520Snw141292 	 */
329*4884Sjp151216 	if ((tsd = idmap_get_tsd()) == NULL) {
3304520Snw141292 		idmapdlog(LOG_ERR,
331*4884Sjp151216 			"Error getting thread specific data for %s",
332*4884Sjp151216 			IDMAP_DBNAME);
333*4884Sjp151216 		return (IDMAP_ERR_MEMORY);
3344520Snw141292 	}
335*4884Sjp151216 
336*4884Sjp151216 	if (tsd->cache_db == NULL) {
337*4884Sjp151216 		tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg);
338*4884Sjp151216 		if (tsd->cache_db == NULL) {
339*4884Sjp151216 			idmapdlog(LOG_ERR,
340*4884Sjp151216 				"Error opening database %s (%s)",
341*4884Sjp151216 				IDMAP_CACHENAME, CHECK_NULL(errmsg));
342*4884Sjp151216 			sqlite_freemem(errmsg);
343*4884Sjp151216 			return (IDMAP_ERR_INTERNAL);
344*4884Sjp151216 		}
345*4884Sjp151216 		tsd->cache_busy.name = IDMAP_CACHENAME;
346*4884Sjp151216 		tsd->cache_busy.delays = cache_delay_table;
347*4884Sjp151216 		tsd->cache_busy.delay_size = sizeof (cache_delay_table) /
348*4884Sjp151216 		    sizeof (int);
349*4884Sjp151216 		sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler,
350*4884Sjp151216 		    &tsd->cache_busy);
351*4884Sjp151216 	}
352*4884Sjp151216 	*cache = tsd->cache_db;
3534520Snw141292 	return (IDMAP_SUCCESS);
3544520Snw141292 }
3554520Snw141292 
3564520Snw141292 #define	CACHE_SQL\
3574520Snw141292 	"CREATE TABLE idmap_cache ("\
3584520Snw141292 	"	sidprefix TEXT,"\
3594520Snw141292 	"	rid INTEGER,"\
3604520Snw141292 	"	windomain TEXT,"\
3614520Snw141292 	"	winname TEXT,"\
3624520Snw141292 	"	pid INTEGER,"\
3634520Snw141292 	"	unixname TEXT,"\
3644520Snw141292 	"	is_user INTEGER,"\
3654520Snw141292 	"	w2u INTEGER,"\
3664520Snw141292 	"	u2w INTEGER,"\
3674520Snw141292 	"	expiration INTEGER"\
3684520Snw141292 	");"\
3694520Snw141292 	"CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache"\
3704520Snw141292 	"		(sidprefix, rid, w2u);"\
3714520Snw141292 	"CREATE UNIQUE INDEX idmap_cache_pid_u2w ON idmap_cache"\
3724520Snw141292 	"		(pid, is_user, u2w);"\
3734520Snw141292 	"CREATE TABLE name_cache ("\
3744520Snw141292 	"	sidprefix TEXT,"\
3754520Snw141292 	"	rid INTEGER,"\
3764520Snw141292 	"	name TEXT,"\
3774520Snw141292 	"	domain TEXT,"\
3784520Snw141292 	"	type INTEGER,"\
3794520Snw141292 	"	expiration INTEGER"\
3804520Snw141292 	");"\
3814520Snw141292 	"CREATE UNIQUE INDEX name_cache_sid ON name_cache"\
3824520Snw141292 	"		(sidprefix, rid);"
3834520Snw141292 
3844520Snw141292 #define	DB_SQL\
3854520Snw141292 	"CREATE TABLE namerules ("\
3864520Snw141292 	"	is_user INTEGER NOT NULL,"\
3874520Snw141292 	"	windomain TEXT,"\
3884520Snw141292 	"	winname TEXT NOT NULL,"\
3894520Snw141292 	"	is_nt4 INTEGER NOT NULL,"\
3904520Snw141292 	"	unixname NOT NULL,"\
3914520Snw141292 	"	w2u_order INTEGER,"\
3924520Snw141292 	"	u2w_order INTEGER"\
3934520Snw141292 	");"\
3944520Snw141292 	"CREATE UNIQUE INDEX namerules_w2u ON namerules"\
3954520Snw141292 	"		(winname, windomain, is_user, w2u_order);"\
3964520Snw141292 	"CREATE UNIQUE INDEX namerules_u2w ON namerules"\
3974520Snw141292 	"		(unixname, is_user, u2w_order);"
3984520Snw141292 
3994520Snw141292 /*
4004520Snw141292  * Initialize cache and db
4014520Snw141292  */
4024520Snw141292 int
4034520Snw141292 init_dbs() {
4044520Snw141292 	/* name-based mappings; probably OK to blow away in a pinch(?) */
4054520Snw141292 	if (init_db_instance(IDMAP_DBNAME, DB_SQL, FAIL_IF_CORRUPT, NULL) < 0)
4064520Snw141292 		return (-1);
4074520Snw141292 
4084520Snw141292 	/* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
4094520Snw141292 	if (init_db_instance(IDMAP_CACHENAME, CACHE_SQL, REMOVE_IF_CORRUPT,
4104520Snw141292 			&_idmapdstate.new_eph_db) < 0)
4114520Snw141292 		return (-1);
4124520Snw141292 
4134520Snw141292 	return (0);
4144520Snw141292 }
4154520Snw141292 
4164520Snw141292 /*
4174520Snw141292  * Finalize databases
4184520Snw141292  */
4194520Snw141292 void
4204520Snw141292 fini_dbs() {
4214520Snw141292 }
4224520Snw141292 
4234520Snw141292 /*
4244520Snw141292  * This table is a listing of status codes that will returned to the
4254520Snw141292  * client when a SQL command fails with the corresponding error message.
4264520Snw141292  */
4274520Snw141292 static msg_table_t sqlmsgtable[] = {
4284864Sbaban 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
4294520Snw141292 	"columns unixname, is_user, u2w_order are not unique"},
4304864Sbaban 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
4314520Snw141292 	"columns winname, windomain, is_user, w2u_order are not unique"},
4324520Snw141292 	{-1, NULL}
4334520Snw141292 };
4344520Snw141292 
4354520Snw141292 /*
4364520Snw141292  * idmapd's version of string2stat to map SQLite messages to
4374520Snw141292  * status codes
4384520Snw141292  */
4394520Snw141292 idmap_retcode
4404520Snw141292 idmapd_string2stat(const char *msg) {
4414520Snw141292 	int i;
4424520Snw141292 	for (i = 0; sqlmsgtable[i].msg; i++) {
4434520Snw141292 		if (strcasecmp(sqlmsgtable[i].msg, msg) == 0)
4444520Snw141292 			return (sqlmsgtable[i].retcode);
4454520Snw141292 	}
4464520Snw141292 	return (IDMAP_ERR_OTHER);
4474520Snw141292 }
4484520Snw141292 
4494520Snw141292 /*
4504520Snw141292  * Execute the given SQL statment without using any callbacks
4514520Snw141292  */
4524520Snw141292 idmap_retcode
4534520Snw141292 sql_exec_no_cb(sqlite *db, char *sql) {
4544520Snw141292 	char		*errmsg = NULL;
455*4884Sjp151216 	int		r;
4564520Snw141292 	idmap_retcode	retcode;
4574520Snw141292 
458*4884Sjp151216 	r = sqlite_exec(db, sql, NULL, NULL, &errmsg);
459*4884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
4604520Snw141292 
4614520Snw141292 	if (r != SQLITE_OK) {
4624520Snw141292 		idmapdlog(LOG_ERR, "Database error during %s (%s)",
4634520Snw141292 			sql, CHECK_NULL(errmsg));
464*4884Sjp151216 		retcode = idmapd_string2stat(errmsg);
4654864Sbaban 		if (errmsg != NULL)
4664520Snw141292 			sqlite_freemem(errmsg);
4674520Snw141292 		return (retcode);
4684520Snw141292 	}
4694520Snw141292 
4704520Snw141292 	return (IDMAP_SUCCESS);
4714520Snw141292 }
4724520Snw141292 
4734520Snw141292 /*
4744520Snw141292  * Generate expression that can be used in WHERE statements.
4754520Snw141292  * Examples:
4764520Snw141292  * <prefix> <col>      <op> <value>   <suffix>
4774520Snw141292  * ""       "unixuser" "="  "foo" "AND"
4784520Snw141292  */
4794520Snw141292 idmap_retcode
4804520Snw141292 gen_sql_expr_from_utf8str(const char *prefix, const char *col,
4814520Snw141292 		const char *op, idmap_utf8str *value,
4824520Snw141292 		const char *suffix, char **out) {
4834520Snw141292 	char		*str;
4844520Snw141292 	idmap_stat	retcode;
4854520Snw141292 
4864520Snw141292 	if (out == NULL)
4874520Snw141292 		return (IDMAP_ERR_ARG);
4884520Snw141292 
4894520Snw141292 	if (value == NULL)
4904520Snw141292 		return (IDMAP_SUCCESS);
4914520Snw141292 
4924520Snw141292 	retcode = idmap_utf82str(&str, 0, value);
4934520Snw141292 	if (retcode != IDMAP_SUCCESS)
4944520Snw141292 		return (retcode);
4954520Snw141292 
4964520Snw141292 	if (prefix == NULL)
4974520Snw141292 		prefix = "";
4984520Snw141292 	if (suffix == NULL)
4994520Snw141292 		suffix = "";
5004520Snw141292 
5014520Snw141292 	*out = sqlite_mprintf("%s %s %s %Q %s",
5024520Snw141292 			prefix, col, op, str, suffix);
5034520Snw141292 	idmap_free(str);
5044520Snw141292 	if (*out == NULL)
5054520Snw141292 		return (IDMAP_ERR_MEMORY);
5064520Snw141292 	return (IDMAP_SUCCESS);
5074520Snw141292 }
5084520Snw141292 
5094520Snw141292 /*
5104520Snw141292  * Generate and execute SQL statement for LIST RPC calls
5114520Snw141292  */
5124520Snw141292 idmap_retcode
5134520Snw141292 process_list_svc_sql(sqlite *db, char *sql, uint64_t limit,
5144520Snw141292 		list_svc_cb cb, void *result) {
5154520Snw141292 	list_cb_data_t	cb_data;
5164520Snw141292 	char		*errmsg = NULL;
517*4884Sjp151216 	int		r;
5184520Snw141292 	idmap_retcode	retcode = IDMAP_ERR_INTERNAL;
5194520Snw141292 
5204520Snw141292 	(void) memset(&cb_data, 0, sizeof (cb_data));
5214520Snw141292 	cb_data.result = result;
5224520Snw141292 	cb_data.limit = limit;
5234520Snw141292 
524*4884Sjp151216 
525*4884Sjp151216 	r = sqlite_exec(db, sql, cb, &cb_data, &errmsg);
526*4884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
527*4884Sjp151216 	switch (r) {
528*4884Sjp151216 	case SQLITE_OK:
529*4884Sjp151216 		retcode = IDMAP_SUCCESS;
530*4884Sjp151216 		break;
531*4884Sjp151216 
532*4884Sjp151216 	default:
533*4884Sjp151216 		retcode = IDMAP_ERR_INTERNAL;
534*4884Sjp151216 		idmapdlog(LOG_ERR,
535*4884Sjp151216 			"Database error during %s (%s)",
536*4884Sjp151216 			sql, CHECK_NULL(errmsg));
537*4884Sjp151216 		break;
5384520Snw141292 	}
5394864Sbaban 	if (errmsg != NULL)
5404520Snw141292 		sqlite_freemem(errmsg);
5414520Snw141292 	return (retcode);
5424520Snw141292 }
5434520Snw141292 
5444520Snw141292 /*
5454520Snw141292  * This routine is called by callbacks that process the results of
5464520Snw141292  * LIST RPC calls to validate data and to allocate memory for
5474520Snw141292  * the result array.
5484520Snw141292  */
5494520Snw141292 idmap_retcode
5504520Snw141292 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv,
5514520Snw141292 		int ncol, uchar_t **list, size_t valsize) {
5524520Snw141292 	size_t	nsize;
5534520Snw141292 	void	*tmplist;
5544520Snw141292 
5554520Snw141292 	if (cb_data->limit > 0 && cb_data->next == cb_data->limit)
5564520Snw141292 		return (IDMAP_NEXT);
5574520Snw141292 
5584520Snw141292 	if (argc < ncol || argv == NULL) {
5594520Snw141292 		idmapdlog(LOG_ERR, "Invalid data");
5604520Snw141292 		return (IDMAP_ERR_INTERNAL);
5614520Snw141292 	}
5624520Snw141292 
5634520Snw141292 	/* alloc in bulk to reduce number of reallocs */
5644520Snw141292 	if (cb_data->next >= cb_data->len) {
5654520Snw141292 		nsize = (cb_data->len + SIZE_INCR) * valsize;
5664520Snw141292 		tmplist = realloc(*list, nsize);
5674520Snw141292 		if (tmplist == NULL) {
5684520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
5694520Snw141292 			return (IDMAP_ERR_MEMORY);
5704520Snw141292 		}
5714520Snw141292 		*list = tmplist;
5724520Snw141292 		(void) memset(*list + (cb_data->len * valsize), 0,
5734520Snw141292 			SIZE_INCR * valsize);
5744520Snw141292 		cb_data->len += SIZE_INCR;
5754520Snw141292 	}
5764520Snw141292 	return (IDMAP_SUCCESS);
5774520Snw141292 }
5784520Snw141292 
5794520Snw141292 static idmap_retcode
5804520Snw141292 get_namerule_order(char *winname, char *windomain, char *unixname,
5814520Snw141292 		int direction, int *w2u_order, int *u2w_order) {
5824520Snw141292 
5834520Snw141292 	*w2u_order = 0;
5844520Snw141292 	*u2w_order = 0;
5854520Snw141292 
5864520Snw141292 	/*
5874520Snw141292 	 * Windows to UNIX lookup order:
5884520Snw141292 	 *  1. winname@domain (or winname) to ""
5894520Snw141292 	 *  2. winname@domain (or winname) to unixname
5904520Snw141292 	 *  3. winname@* to ""
5914520Snw141292 	 *  4. winname@* to unixname
5924520Snw141292 	 *  5. *@domain (or *) to *
5934520Snw141292 	 *  6. *@domain (or *) to ""
5944520Snw141292 	 *  7. *@domain (or *) to unixname
5954520Snw141292 	 *  8. *@* to *
5964520Snw141292 	 *  9. *@* to ""
5974520Snw141292 	 * 10. *@* to unixname
5984520Snw141292 	 *
5994520Snw141292 	 * winname is a special case of winname@domain when domain is the
6004520Snw141292 	 * default domain. Similarly * is a special case of *@domain when
6014520Snw141292 	 * domain is the default domain.
6024520Snw141292 	 *
6034520Snw141292 	 * Note that "" has priority over specific names because "" inhibits
6044520Snw141292 	 * mappings and traditionally deny rules always had higher priority.
6054520Snw141292 	 */
6064644Sbaban 	if (direction != IDMAP_DIRECTION_U2W) {
6074644Sbaban 		/* bi-directional or from windows to unix */
6084520Snw141292 		if (winname == NULL)
6094520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6104520Snw141292 		else if (unixname == NULL)
6114520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6124520Snw141292 		else if (EMPTY_NAME(winname))
6134520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6144520Snw141292 		else if (*winname == '*' && windomain && *windomain == '*') {
6154520Snw141292 			if (*unixname == '*')
6164520Snw141292 				*w2u_order = 8;
6174520Snw141292 			else if (EMPTY_NAME(unixname))
6184520Snw141292 				*w2u_order = 9;
6194520Snw141292 			else /* unixname == name */
6204520Snw141292 				*w2u_order = 10;
6214520Snw141292 		} else if (*winname == '*') {
6224520Snw141292 			if (*unixname == '*')
6234520Snw141292 				*w2u_order = 5;
6244520Snw141292 			else if (EMPTY_NAME(unixname))
6254520Snw141292 				*w2u_order = 6;
6264520Snw141292 			else /* name */
6274520Snw141292 				*w2u_order = 7;
6284864Sbaban 		} else if (windomain != NULL && *windomain == '*') {
6294520Snw141292 			/* winname == name */
6304520Snw141292 			if (*unixname == '*')
6314520Snw141292 				return (IDMAP_ERR_W2U_NAMERULE);
6324520Snw141292 			else if (EMPTY_NAME(unixname))
6334520Snw141292 				*w2u_order = 3;
6344520Snw141292 			else /* name */
6354520Snw141292 				*w2u_order = 4;
6364520Snw141292 		} else  {
6374520Snw141292 			/* winname == name && windomain == null or name */
6384520Snw141292 			if (*unixname == '*')
6394520Snw141292 				return (IDMAP_ERR_W2U_NAMERULE);
6404520Snw141292 			else if (EMPTY_NAME(unixname))
6414520Snw141292 				*w2u_order = 1;
6424520Snw141292 			else /* name */
6434520Snw141292 				*w2u_order = 2;
6444520Snw141292 		}
6454520Snw141292 	}
6464520Snw141292 
6474520Snw141292 	/*
6484520Snw141292 	 * 1. unixname to ""
6494520Snw141292 	 * 2. unixname to winname@domain (or winname)
6504520Snw141292 	 * 3. * to *@domain (or *)
6514520Snw141292 	 * 4. * to ""
6524520Snw141292 	 * 5. * to winname@domain (or winname)
6534520Snw141292 	 */
6544644Sbaban 	if (direction != IDMAP_DIRECTION_W2U) {
6554644Sbaban 		/* bi-directional or from unix to windows */
6564520Snw141292 		if (unixname == NULL || EMPTY_NAME(unixname))
6574520Snw141292 			return (IDMAP_ERR_U2W_NAMERULE);
6584520Snw141292 		else if (winname == NULL)
6594520Snw141292 			return (IDMAP_ERR_U2W_NAMERULE);
6604864Sbaban 		else if (windomain != NULL && *windomain == '*')
6614644Sbaban 			return (IDMAP_ERR_U2W_NAMERULE);
6624520Snw141292 		else if (*unixname == '*') {
6634520Snw141292 			if (*winname == '*')
6644520Snw141292 				*u2w_order = 3;
6654520Snw141292 			else if (EMPTY_NAME(winname))
6664520Snw141292 				*u2w_order = 4;
6674520Snw141292 			else
6684520Snw141292 				*u2w_order = 5;
6694520Snw141292 		} else {
6704520Snw141292 			if (*winname == '*')
6714520Snw141292 				return (IDMAP_ERR_U2W_NAMERULE);
6724520Snw141292 			else if (EMPTY_NAME(winname))
6734520Snw141292 				*u2w_order = 1;
6744520Snw141292 			else
6754520Snw141292 				*u2w_order = 2;
6764520Snw141292 		}
6774520Snw141292 	}
6784520Snw141292 	return (IDMAP_SUCCESS);
6794520Snw141292 }
6804520Snw141292 
6814520Snw141292 /*
6824520Snw141292  * Generate and execute SQL statement to add name-based mapping rule
6834520Snw141292  */
6844520Snw141292 idmap_retcode
6854520Snw141292 add_namerule(sqlite *db, idmap_namerule *rule) {
6864520Snw141292 	char		*sql = NULL;
6874520Snw141292 	idmap_stat	retcode;
6884864Sbaban 	char		*windomain = NULL, *winname = NULL, *dom = NULL;
6894520Snw141292 	char		*unixname = NULL;
6904520Snw141292 	int		w2u_order, u2w_order;
6914520Snw141292 	char		w2ubuf[11], u2wbuf[11];
6924520Snw141292 
6934520Snw141292 	retcode = idmap_utf82str(&windomain, 0, &rule->windomain);
6944520Snw141292 	if (retcode != IDMAP_SUCCESS)
6954520Snw141292 		goto out;
6964520Snw141292 	retcode = idmap_utf82str(&winname, 0, &rule->winname);
6974520Snw141292 	if (retcode != IDMAP_SUCCESS)
6984520Snw141292 		goto out;
6994520Snw141292 	retcode = idmap_utf82str(&unixname, 0, &rule->unixname);
7004520Snw141292 	if (retcode != IDMAP_SUCCESS)
7014520Snw141292 		goto out;
7024520Snw141292 
7034520Snw141292 	retcode = get_namerule_order(winname, windomain, unixname,
7044520Snw141292 			rule->direction, &w2u_order, &u2w_order);
7054520Snw141292 	if (retcode != IDMAP_SUCCESS)
7064520Snw141292 		goto out;
7074520Snw141292 
7084520Snw141292 	if (w2u_order)
7094520Snw141292 		(void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order);
7104520Snw141292 	if (u2w_order)
7114520Snw141292 		(void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order);
7124520Snw141292 
7134864Sbaban 	/*
7144864Sbaban 	 * For the triggers on namerules table to work correctly:
7154864Sbaban 	 * 1) Use NULL instead of 0 for w2u_order and u2w_order
7164864Sbaban 	 * 2) Use "" instead of NULL for "no domain"
7174864Sbaban 	 */
7184864Sbaban 
7194864Sbaban 	if (windomain != NULL)
7204864Sbaban 		dom = windomain;
7214864Sbaban 	else if (lookup_wksids_name2sid(winname, NULL, NULL, NULL)
7224864Sbaban 	    == IDMAP_SUCCESS) {
7234864Sbaban 		/* well-known SIDs don't need domain */
7244864Sbaban 		dom = "";
7254864Sbaban 	}
7264520Snw141292 
7274520Snw141292 	RDLOCK_CONFIG();
7284864Sbaban 	if (dom == NULL) {
7294864Sbaban 		if (_idmapdstate.cfg->pgcfg.mapping_domain)
7304864Sbaban 			dom = _idmapdstate.cfg->pgcfg.mapping_domain;
7314864Sbaban 		else
7324864Sbaban 			dom = "";
7334864Sbaban 	}
734*4884Sjp151216 	sql = sqlite_mprintf("INSERT into namerules "
7354520Snw141292 		"(is_user, windomain, winname, is_nt4, "
7364520Snw141292 		"unixname, w2u_order, u2w_order) "
7374520Snw141292 		"VALUES(%d, %Q, %Q, %d, %Q, %q, %q);",
7384520Snw141292 		rule->is_user?1:0,
7394520Snw141292 		dom,
7404520Snw141292 		winname, rule->is_nt4?1:0,
7414520Snw141292 		unixname,
7424520Snw141292 		w2u_order?w2ubuf:NULL,
7434520Snw141292 		u2w_order?u2wbuf:NULL);
7444520Snw141292 	UNLOCK_CONFIG();
7454520Snw141292 
7464520Snw141292 	if (sql == NULL) {
7474520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
7484520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
7494520Snw141292 		goto out;
7504520Snw141292 	}
7514520Snw141292 
7524520Snw141292 	retcode = sql_exec_no_cb(db, sql);
7534520Snw141292 
7544520Snw141292 	if (retcode == IDMAP_ERR_OTHER)
7554520Snw141292 		retcode = IDMAP_ERR_CFG;
7564520Snw141292 
7574520Snw141292 out:
7584864Sbaban 	if (windomain != NULL)
7594520Snw141292 		idmap_free(windomain);
7604864Sbaban 	if (winname != NULL)
7614520Snw141292 		idmap_free(winname);
7624864Sbaban 	if (unixname != NULL)
7634520Snw141292 		idmap_free(unixname);
7644864Sbaban 	if (sql != NULL)
7654520Snw141292 		sqlite_freemem(sql);
7664520Snw141292 	return (retcode);
7674520Snw141292 }
7684520Snw141292 
7694520Snw141292 /*
7704520Snw141292  * Flush name-based mapping rules
7714520Snw141292  */
7724520Snw141292 idmap_retcode
7734520Snw141292 flush_namerules(sqlite *db, bool_t is_user) {
7744520Snw141292 	char		*sql = NULL;
7754520Snw141292 	idmap_stat	retcode;
7764520Snw141292 
7774520Snw141292 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
7784520Snw141292 		"is_user = %d;", is_user?1:0);
7794520Snw141292 
7804520Snw141292 	if (sql == NULL) {
7814520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
7824520Snw141292 		return (IDMAP_ERR_MEMORY);
7834520Snw141292 	}
7844520Snw141292 
7854520Snw141292 	retcode = sql_exec_no_cb(db, sql);
7864520Snw141292 
7874520Snw141292 	sqlite_freemem(sql);
7884520Snw141292 	return (retcode);
7894520Snw141292 }
7904520Snw141292 
7914520Snw141292 /*
7924520Snw141292  * Generate and execute SQL statement to remove a name-based mapping rule
7934520Snw141292  */
7944520Snw141292 idmap_retcode
7954520Snw141292 rm_namerule(sqlite *db, idmap_namerule *rule) {
7964520Snw141292 	char		*sql = NULL;
7974520Snw141292 	idmap_stat	retcode;
7984520Snw141292 	char		*s_windomain = NULL, *s_winname = NULL;
7994520Snw141292 	char		*s_unixname = NULL;
8004520Snw141292 	char		buf[80];
8014520Snw141292 
8024520Snw141292 	if (rule->direction < 0 &&
8034520Snw141292 			rule->windomain.idmap_utf8str_len < 1 &&
8044520Snw141292 			rule->winname.idmap_utf8str_len < 1 &&
8054520Snw141292 			rule->unixname.idmap_utf8str_len < 1)
8064520Snw141292 		return (IDMAP_SUCCESS);
8074520Snw141292 
8084520Snw141292 	if (rule->direction < 0) {
8094520Snw141292 		buf[0] = 0;
8104644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_BI) {
8114520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
8124520Snw141292 				" AND u2w_order > 0");
8134644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_W2U) {
8144520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
8154520Snw141292 				" AND (u2w_order = 0 OR u2w_order ISNULL)");
8164644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_U2W) {
8174520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND u2w_order > 0"
8184520Snw141292 				" AND (w2u_order = 0 OR w2u_order ISNULL)");
8194520Snw141292 	}
8204520Snw141292 
8214520Snw141292 	retcode = IDMAP_ERR_INTERNAL;
8224520Snw141292 	if (rule->windomain.idmap_utf8str_len > 0) {
8234520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "windomain", "=",
8244520Snw141292 				&rule->windomain,
8254520Snw141292 				"", &s_windomain) != IDMAP_SUCCESS)
8264520Snw141292 			goto out;
8274520Snw141292 	}
8284520Snw141292 
8294520Snw141292 	if (rule->winname.idmap_utf8str_len > 0) {
8304520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "winname", "=",
8314520Snw141292 				&rule->winname,
8324520Snw141292 				"", &s_winname) != IDMAP_SUCCESS)
8334520Snw141292 			goto out;
8344520Snw141292 	}
8354520Snw141292 
8364520Snw141292 	if (rule->unixname.idmap_utf8str_len > 0) {
8374520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "unixname", "=",
8384520Snw141292 				&rule->unixname,
8394520Snw141292 				"", &s_unixname) != IDMAP_SUCCESS)
8404520Snw141292 			goto out;
8414520Snw141292 	}
8424520Snw141292 
8434520Snw141292 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
8444520Snw141292 		"is_user = %d %s %s %s %s;",
8454520Snw141292 		rule->is_user?1:0,
8464520Snw141292 		s_windomain?s_windomain:"",
8474520Snw141292 		s_winname?s_winname:"",
8484520Snw141292 		s_unixname?s_unixname:"",
8494520Snw141292 		buf);
8504520Snw141292 
8514520Snw141292 	if (sql == NULL) {
8524520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
8534520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
8544520Snw141292 		goto out;
8554520Snw141292 	}
8564520Snw141292 
8574520Snw141292 	retcode = sql_exec_no_cb(db, sql);
8584520Snw141292 
8594520Snw141292 out:
8604864Sbaban 	if (s_windomain != NULL)
8614520Snw141292 		sqlite_freemem(s_windomain);
8624864Sbaban 	if (s_winname != NULL)
8634520Snw141292 		sqlite_freemem(s_winname);
8644864Sbaban 	if (s_unixname != NULL)
8654520Snw141292 		sqlite_freemem(s_unixname);
8664864Sbaban 	if (sql != NULL)
8674520Snw141292 		sqlite_freemem(sql);
8684520Snw141292 	return (retcode);
8694520Snw141292 }
8704520Snw141292 
8714520Snw141292 /*
8724520Snw141292  * Compile the given SQL query and step just once.
8734520Snw141292  *
8744520Snw141292  * Input:
8754520Snw141292  * db  - db handle
8764520Snw141292  * sql - SQL statement
8774520Snw141292  *
8784520Snw141292  * Output:
8794520Snw141292  * vm     -  virtual SQL machine
8804520Snw141292  * ncol   - number of columns in the result
8814520Snw141292  * values - column values
8824520Snw141292  *
8834520Snw141292  * Return values:
8844520Snw141292  * IDMAP_SUCCESS
8854520Snw141292  * IDMAP_ERR_NOTFOUND
8864520Snw141292  * IDMAP_ERR_INTERNAL
8874520Snw141292  */
8884520Snw141292 
8894520Snw141292 static idmap_retcode
8904520Snw141292 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
8914520Snw141292 		int reqcol, const char ***values) {
8924520Snw141292 	char		*errmsg = NULL;
893*4884Sjp151216 	int		r;
894*4884Sjp151216 
895*4884Sjp151216 	if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) {
8964520Snw141292 		idmapdlog(LOG_ERR,
8974520Snw141292 			"Database error during %s (%s)",
8984520Snw141292 			sql, CHECK_NULL(errmsg));
8994520Snw141292 		sqlite_freemem(errmsg);
9004520Snw141292 		return (IDMAP_ERR_INTERNAL);
9014520Snw141292 	}
9024520Snw141292 
903*4884Sjp151216 	r = sqlite_step(*vm, ncol, values, NULL);
904*4884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
905*4884Sjp151216 
906*4884Sjp151216 	if (r == SQLITE_ROW) {
9074864Sbaban 		if (ncol != NULL && *ncol < reqcol) {
9084520Snw141292 			(void) sqlite_finalize(*vm, NULL);
9094520Snw141292 			*vm = NULL;
9104520Snw141292 			return (IDMAP_ERR_INTERNAL);
9114520Snw141292 		}
9124520Snw141292 		/* Caller will call finalize after using the results */
9134520Snw141292 		return (IDMAP_SUCCESS);
9144520Snw141292 	} else if (r == SQLITE_DONE) {
9154520Snw141292 		(void) sqlite_finalize(*vm, NULL);
9164520Snw141292 		*vm = NULL;
9174520Snw141292 		return (IDMAP_ERR_NOTFOUND);
9184520Snw141292 	}
9194520Snw141292 
9204520Snw141292 	(void) sqlite_finalize(*vm, &errmsg);
9214520Snw141292 	*vm = NULL;
9224520Snw141292 	idmapdlog(LOG_ERR, "Database error during %s (%s)",
923*4884Sjp151216 	    sql, CHECK_NULL(errmsg));
9244520Snw141292 	sqlite_freemem(errmsg);
9254520Snw141292 	return (IDMAP_ERR_INTERNAL);
9264520Snw141292 }
9274520Snw141292 
9284864Sbaban /*
9294864Sbaban  * Table for well-known SIDs.
9304864Sbaban  *
9314864Sbaban  * Background:
9324864Sbaban  *
9334864Sbaban  * These well-known principals are stored (as of Windows Server 2003) under:
9344864Sbaban  * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
9354864Sbaban  * They belong to objectClass "foreignSecurityPrincipal". They don't have
9364864Sbaban  * "samAccountName" nor "userPrincipalName" attributes. Their names are
9374864Sbaban  * available in "cn" and "name" attributes. Some of these principals have a
9384864Sbaban  * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
9394864Sbaban  * these duplicate entries have the stringified SID in the "name" and "cn"
9404864Sbaban  * attributes instead of the actual name.
9414864Sbaban  *
9424864Sbaban  * These principals remain constant across all operating systems. Using
9434864Sbaban  * a hard-coded table here improves performance and avoids additional
9444864Sbaban  * complexity in the AD lookup code in adutils.c
9454864Sbaban  *
9464864Sbaban  * Currently we don't support localization of well-known SID names,
9474864Sbaban  * unlike Windows.
9484864Sbaban  *
9494864Sbaban  * Note that other well-known SIDs (i.e. S-1-5-<domain>-<w-k RID> and
9504864Sbaban  * S-1-5-32-<w-k RID>) are not stored here because AD does have normal
9514864Sbaban  * user/group objects for these objects and can be looked up using the
9524864Sbaban  * existing AD lookup code.
9534864Sbaban  */
9544864Sbaban static wksids_table_t wksids[] = {
9554864Sbaban 	{"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1},
9564864Sbaban 	{"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 0},
9574864Sbaban 	{"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0},
9584864Sbaban 	{"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1},
9594864Sbaban 	{"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1},
9604864Sbaban 	{"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1},
9614864Sbaban 	{"S-1-5", 2, "Network", 0, SENTINEL_PID, -1},
9624864Sbaban 	{"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1},
9634864Sbaban 	{"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1},
9644864Sbaban 	{"S-1-5", 6, "Service", 0, SENTINEL_PID, -1},
9654864Sbaban 	{"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0},
9664864Sbaban 	{"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1},
9674864Sbaban 	{"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1},
9684864Sbaban 	{"S-1-5", 10, "Self", 0, SENTINEL_PID, -1},
9694864Sbaban 	{"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1},
9704864Sbaban 	{"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1},
9714864Sbaban 	{"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1},
9724864Sbaban 	{"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1},
9734864Sbaban 	{"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1},
9744864Sbaban 	{"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0},
9754864Sbaban 	{"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1},
9764864Sbaban 	{"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1},
9774864Sbaban 	{"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1},
9784864Sbaban 	{"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1},
9794864Sbaban 	{"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1},
9804864Sbaban 	{"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1},
9814864Sbaban 	{NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1}
9824520Snw141292 };
9834520Snw141292 
9844520Snw141292 static idmap_retcode
9854520Snw141292 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res) {
9864520Snw141292 	int i;
9874864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
9884864Sbaban 		if (wksids[i].rid == req->id1.idmap_id_u.sid.rid &&
9894864Sbaban 		    (strcasecmp(wksids[i].sidprefix,
9904864Sbaban 		    req->id1.idmap_id_u.sid.prefix) == 0)) {
9914864Sbaban 
9924864Sbaban 			if (wksids[i].pid == SENTINEL_PID)
9934864Sbaban 				/* Not mapped, break */
9944864Sbaban 				break;
9954864Sbaban 			else if (wksids[i].direction == IDMAP_DIRECTION_U2W)
9964864Sbaban 				continue;
9974864Sbaban 
9984520Snw141292 			switch (req->id2.idtype) {
9994520Snw141292 			case IDMAP_UID:
10004864Sbaban 				if (wksids[i].is_user == 0)
10014864Sbaban 					continue;
10024864Sbaban 				res->id.idmap_id_u.uid = wksids[i].pid;
10034864Sbaban 				res->direction = wksids[i].direction;
10044520Snw141292 				return (IDMAP_SUCCESS);
10054520Snw141292 			case IDMAP_GID:
10064864Sbaban 				if (wksids[i].is_user == 1)
10074864Sbaban 					continue;
10084864Sbaban 				res->id.idmap_id_u.gid = wksids[i].pid;
10094864Sbaban 				res->direction = wksids[i].direction;
10104520Snw141292 				return (IDMAP_SUCCESS);
10114520Snw141292 			case IDMAP_POSIXID:
10124864Sbaban 				res->id.idmap_id_u.uid = wksids[i].pid;
10134864Sbaban 				res->id.idtype = (!wksids[i].is_user)?
10144520Snw141292 						IDMAP_GID:IDMAP_UID;
10154864Sbaban 				res->direction = wksids[i].direction;
10164520Snw141292 				return (IDMAP_SUCCESS);
10174520Snw141292 			default:
10184520Snw141292 				return (IDMAP_ERR_NOTSUPPORTED);
10194520Snw141292 			}
10204520Snw141292 		}
10214520Snw141292 	}
10224520Snw141292 	return (IDMAP_ERR_NOTFOUND);
10234520Snw141292 }
10244520Snw141292 
10254520Snw141292 static idmap_retcode
10264520Snw141292 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) {
10274520Snw141292 	int i;
10284864Sbaban 	if (req->id2.idtype != IDMAP_SID)
10294864Sbaban 		return (IDMAP_ERR_NOTSUPPORTED);
10304864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10314864Sbaban 		if (wksids[i].pid == req->id1.idmap_id_u.uid &&
10324864Sbaban 		    wksids[i].is_user == is_user &&
10334864Sbaban 		    wksids[i].direction != IDMAP_DIRECTION_W2U) {
10344864Sbaban 			res->id.idmap_id_u.sid.rid = wksids[i].rid;
10354864Sbaban 			res->id.idmap_id_u.sid.prefix =
10364864Sbaban 				strdup(wksids[i].sidprefix);
10374864Sbaban 			if (res->id.idmap_id_u.sid.prefix == NULL) {
10384864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10394864Sbaban 				return (IDMAP_ERR_MEMORY);
10404520Snw141292 			}
10414864Sbaban 			res->direction = wksids[i].direction;
10424864Sbaban 			return (IDMAP_SUCCESS);
10434864Sbaban 		}
10444864Sbaban 	}
10454864Sbaban 	return (IDMAP_ERR_NOTFOUND);
10464864Sbaban }
10474864Sbaban 
10484864Sbaban static idmap_retcode
10494864Sbaban lookup_wksids_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
10504864Sbaban 		int *type) {
10514864Sbaban 	int i;
10524864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10534864Sbaban 		if ((strcasecmp(wksids[i].sidprefix, sidprefix) == 0) &&
10544864Sbaban 		    wksids[i].rid == rid) {
10554864Sbaban 			if ((*name = strdup(wksids[i].winname)) == NULL) {
10564864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10574864Sbaban 				return (IDMAP_ERR_MEMORY);
10584864Sbaban 			}
10594864Sbaban 			*type = (wksids[i].is_user)?
10604864Sbaban 			    _IDMAP_T_USER:_IDMAP_T_GROUP;
10614864Sbaban 			return (IDMAP_SUCCESS);
10624864Sbaban 		}
10634864Sbaban 	}
10644864Sbaban 	return (IDMAP_ERR_NOTFOUND);
10654864Sbaban }
10664864Sbaban 
10674864Sbaban static idmap_retcode
10684864Sbaban lookup_wksids_name2sid(const char *name, char **sidprefix, idmap_rid_t *rid,
10694864Sbaban 		int *type) {
10704864Sbaban 	int i;
10714864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10724864Sbaban 		if (strcasecmp(wksids[i].winname, name) == 0) {
10734864Sbaban 			if (sidprefix != NULL && (*sidprefix =
10744864Sbaban 			    strdup(wksids[i].sidprefix)) == NULL) {
10754864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10764864Sbaban 				return (IDMAP_ERR_MEMORY);
10774864Sbaban 			}
10784864Sbaban 			if (type != NULL)
10794864Sbaban 				*type = (wksids[i].is_user)?
10804864Sbaban 				    _IDMAP_T_USER:_IDMAP_T_GROUP;
10814864Sbaban 			if (rid != NULL)
10824864Sbaban 				*rid = wksids[i].rid;
10834864Sbaban 			return (IDMAP_SUCCESS);
10844520Snw141292 		}
10854520Snw141292 	}
10864520Snw141292 	return (IDMAP_ERR_NOTFOUND);
10874520Snw141292 }
10884520Snw141292 
10894520Snw141292 static idmap_retcode
10904520Snw141292 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
10914520Snw141292 	char		*end;
10924520Snw141292 	char		*sql = NULL;
10934520Snw141292 	const char	**values;
10944520Snw141292 	sqlite_vm	*vm = NULL;
10954520Snw141292 	int		ncol, is_user;
10964520Snw141292 	uid_t		pid;
10974520Snw141292 	idmap_utf8str	*str;
10984520Snw141292 	time_t		curtime, exp;
10994520Snw141292 	idmap_retcode	retcode;
11004520Snw141292 
11014520Snw141292 	/* Current time */
11024520Snw141292 	errno = 0;
11034520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
11044520Snw141292 		idmapdlog(LOG_ERR,
11054520Snw141292 			"Failed to get current time (%s)",
11064520Snw141292 			strerror(errno));
11074520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
11084520Snw141292 		goto out;
11094520Snw141292 	}
11104520Snw141292 
11114520Snw141292 	/* SQL to lookup the cache */
11124520Snw141292 	sql = sqlite_mprintf("SELECT pid, is_user, expiration, unixname, u2w "
11134520Snw141292 			"FROM idmap_cache WHERE "
11144520Snw141292 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
11154520Snw141292 			"(pid >= 2147483648 OR "
11164520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
11174520Snw141292 			"expiration > %d));",
11184520Snw141292 			req->id1.idmap_id_u.sid.prefix,
11194520Snw141292 			req->id1.idmap_id_u.sid.rid,
11204520Snw141292 			curtime);
11214520Snw141292 	if (sql == NULL) {
11224520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
11234520Snw141292 		retcode = IDMAP_ERR_MEMORY;
11244520Snw141292 		goto out;
11254520Snw141292 	}
11264520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
11274520Snw141292 	sqlite_freemem(sql);
11284520Snw141292 
11294520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
11304520Snw141292 		goto out;
11314520Snw141292 	} else if (retcode == IDMAP_SUCCESS) {
11324520Snw141292 		/* sanity checks */
11334520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
11344520Snw141292 			retcode = IDMAP_ERR_CACHE;
11354520Snw141292 			goto out;
11364520Snw141292 		}
11374520Snw141292 
11384520Snw141292 		pid = strtoul(values[0], &end, 10);
11394520Snw141292 		is_user = strncmp(values[1], "0", 2)?1:0;
11404520Snw141292 
11414520Snw141292 		/*
11424520Snw141292 		 * We may have an expired ephemeral mapping. Consider
11434520Snw141292 		 * the expired entry as valid if we are not going to
11444520Snw141292 		 * perform name-based mapping. But do not renew the
11454520Snw141292 		 * expiration.
11464520Snw141292 		 * If we will be doing name-based mapping then store the
11474520Snw141292 		 * ephemeral pid in the result so that we can use it
11484520Snw141292 		 * if we end up doing dynamic mapping again.
11494520Snw141292 		 */
11504520Snw141292 		if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) &&
11514520Snw141292 				!AVOID_NAMESERVICE(req)) {
11524864Sbaban 			if (IS_EPHEMERAL(pid) && values[2] != NULL) {
11534520Snw141292 				exp = strtoll(values[2], &end, 10);
11544520Snw141292 				if (exp && exp <= curtime) {
11554520Snw141292 					/* Store the ephemeral pid */
11564520Snw141292 					res->id.idmap_id_u.uid = pid;
11574520Snw141292 					res->id.idtype = is_user?
11584520Snw141292 						IDMAP_UID:IDMAP_GID;
11594644Sbaban 					res->direction = IDMAP_DIRECTION_BI;
11604520Snw141292 					req->direction |= is_user?
11614520Snw141292 						_IDMAP_F_EXP_EPH_UID:
11624520Snw141292 						_IDMAP_F_EXP_EPH_GID;
11634520Snw141292 					retcode = IDMAP_ERR_NOTFOUND;
11644520Snw141292 					goto out;
11654520Snw141292 				}
11664520Snw141292 			}
11674520Snw141292 		}
11684520Snw141292 
11694520Snw141292 		switch (req->id2.idtype) {
11704520Snw141292 		case IDMAP_UID:
11714520Snw141292 			if (!is_user)
11724520Snw141292 				retcode = IDMAP_ERR_NOTUSER;
11734520Snw141292 			else
11744520Snw141292 				res->id.idmap_id_u.uid = pid;
11754520Snw141292 			break;
11764520Snw141292 		case IDMAP_GID:
11774520Snw141292 			if (is_user)
11784520Snw141292 				retcode = IDMAP_ERR_NOTGROUP;
11794520Snw141292 			else
11804520Snw141292 				res->id.idmap_id_u.gid = pid;
11814520Snw141292 			break;
11824520Snw141292 		case IDMAP_POSIXID:
11834520Snw141292 			res->id.idmap_id_u.uid = pid;
11844520Snw141292 			res->id.idtype = (is_user)?IDMAP_UID:IDMAP_GID;
11854520Snw141292 			break;
11864520Snw141292 		default:
11874520Snw141292 			retcode = IDMAP_ERR_NOTSUPPORTED;
11884520Snw141292 			break;
11894520Snw141292 		}
11904520Snw141292 	}
11914520Snw141292 
11924520Snw141292 out:
11934520Snw141292 	if (retcode == IDMAP_SUCCESS) {
11944864Sbaban 		if (values[4] != NULL)
11954520Snw141292 			res->direction =
11964644Sbaban 			    (strtol(values[4], &end, 10) == 0)?
11974644Sbaban 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
11984520Snw141292 		else
11994644Sbaban 			res->direction = IDMAP_DIRECTION_W2U;
12004520Snw141292 
12014864Sbaban 		if (values[3] != NULL) {
12024520Snw141292 			str = &req->id2name;
12034520Snw141292 			retcode = idmap_str2utf8(&str, values[3], 0);
12044520Snw141292 			if (retcode != IDMAP_SUCCESS) {
12054520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
12064520Snw141292 				retcode = IDMAP_ERR_MEMORY;
12074520Snw141292 			}
12084520Snw141292 		}
12094520Snw141292 	}
12104864Sbaban 	if (vm != NULL)
12114520Snw141292 		(void) sqlite_finalize(vm, NULL);
12124520Snw141292 	return (retcode);
12134520Snw141292 }
12144520Snw141292 
12154520Snw141292 static idmap_retcode
12164864Sbaban lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid,
12174520Snw141292 		char **name, char **domain, int *type) {
12184520Snw141292 	char		*end;
12194520Snw141292 	char		*sql = NULL;
12204520Snw141292 	const char	**values;
12214520Snw141292 	sqlite_vm	*vm = NULL;
12224520Snw141292 	int		ncol;
12234520Snw141292 	time_t		curtime;
12244520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
12254520Snw141292 
12264520Snw141292 	/* Get current time */
12274520Snw141292 	errno = 0;
12284520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
12294520Snw141292 		idmapdlog(LOG_ERR,
12304520Snw141292 			"Failed to get current time (%s)",
12314520Snw141292 			strerror(errno));
12324520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
12334520Snw141292 		goto out;
12344520Snw141292 	}
12354520Snw141292 
12364520Snw141292 	/* SQL to lookup the cache */
12374520Snw141292 	sql = sqlite_mprintf("SELECT name, domain, type FROM name_cache WHERE "
12384520Snw141292 			"sidprefix = %Q AND rid = %u AND "
12394520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
12404520Snw141292 			"expiration > %d);",
12414520Snw141292 			sidprefix, rid, curtime);
12424520Snw141292 	if (sql == NULL) {
12434520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
12444520Snw141292 		retcode = IDMAP_ERR_MEMORY;
12454520Snw141292 		goto out;
12464520Snw141292 	}
12474520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
12484520Snw141292 	sqlite_freemem(sql);
12494520Snw141292 
12504520Snw141292 	if (retcode == IDMAP_SUCCESS) {
12514864Sbaban 		if (type != NULL) {
12524520Snw141292 			if (values[2] == NULL) {
12534520Snw141292 				retcode = IDMAP_ERR_CACHE;
12544520Snw141292 				goto out;
12554520Snw141292 			}
12564520Snw141292 			*type = strtol(values[2], &end, 10);
12574520Snw141292 		}
12584520Snw141292 
12594864Sbaban 		if (name != NULL && values[0] != NULL) {
12604520Snw141292 			if ((*name = strdup(values[0])) == NULL) {
12614520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
12624520Snw141292 				retcode = IDMAP_ERR_MEMORY;
12634520Snw141292 				goto out;
12644520Snw141292 			}
12654520Snw141292 		}
12664520Snw141292 
12674864Sbaban 		if (domain != NULL && values[1] != NULL) {
12684520Snw141292 			if ((*domain = strdup(values[1])) == NULL) {
12694864Sbaban 				if (name != NULL && *name) {
12704520Snw141292 					free(*name);
12714520Snw141292 					*name = NULL;
12724520Snw141292 				}
12734520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
12744520Snw141292 				retcode = IDMAP_ERR_MEMORY;
12754520Snw141292 				goto out;
12764520Snw141292 			}
12774520Snw141292 		}
12784520Snw141292 	}
12794520Snw141292 
12804520Snw141292 out:
12814864Sbaban 	if (vm != NULL)
12824520Snw141292 		(void) sqlite_finalize(vm, NULL);
12834520Snw141292 	return (retcode);
12844520Snw141292 }
12854520Snw141292 
12864520Snw141292 static idmap_retcode
12874520Snw141292 verify_type(idmap_id_type idtype, int type, idmap_id_res *res) {
12884520Snw141292 	switch (idtype) {
12894520Snw141292 	case IDMAP_UID:
12904520Snw141292 		if (type != _IDMAP_T_USER)
12914520Snw141292 			return (IDMAP_ERR_NOTUSER);
12924520Snw141292 		res->id.idtype = IDMAP_UID;
12934520Snw141292 		break;
12944520Snw141292 	case IDMAP_GID:
12954520Snw141292 		if (type != _IDMAP_T_GROUP)
12964520Snw141292 			return (IDMAP_ERR_NOTGROUP);
12974520Snw141292 		res->id.idtype = IDMAP_GID;
12984520Snw141292 		break;
12994520Snw141292 	case IDMAP_POSIXID:
13004520Snw141292 		if (type == _IDMAP_T_USER)
13014520Snw141292 			res->id.idtype = IDMAP_UID;
13024520Snw141292 		else if (type == _IDMAP_T_GROUP)
13034520Snw141292 			res->id.idtype = IDMAP_GID;
13044520Snw141292 		else
13054520Snw141292 			return (IDMAP_ERR_SID);
13064520Snw141292 		break;
13074520Snw141292 	default:
13084520Snw141292 		return (IDMAP_ERR_NOTSUPPORTED);
13094520Snw141292 	}
13104520Snw141292 	return (IDMAP_SUCCESS);
13114520Snw141292 }
13124520Snw141292 
13134520Snw141292 /*
13144864Sbaban  * Lookup sid to name locally
13154520Snw141292  */
13164520Snw141292 static idmap_retcode
13174864Sbaban lookup_local_sid2name(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
13184520Snw141292 	int		type = -1;
13194520Snw141292 	idmap_retcode	retcode;
13204520Snw141292 	char		*sidprefix;
13214520Snw141292 	idmap_rid_t	rid;
13224520Snw141292 	char		*name = NULL, *domain = NULL;
13234520Snw141292 	idmap_utf8str	*str;
13244520Snw141292 
13254520Snw141292 	sidprefix = req->id1.idmap_id_u.sid.prefix;
13264520Snw141292 	rid = req->id1.idmap_id_u.sid.rid;
13274520Snw141292 
13284864Sbaban 	/* Lookup sids to name in well-known sids table */
13294864Sbaban 	retcode = lookup_wksids_sid2name(sidprefix, rid, &name, &type);
13304864Sbaban 	if (retcode != IDMAP_ERR_NOTFOUND)
13314864Sbaban 		goto out;
13324864Sbaban 
13334520Snw141292 	/* Lookup sid to name in cache */
13344864Sbaban 	retcode = lookup_cache_sid2name(cache, sidprefix, rid, &name,
13354520Snw141292 		&domain, &type);
13364520Snw141292 	if (retcode != IDMAP_SUCCESS)
13374520Snw141292 		goto out;
13384520Snw141292 
13394520Snw141292 out:
13404520Snw141292 	if (retcode == IDMAP_SUCCESS) {
13414864Sbaban 		/* Verify that the sid type matches the request */
13424864Sbaban 		retcode = verify_type(req->id2.idtype, type, res);
13434864Sbaban 
13444520Snw141292 		/* update state in 'req' */
13454864Sbaban 		if (name != NULL) {
13464520Snw141292 			str = &req->id1name;
13474520Snw141292 			(void) idmap_str2utf8(&str, name, 1);
13484520Snw141292 		}
13494864Sbaban 		if (domain != NULL) {
13504520Snw141292 			str = &req->id1domain;
13514520Snw141292 			(void) idmap_str2utf8(&str, domain, 1);
13524520Snw141292 		}
13534520Snw141292 	} else {
13544864Sbaban 		if (name != NULL)
13554520Snw141292 			free(name);
13564864Sbaban 		if (domain != NULL)
13574520Snw141292 			free(domain);
13584520Snw141292 	}
13594520Snw141292 	return (retcode);
13604520Snw141292 }
13614520Snw141292 
13624520Snw141292 idmap_retcode
13634520Snw141292 lookup_win_batch_sid2name(lookup_state_t *state, idmap_mapping_batch *batch,
13644520Snw141292 		idmap_ids_res *result) {
13654520Snw141292 	idmap_retcode	retcode;
13664520Snw141292 	int		ret, i;
13674520Snw141292 	int		retries = 0;
13684520Snw141292 	idmap_mapping	*req;
13694520Snw141292 	idmap_id_res	*res;
13704520Snw141292 
13714520Snw141292 	if (state->ad_nqueries == 0)
13724520Snw141292 		return (IDMAP_SUCCESS);
13734520Snw141292 
13744520Snw141292 retry:
13754520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries,
13764520Snw141292 		&state->ad_lookup);
13774520Snw141292 	if (ret != 0) {
13784520Snw141292 		idmapdlog(LOG_ERR,
13794520Snw141292 		"Failed to create sid2name batch for AD lookup");
13804520Snw141292 		return (IDMAP_ERR_INTERNAL);
13814520Snw141292 	}
13824520Snw141292 
13834520Snw141292 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
13844520Snw141292 		req = &batch->idmap_mapping_batch_val[i];
13854520Snw141292 		res = &result->ids.ids_val[i];
13864520Snw141292 
13874520Snw141292 		if (req->id1.idtype == IDMAP_SID &&
13884520Snw141292 				req->direction & _IDMAP_F_S2N_AD) {
13894864Sbaban 			if (retries == 0)
13904864Sbaban 				res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
13914864Sbaban 			else if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
13924864Sbaban 				continue;
13934520Snw141292 			retcode = idmap_sid2name_batch_add1(
13944520Snw141292 					state->ad_lookup,
13954520Snw141292 					req->id1.idmap_id_u.sid.prefix,
13964520Snw141292 					&req->id1.idmap_id_u.sid.rid,
13974520Snw141292 					&req->id1name.idmap_utf8str_val,
13984520Snw141292 					&req->id1domain.idmap_utf8str_val,
13994520Snw141292 					(int *)&res->id.idtype,
14004520Snw141292 					&res->retcode);
14014520Snw141292 
14024520Snw141292 			if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
14034520Snw141292 				break;
14044520Snw141292 			if (retcode != IDMAP_SUCCESS)
14054520Snw141292 				goto out;
14064520Snw141292 		}
14074520Snw141292 	}
14084520Snw141292 
14094520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
1410*4884Sjp151216 		idmap_lookup_release_batch(&state->ad_lookup);
14114520Snw141292 	else
14124520Snw141292 		retcode = idmap_lookup_batch_end(&state->ad_lookup, NULL);
14134520Snw141292 
14144520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
14154520Snw141292 		goto retry;
14164520Snw141292 
14174520Snw141292 	return (retcode);
14184520Snw141292 
14194520Snw141292 out:
14204520Snw141292 	idmapdlog(LOG_NOTICE, "Windows SID to user/group name lookup failed");
1421*4884Sjp151216 	idmap_lookup_release_batch(&state->ad_lookup);
14224520Snw141292 	return (retcode);
14234520Snw141292 }
14244520Snw141292 
14254520Snw141292 idmap_retcode
14264520Snw141292 sid2pid_first_pass(lookup_state_t *state, sqlite *cache, idmap_mapping *req,
14274520Snw141292 		idmap_id_res *res) {
14284520Snw141292 	idmap_retcode	retcode;
14294520Snw141292 
14304520Snw141292 	/*
14314520Snw141292 	 * The req->direction field is used to maintain state of the
14324520Snw141292 	 * sid2pid request.
14334520Snw141292 	 */
14344520Snw141292 	req->direction = _IDMAP_F_DONE;
14354520Snw141292 
14364520Snw141292 	if (req->id1.idmap_id_u.sid.prefix == NULL) {
14374520Snw141292 		retcode = IDMAP_ERR_SID;
14384520Snw141292 		goto out;
14394520Snw141292 	}
14404520Snw141292 	res->id.idtype = req->id2.idtype;
14414520Snw141292 	res->id.idmap_id_u.uid = UID_NOBODY;
14424520Snw141292 
14434864Sbaban 	/* Lookup well-known sid to pid mapping */
14444520Snw141292 	retcode = lookup_wksids_sid2pid(req, res);
14454520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
14464520Snw141292 		goto out;
14474520Snw141292 
14484520Snw141292 	/* Lookup sid to pid in cache */
14494520Snw141292 	retcode = lookup_cache_sid2pid(cache, req, res);
14504520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
14514520Snw141292 		goto out;
14524520Snw141292 
14534520Snw141292 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
14544520Snw141292 		res->id.idmap_id_u.uid = SENTINEL_PID;
14554520Snw141292 		goto out;
14564520Snw141292 	}
14574520Snw141292 
14584520Snw141292 	/*
14594520Snw141292 	 * Failed to find non-expired entry in cache. Tell the caller
14604520Snw141292 	 * that we are not done yet.
14614520Snw141292 	 */
14624520Snw141292 	state->sid2pid_done = FALSE;
14634520Snw141292 
14644520Snw141292 	/*
14654520Snw141292 	 * Our next step is name-based mapping. To lookup name-based
14664520Snw141292 	 * mapping rules, we need the windows name and domain-name
14674520Snw141292 	 * associated with the SID.
14684520Snw141292 	 */
14694520Snw141292 
14704520Snw141292 	/*
14714520Snw141292 	 * Check if we already have the name (i.e name2pid lookups)
14724520Snw141292 	 */
14734864Sbaban 	if (req->id1name.idmap_utf8str_val != NULL &&
14744864Sbaban 	    req->id1domain.idmap_utf8str_val != NULL) {
14754520Snw141292 		retcode = IDMAP_SUCCESS;
14764520Snw141292 		req->direction |= _IDMAP_F_S2N_CACHE;
14774520Snw141292 		goto out;
14784520Snw141292 	}
14794520Snw141292 
14804864Sbaban 	/* Lookup sid to winname@domain locally first */
14814864Sbaban 	retcode = lookup_local_sid2name(cache, req, res);
14824864Sbaban 	if (retcode == IDMAP_SUCCESS) {
14834864Sbaban 		req->direction |= _IDMAP_F_S2N_CACHE;
14844864Sbaban 	} else if (retcode == IDMAP_ERR_NOTFOUND) {
14854520Snw141292 		/* Batch sid to name AD lookup request */
14864520Snw141292 		retcode = IDMAP_SUCCESS;
14874520Snw141292 		req->direction |= _IDMAP_F_S2N_AD;
14884520Snw141292 		state->ad_nqueries++;
14894520Snw141292 		goto out;
14904520Snw141292 	}
14914520Snw141292 
14924520Snw141292 
14934520Snw141292 out:
14944520Snw141292 	res->retcode = idmap_stat4prot(retcode);
14954520Snw141292 	return (retcode);
14964520Snw141292 }
14974520Snw141292 
14984520Snw141292 /*
14994520Snw141292  * Generate SID using the following convention
15004520Snw141292  * 	<machine-sid-prefix>-<1000 + uid>
15014520Snw141292  * 	<machine-sid-prefix>-<2^31 + gid>
15024520Snw141292  */
15034520Snw141292 static idmap_retcode
15044520Snw141292 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user) {
15054520Snw141292 
15064864Sbaban 	if (_idmapdstate.cfg->pgcfg.machine_sid != NULL) {
15074520Snw141292 		/* Skip 1000 UIDs */
15084520Snw141292 		if (is_user && req->id1.idmap_id_u.uid >
15094520Snw141292 				(INT32_MAX - LOCALRID_MIN))
15104864Sbaban 			return (IDMAP_ERR_NOMAPPING);
15114520Snw141292 
15124520Snw141292 		RDLOCK_CONFIG();
15134520Snw141292 		res->id.idmap_id_u.sid.prefix =
15144520Snw141292 			strdup(_idmapdstate.cfg->pgcfg.machine_sid);
15154520Snw141292 		if (res->id.idmap_id_u.sid.prefix == NULL) {
15164520Snw141292 			UNLOCK_CONFIG();
15174520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
15184520Snw141292 			return (IDMAP_ERR_MEMORY);
15194520Snw141292 		}
15204520Snw141292 		UNLOCK_CONFIG();
15214520Snw141292 		res->id.idmap_id_u.sid.rid =
15224520Snw141292 			(is_user)?req->id1.idmap_id_u.uid + LOCALRID_MIN:
15234520Snw141292 			req->id1.idmap_id_u.gid + INT32_MAX + 1;
15244644Sbaban 		res->direction = IDMAP_DIRECTION_BI;
15254520Snw141292 
15264520Snw141292 		/*
15274520Snw141292 		 * Don't update name_cache because local sids don't have
15284520Snw141292 		 * valid windows names.
15294520Snw141292 		 * We mark the entry as being found in the namecache so that
15304520Snw141292 		 * the cache update routine doesn't update namecache.
15314520Snw141292 		 */
15324520Snw141292 		req->direction = _IDMAP_F_S2N_CACHE;
15334868Sbaban 		return (IDMAP_SUCCESS);
15344520Snw141292 	}
15354520Snw141292 
15364864Sbaban 	return (IDMAP_ERR_NOMAPPING);
15374520Snw141292 }
15384520Snw141292 
15394520Snw141292 static idmap_retcode
15404520Snw141292 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) {
15414520Snw141292 	char		*sidprefix;
15424520Snw141292 	uint32_t	rid;
15434520Snw141292 	int		s;
15444520Snw141292 
15454520Snw141292 	/*
15464520Snw141292 	 * If the sidprefix == localsid then UID = last RID - 1000 or
15474520Snw141292 	 * GID = last RID - 2^31.
15484520Snw141292 	 */
15494520Snw141292 	sidprefix = req->id1.idmap_id_u.sid.prefix;
15504520Snw141292 	rid = req->id1.idmap_id_u.sid.rid;
15514520Snw141292 
15524520Snw141292 	RDLOCK_CONFIG();
15534520Snw141292 	s = (_idmapdstate.cfg->pgcfg.machine_sid)?
15544520Snw141292 		strcasecmp(sidprefix,
15554520Snw141292 		_idmapdstate.cfg->pgcfg.machine_sid):1;
15564520Snw141292 	UNLOCK_CONFIG();
15574520Snw141292 
15584520Snw141292 	if (s == 0) {
15594520Snw141292 		switch (req->id2.idtype) {
15604520Snw141292 		case IDMAP_UID:
15614520Snw141292 			if (rid > INT32_MAX) {
15624520Snw141292 				return (IDMAP_ERR_NOTUSER);
15634520Snw141292 			} else if (rid < LOCALRID_MIN) {
15644520Snw141292 				return (IDMAP_ERR_NOTFOUND);
15654520Snw141292 			}
15664520Snw141292 			res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
15674520Snw141292 			res->id.idtype = IDMAP_UID;
15684520Snw141292 			break;
15694520Snw141292 		case IDMAP_GID:
15704520Snw141292 			if (rid <= INT32_MAX) {
15714520Snw141292 				return (IDMAP_ERR_NOTGROUP);
15724520Snw141292 			}
15734520Snw141292 			res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
15744520Snw141292 			res->id.idtype = IDMAP_GID;
15754520Snw141292 			break;
15764520Snw141292 		case IDMAP_POSIXID:
15774520Snw141292 			if (rid > INT32_MAX) {
15784520Snw141292 				res->id.idmap_id_u.gid =
15794520Snw141292 					rid - INT32_MAX - 1;
15804520Snw141292 				res->id.idtype = IDMAP_GID;
15814520Snw141292 			} else if (rid < LOCALRID_MIN) {
15824520Snw141292 				return (IDMAP_ERR_NOTFOUND);
15834520Snw141292 			} else {
15844520Snw141292 				res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
15854520Snw141292 				res->id.idtype = IDMAP_UID;
15864520Snw141292 			}
15874520Snw141292 			break;
15884520Snw141292 		default:
15894520Snw141292 			return (IDMAP_ERR_NOTSUPPORTED);
15904520Snw141292 		}
15914520Snw141292 		return (IDMAP_SUCCESS);
15924520Snw141292 	}
15934520Snw141292 
15944520Snw141292 	return (IDMAP_ERR_NOTFOUND);
15954520Snw141292 }
15964520Snw141292 
15974520Snw141292 static idmap_retcode
15984520Snw141292 ns_lookup_byname(int is_user, const char *name, idmap_id_res *res) {
15994520Snw141292 	struct passwd	pwd;
16004520Snw141292 	struct group	grp;
16014520Snw141292 	char		buf[1024];
16024520Snw141292 	int		errnum;
16034520Snw141292 	const char	*me = "ns_lookup_byname";
16044520Snw141292 
16054520Snw141292 	if (is_user) {
16064520Snw141292 		if (getpwnam_r(name, &pwd, buf, sizeof (buf)) == NULL) {
16074520Snw141292 			errnum = errno;
16084520Snw141292 			idmapdlog(LOG_WARNING,
16094520Snw141292 			"%s: getpwnam_r(%s) failed (%s).",
16104520Snw141292 				me, name,
16114520Snw141292 				errnum?strerror(errnum):"not found");
16124520Snw141292 			if (errnum == 0)
16134520Snw141292 				return (IDMAP_ERR_NOTFOUND);
16144520Snw141292 			else
16154520Snw141292 				return (IDMAP_ERR_INTERNAL);
16164520Snw141292 		}
16174520Snw141292 		res->id.idmap_id_u.uid = pwd.pw_uid;
16184520Snw141292 		res->id.idtype = IDMAP_UID;
16194520Snw141292 	} else {
16204520Snw141292 		if (getgrnam_r(name, &grp, buf, sizeof (buf)) == NULL) {
16214520Snw141292 			errnum = errno;
16224520Snw141292 			idmapdlog(LOG_WARNING,
16234520Snw141292 			"%s: getgrnam_r(%s) failed (%s).",
16244520Snw141292 				me, name,
16254520Snw141292 				errnum?strerror(errnum):"not found");
16264520Snw141292 			if (errnum == 0)
16274520Snw141292 				return (IDMAP_ERR_NOTFOUND);
16284520Snw141292 			else
16294520Snw141292 				return (IDMAP_ERR_INTERNAL);
16304520Snw141292 		}
16314520Snw141292 		res->id.idmap_id_u.gid = grp.gr_gid;
16324520Snw141292 		res->id.idtype = IDMAP_GID;
16334520Snw141292 	}
16344520Snw141292 	return (IDMAP_SUCCESS);
16354520Snw141292 }
16364520Snw141292 
16374520Snw141292 /*
16384520Snw141292  * Name-based mapping
16394520Snw141292  *
16404520Snw141292  * Case 1: If no rule matches do ephemeral
16414520Snw141292  *
16424520Snw141292  * Case 2: If rule matches and unixname is "" then return no mapping.
16434520Snw141292  *
16444520Snw141292  * Case 3: If rule matches and unixname is specified then lookup name
16454520Snw141292  *  service using the unixname. If unixname not found then return no mapping.
16464520Snw141292  *
16474520Snw141292  * Case 4: If rule matches and unixname is * then lookup name service
16484520Snw141292  *  using winname as the unixname. If unixname not found then process
16494520Snw141292  *  other rules using the lookup order. If no other rule matches then do
16504520Snw141292  *  ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
16514520Snw141292  *  This allows us to specify a fallback unixname per _domain_ or no mapping
16524520Snw141292  *  instead of the default behaviour of doing ephemeral mapping.
16534520Snw141292  *
16544520Snw141292  * Example 1:
16554520Snw141292  * *@sfbay == *
16564520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16574520Snw141292  * the name service then foo@sfbay will be mapped to an ephemeral id.
16584520Snw141292  *
16594520Snw141292  * Example 2:
16604520Snw141292  * *@sfbay == *
16614520Snw141292  * *@sfbay => guest
16624520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16634520Snw141292  * the name service then foo@sfbay will be mapped to guest.
16644520Snw141292  *
16654520Snw141292  * Example 3:
16664520Snw141292  * *@sfbay == *
16674520Snw141292  * *@sfbay => ""
16684520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16694520Snw141292  * the name service then we will return no mapping for foo@sfbay.
16704520Snw141292  *
16714520Snw141292  */
16724520Snw141292 static idmap_retcode
16734520Snw141292 name_based_mapping_sid2pid(sqlite *db, idmap_mapping *req, idmap_id_res *res) {
16744520Snw141292 	const char	*unixname, *winname, *windomain;
16754520Snw141292 	char		*sql = NULL, *errmsg = NULL;
16764520Snw141292 	idmap_retcode	retcode;
16774520Snw141292 	char		*end;
16784520Snw141292 	const char	**values;
16794520Snw141292 	sqlite_vm	*vm = NULL;
16804520Snw141292 	idmap_utf8str	*str;
1681*4884Sjp151216 	int		ncol, r, i, is_user;
16824520Snw141292 	const char	*me = "name_based_mapping_sid2pid";
16834520Snw141292 
16844520Snw141292 	winname = req->id1name.idmap_utf8str_val;
16854520Snw141292 	windomain = req->id1domain.idmap_utf8str_val;
16864520Snw141292 	is_user = (res->id.idtype == IDMAP_UID)?1:0;
16874520Snw141292 
16884520Snw141292 	i = 0;
16894864Sbaban 	if (windomain == NULL) {
16904864Sbaban 		windomain = "";
16914864Sbaban 	} else {
16924864Sbaban 		RDLOCK_CONFIG();
16934864Sbaban 		if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
16944864Sbaban 			if (strcasecmp(_idmapdstate.cfg->pgcfg.mapping_domain,
16954864Sbaban 			    windomain) == 0)
16964864Sbaban 				i = 1;
16974864Sbaban 		}
16984864Sbaban 		UNLOCK_CONFIG();
16994520Snw141292 	}
17004520Snw141292 
17014520Snw141292 	sql = sqlite_mprintf(
17024520Snw141292 		"SELECT unixname, u2w_order FROM namerules WHERE "
17034520Snw141292 		"w2u_order > 0 AND is_user = %d AND "
17044520Snw141292 		"(winname = %Q OR winname = '*') AND "
17054520Snw141292 		"(windomain = %Q OR windomain = '*' %s) "
17064520Snw141292 		"ORDER BY w2u_order ASC;",
17074864Sbaban 		is_user, winname,
17084864Sbaban 		windomain,
17094864Sbaban 		i?"OR windomain ISNULL OR windomain = ''":"");
17104520Snw141292 	if (sql == NULL) {
17114520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
17124520Snw141292 		retcode = IDMAP_ERR_MEMORY;
17134520Snw141292 		goto out;
17144520Snw141292 	}
17154520Snw141292 
17164520Snw141292 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
17174520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
17184520Snw141292 		idmapdlog(LOG_ERR,
17194520Snw141292 			"%s: database error (%s)",
17204520Snw141292 			me, CHECK_NULL(errmsg));
17214520Snw141292 		sqlite_freemem(errmsg);
17224520Snw141292 		goto out;
17234520Snw141292 	}
17244520Snw141292 
1725*4884Sjp151216 	for (; ; ) {
17264520Snw141292 		r = sqlite_step(vm, &ncol, &values, NULL);
1727*4884Sjp151216 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
1728*4884Sjp151216 
1729*4884Sjp151216 		if (r == SQLITE_ROW) {
17304520Snw141292 			if (ncol < 2) {
17314520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
17324520Snw141292 				goto out;
17334520Snw141292 			}
17344520Snw141292 			if (values[0] == NULL) {
17354520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
17364520Snw141292 				goto out;
17374520Snw141292 			}
17384520Snw141292 
17394520Snw141292 			if (EMPTY_NAME(values[0])) {
17404520Snw141292 				retcode = IDMAP_ERR_NOMAPPING;
17414520Snw141292 				goto out;
17424520Snw141292 			}
17434520Snw141292 			unixname = (values[0][0] == '*')?winname:values[0];
17444520Snw141292 			retcode = ns_lookup_byname(is_user, unixname, res);
17454520Snw141292 			if (retcode == IDMAP_ERR_NOTFOUND) {
17464520Snw141292 				if (unixname == winname)
17474520Snw141292 					/* Case 4 */
17484520Snw141292 					continue;
17494520Snw141292 				else
17504520Snw141292 					/* Case 3 */
17514520Snw141292 					retcode = IDMAP_ERR_NOMAPPING;
17524520Snw141292 			}
17534520Snw141292 			goto out;
17544520Snw141292 		} else if (r == SQLITE_DONE) {
17554520Snw141292 			retcode = IDMAP_ERR_NOTFOUND;
17564520Snw141292 			goto out;
17574520Snw141292 		} else {
17584520Snw141292 			(void) sqlite_finalize(vm, &errmsg);
17594520Snw141292 			vm = NULL;
17604520Snw141292 			idmapdlog(LOG_ERR,
17614520Snw141292 				"%s: database error (%s)",
17624520Snw141292 				me, CHECK_NULL(errmsg));
17634520Snw141292 			sqlite_freemem(errmsg);
17644520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
17654520Snw141292 			goto out;
17664520Snw141292 		}
17674520Snw141292 	}
17684520Snw141292 
17694520Snw141292 out:
17704864Sbaban 	if (sql != NULL)
17714520Snw141292 		sqlite_freemem(sql);
17724520Snw141292 	if (retcode == IDMAP_SUCCESS) {
17734864Sbaban 		if (values[1] != NULL)
17744520Snw141292 			res->direction =
17754644Sbaban 			    (strtol(values[1], &end, 10) == 0)?
17764644Sbaban 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
17774520Snw141292 		else
17784644Sbaban 			res->direction = IDMAP_DIRECTION_W2U;
17794520Snw141292 		str = &req->id2name;
17804520Snw141292 		retcode = idmap_str2utf8(&str, unixname, 0);
17814520Snw141292 	}
17824864Sbaban 	if (vm != NULL)
17834520Snw141292 		(void) sqlite_finalize(vm, NULL);
17844520Snw141292 	return (retcode);
17854520Snw141292 }
17864520Snw141292 
17874520Snw141292 static
17884520Snw141292 int
17894520Snw141292 get_next_eph_uid(uid_t *next_uid)
17904520Snw141292 {
17914520Snw141292 	uid_t uid;
17924520Snw141292 	gid_t gid;
17934520Snw141292 	int err;
17944520Snw141292 
17954520Snw141292 	*next_uid = (uid_t)-1;
17964520Snw141292 	uid = _idmapdstate.next_uid++;
17974520Snw141292 	if (uid >= _idmapdstate.limit_uid) {
17984520Snw141292 		if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0)
17994520Snw141292 			return (err);
18004520Snw141292 
18014520Snw141292 		_idmapdstate.limit_uid = uid + 8192;
18024520Snw141292 		_idmapdstate.next_uid = uid;
18034520Snw141292 	}
18044520Snw141292 	*next_uid = uid;
18054520Snw141292 
18064520Snw141292 	return (0);
18074520Snw141292 }
18084520Snw141292 
18094520Snw141292 static
18104520Snw141292 int
18114520Snw141292 get_next_eph_gid(gid_t *next_gid)
18124520Snw141292 {
18134520Snw141292 	uid_t uid;
18144520Snw141292 	gid_t gid;
18154520Snw141292 	int err;
18164520Snw141292 
18174520Snw141292 	*next_gid = (uid_t)-1;
18184520Snw141292 	gid = _idmapdstate.next_gid++;
18194520Snw141292 	if (gid >= _idmapdstate.limit_gid) {
18204520Snw141292 		if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0)
18214520Snw141292 			return (err);
18224520Snw141292 
18234520Snw141292 		_idmapdstate.limit_gid = gid + 8192;
18244520Snw141292 		_idmapdstate.next_gid = gid;
18254520Snw141292 	}
18264520Snw141292 	*next_gid = gid;
18274520Snw141292 
18284520Snw141292 	return (0);
18294520Snw141292 }
18304520Snw141292 
18314864Sbaban static
18324864Sbaban int
18334864Sbaban gethash(const char *str, uint32_t num, uint_t htsize) {
18344864Sbaban 	uint_t  hval, i, len;
18354864Sbaban 
18364864Sbaban 	if (str == NULL)
18374864Sbaban 		return (0);
18384864Sbaban 	for (len = strlen(str), hval = 0, i = 0; i < len; i++) {
18394864Sbaban 		hval += str[i];
18404864Sbaban 		hval += (hval << 10);
18414864Sbaban 		hval ^= (hval >> 6);
18424864Sbaban 	}
18434864Sbaban 	for (str = (const char *)&num, i = 0; i < sizeof (num); i++) {
18444864Sbaban 		hval += str[i];
18454864Sbaban 		hval += (hval << 10);
18464864Sbaban 		hval ^= (hval >> 6);
18474864Sbaban 	}
18484864Sbaban 	hval += (hval << 3);
18494864Sbaban 	hval ^= (hval >> 11);
18504864Sbaban 	hval += (hval << 15);
18514864Sbaban 	return (hval % htsize);
18524864Sbaban }
18534864Sbaban 
18544864Sbaban static
18554864Sbaban int
18564864Sbaban get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid,
18574864Sbaban 		uid_t *pid) {
18584864Sbaban 	uint_t		next, key;
18594864Sbaban 	uint_t		htsize = state->sid_history_size;
18604864Sbaban 	idmap_sid	*sid;
18614864Sbaban 
18624864Sbaban 	next = gethash(prefix, rid, htsize);
18634864Sbaban 	while (next != htsize) {
18644864Sbaban 		key = state->sid_history[next].key;
18654864Sbaban 		if (key == htsize)
18664864Sbaban 			return (0);
18674864Sbaban 		sid = &state->batch->idmap_mapping_batch_val[key].id1.
18684864Sbaban 		    idmap_id_u.sid;
18694864Sbaban 		if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) {
18704864Sbaban 			*pid = state->result->ids.ids_val[key].id.
18714864Sbaban 			    idmap_id_u.uid;
18724864Sbaban 			return (1);
18734864Sbaban 		}
18744864Sbaban 		next = state->sid_history[next].next;
18754864Sbaban 	}
18764864Sbaban 	return (0);
18774864Sbaban }
18784864Sbaban 
18794864Sbaban static
18804864Sbaban void
18814864Sbaban add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) {
18824864Sbaban 	uint_t		hash, next;
18834864Sbaban 	uint_t		htsize = state->sid_history_size;
18844864Sbaban 
18854864Sbaban 	hash = next = gethash(prefix, rid, htsize);
18864864Sbaban 	while (state->sid_history[next].key != htsize) {
18874864Sbaban 		next++;
18884864Sbaban 		next %= htsize;
18894864Sbaban 	}
18904864Sbaban 	state->sid_history[next].key = state->curpos;
18914864Sbaban 	if (hash == next)
18924864Sbaban 		return;
18934864Sbaban 	state->sid_history[next].next = state->sid_history[hash].next;
18944864Sbaban 	state->sid_history[hash].next = next;
18954864Sbaban }
18964520Snw141292 
18974520Snw141292 /* ARGSUSED */
18984520Snw141292 static
18994520Snw141292 idmap_retcode
19004864Sbaban dynamic_ephemeral_mapping(lookup_state_t *state, sqlite *cache,
19014864Sbaban 		idmap_mapping *req, idmap_id_res *res) {
19024520Snw141292 
19034520Snw141292 	uid_t		next_pid;
19044520Snw141292 
19054864Sbaban 	res->direction = IDMAP_DIRECTION_BI;
19064864Sbaban 
19074864Sbaban 	if (IS_EPHEMERAL(res->id.idmap_id_u.uid))
19084864Sbaban 		return (IDMAP_SUCCESS);
19094864Sbaban 
19104864Sbaban 	if (state->sid_history != NULL &&
19114864Sbaban 	    get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix,
19124864Sbaban 	    req->id1.idmap_id_u.sid.rid, &next_pid)) {
19134864Sbaban 		res->id.idmap_id_u.uid = next_pid;
19144864Sbaban 		return (IDMAP_SUCCESS);
19154864Sbaban 	}
19164864Sbaban 
19174864Sbaban 	if (res->id.idtype == IDMAP_UID) {
19184520Snw141292 		if (get_next_eph_uid(&next_pid) != 0)
19194520Snw141292 			return (IDMAP_ERR_INTERNAL);
19204520Snw141292 		res->id.idmap_id_u.uid = next_pid;
19214520Snw141292 	} else {
19224520Snw141292 		if (get_next_eph_gid(&next_pid) != 0)
19234520Snw141292 			return (IDMAP_ERR_INTERNAL);
19244520Snw141292 		res->id.idmap_id_u.gid = next_pid;
19254520Snw141292 	}
19264520Snw141292 
19274864Sbaban 	if (state->sid_history != NULL)
19284864Sbaban 		add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix,
19294864Sbaban 		    req->id1.idmap_id_u.sid.rid);
19304864Sbaban 
19314520Snw141292 	return (IDMAP_SUCCESS);
19324520Snw141292 }
19334520Snw141292 
19344520Snw141292 idmap_retcode
19354520Snw141292 sid2pid_second_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
19364520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
19374520Snw141292 	idmap_retcode	retcode;
19384520Snw141292 
19394520Snw141292 	/*
19404520Snw141292 	 * The req->direction field is used to maintain state of the
19414520Snw141292 	 * sid2pid request.
19424520Snw141292 	 */
19434520Snw141292 
19444520Snw141292 	/* Check if second pass is needed */
19454520Snw141292 	if (req->direction == _IDMAP_F_DONE)
19464520Snw141292 		return (res->retcode);
19474520Snw141292 
19484520Snw141292 	/* Get status from previous pass */
19494520Snw141292 	retcode = (res->retcode == IDMAP_NEXT)?IDMAP_SUCCESS:res->retcode;
19504520Snw141292 
19514520Snw141292 	if (retcode != IDMAP_SUCCESS) {
19524520Snw141292 		/* Reset return type */
19534520Snw141292 		res->id.idtype = req->id2.idtype;
19544520Snw141292 		res->id.idmap_id_u.uid = UID_NOBODY;
19554520Snw141292 
19564520Snw141292 		/* Check if this is a localsid */
19574520Snw141292 		if (retcode == IDMAP_ERR_NOTFOUND &&
19584864Sbaban 		    _idmapdstate.cfg->pgcfg.machine_sid) {
19594520Snw141292 			retcode = lookup_localsid2pid(req, res);
19604520Snw141292 			if (retcode == IDMAP_SUCCESS) {
19614520Snw141292 				state->sid2pid_done = FALSE;
19624520Snw141292 				req->direction = _IDMAP_F_S2N_CACHE;
19634520Snw141292 			}
19644520Snw141292 		}
19654520Snw141292 		goto out;
19664520Snw141292 	}
19674520Snw141292 
19684520Snw141292 	/*
19694520Snw141292 	 * Verify that the sid type matches the request if the
19704520Snw141292 	 * SID was validated by an AD lookup.
19714520Snw141292 	 */
19724520Snw141292 	if (req->direction & _IDMAP_F_S2N_AD) {
19734520Snw141292 		retcode = verify_type(req->id2.idtype,
19744520Snw141292 			(int)res->id.idtype, res);
19754520Snw141292 		if (retcode != IDMAP_SUCCESS) {
19764520Snw141292 			res->id.idtype = req->id2.idtype;
19774520Snw141292 			res->id.idmap_id_u.uid = UID_NOBODY;
19784520Snw141292 			goto out;
19794520Snw141292 		}
19804520Snw141292 	}
19814520Snw141292 
19824520Snw141292 	/* Name-based mapping */
19834520Snw141292 	retcode = name_based_mapping_sid2pid(db, req, res);
19844520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND)
19854520Snw141292 		/* If not found, do ephemeral mapping */
19864520Snw141292 		goto ephemeral;
19874520Snw141292 	else if (retcode != IDMAP_SUCCESS)
19884520Snw141292 		goto out;
19894520Snw141292 
19904520Snw141292 	state->sid2pid_done = FALSE;
19914520Snw141292 	goto out;
19924520Snw141292 
19934520Snw141292 
19944520Snw141292 ephemeral:
19954864Sbaban 	retcode = dynamic_ephemeral_mapping(state, cache, req, res);
19964520Snw141292 	if (retcode == IDMAP_SUCCESS)
19974520Snw141292 		state->sid2pid_done = FALSE;
19984520Snw141292 
19994520Snw141292 out:
20004520Snw141292 	res->retcode = idmap_stat4prot(retcode);
20014520Snw141292 	return (retcode);
20024520Snw141292 }
20034520Snw141292 
20044520Snw141292 idmap_retcode
20054520Snw141292 update_cache_pid2sid(lookup_state_t *state, sqlite *cache,
20064520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
20074520Snw141292 	char		*sql = NULL;
20084520Snw141292 	idmap_retcode	retcode;
20094520Snw141292 
20104520Snw141292 	/* Check if we need to cache anything */
20114520Snw141292 	if (req->direction == _IDMAP_F_DONE)
20124520Snw141292 		return (IDMAP_SUCCESS);
20134520Snw141292 
20144520Snw141292 	/* We don't cache negative entries */
20154520Snw141292 	if (res->retcode != IDMAP_SUCCESS)
20164520Snw141292 		return (IDMAP_SUCCESS);
20174520Snw141292 
20184520Snw141292 	/*
20194520Snw141292 	 * Using NULL for u2w instead of 0 so that our trigger allows
20204520Snw141292 	 * the same pid to be the destination in multiple entries
20214520Snw141292 	 */
20224520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
20234520Snw141292 		"(sidprefix, rid, windomain, winname, pid, unixname, "
20244520Snw141292 		"is_user, expiration, w2u, u2w) "
20254520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
20264520Snw141292 		"strftime('%%s','now') + 600, %q, 1); ",
20274520Snw141292 		res->id.idmap_id_u.sid.prefix,
20284520Snw141292 		res->id.idmap_id_u.sid.rid,
20294520Snw141292 		req->id2domain.idmap_utf8str_val,
20304520Snw141292 		req->id2name.idmap_utf8str_val,
20314520Snw141292 		req->id1.idmap_id_u.uid,
20324520Snw141292 		req->id1name.idmap_utf8str_val,
20334520Snw141292 		(req->id1.idtype == IDMAP_UID)?1:0,
20344520Snw141292 		(res->direction == 0)?"1":NULL);
20354520Snw141292 
20364520Snw141292 	if (sql == NULL) {
20374520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
20384520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
20394520Snw141292 		goto out;
20404520Snw141292 	}
20414520Snw141292 
20424520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
20434520Snw141292 	if (retcode != IDMAP_SUCCESS)
20444520Snw141292 		goto out;
20454520Snw141292 
20464520Snw141292 	state->pid2sid_done = FALSE;
20474520Snw141292 	sqlite_freemem(sql);
20484520Snw141292 	sql = NULL;
20494520Snw141292 
20504520Snw141292 	/* If sid2name was found in the cache, no need to update namecache */
20514520Snw141292 	if (req->direction & _IDMAP_F_S2N_CACHE)
20524520Snw141292 		goto out;
20534520Snw141292 
20544520Snw141292 	if (req->id2name.idmap_utf8str_val == NULL)
20554520Snw141292 		goto out;
20564520Snw141292 
20574520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
20584520Snw141292 		"(sidprefix, rid, name, domain, type, expiration) "
20594520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
20604520Snw141292 		res->id.idmap_id_u.sid.prefix,
20614520Snw141292 		res->id.idmap_id_u.sid.rid,
20624520Snw141292 		req->id2name.idmap_utf8str_val,
20634520Snw141292 		req->id2domain.idmap_utf8str_val,
20644520Snw141292 		(req->id1.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
20654520Snw141292 
20664520Snw141292 	if (sql == NULL) {
20674520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
20684520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
20694520Snw141292 		goto out;
20704520Snw141292 	}
20714520Snw141292 
20724520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
20734520Snw141292 
20744520Snw141292 out:
20754864Sbaban 	if (sql != NULL)
20764520Snw141292 		sqlite_freemem(sql);
20774520Snw141292 	return (retcode);
20784520Snw141292 }
20794520Snw141292 
20804520Snw141292 idmap_retcode
20814520Snw141292 update_cache_sid2pid(lookup_state_t *state, sqlite *cache,
20824520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
20834520Snw141292 	char		*sql = NULL;
20844520Snw141292 	idmap_retcode	retcode;
20854520Snw141292 	int		is_eph_user;
20864520Snw141292 
20874520Snw141292 	/* Check if we need to cache anything */
20884520Snw141292 	if (req->direction == _IDMAP_F_DONE)
20894520Snw141292 		return (IDMAP_SUCCESS);
20904520Snw141292 
20914520Snw141292 	/* We don't cache negative entries */
20924520Snw141292 	if (res->retcode != IDMAP_SUCCESS)
20934520Snw141292 		return (IDMAP_SUCCESS);
20944520Snw141292 
20954520Snw141292 	if (req->direction & _IDMAP_F_EXP_EPH_UID)
20964520Snw141292 		is_eph_user = 1;
20974520Snw141292 	else if (req->direction & _IDMAP_F_EXP_EPH_GID)
20984520Snw141292 		is_eph_user = 0;
20994520Snw141292 	else
21004520Snw141292 		is_eph_user = -1;
21014520Snw141292 
21024520Snw141292 	if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
21034520Snw141292 		sql = sqlite_mprintf("UPDATE idmap_cache "
21044520Snw141292 			"SET w2u = 0 WHERE "
21054520Snw141292 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
21064520Snw141292 			"pid >= 2147483648 AND is_user = %d;",
21074520Snw141292 			req->id1.idmap_id_u.sid.prefix,
21084520Snw141292 			req->id1.idmap_id_u.sid.rid,
21094520Snw141292 			is_eph_user);
21104520Snw141292 		if (sql == NULL) {
21114520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
21124520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
21134520Snw141292 			goto out;
21144520Snw141292 		}
21154520Snw141292 
21164520Snw141292 		retcode = sql_exec_no_cb(cache, sql);
21174520Snw141292 		if (retcode != IDMAP_SUCCESS)
21184520Snw141292 			goto out;
21194520Snw141292 
21204520Snw141292 		sqlite_freemem(sql);
21214520Snw141292 		sql = NULL;
21224520Snw141292 	}
21234520Snw141292 
21244520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
21254520Snw141292 		"(sidprefix, rid, windomain, winname, pid, unixname, "
21264520Snw141292 		"is_user, expiration, w2u, u2w) "
21274520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
21284520Snw141292 		"strftime('%%s','now') + 600, 1, %q); ",
21294520Snw141292 		req->id1.idmap_id_u.sid.prefix,
21304520Snw141292 		req->id1.idmap_id_u.sid.rid,
21314520Snw141292 		req->id1domain.idmap_utf8str_val,
21324520Snw141292 		req->id1name.idmap_utf8str_val,
21334520Snw141292 		res->id.idmap_id_u.uid,
21344520Snw141292 		req->id2name.idmap_utf8str_val,
21354520Snw141292 		(res->id.idtype == IDMAP_UID)?1:0,
21364520Snw141292 		(res->direction == 0)?"1":NULL);
21374520Snw141292 
21384520Snw141292 	if (sql == NULL) {
21394520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
21404520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
21414520Snw141292 		goto out;
21424520Snw141292 	}
21434520Snw141292 
21444520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
21454520Snw141292 	if (retcode != IDMAP_SUCCESS)
21464520Snw141292 		goto out;
21474520Snw141292 
21484520Snw141292 	state->sid2pid_done = FALSE;
21494520Snw141292 	sqlite_freemem(sql);
21504520Snw141292 	sql = NULL;
21514520Snw141292 
21524520Snw141292 	/* If name2sid was found in the cache, no need to update namecache */
21534520Snw141292 	if (req->direction & _IDMAP_F_S2N_CACHE)
21544520Snw141292 		goto out;
21554520Snw141292 
21564520Snw141292 	if (req->id1name.idmap_utf8str_val == NULL)
21574520Snw141292 		goto out;
21584520Snw141292 
21594520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
21604520Snw141292 		"(sidprefix, rid, name, domain, type, expiration) "
21614520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
21624520Snw141292 		req->id1.idmap_id_u.sid.prefix,
21634520Snw141292 		req->id1.idmap_id_u.sid.rid,
21644520Snw141292 		req->id1name.idmap_utf8str_val,
21654520Snw141292 		req->id1domain.idmap_utf8str_val,
21664520Snw141292 		(res->id.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
21674520Snw141292 
21684520Snw141292 	if (sql == NULL) {
21694520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
21704520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
21714520Snw141292 		goto out;
21724520Snw141292 	}
21734520Snw141292 
21744520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
21754520Snw141292 
21764520Snw141292 out:
21774864Sbaban 	if (sql != NULL)
21784520Snw141292 		sqlite_freemem(sql);
21794520Snw141292 	return (retcode);
21804520Snw141292 }
21814520Snw141292 
21824520Snw141292 static idmap_retcode
21834520Snw141292 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
21844520Snw141292 		int is_user, int getname) {
21854520Snw141292 	char		*end;
21864520Snw141292 	char		*sql = NULL;
21874520Snw141292 	const char	**values;
21884520Snw141292 	sqlite_vm	*vm = NULL;
21894520Snw141292 	int		ncol;
21904520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
21914520Snw141292 	idmap_utf8str	*str;
21924520Snw141292 	time_t		curtime;
21934520Snw141292 
21944520Snw141292 	/* Current time */
21954520Snw141292 	errno = 0;
21964520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
21974520Snw141292 		idmapdlog(LOG_ERR,
21984520Snw141292 			"Failed to get current time (%s)",
21994520Snw141292 			strerror(errno));
22004520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
22014520Snw141292 		goto out;
22024520Snw141292 	}
22034520Snw141292 
22044520Snw141292 	/* SQL to lookup the cache */
22054520Snw141292 	sql = sqlite_mprintf("SELECT sidprefix, rid, winname, windomain, w2u "
22064520Snw141292 			"FROM idmap_cache WHERE "
22074520Snw141292 			"pid = %u AND u2w = 1 AND is_user = %d AND "
22084520Snw141292 			"(pid >= 2147483648 OR "
22094520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
22104520Snw141292 			"expiration > %d));",
22114520Snw141292 			req->id1.idmap_id_u.uid, is_user, curtime);
22124520Snw141292 	if (sql == NULL) {
22134520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
22144520Snw141292 		retcode = IDMAP_ERR_MEMORY;
22154520Snw141292 		goto out;
22164520Snw141292 	}
22174520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
22184520Snw141292 	sqlite_freemem(sql);
22194520Snw141292 
22204520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND)
22214520Snw141292 		goto out;
22224520Snw141292 	else if (retcode == IDMAP_SUCCESS) {
22234520Snw141292 		/* sanity checks */
22244520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
22254520Snw141292 			retcode = IDMAP_ERR_CACHE;
22264520Snw141292 			goto out;
22274520Snw141292 		}
22284520Snw141292 
22294520Snw141292 		switch (req->id2.idtype) {
22304520Snw141292 		case IDMAP_SID:
22314520Snw141292 			res->id.idmap_id_u.sid.rid =
22324520Snw141292 				strtoul(values[1], &end, 10);
22334520Snw141292 			res->id.idmap_id_u.sid.prefix = strdup(values[0]);
22344520Snw141292 			if (res->id.idmap_id_u.sid.prefix == NULL) {
22354520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22364520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22374520Snw141292 				goto out;
22384520Snw141292 			}
22394520Snw141292 
22404864Sbaban 			if (values[4] != NULL)
22414520Snw141292 				res->direction =
22424644Sbaban 				    (strtol(values[4], &end, 10) == 0)?
22434644Sbaban 				    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
22444520Snw141292 			else
22454644Sbaban 				res->direction = IDMAP_DIRECTION_U2W;
22464520Snw141292 
22474520Snw141292 			if (getname == 0 || values[2] == NULL)
22484520Snw141292 				break;
22494520Snw141292 			str = &req->id2name;
22504520Snw141292 			retcode = idmap_str2utf8(&str, values[2], 0);
22514520Snw141292 			if (retcode != IDMAP_SUCCESS) {
22524520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22534520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22544520Snw141292 				goto out;
22554520Snw141292 			}
22564520Snw141292 
22574520Snw141292 			if (values[3] == NULL)
22584520Snw141292 				break;
22594520Snw141292 			str = &req->id2domain;
22604520Snw141292 			retcode = idmap_str2utf8(&str, values[3], 0);
22614520Snw141292 			if (retcode != IDMAP_SUCCESS) {
22624520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22634520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22644520Snw141292 				goto out;
22654520Snw141292 			}
22664520Snw141292 			break;
22674520Snw141292 		default:
22684520Snw141292 			retcode = IDMAP_ERR_NOTSUPPORTED;
22694520Snw141292 			break;
22704520Snw141292 		}
22714520Snw141292 	}
22724520Snw141292 
22734520Snw141292 out:
22744864Sbaban 	if (vm != NULL)
22754520Snw141292 		(void) sqlite_finalize(vm, NULL);
22764520Snw141292 	return (retcode);
22774520Snw141292 }
22784520Snw141292 
22794520Snw141292 static idmap_retcode
22804520Snw141292 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain,
22814520Snw141292 		char **sidprefix, idmap_rid_t *rid, int *type) {
22824520Snw141292 	char		*end;
22834520Snw141292 	char		*sql = NULL;
22844520Snw141292 	const char	**values;
22854520Snw141292 	sqlite_vm	*vm = NULL;
22864520Snw141292 	int		ncol;
22874520Snw141292 	time_t		curtime;
22884520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
22894520Snw141292 
22904520Snw141292 	/* Get current time */
22914520Snw141292 	errno = 0;
22924520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
22934520Snw141292 		idmapdlog(LOG_ERR,
22944520Snw141292 			"Failed to get current time (%s)",
22954520Snw141292 			strerror(errno));
22964520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
22974520Snw141292 		goto out;
22984520Snw141292 	}
22994520Snw141292 
23004520Snw141292 	/* SQL to lookup the cache */
23014520Snw141292 	sql = sqlite_mprintf("SELECT sidprefix, rid, type FROM name_cache "
23024520Snw141292 			"WHERE name = %Q AND domain = %Q AND "
23034520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
23044520Snw141292 			"expiration > %d);",
23054520Snw141292 			name, domain, curtime);
23064520Snw141292 	if (sql == NULL) {
23074520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
23084520Snw141292 		retcode = IDMAP_ERR_MEMORY;
23094520Snw141292 		goto out;
23104520Snw141292 	}
23114520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
23124520Snw141292 	sqlite_freemem(sql);
23134520Snw141292 
23144520Snw141292 	if (retcode == IDMAP_SUCCESS) {
23154864Sbaban 		if (type != NULL) {
23164520Snw141292 			if (values[2] == NULL) {
23174520Snw141292 				retcode = IDMAP_ERR_CACHE;
23184520Snw141292 				goto out;
23194520Snw141292 			}
23204520Snw141292 			*type = strtol(values[2], &end, 10);
23214520Snw141292 		}
23224520Snw141292 
23234520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
23244520Snw141292 			retcode = IDMAP_ERR_CACHE;
23254520Snw141292 			goto out;
23264520Snw141292 		}
23274520Snw141292 		if ((*sidprefix = strdup(values[0])) == NULL) {
23284520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
23294520Snw141292 			retcode = IDMAP_ERR_MEMORY;
23304520Snw141292 			goto out;
23314520Snw141292 		}
23324520Snw141292 		*rid = strtoul(values[1], &end, 10);
23334520Snw141292 	}
23344520Snw141292 
23354520Snw141292 out:
23364864Sbaban 	if (vm != NULL)
23374520Snw141292 		(void) sqlite_finalize(vm, NULL);
23384520Snw141292 	return (retcode);
23394520Snw141292 }
23404520Snw141292 
23414520Snw141292 static idmap_retcode
23424520Snw141292 lookup_win_name2sid(const char *name, const char *domain, char **sidprefix,
23434520Snw141292 		idmap_rid_t *rid, int *type) {
23444520Snw141292 	int			ret;
23454520Snw141292 	int			retries = 0;
23464520Snw141292 	idmap_query_state_t	*qs = NULL;
23474520Snw141292 	idmap_retcode		rc, retcode;
23484520Snw141292 
23494520Snw141292 	retcode = IDMAP_ERR_NOTFOUND;
23504520Snw141292 
23514520Snw141292 retry:
23524520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
23534520Snw141292 	if (ret != 0) {
23544520Snw141292 		idmapdlog(LOG_ERR,
23554520Snw141292 		"Failed to create name2sid batch for AD lookup");
23564520Snw141292 		return (IDMAP_ERR_INTERNAL);
23574520Snw141292 	}
23584520Snw141292 
23594520Snw141292 	retcode = idmap_name2sid_batch_add1(qs, name, domain, sidprefix,
23604520Snw141292 					rid, type, &rc);
23614520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
23624520Snw141292 		goto out;
23634520Snw141292 
23644520Snw141292 	if (retcode != IDMAP_SUCCESS) {
23654520Snw141292 		idmapdlog(LOG_ERR,
23664520Snw141292 		"Failed to batch name2sid for AD lookup");
2367*4884Sjp151216 		idmap_lookup_release_batch(&qs);
23684520Snw141292 		return (IDMAP_ERR_INTERNAL);
23694520Snw141292 	}
23704520Snw141292 
23714520Snw141292 out:
23724520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
2373*4884Sjp151216 		idmap_lookup_release_batch(&qs);
23744520Snw141292 	else
23754520Snw141292 		retcode = idmap_lookup_batch_end(&qs, NULL);
23764520Snw141292 
23774520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
23784520Snw141292 		goto retry;
23794520Snw141292 
23804520Snw141292 	if (retcode != IDMAP_SUCCESS) {
23814520Snw141292 		idmapdlog(LOG_NOTICE, "Windows user/group name to SID lookup "
23824520Snw141292 		    "failed");
23834520Snw141292 		return (retcode);
23844520Snw141292 	} else
23854520Snw141292 		return (rc);
23864520Snw141292 	/* NOTREACHED */
23874520Snw141292 }
23884520Snw141292 
23894520Snw141292 static idmap_retcode
23904520Snw141292 lookup_name2sid(sqlite *cache, const char *name, const char *domain,
23914520Snw141292 		int *is_user, char **sidprefix, idmap_rid_t *rid,
23924520Snw141292 		idmap_mapping *req) {
23934520Snw141292 	int		type;
23944520Snw141292 	idmap_retcode	retcode;
23954520Snw141292 
23964864Sbaban 	/* Lookup name@domain to sid in the well-known sids table */
23974864Sbaban 	retcode = lookup_wksids_name2sid(name, sidprefix, rid, &type);
23984864Sbaban 	if (retcode == IDMAP_SUCCESS) {
23994864Sbaban 		req->direction |= _IDMAP_F_S2N_CACHE;
24004864Sbaban 		goto out;
24014864Sbaban 	} else if (retcode != IDMAP_ERR_NOTFOUND) {
24024864Sbaban 		return (retcode);
24034864Sbaban 	}
24044864Sbaban 
24054864Sbaban 	/* Lookup name@domain to sid in cache */
24064520Snw141292 	retcode = lookup_cache_name2sid(cache, name, domain, sidprefix,
24074520Snw141292 		rid, &type);
24084520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
24094520Snw141292 		/* Lookup Windows NT/AD to map name@domain to sid */
24104520Snw141292 		retcode = lookup_win_name2sid(name, domain, sidprefix, rid,
24114520Snw141292 			&type);
24124520Snw141292 		if (retcode != IDMAP_SUCCESS)
24134520Snw141292 			return (retcode);
24144520Snw141292 		req->direction |= _IDMAP_F_S2N_AD;
24154520Snw141292 	} else if (retcode != IDMAP_SUCCESS) {
24164520Snw141292 		return (retcode);
24174520Snw141292 	} else {
24184520Snw141292 		/* Set flag */
24194520Snw141292 		req->direction |= _IDMAP_F_S2N_CACHE;
24204520Snw141292 	}
24214520Snw141292 
24224864Sbaban out:
24234520Snw141292 	/*
24244520Snw141292 	 * Entry found (cache or Windows lookup)
24254520Snw141292 	 * is_user is both input as well as output parameter
24264520Snw141292 	 */
24274520Snw141292 	if (*is_user == 1) {
24284520Snw141292 		if (type != _IDMAP_T_USER)
24294520Snw141292 			return (IDMAP_ERR_NOTUSER);
24304520Snw141292 	} else if (*is_user == 0) {
24314520Snw141292 		if (type != _IDMAP_T_GROUP)
24324520Snw141292 			return (IDMAP_ERR_NOTGROUP);
24334520Snw141292 	} else if (*is_user == -1) {
24344520Snw141292 		/* Caller wants to know if its user or group */
24354520Snw141292 		if (type == _IDMAP_T_USER)
24364520Snw141292 			*is_user = 1;
24374520Snw141292 		else if (type == _IDMAP_T_GROUP)
24384520Snw141292 			*is_user = 0;
24394520Snw141292 		else
24404520Snw141292 			return (IDMAP_ERR_SID);
24414520Snw141292 	}
24424520Snw141292 
24434520Snw141292 	return (retcode);
24444520Snw141292 }
24454520Snw141292 
24464520Snw141292 static idmap_retcode
24474520Snw141292 name_based_mapping_pid2sid(sqlite *db, sqlite *cache, const char *unixname,
24484520Snw141292 		int is_user, idmap_mapping *req, idmap_id_res *res) {
24494520Snw141292 	const char	*winname, *windomain;
24504520Snw141292 	char		*mapping_domain = NULL;
24514520Snw141292 	char		*sql = NULL, *errmsg = NULL;
24524520Snw141292 	idmap_retcode	retcode;
24534520Snw141292 	char		*end;
24544520Snw141292 	const char	**values;
24554520Snw141292 	sqlite_vm	*vm = NULL;
24564520Snw141292 	idmap_utf8str	*str;
2457*4884Sjp151216 	int		ncol, r;
24584520Snw141292 	const char	*me = "name_based_mapping_pid2sid";
24594520Snw141292 
24604520Snw141292 	RDLOCK_CONFIG();
24614864Sbaban 	if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
24624520Snw141292 		mapping_domain =
24634520Snw141292 			strdup(_idmapdstate.cfg->pgcfg.mapping_domain);
24644520Snw141292 		if (mapping_domain == NULL) {
24654520Snw141292 			UNLOCK_CONFIG();
24664520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
24674520Snw141292 			retcode = IDMAP_ERR_MEMORY;
24684520Snw141292 			goto out;
24694520Snw141292 		}
24704520Snw141292 	}
24714520Snw141292 	UNLOCK_CONFIG();
24724520Snw141292 
24734520Snw141292 	sql = sqlite_mprintf(
24744520Snw141292 		"SELECT winname, windomain, w2u_order FROM namerules WHERE "
24754520Snw141292 		"u2w_order > 0 AND is_user = %d AND "
24764520Snw141292 		"(unixname = %Q OR unixname = '*') "
24774520Snw141292 		"ORDER BY u2w_order ASC;",
24784520Snw141292 		is_user, unixname);
24794520Snw141292 	if (sql == NULL) {
24804520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
24814520Snw141292 		retcode = IDMAP_ERR_MEMORY;
24824520Snw141292 		goto out;
24834520Snw141292 	}
24844520Snw141292 
24854520Snw141292 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
24864520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
24874520Snw141292 		idmapdlog(LOG_ERR,
24884520Snw141292 			"%s: database error (%s)",
24894520Snw141292 			me, CHECK_NULL(errmsg));
24904520Snw141292 		sqlite_freemem(errmsg);
24914520Snw141292 		goto out;
24924520Snw141292 	}
24934520Snw141292 
2494*4884Sjp151216 	for (;;) {
24954520Snw141292 		r = sqlite_step(vm, &ncol, &values, NULL);
2496*4884Sjp151216 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
2497*4884Sjp151216 		if (r == SQLITE_ROW) {
24984520Snw141292 			if (ncol < 3) {
24994520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
25004520Snw141292 				goto out;
25014520Snw141292 			}
25024520Snw141292 			if (values[0] == NULL) {
25034520Snw141292 				/* values [1] and [2] can be null */
25044520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
25054520Snw141292 				goto out;
25064520Snw141292 			}
25074520Snw141292 			if (EMPTY_NAME(values[0])) {
25084520Snw141292 				retcode = IDMAP_ERR_NOMAPPING;
25094520Snw141292 				goto out;
25104520Snw141292 			}
25114520Snw141292 			winname = (values[0][0] == '*')?unixname:values[0];
25124864Sbaban 			if (values[1] != NULL)
25134520Snw141292 				windomain = values[1];
25144864Sbaban 			else if (mapping_domain != NULL)
25154520Snw141292 				windomain = mapping_domain;
25164520Snw141292 			else {
25174520Snw141292 				idmapdlog(LOG_ERR,
25184520Snw141292 					"%s: no domain", me);
25194520Snw141292 				retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
25204520Snw141292 				goto out;
25214520Snw141292 			}
25224520Snw141292 			/* Lookup winname@domain to sid */
25234520Snw141292 			retcode = lookup_name2sid(cache, winname, windomain,
25244520Snw141292 				&is_user, &res->id.idmap_id_u.sid.prefix,
25254520Snw141292 				&res->id.idmap_id_u.sid.rid, req);
25264520Snw141292 			if (retcode == IDMAP_ERR_NOTFOUND) {
25274520Snw141292 				if (winname == unixname)
25284520Snw141292 					continue;
25294520Snw141292 				else
25304520Snw141292 					retcode = IDMAP_ERR_NOMAPPING;
25314520Snw141292 			}
25324520Snw141292 			goto out;
25334520Snw141292 		} else if (r == SQLITE_DONE) {
25344520Snw141292 			retcode = IDMAP_ERR_NOTFOUND;
25354520Snw141292 			goto out;
25364520Snw141292 		} else {
25374520Snw141292 			(void) sqlite_finalize(vm, &errmsg);
25384520Snw141292 			vm = NULL;
25394520Snw141292 			idmapdlog(LOG_ERR,
25404520Snw141292 				"%s: database error (%s)",
25414520Snw141292 				me, CHECK_NULL(errmsg));
25424520Snw141292 			sqlite_freemem(errmsg);
25434520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
25444520Snw141292 			goto out;
25454520Snw141292 		}
25464520Snw141292 	}
25474520Snw141292 
25484520Snw141292 out:
25494864Sbaban 	if (sql != NULL)
25504520Snw141292 		sqlite_freemem(sql);
25514520Snw141292 	if (retcode == IDMAP_SUCCESS) {
25524864Sbaban 		if (values[2] != NULL)
25534520Snw141292 			res->direction =
25544644Sbaban 			    (strtol(values[2], &end, 10) == 0)?
25554644Sbaban 			    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
25564520Snw141292 		else
25574644Sbaban 			res->direction = IDMAP_DIRECTION_U2W;
25584520Snw141292 		str = &req->id2name;
25594520Snw141292 		retcode = idmap_str2utf8(&str, winname, 0);
25604520Snw141292 		if (retcode == IDMAP_SUCCESS) {
25614520Snw141292 			str = &req->id2domain;
25624520Snw141292 			if (windomain == mapping_domain) {
25634520Snw141292 				(void) idmap_str2utf8(&str, windomain, 1);
25644520Snw141292 				mapping_domain = NULL;
25654520Snw141292 			} else
25664520Snw141292 				retcode = idmap_str2utf8(&str, windomain, 0);
25674520Snw141292 		}
25684520Snw141292 	}
25694864Sbaban 	if (vm != NULL)
25704520Snw141292 		(void) sqlite_finalize(vm, NULL);
25714864Sbaban 	if (mapping_domain != NULL)
25724520Snw141292 		free(mapping_domain);
25734520Snw141292 	return (retcode);
25744520Snw141292 }
25754520Snw141292 
25764520Snw141292 idmap_retcode
25774520Snw141292 pid2sid_first_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
25784520Snw141292 		idmap_mapping *req, idmap_id_res *res, int is_user,
25794520Snw141292 		int getname) {
25804520Snw141292 	char		*unixname = NULL;
25814520Snw141292 	struct passwd	pwd;
25824520Snw141292 	struct group	grp;
25834520Snw141292 	idmap_utf8str	*str;
25844520Snw141292 	char		buf[1024];
25854520Snw141292 	int		errnum;
25864520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
25874520Snw141292 	const char	*me = "pid2sid";
25884520Snw141292 
25894520Snw141292 	req->direction = _IDMAP_F_DONE;
25904520Snw141292 	res->id.idtype = req->id2.idtype;
25914520Snw141292 
25924520Snw141292 	/* Lookup well-known SIDs */
25934520Snw141292 	retcode = lookup_wksids_pid2sid(req, res, is_user);
25944520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
25954520Snw141292 		goto out;
25964520Snw141292 
25974520Snw141292 	/* Lookup pid to sid in cache */
25984520Snw141292 	retcode = lookup_cache_pid2sid(cache, req, res, is_user, getname);
25994520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
26004520Snw141292 		goto out;
26014520Snw141292 
26024520Snw141292 	/* Ephemeral ids cannot be allocated during pid2sid */
26034520Snw141292 	if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) {
26044864Sbaban 		retcode = IDMAP_ERR_NOMAPPING;
26054520Snw141292 		goto out;
26064520Snw141292 	}
26074520Snw141292 
26084520Snw141292 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
26094864Sbaban 		retcode = IDMAP_ERR_NOMAPPING;
26104520Snw141292 		goto out;
26114520Snw141292 	}
26124520Snw141292 
26134520Snw141292 	/* uid/gid to name */
26144864Sbaban 	if (req->id1name.idmap_utf8str_val != NULL) {
26154520Snw141292 		unixname = req->id1name.idmap_utf8str_val;
26164520Snw141292 	} if (is_user) {
26174520Snw141292 		errno = 0;
26184520Snw141292 		if (getpwuid_r(req->id1.idmap_id_u.uid, &pwd, buf,
26194520Snw141292 				sizeof (buf)) == NULL) {
26204520Snw141292 			errnum = errno;
26214520Snw141292 			idmapdlog(LOG_WARNING,
26224520Snw141292 			"%s: getpwuid_r(%u) failed (%s).",
26234520Snw141292 				me, req->id1.idmap_id_u.uid,
26244520Snw141292 				errnum?strerror(errnum):"not found");
26254520Snw141292 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
26264520Snw141292 					IDMAP_ERR_INTERNAL;
26274520Snw141292 			goto fallback_localsid;
26284520Snw141292 		}
26294520Snw141292 		unixname = pwd.pw_name;
26304520Snw141292 	} else {
26314520Snw141292 		errno = 0;
26324520Snw141292 		if (getgrgid_r(req->id1.idmap_id_u.gid, &grp, buf,
26334520Snw141292 				sizeof (buf)) == NULL) {
26344520Snw141292 			errnum = errno;
26354520Snw141292 			idmapdlog(LOG_WARNING,
26364520Snw141292 			"%s: getgrgid_r(%u) failed (%s).",
26374520Snw141292 				me, req->id1.idmap_id_u.gid,
26384520Snw141292 				errnum?strerror(errnum):"not found");
26394520Snw141292 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
26404520Snw141292 					IDMAP_ERR_INTERNAL;
26414520Snw141292 			goto fallback_localsid;
26424520Snw141292 		}
26434520Snw141292 		unixname = grp.gr_name;
26444520Snw141292 	}
26454520Snw141292 
26464520Snw141292 	/* Name-based mapping */
26474520Snw141292 	retcode = name_based_mapping_pid2sid(db, cache, unixname, is_user,
26484520Snw141292 		req, res);
26494520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
26504520Snw141292 		retcode = generate_localsid(req, res, is_user);
26514520Snw141292 		goto out;
26524520Snw141292 	} else if (retcode == IDMAP_SUCCESS)
26534520Snw141292 		goto out;
26544520Snw141292 
26554520Snw141292 fallback_localsid:
26564520Snw141292 	/*
26574520Snw141292 	 * Here we generate localsid as fallback id on errors. Our
26584520Snw141292 	 * return status is the error that's been previously assigned.
26594520Snw141292 	 */
26604520Snw141292 	(void) generate_localsid(req, res, is_user);
26614520Snw141292 
26624520Snw141292 out:
26634520Snw141292 	if (retcode == IDMAP_SUCCESS) {
26644864Sbaban 		if (req->id1name.idmap_utf8str_val == NULL &&
26654864Sbaban 		    unixname != NULL) {
26664520Snw141292 			str = &req->id1name;
26674520Snw141292 			retcode = idmap_str2utf8(&str, unixname, 0);
26684520Snw141292 		}
26694520Snw141292 	}
26704520Snw141292 	if (req->direction != _IDMAP_F_DONE)
26714520Snw141292 		state->pid2sid_done = FALSE;
26724520Snw141292 	res->retcode = idmap_stat4prot(retcode);
26734520Snw141292 	return (retcode);
26744520Snw141292 }
26754520Snw141292 
26764520Snw141292 static idmap_retcode
26774520Snw141292 lookup_win_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
26784520Snw141292 		char **domain, int *type) {
26794520Snw141292 	int			ret;
26804520Snw141292 	idmap_query_state_t	*qs = NULL;
26814520Snw141292 	idmap_retcode		rc, retcode;
26824520Snw141292 
26834520Snw141292 	retcode = IDMAP_ERR_NOTFOUND;
26844520Snw141292 
26854520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
26864520Snw141292 	if (ret != 0) {
26874520Snw141292 		idmapdlog(LOG_ERR,
26884520Snw141292 		"Failed to create sid2name batch for AD lookup");
26894520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
26904520Snw141292 		goto out;
26914520Snw141292 	}
26924520Snw141292 
26934520Snw141292 	ret = idmap_sid2name_batch_add1(
26944520Snw141292 			qs, sidprefix, &rid, name, domain, type, &rc);
26954520Snw141292 	if (ret != 0) {
26964520Snw141292 		idmapdlog(LOG_ERR,
26974520Snw141292 		"Failed to batch sid2name for AD lookup");
26984520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
26994520Snw141292 		goto out;
27004520Snw141292 	}
27014520Snw141292 
27024520Snw141292 out:
27034864Sbaban 	if (qs != NULL) {
27044520Snw141292 		ret = idmap_lookup_batch_end(&qs, NULL);
27054520Snw141292 		if (ret != 0) {
27064520Snw141292 			idmapdlog(LOG_ERR,
27074520Snw141292 			"Failed to execute sid2name AD lookup");
27084520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
27094520Snw141292 		} else
27104520Snw141292 			retcode = rc;
27114520Snw141292 	}
27124520Snw141292 
27134520Snw141292 	return (retcode);
27144520Snw141292 }
27154520Snw141292 
27164644Sbaban static int
27174644Sbaban copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request)
27184520Snw141292 {
27194644Sbaban 	(void) memset(mapping, 0, sizeof (*mapping));
27204644Sbaban 
27214520Snw141292 	mapping->flag = request->flag;
27224520Snw141292 	mapping->direction = request->direction;
27234644Sbaban 	mapping->id2.idtype = request->id2.idtype;
27244520Snw141292 
27254520Snw141292 	mapping->id1.idtype = request->id1.idtype;
27264520Snw141292 	if (request->id1.idtype == IDMAP_SID) {
27274520Snw141292 		mapping->id1.idmap_id_u.sid.rid =
27284520Snw141292 		    request->id1.idmap_id_u.sid.rid;
27294644Sbaban 		if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) {
27304520Snw141292 			mapping->id1.idmap_id_u.sid.prefix =
27314520Snw141292 			    strdup(request->id1.idmap_id_u.sid.prefix);
27324644Sbaban 			if (mapping->id1.idmap_id_u.sid.prefix == NULL)
27334644Sbaban 				return (-1);
27344644Sbaban 		}
27354520Snw141292 	} else {
27364520Snw141292 		mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid;
27374520Snw141292 	}
27384520Snw141292 
27394520Snw141292 	mapping->id1domain.idmap_utf8str_len =
27404520Snw141292 	    request->id1domain.idmap_utf8str_len;
27414644Sbaban 	if (mapping->id1domain.idmap_utf8str_len) {
27424520Snw141292 		mapping->id1domain.idmap_utf8str_val =
27434520Snw141292 		    strdup(request->id1domain.idmap_utf8str_val);
27444644Sbaban 		if (mapping->id1domain.idmap_utf8str_val == NULL)
27454644Sbaban 			return (-1);
27464644Sbaban 	}
27474520Snw141292 
27484520Snw141292 	mapping->id1name.idmap_utf8str_len  =
27494520Snw141292 	    request->id1name.idmap_utf8str_len;
27504644Sbaban 	if (mapping->id1name.idmap_utf8str_len) {
27514520Snw141292 		mapping->id1name.idmap_utf8str_val =
27524520Snw141292 		    strdup(request->id1name.idmap_utf8str_val);
27534644Sbaban 		if (mapping->id1name.idmap_utf8str_val == NULL)
27544644Sbaban 			return (-1);
27554644Sbaban 	}
27564520Snw141292 
27574644Sbaban 	/* We don't need the rest of the request i.e request->id2 */
27584644Sbaban 	return (0);
27594644Sbaban 
27604644Sbaban errout:
27614864Sbaban 	if (mapping->id1.idmap_id_u.sid.prefix != NULL) {
27624644Sbaban 		free(mapping->id1.idmap_id_u.sid.prefix);
27634644Sbaban 		mapping->id1.idmap_id_u.sid.prefix = NULL;
27644520Snw141292 	}
27654520Snw141292 
27664864Sbaban 	if (mapping->id1domain.idmap_utf8str_val != NULL) {
27674644Sbaban 		free(mapping->id1domain.idmap_utf8str_val);
27684644Sbaban 		mapping->id1domain.idmap_utf8str_val = NULL;
27694644Sbaban 		mapping->id1domain.idmap_utf8str_len = 0;
27704644Sbaban 	}
27714520Snw141292 
27724864Sbaban 	if (mapping->id1name.idmap_utf8str_val != NULL) {
27734644Sbaban 		free(mapping->id1name.idmap_utf8str_val);
27744644Sbaban 		mapping->id1name.idmap_utf8str_val = NULL;
27754644Sbaban 		mapping->id1name.idmap_utf8str_len = 0;
27764644Sbaban 	}
27774644Sbaban 
27784644Sbaban 	(void) memset(mapping, 0, sizeof (*mapping));
27794644Sbaban 	return (-1);
27804520Snw141292 }
27814520Snw141292 
27824520Snw141292 
27834520Snw141292 idmap_retcode
27844520Snw141292 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
27854520Snw141292 		idmap_mapping *mapping) {
27864520Snw141292 	idmap_id_res	idres;
27874520Snw141292 	lookup_state_t	state;
27884520Snw141292 	idmap_utf8str	*str;
27894520Snw141292 	int		is_user;
27904520Snw141292 	idmap_retcode	retcode;
27914520Snw141292 	const char	*winname, *windomain;
27924520Snw141292 
27934520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
27944520Snw141292 	(void) memset(&state, 0, sizeof (state));
27954520Snw141292 
27964520Snw141292 	if (request->id2.idtype == IDMAP_UID)
27974520Snw141292 		is_user = 1;
27984520Snw141292 	else if (request->id2.idtype == IDMAP_GID)
27994520Snw141292 		is_user = 0;
28004520Snw141292 	else if (request->id2.idtype == IDMAP_POSIXID)
28014520Snw141292 		is_user = -1;
28024520Snw141292 	else {
28034520Snw141292 		retcode = IDMAP_ERR_IDTYPE;
28044520Snw141292 		goto out;
28054520Snw141292 	}
28064520Snw141292 
28074520Snw141292 	/* Copy data from request to result */
28084644Sbaban 	if (copy_mapping_request(mapping, request) < 0) {
28094644Sbaban 		retcode = IDMAP_ERR_MEMORY;
28104644Sbaban 		goto out;
28114644Sbaban 	}
28124520Snw141292 
28134520Snw141292 	winname = mapping->id1name.idmap_utf8str_val;
28144520Snw141292 	windomain = mapping->id1domain.idmap_utf8str_val;
28154520Snw141292 
28164864Sbaban 	if (winname == NULL && windomain != NULL) {
28174520Snw141292 		retcode = IDMAP_ERR_ARG;
28184520Snw141292 		goto out;
28194520Snw141292 	}
28204520Snw141292 
28214864Sbaban 	if (winname != NULL && windomain == NULL) {
28224520Snw141292 		str = &mapping->id1domain;
28234520Snw141292 		RDLOCK_CONFIG();
28244864Sbaban 		if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
28254520Snw141292 			retcode = idmap_str2utf8(&str,
28264520Snw141292 				_idmapdstate.cfg->pgcfg.mapping_domain, 0);
28274520Snw141292 			if (retcode != IDMAP_SUCCESS) {
28284520Snw141292 				UNLOCK_CONFIG();
28294520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
28304520Snw141292 				retcode = IDMAP_ERR_MEMORY;
28314520Snw141292 				goto out;
28324520Snw141292 			}
28334520Snw141292 		}
28344520Snw141292 		UNLOCK_CONFIG();
28354520Snw141292 		windomain = mapping->id1domain.idmap_utf8str_val;
28364520Snw141292 	}
28374520Snw141292 
28384864Sbaban 	if (winname != NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) {
28394520Snw141292 		retcode = lookup_name2sid(cache, winname, windomain,
28404520Snw141292 			&is_user, &mapping->id1.idmap_id_u.sid.prefix,
28414520Snw141292 			&mapping->id1.idmap_id_u.sid.rid, mapping);
28424520Snw141292 		if (retcode != IDMAP_SUCCESS)
28434520Snw141292 			goto out;
28444520Snw141292 		if (mapping->id2.idtype == IDMAP_POSIXID)
28454520Snw141292 			mapping->id2.idtype = is_user?IDMAP_UID:IDMAP_GID;
28464520Snw141292 	}
28474520Snw141292 
28484520Snw141292 	state.sid2pid_done = TRUE;
28494520Snw141292 	retcode = sid2pid_first_pass(&state, cache, mapping, &idres);
28504520Snw141292 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
28514520Snw141292 		goto out;
28524520Snw141292 
28534520Snw141292 	if (state.ad_nqueries) {
28544520Snw141292 		/* sid2name AD lookup */
28554520Snw141292 		retcode = lookup_win_sid2name(
28564520Snw141292 			mapping->id1.idmap_id_u.sid.prefix,
28574520Snw141292 			mapping->id1.idmap_id_u.sid.rid,
28584520Snw141292 			&mapping->id1name.idmap_utf8str_val,
28594520Snw141292 			&mapping->id1domain.idmap_utf8str_val,
28604520Snw141292 			(int *)&idres.id.idtype);
28614520Snw141292 
28624520Snw141292 		idres.retcode = retcode;
28634520Snw141292 	}
28644520Snw141292 
28654520Snw141292 	state.sid2pid_done = TRUE;
28664520Snw141292 	retcode = sid2pid_second_pass(&state, cache, db, mapping, &idres);
28674520Snw141292 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
28684520Snw141292 		goto out;
28694520Snw141292 
28704520Snw141292 	/* Update cache */
28714520Snw141292 	(void) update_cache_sid2pid(&state, cache, mapping, &idres);
28724520Snw141292 
28734520Snw141292 out:
28744520Snw141292 	if (retcode == IDMAP_SUCCESS) {
28754520Snw141292 		mapping->direction = idres.direction;
28764520Snw141292 		mapping->id2 = idres.id;
28774520Snw141292 		(void) memset(&idres, 0, sizeof (idres));
28784864Sbaban 	} else {
28794864Sbaban 		mapping->id2.idmap_id_u.uid = UID_NOBODY;
28804520Snw141292 	}
28814520Snw141292 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
28824520Snw141292 	return (retcode);
28834520Snw141292 }
28844520Snw141292 
28854520Snw141292 idmap_retcode
28864520Snw141292 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
28874520Snw141292 		idmap_mapping *mapping, int is_user) {
28884520Snw141292 	idmap_id_res	idres;
28894520Snw141292 	lookup_state_t	state;
28904520Snw141292 	struct passwd	pwd;
28914520Snw141292 	struct group	grp;
28924520Snw141292 	char		buf[1024];
28934520Snw141292 	int		errnum;
28944520Snw141292 	idmap_retcode	retcode;
28954520Snw141292 	const char	*unixname;
28964520Snw141292 	const char	*me = "get_u2w_mapping";
28974520Snw141292 
28984520Snw141292 	/*
28994520Snw141292 	 * In order to re-use the pid2sid code, we convert
29004520Snw141292 	 * our input data into structs that are expected by
29014520Snw141292 	 * pid2sid_first_pass.
29024520Snw141292 	 */
29034520Snw141292 
29044520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
29054520Snw141292 	(void) memset(&state, 0, sizeof (state));
29064520Snw141292 
29074520Snw141292 	/* Copy data from request to result */
29084644Sbaban 	if (copy_mapping_request(mapping, request) < 0) {
29094644Sbaban 		retcode = IDMAP_ERR_MEMORY;
29104644Sbaban 		goto out;
29114644Sbaban 	}
29124520Snw141292 
29134520Snw141292 	unixname = mapping->id1name.idmap_utf8str_val;
29144520Snw141292 
29154520Snw141292 	if (unixname == NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
29164520Snw141292 		retcode = IDMAP_ERR_ARG;
29174520Snw141292 		goto out;
29184520Snw141292 	}
29194520Snw141292 
29204864Sbaban 	if (unixname != NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
29214520Snw141292 		/* Get uid/gid by name */
29224520Snw141292 		if (is_user) {
29234520Snw141292 			errno = 0;
29244520Snw141292 			if (getpwnam_r(unixname, &pwd, buf,
29254520Snw141292 					sizeof (buf)) == NULL) {
29264520Snw141292 				errnum = errno;
29274520Snw141292 				idmapdlog(LOG_WARNING,
29284520Snw141292 				"%s: getpwnam_r(%s) failed (%s).",
29294520Snw141292 					me, unixname,
29304520Snw141292 					errnum?strerror(errnum):"not found");
29314520Snw141292 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
29324520Snw141292 						IDMAP_ERR_INTERNAL;
29334520Snw141292 				goto out;
29344520Snw141292 			}
29354520Snw141292 			mapping->id1.idmap_id_u.uid = pwd.pw_uid;
29364520Snw141292 		} else {
29374520Snw141292 			errno = 0;
29384520Snw141292 			if (getgrnam_r(unixname, &grp, buf,
29394520Snw141292 					sizeof (buf)) == NULL) {
29404520Snw141292 				errnum = errno;
29414520Snw141292 				idmapdlog(LOG_WARNING,
29424520Snw141292 				"%s: getgrnam_r(%s) failed (%s).",
29434520Snw141292 					me, unixname,
29444520Snw141292 					errnum?strerror(errnum):"not found");
29454520Snw141292 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
29464520Snw141292 						IDMAP_ERR_INTERNAL;
29474520Snw141292 				goto out;
29484520Snw141292 			}
29494520Snw141292 			mapping->id1.idmap_id_u.gid = grp.gr_gid;
29504520Snw141292 		}
29514520Snw141292 	}
29524520Snw141292 
29534520Snw141292 	state.pid2sid_done = TRUE;
29544520Snw141292 	retcode = pid2sid_first_pass(&state, cache, db, mapping, &idres,
29554520Snw141292 			is_user, 1);
29564520Snw141292 	if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE)
29574520Snw141292 		goto out;
29584520Snw141292 
29594520Snw141292 	/* Update cache */
29604520Snw141292 	(void) update_cache_pid2sid(&state, cache, mapping, &idres);
29614520Snw141292 
29624520Snw141292 out:
29634520Snw141292 	mapping->direction = idres.direction;
29644520Snw141292 	mapping->id2 = idres.id;
29654520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
29664520Snw141292 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
29674520Snw141292 	return (retcode);
29684520Snw141292 }
2969