]> git.pld-linux.org Git - packages/postfix.git/blob - postfix-pgsql.patch
- obsolete - already in 1.1.13
[packages/postfix.git] / postfix-pgsql.patch
1 diff -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.
93 diff -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
177 diff -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
198 diff -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 +
877 diff -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.159282 seconds and 3 git commands to generate.