Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F18826534
engine-gpgconf.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
20 KB
Subscribers
None
engine-gpgconf.c
View Options
/* engine-gpgconf.c - gpg-conf engine.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008,
2013 g10 Code GmbH
This file is part of GPGME.
GPGME is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
GPGME 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#if HAVE_CONFIG_H
#include
<config.h>
#endif
#include
<stdlib.h>
#include
<string.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include
<assert.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include
<fcntl.h>
/* FIXME */
#include
<errno.h>
#include
"gpgme.h"
#include
"util.h"
#include
"ops.h"
#include
"wait.h"
#include
"priv-io.h"
#include
"sema.h"
#include
"assuan.h"
#include
"debug.h"
#include
"engine-backend.h"
struct
engine_gpgconf
{
char
*
file_name
;
char
*
home_dir
;
};
typedef
struct
engine_gpgconf
*
engine_gpgconf_t
;
static
char
*
gpgconf_get_version
(
const
char
*
file_name
)
{
return
_gpgme_get_program_version
(
file_name
?
file_name
:
_gpgme_get_default_gpgconf_name
());
}
static
const
char
*
gpgconf_get_req_version
(
void
)
{
return
"2.0.4"
;
}
static
void
gpgconf_release
(
void
*
engine
)
{
engine_gpgconf_t
gpgconf
=
engine
;
if
(
!
gpgconf
)
return
;
if
(
gpgconf
->
file_name
)
free
(
gpgconf
->
file_name
);
if
(
gpgconf
->
home_dir
)
free
(
gpgconf
->
home_dir
);
free
(
gpgconf
);
}
static
gpgme_error_t
gpgconf_new
(
void
**
engine
,
const
char
*
file_name
,
const
char
*
home_dir
)
{
gpgme_error_t
err
=
0
;
engine_gpgconf_t
gpgconf
;
gpgconf
=
calloc
(
1
,
sizeof
*
gpgconf
);
if
(
!
gpgconf
)
return
gpg_error_from_syserror
();
gpgconf
->
file_name
=
strdup
(
file_name
?
file_name
:
_gpgme_get_default_gpgconf_name
());
if
(
!
gpgconf
->
file_name
)
err
=
gpg_error_from_syserror
();
if
(
!
err
&&
home_dir
)
{
gpgconf
->
home_dir
=
strdup
(
home_dir
);
if
(
!
gpgconf
->
home_dir
)
err
=
gpg_error_from_syserror
();
}
if
(
err
)
gpgconf_release
(
gpgconf
);
else
*
engine
=
gpgconf
;
return
err
;
}
static
void
release_arg
(
gpgme_conf_arg_t
arg
,
gpgme_conf_type_t
alt_type
)
{
while
(
arg
)
{
gpgme_conf_arg_t
next
=
arg
->
next
;
if
(
alt_type
==
GPGME_CONF_STRING
)
free
(
arg
->
value
.
string
);
free
(
arg
);
arg
=
next
;
}
}
static
void
release_opt
(
gpgme_conf_opt_t
opt
)
{
if
(
opt
->
name
)
free
(
opt
->
name
);
if
(
opt
->
description
)
free
(
opt
->
description
);
if
(
opt
->
argname
)
free
(
opt
->
argname
);
release_arg
(
opt
->
default_value
,
opt
->
alt_type
);
if
(
opt
->
default_description
)
free
(
opt
->
default_description
);
release_arg
(
opt
->
no_arg_value
,
opt
->
alt_type
);
release_arg
(
opt
->
value
,
opt
->
alt_type
);
release_arg
(
opt
->
new_value
,
opt
->
alt_type
);
free
(
opt
);
}
static
void
release_comp
(
gpgme_conf_comp_t
comp
)
{
gpgme_conf_opt_t
opt
;
if
(
comp
->
name
)
free
(
comp
->
name
);
if
(
comp
->
description
)
free
(
comp
->
description
);
if
(
comp
->
program_name
)
free
(
comp
->
program_name
);
opt
=
comp
->
options
;
while
(
opt
)
{
gpgme_conf_opt_t
next
=
opt
->
next
;
release_opt
(
opt
);
opt
=
next
;
}
free
(
comp
);
}
static
void
gpgconf_config_release
(
gpgme_conf_comp_t
conf
)
{
while
(
conf
)
{
gpgme_conf_comp_t
next
=
conf
->
next
;
release_comp
(
conf
);
conf
=
next
;
}
}
/* Read from gpgconf and pass line after line to the hook function.
We put a limit of 64 k on the maximum size for a line. This should
allow for quite a long "group" line, which is usually the longest
line (mine is currently ~3k). */
static
gpgme_error_t
gpgconf_read
(
void
*
engine
,
char
*
arg1
,
char
*
arg2
,
gpgme_error_t
(
*
cb
)
(
void
*
hook
,
char
*
line
),
void
*
hook
)
{
struct
engine_gpgconf
*
gpgconf
=
engine
;
gpgme_error_t
err
=
0
;
char
*
linebuf
;
size_t
linebufsize
;
int
linelen
;
char
*
argv
[
4
]
=
{
NULL
/* file_name */
,
NULL
,
NULL
,
NULL
};
int
rp
[
2
];
struct
spawn_fd_item_s
cfd
[]
=
{
{
-1
,
1
/* STDOUT_FILENO */
,
-1
,
0
},
{
-1
,
-1
}
};
int
status
;
int
nread
;
char
*
mark
=
NULL
;
argv
[
1
]
=
arg1
;
argv
[
2
]
=
arg2
;
/* FIXME: Deal with engine->home_dir. */
/* _gpgme_engine_new guarantees that this is not NULL. */
argv
[
0
]
=
gpgconf
->
file_name
;
if
(
_gpgme_io_pipe
(
rp
,
1
)
<
0
)
return
gpg_error_from_syserror
();
cfd
[
0
].
fd
=
rp
[
1
];
status
=
_gpgme_io_spawn
(
gpgconf
->
file_name
,
argv
,
IOSPAWN_FLAG_DETACHED
,
cfd
,
NULL
,
NULL
,
NULL
);
if
(
status
<
0
)
{
_gpgme_io_close
(
rp
[
0
]);
_gpgme_io_close
(
rp
[
1
]);
return
gpg_error_from_syserror
();
}
linebufsize
=
1024
;
/* Usually enough for conf lines. */
linebuf
=
malloc
(
linebufsize
);
if
(
!
linebuf
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
linelen
=
0
;
while
((
nread
=
_gpgme_io_read
(
rp
[
0
],
linebuf
+
linelen
,
linebufsize
-
linelen
-
1
)))
{
char
*
line
;
const
char
*
lastmark
=
NULL
;
size_t
nused
;
if
(
nread
<
0
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
linelen
+=
nread
;
linebuf
[
linelen
]
=
'\0'
;
for
(
line
=
linebuf
;
(
mark
=
strchr
(
line
,
'\n'
));
line
=
mark
+
1
)
{
lastmark
=
mark
;
if
(
mark
>
line
&&
mark
[
-1
]
==
'\r'
)
mark
[
-1
]
=
'\0'
;
else
mark
[
0
]
=
'\0'
;
/* Got a full line. Due to the CR removal code (which
occurs only on Windows) we might be one-off and thus
would see empty lines. Don't pass them to the
callback. */
err
=
*
line
?
(
*
cb
)
(
hook
,
line
)
:
0
;
if
(
err
)
goto
leave
;
}
nused
=
lastmark
?
(
lastmark
+
1
-
linebuf
)
:
0
;
memmove
(
linebuf
,
linebuf
+
nused
,
linelen
-
nused
);
linelen
-=
nused
;
if
(
!
(
linelen
<
linebufsize
-
1
))
{
char
*
newlinebuf
;
if
(
linelen
<
8
*
1024
-
1
)
linebufsize
=
8
*
1024
;
else
if
(
linelen
<
64
*
1024
-
1
)
linebufsize
=
64
*
1024
;
else
{
/* We reached our limit - give up. */
err
=
gpg_error
(
GPG_ERR_LINE_TOO_LONG
);
goto
leave
;
}
newlinebuf
=
realloc
(
linebuf
,
linebufsize
);
if
(
!
newlinebuf
)
{
err
=
gpg_error_from_syserror
();
goto
leave
;
}
linebuf
=
newlinebuf
;
}
}
leave
:
free
(
linebuf
);
_gpgme_io_close
(
rp
[
0
]);
return
err
;
}
static
gpgme_error_t
gpgconf_config_load_cb
(
void
*
hook
,
char
*
line
)
{
gpgme_conf_comp_t
*
comp_p
=
hook
;
gpgme_conf_comp_t
comp
=
*
comp_p
;
#define NR_FIELDS 16
char
*
field
[
NR_FIELDS
];
int
fields
=
0
;
while
(
line
&&
fields
<
NR_FIELDS
)
{
field
[
fields
++
]
=
line
;
line
=
strchr
(
line
,
':'
);
if
(
line
)
*
(
line
++
)
=
'\0'
;
}
/* We require at least the first 3 fields. */
if
(
fields
<
2
)
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
/* Find the pointer to the new component in the list. */
while
(
comp
&&
comp
->
next
)
comp
=
comp
->
next
;
if
(
comp
)
comp_p
=
&
comp
->
next
;
comp
=
calloc
(
1
,
sizeof
(
*
comp
));
if
(
!
comp
)
return
gpg_error_from_syserror
();
/* Prepare return value. */
comp
->
_last_opt_p
=
&
comp
->
options
;
*
comp_p
=
comp
;
comp
->
name
=
strdup
(
field
[
0
]);
if
(
!
comp
->
name
)
return
gpg_error_from_syserror
();
comp
->
description
=
strdup
(
field
[
1
]);
if
(
!
comp
->
description
)
return
gpg_error_from_syserror
();
if
(
fields
>=
3
)
{
comp
->
program_name
=
strdup
(
field
[
2
]);
if
(
!
comp
->
program_name
)
return
gpg_error_from_syserror
();
}
return
0
;
}
static
gpgme_error_t
gpgconf_parse_option
(
gpgme_conf_opt_t
opt
,
gpgme_conf_arg_t
*
arg_p
,
char
*
line
)
{
gpgme_error_t
err
;
char
*
mark
;
if
(
!
line
[
0
])
return
0
;
while
(
line
)
{
gpgme_conf_arg_t
arg
;
mark
=
strchr
(
line
,
','
);
if
(
mark
)
*
mark
=
'\0'
;
arg
=
calloc
(
1
,
sizeof
(
*
arg
));
if
(
!
arg
)
return
gpg_error_from_syserror
();
*
arg_p
=
arg
;
arg_p
=
&
arg
->
next
;
if
(
*
line
==
'\0'
)
arg
->
no_arg
=
1
;
else
{
switch
(
opt
->
alt_type
)
{
/* arg->value.count is an alias for arg->value.uint32. */
case
GPGME_CONF_NONE
:
case
GPGME_CONF_UINT32
:
arg
->
value
.
uint32
=
strtoul
(
line
,
NULL
,
0
);
break
;
case
GPGME_CONF_INT32
:
arg
->
value
.
uint32
=
strtol
(
line
,
NULL
,
0
);
break
;
case
GPGME_CONF_STRING
:
/* The complex types below are only here to silent the
compiler warning. */
case
GPGME_CONF_FILENAME
:
case
GPGME_CONF_LDAP_SERVER
:
case
GPGME_CONF_KEY_FPR
:
case
GPGME_CONF_PUB_KEY
:
case
GPGME_CONF_SEC_KEY
:
case
GPGME_CONF_ALIAS_LIST
:
/* Skip quote character. */
line
++
;
err
=
_gpgme_decode_percent_string
(
line
,
&
arg
->
value
.
string
,
0
,
0
);
if
(
err
)
return
err
;
break
;
}
}
/* Find beginning of next value. */
if
(
mark
++
&&
*
mark
)
line
=
mark
;
else
line
=
NULL
;
}
return
0
;
}
static
gpgme_error_t
gpgconf_config_load_cb2
(
void
*
hook
,
char
*
line
)
{
gpgme_error_t
err
;
gpgme_conf_comp_t
comp
=
hook
;
gpgme_conf_opt_t
*
opt_p
=
comp
->
_last_opt_p
;
gpgme_conf_opt_t
opt
;
#define NR_FIELDS 16
char
*
field
[
NR_FIELDS
];
int
fields
=
0
;
while
(
line
&&
fields
<
NR_FIELDS
)
{
field
[
fields
++
]
=
line
;
line
=
strchr
(
line
,
':'
);
if
(
line
)
*
(
line
++
)
=
'\0'
;
}
/* We require at least the first 10 fields. */
if
(
fields
<
10
)
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
opt
=
calloc
(
1
,
sizeof
(
*
opt
));
if
(
!
opt
)
return
gpg_error_from_syserror
();
comp
->
_last_opt_p
=
&
opt
->
next
;
*
opt_p
=
opt
;
if
(
field
[
0
][
0
])
{
opt
->
name
=
strdup
(
field
[
0
]);
if
(
!
opt
->
name
)
return
gpg_error_from_syserror
();
}
opt
->
flags
=
strtoul
(
field
[
1
],
NULL
,
0
);
opt
->
level
=
strtoul
(
field
[
2
],
NULL
,
0
);
if
(
field
[
3
][
0
])
{
opt
->
description
=
strdup
(
field
[
3
]);
if
(
!
opt
->
description
)
return
gpg_error_from_syserror
();
}
opt
->
type
=
strtoul
(
field
[
4
],
NULL
,
0
);
opt
->
alt_type
=
strtoul
(
field
[
5
],
NULL
,
0
);
if
(
field
[
6
][
0
])
{
opt
->
argname
=
strdup
(
field
[
6
]);
if
(
!
opt
->
argname
)
return
gpg_error_from_syserror
();
}
if
(
opt
->
flags
&
GPGME_CONF_DEFAULT
)
{
err
=
gpgconf_parse_option
(
opt
,
&
opt
->
default_value
,
field
[
7
]);
if
(
err
)
return
err
;
}
else
if
((
opt
->
flags
&
GPGME_CONF_DEFAULT_DESC
)
&&
field
[
7
][
0
])
{
opt
->
default_description
=
strdup
(
field
[
7
]);
if
(
!
opt
->
default_description
)
return
gpg_error_from_syserror
();
}
if
(
opt
->
flags
&
GPGME_CONF_NO_ARG_DESC
)
{
opt
->
no_arg_description
=
strdup
(
field
[
8
]);
if
(
!
opt
->
no_arg_description
)
return
gpg_error_from_syserror
();
}
else
{
err
=
gpgconf_parse_option
(
opt
,
&
opt
->
no_arg_value
,
field
[
8
]);
if
(
err
)
return
err
;
}
err
=
gpgconf_parse_option
(
opt
,
&
opt
->
value
,
field
[
9
]);
if
(
err
)
return
err
;
return
0
;
}
static
gpgme_error_t
gpgconf_conf_load
(
void
*
engine
,
gpgme_conf_comp_t
*
comp_p
)
{
gpgme_error_t
err
;
gpgme_conf_comp_t
comp
=
NULL
;
gpgme_conf_comp_t
cur_comp
;
*
comp_p
=
NULL
;
err
=
gpgconf_read
(
engine
,
"--list-components"
,
NULL
,
gpgconf_config_load_cb
,
&
comp
);
if
(
err
)
{
gpgconf_release
(
comp
);
return
err
;
}
cur_comp
=
comp
;
while
(
!
err
&&
cur_comp
)
{
err
=
gpgconf_read
(
engine
,
"--list-options"
,
cur_comp
->
name
,
gpgconf_config_load_cb2
,
cur_comp
);
cur_comp
=
cur_comp
->
next
;
}
if
(
err
)
{
gpgconf_release
(
comp
);
return
err
;
}
*
comp_p
=
comp
;
return
0
;
}
gpgme_error_t
_gpgme_conf_arg_new
(
gpgme_conf_arg_t
*
arg_p
,
gpgme_conf_type_t
type
,
const
void
*
value
)
{
gpgme_conf_arg_t
arg
;
arg
=
calloc
(
1
,
sizeof
(
*
arg
));
if
(
!
arg
)
return
gpg_error_from_syserror
();
if
(
!
value
)
arg
->
no_arg
=
1
;
else
{
/* We need to switch on type here because the alt-type is not
yet known. */
switch
(
type
)
{
case
GPGME_CONF_NONE
:
case
GPGME_CONF_UINT32
:
arg
->
value
.
uint32
=
*
((
unsigned
int
*
)
value
);
break
;
case
GPGME_CONF_INT32
:
arg
->
value
.
int32
=
*
((
int
*
)
value
);
break
;
case
GPGME_CONF_STRING
:
case
GPGME_CONF_FILENAME
:
case
GPGME_CONF_LDAP_SERVER
:
case
GPGME_CONF_KEY_FPR
:
case
GPGME_CONF_PUB_KEY
:
case
GPGME_CONF_SEC_KEY
:
case
GPGME_CONF_ALIAS_LIST
:
arg
->
value
.
string
=
strdup
(
value
);
if
(
!
arg
->
value
.
string
)
{
free
(
arg
);
return
gpg_error_from_syserror
();
}
break
;
default
:
free
(
arg
);
return
gpg_error
(
GPG_ERR_INV_VALUE
);
}
}
*
arg_p
=
arg
;
return
0
;
}
void
_gpgme_conf_arg_release
(
gpgme_conf_arg_t
arg
,
gpgme_conf_type_t
type
)
{
/* Lacking the alt_type we need to switch on type here. */
switch
(
type
)
{
case
GPGME_CONF_NONE
:
case
GPGME_CONF_UINT32
:
case
GPGME_CONF_INT32
:
case
GPGME_CONF_STRING
:
default
:
break
;
case
GPGME_CONF_FILENAME
:
case
GPGME_CONF_LDAP_SERVER
:
case
GPGME_CONF_KEY_FPR
:
case
GPGME_CONF_PUB_KEY
:
case
GPGME_CONF_SEC_KEY
:
case
GPGME_CONF_ALIAS_LIST
:
type
=
GPGME_CONF_STRING
;
break
;
}
release_arg
(
arg
,
type
);
}
gpgme_error_t
_gpgme_conf_opt_change
(
gpgme_conf_opt_t
opt
,
int
reset
,
gpgme_conf_arg_t
arg
)
{
if
(
reset
)
{
if
(
opt
->
new_value
)
release_arg
(
opt
->
new_value
,
opt
->
alt_type
);
opt
->
new_value
=
NULL
;
opt
->
change_value
=
0
;
}
else
{
/* Support self-assignment, for example for adding an item to an
existing list. */
if
(
opt
->
new_value
&&
arg
!=
opt
->
new_value
)
release_arg
(
opt
->
new_value
,
opt
->
alt_type
);
opt
->
new_value
=
arg
;
opt
->
change_value
=
1
;
}
return
0
;
}
/* FIXME: Major problem: We don't get errors from gpgconf. */
static
gpgme_error_t
gpgconf_write
(
void
*
engine
,
char
*
arg1
,
char
*
arg2
,
gpgme_data_t
conf
)
{
struct
engine_gpgconf
*
gpgconf
=
engine
;
gpgme_error_t
err
=
0
;
#define BUFLEN 1024
char
buf
[
BUFLEN
];
int
buflen
=
0
;
char
*
argv
[]
=
{
NULL
/* file_name */
,
arg1
,
arg2
,
0
};
int
rp
[
2
];
struct
spawn_fd_item_s
cfd
[]
=
{
{
-1
,
0
/* STDIN_FILENO */
},
{
-1
,
-1
}
};
int
status
;
int
nwrite
;
/* FIXME: Deal with engine->home_dir. */
/* _gpgme_engine_new guarantees that this is not NULL. */
argv
[
0
]
=
gpgconf
->
file_name
;
if
(
_gpgme_io_pipe
(
rp
,
0
)
<
0
)
return
gpg_error_from_syserror
();
cfd
[
0
].
fd
=
rp
[
0
];
status
=
_gpgme_io_spawn
(
gpgconf
->
file_name
,
argv
,
IOSPAWN_FLAG_DETACHED
,
cfd
,
NULL
,
NULL
,
NULL
);
if
(
status
<
0
)
{
_gpgme_io_close
(
rp
[
0
]);
_gpgme_io_close
(
rp
[
1
]);
return
gpg_error_from_syserror
();
}
for
(;;)
{
if
(
buflen
==
0
)
{
do
{
buflen
=
gpgme_data_read
(
conf
,
buf
,
BUFLEN
);
}
while
(
buflen
<
0
&&
errno
==
EAGAIN
);
if
(
buflen
<
0
)
{
err
=
gpg_error_from_syserror
();
_gpgme_io_close
(
rp
[
1
]);
return
err
;
}
else
if
(
buflen
==
0
)
{
/* All is written. */
_gpgme_io_close
(
rp
[
1
]);
return
0
;
}
}
do
{
nwrite
=
_gpgme_io_write
(
rp
[
1
],
buf
,
buflen
);
}
while
(
nwrite
<
0
&&
errno
==
EAGAIN
);
if
(
nwrite
>
0
)
{
buflen
-=
nwrite
;
if
(
buflen
>
0
)
memmove
(
&
buf
[
0
],
&
buf
[
nwrite
],
buflen
);
}
else
if
(
nwrite
<
0
)
{
_gpgme_io_close
(
rp
[
1
]);
return
gpg_error_from_syserror
();
}
}
return
0
;
}
static
gpgme_error_t
arg_to_data
(
gpgme_data_t
conf
,
gpgme_conf_opt_t
option
,
gpgme_conf_arg_t
arg
)
{
gpgme_error_t
err
=
0
;
int
amt
=
0
;
char
buf
[
16
];
while
(
amt
>=
0
&&
arg
)
{
switch
(
option
->
alt_type
)
{
case
GPGME_CONF_NONE
:
case
GPGME_CONF_UINT32
:
default
:
snprintf
(
buf
,
sizeof
(
buf
),
"%u"
,
arg
->
value
.
uint32
);
buf
[
sizeof
(
buf
)
-
1
]
=
'\0'
;
amt
=
gpgme_data_write
(
conf
,
buf
,
strlen
(
buf
));
break
;
case
GPGME_CONF_INT32
:
snprintf
(
buf
,
sizeof
(
buf
),
"%i"
,
arg
->
value
.
uint32
);
buf
[
sizeof
(
buf
)
-
1
]
=
'\0'
;
amt
=
gpgme_data_write
(
conf
,
buf
,
strlen
(
buf
));
break
;
case
GPGME_CONF_STRING
:
/* The complex types below are only here to silent the
compiler warning. */
case
GPGME_CONF_FILENAME
:
case
GPGME_CONF_LDAP_SERVER
:
case
GPGME_CONF_KEY_FPR
:
case
GPGME_CONF_PUB_KEY
:
case
GPGME_CONF_SEC_KEY
:
case
GPGME_CONF_ALIAS_LIST
:
if
(
arg
->
value
.
string
)
{
/* One quote character, and three times to allow for
percent escaping. */
char
*
ptr
=
arg
->
value
.
string
;
amt
=
gpgme_data_write
(
conf
,
"
\"
"
,
1
);
if
(
amt
<
0
)
break
;
while
(
!
err
&&
*
ptr
)
{
switch
(
*
ptr
)
{
case
'%'
:
amt
=
gpgme_data_write
(
conf
,
"%25"
,
3
);
break
;
case
':'
:
amt
=
gpgme_data_write
(
conf
,
"%3a"
,
3
);
break
;
case
','
:
amt
=
gpgme_data_write
(
conf
,
"%2c"
,
3
);
break
;
default
:
amt
=
gpgme_data_write
(
conf
,
ptr
,
1
);
}
ptr
++
;
}
}
break
;
}
if
(
amt
<
0
)
break
;
arg
=
arg
->
next
;
/* Comma separator. */
if
(
arg
)
amt
=
gpgme_data_write
(
conf
,
","
,
1
);
}
if
(
amt
<
0
)
return
gpg_error_from_syserror
();
return
0
;
}
static
gpgme_error_t
gpgconf_conf_save
(
void
*
engine
,
gpgme_conf_comp_t
comp
)
{
gpgme_error_t
err
;
int
amt
=
0
;
/* We use a data object to store the new configuration. */
gpgme_data_t
conf
;
gpgme_conf_opt_t
option
;
int
something_changed
=
0
;
err
=
gpgme_data_new
(
&
conf
);
if
(
err
)
return
err
;
option
=
comp
->
options
;
while
(
!
err
&&
amt
>=
0
&&
option
)
{
if
(
option
->
change_value
)
{
unsigned
int
flags
=
0
;
char
buf
[
16
];
something_changed
=
1
;
amt
=
gpgme_data_write
(
conf
,
option
->
name
,
strlen
(
option
->
name
));
if
(
amt
>=
0
)
amt
=
gpgme_data_write
(
conf
,
":"
,
1
);
if
(
amt
<
0
)
break
;
if
(
!
option
->
new_value
)
flags
|=
GPGME_CONF_DEFAULT
;
snprintf
(
buf
,
sizeof
(
buf
),
"%u"
,
flags
);
buf
[
sizeof
(
buf
)
-
1
]
=
'\0'
;
amt
=
gpgme_data_write
(
conf
,
buf
,
strlen
(
buf
));
if
(
amt
>=
0
)
amt
=
gpgme_data_write
(
conf
,
":"
,
1
);
if
(
amt
<
0
)
break
;
if
(
option
->
new_value
)
{
err
=
arg_to_data
(
conf
,
option
,
option
->
new_value
);
if
(
err
)
break
;
}
amt
=
gpgme_data_write
(
conf
,
"
\n
"
,
1
);
}
option
=
option
->
next
;
}
if
(
!
err
&&
amt
<
0
)
err
=
gpg_error_from_syserror
();
if
(
err
||
!
something_changed
)
goto
bail
;
err
=
gpgme_data_seek
(
conf
,
0
,
SEEK_SET
);
if
(
err
)
goto
bail
;
err
=
gpgconf_write
(
engine
,
"--change-options"
,
comp
->
name
,
conf
);
bail
:
gpgme_data_release
(
conf
);
return
err
;
}
static
void
gpgconf_set_io_cbs
(
void
*
engine
,
gpgme_io_cbs_t
io_cbs
)
{
/* Nothing to do. */
}
/* Currently, we do not use the engine interface for the various
operations. */
void
_gpgme_conf_release
(
gpgme_conf_comp_t
conf
)
{
gpgconf_config_release
(
conf
);
}
struct
engine_ops
_gpgme_engine_ops_gpgconf
=
{
/* Static functions. */
_gpgme_get_default_gpgconf_name
,
NULL
,
gpgconf_get_version
,
gpgconf_get_req_version
,
gpgconf_new
,
/* Member functions. */
gpgconf_release
,
NULL
,
/* reset */
NULL
,
/* set_status_handler */
NULL
,
/* set_command_handler */
NULL
,
/* set_colon_line_handler */
NULL
,
/* set_locale */
NULL
,
/* set_protocol */
NULL
,
/* decrypt */
NULL
,
/* decrypt_verify */
NULL
,
/* delete */
NULL
,
/* edit */
NULL
,
/* encrypt */
NULL
,
/* encrypt_sign */
NULL
,
/* export */
NULL
,
/* export_ext */
NULL
,
/* genkey */
NULL
,
/* import */
NULL
,
/* keylist */
NULL
,
/* keylist_ext */
NULL
,
/* sign */
NULL
,
/* trustlist */
NULL
,
/* verify */
NULL
,
/* getauditlog */
NULL
,
/* opassuan_transact */
gpgconf_conf_load
,
gpgconf_conf_save
,
gpgconf_set_io_cbs
,
NULL
,
/* io_event */
NULL
,
/* cancel */
NULL
,
/* cancel_op */
NULL
,
/* passwd */
NULL
,
/* set_pinentry_mode */
NULL
/* opspawn */
};
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, Dec 23, 5:25 PM (2 h, 7 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
bd/5e/8815e822a65dd7f9119d4f8bb71e
Attached To
rM GPGME
Event Timeline
Log In to Comment