xref: /onnv-gate/usr/src/cmd/idmap/idmapd/dbutils.c (revision 5064:0fbdaabf14a1)
14520Snw141292 /*
24520Snw141292  * CDDL HEADER START
34520Snw141292  *
44520Snw141292  * The contents of this file are subject to the terms of the
54520Snw141292  * Common Development and Distribution License (the "License").
64520Snw141292  * You may not use this file except in compliance with the License.
74520Snw141292  *
84520Snw141292  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94520Snw141292  * or http://www.opensolaris.org/os/licensing.
104520Snw141292  * See the License for the specific language governing permissions
114520Snw141292  * and limitations under the License.
124520Snw141292  *
134520Snw141292  * When distributing Covered Code, include this CDDL HEADER in each
144520Snw141292  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154520Snw141292  * If applicable, add the following below this CDDL HEADER, with the
164520Snw141292  * fields enclosed by brackets "[]" replaced with your own identifying
174520Snw141292  * information: Portions Copyright [yyyy] [name of copyright owner]
184520Snw141292  *
194520Snw141292  * CDDL HEADER END
204520Snw141292  */
214520Snw141292 /*
224520Snw141292  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
234520Snw141292  * Use is subject to license terms.
244520Snw141292  */
254520Snw141292 
264520Snw141292 #pragma ident	"%Z%%M%	%I%	%E% SMI"
274520Snw141292 
284520Snw141292 /*
294520Snw141292  * Database related utility routines
304520Snw141292  */
314520Snw141292 
324520Snw141292 #include <stdio.h>
334520Snw141292 #include <stdlib.h>
344520Snw141292 #include <string.h>
354520Snw141292 #include <errno.h>
364520Snw141292 #include <sys/types.h>
374520Snw141292 #include <sys/stat.h>
384520Snw141292 #include <rpc/rpc.h>
394520Snw141292 #include <sys/sid.h>
404520Snw141292 #include <time.h>
414520Snw141292 #include <pwd.h>
424520Snw141292 #include <grp.h>
434884Sjp151216 #include <pthread.h>
444884Sjp151216 #include <assert.h>
454520Snw141292 
464520Snw141292 #include "idmapd.h"
474520Snw141292 #include "adutils.h"
484520Snw141292 #include "string.h"
494520Snw141292 #include "idmap_priv.h"
504520Snw141292 
514884Sjp151216 
524520Snw141292 static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
534520Snw141292 		sqlite_vm **, int *, int, const char ***);
544864Sbaban static idmap_retcode lookup_wksids_name2sid(const char *, char **,
554864Sbaban 		idmap_rid_t *, int *);
564520Snw141292 
574520Snw141292 #define	EMPTY_NAME(name)	(*name == 0 || strcmp(name, "\"\"") == 0)
584520Snw141292 
594520Snw141292 #define	DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
604520Snw141292 		(req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
614520Snw141292 
624520Snw141292 #define	AVOID_NAMESERVICE(req)\
634520Snw141292 		(req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
644520Snw141292 
654520Snw141292 #define	IS_EPHEMERAL(pid)	(pid > INT32_MAX)
664520Snw141292 
674520Snw141292 #define	LOCALRID_MIN	1000
684520Snw141292 
694520Snw141292 
704520Snw141292 
714520Snw141292 typedef enum init_db_option {
724520Snw141292 	FAIL_IF_CORRUPT = 0,
734520Snw141292 	REMOVE_IF_CORRUPT = 1
744520Snw141292 } init_db_option_t;
754520Snw141292 
764884Sjp151216 /*
774884Sjp151216  * Thread specfic data to hold the database handles so that the
784884Sjp151216  * databaes are not opened and closed for every request. It also
794884Sjp151216  * contains the sqlite busy handler structure.
804884Sjp151216  */
814884Sjp151216 
824884Sjp151216 struct idmap_busy {
834884Sjp151216 	const char *name;
844884Sjp151216 	const int *delays;
854884Sjp151216 	int delay_size;
864884Sjp151216 	int total;
874884Sjp151216 	int sec;
884884Sjp151216 };
894884Sjp151216 
904884Sjp151216 
914884Sjp151216 typedef struct idmap_tsd {
924884Sjp151216 	sqlite *db_db;
934884Sjp151216 	sqlite *cache_db;
944884Sjp151216 	struct idmap_busy cache_busy;
954884Sjp151216 	struct idmap_busy db_busy;
964884Sjp151216 } idmap_tsd_t;
974884Sjp151216 
984884Sjp151216 
994884Sjp151216 
1004884Sjp151216 static const int cache_delay_table[] =
1014884Sjp151216 		{ 1, 2, 5, 10, 15, 20, 25, 30,  35,  40,
1024884Sjp151216 		50,  50, 60, 70, 80, 90, 100};
1034884Sjp151216 
1044884Sjp151216 static const int db_delay_table[] =
1054884Sjp151216 		{ 5, 10, 15, 20, 30,  40,  55,  70, 100};
1064884Sjp151216 
1074884Sjp151216 
1084884Sjp151216 static pthread_key_t	idmap_tsd_key;
1094884Sjp151216 
1104884Sjp151216 void
1114884Sjp151216 idmap_tsd_destroy(void *key)
1124884Sjp151216 {
1134884Sjp151216 
1144884Sjp151216 	idmap_tsd_t	*tsd = (idmap_tsd_t *)key;
1154884Sjp151216 	if (tsd) {
1164884Sjp151216 		if (tsd->db_db)
1174884Sjp151216 			(void) sqlite_close(tsd->db_db);
1184884Sjp151216 		if (tsd->cache_db)
1194884Sjp151216 			(void) sqlite_close(tsd->cache_db);
1204884Sjp151216 		free(tsd);
1214884Sjp151216 	}
1224884Sjp151216 }
1234884Sjp151216 
1244884Sjp151216 int
1254884Sjp151216 idmap_init_tsd_key(void) {
1264884Sjp151216 
1274884Sjp151216 	return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy));
1284884Sjp151216 }
1294884Sjp151216 
1304884Sjp151216 
1314884Sjp151216 
1324884Sjp151216 idmap_tsd_t *
1334884Sjp151216 idmap_get_tsd(void)
1344884Sjp151216 {
1354884Sjp151216 	idmap_tsd_t	*tsd;
1364884Sjp151216 
1374884Sjp151216 	if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) {
1384884Sjp151216 		/* No thread specific data so create it */
1394884Sjp151216 		if ((tsd = malloc(sizeof (*tsd))) != NULL) {
1404884Sjp151216 			/* Initialize thread specific data */
1414884Sjp151216 			(void) memset(tsd, 0, sizeof (*tsd));
1424884Sjp151216 			/* save the trhread specific data */
1434884Sjp151216 			if (pthread_setspecific(idmap_tsd_key, tsd) != 0) {
1444884Sjp151216 				/* Can't store key */
1454884Sjp151216 				free(tsd);
1464884Sjp151216 				tsd = NULL;
1474884Sjp151216 			}
1484884Sjp151216 		} else {
1494884Sjp151216 			tsd = NULL;
1504884Sjp151216 		}
1514884Sjp151216 	}
1524884Sjp151216 
1534884Sjp151216 	return (tsd);
1544884Sjp151216 }
1554884Sjp151216 
1564884Sjp151216 
1574520Snw141292 
1584520Snw141292 /*
1594520Snw141292  * Initialize 'dbname' using 'sql'
1604520Snw141292  */
1614520Snw141292 static int
1624520Snw141292 init_db_instance(const char *dbname, const char *sql, init_db_option_t opt,
1634520Snw141292 		int *new_db_created)
1644520Snw141292 {
1654520Snw141292 	int rc = 0;
1664520Snw141292 	int tries = 0;
1674520Snw141292 	sqlite *db = NULL;
1684520Snw141292 	char *str = NULL;
1694520Snw141292 
1704520Snw141292 	if (new_db_created != NULL)
1714520Snw141292 		*new_db_created = 0;
1724520Snw141292 
1734520Snw141292 	db = sqlite_open(dbname, 0600, &str);
1744520Snw141292 	while (db == NULL) {
1754520Snw141292 		idmapdlog(LOG_ERR,
1764520Snw141292 		    "Error creating database %s (%s)",
1774520Snw141292 		    dbname, CHECK_NULL(str));
1784520Snw141292 		sqlite_freemem(str);
1794520Snw141292 		if (opt == FAIL_IF_CORRUPT || opt != REMOVE_IF_CORRUPT ||
1804520Snw141292 		    tries > 0)
1814520Snw141292 			return (-1);
1824520Snw141292 
1834520Snw141292 		tries++;
1844520Snw141292 		(void) unlink(dbname);
1854520Snw141292 		db = sqlite_open(dbname, 0600, &str);
1864520Snw141292 	}
1874520Snw141292 
1884520Snw141292 	sqlite_busy_timeout(db, 3000);
1894520Snw141292 	rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &str);
1904520Snw141292 	if (SQLITE_OK != rc) {
1914520Snw141292 		idmapdlog(LOG_ERR, "Cannot begin database transaction (%s)",
1924520Snw141292 		    str);
1934520Snw141292 		sqlite_freemem(str);
1944520Snw141292 		sqlite_close(db);
1954520Snw141292 		return (1);
1964520Snw141292 	}
1974520Snw141292 
1984520Snw141292 	switch (sqlite_exec(db, sql, NULL, NULL, &str)) {
1994520Snw141292 	case SQLITE_ERROR:
2004520Snw141292 /*
2014520Snw141292  * This is the normal situation: CREATE probably failed because tables
2024520Snw141292  * already exist. It may indicate an error in SQL as well, but we cannot
2034520Snw141292  * tell.
2044520Snw141292  */
2054520Snw141292 		sqlite_freemem(str);
2064520Snw141292 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
2074520Snw141292 		    NULL, NULL, &str);
2084520Snw141292 		break;
2094520Snw141292 	case SQLITE_OK:
2104520Snw141292 		rc =  sqlite_exec(db, "COMMIT TRANSACTION",
2114520Snw141292 		    NULL, NULL, &str);
2124520Snw141292 		idmapdlog(LOG_INFO,
2134520Snw141292 		    "Database created at %s", dbname);
2144520Snw141292 
2154520Snw141292 		if (new_db_created != NULL)
2164520Snw141292 			*new_db_created = 1;
2174520Snw141292 		break;
2184520Snw141292 	default:
2194520Snw141292 		idmapdlog(LOG_ERR,
2204520Snw141292 		    "Error initializing database %s (%s)",
2214520Snw141292 		    dbname, str);
2224520Snw141292 		sqlite_freemem(str);
2234520Snw141292 		rc =  sqlite_exec(db, "ROLLBACK TRANSACTION",
2244520Snw141292 		    NULL, NULL, &str);
2254520Snw141292 		break;
2264520Snw141292 	}
2274520Snw141292 
2284520Snw141292 	if (SQLITE_OK != rc) {
2294520Snw141292 		/* this is bad - database may be left in a locked state */
2304520Snw141292 		idmapdlog(LOG_ERR,
2314520Snw141292 		    "Error closing transaction (%s)", str);
2324520Snw141292 		sqlite_freemem(str);
2334520Snw141292 	}
2344520Snw141292 
2354520Snw141292 	(void) sqlite_close(db);
2364520Snw141292 	return (rc);
2374520Snw141292 }
2384520Snw141292 
2394884Sjp151216 
2404884Sjp151216 /*
2414884Sjp151216  * This is the SQLite database busy handler that retries the SQL
2424884Sjp151216  * operation until it is successful.
2434884Sjp151216  */
2444884Sjp151216 int
2454884Sjp151216 /* LINTED E_FUNC_ARG_UNUSED */
2464884Sjp151216 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count)
2474884Sjp151216 {
2484884Sjp151216 	struct idmap_busy	*busy = arg;
2494884Sjp151216 	int			delay;
2504884Sjp151216 	struct timespec		rqtp;
2514884Sjp151216 
2524884Sjp151216 	if (count == 1)  {
2534884Sjp151216 		busy->total = 0;
2544884Sjp151216 		busy->sec = 2;
2554884Sjp151216 	}
2564884Sjp151216 	if (busy->total > 1000 * busy->sec) {
2574884Sjp151216 		idmapdlog(LOG_ERR,
2584884Sjp151216 		    "Thread %d waited %d sec for the %s database",
2594884Sjp151216 		    pthread_self(), busy->sec, busy->name);
2604884Sjp151216 		busy->sec++;
2614884Sjp151216 	}
2624884Sjp151216 
2634884Sjp151216 	if (count <= busy->delay_size) {
2644884Sjp151216 		delay = busy->delays[count-1];
2654884Sjp151216 	} else {
2664884Sjp151216 		delay = busy->delays[busy->delay_size - 1];
2674884Sjp151216 	}
2684884Sjp151216 	busy->total += delay;
2694884Sjp151216 	rqtp.tv_sec = 0;
2704884Sjp151216 	rqtp.tv_nsec = delay * (NANOSEC / MILLISEC);
2714884Sjp151216 	(void) nanosleep(&rqtp, NULL);
2724884Sjp151216 	return (1);
2734884Sjp151216 }
2744884Sjp151216 
2754884Sjp151216 
2764520Snw141292 /*
2774520Snw141292  * Get the database handle
2784520Snw141292  */
2794520Snw141292 idmap_retcode
2804520Snw141292 get_db_handle(sqlite **db) {
2814520Snw141292 	char	*errmsg;
2824884Sjp151216 	idmap_tsd_t *tsd;
2834520Snw141292 
2844520Snw141292 	/*
2854884Sjp151216 	 * Retrieve the db handle from thread-specific storage
2864520Snw141292 	 * If none exists, open and store in thread-specific storage.
2874520Snw141292 	 */
2884884Sjp151216 	if ((tsd = idmap_get_tsd()) == NULL) {
2894520Snw141292 		idmapdlog(LOG_ERR,
2904884Sjp151216 			"Error getting thread specific data for %s",
2914884Sjp151216 			IDMAP_DBNAME);
2924884Sjp151216 		return (IDMAP_ERR_MEMORY);
2934520Snw141292 	}
2944884Sjp151216 
2954884Sjp151216 	if (tsd->db_db == NULL) {
2964884Sjp151216 		tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg);
2974884Sjp151216 		if (tsd->db_db == NULL) {
2984884Sjp151216 			idmapdlog(LOG_ERR,
2994884Sjp151216 				"Error opening database %s (%s)",
3004884Sjp151216 				IDMAP_DBNAME, CHECK_NULL(errmsg));
3014884Sjp151216 			sqlite_freemem(errmsg);
3024884Sjp151216 			return (IDMAP_ERR_INTERNAL);
3034884Sjp151216 		}
3044884Sjp151216 		tsd->db_busy.name = IDMAP_DBNAME;
3054884Sjp151216 		tsd->db_busy.delays = db_delay_table;
3064884Sjp151216 		tsd->db_busy.delay_size = sizeof (db_delay_table) /
3074884Sjp151216 		    sizeof (int);
3084884Sjp151216 		sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler,
3094884Sjp151216 		    &tsd->db_busy);
3104884Sjp151216 	}
3114884Sjp151216 	*db = tsd->db_db;
3124520Snw141292 	return (IDMAP_SUCCESS);
3134520Snw141292 }
3144520Snw141292 
3154520Snw141292 /*
3164520Snw141292  * Get the cache handle
3174520Snw141292  */
3184520Snw141292 idmap_retcode
3194884Sjp151216 get_cache_handle(sqlite **cache) {
3204520Snw141292 	char	*errmsg;
3214884Sjp151216 	idmap_tsd_t *tsd;
3224520Snw141292 
3234520Snw141292 	/*
3244884Sjp151216 	 * Retrieve the db handle from thread-specific storage
3254520Snw141292 	 * If none exists, open and store in thread-specific storage.
3264520Snw141292 	 */
3274884Sjp151216 	if ((tsd = idmap_get_tsd()) == NULL) {
3284520Snw141292 		idmapdlog(LOG_ERR,
3294884Sjp151216 			"Error getting thread specific data for %s",
3304884Sjp151216 			IDMAP_DBNAME);
3314884Sjp151216 		return (IDMAP_ERR_MEMORY);
3324520Snw141292 	}
3334884Sjp151216 
3344884Sjp151216 	if (tsd->cache_db == NULL) {
3354884Sjp151216 		tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg);
3364884Sjp151216 		if (tsd->cache_db == NULL) {
3374884Sjp151216 			idmapdlog(LOG_ERR,
3384884Sjp151216 				"Error opening database %s (%s)",
3394884Sjp151216 				IDMAP_CACHENAME, CHECK_NULL(errmsg));
3404884Sjp151216 			sqlite_freemem(errmsg);
3414884Sjp151216 			return (IDMAP_ERR_INTERNAL);
3424884Sjp151216 		}
3434884Sjp151216 		tsd->cache_busy.name = IDMAP_CACHENAME;
3444884Sjp151216 		tsd->cache_busy.delays = cache_delay_table;
3454884Sjp151216 		tsd->cache_busy.delay_size = sizeof (cache_delay_table) /
3464884Sjp151216 		    sizeof (int);
3474884Sjp151216 		sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler,
3484884Sjp151216 		    &tsd->cache_busy);
3494884Sjp151216 	}
3504884Sjp151216 	*cache = tsd->cache_db;
3514520Snw141292 	return (IDMAP_SUCCESS);
3524520Snw141292 }
3534520Snw141292 
3544520Snw141292 #define	CACHE_SQL\
3554520Snw141292 	"CREATE TABLE idmap_cache ("\
3564520Snw141292 	"	sidprefix TEXT,"\
3574520Snw141292 	"	rid INTEGER,"\
3584520Snw141292 	"	windomain TEXT,"\
3594520Snw141292 	"	winname TEXT,"\
3604520Snw141292 	"	pid INTEGER,"\
3614520Snw141292 	"	unixname TEXT,"\
3624520Snw141292 	"	is_user INTEGER,"\
3634520Snw141292 	"	w2u INTEGER,"\
3644520Snw141292 	"	u2w INTEGER,"\
3654520Snw141292 	"	expiration INTEGER"\
3664520Snw141292 	");"\
3674520Snw141292 	"CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache"\
3684520Snw141292 	"		(sidprefix, rid, w2u);"\
3694520Snw141292 	"CREATE UNIQUE INDEX idmap_cache_pid_u2w ON idmap_cache"\
3704520Snw141292 	"		(pid, is_user, u2w);"\
3714520Snw141292 	"CREATE TABLE name_cache ("\
3724520Snw141292 	"	sidprefix TEXT,"\
3734520Snw141292 	"	rid INTEGER,"\
3744520Snw141292 	"	name TEXT,"\
3754520Snw141292 	"	domain TEXT,"\
3764520Snw141292 	"	type INTEGER,"\
3774520Snw141292 	"	expiration INTEGER"\
3784520Snw141292 	");"\
3794520Snw141292 	"CREATE UNIQUE INDEX name_cache_sid ON name_cache"\
3804520Snw141292 	"		(sidprefix, rid);"
3814520Snw141292 
3824520Snw141292 #define	DB_SQL\
3834520Snw141292 	"CREATE TABLE namerules ("\
3844520Snw141292 	"	is_user INTEGER NOT NULL,"\
3854520Snw141292 	"	windomain TEXT,"\
3864520Snw141292 	"	winname TEXT NOT NULL,"\
3874520Snw141292 	"	is_nt4 INTEGER NOT NULL,"\
3884520Snw141292 	"	unixname NOT NULL,"\
3894520Snw141292 	"	w2u_order INTEGER,"\
3904520Snw141292 	"	u2w_order INTEGER"\
3914520Snw141292 	");"\
3924520Snw141292 	"CREATE UNIQUE INDEX namerules_w2u ON namerules"\
3934520Snw141292 	"		(winname, windomain, is_user, w2u_order);"\
3944520Snw141292 	"CREATE UNIQUE INDEX namerules_u2w ON namerules"\
3954520Snw141292 	"		(unixname, is_user, u2w_order);"
3964520Snw141292 
3974520Snw141292 /*
3984520Snw141292  * Initialize cache and db
3994520Snw141292  */
4004520Snw141292 int
4014520Snw141292 init_dbs() {
4024520Snw141292 	/* name-based mappings; probably OK to blow away in a pinch(?) */
4034520Snw141292 	if (init_db_instance(IDMAP_DBNAME, DB_SQL, FAIL_IF_CORRUPT, NULL) < 0)
4044520Snw141292 		return (-1);
4054520Snw141292 
4064520Snw141292 	/* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
4074520Snw141292 	if (init_db_instance(IDMAP_CACHENAME, CACHE_SQL, REMOVE_IF_CORRUPT,
4084520Snw141292 			&_idmapdstate.new_eph_db) < 0)
4094520Snw141292 		return (-1);
4104520Snw141292 
4114520Snw141292 	return (0);
4124520Snw141292 }
4134520Snw141292 
4144520Snw141292 /*
4154520Snw141292  * Finalize databases
4164520Snw141292  */
4174520Snw141292 void
4184520Snw141292 fini_dbs() {
4194520Snw141292 }
4204520Snw141292 
4214520Snw141292 /*
4224520Snw141292  * This table is a listing of status codes that will returned to the
4234520Snw141292  * client when a SQL command fails with the corresponding error message.
4244520Snw141292  */
4254520Snw141292 static msg_table_t sqlmsgtable[] = {
4264864Sbaban 	{IDMAP_ERR_U2W_NAMERULE_CONFLICT,
4274520Snw141292 	"columns unixname, is_user, u2w_order are not unique"},
4284864Sbaban 	{IDMAP_ERR_W2U_NAMERULE_CONFLICT,
4294520Snw141292 	"columns winname, windomain, is_user, w2u_order are not unique"},
4304520Snw141292 	{-1, NULL}
4314520Snw141292 };
4324520Snw141292 
4334520Snw141292 /*
4344520Snw141292  * idmapd's version of string2stat to map SQLite messages to
4354520Snw141292  * status codes
4364520Snw141292  */
4374520Snw141292 idmap_retcode
4384520Snw141292 idmapd_string2stat(const char *msg) {
4394520Snw141292 	int i;
4404520Snw141292 	for (i = 0; sqlmsgtable[i].msg; i++) {
4414520Snw141292 		if (strcasecmp(sqlmsgtable[i].msg, msg) == 0)
4424520Snw141292 			return (sqlmsgtable[i].retcode);
4434520Snw141292 	}
4444520Snw141292 	return (IDMAP_ERR_OTHER);
4454520Snw141292 }
4464520Snw141292 
4474520Snw141292 /*
4484520Snw141292  * Execute the given SQL statment without using any callbacks
4494520Snw141292  */
4504520Snw141292 idmap_retcode
4514520Snw141292 sql_exec_no_cb(sqlite *db, char *sql) {
4524520Snw141292 	char		*errmsg = NULL;
4534884Sjp151216 	int		r;
4544520Snw141292 	idmap_retcode	retcode;
4554520Snw141292 
4564884Sjp151216 	r = sqlite_exec(db, sql, NULL, NULL, &errmsg);
4574884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
4584520Snw141292 
4594520Snw141292 	if (r != SQLITE_OK) {
4604520Snw141292 		idmapdlog(LOG_ERR, "Database error during %s (%s)",
4614520Snw141292 			sql, CHECK_NULL(errmsg));
4624884Sjp151216 		retcode = idmapd_string2stat(errmsg);
4634864Sbaban 		if (errmsg != NULL)
4644520Snw141292 			sqlite_freemem(errmsg);
4654520Snw141292 		return (retcode);
4664520Snw141292 	}
4674520Snw141292 
4684520Snw141292 	return (IDMAP_SUCCESS);
4694520Snw141292 }
4704520Snw141292 
4714520Snw141292 /*
4724520Snw141292  * Generate expression that can be used in WHERE statements.
4734520Snw141292  * Examples:
4744520Snw141292  * <prefix> <col>      <op> <value>   <suffix>
4754520Snw141292  * ""       "unixuser" "="  "foo" "AND"
4764520Snw141292  */
4774520Snw141292 idmap_retcode
4784520Snw141292 gen_sql_expr_from_utf8str(const char *prefix, const char *col,
479*5064Sdm199847 		const char *op, char *value,
4804520Snw141292 		const char *suffix, char **out) {
4814520Snw141292 	if (out == NULL)
4824520Snw141292 		return (IDMAP_ERR_ARG);
4834520Snw141292 
4844520Snw141292 	if (value == NULL)
4854520Snw141292 		return (IDMAP_SUCCESS);
4864520Snw141292 
4874520Snw141292 	if (prefix == NULL)
4884520Snw141292 		prefix = "";
4894520Snw141292 	if (suffix == NULL)
4904520Snw141292 		suffix = "";
4914520Snw141292 
4924520Snw141292 	*out = sqlite_mprintf("%s %s %s %Q %s",
493*5064Sdm199847 			prefix, col, op, value, suffix);
4944520Snw141292 	if (*out == NULL)
4954520Snw141292 		return (IDMAP_ERR_MEMORY);
4964520Snw141292 	return (IDMAP_SUCCESS);
4974520Snw141292 }
4984520Snw141292 
4994520Snw141292 /*
5004520Snw141292  * Generate and execute SQL statement for LIST RPC calls
5014520Snw141292  */
5024520Snw141292 idmap_retcode
5034520Snw141292 process_list_svc_sql(sqlite *db, char *sql, uint64_t limit,
5044520Snw141292 		list_svc_cb cb, void *result) {
5054520Snw141292 	list_cb_data_t	cb_data;
5064520Snw141292 	char		*errmsg = NULL;
5074884Sjp151216 	int		r;
5084520Snw141292 	idmap_retcode	retcode = IDMAP_ERR_INTERNAL;
5094520Snw141292 
5104520Snw141292 	(void) memset(&cb_data, 0, sizeof (cb_data));
5114520Snw141292 	cb_data.result = result;
5124520Snw141292 	cb_data.limit = limit;
5134520Snw141292 
5144884Sjp151216 
5154884Sjp151216 	r = sqlite_exec(db, sql, cb, &cb_data, &errmsg);
5164884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
5174884Sjp151216 	switch (r) {
5184884Sjp151216 	case SQLITE_OK:
5194884Sjp151216 		retcode = IDMAP_SUCCESS;
5204884Sjp151216 		break;
5214884Sjp151216 
5224884Sjp151216 	default:
5234884Sjp151216 		retcode = IDMAP_ERR_INTERNAL;
5244884Sjp151216 		idmapdlog(LOG_ERR,
5254884Sjp151216 			"Database error during %s (%s)",
5264884Sjp151216 			sql, CHECK_NULL(errmsg));
5274884Sjp151216 		break;
5284520Snw141292 	}
5294864Sbaban 	if (errmsg != NULL)
5304520Snw141292 		sqlite_freemem(errmsg);
5314520Snw141292 	return (retcode);
5324520Snw141292 }
5334520Snw141292 
5344520Snw141292 /*
5354520Snw141292  * This routine is called by callbacks that process the results of
5364520Snw141292  * LIST RPC calls to validate data and to allocate memory for
5374520Snw141292  * the result array.
5384520Snw141292  */
5394520Snw141292 idmap_retcode
5404520Snw141292 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv,
5414520Snw141292 		int ncol, uchar_t **list, size_t valsize) {
5424520Snw141292 	size_t	nsize;
5434520Snw141292 	void	*tmplist;
5444520Snw141292 
5454520Snw141292 	if (cb_data->limit > 0 && cb_data->next == cb_data->limit)
5464520Snw141292 		return (IDMAP_NEXT);
5474520Snw141292 
5484520Snw141292 	if (argc < ncol || argv == NULL) {
5494520Snw141292 		idmapdlog(LOG_ERR, "Invalid data");
5504520Snw141292 		return (IDMAP_ERR_INTERNAL);
5514520Snw141292 	}
5524520Snw141292 
5534520Snw141292 	/* alloc in bulk to reduce number of reallocs */
5544520Snw141292 	if (cb_data->next >= cb_data->len) {
5554520Snw141292 		nsize = (cb_data->len + SIZE_INCR) * valsize;
5564520Snw141292 		tmplist = realloc(*list, nsize);
5574520Snw141292 		if (tmplist == NULL) {
5584520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
5594520Snw141292 			return (IDMAP_ERR_MEMORY);
5604520Snw141292 		}
5614520Snw141292 		*list = tmplist;
5624520Snw141292 		(void) memset(*list + (cb_data->len * valsize), 0,
5634520Snw141292 			SIZE_INCR * valsize);
5644520Snw141292 		cb_data->len += SIZE_INCR;
5654520Snw141292 	}
5664520Snw141292 	return (IDMAP_SUCCESS);
5674520Snw141292 }
5684520Snw141292 
5694520Snw141292 static idmap_retcode
5704520Snw141292 get_namerule_order(char *winname, char *windomain, char *unixname,
5714520Snw141292 		int direction, int *w2u_order, int *u2w_order) {
5724520Snw141292 
5734520Snw141292 	*w2u_order = 0;
5744520Snw141292 	*u2w_order = 0;
5754520Snw141292 
5764520Snw141292 	/*
5774520Snw141292 	 * Windows to UNIX lookup order:
5784520Snw141292 	 *  1. winname@domain (or winname) to ""
5794520Snw141292 	 *  2. winname@domain (or winname) to unixname
5804520Snw141292 	 *  3. winname@* to ""
5814520Snw141292 	 *  4. winname@* to unixname
5824520Snw141292 	 *  5. *@domain (or *) to *
5834520Snw141292 	 *  6. *@domain (or *) to ""
5844520Snw141292 	 *  7. *@domain (or *) to unixname
5854520Snw141292 	 *  8. *@* to *
5864520Snw141292 	 *  9. *@* to ""
5874520Snw141292 	 * 10. *@* to unixname
5884520Snw141292 	 *
5894520Snw141292 	 * winname is a special case of winname@domain when domain is the
5904520Snw141292 	 * default domain. Similarly * is a special case of *@domain when
5914520Snw141292 	 * domain is the default domain.
5924520Snw141292 	 *
5934520Snw141292 	 * Note that "" has priority over specific names because "" inhibits
5944520Snw141292 	 * mappings and traditionally deny rules always had higher priority.
5954520Snw141292 	 */
5964644Sbaban 	if (direction != IDMAP_DIRECTION_U2W) {
5974644Sbaban 		/* bi-directional or from windows to unix */
5984520Snw141292 		if (winname == NULL)
5994520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6004520Snw141292 		else if (unixname == NULL)
6014520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6024520Snw141292 		else if (EMPTY_NAME(winname))
6034520Snw141292 			return (IDMAP_ERR_W2U_NAMERULE);
6044520Snw141292 		else if (*winname == '*' && windomain && *windomain == '*') {
6054520Snw141292 			if (*unixname == '*')
6064520Snw141292 				*w2u_order = 8;
6074520Snw141292 			else if (EMPTY_NAME(unixname))
6084520Snw141292 				*w2u_order = 9;
6094520Snw141292 			else /* unixname == name */
6104520Snw141292 				*w2u_order = 10;
6114520Snw141292 		} else if (*winname == '*') {
6124520Snw141292 			if (*unixname == '*')
6134520Snw141292 				*w2u_order = 5;
6144520Snw141292 			else if (EMPTY_NAME(unixname))
6154520Snw141292 				*w2u_order = 6;
6164520Snw141292 			else /* name */
6174520Snw141292 				*w2u_order = 7;
6184864Sbaban 		} else if (windomain != NULL && *windomain == '*') {
6194520Snw141292 			/* winname == name */
6204520Snw141292 			if (*unixname == '*')
6214520Snw141292 				return (IDMAP_ERR_W2U_NAMERULE);
6224520Snw141292 			else if (EMPTY_NAME(unixname))
6234520Snw141292 				*w2u_order = 3;
6244520Snw141292 			else /* name */
6254520Snw141292 				*w2u_order = 4;
6264520Snw141292 		} else  {
6274520Snw141292 			/* winname == name && windomain == null or name */
6284520Snw141292 			if (*unixname == '*')
6294520Snw141292 				return (IDMAP_ERR_W2U_NAMERULE);
6304520Snw141292 			else if (EMPTY_NAME(unixname))
6314520Snw141292 				*w2u_order = 1;
6324520Snw141292 			else /* name */
6334520Snw141292 				*w2u_order = 2;
6344520Snw141292 		}
6354520Snw141292 	}
6364520Snw141292 
6374520Snw141292 	/*
6384520Snw141292 	 * 1. unixname to ""
6394520Snw141292 	 * 2. unixname to winname@domain (or winname)
6404520Snw141292 	 * 3. * to *@domain (or *)
6414520Snw141292 	 * 4. * to ""
6424520Snw141292 	 * 5. * to winname@domain (or winname)
6434520Snw141292 	 */
6444644Sbaban 	if (direction != IDMAP_DIRECTION_W2U) {
6454644Sbaban 		/* bi-directional or from unix to windows */
6464520Snw141292 		if (unixname == NULL || EMPTY_NAME(unixname))
6474520Snw141292 			return (IDMAP_ERR_U2W_NAMERULE);
6484520Snw141292 		else if (winname == NULL)
6494520Snw141292 			return (IDMAP_ERR_U2W_NAMERULE);
6504864Sbaban 		else if (windomain != NULL && *windomain == '*')
6514644Sbaban 			return (IDMAP_ERR_U2W_NAMERULE);
6524520Snw141292 		else if (*unixname == '*') {
6534520Snw141292 			if (*winname == '*')
6544520Snw141292 				*u2w_order = 3;
6554520Snw141292 			else if (EMPTY_NAME(winname))
6564520Snw141292 				*u2w_order = 4;
6574520Snw141292 			else
6584520Snw141292 				*u2w_order = 5;
6594520Snw141292 		} else {
6604520Snw141292 			if (*winname == '*')
6614520Snw141292 				return (IDMAP_ERR_U2W_NAMERULE);
6624520Snw141292 			else if (EMPTY_NAME(winname))
6634520Snw141292 				*u2w_order = 1;
6644520Snw141292 			else
6654520Snw141292 				*u2w_order = 2;
6664520Snw141292 		}
6674520Snw141292 	}
6684520Snw141292 	return (IDMAP_SUCCESS);
6694520Snw141292 }
6704520Snw141292 
6714520Snw141292 /*
6724520Snw141292  * Generate and execute SQL statement to add name-based mapping rule
6734520Snw141292  */
6744520Snw141292 idmap_retcode
6754520Snw141292 add_namerule(sqlite *db, idmap_namerule *rule) {
6764520Snw141292 	char		*sql = NULL;
6774520Snw141292 	idmap_stat	retcode;
678*5064Sdm199847 	char		*dom = NULL;
6794520Snw141292 	int		w2u_order, u2w_order;
6804520Snw141292 	char		w2ubuf[11], u2wbuf[11];
6814520Snw141292 
682*5064Sdm199847 	retcode = get_namerule_order(rule->winname, rule->windomain,
683*5064Sdm199847 	    rule->unixname, rule->direction, &w2u_order, &u2w_order);
6844520Snw141292 	if (retcode != IDMAP_SUCCESS)
6854520Snw141292 		goto out;
6864520Snw141292 
6874520Snw141292 	if (w2u_order)
6884520Snw141292 		(void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order);
6894520Snw141292 	if (u2w_order)
6904520Snw141292 		(void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order);
6914520Snw141292 
6924864Sbaban 	/*
6934864Sbaban 	 * For the triggers on namerules table to work correctly:
6944864Sbaban 	 * 1) Use NULL instead of 0 for w2u_order and u2w_order
6954864Sbaban 	 * 2) Use "" instead of NULL for "no domain"
6964864Sbaban 	 */
6974864Sbaban 
698*5064Sdm199847 	if (rule->windomain != NULL)
699*5064Sdm199847 		dom = rule->windomain;
700*5064Sdm199847 	else if (lookup_wksids_name2sid(rule->winname, NULL, NULL, NULL)
7014864Sbaban 	    == IDMAP_SUCCESS) {
7024864Sbaban 		/* well-known SIDs don't need domain */
7034864Sbaban 		dom = "";
7044864Sbaban 	}
7054520Snw141292 
7064520Snw141292 	RDLOCK_CONFIG();
7074864Sbaban 	if (dom == NULL) {
7084864Sbaban 		if (_idmapdstate.cfg->pgcfg.mapping_domain)
7094864Sbaban 			dom = _idmapdstate.cfg->pgcfg.mapping_domain;
7104864Sbaban 		else
7114864Sbaban 			dom = "";
7124864Sbaban 	}
7134884Sjp151216 	sql = sqlite_mprintf("INSERT into namerules "
7144520Snw141292 		"(is_user, windomain, winname, is_nt4, "
7154520Snw141292 		"unixname, w2u_order, u2w_order) "
7164520Snw141292 		"VALUES(%d, %Q, %Q, %d, %Q, %q, %q);",
7174520Snw141292 		rule->is_user?1:0,
7184520Snw141292 		dom,
719*5064Sdm199847 		rule->winname, rule->is_nt4?1:0,
720*5064Sdm199847 		rule->unixname,
7214520Snw141292 		w2u_order?w2ubuf:NULL,
7224520Snw141292 		u2w_order?u2wbuf:NULL);
7234520Snw141292 	UNLOCK_CONFIG();
7244520Snw141292 
7254520Snw141292 	if (sql == NULL) {
7264520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
7274520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
7284520Snw141292 		goto out;
7294520Snw141292 	}
7304520Snw141292 
7314520Snw141292 	retcode = sql_exec_no_cb(db, sql);
7324520Snw141292 
7334520Snw141292 	if (retcode == IDMAP_ERR_OTHER)
7344520Snw141292 		retcode = IDMAP_ERR_CFG;
7354520Snw141292 
7364520Snw141292 out:
7374864Sbaban 	if (sql != NULL)
7384520Snw141292 		sqlite_freemem(sql);
7394520Snw141292 	return (retcode);
7404520Snw141292 }
7414520Snw141292 
7424520Snw141292 /*
7434520Snw141292  * Flush name-based mapping rules
7444520Snw141292  */
7454520Snw141292 idmap_retcode
7464520Snw141292 flush_namerules(sqlite *db, bool_t is_user) {
7474520Snw141292 	char		*sql = NULL;
7484520Snw141292 	idmap_stat	retcode;
7494520Snw141292 
7504520Snw141292 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
7514520Snw141292 		"is_user = %d;", is_user?1:0);
7524520Snw141292 
7534520Snw141292 	if (sql == NULL) {
7544520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
7554520Snw141292 		return (IDMAP_ERR_MEMORY);
7564520Snw141292 	}
7574520Snw141292 
7584520Snw141292 	retcode = sql_exec_no_cb(db, sql);
7594520Snw141292 
7604520Snw141292 	sqlite_freemem(sql);
7614520Snw141292 	return (retcode);
7624520Snw141292 }
7634520Snw141292 
7644520Snw141292 /*
7654520Snw141292  * Generate and execute SQL statement to remove a name-based mapping rule
7664520Snw141292  */
7674520Snw141292 idmap_retcode
7684520Snw141292 rm_namerule(sqlite *db, idmap_namerule *rule) {
7694520Snw141292 	char		*sql = NULL;
7704520Snw141292 	idmap_stat	retcode;
7714520Snw141292 	char		*s_windomain = NULL, *s_winname = NULL;
7724520Snw141292 	char		*s_unixname = NULL;
7734520Snw141292 	char		buf[80];
7744520Snw141292 
775*5064Sdm199847 	if (rule->direction < 0 && EMPTY_STRING(rule->windomain) &&
776*5064Sdm199847 	    EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
7774520Snw141292 		return (IDMAP_SUCCESS);
7784520Snw141292 
7794520Snw141292 	if (rule->direction < 0) {
7804520Snw141292 		buf[0] = 0;
7814644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_BI) {
7824520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
7834520Snw141292 				" AND u2w_order > 0");
7844644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_W2U) {
7854520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND w2u_order > 0"
7864520Snw141292 				" AND (u2w_order = 0 OR u2w_order ISNULL)");
7874644Sbaban 	} else if (rule->direction == IDMAP_DIRECTION_U2W) {
7884520Snw141292 		(void) snprintf(buf, sizeof (buf), "AND u2w_order > 0"
7894520Snw141292 				" AND (w2u_order = 0 OR w2u_order ISNULL)");
7904520Snw141292 	}
7914520Snw141292 
7924520Snw141292 	retcode = IDMAP_ERR_INTERNAL;
793*5064Sdm199847 	if (!EMPTY_STRING(rule->windomain)) {
7944520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "windomain", "=",
795*5064Sdm199847 			rule->windomain, "", &s_windomain) != IDMAP_SUCCESS)
7964520Snw141292 			goto out;
7974520Snw141292 	}
7984520Snw141292 
799*5064Sdm199847 	if (!EMPTY_STRING(rule->winname)) {
8004520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "winname", "=",
801*5064Sdm199847 			rule->winname, "", &s_winname) != IDMAP_SUCCESS)
8024520Snw141292 			goto out;
8034520Snw141292 	}
8044520Snw141292 
805*5064Sdm199847 	if (!EMPTY_STRING(rule->unixname)) {
8064520Snw141292 		if (gen_sql_expr_from_utf8str("AND", "unixname", "=",
807*5064Sdm199847 			rule->unixname,	"", &s_unixname) != IDMAP_SUCCESS)
8084520Snw141292 			goto out;
8094520Snw141292 	}
8104520Snw141292 
8114520Snw141292 	sql = sqlite_mprintf("DELETE FROM namerules WHERE "
8124520Snw141292 		"is_user = %d %s %s %s %s;",
8134520Snw141292 		rule->is_user?1:0,
8144520Snw141292 		s_windomain?s_windomain:"",
8154520Snw141292 		s_winname?s_winname:"",
8164520Snw141292 		s_unixname?s_unixname:"",
8174520Snw141292 		buf);
8184520Snw141292 
8194520Snw141292 	if (sql == NULL) {
8204520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
8214520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
8224520Snw141292 		goto out;
8234520Snw141292 	}
8244520Snw141292 
8254520Snw141292 	retcode = sql_exec_no_cb(db, sql);
8264520Snw141292 
8274520Snw141292 out:
8284864Sbaban 	if (s_windomain != NULL)
8294520Snw141292 		sqlite_freemem(s_windomain);
8304864Sbaban 	if (s_winname != NULL)
8314520Snw141292 		sqlite_freemem(s_winname);
8324864Sbaban 	if (s_unixname != NULL)
8334520Snw141292 		sqlite_freemem(s_unixname);
8344864Sbaban 	if (sql != NULL)
8354520Snw141292 		sqlite_freemem(sql);
8364520Snw141292 	return (retcode);
8374520Snw141292 }
8384520Snw141292 
8394520Snw141292 /*
8404520Snw141292  * Compile the given SQL query and step just once.
8414520Snw141292  *
8424520Snw141292  * Input:
8434520Snw141292  * db  - db handle
8444520Snw141292  * sql - SQL statement
8454520Snw141292  *
8464520Snw141292  * Output:
8474520Snw141292  * vm     -  virtual SQL machine
8484520Snw141292  * ncol   - number of columns in the result
8494520Snw141292  * values - column values
8504520Snw141292  *
8514520Snw141292  * Return values:
8524520Snw141292  * IDMAP_SUCCESS
8534520Snw141292  * IDMAP_ERR_NOTFOUND
8544520Snw141292  * IDMAP_ERR_INTERNAL
8554520Snw141292  */
8564520Snw141292 
8574520Snw141292 static idmap_retcode
8584520Snw141292 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
8594520Snw141292 		int reqcol, const char ***values) {
8604520Snw141292 	char		*errmsg = NULL;
8614884Sjp151216 	int		r;
8624884Sjp151216 
8634884Sjp151216 	if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) {
8644520Snw141292 		idmapdlog(LOG_ERR,
8654520Snw141292 			"Database error during %s (%s)",
8664520Snw141292 			sql, CHECK_NULL(errmsg));
8674520Snw141292 		sqlite_freemem(errmsg);
8684520Snw141292 		return (IDMAP_ERR_INTERNAL);
8694520Snw141292 	}
8704520Snw141292 
8714884Sjp151216 	r = sqlite_step(*vm, ncol, values, NULL);
8724884Sjp151216 	assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
8734884Sjp151216 
8744884Sjp151216 	if (r == SQLITE_ROW) {
8754864Sbaban 		if (ncol != NULL && *ncol < reqcol) {
8764520Snw141292 			(void) sqlite_finalize(*vm, NULL);
8774520Snw141292 			*vm = NULL;
8784520Snw141292 			return (IDMAP_ERR_INTERNAL);
8794520Snw141292 		}
8804520Snw141292 		/* Caller will call finalize after using the results */
8814520Snw141292 		return (IDMAP_SUCCESS);
8824520Snw141292 	} else if (r == SQLITE_DONE) {
8834520Snw141292 		(void) sqlite_finalize(*vm, NULL);
8844520Snw141292 		*vm = NULL;
8854520Snw141292 		return (IDMAP_ERR_NOTFOUND);
8864520Snw141292 	}
8874520Snw141292 
8884520Snw141292 	(void) sqlite_finalize(*vm, &errmsg);
8894520Snw141292 	*vm = NULL;
8904520Snw141292 	idmapdlog(LOG_ERR, "Database error during %s (%s)",
8914884Sjp151216 	    sql, CHECK_NULL(errmsg));
8924520Snw141292 	sqlite_freemem(errmsg);
8934520Snw141292 	return (IDMAP_ERR_INTERNAL);
8944520Snw141292 }
8954520Snw141292 
8964864Sbaban /*
8974864Sbaban  * Table for well-known SIDs.
8984864Sbaban  *
8994864Sbaban  * Background:
9004864Sbaban  *
9014864Sbaban  * These well-known principals are stored (as of Windows Server 2003) under:
9024864Sbaban  * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
9034864Sbaban  * They belong to objectClass "foreignSecurityPrincipal". They don't have
9044864Sbaban  * "samAccountName" nor "userPrincipalName" attributes. Their names are
9054864Sbaban  * available in "cn" and "name" attributes. Some of these principals have a
9064864Sbaban  * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
9074864Sbaban  * these duplicate entries have the stringified SID in the "name" and "cn"
9084864Sbaban  * attributes instead of the actual name.
9094864Sbaban  *
9104864Sbaban  * These principals remain constant across all operating systems. Using
9114864Sbaban  * a hard-coded table here improves performance and avoids additional
9124864Sbaban  * complexity in the AD lookup code in adutils.c
9134864Sbaban  *
9144864Sbaban  * Currently we don't support localization of well-known SID names,
9154864Sbaban  * unlike Windows.
9164864Sbaban  *
9174864Sbaban  * Note that other well-known SIDs (i.e. S-1-5-<domain>-<w-k RID> and
9184864Sbaban  * S-1-5-32-<w-k RID>) are not stored here because AD does have normal
9194864Sbaban  * user/group objects for these objects and can be looked up using the
9204864Sbaban  * existing AD lookup code.
9214864Sbaban  */
9224864Sbaban static wksids_table_t wksids[] = {
9234864Sbaban 	{"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1},
9244864Sbaban 	{"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 0},
9254864Sbaban 	{"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0},
9264864Sbaban 	{"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1},
9274864Sbaban 	{"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1},
9284864Sbaban 	{"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1},
9294864Sbaban 	{"S-1-5", 2, "Network", 0, SENTINEL_PID, -1},
9304864Sbaban 	{"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1},
9314864Sbaban 	{"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1},
9324864Sbaban 	{"S-1-5", 6, "Service", 0, SENTINEL_PID, -1},
9334864Sbaban 	{"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0},
9344864Sbaban 	{"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1},
9354864Sbaban 	{"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1},
9364864Sbaban 	{"S-1-5", 10, "Self", 0, SENTINEL_PID, -1},
9374864Sbaban 	{"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1},
9384864Sbaban 	{"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1},
9394864Sbaban 	{"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1},
9404864Sbaban 	{"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1},
9414864Sbaban 	{"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1},
9424864Sbaban 	{"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0},
9434864Sbaban 	{"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1},
9444864Sbaban 	{"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1},
9454864Sbaban 	{"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1},
9464864Sbaban 	{"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1},
9474864Sbaban 	{"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1},
9484864Sbaban 	{"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1},
9494864Sbaban 	{NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1}
9504520Snw141292 };
9514520Snw141292 
9524520Snw141292 static idmap_retcode
9534520Snw141292 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res) {
9544520Snw141292 	int i;
9554864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
9564864Sbaban 		if (wksids[i].rid == req->id1.idmap_id_u.sid.rid &&
9574864Sbaban 		    (strcasecmp(wksids[i].sidprefix,
9584864Sbaban 		    req->id1.idmap_id_u.sid.prefix) == 0)) {
9594864Sbaban 
9604864Sbaban 			if (wksids[i].pid == SENTINEL_PID)
9614864Sbaban 				/* Not mapped, break */
9624864Sbaban 				break;
9634864Sbaban 			else if (wksids[i].direction == IDMAP_DIRECTION_U2W)
9644864Sbaban 				continue;
9654864Sbaban 
9664520Snw141292 			switch (req->id2.idtype) {
9674520Snw141292 			case IDMAP_UID:
9684864Sbaban 				if (wksids[i].is_user == 0)
9694864Sbaban 					continue;
9704864Sbaban 				res->id.idmap_id_u.uid = wksids[i].pid;
9714864Sbaban 				res->direction = wksids[i].direction;
9724520Snw141292 				return (IDMAP_SUCCESS);
9734520Snw141292 			case IDMAP_GID:
9744864Sbaban 				if (wksids[i].is_user == 1)
9754864Sbaban 					continue;
9764864Sbaban 				res->id.idmap_id_u.gid = wksids[i].pid;
9774864Sbaban 				res->direction = wksids[i].direction;
9784520Snw141292 				return (IDMAP_SUCCESS);
9794520Snw141292 			case IDMAP_POSIXID:
9804864Sbaban 				res->id.idmap_id_u.uid = wksids[i].pid;
9814864Sbaban 				res->id.idtype = (!wksids[i].is_user)?
9824520Snw141292 						IDMAP_GID:IDMAP_UID;
9834864Sbaban 				res->direction = wksids[i].direction;
9844520Snw141292 				return (IDMAP_SUCCESS);
9854520Snw141292 			default:
9864520Snw141292 				return (IDMAP_ERR_NOTSUPPORTED);
9874520Snw141292 			}
9884520Snw141292 		}
9894520Snw141292 	}
9904520Snw141292 	return (IDMAP_ERR_NOTFOUND);
9914520Snw141292 }
9924520Snw141292 
9934520Snw141292 static idmap_retcode
9944520Snw141292 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) {
9954520Snw141292 	int i;
9964864Sbaban 	if (req->id2.idtype != IDMAP_SID)
9974864Sbaban 		return (IDMAP_ERR_NOTSUPPORTED);
9984864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
9994864Sbaban 		if (wksids[i].pid == req->id1.idmap_id_u.uid &&
10004864Sbaban 		    wksids[i].is_user == is_user &&
10014864Sbaban 		    wksids[i].direction != IDMAP_DIRECTION_W2U) {
10024864Sbaban 			res->id.idmap_id_u.sid.rid = wksids[i].rid;
10034864Sbaban 			res->id.idmap_id_u.sid.prefix =
10044864Sbaban 				strdup(wksids[i].sidprefix);
10054864Sbaban 			if (res->id.idmap_id_u.sid.prefix == NULL) {
10064864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10074864Sbaban 				return (IDMAP_ERR_MEMORY);
10084520Snw141292 			}
10094864Sbaban 			res->direction = wksids[i].direction;
10104864Sbaban 			return (IDMAP_SUCCESS);
10114864Sbaban 		}
10124864Sbaban 	}
10134864Sbaban 	return (IDMAP_ERR_NOTFOUND);
10144864Sbaban }
10154864Sbaban 
10164864Sbaban static idmap_retcode
10174864Sbaban lookup_wksids_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
10184864Sbaban 		int *type) {
10194864Sbaban 	int i;
10204864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10214864Sbaban 		if ((strcasecmp(wksids[i].sidprefix, sidprefix) == 0) &&
10224864Sbaban 		    wksids[i].rid == rid) {
10234864Sbaban 			if ((*name = strdup(wksids[i].winname)) == NULL) {
10244864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10254864Sbaban 				return (IDMAP_ERR_MEMORY);
10264864Sbaban 			}
10274864Sbaban 			*type = (wksids[i].is_user)?
10284864Sbaban 			    _IDMAP_T_USER:_IDMAP_T_GROUP;
10294864Sbaban 			return (IDMAP_SUCCESS);
10304864Sbaban 		}
10314864Sbaban 	}
10324864Sbaban 	return (IDMAP_ERR_NOTFOUND);
10334864Sbaban }
10344864Sbaban 
10354864Sbaban static idmap_retcode
10364864Sbaban lookup_wksids_name2sid(const char *name, char **sidprefix, idmap_rid_t *rid,
10374864Sbaban 		int *type) {
10384864Sbaban 	int i;
10394864Sbaban 	for (i = 0; wksids[i].sidprefix != NULL; i++) {
10404864Sbaban 		if (strcasecmp(wksids[i].winname, name) == 0) {
10414864Sbaban 			if (sidprefix != NULL && (*sidprefix =
10424864Sbaban 			    strdup(wksids[i].sidprefix)) == NULL) {
10434864Sbaban 				idmapdlog(LOG_ERR, "Out of memory");
10444864Sbaban 				return (IDMAP_ERR_MEMORY);
10454864Sbaban 			}
10464864Sbaban 			if (type != NULL)
10474864Sbaban 				*type = (wksids[i].is_user)?
10484864Sbaban 				    _IDMAP_T_USER:_IDMAP_T_GROUP;
10494864Sbaban 			if (rid != NULL)
10504864Sbaban 				*rid = wksids[i].rid;
10514864Sbaban 			return (IDMAP_SUCCESS);
10524520Snw141292 		}
10534520Snw141292 	}
10544520Snw141292 	return (IDMAP_ERR_NOTFOUND);
10554520Snw141292 }
10564520Snw141292 
10574520Snw141292 static idmap_retcode
10584520Snw141292 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
10594520Snw141292 	char		*end;
10604520Snw141292 	char		*sql = NULL;
10614520Snw141292 	const char	**values;
10624520Snw141292 	sqlite_vm	*vm = NULL;
10634520Snw141292 	int		ncol, is_user;
10644520Snw141292 	uid_t		pid;
10654520Snw141292 	time_t		curtime, exp;
10664520Snw141292 	idmap_retcode	retcode;
10674520Snw141292 
10684520Snw141292 	/* Current time */
10694520Snw141292 	errno = 0;
10704520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
10714520Snw141292 		idmapdlog(LOG_ERR,
10724520Snw141292 			"Failed to get current time (%s)",
10734520Snw141292 			strerror(errno));
10744520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
10754520Snw141292 		goto out;
10764520Snw141292 	}
10774520Snw141292 
10784520Snw141292 	/* SQL to lookup the cache */
10794520Snw141292 	sql = sqlite_mprintf("SELECT pid, is_user, expiration, unixname, u2w "
10804520Snw141292 			"FROM idmap_cache WHERE "
10814520Snw141292 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
10824520Snw141292 			"(pid >= 2147483648 OR "
10834520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
10844520Snw141292 			"expiration > %d));",
10854520Snw141292 			req->id1.idmap_id_u.sid.prefix,
10864520Snw141292 			req->id1.idmap_id_u.sid.rid,
10874520Snw141292 			curtime);
10884520Snw141292 	if (sql == NULL) {
10894520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
10904520Snw141292 		retcode = IDMAP_ERR_MEMORY;
10914520Snw141292 		goto out;
10924520Snw141292 	}
10934520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
10944520Snw141292 	sqlite_freemem(sql);
10954520Snw141292 
10964520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
10974520Snw141292 		goto out;
10984520Snw141292 	} else if (retcode == IDMAP_SUCCESS) {
10994520Snw141292 		/* sanity checks */
11004520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
11014520Snw141292 			retcode = IDMAP_ERR_CACHE;
11024520Snw141292 			goto out;
11034520Snw141292 		}
11044520Snw141292 
11054520Snw141292 		pid = strtoul(values[0], &end, 10);
11064520Snw141292 		is_user = strncmp(values[1], "0", 2)?1:0;
11074520Snw141292 
11084520Snw141292 		/*
11094520Snw141292 		 * We may have an expired ephemeral mapping. Consider
11104520Snw141292 		 * the expired entry as valid if we are not going to
11114520Snw141292 		 * perform name-based mapping. But do not renew the
11124520Snw141292 		 * expiration.
11134520Snw141292 		 * If we will be doing name-based mapping then store the
11144520Snw141292 		 * ephemeral pid in the result so that we can use it
11154520Snw141292 		 * if we end up doing dynamic mapping again.
11164520Snw141292 		 */
11174520Snw141292 		if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) &&
11184520Snw141292 				!AVOID_NAMESERVICE(req)) {
11194864Sbaban 			if (IS_EPHEMERAL(pid) && values[2] != NULL) {
11204520Snw141292 				exp = strtoll(values[2], &end, 10);
11214520Snw141292 				if (exp && exp <= curtime) {
11224520Snw141292 					/* Store the ephemeral pid */
11234520Snw141292 					res->id.idmap_id_u.uid = pid;
11244520Snw141292 					res->id.idtype = is_user?
11254520Snw141292 						IDMAP_UID:IDMAP_GID;
11264644Sbaban 					res->direction = IDMAP_DIRECTION_BI;
11274520Snw141292 					req->direction |= is_user?
11284520Snw141292 						_IDMAP_F_EXP_EPH_UID:
11294520Snw141292 						_IDMAP_F_EXP_EPH_GID;
11304520Snw141292 					retcode = IDMAP_ERR_NOTFOUND;
11314520Snw141292 					goto out;
11324520Snw141292 				}
11334520Snw141292 			}
11344520Snw141292 		}
11354520Snw141292 
11364520Snw141292 		switch (req->id2.idtype) {
11374520Snw141292 		case IDMAP_UID:
11384520Snw141292 			if (!is_user)
11394520Snw141292 				retcode = IDMAP_ERR_NOTUSER;
11404520Snw141292 			else
11414520Snw141292 				res->id.idmap_id_u.uid = pid;
11424520Snw141292 			break;
11434520Snw141292 		case IDMAP_GID:
11444520Snw141292 			if (is_user)
11454520Snw141292 				retcode = IDMAP_ERR_NOTGROUP;
11464520Snw141292 			else
11474520Snw141292 				res->id.idmap_id_u.gid = pid;
11484520Snw141292 			break;
11494520Snw141292 		case IDMAP_POSIXID:
11504520Snw141292 			res->id.idmap_id_u.uid = pid;
11514520Snw141292 			res->id.idtype = (is_user)?IDMAP_UID:IDMAP_GID;
11524520Snw141292 			break;
11534520Snw141292 		default:
11544520Snw141292 			retcode = IDMAP_ERR_NOTSUPPORTED;
11554520Snw141292 			break;
11564520Snw141292 		}
11574520Snw141292 	}
11584520Snw141292 
11594520Snw141292 out:
11604520Snw141292 	if (retcode == IDMAP_SUCCESS) {
11614864Sbaban 		if (values[4] != NULL)
11624520Snw141292 			res->direction =
11634644Sbaban 			    (strtol(values[4], &end, 10) == 0)?
11644644Sbaban 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
11654520Snw141292 		else
11664644Sbaban 			res->direction = IDMAP_DIRECTION_W2U;
11674520Snw141292 
11684864Sbaban 		if (values[3] != NULL) {
1169*5064Sdm199847 			req->id2name = strdup(values[3]);
1170*5064Sdm199847 			if (req->id2name == NULL) {
11714520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
11724520Snw141292 				retcode = IDMAP_ERR_MEMORY;
11734520Snw141292 			}
11744520Snw141292 		}
11754520Snw141292 	}
11764864Sbaban 	if (vm != NULL)
11774520Snw141292 		(void) sqlite_finalize(vm, NULL);
11784520Snw141292 	return (retcode);
11794520Snw141292 }
11804520Snw141292 
11814520Snw141292 static idmap_retcode
11824864Sbaban lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid,
11834520Snw141292 		char **name, char **domain, int *type) {
11844520Snw141292 	char		*end;
11854520Snw141292 	char		*sql = NULL;
11864520Snw141292 	const char	**values;
11874520Snw141292 	sqlite_vm	*vm = NULL;
11884520Snw141292 	int		ncol;
11894520Snw141292 	time_t		curtime;
11904520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
11914520Snw141292 
11924520Snw141292 	/* Get current time */
11934520Snw141292 	errno = 0;
11944520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
11954520Snw141292 		idmapdlog(LOG_ERR,
11964520Snw141292 			"Failed to get current time (%s)",
11974520Snw141292 			strerror(errno));
11984520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
11994520Snw141292 		goto out;
12004520Snw141292 	}
12014520Snw141292 
12024520Snw141292 	/* SQL to lookup the cache */
12034520Snw141292 	sql = sqlite_mprintf("SELECT name, domain, type FROM name_cache WHERE "
12044520Snw141292 			"sidprefix = %Q AND rid = %u AND "
12054520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
12064520Snw141292 			"expiration > %d);",
12074520Snw141292 			sidprefix, rid, curtime);
12084520Snw141292 	if (sql == NULL) {
12094520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
12104520Snw141292 		retcode = IDMAP_ERR_MEMORY;
12114520Snw141292 		goto out;
12124520Snw141292 	}
12134520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
12144520Snw141292 	sqlite_freemem(sql);
12154520Snw141292 
12164520Snw141292 	if (retcode == IDMAP_SUCCESS) {
12174864Sbaban 		if (type != NULL) {
12184520Snw141292 			if (values[2] == NULL) {
12194520Snw141292 				retcode = IDMAP_ERR_CACHE;
12204520Snw141292 				goto out;
12214520Snw141292 			}
12224520Snw141292 			*type = strtol(values[2], &end, 10);
12234520Snw141292 		}
12244520Snw141292 
12254864Sbaban 		if (name != NULL && values[0] != NULL) {
12264520Snw141292 			if ((*name = strdup(values[0])) == NULL) {
12274520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
12284520Snw141292 				retcode = IDMAP_ERR_MEMORY;
12294520Snw141292 				goto out;
12304520Snw141292 			}
12314520Snw141292 		}
12324520Snw141292 
12334864Sbaban 		if (domain != NULL && values[1] != NULL) {
12344520Snw141292 			if ((*domain = strdup(values[1])) == NULL) {
12354864Sbaban 				if (name != NULL && *name) {
12364520Snw141292 					free(*name);
12374520Snw141292 					*name = NULL;
12384520Snw141292 				}
12394520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
12404520Snw141292 				retcode = IDMAP_ERR_MEMORY;
12414520Snw141292 				goto out;
12424520Snw141292 			}
12434520Snw141292 		}
12444520Snw141292 	}
12454520Snw141292 
12464520Snw141292 out:
12474864Sbaban 	if (vm != NULL)
12484520Snw141292 		(void) sqlite_finalize(vm, NULL);
12494520Snw141292 	return (retcode);
12504520Snw141292 }
12514520Snw141292 
12524520Snw141292 static idmap_retcode
12534520Snw141292 verify_type(idmap_id_type idtype, int type, idmap_id_res *res) {
12544520Snw141292 	switch (idtype) {
12554520Snw141292 	case IDMAP_UID:
12564520Snw141292 		if (type != _IDMAP_T_USER)
12574520Snw141292 			return (IDMAP_ERR_NOTUSER);
12584520Snw141292 		res->id.idtype = IDMAP_UID;
12594520Snw141292 		break;
12604520Snw141292 	case IDMAP_GID:
12614520Snw141292 		if (type != _IDMAP_T_GROUP)
12624520Snw141292 			return (IDMAP_ERR_NOTGROUP);
12634520Snw141292 		res->id.idtype = IDMAP_GID;
12644520Snw141292 		break;
12654520Snw141292 	case IDMAP_POSIXID:
12664520Snw141292 		if (type == _IDMAP_T_USER)
12674520Snw141292 			res->id.idtype = IDMAP_UID;
12684520Snw141292 		else if (type == _IDMAP_T_GROUP)
12694520Snw141292 			res->id.idtype = IDMAP_GID;
12704520Snw141292 		else
12714520Snw141292 			return (IDMAP_ERR_SID);
12724520Snw141292 		break;
12734520Snw141292 	default:
12744520Snw141292 		return (IDMAP_ERR_NOTSUPPORTED);
12754520Snw141292 	}
12764520Snw141292 	return (IDMAP_SUCCESS);
12774520Snw141292 }
12784520Snw141292 
12794520Snw141292 /*
12804864Sbaban  * Lookup sid to name locally
12814520Snw141292  */
12824520Snw141292 static idmap_retcode
12834864Sbaban lookup_local_sid2name(sqlite *cache, idmap_mapping *req, idmap_id_res *res) {
12844520Snw141292 	int		type = -1;
12854520Snw141292 	idmap_retcode	retcode;
12864520Snw141292 	char		*sidprefix;
12874520Snw141292 	idmap_rid_t	rid;
12884520Snw141292 	char		*name = NULL, *domain = NULL;
12894520Snw141292 
12904520Snw141292 	sidprefix = req->id1.idmap_id_u.sid.prefix;
12914520Snw141292 	rid = req->id1.idmap_id_u.sid.rid;
12924520Snw141292 
12934864Sbaban 	/* Lookup sids to name in well-known sids table */
12944864Sbaban 	retcode = lookup_wksids_sid2name(sidprefix, rid, &name, &type);
12954864Sbaban 	if (retcode != IDMAP_ERR_NOTFOUND)
12964864Sbaban 		goto out;
12974864Sbaban 
12984520Snw141292 	/* Lookup sid to name in cache */
12994864Sbaban 	retcode = lookup_cache_sid2name(cache, sidprefix, rid, &name,
13004520Snw141292 		&domain, &type);
13014520Snw141292 	if (retcode != IDMAP_SUCCESS)
13024520Snw141292 		goto out;
13034520Snw141292 
13044520Snw141292 out:
13054520Snw141292 	if (retcode == IDMAP_SUCCESS) {
13064864Sbaban 		/* Verify that the sid type matches the request */
13074864Sbaban 		retcode = verify_type(req->id2.idtype, type, res);
13084864Sbaban 
13094520Snw141292 		/* update state in 'req' */
1310*5064Sdm199847 		if (name != NULL)
1311*5064Sdm199847 			req->id1name = name;
1312*5064Sdm199847 		if (domain != NULL)
1313*5064Sdm199847 			req->id1domain = domain;
13144520Snw141292 	} else {
13154864Sbaban 		if (name != NULL)
13164520Snw141292 			free(name);
13174864Sbaban 		if (domain != NULL)
13184520Snw141292 			free(domain);
13194520Snw141292 	}
13204520Snw141292 	return (retcode);
13214520Snw141292 }
13224520Snw141292 
13234520Snw141292 idmap_retcode
13244520Snw141292 lookup_win_batch_sid2name(lookup_state_t *state, idmap_mapping_batch *batch,
13254520Snw141292 		idmap_ids_res *result) {
13264520Snw141292 	idmap_retcode	retcode;
13274520Snw141292 	int		ret, i;
13284520Snw141292 	int		retries = 0;
13294520Snw141292 	idmap_mapping	*req;
13304520Snw141292 	idmap_id_res	*res;
13314520Snw141292 
13324520Snw141292 	if (state->ad_nqueries == 0)
13334520Snw141292 		return (IDMAP_SUCCESS);
13344520Snw141292 
13354520Snw141292 retry:
13364520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries,
13374520Snw141292 		&state->ad_lookup);
13384520Snw141292 	if (ret != 0) {
13394520Snw141292 		idmapdlog(LOG_ERR,
13404520Snw141292 		"Failed to create sid2name batch for AD lookup");
13414520Snw141292 		return (IDMAP_ERR_INTERNAL);
13424520Snw141292 	}
13434520Snw141292 
13444520Snw141292 	for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
13454520Snw141292 		req = &batch->idmap_mapping_batch_val[i];
13464520Snw141292 		res = &result->ids.ids_val[i];
13474520Snw141292 
13484520Snw141292 		if (req->id1.idtype == IDMAP_SID &&
13494520Snw141292 				req->direction & _IDMAP_F_S2N_AD) {
13504864Sbaban 			if (retries == 0)
13514864Sbaban 				res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
13524864Sbaban 			else if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
13534864Sbaban 				continue;
13544520Snw141292 			retcode = idmap_sid2name_batch_add1(
13554520Snw141292 					state->ad_lookup,
13564520Snw141292 					req->id1.idmap_id_u.sid.prefix,
13574520Snw141292 					&req->id1.idmap_id_u.sid.rid,
1358*5064Sdm199847 					&req->id1name,
1359*5064Sdm199847 					&req->id1domain,
13604520Snw141292 					(int *)&res->id.idtype,
13614520Snw141292 					&res->retcode);
13624520Snw141292 
13634520Snw141292 			if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
13644520Snw141292 				break;
13654520Snw141292 			if (retcode != IDMAP_SUCCESS)
13664520Snw141292 				goto out;
13674520Snw141292 		}
13684520Snw141292 	}
13694520Snw141292 
13704520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
13714884Sjp151216 		idmap_lookup_release_batch(&state->ad_lookup);
13724520Snw141292 	else
13734520Snw141292 		retcode = idmap_lookup_batch_end(&state->ad_lookup, NULL);
13744520Snw141292 
13754520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
13764520Snw141292 		goto retry;
13774520Snw141292 
13784520Snw141292 	return (retcode);
13794520Snw141292 
13804520Snw141292 out:
13814520Snw141292 	idmapdlog(LOG_NOTICE, "Windows SID to user/group name lookup failed");
13824884Sjp151216 	idmap_lookup_release_batch(&state->ad_lookup);
13834520Snw141292 	return (retcode);
13844520Snw141292 }
13854520Snw141292 
13864520Snw141292 idmap_retcode
13874520Snw141292 sid2pid_first_pass(lookup_state_t *state, sqlite *cache, idmap_mapping *req,
13884520Snw141292 		idmap_id_res *res) {
13894520Snw141292 	idmap_retcode	retcode;
13904520Snw141292 
13914520Snw141292 	/*
13924520Snw141292 	 * The req->direction field is used to maintain state of the
13934520Snw141292 	 * sid2pid request.
13944520Snw141292 	 */
13954520Snw141292 	req->direction = _IDMAP_F_DONE;
13964520Snw141292 
13974520Snw141292 	if (req->id1.idmap_id_u.sid.prefix == NULL) {
13984520Snw141292 		retcode = IDMAP_ERR_SID;
13994520Snw141292 		goto out;
14004520Snw141292 	}
14014520Snw141292 	res->id.idtype = req->id2.idtype;
14024520Snw141292 	res->id.idmap_id_u.uid = UID_NOBODY;
14034520Snw141292 
14044864Sbaban 	/* Lookup well-known sid to pid mapping */
14054520Snw141292 	retcode = lookup_wksids_sid2pid(req, res);
14064520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
14074520Snw141292 		goto out;
14084520Snw141292 
14094520Snw141292 	/* Lookup sid to pid in cache */
14104520Snw141292 	retcode = lookup_cache_sid2pid(cache, req, res);
14114520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
14124520Snw141292 		goto out;
14134520Snw141292 
14144520Snw141292 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
14154520Snw141292 		res->id.idmap_id_u.uid = SENTINEL_PID;
14164520Snw141292 		goto out;
14174520Snw141292 	}
14184520Snw141292 
14194520Snw141292 	/*
14204520Snw141292 	 * Failed to find non-expired entry in cache. Tell the caller
14214520Snw141292 	 * that we are not done yet.
14224520Snw141292 	 */
14234520Snw141292 	state->sid2pid_done = FALSE;
14244520Snw141292 
14254520Snw141292 	/*
14264520Snw141292 	 * Our next step is name-based mapping. To lookup name-based
14274520Snw141292 	 * mapping rules, we need the windows name and domain-name
14284520Snw141292 	 * associated with the SID.
14294520Snw141292 	 */
14304520Snw141292 
14314520Snw141292 	/*
14324520Snw141292 	 * Check if we already have the name (i.e name2pid lookups)
14334520Snw141292 	 */
1434*5064Sdm199847 	if (req->id1name != NULL &&
1435*5064Sdm199847 	    req->id1domain != NULL) {
14364520Snw141292 		retcode = IDMAP_SUCCESS;
14374520Snw141292 		req->direction |= _IDMAP_F_S2N_CACHE;
14384520Snw141292 		goto out;
14394520Snw141292 	}
14404520Snw141292 
14414864Sbaban 	/* Lookup sid to winname@domain locally first */
14424864Sbaban 	retcode = lookup_local_sid2name(cache, req, res);
14434864Sbaban 	if (retcode == IDMAP_SUCCESS) {
14444864Sbaban 		req->direction |= _IDMAP_F_S2N_CACHE;
14454864Sbaban 	} else if (retcode == IDMAP_ERR_NOTFOUND) {
14464520Snw141292 		/* Batch sid to name AD lookup request */
14474520Snw141292 		retcode = IDMAP_SUCCESS;
14484520Snw141292 		req->direction |= _IDMAP_F_S2N_AD;
14494520Snw141292 		state->ad_nqueries++;
14504520Snw141292 		goto out;
14514520Snw141292 	}
14524520Snw141292 
14534520Snw141292 
14544520Snw141292 out:
14554520Snw141292 	res->retcode = idmap_stat4prot(retcode);
14564520Snw141292 	return (retcode);
14574520Snw141292 }
14584520Snw141292 
14594520Snw141292 /*
14604520Snw141292  * Generate SID using the following convention
14614520Snw141292  * 	<machine-sid-prefix>-<1000 + uid>
14624520Snw141292  * 	<machine-sid-prefix>-<2^31 + gid>
14634520Snw141292  */
14644520Snw141292 static idmap_retcode
14654520Snw141292 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user) {
14664520Snw141292 
14674864Sbaban 	if (_idmapdstate.cfg->pgcfg.machine_sid != NULL) {
14684520Snw141292 		/* Skip 1000 UIDs */
14694520Snw141292 		if (is_user && req->id1.idmap_id_u.uid >
14704520Snw141292 				(INT32_MAX - LOCALRID_MIN))
14714864Sbaban 			return (IDMAP_ERR_NOMAPPING);
14724520Snw141292 
14734520Snw141292 		RDLOCK_CONFIG();
14744520Snw141292 		res->id.idmap_id_u.sid.prefix =
14754520Snw141292 			strdup(_idmapdstate.cfg->pgcfg.machine_sid);
14764520Snw141292 		if (res->id.idmap_id_u.sid.prefix == NULL) {
14774520Snw141292 			UNLOCK_CONFIG();
14784520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
14794520Snw141292 			return (IDMAP_ERR_MEMORY);
14804520Snw141292 		}
14814520Snw141292 		UNLOCK_CONFIG();
14824520Snw141292 		res->id.idmap_id_u.sid.rid =
14834520Snw141292 			(is_user)?req->id1.idmap_id_u.uid + LOCALRID_MIN:
14844520Snw141292 			req->id1.idmap_id_u.gid + INT32_MAX + 1;
14854644Sbaban 		res->direction = IDMAP_DIRECTION_BI;
14864520Snw141292 
14874520Snw141292 		/*
14884520Snw141292 		 * Don't update name_cache because local sids don't have
14894520Snw141292 		 * valid windows names.
14904520Snw141292 		 * We mark the entry as being found in the namecache so that
14914520Snw141292 		 * the cache update routine doesn't update namecache.
14924520Snw141292 		 */
14934520Snw141292 		req->direction = _IDMAP_F_S2N_CACHE;
14944868Sbaban 		return (IDMAP_SUCCESS);
14954520Snw141292 	}
14964520Snw141292 
14974864Sbaban 	return (IDMAP_ERR_NOMAPPING);
14984520Snw141292 }
14994520Snw141292 
15004520Snw141292 static idmap_retcode
15014520Snw141292 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) {
15024520Snw141292 	char		*sidprefix;
15034520Snw141292 	uint32_t	rid;
15044520Snw141292 	int		s;
15054520Snw141292 
15064520Snw141292 	/*
15074520Snw141292 	 * If the sidprefix == localsid then UID = last RID - 1000 or
15084520Snw141292 	 * GID = last RID - 2^31.
15094520Snw141292 	 */
15104520Snw141292 	sidprefix = req->id1.idmap_id_u.sid.prefix;
15114520Snw141292 	rid = req->id1.idmap_id_u.sid.rid;
15124520Snw141292 
15134520Snw141292 	RDLOCK_CONFIG();
15144520Snw141292 	s = (_idmapdstate.cfg->pgcfg.machine_sid)?
15154520Snw141292 		strcasecmp(sidprefix,
15164520Snw141292 		_idmapdstate.cfg->pgcfg.machine_sid):1;
15174520Snw141292 	UNLOCK_CONFIG();
15184520Snw141292 
15194520Snw141292 	if (s == 0) {
15204520Snw141292 		switch (req->id2.idtype) {
15214520Snw141292 		case IDMAP_UID:
15224520Snw141292 			if (rid > INT32_MAX) {
15234520Snw141292 				return (IDMAP_ERR_NOTUSER);
15244520Snw141292 			} else if (rid < LOCALRID_MIN) {
15254520Snw141292 				return (IDMAP_ERR_NOTFOUND);
15264520Snw141292 			}
15274520Snw141292 			res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
15284520Snw141292 			res->id.idtype = IDMAP_UID;
15294520Snw141292 			break;
15304520Snw141292 		case IDMAP_GID:
15314520Snw141292 			if (rid <= INT32_MAX) {
15324520Snw141292 				return (IDMAP_ERR_NOTGROUP);
15334520Snw141292 			}
15344520Snw141292 			res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
15354520Snw141292 			res->id.idtype = IDMAP_GID;
15364520Snw141292 			break;
15374520Snw141292 		case IDMAP_POSIXID:
15384520Snw141292 			if (rid > INT32_MAX) {
15394520Snw141292 				res->id.idmap_id_u.gid =
15404520Snw141292 					rid - INT32_MAX - 1;
15414520Snw141292 				res->id.idtype = IDMAP_GID;
15424520Snw141292 			} else if (rid < LOCALRID_MIN) {
15434520Snw141292 				return (IDMAP_ERR_NOTFOUND);
15444520Snw141292 			} else {
15454520Snw141292 				res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
15464520Snw141292 				res->id.idtype = IDMAP_UID;
15474520Snw141292 			}
15484520Snw141292 			break;
15494520Snw141292 		default:
15504520Snw141292 			return (IDMAP_ERR_NOTSUPPORTED);
15514520Snw141292 		}
15524520Snw141292 		return (IDMAP_SUCCESS);
15534520Snw141292 	}
15544520Snw141292 
15554520Snw141292 	return (IDMAP_ERR_NOTFOUND);
15564520Snw141292 }
15574520Snw141292 
15584520Snw141292 static idmap_retcode
15594520Snw141292 ns_lookup_byname(int is_user, const char *name, idmap_id_res *res) {
15604520Snw141292 	struct passwd	pwd;
15614520Snw141292 	struct group	grp;
15624520Snw141292 	char		buf[1024];
15634520Snw141292 	int		errnum;
15644520Snw141292 	const char	*me = "ns_lookup_byname";
15654520Snw141292 
15664520Snw141292 	if (is_user) {
15674520Snw141292 		if (getpwnam_r(name, &pwd, buf, sizeof (buf)) == NULL) {
15684520Snw141292 			errnum = errno;
15694520Snw141292 			idmapdlog(LOG_WARNING,
15704520Snw141292 			"%s: getpwnam_r(%s) failed (%s).",
15714520Snw141292 				me, name,
15724520Snw141292 				errnum?strerror(errnum):"not found");
15734520Snw141292 			if (errnum == 0)
15744520Snw141292 				return (IDMAP_ERR_NOTFOUND);
15754520Snw141292 			else
15764520Snw141292 				return (IDMAP_ERR_INTERNAL);
15774520Snw141292 		}
15784520Snw141292 		res->id.idmap_id_u.uid = pwd.pw_uid;
15794520Snw141292 		res->id.idtype = IDMAP_UID;
15804520Snw141292 	} else {
15814520Snw141292 		if (getgrnam_r(name, &grp, buf, sizeof (buf)) == NULL) {
15824520Snw141292 			errnum = errno;
15834520Snw141292 			idmapdlog(LOG_WARNING,
15844520Snw141292 			"%s: getgrnam_r(%s) failed (%s).",
15854520Snw141292 				me, name,
15864520Snw141292 				errnum?strerror(errnum):"not found");
15874520Snw141292 			if (errnum == 0)
15884520Snw141292 				return (IDMAP_ERR_NOTFOUND);
15894520Snw141292 			else
15904520Snw141292 				return (IDMAP_ERR_INTERNAL);
15914520Snw141292 		}
15924520Snw141292 		res->id.idmap_id_u.gid = grp.gr_gid;
15934520Snw141292 		res->id.idtype = IDMAP_GID;
15944520Snw141292 	}
15954520Snw141292 	return (IDMAP_SUCCESS);
15964520Snw141292 }
15974520Snw141292 
15984520Snw141292 /*
15994520Snw141292  * Name-based mapping
16004520Snw141292  *
16014520Snw141292  * Case 1: If no rule matches do ephemeral
16024520Snw141292  *
16034520Snw141292  * Case 2: If rule matches and unixname is "" then return no mapping.
16044520Snw141292  *
16054520Snw141292  * Case 3: If rule matches and unixname is specified then lookup name
16064520Snw141292  *  service using the unixname. If unixname not found then return no mapping.
16074520Snw141292  *
16084520Snw141292  * Case 4: If rule matches and unixname is * then lookup name service
16094520Snw141292  *  using winname as the unixname. If unixname not found then process
16104520Snw141292  *  other rules using the lookup order. If no other rule matches then do
16114520Snw141292  *  ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
16124520Snw141292  *  This allows us to specify a fallback unixname per _domain_ or no mapping
16134520Snw141292  *  instead of the default behaviour of doing ephemeral mapping.
16144520Snw141292  *
16154520Snw141292  * Example 1:
16164520Snw141292  * *@sfbay == *
16174520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16184520Snw141292  * the name service then foo@sfbay will be mapped to an ephemeral id.
16194520Snw141292  *
16204520Snw141292  * Example 2:
16214520Snw141292  * *@sfbay == *
16224520Snw141292  * *@sfbay => guest
16234520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16244520Snw141292  * the name service then foo@sfbay will be mapped to guest.
16254520Snw141292  *
16264520Snw141292  * Example 3:
16274520Snw141292  * *@sfbay == *
16284520Snw141292  * *@sfbay => ""
16294520Snw141292  * If looking up windows users foo@sfbay and foo does not exists in
16304520Snw141292  * the name service then we will return no mapping for foo@sfbay.
16314520Snw141292  *
16324520Snw141292  */
16334520Snw141292 static idmap_retcode
16344520Snw141292 name_based_mapping_sid2pid(sqlite *db, idmap_mapping *req, idmap_id_res *res) {
16354520Snw141292 	const char	*unixname, *winname, *windomain;
16364520Snw141292 	char		*sql = NULL, *errmsg = NULL;
16374520Snw141292 	idmap_retcode	retcode;
16384520Snw141292 	char		*end;
16394520Snw141292 	const char	**values;
16404520Snw141292 	sqlite_vm	*vm = NULL;
16414884Sjp151216 	int		ncol, r, i, is_user;
16424520Snw141292 	const char	*me = "name_based_mapping_sid2pid";
16434520Snw141292 
1644*5064Sdm199847 	winname = req->id1name;
1645*5064Sdm199847 	windomain = req->id1domain;
16464520Snw141292 	is_user = (res->id.idtype == IDMAP_UID)?1:0;
16474520Snw141292 
16484520Snw141292 	i = 0;
16494864Sbaban 	if (windomain == NULL) {
16504864Sbaban 		windomain = "";
16514864Sbaban 	} else {
16524864Sbaban 		RDLOCK_CONFIG();
16534864Sbaban 		if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
16544864Sbaban 			if (strcasecmp(_idmapdstate.cfg->pgcfg.mapping_domain,
16554864Sbaban 			    windomain) == 0)
16564864Sbaban 				i = 1;
16574864Sbaban 		}
16584864Sbaban 		UNLOCK_CONFIG();
16594520Snw141292 	}
16604520Snw141292 
16614520Snw141292 	sql = sqlite_mprintf(
16624520Snw141292 		"SELECT unixname, u2w_order FROM namerules WHERE "
16634520Snw141292 		"w2u_order > 0 AND is_user = %d AND "
16644520Snw141292 		"(winname = %Q OR winname = '*') AND "
16654520Snw141292 		"(windomain = %Q OR windomain = '*' %s) "
16664520Snw141292 		"ORDER BY w2u_order ASC;",
16674864Sbaban 		is_user, winname,
16684864Sbaban 		windomain,
16694864Sbaban 		i?"OR windomain ISNULL OR windomain = ''":"");
16704520Snw141292 	if (sql == NULL) {
16714520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
16724520Snw141292 		retcode = IDMAP_ERR_MEMORY;
16734520Snw141292 		goto out;
16744520Snw141292 	}
16754520Snw141292 
16764520Snw141292 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
16774520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
16784520Snw141292 		idmapdlog(LOG_ERR,
16794520Snw141292 			"%s: database error (%s)",
16804520Snw141292 			me, CHECK_NULL(errmsg));
16814520Snw141292 		sqlite_freemem(errmsg);
16824520Snw141292 		goto out;
16834520Snw141292 	}
16844520Snw141292 
16854884Sjp151216 	for (; ; ) {
16864520Snw141292 		r = sqlite_step(vm, &ncol, &values, NULL);
16874884Sjp151216 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
16884884Sjp151216 
16894884Sjp151216 		if (r == SQLITE_ROW) {
16904520Snw141292 			if (ncol < 2) {
16914520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
16924520Snw141292 				goto out;
16934520Snw141292 			}
16944520Snw141292 			if (values[0] == NULL) {
16954520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
16964520Snw141292 				goto out;
16974520Snw141292 			}
16984520Snw141292 
16994520Snw141292 			if (EMPTY_NAME(values[0])) {
17004520Snw141292 				retcode = IDMAP_ERR_NOMAPPING;
17014520Snw141292 				goto out;
17024520Snw141292 			}
17034520Snw141292 			unixname = (values[0][0] == '*')?winname:values[0];
17044520Snw141292 			retcode = ns_lookup_byname(is_user, unixname, res);
17054520Snw141292 			if (retcode == IDMAP_ERR_NOTFOUND) {
17064520Snw141292 				if (unixname == winname)
17074520Snw141292 					/* Case 4 */
17084520Snw141292 					continue;
17094520Snw141292 				else
17104520Snw141292 					/* Case 3 */
17114520Snw141292 					retcode = IDMAP_ERR_NOMAPPING;
17124520Snw141292 			}
17134520Snw141292 			goto out;
17144520Snw141292 		} else if (r == SQLITE_DONE) {
17154520Snw141292 			retcode = IDMAP_ERR_NOTFOUND;
17164520Snw141292 			goto out;
17174520Snw141292 		} else {
17184520Snw141292 			(void) sqlite_finalize(vm, &errmsg);
17194520Snw141292 			vm = NULL;
17204520Snw141292 			idmapdlog(LOG_ERR,
17214520Snw141292 				"%s: database error (%s)",
17224520Snw141292 				me, CHECK_NULL(errmsg));
17234520Snw141292 			sqlite_freemem(errmsg);
17244520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
17254520Snw141292 			goto out;
17264520Snw141292 		}
17274520Snw141292 	}
17284520Snw141292 
17294520Snw141292 out:
17304864Sbaban 	if (sql != NULL)
17314520Snw141292 		sqlite_freemem(sql);
17324520Snw141292 	if (retcode == IDMAP_SUCCESS) {
17334864Sbaban 		if (values[1] != NULL)
17344520Snw141292 			res->direction =
17354644Sbaban 			    (strtol(values[1], &end, 10) == 0)?
17364644Sbaban 			    IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
17374520Snw141292 		else
17384644Sbaban 			res->direction = IDMAP_DIRECTION_W2U;
1739*5064Sdm199847 		req->id2name = strdup(unixname);
17404520Snw141292 	}
17414864Sbaban 	if (vm != NULL)
17424520Snw141292 		(void) sqlite_finalize(vm, NULL);
17434520Snw141292 	return (retcode);
17444520Snw141292 }
17454520Snw141292 
17464520Snw141292 static
17474520Snw141292 int
17484520Snw141292 get_next_eph_uid(uid_t *next_uid)
17494520Snw141292 {
17504520Snw141292 	uid_t uid;
17514520Snw141292 	gid_t gid;
17524520Snw141292 	int err;
17534520Snw141292 
17544520Snw141292 	*next_uid = (uid_t)-1;
17554520Snw141292 	uid = _idmapdstate.next_uid++;
17564520Snw141292 	if (uid >= _idmapdstate.limit_uid) {
17574520Snw141292 		if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0)
17584520Snw141292 			return (err);
17594520Snw141292 
17604520Snw141292 		_idmapdstate.limit_uid = uid + 8192;
17614520Snw141292 		_idmapdstate.next_uid = uid;
17624520Snw141292 	}
17634520Snw141292 	*next_uid = uid;
17644520Snw141292 
17654520Snw141292 	return (0);
17664520Snw141292 }
17674520Snw141292 
17684520Snw141292 static
17694520Snw141292 int
17704520Snw141292 get_next_eph_gid(gid_t *next_gid)
17714520Snw141292 {
17724520Snw141292 	uid_t uid;
17734520Snw141292 	gid_t gid;
17744520Snw141292 	int err;
17754520Snw141292 
17764520Snw141292 	*next_gid = (uid_t)-1;
17774520Snw141292 	gid = _idmapdstate.next_gid++;
17784520Snw141292 	if (gid >= _idmapdstate.limit_gid) {
17794520Snw141292 		if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0)
17804520Snw141292 			return (err);
17814520Snw141292 
17824520Snw141292 		_idmapdstate.limit_gid = gid + 8192;
17834520Snw141292 		_idmapdstate.next_gid = gid;
17844520Snw141292 	}
17854520Snw141292 	*next_gid = gid;
17864520Snw141292 
17874520Snw141292 	return (0);
17884520Snw141292 }
17894520Snw141292 
17904864Sbaban static
17914864Sbaban int
17924864Sbaban gethash(const char *str, uint32_t num, uint_t htsize) {
17934864Sbaban 	uint_t  hval, i, len;
17944864Sbaban 
17954864Sbaban 	if (str == NULL)
17964864Sbaban 		return (0);
17974864Sbaban 	for (len = strlen(str), hval = 0, i = 0; i < len; i++) {
17984864Sbaban 		hval += str[i];
17994864Sbaban 		hval += (hval << 10);
18004864Sbaban 		hval ^= (hval >> 6);
18014864Sbaban 	}
18024864Sbaban 	for (str = (const char *)&num, i = 0; i < sizeof (num); i++) {
18034864Sbaban 		hval += str[i];
18044864Sbaban 		hval += (hval << 10);
18054864Sbaban 		hval ^= (hval >> 6);
18064864Sbaban 	}
18074864Sbaban 	hval += (hval << 3);
18084864Sbaban 	hval ^= (hval >> 11);
18094864Sbaban 	hval += (hval << 15);
18104864Sbaban 	return (hval % htsize);
18114864Sbaban }
18124864Sbaban 
18134864Sbaban static
18144864Sbaban int
18154864Sbaban get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid,
18164864Sbaban 		uid_t *pid) {
18174864Sbaban 	uint_t		next, key;
18184864Sbaban 	uint_t		htsize = state->sid_history_size;
18194864Sbaban 	idmap_sid	*sid;
18204864Sbaban 
18214864Sbaban 	next = gethash(prefix, rid, htsize);
18224864Sbaban 	while (next != htsize) {
18234864Sbaban 		key = state->sid_history[next].key;
18244864Sbaban 		if (key == htsize)
18254864Sbaban 			return (0);
18264864Sbaban 		sid = &state->batch->idmap_mapping_batch_val[key].id1.
18274864Sbaban 		    idmap_id_u.sid;
18284864Sbaban 		if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) {
18294864Sbaban 			*pid = state->result->ids.ids_val[key].id.
18304864Sbaban 			    idmap_id_u.uid;
18314864Sbaban 			return (1);
18324864Sbaban 		}
18334864Sbaban 		next = state->sid_history[next].next;
18344864Sbaban 	}
18354864Sbaban 	return (0);
18364864Sbaban }
18374864Sbaban 
18384864Sbaban static
18394864Sbaban void
18404864Sbaban add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) {
18414864Sbaban 	uint_t		hash, next;
18424864Sbaban 	uint_t		htsize = state->sid_history_size;
18434864Sbaban 
18444864Sbaban 	hash = next = gethash(prefix, rid, htsize);
18454864Sbaban 	while (state->sid_history[next].key != htsize) {
18464864Sbaban 		next++;
18474864Sbaban 		next %= htsize;
18484864Sbaban 	}
18494864Sbaban 	state->sid_history[next].key = state->curpos;
18504864Sbaban 	if (hash == next)
18514864Sbaban 		return;
18524864Sbaban 	state->sid_history[next].next = state->sid_history[hash].next;
18534864Sbaban 	state->sid_history[hash].next = next;
18544864Sbaban }
18554520Snw141292 
18564520Snw141292 /* ARGSUSED */
18574520Snw141292 static
18584520Snw141292 idmap_retcode
18594864Sbaban dynamic_ephemeral_mapping(lookup_state_t *state, sqlite *cache,
18604864Sbaban 		idmap_mapping *req, idmap_id_res *res) {
18614520Snw141292 
18624520Snw141292 	uid_t		next_pid;
18634520Snw141292 
18644864Sbaban 	res->direction = IDMAP_DIRECTION_BI;
18654864Sbaban 
18664864Sbaban 	if (IS_EPHEMERAL(res->id.idmap_id_u.uid))
18674864Sbaban 		return (IDMAP_SUCCESS);
18684864Sbaban 
18694864Sbaban 	if (state->sid_history != NULL &&
18704864Sbaban 	    get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix,
18714864Sbaban 	    req->id1.idmap_id_u.sid.rid, &next_pid)) {
18724864Sbaban 		res->id.idmap_id_u.uid = next_pid;
18734864Sbaban 		return (IDMAP_SUCCESS);
18744864Sbaban 	}
18754864Sbaban 
18764864Sbaban 	if (res->id.idtype == IDMAP_UID) {
18774520Snw141292 		if (get_next_eph_uid(&next_pid) != 0)
18784520Snw141292 			return (IDMAP_ERR_INTERNAL);
18794520Snw141292 		res->id.idmap_id_u.uid = next_pid;
18804520Snw141292 	} else {
18814520Snw141292 		if (get_next_eph_gid(&next_pid) != 0)
18824520Snw141292 			return (IDMAP_ERR_INTERNAL);
18834520Snw141292 		res->id.idmap_id_u.gid = next_pid;
18844520Snw141292 	}
18854520Snw141292 
18864864Sbaban 	if (state->sid_history != NULL)
18874864Sbaban 		add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix,
18884864Sbaban 		    req->id1.idmap_id_u.sid.rid);
18894864Sbaban 
18904520Snw141292 	return (IDMAP_SUCCESS);
18914520Snw141292 }
18924520Snw141292 
18934520Snw141292 idmap_retcode
18944520Snw141292 sid2pid_second_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
18954520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
18964520Snw141292 	idmap_retcode	retcode;
18974520Snw141292 
18984520Snw141292 	/*
18994520Snw141292 	 * The req->direction field is used to maintain state of the
19004520Snw141292 	 * sid2pid request.
19014520Snw141292 	 */
19024520Snw141292 
19034520Snw141292 	/* Check if second pass is needed */
19044520Snw141292 	if (req->direction == _IDMAP_F_DONE)
19054520Snw141292 		return (res->retcode);
19064520Snw141292 
19074520Snw141292 	/* Get status from previous pass */
19084520Snw141292 	retcode = (res->retcode == IDMAP_NEXT)?IDMAP_SUCCESS:res->retcode;
19094520Snw141292 
19104520Snw141292 	if (retcode != IDMAP_SUCCESS) {
19114520Snw141292 		/* Reset return type */
19124520Snw141292 		res->id.idtype = req->id2.idtype;
19134520Snw141292 		res->id.idmap_id_u.uid = UID_NOBODY;
19144520Snw141292 
19154520Snw141292 		/* Check if this is a localsid */
19164520Snw141292 		if (retcode == IDMAP_ERR_NOTFOUND &&
19174864Sbaban 		    _idmapdstate.cfg->pgcfg.machine_sid) {
19184520Snw141292 			retcode = lookup_localsid2pid(req, res);
19194520Snw141292 			if (retcode == IDMAP_SUCCESS) {
19204520Snw141292 				state->sid2pid_done = FALSE;
19214520Snw141292 				req->direction = _IDMAP_F_S2N_CACHE;
19224520Snw141292 			}
19234520Snw141292 		}
19244520Snw141292 		goto out;
19254520Snw141292 	}
19264520Snw141292 
19274520Snw141292 	/*
19284520Snw141292 	 * Verify that the sid type matches the request if the
19294520Snw141292 	 * SID was validated by an AD lookup.
19304520Snw141292 	 */
19314520Snw141292 	if (req->direction & _IDMAP_F_S2N_AD) {
19324520Snw141292 		retcode = verify_type(req->id2.idtype,
19334520Snw141292 			(int)res->id.idtype, res);
19344520Snw141292 		if (retcode != IDMAP_SUCCESS) {
19354520Snw141292 			res->id.idtype = req->id2.idtype;
19364520Snw141292 			res->id.idmap_id_u.uid = UID_NOBODY;
19374520Snw141292 			goto out;
19384520Snw141292 		}
19394520Snw141292 	}
19404520Snw141292 
19414520Snw141292 	/* Name-based mapping */
19424520Snw141292 	retcode = name_based_mapping_sid2pid(db, req, res);
19434520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND)
19444520Snw141292 		/* If not found, do ephemeral mapping */
19454520Snw141292 		goto ephemeral;
19464520Snw141292 	else if (retcode != IDMAP_SUCCESS)
19474520Snw141292 		goto out;
19484520Snw141292 
19494520Snw141292 	state->sid2pid_done = FALSE;
19504520Snw141292 	goto out;
19514520Snw141292 
19524520Snw141292 
19534520Snw141292 ephemeral:
19544864Sbaban 	retcode = dynamic_ephemeral_mapping(state, cache, req, res);
19554520Snw141292 	if (retcode == IDMAP_SUCCESS)
19564520Snw141292 		state->sid2pid_done = FALSE;
19574520Snw141292 
19584520Snw141292 out:
19594520Snw141292 	res->retcode = idmap_stat4prot(retcode);
19604520Snw141292 	return (retcode);
19614520Snw141292 }
19624520Snw141292 
19634520Snw141292 idmap_retcode
19644520Snw141292 update_cache_pid2sid(lookup_state_t *state, sqlite *cache,
19654520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
19664520Snw141292 	char		*sql = NULL;
19674520Snw141292 	idmap_retcode	retcode;
19684520Snw141292 
19694520Snw141292 	/* Check if we need to cache anything */
19704520Snw141292 	if (req->direction == _IDMAP_F_DONE)
19714520Snw141292 		return (IDMAP_SUCCESS);
19724520Snw141292 
19734520Snw141292 	/* We don't cache negative entries */
19744520Snw141292 	if (res->retcode != IDMAP_SUCCESS)
19754520Snw141292 		return (IDMAP_SUCCESS);
19764520Snw141292 
19774520Snw141292 	/*
19784520Snw141292 	 * Using NULL for u2w instead of 0 so that our trigger allows
19794520Snw141292 	 * the same pid to be the destination in multiple entries
19804520Snw141292 	 */
19814520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
19824520Snw141292 		"(sidprefix, rid, windomain, winname, pid, unixname, "
19834520Snw141292 		"is_user, expiration, w2u, u2w) "
19844520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
19854520Snw141292 		"strftime('%%s','now') + 600, %q, 1); ",
19864520Snw141292 		res->id.idmap_id_u.sid.prefix,
19874520Snw141292 		res->id.idmap_id_u.sid.rid,
1988*5064Sdm199847 		req->id2domain,
1989*5064Sdm199847 		req->id2name,
19904520Snw141292 		req->id1.idmap_id_u.uid,
1991*5064Sdm199847 		req->id1name,
19924520Snw141292 		(req->id1.idtype == IDMAP_UID)?1:0,
19934520Snw141292 		(res->direction == 0)?"1":NULL);
19944520Snw141292 
19954520Snw141292 	if (sql == NULL) {
19964520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
19974520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
19984520Snw141292 		goto out;
19994520Snw141292 	}
20004520Snw141292 
20014520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
20024520Snw141292 	if (retcode != IDMAP_SUCCESS)
20034520Snw141292 		goto out;
20044520Snw141292 
20054520Snw141292 	state->pid2sid_done = FALSE;
20064520Snw141292 	sqlite_freemem(sql);
20074520Snw141292 	sql = NULL;
20084520Snw141292 
20094520Snw141292 	/* If sid2name was found in the cache, no need to update namecache */
20104520Snw141292 	if (req->direction & _IDMAP_F_S2N_CACHE)
20114520Snw141292 		goto out;
20124520Snw141292 
2013*5064Sdm199847 	if (req->id2name == NULL)
20144520Snw141292 		goto out;
20154520Snw141292 
20164520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
20174520Snw141292 		"(sidprefix, rid, name, domain, type, expiration) "
20184520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
20194520Snw141292 		res->id.idmap_id_u.sid.prefix,
20204520Snw141292 		res->id.idmap_id_u.sid.rid,
2021*5064Sdm199847 		req->id2name,
2022*5064Sdm199847 		req->id2domain,
20234520Snw141292 		(req->id1.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
20244520Snw141292 
20254520Snw141292 	if (sql == NULL) {
20264520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
20274520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
20284520Snw141292 		goto out;
20294520Snw141292 	}
20304520Snw141292 
20314520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
20324520Snw141292 
20334520Snw141292 out:
20344864Sbaban 	if (sql != NULL)
20354520Snw141292 		sqlite_freemem(sql);
20364520Snw141292 	return (retcode);
20374520Snw141292 }
20384520Snw141292 
20394520Snw141292 idmap_retcode
20404520Snw141292 update_cache_sid2pid(lookup_state_t *state, sqlite *cache,
20414520Snw141292 		idmap_mapping *req, idmap_id_res *res) {
20424520Snw141292 	char		*sql = NULL;
20434520Snw141292 	idmap_retcode	retcode;
20444520Snw141292 	int		is_eph_user;
20454520Snw141292 
20464520Snw141292 	/* Check if we need to cache anything */
20474520Snw141292 	if (req->direction == _IDMAP_F_DONE)
20484520Snw141292 		return (IDMAP_SUCCESS);
20494520Snw141292 
20504520Snw141292 	/* We don't cache negative entries */
20514520Snw141292 	if (res->retcode != IDMAP_SUCCESS)
20524520Snw141292 		return (IDMAP_SUCCESS);
20534520Snw141292 
20544520Snw141292 	if (req->direction & _IDMAP_F_EXP_EPH_UID)
20554520Snw141292 		is_eph_user = 1;
20564520Snw141292 	else if (req->direction & _IDMAP_F_EXP_EPH_GID)
20574520Snw141292 		is_eph_user = 0;
20584520Snw141292 	else
20594520Snw141292 		is_eph_user = -1;
20604520Snw141292 
20614520Snw141292 	if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
20624520Snw141292 		sql = sqlite_mprintf("UPDATE idmap_cache "
20634520Snw141292 			"SET w2u = 0 WHERE "
20644520Snw141292 			"sidprefix = %Q AND rid = %u AND w2u = 1 AND "
20654520Snw141292 			"pid >= 2147483648 AND is_user = %d;",
20664520Snw141292 			req->id1.idmap_id_u.sid.prefix,
20674520Snw141292 			req->id1.idmap_id_u.sid.rid,
20684520Snw141292 			is_eph_user);
20694520Snw141292 		if (sql == NULL) {
20704520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
20714520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
20724520Snw141292 			goto out;
20734520Snw141292 		}
20744520Snw141292 
20754520Snw141292 		retcode = sql_exec_no_cb(cache, sql);
20764520Snw141292 		if (retcode != IDMAP_SUCCESS)
20774520Snw141292 			goto out;
20784520Snw141292 
20794520Snw141292 		sqlite_freemem(sql);
20804520Snw141292 		sql = NULL;
20814520Snw141292 	}
20824520Snw141292 
20834520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
20844520Snw141292 		"(sidprefix, rid, windomain, winname, pid, unixname, "
20854520Snw141292 		"is_user, expiration, w2u, u2w) "
20864520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, "
20874520Snw141292 		"strftime('%%s','now') + 600, 1, %q); ",
20884520Snw141292 		req->id1.idmap_id_u.sid.prefix,
20894520Snw141292 		req->id1.idmap_id_u.sid.rid,
2090*5064Sdm199847 		req->id1domain,
2091*5064Sdm199847 		req->id1name,
20924520Snw141292 		res->id.idmap_id_u.uid,
2093*5064Sdm199847 		req->id2name,
20944520Snw141292 		(res->id.idtype == IDMAP_UID)?1:0,
20954520Snw141292 		(res->direction == 0)?"1":NULL);
20964520Snw141292 
20974520Snw141292 	if (sql == NULL) {
20984520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
20994520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
21004520Snw141292 		goto out;
21014520Snw141292 	}
21024520Snw141292 
21034520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
21044520Snw141292 	if (retcode != IDMAP_SUCCESS)
21054520Snw141292 		goto out;
21064520Snw141292 
21074520Snw141292 	state->sid2pid_done = FALSE;
21084520Snw141292 	sqlite_freemem(sql);
21094520Snw141292 	sql = NULL;
21104520Snw141292 
21114520Snw141292 	/* If name2sid was found in the cache, no need to update namecache */
21124520Snw141292 	if (req->direction & _IDMAP_F_S2N_CACHE)
21134520Snw141292 		goto out;
21144520Snw141292 
2115*5064Sdm199847 	if (req->id1name == NULL)
21164520Snw141292 		goto out;
21174520Snw141292 
21184520Snw141292 	sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
21194520Snw141292 		"(sidprefix, rid, name, domain, type, expiration) "
21204520Snw141292 		"VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
21214520Snw141292 		req->id1.idmap_id_u.sid.prefix,
21224520Snw141292 		req->id1.idmap_id_u.sid.rid,
2123*5064Sdm199847 		req->id1name,
2124*5064Sdm199847 		req->id1domain,
21254520Snw141292 		(res->id.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP);
21264520Snw141292 
21274520Snw141292 	if (sql == NULL) {
21284520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
21294520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
21304520Snw141292 		goto out;
21314520Snw141292 	}
21324520Snw141292 
21334520Snw141292 	retcode = sql_exec_no_cb(cache, sql);
21344520Snw141292 
21354520Snw141292 out:
21364864Sbaban 	if (sql != NULL)
21374520Snw141292 		sqlite_freemem(sql);
21384520Snw141292 	return (retcode);
21394520Snw141292 }
21404520Snw141292 
21414520Snw141292 static idmap_retcode
21424520Snw141292 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
21434520Snw141292 		int is_user, int getname) {
21444520Snw141292 	char		*end;
21454520Snw141292 	char		*sql = NULL;
21464520Snw141292 	const char	**values;
21474520Snw141292 	sqlite_vm	*vm = NULL;
21484520Snw141292 	int		ncol;
21494520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
21504520Snw141292 	time_t		curtime;
21514520Snw141292 
21524520Snw141292 	/* Current time */
21534520Snw141292 	errno = 0;
21544520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
21554520Snw141292 		idmapdlog(LOG_ERR,
21564520Snw141292 			"Failed to get current time (%s)",
21574520Snw141292 			strerror(errno));
21584520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
21594520Snw141292 		goto out;
21604520Snw141292 	}
21614520Snw141292 
21624520Snw141292 	/* SQL to lookup the cache */
21634520Snw141292 	sql = sqlite_mprintf("SELECT sidprefix, rid, winname, windomain, w2u "
21644520Snw141292 			"FROM idmap_cache WHERE "
21654520Snw141292 			"pid = %u AND u2w = 1 AND is_user = %d AND "
21664520Snw141292 			"(pid >= 2147483648 OR "
21674520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
21684520Snw141292 			"expiration > %d));",
21694520Snw141292 			req->id1.idmap_id_u.uid, is_user, curtime);
21704520Snw141292 	if (sql == NULL) {
21714520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
21724520Snw141292 		retcode = IDMAP_ERR_MEMORY;
21734520Snw141292 		goto out;
21744520Snw141292 	}
21754520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values);
21764520Snw141292 	sqlite_freemem(sql);
21774520Snw141292 
21784520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND)
21794520Snw141292 		goto out;
21804520Snw141292 	else if (retcode == IDMAP_SUCCESS) {
21814520Snw141292 		/* sanity checks */
21824520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
21834520Snw141292 			retcode = IDMAP_ERR_CACHE;
21844520Snw141292 			goto out;
21854520Snw141292 		}
21864520Snw141292 
21874520Snw141292 		switch (req->id2.idtype) {
21884520Snw141292 		case IDMAP_SID:
21894520Snw141292 			res->id.idmap_id_u.sid.rid =
21904520Snw141292 				strtoul(values[1], &end, 10);
21914520Snw141292 			res->id.idmap_id_u.sid.prefix = strdup(values[0]);
21924520Snw141292 			if (res->id.idmap_id_u.sid.prefix == NULL) {
21934520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
21944520Snw141292 				retcode = IDMAP_ERR_MEMORY;
21954520Snw141292 				goto out;
21964520Snw141292 			}
21974520Snw141292 
21984864Sbaban 			if (values[4] != NULL)
21994520Snw141292 				res->direction =
22004644Sbaban 				    (strtol(values[4], &end, 10) == 0)?
22014644Sbaban 				    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
22024520Snw141292 			else
22034644Sbaban 				res->direction = IDMAP_DIRECTION_U2W;
22044520Snw141292 
22054520Snw141292 			if (getname == 0 || values[2] == NULL)
22064520Snw141292 				break;
2207*5064Sdm199847 			req->id2name = strdup(values[2]);
2208*5064Sdm199847 			if (req->id2name == NULL) {
22094520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22104520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22114520Snw141292 				goto out;
22124520Snw141292 			}
22134520Snw141292 
22144520Snw141292 			if (values[3] == NULL)
22154520Snw141292 				break;
2216*5064Sdm199847 			req->id2domain = strdup(values[3]);
2217*5064Sdm199847 			if (req->id2domain == NULL) {
22184520Snw141292 				idmapdlog(LOG_ERR, "Out of memory");
22194520Snw141292 				retcode = IDMAP_ERR_MEMORY;
22204520Snw141292 				goto out;
22214520Snw141292 			}
22224520Snw141292 			break;
22234520Snw141292 		default:
22244520Snw141292 			retcode = IDMAP_ERR_NOTSUPPORTED;
22254520Snw141292 			break;
22264520Snw141292 		}
22274520Snw141292 	}
22284520Snw141292 
22294520Snw141292 out:
22304864Sbaban 	if (vm != NULL)
22314520Snw141292 		(void) sqlite_finalize(vm, NULL);
22324520Snw141292 	return (retcode);
22334520Snw141292 }
22344520Snw141292 
22354520Snw141292 static idmap_retcode
22364520Snw141292 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain,
22374520Snw141292 		char **sidprefix, idmap_rid_t *rid, int *type) {
22384520Snw141292 	char		*end;
22394520Snw141292 	char		*sql = NULL;
22404520Snw141292 	const char	**values;
22414520Snw141292 	sqlite_vm	*vm = NULL;
22424520Snw141292 	int		ncol;
22434520Snw141292 	time_t		curtime;
22444520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
22454520Snw141292 
22464520Snw141292 	/* Get current time */
22474520Snw141292 	errno = 0;
22484520Snw141292 	if ((curtime = time(NULL)) == (time_t)-1) {
22494520Snw141292 		idmapdlog(LOG_ERR,
22504520Snw141292 			"Failed to get current time (%s)",
22514520Snw141292 			strerror(errno));
22524520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
22534520Snw141292 		goto out;
22544520Snw141292 	}
22554520Snw141292 
22564520Snw141292 	/* SQL to lookup the cache */
22574520Snw141292 	sql = sqlite_mprintf("SELECT sidprefix, rid, type FROM name_cache "
22584520Snw141292 			"WHERE name = %Q AND domain = %Q AND "
22594520Snw141292 			"(expiration = 0 OR expiration ISNULL OR "
22604520Snw141292 			"expiration > %d);",
22614520Snw141292 			name, domain, curtime);
22624520Snw141292 	if (sql == NULL) {
22634520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
22644520Snw141292 		retcode = IDMAP_ERR_MEMORY;
22654520Snw141292 		goto out;
22664520Snw141292 	}
22674520Snw141292 	retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
22684520Snw141292 	sqlite_freemem(sql);
22694520Snw141292 
22704520Snw141292 	if (retcode == IDMAP_SUCCESS) {
22714864Sbaban 		if (type != NULL) {
22724520Snw141292 			if (values[2] == NULL) {
22734520Snw141292 				retcode = IDMAP_ERR_CACHE;
22744520Snw141292 				goto out;
22754520Snw141292 			}
22764520Snw141292 			*type = strtol(values[2], &end, 10);
22774520Snw141292 		}
22784520Snw141292 
22794520Snw141292 		if (values[0] == NULL || values[1] == NULL) {
22804520Snw141292 			retcode = IDMAP_ERR_CACHE;
22814520Snw141292 			goto out;
22824520Snw141292 		}
22834520Snw141292 		if ((*sidprefix = strdup(values[0])) == NULL) {
22844520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
22854520Snw141292 			retcode = IDMAP_ERR_MEMORY;
22864520Snw141292 			goto out;
22874520Snw141292 		}
22884520Snw141292 		*rid = strtoul(values[1], &end, 10);
22894520Snw141292 	}
22904520Snw141292 
22914520Snw141292 out:
22924864Sbaban 	if (vm != NULL)
22934520Snw141292 		(void) sqlite_finalize(vm, NULL);
22944520Snw141292 	return (retcode);
22954520Snw141292 }
22964520Snw141292 
22974520Snw141292 static idmap_retcode
22984520Snw141292 lookup_win_name2sid(const char *name, const char *domain, char **sidprefix,
22994520Snw141292 		idmap_rid_t *rid, int *type) {
23004520Snw141292 	int			ret;
23014520Snw141292 	int			retries = 0;
23024520Snw141292 	idmap_query_state_t	*qs = NULL;
23034520Snw141292 	idmap_retcode		rc, retcode;
23044520Snw141292 
23054520Snw141292 	retcode = IDMAP_ERR_NOTFOUND;
23064520Snw141292 
23074520Snw141292 retry:
23084520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
23094520Snw141292 	if (ret != 0) {
23104520Snw141292 		idmapdlog(LOG_ERR,
23114520Snw141292 		"Failed to create name2sid batch for AD lookup");
23124520Snw141292 		return (IDMAP_ERR_INTERNAL);
23134520Snw141292 	}
23144520Snw141292 
23154520Snw141292 	retcode = idmap_name2sid_batch_add1(qs, name, domain, sidprefix,
23164520Snw141292 					rid, type, &rc);
23174520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
23184520Snw141292 		goto out;
23194520Snw141292 
23204520Snw141292 	if (retcode != IDMAP_SUCCESS) {
23214520Snw141292 		idmapdlog(LOG_ERR,
23224520Snw141292 		"Failed to batch name2sid for AD lookup");
23234884Sjp151216 		idmap_lookup_release_batch(&qs);
23244520Snw141292 		return (IDMAP_ERR_INTERNAL);
23254520Snw141292 	}
23264520Snw141292 
23274520Snw141292 out:
23284520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
23294884Sjp151216 		idmap_lookup_release_batch(&qs);
23304520Snw141292 	else
23314520Snw141292 		retcode = idmap_lookup_batch_end(&qs, NULL);
23324520Snw141292 
23334520Snw141292 	if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2)
23344520Snw141292 		goto retry;
23354520Snw141292 
23364520Snw141292 	if (retcode != IDMAP_SUCCESS) {
23374520Snw141292 		idmapdlog(LOG_NOTICE, "Windows user/group name to SID lookup "
23384520Snw141292 		    "failed");
23394520Snw141292 		return (retcode);
23404520Snw141292 	} else
23414520Snw141292 		return (rc);
23424520Snw141292 	/* NOTREACHED */
23434520Snw141292 }
23444520Snw141292 
23454520Snw141292 static idmap_retcode
23464520Snw141292 lookup_name2sid(sqlite *cache, const char *name, const char *domain,
23474520Snw141292 		int *is_user, char **sidprefix, idmap_rid_t *rid,
23484520Snw141292 		idmap_mapping *req) {
23494520Snw141292 	int		type;
23504520Snw141292 	idmap_retcode	retcode;
23514520Snw141292 
23524864Sbaban 	/* Lookup name@domain to sid in the well-known sids table */
23534864Sbaban 	retcode = lookup_wksids_name2sid(name, sidprefix, rid, &type);
23544864Sbaban 	if (retcode == IDMAP_SUCCESS) {
23554864Sbaban 		req->direction |= _IDMAP_F_S2N_CACHE;
23564864Sbaban 		goto out;
23574864Sbaban 	} else if (retcode != IDMAP_ERR_NOTFOUND) {
23584864Sbaban 		return (retcode);
23594864Sbaban 	}
23604864Sbaban 
23614864Sbaban 	/* Lookup name@domain to sid in cache */
23624520Snw141292 	retcode = lookup_cache_name2sid(cache, name, domain, sidprefix,
23634520Snw141292 		rid, &type);
23644520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
23654520Snw141292 		/* Lookup Windows NT/AD to map name@domain to sid */
23664520Snw141292 		retcode = lookup_win_name2sid(name, domain, sidprefix, rid,
23674520Snw141292 			&type);
23684520Snw141292 		if (retcode != IDMAP_SUCCESS)
23694520Snw141292 			return (retcode);
23704520Snw141292 		req->direction |= _IDMAP_F_S2N_AD;
23714520Snw141292 	} else if (retcode != IDMAP_SUCCESS) {
23724520Snw141292 		return (retcode);
23734520Snw141292 	} else {
23744520Snw141292 		/* Set flag */
23754520Snw141292 		req->direction |= _IDMAP_F_S2N_CACHE;
23764520Snw141292 	}
23774520Snw141292 
23784864Sbaban out:
23794520Snw141292 	/*
23804520Snw141292 	 * Entry found (cache or Windows lookup)
23814520Snw141292 	 * is_user is both input as well as output parameter
23824520Snw141292 	 */
23834520Snw141292 	if (*is_user == 1) {
23844520Snw141292 		if (type != _IDMAP_T_USER)
23854520Snw141292 			return (IDMAP_ERR_NOTUSER);
23864520Snw141292 	} else if (*is_user == 0) {
23874520Snw141292 		if (type != _IDMAP_T_GROUP)
23884520Snw141292 			return (IDMAP_ERR_NOTGROUP);
23894520Snw141292 	} else if (*is_user == -1) {
23904520Snw141292 		/* Caller wants to know if its user or group */
23914520Snw141292 		if (type == _IDMAP_T_USER)
23924520Snw141292 			*is_user = 1;
23934520Snw141292 		else if (type == _IDMAP_T_GROUP)
23944520Snw141292 			*is_user = 0;
23954520Snw141292 		else
23964520Snw141292 			return (IDMAP_ERR_SID);
23974520Snw141292 	}
23984520Snw141292 
23994520Snw141292 	return (retcode);
24004520Snw141292 }
24014520Snw141292 
24024520Snw141292 static idmap_retcode
24034520Snw141292 name_based_mapping_pid2sid(sqlite *db, sqlite *cache, const char *unixname,
24044520Snw141292 		int is_user, idmap_mapping *req, idmap_id_res *res) {
24054520Snw141292 	const char	*winname, *windomain;
24064520Snw141292 	char		*mapping_domain = NULL;
24074520Snw141292 	char		*sql = NULL, *errmsg = NULL;
24084520Snw141292 	idmap_retcode	retcode;
24094520Snw141292 	char		*end;
24104520Snw141292 	const char	**values;
24114520Snw141292 	sqlite_vm	*vm = NULL;
24124884Sjp151216 	int		ncol, r;
24134520Snw141292 	const char	*me = "name_based_mapping_pid2sid";
24144520Snw141292 
24154520Snw141292 	RDLOCK_CONFIG();
24164864Sbaban 	if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
24174520Snw141292 		mapping_domain =
24184520Snw141292 			strdup(_idmapdstate.cfg->pgcfg.mapping_domain);
24194520Snw141292 		if (mapping_domain == NULL) {
24204520Snw141292 			UNLOCK_CONFIG();
24214520Snw141292 			idmapdlog(LOG_ERR, "Out of memory");
24224520Snw141292 			retcode = IDMAP_ERR_MEMORY;
24234520Snw141292 			goto out;
24244520Snw141292 		}
24254520Snw141292 	}
24264520Snw141292 	UNLOCK_CONFIG();
24274520Snw141292 
24284520Snw141292 	sql = sqlite_mprintf(
24294520Snw141292 		"SELECT winname, windomain, w2u_order FROM namerules WHERE "
24304520Snw141292 		"u2w_order > 0 AND is_user = %d AND "
24314520Snw141292 		"(unixname = %Q OR unixname = '*') "
24324520Snw141292 		"ORDER BY u2w_order ASC;",
24334520Snw141292 		is_user, unixname);
24344520Snw141292 	if (sql == NULL) {
24354520Snw141292 		idmapdlog(LOG_ERR, "Out of memory");
24364520Snw141292 		retcode = IDMAP_ERR_MEMORY;
24374520Snw141292 		goto out;
24384520Snw141292 	}
24394520Snw141292 
24404520Snw141292 	if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
24414520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
24424520Snw141292 		idmapdlog(LOG_ERR,
24434520Snw141292 			"%s: database error (%s)",
24444520Snw141292 			me, CHECK_NULL(errmsg));
24454520Snw141292 		sqlite_freemem(errmsg);
24464520Snw141292 		goto out;
24474520Snw141292 	}
24484520Snw141292 
24494884Sjp151216 	for (;;) {
24504520Snw141292 		r = sqlite_step(vm, &ncol, &values, NULL);
24514884Sjp151216 		assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
24524884Sjp151216 		if (r == SQLITE_ROW) {
24534520Snw141292 			if (ncol < 3) {
24544520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
24554520Snw141292 				goto out;
24564520Snw141292 			}
24574520Snw141292 			if (values[0] == NULL) {
24584520Snw141292 				/* values [1] and [2] can be null */
24594520Snw141292 				retcode = IDMAP_ERR_INTERNAL;
24604520Snw141292 				goto out;
24614520Snw141292 			}
24624520Snw141292 			if (EMPTY_NAME(values[0])) {
24634520Snw141292 				retcode = IDMAP_ERR_NOMAPPING;
24644520Snw141292 				goto out;
24654520Snw141292 			}
24664520Snw141292 			winname = (values[0][0] == '*')?unixname:values[0];
24674864Sbaban 			if (values[1] != NULL)
24684520Snw141292 				windomain = values[1];
24694864Sbaban 			else if (mapping_domain != NULL)
24704520Snw141292 				windomain = mapping_domain;
24714520Snw141292 			else {
24724520Snw141292 				idmapdlog(LOG_ERR,
24734520Snw141292 					"%s: no domain", me);
24744520Snw141292 				retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
24754520Snw141292 				goto out;
24764520Snw141292 			}
24774520Snw141292 			/* Lookup winname@domain to sid */
24784520Snw141292 			retcode = lookup_name2sid(cache, winname, windomain,
24794520Snw141292 				&is_user, &res->id.idmap_id_u.sid.prefix,
24804520Snw141292 				&res->id.idmap_id_u.sid.rid, req);
24814520Snw141292 			if (retcode == IDMAP_ERR_NOTFOUND) {
24824520Snw141292 				if (winname == unixname)
24834520Snw141292 					continue;
24844520Snw141292 				else
24854520Snw141292 					retcode = IDMAP_ERR_NOMAPPING;
24864520Snw141292 			}
24874520Snw141292 			goto out;
24884520Snw141292 		} else if (r == SQLITE_DONE) {
24894520Snw141292 			retcode = IDMAP_ERR_NOTFOUND;
24904520Snw141292 			goto out;
24914520Snw141292 		} else {
24924520Snw141292 			(void) sqlite_finalize(vm, &errmsg);
24934520Snw141292 			vm = NULL;
24944520Snw141292 			idmapdlog(LOG_ERR,
24954520Snw141292 				"%s: database error (%s)",
24964520Snw141292 				me, CHECK_NULL(errmsg));
24974520Snw141292 			sqlite_freemem(errmsg);
24984520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
24994520Snw141292 			goto out;
25004520Snw141292 		}
25014520Snw141292 	}
25024520Snw141292 
25034520Snw141292 out:
25044864Sbaban 	if (sql != NULL)
25054520Snw141292 		sqlite_freemem(sql);
25064520Snw141292 	if (retcode == IDMAP_SUCCESS) {
25074864Sbaban 		if (values[2] != NULL)
25084520Snw141292 			res->direction =
25094644Sbaban 			    (strtol(values[2], &end, 10) == 0)?
25104644Sbaban 			    IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
25114520Snw141292 		else
25124644Sbaban 			res->direction = IDMAP_DIRECTION_U2W;
2513*5064Sdm199847 
2514*5064Sdm199847 		req->id2name = strdup(winname);
2515*5064Sdm199847 		if (req->id2name != NULL) {
25164520Snw141292 			if (windomain == mapping_domain) {
2517*5064Sdm199847 				req->id2domain = (char *)windomain;
25184520Snw141292 				mapping_domain = NULL;
2519*5064Sdm199847 			} else {
2520*5064Sdm199847 				req->id2domain = strdup(windomain);
2521*5064Sdm199847 			}
25224520Snw141292 		}
25234520Snw141292 	}
25244864Sbaban 	if (vm != NULL)
25254520Snw141292 		(void) sqlite_finalize(vm, NULL);
25264864Sbaban 	if (mapping_domain != NULL)
25274520Snw141292 		free(mapping_domain);
25284520Snw141292 	return (retcode);
25294520Snw141292 }
25304520Snw141292 
25314520Snw141292 idmap_retcode
25324520Snw141292 pid2sid_first_pass(lookup_state_t *state, sqlite *cache, sqlite *db,
25334520Snw141292 		idmap_mapping *req, idmap_id_res *res, int is_user,
25344520Snw141292 		int getname) {
25354520Snw141292 	char		*unixname = NULL;
25364520Snw141292 	struct passwd	pwd;
25374520Snw141292 	struct group	grp;
25384520Snw141292 	char		buf[1024];
25394520Snw141292 	int		errnum;
25404520Snw141292 	idmap_retcode	retcode = IDMAP_SUCCESS;
25414520Snw141292 	const char	*me = "pid2sid";
25424520Snw141292 
25434520Snw141292 	req->direction = _IDMAP_F_DONE;
25444520Snw141292 	res->id.idtype = req->id2.idtype;
25454520Snw141292 
25464520Snw141292 	/* Lookup well-known SIDs */
25474520Snw141292 	retcode = lookup_wksids_pid2sid(req, res, is_user);
25484520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
25494520Snw141292 		goto out;
25504520Snw141292 
25514520Snw141292 	/* Lookup pid to sid in cache */
25524520Snw141292 	retcode = lookup_cache_pid2sid(cache, req, res, is_user, getname);
25534520Snw141292 	if (retcode != IDMAP_ERR_NOTFOUND)
25544520Snw141292 		goto out;
25554520Snw141292 
25564520Snw141292 	/* Ephemeral ids cannot be allocated during pid2sid */
25574520Snw141292 	if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) {
25584864Sbaban 		retcode = IDMAP_ERR_NOMAPPING;
25594520Snw141292 		goto out;
25604520Snw141292 	}
25614520Snw141292 
25624520Snw141292 	if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
25634864Sbaban 		retcode = IDMAP_ERR_NOMAPPING;
25644520Snw141292 		goto out;
25654520Snw141292 	}
25664520Snw141292 
25674520Snw141292 	/* uid/gid to name */
2568*5064Sdm199847 	if (req->id1name != NULL) {
2569*5064Sdm199847 		unixname = req->id1name;
2570*5064Sdm199847 	} else if (is_user) {
25714520Snw141292 		errno = 0;
25724520Snw141292 		if (getpwuid_r(req->id1.idmap_id_u.uid, &pwd, buf,
25734520Snw141292 				sizeof (buf)) == NULL) {
25744520Snw141292 			errnum = errno;
25754520Snw141292 			idmapdlog(LOG_WARNING,
25764520Snw141292 			"%s: getpwuid_r(%u) failed (%s).",
25774520Snw141292 				me, req->id1.idmap_id_u.uid,
25784520Snw141292 				errnum?strerror(errnum):"not found");
25794520Snw141292 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
25804520Snw141292 					IDMAP_ERR_INTERNAL;
25814520Snw141292 			goto fallback_localsid;
25824520Snw141292 		}
25834520Snw141292 		unixname = pwd.pw_name;
25844520Snw141292 	} else {
25854520Snw141292 		errno = 0;
25864520Snw141292 		if (getgrgid_r(req->id1.idmap_id_u.gid, &grp, buf,
25874520Snw141292 				sizeof (buf)) == NULL) {
25884520Snw141292 			errnum = errno;
25894520Snw141292 			idmapdlog(LOG_WARNING,
25904520Snw141292 			"%s: getgrgid_r(%u) failed (%s).",
25914520Snw141292 				me, req->id1.idmap_id_u.gid,
25924520Snw141292 				errnum?strerror(errnum):"not found");
25934520Snw141292 			retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
25944520Snw141292 					IDMAP_ERR_INTERNAL;
25954520Snw141292 			goto fallback_localsid;
25964520Snw141292 		}
25974520Snw141292 		unixname = grp.gr_name;
25984520Snw141292 	}
25994520Snw141292 
26004520Snw141292 	/* Name-based mapping */
26014520Snw141292 	retcode = name_based_mapping_pid2sid(db, cache, unixname, is_user,
26024520Snw141292 		req, res);
26034520Snw141292 	if (retcode == IDMAP_ERR_NOTFOUND) {
26044520Snw141292 		retcode = generate_localsid(req, res, is_user);
26054520Snw141292 		goto out;
26064520Snw141292 	} else if (retcode == IDMAP_SUCCESS)
26074520Snw141292 		goto out;
26084520Snw141292 
26094520Snw141292 fallback_localsid:
26104520Snw141292 	/*
26114520Snw141292 	 * Here we generate localsid as fallback id on errors. Our
26124520Snw141292 	 * return status is the error that's been previously assigned.
26134520Snw141292 	 */
26144520Snw141292 	(void) generate_localsid(req, res, is_user);
26154520Snw141292 
26164520Snw141292 out:
2617*5064Sdm199847 	if (retcode == IDMAP_SUCCESS && req->id1name == NULL &&
2618*5064Sdm199847 	    unixname != NULL) {
2619*5064Sdm199847 		req->id1name = strdup(unixname);
26204520Snw141292 	}
26214520Snw141292 	if (req->direction != _IDMAP_F_DONE)
26224520Snw141292 		state->pid2sid_done = FALSE;
26234520Snw141292 	res->retcode = idmap_stat4prot(retcode);
26244520Snw141292 	return (retcode);
26254520Snw141292 }
26264520Snw141292 
26274520Snw141292 static idmap_retcode
26284520Snw141292 lookup_win_sid2name(const char *sidprefix, idmap_rid_t rid, char **name,
26294520Snw141292 		char **domain, int *type) {
26304520Snw141292 	int			ret;
26314520Snw141292 	idmap_query_state_t	*qs = NULL;
26324520Snw141292 	idmap_retcode		rc, retcode;
26334520Snw141292 
26344520Snw141292 	retcode = IDMAP_ERR_NOTFOUND;
26354520Snw141292 
26364520Snw141292 	ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs);
26374520Snw141292 	if (ret != 0) {
26384520Snw141292 		idmapdlog(LOG_ERR,
26394520Snw141292 		"Failed to create sid2name batch for AD lookup");
26404520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
26414520Snw141292 		goto out;
26424520Snw141292 	}
26434520Snw141292 
26444520Snw141292 	ret = idmap_sid2name_batch_add1(
26454520Snw141292 			qs, sidprefix, &rid, name, domain, type, &rc);
26464520Snw141292 	if (ret != 0) {
26474520Snw141292 		idmapdlog(LOG_ERR,
26484520Snw141292 		"Failed to batch sid2name for AD lookup");
26494520Snw141292 		retcode = IDMAP_ERR_INTERNAL;
26504520Snw141292 		goto out;
26514520Snw141292 	}
26524520Snw141292 
26534520Snw141292 out:
26544864Sbaban 	if (qs != NULL) {
26554520Snw141292 		ret = idmap_lookup_batch_end(&qs, NULL);
26564520Snw141292 		if (ret != 0) {
26574520Snw141292 			idmapdlog(LOG_ERR,
26584520Snw141292 			"Failed to execute sid2name AD lookup");
26594520Snw141292 			retcode = IDMAP_ERR_INTERNAL;
26604520Snw141292 		} else
26614520Snw141292 			retcode = rc;
26624520Snw141292 	}
26634520Snw141292 
26644520Snw141292 	return (retcode);
26654520Snw141292 }
26664520Snw141292 
26674644Sbaban static int
26684644Sbaban copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request)
26694520Snw141292 {
26704644Sbaban 	(void) memset(mapping, 0, sizeof (*mapping));
26714644Sbaban 
26724520Snw141292 	mapping->flag = request->flag;
26734520Snw141292 	mapping->direction = request->direction;
26744644Sbaban 	mapping->id2.idtype = request->id2.idtype;
26754520Snw141292 
26764520Snw141292 	mapping->id1.idtype = request->id1.idtype;
26774520Snw141292 	if (request->id1.idtype == IDMAP_SID) {
26784520Snw141292 		mapping->id1.idmap_id_u.sid.rid =
26794520Snw141292 		    request->id1.idmap_id_u.sid.rid;
26804644Sbaban 		if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) {
26814520Snw141292 			mapping->id1.idmap_id_u.sid.prefix =
26824520Snw141292 			    strdup(request->id1.idmap_id_u.sid.prefix);
26834644Sbaban 			if (mapping->id1.idmap_id_u.sid.prefix == NULL)
2684*5064Sdm199847 				goto errout;
26854644Sbaban 		}
26864520Snw141292 	} else {
26874520Snw141292 		mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid;
26884520Snw141292 	}
26894520Snw141292 
2690*5064Sdm199847 	mapping->id1domain = strdup(request->id1domain);
2691*5064Sdm199847 	if (mapping->id1domain == NULL)
2692*5064Sdm199847 		goto errout;
26934520Snw141292 
2694*5064Sdm199847 	mapping->id1name = strdup(request->id1name);
2695*5064Sdm199847 	if (mapping->id1name == NULL)
2696*5064Sdm199847 		goto errout;
26974520Snw141292 
26984644Sbaban 	/* We don't need the rest of the request i.e request->id2 */
26994644Sbaban 	return (0);
27004644Sbaban 
27014644Sbaban errout:
2702*5064Sdm199847 	if (mapping->id1.idmap_id_u.sid.prefix != NULL)
27034644Sbaban 		free(mapping->id1.idmap_id_u.sid.prefix);
2704*5064Sdm199847 	if (mapping->id1domain != NULL)
2705*5064Sdm199847 		free(mapping->id1domain);
2706*5064Sdm199847 	if (mapping->id1name != NULL)
2707*5064Sdm199847 		free(mapping->id1name);
27084644Sbaban 
27094644Sbaban 	(void) memset(mapping, 0, sizeof (*mapping));
27104644Sbaban 	return (-1);
27114520Snw141292 }
27124520Snw141292 
27134520Snw141292 
27144520Snw141292 idmap_retcode
27154520Snw141292 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
27164520Snw141292 		idmap_mapping *mapping) {
27174520Snw141292 	idmap_id_res	idres;
27184520Snw141292 	lookup_state_t	state;
27195043Sbaban 	char		*cp;
27204520Snw141292 	int		is_user;
27214520Snw141292 	idmap_retcode	retcode;
27224520Snw141292 	const char	*winname, *windomain;
27234520Snw141292 
27244520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
27254520Snw141292 	(void) memset(&state, 0, sizeof (state));
27264520Snw141292 
27274520Snw141292 	if (request->id2.idtype == IDMAP_UID)
27284520Snw141292 		is_user = 1;
27294520Snw141292 	else if (request->id2.idtype == IDMAP_GID)
27304520Snw141292 		is_user = 0;
27314520Snw141292 	else if (request->id2.idtype == IDMAP_POSIXID)
27324520Snw141292 		is_user = -1;
27334520Snw141292 	else {
27344520Snw141292 		retcode = IDMAP_ERR_IDTYPE;
27354520Snw141292 		goto out;
27364520Snw141292 	}
27374520Snw141292 
27384520Snw141292 	/* Copy data from request to result */
27394644Sbaban 	if (copy_mapping_request(mapping, request) < 0) {
27404644Sbaban 		retcode = IDMAP_ERR_MEMORY;
27414644Sbaban 		goto out;
27424644Sbaban 	}
27434520Snw141292 
2744*5064Sdm199847 	winname = mapping->id1name;
2745*5064Sdm199847 	windomain = mapping->id1domain;
27464520Snw141292 
27474864Sbaban 	if (winname == NULL && windomain != NULL) {
27484520Snw141292 		retcode = IDMAP_ERR_ARG;
27494520Snw141292 		goto out;
27504520Snw141292 	}
27514520Snw141292 
27524864Sbaban 	if (winname != NULL && windomain == NULL) {
2753*5064Sdm199847 		retcode = IDMAP_SUCCESS;
27545043Sbaban 		if ((cp = strchr(winname, '@')) != NULL) {
27555043Sbaban 			/*
27565043Sbaban 			 * if winname is qualified with a domain, use it.
27575043Sbaban 			 */
27585043Sbaban 			*cp = '\0';
2759*5064Sdm199847 			mapping->id1domain = strdup(cp + 1);
2760*5064Sdm199847 			if (mapping->id1domain == NULL)
2761*5064Sdm199847 				retcode = IDMAP_ERR_MEMORY;
2762*5064Sdm199847 		} else {
2763*5064Sdm199847 			RDLOCK_CONFIG();
2764*5064Sdm199847 			if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) {
27655043Sbaban 			/*
27665043Sbaban 			 * otherwise use the mapping domain
27675043Sbaban 			 */
2768*5064Sdm199847 				mapping->id1domain =
2769*5064Sdm199847 				    strdup(_idmapdstate.cfg->
2770*5064Sdm199847 					pgcfg.mapping_domain);
2771*5064Sdm199847 				if (mapping->id1domain == NULL)
2772*5064Sdm199847 					retcode = IDMAP_ERR_MEMORY;
2773*5064Sdm199847 			}
27745043Sbaban 			UNLOCK_CONFIG();
2775*5064Sdm199847 		}
27765043Sbaban 
27775043Sbaban 		if (retcode != IDMAP_SUCCESS) {
27785043Sbaban 			idmapdlog(LOG_ERR, "Out of memory");
27795043Sbaban 			goto out;
27804520Snw141292 		}
2781*5064Sdm199847 		windomain = mapping->id1domain;
27824520Snw141292 	}
27834520Snw141292 
27844864Sbaban 	if (winname != NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) {
27854520Snw141292 		retcode = lookup_name2sid(cache, winname, windomain,
27864520Snw141292 			&is_user, &mapping->id1.idmap_id_u.sid.prefix,
27874520Snw141292 			&mapping->id1.idmap_id_u.sid.rid, mapping);
27884520Snw141292 		if (retcode != IDMAP_SUCCESS)
27894520Snw141292 			goto out;
27904520Snw141292 		if (mapping->id2.idtype == IDMAP_POSIXID)
27914520Snw141292 			mapping->id2.idtype = is_user?IDMAP_UID:IDMAP_GID;
27924520Snw141292 	}
27934520Snw141292 
27944520Snw141292 	state.sid2pid_done = TRUE;
27954520Snw141292 	retcode = sid2pid_first_pass(&state, cache, mapping, &idres);
27964520Snw141292 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
27974520Snw141292 		goto out;
27984520Snw141292 
27994520Snw141292 	if (state.ad_nqueries) {
28004520Snw141292 		/* sid2name AD lookup */
28014520Snw141292 		retcode = lookup_win_sid2name(
28024520Snw141292 			mapping->id1.idmap_id_u.sid.prefix,
28034520Snw141292 			mapping->id1.idmap_id_u.sid.rid,
2804*5064Sdm199847 			&mapping->id1name,
2805*5064Sdm199847 			&mapping->id1domain,
28064520Snw141292 			(int *)&idres.id.idtype);
28074520Snw141292 
28084520Snw141292 		idres.retcode = retcode;
28094520Snw141292 	}
28104520Snw141292 
28114520Snw141292 	state.sid2pid_done = TRUE;
28124520Snw141292 	retcode = sid2pid_second_pass(&state, cache, db, mapping, &idres);
28134520Snw141292 	if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE)
28144520Snw141292 		goto out;
28154520Snw141292 
28164520Snw141292 	/* Update cache */
28174520Snw141292 	(void) update_cache_sid2pid(&state, cache, mapping, &idres);
28184520Snw141292 
28194520Snw141292 out:
28204520Snw141292 	if (retcode == IDMAP_SUCCESS) {
28214520Snw141292 		mapping->direction = idres.direction;
28224520Snw141292 		mapping->id2 = idres.id;
28234520Snw141292 		(void) memset(&idres, 0, sizeof (idres));
28244864Sbaban 	} else {
28254864Sbaban 		mapping->id2.idmap_id_u.uid = UID_NOBODY;
28264520Snw141292 	}
28274520Snw141292 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
28284520Snw141292 	return (retcode);
28294520Snw141292 }
28304520Snw141292 
28314520Snw141292 idmap_retcode
28324520Snw141292 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request,
28334520Snw141292 		idmap_mapping *mapping, int is_user) {
28344520Snw141292 	idmap_id_res	idres;
28354520Snw141292 	lookup_state_t	state;
28364520Snw141292 	struct passwd	pwd;
28374520Snw141292 	struct group	grp;
28384520Snw141292 	char		buf[1024];
28394520Snw141292 	int		errnum;
28404520Snw141292 	idmap_retcode	retcode;
28414520Snw141292 	const char	*unixname;
28424520Snw141292 	const char	*me = "get_u2w_mapping";
28434520Snw141292 
28444520Snw141292 	/*
28454520Snw141292 	 * In order to re-use the pid2sid code, we convert
28464520Snw141292 	 * our input data into structs that are expected by
28474520Snw141292 	 * pid2sid_first_pass.
28484520Snw141292 	 */
28494520Snw141292 
28504520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
28514520Snw141292 	(void) memset(&state, 0, sizeof (state));
28524520Snw141292 
28534520Snw141292 	/* Copy data from request to result */
28544644Sbaban 	if (copy_mapping_request(mapping, request) < 0) {
28554644Sbaban 		retcode = IDMAP_ERR_MEMORY;
28564644Sbaban 		goto out;
28574644Sbaban 	}
28584520Snw141292 
2859*5064Sdm199847 	unixname = mapping->id1name;
28604520Snw141292 
28614520Snw141292 	if (unixname == NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
28624520Snw141292 		retcode = IDMAP_ERR_ARG;
28634520Snw141292 		goto out;
28644520Snw141292 	}
28654520Snw141292 
28664864Sbaban 	if (unixname != NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) {
28674520Snw141292 		/* Get uid/gid by name */
28684520Snw141292 		if (is_user) {
28694520Snw141292 			errno = 0;
28704520Snw141292 			if (getpwnam_r(unixname, &pwd, buf,
28714520Snw141292 					sizeof (buf)) == NULL) {
28724520Snw141292 				errnum = errno;
28734520Snw141292 				idmapdlog(LOG_WARNING,
28744520Snw141292 				"%s: getpwnam_r(%s) failed (%s).",
28754520Snw141292 					me, unixname,
28764520Snw141292 					errnum?strerror(errnum):"not found");
28774520Snw141292 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
28784520Snw141292 						IDMAP_ERR_INTERNAL;
28794520Snw141292 				goto out;
28804520Snw141292 			}
28814520Snw141292 			mapping->id1.idmap_id_u.uid = pwd.pw_uid;
28824520Snw141292 		} else {
28834520Snw141292 			errno = 0;
28844520Snw141292 			if (getgrnam_r(unixname, &grp, buf,
28854520Snw141292 					sizeof (buf)) == NULL) {
28864520Snw141292 				errnum = errno;
28874520Snw141292 				idmapdlog(LOG_WARNING,
28884520Snw141292 				"%s: getgrnam_r(%s) failed (%s).",
28894520Snw141292 					me, unixname,
28904520Snw141292 					errnum?strerror(errnum):"not found");
28914520Snw141292 				retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND:
28924520Snw141292 						IDMAP_ERR_INTERNAL;
28934520Snw141292 				goto out;
28944520Snw141292 			}
28954520Snw141292 			mapping->id1.idmap_id_u.gid = grp.gr_gid;
28964520Snw141292 		}
28974520Snw141292 	}
28984520Snw141292 
28994520Snw141292 	state.pid2sid_done = TRUE;
29004520Snw141292 	retcode = pid2sid_first_pass(&state, cache, db, mapping, &idres,
29014520Snw141292 			is_user, 1);
29024520Snw141292 	if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE)
29034520Snw141292 		goto out;
29044520Snw141292 
29054520Snw141292 	/* Update cache */
29064520Snw141292 	(void) update_cache_pid2sid(&state, cache, mapping, &idres);
29074520Snw141292 
29084520Snw141292 out:
29094520Snw141292 	mapping->direction = idres.direction;
29104520Snw141292 	mapping->id2 = idres.id;
29114520Snw141292 	(void) memset(&idres, 0, sizeof (idres));
29124520Snw141292 	xdr_free(xdr_idmap_id_res, (caddr_t)&idres);
29134520Snw141292 	return (retcode);
29144520Snw141292 }
2915