diff options
Diffstat (limited to 'source3/librpc')
-rw-r--r-- | source3/librpc/crypto/gse.c | 1438 | ||||
-rw-r--r-- | source3/librpc/crypto/gse.h | 26 | ||||
-rw-r--r-- | source3/librpc/crypto/gse_krb5.c | 609 | ||||
-rw-r--r-- | source3/librpc/crypto/gse_krb5.h | 30 | ||||
-rw-r--r-- | source3/librpc/gen_ndr/README | 4 | ||||
-rw-r--r-- | source3/librpc/idl/IDL_LICENSE.txt | 9 | ||||
-rw-r--r-- | source3/librpc/idl/leases_db.idl | 54 | ||||
-rw-r--r-- | source3/librpc/idl/libnet_join.idl | 92 | ||||
-rw-r--r-- | source3/librpc/idl/libnetapi.idl | 2050 | ||||
-rw-r--r-- | source3/librpc/idl/open_files.idl | 124 | ||||
-rw-r--r-- | source3/librpc/idl/perfcount.idl | 172 | ||||
-rw-r--r-- | source3/librpc/idl/rpc_host.idl | 76 | ||||
-rw-r--r-- | source3/librpc/idl/secrets.idl | 131 | ||||
-rw-r--r-- | source3/librpc/idl/smbXsrv.idl | 550 | ||||
-rw-r--r-- | source3/librpc/idl/wscript_build | 24 | ||||
-rw-r--r-- | source3/librpc/rpc/dcerpc.h | 80 | ||||
-rw-r--r-- | source3/librpc/rpc/dcerpc_helpers.c | 520 | ||||
-rw-r--r-- | source3/librpc/wscript_build | 43 |
18 files changed, 6032 insertions, 0 deletions
diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c new file mode 100644 index 0000000..c2cac7a --- /dev/null +++ b/source3/librpc/crypto/gse.c @@ -0,0 +1,1438 @@ +/* + * GSSAPI Security Extensions + * RPC Pipe client and server routines + * Copyright (C) Simo Sorce 2010. + * Copyright (C) Andrew Bartlett 2004-2011. + * Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* We support only GSSAPI/KRB5 here */ + +#include "includes.h" +#include <tevent.h> +#include "lib/util/tevent_ntstatus.h" +#include "gse.h" +#include "libads/kerberos_proto.h" +#include "auth/common_auth.h" +#include "auth/gensec/gensec.h" +#include "auth/gensec/gensec_internal.h" +#include "auth/credentials/credentials.h" +#include "../librpc/gen_ndr/dcerpc.h" +#include "param/param.h" + +#if defined(HAVE_KRB5) + +#include "auth/kerberos/pac_utils.h" +#include "auth/kerberos/gssapi_helper.h" +#include "gse_krb5.h" + +static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min); +static size_t gensec_gse_sig_size(struct gensec_security *gensec_security, + size_t data_size); + +struct gse_context { + gss_ctx_id_t gssapi_context; + gss_name_t server_name; + gss_name_t client_name; + OM_uint32 gss_want_flags, gss_got_flags; + size_t max_wrap_buf_size; + size_t sig_size; + + gss_cred_id_t delegated_cred_handle; + + NTTIME expire_time; + + /* gensec_gse only */ + krb5_context k5ctx; + krb5_ccache ccache; + krb5_keytab keytab; + + gss_OID_desc gss_mech; + gss_cred_id_t creds; + + gss_OID ret_mech; +}; + +/* free non talloc dependent contexts */ +static int gse_context_destructor(void *ptr) +{ + struct gse_context *gse_ctx; + OM_uint32 gss_min; + + gse_ctx = talloc_get_type_abort(ptr, struct gse_context); + if (gse_ctx->k5ctx) { + if (gse_ctx->ccache) { + krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache); + gse_ctx->ccache = NULL; + } + if (gse_ctx->keytab) { + krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab); + gse_ctx->keytab = NULL; + } + krb5_free_context(gse_ctx->k5ctx); + gse_ctx->k5ctx = NULL; + } + if (gse_ctx->gssapi_context != GSS_C_NO_CONTEXT) { + (void)gss_delete_sec_context(&gss_min, + &gse_ctx->gssapi_context, + GSS_C_NO_BUFFER); + } + if (gse_ctx->server_name) { + (void)gss_release_name(&gss_min, + &gse_ctx->server_name); + } + if (gse_ctx->client_name) { + (void)gss_release_name(&gss_min, + &gse_ctx->client_name); + } + if (gse_ctx->creds) { + (void)gss_release_cred(&gss_min, + &gse_ctx->creds); + } + if (gse_ctx->delegated_cred_handle) { + (void)gss_release_cred(&gss_min, + &gse_ctx->delegated_cred_handle); + } + + /* MIT and Heimdal differ as to if you can call + * gss_release_oid() on this OID, generated by + * gss_{accept,init}_sec_context(). However, as long as the + * oid is gss_mech_krb5 (which it always is at the moment), + * then this is a moot point, as both declare this particular + * OID static, and so no memory is lost. This assert is in + * place to ensure that the programmer who wishes to extend + * this code to EAP or other GSS mechanisms determines an + * implementation-dependent way of releasing any dynamically + * allocated OID */ + SMB_ASSERT(smb_gss_oid_equal(&gse_ctx->gss_mech, GSS_C_NO_OID) || + smb_gss_oid_equal(&gse_ctx->gss_mech, gss_mech_krb5)); + + return 0; +} + +static NTSTATUS gse_setup_server_principal(TALLOC_CTX *mem_ctx, + const char *target_principal, + const char *service, + const char *hostname, + const char *realm, + char **pserver_principal, + gss_name_t *pserver_name) +{ + char *server_principal = NULL; + gss_buffer_desc name_token; + gss_OID name_type; + OM_uint32 maj_stat, min_stat = 0; + + if (target_principal != NULL) { + server_principal = talloc_strdup(mem_ctx, target_principal); + name_type = GSS_C_NULL_OID; + } else { + server_principal = talloc_asprintf(mem_ctx, + "%s/%s@%s", + service, + hostname, + realm); + name_type = GSS_C_NT_USER_NAME; + } + if (server_principal == NULL) { + return NT_STATUS_NO_MEMORY; + } + + name_token.value = (uint8_t *)server_principal; + name_token.length = strlen(server_principal); + + maj_stat = gss_import_name(&min_stat, + &name_token, + name_type, + pserver_name); + if (maj_stat) { + DBG_WARNING("GSS Import name of %s failed: %s\n", + server_principal, + gse_errstr(mem_ctx, maj_stat, min_stat)); + TALLOC_FREE(server_principal); + return NT_STATUS_INVALID_PARAMETER; + } + + *pserver_principal = server_principal; + + return NT_STATUS_OK; +} + +static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx, + bool do_sign, bool do_seal, + const char *ccache_name, + uint32_t add_gss_c_flags, + struct gse_context **_gse_ctx) +{ + struct gse_context *gse_ctx; + krb5_error_code k5ret; + NTSTATUS status; + + gse_ctx = talloc_zero(mem_ctx, struct gse_context); + if (!gse_ctx) { + return NT_STATUS_NO_MEMORY; + } + talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor); + + gse_ctx->expire_time = GENSEC_EXPIRE_TIME_INFINITY; + gse_ctx->max_wrap_buf_size = UINT16_MAX; + + memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc)); + + gse_ctx->gss_want_flags = GSS_C_MUTUAL_FLAG | + GSS_C_DELEG_POLICY_FLAG | + GSS_C_REPLAY_FLAG | + GSS_C_SEQUENCE_FLAG; + if (do_sign) { + gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG; + } + if (do_seal) { + gse_ctx->gss_want_flags |= GSS_C_INTEG_FLAG; + gse_ctx->gss_want_flags |= GSS_C_CONF_FLAG; + } + + gse_ctx->gss_want_flags |= add_gss_c_flags; + + /* Initialize Kerberos Context */ + k5ret = smb_krb5_init_context_common(&gse_ctx->k5ctx); + if (k5ret) { + DBG_ERR("kerberos init context failed (%s)\n", + error_message(k5ret)); + status = NT_STATUS_INTERNAL_ERROR; + goto err_out; + } + +#ifdef SAMBA4_USES_HEIMDAL + k5ret = gsskrb5_set_dns_canonicalize(false); + if (k5ret) { + DBG_ERR("gsskrb5_set_dns_canonicalize() failed (%s)\n", + error_message(k5ret)); + status = NT_STATUS_INTERNAL_ERROR; + goto err_out; + } +#endif + + if (!ccache_name) { + ccache_name = krb5_cc_default_name(gse_ctx->k5ctx); + } + k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name, + &gse_ctx->ccache); + if (k5ret) { + DEBUG(1, ("Failed to resolve credential cache '%s'! (%s)\n", + ccache_name, error_message(k5ret))); + status = NT_STATUS_INTERNAL_ERROR; + goto err_out; + } + + /* TODO: Should we enforce a enc_types list ? + ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types); + */ + + *_gse_ctx = gse_ctx; + return NT_STATUS_OK; + +err_out: + TALLOC_FREE(gse_ctx); + return status; +} + +static NTSTATUS gse_init_client(struct gensec_security *gensec_security, + bool do_sign, bool do_seal, + const char *ccache_name, + const char *server, + const char *service, + const char *realm, + const char *username, + const char *password, + uint32_t add_gss_c_flags, + struct gse_context **_gse_ctx) +{ + struct gse_context *gse_ctx; + OM_uint32 gss_maj, gss_min; +#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X + gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; + gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X); +#endif + NTSTATUS status; + + if (!server || !service) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = gse_context_init(gensec_security, do_sign, do_seal, + ccache_name, add_gss_c_flags, + &gse_ctx); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_NO_MEMORY; + } + +#ifdef SAMBA4_USES_HEIMDAL + { + int ret; + bool set_dns_canon = gensec_setting_bool( + gensec_security->settings, + "krb5", "set_dns_canonicalize", + false); + const char *server_realm = lpcfg_realm( + gensec_security->settings->lp_ctx); + if (server_realm != NULL) { + ret = gsskrb5_set_default_realm(server_realm); + if (ret) { + DBG_ERR("gsskrb5_set_default_realm failed\n"); + return NT_STATUS_INTERNAL_ERROR; + } + } + + /* + * don't do DNS lookups of any kind, it might/will + * fail for a netbios name + */ + ret = gsskrb5_set_dns_canonicalize(set_dns_canon); + if (ret != GSS_S_COMPLETE) { + DBG_ERR("gsskrb5_set_dns_canonicalize failed\n"); + return NT_STATUS_INTERNAL_ERROR; + } + } +#endif + + /* TODO: get krb5 ticket using username/password, if no valid + * one already available in ccache */ + + gss_maj = smb_gss_krb5_import_cred(&gss_min, + gse_ctx->k5ctx, + gse_ctx->ccache, + NULL, /* keytab_principal */ + NULL, /* keytab */ + &gse_ctx->creds); + if (gss_maj) { + char *ccache = NULL; + int kret; + + kret = krb5_cc_get_full_name(gse_ctx->k5ctx, + gse_ctx->ccache, + &ccache); + if (kret != 0) { + ccache = NULL; + } + + DEBUG(5, ("smb_gss_krb5_import_cred ccache[%s] failed with [%s] -" + "the caller may retry after a kinit.\n", + ccache, gse_errstr(gse_ctx, gss_maj, gss_min))); + SAFE_FREE(ccache); + status = NT_STATUS_INTERNAL_ERROR; + goto err_out; + } + +#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X + /* + * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG. + * + * This allows us to disable SIGN and SEAL for + * AUTH_LEVEL_CONNECT and AUTH_LEVEL_INTEGRITY. + * + * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575 + * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938 + */ + gss_maj = gss_set_cred_option(&gss_min, &gse_ctx->creds, + oid, + &empty_buffer); + if (gss_maj) { + DEBUG(0, ("gss_set_cred_option(GSS_KRB5_CRED_NO_CI_FLAGS_X), " + "failed with [%s]\n", + gse_errstr(gse_ctx, gss_maj, gss_min))); + status = NT_STATUS_INTERNAL_ERROR; + goto err_out; + } +#endif + + *_gse_ctx = gse_ctx; + return NT_STATUS_OK; + +err_out: + TALLOC_FREE(gse_ctx); + return status; +} + +static NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx, + struct gensec_security *gensec_security, + const DATA_BLOB *token_in, + DATA_BLOB *token_out) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + OM_uint32 gss_maj = 0; + OM_uint32 gss_min; + gss_buffer_desc in_data; + gss_buffer_desc out_data; + DATA_BLOB blob = data_blob_null; + NTSTATUS status; + OM_uint32 time_rec = 0; + struct timeval tv; + struct cli_credentials *cli_creds = gensec_get_credentials(gensec_security); + const char *target_principal = gensec_get_target_principal(gensec_security); + const char *hostname = gensec_get_target_hostname(gensec_security); + const char *service = gensec_get_target_service(gensec_security); + const char *client_realm = cli_credentials_get_realm(cli_creds); + char *server_principal = NULL; + char *server_realm = NULL; + bool fallback = false; + OM_uint32 time_req = 0; + + time_req = gensec_setting_int(gensec_security->settings, + "gensec_gssapi", + "requested_life_time", + time_req); + + in_data.value = token_in->data; + in_data.length = token_in->length; + + /* + * With credentials for administrator@FOREST1.EXAMPLE.COM this patch + * changes the target_principal for the ldap service of host + * dc2.forest2.example.com from + * + * ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM + * + * to + * + * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM + * + * Typically ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM should be + * used in order to allow the KDC of FOREST1.EXAMPLE.COM to generate a + * referral ticket for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM. + * + * The problem is that KDCs only return such referral tickets if + * there's a forest trust between FOREST1.EXAMPLE.COM and + * FOREST2.EXAMPLE.COM. If there's only an external domain trust + * between FOREST1.EXAMPLE.COM and FOREST2.EXAMPLE.COM the KDC of + * FOREST1.EXAMPLE.COM will respond with S_PRINCIPAL_UNKNOWN when being + * asked for ldap/dc2.forest2.example.com@FOREST1.EXAMPLE.COM. + * + * In the case of an external trust the client can still ask explicitly + * for krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM and the KDC of + * FOREST1.EXAMPLE.COM will generate it. + * + * From there the client can use the + * krbtgt/FOREST2.EXAMPLE.COM@FOREST1.EXAMPLE.COM ticket and ask a KDC + * of FOREST2.EXAMPLE.COM for a service ticket for + * ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM. + * + * With Heimdal we'll get the fallback on S_PRINCIPAL_UNKNOWN behavior + * when we pass ldap/dc2.forest2.example.com@FOREST2.EXAMPLE.COM as + * target principal. As _krb5_get_cred_kdc_any() first calls + * get_cred_kdc_referral() (which always starts with the client realm) + * and falls back to get_cred_kdc_capath() (which starts with the given + * realm). + * + * MIT krb5 only tries the given realm of the target principal, if we + * want to autodetect support for transitive forest trusts, would have + * to do the fallback ourself. + */ +#ifndef SAMBA4_USES_HEIMDAL + if (gse_ctx->server_name == NULL) { + OM_uint32 gss_min2 = 0; + + status = gse_setup_server_principal(mem_ctx, + target_principal, + service, + hostname, + client_realm, + &server_principal, + &gse_ctx->server_name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + gss_maj = gss_init_sec_context(&gss_min, + gse_ctx->creds, + &gse_ctx->gssapi_context, + gse_ctx->server_name, + &gse_ctx->gss_mech, + gse_ctx->gss_want_flags, + time_req, + GSS_C_NO_CHANNEL_BINDINGS, + &in_data, + NULL, + &out_data, + &gse_ctx->gss_got_flags, + &time_rec); + if (gss_maj != GSS_S_FAILURE) { + goto init_sec_context_done; + } + if (gss_min != (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) { + goto init_sec_context_done; + } + if (target_principal != NULL) { + goto init_sec_context_done; + } + + fallback = true; + TALLOC_FREE(server_principal); + gss_release_name(&gss_min2, &gse_ctx->server_name); + } +#endif /* !SAMBA4_USES_HEIMDAL */ + + if (gse_ctx->server_name == NULL) { + server_realm = smb_krb5_get_realm_from_hostname(mem_ctx, + hostname, + client_realm); + if (server_realm == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (fallback && + strequal(client_realm, server_realm)) { + goto init_sec_context_done; + } + + status = gse_setup_server_principal(mem_ctx, + target_principal, + service, + hostname, + server_realm, + &server_principal, + &gse_ctx->server_name); + TALLOC_FREE(server_realm); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + TALLOC_FREE(server_principal); + } + + gss_maj = gss_init_sec_context(&gss_min, + gse_ctx->creds, + &gse_ctx->gssapi_context, + gse_ctx->server_name, + &gse_ctx->gss_mech, + gse_ctx->gss_want_flags, + time_req, GSS_C_NO_CHANNEL_BINDINGS, + &in_data, NULL, &out_data, + &gse_ctx->gss_got_flags, &time_rec); + goto init_sec_context_done; + /* JUMP! */ +init_sec_context_done: + + switch (gss_maj) { + case GSS_S_COMPLETE: + /* we are done with it */ + tv = timeval_current_ofs(time_rec, 0); + gse_ctx->expire_time = timeval_to_nttime(&tv); + + status = NT_STATUS_OK; + break; + case GSS_S_CONTINUE_NEEDED: + /* we will need a third leg */ + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + break; + case GSS_S_CONTEXT_EXPIRED: + /* Make SPNEGO ignore us, we can't go any further here */ + DBG_NOTICE("Context expired\n"); + status = NT_STATUS_INVALID_PARAMETER; + goto done; + case GSS_S_FAILURE: + switch (gss_min) { + case (OM_uint32)KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: { + gss_buffer_desc name_token = { + .length = 0, + }; + + gss_maj = gss_display_name(&gss_min, + gse_ctx->server_name, + &name_token, + NULL); + if (gss_maj == GSS_S_COMPLETE) { + DBG_NOTICE("Server principal %.*s not found\n", + (int)name_token.length, + (char *)name_token.value); + gss_release_buffer(&gss_maj, &name_token); + } else { + DBG_NOTICE("Server principal not found\n"); + } + + /* Make SPNEGO ignore us, we can't go any further here */ + status = NT_STATUS_INVALID_PARAMETER; + goto done; + } + case (OM_uint32)KRB5KRB_AP_ERR_TKT_EXPIRED: + DBG_NOTICE("Ticket expired\n"); + /* Make SPNEGO ignore us, we can't go any further here */ + status = NT_STATUS_INVALID_PARAMETER; + goto done; + case (OM_uint32)KRB5KRB_AP_ERR_TKT_NYV: + DBG_NOTICE("Clockskew\n"); + /* Make SPNEGO ignore us, we can't go any further here */ + status = NT_STATUS_TIME_DIFFERENCE_AT_DC; + goto done; + case (OM_uint32)KRB5_KDC_UNREACH: + DBG_NOTICE("KDC unreachable\n"); + /* Make SPNEGO ignore us, we can't go any further here */ + status = NT_STATUS_NO_LOGON_SERVERS; + goto done; + case (OM_uint32)KRB5KRB_AP_ERR_MSG_TYPE: + /* Garbage input, possibly from the auto-mech detection */ + status = NT_STATUS_INVALID_PARAMETER; + goto done; + case (OM_uint32)KRB5KDC_ERR_ETYPE_NOSUPP: + status = NT_STATUS_KDC_UNKNOWN_ETYPE; + goto done; + default: + DBG_ERR("gss_init_sec_context failed with [%s](%u)\n", + gse_errstr(talloc_tos(), gss_maj, gss_min), + gss_min); + status = NT_STATUS_LOGON_FAILURE; + goto done; + } + break; + default: + DBG_ERR("gss_init_sec_context failed with [%s]\n", + gse_errstr(talloc_tos(), gss_maj, gss_min)); + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + /* we may be told to return nothing */ + if (out_data.length) { + blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length); + if (!blob.data) { + status = NT_STATUS_NO_MEMORY; + } + + gss_release_buffer(&gss_min, &out_data); + } + +done: + *token_out = blob; + return status; +} + +static NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx, + bool do_sign, bool do_seal, + uint32_t add_gss_c_flags, + struct gse_context **_gse_ctx) +{ + struct gse_context *gse_ctx; + OM_uint32 gss_maj, gss_min; + krb5_error_code ret; + NTSTATUS status; + + status = gse_context_init(mem_ctx, do_sign, do_seal, + NULL, add_gss_c_flags, &gse_ctx); + if (!NT_STATUS_IS_OK(status)) { + return NT_STATUS_NO_MEMORY; + } + + ret = gse_krb5_get_server_keytab(gse_ctx->k5ctx, + &gse_ctx->keytab); + if (ret) { + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + /* This creates a GSSAPI cred_id_t with the keytab set */ + gss_maj = smb_gss_krb5_import_cred(&gss_min, gse_ctx->k5ctx, + NULL, NULL, gse_ctx->keytab, + &gse_ctx->creds); + + if (gss_maj != 0) { + DEBUG(0, ("smb_gss_krb5_import_cred failed with [%s]\n", + gse_errstr(gse_ctx, gss_maj, gss_min))); + status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(gse_ctx); + } + + *_gse_ctx = gse_ctx; + return status; +} + +static NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx, + struct gensec_security *gensec_security, + const DATA_BLOB *token_in, + DATA_BLOB *token_out) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + OM_uint32 gss_maj, gss_min; + gss_buffer_desc in_data; + gss_buffer_desc out_data; + DATA_BLOB blob = data_blob_null; + NTSTATUS status; + OM_uint32 time_rec = 0; + struct timeval tv; + + in_data.value = token_in->data; + in_data.length = token_in->length; + + gss_maj = gss_accept_sec_context(&gss_min, + &gse_ctx->gssapi_context, + gse_ctx->creds, + &in_data, + GSS_C_NO_CHANNEL_BINDINGS, + &gse_ctx->client_name, + &gse_ctx->ret_mech, + &out_data, + &gse_ctx->gss_got_flags, + &time_rec, + &gse_ctx->delegated_cred_handle); + switch (gss_maj) { + case GSS_S_COMPLETE: + /* we are done with it */ + tv = timeval_current_ofs(time_rec, 0); + gse_ctx->expire_time = timeval_to_nttime(&tv); + + status = NT_STATUS_OK; + break; + case GSS_S_CONTINUE_NEEDED: + /* we will need a third leg */ + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + break; + default: + DEBUG(1, ("gss_accept_sec_context failed with [%s]\n", + gse_errstr(talloc_tos(), gss_maj, gss_min))); + + if (gse_ctx->gssapi_context) { + gss_delete_sec_context(&gss_min, + &gse_ctx->gssapi_context, + GSS_C_NO_BUFFER); + } + + /* + * If we got an output token, make Windows aware of it + * by telling it that more processing is needed + */ + if (out_data.length > 0) { + status = NT_STATUS_MORE_PROCESSING_REQUIRED; + /* Fall through to handle the out token */ + } else { + status = NT_STATUS_LOGON_FAILURE; + goto done; + } + } + + /* we may be told to return nothing */ + if (out_data.length) { + blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length); + if (!blob.data) { + status = NT_STATUS_NO_MEMORY; + } + gss_release_buffer(&gss_min, &out_data); + } + + +done: + *token_out = blob; + return status; +} + +static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min) +{ + OM_uint32 gss_min, gss_maj; + gss_buffer_desc msg_min; + gss_buffer_desc msg_maj; + OM_uint32 msg_ctx = 0; + + char *errstr = NULL; + + ZERO_STRUCT(msg_min); + ZERO_STRUCT(msg_maj); + + gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE, + GSS_C_NO_OID, &msg_ctx, &msg_maj); + if (gss_maj) { + goto done; + } + errstr = talloc_strndup(mem_ctx, + (char *)msg_maj.value, + msg_maj.length); + if (!errstr) { + goto done; + } + gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE, + (gss_OID)discard_const(gss_mech_krb5), + &msg_ctx, &msg_min); + if (gss_maj) { + goto done; + } + + errstr = talloc_strdup_append_buffer(errstr, ": "); + if (!errstr) { + goto done; + } + errstr = talloc_strndup_append_buffer(errstr, + (char *)msg_min.value, + msg_min.length); + if (!errstr) { + goto done; + } + +done: + if (msg_min.value) { + gss_release_buffer(&gss_min, &msg_min); + } + if (msg_maj.value) { + gss_release_buffer(&gss_min, &msg_maj); + } + return errstr; +} + +static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx; + struct cli_credentials *creds = gensec_get_credentials(gensec_security); + NTSTATUS nt_status; + OM_uint32 want_flags = 0; + bool do_sign = false, do_seal = false; + const char *hostname = gensec_get_target_hostname(gensec_security); + const char *service = gensec_get_target_service(gensec_security); + const char *username = cli_credentials_get_username(creds); + const char *password = cli_credentials_get_password(creds); + const char *realm = cli_credentials_get_realm(creds); + + if (!hostname) { + DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n")); + return NT_STATUS_INVALID_PARAMETER; + } + if (is_ipaddress(hostname)) { + DEBUG(2, ("Cannot do GSE to an IP address\n")); + return NT_STATUS_INVALID_PARAMETER; + } + if (strcmp(hostname, "localhost") == 0) { + DEBUG(2, ("GSE to 'localhost' does not make sense\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { + do_sign = true; + } + if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { + do_sign = true; + } + if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { + do_seal = true; + } + if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) { + want_flags |= GSS_C_DCE_STYLE; + } + + nt_status = gse_init_client(gensec_security, do_sign, do_seal, NULL, + hostname, service, realm, + username, password, want_flags, + &gse_ctx); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + gensec_security->private_data = gse_ctx; + return NT_STATUS_OK; +} + +static NTSTATUS gensec_gse_server_start(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx; + NTSTATUS nt_status; + OM_uint32 want_flags = 0; + bool do_sign = false, do_seal = false; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { + do_sign = true; + } + if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { + do_seal = true; + } + if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) { + want_flags |= GSS_C_DCE_STYLE; + } + + nt_status = gse_init_server(gensec_security, do_sign, do_seal, want_flags, + &gse_ctx); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + gensec_security->private_data = gse_ctx; + return NT_STATUS_OK; +} + +struct gensec_gse_update_state { + NTSTATUS status; + DATA_BLOB out; +}; + +static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB in, + DATA_BLOB *out); + +static struct tevent_req *gensec_gse_update_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct gensec_security *gensec_security, + const DATA_BLOB in) +{ + struct tevent_req *req = NULL; + struct gensec_gse_update_state *state = NULL; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &state, + struct gensec_gse_update_state); + if (req == NULL) { + return NULL; + } + + status = gensec_gse_update_internal(gensec_security, + state, in, + &state->out); + state->status = status; + if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +static NTSTATUS gensec_gse_update_internal(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB in, + DATA_BLOB *out) +{ + NTSTATUS status; + + switch (gensec_security->gensec_role) { + case GENSEC_CLIENT: + status = gse_get_client_auth_token(mem_ctx, + gensec_security, + &in, out); + break; + case GENSEC_SERVER: + status = gse_get_server_auth_token(mem_ctx, + gensec_security, + &in, out); + break; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS gensec_gse_update_recv(struct tevent_req *req, + TALLOC_CTX *out_mem_ctx, + DATA_BLOB *out) +{ + struct gensec_gse_update_state *state = + tevent_req_data(req, + struct gensec_gse_update_state); + NTSTATUS status; + + *out = data_blob_null; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + *out = state->out; + talloc_steal(out_mem_ctx, state->out.data); + status = state->status; + tevent_req_received(req); + return status; +} + +static NTSTATUS gensec_gse_wrap(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token, output_token; + int conf_state; + input_token.length = in->length; + input_token.value = in->data; + + maj_stat = gss_wrap(&min_stat, + gse_ctx->gssapi_context, + gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL), + GSS_C_QOP_DEFAULT, + &input_token, + &conf_state, + &output_token); + if (GSS_ERROR(maj_stat)) { + DEBUG(0, ("gensec_gse_wrap: GSS Wrap failed: %s\n", + gse_errstr(talloc_tos(), maj_stat, min_stat))); + return NT_STATUS_ACCESS_DENIED; + } + + *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); + gss_release_buffer(&min_stat, &output_token); + + if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) + && !conf_state) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + +static NTSTATUS gensec_gse_unwrap(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + OM_uint32 maj_stat, min_stat; + gss_buffer_desc input_token, output_token; + int conf_state; + gss_qop_t qop_state; + input_token.length = in->length; + input_token.value = in->data; + + maj_stat = gss_unwrap(&min_stat, + gse_ctx->gssapi_context, + &input_token, + &output_token, + &conf_state, + &qop_state); + if (GSS_ERROR(maj_stat)) { + DEBUG(0, ("gensec_gse_unwrap: GSS UnWrap failed: %s\n", + gse_errstr(talloc_tos(), maj_stat, min_stat))); + return NT_STATUS_ACCESS_DENIED; + } + + *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length); + gss_release_buffer(&min_stat, &output_token); + + if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) + && !conf_state) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + +static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + DATA_BLOB *sig) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + bool hdr_signing = false; + size_t sig_size = 0; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + sig_size = gensec_gse_sig_size(gensec_security, length); + + status = gssapi_seal_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, sig_size, + data, length, + whole_pdu, pdu_length, + mem_ctx, sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%zu," + "data=%zu,pdu=%zu) failed: %s\n", + hdr_signing, sig_size, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security, + uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + bool hdr_signing = false; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + status = gssapi_unseal_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, + data, length, + whole_pdu, pdu_length, + sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%zu," + "data=%zu,pdu=%zu) failed: %s\n", + hdr_signing, sig->length, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + DATA_BLOB *sig) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + bool hdr_signing = false; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + status = gssapi_sign_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, + data, length, + whole_pdu, pdu_length, + mem_ctx, sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u," + "data=%zu,pdu=%zu) failed: %s\n", + hdr_signing, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security, + const uint8_t *data, size_t length, + const uint8_t *whole_pdu, size_t pdu_length, + const DATA_BLOB *sig) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + bool hdr_signing = false; + NTSTATUS status; + + if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) { + hdr_signing = true; + } + + status = gssapi_check_packet(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + hdr_signing, + data, length, + whole_pdu, pdu_length, + sig); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%zu" + "data=%zu,pdu=%zu) failed: %s\n", + hdr_signing, sig->length, length, pdu_length, + nt_errstr(status))); + return status; + } + + return NT_STATUS_OK; +} + +/* Try to figure out what features we actually got on the connection */ +static bool gensec_gse_have_feature(struct gensec_security *gensec_security, + uint32_t feature) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + + if (feature & GENSEC_FEATURE_SESSION_KEY) { + return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG; + } + if (feature & GENSEC_FEATURE_SIGN) { + return gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG; + } + if (feature & GENSEC_FEATURE_SEAL) { + return gse_ctx->gss_got_flags & GSS_C_CONF_FLAG; + } + if (feature & GENSEC_FEATURE_DCE_STYLE) { + return gse_ctx->gss_got_flags & GSS_C_DCE_STYLE; + } + if (feature & GENSEC_FEATURE_NEW_SPNEGO) { + NTSTATUS status; + uint32_t keytype; + + if (!(gse_ctx->gss_got_flags & GSS_C_INTEG_FLAG)) { + return false; + } + + status = gssapi_get_session_key(talloc_tos(), + gse_ctx->gssapi_context, NULL, &keytype); + /* + * We should do a proper sig on the mechListMic unless + * we know we have to be backwards compatible with + * earlier windows versions. + * + * Negotiating a non-krb5 + * mech for example should be regarded as having + * NEW_SPNEGO + */ + if (NT_STATUS_IS_OK(status)) { + switch (keytype) { + case ENCTYPE_DES_CBC_CRC: + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_ARCFOUR_HMAC: + case ENCTYPE_DES3_CBC_SHA1: + return false; + } + } + return true; + } + /* We can always do async (rather than strict request/reply) packets. */ + if (feature & GENSEC_FEATURE_ASYNC_REPLIES) { + return true; + } + if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) { + return true; + } + return false; +} + +static NTTIME gensec_gse_expire_time(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + + return gse_ctx->expire_time; +} + +/* + * Extract the 'sesssion key' needed by SMB signing and ncacn_np + * (for encrypting some passwords). + * + * This breaks all the abstractions, but what do you expect... + */ +static NTSTATUS gensec_gse_session_key(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + DATA_BLOB *session_key) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + + return gssapi_get_session_key(mem_ctx, gse_ctx->gssapi_context, session_key, NULL); +} + +/* Get some basic (and authorization) information about the user on + * this session. This uses either the PAC (if present) or a local + * database lookup */ +static NTSTATUS gensec_gse_session_info(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + struct auth_session_info **_session_info) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + NTSTATUS nt_status; + TALLOC_CTX *tmp_ctx; + struct auth_session_info *session_info = NULL; + OM_uint32 maj_stat, min_stat; + DATA_BLOB pac_blob, *pac_blob_ptr = NULL; + + gss_buffer_desc name_token; + char *principal_string; + + tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gse_session_info context"); + NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + + maj_stat = gss_display_name(&min_stat, + gse_ctx->client_name, + &name_token, + NULL); + if (GSS_ERROR(maj_stat)) { + DEBUG(1, ("GSS display_name failed: %s\n", + gse_errstr(talloc_tos(), maj_stat, min_stat))); + talloc_free(tmp_ctx); + return NT_STATUS_FOOBAR; + } + + principal_string = talloc_strndup(tmp_ctx, + (const char *)name_token.value, + name_token.length); + + gss_release_buffer(&min_stat, &name_token); + + if (!principal_string) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + nt_status = gssapi_obtain_pac_blob(tmp_ctx, gse_ctx->gssapi_context, + gse_ctx->client_name, + &pac_blob); + + /* IF we have the PAC - otherwise we need to get this + * data from elsewere + */ + if (NT_STATUS_IS_OK(nt_status)) { + pac_blob_ptr = &pac_blob; + } + nt_status = gensec_generate_session_info_pac(tmp_ctx, + gensec_security, + NULL, + pac_blob_ptr, principal_string, + gensec_get_remote_address(gensec_security), + &session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + nt_status = gensec_gse_session_key(gensec_security, session_info, + &session_info->session_key); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(tmp_ctx); + return nt_status; + } + + *_session_info = talloc_move(mem_ctx, &session_info); + talloc_free(tmp_ctx); + + return NT_STATUS_OK; +} + +static size_t gensec_gse_max_input_size(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + OM_uint32 maj_stat, min_stat; + OM_uint32 max_input_size; + + maj_stat = gss_wrap_size_limit(&min_stat, + gse_ctx->gssapi_context, + gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL), + GSS_C_QOP_DEFAULT, + gse_ctx->max_wrap_buf_size, + &max_input_size); + if (GSS_ERROR(maj_stat)) { + TALLOC_CTX *mem_ctx = talloc_new(NULL); + DEBUG(1, ("gensec_gssapi_max_input_size: determining signature size with gss_wrap_size_limit failed: %s\n", + gse_errstr(mem_ctx, maj_stat, min_stat))); + talloc_free(mem_ctx); + return 0; + } + + return max_input_size; +} + +/* Find out the maximum output size negotiated on this connection */ +static size_t gensec_gse_max_wrapped_size(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + return gse_ctx->max_wrap_buf_size; +} + +static size_t gensec_gse_sig_size(struct gensec_security *gensec_security, + size_t data_size) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + + if (gse_ctx->sig_size > 0) { + return gse_ctx->sig_size; + } + + gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context, + &gse_ctx->gss_mech, + gse_ctx->gss_got_flags, + data_size); + return gse_ctx->sig_size; +} + +static const char *gensec_gse_final_auth_type(struct gensec_security *gensec_security) +{ + struct gse_context *gse_ctx = + talloc_get_type_abort(gensec_security->private_data, + struct gse_context); + + /* Only return the string for GSSAPI/Krb5 */ + if (smb_gss_oid_equal(&gse_ctx->gss_mech, + gss_mech_krb5)) { + return GENSEC_FINAL_AUTH_TYPE_KRB5; + } else { + return "gensec_gse: UNKNOWN MECH"; + } +} + +static const char *gensec_gse_krb5_oids[] = { + GENSEC_OID_KERBEROS5_OLD, + GENSEC_OID_KERBEROS5, + NULL +}; + +const struct gensec_security_ops gensec_gse_krb5_security_ops = { + .name = "gse_krb5", + .auth_type = DCERPC_AUTH_TYPE_KRB5, + .oid = gensec_gse_krb5_oids, + .client_start = gensec_gse_client_start, + .server_start = gensec_gse_server_start, + .magic = gensec_magic_check_krb5_oid, + .update_send = gensec_gse_update_send, + .update_recv = gensec_gse_update_recv, + .session_key = gensec_gse_session_key, + .session_info = gensec_gse_session_info, + .sig_size = gensec_gse_sig_size, + .sign_packet = gensec_gse_sign_packet, + .check_packet = gensec_gse_check_packet, + .seal_packet = gensec_gse_seal_packet, + .unseal_packet = gensec_gse_unseal_packet, + .max_input_size = gensec_gse_max_input_size, + .max_wrapped_size = gensec_gse_max_wrapped_size, + .wrap = gensec_gse_wrap, + .unwrap = gensec_gse_unwrap, + .have_feature = gensec_gse_have_feature, + .expire_time = gensec_gse_expire_time, + .final_auth_type = gensec_gse_final_auth_type, + .enabled = true, + .kerberos = true, + .priority = GENSEC_GSSAPI +}; + +#endif /* HAVE_KRB5 */ diff --git a/source3/librpc/crypto/gse.h b/source3/librpc/crypto/gse.h new file mode 100644 index 0000000..8618573 --- /dev/null +++ b/source3/librpc/crypto/gse.h @@ -0,0 +1,26 @@ +/* + * GSSAPI Security Extensions + * Copyright (C) Simo Sorce 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _GSE_H_ +#define _GSE_H_ + +struct gse_context; + +extern const struct gensec_security_ops gensec_gse_krb5_security_ops; + +#endif /* _GSE_H_ */ diff --git a/source3/librpc/crypto/gse_krb5.c b/source3/librpc/crypto/gse_krb5.c new file mode 100644 index 0000000..b4cec1e --- /dev/null +++ b/source3/librpc/crypto/gse_krb5.c @@ -0,0 +1,609 @@ +/* + * GSSAPI Security Extensions + * Krb5 helpers + * Copyright (C) Simo Sorce 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "smb_krb5.h" +#include "secrets.h" +#include "librpc/gen_ndr/secrets.h" +#include "gse_krb5.h" +#include "lib/param/loadparm.h" +#include "libads/kerberos_proto.h" +#include "lib/util/string_wrappers.h" + +#ifdef HAVE_KRB5 + +static krb5_error_code flush_keytab(krb5_context krbctx, krb5_keytab keytab) +{ + krb5_error_code ret; + krb5_kt_cursor kt_cursor; + krb5_keytab_entry kt_entry; + + ZERO_STRUCT(kt_entry); + + ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor); + if (ret != 0) { + return ret; + } + + ret = krb5_kt_next_entry(krbctx, keytab, &kt_entry, &kt_cursor); + while (ret == 0) { + + /* we need to close and reopen enumeration because we modify + * the keytab */ + ret = krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor); + if (ret != 0) { + DEBUG(1, (__location__ ": krb5_kt_end_seq_get() " + "failed (%s)\n", error_message(ret))); + goto out; + } + + /* remove the entry */ + ret = krb5_kt_remove_entry(krbctx, keytab, &kt_entry); + if (ret != 0) { + DEBUG(1, (__location__ ": krb5_kt_remove_entry() " + "failed (%s)\n", error_message(ret))); + goto out; + } + smb_krb5_kt_free_entry(krbctx, &kt_entry); + ZERO_STRUCT(kt_entry); + + /* now reopen */ + ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor); + if (ret != 0) { + DEBUG(1, (__location__ ": krb5_kt_start_seq() failed " + "(%s)\n", error_message(ret))); + goto out; + } + + ret = krb5_kt_next_entry(krbctx, keytab, + &kt_entry, &kt_cursor); + } + + if (ret != KRB5_KT_END && ret != ENOENT) { + DEBUG(1, (__location__ ": flushing keytab we got [%s]!\n", + error_message(ret))); + } + + ret = krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor); + if (ret != 0) { + DEBUG(1, (__location__ ": krb5_kt_end_seq_get() " + "failed (%s)\n", error_message(ret))); + goto out; + } + ret = 0; + +out: + return ret; +} + +static krb5_error_code fill_keytab_from_password(krb5_context krbctx, + krb5_keytab keytab, + krb5_principal princ, + krb5_kvno vno, + struct secrets_domain_info1_password *pw) +{ + krb5_error_code ret; + krb5_enctype *enctypes; + uint16_t i; + + ret = smb_krb5_get_allowed_etypes(krbctx, &enctypes); + if (ret) { + DEBUG(1, (__location__ + ": Can't determine permitted enctypes!\n")); + return ret; + } + + for (i = 0; i < pw->num_keys; i++) { + krb5_keytab_entry kt_entry; + krb5_keyblock *key = NULL; + unsigned int ei; + bool found_etype = false; + + for (ei=0; enctypes[ei] != 0; ei++) { + if ((uint32_t)enctypes[ei] != pw->keys[i].keytype) { + continue; + } + + found_etype = true; + break; + } + + if (!found_etype) { + continue; + } + + ZERO_STRUCT(kt_entry); + kt_entry.principal = princ; + kt_entry.vno = vno; + + key = KRB5_KT_KEY(&kt_entry); + KRB5_KEY_TYPE(key) = pw->keys[i].keytype; + KRB5_KEY_DATA(key) = pw->keys[i].value.data; + KRB5_KEY_LENGTH(key) = pw->keys[i].value.length; + + ret = krb5_kt_add_entry(krbctx, keytab, &kt_entry); + if (ret) { + DEBUG(1, (__location__ ": Failed to add entry to " + "keytab for enctype %d (error: %s)\n", + (unsigned)pw->keys[i].keytype, + error_message(ret))); + goto out; + } + } + + ret = 0; + +out: + SAFE_FREE(enctypes); + return ret; +} + +#define SRV_MEM_KEYTAB_NAME "MEMORY:cifs_srv_keytab" +#define CLEARTEXT_PRIV_ENCTYPE -99 + +static krb5_error_code fill_mem_keytab_from_secrets(krb5_context krbctx, + krb5_keytab *keytab) +{ + TALLOC_CTX *frame = talloc_stackframe(); + krb5_error_code ret, ret2; + const char *domain = lp_workgroup(); + struct secrets_domain_info1 *info = NULL; + const char *realm = NULL; + const DATA_BLOB *ct = NULL; + krb5_kt_cursor kt_cursor; + krb5_keytab_entry kt_entry; + krb5_principal princ = NULL; + krb5_kvno kvno = 0; /* FIXME: fetch current vno from KDC ? */ + NTSTATUS status; + + if (!secrets_init()) { + DEBUG(1, (__location__ ": secrets_init failed\n")); + TALLOC_FREE(frame); + return KRB5_CONFIG_CANTOPEN; + } + + status = secrets_fetch_or_upgrade_domain_info(domain, + frame, + &info); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("secrets_fetch_or_upgrade_domain_info(%s) - %s\n", + domain, nt_errstr(status)); + TALLOC_FREE(frame); + return KRB5_LIBOS_CANTREADPWD; + } + ct = &info->password->cleartext_blob; + + if (info->domain_info.dns_domain.string != NULL) { + realm = strupper_talloc(frame, + info->domain_info.dns_domain.string); + if (realm == NULL) { + TALLOC_FREE(frame); + return ENOMEM; + } + } + + ZERO_STRUCT(kt_entry); + ZERO_STRUCT(kt_cursor); + + /* check if the keytab already has any entry */ + ret = krb5_kt_start_seq_get(krbctx, *keytab, &kt_cursor); + if (ret != 0) { + goto out; + } + + /* check if we have our special enctype used to hold + * the clear text password. If so, check it out so that + * we can verify if the keytab needs to be upgraded */ + while ((ret = krb5_kt_next_entry(krbctx, *keytab, + &kt_entry, &kt_cursor)) == 0) { + if (smb_krb5_kt_get_enctype_from_entry(&kt_entry) == + CLEARTEXT_PRIV_ENCTYPE) { + break; + } + smb_krb5_kt_free_entry(krbctx, &kt_entry); + ZERO_STRUCT(kt_entry); + } + + ret2 = krb5_kt_end_seq_get(krbctx, *keytab, &kt_cursor); + if (ret2 != 0) { + ret = ret2; + DEBUG(1, (__location__ ": krb5_kt_end_seq_get() " + "failed (%s)\n", error_message(ret))); + goto out; + } + + if (ret != 0 && ret != KRB5_KT_END && ret != ENOENT ) { + /* Error parsing keytab */ + DEBUG(1, (__location__ ": Failed to parse memory " + "keytab!\n")); + goto out; + } + + if (ret == 0) { + /* found private entry, + * check if keytab is up to date */ + + if ((ct->length == KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry))) && + (mem_equal_const_time(KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)), + ct->data, ct->length))) { + /* keytab is already up to date, return */ + smb_krb5_kt_free_entry(krbctx, &kt_entry); + goto out; + } + + smb_krb5_kt_free_entry(krbctx, &kt_entry); + ZERO_STRUCT(kt_entry); + + + /* flush keytab, we need to regen it */ + ret = flush_keytab(krbctx, *keytab); + if (ret) { + DEBUG(1, (__location__ ": Failed to flush " + "memory keytab!\n")); + goto out; + } + } + + /* keytab is not up to date, fill it up */ + + ret = smb_krb5_make_principal(krbctx, &princ, realm, + info->account_name, NULL); + if (ret) { + DEBUG(1, (__location__ ": Failed to get host principal!\n")); + goto out; + } + + ret = fill_keytab_from_password(krbctx, *keytab, + princ, kvno, + info->password); + if (ret) { + DBG_WARNING("fill_keytab_from_password() failed for " + "info->password.\n."); + goto out; + } + + if (info->old_password != NULL) { + ret = fill_keytab_from_password(krbctx, *keytab, + princ, kvno - 1, + info->old_password); + if (ret) { + DBG_WARNING("fill_keytab_from_password() failed for " + "info->old_password.\n."); + goto out; + } + } + + if (info->older_password != NULL) { + ret = fill_keytab_from_password(krbctx, *keytab, + princ, kvno - 2, + info->older_password); + if (ret) { + DBG_WARNING("fill_keytab_from_password() failed for " + "info->older_password.\n."); + goto out; + } + } + + if (info->next_change != NULL) { + ret = fill_keytab_from_password(krbctx, *keytab, + princ, kvno - 3, + info->next_change->password); + if (ret) { + DBG_WARNING("fill_keytab_from_password() failed for " + "info->next_change->password.\n."); + goto out; + } + } + + /* add our private enctype + cleartext password so that we can + * update the keytab if secrets change later on */ + ZERO_STRUCT(kt_entry); + kt_entry.principal = princ; + kt_entry.vno = 0; + + KRB5_KEY_TYPE(KRB5_KT_KEY(&kt_entry)) = CLEARTEXT_PRIV_ENCTYPE; + KRB5_KEY_LENGTH(KRB5_KT_KEY(&kt_entry)) = ct->length; + KRB5_KEY_DATA(KRB5_KT_KEY(&kt_entry)) = ct->data; + + ret = krb5_kt_add_entry(krbctx, *keytab, &kt_entry); + if (ret) { + DEBUG(1, (__location__ ": Failed to add entry to " + "keytab for private enctype (%d) (error: %s)\n", + CLEARTEXT_PRIV_ENCTYPE, error_message(ret))); + goto out; + } + + ret = 0; + +out: + + if (princ) { + krb5_free_principal(krbctx, princ); + } + + TALLOC_FREE(frame); + return ret; +} + +static krb5_error_code fill_mem_keytab_from_system_keytab(krb5_context krbctx, + krb5_keytab *mkeytab) +{ + krb5_error_code ret = 0; + krb5_keytab keytab = NULL; + krb5_kt_cursor kt_cursor = { 0, }; + krb5_keytab_entry kt_entry = { 0, }; + char *valid_princ_formats[7] = { NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; + char *entry_princ_s = NULL; + fstring my_name, my_fqdn; + unsigned i; + int err; + + /* Generate the list of principal names which we expect + * clients might want to use for authenticating to the file + * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */ + + fstrcpy(my_name, lp_netbios_name()); + + my_fqdn[0] = '\0'; + name_to_fqdn(my_fqdn, lp_netbios_name()); + + err = asprintf(&valid_princ_formats[0], + "%s$@%s", my_name, lp_realm()); + if (err == -1) { + ret = ENOMEM; + goto out; + } + err = asprintf(&valid_princ_formats[1], + "host/%s@%s", my_name, lp_realm()); + if (err == -1) { + ret = ENOMEM; + goto out; + } + err = asprintf(&valid_princ_formats[2], + "host/%s@%s", my_fqdn, lp_realm()); + if (err == -1) { + ret = ENOMEM; + goto out; + } + err = asprintf(&valid_princ_formats[3], + "host/%s.%s@%s", my_name, lp_realm(), lp_realm()); + if (err == -1) { + ret = ENOMEM; + goto out; + } + err = asprintf(&valid_princ_formats[4], + "cifs/%s@%s", my_name, lp_realm()); + if (err == -1) { + ret = ENOMEM; + goto out; + } + err = asprintf(&valid_princ_formats[5], + "cifs/%s@%s", my_fqdn, lp_realm()); + if (err == -1) { + ret = ENOMEM; + goto out; + } + err = asprintf(&valid_princ_formats[6], + "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()); + if (err == -1) { + ret = ENOMEM; + goto out; + } + + ret = smb_krb5_kt_open_relative(krbctx, NULL, false, &keytab); + if (ret) { + DEBUG(1, ("smb_krb5_kt_open failed (%s)\n", + error_message(ret))); + goto out; + } + + /* + * Iterate through the keytab. For each key, if the principal + * name case-insensitively matches one of the allowed formats, + * copy it to the memory keytab. + */ + + ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor); + if (ret) { + DEBUG(1, (__location__ ": krb5_kt_start_seq_get failed (%s)\n", + error_message(ret))); + /* + * krb5_kt_start_seq_get() may leaves bogus data + * in kt_cursor. And we want to use the all_zero() + * logic below. + * + * See bug #10490 + */ + ZERO_STRUCT(kt_cursor); + goto out; + } + + while ((krb5_kt_next_entry(krbctx, keytab, + &kt_entry, &kt_cursor) == 0)) { + ret = smb_krb5_unparse_name(talloc_tos(), krbctx, + kt_entry.principal, + &entry_princ_s); + if (ret) { + DEBUG(1, (__location__ ": smb_krb5_unparse_name " + "failed (%s)\n", error_message(ret))); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { + + if (!strequal(entry_princ_s, valid_princ_formats[i])) { + continue; + } + + ret = krb5_kt_add_entry(krbctx, *mkeytab, &kt_entry); + if (ret) { + DEBUG(1, (__location__ ": smb_krb5_unparse_name " + "failed (%s)\n", error_message(ret))); + goto out; + } + } + + /* Free the name we parsed. */ + TALLOC_FREE(entry_princ_s); + + /* Free the entry we just read. */ + smb_krb5_kt_free_entry(krbctx, &kt_entry); + ZERO_STRUCT(kt_entry); + } + krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor); + + ZERO_STRUCT(kt_cursor); + +out: + + for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { + SAFE_FREE(valid_princ_formats[i]); + } + + TALLOC_FREE(entry_princ_s); + + if (!all_zero((uint8_t *)&kt_entry, sizeof(kt_entry))) { + smb_krb5_kt_free_entry(krbctx, &kt_entry); + } + + if (!all_zero((uint8_t *)&kt_cursor, sizeof(kt_cursor)) && keytab) { + krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor); + } + + if (keytab) { + krb5_kt_close(krbctx, keytab); + } + + return ret; +} + +static krb5_error_code fill_mem_keytab_from_dedicated_keytab(krb5_context krbctx, + krb5_keytab *mkeytab) +{ + krb5_error_code ret = 0; + krb5_keytab keytab = NULL; + krb5_kt_cursor kt_cursor; + krb5_keytab_entry kt_entry; + + ret = smb_krb5_kt_open(krbctx, lp_dedicated_keytab_file(), + false, &keytab); + if (ret) { + DEBUG(1, ("smb_krb5_kt_open of %s failed (%s)\n", + lp_dedicated_keytab_file(), + error_message(ret))); + return ret; + } + + /* + * Copy the dedicated keyab to our in-memory keytab. + */ + + ret = krb5_kt_start_seq_get(krbctx, keytab, &kt_cursor); + if (ret) { + DEBUG(1, (__location__ ": krb5_kt_start_seq_get on %s " + "failed (%s)\n", + lp_dedicated_keytab_file(), + error_message(ret))); + goto out; + } + + while ((krb5_kt_next_entry(krbctx, keytab, + &kt_entry, &kt_cursor) == 0)) { + + ret = krb5_kt_add_entry(krbctx, *mkeytab, &kt_entry); + + /* Free the entry we just read. */ + smb_krb5_kt_free_entry(krbctx, &kt_entry); + + if (ret) { + DEBUG(1, (__location__ ": smb_krb5_unparse_name " + "failed (%s)\n", error_message(ret))); + break; + } + } + krb5_kt_end_seq_get(krbctx, keytab, &kt_cursor); + +out: + + krb5_kt_close(krbctx, keytab); + + return ret; +} + +krb5_error_code gse_krb5_get_server_keytab(krb5_context krbctx, + krb5_keytab *keytab) +{ + krb5_error_code ret = 0; + krb5_error_code ret1 = 0; + krb5_error_code ret2 = 0; + + *keytab = NULL; + + /* create memory keytab */ + ret = krb5_kt_resolve(krbctx, SRV_MEM_KEYTAB_NAME, keytab); + if (ret) { + DEBUG(1, (__location__ ": Failed to get memory " + "keytab!\n")); + return ret; + } + + switch (lp_kerberos_method()) { + default: + case KERBEROS_VERIFY_SECRETS: + ret = fill_mem_keytab_from_secrets(krbctx, keytab); + break; + case KERBEROS_VERIFY_SYSTEM_KEYTAB: + ret = fill_mem_keytab_from_system_keytab(krbctx, keytab); + break; + case KERBEROS_VERIFY_DEDICATED_KEYTAB: + /* just use whatever keytab is configured */ + ret = fill_mem_keytab_from_dedicated_keytab(krbctx, keytab); + break; + case KERBEROS_VERIFY_SECRETS_AND_KEYTAB: + ret1 = fill_mem_keytab_from_secrets(krbctx, keytab); + if (ret1) { + DEBUG(3, (__location__ ": Warning! Unable to set mem " + "keytab from secrets!\n")); + } + /* Now append system keytab keys too */ + ret2 = fill_mem_keytab_from_system_keytab(krbctx, keytab); + if (ret2) { + DEBUG(3, (__location__ ": Warning! Unable to set mem " + "keytab from system keytab!\n")); + } + if (ret1 == 0 || ret2 == 0) { + ret = 0; + } else { + ret = ret1; + } + break; + } + + if (ret) { + krb5_kt_close(krbctx, *keytab); + *keytab = NULL; + DEBUG(1,("%s: Error! Unable to set mem keytab - %d\n", + __location__, ret)); + } + + return ret; +} + +#endif /* HAVE_KRB5 */ diff --git a/source3/librpc/crypto/gse_krb5.h b/source3/librpc/crypto/gse_krb5.h new file mode 100644 index 0000000..ea789c9 --- /dev/null +++ b/source3/librpc/crypto/gse_krb5.h @@ -0,0 +1,30 @@ +/* + * GSSAPI Security Extensions + * Krb5 helpers + * Copyright (C) Simo Sorce 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _GSE_KRB5_H_ +#define _GSE_KRB5_H_ + +#ifdef HAVE_KRB5 + +krb5_error_code gse_krb5_get_server_keytab(krb5_context krbctx, + krb5_keytab *keytab); + +#endif /* HAVE_KRB5 */ + +#endif /* _GSE_KRB5_H_ */ diff --git a/source3/librpc/gen_ndr/README b/source3/librpc/gen_ndr/README new file mode 100644 index 0000000..5ccb89d --- /dev/null +++ b/source3/librpc/gen_ndr/README @@ -0,0 +1,4 @@ +This contains the generated files from PIDL for the IDL files in ../idl/*.idl + +DO NOT REMOVE THIS FILE. The waf 1.5 build relies on this directory +existing in the source tree. diff --git a/source3/librpc/idl/IDL_LICENSE.txt b/source3/librpc/idl/IDL_LICENSE.txt new file mode 100644 index 0000000..01ae670 --- /dev/null +++ b/source3/librpc/idl/IDL_LICENSE.txt @@ -0,0 +1,9 @@ +The IDL files in this directory are made available by the Samba Team +under the following license: + + Permission to use, copy, modify, and distribute these interface + definitions for any purpose is hereby granted without fee. + + This work is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/source3/librpc/idl/leases_db.idl b/source3/librpc/idl/leases_db.idl new file mode 100644 index 0000000..2551dfc --- /dev/null +++ b/source3/librpc/idl/leases_db.idl @@ -0,0 +1,54 @@ +#include "idl_types.h" + +import "misc.idl"; +import "smb2_lease_struct.idl"; +import "file_id.idl"; + +[ + pointer_default(unique) +] +interface leases_db +{ + typedef [public] struct { + GUID client_guid; + smb2_lease_key lease_key; + } leases_db_key; + + typedef [public] struct { + file_id id; + [string,charset(UTF8)] char *servicepath; + [string,charset(UTF8)] char *base_name; + [string,charset(UTF8)] char *stream_name; + } leases_db_file; + + typedef [public] struct { + smb2_lease_state current_state; + /* + * 'breaking' indicates that we're waiting + * for a lease break ack from the client + * and breaking_to_requested and breaking_to_required + * have a meaning. + * + * breaking_to_requested is the value already sent to + * the client, the client needs to ack to this (or less). + * + * breaking_to_required is the internal value that needs to + * be reached before we can reset breaking = false, this + * may requires multiple roundtrips to the client, e.g. + * when the lease broken to a more reduced value, while + * the lease break is still in progress. + * + * The following can be assumed (if breaking == true): + * + * current_state>breaking_to_requested>=breaking_to_required + */ + boolean8 breaking; + smb2_lease_state breaking_to_requested; + smb2_lease_state breaking_to_required; + uint16 lease_version; + uint16 epoch; + + uint32 num_files; + leases_db_file files[num_files]; + } leases_db_value; +} diff --git a/source3/librpc/idl/libnet_join.idl b/source3/librpc/idl/libnet_join.idl new file mode 100644 index 0000000..f1dc603 --- /dev/null +++ b/source3/librpc/idl/libnet_join.idl @@ -0,0 +1,92 @@ +#include "idl_types.h" + +import "wkssvc.idl", "security.idl", "misc.idl", "netlogon.idl", "ODJ.idl"; + +/* + libnetjoin interface definition +*/ + +[ + pointer_default(unique), + helper("ads.h") +] +interface libnetjoin +{ + typedef bitmap wkssvc_joinflags wkssvc_joinflags; + typedef enum netr_SchannelType netr_SchannelType; + + typedef [public] enum { + JoinDomNameTypeUnknown = 0, + JoinDomNameTypeDNS = 1, + JoinDomNameTypeNBT = 2 + } libnetjoin_JoinDomNameType; + + [nopush,nopull,noopnum] WERROR libnet_JoinCtx( + [in] string dc_name, + [in] string machine_name, + [in,ref] string *domain_name, + [in] libnetjoin_JoinDomNameType domain_name_type, + [in] string account_ou, + [in] string admin_account, + [in] string admin_domain, + [in,noprint] string admin_password, + [in] string machine_password, + [in] wkssvc_joinflags join_flags, + [in] string os_version, + [in] string os_name, + [in] string os_servicepack, + [in] boolean8 create_upn, + [in] string upn, + [in] string dnshostname, + [in] boolean8 modify_config, + [in,unique] ads_struct *ads, + [in] boolean8 debug, + [in] boolean8 use_kerberos, + [in] netr_SchannelType secure_channel_type, + [in,noprint] messaging_context *msg_ctx, + [in] uint32 desired_encryption_types, + [in] boolean8 provision_computer_account_only, + [in,out,unique] ODJ_PROVISION_DATA *odj_provision_data, + [in] boolean8 request_offline_join, + [out] string account_name, + [out] string netbios_domain_name, + [out] string dns_domain_name, + [out] string forest_name, + [out] string dn, + [out] GUID domain_guid, + [out] dom_sid *domain_sid, + [out] boolean8 modified_config, + [out] string error_string, + [out] boolean8 domain_is_ad, + [out] uint32 set_encryption_types, + [out] string krb5_salt, + [out,unique] netr_DsRGetDCNameInfo *dcinfo, + [out] uint32 account_rid + ); + + [nopush,nopull,noopnum] WERROR libnet_UnjoinCtx( + [in] string dc_name, + [in] string machine_name, + [in] string domain_name, + [in] string account_ou, + [in] string admin_account, + [in] string admin_domain, + [in,noprint] string admin_password, + [in] string machine_password, + [in] wkssvc_joinflags unjoin_flags, + [in] boolean8 delete_machine_account, + [in] boolean8 modify_config, + [in] dom_sid *domain_sid, + [in,unique] ads_struct *ads, + [in] boolean8 debug, + [in] boolean8 use_kerberos, + [in,noprint] messaging_context *msg_ctx, + [out] string netbios_domain_name, + [out] string dns_domain_name, + [out] string forest_name, + [out] boolean8 modified_config, + [out] string error_string, + [out] boolean8 disabled_machine_account, + [out] boolean8 deleted_machine_account + ); +} diff --git a/source3/librpc/idl/libnetapi.idl b/source3/librpc/idl/libnetapi.idl new file mode 100644 index 0000000..15cac52 --- /dev/null +++ b/source3/librpc/idl/libnetapi.idl @@ -0,0 +1,2050 @@ +/* + libnetapi interface definition +*/ + +cpp_quote("#define LIBNETAPI_LOCAL_SERVER(x) (!x || is_myname_or_ipaddr(x))") +cpp_quote("#ifndef MAXSUBAUTHS") +cpp_quote("#define MAXSUBAUTHS 15 /* max sub authorities in a SID */") +cpp_quote("#endif") + +import "misc.idl"; + +[ + pointer_default(unique) +] +interface libnetapi +{ + const int ERROR_MORE_DATA = 234L; + + [public] typedef [v1_enum] enum { + NERR_Success = 0, + NERR_NoOfflineJoinInfo = 2709, + NERR_BadOfflineJoinInfo = 2710, + NERR_CantCreateJoinInfo = 2711, + NERR_BadDomainJoinInfo = 2712, + NERR_JoinPerformedMustRestart = 2713, + NERR_NoJoinPending = 2714, + NERR_ValuesNotSet = 2715, + NERR_CantVerifyHostname = 2716, + NERR_CantLoadOfflineHive = 2717, + NERR_Connectionsecure = 2718, + NERR_ProvisioningBlobUnsupported = 2719 + } NET_API_STATUS; + + [public] typedef struct { + uint8 sid_rev_num; + uint8 num_auths; + uint8 id_auth[6]; + uint32 sub_auths[MAXSUBAUTHS]; + } domsid; + + /*******************************************/ + /* NetJoinDomain */ + /*******************************************/ + + typedef [public,bitmap32bit] bitmap { + NETSETUP_JOIN_DOMAIN = 0x00000001, + NETSETUP_ACCT_CREATE = 0x00000002, + NETSETUP_ACCT_DELETE = 0x00000004, + NETSETUP_WIN9X_UPGRADE = 0x00000010, + NETSETUP_DOMAIN_JOIN_IF_JOINED = 0x00000020, + NETSETUP_JOIN_UNSECURE = 0x00000040, + NETSETUP_MACHINE_PWD_PASSED = 0x00000080, + NETSETUP_DEFER_SPN_SET = 0x00000100, + NETSETUP_JOIN_DC_ACCOUNT = 0x00000200, + NETSETUP_JOIN_WITH_NEW_NAME = 0x00000400, + NETSETUP_JOIN_READONLY = 0x00000800, + NETSETUP_AMBIGUOUS_DC = 0x00001000, + NETSETUP_NO_NETLOGON_CACHE = 0x00002000, + NETSETUP_DONT_CONTROL_SERVICES = 0x00004000, + NETSETUP_SET_MACHINE_NAME = 0x00008000, + NETSETUP_FORCE_SPN_SET = 0x00010000, + NETSETUP_NO_ACCT_REUSE = 0x00020000, + NETSETUP_INSTALL_INVOCATION = 0x00040000, + NETSETUP_IGNORE_UNSUPPORTED_FLAGS = 0x10000000 + } NetJoinFlags; + + [nopush,nopull] NET_API_STATUS NetJoinDomain( + [in,unique] string *server, + [in,ref] string *domain, + [in,unique] string *account_ou, + [in,unique] string *account, + [in,unique] string *password, + [in] NetJoinFlags join_flags + ); + + /*******************************************/ + /* NetUnjoinDomain */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetUnjoinDomain( + [in,unique] string *server_name, + [in,unique] string *account, + [in,unique] string *password, + [in] NetJoinFlags unjoin_flags + ); + + /*******************************************/ + /* NetGetJoinInformation */ + /*******************************************/ + + typedef enum { + NetSetupUnknownStatus = 0, + NetSetupUnjoined = 1, + NetSetupWorkgroupName = 2, + NetSetupDomainName = 3 + } NETSETUP_JOIN_STATUS; + + [nopush,nopull] NET_API_STATUS NetGetJoinInformation( + [in,unique] string *server_name, + [out] string **name_buffer, + [out] uint16 *name_type + ); + + /*******************************************/ + /* NetGetJoinableOUs */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGetJoinableOUs( + [in,unique] string *server_name, + [in,ref] string *domain, + [in,unique] string *account, + [in,unique] string *password, + [out] uint32 *ou_count, + [out] string ***ous + ); + + /*******************************************/ + /* NetRenameMachineInDomain */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetRenameMachineInDomain( + [in] string server_name, + [in] string new_machine_name, + [in] string account, + [in] string password, + [in] uint32 rename_options + ); + + /*******************************************/ + /* NetProvisionComputerAccount */ + /*******************************************/ + + typedef [public,bitmap32bit] bitmap { + NETSETUP_PROVISION_DOWNLEVEL_PRIV_SUPPORT = 0x00000001, + NETSETUP_PROVISION_REUSE_ACCOUNT = 0x00000002, + NETSETUP_PROVISION_USE_DEFAULT_PASSWORD = 0x00000004, + NETSETUP_PROVISION_SKIP_ACCOUNT_SEARCH = 0x00000008, + NETSETUP_PROVISION_ROOT_CA_CERTS = 0x00000010 + } NetProvisionFlags; + + [nopush,nopull] NET_API_STATUS NetProvisionComputerAccount( + [in,ref] string *domain, + [in,ref] string *machine_name, + [in,unique] string *machine_account_ou, + [in,unique] string *dcname, + [in] NetProvisionFlags options, + [in,out,unique] uint8 **provision_bin_data, + [in,out,unique] uint32 *provision_bin_data_size, + [in,out,unique] string **provision_text_data + ); + + /*******************************************/ + /* NetRequestOfflineDomainJoin */ + /*******************************************/ + + typedef [public,bitmap32bit] bitmap { + NETSETUP_PROVISION_ONLINE_CALLER = 0x40000000 + } NetProvisionJoinFlags; + + [nopush,nopull] NET_API_STATUS NetRequestOfflineDomainJoin( + [in,unique] uint8 *provision_bin_data, + [in] uint32 provision_bin_data_size, + [in] NetProvisionJoinFlags options, + [in,unique] string *windows_path + ); + + /*******************************************/ + /* NetServerGetInfo */ + /*******************************************/ + + [public] typedef struct { + uint32 sv100_platform_id; + string sv100_name; + } SERVER_INFO_100; + + [public] typedef struct { + uint32 sv101_platform_id; + string sv101_name; + uint32 sv101_version_major; + uint32 sv101_version_minor; + uint32 sv101_type; + string sv101_comment; + } SERVER_INFO_101; + + [public] typedef struct { + uint32 sv102_platform_id; + string sv102_name; + uint32 sv102_version_major; + uint32 sv102_version_minor; + uint32 sv102_type; + string sv102_comment; + uint32 sv102_users; + uint32 sv102_disc; + boolean8 sv102_hidden; + uint32 sv102_announce; + uint32 sv102_anndelta; + uint32 sv102_licenses; + string sv102_userpath; + } SERVER_INFO_102; + + [public] typedef struct { + uint32 sv402_ulist_mtime; + uint32 sv402_glist_mtime; + uint32 sv402_alist_mtime; + string sv402_alerts; + uint32 sv402_security; + uint32 sv402_numadmin; + uint32 sv402_lanmask; + string sv402_guestacct; + uint32 sv402_chdevs; + uint32 sv402_chdevq; + uint32 sv402_chdevjobs; + uint32 sv402_connections; + uint32 sv402_shares; + uint32 sv402_openfiles; + uint32 sv402_sessopens; + uint32 sv402_sessvcs; + uint32 sv402_sessreqs; + uint32 sv402_opensearch; + uint32 sv402_activelocks; + uint32 sv402_numreqbuf; + uint32 sv402_sizreqbuf; + uint32 sv402_numbigbuf; + uint32 sv402_numfiletasks; + uint32 sv402_alertsched; + uint32 sv402_erroralert; + uint32 sv402_logonalert; + uint32 sv402_accessalert; + uint32 sv402_diskalert; + uint32 sv402_netioalert; + uint32 sv402_maxauditsz; + string sv402_srvheuristics; + } SERVER_INFO_402; + + [public] typedef struct { + uint32 sv403_ulist_mtime; + uint32 sv403_glist_mtime; + uint32 sv403_alist_mtime; + string sv403_alerts; + uint32 sv403_security; + uint32 sv403_numadmin; + uint32 sv403_lanmask; + string sv403_guestacct; + uint32 sv403_chdevs; + uint32 sv403_chdevq; + uint32 sv403_chdevjobs; + uint32 sv403_connections; + uint32 sv403_shares; + uint32 sv403_openfiles; + uint32 sv403_sessopens; + uint32 sv403_sessvcs; + uint32 sv403_sessreqs; + uint32 sv403_opensearch; + uint32 sv403_activelocks; + uint32 sv403_numreqbuf; + uint32 sv403_sizreqbuf; + uint32 sv403_numbigbuf; + uint32 sv403_numfiletasks; + uint32 sv403_alertsched; + uint32 sv403_erroralert; + uint32 sv403_logonalert; + uint32 sv403_accessalert; + uint32 sv403_diskalert; + uint32 sv403_netioalert; + uint32 sv403_maxauditsz; + string sv403_srvheuristics; + uint32 sv403_auditedevents; + uint32 sv403_autoprofile; + string sv403_autopath; + } SERVER_INFO_403; + + [public] typedef struct { + uint32 sv502_sessopens; + uint32 sv502_sessvcs; + uint32 sv502_opensearch; + uint32 sv502_sizreqbuf; + uint32 sv502_initworkitems; + uint32 sv502_maxworkitems; + uint32 sv502_rawworkitems; + uint32 sv502_irpstacksize; + uint32 sv502_maxrawbuflen; + uint32 sv502_sessusers; + uint32 sv502_sessconns; + uint32 sv502_maxpagedmemoryusage; + uint32 sv502_maxnonpagedmemoryusage; + boolean8 sv502_enablesoftcompat; + boolean8 sv502_enableforcedlogoff; + boolean8 sv502_timesource; + boolean8 sv502_acceptdownlevelapis; + boolean8 sv502_lmannounce; + } SERVER_INFO_502; + + [public] typedef struct { + uint32 sv503_sessopens; + uint32 sv503_sessvcs; + uint32 sv503_opensearch; + uint32 sv503_sizreqbuf; + uint32 sv503_initworkitems; + uint32 sv503_maxworkitems; + uint32 sv503_rawworkitems; + uint32 sv503_irpstacksize; + uint32 sv503_maxrawbuflen; + uint32 sv503_sessusers; + uint32 sv503_sessconns; + uint32 sv503_maxpagedmemoryusage; + uint32 sv503_maxnonpagedmemoryusage; + boolean8 sv503_enablesoftcompat; + boolean8 sv503_enableforcedlogoff; + boolean8 sv503_timesource; + boolean8 sv503_acceptdownlevelapis; + boolean8 sv503_lmannounce; + string sv503_domain; + uint32 sv503_maxcopyreadlen; + uint32 sv503_maxcopywritelen; + uint32 sv503_minkeepsearch; + uint32 sv503_maxkeepsearch; + uint32 sv503_minkeepcomplsearch; + uint32 sv503_maxkeepcomplsearch; + uint32 sv503_threadcountadd; + uint32 sv503_numblockthreads; + uint32 sv503_scavtimeout; + uint32 sv503_minrcvqueue; + uint32 sv503_minfreeworkitems; + uint32 sv503_xactmemsize; + uint32 sv503_threadpriority; + uint32 sv503_maxmpxct; + uint32 sv503_oplockbreakwait; + uint32 sv503_oplockbreakresponsewait; + boolean8 sv503_enableoplocks; + boolean8 sv503_enableoplockforceclose; + boolean8 sv503_enablefcbopens; + boolean8 sv503_enableraw; + boolean8 sv503_enablesharednetdrives; + uint32 sv503_minfreeconnections; + uint32 sv503_maxfreeconnections; + } SERVER_INFO_503; + + [public] typedef struct { + uint32 sv599_sessopens; + uint32 sv599_sessvcs; + uint32 sv599_opensearch; + uint32 sv599_sizreqbuf; + uint32 sv599_initworkitems; + uint32 sv599_maxworkitems; + uint32 sv599_rawworkitems; + uint32 sv599_irpstacksize; + uint32 sv599_maxrawbuflen; + uint32 sv599_sessusers; + uint32 sv599_sessconns; + uint32 sv599_maxpagedmemoryusage; + uint32 sv599_maxnonpagedmemoryusage; + boolean8 sv599_enablesoftcompat; + boolean8 sv599_enableforcedlogoff; + boolean8 sv599_timesource; + boolean8 sv599_acceptdownlevelapis; + boolean8 sv599_lmannounce; + string sv599_domain; + uint32 sv599_maxcopyreadlen; + uint32 sv599_maxcopywritelen; + uint32 sv599_minkeepsearch; + uint32 sv599_maxkeepsearch; + uint32 sv599_minkeepcomplsearch; + uint32 sv599_maxkeepcomplsearch; + uint32 sv599_threadcountadd; + uint32 sv599_numblockthreads; + uint32 sv599_scavtimeout; + uint32 sv599_minrcvqueue; + uint32 sv599_minfreeworkitems; + uint32 sv599_xactmemsize; + uint32 sv599_threadpriority; + uint32 sv599_maxmpxct; + uint32 sv599_oplockbreakwait; + uint32 sv599_oplockbreakresponsewait; + boolean8 sv599_enableoplocks; + boolean8 sv599_enableoplockforceclose; + boolean8 sv599_enablefcbopens; + boolean8 sv599_enableraw; + boolean8 sv599_enablesharednetdrives; + uint32 sv599_minfreeconnections; + uint32 sv599_maxfreeconnections; + uint32 sv599_initsesstable; + uint32 sv599_initconntable; + uint32 sv599_initfiletable; + uint32 sv599_initsearchtable; + uint32 sv599_alertschedule; + uint32 sv599_errorthreshold; + uint32 sv599_networkerrorthreshold; + uint32 sv599_diskspacethreshold; + uint32 sv599_reserved; + uint32 sv599_maxlinkdelay; + uint32 sv599_minlinkthroughput; + uint32 sv599_linkinfovalidtime; + uint32 sv599_scavqosinfoupdatetime; + uint32 sv599_maxworkitemidletime; + } SERVER_INFO_599; + + [public] typedef struct { + uint32 sv598_maxrawworkitems; + uint32 sv598_maxthreadsperqueue; + uint32 sv598_producttype; + uint32 sv598_serversize; + uint32 sv598_connectionlessautodisc; + uint32 sv598_sharingviolationretries; + uint32 sv598_sharingviolationdelay; + uint32 sv598_maxglobalopensearch; + uint32 sv598_removeduplicatesearches; + uint32 sv598_lockviolationoffset; + uint32 sv598_lockviolationdelay; + uint32 sv598_mdlreadswitchover; + uint32 sv598_cachedopenlimit; + uint32 sv598_otherqueueaffinity; + boolean8 sv598_restrictnullsessaccess; + boolean8 sv598_enablewfw311directipx; + uint32 sv598_queuesamplesecs; + uint32 sv598_balancecount; + uint32 sv598_preferredaffinity; + uint32 sv598_maxfreerfcbs; + uint32 sv598_maxfreemfcbs; + uint32 sv598_maxfreelfcbs; + uint32 sv598_maxfreepagedpoolchunks; + uint32 sv598_minpagedpoolchunksize; + uint32 sv598_maxpagedpoolchunksize; + boolean8 sv598_sendsfrompreferredprocessor; + uint32 sv598_cacheddirectorylimit; + uint32 sv598_maxcopylength; + boolean8 sv598_enablecompression; + boolean8 sv598_autosharewks; + boolean8 sv598_autoshareserver; + boolean8 sv598_enablesecuritysignature; + boolean8 sv598_requiresecuritysignature; + uint32 sv598_minclientbuffersize; + GUID sv598_serverguid; + uint32 sv598_ConnectionNoSessionsTimeout; + uint32 sv598_IdleThreadTimeOut; + boolean8 sv598_enableW9xsecuritysignature; + boolean8 sv598_enforcekerberosreauthentication; + boolean8 sv598_disabledos; + uint32 sv598_lowdiskspaceminimum; + boolean8 sv598_disablestrictnamechecking; + } SERVER_INFO_598; + + [public] typedef struct { + string sv1005_comment; + } SERVER_INFO_1005; + + [public] typedef struct { + uint32 sv1107_users; + } SERVER_INFO_1107; + + [public] typedef struct { + int32 sv1010_disc; + } SERVER_INFO_1010; + + [public] typedef struct { + boolean8 sv1016_hidden; + } SERVER_INFO_1016; + + [public] typedef struct { + uint32 sv1017_announce; + } SERVER_INFO_1017; + + [public] typedef struct { + uint32 sv1018_anndelta; + } SERVER_INFO_1018; + + [public] typedef struct { + uint32 sv1501_sessopens; + } SERVER_INFO_1501; + + [public] typedef struct { + uint32 sv1502_sessvcs; + } SERVER_INFO_1502; + + [public] typedef struct { + uint32 sv1503_opensearch; + } SERVER_INFO_1503; + + [public] typedef struct { + uint32 sv1506_maxworkitems; + } SERVER_INFO_1506; + + [public] typedef struct { + uint32 sv1509_maxrawbuflen; + } SERVER_INFO_1509; + + [public] typedef struct { + uint32 sv1510_sessusers; + } SERVER_INFO_1510; + + [public] typedef struct { + uint32 sv1511_sessconns; + } SERVER_INFO_1511; + + [public] typedef struct { + uint32 sv1512_maxnonpagedmemoryusage; + } SERVER_INFO_1512; + + [public] typedef struct { + uint32 sv1513_maxpagedmemoryusage; + } SERVER_INFO_1513; + + [public] typedef struct { + boolean8 sv1514_enablesoftcompat; + } SERVER_INFO_1514; + + [public] typedef struct { + boolean8 sv1515_enableforcedlogoff; + } SERVER_INFO_1515; + + [public] typedef struct { + boolean8 sv1516_timesource; + } SERVER_INFO_1516; + + [public] typedef struct { + boolean8 sv1518_lmannounce; + } SERVER_INFO_1518; + + [public] typedef struct { + uint32 sv1520_maxcopyreadlen; + } SERVER_INFO_1520; + + [public] typedef struct { + uint32 sv1521_maxcopywritelen; + } SERVER_INFO_1521; + + [public] typedef struct { + uint32 sv1522_minkeepsearch; + } SERVER_INFO_1522; + + [public] typedef struct { + uint32 sv1523_maxkeepsearch; + } SERVER_INFO_1523; + + [public] typedef struct { + uint32 sv1524_minkeepcomplsearch; + } SERVER_INFO_1524; + + [public] typedef struct { + uint32 sv1525_maxkeepcomplsearch; + } SERVER_INFO_1525; + + [public] typedef struct { + uint32 sv1528_scavtimeout; + } SERVER_INFO_1528; + + [public] typedef struct { + uint32 sv1529_minrcvqueue; + } SERVER_INFO_1529; + + [public] typedef struct { + uint32 sv1530_minfreeworkitems; + } SERVER_INFO_1530; + + [public] typedef struct { + uint32 sv1533_maxmpxct; + } SERVER_INFO_1533; + + [public] typedef struct { + uint32 sv1534_oplockbreakwait; + } SERVER_INFO_1534; + + [public] typedef struct { + uint32 sv1535_oplockbreakresponsewait; + } SERVER_INFO_1535; + + [public] typedef struct { + boolean8 sv1536_enableoplocks; + } SERVER_INFO_1536; + + [public] typedef struct { + boolean8 sv1537_enableoplockforceclose; + } SERVER_INFO_1537; + + [public] typedef struct { + boolean8 sv1538_enablefcbopens; + } SERVER_INFO_1538; + + [public] typedef struct { + boolean8 sv1539_enableraw; + } SERVER_INFO_1539; + + [public] typedef struct { + boolean8 sv1540_enablesharednetdrives; + } SERVER_INFO_1540; + + [public] typedef struct { + boolean8 sv1541_minfreeconnections; + } SERVER_INFO_1541; + + [public] typedef struct { + boolean8 sv1542_maxfreeconnections; + } SERVER_INFO_1542; + + [public] typedef struct { + uint32 sv1543_initsesstable; + } SERVER_INFO_1543; + + [public] typedef struct { + uint32 sv1544_initconntable; + } SERVER_INFO_1544; + + [public] typedef struct { + uint32 sv1545_initfiletable; + } SERVER_INFO_1545; + + [public] typedef struct { + uint32 sv1546_initsearchtable; + } SERVER_INFO_1546; + + [public] typedef struct { + uint32 sv1547_alertschedule; + } SERVER_INFO_1547; + + [public] typedef struct { + uint32 sv1548_errorthreshold; + } SERVER_INFO_1548; + + [public] typedef struct { + uint32 sv1549_networkerrorthreshold; + } SERVER_INFO_1549; + + [public] typedef struct { + uint32 sv1550_diskspacethreshold; + } SERVER_INFO_1550; + + [public] typedef struct { + uint32 sv1552_maxlinkdelay; + } SERVER_INFO_1552; + + [public] typedef struct { + uint32 sv1553_minlinkthroughput; + } SERVER_INFO_1553; + + [public] typedef struct { + uint32 sv1554_linkinfovalidtime; + } SERVER_INFO_1554; + + [public] typedef struct { + uint32 sv1555_scavqosinfoupdatetime; + } SERVER_INFO_1555; + + [public] typedef struct { + uint32 sv1556_maxworkitemidletime; + } SERVER_INFO_1556; + + [public] typedef struct { + uint32 sv1557_maxrawworkitems; + } SERVER_INFO_1557; + + [public] typedef struct { + uint32 sv1560_producttype; + } SERVER_INFO_1560; + + [public] typedef struct { + uint32 sv1561_serversize; + } SERVER_INFO_1561; + + [public] typedef struct { + uint32 sv1562_connectionlessautodisc; + } SERVER_INFO_1562; + + [public] typedef struct { + uint32 sv1563_sharingviolationretries; + } SERVER_INFO_1563; + + [public] typedef struct { + uint32 sv1564_sharingviolationdelay; + } SERVER_INFO_1564; + + [public] typedef struct { + uint32 sv1565_maxglobalopensearch; + } SERVER_INFO_1565; + + [public] typedef struct { + boolean8 sv1566_removeduplicatesearches; + } SERVER_INFO_1566; + + [public] typedef struct { + uint32 sv1567_lockviolationretries; + } SERVER_INFO_1567; + + [public] typedef struct { + uint32 sv1568_lockviolationoffset; + } SERVER_INFO_1568; + + [public] typedef struct { + uint32 sv1569_lockviolationdelay; + } SERVER_INFO_1569; + + [public] typedef struct { + uint32 sv1570_mdlreadswitchover; + } SERVER_INFO_1570; + + [public] typedef struct { + uint32 sv1571_cachedopenlimit; + } SERVER_INFO_1571; + + [public] typedef struct { + uint32 sv1572_criticalthreads; + } SERVER_INFO_1572; + + [public] typedef struct { + uint32 sv1573_restrictnullsessaccess; + } SERVER_INFO_1573; + + [public] typedef struct { + uint32 sv1574_enablewfw311directipx; + } SERVER_INFO_1574; + + [public] typedef struct { + uint32 sv1575_otherqueueaffinity; + } SERVER_INFO_1575; + + [public] typedef struct { + uint32 sv1576_queuesamplesecs; + } SERVER_INFO_1576; + + [public] typedef struct { + uint32 sv1577_balancecount; + } SERVER_INFO_1577; + + [public] typedef struct { + uint32 sv1578_preferredaffinity; + } SERVER_INFO_1578; + + [public] typedef struct { + uint32 sv1579_maxfreerfcbs; + } SERVER_INFO_1579; + + [public] typedef struct { + uint32 sv1580_maxfreemfcbs; + } SERVER_INFO_1580; + + [public] typedef struct { + uint32 sv1581_maxfreemlcbs; + } SERVER_INFO_1581; + + [public] typedef struct { + uint32 sv1582_maxfreepagedpoolchunks; + } SERVER_INFO_1582; + + [public] typedef struct { + uint32 sv1583_minpagedpoolchunksize; + } SERVER_INFO_1583; + + [public] typedef struct { + uint32 sv1584_maxpagedpoolchunksize; + } SERVER_INFO_1584; + + [public] typedef struct { + boolean8 sv1585_sendsfrompreferredprocessor; + } SERVER_INFO_1585; + + [public] typedef struct { + uint32 sv1586_maxthreadsperqueue; + } SERVER_INFO_1586; + + [public] typedef struct { + uint32 sv1587_cacheddirectorylimit; + } SERVER_INFO_1587; + + [public] typedef struct { + uint32 sv1588_maxcopylength; + } SERVER_INFO_1588; + + [public] typedef struct { + uint32 sv1590_enablecompression; + } SERVER_INFO_1590; + + [public] typedef struct { + uint32 sv1591_autosharewks; + } SERVER_INFO_1591; + + [public] typedef struct { + uint32 sv1592_autosharewks; + } SERVER_INFO_1592; + + [public] typedef struct { + uint32 sv1593_enablesecuritysignature; + } SERVER_INFO_1593; + + [public] typedef struct { + uint32 sv1594_requiresecuritysignature; + } SERVER_INFO_1594; + + [public] typedef struct { + uint32 sv1595_minclientbuffersize; + } SERVER_INFO_1595; + + [public] typedef struct { + uint32 sv1596_ConnectionNoSessionsTimeout; + } SERVER_INFO_1596; + + [public] typedef struct { + uint32 sv1597_IdleThreadTimeOut; + } SERVER_INFO_1597; + + [public] typedef struct { + uint32 sv1598_enableW9xsecuritysignature; + } SERVER_INFO_1598; + + [public] typedef struct { + boolean8 sv1598_enforcekerberosreauthentication; + } SERVER_INFO_1599; + + [public] typedef struct { + boolean8 sv1598_disabledos; + } SERVER_INFO_1600; + + [public] typedef struct { + uint32 sv1598_lowdiskspaceminimum; + } SERVER_INFO_1601; + + [public] typedef struct { + boolean8 sv_1598_disablestrictnamechecking; + } SERVER_INFO_1602; + + [nopush,nopull] NET_API_STATUS NetServerGetInfo( + [in,unique] string *server_name, + [in] uint32 level, + [out] uint8 **buffer + ); + + /*******************************************/ + /* NetServerSetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetServerSetInfo( + [in,unique] string *server_name, + [in] uint32 level, + [in] uint8 *buffer, + [out] uint32 *parm_error + ); + + /*******************************************/ + /* NetWkstaGetInfo */ + /*******************************************/ + + [public] typedef struct { + uint32 wki100_platform_id; + string wki100_computername; + string wki100_langroup; + uint32 wki100_ver_major; + uint32 wki100_ver_minor; + } WKSTA_INFO_100; + + [public] typedef struct { + uint32 wki101_platform_id; + string wki101_computername; + string wki101_langroup; + uint32 wki101_ver_major; + uint32 wki101_ver_minor; + string wki101_lanroot; + } WKSTA_INFO_101; + + [public] typedef struct { + uint32 wki102_platform_id; + string wki102_computername; + string wki102_langroup; + uint32 wki102_ver_major; + uint32 wki102_ver_minor; + string wki102_lanroot; + uint32 wki102_logged_on_users; + } WKSTA_INFO_102; + + [nopush,nopull] NET_API_STATUS NetWkstaGetInfo( + [in,unique] string *server_name, + [in] uint32 level, + [out] uint8 **buffer + ); + + /*******************************************/ + /* NetGetDCName */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGetDCName( + [in,unique] string *server_name, + [in,unique] string *domain_name, + [out] uint8 **buffer + ); + + /*******************************************/ + /* NetGetAnyDCName */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGetAnyDCName( + [in,unique] string *server_name, + [in,unique] string *domain_name, + [out] uint8 **buffer + ); + + /*******************************************/ + /* DsGetDcName */ + /*******************************************/ + + [public] typedef [bitmap32bit] bitmap { + DS_PDC_FLAG = 0x00000001, + DS_GC_FLAG = 0x00000004, + DS_LDAP_FLAG = 0x00000008, + DS_DS_FLAG = 0x00000010, + DS_KDC_FLAG = 0x00000020, + DS_TIMESERV_FLAG = 0x00000040, + DS_CLOSEST_FLAG = 0x00000080, + DS_WRITABLE_FLAG = 0x00000100, + DS_GOOD_TIMESERV_FLAG = 0x00000200, + DS_NDNC_FLAG = 0x00000400, + DS_SELECT_SECRET_DOMAIN_6_FLAG = 0x00000800, + DS_FULL_SECRET_DOMAIN_6_FLAG = 0x00001000, + DS_WS_FLAG = 0x00002000, + DS_DS_8_FLAG = 0x00004000, + DS_DNS_CONTROLLER_FLAG = 0x20000000, + DS_DNS_DOMAIN_FLAG = 0x40000000, + DS_DNS_FOREST_FLAG = 0x80000000 + } DOMAIN_CONTROLLER_INFO_FLAGS; + + [public] typedef struct { + string domain_controller_name; + string domain_controller_address; + uint32 domain_controller_address_type; + GUID domain_guid; + string domain_name; + string dns_forest_name; + DOMAIN_CONTROLLER_INFO_FLAGS flags; + string dc_site_name; + string client_site_name; + } DOMAIN_CONTROLLER_INFO; + + [nopush,nopull] NET_API_STATUS DsGetDcName( + [in,unique] string *server_name, + [in,ref] string *domain_name, + [in,unique] GUID *domain_guid, + [in,unique] string *site_name, + [in] uint32 flags, + [out,ref] DOMAIN_CONTROLLER_INFO **dc_info + ); + + /*******************************************/ + /* NetUserAdd */ + /*******************************************/ + + [public] typedef struct { + string usri0_name; + } USER_INFO_0; + + /* priv */ + const int USER_PRIV_GUEST = 0; + const int USER_PRIV_USER = 1; + const int USER_PRIV_ADMIN = 2; + + [public] typedef struct { + string usri1_name; + string usri1_password; + uint32 usri1_password_age; + uint32 usri1_priv; + string usri1_home_dir; + string usri1_comment; + uint32 usri1_flags; + string usri1_script_path; + } USER_INFO_1; + + /* auth_flags in USER_INFO_2 */ + + const int AF_OP_PRINT = 0x1; + const int AF_OP_COMM = 0x2; + const int AF_OP_SERVER = 0x4; + const int AF_OP_ACCOUNTS = 0x8; + const int AF_SETTABLE_BITS = (AF_OP_PRINT | AF_OP_COMM | AF_OP_SERVER | AF_OP_ACCOUNTS); + + const int USER_MAXSTORAGE_UNLIMITED = (uint32_t)-1L; + + [public] typedef struct { + string usri2_name; + string usri2_password; + uint32 usri2_password_age; + uint32 usri2_priv; + string usri2_home_dir; + string usri2_comment; + uint32 usri2_flags; + string usri2_script_path; + uint32 usri2_auth_flags; + string usri2_full_name; + string usri2_usr_comment; + string usri2_parms; + string usri2_workstations; + uint32 usri2_last_logon; + uint32 usri2_last_logoff; + uint32 usri2_acct_expires; + uint32 usri2_max_storage; + uint32 usri2_units_per_week; + uint8 *usri2_logon_hours; + uint32 usri2_bad_pw_count; + uint32 usri2_num_logons; + string usri2_logon_server; + uint32 usri2_country_code; + uint32 usri2_code_page; + } USER_INFO_2; + + [public] typedef struct { + string usri3_name; + uint32 usri3_password_age; + uint32 usri3_priv; + string usri3_home_dir; + string usri3_comment; + uint32 usri3_flags; + string usri3_script_path; + uint32 usri3_auth_flags; + string usri3_full_name; + string usri3_usr_comment; + string usri3_parms; + string usri3_workstations; + uint32 usri3_last_logon; + uint32 usri3_last_logoff; + uint32 usri3_acct_expires; + uint32 usri3_max_storage; + uint32 usri3_units_per_week; + uint8 *usri3_logon_hours; + uint32 usri3_bad_pw_count; + uint32 usri3_num_logons; + string usri3_logon_server; + uint32 usri3_country_code; + uint32 usri3_code_page; + uint32 usri3_user_id; + uint32 usri3_primary_group_id; + string usri3_profile; + string usri3_home_dir_drive; + uint32 usri3_password_expired; + } USER_INFO_3; + + [public] typedef struct { + string usri4_name; + string usri4_password; + uint32 usri4_password_age; + uint32 usri4_priv; + string usri4_home_dir; + string usri4_comment; + uint32 usri4_flags; + string usri4_script_path; + uint32 usri4_auth_flags; + string usri4_full_name; + string usri4_usr_comment; + string usri4_parms; + string usri4_workstations; + uint32 usri4_last_logon; + uint32 usri4_last_logoff; + uint32 usri4_acct_expires; + uint32 usri4_max_storage; + uint32 usri4_units_per_week; + uint8 *usri4_logon_hours; + uint32 usri4_bad_pw_count; + uint32 usri4_num_logons; + string usri4_logon_server; + uint32 usri4_country_code; + uint32 usri4_code_page; + domsid *usri4_user_sid; + uint32 usri4_primary_group_id; + string usri4_profile; + string usri4_home_dir_drive; + uint32 usri4_password_expired; + } USER_INFO_4; + + [public] typedef struct { + string usri10_name; + string usri10_comment; + string usri10_usr_comment; + string usri10_full_name; + } USER_INFO_10; + + [public] typedef struct { + string usri11_name; + string usri11_comment; + string usri11_usr_comment; + string usri11_full_name; + uint32 usri11_priv; + uint32 usri11_auth_flags; + uint32 usri11_password_age; + string usri11_home_dir; + string usri11_parms; + uint32 usri11_last_logon; + uint32 usri11_last_logoff; + uint32 usri11_bad_pw_count; + uint32 usri11_num_logons; + string usri11_logon_server; + uint32 usri11_country_code; + string usri11_workstations; + uint32 usri11_max_storage; + uint32 usri11_units_per_week; + uint8 *usri11_logon_hours; + uint32 usri11_code_page; + } USER_INFO_11; + + [public] typedef struct { + string usri20_name; + string usri20_full_name; + string usri20_comment; + uint32 usri20_flags; + uint32 usri20_user_id; + } USER_INFO_20; + + const int ENCRYPTED_PWLEN = 16; + + [public] typedef struct { + uint8 usri21_password[ENCRYPTED_PWLEN]; + } USER_INFO_21; + + [public] typedef struct { + string usri22_name; + uint8 usri22_password[ENCRYPTED_PWLEN]; + uint32 usri22_password_age; + uint32 usri22_priv; + string usri22_home_dir; + string usri22_comment; + uint32 usri22_flags; + uint32 usri22_script_path; + uint32 usri22_auth_flags; + string usri22_full_name; + string usri22_usr_comment; + string usri22_parms; + string usri22_workstations; + uint32 usri22_last_logon; + uint32 usri22_last_logoff; + uint32 usri22_acct_expires; + uint32 usri22_max_storage; + uint32 usri22_units_per_week; + uint8 *usri22_logon_hours; + uint32 usri22_bad_pw_count; + uint32 usri22_num_logons; + string usri22_logon_server; + uint32 usri22_country_code; + uint32 usri22_code_page; + } USER_INFO_22; + + [public] typedef struct { + string usri23_name; + string usri23_full_name; + string usri23_comment; + uint32 usri23_flags; + domsid *usri23_user_sid; + } USER_INFO_23; + + [public] typedef struct { + string usri1003_password; + } USER_INFO_1003; + + [public] typedef struct { + uint32 usri1005_priv; + } USER_INFO_1005; + + [public] typedef struct { + string usri1006_home_dir; + } USER_INFO_1006; + + [public] typedef struct { + string usri1007_comment; + } USER_INFO_1007; + + [public] typedef struct { + uint32 usri1008_flags; + } USER_INFO_1008; + + [public] typedef struct { + string usri1009_script_path; + } USER_INFO_1009; + + [public] typedef struct { + uint32 usri1010_auth_flags; + } USER_INFO_1010; + + [public] typedef struct { + string usri1011_full_name; + } USER_INFO_1011; + + [public] typedef struct { + string usri1012_usr_comment; + } USER_INFO_1012; + + [public] typedef struct { + string usri1013_parms; + } USER_INFO_1013; + + [public] typedef struct { + string usri1014_workstations; + } USER_INFO_1014; + + [public] typedef struct { + uint32 usri1017_acct_expires; + } USER_INFO_1017; + + [public] typedef struct { + uint32 usri1018_max_storage; + } USER_INFO_1018; + + [public] typedef struct { + uint32 usri1020_units_per_week; + uint8 *usri1020_logon_hours; + } USER_INFO_1020; + + [public] typedef struct { + string usri1023_logon_server; + } USER_INFO_1023; + + [public] typedef struct { + uint32 usri1024_country_code; + } USER_INFO_1024; + + [public] typedef struct { + uint32 usri1025_code_page; + } USER_INFO_1025; + + [public] typedef struct { + uint32 usri1051_primary_group_id; + } USER_INFO_1051; + + [public] typedef struct { + string usri1052_profile; + } USER_INFO_1052; + + [public] typedef struct { + string usri1053_home_dir_drive; + } USER_INFO_1053; + + [public] typedef struct { + string usriX_name; + string usriX_password; + uint32 usriX_password_age; + uint32 usriX_priv; + string usriX_home_dir; + string usriX_comment; + uint32 usriX_flags; + string usriX_script_path; + uint32 usriX_auth_flags; + string usriX_full_name; + string usriX_usr_comment; + string usriX_parms; + string usriX_workstations; + uint32 usriX_last_logon; + uint32 usriX_last_logoff; + uint32 usriX_acct_expires; + uint32 usriX_max_storage; + uint32 usriX_units_per_week; + uint8 *usriX_logon_hours; + uint32 usriX_bad_pw_count; + uint32 usriX_num_logons; + string usriX_logon_server; + uint32 usriX_country_code; + uint32 usriX_code_page; + string usriX_profile; + string usriX_home_dir_drive; + uint32 usriX_user_id; + uint32 usriX_primary_group_id; + uint32 usriX_password_expired; + } USER_INFO_X; + + [nopush,nopull] NET_API_STATUS NetUserAdd( + [in,unique] string *server_name, + [in] uint32 level, + [in,ref] uint8 *buffer, + [out,ref] uint32 *parm_error + ); + + /*******************************************/ + /* NetUserDel */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetUserDel( + [in,unique] string *server_name, + [in,ref] string *user_name + ); + + /*******************************************/ + /* NetUserEnum */ + /*******************************************/ + + const int FILTER_TEMP_DUPLICATE_ACCOUNT = 0x0001; + const int FILTER_NORMAL_ACCOUNT = 0x0002; + const int FILTER_INTERDOMAIN_TRUST_ACCOUNT = 0x0008; + const int FILTER_WORKSTATION_TRUST_ACCOUNT = 0x0010; + const int FILTER_SERVER_TRUST_ACCOUNT = 0x0020; + + [nopush,nopull] NET_API_STATUS NetUserEnum( + [in,unique] string *server_name, + [in] uint32 level, + [in] uint32 filter, + [out,ref] uint8 **buffer, + [in] uint32 prefmaxlen, + [out,ref] uint32 *entries_read, + [out,ref] uint32 *total_entries, + [in,out,ref] uint32 *resume_handle + ); + + /*******************************************/ + /* NetUserChangePassword */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetUserChangePassword( + [in] string domain_name, + [in] string user_name, + [in] string old_password, + [in] string new_password + ); + + /*******************************************/ + /* NetUserGetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetUserGetInfo( + [in] string server_name, + [in] string user_name, + [in] uint32 level, + [out] uint8 **buffer + ); + + /*******************************************/ + /* NetUserSetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetUserSetInfo( + [in] string server_name, + [in] string user_name, + [in] uint32 level, + [in] uint8 *buffer, + [out] uint32 *parm_err + ); + + /*******************************************/ + /* NetUserGetGroups */ + /*******************************************/ + + [public] typedef struct { + string grui0_name; + } GROUP_USERS_INFO_0; + + [public] typedef struct { + string grui1_name; + uint32 grui1_attributes; + } GROUP_USERS_INFO_1; + + [nopush,nopull] NET_API_STATUS NetUserGetGroups( + [in] string server_name, + [in] string user_name, + [in] uint32 level, + [out] uint8 **buffer, + [in] uint32 prefmaxlen, + [out,ref] uint32 *entries_read, + [out,ref] uint32 *total_entries + ); + + /*******************************************/ + /* NetUserSetGroups */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetUserSetGroups( + [in] string server_name, + [in] string user_name, + [in] uint32 level, + [in] uint8 *buffer, + [in] uint32 num_entries + ); + + /*******************************************/ + /* NetUserGetLocalGroups */ + /*******************************************/ + + const int LG_INCLUDE_INDIRECT = 0x0001; + + typedef struct { + string lgrui0_name; + } LOCALGROUP_USERS_INFO_0; + + [nopush,nopull] NET_API_STATUS NetUserGetLocalGroups( + [in] string server_name, + [in] string user_name, + [in] uint32 level, + [in] uint32 flags, + [out] uint8 **buffer, + [in] uint32 prefmaxlen, + [out,ref] uint32 *entries_read, + [out,ref] uint32 *total_entries + ); + + /*******************************************/ + /* NetUserModalsGet */ + /*******************************************/ + + const int TIMEQ_FOREVER = (uint32_t)-1L; + + typedef struct { + uint32 usrmod0_min_passwd_len; + uint32 usrmod0_max_passwd_age; + uint32 usrmod0_min_passwd_age; + uint32 usrmod0_force_logoff; + uint32 usrmod0_password_hist_len; + } USER_MODALS_INFO_0; + + typedef struct { + uint32 usrmod1_role; + string usrmod1_primary; + } USER_MODALS_INFO_1; + + typedef struct { + string usrmod2_domain_name; + domsid *usrmod2_domain_id; + } USER_MODALS_INFO_2; + + typedef struct { + uint32 usrmod3_lockout_duration; + uint32 usrmod3_lockout_observation_window; + uint32 usrmod3_lockout_threshold; + } USER_MODALS_INFO_3; + + typedef struct { + uint32 usrmod1001_min_passwd_len; + } USER_MODALS_INFO_1001; + + typedef struct { + uint32 usrmod1002_max_passwd_age; + } USER_MODALS_INFO_1002; + + typedef struct { + uint32 usrmod1003_min_passwd_age; + } USER_MODALS_INFO_1003; + + typedef struct { + uint32 usrmod1004_force_logoff; + } USER_MODALS_INFO_1004; + + typedef struct { + uint32 usrmod1005_password_hist_len; + } USER_MODALS_INFO_1005; + + typedef struct { + uint32 usrmod1006_role; + } USER_MODALS_INFO_1006; + + typedef struct { + string usrmod1007_primary; + } USER_MODALS_INFO_1007; + + [nopush,nopull] NET_API_STATUS NetUserModalsGet( + [in] string server_name, + [in] uint32 level, + [out,ref] uint8 **buffer + ); + + /*******************************************/ + /* NetUserModalsSet */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetUserModalsSet( + [in] string server_name, + [in] uint32 level, + [in] uint8 *buffer, + [out,ref] uint32 *parm_err + ); + + /*******************************************/ + /* NetQueryDisplayInformation */ + /*******************************************/ + + [public] typedef struct { + string usri1_name; + string usri1_comment; + uint32 usri1_flags; + string usri1_full_name; + uint32 usri1_user_id; + uint32 usri1_next_index; + } NET_DISPLAY_USER; + + [public] typedef struct { + string usri2_name; + string usri2_comment; + uint32 usri2_flags; + uint32 usri2_user_id; + uint32 usri2_next_index; + } NET_DISPLAY_MACHINE; + + [public] typedef struct { + string grpi3_name; + string grpi3_comment; + uint32 grpi3_group_id; + uint32 grpi3_attributes; + uint32 grpi3_next_index; + } NET_DISPLAY_GROUP; + + [nopush,nopull] NET_API_STATUS NetQueryDisplayInformation( + [in,unique] string *server_name, + [in] uint32 level, + [in] uint32 idx, + [in] uint32 entries_requested, + [in] uint32 prefmaxlen, + [out,ref] uint32 *entries_read, + [out,ref,noprint] void **buffer + ); + + /*******************************************/ + /* NetGroupAdd */ + /*******************************************/ + + typedef struct { + string grpi0_name; + } GROUP_INFO_0; + + typedef struct { + string grpi1_name; + string grpi1_comment; + } GROUP_INFO_1; + + typedef struct { + string grpi2_name; + string grpi2_comment; + uint32 grpi2_group_id; + uint32 grpi2_attributes; + } GROUP_INFO_2; + + typedef struct { + string grpi3_name; + string grpi3_comment; + domsid *grpi3_group_sid; + uint32 grpi3_attributes; + } GROUP_INFO_3; + + typedef struct { + string grpi1002_comment; + } GROUP_INFO_1002; + + typedef struct { + uint32 grpi1005_attributes; + } GROUP_INFO_1005; + + [nopush,nopull] NET_API_STATUS NetGroupAdd( + [in] string server_name, + [in] uint32 level, + [in] uint8 *buffer, + [out] uint32 *parm_err + ); + + /*******************************************/ + /* NetGroupDel */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupDel( + [in] string server_name, + [in] string group_name + ); + + /*******************************************/ + /* NetGroupEnum */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupEnum( + [in] string server_name, + [in] uint32 level, + [out,ref] uint8 **buffer, + [in] uint32 prefmaxlen, + [out,ref] uint32 *entries_read, + [out,ref] uint32 *total_entries, + [in,out,ref] uint32 *resume_handle + ); + + /*******************************************/ + /* NetGroupSetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupSetInfo( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [in] uint8 *buffer, + [out] uint32 *parm_err + ); + + /*******************************************/ + /* NetGroupGetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupGetInfo( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [out] uint8 **buffer + ); + + /*******************************************/ + /* NetGroupAddUser */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupAddUser( + [in] string server_name, + [in] string group_name, + [in] string user_name + ); + + /*******************************************/ + /* NetGroupDelUser */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupDelUser( + [in] string server_name, + [in] string group_name, + [in] string user_name + ); + + /*******************************************/ + /* NetGroupGetUsers */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupGetUsers( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [out] uint8 **buffer, + [in] uint32 prefmaxlen, + [out,ref] uint32 *entries_read, + [out,ref] uint32 *total_entries, + [in,out,ref] uint32 *resume_handle + ); + + /*******************************************/ + /* NetGroupSetUsers */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetGroupSetUsers( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [in] uint8 *buffer, + [in] uint32 num_entries + ); + + /*******************************************/ + /* NetLocalGroupAdd */ + /*******************************************/ + + typedef struct { + string lgrpi0_name; + } LOCALGROUP_INFO_0; + + typedef struct { + string lgrpi1_name; + string lgrpi1_comment; + } LOCALGROUP_INFO_1; + + typedef struct { + string lgrpi1002_comment; + } LOCALGROUP_INFO_1002; + + [nopush,nopull] NET_API_STATUS NetLocalGroupAdd( + [in] string server_name, + [in] uint32 level, + [in] uint8 *buffer, + [out,ref] uint32 *parm_err + ); + + /*******************************************/ + /* NetLocalGroupDel */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetLocalGroupDel( + [in] string server_name, + [in] string group_name + ); + + /*******************************************/ + /* NetLocalGroupGetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetLocalGroupGetInfo( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [out,ref] uint8 **buffer + ); + + /*******************************************/ + /* NetLocalGroupSetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetLocalGroupSetInfo( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [in,ref] uint8 *buffer, + [out,ref] uint32 *parm_err + ); + + /*******************************************/ + /* NetLocalGroupEnum */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetLocalGroupEnum( + [in] string server_name, + [in] uint32 level, + [out,ref] uint8 **buffer, + [in] uint32 prefmaxlen, + [out,ref] uint32 *entries_read, + [out,ref] uint32 *total_entries, + [in,out,ref] uint32 *resume_handle + ); + + /*******************************************/ + /* NetLocalGroupAddMembers */ + /*******************************************/ + + typedef enum { + SidTypeUser = 1, + SidTypeGroup = 2, + SidTypeDomain = 3, + SidTypeAlias = 4, + SidTypeWellKnownGroup = 5, + SidTypeDeletedAccount = 6, + SidTypeInvalid = 7, + SidTypeUnknown = 8, + SidTypeComputer = 9, + SidTypeLabel = 10 + } SID_NAME_USE; + + typedef struct { + domsid *lgrmi0_sid; + } LOCALGROUP_MEMBERS_INFO_0; + + typedef struct { + domsid *lgrmi1_sid; + SID_NAME_USE lgrmi1_sidusage; + string lgrmi1_name; + } LOCALGROUP_MEMBERS_INFO_1; + + typedef struct { + domsid *lgrmi2_sid; + SID_NAME_USE lgrmi2_sidusage; + string lgrmi2_domainandname; + } LOCALGROUP_MEMBERS_INFO_2; + + typedef struct { + string lgrmi3_domainandname; + } LOCALGROUP_MEMBERS_INFO_3; + + [nopush,nopull] NET_API_STATUS NetLocalGroupAddMembers( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [in] uint8 *buffer, + [in] uint32 total_entries + ); + + /*******************************************/ + /* NetLocalGroupDelMembers */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetLocalGroupDelMembers( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [in] uint8 *buffer, + [in] uint32 total_entries + ); + + /*******************************************/ + /* NetLocalGroupGetMembers */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetLocalGroupGetMembers( + [in] string server_name, + [in] string local_group_name, + [in] uint32 level, + [out] uint8 **buffer, + [in] uint32 prefmaxlen, + [out] uint32 *entries_read, + [out] uint32 *total_entries, + [in,out] uint32 *resume_handle + ); + + /*******************************************/ + /* NetLocalGroupSetMembers */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetLocalGroupSetMembers( + [in] string server_name, + [in] string group_name, + [in] uint32 level, + [in] uint8 *buffer, + [in] uint32 total_entries + ); + + /*******************************************/ + /* NetRemoteTOD */ + /*******************************************/ + + typedef struct { + uint32 tod_elapsedt; + uint32 tod_msecs; + uint32 tod_hours; + uint32 tod_mins; + uint32 tod_secs; + uint32 tod_hunds; + int32 tod_timezone; + uint32 tod_tinterval; + uint32 tod_day; + uint32 tod_month; + uint32 tod_year; + uint32 tod_weekday; + } TIME_OF_DAY_INFO; + + [nopush,nopull] NET_API_STATUS NetRemoteTOD( + [in] string server_name, + [out,ref] uint8 **buffer + ); + + /*******************************************/ + /* NetShareAdd */ + /*******************************************/ + + typedef struct { + string shi0_netname; + } SHARE_INFO_0; + + typedef struct { + string shi1_netname; + uint32 shi1_type; + string shi1_remark; + } SHARE_INFO_1; + + typedef struct { + string shi2_netname; + uint32 shi2_type; + string shi2_remark; + uint32 shi2_permissions; + uint32 shi2_max_uses; + uint32 shi2_current_uses; + string shi2_path; + string shi2_passwd; + } SHARE_INFO_2; + + typedef struct { + string shi501_netname; + uint32 shi501_type; + string shi501_remark; + uint32 shi501_flags; + } SHARE_INFO_501; + + typedef struct { + string shi502_netname; + uint32 shi502_type; + string shi502_remark; + uint32 shi502_permissions; + uint32 shi502_max_uses; + uint32 shi502_current_uses; + string shi502_path; + string shi502_passwd; + uint32 shi502_reserved; + security_descriptor *shi502_security_descriptor; + } SHARE_INFO_502; + + typedef struct { + string shi1004_remark; + } SHARE_INFO_1004; + + const int CSC_MASK = 0x30; + + typedef [public,bitmap32bit] bitmap { + SHI1005_FLAGS_DFS = 0x01, + SHI1005_FLAGS_DFS_ROOT = 0x02, + CSC_CACHE_MANUAL_REINT = 0x00, + CSC_CACHE_AUTO_REINT = 0x10, + CSC_CACHE_VDO = 0x20, + CSC_CACHE_NONE = 0x30, + SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS = 0x0100, + SHI1005_FLAGS_FORCE_SHARED_DELETE = 0x0200, + SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING = 0x0400, + SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM = 0x0800 + } SHARE_INFO_1005_FLAGS; + + typedef struct { + SHARE_INFO_1005_FLAGS shi1005_flags; + } SHARE_INFO_1005; + + typedef struct { + uint32 shi1006_max_uses; + } SHARE_INFO_1006; + + [nopush,nopull] NET_API_STATUS NetShareAdd( + [in] string server_name, + [in] uint32 level, + [in] uint8 *buffer, + [out] uint32 *parm_err + ); + + /*******************************************/ + /* NetShareDel */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetShareDel( + [in] string server_name, + [in] string net_name, + [in] uint32 reserved + ); + + /*******************************************/ + /* NetShareEnum */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetShareEnum( + [in] string server_name, + [in] uint32 level, + [out] uint8 **buffer, + [in] uint32 prefmaxlen, + [out] uint32 *entries_read, + [out] uint32 *total_entries, + [in,out] uint32 *resume_handle + ); + + /*******************************************/ + /* NetShareGetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetShareGetInfo( + [in] string server_name, + [in] string net_name, + [in] uint32 level, + [out] uint8 **buffer + ); + + /*******************************************/ + /* NetShareSetInfo */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetShareSetInfo( + [in] string server_name, + [in] string net_name, + [in] uint32 level, + [in] uint8 *buffer, + [out] uint32 *parm_err + ); + + /*******************************************/ + /* NetFileClose */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetFileClose( + [in] string server_name, + [in] uint32 fileid + ); + + /*******************************************/ + /* NetFileGetInfo */ + /*******************************************/ + + typedef struct { + uint32 fi2_id; + } FILE_INFO_2; + + typedef struct { + uint32 fi3_id; + uint32 fi3_permissions; + uint32 fi3_num_locks; + string fi3_pathname; + string fi3_username; + } FILE_INFO_3; + + [nopush,nopull] NET_API_STATUS NetFileGetInfo( + [in] string server_name, + [in] uint32 fileid, + [in] uint32 level, + [out] uint8 **buffer + ); + + /*******************************************/ + /* NetFileEnum */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetFileEnum( + [in] string server_name, + [in] string base_path, + [in] string user_name, + [in] uint32 level, + [out] uint8 **buffer, + [in] uint32 prefmaxlen, + [out] uint32 *entries_read, + [out] uint32 *total_entries, + [in,out] uint32 *resume_handle + ); + + /*******************************************/ + /* NetShutdownInit */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetShutdownInit( + [in] string server_name, + [in] string message, + [in] uint32 timeout, + [in] uint8 force_apps, + [in] uint8 do_reboot + ); + + /*******************************************/ + /* NetShutdownAbort */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS NetShutdownAbort( + [in] string server_name + ); + + /*******************************************/ + /* I_NetLogonControl */ + /*******************************************/ + + typedef struct { + uint32 netlog1_flags; + NET_API_STATUS netlog1_pdc_connection_status; + } NETLOGON_INFO_1; + + typedef struct { + uint32 netlog2_flags; + NET_API_STATUS netlog2_pdc_connection_status; + string netlog2_trusted_dc_name; + NET_API_STATUS netlog2_tc_connection_status; + } NETLOGON_INFO_2; + + typedef struct { + uint32 netlog1_flags; + uint32 netlog3_logon_attempts; + uint32 netlog3_reserved1; + uint32 netlog3_reserved2; + uint32 netlog3_reserved3; + uint32 netlog3_reserved4; + uint32 netlog3_reserved5; + } NETLOGON_INFO_3; + + typedef struct { + string netlog4_trusted_dc_name; + string netlog4_trusted_domain_name; + } NETLOGON_INFO_4; + + [nopush,nopull] NET_API_STATUS I_NetLogonControl( + [in] string server_name, + [in] uint32 function_code, + [in] uint32 query_level, + [out,ref] uint8 **buffer + ); + + /*******************************************/ + /* I_NetLogonControl2 */ + /*******************************************/ + + [nopush,nopull] NET_API_STATUS I_NetLogonControl2( + [in] string server_name, + [in] uint32 function_code, + [in] uint32 query_level, + [in,unique] uint8 *data, + [out,ref] uint8 **buffer + ); +} diff --git a/source3/librpc/idl/open_files.idl b/source3/librpc/idl/open_files.idl new file mode 100644 index 0000000..49bc09d --- /dev/null +++ b/source3/librpc/idl/open_files.idl @@ -0,0 +1,124 @@ +#include "idl_types.h" + +import "server_id.idl"; +import "security.idl"; +import "file_id.idl"; +import "smb2_lease_struct.idl"; +import "misc.idl"; + +[ + pointer_default(unique) +] + +interface open_files +{ + typedef [public] struct { + server_id pid; + hyper op_mid; + uint16 op_type; + GUID client_guid; + smb2_lease_key lease_key; + uint32 access_mask; + uint32 share_access; + uint32 private_options; + timeval time; + udlong share_file_id; + uint32 uid; + uint16 flags; + uint32 name_hash; + + /* + * In-memory flag indicating a non-existing pid. We don't want + * to store this share_mode_entry on disk. + */ + [skip] boolean8 stale; + } share_mode_entry; + + typedef [public] struct { + uint32 name_hash; + security_token *delete_nt_token; + security_unix_token *delete_token; + } delete_token; + + typedef [public,bitmap16bit] bitmap { + SHARE_MODE_SHARE_DELETE = 0x100, + SHARE_MODE_SHARE_WRITE = 0x080, + SHARE_MODE_SHARE_READ = 0x040, + SHARE_MODE_ACCESS_DELETE = 0x020, + SHARE_MODE_ACCESS_WRITE = 0x010, + SHARE_MODE_ACCESS_READ = 0x008, + SHARE_MODE_LEASE_HANDLE = 0x004, + SHARE_MODE_LEASE_WRITE = 0x002, + SHARE_MODE_LEASE_READ = 0x001 + } share_mode_flags; + + typedef [public] struct { + hyper unique_content_epoch; + share_mode_flags flags; + [string,charset(UTF8)] char *servicepath; + [string,charset(UTF8)] char *base_name; + [string,charset(UTF8)] char *stream_name; + uint32 num_delete_tokens; + [size_is(num_delete_tokens)] delete_token delete_tokens[]; + NTTIME old_write_time; + NTTIME changed_write_time; + [skip] boolean8 fresh; + [skip] boolean8 modified; + [ignore] file_id id; /* In memory key used to lookup cache. */ + } share_mode_data; + + /* these are 0x30 (48) characters */ + const string VFS_DEFAULT_DURABLE_COOKIE_MAGIC = + "VFS_DEFAULT_DURABLE_COOKIE_MAGIC "; + const uint32 VFS_DEFAULT_DURABLE_COOKIE_VERSION = 0; + + /* this corresponds to struct stat_ex (SMB_STRUCT_STAT) */ + typedef struct { + hyper st_ex_dev; + hyper st_ex_ino; + hyper st_ex_mode; + hyper st_ex_nlink; + hyper st_ex_uid; + hyper st_ex_gid; + hyper st_ex_rdev; + hyper st_ex_size; + timespec st_ex_atime; + timespec st_ex_mtime; + timespec st_ex_ctime; + timespec st_ex_btime; + hyper st_ex_blksize; + hyper st_ex_blocks; + uint32 st_ex_flags; + uint32 st_ex_iflags; + } vfs_default_durable_stat; + + typedef [public] struct { + [value(VFS_DEFAULT_DURABLE_COOKIE_MAGIC),charset(DOS)] uint8 magic[0x30]; + [value(VFS_DEFAULT_DURABLE_COOKIE_VERSION)] uint32 version; + boolean8 allow_reconnect; + file_id id; + [string,charset(UTF8)] char *servicepath; + [string,charset(UTF8)] char *base_name; + hyper initial_allocation_size; + hyper position_information; + boolean8 update_write_time_triggered; + boolean8 update_write_time_on_close; + boolean8 write_time_forced; + NTTIME close_write_time; + vfs_default_durable_stat stat_info; + } vfs_default_durable_cookie; + + typedef [public] struct { + file_id id; + udlong share_file_id; + uint8 break_to; + } oplock_break_message; + + typedef [public] struct { + file_id id; + udlong share_file_id; + [string,charset(UTF8)] char *servicepath; + [string,charset(UTF8)] char *base_name; + [string,charset(UTF8)] char *stream_name; + } file_rename_message; +} diff --git a/source3/librpc/idl/perfcount.idl b/source3/librpc/idl/perfcount.idl new file mode 100644 index 0000000..e797e01 --- /dev/null +++ b/source3/librpc/idl/perfcount.idl @@ -0,0 +1,172 @@ +#include "idl_types.h" + +/* + IDL structures for perfcount code +*/ + +[ + pointer_default(unique) +] + interface perfcount +{ + const int PERF_NO_INSTANCES = -1; + const int PERF_NO_UNIQUE_ID = -1; + + /* These determine the data size */ + const int PERF_SIZE_DWORD = 0x00000000; + const int PERF_SIZE_LARGE = 0x00000100; + const int PERF_SIZE_ZERO = 0x00000200; + const int PERF_SIZE_VARIABLE_LEN = 0x00000300; + + /* These determine the usage of the counter */ + const int PERF_TYPE_NUMBER = 0x00000000; + const int PERF_TYPE_COUNTER = 0x00000400; + const int PERF_TYPE_TEXT = 0x00000800; + const int PERF_TYPE_ZERO = 0x00000C00; + + /* If PERF_TYPE_NUMBER was selected, these provide display information */ + const int PERF_NUMBER_HEX = 0x00000000; + const int PERF_NUMBER_DECIMAL = 0x00010000; + const int PERF_NUMBER_DEC_1000 = 0x00020000; + + /* If PERF_TYPE_COUNTER was selected, these provide display information */ + const int PERF_COUNTER_VALUE = 0x00000000; + const int PERF_COUNTER_RATE = 0x00010000; + const int PERF_COUNTER_FRACTION = 0x00020000; + const int PERF_COUNTER_BASE = 0x00030000; + const int PERF_COUNTER_ELAPSED = 0x00040000; + const int PERF_COUNTER_QUEUELEN = 0x00050000; + const int PERF_COUNTER_HISTOGRAM = 0x00060000; + const int PERF_COUNTER_PRECISION = 0x00070000; + + /* If PERF_TYPE_TEXT was selected, these provide display information */ + const int PERF_TEXT_UNICODE = 0x00000000; + const int PERF_TEXT_ASCII = 0x00010000; + + /* These provide information for which tick count to use when computing elapsed interval */ + const int PERF_TIMER_TICK = 0x00000000; + const int PERF_TIMER_100NS = 0x00100000; + const int PERF_OBJECT_TIMER = 0x00200000; + + /* These affect how the data is manipulated prior to being displayed */ + const int PERF_DELTA_COUNTER = 0x00400000; + const int PERF_DELTA_BASE = 0x00800000; + const int PERF_INVERSE_COUNTER = 0x01000000; + const int PERF_MULTI_COUNTER = 0x02000000; + + /* These determine if any text gets added when the value is displayed */ + const int PERF_DISPLAY_NO_SUFFIX = 0x00000000; + const int PERF_DISPLAY_PER_SEC = 0x10000000; + const int PERF_DISPLAY_PERCENT = 0x20000000; + const int PERF_DISPLAY_SECONDS = 0x30000000; + const int PERF_DISPLAY_NOSHOW = 0x40000000; + + /* These determine the DetailLevel of the counter */ + const int PERF_DETAIL_NOVICE = 100; + const int PERF_DETAIL_ADVANCED = 200; + const int PERF_DETAIL_EXPERT = 300; + const int PERF_DETAIL_WIZARD = 400; + + typedef struct { + uint16 year; + uint16 month; + uint16 dayofweek; + uint16 day; + uint16 hour; + uint16 minute; + uint16 second; + uint16 milliseconds; + } SYSTEMTIME; + + typedef [public] struct { + /* sizeof(PERF_COUNTER_DEFINITION) */ + uint32 ByteLength; + uint32 CounterNameTitleIndex; + uint32 CounterNameTitlePointer; + uint32 CounterHelpTitleIndex; + uint32 CounterHelpTitlePointer; + uint32 DefaultScale; + uint32 DetailLevel; + uint32 CounterType; + uint32 CounterSize; + uint32 CounterOffset; + } PERF_COUNTER_DEFINITION; + + typedef [public] struct { + /* Total size of the data block, including all data plus this header */ + uint32 ByteLength; + uint8 data[ByteLength]; + } PERF_COUNTER_BLOCK; + + typedef [public] struct { + /* Total size of the instance definition, including the length of the terminated Name string */ + uint32 ByteLength; + uint32 ParentObjectTitleIndex; + uint32 ParentObjectTitlePointer; + uint32 UniqueID; + /* From the start of the PERF_INSTANCE_DEFINITION, the byte offset to the start of the Name string */ + uint32 NameOffset; + uint32 NameLength; + /* Unicode string containing the name for the instance */ + uint8 *data; + PERF_COUNTER_BLOCK counter_data; + } PERF_INSTANCE_DEFINITION; + + typedef [public] struct { + /* Total size of the object block, including all PERF_INSTANCE_DEFINITIONs, + PERF_COUNTER_DEFINITIONs and PERF_COUNTER_BLOCKs in bytes */ + uint32 TotalByteLength; + /* Size of this PERF_OBJECT_TYPE plus all PERF_COUNTER_DEFINITIONs in bytes */ + uint32 DefinitionLength; + /* Size of this PERF_OBJECT_TYPE */ + uint32 HeaderLength; + uint32 ObjectNameTitleIndex; + uint32 ObjectNameTitlePointer; + uint32 ObjectHelpTitleIndex; + uint32 ObjectHelpTitlePointer; + uint32 DetailLevel; + uint32 NumCounters; + uint32 DefaultCounter; + uint32 NumInstances; + uint32 CodePage; + hyper PerfTime; + hyper PerfFreq; + PERF_COUNTER_DEFINITION counters[NumCounters]; + PERF_INSTANCE_DEFINITION instances[NumInstances]; + PERF_COUNTER_BLOCK counter_data; + } PERF_OBJECT_TYPE; + + /* PerfCounter Inner Buffer structs */ + typedef [public] struct { + /* hardcoded to read "P.E.R.F" */ + uint16 Signature[4]; + uint32 LittleEndian; + /* both currently hardcoded to 1 */ + uint32 Version; + uint32 Revision; + /* bytes of PERF_OBJECT_TYPE data, does NOT include the PERF_DATA_BLOCK */ + uint32 TotalByteLength; + /* size of PERF_DATA_BLOCK including the uint8 *data */ + uint32 HeaderLength; + /* number of PERF_OBJECT_TYPE structures encoded */ + uint32 NumObjectTypes; + uint32 DefaultObject; + SYSTEMTIME SystemTime; + /* This will guarantee that we're on a 64-bit boundary before we encode + PerfTime, and having it there will make my offset math much easier. */ + uint32 Padding; + /* Now when I'm marshalling this, I'll need to call prs_align_uint64() + before I start encoding the uint64 structs */ + /* clock rate * seconds uptime */ + hyper PerfTime; + /* The clock rate of the CPU */ + hyper PerfFreq; + /* used for high-res timers -- for now PerfTime * 10e7 */ + hyper PerfTime100nSec; + uint32 SystemNameLength; + uint32 SystemNameOffset; + /* The SystemName, in unicode, terminated */ + uint8* data; + PERF_OBJECT_TYPE objects[NumObjectTypes]; + } PERF_DATA_BLOCK; +} diff --git a/source3/librpc/idl/rpc_host.idl b/source3/librpc/idl/rpc_host.idl new file mode 100644 index 0000000..b992ca8 --- /dev/null +++ b/source3/librpc/idl/rpc_host.idl @@ -0,0 +1,76 @@ +/** + * @file rpc_host.idl + * + * Definitions for communication between samba-dcerpcd and rpc helper + * daemons + */ +#include "idl_types.h" + +import "named_pipe_auth.idl"; +import "dcerpc.idl"; + +[ + pointer_default(unique) +] + +interface rpc_host_msg +{ + /** + * @brief MSG_RPC_HOST_NEW_CLIENT: samba-dcerpcd->rpcd + * + * samba-dcerpcd to rpcd msg announcing a new client. This + * will carry a file descriptor representing the new + * connection + */ + typedef [public] struct { + /** + * @brief The binding the client wants to connect to + */ + [string,charset(UTF8)] char *binding; + + /** + * @brief Auth info inherited from SMB + */ + named_pipe_auth_req_info7 *npa_info7; + + /** + * @brief Raw bind PDU + * + * Already read from the socket by samba-dcerpcd + */ + DATA_BLOB bind_packet; + } rpc_host_client; + + /** + * @brief MSG_RPC_WORKER_STATUS: rpcd->samba-dcerpcd + * + * Once a client has been handed over from samba-dcerpcd to an + * rpcd, samba-dcerpc has no control over this socket + * anymore. So it can't know when the client exits and the + * rpcd helper process has a slot free. Thus whenever a client + * exits, rpcd sends this message up to samba-dcerpc for a + * status update. + */ + typedef [flag(NDR_NOALIGN),public] struct { + /** + * @brief Which rpc service is this message from + * + * samba-dcerpcd will only have the source pid of this + * message. To avoid a walk through all arrays with + * all rpcd helpers, give samba-dcerpcd a hint where + * in its arrays to find the rpcd that sent this + * message. + */ + uint8 server_index; + + /** + * @brief Which of the processes of a helper prog is this from + */ + uint32 worker_index; + + /** + * @brief How many clients this process serves right now + */ + uint32 num_clients; + } rpc_worker_status; +} diff --git a/source3/librpc/idl/secrets.idl b/source3/librpc/idl/secrets.idl new file mode 100644 index 0000000..2c06fa6 --- /dev/null +++ b/source3/librpc/idl/secrets.idl @@ -0,0 +1,131 @@ +#include "idl_types.h" + +import "misc.idl", "samr.idl", "lsa.idl", "netlogon.idl", "security.idl"; + +/* + IDL structures for secrets code +*/ + +[ + pointer_default(unique) +] + interface secrets +{ + + /* + * s3 on-disc storage structure for trusted domains, do not change ! + */ + + typedef [flag(NDR_NOALIGN),public] struct { + [value(strlen_m_term(uni_name))] uint32 uni_name_len; + [charset(UTF16)] uint16 uni_name[32]; /* unicode domain name */ + [value(strlen(pass))] uint32 pass_len; + astring pass; /* trust relationship's password */ + time_t mod_time; + dom_sid domain_sid; /* remote domain's sid */ + } TRUSTED_DOM_PASS; + + /* + * s3 on-disc storage structure for lsa secrets, do not change ! + */ + + typedef [public] struct { + DATA_BLOB *secret_current; + NTTIME secret_current_lastchange; + DATA_BLOB *secret_old; + NTTIME secret_old_lastchange; + security_descriptor *sd; + } lsa_secret; + + /* + * This is the on-disc format the workstation trust. + * + * DO NOT CHANGE + * without changing secrets_domain_info_version + * and adding glue code. Discuss on samba-technical + * first! + */ + typedef struct { + uint32 keytype; + uint32 iteration_count; + [flag(NDR_SECRET)] DATA_BLOB value; + } secrets_domain_info1_kerberos_key; + + typedef struct { + NTTIME change_time; + [string,charset(UTF16)] uint16 change_server[]; + + [flag(NDR_SECRET)] DATA_BLOB cleartext_blob; + [flag(NDR_SECRET)] samr_Password nt_hash; + + [string,charset(UTF16)] uint16 *salt_data; + uint32 default_iteration_count; + uint16 num_keys; + secrets_domain_info1_kerberos_key keys[num_keys]; + } secrets_domain_info1_password; + + typedef struct { + NTSTATUS local_status; + NTSTATUS remote_status; + NTTIME change_time; + [string,charset(UTF16)] uint16 change_server[]; + [ref] secrets_domain_info1_password *password; + } secrets_domain_info1_change; + + typedef [public] struct { + [value(0)] hyper reserved_flags; + + NTTIME join_time; + + [string,charset(UTF16)] uint16 computer_name[]; + [string,charset(UTF16)] uint16 account_name[]; + netr_SchannelType secure_channel_type; + + lsa_DnsDomainInfo domain_info; + netr_TrustFlags trust_flags; + lsa_TrustType trust_type; + lsa_TrustAttributes trust_attributes; + + /* + * This is unused currently, it might + * be useful to implement multi-tenancy (joining multiple domains) + * in future. + * + * Or we could use it to do other filtering of domains. + */ + [value(NULL)] lsa_ForestTrustInformation *reserved_routing; + + kerb_EncTypes supported_enc_types; + [string,charset(UTF16)] uint16 *salt_principal; + + NTTIME password_last_change; + hyper password_changes; + secrets_domain_info1_change *next_change; + + [ref] secrets_domain_info1_password *password; + secrets_domain_info1_password *old_password; + secrets_domain_info1_password *older_password; + } secrets_domain_info1; + + typedef [v1_enum] enum { + SECRETS_DOMAIN_INFO_VERSION_1 = 0x00000001 + } secrets_domain_info_version; + + /* + * If we ever need to change this we need to + * change secrets_domain_info into + * secrets_domain_info_v1 + */ + typedef union { + [case(SECRETS_DOMAIN_INFO_VERSION_1)] + secrets_domain_info1 *info1; + [default]; + } secrets_domain_infoU; + + typedef [public] struct { + secrets_domain_info_version version; + [value(0)] uint32 reserved; + [switch_is(version)] secrets_domain_infoU info; + } secrets_domain_infoB; +} + diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl new file mode 100644 index 0000000..ec65a5c --- /dev/null +++ b/source3/librpc/idl/smbXsrv.idl @@ -0,0 +1,550 @@ +#include "idl_types.h" + +import "misc.idl"; +import "server_id.idl"; +import "security.idl"; +import "auth.idl"; + +[ + uuid("07408340-ae31-11e1-97dc-539f7fddc06f"), + version(0.0), + pointer_default(unique), + helpstring("smbXsrv structures") +] +interface smbXsrv +{ + /* + * smbXsrv_version* is designed to allow + * rolling code upgrades in future (within a cluster). + * + * This just adds the infrastructure, + * but it does not implement it yet! + * + * Currently it only prevents that + * nodes with a different version numbers + * cannot run at the same time. + * + * Each node checks at startup, if the version + * matches the version of all other nodes. + * And it exits if the version does not match + * to avoid corruption. + * + * While it would be possible to add versioning + * to each of our internal databases it is easier + * use a dedicated database "smbXsrv_version_global.tdb" + * to hold the global version information. + * + * This removes extra complexity from the individual + * databases and allows that we add/remove databases + * or use different indexing keys. + * + */ + typedef [v1_enum] enum { + /* + * NOTE: Version 0 is designed to be unstable and the format + * may change during development. + */ + SMBXSRV_VERSION_0 = 0x00000000 + } smbXsrv_version_values; + + const uint32 SMBXSRV_VERSION_CURRENT = SMBXSRV_VERSION_0; + + typedef struct { + server_id server_id; + smbXsrv_version_values min_version; + smbXsrv_version_values max_version; + smbXsrv_version_values current_version; + } smbXsrv_version_node0; + + typedef struct { + [ignore] db_record *db_rec; + [range(1, 1024)] uint32 num_nodes; + smbXsrv_version_node0 nodes[num_nodes]; + } smbXsrv_version_global0; + + typedef union { + [case(0)] smbXsrv_version_global0 *info0; + [default] hyper *dummy; + } smbXsrv_version_globalU; + + typedef [public] struct { + smbXsrv_version_values version; + uint32 seqnum; + [switch_is(version)] smbXsrv_version_globalU info; + } smbXsrv_version_globalB; + + void smbXsrv_version_global_decode( + [in] smbXsrv_version_globalB blob + ); + + /* client */ + + typedef struct { + [ignore] db_record *db_rec; + server_id server_id; + [charset(UTF8),string] char local_address[]; + [charset(UTF8),string] char remote_address[]; + [charset(UTF8),string] char remote_name[]; + NTTIME initial_connect_time; + GUID client_guid; + boolean8 stored; + } smbXsrv_client_global0; + + typedef union { + [case(0)] smbXsrv_client_global0 *info0; + [default] hyper *dummy; + } smbXsrv_client_globalU; + + typedef [public] struct { + smbXsrv_version_values version; + uint32 seqnum; + [switch_is(version)] smbXsrv_client_globalU info; + } smbXsrv_client_globalB; + + void smbXsrv_client_global_decode( + [in] smbXsrv_client_globalB blob + ); + + typedef [public] struct { + [ignore] smbXsrv_client_table *table; + [ignore] struct tevent_context *raw_ev_ctx; + [ignore] struct messaging_context *msg_ctx; + + [ref] smbXsrv_client_global0 *global; + + /* + * There's just one 'sconn' per client. + * It holds the FSA layer details, which are global + * per client (process). + */ + [ignore] struct smbd_server_connection *sconn; + + /* + * this session_table is used for SMB1 and SMB2, + */ + [ignore] struct smbXsrv_session_table *session_table; + /* + * this tcon_table is only used for SMB1. + */ + [ignore] struct smbXsrv_tcon_table *tcon_table; + /* + * this open_table is used for SMB1 and SMB2, + * because we have a global sconn->real_max_open_files + * limit. + */ + [ignore] struct smbXsrv_open_table *open_table; + + /* + * For now this is only one connection! + * With multi-channel support we'll get more than + * one in future. + */ + [ignore] struct smbXsrv_connection *connections; + boolean8 server_multi_channel_enabled; + hyper next_channel_id; + [ignore] struct tevent_req *connection_pass_subreq; + [ignore] struct tevent_req *connection_drop_subreq; + + /* + * A List of pending breaks. + */ + [ignore] struct smbXsrv_pending_break *pending_breaks; + } smbXsrv_client; + + typedef union { + [case(0)] smbXsrv_client *info0; + [default] hyper *dummy; + } smbXsrv_clientU; + + typedef [public] struct { + smbXsrv_version_values version; + [value(0)] uint32 reserved; + [switch_is(version)] smbXsrv_clientU info; + } smbXsrv_clientB; + + void smbXsrv_client_decode( + [in] smbXsrv_clientB blob + ); + + /* + * smbXsrv_connection_pass is used in the MSG_SMBXSRV_CONNECTION_PASS + * message and echo'ed as MSG_SMBXSRV_CONNECTION_PASSED message with + * negotiate_request.length = 0. + */ + typedef struct { + GUID client_guid; + server_id src_server_id; + NTTIME xconn_connect_time; + server_id dst_server_id; + NTTIME client_connect_time; + DATA_BLOB negotiate_request; + } smbXsrv_connection_pass0; + + typedef union { + [case(0)] smbXsrv_connection_pass0 *info0; + [default] hyper *dummy; + } smbXsrv_connection_passU; + + typedef [public] struct { + smbXsrv_version_values version; + [value(0)] uint32 reserved; + [switch_is(version)] smbXsrv_connection_passU info; + } smbXsrv_connection_passB; + + void smbXsrv_connection_pass_decode( + [in] smbXsrv_connection_passB blob + ); + + /* + * smbXsrv_connection_drop is used in the MSG_SMBXSRV_CONNECTION_DROP + * message as reaction the record is deleted. + */ + typedef struct { + GUID client_guid; + server_id src_server_id; + NTTIME xconn_connect_time; + server_id dst_server_id; + NTTIME client_connect_time; + } smbXsrv_connection_drop0; + + typedef union { + [case(0)] smbXsrv_connection_drop0 *info0; + [default] hyper *dummy; + } smbXsrv_connection_dropU; + + typedef [public] struct { + smbXsrv_version_values version; + [value(0)] uint32 reserved; + [switch_is(version)] smbXsrv_connection_dropU info; + } smbXsrv_connection_dropB; + + void smbXsrv_connection_drop_decode( + [in] smbXsrv_connection_dropB blob + ); + + /* sessions */ + + typedef [public,bitmap8bit] bitmap { + SMBXSRV_ENCRYPTION_REQUIRED = 0x01, + SMBXSRV_ENCRYPTION_DESIRED = 0x02, + SMBXSRV_PROCESSED_ENCRYPTED_PACKET = 0x04, + SMBXSRV_PROCESSED_UNENCRYPTED_PACKET = 0x08 + } smbXsrv_encrpytion_flags; + + typedef [public,bitmap8bit] bitmap { + SMBXSRV_SIGNING_REQUIRED = 0x01, + SMBXSRV_PROCESSED_SIGNED_PACKET = 0x02, + SMBXSRV_PROCESSED_UNSIGNED_PACKET = 0x04 + } smbXsrv_signing_flags; + + typedef struct { + server_id server_id; + hyper channel_id; + NTTIME creation_time; + [charset(UTF8),string] char local_address[]; + [charset(UTF8),string] char remote_address[]; + [charset(UTF8),string] char remote_name[]; + [noprint] DATA_BLOB signing_key_blob; + [ignore] smb2_signing_key *signing_key; + uint32 auth_session_info_seqnum; + [ignore] smbXsrv_connection *connection; + uint16 signing_algo; + uint16 encryption_cipher; + } smbXsrv_channel_global0; + + typedef struct { + [ignore] db_record *db_rec; + uint32 session_global_id; + hyper session_wire_id; + NTTIME creation_time; + NTTIME expiration_time; + /* + * auth_session is NULL until the + * session is valid for the first time. + */ + NTTIME auth_time; + uint32 auth_session_info_seqnum; + auth_session_info *auth_session_info; + uint16 connection_dialect; + smbXsrv_signing_flags signing_flags; + uint16 signing_algo; + smbXsrv_encrpytion_flags encryption_flags; + uint16 encryption_cipher; + [noprint] DATA_BLOB signing_key_blob; + [ignore] smb2_signing_key *signing_key; + [noprint] DATA_BLOB encryption_key_blob; + [ignore] smb2_signing_key *encryption_key; + [noprint] DATA_BLOB decryption_key_blob; + [ignore] smb2_signing_key *decryption_key; + [noprint] DATA_BLOB application_key_blob; + [ignore] smb2_signing_key *application_key; + [range(1, 1024)] uint32 num_channels; + smbXsrv_channel_global0 channels[num_channels]; + } smbXsrv_session_global0; + + typedef union { + [case(0)] smbXsrv_session_global0 *info0; + [default] hyper *dummy; + } smbXsrv_session_globalU; + + typedef [public] struct { + smbXsrv_version_values version; + uint32 seqnum; + [switch_is(version)] smbXsrv_session_globalU info; + } smbXsrv_session_globalB; + + void smbXsrv_session_global_decode( + [in] smbXsrv_session_globalB blob + ); + + /* + * The main server code should just work with + * 'struct smbXsrv_session' and never use + * smbXsrv_session0, smbXsrv_sessionU + * and smbXsrv_sessionB directly. + * + * If we need to change the smbXsrv_session, + * we can just rename smbXsrv_session + * to smbXsrv_session0 and add a new + * smbXsrv_session for version 1 + * and could implement transparent mapping. + */ + + typedef struct { + [ignore] smbXsrv_session_auth0 *prev; + [max_recursion(20000)] smbXsrv_session_auth0 *next; + [ignore] smbXsrv_session *session; + [ignore] smbXsrv_connection *connection; + [ignore] gensec_security *gensec; + [ignore] smbXsrv_preauth *preauth; + uint8 in_flags; + uint8 in_security_mode; + NTTIME creation_time; + NTTIME idle_time; + hyper channel_id; + } smbXsrv_session_auth0; + + typedef struct { + [ignore] smbXsrv_session_table *table; + [ignore] db_record *db_rec; + [ignore] smbXsrv_client *client; + uint32 local_id; + [ref] smbXsrv_session_global0 *global; + NTSTATUS status; + NTTIME idle_time; + hyper nonce_high_random; + hyper nonce_high_max; + hyper nonce_high; + hyper nonce_low; + [ignore] smbXsrv_tcon_table *tcon_table; + [ignore] uint32 homes_snum; + smbXsrv_session_auth0 *pending_auth; + } smbXsrv_session; + + typedef union { + [case(0)] smbXsrv_session *info0; + [default] hyper *dummy; + } smbXsrv_sessionU; + + typedef [public] struct { + smbXsrv_version_values version; + [value(0)] uint32 reserved; + [switch_is(version)] smbXsrv_sessionU info; + } smbXsrv_sessionB; + + void smbXsrv_session_decode( + [in] smbXsrv_sessionB blob + ); + + /* + * smbXsrv_session_close is use in the MSG_SMBXSRV_SESSION_CLOSE + * message + */ + typedef struct { + uint32 old_session_global_id; + hyper old_session_wire_id; + NTTIME old_creation_time; + hyper new_session_wire_id; + } smbXsrv_session_close0; + + typedef union { + [case(0)] smbXsrv_session_close0 *info0; + [default] hyper *dummy; + } smbXsrv_session_closeU; + + typedef [public] struct { + smbXsrv_version_values version; + [value(0)] uint32 reserved; + [switch_is(version)] smbXsrv_session_closeU info; + } smbXsrv_session_closeB; + + void smbXsrv_session_close_decode( + [in] smbXsrv_session_closeB blob + ); + + /* tree connects */ + + typedef struct { + [ignore] db_record *db_rec; + uint32 tcon_global_id; + uint32 tcon_wire_id; + server_id server_id; + NTTIME creation_time; + [charset(UTF8),string] char share_name[]; + smbXsrv_encrpytion_flags encryption_flags; + /* + * for SMB1 this is the session that the tcon was opened on + */ + uint32 session_global_id; + smbXsrv_signing_flags signing_flags; + } smbXsrv_tcon_global0; + + typedef union { + [case(0)] smbXsrv_tcon_global0 *info0; + [default] hyper *dummy; + } smbXsrv_tcon_globalU; + + typedef [public] struct { + smbXsrv_version_values version; + uint32 seqnum; + [switch_is(version)] smbXsrv_tcon_globalU info; + } smbXsrv_tcon_globalB; + + void smbXsrv_tcon_global_decode( + [in] smbXsrv_tcon_globalB blob + ); + + /* + * The main server code should just work with + * 'struct smbXsrv_tcon' and never use + * smbXsrv_tcon0, smbXsrv_tconU + * and smbXsrv_tconB directly. + * + * If we need to change the smbXsrv_tcon, + * we can just rename smbXsrv_tcon + * to smbXsrv_tcon0 and add a new + * smbXsrv_tcon for version 1 + * and could implement transparent mapping. + */ + typedef struct { + [ignore] smbXsrv_tcon_table *table; + [ignore] db_record *db_rec; + uint32 local_id; + [ref] smbXsrv_tcon_global0 *global; + NTSTATUS status; + NTTIME idle_time; + [ignore] connection_struct *compat; + } smbXsrv_tcon; + + typedef union { + [case(0)] smbXsrv_tcon *info0; + [default] hyper *dummy; + } smbXsrv_tconU; + + typedef [public] struct { + smbXsrv_version_values version; + [value(0)] uint32 reserved; + [switch_is(version)] smbXsrv_tconU info; + } smbXsrv_tconB; + + void smbXsrv_tcon_decode( + [in] smbXsrv_tconB blob + ); + + /* open files */ + + typedef [public,bitmap8bit] bitmap { + SMBXSRV_OPEN_NEED_REPLAY_CACHE = 0x01, + SMBXSRV_OPEN_HAVE_REPLAY_CACHE = 0x02 + } smbXsrv_open_flags; + + typedef struct { + [ignore] db_record *db_rec; + server_id server_id; + uint32 open_global_id; + hyper open_persistent_id; + hyper open_volatile_id; + dom_sid open_owner; + NTTIME open_time; + GUID create_guid; + GUID client_guid; + GUID app_instance_id; + /* + * TODO: for durable/resilient/persistent handles we need more + * things here. See [MS-SMB2] 3.3.1.10 Per Open + * + * NOTE: this is still version 0, which is not a stable format! + */ + NTTIME disconnect_time; + uint32 durable_timeout_msec; + boolean8 durable; + DATA_BLOB backend_cookie; + uint16 channel_sequence; + hyper channel_generation; + [flag(NDR_PAHEX)] uint8 lock_sequence_array[64]; + } smbXsrv_open_global0; + + typedef union { + [case(0)] smbXsrv_open_global0 *info0; + [default] hyper *dummy; + } smbXsrv_open_globalU; + + typedef [public] struct { + + smbXsrv_version_values version; + uint32 seqnum; + [switch_is(version)] smbXsrv_open_globalU info; + } smbXsrv_open_globalB; + + void smbXsrv_open_global_decode( + [in] smbXsrv_open_globalB blob + ); + + /* + * The main server code should just work with + * 'struct smbXsrv_open' and never use + * smbXsrv_open0, smbXsrv_openU + * and smbXsrv_openB directly. + * + * If we need to change the smbXsrv_open, + * we can just rename smbXsrv_open + * to smbXsrv_open0 and add a new + * smbXsrv_open for version 1 + * and could implement transparent mapping. + */ + typedef struct { + [ignore] smbXsrv_open_table *table; + [ignore] db_record *db_rec; + uint32 local_id; + [ref] smbXsrv_open_global0 *global; + NTSTATUS status; + NTTIME idle_time; + [ignore] files_struct *compat; + smbXsrv_open_flags flags; + uint32 create_action; + hyper request_count; + hyper pre_request_count; + } smbXsrv_open; + + typedef union { + [case(0)] smbXsrv_open *info0; + [default] hyper *dummy; + } smbXsrv_openU; + + typedef [public] struct { + smbXsrv_version_values version; + [value(0)] uint32 reserved; + [switch_is(version)] smbXsrv_openU info; + } smbXsrv_openB; + + void smbXsrv_open_decode( + [in] smbXsrv_openB blob + ); + + const uint32 SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE = 28; + typedef [public] struct { + GUID holder_req_guid; + NTTIME idle_time; + uint32 local_id; + } smbXsrv_open_replay_cache; +} diff --git a/source3/librpc/idl/wscript_build b/source3/librpc/idl/wscript_build new file mode 100644 index 0000000..9332a8d --- /dev/null +++ b/source3/librpc/idl/wscript_build @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +import os + +topinclude=os.path.join(bld.srcnode.abspath(), 'librpc/idl') + +bld.SAMBA_PIDL_LIST('PIDL', + '''open_files.idl + perfcount.idl secrets.idl + smbXsrv.idl + leases_db.idl + ''', + options='--includedir=%s --header --ndr-parser' % topinclude, + output_dir='../gen_ndr') + +bld.SAMBA_PIDL_LIST('PIDL', + ''' + libnetapi.idl + libnet_join.idl + rpc_host.idl + ''', + options='--includedir=%s --header --ndr-parser' % topinclude, + output_dir='../gen_ndr', + generate_tables=False) diff --git a/source3/librpc/rpc/dcerpc.h b/source3/librpc/rpc/dcerpc.h new file mode 100644 index 0000000..4b76c5c --- /dev/null +++ b/source3/librpc/rpc/dcerpc.h @@ -0,0 +1,80 @@ +/* + Unix SMB/CIFS implementation. + + DCERPC client side interface structures + + Copyright (C) 2008 Jelmer Vernooij + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* This is a public header file that is installed as part of Samba. + * If you remove any functions or change their signature, update + * the so version number. */ + +#ifndef _S3_DCERPC_H__ +#define _S3_DCERPC_H__ + +#include "librpc/gen_ndr/dcerpc.h" +#include "../librpc/ndr/libndr.h" +#include "../librpc/rpc/rpc_common.h" + +struct NL_AUTH_MESSAGE; +struct gensec_security; + +/* auth state for all bind types. */ + +struct pipe_auth_data { + enum dcerpc_AuthType auth_type; + enum dcerpc_AuthLevel auth_level; + uint32_t auth_context_id; + bool client_hdr_signing; + bool hdr_signing; + bool verified_bitmask1; + + struct gensec_security *auth_ctx; + + /* Only the client code uses this for now */ + DATA_BLOB transport_session_key; +}; + +/* The following definitions come from librpc/rpc/dcerpc_helpers.c */ +NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t pfc_flags, + uint16_t auth_length, + uint32_t call_id, + union dcerpc_payload *u, + DATA_BLOB *blob); +NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint8_t auth_pad_length, + uint32_t auth_context_id, + const DATA_BLOB *credentials, + DATA_BLOB *blob); +NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth, + size_t header_len, size_t data_left, + size_t max_xmit_frag, + size_t *data_to_send, size_t *frag_len, + size_t *auth_len, size_t *pad_len); +NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth, + size_t pad_len, DATA_BLOB *rpc_out); +NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, + struct ncacn_packet *pkt, + DATA_BLOB *pkt_trailer, + uint8_t header_size, + DATA_BLOB *raw_pkt); + +#endif /* __S3_DCERPC_H__ */ diff --git a/source3/librpc/rpc/dcerpc_helpers.c b/source3/librpc/rpc/dcerpc_helpers.c new file mode 100644 index 0000000..c609efd --- /dev/null +++ b/source3/librpc/rpc/dcerpc_helpers.c @@ -0,0 +1,520 @@ +/* + * DCERPC Helper routines + * Günther Deschner <gd@samba.org> 2010. + * Simo Sorce <idra@samba.org> 2010. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include "includes.h" +#include "librpc/rpc/dcerpc.h" +#include "librpc/rpc/dcerpc_util.h" +#include "librpc/gen_ndr/ndr_dcerpc.h" +#include "librpc/crypto/gse.h" +#include "auth/gensec/gensec.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_RPC_PARSE + +/** +* @brief NDR Encodes a ncacn_packet +* +* @param mem_ctx The memory context the blob will be allocated on +* @param ptype The DCERPC packet type +* @param pfc_flags The DCERPC PFC Falgs +* @param auth_length The length of the trailing auth blob +* @param call_id The call ID +* @param u The payload of the packet +* @param blob [out] The encoded blob if successful +* +* @return an NTSTATUS error code +*/ +NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx, + enum dcerpc_pkt_type ptype, + uint8_t pfc_flags, + uint16_t auth_length, + uint32_t call_id, + union dcerpc_payload *u, + DATA_BLOB *blob) +{ + struct ncacn_packet r; + enum ndr_err_code ndr_err; + + r.rpc_vers = 5; + r.rpc_vers_minor = 0; + r.ptype = ptype; + r.pfc_flags = pfc_flags; + r.drep[0] = DCERPC_DREP_LE; + r.drep[1] = 0; + r.drep[2] = 0; + r.drep[3] = 0; + r.auth_length = auth_length; + r.call_id = call_id; + r.u = *u; + + ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r, + (ndr_push_flags_fn_t)ndr_push_ncacn_packet); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + dcerpc_set_frag_length(blob, blob->length); + + + if (DEBUGLEVEL >= 10) { + /* set frag len for print function */ + r.frag_length = blob->length; + NDR_PRINT_DEBUG(ncacn_packet, &r); + } + + return NT_STATUS_OK; +} + +/** +* @brief NDR Encodes a dcerpc_auth structure +* +* @param mem_ctx The memory context the blob will be allocated on +* @param auth_type The DCERPC Authentication Type +* @param auth_level The DCERPC Authentication Level +* @param auth_pad_length The padding added to the packet this blob will be +* appended to. +* @param auth_context_id The context id +* @param credentials The authentication credentials blob (signature) +* @param blob [out] The encoded blob if successful +* +* @return a NTSTATUS error code +*/ +NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx, + enum dcerpc_AuthType auth_type, + enum dcerpc_AuthLevel auth_level, + uint8_t auth_pad_length, + uint32_t auth_context_id, + const DATA_BLOB *credentials, + DATA_BLOB *blob) +{ + struct dcerpc_auth r; + enum ndr_err_code ndr_err; + + r.auth_type = auth_type; + r.auth_level = auth_level; + r.auth_pad_length = auth_pad_length; + r.auth_reserved = 0; + r.auth_context_id = auth_context_id; + r.credentials = *credentials; + + ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r, + (ndr_push_flags_fn_t)ndr_push_dcerpc_auth); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return ndr_map_error2ntstatus(ndr_err); + } + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(dcerpc_auth, &r); + } + + return NT_STATUS_OK; +} + +/** +* @brief Calculate how much data we can in a packet, including calculating +* auth token and pad lengths. +* +* @param auth The pipe_auth_data structure for this pipe. +* @param header_len The length of the packet header +* @param data_left The data left in the send buffer +* @param max_xmit_frag The max fragment size. +* @param data_to_send [out] The max data we will send in the pdu +* @param frag_len [out] The total length of the fragment +* @param auth_len [out] The length of the auth trailer +* @param pad_len [out] The padding to be applied +* +* @return A NT Error status code. +*/ +NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth, + size_t header_len, size_t data_left, + size_t max_xmit_frag, + size_t *data_to_send, size_t *frag_len, + size_t *auth_len, size_t *pad_len) +{ + size_t max_len; + size_t mod_len; + struct gensec_security *gensec_security; + + /* no auth token cases first */ + switch (auth->auth_level) { + case DCERPC_AUTH_LEVEL_NONE: + case DCERPC_AUTH_LEVEL_CONNECT: + max_len = max_xmit_frag - header_len; + *data_to_send = MIN(max_len, data_left); + *pad_len = 0; + *auth_len = 0; + *frag_len = header_len + *data_to_send; + return NT_STATUS_OK; + + case DCERPC_AUTH_LEVEL_PRIVACY: + break; + + case DCERPC_AUTH_LEVEL_INTEGRITY: + break; + + case DCERPC_AUTH_LEVEL_PACKET: + break; + + default: + return NT_STATUS_INVALID_PARAMETER; + } + + + /* Sign/seal case, calculate auth and pad lengths */ + + max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH; + + /* Treat the same for all authenticated rpc requests. */ + switch (auth->auth_type) { + case DCERPC_AUTH_TYPE_SPNEGO: + case DCERPC_AUTH_TYPE_NTLMSSP: + case DCERPC_AUTH_TYPE_KRB5: + case DCERPC_AUTH_TYPE_SCHANNEL: + gensec_security = auth->auth_ctx; + mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT); + *auth_len = gensec_sig_size(gensec_security, max_len - mod_len); + if (*auth_len == 0) { + return NT_STATUS_INTERNAL_ERROR; + } + break; + default: + return NT_STATUS_INVALID_PARAMETER; + } + + max_len -= *auth_len; + mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT); + max_len -= mod_len; + + *data_to_send = MIN(max_len, data_left); + + *pad_len = DCERPC_AUTH_PAD_LENGTH(*data_to_send); + + *frag_len = header_len + *data_to_send + *pad_len + + DCERPC_AUTH_TRAILER_LENGTH + *auth_len; + + return NT_STATUS_OK; +} + +/******************************************************************* + Create and add the NTLMSSP sign/seal auth data. + ********************************************************************/ + +static NTSTATUS add_generic_auth_footer(struct gensec_security *gensec_security, + enum dcerpc_AuthLevel auth_level, + DATA_BLOB *rpc_out) +{ + uint16_t data_and_pad_len = rpc_out->length + - DCERPC_RESPONSE_LENGTH + - DCERPC_AUTH_TRAILER_LENGTH; + DATA_BLOB auth_blob; + NTSTATUS status; + + if (!gensec_security) { + return NT_STATUS_INVALID_PARAMETER; + } + + switch (auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + /* Data portion is encrypted. */ + status = gensec_seal_packet(gensec_security, + rpc_out->data, + rpc_out->data + + DCERPC_RESPONSE_LENGTH, + data_and_pad_len, + rpc_out->data, + rpc_out->length, + &auth_blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; + + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PACKET: + /* Data is signed. */ + status = gensec_sign_packet(gensec_security, + rpc_out->data, + rpc_out->data + + DCERPC_RESPONSE_LENGTH, + data_and_pad_len, + rpc_out->data, + rpc_out->length, + &auth_blob); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; + + default: + /* Can't happen. */ + smb_panic("bad auth level"); + /* Notreached. */ + return NT_STATUS_INVALID_PARAMETER; + } + + /* Finally attach the blob. */ + if (!data_blob_append(NULL, rpc_out, + auth_blob.data, auth_blob.length)) { + DEBUG(0, ("Failed to add %u bytes auth blob.\n", + (unsigned int)auth_blob.length)); + return NT_STATUS_NO_MEMORY; + } + data_blob_free(&auth_blob); + + return NT_STATUS_OK; +} + +/******************************************************************* + Check/unseal the NTLMSSP auth data. (Unseal in place). + ********************************************************************/ + +static NTSTATUS get_generic_auth_footer(struct gensec_security *gensec_security, + enum dcerpc_AuthLevel auth_level, + DATA_BLOB *data, DATA_BLOB *full_pkt, + DATA_BLOB *auth_token) +{ + if (gensec_security == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + switch (auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + /* Data portion is encrypted. */ + return gensec_unseal_packet(gensec_security, + data->data, + data->length, + full_pkt->data, + full_pkt->length, + auth_token); + + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PACKET: + /* Data is signed. */ + return gensec_check_packet(gensec_security, + data->data, + data->length, + full_pkt->data, + full_pkt->length, + auth_token); + + default: + return NT_STATUS_INVALID_PARAMETER; + } +} + +/** +* @brief Append an auth footer according to what is the current mechanism +* +* @param auth The pipe_auth_data associated with the connection +* @param pad_len The padding used in the packet +* @param rpc_out Packet blob up to and including the auth header +* +* @return A NTSTATUS error code. +*/ +NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth, + size_t pad_len, DATA_BLOB *rpc_out) +{ + struct gensec_security *gensec_security; + const char pad[DCERPC_AUTH_PAD_ALIGNMENT] = { 0, }; + DATA_BLOB auth_info; + DATA_BLOB auth_blob; + NTSTATUS status; + + if (auth->auth_type == DCERPC_AUTH_TYPE_NONE) { + return NT_STATUS_OK; + } + + if (pad_len) { + SMB_ASSERT(pad_len <= ARRAY_SIZE(pad)); + + /* Copy the sign/seal padding data. */ + if (!data_blob_append(NULL, rpc_out, pad, pad_len)) { + return NT_STATUS_NO_MEMORY; + } + } + + /* marshall the dcerpc_auth with an actually empty auth_blob. + * This is needed because the ntmlssp signature includes the + * auth header. We will append the actual blob later. */ + auth_blob = data_blob_null; + status = dcerpc_push_dcerpc_auth(rpc_out->data, + auth->auth_type, + auth->auth_level, + pad_len, + auth->auth_context_id, + &auth_blob, + &auth_info); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* append the header */ + if (!data_blob_append(NULL, rpc_out, + auth_info.data, auth_info.length)) { + DEBUG(0, ("Failed to add %u bytes auth blob.\n", + (unsigned int)auth_info.length)); + return NT_STATUS_NO_MEMORY; + } + data_blob_free(&auth_info); + + /* Generate any auth sign/seal and add the auth footer. */ + switch (auth->auth_type) { + case DCERPC_AUTH_TYPE_NONE: + status = NT_STATUS_OK; + break; + default: + gensec_security = auth->auth_ctx; + status = add_generic_auth_footer(gensec_security, + auth->auth_level, + rpc_out); + break; + } + + return status; +} + +/** +* @brief Check authentication for request/response packets +* +* @param auth The auth data for the connection +* @param pkt The actual ncacn_packet +* @param pkt_trailer [in][out] The stub_and_verifier part of the packet, +* the auth_trailer and padding will be removed. +* @param header_size The header size +* @param raw_pkt The whole raw packet data blob +* +* @return A NTSTATUS error code +*/ +NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth, + struct ncacn_packet *pkt, + DATA_BLOB *pkt_trailer, + uint8_t header_size, + DATA_BLOB *raw_pkt) +{ + struct gensec_security *gensec_security; + NTSTATUS status; + struct dcerpc_auth auth_info; + uint32_t auth_length; + DATA_BLOB full_pkt; + DATA_BLOB data; + + /* + * These check should be done in the caller. + */ + SMB_ASSERT(raw_pkt->length == pkt->frag_length); + SMB_ASSERT(header_size <= pkt->frag_length); + SMB_ASSERT(pkt_trailer->length < pkt->frag_length); + SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length); + + switch (auth->auth_level) { + case DCERPC_AUTH_LEVEL_PRIVACY: + DEBUG(10, ("Requested Privacy.\n")); + break; + + case DCERPC_AUTH_LEVEL_INTEGRITY: + DEBUG(10, ("Requested Integrity.\n")); + break; + + case DCERPC_AUTH_LEVEL_PACKET: + DEBUG(10, ("Requested packet.\n")); + break; + + case DCERPC_AUTH_LEVEL_CONNECT: + if (pkt->auth_length != 0) { + break; + } + return NT_STATUS_OK; + + case DCERPC_AUTH_LEVEL_NONE: + if (pkt->auth_length != 0) { + DEBUG(3, ("Got non-zero auth len on non " + "authenticated connection!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + return NT_STATUS_OK; + + default: + DEBUG(3, ("Unimplemented Auth Level %d", + auth->auth_level)); + return NT_STATUS_INVALID_PARAMETER; + } + + if (pkt->auth_length == 0) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer, + &auth_info, &auth_length, false); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (auth_info.auth_type != auth->auth_type) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (auth_info.auth_level != auth->auth_level) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (auth_info.auth_context_id != auth->auth_context_id) { + return NT_STATUS_INVALID_PARAMETER; + } + + pkt_trailer->length -= auth_length; + data = data_blob_const(raw_pkt->data + header_size, + pkt_trailer->length); + full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length); + full_pkt.length -= auth_info.credentials.length; + + switch (auth->auth_type) { + case DCERPC_AUTH_TYPE_NONE: + return NT_STATUS_OK; + + default: + DEBUG(10, ("GENSEC auth\n")); + + gensec_security = auth->auth_ctx; + status = get_generic_auth_footer(gensec_security, + auth->auth_level, + &data, &full_pkt, + &auth_info.credentials); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + break; + } + + /* TODO: remove later + * this is still needed because in the server code the + * pkt_trailer actually has a copy of the raw data, and they + * are still both used in later calls */ + if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + if (pkt_trailer->length != data.length) { + return NT_STATUS_INVALID_PARAMETER; + } + memcpy(pkt_trailer->data, data.data, data.length); + } + + pkt_trailer->length -= auth_info.auth_pad_length; + data_blob_free(&auth_info.credentials); + return NT_STATUS_OK; +} + diff --git a/source3/librpc/wscript_build b/source3/librpc/wscript_build new file mode 100644 index 0000000..40b4eaf --- /dev/null +++ b/source3/librpc/wscript_build @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +bld.SAMBA3_SUBSYSTEM('NDR_LIBNETAPI', + cflags="-D SKIP_NDR_TABLE_libnetapi", + source='gen_ndr/ndr_libnetapi.c', + public_deps='ndr', + allow_warnings=True + ) + +bld.SAMBA3_SUBSYSTEM('NDR_LIBNET_JOIN', + source='gen_ndr/ndr_libnet_join.c', + public_deps='ndr krb5samba NDR_ODJ' + ) + +bld.SAMBA3_SUBSYSTEM("NDR_RPC_HOST", + source='gen_ndr/ndr_rpc_host.c', + public_deps='ndr') + +bld.SAMBA3_SUBSYSTEM('NDR_OPEN_FILES', + source='gen_ndr/ndr_open_files.c', + public_deps='ndr NDR_SERVER_ID NDR_FILE_ID NDR_SECURITY NDR_SMB2_LEASE_STRUCT' + ) + +bld.SAMBA3_SUBSYSTEM('NDR_SMBXSRV', + source='gen_ndr/ndr_smbXsrv.c', + public_deps='ndr NDR_SERVER_ID NDR_SECURITY NDR_AUTH' + ) + +bld.SAMBA3_SUBSYSTEM('NDR_LEASES_DB', + source='gen_ndr/ndr_leases_db.c', + public_deps='ndr NDR_SMB2_LEASE_STRUCT NDR_FILE_ID' + ) + +bld.SAMBA3_SUBSYSTEM('NDR_SECRETS', + source='gen_ndr/ndr_secrets.c', + public_deps='ndr NDR_SAMR NDR_LSA NDR_NETLOGON NDR_SECURITY' + ) + +bld.SAMBA3_SUBSYSTEM('NDR_PERFCOUNT', + source='gen_ndr/ndr_perfcount.c', + public_deps='ndr' + ) + |