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
) {
1636 req
->id2name
= strdup(values
[3]);
1637 if (req
->id2name
== NULL
) {
1638 idmapdlog(LOG_ERR
, "Out of memory");
1639 retcode
= IDMAP_ERR_MEMORY
;
1643 req
->id1
.idtype
= strncmp(values
[5], "0", 2) ?
1644 IDMAP_USID
: IDMAP_GSID
;
1646 if (req
->flag
& IDMAP_REQ_FLG_MAPPING_INFO
) {
1647 res
->info
.src
= IDMAP_MAP_SRC_CACHE
;
1648 res
->info
.how
.map_type
= strtoul(values
[6], &end
, 10);
1649 switch (res
->info
.how
.map_type
) {
1650 case IDMAP_MAP_TYPE_DS_AD
:
1651 res
->info
.how
.idmap_how_u
.ad
.dn
=
1653 res
->info
.how
.idmap_how_u
.ad
.attr
=
1655 res
->info
.how
.idmap_how_u
.ad
.value
=
1659 case IDMAP_MAP_TYPE_DS_NLDAP
:
1660 res
->info
.how
.idmap_how_u
.nldap
.dn
=
1662 res
->info
.how
.idmap_how_u
.nldap
.attr
=
1664 res
->info
.how
.idmap_how_u
.nldap
.value
=
1668 case IDMAP_MAP_TYPE_RULE_BASED
:
1669 res
->info
.how
.idmap_how_u
.rule
.windomain
=
1671 res
->info
.how
.idmap_how_u
.rule
.winname
=
1673 res
->info
.how
.idmap_how_u
.rule
.unixname
=
1675 res
->info
.how
.idmap_how_u
.rule
.is_nt4
=
1676 strtoul(values
[13], &end
, 1);
1677 res
->info
.how
.idmap_how_u
.rule
.is_user
=
1679 res
->info
.how
.idmap_how_u
.rule
.is_wuser
=
1680 strtoul(values
[5], &end
, 1);
1683 case IDMAP_MAP_TYPE_EPHEMERAL
:
1686 case IDMAP_MAP_TYPE_LOCAL_SID
:
1689 case IDMAP_MAP_TYPE_KNOWN_SID
:
1692 case IDMAP_MAP_TYPE_IDMU
:
1693 res
->info
.how
.idmap_how_u
.idmu
.dn
=
1695 res
->info
.how
.idmap_how_u
.idmu
.attr
=
1697 res
->info
.how
.idmap_how_u
.idmu
.value
=
1702 /* Unknown mapping type */
1708 (void) sqlite_finalize(vm
, NULL
);
1713 * Previous versions used two enumerations for representing types.
1714 * One of those has largely been eliminated, but was used in the
1715 * name cache table and so during an upgrade might still be visible.
1716 * In addition, the test suite prepopulates the cache with these values.
1718 * This function translates those old values into the new values.
1720 * This code deliberately does not use symbolic values for the legacy
1721 * values. This is the *only* place where they should be used.
1725 xlate_legacy_type(int type
)
1728 case -1004: /* _IDMAP_T_USER */
1729 return (IDMAP_USID
);
1730 case -1005: /* _IDMAP_T_GROUP */
1731 return (IDMAP_GSID
);
1740 lookup_cache_sid2name(sqlite
*cache
, const char *sidprefix
, idmap_rid_t rid
,
1741 char **canonname
, char **canondomain
, idmap_id_type
*type
)
1745 const char **values
;
1746 sqlite_vm
*vm
= NULL
;
1749 idmap_retcode retcode
= IDMAP_SUCCESS
;
1751 /* Get current time */
1753 if ((curtime
= time(NULL
)) == (time_t)-1) {
1754 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
1756 retcode
= IDMAP_ERR_INTERNAL
;
1760 /* SQL to lookup the cache */
1761 sql
= sqlite_mprintf("SELECT canon_name, domain, type "
1762 "FROM name_cache WHERE "
1763 "sidprefix = %Q AND rid = %u AND "
1764 "(expiration = 0 OR expiration ISNULL OR "
1765 "expiration > %d);",
1766 sidprefix
, rid
, curtime
);
1768 idmapdlog(LOG_ERR
, "Out of memory");
1769 retcode
= IDMAP_ERR_MEMORY
;
1772 retcode
= sql_compile_n_step_once(cache
, sql
, &vm
, &ncol
, 3, &values
);
1773 sqlite_freemem(sql
);
1775 if (retcode
== IDMAP_SUCCESS
) {
1777 if (values
[2] == NULL
) {
1778 retcode
= IDMAP_ERR_CACHE
;
1781 *type
= xlate_legacy_type(strtol(values
[2], &end
, 10));
1784 if (canonname
!= NULL
&& values
[0] != NULL
) {
1785 if ((*canonname
= strdup(values
[0])) == NULL
) {
1786 idmapdlog(LOG_ERR
, "Out of memory");
1787 retcode
= IDMAP_ERR_MEMORY
;
1792 if (canondomain
!= NULL
&& values
[1] != NULL
) {
1793 if ((*canondomain
= strdup(values
[1])) == NULL
) {
1794 if (canonname
!= NULL
) {
1798 idmapdlog(LOG_ERR
, "Out of memory");
1799 retcode
= IDMAP_ERR_MEMORY
;
1807 (void) sqlite_finalize(vm
, NULL
);
1812 * Given SID, find winname using name_cache OR
1813 * Given winname, find SID using name_cache.
1814 * Used when mapping win to unix i.e. req->id1 is windows id and
1815 * req->id2 is unix id
1819 lookup_name_cache(sqlite
*cache
, idmap_mapping
*req
, idmap_id_res
*res
)
1821 idmap_id_type type
= -1;
1822 idmap_retcode retcode
;
1823 char *sidprefix
= NULL
;
1825 char *name
= NULL
, *domain
= NULL
;
1827 /* Done if we've both sid and winname */
1828 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
&& req
->id1name
!= NULL
) {
1829 /* Don't bother TRACE()ing, too boring */
1830 return (IDMAP_SUCCESS
);
1833 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
) {
1834 /* Lookup sid to winname */
1835 retcode
= lookup_cache_sid2name(cache
,
1836 req
->id1
.idmap_id_u
.sid
.prefix
,
1837 req
->id1
.idmap_id_u
.sid
.rid
, &name
, &domain
, &type
);
1839 /* Lookup winame to sid */
1840 retcode
= lookup_cache_name2sid(cache
, req
->id1name
,
1841 req
->id1domain
, &name
, &sidprefix
, &rid
, &type
);
1844 if (retcode
!= IDMAP_SUCCESS
) {
1845 if (retcode
== IDMAP_ERR_NOTFOUND
) {
1846 TRACE(req
, res
, "Not found in name cache");
1848 TRACE(req
, res
, "Name cache lookup error=%d", retcode
);
1856 req
->id1
.idtype
= type
;
1858 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
1861 * If we found canonical names or domain, use them instead of
1862 * the existing values.
1866 req
->id1name
= name
;
1868 if (domain
!= NULL
) {
1869 free(req
->id1domain
);
1870 req
->id1domain
= domain
;
1873 if (req
->id1
.idmap_id_u
.sid
.prefix
== NULL
) {
1874 req
->id1
.idmap_id_u
.sid
.prefix
= sidprefix
;
1875 req
->id1
.idmap_id_u
.sid
.rid
= rid
;
1878 TRACE(req
, res
, "Found in name cache");
1885 ad_lookup_batch_int(lookup_state_t
*state
, idmap_mapping_batch
*batch
,
1886 idmap_ids_res
*result
, adutils_ad_t
*dir
, int how_local
,
1889 idmap_retcode retcode
;
1890 int i
, num_queued
, is_wuser
, is_user
;
1892 int retries
= 0, esidtype
;
1896 idmap_query_state_t
*qs
= NULL
;
1898 char **dn
, **attr
, **value
;
1903 * Since req->id2.idtype is unused, we will use it here
1904 * to retrieve the value of sid_type. But it needs to be
1905 * reset to IDMAP_NONE before we return to prevent xdr
1906 * from mis-interpreting req->id2 when it tries to free
1907 * the input argument. Other option is to allocate an
1908 * array of integers and use it instead for the batched
1909 * call. But why un-necessarily allocate memory. That may
1910 * be an option if req->id2.idtype cannot be re-used in
1913 * Similarly, we use req->id2.idmap_id_u.uid to return
1914 * uidNumber or gidNumber supplied by IDMU, and reset it
1915 * back to IDMAP_SENTINEL_PID when we're done. Note that
1916 * the query always puts the result in req->id2.idmap_id_u.uid,
1920 retcode
= idmap_lookup_batch_start(dir
, state
->ad_nqueries
,
1921 state
->directory_based_mapping
,
1924 if (retcode
!= IDMAP_SUCCESS
) {
1925 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
1926 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
1928 degrade_svc(1, "failed to create batch for AD lookup");
1935 if (how_local
& FOREST_IS_LOCAL
) {
1937 * Directory based name mapping is only performed within the
1938 * joined forest. We don't trust other "trusted"
1939 * forests to provide DS-based name mapping information because
1940 * AD's definition of "cross-forest trust" does not encompass
1941 * this sort of behavior.
1943 idmap_lookup_batch_set_unixattr(qs
,
1944 state
->ad_unixuser_attr
, state
->ad_unixgroup_attr
);
1947 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
1948 req
= &batch
->idmap_mapping_batch_val
[i
];
1949 res
= &result
->ids
.ids_val
[i
];
1950 how
= &res
->info
.how
;
1952 retcode
= IDMAP_SUCCESS
;
1953 req
->id2
.idtype
= IDMAP_NONE
;
1954 req
->id2
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
1956 /* Skip if no AD lookup required */
1957 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
1960 /* Skip if we've already tried and gotten a "not found" */
1961 if (req
->direction
& _IDMAP_F_LOOKUP_OTHER_AD
)
1964 /* Skip if we've already either succeeded or failed */
1965 if (res
->retcode
!= IDMAP_ERR_RETRIABLE_NET_ERR
)
1968 if (IS_ID_SID(req
->id1
)) {
1970 /* win2unix request: */
1972 posix_id_t
*pid
= NULL
;
1973 unixname
= dn
= attr
= value
= NULL
;
1974 esidtype
= IDMAP_SID
;
1975 if (state
->directory_based_mapping
==
1976 DIRECTORY_MAPPING_NAME
&&
1977 req
->id2name
== NULL
) {
1978 if (res
->id
.idtype
== IDMAP_UID
&&
1979 AD_OR_MIXED(state
->nm_siduid
)) {
1980 esidtype
= IDMAP_USID
;
1981 unixname
= &req
->id2name
;
1982 } else if (res
->id
.idtype
== IDMAP_GID
&&
1983 AD_OR_MIXED(state
->nm_sidgid
)) {
1984 esidtype
= IDMAP_GSID
;
1985 unixname
= &req
->id2name
;
1986 } else if (AD_OR_MIXED(state
->nm_siduid
) ||
1987 AD_OR_MIXED(state
->nm_sidgid
)) {
1988 unixname
= &req
->id2name
;
1991 if (unixname
!= NULL
) {
1993 * Get how info for DS-based name
1994 * mapping only if AD or MIXED
1997 idmap_how_clear(&res
->info
.how
);
1998 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
1999 how
->map_type
= IDMAP_MAP_TYPE_DS_AD
;
2000 dn
= &how
->idmap_how_u
.ad
.dn
;
2001 attr
= &how
->idmap_how_u
.ad
.attr
;
2002 value
= &how
->idmap_how_u
.ad
.value
;
2004 } else if (state
->directory_based_mapping
==
2005 DIRECTORY_MAPPING_IDMU
&&
2006 (how_local
& DOMAIN_IS_LOCAL
)) {
2008 * Ensure that we only do IDMU processing
2009 * when querying the domain we've joined.
2011 pid
= &req
->id2
.idmap_id_u
.uid
;
2013 * Get how info for IDMU based mapping.
2015 idmap_how_clear(&res
->info
.how
);
2016 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2017 how
->map_type
= IDMAP_MAP_TYPE_IDMU
;
2018 dn
= &how
->idmap_how_u
.idmu
.dn
;
2019 attr
= &how
->idmap_how_u
.idmu
.attr
;
2020 value
= &how
->idmap_how_u
.idmu
.value
;
2023 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
) {
2024 /* Lookup AD by SID */
2025 retcode
= idmap_sid2name_batch_add1(
2026 qs
, req
->id1
.idmap_id_u
.sid
.prefix
,
2027 &req
->id1
.idmap_id_u
.sid
.rid
, esidtype
,
2029 (req
->id1name
== NULL
) ?
2030 &req
->id1name
: NULL
,
2031 (req
->id1domain
== NULL
) ?
2032 &req
->id1domain
: NULL
,
2033 &req
->id2
.idtype
, unixname
,
2036 if (retcode
== IDMAP_SUCCESS
)
2039 /* Lookup AD by winname */
2040 assert(req
->id1name
!= NULL
);
2041 retcode
= idmap_name2sid_batch_add1(
2042 qs
, req
->id1name
, req
->id1domain
,
2046 &req
->id1
.idmap_id_u
.sid
.prefix
,
2047 &req
->id1
.idmap_id_u
.sid
.rid
,
2048 &req
->id2
.idtype
, unixname
,
2051 if (retcode
== IDMAP_SUCCESS
)
2055 } else if (IS_ID_UID(req
->id1
) || IS_ID_GID(req
->id1
)) {
2057 /* unix2win request: */
2059 if (res
->id
.idmap_id_u
.sid
.prefix
!= NULL
&&
2060 req
->id2name
!= NULL
) {
2061 /* Already have SID and winname. done */
2062 res
->retcode
= IDMAP_SUCCESS
;
2066 if (res
->id
.idmap_id_u
.sid
.prefix
!= NULL
) {
2068 * SID but no winname -- lookup AD by
2069 * SID to get winname.
2070 * how info is not needed here because
2071 * we are not retrieving unixname from
2075 retcode
= idmap_sid2name_batch_add1(
2076 qs
, res
->id
.idmap_id_u
.sid
.prefix
,
2077 &res
->id
.idmap_id_u
.sid
.rid
,
2081 &req
->id2domain
, &req
->id2
.idtype
,
2082 NULL
, NULL
, &res
->retcode
);
2083 if (retcode
== IDMAP_SUCCESS
)
2085 } else if (req
->id2name
!= NULL
) {
2087 * winname but no SID -- lookup AD by
2088 * winname to get SID.
2089 * how info is not needed here because
2090 * we are not retrieving unixname from
2093 retcode
= idmap_name2sid_batch_add1(
2094 qs
, req
->id2name
, req
->id2domain
,
2096 NULL
, NULL
, NULL
, NULL
,
2097 &res
->id
.idmap_id_u
.sid
.prefix
,
2098 &res
->id
.idmap_id_u
.sid
.rid
,
2099 &req
->id2
.idtype
, NULL
,
2102 if (retcode
== IDMAP_SUCCESS
)
2104 } else if (state
->directory_based_mapping
==
2105 DIRECTORY_MAPPING_IDMU
&&
2106 (how_local
& DOMAIN_IS_LOCAL
)) {
2107 assert(req
->id1
.idmap_id_u
.uid
!=
2108 IDMAP_SENTINEL_PID
);
2109 is_user
= IS_ID_UID(req
->id1
);
2110 if (res
->id
.idtype
== IDMAP_USID
)
2112 else if (res
->id
.idtype
== IDMAP_GSID
)
2117 /* IDMU can't do diagonal mappings */
2118 if (is_user
!= is_wuser
)
2121 idmap_how_clear(&res
->info
.how
);
2122 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2123 how
->map_type
= IDMAP_MAP_TYPE_IDMU
;
2124 retcode
= idmap_pid2sid_batch_add1(
2125 qs
, req
->id1
.idmap_id_u
.uid
, is_user
,
2126 &how
->idmap_how_u
.ad
.dn
,
2127 &how
->idmap_how_u
.ad
.attr
,
2128 &how
->idmap_how_u
.ad
.value
,
2129 &res
->id
.idmap_id_u
.sid
.prefix
,
2130 &res
->id
.idmap_id_u
.sid
.rid
,
2131 &req
->id2name
, &req
->id2domain
,
2132 &req
->id2
.idtype
, &res
->retcode
);
2133 if (retcode
== IDMAP_SUCCESS
)
2135 } else if (req
->id1name
!= NULL
) {
2137 * No SID and no winname but we've unixname.
2138 * Lookup AD by unixname to get SID.
2140 is_user
= (IS_ID_UID(req
->id1
)) ? 1 : 0;
2141 if (res
->id
.idtype
== IDMAP_USID
)
2143 else if (res
->id
.idtype
== IDMAP_GSID
)
2148 idmap_how_clear(&res
->info
.how
);
2149 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2150 how
->map_type
= IDMAP_MAP_TYPE_DS_AD
;
2151 retcode
= idmap_unixname2sid_batch_add1(
2152 qs
, req
->id1name
, is_user
, is_wuser
,
2153 &how
->idmap_how_u
.ad
.dn
,
2154 &how
->idmap_how_u
.ad
.attr
,
2155 &how
->idmap_how_u
.ad
.value
,
2156 &res
->id
.idmap_id_u
.sid
.prefix
,
2157 &res
->id
.idmap_id_u
.sid
.rid
,
2158 &req
->id2name
, &req
->id2domain
,
2159 &req
->id2
.idtype
, &res
->retcode
);
2160 if (retcode
== IDMAP_SUCCESS
)
2165 if (retcode
== IDMAP_ERR_DOMAIN_NOTFOUND
) {
2166 req
->direction
|= _IDMAP_F_LOOKUP_OTHER_AD
;
2167 retcode
= IDMAP_SUCCESS
;
2168 } else if (retcode
!= IDMAP_SUCCESS
) {
2171 } /* End of for loop */
2173 if (retcode
== IDMAP_SUCCESS
) {
2174 /* add keeps track if we added an entry to the batch */
2176 retcode
= idmap_lookup_batch_end(&qs
);
2178 idmap_lookup_release_batch(&qs
);
2180 idmap_lookup_release_batch(&qs
);
2182 next_request
= i
+ 1;
2185 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
2186 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
2188 else if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
)
2189 degrade_svc(1, "some AD lookups timed out repeatedly");
2191 if (retcode
!= IDMAP_SUCCESS
) {
2192 /* Mark any unproccessed requests for an other AD */
2193 for (i
= next_request
; i
< batch
->idmap_mapping_batch_len
;
2195 req
= &batch
->idmap_mapping_batch_val
[i
];
2196 req
->direction
|= _IDMAP_F_LOOKUP_OTHER_AD
;
2201 if (retcode
!= IDMAP_SUCCESS
)
2202 idmapdlog(LOG_NOTICE
, "Failed to batch AD lookup requests");
2206 * This loop does the following:
2207 * 1. Reset _IDMAP_F_LOOKUP_AD flag from the request.
2208 * 2. Reset req->id2.idtype to IDMAP_NONE
2209 * 3. If batch_start or batch_add failed then set the status
2210 * of each request marked for AD lookup to that error.
2211 * 4. Evaluate the type of the AD object (i.e. user or group)
2212 * and update the idtype in request.
2214 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
2218 req
= &batch
->idmap_mapping_batch_val
[i
];
2219 type
= req
->id2
.idtype
;
2220 req
->id2
.idtype
= IDMAP_NONE
;
2221 posix_id
= req
->id2
.idmap_id_u
.uid
;
2222 req
->id2
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
2223 res
= &result
->ids
.ids_val
[i
];
2226 * If it didn't need AD lookup, ignore it.
2228 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
2232 * If we deferred it this time, reset for the next
2235 if (req
->direction
& _IDMAP_F_LOOKUP_OTHER_AD
) {
2236 req
->direction
&= ~_IDMAP_F_LOOKUP_OTHER_AD
;
2240 /* Count number processed */
2243 /* Reset AD lookup flag */
2244 req
->direction
&= ~(_IDMAP_F_LOOKUP_AD
);
2247 * If batch_start or batch_add failed then set the
2248 * status of each request marked for AD lookup to
2251 if (retcode
!= IDMAP_SUCCESS
) {
2252 res
->retcode
= retcode
;
2256 if (res
->retcode
== IDMAP_ERR_NOTFOUND
) {
2257 /* Nothing found - remove the preset info */
2258 idmap_how_clear(&res
->info
.how
);
2261 if (IS_ID_SID(req
->id1
)) {
2262 if (res
->retcode
== IDMAP_ERR_NOTFOUND
) {
2263 TRACE(req
, res
, "Not found in AD");
2266 if (res
->retcode
!= IDMAP_SUCCESS
) {
2267 TRACE(req
, res
, "AD lookup error=%d",
2271 /* Evaluate result type */
2274 if (res
->id
.idtype
== IDMAP_POSIXID
)
2275 res
->id
.idtype
= IDMAP_UID
;
2277 * We found a user. If we got information
2278 * from IDMU and we were expecting a user,
2281 if (posix_id
!= IDMAP_SENTINEL_PID
&&
2282 res
->id
.idtype
== IDMAP_UID
) {
2283 res
->id
.idmap_id_u
.uid
= posix_id
;
2284 res
->direction
= IDMAP_DIRECTION_BI
;
2285 res
->info
.how
.map_type
=
2286 IDMAP_MAP_TYPE_IDMU
;
2287 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2289 req
->id1
.idtype
= IDMAP_USID
;
2293 if (res
->id
.idtype
== IDMAP_POSIXID
)
2294 res
->id
.idtype
= IDMAP_GID
;
2296 * We found a group. If we got information
2297 * from IDMU and we were expecting a group,
2300 if (posix_id
!= IDMAP_SENTINEL_PID
&&
2301 res
->id
.idtype
== IDMAP_GID
) {
2302 res
->id
.idmap_id_u
.gid
= posix_id
;
2303 res
->direction
= IDMAP_DIRECTION_BI
;
2304 res
->info
.how
.map_type
=
2305 IDMAP_MAP_TYPE_IDMU
;
2306 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
2308 req
->id1
.idtype
= IDMAP_GSID
;
2312 res
->retcode
= IDMAP_ERR_SID
;
2315 TRACE(req
, res
, "Found in AD");
2316 if (res
->retcode
== IDMAP_SUCCESS
&&
2317 req
->id1name
!= NULL
&&
2318 (req
->id2name
== NULL
||
2319 res
->id
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) &&
2320 NLDAP_MODE(res
->id
.idtype
, state
)) {
2321 req
->direction
|= _IDMAP_F_LOOKUP_NLDAP
;
2322 state
->nldap_nqueries
++;
2324 } else if (IS_ID_UID(req
->id1
) || IS_ID_GID(req
->id1
)) {
2325 if (res
->retcode
!= IDMAP_SUCCESS
) {
2326 if ((!(IDMAP_FATAL_ERROR(res
->retcode
))) &&
2327 res
->id
.idmap_id_u
.sid
.prefix
== NULL
&&
2328 req
->id2name
== NULL
) {
2330 * If AD lookup by unixname or pid
2331 * failed with non fatal error
2332 * then clear the error (ie set
2333 * res->retcode to success).
2334 * This allows the next pass to
2335 * process other mapping
2336 * mechanisms for this request.
2339 IDMAP_ERR_NOTFOUND
) {
2340 /* This is not an error */
2341 res
->retcode
= IDMAP_SUCCESS
;
2346 "AD lookup error (ignored)");
2347 res
->retcode
= IDMAP_SUCCESS
;
2350 TRACE(req
, res
, "AD lookup error");
2354 /* Evaluate result type */
2358 if (res
->id
.idtype
== IDMAP_SID
)
2359 res
->id
.idtype
= type
;
2363 res
->retcode
= IDMAP_ERR_SID
;
2366 TRACE(req
, res
, "Found in AD");
2379 ad_lookup_batch(lookup_state_t
*state
, idmap_mapping_batch
*batch
,
2380 idmap_ids_res
*result
)
2382 idmap_retcode retcode
;
2389 if (state
->ad_nqueries
== 0)
2390 return (IDMAP_SUCCESS
);
2392 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
2393 req
= &batch
->idmap_mapping_batch_val
[i
];
2394 res
= &result
->ids
.ids_val
[i
];
2396 /* Skip if not marked for AD lookup or already in error. */
2397 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
) ||
2398 res
->retcode
!= IDMAP_SUCCESS
)
2402 res
->retcode
= IDMAP_ERR_RETRIABLE_NET_ERR
;
2406 num_queries
= state
->ad_nqueries
;
2408 if (_idmapdstate
.num_gcs
== 0 && _idmapdstate
.num_dcs
== 0) {
2409 /* Case of no ADs */
2410 retcode
= IDMAP_ERR_NO_ACTIVEDIRECTORY
;
2411 for (i
= 0; i
< batch
->idmap_mapping_batch_len
; i
++) {
2412 req
= &batch
->idmap_mapping_batch_val
[i
];
2413 res
= &result
->ids
.ids_val
[i
];
2414 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
2416 req
->direction
&= ~(_IDMAP_F_LOOKUP_AD
);
2417 res
->retcode
= IDMAP_ERR_NO_ACTIVEDIRECTORY
;
2422 if (state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
) {
2423 for (i
= 0; i
< _idmapdstate
.num_dcs
&& num_queries
> 0; i
++) {
2425 retcode
= ad_lookup_batch_int(state
, batch
,
2426 result
, _idmapdstate
.dcs
[i
],
2427 i
== 0 ? DOMAIN_IS_LOCAL
|FOREST_IS_LOCAL
: 0,
2429 num_queries
-= num_processed
;
2434 for (i
= 0; i
< _idmapdstate
.num_gcs
&& num_queries
> 0; i
++) {
2436 retcode
= ad_lookup_batch_int(state
, batch
, result
,
2437 _idmapdstate
.gcs
[i
],
2438 i
== 0 ? FOREST_IS_LOCAL
: 0,
2440 num_queries
-= num_processed
;
2445 * There are no more ADs to try. Return errors for any
2446 * remaining requests.
2448 if (num_queries
> 0) {
2449 for (j
= 0; j
< batch
->idmap_mapping_batch_len
; j
++) {
2450 req
= &batch
->idmap_mapping_batch_val
[j
];
2451 res
= &result
->ids
.ids_val
[j
];
2452 if (!(req
->direction
& _IDMAP_F_LOOKUP_AD
))
2454 req
->direction
&= ~(_IDMAP_F_LOOKUP_AD
);
2455 res
->retcode
= IDMAP_ERR_DOMAIN_NOTFOUND
;
2462 /* AD lookups done. Reset state->ad_nqueries and return */
2463 state
->ad_nqueries
= 0;
2468 * Convention when processing win2unix requests:
2472 * winname if given otherwise winname found will be placed
2475 * windomain if given otherwise windomain found will be
2478 * Either IDMAP_SID/USID/GSID. If this is IDMAP_SID then it'll
2479 * be set to IDMAP_USID/GSID depending upon whether the
2480 * given SID is user or group respectively. The user/group-ness
2481 * is determined either when looking up well-known SIDs table OR
2482 * if the SID is found in namecache OR by ad_lookup_batch().
2483 * req->id1..sid.[prefix, rid] =
2484 * SID if given otherwise SID found will be placed here.
2488 * unixname found will be placed here.
2492 * Target type initialized from req->id2.idtype. If
2493 * it is IDMAP_POSIXID then actual type (IDMAP_UID/GID) found
2494 * will be placed here.
2495 * res->id..[uid or gid] =
2496 * UID/GID found will be placed here.
2500 * Return status for this request will be placed here.
2502 * Direction found will be placed here. Direction
2503 * meaning whether the resultant mapping is valid
2504 * only from win2unix or bi-directional.
2506 * INTERNAL USE. Used by idmapd to set various
2507 * flags (_IDMAP_F_xxxx) to aid in processing
2510 * INTERNAL USE. Initially this is the requested target
2511 * type and is used to initialize res->id.idtype.
2512 * ad_lookup_batch() uses this field temporarily to store
2513 * sid_type obtained by the batched AD lookups and after
2514 * use resets it to IDMAP_NONE to prevent xdr from
2515 * mis-interpreting the contents of req->id2.
2516 * req->id2.idmap_id_u.uid =
2517 * INTERNAL USE. If the AD lookup finds IDMU data
2518 * (uidNumber or gidNumber, depending on the type of
2519 * the entry), it's left here.
2523 * This function does the following:
2524 * 1. Lookup well-known SIDs table.
2525 * 2. Check if the given SID is a local-SID and if so extract UID/GID from it.
2527 * 4. Check if the client does not want new mapping to be allocated
2528 * in which case this pass is the final pass.
2529 * 5. Set AD lookup flag if it determines that the next stage needs
2533 sid2pid_first_pass(lookup_state_t
*state
, idmap_mapping
*req
,
2536 idmap_retcode retcode
;
2539 /* Initialize result */
2540 res
->id
.idtype
= req
->id2
.idtype
;
2541 res
->id
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
2542 res
->direction
= IDMAP_DIRECTION_UNDEF
;
2545 if (EMPTY_STRING(req
->id1
.idmap_id_u
.sid
.prefix
)) {
2546 /* They have to give us *something* to work with! */
2547 if (req
->id1name
== NULL
) {
2548 retcode
= IDMAP_ERR_ARG
;
2552 /* sanitize sidprefix */
2553 free(req
->id1
.idmap_id_u
.sid
.prefix
);
2554 req
->id1
.idmap_id_u
.sid
.prefix
= NULL
;
2556 /* Allow for a fully-qualified name in the "name" parameter */
2557 if (req
->id1domain
== NULL
) {
2559 p
= strchr(req
->id1name
, '@');
2563 req
->id1name
= uu_strndup(q
, p
- req
->id1name
);
2564 req
->id1domain
= strdup(p
+1);
2566 if (req
->id1name
== NULL
||
2567 req
->id1domain
== NULL
) {
2568 retcode
= IDMAP_ERR_MEMORY
;
2575 /* Lookup well-known SIDs table */
2576 retcode
= lookup_wksids_sid2pid(req
, res
, &wksid
);
2577 if (retcode
== IDMAP_SUCCESS
) {
2578 /* Found a well-known account with a hardwired mapping */
2579 TRACE(req
, res
, "Hardwired mapping");
2581 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
2583 "Well-known account lookup failed, code %d", retcode
);
2588 /* Found a well-known account, but no mapping */
2589 TRACE(req
, res
, "Well-known account");
2591 TRACE(req
, res
, "Not a well-known account");
2593 /* Check if this is a localsid */
2594 retcode
= lookup_localsid2pid(req
, res
);
2595 if (retcode
== IDMAP_SUCCESS
) {
2596 TRACE(req
, res
, "Local SID");
2598 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
2600 "Local SID lookup error=%d", retcode
);
2603 TRACE(req
, res
, "Not a local SID");
2605 if (ALLOW_WK_OR_LOCAL_SIDS_ONLY(req
)) {
2606 retcode
= IDMAP_ERR_NONE_GENERATED
;
2612 * If this is a name-based request and we don't have a domain,
2613 * use the default domain. Note that the well-known identity
2614 * cases will have supplied a SID prefix already, and that we
2615 * don't (yet?) support looking up a local user through a Windows
2618 if (req
->id1
.idmap_id_u
.sid
.prefix
== NULL
&&
2619 req
->id1name
!= NULL
&& req
->id1domain
== NULL
) {
2620 if (state
->defdom
== NULL
) {
2621 retcode
= IDMAP_ERR_DOMAIN_NOTFOUND
;
2624 req
->id1domain
= strdup(state
->defdom
);
2625 if (req
->id1domain
== NULL
) {
2626 retcode
= IDMAP_ERR_MEMORY
;
2629 TRACE(req
, res
, "Added default domain");
2633 retcode
= lookup_cache_sid2pid(state
->cache
, req
, res
);
2634 if (retcode
== IDMAP_SUCCESS
) {
2635 TRACE(req
, res
, "Found in mapping cache");
2637 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
2638 TRACE(req
, res
, "Mapping cache lookup error=%d", retcode
);
2641 TRACE(req
, res
, "Not found in mapping cache");
2643 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req
) || AVOID_NAMESERVICE(req
)) {
2644 retcode
= IDMAP_ERR_NONE_GENERATED
;
2649 * Failed to find non-expired entry in cache. Next step is
2650 * to determine if this request needs to be batched for AD lookup.
2652 * At this point we have either sid or winname or both. If we don't
2653 * have both then lookup name_cache for the sid or winname
2654 * whichever is missing. If not found then this request will be
2655 * batched for AD lookup.
2657 retcode
= lookup_name_cache(state
->cache
, req
, res
);
2658 if (retcode
== IDMAP_SUCCESS
) {
2659 if (res
->id
.idtype
== IDMAP_POSIXID
) {
2660 if (req
->id1
.idtype
== IDMAP_USID
)
2661 res
->id
.idtype
= IDMAP_UID
;
2663 res
->id
.idtype
= IDMAP_GID
;
2665 } else if (retcode
!= IDMAP_ERR_NOTFOUND
)
2668 if (_idmapdstate
.cfg
->pgcfg
.use_lsa
&&
2669 _idmapdstate
.cfg
->pgcfg
.domain_name
!= NULL
) {
2671 * If we don't have both name and SID, try looking up the
2674 if (req
->id1
.idmap_id_u
.sid
.prefix
!= NULL
&&
2675 req
->id1name
== NULL
) {
2677 retcode
= lookup_lsa_by_sid(
2678 req
->id1
.idmap_id_u
.sid
.prefix
,
2679 req
->id1
.idmap_id_u
.sid
.rid
,
2680 &req
->id1name
, &req
->id1domain
, &req
->id1
.idtype
);
2681 if (retcode
== IDMAP_SUCCESS
) {
2682 TRACE(req
, res
, "Found with LSA");
2683 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
2684 TRACE(req
, res
, "Not found with LSA");
2686 TRACE(req
, res
, "LSA error %d", retcode
);
2690 } else if (req
->id1name
!= NULL
&&
2691 req
->id1
.idmap_id_u
.sid
.prefix
== NULL
) {
2695 retcode
= lookup_lsa_by_name(
2696 req
->id1name
, req
->id1domain
,
2697 &req
->id1
.idmap_id_u
.sid
.prefix
,
2698 &req
->id1
.idmap_id_u
.sid
.rid
,
2699 &canonname
, &canondomain
,
2701 if (retcode
== IDMAP_SUCCESS
) {
2703 req
->id1name
= canonname
;
2704 free(req
->id1domain
);
2705 req
->id1domain
= canondomain
;
2706 TRACE(req
, res
, "Found with LSA");
2707 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
2708 TRACE(req
, res
, "Not found with LSA");
2710 TRACE(req
, res
, "LSA error %d", retcode
);
2717 * Set the flag to indicate that we are not done yet so that
2718 * subsequent passes considers this request for name-based
2719 * mapping and ephemeral mapping.
2721 state
->sid2pid_done
= FALSE
;
2722 req
->direction
|= _IDMAP_F_NOTDONE
;
2725 * Even if we have both sid and winname, we still may need to batch
2726 * this request for AD lookup if we don't have unixname and
2727 * directory-based name mapping (AD or mixed) is enabled.
2728 * We avoid AD lookup for well-known SIDs because they don't have
2729 * regular AD objects.
2731 if (retcode
!= IDMAP_SUCCESS
||
2732 (!wksid
&& req
->id2name
== NULL
&&
2733 AD_OR_MIXED_MODE(res
->id
.idtype
, state
)) ||
2734 (!wksid
&& res
->id
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
&&
2735 state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
)) {
2736 retcode
= IDMAP_SUCCESS
;
2737 req
->direction
|= _IDMAP_F_LOOKUP_AD
;
2738 state
->ad_nqueries
++;
2739 } else if (NLDAP_MODE(res
->id
.idtype
, state
)) {
2740 req
->direction
|= _IDMAP_F_LOOKUP_NLDAP
;
2741 state
->nldap_nqueries
++;
2746 res
->retcode
= idmap_stat4prot(retcode
);
2748 * If we are done and there was an error then set fallback pid
2751 if (ARE_WE_DONE(req
->direction
) && res
->retcode
!= IDMAP_SUCCESS
)
2752 res
->id
.idmap_id_u
.uid
= UID_NOBODY
;
2757 * Generate SID using the following convention
2758 * <machine-sid-prefix>-<1000 + uid>
2759 * <machine-sid-prefix>-<2^31 + gid>
2763 generate_localsid(idmap_mapping
*req
, idmap_id_res
*res
, int is_user
,
2766 free(res
->id
.idmap_id_u
.sid
.prefix
);
2767 res
->id
.idmap_id_u
.sid
.prefix
= NULL
;
2770 * Diagonal mapping for localSIDs not supported because of the
2771 * way we generate localSIDs.
2773 if (is_user
&& res
->id
.idtype
== IDMAP_GSID
)
2774 return (IDMAP_ERR_NOTGROUP
);
2775 if (!is_user
&& res
->id
.idtype
== IDMAP_USID
)
2776 return (IDMAP_ERR_NOTUSER
);
2778 /* Skip 1000 UIDs */
2780 req
->id1
.idmap_id_u
.uid
+ LOCALRID_UID_MIN
> LOCALRID_UID_MAX
)
2781 return (IDMAP_ERR_NOMAPPING
);
2785 * machine_sid is never NULL because if it is we won't be here.
2786 * No need to assert because strdup(NULL) will core anyways.
2788 res
->id
.idmap_id_u
.sid
.prefix
=
2789 strdup(_idmapdstate
.cfg
->pgcfg
.machine_sid
);
2790 if (res
->id
.idmap_id_u
.sid
.prefix
== NULL
) {
2792 idmapdlog(LOG_ERR
, "Out of memory");
2793 return (IDMAP_ERR_MEMORY
);
2796 res
->id
.idmap_id_u
.sid
.rid
=
2797 (is_user
) ? req
->id1
.idmap_id_u
.uid
+ LOCALRID_UID_MIN
:
2798 req
->id1
.idmap_id_u
.gid
+ LOCALRID_GID_MIN
;
2799 res
->direction
= IDMAP_DIRECTION_BI
;
2800 if (res
->id
.idtype
== IDMAP_SID
)
2801 res
->id
.idtype
= is_user
? IDMAP_USID
: IDMAP_GSID
;
2804 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_LOCAL_SID
;
2805 res
->info
.src
= IDMAP_MAP_SRC_ALGORITHMIC
;
2809 * Don't update name_cache because local sids don't have
2810 * valid windows names.
2812 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
2813 return (IDMAP_SUCCESS
);
2818 lookup_localsid2pid(idmap_mapping
*req
, idmap_id_res
*res
)
2825 * If the sidprefix == localsid then UID = last RID - 1000 or
2826 * GID = last RID - 2^31.
2828 if ((sidprefix
= req
->id1
.idmap_id_u
.sid
.prefix
) == NULL
)
2829 /* This means we are looking up by winname */
2830 return (IDMAP_ERR_NOTFOUND
);
2831 rid
= req
->id1
.idmap_id_u
.sid
.rid
;
2834 s
= (_idmapdstate
.cfg
->pgcfg
.machine_sid
) ?
2835 strcasecmp(sidprefix
, _idmapdstate
.cfg
->pgcfg
.machine_sid
) : 1;
2839 * If the given sidprefix does not match machine_sid then this is
2843 return (IDMAP_ERR_NOTFOUND
);
2845 switch (res
->id
.idtype
) {
2847 if (rid
< LOCALRID_UID_MIN
|| rid
> LOCALRID_UID_MAX
)
2848 return (IDMAP_ERR_ARG
);
2849 res
->id
.idmap_id_u
.uid
= rid
- LOCALRID_UID_MIN
;
2852 if (rid
< LOCALRID_GID_MIN
)
2853 return (IDMAP_ERR_ARG
);
2854 res
->id
.idmap_id_u
.gid
= rid
- LOCALRID_GID_MIN
;
2857 if (rid
>= LOCALRID_GID_MIN
) {
2858 res
->id
.idmap_id_u
.gid
= rid
- LOCALRID_GID_MIN
;
2859 res
->id
.idtype
= IDMAP_GID
;
2860 } else if (rid
>= LOCALRID_UID_MIN
) {
2861 res
->id
.idmap_id_u
.uid
= rid
- LOCALRID_UID_MIN
;
2862 res
->id
.idtype
= IDMAP_UID
;
2864 return (IDMAP_ERR_ARG
);
2868 return (IDMAP_ERR_NOTSUPPORTED
);
2870 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_LOCAL_SID
;
2871 res
->info
.src
= IDMAP_MAP_SRC_ALGORITHMIC
;
2872 return (IDMAP_SUCCESS
);
2876 * Name service lookup by unixname to get pid
2880 ns_lookup_byname(const char *name
, const char *lower_name
, idmap_id
*id
)
2882 struct passwd pwd
, *pwdp
;
2883 struct group grp
, *grpp
;
2885 static size_t pwdbufsiz
= 0;
2886 static size_t grpbufsiz
= 0;
2889 switch (id
->idtype
) {
2892 pwdbufsiz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
2893 buf
= alloca(pwdbufsiz
);
2894 ret
= getpwnam_r(name
, &pwd
, buf
, pwdbufsiz
, &pwdp
);
2895 if (ret
== 0 && pwdp
== NULL
&& lower_name
!= NULL
&& name
!=
2896 lower_name
&& strcmp(name
, lower_name
) != 0)
2897 ret
= getpwnam_r(lower_name
, &pwd
, buf
, pwdbufsiz
,
2901 return (IDMAP_ERR_NOTFOUND
);
2903 return (IDMAP_ERR_INTERNAL
);
2905 id
->idmap_id_u
.uid
= pwd
.pw_uid
;
2909 grpbufsiz
= sysconf(_SC_GETGR_R_SIZE_MAX
);
2910 buf
= alloca(grpbufsiz
);
2911 grpp
= getgrnam_r(name
, &grp
, buf
, grpbufsiz
);
2912 if (grpp
== NULL
&& errno
== 0 && lower_name
!= NULL
&&
2913 name
!= lower_name
&& strcmp(name
, lower_name
) != 0)
2914 grpp
= getgrnam_r(lower_name
, &grp
, buf
, grpbufsiz
);
2917 return (IDMAP_ERR_NOTFOUND
);
2919 return (IDMAP_ERR_INTERNAL
);
2921 id
->idmap_id_u
.gid
= grp
.gr_gid
;
2924 return (IDMAP_ERR_ARG
);
2926 return (IDMAP_SUCCESS
);
2931 * Name service lookup by pid to get unixname
2935 ns_lookup_bypid(uid_t pid
, int is_user
, char **unixname
)
2940 static size_t pwdbufsiz
= 0;
2941 static size_t grpbufsiz
= 0;
2943 struct passwd
*pwdp
;
2947 pwdbufsiz
= sysconf(_SC_GETPW_R_SIZE_MAX
);
2948 buf
= alloca(pwdbufsiz
);
2949 ret
= getpwuid_r(pid
, &pwd
, buf
, pwdbufsiz
, &pwdp
);
2952 return (IDMAP_ERR_NOTFOUND
);
2954 return (IDMAP_ERR_INTERNAL
);
2956 *unixname
= strdup(pwd
.pw_name
);
2959 grpbufsiz
= sysconf(_SC_GETGR_R_SIZE_MAX
);
2960 buf
= alloca(grpbufsiz
);
2962 if (getgrgid_r(pid
, &grp
, buf
, grpbufsiz
) == NULL
) {
2964 return (IDMAP_ERR_NOTFOUND
);
2966 return (IDMAP_ERR_INTERNAL
);
2968 *unixname
= strdup(grp
.gr_name
);
2970 if (*unixname
== NULL
)
2971 return (IDMAP_ERR_MEMORY
);
2972 return (IDMAP_SUCCESS
);
2976 * Name-based mapping
2978 * Case 1: If no rule matches do ephemeral
2980 * Case 2: If rule matches and unixname is "" then return no mapping.
2982 * Case 3: If rule matches and unixname is specified then lookup name
2983 * service using the unixname. If unixname not found then return no mapping.
2985 * Case 4: If rule matches and unixname is * then lookup name service
2986 * using winname as the unixname. If unixname not found then process
2987 * other rules using the lookup order. If no other rule matches then do
2988 * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
2989 * This allows us to specify a fallback unixname per _domain_ or no mapping
2990 * instead of the default behaviour of doing ephemeral mapping.
2994 * If looking up windows users foo@sfbay and foo does not exists in
2995 * the name service then foo@sfbay will be mapped to an ephemeral id.
3000 * If looking up windows users foo@sfbay and foo does not exists in
3001 * the name service then foo@sfbay will be mapped to guest.
3006 * If looking up windows users foo@sfbay and foo does not exists in
3007 * the name service then we will return no mapping for foo@sfbay.
3012 name_based_mapping_sid2pid(lookup_state_t
*state
,
3013 idmap_mapping
*req
, idmap_id_res
*res
)
3015 const char *unixname
, *windomain
;
3016 char *sql
= NULL
, *errmsg
= NULL
, *lower_winname
= NULL
;
3017 idmap_retcode retcode
;
3018 char *end
, *lower_unixname
, *winname
;
3019 const char **values
;
3020 sqlite_vm
*vm
= NULL
;
3021 int ncol
, r
, is_user
, is_wuser
;
3022 idmap_namerule
*rule
= &res
->info
.how
.idmap_how_u
.rule
;
3024 const char *me
= "name_based_mapping_sid2pid";
3026 assert(req
->id1name
!= NULL
); /* We have winname */
3027 assert(req
->id2name
== NULL
); /* We don't have unixname */
3029 winname
= req
->id1name
;
3030 windomain
= req
->id1domain
;
3032 switch (req
->id1
.idtype
) {
3040 idmapdlog(LOG_ERR
, "%s: Unable to determine if the "
3041 "given Windows id is user or group.", me
);
3042 return (IDMAP_ERR_INTERNAL
);
3045 switch (res
->id
.idtype
) {
3054 res
->id
.idtype
= is_user
? IDMAP_UID
: IDMAP_GID
;
3058 if (windomain
== NULL
)
3061 if ((lower_winname
= tolower_u8(winname
)) == NULL
)
3062 lower_winname
= winname
; /* hope for the best */
3063 sql
= sqlite_mprintf(
3064 "SELECT unixname, u2w_order, winname_display, windomain, is_nt4 "
3065 "FROM namerules WHERE "
3066 "w2u_order > 0 AND is_user = %d AND is_wuser = %d AND "
3067 "(winname = %Q OR winname = '*') AND "
3068 "(windomain = %Q OR windomain = '*') "
3069 "ORDER BY w2u_order ASC;",
3070 is_user
, is_wuser
, lower_winname
, windomain
);
3072 idmapdlog(LOG_ERR
, "Out of memory");
3073 retcode
= IDMAP_ERR_MEMORY
;
3077 if (sqlite_compile(state
->db
, sql
, NULL
, &vm
, &errmsg
) != SQLITE_OK
) {
3078 retcode
= IDMAP_ERR_INTERNAL
;
3079 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
3080 CHECK_NULL(errmsg
));
3081 sqlite_freemem(errmsg
);
3086 r
= sqlite_step(vm
, &ncol
, &values
, NULL
);
3087 assert(r
!= SQLITE_LOCKED
&& r
!= SQLITE_BUSY
);
3089 if (r
== SQLITE_ROW
) {
3091 retcode
= IDMAP_ERR_INTERNAL
;
3095 TRACE(req
, res
, "Matching rule: %s@%s -> %s",
3096 values
[2] == NULL
? "(null)" : values
[2],
3097 values
[3] == NULL
? "(null)" : values
[3],
3098 values
[0] == NULL
? "(null)" : values
[0]);
3100 if (values
[0] == NULL
) {
3101 retcode
= IDMAP_ERR_INTERNAL
;
3105 if (values
[1] != NULL
)
3107 (strtol(values
[1], &end
, 10) == 0)?
3108 IDMAP_DIRECTION_W2U
:IDMAP_DIRECTION_BI
;
3110 direction
= IDMAP_DIRECTION_W2U
;
3112 if (EMPTY_NAME(values
[0])) {
3113 TRACE(req
, res
, "Mapping inhibited");
3114 idmap_namerule_set(rule
, values
[3], values
[2],
3115 values
[0], is_user
, is_wuser
,
3116 strtol(values
[4], &end
, 10),
3118 retcode
= IDMAP_ERR_NOMAPPING
;
3122 if (values
[0][0] == '*') {
3124 lower_unixname
= lower_winname
;
3126 unixname
= values
[0];
3127 lower_unixname
= NULL
;
3130 retcode
= ns_lookup_byname(unixname
, lower_unixname
,
3132 if (retcode
== IDMAP_SUCCESS
) {
3134 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
3135 if (values
[0][0] == '*') {
3137 "%s not found, continuing",
3143 "%s not found, error", unixname
);
3145 idmap_namerule_set(rule
, values
[3],
3146 values
[2], values
[0], is_user
,
3148 strtol(values
[4], &end
, 10),
3150 retcode
= IDMAP_ERR_NOMAPPING
;
3153 TRACE(req
, res
, "Looking up %s error=%d",
3157 } else if (r
== SQLITE_DONE
) {
3158 TRACE(req
, res
, "No matching rule");
3159 retcode
= IDMAP_ERR_NOTFOUND
;
3162 (void) sqlite_finalize(vm
, &errmsg
);
3164 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
3165 CHECK_NULL(errmsg
));
3166 sqlite_freemem(errmsg
);
3167 retcode
= IDMAP_ERR_INTERNAL
;
3174 if (values
[1] != NULL
)
3176 (strtol(values
[1], &end
, 10) == 0)?
3177 IDMAP_DIRECTION_W2U
:IDMAP_DIRECTION_BI
;
3179 res
->direction
= IDMAP_DIRECTION_W2U
;
3181 req
->id2name
= strdup(unixname
);
3182 if (req
->id2name
== NULL
) {
3183 retcode
= IDMAP_ERR_MEMORY
;
3186 TRACE(req
, res
, "UNIX name found");
3188 idmap_namerule_set(rule
, values
[3], values
[2],
3189 values
[0], is_user
, is_wuser
, strtol(values
[4], &end
, 10),
3193 if (retcode
!= IDMAP_SUCCESS
&&
3194 retcode
!= IDMAP_ERR_NOTFOUND
&&
3195 retcode
!= IDMAP_ERR_NOMAPPING
) {
3196 TRACE(req
, res
, "Rule processing error, code=%d", retcode
);
3200 sqlite_freemem(sql
);
3202 if (retcode
!= IDMAP_ERR_NOTFOUND
) {
3203 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_RULE_BASED
;
3204 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
3207 if (lower_winname
!= NULL
&& lower_winname
!= winname
)
3208 free(lower_winname
);
3210 (void) sqlite_finalize(vm
, NULL
);
3216 get_next_eph_uid(uid_t
*next_uid
)
3222 *next_uid
= (uid_t
)-1;
3223 uid
= _idmapdstate
.next_uid
++;
3224 if (uid
>= _idmapdstate
.limit_uid
) {
3225 if ((err
= allocids(0, 8192, &uid
, 0, &gid
)) != 0)
3228 _idmapdstate
.limit_uid
= uid
+ 8192;
3229 _idmapdstate
.next_uid
= uid
;
3238 get_next_eph_gid(gid_t
*next_gid
)
3244 *next_gid
= (uid_t
)-1;
3245 gid
= _idmapdstate
.next_gid
++;
3246 if (gid
>= _idmapdstate
.limit_gid
) {
3247 if ((err
= allocids(0, 0, &uid
, 8192, &gid
)) != 0)
3250 _idmapdstate
.limit_gid
= gid
+ 8192;
3251 _idmapdstate
.next_gid
= gid
;
3260 gethash(const char *str
, uint32_t num
, uint_t htsize
)
3262 uint_t hval
, i
, len
;
3266 for (len
= strlen(str
), hval
= 0, i
= 0; i
< len
; i
++) {
3268 hval
+= (hval
<< 10);
3269 hval
^= (hval
>> 6);
3271 for (str
= (const char *)&num
, i
= 0; i
< sizeof (num
); i
++) {
3273 hval
+= (hval
<< 10);
3274 hval
^= (hval
>> 6);
3276 hval
+= (hval
<< 3);
3277 hval
^= (hval
>> 11);
3278 hval
+= (hval
<< 15);
3279 return (hval
% htsize
);
3284 get_from_sid_history(lookup_state_t
*state
, const char *prefix
, uint32_t rid
,
3288 uint_t htsize
= state
->sid_history_size
;
3291 next
= gethash(prefix
, rid
, htsize
);
3292 while (next
!= htsize
) {
3293 key
= state
->sid_history
[next
].key
;
3296 sid
= &state
->batch
->idmap_mapping_batch_val
[key
].id1
.
3298 if (sid
->rid
== rid
&& strcmp(sid
->prefix
, prefix
) == 0) {
3299 *pid
= state
->result
->ids
.ids_val
[key
].id
.
3303 next
= state
->sid_history
[next
].next
;
3310 add_to_sid_history(lookup_state_t
*state
, const char *prefix
, uint32_t rid
)
3313 uint_t htsize
= state
->sid_history_size
;
3315 hash
= next
= gethash(prefix
, rid
, htsize
);
3316 while (state
->sid_history
[next
].key
!= htsize
) {
3320 state
->sid_history
[next
].key
= state
->curpos
;
3323 state
->sid_history
[next
].next
= state
->sid_history
[hash
].next
;
3324 state
->sid_history
[hash
].next
= next
;
3328 cleanup_lookup_state(lookup_state_t
*state
)
3330 free(state
->sid_history
);
3331 free(state
->ad_unixuser_attr
);
3332 free(state
->ad_unixgroup_attr
);
3333 free(state
->nldap_winname_attr
);
3334 free(state
->defdom
);
3340 dynamic_ephemeral_mapping(lookup_state_t
*state
,
3341 idmap_mapping
*req
, idmap_id_res
*res
)
3346 res
->direction
= IDMAP_DIRECTION_BI
;
3348 if (IDMAP_ID_IS_EPHEMERAL(res
->id
.idmap_id_u
.uid
)) {
3349 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_EPHEMERAL
;
3350 res
->info
.src
= IDMAP_MAP_SRC_CACHE
;
3351 return (IDMAP_SUCCESS
);
3354 if (state
->sid_history
!= NULL
&&
3355 get_from_sid_history(state
, req
->id1
.idmap_id_u
.sid
.prefix
,
3356 req
->id1
.idmap_id_u
.sid
.rid
, &next_pid
)) {
3357 res
->id
.idmap_id_u
.uid
= next_pid
;
3358 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_EPHEMERAL
;
3359 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
3360 return (IDMAP_SUCCESS
);
3363 if (res
->id
.idtype
== IDMAP_UID
) {
3364 if (get_next_eph_uid(&next_pid
) != 0)
3365 return (IDMAP_ERR_INTERNAL
);
3366 res
->id
.idmap_id_u
.uid
= next_pid
;
3368 if (get_next_eph_gid(&next_pid
) != 0)
3369 return (IDMAP_ERR_INTERNAL
);
3370 res
->id
.idmap_id_u
.gid
= next_pid
;
3373 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_EPHEMERAL
;
3374 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
3375 if (state
->sid_history
!= NULL
)
3376 add_to_sid_history(state
, req
->id1
.idmap_id_u
.sid
.prefix
,
3377 req
->id1
.idmap_id_u
.sid
.rid
);
3379 return (IDMAP_SUCCESS
);
3383 sid2pid_second_pass(lookup_state_t
*state
,
3384 idmap_mapping
*req
, idmap_id_res
*res
)
3386 idmap_retcode retcode
;
3387 idmap_retcode retcode2
;
3389 /* Check if second pass is needed */
3390 if (ARE_WE_DONE(req
->direction
))
3391 return (res
->retcode
);
3393 /* Get status from previous pass */
3394 retcode
= res
->retcode
;
3395 if (retcode
!= IDMAP_SUCCESS
&& state
->eph_map_unres_sids
&&
3396 !EMPTY_STRING(req
->id1
.idmap_id_u
.sid
.prefix
) &&
3397 EMPTY_STRING(req
->id1name
)) {
3399 * We are asked to map an unresolvable SID to a UID or
3400 * GID, but, which? We'll treat all unresolvable SIDs
3401 * as users unless the caller specified which of a UID
3404 if (req
->id1
.idtype
== IDMAP_SID
)
3405 req
->id1
.idtype
= IDMAP_USID
;
3406 if (res
->id
.idtype
== IDMAP_POSIXID
) {
3407 res
->id
.idtype
= IDMAP_UID
;
3408 TRACE(req
, res
, "Assume unresolvable SID is user");
3409 } else if (res
->id
.idtype
== IDMAP_UID
) {
3410 TRACE(req
, res
, "Must map unresolvable SID to user");
3411 } else if (res
->id
.idtype
== IDMAP_GID
) {
3412 TRACE(req
, res
, "Must map unresolvable SID to group");
3416 if (retcode
!= IDMAP_SUCCESS
)
3420 * There are two ways we might get here with a Posix ID:
3421 * - It could be from an expired ephemeral cache entry.
3422 * - It could be from IDMU.
3423 * If it's from IDMU, we need to look up the name, for name-based
3424 * requests and the cache.
3426 if (!IDMAP_ID_IS_EPHEMERAL(res
->id
.idmap_id_u
.uid
) &&
3427 res
->id
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
) {
3428 if (req
->id2name
== NULL
) {
3430 * If the lookup fails, go ahead anyway.
3431 * The general UNIX rule is that it's OK to
3432 * have a UID or GID that isn't in the
3435 retcode2
= ns_lookup_bypid(res
->id
.idmap_id_u
.uid
,
3436 res
->id
.idtype
== IDMAP_UID
, &req
->id2name
);
3437 if (IDMAP_ERROR(retcode2
)) {
3439 "Getting UNIX name, error=%d (ignored)",
3442 TRACE(req
, res
, "Found UNIX name");
3449 * If directory-based name mapping is enabled then the unixname
3450 * may already have been retrieved from the AD object (AD-mode or
3451 * mixed-mode) or from native LDAP object (nldap-mode) -- done.
3453 if (req
->id2name
!= NULL
) {
3454 assert(res
->id
.idtype
!= IDMAP_POSIXID
);
3455 if (AD_MODE(res
->id
.idtype
, state
))
3456 res
->direction
= IDMAP_DIRECTION_BI
;
3457 else if (NLDAP_MODE(res
->id
.idtype
, state
))
3458 res
->direction
= IDMAP_DIRECTION_BI
;
3459 else if (MIXED_MODE(res
->id
.idtype
, state
))
3460 res
->direction
= IDMAP_DIRECTION_W2U
;
3463 * Special case: (1) If the ad_unixuser_attr and
3464 * ad_unixgroup_attr uses the same attribute
3465 * name and (2) if this is a diagonal mapping
3466 * request and (3) the unixname has been retrieved
3467 * from the AD object -- then we ignore it and fallback
3468 * to name-based mapping rules and ephemeral mapping
3472 * config/ad_unixuser_attr = "unixname"
3473 * config/ad_unixgroup_attr = "unixname"
3480 * dn: cn=winadmins ...
3481 * objectclass: group
3483 * unixname: unixadmins
3485 * In this example whether "unixname" refers to a unixuser
3486 * or unixgroup depends upon the AD object.
3488 * $idmap show -c winname:bob gid
3489 * AD lookup by "samAccountName=bob" for
3490 * "ad_unixgroup_attr (i.e unixname)" for directory-based
3491 * mapping would get "bob1234" which is not what we want.
3492 * Now why not getgrnam_r("bob1234") and use it if it
3493 * is indeed a unixgroup? That's because Unix can have
3494 * users and groups with the same name and we clearly
3495 * don't know the intention of the admin here.
3496 * Therefore we ignore this and fallback to name-based
3497 * mapping rules or ephemeral mapping.
3499 if ((AD_MODE(res
->id
.idtype
, state
) ||
3500 MIXED_MODE(res
->id
.idtype
, state
)) &&
3501 state
->ad_unixuser_attr
!= NULL
&&
3502 state
->ad_unixgroup_attr
!= NULL
&&
3503 strcasecmp(state
->ad_unixuser_attr
,
3504 state
->ad_unixgroup_attr
) == 0 &&
3505 ((req
->id1
.idtype
== IDMAP_USID
&&
3506 res
->id
.idtype
== IDMAP_GID
) ||
3507 (req
->id1
.idtype
== IDMAP_GSID
&&
3508 res
->id
.idtype
== IDMAP_UID
))) {
3509 TRACE(req
, res
, "Ignoring UNIX name found in AD");
3511 req
->id2name
= NULL
;
3512 res
->id
.idmap_id_u
.uid
= IDMAP_SENTINEL_PID
;
3515 if (res
->id
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) {
3516 retcode
= ns_lookup_byname(req
->id2name
,
3518 if (retcode
!= IDMAP_SUCCESS
) {
3520 * If ns_lookup_byname() fails that
3521 * means the unixname (req->id2name),
3522 * which was obtained from the AD
3523 * object by directory-based mapping,
3524 * is not a valid Unix user/group and
3525 * therefore we return the error to the
3526 * client instead of doing rule-based
3527 * mapping or ephemeral mapping. This
3528 * way the client can detect the issue.
3531 "UNIX lookup error=%d", retcode
);
3534 TRACE(req
, res
, "UNIX lookup");
3540 /* Free any mapping info from Directory based mapping */
3541 if (res
->info
.how
.map_type
!= IDMAP_MAP_TYPE_UNKNOWN
)
3542 idmap_how_clear(&res
->info
.how
);
3545 * If we don't have unixname then evaluate local name-based
3548 retcode
= name_based_mapping_sid2pid(state
, req
, res
);
3549 if (retcode
== IDMAP_SUCCESS
) {
3550 TRACE(req
, res
, "Rule-based mapping");
3552 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
3553 TRACE(req
, res
, "Rule-based mapping error=%d", retcode
);
3558 /* If not found, do ephemeral mapping */
3559 retcode
= dynamic_ephemeral_mapping(state
, req
, res
);
3560 if (retcode
== IDMAP_SUCCESS
) {
3561 TRACE(req
, res
, "Ephemeral mapping");
3563 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
3564 TRACE(req
, res
, "Ephemeral mapping error=%d", retcode
);
3569 res
->retcode
= idmap_stat4prot(retcode
);
3570 if (res
->retcode
!= IDMAP_SUCCESS
) {
3571 req
->direction
= _IDMAP_F_DONE
;
3572 res
->id
.idmap_id_u
.uid
= UID_NOBODY
;
3574 if (!ARE_WE_DONE(req
->direction
))
3575 state
->sid2pid_done
= FALSE
;
3580 update_cache_pid2sid(lookup_state_t
*state
,
3581 idmap_mapping
*req
, idmap_id_res
*res
)
3584 idmap_retcode retcode
;
3585 idmap_retcode retcode2
;
3586 char *map_dn
= NULL
;
3587 char *map_attr
= NULL
;
3588 char *map_value
= NULL
;
3589 char *map_windomain
= NULL
;
3590 char *map_winname
= NULL
;
3591 char *map_unixname
= NULL
;
3592 int map_is_nt4
= FALSE
;
3594 /* Check if we need to cache anything */
3595 if (ARE_WE_DONE(req
->direction
))
3596 return (IDMAP_SUCCESS
);
3598 /* We don't cache negative entries */
3599 if (res
->retcode
!= IDMAP_SUCCESS
)
3600 return (IDMAP_SUCCESS
);
3602 assert(res
->direction
!= IDMAP_DIRECTION_UNDEF
);
3603 assert(req
->id1
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
);
3604 assert(res
->id
.idtype
!= IDMAP_SID
);
3607 * If we've gotten to this point and we *still* don't know the
3608 * unixname, well, we'd like to have it now for the cache.
3610 * If we truly always need it for the cache, we should probably
3611 * look it up once at the beginning, rather than "at need" in
3612 * several places as is now done. However, it's not really clear
3613 * that we *do* need it in the cache; there's a decent argument
3614 * that the cache should contain only SIDs and PIDs, so we'll
3615 * leave our options open by doing it "at need" here too.
3617 * If we can't find it... c'est la vie.
3619 if (req
->id1name
== NULL
) {
3620 retcode2
= ns_lookup_bypid(req
->id1
.idmap_id_u
.uid
,
3621 req
->id1
.idtype
== IDMAP_UID
, &req
->id1name
);
3622 if (retcode2
== IDMAP_SUCCESS
)
3623 TRACE(req
, res
, "Found UNIX name");
3625 TRACE(req
, res
, "Getting UNIX name error=%d", retcode2
);
3628 assert(res
->info
.how
.map_type
!= IDMAP_MAP_TYPE_UNKNOWN
);
3629 switch (res
->info
.how
.map_type
) {
3630 case IDMAP_MAP_TYPE_DS_AD
:
3631 map_dn
= res
->info
.how
.idmap_how_u
.ad
.dn
;
3632 map_attr
= res
->info
.how
.idmap_how_u
.ad
.attr
;
3633 map_value
= res
->info
.how
.idmap_how_u
.ad
.value
;
3636 case IDMAP_MAP_TYPE_DS_NLDAP
:
3637 map_dn
= res
->info
.how
.idmap_how_u
.nldap
.dn
;
3638 map_attr
= res
->info
.how
.idmap_how_u
.nldap
.attr
;
3639 map_value
= res
->info
.how
.idmap_how_u
.nldap
.value
;
3642 case IDMAP_MAP_TYPE_RULE_BASED
:
3643 map_windomain
= res
->info
.how
.idmap_how_u
.rule
.windomain
;
3644 map_winname
= res
->info
.how
.idmap_how_u
.rule
.winname
;
3645 map_unixname
= res
->info
.how
.idmap_how_u
.rule
.unixname
;
3646 map_is_nt4
= res
->info
.how
.idmap_how_u
.rule
.is_nt4
;
3649 case IDMAP_MAP_TYPE_EPHEMERAL
:
3652 case IDMAP_MAP_TYPE_LOCAL_SID
:
3655 case IDMAP_MAP_TYPE_IDMU
:
3656 map_dn
= res
->info
.how
.idmap_how_u
.idmu
.dn
;
3657 map_attr
= res
->info
.how
.idmap_how_u
.idmu
.attr
;
3658 map_value
= res
->info
.how
.idmap_how_u
.idmu
.value
;
3662 /* Don't cache other mapping types */
3667 * Using NULL for u2w instead of 0 so that our trigger allows
3668 * the same pid to be the destination in multiple entries
3670 sql
= sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3671 "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3672 "is_user, is_wuser, expiration, w2u, u2w, "
3673 "map_type, map_dn, map_attr, map_value, map_windomain, "
3674 "map_winname, map_unixname, map_is_nt4) "
3675 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3676 "strftime('%%s','now') + %u, %q, 1, "
3677 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d); ",
3678 res
->id
.idmap_id_u
.sid
.prefix
, res
->id
.idmap_id_u
.sid
.rid
,
3679 req
->id2domain
, req
->id2name
, req
->id1
.idmap_id_u
.uid
,
3680 req
->id1name
, (req
->id1
.idtype
== IDMAP_UID
) ? 1 : 0,
3681 (res
->id
.idtype
== IDMAP_USID
) ? 1 : 0,
3682 state
->id_cache_timeout
,
3683 (res
->direction
== 0) ? "1" : NULL
,
3684 res
->info
.how
.map_type
, map_dn
, map_attr
, map_value
,
3685 map_windomain
, map_winname
, map_unixname
, map_is_nt4
);
3688 retcode
= IDMAP_ERR_INTERNAL
;
3689 idmapdlog(LOG_ERR
, "Out of memory");
3693 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3694 if (retcode
!= IDMAP_SUCCESS
)
3697 state
->pid2sid_done
= FALSE
;
3698 sqlite_freemem(sql
);
3701 /* Check if we need to update namecache */
3702 if (req
->direction
& _IDMAP_F_DONT_UPDATE_NAMECACHE
)
3705 if (req
->id2name
== NULL
)
3708 sql
= sqlite_mprintf("INSERT OR REPLACE into name_cache "
3709 "(sidprefix, rid, canon_name, domain, type, expiration) "
3710 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + %u); ",
3711 res
->id
.idmap_id_u
.sid
.prefix
, res
->id
.idmap_id_u
.sid
.rid
,
3712 req
->id2name
, req
->id2domain
,
3713 res
->id
.idtype
, state
->name_cache_timeout
);
3716 retcode
= IDMAP_ERR_INTERNAL
;
3717 idmapdlog(LOG_ERR
, "Out of memory");
3721 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3725 sqlite_freemem(sql
);
3730 update_cache_sid2pid(lookup_state_t
*state
,
3731 idmap_mapping
*req
, idmap_id_res
*res
)
3734 idmap_retcode retcode
;
3736 char *map_dn
= NULL
;
3737 char *map_attr
= NULL
;
3738 char *map_value
= NULL
;
3739 char *map_windomain
= NULL
;
3740 char *map_winname
= NULL
;
3741 char *map_unixname
= NULL
;
3742 int map_is_nt4
= FALSE
;
3744 /* Check if we need to cache anything */
3745 if (ARE_WE_DONE(req
->direction
))
3746 return (IDMAP_SUCCESS
);
3748 /* We don't cache negative entries */
3749 if (res
->retcode
!= IDMAP_SUCCESS
)
3750 return (IDMAP_SUCCESS
);
3752 if (req
->direction
& _IDMAP_F_EXP_EPH_UID
)
3754 else if (req
->direction
& _IDMAP_F_EXP_EPH_GID
)
3759 if (is_eph_user
>= 0 &&
3760 !IDMAP_ID_IS_EPHEMERAL(res
->id
.idmap_id_u
.uid
)) {
3761 sql
= sqlite_mprintf("UPDATE idmap_cache "
3762 "SET w2u = 0 WHERE "
3763 "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
3764 "pid >= 2147483648 AND is_user = %d;",
3765 req
->id1
.idmap_id_u
.sid
.prefix
,
3766 req
->id1
.idmap_id_u
.sid
.rid
,
3769 retcode
= IDMAP_ERR_INTERNAL
;
3770 idmapdlog(LOG_ERR
, "Out of memory");
3774 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3775 if (retcode
!= IDMAP_SUCCESS
)
3778 sqlite_freemem(sql
);
3782 assert(res
->direction
!= IDMAP_DIRECTION_UNDEF
);
3783 assert(res
->id
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
);
3785 switch (res
->info
.how
.map_type
) {
3786 case IDMAP_MAP_TYPE_DS_AD
:
3787 map_dn
= res
->info
.how
.idmap_how_u
.ad
.dn
;
3788 map_attr
= res
->info
.how
.idmap_how_u
.ad
.attr
;
3789 map_value
= res
->info
.how
.idmap_how_u
.ad
.value
;
3792 case IDMAP_MAP_TYPE_DS_NLDAP
:
3793 map_dn
= res
->info
.how
.idmap_how_u
.nldap
.dn
;
3794 map_attr
= res
->info
.how
.idmap_how_u
.ad
.attr
;
3795 map_value
= res
->info
.how
.idmap_how_u
.nldap
.value
;
3798 case IDMAP_MAP_TYPE_RULE_BASED
:
3799 map_windomain
= res
->info
.how
.idmap_how_u
.rule
.windomain
;
3800 map_winname
= res
->info
.how
.idmap_how_u
.rule
.winname
;
3801 map_unixname
= res
->info
.how
.idmap_how_u
.rule
.unixname
;
3802 map_is_nt4
= res
->info
.how
.idmap_how_u
.rule
.is_nt4
;
3805 case IDMAP_MAP_TYPE_EPHEMERAL
:
3808 case IDMAP_MAP_TYPE_IDMU
:
3809 map_dn
= res
->info
.how
.idmap_how_u
.idmu
.dn
;
3810 map_attr
= res
->info
.how
.idmap_how_u
.idmu
.attr
;
3811 map_value
= res
->info
.how
.idmap_how_u
.idmu
.value
;
3815 /* Don't cache other mapping types */
3819 sql
= sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3820 "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3821 "is_user, is_wuser, expiration, w2u, u2w, "
3822 "map_type, map_dn, map_attr, map_value, map_windomain, "
3823 "map_winname, map_unixname, map_is_nt4) "
3824 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3825 "strftime('%%s','now') + %u, 1, %q, "
3826 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d);",
3827 req
->id1
.idmap_id_u
.sid
.prefix
, req
->id1
.idmap_id_u
.sid
.rid
,
3828 (req
->id1domain
!= NULL
) ? req
->id1domain
: "", req
->id1name
,
3829 res
->id
.idmap_id_u
.uid
, req
->id2name
,
3830 (res
->id
.idtype
== IDMAP_UID
) ? 1 : 0,
3831 (req
->id1
.idtype
== IDMAP_USID
) ? 1 : 0,
3832 state
->id_cache_timeout
,
3833 (res
->direction
== 0) ? "1" : NULL
,
3834 res
->info
.how
.map_type
, map_dn
, map_attr
, map_value
,
3835 map_windomain
, map_winname
, map_unixname
, map_is_nt4
);
3838 retcode
= IDMAP_ERR_INTERNAL
;
3839 idmapdlog(LOG_ERR
, "Out of memory");
3843 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3844 if (retcode
!= IDMAP_SUCCESS
)
3847 state
->sid2pid_done
= FALSE
;
3848 sqlite_freemem(sql
);
3851 /* Check if we need to update namecache */
3852 if (req
->direction
& _IDMAP_F_DONT_UPDATE_NAMECACHE
)
3855 if (EMPTY_STRING(req
->id1name
))
3858 sql
= sqlite_mprintf("INSERT OR REPLACE into name_cache "
3859 "(sidprefix, rid, canon_name, domain, type, expiration) "
3860 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + %u); ",
3861 req
->id1
.idmap_id_u
.sid
.prefix
, req
->id1
.idmap_id_u
.sid
.rid
,
3862 req
->id1name
, req
->id1domain
,
3863 req
->id1
.idtype
, state
->name_cache_timeout
);
3866 retcode
= IDMAP_ERR_INTERNAL
;
3867 idmapdlog(LOG_ERR
, "Out of memory");
3871 retcode
= sql_exec_no_cb(state
->cache
, IDMAP_CACHENAME
, sql
);
3875 sqlite_freemem(sql
);
3881 lookup_cache_pid2sid(sqlite
*cache
, idmap_mapping
*req
, idmap_id_res
*res
,
3886 const char **values
;
3887 sqlite_vm
*vm
= NULL
;
3889 idmap_retcode retcode
= IDMAP_SUCCESS
;
3891 idmap_id_type idtype
;
3895 if ((curtime
= time(NULL
)) == (time_t)-1) {
3896 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
3898 retcode
= IDMAP_ERR_INTERNAL
;
3902 /* SQL to lookup the cache by pid or by unixname */
3903 if (req
->id1
.idmap_id_u
.uid
!= IDMAP_SENTINEL_PID
) {
3904 sql
= sqlite_mprintf("SELECT sidprefix, rid, "
3905 "canon_winname, windomain, w2u, is_wuser, "
3906 "map_type, map_dn, map_attr, map_value, map_windomain, "
3907 "map_winname, map_unixname, map_is_nt4 "
3908 "FROM idmap_cache WHERE "
3909 "pid = %u AND u2w = 1 AND is_user = %d AND "
3910 "(pid >= 2147483648 OR "
3911 "(expiration = 0 OR expiration ISNULL OR "
3912 "expiration > %d));",
3913 req
->id1
.idmap_id_u
.uid
, is_user
, curtime
);
3914 } else if (req
->id1name
!= NULL
) {
3915 sql
= sqlite_mprintf("SELECT sidprefix, rid, "
3916 "canon_winname, windomain, w2u, is_wuser, "
3917 "map_type, map_dn, map_attr, map_value, map_windomain, "
3918 "map_winname, map_unixname, map_is_nt4 "
3919 "FROM idmap_cache WHERE "
3920 "unixname = %Q AND u2w = 1 AND is_user = %d AND "
3921 "(pid >= 2147483648 OR "
3922 "(expiration = 0 OR expiration ISNULL OR "
3923 "expiration > %d));",
3924 req
->id1name
, is_user
, curtime
);
3926 retcode
= IDMAP_ERR_ARG
;
3931 idmapdlog(LOG_ERR
, "Out of memory");
3932 retcode
= IDMAP_ERR_MEMORY
;
3935 retcode
= sql_compile_n_step_once(
3936 cache
, sql
, &vm
, &ncol
, 14, &values
);
3937 sqlite_freemem(sql
);
3939 if (retcode
== IDMAP_ERR_NOTFOUND
)
3941 else if (retcode
== IDMAP_SUCCESS
) {
3943 if (values
[0] == NULL
|| values
[1] == NULL
) {
3944 retcode
= IDMAP_ERR_CACHE
;
3948 switch (res
->id
.idtype
) {
3952 idtype
= strtol(values
[5], &end
, 10) == 1
3953 ? IDMAP_USID
: IDMAP_GSID
;
3955 if (res
->id
.idtype
== IDMAP_USID
&&
3956 idtype
!= IDMAP_USID
) {
3957 retcode
= IDMAP_ERR_NOTUSER
;
3959 } else if (res
->id
.idtype
== IDMAP_GSID
&&
3960 idtype
!= IDMAP_GSID
) {
3961 retcode
= IDMAP_ERR_NOTGROUP
;
3964 res
->id
.idtype
= idtype
;
3966 res
->id
.idmap_id_u
.sid
.rid
=
3967 strtoul(values
[1], &end
, 10);
3968 res
->id
.idmap_id_u
.sid
.prefix
= strdup(values
[0]);
3969 if (res
->id
.idmap_id_u
.sid
.prefix
== NULL
) {
3970 idmapdlog(LOG_ERR
, "Out of memory");
3971 retcode
= IDMAP_ERR_MEMORY
;
3975 if (values
[4] != NULL
)
3977 (strtol(values
[4], &end
, 10) == 0)?
3978 IDMAP_DIRECTION_U2W
:IDMAP_DIRECTION_BI
;
3980 res
->direction
= IDMAP_DIRECTION_U2W
;
3982 if (values
[2] == NULL
)
3984 req
->id2name
= strdup(values
[2]);
3985 if (req
->id2name
== NULL
) {
3986 idmapdlog(LOG_ERR
, "Out of memory");
3987 retcode
= IDMAP_ERR_MEMORY
;
3991 if (values
[3] == NULL
)
3993 req
->id2domain
= strdup(values
[3]);
3994 if (req
->id2domain
== NULL
) {
3995 idmapdlog(LOG_ERR
, "Out of memory");
3996 retcode
= IDMAP_ERR_MEMORY
;
4002 retcode
= IDMAP_ERR_NOTSUPPORTED
;
4005 if (req
->flag
& IDMAP_REQ_FLG_MAPPING_INFO
) {
4006 res
->info
.src
= IDMAP_MAP_SRC_CACHE
;
4007 res
->info
.how
.map_type
= strtoul(values
[6], &end
, 10);
4008 switch (res
->info
.how
.map_type
) {
4009 case IDMAP_MAP_TYPE_DS_AD
:
4010 res
->info
.how
.idmap_how_u
.ad
.dn
=
4012 res
->info
.how
.idmap_how_u
.ad
.attr
=
4014 res
->info
.how
.idmap_how_u
.ad
.value
=
4018 case IDMAP_MAP_TYPE_DS_NLDAP
:
4019 res
->info
.how
.idmap_how_u
.nldap
.dn
=
4021 res
->info
.how
.idmap_how_u
.nldap
.attr
=
4023 res
->info
.how
.idmap_how_u
.nldap
.value
=
4027 case IDMAP_MAP_TYPE_RULE_BASED
:
4028 res
->info
.how
.idmap_how_u
.rule
.windomain
=
4030 res
->info
.how
.idmap_how_u
.rule
.winname
=
4032 res
->info
.how
.idmap_how_u
.rule
.unixname
=
4034 res
->info
.how
.idmap_how_u
.rule
.is_nt4
=
4035 strtoul(values
[13], &end
, 10);
4036 res
->info
.how
.idmap_how_u
.rule
.is_user
=
4038 res
->info
.how
.idmap_how_u
.rule
.is_wuser
=
4039 strtol(values
[5], &end
, 10);
4042 case IDMAP_MAP_TYPE_EPHEMERAL
:
4045 case IDMAP_MAP_TYPE_LOCAL_SID
:
4048 case IDMAP_MAP_TYPE_KNOWN_SID
:
4051 case IDMAP_MAP_TYPE_IDMU
:
4052 res
->info
.how
.idmap_how_u
.idmu
.dn
=
4054 res
->info
.how
.idmap_how_u
.idmu
.attr
=
4056 res
->info
.how
.idmap_how_u
.idmu
.value
=
4061 /* Unknown mapping type */
4069 (void) sqlite_finalize(vm
, NULL
);
4075 * cache sqlite handle
4076 * name Windows user name
4077 * domain Windows domain name
4079 * Return: Error code
4081 * *canonname Canonical name (if canonname is non-NULL) [1]
4082 * *sidprefix SID prefix [1]
4084 * *type Type of name
4086 * [1] malloc'ed, NULL on error
4090 lookup_cache_name2sid(
4097 idmap_id_type
*type
)
4099 char *end
, *lower_name
;
4101 const char **values
;
4102 sqlite_vm
*vm
= NULL
;
4105 idmap_retcode retcode
;
4108 if (canonname
!= NULL
)
4111 /* Get current time */
4113 if ((curtime
= time(NULL
)) == (time_t)-1) {
4114 idmapdlog(LOG_ERR
, "Failed to get current time (%s)",
4116 retcode
= IDMAP_ERR_INTERNAL
;
4120 /* SQL to lookup the cache */
4121 if ((lower_name
= tolower_u8(name
)) == NULL
)
4122 lower_name
= (char *)name
;
4123 sql
= sqlite_mprintf("SELECT sidprefix, rid, type, canon_name "
4124 "FROM name_cache WHERE name = %Q AND domain = %Q AND "
4125 "(expiration = 0 OR expiration ISNULL OR "
4126 "expiration > %d);", lower_name
, domain
, curtime
);
4127 if (lower_name
!= name
)
4130 idmapdlog(LOG_ERR
, "Out of memory");
4131 retcode
= IDMAP_ERR_MEMORY
;
4134 retcode
= sql_compile_n_step_once(cache
, sql
, &vm
, &ncol
, 4, &values
);
4136 sqlite_freemem(sql
);
4138 if (retcode
!= IDMAP_SUCCESS
)
4142 if (values
[2] == NULL
) {
4143 retcode
= IDMAP_ERR_CACHE
;
4146 *type
= xlate_legacy_type(strtol(values
[2], &end
, 10));
4149 if (values
[0] == NULL
|| values
[1] == NULL
) {
4150 retcode
= IDMAP_ERR_CACHE
;
4154 if (canonname
!= NULL
) {
4155 assert(values
[3] != NULL
);
4156 *canonname
= strdup(values
[3]);
4157 if (*canonname
== NULL
) {
4158 idmapdlog(LOG_ERR
, "Out of memory");
4159 retcode
= IDMAP_ERR_MEMORY
;
4164 *sidprefix
= strdup(values
[0]);
4165 if (*sidprefix
== NULL
) {
4166 idmapdlog(LOG_ERR
, "Out of memory");
4167 retcode
= IDMAP_ERR_MEMORY
;
4170 *rid
= strtoul(values
[1], &end
, 10);
4172 retcode
= IDMAP_SUCCESS
;
4176 (void) sqlite_finalize(vm
, NULL
);
4178 if (retcode
!= IDMAP_SUCCESS
) {
4181 if (canonname
!= NULL
) {
4191 ad_lookup_by_winname(lookup_state_t
*state
,
4192 const char *name
, const char *domain
, int esidtype
,
4193 char **dn
, char **attr
, char **value
, char **canonname
,
4194 char **sidprefix
, idmap_rid_t
*rid
, idmap_id_type
*wintype
,
4198 idmap_query_state_t
*qs
= NULL
;
4199 idmap_retcode rc
, retcode
;
4204 if (_idmapdstate
.num_gcs
> 0) {
4205 for (i
= 0; i
< _idmapdstate
.num_gcs
&& !found_ad
; i
++) {
4208 retcode
= idmap_lookup_batch_start(
4209 _idmapdstate
.gcs
[i
],
4211 _idmapdstate
.cfg
->pgcfg
.directory_based_mapping
,
4212 _idmapdstate
.cfg
->pgcfg
.default_domain
,
4214 if (retcode
!= IDMAP_SUCCESS
) {
4215 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
4216 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
4218 degrade_svc(1, "failed to create request for "
4219 "AD lookup by winname");
4225 if (state
!= NULL
&& i
== 0) {
4227 * Directory based name mapping is only
4228 * performed within the joined forest (i == 0).
4229 * We don't trust other "trusted" forests to
4230 * provide DS-based name mapping information
4231 * because AD's definition of "cross-forest
4232 * trust" does not encompass this sort of
4235 idmap_lookup_batch_set_unixattr(qs
,
4236 state
->ad_unixuser_attr
,
4237 state
->ad_unixgroup_attr
);
4240 retcode
= idmap_name2sid_batch_add1(qs
, name
, domain
,
4241 esidtype
, dn
, attr
, value
, canonname
, sidprefix
,
4242 rid
, wintype
, unixname
, NULL
, &rc
);
4243 if (retcode
== IDMAP_ERR_DOMAIN_NOTFOUND
) {
4244 idmap_lookup_release_batch(&qs
);
4248 if (retcode
!= IDMAP_SUCCESS
)
4249 idmap_lookup_release_batch(&qs
);
4251 retcode
= idmap_lookup_batch_end(&qs
);
4253 if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
&&
4254 retries
++ < ADUTILS_DEF_NUM_RETRIES
)
4256 else if (retcode
== IDMAP_ERR_RETRIABLE_NET_ERR
)
4258 "some AD lookups timed out repeatedly");
4262 retcode
= IDMAP_ERR_NO_ACTIVEDIRECTORY
;
4266 if (retcode
!= IDMAP_SUCCESS
) {
4267 idmapdlog(LOG_NOTICE
,
4268 "AD lookup of winname %s@%s failed, error code %d",
4269 name
== NULL
? "(null)" : name
,
4270 domain
== NULL
? "(null)" : domain
,
4279 * cache sqlite handle to cache
4280 * name Windows user name
4281 * domain Windows domain name
4282 * local_only if true, don't try AD lookups
4284 * Returns: Error code
4286 * *canonname Canonical name (if non-NULL) [1]
4287 * *canondomain Canonical domain (if non-NULL) [1]
4288 * *sidprefix SID prefix [1]
4290 * *req Request (direction is updated)
4292 * [1] malloc'ed, NULL on error
4304 idmap_id_type
*type
,
4308 idmap_retcode retcode
;
4311 if (canonname
!= NULL
)
4313 if (canondomain
!= NULL
)
4314 *canondomain
= NULL
;
4316 /* Lookup well-known SIDs table */
4317 retcode
= lookup_wksids_name2sid(name
, domain
, canonname
, canondomain
,
4318 sidprefix
, rid
, type
);
4319 if (retcode
== IDMAP_SUCCESS
) {
4320 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
4322 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4327 retcode
= lookup_cache_name2sid(cache
, name
, domain
, canonname
,
4328 sidprefix
, rid
, type
);
4329 if (retcode
== IDMAP_SUCCESS
) {
4330 req
->direction
|= _IDMAP_F_DONT_UPDATE_NAMECACHE
;
4332 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4337 * The caller may be using this function to determine if this
4338 * request needs to be marked for AD lookup or not
4339 * (i.e. _IDMAP_F_LOOKUP_AD) and therefore may not want this
4340 * function to AD lookup now.
4345 if (_idmapdstate
.cfg
->pgcfg
.use_lsa
&&
4346 _idmapdstate
.cfg
->pgcfg
.domain_name
!= NULL
&&
4347 name
!= NULL
&& *sidprefix
== NULL
) {
4348 retcode
= lookup_lsa_by_name(name
, domain
,
4350 canonname
, canondomain
,
4352 if (retcode
== IDMAP_SUCCESS
)
4354 else if (retcode
!= IDMAP_ERR_NOTFOUND
)
4359 retcode
= ad_lookup_by_winname(NULL
, name
, domain
, IDMAP_POSIXID
,
4360 NULL
, NULL
, NULL
, canonname
, sidprefix
, rid
, type
, NULL
);
4361 if (retcode
!= IDMAP_SUCCESS
)
4366 * Entry found (cache or Windows lookup)
4368 if (want_wuser
== 1 && *type
!= IDMAP_USID
)
4369 retcode
= IDMAP_ERR_NOTUSER
;
4370 else if (want_wuser
== 0 && *type
!= IDMAP_GSID
)
4371 retcode
= IDMAP_ERR_NOTGROUP
;
4372 else if (want_wuser
== -1) {
4374 * Caller wants to know if its user or group
4375 * Verify that it's one or the other.
4377 if (*type
!= IDMAP_USID
&& *type
!= IDMAP_GSID
)
4378 retcode
= IDMAP_ERR_SID
;
4381 if (retcode
== IDMAP_SUCCESS
) {
4383 * If we were asked for a canonical domain and none
4384 * of the searches have provided one, assume it's the
4387 if (canondomain
!= NULL
&& *canondomain
== NULL
) {
4388 *canondomain
= strdup(domain
);
4389 if (*canondomain
== NULL
)
4390 retcode
= IDMAP_ERR_MEMORY
;
4393 if (retcode
!= IDMAP_SUCCESS
) {
4396 if (canonname
!= NULL
) {
4400 if (canondomain
!= NULL
) {
4402 *canondomain
= NULL
;
4410 name_based_mapping_pid2sid(lookup_state_t
*state
, const char *unixname
,
4411 int is_user
, idmap_mapping
*req
, idmap_id_res
*res
)
4413 const char *winname
, *windomain
;
4416 char *sql
= NULL
, *errmsg
= NULL
;
4417 idmap_retcode retcode
;
4419 const char **values
;
4420 sqlite_vm
*vm
= NULL
;
4423 const char *me
= "name_based_mapping_pid2sid";
4424 idmap_namerule
*rule
= &res
->info
.how
.idmap_how_u
.rule
;
4427 assert(unixname
!= NULL
); /* We have unixname */
4428 assert(req
->id2name
== NULL
); /* We don't have winname */
4429 assert(res
->id
.idmap_id_u
.sid
.prefix
== NULL
); /* No SID either */
4431 sql
= sqlite_mprintf(
4432 "SELECT winname_display, windomain, w2u_order, "
4433 "is_wuser, unixname, is_nt4 "
4434 "FROM namerules WHERE "
4435 "u2w_order > 0 AND is_user = %d AND "
4436 "(unixname = %Q OR unixname = '*') "
4437 "ORDER BY u2w_order ASC;", is_user
, unixname
);
4439 idmapdlog(LOG_ERR
, "Out of memory");
4440 retcode
= IDMAP_ERR_MEMORY
;
4444 if (sqlite_compile(state
->db
, sql
, NULL
, &vm
, &errmsg
) != SQLITE_OK
) {
4445 retcode
= IDMAP_ERR_INTERNAL
;
4446 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
4447 CHECK_NULL(errmsg
));
4448 sqlite_freemem(errmsg
);
4453 r
= sqlite_step(vm
, &ncol
, &values
, NULL
);
4454 assert(r
!= SQLITE_LOCKED
&& r
!= SQLITE_BUSY
);
4455 if (r
== SQLITE_ROW
) {
4457 retcode
= IDMAP_ERR_INTERNAL
;
4461 TRACE(req
, res
, "Matching rule: %s -> %s@%s",
4462 values
[4] == NULL
? "(null)" : values
[4],
4463 values
[0] == NULL
? "(null)" : values
[0],
4464 values
[1] == NULL
? "(null)" : values
[1]);
4466 if (values
[0] == NULL
) {
4467 /* values [1] and [2] can be null */
4468 retcode
= IDMAP_ERR_INTERNAL
;
4472 if (values
[2] != NULL
)
4474 (strtol(values
[2], &end
, 10) == 0)?
4475 IDMAP_DIRECTION_U2W
:IDMAP_DIRECTION_BI
;
4477 direction
= IDMAP_DIRECTION_U2W
;
4479 if (EMPTY_NAME(values
[0])) {
4480 idmap_namerule_set(rule
, values
[1], values
[0],
4482 strtol(values
[3], &end
, 10),
4483 strtol(values
[5], &end
, 10),
4485 TRACE(req
, res
, "Mapping inhibited");
4486 retcode
= IDMAP_ERR_NOMAPPING
;
4490 if (values
[0][0] == '*') {
4493 winname
= values
[0];
4496 want_wuser
= res
->id
.idtype
== IDMAP_USID
? 1
4497 : res
->id
.idtype
== IDMAP_GSID
? 0
4499 if (values
[1] != NULL
)
4500 windomain
= values
[1];
4501 else if (state
->defdom
!= NULL
) {
4502 windomain
= state
->defdom
;
4504 "Added default domain %s to rule",
4507 idmapdlog(LOG_ERR
, "%s: no domain", me
);
4509 "No domain in rule, and no default domain");
4510 retcode
= IDMAP_ERR_DOMAIN_NOTFOUND
;
4514 retcode
= lookup_name2sid(state
->cache
,
4516 want_wuser
, &canonname
, &canondomain
,
4517 &res
->id
.idmap_id_u
.sid
.prefix
,
4518 &res
->id
.idmap_id_u
.sid
.rid
,
4519 &res
->id
.idtype
, req
, 0);
4521 if (retcode
== IDMAP_SUCCESS
) {
4523 } else if (retcode
== IDMAP_ERR_NOTFOUND
) {
4524 if (values
[0][0] == '*') {
4526 "%s@%s not found, continuing",
4527 winname
, windomain
);
4532 winname
, windomain
);
4533 retcode
= IDMAP_ERR_NOMAPPING
;
4537 "Looking up %s@%s error=%d",
4538 winname
, windomain
, retcode
);
4541 idmap_namerule_set(rule
, values
[1],
4542 values
[0], values
[4], is_user
,
4543 strtol(values
[3], &end
, 10),
4544 strtol(values
[5], &end
, 10),
4549 } else if (r
== SQLITE_DONE
) {
4550 TRACE(req
, res
, "No matching rule");
4551 retcode
= IDMAP_ERR_NOTFOUND
;
4554 (void) sqlite_finalize(vm
, &errmsg
);
4556 idmapdlog(LOG_ERR
, "%s: database error (%s)", me
,
4557 CHECK_NULL(errmsg
));
4558 sqlite_freemem(errmsg
);
4559 retcode
= IDMAP_ERR_INTERNAL
;
4564 if (values
[2] != NULL
)
4566 (strtol(values
[2], &end
, 10) == 0)?
4567 IDMAP_DIRECTION_U2W
:IDMAP_DIRECTION_BI
;
4569 res
->direction
= IDMAP_DIRECTION_U2W
;
4571 req
->id2name
= canonname
;
4572 req
->id2domain
= canondomain
;
4574 idmap_namerule_set(rule
, values
[1], values
[0], values
[4],
4575 is_user
, strtol(values
[3], &end
, 10),
4576 strtol(values
[5], &end
, 10),
4578 TRACE(req
, res
, "Windows name found");
4582 sqlite_freemem(sql
);
4584 if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4585 res
->info
.how
.map_type
= IDMAP_MAP_TYPE_RULE_BASED
;
4586 res
->info
.src
= IDMAP_MAP_SRC_NEW
;
4590 (void) sqlite_finalize(vm
, NULL
);
4595 * Convention when processing unix2win requests:
4599 * unixname if given otherwise unixname found will be placed
4604 * Given type (IDMAP_UID or IDMAP_GID)
4605 * req->id1..[uid or gid] =
4606 * UID/GID if given otherwise UID/GID found will be placed here.
4610 * winname found will be placed here.
4612 * windomain found will be placed here.
4614 * Target type initialized from req->id2.idtype. If
4615 * it is IDMAP_SID then actual type (IDMAP_USID/GSID) found
4616 * will be placed here.
4617 * req->id..sid.[prefix, rid] =
4618 * SID found will be placed here.
4622 * Return status for this request will be placed here.
4624 * Direction found will be placed here. Direction
4625 * meaning whether the resultant mapping is valid
4626 * only from unix2win or bi-directional.
4628 * INTERNAL USE. Used by idmapd to set various
4629 * flags (_IDMAP_F_xxxx) to aid in processing
4632 * INTERNAL USE. Initially this is the requested target
4633 * type and is used to initialize res->id.idtype.
4634 * ad_lookup_batch() uses this field temporarily to store
4635 * sid_type obtained by the batched AD lookups and after
4636 * use resets it to IDMAP_NONE to prevent xdr from
4637 * mis-interpreting the contents of req->id2.
4638 * req->id2..[uid or gid or sid] =
4643 * This function does the following:
4644 * 1. Lookup well-known SIDs table.
4646 * 3. Check if the client does not want new mapping to be allocated
4647 * in which case this pass is the final pass.
4648 * 4. Set AD/NLDAP lookup flags if it determines that the next stage needs
4649 * to do AD/NLDAP lookup.
4652 pid2sid_first_pass(lookup_state_t
*state
, idmap_mapping
*req
,
4653 idmap_id_res
*res
, int is_user
)
4655 idmap_retcode retcode
;
4656 idmap_retcode retcode2
;
4657 bool_t gen_localsid_on_err
= FALSE
;
4659 /* Initialize result */
4660 res
->id
.idtype
= req
->id2
.idtype
;
4661 res
->direction
= IDMAP_DIRECTION_UNDEF
;
4663 if (req
->id2
.idmap_id_u
.sid
.prefix
!= NULL
) {
4664 /* sanitize sidprefix */
4665 free(req
->id2
.idmap_id_u
.sid
.prefix
);
4666 req
->id2
.idmap_id_u
.sid
.prefix
= NULL
;
4670 if (req
->id1
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) {
4671 if (req
->id1name
== NULL
) {
4672 retcode
= IDMAP_ERR_ARG
;
4676 retcode
= ns_lookup_byname(req
->id1name
, NULL
, &req
->id1
);
4677 if (retcode
!= IDMAP_SUCCESS
) {
4678 TRACE(req
, res
, "Getting UNIX ID error=%d", retcode
);
4679 retcode
= IDMAP_ERR_NOMAPPING
;
4682 TRACE(req
, res
, "Found UNIX ID");
4685 /* Lookup in well-known SIDs table */
4686 retcode
= lookup_wksids_pid2sid(req
, res
, is_user
);
4687 if (retcode
== IDMAP_SUCCESS
) {
4688 TRACE(req
, res
, "Hardwired mapping");
4690 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4692 "Well-known account lookup error=%d", retcode
);
4696 /* Lookup in cache */
4697 retcode
= lookup_cache_pid2sid(state
->cache
, req
, res
, is_user
);
4698 if (retcode
== IDMAP_SUCCESS
) {
4699 TRACE(req
, res
, "Found in mapping cache");
4701 } else if (retcode
!= IDMAP_ERR_NOTFOUND
) {
4703 "Mapping cache lookup error=%d", retcode
);
4706 TRACE(req
, res
, "Not found in mapping cache");
4708 /* Ephemeral ids cannot be allocated during pid2sid */
4709 if (IDMAP_ID_IS_EPHEMERAL(req
->id1
.idmap_id_u
.uid
)) {
4710 retcode
= IDMAP_ERR_NOMAPPING
;
4711 TRACE(req
, res
, "Shouldn't have an ephemeral ID here");
4715 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req
)) {
4716 retcode
= IDMAP_ERR_NONE_GENERATED
;
4720 if (AVOID_NAMESERVICE(req
)) {
4721 gen_localsid_on_err
= TRUE
;
4722 retcode
= IDMAP_ERR_NOMAPPING
;
4726 /* Set flags for the next stage */
4727 if (state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
) {
4728 req
->direction
|= _IDMAP_F_LOOKUP_AD
;
4729 state
->ad_nqueries
++;
4730 } else if (AD_MODE(req
->id1
.idtype
, state
)) {
4732 * If AD-based name mapping is enabled then the next stage
4733 * will need to lookup AD using unixname to get the
4734 * corresponding winname.
4736 if (req
->id1name
== NULL
) {
4737 /* Get unixname if only pid is given. */
4738 retcode
= ns_lookup_bypid(req
->id1
.idmap_id_u
.uid
,
4739 is_user
, &req
->id1name
);
4740 if (retcode
!= IDMAP_SUCCESS
) {
4742 "Getting UNIX name error=%d", retcode
);
4743 gen_localsid_on_err
= TRUE
;
4746 TRACE(req
, res
, "Found UNIX name");
4748 req
->direction
|= _IDMAP_F_LOOKUP_AD
;
4749 state
->ad_nqueries
++;
4750 } else if (NLDAP_OR_MIXED_MODE(req
->id1
.idtype
, state
)) {
4752 * If native LDAP or mixed mode is enabled for name mapping
4753 * then the next stage will need to lookup native LDAP using
4754 * unixname/pid to get the corresponding winname.
4756 req
->direction
|= _IDMAP_F_LOOKUP_NLDAP
;
4757 state
->nldap_nqueries
++;
4761 * Failed to find non-expired entry in cache. Set the flag to
4762 * indicate that we are not done yet.
4764 state
->pid2sid_done
= FALSE
;
4765 req
->direction
|= _IDMAP_F_NOTDONE
;
4766 retcode
= IDMAP_SUCCESS
;
4769 res
->retcode
= idmap_stat4prot(retcode
);
4770 if (ARE_WE_DONE(req
->direction
) && res
->retcode
!= IDMAP_SUCCESS
) {
4771 if (gen_localsid_on_err
== TRUE
) {
4772 retcode2
= generate_localsid(req
, res
, is_user
, TRUE
);
4773 if (retcode2
== IDMAP_SUCCESS
)
4774 TRACE(req
, res
, "Generate local SID");
4777 "Generate local SID error=%d", retcode2
);
4784 pid2sid_second_pass(lookup_state_t
*state
, idmap_mapping
*req
,
4785 idmap_id_res
*res
, int is_user
)
4787 bool_t gen_localsid_on_err
= TRUE
;
4788 idmap_retcode retcode
= IDMAP_SUCCESS
;
4789 idmap_retcode retcode2
;
4791 /* Check if second pass is needed */
4792 if (ARE_WE_DONE(req
->direction
))
4793 return (res
->retcode
);
4795 /* Get status from previous pass */
4796 retcode
= res
->retcode
;
4797 if (retcode
!= IDMAP_SUCCESS
)
4801 * If directory-based name mapping is enabled then the winname
4802 * may already have been retrieved from the AD object (AD-mode)
4803 * or from native LDAP object (nldap-mode or mixed-mode).
4804 * Note that if we have winname but no SID then it's an error
4805 * because this implies that the Native LDAP entry contains
4806 * winname which does not exist and it's better that we return
4807 * an error instead of doing rule-based mapping so that the user
4808 * can detect the issue and take appropriate action.
4810 if (req
->id2name
!= NULL
) {
4811 /* Return notfound if we've winname but no SID. */
4812 if (res
->id
.idmap_id_u
.sid
.prefix
== NULL
) {
4813 TRACE(req
, res
, "Windows name but no SID");
4814 retcode
= IDMAP_ERR_NOTFOUND
;
4817 if (state
->directory_based_mapping
== DIRECTORY_MAPPING_IDMU
)
4818 res
->direction
= IDMAP_DIRECTION_BI
;
4819 else if (AD_MODE(req
->id1
.idtype
, state
))
4820 res
->direction
= IDMAP_DIRECTION_BI
;
4821 else if (NLDAP_MODE(req
->id1
.idtype
, state
))
4822 res
->direction
= IDMAP_DIRECTION_BI
;
4823 else if (MIXED_MODE(req
->id1
.idtype
, state
))
4824 res
->direction
= IDMAP_DIRECTION_W2U
;
4826 } else if (res
->id
.idmap_id_u
.sid
.prefix
!= NULL
) {
4828 * We've SID but no winname. This is fine because
4829 * the caller may have only requested SID.
4834 /* Free any mapping info from Directory based mapping */
4835 if (res
->info
.how
.map_type
!= IDMAP_MAP_TYPE_UNKNOWN
)
4836 idmap_how_clear(&res
->info
.how
);
4838 if (req
->id1name
== NULL
) {
4839 /* Get unixname from name service */
4840 retcode
= ns_lookup_bypid(req
->id1
.idmap_id_u
.uid
, is_user
,
4842 if (retcode
!= IDMAP_SUCCESS
) {
4844 "Getting UNIX name error=%d", retcode
);
4847 TRACE(req
, res
, "Found UNIX name");
4848 } else if (req
->id1
.idmap_id_u
.uid
== IDMAP_SENTINEL_PID
) {
4849 /* Get pid from name service */
4850 retcode
= ns_lookup_byname(req
->id1name
, NULL
, &req
->id1
);
4851 if (retcode
!= IDMAP_SUCCESS
) {
4853 "Getting UNIX ID error=%d", retcode
);
4854 gen_localsid_on_err
= FALSE
;
4857 TRACE(req
, res
, "Found UNIX ID");
4860 /* Use unixname to evaluate local name-based mapping rules */
4861 retcode
= name_based_mapping_pid2sid(state
, req
->id1name
, is_user
,
4863 if (retcode
== IDMAP_ERR_NOTFOUND
) {
4864 retcode
= generate_localsid(req
, res
, is_user
, FALSE
);
4865 if (retcode
== IDMAP_SUCCESS
) {
4866 TRACE(req
, res
, "Generated local SID");
4869 "Generating local SID error=%d", retcode
);
4871 gen_localsid_on_err
= FALSE
;
4875 res
->retcode
= idmap_stat4prot(retcode
);
4876 if (res
->retcode
!= IDMAP_SUCCESS
) {
4877 req
->direction
= _IDMAP_F_DONE
;
4879 req
->id2name
= NULL
;
4880 free(req
->id2domain
);
4881 req
->id2domain
= NULL
;
4882 if (gen_localsid_on_err
== TRUE
) {
4883 retcode2
= generate_localsid(req
, res
, is_user
, TRUE
);
4884 if (retcode2
== IDMAP_SUCCESS
)
4885 TRACE(req
, res
, "Generate local SID");
4888 "Generate local SID error=%d", retcode2
);
4890 res
->id
.idtype
= is_user
? IDMAP_USID
: IDMAP_GSID
;
4893 if (!ARE_WE_DONE(req
->direction
))
4894 state
->pid2sid_done
= FALSE
;
4899 idmap_cache_flush(idmap_flush_op op
)
4902 sqlite
*cache
= NULL
;
4907 case IDMAP_FLUSH_EXPIRE
:
4909 "UPDATE idmap_cache SET expiration=1 WHERE expiration>0;";
4911 "UPDATE name_cache SET expiration=1 WHERE expiration>0;";
4914 case IDMAP_FLUSH_DELETE
:
4915 sql1
= "DELETE FROM idmap_cache;";
4916 sql2
= "DELETE FROM name_cache;";
4920 return (IDMAP_ERR_INTERNAL
);
4923 rc
= get_cache_handle(&cache
);
4924 if (rc
!= IDMAP_SUCCESS
)
4928 * Note that we flush the idmapd cache first, before the kernel
4929 * cache. If we did it the other way 'round, a request could come
4930 * in after the kernel cache flush and pull a soon-to-be-flushed
4931 * idmapd cache entry back into the kernel cache. This way the
4932 * worst that will happen is that a new entry will be added to
4933 * the kernel cache and then immediately flushed.
4936 rc
= sql_exec_no_cb(cache
, IDMAP_CACHENAME
, sql1
);
4937 if (rc
!= IDMAP_SUCCESS
)
4940 rc
= sql_exec_no_cb(cache
, IDMAP_CACHENAME
, sql2
);
4942 (void) __idmap_flush_kcache();