static enum security_user_level what_is_user(struct ldb_module *module) { struct ldb_context *ldb = ldb_module_get_ctx(module); struct auth_session_info *session_info = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); return security_session_user_level(session_info); }
static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session, 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; 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->session_info = session_info; session->compat->vuid = session->global->session_wire_id; 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; TALLOC_FREE(session->global->auth_session_info); 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); 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; } conn_clear_vuid_caches(smb2req->sconn, session->compat->vuid); if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { smb2req->do_signing = true; } *out_session_id = session->global->session_wire_id; return NT_STATUS_OK; }
/* winreg_QueryValue */ static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_QueryValue *r) { struct dcesrv_handle *h; struct registry_key *key; uint32_t value_type; DATA_BLOB value_data; WERROR result; DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; switch (security_session_user_level(dce_call->conn->auth_state.session_info)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: case SECURITY_USER: result = reg_key_get_value_by_name(mem_ctx, key, r->in.value_name->name, &value_type, &value_data); if (!W_ERROR_IS_OK(result)) { /* if the lookup wasn't successful, send client query back */ value_type = *r->in.type; value_data.data = r->in.data; value_data.length = *r->in.data_length; } r->out.type = talloc(mem_ctx, uint32_t); if (!r->out.type) { return WERR_NOMEM; } *r->out.type = value_type; r->out.data_length = talloc(mem_ctx, uint32_t); if (!r->out.data_length) { return WERR_NOMEM; } *r->out.data_length = value_data.length; r->out.data_size = talloc(mem_ctx, uint32_t); if (!r->out.data_size) { return WERR_NOMEM; } *r->out.data_size = value_data.length; r->out.data = value_data.data; return result; default: return WERR_ACCESS_DENIED; } }
/* winreg_CreateKey */ static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_CreateKey *r) { struct dcesrv_handle *h, *newh; struct security_descriptor sd; struct registry_key *key; WERROR result; DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY); switch (security_session_user_level(dce_call->conn->auth_state.session_info)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: /* the security descriptor is optional */ if (r->in.secdesc != NULL) { DATA_BLOB sdblob; enum ndr_err_code ndr_err; sdblob.data = r->in.secdesc->sd.data; sdblob.length = r->in.secdesc->sd.len; if (sdblob.data == NULL) { return WERR_INVALID_PARAM; } ndr_err = ndr_pull_struct_blob_all(&sdblob, mem_ctx, NULL, &sd, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return WERR_INVALID_PARAM; } } result = reg_key_add_name(newh, key, r->in.name.name, NULL, r->in.secdesc?&sd:NULL, (struct registry_key **)&newh->data); if (W_ERROR_IS_OK(result)) { r->out.new_handle = &newh->wire_handle; } else { talloc_free(newh); } return result; default: return WERR_ACCESS_DENIED; } }
/* winreg_FlushKey */ static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_FlushKey *r) { struct dcesrv_handle *h; struct registry_key *key; DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; switch (security_session_user_level(dce_call->conn->auth_state.session_info)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: return reg_key_flush(key); default: return WERR_ACCESS_DENIED; } }
static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn, TALLOC_CTX *mem_ctx, int snum, struct auth_session_info *session_info, struct auth_session_info **presult) { struct auth_session_info *result; if (lp_guest_only(snum)) { return make_session_info_guest(mem_ctx, presult); } /* * This is the normal security != share case where we have a * valid vuid from the session setup. */ if (security_session_user_level(session_info, NULL) < SECURITY_USER) { if (!lp_guest_ok(snum)) { DEBUG(2, ("guest user (from session setup) " "not permitted to access this share " "(%s)\n", lp_servicename(talloc_tos(), snum))); return NT_STATUS_ACCESS_DENIED; } } else { if (!user_ok_token(session_info->unix_info->unix_name, session_info->info->domain_name, session_info->security_token, snum)) { DEBUG(2, ("user '%s' (from session setup) not " "permitted to access this share " "(%s)\n", session_info->unix_info->unix_name, lp_servicename(talloc_tos(), snum))); return NT_STATUS_ACCESS_DENIED; } } result = copy_session_info(mem_ctx, session_info); if (result == NULL) { return NT_STATUS_NO_MEMORY; } *presult = result; return NT_STATUS_OK; }
bool pipe_access_check(struct pipes_struct *p) { /* Don't let anonymous users access this RPC if restrict anonymous > 0 */ if (lp_restrict_anonymous() > 0) { /* schannel, so we must be ok */ if (p->pipe_bound && (p->auth.auth_type == DCERPC_AUTH_TYPE_SCHANNEL)) { return True; } if (security_session_user_level(p->session_info, NULL) < SECURITY_USER) { return False; } } return True; }
/* drsuapi_DsReplicaGetInfo */ static WERROR dcesrv_drsuapi_DsReplicaGetInfo(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsReplicaGetInfo *r) { enum security_user_level level; if (!lp_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "disable_sec_check", false)) { level = security_session_user_level(dce_call->conn->auth_state.session_info); if (level < SECURITY_ADMINISTRATOR) { DEBUG(1,(__location__ ": Administrator access required for DsReplicaGetInfo\n")); security_token_debug(2, dce_call->conn->auth_state.session_info->security_token); return WERR_DS_DRA_ACCESS_DENIED; } } dcesrv_irpc_forward_rpc_call(dce_call, mem_ctx, r, NDR_DRSUAPI_DSREPLICAGETINFO, &ndr_table_drsuapi, "kccsrv", "DsReplicaGetInfo"); return WERR_OK; }
bool session_claim(struct smbXsrv_session *session) { struct auth_session_info *session_info = session->global->auth_session_info; const char *username; const char *hostname; unsigned int id_num; fstring id_str; /* don't register sessions for the guest user - its just too expensive to go through pam session code for browsing etc */ if (security_session_user_level(session_info, NULL) < SECURITY_USER) { return true; } id_num = session->global->session_global_id; snprintf(id_str, sizeof(id_str), "smb/%u", id_num); /* Make clear that we require the optional unix_token in the source3 code */ SMB_ASSERT(session_info->unix_token); username = session_info->unix_info->unix_name; hostname = session->global->channels[0].remote_name; if (!smb_pam_claim_session(username, id_str, hostname)) { DEBUG(1,("pam_session rejected the session for %s [%s]\n", username, id_str)); return false; } if (lp_utmp()) { sys_utmp_claim(username, hostname, id_str, id_num); } return true; }
/* winreg_SetValue */ static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_SetValue *r) { struct dcesrv_handle *h; struct registry_key *key; DATA_BLOB data; WERROR result; DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; switch (security_session_user_level(dce_call->conn->auth_state.session_info)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: data.data = r->in.data; data.length = r->in.size; result = reg_val_set(key, r->in.name.name, r->in.type, data); return result; default: return WERR_ACCESS_DENIED; } }
/* winreg_QueryInfoKey */ static WERROR dcesrv_winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_QueryInfoKey *r) { struct dcesrv_handle *h; struct registry_key *key; const char *classname = NULL; WERROR result; DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; switch (security_session_user_level(dce_call->conn->auth_state.session_info)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: case SECURITY_USER: result = reg_key_get_info(mem_ctx, key, &classname, r->out.num_subkeys, r->out.num_values, r->out.last_changed_time, r->out.max_subkeylen, r->out.max_valnamelen, r->out.max_valbufsize); if (classname != NULL) { r->out.classname->name = classname; r->out.classname->name_len = 2*strlen_m_term(classname); } else { r->out.classname->name = r->in.classname->name; r->out.classname->name_len = r->in.classname->name_len; } r->out.classname->name_size = r->in.classname->name_size; return result; default: return WERR_ACCESS_DENIED; } }
/* winreg_OpenKey */ static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct winreg_OpenKey *r) { struct dcesrv_handle *h, *newh; struct registry_key *key; WERROR result; DCESRV_PULL_HANDLE_FAULT(h, r->in.parent_handle, HTYPE_REGKEY); key = h->data; switch (security_session_user_level(dce_call->conn->auth_state.session_info)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: case SECURITY_USER: if (r->in.keyname.name && strcmp(r->in.keyname.name, "") == 0) { newh = talloc_reference(dce_call->context, h); result = WERR_OK; } else { newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY); result = reg_open_key(newh, key, r->in.keyname.name, (struct registry_key **)&newh->data); } if (W_ERROR_IS_OK(result)) { r->out.handle = &newh->wire_handle; } else { talloc_free(newh); } return result; default: return WERR_ACCESS_DENIED; } }
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; }
/* drsuapi_DsWriteAccountSpn */ WERROR dcesrv_drsuapi_DsWriteAccountSpn(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct drsuapi_DsWriteAccountSpn *r) { struct drsuapi_bind_state *b_state; struct dcesrv_handle *h; enum security_user_level level; *r->out.level_out = r->in.level; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; r->out.res = talloc(mem_ctx, union drsuapi_DsWriteAccountSpnResult); W_ERROR_HAVE_NO_MEMORY(r->out.res); level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL); switch (r->in.level) { case 1: { struct drsuapi_DsWriteAccountSpnRequest1 *req; struct ldb_message *msg; uint32_t count; unsigned int i; int ret; unsigned spn_count=0; bool passed_checks = true; struct ldb_context *sam_ctx; req = &r->in.req->req1; count = req->count; msg = ldb_msg_new(mem_ctx); if (msg == NULL) { return WERR_NOMEM; } msg->dn = ldb_dn_new(msg, b_state->sam_ctx, req->object_dn); if ( ! ldb_dn_validate(msg->dn)) { r->out.res->res1.status = WERR_OK; return WERR_OK; } /* construct mods */ for (i = 0; i < count; i++) { if (!writespn_check_spn(b_state, dce_call, msg->dn, req->spn_names[i].str)) { passed_checks = false; } ret = ldb_msg_add_string(msg, "servicePrincipalName", req->spn_names[i].str); if (ret != LDB_SUCCESS) { return WERR_NOMEM; } spn_count++; } if (msg->num_elements == 0) { DEBUG(2,("No SPNs need changing on %s\n", ldb_dn_get_linearized(msg->dn))); r->out.res->res1.status = WERR_OK; return WERR_OK; } for (i=0;i<msg->num_elements;i++) { switch (req->operation) { case DRSUAPI_DS_SPN_OPERATION_ADD: msg->elements[i].flags = LDB_FLAG_MOD_ADD; break; case DRSUAPI_DS_SPN_OPERATION_REPLACE: msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; break; case DRSUAPI_DS_SPN_OPERATION_DELETE: msg->elements[i].flags = LDB_FLAG_MOD_DELETE; break; } } if (passed_checks && b_state->sam_ctx_system) { sam_ctx = b_state->sam_ctx_system; } else { sam_ctx = b_state->sam_ctx; } /* Apply to database */ ret = dsdb_modify(sam_ctx, msg, DSDB_MODIFY_PERMISSIVE); if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to modify SPNs on %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(b_state->sam_ctx))); r->out.res->res1.status = WERR_ACCESS_DENIED; } else { DEBUG(2,("Modified %u SPNs on %s\n", spn_count, ldb_dn_get_linearized(msg->dn))); r->out.res->res1.status = WERR_OK; } return WERR_OK; } } return WERR_UNKNOWN_LEVEL; }
static NTSTATUS create_connection_session_info(struct smbd_server_connection *sconn, TALLOC_CTX *mem_ctx, int snum, struct auth_session_info *vuid_serverinfo, DATA_BLOB password, struct auth_session_info **presult) { if (lp_guest_only(snum)) { return make_session_info_guest(mem_ctx, presult); } if (vuid_serverinfo != NULL) { struct auth_session_info *result; /* * This is the normal security != share case where we have a * valid vuid from the session setup. */ if (security_session_user_level(vuid_serverinfo, NULL) < SECURITY_USER) { if (!lp_guest_ok(snum)) { DEBUG(2, ("guest user (from session setup) " "not permitted to access this share " "(%s)\n", lp_servicename(snum))); return NT_STATUS_ACCESS_DENIED; } } else { if (!user_ok_token(vuid_serverinfo->unix_info->unix_name, vuid_serverinfo->info->domain_name, vuid_serverinfo->security_token, snum)) { DEBUG(2, ("user '%s' (from session setup) not " "permitted to access this share " "(%s)\n", vuid_serverinfo->unix_info->unix_name, lp_servicename(snum))); return NT_STATUS_ACCESS_DENIED; } } result = copy_session_info(mem_ctx, vuid_serverinfo); if (result == NULL) { return NT_STATUS_NO_MEMORY; } *presult = result; return NT_STATUS_OK; } if (lp_security() == SEC_SHARE) { fstring user; bool guest; /* add the sharename as a possible user name if we are in share mode security */ add_session_user(sconn, lp_servicename(snum)); /* shall we let them in? */ if (!authorise_login(sconn, snum,user,password,&guest)) { DEBUG( 2, ( "Invalid username/password for [%s]\n", lp_servicename(snum)) ); return NT_STATUS_WRONG_PASSWORD; } return make_session_info_from_username(mem_ctx, user, guest, presult); } DEBUG(0, ("invalid VUID (vuser) but not in security=share\n")); return NT_STATUS_ACCESS_DENIED; }
static NTSTATUS smbd_smb2_session_setup_krb5(struct smbd_smb2_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, const DATA_BLOB *secblob, const char *mechOID, uint16_t *out_session_flags, DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { DATA_BLOB ap_rep = data_blob_null; DATA_BLOB ap_rep_wrapped = data_blob_null; DATA_BLOB ticket = data_blob_null; DATA_BLOB session_key = data_blob_null; DATA_BLOB secblob_out = data_blob_null; uint8 tok_id[2]; struct PAC_LOGON_INFO *logon_info = NULL; char *principal = NULL; char *user = NULL; char *domain = NULL; struct passwd *pw = NULL; NTSTATUS status; char *real_username; bool username_was_mapped = false; bool map_domainuser_to_guest = false; if (!spnego_parse_krb5_wrap(talloc_tos(), *secblob, &ticket, tok_id)) { status = NT_STATUS_LOGON_FAILURE; goto fail; } status = ads_verify_ticket(smb2req, lp_realm(), 0, &ticket, &principal, &logon_info, &ap_rep, &session_key, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("smb2: Failed to verify incoming ticket with error %s!\n", nt_errstr(status))); if (!NT_STATUS_EQUAL(status, NT_STATUS_TIME_DIFFERENCE_AT_DC)) { status = NT_STATUS_LOGON_FAILURE; } goto fail; } status = get_user_from_kerberos_info(talloc_tos(), session->sconn->remote_hostname, principal, logon_info, &username_was_mapped, &map_domainuser_to_guest, &user, &domain, &real_username, &pw); if (!NT_STATUS_IS_OK(status)) { goto fail; } /* save the PAC data if we have it */ if (logon_info) { netsamlogon_cache_store(user, &logon_info->info3); } /* setup the string used by %U */ sub_set_smb_name(real_username); /* reload services so that the new %U is taken into account */ reload_services(smb2req->sconn->msg_ctx, smb2req->sconn->sock, true); status = make_session_info_krb5(session, user, domain, real_username, pw, logon_info, map_domainuser_to_guest, username_was_mapped, &session_key, &session->session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("smb2: make_server_info_krb5 failed\n")); goto fail; } if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || lp_server_signing() == Required) { session->do_signing = true; } if (security_session_user_level(session->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 */ session->do_signing = false; } session->session_key = session->session_info->session_key; session->compat_vuser = talloc_zero(session, user_struct); if (session->compat_vuser == NULL) { status = NT_STATUS_NO_MEMORY; goto fail; } session->compat_vuser->auth_ntlmssp_state = NULL; session->compat_vuser->homes_snum = -1; session->compat_vuser->session_info = session->session_info; session->compat_vuser->session_keystr = NULL; session->compat_vuser->vuid = session->vuid; DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser); if (security_session_user_level(session->session_info, NULL) >= SECURITY_USER) { session->compat_vuser->homes_snum = register_homes_share(session->session_info->unix_info->unix_name); } if (!session_claim(session->sconn, session->compat_vuser)) { DEBUG(1, ("smb2: Failed to claim session " "for vuid=%d\n", session->compat_vuser->vuid)); goto fail; } session->status = NT_STATUS_OK; /* * we attach the session to the request * so that the response can be signed */ smb2req->session = session; if (session->do_signing) { smb2req->do_signing = true; } global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32); status = NT_STATUS_OK; /* wrap that up in a nice GSS-API wrapping */ ap_rep_wrapped = spnego_gen_krb5_wrap(talloc_tos(), ap_rep, TOK_ID_KRB_AP_REP); secblob_out = spnego_gen_auth_response( talloc_tos(), &ap_rep_wrapped, status, mechOID); *out_security_buffer = data_blob_talloc(smb2req, secblob_out.data, secblob_out.length); if (secblob_out.data && out_security_buffer->data == NULL) { status = NT_STATUS_NO_MEMORY; goto fail; } data_blob_free(&ap_rep); data_blob_free(&ap_rep_wrapped); data_blob_free(&ticket); data_blob_free(&session_key); data_blob_free(&secblob_out); *out_session_id = session->vuid; return NT_STATUS_OK; fail: data_blob_free(&ap_rep); data_blob_free(&ap_rep_wrapped); data_blob_free(&ticket); data_blob_free(&session_key); data_blob_free(&secblob_out); ap_rep_wrapped = data_blob_null; secblob_out = spnego_gen_auth_response( talloc_tos(), &ap_rep_wrapped, status, mechOID); *out_security_buffer = data_blob_talloc(smb2req, secblob_out.data, secblob_out.length); data_blob_free(&secblob_out); return status; }
static void reply_sesssetup_and_X_spnego(struct smb_request *req) { const uint8_t *p; DATA_BLOB in_blob; DATA_BLOB out_blob = data_blob_null; size_t bufrem; char *tmp; const char *native_os; const char *native_lanman; const char *primary_domain; uint16_t data_blob_len = SVAL(req->vwv+7, 0); enum remote_arch_types ra_type = get_remote_arch(); uint64_t vuid = req->vuid; NTSTATUS status = NT_STATUS_OK; struct smbXsrv_connection *xconn = req->xconn; struct smbd_server_connection *sconn = req->sconn; uint16_t action = 0; bool is_authenticated = false; NTTIME now = timeval_to_nttime(&req->request_time); struct smbXsrv_session *session = NULL; uint16_t smb_bufsize = SVAL(req->vwv+2, 0); uint32_t client_caps = IVAL(req->vwv+10, 0); struct smbXsrv_session_auth0 *auth; DEBUG(3,("Doing spnego session setup\n")); if (!xconn->smb1.sessions.done_sesssetup) { global_client_caps = client_caps; if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } } p = req->buf; if (data_blob_len == 0) { /* an invalid request */ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE)); return; } bufrem = smbreq_bufrem(req, p); /* pull the spnego blob */ in_blob = data_blob_const(p, MIN(bufrem, data_blob_len)); #if 0 file_save("negotiate.dat", in_blob.data, in_blob.length); #endif p = req->buf + in_blob.length; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_os = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_lanman = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); primary_domain = tmp ? tmp : ""; DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { /* Vista sets neither the OS or lanman strings */ if ( !strlen(native_os) && !strlen(native_lanman) ) set_remote_arch(RA_VISTA); /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ if ( !strlen(native_lanman) ) { ra_lanman_string( primary_domain ); } else { ra_lanman_string( native_lanman ); } } else if ( ra_type == RA_VISTA ) { if ( strncmp(native_os, "Mac OS X", 8) == 0 ) { set_remote_arch(RA_OSX); } } if (vuid != 0) { status = smb1srv_session_lookup(xconn, vuid, now, &session); if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { reply_force_doserror(req, ERRSRV, ERRbaduid); return; } if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { status = NT_STATUS_OK; } if (NT_STATUS_IS_OK(status)) { session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; status = NT_STATUS_MORE_PROCESSING_REQUIRED; TALLOC_FREE(session->pending_auth); } if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { reply_nterror(req, nt_status_squash(status)); return; } } if (session == NULL) { /* create a new session */ status = smbXsrv_session_create(xconn, now, &session); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } status = smbXsrv_session_find_auth(session, xconn, now, &auth); if (!NT_STATUS_IS_OK(status)) { status = smbXsrv_session_create_auth(session, xconn, now, 0, /* flags */ 0, /* security */ &auth); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } if (auth->gensec == NULL) { status = auth_generic_prepare(session, xconn->remote_address, xconn->local_address, "SMB", &auth->gensec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN); gensec_want_feature(auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT); status = gensec_start_mech_by_oid(auth->gensec, GENSEC_OID_SPNEGO); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to start SPNEGO handler!\n")); TALLOC_FREE(session);; reply_nterror(req, nt_status_squash(status)); return; } } become_root(); status = gensec_update(auth->gensec, talloc_tos(), in_blob, &out_blob); unbecome_root(); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) { struct auth_session_info *session_info = NULL; status = gensec_session_info(auth->gensec, session, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("Failed to generate session_info " "(user and group token) for session setup: %s\n", nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) { action |= SMB_SETUP_GUEST; } if (session_info->session_key.length > 0) { struct smbXsrv_session *x = session; /* * Note: the SMB1 signing key is not truncated to 16 byte! */ x->global->signing_key = data_blob_dup_talloc(x->global, session_info->session_key); if (x->global->signing_key.data == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } /* * clear the session key * the first tcon will add setup the application key */ data_blob_clear_free(&session_info->session_key); } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } 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(sconn->users, session->compat); sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { is_authenticated = true; session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } if (srv_is_signing_negotiated(xconn) && is_authenticated && session->global->signing_key.length > 0) { /* * Try and turn on server signing on the first non-guest * sessionsetup. */ srv_set_signing(xconn, session->global->signing_key, data_blob_null); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); session->status = NT_STATUS_OK; session->global->auth_session_info = talloc_move(session->global, &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 = now; if (client_caps & CAP_DYNAMIC_REAUTH) { session->global->expiration_time = gensec_expire_time(auth->gensec); } else { session->global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY; } if (!session_claim(session)) { DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n", (unsigned long long)session->compat->vuid)); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } if (!xconn->smb1.sessions.done_sesssetup) { if (smb_bufsize < SMB_BUFFER_SIZE_MIN) { reply_force_doserror(req, ERRSRV, ERRerror); return; } xconn->smb1.sessions.max_send = smb_bufsize; xconn->smb1.sessions.done_sesssetup = true; } /* current_user_info is changed on new vuid */ reload_services(sconn, conn_snum_used, true); } else if (NT_STATUS_IS_OK(status)) {
static NTSTATUS smbd_smb2_auth_generic_return(struct smbd_smb2_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, DATA_BLOB in_security_buffer, uint16_t *out_session_flags, uint64_t *out_session_id) { bool guest = false; if ((in_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) || lp_server_signing() == SMB_SIGNING_REQUIRED) { session->do_signing = true; } if (security_session_user_level(session->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 */ session->do_signing = false; guest = true; } session->session_key = session->session_info->session_key; session->compat_vuser = talloc_zero(session, user_struct); if (session->compat_vuser == NULL) { TALLOC_FREE(session); return NT_STATUS_NO_MEMORY; } session->compat_vuser->gensec_security = session->gensec_security; session->compat_vuser->homes_snum = -1; session->compat_vuser->session_info = session->session_info; session->compat_vuser->session_keystr = NULL; session->compat_vuser->vuid = session->vuid; DLIST_ADD(session->sconn->smb1.sessions.validated_users, session->compat_vuser); if (security_session_user_level(session->session_info, NULL) >= SECURITY_USER) { session->compat_vuser->homes_snum = register_homes_share(session->session_info->unix_info->unix_name); } if (!session_claim(session->sconn, session->compat_vuser)) { DEBUG(1, ("smb2: Failed to claim session " "for vuid=%d\n", session->compat_vuser->vuid)); TALLOC_FREE(session); return NT_STATUS_LOGON_FAILURE; } set_current_user_info(session->session_info->unix_info->sanitized_username, session->session_info->unix_info->unix_name, session->session_info->info->domain_name); reload_services(smb2req->sconn, conn_snum_used, true); session->status = NT_STATUS_OK; /* * 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->vuid; 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; 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; }
NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, uint32_t access_desired, struct lsa_policy_state **_state) { struct auth_session_info *session_info = dce_call->conn->auth_state.session_info; enum security_user_level security_level; struct lsa_policy_state *state; struct ldb_result *dom_res; const char *dom_attrs[] = { "objectSid", "objectGUID", "nTMixedDomain", "fSMORoleOwner", NULL }; char *p; int ret; state = talloc_zero(mem_ctx, struct lsa_policy_state); if (!state) { return NT_STATUS_NO_MEMORY; } /* make sure the sam database is accessible */ state->sam_ldb = samdb_connect(state, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, dce_call->conn->remote_address, 0); if (state->sam_ldb == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* and the privilege database */ state->pdb = privilege_connect(state, dce_call->conn->dce_ctx->lp_ctx); if (state->pdb == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* work out the domain_dn - useful for so many calls its worth fetching here */ state->domain_dn = ldb_get_default_basedn(state->sam_ldb); if (!state->domain_dn) { return NT_STATUS_NO_MEMORY; } /* work out the forest root_dn - useful for so many calls its worth fetching here */ state->forest_dn = ldb_get_root_basedn(state->sam_ldb); if (!state->forest_dn) { return NT_STATUS_NO_MEMORY; } ret = ldb_search(state->sam_ldb, mem_ctx, &dom_res, state->domain_dn, LDB_SCOPE_BASE, dom_attrs, NULL); if (ret != LDB_SUCCESS) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } if (dom_res->count != 1) { return NT_STATUS_NO_SUCH_DOMAIN; } state->domain_sid = samdb_result_dom_sid(state, dom_res->msgs[0], "objectSid"); if (!state->domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->domain_guid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); state->mixed_domain = ldb_msg_find_attr_as_uint(dom_res->msgs[0], "nTMixedDomain", 0); talloc_free(dom_res); state->domain_name = lpcfg_sam_name(dce_call->conn->dce_ctx->lp_ctx); state->domain_dns = ldb_dn_canonical_string(state, state->domain_dn); if (!state->domain_dns) { return NT_STATUS_NO_SUCH_DOMAIN; } p = strchr(state->domain_dns, '/'); if (p) { *p = '\0'; } state->forest_dns = ldb_dn_canonical_string(state, state->forest_dn); if (!state->forest_dns) { return NT_STATUS_NO_SUCH_DOMAIN; } p = strchr(state->forest_dns, '/'); if (p) { *p = '\0'; } /* work out the builtin_dn - useful for so many calls its worth fetching here */ state->builtin_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(objectClass=builtinDomain)"); if (!state->builtin_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } /* work out the system_dn - useful for so many calls its worth fetching here */ state->system_dn = samdb_search_dn(state->sam_ldb, state, state->domain_dn, "(&(objectClass=container)(cn=System))"); if (!state->system_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } state->builtin_sid = dom_sid_parse_talloc(state, SID_BUILTIN); if (!state->builtin_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->nt_authority_sid = dom_sid_parse_talloc(state, SID_NT_AUTHORITY); if (!state->nt_authority_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->creator_owner_domain_sid = dom_sid_parse_talloc(state, SID_CREATOR_OWNER_DOMAIN); if (!state->creator_owner_domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->world_domain_sid = dom_sid_parse_talloc(state, SID_WORLD_DOMAIN); if (!state->world_domain_sid) { return NT_STATUS_NO_SUCH_DOMAIN; } state->sd = sddl_decode(state, DCESRV_LSA_POLICY_SD_SDDL, state->domain_sid); if (state->sd == NULL) { return NT_STATUS_NO_MEMORY; } state->sd->dacl->revision = SECURITY_ACL_REVISION_NT4; se_map_generic(&access_desired, &dcesrv_lsa_policy_mapping); security_acl_map_generic(state->sd->dacl, &dcesrv_lsa_policy_mapping); security_level = security_session_user_level(session_info, NULL); if (security_level >= SECURITY_SYSTEM) { /* * The security descriptor doesn't allow system, * but we want to allow system via ncalrpc as root. */ state->access_mask = access_desired; if (state->access_mask & SEC_FLAG_MAXIMUM_ALLOWED) { state->access_mask &= ~SEC_FLAG_MAXIMUM_ALLOWED; state->access_mask |= LSA_POLICY_ALL_ACCESS; } } else { NTSTATUS status; status = se_access_check(state->sd, session_info->security_token, access_desired, &state->access_mask); if (!NT_STATUS_IS_OK(status)) { DEBUG(2,("%s: access desired[0x%08X] rejected[0x%08X] - %s\n", __func__, (unsigned)access_desired, (unsigned)state->access_mask, nt_errstr(status))); return status; } } DEBUG(10,("%s: access desired[0x%08X] granted[0x%08X] - success.\n", __func__, (unsigned)access_desired, (unsigned)state->access_mask)); *_state = state; return NT_STATUS_OK; }
NTSTATUS set_conn_force_user_group(connection_struct *conn, int snum) { NTSTATUS status; if (*lp_force_user(talloc_tos(), snum)) { /* * Replace conn->session_info with a completely faked up one * from the username we are forced into :-) */ char *fuser; char *sanitized_username; struct auth_session_info *forced_serverinfo; bool guest; fuser = talloc_string_sub(conn, lp_force_user(talloc_tos(), snum), "%S", lp_const_servicename(snum)); if (fuser == NULL) { return NT_STATUS_NO_MEMORY; } guest = security_session_user_level(conn->session_info, NULL) < SECURITY_USER; status = make_session_info_from_username( conn, fuser, guest, &forced_serverinfo); if (!NT_STATUS_IS_OK(status)) { return status; } /* We don't want to replace the original sanitized_username as it is the original user given in the connect attempt. This is used in '%U' substitutions. */ sanitized_username = discard_const_p(char, forced_serverinfo->unix_info->sanitized_username); TALLOC_FREE(sanitized_username); forced_serverinfo->unix_info->sanitized_username = talloc_move(forced_serverinfo->unix_info, &conn->session_info->unix_info->sanitized_username); TALLOC_FREE(conn->session_info); conn->session_info = forced_serverinfo; conn->force_user = true; DEBUG(3,("Forced user %s\n", fuser)); } /* * If force group is true, then override * any groupid stored for the connecting user. */ if (*lp_force_group(talloc_tos(), snum)) { status = find_forced_group( conn->force_user, snum, conn->session_info->unix_info->unix_name, &conn->session_info->security_token->sids[1], &conn->session_info->unix_token->gid); if (!NT_STATUS_IS_OK(status)) { return status; } /* * We need to cache this gid, to use within * change_to_user() separately from the conn->session_info * struct. We only use conn->session_info directly if * "force_user" was set. */ conn->force_group_gid = conn->session_info->unix_token->gid; } return NT_STATUS_OK; }
static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, const char *in_path, uint8_t *out_share_type, uint32_t *out_share_flags, uint32_t *out_capabilities, uint32_t *out_maximal_access, uint32_t *out_tree_id) { struct smbXsrv_connection *conn = req->sconn->conn; const char *share = in_path; char *service = NULL; int snum = -1; struct smbXsrv_tcon *tcon; NTTIME now = timeval_to_nttime(&req->request_time); connection_struct *compat_conn = NULL; struct user_struct *compat_vuser = req->session->compat; NTSTATUS status; bool encryption_desired = req->session->encryption_desired; bool encryption_required = req->session->global->encryption_required; bool guest_session = false; if (strncmp(share, "\\\\", 2) == 0) { const char *p = strchr(share+2, '\\'); if (p) { share = p + 1; } } DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n", in_path, share)); service = talloc_strdup(talloc_tos(), share); if(!service) { return NT_STATUS_NO_MEMORY; } if (!strlower_m(service)) { DEBUG(2, ("strlower_m %s failed\n", service)); return NT_STATUS_INVALID_PARAMETER; } /* TODO: do more things... */ if (strequal(service,HOMES_NAME)) { if (compat_vuser->homes_snum == -1) { DEBUG(2, ("[homes] share not available for " "user %s because it was not found " "or created at session setup " "time\n", compat_vuser->session_info->unix_info->unix_name)); return NT_STATUS_BAD_NETWORK_NAME; } snum = compat_vuser->homes_snum; } else if ((compat_vuser->homes_snum != -1) && strequal(service, lp_servicename(talloc_tos(), compat_vuser->homes_snum))) { snum = compat_vuser->homes_snum; } else { snum = find_service(talloc_tos(), service, &service); if (!service) { return NT_STATUS_NO_MEMORY; } } if (snum < 0) { DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n", service)); return NT_STATUS_BAD_NETWORK_NAME; } if ((lp_smb_encrypt(snum) >= SMB_SIGNING_DESIRED) && (conn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) { encryption_desired = true; } if (lp_smb_encrypt(snum) == SMB_SIGNING_REQUIRED) { encryption_desired = true; encryption_required = true; } if (security_session_user_level(compat_vuser->session_info, NULL) < SECURITY_USER) { guest_session = true; } if (guest_session && encryption_required) { DEBUG(1,("reject guest as encryption is required for service %s\n", service)); return NT_STATUS_ACCESS_DENIED; } if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) { if (encryption_required) { DEBUG(1,("reject tcon with dialect[0x%04X] " "as encryption is required for service %s\n", conn->smb2.server.dialect, service)); return NT_STATUS_ACCESS_DENIED; } } /* create a new tcon as child of the session */ status = smb2srv_tcon_create(req->session, now, &tcon); if (!NT_STATUS_IS_OK(status)) { return status; } tcon->encryption_desired = encryption_desired; tcon->global->encryption_required = encryption_required; compat_conn = make_connection_smb2(req->sconn, tcon, snum, req->session->compat, "???", &status); if (compat_conn == NULL) { TALLOC_FREE(tcon); return status; } tcon->global->share_name = lp_servicename(tcon->global, SNUM(compat_conn)); if (tcon->global->share_name == NULL) { conn_free(compat_conn); TALLOC_FREE(tcon); return NT_STATUS_NO_MEMORY; } tcon->global->session_global_id = req->session->global->session_global_id; tcon->compat = talloc_move(tcon, &compat_conn); tcon->status = NT_STATUS_OK; status = smbXsrv_tcon_update(tcon); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(tcon); return status; } if (IS_PRINT(tcon->compat)) { *out_share_type = SMB2_SHARE_TYPE_PRINT; } else if (IS_IPC(tcon->compat)) { *out_share_type = SMB2_SHARE_TYPE_PIPE; } else { *out_share_type = SMB2_SHARE_TYPE_DISK; } *out_share_flags = 0; if (lp_msdfs_root(SNUM(tcon->compat)) && lp_host_msdfs()) { *out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT); *out_capabilities = SMB2_SHARE_CAP_DFS; } else { *out_capabilities = 0; } switch(lp_csc_policy(SNUM(tcon->compat))) { case CSC_POLICY_MANUAL: break; case CSC_POLICY_DOCUMENTS: *out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING; break; case CSC_POLICY_PROGRAMS: *out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING; break; case CSC_POLICY_DISABLE: *out_share_flags |= SMB2_SHAREFLAG_NO_CACHING; break; default: break; } if (lp_hideunreadable(SNUM(tcon->compat)) || lp_hideunwriteable_files(SNUM(tcon->compat))) { *out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM; } if (encryption_desired) { *out_share_flags |= SMB2_SHAREFLAG_ENCRYPT_DATA; } *out_maximal_access = tcon->compat->share_access; *out_tree_id = tcon->global->tcon_wire_id; return NT_STATUS_OK; }