Kristoffer Qvists blogg om allt möjligt

Kategori: Programmering

Säkerhet och publicitet – mina tankar

Jag lyssnade för ett tag sedan till en video från YouTube-kanalen Chris Titus Tech som fångade mitt intresse. Själva videon handlade om en säkerhetsforskare som publicerade en s.k. zero-day-bugg som fanns i fönsterhanteraren KDE. Själva buggen patchades inom 24 timmar. Säkerhetsforskaren publicerade säkerhetshålet publikt, antingen utan eller samtidigt som han tog kontakt med utvecklarteamet.

Enligt mig, och även kanalens huvudperson, så var det inte ett jättebra beslut. Framförallt handlar det om att forskaren inte gett utvecklarna tid att täppa till säkerhetshålet innan informationen gjordes publik.

Jag anser att utvecklarna bör få en chans att fixa en patch till säkerhetshålet som uppdagades. Detta innan publikation om fyndet. Jag anser att det handlar om att minimera risken att säkerhetshål inte ska kunna användas av (ondsinta) personer och/eller organisationer så länge säkerhetshålet finns. Det finns andra som (tyvärr) inte riktigt håller med denna åsikt.

Jag tycker att det är i allas intresse att säkerhetshål täpps till snarast möjligt. Samtidigt anser jag att när dessa uppdagas att utvecklaren av mjukvaran uppmärksammas på det privat, via ett meddelande eller e-post. Då minimeras risken att potentiellt ondsinta personer och organisationer får kännedom om sårbarheten innan den är åtgärdad, och därmed ökar risken för att dessa utnyttjar den. Jag säger inte att det är en garanti för att sårbarheterna inte kommer att användas, däremot tänker jag att färre ondsinta personer blir medvetna om det och därigenom blir det färre som riktar illasinnad kod mot sårbarheten.

Lägga till arkivsida i Grav

Eftersom detta är en blogg är det för mig naturligt att man har en så kallad ”arkivsida”. I denna kan man visa då samtliga inlägg skrivna en viss månad eller ett visst år. Det finns ett plugin till Grav som gör detta, men denna är inte automatiskt igång. Det finns förstås färdiga skelett som kommer med mycket färdiggjort, men väljer man däremot att skräddarsy sin sajt med enbart det man behöver bör man ha lite kunskap inom PHP, HTML och Twig.

Mitt inlägg är inspirerat av Bszymans inlägg, som behandlar just detta ämne. Även om pluginet har viss dokumentation på deras Github-sida, är den inte riktigt fullständig. Jag vill också lägga till vissa punkter som jag upplever att båda saknade.

Mål och förklaringar

Målet med detta är att skapa en arkivsida som kan användas i bloggen. Det andra målet är att bloggen skall kunna använda sig av en URL som är mer snarlik en svensk URL än en engelsk. Dock kan man välja att ha kvar de engelska kategorinamnen och ändra arkiv-urlen till engelska om man upplever att det skulle fungera bättre för sin blogg.

Jag använder mig av vissa ord och uttryck i nedan text, nedan finns dessa förklaringar:

  • grav-root Mapp/katalog där Grav är installerat
  • _temanamn Då alla teman heter olika, är det tänkt att detta skall vara samma tema du som läser använder

Välj tema som stödjer arkiv

För att minimera den tid som man behöver skräddarsy sin sajt, rekommenderar jag att man använder ett tema som stödjer arkiv-funktionen. Samtliga teman går att hitta på Gravs hemsida.

Installera och modifiera plugin

Själva pluginet kan installeras via kommandoraden, om man är under grav-root, skriver man bin/gpm install archives i kommandoraden. Pluginet kommer därefter att finnas under grav-root/user/plugins/archives. För att modifiera pluginet ändrar man i grav-root/user/plugins/archives/archives.yaml. Nedan visar jag ett exempel då man vill använda ”blogg” istället för ”blog” som kategori för blogginlägg:

enabled: true
built_in_css: true
date_display_format: 'F Y'
show_count: true
limit: 12
order:
    by: date
    dir: desc
filter_combinator: and
filters:
    category: blogg
taxonomy_names:
    month: archives_month
    year: archives_year

Nu kan man även kopiera arkivinnehållet från plugin till temat. Det gäller att man kopierar filen grav-root/user/plugins/archives/templates/partials/archives.html.twig till grav-root/user/themes/_temanamn/templates/partials/archives.html.twig

Om temat inte har stöd för arkiv, kan nedan kodrad behövas läggas till i grav-root/user/themes/_temanamn/templates/partials/sidebar.html.twig

{% if config.plugins.archives.enabled %}
  <div class="sidebar-content">
    <h6 class="sidebar--heading">Archives</h6>
    <hr class="hr--small">
    {% include 'partials/archives.html.twig' with {'base_url':base_url_relative} %}
  </div>
{% endif %}

Modifiera sidfältet

För att ändra arkivfältet i själva sidfältet, modifiera filen grav-root/user/templates/partials/archives.html.twig. Ändra nedan kodrad

{{ base_url }}/{{ config.plugins... }}

till följande:

{{ base_url }}/arkiv/{{ config.plugins... }}

Modifiera mall och själva arkivsidan

Nu gäller det att dels skapa mallen för arkiv och själva arkivsidan. Först skapas mallen. Skapa filen grav-root/user/themes/_temanamn/templates/arkiv.html.twig. I denna skrivs sidans utseende. Nedan finns ett exempel på hur detta kan se ut:

{% embed 'partials/base.html.twig' %}

    {% block content %}

        <h1>Arkiv</h1>

        <div class="infinite-scroll columns small-12 large-8">
        {% for post in page.collection({'items':{'@taxonomy':{"category": "blogg", "archives_month": uri.param("archives_month")}}}) %}
            {% include 'partials/post-item.html.twig' %}
        {% endfor %}

        {% if config.plugins.pagination.enabled and collection.params.pagination %}
            {% include 'partials/load-more.html.twig' %}
        {% endif %}

        </div>

        <div class="sidebar columns large-4 show-for-large">
            <div class="sidebar--inner">
                {% include 'partials/sidebar.html.twig' with {'blog':page} %}
            </div>
        </div>
    {% endblock %}

{% endembed %}

Mallen säger åt systemet att dels hämta sidans utseende, men också att hämta sidofältet. För att använda mallen i en sida måste denna sida nu skapas. Skapa mappen grav-root/user/pages/arkiv och filen grav-root/user/pages/arkiv/arkiv.md. Fyll i nedan innehåll i filen arkiv.md

---
content:
items:
    "@page.children": "/blogg"
---

Nu bör det finnas en fungerande arkivsida på sajten. Det finns förmodligen sätt att få den sidan ännu bättre, men sidan ser redan nu väldigt bra ut.

Lägg till stöd för logotyp i WordPress

Ibland kan man behöva modifiera WordPress efter ens egna behov, och då kan det handla om att ”gräva ned sig” i koden för att göra ändringarna. Ett exempel kan vara när man vill lägga till en logotyp till ett tema som inte redan stödjer detta. För min egna del krävde detta lite ”trial-and-error”, men till slut så fick jag kläm på det hela. Inlägget kommer att visa hur man gör det i en vanlig

För att exemplet nedan skall fungera krävs minst WordPress 4.5.

Till att börja med bör man modifiera filen functions.php, och detta kan man göra direkt i webbläsaren om man inte råkar ha en mer ”låst” installation, via redigeraren som man kan finna under fliken ”Utseende”. Därifrån väljs filen functions.php, i länken kan det stå Temafunktioner.

I funktionen function tema_setup() (där tema står för ditt aktiva tema) lägger du till följande kodsnutt:

add_theme_support( 'custom-logo', array(
	'height'      => 100,
	'width'       => 400,
	'flex-height' => true,
	'flex-width'  => true,
	'header-text' => array( 'site-title', 'site-description' ),
) );

Därefter läggs kodblocket nedan efter add_action( 'after_setup_theme', 'tema_setup' ); där tema återigen står för det aktiva temat.

function tema_the_custom_logo() {
	if ( function_exists( 'the_custom_logo' ) ) {
		the_custom_logo();
	}
}

Nu är vi nästan klara. Det som krävs nu är att lägga till funktionen tema_the_custom_logo(), eventuellt inom php-taggar, där vi vill ha loggan.

Om loggan behöver centreras, kan detta göras genom att lägga till följande kodblock i stilmallen style.css.

.custom-logo {
	display: block;
	margin-left: auto;
	margin-right: auto;
}

Förmodligen kommer min lösning inte att fungera som ”handen i hansken” för alla, men jag önskar att den vägleder dem som undrar hur man ska sätta upp en logotype till sin sida. Som jag själv skrev tidigare, så var det inte självklart för mig till en början. Men efter lite lekande med koden, så gick det vägen med att få sidan att visa loggan som jag ville.

Egentligen är ”best practice”, eller praxis, att skapa ett så kallat ”child theme”. I och med att syftet med detta inlägg enbart är att visa hur man kan gå tillväga, så ansåg jag att det inte behövdes i inlägget eftersom att det finns en risk för att inlägget blir mer komplicerat än vad det behöver vara.

Skapa användare med PowerShell

PowerShell är ett kraftfullt verktyg i Windowsmiljön. Med detta skriptspråk kan man göra mycket administrativt arbete, bland annat skapande av användare vilket detta inlägg kommer att gå igenom. Lösningen som kommer att visas här kanske inte passar alla, däremot skall den skapa unika användare i domänen och även skapa ett engångslösenord. Lösenordet sparas med användarinformationen i den aktuella administratörens dokument-mapp. Jag publicerar skriptet här med förhoppningen om att den skall vara intressant och ge en fingervisning i hur man kan skapa användare för de som behöver det.

Alla användare skapas så att deras användarnamn består av de två första tecknen i för- och efternamnet. Heter man Sven Svensson blir alltså användarnamnet svsv. Skulle flera användare få ett likadant användarnamn adderas ett nummer till slutet, så om två Sven Svensson finns blir en svsv och den andra svsv2, på samma sätt adderas en siffra om fler personer skulle heta likadant. Då protokollet LDAP – vilket Active Directory använder sig av – kräver en unik identifierare (Distinguished Name) kan detta skript generera 26 + 1 sådana.

För att skriptet skall fungera bör följande saker finnas;

  • Windows Server med Active Directory
  • En csv-fil innehållande användare

Csv-filen skall eller kan innehålla följande värden:

  • Förnamn
  • Efternamn
  • Stad i vilken användaren finns
  • Avdelning i vilken användaren jobbar
  • Roll (valfritt)

För att exemplifiera csv-filen med två användare, kan det se ut på följande sätt:

Firstname;Lastname;Department;City;Role
Sven;Svensson;IT;Göteborg;Manager
Rut;Johansson;HR;Göteborg

Vad gäller skriptet och csv-filen måste dessa sparas i utf-8 format för att åäö skall visas korrekt. I normala fall sparar program såsom exempelvis Notepad filer i ASCII, som inte innehåller vissa svenska tecken. Istället visas ett tecken som kan liknas vid en romb med ett frågetecken inuti.

Skriptet kommer att spara en användare i example.com/Example/Stad/Avdelning/. Här kan förstås ordet Example bytas ut till namnet på den organisation det gäller.

############## METADATA ############## 
# AUTHOR: KRISTOFFER QVIST
# LICENCE: Apache Licence, v.2
# GOALS:
# * Check that new users actually are
#   unique within domain,
# * Assign unique email-addresses
# * Check for duplicate names within
#   an OU to correct these.
#####################################
 
param([string]$csvfile= [Environment]::GetFolderPath('MyDocuments') + "\thisFile.csv")
 
Import-Module ActiveDirectory
 
while((Test-Path -Path $csvfile) -eq $false) {
    $csvfile = Read-Host "Please, fill in the correct path to the .csv file"
}
 
$users  = Import-Csv -Delimiter ";" -Path $csvfile
 
foreach ($user in $users) {
    $fname      = $user.Firstname
    $fname      = $fname.Trim()
    $sname      = $user.Lastname
    $sname      = $sname.Trim()
    $dplName    = $fname+" "+$sname
    $domain     = "@example.com"
    # Get first two letters of firstname
    $samf       = $fname.substring(0,2)
    # Get first two letters of lastname
    $saml       = $sname.substring(0,2)
    $sam        = $samf+$saml
    $sam        = $sam.ToLower()
    $department = $user.Department
    $city       = $user.City
    $role       = $user.Role
 
    # The user should be added here
    $OU = "OU=$department,OU=$city,OU=Example,DC=example,DC=com"
    $dn = "CN=" + $dplName + "," + $OU
 
    # Place to store groups in
    $GroupOU = "OU=Groups,DC=example,DC=com"
 
    # Check if the OU exists, otherwise create it
    $LDAPOU = "LDAP://" + $OU
    $OUexists = [adsi]::Exists($LDAPOU)
 
    if ($OUexists -eq $false) {
        dsadd ou $OU
    }
 
    # Generate random password 8-byte password
    $length   = 2 # length x 4 equals the password length 
    $password = ""
    $chars    = "ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrtuvxyz".ToCharArray()
    for($i=0; $i -lt $length; $i++) {
        $password += $chars | Get-Random
    }
 
    $chars2 = "0123456789!#%/()".ToCharArray()
    for($i=0; $i -lt $length; $i++) {
        $password += $chars2 | Get-Random
    }
 
    for($i=0; $i -lt $length; $i++) {
        $password += $chars | Get-Random
    }
 
    for($i=0; $i -lt $length; $i++) {
        $password += $chars2 | Get-Random
    }
 
    # Create a clean email address (e.g. from Åsa.Lindén to asa.linden)
    $eaddress    = $fname.ToLower() + "." + $sname.ToLower()
    $eaddress    = $eaddress -replace "é","e"
    $eaddress    = $eaddress -replace "å","a"
    $eaddress    = $eaddress -replace "ä","a"
    $eaddress    = $eaddress -replace "ö","o"
 
    $email = $eaddress + $domain
 
    $emailExists = Get-ADUser -Filter { EmailAddress -like $email }
    $emailBase   = $eaddress
    $i = 2
 
    while ($emailExists -ne $null) {
        $email = $emailBase + "." + $i + $domain
        $emailExists = Get-ADUser -Filter {EmailAddress -like $email }
        $i++
    }
 
    # Create clean login name
    $sam    = $sam -replace "é","e"
    $sam    = $sam -replace "å","a"
    $sam    = $sam -replace "ä","a"
    $sam    = $sam -replace "ö","o"
 
    # Check if the user sam exists in AD already
    $checkADUser = Get-ADUser -LDAPFilter "(SamAccountName=$sam)"
    $i = 2
    $baseSam = $sam
 
    # If user exist, add a number to the end
    while ($checkADUser -ne $null) {
        $sam = $baseSam+$i
        $checkADUser = Get-ADUser -LDAPFilter "(SamAccountName=$sam)"
        $i++
    }
 
    # Check that the user has a unique DN
    $DNExists = Get-ADUser -Filter {distinguishedName -eq $dn }
    $i = 0
    $letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
    while ($DNExists -ne $null) {
        $dplName = $fname + " " + $letters[$i] + " " + $sname
        $dn = "CN=" + $dplName + "," + $OU
        #Write-Host $dn
        $DNExists = Get-ADUser -Filter {distinguishedName -eq $dn }
        $i++
    }
 
    # And use it in user principal name
    $upn        = $sam+$domain
 
    # Check if the localisation group exists, otherwise create it
    try {
        Get-ADGroup -Identity $city | out-null
    } catch {
        New-ADGroup -Name $city -GroupScope Global -Path $GroupOU
        Write-Host "New group '$city' created"
    }
 
    # Check if the shadow group exists, otherwise create it
    $ADShadowGroup = "SG_" + $department
    try { 
        Get-ADGroup -Identity $ADShadowGroup | out-null
    } catch {
        New-ADGroup -Name $ADShadowGroup -GroupScope Global -Path $GroupOU
        Write-Host "New group '$ADShadowGroup' created"
    }
 
    # This file will hold the user login credentials
    $file = [Environment]::GetFolderPath('MyDocuments') + "\" + $sam + ".txt"
 
    # Add the user to AD
    New-ADUser -SamAccountName $sam -Name $dplName -GivenName $fname -Surname $sname -DisplayName $dplName -UserPrincipalName $upn -Department $department -City $city -EmailAddress $email -AccountPassword (ConvertTo-SecureString $password -AsPlainText -Force) -AccountExpirationDate $null -ChangePasswordAtLogon $true -Enabled $true -Path $OU -ErrorAction SilentlyContinue
 
    # Add the role as title
    if ( $role -eq $false) {
        $role = $role.Trim()
        if ($role -ne $null) {
            Set-ADUser -Identity $sam -Title $role -ErrorAction SilentlyContinue
        }
    }
 
    # Add the user to an their repective shadow and localisation group
    Add-ADGroupMember $ADShadowGroup $sam
    Add-ADGroupMember $city $sam
 
    # Create file
    New-Item $file -type file -force -value "Login credentials for $dplName
    Domain: $domain
    Login name: $sam
    One time password: $password" | out-null
}
 
Remove-Module ActiveDirectory

Kontrollera medlemskap av Shadow Groups

Shadow groups används i Active Directory (AD) för att enklare administrera olika konton som är; satta i olika s.k. Organizational Units, OU:n. Ibland flyttar man användare över OU:n, av olika orsaker, och detta skript gör det enkelt att kontrollera att varje användare tillhör rätt grupp och OU. För automatisk kontroll bör detta skript schemaläggas.

  • PowerShell är installerat
  • Alla grupper har SG_ som prefix

I skriptet finns alla grupper i example.com/Accounts/Groups/Roles, medan användarna finns i deras respektive OU i example.com/Accounts.

Modifiering av skriptet

Då skriptet är licenserat i enlighet med Apache-licensen version 2 (se länk till höger av sidan) kan du göra i princip allt du vill med det. För att ändra katalogen där grupperna existerar ska variabeln $groups modifieras vid flaggan -SearchBase, och $base till platsen där alla OU:n med deras konton existerar.

Om du undrar något över detta skript och/eller vill ha hjälp med det kan du skicka mig ett mail. Dock kan jag inte lova att jag kan svara på det direkt, och om jag finner det intressant att publicera på bloggen kan jag komma att göra det med tillhörande svar.

############ METADATA ############
# Author: Kristoffer Qvist
# Description: Control that
# correct users, in the
# corresponding OU are set to
# their correct shadow group.
##################################
Import-Module ActiveDirectory
$groups = Get-ADGroup -Filter{name -like "SG_*"} -SearchBase "OU=Roles,OU=Groups,OU=Accounts,DC=example,DC=com"

foreach ($group in $groups) {
    try {
        # This block adds users to their correct Shadow Groups
        $groupSAM = $group.SamAccountName
        $OU       = $groupSAM.Replace("SG_", "")
        $base     = "OU=$OU,OU=Accounts,DC=example,DC=com"
        $users    = Get-ADUser -Filter * -SearchBase $base -Properties DistinguishedName | Select -ExpandPropert DistinguishedName
        foreach ($user in $users) {
            Add-ADGroupMember -Identity $groupSAM -Members $user
        }

        # This block removes users from wrong Shadow Groups
        $groupMember = get-adgroupmember -identity $groupSAM
        foreach ($member in $groupMember) {
            $dgn    = $member.distinguishedName
            $thisOU = Get-ADUser -LDAPFilter "(samAccountType=805306368)" -SearchBase $base
            if ($thisOU -match $dgn) {
                # Nothing to be done ; $dgn should match $thisOU
            } else {
                Remove-ADGroupMember -Identity $groupSAM -Members $dgn -confirm:$false
            }
        } 
    } catch {
        "There was an error adding/removing an user to the correct OU or shadow group. ($group)"
    }
}
# It's good practice to remove the module used
Remove-Module ActiveDirectory

Bash-skript för att förflytta filer

Själv har jag haft behov av att förflytta filer mellan olika mappar i min Linux-dator. Då kan det vara skönt att använda sig utav skript som automatiserar förflyttningen helt och hållet (särskilt om man enbart har CLI). Det är skrivet i vanligt shellspråk (bash) och består av enbart några rader kod.

#!/bin/sh
############ METADATA ############
# Author: Kristoffer Qvist
# Description: Moves file(s) to
# predestined destination.
##################################

destination="/path/to/destination"

for file in "$@"; do
    mv "$file" "$destination/$file"
done

Filerna som skall förflyttas finns är argument som skrivs efter skriptnamnet; alltså skript.sh fil.a fil.b som gör att dessa (det vill säga fil.a och fil.b) förflyttas till vald destination, som har skrivits i variabeln ”destination”. Detta skript gör ingen felsökning, och jag tar inget ansvar för eventuella fel som kan inträffa (nej, inte heller förlust av tangentbord eller guldfiskar).

Skapa användare med Perl

Uppdaterat 2014.09.29, av Kristoffer

För ett tag sedan var jag tvungen att använda mig utav Perl för att generera användare och sedan ge dem ett tillfälligt lösenord som de kommer att få byta när de har loggat i. Systemet där skriptet användes är ett Linux-system (CentOS 6.5).

Skriptet matchar följande krav:

  • Ha stöd för utf-8
  • Läsa in för- och efternamn från en textfil
  • Skapa unika användare från textfilen
  • Skriva ut användarinformation till en ny textfil per användare, i en särskild mapp

För att kunna köra skriptet krävs modulen Text::Iconv, vilket kan testas genom att skriva perl -e 'use Text::Iconv;' i kommandotolken. Om du inte får ett svar, är modulen installerad. Om du får många felmeddelanden som svar, är modulen inte installerad. Hur man installerar moduler kan jag skriva om i ett annat inlägg, annars kan ni använda det ”gamla” sättet (vad gäller mitt skript) där icke-ASCII-tecken blir bytta till ett x. Eventuellt kan du kika på denna hemsida som förklarar hur man installerar ett verktyg som kan vara till stor hjälp i en CentOS-maskin, på engelska. Vidare står här hur man sedan använder verktyget för att installera modulerna.

Om du undrar över något, går det att skicka in ett mail till mig, så ska jag försöka svara så fort jag kan. Eventuellt, om det är flera som frågar, kan jag publicera svaren här i detta inlägg eller någon annanstans på hemsidan. Dock kommer skriptet inte att kontrollera om användaren lägger till mer input än vad som behövs.

För att få denna kod att vara såpass internationell som möjligt, används engelska kommentarer och variabelnamn.

#!/bin/usr/perl
#############METADATA############
# Author:	Kristoffer Qvist
# Version:	2
# Last
# Modified:	Sep 29th, 2014
# History:	Made utf-8 to
# 		ASCII converting
#		better.
#################################

use warnings;
use strict;
use Text::Iconv;

binmode STDOUT, 'utf8';

# Get file that contains users
my ($file, $userDir) = @ARGV;

while(not -e $file) {
    print("Please, add a valid file containing your users.\n");
    chomp($file = <STDIN>);
}

while(not -e $userDir) {
    print("Please, add a valid folder to store the user password files\n");
    chomp($userDir = <STDIN>);
}

# A basic check for script injection attempt
if($file =~ /;/ or $userDir =~ /;/) {
    die("Script injection attempt found!\n");
}

# Put all new users in array
open(USERS, "<", $file) or die("The file $file could not be opened: $!");
chomp(my @new_users=<USERS>);
while (<USERS>) {
    push (@new_users, $_);
}
close USERS or die($!);

# Get passwd content
my $passwd_file     = "/etc/passwd";
my $passwd_contents = open(PASSWD, "<", "/etc/passwd") or die("$!");
my @passwd;
while (<PASSWD>) {
    push (@passwd, $_);
}
close PASSWD or die("$!");

# Set all existing users in hash
my %existing_users = ();
for(my $i=0;$i<scalar(@passwd);$i++) {
    my @passwd_entry = split /:/,$passwd[$i];
    $existing_users{$passwd_entry[0]} = $i;
}

# Add users to the system and create a random one-time password
foreach my $new_user(@new_users) {
    my @names = split(/ /, $new_user); 

    my $fn = substr($names[0],0,3);
    my $ln = substr($names[1],0,2);

    my $username = $fn.$ln;

    # Converts non-ascii to x (old; latter converting is better)
    # $username =~ s/[^[:ascii:]+]/x/g; 

    # Encode usernames to ascii (new)
    my $convert_this = Text::Iconv->new("UTF-8", "ASCII//TRANSLIT");
    $username = $convert_this->convert($username);
    $username = lc($username);

    # Check for duplicate users, if found add number 
    my $i = 1;
    while(exists $existing_users{$username}) {
        $username =~ s/[0-9]//g;
        $username = $username.$i++;
    }
    $existing_users{$username} = $i;
    my $password = join'', map +(0..9,'a'..'z','A'..'Z','!?()""')[rand(10+26*2)], 1..8;
    `useradd $username -c "$new_user" &> /dev/null`;
    `echo -e "$password\n$password" | passwd $username &> /dev/null`;
    `chage -d 0 $username`;
    open (USERFILE, ">", "$userDir/$username.txt") or die("The file $userDir/$username.txt could not be opened: $!\n");
    print USERFILE "$new_user\n--------------------\n$username: $password";
    close USERFILE or die("The file $userDir/$username.txt could not be closed: $!\n");
}
print("\nBatch completed!\n");

© 2022 qvi.st

Tema av Anders NorenUpp ↑