You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
475 lines
9.8 KiB
475 lines
9.8 KiB
Index: sendmail/conf.c |
|
--- sendmail/conf.c.orig 2014-11-07 19:01:17.000000000 +0100 |
|
+++ sendmail/conf.c 2015-01-03 12:26:40.869964710 +0100 |
|
@@ -524,6 +524,12 @@ |
|
ndbm_map_lookup, ndbm_map_store); |
|
#endif /* NDBM */ |
|
|
|
+#if MYSQLMAP |
|
+ MAPDEF("mysql", NULL, MCF_ALIASOK | MCF_NOTPERSIST, |
|
+ mysql_map_parseargs, mysql_map_open, mysql_map_close, |
|
+ mysql_map_lookup, null_map_store); |
|
+#endif |
|
+ |
|
#if NIS |
|
MAPDEF("nis", NULL, MCF_ALIASOK, |
|
map_parseargs, nis_map_open, null_map_close, |
|
@@ -5795,6 +5801,9 @@ |
|
#if NDBM |
|
"NDBM", |
|
#endif |
|
+#if MYSQLMAP |
|
+ "MYSQL", |
|
+#endif /* MYSQLMAP */ |
|
#if NETINET |
|
"NETINET", |
|
#endif |
|
Index: sendmail/map.c |
|
--- sendmail/map.c.orig 2014-10-21 14:55:53.000000000 +0200 |
|
+++ sendmail/map.c 2015-01-03 12:23:54.010131127 +0100 |
|
@@ -1904,12 +1904,443 @@ |
|
} |
|
|
|
#endif /* NDBM */ |
|
+ |
|
+ |
|
/* |
|
-** NEWDB (Hash and BTree) Modules |
|
+* MySQL map class for Sendmail 8.12.x |
|
+* |
|
+* (c) 2001 Igmar Palsenberg |
|
+* JDI Media Solutions |
|
+* |
|
+* MySQL can be obtained from http://www.mysql.com |
|
+* |
|
+* This version is subject to the Sendmail license. Sendmail Inc. is NOT |
|
+* responsible for this code, they don't have anything to do with it, and |
|
+* don't support it. |
|
+* |
|
+* USE AT YOUR OWN RISK. NO WARRANTY OF ANY KIND IS PROVIDED. PLEASE |
|
+* READ THE INSTRUCTIONS FOR USE OF THIS PATCH BEFORE CONTACTING THE |
|
+* AUTHOR OR SENDMAIL, INC. NO SUPPORT OF ANY KIND WILL BE PROVIDED |
|
+* BY SENDMAIL, INC. FOR THIS PATCH. |
|
+* |
|
+* Please use the sendmail_mysql@jdimedia.nl adress for questions, comments, |
|
+* remarks, etc, not my personal address. |
|
+* |
|
+* See http://projects.jdimedia.nl for a HOWTO on installing / using it. |
|
+* |
|
+*/ |
|
+#ifdef MYSQLMAP |
|
+#include <mysql/mysql.h> |
|
+ |
|
+struct mysql_conn { |
|
+ char * host; |
|
+ char * user; |
|
+ char * passwd; |
|
+ char * db; |
|
+ int port; |
|
+}; |
|
+ |
|
+static char * parse_opt_arg(char * in, char * option, char ** value) |
|
+{ |
|
+ int len = strlen(in); |
|
+ char * tmp; |
|
+ |
|
+ /* Skip whitespaces */ |
|
+ while ((*in == ' ') || (*in == '\t') && (*in != '\0')) |
|
+ in++; |
|
+ if (*in == '\0') |
|
+ return NULL; |
|
+ |
|
+ while ((*in != '-') && (*in != '"')) |
|
+ in++; |
|
+ |
|
+ /* " is an error in this case */ |
|
+ if (*in == '"') |
|
+ return NULL; |
|
+ |
|
+ in++; |
|
+ *option = *in; |
|
+ in++; |
|
+ |
|
+ while ((*in == ' ') || (*in == '\t')) |
|
+ in++; |
|
+ |
|
+ /* Not a " is an error */ |
|
+ if (*in != '"') |
|
+ return NULL; |
|
+ in++; |
|
+ |
|
+ tmp = (char *) sm_malloc(sizeof(char) * len); |
|
+ *value = tmp; |
|
+ |
|
+ while (*in != '"') |
|
+ *tmp++ = *in++; |
|
+ |
|
+ /* Null terminate */ |
|
+ *tmp = '\0'; |
|
+ in++; |
|
+ |
|
+ return in; |
|
+} |
|
+ |
|
+static char * parse_delim_arg(char * in, char delim, char ** key, char ** value) |
|
+{ |
|
+ int len = strlen(in); |
|
+ char * tmp; |
|
+ |
|
+ while ((*in == ' ') || (*in == '\t') && (*in != '\0')) |
|
+ in++; |
|
+ if (*in == '\0') |
|
+ return NULL; |
|
+ |
|
+ /* Key */ |
|
+ tmp = (char *) sm_malloc(sizeof(char) * len); |
|
+ |
|
+ *key = tmp; |
|
+ |
|
+ while ((*in != delim) && (*in != '\0') && (*in != ' ') && (*in != '\t')) |
|
+ *tmp++ = *in++; |
|
+ |
|
+ if ((*in != delim) ) { |
|
+ free(*key); |
|
+ return NULL; |
|
+ } |
|
+ *tmp = '\0'; |
|
+ in++; |
|
+ |
|
+ /* Value */ |
|
+ tmp = (char *) sm_malloc(sizeof(char) * len); |
|
+ *value = tmp; |
|
+ |
|
+ while ((*in != '\0') && (*in != ' ') && (*in != '\t')) |
|
+ *tmp++ = *in++; |
|
+ *tmp = '\0'; |
|
+ |
|
+ return in; |
|
+} |
|
+ |
|
+ |
|
+/* |
|
+* Parse MYSQL map definitions. I call it an ugly hack :) |
|
+* |
|
+* return false if failed, true if succeeded |
|
+* |
|
+* Copied from the sendmail generic map_parseargs() code |
|
*/ |
|
+bool |
|
+mysql_map_parseargs(map, args) |
|
+ MAP * map; |
|
+ char * args; |
|
+{ |
|
+ char *p = args; |
|
+ char option; |
|
+ char * value; |
|
|
|
-#if NEWDB |
|
+ map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL; |
|
+ map->map_spacesub = SpaceSub; /* default value */ |
|
+ while (p) |
|
+ { |
|
+ p = parse_opt_arg(p, &option, &value); |
|
+ if (!p) |
|
+ break; |
|
+ switch (option) |
|
+ { |
|
+ case 'N': /* Append NULL byte to all keys */ |
|
+ map->map_mflags |= MF_INCLNULL; |
|
+ map->map_mflags &= ~MF_TRY0NULL; |
|
+ break; |
|
+ |
|
+ case 'O': /* Adaptive versus never add NULL */ |
|
+ map->map_mflags &= ~MF_TRY1NULL; |
|
+ break; |
|
+ |
|
+ case 'o': /* Database file is optional */ |
|
+ map->map_mflags |= MF_OPTIONAL; |
|
+ break; |
|
+ |
|
+ case 'f': /* Don't fold keys to lowercase */ |
|
+ map->map_mflags |= MF_NOFOLDCASE; |
|
+ break; |
|
+ |
|
+ case 'm': /* Supress replacement on match */ |
|
+ map->map_mflags |= MF_MATCHONLY; |
|
+ break; |
|
+ |
|
+ case 'A': /* Append values for duplicate keys */ |
|
+ map->map_mflags |= MF_APPEND; |
|
+ break; |
|
+ |
|
+ case 'q': /* Don't strip quotes */ |
|
+ map->map_mflags |= MF_KEEPQUOTES; |
|
+ break; |
|
+ |
|
+ case 'a': /* Append tag on successful match */ |
|
+ map->map_app = value; |
|
+ value = NULL; |
|
+ break; |
|
+ |
|
+ case 'T': /* No idea */ |
|
+ map->map_tapp = value; |
|
+ value = NULL; |
|
+ break; |
|
+ |
|
+ case 'k': /* No idea */ |
|
+ map->map_keycolnm = value; |
|
+ value = NULL; |
|
+ break; |
|
+ |
|
+ case 'v': /* Specify the value's column */ |
|
+ map->map_valcolnm = value; |
|
+ value = NULL; |
|
+ break; |
|
+ |
|
+ case 'z': /* Column delimiter */ |
|
+ if (value[0] != '\\') |
|
+ map->map_coldelim = value[0]; |
|
+ else |
|
+ { |
|
+ switch (value[1]) |
|
+ { |
|
+ case 'n': |
|
+ map->map_coldelim = '\n'; |
|
+ break; |
|
+ |
|
+ case 't': |
|
+ map->map_coldelim = '\t'; |
|
+ break; |
|
+ |
|
+ default: |
|
+ map->map_coldelim = '\\'; |
|
+ } |
|
+ } |
|
+ break; |
|
+ |
|
+ case 't': /* No idea */ |
|
+ map->map_mflags |= MF_NODEFER; |
|
+ break; |
|
+ |
|
+ |
|
+ case 'S': /* No idea */ |
|
+ map->map_spacesub = value[0]; |
|
+ break; |
|
+ |
|
+ case 'D': /* No idea, I need updated docs :( */ |
|
+ map->map_mflags |= MF_DEFER; |
|
+ break; |
|
+ |
|
+ case 'c': |
|
+ map->map_keycolnm = value; |
|
+ value = NULL; |
|
+ break; |
|
+ |
|
+ case 's': |
|
+ map->map_valcolnm = value; |
|
+ value = NULL; |
|
+ break; |
|
|
|
+ default: |
|
+ syserr("mysql_map_parse_args : illegal option %c map `%s'", *p, map->map_mname); |
|
+ break; |
|
+ } |
|
+ if (value) |
|
+ sm_free(value); |
|
+ } |
|
+ if (map->map_keycolnm == NULL) { |
|
+ syserr("mysql_map_parse_args : no connect string for MySQL map `%s'", map->map_mname); |
|
+ return false; |
|
+ } |
|
+ |
|
+ if (map->map_valcolnm == NULL) { |
|
+ syserr("mysql_map_parse_args : no select statement for MySQL map `%s'", map->map_mname); |
|
+ return false; |
|
+ } |
|
+ |
|
+ return true; |
|
+} |
|
+ |
|
+static bool |
|
+mysql_map_parse_connect(char * cs, struct mysql_conn * conn, MAP * map) |
|
+{ |
|
+ char * p; |
|
+ char * key, * value; |
|
+ char * endptr; |
|
+ |
|
+ p = cs; |
|
+ |
|
+ memset(conn, '\0', sizeof(struct mysql_conn)); |
|
+ |
|
+ while (p) { |
|
+ p = parse_delim_arg(p, '=', &key, &value); |
|
+ if (!p) |
|
+ continue; |
|
+ if (strcmp(key, "host") == 0) { |
|
+ conn->host = value; |
|
+ } else if (strcmp(key, "user") == 0) { |
|
+ conn->user = value; |
|
+ } else if (strcmp(key, "passwd") == 0) { |
|
+ conn->passwd = value; |
|
+ } else if (strcmp(key, "db") == 0) { |
|
+ conn->db = value; |
|
+ } else if (strcmp(key, "port") == 0) { |
|
+ conn->port = (int) strtoul(value, &endptr, 10); |
|
+ if (*endptr != '\0') |
|
+ conn->port = 0; |
|
+ sm_free(value); |
|
+ } else { |
|
+ syserr("mysql_map_parse_connect : illegal MySQL option %s map `%s'", key, map->map_mname); |
|
+ } |
|
+ sm_free(key); |
|
+ } |
|
+ |
|
+ if ((conn->host == NULL) || (conn->user == NULL) || (conn->passwd == NULL)) |
|
+ return false; |
|
+ |
|
+ return true; |
|
+} |
|
+ |
|
+static void mysql_map_free_conn(struct mysql_conn * conn) |
|
+{ |
|
+ if (conn->host) |
|
+ sm_free(conn->host); |
|
+ if (conn->user) |
|
+ sm_free(conn->user); |
|
+ if (conn->passwd) |
|
+ sm_free(conn->passwd); |
|
+ if (conn->db) |
|
+ sm_free(conn->db); |
|
+} |
|
+ |
|
+/* |
|
+* Open connection to the MySQL server |
|
+* |
|
+* returns true if all where OK, false if something went wrong |
|
+* |
|
+*/ |
|
+bool |
|
+mysql_map_open(map, mode) |
|
+ MAP * map; |
|
+ int mode; |
|
+{ |
|
+ MYSQL * mysql; |
|
+ struct mysql_conn conn; |
|
+ |
|
+ /* Make sure newaliases doesn't rebuild it */ |
|
+ mode &= O_ACCMODE; |
|
+ |
|
+ if (mode != O_RDONLY) { |
|
+ errno = EPERM; |
|
+ return false; |
|
+ } |
|
+ |
|
+ mysql = mysql_init(NULL); |
|
+ |
|
+ if (mysql_map_parse_connect(map->map_keycolnm, &conn, map) == false) { |
|
+ syserr("mysql_map_open : cannot parse map arguments %s for map `%s'", map->map_keycolnm, map->map_mname); |
|
+ mysql_map_free_conn(&conn); |
|
+ return false; |
|
+ } |
|
+ |
|
+ if (!mysql_real_connect(mysql, conn.host, conn.user, conn.passwd, conn.db, conn.port, NULL, 0)) { |
|
+ mysql_map_free_conn(&conn); |
|
+ syserr("mysql_map_open : cannot open a MySQL connection for map `%s' : %s", map->map_mname, mysql_error(mysql)); |
|
+ return false; |
|
+ } |
|
+ mysql_map_free_conn(&conn); |
|
+ map->map_db1 = (ARBPTR_T) mysql; |
|
+ map->map_pid = getpid(); |
|
+ |
|
+ return true; |
|
+} |
|
+ |
|
+/* |
|
+* Close connection to the MYSQL database |
|
+* |
|
+* |
|
+*/ |
|
+void |
|
+mysql_map_close(map) |
|
+ MAP * map; |
|
+{ |
|
+ if (map->map_pid == getpid()) |
|
+ mysql_close(map->map_db1); |
|
+} |
|
+ |
|
+/* |
|
+* |
|
+* Do a map look up. |
|
+* |
|
+* Returns value that comes with the key |
|
+* |
|
+*/ |
|
+char * |
|
+mysql_map_lookup(map, name, av, statp) |
|
+ MAP * map; |
|
+ char * name; |
|
+ char ** av; |
|
+ int * statp; |
|
+{ |
|
+ MYSQL * mysql = (MYSQL *) map->map_db1; |
|
+ MYSQL_RES * result; |
|
+ MYSQL_ROW row; |
|
+ char * query; |
|
+ char * tmp; |
|
+ int len; |
|
+ |
|
+ len = strlen(name) + strlen(map->map_valcolnm) + 5; |
|
+ if (len > MAXNAME) |
|
+ return NULL; |
|
+ |
|
+ tmp = (char *) sm_malloc(strlen(name) + 1); |
|
+ strncpy(tmp, name, strlen(name) + 1); |
|
+ |
|
+ if (!bitset(MF_NOFOLDCASE, map->map_mflags)) |
|
+ makelower(tmp); |
|
+ |
|
+ query = (char *) sm_malloc(sizeof(char) * len); |
|
+ /* Create query */ |
|
+ snprintf(query, len, map->map_valcolnm, tmp); |
|
+ |
|
+ sm_free(tmp); |
|
+ |
|
+ /* Query and retreive rows */ |
|
+ if (mysql_real_query(mysql, query, strlen(query))) { |
|
+ syserr("mysql_map_lookup : query %s : %s", query, mysql_error(mysql)); |
|
+ sm_free(query); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ result = mysql_store_result(mysql); |
|
+ if (result == NULL) { |
|
+ syserr("mysql_map_lookup : store result : %s", mysql_error(mysql)); |
|
+ sm_free(query); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ /* 0 rows == no result */ |
|
+ if (mysql_num_rows(result) == 0) { |
|
+ sm_free(query); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ row = mysql_fetch_row(result); |
|
+ if (row[0] == NULL || strlen(row[0]) == 0) { |
|
+ sm_free(query); |
|
+ mysql_free_result(result); |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ if (bitset(MF_MATCHONLY, map->map_mflags)) |
|
+ return map_rewrite(map, name, strlen(name), NULL); |
|
+ else |
|
+ return map_rewrite(map, row[0], strlen(row[0]), av); |
|
+} |
|
+#endif /* MYSQLMAP */ |
|
+ |
|
+ |
|
+/* |
|
+** NEWDB (Hash and BTree) Modules |
|
+*/ |
|
+#if NEWDB |
|
/* |
|
** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. |
|
**
|
|
|