Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36623712
sh-cmd.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
23 KB
Subscribers
None
sh-cmd.c
View Options
/* sh-cmd.c - The Assuan server for g13-syshelp
* Copyright (C) 2015 Werner Koch
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
<stdarg.h>
#include
<errno.h>
#include
<assert.h>
#include
"g13-syshelp.h"
#include
<assuan.h>
#include
"../common/i18n.h"
#include
"keyblob.h"
/* Local data for this server module. A pointer to this is stored in
the CTRL object of each connection. */
struct
server_local_s
{
/* The Assuan context we are working on. */
assuan_context_t
assuan_ctx
;
/* The malloced name of the device. */
char
*
devicename
;
/* A stream open for read of the device set by the DEVICE command or
NULL if no DEVICE command has been used. */
estream_t
devicefp
;
};
/* Local prototypes. */
/*
Helper functions.
*/
/* Set an error and a description. */
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
#define set_error_fail_cmd() set_error (GPG_ERR_NOT_INITIALIZED, \
"not called via userv or unknown user")
/* Skip over options. Blanks after the options are also removed. */
static
char
*
skip_options
(
const
char
*
line
)
{
while
(
spacep
(
line
))
line
++
;
while
(
*
line
==
'-'
&&
line
[
1
]
==
'-'
)
{
while
(
*
line
&&
!
spacep
(
line
))
line
++
;
while
(
spacep
(
line
))
line
++
;
}
return
(
char
*
)
line
;
}
/* Check whether the option NAME appears in LINE. */
/* static int */
/* has_option (const char *line, const char *name) */
/* { */
/* const char *s; */
/* int n = strlen (name); */
/* s = strstr (line, name); */
/* if (s && s >= skip_options (line)) */
/* return 0; */
/* return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
/* } */
/* Helper to print a message while leaving a command. */
static
gpg_error_t
leave_cmd
(
assuan_context_t
ctx
,
gpg_error_t
err
)
{
if
(
err
)
{
const
char
*
name
=
assuan_get_command_name
(
ctx
);
if
(
!
name
)
name
=
"?"
;
if
(
gpg_err_source
(
err
)
==
GPG_ERR_SOURCE_DEFAULT
)
log_error
(
"command '%s' failed: %s
\n
"
,
name
,
gpg_strerror
(
err
));
else
log_error
(
"command '%s' failed: %s <%s>
\n
"
,
name
,
gpg_strerror
(
err
),
gpg_strsource
(
err
));
}
return
err
;
}
/* The handler for Assuan OPTION commands. */
static
gpg_error_t
option_handler
(
assuan_context_t
ctx
,
const
char
*
key
,
const
char
*
value
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
(
void
)
ctrl
;
(
void
)
key
;
(
void
)
value
;
if
(
ctrl
->
fail_all_cmds
)
err
=
set_error_fail_cmd
();
else
err
=
gpg_error
(
GPG_ERR_UNKNOWN_OPTION
);
return
err
;
}
/* The handler for an Assuan RESET command. */
static
gpg_error_t
reset_notify
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
(
void
)
line
;
xfree
(
ctrl
->
server_local
->
devicename
);
ctrl
->
server_local
->
devicename
=
NULL
;
es_fclose
(
ctrl
->
server_local
->
devicefp
);
ctrl
->
server_local
->
devicefp
=
NULL
;
ctrl
->
devti
=
NULL
;
assuan_close_input_fd
(
ctx
);
assuan_close_output_fd
(
ctx
);
return
0
;
}
static
const
char
hlp_finddevice
[]
=
"FINDDEVICE <name>
\n
"
"
\n
"
"Find the device matching NAME. NAME be any identifier from
\n
"
"g13tab permissible for the user. The corresponding block
\n
"
"device is returned using a status line."
;
static
gpg_error_t
cmd_finddevice
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
tab_item_t
ti
;
const
char
*
s
;
const
char
*
name
;
name
=
skip_options
(
line
);
/* Are we allowed to use the given device? We check several names:
* 1. The full block device
* 2. The label
* 3. The final part of the block device if NAME does not have a slash.
* 4. The mountpoint
*/
for
(
ti
=
ctrl
->
client
.
tab
;
ti
;
ti
=
ti
->
next
)
if
(
!
strcmp
(
name
,
ti
->
blockdev
))
break
;
if
(
!
ti
)
{
for
(
ti
=
ctrl
->
client
.
tab
;
ti
;
ti
=
ti
->
next
)
if
(
ti
->
label
&&
!
strcmp
(
name
,
ti
->
label
))
break
;
}
if
(
!
ti
&&
!
strchr
(
name
,
'/'
))
{
for
(
ti
=
ctrl
->
client
.
tab
;
ti
;
ti
=
ti
->
next
)
{
s
=
strrchr
(
ti
->
blockdev
,
'/'
);
if
(
s
&&
s
[
1
]
&&
!
strcmp
(
name
,
s
+
1
))
break
;
}
}
if
(
!
ti
)
{
for
(
ti
=
ctrl
->
client
.
tab
;
ti
;
ti
=
ti
->
next
)
if
(
ti
->
mountpoint
&&
!
strcmp
(
name
,
ti
->
mountpoint
))
break
;
}
if
(
!
ti
)
{
err
=
set_error
(
GPG_ERR_NOT_FOUND
,
"device not configured for user"
);
goto
leave
;
}
/* Check whether we have permissions to open the device. */
{
estream_t
fp
=
es_fopen
(
ti
->
blockdev
,
"rb"
);
if
(
!
fp
)
{
err
=
gpg_error_from_syserror
();
log_error
(
"error opening '%s': %s
\n
"
,
ti
->
blockdev
,
gpg_strerror
(
err
));
goto
leave
;
}
es_fclose
(
fp
);
}
err
=
g13_status
(
ctrl
,
STATUS_BLOCKDEV
,
ti
->
blockdev
,
NULL
);
if
(
err
)
return
err
;
leave
:
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_device
[]
=
"DEVICE <name>
\n
"
"
\n
"
"Set the device used by further commands.
\n
"
"A device name or a PARTUUID string may be used.
\n
"
"Access to that device (by the g13 system) is locked
\n
"
"until a new DEVICE command or end of this process
\n
"
;
static
gpg_error_t
cmd_device
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
tab_item_t
ti
;
estream_t
fp
=
NULL
;
line
=
skip_options
(
line
);
/* # warning hardwired to /dev/sdb1 ! */
/* if (strcmp (line, "/dev/sdb1")) */
/* { */
/* err = gpg_error (GPG_ERR_ENOENT); */
/* goto leave; */
/* } */
/* Always close an open device stream of this session. */
xfree
(
ctrl
->
server_local
->
devicename
);
ctrl
->
server_local
->
devicename
=
NULL
;
es_fclose
(
ctrl
->
server_local
->
devicefp
);
ctrl
->
server_local
->
devicefp
=
NULL
;
/* Are we allowed to use the given device? */
for
(
ti
=
ctrl
->
client
.
tab
;
ti
;
ti
=
ti
->
next
)
if
(
!
strcmp
(
line
,
ti
->
blockdev
))
break
;
if
(
!
ti
)
{
err
=
set_error
(
GPG_ERR_EACCES
,
"device not configured for user"
);
goto
leave
;
}
ctrl
->
server_local
->
devicename
=
xtrystrdup
(
line
);
if
(
!
ctrl
->
server_local
->
devicename
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
/* Check whether we have permissions to open the device and keep an
FD open. */
fp
=
es_fopen
(
ctrl
->
server_local
->
devicename
,
"rb"
);
if
(
!
fp
)
{
err
=
gpg_error_from_syserror
();
log_error
(
"error opening '%s': %s
\n
"
,
ctrl
->
server_local
->
devicename
,
gpg_strerror
(
err
));
goto
leave
;
}
es_fclose
(
ctrl
->
server_local
->
devicefp
);
ctrl
->
server_local
->
devicefp
=
fp
;
fp
=
NULL
;
ctrl
->
devti
=
ti
;
/* Fixme: Take some kind of lock. */
leave
:
es_fclose
(
fp
);
if
(
err
)
{
xfree
(
ctrl
->
server_local
->
devicename
);
ctrl
->
server_local
->
devicename
=
NULL
;
ctrl
->
devti
=
NULL
;
}
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_create
[]
=
"CREATE <type>
\n
"
"
\n
"
"Create a new encrypted partition on the current device.
\n
"
"<type> must be
\"
dm-crypt
\"
for now."
;
static
gpg_error_t
cmd_create
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
estream_t
fp
=
NULL
;
line
=
skip_options
(
line
);
if
(
strcmp
(
line
,
"dm-crypt"
))
{
err
=
set_error
(
GPG_ERR_INV_ARG
,
"Type must be
\"
dm-crypt
\"
"
);
goto
leave
;
}
if
(
!
ctrl
->
server_local
->
devicename
||
!
ctrl
->
server_local
->
devicefp
||
!
ctrl
->
devti
)
{
err
=
set_error
(
GPG_ERR_ENOENT
,
"No device has been set"
);
goto
leave
;
}
err
=
sh_is_empty_partition
(
ctrl
->
server_local
->
devicename
);
if
(
err
)
{
if
(
gpg_err_code
(
err
)
==
GPG_ERR_FALSE
)
err
=
gpg_error
(
GPG_ERR_CONFLICT
);
err
=
assuan_set_error
(
ctx
,
err
,
"Partition is not empty"
);
goto
leave
;
}
/* We need a writeable stream to create the container. */
fp
=
es_fopen
(
ctrl
->
server_local
->
devicename
,
"r+b"
);
if
(
!
fp
)
{
err
=
gpg_error_from_syserror
();
log_error
(
"error opening '%s': %s
\n
"
,
ctrl
->
server_local
->
devicename
,
gpg_strerror
(
err
));
goto
leave
;
}
if
(
es_setvbuf
(
fp
,
NULL
,
_IONBF
,
0
))
{
err
=
gpg_error_from_syserror
();
log_error
(
"error setting '%s' to _IONBF: %s
\n
"
,
ctrl
->
server_local
->
devicename
,
gpg_strerror
(
err
));
goto
leave
;
}
err
=
sh_dmcrypt_create_container
(
ctrl
,
ctrl
->
server_local
->
devicename
,
fp
);
if
(
es_fclose
(
fp
))
{
gpg_error_t
err2
=
gpg_error_from_syserror
();
log_error
(
"error closing '%s': %s
\n
"
,
ctrl
->
server_local
->
devicename
,
gpg_strerror
(
err2
));
if
(
!
err
)
err
=
err2
;
}
fp
=
NULL
;
leave
:
es_fclose
(
fp
);
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_getkeyblob
[]
=
"GETKEYBLOB
\n
"
"
\n
"
"Return the encrypted keyblob of the current device."
;
static
gpg_error_t
cmd_getkeyblob
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
;
void
*
enckeyblob
=
NULL
;
size_t
enckeybloblen
;
line
=
skip_options
(
line
);
if
(
!
ctrl
->
server_local
->
devicename
||
!
ctrl
->
server_local
->
devicefp
||
!
ctrl
->
devti
)
{
err
=
set_error
(
GPG_ERR_ENOENT
,
"No device has been set"
);
goto
leave
;
}
err
=
sh_is_empty_partition
(
ctrl
->
server_local
->
devicename
);
if
(
!
err
)
{
err
=
gpg_error
(
GPG_ERR_ENODEV
);
assuan_set_error
(
ctx
,
err
,
"Partition is empty"
);
goto
leave
;
}
err
=
0
;
err
=
g13_keyblob_read
(
ctrl
->
server_local
->
devicename
,
&
enckeyblob
,
&
enckeybloblen
);
if
(
err
)
goto
leave
;
err
=
assuan_send_data
(
ctx
,
enckeyblob
,
enckeybloblen
);
if
(
!
err
)
err
=
assuan_send_data
(
ctx
,
NULL
,
0
);
/* Flush */
leave
:
xfree
(
enckeyblob
);
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_mount
[]
=
"MOUNT <type>
\n
"
"
\n
"
"Mount an encrypted partition on the current device.
\n
"
"<type> must be
\"
dm-crypt
\"
for now."
;
static
gpg_error_t
cmd_mount
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
unsigned
char
*
keyblob
=
NULL
;
size_t
keybloblen
;
tupledesc_t
tuples
=
NULL
;
line
=
skip_options
(
line
);
if
(
strcmp
(
line
,
"dm-crypt"
))
{
err
=
set_error
(
GPG_ERR_INV_ARG
,
"Type must be
\"
dm-crypt
\"
"
);
goto
leave
;
}
if
(
!
ctrl
->
server_local
->
devicename
||
!
ctrl
->
server_local
->
devicefp
||
!
ctrl
->
devti
)
{
err
=
set_error
(
GPG_ERR_ENOENT
,
"No device has been set"
);
goto
leave
;
}
err
=
sh_is_empty_partition
(
ctrl
->
server_local
->
devicename
);
if
(
!
err
)
{
err
=
gpg_error
(
GPG_ERR_ENODEV
);
assuan_set_error
(
ctx
,
err
,
"Partition is empty"
);
goto
leave
;
}
err
=
0
;
/* We expect that the client already decrypted the keyblob.
* Eventually we should move reading of the keyblob to here and ask
* the client to decrypt it. */
assuan_begin_confidential
(
ctx
);
err
=
assuan_inquire
(
ctx
,
"KEYBLOB"
,
&
keyblob
,
&
keybloblen
,
4
*
1024
);
assuan_end_confidential
(
ctx
);
if
(
err
)
{
log_error
(
_
(
"assuan_inquire failed: %s
\n
"
),
gpg_strerror
(
err
));
goto
leave
;
}
err
=
create_tupledesc
(
&
tuples
,
keyblob
,
keybloblen
);
if
(
!
err
)
keyblob
=
NULL
;
else
{
if
(
gpg_err_code
(
err
)
==
GPG_ERR_NOT_SUPPORTED
)
log_error
(
"unknown keyblob version received
\n
"
);
goto
leave
;
}
err
=
sh_dmcrypt_mount_container
(
ctrl
,
ctrl
->
server_local
->
devicename
,
tuples
);
leave
:
destroy_tupledesc
(
tuples
);
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_umount
[]
=
"UMOUNT <type>
\n
"
"
\n
"
"Unmount an encrypted partition and wipe the key.
\n
"
"<type> must be
\"
dm-crypt
\"
for now."
;
static
gpg_error_t
cmd_umount
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
line
=
skip_options
(
line
);
if
(
strcmp
(
line
,
"dm-crypt"
))
{
err
=
set_error
(
GPG_ERR_INV_ARG
,
"Type must be
\"
dm-crypt
\"
"
);
goto
leave
;
}
if
(
!
ctrl
->
server_local
->
devicename
||
!
ctrl
->
server_local
->
devicefp
||
!
ctrl
->
devti
)
{
err
=
set_error
(
GPG_ERR_ENOENT
,
"No device has been set"
);
goto
leave
;
}
err
=
sh_dmcrypt_umount_container
(
ctrl
,
ctrl
->
server_local
->
devicename
);
leave
:
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_suspend
[]
=
"SUSPEND <type>
\n
"
"
\n
"
"Suspend an encrypted partition and wipe the key.
\n
"
"<type> must be
\"
dm-crypt
\"
for now."
;
static
gpg_error_t
cmd_suspend
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
line
=
skip_options
(
line
);
if
(
strcmp
(
line
,
"dm-crypt"
))
{
err
=
set_error
(
GPG_ERR_INV_ARG
,
"Type must be
\"
dm-crypt
\"
"
);
goto
leave
;
}
if
(
!
ctrl
->
server_local
->
devicename
||
!
ctrl
->
server_local
->
devicefp
||
!
ctrl
->
devti
)
{
err
=
set_error
(
GPG_ERR_ENOENT
,
"No device has been set"
);
goto
leave
;
}
err
=
sh_is_empty_partition
(
ctrl
->
server_local
->
devicename
);
if
(
!
err
)
{
err
=
gpg_error
(
GPG_ERR_ENODEV
);
assuan_set_error
(
ctx
,
err
,
"Partition is empty"
);
goto
leave
;
}
err
=
0
;
err
=
sh_dmcrypt_suspend_container
(
ctrl
,
ctrl
->
server_local
->
devicename
);
leave
:
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_resume
[]
=
"RESUME <type>
\n
"
"
\n
"
"Resume an encrypted partition and set the key.
\n
"
"<type> must be
\"
dm-crypt
\"
for now."
;
static
gpg_error_t
cmd_resume
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
unsigned
char
*
keyblob
=
NULL
;
size_t
keybloblen
;
tupledesc_t
tuples
=
NULL
;
line
=
skip_options
(
line
);
if
(
strcmp
(
line
,
"dm-crypt"
))
{
err
=
set_error
(
GPG_ERR_INV_ARG
,
"Type must be
\"
dm-crypt
\"
"
);
goto
leave
;
}
if
(
!
ctrl
->
server_local
->
devicename
||
!
ctrl
->
server_local
->
devicefp
||
!
ctrl
->
devti
)
{
err
=
set_error
(
GPG_ERR_ENOENT
,
"No device has been set"
);
goto
leave
;
}
err
=
sh_is_empty_partition
(
ctrl
->
server_local
->
devicename
);
if
(
!
err
)
{
err
=
gpg_error
(
GPG_ERR_ENODEV
);
assuan_set_error
(
ctx
,
err
,
"Partition is empty"
);
goto
leave
;
}
err
=
0
;
/* We expect that the client already decrypted the keyblob.
* Eventually we should move reading of the keyblob to here and ask
* the client to decrypt it. */
assuan_begin_confidential
(
ctx
);
err
=
assuan_inquire
(
ctx
,
"KEYBLOB"
,
&
keyblob
,
&
keybloblen
,
4
*
1024
);
assuan_end_confidential
(
ctx
);
if
(
err
)
{
log_error
(
_
(
"assuan_inquire failed: %s
\n
"
),
gpg_strerror
(
err
));
goto
leave
;
}
err
=
create_tupledesc
(
&
tuples
,
keyblob
,
keybloblen
);
if
(
!
err
)
keyblob
=
NULL
;
else
{
if
(
gpg_err_code
(
err
)
==
GPG_ERR_NOT_SUPPORTED
)
log_error
(
"unknown keyblob version received
\n
"
);
goto
leave
;
}
err
=
sh_dmcrypt_resume_container
(
ctrl
,
ctrl
->
server_local
->
devicename
,
tuples
);
leave
:
destroy_tupledesc
(
tuples
);
return
leave_cmd
(
ctx
,
err
);
}
static
const
char
hlp_getinfo
[]
=
"GETINFO <what>
\n
"
"
\n
"
"Multipurpose function to return a variety of information.
\n
"
"Supported values for WHAT are:
\n
"
"
\n
"
" version - Return the version of the program.
\n
"
" pid - Return the process id of the server.
\n
"
" showtab - Show the table for the user."
;
static
gpg_error_t
cmd_getinfo
(
assuan_context_t
ctx
,
char
*
line
)
{
ctrl_t
ctrl
=
assuan_get_pointer
(
ctx
);
gpg_error_t
err
=
0
;
char
*
buf
;
if
(
!
strcmp
(
line
,
"version"
))
{
const
char
*
s
=
PACKAGE_VERSION
;
err
=
assuan_send_data
(
ctx
,
s
,
strlen
(
s
));
}
else
if
(
!
strcmp
(
line
,
"pid"
))
{
char
numbuf
[
50
];
snprintf
(
numbuf
,
sizeof
numbuf
,
"%lu"
,
(
unsigned
long
)
getpid
());
err
=
assuan_send_data
(
ctx
,
numbuf
,
strlen
(
numbuf
));
}
else
if
(
!
strncmp
(
line
,
"getsz"
,
5
))
{
unsigned
long
long
nblocks
;
err
=
sh_blockdev_getsz
(
line
+
6
,
&
nblocks
);
if
(
!
err
)
log_debug
(
"getsz=%llu
\n
"
,
nblocks
);
}
else
if
(
!
strcmp
(
line
,
"showtab"
))
{
tab_item_t
ti
;
for
(
ti
=
ctrl
->
client
.
tab
;
!
err
&&
ti
;
ti
=
ti
->
next
)
{
buf
=
es_bsprintf
(
"%s %s%s %s %s%s
\n
"
,
ctrl
->
client
.
uname
,
*
ti
->
blockdev
==
'/'
?
""
:
"partuuid="
,
ti
->
blockdev
,
ti
->
label
?
ti
->
label
:
"-"
,
ti
->
mountpoint
?
" "
:
""
,
ti
->
mountpoint
?
ti
->
mountpoint
:
""
);
if
(
!
buf
)
err
=
gpg_error_from_syserror
();
else
{
err
=
assuan_send_data
(
ctx
,
buf
,
strlen
(
buf
));
if
(
!
err
)
err
=
assuan_send_data
(
ctx
,
NULL
,
0
);
/* Flush */
}
xfree
(
buf
);
}
}
else
err
=
set_error
(
GPG_ERR_ASS_PARAMETER
,
"unknown value for WHAT"
);
return
leave_cmd
(
ctx
,
err
);
}
/* This command handler is used for all commands if this process has
not been started as expected. */
static
gpg_error_t
fail_command
(
assuan_context_t
ctx
,
char
*
line
)
{
gpg_error_t
err
;
const
char
*
name
=
assuan_get_command_name
(
ctx
);
(
void
)
line
;
if
(
!
name
)
name
=
"?"
;
err
=
set_error_fail_cmd
();
log_error
(
"command '%s' failed: %s
\n
"
,
name
,
gpg_strerror
(
err
));
return
err
;
}
/* Tell the Assuan library about our commands. */
static
int
register_commands
(
assuan_context_t
ctx
,
int
fail_all
)
{
static
struct
{
const
char
*
name
;
assuan_handler_t
handler
;
const
char
*
const
help
;
}
table
[]
=
{
{
"FINDDEVICE"
,
cmd_finddevice
,
hlp_finddevice
},
{
"DEVICE"
,
cmd_device
,
hlp_device
},
{
"CREATE"
,
cmd_create
,
hlp_create
},
{
"GETKEYBLOB"
,
cmd_getkeyblob
,
hlp_getkeyblob
},
{
"MOUNT"
,
cmd_mount
,
hlp_mount
},
{
"UMOUNT"
,
cmd_umount
,
hlp_umount
},
{
"SUSPEND"
,
cmd_suspend
,
hlp_suspend
},
{
"RESUME"
,
cmd_resume
,
hlp_resume
},
{
"INPUT"
,
NULL
},
{
"OUTPUT"
,
NULL
},
{
"GETINFO"
,
cmd_getinfo
,
hlp_getinfo
},
{
NULL
}
};
gpg_error_t
err
;
int
i
;
for
(
i
=
0
;
table
[
i
].
name
;
i
++
)
{
err
=
assuan_register_command
(
ctx
,
table
[
i
].
name
,
fail_all
?
fail_command
:
table
[
i
].
handler
,
table
[
i
].
help
);
if
(
err
)
return
err
;
}
return
0
;
}
/* Startup the server. */
gpg_error_t
syshelp_server
(
ctrl_t
ctrl
)
{
gpg_error_t
err
;
assuan_fd_t
filedes
[
2
];
assuan_context_t
ctx
=
NULL
;
/* We use a pipe based server so that we can work from scripts.
assuan_init_pipe_server will automagically detect when we are
called with a socketpair and ignore FILEDES in this case. */
filedes
[
0
]
=
assuan_fdopen
(
0
);
filedes
[
1
]
=
assuan_fdopen
(
1
);
err
=
assuan_new
(
&
ctx
);
if
(
err
)
{
log_error
(
"failed to allocate an Assuan context: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
err
=
assuan_init_pipe_server
(
ctx
,
filedes
);
if
(
err
)
{
log_error
(
"failed to initialize the server: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
err
=
register_commands
(
ctx
,
0
/*FIXME:ctrl->fail_all_cmds*/
);
if
(
err
)
{
log_error
(
"failed to the register commands with Assuan: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
assuan_set_pointer
(
ctx
,
ctrl
);
{
char
*
tmp
=
xtryasprintf
(
"G13-syshelp %s ready to serve requests "
"from %lu(%s)"
,
PACKAGE_VERSION
,
(
unsigned
long
)
ctrl
->
client
.
uid
,
ctrl
->
client
.
uname
);
if
(
tmp
)
{
assuan_set_hello_line
(
ctx
,
tmp
);
xfree
(
tmp
);
}
}
assuan_register_reset_notify
(
ctx
,
reset_notify
);
assuan_register_option_handler
(
ctx
,
option_handler
);
ctrl
->
server_local
=
xtrycalloc
(
1
,
sizeof
*
ctrl
->
server_local
);
if
(
!
ctrl
->
server_local
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
ctrl
->
server_local
->
assuan_ctx
=
ctx
;
while
(
!
(
err
=
assuan_accept
(
ctx
))
)
{
err
=
assuan_process
(
ctx
);
if
(
err
)
log_info
(
"Assuan processing failed: %s
\n
"
,
gpg_strerror
(
err
));
}
if
(
err
==
-1
)
err
=
0
;
else
log_info
(
"Assuan accept problem: %s
\n
"
,
gpg_strerror
(
err
));
leave
:
reset_notify
(
ctx
,
NULL
);
/* Release all items hold by SERVER_LOCAL. */
if
(
ctrl
->
server_local
)
{
xfree
(
ctrl
->
server_local
);
ctrl
->
server_local
=
NULL
;
}
assuan_release
(
ctx
);
return
err
;
}
gpg_error_t
sh_encrypt_keyblob
(
ctrl_t
ctrl
,
const
void
*
keyblob
,
size_t
keybloblen
,
char
**
r_enckeyblob
,
size_t
*
r_enckeybloblen
)
{
assuan_context_t
ctx
=
ctrl
->
server_local
->
assuan_ctx
;
gpg_error_t
err
;
unsigned
char
*
enckeyblob
;
size_t
enckeybloblen
;
*
r_enckeyblob
=
NULL
;
/* Send the plaintext. */
err
=
g13_status
(
ctrl
,
STATUS_PLAINTEXT_FOLLOWS
,
NULL
);
if
(
err
)
return
err
;
assuan_begin_confidential
(
ctx
);
err
=
assuan_send_data
(
ctx
,
keyblob
,
keybloblen
);
if
(
!
err
)
err
=
assuan_send_data
(
ctx
,
NULL
,
0
);
assuan_end_confidential
(
ctx
);
if
(
!
err
)
err
=
assuan_write_line
(
ctx
,
"END"
);
if
(
err
)
{
log_error
(
_
(
"error sending data: %s
\n
"
),
gpg_strerror
(
err
));
return
err
;
}
/* Inquire the ciphertext. */
err
=
assuan_inquire
(
ctx
,
"ENCKEYBLOB"
,
&
enckeyblob
,
&
enckeybloblen
,
16
*
1024
);
if
(
err
)
{
log_error
(
_
(
"assuan_inquire failed: %s
\n
"
),
gpg_strerror
(
err
));
return
err
;
}
*
r_enckeyblob
=
enckeyblob
;
*
r_enckeybloblen
=
enckeybloblen
;
return
0
;
}
/* Send a status line with status ID NO. The arguments are a list of
strings terminated by a NULL argument. */
gpg_error_t
g13_status
(
ctrl_t
ctrl
,
int
no
,
...)
{
gpg_error_t
err
=
0
;
va_list
arg_ptr
;
const
char
*
text
;
va_start
(
arg_ptr
,
no
);
if
(
1
)
{
assuan_context_t
ctx
=
ctrl
->
server_local
->
assuan_ctx
;
char
buf
[
950
],
*
p
;
size_t
n
;
p
=
buf
;
n
=
0
;
while
(
(
text
=
va_arg
(
arg_ptr
,
const
char
*
))
)
{
if
(
n
)
{
*
p
++
=
' '
;
n
++
;
}
for
(
;
*
text
&&
n
<
DIM
(
buf
)
-2
;
n
++
)
*
p
++
=
*
text
++
;
}
*
p
=
0
;
err
=
assuan_write_status
(
ctx
,
get_status_string
(
no
),
buf
);
}
va_end
(
arg_ptr
);
return
err
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Feb 26, 6:57 PM (1 d, 19 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
24/ba/b83222a98844c8e6df3fe5a0503f
Attached To
rG GnuPG
Event Timeline
Log In to Comment