linux_course_doc/modules/resources/solution_raspberrypi.md

272 lines
10 KiB
Markdown

# The FTP challenge
## Getting the file
The first step to solving this exersise is to download the CSV file to your Raspberry.
For those wondering what on earth a CSV file is I invite you to a detailed [read](https://en.wikipedia.org/wiki/Comma-separated_values) but to make a long story short it stands for *comma separated values* and is one of the most basic ways to structure data.
You can use Libreoffice calc to open it and you'll quickly understand how it works.
Now, to get the file onto our Raspberry PI we need to download it from the webserver.
One way would be to use the `wget` program to do so.
We know *where* the server is by it's IP address, plus we also know the *filename*.
Putting these two together we can construct the following line.
```bash
wget 172.30.6.96/accounts.csv
```
This will download the file to the directory we're in and will save it as `accounts.csv`.
You can change the output filename it you want, just have a look at the `wget` options via `wget --help` or our trusty `man wget`.
## Extracting the data we need
A quick `cat accounts.csv` gives us the following output:
```bash
EMAIL,LASTNAME,FIRSTNAME,MATRIX,GITEA,TEAM
1h.lust.hugo@gmail.com,Lust,Hugo,@hugo_lust:86thumbs.net,https://gitea.86thumbs.net/Hugo,red
ticus@kraland.net,krstev,vladimir,@vl4dd:86thumbs.net,https://gitea.86thumbs.net/vl4dd,blue
adamd@outlook.be,Adam,David,@adamd73:matrix.org,https://gitea.86thumbs.net/adamd,red
nicohawai@gmail.com,Perez,Nicolas,@hawai:86thumbs.net,https://gitea.86thumbs.net/Hawai,blue
nicolas.wattripont@gmail.com,Wattripont,Nicolas,@wawa142:86thumbs.net,https://gitea.86thumbs.net/wawa142,red
laurentdelvigne@hotmail.com,Delvigne,Laurent,@ldelvigne:86thumbs.net,https://gitea.86thumbs.net/ldelvigne,blue
sselcukaslan@gmail.com,Aslan,Selçuk,@slck:86thumbs.net,https://gitea.86thumbs.net/selcuk,blue
Sarah24886@hotmail.com,Rmiki,Sarah,@sarahrm95:matrix.org,https://gitea.86thumbs.net/sarahrm95,blue
knoppixs@hotmail.com,Abbamoulay,Abdellah,@knoppixs:86thumbs.net,https://gitea.86thumbs.net/Abdellah,red
JonathanDechief@hotmail.com,Dechief,Jonathan,@elewene:matrix.org,https://gitea.86thumbs.net/Elewene,red
51207@etu.he2b.be,,Aliou,@aliou:86thumbs.net,https://gitea.86thumbs.net/aliou,blue
```
### The $USERNAME
To extract the `$USERNAME` we're interested in the fourth collumn which has the MATRIX login handle.
We can extract only this collumn by using `cut` with `,` as a delimiter.
```bash
cat accounts.csv | cut -d "," -f 4
```
This leaves us with only the MATRIX login handles which is a good start but there is still a bit too much information .
We need to drop the first line, which is the *header* of the CSV file, plus crop between the `@` and the `:`.
These two operations can be done is multiple ways but I suggest this modification.
It is not the most elegant solution but it uses only tools you have used this far.
The `tail` command drops the *header* line, and the two `cut` commands trim the username to just what we need.
```bash
cat accounts.csv | cut -d "," -f 4 | tail -n +2 | cut -d ":" -f 1 | cut -d "@" -f 2
```
Done!
We have all the usernames we need.
We can save this to a file by redirecting the STDOUT to a file with the following command.
```bash
cat accounts.csv | cut -d "," -f 4 | tail -n +2 | cut -d ":" -f 1 | cut -d "@" -f 2 > usernames.list
```
### The $PASSWORD
To extract the password we need to combine two field from the CSV file.
A *really* good command line program to accieve this is `awk`.
Don't forget the man pages!
```bash
cat accounts.csv | awk -F "," '{print $2 $3}' | tail -n +2
```
If you feel like making the password complexer, you can try to add in extra data into the `awk` command, or even append random numbers to the end.
```bash
cat accounts.csv | awk -F "," '{print $2 "_helloworld_" $3}' | tail -n +2
```
We can now save these passwords to a file in the same way as before.
### The $GROUP
This is an *easy* one because it requires no real modification of the field.
```bash
cat accounts.csv | tail -n +2 | cut -d "," -f 6 > groups.list
```
## Using this information to create accounts
We now have command that extracts the information we need, plus three separate files that contain all the information.
This is a good moment to try and write a very simple script.
I'll first try to do it without a loop but you'll quickly see it's a *lot* easier with a loop in there.
Remember that `$1` represents the first argument on the command line so that when calling our script with `./script.sh 3` we'll get the username, password and group for the third user.
A combination of `head | tail` is a [classic](https://stackoverflow.com/questions/6022384/bash-tool-to-get-nth-line-from-a-file) way of selection only one file from a file.
Last but not least, don't forget to add execution permissions to this script with `chmod`.
```bash
#!/bin/bash
LINE=$1
head -$1 usernames.list | tail -1
head -$1 passwords.list | tail -1
head -$1 groups.list | tail -1
```
We can then *copy/paste* this information to create the following line.
We'll be prompted to paste in the proper information.
```bash
sudo adduser $USERNAME
```
Needless to say this is a labour intensive operation that we can automate with a mini script.
### Putting it together as a script
Brace yourselves a bit but I promise it's worth it!
The only thing we have not seen is how to save the output of a command into a variable.
This can be done with the `$(...)` syntax.
I know it looks a bit cryptic but an example speaks more than words.
```bash
NOW=$(date)
echo $NOW
```
With this in mind, the following code should make sense.
We're doing the exact same thing but saving the output of each command into a variable.
At the last line we *use* the variables to create a message.
```bash
#!/bin/bash
LINE=$1
USERNAME=$(head -$1 usernames.list | tail -1)
PASSWORD=$(head -$1 passwords.list | tail -1)
GROUP=$(head -$1 groups.list | tail -1)
echo "user: $USERNAME password: $PASSWORD group: $GROUP"
```
This just output's all information onto one line, but why not *use* this information to actually create the accounts?
A counterpart to the `adduser` program you're used to using, there is also `useradd` which is better suited for scripting purposes.
By default `useradd` is very *barebones* and does not create a home directory for the user but a quick look at the `man useradd` pages tells us we can use the `-m` flag to do so.
This tells us the the command `useradd $USERNAME -m` will create a user for us with his/her own home directory.
A [google search](https://linux.die.net/man/8/chpasswd) pointed me to `chpasswd` to set passwords from within a script.
The line to set the password will be `echo $USERNAME:$PASSWORD | chpasswd`.
This gives us the following script.
```bash
#!/bin/bash
LINE=$1
USERNAME=$(head -$1 usernames.list | tail -1)
PASSWORD=$(head -$1 passwords.list | tail -1)
GROUP=$(head -$1 groups.list | tail -1)
echo "adding user: $USERNAME"
useradd $USERNAME -m
echo "setting password: $PASSWORD for $USERNAME"
echo $USERNAME:$PASSWORD | chpasswd
```
You probably noticed I did not add the users to their *red/blue* groups.
We can add them on the `useradd` line with the `-G` flag but it would fail if the group does not exist yet.
The `groupadd` command will add a group to the system and if we add the `-f` flag to it will do so without complaining if the group already exists.
This way we can just execute that line each time without worrying wether the group exists or not.
```bash
#!/bin/bash
LINE=$1
USERNAME=$(head -$1 usernames.list | tail -1)
PASSWORD=$(head -$1 passwords.list | tail -1)
GROUP=$(head -$1 groups.list | tail -1)
echo "making sure $GROUP exists..."
groupadd -f $GROUP
echo "adding user: $USERNAME"
useradd $USERNAME -m -G $GROUP
echo "setting password: $PASSWORD for $USERNAME"
echo $USERNAME:$PASSWORD | chpasswd
```
Those who switched to the newly created user noticed that the shell is *very* basic one.
You can find out which shell these new accounts use by looking at the `/etc/passwd` file.
There are multiple ways to sort this problem but a look at the `man useradd` pages tells us we can use the `-s` flag to set the shell we want for the user.
We probably want to use `/bin/bash` for this option!
```bash
#!/bin/bash
LINE=$1
USERNAME=$(head -$1 usernames.list | tail -1)
PASSWORD=$(head -$1 passwords.list | tail -1)
GROUP=$(head -$1 groups.list | tail -1)
echo "making sure $GROUP exists..."
groupadd -f $GROUP
echo "adding user: $USERNAME"
useradd $USERNAME -m -G $GROUP -s "/bin/bash"
echo "setting password: $PASSWORD for $USERNAME"
echo $USERNAME:$PASSWORD | chpasswd
echo "adding $USERNAME to $GROUP"
```
This is getting pretty close to perfect!
We can now run through all of the lines of the file one by one and automatically create the proper user, password and group combinations.
To know how many accounts we have to create we can use `wc -l accounts.csv` and then just run the script, incrementing the number each time.
```bash
sudo ./script.sh 1
sudo ./script.sh 2
sudo ./script.sh 3
echo "etc..."
```
### Taking it further as an extra challenge
If we want to automate the entire thing we'll need a loop to *loop through* every line in the `accounts.csv` file.
Bash loops are for a further class but I'll leave you with this quick example for those who feel like messing around.
Remember the *oneliners* we constructed at the beginning to extract the relevant information from the line!
Don't worry if this looks to complicated at the moment, we'll do this exersise again when we're looking into [bash scripting](https://ryanstutorials.net/bash-scripting-tutorial/).
```bash
#!/bin/bash
FILE=$1
LINES=$(cat $1)
for LINE in $LINES;
do
echo $LINE
done
```
## Setting up the fileserver
### FTP
A quick [google](https://likegeeks.com/ftp-server-linux/) tells us `vsftpd` is a popular *FileTransferProtocol* server.
As expected you can find it in the main Debian repositories.
You know how to install it by now!
```bash
sudo apt search vsftpd
```
To know *where* to configure the server we can look at the `man vsftpd` pages.
Scroll all the way to the bottom to see which files it uses to configure itself.
The configuration file itself is very *verbose* and should explain itself.
### SFTP
TODO