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