Crap from running automake again; remove when merging.
[hcoop/debian/courier-authlib.git] / authsyschangepwd.c
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
25 static const char rcsid[]="$Id: authsyschangepwd.c,v 1.10 2006/06/01 10:47:33 mrsam Exp $";
26
27 static int dochangepwd(struct passwd *, const char *, const char *);
28
29 int 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
72 static 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 }