]> git.pld-linux.org Git - packages/postfix.git/blame - postfix-pgsql.patch
- cosmetic
[packages/postfix.git] / postfix-pgsql.patch
CommitLineData
f512ae96
JB
1diff -rU3 --new-file postfix-1.1.3-vanilla/PGSQL_README postfix-1.1.3/PGSQL_README
2--- postfix-1.1.3-vanilla/PGSQL_README Thu Jan 1 01:00:00 1970
3+++ postfix-1.1.3/PGSQL_README Thu Mar 7 11:48:40 2002
4@@ -0,0 +1,88 @@
5+[Code contributed by Mathieu Arnold]
6+
7+We've written code to add a pgsql map type. It utilizes the pgsql
8+client library, which can be obtained from:
9+
10+ http://www.postgresql.org/
11+
12+In order to build postfix with pgsql map support, you will need to add
13+-DHAS_PGSQL and -I for the directory containing the postgres headers, and
14+the libpq library (and libcrypt) to AUXLIBS, for example:
15+
16+make -f Makefile.init makefiles \
17+ 'CCARGS=-DHAS_PGSQL -I/some/where/include/postgresql' \
18+ 'AUXLIBS=/some/where/lib/postgres/libpq.a -lcrypt'
19+
20+then, just run 'make'.
21+
22+Postfix installations which may benefit from using pgsql map types
23+include sites that have a need for instantaneous updates of
24+forwarding, and sites that may benefit from having mail exchangers
25+reference a networked database, possibly working in conjunction with a
26+customer database of sorts.
27+
28+Once postfix is built with pgsql support, you can specify a map type
29+in main.cf like this:
30+
31+alias_maps = pgsql:/etc/postfix/pgsql-aliases.cf
32+
33+The file /etc/postfix/pgsql-aliases.cf specifies lots of information
34+telling postfix how to reference the postgresql database. An example
35+postgresql map config file follows:
36+
37+#
38+# postgresql config file for alias lookups on postfix
39+# comments are ok.
40+#
41+
42+# the user name and password to log into the pgsql server
43+user = someone
44+password = some_passwordd
45+
46+# the database name on the servers
47+dbname = customer_database
48+
49+# the table name
50+table = mxaliases
51+
52+#
53+select_field = forw_addr
54+where_field = alias
55+
56+# you may specify additional_conditions here
57+additional_conditions = and status = 'paid'
58+
59+# the above variables will result in a query of
60+# the form:
61+# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
62+# ($lookup is escaped so if it contains single quotes or other odd
63+# characters, it will not cause a parse error in the sql).
64+#
65+# the hosts that postfix will try to connect to
66+# and query from (in the order listed)
67+hosts = host1.some.domain host2.some.domain
68+
69+# end postgresql config file
70+
71+Some notes:
72+
73+This configuration interface setup allows for multiple postgresql
74+databases: you can use one for a virtual table, one for an access
75+table, and one for an aliases table if you want.
76+
77+Since sites that have a need for multiple mail exchangers may enjoy
78+the convenience of using a networked mailer database, but do not want
79+to introduce a single point of failure to their system, we've included
80+the ability to have postfix reference multiple hosts for access to a
81+single pgsql map. This will work if sites set up mirrored pgsql
82+databases on two or more hosts. Whenever queries fail with an error
83+at one host, the rest of the hosts will be tried in order. Each host
84+that is in an error state will undergo a reconnection attempt every so
85+often, and if no pgsql server hosts are reachable, then mail will be
86+deferred until atleast one of those hosts is reachable.
87+
88+Performance of postfix with pgsql has not been thoroughly tested,
89+however, we have found it to be stable. Busy mail servers using pgsql
90+maps will generate lots of concurrent pgsql clients, so the pgsql
91+server(s) should be run with this fact in mind. Any further
92+performance information, in addition to any feedback is most welcome.
93diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/Makefile.in postfix-1.1.3/src/util/Makefile.in
94--- postfix-1.1.3-vanilla/src/util/Makefile.in Thu Mar 7 11:47:44 2002
95+++ postfix-1.1.3/src/util/Makefile.in Thu Mar 7 12:10:56 2002
96@@ -4,7 +4,7 @@
97 chroot_uid.c clean_env.c close_on_exec.c concatenate.c ctable.c \
98 dict.c dict_alloc.c dict_db.c dict_dbm.c dict_debug.c dict_env.c \
99 dict_ht.c dict_mysql.c dict_ni.c dict_nis.c \
100- dict_nisplus.c dict_open.c dict_pcre.c dict_regexp.c dict_static.c \
101+ dict_nisplus.c dict_open.c dict_pcre.c dict_pgsql.c dict_regexp.c dict_static.c \
102 dict_tcp.c dict_unix.c dir_forest.c doze.c duplex_pipe.c \
103 environ.c events.c exec_command.c fifo_listen.c fifo_trigger.c \
104 file_limit.c find_inet.c fsspace.c fullname.c get_domainname.c \
105@@ -58,7 +58,7 @@
106 HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
107 connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
108 dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
109- dict_nisplus.h dict_pcre.h dict_regexp.h dict_static.h dict_tcp.h \
110+ dict_nisplus.h dict_pcre.h dict_pgsql.h dict_regexp.h dict_static.h dict_tcp.h \
111 dict_unix.h dir_forest.h events.h exec_command.h find_inet.h \
112 fsspace.h fullname.h get_domainname.h get_hostname.h get_port.h hex_quote.h \
113 htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \
114@@ -84,6 +84,7 @@
115 INCL =
116 PCRESO = dict_pcre.so
117 MYSQLSO = dict_mysql.so
118+PGSQLSO = dict_pgsql.so
119 LIB = libutil.a
120 TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
121 fifo_rdonly_bug fifo_rdwr_bug fifo_trigger fsspace fullname \
122@@ -96,7 +97,7 @@
123
124 LIB_DIR = ../../lib
125 INC_DIR = ../../include
126-LIBS = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO)
127+LIBS = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO) $(LIB_DIR)/$(PGSQLSO)
128
129 .c.o:; $(CC) -fPIC $(CFLAGS) -c $*.c
130
131@@ -113,6 +114,9 @@
132 $(MYSQLSO): dict_mysql.o
133 gcc -shared -Wl,-soname,dict_mysql.so -o $@ $? -lmysqlclient -L. -lutil
134
135+$(PGSQLSO): dict_pgsql.o
136+ gcc -shared -Wl,-soname,dict_pgsql.so -o $@ $? -lpq -lcrypt -L. -lutil
137+
138 $(LIB): $(OBJS)
139 gcc -shared -Wl,-soname,libpostfix-util.so.1 -o $(LIB) $(OBJS) -ldl
140
141@@ -125,6 +129,9 @@
142 $(LIB_DIR)/$(MYSQLSO): $(MYSQLSO)
143 cp $(MYSQLSO) $(LIB_DIR)
144
145+$(LIB_DIR)/$(PGSQLSO): $(PGSQLSO)
146+ cp $(PGSQLSO) $(LIB_DIR)
147+
148 update: $(LIBS) $(HDRS)
149 -for i in $(HDRS); \
150 do \
151@@ -147,7 +154,7 @@
152 lint $(SRCS)
153
154 clean:
155- rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) *core $(TESTPROG) \
156+ rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) $(PGSQLSO) *core $(TESTPROG) \
157 junk $(MAKES) *.tmp
158 rm -rf printfck
159
160@@ -571,6 +578,8 @@
161 dict_ldap.o: sys_defs.h
162 dict_mysql.o: dict_mysql.c
163 dict_mysql.o: sys_defs.h
164+dict_pgsql.o: dict_pgsql.c
165+dict_pgsql.o: sys_defs.h
166 dict_ni.o: dict_ni.c
167 dict_ni.o: sys_defs.h
168 dict_nis.o: dict_nis.c
169@@ -612,6 +621,7 @@
170 dict_open.o: dict_ni.h
171 dict_open.o: dict_ldap.h
172 dict_open.o: dict_mysql.h
173+dict_open.o: dict_pgsql.h
174 dict_open.o: dict_pcre.h
175 dict_open.o: dict_regexp.h
176 dict_open.o: dict_static.h
177diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_open.c postfix-1.1.3/src/util/dict_open.c
178--- postfix-1.1.3-vanilla/src/util/dict_open.c Thu Mar 7 11:47:44 2002
179+++ postfix-1.1.3/src/util/dict_open.c Thu Mar 7 11:48:40 2002
180@@ -170,6 +170,7 @@
181 #include <dict_ni.h>
182 #include <dict_ldap.h>
183 #include <dict_mysql.h>
184+#include <dict_pgsql.h>
185 #include <dict_pcre.h>
186 #include <dict_regexp.h>
187 #include <dict_static.h>
188@@ -223,6 +224,9 @@
189 #ifdef HAS_MYSQL
190 DICT_TYPE_MYSQL, dict_mysql_open,
191 #endif
192+#ifdef HAS_PGSQL
193+ DICT_TYPE_PGSQL, dict_pgsql_open,
194+#endif
195 #ifdef HAS_PCRE
196 DICT_TYPE_PCRE, dict_pcre_open,
197 #endif
198diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_pgsql.c postfix-1.1.3/src/util/dict_pgsql.c
199--- postfix-1.1.3-vanilla/src/util/dict_pgsql.c Thu Jan 1 01:00:00 1970
200+++ postfix-1.1.3/src/util/dict_pgsql.c Thu Mar 7 11:48:41 2002
201@@ -0,0 +1,675 @@
202+
203+/*++
204+/* NAME
205+/* dict_pgsql 3
206+/* SUMMARY
207+/* dictionary manager interface to db files
208+/* SYNOPSIS
209+/* #include <dict.h>
210+/* #include <dict_pgsql.h>
211+/*
212+/* DICT *dict_pgsql_open(name, dummy, unused_dict_flags)
213+/* const char *name;
214+/* int dummy;
215+/* int unused_dict_flags;
216+/* DESCRIPTION
217+/* dict_pgsql_open() creates a dictionary of type 'pg'. This
218+/* dictionary is an interface for the postfix key->value mappings
219+/* to pgsql. The result is a pointer to the installed dictionary,
220+/* or a null pointer in case of problems.
221+/*
222+/* The pgsql dictionary can manage multiple connections to different
223+/* sql servers on different hosts. It assumes that the underlying data
224+/* on each host is identical (mirrored) and maintains one connection
225+/* at any given time. If any connection fails, any other available
226+/* ones will be opened and used. The intent of this feature is to eliminate
227+/* a single point of failure for mail systems that would otherwise rely
228+/* on a single pgsql server.
229+/*
230+/* Arguments:
231+/* .IP name
232+/* The path of the PostgreSQL configuration file. The file encodes a number of
233+/* pieces of information: username, password, databasename, table,
234+/* select_field, where_field, and hosts. For example, if you want the map to
235+/* reference databases of the name "your_db" and execute a query like this:
236+/* select forw_addr from aliases where alias like '<some username>' against
237+/* any database called "vmailer_info" located on hosts host1.some.domain and
238+/* host2.some.domain, logging in as user "vmailer" and password "passwd" then
239+/* the configuration file should read:
240+/*
241+/* user = vmailer
242+/* password = passwd
243+/* DBname = vmailer_info
244+/* table = aliases
245+/* select_field = forw_addr
246+/* where_field = alias
247+/* hosts = host1.some.domain host2.some.domain
248+/*
249+/* .IP other_name
250+/* reference for outside use.
251+/* .IP unusued_flags
252+/* unused flags
253+/* SEE ALSO
254+/* dict(3) generic dictionary manager
255+/* AUTHOR(S)
256+/* Mathieu Arnold
257+/* Absolight
258+/* mat@absolight.com
259+/*
260+/* based on dict_mysql by
261+/*
262+/* Scott Cotton
263+/* IC Group, Inc.
264+/* scott@icgroup.com
265+/*
266+/* Joshua Marcus
267+/* IC Group, Inc.
268+/* josh@icgroup.com
269+/*--*/
270+
271+/* System library. */
272+#include "sys_defs.h"
273+
274+#ifdef HAS_PGSQL
275+#include <sys/socket.h>
276+#include <netinet/in.h>
277+#include <arpa/inet.h>
278+#include <netdb.h>
279+#include <stdio.h>
280+#include <string.h>
281+#include <stdlib.h>
282+#include <syslog.h>
283+#include <time.h>
284+#include <libpq-fe.h>
285+
286+/* Utility library. */
287+#include "dict.h"
288+#include "msg.h"
289+#include "mymalloc.h"
290+#include "dict_pgsql.h"
291+#include "argv.h"
292+#include "vstring.h"
293+#include "split_at.h"
294+#include "find_inet.h"
295+
296+/* need some structs to help organize things */
297+typedef struct
298+{
299+ PGconn *db;
300+ char *hostname;
301+ int stat; /* STATUNTRIED | STATFAIL | STATCUR */
302+ time_t ts; /* used for attempting reconnection
303+ * every so often if a host is down */
304+} HOST;
305+
306+typedef struct
307+{
308+ int len_hosts; /* number of hosts */
309+ HOST *db_hosts; /* the hosts on which the databases
310+ * reside */
311+} PLPGSQL;
312+
313+typedef struct
314+{
315+ char *username;
316+ char *password;
317+ char *dbname;
318+ char *table;
319+ char *select_field;
320+ char *where_field;
321+ char *additional_conditions;
322+ char **hostnames;
323+ int len_hosts;
324+} PGSQL_NAME;
325+
326+typedef struct
327+{
328+ DICT dict;
329+ PLPGSQL *pldb;
330+ PGSQL_NAME *name;
331+} DICT_PGSQL;
332+
333+#define STATACTIVE 0
334+#define STATFAIL 1
335+#define STATUNTRIED 2
336+#define RETRY_CONN_INTV 60 /* 1 minute */
337+
338+/* internal function declarations */
339+static PLPGSQL *plpgsql_init (char *hostnames[], int);
340+static PGresult *plpgsql_query (PLPGSQL *, const char *, char *, char *,
341+
342+ char *);
343+static void plpgsql_dealloc (PLPGSQL *);
344+static void plpgsql_down_host (HOST *);
345+static void plpgsql_connect_single (HOST *, char *, char *, char *);
346+static int plpgsql_ready_reconn (HOST *);
347+static const char *dict_pgsql_lookup (DICT *, const char *);
348+DICT *dict_pgsql_open (const char *, int, int);
349+static void dict_pgsql_close (DICT *);
350+static PGSQL_NAME *pgsqlname_parse (const char *);
351+static HOST host_init (char *);
352+void pgsql_escape_string (char *escaped, const char *name, int len);
353+
354+
355+
356+/**********************************************************************
357+ * public interface dict_pgsql_lookup
358+ * find database entry return 0 if no alias found, set dict_errno
359+ * on errors to DICT_ERRBO_RETRY and set dict_errno to 0 on success
360+ *********************************************************************/
361+static const char *dict_pgsql_lookup (DICT *dict, const char *name)
362+{
363+ PGresult *query_res;
364+ char *field;
365+ DICT_PGSQL *dict_pgsql;
366+ PLPGSQL *pldb;
367+ static VSTRING *result;
368+ static VSTRING *query = 0;
369+ int i,
370+ j,
371+ numrows;
372+ char *name_escaped = 0;
373+
374+ dict_pgsql = (DICT_PGSQL *) dict;
375+ pldb = dict_pgsql->pldb;
376+ /* initialization for query */
377+ query = vstring_alloc (24);
378+ vstring_strcpy (query, "");
379+ if (
380+ (name_escaped =
381+ (char *) mymalloc ((sizeof (char) * (strlen (name) * 2) + 1))) ==
382+ NULL)
383+ {
384+ msg_fatal ("dict_pgsql_lookup: out of memory.");
385+ }
386+ /* prepare the query */
387+ pgsql_escape_string (name_escaped, name, (unsigned int) strlen (name));
388+ vstring_sprintf (query, "select %s from %s where %s = '%s' %s",
389+ dict_pgsql->name->select_field, dict_pgsql->name->table,
390+ dict_pgsql->name->where_field, name_escaped,
391+ dict_pgsql->name->additional_conditions);
392+ if (msg_verbose)
393+ msg_info ("dict_pgsql_lookup using sql query: %s",
394+ vstring_str (query));
395+ /* free mem associated with preparing the query */
396+ myfree (name_escaped);
397+ /* do the query - set dict_errno & cleanup if there's an error */
398+ if ((query_res = plpgsql_query (pldb,
399+ vstring_str (query),
400+ dict_pgsql->name->dbname,
401+ dict_pgsql->name->username,
402+ dict_pgsql->name->password)) == 0)
403+ {
404+ dict_errno = DICT_ERR_RETRY;
405+ vstring_free (query);
406+ return 0;
407+ }
408+ dict_errno = 0;
409+ /* free the vstring query */
410+ vstring_free (query);
411+ numrows = PQntuples (query_res);
412+ if (msg_verbose)
413+ msg_info ("dict_pgsql_lookup: retrieved %d rows", numrows);
414+ if (numrows == 0)
415+ {
416+ PQclear (query_res);
417+ return 0;
418+ }
419+ if (result == 0)
420+ result = vstring_alloc (10);
421+ vstring_strcpy (result, "");
422+ for (i = 0; i < numrows; i++)
423+ {
424+ if (i > 0)
425+ vstring_strcat (result, ",");
426+ for (j = 0; j < PQnfields (query_res); j++)
427+ {
428+ if (j > 0)
429+ vstring_strcat (result, ",");
430+ field = PQgetvalue (query_res, i, j);
431+ vstring_strcat (result, field);
432+ if (msg_verbose > 1)
433+ msg_info ("dict_pgsql_lookup: retrieved field: %d: %s", j,
434+ field);
435+ }
436+ }
437+ PQclear (query_res);
438+ return vstring_str (result);
439+}
440+
441+/*
442+ * plpgsql_query - process a PGSQL query. Return PGresult* on success.
443+ * On failure, log failure and try other db instances.
444+ * on failure of all db instances, return 0;
445+ * close unnecessary active connections
446+ */
447+
448+static PGresult *plpgsql_query (PLPGSQL * PLDB,
449+ const char *query,
450+ char *dbname, char *username, char *password)
451+{
452+ int i;
453+ HOST *host;
454+ PGresult *res = 0;
455+ ExecStatusType status;
456+
457+ for (i = 0; i < PLDB->len_hosts; i++)
458+ {
459+ /* can't deal with typing or reading PLDB->db_hosts[i] over & over */
460+ host = &(PLDB->db_hosts[i]);
461+ if (msg_verbose > 1)
462+ msg_info ("dict_pgsql: trying host %s stat %d, last res %p",
463+ host->hostname, host->stat, res);
464+
465+ /* answer already found */
466+ if (res != 0 && host->stat == STATACTIVE)
467+ {
468+ if (msg_verbose)
469+ msg_info
470+ ("dict_pgsql: closing unnessary connection to %s",
471+ host->hostname);
472+ plpgsql_down_host (host);
473+ }
474+ /* try to connect for the first time if we don't have a result yet */
475+ if (res == 0 && host->stat == STATUNTRIED)
476+ {
477+ if (msg_verbose)
478+ msg_info ("dict_pgsql: attempting to connect to host %s",
479+ host->hostname);
480+ plpgsql_connect_single (host, dbname, username, password);
481+ }
482+
483+ /*
484+ * try to reconnect if we don't have an answer and the host had a
485+ * prob in the past and it's time for it to reconnect
486+ */
487+ if (res == 0 && host->stat == STATFAIL
488+ && host->ts < time ((time_t *) 0))
489+ {
490+ if (msg_verbose)
491+ msg_info
492+ ("dict_pgsql: attempting to reconnect to host %s",
493+ host->hostname);
494+ plpgsql_connect_single (host, dbname, username, password);
495+ }
496+
497+ /*
498+ * if we don't have a result and the current host is marked active,
499+ * try the query. If the query fails, mark the host STATFAIL
500+ */
501+ if (res == 0 && host->stat == STATACTIVE)
502+ {
503+ res = PQexec (host->db, query);
504+ status = PQresultStatus (res);
505+ if (res
506+ && (status = PGRES_COMMAND_OK
507+ || status == PGRES_TUPLES_OK))
508+ {
509+ if (msg_verbose)
510+ msg_info
511+ ("dict_pgsql: successful query from host %s",
512+ host->hostname);
513+ }
514+ else
515+ {
516+ msg_warn ("%s", PQerrorMessage (host->db));
517+ plpgsql_down_host (host);
518+ }
519+ }
520+ }
521+ return res;
522+}
523+
524+/*
525+ * plpgsql_connect_single -
526+ * used to reconnect to a single database when one is down or none is
527+ * connected yet. Log all errors and set the stat field of host accordingly
528+ */
529+static void
530+plpgsql_connect_single (HOST *host, char *dbname, char *username,
531+ char *password)
532+{
533+ char *destination = host->hostname;
534+ char *hostname = 0;
535+ char *service;
536+ VSTRING *conninfo = vstring_alloc (100);
537+ char *conn;
538+ unsigned port = 0;
539+
540+ /*
541+ * Ad-hoc parsing code. Expect "unix:pathname" or "inet:host:port", where
542+ * both "inet:" and ":port" are optional.
543+ */
544+ if (strncmp (destination, "unix:", 5) == 0)
545+ {
546+ vstring_sprintf_append (conninfo, "host=%s ", destination + 5);
547+ }
548+ else
549+ {
550+ if (strncmp (destination, "inet:", 5) == 0)
551+ destination += 5;
552+ hostname = mystrdup (destination);
553+ if ((service = split_at (hostname, ':')) != 0)
554+ {
555+ port = ntohs (find_inet_port (service, "tcp"));
556+ vstring_sprintf_append (conninfo, "host='%s' port='%d'",
557+ hostname, port);
558+ }
559+ else
560+ {
561+ vstring_sprintf_append (conninfo, "host='%s'", hostname);
562+ }
563+ }
564+
565+ vstring_sprintf_append (conninfo, " dbname='%s' user='%s' password='%s'", dbname,
566+ username, password);
567+ conn = vstring_export (conninfo);
568+
569+ host->db = PQconnectdb (conn);
570+
571+ if ((host->db != NULL) && (PQstatus (host->db) == CONNECTION_OK))
572+ {
573+ if (msg_verbose)
574+ msg_info ("dict_pgsql: successful connection to host %s",
575+ host->hostname);
576+ host->stat = STATACTIVE;
577+ }
578+ else
579+ {
580+ msg_warn ("%s", PQerrorMessage (host->db));
581+ plpgsql_down_host (host);
582+ }
583+ if (hostname)
584+ myfree (hostname);
585+ myfree (conn);
586+}
587+
588+/*
589+ * plpgsql_down_host - mark a HOST down update ts if marked down
590+ * for the first time so that we'll know when to retry the connection
591+ */
592+static void plpgsql_down_host (HOST *host)
593+{
594+ if (host->stat != STATFAIL)
595+ {
596+ host->ts = time ((time_t *) 0) + RETRY_CONN_INTV;
597+ host->stat = STATFAIL;
598+ }
599+ PQfinish (host->db);
600+ host->db = 0;
601+}
602+
603+/**********************************************************************
604+ * public interface dict_pgsql_open
605+ * create association with database with appropriate values
606+ * parse the map's config file
607+ * allocate memory
608+ **********************************************************************/
609+DICT *dict_pgsql_open (const char *name, int unused_open_flags,
610+ int dict_flags)
611+{
612+ DICT_PGSQL *dict_pgsql;
613+ int connections;
614+
615+ dict_pgsql = (DICT_PGSQL *) dict_alloc (DICT_TYPE_PGSQL, name,
616+ sizeof (DICT_PGSQL));
617+ dict_pgsql->dict.lookup = dict_pgsql_lookup;
618+ dict_pgsql->dict.close = dict_pgsql_close;
619+ dict_pgsql->dict.flags = dict_flags | DICT_FLAG_FIXED;
620+ dict_pgsql->name = pgsqlname_parse (name);
621+ dict_pgsql->pldb = plpgsql_init (dict_pgsql->name->hostnames,
622+ dict_pgsql->name->len_hosts);
623+ if (dict_pgsql->pldb == NULL)
624+ msg_fatal ("couldn't intialize pldb!\n");
625+ dict_register (name, (DICT *) dict_pgsql);
626+ return (DICT_DEBUG (&dict_pgsql->dict));
627+}
628+
629+/* pgsqlname_parse - parse pgsql configuration file */
630+static PGSQL_NAME *pgsqlname_parse (const char *pgsqlcf_path)
631+{
632+ int i;
633+ char *nameval;
634+ char *hosts;
635+ PGSQL_NAME *name = (PGSQL_NAME *) mymalloc (sizeof (PGSQL_NAME));
636+ ARGV *hosts_argv;
637+ VSTRING *opt_dict_name;
638+
639+ /*
640+ * setup a dict containing info in the pgsql cf file. the dict has a
641+ * name, and a path. The name must be distinct from the path, or the
642+ * dict interface gets confused. The name must be distinct for two
643+ * different paths, or the configuration info will cache across different
644+ * pgsql maps, which can be confusing.
645+ */
646+ opt_dict_name = vstring_alloc (64);
647+ vstring_sprintf (opt_dict_name, "pgsql opt dict %s", pgsqlcf_path);
648+ dict_load_file (vstring_str (opt_dict_name), pgsqlcf_path);
649+ /* pgsql username lookup */
650+ if (
651+ (nameval =
652+ (char *) dict_lookup (vstring_str (opt_dict_name), "user")) == NULL)
653+ name->username = mystrdup ("");
654+ else
655+ name->username = mystrdup (nameval);
656+ if (msg_verbose)
657+ msg_info ("pgsqlname_parse(): set username to '%s'", name->username);
658+ /* password lookup */
659+ if (
660+ (nameval =
661+ (char *) dict_lookup (vstring_str (opt_dict_name),
662+ "password")) == NULL)
663+ name->password = mystrdup ("");
664+ else
665+ name->password = mystrdup (nameval);
666+ if (msg_verbose)
667+ msg_info ("pgsqlname_parse(): set password to '%s'", name->password);
668+
669+ /* database name lookup */
670+ if (
671+ (nameval =
672+ (char *) dict_lookup (vstring_str (opt_dict_name),
673+ "dbname")) == NULL)
674+
675+
676+
677+ msg_fatal ("%s: pgsql options file does not include database name",
678+ pgsqlcf_path);
679+ else
680+ name->dbname = mystrdup (nameval);
681+ if (msg_verbose)
682+ msg_info ("pgsqlname_parse(): set database name to '%s'",
683+ name->dbname);
684+
685+ /* table lookup */
686+ if (
687+ (nameval =
688+ (char *) dict_lookup (vstring_str (opt_dict_name), "table")) == NULL)
689+ msg_fatal ("%s: pgsql options file does not include table name",
690+ pgsqlcf_path);
691+ else
692+ name->table = mystrdup (nameval);
693+ if (msg_verbose)
694+ msg_info ("pgsqlname_parse(): set table name to '%s'", name->table);
695+
696+ /* select field lookup */
697+ if (
698+ (nameval =
699+ (char *) dict_lookup (vstring_str (opt_dict_name),
700+ "select_field")) == NULL)
701+
702+
703+
704+ msg_fatal ("%s: pgsql options file does not include select field",
705+ pgsqlcf_path);
706+ else
707+ name->select_field = mystrdup (nameval);
708+ if (msg_verbose)
709+ msg_info ("pgsqlname_parse(): set select_field to '%s'",
710+ name->select_field);
711+
712+ /* where field lookup */
713+ if (
714+ (nameval =
715+ (char *) dict_lookup (vstring_str (opt_dict_name),
716+ "where_field")) == NULL)
717+ msg_fatal ("%s: pgsql options file does not include where field",
718+ pgsqlcf_path);
719+ else
720+ name->where_field = mystrdup (nameval);
721+ if (msg_verbose)
722+ msg_info ("pgsqlname_parse(): set where_field to '%s'",
723+ name->where_field);
724+
725+ /* additional conditions */
726+ if (
727+ (nameval =
728+ (char *) dict_lookup (vstring_str (opt_dict_name),
729+ "additional_conditions")) == NULL)
730+ name->additional_conditions = mystrdup ("");
731+ else
732+ name->additional_conditions = mystrdup (nameval);
733+ if (msg_verbose)
734+ msg_info ("pgsqlname_parse(): set additional_conditions to '%s'",
735+ name->additional_conditions);
736+
737+ /* pgsql server hosts */
738+ if (
739+ (nameval =
740+ (char *) dict_lookup (vstring_str (opt_dict_name), "hosts")) == NULL)
741+ hosts = mystrdup ("");
742+ else
743+ hosts = mystrdup (nameval);
744+ /* coo argv interface */
745+ hosts_argv = argv_split (hosts, " ,\t\r\n");
746+
747+ if (hosts_argv->argc == 0)
748+ { /* no hosts specified,
749+ * default to 'localhost' */
750+ if (msg_verbose)
751+ msg_info
752+ ("pgsqlname_parse(): no hostnames specified, defaulting to 'localhost'");
753+ argv_add (hosts_argv, "localhost", ARGV_END);
754+ argv_terminate (hosts_argv);
755+ }
756+ name->len_hosts = hosts_argv->argc;
757+ name->hostnames =
758+
759+ (char **) mymalloc ((sizeof (char *)) * name->len_hosts);
760+ i = 0;
761+ for (i = 0; hosts_argv->argv[i] != NULL; i++)
762+ {
763+ name->hostnames[i] = mystrdup (hosts_argv->argv[i]);
764+ if (msg_verbose)
765+ msg_info
766+ ("pgsqlname_parse(): adding host '%s' to list of pgsql server hosts",
767+ name->hostnames[i]);
768+ }
769+ myfree (hosts);
770+ vstring_free (opt_dict_name);
771+ argv_free (hosts_argv);
772+ return name;
773+}
774+
775+
776+/*
777+ * plpgsql_init - initalize a PGSQL database.
778+ * Return NULL on failure, or a PLPGSQL * on success.
779+ */
780+static PLPGSQL *plpgsql_init (char *hostnames[], int len_hosts)
781+{
782+ PLPGSQL *PLDB;
783+ int i;
784+ HOST host;
785+
786+ if ((PLDB = (PLPGSQL *) mymalloc (sizeof (PLPGSQL))) == NULL)
787+ {
788+ msg_fatal ("mymalloc of pldb failed");
789+ }
790+ PLDB->len_hosts = len_hosts;
791+ if ((PLDB->db_hosts = (HOST *) mymalloc (sizeof (HOST) * len_hosts))
792+ == NULL)
793+ return NULL;
794+
795+ for (i = 0; i < len_hosts; i++)
796+ {
797+ PLDB->db_hosts[i] = host_init (hostnames[i]);
798+ }
799+ return PLDB;
800+}
801+
802+
803+/* host_init - initialize HOST structure */
804+static HOST host_init (char *hostname)
805+{
806+ HOST host;
807+
808+ host.stat = STATUNTRIED;
809+ host.hostname = mystrdup (hostname);
810+ host.db = 0;
811+ host.ts = 0;
812+ return host;
813+}
814+
815+/**********************************************************************
816+ * public interface dict_pgsql_close
817+ * unregister, disassociate from database, freeing appropriate memory
818+ **********************************************************************/
819+static void dict_pgsql_close (DICT *dict)
820+{
821+ int i;
822+ DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
823+
824+ plpgsql_dealloc (dict_pgsql->pldb);
825+ myfree (dict_pgsql->name->username);
826+ myfree (dict_pgsql->name->password);
827+ myfree (dict_pgsql->name->dbname);
828+ myfree (dict_pgsql->name->table);
829+ myfree (dict_pgsql->name->select_field);
830+ myfree (dict_pgsql->name->where_field);
831+ myfree (dict_pgsql->name->additional_conditions);
832+ for (i = 0; i < dict_pgsql->name->len_hosts; i++)
833+ {
834+ myfree (dict_pgsql->name->hostnames[i]);
835+ }
836+ myfree ((char *) dict_pgsql->name->hostnames);
837+ myfree ((char *) dict_pgsql->name);
838+ dict_free (dict);
839+}
840+
841+/* plpgsql_dealloc - free memory associated with PLPGSQL close databases */
842+static void plpgsql_dealloc (PLPGSQL * PLDB)
843+{
844+ int i;
845+
846+ for (i = 0; i < PLDB->len_hosts; i++)
847+ {
848+ if (PLDB->db_hosts[i].db)
849+ PQfinish (PLDB->db_hosts[i].db);
850+ myfree (PLDB->db_hosts[i].hostname);
851+ }
852+ myfree ((char *) PLDB->db_hosts);
853+ myfree ((char *) (PLDB));
854+}
855+
856+/* pgsql_escape_string - replace mysql_escape_string */
857+void pgsql_escape_string (char *escaped, const char *name, int len)
858+{
859+ int i,
860+ j;
861+
862+ for (i = 0, j = 0; i <= len; i++, j++)
863+ {
864+ if ((name[i] == '\'') || (name[i] == '\\'))
865+ {
866+ escaped[j] = '\\';
867+ j++;
868+ }
869+ escaped[j] = name[i];
870+ }
871+}
872+
873+
874+
875+#endif
876+
877diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_pgsql.h postfix-1.1.3/src/util/dict_pgsql.h
878--- postfix-1.1.3-vanilla/src/util/dict_pgsql.h Thu Jan 1 01:00:00 1970
879+++ postfix-1.1.3/src/util/dict_pgsql.h Thu Mar 7 11:48:41 2002
880@@ -0,0 +1,41 @@
881+#ifndef _DICT_PGSQL_H_INCLUDED_
882+#define _DICT_PGSQL_H_INCLUDED_
883+
884+/*++
885+/* NAME
886+/* dict_pgsql 3h
887+/* SUMMARY
888+/* dictionary manager interface to pgsql databases
889+/* SYNOPSIS
890+/* #include <dict_pgsql.h>
891+/* DESCRIPTION
892+/* .nf
893+
894+ /*
895+ * Utility library.
896+ */
897+#include <dict.h>
898+
899+ /*
900+ * External interface.
901+ */
902+#define DICT_TYPE_PGSQL "pgsql"
903+
904+extern DICT *dict_pgsql_open (const char *, int, int);
905+
906+/* LICENSE
907+/* .ad
908+/* .fi
909+/* The Secure Mailer license must be distributed with this software.
910+/* AUTHOR(S)
911+/* Scott Cotton
912+/* IC Group, Inc.
913+/* scott@icgroup.com
914+/*
915+/* Joshua Marcus
916+/* IC Group, Inc.
917+/* josh@icgroup.com
918+/*--*/
919+
920+#endif
921+
This page took 0.216621 seconds and 4 git commands to generate.