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.
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
27 * Database related utility routines
34 #include <sys/types.h>
43 #include <sys/u8_textprep.h>
51 #include "idmap_priv.h"
53 #include "nldaputils.h"
54 #include "idmap_lsa.h"
57 static idmap_retcode
sql_compile_n_step_once(sqlite
*, char *,
58 sqlite_vm
**, int *, int, const char ***);
59 static idmap_retcode
lookup_localsid2pid(idmap_mapping
*, idmap_id_res
*);
60 static idmap_retcode
lookup_cache_name2sid(sqlite
*, const char *,
61 const char *, char **, char **, idmap_rid_t
*, idmap_id_type
*);
63 #define EMPTY_NAME(name) (*name == 0 || strcmp(name, "\"\"") == 0)
65 #define DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
66 (req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
68 #define AVOID_NAMESERVICE(req)\
69 (req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
71 #define ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)\
72 (req->flag & IDMAP_REQ_FLG_WK_OR_LOCAL_SIDS_ONLY)
74 typedef enum init_db_option
{
80 * Thread specific data to hold the database handles so that the
81 * databases are not opened and closed for every request. It also
82 * contains the sqlite busy handler structure.
94 typedef struct idmap_tsd
{
97 struct idmap_busy cache_busy
;
98 struct idmap_busy db_busy
;
102 * Flags to indicate how local the directory we're consulting is.
103 * If neither is set, it means the directory belongs to a remote forest.
105 #define DOMAIN_IS_LOCAL 0x01
106 #define FOREST_IS_LOCAL 0x02
108 static const int cache_delay_table
[] =
109 { 1, 2, 5, 10, 15, 20, 25, 30, 35, 40,
110 50, 50, 60, 70, 80, 90, 100};
112 static const int db_delay_table
[] =
113 { 5, 10, 15, 20, 30, 40, 55, 70, 100};
116 static pthread_key_t idmap_tsd_key
;
119 idmap_tsd_destroy(void *key
)
122 idmap_tsd_t
*tsd
= (idmap_tsd_t
*)key
;
125 (void) sqlite_close(tsd
->db_db
);
127 (void) sqlite_close(tsd
->cache_db
);
133 idmap_init_tsd_key(void)
137 rc
= pthread_key_create(&idmap_tsd_key
, idmap_tsd_destroy
);
148 if ((tsd
= pthread_getspecific(idmap_tsd_key
)) == NULL
) {
149 /* No thread specific data so create it */
150 if ((tsd
= malloc(sizeof (*tsd
))) != NULL
) {
151 /* Initialize thread specific data */
152 (void) memset(tsd
, 0, sizeof (*tsd
));
153 /* save the trhread specific data */
154 if (pthread_setspecific(idmap_tsd_key
, tsd
) != 0) {
155 /* Can't store key */
168 * A simple wrapper around u8_textprep_str() that returns the Unicode
169 * lower-case version of some string. The result must be freed.
172 tolower_u8(const char *s
)
176 size_t inlen
, outlen
, inbytesleft
, outbytesleft
;
180 * u8_textprep_str() does not allocate memory. The input and
181 * output buffers may differ in size (though that would be more
182 * likely when normalization is done). We have to loop over it...
184 * To improve the chances that we can avoid looping we add 10
185 * bytes of output buffer room the first go around.
187 inlen
= inbytesleft
= strlen(s
);
188 outlen
= outbytesleft
= inlen
+ 10;
189 if ((res
= malloc(outlen
)) == NULL
)
193 while ((rc
= u8_textprep_str((char *)s
, &inbytesleft
, outs
,
194 &outbytesleft
, U8_TEXTPREP_TOLOWER
, U8_UNICODE_LATEST
, &err
)) < 0 &&
196 if ((res
= realloc(res
, outlen
+ inbytesleft
)) == NULL
)
198 /* adjust input/output buffer pointers */
199 s
+= (inlen
- inbytesleft
);
200 outs
= res
+ outlen
- outbytesleft
;
201 /* adjust outbytesleft and outlen */
202 outlen
+= inbytesleft
;
203 outbytesleft
+= inbytesleft
;
212 res
[outlen
- outbytesleft
] = '\0';
217 static int sql_exec_tran_no_cb(sqlite
*db
, char *sql
, const char *dbname
,
218 const char *while_doing
);
222 * Initialize 'dbname' using 'sql'
226 init_db_instance(const char *dbname
, int version
,
227 const char *detect_version_sql
, char * const *sql
,
228 init_db_option_t opt
, int *created
, int *upgraded
)
230 int rc
, curr_version
;
232 int prio
= LOG_NOTICE
;
239 if (opt
== REMOVE_IF_CORRUPT
)
244 idmapdlog(LOG_ERR
, "Failed to initialize db %s", dbname
);
248 /* Last try, log errors */
251 db
= sqlite_open(dbname
, 0600, &errmsg
);
253 idmapdlog(prio
, "Error creating database %s (%s)",
254 dbname
, CHECK_NULL(errmsg
));
255 sqlite_freemem(errmsg
);
256 if (opt
== REMOVE_IF_CORRUPT
)
257 (void) unlink(dbname
);
261 sqlite_busy_timeout(db
, 3000);
263 /* Detect current version of schema in the db, if any */
265 if (detect_version_sql
!= NULL
) {
266 char *end
, **results
;
270 (void) fprintf(stderr
, "Schema version detection SQL: %s\n",
272 #endif /* IDMAPD_DEBUG */
273 rc
= sqlite_get_table(db
, detect_version_sql
, &results
,
274 &nrow
, NULL
, &errmsg
);
275 if (rc
!= SQLITE_OK
) {
277 "Error detecting schema version of db %s (%s)",
279 sqlite_freemem(errmsg
);
280 sqlite_free_table(results
);
286 "Error detecting schema version of db %s", dbname
);
288 sqlite_free_table(results
);
291 curr_version
= strtol(results
[1], &end
, 10);
292 sqlite_free_table(results
);
295 if (curr_version
< 0) {
296 if (opt
== REMOVE_IF_CORRUPT
)
297 (void) unlink(dbname
);
301 if (curr_version
== version
)
304 /* Install or upgrade schema */
306 (void) fprintf(stderr
, "Schema init/upgrade SQL: %s\n",
308 #endif /* IDMAPD_DEBUG */
309 rc
= sql_exec_tran_no_cb(db
, sql
[curr_version
], dbname
,
310 (curr_version
== 0) ? "installing schema" : "upgrading schema");
312 idmapdlog(prio
, "Error %s schema for db %s", dbname
,
313 (curr_version
== 0) ? "installing schema" :
315 if (opt
== REMOVE_IF_CORRUPT
)
316 (void) unlink(dbname
);
320 *upgraded
= (curr_version
> 0);
321 *created
= (curr_version
== 0);
324 (void) sqlite_close(db
);
330 * This is the SQLite database busy handler that retries the SQL
331 * operation until it is successful.
334 /* LINTED E_FUNC_ARG_UNUSED */
335 idmap_sqlite_busy_handler(void *arg
, const char *table_name
, int count
)
337 struct idmap_busy
*busy
= arg
;
339 struct timespec rqtp
;
345 if (busy
->total
> 1000 * busy
->sec
) {
347 "Thread %d waited %d sec for the %s database",
348 pthread_self(), busy
->sec
, busy
->name
);
352 if (count
<= busy
->delay_size
) {
353 delay
= busy
->delays
[count
-1];
355 delay
= busy
->delays
[busy
->delay_size
- 1];
357 busy
->total
+= delay
;
359 rqtp
.tv_nsec
= MSEC2NSEC(delay
);
360 (void) nanosleep(&rqtp
, NULL
);
366 * Get the database handle
369 get_db_handle(sqlite
**db
)
375 * Retrieve the db handle from thread-specific storage
376 * If none exists, open and store in thread-specific storage.
378 if ((tsd
= idmap_get_tsd()) == NULL
) {
380 "Error getting thread specific data for %s", IDMAP_DBNAME
);
381 return (IDMAP_ERR_MEMORY
);
384 if (tsd
->db_db
== NULL
) {
385 tsd
->db_db
= sqlite_open(IDMAP_DBNAME
, 0, &errmsg
);
386 if (tsd
->db_db
== NULL
) {
387 idmapdlog(LOG_ERR
, "Error opening database %s (%s)",
388 IDMAP_DBNAME
, CHECK_NULL(errmsg
));
389 sqlite_freemem(errmsg
);
390 return (IDMAP_ERR_DB
);
393 tsd
->db_busy
.name
= IDMAP_DBNAME
;
394 tsd
->db_busy
.delays
= db_delay_table
;
395 tsd
->db_busy
.delay_size
= sizeof (db_delay_table
) /
397 sqlite_busy_handler(tsd
->db_db
, idmap_sqlite_busy_handler
,
401 return (IDMAP_SUCCESS
);
405 * Get the cache handle
408 get_cache_handle(sqlite
**cache
)
414 * Retrieve the db handle from thread-specific storage
415 * If none exists, open and store in thread-specific storage.
417 if ((tsd
= idmap_get_tsd()) == NULL
) {
418 idmapdlog(LOG_ERR
, "Error getting thread specific data for %s",
420 return (IDMAP_ERR_MEMORY
);
423 if (tsd
->cache_db
== NULL
) {
424 tsd
->cache_db
= sqlite_open(IDMAP_CACHENAME
, 0, &errmsg
);
425 if (tsd
->cache_db
== NULL
) {
426 idmapdlog(LOG_ERR
, "Error opening database %s (%s)",
427 IDMAP_CACHENAME
, CHECK_NULL(errmsg
));
428 sqlite_freemem(errmsg
);
429 return (IDMAP_ERR_DB
);
432 tsd
->cache_busy
.name
= IDMAP_CACHENAME
;
433 tsd
->cache_busy
.delays
= cache_delay_table
;
434 tsd
->cache_busy
.delay_size
= sizeof (cache_delay_table
) /
436 sqlite_busy_handler(tsd
->cache_db
, idmap_sqlite_busy_handler
,
439 *cache
= tsd
->cache_db
;
440 return (IDMAP_SUCCESS
);
444 * Initialize cache and db
450 int created
, upgraded
;
452 /* name-based mappings; probably OK to blow away in a pinch(?) */
453 sql
[0] = DB_INSTALL_SQL
;
454 sql
[1] = DB_UPGRADE_FROM_v1_SQL
;
457 if (init_db_instance(IDMAP_DBNAME
, DB_VERSION
, DB_VERSION_SQL
, sql
,
458 FAIL_IF_CORRUPT
, &created
, &upgraded
) < 0)
461 /* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
462 sql
[0] = CACHE_INSTALL_SQL
;
463 sql
[1] = CACHE_UPGRADE_FROM_v1_SQL
;
464 sql
[2] = CACHE_UPGRADE_FROM_v2_SQL
;
467 if (init_db_instance(IDMAP_CACHENAME
, CACHE_VERSION
, CACHE_VERSION_SQL
,
468 sql
, REMOVE_IF_CORRUPT
, &created
, &upgraded
) < 0)
471 _idmapdstate
.new_eph_db
= (created
|| upgraded
) ? 1 : 0;
485 * This table is a listing of status codes that will be returned to the
486 * client when a SQL command fails with the corresponding error message.
488 static msg_table_t sqlmsgtable
[] = {
489 {IDMAP_ERR_U2W_NAMERULE_CONFLICT
,
490 "columns unixname, is_user, u2w_order are not unique"},
491 {IDMAP_ERR_W2U_NAMERULE_CONFLICT
,
492 "columns winname, windomain, is_user, is_wuser, w2u_order are not"
494 {IDMAP_ERR_W2U_NAMERULE_CONFLICT
, "Conflicting w2u namerules"},
499 * idmapd's version of string2stat to map SQLite messages to
503 idmapd_string2stat(const char *msg
)
506 for (i
= 0; sqlmsgtable
[i
].msg
; i
++) {
507 if (strcasecmp(sqlmsgtable
[i
].msg
, msg
) == 0)
508 return (sqlmsgtable
[i
].retcode
);
510 return (IDMAP_ERR_OTHER
);
514 * Executes some SQL in a transaction.
516 * Returns 0 on success, -1 if it failed but the rollback succeeded, -2
517 * if the rollback failed.
521 sql_exec_tran_no_cb(sqlite
*db
, char *sql
, const char *dbname
,
522 const char *while_doing
)
527 rc
= sqlite_exec(db
, "BEGIN TRANSACTION;", NULL
, NULL
, &errmsg
);
528 if (rc
!= SQLITE_OK
) {
529 idmapdlog(LOG_ERR
, "Begin transaction failed (%s) "
530 "while %s (%s)", errmsg
, while_doing
, dbname
);
531 sqlite_freemem(errmsg
);
535 rc
= sqlite_exec(db
, sql
, NULL
, NULL
, &errmsg
);
536 if (rc
!= SQLITE_OK
) {
537 idmapdlog(LOG_ERR
, "Database error (%s) while %s (%s)", errmsg
,
538 while_doing
, dbname
);
539 sqlite_freemem(errmsg
);
544 rc
= sqlite_exec(db
, "COMMIT TRANSACTION", NULL
, NULL
, &errmsg
);
545 if (rc
== SQLITE_OK
) {
546 sqlite_freemem(errmsg
);
550 idmapdlog(LOG_ERR
, "Database commit error (%s) while s (%s)",
551 errmsg
, while_doing
, dbname
);
552 sqlite_freemem(errmsg
);
556 rc
= sqlite_exec(db
, "ROLLBACK TRANSACTION", NULL
, NULL
, &errmsg
);
557 if (rc
!= SQLITE_OK
) {
558 idmapdlog(LOG_ERR
, "Rollback failed (%s) while %s (%s)",
559 errmsg
, while_doing
, dbname
);
560 sqlite_freemem(errmsg
);
563 sqlite_freemem(errmsg
);
569 * Execute the given SQL statment without using any callbacks
572 sql_exec_no_cb(sqlite
*db
, const char *dbname
, char *sql
)
576 idmap_retcode retcode
;
578 r
= sqlite_exec(db
, sql
, NULL
, NULL
, &errmsg
);
579 assert(r
!= SQLITE_LOCKED
&& r
!= SQLITE_BUSY
);
581 if (r
!= SQLITE_OK
) {
582 idmapdlog(LOG_ERR
, "Database error on %s while executing %s "
583 "(%s)", dbname
, sql
, CHECK_NULL(errmsg
));
584 retcode
= idmapd_string2stat(errmsg
);
586 sqlite_freemem(errmsg
);
590 return (IDMAP_SUCCESS
);
594 * Generate expression that can be used in WHERE statements.
596 * <prefix> <col> <op> <value> <suffix>
597 * "" "unixuser" "=" "foo" "AND"
600 gen_sql_expr_from_rule(idmap_namerule
*rule
, char **out
)
602 char *s_windomain
= NULL
, *s_winname
= NULL
;
603 char *s_unixname
= NULL
;
606 int retcode
= IDMAP_SUCCESS
;
609 return (IDMAP_ERR_ARG
);
612 if (!EMPTY_STRING(rule
->windomain
)) {
613 s_windomain
= sqlite_mprintf("AND windomain = %Q ",
615 if (s_windomain
== NULL
) {
616 retcode
= IDMAP_ERR_MEMORY
;
621 if (!EMPTY_STRING(rule
->winname
)) {
622 if ((lower_winname
= tolower_u8(rule
->winname
)) == NULL
)
623 lower_winname
= rule
->winname
;
624 s_winname
= sqlite_mprintf(
625 "AND winname = %Q AND is_wuser = %d ",
626 lower_winname
, rule
->is_wuser
? 1 : 0);
627 if (lower_winname
!= rule
->winname
)
629 if (s_winname
== NULL
) {
630 retcode
= IDMAP_ERR_MEMORY
;
635 if (!EMPTY_STRING(rule
->unixname
)) {
636 s_unixname
= sqlite_mprintf(
637 "AND unixname = %Q AND is_user = %d ",
638 rule
->unixname
, rule
->is_user
? 1 : 0);
639 if (s_unixname
== NULL
) {
640 retcode
= IDMAP_ERR_MEMORY
;
645 switch (rule
->direction
) {
646 case IDMAP_DIRECTION_BI
:
647 dir
= "AND w2u_order > 0 AND u2w_order > 0";
649 case IDMAP_DIRECTION_W2U
:
650 dir
= "AND w2u_order > 0"
651 " AND (u2w_order = 0 OR u2w_order ISNULL)";
653 case IDMAP_DIRECTION_U2W
:
654 dir
= "AND u2w_order > 0"
655 " AND (w2u_order = 0 OR w2u_order ISNULL)";
662 *out
= sqlite_mprintf("%s %s %s %s",
663 s_windomain
? s_windomain
: "",
664 s_winname
? s_winname
: "",
665 s_unixname
? s_unixname
: "",
669 retcode
= IDMAP_ERR_MEMORY
;
670 idmapdlog(LOG_ERR
, "Out of memory");
675 if (s_windomain
!= NULL
)
676 sqlite_freemem(s_windomain
);
677 if (s_winname
!= NULL
)
678 sqlite_freemem(s_winname
);
679 if (s_unixname
!= NULL
)
680 sqlite_freemem(s_unixname
);
688 * Generate and execute SQL statement for LIST RPC calls
691 process_list_svc_sql(sqlite
*db
, const char *dbname
, char *sql
, uint64_t limit
,
692 int flag
, list_svc_cb cb
, void *result
)
694 list_cb_data_t cb_data
;
697 idmap_retcode retcode
= IDMAP_ERR_INTERNAL
;
699 (void) memset(&cb_data
, 0, sizeof (cb_data
));
700 cb_data
.result
= result
;
701 cb_data
.limit
= limit
;
705 r
= sqlite_exec(db
, sql
, cb
, &cb_data
, &errmsg
);
706 assert(r
!= SQLITE_LOCKED
&& r
!= SQLITE_BUSY
);
709 retcode
= IDMAP_SUCCESS
;
713 retcode
= IDMAP_ERR_INTERNAL
;
714 idmapdlog(LOG_ERR
, "Database error on %s while executing "
715 "%s (%s)", dbname
, sql
, CHECK_NULL(errmsg
));
719 sqlite_freemem(errmsg
);
724 * This routine is called by callbacks that process the results of
725 * LIST RPC calls to validate data and to allocate memory for
729 validate_list_cb_data(list_cb_data_t
*cb_data
, int argc
, char **argv
,
730 int ncol
, uchar_t
**list
, size_t valsize
)
735 if (cb_data
->limit
> 0 && cb_data
->next
== cb_data
->limit
)
738 if (argc
< ncol
|| argv
== NULL
) {
739 idmapdlog(LOG_ERR
, "Invalid data");
740 return (IDMAP_ERR_INTERNAL
);
743 /* alloc in bulk to reduce number of reallocs */
744 if (cb_data
->next
>= cb_data
->len
) {
745 nsize
= (cb_data
->len
+ SIZE_INCR
) * valsize
;
746 tmplist
= realloc(*list
, nsize
);
747 if (tmplist
== NULL
) {
748 idmapdlog(LOG_ERR
, "Out of memory");
749 return (IDMAP_ERR_MEMORY
);
752 (void) memset(*list
+ (cb_data
->len
* valsize
), 0,
753 SIZE_INCR
* valsize
);
754 cb_data
->len
+= SIZE_INCR
;
756 return (IDMAP_SUCCESS
);
761 get_namerule_order(char *winname
, char *windomain
, char *unixname
,
762 int direction
, int is_diagonal
, int *w2u_order
, int *u2w_order
)
768 * Windows to UNIX lookup order:
769 * 1. winname@domain (or winname) to ""
770 * 2. winname@domain (or winname) to unixname
772 * 4. winname@* to unixname
773 * 5. *@domain (or *) to *
774 * 6. *@domain (or *) to ""
775 * 7. *@domain (or *) to unixname
778 * 10. *@* to unixname
780 * winname is a special case of winname@domain when domain is the
781 * default domain. Similarly * is a special case of *@domain when
782 * domain is the default domain.
784 * Note that "" has priority over specific names because "" inhibits
785 * mappings and traditionally deny rules always had higher priority.
787 if (direction
!= IDMAP_DIRECTION_U2W
) {
788 /* bi-directional or from windows to unix */
790 return (IDMAP_ERR_W2U_NAMERULE
);
791 else if (unixname
== NULL
)
792 return (IDMAP_ERR_W2U_NAMERULE
);
793 else if (EMPTY_NAME(winname
))
794 return (IDMAP_ERR_W2U_NAMERULE
);
795 else if (*winname
== '*' && windomain
&& *windomain
== '*') {
796 if (*unixname
== '*')
798 else if (EMPTY_NAME(unixname
))
800 else /* unixname == name */
802 } else if (*winname
== '*') {
803 if (*unixname
== '*')
805 else if (EMPTY_NAME(unixname
))
809 } else if (windomain
!= NULL
&& *windomain
== '*') {
810 /* winname == name */
811 if (*unixname
== '*')
812 return (IDMAP_ERR_W2U_NAMERULE
);
813 else if (EMPTY_NAME(unixname
))
818 /* winname == name && windomain == null or name */
819 if (*unixname
== '*')
820 return (IDMAP_ERR_W2U_NAMERULE
);
821 else if (EMPTY_NAME(unixname
))
830 * 1. unixname to "", non-diagonal
831 * 2. unixname to winname@domain (or winname), non-diagonal
832 * 3. unixname to "", diagonal
833 * 4. unixname to winname@domain (or winname), diagonal
834 * 5. * to *@domain (or *), non-diagonal
835 * 5. * to *@domain (or *), diagonal
837 * 8. * to winname@domain (or winname)
838 * 9. * to "", non-diagonal
839 * 10. * to winname@domain (or winname), diagonal
841 if (direction
!= IDMAP_DIRECTION_W2U
) {
842 int diagonal
= is_diagonal
? 1 : 0;
844 /* bi-directional or from unix to windows */
845 if (unixname
== NULL
|| EMPTY_NAME(unixname
))
846 return (IDMAP_ERR_U2W_NAMERULE
);
847 else if (winname
== NULL
)
848 return (IDMAP_ERR_U2W_NAMERULE
);
849 else if (windomain
!= NULL
&& *windomain
== '*')
850 return (IDMAP_ERR_U2W_NAMERULE
);
851 else if (*unixname
== '*') {
853 *u2w_order
= 5 + diagonal
;
854 else if (EMPTY_NAME(winname
))
855 *u2w_order
= 7 + 2 * diagonal
;
857 *u2w_order
= 8 + 2 * diagonal
;
860 return (IDMAP_ERR_U2W_NAMERULE
);
861 else if (EMPTY_NAME(winname
))
862 *u2w_order
= 1 + 2 * diagonal
;
864 *u2w_order
= 2 + 2 * diagonal
;
867 return (IDMAP_SUCCESS
);
871 * Generate and execute SQL statement to add name-based mapping rule
874 add_namerule(sqlite
*db
, idmap_namerule
*rule
)
880 int w2u_order
, u2w_order
;
881 char w2ubuf
[11], u2wbuf
[11];
882 char *canonname
= NULL
;
883 char *canondomain
= NULL
;
885 retcode
= get_namerule_order(rule
->winname
, rule
->windomain
,
886 rule
->unixname
, rule
->direction
,
887 rule
->is_user
== rule
->is_wuser
? 0 : 1, &w2u_order
, &u2w_order
);
888 if (retcode
!= IDMAP_SUCCESS
)
892 (void) snprintf(w2ubuf
, sizeof (w2ubuf
), "%d", w2u_order
);
894 (void) snprintf(u2wbuf
, sizeof (u2wbuf
), "%d", u2w_order
);
897 * For the triggers on namerules table to work correctly:
898 * 1) Use NULL instead of 0 for w2u_order and u2w_order
899 * 2) Use "" instead of NULL for "no domain"
902 name
= rule
->winname
;
903 dom
= rule
->windomain
;
906 if (lookup_wksids_name2sid(name
, dom
,
907 &canonname
, &canondomain
,
908 NULL
, NULL
, NULL
) == IDMAP_SUCCESS
) {
911 } else if (EMPTY_STRING(dom
)) {
912 if (_idmapdstate
.cfg
->pgcfg
.default_domain
)
913 dom
= _idmapdstate
.cfg
->pgcfg
.default_domain
;
917 sql
= sqlite_mprintf("INSERT into namerules "
918 "(is_user, is_wuser, windomain, winname_display, is_nt4, "
919 "unixname, w2u_order, u2w_order) "
920 "VALUES(%d, %d, %Q, %Q, %d, %Q, %q, %q);",
921 rule
->is_user
? 1 : 0, rule
->is_wuser
? 1 : 0, dom
,
922 name
, rule
->is_nt4
? 1 : 0, rule
->unixname
,
923 w2u_order
? w2ubuf
: NULL
, u2w_order
? u2wbuf
: NULL
);
927 retcode
= IDMAP_ERR_INTERNAL
;
928 idmapdlog(LOG_ERR
, "Out of memory");
932 retcode
= sql_exec_no_cb(db
, IDMAP_DBNAME
, sql
);
934 if (retcode
== IDMAP_ERR_OTHER
)
935 retcode
= IDMAP_ERR_CFG
;
946 * Flush name-based mapping rules
949 flush_namerules(sqlite
*db
)
953 retcode
= sql_exec_no_cb(db
, IDMAP_DBNAME
, "DELETE FROM namerules;");
959 * Generate and execute SQL statement to remove a name-based mapping rule
962 rm_namerule(sqlite
*db
, idmap_namerule
*rule
)
968 if (rule
->direction
< 0 && EMPTY_STRING(rule
->windomain
) &&
969 EMPTY_STRING(rule
->winname
) && EMPTY_STRING(rule
->unixname
))
970 return (IDMAP_SUCCESS
);
972 retcode
= gen_sql_expr_from_rule(rule
, &expr
);
973 if (retcode
!= IDMAP_SUCCESS
)
976 sql
= sqlite_mprintf("DELETE FROM namerules WHERE 1 %s;", expr
);
979 retcode
= IDMAP_ERR_INTERNAL
;
980 idmapdlog(LOG_ERR
, "Out of memory");
985 retcode
= sql_exec_no_cb(db
, IDMAP_DBNAME
, sql
);
989 sqlite_freemem(expr
);
996 * Compile the given SQL query and step just once.
1000 * sql - SQL statement
1003 * vm - virtual SQL machine
1004 * ncol - number of columns in the result
1005 * values - column values
1009 * IDMAP_ERR_NOTFOUND
1010 * IDMAP_ERR_INTERNAL
1015 sql_compile_n_step_once(sqlite
*db
, char *sql
, sqlite_vm
**vm
, int *ncol
,
1016 int reqcol
, const char ***values
)
1018 char *errmsg
= NULL
;
1021 if ((r
= sqlite_compile(db
, sql
, NULL
, vm
, &errmsg
)) != SQLITE_OK
) {
1022 idmapdlog(LOG_ERR
, "Database error during %s (%s)", sql
,
1023 CHECK_NULL(errmsg
));
1024 sqlite_freemem(errmsg
);
1025 return (IDMAP_ERR_INTERNAL
);
1028 r
= sqlite_step(*vm
, ncol
, values
, NULL
);
1029 assert(r
!= SQLITE_LOCKED
&& r
!= SQLITE_BUSY
);
1031 if (r
== SQLITE_ROW
) {
1032 if (ncol
!= NULL
&& *ncol
< reqcol
) {
1033 (void) sqlite_finalize(*vm
, NULL
);
1035 return (IDMAP_ERR_INTERNAL
);
1037 /* Caller will call finalize after using the results */
1038 return (IDMAP_SUCCESS
);
1039 } else if (r
== SQLITE_DONE
) {
1040 (void) sqlite_finalize(*vm
, NULL
);
1042 return (IDMAP_ERR_NOTFOUND
);
1045 (void) sqlite_finalize(*vm
, &errmsg
);
1047 idmapdlog(LOG_ERR
, "Database error during %s (%s)", sql
,
1048 CHECK_NULL(errmsg
));
1049 sqlite_freemem(errmsg
);
1050 return (IDMAP_ERR_INTERNAL
);
1054 * Load config in the state.
1056 * nm_siduid and nm_sidgid fields:
1057 * state->nm_siduid represents mode used by sid2uid and uid2sid
1058 * requests for directory-based name mappings. Similarly,
1059 * state->nm_sidgid represents mode used by sid2gid and gid2sid
1063 * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
1064 * AD-mode -> !nldap_winname_attr && ad_unixuser_attr
1065 * nldap-mode -> nldap_winname_attr && !ad_unixuser_attr
1066 * mixed-mode -> nldap_winname_attr && ad_unixuser_attr
1069 * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
1070 * AD-mode -> !nldap_winname_attr && ad_unixgroup_attr
1071 * nldap-mode -> nldap_winname_attr && !ad_unixgroup_attr
1072 * mixed-mode -> nldap_winname_attr && ad_unixgroup_attr
1075 load_cfg_in_state(lookup_state_t
*state
)
1077 state
->nm_siduid
= IDMAP_NM_NONE
;
1078 state
->nm_sidgid
= IDMAP_NM_NONE
;
1081 state
->eph_map_unres_sids
= 0;
1082 if (_idmapdstate
.cfg
->pgcfg
.eph_map_unres_sids
)
1083 state
->eph_map_unres_sids
= 1;
1085 state
->id_cache_timeout
=
1086 _idmapdstate
.cfg
->pgcfg
.id_cache_timeout
;
1087 state
->name_cache_timeout
=
1088 _idmapdstate
.cfg
->pgcfg
.name_cache_timeout
;
1090 state
->directory_based_mapping
=
1091 _idmapdstate
.cfg
->pgcfg
.directory_based_mapping
;
1093 if (_idmapdstate
.cfg
->pgcfg
.default_domain
!= NULL
) {
1095 strdup(_idmapdstate
.cfg
->pgcfg
.default_domain
);
1096 if (state
->defdom
== NULL
) {
1098 return (IDMAP_ERR_MEMORY
);
1102 return (IDMAP_SUCCESS
);
1105 if (_idmapdstate
.cfg
->pgcfg
.directory_based_mapping
!=
1106 DIRECTORY_MAPPING_NAME
) {
1108 return (IDMAP_SUCCESS
);
1111 if (_idmapdstate
.cfg
->pgcfg
.nldap_winname_attr
!= NULL
) {
1113 (_idmapdstate
.cfg
->pgcfg
.ad_unixuser_attr
!= NULL
)
1114 ? IDMAP_NM_MIXED
: IDMAP_NM_NLDAP
;
1116 (_idmapdstate
.cfg
->pgcfg
.ad_unixgroup_attr
!= NULL
)
1117 ? IDMAP_NM_MIXED
: IDMAP_NM_NLDAP
;
1120 (_idmapdstate
.cfg
->pgcfg
.ad_unixuser_attr
!= NULL
)
1121 ? IDMAP_NM_AD
: IDMAP_NM_NONE
;
1123 (_idmapdstate
.cfg
->pgcfg
.ad_unixgroup_attr
!= NULL
)
1124 ? IDMAP_NM_AD
: IDMAP_NM_NONE
;
1126 if (_idmapdstate
.cfg
->pgcfg
.ad_unixuser_attr
!= NULL
) {
1127 state
->ad_unixuser_attr
=
1128 strdup(_idmapdstate
.cfg
->pgcfg
.ad_unixuser_attr
);
1129 if (state
->ad_unixuser_attr
== NULL
) {
1131 return (IDMAP_ERR_MEMORY
);
1134 if (_idmapdstate
.cfg
->pgcfg
.ad_unixgroup_attr
!= NULL
) {
1135 state
->ad_unixgroup_attr
=
1136 strdup(_idmapdstate
.cfg
->pgcfg
.ad_unixgroup_attr
);
1137 if (state
->ad_unixgroup_attr
== NULL
) {
1139 return (IDMAP_ERR_MEMORY
);
1142 if (_idmapdstate
.cfg
->pgcfg
.nldap_winname_attr
!= NULL
) {
1143 state
->nldap_winname_attr
=
1144 strdup(_idmapdstate
.cfg
->pgcfg
.nldap_winname_attr
);
1145 if (state
->nldap_winname_attr
== NULL
) {
1147 return (IDMAP_ERR_MEMORY
);
1151 return (IDMAP_SUCCESS
);
1155 * Set the rule with specified values.
1156 * All the strings are copied.
1159 idmap_namerule_set(idmap_namerule
*rule
, const char *windomain
,
1160 const char *winname
, const char *unixname
, boolean_t is_user
,
1161 boolean_t is_wuser
, boolean_t is_nt4
, int direction
)
1164 * Only update if they differ because we have to free
1165 * and duplicate the strings
1167 if (rule
->windomain
== NULL
|| windomain
== NULL
||
1168 strcmp(rule
->windomain
, windomain
) != 0) {
1169 if (rule
->windomain
!= NULL
) {
1170 free(rule
->windomain
);
1171 rule
->windomain
= NULL
;
1173 if (windomain
!= NULL
)
1174 rule
->windomain
= strdup(windomain
);
1177 if (rule
->winname
== NULL
|| winname
== NULL
||
1178 strcmp(rule
->winname
, winname
) != 0) {
1179 if (rule
->winname
!= NULL
) {
1180 free(rule
->winname
);
1181 rule
->winname
= NULL
;
1183 if (winname
!= NULL
)
1184 rule
->winname
= strdup(winname
);
1187 if (rule
->unixname
== NULL
|| unixname
== NULL
||
1188 strcmp(rule
->unixname
, unixname
) != 0) {
1189 if (rule
->unixname
!= NULL
) {
1190 free(rule
->unixname
);
1191 rule
->unixname
= NULL
;
1193 if (unixname
!= NULL
)
1194 rule
->unixname
= strdup(unixname
);
1197 rule
->is_user
= is_user
;
1198 rule
->is_wuser
= is_wuser
;
1199 rule
->is_nt4
= is_nt4
;
1200 rule
->direction
= direction
;
1204 * Lookup well-known SIDs table either by winname or by SID.
1206 * If the given winname or SID is a well-known SID then we set is_wksid
1207 * variable and then proceed to see if the SID has a hard mapping to
1208 * a particular UID/GID (Ex: Creator Owner/Creator Group mapped to
1209 * fixed ephemeral ids). The direction flag indicates whether we have
1210 * a mapping; UNDEF indicates that we do not.
1212 * If we find a mapping then we return success, except for the
1213 * special case of IDMAP_SENTINEL_PID which indicates an inhibited mapping.
1215 * If we find a matching entry, but no mapping, we supply SID, name, and type
1216 * information and return "not found". Higher layers will probably
1217 * do ephemeral mapping.
1219 * If we do not find a match, we return "not found" and leave the question
1224 lookup_wksids_sid2pid(idmap_mapping
*req
, idmap_id_res
*res
, int *is_wksid
)
1226 const wksids_table_t
*wksid
;
1230 assert(req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
||
1231 req
->id1name
!= NULL
);
1233 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
) {
1234 wksid
= find_wksid_by_sid(req
->id1
.idmap_id_u
.sid
.prefix
,
1235 req
->id1
.idmap_id_u
.sid
.rid
, res
->id
.idtype
);
1237 wksid
= find_wksid_by_name(req
->id1name
, req
->id1domain
,
1241 return (IDMAP_ERR_NOTFOUND
);
1243 /* Found matching entry. */
1245 /* Fill in name if it was not already there. */
1246 if (req
->id1name
== NULL
) {
1247 req
->id1name
= strdup(wksid
->winname
);
1248 if (req
->id1name
== NULL
)
1249 return (IDMAP_ERR_MEMORY
);
1252 /* Fill in SID if it was not already there */
1253 if (req
->id1
.idmap_id_u
.sid
.prefix
== NULL
) {
1254 if (wksid
->sidprefix
!= NULL
) {
1255 req
->id1
.idmap_id_u
.sid
.prefix
=
1256 strdup(wksid
->sidprefix
);
1259 req
->id1
.idmap_id_u
.sid
.prefix
=
1260 strdup(_idmapdstate
.cfg
->pgcfg
.machine_sid
);
1263 if (req
->id1
.idmap_id_u
.sid
.prefix
== NULL
)
1264 return (IDMAP_ERR_MEMORY
);
1265 req
->id1
.idmap_id_u
.sid
.rid
= wksid
->rid
;
1268 /* Fill in the canonical domain if not already there */
1269 if (req
->id1domain
== NULL
) {
1273 if (wksid
->domain
!= NULL
)
1274 dom
= wksid
->domain
;
1276 dom
= _idmapdstate
.hostname
;
1277 req
->id1domain
= strdup(dom
);
1279 if (req
->id1domain
== NULL
)
1280 return (IDMAP_ERR_MEMORY
);
1284 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
1286 req
->id1
.idtype
= wksid
->is_wuser
? IDMAP_USID
: IDMAP_GSID
;
1288 if (res
->id
.idtype
== IDMAP_POSIXID
) {
1289 res
->id
.idtype
= wksid
->is_wuser
? IDMAP_UID
: IDMAP_GID
;
1292 if (wksid
->direction
== IDMAP_DIRECTION_UNDEF
) {
1294 * We don't have a mapping
1295 * (But note that we may have supplied SID, name, or type
1298 return (IDMAP_ERR_NOTFOUND
);
1302 * We have an explicit mapping.
1304 if (wksid
->pid
== IDMAP_SENTINEL_PID
) {
1306 * ... which is that mapping is inhibited.
1308 return (IDMAP_ERR_NOMAPPING
);
1311 switch (res
->id
.idtype
) {
1313 res
->id
.idmap_id_u
.uid
= wksid
->pid
;
1316 res
->id
.idmap_id_u
.gid
= wksid
->pid
;
1319 /* IDMAP_POSIXID is eliminated above */
1320 return (IDMAP_ERR_NOTSUPPORTED
);
1323 res
->direction
= wksid
->direction
;
1324 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_KNOWN_SID
;
1325 res
->info
.src
= IDMAP_MAP_SRC_HARD_CODED
;
1326 return (IDMAP_SUCCESS
);
1331 * Look for an entry mapping a PID to a SID.
1333 * Note that direction=UNDEF entries do not specify a mapping,
1334 * and that IDMAP_SENTINEL_PID entries represent either an inhibited
1335 * mapping or an ephemeral mapping. We don't handle either here;
1336 * they are filtered out by find_wksid_by_pid.
1340 lookup_wksids_pid2sid(idmap_mapping
*req
, idmap_id_res
*res
, int is_user
)
1342 const wksids_table_t
*wksid
;
1344 wksid
= find_wksid_by_pid(req
->id1
.idmap_id_u
.uid
, is_user
);
1346 return (IDMAP_ERR_NOTFOUND
);
1348 if (res
->id
.idtype
== IDMAP_SID
) {
1349 res
->id
.idtype
= wksid
->is_wuser
? IDMAP_USID
: IDMAP_GSID
;
1351 res
->id
.idmap_id_u
.sid
.rid
= wksid
->rid
;
1353 if (wksid
->sidprefix
!= NULL
) {
1354 res
->id
.idmap_id_u
.sid
.prefix
=
1355 strdup(wksid
->sidprefix
);
1358 res
->id
.idmap_id_u
.sid
.prefix
=
1359 strdup(_idmapdstate
.cfg
->pgcfg
.machine_sid
);
1363 if (res
->id
.idmap_id_u
.sid
.prefix
== NULL
) {
1364 idmapdlog(LOG_ERR
, "Out of memory");
1365 return (IDMAP_ERR_MEMORY
);
1368 /* Fill in name if it was not already there. */
1369 if (req
->id2name
== NULL
) {
1370 req
->id2name
= strdup(wksid
->winname
);
1371 if (req
->id2name
== NULL
)
1372 return (IDMAP_ERR_MEMORY
);
1375 /* Fill in the canonical domain if not already there */
1376 if (req
->id2domain
== NULL
) {
1380 if (wksid
->domain
!= NULL
)
1381 dom
= wksid
->domain
;
1383 dom
= _idmapdstate
.hostname
;
1384 req
->id2domain
= strdup(dom
);
1386 if (req
->id2domain
== NULL
)
1387 return (IDMAP_ERR_MEMORY
);
1390 res
->direction
= wksid
->direction
;
1391 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_KNOWN_SID
;
1392 res
->info
.src
= IDMAP_MAP_SRC_HARD_CODED
;
1393 return (IDMAP_SUCCESS
);
1397 * Look up a name in the wksids list, matching name and, if supplied, domain,
1401 * name Windows user name
1402 * domain Windows domain name (or NULL)
1404 * Return: Error code
1406 * *canonname canonical name (if canonname non-NULL) [1]
1407 * *canondomain canonical domain (if canondomain non-NULL) [1]
1408 * *sidprefix SID prefix (if sidprefix non-NULL) [1]
1409 * *rid RID (if rid non-NULL) [2]
1410 * *type Type (if type non-NULL) [2]
1412 * [1] malloc'ed, NULL on error
1413 * [2] Undefined on error
1416 lookup_wksids_name2sid(
1423 idmap_id_type
*type
)
1425 const wksids_table_t
*wksid
;
1427 if (sidprefix
!= NULL
)
1429 if (canonname
!= NULL
)
1431 if (canondomain
!= NULL
)
1432 *canondomain
= NULL
;
1434 wksid
= find_wksid_by_name(name
, domain
, IDMAP_POSIXID
);
1436 return (IDMAP_ERR_NOTFOUND
);
1438 if (sidprefix
!= NULL
) {
1439 if (wksid
->sidprefix
!= NULL
) {
1440 *sidprefix
= strdup(wksid
->sidprefix
);
1443 *sidprefix
= strdup(
1444 _idmapdstate
.cfg
->pgcfg
.machine_sid
);
1447 if (*sidprefix
== NULL
)
1454 if (canonname
!= NULL
) {
1455 *canonname
= strdup(wksid
->winname
);
1456 if (*canonname
== NULL
)
1460 if (canondomain
!= NULL
) {
1461 if (wksid
->domain
!= NULL
) {
1462 *canondomain
= strdup(wksid
->domain
);
1465 *canondomain
= strdup(_idmapdstate
.hostname
);
1468 if (*canondomain
== NULL
)
1473 *type
= (wksid
->is_wuser
) ?
1474 IDMAP_USID
: IDMAP_GSID
;
1476 return (IDMAP_SUCCESS
);
1479 idmapdlog(LOG_ERR
, "Out of memory");
1481 if (sidprefix
!= NULL
) {
1486 if (canonname
!= NULL
) {
1491 if (canondomain
!= NULL
) {
1493 *canondomain
= NULL
;
1496 return (IDMAP_ERR_MEMORY
);
1501 lookup_cache_sid2pid(sqlite
*cache
, idmap_mapping
*req
, idmap_id_res
*res
)
1505 const char **values
;
1506 sqlite_vm
*vm
= NULL
;
1509 time_t curtime
, exp
;
1510 idmap_retcode retcode
;
1511 char *is_user_string
, *lower_name
;
1515 if ((curtime
= time(NULL
)) == (time_t)-1) {
1516 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
1518 retcode
= IDMAP_ERR_INTERNAL
;
1522 switch (res
->id
.idtype
) {
1524 is_user_string
= "1";
1527 is_user_string
= "0";
1530 /* the non-diagonal mapping */
1531 is_user_string
= "is_wuser";
1534 retcode
= IDMAP_ERR_NOTSUPPORTED
;
1538 /* SQL to lookup the cache */
1540 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
) {
1541 sql
= sqlite_mprintf("SELECT pid, is_user, expiration, "
1542 "unixname, u2w, is_wuser, "
1543 "map_type, map_dn, map_attr, map_value, "
1544 "map_windomain, map_winname, map_unixname, map_is_nt4 "
1545 "FROM idmap_cache WHERE is_user = %s AND "
1546 "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
1547 "(pid >= 2147483648 OR "
1548 "(expiration = 0 OR expiration ISNULL OR "
1549 "expiration > %d));",
1550 is_user_string
, req
->id1
.idmap_id_u
.sid
.prefix
,
1551 req
->id1
.idmap_id_u
.sid
.rid
, curtime
);
1552 } else if (req
->id1name
!= NULL
) {
1553 if ((lower_name
= tolower_u8(req
->id1name
)) == NULL
)
1554 lower_name
= req
->id1name
;
1555 sql
= sqlite_mprintf("SELECT pid, is_user, expiration, "
1556 "unixname, u2w, is_wuser, "
1557 "map_type, map_dn, map_attr, map_value, "
1558 "map_windomain, map_winname, map_unixname, map_is_nt4 "
1559 "FROM idmap_cache WHERE is_user = %s AND "
1560 "winname = %Q AND windomain = %Q AND w2u = 1 AND "
1561 "(pid >= 2147483648 OR "
1562 "(expiration = 0 OR expiration ISNULL OR "
1563 "expiration > %d));",
1564 is_user_string
, lower_name
, req
->id1domain
,
1566 if (lower_name
!= req
->id1name
)
1569 retcode
= IDMAP_ERR_ARG
;
1573 idmapdlog(LOG_ERR
, "Out of memory");
1574 retcode
= IDMAP_ERR_MEMORY
;
1577 retcode
= sql_compile_n_step_once(cache
, sql
, &vm
, &ncol
,
1579 sqlite_freemem(sql
);
1581 if (retcode
== IDMAP_ERR_NOTFOUND
) {
1583 } else if (retcode
== IDMAP_SUCCESS
) {
1585 if (values
[0] == NULL
|| values
[1] == NULL
) {
1586 retcode
= IDMAP_ERR_CACHE
;
1590 pid
= strtoul(values
[0], &end
, 10);
1591 is_user
= strncmp(values
[1], "0", 2) ? 1 : 0;
1594 res
->id
.idtype
= IDMAP_UID
;
1595 res
->id
.idmap_id_u
.uid
= pid
;
1597 res
->id
.idtype
= IDMAP_GID
;
1598 res
->id
.idmap_id_u
.gid
= pid
;
1602 * We may have an expired ephemeral mapping. Consider
1603 * the expired entry as valid if we are not going to
1604 * perform name-based mapping. But do not renew the
1606 * If we will be doing name-based mapping then store the
1607 * ephemeral pid in the result so that we can use it
1608 * if we end up doing dynamic mapping again.
1610 if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req
) &&
1611 !AVOID_NAMESERVICE(req
) &&
1612 IDMAP_ID_IS_EPHEMERAL(pid
) && values
[2] != NULL
) {
1613 exp
= strtoll(values
[2], &end
, 10);
1614 if (exp
&& exp
<= curtime
) {
1615 /* Store the ephemeral pid */
1616 res
->direction
= IDMAP_DIRECTION_BI
;
1617 req
->direction
|= is_user
1618 ? _IDMAP_F_EXP_EPH_UID
1619 : _IDMAP_F_EXP_EPH_GID
;
1620 retcode
= IDMAP_ERR_NOTFOUND
;
1626 if (retcode
== IDMAP_SUCCESS
) {
1627 if (values
[4] != NULL
)
1629 (strtol(values
[4], &end
, 10) == 0)?
1630 IDMAP_DIRECTION_W2U
:IDMAP_DIRECTION_BI
;
1632 res
->direction
= IDMAP_DIRECTION_W2U
;
1634 if (values
[3] != NULL
) {
1635 if (req
->id2name
!= NULL
)
1637 req
->id2name
= strdup(values
[3]);
1638 if (req
->id2name
== NULL
) {
1639 idmapdlog(LOG_ERR
, "Out of memory");
1640 retcode
= IDMAP_ERR_MEMORY
;
1644 req
->id1
.idtype
= strncmp(values
[5], "0", 2) ?
1645 IDMAP_USID
: IDMAP_GSID
;
1647 if (req
->flag
& IDMAP_REQ_FLG_MAPPING_INFO
) {
1648 res
->info
.src
= IDMAP_MAP_SRC_CACHE
;
1649 res
->info
.how
.map_type
= strtoul(values
[6], &end
, 10);
1650 switch (res
->info
.how
.map_type
) {
1651 case IDMAP_MAP_TYPE_DS_AD
:
1652 res
->info
.how
.idmap_how_u
.ad
.dn
=
1654 res
->info
.how
.idmap_how_u
.ad
.attr
=
1656 res
->info
.how
.idmap_how_u
.ad
.value
=
1660 case IDMAP_MAP_TYPE_DS_NLDAP
:
1661 res
->info
.how
.idmap_how_u
.nldap
.dn
=
1663 res
->info
.how
.idmap_how_u
.nldap
.attr
=
1665 res
->info
.how
.idmap_how_u
.nldap
.value
=
1669 case IDMAP_MAP_TYPE_RULE_BASED
:
1670 res
->info
.how
.idmap_how_u
.rule
.windomain
=
1672 res
->info
.how
.idmap_how_u
.rule
.winname
=
1674 res
->info
.how
.idmap_how_u
.rule
.unixname
=
1676 res
->info
.how
.idmap_how_u
.rule
.is_nt4
=
1677 strtoul(values
[13], &end
, 1);
1678 res
->info
.how
.idmap_how_u
.rule
.is_user
=
1680 res
->info
.how
.idmap_how_u
.rule
.is_wuser
=
1681 strtoul(values
[5], &end
, 1);
1684 case IDMAP_MAP_TYPE_EPHEMERAL
:
1687 case IDMAP_MAP_TYPE_LOCAL_SID
:
1690 case IDMAP_MAP_TYPE_KNOWN_SID
:
1693 case IDMAP_MAP_TYPE_IDMU
:
1694 res
->info
.how
.idmap_how_u
.idmu
.dn
=
1696 res
->info
.how
.idmap_how_u
.idmu
.attr
=
1698 res
->info
.how
.idmap_how_u
.idmu
.value
=
1703 /* Unknown mapping type */
1709 (void) sqlite_finalize(vm
, NULL
);
1714 * Previous versions used two enumerations for representing types.
1715 * One of those has largely been eliminated, but was used in the
1716 * name cache table and so during an upgrade might still be visible.
1717 * In addition, the test suite prepopulates the cache with these values.
1719 * This function translates those old values into the new values.
1721 * This code deliberately does not use symbolic values for the legacy
1722 * values. This is the *only* place where they should be used.
1726 xlate_legacy_type(int type
)
1729 case -1004: /* _IDMAP_T_USER */
1730 return (IDMAP_USID
);
1731 case -1005: /* _IDMAP_T_GROUP */
1732 return (IDMAP_GSID
);
1741 lookup_cache_sid2name(sqlite
*cache
, const char *sidprefix
, idmap_rid_t rid
,
1742 char **canonname
, char **canondomain
, idmap_id_type
*type
)
1746 const char **values
;
1747 sqlite_vm
*vm
= NULL
;
1750 idmap_retcode retcode
= IDMAP_SUCCESS
;
1752 /* Get current time */
1754 if ((curtime
= time(NULL
)) == (time_t)-1) {
1755 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
1757 retcode
= IDMAP_ERR_INTERNAL
;
1761 /* SQL to lookup the cache */
1762 sql
= sqlite_mprintf("SELECT canon_name, domain, type "
1763 "FROM name_cache WHERE "
1764 "sidprefix = %Q AND rid = %u AND "
1765 "(expiration = 0 OR expiration ISNULL OR "
1766 "expiration > %d);",
1767 sidprefix
, rid
, curtime
);
1769 idmapdlog(LOG_ERR
, "Out of memory");
1770 retcode
= IDMAP_ERR_MEMORY
;
1773 retcode
= sql_compile_n_step_once(cache
, sql
, &vm
, &ncol
, 3, &values
);
1774 sqlite_freemem(sql
);
1776 if (retcode
== IDMAP_SUCCESS
) {
1778 if (values
[2] == NULL
) {
1779 retcode
= IDMAP_ERR_CACHE
;
1782 *type
= xlate_legacy_type(strtol(values
[2], &end
, 10));
1785 if (canonname
!= NULL
&& values
[0] != NULL
) {
1786 if ((*canonname
= strdup(values
[0])) == NULL
) {
1787 idmapdlog(LOG_ERR
, "Out of memory");
1788 retcode
= IDMAP_ERR_MEMORY
;
1793 if (canondomain
!= NULL
&& values
[1] != NULL
) {
1794 if ((*canondomain
= strdup(values
[1])) == NULL
) {
1795 if (canonname
!= NULL
) {
1799 idmapdlog(LOG_ERR
, "Out of memory");
1800 retcode
= IDMAP_ERR_MEMORY
;
1808 (void) sqlite_finalize(vm
, NULL
);
1813 * Given SID, find winname using name_cache OR
1814 * Given winname, find SID using name_cache.
1815 * Used when mapping win to unix i.e. req->id1 is windows id and
1816 * req->id2 is unix id
1820 lookup_name_cache(sqlite
*cache
, idmap_mapping
*req
, idmap_id_res
*res
)
1822 idmap_id_type type
= -1;
1823 idmap_retcode retcode
;
1824 char *sidprefix
= NULL
;
1826 char *name
= NULL
, *domain
= NULL
;
1828 /* Done if we've both sid and winname */
1829 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
&& req
->id1name
!= NULL
) {
1830 /* Don't bother TRACE()ing, too boring */
1831 return (IDMAP_SUCCESS
);
1834 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
) {
1835 /* Lookup sid to winname */
1836 retcode
= lookup_cache_sid2name(cache
,
1837 req
->id1
.idmap_id_u
.sid
.prefix
,
1838 req
->id1
.idmap_id_u
.sid
.rid
, &name
, &domain
, &type
);
1840 /* Lookup winame to sid */
1841 retcode
= lookup_cache_name2sid(cache
, req
->id1name
,
1842 req
->id1domain
, &name
, &sidprefix
, &rid
, &type
);
1845 if (retcode
!= IDMAP_SUCCESS
) {
1846 if (retcode
== IDMAP_ERR_NOTFOUND
) {
1847 TRACE(req
, res
, "Not found in name cache");
1849 TRACE(req
, res
, "Name cache lookup error=%d", retcode
);
1857 req
->id1
.idtype
= type
;
1859 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
1862 * If we found canonical names or domain, use them instead of
1863 * the existing values.
1867 req
->id1name
= name
;
1869 if (domain
!= NULL
) {
1870 free(req
->id1domain
);
1871 req
->id1domain
= domain
;
1874 if (req
->id1
.idmap_id_u
.sid
.prefix
== NULL
) {
1875 req
->id1
.idmap_id_u
.sid
.prefix
= sidprefix
;
1876 req
->id1
.idmap_id_u
.sid
.rid
= rid
;
1879 TRACE(req
, res
, "Found in name cache");
1886 ad_lookup_batch_int(lookup_state_t
*state
, idmap_mapping_batch
*batch
,
1887 idmap_ids_res
*result
, adutils_ad_t
*dir
, int how_local
,
1890 idmap_retcode retcode
;
1891 int i
, num_queued
, is_wuser
, is_user
;
1893 int retries
= 0, esidtype
;
1897 idmap_query_state_t
*qs
= NULL
;
1899 char **dn
, **attr
, **value
;
1904 * Since req->id2.idtype is unused, we will use it here
1905 * to retrieve the value of sid_type. But it needs to be
1906 * reset to IDMAP_NONE before we return to prevent xdr
1907 * from mis-interpreting req->id2 when it tries to free
1908 * the input argument. Other option is to allocate an
1909 * array of integers and use it instead for the batched
1910 * call. But why un-necessarily allocate memory. That may
1911 * be an option if req->id2.idtype cannot be re-used in
1914 * Similarly, we use req->id2.idmap_id_u.uid to return
1915 * uidNumber or gidNumber supplied by IDMU, and reset it
1916 * back to IDMAP_SENTINEL_PID when we're done. Note that
1917 * the query always puts the result in req->id2.idmap_id_u.uid,
1921 retcode
= idmap_lookup_batch_start(dir
, state
->ad_nqueries
,
1922 state
->directory_based_mapping
,
1925 if (retcode
!= IDMAP_SUCCESS
) {
1926 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
1927 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
1929 degrade_svc(1, "failed to create batch for AD lookup");
1936 if (how_local
& FOREST_IS_LOCAL
) {
1938 * Directory based name mapping is only performed within the
1939 * joined forest. We don't trust other "trusted"
1940 * forests to provide DS-based name mapping information because
1941 * AD's definition of "cross-forest trust" does not encompass
1942 * this sort of behavior.
1944 idmap_lookup_batch_set_unixattr(qs
,
1945 state
->ad_unixuser_attr
, state
->ad_unixgroup_attr
);
1948 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
1949 req
= &batch
->idmap_mapping_batch_val
[i
];
1950 res
= &result
->ids
.ids_val
[i
];
1951 how
= &res
->info
.how
;
1953 retcode
= IDMAP_SUCCESS
;
1954 req
->id2
.idtype
= IDMAP_NONE
;
1955 req
->id2
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
1957 /* Skip if no AD lookup required */
1958 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
1961 /* Skip if we've already tried and gotten a "not found" */
1962 if (req
->direction
& _IDMAP_F_LOOKUP_OTHER_AD
)
1965 /* Skip if we've already either succeeded or failed */
1966 if (res
->retcode
!= IDMAP_ERR_RETRIABLE_NET_ERR
)
1969 if (IS_ID_SID(req
->id1
)) {
1971 /* win2unix request: */
1973 posix_id_t
*pid
= NULL
;
1974 unixname
= dn
= attr
= value
= NULL
;
1975 esidtype
= IDMAP_SID
;
1976 if (state
->directory_based_mapping
==
1977 DIRECTORY_MAPPING_NAME
&&
1978 req
->id2name
== NULL
) {
1979 if (res
->id
.idtype
== IDMAP_UID
&&
1980 AD_OR_MIXED(state
->nm_siduid
)) {
1981 esidtype
= IDMAP_USID
;
1982 unixname
= &req
->id2name
;
1983 } else if (res
->id
.idtype
== IDMAP_GID
&&
1984 AD_OR_MIXED(state
->nm_sidgid
)) {
1985 esidtype
= IDMAP_GSID
;
1986 unixname
= &req
->id2name
;
1987 } else if (AD_OR_MIXED(state
->nm_siduid
) ||
1988 AD_OR_MIXED(state
->nm_sidgid
)) {
1989 unixname
= &req
->id2name
;
1992 if (unixname
!= NULL
) {
1994 * Get how info for DS-based name
1995 * mapping only if AD or MIXED
1998 idmap_how_clear(&res
->info
.how
);
1999 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2000 how
->map_type
= IDMAP_MAP_TYPE_DS_AD
;
2001 dn
= &how
->idmap_how_u
.ad
.dn
;
2002 attr
= &how
->idmap_how_u
.ad
.attr
;
2003 value
= &how
->idmap_how_u
.ad
.value
;
2005 } else if (state
->directory_based_mapping
==
2006 DIRECTORY_MAPPING_IDMU
&&
2007 (how_local
& DOMAIN_IS_LOCAL
)) {
2009 * Ensure that we only do IDMU processing
2010 * when querying the domain we've joined.
2012 pid
= &req
->id2
.idmap_id_u
.uid
;
2014 * Get how info for IDMU based mapping.
2016 idmap_how_clear(&res
->info
.how
);
2017 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2018 how
->map_type
= IDMAP_MAP_TYPE_IDMU
;
2019 dn
= &how
->idmap_how_u
.idmu
.dn
;
2020 attr
= &how
->idmap_how_u
.idmu
.attr
;
2021 value
= &how
->idmap_how_u
.idmu
.value
;
2024 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
) {
2025 /* Lookup AD by SID */
2026 retcode
= idmap_sid2name_batch_add1(
2027 qs
, req
->id1
.idmap_id_u
.sid
.prefix
,
2028 &req
->id1
.idmap_id_u
.sid
.rid
, esidtype
,
2030 (req
->id1name
== NULL
) ?
2031 &req
->id1name
: NULL
,
2032 (req
->id1domain
== NULL
) ?
2033 &req
->id1domain
: NULL
,
2034 &req
->id2
.idtype
, unixname
,
2037 if (retcode
== IDMAP_SUCCESS
)
2040 /* Lookup AD by winname */
2041 assert(req
->id1name
!= NULL
);
2042 retcode
= idmap_name2sid_batch_add1(
2043 qs
, req
->id1name
, req
->id1domain
,
2047 &req
->id1
.idmap_id_u
.sid
.prefix
,
2048 &req
->id1
.idmap_id_u
.sid
.rid
,
2049 &req
->id2
.idtype
, unixname
,
2052 if (retcode
== IDMAP_SUCCESS
)
2056 } else if (IS_ID_UID(req
->id1
) || IS_ID_GID(req
->id1
)) {
2058 /* unix2win request: */
2060 if (res
->id
.idmap_id_u
.sid
.prefix
!= NULL
&&
2061 req
->id2name
!= NULL
) {
2062 /* Already have SID and winname. done */
2063 res
->retcode
= IDMAP_SUCCESS
;
2067 if (res
->id
.idmap_id_u
.sid
.prefix
!= NULL
) {
2069 * SID but no winname -- lookup AD by
2070 * SID to get winname.
2071 * how info is not needed here because
2072 * we are not retrieving unixname from
2076 retcode
= idmap_sid2name_batch_add1(
2077 qs
, res
->id
.idmap_id_u
.sid
.prefix
,
2078 &res
->id
.idmap_id_u
.sid
.rid
,
2082 &req
->id2domain
, &req
->id2
.idtype
,
2083 NULL
, NULL
, &res
->retcode
);
2084 if (retcode
== IDMAP_SUCCESS
)
2086 } else if (req
->id2name
!= NULL
) {
2088 * winname but no SID -- lookup AD by
2089 * winname to get SID.
2090 * how info is not needed here because
2091 * we are not retrieving unixname from
2094 retcode
= idmap_name2sid_batch_add1(
2095 qs
, req
->id2name
, req
->id2domain
,
2097 NULL
, NULL
, NULL
, NULL
,
2098 &res
->id
.idmap_id_u
.sid
.prefix
,
2099 &res
->id
.idmap_id_u
.sid
.rid
,
2100 &req
->id2
.idtype
, NULL
,
2103 if (retcode
== IDMAP_SUCCESS
)
2105 } else if (state
->directory_based_mapping
==
2106 DIRECTORY_MAPPING_IDMU
&&
2107 (how_local
& DOMAIN_IS_LOCAL
)) {
2108 assert(req
->id1
.idmap_id_u
.uid
!=
2109 IDMAP_SENTINEL_PID
);
2110 is_user
= IS_ID_UID(req
->id1
);
2111 if (res
->id
.idtype
== IDMAP_USID
)
2113 else if (res
->id
.idtype
== IDMAP_GSID
)
2118 /* IDMU can't do diagonal mappings */
2119 if (is_user
!= is_wuser
)
2122 idmap_how_clear(&res
->info
.how
);
2123 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2124 how
->map_type
= IDMAP_MAP_TYPE_IDMU
;
2125 retcode
= idmap_pid2sid_batch_add1(
2126 qs
, req
->id1
.idmap_id_u
.uid
, is_user
,
2127 &how
->idmap_how_u
.ad
.dn
,
2128 &how
->idmap_how_u
.ad
.attr
,
2129 &how
->idmap_how_u
.ad
.value
,
2130 &res
->id
.idmap_id_u
.sid
.prefix
,
2131 &res
->id
.idmap_id_u
.sid
.rid
,
2132 &req
->id2name
, &req
->id2domain
,
2133 &req
->id2
.idtype
, &res
->retcode
);
2134 if (retcode
== IDMAP_SUCCESS
)
2136 } else if (req
->id1name
!= NULL
) {
2138 * No SID and no winname but we've unixname.
2139 * Lookup AD by unixname to get SID.
2141 is_user
= (IS_ID_UID(req
->id1
)) ? 1 : 0;
2142 if (res
->id
.idtype
== IDMAP_USID
)
2144 else if (res
->id
.idtype
== IDMAP_GSID
)
2149 idmap_how_clear(&res
->info
.how
);
2150 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2151 how
->map_type
= IDMAP_MAP_TYPE_DS_AD
;
2152 retcode
= idmap_unixname2sid_batch_add1(
2153 qs
, req
->id1name
, is_user
, is_wuser
,
2154 &how
->idmap_how_u
.ad
.dn
,
2155 &how
->idmap_how_u
.ad
.attr
,
2156 &how
->idmap_how_u
.ad
.value
,
2157 &res
->id
.idmap_id_u
.sid
.prefix
,
2158 &res
->id
.idmap_id_u
.sid
.rid
,
2159 &req
->id2name
, &req
->id2domain
,
2160 &req
->id2
.idtype
, &res
->retcode
);
2161 if (retcode
== IDMAP_SUCCESS
)
2166 if (retcode
== IDMAP_ERR_DOMAIN_NOTFOUND
) {
2167 req
->direction
|= _IDMAP_F_LOOKUP_OTHER_AD
;
2168 retcode
= IDMAP_SUCCESS
;
2169 } else if (retcode
!= IDMAP_SUCCESS
) {
2172 } /* End of for loop */
2174 if (retcode
== IDMAP_SUCCESS
) {
2175 /* add keeps track if we added an entry to the batch */
2177 retcode
= idmap_lookup_batch_end(&qs
);
2179 idmap_lookup_release_batch(&qs
);
2181 idmap_lookup_release_batch(&qs
);
2183 next_request
= i
+ 1;
2186 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
2187 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
2189 else if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
)
2190 degrade_svc(1, "some AD lookups timed out repeatedly");
2192 if (retcode
!= IDMAP_SUCCESS
) {
2193 /* Mark any unproccessed requests for an other AD */
2194 for (i
= next_request
; i
< batch
->idmap_mapping_batch_len
;
2196 req
= &batch
->idmap_mapping_batch_val
[i
];
2197 req
->direction
|= _IDMAP_F_LOOKUP_OTHER_AD
;
2202 if (retcode
!= IDMAP_SUCCESS
)
2203 idmapdlog(LOG_NOTICE
, "Failed to batch AD lookup requests");
2207 * This loop does the following:
2208 * 1. Reset _IDMAP_F_LOOKUP_AD flag from the request.
2209 * 2. Reset req->id2.idtype to IDMAP_NONE
2210 * 3. If batch_start or batch_add failed then set the status
2211 * of each request marked for AD lookup to that error.
2212 * 4. Evaluate the type of the AD object (i.e. user or group)
2213 * and update the idtype in request.
2215 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
2219 req
= &batch
->idmap_mapping_batch_val
[i
];
2220 type
= req
->id2
.idtype
;
2221 req
->id2
.idtype
= IDMAP_NONE
;
2222 posix_id
= req
->id2
.idmap_id_u
.uid
;
2223 req
->id2
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
2224 res
= &result
->ids
.ids_val
[i
];
2227 * If it didn't need AD lookup, ignore it.
2229 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
2233 * If we deferred it this time, reset for the next
2236 if (req
->direction
& _IDMAP_F_LOOKUP_OTHER_AD
) {
2237 req
->direction
&= ~_IDMAP_F_LOOKUP_OTHER_AD
;
2241 /* Count number processed */
2244 /* Reset AD lookup flag */
2245 req
->direction
&= ~(_IDMAP_F_LOOKUP_AD
);
2248 * If batch_start or batch_add failed then set the
2249 * status of each request marked for AD lookup to
2252 if (retcode
!= IDMAP_SUCCESS
) {
2253 res
->retcode
= retcode
;
2257 if (res
->retcode
== IDMAP_ERR_NOTFOUND
) {
2258 /* Nothing found - remove the preset info */
2259 idmap_how_clear(&res
->info
.how
);
2262 if (IS_ID_SID(req
->id1
)) {
2263 if (res
->retcode
== IDMAP_ERR_NOTFOUND
) {
2264 TRACE(req
, res
, "Not found in AD");
2267 if (res
->retcode
!= IDMAP_SUCCESS
) {
2268 TRACE(req
, res
, "AD lookup error=%d",
2272 /* Evaluate result type */
2275 if (res
->id
.idtype
== IDMAP_POSIXID
)
2276 res
->id
.idtype
= IDMAP_UID
;
2278 * We found a user. If we got information
2279 * from IDMU and we were expecting a user,
2282 if (posix_id
!= IDMAP_SENTINEL_PID
&&
2283 res
->id
.idtype
== IDMAP_UID
) {
2284 res
->id
.idmap_id_u
.uid
= posix_id
;
2285 res
->direction
= IDMAP_DIRECTION_BI
;
2286 res
->info
.how
.map_type
=
2287 IDMAP_MAP_TYPE_IDMU
;
2288 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2290 req
->id1
.idtype
= IDMAP_USID
;
2294 if (res
->id
.idtype
== IDMAP_POSIXID
)
2295 res
->id
.idtype
= IDMAP_GID
;
2297 * We found a group. If we got information
2298 * from IDMU and we were expecting a group,
2301 if (posix_id
!= IDMAP_SENTINEL_PID
&&
2302 res
->id
.idtype
== IDMAP_GID
) {
2303 res
->id
.idmap_id_u
.gid
= posix_id
;
2304 res
->direction
= IDMAP_DIRECTION_BI
;
2305 res
->info
.how
.map_type
=
2306 IDMAP_MAP_TYPE_IDMU
;
2307 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2309 req
->id1
.idtype
= IDMAP_GSID
;
2313 res
->retcode
= IDMAP_ERR_SID
;
2316 TRACE(req
, res
, "Found in AD");
2317 if (res
->retcode
== IDMAP_SUCCESS
&&
2318 req
->id1name
!= NULL
&&
2319 (req
->id2name
== NULL
||
2320 res
->id
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) &&
2321 NLDAP_MODE(res
->id
.idtype
, state
)) {
2322 req
->direction
|= _IDMAP_F_LOOKUP_NLDAP
;
2323 state
->nldap_nqueries
++;
2325 } else if (IS_ID_UID(req
->id1
) || IS_ID_GID(req
->id1
)) {
2326 if (res
->retcode
!= IDMAP_SUCCESS
) {
2327 if ((!(IDMAP_FATAL_ERROR(res
->retcode
))) &&
2328 res
->id
.idmap_id_u
.sid
.prefix
== NULL
&&
2329 req
->id2name
== NULL
) {
2331 * If AD lookup by unixname or pid
2332 * failed with non fatal error
2333 * then clear the error (ie set
2334 * res->retcode to success).
2335 * This allows the next pass to
2336 * process other mapping
2337 * mechanisms for this request.
2340 IDMAP_ERR_NOTFOUND
) {
2341 /* This is not an error */
2342 res
->retcode
= IDMAP_SUCCESS
;
2347 "AD lookup error (ignored)");
2348 res
->retcode
= IDMAP_SUCCESS
;
2351 TRACE(req
, res
, "AD lookup error");
2355 /* Evaluate result type */
2359 if (res
->id
.idtype
== IDMAP_SID
)
2360 res
->id
.idtype
= type
;
2364 res
->retcode
= IDMAP_ERR_SID
;
2367 TRACE(req
, res
, "Found in AD");
2380 ad_lookup_batch(lookup_state_t
*state
, idmap_mapping_batch
*batch
,
2381 idmap_ids_res
*result
)
2383 idmap_retcode retcode
;
2390 if (state
->ad_nqueries
== 0)
2391 return (IDMAP_SUCCESS
);
2393 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
2394 req
= &batch
->idmap_mapping_batch_val
[i
];
2395 res
= &result
->ids
.ids_val
[i
];
2397 /* Skip if not marked for AD lookup or already in error. */
2398 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
) ||
2399 res
->retcode
!= IDMAP_SUCCESS
)
2403 res
->retcode
= IDMAP_ERR_RETRIABLE_NET_ERR
;
2407 num_queries
= state
->ad_nqueries
;
2409 if (_idmapdstate
.num_gcs
== 0 && _idmapdstate
.num_dcs
== 0) {
2410 /* Case of no ADs */
2411 retcode
= IDMAP_ERR_NO_ACTIVEDIRECTORY
;
2412 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
2413 req
= &batch
->idmap_mapping_batch_val
[i
];
2414 res
= &result
->ids
.ids_val
[i
];
2415 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
2417 req
->direction
&= ~(_IDMAP_F_LOOKUP_AD
);
2418 res
->retcode
= IDMAP_ERR_NO_ACTIVEDIRECTORY
;
2423 if (state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
) {
2424 for (i
= 0; i
< _idmapdstate
.num_dcs
&& num_queries
> 0; i
++) {
2426 retcode
= ad_lookup_batch_int(state
, batch
,
2427 result
, _idmapdstate
.dcs
[i
],
2428 i
== 0 ? DOMAIN_IS_LOCAL
|FOREST_IS_LOCAL
: 0,
2430 num_queries
-= num_processed
;
2435 for (i
= 0; i
< _idmapdstate
.num_gcs
&& num_queries
> 0; i
++) {
2437 retcode
= ad_lookup_batch_int(state
, batch
, result
,
2438 _idmapdstate
.gcs
[i
],
2439 i
== 0 ? FOREST_IS_LOCAL
: 0,
2441 num_queries
-= num_processed
;
2446 * There are no more ADs to try. Return errors for any
2447 * remaining requests.
2449 if (num_queries
> 0) {
2450 for (j
= 0; j
< batch
->idmap_mapping_batch_len
; j
++) {
2451 req
= &batch
->idmap_mapping_batch_val
[j
];
2452 res
= &result
->ids
.ids_val
[j
];
2453 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
2455 req
->direction
&= ~(_IDMAP_F_LOOKUP_AD
);
2456 res
->retcode
= IDMAP_ERR_DOMAIN_NOTFOUND
;
2463 /* AD lookups done. Reset state->ad_nqueries and return */
2464 state
->ad_nqueries
= 0;
2469 * Convention when processing win2unix requests:
2473 * winname if given otherwise winname found will be placed
2476 * windomain if given otherwise windomain found will be
2479 * Either IDMAP_SID/USID/GSID. If this is IDMAP_SID then it'll
2480 * be set to IDMAP_USID/GSID depending upon whether the
2481 * given SID is user or group respectively. The user/group-ness
2482 * is determined either when looking up well-known SIDs table OR
2483 * if the SID is found in namecache OR by ad_lookup_batch().
2484 * req->id1..sid.[prefix, rid] =
2485 * SID if given otherwise SID found will be placed here.
2489 * unixname found will be placed here.
2493 * Target type initialized from req->id2.idtype. If
2494 * it is IDMAP_POSIXID then actual type (IDMAP_UID/GID) found
2495 * will be placed here.
2496 * res->id..[uid or gid] =
2497 * UID/GID found will be placed here.
2501 * Return status for this request will be placed here.
2503 * Direction found will be placed here. Direction
2504 * meaning whether the resultant mapping is valid
2505 * only from win2unix or bi-directional.
2507 * INTERNAL USE. Used by idmapd to set various
2508 * flags (_IDMAP_F_xxxx) to aid in processing
2511 * INTERNAL USE. Initially this is the requested target
2512 * type and is used to initialize res->id.idtype.
2513 * ad_lookup_batch() uses this field temporarily to store
2514 * sid_type obtained by the batched AD lookups and after
2515 * use resets it to IDMAP_NONE to prevent xdr from
2516 * mis-interpreting the contents of req->id2.
2517 * req->id2.idmap_id_u.uid =
2518 * INTERNAL USE. If the AD lookup finds IDMU data
2519 * (uidNumber or gidNumber, depending on the type of
2520 * the entry), it's left here.
2524 * This function does the following:
2525 * 1. Lookup well-known SIDs table.
2526 * 2. Check if the given SID is a local-SID and if so extract UID/GID from it.
2528 * 4. Check if the client does not want new mapping to be allocated
2529 * in which case this pass is the final pass.
2530 * 5. Set AD lookup flag if it determines that the next stage needs
2534 sid2pid_first_pass(lookup_state_t
*state
, idmap_mapping
*req
,
2537 idmap_retcode retcode
;
2540 /* Initialize result */
2541 res
->id
.idtype
= req
->id2
.idtype
;
2542 res
->id
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
2543 res
->direction
= IDMAP_DIRECTION_UNDEF
;
2546 if (EMPTY_STRING(req
->id1
.idmap_id_u
.sid
.prefix
)) {
2547 /* They have to give us *something* to work with! */
2548 if (req
->id1name
== NULL
) {
2549 retcode
= IDMAP_ERR_ARG
;
2553 /* sanitize sidprefix */
2554 free(req
->id1
.idmap_id_u
.sid
.prefix
);
2555 req
->id1
.idmap_id_u
.sid
.prefix
= NULL
;
2557 /* Allow for a fully-qualified name in the "name" parameter */
2558 if (req
->id1domain
== NULL
) {
2560 p
= strchr(req
->id1name
, '@');
2564 req
->id1name
= uu_strndup(q
, p
- req
->id1name
);
2565 req
->id1domain
= strdup(p
+1);
2567 if (req
->id1name
== NULL
||
2568 req
->id1domain
== NULL
) {
2569 retcode
= IDMAP_ERR_MEMORY
;
2576 /* Lookup well-known SIDs table */
2577 retcode
= lookup_wksids_sid2pid(req
, res
, &wksid
);
2578 if (retcode
== IDMAP_SUCCESS
) {
2579 /* Found a well-known account with a hardwired mapping */
2580 TRACE(req
, res
, "Hardwired mapping");
2582 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
2584 "Well-known account lookup failed, code %d", retcode
);
2589 /* Found a well-known account, but no mapping */
2590 TRACE(req
, res
, "Well-known account");
2592 TRACE(req
, res
, "Not a well-known account");
2594 /* Check if this is a localsid */
2595 retcode
= lookup_localsid2pid(req
, res
);
2596 if (retcode
== IDMAP_SUCCESS
) {
2597 TRACE(req
, res
, "Local SID");
2599 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
2601 "Local SID lookup error=%d", retcode
);
2604 TRACE(req
, res
, "Not a local SID");
2606 if (ALLOW_WK_OR_LOCAL_SIDS_ONLY(req
)) {
2607 retcode
= IDMAP_ERR_NONE_GENERATED
;
2613 * If this is a name-based request and we don't have a domain,
2614 * use the default domain. Note that the well-known identity
2615 * cases will have supplied a SID prefix already, and that we
2616 * don't (yet?) support looking up a local user through a Windows
2619 if (req
->id1
.idmap_id_u
.sid
.prefix
== NULL
&&
2620 req
->id1name
!= NULL
&& req
->id1domain
== NULL
) {
2621 if (state
->defdom
== NULL
) {
2622 retcode
= IDMAP_ERR_DOMAIN_NOTFOUND
;
2625 req
->id1domain
= strdup(state
->defdom
);
2626 if (req
->id1domain
== NULL
) {
2627 retcode
= IDMAP_ERR_MEMORY
;
2630 TRACE(req
, res
, "Added default domain");
2634 retcode
= lookup_cache_sid2pid(state
->cache
, req
, res
);
2635 if (retcode
== IDMAP_SUCCESS
) {
2636 TRACE(req
, res
, "Found in mapping cache");
2638 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
2639 TRACE(req
, res
, "Mapping cache lookup error=%d", retcode
);
2642 TRACE(req
, res
, "Not found in mapping cache");
2644 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req
) || AVOID_NAMESERVICE(req
)) {
2645 retcode
= IDMAP_ERR_NONE_GENERATED
;
2650 * Failed to find non-expired entry in cache. Next step is
2651 * to determine if this request needs to be batched for AD lookup.
2653 * At this point we have either sid or winname or both. If we don't
2654 * have both then lookup name_cache for the sid or winname
2655 * whichever is missing. If not found then this request will be
2656 * batched for AD lookup.
2658 retcode
= lookup_name_cache(state
->cache
, req
, res
);
2659 if (retcode
== IDMAP_SUCCESS
) {
2660 if (res
->id
.idtype
== IDMAP_POSIXID
) {
2661 if (req
->id1
.idtype
== IDMAP_USID
)
2662 res
->id
.idtype
= IDMAP_UID
;
2664 res
->id
.idtype
= IDMAP_GID
;
2666 } else if (retcode
!= IDMAP_ERR_NOTFOUND
)
2669 if (_idmapdstate
.cfg
->pgcfg
.use_lsa
&&
2670 _idmapdstate
.cfg
->pgcfg
.domain_name
!= NULL
) {
2672 * If we don't have both name and SID, try looking up the
2675 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
&&
2676 req
->id1name
== NULL
) {
2678 retcode
= lookup_lsa_by_sid(
2679 req
->id1
.idmap_id_u
.sid
.prefix
,
2680 req
->id1
.idmap_id_u
.sid
.rid
,
2681 &req
->id1name
, &req
->id1domain
, &req
->id1
.idtype
);
2682 if (retcode
== IDMAP_SUCCESS
) {
2683 TRACE(req
, res
, "Found with LSA");
2684 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
2685 TRACE(req
, res
, "Not found with LSA");
2687 TRACE(req
, res
, "LSA error %d", retcode
);
2691 } else if (req
->id1name
!= NULL
&&
2692 req
->id1
.idmap_id_u
.sid
.prefix
== NULL
) {
2696 retcode
= lookup_lsa_by_name(
2697 req
->id1name
, req
->id1domain
,
2698 &req
->id1
.idmap_id_u
.sid
.prefix
,
2699 &req
->id1
.idmap_id_u
.sid
.rid
,
2700 &canonname
, &canondomain
,
2702 if (retcode
== IDMAP_SUCCESS
) {
2704 req
->id1name
= canonname
;
2705 free(req
->id1domain
);
2706 req
->id1domain
= canondomain
;
2707 TRACE(req
, res
, "Found with LSA");
2708 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
2709 TRACE(req
, res
, "Not found with LSA");
2711 TRACE(req
, res
, "LSA error %d", retcode
);
2718 * Set the flag to indicate that we are not done yet so that
2719 * subsequent passes considers this request for name-based
2720 * mapping and ephemeral mapping.
2722 state
->sid2pid_done
= FALSE
;
2723 req
->direction
|= _IDMAP_F_NOTDONE
;
2726 * Even if we have both sid and winname, we still may need to batch
2727 * this request for AD lookup if we don't have unixname and
2728 * directory-based name mapping (AD or mixed) is enabled.
2729 * We avoid AD lookup for well-known SIDs because they don't have
2730 * regular AD objects.
2732 if (retcode
!= IDMAP_SUCCESS
||
2733 (!wksid
&& req
->id2name
== NULL
&&
2734 AD_OR_MIXED_MODE(res
->id
.idtype
, state
)) ||
2735 (!wksid
&& res
->id
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
&&
2736 state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
)) {
2737 retcode
= IDMAP_SUCCESS
;
2738 req
->direction
|= _IDMAP_F_LOOKUP_AD
;
2739 state
->ad_nqueries
++;
2740 } else if (NLDAP_MODE(res
->id
.idtype
, state
)) {
2741 req
->direction
|= _IDMAP_F_LOOKUP_NLDAP
;
2742 state
->nldap_nqueries
++;
2747 res
->retcode
= idmap_stat4prot(retcode
);
2749 * If we are done and there was an error then set fallback pid
2752 if (ARE_WE_DONE(req
->direction
) && res
->retcode
!= IDMAP_SUCCESS
)
2753 res
->id
.idmap_id_u
.uid
= UID_NOBODY
;
2758 * Generate SID using the following convention
2759 * <machine-sid-prefix>-<1000 + uid>
2760 * <machine-sid-prefix>-<2^31 + gid>
2764 generate_localsid(idmap_mapping
*req
, idmap_id_res
*res
, int is_user
,
2767 free(res
->id
.idmap_id_u
.sid
.prefix
);
2768 res
->id
.idmap_id_u
.sid
.prefix
= NULL
;
2771 * Diagonal mapping for localSIDs not supported because of the
2772 * way we generate localSIDs.
2774 if (is_user
&& res
->id
.idtype
== IDMAP_GSID
)
2775 return (IDMAP_ERR_NOTGROUP
);
2776 if (!is_user
&& res
->id
.idtype
== IDMAP_USID
)
2777 return (IDMAP_ERR_NOTUSER
);
2779 /* Skip 1000 UIDs */
2781 req
->id1
.idmap_id_u
.uid
+ LOCALRID_UID_MIN
> LOCALRID_UID_MAX
)
2782 return (IDMAP_ERR_NOMAPPING
);
2786 * machine_sid is never NULL because if it is we won't be here.
2787 * No need to assert because strdup(NULL) will core anyways.
2789 res
->id
.idmap_id_u
.sid
.prefix
=
2790 strdup(_idmapdstate
.cfg
->pgcfg
.machine_sid
);
2791 if (res
->id
.idmap_id_u
.sid
.prefix
== NULL
) {
2793 idmapdlog(LOG_ERR
, "Out of memory");
2794 return (IDMAP_ERR_MEMORY
);
2797 res
->id
.idmap_id_u
.sid
.rid
=
2798 (is_user
) ? req
->id1
.idmap_id_u
.uid
+ LOCALRID_UID_MIN
:
2799 req
->id1
.idmap_id_u
.gid
+ LOCALRID_GID_MIN
;
2800 res
->direction
= IDMAP_DIRECTION_BI
;
2801 if (res
->id
.idtype
== IDMAP_SID
)
2802 res
->id
.idtype
= is_user
? IDMAP_USID
: IDMAP_GSID
;
2805 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_LOCAL_SID
;
2806 res
->info
.src
= IDMAP_MAP_SRC_ALGORITHMIC
;
2810 * Don't update name_cache because local sids don't have
2811 * valid windows names.
2813 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
2814 return (IDMAP_SUCCESS
);
2819 lookup_localsid2pid(idmap_mapping
*req
, idmap_id_res
*res
)
2826 * If the sidprefix == localsid then UID = last RID - 1000 or
2827 * GID = last RID - 2^31.
2829 if ((sidprefix
= req
->id1
.idmap_id_u
.sid
.prefix
) == NULL
)
2830 /* This means we are looking up by winname */
2831 return (IDMAP_ERR_NOTFOUND
);
2832 rid
= req
->id1
.idmap_id_u
.sid
.rid
;
2835 s
= (_idmapdstate
.cfg
->pgcfg
.machine_sid
) ?
2836 strcasecmp(sidprefix
, _idmapdstate
.cfg
->pgcfg
.machine_sid
) : 1;
2840 * If the given sidprefix does not match machine_sid then this is
2844 return (IDMAP_ERR_NOTFOUND
);
2846 switch (res
->id
.idtype
) {
2848 if (rid
< LOCALRID_UID_MIN
|| rid
> LOCALRID_UID_MAX
)
2849 return (IDMAP_ERR_ARG
);
2850 res
->id
.idmap_id_u
.uid
= rid
- LOCALRID_UID_MIN
;
2853 if (rid
< LOCALRID_GID_MIN
)
2854 return (IDMAP_ERR_ARG
);
2855 res
->id
.idmap_id_u
.gid
= rid
- LOCALRID_GID_MIN
;
2858 if (rid
>= LOCALRID_GID_MIN
) {
2859 res
->id
.idmap_id_u
.gid
= rid
- LOCALRID_GID_MIN
;
2860 res
->id
.idtype
= IDMAP_GID
;
2861 } else if (rid
>= LOCALRID_UID_MIN
) {
2862 res
->id
.idmap_id_u
.uid
= rid
- LOCALRID_UID_MIN
;
2863 res
->id
.idtype
= IDMAP_UID
;
2865 return (IDMAP_ERR_ARG
);
2869 return (IDMAP_ERR_NOTSUPPORTED
);
2871 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_LOCAL_SID
;
2872 res
->info
.src
= IDMAP_MAP_SRC_ALGORITHMIC
;
2873 return (IDMAP_SUCCESS
);
2877 * Name service lookup by unixname to get pid
2881 ns_lookup_byname(const char *name
, const char *lower_name
, idmap_id
*id
)
2883 struct passwd pwd
, *pwdp
;
2884 struct group grp
, *grpp
;
2886 static size_t pwdbufsiz
= 0;
2887 static size_t grpbufsiz
= 0;
2889 switch (id
->idtype
) {
2892 pwdbufsiz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
2893 buf
= alloca(pwdbufsiz
);
2894 pwdp
= getpwnam_r(name
, &pwd
, buf
, pwdbufsiz
);
2895 if (pwdp
== NULL
&& errno
== 0 && lower_name
!= NULL
&&
2896 name
!= lower_name
&& strcmp(name
, lower_name
) != 0)
2897 pwdp
= getpwnam_r(lower_name
, &pwd
, buf
, pwdbufsiz
);
2900 return (IDMAP_ERR_NOTFOUND
);
2902 return (IDMAP_ERR_INTERNAL
);
2904 id
->idmap_id_u
.uid
= pwd
.pw_uid
;
2908 grpbufsiz
= sysconf(_SC_GETGR_R_SIZE_MAX
);
2909 buf
= alloca(grpbufsiz
);
2910 grpp
= getgrnam_r(name
, &grp
, buf
, grpbufsiz
);
2911 if (grpp
== NULL
&& errno
== 0 && lower_name
!= NULL
&&
2912 name
!= lower_name
&& strcmp(name
, lower_name
) != 0)
2913 grpp
= getgrnam_r(lower_name
, &grp
, buf
, grpbufsiz
);
2916 return (IDMAP_ERR_NOTFOUND
);
2918 return (IDMAP_ERR_INTERNAL
);
2920 id
->idmap_id_u
.gid
= grp
.gr_gid
;
2923 return (IDMAP_ERR_ARG
);
2925 return (IDMAP_SUCCESS
);
2930 * Name service lookup by pid to get unixname
2934 ns_lookup_bypid(uid_t pid
, int is_user
, char **unixname
)
2939 static size_t pwdbufsiz
= 0;
2940 static size_t grpbufsiz
= 0;
2944 pwdbufsiz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
2945 buf
= alloca(pwdbufsiz
);
2947 if (getpwuid_r(pid
, &pwd
, buf
, pwdbufsiz
) == NULL
) {
2949 return (IDMAP_ERR_NOTFOUND
);
2951 return (IDMAP_ERR_INTERNAL
);
2953 *unixname
= strdup(pwd
.pw_name
);
2956 grpbufsiz
= sysconf(_SC_GETGR_R_SIZE_MAX
);
2957 buf
= alloca(grpbufsiz
);
2959 if (getgrgid_r(pid
, &grp
, buf
, grpbufsiz
) == NULL
) {
2961 return (IDMAP_ERR_NOTFOUND
);
2963 return (IDMAP_ERR_INTERNAL
);
2965 *unixname
= strdup(grp
.gr_name
);
2967 if (*unixname
== NULL
)
2968 return (IDMAP_ERR_MEMORY
);
2969 return (IDMAP_SUCCESS
);
2973 * Name-based mapping
2975 * Case 1: If no rule matches do ephemeral
2977 * Case 2: If rule matches and unixname is "" then return no mapping.
2979 * Case 3: If rule matches and unixname is specified then lookup name
2980 * service using the unixname. If unixname not found then return no mapping.
2982 * Case 4: If rule matches and unixname is * then lookup name service
2983 * using winname as the unixname. If unixname not found then process
2984 * other rules using the lookup order. If no other rule matches then do
2985 * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
2986 * This allows us to specify a fallback unixname per _domain_ or no mapping
2987 * instead of the default behaviour of doing ephemeral mapping.
2991 * If looking up windows users foo@sfbay and foo does not exists in
2992 * the name service then foo@sfbay will be mapped to an ephemeral id.
2997 * If looking up windows users foo@sfbay and foo does not exists in
2998 * the name service then foo@sfbay will be mapped to guest.
3003 * If looking up windows users foo@sfbay and foo does not exists in
3004 * the name service then we will return no mapping for foo@sfbay.
3009 name_based_mapping_sid2pid(lookup_state_t
*state
,
3010 idmap_mapping
*req
, idmap_id_res
*res
)
3012 const char *unixname
, *windomain
;
3013 char *sql
= NULL
, *errmsg
= NULL
, *lower_winname
= NULL
;
3014 idmap_retcode retcode
;
3015 char *end
, *lower_unixname
, *winname
;
3016 const char **values
;
3017 sqlite_vm
*vm
= NULL
;
3018 int ncol
, r
, is_user
, is_wuser
;
3019 idmap_namerule
*rule
= &res
->info
.how
.idmap_how_u
.rule
;
3021 const char *me
= "name_based_mapping_sid2pid";
3023 assert(req
->id1name
!= NULL
); /* We have winname */
3024 assert(req
->id2name
== NULL
); /* We don't have unixname */
3026 winname
= req
->id1name
;
3027 windomain
= req
->id1domain
;
3029 switch (req
->id1
.idtype
) {
3037 idmapdlog(LOG_ERR
, "%s: Unable to determine if the "
3038 "given Windows id is user or group.", me
);
3039 return (IDMAP_ERR_INTERNAL
);
3042 switch (res
->id
.idtype
) {
3051 res
->id
.idtype
= is_user
? IDMAP_UID
: IDMAP_GID
;
3055 if (windomain
== NULL
)
3058 if ((lower_winname
= tolower_u8(winname
)) == NULL
)
3059 lower_winname
= winname
; /* hope for the best */
3060 sql
= sqlite_mprintf(
3061 "SELECT unixname, u2w_order, winname_display, windomain, is_nt4 "
3062 "FROM namerules WHERE "
3063 "w2u_order > 0 AND is_user = %d AND is_wuser = %d AND "
3064 "(winname = %Q OR winname = '*') AND "
3065 "(windomain = %Q OR windomain = '*') "
3066 "ORDER BY w2u_order ASC;",
3067 is_user
, is_wuser
, lower_winname
, windomain
);
3069 idmapdlog(LOG_ERR
, "Out of memory");
3070 retcode
= IDMAP_ERR_MEMORY
;
3074 if (sqlite_compile(state
->db
, sql
, NULL
, &vm
, &errmsg
) != SQLITE_OK
) {
3075 retcode
= IDMAP_ERR_INTERNAL
;
3076 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
3077 CHECK_NULL(errmsg
));
3078 sqlite_freemem(errmsg
);
3083 r
= sqlite_step(vm
, &ncol
, &values
, NULL
);
3084 assert(r
!= SQLITE_LOCKED
&& r
!= SQLITE_BUSY
);
3086 if (r
== SQLITE_ROW
) {
3088 retcode
= IDMAP_ERR_INTERNAL
;
3092 TRACE(req
, res
, "Matching rule: %s@%s -> %s",
3093 values
[2] == NULL
? "(null)" : values
[2],
3094 values
[3] == NULL
? "(null)" : values
[3],
3095 values
[0] == NULL
? "(null)" : values
[0]);
3097 if (values
[0] == NULL
) {
3098 retcode
= IDMAP_ERR_INTERNAL
;
3102 if (values
[1] != NULL
)
3104 (strtol(values
[1], &end
, 10) == 0)?
3105 IDMAP_DIRECTION_W2U
:IDMAP_DIRECTION_BI
;
3107 direction
= IDMAP_DIRECTION_W2U
;
3109 if (EMPTY_NAME(values
[0])) {
3110 TRACE(req
, res
, "Mapping inhibited");
3111 idmap_namerule_set(rule
, values
[3], values
[2],
3112 values
[0], is_user
, is_wuser
,
3113 strtol(values
[4], &end
, 10),
3115 retcode
= IDMAP_ERR_NOMAPPING
;
3119 if (values
[0][0] == '*') {
3121 lower_unixname
= lower_winname
;
3123 unixname
= values
[0];
3124 lower_unixname
= NULL
;
3127 retcode
= ns_lookup_byname(unixname
, lower_unixname
,
3129 if (retcode
== IDMAP_SUCCESS
) {
3131 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
3132 if (values
[0][0] == '*') {
3134 "%s not found, continuing",
3140 "%s not found, error", unixname
);
3142 idmap_namerule_set(rule
, values
[3],
3143 values
[2], values
[0], is_user
,
3145 strtol(values
[4], &end
, 10),
3147 retcode
= IDMAP_ERR_NOMAPPING
;
3150 TRACE(req
, res
, "Looking up %s error=%d",
3154 } else if (r
== SQLITE_DONE
) {
3155 TRACE(req
, res
, "No matching rule");
3156 retcode
= IDMAP_ERR_NOTFOUND
;
3159 (void) sqlite_finalize(vm
, &errmsg
);
3161 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
3162 CHECK_NULL(errmsg
));
3163 sqlite_freemem(errmsg
);
3164 retcode
= IDMAP_ERR_INTERNAL
;
3171 if (values
[1] != NULL
)
3173 (strtol(values
[1], &end
, 10) == 0)?
3174 IDMAP_DIRECTION_W2U
:IDMAP_DIRECTION_BI
;
3176 res
->direction
= IDMAP_DIRECTION_W2U
;
3178 req
->id2name
= strdup(unixname
);
3179 if (req
->id2name
== NULL
) {
3180 retcode
= IDMAP_ERR_MEMORY
;
3183 TRACE(req
, res
, "UNIX name found");
3185 idmap_namerule_set(rule
, values
[3], values
[2],
3186 values
[0], is_user
, is_wuser
, strtol(values
[4], &end
, 10),
3190 if (retcode
!= IDMAP_SUCCESS
&&
3191 retcode
!= IDMAP_ERR_NOTFOUND
&&
3192 retcode
!= IDMAP_ERR_NOMAPPING
) {
3193 TRACE(req
, res
, "Rule processing error, code=%d", retcode
);
3197 sqlite_freemem(sql
);
3199 if (retcode
!= IDMAP_ERR_NOTFOUND
) {
3200 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_RULE_BASED
;
3201 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
3204 if (lower_winname
!= NULL
&& lower_winname
!= winname
)
3205 free(lower_winname
);
3207 (void) sqlite_finalize(vm
, NULL
);
3213 get_next_eph_uid(uid_t
*next_uid
)
3219 *next_uid
= (uid_t
)-1;
3220 uid
= _idmapdstate
.next_uid
++;
3221 if (uid
>= _idmapdstate
.limit_uid
) {
3222 if ((err
= allocids(0, 8192, &uid
, 0, &gid
)) != 0)
3225 _idmapdstate
.limit_uid
= uid
+ 8192;
3226 _idmapdstate
.next_uid
= uid
;
3235 get_next_eph_gid(gid_t
*next_gid
)
3241 *next_gid
= (uid_t
)-1;
3242 gid
= _idmapdstate
.next_gid
++;
3243 if (gid
>= _idmapdstate
.limit_gid
) {
3244 if ((err
= allocids(0, 0, &uid
, 8192, &gid
)) != 0)
3247 _idmapdstate
.limit_gid
= gid
+ 8192;
3248 _idmapdstate
.next_gid
= gid
;
3257 gethash(const char *str
, uint32_t num
, uint_t htsize
)
3259 uint_t hval
, i
, len
;
3263 for (len
= strlen(str
), hval
= 0, i
= 0; i
< len
; i
++) {
3265 hval
+= (hval
<< 10);
3266 hval
^= (hval
>> 6);
3268 for (str
= (const char *)&num
, i
= 0; i
< sizeof (num
); i
++) {
3270 hval
+= (hval
<< 10);
3271 hval
^= (hval
>> 6);
3273 hval
+= (hval
<< 3);
3274 hval
^= (hval
>> 11);
3275 hval
+= (hval
<< 15);
3276 return (hval
% htsize
);
3281 get_from_sid_history(lookup_state_t
*state
, const char *prefix
, uint32_t rid
,
3285 uint_t htsize
= state
->sid_history_size
;
3288 next
= gethash(prefix
, rid
, htsize
);
3289 while (next
!= htsize
) {
3290 key
= state
->sid_history
[next
].key
;
3293 sid
= &state
->batch
->idmap_mapping_batch_val
[key
].id1
.
3295 if (sid
->rid
== rid
&& strcmp(sid
->prefix
, prefix
) == 0) {
3296 *pid
= state
->result
->ids
.ids_val
[key
].id
.
3300 next
= state
->sid_history
[next
].next
;
3307 add_to_sid_history(lookup_state_t
*state
, const char *prefix
, uint32_t rid
)
3310 uint_t htsize
= state
->sid_history_size
;
3312 hash
= next
= gethash(prefix
, rid
, htsize
);
3313 while (state
->sid_history
[next
].key
!= htsize
) {
3317 state
->sid_history
[next
].key
= state
->curpos
;
3320 state
->sid_history
[next
].next
= state
->sid_history
[hash
].next
;
3321 state
->sid_history
[hash
].next
= next
;
3325 cleanup_lookup_state(lookup_state_t
*state
)
3327 free(state
->sid_history
);
3328 free(state
->ad_unixuser_attr
);
3329 free(state
->ad_unixgroup_attr
);
3330 free(state
->nldap_winname_attr
);
3331 free(state
->defdom
);
3337 dynamic_ephemeral_mapping(lookup_state_t
*state
,
3338 idmap_mapping
*req
, idmap_id_res
*res
)
3343 res
->direction
= IDMAP_DIRECTION_BI
;
3345 if (IDMAP_ID_IS_EPHEMERAL(res
->id
.idmap_id_u
.uid
)) {
3346 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_EPHEMERAL
;
3347 res
->info
.src
= IDMAP_MAP_SRC_CACHE
;
3348 return (IDMAP_SUCCESS
);
3351 if (state
->sid_history
!= NULL
&&
3352 get_from_sid_history(state
, req
->id1
.idmap_id_u
.sid
.prefix
,
3353 req
->id1
.idmap_id_u
.sid
.rid
, &next_pid
)) {
3354 res
->id
.idmap_id_u
.uid
= next_pid
;
3355 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_EPHEMERAL
;
3356 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
3357 return (IDMAP_SUCCESS
);
3360 if (res
->id
.idtype
== IDMAP_UID
) {
3361 if (get_next_eph_uid(&next_pid
) != 0)
3362 return (IDMAP_ERR_INTERNAL
);
3363 res
->id
.idmap_id_u
.uid
= next_pid
;
3365 if (get_next_eph_gid(&next_pid
) != 0)
3366 return (IDMAP_ERR_INTERNAL
);
3367 res
->id
.idmap_id_u
.gid
= next_pid
;
3370 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_EPHEMERAL
;
3371 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
3372 if (state
->sid_history
!= NULL
)
3373 add_to_sid_history(state
, req
->id1
.idmap_id_u
.sid
.prefix
,
3374 req
->id1
.idmap_id_u
.sid
.rid
);
3376 return (IDMAP_SUCCESS
);
3380 sid2pid_second_pass(lookup_state_t
*state
,
3381 idmap_mapping
*req
, idmap_id_res
*res
)
3383 idmap_retcode retcode
;
3384 idmap_retcode retcode2
;
3386 /* Check if second pass is needed */
3387 if (ARE_WE_DONE(req
->direction
))
3388 return (res
->retcode
);
3390 /* Get status from previous pass */
3391 retcode
= res
->retcode
;
3392 if (retcode
!= IDMAP_SUCCESS
&& state
->eph_map_unres_sids
&&
3393 !EMPTY_STRING(req
->id1
.idmap_id_u
.sid
.prefix
) &&
3394 EMPTY_STRING(req
->id1name
)) {
3396 * We are asked to map an unresolvable SID to a UID or
3397 * GID, but, which? We'll treat all unresolvable SIDs
3398 * as users unless the caller specified which of a UID
3401 if (req
->id1
.idtype
== IDMAP_SID
)
3402 req
->id1
.idtype
= IDMAP_USID
;
3403 if (res
->id
.idtype
== IDMAP_POSIXID
) {
3404 res
->id
.idtype
= IDMAP_UID
;
3405 TRACE(req
, res
, "Assume unresolvable SID is user");
3406 } else if (res
->id
.idtype
== IDMAP_UID
) {
3407 TRACE(req
, res
, "Must map unresolvable SID to user");
3408 } else if (res
->id
.idtype
== IDMAP_GID
) {
3409 TRACE(req
, res
, "Must map unresolvable SID to group");
3413 if (retcode
!= IDMAP_SUCCESS
)
3417 * There are two ways we might get here with a Posix ID:
3418 * - It could be from an expired ephemeral cache entry.
3419 * - It could be from IDMU.
3420 * If it's from IDMU, we need to look up the name, for name-based
3421 * requests and the cache.
3423 if (!IDMAP_ID_IS_EPHEMERAL(res
->id
.idmap_id_u
.uid
) &&
3424 res
->id
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
) {
3425 if (req
->id2name
== NULL
) {
3427 * If the lookup fails, go ahead anyway.
3428 * The general UNIX rule is that it's OK to
3429 * have a UID or GID that isn't in the
3432 retcode2
= ns_lookup_bypid(res
->id
.idmap_id_u
.uid
,
3433 res
->id
.idtype
== IDMAP_UID
, &req
->id2name
);
3434 if (IDMAP_ERROR(retcode2
)) {
3436 "Getting UNIX name, error=%d (ignored)",
3439 TRACE(req
, res
, "Found UNIX name");
3446 * If directory-based name mapping is enabled then the unixname
3447 * may already have been retrieved from the AD object (AD-mode or
3448 * mixed-mode) or from native LDAP object (nldap-mode) -- done.
3450 if (req
->id2name
!= NULL
) {
3451 assert(res
->id
.idtype
!= IDMAP_POSIXID
);
3452 if (AD_MODE(res
->id
.idtype
, state
))
3453 res
->direction
= IDMAP_DIRECTION_BI
;
3454 else if (NLDAP_MODE(res
->id
.idtype
, state
))
3455 res
->direction
= IDMAP_DIRECTION_BI
;
3456 else if (MIXED_MODE(res
->id
.idtype
, state
))
3457 res
->direction
= IDMAP_DIRECTION_W2U
;
3460 * Special case: (1) If the ad_unixuser_attr and
3461 * ad_unixgroup_attr uses the same attribute
3462 * name and (2) if this is a diagonal mapping
3463 * request and (3) the unixname has been retrieved
3464 * from the AD object -- then we ignore it and fallback
3465 * to name-based mapping rules and ephemeral mapping
3469 * config/ad_unixuser_attr = "unixname"
3470 * config/ad_unixgroup_attr = "unixname"
3477 * dn: cn=winadmins ...
3478 * objectclass: group
3480 * unixname: unixadmins
3482 * In this example whether "unixname" refers to a unixuser
3483 * or unixgroup depends upon the AD object.
3485 * $idmap show -c winname:bob gid
3486 * AD lookup by "samAccountName=bob" for
3487 * "ad_unixgroup_attr (i.e unixname)" for directory-based
3488 * mapping would get "bob1234" which is not what we want.
3489 * Now why not getgrnam_r("bob1234") and use it if it
3490 * is indeed a unixgroup? That's because Unix can have
3491 * users and groups with the same name and we clearly
3492 * don't know the intention of the admin here.
3493 * Therefore we ignore this and fallback to name-based
3494 * mapping rules or ephemeral mapping.
3496 if ((AD_MODE(res
->id
.idtype
, state
) ||
3497 MIXED_MODE(res
->id
.idtype
, state
)) &&
3498 state
->ad_unixuser_attr
!= NULL
&&
3499 state
->ad_unixgroup_attr
!= NULL
&&
3500 strcasecmp(state
->ad_unixuser_attr
,
3501 state
->ad_unixgroup_attr
) == 0 &&
3502 ((req
->id1
.idtype
== IDMAP_USID
&&
3503 res
->id
.idtype
== IDMAP_GID
) ||
3504 (req
->id1
.idtype
== IDMAP_GSID
&&
3505 res
->id
.idtype
== IDMAP_UID
))) {
3506 TRACE(req
, res
, "Ignoring UNIX name found in AD");
3508 req
->id2name
= NULL
;
3509 res
->id
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
3512 if (res
->id
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) {
3513 retcode
= ns_lookup_byname(req
->id2name
,
3515 if (retcode
!= IDMAP_SUCCESS
) {
3517 * If ns_lookup_byname() fails that
3518 * means the unixname (req->id2name),
3519 * which was obtained from the AD
3520 * object by directory-based mapping,
3521 * is not a valid Unix user/group and
3522 * therefore we return the error to the
3523 * client instead of doing rule-based
3524 * mapping or ephemeral mapping. This
3525 * way the client can detect the issue.
3528 "UNIX lookup error=%d", retcode
);
3531 TRACE(req
, res
, "UNIX lookup");
3537 /* Free any mapping info from Directory based mapping */
3538 if (res
->info
.how
.map_type
!= IDMAP_MAP_TYPE_UNKNOWN
)
3539 idmap_how_clear(&res
->info
.how
);
3542 * If we don't have unixname then evaluate local name-based
3545 retcode
= name_based_mapping_sid2pid(state
, req
, res
);
3546 if (retcode
== IDMAP_SUCCESS
) {
3547 TRACE(req
, res
, "Rule-based mapping");
3549 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
3550 TRACE(req
, res
, "Rule-based mapping error=%d", retcode
);
3555 /* If not found, do ephemeral mapping */
3556 retcode
= dynamic_ephemeral_mapping(state
, req
, res
);
3557 if (retcode
== IDMAP_SUCCESS
) {
3558 TRACE(req
, res
, "Ephemeral mapping");
3560 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
3561 TRACE(req
, res
, "Ephemeral mapping error=%d", retcode
);
3566 res
->retcode
= idmap_stat4prot(retcode
);
3567 if (res
->retcode
!= IDMAP_SUCCESS
) {
3568 req
->direction
= _IDMAP_F_DONE
;
3569 res
->id
.idmap_id_u
.uid
= UID_NOBODY
;
3571 if (!ARE_WE_DONE(req
->direction
))
3572 state
->sid2pid_done
= FALSE
;
3577 update_cache_pid2sid(lookup_state_t
*state
,
3578 idmap_mapping
*req
, idmap_id_res
*res
)
3581 idmap_retcode retcode
;
3582 idmap_retcode retcode2
;
3583 char *map_dn
= NULL
;
3584 char *map_attr
= NULL
;
3585 char *map_value
= NULL
;
3586 char *map_windomain
= NULL
;
3587 char *map_winname
= NULL
;
3588 char *map_unixname
= NULL
;
3589 int map_is_nt4
= FALSE
;
3591 /* Check if we need to cache anything */
3592 if (ARE_WE_DONE(req
->direction
))
3593 return (IDMAP_SUCCESS
);
3595 /* We don't cache negative entries */
3596 if (res
->retcode
!= IDMAP_SUCCESS
)
3597 return (IDMAP_SUCCESS
);
3599 assert(res
->direction
!= IDMAP_DIRECTION_UNDEF
);
3600 assert(req
->id1
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
);
3601 assert(res
->id
.idtype
!= IDMAP_SID
);
3604 * If we've gotten to this point and we *still* don't know the
3605 * unixname, well, we'd like to have it now for the cache.
3607 * If we truly always need it for the cache, we should probably
3608 * look it up once at the beginning, rather than "at need" in
3609 * several places as is now done. However, it's not really clear
3610 * that we *do* need it in the cache; there's a decent argument
3611 * that the cache should contain only SIDs and PIDs, so we'll
3612 * leave our options open by doing it "at need" here too.
3614 * If we can't find it... c'est la vie.
3616 if (req
->id1name
== NULL
) {
3617 retcode2
= ns_lookup_bypid(req
->id1
.idmap_id_u
.uid
,
3618 req
->id1
.idtype
== IDMAP_UID
, &req
->id1name
);
3619 if (retcode2
== IDMAP_SUCCESS
)
3620 TRACE(req
, res
, "Found UNIX name");
3622 TRACE(req
, res
, "Getting UNIX name error=%d", retcode2
);
3625 assert(res
->info
.how
.map_type
!= IDMAP_MAP_TYPE_UNKNOWN
);
3626 switch (res
->info
.how
.map_type
) {
3627 case IDMAP_MAP_TYPE_DS_AD
:
3628 map_dn
= res
->info
.how
.idmap_how_u
.ad
.dn
;
3629 map_attr
= res
->info
.how
.idmap_how_u
.ad
.attr
;
3630 map_value
= res
->info
.how
.idmap_how_u
.ad
.value
;
3633 case IDMAP_MAP_TYPE_DS_NLDAP
:
3634 map_dn
= res
->info
.how
.idmap_how_u
.nldap
.dn
;
3635 map_attr
= res
->info
.how
.idmap_how_u
.nldap
.attr
;
3636 map_value
= res
->info
.how
.idmap_how_u
.nldap
.value
;
3639 case IDMAP_MAP_TYPE_RULE_BASED
:
3640 map_windomain
= res
->info
.how
.idmap_how_u
.rule
.windomain
;
3641 map_winname
= res
->info
.how
.idmap_how_u
.rule
.winname
;
3642 map_unixname
= res
->info
.how
.idmap_how_u
.rule
.unixname
;
3643 map_is_nt4
= res
->info
.how
.idmap_how_u
.rule
.is_nt4
;
3646 case IDMAP_MAP_TYPE_EPHEMERAL
:
3649 case IDMAP_MAP_TYPE_LOCAL_SID
:
3652 case IDMAP_MAP_TYPE_IDMU
:
3653 map_dn
= res
->info
.how
.idmap_how_u
.idmu
.dn
;
3654 map_attr
= res
->info
.how
.idmap_how_u
.idmu
.attr
;
3655 map_value
= res
->info
.how
.idmap_how_u
.idmu
.value
;
3659 /* Don't cache other mapping types */
3664 * Using NULL for u2w instead of 0 so that our trigger allows
3665 * the same pid to be the destination in multiple entries
3667 sql
= sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3668 "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3669 "is_user, is_wuser, expiration, w2u, u2w, "
3670 "map_type, map_dn, map_attr, map_value, map_windomain, "
3671 "map_winname, map_unixname, map_is_nt4) "
3672 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3673 "strftime('%%s','now') + %u, %q, 1, "
3674 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d); ",
3675 res
->id
.idmap_id_u
.sid
.prefix
, res
->id
.idmap_id_u
.sid
.rid
,
3676 req
->id2domain
, req
->id2name
, req
->id1
.idmap_id_u
.uid
,
3677 req
->id1name
, (req
->id1
.idtype
== IDMAP_UID
) ? 1 : 0,
3678 (res
->id
.idtype
== IDMAP_USID
) ? 1 : 0,
3679 state
->id_cache_timeout
,
3680 (res
->direction
== 0) ? "1" : NULL
,
3681 res
->info
.how
.map_type
, map_dn
, map_attr
, map_value
,
3682 map_windomain
, map_winname
, map_unixname
, map_is_nt4
);
3685 retcode
= IDMAP_ERR_INTERNAL
;
3686 idmapdlog(LOG_ERR
, "Out of memory");
3690 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3691 if (retcode
!= IDMAP_SUCCESS
)
3694 state
->pid2sid_done
= FALSE
;
3695 sqlite_freemem(sql
);
3698 /* Check if we need to update namecache */
3699 if (req
->direction
& _IDMAP_F_DONT_UPDATE_NAMECACHE
)
3702 if (req
->id2name
== NULL
)
3705 sql
= sqlite_mprintf("INSERT OR REPLACE into name_cache "
3706 "(sidprefix, rid, canon_name, domain, type, expiration) "
3707 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + %u); ",
3708 res
->id
.idmap_id_u
.sid
.prefix
, res
->id
.idmap_id_u
.sid
.rid
,
3709 req
->id2name
, req
->id2domain
,
3710 res
->id
.idtype
, state
->name_cache_timeout
);
3713 retcode
= IDMAP_ERR_INTERNAL
;
3714 idmapdlog(LOG_ERR
, "Out of memory");
3718 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3722 sqlite_freemem(sql
);
3727 update_cache_sid2pid(lookup_state_t
*state
,
3728 idmap_mapping
*req
, idmap_id_res
*res
)
3731 idmap_retcode retcode
;
3733 char *map_dn
= NULL
;
3734 char *map_attr
= NULL
;
3735 char *map_value
= NULL
;
3736 char *map_windomain
= NULL
;
3737 char *map_winname
= NULL
;
3738 char *map_unixname
= NULL
;
3739 int map_is_nt4
= FALSE
;
3741 /* Check if we need to cache anything */
3742 if (ARE_WE_DONE(req
->direction
))
3743 return (IDMAP_SUCCESS
);
3745 /* We don't cache negative entries */
3746 if (res
->retcode
!= IDMAP_SUCCESS
)
3747 return (IDMAP_SUCCESS
);
3749 if (req
->direction
& _IDMAP_F_EXP_EPH_UID
)
3751 else if (req
->direction
& _IDMAP_F_EXP_EPH_GID
)
3756 if (is_eph_user
>= 0 &&
3757 !IDMAP_ID_IS_EPHEMERAL(res
->id
.idmap_id_u
.uid
)) {
3758 sql
= sqlite_mprintf("UPDATE idmap_cache "
3759 "SET w2u = 0 WHERE "
3760 "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
3761 "pid >= 2147483648 AND is_user = %d;",
3762 req
->id1
.idmap_id_u
.sid
.prefix
,
3763 req
->id1
.idmap_id_u
.sid
.rid
,
3766 retcode
= IDMAP_ERR_INTERNAL
;
3767 idmapdlog(LOG_ERR
, "Out of memory");
3771 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3772 if (retcode
!= IDMAP_SUCCESS
)
3775 sqlite_freemem(sql
);
3779 assert(res
->direction
!= IDMAP_DIRECTION_UNDEF
);
3780 assert(res
->id
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
);
3782 switch (res
->info
.how
.map_type
) {
3783 case IDMAP_MAP_TYPE_DS_AD
:
3784 map_dn
= res
->info
.how
.idmap_how_u
.ad
.dn
;
3785 map_attr
= res
->info
.how
.idmap_how_u
.ad
.attr
;
3786 map_value
= res
->info
.how
.idmap_how_u
.ad
.value
;
3789 case IDMAP_MAP_TYPE_DS_NLDAP
:
3790 map_dn
= res
->info
.how
.idmap_how_u
.nldap
.dn
;
3791 map_attr
= res
->info
.how
.idmap_how_u
.ad
.attr
;
3792 map_value
= res
->info
.how
.idmap_how_u
.nldap
.value
;
3795 case IDMAP_MAP_TYPE_RULE_BASED
:
3796 map_windomain
= res
->info
.how
.idmap_how_u
.rule
.windomain
;
3797 map_winname
= res
->info
.how
.idmap_how_u
.rule
.winname
;
3798 map_unixname
= res
->info
.how
.idmap_how_u
.rule
.unixname
;
3799 map_is_nt4
= res
->info
.how
.idmap_how_u
.rule
.is_nt4
;
3802 case IDMAP_MAP_TYPE_EPHEMERAL
:
3805 case IDMAP_MAP_TYPE_IDMU
:
3806 map_dn
= res
->info
.how
.idmap_how_u
.idmu
.dn
;
3807 map_attr
= res
->info
.how
.idmap_how_u
.idmu
.attr
;
3808 map_value
= res
->info
.how
.idmap_how_u
.idmu
.value
;
3812 /* Don't cache other mapping types */
3816 sql
= sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3817 "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3818 "is_user, is_wuser, expiration, w2u, u2w, "
3819 "map_type, map_dn, map_attr, map_value, map_windomain, "
3820 "map_winname, map_unixname, map_is_nt4) "
3821 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3822 "strftime('%%s','now') + %u, 1, %q, "
3823 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d);",
3824 req
->id1
.idmap_id_u
.sid
.prefix
, req
->id1
.idmap_id_u
.sid
.rid
,
3825 (req
->id1domain
!= NULL
) ? req
->id1domain
: "", req
->id1name
,
3826 res
->id
.idmap_id_u
.uid
, req
->id2name
,
3827 (res
->id
.idtype
== IDMAP_UID
) ? 1 : 0,
3828 (req
->id1
.idtype
== IDMAP_USID
) ? 1 : 0,
3829 state
->id_cache_timeout
,
3830 (res
->direction
== 0) ? "1" : NULL
,
3831 res
->info
.how
.map_type
, map_dn
, map_attr
, map_value
,
3832 map_windomain
, map_winname
, map_unixname
, map_is_nt4
);
3835 retcode
= IDMAP_ERR_INTERNAL
;
3836 idmapdlog(LOG_ERR
, "Out of memory");
3840 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3841 if (retcode
!= IDMAP_SUCCESS
)
3844 state
->sid2pid_done
= FALSE
;
3845 sqlite_freemem(sql
);
3848 /* Check if we need to update namecache */
3849 if (req
->direction
& _IDMAP_F_DONT_UPDATE_NAMECACHE
)
3852 if (EMPTY_STRING(req
->id1name
))
3855 sql
= sqlite_mprintf("INSERT OR REPLACE into name_cache "
3856 "(sidprefix, rid, canon_name, domain, type, expiration) "
3857 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + %u); ",
3858 req
->id1
.idmap_id_u
.sid
.prefix
, req
->id1
.idmap_id_u
.sid
.rid
,
3859 req
->id1name
, req
->id1domain
,
3860 req
->id1
.idtype
, state
->name_cache_timeout
);
3863 retcode
= IDMAP_ERR_INTERNAL
;
3864 idmapdlog(LOG_ERR
, "Out of memory");
3868 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3872 sqlite_freemem(sql
);
3878 lookup_cache_pid2sid(sqlite
*cache
, idmap_mapping
*req
, idmap_id_res
*res
,
3883 const char **values
;
3884 sqlite_vm
*vm
= NULL
;
3886 idmap_retcode retcode
= IDMAP_SUCCESS
;
3888 idmap_id_type idtype
;
3892 if ((curtime
= time(NULL
)) == (time_t)-1) {
3893 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
3895 retcode
= IDMAP_ERR_INTERNAL
;
3899 /* SQL to lookup the cache by pid or by unixname */
3900 if (req
->id1
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
) {
3901 sql
= sqlite_mprintf("SELECT sidprefix, rid, "
3902 "canon_winname, windomain, w2u, is_wuser, "
3903 "map_type, map_dn, map_attr, map_value, map_windomain, "
3904 "map_winname, map_unixname, map_is_nt4 "
3905 "FROM idmap_cache WHERE "
3906 "pid = %u AND u2w = 1 AND is_user = %d AND "
3907 "(pid >= 2147483648 OR "
3908 "(expiration = 0 OR expiration ISNULL OR "
3909 "expiration > %d));",
3910 req
->id1
.idmap_id_u
.uid
, is_user
, curtime
);
3911 } else if (req
->id1name
!= NULL
) {
3912 sql
= sqlite_mprintf("SELECT sidprefix, rid, "
3913 "canon_winname, windomain, w2u, is_wuser, "
3914 "map_type, map_dn, map_attr, map_value, map_windomain, "
3915 "map_winname, map_unixname, map_is_nt4 "
3916 "FROM idmap_cache WHERE "
3917 "unixname = %Q AND u2w = 1 AND is_user = %d AND "
3918 "(pid >= 2147483648 OR "
3919 "(expiration = 0 OR expiration ISNULL OR "
3920 "expiration > %d));",
3921 req
->id1name
, is_user
, curtime
);
3923 retcode
= IDMAP_ERR_ARG
;
3928 idmapdlog(LOG_ERR
, "Out of memory");
3929 retcode
= IDMAP_ERR_MEMORY
;
3932 retcode
= sql_compile_n_step_once(
3933 cache
, sql
, &vm
, &ncol
, 14, &values
);
3934 sqlite_freemem(sql
);
3936 if (retcode
== IDMAP_ERR_NOTFOUND
)
3938 else if (retcode
== IDMAP_SUCCESS
) {
3940 if (values
[0] == NULL
|| values
[1] == NULL
) {
3941 retcode
= IDMAP_ERR_CACHE
;
3945 switch (res
->id
.idtype
) {
3949 idtype
= strtol(values
[5], &end
, 10) == 1
3950 ? IDMAP_USID
: IDMAP_GSID
;
3952 if (res
->id
.idtype
== IDMAP_USID
&&
3953 idtype
!= IDMAP_USID
) {
3954 retcode
= IDMAP_ERR_NOTUSER
;
3956 } else if (res
->id
.idtype
== IDMAP_GSID
&&
3957 idtype
!= IDMAP_GSID
) {
3958 retcode
= IDMAP_ERR_NOTGROUP
;
3961 res
->id
.idtype
= idtype
;
3963 res
->id
.idmap_id_u
.sid
.rid
=
3964 strtoul(values
[1], &end
, 10);
3965 res
->id
.idmap_id_u
.sid
.prefix
= strdup(values
[0]);
3966 if (res
->id
.idmap_id_u
.sid
.prefix
== NULL
) {
3967 idmapdlog(LOG_ERR
, "Out of memory");
3968 retcode
= IDMAP_ERR_MEMORY
;
3972 if (values
[4] != NULL
)
3974 (strtol(values
[4], &end
, 10) == 0)?
3975 IDMAP_DIRECTION_U2W
:IDMAP_DIRECTION_BI
;
3977 res
->direction
= IDMAP_DIRECTION_U2W
;
3979 if (values
[2] == NULL
)
3981 req
->id2name
= strdup(values
[2]);
3982 if (req
->id2name
== NULL
) {
3983 idmapdlog(LOG_ERR
, "Out of memory");
3984 retcode
= IDMAP_ERR_MEMORY
;
3988 if (values
[3] == NULL
)
3990 req
->id2domain
= strdup(values
[3]);
3991 if (req
->id2domain
== NULL
) {
3992 idmapdlog(LOG_ERR
, "Out of memory");
3993 retcode
= IDMAP_ERR_MEMORY
;
3999 retcode
= IDMAP_ERR_NOTSUPPORTED
;
4002 if (req
->flag
& IDMAP_REQ_FLG_MAPPING_INFO
) {
4003 res
->info
.src
= IDMAP_MAP_SRC_CACHE
;
4004 res
->info
.how
.map_type
= strtoul(values
[6], &end
, 10);
4005 switch (res
->info
.how
.map_type
) {
4006 case IDMAP_MAP_TYPE_DS_AD
:
4007 res
->info
.how
.idmap_how_u
.ad
.dn
=
4009 res
->info
.how
.idmap_how_u
.ad
.attr
=
4011 res
->info
.how
.idmap_how_u
.ad
.value
=
4015 case IDMAP_MAP_TYPE_DS_NLDAP
:
4016 res
->info
.how
.idmap_how_u
.nldap
.dn
=
4018 res
->info
.how
.idmap_how_u
.nldap
.attr
=
4020 res
->info
.how
.idmap_how_u
.nldap
.value
=
4024 case IDMAP_MAP_TYPE_RULE_BASED
:
4025 res
->info
.how
.idmap_how_u
.rule
.windomain
=
4027 res
->info
.how
.idmap_how_u
.rule
.winname
=
4029 res
->info
.how
.idmap_how_u
.rule
.unixname
=
4031 res
->info
.how
.idmap_how_u
.rule
.is_nt4
=
4032 strtoul(values
[13], &end
, 10);
4033 res
->info
.how
.idmap_how_u
.rule
.is_user
=
4035 res
->info
.how
.idmap_how_u
.rule
.is_wuser
=
4036 strtol(values
[5], &end
, 10);
4039 case IDMAP_MAP_TYPE_EPHEMERAL
:
4042 case IDMAP_MAP_TYPE_LOCAL_SID
:
4045 case IDMAP_MAP_TYPE_KNOWN_SID
:
4048 case IDMAP_MAP_TYPE_IDMU
:
4049 res
->info
.how
.idmap_how_u
.idmu
.dn
=
4051 res
->info
.how
.idmap_how_u
.idmu
.attr
=
4053 res
->info
.how
.idmap_how_u
.idmu
.value
=
4058 /* Unknown mapping type */
4066 (void) sqlite_finalize(vm
, NULL
);
4072 * cache sqlite handle
4073 * name Windows user name
4074 * domain Windows domain name
4076 * Return: Error code
4078 * *canonname Canonical name (if canonname is non-NULL) [1]
4079 * *sidprefix SID prefix [1]
4081 * *type Type of name
4083 * [1] malloc'ed, NULL on error
4087 lookup_cache_name2sid(
4094 idmap_id_type
*type
)
4096 char *end
, *lower_name
;
4098 const char **values
;
4099 sqlite_vm
*vm
= NULL
;
4102 idmap_retcode retcode
;
4105 if (canonname
!= NULL
)
4108 /* Get current time */
4110 if ((curtime
= time(NULL
)) == (time_t)-1) {
4111 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
4113 retcode
= IDMAP_ERR_INTERNAL
;
4117 /* SQL to lookup the cache */
4118 if ((lower_name
= tolower_u8(name
)) == NULL
)
4119 lower_name
= (char *)name
;
4120 sql
= sqlite_mprintf("SELECT sidprefix, rid, type, canon_name "
4121 "FROM name_cache WHERE name = %Q AND domain = %Q AND "
4122 "(expiration = 0 OR expiration ISNULL OR "
4123 "expiration > %d);", lower_name
, domain
, curtime
);
4124 if (lower_name
!= name
)
4127 idmapdlog(LOG_ERR
, "Out of memory");
4128 retcode
= IDMAP_ERR_MEMORY
;
4131 retcode
= sql_compile_n_step_once(cache
, sql
, &vm
, &ncol
, 4, &values
);
4133 sqlite_freemem(sql
);
4135 if (retcode
!= IDMAP_SUCCESS
)
4139 if (values
[2] == NULL
) {
4140 retcode
= IDMAP_ERR_CACHE
;
4143 *type
= xlate_legacy_type(strtol(values
[2], &end
, 10));
4146 if (values
[0] == NULL
|| values
[1] == NULL
) {
4147 retcode
= IDMAP_ERR_CACHE
;
4151 if (canonname
!= NULL
) {
4152 assert(values
[3] != NULL
);
4153 *canonname
= strdup(values
[3]);
4154 if (*canonname
== NULL
) {
4155 idmapdlog(LOG_ERR
, "Out of memory");
4156 retcode
= IDMAP_ERR_MEMORY
;
4161 *sidprefix
= strdup(values
[0]);
4162 if (*sidprefix
== NULL
) {
4163 idmapdlog(LOG_ERR
, "Out of memory");
4164 retcode
= IDMAP_ERR_MEMORY
;
4167 *rid
= strtoul(values
[1], &end
, 10);
4169 retcode
= IDMAP_SUCCESS
;
4173 (void) sqlite_finalize(vm
, NULL
);
4175 if (retcode
!= IDMAP_SUCCESS
) {
4178 if (canonname
!= NULL
) {
4188 ad_lookup_by_winname(lookup_state_t
*state
,
4189 const char *name
, const char *domain
, int esidtype
,
4190 char **dn
, char **attr
, char **value
, char **canonname
,
4191 char **sidprefix
, idmap_rid_t
*rid
, idmap_id_type
*wintype
,
4195 idmap_query_state_t
*qs
= NULL
;
4196 idmap_retcode rc
, retcode
;
4201 if (_idmapdstate
.num_gcs
> 0) {
4202 for (i
= 0; i
< _idmapdstate
.num_gcs
&& !found_ad
; i
++) {
4205 retcode
= idmap_lookup_batch_start(
4206 _idmapdstate
.gcs
[i
],
4208 _idmapdstate
.cfg
->pgcfg
.directory_based_mapping
,
4209 _idmapdstate
.cfg
->pgcfg
.default_domain
,
4211 if (retcode
!= IDMAP_SUCCESS
) {
4212 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
4213 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
4215 degrade_svc(1, "failed to create request for "
4216 "AD lookup by winname");
4222 if (state
!= NULL
&& i
== 0) {
4224 * Directory based name mapping is only
4225 * performed within the joined forest (i == 0).
4226 * We don't trust other "trusted" forests to
4227 * provide DS-based name mapping information
4228 * because AD's definition of "cross-forest
4229 * trust" does not encompass this sort of
4232 idmap_lookup_batch_set_unixattr(qs
,
4233 state
->ad_unixuser_attr
,
4234 state
->ad_unixgroup_attr
);
4237 retcode
= idmap_name2sid_batch_add1(qs
, name
, domain
,
4238 esidtype
, dn
, attr
, value
, canonname
, sidprefix
,
4239 rid
, wintype
, unixname
, NULL
, &rc
);
4240 if (retcode
== IDMAP_ERR_DOMAIN_NOTFOUND
) {
4241 idmap_lookup_release_batch(&qs
);
4245 if (retcode
!= IDMAP_SUCCESS
)
4246 idmap_lookup_release_batch(&qs
);
4248 retcode
= idmap_lookup_batch_end(&qs
);
4250 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
4251 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
4253 else if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
)
4255 "some AD lookups timed out repeatedly");
4259 retcode
= IDMAP_ERR_NO_ACTIVEDIRECTORY
;
4263 if (retcode
!= IDMAP_SUCCESS
) {
4264 idmapdlog(LOG_NOTICE
,
4265 "AD lookup of winname %s@%s failed, error code %d",
4266 name
== NULL
? "(null)" : name
,
4267 domain
== NULL
? "(null)" : domain
,
4276 * cache sqlite handle to cache
4277 * name Windows user name
4278 * domain Windows domain name
4279 * local_only if true, don't try AD lookups
4281 * Returns: Error code
4283 * *canonname Canonical name (if non-NULL) [1]
4284 * *canondomain Canonical domain (if non-NULL) [1]
4285 * *sidprefix SID prefix [1]
4287 * *req Request (direction is updated)
4289 * [1] malloc'ed, NULL on error
4301 idmap_id_type
*type
,
4305 idmap_retcode retcode
;
4308 if (canonname
!= NULL
)
4310 if (canondomain
!= NULL
)
4311 *canondomain
= NULL
;
4313 /* Lookup well-known SIDs table */
4314 retcode
= lookup_wksids_name2sid(name
, domain
, canonname
, canondomain
,
4315 sidprefix
, rid
, type
);
4316 if (retcode
== IDMAP_SUCCESS
) {
4317 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
4319 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4324 retcode
= lookup_cache_name2sid(cache
, name
, domain
, canonname
,
4325 sidprefix
, rid
, type
);
4326 if (retcode
== IDMAP_SUCCESS
) {
4327 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
4329 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4334 * The caller may be using this function to determine if this
4335 * request needs to be marked for AD lookup or not
4336 * (i.e. _IDMAP_F_LOOKUP_AD) and therefore may not want this
4337 * function to AD lookup now.
4342 if (_idmapdstate
.cfg
->pgcfg
.use_lsa
&&
4343 _idmapdstate
.cfg
->pgcfg
.domain_name
!= NULL
&&
4344 name
!= NULL
&& *sidprefix
== NULL
) {
4345 retcode
= lookup_lsa_by_name(name
, domain
,
4347 canonname
, canondomain
,
4349 if (retcode
== IDMAP_SUCCESS
)
4351 else if (retcode
!= IDMAP_ERR_NOTFOUND
)
4356 retcode
= ad_lookup_by_winname(NULL
, name
, domain
, IDMAP_POSIXID
,
4357 NULL
, NULL
, NULL
, canonname
, sidprefix
, rid
, type
, NULL
);
4358 if (retcode
!= IDMAP_SUCCESS
)
4363 * Entry found (cache or Windows lookup)
4365 if (want_wuser
== 1 && *type
!= IDMAP_USID
)
4366 retcode
= IDMAP_ERR_NOTUSER
;
4367 else if (want_wuser
== 0 && *type
!= IDMAP_GSID
)
4368 retcode
= IDMAP_ERR_NOTGROUP
;
4369 else if (want_wuser
== -1) {
4371 * Caller wants to know if its user or group
4372 * Verify that it's one or the other.
4374 if (*type
!= IDMAP_USID
&& *type
!= IDMAP_GSID
)
4375 retcode
= IDMAP_ERR_SID
;
4378 if (retcode
== IDMAP_SUCCESS
) {
4380 * If we were asked for a canonical domain and none
4381 * of the searches have provided one, assume it's the
4384 if (canondomain
!= NULL
&& *canondomain
== NULL
) {
4385 *canondomain
= strdup(domain
);
4386 if (*canondomain
== NULL
)
4387 retcode
= IDMAP_ERR_MEMORY
;
4390 if (retcode
!= IDMAP_SUCCESS
) {
4393 if (canonname
!= NULL
) {
4397 if (canondomain
!= NULL
) {
4399 *canondomain
= NULL
;
4407 name_based_mapping_pid2sid(lookup_state_t
*state
, const char *unixname
,
4408 int is_user
, idmap_mapping
*req
, idmap_id_res
*res
)
4410 const char *winname
, *windomain
;
4413 char *sql
= NULL
, *errmsg
= NULL
;
4414 idmap_retcode retcode
;
4416 const char **values
;
4417 sqlite_vm
*vm
= NULL
;
4420 const char *me
= "name_based_mapping_pid2sid";
4421 idmap_namerule
*rule
= &res
->info
.how
.idmap_how_u
.rule
;
4424 assert(unixname
!= NULL
); /* We have unixname */
4425 assert(req
->id2name
== NULL
); /* We don't have winname */
4426 assert(res
->id
.idmap_id_u
.sid
.prefix
== NULL
); /* No SID either */
4428 sql
= sqlite_mprintf(
4429 "SELECT winname_display, windomain, w2u_order, "
4430 "is_wuser, unixname, is_nt4 "
4431 "FROM namerules WHERE "
4432 "u2w_order > 0 AND is_user = %d AND "
4433 "(unixname = %Q OR unixname = '*') "
4434 "ORDER BY u2w_order ASC;", is_user
, unixname
);
4436 idmapdlog(LOG_ERR
, "Out of memory");
4437 retcode
= IDMAP_ERR_MEMORY
;
4441 if (sqlite_compile(state
->db
, sql
, NULL
, &vm
, &errmsg
) != SQLITE_OK
) {
4442 retcode
= IDMAP_ERR_INTERNAL
;
4443 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
4444 CHECK_NULL(errmsg
));
4445 sqlite_freemem(errmsg
);
4450 r
= sqlite_step(vm
, &ncol
, &values
, NULL
);
4451 assert(r
!= SQLITE_LOCKED
&& r
!= SQLITE_BUSY
);
4452 if (r
== SQLITE_ROW
) {
4454 retcode
= IDMAP_ERR_INTERNAL
;
4458 TRACE(req
, res
, "Matching rule: %s -> %s@%s",
4459 values
[4] == NULL
? "(null)" : values
[4],
4460 values
[0] == NULL
? "(null)" : values
[0],
4461 values
[1] == NULL
? "(null)" : values
[1]);
4463 if (values
[0] == NULL
) {
4464 /* values [1] and [2] can be null */
4465 retcode
= IDMAP_ERR_INTERNAL
;
4469 if (values
[2] != NULL
)
4471 (strtol(values
[2], &end
, 10) == 0)?
4472 IDMAP_DIRECTION_U2W
:IDMAP_DIRECTION_BI
;
4474 direction
= IDMAP_DIRECTION_U2W
;
4476 if (EMPTY_NAME(values
[0])) {
4477 idmap_namerule_set(rule
, values
[1], values
[0],
4479 strtol(values
[3], &end
, 10),
4480 strtol(values
[5], &end
, 10),
4482 TRACE(req
, res
, "Mapping inhibited");
4483 retcode
= IDMAP_ERR_NOMAPPING
;
4487 if (values
[0][0] == '*') {
4490 winname
= values
[0];
4493 want_wuser
= res
->id
.idtype
== IDMAP_USID
? 1
4494 : res
->id
.idtype
== IDMAP_GSID
? 0
4496 if (values
[1] != NULL
)
4497 windomain
= values
[1];
4498 else if (state
->defdom
!= NULL
) {
4499 windomain
= state
->defdom
;
4501 "Added default domain %s to rule",
4504 idmapdlog(LOG_ERR
, "%s: no domain", me
);
4506 "No domain in rule, and no default domain");
4507 retcode
= IDMAP_ERR_DOMAIN_NOTFOUND
;
4511 retcode
= lookup_name2sid(state
->cache
,
4513 want_wuser
, &canonname
, &canondomain
,
4514 &res
->id
.idmap_id_u
.sid
.prefix
,
4515 &res
->id
.idmap_id_u
.sid
.rid
,
4516 &res
->id
.idtype
, req
, 0);
4518 if (retcode
== IDMAP_SUCCESS
) {
4520 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
4521 if (values
[0][0] == '*') {
4523 "%s@%s not found, continuing",
4524 winname
, windomain
);
4529 winname
, windomain
);
4530 retcode
= IDMAP_ERR_NOMAPPING
;
4534 "Looking up %s@%s error=%d",
4535 winname
, windomain
, retcode
);
4538 idmap_namerule_set(rule
, values
[1],
4539 values
[0], values
[4], is_user
,
4540 strtol(values
[3], &end
, 10),
4541 strtol(values
[5], &end
, 10),
4546 } else if (r
== SQLITE_DONE
) {
4547 TRACE(req
, res
, "No matching rule");
4548 retcode
= IDMAP_ERR_NOTFOUND
;
4551 (void) sqlite_finalize(vm
, &errmsg
);
4553 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
4554 CHECK_NULL(errmsg
));
4555 sqlite_freemem(errmsg
);
4556 retcode
= IDMAP_ERR_INTERNAL
;
4561 if (values
[2] != NULL
)
4563 (strtol(values
[2], &end
, 10) == 0)?
4564 IDMAP_DIRECTION_U2W
:IDMAP_DIRECTION_BI
;
4566 res
->direction
= IDMAP_DIRECTION_U2W
;
4568 req
->id2name
= canonname
;
4569 req
->id2domain
= canondomain
;
4571 idmap_namerule_set(rule
, values
[1], values
[0], values
[4],
4572 is_user
, strtol(values
[3], &end
, 10),
4573 strtol(values
[5], &end
, 10),
4575 TRACE(req
, res
, "Windows name found");
4579 sqlite_freemem(sql
);
4581 if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4582 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_RULE_BASED
;
4583 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
4587 (void) sqlite_finalize(vm
, NULL
);
4592 * Convention when processing unix2win requests:
4596 * unixname if given otherwise unixname found will be placed
4601 * Given type (IDMAP_UID or IDMAP_GID)
4602 * req->id1..[uid or gid] =
4603 * UID/GID if given otherwise UID/GID found will be placed here.
4607 * winname found will be placed here.
4609 * windomain found will be placed here.
4611 * Target type initialized from req->id2.idtype. If
4612 * it is IDMAP_SID then actual type (IDMAP_USID/GSID) found
4613 * will be placed here.
4614 * req->id..sid.[prefix, rid] =
4615 * SID found will be placed here.
4619 * Return status for this request will be placed here.
4621 * Direction found will be placed here. Direction
4622 * meaning whether the resultant mapping is valid
4623 * only from unix2win or bi-directional.
4625 * INTERNAL USE. Used by idmapd to set various
4626 * flags (_IDMAP_F_xxxx) to aid in processing
4629 * INTERNAL USE. Initially this is the requested target
4630 * type and is used to initialize res->id.idtype.
4631 * ad_lookup_batch() uses this field temporarily to store
4632 * sid_type obtained by the batched AD lookups and after
4633 * use resets it to IDMAP_NONE to prevent xdr from
4634 * mis-interpreting the contents of req->id2.
4635 * req->id2..[uid or gid or sid] =
4640 * This function does the following:
4641 * 1. Lookup well-known SIDs table.
4643 * 3. Check if the client does not want new mapping to be allocated
4644 * in which case this pass is the final pass.
4645 * 4. Set AD/NLDAP lookup flags if it determines that the next stage needs
4646 * to do AD/NLDAP lookup.
4649 pid2sid_first_pass(lookup_state_t
*state
, idmap_mapping
*req
,
4650 idmap_id_res
*res
, int is_user
)
4652 idmap_retcode retcode
;
4653 idmap_retcode retcode2
;
4654 bool_t gen_localsid_on_err
= FALSE
;
4656 /* Initialize result */
4657 res
->id
.idtype
= req
->id2
.idtype
;
4658 res
->direction
= IDMAP_DIRECTION_UNDEF
;
4660 if (req
->id2
.idmap_id_u
.sid
.prefix
!= NULL
) {
4661 /* sanitize sidprefix */
4662 free(req
->id2
.idmap_id_u
.sid
.prefix
);
4663 req
->id2
.idmap_id_u
.sid
.prefix
= NULL
;
4667 if (req
->id1
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) {
4668 if (req
->id1name
== NULL
) {
4669 retcode
= IDMAP_ERR_ARG
;
4673 retcode
= ns_lookup_byname(req
->id1name
, NULL
, &req
->id1
);
4674 if (retcode
!= IDMAP_SUCCESS
) {
4675 TRACE(req
, res
, "Getting UNIX ID error=%d", retcode
);
4676 retcode
= IDMAP_ERR_NOMAPPING
;
4679 TRACE(req
, res
, "Found UNIX ID");
4682 /* Lookup in well-known SIDs table */
4683 retcode
= lookup_wksids_pid2sid(req
, res
, is_user
);
4684 if (retcode
== IDMAP_SUCCESS
) {
4685 TRACE(req
, res
, "Hardwired mapping");
4687 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4689 "Well-known account lookup error=%d", retcode
);
4693 /* Lookup in cache */
4694 retcode
= lookup_cache_pid2sid(state
->cache
, req
, res
, is_user
);
4695 if (retcode
== IDMAP_SUCCESS
) {
4696 TRACE(req
, res
, "Found in mapping cache");
4698 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4700 "Mapping cache lookup error=%d", retcode
);
4703 TRACE(req
, res
, "Not found in mapping cache");
4705 /* Ephemeral ids cannot be allocated during pid2sid */
4706 if (IDMAP_ID_IS_EPHEMERAL(req
->id1
.idmap_id_u
.uid
)) {
4707 retcode
= IDMAP_ERR_NOMAPPING
;
4708 TRACE(req
, res
, "Shouldn't have an ephemeral ID here");
4712 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req
)) {
4713 retcode
= IDMAP_ERR_NONE_GENERATED
;
4717 if (AVOID_NAMESERVICE(req
)) {
4718 gen_localsid_on_err
= TRUE
;
4719 retcode
= IDMAP_ERR_NOMAPPING
;
4723 /* Set flags for the next stage */
4724 if (state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
) {
4725 req
->direction
|= _IDMAP_F_LOOKUP_AD
;
4726 state
->ad_nqueries
++;
4727 } else if (AD_MODE(req
->id1
.idtype
, state
)) {
4729 * If AD-based name mapping is enabled then the next stage
4730 * will need to lookup AD using unixname to get the
4731 * corresponding winname.
4733 if (req
->id1name
== NULL
) {
4734 /* Get unixname if only pid is given. */
4735 retcode
= ns_lookup_bypid(req
->id1
.idmap_id_u
.uid
,
4736 is_user
, &req
->id1name
);
4737 if (retcode
!= IDMAP_SUCCESS
) {
4739 "Getting UNIX name error=%d", retcode
);
4740 gen_localsid_on_err
= TRUE
;
4743 TRACE(req
, res
, "Found UNIX name");
4745 req
->direction
|= _IDMAP_F_LOOKUP_AD
;
4746 state
->ad_nqueries
++;
4747 } else if (NLDAP_OR_MIXED_MODE(req
->id1
.idtype
, state
)) {
4749 * If native LDAP or mixed mode is enabled for name mapping
4750 * then the next stage will need to lookup native LDAP using
4751 * unixname/pid to get the corresponding winname.
4753 req
->direction
|= _IDMAP_F_LOOKUP_NLDAP
;
4754 state
->nldap_nqueries
++;
4758 * Failed to find non-expired entry in cache. Set the flag to
4759 * indicate that we are not done yet.
4761 state
->pid2sid_done
= FALSE
;
4762 req
->direction
|= _IDMAP_F_NOTDONE
;
4763 retcode
= IDMAP_SUCCESS
;
4766 res
->retcode
= idmap_stat4prot(retcode
);
4767 if (ARE_WE_DONE(req
->direction
) && res
->retcode
!= IDMAP_SUCCESS
) {
4768 if (gen_localsid_on_err
== TRUE
) {
4769 retcode2
= generate_localsid(req
, res
, is_user
, TRUE
);
4770 if (retcode2
== IDMAP_SUCCESS
)
4771 TRACE(req
, res
, "Generate local SID");
4774 "Generate local SID error=%d", retcode2
);
4781 pid2sid_second_pass(lookup_state_t
*state
, idmap_mapping
*req
,
4782 idmap_id_res
*res
, int is_user
)
4784 bool_t gen_localsid_on_err
= TRUE
;
4785 idmap_retcode retcode
= IDMAP_SUCCESS
;
4786 idmap_retcode retcode2
;
4788 /* Check if second pass is needed */
4789 if (ARE_WE_DONE(req
->direction
))
4790 return (res
->retcode
);
4792 /* Get status from previous pass */
4793 retcode
= res
->retcode
;
4794 if (retcode
!= IDMAP_SUCCESS
)
4798 * If directory-based name mapping is enabled then the winname
4799 * may already have been retrieved from the AD object (AD-mode)
4800 * or from native LDAP object (nldap-mode or mixed-mode).
4801 * Note that if we have winname but no SID then it's an error
4802 * because this implies that the Native LDAP entry contains
4803 * winname which does not exist and it's better that we return
4804 * an error instead of doing rule-based mapping so that the user
4805 * can detect the issue and take appropriate action.
4807 if (req
->id2name
!= NULL
) {
4808 /* Return notfound if we've winname but no SID. */
4809 if (res
->id
.idmap_id_u
.sid
.prefix
== NULL
) {
4810 TRACE(req
, res
, "Windows name but no SID");
4811 retcode
= IDMAP_ERR_NOTFOUND
;
4814 if (state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
)
4815 res
->direction
= IDMAP_DIRECTION_BI
;
4816 else if (AD_MODE(req
->id1
.idtype
, state
))
4817 res
->direction
= IDMAP_DIRECTION_BI
;
4818 else if (NLDAP_MODE(req
->id1
.idtype
, state
))
4819 res
->direction
= IDMAP_DIRECTION_BI
;
4820 else if (MIXED_MODE(req
->id1
.idtype
, state
))
4821 res
->direction
= IDMAP_DIRECTION_W2U
;
4823 } else if (res
->id
.idmap_id_u
.sid
.prefix
!= NULL
) {
4825 * We've SID but no winname. This is fine because
4826 * the caller may have only requested SID.
4831 /* Free any mapping info from Directory based mapping */
4832 if (res
->info
.how
.map_type
!= IDMAP_MAP_TYPE_UNKNOWN
)
4833 idmap_how_clear(&res
->info
.how
);
4835 if (req
->id1name
== NULL
) {
4836 /* Get unixname from name service */
4837 retcode
= ns_lookup_bypid(req
->id1
.idmap_id_u
.uid
, is_user
,
4839 if (retcode
!= IDMAP_SUCCESS
) {
4841 "Getting UNIX name error=%d", retcode
);
4844 TRACE(req
, res
, "Found UNIX name");
4845 } else if (req
->id1
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) {
4846 /* Get pid from name service */
4847 retcode
= ns_lookup_byname(req
->id1name
, NULL
, &req
->id1
);
4848 if (retcode
!= IDMAP_SUCCESS
) {
4850 "Getting UNIX ID error=%d", retcode
);
4851 gen_localsid_on_err
= FALSE
;
4854 TRACE(req
, res
, "Found UNIX ID");
4857 /* Use unixname to evaluate local name-based mapping rules */
4858 retcode
= name_based_mapping_pid2sid(state
, req
->id1name
, is_user
,
4860 if (retcode
== IDMAP_ERR_NOTFOUND
) {
4861 retcode
= generate_localsid(req
, res
, is_user
, FALSE
);
4862 if (retcode
== IDMAP_SUCCESS
) {
4863 TRACE(req
, res
, "Generated local SID");
4866 "Generating local SID error=%d", retcode
);
4868 gen_localsid_on_err
= FALSE
;
4872 res
->retcode
= idmap_stat4prot(retcode
);
4873 if (res
->retcode
!= IDMAP_SUCCESS
) {
4874 req
->direction
= _IDMAP_F_DONE
;
4876 req
->id2name
= NULL
;
4877 free(req
->id2domain
);
4878 req
->id2domain
= NULL
;
4879 if (gen_localsid_on_err
== TRUE
) {
4880 retcode2
= generate_localsid(req
, res
, is_user
, TRUE
);
4881 if (retcode2
== IDMAP_SUCCESS
)
4882 TRACE(req
, res
, "Generate local SID");
4885 "Generate local SID error=%d", retcode2
);
4887 res
->id
.idtype
= is_user
? IDMAP_USID
: IDMAP_GSID
;
4890 if (!ARE_WE_DONE(req
->direction
))
4891 state
->pid2sid_done
= FALSE
;
4896 idmap_cache_flush(idmap_flush_op op
)
4899 sqlite
*cache
= NULL
;
4904 case IDMAP_FLUSH_EXPIRE
:
4906 "UPDATE idmap_cache SET expiration=1 WHERE expiration>0;";
4908 "UPDATE name_cache SET expiration=1 WHERE expiration>0;";
4911 case IDMAP_FLUSH_DELETE
:
4912 sql1
= "DELETE FROM idmap_cache;";
4913 sql2
= "DELETE FROM name_cache;";
4917 return (IDMAP_ERR_INTERNAL
);
4920 rc
= get_cache_handle(&cache
);
4921 if (rc
!= IDMAP_SUCCESS
)
4925 * Note that we flush the idmapd cache first, before the kernel
4926 * cache. If we did it the other way 'round, a request could come
4927 * in after the kernel cache flush and pull a soon-to-be-flushed
4928 * idmapd cache entry back into the kernel cache. This way the
4929 * worst that will happen is that a new entry will be added to
4930 * the kernel cache and then immediately flushed.
4933 rc
= sql_exec_no_cb(cache
, IDMAP_CACHENAME
, sql1
);
4934 if (rc
!= IDMAP_SUCCESS
)
4937 rc
= sql_exec_no_cb(cache
, IDMAP_CACHENAME
, sql2
);
4939 (void) __idmap_flush_kcache();