server.c revision 11963:061945695ce1
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27/*
28 * Service routines
29 */
30
31#include "idmapd.h"
32#include "idmap_priv.h"
33#include "nldaputils.h"
34#include <signal.h>
35#include <thread.h>
36#include <string.h>
37#include <strings.h>
38#include <errno.h>
39#include <assert.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <sys/sid.h>
43#include <ucred.h>
44#include <pwd.h>
45#include <auth_attr.h>
46#include <secdb.h>
47#include <sys/u8_textprep.h>
48#include <note.h>
49
50#define	_VALIDATE_LIST_CB_DATA(col, val, siz)\
51	retcode = validate_list_cb_data(cb_data, argc, argv, col,\
52			(uchar_t **)val, siz);\
53	if (retcode == IDMAP_NEXT) {\
54		result->retcode = IDMAP_NEXT;\
55		return (0);\
56	} else if (retcode < 0) {\
57		result->retcode = retcode;\
58		return (1);\
59	}
60
61#define	PROCESS_LIST_SVC_SQL(rcode, db, dbname, sql, limit, flag, cb, res, len)\
62	rcode = process_list_svc_sql(db, dbname, sql, limit, flag, cb, res);\
63	if (rcode == IDMAP_ERR_BUSY)\
64		res->retcode = IDMAP_ERR_BUSY;\
65	else if (rcode == IDMAP_SUCCESS && len == 0)\
66		res->retcode = IDMAP_ERR_NOTFOUND;
67
68
69#define	STRDUP_OR_FAIL(to, from) \
70	if ((from) == NULL) \
71		to = NULL; \
72	else { \
73		if ((to = strdup(from)) == NULL) \
74			return (1); \
75	}
76
77#define	STRDUP_CHECK(to, from) \
78	if ((from) != NULL) { \
79		to = strdup(from); \
80		if (to == NULL) { \
81			result->retcode = IDMAP_ERR_MEMORY; \
82			goto out; \
83		} \
84	}
85
86/* ARGSUSED */
87bool_t
88idmap_null_1_svc(void *result, struct svc_req *rqstp)
89{
90	return (TRUE);
91}
92
93/*
94 * RPC layer allocates empty strings to replace NULL char *.
95 * This utility function frees these empty strings.
96 */
97static
98void
99sanitize_mapping_request(idmap_mapping *req)
100{
101	if (EMPTY_STRING(req->id1name)) {
102		free(req->id1name);
103		req->id1name = NULL;
104	}
105	if (EMPTY_STRING(req->id1domain)) {
106		free(req->id1domain);
107		req->id1domain = NULL;
108	}
109	if (EMPTY_STRING(req->id2name)) {
110		free(req->id2name);
111		req->id2name = NULL;
112	}
113	if (EMPTY_STRING(req->id2domain)) {
114		free(req->id2domain);
115		req->id2domain = NULL;
116	}
117	req->direction = _IDMAP_F_DONE;
118}
119
120static
121int
122validate_mapped_id_by_name_req(idmap_mapping *req)
123{
124	int e;
125
126	if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req))
127		return (IDMAP_SUCCESS);
128
129	if (IS_REQUEST_SID(*req, 1)) {
130		if (!EMPTY_STRING(req->id1name) &&
131		    u8_validate(req->id1name, strlen(req->id1name),
132		    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
133			return (IDMAP_ERR_BAD_UTF8);
134		if (!EMPTY_STRING(req->id1domain) &&
135		    u8_validate(req->id1domain, strlen(req->id1domain),
136		    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
137			return (IDMAP_ERR_BAD_UTF8);
138	}
139
140	return (IDMAP_SUCCESS);
141}
142
143static
144int
145validate_rule(idmap_namerule *rule)
146{
147	int e;
148
149	if (!EMPTY_STRING(rule->winname) &&
150	    u8_validate(rule->winname, strlen(rule->winname),
151	    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
152		return (IDMAP_ERR_BAD_UTF8);
153
154	if (!EMPTY_STRING(rule->windomain) &&
155	    u8_validate(rule->windomain, strlen(rule->windomain),
156	    NULL, U8_VALIDATE_ENTIRE, &e) < 0)
157		return (IDMAP_ERR_BAD_UTF8);
158
159	return (IDMAP_SUCCESS);
160
161}
162
163static
164bool_t
165validate_rules(idmap_update_batch *batch)
166{
167	idmap_update_op	*up;
168	int i;
169
170	for (i = 0; i < batch->idmap_update_batch_len; i++) {
171		up = &(batch->idmap_update_batch_val[i]);
172		if (validate_rule(&(up->idmap_update_op_u.rule))
173		    != IDMAP_SUCCESS)
174			return (IDMAP_ERR_BAD_UTF8);
175	}
176
177	return (IDMAP_SUCCESS);
178}
179
180/* ARGSUSED */
181bool_t
182idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch,
183		idmap_ids_res *result, struct svc_req *rqstp)
184{
185	sqlite		*cache = NULL, *db = NULL;
186	lookup_state_t	state;
187	idmap_retcode	retcode;
188	uint_t		i;
189
190	/* Init */
191	(void) memset(result, 0, sizeof (*result));
192	(void) memset(&state, 0, sizeof (state));
193
194	/* Return success if nothing was requested */
195	if (batch.idmap_mapping_batch_len < 1)
196		goto out;
197
198	/* Get cache handle */
199	result->retcode = get_cache_handle(&cache);
200	if (result->retcode != IDMAP_SUCCESS)
201		goto out;
202	state.cache = cache;
203
204	/* Get db handle */
205	result->retcode = get_db_handle(&db);
206	if (result->retcode != IDMAP_SUCCESS)
207		goto out;
208	state.db = db;
209
210	/* Allocate result array */
211	result->ids.ids_val = calloc(batch.idmap_mapping_batch_len,
212	    sizeof (idmap_id_res));
213	if (result->ids.ids_val == NULL) {
214		idmapdlog(LOG_ERR, "Out of memory");
215		result->retcode = IDMAP_ERR_MEMORY;
216		goto out;
217	}
218	result->ids.ids_len = batch.idmap_mapping_batch_len;
219
220	/* Allocate hash table to check for duplicate sids */
221	state.sid_history = calloc(batch.idmap_mapping_batch_len,
222	    sizeof (*state.sid_history));
223	if (state.sid_history == NULL) {
224		idmapdlog(LOG_ERR, "Out of memory");
225		result->retcode = IDMAP_ERR_MEMORY;
226		goto out;
227	}
228	state.sid_history_size = batch.idmap_mapping_batch_len;
229	for (i = 0; i < state.sid_history_size; i++) {
230		state.sid_history[i].key = state.sid_history_size;
231		state.sid_history[i].next = state.sid_history_size;
232	}
233	state.batch = &batch;
234	state.result = result;
235
236	/* Get directory-based name mapping info */
237	result->retcode = load_cfg_in_state(&state);
238	if (result->retcode != IDMAP_SUCCESS)
239		goto out;
240
241	/* Init our 'done' flags */
242	state.sid2pid_done = state.pid2sid_done = TRUE;
243
244	/* First stage */
245	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
246		state.curpos = i;
247		(void) sanitize_mapping_request(
248		    &batch.idmap_mapping_batch_val[i]);
249		if (IS_BATCH_SID(batch, i)) {
250			retcode = sid2pid_first_pass(
251			    &state,
252			    &batch.idmap_mapping_batch_val[i],
253			    &result->ids.ids_val[i]);
254		} else if (IS_BATCH_UID(batch, i)) {
255			retcode = pid2sid_first_pass(
256			    &state,
257			    &batch.idmap_mapping_batch_val[i],
258			    &result->ids.ids_val[i], 1);
259		} else if (IS_BATCH_GID(batch, i)) {
260			retcode = pid2sid_first_pass(
261			    &state,
262			    &batch.idmap_mapping_batch_val[i],
263			    &result->ids.ids_val[i], 0);
264		} else {
265			result->ids.ids_val[i].retcode = IDMAP_ERR_IDTYPE;
266			continue;
267		}
268		if (IDMAP_FATAL_ERROR(retcode)) {
269			result->retcode = retcode;
270			goto out;
271		}
272	}
273
274	/* Check if we are done */
275	if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
276		goto out;
277
278	/*
279	 * native LDAP lookups:
280	 *  pid2sid:
281	 *	- nldap or mixed mode. Lookup nldap by pid or unixname to get
282	 *	  winname.
283	 *  sid2pid:
284	 *	- nldap mode. Got winname and sid (either given or found in
285	 *	  name_cache). Lookup nldap by winname to get pid and
286	 *	  unixname.
287	 */
288	if (state.nldap_nqueries) {
289		retcode = nldap_lookup_batch(&state, &batch, result);
290		if (IDMAP_FATAL_ERROR(retcode)) {
291			result->retcode = retcode;
292			goto out;
293		}
294	}
295
296	/*
297	 * AD lookups:
298	 *  pid2sid:
299	 *	- nldap or mixed mode. Got winname from nldap lookup.
300	 *	  winname2sid could not be resolved locally. Lookup AD
301	 *	  by winname to get sid.
302	 *	- ad mode. Got unixname. Lookup AD by unixname to get
303	 *	  winname and sid.
304	 *  sid2pid:
305	 *	- ad or mixed mode. Lookup AD by sid or winname to get
306	 *	  winname, sid and unixname.
307	 *	- any mode. Got either sid or winname but not both. Lookup
308	 *	  AD by sid or winname to get winname, sid.
309	 */
310	if (state.ad_nqueries) {
311		retcode = ad_lookup_batch(&state, &batch, result);
312		if (IDMAP_FATAL_ERROR(retcode)) {
313			result->retcode = retcode;
314			goto out;
315		}
316	}
317
318	/*
319	 * native LDAP lookups:
320	 *  sid2pid:
321	 *	- nldap mode. Got winname and sid from AD lookup. Lookup nldap
322	 *	  by winname to get pid and unixname.
323	 */
324	if (state.nldap_nqueries) {
325		retcode = nldap_lookup_batch(&state, &batch, result);
326		if (IDMAP_FATAL_ERROR(retcode)) {
327			result->retcode = retcode;
328			goto out;
329		}
330	}
331
332	/* Reset 'done' flags */
333	state.sid2pid_done = state.pid2sid_done = TRUE;
334
335	/* Second stage */
336	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
337		state.curpos = i;
338		if (IS_BATCH_SID(batch, i)) {
339			retcode = sid2pid_second_pass(
340			    &state,
341			    &batch.idmap_mapping_batch_val[i],
342			    &result->ids.ids_val[i]);
343		} else if (IS_BATCH_UID(batch, i)) {
344			retcode = pid2sid_second_pass(
345			    &state,
346			    &batch.idmap_mapping_batch_val[i],
347			    &result->ids.ids_val[i], 1);
348		} else if (IS_BATCH_GID(batch, i)) {
349			retcode = pid2sid_second_pass(
350			    &state,
351			    &batch.idmap_mapping_batch_val[i],
352			    &result->ids.ids_val[i], 0);
353		} else {
354			/* First stage has already set the error */
355			continue;
356		}
357		if (IDMAP_FATAL_ERROR(retcode)) {
358			result->retcode = retcode;
359			goto out;
360		}
361	}
362
363	/* Check if we are done */
364	if (state.sid2pid_done == TRUE && state.pid2sid_done == TRUE)
365		goto out;
366
367	/* Reset our 'done' flags */
368	state.sid2pid_done = state.pid2sid_done = TRUE;
369
370	/* Update cache in a single transaction */
371	if (sql_exec_no_cb(cache, IDMAP_CACHENAME, "BEGIN TRANSACTION;")
372	    != IDMAP_SUCCESS)
373		goto out;
374
375	for (i = 0; i < batch.idmap_mapping_batch_len; i++) {
376		state.curpos = i;
377		if (IS_BATCH_SID(batch, i)) {
378			(void) update_cache_sid2pid(
379			    &state,
380			    &batch.idmap_mapping_batch_val[i],
381			    &result->ids.ids_val[i]);
382		} else if ((IS_BATCH_UID(batch, i)) ||
383		    (IS_BATCH_GID(batch, i))) {
384			(void) update_cache_pid2sid(
385			    &state,
386			    &batch.idmap_mapping_batch_val[i],
387			    &result->ids.ids_val[i]);
388		}
389	}
390
391	/* Commit if we have at least one successful update */
392	if (state.sid2pid_done == FALSE || state.pid2sid_done == FALSE)
393		(void) sql_exec_no_cb(cache, IDMAP_CACHENAME,
394		    "COMMIT TRANSACTION;");
395	else
396		(void) sql_exec_no_cb(cache, IDMAP_CACHENAME,
397		    "END TRANSACTION;");
398
399out:
400	cleanup_lookup_state(&state);
401	if (IDMAP_ERROR(result->retcode)) {
402		xdr_free(xdr_idmap_ids_res, (caddr_t)result);
403		result->ids.ids_len = 0;
404		result->ids.ids_val = NULL;
405	}
406	result->retcode = idmap_stat4prot(result->retcode);
407	return (TRUE);
408}
409
410
411/* ARGSUSED */
412static
413int
414list_mappings_cb(void *parg, int argc, char **argv, char **colnames)
415{
416	list_cb_data_t		*cb_data;
417	char			*str;
418	idmap_mappings_res	*result;
419	idmap_retcode		retcode;
420	int			w2u, u2w;
421	char			*end;
422	static int		validated_column_names = 0;
423	idmap_how		*how;
424
425	cb_data = (list_cb_data_t *)parg;
426
427	if (!validated_column_names) {
428		assert(strcmp(colnames[0], "rowid") == 0);
429		assert(strcmp(colnames[1], "sidprefix") == 0);
430		assert(strcmp(colnames[2], "rid") == 0);
431		assert(strcmp(colnames[3], "pid") == 0);
432		assert(strcmp(colnames[4], "w2u") == 0);
433		assert(strcmp(colnames[5], "u2w") == 0);
434		assert(strcmp(colnames[6], "windomain") == 0);
435		assert(strcmp(colnames[7], "canon_winname") == 0);
436		assert(strcmp(colnames[8], "unixname") == 0);
437		assert(strcmp(colnames[9], "is_user") == 0);
438		assert(strcmp(colnames[10], "is_wuser") == 0);
439		assert(strcmp(colnames[11], "map_type") == 0);
440		assert(strcmp(colnames[12], "map_dn") == 0);
441		assert(strcmp(colnames[13], "map_attr") == 0);
442		assert(strcmp(colnames[14], "map_value") == 0);
443		assert(strcmp(colnames[15], "map_windomain") == 0);
444		assert(strcmp(colnames[16], "map_winname") == 0);
445		assert(strcmp(colnames[17], "map_unixname") == 0);
446		assert(strcmp(colnames[18], "map_is_nt4") == 0);
447		validated_column_names = 1;
448	}
449
450	result = (idmap_mappings_res *)cb_data->result;
451
452	_VALIDATE_LIST_CB_DATA(19, &result->mappings.mappings_val,
453	    sizeof (idmap_mapping));
454
455	result->mappings.mappings_len++;
456
457	if ((str = strdup(argv[1])) == NULL)
458		return (1);
459	result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.prefix =
460	    str;
461	result->mappings.mappings_val[cb_data->next].id1.idmap_id_u.sid.rid =
462	    strtoul(argv[2], &end, 10);
463	result->mappings.mappings_val[cb_data->next].id1.idtype =
464	    strtol(argv[10], &end, 10) ? IDMAP_USID : IDMAP_GSID;
465
466	result->mappings.mappings_val[cb_data->next].id2.idmap_id_u.uid =
467	    strtoul(argv[3], &end, 10);
468	result->mappings.mappings_val[cb_data->next].id2.idtype =
469	    strtol(argv[9], &end, 10) ? IDMAP_UID : IDMAP_GID;
470
471	w2u = argv[4] ? strtol(argv[4], &end, 10) : 0;
472	u2w = argv[5] ? strtol(argv[5], &end, 10) : 0;
473
474	if (w2u > 0 && u2w == 0)
475		result->mappings.mappings_val[cb_data->next].direction =
476		    IDMAP_DIRECTION_W2U;
477	else if (w2u == 0 && u2w > 0)
478		result->mappings.mappings_val[cb_data->next].direction =
479		    IDMAP_DIRECTION_U2W;
480	else
481		result->mappings.mappings_val[cb_data->next].direction =
482		    IDMAP_DIRECTION_BI;
483
484	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id1domain,
485	    argv[6]);
486
487	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id1name,
488	    argv[7]);
489
490	STRDUP_OR_FAIL(result->mappings.mappings_val[cb_data->next].id2name,
491	    argv[8]);
492
493	if (cb_data->flag & IDMAP_REQ_FLG_MAPPING_INFO) {
494		how = &result->mappings.mappings_val[cb_data->next].info.how;
495		how->map_type = strtoul(argv[11], &end, 10);
496		switch (how->map_type) {
497		case IDMAP_MAP_TYPE_DS_AD:
498			how->idmap_how_u.ad.dn =
499			    strdup(argv[12]);
500			how->idmap_how_u.ad.attr =
501			    strdup(argv[13]);
502			how->idmap_how_u.ad.value =
503			    strdup(argv[14]);
504			break;
505
506		case IDMAP_MAP_TYPE_DS_NLDAP:
507			how->idmap_how_u.nldap.dn =
508			    strdup(argv[12]);
509			how->idmap_how_u.nldap.attr =
510			    strdup(argv[13]);
511			how->idmap_how_u.nldap.value =
512			    strdup(argv[14]);
513			break;
514
515		case IDMAP_MAP_TYPE_RULE_BASED:
516			how->idmap_how_u.rule.windomain =
517			    strdup(argv[15]);
518			how->idmap_how_u.rule.winname =
519			    strdup(argv[16]);
520			how->idmap_how_u.rule.unixname =
521			    strdup(argv[17]);
522			how->idmap_how_u.rule.is_nt4 =
523			    strtoul(argv[18], &end, 10);
524			how->idmap_how_u.rule.is_user =
525			    strtol(argv[9], &end, 10);
526			how->idmap_how_u.rule.is_wuser =
527			    strtol(argv[10], &end, 10);
528			break;
529
530		case IDMAP_MAP_TYPE_EPHEMERAL:
531			break;
532
533		case IDMAP_MAP_TYPE_LOCAL_SID:
534			break;
535
536		case IDMAP_MAP_TYPE_IDMU:
537			how->idmap_how_u.idmu.dn =
538			    strdup(argv[12]);
539			how->idmap_how_u.idmu.attr =
540			    strdup(argv[13]);
541			how->idmap_how_u.idmu.value =
542			    strdup(argv[14]);
543			break;
544
545		default:
546			/* Unknown mapping type */
547			assert(FALSE);
548		}
549
550	}
551
552	result->lastrowid = strtoll(argv[0], &end, 10);
553	cb_data->next++;
554	result->retcode = IDMAP_SUCCESS;
555	return (0);
556}
557
558
559/* ARGSUSED */
560bool_t
561idmap_list_mappings_1_svc(int64_t lastrowid, uint64_t limit, int32_t flag,
562    idmap_mappings_res *result, struct svc_req *rqstp)
563{
564	sqlite		*cache = NULL;
565	char		lbuf[30], rbuf[30];
566	uint64_t	maxlimit;
567	idmap_retcode	retcode;
568	char		*sql = NULL;
569	time_t		curtime;
570
571	(void) memset(result, 0, sizeof (*result));
572
573	/* Current time */
574	errno = 0;
575	if ((curtime = time(NULL)) == (time_t)-1) {
576		idmapdlog(LOG_ERR, "Failed to get current time (%s)",
577		    strerror(errno));
578		retcode = IDMAP_ERR_INTERNAL;
579		goto out;
580	}
581
582	RDLOCK_CONFIG();
583	maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
584	UNLOCK_CONFIG();
585
586	/* Get cache handle */
587	result->retcode = get_cache_handle(&cache);
588	if (result->retcode != IDMAP_SUCCESS)
589		goto out;
590
591	result->retcode = IDMAP_ERR_INTERNAL;
592
593	/* Create LIMIT expression. */
594	if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
595		limit = maxlimit;
596	if (limit > 0)
597		(void) snprintf(lbuf, sizeof (lbuf),
598		    "LIMIT %" PRIu64, limit + 1ULL);
599	else
600		lbuf[0] = '\0';
601
602	(void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
603
604	/*
605	 * Combine all the above into a giant SELECT statement that
606	 * will return the requested mappings
607	 */
608
609	sql = sqlite_mprintf("SELECT rowid, sidprefix, rid, pid, w2u, "
610	    "u2w, windomain, canon_winname, unixname, is_user, is_wuser, "
611	    "map_type, map_dn, map_attr, map_value, map_windomain, "
612	    "map_winname, map_unixname, map_is_nt4 "
613	    "FROM idmap_cache WHERE %s AND "
614	    "(pid >= 2147483648 OR (expiration = 0 OR "
615	    "expiration ISNULL  OR expiration > %d)) "
616	    "%s;",
617	    rbuf, curtime, lbuf);
618	if (sql == NULL) {
619		result->retcode = IDMAP_ERR_MEMORY;
620		idmapdlog(LOG_ERR, "Out of memory");
621		goto out;
622	}
623
624	/* Execute the SQL statement and update the return buffer */
625	PROCESS_LIST_SVC_SQL(retcode, cache, IDMAP_CACHENAME, sql, limit,
626	    flag, list_mappings_cb, result, result->mappings.mappings_len);
627
628out:
629	if (sql)
630		sqlite_freemem(sql);
631	if (IDMAP_ERROR(result->retcode))
632		(void) xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
633	result->retcode = idmap_stat4prot(result->retcode);
634	return (TRUE);
635}
636
637
638/* ARGSUSED */
639static
640int
641list_namerules_cb(void *parg, int argc, char **argv, char **colnames)
642{
643	list_cb_data_t		*cb_data;
644	idmap_namerules_res	*result;
645	idmap_retcode		retcode;
646	int			w2u_order, u2w_order;
647	char			*end;
648	static int		validated_column_names = 0;
649
650	if (!validated_column_names) {
651		assert(strcmp(colnames[0], "rowid") == 0);
652		assert(strcmp(colnames[1], "is_user") == 0);
653		assert(strcmp(colnames[2], "is_wuser") == 0);
654		assert(strcmp(colnames[3], "windomain") == 0);
655		assert(strcmp(colnames[4], "winname_display") == 0);
656		assert(strcmp(colnames[5], "is_nt4") == 0);
657		assert(strcmp(colnames[6], "unixname") == 0);
658		assert(strcmp(colnames[7], "w2u_order") == 0);
659		assert(strcmp(colnames[8], "u2w_order") == 0);
660		validated_column_names = 1;
661	}
662
663	cb_data = (list_cb_data_t *)parg;
664	result = (idmap_namerules_res *)cb_data->result;
665
666	_VALIDATE_LIST_CB_DATA(9, &result->rules.rules_val,
667	    sizeof (idmap_namerule));
668
669	result->rules.rules_len++;
670
671	result->rules.rules_val[cb_data->next].is_user =
672	    strtol(argv[1], &end, 10);
673
674	result->rules.rules_val[cb_data->next].is_wuser =
675	    strtol(argv[2], &end, 10);
676
677	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].windomain,
678	    argv[3]);
679
680	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].winname,
681	    argv[4]);
682
683	result->rules.rules_val[cb_data->next].is_nt4 =
684	    strtol(argv[5], &end, 10);
685
686	STRDUP_OR_FAIL(result->rules.rules_val[cb_data->next].unixname,
687	    argv[6]);
688
689	w2u_order = argv[7] ? strtol(argv[7], &end, 10) : 0;
690	u2w_order = argv[8] ? strtol(argv[8], &end, 10) : 0;
691
692	if (w2u_order > 0 && u2w_order == 0)
693		result->rules.rules_val[cb_data->next].direction =
694		    IDMAP_DIRECTION_W2U;
695	else if (w2u_order == 0 && u2w_order > 0)
696		result->rules.rules_val[cb_data->next].direction =
697		    IDMAP_DIRECTION_U2W;
698	else
699		result->rules.rules_val[cb_data->next].direction =
700		    IDMAP_DIRECTION_BI;
701
702	result->lastrowid = strtoll(argv[0], &end, 10);
703	cb_data->next++;
704	result->retcode = IDMAP_SUCCESS;
705	return (0);
706}
707
708
709/* ARGSUSED */
710bool_t
711idmap_list_namerules_1_svc(idmap_namerule rule, uint64_t lastrowid,
712		uint64_t limit, idmap_namerules_res *result,
713		struct svc_req *rqstp)
714{
715
716	sqlite		*db = NULL;
717	char		lbuf[30], rbuf[30];
718	char		*sql = NULL;
719	char		*expr = NULL;
720	uint64_t	maxlimit;
721	idmap_retcode	retcode;
722
723	(void) memset(result, 0, sizeof (*result));
724
725	result->retcode = validate_rule(&rule);
726	if (result->retcode != IDMAP_SUCCESS)
727		goto out;
728
729	RDLOCK_CONFIG();
730	maxlimit = _idmapdstate.cfg->pgcfg.list_size_limit;
731	UNLOCK_CONFIG();
732
733	/* Get db handle */
734	result->retcode = get_db_handle(&db);
735	if (result->retcode != IDMAP_SUCCESS)
736		goto out;
737
738	result->retcode = gen_sql_expr_from_rule(&rule, &expr);
739	if (result->retcode != IDMAP_SUCCESS)
740		goto out;
741
742	/* Create LIMIT expression. */
743	if (limit == 0 || (maxlimit > 0 && maxlimit < limit))
744		limit = maxlimit;
745	if (limit > 0)
746		(void) snprintf(lbuf, sizeof (lbuf),
747		    "LIMIT %" PRIu64, limit + 1ULL);
748	else
749		lbuf[0] = '\0';
750
751	(void) snprintf(rbuf, sizeof (rbuf), "rowid > %" PRIu64, lastrowid);
752
753	/*
754	 * Combine all the above into a giant SELECT statement that
755	 * will return the requested rules
756	 */
757	sql = sqlite_mprintf("SELECT rowid, is_user, is_wuser, windomain, "
758	    "winname_display, is_nt4, unixname, w2u_order, u2w_order "
759	    "FROM namerules WHERE "
760	    " %s %s %s;",
761	    rbuf, expr, lbuf);
762
763	if (sql == NULL) {
764		result->retcode = IDMAP_ERR_MEMORY;
765		idmapdlog(LOG_ERR, "Out of memory");
766		goto out;
767	}
768
769	/* Execute the SQL statement and update the return buffer */
770	PROCESS_LIST_SVC_SQL(retcode, db, IDMAP_DBNAME, sql, limit,
771	    0, list_namerules_cb, result, result->rules.rules_len);
772
773out:
774	if (expr)
775		sqlite_freemem(expr);
776	if (sql)
777		sqlite_freemem(sql);
778	if (IDMAP_ERROR(result->retcode))
779		(void) xdr_free(xdr_idmap_namerules_res, (caddr_t)result);
780	result->retcode = idmap_stat4prot(result->retcode);
781	return (TRUE);
782}
783
784#define	IDMAP_RULES_AUTH	"solaris.admin.idmap.rules"
785static int
786verify_rules_auth(struct svc_req *rqstp)
787{
788	ucred_t		*uc = NULL;
789	uid_t		uid;
790	char		buf[1024];
791	struct passwd	pwd;
792
793	if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
794		idmapdlog(LOG_ERR, "svc_getcallerucred failed during "
795		    "authorization (%s)", strerror(errno));
796		return (-1);
797	}
798
799	uid = ucred_geteuid(uc);
800	if (uid == (uid_t)-1) {
801		idmapdlog(LOG_ERR, "ucred_geteuid failed during "
802		    "authorization (%s)", strerror(errno));
803		ucred_free(uc);
804		return (-1);
805	}
806
807	if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL) {
808		idmapdlog(LOG_ERR, "getpwuid_r(%u) failed during "
809		    "authorization (%s)", uid, strerror(errno));
810		ucred_free(uc);
811		return (-1);
812	}
813
814	if (chkauthattr(IDMAP_RULES_AUTH, pwd.pw_name) != 1) {
815		idmapdlog(LOG_INFO, "%s is not authorized (%s)",
816		    pwd.pw_name, IDMAP_RULES_AUTH);
817		ucred_free(uc);
818		return (-1);
819	}
820
821	ucred_free(uc);
822	return (1);
823}
824
825/*
826 * Meaning of the return values is the following: For retcode ==
827 * IDMAP_SUCCESS, everything went OK and error_index is
828 * undefined. Otherwise, error_index >=0 shows the failed batch
829 * element. errro_index == -1 indicates failure at the beginning,
830 * error_index == -2 at the end.
831 */
832
833/* ARGSUSED */
834bool_t
835idmap_update_1_svc(idmap_update_batch batch, idmap_update_res *res,
836		struct svc_req *rqstp)
837{
838	sqlite		*db = NULL;
839	idmap_update_op	*up;
840	int		i;
841	int		trans = FALSE;
842
843	res->error_index = -1;
844	(void) memset(&res->error_rule, 0, sizeof (res->error_rule));
845	(void) memset(&res->conflict_rule, 0, sizeof (res->conflict_rule));
846
847	if (verify_rules_auth(rqstp) < 0) {
848		res->retcode = IDMAP_ERR_PERMISSION_DENIED;
849		goto out;
850	}
851
852	if (batch.idmap_update_batch_len == 0 ||
853	    batch.idmap_update_batch_val == NULL) {
854		res->retcode = IDMAP_SUCCESS;
855		goto out;
856	}
857
858	res->retcode = validate_rules(&batch);
859	if (res->retcode != IDMAP_SUCCESS)
860		goto out;
861
862	/* Get db handle */
863	res->retcode = get_db_handle(&db);
864	if (res->retcode != IDMAP_SUCCESS)
865		goto out;
866
867	res->retcode = sql_exec_no_cb(db, IDMAP_DBNAME, "BEGIN TRANSACTION;");
868	if (res->retcode != IDMAP_SUCCESS)
869		goto out;
870	trans = TRUE;
871
872	for (i = 0; i < batch.idmap_update_batch_len; i++) {
873		up = &batch.idmap_update_batch_val[i];
874		switch (up->opnum) {
875		case OP_NONE:
876			res->retcode = IDMAP_SUCCESS;
877			break;
878		case OP_ADD_NAMERULE:
879			res->retcode = add_namerule(db,
880			    &up->idmap_update_op_u.rule);
881			break;
882		case OP_RM_NAMERULE:
883			res->retcode = rm_namerule(db,
884			    &up->idmap_update_op_u.rule);
885			break;
886		case OP_FLUSH_NAMERULES:
887			res->retcode = flush_namerules(db);
888			break;
889		default:
890			res->retcode = IDMAP_ERR_NOTSUPPORTED;
891			break;
892		};
893
894		if (res->retcode != IDMAP_SUCCESS) {
895			res->error_index = i;
896			if (up->opnum == OP_ADD_NAMERULE ||
897			    up->opnum == OP_RM_NAMERULE) {
898				idmap_stat r2 =
899				    idmap_namerule_cpy(&res->error_rule,
900				    &up->idmap_update_op_u.rule);
901				if (r2 != IDMAP_SUCCESS)
902					res->retcode = r2;
903			}
904			goto out;
905		}
906	}
907
908out:
909	if (trans) {
910		if (res->retcode == IDMAP_SUCCESS) {
911			res->retcode =
912			    sql_exec_no_cb(db, IDMAP_DBNAME,
913			    "COMMIT TRANSACTION;");
914			if (res->retcode ==  IDMAP_SUCCESS) {
915				/*
916				 * We've updated the rules.  Expire the cache
917				 * so that existing mappings will be
918				 * reconsidered.
919				 */
920				res->retcode =
921				    idmap_cache_flush(IDMAP_FLUSH_EXPIRE);
922			} else {
923				res->error_index = -2;
924			}
925		}
926		else
927			(void) sql_exec_no_cb(db, IDMAP_DBNAME,
928			    "ROLLBACK TRANSACTION;");
929	}
930
931	res->retcode = idmap_stat4prot(res->retcode);
932
933	return (TRUE);
934}
935
936static
937int
938copy_string(char **to, char *from)
939{
940	if (EMPTY_STRING(from)) {
941		*to = NULL;
942	} else {
943		*to = strdup(from);
944		if (*to == NULL) {
945			idmapdlog(LOG_ERR, "Out of memory");
946			return (IDMAP_ERR_MEMORY);
947		}
948	}
949	return (IDMAP_SUCCESS);
950}
951
952static
953int
954copy_id(idmap_id *to, idmap_id *from)
955{
956	(void) memset(to, 0, sizeof (*to));
957
958	to->idtype = from->idtype;
959	if (IS_ID_SID(*from)) {
960		idmap_retcode retcode;
961
962		to->idmap_id_u.sid.rid = from->idmap_id_u.sid.rid;
963		retcode = copy_string(&to->idmap_id_u.sid.prefix,
964		    from->idmap_id_u.sid.prefix);
965
966		return (retcode);
967	} else {
968		to->idmap_id_u.uid = from->idmap_id_u.uid;
969		return (IDMAP_SUCCESS);
970	}
971}
972
973static
974int
975copy_mapping(idmap_mapping *mapping, idmap_mapping *request)
976{
977	idmap_retcode retcode;
978
979	(void) memset(mapping, 0, sizeof (*mapping));
980
981	mapping->flag = request->flag;
982	mapping->direction = _IDMAP_F_DONE;
983
984	retcode = copy_id(&mapping->id1, &request->id1);
985	if (retcode != IDMAP_SUCCESS)
986		goto errout;
987
988	retcode = copy_string(&mapping->id1domain, request->id1domain);
989	if (retcode != IDMAP_SUCCESS)
990		goto errout;
991
992	retcode = copy_string(&mapping->id1name, request->id1name);
993	if (retcode != IDMAP_SUCCESS)
994		goto errout;
995
996	retcode = copy_id(&mapping->id2, &request->id2);
997	if (retcode != IDMAP_SUCCESS)
998		goto errout;
999
1000	retcode = copy_string(&mapping->id2domain, request->id2domain);
1001	if (retcode != IDMAP_SUCCESS)
1002		goto errout;
1003	retcode = copy_string(&mapping->id2name, request->id2name);
1004	if (retcode != IDMAP_SUCCESS)
1005		goto errout;
1006
1007	return (IDMAP_SUCCESS);
1008
1009errout:
1010	if (IS_ID_SID(mapping->id1))
1011		free(mapping->id1.idmap_id_u.sid.prefix);
1012	free(mapping->id1domain);
1013	free(mapping->id1name);
1014	if (IS_ID_SID(mapping->id2))
1015		free(mapping->id2.idmap_id_u.sid.prefix);
1016	free(mapping->id2domain);
1017	free(mapping->id2name);
1018
1019	(void) memset(mapping, 0, sizeof (*mapping));
1020	return (retcode);
1021}
1022
1023
1024/* ARGSUSED */
1025bool_t
1026idmap_get_mapped_id_by_name_1_svc(idmap_mapping request,
1027		idmap_mappings_res *result, struct svc_req *rqstp)
1028{
1029	idmap_mapping_batch batch_request;
1030	idmap_ids_res batch_result;
1031	idmap_mapping *map;
1032
1033	/* Clear out things we might want to xdr_free on error */
1034	(void) memset(&batch_result, 0, sizeof (batch_result));
1035	(void) memset(result, 0, sizeof (*result));
1036
1037	result->retcode = validate_mapped_id_by_name_req(&request);
1038	if (result->retcode != IDMAP_SUCCESS)
1039		goto out;
1040
1041	/*
1042	 * Copy the request.  We need to modify it, and
1043	 * what we have is a shallow copy.  Freeing pointers from
1044	 * our copy will lead to problems, since the RPC framework
1045	 * has its own copy of those pointers.  Besides, we need
1046	 * a copy to return.
1047	 */
1048	map = calloc(1, sizeof (idmap_mapping));
1049	if (map == NULL) {
1050		idmapdlog(LOG_ERR, "Out of memory");
1051		result->retcode = IDMAP_ERR_MEMORY;
1052		goto out;
1053	}
1054
1055	/*
1056	 * Set up to return the filled-in mapping structure.
1057	 * Note that we xdr_free result on error, and that'll take
1058	 * care of freeing the mapping structure.
1059	 */
1060	result->mappings.mappings_val = map;
1061	result->mappings.mappings_len = 1;
1062
1063	result->retcode = copy_mapping(map, &request);
1064	if (result->retcode != IDMAP_SUCCESS)
1065		goto out;
1066
1067	/* Set up for the request to the batch API */
1068	batch_request.idmap_mapping_batch_val = map;
1069	batch_request.idmap_mapping_batch_len = 1;
1070
1071	/* Do the real work. */
1072	(void) idmap_get_mapped_ids_1_svc(batch_request,
1073	    &batch_result, rqstp);
1074
1075	/* Copy what we need out of the batch response */
1076
1077	if (batch_result.retcode != IDMAP_SUCCESS) {
1078		result->retcode = batch_result.retcode;
1079		goto out;
1080	}
1081
1082	result->retcode = copy_id(&map->id2, &batch_result.ids.ids_val[0].id);
1083	if (result->retcode != IDMAP_SUCCESS)
1084		goto out;
1085
1086	map->direction = batch_result.ids.ids_val[0].direction;
1087
1088	result->retcode = batch_result.ids.ids_val[0].retcode;
1089
1090	if (map->flag & IDMAP_REQ_FLG_MAPPING_INFO ||
1091	    result->retcode != IDMAP_SUCCESS) {
1092		(void) idmap_info_mov(&map->info,
1093		    &batch_result.ids.ids_val[0].info);
1094	}
1095
1096out:
1097	if (IDMAP_FATAL_ERROR(result->retcode)) {
1098		xdr_free(xdr_idmap_mappings_res, (caddr_t)result);
1099		result->mappings.mappings_len = 0;
1100		result->mappings.mappings_val = NULL;
1101	}
1102	result->retcode = idmap_stat4prot(result->retcode);
1103
1104	xdr_free(xdr_idmap_ids_res, (char *)&batch_result);
1105
1106	return (TRUE);
1107}
1108
1109/* ARGSUSED */
1110bool_t
1111idmap_get_prop_1_svc(idmap_prop_type request,
1112		idmap_prop_res *result, struct svc_req *rqstp)
1113{
1114	idmap_pg_config_t *pgcfg;
1115
1116	/* Init */
1117	(void) memset(result, 0, sizeof (*result));
1118	result->retcode = IDMAP_SUCCESS;
1119	result->value.prop = request;
1120
1121	RDLOCK_CONFIG();
1122
1123	/* Just shortcuts: */
1124	pgcfg = &_idmapdstate.cfg->pgcfg;
1125
1126
1127	switch (request) {
1128	case PROP_LIST_SIZE_LIMIT:
1129		result->value.idmap_prop_val_u.intval = pgcfg->list_size_limit;
1130		result->auto_discovered = FALSE;
1131		break;
1132	case PROP_DEFAULT_DOMAIN:
1133		result->auto_discovered = FALSE;
1134		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1135		    pgcfg->default_domain);
1136		break;
1137	case PROP_DOMAIN_NAME:
1138		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1139		    pgcfg->domain_name);
1140		result->auto_discovered =
1141		    pgcfg->domain_name_auto_disc;
1142		break;
1143	case PROP_MACHINE_SID:
1144		result->auto_discovered = FALSE;
1145		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1146		    pgcfg->machine_sid);
1147		break;
1148	case PROP_DOMAIN_CONTROLLER:
1149		if (pgcfg->domain_controller != NULL) {
1150			(void) memcpy(&result->value.idmap_prop_val_u.dsval,
1151			    pgcfg->domain_controller,
1152			    sizeof (idmap_ad_disc_ds_t));
1153		}
1154		result->auto_discovered = pgcfg->domain_controller_auto_disc;
1155		break;
1156	case PROP_FOREST_NAME:
1157		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1158		    pgcfg->forest_name);
1159		result->auto_discovered = pgcfg->forest_name_auto_disc;
1160		break;
1161	case PROP_SITE_NAME:
1162		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1163		    pgcfg->site_name);
1164		result->auto_discovered = pgcfg->site_name_auto_disc;
1165		break;
1166	case PROP_GLOBAL_CATALOG:
1167		if (pgcfg->global_catalog != NULL) {
1168			(void) memcpy(&result->value.idmap_prop_val_u.dsval,
1169			    pgcfg->global_catalog, sizeof (idmap_ad_disc_ds_t));
1170		}
1171		result->auto_discovered = pgcfg->global_catalog_auto_disc;
1172		break;
1173	case PROP_AD_UNIXUSER_ATTR:
1174		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1175		    pgcfg->ad_unixuser_attr);
1176		result->auto_discovered = FALSE;
1177		break;
1178	case PROP_AD_UNIXGROUP_ATTR:
1179		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1180		    pgcfg->ad_unixgroup_attr);
1181		result->auto_discovered = FALSE;
1182		break;
1183	case PROP_NLDAP_WINNAME_ATTR:
1184		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1185		    pgcfg->nldap_winname_attr);
1186		result->auto_discovered = FALSE;
1187		break;
1188	case PROP_DIRECTORY_BASED_MAPPING:
1189		STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
1190		    enum_lookup(pgcfg->directory_based_mapping,
1191		    directory_mapping_map));
1192		result->auto_discovered = FALSE;
1193		break;
1194	default:
1195		result->retcode = IDMAP_ERR_PROP_UNKNOWN;
1196		break;
1197	}
1198
1199out:
1200	UNLOCK_CONFIG();
1201	if (IDMAP_FATAL_ERROR(result->retcode)) {
1202		xdr_free(xdr_idmap_prop_res, (caddr_t)result);
1203		result->value.prop = PROP_UNKNOWN;
1204	}
1205	result->retcode = idmap_stat4prot(result->retcode);
1206	return (TRUE);
1207}
1208
1209int
1210idmap_flush_1_svc(
1211    idmap_flush_op  op,
1212    idmap_retcode *result,
1213    struct svc_req *rqstp)
1214{
1215	NOTE(ARGUNUSED(rqstp))
1216	if (verify_rules_auth(rqstp) < 0) {
1217		*result = IDMAP_ERR_PERMISSION_DENIED;
1218		return (TRUE);
1219	}
1220
1221	*result = idmap_cache_flush(op);
1222
1223	return (TRUE);
1224}
1225
1226/* ARGSUSED */
1227int
1228idmap_prog_1_freeresult(SVCXPRT *transp, xdrproc_t xdr_result,
1229		caddr_t result)
1230{
1231	(void) xdr_free(xdr_result, result);
1232	return (TRUE);
1233}
1234
1235/*
1236 * This function is called by rpc_svc.c when it encounters an error.
1237 */
1238NOTE(PRINTFLIKE(1))
1239void
1240idmap_rpc_msgout(const char *fmt, ...)
1241{
1242	va_list va;
1243	char buf[1000];
1244
1245	va_start(va, fmt);
1246	(void) vsnprintf(buf, sizeof (buf), fmt, va);
1247	va_end(va);
1248
1249	idmapdlog(LOG_ERR, "idmap RPC:  %s", buf);
1250}
1251