xref: /onnv-gate/usr/src/cmd/idmap/idmapd/dbutils.c (revision 5317:8c62b0b138cf)
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 
32*5317Sjp151216 #include <atomic.h>
334520Snw141292 #include <stdio.h>
344520Snw141292 #include <stdlib.h>
354520Snw141292 #include <string.h>
364520Snw141292 #include <errno.h>
374520Snw141292 #include <sys/types.h>
384520Snw141292 #include <sys/stat.h>
394520Snw141292 #include <rpc/rpc.h>
404520Snw141292 #include <sys/sid.h>
414520Snw141292 #include <time.h>
424520Snw141292 #include <pwd.h>
434520Snw141292 #include <grp.h>
444884Sjp151216 #include <pthread.h>
454884Sjp151216 #include <assert.h>
464520Snw141292 
474520Snw141292 #include "idmapd.h"
484520Snw141292 #include "adutils.h"
494520Snw141292 #include "string.h"
504520Snw141292 #include "idmap_priv.h"
514520Snw141292 
524884Sjp151216 
53*5317Sjp151216 static int degraded = 0;	/* whether the FMRI has been marked degraded */
54*5317Sjp151216 
554520Snw141292 static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
564520Snw141292 		sqlite_vm **, int *, int, const char ***);
574864Sbaban static idmap_retcode lookup_wksids_name2sid(const char *, char **,
584864Sbaban 		idmap_rid_t *, int *);
594520Snw141292 
604520Snw141292 #define	EMPTY_NAME(name)	(*name == 0 || strcmp(name, "\"\"") == 0)
614520Snw141292 
624520Snw141292 #define	DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
634520Snw141292 		(req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
644520Snw141292 
654520Snw141292 #define	AVOID_NAMESERVICE(req)\
664520Snw141292 		(req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
674520Snw141292 
684520Snw141292 #define	IS_EPHEMERAL(pid)	(pid > INT32_MAX)
694520Snw141292 
704520Snw141292 #define	LOCALRID_MIN	1000
714520Snw141292 
724520Snw141292 
734520Snw141292 
744520Snw141292 typedef enum init_db_option {
754520Snw141292 	FAIL_IF_CORRUPT = 0,
764520Snw141292 	REMOVE_IF_CORRUPT = 1
774520Snw141292 } init_db_option_t;
784520Snw141292 
794884Sjp151216 /*
804884Sjp151216  * Thread specfic data to hold the database handles so that the
814884Sjp151216  * databaes are not opened and closed for every request. It also
824884Sjp151216  * contains the sqlite busy handler structure.
834884Sjp151216  */
844884Sjp151216 
854884Sjp151216 struct idmap_busy {
864884Sjp151216 	const char *name;
874884Sjp151216 	const int *delays;
884884Sjp151216 	int delay_size;
894884Sjp151216 	int total;
904884Sjp151216 	int sec;
914884Sjp151216 };
924884Sjp151216 
934884Sjp151216 
944884Sjp151216 typedef struct idmap_tsd {
954884Sjp151216 	sqlite *db_db;
964884Sjp151216 	sqlite *cache_db;
974884Sjp151216 	struct idmap_busy cache_busy;
984884Sjp151216 	struct idmap_busy db_busy;
994884Sjp151216 } idmap_tsd_t;
1004884Sjp151216 
1014884Sjp151216 
1024884Sjp151216 
1034884Sjp151216 static const int cache_delay_table[] =
1044884Sjp151216 		{ 1, 2, 5, 10, 15, 20, 25, 30,  35,  40,
1054884Sjp151216 		50,  50, 60, 70, 80, 90, 100};
1064884Sjp151216 
1074884Sjp151216 static const int db_delay_table[] =
1084884Sjp151216 		{ 5, 10, 15, 20, 30,  40,  55,  70, 100};
1094884Sjp151216 
1104884Sjp151216 
1114884Sjp151216 static pthread_key_t	idmap_tsd_key;
1124884Sjp151216 
1134884Sjp151216 void
1144884Sjp151216 idmap_tsd_destroy(void *key)
1154884Sjp151216 {
1164884Sjp151216 
1174884Sjp151216 	idmap_tsd_t	*tsd = (idmap_tsd_t *)key;
1184884Sjp151216 	if (tsd) {
1194884Sjp151216 		if (tsd->db_db)
1204884Sjp151216 			(void) sqlite_close(tsd->db_db);
1214884Sjp151216 		if (tsd->cache_db)
1224884Sjp151216 			(void) sqlite_close(tsd->cache_db);
1234884Sjp151216 		free(tsd);
1244884Sjp151216 	}
1254884Sjp151216 }
1264884Sjp151216 
1274884Sjp151216 int
1284884Sjp151216 idmap_init_tsd_key(void) {
1294884Sjp151216 
1304884Sjp151216 	return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy));
1314884Sjp151216 }
1324884Sjp151216 
1334884Sjp151216 
1344884Sjp151216 
1354884Sjp151216 idmap_tsd_t *
1364884Sjp151216 idmap_get_tsd(void)
1374884Sjp151216 {
1384884Sjp151216 	idmap_tsd_t	*tsd;
1394884Sjp151216 
1404884Sjp151216 	if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) {
1414884Sjp151216 		/* No thread specific data so create it */
1424884Sjp151216 		if ((tsd = malloc(sizeof (*tsd))) != NULL) {
1434884Sjp151216 			/* Initialize thread specific data */
1444884Sjp151216 			(void) memset(tsd, 0, sizeof (*tsd));
1454884Sjp151216 			/* save the trhread specific data */
1464884Sjp151216 			if (pthread_setspecific(idmap_tsd_key, tsd) != 0) {
1474884Sjp151216 				/* Can't store key */
1484884Sjp151216 				free(tsd);
1494884Sjp151216 				tsd = NULL;
1504884Sjp151216 			}
1514884Sjp151216 		} else {
1524884Sjp151216 			tsd = NULL;
1534884Sjp151216 		}
1544884Sjp151216 	}
1554884Sjp151216 
1564884Sjp151216 	return (tsd);
1574884Sjp151216 }
1584884Sjp151216 
159*5317Sjp151216 /*
160*5317Sjp151216  * Wrappers for smf_degrade/restore_instance()
161*5317Sjp151216  *
162*5317Sjp151216  * smf_restore_instance() is too heavy duty to be calling every time we
163*5317Sjp151216  * have a successful AD name<->SID lookup.
164*5317Sjp151216  */
165*5317Sjp151216 void
166*5317Sjp151216 degrade_svc(void)
167*5317Sjp151216 {
168*5317Sjp151216 	membar_consumer();
169*5317Sjp151216 	if (degraded)
170*5317Sjp151216 		return;
171*5317Sjp151216 	(void) smf_degrade_instance(NULL, 0);
172*5317Sjp151216 	membar_producer();
173*5317Sjp151216 	degraded = 1;
174*5317Sjp151216 }
175*5317Sjp151216 
176*5317Sjp151216 
177*5317Sjp151216 void
178*5317Sjp151216 restore_svc(void)
179*5317Sjp151216 {
180*5317Sjp151216 	membar_consumer();
181*5317Sjp151216 	if (!degraded)
182*5317Sjp151216 		return;
183*5317Sjp151216 	(void) smf_restore_instance(NULL);
184*5317Sjp151216 	membar_producer();
185*5317Sjp151216 	degraded = 0;
186*5317Sjp151216 }
1874884Sjp151216 
1884520Snw141292 
1894520Snw141292 /*
1904520Snw141292  * Initialize 'dbname' using 'sql'
1914520Snw141292  */
1924520Snw141292 static int
1934520Snw141292 init_db_instance(const char *dbname, const char *sql, init_db_option_t opt,
1944520Snw141292 		int *new_db_created)
1954520Snw141292 {
1964520Snw141292 	int rc = 0;
1974520Snw141292 	int tries = 0;
1984520Snw141292 	sqlite *db = NULL;
1994520Snw141292 	char *str = NULL;
2004520Snw141292 
2014520Snw141292 	if (new_db_created != NULL)
2024520Snw141292 		*new_db_created = 0;
2034520Snw141292 
2044520Snw141292 	db = sqlite_open(dbname, 0600, &str);
2054520Snw141292 	while (db == NULL) {
2064520Snw141292 		idmapdlog(LOG_ERR,
2074520Snw141292 		    "Error creating database %s (%s)",
2084520Snw141292 		    dbname, CHECK_NULL(str));
2094520Snw141292 		sqlite_freemem(str);
2104520Snw141292 		if (opt == FAIL_IF_CORRUPT || opt != REMOVE_IF_CORRUPT ||
2114520Snw141292 		    tries > 0)
2124520Snw141292 			return (-1);
2134520Snw141292 
2144520Snw141292 		tries++;
2154520Snw141292 		(void) unlink(dbname);
2164520Snw141292 		db = sqlite_open(dbname, 0600, &str);
2174520Snw141292 	}
2184520Snw141292 
2194520Snw141292 	sqlite_busy_timeout(db, 3000);
2204520Snw141292 	rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &str);
2214520Snw141292 	if (SQLITE_OK != rc) {
2224520Snw141292 		idmapdlog(LOG_ERR, "Cannot begin database transaction (%s)",
2234520Snw141292 		    str);
2244520Snw141292 		sqlite_freemem(str);
2254520Snw141292 		sqlite_close(db);
2264520Snw141292 		return (1);
2274520Snw141292 	}
2284520Snw141292 
2294520Snw141292 	switch (sqlite_exec(db, sql, NULL, NULL, &str)) {
2304520Snw141292 	case SQLITE_ERROR:
2314520Snw141292 /*
2324520Snw141292  * This is the normal situation: CREATE probably failed because tables
2334520Snw141292  * already exist. It may indicate an error in SQL as well, but we cannot
2344520Snw141292  * tell.
2354520Snw141292  */
2364520Snw141292 		sqlite_freemem(str);
2374520Snw141292 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
2384520Snw141292 		    NULL, NULL, &str);
2394520Snw141292 		break;
2404520Snw141292 	case SQLITE_OK:
2414520Snw141292 		rc =  sqlite_exec(db, "COMMIT TRANSACTION",
2424520Snw141292 		    NULL, NULL, &str);
2434520Snw141292 		idmapdlog(LOG_INFO,
2444520Snw141292 		    "Database created at %s", dbname);
2454520Snw141292 
2464520Snw141292 		if (new_db_created != NULL)
2474520Snw141292 			*new_db_created = 1;
2484520Snw141292 		break;
2494520Snw141292 	default:
2504520Snw141292 		idmapdlog(LOG_ERR,
2514520Snw141292 		    "Error initializing database %s (%s)",
2524520Snw141292 		    dbname, str);
2534520Snw141292 		sqlite_freemem(str);
2544520Snw141292 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
2554520Snw141292 		    NULL, NULL, &str);
2564520Snw141292 		break;
2574520Snw141292 	}
2584520Snw141292 
2594520Snw141292 	if (SQLITE_OK != rc) {
2604520Snw141292 		/* this is bad - database may be left in a locked state */
2614520Snw141292 		idmapdlog(LOG_ERR,
2624520Snw141292 		    "Error closing transaction (%s)", str);
2634520Snw141292 		sqlite_freemem(str);
2644520Snw141292 	}
2654520Snw141292 
2664520Snw141292 	(void) sqlite_close(db);
2674520Snw141292 	return (rc);
2684520Snw141292 }
2694520Snw141292 
2704884Sjp151216 
2714884Sjp151216 /*
2724884Sjp151216  * This is the SQLite database busy handler that retries the SQL
2734884Sjp151216  * operation until it is successful.
2744884Sjp151216  */
2754884Sjp151216 int
2764884Sjp151216 /* LINTED E_FUNC_ARG_UNUSED */
2774884Sjp151216 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count)
2784884Sjp151216 {
2794884Sjp151216 	struct idmap_busy	*busy = arg;
2804884Sjp151216 	int			delay;
2814884Sjp151216 	struct timespec		rqtp;
2824884Sjp151216 
2834884Sjp151216 	if (count == 1)  {
2844884Sjp151216 		busy->total = 0;
2854884Sjp151216 		busy->sec = 2;
2864884Sjp151216 	}
2874884Sjp151216 	if (busy->total > 1000 * busy->sec) {
2884884Sjp151216 		idmapdlog(LOG_ERR,
2894884Sjp151216 		    "Thread %d waited %d sec for the %s database",
2904884Sjp151216 		    pthread_self(), busy->sec, busy->name);
2914884Sjp151216 		busy->sec++;
2924884Sjp151216 	}
2934884Sjp151216 
2944884Sjp151216 	if (count <= busy->delay_size) {
2954884Sjp151216 		delay = busy->delays[count-1];
2964884Sjp151216 	} else {
2974884Sjp151216 		delay = busy->delays[busy->delay_size - 1];
2984884Sjp151216 	}
2994884Sjp151216 	busy->total += delay;
3004884Sjp151216 	rqtp.tv_sec = 0;
3014884Sjp151216 	rqtp.tv_nsec = delay * (NANOSEC / MILLISEC);
3024884Sjp151216 	(void) nanosleep(&rqtp, NULL);
3034884Sjp151216 	return (1);
3044884Sjp151216 }
3054884Sjp151216 
3064884Sjp151216 
3074520Snw141292 /*
3084520Snw141292  * Get the database handle
3094520Snw141292  */
3104520Snw141292 idmap_retcode
3114520Snw141292 get_db_handle(sqlite **db) {
3124520Snw141292 	char	*errmsg;
3134884Sjp151216 	idmap_tsd_t *tsd;
3144520Snw141292 
3154520Snw141292 	/*
3164884Sjp151216 	 * Retrieve the db handle from thread-specific storage
3174520Snw141292 	 * If none exists, open and store in thread-specific storage.
3184520Snw141292 	 */
3194884Sjp151216 	if ((tsd = idmap_get_tsd()) == NULL) {
3204520Snw141292 		idmapdlog(LOG_ERR,
3214884Sjp151216 			"Error getting thread specific data for %s",
3224884Sjp151216 			IDMAP_DBNAME);
3234884Sjp151216 		return (IDMAP_ERR_MEMORY);
3244520Snw141292 	}
3254884Sjp151216 
3264884Sjp151216 	if (tsd->db_db == NULL) {
3274884Sjp151216 		tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg);
3284884Sjp151216 		if (tsd->db_db == NULL) {
3294884Sjp151216 			idmapdlog(LOG_ERR,
3304884Sjp151216 				"Error opening database %s (%s)",
3314884Sjp151216 				IDMAP_DBNAME, CHECK_NULL(errmsg));
3324884Sjp151216 			sqlite_freemem(errmsg);
3334884Sjp151216 			return (IDMAP_ERR_INTERNAL);
3344884Sjp151216 		}
3354884Sjp151216 		tsd->db_busy.name = IDMAP_DBNAME;
3364884Sjp151216 		tsd->db_busy.delays = db_delay_table;
3374884Sjp151216 		tsd->db_busy.delay_size = sizeof (db_delay_table) /
3384884Sjp151216 		    sizeof (int);
3394884Sjp151216 		sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler,
3404884Sjp151216 		    &tsd->db_busy);
3414884Sjp151216 	}
3424884Sjp151216 	*db = tsd->db_db;
3434520Snw141292 	return (IDMAP_SUCCESS);
3444520Snw141292 }
3454520Snw141292 
3464520Snw141292 /*
3474520Snw141292  * Get the cache handle
3484520Snw141292  */
3494520Snw141292 idmap_retcode
3504884Sjp151216 get_cache_handle(sqlite **cache) {
3514520Snw141292 	char	*errmsg;
3524884Sjp151216 	idmap_tsd_t *tsd;
3534520Snw141292 
3544520Snw141292 	/*
3554884Sjp151216 	 * Retrieve the db handle from thread-specific storage
3564520Snw141292 	 * If none exists, open and store in thread-specific storage.
3574520Snw141292 	 */
3584884Sjp151216 	if ((tsd = idmap_get_tsd()) == NULL) {
3594520Snw141292 		idmapdlog(LOG_ERR,
3604884Sjp151216 			"Error getting thread specific data for %s",
3614884Sjp151216 			IDMAP_DBNAME);
3624884Sjp151216 		return (IDMAP_ERR_MEMORY);
3634520Snw141292 	}
3644884Sjp151216 
3654884Sjp151216 	if (tsd->cache_db == NULL) {
3664884Sjp151216 		tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg);
3674884Sjp151216 		if (tsd->cache_db == NULL) {
3684884Sjp151216 			idmapdlog(LOG_ERR,
3694884Sjp151216 				"Error opening database %s (%s)",
3704884Sjp151216 				IDMAP_CACHENAME, CHECK_NULL(errmsg));
3714884Sjp151216 			sqlite_freemem(errmsg);
3724884Sjp151216 			return (IDMAP_ERR_INTERNAL);
3734884Sjp151216 		}
3744884Sjp151216 		tsd->cache_busy.name = IDMAP_CACHENAME;
3754884Sjp151216 		tsd->cache_busy.delays = cache_delay_table;
3764884Sjp151216 		tsd->cache_busy.delay_size = sizeof (cache_delay_table) /
3774884Sjp151216 		    sizeof (int);
3784884Sjp151216 		sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler,
3794884Sjp151216 		    &tsd->cache_busy);
3804884Sjp151216 	}
3814884Sjp151216 	*cache = tsd->cache_db;
3824520Snw141292 	return (IDMAP_SUCCESS);
3834520Snw141292 }
3844520Snw141292 
3854520Snw141292 #define	CACHE_SQL\
3864520Snw141292 	"CREATE TABLE idmap_cache ("\
3874520Snw141292 	"	sidprefix TEXT,"\
3884520Snw141292 	"	rid INTEGER,"\
3894520Snw141292 	"	windomain TEXT,"\
3904520Snw141292 	"	winname TEXT,"\
3914520Snw141292 	"	pid INTEGER,"\
3924520Snw141292 	"	unixname TEXT,"\
3934520Snw141292 	"	is_user INTEGER,"\
3944520Snw141292 	"	w2u INTEGER,"\
3954520Snw141292 	"	u2w INTEGER,"\
3964520Snw141292 	"	expiration INTEGER"\
3974520Snw141292 	");"\
3984520Snw141292 	"CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache"\
3994520Snw141292 	"		(sidprefix, rid, w2u);"\
4004520Snw141292 	"CREATE UNIQUE INDEX idmap_cache_pid_u2w ON idmap_cache"\
4014520Snw141292 	"		(pid, is_user, u2w);"\
4024520Snw141292 	"CREATE TABLE name_cache ("\
4034520Snw141292 	"	sidprefix TEXT,"\
4044520Snw141292 	"	rid INTEGER,"\
4054520Snw141292 	"	name TEXT,"\
4064520Snw141292 	"	domain TEXT,"\
4074520Snw141292 	"	type INTEGER,"\
4084520Snw141292 	"	expiration INTEGER"\
4094520Snw141292 	");"\
4104520Snw141292 	"CREATE UNIQUE INDEX name_cache_sid ON name_cache"\
4114520Snw141292 	"		(sidprefix, rid);"
4124520Snw141292 
4134520Snw141292 #define	DB_SQL\
4144520Snw141292 	"CREATE TABLE namerules ("\
4154520Snw141292 	"	is_user INTEGER NOT NULL,"\
4164520Snw141292 	"	windomain TEXT,"\
4174520Snw141292 	"	winname TEXT NOT NULL,"\
4184520Snw141292 	"	is_nt4 INTEGER NOT NULL,"\
4194520Snw141292 	"	unixname NOT NULL,"\
4204520Snw141292 	"	w2u_order INTEGER,"\
4214520Snw141292 	"	u2w_order INTEGER"\
4224520Snw141292 	");"\
4234520Snw141292 	"CREATE UNIQUE INDEX namerules_w2u ON namerules"\
4244520Snw141292 	"		(winname, windomain, is_user, w2u_order);"\
4254520Snw141292 	"CREATE UNIQUE INDEX namerules_u2w ON namerules"\
4264520Snw141292 	"		(unixname, is_user, u2w_order);"
4274520Snw141292 
4284520Snw141292 /*
4294520Snw141292  * Initialize cache and db
4304520Snw141292  */
4314520Snw141292 int
4324520Snw141292 init_dbs() {
4334520Snw141292 	/* name-based mappings; probably OK to blow away in a pinch(?) */
4344520Snw141292 	if (init_db_instance(IDMAP_DBNAME, DB_SQL, FAIL_IF_CORRUPT, NULL) < 0)
4354520Snw141292 		return (-1);
4364520Snw141292 
4374520Snw141292 	/* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
4384520Snw141292 	if (init_db_instance(IDMAP_CACHENAME, CACHE_SQL, REMOVE_IF_CORRUPT,
4394520Snw141292 			&_idmapdstate.new_eph_db) < 0)
4404520Snw141292 		return (-1);
4414520Snw141292 
4424520Snw141292 	return (0);
4434520Snw141292 }
4444520Snw141292 
4454520Snw141292 /*
4464520Snw141292  * Finalize databases
4474520Snw141292  */
4484520Snw141292 void
4494520Snw141292 fini_dbs() {
4504520Snw141292 }
4514520Snw141292 
4524520Snw141292 /*
4534520Snw141292  * This table is a listing of status codes that will returned to the
4544520Snw141292  * client when a SQL command fails with the corresponding error message.
4554520Snw141292  */
4564520Snw141292 static msg_table_t sqlmsgtable[] = {
4574864Sbaban 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
4584520Snw141292 	"columns unixname, is_user, u2w_order are not unique"},
4594864Sbaban 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
4604520Snw141292 	"columns winname, windomain, is_user, w2u_order are not unique"},
4614520Snw141292 	{-1, NULL}
4624520Snw141292 };
4634520Snw141292 
4644520Snw141292 /*
4654520Snw141292  * idmapd's version of string2stat to map SQLite messages to
4664520Snw141292  * status codes
4674520Snw141292  */
4684520Snw141292 idmap_retcode
4694520Snw141292 idmapd_string2stat(const char *msg) {
4704520Snw141292 	int i;
4714520Snw141292 	for (i = 0; sqlmsgtable[i].msg; i++) {
4724520Snw141292 		if (strcasecmp(sqlmsgtable[i].msg, msg) == 0)
4734520Snw141292 			return (sqlmsgtable[i].retcode);
4744520Snw141292 	}
4754520Snw141292 	return (IDMAP_ERR_OTHER);
4764520Snw141292 }
4774520Snw141292 
4784520Snw141292 /*
4794520Snw141292  * Execute the given SQL statment without using any callbacks
4804520Snw141292  */
4814520Snw141292 idmap_retcode
4824520Snw141292 sql_exec_no_cb(sqlite *db, char *sql) {
4834520Snw141292 	char		*errmsg = NULL;
4844884Sjp151216 	int		r;
4854520Snw141292 	idmap_retcode	retcode;
4864520Snw141292 
4874884Sjp151216 	r = sqlite_exec(db, sql, NULL, NULL, &errmsg);
4884884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
4894520Snw141292 
4904520Snw141292 	if (r != SQLITE_OK) {
4914520Snw141292 		idmapdlog(LOG_ERR, "Database error during %s (%s)",
4924520Snw141292 			sql, CHECK_NULL(errmsg));
4934884Sjp151216 		retcode = idmapd_string2stat(errmsg);
4944864Sbaban 		if (errmsg != NULL)
4954520Snw141292 			sqlite_freemem(errmsg);
4964520Snw141292 		return (retcode);
4974520Snw141292 	}
4984520Snw141292 
4994520Snw141292 	return (IDMAP_SUCCESS);
5004520Snw141292 }
5014520Snw141292 
5024520Snw141292 /*
5034520Snw141292  * Generate expression that can be used in WHERE statements.
5044520Snw141292  * Examples:
5054520Snw141292  * <prefix> <col>      <op> <value>   <suffix>
5064520Snw141292  * ""       "unixuser" "="  "foo" "AND"
5074520Snw141292  */
5084520Snw141292 idmap_retcode
5094520Snw141292 gen_sql_expr_from_utf8str(const char *prefix, const char *col,
5105064Sdm199847 		const char *op, char *value,
5114520Snw141292 		const char *suffix, char **out) {
5124520Snw141292 	if (out == NULL)
5134520Snw141292 		return (IDMAP_ERR_ARG);
5144520Snw141292 
5154520Snw141292 	if (value == NULL)
5164520Snw141292 		return (IDMAP_SUCCESS);
5174520Snw141292 
5184520Snw141292 	if (prefix == NULL)
5194520Snw141292 		prefix = "";
5204520Snw141292 	if (suffix == NULL)
5214520Snw141292 		suffix = "";
5224520Snw141292 
5234520Snw141292 	*out = sqlite_mprintf("%s %s %s %Q %s",
5245064Sdm199847 			prefix, col, op, value, suffix);
5254520Snw141292 	if (*out == NULL)
5264520Snw141292 		return (IDMAP_ERR_MEMORY);
5274520Snw141292 	return (IDMAP_SUCCESS);
5284520Snw141292 }
5294520Snw141292 
5304520Snw141292 /*
5314520Snw141292  * Generate and execute SQL statement for LIST RPC calls
5324520Snw141292  */
5334520Snw141292 idmap_retcode
5344520Snw141292 process_list_svc_sql(sqlite *db, char *sql, uint64_t limit,
5354520Snw141292 		list_svc_cb cb, void *result) {
5364520Snw141292 	list_cb_data_t	cb_data;
5374520Snw141292 	char		*errmsg = NULL;
5384884Sjp151216 	int		r;
5394520Snw141292 	idmap_retcode	retcode = IDMAP_ERR_INTERNAL;
5404520Snw141292 
5414520Snw141292 	(void) memset(&cb_data, 0, sizeof (cb_data));
5424520Snw141292 	cb_data.result = result;
5434520Snw141292 	cb_data.limit = limit;
5444520Snw141292 
5454884Sjp151216 
5464884Sjp151216 	r = sqlite_exec(db, sql, cb, &cb_data, &errmsg);
5474884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
5484884Sjp151216 	switch (r) {
5494884Sjp151216 	case SQLITE_OK:
5504884Sjp151216 		retcode = IDMAP_SUCCESS;
5514884Sjp151216 		break;
5524884Sjp151216 
5534884Sjp151216 	default:
5544884Sjp151216 		retcode = IDMAP_ERR_INTERNAL;
5554884Sjp151216 		idmapdlog(LOG_ERR,
5564884Sjp151216 			"Database error during %s (%s)",
5574884Sjp151216 			sql, CHECK_NULL(errmsg));
5584884Sjp151216 		break;
5594520Snw141292 	}
5604864Sbaban 	if (errmsg != NULL)
5614520Snw141292 		sqlite_freemem(errmsg);
5624520Snw141292 	return (retcode);
5634520Snw141292 }
5644520Snw141292 
5654520Snw141292 /*
5664520Snw141292  * This routine is called by callbacks that process the results of
5674520Snw141292  * LIST RPC calls to validate data and to allocate memory for
5684520Snw141292  * the result array.
5694520Snw141292  */
5704520Snw141292 idmap_retcode
5714520Snw141292 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv,
5724520Snw141292 		int ncol, uchar_t **list, size_t valsize) {
5734520Snw141292 	size_t	nsize;
5744520Snw141292 	void	*tmplist;
5754520Snw141292 
5764520Snw141292 	if (cb_data->limit > 0 && cb_data->next == cb_data->limit)
5774520Snw141292 		return (IDMAP_NEXT);
5784520Snw141292 
5794520Snw141292 	if (argc < ncol || argv == NULL) {
5804520Snw141292 		idmapdlog(LOG_ERR, "Invalid data");
5814520Snw141292 		return (IDMAP_ERR_INTERNAL);
5824520Snw141292 	}
5834520Snw141292 
5844520Snw141292 	/* alloc in bulk to reduce number of reallocs */
5854520Snw141292 	if (cb_data->next >= cb_data->len) {
5864520Snw141292 		nsize = (cb_data->len + SIZE_INCR) * valsize;
5874520Snw141292 		tmplist = realloc(*list, nsize);
5884520Snw141292 		if (tmplist == NULL) {
5894520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
5904520Snw141292 			return (IDMAP_ERR_MEMORY);
5914520Snw141292 		}
5924520Snw141292 		*list = tmplist;
5934520Snw141292 		(void) memset(*list + (cb_data->len * valsize), 0,
5944520Snw141292 			SIZE_INCR * valsize);
5954520Snw141292 		cb_data->len += SIZE_INCR;
5964520Snw141292 	}
5974520Snw141292 	return (IDMAP_SUCCESS);
5984520Snw141292 }
5994520Snw141292 
6004520Snw141292 static idmap_retcode
6014520Snw141292 get_namerule_order(char *winname, char *windomain, char *unixname,
6024520Snw141292 		int direction, int *w2u_order, int *u2w_order) {
6034520Snw141292 
6044520Snw141292 	*w2u_order = 0;
6054520Snw141292 	*u2w_order = 0;
6064520Snw141292 
6074520Snw141292 	/*
6084520Snw141292 	 * Windows to UNIX lookup order:
6094520Snw141292 	 *  1. winname@domain (or winname) to ""
6104520Snw141292 	 *  2. winname@domain (or winname) to unixname
6114520Snw141292 	 *  3. winname@* to ""
6124520Snw141292 	 *  4. winname@* to unixname
6134520Snw141292 	 *  5. *@domain (or *) to *
6144520Snw141292 	 *  6. *@domain (or *) to ""
6154520Snw141292 	 *  7. *@domain (or *) to unixname
6164520Snw141292 	 *  8. *@* to *
6174520Snw141292 	 *  9. *@* to ""
6184520Snw141292 	 * 10. *@* to unixname
6194520Snw141292 	 *
6204520Snw141292 	 * winname is a special case of winname@domain when domain is the
6214520Snw141292 	 * default domain. Similarly * is a special case of *@domain when
6224520Snw141292 	 * domain is the default domain.
6234520Snw141292 	 *
6244520Snw141292 	 * Note that "" has priority over specific names because "" inhibits
6254520Snw141292 	 * mappings and traditionally deny rules always had higher priority.
6264520Snw141292 	 */
6274644Sbaban 	if (direction != IDMAP_DIRECTION_U2W) {
6284644Sbaban 		/* bi-directional or from windows to unix */
6294520Snw141292 		if (winname == NULL)
6304520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6314520Snw141292 		else if (unixname == NULL)
6324520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6334520Snw141292 		else if (EMPTY_NAME(winname))
6344520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6354520Snw141292 		else if (*winname == '*' && windomain && *windomain == '*') {
6364520Snw141292 			if (*unixname == '*')
6374520Snw141292 				*w2u_order = 8;
6384520Snw141292 			else if (EMPTY_NAME(unixname))
6394520Snw141292 				*w2u_order = 9;
6404520Snw141292 			else /* unixname == name */
6414520Snw141292 				*w2u_order = 10;
6424520Snw141292 		} else if (*winname == '*') {
6434520Snw141292 			if (*unixname == '*')
6444520Snw141292 				*w2u_order = 5;
6454520Snw141292 			else if (EMPTY_NAME(unixname))
6464520Snw141292 				*w2u_order = 6;
6474520Snw141292 			else /* name */
6484520Snw141292 				*w2u_order = 7;
6494864Sbaban 		} else if (windomain != NULL && *windomain == '*') {
6504520Snw141292 			/* winname == name */
6514520Snw141292 			if (*unixname == '*')
6524520Snw141292 				return (IDMAP_ERR_W2U_NAMERULE);
6534520Snw141292 			else if (EMPTY_NAME(unixname))
6544520Snw141292 				*w2u_order = 3;
6554520Snw141292 			else /* name */
6564520Snw141292 				*w2u_order = 4;
6574520Snw141292 		} else  {
6584520Snw141292 			/* winname == name && windomain == null or name */
6594520Snw141292 			if (*unixname == '*')
6604520Snw141292 				return (IDMAP_ERR_W2U_NAMERULE);
6614520Snw141292 			else if (EMPTY_NAME(unixname))
6624520Snw141292 				*w2u_order = 1;
6634520Snw141292 			else /* name */
6644520Snw141292 				*w2u_order = 2;
6654520Snw141292 		}
6664520Snw141292 	}
6674520Snw141292 
6684520Snw141292 	/*
6694520Snw141292 	 * 1. unixname to ""
6704520Snw141292 	 * 2. unixname to winname@domain (or winname)
6714520Snw141292 	 * 3. * to *@domain (or *)
6724520Snw141292 	 * 4. * to ""
6734520Snw141292 	 * 5. * to winname@domain (or winname)
6744520Snw141292 	 */
6754644Sbaban 	if (direction != IDMAP_DIRECTION_W2U) {
6764644Sbaban 		/* bi-directional or from unix to windows */
6774520Snw141292 		if (unixname == NULL || EMPTY_NAME(unixname))
6784520Snw141292 			return (IDMAP_ERR_U2W_NAMERULE);
6794520Snw141292 		else if (winname == NULL)
6804520Snw141292 			return (IDMAP_ERR_U2W_NAMERULE);
6814864Sbaban 		else if (windomain != NULL && *windomain == '*')
6824644Sbaban 			return (IDMAP_ERR_U2W_NAMERULE);
6834520Snw141292 		else if (*unixname == '*') {
6844520Snw141292 			if (*winname == '*')
6854520Snw141292 				*u2w_order = 3;
6864520Snw141292 			else if (EMPTY_NAME(winname))
6874520Snw141292 				*u2w_order = 4;
6884520Snw141292 			else
6894520Snw141292 				*u2w_order = 5;
6904520Snw141292 		} else {
6914520Snw141292 			if (*winname == '*')
6924520Snw141292 				return (IDMAP_ERR_U2W_NAMERULE);
6934520Snw141292 			else if (EMPTY_NAME(winname))
6944520Snw141292 				*u2w_order = 1;
6954520Snw141292 			else
6964520Snw141292 				*u2w_order = 2;
6974520Snw141292 		}
6984520Snw141292 	}
6994520Snw141292 	return (IDMAP_SUCCESS);
7004520Snw141292 }
7014520Snw141292 
7024520Snw141292 /*
7034520Snw141292  * Generate and execute SQL statement to add name-based mapping rule
7044520Snw141292  */
7054520Snw141292 idmap_retcode
7064520Snw141292 add_namerule(sqlite *db, idmap_namerule *rule) {
7074520Snw141292 	char		*sql = NULL;
7084520Snw141292 	idmap_stat	retcode;
7095064Sdm199847 	char		*dom = NULL;
7104520Snw141292 	int		w2u_order, u2w_order;
7114520Snw141292 	char		w2ubuf[11], u2wbuf[11];
7124520Snw141292 
7135064Sdm199847 	retcode = get_namerule_order(rule->winname, rule->windomain,
7145064Sdm199847 	    rule->unixname, rule->direction, &w2u_order, &u2w_order);
7154520Snw141292 	if (retcode != IDMAP_SUCCESS)
7164520Snw141292 		goto out;
7174520Snw141292 
7184520Snw141292 	if (w2u_order)
7194520Snw141292 		(void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order);
7204520Snw141292 	if (u2w_order)
7214520Snw141292 		(void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order);
7224520Snw141292 
7234864Sbaban 	/*
7244864Sbaban 	 * For the triggers on namerules table to work correctly:
7254864Sbaban 	 * 1) Use NULL instead of 0 for w2u_order and u2w_order
7264864Sbaban 	 * 2) Use "" instead of NULL for "no domain"
7274864Sbaban 	 */
7284864Sbaban 
7295064Sdm199847 	if (rule->windomain != NULL)
7305064Sdm199847 		dom = rule->windomain;
7315064Sdm199847 	else if (lookup_wksids_name2sid(rule->winname, NULL, NULL, NULL)
7324864Sbaban 	    == IDMAP_SUCCESS) {
7334864Sbaban 		/* well-known SIDs don't need domain */
7344864Sbaban 		dom = "";
7354864Sbaban 	}
7364520Snw141292 
7374520Snw141292 	RDLOCK_CONFIG();
7384864Sbaban 	if (dom == NULL) {
739*5317Sjp151216 		if (_idmapdstate.cfg->pgcfg.default_domain)
740*5317Sjp151216 			dom = _idmapdstate.cfg->pgcfg.default_domain;
7414864Sbaban 		else
7424864Sbaban 			dom = "";
7434864Sbaban 	}
7444884Sjp151216 	sql = sqlite_mprintf("INSERT into namerules "
7454520Snw141292 		"(is_user, windomain, winname, is_nt4, "
7464520Snw141292 		"unixname, w2u_order, u2w_order) "
7474520Snw141292 		"VALUES(%d, %Q, %Q, %d, %Q, %q, %q);",
7484520Snw141292 		rule->is_user?1:0,
7494520Snw141292 		dom,
7505064Sdm199847 		rule->winname, rule->is_nt4?1:0,
7515064Sdm199847 		rule->unixname,
7524520Snw141292 		w2u_order?w2ubuf:NULL,
7534520Snw141292 		u2w_order?u2wbuf:NULL);
7544520Snw141292 	UNLOCK_CONFIG();
7554520Snw141292 
7564520Snw141292 	if (sql == NULL) {
7574520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
7584520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
7594520Snw141292 		goto out;
7604520Snw141292 	}
7614520Snw141292 
7624520Snw141292 	retcode = sql_exec_no_cb(db, sql);
7634520Snw141292 
7644520Snw141292 	if (retcode == IDMAP_ERR_OTHER)
7654520Snw141292 		retcode = IDMAP_ERR_CFG;
7664520Snw141292 
7674520Snw141292 out:
7684864Sbaban 	if (sql != NULL)
7694520Snw141292 		sqlite_freemem(sql);
7704520Snw141292 	return (retcode);
7714520Snw141292 }
7724520Snw141292 
7734520Snw141292 /*
7744520Snw141292  * Flush name-based mapping rules
7754520Snw141292  */
7764520Snw141292 idmap_retcode
7774520Snw141292 flush_namerules(sqlite *db, bool_t is_user) {
7784520Snw141292 	char		*sql = NULL;
7794520Snw141292 	idmap_stat	retcode;
7804520Snw141292 
7814520Snw141292 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
7824520Snw141292 		"is_user = %d;", is_user?1:0);
7834520Snw141292 
7844520Snw141292 	if (sql == NULL) {
7854520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
7864520Snw141292 		return (IDMAP_ERR_MEMORY);
7874520Snw141292 	}
7884520Snw141292 
7894520Snw141292 	retcode = sql_exec_no_cb(db, sql);
7904520Snw141292 
7914520Snw141292 	sqlite_freemem(sql);
7924520Snw141292 	return (retcode);
7934520Snw141292 }
7944520Snw141292 
7954520Snw141292 /*
7964520Snw141292  * Generate and execute SQL statement to remove a name-based mapping rule
7974520Snw141292  */
7984520Snw141292 idmap_retcode
7994520Snw141292 rm_namerule(sqlite *db, idmap_namerule *rule) {
8004520Snw141292 	char		*sql = NULL;
8014520Snw141292 	idmap_stat	retcode;
8024520Snw141292 	char		*s_windomain = NULL, *s_winname = NULL;
8034520Snw141292 	char		*s_unixname = NULL;
8044520Snw141292 	char		buf[80];
8054520Snw141292 
8065064Sdm199847 	if (rule->direction < 0 && EMPTY_STRING(rule->windomain) &&
8075064Sdm199847 	    EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
8084520Snw141292 		return (IDMAP_SUCCESS);
8094520Snw141292 
8104520Snw141292 	if (rule->direction < 0) {
8114520Snw141292 		buf[0] = 0;
8124644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_BI) {
8134520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
8144520Snw141292 				" AND u2w_order > 0");
8154644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_W2U) {
8164520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
8174520Snw141292 				" AND (u2w_order = 0 OR u2w_order ISNULL)");
8184644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_U2W) {
8194520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND u2w_order > 0"
8204520Snw141292 				" AND (w2u_order = 0 OR w2u_order ISNULL)");
8214520Snw141292 	}
8224520Snw141292 
8234520Snw141292 	retcode = IDMAP_ERR_INTERNAL;
8245064Sdm199847 	if (!EMPTY_STRING(rule->windomain)) {
8254520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "windomain", "=",
8265064Sdm199847 			rule->windomain, "", &s_windomain) != IDMAP_SUCCESS)
8274520Snw141292 			goto out;
8284520Snw141292 	}
8294520Snw141292 
8305064Sdm199847 	if (!EMPTY_STRING(rule->winname)) {
8314520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "winname", "=",
8325064Sdm199847 			rule->winname, "", &s_winname) != IDMAP_SUCCESS)
8334520Snw141292 			goto out;
8344520Snw141292 	}
8354520Snw141292 
8365064Sdm199847 	if (!EMPTY_STRING(rule->unixname)) {
8374520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "unixname", "=",
8385064Sdm199847 			rule->unixname,	"", &s_unixname) != IDMAP_SUCCESS)
8394520Snw141292 			goto out;
8404520Snw141292 	}
8414520Snw141292 
8424520Snw141292 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
8434520Snw141292 		"is_user = %d %s %s %s %s;",
8444520Snw141292 		rule->is_user?1:0,
8454520Snw141292 		s_windomain?s_windomain:"",
8464520Snw141292 		s_winname?s_winname:"",
8474520Snw141292 		s_unixname?s_unixname:"",
8484520Snw141292 		buf);
8494520Snw141292 
8504520Snw141292 	if (sql == NULL) {
8514520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
8524520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
8534520Snw141292 		goto out;
8544520Snw141292 	}
8554520Snw141292 
8564520Snw141292 	retcode = sql_exec_no_cb(db, sql);
8574520Snw141292 
8584520Snw141292 out:
8594864Sbaban 	if (s_windomain != NULL)
8604520Snw141292 		sqlite_freemem(s_windomain);
8614864Sbaban 	if (s_winname != NULL)
8624520Snw141292 		sqlite_freemem(s_winname);
8634864Sbaban 	if (s_unixname != NULL)
8644520Snw141292 		sqlite_freemem(s_unixname);
8654864Sbaban 	if (sql != NULL)
8664520Snw141292 		sqlite_freemem(sql);
8674520Snw141292 	return (retcode);
8684520Snw141292 }
8694520Snw141292 
8704520Snw141292 /*
8714520Snw141292  * Compile the given SQL query and step just once.
8724520Snw141292  *
8734520Snw141292  * Input:
8744520Snw141292  * db  - db handle
8754520Snw141292  * sql - SQL statement
8764520Snw141292  *
8774520Snw141292  * Output:
8784520Snw141292  * vm     -  virtual SQL machine
8794520Snw141292  * ncol   - number of columns in the result
8804520Snw141292  * values - column values
8814520Snw141292  *
8824520Snw141292  * Return values:
8834520Snw141292  * IDMAP_SUCCESS
8844520Snw141292  * IDMAP_ERR_NOTFOUND
8854520Snw141292  * IDMAP_ERR_INTERNAL
8864520Snw141292  */
8874520Snw141292 
8884520Snw141292 static idmap_retcode
8894520Snw141292 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
8904520Snw141292 		int reqcol, const char ***values) {
8914520Snw141292 	char		*errmsg = NULL;
8924884Sjp151216 	int		r;
8934884Sjp151216 
8944884Sjp151216 	if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) {
8954520Snw141292 		idmapdlog(LOG_ERR,
8964520Snw141292 			"Database error during %s (%s)",
8974520Snw141292 			sql, CHECK_NULL(errmsg));
8984520Snw141292 		sqlite_freemem(errmsg);
8994520Snw141292 		return (IDMAP_ERR_INTERNAL);
9004520Snw141292 	}
9014520Snw141292 
9024884Sjp151216 	r = sqlite_step(*vm, ncol, values, NULL);
9034884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
9044884Sjp151216 
9054884Sjp151216 	if (r == SQLITE_ROW) {
9064864Sbaban 		if (ncol != NULL && *ncol < reqcol) {
9074520Snw141292 			(void) sqlite_finalize(*vm, NULL);
9084520Snw141292 			*vm = NULL;
9094520Snw141292 			return (IDMAP_ERR_INTERNAL);
9104520Snw141292 		}
9114520Snw141292 		/* Caller will call finalize after using the results */
9124520Snw141292 		return (IDMAP_SUCCESS);
9134520Snw141292 	} else if (r == SQLITE_DONE) {
9144520Snw141292 		(void) sqlite_finalize(*vm, NULL);
9154520Snw141292 		*vm = NULL;
9164520Snw141292 		return (IDMAP_ERR_NOTFOUND);
9174520Snw141292 	}
9184520Snw141292 
9194520Snw141292 	(void) sqlite_finalize(*vm, &errmsg);
9204520Snw141292 	*vm = NULL;
9214520Snw141292 	idmapdlog(LOG_ERR, "Database error during %s (%s)",
9224884Sjp151216 	    sql, CHECK_NULL(errmsg));
9234520Snw141292 	sqlite_freemem(errmsg);
9244520Snw141292 	return (IDMAP_ERR_INTERNAL);
9254520Snw141292 }
9264520Snw141292 
9274864Sbaban /*
9284864Sbaban  * Table for well-known SIDs.
9294864Sbaban  *
9304864Sbaban  * Background:
9314864Sbaban  *
9325191Sbaban  * Some of the well-known principals are stored under:
9334864Sbaban  * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
9344864Sbaban  * They belong to objectClass "foreignSecurityPrincipal". They don't have
9354864Sbaban  * "samAccountName" nor "userPrincipalName" attributes. Their names are
9364864Sbaban  * available in "cn" and "name" attributes. Some of these principals have a
9374864Sbaban  * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
9384864Sbaban  * these duplicate entries have the stringified SID in the "name" and "cn"
9394864Sbaban  * attributes instead of the actual name.
9404864Sbaban  *
9415191Sbaban  * Those of the form S-1-5-32-X are Builtin groups and are stored in the
9425191Sbaban  * cn=builtin container (except, Power Users which is not stored in AD)
9434864Sbaban  *
9445191Sbaban  * These principals are and will remain constant. Therefore doing AD lookups
9455191Sbaban  * provides no benefit. Also, using hard-coded table (and thus avoiding AD
9465191Sbaban  * lookup) improves performance and avoids additional complexity in the
9475191Sbaban  * adutils.c code. Moreover these SIDs can be used when no Active Directory
9485191Sbaban  * is available (such as the CIFS server's "workgroup" mode).
9495191Sbaban  *
9505191Sbaban  * Notes:
9515191Sbaban  * 1. Currently we don't support localization of well-known SID names,
9524864Sbaban  * unlike Windows.
9534864Sbaban  *
9545191Sbaban  * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored
9555191Sbaban  * here. AD does have normal user/group objects for these objects and
9565191Sbaban  * can be looked up using the existing AD lookup code.
9574864Sbaban  */
9584864Sbaban static wksids_table_t wksids[] = {
9594864Sbaban 	{"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1},
9604864Sbaban 	{"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 0},
9614864Sbaban 	{"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0},
9624864Sbaban 	{"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1},
9634864Sbaban 	{"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1},
9645191Sbaban 	{"S-1-3", 4, "Owner Rights", 0, SENTINEL_PID, -1},
9654864Sbaban 	{"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1},
9664864Sbaban 	{"S-1-5", 2, "Network", 0, SENTINEL_PID, -1},
9674864Sbaban 	{"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1},
9684864Sbaban 	{"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1},
9694864Sbaban 	{"S-1-5", 6, "Service", 0, SENTINEL_PID, -1},
9704864Sbaban 	{"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0},
9714864Sbaban 	{"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1},
9724864Sbaban 	{"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1},
9734864Sbaban 	{"S-1-5", 10, "Self", 0, SENTINEL_PID, -1},
9744864Sbaban 	{"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1},
9754864Sbaban 	{"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1},
9764864Sbaban 	{"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1},
9774864Sbaban 	{"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1},
9784864Sbaban 	{"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1},
9795191Sbaban 	{"S-1-5", 17, "IUSR", 0, SENTINEL_PID, -1},
9804864Sbaban 	{"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0},
9814864Sbaban 	{"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1},
9824864Sbaban 	{"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1},
9834864Sbaban 	{"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1},
9845191Sbaban 	{"S-1-5-32", 544, "Administrators", 0, SENTINEL_PID, -1},
9855191Sbaban 	{"S-1-5-32", 545, "Users", 0, SENTINEL_PID, -1},
9865191Sbaban 	{"S-1-5-32", 546, "Guests", 0, SENTINEL_PID, -1},
9875191Sbaban 	{"S-1-5-32", 547, "Power Users", 0, SENTINEL_PID, -1},
9885191Sbaban 	{"S-1-5-32", 548, "Account Operators", 0, SENTINEL_PID, -1},
9895191Sbaban 	{"S-1-5-32", 549, "Server Operators", 0, SENTINEL_PID, -1},
9905191Sbaban 	{"S-1-5-32", 550, "Print Operators", 0, SENTINEL_PID, -1},
9915191Sbaban 	{"S-1-5-32", 551, "Backup Operators", 0, SENTINEL_PID, -1},
9925191Sbaban 	{"S-1-5-32", 552, "Replicator", 0, SENTINEL_PID, -1},
9935191Sbaban 	{"S-1-5-32", 554, "Pre-Windows 2000 Compatible Access", 0,
9945191Sbaban 	    SENTINEL_PID, -1},
9955191Sbaban 	{"S-1-5-32", 555, "Remote Desktop Users", 0, SENTINEL_PID, -1},
9965191Sbaban 	{"S-1-5-32", 556, "Network Configuration Operators", 0,
9975191Sbaban 	    SENTINEL_PID, -1},
9985191Sbaban 	{"S-1-5-32", 557, "Incoming Forest Trust Builders", 0,
9995191Sbaban 	    SENTINEL_PID, -1},
10005191Sbaban 	{"S-1-5-32", 558, "Performance Monitor Users", 0, SENTINEL_PID, -1},
10015191Sbaban 	{"S-1-5-32", 559, "Performance Log Users", 0, SENTINEL_PID, -1},
10025191Sbaban 	{"S-1-5-32", 560, "Windows Authorization Access Group", 0,
10035191Sbaban 	    SENTINEL_PID, -1},
10045191Sbaban 	{"S-1-5-32", 561, "Terminal Server License Servers", 0,
10055191Sbaban 	    SENTINEL_PID, -1},
10065191Sbaban 	{"S-1-5-32", 561, "Distributed COM Users", 0, SENTINEL_PID, -1},
10075191Sbaban 	{"S-1-5-32", 568, "IIS_IUSRS", 0, SENTINEL_PID, -1},
10085191Sbaban 	{"S-1-5-32", 569, "Cryptograhic Operators", 0, SENTINEL_PID, -1},
10095191Sbaban 	{"S-1-5-32", 573, "Event Log Readers", 0, SENTINEL_PID, -1},
10105191Sbaban 	{"S-1-5-32", 574, "Certificate Service DCOM Access", 0,
10115191Sbaban 	    SENTINEL_PID, -1},
10124864Sbaban 	{"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1},
10134864Sbaban 	{"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1},
10144864Sbaban 	{"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1},
10154864Sbaban 	{NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1}
10164520Snw141292 };
10174520Snw141292 
10184520Snw141292 static idmap_retcode
10194520Snw141292 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res) {
10204520Snw141292 	int i;
10214864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10224864Sbaban 		if (wksids[i].rid == req->id1.idmap_id_u.sid.rid &&
10234864Sbaban 		    (strcasecmp(wksids[i].sidprefix,
10244864Sbaban 		    req->id1.idmap_id_u.sid.prefix) == 0)) {
10254864Sbaban 
10264864Sbaban 			if (wksids[i].pid == SENTINEL_PID)
10274864Sbaban 				/* Not mapped, break */
10284864Sbaban 				break;
10294864Sbaban 			else if (wksids[i].direction == IDMAP_DIRECTION_U2W)
10304864Sbaban 				continue;
10314864Sbaban 
10324520Snw141292 			switch (req->id2.idtype) {
10334520Snw141292 			case IDMAP_UID:
10344864Sbaban 				if (wksids[i].is_user == 0)
10354864Sbaban 					continue;
10364864Sbaban 				res->id.idmap_id_u.uid = wksids[i].pid;
10374864Sbaban 				res->direction = wksids[i].direction;
10384520Snw141292 				return (IDMAP_SUCCESS);
10394520Snw141292 			case IDMAP_GID:
10404864Sbaban 				if (wksids[i].is_user == 1)
10414864Sbaban 					continue;
10424864Sbaban 				res->id.idmap_id_u.gid = wksids[i].pid;
10434864Sbaban 				res->direction = wksids[i].direction;
10444520Snw141292 				return (IDMAP_SUCCESS);
10454520Snw141292 			case IDMAP_POSIXID:
10464864Sbaban 				res->id.idmap_id_u.uid = wksids[i].pid;
10474864Sbaban 				res->id.idtype = (!wksids[i].is_user)?
10484520Snw141292 						IDMAP_GID:IDMAP_UID;
10494864Sbaban 				res->direction = wksids[i].direction;
10504520Snw141292 				return (IDMAP_SUCCESS);
10514520Snw141292 			default:
10524520Snw141292 				return (IDMAP_ERR_NOTSUPPORTED);
10534520Snw141292 			}
10544520Snw141292 		}
10554520Snw141292 	}
10564520Snw141292 	return (IDMAP_ERR_NOTFOUND);
10574520Snw141292 }
10584520Snw141292 
10594520Snw141292 static idmap_retcode
10604520Snw141292 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) {
10614520Snw141292 	int i;
10624864Sbaban 	if (req->id2.idtype != IDMAP_SID)
10634864Sbaban 		return (IDMAP_ERR_NOTSUPPORTED);
10644864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10654864Sbaban 		if (wksids[i].pid == req->id1.idmap_id_u.uid &&
10664864Sbaban 		    wksids[i].is_user == is_user &&
10674864Sbaban 		    wksids[i].direction != IDMAP_DIRECTION_W2U) {
10684864Sbaban 			res->id.idmap_id_u.sid.rid = wksids[i].rid;
10694864Sbaban 			res->id.idmap_id_u.sid.prefix =
10704864Sbaban 				strdup(wksids[i].sidprefix);
10714864Sbaban 			if (res->id.idmap_id_u.sid.prefix == NULL) {
10724864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10734864Sbaban 				return (IDMAP_ERR_MEMORY);
10744520Snw141292 			}
10754864Sbaban 			res->direction = wksids[i].direction;
10764864Sbaban 			return (IDMAP_SUCCESS);
10774864Sbaban 		}
10784864Sbaban 	}
10794864Sbaban 	return (IDMAP_ERR_NOTFOUND);
10804864Sbaban }
10814864Sbaban 
10824864Sbaban static idmap_retcode
10834864Sbaban lookup_wksids_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
10844864Sbaban 		int *type) {
10854864Sbaban 	int i;
10864864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10874864Sbaban 		if ((strcasecmp(wksids[i].sidprefix, sidprefix) == 0) &&
10884864Sbaban 		    wksids[i].rid == rid) {
10894864Sbaban 			if ((*name = strdup(wksids[i].winname)) == NULL) {
10904864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10914864Sbaban 				return (IDMAP_ERR_MEMORY);
10924864Sbaban 			}
10934864Sbaban 			*type = (wksids[i].is_user)?
10944864Sbaban 			    _IDMAP_T_USER:_IDMAP_T_GROUP;
10954864Sbaban 			return (IDMAP_SUCCESS);
10964864Sbaban 		}
10974864Sbaban 	}
10984864Sbaban 	return (IDMAP_ERR_NOTFOUND);
10994864Sbaban }
11004864Sbaban 
11014864Sbaban static idmap_retcode
11024864Sbaban lookup_wksids_name2sid(const char *name, char **sidprefix, idmap_rid_t *rid,
11034864Sbaban 		int *type) {
11044864Sbaban 	int i;
11054864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
11064864Sbaban 		if (strcasecmp(wksids[i].winname, name) == 0) {
11074864Sbaban 			if (sidprefix != NULL && (*sidprefix =
11084864Sbaban 			    strdup(wksids[i].sidprefix)) == NULL) {
11094864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
11104864Sbaban 				return (IDMAP_ERR_MEMORY);
11114864Sbaban 			}
11124864Sbaban 			if (type != NULL)
11134864Sbaban 				*type = (wksids[i].is_user)?
11144864Sbaban 				    _IDMAP_T_USER:_IDMAP_T_GROUP;
11154864Sbaban 			if (rid != NULL)
11164864Sbaban 				*rid = wksids[i].rid;
11174864Sbaban 			return (IDMAP_SUCCESS);
11184520Snw141292 		}
11194520Snw141292 	}
11204520Snw141292 	return (IDMAP_ERR_NOTFOUND);
11214520Snw141292 }
11224520Snw141292 
11234520Snw141292 static idmap_retcode
11244520Snw141292 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
11254520Snw141292 	char		*end;
11264520Snw141292 	char		*sql = NULL;
11274520Snw141292 	const char	**values;
11284520Snw141292 	sqlite_vm	*vm = NULL;
11294520Snw141292 	int		ncol, is_user;
11304520Snw141292 	uid_t		pid;
11314520Snw141292 	time_t		curtime, exp;
11324520Snw141292 	idmap_retcode	retcode;
11334520Snw141292 
11344520Snw141292 	/* Current time */
11354520Snw141292 	errno = 0;
11364520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
11374520Snw141292 		idmapdlog(LOG_ERR,
11384520Snw141292 			"Failed to get current time (%s)",
11394520Snw141292 			strerror(errno));
11404520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
11414520Snw141292 		goto out;
11424520Snw141292 	}
11434520Snw141292 
11444520Snw141292 	/* SQL to lookup the cache */
11454520Snw141292 	sql = sqlite_mprintf("SELECT pid, is_user, expiration, unixname, u2w "
11464520Snw141292 			"FROM idmap_cache WHERE "
11474520Snw141292 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
11484520Snw141292 			"(pid >= 2147483648 OR "
11494520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
11504520Snw141292 			"expiration > %d));",
11514520Snw141292 			req->id1.idmap_id_u.sid.prefix,
11524520Snw141292 			req->id1.idmap_id_u.sid.rid,
11534520Snw141292 			curtime);
11544520Snw141292 	if (sql == NULL) {
11554520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
11564520Snw141292 		retcode = IDMAP_ERR_MEMORY;
11574520Snw141292 		goto out;
11584520Snw141292 	}
11594520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
11604520Snw141292 	sqlite_freemem(sql);
11614520Snw141292 
11624520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
11634520Snw141292 		goto out;
11644520Snw141292 	} else if (retcode == IDMAP_SUCCESS) {
11654520Snw141292 		/* sanity checks */
11664520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
11674520Snw141292 			retcode = IDMAP_ERR_CACHE;
11684520Snw141292 			goto out;
11694520Snw141292 		}
11704520Snw141292 
11714520Snw141292 		pid = strtoul(values[0], &end, 10);
11724520Snw141292 		is_user = strncmp(values[1], "0", 2)?1:0;
11734520Snw141292 
11744520Snw141292 		/*
11754520Snw141292 		 * We may have an expired ephemeral mapping. Consider
11764520Snw141292 		 * the expired entry as valid if we are not going to
11774520Snw141292 		 * perform name-based mapping. But do not renew the
11784520Snw141292 		 * expiration.
11794520Snw141292 		 * If we will be doing name-based mapping then store the
11804520Snw141292 		 * ephemeral pid in the result so that we can use it
11814520Snw141292 		 * if we end up doing dynamic mapping again.
11824520Snw141292 		 */
11834520Snw141292 		if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) &&
11844520Snw141292 				!AVOID_NAMESERVICE(req)) {
11854864Sbaban 			if (IS_EPHEMERAL(pid) && values[2] != NULL) {
11864520Snw141292 				exp = strtoll(values[2], &end, 10);
11874520Snw141292 				if (exp && exp <= curtime) {
11884520Snw141292 					/* Store the ephemeral pid */
11894520Snw141292 					res->id.idmap_id_u.uid = pid;
11904520Snw141292 					res->id.idtype = is_user?
11914520Snw141292 						IDMAP_UID:IDMAP_GID;
11924644Sbaban 					res->direction = IDMAP_DIRECTION_BI;
11934520Snw141292 					req->direction |= is_user?
11944520Snw141292 						_IDMAP_F_EXP_EPH_UID:
11954520Snw141292 						_IDMAP_F_EXP_EPH_GID;
11964520Snw141292 					retcode = IDMAP_ERR_NOTFOUND;
11974520Snw141292 					goto out;
11984520Snw141292 				}
11994520Snw141292 			}
12004520Snw141292 		}
12014520Snw141292 
12024520Snw141292 		switch (req->id2.idtype) {
12034520Snw141292 		case IDMAP_UID:
12044520Snw141292 			if (!is_user)
12054520Snw141292 				retcode = IDMAP_ERR_NOTUSER;
12064520Snw141292 			else
12074520Snw141292 				res->id.idmap_id_u.uid = pid;
12084520Snw141292 			break;
12094520Snw141292 		case IDMAP_GID:
12104520Snw141292 			if (is_user)
12114520Snw141292 				retcode = IDMAP_ERR_NOTGROUP;
12124520Snw141292 			else
12134520Snw141292 				res->id.idmap_id_u.gid = pid;
12144520Snw141292 			break;
12154520Snw141292 		case IDMAP_POSIXID:
12164520Snw141292 			res->id.idmap_id_u.uid = pid;
12174520Snw141292 			res->id.idtype = (is_user)?IDMAP_UID:IDMAP_GID;
12184520Snw141292 			break;
12194520Snw141292 		default:
12204520Snw141292 			retcode = IDMAP_ERR_NOTSUPPORTED;
12214520Snw141292 			break;
12224520Snw141292 		}
12234520Snw141292 	}
12244520Snw141292 
12254520Snw141292 out:
12264520Snw141292 	if (retcode == IDMAP_SUCCESS) {
12274864Sbaban 		if (values[4] != NULL)
12284520Snw141292 			res->direction =
12294644Sbaban 			    (strtol(values[4], &end, 10) == 0)?
12304644Sbaban 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
12314520Snw141292 		else
12324644Sbaban 			res->direction = IDMAP_DIRECTION_W2U;
12334520Snw141292 
12344864Sbaban 		if (values[3] != NULL) {
12355064Sdm199847 			req->id2name = strdup(values[3]);
12365064Sdm199847 			if (req->id2name == NULL) {
12374520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
12384520Snw141292 				retcode = IDMAP_ERR_MEMORY;
12394520Snw141292 			}
12404520Snw141292 		}
12414520Snw141292 	}
12424864Sbaban 	if (vm != NULL)
12434520Snw141292 		(void) sqlite_finalize(vm, NULL);
12444520Snw141292 	return (retcode);
12454520Snw141292 }
12464520Snw141292 
12474520Snw141292 static idmap_retcode
12484864Sbaban lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid,
12494520Snw141292 		char **name, char **domain, int *type) {
12504520Snw141292 	char		*end;
12514520Snw141292 	char		*sql = NULL;
12524520Snw141292 	const char	**values;
12534520Snw141292 	sqlite_vm	*vm = NULL;
12544520Snw141292 	int		ncol;
12554520Snw141292 	time_t		curtime;
12564520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
12574520Snw141292 
12584520Snw141292 	/* Get current time */
12594520Snw141292 	errno = 0;
12604520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
12614520Snw141292 		idmapdlog(LOG_ERR,
12624520Snw141292 			"Failed to get current time (%s)",
12634520Snw141292 			strerror(errno));
12644520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
12654520Snw141292 		goto out;
12664520Snw141292 	}
12674520Snw141292 
12684520Snw141292 	/* SQL to lookup the cache */
12694520Snw141292 	sql = sqlite_mprintf("SELECT name, domain, type FROM name_cache WHERE "
12704520Snw141292 			"sidprefix = %Q AND rid = %u AND "
12714520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
12724520Snw141292 			"expiration > %d);",
12734520Snw141292 			sidprefix, rid, curtime);
12744520Snw141292 	if (sql == NULL) {
12754520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
12764520Snw141292 		retcode = IDMAP_ERR_MEMORY;
12774520Snw141292 		goto out;
12784520Snw141292 	}
12794520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
12804520Snw141292 	sqlite_freemem(sql);
12814520Snw141292 
12824520Snw141292 	if (retcode == IDMAP_SUCCESS) {
12834864Sbaban 		if (type != NULL) {
12844520Snw141292 			if (values[2] == NULL) {
12854520Snw141292 				retcode = IDMAP_ERR_CACHE;
12864520Snw141292 				goto out;
12874520Snw141292 			}
12884520Snw141292 			*type = strtol(values[2], &end, 10);
12894520Snw141292 		}
12904520Snw141292 
12914864Sbaban 		if (name != NULL && values[0] != NULL) {
12924520Snw141292 			if ((*name = strdup(values[0])) == NULL) {
12934520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
12944520Snw141292 				retcode = IDMAP_ERR_MEMORY;
12954520Snw141292 				goto out;
12964520Snw141292 			}
12974520Snw141292 		}
12984520Snw141292 
12994864Sbaban 		if (domain != NULL && values[1] != NULL) {
13004520Snw141292 			if ((*domain = strdup(values[1])) == NULL) {
13014864Sbaban 				if (name != NULL && *name) {
13024520Snw141292 					free(*name);
13034520Snw141292 					*name = NULL;
13044520Snw141292 				}
13054520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
13064520Snw141292 				retcode = IDMAP_ERR_MEMORY;
13074520Snw141292 				goto out;
13084520Snw141292 			}
13094520Snw141292 		}
13104520Snw141292 	}
13114520Snw141292 
13124520Snw141292 out:
13134864Sbaban 	if (vm != NULL)
13144520Snw141292 		(void) sqlite_finalize(vm, NULL);
13154520Snw141292 	return (retcode);
13164520Snw141292 }
13174520Snw141292 
13184520Snw141292 static idmap_retcode
13194520Snw141292 verify_type(idmap_id_type idtype, int type, idmap_id_res *res) {
13204520Snw141292 	switch (idtype) {
13214520Snw141292 	case IDMAP_UID:
13224520Snw141292 		if (type != _IDMAP_T_USER)
13234520Snw141292 			return (IDMAP_ERR_NOTUSER);
13244520Snw141292 		res->id.idtype = IDMAP_UID;
13254520Snw141292 		break;
13264520Snw141292 	case IDMAP_GID:
13274520Snw141292 		if (type != _IDMAP_T_GROUP)
13284520Snw141292 			return (IDMAP_ERR_NOTGROUP);
13294520Snw141292 		res->id.idtype = IDMAP_GID;
13304520Snw141292 		break;
13314520Snw141292 	case IDMAP_POSIXID:
13324520Snw141292 		if (type == _IDMAP_T_USER)
13334520Snw141292 			res->id.idtype = IDMAP_UID;
13344520Snw141292 		else if (type == _IDMAP_T_GROUP)
13354520Snw141292 			res->id.idtype = IDMAP_GID;
13364520Snw141292 		else
13374520Snw141292 			return (IDMAP_ERR_SID);
13384520Snw141292 		break;
13394520Snw141292 	default:
13404520Snw141292 		return (IDMAP_ERR_NOTSUPPORTED);
13414520Snw141292 	}
13424520Snw141292 	return (IDMAP_SUCCESS);
13434520Snw141292 }
13444520Snw141292 
13454520Snw141292 /*
13464864Sbaban  * Lookup sid to name locally
13474520Snw141292  */
13484520Snw141292 static idmap_retcode
13494864Sbaban lookup_local_sid2name(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
13504520Snw141292 	int		type = -1;
13514520Snw141292 	idmap_retcode	retcode;
13524520Snw141292 	char		*sidprefix;
13534520Snw141292 	idmap_rid_t	rid;
13544520Snw141292 	char		*name = NULL, *domain = NULL;
13554520Snw141292 
13564520Snw141292 	sidprefix = req->id1.idmap_id_u.sid.prefix;
13574520Snw141292 	rid = req->id1.idmap_id_u.sid.rid;
13584520Snw141292 
13594864Sbaban 	/* Lookup sids to name in well-known sids table */
13604864Sbaban 	retcode = lookup_wksids_sid2name(sidprefix, rid, &name, &type);
13614864Sbaban 	if (retcode != IDMAP_ERR_NOTFOUND)
13624864Sbaban 		goto out;
13634864Sbaban 
13644520Snw141292 	/* Lookup sid to name in cache */
13654864Sbaban 	retcode = lookup_cache_sid2name(cache, sidprefix, rid, &name,
13664520Snw141292 		&domain, &type);
13674520Snw141292 	if (retcode != IDMAP_SUCCESS)
13684520Snw141292 		goto out;
13694520Snw141292 
13704520Snw141292 out:
13714520Snw141292 	if (retcode == IDMAP_SUCCESS) {
13724864Sbaban 		/* Verify that the sid type matches the request */
13734864Sbaban 		retcode = verify_type(req->id2.idtype, type, res);
13744864Sbaban 
13754520Snw141292 		/* update state in 'req' */
13765064Sdm199847 		if (name != NULL)
13775064Sdm199847 			req->id1name = name;
13785064Sdm199847 		if (domain != NULL)
13795064Sdm199847 			req->id1domain = domain;
13804520Snw141292 	} else {
13814864Sbaban 		if (name != NULL)
13824520Snw141292 			free(name);
13834864Sbaban 		if (domain != NULL)
13844520Snw141292 			free(domain);
13854520Snw141292 	}
13864520Snw141292 	return (retcode);
13874520Snw141292 }
13884520Snw141292 
13894520Snw141292 idmap_retcode
13904520Snw141292 lookup_win_batch_sid2name(lookup_state_t *state, idmap_mapping_batch *batch,
13914520Snw141292 		idmap_ids_res *result) {
13924520Snw141292 	idmap_retcode	retcode;
13934520Snw141292 	int		ret, i;
13944520Snw141292 	int		retries = 0;
13954520Snw141292 	idmap_mapping	*req;
13964520Snw141292 	idmap_id_res	*res;
13974520Snw141292 
13984520Snw141292 	if (state->ad_nqueries == 0)
13994520Snw141292 		return (IDMAP_SUCCESS);
14004520Snw141292 
14014520Snw141292 retry:
14024520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries,
14034520Snw141292 		&state->ad_lookup);
14044520Snw141292 	if (ret != 0) {
1405*5317Sjp151216 		degrade_svc();
14064520Snw141292 		idmapdlog(LOG_ERR,
14074520Snw141292 		"Failed to create sid2name batch for AD lookup");
14084520Snw141292 		return (IDMAP_ERR_INTERNAL);
14094520Snw141292 	}
14104520Snw141292 
1411*5317Sjp151216 	restore_svc();
1412*5317Sjp151216 
14134520Snw141292 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
14144520Snw141292 		req = &batch->idmap_mapping_batch_val[i];
14154520Snw141292 		res = &result->ids.ids_val[i];
14164520Snw141292 
14174520Snw141292 		if (req->id1.idtype == IDMAP_SID &&
14184520Snw141292 				req->direction & _IDMAP_F_S2N_AD) {
14194864Sbaban 			if (retries == 0)
14204864Sbaban 				res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
14214864Sbaban 			else if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
14224864Sbaban 				continue;
14234520Snw141292 			retcode = idmap_sid2name_batch_add1(
14244520Snw141292 					state->ad_lookup,
14254520Snw141292 					req->id1.idmap_id_u.sid.prefix,
14264520Snw141292 					&req->id1.idmap_id_u.sid.rid,
14275064Sdm199847 					&req->id1name,
14285064Sdm199847 					&req->id1domain,
14294520Snw141292 					(int *)&res->id.idtype,
14304520Snw141292 					&res->retcode);
14314520Snw141292 
14324520Snw141292 			if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
14334520Snw141292 				break;
14344520Snw141292 			if (retcode != IDMAP_SUCCESS)
14354520Snw141292 				goto out;
14364520Snw141292 		}
14374520Snw141292 	}
14384520Snw141292 
14394520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
14404884Sjp151216 		idmap_lookup_release_batch(&state->ad_lookup);
14414520Snw141292 	else
14424520Snw141292 		retcode = idmap_lookup_batch_end(&state->ad_lookup, NULL);
14434520Snw141292 
14444520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
14454520Snw141292 		goto retry;
1446*5317Sjp151216 	else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
1447*5317Sjp151216 		degrade_svc();
14484520Snw141292 
14494520Snw141292 	return (retcode);
14504520Snw141292 
14514520Snw141292 out:
14524520Snw141292 	idmapdlog(LOG_NOTICE, "Windows SID to user/group name lookup failed");
14534884Sjp151216 	idmap_lookup_release_batch(&state->ad_lookup);
14544520Snw141292 	return (retcode);
14554520Snw141292 }
14564520Snw141292 
14574520Snw141292 idmap_retcode
14584520Snw141292 sid2pid_first_pass(lookup_state_t *state, sqlite *cache, idmap_mapping *req,
14594520Snw141292 		idmap_id_res *res) {
14604520Snw141292 	idmap_retcode	retcode;
14614520Snw141292 
14624520Snw141292 	/*
14634520Snw141292 	 * The req->direction field is used to maintain state of the
14644520Snw141292 	 * sid2pid request.
14654520Snw141292 	 */
14664520Snw141292 	req->direction = _IDMAP_F_DONE;
14674520Snw141292 
14685127Sdm199847 	if (EMPTY_STRING(req->id1.idmap_id_u.sid.prefix)) {
14694520Snw141292 		retcode = IDMAP_ERR_SID;
14704520Snw141292 		goto out;
14714520Snw141292 	}
14724520Snw141292 	res->id.idtype = req->id2.idtype;
14734520Snw141292 	res->id.idmap_id_u.uid = UID_NOBODY;
14744520Snw141292 
14754864Sbaban 	/* Lookup well-known sid to pid mapping */
14764520Snw141292 	retcode = lookup_wksids_sid2pid(req, res);
14774520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
14784520Snw141292 		goto out;
14794520Snw141292 
14804520Snw141292 	/* Lookup sid to pid in cache */
14814520Snw141292 	retcode = lookup_cache_sid2pid(cache, req, res);
14824520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
14834520Snw141292 		goto out;
14844520Snw141292 
14854520Snw141292 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
14864520Snw141292 		res->id.idmap_id_u.uid = SENTINEL_PID;
14874520Snw141292 		goto out;
14884520Snw141292 	}
14894520Snw141292 
14904520Snw141292 	/*
14914520Snw141292 	 * Failed to find non-expired entry in cache. Tell the caller
14924520Snw141292 	 * that we are not done yet.
14934520Snw141292 	 */
14944520Snw141292 	state->sid2pid_done = FALSE;
14954520Snw141292 
14964520Snw141292 	/*
14974520Snw141292 	 * Our next step is name-based mapping. To lookup name-based
14984520Snw141292 	 * mapping rules, we need the windows name and domain-name
14994520Snw141292 	 * associated with the SID.
15004520Snw141292 	 */
15014520Snw141292 
15024520Snw141292 	/*
15034520Snw141292 	 * Check if we already have the name (i.e name2pid lookups)
15044520Snw141292 	 */
15055127Sdm199847 	if (!EMPTY_STRING(req->id1name) &&
15065127Sdm199847 	    !EMPTY_STRING(req->id1domain)) {
15074520Snw141292 		retcode = IDMAP_SUCCESS;
15084520Snw141292 		req->direction |= _IDMAP_F_S2N_CACHE;
15094520Snw141292 		goto out;
15104520Snw141292 	}
15114520Snw141292 
15124864Sbaban 	/* Lookup sid to winname@domain locally first */
15134864Sbaban 	retcode = lookup_local_sid2name(cache, req, res);
15144864Sbaban 	if (retcode == IDMAP_SUCCESS) {
15154864Sbaban 		req->direction |= _IDMAP_F_S2N_CACHE;
15164864Sbaban 	} else if (retcode == IDMAP_ERR_NOTFOUND) {
15174520Snw141292 		/* Batch sid to name AD lookup request */
15184520Snw141292 		retcode = IDMAP_SUCCESS;
15194520Snw141292 		req->direction |= _IDMAP_F_S2N_AD;
15204520Snw141292 		state->ad_nqueries++;
15214520Snw141292 		goto out;
15224520Snw141292 	}
15234520Snw141292 
15244520Snw141292 
15254520Snw141292 out:
15264520Snw141292 	res->retcode = idmap_stat4prot(retcode);
15274520Snw141292 	return (retcode);
15284520Snw141292 }
15294520Snw141292 
15304520Snw141292 /*
15314520Snw141292  * Generate SID using the following convention
15324520Snw141292  * 	<machine-sid-prefix>-<1000 + uid>
15334520Snw141292  * 	<machine-sid-prefix>-<2^31 + gid>
15344520Snw141292  */
15354520Snw141292 static idmap_retcode
15364520Snw141292 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user) {
15374520Snw141292 
15384864Sbaban 	if (_idmapdstate.cfg->pgcfg.machine_sid != NULL) {
15394520Snw141292 		/* Skip 1000 UIDs */
15404520Snw141292 		if (is_user && req->id1.idmap_id_u.uid >
15414520Snw141292 				(INT32_MAX - LOCALRID_MIN))
15424864Sbaban 			return (IDMAP_ERR_NOMAPPING);
15434520Snw141292 
15444520Snw141292 		RDLOCK_CONFIG();
15454520Snw141292 		res->id.idmap_id_u.sid.prefix =
15464520Snw141292 			strdup(_idmapdstate.cfg->pgcfg.machine_sid);
15474520Snw141292 		if (res->id.idmap_id_u.sid.prefix == NULL) {
15484520Snw141292 			UNLOCK_CONFIG();
15494520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
15504520Snw141292 			return (IDMAP_ERR_MEMORY);
15514520Snw141292 		}
15524520Snw141292 		UNLOCK_CONFIG();
15534520Snw141292 		res->id.idmap_id_u.sid.rid =
15544520Snw141292 			(is_user)?req->id1.idmap_id_u.uid + LOCALRID_MIN:
15554520Snw141292 			req->id1.idmap_id_u.gid + INT32_MAX + 1;
15564644Sbaban 		res->direction = IDMAP_DIRECTION_BI;
15574520Snw141292 
15584520Snw141292 		/*
15594520Snw141292 		 * Don't update name_cache because local sids don't have
15604520Snw141292 		 * valid windows names.
15614520Snw141292 		 * We mark the entry as being found in the namecache so that
15624520Snw141292 		 * the cache update routine doesn't update namecache.
15634520Snw141292 		 */
15644520Snw141292 		req->direction = _IDMAP_F_S2N_CACHE;
15654868Sbaban 		return (IDMAP_SUCCESS);
15664520Snw141292 	}
15674520Snw141292 
15684864Sbaban 	return (IDMAP_ERR_NOMAPPING);
15694520Snw141292 }
15704520Snw141292 
15714520Snw141292 static idmap_retcode
15724520Snw141292 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) {
15734520Snw141292 	char		*sidprefix;
15744520Snw141292 	uint32_t	rid;
15754520Snw141292 	int		s;
15764520Snw141292 
15774520Snw141292 	/*
15784520Snw141292 	 * If the sidprefix == localsid then UID = last RID - 1000 or
15794520Snw141292 	 * GID = last RID - 2^31.
15804520Snw141292 	 */
15814520Snw141292 	sidprefix = req->id1.idmap_id_u.sid.prefix;
15824520Snw141292 	rid = req->id1.idmap_id_u.sid.rid;
15834520Snw141292 
15844520Snw141292 	RDLOCK_CONFIG();
15854520Snw141292 	s = (_idmapdstate.cfg->pgcfg.machine_sid)?
15864520Snw141292 		strcasecmp(sidprefix,
15874520Snw141292 		_idmapdstate.cfg->pgcfg.machine_sid):1;
15884520Snw141292 	UNLOCK_CONFIG();
15894520Snw141292 
15904520Snw141292 	if (s == 0) {
15914520Snw141292 		switch (req->id2.idtype) {
15924520Snw141292 		case IDMAP_UID:
15934520Snw141292 			if (rid > INT32_MAX) {
15944520Snw141292 				return (IDMAP_ERR_NOTUSER);
15954520Snw141292 			} else if (rid < LOCALRID_MIN) {
15964520Snw141292 				return (IDMAP_ERR_NOTFOUND);
15974520Snw141292 			}
15984520Snw141292 			res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
15994520Snw141292 			res->id.idtype = IDMAP_UID;
16004520Snw141292 			break;
16014520Snw141292 		case IDMAP_GID:
16024520Snw141292 			if (rid <= INT32_MAX) {
16034520Snw141292 				return (IDMAP_ERR_NOTGROUP);
16044520Snw141292 			}
16054520Snw141292 			res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
16064520Snw141292 			res->id.idtype = IDMAP_GID;
16074520Snw141292 			break;
16084520Snw141292 		case IDMAP_POSIXID:
16094520Snw141292 			if (rid > INT32_MAX) {
16104520Snw141292 				res->id.idmap_id_u.gid =
16114520Snw141292 					rid - INT32_MAX - 1;
16124520Snw141292 				res->id.idtype = IDMAP_GID;
16134520Snw141292 			} else if (rid < LOCALRID_MIN) {
16144520Snw141292 				return (IDMAP_ERR_NOTFOUND);
16154520Snw141292 			} else {
16164520Snw141292 				res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
16174520Snw141292 				res->id.idtype = IDMAP_UID;
16184520Snw141292 			}
16194520Snw141292 			break;
16204520Snw141292 		default:
16214520Snw141292 			return (IDMAP_ERR_NOTSUPPORTED);
16224520Snw141292 		}
16234520Snw141292 		return (IDMAP_SUCCESS);
16244520Snw141292 	}
16254520Snw141292 
16264520Snw141292 	return (IDMAP_ERR_NOTFOUND);
16274520Snw141292 }
16284520Snw141292 
16294520Snw141292 static idmap_retcode
16304520Snw141292 ns_lookup_byname(int is_user, const char *name, idmap_id_res *res) {
16314520Snw141292 	struct passwd	pwd;
16324520Snw141292 	struct group	grp;
16334520Snw141292 	char		buf[1024];
16344520Snw141292 	int		errnum;
16354520Snw141292 	const char	*me = "ns_lookup_byname";
16364520Snw141292 
16374520Snw141292 	if (is_user) {
16384520Snw141292 		if (getpwnam_r(name, &pwd, buf, sizeof (buf)) == NULL) {
16394520Snw141292 			errnum = errno;
16404520Snw141292 			idmapdlog(LOG_WARNING,
16414520Snw141292 			"%s: getpwnam_r(%s) failed (%s).",
16424520Snw141292 				me, name,
16434520Snw141292 				errnum?strerror(errnum):"not found");
16444520Snw141292 			if (errnum == 0)
16454520Snw141292 				return (IDMAP_ERR_NOTFOUND);
16464520Snw141292 			else
16474520Snw141292 				return (IDMAP_ERR_INTERNAL);
16484520Snw141292 		}
16494520Snw141292 		res->id.idmap_id_u.uid = pwd.pw_uid;
16504520Snw141292 		res->id.idtype = IDMAP_UID;
16514520Snw141292 	} else {
16524520Snw141292 		if (getgrnam_r(name, &grp, buf, sizeof (buf)) == NULL) {
16534520Snw141292 			errnum = errno;
16544520Snw141292 			idmapdlog(LOG_WARNING,
16554520Snw141292 			"%s: getgrnam_r(%s) failed (%s).",
16564520Snw141292 				me, name,
16574520Snw141292 				errnum?strerror(errnum):"not found");
16584520Snw141292 			if (errnum == 0)
16594520Snw141292 				return (IDMAP_ERR_NOTFOUND);
16604520Snw141292 			else
16614520Snw141292 				return (IDMAP_ERR_INTERNAL);
16624520Snw141292 		}
16634520Snw141292 		res->id.idmap_id_u.gid = grp.gr_gid;
16644520Snw141292 		res->id.idtype = IDMAP_GID;
16654520Snw141292 	}
16664520Snw141292 	return (IDMAP_SUCCESS);
16674520Snw141292 }
16684520Snw141292 
16694520Snw141292 /*
16704520Snw141292  * Name-based mapping
16714520Snw141292  *
16724520Snw141292  * Case 1: If no rule matches do ephemeral
16734520Snw141292  *
16744520Snw141292  * Case 2: If rule matches and unixname is "" then return no mapping.
16754520Snw141292  *
16764520Snw141292  * Case 3: If rule matches and unixname is specified then lookup name
16774520Snw141292  *  service using the unixname. If unixname not found then return no mapping.
16784520Snw141292  *
16794520Snw141292  * Case 4: If rule matches and unixname is * then lookup name service
16804520Snw141292  *  using winname as the unixname. If unixname not found then process
16814520Snw141292  *  other rules using the lookup order. If no other rule matches then do
16824520Snw141292  *  ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
16834520Snw141292  *  This allows us to specify a fallback unixname per _domain_ or no mapping
16844520Snw141292  *  instead of the default behaviour of doing ephemeral mapping.
16854520Snw141292  *
16864520Snw141292  * Example 1:
16874520Snw141292  * *@sfbay == *
16884520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16894520Snw141292  * the name service then foo@sfbay will be mapped to an ephemeral id.
16904520Snw141292  *
16914520Snw141292  * Example 2:
16924520Snw141292  * *@sfbay == *
16934520Snw141292  * *@sfbay => guest
16944520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16954520Snw141292  * the name service then foo@sfbay will be mapped to guest.
16964520Snw141292  *
16974520Snw141292  * Example 3:
16984520Snw141292  * *@sfbay == *
16994520Snw141292  * *@sfbay => ""
17004520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
17014520Snw141292  * the name service then we will return no mapping for foo@sfbay.
17024520Snw141292  *
17034520Snw141292  */
17044520Snw141292 static idmap_retcode
17054520Snw141292 name_based_mapping_sid2pid(sqlite *db, idmap_mapping *req, idmap_id_res *res) {
17064520Snw141292 	const char	*unixname, *winname, *windomain;
17074520Snw141292 	char		*sql = NULL, *errmsg = NULL;
17084520Snw141292 	idmap_retcode	retcode;
17094520Snw141292 	char		*end;
17104520Snw141292 	const char	**values;
17114520Snw141292 	sqlite_vm	*vm = NULL;
17124884Sjp151216 	int		ncol, r, i, is_user;
17134520Snw141292 	const char	*me = "name_based_mapping_sid2pid";
17144520Snw141292 
17155064Sdm199847 	winname = req->id1name;
17165064Sdm199847 	windomain = req->id1domain;
17174520Snw141292 	is_user = (res->id.idtype == IDMAP_UID)?1:0;
17184520Snw141292 
17194520Snw141292 	i = 0;
17204864Sbaban 	if (windomain == NULL) {
17214864Sbaban 		windomain = "";
17224864Sbaban 	} else {
17234864Sbaban 		RDLOCK_CONFIG();
1724*5317Sjp151216 		if (_idmapdstate.cfg->pgcfg.default_domain != NULL) {
1725*5317Sjp151216 			if (strcasecmp(_idmapdstate.cfg->pgcfg.default_domain,
17264864Sbaban 			    windomain) == 0)
17274864Sbaban 				i = 1;
17284864Sbaban 		}
17294864Sbaban 		UNLOCK_CONFIG();
17304520Snw141292 	}
17314520Snw141292 
17324520Snw141292 	sql = sqlite_mprintf(
17334520Snw141292 		"SELECT unixname, u2w_order FROM namerules WHERE "
17344520Snw141292 		"w2u_order > 0 AND is_user = %d AND "
17354520Snw141292 		"(winname = %Q OR winname = '*') AND "
17364520Snw141292 		"(windomain = %Q OR windomain = '*' %s) "
17374520Snw141292 		"ORDER BY w2u_order ASC;",
17384864Sbaban 		is_user, winname,
17394864Sbaban 		windomain,
17404864Sbaban 		i?"OR windomain ISNULL OR windomain = ''":"");
17414520Snw141292 	if (sql == NULL) {
17424520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
17434520Snw141292 		retcode = IDMAP_ERR_MEMORY;
17444520Snw141292 		goto out;
17454520Snw141292 	}
17464520Snw141292 
17474520Snw141292 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
17484520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
17494520Snw141292 		idmapdlog(LOG_ERR,
17504520Snw141292 			"%s: database error (%s)",
17514520Snw141292 			me, CHECK_NULL(errmsg));
17524520Snw141292 		sqlite_freemem(errmsg);
17534520Snw141292 		goto out;
17544520Snw141292 	}
17554520Snw141292 
17564884Sjp151216 	for (; ; ) {
17574520Snw141292 		r = sqlite_step(vm, &ncol, &values, NULL);
17584884Sjp151216 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
17594884Sjp151216 
17604884Sjp151216 		if (r == SQLITE_ROW) {
17614520Snw141292 			if (ncol < 2) {
17624520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
17634520Snw141292 				goto out;
17644520Snw141292 			}
17654520Snw141292 			if (values[0] == NULL) {
17664520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
17674520Snw141292 				goto out;
17684520Snw141292 			}
17694520Snw141292 
17704520Snw141292 			if (EMPTY_NAME(values[0])) {
17714520Snw141292 				retcode = IDMAP_ERR_NOMAPPING;
17724520Snw141292 				goto out;
17734520Snw141292 			}
17744520Snw141292 			unixname = (values[0][0] == '*')?winname:values[0];
17754520Snw141292 			retcode = ns_lookup_byname(is_user, unixname, res);
17764520Snw141292 			if (retcode == IDMAP_ERR_NOTFOUND) {
17774520Snw141292 				if (unixname == winname)
17784520Snw141292 					/* Case 4 */
17794520Snw141292 					continue;
17804520Snw141292 				else
17814520Snw141292 					/* Case 3 */
17824520Snw141292 					retcode = IDMAP_ERR_NOMAPPING;
17834520Snw141292 			}
17844520Snw141292 			goto out;
17854520Snw141292 		} else if (r == SQLITE_DONE) {
17864520Snw141292 			retcode = IDMAP_ERR_NOTFOUND;
17874520Snw141292 			goto out;
17884520Snw141292 		} else {
17894520Snw141292 			(void) sqlite_finalize(vm, &errmsg);
17904520Snw141292 			vm = NULL;
17914520Snw141292 			idmapdlog(LOG_ERR,
17924520Snw141292 				"%s: database error (%s)",
17934520Snw141292 				me, CHECK_NULL(errmsg));
17944520Snw141292 			sqlite_freemem(errmsg);
17954520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
17964520Snw141292 			goto out;
17974520Snw141292 		}
17984520Snw141292 	}
17994520Snw141292 
18004520Snw141292 out:
18014864Sbaban 	if (sql != NULL)
18024520Snw141292 		sqlite_freemem(sql);
18034520Snw141292 	if (retcode == IDMAP_SUCCESS) {
18044864Sbaban 		if (values[1] != NULL)
18054520Snw141292 			res->direction =
18064644Sbaban 			    (strtol(values[1], &end, 10) == 0)?
18074644Sbaban 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
18084520Snw141292 		else
18094644Sbaban 			res->direction = IDMAP_DIRECTION_W2U;
18105064Sdm199847 		req->id2name = strdup(unixname);
18114520Snw141292 	}
18124864Sbaban 	if (vm != NULL)
18134520Snw141292 		(void) sqlite_finalize(vm, NULL);
18144520Snw141292 	return (retcode);
18154520Snw141292 }
18164520Snw141292 
18174520Snw141292 static
18184520Snw141292 int
18194520Snw141292 get_next_eph_uid(uid_t *next_uid)
18204520Snw141292 {
18214520Snw141292 	uid_t uid;
18224520Snw141292 	gid_t gid;
18234520Snw141292 	int err;
18244520Snw141292 
18254520Snw141292 	*next_uid = (uid_t)-1;
18264520Snw141292 	uid = _idmapdstate.next_uid++;
18274520Snw141292 	if (uid >= _idmapdstate.limit_uid) {
18284520Snw141292 		if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0)
18294520Snw141292 			return (err);
18304520Snw141292 
18314520Snw141292 		_idmapdstate.limit_uid = uid + 8192;
18324520Snw141292 		_idmapdstate.next_uid = uid;
18334520Snw141292 	}
18344520Snw141292 	*next_uid = uid;
18354520Snw141292 
18364520Snw141292 	return (0);
18374520Snw141292 }
18384520Snw141292 
18394520Snw141292 static
18404520Snw141292 int
18414520Snw141292 get_next_eph_gid(gid_t *next_gid)
18424520Snw141292 {
18434520Snw141292 	uid_t uid;
18444520Snw141292 	gid_t gid;
18454520Snw141292 	int err;
18464520Snw141292 
18474520Snw141292 	*next_gid = (uid_t)-1;
18484520Snw141292 	gid = _idmapdstate.next_gid++;
18494520Snw141292 	if (gid >= _idmapdstate.limit_gid) {
18504520Snw141292 		if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0)
18514520Snw141292 			return (err);
18524520Snw141292 
18534520Snw141292 		_idmapdstate.limit_gid = gid + 8192;
18544520Snw141292 		_idmapdstate.next_gid = gid;
18554520Snw141292 	}
18564520Snw141292 	*next_gid = gid;
18574520Snw141292 
18584520Snw141292 	return (0);
18594520Snw141292 }
18604520Snw141292 
18614864Sbaban static
18624864Sbaban int
18634864Sbaban gethash(const char *str, uint32_t num, uint_t htsize) {
18644864Sbaban 	uint_t  hval, i, len;
18654864Sbaban 
18664864Sbaban 	if (str == NULL)
18674864Sbaban 		return (0);
18684864Sbaban 	for (len = strlen(str), hval = 0, i = 0; i < len; i++) {
18694864Sbaban 		hval += str[i];
18704864Sbaban 		hval += (hval << 10);
18714864Sbaban 		hval ^= (hval >> 6);
18724864Sbaban 	}
18734864Sbaban 	for (str = (const char *)&num, i = 0; i < sizeof (num); i++) {
18744864Sbaban 		hval += str[i];
18754864Sbaban 		hval += (hval << 10);
18764864Sbaban 		hval ^= (hval >> 6);
18774864Sbaban 	}
18784864Sbaban 	hval += (hval << 3);
18794864Sbaban 	hval ^= (hval >> 11);
18804864Sbaban 	hval += (hval << 15);
18814864Sbaban 	return (hval % htsize);
18824864Sbaban }
18834864Sbaban 
18844864Sbaban static
18854864Sbaban int
18864864Sbaban get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid,
18874864Sbaban 		uid_t *pid) {
18884864Sbaban 	uint_t		next, key;
18894864Sbaban 	uint_t		htsize = state->sid_history_size;
18904864Sbaban 	idmap_sid	*sid;
18914864Sbaban 
18924864Sbaban 	next = gethash(prefix, rid, htsize);
18934864Sbaban 	while (next != htsize) {
18944864Sbaban 		key = state->sid_history[next].key;
18954864Sbaban 		if (key == htsize)
18964864Sbaban 			return (0);
18974864Sbaban 		sid = &state->batch->idmap_mapping_batch_val[key].id1.
18984864Sbaban 		    idmap_id_u.sid;
18994864Sbaban 		if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) {
19004864Sbaban 			*pid = state->result->ids.ids_val[key].id.
19014864Sbaban 			    idmap_id_u.uid;
19024864Sbaban 			return (1);
19034864Sbaban 		}
19044864Sbaban 		next = state->sid_history[next].next;
19054864Sbaban 	}
19064864Sbaban 	return (0);
19074864Sbaban }
19084864Sbaban 
19094864Sbaban static
19104864Sbaban void
19114864Sbaban add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) {
19124864Sbaban 	uint_t		hash, next;
19134864Sbaban 	uint_t		htsize = state->sid_history_size;
19144864Sbaban 
19154864Sbaban 	hash = next = gethash(prefix, rid, htsize);
19164864Sbaban 	while (state->sid_history[next].key != htsize) {
19174864Sbaban 		next++;
19184864Sbaban 		next %= htsize;
19194864Sbaban 	}
19204864Sbaban 	state->sid_history[next].key = state->curpos;
19214864Sbaban 	if (hash == next)
19224864Sbaban 		return;
19234864Sbaban 	state->sid_history[next].next = state->sid_history[hash].next;
19244864Sbaban 	state->sid_history[hash].next = next;
19254864Sbaban }
19264520Snw141292 
19274520Snw141292 /* ARGSUSED */
19284520Snw141292 static
19294520Snw141292 idmap_retcode
19304864Sbaban dynamic_ephemeral_mapping(lookup_state_t *state, sqlite *cache,
19314864Sbaban 		idmap_mapping *req, idmap_id_res *res) {
19324520Snw141292 
19334520Snw141292 	uid_t		next_pid;
19344520Snw141292 
19354864Sbaban 	res->direction = IDMAP_DIRECTION_BI;
19364864Sbaban 
19374864Sbaban 	if (IS_EPHEMERAL(res->id.idmap_id_u.uid))
19384864Sbaban 		return (IDMAP_SUCCESS);
19394864Sbaban 
19404864Sbaban 	if (state->sid_history != NULL &&
19414864Sbaban 	    get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix,
19424864Sbaban 	    req->id1.idmap_id_u.sid.rid, &next_pid)) {
19434864Sbaban 		res->id.idmap_id_u.uid = next_pid;
19444864Sbaban 		return (IDMAP_SUCCESS);
19454864Sbaban 	}
19464864Sbaban 
19474864Sbaban 	if (res->id.idtype == IDMAP_UID) {
19484520Snw141292 		if (get_next_eph_uid(&next_pid) != 0)
19494520Snw141292 			return (IDMAP_ERR_INTERNAL);
19504520Snw141292 		res->id.idmap_id_u.uid = next_pid;
19514520Snw141292 	} else {
19524520Snw141292 		if (get_next_eph_gid(&next_pid) != 0)
19534520Snw141292 			return (IDMAP_ERR_INTERNAL);
19544520Snw141292 		res->id.idmap_id_u.gid = next_pid;
19554520Snw141292 	}
19564520Snw141292 
19574864Sbaban 	if (state->sid_history != NULL)
19584864Sbaban 		add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix,
19594864Sbaban 		    req->id1.idmap_id_u.sid.rid);
19604864Sbaban 
19614520Snw141292 	return (IDMAP_SUCCESS);
19624520Snw141292 }
19634520Snw141292 
19644520Snw141292 idmap_retcode
19654520Snw141292 sid2pid_second_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
19664520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
19674520Snw141292 	idmap_retcode	retcode;
19684520Snw141292 
19694520Snw141292 	/*
19704520Snw141292 	 * The req->direction field is used to maintain state of the
19714520Snw141292 	 * sid2pid request.
19724520Snw141292 	 */
19734520Snw141292 
19744520Snw141292 	/* Check if second pass is needed */
19754520Snw141292 	if (req->direction == _IDMAP_F_DONE)
19764520Snw141292 		return (res->retcode);
19774520Snw141292 
19784520Snw141292 	/* Get status from previous pass */
19794520Snw141292 	retcode = (res->retcode == IDMAP_NEXT)?IDMAP_SUCCESS:res->retcode;
19804520Snw141292 
19814520Snw141292 	if (retcode != IDMAP_SUCCESS) {
19824520Snw141292 		/* Reset return type */
19834520Snw141292 		res->id.idtype = req->id2.idtype;
19844520Snw141292 		res->id.idmap_id_u.uid = UID_NOBODY;
19854520Snw141292 
19864520Snw141292 		/* Check if this is a localsid */
19874520Snw141292 		if (retcode == IDMAP_ERR_NOTFOUND &&
19884864Sbaban 		    _idmapdstate.cfg->pgcfg.machine_sid) {
19894520Snw141292 			retcode = lookup_localsid2pid(req, res);
19904520Snw141292 			if (retcode == IDMAP_SUCCESS) {
19914520Snw141292 				state->sid2pid_done = FALSE;
19924520Snw141292 				req->direction = _IDMAP_F_S2N_CACHE;
19934520Snw141292 			}
19944520Snw141292 		}
19954520Snw141292 		goto out;
19964520Snw141292 	}
19974520Snw141292 
19984520Snw141292 	/*
19994520Snw141292 	 * Verify that the sid type matches the request if the
20004520Snw141292 	 * SID was validated by an AD lookup.
20014520Snw141292 	 */
20024520Snw141292 	if (req->direction & _IDMAP_F_S2N_AD) {
20034520Snw141292 		retcode = verify_type(req->id2.idtype,
20044520Snw141292 			(int)res->id.idtype, res);
20054520Snw141292 		if (retcode != IDMAP_SUCCESS) {
20064520Snw141292 			res->id.idtype = req->id2.idtype;
20074520Snw141292 			res->id.idmap_id_u.uid = UID_NOBODY;
20084520Snw141292 			goto out;
20094520Snw141292 		}
20104520Snw141292 	}
20114520Snw141292 
20124520Snw141292 	/* Name-based mapping */
20134520Snw141292 	retcode = name_based_mapping_sid2pid(db, req, res);
20144520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND)
20154520Snw141292 		/* If not found, do ephemeral mapping */
20164520Snw141292 		goto ephemeral;
20174520Snw141292 	else if (retcode != IDMAP_SUCCESS)
20184520Snw141292 		goto out;
20194520Snw141292 
20204520Snw141292 	state->sid2pid_done = FALSE;
20214520Snw141292 	goto out;
20224520Snw141292 
20234520Snw141292 
20244520Snw141292 ephemeral:
20254864Sbaban 	retcode = dynamic_ephemeral_mapping(state, cache, req, res);
20264520Snw141292 	if (retcode == IDMAP_SUCCESS)
20274520Snw141292 		state->sid2pid_done = FALSE;
20284520Snw141292 
20294520Snw141292 out:
20304520Snw141292 	res->retcode = idmap_stat4prot(retcode);
20314520Snw141292 	return (retcode);
20324520Snw141292 }
20334520Snw141292 
20344520Snw141292 idmap_retcode
20354520Snw141292 update_cache_pid2sid(lookup_state_t *state, sqlite *cache,
20364520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
20374520Snw141292 	char		*sql = NULL;
20384520Snw141292 	idmap_retcode	retcode;
20394520Snw141292 
20404520Snw141292 	/* Check if we need to cache anything */
20414520Snw141292 	if (req->direction == _IDMAP_F_DONE)
20424520Snw141292 		return (IDMAP_SUCCESS);
20434520Snw141292 
20444520Snw141292 	/* We don't cache negative entries */
20454520Snw141292 	if (res->retcode != IDMAP_SUCCESS)
20464520Snw141292 		return (IDMAP_SUCCESS);
20474520Snw141292 
20484520Snw141292 	/*
20494520Snw141292 	 * Using NULL for u2w instead of 0 so that our trigger allows
20504520Snw141292 	 * the same pid to be the destination in multiple entries
20514520Snw141292 	 */
20524520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
20534520Snw141292 		"(sidprefix, rid, windomain, winname, pid, unixname, "
20544520Snw141292 		"is_user, expiration, w2u, u2w) "
20554520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
20564520Snw141292 		"strftime('%%s','now') + 600, %q, 1); ",
20574520Snw141292 		res->id.idmap_id_u.sid.prefix,
20584520Snw141292 		res->id.idmap_id_u.sid.rid,
20595064Sdm199847 		req->id2domain,
20605064Sdm199847 		req->id2name,
20614520Snw141292 		req->id1.idmap_id_u.uid,
20625064Sdm199847 		req->id1name,
20634520Snw141292 		(req->id1.idtype == IDMAP_UID)?1:0,
20644520Snw141292 		(res->direction == 0)?"1":NULL);
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 	if (retcode != IDMAP_SUCCESS)
20744520Snw141292 		goto out;
20754520Snw141292 
20764520Snw141292 	state->pid2sid_done = FALSE;
20774520Snw141292 	sqlite_freemem(sql);
20784520Snw141292 	sql = NULL;
20794520Snw141292 
20804520Snw141292 	/* If sid2name was found in the cache, no need to update namecache */
20814520Snw141292 	if (req->direction & _IDMAP_F_S2N_CACHE)
20824520Snw141292 		goto out;
20834520Snw141292 
20845064Sdm199847 	if (req->id2name == NULL)
20854520Snw141292 		goto out;
20864520Snw141292 
20874520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
20884520Snw141292 		"(sidprefix, rid, name, domain, type, expiration) "
20894520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
20904520Snw141292 		res->id.idmap_id_u.sid.prefix,
20914520Snw141292 		res->id.idmap_id_u.sid.rid,
20925064Sdm199847 		req->id2name,
20935064Sdm199847 		req->id2domain,
20944520Snw141292 		(req->id1.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
20954520Snw141292 
20964520Snw141292 	if (sql == NULL) {
20974520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
20984520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
20994520Snw141292 		goto out;
21004520Snw141292 	}
21014520Snw141292 
21024520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
21034520Snw141292 
21044520Snw141292 out:
21054864Sbaban 	if (sql != NULL)
21064520Snw141292 		sqlite_freemem(sql);
21074520Snw141292 	return (retcode);
21084520Snw141292 }
21094520Snw141292 
21104520Snw141292 idmap_retcode
21114520Snw141292 update_cache_sid2pid(lookup_state_t *state, sqlite *cache,
21124520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
21134520Snw141292 	char		*sql = NULL;
21144520Snw141292 	idmap_retcode	retcode;
21154520Snw141292 	int		is_eph_user;
21164520Snw141292 
21174520Snw141292 	/* Check if we need to cache anything */
21184520Snw141292 	if (req->direction == _IDMAP_F_DONE)
21194520Snw141292 		return (IDMAP_SUCCESS);
21204520Snw141292 
21214520Snw141292 	/* We don't cache negative entries */
21224520Snw141292 	if (res->retcode != IDMAP_SUCCESS)
21234520Snw141292 		return (IDMAP_SUCCESS);
21244520Snw141292 
21254520Snw141292 	if (req->direction & _IDMAP_F_EXP_EPH_UID)
21264520Snw141292 		is_eph_user = 1;
21274520Snw141292 	else if (req->direction & _IDMAP_F_EXP_EPH_GID)
21284520Snw141292 		is_eph_user = 0;
21294520Snw141292 	else
21304520Snw141292 		is_eph_user = -1;
21314520Snw141292 
21324520Snw141292 	if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
21334520Snw141292 		sql = sqlite_mprintf("UPDATE idmap_cache "
21344520Snw141292 			"SET w2u = 0 WHERE "
21354520Snw141292 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
21364520Snw141292 			"pid >= 2147483648 AND is_user = %d;",
21374520Snw141292 			req->id1.idmap_id_u.sid.prefix,
21384520Snw141292 			req->id1.idmap_id_u.sid.rid,
21394520Snw141292 			is_eph_user);
21404520Snw141292 		if (sql == NULL) {
21414520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
21424520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
21434520Snw141292 			goto out;
21444520Snw141292 		}
21454520Snw141292 
21464520Snw141292 		retcode = sql_exec_no_cb(cache, sql);
21474520Snw141292 		if (retcode != IDMAP_SUCCESS)
21484520Snw141292 			goto out;
21494520Snw141292 
21504520Snw141292 		sqlite_freemem(sql);
21514520Snw141292 		sql = NULL;
21524520Snw141292 	}
21534520Snw141292 
21544520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
21554520Snw141292 		"(sidprefix, rid, windomain, winname, pid, unixname, "
21564520Snw141292 		"is_user, expiration, w2u, u2w) "
21574520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
21584520Snw141292 		"strftime('%%s','now') + 600, 1, %q); ",
21594520Snw141292 		req->id1.idmap_id_u.sid.prefix,
21604520Snw141292 		req->id1.idmap_id_u.sid.rid,
21615064Sdm199847 		req->id1domain,
21625064Sdm199847 		req->id1name,
21634520Snw141292 		res->id.idmap_id_u.uid,
21645064Sdm199847 		req->id2name,
21654520Snw141292 		(res->id.idtype == IDMAP_UID)?1:0,
21664520Snw141292 		(res->direction == 0)?"1":NULL);
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 	if (retcode != IDMAP_SUCCESS)
21764520Snw141292 		goto out;
21774520Snw141292 
21784520Snw141292 	state->sid2pid_done = FALSE;
21794520Snw141292 	sqlite_freemem(sql);
21804520Snw141292 	sql = NULL;
21814520Snw141292 
21824520Snw141292 	/* If name2sid was found in the cache, no need to update namecache */
21834520Snw141292 	if (req->direction & _IDMAP_F_S2N_CACHE)
21844520Snw141292 		goto out;
21854520Snw141292 
21865127Sdm199847 	if (EMPTY_STRING(req->id1name))
21874520Snw141292 		goto out;
21884520Snw141292 
21894520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
21904520Snw141292 		"(sidprefix, rid, name, domain, type, expiration) "
21914520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
21924520Snw141292 		req->id1.idmap_id_u.sid.prefix,
21934520Snw141292 		req->id1.idmap_id_u.sid.rid,
21945064Sdm199847 		req->id1name,
21955064Sdm199847 		req->id1domain,
21964520Snw141292 		(res->id.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
21974520Snw141292 
21984520Snw141292 	if (sql == NULL) {
21994520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
22004520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
22014520Snw141292 		goto out;
22024520Snw141292 	}
22034520Snw141292 
22044520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
22054520Snw141292 
22064520Snw141292 out:
22074864Sbaban 	if (sql != NULL)
22084520Snw141292 		sqlite_freemem(sql);
22094520Snw141292 	return (retcode);
22104520Snw141292 }
22114520Snw141292 
22124520Snw141292 static idmap_retcode
22134520Snw141292 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
22144520Snw141292 		int is_user, int getname) {
22154520Snw141292 	char		*end;
22164520Snw141292 	char		*sql = NULL;
22174520Snw141292 	const char	**values;
22184520Snw141292 	sqlite_vm	*vm = NULL;
22194520Snw141292 	int		ncol;
22204520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
22214520Snw141292 	time_t		curtime;
22224520Snw141292 
22234520Snw141292 	/* Current time */
22244520Snw141292 	errno = 0;
22254520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
22264520Snw141292 		idmapdlog(LOG_ERR,
22274520Snw141292 			"Failed to get current time (%s)",
22284520Snw141292 			strerror(errno));
22294520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
22304520Snw141292 		goto out;
22314520Snw141292 	}
22324520Snw141292 
22334520Snw141292 	/* SQL to lookup the cache */
22344520Snw141292 	sql = sqlite_mprintf("SELECT sidprefix, rid, winname, windomain, w2u "
22354520Snw141292 			"FROM idmap_cache WHERE "
22364520Snw141292 			"pid = %u AND u2w = 1 AND is_user = %d AND "
22374520Snw141292 			"(pid >= 2147483648 OR "
22384520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
22394520Snw141292 			"expiration > %d));",
22404520Snw141292 			req->id1.idmap_id_u.uid, is_user, curtime);
22414520Snw141292 	if (sql == NULL) {
22424520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
22434520Snw141292 		retcode = IDMAP_ERR_MEMORY;
22444520Snw141292 		goto out;
22454520Snw141292 	}
22464520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
22474520Snw141292 	sqlite_freemem(sql);
22484520Snw141292 
22494520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND)
22504520Snw141292 		goto out;
22514520Snw141292 	else if (retcode == IDMAP_SUCCESS) {
22524520Snw141292 		/* sanity checks */
22534520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
22544520Snw141292 			retcode = IDMAP_ERR_CACHE;
22554520Snw141292 			goto out;
22564520Snw141292 		}
22574520Snw141292 
22584520Snw141292 		switch (req->id2.idtype) {
22594520Snw141292 		case IDMAP_SID:
22604520Snw141292 			res->id.idmap_id_u.sid.rid =
22614520Snw141292 				strtoul(values[1], &end, 10);
22624520Snw141292 			res->id.idmap_id_u.sid.prefix = strdup(values[0]);
22634520Snw141292 			if (res->id.idmap_id_u.sid.prefix == NULL) {
22644520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22654520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22664520Snw141292 				goto out;
22674520Snw141292 			}
22684520Snw141292 
22694864Sbaban 			if (values[4] != NULL)
22704520Snw141292 				res->direction =
22714644Sbaban 				    (strtol(values[4], &end, 10) == 0)?
22724644Sbaban 				    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
22734520Snw141292 			else
22744644Sbaban 				res->direction = IDMAP_DIRECTION_U2W;
22754520Snw141292 
22764520Snw141292 			if (getname == 0 || values[2] == NULL)
22774520Snw141292 				break;
22785064Sdm199847 			req->id2name = strdup(values[2]);
22795064Sdm199847 			if (req->id2name == NULL) {
22804520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22814520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22824520Snw141292 				goto out;
22834520Snw141292 			}
22844520Snw141292 
22854520Snw141292 			if (values[3] == NULL)
22864520Snw141292 				break;
22875064Sdm199847 			req->id2domain = strdup(values[3]);
22885064Sdm199847 			if (req->id2domain == NULL) {
22894520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22904520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22914520Snw141292 				goto out;
22924520Snw141292 			}
22934520Snw141292 			break;
22944520Snw141292 		default:
22954520Snw141292 			retcode = IDMAP_ERR_NOTSUPPORTED;
22964520Snw141292 			break;
22974520Snw141292 		}
22984520Snw141292 	}
22994520Snw141292 
23004520Snw141292 out:
23014864Sbaban 	if (vm != NULL)
23024520Snw141292 		(void) sqlite_finalize(vm, NULL);
23034520Snw141292 	return (retcode);
23044520Snw141292 }
23054520Snw141292 
23064520Snw141292 static idmap_retcode
23074520Snw141292 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain,
23084520Snw141292 		char **sidprefix, idmap_rid_t *rid, int *type) {
23094520Snw141292 	char		*end;
23104520Snw141292 	char		*sql = NULL;
23114520Snw141292 	const char	**values;
23124520Snw141292 	sqlite_vm	*vm = NULL;
23134520Snw141292 	int		ncol;
23144520Snw141292 	time_t		curtime;
23154520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
23164520Snw141292 
23174520Snw141292 	/* Get current time */
23184520Snw141292 	errno = 0;
23194520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
23204520Snw141292 		idmapdlog(LOG_ERR,
23214520Snw141292 			"Failed to get current time (%s)",
23224520Snw141292 			strerror(errno));
23234520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
23244520Snw141292 		goto out;
23254520Snw141292 	}
23264520Snw141292 
23274520Snw141292 	/* SQL to lookup the cache */
23284520Snw141292 	sql = sqlite_mprintf("SELECT sidprefix, rid, type FROM name_cache "
23294520Snw141292 			"WHERE name = %Q AND domain = %Q AND "
23304520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
23314520Snw141292 			"expiration > %d);",
23324520Snw141292 			name, domain, curtime);
23334520Snw141292 	if (sql == NULL) {
23344520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
23354520Snw141292 		retcode = IDMAP_ERR_MEMORY;
23364520Snw141292 		goto out;
23374520Snw141292 	}
23384520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
23394520Snw141292 	sqlite_freemem(sql);
23404520Snw141292 
23414520Snw141292 	if (retcode == IDMAP_SUCCESS) {
23424864Sbaban 		if (type != NULL) {
23434520Snw141292 			if (values[2] == NULL) {
23444520Snw141292 				retcode = IDMAP_ERR_CACHE;
23454520Snw141292 				goto out;
23464520Snw141292 			}
23474520Snw141292 			*type = strtol(values[2], &end, 10);
23484520Snw141292 		}
23494520Snw141292 
23504520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
23514520Snw141292 			retcode = IDMAP_ERR_CACHE;
23524520Snw141292 			goto out;
23534520Snw141292 		}
23544520Snw141292 		if ((*sidprefix = strdup(values[0])) == NULL) {
23554520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
23564520Snw141292 			retcode = IDMAP_ERR_MEMORY;
23574520Snw141292 			goto out;
23584520Snw141292 		}
23594520Snw141292 		*rid = strtoul(values[1], &end, 10);
23604520Snw141292 	}
23614520Snw141292 
23624520Snw141292 out:
23634864Sbaban 	if (vm != NULL)
23644520Snw141292 		(void) sqlite_finalize(vm, NULL);
23654520Snw141292 	return (retcode);
23664520Snw141292 }
23674520Snw141292 
23684520Snw141292 static idmap_retcode
23694520Snw141292 lookup_win_name2sid(const char *name, const char *domain, char **sidprefix,
23704520Snw141292 		idmap_rid_t *rid, int *type) {
23714520Snw141292 	int			ret;
23724520Snw141292 	int			retries = 0;
23734520Snw141292 	idmap_query_state_t	*qs = NULL;
23744520Snw141292 	idmap_retcode		rc, retcode;
23754520Snw141292 
23764520Snw141292 	retcode = IDMAP_ERR_NOTFOUND;
23774520Snw141292 
23784520Snw141292 retry:
23794520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
23804520Snw141292 	if (ret != 0) {
2381*5317Sjp151216 		degrade_svc();
23824520Snw141292 		idmapdlog(LOG_ERR,
23834520Snw141292 		"Failed to create name2sid batch for AD lookup");
23844520Snw141292 		return (IDMAP_ERR_INTERNAL);
23854520Snw141292 	}
23864520Snw141292 
2387*5317Sjp151216 	restore_svc();
2388*5317Sjp151216 
23894520Snw141292 	retcode = idmap_name2sid_batch_add1(qs, name, domain, sidprefix,
23904520Snw141292 					rid, type, &rc);
23914520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
23924520Snw141292 		goto out;
23934520Snw141292 
23944520Snw141292 	if (retcode != IDMAP_SUCCESS) {
23954520Snw141292 		idmapdlog(LOG_ERR,
23964520Snw141292 		"Failed to batch name2sid for AD lookup");
23974884Sjp151216 		idmap_lookup_release_batch(&qs);
23984520Snw141292 		return (IDMAP_ERR_INTERNAL);
23994520Snw141292 	}
24004520Snw141292 
24014520Snw141292 out:
24024520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
24034884Sjp151216 		idmap_lookup_release_batch(&qs);
24044520Snw141292 	else
24054520Snw141292 		retcode = idmap_lookup_batch_end(&qs, NULL);
24064520Snw141292 
24074520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
24084520Snw141292 		goto retry;
2409*5317Sjp151216 	else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
2410*5317Sjp151216 		degrade_svc();
24114520Snw141292 
24124520Snw141292 	if (retcode != IDMAP_SUCCESS) {
24134520Snw141292 		idmapdlog(LOG_NOTICE, "Windows user/group name to SID lookup "
24144520Snw141292 		    "failed");
24154520Snw141292 		return (retcode);
24164520Snw141292 	} else
24174520Snw141292 		return (rc);
24184520Snw141292 	/* NOTREACHED */
24194520Snw141292 }
24204520Snw141292 
24214520Snw141292 static idmap_retcode
24224520Snw141292 lookup_name2sid(sqlite *cache, const char *name, const char *domain,
24234520Snw141292 		int *is_user, char **sidprefix, idmap_rid_t *rid,
24244520Snw141292 		idmap_mapping *req) {
24254520Snw141292 	int		type;
24264520Snw141292 	idmap_retcode	retcode;
24274520Snw141292 
24284864Sbaban 	/* Lookup name@domain to sid in the well-known sids table */
24294864Sbaban 	retcode = lookup_wksids_name2sid(name, sidprefix, rid, &type);
24304864Sbaban 	if (retcode == IDMAP_SUCCESS) {
24314864Sbaban 		req->direction |= _IDMAP_F_S2N_CACHE;
24324864Sbaban 		goto out;
24334864Sbaban 	} else if (retcode != IDMAP_ERR_NOTFOUND) {
24344864Sbaban 		return (retcode);
24354864Sbaban 	}
24364864Sbaban 
24374864Sbaban 	/* Lookup name@domain to sid in cache */
24384520Snw141292 	retcode = lookup_cache_name2sid(cache, name, domain, sidprefix,
24394520Snw141292 		rid, &type);
24404520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
24414520Snw141292 		/* Lookup Windows NT/AD to map name@domain to sid */
24424520Snw141292 		retcode = lookup_win_name2sid(name, domain, sidprefix, rid,
24434520Snw141292 			&type);
24444520Snw141292 		if (retcode != IDMAP_SUCCESS)
24454520Snw141292 			return (retcode);
24464520Snw141292 		req->direction |= _IDMAP_F_S2N_AD;
24474520Snw141292 	} else if (retcode != IDMAP_SUCCESS) {
24484520Snw141292 		return (retcode);
24494520Snw141292 	} else {
24504520Snw141292 		/* Set flag */
24514520Snw141292 		req->direction |= _IDMAP_F_S2N_CACHE;
24524520Snw141292 	}
24534520Snw141292 
24544864Sbaban out:
24554520Snw141292 	/*
24564520Snw141292 	 * Entry found (cache or Windows lookup)
24574520Snw141292 	 * is_user is both input as well as output parameter
24584520Snw141292 	 */
24594520Snw141292 	if (*is_user == 1) {
24604520Snw141292 		if (type != _IDMAP_T_USER)
24614520Snw141292 			return (IDMAP_ERR_NOTUSER);
24624520Snw141292 	} else if (*is_user == 0) {
24634520Snw141292 		if (type != _IDMAP_T_GROUP)
24644520Snw141292 			return (IDMAP_ERR_NOTGROUP);
24654520Snw141292 	} else if (*is_user == -1) {
24664520Snw141292 		/* Caller wants to know if its user or group */
24674520Snw141292 		if (type == _IDMAP_T_USER)
24684520Snw141292 			*is_user = 1;
24694520Snw141292 		else if (type == _IDMAP_T_GROUP)
24704520Snw141292 			*is_user = 0;
24714520Snw141292 		else
24724520Snw141292 			return (IDMAP_ERR_SID);
24734520Snw141292 	}
24744520Snw141292 
24754520Snw141292 	return (retcode);
24764520Snw141292 }
24774520Snw141292 
24784520Snw141292 static idmap_retcode
24794520Snw141292 name_based_mapping_pid2sid(sqlite *db, sqlite *cache, const char *unixname,
24804520Snw141292 		int is_user, idmap_mapping *req, idmap_id_res *res) {
24814520Snw141292 	const char	*winname, *windomain;
2482*5317Sjp151216 	char		*default_domain = NULL;
24834520Snw141292 	char		*sql = NULL, *errmsg = NULL;
24844520Snw141292 	idmap_retcode	retcode;
24854520Snw141292 	char		*end;
24864520Snw141292 	const char	**values;
24874520Snw141292 	sqlite_vm	*vm = NULL;
24884884Sjp151216 	int		ncol, r;
24894520Snw141292 	const char	*me = "name_based_mapping_pid2sid";
24904520Snw141292 
24914520Snw141292 	RDLOCK_CONFIG();
2492*5317Sjp151216 	if (_idmapdstate.cfg->pgcfg.default_domain != NULL) {
2493*5317Sjp151216 		default_domain =
2494*5317Sjp151216 			strdup(_idmapdstate.cfg->pgcfg.default_domain);
2495*5317Sjp151216 		if (default_domain == NULL) {
24964520Snw141292 			UNLOCK_CONFIG();
24974520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
24984520Snw141292 			retcode = IDMAP_ERR_MEMORY;
24994520Snw141292 			goto out;
25004520Snw141292 		}
25014520Snw141292 	}
25024520Snw141292 	UNLOCK_CONFIG();
25034520Snw141292 
25044520Snw141292 	sql = sqlite_mprintf(
25054520Snw141292 		"SELECT winname, windomain, w2u_order FROM namerules WHERE "
25064520Snw141292 		"u2w_order > 0 AND is_user = %d AND "
25074520Snw141292 		"(unixname = %Q OR unixname = '*') "
25084520Snw141292 		"ORDER BY u2w_order ASC;",
25094520Snw141292 		is_user, unixname);
25104520Snw141292 	if (sql == NULL) {
25114520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
25124520Snw141292 		retcode = IDMAP_ERR_MEMORY;
25134520Snw141292 		goto out;
25144520Snw141292 	}
25154520Snw141292 
25164520Snw141292 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
25174520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
25184520Snw141292 		idmapdlog(LOG_ERR,
25194520Snw141292 			"%s: database error (%s)",
25204520Snw141292 			me, CHECK_NULL(errmsg));
25214520Snw141292 		sqlite_freemem(errmsg);
25224520Snw141292 		goto out;
25234520Snw141292 	}
25244520Snw141292 
25254884Sjp151216 	for (;;) {
25264520Snw141292 		r = sqlite_step(vm, &ncol, &values, NULL);
25274884Sjp151216 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
25284884Sjp151216 		if (r == SQLITE_ROW) {
25294520Snw141292 			if (ncol < 3) {
25304520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
25314520Snw141292 				goto out;
25324520Snw141292 			}
25334520Snw141292 			if (values[0] == NULL) {
25344520Snw141292 				/* values [1] and [2] can be null */
25354520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
25364520Snw141292 				goto out;
25374520Snw141292 			}
25384520Snw141292 			if (EMPTY_NAME(values[0])) {
25394520Snw141292 				retcode = IDMAP_ERR_NOMAPPING;
25404520Snw141292 				goto out;
25414520Snw141292 			}
25424520Snw141292 			winname = (values[0][0] == '*')?unixname:values[0];
25434864Sbaban 			if (values[1] != NULL)
25444520Snw141292 				windomain = values[1];
2545*5317Sjp151216 			else if (default_domain != NULL)
2546*5317Sjp151216 				windomain = default_domain;
25474520Snw141292 			else {
25484520Snw141292 				idmapdlog(LOG_ERR,
25494520Snw141292 					"%s: no domain", me);
25504520Snw141292 				retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
25514520Snw141292 				goto out;
25524520Snw141292 			}
25534520Snw141292 			/* Lookup winname@domain to sid */
25544520Snw141292 			retcode = lookup_name2sid(cache, winname, windomain,
25554520Snw141292 				&is_user, &res->id.idmap_id_u.sid.prefix,
25564520Snw141292 				&res->id.idmap_id_u.sid.rid, req);
25574520Snw141292 			if (retcode == IDMAP_ERR_NOTFOUND) {
25584520Snw141292 				if (winname == unixname)
25594520Snw141292 					continue;
25604520Snw141292 				else
25614520Snw141292 					retcode = IDMAP_ERR_NOMAPPING;
25624520Snw141292 			}
25634520Snw141292 			goto out;
25644520Snw141292 		} else if (r == SQLITE_DONE) {
25654520Snw141292 			retcode = IDMAP_ERR_NOTFOUND;
25664520Snw141292 			goto out;
25674520Snw141292 		} else {
25684520Snw141292 			(void) sqlite_finalize(vm, &errmsg);
25694520Snw141292 			vm = NULL;
25704520Snw141292 			idmapdlog(LOG_ERR,
25714520Snw141292 				"%s: database error (%s)",
25724520Snw141292 				me, CHECK_NULL(errmsg));
25734520Snw141292 			sqlite_freemem(errmsg);
25744520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
25754520Snw141292 			goto out;
25764520Snw141292 		}
25774520Snw141292 	}
25784520Snw141292 
25794520Snw141292 out:
25804864Sbaban 	if (sql != NULL)
25814520Snw141292 		sqlite_freemem(sql);
25824520Snw141292 	if (retcode == IDMAP_SUCCESS) {
25834864Sbaban 		if (values[2] != NULL)
25844520Snw141292 			res->direction =
25854644Sbaban 			    (strtol(values[2], &end, 10) == 0)?
25864644Sbaban 			    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
25874520Snw141292 		else
25884644Sbaban 			res->direction = IDMAP_DIRECTION_U2W;
25895064Sdm199847 
25905064Sdm199847 		req->id2name = strdup(winname);
25915064Sdm199847 		if (req->id2name != NULL) {
2592*5317Sjp151216 			if (windomain == default_domain) {
25935064Sdm199847 				req->id2domain = (char *)windomain;
2594*5317Sjp151216 				default_domain = NULL;
25955064Sdm199847 			} else {
25965064Sdm199847 				req->id2domain = strdup(windomain);
25975064Sdm199847 			}
25984520Snw141292 		}
25994520Snw141292 	}
26004864Sbaban 	if (vm != NULL)
26014520Snw141292 		(void) sqlite_finalize(vm, NULL);
2602*5317Sjp151216 	if (default_domain != NULL)
2603*5317Sjp151216 		free(default_domain);
26044520Snw141292 	return (retcode);
26054520Snw141292 }
26064520Snw141292 
26074520Snw141292 idmap_retcode
26084520Snw141292 pid2sid_first_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
26094520Snw141292 		idmap_mapping *req, idmap_id_res *res, int is_user,
26104520Snw141292 		int getname) {
26114520Snw141292 	char		*unixname = NULL;
26124520Snw141292 	struct passwd	pwd;
26134520Snw141292 	struct group	grp;
26144520Snw141292 	char		buf[1024];
26154520Snw141292 	int		errnum;
26164520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
26174520Snw141292 	const char	*me = "pid2sid";
26184520Snw141292 
26194520Snw141292 	req->direction = _IDMAP_F_DONE;
26204520Snw141292 	res->id.idtype = req->id2.idtype;
26214520Snw141292 
26224520Snw141292 	/* Lookup well-known SIDs */
26234520Snw141292 	retcode = lookup_wksids_pid2sid(req, res, is_user);
26244520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
26254520Snw141292 		goto out;
26264520Snw141292 
26274520Snw141292 	/* Lookup pid to sid in cache */
26284520Snw141292 	retcode = lookup_cache_pid2sid(cache, req, res, is_user, getname);
26294520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
26304520Snw141292 		goto out;
26314520Snw141292 
26324520Snw141292 	/* Ephemeral ids cannot be allocated during pid2sid */
26334520Snw141292 	if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) {
26344864Sbaban 		retcode = IDMAP_ERR_NOMAPPING;
26354520Snw141292 		goto out;
26364520Snw141292 	}
26374520Snw141292 
26384520Snw141292 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
26394864Sbaban 		retcode = IDMAP_ERR_NOMAPPING;
26404520Snw141292 		goto out;
26414520Snw141292 	}
26424520Snw141292 
26434520Snw141292 	/* uid/gid to name */
26445127Sdm199847 	if (!EMPTY_STRING(req->id1name)) {
26455064Sdm199847 		unixname = req->id1name;
26465064Sdm199847 	} else if (is_user) {
26474520Snw141292 		errno = 0;
26484520Snw141292 		if (getpwuid_r(req->id1.idmap_id_u.uid, &pwd, buf,
26494520Snw141292 				sizeof (buf)) == NULL) {
26504520Snw141292 			errnum = errno;
26514520Snw141292 			idmapdlog(LOG_WARNING,
26524520Snw141292 			"%s: getpwuid_r(%u) failed (%s).",
26534520Snw141292 				me, req->id1.idmap_id_u.uid,
26544520Snw141292 				errnum?strerror(errnum):"not found");
26554520Snw141292 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
26564520Snw141292 					IDMAP_ERR_INTERNAL;
26574520Snw141292 			goto fallback_localsid;
26584520Snw141292 		}
26594520Snw141292 		unixname = pwd.pw_name;
26604520Snw141292 	} else {
26614520Snw141292 		errno = 0;
26624520Snw141292 		if (getgrgid_r(req->id1.idmap_id_u.gid, &grp, buf,
26634520Snw141292 				sizeof (buf)) == NULL) {
26644520Snw141292 			errnum = errno;
26654520Snw141292 			idmapdlog(LOG_WARNING,
26664520Snw141292 			"%s: getgrgid_r(%u) failed (%s).",
26674520Snw141292 				me, req->id1.idmap_id_u.gid,
26684520Snw141292 				errnum?strerror(errnum):"not found");
26694520Snw141292 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
26704520Snw141292 					IDMAP_ERR_INTERNAL;
26714520Snw141292 			goto fallback_localsid;
26724520Snw141292 		}
26734520Snw141292 		unixname = grp.gr_name;
26744520Snw141292 	}
26754520Snw141292 
26764520Snw141292 	/* Name-based mapping */
26774520Snw141292 	retcode = name_based_mapping_pid2sid(db, cache, unixname, is_user,
26784520Snw141292 		req, res);
26794520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
26804520Snw141292 		retcode = generate_localsid(req, res, is_user);
26814520Snw141292 		goto out;
26824520Snw141292 	} else if (retcode == IDMAP_SUCCESS)
26834520Snw141292 		goto out;
26844520Snw141292 
26854520Snw141292 fallback_localsid:
26864520Snw141292 	/*
26874520Snw141292 	 * Here we generate localsid as fallback id on errors. Our
26884520Snw141292 	 * return status is the error that's been previously assigned.
26894520Snw141292 	 */
26904520Snw141292 	(void) generate_localsid(req, res, is_user);
26914520Snw141292 
26924520Snw141292 out:
26935127Sdm199847 	if (retcode == IDMAP_SUCCESS && EMPTY_STRING(req->id1name) &&
26945064Sdm199847 	    unixname != NULL) {
26955127Sdm199847 		if (req->id1name != NULL)
26965127Sdm199847 			free(req->id1name);
26975064Sdm199847 		req->id1name = strdup(unixname);
26985127Sdm199847 		if (req->id1name == NULL)
26995127Sdm199847 			retcode = IDMAP_ERR_MEMORY;
27004520Snw141292 	}
27014520Snw141292 	if (req->direction != _IDMAP_F_DONE)
27024520Snw141292 		state->pid2sid_done = FALSE;
27034520Snw141292 	res->retcode = idmap_stat4prot(retcode);
27044520Snw141292 	return (retcode);
27054520Snw141292 }
27064520Snw141292 
27074520Snw141292 static idmap_retcode
27084520Snw141292 lookup_win_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
27094520Snw141292 		char **domain, int *type) {
27104520Snw141292 	int			ret;
27114520Snw141292 	idmap_query_state_t	*qs = NULL;
27124520Snw141292 	idmap_retcode		rc, retcode;
27134520Snw141292 
27144520Snw141292 	retcode = IDMAP_ERR_NOTFOUND;
27154520Snw141292 
27164520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
27174520Snw141292 	if (ret != 0) {
2718*5317Sjp151216 		degrade_svc();
27194520Snw141292 		idmapdlog(LOG_ERR,
27204520Snw141292 		"Failed to create sid2name batch for AD lookup");
27214520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
27224520Snw141292 		goto out;
27234520Snw141292 	}
27244520Snw141292 
2725*5317Sjp151216 	restore_svc();
2726*5317Sjp151216 
27274520Snw141292 	ret = idmap_sid2name_batch_add1(
27284520Snw141292 			qs, sidprefix, &rid, name, domain, type, &rc);
27294520Snw141292 	if (ret != 0) {
27304520Snw141292 		idmapdlog(LOG_ERR,
27314520Snw141292 		"Failed to batch sid2name for AD lookup");
27324520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
27334520Snw141292 		goto out;
27344520Snw141292 	}
27354520Snw141292 
27364520Snw141292 out:
27374864Sbaban 	if (qs != NULL) {
27384520Snw141292 		ret = idmap_lookup_batch_end(&qs, NULL);
2739*5317Sjp151216 		if (ret == IDMAP_ERR_RETRIABLE_NET_ERR)
2740*5317Sjp151216 			degrade_svc();
27414520Snw141292 		if (ret != 0) {
27424520Snw141292 			idmapdlog(LOG_ERR,
27434520Snw141292 			"Failed to execute sid2name AD lookup");
27444520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
27454520Snw141292 		} else
27464520Snw141292 			retcode = rc;
27474520Snw141292 	}
27484520Snw141292 
27494520Snw141292 	return (retcode);
27504520Snw141292 }
27514520Snw141292 
27524644Sbaban static int
27534644Sbaban copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request)
27544520Snw141292 {
27554644Sbaban 	(void) memset(mapping, 0, sizeof (*mapping));
27564644Sbaban 
27574520Snw141292 	mapping->flag = request->flag;
27584520Snw141292 	mapping->direction = request->direction;
27594644Sbaban 	mapping->id2.idtype = request->id2.idtype;
27604520Snw141292 
27614520Snw141292 	mapping->id1.idtype = request->id1.idtype;
27624520Snw141292 	if (request->id1.idtype == IDMAP_SID) {
27634520Snw141292 		mapping->id1.idmap_id_u.sid.rid =
27644520Snw141292 		    request->id1.idmap_id_u.sid.rid;
27654644Sbaban 		if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) {
27664520Snw141292 			mapping->id1.idmap_id_u.sid.prefix =
27674520Snw141292 			    strdup(request->id1.idmap_id_u.sid.prefix);
27684644Sbaban 			if (mapping->id1.idmap_id_u.sid.prefix == NULL)
27695064Sdm199847 				goto errout;
27704644Sbaban 		}
27714520Snw141292 	} else {
27724520Snw141292 		mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid;
27734520Snw141292 	}
27744520Snw141292 
27755064Sdm199847 	mapping->id1domain = strdup(request->id1domain);
27765064Sdm199847 	if (mapping->id1domain == NULL)
27775064Sdm199847 		goto errout;
27784520Snw141292 
27795064Sdm199847 	mapping->id1name = strdup(request->id1name);
27805064Sdm199847 	if (mapping->id1name == NULL)
27815064Sdm199847 		goto errout;
27824520Snw141292 
27834644Sbaban 	/* We don't need the rest of the request i.e request->id2 */
27844644Sbaban 	return (0);
27854644Sbaban 
27864644Sbaban errout:
27875064Sdm199847 	if (mapping->id1.idmap_id_u.sid.prefix != NULL)
27884644Sbaban 		free(mapping->id1.idmap_id_u.sid.prefix);
27895064Sdm199847 	if (mapping->id1domain != NULL)
27905064Sdm199847 		free(mapping->id1domain);
27915064Sdm199847 	if (mapping->id1name != NULL)
27925064Sdm199847 		free(mapping->id1name);
27934644Sbaban 
27944644Sbaban 	(void) memset(mapping, 0, sizeof (*mapping));
27954644Sbaban 	return (-1);
27964520Snw141292 }
27974520Snw141292 
27984520Snw141292 
27994520Snw141292 idmap_retcode
28004520Snw141292 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
28014520Snw141292 		idmap_mapping *mapping) {
28024520Snw141292 	idmap_id_res	idres;
28034520Snw141292 	lookup_state_t	state;
28045043Sbaban 	char		*cp;
28054520Snw141292 	int		is_user;
28064520Snw141292 	idmap_retcode	retcode;
28074520Snw141292 	const char	*winname, *windomain;
28084520Snw141292 
28094520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
28104520Snw141292 	(void) memset(&state, 0, sizeof (state));
28114520Snw141292 
28124520Snw141292 	if (request->id2.idtype == IDMAP_UID)
28134520Snw141292 		is_user = 1;
28144520Snw141292 	else if (request->id2.idtype == IDMAP_GID)
28154520Snw141292 		is_user = 0;
28164520Snw141292 	else if (request->id2.idtype == IDMAP_POSIXID)
28174520Snw141292 		is_user = -1;
28184520Snw141292 	else {
28194520Snw141292 		retcode = IDMAP_ERR_IDTYPE;
28204520Snw141292 		goto out;
28214520Snw141292 	}
28224520Snw141292 
28234520Snw141292 	/* Copy data from request to result */
28244644Sbaban 	if (copy_mapping_request(mapping, request) < 0) {
28254644Sbaban 		retcode = IDMAP_ERR_MEMORY;
28264644Sbaban 		goto out;
28274644Sbaban 	}
28284520Snw141292 
28295064Sdm199847 	winname = mapping->id1name;
28305064Sdm199847 	windomain = mapping->id1domain;
28314520Snw141292 
28325127Sdm199847 	if (EMPTY_STRING(winname) && !EMPTY_STRING(windomain)) {
28334520Snw141292 		retcode = IDMAP_ERR_ARG;
28344520Snw141292 		goto out;
28354520Snw141292 	}
28364520Snw141292 
28375127Sdm199847 	if (!EMPTY_STRING(winname) && EMPTY_STRING(windomain)) {
28385064Sdm199847 		retcode = IDMAP_SUCCESS;
28395043Sbaban 		if ((cp = strchr(winname, '@')) != NULL) {
28405043Sbaban 			/*
28415043Sbaban 			 * if winname is qualified with a domain, use it.
28425043Sbaban 			 */
28435043Sbaban 			*cp = '\0';
28445064Sdm199847 			mapping->id1domain = strdup(cp + 1);
28455064Sdm199847 			if (mapping->id1domain == NULL)
28465064Sdm199847 				retcode = IDMAP_ERR_MEMORY;
28475064Sdm199847 		} else {
28485064Sdm199847 			RDLOCK_CONFIG();
2849*5317Sjp151216 			if (_idmapdstate.cfg->pgcfg.default_domain != NULL) {
28505043Sbaban 			/*
28515043Sbaban 			 * otherwise use the mapping domain
28525043Sbaban 			 */
28535064Sdm199847 				mapping->id1domain =
28545064Sdm199847 				    strdup(_idmapdstate.cfg->
2855*5317Sjp151216 					pgcfg.default_domain);
28565064Sdm199847 				if (mapping->id1domain == NULL)
28575064Sdm199847 					retcode = IDMAP_ERR_MEMORY;
28585064Sdm199847 			}
28595043Sbaban 			UNLOCK_CONFIG();
28605064Sdm199847 		}
28615043Sbaban 
28625043Sbaban 		if (retcode != IDMAP_SUCCESS) {
28635043Sbaban 			idmapdlog(LOG_ERR, "Out of memory");
28645043Sbaban 			goto out;
28654520Snw141292 		}
28665064Sdm199847 		windomain = mapping->id1domain;
28674520Snw141292 	}
28684520Snw141292 
28695127Sdm199847 	if (!EMPTY_STRING(winname) &&
28705127Sdm199847 	    EMPTY_STRING(mapping->id1.idmap_id_u.sid.prefix)) {
28714520Snw141292 		retcode = lookup_name2sid(cache, winname, windomain,
28724520Snw141292 			&is_user, &mapping->id1.idmap_id_u.sid.prefix,
28734520Snw141292 			&mapping->id1.idmap_id_u.sid.rid, mapping);
28744520Snw141292 		if (retcode != IDMAP_SUCCESS)
28754520Snw141292 			goto out;
28764520Snw141292 		if (mapping->id2.idtype == IDMAP_POSIXID)
28774520Snw141292 			mapping->id2.idtype = is_user?IDMAP_UID:IDMAP_GID;
28784520Snw141292 	}
28794520Snw141292 
28804520Snw141292 	state.sid2pid_done = TRUE;
28814520Snw141292 	retcode = sid2pid_first_pass(&state, cache, mapping, &idres);
28824520Snw141292 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
28834520Snw141292 		goto out;
28844520Snw141292 
28854520Snw141292 	if (state.ad_nqueries) {
28864520Snw141292 		/* sid2name AD lookup */
28874520Snw141292 		retcode = lookup_win_sid2name(
28884520Snw141292 			mapping->id1.idmap_id_u.sid.prefix,
28894520Snw141292 			mapping->id1.idmap_id_u.sid.rid,
28905064Sdm199847 			&mapping->id1name,
28915064Sdm199847 			&mapping->id1domain,
28924520Snw141292 			(int *)&idres.id.idtype);
28934520Snw141292 
28944520Snw141292 		idres.retcode = retcode;
28954520Snw141292 	}
28964520Snw141292 
28974520Snw141292 	state.sid2pid_done = TRUE;
28984520Snw141292 	retcode = sid2pid_second_pass(&state, cache, db, mapping, &idres);
28994520Snw141292 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
29004520Snw141292 		goto out;
29014520Snw141292 
29024520Snw141292 	/* Update cache */
29034520Snw141292 	(void) update_cache_sid2pid(&state, cache, mapping, &idres);
29044520Snw141292 
29054520Snw141292 out:
29064520Snw141292 	if (retcode == IDMAP_SUCCESS) {
29074520Snw141292 		mapping->direction = idres.direction;
29084520Snw141292 		mapping->id2 = idres.id;
29094520Snw141292 		(void) memset(&idres, 0, sizeof (idres));
29104864Sbaban 	} else {
29114864Sbaban 		mapping->id2.idmap_id_u.uid = UID_NOBODY;
29124520Snw141292 	}
29134520Snw141292 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
29144520Snw141292 	return (retcode);
29154520Snw141292 }
29164520Snw141292 
29174520Snw141292 idmap_retcode
29184520Snw141292 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
29194520Snw141292 		idmap_mapping *mapping, int is_user) {
29204520Snw141292 	idmap_id_res	idres;
29214520Snw141292 	lookup_state_t	state;
29224520Snw141292 	struct passwd	pwd;
29234520Snw141292 	struct group	grp;
29244520Snw141292 	char		buf[1024];
29254520Snw141292 	int		errnum;
29264520Snw141292 	idmap_retcode	retcode;
29274520Snw141292 	const char	*unixname;
29284520Snw141292 	const char	*me = "get_u2w_mapping";
29294520Snw141292 
29304520Snw141292 	/*
29314520Snw141292 	 * In order to re-use the pid2sid code, we convert
29324520Snw141292 	 * our input data into structs that are expected by
29334520Snw141292 	 * pid2sid_first_pass.
29344520Snw141292 	 */
29354520Snw141292 
29364520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
29374520Snw141292 	(void) memset(&state, 0, sizeof (state));
29384520Snw141292 
29394520Snw141292 	/* Copy data from request to result */
29404644Sbaban 	if (copy_mapping_request(mapping, request) < 0) {
29414644Sbaban 		retcode = IDMAP_ERR_MEMORY;
29424644Sbaban 		goto out;
29434644Sbaban 	}
29444520Snw141292 
29455064Sdm199847 	unixname = mapping->id1name;
29464520Snw141292 
29475127Sdm199847 	if (EMPTY_STRING(unixname) &&
29485127Sdm199847 	    mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
29494520Snw141292 		retcode = IDMAP_ERR_ARG;
29504520Snw141292 		goto out;
29514520Snw141292 	}
29524520Snw141292 
29535127Sdm199847 	if (!EMPTY_STRING(unixname) &&
29545127Sdm199847 	    mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
29554520Snw141292 		/* Get uid/gid by name */
29564520Snw141292 		if (is_user) {
29574520Snw141292 			errno = 0;
29584520Snw141292 			if (getpwnam_r(unixname, &pwd, buf,
29594520Snw141292 					sizeof (buf)) == NULL) {
29604520Snw141292 				errnum = errno;
29614520Snw141292 				idmapdlog(LOG_WARNING,
29624520Snw141292 				"%s: getpwnam_r(%s) failed (%s).",
29634520Snw141292 					me, unixname,
29644520Snw141292 					errnum?strerror(errnum):"not found");
29654520Snw141292 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
29664520Snw141292 						IDMAP_ERR_INTERNAL;
29674520Snw141292 				goto out;
29684520Snw141292 			}
29694520Snw141292 			mapping->id1.idmap_id_u.uid = pwd.pw_uid;
29704520Snw141292 		} else {
29714520Snw141292 			errno = 0;
29724520Snw141292 			if (getgrnam_r(unixname, &grp, buf,
29734520Snw141292 					sizeof (buf)) == NULL) {
29744520Snw141292 				errnum = errno;
29754520Snw141292 				idmapdlog(LOG_WARNING,
29764520Snw141292 				"%s: getgrnam_r(%s) failed (%s).",
29774520Snw141292 					me, unixname,
29784520Snw141292 					errnum?strerror(errnum):"not found");
29794520Snw141292 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
29804520Snw141292 						IDMAP_ERR_INTERNAL;
29814520Snw141292 				goto out;
29824520Snw141292 			}
29834520Snw141292 			mapping->id1.idmap_id_u.gid = grp.gr_gid;
29844520Snw141292 		}
29854520Snw141292 	}
29864520Snw141292 
29874520Snw141292 	state.pid2sid_done = TRUE;
29884520Snw141292 	retcode = pid2sid_first_pass(&state, cache, db, mapping, &idres,
29894520Snw141292 			is_user, 1);
29904520Snw141292 	if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE)
29914520Snw141292 		goto out;
29924520Snw141292 
29934520Snw141292 	/* Update cache */
29944520Snw141292 	(void) update_cache_pid2sid(&state, cache, mapping, &idres);
29954520Snw141292 
29964520Snw141292 out:
29974520Snw141292 	mapping->direction = idres.direction;
29984520Snw141292 	mapping->id2 = idres.id;
29994520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
30004520Snw141292 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
30014520Snw141292 	return (retcode);
30024520Snw141292 }
3003