"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/src/pgp.c" (9 Dec 2022, 13291 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "pgp.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.6.1_vs_2.6.2.
1 /*
2 * Project : tin - a Usenet reader
3 * Module : pgp.c
4 * Author : Steven J. Madsen
5 * Created : 1995-05-12
6 * Updated : 2022-02-19
7 * Notes : PGP support
8 *
9 * Copyright (c) 1995-2023 Steven J. Madsen <steve@erinet.com>
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * 3. Neither the name of the copyright holder nor the names of its
24 * contributors may be used to endorse or promote products derived from
25 * this software without specific prior written permission.
26 *
27 * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40
41 #ifndef TIN_H
42 # include "tin.h"
43 #endif /* !TIN_H */
44
45 #ifdef HAVE_PGP_GPG
46 # ifndef TCURSES_H
47 # include "tcurses.h"
48 # endif /* !TCURSES_H */
49
50
51 /*
52 * The first two args are typically the PGP command name and then $PGPOPTS
53 * NB: The '1' variations on DO_{SIGN,BOTH} are used when local-user name is
54 * used and are valid only when signing
55 */
56 # if defined(HAVE_PGP) /* pgp-2 */
57 # define PGPNAME PATH_PGP
58 # define PGPDIR ".pgp"
59 # define PGP_PUBRING "pubring.pgp"
60 # define CHECK_SIGN "%s %s -f <%s %s"
61 # define ADD_KEY "%s %s -ka %s"
62 # define APPEND_KEY "%s %s -kxa %s %s", PGPNAME, pgpopts, buf, keyfile
63 # define DO_ENCRYPT "%s %s -ate %s %s", PGPNAME, pgpopts, pt, mailto
64 # define DO_SIGN "%s %s -ats %s %s", PGPNAME, pgpopts, pt, mailto
65 # define DO_SIGN1 "%s %s -ats %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
66 # define DO_BOTH "%s %s -ates %s %s", PGPNAME, pgpopts, pt, mailto
67 # define DO_BOTH1 "%s %s -ates %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
68 # endif /* HAVE_PGP */
69
70 # if defined(HAVE_PGPK) /* pgp-5 */
71 # define PGPNAME "pgp" /* FIXME: this is AFAIK not PATH_PGPK */
72 # define PGPDIR ".pgp"
73 # define PGP_PUBRING "pubring.pkr"
74 # define CHECK_SIGN "%sv %s -f <%s %s"
75 # define ADD_KEY "%sk %s -a %s"
76 # define APPEND_KEY "%sk %s -xa %s -o %s", PGPNAME, pgpopts, keyfile, buf
77 # define DO_ENCRYPT "%se %s -at %s %s", PGPNAME, pgpopts, pt, mailto
78 # define DO_SIGN "%ss %s -at %s %s", PGPNAME, pgpopts, pt, mailto
79 # define DO_SIGN1 "%ss %s -at %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
80 # define DO_BOTH "%se %s -ats %s %s", PGPNAME, pgpopts, pt, mailto
81 # define DO_BOTH1 "%se %s -ats %s %s -u %s", PGPNAME, pgpopts, pt, mailto, mailfrom
82 # endif /* HAVE_PGPK */
83
84 # if defined(HAVE_GPG) /* gpg */
85 # define PGPNAME PATH_GPG
86 # define PGPDIR ".gnupg"
87 # define PGP_PUBRING "pubring.gpg"
88 # if 0 /* gpg 1.4.11 doesn't like this */
89 # define CHECK_SIGN "%s %s --no-batch --decrypt <%s %s"
90 # else
91 # define CHECK_SIGN "%s %s < %s %s"
92 # endif /* 0 */
93 # define ADD_KEY "%s %s --no-batch --import %s"
94 # define APPEND_KEY "%s %s --no-batch --armor --output %s --export %s", PGPNAME, pgpopts, keyfile, buf
95 # define DO_ENCRYPT \
96 "%s %s --textmode --armor --no-batch --output %s.asc --recipient %s --encrypt %s", \
97 PGPNAME, pgpopts, pt, mailto, pt
98 # define DO_SIGN \
99 "%s %s --textmode --armor --no-batch --output %s.asc --escape-from --clearsign %s", \
100 PGPNAME, pgpopts, pt, pt
101 # define DO_SIGN1 \
102 "%s %s --textmode --armor --no-batch --local-user %s --output %s.asc --escape-from --clearsign %s", \
103 PGPNAME, pgpopts, mailfrom, pt, pt
104 # define DO_BOTH \
105 "%s %s --textmode --armor --no-batch --output %s.asc --recipient %s --sign --encrypt %s", \
106 PGPNAME, pgpopts, pt, mailto, pt
107 # define DO_BOTH1 \
108 "%s %s --textmode --armor --no-batch --output %s.asc --recipient %s --local-user %s --sign --encrypt %s", \
109 PGPNAME, pgpopts, pt, mailto, mailfrom, pt
110 # endif /* HAVE_GPG */
111
112 /* RFC 4880 6.2 */
113 # define PGP_SIG_TAG "-----BEGIN PGP SIGNED MESSAGE-----\n"
114 # define PGP_KEY_TAG "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
115
116 # define HEADERS "tin-%ld.h"
117 # ifdef HAVE_LONG_FILE_NAMES
118 # define PLAINTEXT "tin-%ld.pt"
119 # define CIPHERTEXT "tin-%ld.pt.asc"
120 # define KEYFILE "tin-%ld.k.asc"
121 # else
122 # define PLAINTEXT "tn-%ld.p"
123 # define CIPHERTEXT "tn-%ld.p.asc"
124 # define KEYFILE "tn-%ld.k.asc"
125 # endif /* HAVE_LONG_FILE_NAMES */
126
127
128 /*
129 * local prototypes
130 */
131 static t_bool pgp_available(void);
132 static void do_pgp(t_function what, const char *file, const char *mail_to);
133 static void join_files(const char *file);
134 static void pgp_append_public_key(char *file);
135 static void split_file(const char *file);
136
137 static char pgp_data[PATH_LEN];
138 static char hdr[PATH_LEN], pt[PATH_LEN], ct[PATH_LEN];
139 static const char *pgpopts = "";
140
141
142 void
143 init_pgp(
144 void)
145 {
146 char *ptr;
147
148 pgpopts = get_val("PGPOPTS", "");
149
150 # ifdef HAVE_GPG
151 if ((ptr = getenv("GNUPGHOME")) != NULL)
152 my_strncpy(pgp_data, ptr, sizeof(pgp_data) - 1);
153 else
154 # endif /* HAVE_GPG */
155 {
156 if ((ptr = getenv("PGPPATH")) != NULL)
157 my_strncpy(pgp_data, ptr, sizeof(pgp_data) - 1);
158 else
159 joinpath(pgp_data, sizeof(pgp_data), homedir, PGPDIR);
160 }
161 }
162
163
164 /*
165 * Write the header file then the ciphertext file to the art file
166 * This function is void, no way to return errs
167 */
168 static void
169 join_files(
170 const char *file)
171 {
172 FILE *art, *header, *text;
173
174 if ((header = fopen(hdr, "r")) != NULL) {
175 if ((text = fopen(ct, "r")) != NULL) {
176 if ((art = fopen(file, "w")) != NULL) {
177 if (copy_fp(header, art))
178 copy_fp(text, art);
179 fclose(art);
180 }
181 fclose(text);
182 }
183 fclose(header);
184 }
185
186 unlink(hdr);
187 unlink(pt);
188 unlink(ct);
189 }
190
191
192 /*
193 * Split the file parameter into a header file 'hdr' and a plaintext
194 * file 'pt'
195 */
196 static void
197 split_file(
198 const char *file)
199 {
200 FILE *art, *header, *plaintext;
201 char buf[LEN];
202 char tmp[PATH_LEN];
203 mode_t mask;
204
205 snprintf(tmp, sizeof(tmp), HEADERS, (long) process_id);
206 joinpath(hdr, sizeof(hdr), tmpdir, tmp);
207 snprintf(tmp, sizeof(tmp), PLAINTEXT, (long) process_id);
208 joinpath(pt, sizeof(pt), tmpdir, tmp);
209 snprintf(tmp, sizeof(tmp), CIPHERTEXT, (long) process_id);
210 joinpath(ct, sizeof(ct), tmpdir, tmp);
211
212 if ((art = fopen(file, "r")) == NULL)
213 return;
214
215 mask = umask((mode_t) (S_IRWXO|S_IRWXG));
216
217 if ((header = fopen(hdr, "w")) == NULL)
218 goto err_art;
219
220 if ((plaintext = fopen(pt, "w")) == NULL)
221 goto err_hdr;
222
223 if (fgets(buf, LEN, art) != NULL) { /* Copy the hdr up to and including the \n */
224 while (strcmp(buf, "\n")) {
225 fputs(buf, header);
226 fgets(buf, LEN, art);
227 }
228 fputs(buf, header);
229 copy_fp(art, plaintext);
230 }
231
232 fclose(plaintext);
233 err_hdr:
234 fclose(header);
235 err_art:
236 fclose(art);
237 umask(mask);
238 }
239
240
241 static void
242 do_pgp(
243 t_function what,
244 const char *file,
245 const char *mail_to)
246 {
247 char cmd[LEN];
248 char mailfrom[LEN];
249 const char *mailto = BlankIfNull(mail_to);
250
251 mailfrom[0] = '\0';
252
253 split_file(file);
254
255 /*
256 * <mailfrom> is valid only when signing and a local address exists
257 */
258 if ((CURR_GROUP.attribute->from) != NULL)
259 strip_name(CURR_GROUP.attribute->from, mailfrom);
260
261 switch (what) {
262 case PGP_KEY_SIGN:
263 if (*mailfrom)
264 sh_format(cmd, sizeof(cmd), DO_SIGN1);
265 else
266 sh_format(cmd, sizeof(cmd), DO_SIGN);
267 invoke_cmd(cmd);
268 break;
269
270 case PGP_KEY_ENCRYPT_SIGN:
271 if (*mailfrom)
272 sh_format(cmd, sizeof(cmd), DO_BOTH1);
273 else
274 sh_format(cmd, sizeof(cmd), DO_BOTH);
275 invoke_cmd(cmd);
276 break;
277
278 case PGP_KEY_ENCRYPT:
279 sh_format(cmd, sizeof(cmd), DO_ENCRYPT);
280 invoke_cmd(cmd);
281 break;
282
283 default:
284 break;
285 }
286
287 join_files(file);
288 }
289
290
291 static void
292 pgp_append_public_key(
293 char *file)
294 {
295 FILE *fp, *key;
296 char cmd[LEN], buf[LEN];
297 char keyfile[PATH_LEN], tmp[PATH_LEN];
298
299 if ((CURR_GROUP.attribute->from) != NULL && strlen(CURR_GROUP.attribute->from))
300 strip_name(CURR_GROUP.attribute->from, buf);
301 else
302 snprintf(buf, sizeof(buf), "%s@%s", userid, BlankIfNull(get_host_name()));
303
304 snprintf(tmp, sizeof(tmp), KEYFILE, (long) process_id);
305 joinpath(keyfile, sizeof(keyfile), tmpdir, tmp);
306
307 /*
308 * TODO: I'm guessing the pgp append key command creates 'keyfile' and that
309 * we should remove it
310 */
311 sh_format(cmd, sizeof(cmd), APPEND_KEY);
312 if (invoke_cmd(cmd)) {
313 if ((fp = fopen(file, "a")) != NULL) {
314 if ((key = fopen(keyfile, "r")) != NULL) {
315 fputc('\n', fp); /* Add a blank line */
316 copy_fp(key, fp); /* and copy in the key */
317 fclose(key);
318 }
319 fclose(fp);
320 }
321 unlink(keyfile);
322 }
323 }
324
325
326 /*
327 * Simply check for existence of keyring file
328 */
329 static t_bool
330 pgp_available(
331 void)
332 {
333 FILE *fp;
334 char keyring[PATH_LEN];
335
336 joinpath(keyring, sizeof(keyring), pgp_data, PGP_PUBRING);
337 if ((fp = fopen(keyring, "r")) == NULL) {
338 wait_message(2, _(txt_pgp_not_avail), keyring);
339 return FALSE;
340 }
341
342 fclose(fp);
343 return TRUE;
344 }
345
346
347 void
348 invoke_pgp_mail(
349 const char *nam,
350 char *mail_to)
351 {
352 char keyboth[MAXKEYLEN], keyencrypt[MAXKEYLEN], keyquit[MAXKEYLEN];
353 char keysign[MAXKEYLEN];
354 t_function func, default_func = PGP_KEY_SIGN;
355
356 if (!pgp_available())
357 return;
358
359 func = prompt_slk_response(default_func, pgp_mail_keys, _(txt_pgp_mail),
360 PrintFuncKey(keyencrypt, PGP_KEY_ENCRYPT, pgp_mail_keys),
361 PrintFuncKey(keysign, PGP_KEY_SIGN, pgp_mail_keys),
362 PrintFuncKey(keyboth, PGP_KEY_ENCRYPT_SIGN, pgp_mail_keys),
363 PrintFuncKey(keyquit, GLOBAL_QUIT, pgp_mail_keys));
364 switch (func) {
365 case PGP_KEY_SIGN:
366 # ifdef HAVE_PGPK
367 ClearScreen();
368 MoveCursor(cLINES - 7, 0);
369 # endif /* HAVE_PGPK */
370 do_pgp(func, nam, NULL);
371 break;
372
373 case PGP_KEY_ENCRYPT_SIGN:
374 # ifdef HAVE_PGPK
375 ClearScreen();
376 MoveCursor(cLINES - 7, 0);
377 # endif /* HAVE_PGPK */
378 do_pgp(func, nam, mail_to);
379 break;
380
381 case PGP_KEY_ENCRYPT:
382 do_pgp(func, nam, mail_to);
383 break;
384
385 case GLOBAL_ABORT:
386 case GLOBAL_QUIT:
387 default:
388 break;
389 }
390 }
391
392
393 void
394 invoke_pgp_news(
395 char *artfile)
396 {
397 char keyinclude[MAXKEYLEN], keyquit[MAXKEYLEN], keysign[MAXKEYLEN];
398 t_function func, default_func = PGP_KEY_SIGN;
399
400 if (!pgp_available())
401 return;
402
403 func = prompt_slk_response(default_func, pgp_news_keys, _(txt_pgp_news),
404 PrintFuncKey(keysign, PGP_KEY_SIGN, pgp_news_keys),
405 PrintFuncKey(keyinclude, PGP_INCLUDE_KEY, pgp_news_keys),
406 PrintFuncKey(keyquit, GLOBAL_QUIT, pgp_news_keys));
407 switch (func) {
408 case GLOBAL_ABORT:
409 case GLOBAL_QUIT:
410 break;
411
412 case PGP_KEY_SIGN:
413 # ifdef HAVE_PGPK
414 info_message(" ");
415 MoveCursor(cLINES - 7, 0);
416 my_printf("\n");
417 # endif /* HAVE_PGPK */
418 do_pgp(func, artfile, NULL);
419 break;
420
421 case PGP_INCLUDE_KEY:
422 # ifdef HAVE_PGPK
423 info_message(" ");
424 MoveCursor(cLINES - 7, 0);
425 my_printf("\n");
426 # endif /* HAVE_PGPK */
427 do_pgp(PGP_KEY_SIGN, artfile, NULL);
428 pgp_append_public_key(artfile);
429 break;
430
431 default:
432 break;
433 }
434 }
435
436
437 t_bool
438 pgp_check_article(
439 t_openartinfo *artinfo)
440 {
441 FILE *art;
442 char artfile[PATH_LEN], buf[LEN], cmd[LEN];
443 t_bool pgp_signed = FALSE;
444 t_bool pgp_key = FALSE;
445
446 if (!pgp_available())
447 return FALSE;
448
449 joinpath(artfile, sizeof(artfile), homedir, TIN_ARTICLE_NAME);
450 # ifdef APPEND_PID
451 snprintf(artfile + strlen(artfile), sizeof(artfile) - strlen(artfile), ".%ld", (long) process_id);
452 # endif /* APPEND_PID */
453 if ((art = fopen(artfile, "w")) == NULL) {
454 info_message(_(txt_cannot_open), artfile);
455 return FALSE;
456 }
457 /* -> start of body */
458 if (fseek(artinfo->raw, artinfo->hdr.ext->offset, SEEK_SET) != 0) {
459 fclose(art);
460 return FALSE;
461 }
462
463 if (fgets(buf, LEN, artinfo->raw) != NULL) { /* Copy the body whilst looking for SIG/KEY tags */
464 while (!feof(artinfo->raw)) {
465 if (!pgp_signed && !strcmp(buf, PGP_SIG_TAG))
466 pgp_signed = TRUE;
467 if (!pgp_key && !strcmp(buf, PGP_KEY_TAG))
468 pgp_key = TRUE;
469 fputs(buf, art);
470 fgets(buf, LEN, artinfo->raw);
471 }
472 }
473 fclose(art);
474
475 if (!(pgp_signed || pgp_key)) {
476 info_message(_(txt_pgp_nothing));
477 return FALSE;
478 }
479 ClearScreen();
480
481 if (pgp_signed) {
482 Raw(FALSE);
483
484 /*
485 * We don't use sh_format here else the redirection get misquoted
486 */
487 snprintf(cmd, sizeof(cmd), CHECK_SIGN, PGPNAME, pgpopts, artfile, REDIRECT_PGP_OUTPUT);
488 invoke_cmd(cmd);
489 my_printf("\n");
490 Raw(TRUE);
491 }
492 # ifndef USE_CURSES
493 EndWin();
494 Raw(FALSE);
495 # endif /* !USE_CURSES */
496 prompt_continue();
497 # ifndef USE_CURSES
498 Raw(TRUE);
499 InitWin();
500 # endif /* !USE_CURSES */
501 if (pgp_key) {
502 if (prompt_yn(_(txt_pgp_add), FALSE) == 1) {
503 Raw(FALSE);
504
505 sh_format(cmd, sizeof(cmd), ADD_KEY, PGPNAME, pgpopts, artfile);
506 invoke_cmd(cmd);
507 my_printf("\n");
508 Raw(TRUE);
509 }
510 }
511
512 unlink(artfile);
513 return TRUE;
514 }
515 #endif /* HAVE_PGP_GPG */