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 | |
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 | } |