/*
** Copyright 2001-2006 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "courier_auth_config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <pwd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "auth.h"
#include "authwait.h"
#include "authchangepwdir.h"
#include "numlib/numlib.h"
static const char rcsid[]="$Id: authsyschangepwd.c,v 1.10 2006/06/01 10:47:33 mrsam Exp $";
static int dochangepwd(struct passwd *, const char *, const char *);
int auth_syspasswd(const char *service, /* Ignored */
const char *userid, /* Generally ignored */
const char *oldpwd, /* Old password */
const char *newpwd) /* New password */
{
char *cpy=strdup(userid);
struct passwd *pwd;
int rc;
if (!cpy)
{
perror("malloc");
errno=EPERM;
return (-1);
}
if (strchr(cpy, '@'))
{
free(cpy);
errno=EINVAL;
return (-1);
}
pwd=getpwnam(cpy);
if (!pwd)
{
free(cpy);
errno=EINVAL;
return (-1);
}
rc=dochangepwd(pwd, oldpwd, newpwd);
free(cpy);
if (rc == 0)
return rc;
return (1); /* Fatal error */
}
#define EXPECT AUTHCHANGEPWDIR "/authsystem.passwd"
static int dochangepwd(struct passwd *pwd,
const char *oldpwd, const char *newpwd)
{
pid_t p, p2;
int pipefd[2];
int waitstat;
FILE *fp;
signal(SIGCHLD, SIG_DFL);
signal(SIGTERM, SIG_DFL);
if (pipe(pipefd) < 0)
{
perror("CRIT: authsyschangepwd: pipe() failed");
errno=EPERM;
return (-1);
}
p=fork();
if (p < 0)
{
close(pipefd[0]);
close(pipefd[1]);
perror("CRIT: authsyschangepwd: fork() failed");
errno=EPERM;
return (-1);
}
if (p == 0)
{
char *argv[2];
dup2(pipefd[0], 0);
close(pipefd[0]);
close(pipefd[1]);
close(1);
open("/dev/null", O_WRONLY);
dup2(1, 2);
if (pwd->pw_uid != getuid())
{
#if HAVE_SETLOGIN
#if HAVE_SETSID
if (setsid() < 0)
{
perror("setsid");
exit(1);
}
#endif
setlogin(pwd->pw_name);
#endif
libmail_changeuidgid(pwd->pw_uid, pwd->pw_gid);
}
argv[0]=EXPECT;
argv[1]=0;
execv(argv[0], argv);
perror("exec");
exit(1);
}
close(pipefd[0]);
signal(SIGPIPE, SIG_IGN);
if ((fp=fdopen(pipefd[1], "w")) == NULL)
{
perror("CRIT: authsyschangepwd: fdopen() failed");
kill(p, SIGTERM);
}
else
{
fprintf(fp, "%s\n%s\n", oldpwd, newpwd);
fclose(fp);
}
close(pipefd[1]);
while ((p2=wait(&waitstat)) != p)
{
if (p2 < 0 && errno == ECHILD)
{
perror("CRIT: authsyschangepwd: wait() failed");
errno=EPERM;
return (-1);
}
}
if (WIFEXITED(waitstat) && WEXITSTATUS(waitstat) == 0)
return (0);
errno=EPERM;
return (-1);
}
syntax highlighted by Code2HTML, v. 0.9.1