Coverage Report

Created: 2023-09-25 07:17

/src/neomutt/ncrypt/pgp_functions.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file
3
 * Pgp functions
4
 *
5
 * @authors
6
 * Copyright (C) 2022 Richard Russon <rich@flatcap.org>
7
 *
8
 * @copyright
9
 * This program is free software: you can redistribute it and/or modify it under
10
 * the terms of the GNU General Public License as published by the Free Software
11
 * Foundation, either version 2 of the License, or (at your option) any later
12
 * version.
13
 *
14
 * This program is distributed in the hope that it will be useful, but WITHOUT
15
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17
 * details.
18
 *
19
 * You should have received a copy of the GNU General Public License along with
20
 * this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/**
24
 * @page pgp_functions Pgp functions
25
 *
26
 * Pgp functions
27
 */
28
29
#include "config.h"
30
#include <stdio.h>
31
#include <unistd.h>
32
#include "mutt/lib.h"
33
#include "config/lib.h"
34
#include "core/lib.h"
35
#include "gui/lib.h"
36
#include "pgp_functions.h"
37
#include "lib.h"
38
#include "menu/lib.h"
39
#include "pager/lib.h"
40
#include "question/lib.h"
41
#include "globals.h"
42
#include "mutt_logging.h"
43
#include "pgp.h"
44
#include "pgpinvoke.h"
45
#include "pgpkey.h"
46
#include "pgplib.h"
47
48
/**
49
 * op_exit - Exit this menu - Implements ::pgp_function_t - @ingroup pgp_function_api
50
 */
51
static int op_exit(struct PgpData *pd, int op)
52
0
{
53
0
  pd->done = true;
54
0
  return FR_SUCCESS;
55
0
}
56
57
/**
58
 * op_generic_select_entry - Select the current entry - Implements ::pgp_function_t - @ingroup pgp_function_api
59
 */
60
static int op_generic_select_entry(struct PgpData *pd, int op)
61
0
{
62
  /* XXX make error reporting more verbose */
63
64
0
  const int index = menu_get_index(pd->menu);
65
0
  struct PgpUid *cur_key = pd->key_table[index];
66
0
  if (OptPgpCheckTrust)
67
0
  {
68
0
    if (!pgp_key_is_valid(cur_key->parent))
69
0
    {
70
0
      mutt_error(_("This key can't be used: expired/disabled/revoked"));
71
0
      return FR_ERROR;
72
0
    }
73
0
  }
74
75
0
  if (OptPgpCheckTrust && (!pgp_id_is_valid(cur_key) || !pgp_id_is_strong(cur_key)))
76
0
  {
77
0
    const char *str = "";
78
0
    char buf2[1024];
79
80
0
    if (cur_key->flags & KEYFLAG_CANTUSE)
81
0
    {
82
0
      str = _("ID is expired/disabled/revoked. Do you really want to use the key?");
83
0
    }
84
0
    else
85
0
    {
86
0
      switch (cur_key->trust & 0x03)
87
0
      {
88
0
        case 0:
89
0
          str = _("ID has undefined validity. Do you really want to use the key?");
90
0
          break;
91
0
        case 1:
92
0
          str = _("ID is not valid. Do you really want to use the key?");
93
0
          break;
94
0
        case 2:
95
0
          str = _("ID is only marginally valid. Do you really want to use the key?");
96
0
          break;
97
0
      }
98
0
    }
99
100
0
    snprintf(buf2, sizeof(buf2), "%s", str);
101
102
0
    if (query_yesorno(buf2, MUTT_NO) != MUTT_YES)
103
0
    {
104
0
      mutt_clear_error();
105
0
      return FR_NO_ACTION;
106
0
    }
107
0
  }
108
109
0
  pd->key = cur_key->parent;
110
0
  pd->done = true;
111
0
  return FR_SUCCESS;
112
0
}
113
114
/**
115
 * op_verify_key - Verify a PGP public key - Implements ::pgp_function_t - @ingroup pgp_function_api
116
 */
117
static int op_verify_key(struct PgpData *pd, int op)
118
0
{
119
0
  FILE *fp_null = fopen("/dev/null", "w");
120
0
  if (!fp_null)
121
0
  {
122
0
    mutt_perror(_("Can't open /dev/null"));
123
0
    return FR_ERROR;
124
0
  }
125
0
  struct Buffer *tempfile = NULL;
126
0
  tempfile = buf_pool_get();
127
0
  buf_mktemp(tempfile);
128
0
  FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w");
129
0
  if (!fp_tmp)
130
0
  {
131
0
    mutt_perror(_("Can't create temporary file"));
132
0
    mutt_file_fclose(&fp_null);
133
0
    buf_pool_release(&tempfile);
134
0
    return FR_ERROR;
135
0
  }
136
137
0
  mutt_message(_("Invoking PGP..."));
138
139
0
  const int index = menu_get_index(pd->menu);
140
0
  struct PgpUid *cur_key = pd->key_table[index];
141
0
  char tmpbuf[256] = { 0 };
142
0
  snprintf(tmpbuf, sizeof(tmpbuf), "0x%s",
143
0
           pgp_fpr_or_lkeyid(pgp_principal_key(cur_key->parent)));
144
145
0
  pid_t pid = pgp_invoke_verify_key(NULL, NULL, NULL, -1, fileno(fp_tmp),
146
0
                                    fileno(fp_null), tmpbuf);
147
0
  if (pid == -1)
148
0
  {
149
0
    mutt_perror(_("Can't create filter"));
150
0
    unlink(buf_string(tempfile));
151
0
    mutt_file_fclose(&fp_tmp);
152
0
    mutt_file_fclose(&fp_null);
153
0
  }
154
155
0
  filter_wait(pid);
156
0
  mutt_file_fclose(&fp_tmp);
157
0
  mutt_file_fclose(&fp_null);
158
0
  mutt_clear_error();
159
0
  char title[1024] = { 0 };
160
0
  snprintf(title, sizeof(title), _("Key ID: 0x%s"),
161
0
           pgp_keyid(pgp_principal_key(cur_key->parent)));
162
163
0
  struct PagerData pdata = { 0 };
164
0
  struct PagerView pview = { &pdata };
165
166
0
  pdata.fname = buf_string(tempfile);
167
168
0
  pview.banner = title;
169
0
  pview.flags = MUTT_PAGER_NO_FLAGS;
170
0
  pview.mode = PAGER_MODE_OTHER;
171
172
0
  mutt_do_pager(&pview, NULL);
173
0
  buf_pool_release(&tempfile);
174
0
  menu_queue_redraw(pd->menu, MENU_REDRAW_FULL);
175
0
  return FR_SUCCESS;
176
0
}
177
178
/**
179
 * op_view_id - View the key's user id - Implements ::pgp_function_t - @ingroup pgp_function_api
180
 */
181
static int op_view_id(struct PgpData *pd, int op)
182
0
{
183
0
  const int index = menu_get_index(pd->menu);
184
0
  struct PgpUid *cur_key = pd->key_table[index];
185
0
  mutt_message("%s", NONULL(cur_key->addr));
186
0
  return FR_SUCCESS;
187
0
}
188
189
// -----------------------------------------------------------------------------
190
191
/**
192
 * PgpFunctions - All the NeoMutt functions that the Pgp supports
193
 */
194
static const struct PgpFunction PgpFunctions[] = {
195
  // clang-format off
196
  { OP_EXIT,                   op_exit },
197
  { OP_GENERIC_SELECT_ENTRY,   op_generic_select_entry },
198
  { OP_VERIFY_KEY,             op_verify_key },
199
  { OP_VIEW_ID,                op_view_id },
200
  { 0, NULL },
201
  // clang-format on
202
};
203
204
/**
205
 * pgp_function_dispatcher - Perform a Pgp function - Implements ::function_dispatcher_t - @ingroup dispatcher_api
206
 */
207
int pgp_function_dispatcher(struct MuttWindow *win, int op)
208
0
{
209
0
  if (!win || !win->wdata)
210
0
    return FR_UNKNOWN;
211
212
0
  struct MuttWindow *dlg = dialog_find(win);
213
0
  if (!dlg)
214
0
    return FR_ERROR;
215
216
0
  struct PgpData *pd = dlg->wdata;
217
218
0
  int rc = FR_UNKNOWN;
219
0
  for (size_t i = 0; PgpFunctions[i].op != OP_NULL; i++)
220
0
  {
221
0
    const struct PgpFunction *fn = &PgpFunctions[i];
222
0
    if (fn->op == op)
223
0
    {
224
0
      rc = fn->function(pd, op);
225
0
      break;
226
0
    }
227
0
  }
228
229
0
  if (rc == FR_UNKNOWN) // Not our function
230
0
    return rc;
231
232
0
  const char *result = dispatcher_get_retval_name(rc);
233
0
  mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
234
235
0
  return rc;
236
0
}