29#define SOCKET_CALL "-s"
30#define DOVECOT_SERVICE "-x"
35static struct passwd *pw;
40static struct spwd *spw;
46static struct userpw *upw;
82static void exit(
int fail)
89static int dig_ascii(
char *digascii,
const char *digest,
const int len)
91 static const char hextab[] =
"0123456789abcdef";
94 for (
j = 0;
j < len;
j++) {
95 digascii[2 *
j] = hextab[digest[
j] >> 4];
96 digascii[2 *
j + 1] = hextab[digest[
j] & 0x0f];
98 digascii[2 * len] =
'\0';
103static int auth_sha1(
char *pwdhash,
char *response)
105 unsigned char digest[20];
106 unsigned char digascii[41];
108 sha1_hash(digest,response,str_len(response));
111 return str_diffn(digascii,pwdhash,40);
114static int auth_sha256(
char *pwdhash,
char *response)
116 unsigned char digest[32];
117 unsigned char digascii[65];
122 return str_diffn(digascii,pwdhash,64);
125static int auth_md5(
char *pwdhash,
char *response)
128 unsigned char digest[16];
129 unsigned char digascii[33];
136 return str_diffn(digascii,pwdhash,32);
139static int auth_hash(
char *password,
char *response)
141 switch (str_len(password)) {
142 case 32:
return auth_md5(password,response);
143 case 40:
return auth_sha1(password,response);
144 case 64:
return auth_sha256(password,response);
149static int auth_unix(
char *
user,
char* response)
157 stored = pw->pw_passwd;
161 if (errno == ETXTBSY) exit(111);
167 upw = getuserpw(
user);
169 stored = upw->upw_passwd;
171 if (errno == ETXTBSY) exit(111);
173 spw = getspnam(
user);
175 stored = spw->sp_pwdp;
177 if (errno == ETXTBSY) exit(111);
179 if (!stored || !*stored) exit(111);
180 encrypted =
crypt(response,stored);
181 if (!encrypted) exit(111);
182 r = str_diff(encrypted,stored);
185 if (r == 0 || !response) {
186 if (
prot_gid((
int) pw->pw_gid) == -1) exit(1);
187 if (
prot_uid((
int) pw->pw_uid) == -1) exit(1);
188 if (chdir(pw->pw_dir) == -1) exit(111);
194static int auth_apop(
unsigned char *password,
unsigned char *response,
unsigned char *challenge)
197 unsigned char digest[16];
198 unsigned char digascii[33];
201 MD5Update(&context,challenge,str_len(challenge));
202 MD5Update(&context,password,str_len(password));
206 return (str_diff(digascii,response));
209static int auth_cram(
unsigned char *password,
unsigned char *response,
unsigned char *challenge)
211 unsigned char digest[16];
212 unsigned char digascii[33];
214 hmac_md5(challenge,str_len(challenge),password,str_len(password),digest);
217 return (str_diff(digascii,response) && str_diff(password,response));
220static int auth_dovecot(
char *
user,
char *response,
char *socket,
char *service)
224 char *wrapper[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
229 switch (child = fork()) {
233 wrapper[i] =
"doveadm";
234 wrapper[++i] =
"auth";
235 wrapper[++i] =
"test";
238 wrapper[++i] = socket;
242 wrapper[++i] = service;
245 wrapper[++i] = response;
248 execvp(wrapper[0],wrapper);
252 if (wait_pid(&wstat,child) == -1) exit(111);
253 if (wait_crashed(wstat)) exit(111);
254 return wait_exitcode(wstat);
257static int auth_wrapper(
char *pam,
char *arg1,
char *arg2,
char *
auth,
int len)
262 char *wrapper[4] = {0, 0, 0, 0};
264 if (pipe(pi) == -1) exit(111);
265 if (pi[0] !=
FDAUTH) exit(111);
267 switch (child = fork()) {
272 if (fd_copy(
FDAUTH,pi[0]) == -1) exit(111);
279 execvp(wrapper[0],wrapper);
285 if (buffer_put(&
ba,
auth,len) == -1) exit(111);
286 if (buffer_flush(&
ba) == -1) exit(111);
289 if (wait_pid(&wstat,child) == -1) exit(111);
290 if (wait_crashed(wstat)) exit(111);
291 return wait_exitcode(wstat);
294int main(
int argc,
char *
const *argv)
301 char *authsocket = 0;
304 char *maildirname = 0;
312 if (!argv[1]) exit(2);
315 if (!argv[3]) exit(2);
316 authsocket = argv[2];
319 if (!argv[5]) exit(2);
322 if (!argv[3]) exit(2);
325 if (!argv[5]) exit(2);
326 authsocket = argv[4];
328 }
else if (argv[2]) {
329 if (case_starts(argv[2],
"mail") || case_starts(argv[2],
"mbox")) {
331 maildirname = argv[2];
341 while ((r == -1) && (errno == EINTR));
342 if (r == -1) exit(111);
345 if (buflen >=
sizeof(
authbuf)) exit(2);
350 if (i == buflen) exit(2);
352 if (i == buflen) exit(2);
354 if (i == buflen) exit(2);
356 if (i == buflen) exit(2);
359 authlen = str_len(authuser);
360 if (!stralloc_copyb(&
user,authuser,authlen)) exit(111);
362 if ((i = byte_rchr(authuser,authlen,
'@')))
363 if (i < authlen && authuser[i] ==
'@') {
366 case_lowerb(
domain,domlen);
368 if (!stralloc_copyb(&
user,authuser,i)) exit(111);
370 if (!stralloc_0(&
user)) exit(111);
371 if (!env_put(
"USER",authuser)) exit(111);
386 if (!stralloc_catb(&
disabled,authuser,authlen)) exit(111);
400 if (!authpass && domlen)
407 if (!authpass) exit(1);
409 if (str_len(authpass) == 1) {
410 switch (authpass[0]) {
411 case '?': rc = auth_unix(
user.s,response);
break;
412 case '+':
if (maildirname)
413 rc = auth_wrapper(
"checkvpw",program,maildirname,
authbuf,buflen);
415 rc = auth_wrapper(
"checkvpw",
"true",
"Maildir",
authbuf,buflen);
417 case '&':
if (maildirname)
418 rc = auth_wrapper(
"vchkpw",program,maildirname,
authbuf,buflen);
420 rc = auth_wrapper(
"vchkpw",
"true",0,
authbuf,buflen);
422 case '=': rc = auth_dovecot(authuser,response,authsocket,service);
428 switch (authpass[0]) {
429 case '%': rc = auth_hash(authpass + 1,response);
431 default:
if (maildirname) {
432 if ((rc =
auth_cram(authpass,response,challenge) == 0))
break;
433 if ((rc = auth_apop(authpass,response,challenge)) == 0) {
436 }
else rc =
auth_cram(authpass,response,challenge);
445 if (authsocket && service) pathexec(argv + 5);
446 else if (authsocket || service) pathexec(argv + 3);
447 else pathexec(argv + 1);
int constmap_init(struct constmap *cm, char *s, int len, int flagcolon)
int control_readfile(stralloc *sa, char *fn, int flagme)
int stralloc_copys(stralloc *, char const *)
int dig_ascii(char *digascii, unsigned const char *digest, const int len)
void hmac_md5(unsigned char *text, int text_len, unsigned char *key, int key_len, unsigned char *digest)
void MD5Final(unsigned char[16], MD5_CTX *)
void MD5Update(MD5_CTX *, unsigned char *, unsigned int)
char authbuf[BUFSIZE_AUTH]
struct constmap mapauthuser
void sha1_hash(char *hash, const char *data, uint32_t len)
void sha256_hash(char *hash, const char *data, size_t len)