Skip to content

Commit 28f49a5

Browse files
committed
http: make SPNEGO helpers individually configurable
Offer a way to run SPNEGO-Kerberos through a helper rather than the C library interface. References: GXL-408
1 parent 24565de commit 28f49a5

File tree

3 files changed

+79
-48
lines changed

3 files changed

+79
-48
lines changed

doc/http.8gx

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,24 @@ Maximum execution time for CGI scripts.
7272
.br
7373
Default: \fI10 minutes\fP
7474
.TP
75+
.TP
76+
\fBgss_program\fP
77+
The helper program to use for authenticating SPNEGO-GSS requests. The value is
78+
rudimentarily tokenized at whitespaces, so no special characters may be used.
79+
(If you need to, write a shell wrapper.) The special value "internal-gss" uses
80+
libgssapi directly.
81+
The use of Squid's negotiate_wrapper_auth is optional; Gromox can identify
82+
whether requests are SPNEGO-NTLMSSP or SPNEGO-Kerberos in the same fashion as
83+
negotiate_wrapper_auth does.
84+
.br
85+
Default: \fIinternal\-gss\fP
86+
.br
87+
Example: \fI/usr/lib/squid/negotiate_kerberos_auth \-s GSS_C_NO_NAME\fP
88+
.br
89+
Example: \fI/usr/lib/squid/negotiate_wrapper_auth \-\-ntlm /usr/bin/ntlm_auth
90+
\-\-helper\-protocol=squid\-2.5\-ntlmssp \-\-kerberos
91+
/usr/lib/squid/negotiate_kerberos_auth \-s GSS_C_NO_NAME\fP
92+
.TP
7593
\fBhost_id\fP
7694
A unique identifier for this system. It is used for the Server HTTP responses
7795
header, for service plugins like exmdb_provider(4gx), which makes use of it for
@@ -90,13 +108,6 @@ Enable HTTP Negotiate authentication.
90108
.br
91109
Default: \fIno\fP
92110
.TP
93-
\fBhttp_auth_spnego_ntlmssp\fP
94-
When a client uses HTTP Negotiate authentication and the negotation data looks
95-
like NTLMSSP, pass the data to ntlm_auth rather than GSS-API. (When this option
96-
disabled, data is always passed to GSS-API.)
97-
.br
98-
Default: \fIyes\fP
99-
.TP
100111
\fBhttp_auth_times\fP
101112
The number of login tries a user is allowed before the account is blocked.
102113
.br
@@ -200,11 +211,20 @@ all RPCs. Note the daemon log level needs to be "debug" (6), too.
200211
.br
201212
Default: \fI0\fP
202213
.TP
203-
\fBntlm_auth\fP
204-
Path to samba-winbind ntlm_auth or equivalent program that accepts the
205-
arguments `\fB\-d0 \-\-helper\-protocol=squid\-2.5\-ntlmssp\fP`.
214+
\fBntlmssp_program\fP
215+
Path to samba-winbind ntlm_auth or equivalent program that implements the Squid
216+
authentication helper text protocol ("YR, TT, KK, AF"). The value is
217+
rudimentarily tokenized at whitespaces, so no special characters may be used.
218+
(If you need to, write a shell wrapper.)
219+
The use of Squid's negotiate_wrapper_auth is optional; Gromox can identify
220+
whether requests are SPNEGO-NTLMSSP or SPNEGO-Kerberos in the same fashion as
221+
negotiate_wrapper_auth does.
222+
.br
223+
Default: \fI/usr/bin/ntlm_auth \-\-helper\-protocol=squid\-2.5\-ntlmssp\fP
206224
.br
207-
Default: \fI/usr/bin/ntlm_auth\fP
225+
Example: \fI/usr/lib/squid/negotiate_wrapper_auth \-\-ntlm /usr/bin/ntlm_auth
226+
\-\-helper\-protocol=squid\-2.5\-ntlmssp \-\-kerberos
227+
/usr/lib/squid/negotiate_kerberos_auth \-s GSS_C_NO_NAME\fP
208228
.TP
209229
\fBrequest_max_mem\fP
210230
The maximum hint size for fragmented RPC PDU requests that will be allowed

exch/http/http_parser.cpp

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -787,19 +787,20 @@ static void ntlm_stop(struct HXproc &pi)
787787
pi.p_pid = 0;
788788
}
789789

790-
static int auth_ntlmssp(http_context &ctx, const char *encinput, size_t encsize,
791-
const char *input, size_t isize, std::string &output)
790+
static int htp_auth_ntlmssp(http_context &ctx, const char *prog,
791+
const char *encinput, std::string &output)
792792
{
793+
auto encsize = strlen(encinput);
793794
auto &pinfo = ctx.ntlm_proc;
794795
output.clear();
795796

796797
if (pinfo.p_pid <= 0) {
797-
auto prog = g_config_file->get_value("ntlm_auth");
798798
if (prog == nullptr || *prog == '\0')
799-
prog = "/usr/bin/ntlm_auth";
800-
const char *argv[] = {prog, "-d0", "--helper-protocol=squid-2.5-ntlmssp", nullptr};
799+
prog = "/usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp";
800+
auto args = HX_split(prog, " ", nullptr, 0);
801+
auto cl_0 = make_scope_exit([&]() { HX_zvecfree(args); });
801802
pinfo.p_flags = HXPROC_STDIN | HXPROC_STDOUT | HXPROC_STDERR;
802-
auto ret = HXproc_run_async(argv, &pinfo);
803+
auto ret = HXproc_run_async(&args[0], &pinfo);
803804
if (ret < 0) {
804805
mlog(LV_ERR, "execv ntlm_auth: %s", strerror(-ret));
805806
return -1;
@@ -1005,6 +1006,38 @@ static int auth_krb(http_context &ctx, const char *input, size_t isize,
10051006
}
10061007
#endif
10071008

1009+
static tproc_status htp_auth_spnego(http_context &ctx, const char *past_method)
1010+
{
1011+
bool rq_ntlmssp = strncmp(past_method, "TlRMTVNT", 8) == 0;
1012+
auto the_helper = g_config_file->get_value(rq_ntlmssp ? "ntlmssp_program" : "gss_program");
1013+
1014+
if (strcmp(the_helper, "internal-gss") != 0) {
1015+
auto ret = htp_auth_ntlmssp(ctx, the_helper, past_method,
1016+
ctx.last_gss_output);
1017+
ctx.auth_status = ret <= 0 ? http_status::unauthorized : http_status::ok;
1018+
ctx.auth_method = auth_method::negotiate_b64;
1019+
if (ret <= 0 && ret != -99)
1020+
ntlm_stop(ctx.ntlm_proc);
1021+
} else {
1022+
#ifdef HAVE_GSSAPI
1023+
char decoded[4096];
1024+
size_t decode_len = 0;
1025+
if (decode64(past_method, strlen(past_method), decoded,
1026+
std::size(decoded), &decode_len) != 0)
1027+
return tproc_status::runoff;
1028+
auto ret = auth_krb(ctx, decoded, decode_len, ctx.last_gss_output);
1029+
ctx.auth_status = ret <= 0 ? http_status::unauthorized : http_status::ok;
1030+
ctx.auth_method = auth_method::negotiate;
1031+
#else
1032+
static bool y = false;
1033+
if (!y)
1034+
mlog(LV_DEBUG, "Cannot handle Negotiate request: software built without GSSAPI");
1035+
y = true;
1036+
#endif
1037+
}
1038+
return tproc_status::runoff;
1039+
}
1040+
10081041
/*
10091042
* Implementation notes.
10101043
*
@@ -1055,38 +1088,16 @@ static tproc_status htp_auth(http_context &ctx)
10551088
*p++ = '\0';
10561089
gx_strlcpy(ctx.username, decoded, std::size(ctx.username));
10571090
gx_strlcpy(ctx.password, p, std::size(ctx.password));
1058-
return htp_auth_basic(&ctx);
1059-
} else if (strcasecmp(method, "Negotiate") == 0 &&
1060-
strncmp(past_method, "TlRMTVNT", 8) == 0 &&
1061-
g_config_file->get_ll("http_auth_spnego") &&
1062-
g_config_file->get_ll("http_auth_spnego_ntlmssp")) {
1063-
char decoded[4096];
1064-
size_t decode_len = 0;
1065-
if (decode64(past_method, strlen(past_method), decoded, std::size(decoded), &decode_len) != 0)
1066-
return tproc_status::runoff;
1067-
auto ret = auth_ntlmssp(ctx, past_method, strlen(past_method),
1068-
decoded, decode_len, ctx.last_gss_output);
1069-
ctx.auth_status = ret <= 0 ? http_status::unauthorized : http_status::ok;
1070-
ctx.auth_method = auth_method::negotiate_b64;
1071-
if (ret <= 0 && ret != -99)
1072-
ntlm_stop(ctx.ntlm_proc);
1091+
auto ret = htp_auth_basic(&ctx);
1092+
if (ret != tproc_status::runoff)
1093+
return ret;
10731094
} else if (strcasecmp(method, "Negotiate") == 0 &&
10741095
g_config_file->get_ll("http_auth_spnego")) {
1075-
#ifdef HAVE_GSSAPI
1076-
char decoded[4096];
1077-
size_t decode_len = 0;
1078-
if (decode64(past_method, strlen(past_method), decoded, std::size(decoded), &decode_len) != 0)
1079-
return tproc_status::runoff;
1080-
auto ret = auth_krb(ctx, decoded, decode_len, ctx.last_gss_output);
1081-
ctx.auth_status = ret <= 0 ? http_status::unauthorized : http_status::ok;
1082-
ctx.auth_method = auth_method::negotiate;
1083-
#else
1084-
static bool y = false;
1085-
if (!y)
1086-
mlog(LV_DEBUG, "Cannot handle Negotiate request: software built without GSSAPI");
1087-
y = true;
1088-
#endif
1096+
auto ret = htp_auth_spnego(ctx, past_method);
1097+
if (ret != tproc_status::runoff)
1098+
return ret;
10891099
}
1100+
10901101
if (g_enforce_auth && ctx.auth_status != http_status::ok)
10911102
ctx.auth_status = http_status::unauthorized;
10921103
return tproc_status::runoff;

exch/http/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ static constexpr cfg_directive http_cfg_defaults[] = {
8585
{"context_num", "400", CFG_SIZE},
8686
{"data_file_path", PKGDATADIR "/http:" PKGDATADIR},
8787
{"fastcgi_exec_timeout", "10min", CFG_TIME, "1min"},
88+
{"gss_program", "internal-gss"},
8889
{"http_auth_basic", "1", CFG_BOOL},
8990
{"http_auth_spnego", "0", CFG_BOOL},
90-
{"http_auth_spnego_ntlmssp", "1", CFG_BOOL},
9191
{"http_auth_times", "10", CFG_SIZE, "1"},
9292
{"http_conn_timeout", "3min", CFG_TIME, "30s"},
9393
{"http_debug", "0"},
@@ -108,7 +108,7 @@ static constexpr cfg_directive http_cfg_defaults[] = {
108108
{"listen_port", "http_listen_port", CFG_ALIAS},
109109
{"listen_ssl_port", "http_listen_tls_port", CFG_ALIAS},
110110
{"msrpc_debug", "0"},
111-
{"ntlm_auth", "/usr/bin/ntlm_auth"}, /* part of samba-winbind */
111+
{"ntlmssp_program", "/usr/bin/ntlm_auth --helper-protocol=squid-2.5-ntlmssp"},
112112
{"oxcical_allday_ymd", "1", CFG_BOOL},
113113
{"request_max_mem", "4M", CFG_SIZE, "1M"},
114114
{"running_identity", RUNNING_IDENTITY},

0 commit comments

Comments
 (0)