_PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred) { if (cred->bind_dn) { return true; } /* * If we forced the mech we clearly want authentication. E.g. to use * SASL/EXTERNAL which has no credentials. */ if (cred->forced_sasl_mech) { return true; } if (cli_credentials_is_anonymous(cred)){ return false; } if (cred->principal_obtained >= CRED_SPECIFIED) { return true; } if (cred->username_obtained >= CRED_SPECIFIED) { return true; } if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { return true; } return false; }
/* connect to the sam database */ NTSTATUS ldapsrv_backend_Init(struct ldapsrv_connection *conn) { conn->ldb = ldb_wrap_connect(conn, lp_sam_url(), conn->session_info, NULL, conn->global_catalog ? LDB_FLG_RDONLY : 0, NULL); if (conn->ldb == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } if (conn->server_credentials) { char **sasl_mechs = NULL; struct gensec_security_ops **backends = gensec_security_all(); enum credentials_use_kerberos use_kerberos = cli_credentials_get_kerberos_state(conn->server_credentials); struct gensec_security_ops **ops = gensec_use_kerberos_mechs(conn, backends, use_kerberos); int i, j = 0; for (i = 0; ops && ops[i]; i++) { if (ops[i]->sasl_name && ops[i]->server_start) { char *sasl_name = talloc_strdup(conn, ops[i]->sasl_name); if (!sasl_name) { return NT_STATUS_NO_MEMORY; } sasl_mechs = talloc_realloc(conn, sasl_mechs, char *, j + 2); if (!sasl_mechs) { return NT_STATUS_NO_MEMORY; } sasl_mechs[j] = sasl_name; talloc_steal(sasl_mechs, sasl_name); sasl_mechs[j+1] = NULL; j++; } }
/** * Guess defaults for credentials from environment variables, * and from the configuration file * * @param cred Credentials structure to fill in */ _PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred, struct loadparm_context *lp_ctx) { char *p; const char *error_string; if (lp_ctx != NULL) { cli_credentials_set_conf(cred, lp_ctx); } if (getenv("LOGNAME")) { cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV); } if (getenv("USER")) { cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV); if ((p = strchr_m(getenv("USER"),'%'))) { memset(p,0,strlen(cred->password)); } } if (getenv("PASSWD")) { cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV); } if (getenv("PASSWD_FD")) { cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), CRED_GUESS_FILE); } p = getenv("PASSWD_FILE"); if (p && p[0]) { cli_credentials_parse_password_file(cred, p, CRED_GUESS_FILE); } if (cli_credentials_get_kerberos_state(cred) != CRED_DONT_USE_KERBEROS) { cli_credentials_set_ccache(cred, lp_ctx, NULL, CRED_GUESS_FILE, &error_string); } }
static bool test_session_expire1(struct torture_context *tctx) { NTSTATUS status; bool ret = false; struct smbcli_options options; const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = cmdline_credentials; struct smb2_tree *tree = NULL; enum credentials_use_kerberos use_kerberos; char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; union smb_fileinfo qfinfo; size_t i; use_kerberos = cli_credentials_get_kerberos_state(credentials); if (use_kerberos != CRED_MUST_USE_KERBEROS) { torture_warning(tctx, "smb2.session.expire1 requires -k yes!"); torture_skip(tctx, "smb2.session.expire1 requires -k yes!"); } torture_assert_int_equal(tctx, use_kerberos, CRED_MUST_USE_KERBEROS, "please use -k yes"); lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=4"); lpcfg_smbcli_options(tctx->lp_ctx, &options); status = smb2_connect(tctx, host, lpcfg_smb_ports(tctx->lp_ctx), share, lpcfg_resolve_context(tctx->lp_ctx), credentials, &tree, tctx->ev, &options, lpcfg_socket_options(tctx->lp_ctx), lpcfg_gensec_settings(tctx, tctx->lp_ctx) ); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_connect failed"); /* Add some random component to the file name. */ snprintf(fname, 256, "session_expire1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, tctx, &io1); CHECK_STATUS(status, NT_STATUS_OK); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b")); /* get the security descriptor */ ZERO_STRUCT(qfinfo); qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; qfinfo.access_information.in.file.handle = _h1; for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); torture_comment(tctx, "sleep 5 seconds\n"); smb_msleep(5*1000); torture_comment(tctx, "query info => EXPIRED\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_NETWORK_SESSION_EXPIRED); /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); torture_comment(tctx, "reauth => OK\n"); status = smb2_session_setup_spnego(tree->session, credentials, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_OK); } ZERO_STRUCT(qfinfo.access_information.out); status = smb2_getinfo_file(tree, tctx, &qfinfo); CHECK_STATUS(status, NT_STATUS_OK); ret = true; done: if (h1 != NULL) { smb2_util_close(tree, *h1); } talloc_free(tree); lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=0"); return ret; }
/** * do reauth with wrong credentials, * hence triggering the error path in reauth. * The invalid reauth deletes the session. */ bool test_session_reauth6(struct torture_context *tctx, struct smb2_tree *tree) { NTSTATUS status; TALLOC_CTX *mem_ctx = talloc_new(tctx); char fname[256]; struct smb2_handle _h1; struct smb2_handle *h1 = NULL; struct smb2_create io1; bool ret = true; char *corrupted_password; struct cli_credentials *broken_creds; bool ok; bool encrypted; NTSTATUS expected; enum credentials_use_kerberos krb_state; krb_state = cli_credentials_get_kerberos_state(cmdline_credentials); if (krb_state == CRED_MUST_USE_KERBEROS) { torture_skip(tctx, "Can't test failing session setup with kerberos."); } encrypted = smb2cli_tcon_is_encryption_on(tree->smbXcli); /* Add some random component to the file name. */ snprintf(fname, 256, "session_reauth1_%s.dat", generate_random_str(tctx, 8)); smb2_util_unlink(tree, fname); smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); io1.in.create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE; status = smb2_create(tree, mem_ctx, &io1); CHECK_STATUS(status, NT_STATUS_OK); _h1 = io1.out.file.handle; h1 = &_h1; CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b")); /* * reauthentication with invalid credentials: */ broken_creds = cli_credentials_shallow_copy(mem_ctx, cmdline_credentials); torture_assert(tctx, (broken_creds != NULL), "talloc error"); corrupted_password = talloc_asprintf(mem_ctx, "%s%s", cli_credentials_get_password(broken_creds), "corrupt"); torture_assert(tctx, (corrupted_password != NULL), "talloc error"); ok = cli_credentials_set_password(broken_creds, corrupted_password, CRED_SPECIFIED); CHECK_VAL(ok, true); status = smb2_session_setup_spnego(tree->session, broken_creds, 0 /* previous_session_id */); CHECK_STATUS(status, NT_STATUS_LOGON_FAILURE); torture_comment(tctx, "did failed reauth\n"); /* * now verify that the invalid session reauth has closed our session */ if (encrypted) { expected = NT_STATUS_CONNECTION_DISCONNECTED; } else { expected = NT_STATUS_USER_SESSION_DELETED; } smb2_oplock_create_share(&io1, fname, smb2_util_share_access(""), smb2_util_oplock_level("b")); status = smb2_create(tree, mem_ctx, &io1); CHECK_STATUS(status, expected); done: if (h1 != NULL) { smb2_util_close(tree, *h1); } smb2_util_unlink(tree, fname); talloc_free(tree); talloc_free(mem_ctx); return ret; }
_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, struct gssapi_creds_container **_gcc, const char **error_string) { int ret = 0; OM_uint32 maj_stat, min_stat; struct gssapi_creds_container *gcc; struct ccache_container *ccache; #ifdef SAMBA4_USES_HEIMDAL gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; #endif krb5_enctype *etypes = NULL; if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && cred->client_gss_creds_obtained > CRED_UNINITIALISED) { bool expired = false; OM_uint32 lifetime = 0; gss_cred_usage_t usage = 0; maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds, NULL, &lifetime, &usage, NULL); if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) { DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred))); expired = true; } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) { DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime)); expired = true; } else if (maj_stat != GSS_S_COMPLETE) { *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n", gssapi_error_string(cred, maj_stat, min_stat, NULL)); return EINVAL; } if (expired) { cli_credentials_unconditionally_invalidate_client_gss_creds(cred); } else { DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n", cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); *_gcc = cred->client_gss_creds; return 0; } } ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, &ccache, error_string); if (ret) { if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string)); } else { DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string)); } return ret; } gcc = talloc(cred, struct gssapi_creds_container); if (!gcc) { (*error_string) = error_message(ENOMEM); return ENOMEM; } maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, &gcc->creds); if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) { /* This CCACHE is no good. Ensure we don't use it again */ cli_credentials_unconditionally_invalidate_ccache(cred); /* Now try again to get a ccache */ ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, &ccache, error_string); if (ret) { DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret))); return ret; } maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, &gcc->creds); } if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret)); return ret; } /* * transfer the enctypes from the smb_krb5_context to the gssapi layer * * We use 'our' smb_krb5_context to do the AS-REQ and it is possible * to configure the enctypes via the krb5.conf. * * And the gss_init_sec_context() creates it's own krb5_context and * the TGS-REQ had all enctypes in it and only the ones configured * and used for the AS-REQ, so it wasn't possible to disable the usage * of AES keys. */ min_stat = get_kerberos_allowed_etypes(ccache->smb_krb5_context->krb5_context, &etypes); if (min_stat == 0) { OM_uint32 num_ktypes; for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++); maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds, num_ktypes, (int32_t *) etypes); SAFE_FREE(etypes); if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret)); return ret; } } #ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */ /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */ maj_stat = gss_set_cred_option(&min_stat, &gcc->creds, GSS_KRB5_CRED_NO_CI_FLAGS_X, &empty_buffer); if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret)); return ret; } #endif cred->client_gss_creds_obtained = cred->ccache_obtained; talloc_set_destructor(gcc, free_gssapi_creds); cred->client_gss_creds = gcc; *_gcc = gcc; return 0; }
static PyObject *py_creds_get_kerberos_state(PyObject *self, PyObject *unused) { int state = cli_credentials_get_kerberos_state(PyCredentials_AsCliCredentials(self)); return PyInt_FromLong(state); }
static bool test_session_expire1(struct torture_context *tctx) { NTSTATUS status; bool ret = false; struct smbcli_options options; struct smbcli_session_options session_options; const char *host = torture_setting_string(tctx, "host", NULL); const char *share = torture_setting_string(tctx, "share", NULL); struct cli_credentials *credentials = cmdline_credentials; struct smbcli_state *cli = NULL; enum credentials_use_kerberos use_kerberos; char fname[256]; union smb_fileinfo qfinfo; uint16_t vuid; uint16_t fnum = 0; struct smb_composite_sesssetup io_sesssetup; size_t i; use_kerberos = cli_credentials_get_kerberos_state(credentials); if (use_kerberos != CRED_MUST_USE_KERBEROS) { torture_warning(tctx, "smb2.session.expire1 requires -k yes!"); torture_skip(tctx, "smb2.session.expire1 requires -k yes!"); } torture_assert_int_equal(tctx, use_kerberos, CRED_MUST_USE_KERBEROS, "please use -k yes"); lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=4"); lpcfg_smbcli_options(tctx->lp_ctx, &options); lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options); status = smbcli_full_connection(tctx, &cli, host, lpcfg_smb_ports(tctx->lp_ctx), share, NULL, lpcfg_socket_options(tctx->lp_ctx), credentials, lpcfg_resolve_context(tctx->lp_ctx), tctx->ev, &options, &session_options, lpcfg_gensec_settings(tctx, tctx->lp_ctx)); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smbcli_full_connection failed"); vuid = cli->session->vuid; /* Add some random component to the file name. */ snprintf(fname, 256, "session_expire1_%s.dat", generate_random_str(tctx, 8)); smbcli_unlink(cli->tree, fname); fnum = smbcli_nt_create_full(cli->tree, fname, 0, SEC_RIGHTS_FILE_ALL, FILE_ATTRIBUTE_NORMAL, NTCREATEX_SHARE_ACCESS_NONE, NTCREATEX_DISP_OPEN_IF, NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 0); torture_assert_ntstatus_ok_goto(tctx, smbcli_nt_error(cli->tree), ret, done, "create file"); torture_assert_goto(tctx, fnum > 0, ret, done, "create file"); /* get the access information */ ZERO_STRUCT(qfinfo); qfinfo.access_information.level = RAW_FILEINFO_ACCESS_INFORMATION; qfinfo.access_information.in.file.fnum = fnum; for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); torture_comment(tctx, "sleep 5 seconds\n"); smb_msleep(5*1000); } /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); /* * now with CAP_DYNAMIC_REAUTH * * This should trigger NT_STATUS_NETWORK_SESSION_EXPIRED */ ZERO_STRUCT(io_sesssetup); io_sesssetup.in.sesskey = cli->transport->negotiate.sesskey; io_sesssetup.in.capabilities = cli->transport->negotiate.capabilities; io_sesssetup.in.capabilities |= CAP_DYNAMIC_REAUTH; io_sesssetup.in.credentials = credentials; io_sesssetup.in.workgroup = lpcfg_workgroup(tctx->lp_ctx); io_sesssetup.in.gensec_settings = lpcfg_gensec_settings(tctx, tctx->lp_ctx); torture_comment(tctx, "reauth with CAP_DYNAMIC_REAUTH => OK\n"); ZERO_STRUCT(io_sesssetup.out); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "reauth failed"); torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid, ret, done, "reauth"); for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); torture_comment(tctx, "sleep 5 seconds\n"); smb_msleep(5*1000); torture_comment(tctx, "query info => EXPIRED\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_NETWORK_SESSION_EXPIRED, ret, done, "raw_fileinfo expired"); /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); torture_comment(tctx, "reauth with CAP_DYNAMIC_REAUTH => OK\n"); ZERO_STRUCT(io_sesssetup.out); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "reauth failed"); torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid, ret, done, "reauth"); } torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); /* * the krb5 library may not handle expired creds * well, lets start with an empty ccache. */ cli_credentials_invalidate_ccache(credentials, CRED_SPECIFIED); /* * now without CAP_DYNAMIC_REAUTH * * This should not trigger NT_STATUS_NETWORK_SESSION_EXPIRED */ torture_comment(tctx, "reauth without CAP_DYNAMIC_REAUTH => OK\n"); io_sesssetup.in.capabilities &= ~CAP_DYNAMIC_REAUTH; ZERO_STRUCT(io_sesssetup.out); status = smb_composite_sesssetup(cli->session, &io_sesssetup); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "reauth failed"); torture_assert_int_equal_goto(tctx, io_sesssetup.out.vuid, vuid, ret, done, "reauth"); for (i=0; i < 2; i++) { torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); torture_comment(tctx, "sleep 5 seconds\n"); smb_msleep(5*1000); } torture_comment(tctx, "query info => OK\n"); ZERO_STRUCT(qfinfo.access_information.out); status = smb_raw_fileinfo(cli->tree, tctx, &qfinfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "raw_fileinfo failed"); ret = true; done: if (fnum > 0) { smbcli_close(cli->tree, fnum); } talloc_free(cli); lpcfg_set_option(tctx->lp_ctx, "gensec_gssapi:requested_life_time=0"); return ret; }