8
8
#include <ngx_config.h>
9
9
#include <ngx_core.h>
10
10
#include <ngx_http.h>
11
- /*
12
- #include <ngx_string.h>
13
- */
14
11
15
12
#include <gssapi/gssapi.h>
16
-
13
+ #include <gssapi/gssapi_krb5.h>
17
14
#include <krb5.h>
18
15
19
16
#define krb5_get_err_text (context ,code ) error_message(code)
20
17
21
- /* #include <spnegohelp.h> */
22
- int parseNegTokenInit (const unsigned char * negTokenInit ,
23
- size_t negTokenInitLength ,
24
- const unsigned char * * kerberosToken ,
25
- size_t * kerberosTokenLength );
26
- int makeNegTokenTarg (const unsigned char * kerberosToken ,
27
- size_t kerberosTokenLength ,
28
- const unsigned char * * negTokenTarg ,
29
- size_t * negTokenTargLength );
18
+ #include <spnegohelp.h>
30
19
31
20
/* Module handler */
32
21
static ngx_int_t ngx_http_auth_spnego_handler (ngx_http_request_t * );
@@ -48,20 +37,13 @@ get_gss_error(ngx_pool_t *p,
48
37
size_t len ;
49
38
ngx_str_t str ;
50
39
51
- /* ngx_fubarprintf... what a hack... %Z inserts '\0' */
40
+ /* %Z inserts '\0' */
52
41
ngx_snprintf ((u_char * ) buf , sizeof (buf ), "%s: %Z" , prefix );
53
42
len = ngx_strlen (buf );
54
43
do {
55
- maj_stat = gss_display_status (& min_stat ,
56
- error_status ,
57
- GSS_C_MECH_CODE ,
58
- GSS_C_NO_OID ,
59
- & msg_ctx ,
60
- & status_string );
44
+ maj_stat = gss_display_status (& min_stat , error_status , GSS_C_MECH_CODE ,
45
+ GSS_C_NO_OID , & msg_ctx , & status_string );
61
46
if (sizeof (buf ) > len + status_string .length + 1 ) {
62
- /*
63
- sprintf(buf, "%s:", (char*) status_string.value);
64
- */
65
47
ngx_sprintf ((u_char * ) buf + len , "%s:%Z" , (char * ) status_string .value );
66
48
len += ( status_string .length + 1 );
67
49
}
@@ -141,6 +123,8 @@ static ngx_command_t ngx_http_auth_spnego_commands[] = {
141
123
offsetof(ngx_http_auth_spnego_loc_conf_t , fqun ),
142
124
NULL },
143
125
126
+ /* TODO add support for specifying auth_gss_spn explicitely */
127
+
144
128
ngx_null_command
145
129
};
146
130
@@ -162,7 +146,6 @@ static ngx_http_module_t ngx_http_auth_spnego_module_ctx = {
162
146
163
147
/* Module Definition */
164
148
165
- /* really ngx_module_s /shrug */
166
149
ngx_module_t ngx_http_auth_spnego_module = {
167
150
/* ngx_uint_t ctx_index, index, spare{0-3}, version; */
168
151
NGX_MODULE_V1 , /* 0, 0, 0, 0, 0, 0, 1 */
@@ -193,13 +176,6 @@ ngx_http_auth_spnego_create_loc_conf(ngx_conf_t *cf)
193
176
conf -> protect = NGX_CONF_UNSET ;
194
177
conf -> fqun = NGX_CONF_UNSET ;
195
178
196
- /* temporary "debug" */
197
- #if (NGX_DEBUG )
198
- ngx_conf_log_error (NGX_LOG_INFO , cf , 0 ,
199
- "auth_spnego: allocated loc_conf_t (0x%p)" , conf );
200
- #endif
201
- /* TODO find out if there is way to enable it only in debug mode */
202
-
203
179
return conf ;
204
180
}
205
181
@@ -220,7 +196,6 @@ ngx_http_auth_spnego_merge_loc_conf(ngx_conf_t *cf,
220
196
221
197
ngx_conf_merge_off_value (conf -> fqun , prev -> fqun , 0 );
222
198
223
- /* TODO make it only shout in debug */
224
199
#if (NGX_DEBUG )
225
200
ngx_conf_log_error (NGX_LOG_INFO , cf , 0 , "auth_spnego: protect = %i" ,
226
201
conf -> protect );
@@ -261,26 +236,24 @@ ngx_http_auth_spnego_negotiate_headers(ngx_http_request_t *r,
261
236
ngx_str_t * token ,
262
237
ngx_http_auth_spnego_loc_conf_t * alcf )
263
238
{
239
+ /* The string handling here is inconsistent. Should we be including the NUL
240
+ * or not? My feeling is not, given that these are all ngx_str_t with defined
241
+ * length.
242
+ *
243
+ * TODO: Fix string lengths to be consistent about NUL termination
244
+ */
264
245
ngx_str_t value = ngx_null_string ;
265
- ngx_str_t value2 = ngx_null_string ;
266
246
267
247
if (token == NULL ) {
268
248
value .len = sizeof ("Negotiate" ) - 1 ;
269
249
value .data = (u_char * ) "Negotiate" ;
270
- value2 .len = sizeof ("Basic realm=\"\"" ) + alcf -> realm .len ;
271
- value2 .data = ngx_pcalloc (r -> pool , value2 .len + 1 );
272
- if (value2 .data == NULL ) {
273
- return NGX_ERROR ;
274
- }
275
- ngx_snprintf (value2 .data , value2 .len + 1 , "Basic realm=\"%V\"%Z" ,
276
- & alcf -> realm );
277
250
} else {
278
- value .len = sizeof ("Negotiate" ) + token -> len ;
279
- value .data = ngx_pcalloc (r -> pool , value .len + 1 );
251
+ value .len = sizeof ("Negotiate" ) + token -> len ; //space accounts for \0
252
+ value .data = ngx_pcalloc (r -> pool , value .len );
280
253
if (value .data == NULL ) {
281
254
return NGX_ERROR ;
282
255
}
283
- ngx_snprintf (value .data , value .len + 1 , "Negotiate %V" , token );
256
+ ngx_snprintf (value .data , value .len , "Negotiate %V" , token );
284
257
}
285
258
286
259
r -> headers_out .www_authenticate = ngx_list_push (& r -> headers_out .headers );
@@ -295,7 +268,15 @@ ngx_http_auth_spnego_negotiate_headers(ngx_http_request_t *r,
295
268
r -> headers_out .www_authenticate -> value .len = value .len ;
296
269
r -> headers_out .www_authenticate -> value .data = value .data ;
297
270
271
+ /* Basic auth */
298
272
if (token == NULL ) {
273
+ ngx_str_t value2 = ngx_null_string ;
274
+ value2 .len = sizeof ("Basic realm=\"\"" ) - 1 + alcf -> realm .len ;
275
+ value2 .data = ngx_pcalloc (r -> pool , value2 .len );
276
+ if (value2 .data == NULL ) {
277
+ return NGX_ERROR ;
278
+ }
279
+ ngx_snprintf (value2 .data , value2 .len , "Basic realm=\"%V\"" , & alcf -> realm );
299
280
r -> headers_out .www_authenticate = ngx_list_push (& r -> headers_out .headers );
300
281
if (r -> headers_out .www_authenticate == NULL ) {
301
282
return NGX_ERROR ;
@@ -314,7 +295,6 @@ ngx_http_auth_spnego_negotiate_headers(ngx_http_request_t *r,
314
295
return NGX_OK ;
315
296
}
316
297
317
- /* sort of like ngx_http_auth_basic_user ... except we store in ctx_t? */
318
298
ngx_int_t
319
299
ngx_http_auth_spnego_token (ngx_http_request_t * r ,
320
300
ngx_http_auth_spnego_ctx_t * ctx )
@@ -566,32 +546,22 @@ ngx_http_auth_spnego_auth_user_gss(ngx_http_request_t *r,
566
546
{
567
547
static unsigned char ntlmProtocol [] = {'N' , 'T' , 'L' , 'M' , 'S' , 'S' , 'P' , 0 };
568
548
569
- /*
570
- nginx stuff
571
- */
549
+ /* nginx stuff */
572
550
ngx_str_t host_name ;
573
551
ngx_int_t ret = NGX_DECLINED ;
574
552
int rc ;
575
553
int spnego_flag = 0 ;
576
554
char * p ;
577
- /*
578
- kerberos stuff
579
- */
555
+
556
+ /* kerberos stuff */
580
557
krb5_context krb_ctx = NULL ;
581
558
char * ktname = NULL ;
582
559
/* ngx_str_t kerberosToken; ? */
583
560
unsigned char * kerberosToken = NULL ;
584
561
size_t kerberosTokenLength = 0 ;
585
- /* this izgotten from de-SPNEGGING original token...
586
- and put into gss_accept_sec_context...
587
- silly...
588
- */
589
562
ngx_str_t spnegoToken = ngx_null_string ;
590
- /* unsigned char *spnegoToken = NULL ;
591
- size_t spnegoTokenLength = 0; */
592
- /*
593
- gssapi stuff
594
- */
563
+
564
+ /* gssapi stuff */
595
565
OM_uint32 major_status , minor_status , minor_status2 ;
596
566
gss_buffer_desc service = GSS_C_EMPTY_BUFFER ;
597
567
gss_name_t my_gss_name = GSS_C_NO_NAME ;
@@ -603,19 +573,16 @@ ngx_http_auth_spnego_auth_user_gss(ngx_http_request_t *r,
603
573
OM_uint32 ret_flags = 0 ;
604
574
gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL ;
605
575
606
- /* first, see if there is a point in runing */
607
- /* ctx = ngx_http_get_module_ctx(r, ngx_http_auth_spnego_module); */
608
- /* this really shouldn't 'eppen */
609
- if (!ctx || ctx -> token .len == 0 ) {
576
+ if (NULL == ctx || ctx -> token .len == 0 )
610
577
return ret ;
611
- }
612
- /* on with the copy cat show */
578
+
613
579
ngx_log_debug0 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
614
- "GSSAPI authorizing" );
580
+ "GSSAPI authorizing" );
615
581
616
582
krb5_init_context (& krb_ctx );
617
583
618
- ktname = (char * ) ngx_pcalloc (r -> pool , sizeof ("KRB5_KTNAME=" )+ alcf -> keytab .len );
584
+ ktname = (char * ) ngx_pcalloc (r -> pool , sizeof ("KRB5_KTNAME=" ) +
585
+ alcf -> keytab .len );
619
586
if (ktname == NULL ) {
620
587
ret = NGX_ERROR ;
621
588
goto end ;
@@ -627,48 +594,64 @@ ngx_http_auth_spnego_auth_user_gss(ngx_http_request_t *r,
627
594
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
628
595
"Use keytab %V" , & alcf -> keytab );
629
596
630
- /* TODECIDE: wherefrom use the hostname value for the service name? */
597
+ /* The required logic here is to choose between these options:
598
+ * 1. Use the service as specified in the config? Not yet implemented
599
+ * 2. Use the service as expected by the client? (gss_OID)gss_nt_krb5_name
600
+ * 3. Allow the library to canonicalize the name? GSS_C_NT_HOSTBASED_SERVICE */
631
601
host_name = r -> headers_in .host -> value ;
632
- /* for now using the name client thinks... */
633
- service .length = alcf -> srvcname .len + host_name .len + 2 ;
634
- /* @ vel / */
602
+ u_char * port_start = (u_char * )ngx_strchr (host_name .data , ':' );
603
+ uint real_host_name_len = 0 ;
604
+ if (NULL == port_start ) { /* no port number specified */
605
+ service .length = alcf -> srvcname .len + host_name .len + 2 ;
606
+ real_host_name_len = host_name .len ;
607
+ } else { /* port number included, strip it */
608
+ service .length = alcf -> srvcname .len + (port_start - host_name .data - 1 ) + 2 ;
609
+ real_host_name_len = (port_start - host_name .data );
610
+ }
611
+
635
612
service .value = ngx_palloc (r -> pool , service .length );
636
613
if (service .value == NULL ) {
637
614
ret = NGX_ERROR ;
638
615
goto end ;
639
616
}
640
- ngx_snprintf (service .value , service .length , "%V@%V%Z" ,
641
- & alcf -> srvcname , & host_name );
642
617
643
- ngx_log_debug2 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
644
- "Use service principal %V/%V" , & alcf -> srvcname , & host_name );
618
+ ngx_snprintf (service .value , service .length , "%V/%V" , & alcf -> srvcname ,
619
+ & host_name );
620
+ ngx_snprintf ((u_char * )service .value + service .length , 1 , "%Z" );
621
+ ngx_log_debug1 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 ,
622
+ "Using service principal: %s" , service .value );
645
623
646
624
major_status = gss_import_name (& minor_status , & service ,
647
- GSS_C_NT_HOSTBASED_SERVICE , & my_gss_name );
625
+ (gss_OID )gss_nt_krb5_name , & my_gss_name );
626
+ // GSS_C_NT_HOSTBASED_SERVICE, &my_gss_name);
648
627
if (GSS_ERROR (major_status )) {
649
- ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 ,
650
- "%s Used service principal: %s" ,
651
- get_gss_error (r -> pool , minor_status ,
652
- "gss_import_name() failed for service principal" ),
653
- (unsigned char * )service .value );
654
- ret = NGX_ERROR ;
655
- goto end ;
628
+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 ,
629
+ "%s Used service principal: %s " , get_gss_error (r -> pool , minor_status ,
630
+ "gss_import_name() failed for service principal" ),
631
+ (u_char * )service .value );
632
+ ret = NGX_ERROR ;
633
+ goto end ;
656
634
}
657
635
658
- major_status = gss_acquire_cred (& minor_status ,
659
- my_gss_name ,
660
- GSS_C_INDEFINITE ,
661
- GSS_C_NO_OID_SET ,
662
- GSS_C_ACCEPT ,
663
- & my_gss_creds ,
664
- NULL ,
665
- NULL );
636
+ /* Log the credentials we plan to use */
637
+ gss_buffer_desc human_readable_gss_name = GSS_C_EMPTY_BUFFER ;
638
+ major_status = gss_display_name (& minor_status , my_gss_name ,
639
+ & human_readable_gss_name , NULL );
640
+
641
+ if (GSS_ERROR (major_status )) {
642
+ ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 , "%s" , get_gss_error (
643
+ r -> pool , minor_status , "gss_display_name() failed" ));
644
+ }
645
+ ngx_log_debug1 (NGX_LOG_DEBUG_HTTP , r -> connection -> log , 0 , "my_gss_name %s" ,
646
+ human_readable_gss_name .value );
647
+
648
+ /* Obtain credentials */
649
+ major_status = gss_acquire_cred (& minor_status , my_gss_name , GSS_C_INDEFINITE ,
650
+ GSS_C_NO_OID_SET , GSS_C_ACCEPT , & my_gss_creds , NULL , NULL );
666
651
if (GSS_ERROR (major_status )) {
667
652
ngx_log_error (NGX_LOG_ERR , r -> connection -> log , 0 ,
668
- "%s Used service principal: %s" ,
669
- get_gss_error (r -> pool , minor_status ,
670
- "gss_acquire_cred() failed" ),
671
- (unsigned char * )service .value );
653
+ "%s Used service principal: %s" , get_gss_error (r -> pool , minor_status ,
654
+ "gss_acquire_cred() failed" ), (unsigned char * )service .value );
672
655
ret = NGX_ERROR ;
673
656
goto end ;
674
657
}
0 commit comments