userdb: Allow "+", ":", and "_" in usernames.
[hcoop/debian/courier-authlib.git] / authvchkpw.c
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 }