krypted.com

Tiny Deathstars of Foulness

Apple has a number of different logging APIs. For the past few releases, Apple has tried to capture everything possible in logs, creating what many administrators and developers might consider to be a lot of chatter. As such, an entirely new interface needed to be developed to categorize and filter messages sent into system logs.

Writing Logs

The logger command is still used to create entries in system logs. However, if you are then using tail to view /var/log/system.log then you will notice that you no longer see your entry being written. This is because as the logs being created in macOS have gotten more complex, the tools to read and write those logs has gotten more complicated as well.

Let’s take a simple log entry. Below, we’ll write the string “Hello Logs” into the system log. To do so, use the –i option to put the process id of the logger process and –s to write to the system log, as well as to stderr. To make the entry easier we’ll tag it with –t followed by the string of the tag. And finally, we’ll quote the entry we want written into the log. This is basically the simplest form of an entry:

logger -is -t krypted "Hello Logs"

Once written, use the log command to read your spiffy new entries. This isn’t terribly different than how things worked previously. If you’re a developer, you will need to note that all of the legacy APIs you might be using, which include asl_log_message, NSLog, and syslog, have been redirected to the new Unified Logging system, provided you build software for 10.12 (you can still build as before for 10.11, iOS 9, tvOS 10, and watchOS 3 and below). These are replaced with the os_log, os_log_info, os_log_debug, os_log_error, os_log_fault, and os_log_create APIs (which correspond to various levels of logs that are written).

Reading Logs

Logs are now stored in the tracev3 formatted files in /var/db/diagnostics, which is a compressed binary format. As with all binary files, you’ll need new tools to read the files. Console has been updated with a new hierarchical capability and the ability to watch activities, subsystems, etc.

The log command provides another means of reading those spiffy new logs. To get started, first check out the man page:

man log

That “Hello Logs” string we used earlier is part of a message that you can easily view using the ‘log show’ command. In the below example, we’ll just run a scan of the last 3 minutes, using the –last option, and then providing a –predicate. We’ll explain those a bit later, but think of it as query parameters – here, we’ll specify to look for “Hello Logs” in eventMessage:

log show --predicate 'eventMessage contains "Hello Logs"' --last 3m

Filtering the log data using “eventMessage CONTAINS “Hello Logs”” shows us that our entry appears as follows:

Timestamp                       Thread     Type        Activity             PID

2017-03-23 23:51:05.236542-0500 0x4b83bb   Default     0x0                  88294  logger: Hello Logs

——————————————————————————————————————–

Log      – Default:          1, Info:                0, Debug:             0, Error:          0, Fault:          0

Activity – Create:           0, Transition:          0, Actions:           0

How do you find out what to use where? Here’s an example where I’m going to try to find all invalid login attempts. First, I’m just going to watch the logs. Many will prefer the “log stream’ command. I’m actually going to just use show again, because I like the way it looks more. I’m also going to use log with the syslog –style so it’s easier to read (for me at least), and then here I’m just looking at everything by specifying a space instead of an actual search term:

log show --style syslog --predicate 'eventMessage contains " "' --info --last 24h

Looking at the output, you can see an entry similar to the following:

2017-03-23 14:01:43.953929-0500  localhost authorizationhost[82865]: Failed to authenticate user <admin> (error: 9).

Oh, I’ve got to just search for Failed to authenticate user” and I’ll be able to count invalid login attempts. To then take this and place it into a command that, for example, I could build an extension attribute using, I can then just find each entry in eventMessage that contains the string, as follows:

log show --style syslog --predicate 'eventMessage contains "Failed to authenticate user"' --info --last 1d

As with many tools, once you have a couple of basic incantations, they become infinitely simpler to understand. These few commands basically get you back to where you were with tailing logs. If you want to get that –f functionality from tail, to watch the logs live, just swap show with stream. The most basic incantation of this would just be ‘log stream’ without bothering to constrain the output:

log stream

Running this is going to spew so much data into your terminal session. So to narrow down what you’re looking for, let’s look at events for Twitter:

log stream --predicate 'eventMessage contains "Twitter"'

You can also view other logs and archives, by calling a file name:

log show system_logs.logarchive

Organization and Classification

The new logging format also comes with Subsystems. If you’re a developer you’ll be able to file your messages into, for example, a com.yourname.whatevers domain space, so you can easily find your log messages. You can also build categories, and of course, as we noted previously, tag. So there are about as many ways to find log entries as you can possibly ask for. Apple has a number of subsystems built into macOS. I put together a list of Apple subsystems into a class that you should be able to throw into your python projects at https://gist.github.com/krypted/495e48a995b2c08d25dc4f67358d1983.

You also have different logging levels. These include the basic levels of Default, Info, and Debug. You also have two special levels available: Fault and Error. All of this is to add hierarchical logs (which makes tracing events a much more lovely experience) and protecting privacy of end users (think sandbox for logs). I’d recommend watching the WWDC session where Unified Logging was introduced at https://developer.apple.com/videos/play/wwdc2016/721 if you’re interested in learning more about these types of things, especially if you’ll be building software that makes use of these new logging features.

The one thing that’s worth mentioning for the Mac Techs out there, is how you would go about switching between logging levels for each subsystem. This is done with the ‘log config’ command. Here, I’ll use the –mode option to set the level to debug, and then defining the substyem to do so with using the –subsystem option:

log config --mode "level:debug" --subsystem com.krypted

If you have a particularly dastardly app, the above might just help you troubleshoot a bit. As mentioned earlier, we also have these predicates, which you can think of as metadata in the searching context. These include the following:

  • category: category of a log entry
  • eventMessage: searches the activity or message
  • eventType: type of events that created the entry (e.g. logEvent, traceEvent)
  • messageType – type or level of a log entry
  • processImagePath: name of the process that logged the event
  • senderImagePath: not all entries are created by processes, so this also includes libraries and executables
  • subsystem: The name of the subsystem that logged an event

Comparisons and Searches

OK, now let’s make things just a tad bit more complicated. We’ll do this by stringing together search parameters. Here, we have a number of operators available to us, similar to what you see in SQL. These include:

  • && or AND to indicate two matches
  • || or OR indicates one of the patterns matches
  • ! or NOT searches for items that the patterns don’t match for, which is useful for filtering out false positives in scripts
  • = to indicate that one search matches a pattern or is equal to
  • != to indicate that the search is not equal to
  • > is greater than
  • < is less than
  • => means greater than or equal to
  • =< means less than or equal to
  • CONTAINS indicates a string matches a given pattern with case sensitivity
  • CONTAINS[c] indicates a string matches a given pattern without case sensitivity
  • BEGINSWITH indicates a string begins with a given pattern
  • ENDSWITH indicates that a string ends with a given pattern
  • LIKE indicates a pattern is similar to what you’re searching for
  • MATCHES indicates that two text strings match
  • ANY, SOME, NONE, IN are used for pattern matching in arrays
  • NULL indicates a NULL response (for example, you see “with error (NULL)” in logs a lot)

To put these into context, let’s use one in an example. Thus far my most common as been a compound search, so matching both patterns. Here, we’ll look at the WirelessProximity subsystem for Bluetooth and we’ll look at how often it’s scanning for new devices, keeping both patterns to match inside their own parenthesis, with all patterns stored inside single quotes, as follows:

log show --style syslog --predicate '(subsystem == "com.apple.bluetooth.WirelessProximity") && (eventMessage CONTAINS[c] "scanning")' --info --last 1h

Developers and systems administrators will find that the Apple guide on predicate programming, available at https://developer.apple.com/library/prerelease/content/documentation/Cocoa/Conceptual/Predicates/AdditionalChapters/Introduction.html, to be pretty useful if you’re doing lots of this kind of work.

Note: sysdiagnose, a tool long used for capture diagnostics information to include in bug reports, is still functional, and now includes Unified Logging information, so Apple developers can get a complete picture of what’s going on in systems.

Conclusion

Ultimately, the new Unified Logging is a bit more complicated than the previous options for both creating and reading logs. But once you get used to it, you’ll log it – I mean, love it. I find that I use less grep and awk and get more concise results. I also like the fact that the same code is useable with all four platforms, so learn once and re-use across devices. There’s a lot of information out there, but I had to go hunting around. Hopefully having a number of links and a the structure used in this article makes it easier to learn how to use all these new new little toys! Good luck!

July 26th, 2017

Posted In: Mac OS X, Mac OS X Server, Mac Security

Tags: , , , , ,

Tomcat logs events into the system log. You can use the get-wmiobject commandlet to see events. Here, we’ll look at a JSS and view only system events:

Get-WmiObject Win32_NTLogEvent -ComputerName $jss -Filter "LogFile='system'

We can then use AND to further constrain to specific messages, in this case those containing Tomcat:

Get-WmiObject Win32_NTLogEvent -ComputerName $jss -Filter "LogFile='system' AND (Message like '%Tomcat%')

We can then further constrain output to those with a specific EventCode with another compound statement:

Get-WmiObject Win32_NTLogEvent -ComputerName $jss -Filter "LogFile='system' AND (Message like '%Tomcat%') AND (EventCode=1024)

For a comprehensive list of Windows event codes, see https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/default.aspx.

You could instead use get-eventlog to see system logs. For example, the following will list the latest 100 entries in the system log:

Get-Eventlog -LogName system -Newest 1000

And the following lists the number of unique entries in descending order using Sort-Object, along with the -Property option set to count:

Get-Eventlog -LogName system -Newest 1000 | Sort-Object -Property count -Descending

And the following would additionally constrain the output to entries with the word Tomcat using the -Message option:

Get-Eventlog -LogName system -Newest 1000 -Message "*Tomcat*" | Sort-Object -Property count -Descending

And to focus on a server called jss, use the -ComputerName option:

Get-Eventlog -LogName system -Newest 1000 -Message "*Tomcat*" -ComputerName "localhost" | Sort-Object -Property count -Descending

July 11th, 2017

Posted In: JAMF, Windows Server

Tags: , , , , , , ,

June 21st, 2017

Posted In: MacAdmins Podcast

Tags: , , , , ,

June 2nd, 2017

Posted In: Mac OS X, Mac OS X Server, Mac Security, MacAdmins Podcast

Tags: , , , , ,

Over the users I’ve written a good bit about pushing a workload off to a virtual machine sitting in a data center somewhere. The Google CloudPlatform has matured a lot and I haven’t really gotten around to writing about it. So… It’s worth going into their SDK and what it looks like from a shell using some quick examples.

For starters, you’ll need an account with Google Cloud Platform, at cloud.google.com and you’ll want to go ahead and login to the interface, which is pretty self-explanatory (although at first you might have to hunt a little for some of the more finely grained features, like zoning virtual instances.

The SDK

The SDK will include the gcloud command, which you’ll use to perform most tasks in the Google CloudPlatform. To install the SDK, go to https://cloud.google.com/sdk/downloads and download the appropriate version for your computer. If you’re on a mac, most likely the x86_64 version.

Next, move the downloaded folder to a permanent location and run the install.sh inside it, which will kindly offer to add gcloud to your path.

./install.sh

Welcome to the Google Cloud SDK!
To help improve the quality of this product, we collect anonymized usage data
and anonymized stacktraces when crashes are encountered; additional information
is available at <https://cloud.google.com/sdk/usage-statistics>. You may choose
to opt out of this collection now (by choosing ‘N’ at the below prompt), or at
any time in the future by running the following command:
gcloud config set disable_usage_reporting true
Do you want to help improve the Google Cloud SDK (Y/n)?  y
Modify profile to update your $PATH and enable shell command
completion?
Do you want to continue (Y/n)?  y
The Google Cloud SDK installer will now prompt you to update an rc
file to bring the Google Cloud CLIs into your environment.
Enter a path to an rc file to update, or leave blank to use
[/Users/charlesedge/.bash_profile]:
Backing up [/Users/charlesedge/.bash_profile] to [/Users/charlesedge/.bash_profile.backup].
[/Users/charlesedge/.bash_profile] has been updated.
==> Start a new shell for the changes to take effect.
For more information on how to get started, please visit:
https://cloud.google.com/sdk/docs/quickstarts

Inside that bin folder, you’ll find the gcloud python script, which once installed, you can then run. Next, you’ll need to run the init, which links it to your CloudPlatform account via oauth. To do so, run gcloud with the init verb, which will step you through the process:

gcloud init

Welcome! This command will take you through the configuration of gcloud.
Your current configuration has been set to: [default]
You can skip diagnostics next time by using the following flag:
gcloud init –skip-diagnostics

Network diagnostic detects and fixes local network connection issues.
Checking network connection…done.
Reachability Check passed.
Network diagnostic (1/1 checks) passed.

You must log in to continue. Would you like to log in (Y/n)? y

If you say yes in the above screen, your browser will then prompt you with a standard Google oauth screen where you’ll need to click Allow.

Now go back to Terminal and pick a “Project” (when you set up billing the default was created for you):

Pick cloud project to use:
[1] seventh-capsule-138123
[2] Create a new project
Please enter numeric choice or text value (must exactly match list
item):
1

The Command Line

Next, we’re gonna’ create a VM. There are several tables that lay out machine types. Let’s start by listing any instances we might have:

gcloud compute instances list

Listed 0 items.

Note: If you have a lot of these you can use  --regexp to filter them quickly.

Then let’s pick a machine type. A description of machine types can be found at https://cloud.google.com/compute/docs/machine-types. And an image. Images can be seen using the compute command with images and then list, as follows:

gcloud compute images list

Now, let’s use that table from earlier and make a custom machine using an ubuntu uri, a –custom-cpu and a –custom-memory:

gcloud compute instances create krypted1 –image https://www.googleapis.com/compute/v1/projects/ubuntu-os-cloud/global/images/ubuntu-1610-yakkety-v20170502 –custom-cpu 2 –custom-memory 5

You’ll then see that your VM is up, running, and… has an IP:

Created [https://www.googleapis.com/compute/v1/projects/seventh-capsule-138523/zones/us-central1-a/instances/krypted1].
NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS
krypted1 us-central1-a custom (2 vCPU, 5.00 GiB) 10.128.0.2 104.154.169.65 RUNNING

Now let’s SSH in:

gcloud compute ssh krypted1

This creates ssh keys, adds you to the hosts and SSH’s you into a machine. So viola. You’re done. Oh wait, you don’t want to leave it running forever. After all, you’re paying by the minute… So let’s list your instances:

gcloud compute instances list

Then let’s stop the one we just created:

gcloud compute instances stop krypted1

And if you’d like, tear it down:

gcloud compute instances delete krypted1

Overall, super logical, very easy to use, and lovely command line environment. Fast, highly configurable VMs. Fun times!

May 18th, 2017

Posted In: cloud, Mac OS X, Ubuntu, Unix

Tags: , , , , , , ,

Added 3 new flags into precache tonight: –jamfserver, –jamfuser, and –jamfpassword. These are used to provide a Jamf Pro server (or cloud instance), the username to an account that can list the mobile devices on that server, and a password to that account respectively.

Basically, when you provide these, the script will pull a unique set of models and then precache updates for them. It’s similar to grabbing a list of devices:

curl -s -u myuser:mypassword https://myserver.jamfcloud.com/JSSResource/mobiledevices

And then piping the output of a device list to:

perl -lne 'BEGIN{undef $/} while (/<model_identifier>(.*?)<\/model_identifier>/sg){print $1}'

And then running that array as an input to precache.py. Hope this helps make the script more useful!

May 13th, 2017

Posted In: iPhone, Mac OS X Server

Tags: , , , , , ,

April 23rd, 2017

Posted In: iPhone, MacAdmins Podcast, Mass Deployment

Tags: , , , ,

MySQL usually pulls settings from a my.cnf file. However, you can end up with settings in include files, which can be defined in the my.cnf using the following directives:

include /home/mydir/myopt.cnf
includedir /home/mydir

Because of this, and the fact that you might not have access to all locations of .cnf files on a filesystem, you can also grab them using the SHOW VARIABLES option within SQL, obtained by

/usr/local/mysql/bin/mysql -uroot -p mypassword -e "SHOW VARIABLES;" > /tmp/SQLSettings.txt

In the above command, -uroot defines we’ll be accessing with the root user, -p defines the password (listed as mypassword) and the -e defines that we want to execute a command and then quit. We then use > to dump the output into the defined file.

April 21st, 2017

Posted In: Mac OS X, SQL

Tags: , , ,

There’s a macOS tool called AssetCacheLocatorUtil located at /usr/bin/AssetCacheLocatorUtil. The output is in… stderr. Because stderr is so fun to work with (note that sed -i only works with stdin). So, to update the caching server(s) you are using and only print the IP address of those, you’d do the following:

/usr/bin/AssetCacheLocatorUtil 2>&1 | grep guid | awk '{print$4}' | sed 's/^\(.*\):.*$/\1/' | uniq

If you use Jamf Pro and would like to use this as an extension attribute, that’s posted here: https://github.com/krypted/cachecheck. I didn’t do any of the if/then there, as I’d usually just do that on the JSS.

April 17th, 2017

Posted In: Mac OS X, Mac Security, Mass Deployment, Network Infrastructure, precache

Tags: , , , , , , , , , ,

April 6th, 2017

Posted In: MacAdmins Podcast

Tags: , , , , , ,

Next Page »