static void display_window(TALLOC_CTX *mem_ctx, struct registry_context *ctx) { struct regedit *regedit; struct tree_node *root; bool colors; int key; initscr(); cbreak(); noecho(); fault_configure(regedit_panic_handler); colors = has_colors(); if (colors) { start_color(); use_default_colors(); assume_default_colors(COLOR_WHITE, COLOR_BLUE); init_pair(PAIR_YELLOW_CYAN, COLOR_YELLOW, COLOR_CYAN); init_pair(PAIR_BLACK_CYAN, COLOR_BLACK, COLOR_CYAN); init_pair(PAIR_YELLOW_BLUE, COLOR_YELLOW, COLOR_BLUE); } regedit = talloc_zero(mem_ctx, struct regedit); SMB_ASSERT(regedit != NULL); regedit_main = regedit; regedit->registry_context = ctx; regedit->main_window = stdscr; keypad(regedit->main_window, TRUE); mvwprintw(regedit->main_window, 0, 0, "Path: "); regedit->path_label = newpad(1, PATH_WIDTH_MAX); SMB_ASSERT(regedit->path_label); wprintw(regedit->path_label, "/"); show_path(regedit_main); root = tree_node_new_root(regedit, ctx); SMB_ASSERT(root != NULL); regedit->keys = tree_view_new(regedit, root, KEY_HEIGHT, KEY_WIDTH, KEY_START_Y, KEY_START_X); SMB_ASSERT(regedit->keys != NULL); regedit->vl = value_list_new(regedit, VAL_HEIGHT, VAL_WIDTH, VAL_START_Y, VAL_START_X); SMB_ASSERT(regedit->vl != NULL); regedit->tree_input = true; print_heading(regedit); tree_view_show(regedit->keys); load_values(regedit); value_list_show(regedit->vl); update_panels(); doupdate(); do { key = regedit_getch(); handle_main_input(regedit, key); update_panels(); doupdate(); } while (key != 'q' || key == 'Q'); endwin(); }
/** * @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_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; }
static const uint8 *get_ntlm_challenge(struct auth_context *auth_context) { DATA_BLOB challenge = data_blob(NULL, 0); const char *challenge_set_by = NULL; auth_methods *auth_method; TALLOC_CTX *mem_ctx; if (auth_context->challenge.length) { DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", auth_context->challenge_set_by)); return auth_context->challenge.data; } auth_context->challenge_may_be_modified = False; for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) { if (auth_method->get_chal == NULL) { DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name)); continue; } DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name)); if (challenge_set_by != NULL) { DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge. Challenge by %s ignored.\n", challenge_set_by, auth_method->name)); continue; } mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name); if (!mem_ctx) { smb_panic("talloc_init() failed!"); } challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx); if (!challenge.length) { DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n", auth_method->name)); } else { DEBUG(5, ("auth_get_challenge: sucessfully got challenge from module %s\n", auth_method->name)); auth_context->challenge = challenge; challenge_set_by = auth_method->name; auth_context->challenge_set_method = auth_method; } talloc_destroy(mem_ctx); } if (!challenge_set_by) { uchar chal[8]; generate_random_buffer(chal, sizeof(chal)); auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, chal, sizeof(chal)); challenge_set_by = "random"; auth_context->challenge_may_be_modified = True; } DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by)); DEBUG(5, ("challenge is: \n")); dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length); SMB_ASSERT(auth_context->challenge.length == 8); auth_context->challenge_set_by=challenge_set_by; return auth_context->challenge.data; }
static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp) { connection_struct *conn = fsp->conn; struct smb_filename *smb_dname = fsp->fsp_name; int ret; SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname)); /* Might be a symlink. */ if(SMB_VFS_LSTAT(conn, smb_dname) != 0) { return map_nt_error_from_unix(errno); } if (S_ISLNK(smb_dname->st.st_ex_mode)) { /* Is what it points to a directory ? */ if(SMB_VFS_STAT(conn, smb_dname) != 0) { return map_nt_error_from_unix(errno); } if (!(S_ISDIR(smb_dname->st.st_ex_mode))) { return NT_STATUS_NOT_A_DIRECTORY; } ret = SMB_VFS_UNLINK(conn, smb_dname); } else { ret = SMB_VFS_RMDIR(conn, smb_dname->base_name); } if (ret == 0) { notify_fname(conn, NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_DIR_NAME, smb_dname->base_name); return NT_STATUS_OK; } if(((errno == ENOTEMPTY)||(errno == EEXIST)) && *lp_veto_files(talloc_tos(), SNUM(conn))) { /* * Check to see if the only thing in this directory are * vetoed files/directories. If so then delete them and * retry. If we fail to delete any of them (and we *don't* * do a recursive delete) then fail the rmdir. */ SMB_STRUCT_STAT st; const char *dname = NULL; char *talloced = NULL; long dirpos = 0; struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0); if(dir_hnd == NULL) { errno = ENOTEMPTY; goto err; } while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) { if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) { TALLOC_FREE(talloced); continue; } if (!is_visible_file(conn, smb_dname->base_name, dname, &st, false)) { TALLOC_FREE(talloced); continue; } if(!IS_VETO_PATH(conn, dname)) { TALLOC_FREE(dir_hnd); TALLOC_FREE(talloced); errno = ENOTEMPTY; goto err; } TALLOC_FREE(talloced); } /* We only have veto files/directories. * Are we allowed to delete them ? */ if(!lp_delete_veto_files(SNUM(conn))) { TALLOC_FREE(dir_hnd); errno = ENOTEMPTY; goto err; } /* Do a recursive delete. */ RewindDir(dir_hnd,&dirpos); while ((dname = ReadDirName(dir_hnd, &dirpos, &st, &talloced)) != NULL) { struct smb_filename *smb_dname_full = NULL; char *fullname = NULL; bool do_break = true; if (ISDOT(dname) || ISDOTDOT(dname)) { TALLOC_FREE(talloced); continue; } if (!is_visible_file(conn, smb_dname->base_name, dname, &st, false)) { TALLOC_FREE(talloced); continue; } fullname = talloc_asprintf(ctx, "%s/%s", smb_dname->base_name, dname); if(!fullname) { errno = ENOMEM; goto err_break; } smb_dname_full = synthetic_smb_fname( talloc_tos(), fullname, NULL, NULL); if (smb_dname_full == NULL) { errno = ENOMEM; goto err_break; } if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) { goto err_break; } if(smb_dname_full->st.st_ex_mode & S_IFDIR) { if(!recursive_rmdir(ctx, conn, smb_dname_full)) { goto err_break; } if(SMB_VFS_RMDIR(conn, smb_dname_full->base_name) != 0) { goto err_break; } } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) { goto err_break; } /* Successful iteration. */ do_break = false; err_break: TALLOC_FREE(fullname); TALLOC_FREE(smb_dname_full); TALLOC_FREE(talloced); if (do_break) break; } TALLOC_FREE(dir_hnd); /* Retry the rmdir */ ret = SMB_VFS_RMDIR(conn, smb_dname->base_name); } err: if (ret != 0) { DEBUG(3,("rmdir_internals: couldn't remove directory %s : " "%s\n", smb_fname_str_dbg(smb_dname), strerror(errno))); return map_nt_error_from_unix(errno); } notify_fname(conn, NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_DIR_NAME, smb_dname->base_name); return NT_STATUS_OK; }
static int copy_files(void) { uint8_t * iobuf; /* IO buffer. */ uint64_t iomax; /* Size of the IO buffer. */ uint64_t data_size; /* Amount of data in the IO buffer. */ uint64_t ibs; uint64_t obs; uint64_t count; struct dd_iohandle * ifile; struct dd_iohandle * ofile; ibs = check_arg_numeric("ibs"); obs = check_arg_numeric("obs"); count = check_arg_numeric("count"); /* Allocate IO buffer. We need more than the max IO size because we * could accumulate a remainder if ibs and obs don't match. */ iomax = 2 * MAX(ibs, obs); if ((iobuf = malloc(iomax)) == NULL) { fprintf(stderr, "%s: failed to allocate IO buffer of %llu bytes\n", PROGNAME, (unsigned long long)iomax); return(EOM_EXIT_CODE); } set_max_xmit(MAX(ibs, obs)); DEBUG(4, ("IO buffer size is %llu, max xmit is %d\n", (unsigned long long)iomax, lp_max_xmit())); if (!(ifile = open_file("if"))) { return(FILESYS_EXIT_CODE); } if (!(ofile = open_file("of"))) { return(FILESYS_EXIT_CODE); } /* Seek the files to their respective starting points. */ ifile->io_seek(ifile, check_arg_numeric("skip") * ibs); ofile->io_seek(ofile, check_arg_numeric("seek") * obs); DEBUG(4, ("max xmit was negotiated to be %d\n", lp_max_xmit())); for (data_size = 0;;) { /* Handle signals. We are somewhat compatible with GNU dd. * SIGINT makes us stop, but still print transfer statistics. * SIGUSR1 makes us print transfer statistics but we continue * copying. */ if (dd_sigint) { break; } if (dd_sigusr1) { print_transfer_stats(); dd_sigusr1 = 0; } if (ifile->io_flags & DD_END_OF_FILE) { DEBUG(4, ("flushing %llu bytes at EOF\n", (unsigned long long)data_size)); while (data_size > 0) { if (!dd_flush_block(ofile, iobuf, &data_size, obs)) { return(IOERROR_EXIT_CODE); } } goto done; } /* Try and read enough blocks of ibs bytes to be able write * out one of obs bytes. */ if (!dd_fill_block(ifile, iobuf, &data_size, obs, ibs)) { return(IOERROR_EXIT_CODE); } if (data_size == 0) { /* Done. */ SMB_ASSERT(ifile->io_flags & DD_END_OF_FILE); } /* Stop reading when we hit the block count. */ if (dd_stats.in.bytes >= (ibs * count)) { ifile->io_flags |= DD_END_OF_FILE; } /* If we wanted to be a legitimate dd, we would do character * conversions and other shenanigans here. */ /* Flush what we read in units of obs bytes. We want to have * at least obs bytes in the IO buffer but might not if the * file is too small. */ if (data_size && !dd_flush_block(ofile, iobuf, &data_size, obs)) { return(IOERROR_EXIT_CODE); } } done: print_transfer_stats(); return(0); }
/* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */ static bool zfs_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) { int naces = smb_get_naces(smbacl), i; ace_t *acebuf; SMB4ACE_T *smbace; TALLOC_CTX *mem_ctx; bool have_special_id = false; /* allocate the field of ZFS aces */ mem_ctx = talloc_tos(); acebuf = (ace_t *) talloc_size(mem_ctx, sizeof(ace_t)*naces); if(acebuf == NULL) { errno = ENOMEM; return False; } /* handle all aces */ for(smbace = smb_first_ace4(smbacl), i = 0; smbace!=NULL; smbace = smb_next_ace4(smbace), i++) { SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); acebuf[i].a_type = aceprop->aceType; acebuf[i].a_flags = aceprop->aceFlags; acebuf[i].a_access_mask = aceprop->aceMask; /* SYNC on acls is a no-op on ZFS. See bug #7909. */ acebuf[i].a_access_mask &= ~SMB_ACE4_SYNCHRONIZE; acebuf[i].a_who = aceprop->who.id; if(aceprop->flags & SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) { case SMB_ACE4_WHO_EVERYONE: acebuf[i].a_flags |= ACE_EVERYONE; break; case SMB_ACE4_WHO_OWNER: acebuf[i].a_flags |= ACE_OWNER; break; case SMB_ACE4_WHO_GROUP: acebuf[i].a_flags |= ACE_GROUP; break; default: DEBUG(8, ("unsupported special_id %d\n", \ aceprop->who.special_id)); continue; /* don't add it !!! */ } have_special_id = true; } } if (!have_special_id && lp_parm_bool(fsp->conn->params->service, "zfsacl", "denymissingspecial", false)) { errno = EACCES; return false; } SMB_ASSERT(i == naces); /* store acl */ if(acl(fsp->fsp_name->base_name, ACE_SETACL, naces, acebuf)) { if(errno == ENOSYS) { DEBUG(9, ("acl(ACE_SETACL, %s): Operation is not " "supported on the filesystem where the file " "reside", fsp_str_dbg(fsp))); } else { DEBUG(9, ("acl(ACE_SETACL, %s): %s ", fsp_str_dbg(fsp), strerror(errno))); } return 0; } return True; }
static NTSTATUS close_remove_share_mode(files_struct *fsp, enum file_close_type close_type) { connection_struct *conn = fsp->conn; struct server_id self = messaging_server_id(conn->sconn->msg_ctx); bool delete_file = false; bool changed_user = false; struct share_mode_lock *lck = NULL; NTSTATUS status = NT_STATUS_OK; NTSTATUS tmp_status; struct file_id id; const struct security_unix_token *del_token = NULL; const struct security_token *del_nt_token = NULL; bool got_tokens = false; bool normal_close; int ret_flock; /* Ensure any pending write time updates are done. */ if (fsp->update_write_time_event) { update_write_time_handler(fsp->conn->sconn->ev_ctx, fsp->update_write_time_event, timeval_current(), (void *)fsp); } /* * Lock the share entries, and determine if we should delete * on close. If so delete whilst the lock is still in effect. * This prevents race conditions with the file being created. JRA. */ lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck == NULL) { DEBUG(0, ("close_remove_share_mode: Could not get share mode " "lock for file %s\n", fsp_str_dbg(fsp))); return NT_STATUS_INVALID_PARAMETER; } if (fsp->write_time_forced) { DEBUG(10,("close_remove_share_mode: write time forced " "for file %s\n", fsp_str_dbg(fsp))); set_close_write_time(fsp, lck->data->changed_write_time); } else if (fsp->update_write_time_on_close) { /* Someone had a pending write. */ if (null_timespec(fsp->close_write_time)) { DEBUG(10,("close_remove_share_mode: update to current time " "for file %s\n", fsp_str_dbg(fsp))); /* Update to current time due to "normal" write. */ set_close_write_time(fsp, timespec_current()); } else { DEBUG(10,("close_remove_share_mode: write time pending " "for file %s\n", fsp_str_dbg(fsp))); /* Update to time set on close call. */ set_close_write_time(fsp, fsp->close_write_time); } } if (fsp->initial_delete_on_close && !is_delete_on_close_set(lck, fsp->name_hash)) { bool became_user = False; /* Initial delete on close was set and no one else * wrote a real delete on close. */ if (get_current_vuid(conn) != fsp->vuid) { become_user(conn, fsp->vuid); became_user = True; } fsp->delete_on_close = true; set_delete_on_close_lck(fsp, lck, get_current_nttok(conn), get_current_utok(conn)); if (became_user) { unbecome_user(); } } delete_file = is_delete_on_close_set(lck, fsp->name_hash); if (delete_file) { int i; /* See if others still have the file open via this pathname. If this is the case, then don't delete. If all opens are POSIX delete now. */ for (i=0; i<lck->data->num_share_modes; i++) { struct share_mode_entry *e = &lck->data->share_modes[i]; if (!is_valid_share_mode_entry(e)) { continue; } if (e->name_hash != fsp->name_hash) { continue; } if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) { continue; } if (serverid_equal(&self, &e->pid) && (e->share_file_id == fsp->fh->gen_id)) { continue; } if (share_mode_stale_pid(lck->data, i)) { continue; } delete_file = False; break; } } /* * NT can set delete_on_close of the last open * reference to a file. */ normal_close = (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE); if (!normal_close || !delete_file) { status = NT_STATUS_OK; goto done; } /* * Ok, we have to delete the file */ DEBUG(5,("close_remove_share_mode: file %s. Delete on close was set " "- deleting file.\n", fsp_str_dbg(fsp))); /* * Don't try to update the write time when we delete the file */ fsp->update_write_time_on_close = false; got_tokens = get_delete_on_close_token(lck, fsp->name_hash, &del_nt_token, &del_token); SMB_ASSERT(got_tokens); if (!unix_token_equal(del_token, get_current_utok(conn))) { /* Become the user who requested the delete. */ DEBUG(5,("close_remove_share_mode: file %s. " "Change user to uid %u\n", fsp_str_dbg(fsp), (unsigned int)del_token->uid)); if (!push_sec_ctx()) { smb_panic("close_remove_share_mode: file %s. failed to push " "sec_ctx.\n"); } set_sec_ctx(del_token->uid, del_token->gid, del_token->ngroups, del_token->groups, del_nt_token); changed_user = true; } /* We can only delete the file if the name we have is still valid and hasn't been renamed. */ tmp_status = vfs_stat_fsp(fsp); if (!NT_STATUS_IS_OK(tmp_status)) { DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and stat failed with error %s\n", fsp_str_dbg(fsp), nt_errstr(tmp_status))); /* * Don't save the errno here, we ignore this error */ goto done; } id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st); if (!file_id_equal(&fsp->file_id, &id)) { DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and dev and/or inode does not match\n", fsp_str_dbg(fsp))); DEBUG(5,("close_remove_share_mode: file %s. stored file_id %s, " "stat file_id %s\n", fsp_str_dbg(fsp), file_id_string_tos(&fsp->file_id), file_id_string_tos(&id))); /* * Don't save the errno here, we ignore this error */ goto done; } if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && !is_ntfs_stream_smb_fname(fsp->fsp_name)) { status = delete_all_streams(conn, fsp->fsp_name->base_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("delete_all_streams failed: %s\n", nt_errstr(status))); goto done; } } if (SMB_VFS_UNLINK(conn, fsp->fsp_name) != 0) { /* * This call can potentially fail as another smbd may * have had the file open with delete on close set and * deleted it when its last reference to this file * went away. Hence we log this but not at debug level * zero. */ DEBUG(5,("close_remove_share_mode: file %s. Delete on close " "was set and unlink failed with error %s\n", fsp_str_dbg(fsp), strerror(errno))); status = map_nt_error_from_unix(errno); } /* As we now have POSIX opens which can unlink * with other open files we may have taken * this code path with more than one share mode * entry - ensure we only delete once by resetting * the delete on close flag. JRA. */ fsp->delete_on_close = false; reset_delete_on_close_lck(fsp, lck); done: if (changed_user) { /* unbecome user. */ pop_sec_ctx(); } /* remove filesystem sharemodes */ ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, 0, 0); if (ret_flock == -1) { DEBUG(2, ("close_remove_share_mode: removing kernel flock for " "%s failed: %s\n", fsp_str_dbg(fsp), strerror(errno))); } if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_remove_share_mode: Could not delete share " "entry for file %s\n", fsp_str_dbg(fsp))); } TALLOC_FREE(lck); if (delete_file) { /* * Do the notification after we released the share * mode lock. Inside notify_fname we take out another * tdb lock. With ctdb also accessing our databases, * this can lead to deadlocks. Putting this notify * after the TALLOC_FREE(lck) above we avoid locking * two records simultaneously. Notifies are async and * informational only, so calling the notify_fname * without holding the share mode lock should not do * any harm. */ notify_fname(conn, NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_FILE_NAME, fsp->fsp_name->base_name); } return status; }
static NTSTATUS set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge) { SMB_ASSERT(challenge->length == 8); return NT_STATUS_OK; }
static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, const DATA_BLOB request, DATA_BLOB *reply) { DATA_BLOB encrypted_session_key = data_blob(NULL, 0); DATA_BLOB user_session_key = data_blob(NULL, 0); DATA_BLOB lm_session_key = data_blob(NULL, 0); DATA_BLOB session_key = data_blob(NULL, 0); uint32 ntlmssp_command, auth_flags; NTSTATUS nt_status; /* used by NTLM2 */ BOOL doing_ntlm2 = False; uchar session_nonce[16]; uchar session_nonce_hash[16]; const char *parse_string; char *domain = NULL; char *user = NULL; char *workstation = NULL; /* parse the NTLMSSP packet */ *reply = data_blob(NULL, 0); #if 0 file_save("ntlmssp_auth.dat", request.data, request.length); #endif if (ntlmssp_state->unicode) { parse_string = "CdBBUUUBd"; } else { parse_string = "CdBBAAABd"; } data_blob_free(&ntlmssp_state->lm_resp); data_blob_free(&ntlmssp_state->nt_resp); ntlmssp_state->user = NULL; ntlmssp_state->domain = NULL; ntlmssp_state->workstation = NULL; /* now the NTLMSSP encoded auth hashes */ if (!msrpc_parse(&request, parse_string, "NTLMSSP", &ntlmssp_command, &ntlmssp_state->lm_resp, &ntlmssp_state->nt_resp, &domain, &user, &workstation, &encrypted_session_key, &auth_flags)) { SAFE_FREE(domain); SAFE_FREE(user); SAFE_FREE(workstation); data_blob_free(&encrypted_session_key); auth_flags = 0; /* Try again with a shorter string (Win9X truncates this packet) */ if (ntlmssp_state->unicode) { parse_string = "CdBBUUU"; } else { parse_string = "CdBBAAA"; } /* now the NTLMSSP encoded auth hashes */ if (!msrpc_parse(&request, parse_string, "NTLMSSP", &ntlmssp_command, &ntlmssp_state->lm_resp, &ntlmssp_state->nt_resp, &domain, &user, &workstation)) { DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP (tried both formats):\n")); dump_data(2, (const char *)request.data, request.length); SAFE_FREE(domain); SAFE_FREE(user); SAFE_FREE(workstation); return NT_STATUS_INVALID_PARAMETER; } } if (auth_flags) ntlmssp_handle_neg_flags(ntlmssp_state, auth_flags, lp_lanman_auth()); if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) { SAFE_FREE(domain); SAFE_FREE(user); SAFE_FREE(workstation); data_blob_free(&encrypted_session_key); return nt_status; } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) { SAFE_FREE(domain); SAFE_FREE(user); SAFE_FREE(workstation); data_blob_free(&encrypted_session_key); return nt_status; } if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_workstation(ntlmssp_state, workstation))) { SAFE_FREE(domain); SAFE_FREE(user); SAFE_FREE(workstation); data_blob_free(&encrypted_session_key); return nt_status; } SAFE_FREE(domain); SAFE_FREE(user); SAFE_FREE(workstation); DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n", ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, (unsigned long)ntlmssp_state->lm_resp.length, (unsigned long)ntlmssp_state->nt_resp.length)); #if 0 file_save("nthash1.dat", &ntlmssp_state->nt_resp.data, &ntlmssp_state->nt_resp.length); file_save("lmhash1.dat", &ntlmssp_state->lm_resp.data, &ntlmssp_state->lm_resp.length); #endif /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a client challenge However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful. */ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { if (ntlmssp_state->nt_resp.length == 24 && ntlmssp_state->lm_resp.length == 24) { struct MD5Context md5_session_nonce_ctx; SMB_ASSERT(ntlmssp_state->internal_chal.data && ntlmssp_state->internal_chal.length == 8); doing_ntlm2 = True; memcpy(session_nonce, ntlmssp_state->internal_chal.data, 8); memcpy(&session_nonce[8], ntlmssp_state->lm_resp.data, 8); MD5Init(&md5_session_nonce_ctx); MD5Update(&md5_session_nonce_ctx, session_nonce, 16); MD5Final(session_nonce_hash, &md5_session_nonce_ctx); ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, session_nonce_hash, 8); /* LM response is no longer useful */ data_blob_free(&ntlmssp_state->lm_resp); /* We changed the effective challenge - set it */ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->set_challenge(ntlmssp_state, &ntlmssp_state->chal))) { data_blob_free(&encrypted_session_key); return nt_status; } } } /* * Note we don't check here for NTLMv2 auth settings. If NTLMv2 auth * is required (by "ntlm auth = no" and "lm auth = no" being set in the * smb.conf file) and no NTLMv2 response was sent then the password check * will fail here. JRA. */ /* Finally, actually ask if the password is OK */ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state, &user_session_key, &lm_session_key))) { data_blob_free(&encrypted_session_key); return nt_status; } dump_data_pw("NT session key:\n", user_session_key.data, user_session_key.length); dump_data_pw("LM first-8:\n", lm_session_key.data, lm_session_key.length); /* Handle the different session key derivation for NTLM2 */ if (doing_ntlm2) { if (user_session_key.data && user_session_key.length == 16) { session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); hmac_md5(user_session_key.data, session_nonce, sizeof(session_nonce), session_key.data); DEBUG(10,("ntlmssp_server_auth: Created NTLM2 session key.\n")); dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); } else { DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM2 session key.\n")); session_key = data_blob(NULL, 0); } } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) { if (lm_session_key.data && lm_session_key.length >= 8) { if (ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) { session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); SMBsesskeygen_lm_sess_key(lm_session_key.data, ntlmssp_state->lm_resp.data, session_key.data); DEBUG(10,("ntlmssp_server_auth: Created NTLM session key.\n")); dump_data_pw("LM session key:\n", session_key.data, session_key.length); } else { /* use the key unmodified - it's * probably a NULL key from the guest * login */ session_key = lm_session_key; } } else { DEBUG(10,("ntlmssp_server_auth: Failed to create NTLM session key.\n")); session_key = data_blob(NULL, 0); } } else if (user_session_key.data) { session_key = user_session_key; DEBUG(10,("ntlmssp_server_auth: Using unmodified nt session key.\n")); dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); } else if (lm_session_key.data) { session_key = lm_session_key; DEBUG(10,("ntlmssp_server_auth: Using unmodified lm session key.\n")); dump_data_pw("unmodified session key:\n", session_key.data, session_key.length); } else { DEBUG(10,("ntlmssp_server_auth: Failed to create unmodified session key.\n")); session_key = data_blob(NULL, 0); } /* With KEY_EXCH, the client supplies the proposed session key, but encrypts it with the long-term key */ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { if (!encrypted_session_key.data || encrypted_session_key.length != 16) { data_blob_free(&encrypted_session_key); DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n", encrypted_session_key.length)); return NT_STATUS_INVALID_PARAMETER; } else if (!session_key.data || session_key.length != 16) { DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n", session_key.length)); ntlmssp_state->session_key = session_key; } else { dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length); SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length); ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state->mem_ctx, encrypted_session_key.data, encrypted_session_key.length); dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length); } } else { ntlmssp_state->session_key = session_key; } if (!NT_STATUS_IS_OK(nt_status)) { ntlmssp_state->session_key = data_blob(NULL, 0); } else if (ntlmssp_state->session_key.length) { nt_status = ntlmssp_sign_init(ntlmssp_state); } data_blob_free(&encrypted_session_key); /* allow arbitarily many authentications */ ntlmssp_state->expected_state = NTLMSSP_AUTH; return nt_status; }
NTSTATUS unix_convert(TALLOC_CTX *ctx, connection_struct *conn, const char *orig_path, bool allow_wcard_last_component, char **pp_conv_path, char **pp_saved_last_component, SMB_STRUCT_STAT *pst) { SMB_STRUCT_STAT st; char *start, *end; char *dirpath = NULL; char *name = NULL; char *stream = NULL; bool component_was_mangled = False; bool name_has_wildcard = False; bool posix_pathnames = false; NTSTATUS result; int ret = -1; SET_STAT_INVALID(*pst); *pp_conv_path = NULL; if(pp_saved_last_component) { *pp_saved_last_component = NULL; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) { return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; } DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path)); /* * Conversion to basic unix format is already done in * check_path_syntax(). */ /* * Names must be relative to the root of the service - any leading /. * and trailing /'s should have been trimmed by check_path_syntax(). */ #ifdef DEVELOPER SMB_ASSERT(*orig_path != '/'); #endif /* * If we trimmed down to a single '\0' character * then we should use the "." directory to avoid * searching the cache, but not if we are in a * printing share. * As we know this is valid we can return true here. */ if (!*orig_path) { if (!(name = talloc_strdup(ctx,"."))) { return NT_STATUS_NO_MEMORY; } if (SMB_VFS_STAT(conn,name,&st) == 0) { *pst = st; } else { return map_nt_error_from_unix(errno); } DEBUG(5,("conversion finished \"\" -> %s\n",name)); goto done; } if (orig_path[0] == '.' && (orig_path[1] == '/' || orig_path[1] == '\0')) { /* Start of pathname can't be "." only. */ if (orig_path[1] == '\0' || orig_path[2] == '\0') { result = NT_STATUS_OBJECT_NAME_INVALID; } else { result =determine_path_error( &orig_path[2], allow_wcard_last_component); } return result; } if (!(name = talloc_strdup(ctx, orig_path))) { DEBUG(0, ("talloc_strdup failed\n")); return NT_STATUS_NO_MEMORY; } /* * Large directory fix normalization. If we're case sensitive, and * the case preserving parameters are set to "no", normalize the case of * the incoming filename from the client WHETHER IT EXISTS OR NOT ! * This is in conflict with the current (3.0.20) man page, but is * what people expect from the "large directory howto". I'll update * the man page. Thanks to [email protected] for finding this. JRA. */ if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) { strnorm(name, lp_defaultcase(SNUM(conn))); } /* * Ensure saved_last_component is valid even if file exists. */ if(pp_saved_last_component) { end = strrchr_m(name, '/'); if (end) { *pp_saved_last_component = talloc_strdup(ctx, end + 1); } else { *pp_saved_last_component = talloc_strdup(ctx, name); } } posix_pathnames = lp_posix_pathnames(); if (!posix_pathnames) { stream = strchr_m(name, ':'); if (stream != NULL) { char *tmp = talloc_strdup(ctx, stream); if (tmp == NULL) { TALLOC_FREE(name); return NT_STATUS_NO_MEMORY; } *stream = '\0'; stream = tmp; } } start = name; /* If we're providing case insentive semantics or * the underlying filesystem is case insensitive, * then a case-normalized hit in the stat-cache is * authoratitive. JRA. */ if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && stat_cache_lookup(conn, &name, &dirpath, &start, &st)) { *pst = st; goto done; } /* * Make sure "dirpath" is an allocated string, we use this for * building the directories with asprintf and free it. */ if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) { DEBUG(0, ("talloc_strdup failed\n")); TALLOC_FREE(name); return NT_STATUS_NO_MEMORY; } /* * stat the name - if it exists then we are all done! */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn,name,&st); } else { ret = SMB_VFS_STAT(conn,name,&st); } if (ret == 0) { /* Ensure we catch all names with in "/." this is disallowed under Windows. */ const char *p = strstr(name, "/."); /* mb safe. */ if (p) { if (p[2] == '/') { /* Error code within a pathname. */ result = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } else if (p[2] == '\0') { /* Error code at the end of a pathname. */ result = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } } stat_cache_add(orig_path, name, conn->case_sensitive); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); *pst = st; goto done; } DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start)); /* * A special case - if we don't have any mangling chars and are case * sensitive or the underlying filesystem is case insentive then searching * won't help. */ if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && !mangle_is_mangled(name, conn->params)) { goto done; } /* * is_mangled() was changed to look at an entire pathname, not * just a component. JRA. */ if (mangle_is_mangled(start, conn->params)) { component_was_mangled = True; } /* * Now we need to recursively match the name against the real * directory structure. */ /* * Match each part of the path name separately, trying the names * as is first, then trying to scan the directory for matching names. */ for (; start ; start = (end?end+1:(char *)NULL)) { /* * Pinpoint the end of this section of the filename. */ /* mb safe. '/' can't be in any encoded char. */ end = strchr(start, '/'); /* * Chop the name at this point. */ if (end) { *end = 0; } if (pp_saved_last_component) { TALLOC_FREE(*pp_saved_last_component); *pp_saved_last_component = talloc_strdup(ctx, end ? end + 1 : start); if (!*pp_saved_last_component) { DEBUG(0, ("talloc failed\n")); return NT_STATUS_NO_MEMORY; } } /* The name cannot have a component of "." */ if (ISDOT(start)) { if (!end) { /* Error code at the end of a pathname. */ result = NT_STATUS_OBJECT_NAME_INVALID; } else { result = determine_path_error(end+1, allow_wcard_last_component); } goto fail; } /* The name cannot have a wildcard if it's not the last component. */ name_has_wildcard = ms_has_wild(start); /* Wildcard not valid anywhere. */ if (name_has_wildcard && !allow_wcard_last_component) { result = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } /* Wildcards never valid within a pathname. */ if (name_has_wildcard && end) { result = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } /* * Check if the name exists up to this point. */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn,name, &st); } else { ret = SMB_VFS_STAT(conn,name, &st); } if (ret == 0) { /* * It exists. it must either be a directory or this must * be the last part of the path for it to be OK. */ if (end && !(st.st_mode & S_IFDIR)) { /* * An intermediate part of the name isn't * a directory. */ DEBUG(5,("Not a dir %s\n",start)); *end = '/'; /* * We need to return the fact that the * intermediate name resolution failed. This * is used to return an error of ERRbadpath * rather than ERRbadfile. Some Windows * applications depend on the difference between * these two errors. */ result = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } if (!end) { /* * We just scanned for, and found the end of * the path. We must return the valid stat * struct. JRA. */ *pst = st; } } else { char *found_name = NULL; /* Stat failed - ensure we don't use it. */ SET_STAT_INVALID(st); /* * Reset errno so we can detect * directory open errors. */ errno = 0; /* * Try to find this part of the path in the directory. */ if (name_has_wildcard || (get_real_filename_mangled( conn, dirpath, start, talloc_tos(), &found_name) == -1)) { char *unmangled; if (end) { /* * An intermediate part of the name * can't be found. */ DEBUG(5,("Intermediate not found %s\n", start)); *end = '/'; /* * We need to return the fact that the * intermediate name resolution failed. * This is used to return an error of * ERRbadpath rather than ERRbadfile. * Some Windows applications depend on * the difference between these two * errors. */ /* * ENOENT, ENOTDIR and ELOOP all map * to NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP) { result = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { result = map_nt_error_from_unix(errno); } goto fail; } /* ENOENT is the only valid error here. */ if ((errno != 0) && (errno != ENOENT)) { /* * ENOTDIR and ELOOP both map to * NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOTDIR || errno == ELOOP) { result = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { result = map_nt_error_from_unix(errno); } goto fail; } /* * Just the last part of the name doesn't exist. * We need to strupper() or strlower() it as * this conversion may be used for file creation * purposes. Fix inspired by * Thomas Neumann <*****@*****.**>. */ if (!conn->case_preserve || (mangle_is_8_3(start, False, conn->params) && !conn->short_case_preserve)) { strnorm(start, lp_defaultcase(SNUM(conn))); } /* * check on the mangled stack to see if we can * recover the base of the filename. */ if (mangle_is_mangled(start, conn->params) && mangle_lookup_name_from_8_3(ctx, start, &unmangled, conn->params)) { char *tmp; size_t start_ofs = start - name; if (*dirpath != '\0') { tmp = talloc_asprintf(ctx, "%s/%s", dirpath, unmangled); TALLOC_FREE(unmangled); } else { tmp = unmangled; } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); return NT_STATUS_NO_MEMORY; } TALLOC_FREE(name); name = tmp; start = name + start_ofs; end = start + strlen(start); } DEBUG(5,("New file %s\n",start)); goto done; } /* * Restore the rest of the string. If the string was * mangled the size may have changed. */ if (end) { char *tmp; size_t start_ofs = start - name; if (*dirpath != '\0') { tmp = talloc_asprintf(ctx, "%s/%s/%s", dirpath, found_name, end+1); } else { tmp = talloc_asprintf(ctx, "%s/%s", found_name, end+1); } if (tmp == NULL) { DEBUG(0, ("talloc_asprintf failed\n")); return NT_STATUS_NO_MEMORY; } TALLOC_FREE(name); name = tmp; start = name + start_ofs; end = start + strlen(found_name); *end = '\0'; } else { char *tmp; size_t start_ofs = start - name; if (*dirpath != '\0') { tmp = talloc_asprintf(ctx, "%s/%s", dirpath, found_name); } else { tmp = talloc_strdup(ctx, found_name); } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); return NT_STATUS_NO_MEMORY; } TALLOC_FREE(name); name = tmp; start = name + start_ofs; /* * We just scanned for, and found the end of * the path. We must return a valid stat struct * if it exists. JRA. */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn,name, &st); } else { ret = SMB_VFS_STAT(conn,name, &st); } if (ret == 0) { *pst = st; } else { SET_STAT_INVALID(st); } } TALLOC_FREE(found_name); } /* end else */ #ifdef DEVELOPER /* * This sucks! * We should never provide different behaviors * depending on DEVELOPER!!! */ if (VALID_STAT(st)) { bool delete_pending; get_file_infos(vfs_file_id_from_sbuf(conn, &st), &delete_pending, NULL); if (delete_pending) { result = NT_STATUS_DELETE_PENDING; goto fail; } } #endif /* * Add to the dirpath that we have resolved so far. */ if (*dirpath != '\0') { char *tmp = talloc_asprintf(ctx, "%s/%s", dirpath, start); if (!tmp) { DEBUG(0, ("talloc_asprintf failed\n")); return NT_STATUS_NO_MEMORY; } TALLOC_FREE(dirpath); dirpath = tmp; } else { TALLOC_FREE(dirpath); if (!(dirpath = talloc_strdup(ctx,start))) { DEBUG(0, ("talloc_strdup failed\n")); return NT_STATUS_NO_MEMORY; } } /* * Don't cache a name with mangled or wildcard components * as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, dirpath, conn->case_sensitive); } /* * Restore the / that we wiped out earlier. */ if (end) { *end = '/'; } } /* * Don't cache a name with mangled or wildcard components * as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, name, conn->case_sensitive); } /* * The name has been resolved. */ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); done: if (stream != NULL) { char *tmp = NULL; result = build_stream_path(ctx, conn, orig_path, name, stream, pst, &tmp); if (!NT_STATUS_IS_OK(result)) { goto fail; } DEBUG(10, ("build_stream_path returned %s\n", tmp)); TALLOC_FREE(name); name = tmp; } *pp_conv_path = name; TALLOC_FREE(dirpath); return NT_STATUS_OK; fail: DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); if (*dirpath != '\0') { *pp_conv_path = talloc_asprintf(ctx, "%s/%s", dirpath, start); } else { *pp_conv_path = talloc_strdup(ctx, start); } if (!*pp_conv_path) { DEBUG(0, ("talloc_asprintf failed\n")); return NT_STATUS_NO_MEMORY; } TALLOC_FREE(name); TALLOC_FREE(dirpath); return result; }
NTSTATUS unix_convert(connection_struct *conn, pstring name, BOOL allow_wcard_last_component, char *saved_last_component, SMB_STRUCT_STAT *pst) { SMB_STRUCT_STAT st; char *start, *end; pstring dirpath; pstring orig_path; BOOL component_was_mangled = False; BOOL name_has_wildcard = False; SET_STAT_INVALID(*pst); *dirpath = 0; if(saved_last_component) { *saved_last_component = 0; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ return NT_STATUS_OK; } DEBUG(5, ("unix_convert called on file \"%s\"\n", name)); /* * Conversion to basic unix format is already done in check_path_syntax(). */ /* * Names must be relative to the root of the service - any leading /. * and trailing /'s should have been trimmed by check_path_syntax(). */ #ifdef DEVELOPER SMB_ASSERT(*name != '/'); #endif /* * If we trimmed down to a single '\0' character * then we should use the "." directory to avoid * searching the cache, but not if we are in a * printing share. * As we know this is valid we can return true here. */ if (!*name) { name[0] = '.'; name[1] = '\0'; if (SMB_VFS_STAT(conn,name,&st) == 0) { *pst = st; } DEBUG(5,("conversion finished \"\" -> %s\n",name)); return NT_STATUS_OK; } if (name[0] == '.' && (name[1] == '/' || name[1] == '\0')) { /* Start of pathname can't be "." only. */ if (name[1] == '\0' || name[2] == '\0') { return NT_STATUS_OBJECT_NAME_INVALID; } else { return determine_path_error(&name[2], allow_wcard_last_component); } } /* * Ensure saved_last_component is valid even if file exists. */ if(saved_last_component) { end = strrchr_m(name, '/'); if (end) { pstrcpy(saved_last_component, end + 1); } else { pstrcpy(saved_last_component, name); } } /* * Large directory fix normalization. If we're case sensitive, and * the case preserving parameters are set to "no", normalize the case of * the incoming filename from the client WHETHER IT EXISTS OR NOT ! * This is in conflict with the current (3.0.20) man page, but is * what people expect from the "large directory howto". I'll update * the man page. Thanks to [email protected] for finding this. JRA. */ if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) { strnorm(name, lp_defaultcase(SNUM(conn))); } start = name; pstrcpy(orig_path, name); if(!conn->case_sensitive && stat_cache_lookup(conn, name, dirpath, &start, &st)) { *pst = st; return NT_STATUS_OK; } /* * stat the name - if it exists then we are all done! */ if (SMB_VFS_STAT(conn,name,&st) == 0) { /* Ensure we catch all names with in "/." this is disallowed under Windows. */ const char *p = strstr(name, "/."); /* mb safe. */ if (p) { if (p[2] == '/') { /* Error code within a pathname. */ return NT_STATUS_OBJECT_PATH_NOT_FOUND; } else if (p[2] == '\0') { /* Error code at the end of a pathname. */ return NT_STATUS_OBJECT_NAME_INVALID; } } stat_cache_add(orig_path, name, conn->case_sensitive); DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); *pst = st; return NT_STATUS_OK; } DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", name, dirpath, start)); /* * A special case - if we don't have any mangling chars and are case * sensitive then searching won't help. */ if (conn->case_sensitive && !mangle_is_mangled(name, conn->params) && !*lp_mangled_map(conn->params)) { return NT_STATUS_OK; } /* * is_mangled() was changed to look at an entire pathname, not * just a component. JRA. */ if (mangle_is_mangled(start, conn->params)) { component_was_mangled = True; } /* * Now we need to recursively match the name against the real * directory structure. */ /* * Match each part of the path name separately, trying the names * as is first, then trying to scan the directory for matching names. */ for (; start ; start = (end?end+1:(char *)NULL)) { /* * Pinpoint the end of this section of the filename. */ end = strchr(start, '/'); /* mb safe. '/' can't be in any encoded char. */ /* * Chop the name at this point. */ if (end) { *end = 0; } if (saved_last_component != 0) { pstrcpy(saved_last_component, end ? end + 1 : start); } /* The name cannot have a component of "." */ if (ISDOT(start)) { if (!end) { /* Error code at the end of a pathname. */ return NT_STATUS_OBJECT_NAME_INVALID; } return determine_path_error(end+1, allow_wcard_last_component); } /* The name cannot have a wildcard if it's not the last component. */ name_has_wildcard = ms_has_wild(start); /* Wildcard not valid anywhere. */ if (name_has_wildcard && !allow_wcard_last_component) { return NT_STATUS_OBJECT_NAME_INVALID; } /* Wildcards never valid within a pathname. */ if (name_has_wildcard && end) { return NT_STATUS_OBJECT_NAME_INVALID; } /* * Check if the name exists up to this point. */ if (SMB_VFS_STAT(conn,name, &st) == 0) { /* * It exists. it must either be a directory or this must be * the last part of the path for it to be OK. */ if (end && !(st.st_mode & S_IFDIR)) { /* * An intermediate part of the name isn't a directory. */ DEBUG(5,("Not a dir %s\n",start)); *end = '/'; /* * We need to return the fact that the intermediate * name resolution failed. This is used to return an * error of ERRbadpath rather than ERRbadfile. Some * Windows applications depend on the difference between * these two errors. */ return NT_STATUS_OBJECT_PATH_NOT_FOUND; } if (!end) { /* * We just scanned for, and found the end of the path. * We must return the valid stat struct. * JRA. */ *pst = st; } } else { pstring rest; /* Stat failed - ensure we don't use it. */ SET_STAT_INVALID(st); *rest = 0; /* * Remember the rest of the pathname so it can be restored * later. */ if (end) { pstrcpy(rest,end+1); } /* Reset errno so we can detect directory open errors. */ errno = 0; /* * Try to find this part of the path in the directory. */ if (name_has_wildcard || !scan_directory(conn, dirpath, start, sizeof(pstring) - 1 - (start - name))) { if (end) { /* * An intermediate part of the name can't be found. */ DEBUG(5,("Intermediate not found %s\n",start)); *end = '/'; /* * We need to return the fact that the intermediate * name resolution failed. This is used to return an * error of ERRbadpath rather than ERRbadfile. Some * Windows applications depend on the difference between * these two errors. */ /* ENOENT, ENOTDIR and ELOOP all map to * NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } return map_nt_error_from_unix(errno); } /* ENOENT is the only valid error here. */ if (errno != ENOENT) { /* ENOTDIR and ELOOP both map to * NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOTDIR || errno == ELOOP) { return NT_STATUS_OBJECT_PATH_NOT_FOUND; } return map_nt_error_from_unix(errno); } /* * Just the last part of the name doesn't exist. * We need to strupper() or strlower() it as * this conversion may be used for file creation * purposes. Fix inspired by Thomas Neumann <*****@*****.**>. */ if (!conn->case_preserve || (mangle_is_8_3(start, False, conn->params) && !conn->short_case_preserve)) { strnorm(start, lp_defaultcase(SNUM(conn))); } /* * check on the mangled stack to see if we can recover the * base of the filename. */ if (mangle_is_mangled(start, conn->params)) { mangle_check_cache( start, sizeof(pstring) - 1 - (start - name), conn->params); } DEBUG(5,("New file %s\n",start)); return NT_STATUS_OK; } /* * Restore the rest of the string. If the string was mangled the size * may have changed. */ if (end) { end = start + strlen(start); if (!safe_strcat(start, "/", sizeof(pstring) - 1 - (start - name)) || !safe_strcat(start, rest, sizeof(pstring) - 1 - (start - name))) { return map_nt_error_from_unix(ENAMETOOLONG); } *end = '\0'; } else { /* * We just scanned for, and found the end of the path. * We must return a valid stat struct if it exists. * JRA. */ if (SMB_VFS_STAT(conn,name, &st) == 0) { *pst = st; } else { SET_STAT_INVALID(st); } } } /* end else */ #ifdef DEVELOPER if (VALID_STAT(st) && get_delete_on_close_flag(st.st_dev, st.st_ino)) { return NT_STATUS_DELETE_PENDING; } #endif /* * Add to the dirpath that we have resolved so far. */ if (*dirpath) { pstrcat(dirpath,"/"); } pstrcat(dirpath,start); /* * Don't cache a name with mangled or wildcard components * as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, dirpath, conn->case_sensitive); } /* * Restore the / that we wiped out earlier. */ if (end) { *end = '/'; } } /* * Don't cache a name with mangled or wildcard components * as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, name, conn->case_sensitive); } /* * The name has been resolved. */ DEBUG(5,("conversion finished %s -> %s\n",orig_path, name)); return NT_STATUS_OK; }
/* search for attrs on one DN, in the modules below */ int dsdb_module_search_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_result **_res, struct ldb_dn *basedn, const char * const *attrs, uint32_t dsdb_flags, struct ldb_request *parent) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; tmp_ctx = talloc_new(mem_ctx); res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { talloc_free(tmp_ctx); return ldb_oom(ldb_module_get_ctx(module)); } ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx, basedn, LDB_SCOPE_BASE, NULL, attrs, NULL, res, ldb_search_default_callback, parent); LDB_REQ_SET_LOCATION(req); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = dsdb_request_add_controls(req, dsdb_flags); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (dsdb_flags & DSDB_FLAG_TRUSTED) { ldb_req_mark_trusted(req); } /* Run the new request */ if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) { ret = ldb_next_request(module, req); } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { ret = ldb_request(ldb_module_get_ctx(module), req); } else { const struct ldb_module_ops *ops = ldb_module_get_ops(module); SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE); ret = ops->search(module, req); } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (res->count != 1) { /* we may be reading a DB that does not have the 'check base on search' option... */ ret = LDB_ERR_NO_SUCH_OBJECT; ldb_asprintf_errstring(ldb_module_get_ctx(module), "dsdb_module_search_dn: did not find base dn %s (%d results)", ldb_dn_get_linearized(basedn), res->count); } else { *_res = talloc_steal(mem_ctx, res); } talloc_free(tmp_ctx); return ret; }
int dsdb_module_search_tree(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_result **_res, struct ldb_dn *basedn, enum ldb_scope scope, struct ldb_parse_tree *tree, const char * const *attrs, int dsdb_flags, struct ldb_request *parent) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; tmp_ctx = talloc_new(mem_ctx); /* cross-partitions searches with a basedn break multi-domain support */ SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0); res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { talloc_free(tmp_ctx); return ldb_oom(ldb_module_get_ctx(module)); } ret = ldb_build_search_req_ex(&req, ldb_module_get_ctx(module), tmp_ctx, basedn, scope, tree, attrs, NULL, res, ldb_search_default_callback, parent); LDB_REQ_SET_LOCATION(req); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } ret = dsdb_request_add_controls(req, dsdb_flags); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } if (dsdb_flags & DSDB_FLAG_TRUSTED) { ldb_req_mark_trusted(req); } if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) { ret = ldb_next_request(module, req); } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) { ret = ldb_request(ldb_module_get_ctx(module), req); } else { const struct ldb_module_ops *ops = ldb_module_get_ops(module); SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE); ret = ops->search(module, req); } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } talloc_free(req); if (ret == LDB_SUCCESS) { *_res = talloc_steal(mem_ctx, res); } talloc_free(tmp_ctx); return ret; }
/** * Provision a Samba installation using @param setupdir_script and start smbd. */ NTSTATUS torture_setup_server(TALLOC_CTX *mem_ctx, const char *prefix, const char *setupdir_script, const char *smbd_path, pid_t *smbd_pid) { char *tempdir; NTSTATUS status; pid_t pid; int child_status; char *configfile, *configparam; pid_t closed_pid; *smbd_pid = -1; status = torture_temp_dir(mem_ctx, prefix, &tempdir); if (NT_STATUS_IS_ERR(status)) { return status; } if ((pid = fork()) == 0) { execl(setupdir_script, setupdir_script, tempdir, NULL); exit(1); } else if (pid == -1) { DEBUG(0, ("Unable to fork()\n")); return NT_STATUS_UNSUCCESSFUL; } closed_pid = waitpid(pid, &child_status, 0); if (closed_pid == -1) { DEBUG(1, ("Error waiting for child")); return NT_STATUS_UNSUCCESSFUL; } SMB_ASSERT(closed_pid == pid); if (!WIFEXITED(child_status) || WEXITSTATUS(child_status) != 0) { DEBUG(1, ("Invalid return code from setup script %s: %d\n", setupdir_script, WEXITSTATUS(child_status))); return NT_STATUS_UNSUCCESSFUL; } configfile = talloc_asprintf(mem_ctx, "%s/etc/smb.conf", tempdir); if (!file_exist(configfile)) { DEBUG(1, ("Setup script didn't create %s\n", configfile)); return NT_STATUS_UNSUCCESSFUL; } configparam = talloc_asprintf(mem_ctx, "--configfile=%s", configfile); talloc_free(configfile); if ((pid = fork()) == 0) { execl(smbd_path, smbd_path, "-i", "--model=single", configparam, NULL); exit(1); } else if (pid == -1) { DEBUG(0, ("Unable to fork()\n")); return NT_STATUS_UNSUCCESSFUL; } *smbd_pid = pid; return NT_STATUS_OK; }
NTSTATUS file_new(connection_struct *conn, files_struct **result) { int i; static int first_file; files_struct *fsp; /* we want to give out file handles differently on each new connection because of a common bug in MS clients where they try to reuse a file descriptor from an earlier smb connection. This code increases the chance that the errant client will get an error rather than causing corruption */ if (first_file == 0) { first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files; } /* TODO: Port the id-tree implementation from Samba4 */ i = bitmap_find(file_bmap, first_file); if (i == -1) { DEBUG(0,("ERROR! Out of file structures\n")); /* TODO: We have to unconditionally return a DOS error here, * W2k3 even returns ERRDOS/ERRnofids for ntcreate&x with * NTSTATUS negotiated */ return NT_STATUS_TOO_MANY_OPENED_FILES; } fsp = SMB_MALLOC_P(files_struct); if (!fsp) { return NT_STATUS_NO_MEMORY; } ZERO_STRUCTP(fsp); fsp->fh = SMB_MALLOC_P(struct fd_handle); if (!fsp->fh) { SAFE_FREE(fsp); return NT_STATUS_NO_MEMORY; } ZERO_STRUCTP(fsp->fh); fsp->fh->ref_count = 1; fsp->fh->fd = -1; fsp->conn = conn; fsp->fh->file_id = get_gen_count(); GetTimeOfDay(&fsp->open_time); first_file = (i+1) % real_max_open_files; bitmap_set(file_bmap, i); files_used++; fsp->fnum = i + FILE_HANDLE_OFFSET; SMB_ASSERT(fsp->fnum < 65536); string_set(&fsp->fsp_name,""); DLIST_ADD(Files, fsp); DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n", i, fsp->fnum, files_used)); chain_fsp = fsp; /* A new fsp invalidates the positive and negative fsp_fi_cache as the new fsp is pushed at the start of the list and we search from a cache hit to the *end* of the list. */ ZERO_STRUCT(fsp_fi_cache); *result = fsp; return NT_STATUS_OK; }
NTSTATUS cli_do_rpc_ndr(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int p_idx, int opnum, void *data, ndr_pull_flags_fn_t pull_fn, ndr_push_flags_fn_t push_fn) { prs_struct q_ps, r_ps; struct ndr_pull *pull; DATA_BLOB blob; struct ndr_push *push; NTSTATUS status; SMB_ASSERT(cli->pipe_idx == p_idx); push = ndr_push_init_ctx(mem_ctx); if (!push) { return NT_STATUS_NO_MEMORY; } status = push_fn(push, NDR_IN, data); if (!NT_STATUS_IS_OK(status)) { return status; } blob = ndr_push_blob(push); if (!prs_init_data_blob(&q_ps, &blob, mem_ctx)) { return NT_STATUS_NO_MEMORY; } talloc_free(push); if (!prs_init( &r_ps, 0, mem_ctx, UNMARSHALL )) { prs_mem_free( &q_ps ); return NT_STATUS_NO_MEMORY; } status = rpc_api_pipe_req(cli, opnum, &q_ps, &r_ps); prs_mem_free( &q_ps ); if (!NT_STATUS_IS_OK(status)) { prs_mem_free( &r_ps ); return status; } if (!prs_data_blob(&r_ps, &blob, mem_ctx)) { prs_mem_free( &r_ps ); return NT_STATUS_NO_MEMORY; } prs_mem_free( &r_ps ); pull = ndr_pull_init_blob(&blob, mem_ctx); if (pull == NULL) { return NT_STATUS_NO_MEMORY; } /* have the ndr parser alloc memory for us */ pull->flags |= LIBNDR_FLAG_REF_ALLOC; status = pull_fn(pull, NDR_OUT, data); talloc_free(pull); if (!NT_STATUS_IS_OK(status)) { return status; } return NT_STATUS_OK; }
ELOG_TDB *elog_open_tdb( const char *logname, bool force_clear, bool read_only ) { TDB_CONTEXT *tdb = NULL; uint32_t vers_id; ELOG_TDB *ptr; char *tdbpath = NULL; ELOG_TDB *tdb_node = NULL; char *eventlogdir; TALLOC_CTX *ctx = talloc_tos(); /* check for invalid options */ if (force_clear && read_only) { DEBUG(1,("elog_open_tdb: Invalid flags\n")); return NULL; } /* first see if we have an open context */ for ( ptr=open_elog_list; ptr; ptr=ptr->next ) { if ( strequal( ptr->name, logname ) ) { ptr->ref_count++; /* trick to alow clearing of the eventlog tdb. The force_clear flag should imply that someone has done a force close. So make sure the tdb is NULL. If this is a normal open, then just return the existing reference */ if ( force_clear ) { SMB_ASSERT( ptr->tdb == NULL ); break; } else return ptr; } } /* make sure that the eventlog dir exists */ eventlogdir = state_path( "eventlog" ); if ( !directory_exist( eventlogdir ) ) mkdir( eventlogdir, 0755 ); /* get the path on disk */ tdbpath = elog_tdbname(ctx, logname); if (!tdbpath) { return NULL; } DEBUG(7,("elog_open_tdb: Opening %s...(force_clear == %s)\n", tdbpath, force_clear?"True":"False" )); /* the tdb wasn't already open or this is a forced clear open */ if ( !force_clear ) { tdb = tdb_open_log( tdbpath, 0, TDB_DEFAULT, read_only ? O_RDONLY : O_RDWR , 0 ); if ( tdb ) { vers_id = tdb_fetch_int32( tdb, EVT_VERSION ); if ( vers_id != EVENTLOG_DATABASE_VERSION_V1 ) { DEBUG(1,("elog_open_tdb: Invalid version [%d] on file [%s].\n", vers_id, tdbpath)); tdb_close( tdb ); tdb = elog_init_tdb( tdbpath ); } } } if ( !tdb ) tdb = elog_init_tdb( tdbpath ); /* if we got a valid context, then add it to the list */ if ( tdb ) { /* on a forced clear, just reset the tdb context if we already have an open entry in the list */ if ( ptr ) { ptr->tdb = tdb; return ptr; } if ( !(tdb_node = TALLOC_ZERO_P( NULL, ELOG_TDB)) ) { DEBUG(0,("elog_open_tdb: talloc() failure!\n")); tdb_close( tdb ); return NULL; } tdb_node->name = talloc_strdup( tdb_node, logname ); tdb_node->tdb = tdb; tdb_node->ref_count = 1; DLIST_ADD( open_elog_list, tdb_node ); } return tdb_node; }
static bool smbd_scavenger_start(struct smbd_scavenger_state *state) { struct server_id self = messaging_server_id(state->msg); struct tevent_fd *fde = NULL; int fds[2]; int ret; uint64_t unique_id; bool ok; SMB_ASSERT(server_id_equal(&state->parent_id, &self)); if (smbd_scavenger_running(state)) { struct server_id_buf tmp; DEBUG(10, ("scavenger %s already running\n", server_id_str_buf(*state->scavenger_id, &tmp))); return true; } if (state->scavenger_id != NULL) { struct server_id_buf tmp; DEBUG(10, ("scavenger zombie %s, cleaning up\n", server_id_str_buf(*state->scavenger_id, &tmp))); TALLOC_FREE(state->scavenger_id); } state->scavenger_id = talloc_zero(state, struct server_id); if (state->scavenger_id == NULL) { DEBUG(2, ("Out of memory\n")); goto fail; } talloc_set_destructor(state->scavenger_id, smbd_scavenger_server_id_destructor); ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds); if (ret == -1) { DEBUG(2, ("socketpair failed: %s", strerror(errno))); goto fail; } smb_set_close_on_exec(fds[0]); smb_set_close_on_exec(fds[1]); unique_id = serverid_get_random_unique_id(); ret = fork(); if (ret == -1) { int err = errno; close(fds[0]); close(fds[1]); DEBUG(0, ("fork failed: %s", strerror(err))); goto fail; } if (ret == 0) { /* child */ NTSTATUS status; close(fds[0]); set_my_unique_id(unique_id); status = smbd_reinit_after_fork(state->msg, state->ev, true); if (!NT_STATUS_IS_OK(status)) { DEBUG(2, ("reinit_after_fork failed: %s\n", nt_errstr(status))); exit_server("reinit_after_fork failed"); return false; } prctl_set_comment("smbd-scavenger"); state->am_scavenger = true; *state->scavenger_id = messaging_server_id(state->msg); scavenger_setup_sig_term_handler(state->ev); serverid_register(*state->scavenger_id, FLAG_MSG_GENERAL); ok = scavenger_say_hello(fds[1], *state->scavenger_id); if (!ok) { DEBUG(2, ("scavenger_say_hello failed\n")); exit_server("scavenger_say_hello failed"); return false; } fde = tevent_add_fd(state->ev, state->scavenger_id, fds[1], TEVENT_FD_READ, smbd_scavenger_parent_dead, state); if (fde == NULL) { DEBUG(2, ("tevent_add_fd(smbd_scavenger_parent_dead) " "failed\n")); exit_server("tevent_add_fd(smbd_scavenger_parent_dead) " "failed"); return false; } tevent_fd_set_auto_close(fde); ret = smbd_scavenger_main(state); DEBUG(10, ("scavenger ended: %d\n", ret)); exit_server_cleanly("scavenger ended"); return false; } /* parent */ close(fds[1]); ok = scavenger_wait_hello(fds[0], state->scavenger_id); if (!ok) { close(fds[0]); goto fail; } fde = tevent_add_fd(state->ev, state->scavenger_id, fds[0], TEVENT_FD_READ, smbd_scavenger_done, state); if (fde == NULL) { close(fds[0]); goto fail; } tevent_fd_set_auto_close(fde); return true; fail: TALLOC_FREE(state->scavenger_id); return false; }
NTSTATUS unix_convert(TALLOC_CTX *ctx, connection_struct *conn, const char *orig_path, struct smb_filename **smb_fname_out, uint32_t ucf_flags) { struct smb_filename *smb_fname = NULL; char *start, *end; char *dirpath = NULL; char *stream = NULL; bool component_was_mangled = False; bool name_has_wildcard = False; bool posix_pathnames = false; bool allow_wcard_last_component = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP); bool save_last_component = ucf_flags & UCF_SAVE_LCOMP; NTSTATUS status; int ret = -1; *smb_fname_out = NULL; smb_fname = talloc_zero(ctx, struct smb_filename); if (smb_fname == NULL) { return NT_STATUS_NO_MEMORY; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) { status = NT_STATUS_NO_MEMORY; goto err; } goto done; } DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path)); /* * Conversion to basic unix format is already done in * check_path_syntax(). */ /* * Names must be relative to the root of the service - any leading /. * and trailing /'s should have been trimmed by check_path_syntax(). */ #ifdef DEVELOPER SMB_ASSERT(*orig_path != '/'); #endif /* * If we trimmed down to a single '\0' character * then we should use the "." directory to avoid * searching the cache, but not if we are in a * printing share. * As we know this is valid we can return true here. */ if (!*orig_path) { if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) { status = NT_STATUS_NO_MEMORY; goto err; } if (SMB_VFS_STAT(conn, smb_fname) != 0) { status = map_nt_error_from_unix(errno); goto err; } DEBUG(5, ("conversion finished \"\" -> %s\n", smb_fname->base_name)); goto done; } if (orig_path[0] == '.' && (orig_path[1] == '/' || orig_path[1] == '\0')) { /* Start of pathname can't be "." only. */ if (orig_path[1] == '\0' || orig_path[2] == '\0') { status = NT_STATUS_OBJECT_NAME_INVALID; } else { status =determine_path_error(&orig_path[2], allow_wcard_last_component); } goto err; } /* Start with the full orig_path as given by the caller. */ if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) { DEBUG(0, ("talloc_strdup failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } /* * Large directory fix normalization. If we're case sensitive, and * the case preserving parameters are set to "no", normalize the case of * the incoming filename from the client WHETHER IT EXISTS OR NOT ! * This is in conflict with the current (3.0.20) man page, but is * what people expect from the "large directory howto". I'll update * the man page. Thanks to [email protected] for finding this. JRA. */ if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) { if (!strnorm(smb_fname->base_name, lp_defaultcase(SNUM(conn)))) { DEBUG(0, ("strnorm %s failed\n", smb_fname->base_name)); status = NT_STATUS_INVALID_PARAMETER; goto err; } } /* * Ensure saved_last_component is valid even if file exists. */ if(save_last_component) { end = strrchr_m(smb_fname->base_name, '/'); if (end) { smb_fname->original_lcomp = talloc_strdup(smb_fname, end + 1); } else { smb_fname->original_lcomp = talloc_strdup(smb_fname, smb_fname->base_name); } if (smb_fname->original_lcomp == NULL) { status = NT_STATUS_NO_MEMORY; goto err; } } posix_pathnames = (lp_posix_pathnames() || (ucf_flags & UCF_POSIX_PATHNAMES)); /* * Strip off the stream, and add it back when we're done with the * base_name. */ if (!posix_pathnames) { stream = strchr_m(smb_fname->base_name, ':'); if (stream != NULL) { char *tmp = talloc_strdup(smb_fname, stream); if (tmp == NULL) { status = NT_STATUS_NO_MEMORY; goto err; } /* * Since this is actually pointing into * smb_fname->base_name this truncates base_name. */ *stream = '\0'; stream = tmp; } } start = smb_fname->base_name; /* * If we're providing case insensitive semantics or * the underlying filesystem is case insensitive, * then a case-normalized hit in the stat-cache is * authoratitive. JRA. * * Note: We're only checking base_name. The stream_name will be * added and verified in build_stream_path(). */ if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && stat_cache_lookup(conn, posix_pathnames, &smb_fname->base_name, &dirpath, &start, &smb_fname->st)) { goto done; } /* * Make sure "dirpath" is an allocated string, we use this for * building the directories with talloc_asprintf and free it. */ if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) { DEBUG(0, ("talloc_strdup failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } /* * If we have a wildcard we must walk the path to * find where the error is, even if case sensitive * is true. */ name_has_wildcard = ms_has_wild(smb_fname->base_name); if (name_has_wildcard && !allow_wcard_last_component) { /* Wildcard not valid anywhere. */ status = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", smb_fname->base_name, dirpath, start)); if (!name_has_wildcard) { /* * stat the name - if it exists then we can add the stream back (if * there was one) and be done! */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, smb_fname); } else { ret = SMB_VFS_STAT(conn, smb_fname); } if (ret == 0) { status = check_for_dot_component(smb_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } /* Add the path (not including the stream) to the cache. */ stat_cache_add(orig_path, smb_fname->base_name, conn->case_sensitive); DEBUG(5,("conversion of base_name finished %s -> %s\n", orig_path, smb_fname->base_name)); goto done; } /* Stat failed - ensure we don't use it. */ SET_STAT_INVALID(smb_fname->st); if (errno == ENOENT) { /* Optimization when creating a new file - only the last component doesn't exist. NOTE : check_parent_exists() doesn't preserve errno. */ int saved_errno = errno; status = check_parent_exists(ctx, conn, posix_pathnames, smb_fname, &dirpath, &start); errno = saved_errno; if (!NT_STATUS_IS_OK(status)) { goto fail; } } /* * A special case - if we don't have any wildcards or mangling chars and are case * sensitive or the underlying filesystem is case insensitive then searching * won't help. */ if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && !mangle_is_mangled(smb_fname->base_name, conn->params)) { status = check_for_dot_component(smb_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } /* * The stat failed. Could be ok as it could be * a new file. */ if (errno == ENOTDIR || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } else if (errno == ENOENT) { /* * Was it a missing last component ? * or a missing intermediate component ? */ struct smb_filename parent_fname; const char *last_component = NULL; ZERO_STRUCT(parent_fname); if (!parent_dirname(ctx, smb_fname->base_name, &parent_fname.base_name, &last_component)) { status = NT_STATUS_NO_MEMORY; goto fail; } if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, &parent_fname); } else { ret = SMB_VFS_STAT(conn, &parent_fname); } if (ret == -1) { if (errno == ENOTDIR || errno == ENOENT || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } } /* * Missing last component is ok - new file. * Also deal with permission denied elsewhere. * Just drop out to done. */ goto done; } } } else { /* * We have a wildcard in the pathname. * * Optimization for common case where the wildcard * is in the last component and the client already * sent the correct case. * NOTE : check_parent_exists() doesn't preserve errno. */ int saved_errno = errno; status = check_parent_exists(ctx, conn, posix_pathnames, smb_fname, &dirpath, &start); errno = saved_errno; if (!NT_STATUS_IS_OK(status)) { goto fail; } } /* * is_mangled() was changed to look at an entire pathname, not * just a component. JRA. */ if (mangle_is_mangled(start, conn->params)) { component_was_mangled = True; } /* * Now we need to recursively match the name against the real * directory structure. */ /* * Match each part of the path name separately, trying the names * as is first, then trying to scan the directory for matching names. */ for (; start ; start = (end?end+1:(char *)NULL)) { /* * Pinpoint the end of this section of the filename. */ /* mb safe. '/' can't be in any encoded char. */ end = strchr(start, '/'); /* * Chop the name at this point. */ if (end) { *end = 0; } if (save_last_component) { TALLOC_FREE(smb_fname->original_lcomp); smb_fname->original_lcomp = talloc_strdup(smb_fname, end ? end + 1 : start); if (!smb_fname->original_lcomp) { DEBUG(0, ("talloc failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } } /* The name cannot have a component of "." */ if (ISDOT(start)) { if (!end) { /* Error code at the end of a pathname. */ status = NT_STATUS_OBJECT_NAME_INVALID; } else { status = determine_path_error(end+1, allow_wcard_last_component); } goto fail; } /* The name cannot have a wildcard if it's not the last component. */ name_has_wildcard = ms_has_wild(start); /* Wildcards never valid within a pathname. */ if (name_has_wildcard && end) { status = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } /* Skip the stat call if it's a wildcard end. */ if (name_has_wildcard) { DEBUG(5,("Wildcard %s\n",start)); goto done; } /* * Check if the name exists up to this point. */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, smb_fname); } else { ret = SMB_VFS_STAT(conn, smb_fname); } if (ret == 0) { /* * It exists. it must either be a directory or this must * be the last part of the path for it to be OK. */ if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) { /* * An intermediate part of the name isn't * a directory. */ DEBUG(5,("Not a dir %s\n",start)); *end = '/'; /* * We need to return the fact that the * intermediate name resolution failed. This * is used to return an error of ERRbadpath * rather than ERRbadfile. Some Windows * applications depend on the difference between * these two errors. */ status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } } else { char *found_name = NULL; /* Stat failed - ensure we don't use it. */ SET_STAT_INVALID(smb_fname->st); /* * Reset errno so we can detect * directory open errors. */ errno = 0; /* * Try to find this part of the path in the directory. */ if (name_has_wildcard || (get_real_filename(conn, dirpath, start, talloc_tos(), &found_name) == -1)) { char *unmangled; if (end) { /* * An intermediate part of the name * can't be found. */ DEBUG(5,("Intermediate not found %s\n", start)); *end = '/'; /* * We need to return the fact that the * intermediate name resolution failed. * This is used to return an error of * ERRbadpath rather than ERRbadfile. * Some Windows applications depend on * the difference between these two * errors. */ /* * ENOENT, ENOTDIR and ELOOP all map * to NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { status = map_nt_error_from_unix(errno); } goto fail; } /* * ENOENT/EACCESS are the only valid errors * here. */ if (errno == EACCES) { if (ucf_flags & UCF_CREATING_FILE) { /* * This is the dropbox * behaviour. A dropbox is a * directory with only -wx * permissions, so * get_real_filename fails * with EACCESS, it needs to * list the directory. We * nevertheless want to allow * users creating a file. */ status = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { status = NT_STATUS_ACCESS_DENIED; } goto fail; } if ((errno != 0) && (errno != ENOENT)) { /* * ENOTDIR and ELOOP both map to * NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOTDIR || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { status = map_nt_error_from_unix(errno); } goto fail; } /* * Just the last part of the name doesn't exist. * We need to strupper() or strlower() it as * this conversion may be used for file creation * purposes. Fix inspired by * Thomas Neumann <*****@*****.**>. */ if (!conn->case_preserve || (mangle_is_8_3(start, False, conn->params) && !conn->short_case_preserve)) { if (!strnorm(start, lp_defaultcase(SNUM(conn)))) { DEBUG(0, ("strnorm %s failed\n", start)); status = NT_STATUS_INVALID_PARAMETER; goto err; } } /* * check on the mangled stack to see if we can * recover the base of the filename. */ if (mangle_is_mangled(start, conn->params) && mangle_lookup_name_from_8_3(ctx, start, &unmangled, conn->params)) { char *tmp; size_t start_ofs = start - smb_fname->base_name; if (*dirpath != '\0') { tmp = talloc_asprintf( smb_fname, "%s/%s", dirpath, unmangled); TALLOC_FREE(unmangled); } else { tmp = unmangled; } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; start = smb_fname->base_name + start_ofs; end = start + strlen(start); } DEBUG(5,("New file %s\n",start)); goto done; } /* * Restore the rest of the string. If the string was * mangled the size may have changed. */ if (end) { char *tmp; size_t start_ofs = start - smb_fname->base_name; if (*dirpath != '\0') { tmp = talloc_asprintf(smb_fname, "%s/%s/%s", dirpath, found_name, end+1); } else { tmp = talloc_asprintf(smb_fname, "%s/%s", found_name, end+1); } if (tmp == NULL) { DEBUG(0, ("talloc_asprintf failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; start = smb_fname->base_name + start_ofs; end = start + strlen(found_name); *end = '\0'; } else { char *tmp; size_t start_ofs = start - smb_fname->base_name; if (*dirpath != '\0') { tmp = talloc_asprintf(smb_fname, "%s/%s", dirpath, found_name); } else { tmp = talloc_strdup(smb_fname, found_name); } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; start = smb_fname->base_name + start_ofs; /* * We just scanned for, and found the end of * the path. We must return a valid stat struct * if it exists. JRA. */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, smb_fname); } else { ret = SMB_VFS_STAT(conn, smb_fname); } if (ret != 0) { SET_STAT_INVALID(smb_fname->st); } } TALLOC_FREE(found_name); } /* end else */ #ifdef DEVELOPER /* * This sucks! * We should never provide different behaviors * depending on DEVELOPER!!! */ if (VALID_STAT(smb_fname->st)) { bool delete_pending; uint32_t name_hash; status = file_name_hash(conn, smb_fname_str_dbg(smb_fname), &name_hash); if (!NT_STATUS_IS_OK(status)) { goto fail; } get_file_infos(vfs_file_id_from_sbuf(conn, &smb_fname->st), name_hash, &delete_pending, NULL); if (delete_pending) { status = NT_STATUS_DELETE_PENDING; goto fail; } } #endif /* * Add to the dirpath that we have resolved so far. */ if (*dirpath != '\0') { char *tmp = talloc_asprintf(ctx, "%s/%s", dirpath, start); if (!tmp) { DEBUG(0, ("talloc_asprintf failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(dirpath); dirpath = tmp; } else { TALLOC_FREE(dirpath); if (!(dirpath = talloc_strdup(ctx,start))) { DEBUG(0, ("talloc_strdup failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } } /* * Cache the dirpath thus far. Don't cache a name with mangled * or wildcard components as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, dirpath, conn->case_sensitive); } /* * Restore the / that we wiped out earlier. */ if (end) { *end = '/'; } } /* * Cache the full path. Don't cache a name with mangled or wildcard * components as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, smb_fname->base_name, conn->case_sensitive); } /* * The name has been resolved. */ DEBUG(5,("conversion finished %s -> %s\n", orig_path, smb_fname->base_name)); done: /* Add back the stream if one was stripped off originally. */ if (stream != NULL) { smb_fname->stream_name = stream; /* Check path now that the base_name has been converted. */ status = build_stream_path(ctx, conn, orig_path, smb_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } } TALLOC_FREE(dirpath); *smb_fname_out = smb_fname; return NT_STATUS_OK; fail: DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); if (*dirpath != '\0') { smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s", dirpath, start); } else { smb_fname->base_name = talloc_strdup(smb_fname, start); } if (!smb_fname->base_name) { DEBUG(0, ("talloc_asprintf failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } *smb_fname_out = smb_fname; TALLOC_FREE(dirpath); return status; err: TALLOC_FREE(smb_fname); return status; }
static bool change_to_user_internal(connection_struct *conn, const struct auth_session_info *session_info, uint64_t vuid) { int snum; gid_t gid; uid_t uid; char group_c; int num_groups = 0; gid_t *group_list = NULL; bool ok; snum = SNUM(conn); ok = check_user_ok(conn, vuid, session_info, snum); if (!ok) { DEBUG(2,("SMB user %s (unix user %s) " "not permitted access to share %s.\n", session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, lp_servicename(talloc_tos(), snum))); return false; } uid = conn->session_info->unix_token->uid; gid = conn->session_info->unix_token->gid; num_groups = conn->session_info->unix_token->ngroups; group_list = conn->session_info->unix_token->groups; /* * See if we should force group for this service. If so this overrides * any group set in the force user code. */ if((group_c = *lp_force_group(talloc_tos(), snum))) { SMB_ASSERT(conn->force_group_gid != (gid_t)-1); if (group_c == '+') { int i; /* * Only force group if the user is a member of the * service group. Check the group memberships for this * user (we already have this) to see if we should force * the group. */ for (i = 0; i < num_groups; i++) { if (group_list[i] == conn->force_group_gid) { conn->session_info->unix_token->gid = conn->force_group_gid; gid = conn->force_group_gid; gid_to_sid(&conn->session_info->security_token ->sids[1], gid); break; } } } else { conn->session_info->unix_token->gid = conn->force_group_gid; gid = conn->force_group_gid; gid_to_sid(&conn->session_info->security_token->sids[1], gid); } } /*Set current_user since we will immediately also call set_sec_ctx() */ current_user.ut.ngroups = num_groups; current_user.ut.groups = group_list; set_sec_ctx(uid, gid, current_user.ut.ngroups, current_user.ut.groups, conn->session_info->security_token); current_user.conn = conn; current_user.vuid = vuid; DEBUG(5, ("Impersonated user: uid=(%d,%d), gid=(%d,%d)\n", (int)getuid(), (int)geteuid(), (int)getgid(), (int)getegid())); return true; }
bool recursive_rmdir(TALLOC_CTX *ctx, connection_struct *conn, struct smb_filename *smb_dname) { const char *dname = NULL; char *talloced = NULL; bool ret = True; long offset = 0; SMB_STRUCT_STAT st; struct smb_Dir *dir_hnd; SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname)); dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0); if(dir_hnd == NULL) return False; while((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) { struct smb_filename *smb_dname_full = NULL; char *fullname = NULL; bool do_break = true; if (ISDOT(dname) || ISDOTDOT(dname)) { TALLOC_FREE(talloced); continue; } if (!is_visible_file(conn, smb_dname->base_name, dname, &st, false)) { TALLOC_FREE(talloced); continue; } /* Construct the full name. */ fullname = talloc_asprintf(ctx, "%s/%s", smb_dname->base_name, dname); if (!fullname) { errno = ENOMEM; goto err_break; } smb_dname_full = synthetic_smb_fname(talloc_tos(), fullname, NULL, NULL); if (smb_dname_full == NULL) { errno = ENOMEM; goto err_break; } if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) { goto err_break; } if(smb_dname_full->st.st_ex_mode & S_IFDIR) { if(!recursive_rmdir(ctx, conn, smb_dname_full)) { goto err_break; } if(SMB_VFS_RMDIR(conn, smb_dname_full->base_name) != 0) { goto err_break; } } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) { goto err_break; } /* Successful iteration. */ do_break = false; err_break: TALLOC_FREE(smb_dname_full); TALLOC_FREE(fullname); TALLOC_FREE(talloced); if (do_break) { ret = false; break; } } TALLOC_FREE(dir_hnd); return ret; }
const uint8 *pdb_get_nt_passwd(const struct samu *sampass) { SMB_ASSERT((!sampass->nt_pw.data) || sampass->nt_pw.length == NT_HASH_LEN); return (uint8 *)sampass->nt_pw.data; }
static WERROR cmd_witness_GetInterfaceList(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { NTSTATUS status; WERROR result; TALLOC_CTX *frame = talloc_stackframe(); struct witness_interfaceList *interface_list = NULL; uint32_t num_interfaces, n; struct witness_interfaceInfo *interfaces; use_only_one_rpc_pipe_hack(cli); status = dcerpc_witness_GetInterfaceList(cli->binding_handle, frame, &interface_list, &result); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, status: %s\n", nt_errstr(status))); result = ntstatus_to_werror(status); goto done; } if (!W_ERROR_IS_OK(result)) { DEBUG(0, ("dcerpc_witness_GetInterfaceList failed, error: %s\n", win_errstr(result))); goto done; } SMB_ASSERT(interface_list); interfaces = interface_list->interfaces; num_interfaces = interface_list->num_interfaces; for (n=0; n < num_interfaces; n++) { char wif = (interfaces[n].flags & WITNESS_INFO_WITNESS_IF) ? '*' : ' '; char state = 'X'; if (interfaces[n].state == WITNESS_STATE_AVAILABLE) { state = '+'; } else if (interfaces[n].state == WITNESS_STATE_UNAVAILABLE) { state = '-'; } else if (interfaces[n].state == WITNESS_STATE_UNKNOWN) { state = '?'; } d_printf("%c%c %s", wif, state, interfaces[n].group_name); if (interfaces[n].flags & WITNESS_INFO_IPv4_VALID) { d_printf(" %s", interfaces[n].ipv4); } if (interfaces[n].flags & WITNESS_INFO_IPv6_VALID) { d_printf(" %s", interfaces[n].ipv6); } switch (interfaces[n].version) { case WITNESS_V1: d_printf(" V1"); break; case WITNESS_V2: d_printf(" V2"); break; default: d_printf(" Unsuported Version (0x%08x)", interfaces[n].version); } d_printf("\n"); } done: talloc_free(frame); return result; }
const uint8 *pdb_get_lanman_passwd(const struct samu *sampass) { SMB_ASSERT((!sampass->lm_pw.data) || sampass->lm_pw.length == LM_HASH_LEN); return (uint8 *)sampass->lm_pw.data; }
/** * @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; }
NTSTATUS cli_do_rpc_ndr(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const struct ndr_interface_table *table, uint32 opnum, void *r) { #ifdef AVM_SMALL return NT_STATUS_NO_MEMORY; #else prs_struct q_ps, r_ps; const struct ndr_interface_call *call; struct ndr_pull *pull; DATA_BLOB blob; struct ndr_push *push; NTSTATUS status; enum ndr_err_code ndr_err; SMB_ASSERT(ndr_syntax_id_equal(&table->syntax_id, &cli->abstract_syntax)); SMB_ASSERT(table->num_calls > opnum); call = &table->calls[opnum]; push = ndr_push_init_ctx(mem_ctx); if (!push) { return NT_STATUS_NO_MEMORY; } ndr_err = call->ndr_push(push, NDR_IN, r); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return ndr_map_error2ntstatus(ndr_err); } blob = ndr_push_blob(push); if (!prs_init_data_blob(&q_ps, &blob, mem_ctx)) { return NT_STATUS_NO_MEMORY; } talloc_free(push); prs_init_empty( &r_ps, mem_ctx, UNMARSHALL ); status = rpc_api_pipe_req(cli, opnum, &q_ps, &r_ps); prs_mem_free( &q_ps ); if (!NT_STATUS_IS_OK(status)) { prs_mem_free( &r_ps ); return status; } if (!prs_data_blob(&r_ps, &blob, mem_ctx)) { prs_mem_free( &r_ps ); return NT_STATUS_NO_MEMORY; } prs_mem_free( &r_ps ); pull = ndr_pull_init_blob(&blob, mem_ctx); if (pull == NULL) { return NT_STATUS_NO_MEMORY; } /* have the ndr parser alloc memory for us */ pull->flags |= LIBNDR_FLAG_REF_ALLOC; ndr_err = call->ndr_pull(pull, NDR_OUT, r); talloc_free(pull); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return ndr_map_error2ntstatus(ndr_err); } return NT_STATUS_OK; #endif }
const char *cli_errstr(struct cli_state *cli) { fstring cli_error_message; uint32 flgs2 = SVAL(cli->inbuf,smb_flg2), errnum; uint8 errclass; int i; char *result; if (!cli->initialised) { fstrcpy(cli_error_message, "[Programmer's error] cli_errstr called on unitialized cli_stat struct!\n"); goto done; } /* Was it server socket error ? */ if (cli->fd == -1 && cli->smb_rw_error) { switch(cli->smb_rw_error) { case SMB_READ_TIMEOUT: slprintf(cli_error_message, sizeof(cli_error_message) - 1, "Call timed out: server did not respond after %d milliseconds", cli->timeout); break; case SMB_READ_EOF: slprintf(cli_error_message, sizeof(cli_error_message) - 1, "Call returned zero bytes (EOF)" ); break; case SMB_READ_ERROR: slprintf(cli_error_message, sizeof(cli_error_message) - 1, "Read error: %s", strerror(errno) ); break; case SMB_WRITE_ERROR: slprintf(cli_error_message, sizeof(cli_error_message) - 1, "Write error: %s", strerror(errno) ); break; case SMB_READ_BAD_SIG: slprintf(cli_error_message, sizeof(cli_error_message) - 1, "Server packet had invalid SMB signature!"); break; case SMB_NO_MEMORY: slprintf(cli_error_message, sizeof(cli_error_message) - 1, "Out of memory"); break; default: slprintf(cli_error_message, sizeof(cli_error_message) - 1, "Unknown error code %d\n", cli->smb_rw_error ); break; } goto done; } /* Case #1: RAP error */ if (cli->rap_error) { for (i = 0; rap_errmap[i].message != NULL; i++) { if (rap_errmap[i].err == cli->rap_error) { return rap_errmap[i].message; } } slprintf(cli_error_message, sizeof(cli_error_message) - 1, "RAP code %d", cli->rap_error); goto done; } /* Case #2: 32-bit NT errors */ if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) { NTSTATUS status = NT_STATUS(IVAL(cli->inbuf,smb_rcls)); return nt_errstr(status); } cli_dos_error(cli, &errclass, &errnum); /* Case #3: SMB error */ return cli_smb_errstr(cli); done: result = talloc_strdup(talloc_tos(), cli_error_message); SMB_ASSERT(result); return result; }
static NTSTATUS ipv4_connect(struct socket_context *sock, const struct socket_address *my_address, const struct socket_address *srv_address, uint32_t flags) { struct sockaddr_in srv_addr; struct in_addr my_ip; struct in_addr srv_ip; int ret; if (my_address && my_address->sockaddr) { ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen); if (ret == -1) { return map_nt_error_from_unix(errno); } } else if (my_address) { my_ip = interpret_addr2(my_address->addr); if (my_ip.s_addr != 0 || my_address->port != 0) { struct sockaddr_in my_addr; ZERO_STRUCT(my_addr); #ifdef HAVE_SOCK_SIN_LEN my_addr.sin_len = sizeof(my_addr); #endif my_addr.sin_addr.s_addr = my_ip.s_addr; my_addr.sin_port = htons(my_address->port); my_addr.sin_family = PF_INET; ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr)); if (ret == -1) { return map_nt_error_from_unix(errno); } } } if (srv_address->sockaddr) { ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen); if (ret == -1) { return map_nt_error_from_unix(errno); } } else { srv_ip = interpret_addr2(srv_address->addr); if (!srv_ip.s_addr) { return NT_STATUS_BAD_NETWORK_NAME; } SMB_ASSERT(srv_address->port != 0); ZERO_STRUCT(srv_addr); #ifdef HAVE_SOCK_SIN_LEN srv_addr.sin_len = sizeof(srv_addr); #endif srv_addr.sin_addr.s_addr= srv_ip.s_addr; srv_addr.sin_port = htons(srv_address->port); srv_addr.sin_family = PF_INET; ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr)); if (ret == -1) { return map_nt_error_from_unix(errno); } } return ip_connect_complete(sock, flags); }
/* This function MUST only used to create the cached server_info for * guest. * * This is a lossy conversion. Variables known to be lost so far * include: * * - nss_token (not needed because the only read doesn't happen * for the GUEST user, as this routine populates ->security_token * * - extra (not needed because the guest account must have valid RIDs per the output of get_guest_info3()) * * - The 'server_info' parameter allows the missing 'info3' to be copied across. */ static struct auth_serversupplied_info *copy_session_info_serverinfo_guest(TALLOC_CTX *mem_ctx, const struct auth_session_info *src, struct auth_serversupplied_info *server_info) { struct auth_serversupplied_info *dst; dst = make_server_info(mem_ctx); if (dst == NULL) { return NULL; } /* This element must be provided to convert back to an auth_serversupplied_info */ SMB_ASSERT(src->unix_info); dst->guest = true; dst->system = false; /* This element must be provided to convert back to an * auth_serversupplied_info. This needs to be from the * auth_session_info because the group values in particular * may change during create_local_token() processing */ SMB_ASSERT(src->unix_token); dst->utok.uid = src->unix_token->uid; dst->utok.gid = src->unix_token->gid; dst->utok.ngroups = src->unix_token->ngroups; if (src->unix_token->ngroups != 0) { dst->utok.groups = (gid_t *)talloc_memdup( dst, src->unix_token->groups, sizeof(gid_t)*dst->utok.ngroups); } else { dst->utok.groups = NULL; } /* We must have a security_token as otherwise the lossy * conversion without nss_token would cause create_local_token * to take the wrong path */ SMB_ASSERT(src->security_token); dst->security_token = dup_nt_token(dst, src->security_token); if (!dst->security_token) { TALLOC_FREE(dst); return NULL; } dst->session_key = data_blob_talloc( dst, src->session_key.data, src->session_key.length); /* This is OK because this functions is only used for the * GUEST account, which has all-zero keys for both values */ dst->lm_session_key = data_blob_talloc(dst, src->session_key.data, src->session_key.length); dst->info3 = copy_netr_SamInfo3(dst, server_info->info3); if (!dst->info3) { TALLOC_FREE(dst); return NULL; } dst->unix_name = talloc_strdup(dst, src->unix_info->unix_name); if (!dst->unix_name) { TALLOC_FREE(dst); return NULL; } return dst; }
static void handle_main_input(struct regedit *regedit, int c) { switch (c) { case 18: { /* CTRL-R */ struct tree_node *root, *node; const char **path; node = tree_view_get_current_node(regedit->keys); path = tree_node_get_path(regedit, node); SMB_ASSERT(path != NULL); root = tree_node_new_root(regedit, regedit->registry_context); SMB_ASSERT(root != NULL); tree_view_set_root(regedit->keys, root); tree_view_set_path(regedit->keys, path); node = tree_view_get_current_node(regedit->keys); value_list_load(regedit->vl, node->key); tree_view_show(regedit->keys); value_list_show(regedit->vl); print_path(regedit, node); talloc_free(discard_const(path)); break; } case 'f': case 'F': case '/': { int rv; struct regedit_search_opts *opts; struct tree_node *node; opts = ®edit->active_search; rv = dialog_search_input(regedit, opts); if (rv == DIALOG_OK) { SMB_ASSERT(opts->query != NULL); opts->match = find_substring_nocase; node = regedit->keys->root->child_head; if (opts->search_case) { opts->match = find_substring; } if (!opts->search_recursive) { node = tree_view_get_current_node(regedit->keys); node = tree_node_first(node); } regedit_search(regedit, node, NULL, SEARCH_NEXT); } break; } case 'x': regedit_search_repeat(regedit, SEARCH_NEXT); break; case 'X': regedit_search_repeat(regedit, SEARCH_PREV); break; case '\t': regedit->tree_input = !regedit->tree_input; print_heading(regedit); break; default: if (regedit->tree_input) { handle_tree_input(regedit, c); } else { handle_value_input(regedit, c); } } }