d9898ee8 |
1 | /* |
2 | ** Copyright 1998 - 2004 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 <errno.h> |
13 | #include <pwd.h> |
14 | #if HAVE_UNISTD_H |
15 | #include <unistd.h> |
16 | #endif |
17 | #include "auth.h" |
18 | #include "authstaticlist.h" |
19 | #include "courierauthdebug.h" |
20 | #include "vpopmail_config.h" |
21 | #include <vpopmail.h> |
22 | #include <vauth.h> |
23 | |
24 | static const char rcsid[]="$Id: authvchkpw.c,v 1.26 2007/04/22 18:53:30 mrsam Exp $"; |
25 | |
26 | |
27 | extern int auth_vchkpw_pre(const char *userid, const char *service, |
28 | int (*callback)(struct authinfo *, void *), |
29 | void *arg); |
30 | |
31 | extern FILE *authvchkpw_file(const char *, const char *); |
32 | |
33 | struct callback_info { |
34 | const char *pass; |
35 | int (*callback_func)(struct authinfo *, void *); |
36 | void *callback_arg; |
37 | }; |
38 | |
39 | static int callback_vchkpw(struct authinfo *a, void *p) |
40 | { |
41 | struct callback_info *i=(struct callback_info *)p; |
42 | |
43 | /* exit with perm failure if the supplied password is empty, |
44 | * or if the supplied password doesnt match the retrieved password */ |
45 | if (a->passwd == 0) |
46 | { |
47 | DPRINTF("no password supplied"); |
48 | return (-1); |
49 | } |
50 | |
51 | if (authcheckpassword(i->pass, a->passwd)) |
52 | return (-1); |
53 | |
54 | a->clearpasswd=i->pass; |
55 | return (*i->callback_func)(a, i->callback_arg); |
56 | } |
57 | |
58 | #if HAVE_HMACLIB |
59 | |
60 | #include "libhmac/hmac.h" |
61 | #include "cramlib.h" |
62 | |
63 | |
64 | static int auth_vchkpw_cram(const char *service, |
65 | const char *authtype, char *authdata, |
66 | int (*callback_func)(struct authinfo *, void *), |
67 | void *callback_arg) |
68 | { |
69 | struct cram_callback_info cci; |
70 | |
71 | if (auth_get_cram(authtype, authdata, &cci)) |
72 | return (-1); |
73 | |
74 | cci.callback_func=callback_func; |
75 | cci.callback_arg=callback_arg; |
76 | |
77 | return auth_vchkpw_pre(cci.user, service, &auth_cram_callback, &cci); |
78 | } |
79 | #endif |
80 | |
81 | int auth_vchkpw(const char *service, const char *authtype, char *authdata, |
82 | int (*callback_func)(struct authinfo *, void *), |
83 | void *callback_arg) |
84 | { |
85 | if (strcmp(authtype, AUTHTYPE_LOGIN) == 0) |
86 | return (auth_vchkpw_login(service, authdata, |
87 | callback_func, callback_arg)); |
88 | |
89 | #if HAVE_HMACLIB |
90 | return (auth_vchkpw_cram(service, authtype, authdata, |
91 | callback_func, callback_arg)); |
92 | #else |
93 | errno=EPERM; |
94 | return (-1); |
95 | #endif |
96 | |
97 | } |
98 | |
99 | |
100 | |
101 | static int auth_vchkpw_login(const char *service, char *authdata, |
102 | int (*callback_func)(struct authinfo *, void *), void *callback_arg) |
103 | { |
104 | char *user, *pass; |
105 | struct callback_info ci; |
106 | int rc; |
107 | /* Make sure that we have been supplied with the correct |
108 | * AUTHDATA format which is : userid<NEWLINE>password<NEWLINE> |
109 | */ |
110 | if ( (user=strtok(authdata, "\n")) == 0 || (pass=strtok(0, "\n")) == 0) |
111 | { |
112 | /* login syntax was invalid */ |
113 | errno=EPERM; |
114 | return (-1); |
115 | } |
116 | |
117 | ci.pass=pass; |
118 | ci.callback_func=callback_func; |
119 | ci.callback_arg=callback_arg; |
120 | |
121 | /* auth_vchkpw_pre() does this : |
122 | * - lookup the passwd entry for this user from the auth backend |
123 | * - check to see if this user is permitted to use this service type |
124 | * If successful it will populate the ci struct with the |
125 | * user's passwd entry. Return value of function will be 0. |
126 | * If unsuccessful (eg user doesnt exist, or is not permitted to |
127 | * use this auth method), it will return : |
128 | * <0 on a permanent failure (eg user doesnt exist) |
129 | * >0 on a temp failure |
130 | */ |
131 | rc=auth_vchkpw_pre(user, service, &callback_vchkpw, &ci); |
132 | |
133 | if (rc) |
134 | return rc; |
135 | |
136 | /* user has been successfully auth'ed at this point */ |
137 | |
138 | #if 0 |
139 | /* |
140 | ** sam - new courier-authlib never receives TCPREMOTEIP, at this |
141 | ** time. |
142 | */ |
143 | |
144 | #ifdef HAVE_OPEN_SMTP_RELAY |
145 | if ( (strcmp("pop3", service)==0) || (strcmp("imap", service)==0) ) { |
146 | /* Michael Bowe 13th August 2003 |
147 | * |
148 | * There is a problem here because open_smtp_relay needs |
149 | * to get the user's ip from getenv("TCPREMOTEIP"). |
150 | * If we run --with-authvchkpw --without-authdaemon, |
151 | * then this var is available. |
152 | * But if we run --with-authvchkpw --with-authdaemon, |
153 | * then TCPREMOTEIP is null |
154 | * |
155 | * If TCPREMOTEIP isnt available, then open_smtp_relay() |
156 | * will just return() back immediately. |
157 | */ |
158 | open_smtp_relay(); |
159 | } |
160 | #endif |
161 | #endif |
162 | |
163 | return 0; |
164 | } |
165 | |
166 | static void authvchkpwclose() |
167 | { |
168 | } |
169 | |
170 | static int auth_vchkpw_changepass(const char *service, |
171 | const char *username, |
172 | const char *pass, |
173 | const char *npass) |
174 | { |
175 | struct vqpasswd *vpw; |
176 | char User[256]; |
177 | char Domain[256]; |
178 | |
179 | /* Take the supplied userid, and split it out into the user and domain |
180 | * parts. (If a domain was not supplied, then set the domain to be |
181 | * the default domain) |
182 | */ |
183 | /* WARNING: parse_email lowercases the username in place - not const!! */ |
184 | if ( parse_email(username, User, Domain, 256) != 0) { |
185 | /* Failed to successfully extract user and domain. |
186 | * So now exit with a permanent failure code |
187 | */ |
188 | return(-1); |
189 | } |
190 | |
191 | /* check to see if domain exists. |
192 | * If you pass an alias domain to vget_assign, it will change it |
193 | * to be the real domain on return from the function |
194 | */ |
195 | if ( vget_assign(Domain,NULL,0,NULL,NULL) ==NULL ) { |
196 | /* domain doesnt exist */ |
197 | return (-1); |
198 | } |
199 | |
200 | if ( (vpw=vauth_getpw(User, Domain)) == NULL) { |
201 | /* That user doesnt exist in the auth backend */ |
202 | errno=ENOENT; |
203 | return (-1); |
204 | } |
205 | |
206 | /* Exit if any of the following : |
207 | * - user's password field in the passwd entry is empty |
208 | * - supplied current password doesnt match stored password |
209 | */ |
210 | if (vpw->pw_passwd == 0 || authcheckpassword(pass, vpw->pw_passwd)) { |
211 | errno=EPERM; |
212 | return (-1); |
213 | } |
214 | |
215 | /* save the new password into the auth backend */ |
216 | if ( vpasswd(User, Domain, (char *)npass, 0) != 0 ) { |
217 | /* password set failed */ |
218 | return (-1); |
219 | }; |
220 | |
221 | return (0); |
222 | } |
223 | |
224 | struct authstaticinfo authvchkpw_info={ |
225 | "authvchkpw", |
226 | auth_vchkpw, |
227 | auth_vchkpw_pre, |
228 | authvchkpwclose, |
229 | auth_vchkpw_changepass, |
230 | authvchkpwclose, |
231 | NULL}; |
232 | |
233 | |
234 | struct authstaticinfo *courier_authvchkpw_init() |
235 | { |
236 | return &authvchkpw_info; |
237 | } |