a8486e684a
Use the same distfile with qpopper 4.1.0.
381 lines
11 KiB
Text
381 lines
11 KiB
Text
$NetBSD: patch-ac,v 1.10 2012/03/22 14:15:32 taca Exp $
|
|
|
|
--- password/poppassd.c.orig 2011-05-30 19:13:39.000000000 +0000
|
|
+++ password/poppassd.c
|
|
@@ -171,14 +171,20 @@
|
|
/* LANMAN allows up to 14 char passwords (truncates if longer), but tacacs
|
|
only seems to allow 11. */
|
|
|
|
+#ifndef PASSWD_BINARY
|
|
#define PASSWD_BINARY "/usr/bin/passwd" /* TBD: config.h */
|
|
-#define SMBPASSWD_BINARY "/usr/bin/smbpasswd" /* TBD: config.h */
|
|
+#endif
|
|
+
|
|
+#ifndef SMBPASSWD_BINARY
|
|
+#define SMBPASSWD_BINARY "@PREFIX@/bin/smbpasswd" /* TBD: config.h */
|
|
+#endif
|
|
|
|
#include "config.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
+#include <signal.h>
|
|
|
|
#if HAVE_SYS_NETINET_IN_H
|
|
# include <sys/netinet/in.h>
|
|
@@ -251,7 +257,7 @@ int dochild (int master, char *slave
|
|
int findpty (char **slave);
|
|
void writestring (int fd, char *s);
|
|
int talktochild (int master, char *user, char *oldpass, char *newpass,
|
|
- char *emess, int asroot);
|
|
+ char *emess);
|
|
int match (char *str, char *pat);
|
|
int expect (int master, char **expected, char *buf);
|
|
void getemess (int master, char **expected, char *buf);
|
|
@@ -268,6 +274,7 @@ void get_client_info ( POP *p, BOOL n
|
|
char *sock_ntop ( struct sockaddr *p, int salen );
|
|
int sock_port ( struct sockaddr *p, int salen );
|
|
char *debug_str ( char *p, int inLen, int order );
|
|
+void reapchild (int);
|
|
|
|
|
|
/*
|
|
@@ -289,6 +296,8 @@ pop_result auth_user ( POP *p, char *pas
|
|
|
|
static char *P1[] =
|
|
{
|
|
+ "changing local password for *\nold password: ", /* BSD */
|
|
+ "old password: ", /* NetBSD>=3.0 */
|
|
"changing password for *\nold password: ", /* shadow */
|
|
"enter login password: ", /* Solaris */
|
|
"old smb password: ", /* smb */
|
|
@@ -318,6 +327,7 @@ static char *P4[] =
|
|
{
|
|
"password changed. ", /* shadow */
|
|
"password changed ", /* smb */
|
|
+ "password changed for user *\n", /* smb */
|
|
""
|
|
};
|
|
|
|
@@ -332,6 +342,8 @@ char msg_buf [ 2048 ] = ""
|
|
char *pwd_binary = PASSWD_BINARY;
|
|
char *smb_binary = SMBPASSWD_BINARY;
|
|
|
|
+int child_pid;
|
|
+int child_status;
|
|
|
|
/*
|
|
* Be careful using TRACE in an 'if' statement!
|
|
@@ -348,11 +360,13 @@ int main ( int argc, char *argv[] )
|
|
char oldpass [BUFSIZE] = "";
|
|
char newpass [BUFSIZE] = "";
|
|
int nopt = -1;
|
|
- static char options [] = "dl:p:Rs:t:vy:?";
|
|
+ static char options [] = "dhl:oPp:RSs:t:vy:";
|
|
int mode = 0;
|
|
char *ptr = NULL;
|
|
POP p;
|
|
BOOL no_rev_lookup = FALSE;
|
|
+ int compat_mode = 0;
|
|
+ BOOL bad_user = FALSE;
|
|
|
|
#ifdef HAS_SHADOW
|
|
struct spwd *spwd;
|
|
@@ -370,8 +384,6 @@ int main ( int argc, char *argv[] )
|
|
pname = ptr + 1;
|
|
}
|
|
|
|
- openlog ( pname, POP_LOGOPTS, LOG_LOCAL2 );
|
|
-
|
|
/*
|
|
* Set up some stuff in -p- so we can call Qpopper routines
|
|
*/
|
|
@@ -379,6 +391,17 @@ int main ( int argc, char *argv[] )
|
|
p.AuthType = noauth;
|
|
p.myname = pname;
|
|
|
|
+#ifndef POP_FACILITY
|
|
+# if defined(OSF1) || defined(LINUX)
|
|
+# define POP_FACILITY LOG_MAIL
|
|
+# else
|
|
+# define POP_FACILITY LOG_LOCAL0
|
|
+# endif /* OSF1 or Linux */
|
|
+#endif /* POP_FACILITY not defined */
|
|
+
|
|
+ p.log_facility = (log_facility_type) POP_FACILITY;
|
|
+ openlog ( pname, POP_LOGOPTS, p.log_facility );
|
|
+
|
|
/*
|
|
* Handle command-line options
|
|
*/
|
|
@@ -387,9 +410,9 @@ int main ( int argc, char *argv[] )
|
|
{
|
|
switch (nopt)
|
|
{
|
|
- case '?':
|
|
- fprintf ( stderr, "%s [-?] [-d] [-l 0|1|2] [-p [passd-path]] "
|
|
- "[-R] [-s [smbpasswd-path]]\n\t"
|
|
+ case 'h':
|
|
+ fprintf ( stderr, "%s [-h] [-d] [-l 0|1|2] [-p [passd-path]] "
|
|
+ "[-P] [-R] [-S] [-s [smbpasswd-path]]\n\t"
|
|
"[-t trace-file] [-v] [-y log-facility]\n",
|
|
pname );
|
|
exit (1);
|
|
@@ -406,6 +429,13 @@ int main ( int argc, char *argv[] )
|
|
verbose = TRUE;
|
|
break;
|
|
|
|
+ case 'S':
|
|
+ mode |= RUN_SMBPASSWD;
|
|
+ TRACE ( trace_file, POP_DEBUG, HERE,
|
|
+ "Changing SMB password enabled" );
|
|
+ break;
|
|
+
|
|
+
|
|
case 's':
|
|
mode |= RUN_SMBPASSWD;
|
|
if ( optarg != NULL && *optarg != '\0' )
|
|
@@ -414,6 +444,13 @@ int main ( int argc, char *argv[] )
|
|
"Changing SMB passwords using %s", smb_binary );
|
|
break;
|
|
|
|
+ case 'P':
|
|
+ mode |= RUN_PASSWD;
|
|
+ TRACE ( trace_file, POP_DEBUG, HERE,
|
|
+ "Changing standard password enabled" );
|
|
+ break;
|
|
+
|
|
+
|
|
case 'p':
|
|
mode |= RUN_PASSWD;
|
|
if ( optarg != NULL && *optarg != '\0' )
|
|
@@ -470,6 +507,10 @@ int main ( int argc, char *argv[] )
|
|
"Avoiding reverse lookups (-R)" );
|
|
break;
|
|
|
|
+ case 'o': /* compatibility mode */
|
|
+ compat_mode = 1;
|
|
+ break;
|
|
+
|
|
case 'y': /* log facility */
|
|
if ( optarg == NULL || *optarg == '\0' ) {
|
|
err_msg ( HERE, "-y value expected" );
|
|
@@ -557,44 +598,51 @@ int main ( int argc, char *argv[] )
|
|
return 1;
|
|
}
|
|
|
|
- WriteToClient ( "200 your new password please." );
|
|
- ReadFromClient ( line );
|
|
- sscanf ( line, "newpass %s", newpass );
|
|
-
|
|
- /* new pass required */
|
|
- if ( strlen (newpass) == 0 )
|
|
- {
|
|
- WriteToClient ("500 New password required.");
|
|
- return 1;
|
|
- }
|
|
-
|
|
pw = getpwnam ( userid );
|
|
if ( pw == NULL )
|
|
{
|
|
- WriteToClient ( "500 Invalid user or password" );
|
|
- return 1;
|
|
- }
|
|
+ bad_user = TRUE;
|
|
+ } else {
|
|
|
|
#ifdef HAS_SHADOW
|
|
- if ((spwd = getspnam(userid)) == NULL)
|
|
- pw->pw_passwd = "";
|
|
- else
|
|
pw->pw_passwd = spwd->sp_pwdp;
|
|
+ if ((spwd = getspnam(userid)) == NULL)
|
|
+ pw->pw_passwd = "";
|
|
+ else
|
|
+ pw->pw_passwd = spwd->sp_pwdp;
|
|
#endif
|
|
|
|
+ if ( chkPass ( userid, oldpass, pw, &p ) == FAILURE )
|
|
+ {
|
|
+ syslog ( LOG_ERR, "password failure for %s", userid );
|
|
+ bad_user = TRUE;
|
|
+ }
|
|
+
|
|
+ if ( pw->pw_uid <= BLOCK_UID )
|
|
+ {
|
|
+ syslog( LOG_ERR, "someone tried to change %s's password", userid );
|
|
+ bad_user = TRUE;
|
|
+ }
|
|
+ }
|
|
+ if (compat_mode && bad_user) {
|
|
+ sleep(1); /* XXX */
|
|
+ WriteToClient ( "500 Invalid user or password" );
|
|
+ return 1;
|
|
+ }
|
|
|
|
- if ( chkPass ( userid, oldpass, pw, &p ) == FAILURE )
|
|
- {
|
|
- syslog ( LOG_ERR, "password failure for %s", userid );
|
|
- WriteToClient ( "500 Invalid user or password" );
|
|
- return 1;
|
|
+ WriteToClient ( "200 your new password please." );
|
|
+ ReadFromClient ( line );
|
|
+ sscanf ( line, "newpass %s", newpass );
|
|
+
|
|
+ if (bad_user) {
|
|
+ WriteToClient ( "500 Invalid user or password" );
|
|
+ return 1;
|
|
}
|
|
|
|
- if ( pw->pw_uid <= BLOCK_UID )
|
|
-
|
|
- {
|
|
- syslog ( LOG_ERR, "someone tried to change %s's password", userid );
|
|
- WriteToClient ( "500 Not a user account." );
|
|
+ /* new pass required */
|
|
+ if ( strlen (newpass) == 0 )
|
|
+ {
|
|
+ WriteToClient ("500 New password required.");
|
|
return 1;
|
|
}
|
|
|
|
@@ -627,6 +675,20 @@ int main ( int argc, char *argv[] )
|
|
return 0;
|
|
}
|
|
|
|
+/* catch child */
|
|
+void
|
|
+reapchild(sig)
|
|
+ int sig;
|
|
+{
|
|
+ int status;
|
|
+ int pid;
|
|
+
|
|
+ while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
|
|
+ child_pid = pid;
|
|
+ child_status = status;
|
|
+ }
|
|
+}
|
|
+
|
|
|
|
/* Run a child process to do the password change */
|
|
|
|
@@ -647,6 +709,10 @@ void runchild ( char *userid, char *oldp
|
|
exit ( 1 );
|
|
}
|
|
|
|
+ signal(SIGCHLD, reapchild);
|
|
+ child_pid = 0;
|
|
+ child_status = -1;
|
|
+
|
|
/* fork child process to talk to password program */
|
|
|
|
pid = fork();
|
|
@@ -659,7 +725,7 @@ void runchild ( char *userid, char *oldp
|
|
|
|
if ( pid > 0 ) /* Parent */
|
|
{
|
|
- if (talktochild (master, userid, oldpass, newpass, emess, smb) == FAILURE)
|
|
+ if (talktochild (master, userid, oldpass, newpass, emess) == FAILURE)
|
|
{
|
|
logit ( trace_file, LOG_ERR, HERE,
|
|
"%s failed for %s", smb ? "smbpasswd" : "passwd", userid );
|
|
@@ -671,10 +737,16 @@ void runchild ( char *userid, char *oldp
|
|
wpid = waitpid ( pid, &wstat, 0 );
|
|
if ( wpid < 0 )
|
|
{
|
|
- logit ( trace_file, LOG_ERR, HERE, "wait for child failed" );
|
|
- WriteToClient ("500 Server error (wait failed), get help!");
|
|
- exit(1);
|
|
+ if (child_pid > 0) {
|
|
+ wpid = child_pid;
|
|
+ wstat = child_status;
|
|
+ } else {
|
|
+ logit ( trace_file, LOG_ERR, HERE, "wait for child failed" );
|
|
+ WriteToClient ("500 Server error (wait failed), get help!");
|
|
+ exit(1);
|
|
+ }
|
|
}
|
|
+ signal(SIGCHLD, SIG_DFL);
|
|
|
|
if ( pid != wpid )
|
|
{
|
|
@@ -778,6 +850,13 @@ int dochild (int master, char *slavedev,
|
|
chdir ("/");
|
|
umask (0);
|
|
|
|
+#ifdef HAVE_SETLOGIN
|
|
+ if (setlogin(userid) < 0) {
|
|
+ err_msg ( HERE, "setlogin failed: %m" );
|
|
+ return(0);
|
|
+ }
|
|
+#endif
|
|
+
|
|
/*
|
|
* Become the user and run passwd. Linux shadowed passwd doesn't need
|
|
* to be run as root with the username passed on the command line.
|
|
@@ -877,20 +956,19 @@ void writestring (int fd, char *s)
|
|
* that the password wasn't changed).
|
|
*/
|
|
int talktochild (int master, char *userid, char *oldpass, char *newpass,
|
|
- char *emess, int asroot)
|
|
+ char *emess)
|
|
{
|
|
+ int n;
|
|
char buf[BUFSIZE];
|
|
char pswd[BUFSIZE+1];
|
|
|
|
*emess = 0;
|
|
|
|
TRACE ( trace_file, POP_DEBUG, HERE,
|
|
- "talktochild; master=%d; userid=%s; asroot=%d",
|
|
- master, userid, asroot );
|
|
+ "talktochild; master=%d; userid=%s", master, userid);
|
|
|
|
/* only get current password if not root */
|
|
- if (!asroot)
|
|
- {
|
|
+ if (geteuid() == 0) {
|
|
/* wait for current password prompt */
|
|
if (!expect(master, P1, buf)) return FAILURE;
|
|
|
|
@@ -920,6 +998,10 @@ int talktochild (int master, char *useri
|
|
if ( !expect(master, P4, buf) )
|
|
TRACE ( trace_file, POP_DEBUG, HERE, "no response -- assuming OK" );
|
|
|
|
+ while ((n = read(master, buf, sizeof buf)) > 0) {
|
|
+ TRACE ( trace_file, POP_DEBUG, HERE, "reading remained output" );
|
|
+ ;
|
|
+ }
|
|
return SUCCESS;
|
|
}
|
|
|
|
@@ -949,8 +1031,12 @@ int match (char *str, char *pat)
|
|
strlen(pat), debug_str(pat, strlen(pat), 1) );
|
|
|
|
while (*str && *pat) {
|
|
- if (*pat == '*')
|
|
- break;
|
|
+ if (*pat == '*') {
|
|
+ pat++;
|
|
+ while (*str != '\0' && *str != '\n')
|
|
+ *str++;
|
|
+ continue;
|
|
+ }
|
|
|
|
/* ignore multiple space sequences */
|
|
if (*pat == ' ' && isspace (*str)) {
|
|
@@ -1049,7 +1135,11 @@ int expect (int master, char **expected,
|
|
if ( m < 0 ) {
|
|
err_msg ( HERE, "read error from child" );
|
|
return FAILURE;
|
|
- }
|
|
+ } else if (m == 0) {
|
|
+ TRACE ( trace_file, POP_DEBUG, HERE, "no data from child");
|
|
+ return FAILURE;
|
|
+ }
|
|
+
|
|
buf [ n + m ] = '\0';
|
|
|
|
TRACE ( trace_file, POP_DEBUG, HERE, "...read: (%d) '%.128s'",
|