29#define SOCKET_CALL "-s" 
   30#define DOVECOT_SERVICE "-x" 
   33extern char *
crypt(
const char *, 
const char *);
 
   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] == 
'@') {
 
  364      domain = authuser + i;
 
  365      domlen = str_len(domain);
 
  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);
 
  392    if (!stralloc_catb(&
disabled,domain,domlen)) 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)
 
char * constmap(struct constmap *cm, char *s, int len)
 
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
 
char * crypt(const char *, const char *)
 
void sha1_hash(char *hash, const char *data, uint32_t len)
 
void sha256_hash(char *hash, const char *data, size_t len)