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