]> granicus.if.org Git - postgresql/blob - src/backend/libpq/hba.c
From: Phil Thompson <phil@river-bank.demon.co.uk>
[postgresql] / src / backend / libpq / hba.c
1 /*-------------------------------------------------------------------------
2  *
3  * hba.c--
4  *        Routines to handle host based authentication (that's the scheme
5  *        wherein you authenticate a user by seeing what IP address the system
6  *        says he comes from and possibly using ident).
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.26 1998/01/26 01:41:08 scrappy Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <pwd.h>
18 #include <sys/types.h>
19 #include <fcntl.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <unistd.h>
24
25 #include <postgres.h>
26 #include <miscadmin.h>
27 #include <libpq/libpq.h>
28 #include <libpq/pqcomm.h>
29 #include <libpq/hba.h>
30 #include <port/inet_aton.h>             /* For inet_aton() */
31 #include <storage/fd.h>
32
33 /* Some standard C libraries, including GNU, have an isblank() function.
34    Others, including Solaris, do not.  So we have our own.
35 */
36 static bool
37 isblank(const char c)
38 {
39         return (c == ' ' || c == 9 /* tab */ );
40 }
41
42
43
44 static void
45 next_token(FILE *fp, char *buf, const int bufsz)
46 {
47 /*--------------------------------------------------------------------------
48   Grab one token out of fp.  Tokens are strings of non-blank
49   characters bounded by blank characters, beginning of line, and end
50   of line.      Blank means space or tab.  Return the token as *buf.
51   Leave file positioned to character immediately after the token or
52   EOF, whichever comes first.  If no more tokens on line, return null
53   string as *buf and position file to beginning of next line or EOF,
54   whichever comes first.
55 --------------------------------------------------------------------------*/
56         int                     c;
57         char       *eb = buf + (bufsz - 1);
58
59         /* Move over inital token-delimiting blanks */
60         while (isblank(c = getc(fp)));
61
62         if (c != '\n')
63         {
64
65                 /*
66                  * build a token in buf of next characters up to EOF, eol, or
67                  * blank.
68                  */
69                 while (c != EOF && c != '\n' && !isblank(c))
70                 {
71                         if (buf < eb)
72                                 *buf++ = c;
73                         c = getc(fp);
74
75                         /*
76                          * Put back the char right after the token (putting back EOF
77                          * is ok)
78                          */
79                 }
80                 ungetc(c, fp);
81         }
82         *buf = '\0';
83 }
84
85
86
87 static void
88 read_through_eol(FILE *file)
89 {
90         int                     c;
91
92         do
93                 c = getc(file);
94         while (c != '\n' && c != EOF);
95 }
96
97
98
99 static void
100 read_hba_entry2(FILE *file, UserAuth * userauth_p, char auth_arg[],
101                           bool *error_p)
102 {
103 /*--------------------------------------------------------------------------
104   Read from file FILE the rest of a host record, after the mask field,
105   and return the interpretation of it as *userauth_p, auth_arg, and
106   *error_p.
107 ---------------------------------------------------------------------------*/
108         char            buf[MAX_TOKEN];
109
110         /* Get authentication type token. */
111         next_token(file, buf, sizeof(buf));
112
113         if (strcmp(buf, "trust") == 0)
114                 *userauth_p = uaTrust;
115         else if (strcmp(buf, "ident") == 0)
116                 *userauth_p = uaIdent;
117         else if (strcmp(buf, "password") == 0)
118                 *userauth_p = uaPassword;
119         else if (strcmp(buf, "krb4") == 0)
120                 *userauth_p = uaKrb4;
121         else if (strcmp(buf, "krb5") == 0)
122                 *userauth_p = uaKrb5;
123         else if (strcmp(buf, "reject") == 0)
124                 *userauth_p = uaReject;
125         else if (strcmp(buf, "crypt") == 0)
126                 *userauth_p = uaCrypt;
127         else
128         {
129                 *error_p = true;
130
131                 if (buf[0] != '\0')
132                         read_through_eol(file);
133         }
134
135         if (!*error_p)
136         {
137                 /* Get the authentication argument token, if any */
138                 next_token(file, buf, sizeof(buf));
139                 if (buf[0] == '\0')
140                         auth_arg[0] = '\0';
141                 else
142                 {
143                         StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);
144                         next_token(file, buf, sizeof(buf));
145                         if (buf[0] != '\0')
146                         {
147                                 *error_p = true;
148                                 read_through_eol(file);
149                         }
150                 }
151         }
152 }
153
154
155
156 static void
157 process_hba_record(FILE *file, SockAddr *raddr, const char database[],
158                                    bool *matches_p, bool *error_p,
159                                    UserAuth * userauth_p, char auth_arg[])
160 {
161 /*---------------------------------------------------------------------------
162   Process the non-comment record in the config file that is next on the file.
163   See if it applies to a connection to a host with IP address "*raddr"
164   to a database named "database[]".  If so, return *matches_p true
165   and *userauth_p and auth_arg[] as the values from the entry.
166   If not, leave *matches_p as it was.  If the record has a syntax error,
167   return *error_p true, after issuing a message to stderr.      If no error,
168   leave *error_p as it was.
169 ---------------------------------------------------------------------------*/
170         char db[MAX_TOKEN], buf[MAX_TOKEN];
171
172         /* Read the record type field. */
173
174         next_token(file, buf, sizeof(buf));
175
176         if (buf[0] == '\0')
177                 return;
178
179         /* Check the record type. */
180
181         if (strcmp(buf, "local") == 0)
182         {
183                 /* Get the database. */
184
185                 next_token(file, db, sizeof(db));
186
187                 if (db[0] == '\0')
188                         goto syntax;
189
190                 /* Read the rest of the line. */
191
192                 read_hba_entry2(file, userauth_p, auth_arg, error_p);
193
194                 /*
195                  * For now, disallow methods that need AF_INET sockets to work.
196                  */
197
198                 if (!*error_p &&
199                                 (*userauth_p == uaIdent ||
200                                  *userauth_p == uaKrb4 ||
201                                  *userauth_p == uaKrb5))
202                         *error_p = true;
203
204                 if (*error_p)
205                         goto syntax;
206
207                 /*
208                  * If this record isn't for our database, or this is the wrong
209                  * sort of connection, ignore it.
210                  */
211
212                 if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0) ||
213                                 raddr->sa.sa_family != AF_UNIX)
214                         return;
215         }
216         else if (strcmp(buf, "host") == 0)
217         {
218                 struct in_addr file_ip_addr, mask;
219
220                 /* Get the database. */
221
222                 next_token(file, db, sizeof(db));
223
224                 if (db[0] == '\0')
225                         goto syntax;
226
227                 /* Read the IP address field. */
228
229                 next_token(file, buf, sizeof(buf));
230
231                 if (buf[0] == '\0')
232                         goto syntax;
233
234                 /* Remember the IP address field and go get mask field. */
235
236                 if (!inet_aton(buf, &file_ip_addr))
237                 {
238                         read_through_eol(file);
239                         goto syntax;
240                 }
241
242                 /* Read the mask field. */
243
244                 next_token(file, buf, sizeof(buf));
245
246                 if (buf[0] == '\0')
247                         goto syntax;
248
249                 if (!inet_aton(buf, &mask))
250                 {
251                         read_through_eol(file);
252                         goto syntax;
253                 }
254
255                 /*
256                  * This is the record we're looking for.  Read the rest of the
257                  * info from it.
258                  */
259
260                 read_hba_entry2(file, userauth_p, auth_arg, error_p);
261
262                 if (*error_p)
263                         goto syntax;
264
265                 /*
266                  * If this record isn't for our database, or this is the wrong
267                  * sort of connection, ignore it.
268                  */
269
270                 if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0) ||
271                         raddr->sa.sa_family != AF_INET ||
272                         ((file_ip_addr.s_addr ^ raddr->in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
273                         return;
274         }
275         else
276         {
277                 read_through_eol(file);
278                 goto syntax;
279         }
280
281         *matches_p = true;
282
283         return;
284
285 syntax:
286         sprintf(PQerrormsg,
287                 "process_hba_record: invalid syntax in pg_hba.conf file\n");
288
289         fputs(PQerrormsg, stderr);
290         pqdebug("%s", PQerrormsg);
291
292         *error_p = true;
293 }
294
295
296
297 static void
298 process_open_config_file(FILE *file, SockAddr *raddr, const char database[],
299                                 bool *host_ok_p, UserAuth * userauth_p,
300                                 char auth_arg[])
301 {
302 /*---------------------------------------------------------------------------
303   This function does the same thing as find_hba_entry, only with
304   the config file already open on stream descriptor "file".
305 ----------------------------------------------------------------------------*/
306         bool            found_entry;
307
308         /* We've processed a record that applies to our connection */
309         bool            error;
310
311         /* Said record has invalid syntax. */
312         bool            eof;                    /* We've reached the end of the file we're
313                                                                  * reading */
314
315         found_entry = false;            /* initial value */
316         error = false;                          /* initial value */
317         eof = false;                            /* initial value */
318         while (!eof && !found_entry && !error)
319         {
320                 /* Process a line from the config file */
321
322                 int                     c;                      /* a character read from the file */
323
324                 c = getc(file);
325                 ungetc(c, file);
326                 if (c == EOF)
327                         eof = true;
328                 else
329                 {
330                         if (c == '#')
331                                 read_through_eol(file);
332                         else
333                         {
334                                 process_hba_record(file, raddr, database,
335                                                   &found_entry, &error, userauth_p, auth_arg);
336                         }
337                 }
338         }
339
340         if (found_entry && !error)
341                 *host_ok_p = true;
342 }
343
344
345
346 static void
347 find_hba_entry(SockAddr *raddr, const char database[], bool *host_ok_p,
348                 UserAuth * userauth_p, char auth_arg[])
349 {
350 /*--------------------------------------------------------------------------
351   Read the config file and find an entry that allows connection from
352   host "*raddr" to database "database".  If found, return *host_ok_p == true
353   and *userauth_p and *auth_arg representing the contents of that entry.
354
355   When a record has invalid syntax, we either ignore it or reject the
356   connection (depending on where it's invalid).  No message or anything.
357   We need to fix that some day.
358
359   If we don't find or can't access the config file, we issue an error
360   message and deny the connection.
361
362   If we find a file by the old name of the config file (pg_hba), we issue
363   an error message because it probably needs to be converted.  He didn't
364   follow directions and just installed his old hba file in the new database
365   system.
366
367 ---------------------------------------------------------------------------*/
368         int                     fd;
369
370         FILE       *file;                       /* The config file we have to read */
371
372         char       *old_conf_file;
373
374         /* The name of old config file that better not exist. */
375
376         /* Fail if config file by old name exists. */
377
378
379         /* put together the full pathname to the old config file */
380         old_conf_file = (char *) palloc((strlen(DataDir) +
381                                                           strlen(OLD_CONF_FILE) + 2) * sizeof(char));
382         sprintf(old_conf_file, "%s/%s", DataDir, OLD_CONF_FILE);
383
384         if ((fd = open(old_conf_file, O_RDONLY, 0)) != -1)
385         {
386                 /* Old config file exists.      Tell this guy he needs to upgrade. */
387                 close(fd);
388                 sprintf(PQerrormsg,
389                   "A file exists by the name used for host-based authentication "
390                    "in prior releases of Postgres (%s).  The name and format of "
391                    "the configuration file have changed, so this file should be "
392                                 "converted.\n",
393                                 old_conf_file);
394                 fputs(PQerrormsg, stderr);
395                 pqdebug("%s", PQerrormsg);
396         }
397         else
398         {
399                 char       *conf_file;  /* The name of the config file we have to
400                                                                  * read */
401
402                 /* put together the full pathname to the config file */
403                 conf_file = (char *) palloc((strlen(DataDir) +
404                                                                   strlen(CONF_FILE) + 2) * sizeof(char));
405                 sprintf(conf_file, "%s/%s", DataDir, CONF_FILE);
406
407                 file = AllocateFile(conf_file, "r");
408                 if (file == NULL)
409                 {
410                         /* The open of the config file failed.  */
411
412                         sprintf(PQerrormsg,
413                                  "find_hba_entry: Host-based authentication config file "
414                                 "does not exist or permissions are not setup correctly! "
415                                         "Unable to open file \"%s\".\n",
416                                         conf_file);
417                         fputs(PQerrormsg, stderr);
418                         pqdebug("%s", PQerrormsg);
419                 }
420                 else
421                 {
422                         process_open_config_file(file, raddr, database, host_ok_p, userauth_p,
423                                                                          auth_arg);
424                         FreeFile(file);
425                 }
426                 pfree(conf_file);
427         }
428         pfree(old_conf_file);
429         return;
430 }
431
432
433 static void
434 interpret_ident_response(char ident_response[],
435                                                  bool *error_p, char ident_username[])
436 {
437 /*----------------------------------------------------------------------------
438   Parse the string "ident_response[]" as a response from a query to an Ident
439   server.  If it's a normal response indicating a username, return
440   *error_p == false and the username as ident_username[].  If it's anything
441   else, return *error_p == true and ident_username[] undefined.
442 ----------------------------------------------------------------------------*/
443         char       *cursor;                     /* Cursor into ident_response[] */
444
445         cursor = &ident_response[0];
446
447         /*
448          * Ident's response, in the telnet tradition, should end in crlf
449          * (\r\n).
450          */
451         if (strlen(ident_response) < 2)
452                 *error_p = true;
453         else if (ident_response[strlen(ident_response) - 2] != '\r')
454                 *error_p = true;
455         else
456         {
457                 while (*cursor != ':' && *cursor != '\r')
458                         cursor++;                       /* skip port field */
459
460                 if (*cursor != ':')
461                         *error_p = true;
462                 else
463                 {
464                         /* We're positioned to colon before response type field */
465                         char            response_type[80];
466                         int                     i;              /* Index into response_type[] */
467
468                         cursor++;                       /* Go over colon */
469                         while (isblank(*cursor))
470                                 cursor++;               /* skip blanks */
471                         i = 0;
472                         while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor)
473                                    && i < sizeof(response_type) - 1)
474                                 response_type[i++] = *cursor++;
475                         response_type[i] = '\0';
476                         while (isblank(*cursor))
477                                 cursor++;               /* skip blanks */
478                         if (strcmp(response_type, "USERID") != 0)
479                                 *error_p = true;
480                         else
481                         {
482
483                                 /*
484                                  * It's a USERID response.  Good.  "cursor" should be
485                                  * pointing to the colon that precedes the operating
486                                  * system type.
487                                  */
488                                 if (*cursor != ':')
489                                         *error_p = true;
490                                 else
491                                 {
492                                         cursor++;       /* Go over colon */
493                                         /* Skip over operating system field. */
494                                         while (*cursor != ':' && *cursor != '\r')
495                                                 cursor++;
496                                         if (*cursor != ':')
497                                                 *error_p = true;
498                                         else
499                                         {
500                                                 int                     i;      /* Index into ident_username[] */
501
502                                                 cursor++;               /* Go over colon */
503                                                 while (isblank(*cursor))
504                                                         cursor++;       /* skip blanks */
505                                                 /* Rest of line is username.  Copy it over. */
506                                                 i = 0;
507                                                 while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
508                                                         ident_username[i++] = *cursor++;
509                                                 ident_username[i] = '\0';
510                                                 *error_p = false;
511                                         }
512                                 }
513                         }
514                 }
515         }
516 }
517
518
519
520 static void
521 ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,
522           const ushort remote_port, const ushort local_port,
523           bool *ident_failed, char ident_username[])
524 {
525 /*--------------------------------------------------------------------------
526   Talk to the ident server on host "remote_ip_addr" and find out who
527   owns the tcp connection from his port "remote_port" to port
528   "local_port_addr" on host "local_ip_addr".  Return the username the
529   ident server gives as "ident_username[]".
530
531   IP addresses and port numbers are in network byte order.
532
533   But iff we're unable to get the information from ident, return
534   *ident_failed == true (and ident_username[] undefined).
535 ----------------------------------------------------------------------------*/
536
537         int                     sock_fd;
538
539         /* File descriptor for socket on which we talk to Ident */
540
541         int                     rc;                             /* Return code from a locally called
542                                                                  * function */
543
544         sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
545         if (sock_fd == -1)
546         {
547                 sprintf(PQerrormsg,
548                          "Failed to create socket on which to talk to Ident server. "
549                                 "socket() returned errno = %s (%d)\n",
550                                 strerror(errno), errno);
551                 fputs(PQerrormsg, stderr);
552                 pqdebug("%s", PQerrormsg);
553         }
554         else
555         {
556                 struct sockaddr_in ident_server;
557
558                 /*
559                  * Socket address of Ident server on the system from which client
560                  * is attempting to connect to us.
561                  */
562                 ident_server.sin_family = AF_INET;
563                 ident_server.sin_port = htons(IDENT_PORT);
564                 ident_server.sin_addr = remote_ip_addr;
565                 rc = connect(sock_fd,
566                            (struct sockaddr *) & ident_server, sizeof(ident_server));
567                 if (rc != 0)
568                 {
569                         sprintf(PQerrormsg,
570                                 "Unable to connect to Ident server on the host which is "
571                                         "trying to connect to Postgres "
572                                         "(IP address %s, Port %d). "
573                                         "errno = %s (%d)\n",
574                                         inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
575                         fputs(PQerrormsg, stderr);
576                         pqdebug("%s", PQerrormsg);
577                         *ident_failed = true;
578                 }
579                 else
580                 {
581                         char            ident_query[80];
582
583                         /* The query we send to the Ident server */
584                         sprintf(ident_query, "%d,%d\n",
585                                         ntohs(remote_port), ntohs(local_port));
586                         rc = send(sock_fd, ident_query, strlen(ident_query), 0);
587                         if (rc < 0)
588                         {
589                                 sprintf(PQerrormsg,
590                                                 "Unable to send query to Ident server on the host which is "
591                                           "trying to connect to Postgres (Host %s, Port %d),"
592                                                 "even though we successfully connected to it.  "
593                                                 "errno = %s (%d)\n",
594                                                 inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
595                                 fputs(PQerrormsg, stderr);
596                                 pqdebug("%s", PQerrormsg);
597                                 *ident_failed = true;
598                         }
599                         else
600                         {
601                                 char            ident_response[80 + IDENT_USERNAME_MAX];
602
603                                 rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
604                                 if (rc < 0)
605                                 {
606                                         sprintf(PQerrormsg,
607                                                   "Unable to receive response from Ident server "
608                                                         "on the host which is "
609                                           "trying to connect to Postgres (Host %s, Port %d),"
610                                         "even though we successfully sent our query to it.  "
611                                                         "errno = %s (%d)\n",
612                                                         inet_ntoa(remote_ip_addr), IDENT_PORT,
613                                                         strerror(errno), errno);
614                                         fputs(PQerrormsg, stderr);
615                                         pqdebug("%s", PQerrormsg);
616                                         *ident_failed = true;
617                                 }
618                                 else
619                                 {
620                                         bool            error;  /* response from Ident is garbage. */
621
622                                         ident_response[rc] = '\0';
623                                         interpret_ident_response(ident_response, &error, ident_username);
624                                         *ident_failed = error;
625                                 }
626                         }
627                         close(sock_fd);
628                 }
629         }
630 }
631
632
633
634 static void
635 parse_map_record(FILE *file,
636                                  char file_map[], char file_pguser[], char file_iuser[])
637 {
638 /*---------------------------------------------------------------------------
639   Take the noncomment line which is next on file "file" and interpret
640   it as a line in a usermap file.  Specifically, return the first
641   3 tokens as file_map, file_iuser, and file_pguser, respectively.      If
642   there are fewer than 3 tokens, return null strings for the missing
643   ones.
644
645 ---------------------------------------------------------------------------*/
646         char            buf[MAX_TOKEN];
647
648         /* A token read from the file */
649
650         /* Set defaults in case fields not in file */
651         file_map[0] = '\0';
652         file_pguser[0] = '\0';
653         file_iuser[0] = '\0';
654
655         next_token(file, buf, sizeof(buf));
656         if (buf != '\0')
657         {
658                 strcpy(file_map, buf);
659                 next_token(file, buf, sizeof(buf));
660                 if (buf != '\0')
661                 {
662                         strcpy(file_iuser, buf);
663                         next_token(file, buf, sizeof(buf));
664                         if (buf != '\0')
665                         {
666                                 strcpy(file_pguser, buf);
667                                 read_through_eol(file);
668                         }
669                 }
670         }
671 }
672
673
674
675 static void
676 verify_against_open_usermap(FILE *file,
677                                                         const char pguser[],
678                                                         const char ident_username[],
679                                                         const char usermap_name[],
680                                                         bool *checks_out_p)
681 {
682 /*--------------------------------------------------------------------------
683   This function does the same thing as verify_against_usermap,
684   only with the config file already open on stream descriptor "file".
685 ---------------------------------------------------------------------------*/
686         bool            match;                  /* We found a matching entry in the map
687                                                                  * file */
688         bool            eof;                    /* We've reached the end of the file we're
689                                                                  * reading */
690
691         match = false;                          /* initial value */
692         eof = false;                            /* initial value */
693         while (!eof && !match)
694         {
695                 /* Process a line from the map file */
696
697                 int                     c;                      /* a character read from the file */
698
699                 c = getc(file);
700                 ungetc(c, file);
701                 if (c == EOF)
702                         eof = true;
703                 else
704                 {
705                         if (c == '#')
706                                 read_through_eol(file);
707                         else
708                         {
709                                 /* The following are fields read from a record of the file */
710                                 char            file_map[MAX_TOKEN + 1];
711                                 char            file_pguser[MAX_TOKEN + 1];
712                                 char            file_iuser[MAX_TOKEN + 1];
713
714                                 parse_map_record(file, file_map, file_pguser, file_iuser);
715                                 if (strcmp(file_map, usermap_name) == 0 &&
716                                         strcmp(file_pguser, pguser) == 0 &&
717                                         strcmp(file_iuser, ident_username) == 0)
718                                         match = true;
719                         }
720                 }
721         }
722         *checks_out_p = match;
723 }
724
725
726
727 static void
728 verify_against_usermap(const char pguser[],
729                                            const char ident_username[],
730                                            const char usermap_name[],
731                                            bool *checks_out_p)
732 {
733 /*--------------------------------------------------------------------------
734   See if the user with ident username "ident_username" is allowed to act
735   as Postgres user "pguser" according to usermap "usermap_name".   Look
736   it up in the usermap file.
737
738   Special case: For usermap "sameuser", don't look in the usermap
739   file.  That's an implied map where "pguser" must be identical to
740   "ident_username" in order to be authorized.
741
742   Iff authorized, return *checks_out_p == true.
743
744 --------------------------------------------------------------------------*/
745
746         if (usermap_name[0] == '\0')
747         {
748                 *checks_out_p = false;
749                 sprintf(PQerrormsg,
750                                 "verify_against_usermap: hba configuration file does not "
751                    "have the usermap field filled in in the entry that pertains "
752                   "to this connection.  That field is essential for Ident-based "
753                                 "authentication.\n");
754                 fputs(PQerrormsg, stderr);
755                 pqdebug("%s", PQerrormsg);
756         }
757         else if (strcmp(usermap_name, "sameuser") == 0)
758         {
759                 if (strcmp(ident_username, pguser) == 0)
760                         *checks_out_p = true;
761                 else
762                         *checks_out_p = false;
763         }
764         else
765         {
766                 FILE       *file;               /* The map file we have to read */
767
768                 char       *map_file;   /* The name of the map file we have to
769                                                                  * read */
770
771                 /* put together the full pathname to the map file */
772                 map_file = (char *) palloc((strlen(DataDir) +
773                                                                         strlen(MAP_FILE) + 2) * sizeof(char));
774                 sprintf(map_file, "%s/%s", DataDir, MAP_FILE);
775
776                 file = AllocateFile(map_file, "r");
777                 if (file == NULL)
778                 {
779                         /* The open of the map file failed.  */
780
781                         *checks_out_p = false;
782
783                         sprintf(PQerrormsg,
784                                   "verify_against_usermap: usermap file for Ident-based "
785                                         "authentication "
786                                 "does not exist or permissions are not setup correctly! "
787                                         "Unable to open file \"%s\".\n",
788                                         map_file);
789                         fputs(PQerrormsg, stderr);
790                         pqdebug("%s", PQerrormsg);
791                 }
792                 else
793                 {
794                         verify_against_open_usermap(file,
795                                                                         pguser, ident_username, usermap_name,
796                                                                                 checks_out_p);
797                         FreeFile(file);
798                 }
799                 pfree(map_file);
800
801
802         }
803 }
804
805
806
807 int
808 authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr,
809                   const char postgres_username[],
810                   const char auth_arg[])
811 {
812 /*---------------------------------------------------------------------------
813   Talk to the ident server on the remote host and find out who owns the
814   connection described by "port".  Then look in the usermap file under
815   the usermap auth_arg[] and see if that user is equivalent to
816   Postgres user user[].
817
818   Return STATUS_OK if yes.
819 ---------------------------------------------------------------------------*/
820         bool            checks_out;
821         bool            ident_failed;
822
823         /* We were unable to get ident to give us a username */
824         char            ident_username[IDENT_USERNAME_MAX + 1];
825
826         /* The username returned by ident */
827
828         ident(raddr->sin_addr, laddr->sin_addr,
829                   raddr->sin_port, laddr->sin_port,
830                   &ident_failed, ident_username);
831
832         if (ident_failed)
833                 return STATUS_ERROR;
834
835         verify_against_usermap(postgres_username, ident_username, auth_arg,
836                                                            &checks_out);
837
838         return (checks_out ? STATUS_OK : STATUS_ERROR);
839 }
840
841
842
843 extern int
844 hba_getauthmethod(SockAddr *raddr, char *database, char *auth_arg,
845                         UserAuth *auth_method)
846 {
847 /*---------------------------------------------------------------------------
848   Determine what authentication method should be used when accessing database
849   "database" from frontend "raddr".  Return the method, an optional argument,
850   and STATUS_OK.
851 ----------------------------------------------------------------------------*/
852         bool            host_ok;
853
854         host_ok = false;
855
856         find_hba_entry(raddr, database, &host_ok, auth_method, auth_arg);
857
858         return (host_ok ? STATUS_OK : STATUS_ERROR);
859 }