bool reset_stat_cache( void ) { if (!lp_stat_cache()) return True; memcache_flush(smbd_memcache(), STAT_CACHE); return True; }
/* insert an entry into the prefix cache. The string might not be null terminated */ static void cache_insert(const char *prefix, int length, unsigned int hash) { char *str = SMB_STRNDUP(prefix, length); if (str == NULL) { return; } memcache_add(smbd_memcache(), MANGLE_HASH2_CACHE, data_blob_const(&hash, sizeof(hash)), data_blob_const(str, length+1)); SAFE_FREE(str); }
void stat_cache_delete(const char *name) { char *lname = talloc_strdup_upper(talloc_tos(), name); if (!lname) { return; } DEBUG(10,("stat_cache_delete: deleting name [%s] -> %s\n", lname, name )); memcache_delete(smbd_memcache(), STAT_CACHE, data_blob_const(lname, talloc_get_size(lname)-1)); TALLOC_FREE(lname); }
/* lookup an entry in the prefix cache. Return NULL if not found. */ static char *cache_lookup(TALLOC_CTX *mem_ctx, unsigned int hash) { DATA_BLOB value; if (!memcache_lookup(smbd_memcache(), MANGLE_HASH2_CACHE, data_blob_const(&hash, sizeof(hash)), &value)) { return NULL; } SMB_ASSERT((value.length > 0) && (value.data[value.length-1] == '\0')); return talloc_strdup(mem_ctx, (char *)value.data); }
int main(int argc,const char *argv[]) { /* shall I run as a daemon */ bool is_daemon = false; bool interactive = false; bool Fork = true; bool no_process_group = false; bool log_stdout = false; char *ports = NULL; char *profile_level = NULL; int opt; poptContext pc; bool print_build_options = False; enum { OPT_DAEMON = 1000, OPT_INTERACTIVE, OPT_FORK, OPT_NO_PROCESS_GROUP, OPT_LOG_STDOUT }; struct poptOption long_options[] = { POPT_AUTOHELP {"daemon", 'D', POPT_ARG_NONE, NULL, OPT_DAEMON, "Become a daemon (default)" }, {"interactive", 'i', POPT_ARG_NONE, NULL, OPT_INTERACTIVE, "Run interactive (not a daemon)"}, {"foreground", 'F', POPT_ARG_NONE, NULL, OPT_FORK, "Run daemon in foreground (for daemontools, etc.)" }, {"no-process-group", '\0', POPT_ARG_NONE, NULL, OPT_NO_PROCESS_GROUP, "Don't create a new process group" }, {"log-stdout", 'S', POPT_ARG_NONE, NULL, OPT_LOG_STDOUT, "Log to stdout" }, {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" }, {"port", 'p', POPT_ARG_STRING, &ports, 0, "Listen on the specified ports"}, {"profiling-level", 'P', POPT_ARG_STRING, &profile_level, 0, "Set profiling level","PROFILE_LEVEL"}, POPT_COMMON_SAMBA POPT_COMMON_DYNCONFIG POPT_TABLEEND }; struct smbd_parent_context *parent = NULL; TALLOC_CTX *frame; NTSTATUS status; uint64_t unique_id; struct tevent_context *ev_ctx; struct messaging_context *msg_ctx; /* * Do this before any other talloc operation */ talloc_enable_null_tracking(); frame = talloc_stackframe(); setup_logging(argv[0], DEBUG_DEFAULT_STDOUT); load_case_tables(); smbd_init_globals(); TimeInit(); #ifdef HAVE_SET_AUTH_PARAMETERS set_auth_parameters(argc,argv); #endif pc = poptGetContext("smbd", argc, argv, long_options, 0); while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case OPT_DAEMON: is_daemon = true; break; case OPT_INTERACTIVE: interactive = true; break; case OPT_FORK: Fork = false; break; case OPT_NO_PROCESS_GROUP: no_process_group = true; break; case OPT_LOG_STDOUT: log_stdout = true; break; case 'b': print_build_options = True; break; default: d_fprintf(stderr, "\nInvalid option %s: %s\n\n", poptBadOption(pc, 0), poptStrerror(opt)); poptPrintUsage(pc, stderr, 0); exit(1); } } poptFreeContext(pc); if (interactive) { Fork = False; log_stdout = True; } if (log_stdout) { setup_logging(argv[0], DEBUG_STDOUT); } else { setup_logging(argv[0], DEBUG_FILE); } if (print_build_options) { build_options(True); /* Display output to screen as well as debug */ exit(0); } #ifdef HAVE_SETLUID /* needed for SecureWare on SCO */ setluid(0); #endif set_remote_machine_name("smbd", False); if (interactive && (DEBUGLEVEL >= 9)) { talloc_enable_leak_report(); } if (log_stdout && Fork) { DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n")); exit(1); } /* we want to re-seed early to prevent time delays causing client problems at a later date. (tridge) */ generate_random_buffer(NULL, 0); /* get initial effective uid and gid */ sec_init(); /* make absolutely sure we run as root - to handle cases where people are crazy enough to have it setuid */ gain_root_privilege(); gain_root_group_privilege(); fault_setup(); dump_core_setup("smbd", lp_logfile()); /* we are never interested in SIGPIPE */ BlockSignals(True,SIGPIPE); #if defined(SIGFPE) /* we are never interested in SIGFPE */ BlockSignals(True,SIGFPE); #endif #if defined(SIGUSR2) /* We are no longer interested in USR2 */ BlockSignals(True,SIGUSR2); #endif /* POSIX demands that signals are inherited. If the invoking process has * these signals masked, we will have problems, as we won't recieve them. */ BlockSignals(False, SIGHUP); BlockSignals(False, SIGUSR1); BlockSignals(False, SIGTERM); /* Ensure we leave no zombies until we * correctly set up child handling below. */ CatchChild(); /* we want total control over the permissions on created files, so set our umask to 0 */ umask(0); reopen_logs(); DEBUG(0,("smbd version %s started.\n", samba_version_string())); DEBUGADD(0,("%s\n", COPYRIGHT_STARTUP_MESSAGE)); DEBUG(2,("uid=%d gid=%d euid=%d egid=%d\n", (int)getuid(),(int)getgid(),(int)geteuid(),(int)getegid())); /* Output the build options to the debug log */ build_options(False); if (sizeof(uint16) < 2 || sizeof(uint32) < 4) { DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); exit(1); } if (!lp_load_initial_only(get_dyn_CONFIGFILE())) { DEBUG(0, ("error opening config file '%s'\n", get_dyn_CONFIGFILE())); exit(1); } /* Init the security context and global current_user */ init_sec_ctx(); /* * Initialize the event context. The event context needs to be * initialized before the messaging context, cause the messaging * context holds an event context. * FIXME: This should be s3_tevent_context_init() */ ev_ctx = server_event_context(); if (ev_ctx == NULL) { exit(1); } /* * Init the messaging context * FIXME: This should only call messaging_init() */ msg_ctx = server_messaging_context(); if (msg_ctx == NULL) { exit(1); } /* * Reloading of the printers will not work here as we don't have a * server info and rpc services set up. It will be called later. */ if (!reload_services(NULL, -1, False)) { exit(1); } /* ...NOTE... Log files are working from this point! */ DEBUG(3,("loaded services\n")); init_structs(); #ifdef WITH_PROFILE if (!profile_setup(msg_ctx, False)) { DEBUG(0,("ERROR: failed to setup profiling\n")); return -1; } if (profile_level != NULL) { int pl = atoi(profile_level); struct server_id src; DEBUG(1, ("setting profiling level: %s\n",profile_level)); src.pid = getpid(); set_profile_level(pl, src); } #endif if (!is_daemon && !is_a_socket(0)) { if (!interactive) DEBUG(0,("standard input is not a socket, assuming -D option\n")); /* * Setting is_daemon here prevents us from eventually calling * the open_sockets_inetd() */ is_daemon = True; } if (is_daemon && !interactive) { DEBUG( 3, ( "Becoming a daemon.\n" ) ); become_daemon(Fork, no_process_group, log_stdout); } generate_random_buffer((uint8_t *)&unique_id, sizeof(unique_id)); set_my_unique_id(unique_id); #if HAVE_SETPGID /* * If we're interactive we want to set our own process group for * signal management. */ if (interactive && !no_process_group) setpgid( (pid_t)0, (pid_t)0); #endif if (!directory_exist(lp_lockdir())) mkdir(lp_lockdir(), 0755); if (is_daemon) pidfile_create("smbd"); status = reinit_after_fork(msg_ctx, ev_ctx, procid_self(), false); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("reinit_after_fork() failed\n")); exit(1); } smbd_server_conn->msg_ctx = msg_ctx; smbd_setup_sig_term_handler(); smbd_setup_sig_hup_handler(ev_ctx, msg_ctx); /* Setup all the TDB's - including CLEAR_IF_FIRST tdb's. */ if (smbd_memcache() == NULL) { exit(1); } memcache_set_global(smbd_memcache()); /* Initialise the password backed before the global_sam_sid to ensure that we fetch from ldap before we make a domain sid up */ if(!initialize_password_db(false, ev_ctx)) exit(1); if (!secrets_init()) { DEBUG(0, ("ERROR: smbd can not open secrets.tdb\n")); exit(1); } if (lp_server_role() == ROLE_DOMAIN_BDC || lp_server_role() == ROLE_DOMAIN_PDC) { struct loadparm_context *lp_ctx = loadparm_init_s3(NULL, loadparm_s3_context()); if (!open_schannel_session_store(NULL, lp_ctx)) { DEBUG(0,("ERROR: Samba cannot open schannel store for secured NETLOGON operations.\n")); exit(1); } TALLOC_FREE(lp_ctx); } if(!get_global_sam_sid()) { DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n")); exit(1); } if (!sessionid_init()) { exit(1); } if (!connections_init(True)) exit(1); if (!locking_init()) exit(1); if (!messaging_tdb_parent_init(ev_ctx)) { exit(1); } if (!notify_internal_parent_init(ev_ctx)) { exit(1); } if (!serverid_parent_init(ev_ctx)) { exit(1); } if (!W_ERROR_IS_OK(registry_init_full())) exit(1); /* Open the share_info.tdb here, so we don't have to open after the fork on every single connection. This is a small performance improvment and reduces the total number of system fds used. */ if (!share_info_db_init()) { DEBUG(0,("ERROR: failed to load share info db.\n")); exit(1); } status = init_system_info(); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("ERROR: failed to setup system user info: %s.\n", nt_errstr(status))); return -1; } if (!init_guest_info()) { DEBUG(0,("ERROR: failed to setup guest info.\n")); return -1; } if (!file_init(smbd_server_conn)) { DEBUG(0, ("ERROR: file_init failed\n")); return -1; } /* This MUST be done before start_epmd() because otherwise * start_epmd() forks and races against dcesrv_ep_setup() to * call directory_create_or_exist() */ if (!directory_create_or_exist(lp_ncalrpc_dir(), geteuid(), 0755)) { DEBUG(0, ("Failed to create pipe directory %s - %s\n", lp_ncalrpc_dir(), strerror(errno))); return -1; } if (is_daemon && !interactive) { if (rpc_epmapper_daemon() == RPC_DAEMON_FORK) { start_epmd(ev_ctx, msg_ctx); } } if (!dcesrv_ep_setup(ev_ctx, msg_ctx)) { exit(1); } /* only start other daemons if we are running as a daemon * -- bad things will happen if smbd is launched via inetd * and we fork a copy of ourselves here */ if (is_daemon && !interactive) { if (rpc_lsasd_daemon() == RPC_DAEMON_FORK) { start_lsasd(ev_ctx, msg_ctx); } if (!_lp_disable_spoolss() && (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) { bool bgq = lp_parm_bool(-1, "smbd", "backgroundqueue", true); if (!printing_subsystem_init(ev_ctx, msg_ctx, true, bgq)) { exit(1); } } } else if (!_lp_disable_spoolss() && (rpc_spoolss_daemon() != RPC_DAEMON_DISABLED)) { if (!printing_subsystem_init(ev_ctx, msg_ctx, false, false)) { exit(1); } } if (!is_daemon) { /* inetd mode */ TALLOC_FREE(frame); /* Started from inetd. fd 0 is the socket. */ /* We will abort gracefully when the client or remote system goes away */ smbd_server_conn->sock = dup(0); /* close our standard file descriptors */ if (!debug_get_output_is_stdout()) { close_low_fds(False); /* Don't close stderr */ } #ifdef HAVE_ATEXIT atexit(killkids); #endif /* Stop zombies */ smbd_setup_sig_chld_handler(ev_ctx); smbd_process(ev_ctx, smbd_server_conn); exit_server_cleanly(NULL); return(0); } parent = talloc_zero(ev_ctx, struct smbd_parent_context); if (!parent) { exit_server("talloc(struct smbd_parent_context) failed"); } parent->interactive = interactive; if (!open_sockets_smbd(parent, ev_ctx, msg_ctx, ports)) exit_server("open_sockets_smbd() failed"); /* do a printer update now that all messaging has been set up, * before we allow clients to start connecting */ printing_subsystem_update(ev_ctx, msg_ctx, false); TALLOC_FREE(frame); /* make sure we always have a valid stackframe */ frame = talloc_stackframe(); smbd_parent_loop(ev_ctx, parent); exit_server_cleanly(NULL); TALLOC_FREE(frame); return(0); }
void stat_cache_add( const char *full_orig_name, char *translated_path, bool case_sensitive) { size_t translated_path_length; char *original_path; size_t original_path_length; char saved_char; TALLOC_CTX *ctx = talloc_tos(); if (!lp_stat_cache()) { return; } /* * Don't cache trivial valid directory entries such as . and .. */ if ((*full_orig_name == '\0') || ISDOT(full_orig_name) || ISDOTDOT(full_orig_name)) { return; } /* * If we are in case insentive mode, we don't need to * store names that need no translation - else, it * would be a waste. */ if (case_sensitive && (strcmp(full_orig_name, translated_path) == 0)) { return; } /* * Remove any trailing '/' characters from the * translated path. */ translated_path_length = strlen(translated_path); if(translated_path[translated_path_length-1] == '/') { translated_path_length--; } if(case_sensitive) { original_path = talloc_strdup(ctx,full_orig_name); } else { original_path = talloc_strdup_upper(ctx,full_orig_name); } if (!original_path) { return; } original_path_length = strlen(original_path); if(original_path[original_path_length-1] == '/') { original_path[original_path_length-1] = '\0'; original_path_length--; } if (original_path_length != translated_path_length) { if (original_path_length < translated_path_length) { DEBUG(0, ("OOPS - tried to store stat cache entry " "for weird length paths [%s] %lu and [%s] %lu)!\n", original_path, (unsigned long)original_path_length, translated_path, (unsigned long)translated_path_length)); TALLOC_FREE(original_path); return; } /* we only want to index by the first part of original_path, up to the length of translated_path */ original_path[translated_path_length] = '\0'; original_path_length = translated_path_length; } /* Ensure we're null terminated. */ saved_char = translated_path[translated_path_length]; translated_path[translated_path_length] = '\0'; /* * New entry or replace old entry. */ memcache_add( smbd_memcache(), STAT_CACHE, data_blob_const(original_path, original_path_length), data_blob_const(translated_path, translated_path_length + 1)); DEBUG(5,("stat_cache_add: Added entry (%lx:size %x) %s -> %s\n", (unsigned long)translated_path, (unsigned int)translated_path_length, original_path, translated_path)); translated_path[translated_path_length] = saved_char; TALLOC_FREE(original_path); }
bool stat_cache_lookup(connection_struct *conn, bool posix_paths, char **pp_name, char **pp_dirpath, char **pp_start, SMB_STRUCT_STAT *pst) { char *chk_name; size_t namelen; bool sizechanged = False; unsigned int num_components = 0; char *translated_path; size_t translated_path_length; DATA_BLOB data_val; char *name; TALLOC_CTX *ctx = talloc_tos(); struct smb_filename smb_fname; int ret; *pp_dirpath = NULL; *pp_start = *pp_name; if (!lp_stat_cache()) { return False; } name = *pp_name; namelen = strlen(name); DO_PROFILE_INC(statcache_lookups); /* * Don't lookup trivial valid directory entries. */ if ((*name == '\0') || ISDOT(name) || ISDOTDOT(name)) { return False; } if (conn->case_sensitive) { chk_name = talloc_strdup(ctx,name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: strdup failed!\n")); return False; } } else { chk_name = talloc_strdup_upper(ctx,name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: talloc_strdup_upper failed!\n")); return False; } /* * In some language encodings the length changes * if we uppercase. We need to treat this differently * below. */ if (strlen(chk_name) != namelen) { sizechanged = True; } } while (1) { char *sp; data_val = data_blob_null; if (memcache_lookup( smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name)), &data_val)) { break; } DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n", chk_name )); /* * Didn't find it - remove last component for next try. */ if (!(sp = strrchr_m(chk_name, '/'))) { /* * We reached the end of the name - no match. */ DO_PROFILE_INC(statcache_misses); TALLOC_FREE(chk_name); return False; } *sp = '\0'; /* * Count the number of times we have done this, we'll * need it when reconstructing the string. */ if (sizechanged) { num_components++; } if ((*chk_name == '\0') || ISDOT(chk_name) || ISDOTDOT(chk_name)) { DO_PROFILE_INC(statcache_misses); TALLOC_FREE(chk_name); return False; } } translated_path = talloc_strdup(ctx,(char *)data_val.data); if (!translated_path) { smb_panic("talloc failed"); } translated_path_length = data_val.length - 1; DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] " "-> [%s]\n", chk_name, translated_path )); DO_PROFILE_INC(statcache_hits); ZERO_STRUCT(smb_fname); smb_fname.base_name = translated_path; if (posix_paths) { ret = SMB_VFS_LSTAT(conn, &smb_fname); } else { ret = SMB_VFS_STAT(conn, &smb_fname); } if (ret != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ memcache_delete(smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name))); TALLOC_FREE(chk_name); TALLOC_FREE(translated_path); return False; } *pst = smb_fname.st; if (!sizechanged) { memcpy(*pp_name, translated_path, MIN(namelen, translated_path_length)); } else { if (num_components == 0) { name = talloc_strndup(ctx, translated_path, translated_path_length); } else { char *sp; sp = strnrchr_m(name, '/', num_components); if (sp) { name = talloc_asprintf(ctx,"%.*s%s", (int)translated_path_length, translated_path, sp); } else { name = talloc_strndup(ctx, translated_path, translated_path_length); } } if (name == NULL) { /* * TODO: Get us out of here with a real error message */ smb_panic("talloc failed"); } TALLOC_FREE(*pp_name); *pp_name = name; } /* set pointer for 'where to start' on fixing the rest of the name */ *pp_start = &name[translated_path_length]; if (**pp_start == '/') { ++*pp_start; } *pp_dirpath = translated_path; TALLOC_FREE(chk_name); return (namelen == translated_path_length); }