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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
31 #include "idmap_priv.h"
32 #include "nldaputils.h"
39 #include <sys/types.h>
44 #include <auth_attr.h>
46 #include <sys/u8_textprep.h>
49 #define _VALIDATE_LIST_CB_DATA(col, val, siz)\
50 retcode = validate_list_cb_data(cb_data, argc, argv, col,\
51 (uchar_t **)val, siz);\
52 if (retcode == IDMAP_NEXT) {\
53 result->retcode = IDMAP_NEXT;\
55 } else if (retcode < 0) {\
56 result->retcode = retcode;\
60 #define PROCESS_LIST_SVC_SQL(rcode, db, dbname, sql, limit, flag, cb, res, len)\
61 rcode = process_list_svc_sql(db, dbname, sql, limit, flag, cb, res);\
62 if (rcode == IDMAP_ERR_BUSY)\
63 res->retcode = IDMAP_ERR_BUSY;\
64 else if (rcode == IDMAP_SUCCESS && len == 0)\
65 res->retcode = IDMAP_ERR_NOTFOUND;
68 #define STRDUP_OR_FAIL(to, from) \
72 if ((to = strdup(from)) == NULL) \
76 #define STRDUP_CHECK(to, from) \
77 if ((from) != NULL) { \
80 result->retcode = IDMAP_ERR_MEMORY; \
87 idmap_null_1_svc(void *result
, struct svc_req
*rqstp
)
93 * RPC layer allocates empty strings to replace NULL char *.
94 * This utility function frees these empty strings.
98 sanitize_mapping_request(idmap_mapping
*req
)
100 if (EMPTY_STRING(req
->id1name
)) {
104 if (EMPTY_STRING(req
->id1domain
)) {
105 free(req
->id1domain
);
106 req
->id1domain
= NULL
;
108 if (EMPTY_STRING(req
->id2name
)) {
112 if (EMPTY_STRING(req
->id2domain
)) {
113 free(req
->id2domain
);
114 req
->id2domain
= NULL
;
116 req
->direction
= _IDMAP_F_DONE
;
121 validate_mapped_id_by_name_req(idmap_mapping
*req
)
125 if (IS_ID_UID(req
->id1
) || IS_ID_GID(req
->id1
))
126 return (IDMAP_SUCCESS
);
128 if (IS_ID_SID(req
->id1
)) {
129 if (!EMPTY_STRING(req
->id1name
) &&
130 u8_validate(req
->id1name
, strlen(req
->id1name
),
131 NULL
, U8_VALIDATE_ENTIRE
, &e
) < 0)
132 return (IDMAP_ERR_BAD_UTF8
);
133 if (!EMPTY_STRING(req
->id1domain
) &&
134 u8_validate(req
->id1domain
, strlen(req
->id1domain
),
135 NULL
, U8_VALIDATE_ENTIRE
, &e
) < 0)
136 return (IDMAP_ERR_BAD_UTF8
);
139 return (IDMAP_SUCCESS
);
144 validate_rule(idmap_namerule
*rule
)
148 if (!EMPTY_STRING(rule
->winname
) &&
149 u8_validate(rule
->winname
, strlen(rule
->winname
),
150 NULL
, U8_VALIDATE_ENTIRE
, &e
) < 0)
151 return (IDMAP_ERR_BAD_UTF8
);
153 if (!EMPTY_STRING(rule
->windomain
) &&
154 u8_validate(rule
->windomain
, strlen(rule
->windomain
),
155 NULL
, U8_VALIDATE_ENTIRE
, &e
) < 0)
156 return (IDMAP_ERR_BAD_UTF8
);
158 return (IDMAP_SUCCESS
);
164 validate_rules(idmap_update_batch
*batch
)
169 for (i
= 0; i
< batch
->idmap_update_batch_len
; i
++) {
170 up
= &(batch
->idmap_update_batch_val
[i
]);
171 if (validate_rule(&(up
->idmap_update_op_u
.rule
))
173 return (IDMAP_ERR_BAD_UTF8
);
176 return (IDMAP_SUCCESS
);
181 idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch
,
182 idmap_ids_res
*result
, struct svc_req
*rqstp
)
184 sqlite
*cache
= NULL
, *db
= NULL
;
185 lookup_state_t state
;
186 idmap_retcode retcode
;
190 boolean_t any_tracing
;
193 (void) memset(result
, 0, sizeof (*result
));
194 (void) memset(&state
, 0, sizeof (state
));
196 /* Return success if nothing was requested */
197 if (batch
.idmap_mapping_batch_len
< 1)
200 /* Get cache handle */
201 result
->retcode
= get_cache_handle(&cache
);
202 if (result
->retcode
!= IDMAP_SUCCESS
)
207 result
->retcode
= get_db_handle(&db
);
208 if (result
->retcode
!= IDMAP_SUCCESS
)
212 /* Allocate result array */
213 result
->ids
.ids_val
= calloc(batch
.idmap_mapping_batch_len
,
214 sizeof (idmap_id_res
));
215 if (result
->ids
.ids_val
== NULL
) {
216 idmapdlog(LOG_ERR
, "Out of memory");
217 result
->retcode
= IDMAP_ERR_MEMORY
;
220 result
->ids
.ids_len
= batch
.idmap_mapping_batch_len
;
222 /* Allocate hash table to check for duplicate sids */
223 state
.sid_history
= calloc(batch
.idmap_mapping_batch_len
,
224 sizeof (*state
.sid_history
));
225 if (state
.sid_history
== NULL
) {
226 idmapdlog(LOG_ERR
, "Out of memory");
227 result
->retcode
= IDMAP_ERR_MEMORY
;
230 state
.sid_history_size
= batch
.idmap_mapping_batch_len
;
231 for (i
= 0; i
< state
.sid_history_size
; i
++) {
232 state
.sid_history
[i
].key
= state
.sid_history_size
;
233 state
.sid_history
[i
].next
= state
.sid_history_size
;
235 state
.batch
= &batch
;
236 state
.result
= result
;
238 /* Get directory-based name mapping info */
239 result
->retcode
= load_cfg_in_state(&state
);
240 if (result
->retcode
!= IDMAP_SUCCESS
)
243 /* Init our 'done' flags */
244 state
.sid2pid_done
= state
.pid2sid_done
= TRUE
;
246 any_tracing
= B_FALSE
;
249 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
250 req
= &batch
.idmap_mapping_batch_val
[i
];
251 res
= &result
->ids
.ids_val
[i
];
253 any_tracing
= B_TRUE
;
255 (void) sanitize_mapping_request(req
);
256 TRACE(req
, res
, "Start mapping");
257 if (IS_ID_SID(req
->id1
)) {
258 retcode
= sid2pid_first_pass(
262 } else if (IS_ID_UID(req
->id1
)) {
263 retcode
= pid2sid_first_pass(
267 } else if (IS_ID_GID(req
->id1
)) {
268 retcode
= pid2sid_first_pass(
273 res
->retcode
= IDMAP_ERR_IDTYPE
;
276 if (IDMAP_FATAL_ERROR(retcode
)) {
277 result
->retcode
= retcode
;
282 /* Check if we are done */
283 if (state
.sid2pid_done
== TRUE
&& state
.pid2sid_done
== TRUE
)
287 * native LDAP lookups:
289 * - nldap or mixed mode. Lookup nldap by pid or unixname to get
292 * - nldap mode. Got winname and sid (either given or found in
293 * name_cache). Lookup nldap by winname to get pid and
296 if (state
.nldap_nqueries
) {
297 retcode
= nldap_lookup_batch(&state
, &batch
, result
);
298 if (IDMAP_FATAL_ERROR(retcode
)) {
299 TRACE(req
, res
, "Native LDAP lookup error=%d", retcode
);
300 result
->retcode
= retcode
;
304 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
305 res
= &result
->ids
.ids_val
[i
];
306 req
= &batch
.idmap_mapping_batch_val
[i
];
307 if (IDMAP_ERROR(res
->retcode
)) {
309 "Native LDAP lookup error=%d",
312 TRACE(req
, res
, "Native LDAP lookup");
321 * - nldap or mixed mode. Got winname from nldap lookup.
322 * winname2sid could not be resolved locally. Lookup AD
323 * by winname to get sid.
324 * - ad mode. Got unixname. Lookup AD by unixname to get
327 * - ad or mixed mode. Lookup AD by sid or winname to get
328 * winname, sid and unixname.
329 * - any mode. Got either sid or winname but not both. Lookup
330 * AD by sid or winname to get winname, sid.
332 if (state
.ad_nqueries
) {
333 retcode
= ad_lookup_batch(&state
, &batch
, result
);
334 if (IDMAP_FATAL_ERROR(retcode
)) {
335 TRACE(req
, res
, "AD lookup error=%d", retcode
);
336 result
->retcode
= retcode
;
339 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
340 res
= &result
->ids
.ids_val
[i
];
341 req
= &batch
.idmap_mapping_batch_val
[i
];
342 if (res
->retcode
== IDMAP_ERR_DOMAIN_NOTFOUND
&&
343 req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
&&
344 req
->id1name
!= NULL
) {
346 * If AD lookup failed Domain Not Found but
347 * we have a winname and SID, it means that
349 * - it's a request a cross-forest trust
351 * - we were looking for directory-based
352 * mapping information.
353 * In that case, we're OK, just go on.
355 * If this seems more convoluted than it
356 * should be, it is - really, we probably
357 * shouldn't even be attempting AD lookups
358 * in this situation, but that's a more
359 * intricate cleanup that will have to wait
362 res
->retcode
= IDMAP_SUCCESS
;
364 "AD lookup - domain not found (ignored)");
371 * native LDAP lookups:
373 * - nldap mode. Got winname and sid from AD lookup. Lookup nldap
374 * by winname to get pid and unixname.
376 if (state
.nldap_nqueries
) {
377 retcode
= nldap_lookup_batch(&state
, &batch
, result
);
378 if (IDMAP_FATAL_ERROR(retcode
)) {
379 TRACE(req
, res
, "Native LDAP lookup error=%d", retcode
);
380 result
->retcode
= retcode
;
384 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
385 res
= &result
->ids
.ids_val
[i
];
386 req
= &batch
.idmap_mapping_batch_val
[i
];
387 TRACE(req
, res
, "Native LDAP lookup");
392 /* Reset 'done' flags */
393 state
.sid2pid_done
= state
.pid2sid_done
= TRUE
;
396 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
397 req
= &batch
.idmap_mapping_batch_val
[i
];
398 res
= &result
->ids
.ids_val
[i
];
400 if (IS_ID_SID(req
->id1
)) {
401 retcode
= sid2pid_second_pass(
405 } else if (IS_ID_UID(req
->id1
)) {
406 retcode
= pid2sid_second_pass(
410 } else if (IS_ID_GID(req
->id1
)) {
411 retcode
= pid2sid_second_pass(
416 /* First stage has already set the error */
419 if (IDMAP_FATAL_ERROR(retcode
)) {
420 result
->retcode
= retcode
;
425 /* Check if we are done */
426 if (state
.sid2pid_done
== TRUE
&& state
.pid2sid_done
== TRUE
)
429 /* Reset our 'done' flags */
430 state
.sid2pid_done
= state
.pid2sid_done
= TRUE
;
432 /* Update cache in a single transaction */
433 if (sql_exec_no_cb(cache
, IDMAP_CACHENAME
, "BEGIN TRANSACTION;")
437 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
438 req
= &batch
.idmap_mapping_batch_val
[i
];
439 res
= &result
->ids
.ids_val
[i
];
441 if (IS_ID_SID(req
->id1
)) {
442 (void) update_cache_sid2pid(
446 } else if ((IS_ID_UID(req
->id1
)) ||
447 (IS_ID_GID(req
->id1
))) {
448 (void) update_cache_pid2sid(
455 /* Commit if we have at least one successful update */
456 if (state
.sid2pid_done
== FALSE
|| state
.pid2sid_done
== FALSE
)
457 (void) sql_exec_no_cb(cache
, IDMAP_CACHENAME
,
458 "COMMIT TRANSACTION;");
460 (void) sql_exec_no_cb(cache
, IDMAP_CACHENAME
,
464 cleanup_lookup_state(&state
);
465 if (IDMAP_ERROR(result
->retcode
)) {
467 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
468 req
= &batch
.idmap_mapping_batch_val
[i
];
469 res
= &result
->ids
.ids_val
[i
];
471 "Failure code %d", result
->retcode
);
474 xdr_free(xdr_idmap_ids_res
, (caddr_t
)result
);
475 result
->ids
.ids_len
= 0;
476 result
->ids
.ids_val
= NULL
;
479 for (i
= 0; i
< batch
.idmap_mapping_batch_len
; i
++) {
480 req
= &batch
.idmap_mapping_batch_val
[i
];
481 res
= &result
->ids
.ids_val
[i
];
482 TRACE(req
, res
, "Done");
486 result
->retcode
= idmap_stat4prot(result
->retcode
);
488 for (i
= 0; i
< result
->ids
.ids_len
; i
++) {
489 req
= &batch
.idmap_mapping_batch_val
[i
];
490 res
= &result
->ids
.ids_val
[i
];
492 if (!(req
->flag
& IDMAP_REQ_FLG_MAPPING_INFO
) &&
493 res
->retcode
== IDMAP_SUCCESS
)
494 idmap_how_clear(&res
->info
.how
);
503 list_mappings_cb(void *parg
, int argc
, char **argv
, char **colnames
)
505 list_cb_data_t
*cb_data
;
507 idmap_mappings_res
*result
;
508 idmap_retcode retcode
;
511 static int validated_column_names
= 0;
514 cb_data
= (list_cb_data_t
*)parg
;
516 if (!validated_column_names
) {
517 assert(strcmp(colnames
[0], "rowid") == 0);
518 assert(strcmp(colnames
[1], "sidprefix") == 0);
519 assert(strcmp(colnames
[2], "rid") == 0);
520 assert(strcmp(colnames
[3], "pid") == 0);
521 assert(strcmp(colnames
[4], "w2u") == 0);
522 assert(strcmp(colnames
[5], "u2w") == 0);
523 assert(strcmp(colnames
[6], "windomain") == 0);
524 assert(strcmp(colnames
[7], "canon_winname") == 0);
525 assert(strcmp(colnames
[8], "unixname") == 0);
526 assert(strcmp(colnames
[9], "is_user") == 0);
527 assert(strcmp(colnames
[10], "is_wuser") == 0);
528 assert(strcmp(colnames
[11], "map_type") == 0);
529 assert(strcmp(colnames
[12], "map_dn") == 0);
530 assert(strcmp(colnames
[13], "map_attr") == 0);
531 assert(strcmp(colnames
[14], "map_value") == 0);
532 assert(strcmp(colnames
[15], "map_windomain") == 0);
533 assert(strcmp(colnames
[16], "map_winname") == 0);
534 assert(strcmp(colnames
[17], "map_unixname") == 0);
535 assert(strcmp(colnames
[18], "map_is_nt4") == 0);
536 validated_column_names
= 1;
539 result
= (idmap_mappings_res
*)cb_data
->result
;
541 _VALIDATE_LIST_CB_DATA(19, &result
->mappings
.mappings_val
,
542 sizeof (idmap_mapping
));
544 result
->mappings
.mappings_len
++;
546 if ((str
= strdup(argv
[1])) == NULL
)
548 result
->mappings
.mappings_val
[cb_data
->next
].id1
.idmap_id_u
.sid
.prefix
=
550 result
->mappings
.mappings_val
[cb_data
->next
].id1
.idmap_id_u
.sid
.rid
=
551 strtoul(argv
[2], &end
, 10);
552 result
->mappings
.mappings_val
[cb_data
->next
].id1
.idtype
=
553 strtol(argv
[10], &end
, 10) ? IDMAP_USID
: IDMAP_GSID
;
555 result
->mappings
.mappings_val
[cb_data
->next
].id2
.idmap_id_u
.uid
=
556 strtoul(argv
[3], &end
, 10);
557 result
->mappings
.mappings_val
[cb_data
->next
].id2
.idtype
=
558 strtol(argv
[9], &end
, 10) ? IDMAP_UID
: IDMAP_GID
;
560 w2u
= argv
[4] ? strtol(argv
[4], &end
, 10) : 0;
561 u2w
= argv
[5] ? strtol(argv
[5], &end
, 10) : 0;
563 if (w2u
> 0 && u2w
== 0)
564 result
->mappings
.mappings_val
[cb_data
->next
].direction
=
566 else if (w2u
== 0 && u2w
> 0)
567 result
->mappings
.mappings_val
[cb_data
->next
].direction
=
570 result
->mappings
.mappings_val
[cb_data
->next
].direction
=
573 STRDUP_OR_FAIL(result
->mappings
.mappings_val
[cb_data
->next
].id1domain
,
576 STRDUP_OR_FAIL(result
->mappings
.mappings_val
[cb_data
->next
].id1name
,
579 STRDUP_OR_FAIL(result
->mappings
.mappings_val
[cb_data
->next
].id2name
,
582 if (cb_data
->flag
& IDMAP_REQ_FLG_MAPPING_INFO
) {
583 how
= &result
->mappings
.mappings_val
[cb_data
->next
].info
.how
;
584 how
->map_type
= strtoul(argv
[11], &end
, 10);
585 switch (how
->map_type
) {
586 case IDMAP_MAP_TYPE_DS_AD
:
587 how
->idmap_how_u
.ad
.dn
=
589 how
->idmap_how_u
.ad
.attr
=
591 how
->idmap_how_u
.ad
.value
=
595 case IDMAP_MAP_TYPE_DS_NLDAP
:
596 how
->idmap_how_u
.nldap
.dn
=
598 how
->idmap_how_u
.nldap
.attr
=
600 how
->idmap_how_u
.nldap
.value
=
604 case IDMAP_MAP_TYPE_RULE_BASED
:
605 how
->idmap_how_u
.rule
.windomain
=
607 how
->idmap_how_u
.rule
.winname
=
609 how
->idmap_how_u
.rule
.unixname
=
611 how
->idmap_how_u
.rule
.is_nt4
=
612 strtoul(argv
[18], &end
, 10);
613 how
->idmap_how_u
.rule
.is_user
=
614 strtol(argv
[9], &end
, 10);
615 how
->idmap_how_u
.rule
.is_wuser
=
616 strtol(argv
[10], &end
, 10);
619 case IDMAP_MAP_TYPE_EPHEMERAL
:
622 case IDMAP_MAP_TYPE_LOCAL_SID
:
625 case IDMAP_MAP_TYPE_IDMU
:
626 how
->idmap_how_u
.idmu
.dn
=
628 how
->idmap_how_u
.idmu
.attr
=
630 how
->idmap_how_u
.idmu
.value
=
635 /* Unknown mapping type */
641 result
->lastrowid
= strtoll(argv
[0], &end
, 10);
643 result
->retcode
= IDMAP_SUCCESS
;
650 idmap_list_mappings_1_svc(int64_t lastrowid
, uint64_t limit
, int32_t flag
,
651 idmap_mappings_res
*result
, struct svc_req
*rqstp
)
653 sqlite
*cache
= NULL
;
654 char lbuf
[30], rbuf
[30];
656 idmap_retcode retcode
;
660 (void) memset(result
, 0, sizeof (*result
));
664 if ((curtime
= time(NULL
)) == (time_t)-1) {
665 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
667 retcode
= IDMAP_ERR_INTERNAL
;
672 maxlimit
= _idmapdstate
.cfg
->pgcfg
.list_size_limit
;
675 /* Get cache handle */
676 result
->retcode
= get_cache_handle(&cache
);
677 if (result
->retcode
!= IDMAP_SUCCESS
)
680 result
->retcode
= IDMAP_ERR_INTERNAL
;
682 /* Create LIMIT expression. */
683 if (limit
== 0 || (maxlimit
> 0 && maxlimit
< limit
))
686 (void) snprintf(lbuf
, sizeof (lbuf
),
687 "LIMIT %" PRIu64
, limit
+ 1ULL);
691 (void) snprintf(rbuf
, sizeof (rbuf
), "rowid > %" PRIu64
, lastrowid
);
694 * Combine all the above into a giant SELECT statement that
695 * will return the requested mappings
698 sql
= sqlite_mprintf("SELECT rowid, sidprefix, rid, pid, w2u, "
699 "u2w, windomain, canon_winname, unixname, is_user, is_wuser, "
700 "map_type, map_dn, map_attr, map_value, map_windomain, "
701 "map_winname, map_unixname, map_is_nt4 "
702 "FROM idmap_cache WHERE %s AND "
703 "(pid >= 2147483648 OR (expiration = 0 OR "
704 "expiration ISNULL OR expiration > %d)) "
706 rbuf
, curtime
, lbuf
);
708 result
->retcode
= IDMAP_ERR_MEMORY
;
709 idmapdlog(LOG_ERR
, "Out of memory");
713 /* Execute the SQL statement and update the return buffer */
714 PROCESS_LIST_SVC_SQL(retcode
, cache
, IDMAP_CACHENAME
, sql
, limit
,
715 flag
, list_mappings_cb
, result
, result
->mappings
.mappings_len
);
720 if (IDMAP_ERROR(result
->retcode
))
721 (void) xdr_free(xdr_idmap_mappings_res
, (caddr_t
)result
);
722 result
->retcode
= idmap_stat4prot(result
->retcode
);
730 list_namerules_cb(void *parg
, int argc
, char **argv
, char **colnames
)
732 list_cb_data_t
*cb_data
;
733 idmap_namerules_res
*result
;
734 idmap_retcode retcode
;
735 int w2u_order
, u2w_order
;
737 static int validated_column_names
= 0;
739 if (!validated_column_names
) {
740 assert(strcmp(colnames
[0], "rowid") == 0);
741 assert(strcmp(colnames
[1], "is_user") == 0);
742 assert(strcmp(colnames
[2], "is_wuser") == 0);
743 assert(strcmp(colnames
[3], "windomain") == 0);
744 assert(strcmp(colnames
[4], "winname_display") == 0);
745 assert(strcmp(colnames
[5], "is_nt4") == 0);
746 assert(strcmp(colnames
[6], "unixname") == 0);
747 assert(strcmp(colnames
[7], "w2u_order") == 0);
748 assert(strcmp(colnames
[8], "u2w_order") == 0);
749 validated_column_names
= 1;
752 cb_data
= (list_cb_data_t
*)parg
;
753 result
= (idmap_namerules_res
*)cb_data
->result
;
755 _VALIDATE_LIST_CB_DATA(9, &result
->rules
.rules_val
,
756 sizeof (idmap_namerule
));
758 result
->rules
.rules_len
++;
760 result
->rules
.rules_val
[cb_data
->next
].is_user
=
761 strtol(argv
[1], &end
, 10);
763 result
->rules
.rules_val
[cb_data
->next
].is_wuser
=
764 strtol(argv
[2], &end
, 10);
766 STRDUP_OR_FAIL(result
->rules
.rules_val
[cb_data
->next
].windomain
,
769 STRDUP_OR_FAIL(result
->rules
.rules_val
[cb_data
->next
].winname
,
772 result
->rules
.rules_val
[cb_data
->next
].is_nt4
=
773 strtol(argv
[5], &end
, 10);
775 STRDUP_OR_FAIL(result
->rules
.rules_val
[cb_data
->next
].unixname
,
778 w2u_order
= argv
[7] ? strtol(argv
[7], &end
, 10) : 0;
779 u2w_order
= argv
[8] ? strtol(argv
[8], &end
, 10) : 0;
781 if (w2u_order
> 0 && u2w_order
== 0)
782 result
->rules
.rules_val
[cb_data
->next
].direction
=
784 else if (w2u_order
== 0 && u2w_order
> 0)
785 result
->rules
.rules_val
[cb_data
->next
].direction
=
788 result
->rules
.rules_val
[cb_data
->next
].direction
=
791 result
->lastrowid
= strtoll(argv
[0], &end
, 10);
793 result
->retcode
= IDMAP_SUCCESS
;
800 idmap_list_namerules_1_svc(idmap_namerule rule
, uint64_t lastrowid
,
801 uint64_t limit
, idmap_namerules_res
*result
,
802 struct svc_req
*rqstp
)
806 char lbuf
[30], rbuf
[30];
810 idmap_retcode retcode
;
812 (void) memset(result
, 0, sizeof (*result
));
814 result
->retcode
= validate_rule(&rule
);
815 if (result
->retcode
!= IDMAP_SUCCESS
)
819 maxlimit
= _idmapdstate
.cfg
->pgcfg
.list_size_limit
;
823 result
->retcode
= get_db_handle(&db
);
824 if (result
->retcode
!= IDMAP_SUCCESS
)
827 result
->retcode
= gen_sql_expr_from_rule(&rule
, &expr
);
828 if (result
->retcode
!= IDMAP_SUCCESS
)
831 /* Create LIMIT expression. */
832 if (limit
== 0 || (maxlimit
> 0 && maxlimit
< limit
))
835 (void) snprintf(lbuf
, sizeof (lbuf
),
836 "LIMIT %" PRIu64
, limit
+ 1ULL);
840 (void) snprintf(rbuf
, sizeof (rbuf
), "rowid > %" PRIu64
, lastrowid
);
843 * Combine all the above into a giant SELECT statement that
844 * will return the requested rules
846 sql
= sqlite_mprintf("SELECT rowid, is_user, is_wuser, windomain, "
847 "winname_display, is_nt4, unixname, w2u_order, u2w_order "
848 "FROM namerules WHERE "
853 result
->retcode
= IDMAP_ERR_MEMORY
;
854 idmapdlog(LOG_ERR
, "Out of memory");
858 /* Execute the SQL statement and update the return buffer */
859 PROCESS_LIST_SVC_SQL(retcode
, db
, IDMAP_DBNAME
, sql
, limit
,
860 0, list_namerules_cb
, result
, result
->rules
.rules_len
);
864 sqlite_freemem(expr
);
867 if (IDMAP_ERROR(result
->retcode
))
868 (void) xdr_free(xdr_idmap_namerules_res
, (caddr_t
)result
);
869 result
->retcode
= idmap_stat4prot(result
->retcode
);
873 #define IDMAP_RULES_AUTH "solaris.admin.idmap.rules"
875 verify_rules_auth(struct svc_req
*rqstp
)
882 if (svc_getcallerucred(rqstp
->rq_xprt
, &uc
) != 0) {
883 idmapdlog(LOG_ERR
, "svc_getcallerucred failed during "
884 "authorization (%s)", strerror(errno
));
888 uid
= ucred_geteuid(uc
);
889 if (uid
== (uid_t
)-1) {
890 idmapdlog(LOG_ERR
, "ucred_geteuid failed during "
891 "authorization (%s)", strerror(errno
));
896 if (getpwuid_r(uid
, &pwd
, buf
, sizeof (buf
)) == NULL
) {
897 idmapdlog(LOG_ERR
, "getpwuid_r(%u) failed during "
898 "authorization (%s)", uid
, strerror(errno
));
903 if (chkauthattr(IDMAP_RULES_AUTH
, pwd
.pw_name
) != 1) {
904 idmapdlog(LOG_INFO
, "%s is not authorized (%s)",
905 pwd
.pw_name
, IDMAP_RULES_AUTH
);
915 * Meaning of the return values is the following: For retcode ==
916 * IDMAP_SUCCESS, everything went OK and error_index is
917 * undefined. Otherwise, error_index >=0 shows the failed batch
918 * element. errro_index == -1 indicates failure at the beginning,
919 * error_index == -2 at the end.
924 idmap_update_1_svc(idmap_update_batch batch
, idmap_update_res
*res
,
925 struct svc_req
*rqstp
)
932 res
->error_index
= -1;
933 (void) memset(&res
->error_rule
, 0, sizeof (res
->error_rule
));
934 (void) memset(&res
->conflict_rule
, 0, sizeof (res
->conflict_rule
));
936 if (verify_rules_auth(rqstp
) < 0) {
937 res
->retcode
= IDMAP_ERR_PERMISSION_DENIED
;
941 if (batch
.idmap_update_batch_len
== 0 ||
942 batch
.idmap_update_batch_val
== NULL
) {
943 res
->retcode
= IDMAP_SUCCESS
;
947 res
->retcode
= validate_rules(&batch
);
948 if (res
->retcode
!= IDMAP_SUCCESS
)
952 res
->retcode
= get_db_handle(&db
);
953 if (res
->retcode
!= IDMAP_SUCCESS
)
956 res
->retcode
= sql_exec_no_cb(db
, IDMAP_DBNAME
, "BEGIN TRANSACTION;");
957 if (res
->retcode
!= IDMAP_SUCCESS
)
961 for (i
= 0; i
< batch
.idmap_update_batch_len
; i
++) {
962 up
= &batch
.idmap_update_batch_val
[i
];
965 res
->retcode
= IDMAP_SUCCESS
;
967 case OP_ADD_NAMERULE
:
968 res
->retcode
= add_namerule(db
,
969 &up
->idmap_update_op_u
.rule
);
972 res
->retcode
= rm_namerule(db
,
973 &up
->idmap_update_op_u
.rule
);
975 case OP_FLUSH_NAMERULES
:
976 res
->retcode
= flush_namerules(db
);
979 res
->retcode
= IDMAP_ERR_NOTSUPPORTED
;
983 if (res
->retcode
!= IDMAP_SUCCESS
) {
984 res
->error_index
= i
;
985 if (up
->opnum
== OP_ADD_NAMERULE
||
986 up
->opnum
== OP_RM_NAMERULE
) {
988 idmap_namerule_cpy(&res
->error_rule
,
989 &up
->idmap_update_op_u
.rule
);
990 if (r2
!= IDMAP_SUCCESS
)
999 if (res
->retcode
== IDMAP_SUCCESS
) {
1001 sql_exec_no_cb(db
, IDMAP_DBNAME
,
1002 "COMMIT TRANSACTION;");
1003 if (res
->retcode
== IDMAP_SUCCESS
) {
1005 * We've updated the rules. Expire the cache
1006 * so that existing mappings will be
1010 idmap_cache_flush(IDMAP_FLUSH_EXPIRE
);
1012 res
->error_index
= -2;
1016 (void) sql_exec_no_cb(db
, IDMAP_DBNAME
,
1017 "ROLLBACK TRANSACTION;");
1020 res
->retcode
= idmap_stat4prot(res
->retcode
);
1027 copy_string(char **to
, char *from
)
1029 if (EMPTY_STRING(from
)) {
1034 idmapdlog(LOG_ERR
, "Out of memory");
1035 return (IDMAP_ERR_MEMORY
);
1038 return (IDMAP_SUCCESS
);
1043 copy_id(idmap_id
*to
, idmap_id
*from
)
1045 (void) memset(to
, 0, sizeof (*to
));
1047 to
->idtype
= from
->idtype
;
1048 if (IS_ID_SID(*from
)) {
1049 idmap_retcode retcode
;
1051 to
->idmap_id_u
.sid
.rid
= from
->idmap_id_u
.sid
.rid
;
1052 retcode
= copy_string(&to
->idmap_id_u
.sid
.prefix
,
1053 from
->idmap_id_u
.sid
.prefix
);
1057 to
->idmap_id_u
.uid
= from
->idmap_id_u
.uid
;
1058 return (IDMAP_SUCCESS
);
1064 copy_mapping(idmap_mapping
*mapping
, idmap_mapping
*request
)
1066 idmap_retcode retcode
;
1068 (void) memset(mapping
, 0, sizeof (*mapping
));
1070 mapping
->flag
= request
->flag
;
1071 mapping
->direction
= _IDMAP_F_DONE
;
1073 retcode
= copy_id(&mapping
->id1
, &request
->id1
);
1074 if (retcode
!= IDMAP_SUCCESS
)
1077 retcode
= copy_string(&mapping
->id1domain
, request
->id1domain
);
1078 if (retcode
!= IDMAP_SUCCESS
)
1081 retcode
= copy_string(&mapping
->id1name
, request
->id1name
);
1082 if (retcode
!= IDMAP_SUCCESS
)
1085 retcode
= copy_id(&mapping
->id2
, &request
->id2
);
1086 if (retcode
!= IDMAP_SUCCESS
)
1089 retcode
= copy_string(&mapping
->id2domain
, request
->id2domain
);
1090 if (retcode
!= IDMAP_SUCCESS
)
1092 retcode
= copy_string(&mapping
->id2name
, request
->id2name
);
1093 if (retcode
!= IDMAP_SUCCESS
)
1096 return (IDMAP_SUCCESS
);
1099 if (IS_ID_SID(mapping
->id1
))
1100 free(mapping
->id1
.idmap_id_u
.sid
.prefix
);
1101 free(mapping
->id1domain
);
1102 free(mapping
->id1name
);
1103 if (IS_ID_SID(mapping
->id2
))
1104 free(mapping
->id2
.idmap_id_u
.sid
.prefix
);
1105 free(mapping
->id2domain
);
1106 free(mapping
->id2name
);
1108 (void) memset(mapping
, 0, sizeof (*mapping
));
1115 idmap_get_mapped_id_by_name_1_svc(idmap_mapping request
,
1116 idmap_mappings_res
*result
, struct svc_req
*rqstp
)
1118 idmap_mapping_batch batch_request
;
1119 idmap_ids_res batch_result
;
1122 /* Clear out things we might want to xdr_free on error */
1123 (void) memset(&batch_result
, 0, sizeof (batch_result
));
1124 (void) memset(result
, 0, sizeof (*result
));
1126 result
->retcode
= validate_mapped_id_by_name_req(&request
);
1127 if (result
->retcode
!= IDMAP_SUCCESS
)
1131 * Copy the request. We need to modify it, and
1132 * what we have is a shallow copy. Freeing pointers from
1133 * our copy will lead to problems, since the RPC framework
1134 * has its own copy of those pointers. Besides, we need
1137 map
= calloc(1, sizeof (idmap_mapping
));
1139 idmapdlog(LOG_ERR
, "Out of memory");
1140 result
->retcode
= IDMAP_ERR_MEMORY
;
1145 * Set up to return the filled-in mapping structure.
1146 * Note that we xdr_free result on error, and that'll take
1147 * care of freeing the mapping structure.
1149 result
->mappings
.mappings_val
= map
;
1150 result
->mappings
.mappings_len
= 1;
1152 result
->retcode
= copy_mapping(map
, &request
);
1153 if (result
->retcode
!= IDMAP_SUCCESS
)
1156 /* Set up for the request to the batch API */
1157 batch_request
.idmap_mapping_batch_val
= map
;
1158 batch_request
.idmap_mapping_batch_len
= 1;
1160 /* Do the real work. */
1161 (void) idmap_get_mapped_ids_1_svc(batch_request
,
1162 &batch_result
, rqstp
);
1164 /* Copy what we need out of the batch response */
1166 if (batch_result
.retcode
!= IDMAP_SUCCESS
) {
1167 result
->retcode
= batch_result
.retcode
;
1171 result
->retcode
= copy_id(&map
->id2
, &batch_result
.ids
.ids_val
[0].id
);
1172 if (result
->retcode
!= IDMAP_SUCCESS
)
1175 map
->direction
= batch_result
.ids
.ids_val
[0].direction
;
1177 result
->retcode
= batch_result
.ids
.ids_val
[0].retcode
;
1179 idmap_info_mov(&map
->info
, &batch_result
.ids
.ids_val
[0].info
);
1182 if (IDMAP_FATAL_ERROR(result
->retcode
)) {
1183 xdr_free(xdr_idmap_mappings_res
, (caddr_t
)result
);
1184 result
->mappings
.mappings_len
= 0;
1185 result
->mappings
.mappings_val
= NULL
;
1187 result
->retcode
= idmap_stat4prot(result
->retcode
);
1189 xdr_free(xdr_idmap_ids_res
, (char *)&batch_result
);
1196 idmap_get_prop_1_svc(idmap_prop_type request
,
1197 idmap_prop_res
*result
, struct svc_req
*rqstp
)
1199 idmap_pg_config_t
*pgcfg
;
1202 (void) memset(result
, 0, sizeof (*result
));
1203 result
->retcode
= IDMAP_SUCCESS
;
1204 result
->value
.prop
= request
;
1208 /* Just shortcuts: */
1209 pgcfg
= &_idmapdstate
.cfg
->pgcfg
;
1213 case PROP_LIST_SIZE_LIMIT
:
1214 result
->value
.idmap_prop_val_u
.intval
= pgcfg
->list_size_limit
;
1215 result
->auto_discovered
= FALSE
;
1217 case PROP_DEFAULT_DOMAIN
:
1218 result
->auto_discovered
= FALSE
;
1219 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1220 pgcfg
->default_domain
);
1222 case PROP_DOMAIN_NAME
:
1223 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1224 pgcfg
->domain_name
);
1225 result
->auto_discovered
=
1226 pgcfg
->domain_name_auto_disc
;
1228 case PROP_MACHINE_SID
:
1229 result
->auto_discovered
= FALSE
;
1230 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1231 pgcfg
->machine_sid
);
1233 case PROP_DOMAIN_CONTROLLER
:
1234 if (pgcfg
->domain_controller
!= NULL
) {
1235 (void) memcpy(&result
->value
.idmap_prop_val_u
.dsval
,
1236 pgcfg
->domain_controller
,
1237 sizeof (idmap_ad_disc_ds_t
));
1239 result
->auto_discovered
= pgcfg
->domain_controller_auto_disc
;
1241 case PROP_FOREST_NAME
:
1242 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1243 pgcfg
->forest_name
);
1244 result
->auto_discovered
= pgcfg
->forest_name_auto_disc
;
1246 case PROP_SITE_NAME
:
1247 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1249 result
->auto_discovered
= pgcfg
->site_name_auto_disc
;
1251 case PROP_GLOBAL_CATALOG
:
1252 if (pgcfg
->global_catalog
!= NULL
) {
1253 (void) memcpy(&result
->value
.idmap_prop_val_u
.dsval
,
1254 pgcfg
->global_catalog
, sizeof (idmap_ad_disc_ds_t
));
1256 result
->auto_discovered
= pgcfg
->global_catalog_auto_disc
;
1258 case PROP_AD_UNIXUSER_ATTR
:
1259 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1260 pgcfg
->ad_unixuser_attr
);
1261 result
->auto_discovered
= FALSE
;
1263 case PROP_AD_UNIXGROUP_ATTR
:
1264 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1265 pgcfg
->ad_unixgroup_attr
);
1266 result
->auto_discovered
= FALSE
;
1268 case PROP_NLDAP_WINNAME_ATTR
:
1269 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1270 pgcfg
->nldap_winname_attr
);
1271 result
->auto_discovered
= FALSE
;
1273 case PROP_DIRECTORY_BASED_MAPPING
:
1274 STRDUP_CHECK(result
->value
.idmap_prop_val_u
.utf8val
,
1275 enum_lookup(pgcfg
->directory_based_mapping
,
1276 directory_mapping_map
));
1277 result
->auto_discovered
= FALSE
;
1280 result
->retcode
= IDMAP_ERR_PROP_UNKNOWN
;
1286 if (IDMAP_FATAL_ERROR(result
->retcode
)) {
1287 xdr_free(xdr_idmap_prop_res
, (caddr_t
)result
);
1288 result
->value
.prop
= PROP_UNKNOWN
;
1290 result
->retcode
= idmap_stat4prot(result
->retcode
);
1297 idmap_retcode
*result
,
1298 struct svc_req
*rqstp
)
1300 NOTE(ARGUNUSED(rqstp
))
1301 if (verify_rules_auth(rqstp
) < 0) {
1302 *result
= IDMAP_ERR_PERMISSION_DENIED
;
1306 *result
= idmap_cache_flush(op
);
1313 idmap_prog_1_freeresult(SVCXPRT
*transp
, xdrproc_t xdr_result
,
1316 (void) xdr_free(xdr_result
, result
);
1321 * This function is called by rpc_svc.c when it encounters an error.
1325 idmap_rpc_msgout(const char *fmt
, ...)
1331 (void) vsnprintf(buf
, sizeof (buf
), fmt
, va
);
1334 idmapdlog(LOG_ERR
, "idmap RPC: %s", buf
);