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 | |
d9898ee8 |
25 | |
26 | static int dochangepwd(struct passwd *, const char *, const char *); |
27 | |
28 | int auth_syspasswd(const char *service, /* Ignored */ |
29 | const char *userid, /* Generally ignored */ |
30 | const char *oldpwd, /* Old password */ |
31 | const char *newpwd) /* New password */ |
32 | { |
33 | char *cpy=strdup(userid); |
34 | struct passwd *pwd; |
35 | int rc; |
36 | |
37 | if (!cpy) |
38 | { |
39 | perror("malloc"); |
40 | errno=EPERM; |
41 | return (-1); |
42 | } |
43 | |
44 | if (strchr(cpy, '@')) |
45 | { |
46 | free(cpy); |
47 | errno=EINVAL; |
48 | return (-1); |
49 | } |
50 | |
51 | pwd=getpwnam(cpy); |
52 | |
53 | if (!pwd) |
54 | { |
55 | free(cpy); |
56 | errno=EINVAL; |
57 | return (-1); |
58 | } |
59 | |
60 | rc=dochangepwd(pwd, oldpwd, newpwd); |
61 | |
62 | free(cpy); |
63 | if (rc == 0) |
64 | return rc; |
65 | |
66 | return (1); /* Fatal error */ |
67 | } |
68 | |
69 | #define EXPECT AUTHCHANGEPWDIR "/authsystem.passwd" |
70 | |
71 | static int dochangepwd(struct passwd *pwd, |
72 | const char *oldpwd, const char *newpwd) |
73 | { |
74 | pid_t p, p2; |
75 | int pipefd[2]; |
76 | int waitstat; |
77 | FILE *fp; |
78 | |
79 | signal(SIGCHLD, SIG_DFL); |
80 | signal(SIGTERM, SIG_DFL); |
81 | |
82 | if (pipe(pipefd) < 0) |
83 | { |
84 | perror("CRIT: authsyschangepwd: pipe() failed"); |
85 | errno=EPERM; |
86 | return (-1); |
87 | } |
88 | |
89 | p=fork(); |
90 | |
91 | if (p < 0) |
92 | { |
93 | close(pipefd[0]); |
94 | close(pipefd[1]); |
95 | perror("CRIT: authsyschangepwd: fork() failed"); |
96 | errno=EPERM; |
97 | return (-1); |
98 | } |
99 | |
100 | if (p == 0) |
101 | { |
102 | char *argv[2]; |
103 | |
104 | dup2(pipefd[0], 0); |
105 | close(pipefd[0]); |
106 | close(pipefd[1]); |
107 | |
108 | close(1); |
109 | open("/dev/null", O_WRONLY); |
110 | dup2(1, 2); |
111 | |
112 | if (pwd->pw_uid != getuid()) |
113 | { |
114 | #if HAVE_SETLOGIN |
115 | #if HAVE_SETSID |
116 | if (setsid() < 0) |
117 | { |
118 | perror("setsid"); |
119 | exit(1); |
120 | } |
121 | #endif |
122 | |
123 | setlogin(pwd->pw_name); |
124 | #endif |
125 | libmail_changeuidgid(pwd->pw_uid, pwd->pw_gid); |
126 | } |
127 | |
128 | argv[0]=EXPECT; |
129 | argv[1]=0; |
130 | |
131 | execv(argv[0], argv); |
132 | perror("exec"); |
133 | exit(1); |
134 | } |
135 | |
136 | close(pipefd[0]); |
137 | signal(SIGPIPE, SIG_IGN); |
138 | |
139 | if ((fp=fdopen(pipefd[1], "w")) == NULL) |
140 | { |
141 | perror("CRIT: authsyschangepwd: fdopen() failed"); |
142 | kill(p, SIGTERM); |
143 | } |
144 | else |
145 | { |
146 | fprintf(fp, "%s\n%s\n", oldpwd, newpwd); |
147 | fclose(fp); |
148 | } |
149 | close(pipefd[1]); |
150 | |
151 | while ((p2=wait(&waitstat)) != p) |
152 | { |
153 | if (p2 < 0 && errno == ECHILD) |
154 | { |
155 | perror("CRIT: authsyschangepwd: wait() failed"); |
156 | errno=EPERM; |
157 | return (-1); |
158 | } |
159 | } |
160 | |
161 | if (WIFEXITED(waitstat) && WEXITSTATUS(waitstat) == 0) |
162 | return (0); |
163 | errno=EPERM; |
164 | return (-1); |
165 | } |