userdb: Allow "+", ":", and "_" in usernames.
[hcoop/debian/courier-authlib.git] / authvchkpw.c
CommitLineData
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
24static const char rcsid[]="$Id: authvchkpw.c,v 1.26 2007/04/22 18:53:30 mrsam Exp $";
25
26
27extern int auth_vchkpw_pre(const char *userid, const char *service,
28 int (*callback)(struct authinfo *, void *),
29 void *arg);
30
31extern FILE *authvchkpw_file(const char *, const char *);
32
33struct callback_info {
34 const char *pass;
35 int (*callback_func)(struct authinfo *, void *);
36 void *callback_arg;
37 };
38
39static int callback_vchkpw(struct authinfo *a, void *p)
40{
41struct 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
64static 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
81int 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
101static int auth_vchkpw_login(const char *service, char *authdata,
102 int (*callback_func)(struct authinfo *, void *), void *callback_arg)
103{
104char *user, *pass;
105struct callback_info ci;
106int 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
166static void authvchkpwclose()
167{
168}
169
170static int auth_vchkpw_changepass(const char *service,
171 const char *username,
172 const char *pass,
173 const char *npass)
174{
175struct vqpasswd *vpw;
176char User[256];
177char 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
224struct authstaticinfo authvchkpw_info={
225 "authvchkpw",
226 auth_vchkpw,
227 auth_vchkpw_pre,
228 authvchkpwclose,
229 auth_vchkpw_changepass,
230 authvchkpwclose,
231 NULL};
232
233
234struct authstaticinfo *courier_authvchkpw_init()
235{
236 return &authvchkpw_info;
237}