- updated to 8.16.1 (includes security fix)
[packages/sendmail.git] / bluelabs-smpgsql-8.14.3.patch
1 diff -ruN sendmail-8.14.3/cf/feature/pg_accessdb.m4 sendmail-8.14.3.pgsql/cf/feature/pg_accessdb.m4
2 --- sendmail-8.14.3/cf/feature/pg_accessdb.m4   1969-12-31 16:00:00.000000000 -0800
3 +++ sendmail-8.14.3.pgsql/cf/feature/pg_accessdb.m4     2007-03-26 13:19:46.000000000 -0700
4 @@ -0,0 +1,19 @@
5 +divert(-1)
6 +# By using this file, you agree to be cool and share your knowledge
7 +#
8 +# David, http://blue-labs.org/software/sm-pgsql/sendmail.php
9 +#
10 +
11 +divert(0)
12 +VERSIONID(`$Id: pg_accessdb.m4,v 2.0 2000/07/19 18:15:16 blu3 Exp $')
13 +divert(-1)
14 +
15 +define(`_ACCESS_TABLE_', `')
16 +define(`_PG_ACCESS_TABLE_', `')
17 +define(`_TAG_DELIM_', `:')dnl should be in OperatorChars
18 +
19 +LOCAL_CONFIG
20 +# PostgreSQL based access list
21 +Kaccess ifelse(defn(`_ARG_'), `',
22 +                DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`access',
23 +                `_ARG_')
24 diff -ruN sendmail-8.14.3/cf/feature/pg_aliases.m4 sendmail-8.14.3.pgsql/cf/feature/pg_aliases.m4
25 --- sendmail-8.14.3/cf/feature/pg_aliases.m4    1969-12-31 16:00:00.000000000 -0800
26 +++ sendmail-8.14.3.pgsql/cf/feature/pg_aliases.m4      2007-03-26 13:19:46.000000000 -0700
27 @@ -0,0 +1,19 @@
28 +divert(-1)
29 +# By using this file, you agree to be cool and share your knowledge
30 +#
31 +# David, http://blue-labs.org/software/sm-pgsql/sendmail.php
32 +#
33 +
34 +divert(0)
35 +VERSIONID(`$Id: pg_aliases.m4,v 2.0 2000/07/19 18:15:16 blu3 Exp $')
36 +divert(-1)
37 +
38 +undefine(`ALIAS_FILE')
39 +define(`_ALIASES_TABLE_', `')
40 +define(`_PG_ALIASES_TABLE_', `')
41 +
42 +LOCAL_CONFIG
43 +# PostgreSQL based local aliases
44 +Kaliases ifelse(defn(`_ARG_'), `',
45 +                DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`aliases',
46 +                `_ARG_')
47 diff -ruN sendmail-8.14.3/cf/feature/pg_domaintable.m4 sendmail-8.14.3.pgsql/cf/feature/pg_domaintable.m4
48 --- sendmail-8.14.3/cf/feature/pg_domaintable.m4        1969-12-31 16:00:00.000000000 -0800
49 +++ sendmail-8.14.3.pgsql/cf/feature/pg_domaintable.m4  2007-03-26 13:19:46.000000000 -0700
50 @@ -0,0 +1,18 @@
51 +divert(-1)
52 +# By using this file, you agree to be cool and share your knowledge
53 +#
54 +# David, http://blue-labs.org/software/sm-pgsql/sendmail.php
55 +#
56 +
57 +divert(0)
58 +VERSIONID(`$Id: pg_domaintable.m4,v 2.0 2000/07/19 18:15:16 blu3 Exp $')
59 +divert(-1)
60 +
61 +define(`_DOMAIN_TABLE_', `')
62 +define(`_PG_DOMAIN_TABLE', `')
63 +
64 +LOCAL_CONFIG
65 +# PostgreSQL based domain rewriting table
66 +Kdomaintable ifelse(defn(`_ARG_'), `',
67 +                DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`domaintable',
68 +                `_ARG_')
69 diff -ruN sendmail-8.14.3/cf/feature/pg_generics.m4 sendmail-8.14.3.pgsql/cf/feature/pg_generics.m4
70 --- sendmail-8.14.3/cf/feature/pg_generics.m4   1969-12-31 16:00:00.000000000 -0800
71 +++ sendmail-8.14.3.pgsql/cf/feature/pg_generics.m4     2007-03-26 13:19:46.000000000 -0700
72 @@ -0,0 +1,18 @@
73 +divert(-1)
74 +# By using this file, you agree to be cool and share your knowledge
75 +#
76 +# David, http://blue-labs.org/software/sm-pgsql/sendmail.php
77 +#
78 +
79 +divert(0)
80 +VERSIONID(`$Id: pg_genericstable.m4,v 2.0 2000/07/19 18:15:16 blu3 Exp $')
81 +divert(-1)
82 +
83 +define(`_GENERICS_TABLE_', `')
84 +define(`_PG_GENERICS_TABLE', `')
85 +
86 +LOCAL_CONFIG
87 +# PostgreSQL based generic domain mapping table, similar to userdb
88 +Kgenerics ifelse(defn(`_ARG_'), `',
89 +                DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`generics',
90 +                `_ARG_')
91 diff -ruN sendmail-8.14.3/cf/feature/pg_mailer.m4 sendmail-8.14.3.pgsql/cf/feature/pg_mailer.m4
92 --- sendmail-8.14.3/cf/feature/pg_mailer.m4     1969-12-31 16:00:00.000000000 -0800
93 +++ sendmail-8.14.3.pgsql/cf/feature/pg_mailer.m4       2007-03-26 13:19:46.000000000 -0700
94 @@ -0,0 +1,18 @@
95 +divert(-1)
96 +# By using this file, you agree to be cool and share your knowledge
97 +#
98 +# David, http://blue-labs.org/software/sm-pgsql/sendmail.php
99 +#
100 +
101 +divert(0)
102 +VERSIONID(`$Id: pg_mailertable.m4,v 2.0 2000/07/19 18:15:16 blu3 Exp $')
103 +divert(-1)
104 +
105 +define(`_MAILER_TABLE_', `')
106 +define(`_PG_MAILER_TABLE', `')
107 +
108 +LOCAL_CONFIG
109 +# PostgreSQL based mailer table, for overriding domain and MX
110 +Kmailertable ifelse(defn(`_ARG_'), `',
111 +                DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`mailertable',
112 +                `_ARG_')
113 diff -ruN sendmail-8.14.3/cf/feature/pg_usersdb.m4 sendmail-8.14.3.pgsql/cf/feature/pg_usersdb.m4
114 --- sendmail-8.14.3/cf/feature/pg_usersdb.m4    1969-12-31 16:00:00.000000000 -0800
115 +++ sendmail-8.14.3.pgsql/cf/feature/pg_usersdb.m4      2007-03-26 13:19:46.000000000 -0700
116 @@ -0,0 +1,18 @@
117 +divert(-1)
118 +# By using this file, you agree to be cool and share your knowledge
119 +#
120 +# David, http://blue-labs.org/software/sm-pgsql/sendmail.php
121 +#
122 +
123 +divert(0)
124 +VERSIONID(`$Id: pg_usersdb.m4,v 2.0 2000/07/19 18:15:16 blu3 Exp $')
125 +divert(-1)
126 +
127 +define(`_REWRITE_TABLE_', `')
128 +define(`_PG_REWRITE_TABLE_', `')
129 +
130 +LOCAL_CONFIG
131 +# PostgreSQL based user rewrite table (can turn "John.Doe" into "jdoe")
132 +Kusersdb ifelse(defn(`_ARG_'), `',
133 +                DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`usersdb',
134 +                `_ARG_')
135 diff -ruN sendmail-8.14.3/cf/feature/pg_virtualusers.m4 sendmail-8.14.3.pgsql/cf/feature/pg_virtualusers.m4
136 --- sendmail-8.14.3/cf/feature/pg_virtualusers.m4       1969-12-31 16:00:00.000000000 -0800
137 +++ sendmail-8.14.3.pgsql/cf/feature/pg_virtualusers.m4 2007-03-26 13:19:46.000000000 -0700
138 @@ -0,0 +1,18 @@
139 +divert(-1)
140 +# By using this file, you agree to be cool and share your knowledge
141 +#
142 +# David, http://blue-labs.org/software/sm-pgsql/sendmail.php
143 +#
144 +
145 +divert(0)
146 +VERSIONID(`$Id: pg_virtusertable.m4,v 2.0 2000/07/19 18:15:16 blu3 Exp $')
147 +divert(-1)
148 +
149 +define(`_VIRTUSER_TABLE_', `')
150 +define(`_PG_VIRTUSER_TABLE_', `')
151 +
152 +LOCAL_CONFIG
153 +# PostgreSQL based virtual user table (maps incoming users)
154 +Kvirtuser ifelse(defn(`_ARG_'), `',
155 +                DATABASE_MAP_TYPE MAIL_SETTINGS_DIR`virtusertable',
156 +                `_ARG_')
157 diff -ruN sendmail-8.14.3/pgsql-build.mc sendmail-8.14.3.pgsql/pgsql-build.mc
158 --- sendmail-8.14.3/pgsql-build.mc      1969-12-31 16:00:00.000000000 -0800
159 +++ sendmail-8.14.3.pgsql/pgsql-build.mc        2007-03-26 13:19:46.000000000 -0700
160 @@ -0,0 +1,32 @@
161 +######################################################################
162 +# This is the Blue Labs m4 file for the Sendmail w/ Postgres Tables patch.
163 +#
164 +# The website for building sendmail with this patch is at
165 +#   http://blue-labs.org/software/sm-pgsql/sendmail.php
166 +#
167 +# This patch may eventually be available to Gentoo (http://gentoo.org/)
168 +# users with the "USE=postgres" use flag
169 +#
170 +# !!! EDIT THE CONFIGURATION SETTINGS TO MATCH YOUR NEEDS !!!
171 +#
172 +# NOTE: This is a specialised .cf for the postgresql patch only
173 +#
174 +VERSIONID(`(#) Blue Labs bluelabs.mc   v 11.1 (Blue Labs) 12 Jan 2007')
175 +######################################################################
176 +
177 +##
178 +# See http://blue-labs.org/software/sm-pgsql/sendmail.php for detailed
179 +# instructions
180 +#
181 +# TODO: replace 'newaliases' and 'makemap' targets with "don't run this"
182 +#       update man pages also
183 +##
184 +
185 +# uncomment these two lines if you use /usr/local/pgsql
186 +# APPENDDEF(`confINCDIRS',`-I/usr/local/pgsql/include')dnl
187 +# APPENDDEF(`confLIBDIRS',`-L/usr/local/pgsql/lib')dnl
188 +
189 +APPENDDEF(`confLIBS',`-lpq')dnl
190 +APPENDDEF(`confMAPDEF',`-DPGSQLMAP')dnl
191 +APPENDDEF(`DATABASE_MAP_TYPE', `pgsql')dnl
192 +
193 diff -ruN sendmail-8.14.3/pgsql-config.mc sendmail-8.14.3.pgsql/pgsql-config.mc
194 --- sendmail-8.14.3/pgsql-config.mc     1969-12-31 16:00:00.000000000 -0800
195 +++ sendmail-8.14.3.pgsql/pgsql-config.mc       2007-03-26 13:19:46.000000000 -0700
196 @@ -0,0 +1,51 @@
197 +######################################################################
198 +# This is the Blue Labs m4 file for the Sendmail w/ Postgres Tables patch.
199 +#
200 +# The website for building sendmail with this patch is at
201 +#   http://blue-labs.org/software/sm-pgsql/sendmail.php
202 +#
203 +# This patch may eventually be available to Gentoo (http://gentoo.org/)
204 +# users with the "USE=postgres" use flag
205 +#
206 +# !!! EDIT THE CONFIGURATION SETTINGS TO MATCH YOUR NEEDS !!!
207 +#
208 +# NOTE: This is a specialised .cf for the postgresql patch only
209 +#
210 +VERSIONID(`(#) Blue Labs bluelabs.mc   v 12.0 (Blue Labs) 12 Dec 2007')
211 +######################################################################
212 +
213 +##
214 +# See http://blue-labs.org/software/sm-pgsql/sendmail.php for detailed
215 +# instructions
216 +##
217 +
218 +dnl ##
219 +dnl # example line:
220 +dnl #  pgsql [-h <pgsql server>] -c <connection string> -s <query string>
221 +dnl ##
222 +
223 +#
224 +# PgSql
225 +#
226 +# add the flag -f to force case sensitive queries, by default both the
227 +# search and the value will be folded to lower case. by default %s will be
228 +# rewritten to by lower('%s').  if -f is specified, then it will only be
229 +# written as ('%s') and both the input value and the row value MUST match
230 +# case exactly.
231 +#
232 +
233 +define(`PG_CONNSTR', "host=localhost dbname=sendmail user=sendmail password=raisins")
234 +define(`SELECT', "select distinct s_out from )
235 +define(`WHERE', where ``lower'' (s_in) = %s")
236 +FEATURE(`pg_aliases',      pgsql -c `PG_CONNSTR' -s `SELECT' `aliases'       `WHERE')dnl
237 +FEATURE(`pg_virtualusers', pgsql -c `PG_CONNSTR' -s `SELECT' `virtualusers'  `WHERE')dnl
238 +FEATURE(`pg_usersdb',      pgsql -c `PG_CONNSTR' -s `SELECT' `userrewrite'   `WHERE')dnl
239 +FEATURE(`pg_accessdb',     pgsql -c `PG_CONNSTR' -s `SELECT' `access'        `WHERE')dnl
240 +FEATURE(`pg_domaintable',  pgsql -c `PG_CONNSTR' -s `SELECT' `domaintable'   `WHERE')dnl
241 +FEATURE(`pg_generics',     pgsql -c `PG_CONNSTR' -s `SELECT' `genericstable' `WHERE')dnl
242 +FEATURE(`pg_mailer',       pgsql -c `PG_CONNSTR' -s `SELECT' `mailertable'   `WHERE')dnl
243 +
244 +define(`confPROCESS_TITLE_PREFIX', `[Blue-PgSQL]')dnl
245 +define(`confSMTP_LOGIN_MSG', `Mail server\
246 + \
247 + Unauthorized use prohibited\
248 + \
249 + Spam is prohibited here and any detected spam may be used in prosecution\
250 + against the spammer. This setup uses PgSQL (postgresql) for most of it''`s\
251 + tables, for information on this, see\
252 + http://blue-labs.org/software/sm-pgsql/sendmail.php\
253 + Don''`t bitch if your MTA is busted and doesn''`t play well with others.\
254 + \
255 +')dnl
256 +
257 +dnl # Don't attempt to rebuild an aliases file, sm-pgsql doesn't use files
258 +dnl # however if you have multiple alias tables and DO use files, remove this
259 +dnl # next line
260 +define(`confALIAS_WAIT', `0')dnl
261 diff -ruN sendmail-8.14.3/sendmail/README sendmail-8.14.3.pgsql/sendmail/README
262 --- sendmail-8.14.3/sendmail/README     2006-11-13 14:27:27.000000000 -0800
263 +++ sendmail-8.14.3.pgsql/sendmail/README       2007-03-26 13:19:46.000000000 -0700
264 @@ -119,6 +119,11 @@
265                 have to install the UMich or OpenLDAP
266                 (http://www.openldap.org/) ldap and lber libraries to use
267                 this flag.
268 +PGSQLMAP       PostgreSQL SQL query support.  You will need to have
269 +               PostgreSQL include files and libraries installed to use this
270 +               feature.  Information on PostgreSQL can be found at
271 +               http://www.postgresql.org/  Support for this map may be
272 +               found at http://blue-labs.org/software/sm-pgsql/sendmail.php
273  MAP_REGEX      Regular Expression support.  You will need to use an
274                 operating system which comes with the POSIX regex()
275                 routines or install a regexp library such as libregex from
276 --- sendmail-8.16.1/sendmail/conf.c.orig        2020-06-04 08:27:49.000000000 +0200
277 +++ sendmail-8.16.1/sendmail/conf.c     2020-08-29 10:15:17.896341069 +0200
278 @@ -576,6 +576,12 @@
279                 ldapmap_lookup, null_map_store);
280  #endif
281  
282 +#ifdef PGSQLMAP
283 +       MAPDEF("pgsql", NULL, MCF_ALIASOK|MCF_NOTPERSIST,
284 +               pgsql_map_parseargs, pgsql_map_open, pgsql_map_close,
285 +               pgsql_map_lookup, null_map_store);
286 +#endif
287 +
288  #if PH_MAP
289         MAPDEF("ph", NULL, MCF_NOTPERSIST,
290                 ph_map_parseargs, ph_map_open, ph_map_close,
291 @@ -5864,6 +5870,9 @@
292  #if LDAP_REFERRALS
293         "LDAP_REFERRALS",
294  #endif
295 +#if PGSQLMAP
296 +       "PGSQLMAP",
297 +#endif /* PGSQLMAP */
298  #if LOG
299         "LOG",
300  #endif
301 --- sendmail-8.14.3/sendmail/map.c      2007-10-09 20:06:45.000000000 -0400
302 +++ sendmail-8.14.3.pgsql/sendmail/map.c        2009-11-09 19:54:47.214965897 -0500
303 @@ -4706,6 +4706,588 @@
304         }
305  }
306  #endif /* LDAPMAP */
307 +
308 +#ifdef PGSQLMAP
309 +#include <libpq-fe.h>
310 +
311 +/* 
312 + * PostgreSQL map functionality for Sendmail 8.14.3
313 + * Portions Copyright (C) 2000 Jonathan Yarden <jyarden@bluegrass.net>
314 + * Remainder copyright (c) 2000-2009 David Ford <david@blue-labs.org>
315 + *
316 + * For information on PostgreSQL, visit http://www.pgsql.com/
317 + * Information on this patch and setup is at
318 + * http://blue-labs.org/software/sm-pgsql/sendmail.php
319 + *
320 + * This patch, because it integrates with and is based on the existing
321 + * prior work of Sendmail, is considered by me to be a "derivative
322 + * work" subject to the Sendmail licensing terms. Sendmail, Inc. in not
323 + * responsible for this code.
324 + *
325 + * USE AT YOUR OWN RISK. NO WARRANTY OF ANY KIND IS PROVIDED. PLEASE
326 + * READ THE INSTRUCTIONS FOR USE OF THIS PATCH BEFORE CONTACTING THE
327 + * AUTHOR OR SENDMAIL, INC.    NO SUPPORT OF ANY KIND WILL BE PROVIDED
328 + * BY SENDMAIL, INC. FOR THIS PATCH.
329 + */
330 +
331 +/*
332 +struct pgsqlmap
333 +{
334 +       struct pgsqlmap *p,*n;
335 +       char    *connstr;
336 +       PGconn  *conn;
337 +       pid_t    opener_pid;
338 +       char    *mapname;
339 +} *pgsqlmap = NULL; */
340 +
341 +char *pgsql_skip_quotes(char *p)
342 +{
343 +       p = strchr(p,'"');
344 +       if (p)
345 +       {
346 +               p++;
347 +               p = strchr(p,'"');
348 +               if (p) p++;
349 +       }
350 +       return p;
351 +}
352 +
353 +/*
354 + * Parse PostgreSQL map definition args.
355 + *
356 + * Nothing really special here, since to be perfectly honest, I have never
357 + * seen or used almost all of these options.   Most of this code was taken
358 + * directly from existing Sendmail source code.
359 + */
360 +bool pgsql_map_parseargs(MAP *map, char *args)
361 +{
362 +       register char *p = args;
363 +       register int done;
364 +
365 +       map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
366 +       for (;;)
367 +       {
368 +               while (isascii(*p) && isspace(*p))
369 +                       p++;
370 +               if (*p != '-')
371 +                       break;
372 +               switch (*++p)
373 +               {
374 +                       case 'A':
375 +                               map->map_mflags |= MF_APPEND;
376 +                               break;
377 +
378 +                       case 'N':
379 +                               map->map_mflags |= MF_INCLNULL;
380 +                               map->map_mflags &= ~MF_TRY0NULL;
381 +                               break;
382 +
383 +                       case 'O':
384 +                               map->map_mflags &= ~MF_TRY1NULL;
385 +                               break;
386 +
387 +                       case 'T':
388 +                               map->map_tapp = ++p;
389 +                               break;
390 +
391 +                       case 'a':
392 +                               map->map_app = ++p;
393 +                               break;
394 +
395 +                       case 'f':
396 +                               map->map_mflags |= MF_NOFOLDCASE;
397 +                               break;
398 +
399 +                       case 'h':
400 +                               map->map_db2 = ++p;
401 +                               break;
402 +
403 +                       case 'm':
404 +                               map->map_mflags |= MF_MATCHONLY;
405 +                               break;
406 +
407 +                       case 'o':
408 +                               map->map_mflags |= MF_OPTIONAL;
409 +                               break;
410 +
411 +                       case 'q':
412 +                               map->map_mflags |= MF_KEEPQUOTES;
413 +                               break;
414 +
415 +                       case 't':
416 +                               map->map_mflags |= MF_NODEFER;
417 +                               break;
418 +
419 +/* 
420 + * Start of PostgreSQL specific args.  I cheat and use some existing
421 + * Sendmail variables here since this map class makes no other use of them.
422 + */
423 +
424 +                       case 'c':                       /* connection string */
425 +                               map->map_keycolnm = ++p;
426 +                               p = pgsql_skip_quotes(p);
427 +                               break;
428 +
429 +                       case 's':                       /* select statement */
430 +                               map->map_valcolnm = ++p;
431 +                               p = pgsql_skip_quotes(p);
432 +                               break;
433 +               }
434 +
435 +               if (*p != '\0')
436 +                       *p++ = '\0';
437 +       }
438 +
439 +       if (map->map_app != NULL)
440 +               map->map_app = newstr(map->map_app);
441 +
442 +       if (map->map_tapp != NULL)
443 +               map->map_tapp = newstr(map->map_tapp);
444 +       
445 +       if (map->map_keycolnm != NULL) { /* database connect string */
446 +               map->map_keycolnm = newstr(map->map_keycolnm);
447 +               stripquotes(map->map_keycolnm);
448 +               p = map->map_keycolnm;
449 +               while(*p==' ')
450 +                       p++;
451 +               map->map_keycolnm = p;
452 +       } else {
453 +               sm_syslog(LOG_WARNING, CurEnv->e_id, "No PostgreSQL connect string for %s map %s",
454 +                               map->map_class->map_cname, map->map_mname);
455 +               syserr("451 4.3.5 No PostgreSQL connect string for map %s",
456 +                               map->map_mname);
457 +               SM_SET_H_ERRNO(TRY_AGAIN);
458 +               errno = DB_NOTFOUND;
459 +               return false;
460 +       }
461 +
462 +       if (map->map_valcolnm != NULL) { /* select statement */
463 +               map->map_valcolnm = newstr(map->map_valcolnm);
464 +               stripquotes(map->map_valcolnm);
465 +               p = map->map_valcolnm;
466 +               while(*p==' ')
467 +                       p++;
468 +               map->map_valcolnm = p;
469 +       } else {
470 +               sm_syslog(LOG_WARNING, CurEnv->e_id, "No PostgreSQL select statement for %s map %s",
471 +                               map->map_class->map_cname, map->map_mname);
472 +               syserr("451 5.3.5 No PostgreSQL select statement for map %s",
473 +                               map->map_mname);
474 +               SM_SET_H_ERRNO(TRY_AGAIN);
475 +               errno = DB_NOTFOUND;
476 +               return false;
477 +       }
478 +
479 +       return true;
480 +}
481 +
482 +#if 0
483 +/*
484 + * search our list of map connections for a entry that matches our
485 + * connection.  it should have the same host and connection string, as well
486 + * as the same PID.  someone can choose to put their maps on different
487 + * databases, so we cannot share a connection.
488 + */
489 +
490 +PGconn *pgsql_getconn(char *connstr, char *mapname)
491 +{
492 +       pid_t p = getpid();
493 +       
494 +       // if no map has been allocated, return immediately
495 +       if(!pgsqlmap) return NULL;
496 +
497 +       // rewind
498 +       while(pgsqlmap->p) pgsqlmap = pgsqlmap->p;
499 +
500 +       #ifdef PGSQLDEBUG
501 +       sm_syslog(LOG_INFO, CurEnv->e_id, "pgsql_getconn (connection string:%s, pid:%i)", connstr, p);
502 +       #endif
503 +
504 +       // only return connections that match everything                        
505 +       do
506 +       {
507 +               if(pgsqlmap->conn)
508 +                       if (!strncmp(connstr, pgsqlmap->connstr, strlen(connstr)+1))
509 +                               if (pgsqlmap->opener_pid == p)
510 +                                       if (!strncmp(pgsqlmap->mapname, mapname, strlen(mapname))
511 +                                               return pgsqlmap->conn;
512 +
513 +               // if there is more than one map and we're still searching, bump to the next one
514 +               if (pgsqlmap->n)
515 +                       pgsqlmap = pgsqlmap->n;
516 +               else
517 +                       break;
518 +       } while(1);
519 +
520 +       return NULL;
521 +}
522 +
523 +/*
524 + * add a new map entry structure and populate it
525 + */
526 +void pgsql_addconn(char *host, char *connstr, PGconn *conn, mapname)
527 +{
528 +       int count=1;
529 +       
530 +       if (!pgsqlmap)
531 +               // create a brand new map structure
532 +               pgsqlmap= (struct pgsqlmap *) xalloc(sizeof(struct pgsqlmap));
533 +       
534 +       else
535 +       {
536 +               // fast-forward to the end of the list
537 +               while(pgsqlmap->n)
538 +               {
539 +                       count++;
540 +                       pgsqlmap = pgsqlmap->n;
541 +               }
542 +
543 +               pgsqlmap->n     = (struct pgsqlmap *) xalloc(sizeof(struct pgsqlmap));
544 +               pgsqlmap->n->p  = pgsqlmap;
545 +               pgsqlmap        = pgsqlmap->n;
546 +       }
547 +
548 +       bzero(pgsqlmap, sizeof(struct pgsqlmap));
549 +       pgsqlmap->connstr       =connstr;
550 +       pgsqlmap->conn              =conn;
551 +       pgsqlmap->opener_pid    =getpid();
552 +       pgsqlmap->mapname       =mapname;
553 +
554 +       #ifdef PGSQLDEBUG
555 +       sm_syslog(LOG_INFO, CurEnv->e_id, "pgsql_ add map connection (connection string:%s, connptr:%p, pid:%i), maplist size is %i",
556 +                       pgsqlmap->connstr, pgsqlmap->conn, pgsqlmap->opener_pid, count);
557 +       #endif
558 +}
559 +
560 +int psql_removeconn(PGconn *conn, char *mapname)
561 +{
562 +       if(!pgsqlmap) return 0;
563 +
564 +       while(pgsqlmap->p) pgsqlmap = pgsqlmap->p;
565 +
566 +       do
567 +       {
568 +               if (pgsqlmap->conn == conn && !strncmp(pgsqlmap->mapname, mapname, strlen(mapname))
569 +               {
570 +                       // the map data doesn't belong to us, just deallocate the map pointer
571 +                       struct pgsqlmap *z = pgsqlmap;
572 +
573 +                       #ifdef PGSQLDEBUG
574 +                               sm_syslog(LOG_INFO, CurEnv->e_id, "pgsql_ delete map connection (connection string:%s, connptr:%p, pid:%i)",
575 +                       pgsqlmap->connstr, pgsqlmap->conn, pgsqlmap->opener_pid);
576 +                       #endif
577 +
578 +                       if (z->p && z->n)
579 +                       {
580 +                               z->p->n = z->n;
581 +                               z->n->p = z->p;
582 +                               free(z);
583 +                               pgsqlmap = pgsqlmap->n;
584 +                               return 1;
585 +                       }
586 +
587 +                       else if (z->p)
588 +                       {
589 +                               z->p->n = NULL;
590 +                               free(z);
591 +                               pgsqlmap = pgsqlmap->p;
592 +                               return 1;
593 +                       }
594 +
595 +                       else if (z->n)
596 +                       {
597 +                               z->n->p = NULL;
598 +                               free(z);
599 +                               pgsqlmap = pgsqlmap->n;
600 +                               return 1;
601 +                       }
602 +                       
603 +                       // only return 1 if no map references are left so the pgsql connection can be shut down
604 +                       else
605 +                       {
606 +                               free(z);
607 +                               pgsqlmap = NULL;
608 +                               return 1;
609 +                       }
610 +                               
611 +               }
612 +
613 +               if (pgsqlmap->n)
614 +                       pgsqlmap = pgsqlmap->n;
615 +               else
616 +                       break;
617 +       } while(1);
618 +       
619 +       // no maps found
620 +       return 0;
621 +}
622 +#endif
623 +
624 +/*
625 + * Open a PostgreSQL database connection using the connection string, the
626 + * mode parameter is entirely ignored - it has no purpose in SQL.
627 + *
628 + * Returns TRUE if the database was opened or FALSE if it choked
629 + */
630 +bool pgsql_map_open(MAP *map, int mode)
631 +{
632 +       char *s= NULL;
633 +       int n, retries;
634 +
635 +       /*
636 +        * each map can have a different connection, so we can't easily share
637 +        * it.  further, each connection is protected between thread instances.
638 +        */
639 +
640 +       /*
641 +        * this is the most likely test so it comes first.  we have a connection
642 +        * to the server, if the status appears good, return.  note: the status
643 +        * may be misleading, the server may have crashed underneath us or
644 +        * terminated our connection for any of several reasons.  we won't know
645 +        * that until we actually use it however.
646 +        */
647 +       if (map->map_db1 && PQstatus(map->map_db1) == CONNECTION_OK)
648 +       {
649 +               // the connection is shared between all maps, we don't need to differentiate
650 +               #ifdef PGSQLDEBUG
651 +               sm_syslog(LOG_INFO, CurEnv->e_id, "Connection is good (connection string:%s, connptr:%p)",
652 +                               map->map_keycolnm, map->map_db1);
653 +               #endif
654 +               
655 +               return true;
656 +       }
657 +
658 +       #ifdef PGSQLDEBUG
659 +       if (!map->map_db1 || PQstatus(map->map_db1) == CONNECTION_BAD)
660 +               sm_syslog(LOG_INFO, CurEnv->e_id, "Connection to SQL server not found or stale for map:%s, looking for a new one", map->map_mname);
661 +       #endif
662 +
663 +       retries=10;
664 +       while ((!map->map_db1 || PQstatus(map->map_db1) == CONNECTION_BAD) && retries-- >0)
665 +       {
666 +               /*
667 +                * now either conn is still null (not yet allocated), or our connection
668 +                * is bad.  synchronous connections only have _OK or _BAD.  looks like
669 +                * we have to reset or make a new connection.  allocate space and try to
670 +                * connect
671 +                */
672 +               if (!map->map_db1)
673 +               {
674 +                       map->map_db1 = PQconnectdb(map->map_keycolnm);
675 +                       PQsetErrorVerbosity(map->map_db1, PQERRORS_VERBOSE);
676 +                       //pgsql_addconn(map->map_keycolnm, map->map_db1, map->map_mname);
677 +                       map->map_pid = getpid(); /* save PID for check on close */
678 +               }
679 +
680 +               else
681 +                       PQreset(map->map_db1);
682 +       
683 +               if (!map->map_db1)
684 +               {
685 +                       sm_syslog(LOG_WARNING, CurEnv->e_id, "Cannot open %s map %s using %s, attempt %i",
686 +                                       map->map_class->map_cname, map->map_mname, map->map_keycolnm, 10-retries);
687 +               }
688 +
689 +               if (PQstatus(map->map_db1) == CONNECTION_BAD)
690 +               {
691 +                       sm_syslog(LOG_WARNING, CurEnv->e_id, "Cannot open %s map %s using %s (%s), attempt %i",
692 +                                       map->map_class->map_cname, map->map_mname, map->map_keycolnm,
693 +                                       PQerrorMessage(map->map_db1), 10-retries);
694 +               }
695 +       }
696 +
697 +       if (!map->map_db1 || PQstatus(map->map_db1) == CONNECTION_BAD)
698 +       {
699 +               syserr("451 4.3.5 Map database unreachable");
700 +               if (map->map_db1)
701 +               {
702 +                       //psql_removeconn(conn, map->map_mname);
703 +                       PQfinish(map->map_db1);
704 +                       map->map_db1 = NULL;
705 +               }
706 +               
707 +               errno = DB_NOTFOUND;
708 +               SM_SET_H_ERRNO(TRY_AGAIN);
709 +               
710 +               return false;
711 +       }
712 +       
713 +       return true;
714 +}      
715 +
716 +/*
717 + * Close the PostgreSQL database connection, check that the opening process
718 + * is the closing process; ignore if not.
719 + */
720 +void pgsql_map_close(MAP *map)
721 +{
722 +       int r;
723 +       
724 +       if (map->map_pid == getpid())
725 +       {
726 +               //conn = map->map_db1;
727 +/*
728 +               r = psql_removeconn(conn, map->map_mname);
729 +               if(r)
730 +               {
731 +*/                     PQfinish(map->map_db1);
732 +                       map->map_db1 = NULL;
733 +                       #ifdef PGSQLDEBUG
734 +                       sm_syslog(LOG_INFO, CurEnv->e_id, "Closed connection for map %s", map->map_mname);
735 +                       #endif
736 +/*             }
737 +
738 +               #ifdef PGSQLDEBUG
739 +               else
740 +                       sm_syslog(LOG_INFO, CurEnv->e_id, "No connection found for map: %s", map->map_mname);
741 +               #endif
742 +*/     }
743 +}
744 +
745 +/*
746 +** PGSQL_MAP_LOOKUP -- look up a datum in a PGSQL map
747 +**
748 +** Attempt to map an incoming key value with a PostgreSQL query.
749 +**
750 +** This performs the query specified in the Sendmail config file and
751 +** uses the value of the first row and column as the map data value.
752 +** All other rows and columns are ignored.
753 +*/
754 +char *
755 +pgsql_map_lookup(MAP *map, char *name, char **av, int *statp)
756 +{
757 +       int len,esc_len,ntuples,r,retries;
758 +       char *format,*workingbuf,*trustedbuf;
759 +       char sname[MAXNAME+1];
760 +       char resbuf[MAXNAME+1];
761 +       PGresult *res;
762 +
763 +       /*
764 +        * Check the backend to make sure it's still valid.     If it's not, try and
765 +        * reset the connection.
766 +        */
767 +       if (!map->map_db1 || PQstatus(map->map_db1) == CONNECTION_BAD)
768 +       {
769 +               #ifdef PGSQLDEBUG
770 +               sm_syslog(LOG_INFO, NOQID, "Connection bad for map: %s, reconnecting to SQL server using: %s", map->map_mname, map->map_keycolnm);
771 +               #endif
772 +               if (!pgsql_map_open(map, 0))
773 +               {
774 +                       #ifdef PGSQLDEBUG
775 +                       sm_syslog(LOG_INFO, CurEnv->e_id, "dbg> aborting map lookup");
776 +                       #endif
777 +                       return NULL;
778 +               }
779 +       }                               
780 +
781 +       bzero(sname,sizeof sname);
782 +       bzero(resbuf,sizeof resbuf);
783 +
784 +       /* Buffer overflow check. */
785 +       len = strlen(name);
786 +       if (len > MAXNAME)
787 +               len = MAXNAME;
788 +       bcopy(name,sname,len);
789 +       
790 +       if (!bitset(MF_NOFOLDCASE, map->map_mflags))
791 +       {
792 +               //#ifdef PGSQLDEBUG
793 +               //sm_syslog(LOG_INFO, CurEnv->e_id, "dbg> making querystring value lowercase");
794 +               //#endif
795 +               makelower(sname);
796 +       }
797 +
798 +       /* Allocate query buffer (select statement + key value) */
799 +       len                      = strlen(map->map_valcolnm);
800 +       esc_len      = strlen(sname);
801 +       workingbuf       = xalloc(esc_len*2+1+9);
802 +       trustedbuf   = xalloc(len+(esc_len*2)+1+9);
803 +       bzero(trustedbuf,len);
804 +
805 +       // escape untrusted data passed to us from network
806 +       PQescapeStringConn(map->map_db1, trustedbuf, sname, strlen(sname), NULL);
807 +       
808 +       // if MF_NOFOLDCASE is set, don't wrap this in lower()
809 +       if (!bitset(MF_NOFOLDCASE, map->map_mflags))
810 +               format="lower('%s')";
811 +       else
812 +               format="'%s'";
813 +       
814 +       sprintf(workingbuf, format, trustedbuf);
815 +       sprintf(trustedbuf, map->map_valcolnm, workingbuf);
816 +       free(workingbuf);
817 +       
818 +       #ifdef PGSQLDEBUG
819 +       sm_syslog(LOG_INFO, CurEnv->e_id, "dbg-sql> %s", trustedbuf);
820 +       #endif
821 +       
822 +       retries = 2;
823 +       while (retries--)
824 +       {
825 +               res = PQexec(map->map_db1, trustedbuf);
826 +               if (PQresultStatus(res) == PGRES_TUPLES_OK)
827 +                       break;
828 +
829 +               sm_syslog(LOG_WARNING, CurEnv->e_id, "Cannot query PGSQL database (attempt:%i) \"%s\" using \"%s\" because of: %s",
830 +                               10-retries, map->map_keycolnm, trustedbuf, PQresultErrorMessage(res));
831 +               PQclear(res);
832 +
833 +               // try to reset connection
834 +               if (!pgsql_map_open(map, 0))
835 +               {
836 +                       #ifdef PGSQLDEBUG
837 +                       sm_syslog(LOG_INFO, CurEnv->e_id, "dbg> aborting map lookup");
838 +                       #endif
839 +                       return NULL;
840 +               }
841 +       }
842 +
843 +       if (!map->map_db1 || PQresultStatus(res) != PGRES_TUPLES_OK)
844 +       {
845 +               syserr("451 4.3.1 Cannot query PGSQL database");
846 +               SM_SET_H_ERRNO(TRY_AGAIN);
847 +               errno = DB_NOTFOUND;
848 +               free(trustedbuf);
849 +               return NULL;
850 +       }
851 +
852 +       /*
853 +        * See if anything came back. If no rows were returned, nothing there for
854 +        * this query.
855 +        */
856 +       ntuples = PQntuples(res);
857 +       #ifdef PGSQLDEBUG
858 +       sm_syslog(LOG_INFO, CurEnv->e_id, "dbg> finishing map lookup, ntuples:%i", ntuples);
859 +       #endif
860 +
861 +       if (ntuples <= 0)
862 +       {
863 +               PQclear(res);
864 +               return NULL;
865 +       }
866 +
867 +       /*
868 +        * Get the result from column 0 and clear the rest of the result.
869 +        * If the result data is too big, then it's truncated.
870 +        */     
871 +       len = PQgetlength(res,0,0);
872 +       if (len > MAXNAME)
873 +               len = MAXNAME;
874 +       bcopy(PQgetvalue(res,0,0),resbuf,len);
875 +       PQclear(res);
876 +
877 +       /* Process results like the other map classes do. */
878 +
879 +       #ifdef PGSQLDEBUG
880 +       sm_syslog(LOG_INFO, CurEnv->e_id, "dbg> finishing map lookup, result:\"%s\"", resbuf);
881 +       #endif
882 +
883 +       if (bitset(MF_MATCHONLY, map->map_mflags))
884 +               return map_rewrite(map, name, strlen(name), NULL);
885 +       else
886 +               return map_rewrite(map, resbuf, len, av);
887 +}
888 +#endif /* PGSQLMAP */
889  /*
890  **  PH map
891  */
This page took 0.133041 seconds and 3 git commands to generate.