giovedì 18 giugno 2009
Questa mattina la batteria del mio portatile (Dell XPS) è defunta. Estraendo la batteria e premendo il pulsante di controllo della carica non si accende nessun led. La diagnostica del bios e quella su chiavetta USB indicano che la batteria è difettosa.
Avendo una assistenza a copertura totale (Premium Hardware Support), chiamo per avere una sostituzione. La batteria ha una garanzia di solo un anno che naturalmente è appena trascorso (due mesi fuori).
A questo punto vado sul sito per un acquisto e il tempo di arrivo è di ben 10 giorni.
Ma l'assistenza "Premium Hardware Support" non dovrebbe garantire un servizio al cliente per evitargli di doversi comprare un notebook di riserva?
Batteria fuori garanzia? Mi sta anche bene se te ne anticipano una e poi la paghi se verifichi che sia effettivamente quella la vera causa del problema.
Oltre a questo va detto che il guasto è sull'elettronica della batteria e non sulle celle. Quindi si tratta di guasto e non di pezzo esausto (considerato che la garanzia della batteria viene limitata a un anno con la scusa che si tratti di un 'consumabile').
Dell invece ha scelto di tirare il pacco al cliente e mollarlo per la strada. Meditate gente, meditate.
domenica 14 giugno 2009
Come molti sapranno al recente workshop UGIdotNET tenutosi a Predappio ha esordito il mio SurfRaf. Per chi vuole subito vederlo all’opera ecco i video girati da Corrado a Predappio e dal sottoscritto oggi:
Video 1: com’è fatto
Video 2: come funziona parte 1
Video 3: come funziona parte 2
Per chi fosse andato per un annetto in antartide :), Microsoft Surface è un dispositivo (equipaggiato con Vista) che permette di usare diverse applicazioni con le sole “gesture” ossia muovendo con le mani gli oggetti disposti sullo schermo.
Surface è venduto da Microsoft sotto forma di tavolo a circa 10K$ ed ha avuto successo in alcune catene di alberghi per applicazioni di concierge. Internamente mi è stato detto che ci sono 9 telecamere a infrarosso e diverse altre diavolerie che ne giustificano il prezzo.
Se volete vederlo all’opera dal vivo venite al Remix Italia Mercoledi 17 Giugno 2009.
Dopo l’esperienza e il successo di Surface, Microsoft ha deciso (come sempre) di creare un supporto device-independent e relativo SDK. Tutto ciò è disponibile in Windows 7 con API native e managed grazie a WPF 4.0. A quanto sembra la prossima versione di Surface userà questo supporto e sarà basata su questa nuova piattaforma.
Il multitouch è economico. Il primo dispositivo (monitor sensibile al multitouch) che viene visto da Windows 7 è stato presentato a PDC 2008. È HP SmartTouch che da vari siti internet si può comprare intorno ai 1000$. Questo è un dato significativo perché obbliga noi sviluppatori a ripensare completamente all’ergonomia delle nostre applicazioni. Non c’è dubbio che di questo se ne parlerà molto.
Il developer che vuole provare a farsi venire qualche idea costruendo un device multitouch a basso prezzo può fare come ha fatto il sottoscritto.
L’idea di per se non è nuova e come ho precisato in sessione il lavoro più duro è suddiviso in quattro parti:
- Il progetto NuiGroup (progetto Tbeta) che riconosce le immagini dalla webcam, elabora l’immagine con edge-detect e altri filtri estrapolando solo le ombre più nere (quelle dove appoggiamo le dita allo schemo traslucido). Le “ditate” indicano le coordinate di ogni “touch” e vengono trasmesse via socket. Da notare che questo progetto può sfruttare la GPU ma che nonostante questo sovraccarica una CPU in modo molto pesante.
- Il progetto MultiTouchVista che installa un driver per Windows 7 e una applicazione helper che riceve dal socket i touch e li passa al driver che emula un device “touch-enabled” di Windows.
- Windows 7 che normalizza gli input e li fornisce alle applicazioni che desiderano supportare questa feature.
- WPF 4.0 che mette a disposizione dello sviluppatore sugli UIElement una serie di eventi (nuovi per WPF 4.0) e una proprietà che permette di decidere le gesture che sono abilitate.
Do-it-yourself! Non si ottiene certamente lo stesso risultato (i touch saranno su uno schermo bianco e non sulle ‘vere’ immagini di uno schermo, e questo fa una bella differenza) e il consumo di CPU è notevole, ma è comunque un ottimo modo per provare la propria applicazione. Insomma per noi dev, funziona alla grande!
Per chi si vuole cimentare:
- Webcam. Preferibilmente 640x480 o più. Meglio se consente la regolazione manuale del focus e della luminosità. Le regolazioni automatiche possono cambiare la resa dell’immagine con sopra la mano.
- Scatola profonda. Il cono di ripresa delle webcam tipicamente è stretto per cui la scatola deve essere profonda. L’interno della scatola deve essere scuro. Mettendo la luce all’interno la webcam non potrebbe ‘vedere’ le ombre delle dita.
- Applicare la webcam in fondo alla scatola, centrandola e tenendola molto ferma. La Köllä a Käldö è vostra amica ;-)
- Plexiglass. Il Plexiglass bianco latte si trova nei fai-da-te e ce lo si può far ritagliare della misura giusta al banco del taglio del legno. Per arrotondare gli angoli ho usato il mio trapano da bricolage ma anche un seghetto manuale funziona allo scopo.
- Illuminazione. Le strisce di led si trovano nei negozi di elettronica. L’alimentazione di solito è a 12V per cui basta saldare qualche pezzo di filo e portarlo ad un jack di alimentazione fissato sulla scatola. Un qualsiasi alimentatore dovrebbe essere sufficiente visto che la corrente necessaria ad alimentare i led è veramente minima.
Per evitare che i fili passino davanti alla webcam dentro la scatola, basta fissarli con la colla alle pareti. Io ho preferito fissare alle pareti dei tubetti dentro cui passano i fili. - Per fissare le strisce di led ho preso un profilato di alluminio a “U”. Alcuni profilati hanno delle sezioni interne dentro cui la striscia di led può slittare dentro. Ammetto che ci vuole un po’ di fortuna ma con un minimo di manualità si può fare un lavoro che abbia un minimo di estetica.
- Infine installare tutto il software.
Ecco alcuni punti a cui fare molta attenzione:
- l’illuminazione è cruciale per la buona riuscita del device. Le ombre delle mani possono ingannare i filtri e risultare in coordinate imprecise
- L’illuminazione a led bianchi è efficace ma purtroppo i led hanno un cono di illuminazione molto stretto. Il cono stretto non permette una illuminazione diffusa. La soluzione è alta luminosità e controllo dell’angolo di incidenza.
Tra le tante ho provato a mettere uno schermo davanti ai led, ma la luminosità si abbatte troppo e creando un’ombra centrale decisamente controproducente. - Lo schermo in plexiglass bianco latte ha un’ottima resa. Basta sceglierlo piuttosto spesso per evitare che fletta durante i ‘touch’.
- Il driver del progetto MultiTouchVista è privo di firma digitale e su Windows 7 a 64 bit non è possibile installarlo. La soluzione è quella di firmare il driver con un certificato self-signed e di fare il boot di Windows 7 abilitando i certificati self-signed.
Se qualcuno arriva fino a qui e vuole due dritte su come fare, è sufficiente che posti un commento a questo post e mi farò vivo con ulteriori istruzioni.
Cosa manca ancora?
La parte più divertente :) cioè scrivere una applicazione multitouch enabled con Visual Studio 2010 e WPF 4.0. Beh per questo ci saranno altre occasioni per parlarne. Ad ogni modo, come ho mostrato in sessione, il sorgente della mia demo è realmente molto semplice.
Enjoy!
venerdì 5 giugno 2009
Ci siamo, Lunedi 8 Giugno è la data del prossimo workshop. Agenda fantastica, location diversa dal solito (Predappio - Forlì), clima perfetto.
Da parte mia non posso ancora anticipare nulla perché avrò delle demo che ... (beeeep) ... e chi non c'è ... si perderà qualcosa che non si può raccontare.
Se siete indecisi rompete gli indugi e venite! Windows 7 rulez.
sabato 30 maggio 2009
Tra le mille nuove bellezze in Visual Studio 2010 ho trovato estremamente utile le Code Dependencies.
L'ho subito voluto provare su un progetto che stiamo realizzando che consiste in una elaborazione a pipeline di due documenti XML. La natura del progetto importa poco, diciamo per semplicità che è una mera blackbox lato server che prende dei dati in entrata e spara il risultato in uscita.
Dal menu Analyze, "Visualize Code Dependencies", "By Class" si ottiene subito un grafico interessante.

Appare subito chiaro che il grafico ha alcuni "intrusi" come le dipendenze dagli assembly del Framework ("External"), le interfacce che aumentano inutilemente la complessità nelle dipendenze (vale probabilmente la pena di avere un diagramma separato solo per queste), ed infine le classi del programma di test.
Per epurarle si seleziona la classe, e dal menu contestuale si sceglie Selection, Hide. Ecco il risultato:
Una classe che mi ha subito attirato l'attenzione è la classe statica degli extension methods per XElement, la XElementHelper che ha una dipendenza da BindingInfo. Per avere più dettagli espando la classe XElementHelper e seleziono la BindingInfo, cosa che evidenzia subito il metodo che ha la dipendenza sulla BindingInfo.
Grazie a questa feature ho già eliminato alcune dipendenze dalla GroupInfo (non più visibili in questi screenshot). Devo dire che l'utilità di questi diagrammi è decisamente altissima.
Ma un'altra cosa che non vorremmo mai vedere in un progetto sono le circular references:
La cosa mi ha subito spaventato ma è apparso invece chiaro che si trattava dei factory methods:
Avrei voluto vedere un'opzione per eliminare le factory dal grafico, e così ho eseguito la submit di un wish su Connect. Se lo volete votare, qui c'è il link.
Un altro grafico interessante è questo:
Invito tutti a provare questa feature perché sono convinto che possa rendere più evidente alcuni aspetti oscuri del codice. Durante la fase di code review, i diagrammi di Code Depenenciees sono certamente una 'killer feature'.
lunedì 18 maggio 2009
Tutti lo sanno, tutti lo scaricano ma ancora nessuno lo blogga… a questo punto eccomi qui :)
Visual Studio 2010 e il Framework 4.0 (entrambi in beta 1) sono disponibili al download. Per i primi giorni il download è solo per gli abbonati MSDN mentre poco più avanti sarà disponibile per tutti.
Io ho installato la beta 1 sul mio portatile (Windows 7 Release Candidate 1) e sta convivendo bene con Visual Studio 2008. Ovviamente è troppo presto per dire altro ma se rimane stabile come nelle ultime due ore, dirò addio a VS2008 visto lo splendido editor, la velocità di caricamento e le nuove bellezze del designer WPF, e naturalmente tutte le novità di FX 4.0, VC++, etc. etc.
Buon download …
mercoledì 13 maggio 2009
Come da Roadmap annunciata durante PDC 2008, Geneva (AKA Identity Platform) è andata in beta 2.
Per chi non lo sapesse ancora alcuni dati essenziali di Geneva:
- A PDC 2008 è stato detto che Geneva rimpiazzerà totalmente il modello a Claim attuale di WCF che diventa obsoleto e con notevoli breaking changes: i Claim di WCF attuali sono differenti da quelli di Geneva sia per proprietà che concettualmente.
Dopo un primo sobbalzo quando li vidi in Zermatt (la ‘alpha’ release di Geneva) devo dire che il modello di Geneva vale tutte le breaking changes - Geneva Framework rende semplice sviluppare scenari con Claim ed STS (Secure Token Service) pur conservando tutto ciò che si è fatto con i ruoli. Questo vale sia per applicazioni asp.net che per servizi WCF.
- Geneva Framework rende facile sviluppare custom STS. Sebbene questo sia un task molto delicato, sono dozzine i casi reali in cui questo è fortemente richiesto e motivato.
- Geneva Server è un STS che usa Active Directory come provider di identità per generare token in formato SAML.
- Geneva Cardspace è la versione 2 di Cardspace e introduce molte novità rispetto al suo predecessore.
- A PDC 2008 è stato detto che le future versioni di SQL Server saranno in grado di “parlare” con le applicazioni Geneva-Enabled, quindi digerire i token SAML. Questo avrà un impatto enorme sull’architettura delle applicazioni in quanto il token SAML in scenari di delegation si porta dietro almeno due identity. Di questo parlerò in un altro post.
Ma torniamo alla beta 2 …
Nessuna major changes. I miei samples non ricompilano ma a prima vista le modifiche sono minori. Il modello ad oggetti dei claim è definitivo e tutti i concetti e le classi che costituiscono lo scheletro di Identity Platform sono definitive in questo stadio. A meno di grosse sorprese la RTM dovrebbe solo vedere consolidarsi il tutto, RTM che è stata annunciata a PDC per fine anno 2009.
Come attesi ci sono:
- nuovi wizard per vs.net per una migliore integrazione
- nuove classi per la configurazione che rende possibile integrare Geneva senza modifiche al ServiceHost e permettendo il riutilizzo del self-hosting di vs.net (cosa che non era possibile nella beta 1)
Novità interessanti:
- FedUtil era prima disponibile solo per scenari asp.net adesso è usabile anche in scenari WCF tradizionali
- ClaimsAuthorizationManager dal nome super promettente. Un manager della fase di autenticazione per i Claim.
- Una lunga serie di eventi per il FederatedAuthenticationModule di asp.net che rende più semplice intervenire durante il processo di logon
- Un nuovo behavior che abilita Geneva senza dover scrivere codice nel service host
Le novità, oltre a leggerle nella documentazione che compara beta 1 e beta 2, sono ben spiegate dal blog del team.
Ho già modificato il mio esempio più semplice: una piccola console che crea delle managed card per Cardspace. È semplicissimo ed estremamente pratico in uno scenario WCF + STS in cui Geneva Framework rende tutto più semplice.
martedì 12 maggio 2009
SvcUtil permette di creare automaticamente la configurazione client di un servizio WCF.
Tra le cose che vengono create c'è l'encoding in Base64 della chiave pubblica del certificato usato dal server
1: <identity>
2: <certificate encodedValue="AwAAAA ...." />
3: </identity>
Naturalmente SvcUtil ricava questa informazione dai metadati.
Sfortunatamente ci sono casi in cui la configurazione del servizio è complessa e non si riesce in modo semplice ad abilitare l'endpoint dei metadati. Guardacaso mi è capitato e il certificato delle due macchine di sviluppo erano diverse.
Apparentemente la soluzione è semplice:
1: private static string GetEncoded(X509Certificate2 cert)
2: {
3: byte[] export = cert.Export(X509ContentType.SerializedCert);
4: string encoded = Convert.ToBase64String(export);
5: return encoded;
6: }
Questo valore è corretto per molti certificati ma ha un side-effect pericolosissimo. Il metodo Export esporta il certificato nella sua interezza, cioè compresa la chiave privata, se presente. Quando viene fatto il deploy di un certificato nello store si può scegliere se installarlo con o senza chiave privata.
Questo significa che la funzione GetEncoded ricava la stessa stringa di SvcUtil per i certificati con sola chiave pubblica, ma dal momento in cui ci imbattiamo in un certificato con chiave privata esportiamo anche quella. Dare una chiave privata in giro equivale a dare una copia delle chiavi di casa a tutti quelli che incontriamo. Non è proprio quello che si dice una cosa saggia.
Così ho cercato di eliminare la chiave privata dal certificato prima di esportarla. Dopo un po' di tentativi andati a vuoto mi sono rivolto al buon amico Mario Fontana (anche se lo tiene nascosto bene, un po' di codice delle CAPICOM viene dalla sua tastiera) che mi ha fatto notare che il formato DER dei certificati si può ottenere semplicemente esportando con l'opzione "X509ContentType.Cert".
1: byte[] der = certRaf.Export(X509ContentType.Cert); // solo public key
A noi però interessa la SerializedCert e quindi non ci resta che re-importare il certificato appena esportato con "Cert"
1: private static X509Certificate2 ImportFromBlob(byte[] certBlob)
2: {
3: X509Certificate2Collection certs = new X509Certificate2Collection();
4: certs.Import(certBlob);
5: X509Certificate2 imported = certs[0];
6: return imported;
7: }
Ed infine richiamare la GetEncoded per ottenere la magica stringa che viene usata nella configurazione client di WCF.
domenica 26 aprile 2009
A quanto sembra Windows 7 vuole far funzionare 'per forza' tutte le applicazioni legacy che hanno 'tradito' le best practice della application compatibility.
Sebbene alcuni cambiamenti introdotti in Vista erano delle novità rispetto alle versioni precedenti (leggasi per esempio i cambiamenti nella Session 0 e nei componenti della logon), la maggior parte sono diventate 'obbligatorie' ma già best practice anche per Windows XP (leggasi ad esempio l'interattività dei servizi, l'accesso in scrittura ai folder program files o alle chiavi di registri HKLM).
Sembra che Windows 7 introdurrà il "Windows XP Mode". Si tratta di un Windows XP virtualizzato all'interno di Windows 7 che rende quasi impossibile non far funzionare le applicazioni legacy. Dico quasi perché dipenderà dall'hardware supportato. Da quello che si legge qui, questa modalità sarà però solo disponibile solo per PC che supportano la virtualizzazione hardware.
Io però non sono daccordo sul nome. L'ho già ribattezzato con il nome di "Shame Box" ossia la "modalità vergogna", visto che ritengo una vera vergogna che una applicazione debba avere necessità dello Shame Box per funzionare.
Non appena uscirà la Release Candidate credo che sarà abbastanza naturale vedere stilate le classifiche delle "Applicazioni da Vergogna".
Il software non è per sempre.
No, non scrivo queste cose da 'tifoso Microsoft'. Io voglio vedere quante più novità possibili e se delle vecchie applicazioni dovessero frenare il progresso del software, beh allora le caccio via. BTW l'ho già fatto con diverse apps.
martedì 21 aprile 2009
Ieri Oracle ha comprato Sun e questa ormai è già notizia "vecchia". IMHO notizia bomba, ma c'è uno strano silenzio.
Sun possedeva diverse "cosette" interessanti: Java, mySQL, NetBeans e OpenOffice solo per citare le più famose e senza citare le partecipazioni con gran soldoni ai progetti Open Source. A parte le promesse istituzionali, bisognerà vedere cosa accadrà ai vari prodotti/finanziamenti.
Per esempio OpenOffice nella FAQ non è neppure citato e il silenzio europeo è piuttosto sospetto. Molti paesi europei hanno adottato OpenOffice e mi risulta che molti uffici della stesso governo europeo usi questo prodotto.
Adesso immaginate uno scenario fanta-it. Oracle mette a pagamento OpenOffice e la comunità europea che fa? Li multa per trust? Il governo (non una persona ma proprio il governo stesso) sarebbe in un conflitto di interesse come pochi se ne sono visti prima. Fanta-it divertente, stiamo a vedere che succede.
venerdì 17 aprile 2009
Uno dei vantaggi più graditi di Linq sono gli Expression Tree, una vera manna per sistemare i classici problemi di condizioni where non prevedibili durante la progettazione.
Gli Expression Tree sono compilati, strong-typed, provider independent e serializzabili (anche se con qualche aiutino).
Prendiamo l'esempio di un semplice accesso ai dati usando Linq2SQL, il mio DAL preferito.
1: public static IEnumerable<Article> GetList(Expression<Func<AnaArt, bool>> Filter)
2: {
3: var ctx = GetDataContext();
4: var items = ctx.AnaArts.Where(Filter).Select(c => new Article(c.MGAA_Id, c.MGAA_MBDC_Classe, c.MGAA_Matricola, c.MGAA_Descr));
5: return items;
6: }
7:
8: public static int GetListCount(Expression<Func<AnaArt, bool>> Filter)
9: {
10: var ctx = GetDataContext();
11: var res = ctx.AnaArts.Count(Filter);
12: return res;
13: }
La GetList usa un predicate che ha in ingresso l'i-esimo oggetto mappato ad un record e in uscita c'è il boolean che decide se quel record debba essere incluso o meno nel resultset. Func è il delegate, Expression<Func<..>> è l'Expression Tree che usa quel delegate. L'Expression Tree è quello che permette la "magia" di tradurre il predicate in linguaggio SQL a carico del provider.
La GetListCount fa esattamente lo stesso ma si avvale di Count che, come la where, accetta un predicate.
- Creando il predicate al volo con PredicateBuilder di Joe Albahari di cui raccomando LinqPad, fantastico tool ora dotato anche di Intellisense da usarsi al posto del classico Query Analyzer e per rendersi conto se la query Linq è scritta bene o rischia di fare disastri in performance sul DB (che è sempre colpa di una query scritta male).
Per dare l'idea di un caso pratico, in una applicazione per un cliente abbiamo creato un designer visuale in WPF di condizioni Where in modo che l'utente potesse decidere il criterio di scelta. Poi abbiamo serializzato i predicate in modo 'custom' e le ricerche possono essere ricaricate e riutilizzate con estrema semplicità.
Per chi sia interessato a serializzare, esiste un serializzatore di Expression Tree realizzato da una persona del team di C#
- In alcuni casi la where la si può prevedere facilmente e quindi basta creare un filtro ad-hoc, per esempio recuperando il record con un certo Id:
1: public static Article GetArticleById(int Id, bool IsCount)
2: {
3: Expression<Func<AnaArt, bool>> Filter = c => c.MGAA_Id == Id;
4:
5: return GetArticles(Filter).FirstOrDefault();
6: }
Bello, vero ma ci sono casi in cui queste where sono solo dei "pezzi" che farebbe comodo riutilizzare in diversi contesti e magari unire, grazie al predicatebuilder, con altri "pezzi" di where.
In sostanza, tanto per fare un esempio semplice, sarebbe più comodo ed elegante che il metodo usasse la funzione FilterById.
Attenzione però che non può trattarsi di una normale funzione C#. Il nostro requisito indispensabile è che sia un Expression Tree traducibile in linguaggio SQL a cura del provider. Quindi FilterById deve essere un Expression<Func<...>>.
1: public static Article GetArticleById(int Id, bool IsCount)
2: {
3: Expression<Func<AnaArt, bool>> Filter = FilterById(Id);
4:
5: return GetArticles(Filter).FirstOrDefault();
6: }
In pratica mi serve una funzione che:
- in ingresso prenda un intero (Id)
- in uscita mi restituisca un Expression<Func<...>>, cioè quello che la where si aspetta
- Ed ecco il risultato (opzione 3):
1: public static readonly Func<int, Expression<Func<AnaArt, bool>>> FilterById = Id => (d => d.MGAA_Id == Id);
FilterById è una lambda dove:
- Id è il parametro di ingresso (un intero)
- (d => d.MGAA_Id == Id) è una lambda in uscita
Questa lambda in uscita ha la forma di Expression<Func<AnaArt, bool> cioè:
- in ingresso prende l'i-esimo id del record che verrà processato e lo compara con l'intero che gli è arrivato come parametro dalla lambda precedente (quindi ormai è noto)
- in uscita restituisce un boolean che dice se includere o meno il record nel resultset
Niente di nuovo, e chi ha già giocato con Linq avrà sicuramente esplorato queste belle cose, ma ripeterle non fa mai male.
venerdì 20 marzo 2009
Sono molto soddisfatto della conferenza appena conclusa a Roma. Ottima organizzazione, agenda succulenta, un clima molto piacevole con tutti i presenti, nessuno escluso.
Solo un peccato per aver visto una affluenza minima dal centro-sud della penisola. Sarebbe stata una buona occasione per richiamare l'attenzione sugli organizzatori di eventi a dare più spazio a eventi in questa zona.
Parlando con alcuni partecipanti, erano dispiaciuti per la contemporaneità delle track. Devo rassicurarli che questo è un denominatore comune a qualsiasi conferenza e che la sovrapposizione a Basta! Italia è stata molto inferiore di quello che avviene nell'edizione tedesca o anche al TechEd. Ovviamente i pianificatori dell'agenda, Sebastian e Dino, sono sempre interessati ad avere feedback per le prossime edizioni.
I feedback positivi continuano ad arrivarmi via email da alcuni partecipanti che voglio ringraziare di cuore.
Ho avuto il piacere di far esordire in una conference italiana l'argomento "Geneva Framework" arrivato alla beta 1 e destinato a far parlare moltissimo di se. Parliamo della sicurezza a claim che sostituirà integralmente l'attuale modello a claim di WCF, quindi certamente un argomento molto popolare.
Ho collezionato in questi mesi quantità gigantesche di appunti, tweaks, prodotto slides in quantità industriale e mi sono sviluppato tantissimi esempi.
L'altro argomento che avevo in agenda è stato sul modello di sicurezza usando WCF e WF insieme. Purtroppo su sicurezza e Workflow Foundation non c'è quasi nulla in giro e persino un articolo di MSDN con errori che mi sono stati confermati dal team di sviluppo. In sessione ho stressato sulla necessità di rendere il progetto WCF+WF agnosta sulle scelte nel modello di sicurezza di WCF o del modello di threading. Sono problematiche che possono essere molto tricky. Insomma una sessione in linea con la filosofia di Basta!, cioè le best practices.
Infine, ma non per importanza, il technical after-hour di UGIdotNET dove una dozzina di coraggiosi mi hanno seguito nella sessione sui "Windows Web Services" di Windows 7 (da poco online in beta anche per gli OS precedenti) in codice nativo. Dico coraggiosi perché la sessione era dalle 20:15 alle 21:00 e la fame si faceva sentire :)
Alla prossima!
giovedì 12 marzo 2009
Finalmente un evento un po' diverso dal solito. L'occasione è quella di incontrare le community e installare al volo Windows 7 beta 1 che ha già dimostrato di essere decisamente molto stabile.
D'altra parte il grosso dei cambiamenti era apparso con Vista (come ho ampiamente stressato qui e post successivi sugli integrity levels qui, qui e qui e poi ancora UIPI) ma attenzione che Windows 7 non è affatto una release di minore importanza, anzi ...
- Performance globalmente migliorate
- Minori requisiti di memoria
- Minore consumo di batteria sui notebook
- Auto-diagnosi sui problemi applicativi
- Rimozione di un paio di lock globali nel kernel per migliorare le performance nelle macchine multicore (da qui in avanti praticamente tutti i pc)
- Trigger sullo start/stop dei servizi. Esempio: se pluggo un device USB il servizio parte, se lo stacco si ferma. Questo diminuisce la memoria usata dai servizi e naturalmente le performance per lo start del servizio al boot.
- Boot da VHD
- Miglioramenti nel riconoscimento di scrittura e voce
- Gadget usabili senza Sidebar
- Taskbar ridisegnata completamente e decisamente più usabile
- Naturalmente Internet Explorer 8
- ...
Questo per non parlare delle feature più developer oriented come:
- Supporto ai sensori
- API dei Windows Web Services
- API per i Package (usati per XPS e i nuovi formati ISO Office OpenXML)
- MultiTouch API
- Powershell 2.0 preinstallata
- ...
Per chi vuole maggiori dettagli sull'evento, li trova qui: http://www.microsoft.it/installation/
I link diretti agli eventi locali sono invece questi:
Non so bene a quale evento potrei partecipare visto che sfortunatamente non ce n'è uno nella mia città. Percherò a caso da una ampolla di vetro ... 
lunedì 9 marzo 2009
È sempre una fantastica esperienza andare al Summit. Negli anni ho conosciuto tante persone e, anno dopo anno, è sempre più difficile trovare il tempo per reincontrare tutti in mezzo alle sessioni ufficiali.
I contenuti sono stati molto proficui, meglio di altre passate edizioni. Le novità che ci aspettano sono tantissime ed entusiasmanti, ma sotto NDA quindi non ne posso parlare per il momento. Ci vuole solo un po' di pazienza, tempo che arrivi la beta 1 di Visual Studio 2010 e poi saranno sotto gli occhi di tutti.
In diversi mi pingano in questi giorni chiedendomi del Summit, per cui ecco cosa ho fatto giorno per giorno in quel di Seattle/Redmond.
Venerdi pomeriggio l'arrivo a Seattle; compagni di viaggio Alessandro e Giuseppe. Ho avuto il piacere di conoscere Enzo, un illustre italiano developer in quel di Redmond con cui abbiamo trascorso il pomeriggio e che ringrazio ancora per lo 'strappo' a Downtown dall'areporto.
Sabato di svago a Vancouver (Canada). Il buon Giorgio, da poco indigeno di Seattle, ci ospita sulla sua nuova Mustang con un motore che fa musica. Il resto del gruppo ci segue con una macchina affittata.
Vancouver è una grossa città, all'apparenza semi-deserta per poi scoprire che la vita è negli enormi centri commerciali sotterranei sviluppati a gallerie. Il freddo lo impone.
La comunità asiatica (almeno per l'aspetto, probabilmente Canadesi da generazioni) la fa da padrona. La cortesia della west-coast regna anche laggiù.
In serata cena al mitico Crab Pot di Bellevue che ci ha fatto conoscere Aldo. Veramente peccato non ci fosse, sarà per la prossima.
Domenica. Di mattina immancabile gita al tempio dell'elettronica, Fry's, dove abbiamo dato sfogo al geek-shopping più sfrenato (ci siamo trattenuti). Poi a pranzo in un simpativo localino di Bellevue.
Nel pomeriggio il Summit prende il via con le prime keynote. Interessanti probabilmente più per i neo-awarded che per i rinnovati.
Lunedi sveglia alle 5:30, colazione e poi via al Campus. Per me mattinata a base di Oslo e pomeriggio di WPF. Ottima occasione per ascoltare e fare domande a Don Box, Chris Anderson, Martin Gaudgin ed altri meno noti ma non meno tosti.
Nel pomeriggio sessione di security con Adam Shostack e la superstar Larry Osterman a parlare di Threat Modeling in Windows 7. Tra i pochi presenti anche un nome noto, Jesper. Nei corridoi incontriamo di sfuggita anche Mark.
Non è finita, dopo peripezie io, Max e Leone raggiungiamo per cena un meeting in caffetteria su Windows 7.
Giornata finita al campus. Giorgio ci passa a prendere e via in un bizzarro localino di Seattle per uno spuntino. All'ingresso mi chiedono il passaporto per entrare ... non ho smesso di ringraziarli per avermi fatto intendere di dimostrare meno di 21 anni :)
Martedi sveglia alle 5:30 e via di nuovo al Campus. Giornata Visual C++ reincontrando tanti amici nel team: Ayman, Tareq, Ronald, Ale, Marian, per scrivere i primi che mi sono venuti in mente. Tantissimi argomenti, molti dei quali sul parallel computing a cui interviene il carissimo amico Steve e anche Daniel Moth, celebre ex-MVP. Giornata fantastica con tantissimi contenuti validi anche per lo sviluppo managed con C#/VB.
In serata veloce ritorno in albergo e poi via alla festa all'Experience Music Project sotto lo Space Needle.
Mercoledi è giorno di chiusura con le keynote di Mike Nash, Steve Ballmer e Somasegard che porta sul palco 4 illustri Technical Fellows.
Nel pomeriggio un fuori programma e torniamo al Campus con Corrado, Mauro e Cristian. Shawn mi ha infatti organizzato un meeting di recap sulle novità del CLR 4.0 in presenza di alcuni suoi illustri colleghi e tester. Wow, spettacolare, thanks Shawn.
Poi Corrado, ormai nota superstar Redmondiana, va a Channel9 mentre noi altri al building di Windows per un altro meeting.
Mi aspettava infatti l'amico Nikola che faceva parte del team di VC++ e ora si occupa di un tema ultra interessante su cui ho già fatto un webcast per il pre-evento di Windows 7: i Windows Web Services, le API native "C" per creare web services e quindi disaccoppiare codice managed da nativo ... ma di questo parlerò in altri post.
Nikola ci presenta tutto il team del networking, ufficio per ufficio. Chi si occupa del service layer, chi del channel layer, i tester, e l'utility di generazione del proxy... spettacolare. È lo stesso piano in cui c'è il team di RPC :)
Finito il meeting andiamo a trovare Enzo nel suo building e poi via a Seattle per cena in un ristorante giapponese dove Ale ci consiglia su sushi e sake. Devo dire tutto molto buono. La tavolata è tutta di noi italiani MVP e italiani di Redmond. Proprio una bella compagnia.
Giovedi è il rientro. Volo via Cincinnati e Parigi per me ed Alessandro e dopo tante, troppe ore finalmente tra le braccia dei nostri cari.
Bilancio super positivo. Grazie a tutti coloro che ci hanno accolti, abbiamo avuto un trattamento da re.
A passarci una settimana di più l'avrei speso certamente bene ma il tempo è sempre tiranno. Non c'è che dire, stanno lavorando a ritmi serrati e quello che ho visto è stato extra-positivo.
Se la beta 1 di VS2010 sarà stabile e avrà tutto quello che ho visto, sarà certamente la migliore versione di VS che abbia usato. Non ci resta che aspettare ...
lunedì 2 marzo 2009
Siamo a 20 minuti dalla keynote nel conference center di Seattle e il Summit sta per partire. Domani e Martedi al Campus in Redmond.
Dopo la mattinata di pellegrinaggio da Fry’s ci vuole adesso un buon caffè americano :)
giovedì 26 febbraio 2009
Sbarca in Italia la Basta! conference dal 16 al 19 Marzo a Roma: http://www.bastaitalia.it/
È una conferenza di grande successo in Germania che esordisce per la prima volta in Italia e tra l'altro a Roma, location purtroppo insolita per conferenze sullo sviluppo con tecnologie di casa Microsoft.
Personalmente credo che sia una grande occasione per chi solitamente non riesce a raggiungere le solite location di Milano.
Basta! è una conferenza dal taglio molto pratico e fa delle "Best Practice" la sua parola chiave. L'agenda è curata da Dino Esposito e Sebastian Meyen e per gli speaker c'è l'imbarazzo della scelta.
Personalmente ho il grande piacere ed onore di essere speaker di due sessioni su temi di sicurezza e 'scottanti':
- Autenticazione e autorizzazione secondo Microsoft Identity Framework
- WCF e WF: Sicurezza e integrazione
Dulcis in fundo, UGIdotNET organizza un technical after hour gratuito costituito da due sessioni i cui temi saranno decisi dai soci UGIdotNET. Ricordo che per essere soci è sufficiente essere iscritti ad UGIdotNET. Al momento il sito è in rinnovamento e non c'è una form di iscrizione ma si può chiedere direttamente a "il presidente"!
mercoledì 25 febbraio 2009
Oggi si è aperto l'evento "Anteprima di Windows 7": http://www.microsoft.com/italy/beit/eventi/windows7/
Per questa occasione le sessioni sono pre-registrate e ho avuto il piacere di preparare tre argomenti:
Le nuove API native per scrivere Web Services in C/C++ nativo:
http://www.microsoft.com/italy/beit/eventi/windows7/win7_api.aspx
A partire da Windows 7 sono disponibili delle nuove API C per scrivere web services basati sugli standard SOAP e quindi compatibili con WCF. Le API verranno rese disponibili anche da XP/2003 in su e costituiranno un ottimo modo per disaccoppiare le porzioni di codice nativo C++ con quello managed.
Le novità in Windows 7 per lo sviluppo multicore:
http://www.microsoft.com/italy/beit/eventi/windows7/win7_multicore.aspx
Windows 7 si sta adeguando alle novità hardware in termini di multicore. Nel webcast si analizzano le novità e come queste diano, in aggiunta a nuove librerie presenti nella prossima versione di Visual Studio, un concreto aiuto per sfruttare al massimo la capacìtà elaborativa delle nuove CPU.
Le best practices per la creazione di applicazioni per Vista e Windows 7:
http://www.microsoft.com/italy/beit/eventi/windows7/win7_compatibilita.aspx
Gli sviluppatori hanno dimostrato di fare fatica ad adeguare le applicazioni a Vista e Windows 7. Eppure ci sono best practices già note all'epoca di Windows XP che avrebbero reso indolore questo passaggio.
Nel webcast si analizzano queste best practices e come sfruttare al meglio le novità introdotte in Windows Vista e Windows 7.
Giovedi 26 Febbraio pomeriggio sarò disponibile online per domande su queste ed altri argomenti inerenti l'evento su Windows 7.
Giovedì 26 febbraio, ore 14.00 – 15.00
Giovedì 26 febbraio, ore 17.00 – 18.00
Mi sarebbe piaciuto essere online anche i giorni seguenti ma Venerdi io e molti altri MVP arriveremo a Seattle per partecipare in quel di Redmond al "MVP Summit 2009", e gli impegni non ci permettono fare diversamente.
venerdì 20 febbraio 2009
Quando una elaborazione “pesante” viene eseguita in un contesto di una interfaccia utente, sia essa Winform, MFC o WPF, è necessario che questa venga “alimentata” servendo il thread sottostante:
- Windows Forms ed MFC, come anche altre librerie basate sulle Win32, hanno bisogno di alimentare la message pump. Si tratta di una coda associata ad uno specifico thread che accumula messaggi e li smista verso i controlli contenuti.
- WPF non ha message pump perché ha un meccanismo di rendering completamente differente. Nonostante questo esiste un meccanismo analogo alla message pump, basasto sul Dispatcher di WPF.
Fin qui tutto chiaro. Il developer attento conosce questi aspetti ma ci sono almeno due casi in cui queste precauzioni vengono tipicamente ignorate:
- Quando l’elaborazione viene eseguita in un thread differente, il developer è “tranquillo” di lasciare libero il dispatcher del thread principale e perciò di eseguire tutto nel rispetto delle regole
- Quando non esiste neppure una finestra di presentazione perché WPF viene usato per eseguire delle elaborazioni non visuali: creazione di XPS, rendering per la creazione di bitmap, etc.
Questi casi sono tipici per elaborazioni dentro servizi WCF o applicazioni asp.net
Da un punto di vista di elaborazione grafica tutto questo non fa una grinza eppure c’è un problema.
Tutto nasce da un test per verificare una procedura complessa per la creazione di documenti XPS. Ad ogni loop viene creato un documento e salvato su file. Una volta eseguito il giro, tutti gli oggetti grafici che sono serviti per la creazione del documento vengono buttati via. Eppure la memoria (working set) continua a crescere ad ogni giro fino a dare una OutOfMemoryException.
Il primo pensiero va giustamente ad un classico memory leak e qui parte un intreccio di code review e misurazioni sull’uso della memoria eseguite con il profiler di Visual Studio. Quando si incontra un managed memory leak i maggiori sospetti sono tipicamente per:
- Collection/hashtable/oggetti statici che accumulano un grosso numero di children senza rimuoverli
- Oggetti singleton che fungono da “root” per interi tree di oggetti
- Allocazioni native non rilasciate
Eppure non era nulla di tutto questo. Inoltre la traccia del profiler è decisamente poco generosa di informazioni utili. Si vede un esagerato numero di oggetti WPF referenziati internamente nelle classi di WPF e nulla di riconducibile al codice utente.
Il secondo tentativo è quello di forzare ad ogni ciclo una garbage collection con il classico pattern:
GC.Collect();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Disclaimer: questo è solo codice per eseguire dei test e non dovrebbe mai essere usato in produzione.
I primi due Collect sono necessary per garantire che siano soggetti alla collection anche gli oggetti che hanno un finalizzatore. La WaitForPendingFinalizers serve ad attendere che la coda di finalizzazione sia vuota. L’ultima Collect garantisce che anche gli oggetti ormai finalizzati siano soggetti a collection.
Anche questo test non dà alcun esito, cioè la memoria non scende. A questo punto è sostanzialmente certa la presenza di un memory leak, cioè la presenza di un reference “da qualche parte” che non permetta al garbage collector di liberare la memoria.
Limitando il numero di cicli e forzando il garbage collector dopo un paio di secondi (tramite un pulsante) la memoria veniva liberata. Ma che razza di memory leak è questo?
E arriviamo al terzo tentativo. Mi dico: “come fa WPF a gestire oggetti grafici (i.e. risorse unmanaged di directx) senza aver mai bisogno di Dispose?”. Mi rispondo: “dovessi farlo io, implementerei un gestore di oggetti che li libera non appena non vengono più usati”.
Visto che l’apartment dei thread di WPF deve essere di tipo STA (Single Threading Apartment), se non permetto al dispatcher (che suppongo sia basato su una message pump di un oggetto COM di tipo STA) di svuotare la coda dei suoi messaggi, questo non potrà eseguire il metodo che presuppongo sia preposto al rilascio delle risorse e a ruota dei reference agli oggetti.
Per verificare la mia ipotesi, ad ogni ciclo faccio eseguire:
1: Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
La priorità di tipo Background è fondamentale perché, come dice MSDN, il delegate vuoto verrà eseguito ... “Operations are processed after all other non-idle operations are completed”. In pratica il codice del delegate “{}” è una scusa per assicurarsi che il dispatcher svuoti prima la coda dei messaggi.
Bingo, funziona! Adesso ad ogni ciclo la memoria viene liberata senza alcuna necessità di invocare manualmente la collection.
Considerazioni finali.
1. Le motivazioni appena descritte sono solo una mia deduzione. Non ho trovato alcuna documentazione in merito sul funzionamento interno di WPF per quello che riguarda la disallocazione di oggetti e risorse.
2. Anche eseguendo il ciclo in un thread separato il problema si verifica comunque.
Il thread secondario deve essere aperto con apartment STA e come tale necessita comunque di alimentare il dispatcher in quel thread.
3. Se è effettivamente come ho descritto, si spiega il fatto che le chiamate alla GC.Collect non abbiano effetto.
Quello che posso dedurre è che WPF si comporti come un runtime che, in modo analogo a quanto viene fatto dal garbage collector, si accorge quando un reference non viene più usato. A quel punto, alla passata successiva, il dispatcher può rilasciare le risorse unmanaged sottostanti e finalmente rilasciare l’oggetto al GC che eseguirà il rilascio reale della memoria occupata.
Perciò fin tanto che WPF non ha processato questi oggetti, anche se il codice utente non ha più reference attivi, è WPF ad averli perché questi oggetti devono ancora essere soggetti al rilascio di risorse interno di WPF.
Ripeto: sono solo mie deduzioni e non ho alcuna conferma a sostegno del mio ragionamento, se non i test che ho eseguito.
Morale.
Il garbage collector funziona, e funziona molto bene.
WPF fa il suo dovere e se il funzionamento è quello che ho intuito osservando questo test, i vantaggi sono superiori al problema che ho incontrato. L’assenza di Dispose in tutto WPF è un vantaggio non da poco e da qualche parte le risorse unmanaged ci devono essere per forza visto che si tratta di oggetti grafici.
Perciò come al solito prima di pensare a malfunzionamenti e bug bisogna cercare di capire come funziona e mettersi nei panni di chi ha dovuto risolvere il problema del rilascio delle risorse.
lunedì 9 febbraio 2009
Parte 1: http://blogs.ugidotnet.org/raffaele/archive/2009/01/27/windows-vista-integrity-levels-parte-1.aspx
Parte 2: http://blogs.ugidotnet.org/raffaele/archive/2009/01/29/windows-vista-integrity-levels-parte-2.aspx
Parte 3: http://blogs.ugidotnet.org/raffaele/archive/2009/02/03/windows-vista-integrity-levels-parte-3.aspx
Lo Shatter Attack
Nel 2005 Fabio Santini ed io abbiamo tenuto il Security Roadshow in giro per l'Italia. Una delle demo di Fabio consisteva nello Shatter Attack, un tipo di Luring Attack che più generalmente sono attacchi di tipo "Elevation of Privilege". Questo attacco mostrava quanto fosse pericoloso girare come administrator in Windows XP.
Fabio avviava un "malware" di sua creazione con credenziali di normale utente allo scopo di limitare i danni che il malware avrebbe potuto fare.
Il malware in questione mandava una serie di "click" del mouse da codice verso Explorer.exe (la shell di Windows) lanciando così un comando "distruttivo" come potrebbe essere format: "Start, run, format " .... Ok format è solo un esempio di 'effetto' ma se ci pensiamo un attimo non si fa fatica a disastrare una macchina quando si hanno i privilegi di administrator.
Il processo malware, avendo ricevuto un token da normale utente grazie a runas, non avrebbe mai avuto i privilegi per eseguire un format e avrebbe ricevuto un "access denied".
Il processo malware però poteva mandare una serie di WM_LBUTTONDOWN verso il processo Explorer.exe che aveva il token di administrator in quanto l'utente (Fabio nella demo, non nella vita reale) si loggava con privilegi di amministratore. La command che lanciava l'operazione di Format ereditava il token da Explorer.exe e di conseguenza riceveva il token di administrator.
Il gateway all'elevazione di privilegi
Il motivo per cui è possibile realizzare uno Shatter Attack è che gli oggetti di windowing (USER) e grafici (GDI) non sono soggetti a security per ovvi problemi di performance. Pensate cosa significherebbe eseguire un controllo di security per ogni Pen, Brush, CreateWindow, SetWindowText, LineTo, Draw, ... eseguita nel sistema. A distanza di diciotto anni, considero giusta questa scelta che Microsoft fece con Windows NT.
L'introduzione di UIPI in Vista
Il meccanismo di User Interface Privilege Isolation (UIPI) è strettamente legato agli Integrity Levels. UIPI ha il compito di impedire ad un processo di comunicare con un altro che abbia Integrity Level più elevato.
Per esempio un processo con Integrity Level Medium (normale user) non riuscirà a fare una serie di cose verso un altro processo con Integrity Level High (Administrator) o System (servizi e web application):
- Usare SendMessage / PostMessage di messaggi considerati potenzialmente pericolosi.
Windows mantiene una blacklist di messaggi tra cui tutti quelli superiori a WM_USER, tipicamente usati dalle applicazioni come meccanismo di comunicazione privato. Questi messaggi vengono filtrati da Windows. - Eseguire un thread hook
- Monitorare con i journal hook
- Iniettare dll
In pratica UIPI impedisce, grazie agli Integrity Level, gli Shatter Attack che erano fatali in Windows XP. Aggiungerei che UIPI è un meccanismo indispensabile, senza il quale sarebbe facile bypassare il blocco agli oggetti offerto dal meccanismo degli Integrity Levels visto nei precedenti post.
Application Compatibility
Parlando di Application Compatibility, UIPI è certamente un fattore di primo piano in quanto molte applicazioni eseguono una comunicazione tra processi utilizzando l'API RegisterWindowMessage e comunicando con messaggi custom (WM_USER+...).
Per permettere alle applicazioni di modificare il filtro esiste l'API ChangeWindowMessageFilter:
- MSGFLT_ADD. Permette al processo che invoca la API di ricevere il messaggio
- MSGFLT_REMOVE. Nega al processo che invoca la API la ricezione del messaggio
I processi con Integrity Level <= Low non possono usare questa API.
Con una semplice call a questa API i problemi di comunicazione tra processi via WM_xxx sono risolti.
Accessibility
Sembra tutto risolto e invece c'è un problema di primaria importanza: le applicazioni per l'accessibilità. In Windows esiste per esempio la "On-Screen Keyboard" che permette di simulare la tastiera usando solo il mouse. Molte altre applicazioni esistono per i portatori di handicap che permettono di facilitare il canale di I/O tra computer e persona.
Non è perciò improbabile avere la on-screen keyboard che gira come normale user (Integrity Level Low) che devono pilotare applicazioni ad Integrity Level superiore, magari una command prompt amministrativa. Purtroppo UIPI impedisce tutto questo e rende impossibile l'uso di queste applicazioni.
Microsoft non si è affatto dimenticata di questo problema e ha introdotto il flag UIAccess che bypassa UIPI. Questo flag viene letto dal manifest dell'eseguibile e conservato nel token associato al processo.
Visto che questo flag può essere usato per bypassare il meccanismo di protezione da parte di un malware, esiste una policy (abilitata per default) per cui il flag ha effetto solo se l'exe è stato installato in una di queste cartelle:
- in una sottocartella di "Program Files" o "Program Files (x86)"
- in una sottocartella di Windows\System32
Poiché la scrittura in queste cartelle è possibile solo ad un adminstrator, solo una applicazione installata da un token elevato può usare UIAccess.
Per sapere se un token di processo ha abilitato o meno il flag UIAccess, si usa GetTokenInformation passando TokenUIAccess. Il valore di ritorno è 0 (disabilitato) o 1 (abilitato).
Integrity Levels e UIPI sono quindi in primo piano per quello che riguarda i problemi di "Application Compatibility" nei sistemi operativi dalla 6.0 in su (cioè da Vista/2008 in avanti).
Valeva la pena di introdurre queste novità a scapito della piena compatibilità delle vecchie applicazioni? A mio avviso si, senza alcun dubbio perché sottolineo che presto gli antivirus non serviranno più a nulla.
martedì 3 febbraio 2009
Parte 1: http://blogs.ugidotnet.org/raffaele/archive/2009/01/27/windows-vista-integrity-levels-parte-1.aspx
Parte 2: http://blogs.ugidotnet.org/raffaele/archive/2009/01/29/windows-vista-integrity-levels-parte-2.aspx
La parte divertente è quella di scrivere codice, vediamo quindi le API per usare gli Integrity Levels.
Creazione di un processo via API con integrity level impostato a low
- Prendere l'handle del token del processo corrente (che di default è "medium")
- Duplicare l'handle (API DuplicateHandle)
- Impostare l'Integrity Level a "Low" grazie a SetTokenInformation
- Creare il processo con CreateProcessAsUser usando il nuovo token modificato
1: #include <windows.h>
2: #include <Sddl.h>
3:
4: #include <string>
5: using namespace std;
6:
7:
8: // restituisce zero se tutto è ok, oppure l'errore win32
9: DWORD CreateLowProcess(wstring PathName, wstring CommandLine)
10: {
11: // Low integrity SID
12: WCHAR IntegritySid[20] = L"S-1-16-4096";
13: DWORD LastError = 0;
14:
15: HANDLE hToken = NULL;
16: // Legge il token del processo attuale
17: if(OpenProcessToken(GetCurrentProcess(),
18: TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT |
19: TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY,
20: &hToken))
21: {
22: HANDLE hNewToken = NULL;
23: // duplica il token per poterlo modificare
24: if(DuplicateTokenEx(hToken,
25: MAXIMUM_ALLOWED,
26: NULL,
27: SecurityImpersonation,
28: TokenPrimary,
29: &hNewToken))
30: {
31: PSID pIntegritySid = NULL;
32: // converte la stringa del sid in struttura binaria
33: if(ConvertStringSidToSid(IntegritySid, &pIntegritySid))
34: {
35: TOKEN_MANDATORY_LABEL TIL = {0};
36: TIL.Label.Attributes = SE_GROUP_INTEGRITY;
37: TIL.Label.Sid = pIntegritySid;
38:
39: // Modifica l'integrity level del nuovo token
40: if(SetTokenInformation(hNewToken, TokenIntegrityLevel, &TIL,
41: sizeof(TOKEN_MANDATORY_LABEL)))
42: {
43: PROCESS_INFORMATION ProcInformation = {0};
44: STARTUPINFO StartupInfo = {0};
45: StartupInfo.cb = sizeof(StartupInfo);
46:
47: // crea il processo con il nuovo token
48: if(CreateProcessAsUser(hNewToken,
49: PathName.c_str(),
50: const_cast<wchar_t*>(CommandLine.c_str()),
51: NULL,
52: NULL,
53: FALSE,
54: 0,
55: NULL,
56: NULL,
57: &StartupInfo,
58: &ProcInformation))
59: {
60: if (ProcInformation.hProcess != NULL)
61: CloseHandle(ProcInformation.hProcess);
62:
63: if (ProcInformation.hThread != NULL)
64: CloseHandle(ProcInformation.hThread);
65: }
66: else
67: LastError = ::GetLastError();
68: }
69: else
70: LastError = ::GetLastError();
71: LocalFree(pIntegritySid);
72: }
73: else
74: LastError = ::GetLastError();
75: CloseHandle(hNewToken);
76: }
77: else
78: LastError = ::GetLastError();
79: CloseHandle(hToken);
80: }
81: else
82: LastError = ::GetLastError();
83:
84: return LastError;
85: }
Il listato è in C++ perché non ci sono chiamate pronte nel Framework.NET. Ovviamente le stesse cose si possono fare creando le corrispondenti chiamate PInvoke.
In alternativa è sufficiente impostare il file dell'exe con un Integrity Level "low" e di conseguenza al suo avvio il token sarà automaticamente a quello stesso livello.
Impostare a low un file
Per fare le prove consiglio di copiare il file notepad.exe in una cartella temporanea.
Si può cambiare l'integrity level di un file con l'utility ICACLS:
icacls notepad.exe /setintegritylevel L
Per leggere l'integrity level non è necessario il prompt elevato e il risultato è:
C:\Temp>icacls notepad.exe
notepad.exe XYZ\Raf:(I)(F)
BUILTIN\Administrators:(I)(F)
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Users:(I)(RX)
Mandatory Label\Low Mandatory Level:(NW)
Successfully processed 1 files; Failed processing 0 files
Io mi sono costruitio una mia utility per modificare i token e posso impostare l'integrity level ad un numero arbitrario, non solo ai livelli prefissati nell'sdk.
Se un file viene impostato ad un valore non predeterminato nell'SDK, ICACLS non mostra il numero esatto.
Per esempio uso la mia utility RafToken per impostare il livello 4095 (Low è 4096), ma poi ICACLS mi dice che non è riuscito a mappare il numero 4095 in uno degli Integrity Level noti.
C:\Temp>debug\raftoken -i 4095 notepad.exe
C:\Temp>icacls notepad.exe
notepad.exe XYZ\Raf:(I)(F)
BUILTIN\Administrators:(I)(F)
NT AUTHORITY\SYSTEM:(I)(F)
BUILTIN\Users:(I)(RX)
No mapping between account names and security IDs was done.
(NW,NR,NX)
Successfully processed 1 files; Failed processing 0 files
Questa operazione non è affatto illegale. È solo l'utility ICACLS che non mostra il valore numerico. L'integrity Level alla fine dei conti è solo un numero a 16 bit e quindi qualsiasi valore è valido. Ovviamente il sistema operativo ha dei valori noti a cui fa riferimento.
Impostare a low un oggetto kernel (come un file) via API
- Creare una stringa SDDL con le opzioni desiderate
Per esempio "S:(ML;;NWNRNX;;;S-1-16-4096)" imposta
- no-write-up (NW), no-read-up (NR), no-execute-up (NX) e level 4096 cioè medium
(ML è l'acronimo di Mandatory Label, usato in MSDN per indicare la struttura che contiene le informazioni relative agli Integriry Level e Policy)
- Aprire il file per ottenerne l'handle (GENERIC_READ | GENERIC_WRITE | WRITE_DAC | WRITE_OWNER)
- Chiamare ConvertStringSecurityDescriptorToSecurityDescriptor per creare un security descriptor binario a partire dalla stringa SDDL
- Chiamare GetSecurityDescriptorSacl per ottenere la SACL a partire dal security descriptor appena ottenuto
- Chiamare SetSecurityInfo specificando come object type "SE_KERNEL_OBJECT", come security information "LABEL_SECURITY_INFORMATION" e infine la SACL nell'ultimo parametro.
Le SACL sono nate per ospitare le informazioni sull'auditing degli oggetti e sono accessibili solo dagli administrators.
Il mio target era invece quello di poter modificare gli integrity level / policy senza richiedere l'elevazione con UAC.
Il "trucco" sta nell'API SetSecurityInfo con parametro "LABEL_SECURITY_INFORMATION". Impostando le SACL con altre API l'operazione fallirebbe con un accesso negato e sarebbe perciò necessario elevare il processo ad administrator.
Il listato per questa sequenza di chiamate è più lungo e il blog non mi sembra il posto più indicato dove farlo. Ad ogni modo le chiamate sopra citate fanno parte della mia utility (scritta in C++) e quindi sono assolutamente collaudate. Basta un minimo di pazienza e il gioco è fatto.
La lettura degli integrity level è del tutto analoga e consiste nel chiamare GetSecurityInfo con "LABEL_SECURITY_INFORMATION" ottenendo le Sacl da cui estrarre le ACE di tipo "SYSTEM_MANDATORY_LABEL_ACE_TYPE" che contengono le informazioni su Integrity Level e Policy.
Tool: AccessChk
AccessChk di Mark Russinovich permette di verificare l'accesso ad un oggetto e mostrare la relativa security. Per esempio nel caso del file di notepad a cui abbiamo modificato l'Integrity Level a Low, ecco il risultato:
C:\Temp>c:\util\SysinternalsSuite\accesschk -e notepad.exe
Accesschk v4.20 - Reports effective permissions for securable objects
Copyright (C) 2006-2008 Mark Russinovich
Sysinternals - www.sysinternals.com
C:\Temp\notepad.exe
Low Mandatory Level [No-Write-Up, No-Read-Up, No-Execute-Up]
RW XYZ\Raf
RW BUILTIN\Administrators
RW NT AUTHORITY\SYSTEM
R BUILTIN\Users
Tool: Process Explorer
Process Explorer è il famoso tool sempre della suite SysInternals, che forinisce centinaia di informazioni interessanti. Tra queste possiamo vedere l'Integrity Level nel token del processo di Notepad che abbiamo lanciato grazie al primo listato del post.
Lo stesso "Low Mandatory Label" sarebbe visibile nel processo di Internet Explorer in Protected Mode.
Gli Integrity Levels sono il mattoncino per un'altra novità fondamentale in Vista che è UIPI.
[more to come ...]
Parte 4: http://blogs.ugidotnet.org/raffaele/archive/2009/02/09/windows-vista-uipi-parte-4.aspx
Era il 1989 e il grande Doc, non conoscendo ancora la nuova generazione di utenti, diceva: "È meglio che mi dedichi a studiare l'altro grande mistero dell'universo... le donne.".
Da allora i geek sono stati sopraffatti da una nuova specie: gli utenti.
Utente è colui che quando vede una mail con scritto "hai vinto" ... clicca; compra dozzine di pillole di tutti i colori; è il rarissimo vincitore ... di una partecipazione a giocare d'azzardo (?); sente la necessità di "allargarsi"; ...
Ma spazia anche oltre perché l'Utente ha sempre detto di detestare il PC e tutto ciò che è tecnologico ma (c'è sempre un ma) non appena ha capito che esisteva il P2P e poteva scroccare film e musica ha imparato ad usare, installare, etc. etc. Ma siccome non è tutto oro quello che luccica, anche a incriccarsi il PC e chiamare il cugino del cugino per sistemarlo.
L'Utente ha fiducia cieca nell'antivirus, e mentre gira gli sembra di vedere il Dr Welby che fa uno dei suoi miracoli.
Così scarica il mondo di applicazioni incriccate, le avvia e gli tocca rivolgersi al Dr Quincy perché gli antivirus sono arrivati al capolinea e molto presto non serviranno più a nulla. A quelli che non ci credono mi possono portare il PC così gli creo "ad hoc" un virus su misura e sconosciuto agli antivirus: nella richiesta si prega di specificare se è per Windows 9x, XP, Linux (specificare la distro), FreeBsd o la variante Mac.
A questo Utente è stata offerta la UAC che ricorda all'utente che l'operazione che sta facendo può modificare in qualche modo la stabilità del sistema operativo. UAC è un modo per rendere consapevole l'utente che esiste un rischio diretto o indiretto nell'operazione che ha chiesto di eseguire. UAC permette tutto questo senza richiedere la password come invece accade nei sistemi *nix con Sudo.
Ma l'Utente aveva ancora memoria dell'istinto primordiale di quando odiava la tecnologia, di quando non voleva neppure capire come funzionasse, e anche se l'era pre-P2P era già passata da un pezzo, Vista evidenziò il lato schizzinoso dell'Utente.
E l'Utente dapprima rigettò Vista ma per avere, come accadeva a Camogli, il 'diritto al mugugno' cambiò idea, prese Vista e rigettò UAC.
E così Microsoft decise di ascoltare l'Utente e di introdurre in Windows 7 una diabolica slider che diminuisce il numero di volte in cui la UAC avverte l'utente. Le applicazioni parte del sistema operativo avrebbero taciuto.
Ma non si erano bevuti il cervello all'epoca di Vista, non era sbagliato chiedere all'Utente *sempre* il permesso. E infatti puntualmente le conseguenze: http://www.istartedsomething.com/20090130/uac-security-flaw-windows-7-beta-proof/
A quanto sembra Microsoft dice che è "by design". Mai avrei potuto essere più daccordo.
Microsoft ascolta gli "Utenti"? Per favore prima facciamo un distinguo su quali U/utenti andrebbero ascoltati.
I misteri di Doc oltre che misteriosi sono affascinanti, chiedo scusa alle donne per aver mischiato il fascino con il profano.