1 /*- 2 * Copyright (c) 2009 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Alistair Crooks (agc@NetBSD.org) 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 #include "config.h" 30 31 #ifdef HAVE_SYS_CDEFS_H 32 #include <sys/cdefs.h> 33 #endif 34 35 #if defined(__NetBSD__) 36 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved."); 37 __RCSID("$NetBSD: netpgp.c,v 1.29 2009/10/07 04:18:47 agc Exp $"); 38 #endif 39 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <sys/param.h> 43 #include <sys/mman.h> 44 45 #ifdef HAVE_SYS_RESOURCE_H 46 #include <sys/resource.h> 47 #endif 48 49 #ifdef HAVE_FCNTL_H 50 #include <fcntl.h> 51 #endif 52 53 #include <regex.h> 54 #include <stdarg.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <time.h> 58 59 #ifdef HAVE_UNISTD_H 60 #include <unistd.h> 61 #endif 62 63 #include <errno.h> 64 65 #ifdef HAVE_LIMITS_H 66 #include <limits.h> 67 #endif 68 69 #include <netpgp.h> 70 71 #include "packet.h" 72 #include "packet-parse.h" 73 #include "keyring.h" 74 #include "errors.h" 75 #include "packet-show.h" 76 #include "create.h" 77 #include "netpgpsdk.h" 78 #include "memory.h" 79 #include "validate.h" 80 #include "readerwriter.h" 81 #include "netpgpdefs.h" 82 #include "crypto.h" 83 84 /* read any gpg config file */ 85 static int 86 conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length) 87 { 88 regmatch_t matchv[10]; 89 regex_t keyre; 90 char buf[BUFSIZ]; 91 FILE *fp; 92 93 __OPS_USED(netpgp); 94 (void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir); 95 if ((fp = fopen(buf, "r")) == NULL) { 96 return 0; 97 } 98 (void) memset(&keyre, 0x0, sizeof(keyre)); 99 (void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)", 100 REG_EXTENDED); 101 while (fgets(buf, sizeof(buf), fp) != NULL) { 102 if (regexec(&keyre, buf, 10, matchv, 0) == 0) { 103 (void) memcpy(userid, &buf[(int)matchv[1].rm_so], 104 MIN((unsigned)(matchv[1].rm_eo - 105 matchv[1].rm_so), length)); 106 (void) fprintf(stderr, 107 "netpgp: default key set to \"%.*s\"\n", 108 (int)(matchv[1].rm_eo - matchv[1].rm_so), 109 &buf[(int)matchv[1].rm_so]); 110 } 111 } 112 (void) fclose(fp); 113 return 1; 114 } 115 116 /* small function to pretty print an 8-character raw userid */ 117 static char * 118 userid_to_id(const unsigned char *userid, char *id) 119 { 120 static const char *hexes = "0123456789abcdef"; 121 int i; 122 123 for (i = 0; i < 8 ; i++) { 124 id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4]; 125 id[(i * 2) + 1] = hexes[userid[i] & 0xf]; 126 } 127 id[8 * 2] = 0x0; 128 return id; 129 } 130 131 /* print out the successful signature information */ 132 static void 133 resultp(__ops_io_t *io, 134 const char *f, 135 __ops_validation_t *res, 136 __ops_keyring_t *ring) 137 { 138 const __ops_key_t *pubkey; 139 unsigned i; 140 char id[MAX_ID_LENGTH + 1]; 141 142 for (i = 0; i < res->validc; i++) { 143 (void) fprintf(io->res, 144 "Good signature for %s made %susing %s key %s\n", 145 f, 146 ctime(&res->valid_sigs[i].birthtime), 147 __ops_show_pka(res->valid_sigs[i].key_alg), 148 userid_to_id(res->valid_sigs[i].signer_id, id)); 149 pubkey = __ops_getkeybyid(io, ring, 150 (const unsigned char *) res->valid_sigs[i].signer_id); 151 __ops_print_pubkeydata(io, pubkey); 152 } 153 } 154 155 /* check there's enough space in the arrays */ 156 static int 157 size_arrays(netpgp_t *netpgp, unsigned needed) 158 { 159 char **temp; 160 161 if (netpgp->size == 0) { 162 /* only get here first time around */ 163 netpgp->size = needed; 164 if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) { 165 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 166 return 0; 167 } 168 if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) { 169 free(netpgp->name); 170 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 171 return 0; 172 } 173 } else if (netpgp->c == netpgp->size) { 174 /* only uses 'needed' when filled array */ 175 netpgp->size += needed; 176 temp = realloc(netpgp->name, sizeof(char *) * needed); 177 if (temp == NULL) { 178 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 179 return 0; 180 } 181 netpgp->name = temp; 182 temp = realloc(netpgp->value, sizeof(char *) * needed); 183 if (temp == NULL) { 184 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 185 return 0; 186 } 187 netpgp->value = temp; 188 } 189 return 1; 190 } 191 192 /* find the name in the array */ 193 static int 194 findvar(netpgp_t *netpgp, const char *name) 195 { 196 unsigned i; 197 198 for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) { 199 } 200 return (i == netpgp->c) ? -1 : (int)i; 201 } 202 203 /* read a keyring and return it */ 204 static void * 205 readkeyring(netpgp_t *netpgp, const char *name) 206 { 207 __ops_keyring_t *keyring; 208 const unsigned noarmor = 0; 209 char f[MAXPATHLEN]; 210 char *filename; 211 char *homedir; 212 213 homedir = netpgp_getvar(netpgp, "homedir"); 214 if ((filename = netpgp_getvar(netpgp, name)) == NULL) { 215 (void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name); 216 filename = f; 217 } 218 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 219 (void) fprintf(stderr, "readkeyring: bad alloc\n"); 220 return NULL; 221 } 222 if (!__ops_keyring_fileread(keyring, noarmor, filename)) { 223 free(keyring); 224 (void) fprintf(stderr, "Can't read %s %s\n", name, filename); 225 return NULL; 226 } 227 netpgp_setvar(netpgp, name, filename); 228 return keyring; 229 } 230 231 /***************************************************************************/ 232 /* exported functions start here */ 233 /***************************************************************************/ 234 235 /* initialise a netpgp_t structure */ 236 int 237 netpgp_init(netpgp_t *netpgp) 238 { 239 __ops_io_t *io; 240 char id[MAX_ID_LENGTH]; 241 char *homedir; 242 char *userid; 243 char *stream; 244 char *passfd; 245 char *results; 246 int coredumps; 247 248 #ifdef HAVE_SYS_RESOURCE_H 249 struct rlimit limit; 250 251 coredumps = netpgp_getvar(netpgp, "coredumps") != NULL; 252 if (!coredumps) { 253 (void) memset(&limit, 0x0, sizeof(limit)); 254 if (setrlimit(RLIMIT_CORE, &limit) != 0) { 255 (void) fprintf(stderr, 256 "netpgp_init: warning - can't turn off core dumps\n"); 257 coredumps = 1; 258 } 259 } 260 #else 261 coredumps = 1; 262 #endif 263 if ((io = calloc(1, sizeof(*io))) == NULL) { 264 (void) fprintf(stderr, "netpgp_init: bad alloc\n"); 265 return 0; 266 } 267 io->outs = stdout; 268 if ((stream = netpgp_getvar(netpgp, "stdout")) != NULL && 269 strcmp(stream, "stderr") == 0) { 270 io->outs = stderr; 271 } 272 io->errs = stderr; 273 if ((stream = netpgp_getvar(netpgp, "stderr")) != NULL && 274 strcmp(stream, "stdout") == 0) { 275 io->errs = stdout; 276 } 277 io->errs = stderr; 278 netpgp->io = io; 279 if (coredumps) { 280 (void) fprintf(io->errs, 281 "netpgp: warning: core dumps enabled\n"); 282 } 283 if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) { 284 (void) fprintf(io->errs, "netpgp: bad homedir\n"); 285 return 0; 286 } 287 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 288 (void) memset(id, 0x0, sizeof(id)); 289 (void) conffile(netpgp, homedir, id, sizeof(id)); 290 if (id[0] != 0x0) { 291 netpgp_setvar(netpgp, "userid", userid = id); 292 } 293 } 294 if (userid == NULL) { 295 if (netpgp_getvar(netpgp, "need userid") != NULL) { 296 (void) fprintf(io->errs, "Cannot find user id\n"); 297 return 0; 298 } 299 } else { 300 (void) netpgp_setvar(netpgp, "userid", userid); 301 } 302 if ((netpgp->pubring = readkeyring(netpgp, "pubring")) == NULL) { 303 (void) fprintf(io->errs, "Can't read pub keyring\n"); 304 return 0; 305 } 306 if ((netpgp->secring = readkeyring(netpgp, "secring")) == NULL) { 307 (void) fprintf(io->errs, "Can't read sec keyring\n"); 308 return 0; 309 } 310 if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL && 311 (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) { 312 (void) fprintf(io->errs, "Can't open fd %s for reading\n", 313 passfd); 314 return 0; 315 } 316 if ((results = netpgp_getvar(netpgp, "results")) == NULL) { 317 io->res = io->errs; 318 } else if ((io->res = fopen(results, "w")) == NULL) { 319 (void) fprintf(io->errs, "Can't open results %s for writing\n", 320 results); 321 return 0; 322 } 323 return 1; 324 } 325 326 /* finish off with the netpgp_t struct */ 327 int 328 netpgp_end(netpgp_t *netpgp) 329 { 330 unsigned i; 331 332 for (i = 0 ; i < netpgp->c ; i++) { 333 if (netpgp->name[i] != NULL) { 334 free(netpgp->name[i]); 335 } 336 if (netpgp->value[i] != NULL) { 337 free(netpgp->value[i]); 338 } 339 } 340 if (netpgp->name != NULL) { 341 free(netpgp->name); 342 } 343 if (netpgp->value != NULL) { 344 free(netpgp->value); 345 } 346 if (netpgp->pubring != NULL) { 347 __ops_keyring_free(netpgp->pubring); 348 } 349 if (netpgp->secring != NULL) { 350 __ops_keyring_free(netpgp->secring); 351 } 352 free(netpgp->io); 353 return 1; 354 } 355 356 /* list the keys in a keyring */ 357 int 358 netpgp_list_keys(netpgp_t *netpgp) 359 { 360 return __ops_keyring_list(netpgp->io, netpgp->pubring); 361 } 362 363 /* find a key in a keyring */ 364 int 365 netpgp_find_key(netpgp_t *netpgp, char *id) 366 { 367 __ops_io_t *io; 368 369 io = netpgp->io; 370 if (id == NULL) { 371 (void) fprintf(io->errs, "NULL id to search for\n"); 372 return 0; 373 } 374 return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL; 375 } 376 377 /* export a given key */ 378 int 379 netpgp_export_key(netpgp_t *netpgp, char *userid) 380 { 381 const __ops_key_t *keypair; 382 __ops_io_t *io; 383 384 io = netpgp->io; 385 if (userid == NULL) { 386 userid = netpgp_getvar(netpgp, "userid"); 387 } 388 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 389 if (keypair == NULL) { 390 (void) fprintf(io->errs, 391 "Cannot find own key \"%s\" in keyring\n", userid); 392 return 0; 393 } 394 return __ops_export_key(keypair, NULL); 395 } 396 397 /* import a key into our keyring */ 398 int 399 netpgp_import_key(netpgp_t *netpgp, char *f) 400 { 401 const unsigned noarmor = 0; 402 const unsigned armor = 1; 403 __ops_io_t *io; 404 int done; 405 406 io = netpgp->io; 407 if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) { 408 done = __ops_keyring_fileread(netpgp->pubring, armor, f); 409 } 410 if (!done) { 411 (void) fprintf(io->errs, "Cannot import key from file %s\n", 412 f); 413 return 0; 414 } 415 return __ops_keyring_list(io, netpgp->pubring); 416 } 417 418 /* generate a new key */ 419 int 420 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 421 { 422 __ops_key_t *keypair; 423 __ops_userid_t uid; 424 __ops_output_t *create; 425 const unsigned noarmor = 0; 426 __ops_io_t *io; 427 char *ringfile; 428 int fd; 429 430 (void) memset(&uid, 0x0, sizeof(uid)); 431 io = netpgp->io; 432 /* generate a new key for 'id' */ 433 uid.userid = (unsigned char *) id; 434 keypair = __ops_rsa_new_selfsign_key(numbits, 65537UL, &uid); 435 if (keypair == NULL) { 436 (void) fprintf(io->errs, "Cannot generate key\n"); 437 return 0; 438 } 439 /* write public key, and try to re-read it */ 440 ringfile = netpgp_getvar(netpgp, "pubring"); 441 fd = __ops_setup_file_append(&create, ringfile); 442 if (!__ops_write_xfer_pubkey(create, keypair, noarmor)) { 443 (void) fprintf(io->errs, "Cannot write pubkey\n"); 444 return 0; 445 } 446 __ops_teardown_file_write(create, fd); 447 __ops_keyring_free(netpgp->pubring); 448 if (!__ops_keyring_fileread(netpgp->pubring, noarmor, ringfile)) { 449 (void) fprintf(io->errs, "Cannot read pubring %s\n", ringfile); 450 return 0; 451 } 452 /* write secret key, and try to re-read it */ 453 ringfile = netpgp_getvar(netpgp, "sec ring file"); 454 fd = __ops_setup_file_append(&create, ringfile); 455 if (!__ops_write_xfer_seckey(create, keypair, NULL, 0, noarmor)) { 456 (void) fprintf(io->errs, "Cannot write seckey\n"); 457 return 0; 458 } 459 __ops_teardown_file_write(create, fd); 460 __ops_keyring_free(netpgp->secring); 461 if (!__ops_keyring_fileread(netpgp->secring, noarmor, ringfile)) { 462 (void) fprintf(io->errs, "Can't read secring %s\n", ringfile); 463 return 0; 464 } 465 __ops_keydata_free(keypair); 466 return 1; 467 } 468 469 /* encrypt a file */ 470 int 471 netpgp_encrypt_file(netpgp_t *netpgp, 472 const char *userid, 473 const char *f, 474 char *out, 475 int armored) 476 { 477 const __ops_key_t *keypair; 478 const unsigned overwrite = 1; 479 const char *suffix; 480 __ops_io_t *io; 481 char outname[MAXPATHLEN]; 482 483 io = netpgp->io; 484 if (f == NULL) { 485 (void) fprintf(io->errs, 486 "netpgp_encrypt_file: no filename specified\n"); 487 return 0; 488 } 489 if (userid == NULL) { 490 userid = netpgp_getvar(netpgp, "userid"); 491 } 492 suffix = (armored) ? ".asc" : ".gpg"; 493 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 494 if (keypair == NULL) { 495 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 496 userid); 497 return 0; 498 } 499 if (out == NULL) { 500 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 501 out = outname; 502 } 503 return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored, 504 overwrite); 505 } 506 507 /* decrypt a file */ 508 int 509 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored) 510 { 511 const unsigned overwrite = 1; 512 __ops_io_t *io; 513 514 io = netpgp->io; 515 if (f == NULL) { 516 (void) fprintf(io->errs, 517 "netpgp_decrypt_file: no filename specified\n"); 518 return 0; 519 } 520 return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring, 521 (unsigned)armored, overwrite, netpgp->passfp, 522 get_passphrase_cb); 523 } 524 525 /* sign a file */ 526 int 527 netpgp_sign_file(netpgp_t *netpgp, 528 const char *userid, 529 const char *f, 530 char *out, 531 int armored, 532 int cleartext, 533 int detached) 534 { 535 const __ops_key_t *keypair; 536 __ops_seckey_t *seckey; 537 const unsigned overwrite = 1; 538 __ops_io_t *io; 539 char *hashalg; 540 int ret; 541 542 io = netpgp->io; 543 if (f == NULL) { 544 (void) fprintf(io->errs, 545 "netpgp_sign_file: no filename specified\n"); 546 return 0; 547 } 548 if (userid == NULL) { 549 userid = netpgp_getvar(netpgp, "userid"); 550 } 551 /* get key with which to sign */ 552 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 553 if (keypair == NULL) { 554 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 555 userid); 556 return 0; 557 } 558 ret = 1; 559 do { 560 /* print out the user id */ 561 __ops_print_pubkeydata(io, keypair); 562 /* now decrypt key */ 563 seckey = __ops_decrypt_seckey(keypair); 564 if (seckey == NULL) { 565 (void) fprintf(io->errs, "Bad passphrase\n"); 566 } 567 } while (seckey == NULL); 568 /* sign file */ 569 hashalg = netpgp_getvar(netpgp, "hash"); 570 if (cleartext) { 571 ret = __ops_sign_file_as_cleartext(io, f, out, seckey, 572 hashalg, overwrite); 573 } else if (detached) { 574 ret = __ops_sign_detached(io, f, out, seckey, hashalg); 575 } else { 576 ret = __ops_sign_file(io, f, out, seckey, hashalg, 577 (unsigned)armored, overwrite); 578 } 579 __ops_forget(seckey, sizeof(*seckey)); 580 return ret; 581 } 582 583 /* verify a file */ 584 int 585 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored) 586 { 587 __ops_validation_t result; 588 __ops_io_t *io; 589 590 (void) memset(&result, 0x0, sizeof(result)); 591 io = netpgp->io; 592 if (in == NULL) { 593 (void) fprintf(io->errs, 594 "netpgp_verify_file: no filename specified\n"); 595 return 0; 596 } 597 if (__ops_validate_file(io, &result, in, out, armored, 598 netpgp->pubring)) { 599 resultp(io, in, &result, netpgp->pubring); 600 return 1; 601 } 602 if (result.validc + result.invalidc + result.unknownc == 0) { 603 (void) fprintf(io->errs, 604 "\"%s\": No signatures found - is this a signed file?\n", 605 in); 606 } else { 607 (void) fprintf(io->errs, 608 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n", 609 in, result.invalidc, result.unknownc); 610 } 611 return 0; 612 } 613 614 /* wrappers for the ops_debug_level functions we added to openpgpsdk */ 615 616 /* set the debugging level per filename */ 617 int 618 netpgp_set_debug(const char *f) 619 { 620 return __ops_set_debug_level(f); 621 } 622 623 /* get the debugging level per filename */ 624 int 625 netpgp_get_debug(const char *f) 626 { 627 return __ops_get_debug_level(f); 628 } 629 630 /* return the version for the library */ 631 const char * 632 netpgp_get_info(const char *type) 633 { 634 return __ops_get_info(type); 635 } 636 637 /* list all the packets in a file */ 638 int 639 netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname) 640 { 641 __ops_keyring_t *keyring; 642 const unsigned noarmor = 0; 643 __ops_io_t *io; 644 char ringname[MAXPATHLEN]; 645 char *homedir; 646 int ret; 647 648 io = netpgp->io; 649 if (f == NULL) { 650 (void) fprintf(io->errs, "No file containing packets\n"); 651 return 0; 652 } 653 homedir = netpgp_getvar(netpgp, "homedir"); 654 if (pubringname == NULL) { 655 (void) snprintf(ringname, sizeof(ringname), 656 "%s/pubring.gpg", homedir); 657 pubringname = ringname; 658 } 659 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 660 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n"); 661 return 0; 662 } 663 if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) { 664 free(keyring); 665 (void) fprintf(io->errs, "Cannot read pub keyring %s\n", 666 pubringname); 667 return 0; 668 } 669 netpgp->pubring = keyring; 670 netpgp_setvar(netpgp, "pubring", pubringname); 671 ret = __ops_list_packets(io, f, (unsigned)armour, keyring, 672 netpgp->passfp, 673 get_passphrase_cb); 674 free(keyring); 675 return ret; 676 } 677 678 /* set a variable */ 679 int 680 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value) 681 { 682 int i; 683 684 if ((i = findvar(netpgp, name)) < 0) { 685 /* add the element to the array */ 686 if (size_arrays(netpgp, netpgp->size + 15)) { 687 netpgp->name[i = netpgp->c++] = strdup(name); 688 } 689 } else { 690 /* replace the element in the array */ 691 if (netpgp->value[i]) { 692 free(netpgp->value[i]); 693 netpgp->value[i] = NULL; 694 } 695 } 696 /* sanity checks for range of values */ 697 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) { 698 if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) { 699 return 0; 700 } 701 } 702 netpgp->value[i] = strdup(value); 703 return 1; 704 } 705 706 /* get a variable's value (NULL if not set) */ 707 char * 708 netpgp_getvar(netpgp_t *netpgp, const char *name) 709 { 710 int i; 711 712 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i]; 713 } 714