8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.44 2000/04/12 17:15:13 momjian Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.45 2000/05/27 03:39:31 momjian Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -149,7 +149,8 @@ pg_krb4_recvauth(Port *port)
149
149
*----------------------------------------------------------------
150
150
*/
151
151
152
- #include "krb5/krb5.h"
152
+ #include <krb5.h>
153
+ #include <com_err.h>
153
154
154
155
/*
155
156
* pg_an_to_ln -- return the local name corresponding to an authentication
@@ -174,130 +175,134 @@ pg_an_to_ln(char *aname)
174
175
return aname ;
175
176
}
176
177
178
+
177
179
/*
178
- * pg_krb5_recvauth -- server routine to receive authentication information
179
- * from the client
180
- *
181
- * We still need to compare the username obtained from the client's setup
182
- * packet to the authenticated name, as described in pg_krb4_recvauth. This
183
- * is a bit more problematic in v5, as described above in pg_an_to_ln.
184
- *
185
- * In addition, as described above in pg_krb5_sendauth, we still need to
186
- * canonicalize the server name v4-style before constructing a principal
187
- * from it. Again, this is kind of iffy.
188
- *
189
- * Finally, we need to tangle with the fact that v5 doesn't let you explicitly
190
- * set server keytab file names -- you have to feed lower-level routines a
191
- * function to retrieve the contents of a keytab, along with a single argument
192
- * that allows them to open the keytab. We assume that a server keytab is
193
- * always a real file so we can allow people to specify their own filenames.
194
- * (This is important because the POSTGRES keytab needs to be readable by
195
- * non-root users/groups; the v4 tools used to force you do dump a whole
196
- * host's worth of keys into a file, effectively forcing you to use one file,
197
- * but kdb5_edit allows you to select which principals to dump. Yay!)
180
+ * Various krb5 state which is not connection specfic, and a flag to
181
+ * indicate whether we have initialised it yet.
198
182
*/
183
+ static int pg_krb5_initialised ;
184
+ static krb5_context pg_krb5_context ;
185
+ static krb5_keytab pg_krb5_keytab ;
186
+ static krb5_principal pg_krb5_server ;
187
+
188
+
199
189
static int
200
- pg_krb5_recvauth ( Port * port )
190
+ pg_krb5_init ( void )
201
191
{
202
- char servbuf [MAXHOSTNAMELEN + 1 +
203
- sizeof (PG_KRB_SRVNAM )];
204
- char * hostp ,
205
- * kusername = (char * ) NULL ;
206
- krb5_error_code code ;
207
- krb5_principal client ,
208
- server ;
209
- krb5_address sender_addr ;
210
- krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc ) NULL ;
211
- krb5_pointer keyprocarg = (krb5_pointer ) NULL ;
192
+ krb5_error_code retval ;
212
193
213
- /*
214
- * Set up server side -- since we have no ticket file to make this
215
- * easy, we construct our own name and parse it. See note on
216
- * canonicalization above.
217
- */
218
- strcpy (servbuf , PG_KRB_SRVNAM );
219
- * (hostp = servbuf + (sizeof (PG_KRB_SRVNAM ) - 1 )) = '/' ;
220
- if (gethostname (++ hostp , MAXHOSTNAMELEN ) < 0 )
221
- strcpy (hostp , "localhost" );
222
- if (hostp = strchr (hostp , '.' ))
223
- * hostp = '\0' ;
224
- if (code = krb5_parse_name (servbuf , & server ))
225
- {
194
+ if (pg_krb5_initialised )
195
+ return STATUS_OK ;
196
+
197
+ retval = krb5_init_context (& pg_krb5_context );
198
+ if (retval ) {
226
199
snprintf (PQerrormsg , PQERRORMSG_LENGTH ,
227
- "pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n" , code );
228
- com_err ("pg_krb5_recvauth" , code , "in krb5_parse_name" );
200
+ "pg_krb5_init: krb5_init_context returned"
201
+ " Kerberos error %d\n" , retval );
202
+ com_err ("postgres" , retval , "while initializing krb5" );
229
203
return STATUS_ERROR ;
230
204
}
231
205
232
- /*
233
- * krb5_sendauth needs this to verify the address in the client
234
- * authenticator.
235
- */
236
- sender_addr .addrtype = port -> raddr .in .sin_family ;
237
- sender_addr .length = sizeof (port -> raddr .in .sin_addr );
238
- sender_addr .contents = (krb5_octet * ) & (port -> raddr .in .sin_addr );
239
-
240
- if (strcmp (PG_KRB_SRVTAB , "" ))
241
- {
242
- keyproc = krb5_kt_read_service_key ;
243
- keyprocarg = PG_KRB_SRVTAB ;
206
+ retval = krb5_kt_resolve (pg_krb5_context , PG_KRB_SRVTAB , & pg_krb5_keytab );
207
+ if (retval ) {
208
+ snprintf (PQerrormsg , PQERRORMSG_LENGTH ,
209
+ "pg_krb5_init: krb5_kt_resolve returned"
210
+ " Kerberos error %d\n" , retval );
211
+ com_err ("postgres" , retval , "while resolving keytab file %s" ,
212
+ PG_KRB_SRVTAB );
213
+ krb5_free_context (pg_krb5_context );
214
+ return STATUS_ERROR ;
244
215
}
245
216
246
- if (code = krb5_recvauth ((krb5_pointer ) & port -> sock ,
247
- PG_KRB5_VERSION ,
248
- server ,
249
- & sender_addr ,
250
- (krb5_pointer ) NULL ,
251
- keyproc ,
252
- keyprocarg ,
253
- (char * ) NULL ,
254
- (krb5_int32 * ) NULL ,
255
- & client ,
256
- (krb5_ticket * * ) NULL ,
257
- (krb5_authenticator * * ) NULL ))
258
- {
217
+ retval = krb5_sname_to_principal (pg_krb5_context , NULL , PG_KRB_SRVNAM ,
218
+ KRB5_NT_SRV_HST , & pg_krb5_server );
219
+ if (retval ) {
259
220
snprintf (PQerrormsg , PQERRORMSG_LENGTH ,
260
- "pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n" , code );
261
- com_err ("pg_krb5_recvauth" , code , "in krb5_recvauth" );
262
- krb5_free_principal (server );
221
+ "pg_krb5_init: krb5_sname_to_principal returned"
222
+ " Kerberos error %d\n" , retval );
223
+ com_err ("postgres" , retval ,
224
+ "while getting server principal for service %s" ,
225
+ PG_KRB_SRVTAB );
226
+ krb5_kt_close (pg_krb5_context , pg_krb5_keytab );
227
+ krb5_free_context (pg_krb5_context );
263
228
return STATUS_ERROR ;
264
229
}
265
- krb5_free_principal (server );
230
+
231
+ pg_krb5_initialised = 1 ;
232
+ return STATUS_OK ;
233
+ }
234
+
235
+
236
+ /*
237
+ * pg_krb5_recvauth -- server routine to receive authentication information
238
+ * from the client
239
+ *
240
+ * We still need to compare the username obtained from the client's setup
241
+ * packet to the authenticated name, as described in pg_krb4_recvauth. This
242
+ * is a bit more problematic in v5, as described above in pg_an_to_ln.
243
+ *
244
+ * We have our own keytab file because postgres is unlikely to run as root,
245
+ * and so cannot read the default keytab.
246
+ */
247
+ static int
248
+ pg_krb5_recvauth (Port * port )
249
+ {
250
+ krb5_error_code retval ;
251
+ int ret ;
252
+ krb5_auth_context auth_context = NULL ;
253
+ krb5_ticket * ticket ;
254
+ char * kusername ;
255
+
256
+ ret = pg_krb5_init ();
257
+ if (ret != STATUS_OK )
258
+ return ret ;
259
+
260
+ retval = krb5_recvauth (pg_krb5_context , & auth_context ,
261
+ (krb5_pointer )& port -> sock , PG_KRB_SRVNAM ,
262
+ pg_krb5_server , 0 , pg_krb5_keytab , & ticket );
263
+ if (retval ) {
264
+ snprintf (PQerrormsg , PQERRORMSG_LENGTH ,
265
+ "pg_krb5_recvauth: krb5_recvauth returned"
266
+ " Kerberos error %d\n" , retval );
267
+ com_err ("postgres" , retval , "from krb5_recvauth" );
268
+ return STATUS_ERROR ;
269
+ }
266
270
267
271
/*
268
272
* The "client" structure comes out of the ticket and is therefore
269
273
* authenticated. Use it to check the username obtained from the
270
274
* postmaster startup packet.
275
+ *
276
+ * I have no idea why this is considered necessary.
271
277
*/
272
- if ((code = krb5_unparse_name (client , & kusername )))
273
- {
278
+ retval = krb5_unparse_name (pg_krb5_context ,
279
+ ticket -> enc_part2 -> client , & kusername );
280
+ if (retval ) {
274
281
snprintf (PQerrormsg , PQERRORMSG_LENGTH ,
275
- "pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n" , code );
276
- com_err ("pg_krb5_recvauth" , code , "in krb5_unparse_name" );
277
- krb5_free_principal (client );
278
- return STATUS_ERROR ;
279
- }
280
- krb5_free_principal (client );
281
- if (!kusername )
282
- {
283
- snprintf (PQerrormsg , PQERRORMSG_LENGTH ,
284
- "pg_krb5_recvauth: could not decode username\n" );
285
- fputs (PQerrormsg , stderr );
286
- pqdebug ("%s" , PQerrormsg );
282
+ "pg_krb5_recvauth: krb5_unparse_name returned"
283
+ " Kerberos error %d\n" , retval );
284
+ com_err ("postgres" , retval , "while unparsing client name" );
285
+ krb5_free_ticket (pg_krb5_context , ticket );
286
+ krb5_auth_con_free (pg_krb5_context , auth_context );
287
287
return STATUS_ERROR ;
288
288
}
289
+
289
290
kusername = pg_an_to_ln (kusername );
290
- if (strncmp (username , kusername , SM_USER ))
291
+ if (strncmp (port -> user , kusername , SM_USER ))
291
292
{
292
293
snprintf (PQerrormsg , PQERRORMSG_LENGTH ,
293
- "pg_krb5_recvauth: name \"%s\" != \"%s\"\n" , port -> user , kusername );
294
- fputs (PQerrormsg , stderr );
295
- pqdebug ("%s" , PQerrormsg );
296
- pfree (kusername );
297
- return STATUS_ERROR ;
294
+ "pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"\n" ,
295
+ port -> user , kusername );
296
+ ret = STATUS_ERROR ;
298
297
}
299
- pfree (kusername );
300
- return STATUS_OK ;
298
+ else
299
+ ret = STATUS_OK ;
300
+
301
+ krb5_free_ticket (pg_krb5_context , ticket );
302
+ krb5_auth_con_free (pg_krb5_context , auth_context );
303
+ free (kusername );
304
+
305
+ return ret ;
301
306
}
302
307
303
308
#else
0 commit comments