Oded Lazar

I code during the day, and think about the bugs I created at night.

I’m travelling a lot with my laptop, and having an accurate weather forecast on-the-go is very convenient.

I’m using Fedora as my main (and only) OS, along with i3wm and polybar. Previously I used GNOME 3 which had a few weather widgets. The most feature-rich was OpenWeather, which worked pretty well.

polybar doesn’t have a native weather widget and the one’s at x70b1/polybar-scripts suffered from the same drawbacks that OpenWeather did: location had to be manually specified or was ip-geolocation based (which is not accurate enough)

How do I get an accurate location without a GPS? WiPS to the rescue!

Wi-Fi Positioning System

Did you ever notice that you can get accurate location data when your GPS is turned off? The trick is to measure Wi-Fi signal intensity in order to triangulate your location.

Google, for instance, tracks open access points when you walk around and upload these along with your GPS location. When your GPS is turned off, they can use the access points around you to calculate your GPS coordinates. Cool right?

But how the heck do I get the wireless interfaces? well, there’s /proc/net/wireless for that -

import redefget_wireless_interfaces(): iface_rx = re.compile('^(.*): ')# I love one-liners. Hope that doesn't look like perl :)# - open() returns a read-only file wrapper that is iterable# - map() executes re.match() on each line returned from open()# - 'yield from' is used to delegate the generator were creating to another generatoryieldfrom (m.group(1) for min map(iface_rx.match, open('/proc/net/wireless'))if m)

Now, I need to to run iw. Running system commands from python is a pain in the ass.unless you use the mighty sh package, that is!

You are not a “Java Developer”.You are a Software Developer who is capable of writing software in Java.

You don’t want to hire people that call themselves “Java Developers”.You want to hire devs that either have extensive knowledge in Java (and are also good software developers), or hire superb developers that don’t, but can close the gap quickly.

Java, or any other language for that matter, is just syntax. Learning a language is a long process, which consists of:

Understanding how to write good software with it

Understanding How the language works under the hood

Understanding What are the language’s limitations

Understanding which problems are good to solve with it, and more importantly - which aren’t.

Learning the eco-system: libraries, tooling, etc’

I can’t stress that enough.

The language does not define you. What does?

Your ability to make the right architectural decisions

Your ability to take responsibility for your work

Your ability to grasp new ideas

Your ability to learn new languages & technologies quickly

Your passion for software crafstmanship & understanding that you have to constantly learn in order to be good at it.

You don’t want to be an “X Developer”, because that means that you are only expected to know X. IMO, that means that you have only one tool in your toolbox which you use to solve every problem.

You want to learn new languages, new operation systems, new tools, new techniques.Each one teaches you new ways to reason about & solve problems.

Java is very good language for a given set of problems. It’s a very bad language for others. Furthermore, Java has it’s own view on how to solve problems. Haskell, for example, look at & solves problems in a completely different way.

The “I’m an X Developer” kind of people look at (and reason about) problems from the wrong angle. Instead of looking at a problem and searching for the right tool to solve it, They use the tools they feel comfortable with in order to solve it.

Don’t get me wrong, being proficient in a specific domain (which might be a language and its ecosystem) is important, but the domain does not define you and you should not limit yourself to only one.

The way I see it, there is no such thing as a “Java Developer”, there’s a developer that is proficient in Java. This subtlety is important.

Then, change my BIOS configuration to boot up in UEFI mode and boot it up.

Convert parition table to GPT

I got the LiveUSB installed on a company thumb drive. Now I need to convert my paritition table from dos to GUID (GPT).

This step is rather simple. I Used gdisk:

# shouldn't require a password$ su$ gdisk /dev/your/device# gdisk will now prompt that it wants to convert the partition table.# press 'w' to save and you're done.

Free up space

I actually had another OS installed at the beginning of the partition table which I didn’t use anymore, so I just deleted it and recreated a new one from the LiveCD.

If you don’t have one, install GParted and use it to free up ~10gb at beginning of the partition table.

Why 10GB? well, instead of trying to figure out how to install UEFI correctly, I decided to install another Fedora instance and delete it once I’m done. That way I know for sure everything will work correctly.

Ok, so now - install Fedora. It should prompt you to create an EFI partition. Create a 1GB partition at the beginning, and use the rest for the new Fedora installation.

Update GRUB

Installed? Yay. Now reboot. Don’t worry, you won’t see your “old” Fedora installation on boot. Get it your new shiny installation, but don’t get too attached, we’ll destroy it in a few minutes!

Instead of just explaining how databases work, He incrementally builds a database from scratch. He goes over most database essentials, so once done you’ll be able to understand how databases actually work. If you haven’t taken any database courses at Uni, this is a must in my opinion.

The series is built around a “book keeping’ system. The problem? We need to keep track of users and how often they log into the system

He begins at persisting the data to a simple csv file, and then raises issues with this solution. The next part in the series addresses those issues and raises new ones: from selection time, concurrency, durability, logging and more.

Each part builds upon the previous and most parts take around 5 minutes to read.The series is made up of 20 parts and takes ~ 1.5hrs to read from start to finish. Not so bad, right?

C++ is a big language that has evolved tremendously since it’s inception way back in the 1980’s.

Throughout the years, many million lines of code have been written in the language and a big portion of that code is using legacy features that aren’t considered good practice anymore.

Replacing C++?

There were many attempts to replace the lanaguage. All of them failed as far as I know.

Some attempts were made to subset the language in order to get rid of code & language dept, which hurt speed and portability.

The most recent hype is around rust, which is a blazing fast, memory safe systems programming language. I see a promising future for rust, and I’m actually learning it myself. But like Bjarne said in his talk Writing Good C++14, it would take ~10 years for a good language to make it to the mainstream.

C++ is already here. We need to find a way for people to write good C++ now.

Subset of Superset

Simply sub-setting the language won’t work. This is backed by previous, failed, attempts. In order to maintain the speed of C++ we need the low-level / tricky / close-to-the-hardware / error-prone / expert-only features. Those feature are the building blocks of for higher-level facilitiese & libraries.

Bjarne talked about the subject at CPPCon a few years back:

Bjarne said we first need to create a superset of the langauge, then subset it in order to get rid of the crud. In order to do so, we need supporting facilities to make the transition: from guidelines on how to write modern C++, to libraries that enpasulate the usage of messy & dangerous things so most programmers won’t need to use them.

What is Modern C++

What is modern C++? Put simply, C++ that is based on C++1x and uses modern best practices.

To really grasp the essence of Modern C++, read the Core Guidelines. But nobody does that right?

C++ Seasoning

The talk takes a look at many of the new features in C++ and a couple of old features you may not have known about. With the goal of correctness in mind, Sean shows how to utilize these features to create simple, clear, and beautiful code.

Sean also gave another talk on the subject at Amazon’s A9 Programming Converstaions course.

Writing Modern C++

These are my do’s and don’ts regarding modern c++. There are also other things I do in order to make sure my project’s are written well:

Use CMake to build your project

Use memcheck to detect memory leaks

Run fuzzers to validate input

and more …

[!] Are you using a package manager? please let me know.

Follow Well-Known Guidelines

First, follow C++ Core Guidlines. You don’t need to actually read it, there are tools like Clang-Tidy that have the core guidelines pre-baked. Once you get a warning please go ahead and read the whole guideline. It’s important to understand Why the guideline exists.

Second, consider following well-known coding conventions and guidelines. On many occasions you can find tooling that help you follow guidelines created by big projects / corporations.

Use Popular Libraries

Compiler Flags

Turn on warnings, and preferebly warnings as errors. I usually turn on Wall and Werror. They are anoyying, but a neccessery evil IMO.

RAII

A few days ago I watched a talk called “Modernizing Legacy C++ Code” where they suggested to use RAII everywhere:

I’m not suprised, I’m a huge fan of RAII. Not only it makes code cleaner, thus reducing bugs and memory leaks, it also has an extremely low performance impact (compared to golang’s defer, which is used for the same purpose)

If Your’e interfacing C code, consider creating a scope guard. I use my home-baked defer-clone for that purpose.

Const-Qualify Everything

On “Modernizing Legacy C++ Code” they also talked about using const everywhere. At first it sounded weird, but it actually made a lot of sense once they showed a few examples:

This is a rolling release. That is, I’ll keep updating this post with new insights.

I have this “I don’t know anything about programming” feeling every time I watch a Rich Hickey talk.Sean’s C++ Seasoning (then Programming Converstaions #1 & #2) made me feel the same.His talk reminded me, again, that I have a lot to learn.

One of the key points of his talk is that developers need to be familiar with the algorithm library,and be able to extend it. During his talk, He magically transformed a few-dozen-lines of complex code into two, using <algorithm>.

I’m used to seeing python code refactoring that turn huge pieces of code into a few, which are easy to read and reason about. But in C++? wow.

Anyway, one of my takeaways is that I don’t use <algorithm> enough. It’s time to change that.

The gist is that sudo is hard to configure and does a lot more then the standard user needs. doas was created in order to replace sudo for regular folks like me and you.Moreover, sudo lacks ‘blacklist’ behaviour which is extremely useful at times.

doas is relatively easy to configure, and an absolute joy compared to sudo. It’s also powerful enough for most daily use-cases.IMO, the permit / deny concept of doas is so powerful that it’s enough to make the switch.

Implementing doas from scratch

The problem was that doas was written for OpenBSD.I’m not running OpenBSD, so I looked around for a port.

All ports I found were half baked and poorly written.

Then I looked at the original source code, and decided I’m not going to port it.

Why? because it’s written in C, and I really don’t want to maintain C code.Furthermore, the original code base lacked feature I introduced in runas which I really loved.

Instead, I decided to start this project. A complete re-implementation of doas.

This is my first attempt at writing a production quality, open source project from scratch.

I’m not there yet, but I’m determined on pushing this project into the main repositories of both ubuntu and fedora. More work has to be done in order to get there. for instance: Adding system tests & Getting the code audited.

Feel free to reach out if you want to contribute!

Project Goals

Secure. User’s shouldn’t be able to abuse the utility, and it should protect the user from making stupid mistakes.

Easy. The utility should be easy to audit, to maintain, to extend and to contribute to.

Friendly. Rule creation should be straight forward. Rule should be easy to understand and easy to debug.

Powerful. Rules should be short, concise and allow find-grained control.

Feature Parity. This project should have complete feature parity with the original utility.

To achieve these goals, the following design decisions were made:

The whole project was implemented in modern C++.

Explicit is better then implicit (for instance, rule commands must be absolute paths)

Prefer using the standard library when possible - for the sake of security and maintainability.

Commands are globs, which allows to use the same rule for many executables.

Getting started

You can also build from source. more information found at odedlaz/suex.

Changes compared to the original

Security checks

doas doesn’t check the owners & permissions of the binary and configuration file.sudo checks those, but only warns the user.

This version ensures the binary and configuration file are owned by root:root.It also ensures the binary has setuid, and that the configuration file has only read permissions.

Furthermore, only full paths of commands are allowed in the configuration file.The idea is that privileged users (i.e: members of the wheel group) need to explicitly set the rule instead of depending on the running user’s path.

Edit mode

suex -E

suex allows any privileged user (i.e: members of the wheel group) to edit the configuration file safely.Furthermore, if the configuration file is corrupted, privileged users can still access it and edit it.

The edit option is similar to visudo, it creates a copy of the configuration and updates the real configuration only when the copy is valid.

Non-privileged users are not allowed to edit the configuration.

Verbose mode

suex -V

suex allows to show logging information to privileged users. That information shows which rules are being loaded & how they are processed.

Non-privileged users are not allowed to turn on verbose mode.

Dump mode

suex -D

suex allows the user to dump the permissions it loaded to screen.group permissions and command globs are expanded into individual rules as well.

privileged users see the permissions of all users instead of only their own.

Examples

Ted Unagst’s wrote a great blog post called doas mastery. Because the project has complete feature parity with the OpenBSD version, the mentioned post should be a good starting point.

Never the less, there are some powerful enhancments in this release that deserve special attention.

Immediately after getting a file object with createFile, we defer the closing of that file with closeFile. This will be executed at the end of the enclosing function (main), after writeFile has finished.

Running the program confirms that the file is closed after being written:

But why do we need the excess [&]() { ... ; } part? and what is it anyway?[&] tells the compiler to pass all locals by reference, and () is used to indicate function args.We want this behaviour for allDEFER calls, so let’s put it in the macro:

Motivation

You must be thinking that I’m re-inventing the wheel. Well, I’m not. Let look at the following scenario:

There’s a binary that you want to run in a non-interactive session.

You want the binary to run with different permissions then the current user.

You don’t want the user to be able to run any binary with any permissions,only the one you want, with the requested user / group.

You don’t want a child process to get created, because you want to run the binaryas part of a filter without any other processes getting in the way.

A good example would be to debug an elevated app, while running your editor regularly. for example -> running gdb and debugging a binary as root.

You probably don’t want to turn on Set owner User ID because that’s a major security hole.You also can’t use su / sudo as part of your editor / IDE because they execute the target process as child, which causes many issues.

sudo is also somewhat complex to configure, and honestly, I prefer to avoid using it alltogether.

Solution

A tool that is easy to configure & runs the target binary with requested owner:group.runas is that tool. It does one thing, and (hopefully) does it well.

Notice I added /usr/bin/bash which is linked to /bin/bash.runas follows links to their source, to make sure the right binary is called.It also mimics the way shells parse commands so the configuration and command should be identical.

For instance, 'whoami && id' is concatenated by the shell into one argument.runas makes sure you don’t have to think about the way things get parsed.

Fine-grained permissions

runas uses c++ 14, which comes with a built-in ECMAScript flavored regex library.Using regular expressions can be really helpful when you want to have a lot of control over given permissions, which is still easy to understand..

A good example would be to allow the user to run only “readonly” operations on systemd units:

Why reinvent gosu?

gosu is a tool that was invented to solve TTY & signaling issues, mainly for containers.As I said before, sudo and su run the target process as a child, which means all signals are passed to them, and sometimes aren’t forwarded propely.gosu solves that issue, but doesn’t provide a permissions mechanism which makes it practically impossible to use on regular systems that need an extra layer security.

gosu is also written in Go, which is notoriously known for creating really big binaries:

1.23MB for the amd64 release

1.1MB for the i386 release

runas‘s binary takes only 200KB unpacked, and ~60KB when packed with UPX.

A few days ago I installed PulseSecure’s client to gain access to the corporate VPN.For reasons comepletely unknown to me, these guys are stuck in the past, providing only a 32bit client for linux. WTF.

Anyway, I got everything working with Open Connect so I could safely remove all 32bit dependencies I added to my system.

TL;DR: many parts of the system broke, but I got everything up and running after an hour or so.

There were only two things that stayed broken:

The date/time clock, which is usually centered at the top bar, moved to the right.

I had a window list bar stuck at the bottom of the screen.

I couldn’t find solutions to either. It seemed that everyone online were trying to move the clock to the right, not to the middle.Moreover, every time I tried to disable the Window List extension, it came back.

While trying to remove the extension, I found a small configuration file at /usr/share/gnome-shell/modes called classic.json, with the following content: