]> granicus.if.org Git - postgresql/blob - src/interfaces/libpq/fe-auth.c
Disable local creds on OpenBSD because it doesn't support it. Document
[postgresql] / src / interfaces / libpq / fe-auth.c
1 /*-------------------------------------------------------------------------
2  *
3  * fe-auth.c
4  *         The front-end (client) authorization routines
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * NOTE: the error message strings returned by this module must not
10  * exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
11  *
12  * IDENTIFICATION
13  *        $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.61 2001/09/26 19:54:12 momjian Exp $
14  *
15  *-------------------------------------------------------------------------
16  */
17
18 /*
19  * INTERFACE ROUTINES
20  *         frontend (client) routines:
21  *              fe_sendauth                             send authentication information
22  *              fe_getauthname                  get user's name according to the client side
23  *                                                              of the authentication system
24  *              fe_setauthsvc                   set frontend authentication service
25  *              fe_getauthsvc                   get current frontend authentication service
26  *
27  *
28  *
29  */
30
31 #include "postgres_fe.h"
32
33 #ifdef WIN32
34 #include "win32.h"
35 #else
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <sys/param.h>                  /* for MAXHOSTNAMELEN on most */
41 #include <sys/socket.h>
42 #if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
43 #include <sys/uio.h>
44 #include <sys/ucred.h>
45 #endif
46 #ifndef  MAXHOSTNAMELEN
47 #include <netdb.h>                              /* for MAXHOSTNAMELEN on some */
48 #endif
49 #include <pwd.h>
50 #endif
51
52 #ifdef HAVE_CRYPT_H
53 #include <crypt.h>
54 #endif
55
56 #include "libpq-fe.h"
57 #include "libpq-int.h"
58 #include "fe-auth.h"
59 #include "libpq/crypt.h"
60
61
62 /*
63  * common definitions for generic fe/be routines
64  */
65
66 struct authsvc
67 {
68         char            name[NAMEDATALEN];              /* service nickname (for command
69                                                                                  * line) */
70         MsgType         msgtype;                /* startup packet header type */
71         int                     allowed;                /* initially allowed (before command line
72                                                                  * option parsing)? */
73 };
74
75 /*
76  * Command-line parsing routines use this structure to map nicknames
77  * onto service types (and the startup packets to use with them).
78  *
79  * Programs receiving an authentication request use this structure to
80  * decide which authentication service types are currently permitted.
81  * By default, all authentication systems compiled into the system are
82  * allowed.  Unauthenticated connections are disallowed unless there
83  * isn't any authentication system.
84  */
85 static const struct authsvc authsvcs[] = {
86 #ifdef KRB4
87         {"krb4", STARTUP_KRB4_MSG, 1},
88         {"kerberos", STARTUP_KRB4_MSG, 1},
89 #endif   /* KRB4 */
90 #ifdef KRB5
91         {"krb5", STARTUP_KRB5_MSG, 1},
92         {"kerberos", STARTUP_KRB5_MSG, 1},
93 #endif   /* KRB5 */
94         {UNAUTHNAME, STARTUP_MSG,
95 #if defined(KRB4) || defined(KRB5)
96                 0
97 #else                                                   /* !(KRB4 || KRB5) */
98                 1
99 #endif   /* !(KRB4 || KRB5) */
100         },
101         {"password", STARTUP_PASSWORD_MSG, 0}
102 };
103
104 static const int n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
105
106 #ifdef KRB4
107 /*
108  * MIT Kerberos authentication system - protocol version 4
109  */
110
111 #include "krb.h"
112
113 /* for some reason, this is not defined in krb.h ... */
114 extern char *tkt_string(void);
115
116 /*
117  * pg_krb4_init -- initialization performed before any Kerberos calls are made
118  *
119  * For v4, all we need to do is make sure the library routines get the right
120  * ticket file if we want them to see a special one.  (They will open the file
121  * themselves.)
122  */
123 static void
124 pg_krb4_init()
125 {
126         char       *realm;
127         static int      init_done = 0;
128
129         if (init_done)
130                 return;
131         init_done = 1;
132
133         /*
134          * If the user set PGREALM, then we use a ticket file with a special
135          * name: <usual-ticket-file-name>@<PGREALM-value>
136          */
137         if ((realm = getenv("PGREALM")))
138         {
139                 char            tktbuf[MAXPGPATH];
140
141                 (void) sprintf(tktbuf, "%s@%s", tkt_string(), realm);
142                 krb_set_tkt_string(tktbuf);
143         }
144 }
145
146 /*
147  * pg_krb4_authname -- returns a pointer to static space containing whatever
148  *                                         name the user has authenticated to the system
149  *
150  * We obtain this information by digging around in the ticket file.
151  */
152 static char *
153 pg_krb4_authname(char *PQerrormsg)
154 {
155         char            instance[INST_SZ + 1];
156         char            realm[REALM_SZ + 1];
157         int                     status;
158         static char name[SNAME_SZ + 1] = "";
159
160         if (name[0])
161                 return name;
162
163         pg_krb4_init();
164
165         name[SNAME_SZ] = '\0';
166         status = krb_get_tf_fullname(tkt_string(), name, instance, realm);
167         if (status != KSUCCESS)
168         {
169                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
170                                  "pg_krb4_authname: krb_get_tf_fullname: %s\n",
171                                  krb_err_txt[status]);
172                 return (char *) NULL;
173         }
174         return name;
175 }
176
177 /*
178  * pg_krb4_sendauth -- client routine to send authentication information to
179  *                                         the server
180  *
181  * This routine does not do mutual authentication, nor does it return enough
182  * information to do encrypted connections.  But then, if we want to do
183  * encrypted connections, we'll have to redesign the whole RPC mechanism
184  * anyway.
185  *
186  * If the user is too lazy to feed us a hostname, we try to come up with
187  * something other than "localhost" since the hostname is used as an
188  * instance and instance names in v4 databases are usually actual hostnames
189  * (canonicalized to omit all domain suffixes).
190  */
191 static int
192 pg_krb4_sendauth(char *PQerrormsg, int sock,
193                                  struct sockaddr_in * laddr,
194                                  struct sockaddr_in * raddr,
195                                  const char *hostname)
196 {
197         long            krbopts = 0;    /* one-way authentication */
198         KTEXT_ST        clttkt;
199         int                     status;
200         char            hostbuf[MAXHOSTNAMELEN];
201         const char *realm = getenv("PGREALM");          /* NULL == current realm */
202
203         if (!hostname || !(*hostname))
204         {
205                 if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
206                         strcpy(hostbuf, "localhost");
207                 hostname = hostbuf;
208         }
209
210         pg_krb4_init();
211
212         status = krb_sendauth(krbopts,
213                                                   sock,
214                                                   &clttkt,
215                                                   PG_KRB_SRVNAM,
216                                                   hostname,
217                                                   realm,
218                                                   (u_long) 0,
219                                                   (MSG_DAT *) NULL,
220                                                   (CREDENTIALS *) NULL,
221                                                   NULL,
222                                                   laddr,
223                                                   raddr,
224                                                   PG_KRB4_VERSION);
225         if (status != KSUCCESS)
226         {
227                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
228                                  libpq_gettext("Kerberos 4 error: %s\n"),
229                                  krb_err_txt[status]);
230                 return STATUS_ERROR;
231         }
232         return STATUS_OK;
233 }
234
235 #endif   /* KRB4 */
236
237 #ifdef KRB5
238 /*
239  * MIT Kerberos authentication system - protocol version 5
240  */
241
242 #include <krb5.h>
243 #include <com_err.h>
244
245 /*
246  * pg_an_to_ln -- return the local name corresponding to an authentication
247  *                                name
248  *
249  * XXX Assumes that the first aname component is the user name.  This is NOT
250  *         necessarily so, since an aname can actually be something out of your
251  *         worst X.400 nightmare, like
252  *                ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
253  *         Note that the MIT an_to_ln code does the same thing if you don't
254  *         provide an aname mapping database...it may be a better idea to use
255  *         krb5_an_to_ln, except that it punts if multiple components are found,
256  *         and we can't afford to punt.
257  */
258 static char *
259 pg_an_to_ln(char *aname)
260 {
261         char       *p;
262
263         if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
264                 *p = '\0';
265         return aname;
266 }
267
268
269 /*
270  * Various krb5 state which is not connection specfic, and a flag to
271  * indicate whether we have initialised it yet.
272  */
273 static int      pg_krb5_initialised;
274 static krb5_context pg_krb5_context;
275 static krb5_ccache pg_krb5_ccache;
276 static krb5_principal pg_krb5_client;
277 static char *pg_krb5_name;
278
279
280 static int
281 pg_krb5_init(char *PQerrormsg)
282 {
283         krb5_error_code retval;
284
285         if (pg_krb5_initialised)
286                 return STATUS_OK;
287
288         retval = krb5_init_context(&pg_krb5_context);
289         if (retval)
290         {
291                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
292                                  "pg_krb5_init: krb5_init_context: %s\n",
293                                  error_message(retval));
294                 return STATUS_ERROR;
295         }
296
297         retval = krb5_cc_default(pg_krb5_context, &pg_krb5_ccache);
298         if (retval)
299         {
300                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
301                                  "pg_krb5_init: krb5_cc_default: %s\n",
302                                  error_message(retval));
303                 krb5_free_context(pg_krb5_context);
304                 return STATUS_ERROR;
305         }
306
307         retval = krb5_cc_get_principal(pg_krb5_context, pg_krb5_ccache,
308                                                                    &pg_krb5_client);
309         if (retval)
310         {
311                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
312                                  "pg_krb5_init: krb5_cc_get_principal: %s\n",
313                                  error_message(retval));
314                 krb5_cc_close(pg_krb5_context, pg_krb5_ccache);
315                 krb5_free_context(pg_krb5_context);
316                 return STATUS_ERROR;
317         }
318
319         retval = krb5_unparse_name(pg_krb5_context, pg_krb5_client, &pg_krb5_name);
320         if (retval)
321         {
322                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
323                                  "pg_krb5_init: krb5_unparse_name: %s\n",
324                                  error_message(retval));
325                 krb5_free_principal(pg_krb5_context, pg_krb5_client);
326                 krb5_cc_close(pg_krb5_context, pg_krb5_ccache);
327                 krb5_free_context(pg_krb5_context);
328                 return STATUS_ERROR;
329         }
330
331         pg_krb5_name = pg_an_to_ln(pg_krb5_name);
332
333         pg_krb5_initialised = 1;
334         return STATUS_OK;
335 }
336
337
338 /*
339  * pg_krb5_authname -- returns a pointer to static space containing whatever
340  *                                         name the user has authenticated to the system
341   */
342 static const char *
343 pg_krb5_authname(char *PQerrormsg)
344 {
345         if (pg_krb5_init(PQerrormsg) != STATUS_OK)
346                 return NULL;
347
348         return pg_krb5_name;
349 }
350
351
352 /*
353  * pg_krb5_sendauth -- client routine to send authentication information to
354  *                                         the server
355  */
356 static int
357 pg_krb5_sendauth(char *PQerrormsg, int sock,
358                                  struct sockaddr_in * laddr,
359                                  struct sockaddr_in * raddr,
360                                  const char *hostname)
361 {
362         krb5_error_code retval;
363         int                     ret;
364         krb5_principal server;
365         krb5_auth_context auth_context = NULL;
366         krb5_error *err_ret = NULL;
367         int                     flags;
368
369         ret = pg_krb5_init(PQerrormsg);
370         if (ret != STATUS_OK)
371                 return ret;
372
373         retval = krb5_sname_to_principal(pg_krb5_context, hostname, PG_KRB_SRVNAM,
374                                                                          KRB5_NT_SRV_HST, &server);
375         if (retval)
376         {
377                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
378                                  "pg_krb5_sendauth: krb5_sname_to_principal: %s\n",
379                                  error_message(retval));
380                 return STATUS_ERROR;
381         }
382
383         /*
384          * libpq uses a non-blocking socket. But kerberos needs a blocking
385          * socket, and we have to block somehow to do mutual authentication
386          * anyway. So we temporarily make it blocking.
387          */
388         flags = fcntl(sock, F_GETFL);
389         if (flags < 0 || fcntl(sock, F_SETFL, (long) (flags & ~O_NONBLOCK)))
390         {
391                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
392                                  libpq_gettext("could not set socket to blocking mode: %s\n"), strerror(errno));
393                 krb5_free_principal(pg_krb5_context, server);
394                 return STATUS_ERROR;
395         }
396
397         retval = krb5_sendauth(pg_krb5_context, &auth_context,
398                                                    (krb5_pointer) & sock, PG_KRB_SRVNAM,
399                                                    pg_krb5_client, server,
400                                                    AP_OPTS_MUTUAL_REQUIRED,
401                                                    NULL, 0,             /* no creds, use ccache instead */
402                                                    pg_krb5_ccache, &err_ret, NULL, NULL);
403         if (retval)
404         {
405                 if (retval == KRB5_SENDAUTH_REJECTED && err_ret)
406                 {
407                         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
408                                          libpq_gettext("Kerberos 5 authentication rejected: %*s\n"),
409                                          err_ret->text.length, err_ret->text.data);
410                 }
411                 else
412                 {
413                         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
414                                          "krb5_sendauth: %s\n", error_message(retval));
415                 }
416
417                 if (err_ret)
418                         krb5_free_error(pg_krb5_context, err_ret);
419
420                 ret = STATUS_ERROR;
421         }
422
423         krb5_free_principal(pg_krb5_context, server);
424
425         if (fcntl(sock, F_SETFL, (long) flags))
426         {
427                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
428                                  libpq_gettext("could not restore non-blocking mode on socket: %s\n"),
429                                  strerror(errno));
430                 ret = STATUS_ERROR;
431         }
432
433         return ret;
434 }
435
436 #endif   /* KRB5 */
437
438 static int
439 pg_local_sendauth(char *PQerrormsg, PGconn *conn)
440 {
441 #if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
442         char buf;
443         struct iovec iov;
444         struct msghdr msg;
445 #ifdef HAVE_STRUCT_CMSGCRED
446         /* Prevent padding */
447         char cmsgmem[sizeof(struct cmsghdr) + sizeof(struct cmsgcred)];
448         /* Point to start of first structure */
449         struct cmsghdr *cmsg = (struct cmsghdr *)cmsgmem;
450 #endif
451 #ifdef HAVE_STRUCT_SOCKCRED
452         /* Prevent padding */
453         char cmsgmem[sizeof(struct cmsghdr) + sizeof(struct sockcred)];
454         /* Point to start of first structure */
455         struct cmsghdr *cmsg = (struct cmsghdr *)cmsgmem;
456 #endif
457
458         /*
459          * The backend doesn't care what we send here, but it wants
460          * exactly one character to force recvmsg() to block and wait
461          * for us.
462          */
463         buf = '\0';
464         iov.iov_base = &buf;
465         iov.iov_len = 1;
466
467         memset(&msg, 0, sizeof(msg));
468         msg.msg_iov = &iov;
469         msg.msg_iovlen = 1;
470
471 #ifdef HAVE_STRUCT_CMSGCRED
472         /* Create control header, FreeBSD */
473         msg.msg_control = cmsg;
474         msg.msg_controllen = sizeof(cmsgmem);
475         memset(cmsg, 0, sizeof(cmsgmem));
476         cmsg->cmsg_len = sizeof(cmsgmem);
477         cmsg->cmsg_level = SOL_SOCKET;
478         cmsg->cmsg_type = SCM_CREDS;
479 #endif
480
481         if (sendmsg(conn->sock, &msg, 0) == -1)
482         {
483                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
484                          "pg_local_sendauth: sendmsg: %s\n", strerror(errno));
485                 return STATUS_ERROR;
486         }
487         return STATUS_OK;
488 #else
489         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
490                          libpq_gettext("SCM_CRED authentication method not supported\n"));
491         return STATUS_ERROR;
492 #endif
493 }
494
495 static int
496 pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
497 {
498         int ret;
499         char *crypt_pwd;
500
501         /* Encrypt the password if needed. */
502
503         switch (areq)
504         {
505                 case AUTH_REQ_MD5:
506                 {
507                         char *crypt_pwd2;
508
509                         if (!(crypt_pwd = malloc(MD5_PASSWD_LEN+1)) ||
510                                 !(crypt_pwd2 = malloc(MD5_PASSWD_LEN+1)))
511                         {
512                                 perror("malloc");
513                                 return STATUS_ERROR;
514                         }
515                         if (!EncryptMD5(password, conn->pguser,
516                                                         strlen(conn->pguser), crypt_pwd2))
517                         {
518                                 free(crypt_pwd);
519                                 free(crypt_pwd2);
520                                 return STATUS_ERROR;
521                         }
522                         if (!EncryptMD5(crypt_pwd2 + strlen("md5"), conn->md5Salt,
523                                                         sizeof(conn->md5Salt), crypt_pwd))
524                         {
525                                 free(crypt_pwd);
526                                 free(crypt_pwd2);
527                                 return STATUS_ERROR;
528                         }
529                         free(crypt_pwd2);
530                         break;
531                 }
532                 case AUTH_REQ_CRYPT:
533                 {
534                         char salt[3];
535
536                         StrNCpy(salt, conn->cryptSalt,3);
537                         crypt_pwd = crypt(password, salt);
538                         break;
539                 }
540                 case AUTH_REQ_PASSWORD:
541                         /* discard const so we can assign it */
542                         crypt_pwd = (char *)password;
543                         break;
544                 default:
545                         return STATUS_ERROR;
546         }
547         ret = pqPacketSend(conn, crypt_pwd, strlen(crypt_pwd) + 1);
548         if (areq == AUTH_REQ_MD5)
549                 free(crypt_pwd);
550         return ret;
551 }
552
553 /*
554  * fe_sendauth -- client demux routine for outgoing authentication information
555  */
556 int
557 fe_sendauth(AuthRequest areq, PGconn *conn, const char *hostname,
558                         const char *password, char *PQerrormsg)
559 {
560 #if !defined(KRB4) && !defined(KRB5)
561         (void) hostname;                        /* not used */
562 #endif
563
564         switch (areq)
565         {
566                 case AUTH_REQ_OK:
567                         break;
568
569                 case AUTH_REQ_KRB4:
570 #ifdef KRB4
571                         if (pg_krb4_sendauth(PQerrormsg, conn->sock, &conn->laddr.in,
572                                                                  &conn->raddr.in,
573                                                                  hostname) != STATUS_OK)
574                         {
575                                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
576                                                  libpq_gettext("Kerberos 4 authentication failed\n"));
577                                 return STATUS_ERROR;
578                         }
579                         break;
580 #else
581                         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
582                                          libpq_gettext("Kerberos 4 authentication not supported\n"));
583                         return STATUS_ERROR;
584 #endif
585
586                 case AUTH_REQ_KRB5:
587 #ifdef KRB5
588                         if (pg_krb5_sendauth(PQerrormsg, conn->sock, &conn->laddr.in,
589                                                                  &conn->raddr.in,
590                                                                  hostname) != STATUS_OK)
591                         {
592                                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
593                                                  libpq_gettext("Kerberos 5 authentication failed\n"));
594                                 return STATUS_ERROR;
595                         }
596                         break;
597 #else
598                         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
599                                          libpq_gettext("Kerberos 5 authentication not supported\n"));
600                         return STATUS_ERROR;
601 #endif
602
603                 case AUTH_REQ_MD5:
604                 case AUTH_REQ_CRYPT:
605                 case AUTH_REQ_PASSWORD:
606                         if (password == NULL || *password == '\0')
607                         {
608                                 (void) sprintf(PQerrormsg,
609                                                            "fe_sendauth: no password supplied\n");
610                                 return STATUS_ERROR;
611                         }
612                         if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
613                         {
614                                 (void) sprintf(PQerrormsg,
615                                  "fe_sendauth: error sending password authentication\n");
616                                 return STATUS_ERROR;
617                         }
618                         break;
619
620                 case AUTH_REQ_SCM_CREDS:
621                         if (pg_local_sendauth(PQerrormsg, conn) != STATUS_OK)
622                                 return STATUS_ERROR;
623                         break;
624
625                 default:
626                         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
627                                          libpq_gettext("authentication method %u not supported\n"), areq);
628                         return STATUS_ERROR;
629         }
630
631         return STATUS_OK;
632 }
633
634 /*
635  * fe_setauthsvc
636  * fe_getauthsvc
637  *
638  * Set/return the authentication service currently selected for use by the
639  * frontend. (You can only use one in the frontend, obviously.)
640  *
641  * NB: This is not thread-safe if different threads try to select different
642  * authentication services!  It's OK for fe_getauthsvc to select the default,
643  * since that will be the same for all threads, but direct application use
644  * of fe_setauthsvc is not thread-safe.  However, use of fe_setauthsvc is
645  * deprecated anyway...
646  */
647
648 static int      pg_authsvc = -1;
649
650 void
651 fe_setauthsvc(const char *name, char *PQerrormsg)
652 {
653         int                     i;
654
655         for (i = 0; i < n_authsvcs; ++i)
656                 if (strcmp(name, authsvcs[i].name) == 0)
657                 {
658                         pg_authsvc = i;
659                         break;
660                 }
661         if (i == n_authsvcs)
662         {
663                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
664                                  libpq_gettext("invalid authentication service name \"%s\", ignored\n"),
665                                  name);
666         }
667         return;
668 }
669
670 MsgType
671 fe_getauthsvc(char *PQerrormsg)
672 {
673         if (pg_authsvc < 0 || pg_authsvc >= n_authsvcs)
674                 fe_setauthsvc(DEFAULT_CLIENT_AUTHSVC, PQerrormsg);
675         return authsvcs[pg_authsvc].msgtype;
676 }
677
678 /*
679  * fe_getauthname -- returns a pointer to dynamic space containing whatever
680  *                                       name the user has authenticated to the system
681  * if there is an error, return the error message in PQerrormsg
682  */
683 char *
684 fe_getauthname(char *PQerrormsg)
685 {
686         char       *name = (char *) NULL;
687         char       *authn = (char *) NULL;
688         MsgType         authsvc;
689
690         authsvc = fe_getauthsvc(PQerrormsg);
691
692 #ifdef KRB4
693         if (authsvc == STARTUP_KRB4_MSG)
694                 name = pg_krb4_authname(PQerrormsg);
695 #endif
696 #ifdef KRB5
697         if (authsvc == STARTUP_KRB5_MSG)
698                 name = pg_krb5_authname(PQerrormsg);
699 #endif
700
701         if (authsvc == STARTUP_MSG
702                 || (authsvc == STARTUP_KRB4_MSG && !name)
703                 || (authsvc == STARTUP_KRB5_MSG && !name))
704         {
705 #ifdef WIN32
706                 char            username[128];
707                 DWORD           namesize = sizeof(username) - 1;
708
709                 if (GetUserName(username, &namesize))
710                         name = username;
711 #else
712                 struct passwd *pw = getpwuid(geteuid());
713
714                 if (pw)
715                         name = pw->pw_name;
716 #endif
717         }
718
719         if (authsvc != STARTUP_MSG && authsvc != STARTUP_KRB4_MSG && authsvc != STARTUP_KRB5_MSG)
720                 snprintf(PQerrormsg, PQERRORMSG_LENGTH,
721                                  libpq_gettext("fe_getauthname: invalid authentication system: %d\n"),
722                                  authsvc);
723
724         if (name && (authn = (char *) malloc(strlen(name) + 1)))
725                 strcpy(authn, name);
726         return authn;
727 }