Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * fe-auth.c
4 : * The front-end (client) authorization routines
5 : *
6 : * Portions Copyright (c) 1996-2024, 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 <limits.h>
31 : #include <sys/param.h> /* for MAXHOSTNAMELEN on most */
32 : #include <sys/socket.h>
33 : #ifdef HAVE_SYS_UCRED_H
34 : #include <sys/ucred.h>
35 : #endif
36 : #ifndef MAXHOSTNAMELEN
37 : #include <netdb.h> /* for MAXHOSTNAMELEN on some */
38 : #endif
39 : #endif
40 :
41 : #include "common/md5.h"
42 : #include "common/scram-common.h"
43 : #include "fe-auth.h"
44 : #include "fe-auth-sasl.h"
45 : #include "libpq-fe.h"
46 :
47 : #ifdef ENABLE_GSS
48 : /*
49 : * GSSAPI authentication system.
50 : */
51 :
52 : #include "fe-gssapi-common.h"
53 :
54 : /*
55 : * Continue GSS authentication with next token as needed.
56 : */
57 : static int
58 : pg_GSS_continue(PGconn *conn, int payloadlen)
59 : {
60 : OM_uint32 maj_stat,
61 : min_stat,
62 : lmin_s,
63 : gss_flags = GSS_C_MUTUAL_FLAG;
64 : gss_buffer_desc ginbuf;
65 : gss_buffer_desc goutbuf;
66 :
67 : /*
68 : * On first call, there's no input token. On subsequent calls, read the
69 : * input token into a GSS buffer.
70 : */
71 : if (conn->gctx != GSS_C_NO_CONTEXT)
72 : {
73 : ginbuf.length = payloadlen;
74 : ginbuf.value = malloc(payloadlen);
75 : if (!ginbuf.value)
76 : {
77 : libpq_append_conn_error(conn, "out of memory allocating GSSAPI buffer (%d)",
78 : payloadlen);
79 : return STATUS_ERROR;
80 : }
81 : if (pqGetnchar(ginbuf.value, payloadlen, conn))
82 : {
83 : /*
84 : * Shouldn't happen, because the caller should've ensured that the
85 : * whole message is already in the input buffer.
86 : */
87 : free(ginbuf.value);
88 : return STATUS_ERROR;
89 : }
90 : }
91 : else
92 : {
93 : ginbuf.length = 0;
94 : ginbuf.value = NULL;
95 : }
96 :
97 : /* Only try to acquire credentials if GSS delegation isn't disabled. */
98 : if (!pg_GSS_have_cred_cache(&conn->gcred))
99 : conn->gcred = GSS_C_NO_CREDENTIAL;
100 :
101 : if (conn->gssdelegation && conn->gssdelegation[0] == '1')
102 : gss_flags |= GSS_C_DELEG_FLAG;
103 :
104 : maj_stat = gss_init_sec_context(&min_stat,
105 : conn->gcred,
106 : &conn->gctx,
107 : conn->gtarg_nam,
108 : GSS_C_NO_OID,
109 : gss_flags,
110 : 0,
111 : GSS_C_NO_CHANNEL_BINDINGS,
112 : (ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf,
113 : NULL,
114 : &goutbuf,
115 : NULL,
116 : NULL);
117 :
118 : free(ginbuf.value);
119 :
120 : if (goutbuf.length != 0)
121 : {
122 : /*
123 : * GSS generated data to send to the server. We don't care if it's the
124 : * first or subsequent packet, just send the same kind of password
125 : * packet.
126 : */
127 : if (pqPacketSend(conn, 'p',
128 : goutbuf.value, goutbuf.length) != STATUS_OK)
129 : {
130 : gss_release_buffer(&lmin_s, &goutbuf);
131 : return STATUS_ERROR;
132 : }
133 : }
134 : gss_release_buffer(&lmin_s, &goutbuf);
135 :
136 : if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
137 : {
138 : pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
139 : conn,
140 : maj_stat, min_stat);
141 : gss_release_name(&lmin_s, &conn->gtarg_nam);
142 : if (conn->gctx)
143 : gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
144 : return STATUS_ERROR;
145 : }
146 :
147 : if (maj_stat == GSS_S_COMPLETE)
148 : {
149 : conn->client_finished_auth = true;
150 : gss_release_name(&lmin_s, &conn->gtarg_nam);
151 : conn->gssapi_used = true;
152 : }
153 :
154 : return STATUS_OK;
155 : }
156 :
157 : /*
158 : * Send initial GSS authentication token
159 : */
160 : static int
161 : pg_GSS_startup(PGconn *conn, int payloadlen)
162 : {
163 : int ret;
164 : char *host = conn->connhost[conn->whichhost].host;
165 :
166 : if (!(host && host[0] != '\0'))
167 : {
168 : libpq_append_conn_error(conn, "host name must be specified");
169 : return STATUS_ERROR;
170 : }
171 :
172 : if (conn->gctx)
173 : {
174 : libpq_append_conn_error(conn, "duplicate GSS authentication request");
175 : return STATUS_ERROR;
176 : }
177 :
178 : ret = pg_GSS_load_servicename(conn);
179 : if (ret != STATUS_OK)
180 : return ret;
181 :
182 : /*
183 : * Initial packet is the same as a continuation packet with no initial
184 : * context.
185 : */
186 : conn->gctx = GSS_C_NO_CONTEXT;
187 :
188 : return pg_GSS_continue(conn, payloadlen);
189 : }
190 : #endif /* ENABLE_GSS */
191 :
192 :
193 : #ifdef ENABLE_SSPI
194 : /*
195 : * SSPI authentication system (Windows only)
196 : */
197 :
198 : static void
199 : pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
200 : {
201 : char sysmsg[256];
202 :
203 : if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
204 : FORMAT_MESSAGE_FROM_SYSTEM,
205 : NULL, r, 0,
206 : sysmsg, sizeof(sysmsg), NULL) == 0)
207 : appendPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n",
208 : mprefix, (unsigned int) r);
209 : else
210 : appendPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n",
211 : mprefix, sysmsg, (unsigned int) r);
212 : }
213 :
214 : /*
215 : * Continue SSPI authentication with next token as needed.
216 : */
217 : static int
218 : pg_SSPI_continue(PGconn *conn, int payloadlen)
219 : {
220 : SECURITY_STATUS r;
221 : CtxtHandle newContext;
222 : ULONG contextAttr;
223 : SecBufferDesc inbuf;
224 : SecBufferDesc outbuf;
225 : SecBuffer OutBuffers[1];
226 : SecBuffer InBuffers[1];
227 : char *inputbuf = NULL;
228 :
229 : if (conn->sspictx != NULL)
230 : {
231 : /*
232 : * On runs other than the first we have some data to send. Put this
233 : * data in a SecBuffer type structure.
234 : */
235 : inputbuf = malloc(payloadlen);
236 : if (!inputbuf)
237 : {
238 : libpq_append_conn_error(conn, "out of memory allocating SSPI buffer (%d)",
239 : payloadlen);
240 : return STATUS_ERROR;
241 : }
242 : if (pqGetnchar(inputbuf, payloadlen, conn))
243 : {
244 : /*
245 : * Shouldn't happen, because the caller should've ensured that the
246 : * whole message is already in the input buffer.
247 : */
248 : free(inputbuf);
249 : return STATUS_ERROR;
250 : }
251 :
252 : inbuf.ulVersion = SECBUFFER_VERSION;
253 : inbuf.cBuffers = 1;
254 : inbuf.pBuffers = InBuffers;
255 : InBuffers[0].pvBuffer = inputbuf;
256 : InBuffers[0].cbBuffer = payloadlen;
257 : InBuffers[0].BufferType = SECBUFFER_TOKEN;
258 : }
259 :
260 : OutBuffers[0].pvBuffer = NULL;
261 : OutBuffers[0].BufferType = SECBUFFER_TOKEN;
262 : OutBuffers[0].cbBuffer = 0;
263 : outbuf.cBuffers = 1;
264 : outbuf.pBuffers = OutBuffers;
265 : outbuf.ulVersion = SECBUFFER_VERSION;
266 :
267 : r = InitializeSecurityContext(conn->sspicred,
268 : conn->sspictx,
269 : conn->sspitarget,
270 : ISC_REQ_ALLOCATE_MEMORY,
271 : 0,
272 : SECURITY_NETWORK_DREP,
273 : (conn->sspictx == NULL) ? NULL : &inbuf,
274 : 0,
275 : &newContext,
276 : &outbuf,
277 : &contextAttr,
278 : NULL);
279 :
280 : /* we don't need the input anymore */
281 : free(inputbuf);
282 :
283 : if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
284 : {
285 : pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r);
286 :
287 : return STATUS_ERROR;
288 : }
289 :
290 : if (conn->sspictx == NULL)
291 : {
292 : /* On first run, transfer retrieved context handle */
293 : conn->sspictx = malloc(sizeof(CtxtHandle));
294 : if (conn->sspictx == NULL)
295 : {
296 : libpq_append_conn_error(conn, "out of memory");
297 : return STATUS_ERROR;
298 : }
299 : memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
300 : }
301 :
302 : /*
303 : * If SSPI returned any data to be sent to the server (as it normally
304 : * would), send this data as a password packet.
305 : */
306 : if (outbuf.cBuffers > 0)
307 : {
308 : if (outbuf.cBuffers != 1)
309 : {
310 : /*
311 : * This should never happen, at least not for Kerberos
312 : * authentication. Keep check in case it shows up with other
313 : * authentication methods later.
314 : */
315 : appendPQExpBufferStr(&conn->errorMessage,
316 : "SSPI returned invalid number of output buffers\n");
317 : return STATUS_ERROR;
318 : }
319 :
320 : /*
321 : * If the negotiation is complete, there may be zero bytes to send.
322 : * The server is at this point not expecting any more data, so don't
323 : * send it.
324 : */
325 : if (outbuf.pBuffers[0].cbBuffer > 0)
326 : {
327 : if (pqPacketSend(conn, 'p',
328 : outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
329 : {
330 : FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
331 : return STATUS_ERROR;
332 : }
333 : }
334 : FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
335 : }
336 :
337 : if (r == SEC_E_OK)
338 : conn->client_finished_auth = true;
339 :
340 : /* Cleanup is handled by the code in freePGconn() */
341 : return STATUS_OK;
342 : }
343 :
344 : /*
345 : * Send initial SSPI authentication token.
346 : * If use_negotiate is 0, use kerberos authentication package which is
347 : * compatible with Unix. If use_negotiate is 1, use the negotiate package
348 : * which supports both kerberos and NTLM, but is not compatible with Unix.
349 : */
350 : static int
351 : pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen)
352 : {
353 : SECURITY_STATUS r;
354 : TimeStamp expire;
355 : char *host = conn->connhost[conn->whichhost].host;
356 :
357 : if (conn->sspictx)
358 : {
359 : libpq_append_conn_error(conn, "duplicate SSPI authentication request");
360 : return STATUS_ERROR;
361 : }
362 :
363 : /*
364 : * Retrieve credentials handle
365 : */
366 : conn->sspicred = malloc(sizeof(CredHandle));
367 : if (conn->sspicred == NULL)
368 : {
369 : libpq_append_conn_error(conn, "out of memory");
370 : return STATUS_ERROR;
371 : }
372 :
373 : r = AcquireCredentialsHandle(NULL,
374 : use_negotiate ? "negotiate" : "kerberos",
375 : SECPKG_CRED_OUTBOUND,
376 : NULL,
377 : NULL,
378 : NULL,
379 : NULL,
380 : conn->sspicred,
381 : &expire);
382 : if (r != SEC_E_OK)
383 : {
384 : pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r);
385 : free(conn->sspicred);
386 : conn->sspicred = NULL;
387 : return STATUS_ERROR;
388 : }
389 :
390 : /*
391 : * Compute target principal name. SSPI has a different format from GSSAPI,
392 : * but not more complex. We can skip the @REALM part, because Windows will
393 : * fill that in for us automatically.
394 : */
395 : if (!(host && host[0] != '\0'))
396 : {
397 : libpq_append_conn_error(conn, "host name must be specified");
398 : return STATUS_ERROR;
399 : }
400 : conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2);
401 : if (!conn->sspitarget)
402 : {
403 : libpq_append_conn_error(conn, "out of memory");
404 : return STATUS_ERROR;
405 : }
406 : sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host);
407 :
408 : /*
409 : * Indicate that we're in SSPI authentication mode to make sure that
410 : * pg_SSPI_continue is called next time in the negotiation.
411 : */
412 : conn->usesspi = 1;
413 :
414 : return pg_SSPI_continue(conn, payloadlen);
415 : }
416 : #endif /* ENABLE_SSPI */
417 :
418 : /*
419 : * Initialize SASL authentication exchange.
420 : */
421 : static int
422 82 : pg_SASL_init(PGconn *conn, int payloadlen)
423 : {
424 82 : char *initialresponse = NULL;
425 : int initialresponselen;
426 : const char *selected_mechanism;
427 : PQExpBufferData mechanism_buf;
428 82 : char *password = NULL;
429 : SASLStatus status;
430 :
431 82 : initPQExpBuffer(&mechanism_buf);
432 :
433 82 : if (conn->channel_binding[0] == 'r' && /* require */
434 8 : !conn->ssl_in_use)
435 : {
436 2 : libpq_append_conn_error(conn, "channel binding required, but SSL not in use");
437 2 : goto error;
438 : }
439 :
440 80 : if (conn->sasl_state)
441 : {
442 0 : libpq_append_conn_error(conn, "duplicate SASL authentication request");
443 0 : goto error;
444 : }
445 :
446 : /*
447 : * Parse the list of SASL authentication mechanisms in the
448 : * AuthenticationSASL message, and select the best mechanism that we
449 : * support. Mechanisms are listed by order of decreasing importance.
450 : */
451 80 : selected_mechanism = NULL;
452 : for (;;)
453 : {
454 174 : if (pqGets(&mechanism_buf, conn))
455 : {
456 0 : appendPQExpBufferStr(&conn->errorMessage,
457 : "fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n");
458 0 : goto error;
459 : }
460 174 : if (PQExpBufferDataBroken(mechanism_buf))
461 0 : goto oom_error;
462 :
463 : /* An empty string indicates end of list */
464 174 : if (mechanism_buf.data[0] == '\0')
465 80 : break;
466 :
467 : /*
468 : * Select the mechanism to use. Pick SCRAM-SHA-256-PLUS over anything
469 : * else if a channel binding type is set and if the client supports it
470 : * (and did not set channel_binding=disable). Pick SCRAM-SHA-256 if
471 : * nothing else has already been picked. If we add more mechanisms, a
472 : * more refined priority mechanism might become necessary.
473 : */
474 94 : if (strcmp(mechanism_buf.data, SCRAM_SHA_256_PLUS_NAME) == 0)
475 : {
476 14 : if (conn->ssl_in_use)
477 : {
478 : /* The server has offered SCRAM-SHA-256-PLUS. */
479 :
480 : #ifdef USE_SSL
481 : /*
482 : * The client supports channel binding, which is chosen if
483 : * channel_binding is not disabled.
484 : */
485 14 : if (conn->channel_binding[0] != 'd') /* disable */
486 : {
487 10 : selected_mechanism = SCRAM_SHA_256_PLUS_NAME;
488 10 : conn->sasl = &pg_scram_mech;
489 10 : conn->password_needed = true;
490 : }
491 : #else
492 : /*
493 : * The client does not support channel binding. If it is
494 : * required, complain immediately instead of the error below
495 : * which would be confusing as the server is publishing
496 : * SCRAM-SHA-256-PLUS.
497 : */
498 : if (conn->channel_binding[0] == 'r') /* require */
499 : {
500 : libpq_append_conn_error(conn, "channel binding is required, but client does not support it");
501 : goto error;
502 : }
503 : #endif
504 : }
505 : else
506 : {
507 : /*
508 : * The server offered SCRAM-SHA-256-PLUS, but the connection
509 : * is not SSL-encrypted. That's not sane. Perhaps SSL was
510 : * stripped by a proxy? There's no point in continuing,
511 : * because the server will reject the connection anyway if we
512 : * try authenticate without channel binding even though both
513 : * the client and server supported it. The SCRAM exchange
514 : * checks for that, to prevent downgrade attacks.
515 : */
516 0 : libpq_append_conn_error(conn, "server offered SCRAM-SHA-256-PLUS authentication over a non-SSL connection");
517 0 : goto error;
518 : }
519 : }
520 80 : else if (strcmp(mechanism_buf.data, SCRAM_SHA_256_NAME) == 0 &&
521 : !selected_mechanism)
522 : {
523 70 : selected_mechanism = SCRAM_SHA_256_NAME;
524 70 : conn->sasl = &pg_scram_mech;
525 70 : conn->password_needed = true;
526 : }
527 : }
528 :
529 80 : if (!selected_mechanism)
530 : {
531 0 : libpq_append_conn_error(conn, "none of the server's SASL authentication mechanisms are supported");
532 0 : goto error;
533 : }
534 :
535 80 : if (conn->channel_binding[0] == 'r' && /* require */
536 6 : strcmp(selected_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0)
537 : {
538 0 : libpq_append_conn_error(conn, "channel binding is required, but server did not offer an authentication method that supports channel binding");
539 0 : goto error;
540 : }
541 :
542 : /*
543 : * Now that the SASL mechanism has been chosen for the exchange,
544 : * initialize its state information.
545 : */
546 :
547 : /*
548 : * First, select the password to use for the exchange, complaining if
549 : * there isn't one and the selected SASL mechanism needs it.
550 : */
551 80 : if (conn->password_needed)
552 : {
553 80 : password = conn->connhost[conn->whichhost].password;
554 80 : if (password == NULL)
555 80 : password = conn->pgpass;
556 80 : if (password == NULL || password[0] == '\0')
557 : {
558 0 : appendPQExpBufferStr(&conn->errorMessage,
559 : PQnoPasswordSupplied);
560 0 : goto error;
561 : }
562 : }
563 :
564 : Assert(conn->sasl);
565 :
566 : /*
567 : * Initialize the SASL state information with all the information gathered
568 : * during the initial exchange.
569 : *
570 : * Note: Only tls-unique is supported for the moment.
571 : */
572 80 : conn->sasl_state = conn->sasl->init(conn,
573 : password,
574 : selected_mechanism);
575 80 : if (!conn->sasl_state)
576 0 : goto oom_error;
577 :
578 : /* Get the mechanism-specific Initial Client Response, if any */
579 80 : status = conn->sasl->exchange(conn->sasl_state,
580 : NULL, -1,
581 : &initialresponse, &initialresponselen);
582 :
583 80 : if (status == SASL_FAILED)
584 0 : goto error;
585 :
586 : /*
587 : * Build a SASLInitialResponse message, and send it.
588 : */
589 80 : if (pqPutMsgStart(PqMsg_SASLInitialResponse, conn))
590 0 : goto error;
591 80 : if (pqPuts(selected_mechanism, conn))
592 0 : goto error;
593 80 : if (initialresponse)
594 : {
595 80 : if (pqPutInt(initialresponselen, 4, conn))
596 0 : goto error;
597 80 : if (pqPutnchar(initialresponse, initialresponselen, conn))
598 0 : goto error;
599 : }
600 80 : if (pqPutMsgEnd(conn))
601 0 : goto error;
602 80 : if (pqFlush(conn))
603 0 : goto error;
604 :
605 80 : termPQExpBuffer(&mechanism_buf);
606 80 : free(initialresponse);
607 :
608 80 : return STATUS_OK;
609 :
610 2 : error:
611 2 : termPQExpBuffer(&mechanism_buf);
612 2 : free(initialresponse);
613 2 : return STATUS_ERROR;
614 :
615 0 : oom_error:
616 0 : termPQExpBuffer(&mechanism_buf);
617 0 : free(initialresponse);
618 0 : libpq_append_conn_error(conn, "out of memory");
619 0 : return STATUS_ERROR;
620 : }
621 :
622 : /*
623 : * Exchange a message for SASL communication protocol with the backend.
624 : * This should be used after calling pg_SASL_init to set up the status of
625 : * the protocol.
626 : */
627 : static int
628 148 : pg_SASL_continue(PGconn *conn, int payloadlen, bool final)
629 : {
630 : char *output;
631 : int outputlen;
632 : int res;
633 : char *challenge;
634 : SASLStatus status;
635 :
636 : /* Read the SASL challenge from the AuthenticationSASLContinue message. */
637 148 : challenge = malloc(payloadlen + 1);
638 148 : if (!challenge)
639 : {
640 0 : libpq_append_conn_error(conn, "out of memory allocating SASL buffer (%d)",
641 : payloadlen);
642 0 : return STATUS_ERROR;
643 : }
644 :
645 148 : if (pqGetnchar(challenge, payloadlen, conn))
646 : {
647 0 : free(challenge);
648 0 : return STATUS_ERROR;
649 : }
650 : /* For safety and convenience, ensure the buffer is NULL-terminated. */
651 148 : challenge[payloadlen] = '\0';
652 :
653 148 : status = conn->sasl->exchange(conn->sasl_state,
654 : challenge, payloadlen,
655 : &output, &outputlen);
656 148 : free(challenge); /* don't need the input anymore */
657 :
658 148 : if (final && status == SASL_CONTINUE)
659 : {
660 0 : if (outputlen != 0)
661 0 : free(output);
662 :
663 0 : libpq_append_conn_error(conn, "AuthenticationSASLFinal received from server, but SASL authentication was not completed");
664 0 : return STATUS_ERROR;
665 : }
666 :
667 : /*
668 : * If the exchange is not completed yet, we need to make sure that the
669 : * SASL mechanism has generated a message to send back.
670 : */
671 148 : if (output == NULL && status == SASL_CONTINUE)
672 : {
673 0 : libpq_append_conn_error(conn, "no client response found after SASL exchange success");
674 0 : return STATUS_ERROR;
675 : }
676 :
677 : /*
678 : * SASL allows zero-length responses, so this check uses "output" and not
679 : * "outputlen" to allow the case of an empty message.
680 : */
681 148 : if (output)
682 : {
683 : /*
684 : * Send the SASL response to the server.
685 : */
686 80 : res = pqPacketSend(conn, 'p', output, outputlen);
687 80 : free(output);
688 :
689 80 : if (res != STATUS_OK)
690 0 : return STATUS_ERROR;
691 : }
692 :
693 148 : if (status == SASL_FAILED)
694 0 : return STATUS_ERROR;
695 :
696 148 : return STATUS_OK;
697 : }
698 :
699 : static int
700 78 : pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
701 : {
702 : int ret;
703 78 : char *crypt_pwd = NULL;
704 : const char *pwd_to_send;
705 : char md5Salt[4];
706 :
707 : /* Read the salt from the AuthenticationMD5Password message. */
708 78 : if (areq == AUTH_REQ_MD5)
709 : {
710 2 : if (pqGetnchar(md5Salt, 4, conn))
711 0 : return STATUS_ERROR; /* shouldn't happen */
712 : }
713 :
714 : /* Encrypt the password if needed. */
715 :
716 78 : switch (areq)
717 : {
718 2 : case AUTH_REQ_MD5:
719 : {
720 : char *crypt_pwd2;
721 2 : const char *errstr = NULL;
722 :
723 : /* Allocate enough space for two MD5 hashes */
724 2 : crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
725 2 : if (!crypt_pwd)
726 : {
727 0 : libpq_append_conn_error(conn, "out of memory");
728 0 : return STATUS_ERROR;
729 : }
730 :
731 2 : crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
732 2 : if (!pg_md5_encrypt(password, conn->pguser,
733 2 : strlen(conn->pguser), crypt_pwd2,
734 : &errstr))
735 : {
736 0 : libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
737 0 : free(crypt_pwd);
738 0 : return STATUS_ERROR;
739 : }
740 2 : if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), md5Salt,
741 : 4, crypt_pwd, &errstr))
742 : {
743 0 : libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
744 0 : free(crypt_pwd);
745 0 : return STATUS_ERROR;
746 : }
747 :
748 2 : pwd_to_send = crypt_pwd;
749 2 : break;
750 : }
751 76 : case AUTH_REQ_PASSWORD:
752 76 : pwd_to_send = password;
753 76 : break;
754 0 : default:
755 0 : return STATUS_ERROR;
756 : }
757 78 : ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
758 78 : free(crypt_pwd);
759 78 : return ret;
760 : }
761 :
762 : /*
763 : * Translate a disallowed AuthRequest code into an error message.
764 : */
765 : static const char *
766 32 : auth_method_description(AuthRequest areq)
767 : {
768 32 : switch (areq)
769 : {
770 12 : case AUTH_REQ_PASSWORD:
771 12 : return libpq_gettext("server requested a cleartext password");
772 0 : case AUTH_REQ_MD5:
773 0 : return libpq_gettext("server requested a hashed password");
774 0 : case AUTH_REQ_GSS:
775 : case AUTH_REQ_GSS_CONT:
776 0 : return libpq_gettext("server requested GSSAPI authentication");
777 0 : case AUTH_REQ_SSPI:
778 0 : return libpq_gettext("server requested SSPI authentication");
779 20 : case AUTH_REQ_SASL:
780 : case AUTH_REQ_SASL_CONT:
781 : case AUTH_REQ_SASL_FIN:
782 20 : return libpq_gettext("server requested SASL authentication");
783 : }
784 :
785 0 : return libpq_gettext("server requested an unknown authentication type");
786 : }
787 :
788 : /*
789 : * Convenience macro for checking the allowed_auth_methods bitmask. Caller
790 : * must ensure that type is not greater than 31 (high bit of the bitmask).
791 : */
792 : #define auth_method_allowed(conn, type) \
793 : (((conn)->allowed_auth_methods & (1 << (type))) != 0)
794 :
795 : /*
796 : * Verify that the authentication request is expected, given the connection
797 : * parameters. This is especially important when the client wishes to
798 : * authenticate the server before any sensitive information is exchanged.
799 : */
800 : static bool
801 21782 : check_expected_areq(AuthRequest areq, PGconn *conn)
802 : {
803 21782 : bool result = true;
804 21782 : const char *reason = NULL;
805 :
806 : StaticAssertDecl((sizeof(conn->allowed_auth_methods) * CHAR_BIT) > AUTH_REQ_MAX,
807 : "AUTH_REQ_MAX overflows the allowed_auth_methods bitmask");
808 :
809 21782 : if (conn->sslcertmode[0] == 'r' /* require */
810 6 : && areq == AUTH_REQ_OK)
811 : {
812 : /*
813 : * Trade off a little bit of complexity to try to get these error
814 : * messages as precise as possible.
815 : */
816 6 : if (!conn->ssl_cert_requested)
817 : {
818 0 : libpq_append_conn_error(conn, "server did not request an SSL certificate");
819 0 : return false;
820 : }
821 6 : else if (!conn->ssl_cert_sent)
822 : {
823 2 : libpq_append_conn_error(conn, "server accepted connection without a valid SSL certificate");
824 2 : return false;
825 : }
826 : }
827 :
828 : /*
829 : * If the user required a specific auth method, or specified an allowed
830 : * set, then reject all others here, and make sure the server actually
831 : * completes an authentication exchange.
832 : */
833 21780 : if (conn->require_auth)
834 : {
835 144 : switch (areq)
836 : {
837 54 : case AUTH_REQ_OK:
838 :
839 : /*
840 : * Check to make sure we've actually finished our exchange (or
841 : * else that the user has allowed an authentication-less
842 : * connection).
843 : *
844 : * If the user has allowed both SCRAM and unauthenticated
845 : * (trust) connections, then this check will silently accept
846 : * partial SCRAM exchanges, where a misbehaving server does
847 : * not provide its verifier before sending an OK. This is
848 : * consistent with historical behavior, but it may be a point
849 : * to revisit in the future, since it could allow a server
850 : * that doesn't know the user's password to silently harvest
851 : * material for a brute force attack.
852 : */
853 54 : if (!conn->auth_required || conn->client_finished_auth)
854 : break;
855 :
856 : /*
857 : * No explicit authentication request was made by the server
858 : * -- or perhaps it was made and not completed, in the case of
859 : * SCRAM -- but there is one special case to check. If the
860 : * user allowed "gss", then a GSS-encrypted channel also
861 : * satisfies the check.
862 : */
863 : #ifdef ENABLE_GSS
864 : if (auth_method_allowed(conn, AUTH_REQ_GSS) && conn->gssenc)
865 : {
866 : /*
867 : * If implicit GSS auth has already been performed via GSS
868 : * encryption, we don't need to have performed an
869 : * AUTH_REQ_GSS exchange. This allows require_auth=gss to
870 : * be combined with gssencmode, since there won't be an
871 : * explicit authentication request in that case.
872 : */
873 : }
874 : else
875 : #endif
876 : {
877 14 : reason = libpq_gettext("server did not complete authentication");
878 14 : result = false;
879 : }
880 :
881 14 : break;
882 :
883 90 : case AUTH_REQ_PASSWORD:
884 : case AUTH_REQ_MD5:
885 : case AUTH_REQ_GSS:
886 : case AUTH_REQ_GSS_CONT:
887 : case AUTH_REQ_SSPI:
888 : case AUTH_REQ_SASL:
889 : case AUTH_REQ_SASL_CONT:
890 : case AUTH_REQ_SASL_FIN:
891 :
892 : /*
893 : * We don't handle these with the default case, to avoid
894 : * bit-shifting past the end of the allowed_auth_methods mask
895 : * if the server sends an unexpected AuthRequest.
896 : */
897 90 : result = auth_method_allowed(conn, areq);
898 90 : break;
899 :
900 0 : default:
901 0 : result = false;
902 0 : break;
903 : }
904 21676 : }
905 :
906 21780 : if (!result)
907 : {
908 46 : if (!reason)
909 32 : reason = auth_method_description(areq);
910 :
911 46 : libpq_append_conn_error(conn, "authentication method requirement \"%s\" failed: %s",
912 : conn->require_auth, reason);
913 46 : return result;
914 : }
915 :
916 : /*
917 : * When channel_binding=require, we must protect against two cases: (1) we
918 : * must not respond to non-SASL authentication requests, which might leak
919 : * information such as the client's password; and (2) even if we receive
920 : * AUTH_REQ_OK, we still must ensure that channel binding has happened in
921 : * order to authenticate the server.
922 : */
923 21734 : if (conn->channel_binding[0] == 'r' /* require */ )
924 : {
925 34 : switch (areq)
926 : {
927 20 : case AUTH_REQ_SASL:
928 : case AUTH_REQ_SASL_CONT:
929 : case AUTH_REQ_SASL_FIN:
930 20 : break;
931 8 : case AUTH_REQ_OK:
932 8 : if (!conn->sasl || !conn->sasl->channel_bound(conn->sasl_state))
933 : {
934 2 : libpq_append_conn_error(conn, "channel binding required, but server authenticated client without channel binding");
935 2 : result = false;
936 : }
937 8 : break;
938 6 : default:
939 6 : libpq_append_conn_error(conn, "channel binding required but not supported by server's authentication request");
940 6 : result = false;
941 6 : break;
942 : }
943 21700 : }
944 :
945 21734 : return result;
946 : }
947 :
948 : /*
949 : * pg_fe_sendauth
950 : * client demux routine for processing an authentication request
951 : *
952 : * The server has sent us an authentication challenge (or OK). Send an
953 : * appropriate response. The caller has ensured that the whole message is
954 : * now in the input buffer, and has already read the type and length of
955 : * it. We are responsible for reading any remaining extra data, specific
956 : * to the authentication method. 'payloadlen' is the remaining length in
957 : * the message.
958 : */
959 : int
960 21782 : pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
961 : {
962 : int oldmsglen;
963 :
964 21782 : if (!check_expected_areq(areq, conn))
965 56 : return STATUS_ERROR;
966 :
967 21726 : switch (areq)
968 : {
969 21416 : case AUTH_REQ_OK:
970 21416 : break;
971 :
972 0 : case AUTH_REQ_KRB4:
973 0 : libpq_append_conn_error(conn, "Kerberos 4 authentication not supported");
974 0 : return STATUS_ERROR;
975 :
976 0 : case AUTH_REQ_KRB5:
977 0 : libpq_append_conn_error(conn, "Kerberos 5 authentication not supported");
978 0 : return STATUS_ERROR;
979 :
980 : #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
981 : case AUTH_REQ_GSS:
982 : #if !defined(ENABLE_SSPI)
983 : /* no native SSPI, so use GSSAPI library for it */
984 : case AUTH_REQ_SSPI:
985 : #endif
986 : {
987 : int r;
988 :
989 : pglock_thread();
990 :
991 : /*
992 : * If we have both GSS and SSPI support compiled in, use SSPI
993 : * support by default. This is overridable by a connection
994 : * string parameter. Note that when using SSPI we still leave
995 : * the negotiate parameter off, since we want SSPI to use the
996 : * GSSAPI kerberos protocol. For actual SSPI negotiate
997 : * protocol, we use AUTH_REQ_SSPI.
998 : */
999 : #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1000 : if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
1001 : r = pg_GSS_startup(conn, payloadlen);
1002 : else
1003 : r = pg_SSPI_startup(conn, 0, payloadlen);
1004 : #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
1005 : r = pg_GSS_startup(conn, payloadlen);
1006 : #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1007 : r = pg_SSPI_startup(conn, 0, payloadlen);
1008 : #endif
1009 : if (r != STATUS_OK)
1010 : {
1011 : /* Error message already filled in. */
1012 : pgunlock_thread();
1013 : return STATUS_ERROR;
1014 : }
1015 : pgunlock_thread();
1016 : }
1017 : break;
1018 :
1019 : case AUTH_REQ_GSS_CONT:
1020 : {
1021 : int r;
1022 :
1023 : pglock_thread();
1024 : #if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1025 : if (conn->usesspi)
1026 : r = pg_SSPI_continue(conn, payloadlen);
1027 : else
1028 : r = pg_GSS_continue(conn, payloadlen);
1029 : #elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
1030 : r = pg_GSS_continue(conn, payloadlen);
1031 : #elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
1032 : r = pg_SSPI_continue(conn, payloadlen);
1033 : #endif
1034 : if (r != STATUS_OK)
1035 : {
1036 : /* Error message already filled in. */
1037 : pgunlock_thread();
1038 : return STATUS_ERROR;
1039 : }
1040 : pgunlock_thread();
1041 : }
1042 : break;
1043 : #else /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
1044 : /* No GSSAPI *or* SSPI support */
1045 0 : case AUTH_REQ_GSS:
1046 : case AUTH_REQ_GSS_CONT:
1047 0 : libpq_append_conn_error(conn, "GSSAPI authentication not supported");
1048 0 : return STATUS_ERROR;
1049 : #endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
1050 :
1051 : #ifdef ENABLE_SSPI
1052 : case AUTH_REQ_SSPI:
1053 :
1054 : /*
1055 : * SSPI has its own startup message so libpq can decide which
1056 : * method to use. Indicate to pg_SSPI_startup that we want SSPI
1057 : * negotiation instead of Kerberos.
1058 : */
1059 : pglock_thread();
1060 : if (pg_SSPI_startup(conn, 1, payloadlen) != STATUS_OK)
1061 : {
1062 : /* Error message already filled in. */
1063 : pgunlock_thread();
1064 : return STATUS_ERROR;
1065 : }
1066 : pgunlock_thread();
1067 : break;
1068 : #else
1069 :
1070 : /*
1071 : * No SSPI support. However, if we have GSSAPI but not SSPI
1072 : * support, AUTH_REQ_SSPI will have been handled in the codepath
1073 : * for AUTH_REQ_GSS above, so don't duplicate the case label in
1074 : * that case.
1075 : */
1076 : #if !defined(ENABLE_GSS)
1077 0 : case AUTH_REQ_SSPI:
1078 0 : libpq_append_conn_error(conn, "SSPI authentication not supported");
1079 0 : return STATUS_ERROR;
1080 : #endif /* !define(ENABLE_GSS) */
1081 : #endif /* ENABLE_SSPI */
1082 :
1083 :
1084 0 : case AUTH_REQ_CRYPT:
1085 0 : libpq_append_conn_error(conn, "Crypt authentication not supported");
1086 0 : return STATUS_ERROR;
1087 :
1088 80 : case AUTH_REQ_MD5:
1089 : case AUTH_REQ_PASSWORD:
1090 : {
1091 : char *password;
1092 :
1093 80 : conn->password_needed = true;
1094 80 : password = conn->connhost[conn->whichhost].password;
1095 80 : if (password == NULL)
1096 70 : password = conn->pgpass;
1097 80 : if (password == NULL || password[0] == '\0')
1098 : {
1099 2 : appendPQExpBufferStr(&conn->errorMessage,
1100 : PQnoPasswordSupplied);
1101 2 : return STATUS_ERROR;
1102 : }
1103 78 : if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
1104 : {
1105 0 : appendPQExpBufferStr(&conn->errorMessage,
1106 : "fe_sendauth: error sending password authentication\n");
1107 0 : return STATUS_ERROR;
1108 : }
1109 :
1110 : /* We expect no further authentication requests. */
1111 78 : conn->client_finished_auth = true;
1112 78 : break;
1113 : }
1114 :
1115 82 : case AUTH_REQ_SASL:
1116 :
1117 : /*
1118 : * The request contains the name (as assigned by IANA) of the
1119 : * authentication mechanism.
1120 : */
1121 82 : if (pg_SASL_init(conn, payloadlen) != STATUS_OK)
1122 : {
1123 : /* pg_SASL_init already set the error message */
1124 2 : return STATUS_ERROR;
1125 : }
1126 80 : break;
1127 :
1128 148 : case AUTH_REQ_SASL_CONT:
1129 : case AUTH_REQ_SASL_FIN:
1130 148 : if (conn->sasl_state == NULL)
1131 : {
1132 0 : appendPQExpBufferStr(&conn->errorMessage,
1133 : "fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n");
1134 0 : return STATUS_ERROR;
1135 : }
1136 148 : oldmsglen = conn->errorMessage.len;
1137 148 : if (pg_SASL_continue(conn, payloadlen,
1138 : (areq == AUTH_REQ_SASL_FIN)) != STATUS_OK)
1139 : {
1140 : /* Use this message if pg_SASL_continue didn't supply one */
1141 0 : if (conn->errorMessage.len == oldmsglen)
1142 0 : appendPQExpBufferStr(&conn->errorMessage,
1143 : "fe_sendauth: error in SASL authentication\n");
1144 0 : return STATUS_ERROR;
1145 : }
1146 148 : break;
1147 :
1148 0 : default:
1149 0 : libpq_append_conn_error(conn, "authentication method %u not supported", areq);
1150 0 : return STATUS_ERROR;
1151 : }
1152 :
1153 21722 : return STATUS_OK;
1154 : }
1155 :
1156 :
1157 : /*
1158 : * pg_fe_getusername
1159 : *
1160 : * Returns a pointer to malloc'd space containing the name of the
1161 : * specified user_id. If there is an error, return NULL, and append
1162 : * a suitable error message to *errorMessage if that's not NULL.
1163 : *
1164 : * Caution: on Windows, the user_id argument is ignored, and we always
1165 : * fetch the current user's name.
1166 : */
1167 : char *
1168 20576 : pg_fe_getusername(uid_t user_id, PQExpBuffer errorMessage)
1169 : {
1170 20576 : char *result = NULL;
1171 20576 : const char *name = NULL;
1172 :
1173 : #ifdef WIN32
1174 : /* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
1175 : char username[256 + 1];
1176 : DWORD namesize = sizeof(username);
1177 : #else
1178 : char pwdbuf[BUFSIZ];
1179 : #endif
1180 :
1181 : #ifdef WIN32
1182 : if (GetUserName(username, &namesize))
1183 : name = username;
1184 : else if (errorMessage)
1185 : libpq_append_error(errorMessage,
1186 : "user name lookup failure: error code %lu",
1187 : GetLastError());
1188 : #else
1189 20576 : if (pg_get_user_name(user_id, pwdbuf, sizeof(pwdbuf)))
1190 20576 : name = pwdbuf;
1191 0 : else if (errorMessage)
1192 0 : appendPQExpBuffer(errorMessage, "%s\n", pwdbuf);
1193 : #endif
1194 :
1195 20576 : if (name)
1196 : {
1197 20576 : result = strdup(name);
1198 20576 : if (result == NULL && errorMessage)
1199 0 : libpq_append_error(errorMessage, "out of memory");
1200 : }
1201 :
1202 20576 : return result;
1203 : }
1204 :
1205 : /*
1206 : * pg_fe_getauthname
1207 : *
1208 : * Returns a pointer to malloc'd space containing whatever name the user
1209 : * has authenticated to the system. If there is an error, return NULL,
1210 : * and append a suitable error message to *errorMessage if that's not NULL.
1211 : */
1212 : char *
1213 20576 : pg_fe_getauthname(PQExpBuffer errorMessage)
1214 : {
1215 : #ifdef WIN32
1216 : return pg_fe_getusername(0, errorMessage);
1217 : #else
1218 20576 : return pg_fe_getusername(geteuid(), errorMessage);
1219 : #endif
1220 : }
1221 :
1222 :
1223 : /*
1224 : * PQencryptPassword -- exported routine to encrypt a password with MD5
1225 : *
1226 : * This function is equivalent to calling PQencryptPasswordConn with
1227 : * "md5" as the encryption method, except that this doesn't require
1228 : * a connection object. This function is deprecated, use
1229 : * PQencryptPasswordConn instead.
1230 : */
1231 : char *
1232 0 : PQencryptPassword(const char *passwd, const char *user)
1233 : {
1234 : char *crypt_pwd;
1235 0 : const char *errstr = NULL;
1236 :
1237 0 : crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
1238 0 : if (!crypt_pwd)
1239 0 : return NULL;
1240 :
1241 0 : if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd, &errstr))
1242 : {
1243 0 : free(crypt_pwd);
1244 0 : return NULL;
1245 : }
1246 :
1247 0 : return crypt_pwd;
1248 : }
1249 :
1250 : /*
1251 : * PQencryptPasswordConn -- exported routine to encrypt a password
1252 : *
1253 : * This is intended to be used by client applications that wish to send
1254 : * commands like ALTER USER joe PASSWORD 'pwd'. The password need not
1255 : * be sent in cleartext if it is encrypted on the client side. This is
1256 : * good because it ensures the cleartext password won't end up in logs,
1257 : * pg_stat displays, etc. We export the function so that clients won't
1258 : * be dependent on low-level details like whether the encryption is MD5
1259 : * or something else.
1260 : *
1261 : * Arguments are a connection object, the cleartext password, the SQL
1262 : * name of the user it is for, and a string indicating the algorithm to
1263 : * use for encrypting the password. If algorithm is NULL, this queries
1264 : * the server for the current 'password_encryption' value. If you wish
1265 : * to avoid that, e.g. to avoid blocking, you can execute
1266 : * 'show password_encryption' yourself before calling this function, and
1267 : * pass it as the algorithm.
1268 : *
1269 : * Return value is a malloc'd string. The client may assume the string
1270 : * doesn't contain any special characters that would require escaping.
1271 : * On error, an error message is stored in the connection object, and
1272 : * returns NULL.
1273 : */
1274 : char *
1275 2 : PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
1276 : const char *algorithm)
1277 : {
1278 : #define MAX_ALGORITHM_NAME_LEN 50
1279 : char algobuf[MAX_ALGORITHM_NAME_LEN + 1];
1280 2 : char *crypt_pwd = NULL;
1281 :
1282 2 : if (!conn)
1283 0 : return NULL;
1284 :
1285 2 : pqClearConnErrorState(conn);
1286 :
1287 : /* If no algorithm was given, ask the server. */
1288 2 : if (algorithm == NULL)
1289 : {
1290 : PGresult *res;
1291 : char *val;
1292 :
1293 2 : res = PQexec(conn, "show password_encryption");
1294 2 : if (res == NULL)
1295 : {
1296 : /* PQexec() should've set conn->errorMessage already */
1297 0 : return NULL;
1298 : }
1299 2 : if (PQresultStatus(res) != PGRES_TUPLES_OK)
1300 : {
1301 : /* PQexec() should've set conn->errorMessage already */
1302 0 : PQclear(res);
1303 0 : return NULL;
1304 : }
1305 2 : if (PQntuples(res) != 1 || PQnfields(res) != 1)
1306 : {
1307 0 : PQclear(res);
1308 0 : libpq_append_conn_error(conn, "unexpected shape of result set returned for SHOW");
1309 0 : return NULL;
1310 : }
1311 2 : val = PQgetvalue(res, 0, 0);
1312 :
1313 2 : if (strlen(val) > MAX_ALGORITHM_NAME_LEN)
1314 : {
1315 0 : PQclear(res);
1316 0 : libpq_append_conn_error(conn, "password_encryption value too long");
1317 0 : return NULL;
1318 : }
1319 2 : strcpy(algobuf, val);
1320 2 : PQclear(res);
1321 :
1322 2 : algorithm = algobuf;
1323 : }
1324 :
1325 : /*
1326 : * Also accept "on" and "off" as aliases for "md5", because
1327 : * password_encryption was a boolean before PostgreSQL 10. We refuse to
1328 : * send the password in plaintext even if it was "off".
1329 : */
1330 2 : if (strcmp(algorithm, "on") == 0 ||
1331 2 : strcmp(algorithm, "off") == 0)
1332 0 : algorithm = "md5";
1333 :
1334 : /*
1335 : * Ok, now we know what algorithm to use
1336 : */
1337 2 : if (strcmp(algorithm, "scram-sha-256") == 0)
1338 : {
1339 2 : const char *errstr = NULL;
1340 :
1341 2 : crypt_pwd = pg_fe_scram_build_secret(passwd,
1342 : conn->scram_sha_256_iterations,
1343 : &errstr);
1344 2 : if (!crypt_pwd)
1345 0 : libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
1346 : }
1347 0 : else if (strcmp(algorithm, "md5") == 0)
1348 : {
1349 0 : crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
1350 0 : if (crypt_pwd)
1351 : {
1352 0 : const char *errstr = NULL;
1353 :
1354 0 : if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd, &errstr))
1355 : {
1356 0 : libpq_append_conn_error(conn, "could not encrypt password: %s", errstr);
1357 0 : free(crypt_pwd);
1358 0 : crypt_pwd = NULL;
1359 : }
1360 : }
1361 : else
1362 0 : libpq_append_conn_error(conn, "out of memory");
1363 : }
1364 : else
1365 : {
1366 0 : libpq_append_conn_error(conn, "unrecognized password encryption algorithm \"%s\"",
1367 : algorithm);
1368 0 : return NULL;
1369 : }
1370 :
1371 2 : return crypt_pwd;
1372 : }
1373 :
1374 : /*
1375 : * PQchangePassword -- exported routine to change a password
1376 : *
1377 : * This is intended to be used by client applications that wish to
1378 : * change the password for a user. The password is not sent in
1379 : * cleartext because it is encrypted on the client side. This is
1380 : * good because it ensures the cleartext password is never known by
1381 : * the server, and therefore won't end up in logs, pg_stat displays,
1382 : * etc. The password encryption is performed by PQencryptPasswordConn(),
1383 : * which is passed a NULL for the algorithm argument. Hence encryption
1384 : * is done according to the server's password_encryption
1385 : * setting. We export the function so that clients won't be dependent
1386 : * on the implementation specific details with respect to how the
1387 : * server changes passwords.
1388 : *
1389 : * Arguments are a connection object, the SQL name of the target user,
1390 : * and the cleartext password.
1391 : *
1392 : * Return value is the PGresult of the executed ALTER USER statement
1393 : * or NULL if we never get there. The caller is responsible to PQclear()
1394 : * the returned PGresult.
1395 : *
1396 : * PQresultStatus() should be called to check the return value for errors,
1397 : * and PQerrorMessage() used to get more information about such errors.
1398 : */
1399 : PGresult *
1400 2 : PQchangePassword(PGconn *conn, const char *user, const char *passwd)
1401 : {
1402 2 : char *encrypted_password = PQencryptPasswordConn(conn, passwd,
1403 : user, NULL);
1404 :
1405 2 : if (!encrypted_password)
1406 : {
1407 : /* PQencryptPasswordConn() already registered the error */
1408 0 : return NULL;
1409 : }
1410 : else
1411 : {
1412 2 : char *fmtpw = PQescapeLiteral(conn, encrypted_password,
1413 : strlen(encrypted_password));
1414 :
1415 : /* no longer needed, so clean up now */
1416 2 : PQfreemem(encrypted_password);
1417 :
1418 2 : if (!fmtpw)
1419 : {
1420 : /* PQescapeLiteral() already registered the error */
1421 0 : return NULL;
1422 : }
1423 : else
1424 : {
1425 2 : char *fmtuser = PQescapeIdentifier(conn, user, strlen(user));
1426 :
1427 2 : if (!fmtuser)
1428 : {
1429 : /* PQescapeIdentifier() already registered the error */
1430 0 : PQfreemem(fmtpw);
1431 0 : return NULL;
1432 : }
1433 : else
1434 : {
1435 : PQExpBufferData buf;
1436 : PGresult *res;
1437 :
1438 2 : initPQExpBuffer(&buf);
1439 2 : printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD %s",
1440 : fmtuser, fmtpw);
1441 :
1442 2 : res = PQexec(conn, buf.data);
1443 :
1444 : /* clean up */
1445 2 : termPQExpBuffer(&buf);
1446 2 : PQfreemem(fmtuser);
1447 2 : PQfreemem(fmtpw);
1448 :
1449 2 : return res;
1450 : }
1451 : }
1452 : }
1453 : }
|