1 /*
2  * $Id: vpgsql.c 1014 2011-02-03 16:04:37Z volz0r $
3  * Copyright (C) 1999-2009 Inter7 Internet Technologies, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  */
19 #include <ctype.h>
20 #include <pwd.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <time.h>
27 #include <errno.h>
28 #include <libpq-fe.h> /* required pgsql front-end headers */
29 
30 #include "config.h"
31 #include "vpopmail.h"
32 #include "vauth.h"
33 #include "vlimits.h"
34 #include "vpgsql.h"
35 
36 //  Variables to control debug output
37 #ifdef VPOPMAIL_DEBUG
38 int show_trace=0;
39 int show_query=0;
40 int dump_data=0;
41 #endif
42 
43 /* pgsql has no built-in replication, yet.
44    #ifdef PGSQL_REPLICATION
45    static PGconn *pgc_read;
46    #else
47    #define pgc_read pgc_update
48    #endif
49 
50    #ifdef PGSQL_REPLICATION
51    static int read_open = 0;
52    #else
53    #define read_open update_open
54    #endif
55    #ifdef PGSQL_REPLICATION
56    static PGresult *res_read = NULL;
57    #else
58    #define res_read res_update
59    #endif
60 */
61 
62 /*
63    read-only and read-write connections
64    to be implemented later...
65 static PGconn *pgc_update;
66 static PGconn *pgc_read;
67 static PGconn *pgc_read_getall;
68 */
69 
70 static PGconn *pgc; /* pointer to pgsql connection */
71 static int is_open = 0;
72 
73 #define SQL_BUF_SIZE 2048
74 static char SqlBufRead[SQL_BUF_SIZE];
75 static char SqlBufUpdate[SQL_BUF_SIZE];
76 
77 #define SMALL_BUFF 200
78 char IUser[SMALL_BUFF];
79 char IPass[SMALL_BUFF];
80 char IGecos[SMALL_BUFF];
81 char IDir[SMALL_BUFF];
82 char IShell[SMALL_BUFF];
83 char IClearPass[SMALL_BUFF];
84 
85 void vcreate_dir_control(char *domain);
86 void vcreate_vlog_table();
87 
88 #ifdef POP_AUTH_OPEN_RELAY
89 void vcreate_relay_table();
90 #endif
91 
92 #ifdef VALIAS
93 void vcreate_valias_table();
94 #endif
95 
96 #ifdef ENABLE_AUTH_LOGGING
97 void vcreate_lastauth_table();
98 #endif
99 
100 /* pgsql BEGIN TRANSACTION ********/
pg_begin(void)101 int pg_begin(void)
102 {
103   PGresult *pgres;
104   pgres=PQexec(pgc, "BEGIN");
105   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
106     fprintf(stderr, "pg_begin: %s\n", PQerrorMessage(pgc));
107     if (pgres) PQclear (pgres);
108     return -1;
109   }
110   PQclear(pgres);
111   return 0;
112 }
113 
114 /* pgsql END TRANSACTION ********/
pg_end(void)115 int pg_end(void)
116 {
117   PGresult *pgres;
118   pgres=PQexec(pgc, "END");
119   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
120     fprintf(stderr, "pg_end: %s\n", PQerrorMessage(pgc));
121     if (pgres) PQclear (pgres);
122     return -1;
123   }
124   PQclear(pgres);
125   return 0;
126 }
127 
128 /*** Open a connection to pgsql ***/
vauth_open(int will_update)129 int vauth_open( int will_update )
130 {
131 #ifdef VPOPMAIL_DEBUG
132 show_trace = ( getenv("VPSHOW_TRACE") != NULL);
133 show_query = ( getenv("VPSHOW_QUERY") != NULL);
134 dump_data  = ( getenv("VPDUMP_DATA")  != NULL);
135 #endif
136 
137 #ifdef VPOPMAIL_DEBUG
138     if( show_trace ) {
139         fprintf( stderr, "vauth_open(%d)\n",will_update);
140     }
141 #endif
142 
143 
144 /*
145  *  If the connection to this authentication database can fail
146  *  you should test access here.  If it works, return 0, else
147  *  return VA_NO_AUTH_CONNECTION.  You can also set the string
148  *  sqlerr to some short descriptive text about the problem,
149  *  and allocate a much longer string, pointed to by last_query
150  *  that can be displayed in an error message returned because
151  *  of this problem.
152  *
153  */
154 
155   if ( is_open != 0 ) return(0);
156   is_open = 1;
157   verrori = 0;
158 
159   /* Try to connect to the pgserver with the specified database. */
160   pgc = PQconnectdb(PG_CONNECT);
161   if( PQstatus(pgc) == CONNECTION_BAD) {
162     fprintf(stderr, "vauth_open: can't connect: %s\n", PQerrorMessage(pgc));
163     return VA_NO_AUTH_CONNECTION;
164   }
165   return(0);
166 }
167 
vauth_create_table(char * table,char * layout,int showerror)168 int vauth_create_table (char *table, char *layout, int showerror)
169 {
170   int err;
171   PGresult *pgres;
172   char SqlBufCreate[SQL_BUF_SIZE];
173 
174   if ((err = vauth_open(1))) return (err);
175 
176   snprintf(SqlBufCreate, SQL_BUF_SIZE,
177     "CREATE TABLE %s ( %s )", table, layout);
178   pgres=PQexec(pgc, SqlBufCreate);
179   if (!pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK) {
180     err = -1;
181     if (showerror)
182       fprintf (stderr, "vpgsql: error creating table '%s': %s\n", table,
183         PQerrorMessage(pgc));
184   } else err = 0;
185 
186   if (pgres) PQclear (pgres);
187   return err;
188 }
189 
vauth_adddomain(char * domain)190 int vauth_adddomain( char *domain )
191 {
192 #ifndef MANY_DOMAINS
193   vset_default_domain( domain );
194   return (vauth_create_table (vauth_munch_domain( domain ), TABLE_LAYOUT, 1));
195 #else
196   /* if creation fails, don't show an error */
197   vauth_create_table (PGSQL_DEFAULT_TABLE, TABLE_LAYOUT, 0);
198   return (0);
199 #endif
200 }
201 
vauth_adduser(char * user,char * domain,char * pass,char * gecos,char * dir,int apop)202 int vauth_adduser(char *user, char *domain, char *pass, char *gecos,
203 		  char *dir, int apop )
204 {
205   char *domstr;
206   char dom_dir[156];
207   uid_t uid;
208   gid_t gid;
209   char dirbuf[200];
210   char quota[30];
211   char Crypted[100];
212   int err;
213   PGresult *pgres;
214 
215   if ( (err=vauth_open(1)) != 0 ) return(err);
216   vset_default_domain( domain );
217 
218   strncpy( quota, "NOQUOTA", 30 );
219 
220 #ifndef MANY_DOMAINS
221   domstr = vauth_munch_domain( domain );
222 #else
223   domstr = PGSQL_DEFAULT_TABLE;
224 #endif
225   if ( domain == NULL || domain[0] == 0 ) {
226     domstr = PGSQL_LARGE_USERS_TABLE;
227   }
228 
229   *dirbuf = '\0';
230 
231   if ( strlen(domain) <= 0 ) {
232     if ( strlen(dir) > 0 ) {
233       snprintf(dirbuf, sizeof(dirbuf),
234 	       "%s/users/%s/%s", VPOPMAILDIR, dir, user);
235     } else {
236       snprintf(dirbuf, sizeof(dirbuf), "%s/users/%s", VPOPMAILDIR, user);
237     }
238   } else {
239     vget_assign(domain, dom_dir, 156, &uid, &gid );
240     if ( strlen(dir) > 0 ) {
241       snprintf(dirbuf,sizeof(dirbuf), "%s/%s/%s", dom_dir, dir, user);
242     } else {
243       snprintf(dirbuf,sizeof(dirbuf), "%s/%s", dom_dir, user);
244     }
245   }
246 
247   if ( pass[0] != 0 ) {
248     mkpasswd3(pass,Crypted, 100);
249   } else {
250     Crypted[0] = 0;
251   }
252 
253   qnprintf( SqlBufUpdate, sizeof(SqlBufUpdate), INSERT,
254 	    domstr, user,
255 #ifdef MANY_DOMAINS
256 	    domain,
257 #endif
258 	    Crypted, apop, gecos, dirbuf, quota
259 #ifdef CLEAR_PASS
260 	    ,pass
261 #endif
262 	    );
263   if(! ( pgres=PQexec(pgc,SqlBufUpdate) )||
264      PQresultStatus(pgres)!=PGRES_COMMAND_OK )  {
265     fprintf(stderr, "vauth_adduser: %s\npgsql: %s\n",
266 	    SqlBufUpdate, PQerrorMessage(pgc));
267   }
268   if( pgres )  PQclear(pgres);
269   return(0);
270 
271 }
vauth_getpw(char * user,char * domain)272 struct vqpasswd *vauth_getpw(char *user, char *domain)
273 {
274   char in_domain[156];
275   char *domstr;
276   static struct vqpasswd vpw;
277   int err;
278   PGresult *pgres;
279 
280   verrori = 0;
281   if ( (err=vauth_open(0)) != 0 ) {
282     verrori = err;
283     return(NULL);
284   }
285   lowerit(user);
286   lowerit(domain);
287 
288   snprintf (in_domain, sizeof(in_domain), "%s", domain);
289 
290   vset_default_domain( in_domain );
291 
292 #ifndef MANY_DOMAINS
293   domstr = vauth_munch_domain( in_domain );
294 #else
295   domstr = PGSQL_DEFAULT_TABLE;
296 #endif
297 
298   if ( domstr == NULL || domstr[0] == 0 ) {
299     domstr = PGSQL_LARGE_USERS_TABLE;
300   }
301 
302   qnprintf(SqlBufRead, SQL_BUF_SIZE, USER_SELECT, domstr, user
303 #ifdef MANY_DOMAINS
304 	   ,in_domain
305 #endif
306 	   );
307   pgres=PQexec(pgc, SqlBufRead);
308   if ( ! pgres || PQresultStatus(pgres)!=PGRES_TUPLES_OK) {
309     if( pgres ) PQclear(pgres);
310 #ifdef DEBUG
311     fprintf(stderr,
312 	    "vauth_getpw: failed select: %s : %s\n",
313 	    SqlBufRead, PQerrorMessage(pgc));
314 #endif
315     return NULL;
316   }
317   if ( PQntuples(pgres) <= 0 ) { /* rows count */
318     PQclear(pgres);
319     return NULL;
320   }
321 
322   memset(IUser, 0, sizeof(IUser));
323   memset(IPass, 0, sizeof(IPass));
324   memset(IGecos, 0, sizeof(IGecos));
325   memset(IDir, 0, sizeof(IDir));
326   memset(IShell, 0, sizeof(IShell));
327   memset(IClearPass, 0, sizeof(IClearPass));
328 
329   vpw.pw_name   = IUser;
330   vpw.pw_passwd = IPass;
331   vpw.pw_gecos  = IGecos;
332   vpw.pw_dir    = IDir;
333   vpw.pw_shell  = IShell;
334   vpw.pw_clear_passwd  = IClearPass;
335 
336   strncpy(vpw.pw_name,PQgetvalue( pgres, 0, 0 ),SMALL_BUFF);
337   strncpy(vpw.pw_passwd,PQgetvalue( pgres, 0, 1 ),SMALL_BUFF);
338   vpw.pw_uid    = atoi(PQgetvalue( pgres, 0, 2 ));
339   vpw.pw_gid    = atoi(PQgetvalue( pgres, 0, 3 ));
340   strncpy(vpw.pw_gecos,PQgetvalue( pgres, 0, 4 ),SMALL_BUFF);
341   strncpy(vpw.pw_dir,PQgetvalue( pgres, 0, 5 ),SMALL_BUFF);
342   strncpy(vpw.pw_shell, PQgetvalue( pgres, 0, 6 ),SMALL_BUFF);
343 #ifdef CLEAR_PASS
344   if ( PQgetvalue( pgres, 0, 7 ) != 0 )
345     strncpy(vpw.pw_clear_passwd, PQgetvalue( pgres, 0, 7 ),SMALL_BUFF);
346 #endif
347 
348   vlimits_setflags (&vpw, in_domain);
349 
350   return(&vpw);
351 }
352 
vauth_deldomain(char * domain)353 int vauth_deldomain( char *domain )
354 {
355   PGresult *pgres;
356   char *tmpstr;
357   int err;
358 
359   if ( (err=vauth_open(1)) != 0 ) return(err);
360   vset_default_domain( domain );
361 
362 #ifndef MANY_DOMAINS
363   tmpstr = vauth_munch_domain( domain );
364   snprintf( SqlBufUpdate, SQL_BUF_SIZE, "drop table %s", tmpstr);
365 #else
366   tmpstr = PGSQL_DEFAULT_TABLE;
367   qnprintf(SqlBufUpdate,SQL_BUF_SIZE,
368 	   "delete from %s where pw_domain = '%s'",
369 	   tmpstr, domain );
370 #endif
371   pgres=PQexec(pgc, SqlBufUpdate);
372   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK){
373     fprintf(stderr,"vauth_deldomain: pgsql query: %s",
374 	    PQerrorMessage(pgc));
375     if(pgres) PQclear(pgres);
376     return(-1);
377   }
378   if(pgres) PQclear(pgres);
379 
380 #ifdef VALIAS
381     valias_delete_domain( domain);
382 #endif
383 
384 #ifdef ENABLE_AUTH_LOGGING
385     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
386         "delete from lastauth where domain = '%s'", domain );
387     pgres=PQexec(pgc, SqlBufUpdate);
388     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK) {
389       return(-1);
390     }
391     if(pgres) PQclear(pgres);
392 #endif
393 
394 #ifdef ENABLE_SQL_LOGGING
395 #ifdef ENABLE_SQL_REMOVE_DELETED
396     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
397        "delete from vlog where domain = '%s'", domain );
398     pgres=PQexec(pgc, SqlBufUpdate);
399     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK) {
400       return(-1);
401     }
402 #endif
403 #endif
404     return(0);
405 }
406 
vauth_deluser(char * user,char * domain)407 int vauth_deluser( char *user, char *domain )
408 {
409   PGresult *pgres;
410   char *tmpstr;
411   int err = 0;
412 
413   if ( (err=vauth_open(1)) != 0 ) return(err);
414   vset_default_domain( domain );
415 
416 #ifndef MANY_DOMAINS
417   if ( domain == NULL || domain[0] == 0 ) {
418     tmpstr = PGSQL_LARGE_USERS_TABLE;
419   } else {
420     tmpstr = vauth_munch_domain( domain );
421   }
422 #else
423   tmpstr = PGSQL_DEFAULT_TABLE;
424 #endif
425 
426   qnprintf( SqlBufUpdate, SQL_BUF_SIZE, DELETE_USER, tmpstr, user
427 #ifdef MANY_DOMAINS
428 	    , domain
429 #endif
430 	    );
431 
432   pgres=PQexec(pgc, SqlBufUpdate);
433   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
434     err = -1;
435   }
436   if( pgres ) PQclear(pgres);
437 
438 #ifdef ENABLE_AUTH_LOGGING
439   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
440 	    "delete from lastauth where user = '%s' and domain = '%s'",
441 	    user, domain );
442   pgres=PQexec(pgc, SqlBufUpdate);
443   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
444     err = -1;
445   }
446   if( pgres ) PQclear(pgres);
447 #endif
448 
449 #ifdef ENABLE_SQL_LOGGING
450 #ifdef ENABLE_SQL_REMOVE_DELETED
451     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
452         "delete from vlog where domain = '%s' and user='%s'",
453        domain, user );
454     pgres=PQexec(pgc, SqlBufUpdate);
455     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK) {
456       err = -1;
457     }
458 #endif
459 #endif
460 
461   return(err);
462 }
463 
vauth_setquota(char * username,char * domain,char * quota)464 int vauth_setquota( char *username, char *domain, char *quota)
465 {
466   PGresult *pgres;
467   char *tmpstr;
468   int err;
469 
470   if ( strlen(username) > MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);
471 #ifdef USERS_BIG_DIR
472   if ( strlen(username) == 1 ) return(VA_ILLEGAL_USERNAME);
473 #endif
474   if ( strlen(domain) > MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);
475   if ( strlen(quota) > MAX_PW_QUOTA )    return(VA_QUOTA_TOO_LONG);
476 
477   if ( (err=vauth_open(1)) != 0 ) return(err);
478   vset_default_domain( domain );
479 
480 #ifndef MANY_DOMAINS
481   tmpstr = vauth_munch_domain( domain );
482 #else
483   tmpstr = PGSQL_DEFAULT_TABLE;
484 #endif
485 
486   qnprintf( SqlBufUpdate, SQL_BUF_SIZE, SETQUOTA, tmpstr, quota, username
487 #ifdef MANY_DOMAINS
488 	    , domain
489 #endif
490 	    );
491 
492   pgres = PQexec(pgc, SqlBufUpdate);
493   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
494     fprintf(stderr,
495 	    "vauth_setquota: query failed: %s\n", PQerrorMessage(pgc));
496     if( pgres ) PQclear(pgres);
497     return(-1);
498   }
499   if( pgres ) PQclear(pgres);
500   return(0);
501 }
502 
vauth_getall(char * domain,int first,int sortit)503 struct vqpasswd *vauth_getall(char *domain, int first, int sortit)
504 {
505   static PGresult *pgres=NULL;
506   /* ntuples - number of tuples ctuple - current tuple */
507   static unsigned ntuples=0, ctuple=0;
508 
509   char *domstr = NULL;
510   static struct vqpasswd vpw;
511   int err;
512 
513   vset_default_domain( domain );
514 
515 #ifdef MANY_DOMAINS
516   domstr = PGSQL_DEFAULT_TABLE;
517 #else
518   domstr = vauth_munch_domain( domain );
519 #endif
520 
521   if ( first == 1 ) {
522     if ( (err=vauth_open(0)) != 0 ) return(NULL);
523     qnprintf(SqlBufRead,  SQL_BUF_SIZE, GETALL, domstr
524 #ifdef MANY_DOMAINS
525 	     ,domain
526 #endif
527 	     );
528     if ( sortit == 1 ) {
529       strncat( SqlBufRead, " order by pw_name", SQL_BUF_SIZE);
530     }
531     if ( pgres ) { /* reset state if we had previous result */
532       PQclear(pgres);    // clear previous result
533       pgres=NULL;
534       ntuples=ctuple=0;
535     }
536     pgres = PQexec(pgc, SqlBufRead);
537     if( !pgres || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
538       fprintf(stderr, "vauth_getall:query failed[5]: %s\n", PQerrorMessage(pgc));
539       if( pgres ) {
540         PQclear(pgres);
541         pgres=NULL;
542       }
543       return (NULL);
544     }
545     ntuples = PQntuples( pgres );
546   }
547 
548   if ( ctuple == ntuples ) {
549     PQclear(pgres);
550     pgres=NULL;
551     ctuple=ntuples=0;
552     return NULL;
553   }
554   memset(IUser, 0, sizeof(IUser));
555   memset(IPass, 0, sizeof(IPass));
556   memset(IGecos, 0, sizeof(IGecos));
557   memset(IDir, 0, sizeof(IDir));
558   memset(IShell, 0, sizeof(IShell));
559   memset(IClearPass, 0, sizeof(IClearPass));
560 
561   vpw.pw_name   = IUser;
562   vpw.pw_passwd = IPass;
563   vpw.pw_gecos  = IGecos;
564   vpw.pw_dir    = IDir;
565   vpw.pw_shell  = IShell;
566   vpw.pw_clear_passwd  = IClearPass;
567 
568   strncpy(vpw.pw_name, PQgetvalue( pgres, ctuple, 0 ),SMALL_BUFF );
569   strncpy(vpw.pw_passwd, PQgetvalue( pgres, ctuple, 1 ),SMALL_BUFF );
570 
571   vpw.pw_uid    = atoi(PQgetvalue( pgres, ctuple, 2 ));
572   vpw.pw_gid    = atoi(PQgetvalue( pgres, ctuple, 3 ));
573 
574   strncpy(vpw.pw_gecos, PQgetvalue( pgres, ctuple, 4 ),SMALL_BUFF);
575   strncpy(vpw.pw_dir, PQgetvalue( pgres, ctuple, 5 ),SMALL_BUFF);
576   strncpy(vpw.pw_shell, PQgetvalue( pgres, ctuple, 6 ),SMALL_BUFF);
577 
578 #ifdef CLEAR_PASS
579     if (PQgetvalue( pgres, ctuple, 7)!= 0 ) {
580       strncpy(vpw.pw_clear_passwd, PQgetvalue( pgres, ctuple, 7 ),SMALL_BUFF);
581     }
582 #endif
583     ctuple++;
584     vlimits_setflags(&vpw,domain);
585     return(&vpw);
586 }
587 
vauth_end_getall()588 void vauth_end_getall()
589 {
590   /* not applicable in pgsql? */
591 }
592 
vauth_munch_domain(char * domain)593 char *vauth_munch_domain( char *domain )
594 {
595   int i;
596   static char tmpbuf[512];
597 
598   if ( domain == NULL || domain[0] == 0 ) return(domain);
599 
600   for(i=0;domain[i]!=0 && i < (sizeof(tmpbuf) - 1);++i){
601     tmpbuf[i] = tolower(domain[i]);
602     if ( domain[i] == '.' || domain[i] == '-' ) {
603       tmpbuf[i] = SQL_DOT_CHAR;
604     }
605   }
606   tmpbuf[i] = 0;
607   return(tmpbuf);
608 }
609 
vauth_setpw(struct vqpasswd * inpw,char * domain)610 int vauth_setpw( struct vqpasswd *inpw, char *domain )
611 {
612   PGresult *pgres;
613   char *tmpstr;
614   uid_t myuid;
615   uid_t uid;
616   gid_t gid;
617   int err;
618 
619   err = vcheck_vqpw(inpw, domain);
620   if ( err != 0 ) return(err);
621 
622   vget_assign(domain,NULL,0,&uid,&gid);
623   myuid = geteuid();
624   if ( myuid != 0 && myuid != uid ) {
625     return(VA_BAD_UID);
626   }
627 
628   if ( (err=vauth_open(1)) != 0 ) return(err);
629   vset_default_domain( domain );
630 
631 #ifndef MANY_DOMAINS
632   tmpstr = vauth_munch_domain( domain );
633 #else
634   tmpstr = PGSQL_DEFAULT_TABLE;
635 #endif
636 
637   qnprintf( SqlBufUpdate,SQL_BUF_SIZE,SETPW,
638             tmpstr,
639             inpw->pw_passwd,
640             inpw->pw_uid,
641             inpw->pw_gid,
642             inpw->pw_gecos,
643             inpw->pw_dir,
644             inpw->pw_shell,
645 #ifdef CLEAR_PASS
646             inpw->pw_clear_passwd,
647 #endif
648             inpw->pw_name
649 #ifdef MANY_DOMAINS
650             ,domain
651 #endif
652             );
653   pgres=PQexec(pgc, SqlBufUpdate);
654   if ( !pgres || PQresultStatus(pgres)!= PGRES_COMMAND_OK ) {
655     fprintf(stderr, "vauth_setpw: pgsql query[6]: %s\n",
656 	    PQerrorMessage(pgc));
657     if( pgres )  PQclear(pgres);
658     return(-1);
659   }
660   if( pgres ) PQclear(pgres);
661 #ifdef SQWEBMAIL_PASS
662     vsqwebmail_pass( inpw->pw_dir, inpw->pw_passwd, uid, gid);
663 #endif
664 
665 #ifdef ONCHANGE_SCRIPT
666     if( allow_onchange ) {
667        /* tell other programs that data has changed */
668        snprintf ( onchange_buf, MAX_BUFF, "%s@%s", inpw->pw_name, domain );
669        call_onchange ( "mod_user" );
670        }
671 #endif
672 
673     return(0);
674 }
675 
676 #ifdef POP_AUTH_OPEN_RELAY
vopen_smtp_relay()677 int vopen_smtp_relay()
678 {
679   PGresult *pgres;
680   char *ipaddr;
681   time_t mytime;
682   int err;
683 
684   mytime = time(NULL);
685   ipaddr = get_remote_ip();
686   if ( ipaddr == NULL ) {
687     return 0;
688   }
689 
690   if ( (err=vauth_open(1)) != 0 ) return 0;
691 
692   qnprintf(SqlBufUpdate, SQL_BUF_SIZE,
693     "UPDATE relay SET ip_addr='%s', timestamp=%d WHERE ip_addr='%s'",
694     ipaddr, (int)mytime, ipaddr);
695 
696   pgres=PQexec(pgc, SqlBufUpdate);
697   if (PQresultStatus(pgres) == PGRES_COMMAND_OK && atoi(PQcmdTuples(pgres)) == 0) {
698     if( pgres ) PQclear(pgres);
699 
700     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
701       "INSERT INTO relay (ip_addr, timestamp) VALUES ('%s', %lu)",
702       ipaddr, time(NULL));
703 
704     pgres=PQexec(pgc, SqlBufUpdate);
705     }
706 
707 /* UPDATE returned 0 rows and/or INSERT failed.  Try creating the table */
708   if(!pgres || PQresultStatus(pgres) != PGRES_COMMAND_OK) {
709     if( pgres ) PQclear(pgres);
710 
711     vcreate_relay_table();
712 
713 /* and try INSERTing now... */
714     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
715       "INSERT INTO relay (ip_addr, timestamp) VALUES ('%s', %lu)",
716       ipaddr, time(NULL));
717 
718     pgres=PQexec(pgc, SqlBufUpdate);
719     }
720 
721   if(pgres && PQresultStatus(pgres) == PGRES_COMMAND_OK ) {
722     /* need to return non-zero value if value inserted */
723     if( pgres ) PQclear(pgres);
724     return 1;
725   }
726 
727   if( pgres ) PQclear(pgres);
728   return 0;
729 }
730 
vupdate_rules(int fdm)731 void vupdate_rules(int fdm)
732 {
733   PGresult *pgres;
734   const char re[]=":allow,RELAYCLIENT=\"\",RBLSMTPD=\"\"\n";
735   register unsigned i=0, n, len=strlen(re)+1;
736   char *buf=NULL;
737 
738   if (vauth_open(0) != 0) return;
739 
740   snprintf(SqlBufRead, SQL_BUF_SIZE, "SELECT ip_addr FROM relay");
741   if ( !(pgres=PQexec(pgc, SqlBufRead)) || PQresultStatus(pgres)!=PGRES_TUPLES_OK) {
742     vcreate_relay_table();
743     if(pgres) PQclear(pgres);
744     if ( !(pgres=PQexec(pgc, SqlBufRead)) || PQresultStatus(pgres)!=PGRES_TUPLES_OK ) {
745       fprintf(stderr, "vupdate_rules: query : %s\n", PQerrorMessage(pgc));
746       if (pgres) PQclear (pgres);
747       return;
748     }
749   }
750 
751   n=PQntuples(pgres);
752   for( ; i < n ; i++ ) {
753     buf=realloc(buf, len+PQgetlength(pgres, i, 0) );
754     if( buf==NULL || errno==ENOMEM ) {
755       PQclear(pgres);
756       free(buf);
757       fprintf(stderr, "vupdate_rules: no mem\n");
758       return;
759     }
760 
761     sprintf( buf, "%s%s", PQgetvalue(pgres, i, 0), re );
762     if( write( fdm, buf, strlen(buf) ) != strlen(buf) ) {
763       fprintf(stderr, "vupdate_rules: short write: %s",
764 	      strerror(errno));
765       break;
766     }
767   }
768   if(pgres) PQclear(pgres);
769   free(buf);
770   return;
771 }
772 
vclear_open_smtp(time_t clear_minutes,time_t mytime)773 void vclear_open_smtp(time_t clear_minutes, time_t mytime)
774 {
775   PGresult *pgres;
776   time_t delete_time;
777   int err;
778 
779   if ( (err=vauth_open(1)) != 0 ) return;
780   delete_time = mytime - clear_minutes;
781 
782   snprintf( SqlBufUpdate, SQL_BUF_SIZE,
783 	    "DELETE FROM relay WHERE timestamp <= %d",
784 	    (int)delete_time);
785   pgres=PQexec(pgc, SqlBufUpdate);
786   if( !pgres || PQresultStatus(pgres) != PGRES_COMMAND_OK) {
787     vcreate_relay_table();
788   }
789   return;
790 }
791 
vcreate_relay_table()792 void vcreate_relay_table()
793 {
794   vauth_create_table ("relay", RELAY_TABLE_LAYOUT, 1);
795   return;
796 }
797 #endif
798 
vmkpasswd(char * domain)799 int vmkpasswd( char *domain )
800 {
801     return(0);
802 }
803 
vclose()804 void vclose()
805 {
806   /* disconnection from the database */
807   if ( is_open == 1 ) {
808     is_open = 0;
809     PQfinish(pgc);
810   }
811 }
812 
813 #ifdef IP_ALIAS_DOMAINS
vcreate_ip_map_table()814 void vcreate_ip_map_table()
815 {
816   vauth_create_table ("ip_alias_map", IP_ALIAS_TABLE_LAYOUT, 1);
817   return;
818 }
819 
vget_ip_map(char * ip,char * domain,int domain_size)820 int vget_ip_map( char *ip, char *domain, int domain_size)
821 {
822   PGresult *pgres;
823   char *ptr;
824   unsigned ntuples;
825   int ret = -1;
826 
827   if ( ip == NULL || strlen(ip) <= 0 ) return(-1);
828   if ( domain == NULL ) return(-2);
829   if ( vauth_open(0) != 0 ) return(-3);
830 
831   qnprintf(SqlBufRead, SQL_BUF_SIZE,
832 	   "select domain from ip_alias_map where ip_addr = '%s'",
833 	   ip);
834   pgres=PQexec(pgc, SqlBufRead);
835   if( !pgres || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
836     fprintf( stderr, "vget_ip_map: pgsql query: %s\n", PQerrorMessage(pgc));
837       if( pgres ) PQclear(pgres);
838       return -1;
839     }
840 
841   ntuples = PQntuples(pgres);
842   if(!ntuples)
843     *domain='\0';
844   else {
845     ret = 0;
846     ptr = PQgetvalue(pgres, ntuples-1, 0);
847     strncpy(domain, ptr, strlen(ptr) );
848   }
849 
850   PQclear(pgres);
851   return (ret);
852 }
853 
vadd_ip_map(char * ip,char * domain)854 int vadd_ip_map( char *ip, char *domain)
855 {
856   PGresult *pgres;
857   int err = 0;
858 
859   if ( ip == NULL || strlen(ip) <= 0 ) return(-1);
860   if ( domain == NULL || strlen(domain) <= 0 ) return(-1);
861 
862   if ( (err=vauth_open(1)) != 0 ) return(err);
863 
864   if( ( err=pg_begin() )!= 0 ) {     /* begin transaction */
865     return(err);
866   }
867   qnprintf(SqlBufUpdate,SQL_BUF_SIZE,
868 	   "delete from ip_alias_map where ip_addr='%s' and domain='%s'",
869 	   ip, domain);
870 
871   /* step 1: delete previous entry */
872   pgres=PQexec(pgc, SqlBufUpdate);
873   if( pgres ) PQclear(pgres); /* don't check pgres status
874 				 table may not exist */
875 
876   /* step 2: insert new data */
877   qnprintf(SqlBufUpdate,SQL_BUF_SIZE,
878 	   "insert into ip_alias_map (ip_addr,domain) values ('%s','%s')",
879 	   ip, domain);
880   pgres=PQexec(pgc, SqlBufUpdate);
881   if ( !pgres || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
882     if( pgres ) PQclear(pgres);
883     vcreate_ip_map_table();
884     qnprintf(SqlBufUpdate,SQL_BUF_SIZE,
885 	   "insert into ip_alias_map (ip_addr,domain) values ('%s','%s')",
886 	     ip, domain);
887     pgres=PQexec( pgc, SqlBufUpdate);
888     if ( !pgres || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
889       fprintf( stderr, "vadd_ip_map: insert: %s\n", PQerrorMessage(pgc));
890       if( pgres ) PQclear(pgres);
891       return -1;
892     }
893   }
894   if( pgres ) PQclear(pgres);
895   return ( pg_end() ); /* end transaction */
896 }
897 
vdel_ip_map(char * ip,char * domain)898 int vdel_ip_map( char *ip, char *domain)
899 {
900   PGresult *pgres;
901   int err=0;
902 
903   if ( ip == NULL || strlen(ip) <= 0 ) return(-1);
904   if ( domain == NULL || strlen(domain) <= 0 ) return(-1);
905   if ( (err=vauth_open(1)) != 0 ) return(err);
906 
907   qnprintf( SqlBufUpdate,SQL_BUF_SIZE,
908 	    "delete from ip_alias_map where ip_addr='%s' and domain='%s'",
909             ip, domain);
910 
911   pgres=PQexec(pgc, SqlBufUpdate);
912   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
913     fprintf(stderr, "vdel_ip_map: delete failed: %s\n",
914 	    PQerrorMessage(pgc));
915     if(pgres) PQclear(pgres);
916     /* #warning why are we returning 0 when we couldn't delete?*/
917     return(0);
918   }
919   if(pgres) PQclear(pgres);
920   return(0);
921 }
vshow_ip_map(int first,char * ip,char * domain)922 int vshow_ip_map( int first, char *ip, char *domain )
923 {
924   static PGresult *pgres=NULL;
925   static unsigned ntuples=0, ctuple=0;
926   int err= 0;
927 
928   if ( ip == NULL ) return(-1);
929   if ( domain == NULL ) return(-1);
930   if ( ( err=vauth_open(0) ) != 0 ) return(err);
931 
932   if ( first == 1 ) {
933     snprintf(SqlBufRead,SQL_BUF_SIZE,
934 	     "select ip_addr, domain from ip_alias_map");
935     if (pgres) {
936       PQclear(pgres);
937       ntuples=ctuple=0;
938     }
939     if ( ! (pgres=PQexec(pgc, SqlBufRead))
940          || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
941       if(pgres) PQclear(pgres);
942       snprintf(SqlBufRead,SQL_BUF_SIZE,
943 	       "select ip_addr, domain from ip_alias_map");
944       vcreate_ip_map_table();
945       if ( ! (pgres=PQexec(pgc, SqlBufRead))
946 	   || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
947 	return(0);
948       }
949     }
950     ntuples=PQntuples(pgres);
951   }
952 
953   if ( ctuple == ntuples ) {
954     PQclear(pgres);
955     ntuples=ctuple=0;
956     return (0);
957   }
958 
959   strncpy( ip, PQgetvalue( pgres, ctuple, 0), 18);
960   strncpy( domain, PQgetvalue( pgres, ctuple, 1), 156);
961   strncpy( ip, PQgetvalue( pgres, ctuple, 0), 18);
962   strncpy( domain, PQgetvalue( pgres, ctuple, 1), 156);
963 
964   ctuple++;
965   return 1;
966 }
967 #endif
968 
vread_dir_control(vdir_type * vdir,char * domain,uid_t uid,gid_t gid)969 int vread_dir_control(vdir_type *vdir, char *domain, uid_t uid, gid_t gid)
970 {
971   PGresult *pgres;
972   int found = 0;
973 
974   if ( vauth_open(0) != 0 ) return(-1);
975 
976   qnprintf(SqlBufUpdate, SQL_BUF_SIZE,
977 	   "select %s from dir_control where domain = '%s'",
978 	   DIR_CONTROL_SELECT, domain );
979 
980   if (!(pgres=PQexec(pgc, SqlBufUpdate)) ||
981       PQresultStatus(pgres)!=PGRES_TUPLES_OK ) {
982       if( pgres ) PQclear(pgres);
983       vcreate_dir_control(domain);
984       qnprintf(SqlBufUpdate, SQL_BUF_SIZE,
985 	       "select %s from dir_control where domain = '%s'",
986 	       DIR_CONTROL_SELECT, domain );
987       if (! (pgres=PQexec(pgc, SqlBufUpdate)) ||
988 	  PQresultStatus(pgres)!=PGRES_TUPLES_OK ) {
989 	fprintf(stderr, "vread_dir_control: q: %s\npgsql: %s",
990 		SqlBufUpdate, PQerrorMessage(pgc));
991 	  if (pgres) PQclear (pgres);
992 	  return (-1);
993       }
994   }
995   if ( PQntuples(pgres) > 0 ) {
996     found = 1;
997     vdir->cur_users = atol( PQgetvalue( pgres, 0, 0 ) );
998     vdir->level_cur = atoi( PQgetvalue( pgres, 0, 1 ) );
999     vdir->level_max = atoi( PQgetvalue( pgres, 0, 2 ) );
1000 
1001     vdir->level_start[0] = atoi( PQgetvalue( pgres, 0, 3 ) );
1002     vdir->level_start[1] = atoi( PQgetvalue( pgres, 0, 4 ) );
1003     vdir->level_start[2] = atoi( PQgetvalue( pgres, 0, 5 ) );
1004 
1005     vdir->level_end[0] = atoi( PQgetvalue( pgres, 0, 6 ) );
1006     vdir->level_end[1] = atoi( PQgetvalue( pgres, 0, 7 ) );
1007     vdir->level_end[2] = atoi( PQgetvalue( pgres, 0, 8 ) );
1008 
1009     vdir->level_mod[0] = atoi( PQgetvalue( pgres, 0, 9 ) );
1010     vdir->level_mod[1] = atoi( PQgetvalue( pgres, 0, 10 ) );
1011     vdir->level_mod[2] = atoi( PQgetvalue( pgres, 0, 11 ) );
1012 
1013     vdir->level_index[0] = atoi( PQgetvalue( pgres, 0, 12 ) );
1014     vdir->level_index[1] = atoi( PQgetvalue( pgres, 0, 13 ) );
1015     vdir->level_index[2] = atoi( PQgetvalue( pgres, 0, 14 ) );
1016 
1017     strncpy(vdir->the_dir, PQgetvalue( pgres, 0, 15 ), MAX_DIR_NAME);
1018   }
1019   PQclear(pgres);
1020   if ( found == 0 ) {
1021     int i;
1022     vdir->cur_users = 0;
1023     for(i=0;i<MAX_DIR_LEVELS;++i) {
1024       vdir->level_start[i] = 0;
1025       vdir->level_end[i] = MAX_DIR_LIST-1;
1026       vdir->level_index[i] = 0;
1027     }
1028     vdir->level_mod[0] = 0;
1029     vdir->level_mod[1] = 2;
1030     vdir->level_mod[2] = 4;
1031     vdir->level_cur = 0;
1032     vdir->level_max = MAX_DIR_LEVELS;
1033     vdir->the_dir[0] = 0;
1034   }
1035   return(0);
1036 }
1037 
vwrite_dir_control(vdir_type * vdir,char * domain,uid_t uid,gid_t gid)1038 int vwrite_dir_control(vdir_type *vdir, char *domain, uid_t uid, gid_t gid)
1039 {
1040   PGresult *pgres;
1041 
1042   if ( vauth_open(1) != 0 ) return(-1);
1043 
1044   qnprintf(SqlBufUpdate, SQL_BUF_SIZE,
1045 	   "delete from dir_control where domain='%s'", domain );
1046   if( pg_begin() ) { /* begin transaction */
1047       return -1;
1048   }
1049   pgres=PQexec(pgc, SqlBufUpdate);
1050   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1051     fprintf(stderr, "vwrite_dir_control: delete failed: %s",
1052 	    PQerrorMessage(pgc));
1053 	if (pgres) PQclear (pgres);
1054     return -1;
1055   }
1056   qnprintf(SqlBufUpdate, SQL_BUF_SIZE,
1057 	   "insert into dir_control ( \
1058 domain, cur_users, \
1059 level_cur, level_max, \
1060 level_start0, level_start1, level_start2, \
1061 level_end0, level_end1, level_end2, \
1062 level_mod0, level_mod1, level_mod2, \
1063 level_index0, level_index1, level_index2, the_dir ) values ( \
1064 '%s', %lu, %d, %d, \
1065 %d, %d, %d, \
1066 %d, %d, %d, \
1067 %d, %d, %d, \
1068 %d, %d, %d, \
1069 '%s')\n",
1070 	   domain, vdir->cur_users, vdir->level_cur, vdir->level_max,
1071 	   vdir->level_start[0], vdir->level_start[1], vdir->level_start[2],
1072 	   vdir->level_end[0], vdir->level_end[1], vdir->level_end[2],
1073 	   vdir->level_mod[0], vdir->level_mod[1], vdir->level_mod[2],
1074 	   vdir->level_index[0], vdir->level_index[1], vdir->level_index[2],
1075 	   vdir->the_dir);
1076 
1077   pgres=PQexec(pgc, SqlBufUpdate);
1078   if ( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1079     PQclear(pgres);
1080     vcreate_dir_control(domain);
1081     if ( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1082       fprintf(stderr, "vwrite_dir_control: %s\n", PQerrorMessage(pgc));
1083       if (pgres) PQclear (pgres);
1084       return(-1);
1085     }
1086   }
1087   PQclear(pgres);
1088   return pg_end(); /* end transcation */
1089 
1090 }
1091 
vcreate_dir_control(char * domain)1092 void vcreate_dir_control(char *domain)
1093 {
1094   PGresult *pgres;
1095   vauth_create_table ("dir_control", DIR_CONTROL_TABLE_LAYOUT, 1);
1096 
1097   qnprintf(SqlBufUpdate, SQL_BUF_SIZE, "insert into dir_control ( \
1098 domain, cur_users, \
1099 level_cur, level_max, \
1100 level_start0, level_start1, level_start2, \
1101 level_end0, level_end1, level_end2, \
1102 level_mod0, level_mod1, level_mod2, \
1103 level_index0, level_index1, level_index2, the_dir ) values ( \
1104 \'%s\', 0, \
1105 0, %d, \
1106 0, 0, 0, \
1107 %d, %d, %d, \
1108 0, 2, 4, \
1109 0, 0, 0, \
1110 \'\')\n",
1111     domain, MAX_DIR_LEVELS, MAX_DIR_LIST-1, MAX_DIR_LIST-1, MAX_DIR_LIST-1);
1112 
1113   pgres = PQexec( pgc, SqlBufUpdate );
1114   if ( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1115     fprintf(stderr, "vcreate_dir_control: insert failed: %s\n",
1116 	    PQerrorMessage(pgc));
1117 	  if (pgres) PQclear (pgres);
1118       return;
1119   }
1120 
1121   PQclear(pgres);
1122 }
1123 
vdel_dir_control(char * domain)1124 int vdel_dir_control(char *domain)
1125 {
1126   PGresult *pgres;
1127   int err;
1128 
1129   if ( (err=vauth_open(1)) != 0 ) return(err);
1130 
1131   qnprintf(SqlBufUpdate, SQL_BUF_SIZE,
1132 	   "delete from dir_control where domain = '%s'",
1133 	   domain);
1134   pgres=PQexec(pgc, SqlBufUpdate);
1135 
1136   if ( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1137     PQclear(pgres);
1138     vcreate_dir_control(domain);
1139     qnprintf(SqlBufUpdate, SQL_BUF_SIZE,
1140 	     "delete from dir_control where domain = '%s'",
1141 	     domain);
1142     if ( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1143       fprintf(stderr, "vdel_dir_control: delete failed[e]: %s\n",
1144 	      PQerrorMessage(pgc));
1145       err=-1;
1146     }
1147   }
1148   if( pgres ) PQclear(pgres);
1149   return err;
1150 }
1151 
1152 #ifdef ENABLE_AUTH_LOGGING
vset_lastauth(char * user,char * domain,char * remoteip)1153 int vset_lastauth(char *user, char *domain, char *remoteip )
1154 {
1155   PGresult *pgres;
1156   int err=0;
1157 
1158   if ( (err=vauth_open(1)) != 0 ) return(err);
1159 
1160   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1161     "UPDATE lastauth SET remote_ip='%s', timestamp=%lu " \
1162     "WHERE userid='%s' AND domain='%s'", remoteip, time(NULL), user, domain);
1163 
1164 #ifdef DEBUG
1165 fprintf(stderr,"UPDATE command to run is \n\n%s\n\n", SqlBufUpdate);
1166 #endif
1167 
1168   pgres=PQexec(pgc, SqlBufUpdate);
1169 
1170   if (pgres && PQresultStatus(pgres) == PGRES_COMMAND_OK && atoi(PQcmdTuples(pgres)) == 0) {
1171 
1172 #ifdef DEBUG
1173 fprintf(stderr,"UPDATE returned OK but had 0 rows\n");
1174 #endif
1175 
1176     if( pgres ) PQclear(pgres);
1177 
1178     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1179       "INSERT INTO lastauth (userid, domain, remote_ip, timestamp) " \
1180       "VALUES ('%s', '%s', '%s', %lu)", user, domain, remoteip, time(NULL));
1181 
1182 #ifdef DEBUG
1183 fprintf(stderr,"INSERT command to run is \n\n%s\n\n", SqlBufUpdate);
1184 #endif
1185     pgres=PQexec(pgc, SqlBufUpdate);
1186     }
1187 
1188 /* UPDATE returned 0 rows and/or INSERT failed.  Try creating the table */
1189   if(!pgres || PQresultStatus(pgres) != PGRES_COMMAND_OK) {
1190 #ifdef DEBUG
1191 fprintf(stderr,"UPDATE and/or INSERT failed.  error was %s\n", PQerrorMessage(pgc));
1192 #endif
1193     if( pgres ) PQclear(pgres);
1194 
1195 #ifdef DEBUG
1196 fprintf(stderr, "update returned 0 and/or insert failed in vset_lastauth()\n");
1197 #endif
1198     vcreate_lastauth_table();
1199 
1200 /* and try INSERTing now... */
1201     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1202       "INSERT INTO lastauth (userid, domain, remote_ip, timestamp) " \
1203       "VALUES ('%s', '%s', '%s', %lu)", user, domain, remoteip, time(NULL));
1204 
1205     pgres=PQexec(pgc, SqlBufUpdate);
1206     }
1207 
1208   if ( !pgres || PQresultStatus(pgres) != PGRES_COMMAND_OK ) {
1209     fprintf( stderr, "vset_lastauth[f]: %s\n: %s\n", SqlBufUpdate,PQerrorMessage(pgc));
1210     if( pgres ) PQclear(pgres);
1211     return (-1);
1212   }
1213 
1214   if( pgres ) PQclear(pgres);
1215   return(0);
1216 }
vget_lastauth(struct vqpasswd * pw,char * domain)1217 time_t vget_lastauth(struct vqpasswd *pw, char *domain)
1218 {
1219   PGresult *pgres;
1220   int err, ntuples;
1221   time_t mytime;
1222 
1223   if ( (err=vauth_open(0)) != 0 ) return(err);
1224 
1225   qnprintf( SqlBufRead,  SQL_BUF_SIZE, "SELECT timestamp FROM lastauth WHERE userid='%s' AND domain='%s'", pw->pw_name, domain);
1226 
1227   pgres=PQexec(pgc, SqlBufRead);
1228 
1229   if ( !pgres || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1230     if( pgres ) PQclear(pgres);
1231     vcreate_lastauth_table();
1232     qnprintf( SqlBufRead,  SQL_BUF_SIZE, "SELECT timestamp FROM lastauth WHERE userid='%s' AND domain='%s'", pw->pw_name, domain);
1233     pgres=PQexec(pgc, SqlBufRead);
1234     if ( !pgres || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1235       fprintf(stderr,"vpgsql: sql error[g]: %s\n", PQerrorMessage(pgc));
1236       return(0);
1237     }
1238   }
1239 
1240   ntuples = PQntuples(pgres);
1241   mytime = 0;
1242   if( ntuples ) { /* got something */
1243     mytime = atol( PQgetvalue(pgres, ntuples-1, 0));
1244   }
1245   if( pgres ) PQclear(pgres);
1246   return(mytime);
1247 }
1248 
vget_lastauthip(struct vqpasswd * pw,char * domain)1249 char *vget_lastauthip(struct vqpasswd *pw, char *domain)
1250 {
1251   PGresult *pgres;
1252   static char tmpbuf[100];
1253   int ntuples=0;
1254 
1255   if ( vauth_open(0) != 0 ) return(NULL);
1256 
1257   qnprintf( SqlBufRead,  SQL_BUF_SIZE, "select remote_ip from lastauth where userid='%s' and domain='%s'",  pw->pw_name, domain);
1258 
1259   pgres=PQexec(pgc, SqlBufRead);
1260   if ( !pgres || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1261     if( pgres ) PQclear(pgres);
1262     vcreate_lastauth_table();
1263     qnprintf( SqlBufRead,  SQL_BUF_SIZE, "select remote_ip from lastauth where userid='%s' and domain='%s'", pw->pw_name, domain);
1264 
1265     pgres=PQexec(pgc, SqlBufRead);
1266     if ( !pgres || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1267       fprintf( stderr,"vpgsql: sql error[h]: %s\n", PQerrorMessage(pgc));
1268       return(NULL);
1269     }
1270   }
1271   ntuples = PQntuples(pgres);
1272   if( ntuples ) { /* got something */
1273     strncpy(tmpbuf, PQgetvalue(pgres, ntuples-1, 0),100 );
1274   }
1275   if( pgres ) PQclear(pgres);
1276   return(tmpbuf);
1277 }
1278 
vcreate_lastauth_table()1279 void vcreate_lastauth_table()
1280 {
1281   vauth_create_table ("lastauth", LASTAUTH_TABLE_LAYOUT, 1);
1282   return;
1283 }
1284 #endif /* ENABLE_AUTH_LOGGING */
1285 
1286 #ifdef VALIAS
1287 struct linklist *valias_current = NULL;
1288 
valias_select(char * alias,char * domain)1289 char *valias_select( char *alias, char *domain )
1290 {
1291   PGresult *pgvalias;
1292   int err, verrori;
1293   unsigned ntuples, ctuple;
1294   struct linklist *temp_entry = NULL;
1295 
1296   /* remove old entries as necessary */
1297   while (valias_current != NULL)
1298     valias_current = linklist_del (valias_current);
1299 
1300   if ( (err=vauth_open(0)) != 0 ) {
1301     verrori = err;
1302     return(NULL);
1303   }
1304 
1305   qnprintf( SqlBufRead, SQL_BUF_SIZE,
1306 	    "select valias_line from valias where alias='%s' and domain='%s'",
1307 	    alias, domain );
1308   if ( ! (pgvalias=PQexec(pgc, SqlBufRead))
1309        || PQresultStatus(pgvalias) != PGRES_TUPLES_OK ) {
1310     if(pgvalias) PQclear(pgvalias);
1311     vcreate_valias_table();
1312     if ( ! (pgvalias=PQexec(pgc, SqlBufRead))
1313 	 || PQresultStatus(pgvalias) != PGRES_TUPLES_OK ) {
1314       fprintf(stderr,"vpgsql: sql error[j]: %s\n",
1315 	      PQerrorMessage(pgc));
1316 	  if (pgvalias) PQclear(pgvalias);
1317       return(NULL);
1318     }
1319   }
1320 
1321   ntuples = PQntuples (pgvalias);
1322   for (ctuple = 0; ctuple < ntuples; ctuple++) {
1323     temp_entry = linklist_add (temp_entry, PQgetvalue (pgvalias, ctuple, 0), "");
1324     if (valias_current == NULL) valias_current = temp_entry;
1325   }
1326   PQclear (pgvalias);
1327   pgvalias = NULL;
1328 
1329   if (valias_current == NULL) return NULL; /* no results */
1330   else return(valias_current->data);
1331 }
1332 
valias_select_next()1333 char *valias_select_next()
1334 {
1335   if (valias_current == NULL) return NULL;
1336 
1337   valias_current = linklist_del (valias_current);
1338 
1339   if (valias_current == NULL) return NULL;
1340   else return valias_current->data;
1341 }
1342 
valias_insert(char * alias,char * domain,char * alias_line)1343 int valias_insert( char *alias, char *domain, char *alias_line)
1344 {
1345   PGresult *pgres;
1346   int err;
1347 
1348   if ( (err=vauth_open(1)) != 0 ) return(err);
1349 
1350   while(*alias_line==' ') ++alias_line;
1351 
1352   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1353     "insert into valias(alias,domain,valias_line) values ('%s','%s','%s')",
1354 	    alias, domain, alias_line );
1355 
1356   pgres=PQexec( pgc, SqlBufUpdate );
1357   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1358     if(pgres) PQclear(pgres);
1359     vcreate_valias_table();
1360     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1361     "insert into valias(alias,domain,valias_line) values ('%s','%s','%s')",
1362 	    alias, domain, alias_line );
1363     pgres=PQexec( pgc, SqlBufUpdate );
1364     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1365       fprintf(stderr,"vpgsql: sql error[k]: %s\n", PQerrorMessage(pgc));
1366       if (pgres) PQclear (pgres);
1367       return(-1);
1368     }
1369     if(pgres) PQclear(pgres);
1370 
1371 #ifdef ONCHANGE_SCRIPT
1372     if( allow_onchange ) {
1373        /* tell other programs that data has changed */
1374        snprintf ( onchange_buf, MAX_BUFF, "%s@%s - %s", alias, domain, alias_line );
1375        call_onchange ( "valias_add" );
1376        }
1377 #endif
1378 
1379     return(0);
1380   }
1381   return(-1);
1382 }
1383 
valias_delete(char * alias,char * domain)1384 int valias_delete( char *alias, char *domain)
1385 {
1386   PGresult *pgres;
1387   int err;
1388 
1389   if ( (err=vauth_open(1)) != 0 ) return(err);
1390 
1391 #ifdef ONCHANGE_SCRIPT
1392   if( allow_onchange ) {
1393      /* tell other programs that data has changed */
1394      snprintf ( onchange_buf, MAX_BUFF, "%s@%s", alias, domain );
1395      call_onchange ( "valias_delete" );
1396      }
1397 #endif
1398 
1399   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1400 	    "delete from valias where alias='%s' and domain='%s'",
1401 	    alias, domain );
1402   pgres=PQexec( pgc, SqlBufUpdate );
1403   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1404     if(pgres) PQclear(pgres);
1405     vcreate_valias_table();
1406     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1407 	      "delete from valias where alias='%s' and domain='%s'",
1408 	      alias, domain );
1409     pgres=PQexec( pgc, SqlBufUpdate );
1410     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1411       fprintf(stderr,"vpgsql: sql error: %s\n", PQerrorMessage(pgc));
1412       if (pgres) PQclear (pgres);
1413       return(-1);
1414     }
1415   }
1416   if(pgres) PQclear(pgres);
1417   return(0);
1418 }
1419 
valias_remove(char * alias,char * domain,char * alias_line)1420 int valias_remove( char *alias, char *domain, char *alias_line)
1421 {
1422   PGresult *pgres;
1423   int err;
1424 
1425   if ( (err=vauth_open(1)) != 0 ) return(err);
1426 
1427 #ifdef ONCHANGE_SCRIPT
1428   if( allow_onchange ) {
1429      /* tell other programs that data has changed */
1430      snprintf ( onchange_buf, MAX_BUFF, "%s@%s - %s", alias, domain, alias_line);
1431      call_onchange ( "valias_remove" );
1432      }
1433 #endif
1434 
1435   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1436 	    "delete from valias where alias='%s' and valias_line='%s' and domain='%s'",
1437 	    alias, alias_line, domain );
1438   pgres=PQexec( pgc, SqlBufUpdate );
1439   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1440     if(pgres) PQclear(pgres);
1441     vcreate_valias_table();
1442     pgres=PQexec( pgc, SqlBufUpdate );
1443     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1444       fprintf(stderr,"vpgsql: sql error: %s\n", PQerrorMessage(pgc));
1445       if (pgres) PQclear (pgres);
1446       return(-1);
1447     }
1448   }
1449   if(pgres) PQclear(pgres);
1450   return(0);
1451 }
1452 
valias_delete_domain(char * domain)1453 int valias_delete_domain( char *domain)
1454 {
1455   PGresult *pgres;
1456   int err;
1457 
1458   if ( (err=vauth_open(1)) != 0 ) return(err);
1459 
1460 #ifdef ONCHANGE_SCRIPT
1461   if( allow_onchange ) {
1462      /* tell other programs that data has changed */
1463      snprintf ( onchange_buf, MAX_BUFF, "%s@%s - %s", alias, domain, alias_line);
1464      call_onchange ( "valias_delete_domain" );
1465      }
1466 #endif
1467 
1468   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1469 	    "delete from valias where domain='%s'", domain );
1470 
1471   pgres=PQexec( pgc, SqlBufUpdate );
1472   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1473     if(pgres) PQclear(pgres);
1474     vcreate_valias_table();
1475     qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1476 	      "delete from valias where domain='%s'", domain );
1477     pgres=PQexec( pgc, SqlBufUpdate );
1478     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1479       fprintf(stderr,"vpgsql: sql error: %s\n", PQerrorMessage(pgc));
1480       if (pgres) PQclear (pgres);
1481       return(-1);
1482     }
1483   }
1484   if(pgres) PQclear(pgres);
1485   return(0);
1486 }
1487 
vcreate_valias_table()1488 void vcreate_valias_table()
1489 {
1490   PGresult *pgres;
1491   char SqlBufCreate[SQL_BUF_SIZE];
1492 
1493   vauth_create_table ("valias", VALIAS_TABLE_LAYOUT, 1);
1494     snprintf( SqlBufCreate, SQL_BUF_SIZE,
1495 	"create index valias_idx on valias ( %s )", VALIAS_INDEX_LAYOUT );
1496 
1497     pgres=PQexec( pgc, SqlBufCreate );
1498     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1499       fprintf(stderr,"vpgsql:sql error[n.i]:%s\n", PQerrorMessage(pgc));
1500       if( pgres ) PQclear(pgres);
1501       return;
1502     }
1503     if( pgres ) PQclear(pgres);
1504     return;
1505 }
1506 
valias_select_all(char * alias,char * domain)1507 char *valias_select_all( char *alias, char *domain )
1508 {
1509   PGresult *pgres;
1510   int err;
1511   unsigned ntuples, ctuple;
1512   struct linklist *temp_entry = NULL;
1513 
1514   /* remove old entries as necessary */
1515   while (valias_current != NULL)
1516     valias_current = linklist_del (valias_current);
1517 
1518   if ( (err=vauth_open(0)) != 0 ) return(NULL);
1519 
1520   qnprintf( SqlBufRead, SQL_BUF_SIZE,
1521 	    "select alias, valias_line from valias where domain = '%s' order by alias",
1522 	    domain );
1523   if ( ! (pgres=PQexec(pgc, SqlBufRead))
1524        || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1525     if(pgres) PQclear(pgres);
1526     vcreate_valias_table();
1527     if ( ! (pgres=PQexec(pgc, SqlBufRead))
1528          || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1529       fprintf(stderr,"vpgsql: sql error[o]: %s\n",
1530               PQerrorMessage(pgc));
1531       if (pgres) PQclear (pgres);
1532       return(NULL);
1533     }
1534   }
1535 
1536   ntuples = PQntuples (pgres);
1537   for (ctuple = 0; ctuple < ntuples; ctuple++) {
1538     temp_entry = linklist_add (temp_entry, PQgetvalue (pgres, ctuple, 1), PQgetvalue (pgres, ctuple, 0));
1539     if (valias_current == NULL) valias_current = temp_entry;
1540   }
1541   PQclear (pgres);
1542   pgres = NULL;
1543 
1544   if (valias_current == NULL) return NULL; /* no results */
1545   else {
1546     strcpy (alias, valias_current->d2);
1547     return(valias_current->data);
1548   }
1549 }
1550 
valias_select_all_next(char * alias)1551 char *valias_select_all_next(char *alias)
1552 {
1553   if (valias_current == NULL) return NULL;
1554   valias_current = linklist_del (valias_current);
1555 
1556   if (valias_current == NULL) return NULL;
1557   else {
1558     strcpy (alias, valias_current->d2);
1559     return valias_current->data;
1560   }
1561 }
1562 
1563 /************************************************************************
1564  *
1565  *  valias_select_names
1566  */
1567 
valias_select_names(char * domain)1568 char *valias_select_names( char *domain )
1569 {
1570   PGresult *pgres;
1571   int err;
1572   unsigned ntuples, ctuple;
1573  struct linklist *temp_entry = NULL;
1574 
1575 
1576     /* remove old entries as necessary */
1577     while (valias_current != NULL)
1578         valias_current = linklist_del (valias_current);
1579 
1580     if ( (err=vauth_open(0)) != 0 ) return(NULL);
1581 
1582     qnprintf( SqlBufRead, SQL_BUF_SIZE,
1583         "select distinct alias from valias where domain = '%s' order by alias", domain );
1584 
1585   if ( ! (pgres=PQexec(pgc, SqlBufRead))
1586        || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1587     if(pgres) PQclear(pgres);
1588     vcreate_valias_table();
1589     if ( ! (pgres=PQexec(pgc, SqlBufRead))
1590          || PQresultStatus(pgres) != PGRES_TUPLES_OK ) {
1591       fprintf(stderr,"vpgsql: sql error[o]: %s\n",
1592               PQerrorMessage(pgc));
1593       if (pgres) PQclear (pgres);
1594       return(NULL);
1595     }
1596   }
1597 
1598   ntuples = PQntuples (pgres);
1599   for (ctuple = 0; ctuple < ntuples; ctuple++) {
1600     temp_entry = linklist_add (temp_entry, PQgetvalue (pgres, ctuple, 0), "");
1601     if (valias_current == NULL) valias_current = temp_entry;
1602   }
1603   PQclear (pgres);
1604   pgres = NULL;
1605 
1606     if (valias_current == NULL) return NULL; /* no results */
1607     else return(valias_current->data);
1608 }
1609 
1610 /************************************************************************
1611  *
1612  *  valias_select_names_next
1613  */
1614 
valias_select_names_next()1615 char *valias_select_names_next()
1616 {
1617     if (valias_current == NULL) return NULL;
1618     valias_current = linklist_del (valias_current);
1619 
1620     if (valias_current == NULL) return NULL; /* no results */
1621     else return(valias_current->data);
1622 }
1623 
1624 
1625 /************************************************************************
1626  *
1627  *  valias_select_names_end
1628  */
1629 
valias_select_names_end()1630 void valias_select_names_end() {
1631 
1632 //  not needed by pgsql
1633 
1634 }
1635 
1636 #endif
1637 
1638 #ifdef ENABLE_SQL_LOGGING
logsql(int verror,char * TheUser,char * TheDomain,char * ThePass,char * TheName,char * IpAddr,char * LogLine)1639 int logsql(	int verror, char *TheUser, char *TheDomain, char *ThePass,
1640 		char *TheName, char *IpAddr, char *LogLine)
1641 {
1642   PGresult *pgres;
1643   int err;
1644   time_t mytime;
1645 
1646   mytime = time(NULL);
1647   if ( (err=vauth_open(1)) != 0 ) return(err);
1648   /*
1649 
1650   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1651 	    "INSERT INTO vlog set userid='%s', passwd='%s', \
1652         domain='%s', logon='%s', remoteip='%s', message='%s', \
1653         error=%i, timestamp=%d", TheUser, ThePass, TheDomain,
1654         TheName, IpAddr, LogLine, verror, (int)mytime);
1655   */
1656 
1657   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1658   "INSERT INTO vlog (userid,passwd,domain,logon,remoteip,message,error,timestamp) values('%s','%s','%s','%s','%s','%s',%i,%d)",
1659 	    TheUser, ThePass, TheDomain, TheName,
1660 	    IpAddr, LogLine, verror, (int)mytime);
1661 
1662   pgres=PQexec( pgc, SqlBufUpdate );
1663   if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1664     if( pgres ) PQclear(pgres);
1665     vcreate_vlog_table();
1666   qnprintf( SqlBufUpdate, SQL_BUF_SIZE,
1667   "INSERT INTO vlog (userid,passwd,domain,logon,remoteip,message,error,timestamp) values('%s','%s','%s','%s','%s','%s',%i,%d)",
1668 	    TheUser, ThePass, TheDomain, TheName,
1669 	    IpAddr, LogLine, verror, (int)mytime);
1670 
1671     pgres=PQexec( pgc, SqlBufUpdate );
1672     if( !pgres || PQresultStatus(pgres)!=PGRES_COMMAND_OK ) {
1673       if( pgres ) PQclear(pgres);
1674       fprintf(stderr,"error inserting into lastauth table\n");
1675     }
1676   }
1677   if( pgres ) PQclear(pgres);
1678   return(0);
1679 }
1680 
vcreate_vlog_table()1681 void vcreate_vlog_table()
1682 {
1683   vauth_create_table ("vlog", VLOG_TABLE_LAYOUT, 1);
1684   return;
1685 }
1686 #endif
1687 
vauth_crypt(char * user,char * domain,char * clear_pass,struct vqpasswd * vpw)1688 int vauth_crypt(char *user,char *domain,char *clear_pass,struct vqpasswd *vpw)
1689 {
1690 	  if ( vpw == NULL ) return(-1);
1691 
1692 	    return(strcmp(crypt(clear_pass,vpw->pw_passwd),vpw->pw_passwd));
1693 }
1694 
1695