88 *
99 *
1010 * 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 $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -149,8 +149,7 @@ pg_krb4_recvauth(Port *port)
149149 *----------------------------------------------------------------
150150 */
151151
152- #include <krb5.h>
153- #include <com_err.h>
152+ #include "krb5/krb5.h"
154153
155154/*
156155 * pg_an_to_ln -- return the local name corresponding to an authentication
@@ -175,64 +174,6 @@ pg_an_to_ln(char *aname)
175174return aname ;
176175}
177176
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-
236177/*
237178 * pg_krb5_recvauth -- server routine to receive authentication information
238179 * from the client
@@ -241,68 +182,122 @@ pg_krb5_init(void)
241182 * packet to the authenticated name, as described in pg_krb4_recvauth.This
242183 * is a bit more problematic in v5, as described above in pg_an_to_ln.
243184 *
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!)
246198 */
247199static int
248200pg_krb5_recvauth (Port * port )
249201{
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+ {
264259snprintf (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 );
268263return STATUS_ERROR ;
269- }
264+ }
265+ krb5_free_principal (server );
270266
271267/*
272268 * The "client" structure comes out of the ticket and is therefore
273269 * authenticated. Use it to check the username obtained from the
274270 * postmaster startup packet.
275- *
276- * I have no idea why this is considered necessary.
277271 */
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+ {
281274snprintf (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 );
287287return STATUS_ERROR ;
288288}
289-
290289kusername = pg_an_to_ln (kusername );
291- if (strncmp (port -> user ,kusername ,SM_USER ))
290+ if (strncmp (username ,kusername ,SM_USER ))
292291{
293292snprintf (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 ;
297298}
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 ;
306301}
307302
308303#else