diff options
-rw-r--r-- | source3/auth/auth_util.c | 65 | ||||
-rw-r--r-- | source3/auth/auth_winbind.c | 2 | ||||
-rw-r--r-- | source3/include/smb_macros.h | 3 | ||||
-rw-r--r-- | source3/lib/smbldap.c | 2 | ||||
-rw-r--r-- | source3/lib/system_smbd.c | 4 | ||||
-rw-r--r-- | source3/nsswitch/wb_client.c | 70 | ||||
-rw-r--r-- | source3/nsswitch/wb_common.c | 16 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_group.c | 26 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_nss.h | 13 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_pam.c | 63 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_passdb.c | 4 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_sid.c | 30 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_user.c | 23 | ||||
-rw-r--r-- | source3/param/loadparm.c | 15 | ||||
-rw-r--r-- | source3/passdb/passdb.c | 202 | ||||
-rw-r--r-- | source3/passdb/pdb_ldap.c | 10 | ||||
-rw-r--r-- | source3/sam/idmap_util.c | 137 | ||||
-rw-r--r-- | source3/smbd/server.c | 14 | ||||
-rw-r--r-- | source3/smbd/uid.c | 408 | ||||
-rw-r--r-- | source3/utils/ntlm_auth.c | 40 | ||||
-rw-r--r-- | source3/utils/pdbedit.c | 4 |
21 files changed, 874 insertions, 277 deletions
diff --git a/source3/auth/auth_util.c b/source3/auth/auth_util.c index f77ee350b4..399a1e9006 100644 --- a/source3/auth/auth_util.c +++ b/source3/auth/auth_util.c @@ -923,12 +923,8 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, DOM_SID user_sid; DOM_SID group_sid; - struct passwd *passwd; - - unid_t u_id, g_id; uid_t uid; gid_t gid; - int u_type, g_type; int n_lgroupSIDs; DOM_SID *lgroupSIDs = NULL; @@ -964,44 +960,20 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, /* If the server didn't give us one, just use the one we sent them */ domain = domain; } - - u_type = ID_USERID; - g_type = ID_GROUPID; - - /* we are trying to check that idmap isn't stuffing us over - does this - user actually exist? */ - if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&u_id, &u_type, &user_sid)) - && NT_STATUS_IS_OK(idmap_get_id_from_sid(&g_id, &g_type, &group_sid)) - && ((passwd = getpwuid_alloc(u_id.uid)))) { - - nt_status = pdb_init_sam_pw(&sam_account, passwd); - - uid = passwd->pw_uid; - gid = passwd->pw_gid; - - /* we should check this is the same name */ - found_username = talloc_strdup(mem_ctx, passwd->pw_name); - - passwd_free(&passwd); - } else { - - /* User not from winbind - try and find them by getpwnam() */ - nt_status = fill_sam_account(mem_ctx, nt_domain, - internal_username, - &found_username, - &uid, &gid, - &sam_account); - - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) { - DEBUG(3,("User %s does not exist, trying to add it\n", - internal_username)); - auth_add_user_script(nt_domain, internal_username); - nt_status = fill_sam_account(mem_ctx, nt_domain, - internal_username, - &found_username, - &uid, &gid, - &sam_account); - } + + /* try to fill the same account.. If getpwnam() fails, then try the + add user script (2.2.x behavior) */ + + nt_status = fill_sam_account(mem_ctx, nt_domain, internal_username, + &found_username, &uid, &gid, &sam_account); + + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) { + DEBUG(3,("User %s does not exist, trying to add it\n", + internal_username)); + auth_add_user_script(nt_domain, internal_username); + nt_status = fill_sam_account(mem_ctx, nt_domain, + internal_username, &found_username, + &uid, &gid, &sam_account); } if (!NT_STATUS_IS_OK(nt_status)) { @@ -1082,12 +1054,9 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx, /* Store the user group information in the server_info returned to the caller. */ - if (!NT_STATUS_IS_OK(nt_status - = get_user_groups_from_local_sam((*server_info)->unix_name, - uid, gid, - &n_lgroupSIDs, - &lgroupSIDs, - &unix_groups))) + nt_status = get_user_groups_from_local_sam((*server_info)->unix_name, + uid, gid, &n_lgroupSIDs, &lgroupSIDs, &unix_groups); + if ( !NT_STATUS_IS_OK(nt_status) ) { DEBUG(4,("get_user_groups_from_local_sam failed\n")); return nt_status; diff --git a/source3/auth/auth_winbind.c b/source3/auth/auth_winbind.c index 856b8f5a82..aa8f345a5b 100644 --- a/source3/auth/auth_winbind.c +++ b/source3/auth/auth_winbind.c @@ -85,7 +85,7 @@ static NTSTATUS check_winbind_security(const struct auth_context *auth_context, ZERO_STRUCT(request); ZERO_STRUCT(response); - request.data.auth_crap.flags = WINBIND_PAM_INFO3_NDR; + request.flags = WBFLAG_PAM_INFO3_NDR; push_utf8_fstring(request.data.auth_crap.user, user_info->smb_name.str); diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index 40b114a6b9..21ccdf295c 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -252,7 +252,6 @@ copy an IP address from one buffer to another Check to see if we are a DO for this domain *****************************************************************************/ -#define IS_DC_FOR_DOMAIN(x) ( (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC) \ - && strequal((x), lp_workgroup()) ) +#define IS_DC (lp_server_role()==ROLE_DOMAIN_PDC || lp_server_role()==ROLE_DOMAIN_BDC) #endif /* _SMB_MACROS_H */ diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index e0c6aab617..cba73d386c 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -815,7 +815,7 @@ static int smbldap_open(struct smbldap_state *ldap_state) } if (ldap_state->ldap_struct != NULL) { - DEBUG(5,("smbldap_open: already connected to the LDAP server\n")); + DEBUG(11,("smbldap_open: already connected to the LDAP server\n")); return LDAP_SUCCESS; } diff --git a/source3/lib/system_smbd.c b/source3/lib/system_smbd.c index 3498307acb..bcbc8c61e6 100644 --- a/source3/lib/system_smbd.c +++ b/source3/lib/system_smbd.c @@ -114,7 +114,7 @@ int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt) /* see if we should disable winbindd lookups for local users */ if ( (p = strchr(user, *lp_winbind_separator())) == NULL ) { - if ( setenv(WINBINDD_DONT_ENV, "1", 1) == -1 ) + if ( !winbind_off() ) DEBUG(0,("sys_getgroup_list: Insufficient environment space for %s\n", WINBINDD_DONT_ENV)); else @@ -131,7 +131,7 @@ int sys_getgrouplist(const char *user, gid_t gid, gid_t *groups, int *grpcnt) #endif /* allow winbindd lookups */ - setenv( WINBINDD_DONT_ENV, "0", 1); + winbind_on(); return retval; } diff --git a/source3/nsswitch/wb_client.c b/source3/nsswitch/wb_client.c index 196e44020c..67548592b2 100644 --- a/source3/nsswitch/wb_client.c +++ b/source3/nsswitch/wb_client.c @@ -168,6 +168,41 @@ BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid) return (result == NSS_STATUS_SUCCESS); } +/* Call winbindd to convert SID to uid. Do not allocate */ + +BOOL winbind_sid_to_uid_query(uid_t *puid, const DOM_SID *sid) +{ + struct winbindd_request request; + struct winbindd_response response; + int result; + fstring sid_str; + + if (!puid) + return False; + + /* Initialise request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + sid_to_string(sid_str, sid); + fstrcpy(request.data.sid, sid_str); + + request.flags = WBFLAG_QUERY_ONLY; + + /* Make request */ + + result = winbindd_request(WINBINDD_SID_TO_UID, &request, &response); + + /* Copy out result */ + + if (result == NSS_STATUS_SUCCESS) { + *puid = response.data.uid; + } + + return (result == NSS_STATUS_SUCCESS); +} + /* Call winbindd to convert SID to gid */ BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid) @@ -201,6 +236,41 @@ BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid) return (result == NSS_STATUS_SUCCESS); } +/* Call winbindd to convert SID to gid. Do not allocate */ + +BOOL winbind_sid_to_gid_query(gid_t *pgid, const DOM_SID *sid) +{ + struct winbindd_request request; + struct winbindd_response response; + int result; + fstring sid_str; + + if (!pgid) + return False; + + /* Initialise request */ + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + sid_to_string(sid_str, sid); + fstrcpy(request.data.sid, sid_str); + + request.flags = WBFLAG_QUERY_ONLY; + + /* Make request */ + + result = winbindd_request(WINBINDD_SID_TO_GID, &request, &response); + + /* Copy out result */ + + if (result == NSS_STATUS_SUCCESS) { + *pgid = response.data.gid; + } + + return (result == NSS_STATUS_SUCCESS); +} + /* Call winbindd to convert gid to sid */ BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid) diff --git a/source3/nsswitch/wb_common.c b/source3/nsswitch/wb_common.c index adcfdaa9d8..acaf0ed17c 100644 --- a/source3/nsswitch/wb_common.c +++ b/source3/nsswitch/wb_common.c @@ -468,3 +468,19 @@ NSS_STATUS winbindd_request(int req_type, return(status); return winbindd_get_response(response); } + +/************************************************************************* + A couple of simple jfunctions to disable winbindd lookups and re- + enable them + ************************************************************************/ + +BOOL winbind_off( void ) +{ + return (setenv( WINBINDD_DONT_ENV, "1", 1 ) != -1); +} + +BOOL winbind_on( void ) +{ + return (setenv( WINBINDD_DONT_ENV, "0", 1 ) != -1); +} + diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index 70c8de6ee9..9a969abeaa 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -214,10 +214,11 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) if (!parse_domain_user(tmp, name_domain, name_group)) return WINBINDD_ERROR; - /* don't handle our own domain if we are a DC. This code handles cases where + /* don't handle our own domain if we are a DC ( or a member of a Samba domain + that shares UNIX accounts). This code handles cases where the account doesn't exist anywhere and gets passed on down the NSS layer */ - if ( IS_DC_FOR_DOMAIN(domain->name) ) { + if ( (IS_DC || lp_winbind_trusted_domains_only()) && strequal(name_domain, lp_workgroup()) ) { DEBUG(7,("winbindd_getgrnam: rejecting getpwnam() for %s\\%s since I am on the PDC for this domain\n", name_domain, name_group)); return WINBINDD_ERROR; @@ -248,7 +249,7 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) return WINBINDD_ERROR; } - if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid, 0))) { DEBUG(1, ("error converting unix gid to sid\n")); return WINBINDD_ERROR; } @@ -293,7 +294,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) return WINBINDD_ERROR; /* Get rid from gid */ - if (!NT_STATUS_IS_OK(gid_to_sid(&group_sid, state->request.data.gid))) { + if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) { DEBUG(1, ("could not convert gid %d to rid\n", state->request.data.gid)); return WINBINDD_ERROR; @@ -370,10 +371,14 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state) struct getent_state *domain_state; - /* don't add our domaina if we are a PDC */ + /* don't add our domaina if we are a PDC or if we + are a member of a Samba domain */ - if ( IS_DC_FOR_DOMAIN(domain->name) ) + if ( (IS_DC || lp_winbind_trusted_domains_only()) + && strequal(domain->name, lp_workgroup()) ) + { continue; + } /* Create a state record for this domain */ @@ -612,7 +617,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) sid_copy(&group_sid, &domain->sid); sid_append_rid(&group_sid, name_list[ent->sam_entry_index].rid); - if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &group_gid))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &group_gid, 0))) { DEBUG(1, ("could not look up gid for group %s\n", name_list[ent->sam_entry_index].acct_name)); @@ -925,8 +930,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) /* Map to a gid */ - if (!NT_STATUS_IS_OK(sid_to_gid(&info3->other_sids[i].sid, - &gid_list[num_gids])) ) + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&info3->other_sids[i].sid, &gid_list[num_gids], 0)) ) { DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n", sid_string_static(&info3->other_sids[i].sid))); @@ -950,7 +954,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) sid_copy( &group_sid, &domain->sid ); sid_append_rid( &group_sid, info3->gids[i].g_rid ); - if (!NT_STATUS_IS_OK(sid_to_gid(&group_sid, &gid_list[num_gids])) ) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(&group_sid, &gid_list[num_gids], 0)) ) { DEBUG(10, ("winbindd_getgroups: could not map sid %s to gid\n", sid_string_static(&group_sid))); } @@ -973,7 +977,7 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) goto done; for (i = 0; i < num_groups; i++) { - if (!NT_STATUS_IS_OK(sid_to_gid(user_grpsids[i], &gid_list[num_gids]))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_grpsids[i], &gid_list[num_gids], 0))) { DEBUG(1, ("unable to convert group sid %s to gid\n", sid_string_static(user_grpsids[i]))); continue; diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index cc1b144063..1ddfb2174e 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -111,11 +111,12 @@ enum winbindd_cmd { WINBINDD_NUM_CMDS }; -#define WINBIND_PAM_INFO3_NDR 0x0001 -#define WINBIND_PAM_INFO3_TEXT 0x0002 -#define WINBIND_PAM_NTKEY 0x0004 -#define WINBIND_PAM_LMKEY 0x0008 -#define WINBIND_PAM_CONTACT_TRUSTDOM 0x0010 +#define WBFLAG_PAM_INFO3_NDR 0x0001 +#define WBFLAG_PAM_INFO3_TEXT 0x0002 +#define WBFLAG_PAM_NTKEY 0x0004 +#define WBFLAG_PAM_LMKEY 0x0008 +#define WBFLAG_PAM_CONTACT_TRUSTDOM 0x0010 +#define WBFLAG_QUERY_ONLY 0x0020 /* Winbind request structure */ @@ -123,6 +124,7 @@ struct winbindd_request { uint32 length; enum winbindd_cmd cmd; /* Winbindd command to execute */ pid_t pid; /* pid of calling process */ + uint32 flags; /* flags relavant to a given request */ union { fstring winsreq; /* WINS request */ @@ -146,7 +148,6 @@ struct winbindd_request { fstring nt_resp; uint16 nt_resp_len; fstring workstation; - uint32 flags; } auth_crap; struct { fstring user; diff --git a/source3/nsswitch/winbindd_pam.c b/source3/nsswitch/winbindd_pam.c index 75e10eb405..6aaf3bc715 100644 --- a/source3/nsswitch/winbindd_pam.c +++ b/source3/nsswitch/winbindd_pam.c @@ -63,41 +63,38 @@ static BOOL get_trust_pw(const char *domain, uint8 ret_pwd[16], DOM_SID sid; char *pwd; - if ( lp_server_role()==ROLE_DOMAIN_MEMBER || strequal(domain, lp_workgroup()) ) + /* if we are a DC and this is not our domain, then lookup an account + for the domain trust */ + + if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains() ) { - /* - * Get the machine account password for the domain to contact. - * This is either our own domain for a workstation, or possibly - * any domain for a PDC with trusted domains. - */ - - if ( !secrets_fetch_trust_account_password (domain, ret_pwd, - pass_last_set_time, channel) ) + if ( !secrets_fetch_trusted_domain_password(domain, &pwd, &sid, + pass_last_set_time) ) { DEBUG(0, ("get_trust_pw: could not fetch trust account " - "password for my domain %s\n", domain)); + "password for trusted domain %s\n", domain)); return False; } + *channel = SEC_CHAN_DOMAIN; + E_md4hash(pwd, ret_pwd); + SAFE_FREE(pwd); + return True; } - else if ( lp_allow_trusted_domains() ) + else /* just get the account for our domain (covers + ROLE_DOMAIN_MEMBER as well */ { - /* if we are not a domain member, then we must be a DC and - this must be a trusted domain */ + /* get the machine trust account for our domain */ - if ( !secrets_fetch_trusted_domain_password(domain, &pwd, &sid, - pass_last_set_time) ) + if ( !secrets_fetch_trust_account_password (lp_workgroup(), ret_pwd, + pass_last_set_time, channel) ) { DEBUG(0, ("get_trust_pw: could not fetch trust account " - "password for trusted domain %s\n", domain)); + "password for my domain %s\n", domain)); return False; } - *channel = SEC_CHAN_DOMAIN; - E_md4hash(pwd, ret_pwd); - SAFE_FREE(pwd); - return True; } @@ -126,6 +123,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) int attempts = 0; unsigned char local_lm_response[24]; unsigned char local_nt_response[24]; + const char *contact_domain; /* Ensure null termination */ state->request.data.auth.user[sizeof(state->request.data.auth.user)-1]='\0'; @@ -166,6 +164,13 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) goto done; } + /* what domain should we contact? */ + + if ( IS_DC ) + contact_domain = name_domain; + else + contact_domain = lp_workgroup(); + /* check authentication loop */ do { @@ -173,7 +178,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) ZERO_STRUCT(ret_creds); /* Don't shut this down - it belongs to the connection cache code */ - result = cm_get_netlogon_cli(name_domain, trust_passwd, + result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli); if (!NT_STATUS_IS_OK(result)) { @@ -255,6 +260,7 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) char *user = NULL; const char *domain = NULL; const char *workstation; + const char *contact_domain; DOM_CRED ret_creds; int attempts = 0; @@ -329,12 +335,19 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len); nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len); + /* what domain should we contact? */ + + if ( IS_DC ) + contact_domain = domain; + else + contact_domain = lp_workgroup(); + do { ZERO_STRUCT(info3); ZERO_STRUCT(ret_creds); /* Don't shut this down - it belongs to the connection cache code */ - result = cm_get_netlogon_cli(domain, trust_passwd, sec_channel_type, False, &cli); + result = cm_get_netlogon_cli(contact_domain, trust_passwd, sec_channel_type, False, &cli); if (!NT_STATUS_IS_OK(result)) { DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", @@ -376,14 +389,14 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) netsamlogon_cache_store( cli->mem_ctx, &info3 ); wcache_invalidate_samlogon(find_domain_from_name(domain), &info3); - if (state->request.data.auth_crap.flags & WINBIND_PAM_INFO3_NDR) { + if (state->request.flags & WBFLAG_PAM_INFO3_NDR) { result = append_info3_as_ndr(mem_ctx, state, &info3); } - if (state->request.data.auth_crap.flags & WINBIND_PAM_NTKEY) { + if (state->request.flags & WBFLAG_PAM_NTKEY) { memcpy(state->response.data.auth.nt_session_key, info3.user_sess_key, sizeof(state->response.data.auth.nt_session_key) /* 16 */); } - if (state->request.data.auth_crap.flags & WINBIND_PAM_LMKEY) { + if (state->request.flags & WBFLAG_PAM_LMKEY) { memcpy(state->response.data.auth.first_8_lm_hash, info3.padding, sizeof(state->response.data.auth.first_8_lm_hash) /* 8 */); } } diff --git a/source3/nsswitch/winbindd_passdb.c b/source3/nsswitch/winbindd_passdb.c index 401662b6a7..456b1afeab 100644 --- a/source3/nsswitch/winbindd_passdb.c +++ b/source3/nsswitch/winbindd_passdb.c @@ -175,7 +175,7 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, DEBUG(3,("pdb: sid_to_name sid=%s\n", sid_string_static(sid))); - if (NT_STATUS_IS_OK(sid_to_uid(sid, &id))) { /* this is a user */ + if (NT_STATUS_IS_OK(idmap_sid_to_uid(sid, &id, 0))) { /* this is a user */ if (!NT_STATUS_IS_OK(result = pdb_init_sam(&sam_account))) { return result; @@ -197,7 +197,7 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, *type = SID_NAME_USER; result = NT_STATUS_OK; - } else if (NT_STATUS_IS_OK(sid_to_gid(sid, &id))) { /* this is a group */ + } else if (NT_STATUS_IS_OK(idmap_sid_to_gid(sid, &id, 0))) { /* this is a group */ DEBUG(3,("pdb: sid_to_name: group support not implemented\n")); result = NT_STATUS_UNSUCCESSFUL; diff --git a/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c index 5d7741850c..676beae3aa 100644 --- a/source3/nsswitch/winbindd_sid.c +++ b/source3/nsswitch/winbindd_sid.c @@ -122,6 +122,7 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) { DOM_SID sid; + uint32 flags = 0x0; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; @@ -131,15 +132,16 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) /* Split sid into domain sid and user rid */ if (!string_to_sid(&sid, state->request.data.sid)) { - DEBUG(1, ("Could not get convert sid %s from string\n", - state->request.data.sid)); + DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid)); return WINBINDD_ERROR; } - + + if ( state->request.flags & WBFLAG_QUERY_ONLY ) + flags = ID_QUERY_ONLY; + /* Find uid for this sid and return it */ - if (!NT_STATUS_IS_OK(sid_to_uid(&sid, &(state->response.data.uid)))) { - DEBUG(1, ("Could not get uid for sid %s\n", - state->request.data.sid)); + if ( !NT_STATUS_IS_OK(idmap_sid_to_uid(&sid, &(state->response.data.uid), flags)) ) { + DEBUG(1, ("Could not get uid for sid %s\n", state->request.data.sid)); return WINBINDD_ERROR; } @@ -152,6 +154,7 @@ enum winbindd_result winbindd_sid_to_uid(struct winbindd_cli_state *state) enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) { DOM_SID sid; + uint32 flags = 0x0; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; @@ -160,15 +163,16 @@ enum winbindd_result winbindd_sid_to_gid(struct winbindd_cli_state *state) state->request.data.sid)); if (!string_to_sid(&sid, state->request.data.sid)) { - DEBUG(1, ("Could not cvt string to sid %s\n", - state->request.data.sid)); + DEBUG(1, ("Could not cvt string to sid %s\n", state->request.data.sid)); return WINBINDD_ERROR; } + if ( state->request.flags & WBFLAG_QUERY_ONLY ) + flags = ID_QUERY_ONLY; + /* Find gid for this sid and return it */ - if (!NT_STATUS_IS_OK(sid_to_gid(&sid, &(state->response.data.gid)))) { - DEBUG(1, ("Could not get gid for sid %s\n", - state->request.data.sid)); + if ( !NT_STATUS_IS_OK(idmap_sid_to_gid(&sid, &(state->response.data.gid), flags)) ) { + DEBUG(1, ("Could not get gid for sid %s\n", state->request.data.sid)); return WINBINDD_ERROR; } @@ -192,7 +196,7 @@ enum winbindd_result winbindd_uid_to_sid(struct winbindd_cli_state *state) state->request.data.uid)); /* Lookup rid for this uid */ - if (!NT_STATUS_IS_OK(uid_to_sid(&sid, state->request.data.uid))) { + if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&sid, state->request.data.uid))) { DEBUG(1, ("Could not convert uid %d to rid\n", state->request.data.uid)); return WINBINDD_ERROR; @@ -221,7 +225,7 @@ enum winbindd_result winbindd_gid_to_sid(struct winbindd_cli_state *state) state->request.data.gid)); /* Lookup sid for this uid */ - if (!NT_STATUS_IS_OK(gid_to_sid(&sid, state->request.data.gid))) { + if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&sid, state->request.data.gid))) { DEBUG(1, ("Could not convert gid %d to sid\n", state->request.data.gid)); return WINBINDD_ERROR; diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 9d9360a6fa..37d9245075 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -44,14 +44,14 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name, /* Resolve the uid number */ - if (!NT_STATUS_IS_OK(sid_to_uid(user_sid, &(pw->pw_uid)))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &(pw->pw_uid), 0))) { DEBUG(1, ("error getting user id for sid %s\n", sid_to_string(sid_string, user_sid))); return False; } /* Resolve the gid number */ - if (!NT_STATUS_IS_OK(sid_to_gid(group_sid, &(pw->pw_gid)))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &(pw->pw_gid), 0))) { DEBUG(1, ("error getting group id for sid %s\n", sid_to_string(sid_string, group_sid))); return False; } @@ -116,10 +116,11 @@ enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state) name_user)) return WINBINDD_ERROR; - /* don't handle our own domain if we are a DC. This code handles cases where + /* don't handle our own domain if we are a DC ( or a member of a Samba domain + that shares UNIX accounts). This code handles cases where the account doesn't exist anywhere and gets passed on down the NSS layer */ - if ( IS_DC_FOR_DOMAIN(domain->name) ) { + if ( (IS_DC || lp_winbind_trusted_domains_only()) && strequal(name_domain, lp_workgroup()) ) { DEBUG(7,("winbindd_getpwnam: rejecting getpwnam() for %s\\%s since I am on the PDC for this domain\n", name_domain, name_user)); return WINBINDD_ERROR; @@ -202,7 +203,7 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) /* Get rid from uid */ - if (!NT_STATUS_IS_OK(uid_to_sid(&user_sid, state->request.data.uid))) { + if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&user_sid, state->request.data.uid))) { DEBUG(1, ("could not convert uid %d to SID\n", state->request.data.uid)); return WINBINDD_ERROR; @@ -246,7 +247,7 @@ enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state) /* Check group has a gid number */ - if (!NT_STATUS_IS_OK(sid_to_gid(user_info.group_sid, &gid))) { + if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_info.group_sid, &gid, 0))) { DEBUG(1, ("error getting group id for user %s\n", user_name)); talloc_destroy(mem_ctx); return WINBINDD_ERROR; @@ -296,10 +297,14 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state) struct getent_state *domain_state; - /* don't add our domaina if we are a PDC */ + /* don't add our domaina if we are a PDC or if we + are a member of a Samba domain */ - if ( IS_DC_FOR_DOMAIN( domain->name ) ) - continue; + if ( (IS_DC || lp_winbind_trusted_domains_only()) + && strequal(domain->name, lp_workgroup()) ) + { + continue; + } /* Create a state record for this domain */ diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 1736254a4c..3ce4979489 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -163,8 +163,7 @@ typedef struct char *szSourceEnv; char *szIdmapUID; char *szIdmapGID; - BOOL *bIdmapOnly; - char *szNonUnixAccountRange; + BOOL bEnableRidAlgorithm; int AlgorithmicRidBase; char *szTemplateHomedir; char *szTemplateShell; @@ -172,6 +171,7 @@ typedef struct BOOL bWinbindEnumUsers; BOOL bWinbindEnumGroups; BOOL bWinbindUseDefaultDomain; + BOOL bWinbindTrustedDomainsOnly; char *szWinbindBackend; char *szIdmapBackend; char *szAddShareCommand; @@ -1117,7 +1117,7 @@ static struct parm_struct parm_table[] = { {"Winbind options", P_SEP, P_SEPARATOR}, - {"idmap only", P_BOOL, P_GLOBAL, &Globals.bIdmapOnly, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, + {"enable rid algorithm", P_BOOL, P_GLOBAL, &Globals.bEnableRidAlgorithm, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER | FLAG_DEPRECATED}, {"idmap backend", P_STRING, P_GLOBAL, &Globals.szIdmapBackend, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"idmap uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"winbind uid", P_STRING, P_GLOBAL, &Globals.szIdmapUID, handle_idmap_uid, NULL, FLAG_ADVANCED | FLAG_DEVELOPER | FLAG_DEPRECATED }, @@ -1130,6 +1130,7 @@ static struct parm_struct parm_table[] = { {"winbind enum users", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumUsers, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"winbind enum groups", P_BOOL, P_GLOBAL, &Globals.bWinbindEnumGroups, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"winbind use default domain", P_BOOL, P_GLOBAL, &Globals.bWinbindUseDefaultDomain, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, + {"winbind trusted domains only", P_BOOL, P_GLOBAL, &Globals.bWinbindTrustedDomainsOnly, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0} }; @@ -1467,12 +1468,13 @@ static void init_globals(void) string_set(&Globals.szWinbindSeparator, "\\"); string_set(&Globals.szAclCompat, ""); - Globals.winbind_cache_time = 600; /* 5 minutes */ + Globals.winbind_cache_time = 300; /* 5 minutes */ Globals.bWinbindEnumUsers = True; Globals.bWinbindEnumGroups = True; Globals.bWinbindUseDefaultDomain = False; + Globals.bWinbindTrustedDomainsOnly = False; - Globals.bIdmapOnly = False; + Globals.bEnableRidAlgorithm = True; Globals.name_cache_timeout = 660; /* In seconds */ @@ -1637,9 +1639,10 @@ FN_GLOBAL_STRING(lp_acl_compatibility, &Globals.szAclCompat) FN_GLOBAL_BOOL(lp_winbind_enum_users, &Globals.bWinbindEnumUsers) FN_GLOBAL_BOOL(lp_winbind_enum_groups, &Globals.bWinbindEnumGroups) FN_GLOBAL_BOOL(lp_winbind_use_default_domain, &Globals.bWinbindUseDefaultDomain) +FN_GLOBAL_BOOL(lp_winbind_trusted_domains_only, &Globals.bWinbindTrustedDomainsOnly) FN_GLOBAL_STRING(lp_idmap_backend, &Globals.szIdmapBackend) -FN_GLOBAL_BOOL(lp_idmap_only, &Globals.bIdmapOnly) +FN_GLOBAL_BOOL(lp_enable_rid_algorithm, &Globals.bEnableRidAlgorithm) #ifdef WITH_LDAP_SAMCONFIG FN_GLOBAL_STRING(lp_ldap_server, &Globals.szLdapServer) diff --git a/source3/passdb/passdb.c b/source3/passdb/passdb.c index de919ef6f9..4c50b05107 100644 --- a/source3/passdb/passdb.c +++ b/source3/passdb/passdb.c @@ -892,10 +892,6 @@ BOOL local_lookup_name(const char *c_user, DOM_SID *psid, enum SID_NAME_USE *psi /************************************************************* Change a password entry in the local smbpasswd file. - -It is currently being called by SWAT and by smbpasswd. - - --jerry *************************************************************/ BOOL local_password_change(const char *user_name, int local_flags, @@ -1040,3 +1036,201 @@ BOOL local_password_change(const char *user_name, int local_flags, pdb_free_sam(&sam_pass); return True; } + +/**************************************************************************** + Convert a uid to SID - locally. +****************************************************************************/ + +DOM_SID *local_uid_to_sid(DOM_SID *psid, uid_t uid) +{ + SAM_ACCOUNT *sampw = NULL; + struct passwd *unix_pw; + + + + winbind_off(); + unix_pw = sys_getpwuid( uid ); + winbind_on(); + + if ( !unix_pw ) { + DEBUG(4,("local_uid_to_sid: host has know idea of uid %d\n", uid)); + return NULL; + } + + if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { + DEBUG(0,("local_uid_to_sid: failed to allocate SAM_ACCOUTN object\n")); + return NULL; + } + + if ( !pdb_getsampwnam( sampw, unix_pw->pw_name ) ) { + DEBUG(4,("local_uid_to_sid: User %s [uid == %d] has no samba account\n", + unix_pw->pw_name, uid)); + return NULL; + } + + sid_copy( psid, pdb_get_user_sid(sampw) ); + + DEBUG(10,("local_uid_to_sid: uid (%d) -> SID %s (%s).\n", + (unsigned int)uid, sid_string_static(psid), unix_pw->pw_name)); + + return psid; +} + +/**************************************************************************** + Convert a SID to uid - locally. +****************************************************************************/ + +BOOL local_sid_to_uid(uid_t *puid, DOM_SID *psid, enum SID_NAME_USE *name_type) +{ + DOM_SID dom_sid; + uint32 rid; + SAM_ACCOUNT *sampw = NULL; + struct passwd *unix_pw; + const char *user_name; + + *name_type = SID_NAME_UNKNOWN; + + sid_copy(&dom_sid, psid); + sid_split_rid(&dom_sid, &rid); + + /* + * We can only convert to a uid if this is our local + * Domain SID (ie. we are the controling authority). + */ + if ( !sid_equal(get_global_sam_sid(), &dom_sid) ) + return False; + + + /* lookup the user account */ + + if ( !NT_STATUS_IS_OK(pdb_init_sam(&sampw)) ) { + DEBUG(0,("local_sid_to_uid: Failed to allocate memory for SAM_ACCOUNT object\n")); + return False; + } + + if ( !pdb_getsampwsid(sampw, psid) ) { + DEBUG(8,("local_sid_to_uid: Could not find SID %s in passdb\n", + sid_string_static(psid))); + return False; + } + + user_name = pdb_get_username(sampw); + + winbind_off(); + unix_pw = sys_getpwnam( user_name ); + winbind_on(); + + if ( !unix_pw ) { + DEBUG(0,("local_sid_to_uid: %s found in passdb but getpwnam() return NULL!\n", + user_name)); + pdb_free_sam( &sampw ); + return False; + } + + *puid = unix_pw->pw_uid; + + DEBUG(10,("local_sid_to_uid: SID %s -> uid (%u) (%s).\n", sid_string_static(psid), + (unsigned int)*puid, user_name )); + + *name_type = SID_NAME_USER; + + return True; +} + +/**************************************************************************** + Convert a gid to SID - locally. +****************************************************************************/ + +DOM_SID *local_gid_to_sid(DOM_SID *psid, gid_t gid) +{ + GROUP_MAP group; + + /* we don't need to disable winbindd since the gid is stored in + the GROUP_MAP object */ + + if ( !pdb_getgrgid( &group, gid ) ) { + + /* fallback to rid mapping if enabled */ + + if ( lp_enable_rid_algorithm() ) { + sid_copy(psid, get_global_sam_sid()); + sid_append_rid(psid, pdb_gid_to_group_rid(gid)); + + DEBUG(10,("local_gid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", + (unsigned int)gid, sid_string_static(psid))); + + return psid; + } + else + return NULL; + } + + sid_copy( psid, &group.sid ); + + DEBUG(10,("local_gid_to_sid: gid (%d) -> SID %s.\n", + (unsigned int)gid, sid_string_static(psid))); + + return psid; +} + +/**************************************************************************** + Convert a SID to gid - locally. +****************************************************************************/ + +BOOL local_sid_to_gid(gid_t *pgid, DOM_SID *psid, enum SID_NAME_USE *name_type) +{ + DOM_SID dom_sid; + uint32 rid; + GROUP_MAP group; + + *name_type = SID_NAME_UNKNOWN; + + /* This call can enumerate grou mappings for foreign sids as well. + So don't check for a match against our domain SID */ + + /* we don't need to disable winbindd since the gid is stored in + the GROUP_MAP object */ + + if ( !pdb_getgrsid(&group, *psid) ) { + + /* fallback to rid mapping if enabled */ + + if ( lp_enable_rid_algorithm() ) { + sid_copy(&dom_sid, psid); + sid_split_rid(&dom_sid, &rid); + + if (!sid_equal(get_global_sam_sid(), &dom_sid) ) { + DEBUG(5,("local_sid_to_gid: RID algorithm only supported for our domain (not %s)\n", + sid_string_static(&dom_sid))); + return False; + } + + if (!sid_peek_rid(psid, &rid)) { + DEBUG(10,("local_sid_to_uid: invalid SID!\n")); + return False; + } + + DEBUG(10,("local_sid_to_gid: Fall back to algorithmic mapping\n")); + + if (fallback_pdb_rid_is_user(rid)) { + DEBUG(3, ("local_sid_to_gid: SID %s is *NOT* a group\n", sid_string_static(psid))); + return False; + } else { + *pgid = pdb_group_rid_to_gid(rid); + DEBUG(10,("local_sid_to_gid: mapping: %s -> %u\n", sid_string_static(psid), (unsigned int)(*pgid))); + return True; + } + } + + return False; + } + + *pgid = group.gid; + + DEBUG(10,("local_sid_to_gid: SID %s -> gid (%u)\n", sid_string_static(psid), + (unsigned int)*pgid)); + + return True; +} + + diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index 698365f42c..886fd809f3 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -2217,7 +2217,7 @@ static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods, count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); if (count < 1) { - DEBUG(4, ("Did not find group for filter %s\n", filter)); + DEBUG(4, ("Did not find group\n")); return NT_STATUS_NO_SUCH_GROUP; } @@ -2327,6 +2327,7 @@ static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods, (struct ldapsam_privates *)methods->private_data; LDAPMessage *result = NULL; LDAPMod **mods = NULL; + int count; char *tmp; pstring dn; @@ -2347,7 +2348,12 @@ static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods, return NT_STATUS_UNSUCCESSFUL; } - if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 1) { + count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result); + + if ( count == 0 ) + return NT_STATUS_UNSUCCESSFUL; + + if (count > 1) { DEBUG(2, ("Group %i must exist exactly once in LDAP\n", map->gid)); ldap_msgfree(result); diff --git a/source3/sam/idmap_util.c b/source3/sam/idmap_util.c index 8c66ef9ab0..626989656a 100644 --- a/source3/sam/idmap_util.c +++ b/source3/sam/idmap_util.c @@ -93,7 +93,7 @@ BOOL idmap_get_free_rid_range(uint32 *low, uint32 *high) { uint32 id_low, id_high; - if (lp_idmap_only()) { + if (!lp_enable_rid_algorithm()) { *low = BASE_RID; *high = (uint32)-1; } @@ -134,130 +134,71 @@ BOOL idmap_get_free_ugid_range(uint32 *low, uint32 *high) } /***************************************************************** - *THE CANONICAL* convert uid_t to SID function. check idmap if uid is in idmap range, otherwise falls back to - the legacy algorithmic mapping. - Returns SID pointer. + the legacy algorithmic mapping. Returns SID pointer. *****************************************************************/ -NTSTATUS uid_to_sid(DOM_SID *sid, uid_t uid) +NTSTATUS idmap_uid_to_sid(DOM_SID *sid, uid_t uid) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; unid_t id; int flags; - DEBUG(10,("uid_to_sid: uid = [%d]\n", uid)); + DEBUG(10,("idmap_uid_to_sid: uid = [%d]\n", uid)); flags = ID_USERID; - if (!lp_idmap_only() && !idmap_check_ugid_is_in_free_range(uid)) { - flags |= ID_QUERY_ONLY; - } - id.uid = uid; - if (!NT_STATUS_IS_OK(ret = idmap_get_sid_from_id(sid, id, flags))) { - DEBUG(10, ("uid_to_sid: Failed to map uid = [%u]\n", (unsigned int)uid)); - if (flags & ID_QUERY_ONLY) { - sid_copy(sid, get_global_sam_sid()); - sid_append_rid(sid, fallback_pdb_uid_to_user_rid(uid)); - - DEBUG(10,("uid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", (unsigned int)uid, sid_string_static(sid))); - ret = NT_STATUS_OK; - } - } - - return ret; + + return idmap_get_sid_from_id(sid, id, flags); } /***************************************************************** - *THE CANONICAL* convert gid_t to SID function. check idmap if gid is in idmap range, otherwise falls back to the legacy algorithmic mapping. Group mapping is used for gids that maps to Wellknown SIDs Returns SID pointer. *****************************************************************/ -NTSTATUS gid_to_sid(DOM_SID *sid, gid_t gid) +NTSTATUS idmap_gid_to_sid(DOM_SID *sid, gid_t gid) { - NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; unid_t id; int flags; - DEBUG(10,("gid_to_sid: gid = [%d]\n", gid)); + DEBUG(10,("idmap_gid_to_sid: gid = [%d]\n", gid)); flags = ID_GROUPID; - if (!lp_idmap_only() && !idmap_check_ugid_is_in_free_range(gid)) { + if (!idmap_check_ugid_is_in_free_range(gid)) { flags |= ID_QUERY_ONLY; } id.gid = gid; - if (!NT_STATUS_IS_OK(ret = idmap_get_sid_from_id(sid, id, flags))) { - DEBUG(10, ("gid_to_sid: Failed to map gid = [%u]\n", (unsigned int)gid)); - if (flags & ID_QUERY_ONLY) { - sid_copy(sid, get_global_sam_sid()); - sid_append_rid(sid, pdb_gid_to_group_rid(gid)); - - DEBUG(10,("gid_to_sid: Fall back to algorithmic mapping: %u -> %s\n", (unsigned int)gid, sid_string_static(sid))); - ret = NT_STATUS_OK; - } - } - - return ret; + return idmap_get_sid_from_id(sid, id, flags); } /***************************************************************** - *THE CANONICAL* convert SID to uid function. if it is a foreign sid or it is in idmap rid range check idmap, otherwise falls back to the legacy algorithmic mapping. Returns True if this name is a user sid and the conversion was done correctly, False if not. *****************************************************************/ -NTSTATUS sid_to_uid(const DOM_SID *sid, uid_t *uid) +NTSTATUS idmap_sid_to_uid(const DOM_SID *sid, uid_t *uid, uint32 flags) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - BOOL fallback = False; unid_t id; - int flags; - - DEBUG(10,("sid_to_uid: sid = [%s]\n", sid_string_static(sid))); - - flags = ID_USERID; - if (!lp_idmap_only()) { - if (!idmap_check_sid_is_in_free_range(sid)) { - flags |= ID_QUERY_ONLY; - fallback = True; - } - } - if (NT_STATUS_IS_OK(ret = idmap_get_id_from_sid(&id, &flags, sid))) { + DEBUG(10,("idmap_sid_to_uid: sid = [%s]\n", sid_string_static(sid))); - DEBUG(10,("sid_to_uid: uid = [%d]\n", id.uid)); + flags |= ID_USERID; + ret = idmap_get_id_from_sid(&id, &flags, sid); + + if ( NT_STATUS_IS_OK(ret) ) { + DEBUG(10,("idmap_sid_to_uid: uid = [%d]\n", id.uid)); *uid = id.uid; - - } else if (fallback) { - uint32 rid; - - if (!sid_peek_rid(sid, &rid)) { - DEBUG(10,("sid_to_uid: invalid SID!\n")); - ret = NT_STATUS_INVALID_PARAMETER; - goto done; - } - - DEBUG(10,("sid_to_uid: Fall back to algorithmic mapping\n")); + } - if (!fallback_pdb_rid_is_user(rid)) { - DEBUG(3, ("sid_to_uid: SID %s is *NOT* a user\n", sid_string_static(sid))); - ret = NT_STATUS_UNSUCCESSFUL; - } else { - *uid = fallback_pdb_user_rid_to_uid(rid); - DEBUG(10,("sid_to_uid: mapping: %s -> %u\n", sid_string_static(sid), (unsigned int)(*uid))); - ret = NT_STATUS_OK; - } - } - -done: return ret; + } /***************************************************************** @@ -269,51 +210,27 @@ done: was done correctly, False if not. *****************************************************************/ -NTSTATUS sid_to_gid(const DOM_SID *sid, gid_t *gid) +NTSTATUS idmap_sid_to_gid(const DOM_SID *sid, gid_t *gid, uint32 flags) { NTSTATUS ret = NT_STATUS_UNSUCCESSFUL; - BOOL fallback = False; unid_t id; - int flags; DEBUG(10,("sid_to_gid: sid = [%s]\n", sid_string_static(sid))); - flags = ID_GROUPID; - if (!lp_idmap_only()) { - if (!idmap_check_sid_is_in_free_range(sid)) { - flags |= ID_QUERY_ONLY; - fallback = True; - } - } + flags |= ID_GROUPID; - if (NT_STATUS_IS_OK(ret = idmap_get_id_from_sid(&id, &flags, sid))) { - - DEBUG(10,("sid_to_gid: gid = [%d]\n", id.gid)); + ret = idmap_get_id_from_sid(&id, &flags, sid); + + if ( NT_STATUS_IS_OK(ret) ) + { + DEBUG(10,("idmap_sid_to_gid: gid = [%d]\n", id.gid)); *gid = id.gid; - - } else if (fallback) { - uint32 rid; - - if (!sid_peek_rid(sid, &rid)) { - DEBUG(10,("sid_to_uid: invalid SID!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - DEBUG(10,("sid_to_gid: Fall back to algorithmic mapping\n")); - - if (fallback_pdb_rid_is_user(rid)) { - DEBUG(3, ("sid_to_gid: SID %s is *NOT* a group\n", sid_string_static(sid))); - ret = NT_STATUS_UNSUCCESSFUL; - } else { - *gid = pdb_group_rid_to_gid(rid); - DEBUG(10,("sid_to_gid: mapping: %s -> %u\n", sid_string_static(sid), (unsigned int)(*gid))); - ret = NT_STATUS_OK; - } } return ret; } + /*************************************************************************** Check first, call set_mapping if it doesn't already exist. ***************************************************************************/ diff --git a/source3/smbd/server.c b/source3/smbd/server.c index 6f549aab1c..0906e3b9d8 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -842,7 +842,7 @@ void build_options(BOOL screen); if (!init_registry()) exit(1); - /* Initialise the password backed before idmap and the global_sam_sid + /* Initialise the password backed before the global_sam_sid to ensure that we fetch from ldap before we make a domain sid up */ if(!initialize_password_db(False)) @@ -855,18 +855,6 @@ void build_options(BOOL screen); static_init_auth; - { - const char *idmap_back = lp_idmap_backend(); - - if (!idmap_init((idmap_back && *idmap_back) ? "winbind" : NULL)) - exit(1); - } - - if (!idmap_init_wellknown_sids()) { - DEBUG(0,("ERROR: Samba failed to initialize it's 'well known' SID -> ID mapping tables.\n")); - exit(1); - } - static_init_rpc; init_modules(); diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index c68d00025c..04ff0faa28 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -529,3 +529,411 @@ BOOL lookup_sid(DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE } return True; } + + +/***************************************************************** + Id mapping cache. This is to avoid Winbind mappings already + seen by smbd to be queried too frequently, keeping winbindd + busy, and blocking smbd while winbindd is busy with other + stuff. Written by Michael Steffens <michael.steffens@hp.com>, + modified to use linked lists by jra. +*****************************************************************/ + +#define MAX_UID_SID_CACHE_SIZE 100 +#define TURNOVER_UID_SID_CACHE_SIZE 10 +#define MAX_GID_SID_CACHE_SIZE 100 +#define TURNOVER_GID_SID_CACHE_SIZE 10 + +static size_t n_uid_sid_cache = 0; +static size_t n_gid_sid_cache = 0; + +static struct uid_sid_cache { + struct uid_sid_cache *next, *prev; + uid_t uid; + DOM_SID sid; + enum SID_NAME_USE sidtype; +} *uid_sid_cache_head; + +static struct gid_sid_cache { + struct gid_sid_cache *next, *prev; + gid_t gid; + DOM_SID sid; + enum SID_NAME_USE sidtype; +} *gid_sid_cache_head; + +/***************************************************************** + Find a SID given a uid. +*****************************************************************/ + +static BOOL fetch_sid_from_uid_cache(const DOM_SID *psid, uid_t uid) +{ + struct uid_sid_cache *pc; + + for (pc = uid_sid_cache_head; pc; pc = pc->next) { + if (pc->uid == uid) { + fstring sid; + *psid = pc->sid; + DEBUG(3,("fetch sid from uid cache %u -> %s\n", + (unsigned int)uid, sid_to_string(sid, psid))); + DLIST_PROMOTE(uid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Find a uid given a SID. +*****************************************************************/ + +static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid ) +{ + struct uid_sid_cache *pc; + + for (pc = uid_sid_cache_head; pc; pc = pc->next) { + if (sid_compare(&pc->sid, psid) == 0) { + fstring sid; + *puid = pc->uid; + DEBUG(3,("fetch uid from cache %u -> %s\n", + (unsigned int)*puid, sid_to_string(sid, psid))); + DLIST_PROMOTE(uid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Store uid to SID mapping in cache. +*****************************************************************/ + +static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid) +{ + struct uid_sid_cache *pc; + + if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) { + /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */ + struct uid_sid_cache *pc_next; + size_t i; + + for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next) + ; + for(; pc; pc = pc_next) { + pc_next = pc->next; + DLIST_REMOVE(uid_sid_cache_head,pc); + SAFE_FREE(pc); + n_uid_sid_cache--; + } + } + + pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache)); + if (!pc) + return; + pc->uid = uid; + sid_copy(&pc->sid, psid); + DLIST_ADD(uid_sid_cache_head, pc); + n_uid_sid_cache++; +} + +/***************************************************************** + Find a SID given a gid. +*****************************************************************/ + +static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid) +{ + struct gid_sid_cache *pc; + + for (pc = gid_sid_cache_head; pc; pc = pc->next) { + if (pc->gid == gid) { + fstring sid; + *psid = pc->sid; + DEBUG(3,("fetch sid from gid cache %u -> %s\n", + (unsigned int)gid, sid_to_string(sid, psid))); + DLIST_PROMOTE(gid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Find a gid given a SID. +*****************************************************************/ + +static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid) +{ + struct gid_sid_cache *pc; + + for (pc = gid_sid_cache_head; pc; pc = pc->next) { + if (sid_compare(&pc->sid, psid) == 0) { + fstring sid; + *pgid = pc->gid; + DEBUG(3,("fetch uid from cache %u -> %s\n", + (unsigned int)*pgid, sid_to_string(sid, psid))); + DLIST_PROMOTE(gid_sid_cache_head, pc); + return True; + } + } + return False; +} + +/***************************************************************** + Store gid to SID mapping in cache. +*****************************************************************/ + +static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid) +{ + struct gid_sid_cache *pc; + + if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) { + /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */ + struct gid_sid_cache *pc_next; + size_t i; + + for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next) + ; + for(; pc; pc = pc_next) { + pc_next = pc->next; + DLIST_REMOVE(gid_sid_cache_head,pc); + SAFE_FREE(pc); + n_gid_sid_cache--; + } + } + + pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache)); + if (!pc) + return; + pc->gid = gid; + sid_copy(&pc->sid, psid); + DLIST_ADD(gid_sid_cache_head, pc); + n_gid_sid_cache++; +} + +/***************************************************************** + *THE CANONICAL* convert uid_t to SID function. + check idmap if uid is in idmap range, otherwise falls back to + the legacy algorithmic mapping. + A special cache is used for uids that maps to Wellknown SIDs + Returns SID pointer. +*****************************************************************/ + +NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid) +{ + uid_t low, high; + fstring sid; + + if (fetch_sid_from_uid_cache(psid, uid)) + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + + if (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) { + if (winbind_uid_to_sid(psid, uid)) { + + DEBUG(10,("uid_to_sid: winbindd %u -> %s\n", + (unsigned int)uid, sid_to_string(sid, psid))); + + if (psid) + store_uid_sid_cache(psid, uid); + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + } + } + + local_uid_to_sid(psid, uid); + + DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid))); + + if (psid) + store_uid_sid_cache(psid, uid); + + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); +} + +/***************************************************************** + *THE CANONICAL* convert gid_t to SID function. + check idmap if gid is in idmap range, otherwise falls back to + the legacy algorithmic mapping. + Group mapping is used for gids that maps to Wellknown SIDs + Returns SID pointer. +*****************************************************************/ + +NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid) +{ + gid_t low, high; + fstring sid; + + if (fetch_sid_from_gid_cache(psid, gid)) + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + + if (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) { + if (winbind_gid_to_sid(psid, gid)) { + + DEBUG(10,("gid_to_sid: winbindd %u -> %s\n", + (unsigned int)gid, sid_to_string(sid, psid))); + + if (psid) + store_gid_sid_cache(psid, gid); + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); + } + } + + local_gid_to_sid(psid, gid); + + DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid))); + + if (psid) + store_gid_sid_cache(psid, gid); + + return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL ); +} + +/***************************************************************** + *THE CANONICAL* convert SID to uid function. + if it is a foreign sid or it is in idmap rid range check idmap, + otherwise falls back to the legacy algorithmic mapping. + A special cache is used for uids that maps to Wellknown SIDs + Returns True if this name is a user sid and the conversion + was done correctly, False if not. +*****************************************************************/ + +NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid) +{ + fstring dom_name, name, sid_str; + enum SID_NAME_USE name_type; + BOOL ret; + + if (fetch_uid_from_cache(puid, psid)) + return NT_STATUS_OK; + + /* + * First we must look up the name and decide if this is a user sid. + */ + + if ( (!winbind_lookup_sid(psid, dom_name, name, &name_type)) || (name_type != SID_NAME_USER) ) { + DEBUG(10,("sid_to_uid: winbind lookup for sid %s failed - trying local.\n", + sid_to_string(sid_str, psid) )); + + ret = local_sid_to_uid(puid, psid, &name_type); + if (ret) + store_uid_sid_cache(psid, *puid); + return (ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL); + } + + /* + * Ensure this is a user sid. + */ + + if (name_type != SID_NAME_USER) { + DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a uid (%u)\n", + (unsigned int)name_type )); + return NT_STATUS_INVALID_PARAMETER; + } + + /* query only first */ + + if ( !winbind_sid_to_uid_query(puid, psid) ) + { + DEBUG(10,("sid_to_uid: winbind query for sid %s failed.\n", + sid_to_string(sid_str, psid) )); + + /* see if we have a local mapping */ + + if ( local_sid_to_uid(puid, psid, &name_type) ) { + store_uid_sid_cache(psid, *puid); + return NT_STATUS_OK; + } + + /* Call back to winbind to allocate a new uid */ + + if ( !winbind_sid_to_uid(puid, psid) ) { + DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n", + sid_to_string(sid_str, psid) )); + return NT_STATUS_UNSUCCESSFUL; + } + } + + DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid), + (unsigned int)*puid )); + + store_uid_sid_cache(psid, *puid); + + return NT_STATUS_OK; +} +/***************************************************************** + *THE CANONICAL* convert SID to gid function. + if it is a foreign sid or it is in idmap rid range check idmap, + otherwise falls back to the legacy algorithmic mapping. + Group mapping is used for gids that maps to Wellknown SIDs + Returns True if this name is a user sid and the conversion + was done correctly, False if not. +*****************************************************************/ + +NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid) +{ + fstring dom_name, name, sid_str; + enum SID_NAME_USE name_type; + BOOL ret; + + if (fetch_gid_from_cache(pgid, psid)) + return NT_STATUS_OK; + + /* + * First we must look up the name and decide if this is a group sid. + */ + + if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) { + DEBUG(10,("sid_to_gid: winbind lookup for sid %s failed - trying local.\n", + sid_to_string(sid_str, psid) )); + + ret = local_sid_to_gid(pgid, psid, &name_type); + if (ret) + store_gid_sid_cache(psid, *pgid); + + return (ret ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL); + } + + /* + * Ensure this is a group sid. + */ + + if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_WKN_GRP)) { + DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n", + (unsigned int)name_type )); + + ret = local_sid_to_gid(pgid, psid, &name_type); + if (ret) + store_gid_sid_cache(psid, *pgid); + return (ret ? NT_STATUS_OK : NT_STATUS_INVALID_PARAMETER); + } + + /* query only first */ + + if ( !winbind_sid_to_gid_query(pgid, psid) ) + { + DEBUG(10,("sid_to_gid: winbind query for sid %s failed.\n", + sid_to_string(sid_str, psid) )); + + /* see if we have a local mapping */ + + if ( local_sid_to_gid(pgid, psid, &name_type) ) { + store_gid_sid_cache(psid, *pgid); + return NT_STATUS_OK; + } + + /* Call back to winbind to allocate a new uid */ + + if ( !winbind_sid_to_gid(pgid, psid) ) { + DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n", + sid_to_string(sid_str, psid) )); + return NT_STATUS_UNSUCCESSFUL; + } + else + return NT_STATUS_UNSUCCESSFUL; + } + + DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid), + (unsigned int)*pgid )); + + store_gid_sid_cache(psid, *pgid); + + return NT_STATUS_OK; +} + diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index c619936f68..3dfa157bda 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -196,7 +196,7 @@ static NTSTATUS contact_winbind_auth_crap(const char *username, ZERO_STRUCT(request); ZERO_STRUCT(response); - request.data.auth_crap.flags = flags; + request.flags = flags; fstrcpy(request.data.auth_crap.user, username); @@ -233,13 +233,13 @@ static NTSTATUS contact_winbind_auth_crap(const char *username, return nt_status; } - if ((flags & WINBIND_PAM_LMKEY) && lm_key + if ((flags & WBFLAG_PAM_LMKEY) && lm_key && (memcmp(zeros, response.data.auth.first_8_lm_hash, sizeof(response.data.auth.first_8_lm_hash)) != 0)) { memcpy(lm_key, response.data.auth.first_8_lm_hash, sizeof(response.data.auth.first_8_lm_hash)); } - if ((flags & WINBIND_PAM_NTKEY) && nt_key + if ((flags & WBFLAG_PAM_NTKEY) && nt_key && (memcmp(zeros, response.data.auth.nt_session_key, sizeof(response.data.auth.nt_session_key)) != 0)) { memcpy(nt_key, response.data.auth.nt_session_key, @@ -413,10 +413,10 @@ static BOOL check_auth_crap(void) x_setbuf(x_stdout, NULL); if (request_lm_key) - flags |= WINBIND_PAM_LMKEY; + flags |= WBFLAG_PAM_LMKEY; if (request_nt_key) - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_NTKEY; nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, @@ -494,8 +494,8 @@ static BOOL test_lm(void) ZERO_STRUCT(lm_key); ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_LMKEY; - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_LMKEY; + flags |= WBFLAG_PAM_NTKEY; SMBencrypt(opt_password, chall.data, lm_response.data); E_deshash(opt_password, lm_hash); @@ -559,8 +559,8 @@ static BOOL test_lm_ntlm(void) ZERO_STRUCT(lm_key); ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_LMKEY; - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_LMKEY; + flags |= WBFLAG_PAM_NTKEY; SMBencrypt(opt_password,chall.data,lm_response.data); E_deshash(opt_password, lm_hash); @@ -633,8 +633,8 @@ static BOOL test_ntlm(void) ZERO_STRUCT(lm_key); ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_LMKEY; - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_LMKEY; + flags |= WBFLAG_PAM_NTKEY; SMBNTencrypt(opt_password,chall.data,nt_response.data); E_md4hash(opt_password, nt_hash); @@ -702,8 +702,8 @@ static BOOL test_ntlm_in_lm(void) ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_LMKEY; - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_LMKEY; + flags |= WBFLAG_PAM_NTKEY; SMBNTencrypt(opt_password,chall.data,nt_response.data); @@ -771,8 +771,8 @@ static BOOL test_ntlm_in_both(void) ZERO_STRUCT(lm_key); ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_LMKEY; - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_LMKEY; + flags |= WBFLAG_PAM_NTKEY; SMBNTencrypt(opt_password,chall.data,nt_response.data); E_md4hash(opt_password, nt_hash); @@ -842,7 +842,7 @@ static BOOL test_ntlmv2(void) ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_NTKEY; if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall, &names_blob, @@ -905,7 +905,7 @@ static BOOL test_lmv2_ntlmv2(void) ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_NTKEY; if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall, &names_blob, @@ -1016,8 +1016,8 @@ static BOOL test_ntlm_broken(BOOL break_lm) ZERO_STRUCT(lm_key); ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_LMKEY; - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_LMKEY; + flags |= WBFLAG_PAM_NTKEY; SMBencrypt(opt_password,chall.data,lm_response.data); E_deshash(opt_password, lm_hash); @@ -1099,7 +1099,7 @@ static BOOL test_ntlmv2_broken(BOOL break_lmv2) ZERO_STRUCT(nt_key); - flags |= WINBIND_PAM_NTKEY; + flags |= WBFLAG_PAM_NTKEY; if (!SMBNTLMv2encrypt(opt_username, opt_domain, opt_password, &chall, &names_blob, diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index 5b702f7591..2f57470c4a 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -158,7 +158,7 @@ static int print_sam_info (SAM_ACCOUNT *sam_pwent, BOOL verbosity, BOOL smbpwdst char nt_passwd[33]; uid = -1; - sid_to_uid(pdb_get_user_sid(sam_pwent), &uid); + idmap_sid_to_uid(pdb_get_user_sid(sam_pwent), &uid, 0); pdb_sethexpwd(lm_passwd, pdb_get_lanman_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent)); pdb_sethexpwd(nt_passwd, pdb_get_nt_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent)); @@ -171,7 +171,7 @@ static int print_sam_info (SAM_ACCOUNT *sam_pwent, BOOL verbosity, BOOL smbpwdst (uint32)pdb_get_pass_last_set_time(sam_pwent)); } else { uid = -1; - sid_to_uid(pdb_get_user_sid(sam_pwent), &uid); + idmap_sid_to_uid(pdb_get_user_sid(sam_pwent), &uid, 0); printf ("%s:%d:%s\n", pdb_get_username(sam_pwent), uid, pdb_get_fullname(sam_pwent)); } |