Download | Plain Text | Line Numbers


/*
 * Copyright (c) 2016, Manuel Mausz <manuel at mausz dot at>,
 * All rights reserved.
 *
 * Some maildir specified code is copied from dovecot (dovecot.org),
 * Copyright by Timo Sirainen <tss at iki dot fi> (and others).
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
 */
 
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <vpopmail.h>
#include <vauth.h>
 
#define LOGPREFIX "USERLOOKUP: "
 
static void my_lowerit(char *s)
{
  unsigned char x;
  while ((x = *s)) {
    if (isupper(x))
      *s = tolower(x);
    ++s;
  }
}
 
struct my_email {
  char user[MAX_PW_NAME + 1];
  char domain[MAX_PW_DOMAIN + 1];
};
 
static int my_parse_email(const char *address, struct my_email *email)
{
  static char buf[MAX_BUFF] = { 0 };
  char *user, *domain;
 
  if (strlcpy(buf, address, sizeof(buf)) >= sizeof(buf))
    return -1;
  if ((domain = strchr(buf, '@')) == NULL)
    return -1;
  *domain++ = '\0';
  user = buf;
 
  my_lowerit(user);
  my_lowerit(domain);
  if (is_username_valid(user) != 0 || is_domain_valid(domain) != 0)
    return -1;
 
  if (strlcpy(email->user, user, sizeof(email->user)) >= sizeof(email->user)
      || strlcpy(email->domain, domain, sizeof(email->domain)) >= sizeof(email->domain))
    return -1;
  return 0;
}
 
int my_lookup_destination(const char *address, unsigned recursion)
{
  if (recursion >= 10) {
    (void)fprintf(stderr, LOGPREFIX "Recursion limit reached\n");
    return -1;
  }
 
  struct my_email email;
  if (my_parse_email(address, &email) != 0) {
    (void)fprintf(stderr, LOGPREFIX "Invalid email address\n");
    return -1;
  }
 
  // lookup domain and do an in-place replace in case of an alias domain
  if (vget_assign(email.domain, NULL, 0, NULL, NULL) == NULL)
    return 0;
 
  // lookup user
  struct vqpasswd *user_passwd = vauth_getpw(email.user, email.domain);
  if (user_passwd != NULL) {
    printf("SDTUSER=%s@%s\n", email.user, email.domain);
    return 0;
  }
 
  // lookup alias/forwards. bail out if no or more than one forward
  char *action, *dash, *forward = NULL;
  static char buf[MAX_ALIAS_LINE];
  action = valias_select(email.user, email.domain);
  if ((action = valias_select(email.user, email.domain)) == NULL
      && (dash = strchr(email.user, '-')) != NULL) {
    *dash = '\0';
    strcat(email.user, "-default");
    action = valias_select(email.user, email.domain);
  }
  for (; action != NULL; action = valias_select_next()) {
    if (!*action || *action == '#' || *action == '|' || *action == '.' || *action == '/')
      continue;
    if (forward != NULL) // more than one forward
      return 0;
    if (strlcpy(buf, action, sizeof(buf)) >= sizeof(buf))
      return -1;
    forward = buf;
  }
  if (forward == NULL) // no forward found
    return 0;
 
  if (*forward == '&')
    forward++;
  return my_lookup_destination(forward, ++recursion);
}
 
int main()
{
  const char *address;
  if ((address = getenv("SMTPRCPTTO")) != NULL)
    my_lookup_destination(address, 1);
 
  return 0;
}