mirror of
https://github.com/gnustep/libs-ec.git
synced 2025-02-15 16:11:01 +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>
|
||||
|
||||
* AlarmTool.m: Add default values for arguments, suitable for sending
|
||||
|
|
194
Control.m
194
Control.m
|
@ -32,144 +32,12 @@
|
|||
#import "EcProcess.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <termios.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])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_DEFAULTS_PREFIX)
|
||||
#define EC_DEFAULTS_PREFIX nil
|
||||
#endif
|
||||
|
||||
#if !defined(EC_BASE_CLASS)
|
||||
#define EC_BASE_CLASS EcControl
|
||||
|
@ -203,6 +71,7 @@ main(int argc, char *argv[])
|
|||
NSString *path = [[NSBundle mainBundle] executablePath];
|
||||
NSAutoreleasePool *inner = nil;
|
||||
BOOL done = NO;
|
||||
NSUInteger index = NSNotFound;
|
||||
int status = 0;
|
||||
NSTask *t;
|
||||
|
||||
|
@ -210,20 +79,43 @@ main(int argc, char *argv[])
|
|||
|
||||
if ([pArgs containsObject: @"--Watcher"] == NO)
|
||||
{
|
||||
/* 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.
|
||||
*/
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:
|
||||
@"EcControlKey"] == YES)
|
||||
NSUserDefaults *defs;
|
||||
NSString *str;
|
||||
|
||||
defs = [NSUserDefaults standardUserDefaults];
|
||||
str = [defs stringForKey: @"EcControlKey"];
|
||||
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");
|
||||
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"];
|
||||
t = [NSTask new];
|
||||
NS_DURING
|
||||
|
@ -267,8 +159,26 @@ main(int argc, char *argv[])
|
|||
|
||||
/* Set args to tell subtask task not to make itself a daemon
|
||||
*/
|
||||
if (EC_DEFAULTS_PREFIX != nil)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
|
45
EcControl.m
45
EcControl.m
|
@ -2758,6 +2758,7 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
|||
NSMutableDictionary *root;
|
||||
NSEnumerator *rootEnum;
|
||||
id hostKey;
|
||||
NSString *digest = nil;
|
||||
|
||||
if ([conf isKindOfClass: [NSDictionary class]] == NO)
|
||||
{
|
||||
|
@ -2775,6 +2776,50 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
|||
* applications/classes levels of the configuration.
|
||||
*/
|
||||
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];
|
||||
[mgr changeFileAttributes: [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt: 0666], NSFilePosixPermissions,
|
||||
|
|
18
EcProcess.h
18
EcProcess.h
|
@ -182,6 +182,7 @@ typedef enum {
|
|||
* Useful functions -
|
||||
*/
|
||||
extern void cmdSetHome(NSString *home);
|
||||
extern NSString* cmdDataDir();
|
||||
extern NSString* cmdLogsDir(NSString *date);
|
||||
extern NSString* cmdLogKey(EcLogType t);
|
||||
extern NSString* cmdLogName();
|
||||
|
@ -408,6 +409,23 @@ extern NSString* cmdVersion(NSString *ver);
|
|||
*/
|
||||
@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.
|
||||
* This method is used by -init and its return value is passed to
|
||||
* -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. */
|
||||
#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. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -3581,7 +3581,7 @@ fi
|
|||
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 :
|
||||
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"
|
||||
|
|
|
@ -35,7 +35,7 @@ AC_TYPE_SIGNAL
|
|||
AC_HEADER_STDC
|
||||
AC_HEADER_TIME
|
||||
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_SIGNAL
|
||||
|
|
Loading…
Reference in a new issue