diff options
author | Gerald Carter <jerry@samba.org> | 2006-05-23 15:21:55 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2006-05-23 15:21:55 +0000 |
commit | 3f7bb704a9e62e7a46a05838ec9300c2f6916c16 (patch) | |
tree | e2ca7f1b8da68d725e5359d7746f391fedcad6be /source/nsswitch | |
parent | 34b471724d1c8eb9e020fce02fc538bd0993d1c4 (diff) | |
download | samba-3f7bb704a9e62e7a46a05838ec9300c2f6916c16.tar.gz samba-3f7bb704a9e62e7a46a05838ec9300c2f6916c16.tar.xz samba-3f7bb704a9e62e7a46a05838ec9300c2f6916c16.zip |
r15837: starting sync up for 3.0.23rc1 (in sync with SAMBA_3_0 r15822)
Diffstat (limited to 'source/nsswitch')
-rw-r--r-- | source/nsswitch/pam_winbind.c | 83 | ||||
-rw-r--r-- | source/nsswitch/pam_winbind.h | 2 | ||||
-rw-r--r-- | source/nsswitch/wbinfo.c | 40 | ||||
-rw-r--r-- | source/nsswitch/winbind_nss_aix.c | 3 | ||||
-rw-r--r-- | source/nsswitch/winbind_nss_config.h | 1 | ||||
-rw-r--r-- | source/nsswitch/winbind_nss_irix.c | 260 | ||||
-rw-r--r-- | source/nsswitch/winbindd.c | 11 | ||||
-rw-r--r-- | source/nsswitch/winbindd.h | 4 | ||||
-rw-r--r-- | source/nsswitch/winbindd_ads.c | 225 | ||||
-rw-r--r-- | source/nsswitch/winbindd_cache.c | 20 | ||||
-rw-r--r-- | source/nsswitch/winbindd_cm.c | 9 | ||||
-rw-r--r-- | source/nsswitch/winbindd_cred_cache.c | 69 | ||||
-rw-r--r-- | source/nsswitch/winbindd_dual.c | 76 | ||||
-rw-r--r-- | source/nsswitch/winbindd_nss.h | 2 | ||||
-rw-r--r-- | source/nsswitch/winbindd_pam.c | 24 | ||||
-rw-r--r-- | source/nsswitch/winbindd_rpc.c | 22 | ||||
-rw-r--r-- | source/nsswitch/winbindd_user.c | 2 | ||||
-rw-r--r-- | source/nsswitch/winbindd_util.c | 49 |
18 files changed, 711 insertions, 191 deletions
diff --git a/source/nsswitch/pam_winbind.c b/source/nsswitch/pam_winbind.c index b2c3a011643..43ac83a99a8 100644 --- a/source/nsswitch/pam_winbind.c +++ b/source/nsswitch/pam_winbind.c @@ -66,7 +66,7 @@ static int _pam_parse(int argc, const char **argv, dictionary **d) *d = iniparser_load(CONST_DISCARD(char *, config_file)); if (*d == NULL) { - return -1; + goto config_from_pam; } if (iniparser_getboolean(*d, CONST_DISCARD(char *, "global:debug"), False)) { @@ -191,7 +191,7 @@ static int _make_remark(pam_handle_t * pamh, int type, const char *text) struct pam_response *resp; pmsg[0] = &msg[0]; - msg[0].msg = text; + msg[0].msg = CONST_DISCARD(char *, text); msg[0].msg_style = type; resp = NULL; @@ -242,8 +242,9 @@ static int pam_winbind_request(pam_handle_t * pamh, int ctrl, /* Copy reply data from socket */ if (response->result != WINBINDD_OK) { if (response->data.auth.pam_error != PAM_SUCCESS) { - _pam_log(LOG_ERR, "request failed: %s, PAM error was %d, NT error was %s", + _pam_log(LOG_ERR, "request failed: %s, PAM error was %s (%d), NT error was %s", response->data.auth.error_string, + pam_strerror(pamh, response->data.auth.pam_error), response->data.auth.pam_error, response->data.auth.nt_status_string); return response->data.auth.pam_error; @@ -286,8 +287,7 @@ static int pam_winbind_request_log(pam_handle_t * pamh, return retval; case PAM_USER_UNKNOWN: /* the user does not exist */ - _pam_log_debug(ctrl, LOG_NOTICE, "user `%s' not found", - user); + _pam_log_debug(ctrl, LOG_NOTICE, "user `%s' not found", user); if (ctrl & WINBIND_UNKNOWN_OK_ARG) { return PAM_IGNORE; } @@ -320,7 +320,8 @@ static int winbind_auth_request(pam_handle_t * pamh, const char *pass, const char *member, const char *cctype, - int process_result) + int process_result, + time_t *pwd_last_set) { struct winbindd_request request; struct winbindd_response response; @@ -329,6 +330,10 @@ static int winbind_auth_request(pam_handle_t * pamh, ZERO_STRUCT(request); ZERO_STRUCT(response); + if (pwd_last_set) { + *pwd_last_set = 0; + } + strncpy(request.data.auth.user, user, sizeof(request.data.auth.user)-1); @@ -401,6 +406,10 @@ static int winbind_auth_request(pam_handle_t * pamh, ret = pam_winbind_request_log(pamh, ctrl, WINBINDD_PAM_AUTH, &request, &response, user); + if (pwd_last_set) { + *pwd_last_set = response.data.auth.info3.pass_last_set_time; + } + if ((ctrl & WINBIND_KRB5_AUTH) && response.data.auth.krb5ccname[0] != '\0') { @@ -466,6 +475,7 @@ static int winbind_auth_request(pam_handle_t * pamh, if (response.data.auth.info3.user_flgs & LOGON_CACHED_ACCOUNT) { _make_remark(pamh, PAM_ERROR_MSG, "Logging on using cached account. Network ressources can be unavailable"); + _pam_log_debug(ctrl, LOG_DEBUG,"User %s logged on using cached account\n", user); } /* save the CIFS homedir for pam_cifs / pam_mount */ @@ -487,7 +497,8 @@ static int winbind_chauthtok_request(pam_handle_t * pamh, int ctrl, const char *user, const char *oldpass, - const char *newpass) + const char *newpass, + time_t pwd_last_set) { struct winbindd_request request; struct winbindd_response response; @@ -541,7 +552,13 @@ static int winbind_chauthtok_request(pam_handle_t * pamh, /* FIXME: avoid to send multiple PAM messages after another */ switch (response.data.auth.reject_reason) { - case 0: + case -1: + break; + case REJECT_REASON_OTHER: + if ((response.data.auth.policy.min_passwordage > 0) && + (pwd_last_set + response.data.auth.policy.min_passwordage > time(NULL))) { + PAM_WB_REMARK_DIRECT(pamh, "NT_STATUS_PWD_TOO_RECENT"); + } break; case REJECT_REASON_TOO_SHORT: PAM_WB_REMARK_DIRECT(pamh, "NT_STATUS_PWD_TOO_SHORT"); @@ -692,7 +709,7 @@ static int _winbind_read_password(pam_handle_t * pamh, if (comment != NULL) { pmsg[0] = &msg[0]; msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = comment; + msg[0].msg = CONST_DISCARD(char *, comment); i = 1; } else { i = 0; @@ -700,13 +717,13 @@ static int _winbind_read_password(pam_handle_t * pamh, pmsg[i] = &msg[i]; msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt1; + msg[i++].msg = CONST_DISCARD(char *, prompt1); replies = 1; if (prompt2 != NULL) { pmsg[i] = &msg[i]; msg[i].msg_style = PAM_PROMPT_ECHO_OFF; - msg[i++].msg = prompt2; + msg[i++].msg = CONST_DISCARD(char *, prompt2); ++replies; } /* so call the conversation expecting i responses */ @@ -790,7 +807,7 @@ const char *get_conf_item_string(int argc, goto out; } - /* let the pam opt take precedence over the smb.conf option */ + /* let the pam opt take precedence over the pam_winbind.conf option */ if (d != NULL) { @@ -819,7 +836,9 @@ const char *get_conf_item_string(int argc, } } - _pam_log_debug(ctrl, LOG_INFO, "CONFIG file: %s '%s'\n", item, parm_opt); + if (d != NULL) { + _pam_log_debug(ctrl, LOG_INFO, "CONFIG file: %s '%s'\n", item, parm_opt); + } out: SAFE_FREE(parm); return parm_opt; @@ -858,7 +877,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, goto out; } - _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_authenticate"); + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_authenticate (flags: 0x%04x)", flags); /* Get the username */ retval = pam_get_user(pamh, &username, NULL); @@ -892,7 +911,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, cctype = get_krb5_cc_type_from_config(argc, argv, ctrl, d); /* Now use the username to look up password */ - retval = winbind_auth_request(pamh, ctrl, username, password, member, cctype, True); + retval = winbind_auth_request(pamh, ctrl, username, password, member, cctype, True, NULL); if (retval == PAM_NEW_AUTHTOK_REQD || retval == PAM_AUTHTOK_EXPIRED) { @@ -927,7 +946,7 @@ int pam_sm_setcred(pam_handle_t *pamh, int flags, return PAM_SYSTEM_ERR; } - _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_setcred"); + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_setcred (flags: 0x%04x)", flags); if (flags & PAM_DELETE_CRED) { return pam_sm_close_session(pamh, flags, argc, argv); @@ -954,7 +973,7 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, return PAM_SYSTEM_ERR; } - _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_acct_mgmt"); + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_acct_mgmt (flags: 0x%04x)", flags); /* Get the username */ @@ -1021,7 +1040,7 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags, return PAM_SYSTEM_ERR; } - _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_open_session handler"); + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_open_session handler (flags: 0x%04x)", flags); return PAM_SUCCESS; } @@ -1040,7 +1059,7 @@ int pam_sm_close_session(pam_handle_t *pamh, int flags, goto out; } - _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_close_session handler"); + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_close_session handler (flags: 0x%04x)", flags); if (!(flags & PAM_DELETE_CRED)) { retval = PAM_SUCCESS; @@ -1132,7 +1151,10 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, goto out; } - _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_chauthtok"); + _pam_log_debug(ctrl, LOG_DEBUG,"pam_winbind: pam_sm_chauthtok (flags: 0x%04x)", flags); + + /* clearing offline bit for the auth in the password change */ + ctrl &= ~WINBIND_CACHED_LOGIN; /* * First get the name of a user @@ -1174,6 +1196,8 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (flags & PAM_PRELIM_CHECK) { + time_t pwdlastset_prelim = 0; + /* instruct user what is happening */ #define greeting "Changing password for " Announce = (char *) malloc(sizeof(greeting) + strlen(user)); @@ -1198,16 +1222,18 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, } /* verify that this is the password for this user */ - retval = winbind_auth_request(pamh, ctrl, user, pass_old, NULL, NULL, False); + retval = winbind_auth_request(pamh, ctrl, user, pass_old, NULL, NULL, False, &pwdlastset_prelim); - if (retval != PAM_ACCT_EXPIRED - && retval != PAM_AUTHTOK_EXPIRED - && retval != PAM_NEW_AUTHTOK_REQD - && retval != PAM_SUCCESS) { + if (retval != PAM_ACCT_EXPIRED && + retval != PAM_AUTHTOK_EXPIRED && + retval != PAM_NEW_AUTHTOK_REQD && + retval != PAM_SUCCESS) { pass_old = NULL; goto out; } + pam_set_data(pamh, PAM_WINBIND_PWD_LAST_SET, (void *)pwdlastset_prelim, _pam_winbind_cleanup_func); + retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); pass_old = NULL; if (retval != PAM_SUCCESS) { @@ -1215,6 +1241,8 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, } } else if (flags & PAM_UPDATE_AUTHTOK) { + time_t pwdlastset_update = 0; + /* * obtain the proposed password */ @@ -1272,8 +1300,9 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, * By reaching here we have approved the passwords and must now * rebuild the password database file. */ + pam_get_data( pamh, PAM_WINBIND_PWD_LAST_SET, (const void **)&pwdlastset_update); - retval = winbind_chauthtok_request(pamh, ctrl, user, pass_old, pass_new); + retval = winbind_chauthtok_request(pamh, ctrl, user, pass_old, pass_new, pwdlastset_update); if (retval) { _pam_overwrite(pass_new); _pam_overwrite(pass_old); @@ -1288,7 +1317,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, const char *member = get_member_from_config(argc, argv, ctrl, d); const char *cctype = get_krb5_cc_type_from_config(argc, argv, ctrl, d); - retval = winbind_auth_request(pamh, ctrl, user, pass_new, member, cctype, False); + retval = winbind_auth_request(pamh, ctrl, user, pass_new, member, cctype, False, NULL); _pam_overwrite(pass_new); _pam_overwrite(pass_old); pass_old = pass_new = NULL; diff --git a/source/nsswitch/pam_winbind.h b/source/nsswitch/pam_winbind.h index 89553ebfc38..fb2769d1c1a 100644 --- a/source/nsswitch/pam_winbind.h +++ b/source/nsswitch/pam_winbind.h @@ -10,6 +10,7 @@ #include <stdlib.h> #include <unistd.h> +#include <limits.h> #include <string.h> #include <syslog.h> #include <stdarg.h> @@ -107,6 +108,7 @@ do { \ #define PAM_WINBIND_NEW_AUTHTOK_REQD "PAM_WINBIND_NEW_AUTHTOK_REQD" #define PAM_WINBIND_HOMEDIR "PAM_WINBIND_HOMEDIR" +#define PAM_WINBIND_PWD_LAST_SET "PAM_WINBIND_PWD_LAST_SET" #define SECONDS_PER_DAY 86400 diff --git a/source/nsswitch/wbinfo.c b/source/nsswitch/wbinfo.c index ad5ef715230..c004b842f4f 100644 --- a/source/nsswitch/wbinfo.c +++ b/source/nsswitch/wbinfo.c @@ -119,6 +119,38 @@ static BOOL parse_wbinfo_domain_user(const char *domuser, fstring domain, return True; } +/* pull pwent info for a given user */ + +static BOOL wbinfo_get_userinfo(char *user) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + /* Send request */ + + fstrcpy(request.data.username, user); + + result = winbindd_request_response(WINBINDD_GETPWNAM, &request, &response); + + if (result != NSS_STATUS_SUCCESS) + return False; + + d_printf( "%s:%s:%d:%d:%s:%s:%s\n", + response.data.pw.pw_name, + response.data.pw.pw_passwd, + response.data.pw.pw_uid, + response.data.pw.pw_gid, + response.data.pw.pw_gecos, + response.data.pw.pw_dir, + response.data.pw.pw_shell ); + + return True; +} + /* List groups a user is a member of */ static BOOL wbinfo_get_usergroups(char *user) @@ -1086,6 +1118,7 @@ int main(int argc, char **argv) { "all-domains", 0, POPT_ARG_NONE, 0, OPT_LIST_ALL_DOMAINS, "List all domains (trusted and own domain)" }, { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" }, { "domain-info", 'D', POPT_ARG_STRING, &string_arg, 'D', "Show most of the info we have about the domain" }, + { "user-info", 'i', POPT_ARG_STRING, &string_arg, 'i', "Get user info", "USER" }, { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" }, { "user-domgroups", 0, POPT_ARG_STRING, &string_arg, OPT_USERDOMGROUPS, "Get user domain groups", "SID" }, @@ -1245,6 +1278,13 @@ int main(int argc, char **argv) goto done; } break; + case 'i': + if (!wbinfo_get_userinfo(string_arg)) { + d_fprintf(stderr, "Could not get info for user %s\n", + string_arg); + goto done; + } + break; case 'r': if (!wbinfo_get_usergroups(string_arg)) { d_fprintf(stderr, "Could not get groups for user %s\n", diff --git a/source/nsswitch/winbind_nss_aix.c b/source/nsswitch/winbind_nss_aix.c index c5d98dad067..5b3aaeb8d77 100644 --- a/source/nsswitch/winbind_nss_aix.c +++ b/source/nsswitch/winbind_nss_aix.c @@ -360,6 +360,9 @@ static char *wb_aix_getgrset(char *user) logit("getgrset '%s'\n", r_user); + ZERO_STRUCT(response); + ZERO_STRUCT(request); + STRCPY_RETNULL(request.data.username, r_user); if (*user == WB_AIX_ENCODED) { diff --git a/source/nsswitch/winbind_nss_config.h b/source/nsswitch/winbind_nss_config.h index 0400b2fb36d..66e38513fd2 100644 --- a/source/nsswitch/winbind_nss_config.h +++ b/source/nsswitch/winbind_nss_config.h @@ -159,6 +159,7 @@ typedef int BOOL; #endif #ifndef HAVE_SOCKLEN_T_TYPE +#define HAVE_SOCKLEN_T_TYPE typedef int socklen_t; #endif diff --git a/source/nsswitch/winbind_nss_irix.c b/source/nsswitch/winbind_nss_irix.c index 05085ba1f39..2fbf3e0df82 100644 --- a/source/nsswitch/winbind_nss_irix.c +++ b/source/nsswitch/winbind_nss_irix.c @@ -4,6 +4,7 @@ Windows NT Domain nsswitch module Copyright (C) Tim Potter 2000 + Copyright (C) James Peach 2006 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -23,8 +24,19 @@ #include "winbind_client.h" +#ifndef PRINTF_ATTRIBUTE +#define PRINTF_ATTRIBUTE(m, n) +#endif + +#ifndef HAVE_ASPRINTF_DECL +/*PRINTFLIKE2 */ +int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3); +#endif + #ifdef HAVE_NS_API_H #undef VOLATILE +#undef STATIC +#undef DYNAMIC #include <ns_daemon.h> #endif @@ -165,13 +177,10 @@ static int winbind_callback(nsd_file_t **rqp, int fd) { struct winbindd_response response; - struct winbindd_pw *pw = &response.data.pw; - struct winbindd_gr *gr = &response.data.gr; nsd_file_t *rq; NSS_STATUS status; - fstring result; - char *members; - int i, maxlen; + char * result = NULL; + size_t rlen; dequeue_request(); @@ -192,76 +201,164 @@ winbind_callback(nsd_file_t **rqp, int fd) nsd_logprintf(NSD_LOG_MIN, "callback (winbind) returning not found, status = %d\n", status); - rq->f_status = NS_NOTFOUND; + + switch (status) { + case NSS_STATUS_UNAVAIL: + rq->f_status = NS_UNAVAIL; + break; + case NSS_STATUS_TRYAGAIN: + rq->f_status = NS_TRYAGAIN; + break; + case NSS_STATUS_NOTFOUND: + /* FALLTHRU */ + default: + rq->f_status = NS_NOTFOUND; + } + return NSD_NEXT; } - maxlen = sizeof(result) - 1; - switch ((int)rq->f_cmd_data) { case WINBINDD_WINS_BYNAME: case WINBINDD_WINS_BYIP: - snprintf(result,maxlen,"%s\n",response.data.winsresp); - break; + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) WINS_BYNAME | WINS_BYIP\n"); + + rlen = asprintf(&result, "%s\n", response.data.winsresp); + if (rlen == 0 || result == NULL) { + return NSD_ERROR; + } + + free_response(&response); + + nsd_logprintf(NSD_LOG_MIN, " %s\n", result); + nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC); + return NSD_OK; + case WINBINDD_GETPWUID: case WINBINDD_GETPWNAM: - snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s\n", - pw->pw_name, - pw->pw_passwd, - pw->pw_uid, - pw->pw_gid, - pw->pw_gecos, - pw->pw_dir, - pw->pw_shell); - break; + { + struct winbindd_pw *pw = &response.data.pw; + + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) GETPWUID | GETPWUID\n"); + + rlen = asprintf(&result,"%s:%s:%d:%d:%s:%s:%s\n", + pw->pw_name, + pw->pw_passwd, + pw->pw_uid, + pw->pw_gid, + pw->pw_gecos, + pw->pw_dir, + pw->pw_shell); + if (rlen == 0 || result == NULL) + return NSD_ERROR; + + free_response(&response); + + nsd_logprintf(NSD_LOG_MIN, " %s\n", result); + nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC); + return NSD_OK; + } + case WINBINDD_GETGRNAM: case WINBINDD_GETGRGID: - if (gr->num_gr_mem && response.extra_data.data) - members = response.extra_data.data; - else - members = ""; - snprintf(result,maxlen,"%s:%s:%d:%s\n", - gr->gr_name, gr->gr_passwd, gr->gr_gid, members); - break; + { + const struct winbindd_gr *gr = &response.data.gr; + const char * members; + + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) GETGRNAM | GETGRGID\n"); + + if (gr->num_gr_mem && response.extra_data.data) { + members = response.extra_data.data; + } else { + members = ""; + } + + rlen = asprintf(&result, "%s:%s:%d:%s\n", + gr->gr_name, gr->gr_passwd, gr->gr_gid, members); + if (rlen == 0 || result == NULL) + return NSD_ERROR; + + free_response(&response); + + nsd_logprintf(NSD_LOG_MIN, " %s\n", result); + nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC); + return NSD_OK; + } + case WINBINDD_SETGRENT: case WINBINDD_SETPWENT: - nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - SETPWENT/SETGRENT\n"); + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) SETGRENT | SETPWENT\n"); free_response(&response); return(do_list(1,rq)); + case WINBINDD_GETGRENT: case WINBINDD_GETGRLST: - nsd_logprintf(NSD_LOG_MIN, - "callback (winbind) - %d GETGRENT responses\n", - response.data.num_entries); - if (response.data.num_entries) { - gr = (struct winbindd_gr *)response.extra_data.data; - if (! gr ) { - nsd_logprintf(NSD_LOG_MIN, " no extra_data.data\n"); - free_response(&response); - return NSD_ERROR; - } - members = (char *)response.extra_data.data + - (response.data.num_entries * sizeof(struct winbindd_gr)); - for (i = 0; i < response.data.num_entries; i++) { - snprintf(result,maxlen,"%s:%s:%d:%s\n", - gr->gr_name, gr->gr_passwd, gr->gr_gid, - &members[gr->gr_mem_ofs]); - nsd_logprintf(NSD_LOG_MIN, " GETGRENT %s\n",result); - nsd_append_element(rq,NS_SUCCESS,result,strlen(result)); - gr++; - } - } - i = response.data.num_entries; - free_response(&response); - if (i < MAX_GETPWENT_USERS) - return(do_list(2,rq)); - else - return(do_list(1,rq)); + { + int entries; + + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) GETGRENT | GETGRLIST %d responses\n", + response.data.num_entries); + + if (response.data.num_entries) { + const struct winbindd_gr *gr = &response.data.gr; + const char * members; + fstring grp_name; + int i; + + gr = (struct winbindd_gr *)response.extra_data.data; + if (! gr ) { + nsd_logprintf(NSD_LOG_MIN, " no extra_data\n"); + free_response(&response); + return NSD_ERROR; + } + + members = (char *)response.extra_data.data + + (response.data.num_entries * sizeof(struct winbindd_gr)); + + for (i = 0; i < response.data.num_entries; i++) { + snprintf(grp_name, sizeof(grp_name) - 1, "%s:%s:%d:", + gr->gr_name, gr->gr_passwd, gr->gr_gid); + + nsd_append_element(rq, NS_SUCCESS, result, rlen); + nsd_append_result(rq, NS_SUCCESS, + &members[gr->gr_mem_ofs], + strlen(&members[gr->gr_mem_ofs])); + + /* Don't log the whole list, because it might be + * _really_ long and we probably don't want to clobber + * the log with it. + */ + nsd_logprintf(NSD_LOG_MIN, " %s (...)\n", grp_name); + + gr++; + } + } + + entries = response.data.num_entries; + free_response(&response); + if (entries < MAX_GETPWENT_USERS) + return(do_list(2,rq)); + else + return(do_list(1,rq)); + } + case WINBINDD_GETPWENT: - nsd_logprintf(NSD_LOG_MIN, - "callback (winbind) - %d GETPWENT responses\n", + { + int entries; + + nsd_logprintf(NSD_LOG_MIN, + "callback (winbind) GETPWENT %d responses\n", response.data.num_entries); + if (response.data.num_entries) { + struct winbindd_pw *pw = &response.data.pw; + int i; + pw = (struct winbindd_pw *)response.extra_data.data; if (! pw ) { nsd_logprintf(NSD_LOG_MIN, " no extra_data\n"); @@ -269,41 +366,46 @@ winbind_callback(nsd_file_t **rqp, int fd) return NSD_ERROR; } for (i = 0; i < response.data.num_entries; i++) { - snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s", - pw->pw_name, - pw->pw_passwd, - pw->pw_uid, - pw->pw_gid, - pw->pw_gecos, - pw->pw_dir, - pw->pw_shell); - nsd_logprintf(NSD_LOG_MIN, " GETPWENT %s\n",result); - nsd_append_element(rq,NS_SUCCESS,result,strlen(result)); + result = NULL; + rlen = asprintf(&result, "%s:%s:%d:%d:%s:%s:%s", + pw->pw_name, + pw->pw_passwd, + pw->pw_uid, + pw->pw_gid, + pw->pw_gecos, + pw->pw_dir, + pw->pw_shell); + + if (rlen != 0 && result != NULL) { + nsd_logprintf(NSD_LOG_MIN, " %s\n",result); + nsd_append_element(rq, NS_SUCCESS, result, rlen); + free(result); + } + pw++; } } - i = response.data.num_entries; + + entries = response.data.num_entries; free_response(&response); - if (i < MAX_GETPWENT_USERS) + if (entries < MAX_GETPWENT_USERS) return(do_list(2,rq)); else return(do_list(1,rq)); + } + case WINBINDD_ENDGRENT: case WINBINDD_ENDPWENT: - nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - ENDPWENT/ENDGRENT\n"); - nsd_append_element(rq,NS_SUCCESS,"\n",1); + nsd_logprintf(NSD_LOG_MIN, "callback (winbind) ENDGRENT | ENDPWENT\n"); + nsd_append_element(rq, NS_SUCCESS, "\n", 1); free_response(&response); return NSD_NEXT; + default: free_response(&response); - nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - no valid command\n"); + nsd_logprintf(NSD_LOG_MIN, "callback (winbind) invalid command %d\n", (int)rq->f_cmd_data); return NSD_NEXT; } - nsd_logprintf(NSD_LOG_MIN, "callback (winbind) %s\n", result); - /* free any extra data area in response structure */ - free_response(&response); - nsd_set_result(rq,NS_SUCCESS,result,strlen(result),VOLATILE); - return NSD_OK; } static int @@ -349,14 +451,16 @@ send_next_request(nsd_file_t *rq, struct winbindd_request *request) return NSD_NEXT; } - nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) %d to = %d\n", + nsd_logprintf(NSD_LOG_MIN, + "send_next_request (winbind) %d, timeout = %d sec\n", rq->f_cmd_data, timeout); status = winbindd_send_request((int)rq->f_cmd_data,request); SAFE_FREE(request); if (status != NSS_STATUS_SUCCESS) { nsd_logprintf(NSD_LOG_MIN, - "send_next_request (winbind) error status = %d\n",status); + "send_next_request (winbind) error status = %d\n", + status); rq->f_status = status; return NSD_NEXT; } diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c index e6c69247f85..cc904c32091 100644 --- a/source/nsswitch/winbindd.c +++ b/source/nsswitch/winbindd.c @@ -769,10 +769,14 @@ static void process_loop(void) selret = sys_select(maxfd + 1, &r_fds, &w_fds, NULL, &timeout); - if (selret == 0) + if (selret == 0) { goto no_fds_ready; + } - if ((selret == -1 && errno != EINTR) || selret == 0) { + if (selret == -1) { + if (errno == EINTR) { + goto no_fds_ready; + } /* Select error, something is badly wrong */ @@ -780,6 +784,8 @@ static void process_loop(void) exit(1); } + /* selret > 0 */ + ev = fd_events; while (ev != NULL) { struct fd_event *next = ev->next; @@ -1035,6 +1041,7 @@ int main(int argc, char **argv) /* Handle online/offline messages. */ message_register(MSG_WINBIND_OFFLINE,winbind_msg_offline); message_register(MSG_WINBIND_ONLINE,winbind_msg_online); + message_register(MSG_WINBIND_ONLINESTATUS,winbind_msg_onlinestatus); poptFreeContext(pc); diff --git a/source/nsswitch/winbindd.h b/source/nsswitch/winbindd.h index e5f1c9699ca..7d5330dccb2 100644 --- a/source/nsswitch/winbindd.h +++ b/source/nsswitch/winbindd.h @@ -33,6 +33,10 @@ #include "libnscd.h" #endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + #undef DBGC_CLASS #define DBGC_CLASS DBGC_WINBIND diff --git a/source/nsswitch/winbindd_ads.c b/source/nsswitch/winbindd_ads.c index 5e0d4cfe8e0..8259fd7cd36 100644 --- a/source/nsswitch/winbindd_ads.c +++ b/source/nsswitch/winbindd_ads.c @@ -38,6 +38,9 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) { ADS_STRUCT *ads; ADS_STATUS status; + enum wb_posix_mapping map_type; + + DEBUG(10,("ads_cached_connection\n")); if (domain->private_data) { ads = (ADS_STRUCT *)domain->private_data; @@ -125,11 +128,18 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) return NULL; } - if (use_nss_info("sfu") && (!ads_check_sfu_mapping(ads))) { - DEBUG(0,("ads_cached_connection: failed to check sfu attributes\n")); - return NULL; - } + map_type = get_nss_info(domain->name); + + if ((map_type == WB_POSIX_MAP_RFC2307)|| + (map_type == WB_POSIX_MAP_SFU)) { + status = ads_check_posix_schema_mapping(ads, map_type); + if (!ADS_ERR_OK(status)) { + DEBUG(10,("ads_check_posix_schema_mapping failed " + "with: %s\n", ads_errstr(status))); + } + } + /* set the flag that says we don't own the memory even though we do so that ads_destroy() won't destroy the structure we pass back by reference */ @@ -155,6 +165,9 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, ADS_ATTR_SFU_HOMEDIR_OID, ADS_ATTR_SFU_SHELL_OID, ADS_ATTR_SFU_GECOS_OID, + ADS_ATTR_RFC2307_HOMEDIR_OID, + ADS_ATTR_RFC2307_SHELL_OID, + ADS_ATTR_RFC2307_GECOS_OID, NULL}; int i, count; ADS_STATUS rc; @@ -173,7 +186,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, goto done; } - rc = ads_search_retry(ads, &res, "(objectClass=user)", attrs); + rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs); if (!ADS_ERR_OK(rc) || !res) { DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc))); goto done; @@ -208,13 +221,17 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, name = ads_pull_username(ads, mem_ctx, msg); - if (use_nss_info("sfu")) { + if (get_nss_info(domain->name) && ads->schema.map_type) { + + DEBUG(10,("pulling posix attributes (%s schema)\n", + wb_posix_map_str(ads->schema.map_type))); + homedir = ads_pull_string(ads, mem_ctx, msg, - ads->schema.sfu_homedir_attr); + ads->schema.posix_homedir_attr); shell = ads_pull_string(ads, mem_ctx, msg, - ads->schema.sfu_shell_attr); + ads->schema.posix_shell_attr); gecos = ads_pull_string(ads, mem_ctx, msg, - ads->schema.sfu_gecos_attr); + ads->schema.posix_gecos_attr); } if (gecos == NULL) { @@ -446,6 +463,9 @@ static NTSTATUS query_user(struct winbindd_domain *domain, ADS_ATTR_SFU_HOMEDIR_OID, ADS_ATTR_SFU_SHELL_OID, ADS_ATTR_SFU_GECOS_OID, + ADS_ATTR_RFC2307_HOMEDIR_OID, + ADS_ATTR_RFC2307_SHELL_OID, + ADS_ATTR_RFC2307_GECOS_OID, NULL}; ADS_STATUS rc; int count; @@ -484,13 +504,17 @@ static NTSTATUS query_user(struct winbindd_domain *domain, info->acct_name = ads_pull_username(ads, mem_ctx, msg); - if (use_nss_info("sfu")) { + if (get_nss_info(domain->name) && ads->schema.map_type) { + + DEBUG(10,("pulling posix attributes (%s schema)\n", + wb_posix_map_str(ads->schema.map_type))); + info->homedir = ads_pull_string(ads, mem_ctx, msg, - ads->schema.sfu_homedir_attr); + ads->schema.posix_homedir_attr); info->shell = ads_pull_string(ads, mem_ctx, msg, - ads->schema.sfu_shell_attr); + ads->schema.posix_shell_attr); info->full_name = ads_pull_string(ads, mem_ctx, msg, - ads->schema.sfu_gecos_attr); + ads->schema.posix_gecos_attr); } if (info->full_name == NULL) { @@ -518,11 +542,11 @@ done: /* Lookup groups a user is a member of - alternate method, for when tokenGroups are not available. */ -static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, - const char *user_dn, - DOM_SID *primary_group, - size_t *p_num_groups, DOM_SID **user_sids) +static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_dn, + DOM_SID *primary_group, + size_t *p_num_groups, DOM_SID **user_sids) { ADS_STATUS rc; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; @@ -535,7 +559,7 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain, char *escaped_dn; size_t num_groups = 0; - DEBUG(3,("ads: lookup_usergroups_alt\n")); + DEBUG(3,("ads: lookup_usergroups_member\n")); ads = ads_cached_connection(domain); @@ -549,10 +573,7 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain, goto done; } - /* buggy server, no tokenGroups. Instead lookup what groups this user - is a member of by DN search on member*/ - - if (!(ldap_exp = talloc_asprintf(mem_ctx, "(&(member=%s)(objectClass=group))", escaped_dn))) { + if (!(ldap_exp = talloc_asprintf(mem_ctx, "(&(member=%s)(objectCategory=group))", escaped_dn))) { DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn)); SAFE_FREE(escaped_dn); status = NT_STATUS_NO_MEMORY; @@ -585,7 +606,12 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain, DEBUG(1,("No sid for this group ?!?\n")); continue; } - + + /* ignore Builtin groups from ADS - Guenther */ + if (sid_check_is_in_builtin(&group_sid)) { + continue; + } + add_sid_to_array(mem_ctx, &group_sid, user_sids, &num_groups); } @@ -595,7 +621,7 @@ static NTSTATUS lookup_usergroups_alt(struct winbindd_domain *domain, *p_num_groups = num_groups; status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; - DEBUG(3,("ads lookup_usergroups (alt) for dn=%s\n", user_dn)); + DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn)); done: if (res) ads_msgfree(ads, res); @@ -603,6 +629,89 @@ done: return status; } +/* Lookup groups a user is a member of - alternate method, for when + tokenGroups are not available. */ +static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_dn, + DOM_SID *primary_group, + size_t *p_num_groups, DOM_SID **user_sids) +{ + ADS_STATUS rc; + NTSTATUS status = NT_STATUS_UNSUCCESSFUL; + int count; + void *res = NULL; + ADS_STRUCT *ads; + const char *attrs[] = {"memberOf", NULL}; + size_t num_groups = 0; + DOM_SID *group_sids = NULL; + int i; + + DEBUG(3,("ads: lookup_usergroups_memberof\n")); + + ads = ads_cached_connection(domain); + + if (!ads) { + domain->last_status = NT_STATUS_SERVER_DISABLED; + goto done; + } + + rc = ads_search_retry_extended_dn(ads, &res, user_dn, attrs, + ADS_EXTENDED_DN_HEX_STRING); + + if (!ADS_ERR_OK(rc) || !res) { + DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n", + user_dn, ads_errstr(rc))); + return ads_ntstatus(rc); + } + + count = ads_count_replies(ads, res); + + if (count == 0) { + status = NT_STATUS_NO_SUCH_USER; + goto done; + } + + *user_sids = NULL; + num_groups = 0; + + /* always add the primary group to the sid array */ + add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups); + + count = ads_pull_sids_from_extendeddn(ads, mem_ctx, res, "memberOf", + ADS_EXTENDED_DN_HEX_STRING, + &group_sids); + if (count == 0) { + DEBUG(1,("No memberOf for this user?!?\n")); + status = NT_STATUS_NO_MEMORY; + goto done; + } + + for (i=0; i<count; i++) { + + /* ignore Builtin groups from ADS - Guenther */ + if (sid_check_is_in_builtin(&group_sids[i])) { + continue; + } + + add_sid_to_array(mem_ctx, &group_sids[i], user_sids, + &num_groups); + + } + + *p_num_groups = num_groups; + status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; + + DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn)); +done: + TALLOC_FREE(group_sids); + if (res) + ads_msgfree(ads, res); + + return status; +} + + /* Lookup groups a user is a member of. */ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, @@ -626,6 +735,12 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, DEBUG(3,("ads: lookup_usergroups\n")); *p_num_groups = 0; + status = lookup_usergroups_cached(domain, mem_ctx, sid, + p_num_groups, user_sids); + if (NT_STATUS_IS_OK(status)) { + return NT_STATUS_OK; + } + ads = ads_cached_connection(domain); if (!ads) { @@ -634,13 +749,8 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, goto done; } - rc = ads_sid_to_dn(ads, mem_ctx, sid, &user_dn); - if (!ADS_ERR_OK(rc)) { - status = ads_ntstatus(rc); - goto done; - } + rc = ads_search_retry_sid(ads, (void**)(void *)&msg, sid, attrs); - rc = ads_search_retry_dn(ads, (void**)(void *)&msg, user_dn, attrs); if (!ADS_ERR_OK(rc)) { status = ads_ntstatus(rc); DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: %s\n", @@ -648,6 +758,15 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, goto done; } + count = ads_count_replies(ads, msg); + if (count != 1) { + status = NT_STATUS_UNSUCCESSFUL; + DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: " + "invalid number of results (count=%d)\n", + sid_to_string(sid_string, sid), count)); + goto done; + } + if (!msg) { DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", sid_to_string(sid_string, sid))); @@ -655,6 +774,12 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, goto done; } + user_dn = ads_get_dn(ads, msg); + if (user_dn == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) { DEBUG(1,("%s: No primary group for sid=%s !?\n", domain->name, sid_to_string(sid_string, sid))); @@ -671,12 +796,30 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, /* there must always be at least one group in the token, unless we are talking to a buggy Win2k server */ + + /* actually this only happens when the machine account has no read + * permissions on the tokenGroup attribute - gd */ + if (count == 0) { - status = lookup_usergroups_alt(domain, mem_ctx, user_dn, - &primary_group, - &num_groups, user_sids); - *p_num_groups = (uint32)num_groups; - return status; + + /* no tokenGroups */ + + /* lookup what groups this user is a member of by DN search on + * "memberOf" */ + + status = lookup_usergroups_memberof(domain, mem_ctx, user_dn, + &primary_group, + p_num_groups, user_sids); + if (NT_STATUS_IS_OK(status)) { + return status; + } + + /* lookup what groups this user is a member of by DN search on + * "member" */ + + return lookup_usergroups_member(domain, mem_ctx, user_dn, + &primary_group, + p_num_groups, user_sids); } *user_sids = NULL; @@ -698,7 +841,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, *p_num_groups = (uint32)num_groups; status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; - DEBUG(3,("ads lookup_usergroups for sid=%s\n", + DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n", sid_to_string(sid_string, sid))); done: return status; @@ -826,6 +969,14 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members); (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members); + if ((num_members != 0) && + ((members == NULL) || (*sid_mem == NULL) || + (*name_types == NULL) || (*names == NULL))) { + DEBUG(1, ("talloc failed\n")); + status = NT_STATUS_NO_MEMORY; + goto done; + } + for (i=0;i<num_members;i++) { uint32 name_type; char *name; diff --git a/source/nsswitch/winbindd_cache.c b/source/nsswitch/winbindd_cache.c index 76e49ee96a0..0c096352d39 100644 --- a/source/nsswitch/winbindd_cache.c +++ b/source/nsswitch/winbindd_cache.c @@ -524,6 +524,12 @@ static struct cache_entry *wcache_fetch(struct winbind_cache *cache, char *kstr; struct cache_entry *centry; + extern BOOL opt_nocache; + + if (opt_nocache) { + return NULL; + } + refresh_sequence_number(domain, False); va_start(ap, format); @@ -2095,19 +2101,14 @@ static int traverse_fn_cleanup(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) { struct cache_entry *centry; - char buf[1024]; - if (!snprintf(buf, kbuf.dsize + 1, "%s", kbuf.dptr)) { - return 1; - } - - centry = wcache_fetch_raw(buf); + centry = wcache_fetch_raw(kbuf.dptr); if (!centry) { return 0; } if (!NT_STATUS_IS_OK(centry->status)) { - DEBUG(10,("deleting centry %s\n", buf)); + DEBUG(10,("deleting centry %s\n", kbuf.dptr)); tdb_delete(the_tdb, kbuf); } @@ -2351,6 +2352,11 @@ void set_global_winbindd_state_online(void) tdb_delete_bystring(wcache->tdb, "WINBINDD_OFFLINE"); } +BOOL get_global_winbindd_state_online(void) +{ + return global_winbindd_offline_state; +} + /* the cache backend methods are exposed via this structure */ struct winbindd_methods cache_methods = { True, diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c index 9e450d9de74..6322a33c029 100644 --- a/source/nsswitch/winbindd_cm.c +++ b/source/nsswitch/winbindd_cm.c @@ -618,18 +618,11 @@ static void dcip_to_name( const char *domainname, const char *realm, if ( lp_security() == SEC_ADS ) { ADS_STRUCT *ads; - ADS_STATUS status; ads = ads_init( realm, domainname, NULL ); ads->auth.flags |= ADS_AUTH_NO_BIND; - if ( !ads_try_connect( ads, inet_ntoa(ip), LDAP_PORT ) ) { - ads_destroy( &ads ); - return; - } - - status = ads_server_info(ads); - if ( !ADS_ERR_OK(status) ) { + if ( !ads_try_connect( ads, inet_ntoa(ip) ) ) { ads_destroy( &ads ); return; } diff --git a/source/nsswitch/winbindd_cred_cache.c b/source/nsswitch/winbindd_cred_cache.c index 4c539b9b23a..5fdb79c107a 100644 --- a/source/nsswitch/winbindd_cred_cache.c +++ b/source/nsswitch/winbindd_cred_cache.c @@ -74,7 +74,25 @@ NTSTATUS remove_ccache_by_ccname(const char *ccname) if (strequal(entry->ccname, ccname)) { DLIST_REMOVE(ccache_list, entry); TALLOC_FREE(entry->event); /* unregisters events */ +#ifdef HAVE_MUNLOCK + if (entry->pass) { + size_t len = strlen(entry->pass)+1; +#ifdef DEBUG_PASSWORD + DEBUG(10,("unlocking memory: %p\n", entry->pass)); +#endif + memset(&(entry->pass), 0, len); + if ((munlock(&entry->pass, len)) == -1) { + DEBUG(0,("failed to munlock memory: %s (%d)\n", + strerror(errno), errno)); + return map_nt_error_from_unix(errno); + } +#ifdef DEBUG_PASSWORD + DEBUG(10,("munlocked memory: %p\n", entry->pass)); +#endif + } +#endif /* HAVE_MUNLOCK */ TALLOC_FREE(entry); + DEBUG(10,("remove_ccache_by_ccname: removed ccache %s\n", ccname)); return NT_STATUS_OK; } } @@ -104,7 +122,7 @@ static void krb5_ticket_refresh_handler(struct timed_event *te, if ((entry->renew_until < time(NULL)) && (entry->pass != NULL)) { - seteuid(entry->uid); + set_effective_uid(entry->uid); ret = kerberos_kinit_password_ext(entry->principal_name, entry->pass, @@ -113,8 +131,9 @@ static void krb5_ticket_refresh_handler(struct timed_event *te, &entry->renew_until, entry->ccname, False, /* no PAC required anymore */ + True, WINBINDD_PAM_AUTH_KRB5_RENEW_TIME); - seteuid(0); + gain_root_privilege(); if (ret) { DEBUG(3,("could not re-kinit: %s\n", error_message(ret))); @@ -130,13 +149,13 @@ static void krb5_ticket_refresh_handler(struct timed_event *te, goto done; } - seteuid(entry->uid); + set_effective_uid(entry->uid); ret = smb_krb5_renew_ticket(entry->ccname, entry->principal_name, entry->service, &new_start); - seteuid(0); + gain_root_privilege(); if (ret) { DEBUG(3,("could not renew tickets: %s\n", error_message(ret))); @@ -170,6 +189,7 @@ NTSTATUS add_ccache_to_list(const char *princ_name, BOOL schedule_refresh_event) { struct WINBINDD_CCACHE_ENTRY *new_entry = NULL; + struct WINBINDD_CCACHE_ENTRY *old_entry = NULL; NTSTATUS status; if ((username == NULL && sid_string == NULL && princ_name == NULL) || @@ -191,6 +211,16 @@ NTSTATUS add_ccache_to_list(const char *princ_name, return NT_STATUS_NO_MORE_ENTRIES; } + /* get rid of old entries */ + old_entry = get_ccache_by_username(username); + if (old_entry) { + status = remove_ccache_by_ccname(old_entry->ccname); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10,("add_ccache_to_list: failed to delete old ccache entry\n")); + return status; + } + } + new_entry = TALLOC_P(mem_ctx, struct WINBINDD_CCACHE_ENTRY); if (new_entry == NULL) { return NT_STATUS_NO_MEMORY; @@ -214,9 +244,31 @@ NTSTATUS add_ccache_to_list(const char *princ_name, new_entry->service = talloc_strdup(mem_ctx, service); NT_STATUS_HAVE_NO_MEMORY(new_entry->service); } - if (pass) { + + if (schedule_refresh_event && pass) { +#ifdef HAVE_MLOCK + size_t len = strlen(pass)+1; + + new_entry->pass = TALLOC_ZERO(mem_ctx, len); + NT_STATUS_HAVE_NO_MEMORY(new_entry->pass); + +#ifdef DEBUG_PASSWORD + DEBUG(10,("mlocking memory: %p\n", new_entry->pass)); +#endif + if ((mlock(new_entry->pass, len)) == -1) { + DEBUG(0,("failed to mlock memory: %s (%d)\n", + strerror(errno), errno)); + return map_nt_error_from_unix(errno); + } + +#ifdef DEBUG_PASSWORD + DEBUG(10,("mlocked memory: %p\n", new_entry->pass)); +#endif + memcpy(new_entry->pass, pass, len); +#else new_entry->pass = talloc_strdup(mem_ctx, pass); NT_STATUS_HAVE_NO_MEMORY(new_entry->pass); +#endif /* HAVE_MLOCK */ } new_entry->create_time = create_time; @@ -248,6 +300,13 @@ NTSTATUS add_ccache_to_list(const char *princ_name, NTSTATUS destroy_ccache_list(void) { +#ifdef HAVE_MUNLOCKALL + if ((munlockall()) == -1) { + DEBUG(0,("failed to unlock memory: %s (%d)\n", + strerror(errno), errno)); + return map_nt_error_from_unix(errno); + } +#endif /* HAVE_MUNLOCKALL */ return talloc_destroy(mem_ctx) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL; } diff --git a/source/nsswitch/winbindd_dual.c b/source/nsswitch/winbindd_dual.c index c5d24f98c1b..3003a314c03 100644 --- a/source/nsswitch/winbindd_dual.c +++ b/source/nsswitch/winbindd_dual.c @@ -496,6 +496,26 @@ void winbind_msg_online(int msg_type, struct process_id src, void *buf, size_t l } } +/* Forward the online/offline messages to our children. */ +void winbind_msg_onlinestatus(int msg_type, struct process_id src, void *buf, size_t len) +{ + struct winbindd_child *child; + + DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n")); + + for (child = children; child != NULL; child = child->next) { + if (child->domain && child->domain->primary) { + DEBUG(10,("winbind_msg_onlinestatus: " + "sending message to pid %u of primary domain.\n", + (unsigned int)child->pid)); + message_send_pid(pid_to_procid(child->pid), + MSG_WINBIND_ONLINESTATUS, buf, len, False); + break; + } + } +} + + static void account_lockout_policy_handler(struct timed_event *te, const struct timeval *now, void *private_data) @@ -582,6 +602,60 @@ static void child_msg_online(int msg_type, struct process_id src, void *buf, siz } } +static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx) +{ + struct winbindd_domain *domain; + char *buf = NULL; + + if ((buf = talloc_asprintf(mem_ctx, "global:%s ", + get_global_winbindd_state_online() ? + "Offline":"Online")) == NULL) { + return NULL; + } + + for (domain = domain_list(); domain; domain = domain->next) { + if ((buf = talloc_asprintf_append(buf, "%s:%s ", + domain->name, + domain->online ? + "Online":"Offline")) == NULL) { + return NULL; + } + } + + buf = talloc_asprintf_append(buf, "\n"); + + DEBUG(5,("collect_onlinestatus: %s", buf)); + + return buf; +} + +static void child_msg_onlinestatus(int msg_type, struct process_id src, void *buf, size_t len) +{ + TALLOC_CTX *mem_ctx; + const char *message; + struct process_id *sender; + + DEBUG(5,("winbind_msg_onlinestatus received.\n")); + + if (!buf) { + return; + } + + sender = (struct process_id *)buf; + + mem_ctx = talloc_init("winbind_msg_onlinestatus"); + if (mem_ctx == NULL) { + return; + } + + message = collect_onlinestatus(mem_ctx); + + message_send_pid(*sender, MSG_WINBIND_ONLINESTATUS, + message, strlen(message) + 1, True); + + talloc_destroy(mem_ctx); +} + static BOOL fork_domain_child(struct winbindd_child *child) { int fdpair[2]; @@ -646,6 +720,7 @@ static BOOL fork_domain_child(struct winbindd_child *child) message_deregister(MSG_SHUTDOWN); message_deregister(MSG_WINBIND_OFFLINE); message_deregister(MSG_WINBIND_ONLINE); + message_deregister(MSG_WINBIND_ONLINESTATUS); /* The child is ok with online/offline messages now. */ message_unblock(); @@ -667,6 +742,7 @@ static BOOL fork_domain_child(struct winbindd_child *child) /* Handle online/offline messages. */ message_register(MSG_WINBIND_OFFLINE,child_msg_offline); message_register(MSG_WINBIND_ONLINE,child_msg_online); + message_register(MSG_WINBIND_ONLINESTATUS,child_msg_onlinestatus); while (1) { diff --git a/source/nsswitch/winbindd_nss.h b/source/nsswitch/winbindd_nss.h index fe09cd8a06d..34e0d097219 100644 --- a/source/nsswitch/winbindd_nss.h +++ b/source/nsswitch/winbindd_nss.h @@ -394,7 +394,7 @@ struct WINBINDD_CCACHE_ENTRY { const char *service; const char *username; const char *sid_string; - const char *pass; + char *pass; uid_t uid; time_t create_time; time_t renew_until; diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c index 6f077294934..b02ba8e36ca 100644 --- a/source/nsswitch/winbindd_pam.c +++ b/source/nsswitch/winbindd_pam.c @@ -478,7 +478,7 @@ static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain, if (!internal_ccache) { - seteuid(uid); + set_effective_uid(uid); DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid)); } @@ -489,6 +489,7 @@ static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain, &renewal_until, cc, True, + True, WINBINDD_PAM_AUTH_KRB5_RENEW_TIME); if (krb5_ret) { @@ -532,13 +533,14 @@ static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain, } if (!internal_ccache) { - seteuid(0); + gain_root_privilege(); } /************************ NON-ROOT **********************/ result = ads_verify_ticket(state->mem_ctx, lp_realm(), + time_offset, &tkt, &client_princ_out, &pac_data, @@ -610,11 +612,16 @@ failed: krb5_ret = ads_kdestroy(cc); if (krb5_ret) { - DEBUG(0,("winbindd_raw_kerberos_login: " + DEBUG(3,("winbindd_raw_kerberos_login: " "could not destroy krb5 credential cache: " "%s\n", error_message(krb5_ret))); } + if (!NT_STATUS_IS_OK(remove_ccache_by_ccname(cc))) { + DEBUG(3,("winbindd_raw_kerberos_login: " + "could not remove ccache\n")); + } + done: data_blob_free(&session_key); data_blob_free(&session_key_krb5); @@ -624,7 +631,7 @@ done: SAFE_FREE(client_princ_out); if (!internal_ccache) { - seteuid(0); + gain_root_privilege(); } return result; @@ -1105,7 +1112,9 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain, DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result))); } - if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS)) { + if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) || + NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) || + NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) { DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n")); domain->online = False; } @@ -1644,6 +1653,9 @@ void winbindd_pam_chauthtok(struct winbindd_cli_state *state) oldpass = state->request.data.chauthtok.oldpass; newpass = state->request.data.chauthtok.newpass; + /* Initialize reject reason */ + state->response.data.auth.reject_reason = Undefined; + /* Get sam handle */ result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, @@ -1682,8 +1694,6 @@ void winbindd_pam_chauthtok(struct winbindd_cli_state *state) DEBUG(10,("Password change with chgpasswd3 failed with: %s, retrying chgpasswd_user\n", nt_errstr(result))); - state->response.data.auth.reject_reason = 0; - result = rpccli_samr_chgpasswd_user(cli, state->mem_ctx, user, newpass, oldpass); } diff --git a/source/nsswitch/winbindd_rpc.c b/source/nsswitch/winbindd_rpc.c index 4aaedad4a21..22df8d4db96 100644 --- a/source/nsswitch/winbindd_rpc.c +++ b/source/nsswitch/winbindd_rpc.c @@ -412,7 +412,6 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, unsigned int i; fstring sid_string; uint32 user_rid; - NET_USER_INFO_3 *user; struct rpc_pipe_client *cli; DEBUG(3,("rpc: lookup_usergroups sid=%s\n", @@ -425,23 +424,10 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, *user_grpsids = NULL; /* so lets see if we have a cached user_info_3 */ - - if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL ) - { - DEBUG(5,("query_user: Cache lookup succeeded for %s\n", - sid_string_static(user_sid))); - - *num_groups = user->num_groups; - - (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups); - for (i=0;i<(*num_groups);i++) { - sid_copy(&((*user_grpsids)[i]), &domain->sid); - sid_append_rid(&((*user_grpsids)[i]), - user->gids[i].g_rid); - } - - SAFE_FREE(user); - + result = lookup_usergroups_cached(domain, mem_ctx, user_sid, + num_groups, user_grpsids); + + if (NT_STATUS_IS_OK(result)) { return NT_STATUS_OK; } diff --git a/source/nsswitch/winbindd_user.c b/source/nsswitch/winbindd_user.c index 6179e497b78..07bd2a30bf7 100644 --- a/source/nsswitch/winbindd_user.c +++ b/source/nsswitch/winbindd_user.c @@ -43,7 +43,7 @@ static BOOL fillup_pw_field(const char *lp_template, if (out == NULL) return False; - if (in && !strequal(in,"") && lp_security() == SEC_ADS && use_nss_info("sfu")) { + if (in && !strequal(in,"") && lp_security() == SEC_ADS && (get_nss_info(domname))) { safe_strcpy(out, in, sizeof(fstring) - 1); return True; } diff --git a/source/nsswitch/winbindd_util.c b/source/nsswitch/winbindd_util.c index d64345a36f3..4e5075d89d0 100644 --- a/source/nsswitch/winbindd_util.c +++ b/source/nsswitch/winbindd_util.c @@ -1232,3 +1232,52 @@ void winbindd_flush_nscd_cache(void) #endif } +NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const DOM_SID *user_sid, + uint32 *p_num_groups, DOM_SID **user_sids) +{ + NET_USER_INFO_3 *info3 = NULL; + NTSTATUS status = NT_STATUS_NO_MEMORY; + int i; + size_t num_groups = 0; + DOM_SID group_sid, primary_group; + + DEBUG(3,(": lookup_usergroups_cached\n")); + + *user_sids = NULL; + num_groups = 0; + *p_num_groups = 0; + + info3 = netsamlogon_cache_get(mem_ctx, user_sid); + + if (info3 == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (info3->num_groups == 0) { + SAFE_FREE(info3); + return NT_STATUS_UNSUCCESSFUL; + } + + /* always add the primary group to the sid array */ + sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid); + + add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups); + + for (i=0; i<info3->num_groups; i++) { + sid_copy(&group_sid, &info3->dom_sid.sid); + sid_append_rid(&group_sid, info3->gids[i].g_rid); + + add_sid_to_array(mem_ctx, &group_sid, user_sids, + &num_groups); + } + + SAFE_FREE(info3); + *p_num_groups = num_groups; + status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY; + + DEBUG(3,(": lookup_usergroups_cached succeeded\n")); + + return status; +} |