8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.45 2000/05/27 03:39:31 momjian Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.46 2000/05/27 03:58:19 momjian Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -149,8 +149,7 @@ pg_krb4_recvauth(Port *port)
149
149
*----------------------------------------------------------------
150
150
*/
151
151
152
- #include <krb5.h>
153
- #include <com_err.h>
152
+ #include "krb5/krb5.h"
154
153
155
154
/*
156
155
* pg_an_to_ln -- return the local name corresponding to an authentication
@@ -175,64 +174,6 @@ pg_an_to_ln(char *aname)
175
174
return aname ;
176
175
}
177
176
178
-
179
- /*
180
- * Various krb5 state which is not connection specfic, and a flag to
181
- * indicate whether we have initialised it yet.
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
-
189
- static int
190
- pg_krb5_init (void )
191
- {
192
- krb5_error_code retval ;
193
-
194
- if (pg_krb5_initialised )
195
- return STATUS_OK ;
196
-
197
- retval = krb5_init_context (& pg_krb5_context );
198
- if (retval ) {
199
- snprintf (PQerrormsg ,PQERRORMSG_LENGTH ,
200
- "pg_krb5_init: krb5_init_context returned"
201
- " Kerberos error %d\n" ,retval );
202
- com_err ("postgres" ,retval ,"while initializing krb5" );
203
- return STATUS_ERROR ;
204
- }
205
-
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 ;
215
- }
216
-
217
- retval = krb5_sname_to_principal (pg_krb5_context ,NULL ,PG_KRB_SRVNAM ,
218
- KRB5_NT_SRV_HST ,& pg_krb5_server );
219
- if (retval ) {
220
- snprintf (PQerrormsg ,PQERRORMSG_LENGTH ,
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 );
228
- return STATUS_ERROR ;
229
- }
230
-
231
- pg_krb5_initialised = 1 ;
232
- return STATUS_OK ;
233
- }
234
-
235
-
236
177
/*
237
178
* pg_krb5_recvauth -- server routine to receive authentication information
238
179
* from the client
@@ -241,68 +182,122 @@ pg_krb5_init(void)
241
182
* packet to the authenticated name, as described in pg_krb4_recvauth.This
242
183
* is a bit more problematic in v5, as described above in pg_an_to_ln.
243
184
*
244
- * We have our own keytab file because postgres is unlikely to run as root,
245
- * and so cannot read the default keytab.
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!)
246
198
*/
247
199
static int
248
200
pg_krb5_recvauth (Port * port )
249
201
{
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 ) {
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 ;
212
+
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
+ {
226
+ 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" );
229
+ return STATUS_ERROR ;
230
+ }
231
+
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 ;
244
+ }
245
+
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
+ {
264
259
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" );
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 );
268
263
return STATUS_ERROR ;
269
- }
264
+ }
265
+ krb5_free_principal (server );
270
266
271
267
/*
272
268
* The "client" structure comes out of the ticket and is therefore
273
269
* authenticated. Use it to check the username obtained from the
274
270
* postmaster startup packet.
275
- *
276
- * I have no idea why this is considered necessary.
277
271
*/
278
- retval = krb5_unparse_name (pg_krb5_context ,
279
- ticket -> enc_part2 -> client ,& kusername );
280
- if (retval ) {
272
+ if ((code = krb5_unparse_name (client ,& kusername )))
273
+ {
281
274
snprintf (PQerrormsg ,PQERRORMSG_LENGTH ,
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 );
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 );
287
287
return STATUS_ERROR ;
288
288
}
289
-
290
289
kusername = pg_an_to_ln (kusername );
291
- if (strncmp (port -> user ,kusername ,SM_USER ))
290
+ if (strncmp (username ,kusername ,SM_USER ))
292
291
{
293
292
snprintf (PQerrormsg ,PQERRORMSG_LENGTH ,
294
- "pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"\n" ,
295
- port -> user ,kusername );
296
- ret = STATUS_ERROR ;
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 ;
297
298
}
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 ;
299
+ pfree (kusername );
300
+ return STATUS_OK ;
306
301
}
307
302
308
303
#else