The idea is that you have Socky listen on target ports, and any connection attempts that come in to those target ports will fire a user notification at the top right of your screen (that’s the job of SockyNotifier — to show those notifications).
Note: that this is not particularly serious or practical, but I wanted a project that let me work directly with the Core Foundation APIs in C, and this seemed a good opportunity.
It’s a lightweight application designed to run in the background, detecting if the computer is idle (based on keyboard or mouse movement) and presenting a timed warning that the computer will be locked. It then locks the computer if it is still idle once the grace period expires.
It is functional, but its real world usability isn’t there yet — it’s not going to be usable in practice if it isn’t aware of things like playing back video, presentations and other states that are not idle, but don’t involve user input for longer periods of time. It isn’t aware of those things at the time of writing!
However, it has been an enjoyable and informative further exploration of working with the Win32 API directly.
I found myself drawn to working in C/Win32 for this application and its predecessor — the result here is less than 50 KiB in size and uses about 1.4 MiB of RAM (Private Bytes). Any similar application you would create in .NET, for example, would be an order of magnitude more demanding in terms of resources, just because of the nature of the framework.
Here’s an explanation of how it works:
It accepts two command line arguments — the number of seconds before displaying the warning window and the number of grace period seconds while that window is open.
It measures the number of GetTickCount64 ticks taken for a SetTimer with 1000 ms to be fired. This is used to calculate idle periods and grace periods in terms of ticks.
It sets up two SetWindowsHookEx hooks — one for keyboard activity and one for the mouse. These yield execution some of the time to avoid performance issues from the frequency with which they are called. These update our last interaction tick number to indicate the computer is in use.
Every ten seconds, a SetTimer-based timer calls a function which evaluates if we’ve reached the idle condition. If so, the warning dialogue is displayed.
The warning dialogue counts down the grace period with the progress bar and another SetTimer callback. Upon expiry, LockWorkStation is called to lock the computer.
The WM_WTSSESSION_CHANGE window event is listened for — we take notice of WTS_SESSION_LOCK and UNLOCK events to ensure that we don’t try to detect idle conditions if the screen is already locked, and that when unlocked, any previous idle period is reset.
Learning about how Windows operates at a lower-level — windows, window messages and some of the more primitive operations has been illuminating! This is the perfect bi(y)te-sized project to help me move forward with learning about this!
I recently completed my rewrite of DfontSplitter for Mac, my tool for converting Mac-formatted Dfont, Font Suitcase and TTC font files into TTF files.
This new version is written in Swift, targets macOS Mojave (10.14) and later and meets all the requirements that soon will be required of Mac software (code signing, notarisation/delivery via Mac App Store).
The “T with chisel” DfontSplitter icon is licensed under the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. The icon includes a modified version of “Chisel wood 24mm” by Isabelle Grosjean, which is also licensed as such.
Apple, the Apple logo and Mac are trademarks of Apple Inc., registered in the U.S. and other countries and regions. App Store is a service mark of Apple Inc.
Keeping an eye on failed logins and the user accounts that are being targeted is an important part of being responsible for an Office 365/Azure Active Directory tenant.
If you can afford the higher-level O365/Azure AD plans, there are great tools built in to the Azure Portal that allow useful intelligence into your security posture.
For The Rest of Us(tm), we sometimes need to be a little creative to gather the information needed. For on-premises Active Directory Federation Services (ADFS) servers, I put together a simple, quick and, perhaps slightly hacky script to extract the usernames from recent failed login events from the Windows Event Log and dump them, along with the rest of the Windows Event, to a CSV file for later analysis.
This specifically searches event logs from the past 12 hours (43200000 milliseconds in the $query).
Note that this is heavily dependent upon the format of the event message having the username on the (zero-indexed) line 14. Works for us — no warranties, etc. etc.!
Installing the Remote System Administration Tools on a Windows 10 1903 system that uses System Center Configuration Manager to receive Windows updates seems to be challenging. The process of pulling the RSAT bits down from Windows Update in my experience was not succeeding – perhaps because the SCCM WSUS instance did not have them.
The CBS.log showed:
CBS Exec: Failed to download FOD from WU, retry onece. [HRESULT = 0x800f0954 - CBS_E_INVALID_WINDOWS_UPDATE_COUNT_WSUS]
Some solutions online seemed to suggest temporarily switching the Windows Update source in the registry to Windows Update (online) rather than WSUS, but editing the registry this way and upsetting the software update system seemed… unwise.
I ended up doing it a different way: downloading the Features on Demand DVD ISO from the Volume Licensing Service Center (in my case, SW_DVD9_NTRL_Win_10_1903_64Bit_MultiLang_FOD_1_X22-01658.ISO), mounting the ISO and using this modified version of Martin Bengtsson’s script to install the components from that ISO without contacting Windows Update.
I just released, on GitHub, IdleTaskTerminatorLite, my first foray into the lower-level world of programming directly with the Win32 API.
We use an old custom shutdown.exe (BeyondLogic Shutdown) to provide a timed screen lock feature, where a user is notified their screen will lock in a period of time and can cancel the locking of the workstation.
Clicking the Cancel button within the time limit, however, seems unnecessary and requires precisely clicking the Cancel button when the user is under time pressure! This is not a good user experience. A simple change to the idle state of the machine (any keypress or mouse movement) should cancel the timed locking of the workstation.
This lightweight background application detects user activity and forcibly kills the beyondlogic.shutdown.exe process, effectively cancelling the locking of the workstation without requiring the user to actually click Cancel.
This is currently rather ‘opinionated’ in that it specifically checks for hard-coded named processes running. It Works for Us(tm), but you may need to modify it for your environment. 😉
This whole solution is a little bit hacky, but it works. 😐
I had written something along these lines to terminate this workstation lock program in C#, but as a .NET process running in the background, you were looking at dozens of megabytes of RAM for something always running in the background. It felt thoroughly inefficient and unnecessary for something so simple.
I have always found myself honestly a little frightened of C and C++. Horror stories around coding securely, the undefined behaviour of doing ‘pointer stuff’ yourself… but this little project represented an opportunity to take this relatively rudimentary functionality and learn how to implement it the Win32 API directly in a C program — and in doing so, cut resource usage (hopefully) significantly.
So, I did. Using the oft-abused WH_KEYBOARD_LL hook (and its WH_MOUSE_LL cousin), I periodically update a counter as to the user’s last idle time. If the hook is called (i.e. the user is typing or moving the mouse) and it’s been long enough since we last noticed such interaction, I check for the beyondlogic.shutdown.exe process and, if present, kill it.
This began life as whatever Visual Studio template gave me a buildable project that let me work with the right APIs, so there is likely unnecessary stuff still present and it could be more lightweight still. And, there’s a good chance I’ve made mistakes that need correcting, so please do get in contact if you’re willing to educate me in some small (or large) way!
I have tried to be particularly careful with buffers — string handling is either done with (I guess, inefficient) fixed-size buffers where I check what I put in will fit first, and I’ve tried to use the ‘safe’ string functions where possible too.
So, it’s a baby step towards working on more low-level projects. But, I’ve taken some action to tackle my pointer anxiety. 🙂
Maybe next the whole program should do the workstation locking, warning message and idle detection in one program.
This was a whole month and a bit ago, and I never got around to throwing it here on the site, but I will now announce that I am a Red Hat Certified System Adminstrator!
It’s a tough day for some at Mozilla, I imagine, with pretty much all Firefox add-ons suddenly being disabled due to an expired intermediate certificate.
I love Firefox. I love having a browser that is not increasingly proprietary (*cough* Chrome *cough*), and so I too was hit by this issue.
Mozilla rolled out a fix using their studies system, and users were told to go to about:studies and it would show up within 24 hours.
My about:studies was a blank white page. Not a blank list of studies with the explanatory text — an entirely blank page. Here’s what it should have looked like:
I delved into the Firefox source code to see if I could track this down.
Running Firefox with the -jsconsole switch revealed errors relating to IndexedDB and the Top Sites component. Initially, I ignored these, but it turns out they were likely symptoms of the same problem.
In the end, I found toolkit/components/normandy/lib/AddonStudies.jsm, which I believe is the backend that the about:studies frontend JavaScript code talks to.
const DB_NAME = "shield";
const STORE_NAME = "addon-studies";
const DB_OPTIONS = {
version: 1,
};
const STUDY_ENDED_TOPIC = "shield-study-ended";
const log = LogManager.getLogger("addon-studies");
/**
* Create a new connection to the database.
*/
function openDatabase() {
return IndexedDB.open(DB_NAME, DB_OPTIONS, db => {
db.createObjectStore(STORE_NAME, {
keyPath: "recipeId",
});
});
}
So, I knew I was looking at IndexedDB and I needed to locate what was happening with this particular shield database.
This StackOverflow answer was old, but gave me a hint of where to look. In the Firefox profile folder, there is storage/permanent. Inside here, a number of subfolders, including chrome (no, not Chrome — chrome) and other folders relating to devtools.
I noticed that in the chrome folder, I had four files for two different databases. Each database had a .sqlite-wal file and a .sqlite-shm file. This didn’t seem right — these are an index and a write-ahead log, but where is the actual data file? There should be a .sqlite file as well with the actual data for both databases.
So, I deleted these four .sqlite-wal and .sqlite-shm files from my profile (after a backup, of course, and when Firefox was not running).
A restart of Firefox later — several databases were regenerated and reappeared in that folder. Critically, about:studies was no longer blank and displayed as it should have — albeit with no studies yet.
A Fix? A Workaround?
Performing these steps may cause your Firefox profile to be irreparably damaged. This is an advanced and entirely unsupported process. Proceed at your own risk and only with a backup.
Great caution should be exercised here — I don’t know what these chrome IndexedDB databases contain, or should have contained. In any case, I’m pretty sure that the absence of the .sqlite file but the presence of the wal and shm files meant that Firefox was unwilling to delete them and start again for fear of losing something.
However, if you are experiencing the same problem:
A recent upgrade to System Center Operations Manager, taking it to the new 2019 release, perhaps combined with an update to the Windows Server management packs, created an interesting issue.
On the management server, an alert was triggered about the management server itself:
Resolution State: New Alert: Server Service: File and Printer Sharing Ports Blocked Source: SCOM (SMB) Path: SCOM.fqdn Last modified by: System Last modified time: 3/13/2019 2:14:28 PM Alert description: Either Windows Firewall is disabled or the firewall inbound rules for TCP ports 445 or 139 are disabled.
Interesting. Did the upgrade to SCOM 2019 or the management pack somehow break Windows File Sharing? And if it did, why hadn’t we noticed more significant issues than just this alert?
Well, no — it looks like this alert is actually earlier from March, but perhaps the alert has re-surfaced, post upgrade, as the monitor re-evaluated. What I was sure about, however, was that the file sharing ports were indeed open and that this alert couldn’t be correct!
Right? Right?
To the Firewall!
Investigating all the relevant firewall rules revealed that everything was in order — Windows File and Printer Sharing exceptions were allowed, as appropriate, across the board.
What is it Detecting?
So, it was time to dig a little deeper.
I was able to go to the Alert details and click on the Alert Monitor to drill down and find the details of how the monitor was coming to this apparently erroneous conclusion.
I extracted the script and tried running it manually on the server using cscript.
With a few WScript.Echo calls of mine sprinkled in, the relevant part of the VBScript that powered the monitor was as follows:
Dim rule
For Each rule in fwPolicy2.Rules
If (rule.Protocol = NET_FW_IP_PROTOCOL_TCP) And (rule.LocalPorts = "445") Then
WScript.Echo("Proto " + CStr(rule.Protocol) + " and port " + rule.LocalPorts + " enabled: " + CStr(rule.Enabled))
WScript.Echo("rule.Profiles: " + CStr(rule.Profiles) + " and rule.Enabled " + CStr(rule.Enabled))
If (Not rule.Enabled) And (rule.Profiles And fwCheckProfile ) Then
WScript.Echo "Setting file sharing ports enabled to true"
fwFileSharingPortsEnabled = "True"
Exit For
End If
End If
Next
So, let’s go ahead and run this.
The script also checks to see if any non-hidden shares exist on the server and will only put the monitor in an unhealthy state if at least one exists.
It iterates over all the rules for port 445, decides all the rules are enabled, which would allow access to File Sharing, but then ends up with fwFileSharingPortsEnabled still being false.
This propagates to the ultimate script output of a PropertyBag with the value Disabled under PortStatus.
All the rules are enabled, but the result is that it considers the ports not open for business??
Is this Logic?
It seems to me that there is a logic error here:
If (Not rule.Enabled) And (rule.Profiles And fwCheckProfile ) Then
Only if the firewall rule is not enabled and the profile matches the current network profile, we consider the port enabled?
Remember that if the rule is not enabled, traffic would be blocked by the Windows Firewall.
It seems that this might be a simple logic error in the management pack. A comment later in the script even states:
‘ Only if regular share exists and port 139/445 are not open will portStatus be returned as “Disabled”
Am I missing something obvious?
I’d Report This…
I cannot figure out where I should report this, if I’m correct in thinking how this should be working. Should I complain on a forum? Is there a System Center Operations Manager support Short-Form “Bird” Social Media Site Before It Went Terrible profile? Product Support?
An Unorthodox Workaround
For now, disabling at least one of the rules for port 445 suppresses this alert. For example, if you don’t need or want Remote Event Log Management, you can disable the Remote Event Log Management (NP-In) rule. This script will then return Enabled and the alert will not be fired.
Facebook is a company that engages in unethical behaviour. Its ubiquity and its necessity for many people’s social lives undermines people’s ability to meaningfully grant or withhold their consent to its policies.
I take no pride in seeing this coming in 2010, and I have refused to use any of their services consistently since.
So I was surprised, to say the least, when I sent a link over iMessage that I knew would be unique, but saw a request being made for it by the facebookexternalhit/1.1 bot user agent. This URL should not have ever been seen by anyone but me and the recipient. I took the time to verify that the only access to this URL was by myself and the recipient.
“GET /some-secret-url HTTP/1.1” 200 – “” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.4 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.4 facebookexternalhit/1.1 Facebot Short-Form “Bird” Social Media Site Before It Went Terriblebot/1.0″
It turned out that the facebookexternalhit/1.1 request (also identifying as Short-Form “Bird” Social Media Site Before It Went Terriblebot!) was issued by the same IP address that I had. How could I be a Facebook/Short-Form “Bird” Social Media Site Before It Went Terrible bot? How could it be that some Facebook code was running in my network? (I’m pretty particular in blocking large numbers of domains relating to Facebook properties.)
It turns out that this message preview in iMessage seems to make a request for the URL using this user agent string. It doesn’t identify itself as iMessage in the user agent string at all!
I’m satisfied that I answered the question — and indeed I understand the nature of user agent strings and how everybody pretends to be something else for compatibility. I expect a service to add to the user agent string, though. Chrome pretends to be Safari, which pretends to be “like Gecko”, which pretends to be “Mozilla/5.0”.
So why can’t iMessage add “iMessageLinkPreview/1.0” or something to the user agent string?
There used to be advertising here, but I no longer feel sure that advertising delivers the best experience and truly reflects the values of this site.
Keeping things running, however, is not without financial cost. If you would like to support the time and effort I have put into my tutorials and writing, please
consider making a donation.