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