qt: Handle diagnostic audit log for CMS
[gpgme.git] / src / passwd.c
1 /* passwd.c - Passphrase changing function
2  * Copyright (C) 2010 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <https://gnu.org/licenses/>.
18  * SPDX-License-Identifier: LGPL-2.1-or-later
19  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25
26 #include "gpgme.h"
27 #include "debug.h"
28 #include "context.h"
29 #include "ops.h"
30
31
32 typedef struct
33 {
34   /* The error code from a FAILURE status line or 0.  */
35   gpg_error_t failure_code;
36
37   int success_seen;
38   int error_seen;
39 } *op_data_t;
40
41
42 \f
43 /* Parse an error status line and return the error code.  */
44 static gpgme_error_t
45 parse_error (char *args)
46 {
47   gpgme_error_t err;
48   char *where = strchr (args, ' ');
49   char *which;
50
51   if (where)
52     {
53       *where = '\0';
54       which = where + 1;
55
56       where = strchr (which, ' ');
57       if (where)
58         *where = '\0';
59
60       where = args;
61     }
62   else
63     return trace_gpg_error (GPG_ERR_INV_ENGINE);
64
65   err = atoi (which);
66
67   if (!strcmp (where, "keyedit.passwd"))
68     return err;
69
70   return 0;
71 }
72
73
74 static gpgme_error_t
75 passwd_status_handler (void *priv, gpgme_status_code_t code, char *args)
76 {
77   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
78   gpgme_error_t err;
79   void *hook;
80   op_data_t opd;
81
82   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSWD, &hook, -1, NULL);
83   opd = hook;
84   if (err)
85     return err;
86
87   switch (code)
88     {
89     case GPGME_STATUS_ERROR:
90       err = parse_error (args);
91       if (err)
92         opd->error_seen = 1;
93       break;
94
95     case GPGME_STATUS_SUCCESS:
96       opd->success_seen = 1;
97       break;
98
99     case GPGME_STATUS_FAILURE:
100       opd->failure_code = _gpgme_parse_failure (args);
101       break;
102
103     case GPGME_STATUS_EOF:
104       /* In case the OpenPGP engine does not properly implement the
105          passwd command we won't get a success status back and thus we
106          conclude that this operation is not supported.  This is for
107          example the case for GnuPG < 2.0.16.  Note that this test is
108          obsolete for assuan based engines because they will properly
109          return an error for an unknown command.  */
110       if (ctx->protocol == GPGME_PROTOCOL_OpenPGP
111           && !opd->error_seen && !opd->success_seen)
112         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
113       else if (opd->failure_code)
114         err = opd->failure_code;
115       break;
116
117     default:
118       break;
119     }
120
121   return err;
122 }
123
124
125 static gpgme_error_t
126 passwd_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key,
127               unsigned int flags)
128 {
129   gpgme_error_t err;
130   void *hook;
131   op_data_t opd;
132
133   if (!key)
134     return gpg_error (GPG_ERR_INV_VALUE);
135   if (flags)
136     return gpg_error (GPG_ERR_INV_FLAG);
137
138   err = _gpgme_op_reset (ctx, synchronous);
139   if (err)
140     return err;
141
142   err = _gpgme_op_data_lookup (ctx, OPDATA_PASSWD, &hook, sizeof (*opd), NULL);
143   opd = hook;
144   if (err)
145     return err;
146
147   opd->success_seen = 0;
148   opd->error_seen = 0;
149
150   _gpgme_engine_set_status_handler (ctx->engine, passwd_status_handler, ctx);
151
152   if (ctx->passphrase_cb)
153     {
154       err = _gpgme_engine_set_command_handler
155         (ctx->engine, _gpgme_passphrase_command_handler, ctx);
156       if (err)
157         return err;
158     }
159
160   return _gpgme_engine_op_passwd (ctx->engine, key, flags);
161 }
162
163
164
165 /* Change the passphrase for KEY.  FLAGS is reserved for future use
166    and must be passed as 0.  The engine is expected to present a user
167    interface to enter the old and the new passphrase.  This is the
168    asynchronous variant.
169
170    Note that if ever the need arises to supply a passphrase we can do
171    this with a flag value and the passphrase callback feature.  */
172 gpgme_error_t
173 gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags)
174 {
175   gpg_error_t err;
176   TRACE_BEG  (DEBUG_CTX, "gpgme_op_passwd_start", ctx,
177               "key=%p, flags=0x%x", key, flags);
178
179   if (!ctx)
180     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
181
182   err = passwd_start (ctx, 0, key, flags);
183   return TRACE_ERR (err);
184 }
185
186
187 /* Change the passphrase for KEY.  FLAGS is reserved for future use
188    and must be passed as 0.  This is the synchronous variant.  */
189 gpgme_error_t
190 gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags)
191 {
192   gpgme_error_t err;
193
194   TRACE_BEG  (DEBUG_CTX, "gpgme_op_passwd", ctx,
195               "key=%p, flags=0x%x", key, flags);
196
197   if (!ctx)
198     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
199
200   err = passwd_start (ctx, 1, key, flags);
201   if (!err)
202     err = _gpgme_wait_one (ctx);
203   return TRACE_ERR (err);
204 }
205