mirror of
https://github.com/gnustep/libs-ec.git
synced 2025-02-16 08:31:19 +00:00
Improve key entry code
This commit is contained in:
parent
8c2e4d44ce
commit
5967901af8
8 changed files with 793 additions and 553 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
||||||
|
2018-03-02 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Control.m:
|
||||||
|
* EcControl.m:
|
||||||
|
* EcProcess.h:
|
||||||
|
* EcProcess.m:
|
||||||
|
Allow EcControlKey to be an MD5 digest of the expected key, so we can
|
||||||
|
easily tell if the expected key was entered correctly.
|
||||||
|
Expose method to request entry of a hexadecimal key, with checking
|
||||||
|
against an MD5 digest of the expected value.
|
||||||
|
|
||||||
2018-02-23 Richard Frith-Macdonald <rfm@gnu.org>
|
2018-02-23 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* AlarmTool.m: Add default values for arguments, suitable for sending
|
* AlarmTool.m: Add default values for arguments, suitable for sending
|
||||||
|
|
198
Control.m
198
Control.m
|
@ -32,144 +32,12 @@
|
||||||
#import "EcProcess.h"
|
#import "EcProcess.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <termios.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static size_t
|
|
||||||
trim(char *str)
|
|
||||||
{
|
|
||||||
size_t len = 0;
|
|
||||||
char *frontp = str - 1;
|
|
||||||
char *endp = NULL;
|
|
||||||
|
|
||||||
if (NULL == str || '\0' == str[0])
|
#if !defined(EC_DEFAULTS_PREFIX)
|
||||||
{
|
#define EC_DEFAULTS_PREFIX nil
|
||||||
return 0;
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
len = strlen(str);
|
|
||||||
endp = str + len;
|
|
||||||
|
|
||||||
while (isspace(*(++frontp)))
|
|
||||||
;
|
|
||||||
|
|
||||||
while (isspace(*(--endp)) && endp != frontp)
|
|
||||||
;
|
|
||||||
|
|
||||||
if (str + len - 1 != endp)
|
|
||||||
{
|
|
||||||
*(endp + 1) = '\0';
|
|
||||||
}
|
|
||||||
else if (frontp != str && endp == frontp)
|
|
||||||
{
|
|
||||||
*str = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frontp != str)
|
|
||||||
{
|
|
||||||
endp = str;
|
|
||||||
while (*frontp)
|
|
||||||
{
|
|
||||||
*endp++ = *frontp++;
|
|
||||||
}
|
|
||||||
*endp = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return endp - str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL
|
|
||||||
getkey(NSString **key)
|
|
||||||
{
|
|
||||||
FILE *stream;
|
|
||||||
struct termios old;
|
|
||||||
struct termios new;
|
|
||||||
char *one = NULL;
|
|
||||||
char *two = NULL;
|
|
||||||
|
|
||||||
#define MINKEY 16
|
|
||||||
|
|
||||||
/* Open the terminal
|
|
||||||
*/
|
|
||||||
if ((stream = fopen("/dev/tty", "r+")) == NULL)
|
|
||||||
{
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
/* Turn echoing off
|
|
||||||
*/
|
|
||||||
if (tcgetattr(fileno(stream), &old) != 0)
|
|
||||||
{
|
|
||||||
fclose(stream);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
new = old;
|
|
||||||
new.c_lflag &= ~ECHO;
|
|
||||||
if (tcsetattr (fileno(stream), TCSAFLUSH, &new) != 0)
|
|
||||||
{
|
|
||||||
fclose(stream);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (NULL == one || NULL == two)
|
|
||||||
{
|
|
||||||
int olen = 0;
|
|
||||||
int tlen = 0;
|
|
||||||
|
|
||||||
while (olen < MINKEY)
|
|
||||||
{
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
fprintf(stream, "\nPlease enter EcControlKey: ");
|
|
||||||
if (one != NULL) { free(one); one = NULL; }
|
|
||||||
olen = getline(&one, &len, stream);
|
|
||||||
if (olen < 0)
|
|
||||||
{
|
|
||||||
if (one != NULL) { free(one); one = NULL; }
|
|
||||||
fclose(stream);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
olen = trim(one);
|
|
||||||
if (olen < MINKEY)
|
|
||||||
{
|
|
||||||
fprintf(stream, "\nKey must be at least %u characters\n", MINKEY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (0 == tlen)
|
|
||||||
{
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
fprintf(stream, "\nPlease re-enter to confirm: ");
|
|
||||||
if (two != NULL) { free(two); two = NULL; }
|
|
||||||
tlen = getline(&two, &len, stream);
|
|
||||||
if (tlen < 0)
|
|
||||||
{
|
|
||||||
if (one != NULL) { free(one); one = NULL; }
|
|
||||||
if (two != NULL) { free(two); two = NULL; }
|
|
||||||
fclose(stream);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
tlen = trim(two);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(one, two) != 0)
|
|
||||||
{
|
|
||||||
free(one); one = NULL;
|
|
||||||
free(two); two = NULL;
|
|
||||||
fprintf(stream, "\nKeys do not match, please try again.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore terminal. */
|
|
||||||
(void) tcsetattr(fileno(stream), TCSAFLUSH, &old);
|
|
||||||
|
|
||||||
*key = [NSString stringWithUTF8String: one];
|
|
||||||
free(one);
|
|
||||||
free(two);
|
|
||||||
fprintf(stream, "\nEcControlKey accepted.\n");
|
|
||||||
fclose(stream);
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(EC_BASE_CLASS)
|
#if !defined(EC_BASE_CLASS)
|
||||||
#define EC_BASE_CLASS EcControl
|
#define EC_BASE_CLASS EcControl
|
||||||
|
@ -203,6 +71,7 @@ main(int argc, char *argv[])
|
||||||
NSString *path = [[NSBundle mainBundle] executablePath];
|
NSString *path = [[NSBundle mainBundle] executablePath];
|
||||||
NSAutoreleasePool *inner = nil;
|
NSAutoreleasePool *inner = nil;
|
||||||
BOOL done = NO;
|
BOOL done = NO;
|
||||||
|
NSUInteger index = NSNotFound;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
NSTask *t;
|
NSTask *t;
|
||||||
|
|
||||||
|
@ -210,20 +79,43 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
if ([pArgs containsObject: @"--Watcher"] == NO)
|
if ([pArgs containsObject: @"--Watcher"] == NO)
|
||||||
{
|
{
|
||||||
/* In the top level task ... set flags to create a subtask
|
NSUserDefaults *defs;
|
||||||
* to act as a watcher for other tasks, and once that has
|
NSString *str;
|
||||||
* been created, exit to leave it running as a daemon.
|
|
||||||
*/
|
defs = [NSUserDefaults standardUserDefaults];
|
||||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:
|
str = [defs stringForKey: @"EcControlKey"];
|
||||||
@"EcControlKey"] == YES)
|
if ([str length] == 32 || [str boolValue] == YES)
|
||||||
{
|
{
|
||||||
if (getkey(&key) == NO)
|
NSData *digest = nil;
|
||||||
|
|
||||||
|
if ([str length] == 32)
|
||||||
|
{
|
||||||
|
/* Check that the 32 character value is hex digits,
|
||||||
|
* in which case it should be the MD5 digest of the
|
||||||
|
* actual key to be entered.
|
||||||
|
*/
|
||||||
|
digest = AUTORELEASE([[NSData alloc]
|
||||||
|
initWithHexadecimalRepresentation: str]);
|
||||||
|
if ([digest length] != 16)
|
||||||
|
{
|
||||||
|
NSLog(@"Bad values specified in EcControlKey... abort");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key = [EcProcess ecGetKey: "EcControlKey"
|
||||||
|
size: 32
|
||||||
|
md5: digest];
|
||||||
|
if (nil == key)
|
||||||
{
|
{
|
||||||
NSLog(@"Failed to read EcControlKey from terminal ... abort");
|
NSLog(@"Failed to read EcControlKey from terminal ... abort");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* In the top level task ... set flags to create a subtask
|
||||||
|
* to act as a watcher for other tasks, and once that has
|
||||||
|
* been created, exit to leave it running as a daemon.
|
||||||
|
*/
|
||||||
[args addObject: @"--Watcher"];
|
[args addObject: @"--Watcher"];
|
||||||
t = [NSTask new];
|
t = [NSTask new];
|
||||||
NS_DURING
|
NS_DURING
|
||||||
|
@ -267,8 +159,26 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
/* Set args to tell subtask task not to make itself a daemon
|
/* Set args to tell subtask task not to make itself a daemon
|
||||||
*/
|
*/
|
||||||
[args addObject: @"-Daemon"];
|
if (EC_DEFAULTS_PREFIX != nil)
|
||||||
[args addObject: @"NO"];
|
{
|
||||||
|
NSString *str;
|
||||||
|
|
||||||
|
str = [NSString stringWithFormat: @"-%@Daemon", EC_DEFAULTS_PREFIX];
|
||||||
|
index = [args indexOfObject: str];
|
||||||
|
}
|
||||||
|
if (NSNotFound == index)
|
||||||
|
{
|
||||||
|
index = [args indexOfObject: @"-Daemon"];
|
||||||
|
}
|
||||||
|
if (NSNotFound != index)
|
||||||
|
{
|
||||||
|
[args replaceObjectAtIndex: index + 1 withObject: @"NO"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[args addObject: @"-Daemon"];
|
||||||
|
[args addObject: @"NO"];
|
||||||
|
}
|
||||||
|
|
||||||
/* Set args to tell task it is being watched.
|
/* Set args to tell task it is being watched.
|
||||||
*/
|
*/
|
||||||
|
|
45
EcControl.m
45
EcControl.m
|
@ -2758,6 +2758,7 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
NSMutableDictionary *root;
|
NSMutableDictionary *root;
|
||||||
NSEnumerator *rootEnum;
|
NSEnumerator *rootEnum;
|
||||||
id hostKey;
|
id hostKey;
|
||||||
|
NSString *digest = nil;
|
||||||
|
|
||||||
if ([conf isKindOfClass: [NSDictionary class]] == NO)
|
if ([conf isKindOfClass: [NSDictionary class]] == NO)
|
||||||
{
|
{
|
||||||
|
@ -2775,6 +2776,50 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
* applications/classes levels of the configuration.
|
* applications/classes levels of the configuration.
|
||||||
*/
|
*/
|
||||||
conf = [self recursiveInclude: conf];
|
conf = [self recursiveInclude: conf];
|
||||||
|
|
||||||
|
/* Get the EcControlKey from the generic area of the configuration.
|
||||||
|
* If present, this should be an MD5 digest of the actual key.
|
||||||
|
*/
|
||||||
|
if ([[conf objectForKey: @"*"] isKindOfClass: [NSDictionary class]]
|
||||||
|
&& [[[conf objectForKey: @"*"] objectForKey: @"*"]
|
||||||
|
isKindOfClass: [NSDictionary class]])
|
||||||
|
{
|
||||||
|
digest = [[[conf objectForKey: @"*"] objectForKey: @"*"]
|
||||||
|
objectForKey: @"EcControlKey"];
|
||||||
|
}
|
||||||
|
if ([controlKey length] > 0 && nil == digest)
|
||||||
|
{
|
||||||
|
ASSIGN(configFailed,
|
||||||
|
@"EcControlKey supplied on startup but not in Control.plist");
|
||||||
|
[[self cmdLogFile: logname] printf: @"%@", configFailed];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if ([controlKey length] == 0 && digest != nil)
|
||||||
|
{
|
||||||
|
ASSIGN(configFailed,
|
||||||
|
@"EcControlKey configured but no value supplied on startup");
|
||||||
|
[[self cmdLogFile: logname] printf: @"%@", configFailed];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if (digest != nil)
|
||||||
|
{
|
||||||
|
NSData *key;
|
||||||
|
NSData *md5;
|
||||||
|
NSString *hex;
|
||||||
|
|
||||||
|
key = [[NSData alloc] initWithHexadecimalRepresentation: controlKey];
|
||||||
|
md5 = [key md5Digest];
|
||||||
|
RELEASE(key);
|
||||||
|
hex = [md5 hexadecimalRepresentation];
|
||||||
|
if (NO == [digest isEqual: hex])
|
||||||
|
{
|
||||||
|
ASSIGN(configFailed,
|
||||||
|
@"EcControlKey is not the MD5 digest of value from startup");
|
||||||
|
[[self cmdLogFile: logname] printf: @"%@", configFailed];
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[conf writeToFile: @"/tmp/Control.cnf" atomically: YES];
|
[conf writeToFile: @"/tmp/Control.cnf" atomically: YES];
|
||||||
[mgr changeFileAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
|
[mgr changeFileAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithInt: 0666], NSFilePosixPermissions,
|
[NSNumber numberWithInt: 0666], NSFilePosixPermissions,
|
||||||
|
|
18
EcProcess.h
18
EcProcess.h
|
@ -182,6 +182,7 @@ typedef enum {
|
||||||
* Useful functions -
|
* Useful functions -
|
||||||
*/
|
*/
|
||||||
extern void cmdSetHome(NSString *home);
|
extern void cmdSetHome(NSString *home);
|
||||||
|
extern NSString* cmdDataDir();
|
||||||
extern NSString* cmdLogsDir(NSString *date);
|
extern NSString* cmdLogsDir(NSString *date);
|
||||||
extern NSString* cmdLogKey(EcLogType t);
|
extern NSString* cmdLogKey(EcLogType t);
|
||||||
extern NSString* cmdLogName();
|
extern NSString* cmdLogName();
|
||||||
|
@ -408,6 +409,23 @@ extern NSString* cmdVersion(NSString *ver);
|
||||||
*/
|
*/
|
||||||
@interface EcProcess : NSObject <CmdClient,EcAlarmDestination>
|
@interface EcProcess : NSObject <CmdClient,EcAlarmDestination>
|
||||||
|
|
||||||
|
/** This method is provided to prompt for an encryptionkey using the
|
||||||
|
* specified key name and read in a value from the terminal.<br />
|
||||||
|
* The entered value must be an even numbered sequence of hexadecimal
|
||||||
|
* digits, each pair representing one byte of the key.<br />
|
||||||
|
* The key length (number of bytes) must be the specified size, a value
|
||||||
|
* between 16 and 128, which is exactly half the number of hexadecimal
|
||||||
|
* digits that must be entered.<br />
|
||||||
|
* If the digest is not supplied, the user will be required to
|
||||||
|
* enter the value twice (and the two values must match) for
|
||||||
|
* confirmation.<br />
|
||||||
|
* If the digest is supplied, the md5 digest of the entered key must
|
||||||
|
* match it (but the user does not need to enter the value twice).
|
||||||
|
*/
|
||||||
|
+ (NSString*) ecGetKey: (const char*)name
|
||||||
|
size: (unsigned)size
|
||||||
|
md5: (NSData*)digest;
|
||||||
|
|
||||||
/** Provides initial configuration.
|
/** Provides initial configuration.
|
||||||
* This method is used by -init and its return value is passed to
|
* This method is used by -init and its return value is passed to
|
||||||
* -initWithDefaults: method.<br />
|
* -initWithDefaults: method.<br />
|
||||||
|
|
1067
EcProcess.m
1067
EcProcess.m
File diff suppressed because it is too large
Load diff
|
@ -94,6 +94,9 @@
|
||||||
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
|
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
|
||||||
#undef HAVE_SYS_WAIT_H
|
#undef HAVE_SYS_WAIT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <termios.h> header file. */
|
||||||
|
#undef HAVE_TERMIOS_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
#undef HAVE_UNISTD_H
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -3581,7 +3581,7 @@ fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
for ac_header in arpa/inet.h arpa/telnet.h netinet/in.h netdb.h pwd.h string.h fcntl.h sys/fcntl.h sys/file.h sys/resource.h sys/time.h sys/types.h sys/socket.h sys/signal.h stdlib.h unistd.h
|
for ac_header in arpa/inet.h arpa/telnet.h netinet/in.h netdb.h pwd.h string.h fcntl.h sys/fcntl.h sys/file.h sys/resource.h sys/time.h sys/types.h sys/socket.h sys/signal.h stdlib.h unistd.h termios.h
|
||||||
do :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||||
|
|
|
@ -35,7 +35,7 @@ AC_TYPE_SIGNAL
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
AC_HEADER_SYS_WAIT
|
AC_HEADER_SYS_WAIT
|
||||||
AC_CHECK_HEADERS(arpa/inet.h arpa/telnet.h netinet/in.h netdb.h pwd.h string.h fcntl.h sys/fcntl.h sys/file.h sys/resource.h sys/time.h sys/types.h sys/socket.h sys/signal.h stdlib.h unistd.h)
|
AC_CHECK_HEADERS(arpa/inet.h arpa/telnet.h netinet/in.h netdb.h pwd.h string.h fcntl.h sys/fcntl.h sys/file.h sys/resource.h sys/time.h sys/types.h sys/socket.h sys/signal.h stdlib.h unistd.h termios.h)
|
||||||
|
|
||||||
AC_TYPE_GETGROUPS
|
AC_TYPE_GETGROUPS
|
||||||
AC_TYPE_SIGNAL
|
AC_TYPE_SIGNAL
|
||||||
|
|
Loading…
Reference in a new issue