2 Unix SMB/CIFS implementation.
4 dcerpc schannel operations
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "librpc/gen_ndr/ndr_schannel.h"
26 #include "auth/auth.h"
27 #include "auth/gensec/schannel.h"
28 #include "auth/gensec/schannel_state.h"
29 #include "auth/gensec/schannel_proto.h"
30 #include "librpc/rpc/dcerpc.h"
32 static size_t schannel_sig_size(struct gensec_security
*gensec_security
, size_t data_size
)
37 static NTSTATUS
schannel_session_key(struct gensec_security
*gensec_security
,
38 DATA_BLOB
*session_key
)
40 return NT_STATUS_NOT_IMPLEMENTED
;
43 static NTSTATUS
schannel_update(struct gensec_security
*gensec_security
, TALLOC_CTX
*out_mem_ctx
,
44 const DATA_BLOB in
, DATA_BLOB
*out
)
46 struct schannel_state
*state
= gensec_security
->private_data
;
48 struct schannel_bind bind_schannel
;
49 struct schannel_bind_ack bind_schannel_ack
;
50 struct creds_CredentialState
*creds
;
52 const char *workstation
;
54 *out
= data_blob(NULL
, 0);
56 switch (gensec_security
->gensec_role
) {
58 if (state
->state
!= SCHANNEL_STATE_START
) {
59 /* we could parse the bind ack, but we don't know what it is yet */
63 state
->creds
= talloc_reference(state
, cli_credentials_get_netlogon_creds(gensec_security
->credentials
));
65 bind_schannel
.unknown1
= 0;
67 /* to support this we'd need to have access to the full domain name */
68 bind_schannel
.bind_type
= 23;
69 bind_schannel
.u
.info23
.domain
= cli_credentials_get_domain(gensec_security
->credentials
);
70 bind_schannel
.u
.info23
.workstation
= cli_credentials_get_workstation(gensec_security
->credentials
);
71 bind_schannel
.u
.info23
.dnsdomain
= cli_credentials_get_realm(gensec_security
->credentials
);
72 /* w2k3 refuses us if we use the full DNS workstation?
73 why? perhaps because we don't fill in the dNSHostName
74 attribute in the machine account? */
75 bind_schannel
.u
.info23
.dnsworkstation
= cli_credentials_get_workstation(gensec_security
->credentials
);
77 bind_schannel
.bind_type
= 3;
78 bind_schannel
.u
.info3
.domain
= cli_credentials_get_domain(gensec_security
->credentials
);
79 bind_schannel
.u
.info3
.workstation
= cli_credentials_get_workstation(gensec_security
->credentials
);
82 status
= ndr_push_struct_blob(out
, out_mem_ctx
, &bind_schannel
,
83 (ndr_push_flags_fn_t
)ndr_push_schannel_bind
);
84 if (!NT_STATUS_IS_OK(status
)) {
85 DEBUG(3, ("Could not create schannel bind: %s\n",
90 state
->state
= SCHANNEL_STATE_UPDATE_1
;
92 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
95 if (state
->state
!= SCHANNEL_STATE_START
) {
96 /* no third leg on this protocol */
97 return NT_STATUS_INVALID_PARAMETER
;
100 /* parse the schannel startup blob */
101 status
= ndr_pull_struct_blob(&in
, out_mem_ctx
, &bind_schannel
,
102 (ndr_pull_flags_fn_t
)ndr_pull_schannel_bind
);
103 if (!NT_STATUS_IS_OK(status
)) {
107 if (bind_schannel
.bind_type
== 23) {
108 workstation
= bind_schannel
.u
.info23
.workstation
;
109 domain
= bind_schannel
.u
.info23
.domain
;
111 workstation
= bind_schannel
.u
.info3
.workstation
;
112 domain
= bind_schannel
.u
.info3
.domain
;
115 /* pull the session key for this client */
116 status
= schannel_fetch_session_key(out_mem_ctx
, workstation
,
118 if (!NT_STATUS_IS_OK(status
)) {
119 DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
120 workstation
, nt_errstr(status
)));
124 state
->creds
= talloc_reference(state
, creds
);
126 bind_schannel_ack
.unknown1
= 1;
127 bind_schannel_ack
.unknown2
= 0;
128 bind_schannel_ack
.unknown3
= 0x6c0000;
130 status
= ndr_push_struct_blob(out
, out_mem_ctx
, &bind_schannel_ack
,
131 (ndr_push_flags_fn_t
)ndr_push_schannel_bind_ack
);
132 if (!NT_STATUS_IS_OK(status
)) {
133 DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
134 workstation
, nt_errstr(status
)));
138 state
->state
= SCHANNEL_STATE_UPDATE_1
;
142 return NT_STATUS_INVALID_PARAMETER
;
146 * Return the struct creds_CredentialState.
148 * Make sure not to call this unless gensec is using schannel...
151 /* TODO: make this non-public */
152 _PUBLIC_ NTSTATUS
dcerpc_schannel_creds(struct gensec_security
*gensec_security
,
154 struct creds_CredentialState
**creds
)
156 struct schannel_state
*state
= talloc_get_type(gensec_security
->private_data
, struct schannel_state
);
158 *creds
= talloc_reference(mem_ctx
, state
->creds
);
160 return NT_STATUS_NO_MEMORY
;
167 * Returns anonymous credentials for schannel, matching Win2k3.
171 static NTSTATUS
schannel_session_info(struct gensec_security
*gensec_security
,
172 struct auth_session_info
**_session_info
)
174 struct schannel_state
*state
= talloc_get_type(gensec_security
->private_data
, struct schannel_state
);
175 return auth_anonymous_session_info(state
, _session_info
);
178 static NTSTATUS
schannel_start(struct gensec_security
*gensec_security
)
180 struct schannel_state
*state
;
182 state
= talloc(gensec_security
, struct schannel_state
);
184 return NT_STATUS_NO_MEMORY
;
187 state
->state
= SCHANNEL_STATE_START
;
189 gensec_security
->private_data
= state
;
194 static NTSTATUS
schannel_server_start(struct gensec_security
*gensec_security
)
197 struct schannel_state
*state
;
199 status
= schannel_start(gensec_security
);
200 if (!NT_STATUS_IS_OK(status
)) {
204 state
= gensec_security
->private_data
;
205 state
->initiator
= False
;
210 static NTSTATUS
schannel_client_start(struct gensec_security
*gensec_security
)
213 struct schannel_state
*state
;
215 status
= schannel_start(gensec_security
);
216 if (!NT_STATUS_IS_OK(status
)) {
220 state
= gensec_security
->private_data
;
221 state
->initiator
= True
;
227 static BOOL
schannel_have_feature(struct gensec_security
*gensec_security
,
230 if (feature
& (GENSEC_FEATURE_SIGN
|
231 GENSEC_FEATURE_SEAL
)) {
234 if (feature
& GENSEC_FEATURE_DCE_STYLE
) {
237 if (feature
& GENSEC_FEATURE_ASYNC_REPLIES
) {
244 static const struct gensec_security_ops gensec_schannel_security_ops
= {
246 .auth_type
= DCERPC_AUTH_TYPE_SCHANNEL
,
247 .client_start
= schannel_client_start
,
248 .server_start
= schannel_server_start
,
249 .update
= schannel_update
,
250 .seal_packet
= schannel_seal_packet
,
251 .sign_packet
= schannel_sign_packet
,
252 .check_packet
= schannel_check_packet
,
253 .unseal_packet
= schannel_unseal_packet
,
254 .session_key
= schannel_session_key
,
255 .session_info
= schannel_session_info
,
256 .sig_size
= schannel_sig_size
,
257 .have_feature
= schannel_have_feature
,
259 .order
= GENSEC_SCHANNEL
262 NTSTATUS
gensec_schannel_init(void)
265 ret
= gensec_register(&gensec_schannel_security_ops
);
266 if (!NT_STATUS_IS_OK(ret
)) {
267 DEBUG(0,("Failed to register '%s' gensec backend!\n",
268 gensec_schannel_security_ops
.name
));