Beispiel #1
0
/* Add (flagadd=1) or remove (flagadd=0) userhost from the subscriber
 * database table. Comment is e.g. the subscriber from line or name. It
 * is added to the log. Event is the action type, e.g. "probe",
 * "manual", etc. The direction (sub/unsub) is inferred from
 * flagadd. Returns 1 on success, 0 on failure. If forcehash is >=0 it
 * is used in place of the calculated hash. This makes it possible to
 * add addresses with a hash that does not exist. forcehash has to be
 * 0..99.  For unsubscribes, the address is only removed if forcehash
 * matches the actual hash. This way, ezmlm-manage can be prevented from
 * touching certain addresses that can only be removed by
 * ezmlm-unsub. Usually, this would be used for sublist addresses (to
 * avoid removal) and sublist aliases (to prevent users from subscribing
 * them (although the cookie mechanism would prevent the resulting
 * duplicate message from being distributed. */
int sub_sql_subscribe(struct subdbinfo *info,
		      const char *table,
		      const char *userhost,
		      int flagadd,
		      const char *comment,
		      const char *event,
		      int forcehash)
{
  void *result;
  char *cpat;
  char szhash[3] = "00";

  unsigned int j;
  unsigned char ch;
  int nparams;

  make_name(info,table?"_":0,table,0);

  /* lowercase and check address */
  stralloc_copys(&addr,userhost);
  if (addr.len > 255)			/* this is 401 in std ezmlm. 255 */
					/* should be plenty! */
    strerr_die2x(100,FATAL,MSG(ERR_ADDR_LONG));
  j = byte_rchr(addr.s,addr.len,'@');
  if (j == addr.len)
    strerr_die2x(100,FATAL,MSG(ERR_ADDR_AT));
  cpat = addr.s + j;
  case_lowerb(cpat + 1,addr.len - j - 1);

  if (forcehash < 0) {
    stralloc_copy(&lcaddr,&addr);
    case_lowerb(lcaddr.s,j);		/* make all-lc version of address */
    ch = subhashsa(&lcaddr);
  } else
    ch = (forcehash % 100);

  szhash[0] = '0' + ch / 10;		/* hash for sublist split */
  szhash[1] = '0' + (ch % 10);

  if (flagadd) {
    /* FIXME: LOCK TABLES name WRITE */
    stralloc_copys(&query,"SELECT address FROM ");
    stralloc_cat(&query,&name);
    stralloc_cats(&query," WHERE ");
    stralloc_cats(&query,sql_subscribe_select_where_defn);
    stralloc_copy(&params[0],&addr);
    result = sql_select(info,&query,1,params);
    if (sql_fetch_row(info,result,1,params)) {
      sql_free_result(info,result);
      /* FIXME: UNLOCK TABLES */
      return 0;			/* already subscribed */
    } else {			/* not there */
      sql_free_result(info,result);

      stralloc_copys(&query,"INSERT INTO ");
      stralloc_cat(&query,&name);
      stralloc_cats(&query," (address,hash) VALUES ");
      stralloc_cats(&query,sql_subscribe_list_values_defn);
      stralloc_copy(&params[0],&addr);
      stralloc_copys(&params[1],szhash);
      sql_exec(info,&query,2,params);
      /* FIXME: UNLOCK TABLES */
    }
  } else {							/* unsub */
    stralloc_copys(&query,"DELETE FROM ");
    stralloc_cat(&query,&name);
    stralloc_cats(&query," WHERE ");
    stralloc_copy(&params[0],&addr);
    if (forcehash >= 0) {
      stralloc_cats(&query,sql_subscribe_delete2_where_defn);
      stralloc_copys(&params[1],szhash);
      nparams = 2;
    }
    else {
      stralloc_cats(&query,sql_subscribe_delete1_where_defn);
      nparams = 1;
    }
    if (sql_exec(info,&query,1,params) == 0)
      return 0;			/* address wasn't there*/
  }

  /* log to subscriber log */
  /* INSERT INTO t_slog (address,edir,etype,fromline) */
  /* VALUES('address',{'+'|'-'},'etype','[comment]') */

  stralloc_copys(&query,"INSERT INTO ");
  stralloc_cat(&query,&name);
  stralloc_cats(&query,"_slog (address,edir,etype,fromline) VALUES ");
  stralloc_cats(&query,sql_subscribe_slog_values_defn);
  stralloc_copy(&params[0],&addr);
  stralloc_copys(&params[1],flagadd?"+":"-"); /* edir */
  stralloc_copyb(&params[2],event+1,!!*(event+1)); /* etype */
  stralloc_copys(&params[3],comment && *comment ? comment : ""); /* from */

  sql_exec(info,&query,4,params); /* log (ignore errors) */
  stralloc_0(&addr);
  logaddr(table,event,addr.s,comment);   /* also log to old log */
  return 1;				 /* desired effect */
}
Beispiel #2
0
int std_subscribe(const char *dir,
		  const char *subdir,
		  const char *userhost,
		  int flagadd,
		  const char *comment,
		  const char *event,
		  int forcehash)
/* add (flagadd=1) or remove (flagadd=0) userhost from the subscr. database  */
/* dbname. Comment is e.g. the subscriber from line or name. It is added to  */
/* the log. Event is the action type, e.g. "probe", "manual", etc. The       */
/* direction (sub/unsub) is inferred from flagadd. Returns 1 on success, 0   */
/* on failure. If flagmysql is set and the file "sql" is found in the        */
/* directory dbname, it is parsed and a mysql db is assumed. if forcehash is */
/* >=0 it is used in place of the calculated hash. This makes it possible to */
/* add addresses with a hash that does not exist. forcehash has to be 0..99. */
/* for unsubscribes, the address is only removed if forcehash matches the    */
/* actual hash. This way, ezmlm-manage can be prevented from touching certain*/
/* addresses that can only be removed by ezmlm-unsub. Usually, this would be */
/* used for sublist addresses (to avoid removal) and sublist aliases (to     */
/* prevent users from subscribing them (although the cookie mechanism would  */
/* prevent the resulting duplicate message from being distributed. */
{
  int fdlock;

  unsigned int j;
  unsigned char ch,lcch;
  int match;
  int flagwasthere;

  if (userhost[str_chr(userhost,'\n')])
    strerr_die2x(100,FATAL,ERR_ADDR_NL);

    if (!stralloc_copys(&addr,"T")) die_nomem();
    if (!stralloc_cats(&addr,userhost)) die_nomem();
    if (addr.len > 401)
      strerr_die2x(100,FATAL,ERR_ADDR_LONG);

    j = byte_rchr(addr.s,addr.len,'@');
    if (j == addr.len)
      strerr_die2x(100,FATAL,ERR_ADDR_AT);
    case_lowerb(addr.s + j + 1,addr.len - j - 1);
    if (!stralloc_copy(&lcaddr,&addr)) die_nomem();
    case_lowerb(lcaddr.s + 1,j - 1);	/* make all-lc version of address */

    if (forcehash >= 0 && forcehash <= 52) {
      ch = lcch = 64 + (unsigned char) forcehash;
    } else {
      ch = 64 + subhashsa(&addr);
      lcch = 64 + subhashsa(&lcaddr);
    }

    if (!stralloc_0(&addr)) die_nomem();
    if (!stralloc_0(&lcaddr)) die_nomem();
    std_makepath(&fn,dir,subdir,"/subscribers/",lcch);
    std_makepath(&fnlock,dir,subdir,"/lock",0);

    if (!stralloc_copyb(&fnnew,fn.s,fn.len-1)) die_nomem();
	/* code later depends on fnnew = fn + 'n' */
    if (!stralloc_cats(&fnnew,"n")) die_nomem();
    if (!stralloc_0(&fnnew)) die_nomem();

    fdlock = lockfile(fnlock.s);

				/* do lower case hashed version first */
    fdnew = open_trunc(fnnew.s);
    if (fdnew == -1) die_write();
    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));

    flagwasthere = 0;

    fd = open_read(fn.s);
    if (fd == -1) {
      if (errno != error_noent) { close(fdnew); die_read(); }
    }
    else {
      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));

      for (;;) {
        if (getln(&ss,&line,&match,'\0') == -1) {
	  close(fd); close(fdnew); die_read();
        }
        if (!match) break;
        if (line.len == addr.len)
          if (!case_diffb(line.s,line.len,addr.s)) {
	    flagwasthere = 1;
	    if (!flagadd)
	      continue;
	  }
        if (substdio_bput(&ssnew,line.s,line.len) == -1) {
	  close(fd); close(fdnew); die_write();
        }
      }

      close(fd);
    }

    if (flagadd && !flagwasthere)
      if (substdio_bput(&ssnew,addr.s,addr.len) == -1) {
        close(fdnew); die_write();
      }

    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); }
    if (fsync(fdnew) == -1) { close(fdnew); die_write(); }
    close(fdnew);

    if (rename(fnnew.s,fn.s) == -1)
      strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": ");

    if ((ch == lcch) || flagwasthere) {
      close(fdlock);
      if (flagadd ^ flagwasthere) {
        if (!stralloc_0(&addr)) die_nomem();
        logaddr(dir,subdir,event,addr.s+1,comment);
        return 1;
      }
      return 0;
    }

			/* If unsub and not found and hashed differ, OR */
			/* sub and not found (so added with new hash) */
			/* do the 'case-dependent' hash */

    fn.s[fn.len - 2] = ch;
    fnnew.s[fnnew.len - 3] = ch;
    fdnew = open_trunc(fnnew.s);
    if (fdnew == -1) die_write();
    substdio_fdbuf(&ssnew,write,fdnew,ssnewbuf,sizeof(ssnewbuf));

    fd = open_read(fn.s);
    if (fd == -1) {
      if (errno != error_noent) { close(fdnew); die_read(); }
    } else {
      substdio_fdbuf(&ss,read,fd,ssbuf,sizeof(ssbuf));

      for (;;) {
        if (getln(&ss,&line,&match,'\0') == -1)
          { close(fd); close(fdnew); die_read(); }
        if (!match) break;
        if (line.len == addr.len)
          if (!case_diffb(line.s,line.len,addr.s)) {
            flagwasthere = 1;
            continue;	/* always want to remove from case-sensitive hash */
          }
        if (substdio_bput(&ssnew,line.s,line.len) == -1)
          { close(fd); close(fdnew); die_write(); }
      }

      close(fd);
    }

    if (substdio_flush(&ssnew) == -1) { close(fdnew); die_write(); }
    if (fsync(fdnew) == -1) { close(fdnew); die_write(); }
    close(fdnew);

    if (rename(fnnew.s,fn.s) == -1)
      strerr_die6sys(111,FATAL,ERR_MOVE,fnnew.s," to ",fn.s,": ");

    close(fdlock);
    if (flagadd ^ flagwasthere) {
      if (!stralloc_0(&addr)) die_nomem();
      logaddr(dir,subdir,event,addr.s+1,comment);
      return 1;
    }
    return 0;

}
Beispiel #3
0
/* Add (flagadd=1) or remove (flagadd=0) userhost from the subscriber
 * database table. Comment is e.g. the subscriber from line or name. It
 * is added to the log. Event is the action type, e.g. "probe",
 * "manual", etc. The direction (sub/unsub) is inferred from
 * flagadd. Returns 1 on success, 0 on failure. If forcehash is >=0 it
 * is used in place of the calculated hash. This makes it possible to
 * add addresses with a hash that does not exist. forcehash has to be
 * 0..99.  For unsubscribes, the address is only removed if forcehash
 * matches the actual hash. This way, ezmlm-manage can be prevented from
 * touching certain addresses that can only be removed by
 * ezmlm-unsub. Usually, this would be used for sublist addresses (to
 * avoid removal) and sublist aliases (to prevent users from subscribing
 * them (although the cookie mechanism would prevent the resulting
 * duplicate message from being distributed. */
static int _subscribe(struct subdbinfo *info,
                      const char *table,
                      const char *userhost,
                      int flagadd,
                      const char *comment,
                      const char *event,
                      int forcehash)
{
    sqlite3_stmt *stmt;
    char *cpat;
    char szhash[3] = "00";
    int res;

    unsigned int j;
    unsigned char ch;

    domain.len = 0;			/* clear domain */
    /* lowercase and check address */
    if (!stralloc_copys(&addr,userhost)) die_nomem();
    if (addr.len > 255)			/* this is 401 in std ezmlm. 255 */
        /* should be plenty! */
        strerr_die2x(100,FATAL,MSG(ERR_ADDR_LONG));
    j = byte_rchr(addr.s,addr.len,'@');
    if (j == addr.len)
        strerr_die2x(100,FATAL,MSG(ERR_ADDR_AT));
    cpat = addr.s + j;
    case_lowerb(cpat + 1,addr.len - j - 1);
    if (!stralloc_copy(&quoted, &addr)) die_nomem();
    /* stored unescaped, so it should be ok if quoted.len is >255, as */
    /* long as addr.len is not */

    if (forcehash < 0) {
        if (!stralloc_copy(&lcaddr,&addr)) die_nomem();
        case_lowerb(lcaddr.s,j);		/* make all-lc version of address */
        ch = subhashsa(&lcaddr);
    } else
        ch = (forcehash % 100);

    szhash[0] = '0' + ch / 10;		/* hash for sublist split */
    szhash[1] = '0' + (ch % 10);

    if (flagadd) {
        if (!stralloc_copys(&line,"SELECT address FROM ")) die_nomem();
        if (!stralloc_cat_table(&line,info,table)) die_nomem();
        if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem();
        if (!stralloc_cat(&line,&quoted)) die_nomem();	/* addr */
        if (!stralloc_cats(&line,"'")) die_nomem();
        if (!stralloc_0(&line)) die_nomem();

        if ((stmt = _sqlquery(info, &line)) == NULL)
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

        res = sqlite3_step(stmt);
        sqlite3_finalize(stmt);

        if (res == SQLITE_ROW)
            return 0;						/* there */
        else if (res != SQLITE_DONE)
        {
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));
        } else {							/* not there */
            if (!stralloc_copys(&line,"INSERT INTO ")) die_nomem();
            if (!stralloc_cat_table(&line,info,table)) die_nomem();
            if (!stralloc_cats(&line," (address,hash) VALUES ('"))
                die_nomem();
            if (!stralloc_cat(&line,&quoted)) die_nomem();	/* addr */
            if (!stralloc_cats(&line,"',")) die_nomem();
            if (!stralloc_cats(&line,szhash)) die_nomem();	/* hash */
            if (!stralloc_cats(&line,")")) die_nomem();
            if (!stralloc_0(&line)) die_nomem();

            if ((stmt = _sqlquery(info, &line)) == NULL)
                strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

            if (sqlite3_step(stmt) != SQLITE_DONE)
                strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

            sqlite3_finalize(stmt);
        }
    } else {							/* unsub */
        if (!stralloc_copys(&line,"DELETE FROM ")) die_nomem();
        if (!stralloc_cat_table(&line,info,table)) die_nomem();
        if (!stralloc_cats(&line," WHERE address LIKE '")) die_nomem();
        if (!stralloc_cat(&line,&quoted)) die_nomem();	/* addr */
        if (forcehash >= 0) {
            if (!stralloc_cats(&line,"' AND hash=")) die_nomem();
            if (!stralloc_cats(&line,szhash)) die_nomem();
        } else {
            if (!stralloc_cats(&line,"' AND hash BETWEEN 0 AND 52"))
                die_nomem();
        }

        if (!stralloc_0(&line)) die_nomem();

        if ((stmt = _sqlquery(info, &line)) == NULL)
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

        if (sqlite3_step(stmt) != SQLITE_DONE)
            strerr_die2x(111,FATAL,sqlite3_errmsg((sqlite3*)info->conn));

        sqlite3_finalize(stmt);

        if (sqlite3_changes((sqlite3*)info->conn) == 0)
            return 0;				/* address wasn't there*/
    }

    /* log to subscriber log */
    /* INSERT INTO t_slog (address,edir,etype,fromline) */
    /* VALUES('address',{'+'|'-'},'etype','[comment]') */

    if (!stralloc_copys(&logline,"INSERT INTO ")) die_nomem();
    if (!stralloc_cat_table(&logline,info,table)) die_nomem();
    if (!stralloc_cats(&logline,
                       "_slog (tai,address,edir,etype,fromline) VALUES ("))
        die_nomem();
    if (!stralloc_catb(&logline,strnum,fmt_ulong(strnum,now()))) die_nomem();
    if (!stralloc_cats(&logline,",'")) die_nomem();
    if (!stralloc_cat(&logline,&quoted)) die_nomem();
    if (flagadd) {						/* edir */
        if (!stralloc_cats(&logline,"','+','")) die_nomem();
    } else {
        if (!stralloc_cats(&logline,"','-','")) die_nomem();
    }
    if (*(event + 1))	/* ezmlm-0.53 uses '' for ezmlm-manage's work */
        if (!stralloc_catb(&logline,event+1,1)) die_nomem();	/* etype */
    if (!stralloc_cats(&logline,"','")) die_nomem();
    if (comment && *comment) {
        j = str_len(comment);
        if (!stralloc_copys(&quoted, comment)) die_nomem();	/* from */
        if (!stralloc_cat(&logline,&quoted)) die_nomem();
    }
    if (!stralloc_cats(&logline,"')")) die_nomem();
    if (!stralloc_0(&logline)) die_nomem();

    if ((stmt = _sqlquery(info, &logline)) != NULL)
    {
        sqlite3_step(stmt);			/* log (ignore errors) */
        sqlite3_finalize(stmt);
    }

    if (!stralloc_0(&addr))
        ;				/* ignore errors */
    logaddr(table,event,addr.s,comment);	/* also log to old log */
    return 1;					/* desired effect */
}