root/source4/auth/gensec/schannel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. schannel_sig_size
  2. schannel_session_key
  3. schannel_update
  4. dcerpc_schannel_creds
  5. schannel_session_info
  6. schannel_start
  7. schannel_server_start
  8. schannel_client_start
  9. schannel_have_feature
  10. gensec_schannel_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    dcerpc schannel operations
   5 
   6    Copyright (C) Andrew Tridgell 2004
   7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
   8 
   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 3 of the License, or
  12    (at your option) any later version.
  13    
  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.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "librpc/gen_ndr/ndr_schannel.h"
  25 #include "auth/auth.h"
  26 #include "auth/credentials/credentials.h"
  27 #include "auth/gensec/gensec.h"
  28 #include "auth/gensec/gensec_proto.h"
  29 #include "auth/gensec/schannel.h"
  30 #include "auth/gensec/schannel_state.h"
  31 #include "auth/gensec/schannel_proto.h"
  32 #include "librpc/rpc/dcerpc.h"
  33 #include "param/param.h"
  34 #include "auth/session_proto.h"
  35 
  36 static size_t schannel_sig_size(struct gensec_security *gensec_security, size_t data_size)
     /* [<][>][^][v][top][bottom][index][help] */
  37 {
  38         return 32;
  39 }
  40 
  41 static NTSTATUS schannel_session_key(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
  42                                             DATA_BLOB *session_key)
  43 {
  44         return NT_STATUS_NOT_IMPLEMENTED;
  45 }
  46 
  47 static NTSTATUS schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
  48                                        const DATA_BLOB in, DATA_BLOB *out) 
  49 {
  50         struct schannel_state *state = (struct schannel_state *)gensec_security->private_data;
  51         NTSTATUS status;
  52         enum ndr_err_code ndr_err;
  53         struct schannel_bind bind_schannel;
  54         struct schannel_bind_ack bind_schannel_ack;
  55         struct creds_CredentialState *creds;
  56 
  57         const char *workstation;
  58         const char *domain;
  59         *out = data_blob(NULL, 0);
  60 
  61         switch (gensec_security->gensec_role) {
  62         case GENSEC_CLIENT:
  63                 if (state->state != SCHANNEL_STATE_START) {
  64                         /* we could parse the bind ack, but we don't know what it is yet */
  65                         return NT_STATUS_OK;
  66                 }
  67 
  68                 state->creds = talloc_reference(state, cli_credentials_get_netlogon_creds(gensec_security->credentials));
  69 
  70                 bind_schannel.unknown1 = 0;
  71 #if 0
  72                 /* to support this we'd need to have access to the full domain name */
  73                 bind_schannel.bind_type = 23;
  74                 bind_schannel.u.info23.domain = cli_credentials_get_domain(gensec_security->credentials);
  75                 bind_schannel.u.info23.workstation = cli_credentials_get_workstation(gensec_security->credentials);
  76                 bind_schannel.u.info23.dnsdomain = cli_credentials_get_realm(gensec_security->credentials);
  77                 /* w2k3 refuses us if we use the full DNS workstation?
  78                  why? perhaps because we don't fill in the dNSHostName
  79                  attribute in the machine account? */
  80                 bind_schannel.u.info23.dnsworkstation = cli_credentials_get_workstation(gensec_security->credentials);
  81 #else
  82                 bind_schannel.bind_type = 3;
  83                 bind_schannel.u.info3.domain = cli_credentials_get_domain(gensec_security->credentials);
  84                 bind_schannel.u.info3.workstation = cli_credentials_get_workstation(gensec_security->credentials);
  85 #endif
  86                 
  87                 ndr_err = ndr_push_struct_blob(out, out_mem_ctx, 
  88                                                gensec_security->settings->iconv_convenience, &bind_schannel,
  89                                                (ndr_push_flags_fn_t)ndr_push_schannel_bind);
  90                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  91                         status = ndr_map_error2ntstatus(ndr_err);
  92                         DEBUG(3, ("Could not create schannel bind: %s\n",
  93                                   nt_errstr(status)));
  94                         return status;
  95                 }
  96                 
  97                 state->state = SCHANNEL_STATE_UPDATE_1;
  98 
  99                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
 100         case GENSEC_SERVER:
 101                 
 102                 if (state->state != SCHANNEL_STATE_START) {
 103                         /* no third leg on this protocol */
 104                         return NT_STATUS_INVALID_PARAMETER;
 105                 }
 106                 
 107                 /* parse the schannel startup blob */
 108                 ndr_err = ndr_pull_struct_blob(&in, out_mem_ctx,
 109                         gensec_security->settings->iconv_convenience,
 110                         &bind_schannel, 
 111                         (ndr_pull_flags_fn_t)ndr_pull_schannel_bind);
 112                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 113                         status = ndr_map_error2ntstatus(ndr_err);
 114                         DEBUG(3, ("Could not parse incoming schannel bind: %s\n",
 115                                   nt_errstr(status)));
 116                         return status;
 117                 }
 118                 
 119                 if (bind_schannel.bind_type == 23) {
 120                         workstation = bind_schannel.u.info23.workstation;
 121                         domain = bind_schannel.u.info23.domain;
 122                 } else {
 123                         workstation = bind_schannel.u.info3.workstation;
 124                         domain = bind_schannel.u.info3.domain;
 125                 }
 126                 
 127                 /* pull the session key for this client */
 128                 status = schannel_fetch_session_key(out_mem_ctx, gensec_security->event_ctx, 
 129                                                     gensec_security->settings->lp_ctx, workstation, 
 130                                                     domain, &creds);
 131                 if (!NT_STATUS_IS_OK(status)) {
 132                         DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
 133                                   workstation, nt_errstr(status)));
 134                         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
 135                                 return NT_STATUS_LOGON_FAILURE;
 136                         }
 137                         return status;
 138                 }
 139 
 140                 state->creds = talloc_reference(state, creds);
 141 
 142                 bind_schannel_ack.unknown1 = 1;
 143                 bind_schannel_ack.unknown2 = 0;
 144                 bind_schannel_ack.unknown3 = 0x6c0000;
 145                 
 146                 ndr_err = ndr_push_struct_blob(out, out_mem_ctx, 
 147                                                gensec_security->settings->iconv_convenience, &bind_schannel_ack,
 148                                                (ndr_push_flags_fn_t)ndr_push_schannel_bind_ack);
 149                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 150                         status = ndr_map_error2ntstatus(ndr_err);
 151                         DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
 152                                   workstation, nt_errstr(status)));
 153                         return status;
 154                 }
 155 
 156                 state->state = SCHANNEL_STATE_UPDATE_1;
 157 
 158                 return NT_STATUS_OK;
 159         }
 160         return NT_STATUS_INVALID_PARAMETER;
 161 }
 162 
 163 /**
 164  * Return the struct creds_CredentialState.
 165  *
 166  * Make sure not to call this unless gensec is using schannel...
 167  */
 168 
 169 /* TODO: make this non-public */
 170 _PUBLIC_ NTSTATUS dcerpc_schannel_creds(struct gensec_security *gensec_security,
     /* [<][>][^][v][top][bottom][index][help] */
 171                                TALLOC_CTX *mem_ctx,
 172                                struct creds_CredentialState **creds)
 173 { 
 174         struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);
 175 
 176         *creds = talloc_reference(mem_ctx, state->creds);
 177         if (!*creds) {
 178                 return NT_STATUS_NO_MEMORY;
 179         }
 180         return NT_STATUS_OK;
 181 }
 182                 
 183 
 184 /** 
 185  * Returns anonymous credentials for schannel, matching Win2k3.
 186  *
 187  */
 188 
 189 static NTSTATUS schannel_session_info(struct gensec_security *gensec_security,
     /* [<][>][^][v][top][bottom][index][help] */
 190                                          struct auth_session_info **_session_info) 
 191 {
 192         struct schannel_state *state = talloc_get_type(gensec_security->private_data, struct schannel_state);
 193         return auth_anonymous_session_info(state, gensec_security->event_ctx, gensec_security->settings->lp_ctx, _session_info);
 194 }
 195 
 196 static NTSTATUS schannel_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
 197 {
 198         struct schannel_state *state;
 199 
 200         state = talloc(gensec_security, struct schannel_state);
 201         if (!state) {
 202                 return NT_STATUS_NO_MEMORY;
 203         }
 204 
 205         state->state = SCHANNEL_STATE_START;
 206         state->seq_num = 0;
 207         gensec_security->private_data = state;
 208 
 209         return NT_STATUS_OK;
 210 }
 211 
 212 static NTSTATUS schannel_server_start(struct gensec_security *gensec_security) 
     /* [<][>][^][v][top][bottom][index][help] */
 213 {
 214         NTSTATUS status;
 215         struct schannel_state *state;
 216 
 217         status = schannel_start(gensec_security);
 218         if (!NT_STATUS_IS_OK(status)) {
 219                 return status;
 220         }
 221 
 222         state = (struct schannel_state *)gensec_security->private_data;
 223         state->initiator = false;
 224                 
 225         return NT_STATUS_OK;
 226 }
 227 
 228 static NTSTATUS schannel_client_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
 229 {
 230         NTSTATUS status;
 231         struct schannel_state *state;
 232 
 233         status = schannel_start(gensec_security);
 234         if (!NT_STATUS_IS_OK(status)) {
 235                 return status;
 236         }
 237 
 238         state = (struct schannel_state *)gensec_security->private_data;
 239         state->initiator = true;
 240                 
 241         return NT_STATUS_OK;
 242 }
 243 
 244 
 245 static bool schannel_have_feature(struct gensec_security *gensec_security,
     /* [<][>][^][v][top][bottom][index][help] */
 246                                          uint32_t feature)
 247 {
 248         if (feature & (GENSEC_FEATURE_SIGN | 
 249                        GENSEC_FEATURE_SEAL)) {
 250                 return true;
 251         }
 252         if (feature & GENSEC_FEATURE_DCE_STYLE) {
 253                 return true;
 254         }
 255         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
 256                 return true;
 257         }
 258         return false;
 259 }
 260 
 261 
 262 static const struct gensec_security_ops gensec_schannel_security_ops = {
 263         .name           = "schannel",
 264         .auth_type      = DCERPC_AUTH_TYPE_SCHANNEL,
 265         .client_start   = schannel_client_start,
 266         .server_start   = schannel_server_start,
 267         .update         = schannel_update,
 268         .seal_packet    = schannel_seal_packet,
 269         .sign_packet    = schannel_sign_packet,
 270         .check_packet   = schannel_check_packet,
 271         .unseal_packet  = schannel_unseal_packet,
 272         .session_key    = schannel_session_key,
 273         .session_info   = schannel_session_info,
 274         .sig_size       = schannel_sig_size,
 275         .have_feature   = schannel_have_feature,
 276         .enabled        = true,
 277         .priority       = GENSEC_SCHANNEL
 278 };
 279 
 280 _PUBLIC_ NTSTATUS gensec_schannel_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 281 {
 282         NTSTATUS ret;
 283         ret = gensec_register(&gensec_schannel_security_ops);
 284         if (!NT_STATUS_IS_OK(ret)) {
 285                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
 286                         gensec_schannel_security_ops.name));
 287                 return ret;
 288         }
 289 
 290         return ret;
 291 }

/* [<][>][^][v][top][bottom][index][help] */