dbutils.c revision 08f0d8da054d72c87f9a35f2ea891d2c3541ceb5
* Data structure to store well-known SIDs and * associated mappings (if any) * Thread specific data to hold the database handles so that the * databases are not opened and closed for every request. It also * contains the sqlite busy handler structure. {
1,
2,
5,
10,
15,
20,
25,
30,
35,
40,
50,
50,
60,
70,
80,
90,
100};
{
5,
10,
15,
20,
30,
40,
55,
70,
100};
/* No thread specific data so create it */ /* Initialize thread specific data */ /* save the trhread specific data */ * A simple wrapper around u8_textprep_str() that returns the Unicode * lower-case version of some string. The result must be freed. * u8_textprep_str() does not allocate memory. The input and * output buffers may differ in size (though that would be more * likely when normalization is done). We have to loop over it... * To improve the chances that we can avoid looping we add 10 * bytes of output buffer room the first go around. /* adjust outbytesleft and outlen */ * Initialize 'dbname' using 'sql' /* Last try, log errors */ /* Detect current version of schema in the db, if any */ #
endif /* IDMAPD_DEBUG */ "Error detecting schema version of db %s (%s)",
"Error detecting schema version of db %s",
dbname);
/* Install or upgrade schema */ #
endif /* IDMAPD_DEBUG */ (
curr_version == 0) ?
"installing schema" :
"upgrading schema");
* This is the SQLite database busy handler that retries the SQL * operation until it is successful. /* LINTED E_FUNC_ARG_UNUSED */ "Thread %d waited %d sec for the %s database",
* Get the database handle * Retrieve the db handle from thread-specific storage * If none exists, open and store in thread-specific storage. * Retrieve the db handle from thread-specific storage * If none exists, open and store in thread-specific storage. * Initialize cache and db /* name-based mappings; probably OK to blow away in a pinch(?) */ /* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */ * This table is a listing of status codes that will be returned to the * client when a SQL command fails with the corresponding error message. "columns unixname, is_user, u2w_order are not unique"},
"columns winname, windomain, is_user, is_wuser, w2u_order are not" * idmapd's version of string2stat to map SQLite messages to * Executes some SQL in a transaction. * Returns 0 on success, -1 if it failed but the rollback succeeded, -2 * if the rollback failed. * Execute the given SQL statment without using any callbacks * Generate expression that can be used in WHERE statements. * <prefix> <col> <op> <value> <suffix> * "" "unixuser" "=" "foo" "AND" "AND winname = %Q AND is_wuser = %d ",
"AND unixname = %Q AND is_user = %d ",
* Generate and execute SQL statement for LIST RPC calls * This routine is called by callbacks that process the results of * LIST RPC calls to validate data and to allocate memory for /* alloc in bulk to reduce number of reallocs */ * Windows to UNIX lookup order: * 1. winname@domain (or winname) to "" * 2. winname@domain (or winname) to unixname * 4. winname@* to unixname * 5. *@domain (or *) to * * 6. *@domain (or *) to "" * 7. *@domain (or *) to unixname * winname is a special case of winname@domain when domain is the * default domain. Similarly * is a special case of *@domain when * domain is the default domain. * Note that "" has priority over specific names because "" inhibits * mappings and traditionally deny rules always had higher priority. /* bi-directional or from windows to unix */ else /* unixname == name */ /* winname == name && windomain == null or name */ * 1. unixname to "", non-diagonal * 2. unixname to winname@domain (or winname), non-diagonal * 3. unixname to "", diagonal * 4. unixname to winname@domain (or winname), diagonal * 5. * to *@domain (or *), non-diagonal * 5. * to *@domain (or *), diagonal * 8. * to winname@domain (or winname) * 9. * to "", non-diagonal * 10. * to winname@domain (or winname), diagonal /* bi-directional or from unix to windows */ * Generate and execute SQL statement to add name-based mapping rule * For the triggers on namerules table to work correctly: * 1) Use NULL instead of 0 for w2u_order and u2w_order * 2) Use "" instead of NULL for "no domain" "(is_user, is_wuser, windomain, winname_display, is_nt4, " "unixname, w2u_order, u2w_order) " "VALUES(%d, %d, %Q, %Q, %d, %Q, %q, %q);",
* Flush name-based mapping rules * Generate and execute SQL statement to remove a name-based mapping rule " AND (u2w_order = 0 OR u2w_order ISNULL)");
" AND (w2u_order = 0 OR w2u_order ISNULL)");
* Compile the given SQL query and step just once. * vm - virtual SQL machine * ncol - number of columns in the result /* Caller will call finalize after using the results */ * Load config in the state. * nm_siduid and nm_sidgid fields: * state->nm_siduid represents mode used by sid2uid and uid2sid * requests for directory-based name mappings. Similarly, * state->nm_sidgid represents mode used by sid2gid and gid2sid * none -> ds_name_mapping_enabled != true * AD-mode -> !nldap_winname_attr && ad_unixuser_attr * nldap-mode -> nldap_winname_attr && !ad_unixuser_attr * mixed-mode -> nldap_winname_attr && ad_unixuser_attr * none -> ds_name_mapping_enabled != true * AD-mode -> !nldap_winname_attr && ad_unixgroup_attr * nldap-mode -> nldap_winname_attr && !ad_unixgroup_attr * mixed-mode -> nldap_winname_attr && ad_unixgroup_attr * Set the rule with specified values. * All the strings are copied. * Only update if they differ because we have to free * and duplicate the strings * Table for well-known SIDs. * Some of the well-known principals are stored under: * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain> * They belong to objectClass "foreignSecurityPrincipal". They don't have * "samAccountName" nor "userPrincipalName" attributes. Their names are * available in "cn" and "name" attributes. Some of these principals have a * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and * these duplicate entries have the stringified SID in the "name" and "cn" * attributes instead of the actual name. * Those of the form S-1-5-32-X are Builtin groups and are stored in the * cn=builtin container (except, Power Users which is not stored in AD) * These principals are and will remain constant. Therefore doing AD lookups * provides no benefit. Also, using hard-coded table (and thus avoiding AD * lookup) improves performance and avoids additional complexity in the * adutils.c code. Moreover these SIDs can be used when no Active Directory * is available (such as the CIFS server's "workgroup" mode). * 1. Currently we don't support localization of well-known SID names, * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored * here. AD does have normal user/group objects for these objects and * can be looked up using the existing AD lookup code. * 3. See comments above lookup_wksids_sid2pid() for more information * on how we lookup the wksids table. * 4. If this table contains two entries for a particular Windows name, * so as to offer both UID and GID mappings, the preferred mapping (the * one that matches Windows usage) must be listed first. That is the * entry that will be used when the caller specifies IDMAP_POSIXID * ("don't care") as the target. * Entries here come from KB243330, MS-LSAT, and /* S-1-0 Null Authority */ /* S-1-1 World Authority */ /* S-1-2 Local Authority */ /* S-1-3 Creator Authority */ {
"S-1-3",
2,
"",
"Creator Owner Server",
1,
SENTINEL_PID, -
1, -
1},
{
"S-1-3",
3,
"",
"Creator Group Server", 0,
SENTINEL_PID, -
1,
1},
/* S-1-4 Non-unique Authority */ /* S-1-5-5-X-Y Logon Session */ {
"S-1-5",
7,
"",
"Anonymous Logon", 0,
GID_NOBODY, 0, 0},
{
"S-1-5",
7,
"",
"Anonymous Logon", 0,
UID_NOBODY,
1, 0},
{
"S-1-5",
9,
"",
"Enterprise Domain Controllers", 0,
{
"S-1-5",
11,
"",
"Authenticated Users", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5",
13,
"",
"Terminal Server Users", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5",
14,
"",
"Remote Interactive Logon", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5",
15,
"",
"This Organization", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5",
19,
"",
"Local Service", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5",
20,
"",
"Network Service", 0,
SENTINEL_PID, -
1, -
1},
/* S-1-5-21-<domain> Machine-local definitions */ {
NULL,
498,
NULL,
"Enterprise Read-only Domain Controllers", 0,
{
NULL,
520,
NULL,
"Global Policy Creator Owners", 0,
{
"S-1-5-32",
544,
"BUILTIN",
"Administrators", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5-32",
545,
"BUILTIN",
"Users", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5-32",
546,
"BUILTIN",
"Guests", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5-32",
547,
"BUILTIN",
"Power Users", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5-32",
548,
"BUILTIN",
"Account Operators", 0,
{
"S-1-5-32",
549,
"BUILTIN",
"Server Operators", 0,
{
"S-1-5-32",
550,
"BUILTIN",
"Print Operators", 0,
{
"S-1-5-32",
551,
"BUILTIN",
"Backup Operators", 0,
{
"S-1-5-32",
552,
"BUILTIN",
"Replicator", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5-32",
554,
"BUILTIN",
"Pre-Windows 2000 Compatible Access", 0,
{
"S-1-5-32",
555,
"BUILTIN",
"Remote Desktop Users", 0,
{
"S-1-5-32",
556,
"BUILTIN",
"Network Configuration Operators", 0,
{
"S-1-5-32",
557,
"BUILTIN",
"Incoming Forest Trust Builders", 0,
{
"S-1-5-32",
558,
"BUILTIN",
"Performance Monitor Users", 0,
{
"S-1-5-32",
559,
"BUILTIN",
"Performance Log Users", 0,
{
"S-1-5-32",
560,
"BUILTIN",
"Windows Authorization Access Group", 0,
{
"S-1-5-32",
561,
"BUILTIN",
"Terminal Server License Servers", 0,
{
"S-1-5-32",
562,
"BUILTIN",
"Distributed COM Users", 0,
{
"S-1-5-32",
568,
"BUILTIN",
"IIS_IUSRS", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5-32",
569,
"BUILTIN",
"Cryptographic Operators", 0,
{
"S-1-5-32",
573,
"BUILTIN",
"Event Log Readers", 0,
{
"S-1-5-32",
574,
"BUILTIN",
"Certificate Service DCOM Access", 0,
{
"S-1-5",
33,
"",
"Write Restricted", 0,
SENTINEL_PID, -
1, -
1},
/* S-1-5-64 NT Authority */ {
"S-1-5-64",
10,
"",
"NTLM Authentication", 0,
SENTINEL_PID, -
1, -
1},
{
"S-1-5-64",
14,
"",
"SChannel Authentication", 0,
{
"S-1-5-64",
21,
"",
"Digest Authentication", 0,
SENTINEL_PID, -
1, -
1},
/* S-1-5-80-a-b-c-d NT Service */ {
"S-1-5",
1000,
"",
"Other Organization", 0,
SENTINEL_PID, -
1, -
1},
* S-1-16-0 Untrusted Mandatory Level * S-1-16-4096 Low Mandatory Level * S-1-16-8192 Medium Mandatory Level * S-1-16-8448 Medium Plus Mandatory Level * S-1-16-12288 High Mandatory Level * S-1-16-16384 System Mandatory Level * S-1-16-20480 Protected Process Mandatory Level * Lookup well-known SIDs table either by winname or by SID. * If the given winname or SID is a well-known SID then we set is_wksid * variable and then proceed to see if the SID has a hard mapping to * fixed ephemeral ids). The direction flag indicates whether we have * a mapping; UNDEF indicates that we do not. * If we find a mapping then we return success, except for the * special case of SENTINEL_PID which indicates an inhibited mapping. * If we find a matching entry, but no mapping, we supply SID, name, and type * information and return "not found". Higher layers will probably * If we do not find a match, we return "not found" and leave the question /* Found matching entry. */ /* Fill in name if it was not already there. */ /* Fill in SID if it was not already there */ /* Fill in the canonical domain if not already there */ * We don't have a mapping * (But note that we may have supplied SID, name, or type * We have an explicit mapping. * ... which is that mapping is inhibited. /* IDMAP_POSIXID is eliminated above */ * Look for an entry mapping a PID to a SID. * Note that direction=UNDEF entries do not specify a mapping, * and that SENTINEL_PID entries represent either an inhibited * mapping or an ephemeral mapping. We don't handle either here; * they are filtered out by find_wksid_by_pid. * Look up a name in the wksids list, matching name and, if supplied, domain, * domain Windows domain name (or NULL) * *canonname canonical name (if canonname non-NULL) [1] * *canondomain canonical domain (if canondomain non-NULL) [1] * *sidprefix SID prefix (if sidprefix non-NULL) [1] * *rid RID (if rid non-NULL) [2] * *type Type (if type non-NULL) [2] * [1] malloc'ed, NULL on error /* the non-diagonal mapping */ /* SQL to lookup the cache */ "unixname, u2w, is_wuser, " "map_type, map_dn, map_attr, map_value, " "map_windomain, map_winname, map_unixname, map_is_nt4 " "FROM idmap_cache WHERE is_user = %s AND " "sidprefix = %Q AND rid = %u AND w2u = 1 AND " "(expiration = 0 OR expiration ISNULL OR " "unixname, u2w, is_wuser, " "map_type, map_dn, map_attr, map_value, " "map_windomain, map_winname, map_unixname, map_is_nt4 " "FROM idmap_cache WHERE is_user = %s AND " "winname = %Q AND windomain = %Q AND w2u = 1 AND " "(expiration = 0 OR expiration ISNULL OR " * We may have an expired ephemeral mapping. Consider * the expired entry as valid if we are not going to * perform name-based mapping. But do not renew the * If we will be doing name-based mapping then store the * ephemeral pid in the result so that we can use it * if we end up doing dynamic mapping again. /* Store the ephemeral pid */ /* Unknow mapping type */ /* SQL to lookup the cache */ "sidprefix = %Q AND rid = %u AND " "(expiration = 0 OR expiration ISNULL OR " * Given SID, find winname using name_cache OR * Given winname, find SID using name_cache. * Used when mapping win to unix i.e. req->id1 is windows id and /* Done if we've both sid and winname */ /* Lookup sid to winname */ /* Lookup winame to sid */ * If we found canonical names or domain, use them instead of * Since req->id2.idtype is unused, we will use it here * to retrieve the value of sid_type. But it needs to be * reset to IDMAP_NONE before we return to prevent xdr * from mis-interpreting req->id2 when it tries to free * the input argument. Other option is to allocate an * array of integers and use it instead for the batched * call. But why un-necessarily allocate memory. That may * be an option if req->id2.idtype cannot be re-used in degrade_svc(
1,
"failed to create batch for AD lookup");
* Directory based name mapping is only performed within the * joined forest (index == 0). We don't trust other "trusted" * forests to provide DS-based name mapping information because * AD's definition of "cross-forest trust" does not encompass /* Skip if not marked for this AD lookup */ * Get how info for DS-based name * mapping only if AD or MIXED /* Lookup AD by winname */ /* Already have SID and winname. done */ * SID but no winname -- lookup AD by * how info is not needed here because * we are not retrieving unixname from * winname but no SID -- lookup AD by * how info is not needed here because * we are not retrieving unixname from * No SID and no winname but we've unixname. * Lookup AD by unixname to get SID. /* add keeps track if we added an entry to the batch */ degrade_svc(
1,
"some AD lookups timed out repeatedly");
/* Mark any unproccessed requests for an other AD */ * This loop does the following: * 1. Reset _IDMAP_F_LOOKUP_AD flag from the request. * 2. Reset req->id2.idtype to IDMAP_NONE * 3. If batch_start or batch_add failed then set the status * of each request marked for AD lookup to that error. * 4. Evaluate the type of the AD object (i.e. user or group) * and update the idtype in request. /* Count number processed */ /* Reset AD lookup flag */ * If batch_start or batch_add failed then set the * status of each request marked for AD lookup to /* Nothing found - remove the preset info */ /* Evaluate result type */ * If AD lookup by unixname * failed with non fatal error * then clear the error (ie set * res->retcode to success). * This allows the next pass to * mechanisms for this request. /* Evaluate result type */ /* Skip if not marked for AD lookup or already in error. */ * Reset the other AD lookup flag so * that we can try the next AD * There are no more ADs to try /* AD lookups done. Reset state->ad_nqueries and return */ * Convention when processing win2unix requests: * winname if given otherwise winname found will be placed * windomain if given otherwise windomain found will be * is determined either when looking up well-known SIDs table OR * if the SID is found in namecache OR by ad_lookup_one() OR by * req->id1..sid.[prefix, rid] = * SID if given otherwise SID found will be placed here. * unixname found will be placed here. * Target type initialized from req->id2.idtype. If * it is IDMAP_POSIXID then actual type (IDMAP_UID/GID) found * res->id..[uid or gid] = * UID/GID found will be placed here. * Return status for this request will be placed here. * Direction found will be placed here. Direction * meaning whether the resultant mapping is valid * only from win2unix or bi-directional. * INTERNAL USE. Used by idmapd to set various * flags (_IDMAP_F_xxxx) to aid in processing * INTERNAL USE. Initially this is the requested target * type and is used to initialize res->id.idtype. * ad_lookup_batch() uses this field temporarily to store * sid_type obtained by the batched AD lookups and after * use resets it to IDMAP_NONE to prevent xdr from * mis-interpreting the contents of req->id2. * req->id2..[uid or gid or sid] = * This function does the following: * 1. Lookup well-known SIDs table. * 2. Check if the given SID is a local-SID and if so extract UID/GID from it. * 4. Check if the client does not want new mapping to be allocated * in which case this pass is the final pass. * 5. Set AD lookup flag if it determines that the next stage needs /* Lookup well-known SIDs table */ /* Check if this is a localsid */ * Failed to find non-expired entry in cache. Next step is * to determine if this request needs to be batched for AD lookup. * At this point we have either sid or winname or both. If we don't * have both then lookup name_cache for the sid or winname * whichever is missing. If not found then this request will be * Set the flag to indicate that we are not done yet so that * subsequent passes considers this request for name-based * mapping and ephemeral mapping. * Even if we have both sid and winname, we still may need to batch * this request for AD lookup if we don't have unixname and * directory-based name mapping (AD or mixed) is enabled. * We avoid AD lookup for well-known SIDs because they don't have * If we are done and there was an error then set fallback pid * Generate SID using the following convention * <machine-sid-prefix>-<1000 + uid> * <machine-sid-prefix>-<2^31 + gid> * Diagonal mapping for localSIDs not supported because of the * way we generate localSIDs. * machine_sid is never NULL because if it is we won't be here. * No need to assert because stdrup(NULL) will core anyways. * Don't update name_cache because local sids don't have * If the sidprefix == localsid then UID = last RID - 1000 or /* This means we are looking up by winname */ * If the given sidprefix does not match machine_sid then this is * Name service lookup by unixname to get pid const char *
me =
"ns_lookup_byname";
"%s: getpwnam_r(%s) failed (%s).",
"%s: getgrnam_r(%s) failed (%s).",
* Name service lookup by pid to get unixname const char *
me =
"ns_lookup_bypid";
"%s: getpwuid_r(%u) failed (%s).",
"%s: getgrgid_r(%u) failed (%s).",
* Case 1: If no rule matches do ephemeral * Case 2: If rule matches and unixname is "" then return no mapping. * Case 3: If rule matches and unixname is specified then lookup name * service using the unixname. If unixname not found then return no mapping. * Case 4: If rule matches and unixname is * then lookup name service * using winname as the unixname. If unixname not found then process * other rules using the lookup order. If no other rule matches then do * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4. * This allows us to specify a fallback unixname per _domain_ or no mapping * instead of the default behaviour of doing ephemeral mapping. * If looking up windows users foo@sfbay and foo does not exists in * the name service then foo@sfbay will be mapped to an ephemeral id. * If looking up windows users foo@sfbay and foo does not exists in * the name service then foo@sfbay will be mapped to guest. * If looking up windows users foo@sfbay and foo does not exists in * the name service then we will return no mapping for foo@sfbay. const char *
me =
"name_based_mapping_sid2pid";
"given Windows id is user or group.",
me);
"SELECT unixname, u2w_order, winname_display, windomain, is_nt4 " "w2u_order > 0 AND is_user = %d AND is_wuser = %d AND " "(winname = %Q OR winname = '*') AND " "(windomain = %Q OR windomain = '*') " "ORDER BY w2u_order ASC;",
for (
str = (
const char *)&
num, i = 0; i <
sizeof (
num); i++) {
/* Check if second pass is needed */ /* Get status from previous pass */ * We are asked to map an unresolvable SID to a UID or * GID, but, which? We'll treat all unresolvable SIDs * as users unless the caller specified which of a UID * If directory-based name mapping is enabled then the unixname * may already have been retrieved from the AD object (AD-mode or * mixed-mode) or from native LDAP object (nldap-mode) -- done. * Special case: (1) If the ad_unixuser_attr and * ad_unixgroup_attr uses the same attribute * name and (2) if this is a diagonal mapping * request and (3) the unixname has been retrieved * from the AD object -- then we ignore it and fallback * to name-based mapping rules and ephemeral mapping * In this example whether "unixname" refers to a unixuser * or unixgroup depends upon the AD object. * $idmap show -c winname:bob gid * AD lookup by "samAccountName=bob" for * "ad_unixgroup_attr (i.e unixname)" for directory-based * mapping would get "bob1234" which is not what we want. * Now why not getgrnam_r("bob1234") and use it if it * is indeed a unixgroup? That's because Unix can have * users and groups with the same name and we clearly * don't know the intention of the admin here. * Therefore we ignore this and fallback to name-based * mapping rules or ephemeral mapping. * If ns_lookup_byname() fails that means the * unixname (req->id2name), which was obtained * from the AD object by directory-based mapping, * is not a valid Unix user/group and therefore * we return the error to the client instead of * doing rule-based mapping or ephemeral mapping. * This way the client can detect the issue. /* Free any mapping info from Directory based mapping */ * If we don't have unixname then evaluate local name-based /* If not found, do ephemeral mapping */ /* Check if we need to cache anything */ /* We don't cache negative entries */ /* Dont cache other mapping types */ * Using NULL for u2w instead of 0 so that our trigger allows * the same pid to be the destination in multiple entries "(sidprefix, rid, windomain, canon_winname, pid, unixname, " "is_user, is_wuser, expiration, w2u, u2w, " "map_type, map_dn, map_attr, map_value, map_windomain, " "map_winname, map_unixname, map_is_nt4) " "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, " "strftime('%%s','now') + 600, %q, 1, " "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d); ",
/* Check if we need to update namecache */ "(sidprefix, rid, canon_name, domain, type, expiration) " "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
/* Check if we need to cache anything */ /* We don't cache negative entries */ "sidprefix = %Q AND rid = %u AND w2u = 1 AND " "pid >= 2147483648 AND is_user = %d;",
/* Dont cache other mapping types */ "(sidprefix, rid, windomain, canon_winname, pid, unixname, " "is_user, is_wuser, expiration, w2u, u2w, " "map_type, map_dn, map_attr, map_value, map_windomain, " "map_winname, map_unixname, map_is_nt4) " "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, " "strftime('%%s','now') + 600, 1, %q, " "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d);",
/* Check if we need to update namecache */ "(sidprefix, rid, canon_name, domain, type, expiration) " "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ",
/* SQL to lookup the cache by pid or by unixname */ "canon_winname, windomain, w2u, is_wuser, " "map_type, map_dn, map_attr, map_value, map_windomain, " "map_winname, map_unixname, map_is_nt4 " "FROM idmap_cache WHERE " "pid = %u AND u2w = 1 AND is_user = %d AND " "(expiration = 0 OR expiration ISNULL OR " "canon_winname, windomain, w2u, is_wuser, " "map_type, map_dn, map_attr, map_value, map_windomain, " "map_winname, map_unixname, map_is_nt4 " "FROM idmap_cache WHERE " "unixname = %Q AND u2w = 1 AND is_user = %d AND " "(expiration = 0 OR expiration ISNULL OR " /* Unknow mapping type */ * domain Windows domain name * *canonname Canonical name (if canonname is non-NULL) [1] * *sidprefix SID prefix [1] * [1] malloc'ed, NULL on error /* SQL to lookup the cache */ "FROM name_cache WHERE name = %Q AND domain = %Q AND " "(expiration = 0 OR expiration ISNULL OR " * Directory based name mapping is only * performed within the joined forest (i == 0). * We don't trust other "trusted" forests to * provide DS-based name mapping information * because AD's definition of "cross-forest * trust" does not encompass this sort of "some AD lookups timed out repeatedly");
* cache sqlite handle to cache * domain Windows domain name * local_only if true, don't try AD lookups * *canonname Canonical name (if non-NULL) [1] * *canondomain Canonical domain (if non-NULL) [1] * *sidprefix SID prefix [1] * *req Request (direction is updated) * [1] malloc'ed, NULL on error /* Lookup well-known SIDs table */ * The caller may be using this function to determine if this * request needs to be marked for AD lookup or not * (i.e. _IDMAP_F_LOOKUP_AD) and therefore may not want this * function to AD lookup now. * Entry found (cache or Windows lookup) * is_wuser is both input as well as output parameter /* Caller wants to know if its user or group */ * If we were asked for a canonical domain and none * of the searches have provided one, assume it's the const char *
me =
"name_based_mapping_pid2sid";
"SELECT winname_display, windomain, w2u_order, " "is_wuser, unixname, is_nt4 " "u2w_order > 0 AND is_user = %d AND " "(unixname = %Q OR unixname = '*') " /* values [1] and [2] can be null */ * There were non-wildcard rules * where the Windows identity doesn't * exist. Return no mapping. /* Save first non-wild match rule */ * If there were non-wildcard rules where * Windows identity doesn't exist * Convention when processing unix2win requests: * unixname if given otherwise unixname found will be placed * Given type (IDMAP_UID or IDMAP_GID) * req->id1..[uid or gid] = * UID/GID if given otherwise UID/GID found will be placed here. * winname found will be placed here. * windomain found will be placed here. * Target type initialized from req->id2.idtype. If * req->id..sid.[prefix, rid] = * SID found will be placed here. * Return status for this request will be placed here. * Direction found will be placed here. Direction * meaning whether the resultant mapping is valid * only from unix2win or bi-directional. * INTERNAL USE. Used by idmapd to set various * flags (_IDMAP_F_xxxx) to aid in processing * INTERNAL USE. Initially this is the requested target * type and is used to initialize res->id.idtype. * ad_lookup_batch() uses this field temporarily to store * sid_type obtained by the batched AD lookups and after * use resets it to IDMAP_NONE to prevent xdr from * mis-interpreting the contents of req->id2. * req->id2..[uid or gid or sid] = * This function does the following: * 1. Lookup well-known SIDs table. * 3. Check if the client does not want new mapping to be allocated * in which case this pass is the final pass. * 4. Set AD/NLDAP lookup flags if it determines that the next stage needs /* Lookup in well-known SIDs table */ /* Ephemeral ids cannot be allocated during pid2sid */ /* Set flags for the next stage */ * If AD-based name mapping is enabled then the next stage * will need to lookup AD using unixname to get the /* Get unixname if only pid is given. */ * If native LDAP or mixed mode is enabled for name mapping * then the next stage will need to lookup native LDAP using * Failed to find non-expired entry in cache. Set the flag to * indicate that we are not done yet. /* Check if second pass is needed */ /* Get status from previous pass */ * If directory-based name mapping is enabled then the winname * may already have been retrieved from the AD object (AD-mode) * or from native LDAP object (nldap-mode or mixed-mode). * Note that if we have winname but no SID then it's an error * because this implies that the Native LDAP entry contains * winname which does not exist and it's better that we return * an error instead of doing rule-based mapping so that the user * can detect the issue and take appropriate action. /* Return notfound if we've winname but no SID. */ * We've SID but no winname. This is fine because * the caller may have only requested SID. /* Free any mapping info from Directory based mapping */ /* Get unixname from name service */ /* Get pid from name service */ /* Use unixname to evaluate local name-based mapping rules */ /* We don't need the rest of the request i.e request->id2 */ /* Get directory-based name mapping info */ * Copy data from "request" to "mapping". Note that * empty strings are not copied from "request" to * "mapping" and therefore the coresponding strings in * "mapping" will be NULL. This eliminates having to * check for empty strings henceforth. /* Need atleast winname or sid to proceed */ * If domainname is not given but we have a fully qualified * winname then extract the domainname from the winname, * otherwise use the default_domain from the config * We have a non-qualified winname which is * neither the name of a well-known SID nor * there is a default domain with which we can * First pass looks up the well-known SIDs table and cache /* Next pass performs name-based mapping and ephemeral mapping. */ * Note that "mapping" is returned to the client. Therefore * copy whatever we have in "idres" to mapping->id2 and * In order to re-use the pid2sid code, we convert * our input data into structs that are expected by /* Get directory-based name mapping info */ * Copy data from "request" to "mapping". Note that * empty strings are not copied from "request" to * "mapping" and therefore the coresponding strings in * "mapping" will be NULL. This eliminates having to * check for empty strings henceforth. * For unix to windows mapping request, we need atleast a * unixname or uid/gid to proceed /* First pass looks up cache and well-known SIDs */ * Next pass processes the result of the preceding passes/lookups. * It returns if there's nothing more to be done otherwise it * evaluates local name-based mapping rules * Note that "mapping" is returned to the client. Therefore * copy whatever we have in "idres" to mapping->id2 and * Find a wksid entry for the specified Windows name and domain, of the * Ignore entries intended only for U2W use. /* Check to see if this entry yields the desired type */ /* this is not our domain */ * We have a Windows name, so ignore entries that are only * usable for mapping UNIX->Windows. (Note: the current * table does not have any such entries.) * Find a wksid entry for the specified SID, of the specified type. * Ignore entries intended only for U2W use. /* Check to see if this entry yields the desired type */ * We have a SID, so ignore entries that are only usable * for mapping UNIX->Windows. (Note: the current table * does not have any such entries.) * Find a wksid entry for the specified pid, of the specified type. * Ignore entries that do not specify U2W mappings.