/* Open up the notify.tdb database. You should close it down using talloc_free(). We need the messaging_ctx to allow for notifications via internal messages */ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, struct messaging_context *messaging_ctx, struct event_context *ev, connection_struct *conn) { struct notify_context *notify; if (!lp_change_notify(conn->params)) { return NULL; } notify = talloc(mem_ctx, struct notify_context); if (notify == NULL) { return NULL; } notify->db_recursive = db_open(notify, lock_path("notify.tdb"), 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2); if (notify->db_recursive == NULL) { talloc_free(notify); return NULL; } notify->db_onelevel = db_open(notify, lock_path("notify_onelevel.tdb"), 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2); if (notify->db_onelevel == NULL) { talloc_free(notify); return NULL; } notify->server = server; notify->messaging_ctx = messaging_ctx; notify->list = NULL; notify->array = NULL; notify->seqnum = dbwrap_get_seqnum(notify->db_recursive); notify->key = string_term_tdb_data(NOTIFY_KEY); talloc_set_destructor(notify, notify_destructor); /* register with the messaging subsystem for the notify message type */ messaging_register(notify->messaging_ctx, notify, MSG_PVFS_NOTIFY, notify_handler); notify->sys_notify_ctx = sys_notify_context_create(conn, notify, ev); return notify; }
static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn, connection_struct *conn, int snum, struct user_struct *vuser, const char *pdev) { struct smbd_server_connection *sconn = xconn->client->sconn; struct smb_filename *smb_fname_cpath = NULL; fstring dev; int ret; bool on_err_call_dis_hook = false; uid_t effuid; gid_t effgid; NTSTATUS status; fstrcpy(dev, pdev); status = share_sanity_checks(sconn->remote_address, sconn->remote_hostname, snum, dev); if (NT_STATUS_IS_ERR(status)) { goto err_root_exit; } conn->params->service = snum; status = create_connection_session_info(sconn, conn, snum, vuser->session_info, &conn->session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("create_connection_session_info failed: %s\n", nt_errstr(status))); goto err_root_exit; } if (lp_guest_only(snum)) { conn->force_user = true; } conn->num_files_open = 0; conn->lastused = conn->lastused_count = time(NULL); conn->printer = (strncmp(dev,"LPT",3) == 0); conn->ipc = ( (strncmp(dev,"IPC",3) == 0) || ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) ); /* Case options for the share. */ if (lp_case_sensitive(snum) == Auto) { /* We will be setting this per packet. Set to be case * insensitive for now. */ conn->case_sensitive = False; } else { conn->case_sensitive = (bool)lp_case_sensitive(snum); } conn->case_preserve = lp_preserve_case(snum); conn->short_case_preserve = lp_short_preserve_case(snum); conn->encrypt_level = lp_smb_encrypt(snum); conn->veto_list = NULL; conn->hide_list = NULL; conn->veto_oplock_list = NULL; conn->aio_write_behind_list = NULL; conn->read_only = lp_read_only(SNUM(conn)); status = set_conn_force_user_group(conn, snum); if (!NT_STATUS_IS_OK(status)) { goto err_root_exit; } conn->vuid = vuser->vuid; { char *s = talloc_sub_advanced(talloc_tos(), lp_servicename(talloc_tos(), SNUM(conn)), conn->session_info->unix_info->unix_name, conn->connectpath, conn->session_info->unix_token->gid, conn->session_info->unix_info->sanitized_username, conn->session_info->info->domain_name, lp_path(talloc_tos(), snum)); if (!s) { status = NT_STATUS_NO_MEMORY; goto err_root_exit; } if (!set_conn_connectpath(conn,s)) { TALLOC_FREE(s); status = NT_STATUS_NO_MEMORY; goto err_root_exit; } DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(talloc_tos(), snum))); TALLOC_FREE(s); } /* * Set up the share security descriptor. * NOTE - we use the *INCOMING USER* session_info * here, as does (indirectly) change_to_user(), * which can be called on any incoming packet. * This way we set up the share access based * on the authenticated user, not the forced * user. See bug: * * https://bugzilla.samba.org/show_bug.cgi?id=9878 */ status = check_user_share_access(conn, vuser->session_info, &conn->share_access, &conn->read_only); if (!NT_STATUS_IS_OK(status)) { goto err_root_exit; } /* Initialise VFS function pointers */ if (!smbd_vfs_init(conn)) { DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(talloc_tos(), snum))); status = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } /* ROOT Activities: */ /* explicitly check widelinks here so that we can correctly warn * in the logs. */ widelinks_warning(snum); /* * Enforce the max connections parameter. */ if ((lp_max_connections(snum) > 0) && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn)), True) >= lp_max_connections(snum))) { DEBUG(1, ("Max connections (%d) exceeded for %s\n", lp_max_connections(snum), lp_servicename(talloc_tos(), snum))); status = NT_STATUS_INSUFFICIENT_RESOURCES; goto err_root_exit; } /* Invoke VFS make connection hook - this must be the first filesystem operation that we do. */ if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum), conn->session_info->unix_info->unix_name) < 0) { DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n", lp_servicename(talloc_tos(), snum), conn->connectpath, strerror(errno)); status = NT_STATUS_UNSUCCESSFUL; goto err_root_exit; } /* Any error exit after here needs to call the disconnect hook. */ on_err_call_dis_hook = true; if ((!conn->printer) && (!conn->ipc) && lp_change_notify()) { if (sconn->notify_ctx == NULL) { sconn->notify_ctx = notify_init( sconn, sconn->msg_ctx, sconn->ev_ctx); status = messaging_register( sconn->msg_ctx, sconn, MSG_SMB_NOTIFY_CANCEL_DELETED, smbd_notify_cancel_deleted); } if (sconn->sys_notify_ctx == NULL) { sconn->sys_notify_ctx = sys_notify_context_create( sconn, sconn->ev_ctx); } } if (lp_kernel_oplocks(snum)) { init_kernel_oplocks(conn->sconn); } /* * Fix compatibility issue pointed out by Volker. * We pass the conn->connectpath to the preexec * scripts as a parameter, so attempt to canonicalize * it here before calling the preexec scripts. * We ignore errors here, as it is possible that * the conn->connectpath doesn't exist yet and * the preexec scripts will create them. */ (void)canonicalize_connect_path(conn); /* Preexecs are done here as they might make the dir we are to ChDir * to below */ /* execute any "root preexec = " line */ if (*lp_root_preexec(talloc_tos(), snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), lp_servicename(talloc_tos(), SNUM(conn)), conn->session_info->unix_info->unix_name, conn->connectpath, conn->session_info->unix_token->gid, conn->session_info->unix_info->sanitized_username, conn->session_info->info->domain_name, lp_root_preexec(talloc_tos(), snum)); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); if (ret != 0 && lp_root_preexec_close(snum)) { DEBUG(1,("root preexec gave %d - failing " "connection\n", ret)); status = NT_STATUS_ACCESS_DENIED; goto err_root_exit; } } /* USER Activites: */ if (!change_to_user(conn, conn->vuid)) { /* No point continuing if they fail the basic checks */ DEBUG(0,("Can't become connected user!\n")); status = NT_STATUS_LOGON_FAILURE; goto err_root_exit; } effuid = geteuid(); effgid = getegid(); /* Remember that a different vuid can connect later without these * checks... */ /* Preexecs are done here as they might make the dir we are to ChDir * to below */ /* execute any "preexec = " line */ if (*lp_preexec(talloc_tos(), snum)) { char *cmd = talloc_sub_advanced(talloc_tos(), lp_servicename(talloc_tos(), SNUM(conn)), conn->session_info->unix_info->unix_name, conn->connectpath, conn->session_info->unix_token->gid, conn->session_info->unix_info->sanitized_username, conn->session_info->info->domain_name, lp_preexec(talloc_tos(), snum)); ret = smbrun(cmd,NULL); TALLOC_FREE(cmd); if (ret != 0 && lp_preexec_close(snum)) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); status = NT_STATUS_ACCESS_DENIED; goto err_root_exit; } } #ifdef WITH_FAKE_KASERVER if (lp_afs_share(snum)) { afs_login(conn); } #endif /* * we've finished with the user stuff - go back to root * so the SMB_VFS_STAT call will only fail on path errors, * not permission problems. */ change_to_root_user(); /* ROOT Activites: */ /* * If widelinks are disallowed we need to canonicalise the connect * path here to ensure we don't have any symlinks in the * connectpath. We will be checking all paths on this connection are * below this directory. We must do this after the VFS init as we * depend on the realpath() pointer in the vfs table. JRA. */ if (!lp_widelinks(snum)) { if (!canonicalize_connect_path(conn)) { DEBUG(0, ("canonicalize_connect_path failed " "for service %s, path %s\n", lp_servicename(talloc_tos(), snum), conn->connectpath)); status = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } } /* Add veto/hide lists */ if (!IS_IPC(conn) && !IS_PRINT(conn)) { set_namearray( &conn->veto_list, lp_veto_files(talloc_tos(), snum)); set_namearray( &conn->hide_list, lp_hide_files(talloc_tos(), snum)); set_namearray( &conn->veto_oplock_list, lp_veto_oplock_files(talloc_tos(), snum)); set_namearray( &conn->aio_write_behind_list, lp_aio_write_behind(talloc_tos(), snum)); } smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath, NULL, NULL); if (smb_fname_cpath == NULL) { status = NT_STATUS_NO_MEMORY; goto err_root_exit; } /* win2000 does not check the permissions on the directory during the tree connect, instead relying on permission check during individual operations. To match this behaviour I have disabled this chdir check (tridge) */ /* the alternative is just to check the directory exists */ if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 || !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) { DEBUG(0,("'%s' is not a directory, when connecting to " "[%s]\n", conn->connectpath, lp_servicename(talloc_tos(), snum))); } else { DEBUG(0,("'%s' does not exist or permission denied " "when connecting to [%s] Error was %s\n", conn->connectpath, lp_servicename(talloc_tos(), snum), strerror(errno) )); } status = NT_STATUS_BAD_NETWORK_NAME; goto err_root_exit; } conn->base_share_dev = smb_fname_cpath->st.st_ex_dev; talloc_free(conn->origpath); conn->origpath = talloc_strdup(conn, conn->connectpath); /* Figure out the characteristics of the underlying filesystem. This * assumes that all the filesystem mounted withing a share path have * the same characteristics, which is likely but not guaranteed. */ conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res); /* * Print out the 'connected as' stuff here as we need * to know the effective uid and gid we will be using * (at least initially). */ if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) { dbgtext( "%s (%s) ", get_remote_machine_name(), tsocket_address_string(conn->sconn->remote_address, talloc_tos()) ); dbgtext( "%s", srv_is_signing_active(xconn) ? "signed " : ""); dbgtext( "connect to service %s ", lp_servicename(talloc_tos(), snum) ); dbgtext( "initially as user %s ", conn->session_info->unix_info->unix_name ); dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid ); dbgtext( "(pid %d)\n", (int)getpid() ); } return status; err_root_exit: TALLOC_FREE(smb_fname_cpath); /* We must exit this function as root. */ if (geteuid() != 0) { change_to_root_user(); } if (on_err_call_dis_hook) { /* Call VFS disconnect hook */ SMB_VFS_DISCONNECT(conn); } return status; }