preauthuserdbcommon.c: Move token-getting code to below callback.
[hcoop/debian/courier-authlib.git] / authsyschangepwd.c
CommitLineData
d9898ee8 1/*
2** Copyright 2001-2006 Double Precision, Inc. See COPYING for
3** distribution information.
4*/
5
6#if HAVE_CONFIG_H
7#include "courier_auth_config.h"
8#endif
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <signal.h>
13#include <errno.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <pwd.h>
18#include <sys/types.h>
19#include <fcntl.h>
20#include "auth.h"
21#include "authwait.h"
22#include "authchangepwdir.h"
23#include "numlib/numlib.h"
24
25static const char rcsid[]="$Id: authsyschangepwd.c,v 1.10 2006/06/01 10:47:33 mrsam Exp $";
26
27static int dochangepwd(struct passwd *, const char *, const char *);
28
29int auth_syspasswd(const char *service, /* Ignored */
30 const char *userid, /* Generally ignored */
31 const char *oldpwd, /* Old password */
32 const char *newpwd) /* New password */
33{
34 char *cpy=strdup(userid);
35 struct passwd *pwd;
36 int rc;
37
38 if (!cpy)
39 {
40 perror("malloc");
41 errno=EPERM;
42 return (-1);
43 }
44
45 if (strchr(cpy, '@'))
46 {
47 free(cpy);
48 errno=EINVAL;
49 return (-1);
50 }
51
52 pwd=getpwnam(cpy);
53
54 if (!pwd)
55 {
56 free(cpy);
57 errno=EINVAL;
58 return (-1);
59 }
60
61 rc=dochangepwd(pwd, oldpwd, newpwd);
62
63 free(cpy);
64 if (rc == 0)
65 return rc;
66
67 return (1); /* Fatal error */
68}
69
70#define EXPECT AUTHCHANGEPWDIR "/authsystem.passwd"
71
72static int dochangepwd(struct passwd *pwd,
73 const char *oldpwd, const char *newpwd)
74{
75 pid_t p, p2;
76 int pipefd[2];
77 int waitstat;
78 FILE *fp;
79
80 signal(SIGCHLD, SIG_DFL);
81 signal(SIGTERM, SIG_DFL);
82
83 if (pipe(pipefd) < 0)
84 {
85 perror("CRIT: authsyschangepwd: pipe() failed");
86 errno=EPERM;
87 return (-1);
88 }
89
90 p=fork();
91
92 if (p < 0)
93 {
94 close(pipefd[0]);
95 close(pipefd[1]);
96 perror("CRIT: authsyschangepwd: fork() failed");
97 errno=EPERM;
98 return (-1);
99 }
100
101 if (p == 0)
102 {
103 char *argv[2];
104
105 dup2(pipefd[0], 0);
106 close(pipefd[0]);
107 close(pipefd[1]);
108
109 close(1);
110 open("/dev/null", O_WRONLY);
111 dup2(1, 2);
112
113 if (pwd->pw_uid != getuid())
114 {
115#if HAVE_SETLOGIN
116#if HAVE_SETSID
117 if (setsid() < 0)
118 {
119 perror("setsid");
120 exit(1);
121 }
122#endif
123
124 setlogin(pwd->pw_name);
125#endif
126 libmail_changeuidgid(pwd->pw_uid, pwd->pw_gid);
127 }
128
129 argv[0]=EXPECT;
130 argv[1]=0;
131
132 execv(argv[0], argv);
133 perror("exec");
134 exit(1);
135 }
136
137 close(pipefd[0]);
138 signal(SIGPIPE, SIG_IGN);
139
140 if ((fp=fdopen(pipefd[1], "w")) == NULL)
141 {
142 perror("CRIT: authsyschangepwd: fdopen() failed");
143 kill(p, SIGTERM);
144 }
145 else
146 {
147 fprintf(fp, "%s\n%s\n", oldpwd, newpwd);
148 fclose(fp);
149 }
150 close(pipefd[1]);
151
152 while ((p2=wait(&waitstat)) != p)
153 {
154 if (p2 < 0 && errno == ECHILD)
155 {
156 perror("CRIT: authsyschangepwd: wait() failed");
157 errno=EPERM;
158 return (-1);
159 }
160 }
161
162 if (WIFEXITED(waitstat) && WEXITSTATUS(waitstat) == 0)
163 return (0);
164 errno=EPERM;
165 return (-1);
166}