Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * be-gssapi-common.c
4 : : * Common code for GSSAPI authentication and encryption
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/backend/libpq/be-gssapi-common.c
11 : : *
12 : : *-------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include "libpq/be-gssapi-common.h"
18 : :
19 : : /*
20 : : * Fetch all errors of a specific type and append to "s" (buffer of size len).
21 : : * If we obtain more than one string, separate them with spaces.
22 : : * Call once for GSS_CODE and once for MECH_CODE.
23 : : */
24 : : static void
1838 sfrost@snowman.net 25 :UBC 0 : pg_GSS_error_int(char *s, size_t len, OM_uint32 stat, int type)
26 : : {
27 : : gss_buffer_desc gmsg;
28 : 0 : size_t i = 0;
29 : : OM_uint32 lmin_s,
30 : 0 : msg_ctx = 0;
31 : :
32 : : do
33 : : {
1203 tgl@sss.pgh.pa.us 34 [ # # ]: 0 : if (gss_display_status(&lmin_s, stat, type, GSS_C_NO_OID,
35 : : &msg_ctx, &gmsg) != GSS_S_COMPLETE)
36 : 0 : break;
37 [ # # ]: 0 : if (i > 0)
38 : : {
39 [ # # ]: 0 : if (i < len)
40 : 0 : s[i] = ' ';
41 : 0 : i++;
42 : : }
43 [ # # ]: 0 : if (i < len)
1026 44 : 0 : memcpy(s + i, gmsg.value, Min(len - i, gmsg.length));
1838 sfrost@snowman.net 45 : 0 : i += gmsg.length;
46 : 0 : gss_release_buffer(&lmin_s, &gmsg);
47 : : }
1203 tgl@sss.pgh.pa.us 48 [ # # ]: 0 : while (msg_ctx);
49 : :
50 : : /* add nul termination */
1026 51 [ # # ]: 0 : if (i < len)
52 : 0 : s[i] = '\0';
53 : : else
54 : : {
1203 55 [ # # ]: 0 : elog(COMMERROR, "incomplete GSS error report");
1026 56 : 0 : s[len - 1] = '\0';
57 : : }
1838 sfrost@snowman.net 58 : 0 : }
59 : :
60 : : /*
61 : : * Report the GSSAPI error described by maj_stat/min_stat.
62 : : *
63 : : * errmsg should be an already-translated primary error message.
64 : : * The GSSAPI info is appended as errdetail.
65 : : *
66 : : * The error is always reported with elevel COMMERROR; we daren't try to
67 : : * send it to the client, as that'd likely lead to infinite recursion
68 : : * when elog.c tries to write to the client.
69 : : *
70 : : * To avoid memory allocation, total error size is capped (at 128 bytes for
71 : : * each of major and minor). No known mechanisms will produce error messages
72 : : * beyond this cap.
73 : : */
74 : : void
1203 tgl@sss.pgh.pa.us 75 : 0 : pg_GSS_error(const char *errmsg,
76 : : OM_uint32 maj_stat, OM_uint32 min_stat)
77 : : {
78 : : char msg_major[128],
79 : : msg_minor[128];
80 : :
81 : : /* Fetch major status message */
1838 sfrost@snowman.net 82 : 0 : pg_GSS_error_int(msg_major, sizeof(msg_major), maj_stat, GSS_C_GSS_CODE);
83 : :
84 : : /* Fetch mechanism minor status message */
85 : 0 : pg_GSS_error_int(msg_minor, sizeof(msg_minor), min_stat, GSS_C_MECH_CODE);
86 : :
87 : : /*
88 : : * errmsg_internal, since translation of the first part must be done
89 : : * before calling this function anyway.
90 : : */
1203 tgl@sss.pgh.pa.us 91 [ # # ]: 0 : ereport(COMMERROR,
92 : : (errmsg_internal("%s", errmsg),
93 : : errdetail_internal("%s: %s", msg_major, msg_minor)));
1838 sfrost@snowman.net 94 : 0 : }
95 : :
96 : : /*
97 : : * Store the credentials passed in into the memory cache for later usage.
98 : : *
99 : : * This allows credentials to be delegated to us for us to use to connect
100 : : * to other systems with, using, e.g. postgres_fdw or dblink.
101 : : */
102 : : #define GSS_MEMORY_CACHE "MEMORY:"
103 : : void
367 sfrost@snowman.net 104 :CBC 16 : pg_store_delegated_credential(gss_cred_id_t cred)
105 : : {
106 : : OM_uint32 major,
107 : : minor;
108 : : gss_OID_set mech;
109 : : gss_cred_usage_t usage;
110 : : gss_key_value_element_desc cc;
111 : : gss_key_value_set_desc ccset;
112 : :
113 : 16 : cc.key = "ccache";
114 : 16 : cc.value = GSS_MEMORY_CACHE;
115 : 16 : ccset.count = 1;
116 : 16 : ccset.elements = &cc;
117 : :
118 : : /* Make the delegated credential only available to current process */
119 : 16 : major = gss_store_cred_into(&minor,
120 : : cred,
121 : : GSS_C_INITIATE, /* credential only used for
122 : : * starting libpq connection */
123 : : GSS_C_NULL_OID, /* store all */
124 : : true, /* overwrite */
125 : : true, /* make default */
126 : : &ccset,
127 : : &mech,
128 : : &usage);
129 : :
130 [ - + ]: 16 : if (major != GSS_S_COMPLETE)
131 : : {
367 sfrost@snowman.net 132 :UBC 0 : pg_GSS_error("gss_store_cred", major, minor);
133 : : }
134 : :
135 : : /* Credential stored, so we can release our credential handle. */
367 sfrost@snowman.net 136 :CBC 16 : major = gss_release_cred(&minor, &cred);
137 [ - + ]: 16 : if (major != GSS_S_COMPLETE)
138 : : {
367 sfrost@snowman.net 139 :UBC 0 : pg_GSS_error("gss_release_cred", major, minor);
140 : : }
141 : :
142 : : /*
143 : : * Set KRB5CCNAME for this backend, so that later calls to
144 : : * gss_acquire_cred will find the delegated credentials we stored.
145 : : */
367 sfrost@snowman.net 146 :CBC 16 : setenv("KRB5CCNAME", GSS_MEMORY_CACHE, 1);
147 : 16 : }
|