From cvs at cvs.gnupg.org Mon Feb 6 17:13:21 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon Feb 6 16:32:20 2006 Subject: [svn] GnuPG - r3994 - branches/GNUPG-1-9-BRANCH/scd Message-ID: Author: wk Date: 2006-02-06 17:13:20 +0100 (Mon, 06 Feb 2006) New Revision: 3994 Modified: branches/GNUPG-1-9-BRANCH/scd/ChangeLog branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c Log: Support for CardMan 4040 Modified: branches/GNUPG-1-9-BRANCH/scd/ChangeLog =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/ChangeLog 2006-01-26 16:51:04 UTC (rev 3993) +++ branches/GNUPG-1-9-BRANCH/scd/ChangeLog 2006-02-06 16:13:20 UTC (rev 3994) @@ -1,3 +1,18 @@ +2006-02-02 Werner Koch + + * ccid-driver.c (special_transport): New + (ccid_open_reader, do_close_reader, ccid_shutdown_reader) + (bulk_out, bulk_in): Add support for CardMan 4040 reader. + + * ccid-driver.c (scan_or_find_devices): Factored most code out to + (scan_or_find_usb_device): .. new. + (make_reader_id): Fixed vendor mask. + +2006-01-01 Werner Koch + + * app-openpgp.c (do_sign): Give user error if hash algorithm is + not supported by the card. + 2005-12-06 Werner Koch * apdu.c (open_pcsc_reader): Check that pcsc-wrapper is actually Modified: branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c 2006-01-26 16:51:04 UTC (rev 3993) +++ branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c 2006-02-06 16:13:20 UTC (rev 3994) @@ -484,7 +484,7 @@ Everything up to a LF is considered a mailbox or account name. If the first LF is followed by DC4 (0x14) control sequence are expected up to the next LF. Control sequences are separated by FS - (0x28) and consist of key=value pairs. There is one key defined: + (0x18) and consist of key=value pairs. There is one key defined: F= @@ -2084,7 +2084,7 @@ raw message digest. For this application the KEYIDSTR consists of the serialnumber and the fingerprint delimited by a slash. - Note that this fucntion may return the error code + Note that this function may return the error code GPG_ERR_WRONG_CARD to indicate that the card currently present does not match the one required for the requested action (e.g. the serial number does not match). */ @@ -2120,7 +2120,11 @@ && !memcmp (indata, rmd160_prefix, 15)) ; else - return gpg_error (GPG_ERR_INV_VALUE); + { + log_error (_("card does not support digest algorithm %s\n"), + gcry_md_algo_name (hashalgo)); + return gpg_error (GPG_ERR_INV_VALUE); + } /* Check whether an OpenPGP card of any version has been requested. */ if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) Modified: branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c 2006-01-26 16:51:04 UTC (rev 3993) +++ branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c 2006-02-06 16:13:20 UTC (rev 3994) @@ -67,8 +67,8 @@ portable access to USB. This driver has been tested with the SCM SCR335 and SPR532 - smartcard readers and requires that a reader implements the TPDU - level exchange and does fully automatic initialization. + smartcard readers and requires that a reader implements APDU or + TPDU level exchange and does fully automatic initialization. */ #ifdef HAVE_CONFIG_H @@ -82,6 +82,9 @@ #include #include #include +#include +#include +#include #include @@ -194,18 +197,38 @@ /* We need to know the vendor to do some hacks. */ enum { + VENDOR_CHERRY = 0x046a, VENDOR_SCM = 0x04e6, - VENDOR_CHERRY = 0x046a, + VENDOR_OMNIKEY= 0x076b, VENDOR_GEMPC = 0x08e6 }; +/* A list and a table with special transport descriptions. */ +enum { + TRANSPORT_USB = 0, /* Standard USB transport. */ + TRANSPORT_CM4040 = 1 /* As used by the Cardman 4040. */ +}; +static struct +{ + char *name; /* Device name. */ + int type; + +} transports[] = { + { "/dev/cmx0", TRANSPORT_CM4040 }, + { "/dev/cmx1", TRANSPORT_CM4040 }, + { NULL }, +}; + + /* Store information on the driver's state. A pointer to such a structure is used as handle for most functions. */ struct ccid_driver_s { usb_dev_handle *idev; char *rid; + int dev_fd; /* -1 for USB transport or file descriptor of the + transport device. */ unsigned short id_vendor; unsigned short id_product; unsigned short bcd_device; @@ -306,8 +329,35 @@ } +/* Given a handle used for special transport prepare it for use. In + particular setup all information in way that resembles what + parse_cccid_descriptor does. */ +static void +prepare_special_transport (ccid_driver_t handle) +{ + assert (!handle->id_vendor); + handle->nonnull_nad = 0; + handle->auto_ifsd = 0; + handle->max_ifsd = 32; + handle->ifsd = 0; + handle->has_pinpad = 0; + handle->apdu_level = 0; + switch (handle->id_product) + { + case TRANSPORT_CM4040: + DEBUGOUT ("setting up transport for CardMan 4040\n"); + /* Most values are guessed. */ + handle->nonnull_nad = 1; + handle->auto_ifsd = 1; + handle->max_ifsd = 254; + handle->apdu_level = 1; + break; + default: assert (!"transport not defined"); + } +} + /* Parse a CCID descriptor, optionally print all available features and test whether this reader is usable by this driver. Returns 0 if it is usable. @@ -615,7 +665,7 @@ char *rid; char prefix[20]; - sprintf (prefix, "%04X:%04X:", (vendor & 0xfff), (product & 0xffff)); + sprintf (prefix, "%04X:%04X:", (vendor & 0xffff), (product & 0xffff)); rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0"); if (!rid) { @@ -658,10 +708,177 @@ } +/* Helper for scan_or_find_devices. This function returns true if a + requested device has been found or the caller should stop scanning + for other reasons. */ +static int +scan_or_find_usb_device (int scan_mode, + int *readerno, int *count, char **rid_list, + const char *readerid, + struct usb_device *dev, + char **r_rid, + struct usb_device **r_dev, + usb_dev_handle **r_idev, + unsigned char **ifcdesc_extra, + size_t *ifcdesc_extra_len, + int *interface_number, + int *ep_bulk_out, int *ep_bulk_in, int *ep_intr) +{ + int cfg_no; + int ifc_no; + int set_no; + struct usb_config_descriptor *config; + struct usb_interface *interface; + struct usb_interface_descriptor *ifcdesc; + char *rid; + usb_dev_handle *idev; + *r_idev = NULL; + + for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++) + { + config = dev->config + cfg_no; + if(!config) + continue; + + for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++) + { + interface = config->interface + ifc_no; + if (!interface) + continue; + + for (set_no=0; set_no < interface->num_altsetting; set_no++) + { + ifcdesc = (interface->altsetting + set_no); + /* The second condition is for older SCM SPR 532 who did + not know about the assigned CCID class. Instead of + trying to interpret the strings we simply check the + product ID. */ + if (ifcdesc && ifcdesc->extra + && ((ifcdesc->bInterfaceClass == 11 + && ifcdesc->bInterfaceSubClass == 0 + && ifcdesc->bInterfaceProtocol == 0) + || (ifcdesc->bInterfaceClass == 255 + && dev->descriptor.idVendor == VENDOR_SCM + && dev->descriptor.idProduct == 0xe003))) + { + idev = usb_open (dev); + if (!idev) + { + DEBUGOUT_1 ("usb_open failed: %s\n", + strerror (errno)); + continue; /* with next setting. */ + } + + rid = make_reader_id (idev, + dev->descriptor.idVendor, + dev->descriptor.idProduct, + dev->descriptor.iSerialNumber); + if (rid) + { + if (scan_mode) + { + char *p; + + /* We are collecting infos about all + available CCID readers. Store them and + continue. */ + DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", + *count, rid ); + p = malloc ((*rid_list? strlen (*rid_list):0) + 1 + + strlen (rid) + 1); + if (p) + { + *p = 0; + if (*rid_list) + { + strcat (p, *rid_list); + free (*rid_list); + } + strcat (p, rid); + strcat (p, "\n"); + *rid_list = p; + } + else /* Out of memory. */ + free (rid); + + rid = NULL; + ++*count; + } + else if (!*readerno + || (*readerno < 0 + && readerid + && !strcmp (readerid, rid))) + { + /* We found the requested reader. */ + if (ifcdesc_extra && ifcdesc_extra_len) + { + *ifcdesc_extra = malloc (ifcdesc + ->extralen); + if (!*ifcdesc_extra) + { + usb_close (idev); + free (rid); + return 1; /* Out of core. */ + } + memcpy (*ifcdesc_extra, ifcdesc->extra, + ifcdesc->extralen); + *ifcdesc_extra_len = ifcdesc->extralen; + } + + if (interface_number) + *interface_number = (ifcdesc->bInterfaceNumber); + + if (ep_bulk_out) + *ep_bulk_out = find_endpoint (ifcdesc, 0); + if (ep_bulk_in) + *ep_bulk_in = find_endpoint (ifcdesc, 1); + if (ep_intr) + *ep_intr = find_endpoint (ifcdesc, 2); + + if (r_dev) + *r_dev = dev; + if (r_rid) + { + *r_rid = rid; + rid = NULL; + } + else + free (rid); + + *r_idev = idev; + return 1; /* Found requested device. */ + } + else + { + /* This is not yet the reader we want. + fixme: We should avoid the extra usb_open + in this case. */ + if (*readerno >= 0) + --*readerno; + } + free (rid); + } + + usb_close (idev); + idev = NULL; + return 0; + } + } + } + } + + return 0; +} + /* Combination function to either scan all CCID devices or to find and open one specific device. + The function returns 0 if a reader has been found or when a scan + returned without error. + + FIXME!! + With READERNO = -1 and READERID is NULL, scan mode is used and R_RID should be the address where to store the list of reader_ids we found. If on return this list is empty, no CCID device has been @@ -671,11 +888,11 @@ With READERNO >= 0 or READERID is not NULL find mode is used. This uses the same algorithm as the scan mode but stops and returns at the entry number READERNO and return the handle for the the opened - USB device. If R_ID is not NULL it will receive the reader ID of + USB device. If R_RID is not NULL it will receive the reader ID of that device. If R_DEV is not NULL it will the device pointer of that device. If IFCDESC_EXTRA is NOT NULL it will receive a malloced copy of the interfaces "extra: data filed; - IFCDESC_EXTRA_LEN receive the lengtyh of this field. If there is + IFCDESC_EXTRA_LEN receive the length of this field. If there is no reader with number READERNO or that reader is not usable by our implementation NULL will be returned. The caller must close a returned USB device handle and free (if not passed as NULL) the @@ -684,17 +901,25 @@ IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if the READERID was found. + If R_FD is not -1 on return the device is not using USB for + transport but the device associated with that file descriptor. In + this case INTERFACE will receive the transport type and the other + USB specific return values are not used; the return value is + (void*)(1). + Note that the first entry of the returned reader ID list in scan mode corresponds with a READERNO of 0 in find mode. */ -static usb_dev_handle * +static int scan_or_find_devices (int readerno, const char *readerid, char **r_rid, struct usb_device **r_dev, unsigned char **ifcdesc_extra, size_t *ifcdesc_extra_len, int *interface_number, - int *ep_bulk_out, int *ep_bulk_in, int *ep_intr) + int *ep_bulk_out, int *ep_bulk_in, int *ep_intr, + usb_dev_handle **r_idev, + int *r_fd) { char *rid_list = NULL; int count = 0; @@ -702,8 +927,9 @@ struct usb_device *dev = NULL; usb_dev_handle *idev = NULL; int scan_mode = (readerno == -1 && !readerid); + int i; - /* Set return values to a default. */ + /* Set return values to a default. */ if (r_rid) *r_rid = NULL; if (r_dev) @@ -714,6 +940,10 @@ *ifcdesc_extra_len = 0; if (interface_number) *interface_number = 0; + if (r_idev) + *r_idev = NULL; + if (r_fd) + *r_fd = -1; /* See whether we want scan or find mode. */ if (scan_mode) @@ -734,161 +964,102 @@ { for (dev = bus->devices; dev; dev = dev->next) { - int cfg_no; - - for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++) + if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list, + readerid, + dev, + r_rid, + r_dev, + &idev, + ifcdesc_extra, + ifcdesc_extra_len, + interface_number, + ep_bulk_out, ep_bulk_in, ep_intr)) { - struct usb_config_descriptor *config = dev->config + cfg_no; - int ifc_no; - - if(!config) - continue; - - for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++) + /* Found requested device or out of core. */ + if (!idev) { - struct usb_interface *interface - = config->interface + ifc_no; - int set_no; - - if (!interface) - continue; - - for (set_no=0; set_no < interface->num_altsetting; set_no++) - { - struct usb_interface_descriptor *ifcdesc - = interface->altsetting + set_no; - char *rid; - - /* The second condition is for some SCM Micro - SPR 532 which does not know about the - assigned CCID class. Instead of trying to - interpret the strings we simply look at the - product ID. */ - if (ifcdesc && ifcdesc->extra - && ( (ifcdesc->bInterfaceClass == 11 - && ifcdesc->bInterfaceSubClass == 0 - && ifcdesc->bInterfaceProtocol == 0) - || (ifcdesc->bInterfaceClass == 255 - && dev->descriptor.idVendor == 0x04e6 - && dev->descriptor.idProduct == 0xe003))) - { - idev = usb_open (dev); - if (!idev) - { - DEBUGOUT_1 ("usb_open failed: %s\n", - strerror (errno)); - continue; - } - - rid = make_reader_id (idev, - dev->descriptor.idVendor, - dev->descriptor.idProduct, - dev->descriptor.iSerialNumber); - if (rid) - { - if (scan_mode) - { - char *p; + free (rid_list); + return -1; /* error */ + } + *r_idev = idev; + return 0; + } + } + } - /* We are collecting infos about all - available CCID readers. Store - them and continue. */ - DEBUGOUT_2 ("found CCID reader %d " - "(ID=%s)\n", - count, rid ); - if ((p = malloc ((rid_list? - strlen (rid_list):0) - + 1 + strlen (rid) - + 1))) - { - *p = 0; - if (rid_list) - { - strcat (p, rid_list); - free (rid_list); - } - strcat (p, rid); - strcat (p, "\n"); - rid_list = p; - } - else /* Out of memory. */ - free (rid); - rid = NULL; - count++; - } - else if (!readerno - || (readerno < 0 - && readerid - && !strcmp (readerid, rid))) - { - /* We found the requested reader. */ - if (ifcdesc_extra && ifcdesc_extra_len) - { - *ifcdesc_extra = malloc (ifcdesc - ->extralen); - if (!*ifcdesc_extra) - { - usb_close (idev); - free (rid); - return NULL; /* Out of core. */ - } - memcpy (*ifcdesc_extra, ifcdesc->extra, - ifcdesc->extralen); - *ifcdesc_extra_len = ifcdesc->extralen; - } - if (interface_number) - *interface_number = (ifcdesc-> - bInterfaceNumber); - if (ep_bulk_out) - *ep_bulk_out = find_endpoint (ifcdesc, 0); - if (ep_bulk_in) - *ep_bulk_in = find_endpoint (ifcdesc, 1); - if (ep_intr) - *ep_intr = find_endpoint (ifcdesc, 2); + /* Now check whether there are any devices with special transport types. */ + for (i=0; transports[i].name; i++) + { + int fd; + char *rid, *p; + fd = open (transports[i].name, O_RDWR); + if (fd == -1) + continue; - if (r_dev) - *r_dev = dev; - if (r_rid) - { - *r_rid = rid; - rid = NULL; - } - else - free (rid); - return idev; /* READY. */ - } - else - { - /* This is not yet the reader we - want. fixme: We could avoid the - extra usb_open in this case. */ - if (readerno >= 0) - readerno--; - } - free (rid); - } - - usb_close (idev); - idev = NULL; - goto next_device; - } - } - } + rid = malloc (strlen (transports[i].name) + 30 + 10); + if (!rid) + { + close (fd); + free (rid_list); + return -1; /* Error. */ + } + sprintf (rid, "0000:%04X:%s:0", transports[i].type, transports[i].name); + if (scan_mode) + { + DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", count, rid); + p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1); + if (!p) + { + close (fd); + free (rid_list); + free (rid); + return -1; /* Error. */ } - next_device: - ; + *p = 0; + if (rid_list) + { + strcat (p, rid_list); + free (rid_list); + } + strcat (p, rid); + strcat (p, "\n"); + rid_list = p; + ++count; } + else if (!readerno || + (readerno < 0 && readerid && !strcmp (readerid, rid))) + { + /* Found requested device. */ + if (interface_number) + *interface_number = transports[i].type; + if (r_rid) + *r_rid = rid; + else + free (rid); + *r_fd = fd; + return 0; /* Okay, found device */ + } + else /* This is not yet the reader we want. */ + { + if (readerno >= 0) + --readerno; + } + free (rid); + close (fd); } if (scan_mode) - *r_rid = rid_list; - - return NULL; + { + *r_rid = rid_list; + return 0; + } + else + return -1; } -/* Set the level of debugging to to usea dn return the old level. -1 +/* Set the level of debugging to LEVEL and return the old level. -1 just returns the old level. A level of 0 disables debugging, 1 enables debugging, 2 enables additional tracing of the T=1 protocol, other values are not yet defined. */ @@ -913,8 +1084,9 @@ initialized_usb = 1; } - scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL, - NULL, NULL, NULL); + if (scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL)) + return NULL; /* Error. */ return reader_list; } @@ -927,6 +1099,7 @@ int rc = 0; struct usb_device *dev = NULL; usb_dev_handle *idev = NULL; + int dev_fd = -1; char *rid = NULL; unsigned char *ifcdesc_extra = NULL; size_t ifcdesc_extra_len; @@ -959,10 +1132,10 @@ else readerno = 0; /* Default. */ - idev = scan_or_find_devices (readerno, readerid, &rid, &dev, - &ifcdesc_extra, &ifcdesc_extra_len, - &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr); - if (!idev) + if (scan_or_find_devices (readerno, readerid, &rid, &dev, + &ifcdesc_extra, &ifcdesc_extra_len, + &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr, + &idev, &dev_fd) ) { if (readerno == -1) DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid ); @@ -980,34 +1153,52 @@ rc = CCID_DRIVER_ERR_OUT_OF_CORE; goto leave; } - (*handle)->idev = idev; (*handle)->rid = rid; - (*handle)->id_vendor = dev->descriptor.idVendor; - (*handle)->id_product = dev->descriptor.idProduct; - (*handle)->bcd_device = dev->descriptor.bcdDevice; - (*handle)->ifc_no = ifc_no; - (*handle)->ep_bulk_out = ep_bulk_out; - (*handle)->ep_bulk_in = ep_bulk_in; - (*handle)->ep_intr = ep_intr; + if (idev) /* Regular USB transport. */ + { + (*handle)->idev = idev; + (*handle)->dev_fd = -1; + (*handle)->id_vendor = dev->descriptor.idVendor; + (*handle)->id_product = dev->descriptor.idProduct; + (*handle)->bcd_device = dev->descriptor.bcdDevice; + (*handle)->ifc_no = ifc_no; + (*handle)->ep_bulk_out = ep_bulk_out; + (*handle)->ep_bulk_in = ep_bulk_in; + (*handle)->ep_intr = ep_intr; + } + else if (dev_fd != -1) /* Device transport. */ + { + (*handle)->idev = NULL; + (*handle)->dev_fd = dev_fd; + (*handle)->id_vendor = 0; /* Magic vendor for special transport. */ + (*handle)->id_product = ifc_no; /* Transport type */ + prepare_special_transport (*handle); + } + else + { + assert (!"no transport"); /* Bug. */ + } DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid ); - - if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len)) + if (idev) { - DEBUGOUT ("device not supported\n"); - rc = CCID_DRIVER_ERR_NO_READER; - goto leave; + if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len)) + { + DEBUGOUT ("device not supported\n"); + rc = CCID_DRIVER_ERR_NO_READER; + goto leave; + } + + rc = usb_claim_interface (idev, ifc_no); + if (rc) + { + DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); + rc = CCID_DRIVER_ERR_CARD_IO_ERROR; + goto leave; + } } - - rc = usb_claim_interface (idev, ifc_no); - if (rc) - { - DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); - rc = CCID_DRIVER_ERR_CARD_IO_ERROR; - goto leave; - } - + leave: free (ifcdesc_extra); if (rc) @@ -1015,6 +1206,8 @@ free (rid); if (idev) usb_close (idev); + if (dev_fd != -1) + close (dev_fd); free (*handle); *handle = NULL; } @@ -1054,6 +1247,11 @@ usb_close (handle->idev); handle->idev = NULL; } + if (handle->dev_fd != -1) + { + close (handle->dev_fd); + handle->dev_fd = -1; + } } @@ -1080,43 +1278,49 @@ do_close_reader (handle); - idev = scan_or_find_devices (-1, handle->rid, NULL, &dev, - &ifcdesc_extra, &ifcdesc_extra_len, - &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr); - if (!idev) + if (scan_or_find_devices (-1, handle->rid, NULL, &dev, + &ifcdesc_extra, &ifcdesc_extra_len, + &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr, + &idev, NULL) || !idev) { DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid); return CCID_DRIVER_ERR_NO_READER; } + if (idev) + { + handle->idev = idev; + handle->ifc_no = ifc_no; + handle->ep_bulk_out = ep_bulk_out; + handle->ep_bulk_in = ep_bulk_in; + handle->ep_intr = ep_intr; - handle->idev = idev; - handle->ifc_no = ifc_no; - handle->ep_bulk_out = ep_bulk_out; - handle->ep_bulk_in = ep_bulk_in; - handle->ep_intr = ep_intr; + if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len)) + { + DEBUGOUT ("device not supported\n"); + rc = CCID_DRIVER_ERR_NO_READER; + goto leave; + } + + rc = usb_claim_interface (idev, ifc_no); + if (rc) + { + DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); + rc = CCID_DRIVER_ERR_CARD_IO_ERROR; + goto leave; + } + } - if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len)) - { - DEBUGOUT ("device not supported\n"); - rc = CCID_DRIVER_ERR_NO_READER; - goto leave; - } - - rc = usb_claim_interface (idev, ifc_no); - if (rc) - { - DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); - rc = CCID_DRIVER_ERR_CARD_IO_ERROR; - goto leave; - } - leave: free (ifcdesc_extra); if (rc) { - usb_close (handle->idev); + if (handle->idev) + usb_close (handle->idev); handle->idev = NULL; + if (handle->dev_fd != -1) + close (handle->dev_fd); + handle->dev_fd = -1; } return rc; @@ -1147,6 +1351,31 @@ } +/* Write NBYTES of BUF to file descriptor FD. */ +static int +writen (int fd, const void *buf, size_t nbytes) +{ + size_t nleft = nbytes; + int nwritten; + + while (nleft > 0) + { + nwritten = write (fd, buf, nleft); + if (nwritten < 0) + { + if (errno == EINTR) + nwritten = 0; + else + return -1; + } + nleft -= nwritten; + buf = (const char*)buf + nwritten; + } + + return 0; +} + + /* Write a MSG of length MSGLEN to the designated bulk out endpoint. Returns 0 on success. */ static int @@ -1154,17 +1383,28 @@ { int rc; - rc = usb_bulk_write (handle->idev, - handle->ep_bulk_out, - (char*)msg, msglen, - 1000 /* ms timeout */); - if (rc == msglen) - return 0; - - if (rc == -1) - DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno)); + if (handle->idev) + { + rc = usb_bulk_write (handle->idev, + handle->ep_bulk_out, + (char*)msg, msglen, + 1000 /* ms timeout */); + if (rc == msglen) + return 0; + if (rc == -1) + DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno)); + else + DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc); + } else - DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc); + { + rc = writen (handle->dev_fd, msg, msglen); + if (!rc) + return 0; + DEBUGOUT_2 ("writen to %d failed: %s\n", + handle->dev_fd, strerror (errno)); + + } return CCID_DRIVER_ERR_CARD_IO_ERROR; } @@ -1187,17 +1427,31 @@ for USB IOCTLs. */ memset (buffer, 0, length); retry: - rc = usb_bulk_read (handle->idev, - handle->ep_bulk_in, - (char*)buffer, length, - timeout); - if (rc < 0) + if (handle->idev) { - DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); - return CCID_DRIVER_ERR_CARD_IO_ERROR; + rc = usb_bulk_read (handle->idev, + handle->ep_bulk_in, + (char*)buffer, length, + timeout); + if (rc < 0) + { + DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + *nread = msglen = rc; } + else + { + rc = read (handle->dev_fd, buffer, length); + if (rc < 0) + { + DEBUGOUT_2 ("read from %d failed: %s\n", + handle->dev_fd, strerror (errno)); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + *nread = msglen = rc; + } - *nread = msglen = rc; if (msglen < 10) { @@ -1339,11 +1593,16 @@ size_t msglen; int i, j; - rc = usb_bulk_read (handle->idev, - handle->ep_intr, - (char*)msg, sizeof msg, - 0 /* ms timeout */ ); - if (rc < 0 && errno == ETIMEDOUT) + if (handle->idev) + { + rc = usb_bulk_read (handle->idev, + handle->ep_intr, + (char*)msg, sizeof msg, + 0 /* ms timeout */ ); + if (rc < 0 && errno == ETIMEDOUT) + return 0; + } + else return 0; if (rc < 0) From cvs at cvs.gnupg.org Mon Feb 6 17:34:21 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon Feb 6 16:53:13 2006 Subject: [svn] GnuPG - r3995 - trunk/g10 Message-ID: Author: wk Date: 2006-02-06 17:34:20 +0100 (Mon, 06 Feb 2006) New Revision: 3995 Modified: trunk/g10/ChangeLog trunk/g10/ccid-driver.c trunk/g10/ccid-driver.h Log: Add support fro CardMan 4040 Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-06 16:13:20 UTC (rev 3994) +++ trunk/g10/ChangeLog 2006-02-06 16:34:20 UTC (rev 3995) @@ -1,3 +1,17 @@ +2006-02-06 Werner Koch + + * ccid-driver.c, ccid-driver.h: Updated from GnuPG 1.9. Changes: + * ccid-driver.h (CCID_DRIVER_ERR_NO_KEYPAD): New. + * ccid-driver.c (send_escape_cmd): New args RESULT, RESULTLEN and + RESULTMAX. Changed all callers. + (ccid_transceive_escape): New. + * ccid-driver.c (special_transport): New + (ccid_open_reader, do_close_reader, ccid_shutdown_reader) + (bulk_out, bulk_in): Add support for CardMan 4040 reader. + * ccid-driver.c (scan_or_find_devices): Factored most code out to + (scan_or_find_usb_device): .. new. + (make_reader_id): Fixed vendor mask. + 2006-01-24 David Shaw * keyserver.c (parse_keyserver_uri): If there is a path present, Modified: trunk/g10/ccid-driver.c =================================================================== --- trunk/g10/ccid-driver.c 2006-02-06 16:13:20 UTC (rev 3994) +++ trunk/g10/ccid-driver.c 2006-02-06 16:34:20 UTC (rev 3995) @@ -1,5 +1,5 @@ /* ccid-driver.c - USB ChipCardInterfaceDevices driver - * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. * Written by Werner Koch. * * This file is part of GnuPG. @@ -67,8 +67,8 @@ portable access to USB. This driver has been tested with the SCM SCR335 and SPR532 - smartcard readers and requires that a reader implements the TPDU - level exchange and does fully automatic initialization. + smartcard readers and requires that a reader implements APDU or + TPDU level exchange and does fully automatic initialization. */ #ifdef HAVE_CONFIG_H @@ -82,6 +82,9 @@ #include #include #include +#include +#include +#include #include @@ -194,18 +197,38 @@ /* We need to know the vendor to do some hacks. */ enum { + VENDOR_CHERRY = 0x046a, VENDOR_SCM = 0x04e6, - VENDOR_CHERRY = 0x046a, + VENDOR_OMNIKEY= 0x076b, VENDOR_GEMPC = 0x08e6 }; +/* A list and a table with special transport descriptions. */ +enum { + TRANSPORT_USB = 0, /* Standard USB transport. */ + TRANSPORT_CM4040 = 1 /* As used by the Cardman 4040. */ +}; +static struct +{ + char *name; /* Device name. */ + int type; + +} transports[] = { + { "/dev/cmx0", TRANSPORT_CM4040 }, + { "/dev/cmx1", TRANSPORT_CM4040 }, + { NULL }, +}; + + /* Store information on the driver's state. A pointer to such a structure is used as handle for most functions. */ struct ccid_driver_s { usb_dev_handle *idev; char *rid; + int dev_fd; /* -1 for USB transport or file descriptor of the + transport device. */ unsigned short id_vendor; unsigned short id_product; unsigned short bcd_device; @@ -306,8 +329,35 @@ } +/* Given a handle used for special transport prepare it for use. In + particular setup all information in way that resembles what + parse_cccid_descriptor does. */ +static void +prepare_special_transport (ccid_driver_t handle) +{ + assert (!handle->id_vendor); + handle->nonnull_nad = 0; + handle->auto_ifsd = 0; + handle->max_ifsd = 32; + handle->ifsd = 0; + handle->has_pinpad = 0; + handle->apdu_level = 0; + switch (handle->id_product) + { + case TRANSPORT_CM4040: + DEBUGOUT ("setting up transport for CardMan 4040\n"); + /* Most values are guessed. */ + handle->nonnull_nad = 1; + handle->auto_ifsd = 1; + handle->max_ifsd = 254; + handle->apdu_level = 1; + break; + default: assert (!"transport not defined"); + } +} + /* Parse a CCID descriptor, optionally print all available features and test whether this reader is usable by this driver. Returns 0 if it is usable. @@ -615,7 +665,7 @@ char *rid; char prefix[20]; - sprintf (prefix, "%04X:%04X:", (vendor & 0xfff), (product & 0xffff)); + sprintf (prefix, "%04X:%04X:", (vendor & 0xffff), (product & 0xffff)); rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0"); if (!rid) { @@ -658,10 +708,177 @@ } +/* Helper for scan_or_find_devices. This function returns true if a + requested device has been found or the caller should stop scanning + for other reasons. */ +static int +scan_or_find_usb_device (int scan_mode, + int *readerno, int *count, char **rid_list, + const char *readerid, + struct usb_device *dev, + char **r_rid, + struct usb_device **r_dev, + usb_dev_handle **r_idev, + unsigned char **ifcdesc_extra, + size_t *ifcdesc_extra_len, + int *interface_number, + int *ep_bulk_out, int *ep_bulk_in, int *ep_intr) +{ + int cfg_no; + int ifc_no; + int set_no; + struct usb_config_descriptor *config; + struct usb_interface *interface; + struct usb_interface_descriptor *ifcdesc; + char *rid; + usb_dev_handle *idev; + *r_idev = NULL; + + for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++) + { + config = dev->config + cfg_no; + if(!config) + continue; + + for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++) + { + interface = config->interface + ifc_no; + if (!interface) + continue; + + for (set_no=0; set_no < interface->num_altsetting; set_no++) + { + ifcdesc = (interface->altsetting + set_no); + /* The second condition is for older SCM SPR 532 who did + not know about the assigned CCID class. Instead of + trying to interpret the strings we simply check the + product ID. */ + if (ifcdesc && ifcdesc->extra + && ((ifcdesc->bInterfaceClass == 11 + && ifcdesc->bInterfaceSubClass == 0 + && ifcdesc->bInterfaceProtocol == 0) + || (ifcdesc->bInterfaceClass == 255 + && dev->descriptor.idVendor == VENDOR_SCM + && dev->descriptor.idProduct == 0xe003))) + { + idev = usb_open (dev); + if (!idev) + { + DEBUGOUT_1 ("usb_open failed: %s\n", + strerror (errno)); + continue; /* with next setting. */ + } + + rid = make_reader_id (idev, + dev->descriptor.idVendor, + dev->descriptor.idProduct, + dev->descriptor.iSerialNumber); + if (rid) + { + if (scan_mode) + { + char *p; + + /* We are collecting infos about all + available CCID readers. Store them and + continue. */ + DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", + *count, rid ); + p = malloc ((*rid_list? strlen (*rid_list):0) + 1 + + strlen (rid) + 1); + if (p) + { + *p = 0; + if (*rid_list) + { + strcat (p, *rid_list); + free (*rid_list); + } + strcat (p, rid); + strcat (p, "\n"); + *rid_list = p; + } + else /* Out of memory. */ + free (rid); + + rid = NULL; + ++*count; + } + else if (!*readerno + || (*readerno < 0 + && readerid + && !strcmp (readerid, rid))) + { + /* We found the requested reader. */ + if (ifcdesc_extra && ifcdesc_extra_len) + { + *ifcdesc_extra = malloc (ifcdesc + ->extralen); + if (!*ifcdesc_extra) + { + usb_close (idev); + free (rid); + return 1; /* Out of core. */ + } + memcpy (*ifcdesc_extra, ifcdesc->extra, + ifcdesc->extralen); + *ifcdesc_extra_len = ifcdesc->extralen; + } + + if (interface_number) + *interface_number = (ifcdesc->bInterfaceNumber); + + if (ep_bulk_out) + *ep_bulk_out = find_endpoint (ifcdesc, 0); + if (ep_bulk_in) + *ep_bulk_in = find_endpoint (ifcdesc, 1); + if (ep_intr) + *ep_intr = find_endpoint (ifcdesc, 2); + + if (r_dev) + *r_dev = dev; + if (r_rid) + { + *r_rid = rid; + rid = NULL; + } + else + free (rid); + + *r_idev = idev; + return 1; /* Found requested device. */ + } + else + { + /* This is not yet the reader we want. + fixme: We should avoid the extra usb_open + in this case. */ + if (*readerno >= 0) + --*readerno; + } + free (rid); + } + + usb_close (idev); + idev = NULL; + return 0; + } + } + } + } + + return 0; +} + /* Combination function to either scan all CCID devices or to find and open one specific device. + The function returns 0 if a reader has been found or when a scan + returned without error. + + FIXME!! + With READERNO = -1 and READERID is NULL, scan mode is used and R_RID should be the address where to store the list of reader_ids we found. If on return this list is empty, no CCID device has been @@ -671,11 +888,11 @@ With READERNO >= 0 or READERID is not NULL find mode is used. This uses the same algorithm as the scan mode but stops and returns at the entry number READERNO and return the handle for the the opened - USB device. If R_ID is not NULL it will receive the reader ID of + USB device. If R_RID is not NULL it will receive the reader ID of that device. If R_DEV is not NULL it will the device pointer of that device. If IFCDESC_EXTRA is NOT NULL it will receive a malloced copy of the interfaces "extra: data filed; - IFCDESC_EXTRA_LEN receive the lengtyh of this field. If there is + IFCDESC_EXTRA_LEN receive the length of this field. If there is no reader with number READERNO or that reader is not usable by our implementation NULL will be returned. The caller must close a returned USB device handle and free (if not passed as NULL) the @@ -684,17 +901,25 @@ IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if the READERID was found. + If R_FD is not -1 on return the device is not using USB for + transport but the device associated with that file descriptor. In + this case INTERFACE will receive the transport type and the other + USB specific return values are not used; the return value is + (void*)(1). + Note that the first entry of the returned reader ID list in scan mode corresponds with a READERNO of 0 in find mode. */ -static usb_dev_handle * +static int scan_or_find_devices (int readerno, const char *readerid, char **r_rid, struct usb_device **r_dev, unsigned char **ifcdesc_extra, size_t *ifcdesc_extra_len, int *interface_number, - int *ep_bulk_out, int *ep_bulk_in, int *ep_intr) + int *ep_bulk_out, int *ep_bulk_in, int *ep_intr, + usb_dev_handle **r_idev, + int *r_fd) { char *rid_list = NULL; int count = 0; @@ -702,8 +927,9 @@ struct usb_device *dev = NULL; usb_dev_handle *idev = NULL; int scan_mode = (readerno == -1 && !readerid); + int i; - /* Set return values to a default. */ + /* Set return values to a default. */ if (r_rid) *r_rid = NULL; if (r_dev) @@ -714,6 +940,10 @@ *ifcdesc_extra_len = 0; if (interface_number) *interface_number = 0; + if (r_idev) + *r_idev = NULL; + if (r_fd) + *r_fd = -1; /* See whether we want scan or find mode. */ if (scan_mode) @@ -734,161 +964,102 @@ { for (dev = bus->devices; dev; dev = dev->next) { - int cfg_no; - - for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++) + if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list, + readerid, + dev, + r_rid, + r_dev, + &idev, + ifcdesc_extra, + ifcdesc_extra_len, + interface_number, + ep_bulk_out, ep_bulk_in, ep_intr)) { - struct usb_config_descriptor *config = dev->config + cfg_no; - int ifc_no; - - if(!config) - continue; - - for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++) + /* Found requested device or out of core. */ + if (!idev) { - struct usb_interface *interface - = config->interface + ifc_no; - int set_no; - - if (!interface) - continue; - - for (set_no=0; set_no < interface->num_altsetting; set_no++) - { - struct usb_interface_descriptor *ifcdesc - = interface->altsetting + set_no; - char *rid; - - /* The second condition is for some SCM Micro - SPR 532 which does not know about the - assigned CCID class. Instead of trying to - interpret the strings we simply look at the - product ID. */ - if (ifcdesc && ifcdesc->extra - && ( (ifcdesc->bInterfaceClass == 11 - && ifcdesc->bInterfaceSubClass == 0 - && ifcdesc->bInterfaceProtocol == 0) - || (ifcdesc->bInterfaceClass == 255 - && dev->descriptor.idVendor == 0x04e6 - && dev->descriptor.idProduct == 0xe003))) - { - idev = usb_open (dev); - if (!idev) - { - DEBUGOUT_1 ("usb_open failed: %s\n", - strerror (errno)); - continue; - } - - rid = make_reader_id (idev, - dev->descriptor.idVendor, - dev->descriptor.idProduct, - dev->descriptor.iSerialNumber); - if (rid) - { - if (scan_mode) - { - char *p; + free (rid_list); + return -1; /* error */ + } + *r_idev = idev; + return 0; + } + } + } - /* We are collecting infos about all - available CCID readers. Store - them and continue. */ - DEBUGOUT_2 ("found CCID reader %d " - "(ID=%s)\n", - count, rid ); - if ((p = malloc ((rid_list? - strlen (rid_list):0) - + 1 + strlen (rid) - + 1))) - { - *p = 0; - if (rid_list) - { - strcat (p, rid_list); - free (rid_list); - } - strcat (p, rid); - strcat (p, "\n"); - rid_list = p; - } - else /* Out of memory. */ - free (rid); - rid = NULL; - count++; - } - else if (!readerno - || (readerno < 0 - && readerid - && !strcmp (readerid, rid))) - { - /* We found the requested reader. */ - if (ifcdesc_extra && ifcdesc_extra_len) - { - *ifcdesc_extra = malloc (ifcdesc - ->extralen); - if (!*ifcdesc_extra) - { - usb_close (idev); - free (rid); - return NULL; /* Out of core. */ - } - memcpy (*ifcdesc_extra, ifcdesc->extra, - ifcdesc->extralen); - *ifcdesc_extra_len = ifcdesc->extralen; - } - if (interface_number) - *interface_number = (ifcdesc-> - bInterfaceNumber); - if (ep_bulk_out) - *ep_bulk_out = find_endpoint (ifcdesc, 0); - if (ep_bulk_in) - *ep_bulk_in = find_endpoint (ifcdesc, 1); - if (ep_intr) - *ep_intr = find_endpoint (ifcdesc, 2); + /* Now check whether there are any devices with special transport types. */ + for (i=0; transports[i].name; i++) + { + int fd; + char *rid, *p; + fd = open (transports[i].name, O_RDWR); + if (fd == -1) + continue; - if (r_dev) - *r_dev = dev; - if (r_rid) - { - *r_rid = rid; - rid = NULL; - } - else - free (rid); - return idev; /* READY. */ - } - else - { - /* This is not yet the reader we - want. fixme: We could avoid the - extra usb_open in this case. */ - if (readerno >= 0) - readerno--; - } - free (rid); - } - - usb_close (idev); - idev = NULL; - goto next_device; - } - } - } + rid = malloc (strlen (transports[i].name) + 30 + 10); + if (!rid) + { + close (fd); + free (rid_list); + return -1; /* Error. */ + } + sprintf (rid, "0000:%04X:%s:0", transports[i].type, transports[i].name); + if (scan_mode) + { + DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", count, rid); + p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1); + if (!p) + { + close (fd); + free (rid_list); + free (rid); + return -1; /* Error. */ } - next_device: - ; + *p = 0; + if (rid_list) + { + strcat (p, rid_list); + free (rid_list); + } + strcat (p, rid); + strcat (p, "\n"); + rid_list = p; + ++count; } + else if (!readerno || + (readerno < 0 && readerid && !strcmp (readerid, rid))) + { + /* Found requested device. */ + if (interface_number) + *interface_number = transports[i].type; + if (r_rid) + *r_rid = rid; + else + free (rid); + *r_fd = fd; + return 0; /* Okay, found device */ + } + else /* This is not yet the reader we want. */ + { + if (readerno >= 0) + --readerno; + } + free (rid); + close (fd); } if (scan_mode) - *r_rid = rid_list; - - return NULL; + { + *r_rid = rid_list; + return 0; + } + else + return -1; } -/* Set the level of debugging to to usea dn return the old level. -1 +/* Set the level of debugging to LEVEL and return the old level. -1 just returns the old level. A level of 0 disables debugging, 1 enables debugging, 2 enables additional tracing of the T=1 protocol, other values are not yet defined. */ @@ -913,8 +1084,9 @@ initialized_usb = 1; } - scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL, - NULL, NULL, NULL); + if (scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL)) + return NULL; /* Error. */ return reader_list; } @@ -927,6 +1099,7 @@ int rc = 0; struct usb_device *dev = NULL; usb_dev_handle *idev = NULL; + int dev_fd = -1; char *rid = NULL; unsigned char *ifcdesc_extra = NULL; size_t ifcdesc_extra_len; @@ -959,10 +1132,10 @@ else readerno = 0; /* Default. */ - idev = scan_or_find_devices (readerno, readerid, &rid, &dev, - &ifcdesc_extra, &ifcdesc_extra_len, - &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr); - if (!idev) + if (scan_or_find_devices (readerno, readerid, &rid, &dev, + &ifcdesc_extra, &ifcdesc_extra_len, + &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr, + &idev, &dev_fd) ) { if (readerno == -1) DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid ); @@ -980,34 +1153,52 @@ rc = CCID_DRIVER_ERR_OUT_OF_CORE; goto leave; } - (*handle)->idev = idev; (*handle)->rid = rid; - (*handle)->id_vendor = dev->descriptor.idVendor; - (*handle)->id_product = dev->descriptor.idProduct; - (*handle)->bcd_device = dev->descriptor.bcdDevice; - (*handle)->ifc_no = ifc_no; - (*handle)->ep_bulk_out = ep_bulk_out; - (*handle)->ep_bulk_in = ep_bulk_in; - (*handle)->ep_intr = ep_intr; + if (idev) /* Regular USB transport. */ + { + (*handle)->idev = idev; + (*handle)->dev_fd = -1; + (*handle)->id_vendor = dev->descriptor.idVendor; + (*handle)->id_product = dev->descriptor.idProduct; + (*handle)->bcd_device = dev->descriptor.bcdDevice; + (*handle)->ifc_no = ifc_no; + (*handle)->ep_bulk_out = ep_bulk_out; + (*handle)->ep_bulk_in = ep_bulk_in; + (*handle)->ep_intr = ep_intr; + } + else if (dev_fd != -1) /* Device transport. */ + { + (*handle)->idev = NULL; + (*handle)->dev_fd = dev_fd; + (*handle)->id_vendor = 0; /* Magic vendor for special transport. */ + (*handle)->id_product = ifc_no; /* Transport type */ + prepare_special_transport (*handle); + } + else + { + assert (!"no transport"); /* Bug. */ + } DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid ); - - if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len)) + if (idev) { - DEBUGOUT ("device not supported\n"); - rc = CCID_DRIVER_ERR_NO_READER; - goto leave; + if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len)) + { + DEBUGOUT ("device not supported\n"); + rc = CCID_DRIVER_ERR_NO_READER; + goto leave; + } + + rc = usb_claim_interface (idev, ifc_no); + if (rc) + { + DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); + rc = CCID_DRIVER_ERR_CARD_IO_ERROR; + goto leave; + } } - - rc = usb_claim_interface (idev, ifc_no); - if (rc) - { - DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); - rc = CCID_DRIVER_ERR_CARD_IO_ERROR; - goto leave; - } - + leave: free (ifcdesc_extra); if (rc) @@ -1015,6 +1206,8 @@ free (rid); if (idev) usb_close (idev); + if (dev_fd != -1) + close (dev_fd); free (*handle); *handle = NULL; } @@ -1054,6 +1247,11 @@ usb_close (handle->idev); handle->idev = NULL; } + if (handle->dev_fd != -1) + { + close (handle->dev_fd); + handle->dev_fd = -1; + } } @@ -1080,43 +1278,49 @@ do_close_reader (handle); - idev = scan_or_find_devices (-1, handle->rid, NULL, &dev, - &ifcdesc_extra, &ifcdesc_extra_len, - &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr); - if (!idev) + if (scan_or_find_devices (-1, handle->rid, NULL, &dev, + &ifcdesc_extra, &ifcdesc_extra_len, + &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr, + &idev, NULL) || !idev) { DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid); return CCID_DRIVER_ERR_NO_READER; } + if (idev) + { + handle->idev = idev; + handle->ifc_no = ifc_no; + handle->ep_bulk_out = ep_bulk_out; + handle->ep_bulk_in = ep_bulk_in; + handle->ep_intr = ep_intr; - handle->idev = idev; - handle->ifc_no = ifc_no; - handle->ep_bulk_out = ep_bulk_out; - handle->ep_bulk_in = ep_bulk_in; - handle->ep_intr = ep_intr; + if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len)) + { + DEBUGOUT ("device not supported\n"); + rc = CCID_DRIVER_ERR_NO_READER; + goto leave; + } + + rc = usb_claim_interface (idev, ifc_no); + if (rc) + { + DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); + rc = CCID_DRIVER_ERR_CARD_IO_ERROR; + goto leave; + } + } - if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len)) - { - DEBUGOUT ("device not supported\n"); - rc = CCID_DRIVER_ERR_NO_READER; - goto leave; - } - - rc = usb_claim_interface (idev, ifc_no); - if (rc) - { - DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); - rc = CCID_DRIVER_ERR_CARD_IO_ERROR; - goto leave; - } - leave: free (ifcdesc_extra); if (rc) { - usb_close (handle->idev); + if (handle->idev) + usb_close (handle->idev); handle->idev = NULL; + if (handle->dev_fd != -1) + close (handle->dev_fd); + handle->dev_fd = -1; } return rc; @@ -1147,6 +1351,31 @@ } +/* Write NBYTES of BUF to file descriptor FD. */ +static int +writen (int fd, const void *buf, size_t nbytes) +{ + size_t nleft = nbytes; + int nwritten; + + while (nleft > 0) + { + nwritten = write (fd, buf, nleft); + if (nwritten < 0) + { + if (errno == EINTR) + nwritten = 0; + else + return -1; + } + nleft -= nwritten; + buf = (const char*)buf + nwritten; + } + + return 0; +} + + /* Write a MSG of length MSGLEN to the designated bulk out endpoint. Returns 0 on success. */ static int @@ -1154,17 +1383,28 @@ { int rc; - rc = usb_bulk_write (handle->idev, - handle->ep_bulk_out, - (char*)msg, msglen, - 1000 /* ms timeout */); - if (rc == msglen) - return 0; - - if (rc == -1) - DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno)); + if (handle->idev) + { + rc = usb_bulk_write (handle->idev, + handle->ep_bulk_out, + (char*)msg, msglen, + 1000 /* ms timeout */); + if (rc == msglen) + return 0; + if (rc == -1) + DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno)); + else + DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc); + } else - DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc); + { + rc = writen (handle->dev_fd, msg, msglen); + if (!rc) + return 0; + DEBUGOUT_2 ("writen to %d failed: %s\n", + handle->dev_fd, strerror (errno)); + + } return CCID_DRIVER_ERR_CARD_IO_ERROR; } @@ -1187,17 +1427,31 @@ for USB IOCTLs. */ memset (buffer, 0, length); retry: - rc = usb_bulk_read (handle->idev, - handle->ep_bulk_in, - (char*)buffer, length, - timeout); - if (rc < 0) + if (handle->idev) { - DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); - return CCID_DRIVER_ERR_CARD_IO_ERROR; + rc = usb_bulk_read (handle->idev, + handle->ep_bulk_in, + (char*)buffer, length, + timeout); + if (rc < 0) + { + DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + *nread = msglen = rc; } + else + { + rc = read (handle->dev_fd, buffer, length); + if (rc < 0) + { + DEBUGOUT_2 ("read from %d failed: %s\n", + handle->dev_fd, strerror (errno)); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + *nread = msglen = rc; + } - *nread = msglen = rc; if (msglen < 10) { @@ -1240,7 +1494,9 @@ if (CCID_COMMAND_FAILED (buffer)) print_command_failed (buffer); - /* Check whether a card is at all available. */ + /* Check whether a card is at all available. Note: If you add new + error codes here, check whether they need to be ignored in + send_escape_cmd. */ switch ((buffer[7] & 0x03)) { case 0: /* no error */ break; @@ -1253,16 +1509,23 @@ /* Note that this function won't return the error codes NO_CARD or - CARD_INACTIVE */ + CARD_INACTIVE. IF RESULT is not NULL, the result from the + operation will get returned in RESULT and its length in RESULTLEN. + If the response is larger than RESULTMAX, an error is returned and + the required buffer length returned in RESULTLEN. */ static int send_escape_cmd (ccid_driver_t handle, - const unsigned char *data, size_t datalen) + const unsigned char *data, size_t datalen, + unsigned char *result, size_t resultmax, size_t *resultlen) { int i, rc; unsigned char msg[100]; size_t msglen; unsigned char seqno; + if (resultlen) + *resultlen = 0; + if (datalen > sizeof msg - 10) return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large. */ @@ -1285,11 +1548,42 @@ return rc; rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno, 5000, 0); - + if (result) + switch (rc) + { + /* We need to ignore certain errorcode here. */ + case 0: + case CCID_DRIVER_ERR_CARD_INACTIVE: + case CCID_DRIVER_ERR_NO_CARD: + { + if (msglen > resultmax) + rc = CCID_DRIVER_ERR_INV_VALUE; /* Response too large. */ + else + { + memcpy (result, msg, msglen); + *resultlen = msglen; + } + rc = 0; + } + break; + default: + break; + } + return rc; } +int +ccid_transceive_escape (ccid_driver_t handle, + const unsigned char *data, size_t datalen, + unsigned char *resp, size_t maxresplen, size_t *nresp) +{ + return send_escape_cmd (handle, data, datalen, resp, maxresplen, nresp); +} + + + /* experimental */ int ccid_poll (ccid_driver_t handle) @@ -1299,11 +1593,16 @@ size_t msglen; int i, j; - rc = usb_bulk_read (handle->idev, - handle->ep_intr, - (char*)msg, sizeof msg, - 0 /* ms timeout */ ); - if (rc < 0 && errno == ETIMEDOUT) + if (handle->idev) + { + rc = usb_bulk_read (handle->idev, + handle->ep_intr, + (char*)msg, sizeof msg, + 0 /* ms timeout */ ); + if (rc < 0 && errno == ETIMEDOUT) + return 0; + } + else return 0; if (rc < 0) @@ -1445,7 +1744,8 @@ { tried_iso = 1; /* Try switching to ISO mode. */ - if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2)) + if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2, + NULL, 0, NULL)) goto again; } else if (CCID_COMMAND_FAILED (msg)) @@ -1957,14 +2257,16 @@ } -/* Send the CCID Secure command to the reader. APDU_BUF should contain the APDU template. PIN_MODE defines now the pin gets formatted: +/* Send the CCID Secure command to the reader. APDU_BUF should + contain the APDU template. PIN_MODE defines how the pin gets + formatted: 1 := The PIN is ASCII encoded and of variable length. The length of the PIN entered will be put into Lc by the reader. The APDU should me made up of 4 bytes without Lc. PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0 - may be used t enable usbale defaults. PIN_PADLEN should be 0 + may be used t enable reasonable defaults. PIN_PADLEN should be 0. When called with RESP and NRESP set to NULL, the function will merely check whether the reader supports the secure command for the @@ -1996,7 +2298,7 @@ else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2)) return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */ else - return CCID_DRIVER_ERR_NOT_SUPPORTED; + return CCID_DRIVER_ERR_NO_KEYPAD; if (pin_mode != 1) return CCID_DRIVER_ERR_NOT_SUPPORTED; @@ -2027,7 +2329,8 @@ if (handle->id_vendor == VENDOR_SCM) { DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n"); - rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3); + rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3, + NULL, 0, NULL); if (rc) return rc; } @@ -2044,7 +2347,7 @@ if (handle->id_vendor == VENDOR_SCM) { /* For the SPR532 the next 2 bytes need to be zero. We do this - for all SCM product. Kudos to to Martin Paljak for this + for all SCM product. Kudos to Martin Paljak for this hint. */ msg[13] = msg[14] = 0; } Modified: trunk/g10/ccid-driver.h =================================================================== --- trunk/g10/ccid-driver.h 2006-02-06 16:13:20 UTC (rev 3994) +++ trunk/g10/ccid-driver.h 2006-02-06 16:34:20 UTC (rev 3995) @@ -58,7 +58,7 @@ #ifndef CCID_DRIVER_H #define CCID_DRIVER_H -/* The CID driver returns the same error codes as the statsu words +/* The CID driver returns the same error codes as the status words used by GnuPG's apdu.h. For ease of maintenance they should always match. */ #define CCID_DRIVER_ERR_OUT_OF_CORE 0x10001 @@ -74,6 +74,7 @@ #define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b #define CCID_DRIVER_ERR_NO_READER 0x1000c #define CCID_DRIVER_ERR_ABORTED 0x1000d +#define CCID_DRIVER_ERR_NO_KEYPAD 0x1000e struct ccid_driver_s; typedef struct ccid_driver_s *ccid_driver_t; @@ -94,6 +95,10 @@ int pin_mode, int pinlen_min, int pinlen_max, int pin_padlen, unsigned char *resp, size_t maxresplen, size_t *nresp); +int ccid_transceive_escape (ccid_driver_t handle, + const unsigned char *data, size_t datalen, + unsigned char *resp, size_t maxresplen, + size_t *nresp); From cvs at cvs.gnupg.org Mon Feb 6 19:31:28 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Mon Feb 6 18:50:21 2006 Subject: [svn] GnuPG - r3996 - in branches/GNUPG-1-9-BRANCH: . scd tools Message-ID: Author: wk Date: 2006-02-06 19:31:27 +0100 (Mon, 06 Feb 2006) New Revision: 3996 Modified: branches/GNUPG-1-9-BRANCH/NEWS branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c branches/GNUPG-1-9-BRANCH/tools/ChangeLog branches/GNUPG-1-9-BRANCH/tools/gpgconf-comp.c Log: From cvs at cvs.gnupg.org Wed Feb 8 18:55:21 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Wed Feb 8 18:14:03 2006 Subject: [svn] GnuPG - r3997 - trunk/g10 Message-ID: Author: wk Date: 2006-02-08 18:55:20 +0100 (Wed, 08 Feb 2006) New Revision: 3997 Modified: trunk/g10/ccid-driver.c Log: Fixed a couple of problems Modified: trunk/g10/ccid-driver.c =================================================================== --- trunk/g10/ccid-driver.c 2006-02-06 18:31:27 UTC (rev 3996) +++ trunk/g10/ccid-driver.c 2006-02-08 17:55:20 UTC (rev 3997) @@ -347,10 +347,6 @@ { case TRANSPORT_CM4040: DEBUGOUT ("setting up transport for CardMan 4040\n"); - /* Most values are guessed. */ - handle->nonnull_nad = 1; - handle->auto_ifsd = 1; - handle->max_ifsd = 254; handle->apdu_level = 1; break; @@ -877,8 +873,6 @@ The function returns 0 if a reader has been found or when a scan returned without error. - FIXME!! - With READERNO = -1 and READERID is NULL, scan mode is used and R_RID should be the address where to store the list of reader_ids we found. If on return this list is empty, no CCID device has been @@ -1037,7 +1031,8 @@ *r_rid = rid; else free (rid); - *r_fd = fd; + if (r_fd) + *r_fd = fd; return 0; /* Okay, found device */ } else /* This is not yet the reader we want. */ @@ -1708,6 +1703,7 @@ unsigned int edc; int i; int tried_iso = 0; + int got_param; /* First check whether a card is available. */ rc = ccid_slot_status (handle, &statusbits); @@ -1716,6 +1712,7 @@ if (statusbits == 2) return CCID_DRIVER_ERR_NO_CARD; + /* For an inactive and also for an active card, issue the PowerOn command to get the ATR. */ again: @@ -1764,6 +1761,44 @@ *atrlen = n; } + got_param = 0; + msg[0] = PC_to_RDR_GetParameters; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; /* RFU */ + msg[8] = 0; /* RFU */ + msg[9] = 0; /* RFU */ + set_msg_len (msg, 0); + msglen = 10; + rc = bulk_out (handle, msg, msglen); + if (!rc) + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 2000, 0); + if (rc) + DEBUGOUT ("GetParameters failed\n"); + else + { + DEBUGOUT ("GetParametes returned"); + for (i=0; i < msglen; i++) + DEBUGOUT_CONT_1 (" %02X", msg[i]); + DEBUGOUT_LF (); + if (msglen >= 10) + { + DEBUGOUT_1 (" protocol ..........: T=%d\n", msg[9]); + if (msglen == 17 && msg[9] == 1) + { + DEBUGOUT_1 (" bmFindexDindex ....: %02X\n", msg[10]); + DEBUGOUT_1 (" bmTCCKST1 .........: %02X\n", msg[11]); + DEBUGOUT_1 (" bGuardTimeT1 ......: %02X\n", msg[12]); + DEBUGOUT_1 (" bmWaitingIntegersT1: %02X\n", msg[13]); + DEBUGOUT_1 (" bClockStop ........: %02X\n", msg[14]); + DEBUGOUT_1 (" bIFSC .............: %d\n", msg[15]); + DEBUGOUT_1 (" bNadValue .........: %d\n", msg[16]); + got_param = 1; + } + } + } + /* Setup parameters to select T=1. */ msg[0] = PC_to_RDR_SetParameters; msg[5] = 0; /* slot */ @@ -1772,14 +1807,17 @@ msg[8] = 0; /* RFU */ msg[9] = 0; /* RFU */ - /* FIXME: Get those values from the ATR. */ - msg[10]= 0x01; /* Fi/Di */ - msg[11]= 0x10; /* LRC, direct convention. */ - msg[12]= 0; /* Extra guardtime. */ - msg[13]= 0x41; /* BWI/CWI */ - msg[14]= 0; /* No clock stoppping. */ - msg[15]= 254; /* IFSC */ - msg[16]= 0; /* Does not support non default NAD values. */ + if (!got_param) + { + /* FIXME: Get those values from the ATR. */ + msg[10]= 0x01; /* Fi/Di */ + msg[11]= 0x10; /* LRC, direct convention. */ + msg[12]= 0; /* Extra guardtime. */ + msg[13]= 0x41; /* BWI/CWI */ + msg[14]= 0; /* No clock stoppping. */ + msg[15]= 254; /* IFSC */ + msg[16]= 0; /* Does not support non default NAD values. */ + } set_msg_len (msg, 7); msglen = 10 + 7; @@ -1791,15 +1829,16 @@ rc = bulk_out (handle, msg, msglen); if (rc) return rc; - /* Note that we ignore the error code on purpose. */ - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, - seqno, 5000, 0); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 5000, 0); + if (rc) + DEBUGOUT ("SetParameters failed (ignored)\n"); handle->t1_ns = 0; handle->t1_nr = 0; - /* Send an S-Block with our maximun IFSD to the CCID. */ - if (!handle->auto_ifsd) + /* Send an S-Block with our maximum IFSD to the CCID. */ + if (!handle->apdu_level && !handle->auto_ifsd) { tpdu = msg+10; /* NAD: DAD=1, SAD=0 */ From cvs at cvs.gnupg.org Wed Feb 8 18:56:01 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Wed Feb 8 18:14:42 2006 Subject: [svn] GnuPG - r3998 - branches/GNUPG-1-9-BRANCH/scd Message-ID: Author: wk Date: 2006-02-08 18:56:01 +0100 (Wed, 08 Feb 2006) New Revision: 3998 Modified: branches/GNUPG-1-9-BRANCH/scd/ChangeLog branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c Log: Fixed a couple of problems with omnikey based readers Modified: branches/GNUPG-1-9-BRANCH/scd/ChangeLog =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/ChangeLog 2006-02-08 17:55:20 UTC (rev 3997) +++ branches/GNUPG-1-9-BRANCH/scd/ChangeLog 2006-02-08 17:56:01 UTC (rev 3998) @@ -1,3 +1,9 @@ +2006-02-08 Werner Koch + + * ccid-driver.c (ccid_get_atr): Read Parameter and select T=1 + using these parameters. + (scan_or_find_devices): Check for NULL r_fd. + 2006-02-02 Werner Koch * ccid-driver.c (special_transport): New Modified: branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c 2006-02-08 17:55:20 UTC (rev 3997) +++ branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c 2006-02-08 17:56:01 UTC (rev 3998) @@ -347,10 +347,6 @@ { case TRANSPORT_CM4040: DEBUGOUT ("setting up transport for CardMan 4040\n"); - /* Most values are guessed. */ - handle->nonnull_nad = 1; - handle->auto_ifsd = 1; - handle->max_ifsd = 254; handle->apdu_level = 1; break; @@ -877,8 +873,6 @@ The function returns 0 if a reader has been found or when a scan returned without error. - FIXME!! - With READERNO = -1 and READERID is NULL, scan mode is used and R_RID should be the address where to store the list of reader_ids we found. If on return this list is empty, no CCID device has been @@ -1037,7 +1031,8 @@ *r_rid = rid; else free (rid); - *r_fd = fd; + if (r_fd) + *r_fd = fd; return 0; /* Okay, found device */ } else /* This is not yet the reader we want. */ @@ -1708,6 +1703,7 @@ unsigned int edc; int i; int tried_iso = 0; + int got_param; /* First check whether a card is available. */ rc = ccid_slot_status (handle, &statusbits); @@ -1716,6 +1712,7 @@ if (statusbits == 2) return CCID_DRIVER_ERR_NO_CARD; + /* For an inactive and also for an active card, issue the PowerOn command to get the ATR. */ again: @@ -1764,6 +1761,44 @@ *atrlen = n; } + got_param = 0; + msg[0] = PC_to_RDR_GetParameters; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; /* RFU */ + msg[8] = 0; /* RFU */ + msg[9] = 0; /* RFU */ + set_msg_len (msg, 0); + msglen = 10; + rc = bulk_out (handle, msg, msglen); + if (!rc) + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 2000, 0); + if (rc) + DEBUGOUT ("GetParameters failed\n"); + else + { + DEBUGOUT ("GetParametes returned"); + for (i=0; i < msglen; i++) + DEBUGOUT_CONT_1 (" %02X", msg[i]); + DEBUGOUT_LF (); + if (msglen >= 10) + { + DEBUGOUT_1 (" protocol ..........: T=%d\n", msg[9]); + if (msglen == 17 && msg[9] == 1) + { + DEBUGOUT_1 (" bmFindexDindex ....: %02X\n", msg[10]); + DEBUGOUT_1 (" bmTCCKST1 .........: %02X\n", msg[11]); + DEBUGOUT_1 (" bGuardTimeT1 ......: %02X\n", msg[12]); + DEBUGOUT_1 (" bmWaitingIntegersT1: %02X\n", msg[13]); + DEBUGOUT_1 (" bClockStop ........: %02X\n", msg[14]); + DEBUGOUT_1 (" bIFSC .............: %d\n", msg[15]); + DEBUGOUT_1 (" bNadValue .........: %d\n", msg[16]); + got_param = 1; + } + } + } + /* Setup parameters to select T=1. */ msg[0] = PC_to_RDR_SetParameters; msg[5] = 0; /* slot */ @@ -1772,14 +1807,17 @@ msg[8] = 0; /* RFU */ msg[9] = 0; /* RFU */ - /* FIXME: Get those values from the ATR. */ - msg[10]= 0x01; /* Fi/Di */ - msg[11]= 0x10; /* LRC, direct convention. */ - msg[12]= 0; /* Extra guardtime. */ - msg[13]= 0x41; /* BWI/CWI */ - msg[14]= 0; /* No clock stoppping. */ - msg[15]= 254; /* IFSC */ - msg[16]= 0; /* Does not support non default NAD values. */ + if (!got_param) + { + /* FIXME: Get those values from the ATR. */ + msg[10]= 0x01; /* Fi/Di */ + msg[11]= 0x10; /* LRC, direct convention. */ + msg[12]= 0; /* Extra guardtime. */ + msg[13]= 0x41; /* BWI/CWI */ + msg[14]= 0; /* No clock stoppping. */ + msg[15]= 254; /* IFSC */ + msg[16]= 0; /* Does not support non default NAD values. */ + } set_msg_len (msg, 7); msglen = 10 + 7; @@ -1791,15 +1829,16 @@ rc = bulk_out (handle, msg, msglen); if (rc) return rc; - /* Note that we ignore the error code on purpose. */ - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, - seqno, 5000, 0); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 5000, 0); + if (rc) + DEBUGOUT ("SetParameters failed (ignored)\n"); handle->t1_ns = 0; handle->t1_nr = 0; - /* Send an S-Block with our maximun IFSD to the CCID. */ - if (!handle->auto_ifsd) + /* Send an S-Block with our maximum IFSD to the CCID. */ + if (!handle->apdu_level && !handle->auto_ifsd) { tpdu = msg+10; /* NAD: DAD=1, SAD=0 */ From cvs at cvs.gnupg.org Thu Feb 9 13:54:43 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Thu Feb 9 13:13:22 2006 Subject: [svn] GnuPG - r3999 - in trunk: . cipher g10 Message-ID: Author: wk Date: 2006-02-09 13:54:41 +0100 (Thu, 09 Feb 2006) New Revision: 3999 Modified: trunk/ChangeLog trunk/cipher/ChangeLog trunk/cipher/random.c trunk/cipher/random.h trunk/configure.ac trunk/g10/ChangeLog trunk/g10/gpg.c Log: Lock random seed file Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2006-02-08 17:56:01 UTC (rev 3998) +++ trunk/ChangeLog 2006-02-09 12:54:41 UTC (rev 3999) @@ -1,3 +1,7 @@ +2006-02-09 Werner Koch + + * configure.ac: Check for fcntl and ftruncate. + 2006-01-22 David Shaw * configure.ac: Add define for EXEEXT so we can find keyserver Modified: trunk/cipher/ChangeLog =================================================================== --- trunk/cipher/ChangeLog 2006-02-08 17:56:01 UTC (rev 3998) +++ trunk/cipher/ChangeLog 2006-02-09 12:54:41 UTC (rev 3999) @@ -1,3 +1,9 @@ +2006-02-09 Werner Koch + + * random.c (lock_seed_file): New. + (read_seed_file, update_random_seed_file): Use it. + (random_disable_locking): New. + 2005-12-06 David Shaw * idea-stub.c (load_module): Not legal to return a void * as a Modified: trunk/cipher/random.c =================================================================== --- trunk/cipher/random.c 2006-02-08 17:56:01 UTC (rev 3998) +++ trunk/cipher/random.c 2006-02-09 12:54:41 UTC (rev 3999) @@ -1,6 +1,6 @@ /* random.c - random number generator * Copyright (C) 1998, 1999, 2000, 2001, 2002, - * 2003 Free Software Foundation, Inc. + * 2003, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -70,6 +70,14 @@ #endif +/* Check whether we can lock the seed file read write. */ +#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM) +#define LOCK_SEED_FILE 1 +#else +#define LOCK_SEED_FILE 0 +#endif + + #if SIZEOF_UNSIGNED_LONG == 8 #define ADD_VALUE 0xa5a5a5a5a5a5a5a5 #elif SIZEOF_UNSIGNED_LONG == 4 @@ -105,6 +113,7 @@ static int did_initial_extra_seeding; static char *seed_file_name; static int allow_seed_file_update; +static int no_seed_file_locking; static int secure_alloc; static int quick_test; @@ -272,6 +281,13 @@ return faked_rng || quick_test; } +/* Disable locking of seed files. */ +void +random_disable_locking () +{ + no_seed_file_locking = 1; +} + /**************** * Return a pointer to a randomized buffer of level 0 and LENGTH bits * caller must free the buffer. @@ -359,6 +375,50 @@ seed_file_name = xstrdup( name ); } + +/* Lock an open file identified by file descriptor FD and wait a + reasonable time to succeed. With FOR_WRITE set to true a Rite lock + will be taken. FNAME is used only for diagnostics. Returns 0 on + success or -1 on error. */ +#if LOCK_SEED_FILE +static int +lock_seed_file (int fd, const char *fname, int for_write) +{ + struct flock lck; + struct timeval tv; + int backoff=0; + + if (no_seed_file_locking) + return 0; + + /* We take a lock on the entire file. */ + memset (&lck, 0, sizeof lck); + lck.l_type = for_write? F_WRLCK : F_RDLCK; + lck.l_whence = SEEK_SET; + + while (fcntl (fd, F_SETLK, &lck) == -1) + { + if (errno != EAGAIN && errno != EACCES) + { + log_info (_("can't lock `%s': %s\n"), fname, strerror (errno)); + return -1; + } + + if (backoff > 2) /* Show the first message after ~2.25 seconds. */ + log_info( _("waiting for lock on `%s'...\n"), fname); + + tv.tv_sec = backoff; + tv.tv_usec = 250000; + select (0, NULL, NULL, NULL, &tv); + if (backoff < 10) + backoff++ ; + } + return 0; +} +#endif /*LOCK_SEED_FILE*/ + + + /**************** * Read in a seed form the random_seed file * and return true if this was successful @@ -388,6 +448,12 @@ log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) ); return 0; } + if (lock_seed_file (fd, seed_file_name, 0)) + { + close (fd); + return 0; + } + if( fstat( fd, &sb ) ) { log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) ); close(fd); @@ -468,12 +534,31 @@ fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR ); #else +# if LOCK_SEED_FILE + fd = open( seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR ); +# else fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR ); +# endif #endif if( fd == -1 ) { log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) ); return; } + + if (lock_seed_file (fd, seed_file_name, 1)) + { + close (fd); + return; + } +#if LOCK_SEED_FILE + if (ftruncate (fd, 0)) + { + log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno)); + close (fd); + return; + } +#endif /*LOCK_SEED_FILE*/ + do { i = write( fd, keypool, POOLSIZE ); } while( i == -1 && errno == EINTR ); Modified: trunk/cipher/random.h =================================================================== --- trunk/cipher/random.h 2006-02-08 17:56:01 UTC (rev 3998) +++ trunk/cipher/random.h 2006-02-09 12:54:41 UTC (rev 3999) @@ -30,6 +30,7 @@ void update_random_seed_file(void); int quick_random_gen( int onoff ); int random_is_faked(void); +void random_disable_locking (void); void randomize_buffer( byte *buffer, size_t length, int level ); byte *get_random_bits( size_t nbits, int level, int secure ); void fast_random_poll( void ); Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2006-02-08 17:56:01 UTC (rev 3998) +++ trunk/configure.ac 2006-02-09 12:54:41 UTC (rev 3999) @@ -858,6 +858,7 @@ AC_CHECK_FUNCS(memmove gettimeofday getrusage setrlimit clock_gettime) AC_CHECK_FUNCS(atexit raise getpagesize strftime nl_langinfo setlocale) AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask rand pipe stat getaddrinfo) +AC_CHECK_FUNCS(fcntl ftruncate) AC_REPLACE_FUNCS(mkdtemp timegm isascii memrchr) AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include ]) Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-08 17:56:01 UTC (rev 3998) +++ trunk/g10/ChangeLog 2006-02-09 12:54:41 UTC (rev 3999) @@ -1,3 +1,7 @@ +2006-02-09 Werner Koch + + * gpg.c (main) : Disable random locking. + 2006-02-06 Werner Koch * ccid-driver.c, ccid-driver.h: Updated from GnuPG 1.9. Changes: Modified: trunk/g10/gpg.c =================================================================== --- trunk/g10/gpg.c 2006-02-08 17:56:01 UTC (rev 3998) +++ trunk/g10/gpg.c 2006-02-09 12:54:41 UTC (rev 3999) @@ -2404,7 +2404,10 @@ case oEscapeFrom: opt.escape_from = 1; break; case oNoEscapeFrom: opt.escape_from = 0; break; case oLockOnce: opt.lock_once = 1; break; - case oLockNever: disable_dotlock(); break; + case oLockNever: + disable_dotlock (); + random_disable_locking (); + break; case oLockMultiple: #ifndef __riscos__ opt.lock_once = 0; From cvs at cvs.gnupg.org Thu Feb 9 19:29:33 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Thu Feb 9 18:48:30 2006 Subject: [svn] GnuPG - r4000 - in branches/GNUPG-1-9-BRANCH: . agent scd Message-ID: Author: wk Date: 2006-02-09 19:29:31 +0100 (Thu, 09 Feb 2006) New Revision: 4000 Modified: branches/GNUPG-1-9-BRANCH/NEWS branches/GNUPG-1-9-BRANCH/agent/ChangeLog branches/GNUPG-1-9-BRANCH/agent/agent.h branches/GNUPG-1-9-BRANCH/agent/call-scd.c branches/GNUPG-1-9-BRANCH/agent/gpg-agent.c branches/GNUPG-1-9-BRANCH/scd/ChangeLog branches/GNUPG-1-9-BRANCH/scd/app-common.h branches/GNUPG-1-9-BRANCH/scd/app.c branches/GNUPG-1-9-BRANCH/scd/command.c Log: PIN caching of cards does now work. Modified: branches/GNUPG-1-9-BRANCH/NEWS =================================================================== --- branches/GNUPG-1-9-BRANCH/NEWS 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/NEWS 2006-02-09 18:29:31 UTC (rev 4000) @@ -6,7 +6,9 @@ * Support for CardMan 4040 PCMCIA reader. + * Cards are not anymore reseted at the end of a connection. + Noteworthy changes in version 1.9.20 (2005-12-20) ------------------------------------------------- Modified: branches/GNUPG-1-9-BRANCH/agent/ChangeLog =================================================================== --- branches/GNUPG-1-9-BRANCH/agent/ChangeLog 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/agent/ChangeLog 2006-02-09 18:29:31 UTC (rev 4000) @@ -1,3 +1,13 @@ +2006-02-09 Werner Koch + + * call-scd.c (struct scd_local_s): New field next_local. + (scd_local_list): New. + (start_scd): Put new local into list. + (agent_reset_scd): Remove it from the list. + (agent_scd_check_aliveness): Here is the actual reason why we need + all this stuff. + (agent_reset_scd): Send the new command RESTART instead of RESET. + 2005-12-16 Werner Koch * minip12.c (cram_octet_string): New Modified: branches/GNUPG-1-9-BRANCH/agent/agent.h =================================================================== --- branches/GNUPG-1-9-BRANCH/agent/agent.h 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/agent/agent.h 2006-02-09 18:29:31 UTC (rev 4000) @@ -54,7 +54,7 @@ int batch; /* Batch mode */ const char *homedir; /* Configuration directory name */ - /* Environment setting gathered at program start or hanged using the + /* Environment setting gathered at program start or changed using the Assuan command UPDATESTARTUPTTY. */ char *startup_display; char *startup_ttyname; Modified: branches/GNUPG-1-9-BRANCH/agent/call-scd.c =================================================================== --- branches/GNUPG-1-9-BRANCH/agent/call-scd.c 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/agent/call-scd.c 2006-02-09 18:29:31 UTC (rev 4000) @@ -45,6 +45,16 @@ /* Definition of module local data of the CTRL structure. */ struct scd_local_s { + /* We keep a list of all allocated context with a an achnor at + SCD_LOCAL_LIST (see below). */ + struct scd_local_s *next_local; + + /* We need to get back to the ctrl object actually referencing this + structure. This is really an awkward way of enumerint the lcoal + contects. A much cleaner way would be to keep a global list of + ctrl objects to enumerate them. */ + ctrl_t ctrl_backlink; + assuan_context_t ctx; /* NULL or session context for the SCdaemon used with this connection. */ int locked; /* This flag is used to assert proper use of @@ -72,6 +82,10 @@ }; +/* To keep track of all active SCD contexts, we keep a linked list + anchored at this variable. */ +static struct scd_local_s *scd_local_list; + /* A Mutex used inside the start_scd function. */ static pth_mutex_t start_scd_lock; @@ -202,6 +216,9 @@ ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local); if (!ctrl->scd_local) return gpg_error_from_errno (errno); + ctrl->scd_local->ctrl_backlink = ctrl; + ctrl->scd_local->next_local = scd_local_list; + scd_local_list = ctrl->scd_local; } @@ -216,7 +233,7 @@ if (ctrl->scd_local->ctx) return 0; /* Okay, the context is fine. We used to test for an - alive context here and do an disconnect. How that we + alive context here and do an disconnect. Now that we have a ticker function to check for it, it is easier not to check here but to let the connection run on an error instead. */ @@ -404,12 +421,30 @@ if (pid != (pid_t)(-1) && pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) ) { - /* Okay, scdaemon died. Disconnect the primary connection now - but take care that it won't do another wait. */ + /* Okay, scdaemon died. Disconnect the primary connection + now but take care that it won't do another wait. Also + cleanup all other connections and release their + resources. The next use will start a new daemon then. + Due to the use of the START_SCD_LOCAL we are sure that + none of these context are actually in use. */ + struct scd_local_s *sl; + assuan_set_flag (primary_scd_ctx, ASSUAN_NO_WAITPID, 1); assuan_disconnect (primary_scd_ctx); + + for (sl=scd_local_list; sl; sl = sl->next_local) + { + if (sl->ctx) + { + if (sl->ctx != primary_scd_ctx) + assuan_disconnect (sl->ctx); + sl->ctx = NULL; + } + } + primary_scd_ctx = NULL; primary_scd_ctx_reusable = 0; + xfree (socket_name); socket_name = NULL; } @@ -422,7 +457,8 @@ -/* Reset the SCD if it has been used. */ +/* Reset the SCD if it has been used. Actually it is not a reset but + a cleanup of resources used by the current connection. */ int agent_reset_scd (ctrl_t ctrl) { @@ -436,17 +472,41 @@ reuse. */ if (ctrl->scd_local->ctx == primary_scd_ctx) { - /* The RESET may fail for example if the scdaemon has - already been terminated. We need to set the reusable - flag anyway to make sure that the aliveness check can - clean it up. */ - assuan_transact (primary_scd_ctx, "RESET", + /* Send a RESTART to the SCD. This is required for the + primary connection as a kind of virtual EOF; we don't + have another way to tell it that the next command + should be viewed as if a new connection has been + made. For the non-primary connections this is not + needed as we simply close the socket. We don't check + for an error here because the RESTART may fail for + example if the scdaemon has already been terminated. + Anyway, we need to set the reusable flag to make sure + that the aliveness check can clean it up. */ + assuan_transact (primary_scd_ctx, "RESTART", NULL, NULL, NULL, NULL, NULL, NULL); primary_scd_ctx_reusable = 1; } else assuan_disconnect (ctrl->scd_local->ctx); + ctrl->scd_local->ctx = NULL; } + + /* Remove the local context from our list and release it. */ + if (!scd_local_list) + BUG (); + else if (scd_local_list == ctrl->scd_local) + scd_local_list = ctrl->scd_local->next_local; + else + { + struct scd_local_s *sl; + + for (sl=scd_local_list; sl->next_local; sl = sl->next_local) + if (sl->next_local == ctrl->scd_local) + break; + if (!sl->next_local) + BUG (); + sl->next_local = ctrl->scd_local->next_local; + } xfree (ctrl->scd_local); ctrl->scd_local = NULL; } Modified: branches/GNUPG-1-9-BRANCH/agent/gpg-agent.c =================================================================== --- branches/GNUPG-1-9-BRANCH/agent/gpg-agent.c 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/agent/gpg-agent.c 2006-02-09 18:29:31 UTC (rev 4000) @@ -1320,7 +1320,7 @@ agent_scd_check_aliveness (); /* If we are running as a child of another process, check whether - the parent is still alive and shutdwon if now. */ + the parent is still alive and shutdown if not. */ #ifndef HAVE_W32_SYSTEM if (parent_pid != (pid_t)(-1)) { Modified: branches/GNUPG-1-9-BRANCH/scd/ChangeLog =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/ChangeLog 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/scd/ChangeLog 2006-02-09 18:29:31 UTC (rev 4000) @@ -1,3 +1,17 @@ +2006-02-09 Werner Koch + + * app.c (release_application): Factored code out to .. + (deallocate_app): new function. + (select_application): Introduce new saved application stuff. + (application_notify_card_removed): New. + * command.c (update_card_removed): Call it. + + * app.c (check_application_conflict): New. + * command.c (open_card): Use it here. + (cmd_restart): New command. + + * command.c (cmd_lock): Fixed --wait option to actually terminate. + 2006-02-08 Werner Koch * ccid-driver.c (ccid_get_atr): Read Parameter and select T=1 Modified: branches/GNUPG-1-9-BRANCH/scd/app-common.h =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/app-common.h 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/scd/app-common.h 2006-02-09 18:29:31 UTC (rev 4000) @@ -129,6 +129,8 @@ /*-- app.c --*/ void app_dump_state (void); +void application_notify_card_removed (int slot); +gpg_error_t check_application_conflict (ctrl_t ctrl, const char *name); gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app); void release_application (app_t app); Modified: branches/GNUPG-1-9-BRANCH/scd/app.c =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/app.c 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/scd/app.c 2006-02-09 18:29:31 UTC (rev 4000) @@ -40,9 +40,15 @@ int initialized; pth_mutex_t lock; app_t app; /* Application context in use or NULL. */ + app_t last_app; /* Last application object used as this slot or NULL. */ } lock_table[10]; + +static void deallocate_app (app_t app); + + + /* Lock the reader SLOT. This function shall be used right before calling any of the actual application functions to serialize access to the reader. We do this always even if the reader is not @@ -68,6 +74,7 @@ } lock_table[slot].initialized = 1; lock_table[slot].app = NULL; + lock_table[slot].last_app = NULL; } if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL)) @@ -121,13 +128,21 @@ log_info ("app_dump_state: slot=%d lock=", slot); dump_mutex_state (&lock_table[slot].lock); if (lock_table[slot].app) - log_printf (" app=%p type=`%s'", - lock_table[slot].app, lock_table[slot].app->apptype); + { + log_printf (" app=%p", lock_table[slot].app); + if (lock_table[slot].app->apptype) + log_printf (" type=`%s'", lock_table[slot].app->apptype); + } + if (lock_table[slot].last_app) + { + log_printf (" lastapp=%p", lock_table[slot].last_app); + if (lock_table[slot].last_app->apptype) + log_printf (" type=`%s'", lock_table[slot].last_app->apptype); + } log_printf ("\n"); } } - /* Check wether the application NAME is allowed. This does not mean we have support for it though. */ static int @@ -142,6 +157,46 @@ } +/* This may be called to tell this module about a removed card. */ +void +application_notify_card_removed (int slot) +{ + if (slot < 0 || slot >= DIM (lock_table)) + return; + + /* Deallocate a saved application for that slot, so that we won't + try to reuse it. */ + if (lock_table[slot].initialized && lock_table[slot].last_app) + { + app_t app = lock_table[slot].last_app; + + lock_table[slot].last_app = NULL; + deallocate_app (app); + } +} + + +/* This fucntion is used by the serialno command to check for an + application conflict which may appear if the serialno command is + used to request a specific application and the connection has + already done a select_application. */ +gpg_error_t +check_application_conflict (ctrl_t ctrl, const char *name) +{ + int slot = ctrl->reader_slot; + app_t app; + + if (slot < 0 || slot >= DIM (lock_table)) + return gpg_error (GPG_ERR_INV_VALUE); + + app = lock_table[slot].initialized ? lock_table[slot].app : NULL; + if (app && app->apptype && name) + if ( ascii_strcasecmp (app->apptype, name)) + return gpg_error (GPG_ERR_CONFLICT); + return 0; +} + + /* If called with NAME as NULL, select the best fitting application and return a context; otherwise select the application with NAME and return a context. SLOT identifies the reader device. Returns @@ -173,6 +228,32 @@ return gpg_error (GPG_ERR_CONFLICT); } + /* If we don't have an app, check whether we have a saved + application for that slot. This is useful so that a card does + not get reset even if only one session is using the card - so the + PIN cache and other cached data are preserved. */ + if (!app && lock_table[slot].initialized && lock_table[slot].last_app) + { + app = lock_table[slot].last_app; + if (!name || (app->apptype && !ascii_strcasecmp (app->apptype, name)) ) + { + /* Yes, we can reuse this application - either the caller + requested an unspecific one or the requested one matches + the saved one. */ + lock_table[slot].app = app; + lock_table[slot].last_app = NULL; + } + else + { + /* No, this saved application can't be used - deallocate it. */ + lock_table[slot].last_app = NULL; + deallocate_app (app); + app = NULL; + } + } + + /* If we can reuse an application, bump the reference count and + return it. */ if (app) { if (app->slot != slot) @@ -183,6 +264,7 @@ return 0; /* Okay: We share that one. */ } + /* Need to allocate a new one. */ app = xtrycalloc (1, sizeof *app); if (!app) { @@ -281,9 +363,25 @@ } +/* Deallocate the application. */ +static void +deallocate_app (app_t app) +{ + if (app->fnc.deinit) + { + app->fnc.deinit (app); + app->fnc.deinit = NULL; + } + + xfree (app->serialno); + xfree (app); +} + /* Free the resources associated with the application APP. APP is allowed to be NULL in which case this is a no-op. Note that we are - using reference counting to track the users of the application. */ + using reference counting to track the users of the application and + actually deferiing the deallcoation to allow for a later resuse by + a new connection. */ void release_application (app_t app) { @@ -297,20 +395,19 @@ if (--app->ref_count) return; - /* Clear the reference to the application from the lock table. */ + /* Move the reference to the application in the lock table. */ for (slot = 0; slot < DIM (lock_table); slot++) if (lock_table[slot].initialized && lock_table[slot].app == app) - lock_table[slot].app = NULL; + { + if (lock_table[slot].last_app) + deallocate_app (lock_table[slot].last_app); + lock_table[slot].last_app = lock_table[slot].app; + lock_table[slot].app = NULL; + return; + } - /* Deallocate. */ - if (app->fnc.deinit) - { - app->fnc.deinit (app); - app->fnc.deinit = NULL; - } - - xfree (app->serialno); - xfree (app); + log_debug ("application missing in lock table - deallocating anyway\n"); + deallocate_app (app); } Modified: branches/GNUPG-1-9-BRANCH/scd/command.c =================================================================== --- branches/GNUPG-1-9-BRANCH/scd/command.c 2006-02-09 12:54:41 UTC (rev 3999) +++ branches/GNUPG-1-9-BRANCH/scd/command.c 2006-02-09 18:29:31 UTC (rev 4000) @@ -47,7 +47,7 @@ #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t)) -/* Macro to flag a a removed card. */ +/* Macro to flag a removed card. */ #define TEST_CARD_REMOVAL(c,r) \ do { \ int _r = (r); \ @@ -108,6 +108,8 @@ if (sl->ctrl_backlink && sl->ctrl_backlink->reader_slot == slot) sl->card_removed = value; + if (value) + application_notify_card_removed (slot); } @@ -142,7 +144,7 @@ struct server_local_s *sl; /* If we are the only session with the reader open we may close - it. If not, do a reset unless the a lock is held on the + it. If not, do a reset unless a lock is held on the reader. */ for (sl=session_list; sl; sl = sl->next_session) if (sl != ctrl->server_local @@ -257,7 +259,12 @@ return gpg_error (GPG_ERR_LOCKED); if (ctrl->app_ctx) - return 0; /* Already initialized for one specific application. */ + { + /* Already initialized for one specific application. Need to + check that the client didn't requested a specific application + different from the one in use. */ + return check_application_conflict (ctrl, apptype); + } if (ctrl->reader_slot != -1) slot = ctrl->reader_slot; @@ -1201,7 +1208,7 @@ Grant exclusive card access to this session. Note that there is no lock counter used and a second lock from the same session will - get ignore. A single unlock (or RESET) unlocks the session. + be ignored. A single unlock (or RESET) unlocks the session. Return GPG_ERR_LOCKED if another session has locked the reader. If the option --wait is given the command will wait until a @@ -1225,9 +1232,12 @@ #ifdef USE_GNU_PTH if (rc && has_option (line, "--wait")) { + rc = 0; pth_sleep (1); /* Better implement an event mechanism. However, for card operations this should be sufficient. */ + /* FIXME: Need to check that the connection is still alive. + This can be done by issuing status messages. */ goto retry; } #endif /*USE_GNU_PTH*/ @@ -1293,7 +1303,37 @@ } +/* RESTART + Restart the current connection; this is a kind of warn reset. It + deletes the context used by this connection but does not send a + RESET to the card. Thus the card itself won't get reset. + + This is used by gpg-agent to reuse a primary pipe connection and + may be used by clients to backup from a conflict in the serial + command; i.e. to select another application. +*/ + +static int +cmd_restart (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + + if (ctrl->app_ctx) + { + release_application (ctrl->app_ctx); + ctrl->app_ctx = NULL; + } + if (locked_session && ctrl->server_local == locked_session) + { + locked_session = NULL; + log_info ("implicitly unlocking due to RESTART\n"); + } + return 0; +} + + + /* Tell the assuan library about our commands */ static int @@ -1323,6 +1363,7 @@ { "LOCK", cmd_lock }, { "UNLOCK", cmd_unlock }, { "GETINFO", cmd_getinfo }, + { "RESTART", cmd_restart }, { NULL } }; int i, rc; From cvs at cvs.gnupg.org Tue Feb 14 11:18:02 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue Feb 14 10:36:10 2006 Subject: [svn] GnuPG - r4001 - in trunk: checks doc g10 include tools util Message-ID: Author: wk Date: 2006-02-14 11:17:57 +0100 (Tue, 14 Feb 2006) New Revision: 4001 Added: trunk/checks/verify.test Modified: trunk/checks/ChangeLog trunk/checks/Makefile.am trunk/doc/DETAILS trunk/g10/ChangeLog trunk/g10/mainproc.c trunk/g10/verify.c trunk/include/ChangeLog trunk/include/errors.h trunk/tools/ChangeLog trunk/tools/mk-tdata.c trunk/util/ChangeLog trunk/util/errors.c Log: Fixed a wrong return code with gpg --verify Modified: trunk/checks/ChangeLog =================================================================== --- trunk/checks/ChangeLog 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/checks/ChangeLog 2006-02-14 10:17:57 UTC (rev 4001) @@ -1,3 +1,7 @@ +2006-02-14 Werner Koch + + * verify.test: New. + 2005-06-21 Werner Koch * conventional.test (algos): Uhh ohh, cut+paste error and not Modified: trunk/checks/Makefile.am =================================================================== --- trunk/checks/Makefile.am 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/checks/Makefile.am 2006-02-14 10:17:57 UTC (rev 4001) @@ -30,7 +30,7 @@ armsignencrypt.test armdetach.test \ armdetachm.test detachm.test genkey1024.test \ conventional.test conventional-mdc.test \ - multisig.test + multisig.test verify.test TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \ Added: trunk/checks/verify.test =================================================================== --- trunk/checks/verify.test 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/checks/verify.test 2006-02-14 10:17:57 UTC (rev 4001) @@ -0,0 +1,11 @@ +#!/bin/sh + +. $srcdir/defs.inc || exit 3 + +#info check that verify fails for bad input data +../tools/mk-tdata --char 0x2d 64 >x +$GPG --verify x data-500 && error "no error code from verify" +../tools/mk-tdata --char 0xca 64 >x +$GPG --verify x data-500 && error "no error code from verify" + +exit 0 Property changes on: trunk/checks/verify.test ___________________________________________________________________ Name: svn:executable + * Modified: trunk/doc/DETAILS =================================================================== --- trunk/doc/DETAILS 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/doc/DETAILS 2006-02-14 10:17:57 UTC (rev 4001) @@ -270,7 +270,9 @@ No data has been found. Codes for what are: 1 - No armored data. 2 - Expected a packet but did not found one. - 3 - Invalid packet found, this may indicate a non OpenPGP message. + 3 - Invalid packet found, this may indicate a non OpenPGP + message. + 4 - signature expected but not found You may see more than one of these status lines. UNEXPECTED Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/g10/ChangeLog 2006-02-14 10:17:57 UTC (rev 4001) @@ -1,3 +1,11 @@ +2006-02-14 Werner Koch + + * verify.c (verify_signatures): Print warning also for NO_DATA. + + * mainproc.c (struct mainproc_context): New field any_sig_seen. + (add_signature): Set it. + (proc_signature_packets): Test and return NO_DATA. + 2006-02-09 Werner Koch * gpg.c (main) : Disable random locking. Modified: trunk/g10/mainproc.c =================================================================== --- trunk/g10/mainproc.c 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/g10/mainproc.c 2006-02-14 10:17:57 UTC (rev 4001) @@ -1,6 +1,6 @@ /* mainproc.c - handle packets * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. + * 2005, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -55,28 +55,31 @@ * Structure to hold the context */ typedef struct mainproc_context *CTX; -struct mainproc_context { - struct mainproc_context *anchor; /* may be useful in the future */ - PKT_public_key *last_pubkey; - PKT_secret_key *last_seckey; - PKT_user_id *last_user_id; - md_filter_context_t mfx; - int sigs_only; /* process only signatures and reject all other stuff */ - int encrypt_only; /* process only encryption messages */ - STRLIST signed_data; - const char *sigfilename; - DEK *dek; - int last_was_session_key; - KBNODE list; /* the current list of packets */ - int have_data; - IOBUF iobuf; /* used to get the filename etc. */ - int trustletter; /* temp usage in list_node */ - ulong symkeys; - struct kidlist_item *pkenc_list; /* list of encryption packets */ - struct { - int op; - int stop_now; - } pipemode; +struct mainproc_context +{ + struct mainproc_context *anchor; /* May be useful in the future. */ + PKT_public_key *last_pubkey; + PKT_secret_key *last_seckey; + PKT_user_id *last_user_id; + md_filter_context_t mfx; + int sigs_only; /* Process only signatures and reject all other stuff. */ + int encrypt_only; /* Process only encryption messages. */ + STRLIST signed_data; + const char *sigfilename; + DEK *dek; + int last_was_session_key; + KBNODE list; /* The current list of packets. */ + int have_data; + IOBUF iobuf; /* Used to get the filename etc. */ + int trustletter; /* Temporary usage in list_node. */ + ulong symkeys; + struct kidlist_item *pkenc_list; /* List of encryption packets. */ + struct + { + int op; + int stop_now; + } pipemode; + int any_sig_seen; /* Set to true if a signature packet has been seen. */ }; @@ -217,6 +220,7 @@ { KBNODE node; + c->any_sig_seen = 1; if( pkt->pkttype == PKT_SIGNATURE && !c->list ) { /* This is the first signature for the following datafile. * GPG does not write such packets; instead it always uses @@ -1152,6 +1156,18 @@ c->signed_data = signedfiles; c->sigfilename = sigfilename; rc = do_proc_packets( c, a ); + + /* If we have not encountered any signature we print an error + messages, send a NODATA status back and return an error code. + Using log_error is required becuase verify_files does not check + error codes for each file but we want to terminate the process + with an error. */ + if (!rc && !c->any_sig_seen) + { + write_status_text (STATUS_NODATA, "4"); + log_error (_("no signature found\n")); + rc = G10ERR_NO_DATA; + } xfree( c ); return rc; } Modified: trunk/g10/verify.c =================================================================== --- trunk/g10/verify.c 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/g10/verify.c 2006-02-14 10:17:57 UTC (rev 4001) @@ -113,7 +113,7 @@ rc = proc_signature_packets( NULL, fp, sl, sigfile ); free_strlist(sl); iobuf_close(fp); - if( afx.no_openpgp_data && rc == -1 ) { + if( (afx.no_openpgp_data && rc == -1) || rc == G10ERR_NO_DATA ) { log_error(_("the signature could not be verified.\n" "Please remember that the signature file (.sig or .asc)\n" "should be the first file given on the command line.\n") ); Modified: trunk/include/ChangeLog =================================================================== --- trunk/include/ChangeLog 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/include/ChangeLog 2006-02-14 10:17:57 UTC (rev 4001) @@ -1,3 +1,7 @@ +2006-02-14 Werner Koch + + * errors.h (G10ERR_NO_DATA): New. + 2005-12-23 David Shaw * util.h: Prototype get_cert(). Modified: trunk/include/errors.h =================================================================== --- trunk/include/errors.h 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/include/errors.h 2006-02-14 10:17:57 UTC (rev 4001) @@ -78,6 +78,7 @@ #define G10ERR_KEYSERVER 55 #define G10ERR_CANCELED 56 #define G10ERR_NO_CARD 57 +#define G10ERR_NO_DATA 58 #ifndef HAVE_STRERROR char *strerror (int n); Modified: trunk/tools/ChangeLog =================================================================== --- trunk/tools/ChangeLog 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/tools/ChangeLog 2006-02-14 10:17:57 UTC (rev 4001) @@ -1,3 +1,7 @@ +2006-02-14 Werner Koch + + * mk-tdata.c (main): Implement option --char. + 2005-08-05 David Shaw * gpg-zip.in: Add --decrypt functionality. Fix quoting so Modified: trunk/tools/mk-tdata.c =================================================================== --- trunk/tools/mk-tdata.c 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/tools/mk-tdata.c 2006-02-14 10:17:57 UTC (rev 4001) @@ -1,5 +1,5 @@ /* mk-tdata.c - Create some simple random testdata - * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2006 Free Software Foundation, Inc. * * This file is free software; as a special exception the author gives * unlimited permission to copy and/or distribute it, with or without @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -23,20 +24,44 @@ int main(int argc, char **argv) { - int i, c; - int limit =0; + int i, c = 0; + int limit =0; + int char_mode = 0; - limit = argc > 1 ? atoi(argv[1]) : 0; + if (argc) + { + argc--; + argv++; + } - srand(getpid()); + /* Check for option --char N */ + if (argc > 1 && !strcmp (argv[0], "--char")) + { + char_mode = 1; + c = strtol (argv[1], NULL, 0); + argc -= 2; + argv += 2; + } + + limit = argc ? atoi(argv[0]) : 0; - for(i=0; !limit || i < limit; i++ ) { + srand(getpid()); + + for (i=0; !limit || i < limit; i++ ) + { + if (char_mode) + { + putchar (c); + } + else + { #ifdef HAVE_RAND - c = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1); + c = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1); #else - c = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1); + c = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1); #endif - putchar(c); + putchar (c); + } } - return 0; + return 0; } Modified: trunk/util/ChangeLog =================================================================== --- trunk/util/ChangeLog 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/util/ChangeLog 2006-02-14 10:17:57 UTC (rev 4001) @@ -1,3 +1,7 @@ +2006-02-14 Werner Koch + + * errors.c (g10_errstr): Add NO_DATA. + 2006-01-26 David Shaw * cert.c (get_cert): Disable IPGP types for now until the format Modified: trunk/util/errors.c =================================================================== --- trunk/util/errors.c 2006-02-09 18:29:31 UTC (rev 4000) +++ trunk/util/errors.c 2006-02-14 10:17:57 UTC (rev 4001) @@ -108,6 +108,7 @@ X(KEYSERVER ,N_("keyserver error")) X(CANCELED ,N_("canceled")) X(NO_CARD ,N_("no card")) + X(NO_DATA ,N_("no data")) default: p = buf; sprintf(buf, "g10err=%d", err); break; } #undef X From cvs at cvs.gnupg.org Tue Feb 14 14:34:24 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue Feb 14 13:52:32 2006 Subject: [svn] GnuPG - r4002 - in branches/GNUPG-1-9-BRANCH: doc sm Message-ID: Author: wk Date: 2006-02-14 14:34:23 +0100 (Tue, 14 Feb 2006) New Revision: 4002 Modified: branches/GNUPG-1-9-BRANCH/doc/ChangeLog branches/GNUPG-1-9-BRANCH/doc/gpgsm.texi branches/GNUPG-1-9-BRANCH/sm/qualified.c Log: Added documentation for qualified signatures Modified: branches/GNUPG-1-9-BRANCH/doc/ChangeLog =================================================================== --- branches/GNUPG-1-9-BRANCH/doc/ChangeLog 2006-02-14 10:17:57 UTC (rev 4001) +++ branches/GNUPG-1-9-BRANCH/doc/ChangeLog 2006-02-14 13:34:23 UTC (rev 4002) @@ -1,3 +1,7 @@ +2006-02-14 Werner Koch + + * gpgsm.texi (GPGSM Configuration): New section. + 2005-11-14 Werner Koch * qualified.txt: Added real information. Modified: branches/GNUPG-1-9-BRANCH/doc/gpgsm.texi =================================================================== --- branches/GNUPG-1-9-BRANCH/doc/gpgsm.texi 2006-02-14 10:17:57 UTC (rev 4001) +++ branches/GNUPG-1-9-BRANCH/doc/gpgsm.texi 2006-02-14 13:34:23 UTC (rev 4002) @@ -23,6 +23,7 @@ @menu * GPGSM Commands:: List of all commands. * GPGSM Options:: List of all options. +* GPGSM Configuration:: Configuration files. * GPGSM Examples:: Some usage examples. Developer information: @@ -526,7 +527,106 @@ stripping off the two leading dashes. +@c man begin FILES +@node GPGSM Configuration +@section Configuration files + +There are a few configuration files to control certain aspects of +@command{gpgsm}'s operation. Unless noted, they are expected in the +current home directory (@pxref{option --homedir}). + +@table @file + +@item gpgsm.conf +@cindex gpgsm.conf +This is the standard configuration file read by @command{gpgsm} on +startup. It may contain any valid long option; the leading two dashes +may not be entered and the option may not be abbreviated. This default +name may be changed on the command line (@pxref{option + --options}). + +@item policies.txt +@cindex policies.txt +This is a list of allowed CA policies. This file should list the +object identifiers of the policies line by line. Empty lines and +lines starting with a hash mark are ignored. Policies missing in this +file and not marked as critical in the certificate will print only a +warning; certificates with policies marked as critical and not listed +in this file will fail the signature verification. + +For example, to allow only the policy 2.289.9.9, the file should look +like this: + +@example +# Allowed policies +2.289.9.9 +@end example + +@item qualified.txt +@cindex qualified.txt +This is the list of root certificates used for qualified certificates. +They are defined as certificates capable of creating legally binding +signatures in the same way as handwritten signatures are. Comments +start with a hash mark and empty lines are ignored. Lines do have a +length limit but this is not a serious limitation as the format of the +entries is fixed and checked by gpgsm: A non-comment line starts with +optional white spaces, followed by exactly 40 hex character, white space +and a lowercased 2 letter country code. Additional data delimited with +by a white space is current ignored but might late be used for other +purposes. + +Note that even if a certificate is listed in this file, this does not +mean that thecertificate is trusted; in general the certificates listed +in this file need to be listed also in @file{trustlist.txt}. + +This is a global file an installed in the data directory +(e.g. @file{/usr/share/gnupg/qualified.txt}). GnuPG installs a suitable +file with root certificates as used in Germany. As new Root-CA +certificates may be issued over time, these entries may need to be +updated; new distributions of this software should come with an updated +list but it is still the responsibility of the Administrator to check +that this list is correct. + +Everytime @command{gpgsm} uses a certificate for signing or verification +this file will be consulted to check whether the certificate under +question has ultimately been issued by one of these CAs. If this is the +case the user will be informed that the verified signature represents a +legally binding (``qualified'') signature. When creating a signature +using such a certificate an extra prompt will be issued to let the user +confirm that such a legally binding signature shall really be created. + +Because this software has not yet been approved for use with such +certificates, appropriate notices will be shown to indicate this fact. + +@end table + +Note that on larger installations, it is useful to put predefined files +into the directory @file{/etc/skel/.gnupg/} so that newly created users +start up with a working configuration. For existing users the a small +helper script is provided to create these files (@pxref{addgnupghome}). + + +For internal purposes gpgsm creates and maintaines a few other files; +They all live in in the current home directory (@pxref{option +--homedir}). Only @command{gpgsm} may modify these files. + +@table @file +@item pubring.kbx +@cindex pubring.kbx +This a database file storing the certificates as well as meta +information. For debugging purposes the tool @command{kbxutil} may be +used to show the internal structure of this file. + +@item random_seed +@cindex random_seed +This content of this file is used to maintain the internal state of the +random number generator accross invocations. The same file is used by +other programs of this software too. + +@end table + + @c @c Examples @c Modified: branches/GNUPG-1-9-BRANCH/sm/qualified.c =================================================================== --- branches/GNUPG-1-9-BRANCH/sm/qualified.c 2006-02-14 10:17:57 UTC (rev 4001) +++ branches/GNUPG-1-9-BRANCH/sm/qualified.c 2006-02-14 13:34:23 UTC (rev 4002) @@ -270,7 +270,7 @@ /* Popup a prompt to inform the user that the signature created is not - a qualified one. This is of course only doen if we know that we + a qualified one. This is of course only done if we know that we have been approved. */ gpg_error_t gpgsm_not_qualified_warning (ctrl_t ctrl, ksba_cert_t cert) From cvs at cvs.gnupg.org Tue Feb 14 19:26:13 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Tue Feb 14 18:44:24 2006 Subject: [svn] GnuPG - r4004 - tags Message-ID: Author: wk Date: 2006-02-14 19:26:13 +0100 (Tue, 14 Feb 2006) New Revision: 4004 Added: tags/gnupg-1.4.3rc1/ Log: Tagged RC Copied: tags/gnupg-1.4.3rc1 (from rev 4003, trunk) From cvs at cvs.gnupg.org Wed Feb 15 14:30:10 2006 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed Feb 15 13:48:10 2006 Subject: [svn] gpgme - r1153 - trunk/gpgme Message-ID: Author: marcus Date: 2006-02-15 14:30:08 +0100 (Wed, 15 Feb 2006) New Revision: 1153 Modified: trunk/gpgme/ChangeLog trunk/gpgme/w32-io.c Log: 2006-02-15 Marcus Brinkmann * w32-io.c (create_writer): Make C->have_data a manually resetted event. (writer): Move code from end of if block to beginning, so it is also run the first time. (_gpgme_io_write): Move assert check after error check. Reset the is_empty event, and also do it eagerly. (_gpgme_io_select): Unconditionally wait for the is_empty event. Modified: trunk/gpgme/ChangeLog =================================================================== --- trunk/gpgme/ChangeLog 2006-01-26 10:56:56 UTC (rev 1152) +++ trunk/gpgme/ChangeLog 2006-02-15 13:30:08 UTC (rev 1153) @@ -1,3 +1,13 @@ +2006-02-15 Marcus Brinkmann + + * w32-io.c (create_writer): Make C->have_data a manually resetted + event. + (writer): Move code from end of if block to beginning, so it + is also run the first time. + (_gpgme_io_write): Move assert check after error check. Reset + the is_empty event, and also do it eagerly. + (_gpgme_io_select): Unconditionally wait for the is_empty event. + 2006-01-26 Werner Koch * w32-util.c (_gpgme_get_conf_int): New. Modified: trunk/gpgme/w32-io.c =================================================================== --- trunk/gpgme/w32-io.c 2006-01-26 10:56:56 UTC (rev 1152) +++ trunk/gpgme/w32-io.c 2006-02-15 13:30:08 UTC (rev 1153) @@ -438,7 +438,13 @@ DEBUG2 ("writer thread %p for file %p started", c->thread_hd, c->file_hd ); for (;;) { LOCK (c->mutex); + if ( c->stop_me ) { + UNLOCK (c->mutex); + break; + } if ( !c->nbytes ) { + if (!SetEvent (c->is_empty)) + DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); if (!ResetEvent (c->have_data) ) DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); UNLOCK (c->mutex); @@ -468,14 +474,6 @@ LOCK (c->mutex); c->nbytes -= nwritten; - if (c->stop_me) { - UNLOCK (c->mutex); - break; - } - if ( !c->nbytes ) { - if ( !SetEvent (c->is_empty) ) - DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); - } UNLOCK (c->mutex); } /* indicate that we have an error */ @@ -505,7 +503,7 @@ return NULL; c->file_hd = fd; - c->have_data = CreateEvent (&sec_attr, FALSE, FALSE, NULL); + c->have_data = CreateEvent (&sec_attr, TRUE, FALSE, NULL); c->is_empty = CreateEvent (&sec_attr, TRUE, TRUE, NULL); c->stopped = CreateEvent (&sec_attr, TRUE, FALSE, NULL); if (!c->have_data || !c->is_empty || !c->stopped ) { @@ -637,12 +635,14 @@ LOCK (c->mutex); if ( c->nbytes ) { /* bytes are pending for send */ + /* Reset the is_empty event. Better safe than sorry. */ + if (!ResetEvent (c->is_empty)) + DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); UNLOCK (c->mutex); DEBUG2 ("fd %d: waiting for empty buffer in thread %p", fd, c->thread_hd); WaitForSingleObject (c->is_empty, INFINITE); DEBUG2 ("fd %d: thread %p buffer is empty", fd, c->thread_hd); - assert (!c->nbytes); LOCK (c->mutex); } @@ -651,11 +651,20 @@ DEBUG1 ("fd %d: write error", fd ); return -1; } - + + /* If no error occured, the number of bytes in the buffer must be + zero. */ + assert (!c->nbytes); + if (count > WRITEBUF_SIZE) count = WRITEBUF_SIZE; memcpy (c->buffer, buffer, count); c->nbytes = count; + + /* We have to reset the is_empty event early, because it is also + used by the select() implementation to probe the channel. */ + if (!ResetEvent (c->is_empty)) + DEBUG1 ("ResetEvent failed: ec=%d", (int)GetLastError ()); if (!SetEvent (c->have_data)) DEBUG1 ("SetEvent failed: ec=%d", (int)GetLastError ()); UNLOCK (c->mutex); @@ -1018,18 +1027,11 @@ DEBUG0 ("Too many objects for WFMO!" ); return -1; } - LOCK (c->mutex); - if ( !c->nbytes ) { - waitidx[nwait] = i; - waitbuf[nwait++] = c->is_empty; - DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd ); - any = 1; - } - else { - DEBUG_ADD1 (dbg_help, "w%d(ignored) ", fds[i].fd ); - } - UNLOCK (c->mutex); + waitidx[nwait] = i; + waitbuf[nwait++] = c->is_empty; } + DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd ); + any = 1; } } } From cvs at cvs.gnupg.org Sun Feb 19 03:08:44 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Sun Feb 19 02:26:26 2006 Subject: [svn] GnuPG - r4006 - trunk Message-ID: Author: dshaw Date: 2006-02-19 03:08:43 +0100 (Sun, 19 Feb 2006) New Revision: 4006 Modified: trunk/ChangeLog trunk/configure.ac Log: * configure.ac: Try linking the UINT64_C test program (rather than just compiling it) as UINT64_C looks like a (missing) function, causing a false positive. Noted by Claus Assmann. Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2006-02-14 18:39:24 UTC (rev 4005) +++ trunk/ChangeLog 2006-02-19 02:08:43 UTC (rev 4006) @@ -1,3 +1,9 @@ +2006-02-18 David Shaw + + * configure.ac: Try linking the UINT64_C test program (rather than + just compiling it) as UINT64_C looks like a (missing) function, + causing a false positive. Noted by Claus Assmann. + 2006-02-14 Werner Koch Released 1.4.3rc1. Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2006-02-14 18:39:24 UTC (rev 4005) +++ trunk/configure.ac 2006-02-19 02:08:43 UTC (rev 4006) @@ -817,9 +817,9 @@ AC_CHECK_SIZEOF(unsigned long long) # Ensure that we have UINT64_C before we bother to check for uint64_t -gt_HEADER_INTTYPES_H +AC_CHECK_HEADERS([inttypes.h]) AC_CACHE_CHECK([for UINT64_C], [gnupg_cv_uint64_c_works], - AC_COMPILE_IFELSE(AC_LANG_PROGRAM([#include ],[ + AC_LINK_IFELSE(AC_LANG_PROGRAM([#include ],[ uint64_t foo=UINT64_C(42);]),gnupg_cv_uint64_c_works=yes,gnupg_cv_uint64_c_works=no)) if test "$gnupg_cv_uint64_c_works" = "yes" ; then From cvs at cvs.gnupg.org Sun Feb 19 22:03:02 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Sun Feb 19 21:20:37 2006 Subject: [svn] GnuPG - r4007 - trunk/util Message-ID: Author: dshaw Date: 2006-02-19 22:03:01 +0100 (Sun, 19 Feb 2006) New Revision: 4007 Modified: trunk/util/ChangeLog trunk/util/http.c Log: * http.c (send_request): A zero length proxy is the same as no proxy. Modified: trunk/util/ChangeLog =================================================================== --- trunk/util/ChangeLog 2006-02-19 02:08:43 UTC (rev 4006) +++ trunk/util/ChangeLog 2006-02-19 21:03:01 UTC (rev 4007) @@ -1,3 +1,8 @@ +2006-02-19 David Shaw + + * http.c (send_request): A zero length proxy is the same as no + proxy. + 2006-02-14 Werner Koch * errors.c (g10_errstr): Add NO_DATA. Modified: trunk/util/http.c =================================================================== --- trunk/util/http.c 2006-02-19 02:08:43 UTC (rev 4006) +++ trunk/util/http.c 2006-02-19 21:03:01 UTC (rev 4007) @@ -518,7 +518,7 @@ server = *hd->uri->host? hd->uri->host : "localhost"; port = hd->uri->port? hd->uri->port : 80; - if(proxy) + if(proxy && *proxy) { PARSED_URI uri; From cvs at cvs.gnupg.org Sun Feb 19 23:09:11 2006 From: cvs at cvs.gnupg.org (svn author wk) Date: Sun Feb 19 22:26:47 2006 Subject: [svn] GnuPG - r4008 - branches/GNUPG-1-9-BRANCH/sm Message-ID: Author: wk Date: 2006-02-19 23:09:10 +0100 (Sun, 19 Feb 2006) New Revision: 4008 Modified: branches/GNUPG-1-9-BRANCH/sm/ChangeLog branches/GNUPG-1-9-BRANCH/sm/call-dirmngr.c Log: Better warning messages Modified: branches/GNUPG-1-9-BRANCH/sm/ChangeLog =================================================================== --- branches/GNUPG-1-9-BRANCH/sm/ChangeLog 2006-02-19 21:03:01 UTC (rev 4007) +++ branches/GNUPG-1-9-BRANCH/sm/ChangeLog 2006-02-19 22:09:10 UTC (rev 4008) @@ -1,3 +1,7 @@ +2006-02-17 Werner Koch + + * call-dirmngr.c (start_dirmngr): Print name of dirmngr to be started. + 2005-11-23 Werner Koch * gpgsm.h: New member QUALSIG_APPROVAL. Modified: branches/GNUPG-1-9-BRANCH/sm/call-dirmngr.c =================================================================== --- branches/GNUPG-1-9-BRANCH/sm/call-dirmngr.c 2006-02-19 21:03:01 UTC (rev 4007) +++ branches/GNUPG-1-9-BRANCH/sm/call-dirmngr.c 2006-02-19 22:09:10 UTC (rev 4008) @@ -170,8 +170,16 @@ int no_close_list[3]; int i; + if (!opt.dirmngr_program || !*opt.dirmngr_program) + opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR; + if ( !(pgmname = strrchr (opt.dirmngr_program, '/'))) + pgmname = opt.dirmngr_program; + else + pgmname++; + if (opt.verbose) - log_info (_("no running dirmngr - starting one\n")); + log_info (_("no running dirmngr - starting `%s'\n"), + opt.dirmngr_program); if (fflush (NULL)) { @@ -180,13 +188,6 @@ return tmperr; } - if (!opt.dirmngr_program || !*opt.dirmngr_program) - opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR; - if ( !(pgmname = strrchr (opt.dirmngr_program, '/'))) - pgmname = opt.dirmngr_program; - else - pgmname++; - argv[0] = pgmname; argv[1] = "--server"; argv[2] = NULL; From cvs at cvs.gnupg.org Tue Feb 21 06:20:09 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Tue Feb 21 05:37:37 2006 Subject: [svn] GnuPG - r4009 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-21 06:20:08 +0100 (Tue, 21 Feb 2006) New Revision: 4009 Modified: trunk/g10/ChangeLog trunk/g10/keyserver.c Log: * keyserver.c (parse_keyserver_uri): Include the scheme in the uri even when we've assumed "hkp" when there was no scheme. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-19 22:09:10 UTC (rev 4008) +++ trunk/g10/ChangeLog 2006-02-21 05:20:08 UTC (rev 4009) @@ -1,3 +1,8 @@ +2006-02-20 David Shaw + + * keyserver.c (parse_keyserver_uri): Include the scheme in the uri + even when we've assumed "hkp" when there was no scheme. + 2006-02-14 Werner Koch * verify.c (verify_signatures): Print warning also for NO_DATA. Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-19 22:09:10 UTC (rev 4008) +++ trunk/g10/keyserver.c 2006-02-21 05:20:08 UTC (rev 4009) @@ -215,8 +215,6 @@ keyserver=xmalloc_clear(sizeof(struct keyserver_spec)); - keyserver->uri=xstrdup(uri); - /* Get the scheme */ for(idx=uri,count=0;*idx && *idx!=':';idx++) @@ -247,11 +245,18 @@ /* Assume HKP if there is no scheme */ assume_hkp=1; keyserver->scheme=xstrdup("hkp"); + + keyserver->uri=xmalloc(strlen(keyserver->scheme)+3+strlen(uri)+1); + strcpy(keyserver->uri,keyserver->scheme); + strcat(keyserver->uri,"://"); + strcat(keyserver->uri,uri); } else { int i; + keyserver->uri=xstrdup(uri); + keyserver->scheme=xmalloc(count+1); /* Force to lowercase */ From cvs at cvs.gnupg.org Tue Feb 21 17:09:13 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Tue Feb 21 16:44:55 2006 Subject: [svn] GnuPG - r4010 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-21 17:09:09 +0100 (Tue, 21 Feb 2006) New Revision: 4010 Modified: trunk/g10/ChangeLog trunk/g10/gpgv.c trunk/g10/keyserver-internal.h trunk/g10/keyserver.c Log: * gpgv.c: Stub keyserver_import_ldap. * keyserver-internal.h, keyserver.c (keyserver_import_ldap): Import using the PGP Universal trick of asking ldap://keys.(maildomain) for the key. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-21 05:20:08 UTC (rev 4009) +++ trunk/g10/ChangeLog 2006-02-21 16:09:09 UTC (rev 4010) @@ -1,3 +1,11 @@ +2006-02-21 David Shaw + + * gpgv.c: Stub keyserver_import_ldap. + + * keyserver-internal.h, keyserver.c (keyserver_import_ldap): + Import using the PGP Universal trick of asking + ldap://keys.(maildomain) for the key. + 2006-02-20 David Shaw * keyserver.c (parse_keyserver_uri): Include the scheme in the uri Modified: trunk/g10/gpgv.c =================================================================== --- trunk/g10/gpgv.c 2006-02-21 05:20:08 UTC (rev 4009) +++ trunk/g10/gpgv.c 2006-02-21 16:09:09 UTC (rev 4010) @@ -289,6 +289,9 @@ int keyserver_import_name(const char *name) { return -1; } +int +keyserver_import_ldap(const char *name) { return -1; } + /* Stub: * No encryption here but mainproc links to these functions. */ Modified: trunk/g10/keyserver-internal.h =================================================================== --- trunk/g10/keyserver-internal.h 2006-02-21 05:20:08 UTC (rev 4009) +++ trunk/g10/keyserver-internal.h 2006-02-21 16:09:09 UTC (rev 4010) @@ -44,5 +44,6 @@ int keyserver_import_cert(const char *name); int keyserver_import_pka(const char *name); int keyserver_import_name(const char *name); +int keyserver_import_ldap(const char *name); #endif /* !_KEYSERVER_INTERNAL_H_ */ Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-21 05:20:08 UTC (rev 4009) +++ trunk/g10/keyserver.c 2006-02-21 16:09:09 UTC (rev 4010) @@ -2016,3 +2016,38 @@ return rc; } + +/* Use the PGP Universal trick of asking ldap://keys.(maildomain) for + the key. */ +int +keyserver_import_ldap(const char *name) +{ + char *domain; + struct keyserver_spec *keyserver; + STRLIST list=NULL; + int rc; + + append_to_strlist(&list,name); + + /* Parse out the domain */ + domain=strrchr(name,'@'); + if(!domain) + return G10ERR_GENERAL; + + domain++; + + keyserver=xmalloc_clear(sizeof(struct keyserver_spec)); + + keyserver->scheme=xstrdup("ldap"); + keyserver->host=xmalloc(5+strlen(domain)+1); + strcpy(keyserver->host,"keys."); + strcat(keyserver->host,domain); + + rc=keyserver_work(KS_GETNAME,list,NULL,0,keyserver); + + free_strlist(list); + + free_keyserver_spec(keyserver); + + return rc; +} From cvs at cvs.gnupg.org Tue Feb 21 17:16:10 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Tue Feb 21 16:51:51 2006 Subject: [svn] GnuPG - r4011 - trunk/keyserver Message-ID: Author: dshaw Date: 2006-02-21 17:16:09 +0100 (Tue, 21 Feb 2006) New Revision: 4011 Modified: trunk/keyserver/ChangeLog trunk/keyserver/curl-shim.c trunk/keyserver/curl-shim.h Log: * curl-shim.h, curl-shim.c (curl_easy_init, curl_easy_setopt, curl_easy_perform): Add CURLOPT_VERBOSE and CURLOPT_STDERR for easier debugging. Modified: trunk/keyserver/ChangeLog =================================================================== --- trunk/keyserver/ChangeLog 2006-02-21 16:09:09 UTC (rev 4010) +++ trunk/keyserver/ChangeLog 2006-02-21 16:16:09 UTC (rev 4011) @@ -1,3 +1,9 @@ +2006-02-21 David Shaw + + * curl-shim.h, curl-shim.c (curl_easy_init, curl_easy_setopt, + curl_easy_perform): Add CURLOPT_VERBOSE and CURLOPT_STDERR for + easier debugging. + 2006-01-16 David Shaw * gpgkeys_hkp.c (send_key): Do not escape the '=' in the HTTP POST Modified: trunk/keyserver/curl-shim.c =================================================================== --- trunk/keyserver/curl-shim.c 2006-02-21 16:09:09 UTC (rev 4010) +++ trunk/keyserver/curl-shim.c 2006-02-21 16:16:09 UTC (rev 4011) @@ -1,7 +1,7 @@ /* curl-shim.c - Implement a small subset of the curl API in terms of * the iobuf HTTP API * - * Copyright (C) 2005 Free Software Foundation, Inc. + * Copyright (C) 2005, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -88,7 +88,13 @@ CURL * curl_easy_init(void) { - return calloc(1,sizeof(CURL)); + CURL *handle; + + handle=calloc(1,sizeof(CURL)); + if(handle) + handle->stderr=stderr; + + return handle; } void @@ -133,6 +139,12 @@ case CURLOPT_FAILONERROR: curl->flags.failonerror=va_arg(ap,unsigned int); break; + case CURLOPT_VERBOSE: + curl->flags.verbose=va_arg(ap,unsigned int); + break; + case CURLOPT_STDERR: + curl->stderr=va_arg(ap,FILE *); + break; default: /* We ignore the huge majority of curl options */ break; @@ -162,6 +174,9 @@ else proxy=getenv(HTTP_PROXY_ENV); + if(curl->flags.verbose) + fprintf(curl->stderr,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null"); + if(curl->flags.post) { rc=http_open(&curl->hd,HTTP_REQ_POST,curl->url,curl->auth,0,proxy); Modified: trunk/keyserver/curl-shim.h =================================================================== --- trunk/keyserver/curl-shim.h 2006-02-21 16:09:09 UTC (rev 4010) +++ trunk/keyserver/curl-shim.h 2006-02-21 16:16:09 UTC (rev 4011) @@ -1,5 +1,5 @@ /* curl-shim.h - * Copyright (C) 2005 Free Software Foundation, Inc. + * Copyright (C) 2005, 2006 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -66,10 +66,12 @@ void *file; char *postfields; unsigned int status; + FILE *stderr; struct { unsigned int post:1; unsigned int failonerror:1; + unsigned int verbose:1; } flags; struct http_context hd; } CURL; From cvs at cvs.gnupg.org Tue Feb 21 23:23:38 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Tue Feb 21 22:59:17 2006 Subject: [svn] GnuPG - r4012 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-21 23:23:35 +0100 (Tue, 21 Feb 2006) New Revision: 4012 Modified: trunk/g10/ChangeLog trunk/g10/getkey.c trunk/g10/gpgv.c trunk/g10/keyserver-internal.h trunk/g10/keyserver.c Log: * getkey.c (get_pubkey_byname): Fix minor security problem with PKA when importing at -r time. The URL in the PKA record may point to a key put in by an attacker. Fix is to use the fingerprint from the PKA record as the recipient. This ensures that the PKA record is followed. * keyserver-internal.h, keyserver.c (keyserver_import_pka): Return the fingerprint we requested. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-21 16:16:09 UTC (rev 4011) +++ trunk/g10/ChangeLog 2006-02-21 22:23:35 UTC (rev 4012) @@ -1,5 +1,14 @@ 2006-02-21 David Shaw + * getkey.c (get_pubkey_byname): Fix minor security problem with + PKA when importing at -r time. The URL in the PKA record may + point to a key put in by an attacker. Fix is to use the + fingerprint from the PKA record as the recipient. This ensures + that the PKA record is followed. + + * keyserver-internal.h, keyserver.c (keyserver_import_pka): Return + the fingerprint we requested. + * gpgv.c: Stub keyserver_import_ldap. * keyserver-internal.h, keyserver.c (keyserver_import_ldap): Modified: trunk/g10/getkey.c =================================================================== --- trunk/g10/getkey.c 2006-02-21 16:16:09 UTC (rev 4011) +++ trunk/g10/getkey.c 2006-02-21 22:23:35 UTC (rev 4012) @@ -938,6 +938,7 @@ && opt.allow_pka_lookup && (opt.keyserver_options.options&KEYSERVER_AUTO_PKA_RETRIEVE)) { + unsigned char fpr[MAX_FINGERPRINT_LEN]; /* If the requested name resembles a valid mailbox and automatic retrieval via PKA records has been enabled, we try to import the key via the URI and try again. */ @@ -945,13 +946,25 @@ tried_pka=1; glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_pka(name); + res=keyserver_import_pka(name,fpr); glo_ctrl.in_auto_key_retrieve--; if(res==0) { + int i; + char fpr_string[2+(MAX_FINGERPRINT_LEN*2)+1]; + log_info(_("Automatically retrieved `%s' via %s\n"), name,"PKA"); + + free_strlist(namelist); + namelist=NULL; + + for(i=0;i Author: dshaw Date: 2006-02-22 03:11:35 +0100 (Wed, 22 Feb 2006) New Revision: 4013 Modified: trunk/keyserver/ChangeLog trunk/keyserver/curl-shim.c trunk/keyserver/curl-shim.h Log: * curl-shim.h, curl-shim.c (curl_easy_init, curl_easy_setopt, curl_easy_perform): Mingw has 'stderr' as a macro? Modified: trunk/keyserver/ChangeLog =================================================================== --- trunk/keyserver/ChangeLog 2006-02-21 22:23:35 UTC (rev 4012) +++ trunk/keyserver/ChangeLog 2006-02-22 02:11:35 UTC (rev 4013) @@ -1,6 +1,9 @@ 2006-02-21 David Shaw * curl-shim.h, curl-shim.c (curl_easy_init, curl_easy_setopt, + curl_easy_perform): Mingw has 'stderr' as a macro? + + * curl-shim.h, curl-shim.c (curl_easy_init, curl_easy_setopt, curl_easy_perform): Add CURLOPT_VERBOSE and CURLOPT_STDERR for easier debugging. Modified: trunk/keyserver/curl-shim.c =================================================================== --- trunk/keyserver/curl-shim.c 2006-02-21 22:23:35 UTC (rev 4012) +++ trunk/keyserver/curl-shim.c 2006-02-22 02:11:35 UTC (rev 4013) @@ -92,7 +92,7 @@ handle=calloc(1,sizeof(CURL)); if(handle) - handle->stderr=stderr; + handle->errors=stderr; return handle; } @@ -143,7 +143,7 @@ curl->flags.verbose=va_arg(ap,unsigned int); break; case CURLOPT_STDERR: - curl->stderr=va_arg(ap,FILE *); + curl->errors=va_arg(ap,FILE *); break; default: /* We ignore the huge majority of curl options */ @@ -175,7 +175,7 @@ proxy=getenv(HTTP_PROXY_ENV); if(curl->flags.verbose) - fprintf(curl->stderr,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null"); + fprintf(curl->errors,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null"); if(curl->flags.post) { Modified: trunk/keyserver/curl-shim.h =================================================================== --- trunk/keyserver/curl-shim.h 2006-02-21 22:23:35 UTC (rev 4012) +++ trunk/keyserver/curl-shim.h 2006-02-22 02:11:35 UTC (rev 4013) @@ -66,7 +66,7 @@ void *file; char *postfields; unsigned int status; - FILE *stderr; + FILE *errors; struct { unsigned int post:1; From cvs at cvs.gnupg.org Wed Feb 22 04:49:50 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Wed Feb 22 04:25:29 2006 Subject: [svn] GnuPG - r4014 - trunk/keyserver Message-ID: Author: dshaw Date: 2006-02-22 04:49:49 +0100 (Wed, 22 Feb 2006) New Revision: 4014 Modified: trunk/keyserver/ChangeLog trunk/keyserver/gpgkeys_ldap.c Log: * gpgkeys_ldap.c (main): Add binddn and bindpw so users can pass credentials to a remote LDAP server. Modified: trunk/keyserver/ChangeLog =================================================================== --- trunk/keyserver/ChangeLog 2006-02-22 02:11:35 UTC (rev 4013) +++ trunk/keyserver/ChangeLog 2006-02-22 03:49:49 UTC (rev 4014) @@ -1,5 +1,8 @@ 2006-02-21 David Shaw + * gpgkeys_ldap.c (main): Add binddn and bindpw so users can pass + credentials to a remote LDAP server. + * curl-shim.h, curl-shim.c (curl_easy_init, curl_easy_setopt, curl_easy_perform): Mingw has 'stderr' as a macro? Modified: trunk/keyserver/gpgkeys_ldap.c =================================================================== --- trunk/keyserver/gpgkeys_ldap.c 2006-02-22 02:11:35 UTC (rev 4013) +++ trunk/keyserver/gpgkeys_ldap.c 2006-02-22 03:49:49 UTC (rev 4014) @@ -1714,7 +1714,7 @@ main(int argc,char *argv[]) { int port=0,arg,err,ret=KEYSERVER_INTERNAL_ERROR; - char line[MAX_LINE]; + char line[MAX_LINE],*binddn=NULL,*bindpw=NULL; int failed=0,use_ssl=0,use_tls=0,bound=0; struct keylist *keylist=NULL,*keyptr=NULL; @@ -1850,7 +1850,51 @@ real_ldap=1; } } + else if(strncasecmp(start,"binddn",6)==0) + { + if(no) + { + free(binddn); + binddn=NULL; + } + else if(start[6]=='=') + { + free(binddn); + binddn=strdup(&start[7]); + if(!binddn) + { + fprintf(console,"gpgkeys: out of memory while creating " + "bind DN\n"); + ret=KEYSERVER_NO_MEMORY; + goto fail; + } + real_ldap=1; + } + } + else if(strncasecmp(start,"bindpw",6)==0) + { + if(no) + { + free(bindpw); + bindpw=NULL; + } + else if(start[6]=='=') + { + free(bindpw); + bindpw=strdup(&start[7]); + if(!bindpw) + { + fprintf(console,"gpgkeys: out of memory while creating " + "bind password\n"); + ret=KEYSERVER_NO_MEMORY; + goto fail; + } + + real_ldap=1; + } + } + continue; } } @@ -2098,25 +2142,40 @@ } } -#if 0 - /* The LDAP keyserver doesn't require this, but it might be useful - if someone stores keys on a V2 LDAP server somewhere. (V3 - doesn't require a bind). Leave this out for now since it is not - clear if anyone's server we're likely to use really cares, plus - there are some servers that don't allow it. */ + /* By default we don't bind as there is usually no need to. For + cases where the server needs some authentication, the user can + use binddn and bindpw for auth. */ - err=ldap_simple_bind_s(ldap,NULL,NULL); - if(err!=0) + if(binddn) { - fprintf(console,"gpgkeys: internal LDAP bind error: %s\n", - ldap_err2string(err)); - fail_all(keylist,ldap_err_to_gpg_err(err)); - goto fail; - } - else - bound=1; +#ifdef HAVE_LDAP_SET_OPTION + int ver=LDAP_VERSION3; + + err=ldap_set_option(ldap,LDAP_OPT_PROTOCOL_VERSION,&ver); + if(err!=LDAP_SUCCESS) + { + fprintf(console,"gpgkeys: unable to go to LDAP 3: %s\n", + ldap_err2string(err)); + fail_all(keylist,ldap_err_to_gpg_err(err)); + goto fail; + } #endif + if(opt->verbose>2) + fprintf(console,"gpgkeys: LDAP bind to %s, pw %s\n",binddn, + bindpw?">not shown<":">none<"); + err=ldap_simple_bind_s(ldap,binddn,bindpw); + if(err!=LDAP_SUCCESS) + { + fprintf(console,"gpgkeys: internal LDAP bind error: %s\n", + ldap_err2string(err)); + fail_all(keylist,ldap_err_to_gpg_err(err)); + goto fail; + } + else + bound=1; + } + if(opt->action==KS_GET) { keyptr=keylist; From cvs at cvs.gnupg.org Wed Feb 22 05:19:22 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Wed Feb 22 04:55:06 2006 Subject: [svn] GnuPG - r4015 - trunk/keyserver Message-ID: Author: dshaw Date: 2006-02-22 05:19:21 +0100 (Wed, 22 Feb 2006) New Revision: 4015 Modified: trunk/keyserver/ChangeLog trunk/keyserver/gpgkeys_ldap.c Log: * gpgkeys_ldap.c (make_one_attr, build_attrs, send_key): Don't allow duplicate attributes as OpenLDAP is now enforcing this. Modified: trunk/keyserver/ChangeLog =================================================================== --- trunk/keyserver/ChangeLog 2006-02-22 03:49:49 UTC (rev 4014) +++ trunk/keyserver/ChangeLog 2006-02-22 04:19:21 UTC (rev 4015) @@ -1,5 +1,8 @@ 2006-02-21 David Shaw + * gpgkeys_ldap.c (make_one_attr, build_attrs, send_key): Don't + allow duplicate attributes as OpenLDAP is now enforcing this. + * gpgkeys_ldap.c (main): Add binddn and bindpw so users can pass credentials to a remote LDAP server. Modified: trunk/keyserver/gpgkeys_ldap.c =================================================================== --- trunk/keyserver/gpgkeys_ldap.c 2006-02-22 03:49:49 UTC (rev 4014) +++ trunk/keyserver/gpgkeys_ldap.c 2006-02-22 04:19:21 UTC (rev 4015) @@ -1,5 +1,5 @@ /* gpgkeys_ldap.c - talk to a LDAP keyserver - * Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -248,7 +248,7 @@ the attribute in question exists or not. */ static int -make_one_attr(LDAPMod ***modlist,int unique,char *attr,const char *value) +make_one_attr(LDAPMod ***modlist,char *attr,const char *value) { LDAPMod **m; int nummods=0; @@ -270,7 +270,8 @@ if(ptr) for(ptr=(*m)->mod_values;*ptr;ptr++) { - if(unique && strcmp(*ptr,value)==0) + /* Duplicate value */ + if(strcmp(*ptr,value)==0) return 1; numvalues++; } @@ -363,8 +364,8 @@ if(strlen(tok)==16) { - make_one_attr(modlist,0,"pgpCertID",tok); - make_one_attr(modlist,0,"pgpKeyID",&tok[8]); + make_one_attr(modlist,"pgpCertID",tok); + make_one_attr(modlist,"pgpKeyID",&tok[8]); } else return; @@ -376,11 +377,11 @@ switch(atoi(tok)) { case 1: - make_one_attr(modlist,0,"pgpKeyType","RSA"); + make_one_attr(modlist,"pgpKeyType","RSA"); break; case 17: - make_one_attr(modlist,0,"pgpKeyType","DSS/DH"); + make_one_attr(modlist,"pgpKeyType","DSS/DH"); break; } @@ -398,7 +399,7 @@ if(val<99999 && val>0) { sprintf(padded,"%05u",atoi(tok)); - make_one_attr(modlist,0,"pgpKeySize",padded); + make_one_attr(modlist,"pgpKeySize",padded); } } @@ -411,7 +412,7 @@ char *stamp=epoch2ldaptime(atoi(tok)); if(stamp) { - make_one_attr(modlist,0,"pgpKeyCreateTime",stamp); + make_one_attr(modlist,"pgpKeyCreateTime",stamp); free(stamp); } } @@ -425,7 +426,7 @@ char *stamp=epoch2ldaptime(atoi(tok)); if(stamp) { - make_one_attr(modlist,0,"pgpKeyExpireTime",stamp); + make_one_attr(modlist,"pgpKeyExpireTime",stamp); free(stamp); } } @@ -455,8 +456,8 @@ "(&(pgpUserID=*isabella*)(pgpDisabled=0))" */ - make_one_attr(modlist,0,"pgpDisabled",disabled?"1":"0"); - make_one_attr(modlist,0,"pgpRevoked",revoked?"1":"0"); + make_one_attr(modlist,"pgpDisabled",disabled?"1":"0"); + make_one_attr(modlist,"pgpRevoked",revoked?"1":"0"); } else if(ascii_strcasecmp("sub",record)==0) { @@ -467,7 +468,7 @@ return; if(strlen(tok)==16) - make_one_attr(modlist,0,"pgpSubKeyID",tok); + make_one_attr(modlist,"pgpSubKeyID",tok); else return; @@ -489,7 +490,7 @@ if(val<99999 && val>0) { sprintf(padded,"%05u",atoi(tok)); - make_one_attr(modlist,0,"pgpKeySize",padded); + make_one_attr(modlist,"pgpKeySize",padded); } } @@ -531,7 +532,7 @@ /* We don't care about the other info provided in the uid: line since the LDAP schema doesn't need it. */ - make_one_attr(modlist,0,"pgpUserID",userid); + make_one_attr(modlist,"pgpUserID",userid); } else if(ascii_strcasecmp("sig",record)==0) { @@ -541,7 +542,7 @@ return; if(strlen(tok)==16) - make_one_attr(modlist,1,"pgpSignerID",tok); + make_one_attr(modlist,"pgpSignerID",tok); } } @@ -590,17 +591,17 @@ /* Start by nulling out all attributes. We try and do a modify operation first, so this ensures that we don't leave old attributes lying around. */ - make_one_attr(&modlist,0,"pgpDisabled",NULL); - make_one_attr(&modlist,0,"pgpKeyID",NULL); - make_one_attr(&modlist,0,"pgpKeyType",NULL); - make_one_attr(&modlist,0,"pgpUserID",NULL); - make_one_attr(&modlist,0,"pgpKeyCreateTime",NULL); - make_one_attr(&modlist,0,"pgpSignerID",NULL); - make_one_attr(&modlist,0,"pgpRevoked",NULL); - make_one_attr(&modlist,0,"pgpSubKeyID",NULL); - make_one_attr(&modlist,0,"pgpKeySize",NULL); - make_one_attr(&modlist,0,"pgpKeyExpireTime",NULL); - make_one_attr(&modlist,0,"pgpCertID",NULL); + make_one_attr(&modlist,"pgpDisabled",NULL); + make_one_attr(&modlist,"pgpKeyID",NULL); + make_one_attr(&modlist,"pgpKeyType",NULL); + make_one_attr(&modlist,"pgpUserID",NULL); + make_one_attr(&modlist,"pgpKeyCreateTime",NULL); + make_one_attr(&modlist,"pgpSignerID",NULL); + make_one_attr(&modlist,"pgpRevoked",NULL); + make_one_attr(&modlist,"pgpSubKeyID",NULL); + make_one_attr(&modlist,"pgpKeySize",NULL); + make_one_attr(&modlist,"pgpKeyExpireTime",NULL); + make_one_attr(&modlist,"pgpCertID",NULL); /* Assemble the INFO stuff into LDAP attributes */ @@ -719,8 +720,8 @@ goto fail; } - make_one_attr(&addlist,0,"objectClass","pgpKeyInfo"); - make_one_attr(&addlist,0,"pgpKey",key); + make_one_attr(&addlist,"objectClass","pgpKeyInfo"); + make_one_attr(&addlist,"pgpKey",key); /* Now append addlist onto modlist */ if(!join_two_modlists(&modlist,addlist)) From cvs at cvs.gnupg.org Wed Feb 22 12:02:51 2006 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed Feb 22 11:38:28 2006 Subject: [svn] gpgme - r1154 - in trunk: . gpgme Message-ID: Author: marcus Date: 2006-02-22 12:02:50 +0100 (Wed, 22 Feb 2006) New Revision: 1154 Modified: trunk/TODO trunk/gpgme/ChangeLog trunk/gpgme/keylist.c trunk/gpgme/rungpg.c Log: 2006-02-22 Marcus Brinkmann * rungpg.c (read_colon_line): Invoke colon preprocess handler if it is set. (colon_preprocessor_t): New type. (struct engine_gpg): New member colon.preprocess_fnc. (gpg_keylist_preprocess): New function. * keylist.c (keylist_colon_handler): Allow short key IDs. Modified: trunk/TODO =================================================================== --- trunk/TODO 2006-02-15 13:30:08 UTC (rev 1153) +++ trunk/TODO 2006-02-22 11:02:50 UTC (rev 1154) @@ -5,10 +5,7 @@ The test is currently disabled there and in gpg/t-import. ** When gpg supports it, write binary subpackets directly, and parse SUBPACKET status lines. -** External key listing for OpenPGP. - This probably requires changes at gpg. - * ABI's to break: ** gpgme_edit_cb_t: Add "processed" return argument (see edit.c::command_handler). @@ -81,7 +78,7 @@ release everything properly at a reset and at an error. Think hard about where to guarantee what (ie, what happens if start fails, are the fds unregistered immediately - i think so?) -** Optimize the case where a data object has an underlying fd we can pass +** Optimize the case where a data object has 0an underlying fd we can pass directly to the engine. This will be automatic with socket I/O and descriptor passing. ** Move code common to all engines up from gpg to engine. Modified: trunk/gpgme/ChangeLog =================================================================== --- trunk/gpgme/ChangeLog 2006-02-15 13:30:08 UTC (rev 1153) +++ trunk/gpgme/ChangeLog 2006-02-22 11:02:50 UTC (rev 1154) @@ -1,3 +1,12 @@ +2006-02-22 Marcus Brinkmann + + * rungpg.c (read_colon_line): Invoke colon preprocess handler if + it is set. + (colon_preprocessor_t): New type. + (struct engine_gpg): New member colon.preprocess_fnc. + (gpg_keylist_preprocess): New function. + * keylist.c (keylist_colon_handler): Allow short key IDs. + 2006-02-15 Marcus Brinkmann * w32-io.c (create_writer): Make C->have_data a manually resetted Modified: trunk/gpgme/keylist.c =================================================================== --- trunk/gpgme/keylist.c 2006-02-15 13:30:08 UTC (rev 1153) +++ trunk/gpgme/keylist.c 2006-02-22 11:02:50 UTC (rev 1154) @@ -176,7 +176,8 @@ case 'd': /* Note that gpg 1.3 won't print that anymore but only uses - the capabilities field. */ + the capabilities field. However, it is still used for + external key listings. */ key->disabled = 1; break; @@ -493,8 +494,9 @@ subkey->pubkey_algo = i; } - /* Field 5 has the long keyid. */ - if (fields >= 5 && strlen (field[4]) == DIM(subkey->_keyid) - 1) + /* Field 5 has the long keyid. Allow short key IDs for the + output of an external keyserver listing. */ + if (fields >= 5 && strlen (field[4]) <= DIM(subkey->_keyid) - 1) strcpy (subkey->_keyid, field[4]); /* Field 6 has the timestamp (seconds). */ Modified: trunk/gpgme/rungpg.c =================================================================== --- trunk/gpgme/rungpg.c 2006-02-15 13:30:08 UTC (rev 1153) +++ trunk/gpgme/rungpg.c 2006-02-22 11:02:50 UTC (rev 1154) @@ -65,6 +65,8 @@ }; +typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline); + struct engine_gpg { char *file_name; @@ -95,6 +97,7 @@ engine_colon_line_handler_t fnc; /* this indicate use of this structrue */ void *fnc_value; void *tag; + colon_preprocessor_t preprocess_fnc; } colon; char **argv; @@ -1013,14 +1016,27 @@ { /* (we require that the last line is terminated by a LF) and we skip empty lines. Note: we use UTF8 encoding - and escaping of special characters We require at + and escaping of special characters. We require at least one colon to cope with some other printed information. */ *p = 0; if (*buffer && strchr (buffer, ':')) { + char *line = NULL; + + if (gpg->colon.preprocess_fnc) + { + gpgme_error_t err; + + err = gpg->colon.preprocess_fnc (buffer, &line); + if (err) + return err; + } + assert (gpg->colon.fnc); - gpg->colon.fnc (gpg->colon.fnc_value, buffer); + gpg->colon.fnc (gpg->colon.fnc_value, line ? line : buffer); + if (line) + free (line); } /* To reuse the buffer for the next line we have to @@ -1613,13 +1629,107 @@ } +/* The output for external keylistings in GnuPG is different from all + the other key listings. We catch this here with a special + preprocessor that reformats the colon handler lines. */ static gpgme_error_t +gpg_keylist_preprocess (char *line, char **r_line) +{ + enum + { + RT_NONE, RT_INFO, RT_PUB, RT_UID + } + rectype = RT_NONE; +#define NR_FIELDS 16 + char *field[NR_FIELDS]; + int fields = 0; + + *r_line = NULL; + + while (line && fields < NR_FIELDS) + { + field[fields++] = line; + line = strchr (line, ':'); + if (line) + *(line++) = '\0'; + } + + if (!strcmp (field[0], "info")) + rectype = RT_INFO; + else if (!strcmp (field[0], "pub")) + rectype = RT_PUB; + else if (!strcmp (field[0], "uid")) + rectype = RT_UID; + else + rectype = RT_NONE; + + switch (rectype) + { + case RT_INFO: + /* FIXME: Eventually, check the version number at least. */ + return 0; + + case RT_PUB: + if (fields < 7) + return 0; + + /* The format is: + + pub:::::: + + as defined in 5.2. Machine Readable Indexes of the OpenPGP + HTTP Keyserver Protocol (draft). + + We want: + pub:o::::::::::::: + */ + + if (asprintf (r_line, "pub:o%s:%s:%s:%s:%s:%s::::::::", + field[6], field[3], field[2], field[1], + field[4], field[5]) < 0) + return gpg_error_from_errno (errno); + return 0; + + case RT_UID: + /* The format is: + + uid:::: + + as defined in 5.2. Machine Readable Indexes of the OpenPGP + HTTP Keyserver Protocol (draft). + + We want: + uid:o::::::::: + */ + + if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:", + field[4], field[2], field[3], field[1]) < 0) + return gpg_error_from_errno (errno); + return 0; + + case RT_NONE: + /* Unknown record. */ + break; + } + return 0; + +} + + +static gpgme_error_t gpg_keylist (void *engine, const char *pattern, int secret_only, gpgme_keylist_mode_t mode) { engine_gpg_t gpg = engine; gpgme_error_t err; + if (mode & GPGME_KEYLIST_MODE_EXTERN) + { + if ((mode & GPGME_KEYLIST_MODE_LOCAL) + || secret_only) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + } + err = add_arg (gpg, "--with-colons"); if (!err) err = add_arg (gpg, "--fixed-list-mode"); @@ -1635,10 +1745,20 @@ err = add_arg (gpg, "show-sig-subpackets=\"20,26\""); } if (!err) - err = add_arg (gpg, secret_only ? "--list-secret-keys" - : ((mode & GPGME_KEYLIST_MODE_SIGS) - ? "--check-sigs" : "--list-keys")); - + { + if (mode & GPGME_KEYLIST_MODE_EXTERN) + { + err = add_arg (gpg, "--search-keys"); + gpg->colon.preprocess_fnc = gpg_keylist_preprocess; + } + else + { + err = add_arg (gpg, secret_only ? "--list-secret-keys" + : ((mode & GPGME_KEYLIST_MODE_SIGS) + ? "--check-sigs" : "--list-keys")); + } + } + /* Tell the gpg object about the data. */ if (!err) err = add_arg (gpg, "--"); From cvs at cvs.gnupg.org Wed Feb 22 12:44:16 2006 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed Feb 22 12:19:52 2006 Subject: [svn] gpgme - r1155 - trunk/gpgme Message-ID: Author: marcus Date: 2006-02-22 12:44:16 +0100 (Wed, 22 Feb 2006) New Revision: 1155 Modified: trunk/gpgme/ChangeLog trunk/gpgme/engine.c Log: 2006-02-22 Marcus Brinkmann * engine.c (gpgme_engine_check_version): Reimplemented to allow checking the version correctly even after changing the engine information. Bug reported by St?\195?\169phane Corth?\195?\169sy. Modified: trunk/gpgme/ChangeLog =================================================================== --- trunk/gpgme/ChangeLog 2006-02-22 11:02:50 UTC (rev 1154) +++ trunk/gpgme/ChangeLog 2006-02-22 11:44:16 UTC (rev 1155) @@ -1,5 +1,9 @@ 2006-02-22 Marcus Brinkmann + * engine.c (gpgme_engine_check_version): Reimplemented to allow + checking the version correctly even after changing the engine + information. Bug reported by Stéphane Corthésy. + * rungpg.c (read_colon_line): Invoke colon preprocess handler if it is set. (colon_preprocessor_t): New type. Modified: trunk/gpgme/engine.c =================================================================== --- trunk/gpgme/engine.c 2006-02-22 11:02:50 UTC (rev 1154) +++ trunk/gpgme/engine.c 2006-02-22 11:44:16 UTC (rev 1155) @@ -106,14 +106,33 @@ gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto) { + gpgme_error_t err; + gpgme_engine_info_t info; int result; - char *engine_version = engine_get_version (proto, NULL); - result = _gpgme_compare_versions (engine_version, - engine_get_req_version (proto)); - if (engine_version) - free (engine_version); + LOCK (engine_info_lock); + info = engine_info; + if (!info) + { + /* Make sure it is initialized. */ + UNLOCK (engine_info_lock); + err = gpgme_get_engine_info (&info); + if (err) + return err; + LOCK (engine_info_lock); + } + + while (info && info->protocol != proto) + info = info->next; + + if (!info) + result = 0; + else + result = _gpgme_compare_versions (info->version, + info->req_version); + + UNLOCK (engine_info_lock); return result ? 0 : gpg_error (GPG_ERR_INV_ENGINE); } From cvs at cvs.gnupg.org Wed Feb 22 12:58:33 2006 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed Feb 22 12:34:13 2006 Subject: [svn] gpgme - r1156 - trunk/m4 Message-ID: Author: marcus Date: 2006-02-22 12:58:33 +0100 (Wed, 22 Feb 2006) New Revision: 1156 Modified: trunk/m4/ChangeLog trunk/m4/pth.m4 Log: 2006-02-22 Marcus Brinkmann * pth.m4: Fix code generation (required for Max OS X). Submitted by Emanuele Giaquinta . Modified: trunk/m4/ChangeLog =================================================================== --- trunk/m4/ChangeLog 2006-02-22 11:44:16 UTC (rev 1155) +++ trunk/m4/ChangeLog 2006-02-22 11:58:33 UTC (rev 1156) @@ -1,3 +1,8 @@ +2006-02-22 Marcus Brinkmann + + * pth.m4: Fix code generation (required for Max OS X). + Submitted by Emanuele Giaquinta . + 2005-11-17 Marcus Brinkmann * glib-2.0.m4: New file. Modified: trunk/m4/pth.m4 =================================================================== --- trunk/m4/pth.m4 2006-02-22 11:44:16 UTC (rev 1155) +++ trunk/m4/pth.m4 2006-02-22 11:58:33 UTC (rev 1156) @@ -285,8 +285,6 @@ #include ]) define(_code2, [dnl - int main(int argc, char *argv[]) - { FILE *fp; if (!(fp = fopen("conftestval", "w"))) exit(1); @@ -299,7 +297,6 @@ fprintf(fp, "yes"); fclose(fp); exit(0); - } ]) _AC_PTH_VERBOSE([+ Performing Sanity Checks:]) _AC_PTH_VERBOSE([ o pre-processor test]) @@ -329,7 +326,7 @@ See config.log for possibly more details.]) fi _AC_PTH_VERBOSE([ o run-time check]) - AC_TRY_RUN(_code1 _code2, _ok=`cat conftestval`, _ok=no, _ok=no) + AC_TRY_RUN(AC_LANG_PROGRAM(_code1, _code2), _ok=`cat conftestval`, _ok=no, _ok=no) if test ".$_ok" != .yes; then if test ".$_ok" = .no; then _AC_PTH_ERROR([dnl From cvs at cvs.gnupg.org Wed Feb 22 13:01:27 2006 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed Feb 22 12:37:02 2006 Subject: [svn] gpgme - r1157 - trunk/gpgme Message-ID: Author: marcus Date: 2006-02-22 13:01:27 +0100 (Wed, 22 Feb 2006) New Revision: 1157 Modified: trunk/gpgme/engine.c trunk/gpgme/keylist.c trunk/gpgme/rungpg.c Log: Fix copyright year. Modified: trunk/gpgme/engine.c =================================================================== --- trunk/gpgme/engine.c 2006-02-22 11:58:33 UTC (rev 1156) +++ trunk/gpgme/engine.c 2006-02-22 12:01:27 UTC (rev 1157) @@ -1,6 +1,6 @@ /* engine.c - GPGME engine support. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2006 g10 Code GmbH This file is part of GPGME. Modified: trunk/gpgme/keylist.c =================================================================== --- trunk/gpgme/keylist.c 2006-02-22 11:58:33 UTC (rev 1156) +++ trunk/gpgme/keylist.c 2006-02-22 12:01:27 UTC (rev 1157) @@ -1,6 +1,6 @@ /* keylist.c - Listing keys. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2006 g10 Code GmbH This file is part of GPGME. Modified: trunk/gpgme/rungpg.c =================================================================== --- trunk/gpgme/rungpg.c 2006-02-22 11:58:33 UTC (rev 1156) +++ trunk/gpgme/rungpg.c 2006-02-22 12:01:27 UTC (rev 1157) @@ -1,6 +1,6 @@ /* rungpg.c - Gpg Engine. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 g10 Code GmbH This file is part of GPGME. From cvs at cvs.gnupg.org Wed Feb 22 13:03:34 2006 From: cvs at cvs.gnupg.org (svn author marcus) Date: Wed Feb 22 12:39:09 2006 Subject: [svn] gpgme - r1158 - trunk Message-ID: Author: marcus Date: 2006-02-22 13:03:33 +0100 (Wed, 22 Feb 2006) New Revision: 1158 Modified: trunk/ChangeLog trunk/NEWS trunk/configure.ac Log: 2006-02-22 Marcus Brinkmann Released 1.1.1. * configure.ac (LIBGPGME_LT_CURRENT, LIBGPGME_LT_AGE): Bump for release. (LIBGPGME_LT_REVISION): Reset to 0 for release. Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2006-02-22 12:01:27 UTC (rev 1157) +++ trunk/ChangeLog 2006-02-22 12:03:33 UTC (rev 1158) @@ -1,3 +1,11 @@ +2006-02-22 Marcus Brinkmann + + Released 1.1.1. + + * configure.ac (LIBGPGME_LT_CURRENT, LIBGPGME_LT_AGE): Bump for + release. + (LIBGPGME_LT_REVISION): Reset to 0 for release. + 2006-01-05 Werner Koch * configure.ac: Test for inline feature. Modified: trunk/NEWS =================================================================== --- trunk/NEWS 2006-02-22 12:01:27 UTC (rev 1157) +++ trunk/NEWS 2006-02-22 12:03:33 UTC (rev 1158) @@ -1,4 +1,4 @@ -Noteworthy changes in version 1.1.1 (unreleased) +Noteworthy changes in version 1.1.1 (2006-02-22) ------------------------------------------------ * Fixed a bug in that the fingerprints of subkeys are not available. Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2006-02-22 12:01:27 UTC (rev 1157) +++ trunk/configure.ac 2006-02-22 12:03:33 UTC (rev 1158) @@ -1,6 +1,6 @@ # configure.ac for GPGME # Copyright (C) 2000 Werner Koch (dd9jn) -# Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH +# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 g10 Code GmbH # # This file is part of GPGME. # @@ -37,7 +37,7 @@ # the configure script, so that a proper revision number for all files # is available when running a "make distcheck". m4_define(my_version, [1.1.1]) -m4_define(my_iscvs, yes) +#m4_define(my_iscvs, yes) AC_INIT([gpgme], my_version[]m4_ifdef([my_iscvs], [-cvs[]m4_translit( [$Revision$],[Ra-z $:])]), [bug-gpgme@gnupg.org]) @@ -48,10 +48,10 @@ # (Interfaces added: AGE++) # (Interfaces removed/changed: AGE=0) # -LIBGPGME_LT_CURRENT=16 +LIBGPGME_LT_CURRENT=17 # Subtract 2 from this value if you want to make the LFS transition an # ABI break. [Note to self: Remove this comment with the next regular break.] -LIBGPGME_LT_AGE=5 +LIBGPGME_LT_AGE=7 LIBGPGME_LT_REVISION=0 # If the API is changed in an incompatible way: increment the next counter. From cvs at cvs.gnupg.org Wed Feb 22 20:06:26 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Wed Feb 22 19:42:00 2006 Subject: [svn] GnuPG - r4016 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-22 20:06:23 +0100 (Wed, 22 Feb 2006) New Revision: 4016 Modified: trunk/g10/ChangeLog trunk/g10/getkey.c trunk/g10/gpg.c trunk/g10/keydb.h trunk/g10/options.h Log: * options.h, keydb.h, g10.c (main), getkey.c (parse_auto_key_locate): Parse a list of key access methods. (get_pubkey_byname): Walk the list here to try and retrieve keys we don't have locally. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-22 04:19:21 UTC (rev 4015) +++ trunk/g10/ChangeLog 2006-02-22 19:06:23 UTC (rev 4016) @@ -1,3 +1,10 @@ +2006-02-22 David Shaw + + * options.h, keydb.h, g10.c (main), getkey.c + (parse_auto_key_locate): Parse a list of key access methods. + (get_pubkey_byname): Walk the list here to try and retrieve keys + we don't have locally. + 2006-02-21 David Shaw * getkey.c (get_pubkey_byname): Fix minor security problem with Modified: trunk/g10/getkey.c =================================================================== --- trunk/g10/getkey.c 2006-02-22 04:19:21 UTC (rev 4015) +++ trunk/g10/getkey.c 2006-02-22 19:06:23 UTC (rev 4016) @@ -905,91 +905,94 @@ KEYDB_HANDLE *ret_kdbhd, int include_unusable ) { int rc; - int tried_cert=0, tried_pka=0, tried_ks=0; STRLIST namelist = NULL; add_to_strlist( &namelist, name ); - retry: + rc = key_byname( NULL, namelist, pk, NULL, 0, include_unusable, ret_keyblock, ret_kdbhd); + /* If the requested name resembles a valid mailbox and automatic + retrieval has been enabled, we try to import the key. */ + if (rc == G10ERR_NO_PUBKEY && is_valid_mailbox(name)) { int res; + struct akl *akl; - if(!tried_cert - && (opt.keyserver_options.options&KEYSERVER_AUTO_CERT_RETRIEVE)) + for(akl=opt.auto_key_locate;akl;akl=akl->next) { - tried_cert=1; - - glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_cert(name); - glo_ctrl.in_auto_key_retrieve--; - - if(res==0) + switch(akl->type) { - log_info(_("Automatically retrieved `%s' via %s\n"), - name,"DNS CERT"); - goto retry; - } - } + case AKL_CERT: + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_cert(name); + glo_ctrl.in_auto_key_retrieve--; - if(!tried_pka - && opt.allow_pka_lookup - && (opt.keyserver_options.options&KEYSERVER_AUTO_PKA_RETRIEVE)) - { - unsigned char fpr[MAX_FINGERPRINT_LEN]; - /* If the requested name resembles a valid mailbox and - automatic retrieval via PKA records has been enabled, we - try to import the key via the URI and try again. */ + if(res==0) + log_info(_("Automatically retrieved `%s' via %s\n"), + name,"DNS CERT"); + break; - tried_pka=1; + case AKL_PKA: + { + unsigned char fpr[MAX_FINGERPRINT_LEN]; - glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_pka(name,fpr); - glo_ctrl.in_auto_key_retrieve--; + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_pka(name,fpr); + glo_ctrl.in_auto_key_retrieve--; - if(res==0) - { - int i; - char fpr_string[2+(MAX_FINGERPRINT_LEN*2)+1]; + if(res==0) + { + int i; + char fpr_string[MAX_FINGERPRINT_LEN*2+1]; - log_info(_("Automatically retrieved `%s' via %s\n"), - name,"PKA"); + log_info(_("Automatically retrieved `%s' via %s\n"), + name,"PKA"); - free_strlist(namelist); - namelist=NULL; + free_strlist(namelist); + namelist=NULL; - for(i=0;iuri); - goto retry; + if(res==0) + log_info(_("Automatically retrieved `%s' via %s\n"), + name,opt.keyserver->uri); + } + break; } + + rc = key_byname( NULL, namelist, pk, NULL, 0, + include_unusable, ret_keyblock, ret_kdbhd); + if(rc!=G10ERR_NO_PUBKEY) + break; } } @@ -2875,3 +2878,48 @@ { return ctx->kr_handle; } + +int +parse_auto_key_locate(char *options) +{ + char *tok; + + while((tok=optsep(&options))) + { + struct akl *akl,*last; + + if(tok[0]=='\0') + continue; + + akl=xmalloc_clear(sizeof(*akl)); + + if(ascii_strcasecmp(tok,"cert")==0) + akl->type=AKL_CERT; + else if(ascii_strcasecmp(tok,"pka")==0) + akl->type=AKL_PKA; + else if(ascii_strcasecmp(tok,"ldap")==0) + akl->type=AKL_LDAP; + else if(ascii_strcasecmp(tok,"keyserver")==0) + akl->type=AKL_KEYSERVER; + else + { + xfree(akl); + return 0; + } + + /* We must maintain the order the user gave us */ + for(last=opt.auto_key_locate;last && last->next;last=last->next) + { + /* Check for duplicates */ + if(last && last->type==akl->type) + return 0; + } + + if(last) + last->next=akl; + else + opt.auto_key_locate=akl; + } + + return 1; +} Modified: trunk/g10/gpg.c =================================================================== --- trunk/g10/gpg.c 2006-02-22 04:19:21 UTC (rev 4015) +++ trunk/g10/gpg.c 2006-02-22 19:06:23 UTC (rev 4016) @@ -354,14 +354,13 @@ oKeyidFormat, oExitOnStatusWriteError, oLimitCardInsertTries, - oReaderPort, octapiDriver, opcscDriver, oDisableCCID, - oRequireBacksigs, oNoRequireBacksigs, + oAutoKeyLocate, oNoop }; @@ -707,6 +706,7 @@ { oRecipient, "user", 2, "@" }, { oRequireBacksigs, "require-backsigs", 0, "@"}, { oNoRequireBacksigs, "no-require-backsigs", 0, "@"}, + { oAutoKeyLocate, "auto-key-locate", 2, "@"}, {0,NULL,0,NULL} }; @@ -2645,6 +2645,17 @@ case oRequireBacksigs: opt.require_backsigs=1; break; case oNoRequireBacksigs: opt.require_backsigs=0; break; + case oAutoKeyLocate: + if(!parse_auto_key_locate(pargs.r.ret_str)) + { + if(configname) + log_error(_("%s:%d: invalid auto-key-locate list\n"), + configname,configlineno); + else + log_error(_("invalid auto-key-locate list\n")); + } + break; + case oNoop: break; default : pargs.err = configfp? 1:2; break; Modified: trunk/g10/keydb.h =================================================================== --- trunk/g10/keydb.h 2006-02-22 04:19:21 UTC (rev 4015) +++ trunk/g10/keydb.h 2006-02-22 19:06:23 UTC (rev 4016) @@ -258,6 +258,7 @@ char*get_user_id( u32 *keyid, size_t *rn ); char*get_user_id_native( u32 *keyid ); KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx); +int parse_auto_key_locate(char *options); /*-- keyid.c --*/ int pubkey_letter( int algo ); Modified: trunk/g10/options.h =================================================================== --- trunk/g10/options.h 2006-02-22 04:19:21 UTC (rev 4015) +++ trunk/g10/options.h 2006-02-22 19:06:23 UTC (rev 4016) @@ -220,6 +220,14 @@ error (but an invalid backsig still is). */ int require_backsigs; + /* Linked list of ways to find a key if the key isn't on the local + keyring. */ + struct akl + { + enum {AKL_CERT, AKL_PKA, AKL_LDAP, AKL_KEYSERVER} type; + struct akl *next; + } *auto_key_locate; + } opt; /* CTRL is used to keep some global variables we currently can't From cvs at cvs.gnupg.org Wed Feb 22 21:21:01 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Wed Feb 22 20:56:36 2006 Subject: [svn] GnuPG - r4017 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-22 21:20:58 +0100 (Wed, 22 Feb 2006) New Revision: 4017 Modified: trunk/g10/ChangeLog trunk/g10/gpg.c trunk/g10/keyserver.c trunk/g10/mainproc.c trunk/g10/options.h Log: * options.h, gpg.c (main), mainproc.c (check_sig_and_print), keyserver.c (keyserver_opts): Rename auto-pka-retrieve to honor-pka-record to be consistent with honor-keyserver-url. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-22 19:06:23 UTC (rev 4016) +++ trunk/g10/ChangeLog 2006-02-22 20:20:58 UTC (rev 4017) @@ -1,5 +1,9 @@ 2006-02-22 David Shaw + * options.h, gpg.c (main), mainproc.c (check_sig_and_print), + keyserver.c (keyserver_opts): Rename auto-pka-retrieve to + honor-pka-record to be consistent with honor-keyserver-url. + * options.h, keydb.h, g10.c (main), getkey.c (parse_auto_key_locate): Parse a list of key access methods. (get_pubkey_byname): Walk the list here to try and retrieve keys Modified: trunk/g10/gpg.c =================================================================== --- trunk/g10/gpg.c 2006-02-22 19:06:23 UTC (rev 4016) +++ trunk/g10/gpg.c 2006-02-22 20:20:58 UTC (rev 4017) @@ -1731,7 +1731,7 @@ opt.keyserver_options.import_options=IMPORT_REPAIR_PKS_SUBKEY_BUG; opt.keyserver_options.export_options=EXPORT_ATTRIBUTES; opt.keyserver_options.options= - KEYSERVER_INCLUDE_SUBKEYS|KEYSERVER_INCLUDE_REVOKED|KEYSERVER_TRY_DNS_SRV|KEYSERVER_HONOR_KEYSERVER_URL|KEYSERVER_AUTO_PKA_RETRIEVE; + KEYSERVER_INCLUDE_SUBKEYS|KEYSERVER_INCLUDE_REVOKED|KEYSERVER_TRY_DNS_SRV|KEYSERVER_HONOR_KEYSERVER_URL|KEYSERVER_HONOR_PKA_RECORD; opt.verify_options= VERIFY_SHOW_POLICY_URLS|VERIFY_SHOW_STD_NOTATIONS|VERIFY_SHOW_KEYSERVER_URLS; opt.trust_model=TM_AUTO; Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-22 19:06:23 UTC (rev 4016) +++ trunk/g10/keyserver.c 2006-02-22 20:20:58 UTC (rev 4017) @@ -85,14 +85,14 @@ NULL}, {"auto-key-retrieve",KEYSERVER_AUTO_KEY_RETRIEVE,NULL, N_("automatically retrieve keys when verifying signatures")}, - {"auto-pka-retrieve",KEYSERVER_AUTO_PKA_RETRIEVE,NULL, - N_("automatically retrieve keys from PKA records")}, {"auto-cert-retrieve",KEYSERVER_AUTO_CERT_RETRIEVE,NULL, N_("automatically retrieve keys from DNS")}, {"try-dns-srv",KEYSERVER_TRY_DNS_SRV,NULL, NULL}, {"honor-keyserver-url",KEYSERVER_HONOR_KEYSERVER_URL,NULL, N_("honor the preferred keyserver URL set on the key")}, + {"honor-pka-record",KEYSERVER_HONOR_PKA_RECORD,NULL, + N_("honor the PKA record set on a key when retrieving keys")}, {NULL,0,NULL,NULL} }; @@ -1740,7 +1740,7 @@ /* Try and parse the keyserver URL. If it doesn't work, then we end up writing NULL which indicates we are the same as any other key. */ - if(uid && sig) + if(sig) (*klist)[*count].skipfncvalue=parse_preferred_keyserver(sig); } @@ -1977,7 +1977,8 @@ return rc; } -/* Import key pointed to by a PKA record */ +/* Import key pointed to by a PKA record. Return the requested + fingerprint in fpr. */ int keyserver_import_pka(const char *name,unsigned char *fpr) { @@ -2041,6 +2042,11 @@ keyserver->host=xmalloc(5+strlen(domain)+1); strcpy(keyserver->host,"keys."); strcat(keyserver->host,domain); + keyserver->uri=xmalloc(strlen(keyserver->scheme)+ + 3+strlen(keyserver->host)+1); + strcpy(keyserver->uri,keyserver->scheme); + strcat(keyserver->uri,"://"); + strcat(keyserver->uri,keyserver->host); rc=keyserver_work(KS_GETNAME,list,NULL,0,keyserver); Modified: trunk/g10/mainproc.c =================================================================== --- trunk/g10/mainproc.c 2006-02-22 19:06:23 UTC (rev 4016) +++ trunk/g10/mainproc.c 2006-02-22 20:20:58 UTC (rev 4017) @@ -1530,11 +1530,11 @@ } } - /* If the preferred keyserver thing above didn't work, our second try is to use the URI from a DNS PKA record. */ if ( rc == G10ERR_NO_PUBKEY - && (opt.keyserver_options.options&KEYSERVER_AUTO_PKA_RETRIEVE)) + && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE + && opt.keyserver_options.options&KEYSERVER_HONOR_PKA_RECORD) { const char *uri = pka_uri_from_sig (sig); @@ -1558,12 +1558,11 @@ } } - /* If the preferred keyserver thing above didn't work and we got no information from the DNS PKA, this is a third try. */ if( rc == G10ERR_NO_PUBKEY && opt.keyserver - && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)) + && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) { int res; Modified: trunk/g10/options.h =================================================================== --- trunk/g10/options.h 2006-02-22 19:06:23 UTC (rev 4016) +++ trunk/g10/options.h 2006-02-22 20:20:58 UTC (rev 4017) @@ -319,7 +319,7 @@ #define KEYSERVER_AUTO_KEY_RETRIEVE (1<<5) #define KEYSERVER_TRY_DNS_SRV (1<<6) #define KEYSERVER_HONOR_KEYSERVER_URL (1<<7) -#define KEYSERVER_AUTO_PKA_RETRIEVE (1<<8) +#define KEYSERVER_HONOR_PKA_RECORD (1<<8) #define KEYSERVER_AUTO_CERT_RETRIEVE (1<<9) #endif /*G10_OPTIONS_H*/ From cvs at cvs.gnupg.org Wed Feb 22 21:34:50 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Wed Feb 22 21:10:23 2006 Subject: [svn] GnuPG - r4018 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-22 21:34:48 +0100 (Wed, 22 Feb 2006) New Revision: 4018 Modified: trunk/g10/ChangeLog trunk/g10/keyserver.c trunk/g10/options.h Log: * options.h, keyserver.c (parse_keyserver_options): Remove auto-cert-retrieve as it is no longer meaningful. Add max-cert-size to allow users to pick a max key size retrieved via CERT. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-22 20:20:58 UTC (rev 4017) +++ trunk/g10/ChangeLog 2006-02-22 20:34:48 UTC (rev 4018) @@ -1,5 +1,10 @@ 2006-02-22 David Shaw + * options.h, keyserver.c (parse_keyserver_options): Remove + auto-cert-retrieve as it is no longer meaningful. Add + max-cert-size to allow users to pick a max key size retrieved via + CERT. + * options.h, gpg.c (main), mainproc.c (check_sig_and_print), keyserver.c (keyserver_opts): Rename auto-pka-retrieve to honor-pka-record to be consistent with honor-keyserver-url. Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-22 20:20:58 UTC (rev 4017) +++ trunk/g10/keyserver.c 2006-02-22 20:34:48 UTC (rev 4018) @@ -72,6 +72,7 @@ static struct parse_options keyserver_opts[]= { + {"max-cert-size",0,NULL,NULL}, {"include-revoked",KEYSERVER_INCLUDE_REVOKED,NULL, N_("include revoked keys in search results")}, {"include-subkeys",KEYSERVER_INCLUDE_SUBKEYS,NULL, @@ -85,8 +86,6 @@ NULL}, {"auto-key-retrieve",KEYSERVER_AUTO_KEY_RETRIEVE,NULL, N_("automatically retrieve keys when verifying signatures")}, - {"auto-cert-retrieve",KEYSERVER_AUTO_CERT_RETRIEVE,NULL, - N_("automatically retrieve keys from DNS")}, {"try-dns-srv",KEYSERVER_TRY_DNS_SRV,NULL, NULL}, {"honor-keyserver-url",KEYSERVER_HONOR_KEYSERVER_URL,NULL, @@ -112,7 +111,7 @@ char *tok; char *max_cert; - keyserver_opts[7].value=&max_cert; + keyserver_opts[0].value=&max_cert; while((tok=optsep(&options))) { @@ -173,10 +172,9 @@ } } - if(opt.keyserver_options.options&KEYSERVER_AUTO_CERT_RETRIEVE) + if(max_cert) { - if(max_cert) - max_cert_size=strtoul(max_cert,(char **)NULL,10); + max_cert_size=strtoul(max_cert,(char **)NULL,10); if(max_cert_size==0) max_cert_size=DEFAULT_MAX_CERT_SIZE; Modified: trunk/g10/options.h =================================================================== --- trunk/g10/options.h 2006-02-22 20:20:58 UTC (rev 4017) +++ trunk/g10/options.h 2006-02-22 20:34:48 UTC (rev 4018) @@ -320,6 +320,5 @@ #define KEYSERVER_TRY_DNS_SRV (1<<6) #define KEYSERVER_HONOR_KEYSERVER_URL (1<<7) #define KEYSERVER_HONOR_PKA_RECORD (1<<8) -#define KEYSERVER_AUTO_CERT_RETRIEVE (1<<9) #endif /*G10_OPTIONS_H*/ From cvs at cvs.gnupg.org Thu Feb 23 00:19:37 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Wed Feb 22 23:55:11 2006 Subject: [svn] GnuPG - r4019 - trunk/keyserver Message-ID: Author: dshaw Date: 2006-02-23 00:19:36 +0100 (Thu, 23 Feb 2006) New Revision: 4019 Modified: trunk/keyserver/ChangeLog trunk/keyserver/gpgkeys_hkp.c Log: * gpgkeys_hkp.c (get_name): A GETNAME query turns exact=on to cut down on odd matches. Modified: trunk/keyserver/ChangeLog =================================================================== --- trunk/keyserver/ChangeLog 2006-02-22 20:34:48 UTC (rev 4018) +++ trunk/keyserver/ChangeLog 2006-02-22 23:19:36 UTC (rev 4019) @@ -1,3 +1,8 @@ +2006-02-22 David Shaw + + * gpgkeys_hkp.c (get_name): A GETNAME query turns exact=on to cut + down on odd matches. + 2006-02-21 David Shaw * gpgkeys_ldap.c (make_one_attr, build_attrs, send_key): Don't Modified: trunk/keyserver/gpgkeys_hkp.c =================================================================== --- trunk/keyserver/gpgkeys_hkp.c 2006-02-22 20:34:48 UTC (rev 4018) +++ trunk/keyserver/gpgkeys_hkp.c 2006-02-22 23:19:36 UTC (rev 4019) @@ -327,6 +327,9 @@ append_path(request,"/pks/lookup?op=get&options=mr&search="); strcat(request,searchkey_encoded); + if(opt->action==KS_GETNAME) + strcat(request,"&exact=on"); + if(opt->verbose>2) fprintf(console,"gpgkeys: HTTP URL is `%s'\n",request); From cvs at cvs.gnupg.org Thu Feb 23 00:37:26 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Thu Feb 23 00:13:00 2006 Subject: [svn] GnuPG - r4020 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-23 00:37:23 +0100 (Thu, 23 Feb 2006) New Revision: 4020 Modified: trunk/g10/ChangeLog trunk/g10/getkey.c trunk/g10/gpgv.c trunk/g10/keyserver-internal.h trunk/g10/keyserver.c trunk/g10/options.h Log: * options.h, keyserver-internal.h, keyserver.c (keyserver_import_name), getkey.c (free_akl, parse_auto_key_locate, get_pubkey_byname): The obvious next step: allow arbitrary keyservers in the auto-key-locate list. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-22 23:19:36 UTC (rev 4019) +++ trunk/g10/ChangeLog 2006-02-22 23:37:23 UTC (rev 4020) @@ -1,5 +1,10 @@ 2006-02-22 David Shaw + * options.h, keyserver-internal.h, keyserver.c + (keyserver_import_name), getkey.c (free_akl, + parse_auto_key_locate, get_pubkey_byname): The obvious next step: + allow arbitrary keyservers in the auto-key-locate list. + * options.h, keyserver.c (parse_keyserver_options): Remove auto-cert-retrieve as it is no longer meaningful. Add max-cert-size to allow users to pick a max key size retrieved via Modified: trunk/g10/getkey.c =================================================================== --- trunk/g10/getkey.c 2006-02-22 23:19:36 UTC (rev 4019) +++ trunk/g10/getkey.c 2006-02-22 23:37:23 UTC (rev 4020) @@ -979,7 +979,7 @@ if(opt.keyserver) { glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_name(name); + res=keyserver_import_name(name,opt.keyserver); glo_ctrl.in_auto_key_retrieve--; if(res==0) @@ -987,6 +987,16 @@ name,opt.keyserver->uri); } break; + + case AKL_SPEC: + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_name(name,akl->spec); + glo_ctrl.in_auto_key_retrieve--; + + if(res==0) + log_info(_("Automatically retrieved `%s' via %s\n"), + name,akl->spec->uri); + break; } rc = key_byname( NULL, namelist, pk, NULL, 0, @@ -2879,6 +2889,15 @@ return ctx->kr_handle; } +static void +free_akl(struct akl *akl) +{ + if(akl->spec) + free_keyserver_spec(akl->spec); + + xfree(akl); +} + int parse_auto_key_locate(char *options) { @@ -2901,9 +2920,11 @@ akl->type=AKL_LDAP; else if(ascii_strcasecmp(tok,"keyserver")==0) akl->type=AKL_KEYSERVER; + else if((akl->spec=parse_keyserver_uri(tok,1,NULL,0))) + akl->type=AKL_SPEC; else { - xfree(akl); + free_akl(akl); return 0; } @@ -2911,8 +2932,14 @@ for(last=opt.auto_key_locate;last && last->next;last=last->next) { /* Check for duplicates */ - if(last && last->type==akl->type) - return 0; + if(last && last->type==akl->type + && (akl->type!=AKL_SPEC + || (akl->type==AKL_SPEC + && strcmp(last->spec->uri,akl->spec->uri)==0))) + { + free_akl(akl); + return 0; + } } if(last) Modified: trunk/g10/gpgv.c =================================================================== --- trunk/g10/gpgv.c 2006-02-22 23:19:36 UTC (rev 4019) +++ trunk/g10/gpgv.c 2006-02-22 23:37:23 UTC (rev 4020) @@ -287,7 +287,10 @@ keyserver_import_pka(const char *name,unsigned char *fpr) { return -1; } int -keyserver_import_name(const char *name) { return -1; } +keyserver_import_name(const char *name,struct keyserver_spec *spec) +{ + return -1; +} int keyserver_import_ldap(const char *name) { return -1; } Modified: trunk/g10/keyserver-internal.h =================================================================== --- trunk/g10/keyserver-internal.h 2006-02-22 23:19:36 UTC (rev 4019) +++ trunk/g10/keyserver-internal.h 2006-02-22 23:37:23 UTC (rev 4020) @@ -43,7 +43,7 @@ int keyserver_fetch(STRLIST urilist); int keyserver_import_cert(const char *name); int keyserver_import_pka(const char *name,unsigned char *fpr); -int keyserver_import_name(const char *name); +int keyserver_import_name(const char *name,struct keyserver_spec *keyserver); int keyserver_import_ldap(const char *name); #endif /* !_KEYSERVER_INTERNAL_H_ */ Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-22 23:19:36 UTC (rev 4019) +++ trunk/g10/keyserver.c 2006-02-22 23:37:23 UTC (rev 4020) @@ -2001,14 +2001,14 @@ /* Import all keys that match name */ int -keyserver_import_name(const char *name) +keyserver_import_name(const char *name,struct keyserver_spec *keyserver) { STRLIST list=NULL; int rc; append_to_strlist(&list,name); - rc=keyserver_work(KS_GETNAME,list,NULL,0,opt.keyserver); + rc=keyserver_work(KS_GETNAME,list,NULL,0,keyserver); free_strlist(list); Modified: trunk/g10/options.h =================================================================== --- trunk/g10/options.h 2006-02-22 23:19:36 UTC (rev 4019) +++ trunk/g10/options.h 2006-02-22 23:37:23 UTC (rev 4020) @@ -224,7 +224,8 @@ keyring. */ struct akl { - enum {AKL_CERT, AKL_PKA, AKL_LDAP, AKL_KEYSERVER} type; + enum {AKL_CERT, AKL_PKA, AKL_LDAP, AKL_KEYSERVER, AKL_SPEC} type; + struct keyserver_spec *spec; struct akl *next; } *auto_key_locate; From cvs at cvs.gnupg.org Thu Feb 23 17:31:54 2006 From: cvs at cvs.gnupg.org (svn author marcus) Date: Thu Feb 23 17:07:23 2006 Subject: [svn] gpgme - r1159 - trunk Message-ID: Author: marcus Date: 2006-02-23 17:31:54 +0100 (Thu, 23 Feb 2006) New Revision: 1159 Modified: trunk/NEWS trunk/configure.ac Log: Change history. That's double plus good. Modified: trunk/NEWS =================================================================== --- trunk/NEWS 2006-02-22 12:03:33 UTC (rev 1158) +++ trunk/NEWS 2006-02-23 16:31:54 UTC (rev 1159) @@ -1,4 +1,4 @@ -Noteworthy changes in version 1.1.1 (2006-02-22) +Noteworthy changes in version 1.1.1 (2006-02-23) ------------------------------------------------ * Fixed a bug in that the fingerprints of subkeys are not available. Modified: trunk/configure.ac =================================================================== --- trunk/configure.ac 2006-02-22 12:03:33 UTC (rev 1158) +++ trunk/configure.ac 2006-02-23 16:31:54 UTC (rev 1159) @@ -51,7 +51,7 @@ LIBGPGME_LT_CURRENT=17 # Subtract 2 from this value if you want to make the LFS transition an # ABI break. [Note to self: Remove this comment with the next regular break.] -LIBGPGME_LT_AGE=7 +LIBGPGME_LT_AGE=6 LIBGPGME_LT_REVISION=0 # If the API is changed in an incompatible way: increment the next counter. From cvs at cvs.gnupg.org Thu Feb 23 18:00:04 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Thu Feb 23 17:35:32 2006 Subject: [svn] GnuPG - r4021 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-23 18:00:02 +0100 (Thu, 23 Feb 2006) New Revision: 4021 Modified: trunk/g10/ChangeLog trunk/g10/keyserver-internal.h trunk/g10/keyserver.c trunk/g10/options.h Log: * options.h, keyserver.c (add_canonical_option): New. (parse_keyserver_options): Moved from here. (parse_keyserver_uri): Use it here so each keyserver can have some private options in addition to the main keyserver-options (e.g. per-keyserver auth). Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-22 23:37:23 UTC (rev 4020) +++ trunk/g10/ChangeLog 2006-02-23 17:00:02 UTC (rev 4021) @@ -1,3 +1,11 @@ +2006-02-23 David Shaw + + * options.h, keyserver.c (add_canonical_option): New. + (parse_keyserver_options): Moved from here. + (parse_keyserver_uri): Use it here so each keyserver can have some + private options in addition to the main keyserver-options + (e.g. per-keyserver auth). + 2006-02-22 David Shaw * options.h, keyserver-internal.h, keyserver.c Modified: trunk/g10/keyserver-internal.h =================================================================== --- trunk/g10/keyserver-internal.h 2006-02-22 23:37:23 UTC (rev 4020) +++ trunk/g10/keyserver-internal.h 2006-02-23 17:00:02 UTC (rev 4021) @@ -29,7 +29,8 @@ int parse_keyserver_options(char *options); void free_keyserver_spec(struct keyserver_spec *keyserver); -struct keyserver_spec *parse_keyserver_uri(const char *uri,int require_scheme, +struct keyserver_spec *parse_keyserver_uri(const char *string, + int require_scheme, const char *configname, unsigned int configlineno); struct keyserver_spec *parse_preferred_keyserver(PKT_signature *sig); Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-22 23:37:23 UTC (rev 4020) +++ trunk/g10/keyserver.c 2006-02-23 17:00:02 UTC (rev 4021) @@ -104,6 +104,27 @@ static size_t max_cert_size=DEFAULT_MAX_CERT_SIZE; +static void +add_canonical_option(char *option,STRLIST *list) +{ + char *arg=argsplit(option); + + if(arg) + { + char *joined; + + joined=xmalloc(strlen(option)+1+strlen(arg)+1); + /* Make a canonical name=value form with no spaces */ + strcpy(joined,option); + strcat(joined,"="); + strcat(joined,arg); + add_to_strlist(list,joined); + xfree(joined); + } + else + add_to_strlist(list,option); +} + int parse_keyserver_options(char *options) { @@ -152,23 +173,7 @@ { /* All of the standard options have failed, so the option is destined for a keyserver plugin. */ - char *arg=argsplit(tok); - - if(arg) - { - char *joined; - - joined=xmalloc(strlen(tok)+1+strlen(arg)+1); - /* Make a canonical name=value form with no - spaces */ - strcpy(joined,tok); - strcat(joined,"="); - strcat(joined,arg); - add_to_strlist(&opt.keyserver_options.other,joined); - xfree(joined); - } - else - add_to_strlist(&opt.keyserver_options.other,tok); + add_canonical_option(tok,&opt.keyserver_options.other); } } @@ -193,6 +198,7 @@ xfree(keyserver->port); xfree(keyserver->path); xfree(keyserver->opaque); + free_strlist(keyserver->options); xfree(keyserver); } @@ -201,18 +207,33 @@ keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */ struct keyserver_spec * -parse_keyserver_uri(const char *uri,int require_scheme, +parse_keyserver_uri(const char *string,int require_scheme, const char *configname,unsigned int configlineno) { int assume_hkp=0; struct keyserver_spec *keyserver; const char *idx; int count; + char *uri,*options; - assert(uri!=NULL); + assert(string!=NULL); keyserver=xmalloc_clear(sizeof(struct keyserver_spec)); + uri=xstrdup(string); + + options=strchr(uri,' '); + if(options) + { + char *tok; + + *options='\0'; + options++; + + while((tok=optsep(&options))) + add_canonical_option(tok,&keyserver->options); + } + /* Get the scheme */ for(idx=uri,count=0;*idx && *idx!=':';idx++) @@ -1038,6 +1059,9 @@ for(temp=opt.keyserver_options.other;temp;temp=temp->next) fprintf(spawn->tochild,"OPTION %s\n",temp->d); + for(temp=opt.keyserver->options;temp;temp=temp->next) + fprintf(spawn->tochild,"OPTION %s\n",temp->d); + switch(action) { case KS_GET: Modified: trunk/g10/options.h =================================================================== --- trunk/g10/options.h 2006-02-22 23:37:23 UTC (rev 4020) +++ trunk/g10/options.h 2006-02-23 17:00:02 UTC (rev 4021) @@ -136,6 +136,7 @@ char *port; char *path; char *opaque; + STRLIST options; struct { unsigned int direct_uri:1; From cvs at cvs.gnupg.org Thu Feb 23 20:52:22 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Thu Feb 23 20:27:48 2006 Subject: [svn] GnuPG - r4022 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-23 20:52:20 +0100 (Thu, 23 Feb 2006) New Revision: 4022 Modified: trunk/g10/ChangeLog trunk/g10/gpg.c Log: * gpg.c (add_notation_data): Fix reversed logic for isascii check when adding notations. Noted by Christian Biere. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-23 17:00:02 UTC (rev 4021) +++ trunk/g10/ChangeLog 2006-02-23 19:52:20 UTC (rev 4022) @@ -1,5 +1,8 @@ 2006-02-23 David Shaw + * gpg.c (add_notation_data): Fix reversed logic for isascii check + when adding notations. Noted by Christian Biere. + * options.h, keyserver.c (add_canonical_option): New. (parse_keyserver_options): Moved from here. (parse_keyserver_uri): Use it here so each keyserver can have some Modified: trunk/g10/gpg.c =================================================================== --- trunk/g10/gpg.c 2006-02-23 17:00:02 UTC (rev 4021) +++ trunk/g10/gpg.c 2006-02-23 19:52:20 UTC (rev 4022) @@ -4029,7 +4029,7 @@ /* we only support printable text - therefore we enforce the use * of only printable characters (an empty value is valid) */ for( s++; *s ; s++ ) { - if ( isascii (*s) ) + if ( !isascii (*s) ) highbit = 1; else if (iscntrl(*s)) { log_error(_("a notation value must not use" From cvs at cvs.gnupg.org Thu Feb 23 21:54:32 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Thu Feb 23 21:29:58 2006 Subject: [svn] GnuPG - r4023 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-23 21:54:30 +0100 (Thu, 23 Feb 2006) New Revision: 4023 Modified: trunk/g10/ChangeLog trunk/g10/keyserver.c Log: * keyserver.c (parse_keyserver_uri, add_canonical_option): Always append options to the list, as ordering may be significant to the user. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-23 19:52:20 UTC (rev 4022) +++ trunk/g10/ChangeLog 2006-02-23 20:54:30 UTC (rev 4023) @@ -1,5 +1,9 @@ 2006-02-23 David Shaw + * keyserver.c (parse_keyserver_uri, add_canonical_option): Always + append options to the list, as ordering may be significant to the + user. + * gpg.c (add_notation_data): Fix reversed logic for isascii check when adding notations. Noted by Christian Biere. Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-23 19:52:20 UTC (rev 4022) +++ trunk/g10/keyserver.c 2006-02-23 20:54:30 UTC (rev 4023) @@ -118,11 +118,11 @@ strcpy(joined,option); strcat(joined,"="); strcat(joined,arg); - add_to_strlist(list,joined); + append_to_strlist(list,joined); xfree(joined); } else - add_to_strlist(list,option); + append_to_strlist(list,option); } int @@ -294,7 +294,7 @@ "--keyserver-options ","broken-http-proxy"); xfree(keyserver->scheme); keyserver->scheme=xstrdup("hkp"); - add_to_strlist(&opt.keyserver_options.other,"broken-http-proxy"); + append_to_strlist(&opt.keyserver_options.other,"broken-http-proxy"); } else if(ascii_strcasecmp(keyserver->scheme,"x-hkp")==0) { From cvs at cvs.gnupg.org Thu Feb 23 22:06:32 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Thu Feb 23 21:41:58 2006 Subject: [svn] GnuPG - r4024 - trunk/keyserver Message-ID: Author: dshaw Date: 2006-02-23 22:06:32 +0100 (Thu, 23 Feb 2006) New Revision: 4024 Modified: trunk/keyserver/ChangeLog trunk/keyserver/ksutil.c Log: * ksutil.c (init_ks_options): Default include-revoked and include-subkeys to on, as gpg isn't doing this any longer. Modified: trunk/keyserver/ChangeLog =================================================================== --- trunk/keyserver/ChangeLog 2006-02-23 20:54:30 UTC (rev 4023) +++ trunk/keyserver/ChangeLog 2006-02-23 21:06:32 UTC (rev 4024) @@ -1,3 +1,8 @@ +2006-02-23 David Shaw + + * ksutil.c (init_ks_options): Default include-revoked and + include-subkeys to on, as gpg isn't doing this any longer. + 2006-02-22 David Shaw * gpgkeys_hkp.c (get_name): A GETNAME query turns exact=on to cut Modified: trunk/keyserver/ksutil.c =================================================================== --- trunk/keyserver/ksutil.c 2006-02-23 20:54:30 UTC (rev 4023) +++ trunk/keyserver/ksutil.c 2006-02-23 21:06:32 UTC (rev 4024) @@ -86,6 +86,8 @@ if(opt) { opt->action=KS_UNKNOWN; + opt->flags.include_revoked=1; + opt->flags.include_subkeys=1; opt->flags.check_cert=1; opt->timeout=DEFAULT_KEYSERVER_TIMEOUT; opt->path=strdup("/"); From cvs at cvs.gnupg.org Thu Feb 23 23:39:43 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Thu Feb 23 23:15:09 2006 Subject: [svn] GnuPG - r4025 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-23 23:39:40 +0100 (Thu, 23 Feb 2006) New Revision: 4025 Modified: trunk/g10/ChangeLog trunk/g10/gpg.c trunk/g10/keyserver.c trunk/g10/options.h Log: * options.c, gpg.c (main), keyserver.c (keyserver_spawn): No special treatment of include-revoked, include-subkeys, and try-dns-srv. These are keyserver features, and GPG shouldn't get involved here. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-23 21:06:32 UTC (rev 4024) +++ trunk/g10/ChangeLog 2006-02-23 22:39:40 UTC (rev 4025) @@ -1,5 +1,10 @@ 2006-02-23 David Shaw + * options.c, gpg.c (main), keyserver.c (keyserver_spawn): No + special treatment of include-revoked, include-subkeys, and + try-dns-srv. These are keyserver features, and GPG shouldn't get + involved here. + * keyserver.c (parse_keyserver_uri, add_canonical_option): Always append options to the list, as ordering may be significant to the user. Modified: trunk/g10/gpg.c =================================================================== --- trunk/g10/gpg.c 2006-02-23 21:06:32 UTC (rev 4024) +++ trunk/g10/gpg.c 2006-02-23 22:39:40 UTC (rev 4025) @@ -1731,7 +1731,7 @@ opt.keyserver_options.import_options=IMPORT_REPAIR_PKS_SUBKEY_BUG; opt.keyserver_options.export_options=EXPORT_ATTRIBUTES; opt.keyserver_options.options= - KEYSERVER_INCLUDE_SUBKEYS|KEYSERVER_INCLUDE_REVOKED|KEYSERVER_TRY_DNS_SRV|KEYSERVER_HONOR_KEYSERVER_URL|KEYSERVER_HONOR_PKA_RECORD; + KEYSERVER_HONOR_KEYSERVER_URL|KEYSERVER_HONOR_PKA_RECORD; opt.verify_options= VERIFY_SHOW_POLICY_URLS|VERIFY_SHOW_STD_NOTATIONS|VERIFY_SHOW_KEYSERVER_URLS; opt.trust_model=TM_AUTO; Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-23 21:06:32 UTC (rev 4024) +++ trunk/g10/keyserver.c 2006-02-23 22:39:40 UTC (rev 4025) @@ -67,17 +67,13 @@ enum ks_action {KS_UNKNOWN=0,KS_GET,KS_GETNAME,KS_SEND,KS_SEARCH}; -/* Tell remote processes about these options */ -#define REMOTE_TELL (KEYSERVER_INCLUDE_REVOKED|KEYSERVER_INCLUDE_SUBKEYS|KEYSERVER_TRY_DNS_SRV) - static struct parse_options keyserver_opts[]= { + /* some of these options are not real - just for the help + message */ {"max-cert-size",0,NULL,NULL}, - {"include-revoked",KEYSERVER_INCLUDE_REVOKED,NULL, - N_("include revoked keys in search results")}, - {"include-subkeys",KEYSERVER_INCLUDE_SUBKEYS,NULL, - N_("include subkeys when searching by key ID")}, - /* not a real option - just for the help message */ + {"include-revoked",0,NULL,N_("include revoked keys in search results")}, + {"include-subkeys",0,NULL,N_("include subkeys when searching by key ID")}, {"use-temp-files",0,NULL, N_("use temporary files to pass data to keyserver helpers")}, {"keep-temp-files",KEYSERVER_KEEP_TEMP_FILES,NULL, @@ -86,8 +82,6 @@ NULL}, {"auto-key-retrieve",KEYSERVER_AUTO_KEY_RETRIEVE,NULL, N_("automatically retrieve keys when verifying signatures")}, - {"try-dns-srv",KEYSERVER_TRY_DNS_SRV,NULL, - NULL}, {"honor-keyserver-url",KEYSERVER_HONOR_KEYSERVER_URL,NULL, N_("honor the preferred keyserver URL set on the key")}, {"honor-pka-record",KEYSERVER_HONOR_PKA_RECORD,NULL, @@ -933,7 +927,6 @@ unsigned int maxlen,buflen; char *command,*end,*searchstr=NULL; byte *line=NULL; - struct parse_options *kopts; struct exec_info *spawn; const char *scheme; const char *libexecdir = get_libexecdir (); @@ -1050,15 +1043,13 @@ fprintf(spawn->tochild,"PATH %s\n",keyserver->path); } - /* Write options */ + /* Write global options */ - for(i=0,kopts=keyserver_opts;kopts[i].name;i++) - if(opt.keyserver_options.options & kopts[i].bit & REMOTE_TELL) - fprintf(spawn->tochild,"OPTION %s\n",kopts[i].name); - for(temp=opt.keyserver_options.other;temp;temp=temp->next) fprintf(spawn->tochild,"OPTION %s\n",temp->d); + /* Write per-keyserver options */ + for(temp=opt.keyserver->options;temp;temp=temp->next) fprintf(spawn->tochild,"OPTION %s\n",temp->d); Modified: trunk/g10/options.h =================================================================== --- trunk/g10/options.h 2006-02-23 21:06:32 UTC (rev 4024) +++ trunk/g10/options.h 2006-02-23 22:39:40 UTC (rev 4025) @@ -313,14 +313,11 @@ #define VERIFY_SHOW_UID_VALIDITY (1<<5) #define VERIFY_SHOW_UNUSABLE_UIDS (1<<6) -#define KEYSERVER_INCLUDE_REVOKED (1<<0) -#define KEYSERVER_INCLUDE_SUBKEYS (1<<1) -#define KEYSERVER_USE_TEMP_FILES (1<<2) -#define KEYSERVER_KEEP_TEMP_FILES (1<<3) -#define KEYSERVER_ADD_FAKE_V3 (1<<4) -#define KEYSERVER_AUTO_KEY_RETRIEVE (1<<5) -#define KEYSERVER_TRY_DNS_SRV (1<<6) -#define KEYSERVER_HONOR_KEYSERVER_URL (1<<7) -#define KEYSERVER_HONOR_PKA_RECORD (1<<8) +#define KEYSERVER_USE_TEMP_FILES (1<<0) +#define KEYSERVER_KEEP_TEMP_FILES (1<<1) +#define KEYSERVER_ADD_FAKE_V3 (1<<2) +#define KEYSERVER_AUTO_KEY_RETRIEVE (1<<3) +#define KEYSERVER_HONOR_KEYSERVER_URL (1<<4) +#define KEYSERVER_HONOR_PKA_RECORD (1<<5) #endif /*G10_OPTIONS_H*/ From cvs at cvs.gnupg.org Fri Feb 24 04:57:12 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Fri Feb 24 04:32:41 2006 Subject: [svn] GnuPG - r4026 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-24 04:57:11 +0100 (Fri, 24 Feb 2006) New Revision: 4026 Modified: trunk/g10/ChangeLog trunk/g10/keyserver.c Log: * keyserver.c (parse_keyserver_options): Only change max_cert if it is used. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-23 22:39:40 UTC (rev 4025) +++ trunk/g10/ChangeLog 2006-02-24 03:57:11 UTC (rev 4026) @@ -1,5 +1,8 @@ 2006-02-23 David Shaw + * keyserver.c (parse_keyserver_options): Only change max_cert if + it is used. + * options.c, gpg.c (main), keyserver.c (keyserver_spawn): No special treatment of include-revoked, include-subkeys, and try-dns-srv. These are keyserver features, and GPG shouldn't get Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-23 22:39:40 UTC (rev 4025) +++ trunk/g10/keyserver.c 2006-02-24 03:57:11 UTC (rev 4026) @@ -124,7 +124,7 @@ { int ret=1; char *tok; - char *max_cert; + char *max_cert=NULL; keyserver_opts[0].value=&max_cert; From cvs at cvs.gnupg.org Fri Feb 24 15:27:24 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Fri Feb 24 15:02:53 2006 Subject: [svn] GnuPG - r4027 - trunk/g10 Message-ID: Author: dshaw Date: 2006-02-24 15:27:22 +0100 (Fri, 24 Feb 2006) New Revision: 4027 Modified: trunk/g10/ChangeLog trunk/g10/getkey.c trunk/g10/gpg.c trunk/g10/gpgv.c trunk/g10/keydb.h trunk/g10/keyserver-internal.h trunk/g10/keyserver.c trunk/g10/options.h Log: * keydb.h, getkey.c (release_akl), gpg.c (main): Add --no-auto-key-locate. * options.h, gpg.c (main): Keep track of each keyserver registered so we can match on them later. * keyserver-internal.h, keyserver.c (cmp_keyserver_spec, keyserver_match), gpgv.c: New. Find a keyserver that matches ours and return its spec. * getkey.c (get_pubkey_byname): Use it here to get the per-keyserver options from an earlier keyserver. Modified: trunk/g10/ChangeLog =================================================================== --- trunk/g10/ChangeLog 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/ChangeLog 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,3 +1,18 @@ +2006-02-24 David Shaw + + * keydb.h, getkey.c (release_akl), gpg.c (main): Add + --no-auto-key-locate. + + * options.h, gpg.c (main): Keep track of each keyserver registered + so we can match on them later. + + * keyserver-internal.h, keyserver.c (cmp_keyserver_spec, + keyserver_match), gpgv.c: New. Find a keyserver that matches ours + and return its spec. + + * getkey.c (get_pubkey_byname): Use it here to get the + per-keyserver options from an earlier keyserver. + 2006-02-23 David Shaw * keyserver.c (parse_keyserver_options): Only change max_cert if Modified: trunk/g10/getkey.c =================================================================== --- trunk/g10/getkey.c 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/getkey.c 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,6 +1,6 @@ /* getkey.c - Get a key from the database - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -989,13 +989,18 @@ break; case AKL_SPEC: - glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_name(name,akl->spec); - glo_ctrl.in_auto_key_retrieve--; + { + struct keyserver_spec *keyserver; - if(res==0) - log_info(_("Automatically retrieved `%s' via %s\n"), - name,akl->spec->uri); + keyserver=keyserver_match(akl->spec); + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_name(name,keyserver); + glo_ctrl.in_auto_key_retrieve--; + + if(res==0) + log_info(_("Automatically retrieved `%s' via %s\n"), + name,akl->spec->uri); + } break; } @@ -2898,6 +2903,17 @@ xfree(akl); } +void +release_akl(void) +{ + while(opt.auto_key_locate) + { + struct akl *akl2=opt.auto_key_locate; + opt.auto_key_locate=opt.auto_key_locate->next; + free_akl(akl2); + } +} + int parse_auto_key_locate(char *options) { Modified: trunk/g10/gpg.c =================================================================== --- trunk/g10/gpg.c 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/gpg.c 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,6 +1,6 @@ /* gpg.c - The GnuPG utility (main for gpg) - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -361,6 +361,7 @@ oRequireBacksigs, oNoRequireBacksigs, oAutoKeyLocate, + oNoAutoKeyLocate, oNoop }; @@ -698,15 +699,16 @@ #if defined(ENABLE_CARD_SUPPORT) && defined(HAVE_LIBUSB) { oDebugCCIDDriver, "debug-ccid-driver", 0, "@"}, #endif - /* These are aliases to help users of the PGP command line product - use gpg with minimal pain. Many commands are common already as - they seem to have borrowed commands from us. Now I'm returning - the favor. */ + /* These two are aliases to help users of the PGP command line + product use gpg with minimal pain. Many commands are common + already as they seem to have borrowed commands from us. Now + I'm returning the favor. */ { oLocalUser, "sign-with", 2, "@" }, { oRecipient, "user", 2, "@" }, { oRequireBacksigs, "require-backsigs", 0, "@"}, { oNoRequireBacksigs, "no-require-backsigs", 0, "@"}, { oAutoKeyLocate, "auto-key-locate", 2, "@"}, + { oNoAutoKeyLocate, "no-auto-key-locate", 0, "@"}, {0,NULL,0,NULL} }; @@ -2416,10 +2418,18 @@ #endif /* __riscos__ */ break; case oKeyServer: - opt.keyserver=parse_keyserver_uri(pargs.r.ret_str,0, - configname,configlineno); - if(!opt.keyserver) - log_error(_("could not parse keyserver URL\n")); + { + struct keyserver_spec *keyserver; + keyserver=parse_keyserver_uri(pargs.r.ret_str,0, + configname,configlineno); + if(!keyserver) + log_error(_("could not parse keyserver URL\n")); + else + { + keyserver->next=opt.keyserver; + opt.keyserver=keyserver; + } + } break; case oKeyServerOptions: if(!parse_keyserver_options(pargs.r.ret_str)) @@ -2655,6 +2665,9 @@ log_error(_("invalid auto-key-locate list\n")); } break; + case oNoAutoKeyLocate: + release_akl(); + break; case oNoop: break; Modified: trunk/g10/gpgv.c =================================================================== --- trunk/g10/gpgv.c 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/gpgv.c 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,6 +1,6 @@ /* gpgv.c - The GnuPG signature verify utility - * Copyright (C) 1998, 1999, 2000, 2001, 2002, - * 2005 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -274,6 +274,10 @@ * Because we only work with trusted keys, it does not make sense to * get them from a keyserver */ + +struct keyserver_spec * +keyserver_match(struct keyserver_spec *spec) { return NULL; } + int keyserver_import_keyid( u32 *keyid, void *dummy ) { Modified: trunk/g10/keydb.h =================================================================== --- trunk/g10/keydb.h 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/keydb.h 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,6 +1,6 @@ /* keydb.h - Key database - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -258,6 +258,7 @@ char*get_user_id( u32 *keyid, size_t *rn ); char*get_user_id_native( u32 *keyid ); KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx); +void release_akl(void); int parse_auto_key_locate(char *options); /*-- keyid.c --*/ Modified: trunk/g10/keyserver-internal.h =================================================================== --- trunk/g10/keyserver-internal.h 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/keyserver-internal.h 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,5 +1,5 @@ /* keyserver-internal.h - Keyserver internals - * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -29,6 +29,7 @@ int parse_keyserver_options(char *options); void free_keyserver_spec(struct keyserver_spec *keyserver); +struct keyserver_spec *keyserver_match(struct keyserver_spec *spec); struct keyserver_spec *parse_keyserver_uri(const char *string, int require_scheme, const char *configname, Modified: trunk/g10/keyserver.c =================================================================== --- trunk/g10/keyserver.c 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/keyserver.c 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,5 +1,6 @@ /* keyserver.c - generic keyserver code - * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2004, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -196,6 +197,41 @@ xfree(keyserver); } +/* Return 0 for match */ +static int +cmp_keyserver_spec(struct keyserver_spec *one,struct keyserver_spec *two) +{ + if(ascii_strcasecmp(one->scheme,two->scheme)==0) + { + if(one->host && two->host && ascii_strcasecmp(one->host,two->host)==0) + { + if((one->port && two->port + && ascii_strcasecmp(one->port,two->port)==0) + || (!one->port && !two->port)) + return 0; + } + else if(one->opaque && two->opaque + && ascii_strcasecmp(one->opaque,two->opaque)==0) + return 0; + } + + return 1; +} + +/* Try and match one of our keyservers. If we can, return that. If + we can't, return our input. */ +struct keyserver_spec * +keyserver_match(struct keyserver_spec *spec) +{ + struct keyserver_spec *ks; + + for(ks=opt.keyserver;ks;ks=ks->next) + if(cmp_keyserver_spec(spec,ks)==0) + return ks; + + return spec; +} + /* TODO: once we cut over to an all-curl world, we don't need this parser any longer so it can be removed, or at least moved to keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */ @@ -1050,7 +1086,7 @@ /* Write per-keyserver options */ - for(temp=opt.keyserver->options;temp;temp=temp->next) + for(temp=keyserver->options;temp;temp=temp->next) fprintf(spawn->tochild,"OPTION %s\n",temp->d); switch(action) Modified: trunk/g10/options.h =================================================================== --- trunk/g10/options.h 2006-02-24 03:57:11 UTC (rev 4026) +++ trunk/g10/options.h 2006-02-24 14:27:22 UTC (rev 4027) @@ -1,6 +1,6 @@ /* options.h - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -141,6 +141,7 @@ { unsigned int direct_uri:1; } flags; + struct keyserver_spec *next; } *keyserver; struct { From cvs at cvs.gnupg.org Sat Feb 25 01:21:26 2006 From: cvs at cvs.gnupg.org (svn author dshaw) Date: Sat Feb 25 00:56:53 2006 Subject: [svn] GnuPG - r4028 - trunk/doc Message-ID: Author: dshaw Date: 2006-02-25 01:21:20 +0100 (Sat, 25 Feb 2006) New Revision: 4028 Modified: trunk/doc/ChangeLog trunk/doc/gpg.sgml Log: * gpg.sgml: Document new --keyserver syntax. Modified: trunk/doc/ChangeLog =================================================================== --- trunk/doc/ChangeLog 2006-02-24 14:27:22 UTC (rev 4027) +++ trunk/doc/ChangeLog 2006-02-25 00:21:20 UTC (rev 4028) @@ -1,3 +1,7 @@ +2006-02-24 David Shaw + + * gpg.sgml: Document new --keyserver syntax. + 2005-12-20 Werner Koch * gpg.sgml (trust-model): Document "auto" and the "pka" variants. Modified: trunk/doc/gpg.sgml =================================================================== --- trunk/doc/gpg.sgml 2006-02-24 14:27:22 UTC (rev 4027) +++ trunk/doc/gpg.sgml 2006-02-25 00:21:20 UTC (rev 4028) @@ -1,6 +1,6 @@