3 * DCERPC Server functions
4 * Copyright (C) Simo Sorce 2010.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "../libcli/auth/spnego.h"
22 #include "../lib/tsocket/tsocket.h"
23 #include "dcesrv_auth_generic.h"
24 #include "dcesrv_gssapi.h"
25 #include "dcesrv_spnego.h"
26 #include "auth/gensec/gensec.h"
28 static NTSTATUS
spnego_init_server(TALLOC_CTX
*mem_ctx
,
29 bool do_sign
, bool do_seal
,
31 const struct tsocket_address
*remote_address
,
32 struct spnego_context
**spnego_ctx
)
34 struct spnego_context
*sp_ctx
= NULL
;
36 sp_ctx
= talloc_zero(mem_ctx
, struct spnego_context
);
38 return NT_STATUS_NO_MEMORY
;
41 sp_ctx
->remote_address
= tsocket_address_copy(remote_address
, sp_ctx
);
42 if (sp_ctx
->remote_address
== NULL
) {
43 return NT_STATUS_NO_MEMORY
;
46 sp_ctx
->do_sign
= do_sign
;
47 sp_ctx
->do_seal
= do_seal
;
48 sp_ctx
->is_dcerpc
= is_dcerpc
;
54 static NTSTATUS
spnego_server_mech_init(struct spnego_context
*sp_ctx
,
58 struct gensec_security
*gensec_security
;
62 switch (sp_ctx
->mech
) {
64 oid
= GENSEC_OID_KERBEROS5
;
67 oid
= GENSEC_OID_NTLMSSP
;
70 DEBUG(3, ("No known mechanisms available\n"));
71 return NT_STATUS_INVALID_PARAMETER
;
74 status
= auth_generic_server_start(sp_ctx
,
81 sp_ctx
->remote_address
,
83 if (!NT_STATUS_IS_OK(status
)) {
84 DEBUG(0, ("Failed to init ntlmssp server "
85 "(%s)\n", nt_errstr(status
)));
89 sp_ctx
->mech_ctx
.gensec_security
= gensec_security
;
94 NTSTATUS
spnego_server_step(struct spnego_context
*sp_ctx
,
97 DATA_BLOB
*spnego_out
)
99 DATA_BLOB token_in
= data_blob_null
;
100 DATA_BLOB token_out
= data_blob_null
;
101 DATA_BLOB signature
= data_blob_null
;
102 DATA_BLOB MICblob
= data_blob_null
;
103 struct spnego_data sp_in
;
108 len_in
= spnego_read_data(mem_ctx
, *spnego_in
, &sp_in
);
110 DEBUG(1, (__location__
": invalid SPNEGO blob.\n"));
111 dump_data(10, spnego_in
->data
, spnego_in
->length
);
112 status
= NT_STATUS_INVALID_PARAMETER
;
113 sp_ctx
->state
= SPNEGO_CONV_AUTH_DONE
;
116 if (sp_in
.type
!= SPNEGO_NEG_TOKEN_TARG
) {
117 status
= NT_STATUS_INVALID_PARAMETER
;
120 token_in
= sp_in
.negTokenTarg
.responseToken
;
121 signature
= sp_in
.negTokenTarg
.mechListMIC
;
123 switch (sp_ctx
->state
) {
124 case SPNEGO_CONV_NEGO
:
125 /* still to initialize */
126 status
= spnego_server_mech_init(sp_ctx
,
129 if (!NT_STATUS_IS_OK(status
)) {
132 /* server always need at least one reply from client */
133 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
134 sp_ctx
->state
= SPNEGO_CONV_AUTH_MORE
;
137 case SPNEGO_CONV_AUTH_MORE
:
139 status
= auth_generic_server_step(
140 sp_ctx
->mech_ctx
.gensec_security
,
141 mem_ctx
, &token_in
, &token_out
);
144 case SPNEGO_CONV_AUTH_DONE
:
145 /* we are already done, can't step further */
146 /* fall thorugh and return error */
149 return NT_STATUS_INVALID_PARAMETER
;
152 if (NT_STATUS_IS_OK(status
) && signature
.length
!= 0) {
153 /* last packet and requires signature check */
154 ret
= spnego_mech_list_blob(talloc_tos(),
155 sp_ctx
->oid_list
, &MICblob
);
157 status
= spnego_sigcheck(talloc_tos(), sp_ctx
,
161 status
= NT_STATUS_UNSUCCESSFUL
;
164 if (NT_STATUS_IS_OK(status
) && signature
.length
!= 0) {
165 /* if signature was good, sign our own packet too */
166 status
= spnego_sign(talloc_tos(), sp_ctx
,
167 &MICblob
, &MICblob
, &signature
);
171 *spnego_out
= spnego_gen_auth_response_and_mic(mem_ctx
, status
,
175 if (!spnego_out
->data
) {
176 DEBUG(1, ("SPNEGO wrapping failed!\n"));
177 status
= NT_STATUS_UNSUCCESSFUL
;
180 if (NT_STATUS_IS_OK(status
) ||
181 !NT_STATUS_EQUAL(status
,
182 NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
183 sp_ctx
->state
= SPNEGO_CONV_AUTH_DONE
;
186 data_blob_free(&token_in
);
187 data_blob_free(&token_out
);
191 NTSTATUS
spnego_server_auth_start(TALLOC_CTX
*mem_ctx
,
195 DATA_BLOB
*spnego_in
,
196 DATA_BLOB
*spnego_out
,
197 const struct tsocket_address
*remote_address
,
198 struct spnego_context
**spnego_ctx
)
200 struct spnego_context
*sp_ctx
;
201 DATA_BLOB token_in
= data_blob_null
;
202 DATA_BLOB token_out
= data_blob_null
;
207 if (!spnego_in
->length
) {
208 return NT_STATUS_INVALID_PARAMETER
;
211 status
= spnego_init_server(mem_ctx
,
217 if (!NT_STATUS_IS_OK(status
)) {
221 ret
= spnego_parse_negTokenInit(sp_ctx
, *spnego_in
,
222 sp_ctx
->oid_list
, NULL
, &token_in
);
223 if (!ret
|| sp_ctx
->oid_list
[0] == NULL
) {
224 DEBUG(3, ("Invalid SPNEGO message\n"));
225 status
= NT_STATUS_INVALID_PARAMETER
;
229 /* try for krb auth first */
230 for (i
= 0; sp_ctx
->oid_list
[i
] && sp_ctx
->mech
== SPNEGO_NONE
; i
++) {
231 if (strcmp(OID_KERBEROS5
, sp_ctx
->oid_list
[i
]) == 0 ||
232 strcmp(OID_KERBEROS5_OLD
, sp_ctx
->oid_list
[i
]) == 0) {
234 if (lp_security() == SEC_ADS
|| USE_KERBEROS_KEYTAB
) {
235 sp_ctx
->mech
= SPNEGO_KRB5
;
236 sp_ctx
->mech_oid
= sp_ctx
->oid_list
[i
];
241 /* if auth type still undetermined, try for NTLMSSP */
242 for (i
= 0; sp_ctx
->oid_list
[i
] && sp_ctx
->mech
== SPNEGO_NONE
; i
++) {
243 if (strcmp(OID_NTLMSSP
, sp_ctx
->oid_list
[i
]) == 0) {
244 sp_ctx
->mech
= SPNEGO_NTLMSSP
;
245 sp_ctx
->mech_oid
= sp_ctx
->oid_list
[i
];
249 if (!sp_ctx
->mech_oid
) {
250 DEBUG(3, ("No known mechanisms available\n"));
251 status
= NT_STATUS_INVALID_PARAMETER
;
255 if (DEBUGLEVEL
>= 10) {
256 DEBUG(10, ("Client Provided OIDs:\n"));
257 for (i
= 0; sp_ctx
->oid_list
[i
]; i
++) {
258 DEBUG(10, (" %d: %s\n", i
, sp_ctx
->oid_list
[i
]));
260 DEBUG(10, ("Chosen OID: %s\n", sp_ctx
->mech_oid
));
263 /* If it is not the first OID, then token_in is not valid for the
265 if (sp_ctx
->mech_oid
!= sp_ctx
->oid_list
[0]) {
266 /* request more and send back empty token */
267 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
268 sp_ctx
->state
= SPNEGO_CONV_NEGO
;
272 status
= spnego_server_mech_init(sp_ctx
, &token_in
, &token_out
);
273 if (!NT_STATUS_IS_OK(status
)) {
277 DEBUG(10, ("SPNEGO(%d) auth started\n", sp_ctx
->mech
));
279 /* server always need at least one reply from client */
280 status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
281 sp_ctx
->state
= SPNEGO_CONV_AUTH_MORE
;
284 *spnego_out
= spnego_gen_auth_response(mem_ctx
, &token_out
,
285 status
, sp_ctx
->mech_oid
);
286 if (!spnego_out
->data
) {
287 status
= NT_STATUS_INVALID_PARAMETER
;
290 status
= NT_STATUS_OK
;
291 *spnego_ctx
= sp_ctx
;
294 data_blob_free(&token_in
);
295 data_blob_free(&token_out
);