static struct passwd *getpwnam_alloc_cached(TALLOC_CTX *mem_ctx, const char *name) { struct passwd *pw, *for_cache; pw = (struct passwd *)memcache_lookup_talloc( NULL, GETPWNAM_CACHE, data_blob_string_const_null(name)); if (pw != NULL) { return tcopy_passwd(mem_ctx, pw); } pw = getpwnam(name); if (pw == NULL) { return NULL; } for_cache = tcopy_passwd(talloc_tos(), pw); if (for_cache == NULL) { return NULL; } memcache_add_talloc(NULL, GETPWNAM_CACHE, data_blob_string_const_null(name), &for_cache); return tcopy_passwd(mem_ctx, pw); }
static bool delete_getpwnam_cache(const char *username) { DATA_BLOB name = data_blob_string_const_null(username); DEBUG(6, ("Delete passwd struct for %s from memcache\n", username)); memcache_delete(NULL, GETPWNAM_CACHE, name); return true; }
static bool test_string_null(struct torture_context *tctx) { DATA_BLOB blob = data_blob_string_const_null("bla"); torture_assert_int_equal(tctx, blob.length, 4, "blob length"); torture_assert_str_equal(tctx, (char *)blob.data, "bla", "blob data"); return true; }
/* string_match - match string s against token tok */ static bool string_match(const char *tok,const char *s) { size_t tok_len; size_t str_len; const char *cut; /* Return true if a token has the magic value "ALL". Return * true if the token is "FAIL". If the token starts with a "." * (domain name), return true if it matches the last fields of * the string. If the token has the magic value "LOCAL", * return true if the string does not contain a "." * character. If the token ends on a "." (network number), * return true if it matches the first fields of the * string. If the token begins with a "@" (netgroup name), * return true if the string is a (host) member of the * netgroup. Return true if the token fully matches the * string. If the token is a netnumber/netmask pair, return * true if the address is a member of the specified subnet. */ if (tok[0] == '.') { /* domain: match last fields */ if ((str_len = strlen(s)) > (tok_len = strlen(tok)) && strequal(tok, s + str_len - tok_len)) { return true; } } else if (tok[0] == '@') { /* netgroup: look it up */ #ifdef HAVE_NETGROUP DATA_BLOB tmp; char *mydomain = NULL; char *hostname = NULL; bool netgroup_ok = false; if (memcache_lookup( NULL, SINGLETON_CACHE, data_blob_string_const_null("yp_default_domain"), &tmp)) { SMB_ASSERT(tmp.length > 0); mydomain = (tmp.data[0] == '\0') ? NULL : (char *)tmp.data; } else { yp_get_default_domain(&mydomain); memcache_add( NULL, SINGLETON_CACHE, data_blob_string_const_null("yp_default_domain"), data_blob_string_const_null(mydomain?mydomain:"")); } if (!mydomain) { DEBUG(0,("Unable to get default yp domain. " "Try without it.\n")); } if (!(hostname = SMB_STRDUP(s))) { DEBUG(1,("out of memory for strdup!\n")); return false; } netgroup_ok = innetgr(tok + 1, hostname, (char *) 0, mydomain); DEBUG(5,("looking for %s of domain %s in netgroup %s gave %s\n", hostname, mydomain?mydomain:"(ANY)", tok+1, BOOLSTR(netgroup_ok))); SAFE_FREE(hostname); if (netgroup_ok) return true; #else DEBUG(0,("access: netgroup support is not configured\n")); return false; #endif } else if (strequal(tok, "ALL")) { /* all: match any */ return true; } else if (strequal(tok, "FAIL")) { /* fail: match any */ return true; } else if (strequal(tok, "LOCAL")) { /* local: no dots */ if (strchr_m(s, '.') == 0 && !strequal(s, "unknown")) { return true; } } else if (strequal(tok, s)) { /* match host name or address */ return true; } else if (tok[(tok_len = strlen(tok)) - 1] == '.') { /* network */ if (strncmp(tok, s, tok_len) == 0) { return true; } } else if ((cut = strchr_m(tok, '/')) != 0) { /* netnumber/netmask */ if ((isdigit(s[0]) && strchr_m(tok, '.') != NULL) || (tok[0] == '[' && cut > tok && cut[-1] == ']') || ((isxdigit(s[0]) || s[0] == ':') && strchr_m(tok, ':') != NULL)) { /* IPv4/netmask or * [IPv6:addr]/netmask or IPv6:addr/netmask */ return masked_match(tok, cut, s); } } else if (strchr_m(tok, '*') != 0 || strchr_m(tok, '?')) { return unix_wild_match(tok, s); } return false; }
static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, struct auth_session_info *session_info, uint16_t *out_session_flags, uint64_t *out_session_id) { NTSTATUS status; bool guest = false; uint8_t session_key[16]; struct smbXsrv_session *x = session; struct smbXsrv_connection *xconn = smb2req->xconn; struct _derivation { DATA_BLOB label; DATA_BLOB context; }; struct { struct _derivation signing; struct _derivation encryption; struct _derivation decryption; struct _derivation application; } derivation = { }; if (xconn->protocol >= PROTOCOL_SMB3_10) { struct smbXsrv_preauth *preauth; struct _derivation *d; DATA_BLOB p; struct hc_sha512state sctx; size_t i; preauth = talloc_move(smb2req, &session->preauth); samba_SHA512_Init(&sctx); samba_SHA512_Update(&sctx, preauth->sha512_value, sizeof(preauth->sha512_value)); for (i = 1; i < smb2req->in.vector_count; i++) { samba_SHA512_Update(&sctx, smb2req->in.vector[i].iov_base, smb2req->in.vector[i].iov_len); } samba_SHA512_Final(preauth->sha512_value, &sctx); p = data_blob_const(preauth->sha512_value, sizeof(preauth->sha512_value)); d = &derivation.signing; d->label = data_blob_string_const_null("SMBSigningKey"); d->context = p; d = &derivation.decryption; d->label = data_blob_string_const_null("SMBC2SCipherKey"); d->context = p; d = &derivation.encryption; d->label = data_blob_string_const_null("SMBS2CCipherKey"); d->context = p; d = &derivation.application; d->label = data_blob_string_const_null("SMBAppKey"); d->context = p; } else if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d; d = &derivation.signing; d->label = data_blob_string_const_null("SMB2AESCMAC"); d->context = data_blob_string_const_null("SmbSign"); d = &derivation.decryption; d->label = data_blob_string_const_null("SMB2AESCCM"); d->context = data_blob_string_const_null("ServerIn "); d = &derivation.encryption; d->label = data_blob_string_const_null("SMB2AESCCM"); d->context = data_blob_string_const_null("ServerOut"); d = &derivation.application; d->label = data_blob_string_const_null("SMB2APP"); d->context = data_blob_string_const_null("SmbRpc"); } if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || (xconn->smb2.server.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)) { x->global->signing_required = true; } if ((lp_smb_encrypt(-1) >= SMB_SIGNING_DESIRED) && (xconn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) { x->encryption_desired = true; } if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) { x->encryption_desired = true; x->global->encryption_required = true; } if (security_session_user_level(session_info, NULL) < SECURITY_USER) { /* we map anonymous to guest internally */ *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; /* force no signing */ x->global->signing_required = false; guest = true; } if (guest && x->global->encryption_required) { DEBUG(1,("reject guest session as encryption is required\n")); return NT_STATUS_ACCESS_DENIED; } if (xconn->smb2.server.cipher == 0) { if (x->global->encryption_required) { DEBUG(1,("reject session with dialect[0x%04X] " "as encryption is required\n", xconn->smb2.server.dialect)); return NT_STATUS_ACCESS_DENIED; } } if (x->encryption_desired) { *out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA; } ZERO_STRUCT(session_key); memcpy(session_key, session_info->session_key.data, MIN(session_info->session_key.length, sizeof(session_key))); x->global->signing_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->signing_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.signing; smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->signing_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.decryption; x->global->decryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->decryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->decryption_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.encryption; size_t nonce_size; x->global->encryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->encryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->encryption_key.data); /* * CCM and GCM algorithms must never have their * nonce wrap, or the security of the whole * communication and the keys is destroyed. * We must drop the connection once we have * transfered too much data. * * NOTE: We assume nonces greater than 8 bytes. */ generate_random_buffer((uint8_t *)&x->nonce_high_random, sizeof(x->nonce_high_random)); switch (xconn->smb2.server.cipher) { case SMB2_ENCRYPTION_AES128_CCM: nonce_size = AES_CCM_128_NONCE_SIZE; break; case SMB2_ENCRYPTION_AES128_GCM: nonce_size = AES_GCM_128_IV_SIZE; break; default: nonce_size = 0; break; } x->nonce_high_max = SMB2_NONCE_HIGH_MAX(nonce_size); x->nonce_high = 0; x->nonce_low = 0; } x->global->application_key = data_blob_dup_talloc(x->global, x->global->signing_key); if (x->global->application_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.application; smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, x->global->application_key.data); } ZERO_STRUCT(session_key); x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels, x->global->signing_key); if (x->global->channels[0].signing_key.data == NULL) { return NT_STATUS_NO_MEMORY; } data_blob_clear_free(&session_info->session_key); session_info->session_key = data_blob_dup_talloc(session_info, x->global->application_key); if (session_info->session_key.data == NULL) { return NT_STATUS_NO_MEMORY; } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { return NT_STATUS_NO_MEMORY; } session->compat->session = session; session->compat->homes_snum = -1; session->compat->session_info = session_info; session->compat->session_keystr = NULL; session->compat->vuid = session->global->session_wire_id; DLIST_ADD(smb2req->sconn->users, session->compat); smb2req->sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); reload_services(smb2req->sconn, conn_snum_used, true); session->status = NT_STATUS_OK; session->global->auth_session_info = session_info; session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = timeval_to_nttime(&smb2req->request_time); session->global->expiration_time = gensec_expire_time(session->gensec); if (!session_claim(session)) { DEBUG(1, ("smb2: Failed to claim session " "for vuid=%llu\n", (unsigned long long)session->compat->vuid)); return NT_STATUS_LOGON_FAILURE; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); return NT_STATUS_LOGON_FAILURE; } /* * we attach the session to the request * so that the response can be signed */ if (!guest) { smb2req->do_signing = true; } global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; }
static NTSTATUS smbd_smb2_bind_auth_return(struct smbXsrv_session *session, struct smbXsrv_session_auth0 **_auth, struct smbd_smb2_request *smb2req, struct auth_session_info *session_info, uint16_t *out_session_flags, uint64_t *out_session_id) { NTSTATUS status; struct smbXsrv_session *x = session; struct smbXsrv_session_auth0 *auth = *_auth; struct smbXsrv_connection *xconn = smb2req->xconn; struct smbXsrv_channel_global0 *c = NULL; uint8_t session_key[16]; size_t i; struct _derivation { DATA_BLOB label; DATA_BLOB context; }; struct { struct _derivation signing; } derivation = { }; bool ok; *_auth = NULL; if (xconn->protocol >= PROTOCOL_SMB3_10) { struct smbXsrv_preauth *preauth; struct _derivation *d; DATA_BLOB p; struct hc_sha512state sctx; preauth = talloc_move(smb2req, &auth->preauth); samba_SHA512_Init(&sctx); samba_SHA512_Update(&sctx, preauth->sha512_value, sizeof(preauth->sha512_value)); for (i = 1; i < smb2req->in.vector_count; i++) { samba_SHA512_Update(&sctx, smb2req->in.vector[i].iov_base, smb2req->in.vector[i].iov_len); } samba_SHA512_Final(preauth->sha512_value, &sctx); p = data_blob_const(preauth->sha512_value, sizeof(preauth->sha512_value)); d = &derivation.signing; d->label = data_blob_string_const_null("SMBSigningKey"); d->context = p; } else if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d; d = &derivation.signing; d->label = data_blob_string_const_null("SMB2AESCMAC"); d->context = data_blob_string_const_null("SmbSign"); } status = smbXsrv_session_find_channel(session, xconn, &c); if (!NT_STATUS_IS_OK(status)) { return status; } ok = security_token_is_sid(session_info->security_token, &x->global->auth_session_info->security_token->sids[0]); if (!ok) { return NT_STATUS_NOT_SUPPORTED; } if (session_info->session_key.length == 0) { /* See [MS-SMB2] 3.3.5.2.4 for the return code. */ return NT_STATUS_NOT_SUPPORTED; } ZERO_STRUCT(session_key); memcpy(session_key, session_info->session_key.data, MIN(session_info->session_key.length, sizeof(session_key))); c->signing_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (c->signing_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { struct _derivation *d = &derivation.signing; smb2_key_derivation(session_key, sizeof(session_key), d->label.data, d->label.length, d->context.data, d->context.length, c->signing_key.data); } ZERO_STRUCT(session_key); TALLOC_FREE(auth); status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); return NT_STATUS_LOGON_FAILURE; } *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; }
static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, struct auth_session_info *session_info, uint16_t *out_session_flags, uint64_t *out_session_id) { NTSTATUS status; bool guest = false; uint8_t session_key[16]; struct smbXsrv_session *x = session; struct smbXsrv_connection *xconn = smb2req->xconn; if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || lp_server_signing() == SMB_SIGNING_REQUIRED) { x->global->signing_required = true; } if (lp_smb_encrypt(-1) == SMB_SIGNING_REQUIRED) { x->global->encryption_required = true; } if (security_session_user_level(session_info, NULL) < SECURITY_USER) { /* we map anonymous to guest internally */ *out_session_flags |= SMB2_SESSION_FLAG_IS_GUEST; *out_session_flags |= SMB2_SESSION_FLAG_IS_NULL; /* force no signing */ x->global->signing_required = false; guest = true; } if (guest && x->global->encryption_required) { DEBUG(1,("reject guest session as encryption is required\n")); return NT_STATUS_ACCESS_DENIED; } if (xconn->smb2.server.cipher == 0) { if (x->global->encryption_required) { DEBUG(1,("reject session with dialect[0x%04X] " "as encryption is required\n", xconn->smb2.server.dialect)); return NT_STATUS_ACCESS_DENIED; } } if (x->global->encryption_required) { *out_session_flags |= SMB2_SESSION_FLAG_ENCRYPT_DATA; } ZERO_STRUCT(session_key); memcpy(session_key, session_info->session_key.data, MIN(session_info->session_key.length, sizeof(session_key))); x->global->signing_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->signing_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2AESCMAC"); const DATA_BLOB context = data_blob_string_const_null("SmbSign"); smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->signing_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2AESCCM"); const DATA_BLOB context = data_blob_string_const_null("ServerIn "); x->global->decryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->decryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->decryption_key.data); } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2AESCCM"); const DATA_BLOB context = data_blob_string_const_null("ServerOut"); x->global->encryption_key = data_blob_talloc(x->global, session_key, sizeof(session_key)); if (x->global->encryption_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->encryption_key.data); generate_random_buffer((uint8_t *)&x->nonce_high, sizeof(x->nonce_high)); x->nonce_low = 1; } x->global->application_key = data_blob_dup_talloc(x->global, x->global->signing_key); if (x->global->application_key.data == NULL) { ZERO_STRUCT(session_key); return NT_STATUS_NO_MEMORY; } if (xconn->protocol >= PROTOCOL_SMB2_24) { const DATA_BLOB label = data_blob_string_const_null("SMB2APP"); const DATA_BLOB context = data_blob_string_const_null("SmbRpc"); smb2_key_derivation(session_key, sizeof(session_key), label.data, label.length, context.data, context.length, x->global->application_key.data); } ZERO_STRUCT(session_key); x->global->channels[0].signing_key = data_blob_dup_talloc(x->global->channels, x->global->signing_key); if (x->global->channels[0].signing_key.data == NULL) { return NT_STATUS_NO_MEMORY; } data_blob_clear_free(&session_info->session_key); session_info->session_key = data_blob_dup_talloc(session_info, x->global->application_key); if (session_info->session_key.data == NULL) { return NT_STATUS_NO_MEMORY; } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { return NT_STATUS_NO_MEMORY; } session->compat->session = session; session->compat->homes_snum = -1; session->compat->session_info = session_info; session->compat->session_keystr = NULL; session->compat->vuid = session->global->session_wire_id; DLIST_ADD(smb2req->sconn->users, session->compat); smb2req->sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); reload_services(smb2req->sconn, conn_snum_used, true); session->status = NT_STATUS_OK; session->global->auth_session_info = session_info; session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = timeval_to_nttime(&smb2req->request_time); session->global->expiration_time = gensec_expire_time(session->gensec); if (!session_claim(session)) { DEBUG(1, ("smb2: Failed to claim session " "for vuid=%llu\n", (unsigned long long)session->compat->vuid)); return NT_STATUS_LOGON_FAILURE; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb2: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); return NT_STATUS_LOGON_FAILURE; } /* * we attach the session to the request * so that the response can be signed */ smb2req->session = session; if (!guest) { smb2req->do_signing = true; } global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; }