📄 spnego.c
字号:
continue; } spnego_state->state_position = SPNEGO_FALLBACK; nt_status = gensec_subcontext_start(spnego_state, gensec_security, &spnego_state->sub_sec_security); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } /* select the sub context */ nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, all_ops[i]); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } nt_status = gensec_update(spnego_state->sub_sec_security, out_mem_ctx, in, out); return nt_status; } DEBUG(1, ("Failed to parse SPNEGO request\n")); return NT_STATUS_INVALID_PARAMETER; }/* Parse the netTokenInit, either from the client, to the server, or from the server to the client.*/static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_security, struct spnego_state *spnego_state, TALLOC_CTX *out_mem_ctx, const char **mechType, const DATA_BLOB unwrapped_in, DATA_BLOB *unwrapped_out) { int i; NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; DATA_BLOB null_data_blob = data_blob(NULL,0); const struct gensec_security_ops_wrapper *all_sec = gensec_security_by_oid_list(gensec_security, out_mem_ctx, mechType, GENSEC_OID_SPNEGO); if (spnego_state->state_position == SPNEGO_SERVER_START) { for (i=0; all_sec && all_sec[i].op; i++) { /* optomisitic token */ if (strcmp(all_sec[i].oid, mechType[0]) == 0) { nt_status = gensec_subcontext_start(spnego_state, gensec_security, &spnego_state->sub_sec_security); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } /* select the sub context */ nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, all_sec[i].op); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; break; } nt_status = gensec_update(spnego_state->sub_sec_security, out_mem_ctx, unwrapped_in, unwrapped_out); if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) || NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) { /* Pretend we never started it (lets the first run find some incompatible demand) */ DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse contents: %s\n", spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; break; } spnego_state->neg_oid = all_sec[i].oid; break; } } } /* Having tried any optomisitc token from the client (if we * were the server), if we didn't get anywhere, walk our list * in our preference order */ if (!spnego_state->sub_sec_security) { for (i=0; all_sec && all_sec[i].op; i++) { nt_status = gensec_subcontext_start(spnego_state, gensec_security, &spnego_state->sub_sec_security); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } /* select the sub context */ nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, all_sec[i].op); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; continue; } spnego_state->neg_oid = all_sec[i].oid; /* only get the helping start blob for the first OID */ nt_status = gensec_update(spnego_state->sub_sec_security, out_mem_ctx, null_data_blob, unwrapped_out); /* it is likely that a NULL input token will * not be liked by most server mechs, but if * we are in the client, we want the first * update packet to be able to abort the use * of this mech */ if (spnego_state->state_position != SPNEGO_SERVER_START) { if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) || NT_STATUS_EQUAL(nt_status, NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) { /* Pretend we never started it (lets the first run find some incompatible demand) */ DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed to parse: %s\n", spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; continue; } } break; } } if (spnego_state->sub_sec_security) { /* it is likely that a NULL input token will * not be liked by most server mechs, but this * does the right thing in the CIFS client. * just push us along the merry-go-round * again, and hope for better luck next * time */ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) { *unwrapped_out = data_blob(NULL, 0); nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; } if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("SPNEGO(%s) NEG_TOKEN_INIT failed: %s\n", spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; /* We started the mech correctly, and the * input from the other side was valid. * Return the error (say bad password, invalid * ticket) */ return nt_status; } return nt_status; /* OK, INVALID_PARAMETER ore MORE PROCESSING */ } DEBUG(1, ("SPNEGO: Could not find a suitable mechtype in NEG_TOKEN_INIT\n")); /* we could re-negotiate here, but it would only work * if the client or server lied about what it could * support the first time. Lets keep this code to * reality */ return nt_status;}/** create a negTokenInit * * This is the same packet, no matter if the client or server sends it first, but it is always the first packet*/static NTSTATUS gensec_spnego_create_negTokenInit(struct gensec_security *gensec_security, struct spnego_state *spnego_state, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out) { int i; NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; DATA_BLOB null_data_blob = data_blob(NULL,0); const char **mechTypes = NULL; DATA_BLOB unwrapped_out = data_blob(NULL, 0); const struct gensec_security_ops_wrapper *all_sec; const char *principal = NULL; mechTypes = gensec_security_oids(gensec_security, out_mem_ctx, GENSEC_OID_SPNEGO); all_sec = gensec_security_by_oid_list(gensec_security, out_mem_ctx, mechTypes, GENSEC_OID_SPNEGO); for (i=0; all_sec && all_sec[i].op; i++) { struct spnego_data spnego_out; nt_status = gensec_subcontext_start(spnego_state, gensec_security, &spnego_state->sub_sec_security); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } /* select the sub context */ nt_status = gensec_start_mech_by_ops(spnego_state->sub_sec_security, all_sec[i].op); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; continue; } /* In the client, try and produce the first (optimistic) packet */ if (spnego_state->state_position == SPNEGO_CLIENT_START) { nt_status = gensec_update(spnego_state->sub_sec_security, out_mem_ctx, null_data_blob, &unwrapped_out); if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("SPNEGO(%s) creating NEG_TOKEN_INIT failed: %s\n", spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status))); talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; /* Pretend we never started it (lets the first run find some incompatible demand) */ continue; } } spnego_out.type = SPNEGO_NEG_TOKEN_INIT; /* List the remaining mechs as options */ spnego_out.negTokenInit.mechTypes = gensec_security_oids_from_ops_wrapped(out_mem_ctx, &all_sec[i]); spnego_out.negTokenInit.reqFlags = 0; if (spnego_state->state_position == SPNEGO_SERVER_START) { /* server credentials */ struct cli_credentials *creds = gensec_get_credentials(gensec_security); if (creds) { principal = cli_credentials_get_principal(creds, out_mem_ctx); } } if (principal) { spnego_out.negTokenInit.mechListMIC = data_blob_string_const(principal); } else { spnego_out.negTokenInit.mechListMIC = null_data_blob; } spnego_out.negTokenInit.mechToken = unwrapped_out; if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { DEBUG(1, ("Failed to write NEG_TOKEN_INIT\n")); return NT_STATUS_INVALID_PARAMETER; } /* set next state */ spnego_state->neg_oid = all_sec[i].oid; if (NT_STATUS_IS_OK(nt_status)) { spnego_state->no_response_expected = true; } return NT_STATUS_MORE_PROCESSING_REQUIRED; } talloc_free(spnego_state->sub_sec_security); spnego_state->sub_sec_security = NULL; DEBUG(1, ("Failed to setup SPNEGO negTokenInit request: %s\n", nt_errstr(nt_status))); return NT_STATUS_INVALID_PARAMETER;}/** create a server negTokenTarg * * This is the case, where the client is the first one who sends data*/static NTSTATUS gensec_spnego_server_negTokenTarg(struct gensec_security *gensec_security, struct spnego_state *spnego_state, TALLOC_CTX *out_mem_ctx, NTSTATUS nt_status, const DATA_BLOB unwrapped_out, DATA_BLOB *out) { struct spnego_data spnego_out; DATA_BLOB null_data_blob = data_blob(NULL, 0); /* compose reply */ spnego_out.type = SPNEGO_NEG_TOKEN_TARG; spnego_out.negTokenTarg.responseToken = unwrapped_out; spnego_out.negTokenTarg.mechListMIC = null_data_blob; spnego_out.negTokenTarg.supportedMech = NULL; if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid; spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE; spnego_state->state_position = SPNEGO_SERVER_TARG; } else if (NT_STATUS_IS_OK(nt_status)) { if (unwrapped_out.data) { spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid; } spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED; spnego_state->state_position = SPNEGO_DONE; } else { spnego_out.negTokenTarg.negResult = SPNEGO_REJECT; DEBUG(2, ("SPNEGO login failed: %s\n", nt_errstr(nt_status))); spnego_state->state_position = SPNEGO_DONE; } if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) { DEBUG(1, ("Failed to write SPNEGO reply to NEG_TOKEN_TARG\n")); return NT_STATUS_INVALID_PARAMETER; } spnego_state->expected_packet = SPNEGO_NEG_TOKEN_TARG; return nt_status;}static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, const DATA_BLOB in, DATA_BLOB *out) { struct spnego_state *spnego_state = (struct spnego_state *)gensec_security->private_data; DATA_BLOB null_data_blob = data_blob(NULL, 0); DATA_BLOB unwrapped_out = data_blob(NULL, 0); struct spnego_data spnego_out; struct spnego_data spnego; ssize_t len; *out = data_blob(NULL, 0); if (!out_mem_ctx) { out_mem_ctx = spnego_state; } /* and switch into the state machine */ switch (spnego_state->state_position) { case SPNEGO_FALLBACK: return gensec_update(spnego_state->sub_sec_security,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -