Index: sbin/geom/class/eli/geom_eli.c =================================================================== --- sbin/geom/class/eli/geom_eli.c (wersja 182434) +++ sbin/geom/class/eli/geom_eli.c (kopia robocza) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004-2006 Pawel Jakub Dawidek + * Copyright (c) 2004-2008 Pawel Jakub Dawidek * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,6 +54,8 @@ uint32_t lib_version = G_LIB_VERSION; uint32_t version = G_ELI_VERSION; +#define GELI_BACKUP_DIR "/var/backups/" + static char aalgo[] = "none"; static char ealgo[] = "aes"; static intmax_t keylen = 0; @@ -61,6 +63,7 @@ static intmax_t iterations = -1; static intmax_t sectorsize = 0; static char keyfile[] = "", newkeyfile[] = ""; +static char backupfile[] = ""; static void eli_main(struct gctl_req *req, unsigned flags); static void eli_init(struct gctl_req *req); @@ -74,10 +77,13 @@ static void eli_clear(struct gctl_req *req); static void eli_dump(struct gctl_req *req); +static int eli_backup_create(struct gctl_req *req, const char *prov, + const char *file); + /* * Available commands: * - * init [-bhPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov + * init [-bhPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] prov * label - alias for 'init' * attach [-dprv] [-k keyfile] prov * detach [-fl] prov ... @@ -97,6 +103,7 @@ { { 'a', "aalgo", aalgo, G_TYPE_STRING }, { 'b', "boot", NULL, G_TYPE_BOOL }, + { 'B', "backupfile", backupfile, G_TYPE_STRING }, { 'e', "ealgo", ealgo, G_TYPE_STRING }, { 'i', "iterations", &iterations, G_TYPE_NUMBER }, { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, @@ -105,12 +112,13 @@ { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, G_OPT_SENTINEL }, - NULL, "[-bPv] [-a aalgo] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" + NULL, "[-bPv] [-a aalgo] [-B backupfile] [-e ealgo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" }, { "label", G_FLAG_VERBOSE, eli_main, { { 'a', "aalgo", aalgo, G_TYPE_STRING }, { 'b', "boot", NULL, G_TYPE_BOOL }, + { 'B', "backupfile", backupfile, G_TYPE_STRING }, { 'e', "ealgo", ealgo, G_TYPE_STRING }, { 'i', "iterations", &iterations, G_TYPE_NUMBER }, { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, @@ -514,6 +522,7 @@ struct g_eli_metadata md; unsigned char sector[sizeof(struct g_eli_metadata)]; unsigned char key[G_ELI_USERKEYLEN]; + char backfile[MAXPATHLEN]; const char *str, *prov; unsigned secsize; off_t mediasize; @@ -648,6 +657,32 @@ } if (verbose) printf("Metadata value stored on %s.\n", prov); + /* Backup metadata to a file. */ + str = gctl_get_ascii(req, "backupfile"); + if (str[0] != '\0') { + /* Backupfile given be the user, just copy it. */ + strlcpy(backfile, str, sizeof(backfile)); + } else { + /* Generate file name automatically. */ + const char *p = prov; + unsigned int i; + + if (strncmp(p, _PATH_DEV, strlen(_PATH_DEV)) == 0) + p += strlen(_PATH_DEV); + snprintf(backfile, sizeof(backfile), "%s%s.eli", + GELI_BACKUP_DIR, p); + /* Replace all / with _. */ + for (i = strlen(GELI_BACKUP_DIR); backfile[i] != '\0'; i++) { + if (backfile[i] == '/') + backfile[i] = '_'; + } + } + if (strcmp(backfile, "none") != 0 && + eli_backup_create(req, prov, backfile) == 0) { + printf("\nMetadata backup can be found in %s and\n", backfile); + printf("can be restored with the following command:\n"); + printf("\n\t# geli restore %s %s\n\n", backfile, prov); + } } static void @@ -887,6 +922,12 @@ eli_setkey_attached(req, &md); else eli_setkey_detached(req, prov, &md); + + if (req->error == NULL || req->error[0] == '\0') { + printf("Note, that the master key encrypted with old keys " + "and/or passphrase may still exists in a metadata backup " + "file.\n"); + } } static void @@ -1022,24 +1063,16 @@ gctl_issue(req); } -static void -eli_backup(struct gctl_req *req) +static int +eli_backup_create(struct gctl_req *req, const char *prov, const char *file) { struct g_eli_metadata md; - const char *file, *prov; unsigned secsize; unsigned char *sector; off_t mediasize; - int nargs, filefd, provfd; + int filefd, provfd, ret; - nargs = gctl_get_int(req, "nargs"); - if (nargs != 2) { - gctl_error(req, "Invalid number of arguments."); - return; - } - prov = gctl_get_ascii(req, "arg0"); - file = gctl_get_ascii(req, "arg1"); - + ret = -1; provfd = filefd = -1; sector = NULL; secsize = 0; @@ -1092,6 +1125,8 @@ strerror(errno)); goto out; } + /* Success. */ + ret = 0; out: if (provfd > 0) close(provfd); @@ -1101,9 +1136,27 @@ bzero(sector, secsize); free(sector); } + return (ret); } static void +eli_backup(struct gctl_req *req) +{ + const char *file, *prov; + int nargs; + + nargs = gctl_get_int(req, "nargs"); + if (nargs != 2) { + gctl_error(req, "Invalid number of arguments."); + return; + } + prov = gctl_get_ascii(req, "arg0"); + file = gctl_get_ascii(req, "arg1"); + + eli_backup_create(req, prov, file); +} + +static void eli_restore(struct gctl_req *req) { struct g_eli_metadata md; Index: sbin/geom/class/eli/geli.8 =================================================================== --- sbin/geom/class/eli/geli.8 (wersja 182451) +++ sbin/geom/class/eli/geli.8 (kopia robocza) @@ -1,4 +1,4 @@ -.\" Copyright (c) 2005-2006 Pawel Jakub Dawidek +.\" Copyright (c) 2005-2008 Pawel Jakub Dawidek .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 16, 2006 +.Dd August 29, 2008 .Dt GELI 8 .Os .Sh NAME @@ -53,6 +53,7 @@ .Cm init .Op Fl bPv .Op Fl a Ar aalgo +.Op Fl B Ar backupfile .Op Fl e Ar ealgo .Op Fl i Ar iterations .Op Fl K Ar newkeyfile @@ -206,6 +207,14 @@ Initialize provider which needs to be encrypted. Here you can set up the cryptographic algorithm to use, key length, etc. The last provider's sector is used to store metadata. +The +.Cm init +subcommand also automatically backups metadata in +.Pa /var/backups/.eli +file. +The metadata can be recovered with the +.Cm restore +subcommand described below. .Pp Additional options include: .Bl -tag -width ".Fl a Ar aalgo" @@ -233,6 +242,13 @@ .Pa /boot/ directory, which can be a CD-ROM disc or USB pen-drive, that can be removed after boot. +.It Fl B Ar backupfile +File name to use for metadata backup instead of the default +.Pa /var/backups/.eli . +To inhibit backups, you can use +.Pa none +as the +.Ar backupfile . .It Fl e Ar ealgo Encryption algorithm to use. Currently supported algorithms are: @@ -625,6 +641,30 @@ # newfs /dev/da0.eli # mount /dev/da0.eli /mnt/secret .Ed +.Pp +.Cm geli +backups metadata by default to the +.Pa /var/backups/.eli +file. +If metadata is lost in any way (eg. by accidental overwrite), it can be restored. +Consider the following situation: +.Bd -literal -offset indent +# geli init /dev/da0 +Enter new passphrase: +Reenter new passphrase: + +Metadata backup can be found in /var/backups/da0.eli and +can be restored with the following command: + + # geli restore /var/backups/da0.eli /dev/da0 + +# geli clear /dev/da0 +# geli attach /dev/da0 +geli: Cannot read metadata from /dev/da0: Invalid argument. +# geli restore /var/backups/da0.eli /dev/da0 +# geli attach /dev/da0 +Enter passphrase: +.Ed .Sh DATA AUTHENTICATION .Nm can verify data integrity when an authentication algorithm is specified. Index: tools/regression/geom_eli/readonly.t =================================================================== --- tools/regression/geom_eli/readonly.t (wersja 182434) +++ tools/regression/geom_eli/readonly.t (kopia robocza) @@ -11,7 +11,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 -geli init -P -K $keyfile md${no} +geli init -B none -P -K $keyfile md${no} if [ $? -eq 0 ]; then echo "ok 1" else Index: tools/regression/geom_eli/delkey.t =================================================================== --- tools/regression/geom_eli/delkey.t (wersja 182434) +++ tools/regression/geom_eli/delkey.t (kopia robocza) @@ -17,7 +17,7 @@ dd if=/dev/random of=${keyfile3} bs=512 count=16 >/dev/null 2>&1 dd if=/dev/random of=${keyfile4} bs=512 count=16 >/dev/null 2>&1 -geli init -P -K $keyfile1 md${no} +geli init -B none -P -K $keyfile1 md${no} geli attach -p -k $keyfile1 md${no} geli setkey -n 1 -P -K $keyfile2 md${no} Index: tools/regression/geom_eli/configure-b-B.t =================================================================== --- tools/regression/geom_eli/configure-b-B.t (wersja 182434) +++ tools/regression/geom_eli/configure-b-B.t (kopia robocza) @@ -8,7 +8,7 @@ echo "1..17" -geli init -P -K /dev/null md${no} +geli init -B none -P -K /dev/null md${no} if [ $? -eq 0 ]; then echo "ok 1" else @@ -22,7 +22,7 @@ echo "not ok 2" fi -geli init -b -P -K /dev/null md${no} +geli init -B none -b -P -K /dev/null md${no} if [ $? -eq 0 ]; then echo "ok 3" else Index: tools/regression/geom_eli/init-a.t =================================================================== --- tools/regression/geom_eli/init-a.t (wersja 182434) +++ tools/regression/geom_eli/init-a.t (kopia robocza) @@ -24,7 +24,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 - geli init -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null + geli init -B none -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null geli attach -p -k $keyfile md${no} secs=`diskinfo /dev/md${no}.eli | awk '{print $4}'` Index: tools/regression/geom_eli/detach-l.t =================================================================== --- tools/regression/geom_eli/detach-l.t (wersja 182434) +++ tools/regression/geom_eli/detach-l.t (kopia robocza) @@ -11,7 +11,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 -geli init -P -K $keyfile md${no} +geli init -B none -P -K $keyfile md${no} geli attach -p -k $keyfile md${no} if [ -c /dev/md${no}.eli ]; then echo "ok 1" Index: tools/regression/geom_eli/init-B.t =================================================================== --- tools/regression/geom_eli/init-B.t (wersja 0) +++ tools/regression/geom_eli/init-B.t (wersja 0) @@ -0,0 +1,106 @@ +#!/bin/sh +# $FreeBSD$ + +base=`basename $0` +no=45 +sectors=100 +keyfile=`mktemp /tmp/$base.XXXXXX` || exit 1 +backupfile=`mktemp /tmp/$base.XXXXXX` || exit 1 + +echo "1..13" + +dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 + +mdconfig -a -t malloc -s $sectors -u $no || exit 1 + +# -B none +rm -f /var/backups/md${no}.eli +geli init -B none -P -K $keyfile md${no} 2>/dev/null +if [ ! -f /var/backups/md${no}.eli ]; then + echo "ok 1 - -B none" +else + echo "not ok 1 - -B none" +fi + +# no -B +rm -f /var/backups/md${no}.eli +geli init -P -K $keyfile md${no} >/dev/null 2>&1 +if [ -f /var/backups/md${no}.eli ]; then + echo "ok 2 - no -B" +else + echo "not ok 2 - no -B" +fi +geli clear md${no} +geli attach -p -k $keyfile md${no} 2>/dev/null +if [ $? -ne 0 ]; then + echo "ok 3 - no -B" +else + echo "not ok 3 - no -B" +fi +if [ ! -c /dev/md${no}.eli ]; then + echo "ok 4 - no -B" +else + echo "not ok 4 - no -B" +fi +geli restore /var/backups/md${no}.eli md${no} +if [ $? -eq 0 ]; then + echo "ok 5 - no -B" +else + echo "not ok 5 - no -B" +fi +geli attach -p -k $keyfile md${no} 2>/dev/null +if [ $? -eq 0 ]; then + echo "ok 6 - no -B" +else + echo "not ok 6 - no -B" +fi +if [ -c /dev/md${no}.eli ]; then + echo "ok 7 - no -B" +else + echo "not ok 7 - no -B" +fi +geli detach md${no} +rm -f /var/backups/md${no}.eli + +# -B file +rm -f $backupfile +geli init -B $backupfile -P -K $keyfile md${no} >/dev/null 2>&1 +if [ -f $backupfile ]; then + echo "ok 8 - -B file" +else + echo "not ok 8 - -B file" +fi +geli clear md${no} +geli attach -p -k $keyfile md${no} 2>/dev/null +if [ $? -ne 0 ]; then + echo "ok 9 - -B file" +else + echo "not ok 9 - -B file" +fi +if [ ! -c /dev/md${no}.eli ]; then + echo "ok 10 - -B file" +else + echo "not ok 10 - -B file" +fi +geli restore $backupfile md${no} +if [ $? -eq 0 ]; then + echo "ok 11 - -B file" +else + echo "not ok 11 - -B file" +fi +geli attach -p -k $keyfile md${no} 2>/dev/null +if [ $? -eq 0 ]; then + echo "ok 12 - -B file" +else + echo "not ok 12 - -B file" +fi +if [ -c /dev/md${no}.eli ]; then + echo "ok 13 - -B file" +else + echo "not ok 13 - -B file" +fi +geli detach md${no} +rm -f $backupfile + +mdconfig -d -u $no +rm -f $keyfile Index: tools/regression/geom_eli/integrity-hmac.t =================================================================== --- tools/regression/geom_eli/integrity-hmac.t (wersja 182434) +++ tools/regression/geom_eli/integrity-hmac.t (kopia robocza) @@ -24,7 +24,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 - geli init -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null + geli init -B none -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null geli attach -p -k $keyfile md${no} dd if=/dev/random of=/dev/md${no}.eli bs=${secsize} count=1 >/dev/null 2>&1 Index: tools/regression/geom_eli/nokey.t =================================================================== --- tools/regression/geom_eli/nokey.t (wersja 182434) +++ tools/regression/geom_eli/nokey.t (kopia robocza) @@ -9,7 +9,7 @@ echo "1..8" -geli init -P md${no} 2>/dev/null +geli init -B none -P md${no} 2>/dev/null if [ $? -ne 0 ]; then echo "ok 1" else @@ -18,7 +18,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 -geli init -P -K ${keyfile} md${no} 2>/dev/null +geli init -B none -P -K ${keyfile} md${no} 2>/dev/null if [ $? -eq 0 ]; then echo "ok 2" else Index: tools/regression/geom_eli/integrity-data.t =================================================================== --- tools/regression/geom_eli/integrity-data.t (wersja 182434) +++ tools/regression/geom_eli/integrity-data.t (kopia robocza) @@ -24,7 +24,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 - geli init -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null + geli init -B none -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null geli attach -p -k $keyfile md${no} dd if=/dev/random of=/dev/md${no}.eli bs=${secsize} count=1 >/dev/null 2>&1 Index: tools/regression/geom_eli/attach-d.t =================================================================== --- tools/regression/geom_eli/attach-d.t (wersja 182434) +++ tools/regression/geom_eli/attach-d.t (kopia robocza) @@ -11,7 +11,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 -geli init -P -K $keyfile md${no} +geli init -B none -P -K $keyfile md${no} geli attach -d -p -k $keyfile md${no} if [ -c /dev/md${no}.eli ]; then echo "ok 1" Index: tools/regression/geom_eli/integrity-copy.t =================================================================== --- tools/regression/geom_eli/integrity-copy.t (wersja 182434) +++ tools/regression/geom_eli/integrity-copy.t (kopia robocza) @@ -25,7 +25,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 - geli init -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null + geli init -B none -a $aalgo -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null geli attach -p -k $keyfile md${no} dd if=/dev/random of=/dev/md${no}.eli bs=${secsize} count=1 >/dev/null 2>&1 Index: tools/regression/geom_eli/init-i-P.t =================================================================== --- tools/regression/geom_eli/init-i-P.t (wersja 182434) +++ tools/regression/geom_eli/init-i-P.t (kopia robocza) @@ -11,7 +11,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 -geli init -i 64 -P -K ${keyfile} md${no} 2>/dev/null +geli init -B none -i 64 -P -K ${keyfile} md${no} 2>/dev/null if [ $? -ne 0 ]; then echo "ok 1" else Index: tools/regression/geom_eli/kill.t =================================================================== --- tools/regression/geom_eli/kill.t (wersja 182434) +++ tools/regression/geom_eli/kill.t (kopia robocza) @@ -13,7 +13,7 @@ dd if=/dev/random of=${keyfile1} bs=512 count=16 >/dev/null 2>&1 dd if=/dev/random of=${keyfile2} bs=512 count=16 >/dev/null 2>&1 -geli init -P -K $keyfile1 md${no} +geli init -B none -P -K $keyfile1 md${no} geli attach -p -k $keyfile1 md${no} geli setkey -n 1 -P -K $keyfile2 md${no} @@ -48,7 +48,7 @@ echo "not ok 4" fi -geli init -P -K $keyfile1 md${no} +geli init -B none -P -K $keyfile1 md${no} geli setkey -n 1 -p -k $keyfile1 -P -K $keyfile2 md${no} # Should be possible to attach with keyfile1. Index: tools/regression/geom_eli/init.t =================================================================== --- tools/regression/geom_eli/init.t (wersja 182434) +++ tools/regression/geom_eli/init.t (kopia robocza) @@ -23,7 +23,7 @@ dd if=/dev/random of=${keyfile} bs=512 count=16 >/dev/null 2>&1 - geli init -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null + geli init -B none -e $ealgo -l $keylen -P -K $keyfile -s $secsize md${no} 2>/dev/null geli attach -p -k $keyfile md${no} secs=`diskinfo /dev/md${no}.eli | awk '{print $4}'` Index: tools/regression/geom_eli/setkey.t =================================================================== --- tools/regression/geom_eli/setkey.t (wersja 182434) +++ tools/regression/geom_eli/setkey.t (kopia robocza) @@ -22,7 +22,7 @@ dd if=/dev/random of=${keyfile4} bs=512 count=16 >/dev/null 2>&1 dd if=/dev/random of=${keyfile5} bs=512 count=16 >/dev/null 2>&1 -geli init -P -K $keyfile1 md${no} +geli init -B none -P -K $keyfile1 md${no} geli attach -p -k $keyfile1 md${no} dd if=${rnd} of=/dev/md${no}.eli bs=512 count=${sectors} 2>/dev/null