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