summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2001-10-02 21:58:09 +0000
committerJeremy Allison <jra@samba.org>2001-10-02 21:58:09 +0000
commitfacbdd692dc7d4b87fcc59b369ae445153146c13 (patch)
treeb0098afccb40415154002ceba82269618940b6b5
parente8547256f3d3c0e51a7715894874de36475ec131 (diff)
downloadsamba-facbdd692dc7d4b87fcc59b369ae445153146c13.tar.gz
samba-facbdd692dc7d4b87fcc59b369ae445153146c13.tar.bz2
samba-facbdd692dc7d4b87fcc59b369ae445153146c13.zip
Fixed up the change password bug when not using PAM.
The problem is we were trying to use mask_match as a generic wildcard matcher for UNIX strings (like the password prompts). We can't do that - we need a unix_wild_match (re-added into lib/util.c) as the ms_fnmatch semantics for empty strings are completely wrong. This caused partial reads to be accepted as correct passwd change responses when they were not.... Also added paranioa test to stop passwd change being done as root with no %u in the passwd program string. Jeremy. (This used to be commit 9333bbeb7627c8b21a3eaeae1683c34e17d14bf0)
-rw-r--r--source3/auth/pampass.c4
-rw-r--r--source3/lib/util.c120
-rw-r--r--source3/passdb/pampass.c4
-rw-r--r--source3/smbd/chgpasswd.c48
4 files changed, 152 insertions, 24 deletions
diff --git a/source3/auth/pampass.c b/source3/auth/pampass.c
index 6d0dabcd9d..0c7c4f1291 100644
--- a/source3/auth/pampass.c
+++ b/source3/auth/pampass.c
@@ -306,7 +306,7 @@ static int smb_pam_passchange_conv(int num_msg,
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",
t->prompt, current_prompt ));
- if (wild_match(t->prompt, current_prompt) == 0) {
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
fstrcpy(current_reply, t->reply);
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));
pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
@@ -337,7 +337,7 @@ static int smb_pam_passchange_conv(int num_msg,
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",
t->prompt, current_prompt ));
- if (wild_match(t->prompt, current_prompt) == 0) {
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
fstrcpy(current_reply, t->reply);
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));
pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 7fbdb44b4a..ce39bb3b1d 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -3,6 +3,7 @@
Version 1.9.
Samba utility functions
Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 2001
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1756,19 +1757,130 @@ BOOL mask_match(char *string, char *pattern, BOOL is_case_sensitive)
return ms_fnmatch(p2, s2, Protocol) == 0;
}
+/*********************************************************
+ Recursive routine that is called by unix_wild_match.
+*********************************************************/
+
+static BOOL unix_do_match(char *regexp, char *str)
+{
+ char *p;
+
+ for( p = regexp; *p && *str; ) {
+
+ switch(*p) {
+ case '?':
+ str++;
+ p++;
+ break;
+
+ case '*':
+
+ /*
+ * Look for a character matching
+ * the one after the '*'.
+ */
+ p++;
+ if(!*p)
+ return True; /* Automatic match */
+ while(*str) {
+
+ while(*str && (*p != *str))
+ str++;
+
+ /*
+ * Patch from weidel@multichart.de. In the case of the regexp
+ * '*XX*' we want to ensure there are at least 2 'X' characters
+ * in the string after the '*' for a match to be made.
+ */
+
+ {
+ int matchcount=0;
+
+ /*
+ * Eat all the characters that match, but count how many there were.
+ */
+
+ while(*str && (*p == *str)) {
+ str++;
+ matchcount++;
+ }
+
+ /*
+ * Now check that if the regexp had n identical characters that
+ * matchcount had at least that many matches.
+ */
+
+ while ( *(p+1) && (*(p+1) == *p)) {
+ p++;
+ matchcount--;
+ }
+
+ if ( matchcount <= 0 )
+ return False;
+ }
+
+ str--; /* We've eaten the match char after the '*' */
+
+ if(unix_do_match(p, str))
+ return True;
+
+ if(!*str)
+ return False;
+ else
+ str++;
+ }
+ return False;
+
+ default:
+ if(*str != *p)
+ return False;
+ str++;
+ p++;
+ break;
+ }
+ }
+
+ if(!*p && !*str)
+ return True;
+
+ if (!*p && str[0] == '.' && str[1] == 0)
+ return(True);
+
+ if (!*str && *p == '?') {
+ while (*p == '?')
+ p++;
+ return(!*p);
+ }
+
+ if(!*str && (*p == '*' && p[1] == '\0'))
+ return True;
+
+ return False;
+}
+
/*******************************************************************
- Simple case insensitive interface to ms_fnmatch.
+ Simple case insensitive interface to a UNIX wildcard matcher.
*******************************************************************/
-
-BOOL wild_match(char *string, char *pattern)
+
+BOOL unix_wild_match(char *pattern, char *string)
{
pstring p2, s2;
+ char *p;
pstrcpy(p2, pattern);
pstrcpy(s2, string);
strlower(p2);
strlower(s2);
- return ms_fnmatch(p2, s2, Protocol) == 0;
+
+ /* Remove any *? and ** from the pattern as they are meaningless */
+ for(p = p2; *p; p++)
+ while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
+ pstrcpy( &p[1], &p[2]);
+
+ if (strequal(p2,"*"))
+ return True;
+
+ return unix_do_match(p2, s2) == 0;
}
#ifdef __INSURE__
diff --git a/source3/passdb/pampass.c b/source3/passdb/pampass.c
index 6d0dabcd9d..0c7c4f1291 100644
--- a/source3/passdb/pampass.c
+++ b/source3/passdb/pampass.c
@@ -306,7 +306,7 @@ static int smb_pam_passchange_conv(int num_msg,
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: trying to match |%s| to |%s|\n",
t->prompt, current_prompt ));
- if (wild_match(t->prompt, current_prompt) == 0) {
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
fstrcpy(current_reply, t->reply);
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_ON: We sent: %s\n", current_reply));
pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
@@ -337,7 +337,7 @@ static int smb_pam_passchange_conv(int num_msg,
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: trying to match |%s| to |%s|\n",
t->prompt, current_prompt ));
- if (wild_match(t->prompt, current_prompt) == 0) {
+ if (unix_wild_match(t->prompt, current_prompt) == 0) {
fstrcpy(current_reply, t->reply);
DEBUG(10,("smb_pam_passchange_conv: PAM_PROMPT_ECHO_OFF: We sent: %s\n", current_reply));
pwd_sub(current_reply, udp->PAM_username, udp->PAM_password, udp->PAM_newpassword);
diff --git a/source3/smbd/chgpasswd.c b/source3/smbd/chgpasswd.c
index fbcefd6128..d2ee2f46fa 100644
--- a/source3/smbd/chgpasswd.c
+++ b/source3/smbd/chgpasswd.c
@@ -199,7 +199,7 @@ static int dochild(int master, char *slavedev, char *name,
}
stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
stermios.c_lflag |= ICANON;
- stermios.c_oflag &= ~(ONLCR);
+ stermios.c_oflag &= ~(ONLCR);
if (tcsetattr(0, TCSANOW, &stermios) < 0)
{
DEBUG(3, ("could not set attributes of pty\n"));
@@ -231,14 +231,15 @@ static int expect(int master, char *issue, char *expected)
int attempts, timeout, nread, len;
BOOL match = False;
- for (attempts = 0; attempts < 2; attempts++)
- {
- if (!strequal(issue, "."))
- {
+ for (attempts = 0; attempts < 2; attempts++) {
+ if (!strequal(issue, ".")) {
if (lp_passwd_chat_debug())
DEBUG(100, ("expect: sending [%s]\n", issue));
- write(master, issue, strlen(issue));
+ if ((len = write(master, issue, strlen(issue))) != strlen(issue)) {
+ DEBUG(2,("expect: (short) write returned %d\n", len ));
+ return False;
+ }
}
if (strequal(expected, "."))
@@ -250,29 +251,35 @@ static int expect(int master, char *issue, char *expected)
while ((len = read_with_timeout(master, buffer + nread, 1,
sizeof(buffer) - nread - 1,
- timeout)) > 0)
- {
+ timeout)) > 0) {
nread += len;
buffer[nread] = 0;
- if ((match = (wild_match(expected, buffer) == 0)))
- timeout = 200;
+ {
+ /* Eat leading/trailing whitespace before match. */
+ pstring str;
+ pstrcpy( str, buffer);
+ trim_string( str, " ", " ");
+
+ if ((match = (unix_wild_match(expected, str) == 0)))
+ timeout = 200;
+ }
}
if (lp_passwd_chat_debug())
- DEBUG(100, ("expect: expected [%s] received [%s]\n",
- expected, buffer));
+ DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
+ expected, buffer, match ? "yes" : "no" ));
if (match)
break;
- if (len < 0)
- {
+ if (len < 0) {
DEBUG(2, ("expect: %s\n", strerror(errno)));
return False;
}
}
+ DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
return match;
}
@@ -519,15 +526,24 @@ BOOL chgpasswd(char *name, char *oldpass, char *newpass, BOOL as_root)
pstrcpy(chatsequence, lp_passwd_chat());
if (!*chatsequence) {
- DEBUG(2, ("Null chat sequence - no password changing\n"));
+ DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
return (False);
}
if (!*passwordprogram) {
- DEBUG(2, ("Null password program - no password changing\n"));
+ DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
return (False);
}
+ if (as_root) {
+ /* The password program *must* contain the user name to work. Fail if not. */
+ if (strstr(passwordprogram, "%u") == NULL) {
+ DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
+the string %%u, and the given string %s does not.\n", passwordprogram ));
+ return False;
+ }
+ }
+
pstring_sub(passwordprogram, "%u", name);
/* note that we do NOT substitute the %o and %n in the password program
as this would open up a security hole where the user could use