diff options
Diffstat (limited to '')
-rw-r--r-- | scd/app-common.h | 3 | ||||
-rw-r--r-- | scd/app.c | 39 | ||||
-rw-r--r-- | scd/command.c | 88 |
3 files changed, 91 insertions, 39 deletions
diff --git a/scd/app-common.h b/scd/app-common.h index 2371818e5..fb0fe550a 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -129,7 +129,8 @@ void application_notify_card_reset (int slot); gpg_error_t check_application_conflict (const char *name, app_t app); gpg_error_t app_reset (app_t app, ctrl_t ctrl, int send_reset); gpg_error_t select_application (ctrl_t ctrl, const char *name, app_t *r_app, - int scan); + int scan, const unsigned char *serialno_bin, + size_t serialno_bin_len); char *get_supported_applications (void); void release_application (app_t app); gpg_error_t app_munge_serialno (app_t app); @@ -317,10 +317,12 @@ app_new_register (int slot, ctrl_t ctrl, const char *name) and return a context. Returns an error code and stores NULL at R_APP if no application was found or no card is present. */ gpg_error_t -select_application (ctrl_t ctrl, const char *name, app_t *r_app, int scan) +select_application (ctrl_t ctrl, const char *name, app_t *r_app, + int scan, const unsigned char *serialno_bin, + size_t serialno_bin_len) { gpg_error_t err = 0; - app_t app; + app_t a; *r_app = NULL; @@ -352,33 +354,50 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app, int scan) if (!sw || sw == SW_HOST_ALREADY_CONNECTED) err = 0; + else if (sw == SW_HOST_NO_CARD) + err = gpg_error (GPG_ERR_CARD_NOT_PRESENT); else err = gpg_error (GPG_ERR_ENODEV); if (!err) err = app_new_register (slot, ctrl, name); else - apdu_close_reader (slot); + { + /* We close a reader with no card. */ + apdu_close_reader (slot); + } } apdu_dev_list_finish (l); } - app = app_top; - if (app) + npth_mutex_lock (&app_list_lock); + for (a = app_top; a; a = a->next) { - lock_app (app, ctrl); - err = check_conflict (app, name); + lock_app (a, ctrl); + if (serialno_bin == NULL) + break; + if (a->serialnolen == serialno_bin_len + && !memcmp (a->serialno, serialno_bin, a->serialnolen)) + break; + unlock_app (a); + } + + if (a) + { + err = check_conflict (a, name); if (!err) { - app->ref_count++; - *r_app = app; + a->ref_count++; + *r_app = a; } - unlock_app (app); + unlock_app (a); } else err = gpg_error (GPG_ERR_ENODEV); + npth_mutex_unlock (&app_list_lock); + return err; } diff --git a/scd/command.c b/scd/command.c index ce2be3485..dc854e35d 100644 --- a/scd/command.c +++ b/scd/command.c @@ -193,10 +193,8 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) /* If the card has not yet been opened, do it. */ static gpg_error_t -open_card (ctrl_t ctrl, const char *apptype, int scan) +open_card (ctrl_t ctrl) { - gpg_error_t err; - /* If we ever got a card not present error code, return that. Only the SERIALNO command and a reset are able to clear from that state. */ @@ -206,24 +204,46 @@ open_card (ctrl_t ctrl, const char *apptype, int scan) if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); + if (ctrl->app_ctx) + return 0; + + return select_application (ctrl, NULL, &ctrl->app_ctx, 0, NULL, 0); +} + +/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */ +static gpg_error_t +open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno) +{ + gpg_error_t err; + unsigned char *serialno_bin = NULL; + size_t serialno_bin_len = 0; + /* If we are already initialized for one specific application we need to check that the client didn't requested a specific application different from the one in use before we continue. */ - if (!scan && ctrl->app_ctx) + if (apptype && ctrl->app_ctx) return check_application_conflict (apptype, ctrl->app_ctx); - err = select_application (ctrl, apptype, &ctrl->app_ctx, scan); + if (serialno) + serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); + + err = select_application (ctrl, apptype, &ctrl->app_ctx, 1, + serialno_bin, serialno_bin_len); + xfree (serialno_bin); return err; } static const char hlp_serialno[] = - "SERIALNO [<apptype>]\n" + "SERIALNO [--demand=<serialno>] [<apptype>]\n" "\n" "Return the serial number of the card using a status response. This\n" "function should be used to check for the presence of a card.\n" "\n" + "If --demand is given, an application on the card with SERIALNO is\n" + "selected and an error is returned if no such card available.\n" + "\n" "If APPTYPE is given, an application of that type is selected and an\n" "error is returned if the application is not supported or available.\n" "The default is to auto-select the application using a hardwired\n" @@ -245,17 +265,29 @@ cmd_serialno (assuan_context_t ctx, char *line) int rc = 0; char *serial; time_t stamp; + const char *demand; - /* Clear the remove flag so that the open_card is able to reread it. */ - if (ctrl->server_local->card_removed) - { - if ( IS_LOCKED (ctrl) ) - return gpg_error (GPG_ERR_LOCKED); + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_LOCKED); - ctrl->server_local->card_removed = 0; + if ((demand = has_option_name (line, "--demand"))) + { + if (*demand != '=') + return set_error (GPG_ERR_ASS_PARAMETER, "missing value for option"); + line = (char *)++demand; + for (; *line && !spacep (line); line++) + ; + if (*line) + *line++ = 0; } + else + demand = NULL; + + /* Clear the remove flag so that the open_card is able to reread it. */ + if (ctrl->server_local->card_removed) + ctrl->server_local->card_removed = 0; - if ((rc = open_card (ctrl, *line? line:NULL, 1))) + if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand))) { ctrl->server_local->card_removed = 1; return rc; @@ -357,7 +389,7 @@ cmd_learn (assuan_context_t ctx, char *line) int rc = 0; int only_keypairinfo = has_option (line, "--keypairinfo"); - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; /* Unless the force option is used we try a shortcut by identifying @@ -440,7 +472,7 @@ cmd_readcert (assuan_context_t ctx, char *line) unsigned char *cert; size_t ncert; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; line = xstrdup (line); /* Need a copy of the line. */ @@ -482,7 +514,7 @@ cmd_readkey (assuan_context_t ctx, char *line) unsigned char *pk; size_t pklen; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (has_option (line, "--advanced")) @@ -704,7 +736,7 @@ cmd_pksign (assuan_context_t ctx, char *line) line = skip_options (line); - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; /* We have to use a copy of the key ID because the function may use @@ -748,7 +780,7 @@ cmd_pkauth (assuan_context_t ctx, char *line) size_t outdatalen; char *keyidstr; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (!ctrl->app_ctx) @@ -793,7 +825,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) char *keyidstr; unsigned int infoflags; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; keyidstr = xtrystrdup (line); @@ -846,7 +878,7 @@ cmd_getattr (assuan_context_t ctx, char *line) int rc; const char *keyword; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; keyword = line; @@ -888,7 +920,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) size_t nbytes; char *line, *linebuf; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; /* We need to use a copy of LINE, because PIN_CB uses the same @@ -943,7 +975,7 @@ cmd_writecert (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (!ctrl->app_ctx) @@ -1005,7 +1037,7 @@ cmd_writekey (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (!ctrl->app_ctx) @@ -1092,7 +1124,7 @@ cmd_genkey (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (!ctrl->app_ctx) @@ -1130,7 +1162,7 @@ cmd_random (assuan_context_t ctx, char *line) "number of requested bytes missing"); nbytes = strtoul (line, NULL, 0); - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (!ctrl->app_ctx) @@ -1183,7 +1215,7 @@ cmd_passwd (assuan_context_t ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (!ctrl->app_ctx) @@ -1240,7 +1272,7 @@ cmd_checkpin (assuan_context_t ctx, char *line) int rc; char *idstr; - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; if (!ctrl->app_ctx) @@ -1531,7 +1563,7 @@ cmd_apdu (assuan_context_t ctx, char *line) line = skip_options (line); - if ((rc = open_card (ctrl, NULL, 0))) + if ((rc = open_card (ctrl))) return rc; app = ctrl->app_ctx; |