Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * fe-auth.c
4 : * The front-end (client) authorization routines
5 : *
6 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * IDENTIFICATION
10 : * src/interfaces/libpq/fe-auth.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 :
15 : /*
16 : * INTERFACE ROUTINES
17 : * frontend (client) routines:
18 : * pg_fe_sendauth send authentication information
19 : * pg_fe_getauthname get user's name according to the client side
20 : * of the authentication system
21 : */
22 :
23 : #include "postgres_fe.h"
24 :
25 : #ifdef WIN32
26 : #include "win32.h"
27 : #else
28 : #include <unistd.h>
29 : #include <fcntl.h>
30 : #include <sys/param.h> /* for MAXHOSTNAMELEN on most */
31 : #include <sys/socket.h>
32 : #ifdef HAVE_SYS_UCRED_H
33 : #include <sys/ucred.h>
34 : #endif
35 : #ifndef MAXHOSTNAMELEN
36 : #include <netdb.h> /* for MAXHOSTNAMELEN on some */
37 : #endif
38 : #include <pwd.h>
39 : #endif
40 :
41 : #include "common/md5.h"
42 : #include "libpq-fe.h"
43 : #include "libpq/scram.h"
44 : #include "fe-auth.h"
45 :
46 :
47 : #ifdef ENABLE_GSS
48 : /*
49 : * GSSAPI authentication system.
50 : */
51 :
52 : #if defined(WIN32) && !defined(_MSC_VER)
53 : /*
54 : * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW
55 : * that contain the OIDs required. Redefine here, values copied
56 : * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c
57 : */
58 : static const gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_desc =
59 : {10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"};
60 : static GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_desc;
61 : #endif
62 :
63 : /*
64 : * Fetch all errors of a specific type and append to "str".
65 : */
66 : static void
67 : pg_GSS_error_int(PQExpBuffer str, const char *mprefix,
68 : OM_uint32 stat, int type)
69 : {
70 : OM_uint32 lmin_s;
71 : gss_buffer_desc lmsg;
72 : OM_uint32 msg_ctx = 0;
73 :
74 : do
75 : {
76 : gss_display_status(&lmin_s, stat, type,
77 : GSS_C_NO_OID, &msg_ctx, &lmsg);
78 : appendPQExpBuffer(str, "%s: %s\n", mprefix, (char *) lmsg.value);
79 : gss_release_buffer(&lmin_s, &lmsg);
80 : } while (msg_ctx);
81 : }
82 :
83 : /*
84 : * GSSAPI errors contain two parts; put both into conn->errorMessage.
85 : */
86 : static void
87 : pg_GSS_error(const char *mprefix, PGconn *conn,
88 : OM_uint32 maj_stat, OM_uint32 min_stat)
89 : {
90 : resetPQExpBuffer(&conn->errorMessage);
91 :
92 : /* Fetch major error codes */
93 : pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE);
94 :
95 : /* Add the minor codes as well */
96 : pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE);
97 : }
98 :
99 : /*
100 : * Continue GSS authentication with next token as needed.
101 : */
102 : static int
103 : pg_GSS_continue(PGconn *conn, int payloadlen)
104 : {
105 : OM_uint32 maj_stat,
106 : min_stat,
107 : lmin_s;
108 : gss_buffer_desc ginbuf;
109 : gss_buffer_desc goutbuf;
110 :
111 : /*
112 : * On first call, there's no input token. On subsequent calls, read the
113 : * input token into a GSS buffer.
114 : */
115 : if (conn->gctx != GSS_C_NO_CONTEXT)
116 : {
117 : ginbuf.length = payloadlen;
118 : ginbuf.value = malloc(payloadlen);
119 : if (!ginbuf.value)
120 : {
121 : printfPQExpBuffer(&conn->errorMessage,
122 : libpq_gettext("out of memory allocating GSSAPI buffer (%d)\n"),
123 : payloadlen);
124 : return STATUS_ERROR;
125 : }
126 : if (pqGetnchar(ginbuf.value, payloadlen, conn))
127 : {
128 : /*
129 : * Shouldn't happen, because the caller should've ensured that the
130 : * whole message is already in the input buffer.
131 : */
132 : free(ginbuf.value);
133 : return STATUS_ERROR;
134 : }
135 : }
136 : else
137 : {
138 : ginbuf.length = 0;
139 : ginbuf.value = NULL;
140 : }
141 :
142 : maj_stat = gss_init_sec_context(&min_stat,
143 : GSS_C_NO_CREDENTIAL,
144 : &conn->gctx,
145 : conn->gtarg_nam,
146 : GSS_C_NO_OID,
147 : GSS_C_MUTUAL_FLAG,
148 : 0,
149 : GSS_C_NO_CHANNEL_BINDINGS,
150 : (ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf,
151 : NULL,
152 : &goutbuf,
153 : NULL,
154 : NULL);
155 :
156 : if (ginbuf.value)
157 : free(ginbuf.value);
158 :
159 : if (goutbuf.length != 0)
160 : {
161 : /*
162 : * GSS generated data to send to the server. We don't care if it's the
163 : * first or subsequent packet, just send the same kind of password
164 : * packet.
165 : */
166 : if (pqPacketSend(conn, 'p',
167 : goutbuf.value, goutbuf.length) != STATUS_OK)
168 : {
169 : gss_release_buffer(&lmin_s, &goutbuf);
170 : return STATUS_ERROR;
171 : }
172 : }
173 : gss_release_buffer(&lmin_s, &goutbuf);
174 :
175 : if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
176 : {
177 : pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
178 : conn,
179 : maj_stat, min_stat);
180 : gss_release_name(&lmin_s, &conn->gtarg_nam);
181 : if (conn->gctx)
182 : gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
183 : return STATUS_ERROR;
184 : }
185 :
186 : if (maj_stat == GSS_S_COMPLETE)
187 : gss_release_name(&lmin_s, &conn->gtarg_nam);
188 :
189 : return STATUS_OK;
190 : }
191 :
192 : /*
193 : * Send initial GSS authentication token
194 : */
195 : static int
196 : pg_GSS_startup(PGconn *conn, int payloadlen)
197 : {
198 : OM_uint32 maj_stat,
199 : min_stat;
200 : int maxlen;
201 : gss_buffer_desc temp_gbuf;
202 : char *host = PQhost(conn);
203 :
204 : if (!(host && host[0] != '\0'))
205 : {
206 : printfPQExpBuffer(&conn->errorMessage,
207 : libpq_gettext("host name must be specified\n"));
208 : return STATUS_ERROR;
209 : }
210 :
211 : if (conn->gctx)
212 : {
213 : printfPQExpBuffer(&conn->errorMessage,
214 : libpq_gettext("duplicate GSS authentication request\n"));
215 : return STATUS_ERROR;
216 : }
217 :
218 : /*
219 : * Import service principal name so the proper ticket can be acquired by
220 : * the GSSAPI system.
221 : */
222 : maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
223 : temp_gbuf.value = (char *) malloc(maxlen);
224 : if (!temp_gbuf.value)
225 : {
226 : printfPQExpBuffer(&conn->errorMessage,
227 : libpq_gettext("out of memory\n"));
228 : return STATUS_ERROR;
229 : }
230 : snprintf(temp_gbuf.value, maxlen, "%s@%s",
231 : conn->krbsrvname, host);
232 : temp_gbuf.length = strlen(temp_gbuf.value);
233 :
234 : maj_stat = gss_import_name(&min_stat, &temp_gbuf,
235 : GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam);
236 : free(temp_gbuf.value);
237 :
238 : if (maj_stat != GSS_S_COMPLETE)
239 : {
240 : pg_GSS_error(libpq_gettext("GSSAPI name import error"),
241 : conn,
242 : maj_stat, min_stat);
243 : return STATUS_ERROR;
244 : }
245 :
246 : /*
247 : * Initial packet is the same as a continuation packet with no initial
248 : * context.
249 : */
250 : conn->gctx = GSS_C_NO_CONTEXT;
251 :
252 : return pg_GSS_continue(conn, payloadlen);
253 : }
254 : #endif /* ENABLE_GSS */
255 :
256 :
257 : #ifdef ENABLE_SSPI
258 : /*
259 : * SSPI authentication system (Windows only)
260 : */
261 :
262 : static void
263 : pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
264 : {
265 : char sysmsg[256];
266 :
267 : if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
268 : FORMAT_MESSAGE_FROM_SYSTEM,
269 : NULL, r, 0,
270 : sysmsg, sizeof(sysmsg), NULL) == 0)
271 : printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n",
272 : mprefix, (unsigned int) r);
273 : else
274 : printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n",
275 : mprefix, sysmsg, (unsigned int) r);
276 : }
277 :
278 : /*
279 : * Continue SSPI authentication with next token as needed.
280 : */
281 : static int
282 : pg_SSPI_continue(PGconn *conn, int payloadlen)
283 : {
284 : SECURITY_STATUS r;
285 : CtxtHandle newContext;
286 : ULONG contextAttr;
287 : SecBufferDesc inbuf;
288 : SecBufferDesc outbuf;
289 : SecBuffer OutBuffers[1];
290 : SecBuffer InBuffers[1];
291 : char *inputbuf = NULL;
292 :
293 : if (conn->sspictx != NULL)
294 : {
295 : /*
296 : * On runs other than the first we have some data to send. Put this
297 : * data in a SecBuffer type structure.
298 : */
299 : inputbuf = malloc(payloadlen);
300 : if (!inputbuf)
301 : {
302 : printfPQExpBuffer(&conn->errorMessage,
303 : libpq_gettext("out of memory allocating SSPI buffer (%d)\n"),
304 : payloadlen);
305 : return STATUS_ERROR;
306 : }
307 : if (pqGetnchar(inputbuf, payloadlen, conn))
308 : {
309 : /*
310 : * Shouldn't happen, because the caller should've ensured that the
311 : * whole message is already in the input buffer.
312 : */
313 : free(inputbuf);
314 : return STATUS_ERROR;
315 : }
316 :
317 : inbuf.ulVersion = SECBUFFER_VERSION;
318 : inbuf.cBuffers = 1;
319 : inbuf.pBuffers = InBuffers;
320 : InBuffers[0].pvBuffer = inputbuf;
321 : InBuffers[0].cbBuffer = payloadlen;
322 : InBuffers[0].BufferType = SECBUFFER_TOKEN;
323 : }
324 :
325 : OutBuffers[0].pvBuffer = NULL;
326 : OutBuffers[0].BufferType = SECBUFFER_TOKEN;
327 : OutBuffers[0].cbBuffer = 0;
328 : outbuf.cBuffers = 1;
329 : outbuf.pBuffers = OutBuffers;
330 : outbuf.ulVersion = SECBUFFER_VERSION;
331 :
332 : r = InitializeSecurityContext(conn->sspicred,
333 : conn->sspictx,
334 : conn->sspitarget,
335 : ISC_REQ_ALLOCATE_MEMORY,
336 : 0,
337 : SECURITY_NETWORK_DREP,
338 : (conn->sspictx == NULL) ? NULL : &inbuf,
339 : 0,
340 : &newContext,
341 : &outbuf,
342 : &contextAttr,
343 : NULL);
344 :
345 : /* we don't need the input anymore */
346 : if (inputbuf)
347 : free(inputbuf);
348 :
349 : if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
350 : {
351 : pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r);
352 :
353 : return STATUS_ERROR;
354 : }
355 :
356 : if (conn->sspictx == NULL)
357 : {
358 : /* On first run, transfer retrieved context handle */
359 : conn->sspictx = malloc(sizeof(CtxtHandle));
360 : if (conn->sspictx == NULL)
361 : {
362 : printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
363 : return STATUS_ERROR;
364 : }
365 : memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
366 : }
367 :
368 : /*
369 : * If SSPI returned any data to be sent to the server (as it normally
370 : * would), send this data as a password packet.
371 : */
372 : if (outbuf.cBuffers > 0)
373 : {
374 : if (outbuf.cBuffers != 1)
375 : {
376 : /*
377 : * This should never happen, at least not for Kerberos
378 : * authentication. Keep check in case it shows up with other
379 : * authentication methods later.
380 : */
381 : printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n");
382 : return STATUS_ERROR;
383 : }
384 :
385 : /*
386 : * If the negotiation is complete, there may be zero bytes to send.
387 : * The server is at this point not expecting any more data, so don't
388 : * send it.
389 : */
390 : if (outbuf.pBuffers[0].cbBuffer > 0)
391 : {
392 : if (pqPacketSend(conn, 'p',
393 : outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
394 : {
395 : FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
396 : return STATUS_ERROR;
397 : }
398 : }
399 : FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
400 : }
401 :
402 : /* Cleanup is handled by the code in freePGconn() */
403 : return STATUS_OK;
404 : }
405 :
406 : /*
407 : * Send initial SSPI authentication token.
408 : * If use_negotiate is 0, use kerberos authentication package which is
409 : * compatible with Unix. If use_negotiate is 1, use the negotiate package
410 : * which supports both kerberos and NTLM, but is not compatible with Unix.
411 : */
412 : static int
413 : pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen)
414 : {
415 : SECURITY_STATUS r;
416 : TimeStamp expire;
417 : char *host = PQhost(conn);
418 :
419 : if (conn->sspictx)
420 : {
421 : printfPQExpBuffer(&conn->errorMessage,
422 : libpq_gettext("duplicate SSPI authentication request\n"));
423 : return STATUS_ERROR;
424 : }
425 :
426 : /*
427 : * Retrieve credentials handle
428 : */
429 : conn->sspicred = malloc(sizeof(CredHandle));
430 : if (conn->sspicred == NULL)
431 : {
432 : printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
433 : return STATUS_ERROR;
434 : }
435 :
436 : r = AcquireCredentialsHandle(NULL,
437 : use_negotiate ? "negotiate" : "kerberos",
438 : SECPKG_CRED_OUTBOUND,
439 : NULL,
440 : NULL,
441 : NULL,
442 : NULL,
443 : conn->sspicred,
444 : &expire);
445 : if (r != SEC_E_OK)
446 : {
447 : pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r);
448 : free(conn->sspicred);
449 : conn->sspicred = NULL;
450 : return STATUS_ERROR;
451 : }
452 :
453 : /*
454 : * Compute target principal name. SSPI has a different format from GSSAPI,
455 : * but not more complex. We can skip the @REALM part, because Windows will
456 : * fill that in for us automatically.
457 : */
458 : if (!(host && host[0] != '\0'))
459 : {
460 : printfPQExpBuffer(&conn->errorMessage,
461 : libpq_gettext("host name must be specified\n"));
462 : return STATUS_ERROR;
463 : }
464 : conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2);
465 : if (!conn->sspitarget)
466 : {
467 : printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
468 : return STATUS_ERROR;
469 : }
470 : sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host);
471 :
472 : /*
473 : * Indicate that we're in SSPI authentication mode to make sure that
474 : * pg_SSPI_continue is called next time in the negotiation.
475 : */
476 : conn->usesspi = 1;
477 :
478 : return pg_SSPI_continue(conn, payloadlen);
479 : }
480 : #endif /* ENABLE_SSPI */
481 :
482 : /*
483 : * Initialize SASL authentication exchange.
484 : */
485 : static int
486 0 : pg_SASL_init(PGconn *conn, int payloadlen)
487 : {
488 0 : char *initialresponse = NULL;
489 : int initialresponselen;
490 : bool done;
491 : bool success;
492 : const char *selected_mechanism;
493 : PQExpBufferData mechanism_buf;
494 :
495 0 : initPQExpBuffer(&mechanism_buf);
496 :
497 0 : if (conn->sasl_state)
498 : {
499 0 : printfPQExpBuffer(&conn->errorMessage,
500 : libpq_gettext("duplicate SASL authentication request\n"));
501 0 : goto error;
502 : }
503 :
504 : /*
505 : * Parse the list of SASL authentication mechanisms in the
506 : * AuthenticationSASL message, and select the best mechanism that we
507 : * support. (Only SCRAM-SHA-256 is supported at the moment.)
508 : */
509 0 : selected_mechanism = NULL;
510 : for (;;)
511 : {
512 0 : if (pqGets(&mechanism_buf, conn))
513 : {
514 0 : printfPQExpBuffer(&conn->errorMessage,
515 : "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n");
516 0 : goto error;
517 : }
518 0 : if (PQExpBufferDataBroken(mechanism_buf))
519 0 : goto oom_error;
520 :
521 : /* An empty string indicates end of list */
522 0 : if (mechanism_buf.data[0] == '\0')
523 0 : break;
524 :
525 : /*
526 : * If we have already selected a mechanism, just skip through the rest
527 : * of the list.
528 : */
529 0 : if (selected_mechanism)
530 0 : continue;
531 :
532 : /*
533 : * Do we support this mechanism?
534 : */
535 0 : if (strcmp(mechanism_buf.data, SCRAM_SHA256_NAME) == 0)
536 : {
537 : char *password;
538 :
539 0 : conn->password_needed = true;
540 0 : password = conn->connhost[conn->whichhost].password;
541 0 : if (password == NULL)
542 0 : password = conn->pgpass;
543 0 : if (password == NULL || password[0] == '\0')
544 : {
545 0 : printfPQExpBuffer(&conn->errorMessage,
546 : PQnoPasswordSupplied);
547 0 : goto error;
548 : }
549 :
550 0 : conn->sasl_state = pg_fe_scram_init(conn->pguser, password);
551 0 : if (!conn->sasl_state)
552 0 : goto oom_error;
553 0 : selected_mechanism = SCRAM_SHA256_NAME;
554 : }
555 0 : }
556 :
557 0 : if (!selected_mechanism)
558 : {
559 0 : printfPQExpBuffer(&conn->errorMessage,
560 : libpq_gettext("none of the server's SASL authentication mechanisms are supported\n"));
561 0 : goto error;
562 : }
563 :
564 : /* Get the mechanism-specific Initial Client Response, if any */
565 0 : pg_fe_scram_exchange(conn->sasl_state,
566 : NULL, -1,
567 : &initialresponse, &initialresponselen,
568 : &done, &success, &conn->errorMessage);
569 :
570 0 : if (done && !success)
571 0 : goto error;
572 :
573 : /*
574 : * Build a SASLInitialResponse message, and send it.
575 : */
576 0 : if (pqPutMsgStart('p', true, conn))
577 0 : goto error;
578 0 : if (pqPuts(selected_mechanism, conn))
579 0 : goto error;
580 0 : if (initialresponse)
581 : {
582 0 : if (pqPutInt(initialresponselen, 4, conn))
583 0 : goto error;
584 0 : if (pqPutnchar(initialresponse, initialresponselen, conn))
585 0 : goto error;
586 : }
587 0 : if (pqPutMsgEnd(conn))
588 0 : goto error;
589 0 : if (pqFlush(conn))
590 0 : goto error;
591 :
592 0 : termPQExpBuffer(&mechanism_buf);
593 0 : if (initialresponse)
594 0 : free(initialresponse);
595 :
596 0 : return STATUS_OK;
597 :
598 : error:
599 0 : termPQExpBuffer(&mechanism_buf);
600 0 : if (initialresponse)
601 0 : free(initialresponse);
602 0 : return STATUS_ERROR;
603 :
604 : oom_error:
605 0 : termPQExpBuffer(&mechanism_buf);
606 0 : if (initialresponse)
607 0 : free(initialresponse);
608 0 : printfPQExpBuffer(&conn->errorMessage,
609 : libpq_gettext("out of memory\n"));
610 0 : return STATUS_ERROR;
611 : }
612 :
613 : /*
614 : * Exchange a message for SASL communication protocol with the backend.
615 : * This should be used after calling pg_SASL_init to set up the status of
616 : * the protocol.
617 : */
618 : static int
619 0 : pg_SASL_continue(PGconn *conn, int payloadlen, bool final)
620 : {
621 : char *output;
622 : int outputlen;
623 : bool done;
624 : bool success;
625 : int res;
626 : char *challenge;
627 :
628 : /* Read the SASL challenge from the AuthenticationSASLContinue message. */
629 0 : challenge = malloc(payloadlen + 1);
630 0 : if (!challenge)
631 : {
632 0 : printfPQExpBuffer(&conn->errorMessage,
633 : libpq_gettext("out of memory allocating SASL buffer (%d)\n"),
634 : payloadlen);
635 0 : return STATUS_ERROR;
636 : }
637 :
638 0 : if (pqGetnchar(challenge, payloadlen, conn))
639 : {
640 0 : free(challenge);
641 0 : return STATUS_ERROR;
642 : }
643 : /* For safety and convenience, ensure the buffer is NULL-terminated. */
644 0 : challenge[payloadlen] = '\0';
645 :
646 0 : pg_fe_scram_exchange(conn->sasl_state,
647 : challenge, payloadlen,
648 : &output, &outputlen,
649 : &done, &success, &conn->errorMessage);
650 0 : free(challenge); /* don't need the input anymore */
651 :
652 0 : if (final && !done)
653 : {
654 0 : if (outputlen != 0)
655 0 : free(output);
656 :
657 0 : printfPQExpBuffer(&conn->errorMessage,
658 : libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n"));
659 0 : return STATUS_ERROR;
660 : }
661 0 : if (outputlen != 0)
662 : {
663 : /*
664 : * Send the SASL response to the server.
665 : */
666 0 : res = pqPacketSend(conn, 'p', output, outputlen);
667 0 : free(output);
668 :
669 0 : if (res != STATUS_OK)
670 0 : return STATUS_ERROR;
671 : }
672 :
673 0 : if (done && !success)
674 0 : return STATUS_ERROR;
675 :
676 0 : return STATUS_OK;
677 : }
678 :
679 : /*
680 : * Respond to AUTH_REQ_SCM_CREDS challenge.
681 : *
682 : * Note: this is dead code as of Postgres 9.1, because current backends will
683 : * never send this challenge. But we must keep it as long as libpq needs to
684 : * interoperate with pre-9.1 servers. It is believed to be needed only on
685 : * Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the
686 : * getpeereid() function isn't provided by libc).
687 : */
688 : static int
689 0 : pg_local_sendauth(PGconn *conn)
690 : {
691 : #ifdef HAVE_STRUCT_CMSGCRED
692 : char buf;
693 : struct iovec iov;
694 : struct msghdr msg;
695 : struct cmsghdr *cmsg;
696 : union
697 : {
698 : struct cmsghdr hdr;
699 : unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))];
700 : } cmsgbuf;
701 :
702 : /*
703 : * The backend doesn't care what we send here, but it wants exactly one
704 : * character to force recvmsg() to block and wait for us.
705 : */
706 : buf = '\0';
707 : iov.iov_base = &buf;
708 : iov.iov_len = 1;
709 :
710 : memset(&msg, 0, sizeof(msg));
711 : msg.msg_iov = &iov;
712 : msg.msg_iovlen = 1;
713 :
714 : /* We must set up a message that will be filled in by kernel */
715 : memset(&cmsgbuf, 0, sizeof(cmsgbuf));
716 : msg.msg_control = &cmsgbuf.buf;
717 : msg.msg_controllen = sizeof(cmsgbuf.buf);
718 : cmsg = CMSG_FIRSTHDR(&msg);
719 : cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
720 : cmsg->cmsg_level = SOL_SOCKET;
721 : cmsg->cmsg_type = SCM_CREDS;
722 :
723 : if (sendmsg(conn->sock, &msg, 0) == -1)
724 : {
725 : char sebuf[256];
726 :
727 : printfPQExpBuffer(&conn->errorMessage,
728 : "pg_local_sendauth: sendmsg: %s\n",
729 : pqStrerror(errno, sebuf, sizeof(sebuf)));
730 : return STATUS_ERROR;
731 : }
732 : return STATUS_OK;
733 : #else
734 0 : printfPQExpBuffer(&conn->errorMessage,
735 : libpq_gettext("SCM_CRED authentication method not supported\n"));
736 0 : return STATUS_ERROR;
737 : #endif
738 : }
739 :
740 : static int
741 0 : pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
742 : {
743 : int ret;
744 0 : char *crypt_pwd = NULL;
745 : const char *pwd_to_send;
746 : char md5Salt[4];
747 :
748 : /* Read the salt from the AuthenticationMD5 message. */
749 0 : if (areq == AUTH_REQ_MD5)
750 : {
751 0 : if (pqGetnchar(md5Salt, 4, conn))
752 0 : return STATUS_ERROR; /* shouldn't happen */
753 : }
754 :
755 : /* Encrypt the password if needed. */
756 :
757 0 : switch (areq)
758 : {
759 : case AUTH_REQ_MD5:
760 : {
761 : char *crypt_pwd2;
762 :
763 : /* Allocate enough space for two MD5 hashes */
764 0 : crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
765 0 : if (!crypt_pwd)
766 : {
767 0 : printfPQExpBuffer(&conn->errorMessage,
768 : libpq_gettext("out of memory\n"));
769 0 : return STATUS_ERROR;
770 : }
771 :
772 0 : crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
773 0 : if (!pg_md5_encrypt(password, conn->pguser,
774 0 : strlen(conn->pguser), crypt_pwd2))
775 : {
776 0 : free(crypt_pwd);
777 0 : return STATUS_ERROR;
778 : }
779 0 : if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), md5Salt,
780 : 4, crypt_pwd))
781 : {
782 0 : free(crypt_pwd);
783 0 : return STATUS_ERROR;
784 : }
785 :
786 0 : pwd_to_send = crypt_pwd;
787 0 : break;
788 : }
789 : case AUTH_REQ_PASSWORD:
790 0 : pwd_to_send = password;
791 0 : break;
792 : default:
793 0 : return STATUS_ERROR;
794 : }
795 : /* Packet has a message type as of protocol 3.0 */
796 0 : if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
797 0 : ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
798 : else
799 0 : ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
800 0 : if (crypt_pwd)
801 0 : free(crypt_pwd);
802 0 : return ret;
803 : }
804 :
805 : /*
806 : * pg_fe_sendauth
807 : * client demux routine for processing an authentication request
808 : *
809 : * The server has sent us an authentication challenge (or OK). Send an
810 : * appropriate response. The caller has ensured that the whole message is
811 : * now in the input buffer, and has already read the type and length of
812 : * it. We are responsible for reading any remaining extra data, specific
813 : * to the authentication method. 'payloadlen' is the remaining length in
814 : * the message.
815 : */
816 : int
817 215 : pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
818 : {
819 215 : switch (areq)
820 : {
821 : case AUTH_REQ_OK:
822 215 : break;
823 :
824 : case AUTH_REQ_KRB4:
825 0 : printfPQExpBuffer(&conn->errorMessage,
826 : libpq_gettext("Kerberos 4 authentication not supported\n"));
827 0 : return STATUS_ERROR;
828 :
829 : case AUTH_REQ_KRB5:
830 0 : printfPQExpBuffer(&conn->errorMessage,
831 : libpq_gettext("Kerberos 5 authentication not supported\n"));
832 0 : return STATUS_ERROR;
833 :
834 : #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
835 : case AUTH_REQ_GSS:
836 : #if !defined(ENABLE_SSPI)
837 : /* no native SSPI, so use GSSAPI library for it */
838 : case AUTH_REQ_SSPI:
839 : #endif
840 : {
841 : int r;
842 :
843 : pglock_thread();
844 :
845 : /*
846 : * If we have both GSS and SSPI support compiled in, use SSPI
847 : * support by default. This is overridable by a connection
848 : * string parameter. Note that when using SSPI we still leave
849 : * the negotiate parameter off, since we want SSPI to use the
850 : * GSSAPI kerberos protocol. For actual SSPI negotiate
851 : * protocol, we use AUTH_REQ_SSPI.
852 : */
853 : #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
854 : if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
855 : r = pg_GSS_startup(conn, payloadlen);
856 : else
857 : r = pg_SSPI_startup(conn, 0, payloadlen);
858 : #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
859 : r = pg_GSS_startup(conn, payloadlen);
860 : #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
861 : r = pg_SSPI_startup(conn, 0, payloadlen);
862 : #endif
863 : if (r != STATUS_OK)
864 : {
865 : /* Error message already filled in. */
866 : pgunlock_thread();
867 : return STATUS_ERROR;
868 : }
869 : pgunlock_thread();
870 : }
871 : break;
872 :
873 : case AUTH_REQ_GSS_CONT:
874 : {
875 : int r;
876 :
877 : pglock_thread();
878 : #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
879 : if (conn->usesspi)
880 : r = pg_SSPI_continue(conn, payloadlen);
881 : else
882 : r = pg_GSS_continue(conn, payloadlen);
883 : #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
884 : r = pg_GSS_continue(conn, payloadlen);
885 : #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
886 : r = pg_SSPI_continue(conn, payloadlen);
887 : #endif
888 : if (r != STATUS_OK)
889 : {
890 : /* Error message already filled in. */
891 : pgunlock_thread();
892 : return STATUS_ERROR;
893 : }
894 : pgunlock_thread();
895 : }
896 : break;
897 : #else /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
898 : /* No GSSAPI *or* SSPI support */
899 : case AUTH_REQ_GSS:
900 : case AUTH_REQ_GSS_CONT:
901 0 : printfPQExpBuffer(&conn->errorMessage,
902 : libpq_gettext("GSSAPI authentication not supported\n"));
903 0 : return STATUS_ERROR;
904 : #endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
905 :
906 : #ifdef ENABLE_SSPI
907 : case AUTH_REQ_SSPI:
908 :
909 : /*
910 : * SSPI has it's own startup message so libpq can decide which
911 : * method to use. Indicate to pg_SSPI_startup that we want SSPI
912 : * negotiation instead of Kerberos.
913 : */
914 : pglock_thread();
915 : if (pg_SSPI_startup(conn, 1, payloadlen) != STATUS_OK)
916 : {
917 : /* Error message already filled in. */
918 : pgunlock_thread();
919 : return STATUS_ERROR;
920 : }
921 : pgunlock_thread();
922 : break;
923 : #else
924 :
925 : /*
926 : * No SSPI support. However, if we have GSSAPI but not SSPI
927 : * support, AUTH_REQ_SSPI will have been handled in the codepath
928 : * for AUTH_REQ_GSSAPI above, so don't duplicate the case label in
929 : * that case.
930 : */
931 : #if !defined(ENABLE_GSS)
932 : case AUTH_REQ_SSPI:
933 0 : printfPQExpBuffer(&conn->errorMessage,
934 : libpq_gettext("SSPI authentication not supported\n"));
935 0 : return STATUS_ERROR;
936 : #endif /* !define(ENABLE_GSSAPI) */
937 : #endif /* ENABLE_SSPI */
938 :
939 :
940 : case AUTH_REQ_CRYPT:
941 0 : printfPQExpBuffer(&conn->errorMessage,
942 : libpq_gettext("Crypt authentication not supported\n"));
943 0 : return STATUS_ERROR;
944 :
945 : case AUTH_REQ_MD5:
946 : case AUTH_REQ_PASSWORD:
947 : {
948 : char *password;
949 :
950 0 : conn->password_needed = true;
951 0 : password = conn->connhost[conn->whichhost].password;
952 0 : if (password == NULL)
953 0 : password = conn->pgpass;
954 0 : if (password == NULL || password[0] == '\0')
955 : {
956 0 : printfPQExpBuffer(&conn->errorMessage,
957 : PQnoPasswordSupplied);
958 0 : return STATUS_ERROR;
959 : }
960 0 : if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
961 : {
962 0 : printfPQExpBuffer(&conn->errorMessage,
963 : "fe_sendauth: error sending password authentication\n");
964 0 : return STATUS_ERROR;
965 : }
966 0 : break;
967 : }
968 :
969 : case AUTH_REQ_SASL:
970 :
971 : /*
972 : * The request contains the name (as assigned by IANA) of the
973 : * authentication mechanism.
974 : */
975 0 : if (pg_SASL_init(conn, payloadlen) != STATUS_OK)
976 : {
977 : /* pg_SASL_init already set the error message */
978 0 : return STATUS_ERROR;
979 : }
980 0 : break;
981 :
982 : case AUTH_REQ_SASL_CONT:
983 : case AUTH_REQ_SASL_FIN:
984 0 : if (conn->sasl_state == NULL)
985 : {
986 0 : printfPQExpBuffer(&conn->errorMessage,
987 : "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n");
988 0 : return STATUS_ERROR;
989 : }
990 0 : if (pg_SASL_continue(conn, payloadlen,
991 : (areq == AUTH_REQ_SASL_FIN)) != STATUS_OK)
992 : {
993 : /* Use error message, if set already */
994 0 : if (conn->errorMessage.len == 0)
995 0 : printfPQExpBuffer(&conn->errorMessage,
996 : "fe_sendauth: error in SASL authentication\n");
997 0 : return STATUS_ERROR;
998 : }
999 0 : break;
1000 :
1001 : case AUTH_REQ_SCM_CREDS:
1002 0 : if (pg_local_sendauth(conn) != STATUS_OK)
1003 0 : return STATUS_ERROR;
1004 0 : break;
1005 :
1006 : default:
1007 0 : printfPQExpBuffer(&conn->errorMessage,
1008 : libpq_gettext("authentication method %u not supported\n"), areq);
1009 0 : return STATUS_ERROR;
1010 : }
1011 :
1012 215 : return STATUS_OK;
1013 : }
1014 :
1015 :
1016 : /*
1017 : * pg_fe_getauthname
1018 : *
1019 : * Returns a pointer to malloc'd space containing whatever name the user
1020 : * has authenticated to the system. If there is an error, return NULL,
1021 : * and put a suitable error message in *errorMessage if that's not NULL.
1022 : */
1023 : char *
1024 184 : pg_fe_getauthname(PQExpBuffer errorMessage)
1025 : {
1026 184 : char *result = NULL;
1027 184 : const char *name = NULL;
1028 :
1029 : #ifdef WIN32
1030 : /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
1031 : char username[256 + 1];
1032 : DWORD namesize = sizeof(username);
1033 : #else
1034 184 : uid_t user_id = geteuid();
1035 : char pwdbuf[BUFSIZ];
1036 : struct passwd pwdstr;
1037 184 : struct passwd *pw = NULL;
1038 : int pwerr;
1039 : #endif
1040 :
1041 : /*
1042 : * Some users are using configure --enable-thread-safety-force, so we
1043 : * might as well do the locking within our library to protect
1044 : * pqGetpwuid(). In fact, application developers can use getpwuid() in
1045 : * their application if they use the locking call we provide, or install
1046 : * their own locking function using PQregisterThreadLock().
1047 : */
1048 184 : pglock_thread();
1049 :
1050 : #ifdef WIN32
1051 : if (GetUserName(username, &namesize))
1052 : name = username;
1053 : else if (errorMessage)
1054 : printfPQExpBuffer(errorMessage,
1055 : libpq_gettext("user name lookup failure: error code %lu\n"),
1056 : GetLastError());
1057 : #else
1058 184 : pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
1059 184 : if (pw != NULL)
1060 184 : name = pw->pw_name;
1061 0 : else if (errorMessage)
1062 : {
1063 0 : if (pwerr != 0)
1064 0 : printfPQExpBuffer(errorMessage,
1065 : libpq_gettext("could not look up local user ID %d: %s\n"),
1066 : (int) user_id,
1067 : pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf)));
1068 : else
1069 0 : printfPQExpBuffer(errorMessage,
1070 : libpq_gettext("local user with ID %d does not exist\n"),
1071 : (int) user_id);
1072 : }
1073 : #endif
1074 :
1075 184 : if (name)
1076 : {
1077 184 : result = strdup(name);
1078 184 : if (result == NULL && errorMessage)
1079 0 : printfPQExpBuffer(errorMessage,
1080 : libpq_gettext("out of memory\n"));
1081 : }
1082 :
1083 184 : pgunlock_thread();
1084 :
1085 184 : return result;
1086 : }
1087 :
1088 :
1089 : /*
1090 : * PQencryptPassword -- exported routine to encrypt a password with MD5
1091 : *
1092 : * This function is equivalent to calling PQencryptPasswordConn with
1093 : * "md5" as the encryption method, except that this doesn't require
1094 : * a connection object. This function is deprecated, use
1095 : * PQencryptPasswordConn instead.
1096 : */
1097 : char *
1098 0 : PQencryptPassword(const char *passwd, const char *user)
1099 : {
1100 : char *crypt_pwd;
1101 :
1102 0 : crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
1103 0 : if (!crypt_pwd)
1104 0 : return NULL;
1105 :
1106 0 : if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
1107 : {
1108 0 : free(crypt_pwd);
1109 0 : return NULL;
1110 : }
1111 :
1112 0 : return crypt_pwd;
1113 : }
1114 :
1115 : /*
1116 : * PQencryptPasswordConn -- exported routine to encrypt a password
1117 : *
1118 : * This is intended to be used by client applications that wish to send
1119 : * commands like ALTER USER joe PASSWORD 'pwd'. The password need not
1120 : * be sent in cleartext if it is encrypted on the client side. This is
1121 : * good because it ensures the cleartext password won't end up in logs,
1122 : * pg_stat displays, etc. We export the function so that clients won't
1123 : * be dependent on low-level details like whether the encryption is MD5
1124 : * or something else.
1125 : *
1126 : * Arguments are a connection object, the cleartext password, the SQL
1127 : * name of the user it is for, and a string indicating the algorithm to
1128 : * use for encrypting the password. If algorithm is NULL, this queries
1129 : * the server for the current 'password_encryption' value. If you wish
1130 : * to avoid that, e.g. to avoid blocking, you can execute
1131 : * 'show password_encryption' yourself before calling this function, and
1132 : * pass it as the algorithm.
1133 : *
1134 : * Return value is a malloc'd string. The client may assume the string
1135 : * doesn't contain any special characters that would require escaping.
1136 : * On error, an error message is stored in the connection object, and
1137 : * returns NULL.
1138 : */
1139 : char *
1140 0 : PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
1141 : const char *algorithm)
1142 : {
1143 : #define MAX_ALGORITHM_NAME_LEN 50
1144 : char algobuf[MAX_ALGORITHM_NAME_LEN + 1];
1145 0 : char *crypt_pwd = NULL;
1146 :
1147 0 : if (!conn)
1148 0 : return NULL;
1149 :
1150 : /* If no algorithm was given, ask the server. */
1151 0 : if (algorithm == NULL)
1152 : {
1153 : PGresult *res;
1154 : char *val;
1155 :
1156 0 : res = PQexec(conn, "show password_encryption");
1157 0 : if (res == NULL)
1158 : {
1159 : /* PQexec() should've set conn->errorMessage already */
1160 0 : return NULL;
1161 : }
1162 0 : if (PQresultStatus(res) != PGRES_TUPLES_OK)
1163 : {
1164 : /* PQexec() should've set conn->errorMessage already */
1165 0 : PQclear(res);
1166 0 : return NULL;
1167 : }
1168 0 : if (PQntuples(res) != 1 || PQnfields(res) != 1)
1169 : {
1170 0 : PQclear(res);
1171 0 : printfPQExpBuffer(&conn->errorMessage,
1172 : libpq_gettext("unexpected shape of result set returned for SHOW\n"));
1173 0 : return NULL;
1174 : }
1175 0 : val = PQgetvalue(res, 0, 0);
1176 :
1177 0 : if (strlen(val) > MAX_ALGORITHM_NAME_LEN)
1178 : {
1179 0 : PQclear(res);
1180 0 : printfPQExpBuffer(&conn->errorMessage,
1181 : libpq_gettext("password_encryption value too long\n"));
1182 0 : return NULL;
1183 : }
1184 0 : strcpy(algobuf, val);
1185 0 : PQclear(res);
1186 :
1187 0 : algorithm = algobuf;
1188 : }
1189 :
1190 : /*
1191 : * Also accept "on" and "off" as aliases for "md5", because
1192 : * password_encryption was a boolean before PostgreSQL 10. We refuse to
1193 : * send the password in plaintext even if it was "off".
1194 : */
1195 0 : if (strcmp(algorithm, "on") == 0 ||
1196 0 : strcmp(algorithm, "off") == 0)
1197 0 : algorithm = "md5";
1198 :
1199 : /*
1200 : * Ok, now we know what algorithm to use
1201 : */
1202 0 : if (strcmp(algorithm, "scram-sha-256") == 0)
1203 : {
1204 0 : crypt_pwd = pg_fe_scram_build_verifier(passwd);
1205 : }
1206 0 : else if (strcmp(algorithm, "md5") == 0)
1207 : {
1208 0 : crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
1209 0 : if (crypt_pwd)
1210 : {
1211 0 : if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
1212 : {
1213 0 : free(crypt_pwd);
1214 0 : crypt_pwd = NULL;
1215 : }
1216 : }
1217 : }
1218 : else
1219 : {
1220 0 : printfPQExpBuffer(&conn->errorMessage,
1221 : libpq_gettext("unrecognized password encryption algorithm \"%s\"\n"),
1222 : algorithm);
1223 0 : return NULL;
1224 : }
1225 :
1226 0 : if (!crypt_pwd)
1227 0 : printfPQExpBuffer(&conn->errorMessage,
1228 : libpq_gettext("out of memory\n"));
1229 :
1230 0 : return crypt_pwd;
1231 : }
|