summaryrefslogtreecommitdiffstats
path: root/source/nsswitch
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2006-05-23 15:21:55 +0000
committerGerald Carter <jerry@samba.org>2006-05-23 15:21:55 +0000
commit3f7bb704a9e62e7a46a05838ec9300c2f6916c16 (patch)
treee2ca7f1b8da68d725e5359d7746f391fedcad6be /source/nsswitch
parent34b471724d1c8eb9e020fce02fc538bd0993d1c4 (diff)
downloadsamba-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.c83
-rw-r--r--source/nsswitch/pam_winbind.h2
-rw-r--r--source/nsswitch/wbinfo.c40
-rw-r--r--source/nsswitch/winbind_nss_aix.c3
-rw-r--r--source/nsswitch/winbind_nss_config.h1
-rw-r--r--source/nsswitch/winbind_nss_irix.c260
-rw-r--r--source/nsswitch/winbindd.c11
-rw-r--r--source/nsswitch/winbindd.h4
-rw-r--r--source/nsswitch/winbindd_ads.c225
-rw-r--r--source/nsswitch/winbindd_cache.c20
-rw-r--r--source/nsswitch/winbindd_cm.c9
-rw-r--r--source/nsswitch/winbindd_cred_cache.c69
-rw-r--r--source/nsswitch/winbindd_dual.c76
-rw-r--r--source/nsswitch/winbindd_nss.h2
-rw-r--r--source/nsswitch/winbindd_pam.c24
-rw-r--r--source/nsswitch/winbindd_rpc.c22
-rw-r--r--source/nsswitch/winbindd_user.c2
-rw-r--r--source/nsswitch/winbindd_util.c49
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;
+}