[SSSD] [PATCHES] Add support for Smartcard authentication

Jakub Hrozek jhrozek at redhat.com
Mon Jul 27 10:35:45 UTC 2015


On Fri, Jul 17, 2015 at 09:01:49PM +0200, Sumit Bose wrote:
> On Fri, Jul 10, 2015 at 06:40:30PM +0200, Sumit Bose wrote:
> > Hi,
> > 
> > this is the initial version of my patch which add Smartcard
> > authentication to SSSD. I'm still working on a design page which will
> > explain everything in more details so I will only add a short version
> > here.
> > 
> > The main job will be done by a new child process called p11_child. Since
> > the Smartcard support in GDM is based on NSS I used NSS for the first
> > version of p11_child as well. But since all PKCS#11 (API to talk to
> > Smartcards) related code is in this child process adding support for
> > other PKCS#11 frameworks like p11-kit would be straight forward (in fact
> > I already started on the p11-kit version). Using NSS here means you have
> > to add the PKCS#11 module for your Smartcards reader to /etc/pki/nssdb
> > (the NSS DB GDM uses as well) with modutil or pk11install from the
> > coolkey package.
> > 
> > The PAM configuration so far must not be changed. pam_sss will do a
> > pre-auth request similar to the OPT case for find a suitable
> > authentication method for the user. The pam responder then checks is
> > Smartcard authentication is enabled (pam_cert_auth = True in the [pam]
> > section of sssd.conf), if the service is a local one and if there if a
> > valid certificate can be found which is available in the users LDAP
> > entry as well. If all this checks pass pam_sss will ask the user for a
> > PIN and then SSSD tries to validate that PIN, public and private keys
> > all relate to each other. If no Smartcard is found for the user the
> > standard password prompt is displayed.
> > 
> > With some valuable input form Christian Heimes I think I found a way to
> > test the Smartcard support even without real hardware but I still have
> > to work out some of the details. I will add instructions to the design
> > page and better and more unit tests.
> > 
> > Any comments and suggestions are welcome.
> 
> Please find attached an improved version of the patches. Especially
> there are improvements to the test, the return values from the p11_child
> are not mocked used the actual retrieved certificate data. The test data
> causes some increase in the patch size. I plan to replace this with data
> which is generate during the test run but for a start it is easier this
> way.
> 
> I also added a 7th patch which should resolve
> https://fedorahosted.org/sssd/ticket/2711 (SSH with certificates).
> Strictly it is not related to Smartcard authentication via PAM but it
> depends on the NSS version of the cert utilities (patch 0001) so I
> included it here as well.
> 
> On the design page I added the 'How to test' section
> https://fedorahosted.org/sssd/wiki/DesignDocs/SmartcardAuthenticationStep1#Howtotest
> which hopefully gives sufficient details how to set up a test
> environment.
> 
> bye,
> Sumit
> 

Hi,

I started the review, but because the patches are quite big, I will send
my comments in batches. I hope that's fine.

CI failed in distcheck.

Coverity found some issues that I forwarded to Sumit.

> From 97b6f25141c56f7d40446b7baf9780dacf8a822b Mon Sep 17 00:00:00 2001
> From: Sumit Bose <sbose at redhat.com>
> Date: Mon, 22 Jun 2015 16:36:36 +0200
> Subject: [PATCH 1/7] utils: add NSS version of cert utils

With this patch and p11_child being written with NSS, should the
downstreams switch to NSS only again and drop the openssl-devel
BuildRequires, as you did in the upstream specfile?

> 
> ---
>  Makefile.am                        |  29 ++++-
>  configure.ac                       |   4 +-
>  contrib/sssd.spec.in               |   1 -
>  src/tests/cmocka/test_cert_utils.c |   4 +
>  src/util/cert/nss/cert.c           | 211 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 243 insertions(+), 6 deletions(-)
>  create mode 100644 src/util/cert/nss/cert.c

[...]

> +errno_t sss_cert_der_to_pem(TALLOC_CTX *mem_ctx, const uint8_t *der_blob,
> +                            size_t der_size, char **pem, size_t *pem_size)
> +{
> +
> +    CERTCertDBHandle *handle;
> +    CERTCertificate *cert = NULL;
> +    SECItem der_item;
> +    char *ascii_crlf = NULL;
> +    size_t ascii_crlf_len;
> +    char *ascii_lf = NULL;
> +    char *pem_cert_str = NULL;
> +    int ret;
> +    size_t c;
> +    size_t d;
> +
> +    /* initialize NSS if needed */
> +    ret = nspr_nss_init();
> +    if (ret != EOK) {
> +        DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n");
> +        return ret;
> +    }
> +
> +    handle = CERT_GetDefaultCertDB();
> +
> +    der_item.len = der_size;
> +    der_item.data = discard_const(der_blob);
> +
> +    cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE , PR_TRUE);
                                                                      ~~~
If you end up changing this patch, please also remove the extra space.

> +    if (cert == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
> +        return EINVAL;
> +    }
> +
> +    ascii_crlf = BTOA_DataToAscii(cert->derCert.data, cert->derCert.len);
> +    if (ascii_crlf == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "BTOA_DataToAscii failed.\n");
> +        ret = EIO;
> +        goto done;
> +    }
> +
> +    ascii_crlf_len = strlen(ascii_crlf) + 1;
> +    ascii_lf = malloc(ascii_crlf_len * sizeof(char));

Any reason to use malloc and not talloc here? Using talloc would protect
against leaks better, I think, if we forget to free ascii_lf here, but
mem_ctx goes away later.

> +    if (ascii_lf == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "malloc failed.\n");
> +        ret = ENOMEM;
> +        goto done;
> +    }
> +
> +    d = 0;
> +    for (c = 0; c < ascii_crlf_len; c++) {
> +        if (ascii_crlf[c] != '\r') {
> +            ascii_lf[d++] = ascii_crlf[c];
> +        }
> +    }
> +
> +    pem_cert_str = talloc_asprintf(mem_ctx, "%s\n%s\n%s\n", NS_CERT_HEADER,
> +                                                            ascii_lf,
> +                                                            NS_CERT_TRAILER);
> +    if (pem_cert_str == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
> +        ret = ENOMEM;
> +        goto done;
> +    }
> +
> +    if (pem_size != NULL) {
> +        *pem_size = strlen(pem_cert_str);
> +    }
> +
> +    if (pem != NULL) {
> +        *pem = pem_cert_str;
> +        pem_cert_str = NULL;
> +    }
> +
> +    ret = EOK;
> +done:
> +    talloc_free(pem_cert_str);
> +    free(ascii_crlf);

It would be better to use PORT_free() to stick with NSPR API because the
buffer is already created with NSS/NSPR.

> +    free(ascii_lf);
> +    CERT_DestroyCertificate(cert);
> +
> +    return ret;
> +}
> +
> +errno_t sss_cert_pem_to_der(TALLOC_CTX *mem_ctx, const char *pem,
> +                            uint8_t **_der_blob, size_t *_der_size)
> +{
> +    const char *ps;
> +    const char *pe;
> +    size_t pem_len;
> +    uint8_t *der_blob = NULL;
> +    size_t der_size;
> +    CERTCertDBHandle *handle;
> +    CERTCertificate *cert = NULL;
> +    SECItem der_item;
> +    int ret;
> +    char *b64 = NULL;
> +
> +    /* initialize NSS if needed */
> +    ret = nspr_nss_init();
> +    if (ret != EOK) {
> +        DEBUG(SSSDBG_OP_FAILURE, "nspr_nss_init failed.\n");
> +        return ret;
> +    }
> +
> +    if (pem == NULL || *pem == '\0') {
> +        return EINVAL;
> +    }
> +
> +    pem_len = strlen(pem);
> +    if (pem_len <= NS_CERT_HEADER_LEN + NS_CERT_TRAILER_LEN) {
> +        DEBUG(SSSDBG_CRIT_FAILURE, "PEM data too short.\n");
> +        return EINVAL;
> +    }
> +
> +    if (strncmp(pem, NS_CERT_HEADER, NS_CERT_HEADER_LEN) != 0) {
> +        DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM header.\n");
> +        return EINVAL;
> +    }
> +    if (pem[NS_CERT_HEADER_LEN] != '\n') {
> +        DEBUG(SSSDBG_CRIT_FAILURE, "Missing newline in PEM data.\n");
> +        return EINVAL;
> +    }
> +
> +    pe = pem + pem_len - NS_CERT_TRAILER_LEN;
> +    if (pem[pem_len - 1] == '\n') {
> +        pe--;
> +    }
> +    if (strncmp(pe, NS_CERT_TRAILER, NS_CERT_TRAILER_LEN) != 0) {
> +        DEBUG(SSSDBG_CRIT_FAILURE, "Wrong PEM trailer.\n");
> +        return EINVAL;
> +    }
> +
> +    ps = pem + NS_CERT_HEADER_LEN + 1;
> +
> +    b64 = talloc_strndup(mem_ctx, ps, pe - ps);
> +    if(b64 == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
> +        ret = ENOMEM;
> +        goto done;
> +    }
> +
> +    der_blob = ATOB_AsciiToData(b64, &der_size);
> +    if (der_blob == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "ATOB_AsciiToData failed.\n");
> +        return EIO;
> +    }
> +
> +    handle = CERT_GetDefaultCertDB();
> +
> +    der_item.len = der_size;
> +    der_item.data = der_blob;
> +
> +    cert = CERT_NewTempCertificate(handle, &der_item, NULL, PR_FALSE , PR_TRUE);
                                                                      ~~
                                                                    Extra
                                                                    space
> +    if (cert == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "CERT_NewTempCertificate failed.\n");
> +        ret = EINVAL;
> +        goto done;
> +    }
> +
> +    if (_der_blob != NULL) {
> +        *_der_blob = talloc_memdup(mem_ctx, cert->derCert.data,
> +                                   cert->derCert.len);
> +        if (*_der_blob == NULL) {
> +            DEBUG(SSSDBG_OP_FAILURE, "talloc_memdup failed.\n");
> +            ret = ENOMEM;
> +            goto done;
> +        }
> +    }
> +
> +    if (_der_size != NULL) {
> +        *_der_size = cert->derCert.len;
> +    }
> +done:
> +    free(der_blob);

PORT_free() would be nicer here as well.

> +    talloc_free(b64);
> +    CERT_DestroyCertificate(cert);
> +
> +    return ret;
> +}
> -- 
> 2.1.0
> 

> From 14532dbe323aa18c48b02c7d2178b2cb85c19e72 Mon Sep 17 00:00:00 2001
> From: Sumit Bose <sbose at redhat.com>
> Date: Fri, 10 Jul 2015 12:10:53 +0200
> Subject: [PATCH 2/7] Add NSS version of p11_child
> 
> ---
>  Makefile.am                   |  25 +-
>  src/p11_child/p11_child_nss.c | 634 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 658 insertions(+), 1 deletion(-)
>  create mode 100644 src/p11_child/p11_child_nss.c

[...]

>  endif
> +if HAVE_NSS
> +	-chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/p11_child
> +	chmod 4750 $(DESTDIR)$(sssdlibexecdir)/p11_child

Because this patch adds a setuid executable, I would prefer if the
specfile change that also specifies the ownership and permissions of the
executable was part of this patch.

> +endif
>  endif
>  
>  install-data-hook:
> diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c

In general my NSS knowledge is lacking a bit here. It would be helpful
if you could add some comments (see inline). Also, did you follow some
particular NSS documentation? Or another code that is using NSS (this is
mostly for my education)

The code looks mostly good to me, though, just a couple of small picks..

> new file mode 100644
> index 0000000000000000000000000000000000000000..63e6ded7f6dbb2c5f05c085eb40082cf7f992b98
> --- /dev/null
> +++ b/src/p11_child/p11_child_nss.c
> @@ -0,0 +1,634 @@
> +/*
> +    SSSD
> +
> +    Helper child to commmunicate with SamrtCard via NSS
                                         ~~~~~~~~
                                        typo
> +
> +    Authors:
> +        Sumit Bose <sbose at redhat.com>
> +
> +    Copyright (C) 2015 Red Hat
> +
> +    This program is free software; you can redistribute it and/or modify
> +    it under the terms of the GNU General Public License as published by
> +    the Free Software Foundation; either version 3 of the License, or
> +    (at your option) any later version.
> +
> +    This program is distributed in the hope that it will be useful,
> +    but WITHOUT ANY WARRANTY; without even the implied warranty of
> +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +    GNU General Public License for more details.
> +
> +    You should have received a copy of the GNU General Public License
> +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +*/

[...]

> +static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg)
> +{
> +  /* give up if 1) no password was supplied, or 2) the password has already
> + *    * been rejected once by this token. */

This comment is strangely formatted

> +  if (retry || (arg == NULL)) {
> +    return NULL;
> +  }
> +  return PL_strdup((char *)arg);
> +}
> +
> +
> +
> +int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in,
> +            enum op_mode mode, const char *pin, char **cert,
> +            char **token_name_out)
> +{
> +    int ret;
> +    SECStatus rv;
> +    NSSInitContext *nss_ctx;
> +    SECMODModuleList *mod_list;
> +    SECMODModuleList *mod_list_item;
> +    const char *slot_name;
> +    const char *token_name;
> +    uint32_t flags = NSS_INIT_READONLY
> +                                   | NSS_INIT_FORCEOPEN
> +                                   | NSS_INIT_NOROOTINIT
> +                                   | NSS_INIT_OPTIMIZESPACE
> +                                   | NSS_INIT_PK11RELOAD;
> +    NSSInitParameters parameters = { 0 };
> +    parameters.length =  sizeof (parameters);
> +    PK11SlotInfo *slot = NULL;
> +    CK_SLOT_ID slot_id;
> +    SECMODModuleID module_id;
> +    CERTCertList *cert_list = NULL;
> +    CERTCertListNode *cert_list_node;
> +    const PK11DefaultArrayEntry friendly_attr = { "Publicly-readable certs",
> +                                                  SECMOD_FRIENDLY_FLAG,
> +                                                  CKM_INVALID_MECHANISM };
> +    CERTCertDBHandle *handle;
> +    unsigned char random_value[128];
> +    SECKEYPrivateKey *priv_key;
> +    SECOidTag algtag;
> +    SECItem signed_random_value = {0};
> +    SECKEYPublicKey *pub_key;
> +    CERTCertificate *found_cert = NULL;
> +    PK11SlotList *list = NULL;
> +    PK11SlotListElement *le;
> +
> +
> +    nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters, flags);
> +    if (nss_ctx == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d].\n",
> +                                 PR_GetError());
> +        return EIO;
> +    }
> +
> +    PK11_SetPasswordFunc(password_passthrough);
> +
> +    DEBUG(SSSDBG_TRACE_ALL, "Default Module List:\n");
> +    mod_list = SECMOD_GetDefaultModuleList();
> +    for (mod_list_item = mod_list; mod_list_item != NULL;
> +                                   mod_list_item = mod_list_item->next) {
> +        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n",
> +                                mod_list_item->module->commonName);
> +        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n",
> +                                mod_list_item->module->dllName);
> +    }
> +
> +    DEBUG(SSSDBG_TRACE_ALL, "Dead Module List:\n");

What does "dead module" mean?

> +    mod_list = SECMOD_GetDeadModuleList();
> +    for (mod_list_item = mod_list; mod_list_item != NULL;
> +                                   mod_list_item = mod_list_item->next) {
> +        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n",
> +                                mod_list_item->module->commonName);
> +        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n",
> +                                mod_list_item->module->dllName);
> +    }
> +
> +    DEBUG(SSSDBG_TRACE_ALL, "DB Module List:\n");
> +    mod_list = SECMOD_GetDeadModuleList();

Did you really mean to call SECMOD_GetDeadModuleList() twice?

> +    for (mod_list_item = mod_list; mod_list_item != NULL;
> +                                   mod_list_item = mod_list_item->next) {
> +        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n",
> +                                mod_list_item->module->commonName);
> +        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n",
> +                                mod_list_item->module->dllName);
> +    }
> +
> +    if (slot_name_in != NULL) {
> +        slot = PK11_FindSlotByName(slot_name_in);
> +        if (slot == NULL) {
> +            DEBUG(SSSDBG_OP_FAILURE, "PK11_FindSlotByName failed for [%s]: [%d].\n",
> +                                     slot_name_in, PR_GetError());
> +            return EIO;
> +        }
> +    } else {
> +
> +        list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE,
> +                                 NULL);
> +        if (list == NULL) {
> +            DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n");
> +            return EIO;
> +        }
> +
> +        for (le = list->head; le; le = le->next) {
> +            CK_SLOT_INFO slInfo;
> +
> +            slInfo.flags = 0;
> +            rv = PK11_GetSlotInfo(le->slot, &slInfo);
> +            DEBUG(SSSDBG_TRACE_ALL,
> +                  "Description [%s] Manufacturer [%s] flags [%lu].\n",
> +                  slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags);
> +            if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
> +                slot = PK11_ReferenceSlot(le->slot);
> +                break;
> +           }
> +        }
> +        PK11_FreeSlotList(list);
> +        if (slot == NULL) {
> +            DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n");
> +            return EIO;
> +        }
> +    }
> +
> +
> +    slot_id = PK11_GetSlotID(slot);
> +    module_id = PK11_GetModuleID(slot);
> +    slot_name = PK11_GetSlotName(slot);
> +    token_name = PK11_GetTokenName(slot);
> +    DEBUG(SSSDBG_TRACE_ALL, "Found [%s] in slot [%s][%d] of module [%d].\n",
> +          token_name, slot_name, (int) slot_id, (int) module_id);
> +
> +    if (PK11_IsFriendly(slot)) {
> +        DEBUG(SSSDBG_TRACE_ALL, "Token is friendly.\n");

What does it mean for a token to be friendly? man modutil says it's when
certificates are publicly readable, I guess that's it?

> +    } else {
> +        DEBUG(SSSDBG_TRACE_ALL,
> +              "Token is NOT friendly.\n");
> +        if (mode == OP_PREAUTH) {
> +            DEBUG(SSSDBG_TRACE_ALL, "Trying to switch to friendly to read certificate.\n");
> +            rv = PK11_UpdateSlotAttribute(slot, &friendly_attr, PR_TRUE);
> +            if (rv != SECSuccess) {
> +                DEBUG(SSSDBG_OP_FAILURE,
> +                      "PK11_UpdateSlotAttribute failed, continue.\n");
> +            }
> +        }
> +    }
> +
> +    /* TODO: check  PK11_ProtectedAuthenticationPath() and return the result */
> +    if (mode == OP_AUTH || PK11_NeedLogin(slot)) {
> +        DEBUG(SSSDBG_TRACE_ALL, "Login required.\n");
> +        if (pin != NULL) {
> +            rv = PK11_Authenticate(slot, PR_FALSE, discard_const(pin));
> +            if (rv !=  SECSuccess) {
> +                DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d].\n",
> +                                         PR_GetError());
> +                return EIO;
> +            }
> +        } else {
> +            DEBUG(SSSDBG_CRIT_FAILURE,
> +                  "Login required but no pin available, continue.\n");
> +        }
> +    } else {
> +        DEBUG(SSSDBG_TRACE_ALL, "Login NOT required.\n");
> +    }
> +
> +    cert_list = PK11_ListCertsInSlot(slot);
> +    if (cert_list == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d].\n",
> +                                 PR_GetError());
> +        return EIO;
> +    }
> +
> +    for (cert_list_node = CERT_LIST_HEAD(cert_list);
> +                !CERT_LIST_END(cert_list_node, cert_list);
> +                cert_list_node = CERT_LIST_NEXT(cert_list_node)) {
> +        if (cert_list_node->cert) {
> +            DEBUG(SSSDBG_TRACE_ALL, "found cert[%s][%s]\n",
> +                             cert_list_node->cert->nickname,
> +                             cert_list_node->cert->subjectName);
> +        } else {
> +            DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n");
> +        }
> +    }
> +
> +    rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE);
> +    if (rv != SECSuccess) {
> +        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d].\n",
> +                                 PR_GetError());
> +        return EIO;
> +    }
> +
> +    rv = CERT_FilterCertListForUserCerts(cert_list);
> +    if (rv != SECSuccess) {
> +        DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListForUserCerts failed: [%d].\n",
> +                                 PR_GetError());
> +        return EIO;
> +    }
> +
> +
> +    handle = CERT_GetDefaultCertDB();
> +    if (handle == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d].\n",
> +                                 PR_GetError());
> +        return EIO;
> +    }
> +
> +
> +    found_cert = NULL;
> +    DEBUG(SSSDBG_TRACE_ALL, "Filtered certificates:\n");
> +    for (cert_list_node = CERT_LIST_HEAD(cert_list);
> +                !CERT_LIST_END(cert_list_node, cert_list);
> +                cert_list_node = CERT_LIST_NEXT(cert_list_node)) {
> +        if (cert_list_node->cert) {
> +            DEBUG(SSSDBG_TRACE_ALL, "found cert[%s][%s]\n",
> +                             cert_list_node->cert->nickname,
> +                             cert_list_node->cert->subjectName);
> +
> +            if (found_cert == NULL) {
> +                found_cert = cert_list_node->cert;
> +            } else {
> +                DEBUG(SSSDBG_TRACE_ALL, "More than one certificate found, " \
> +                                        "using just the first one.\n");
> +            }
> +        } else {
> +            DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n");
> +        }
> +    }
> +
> +    if (found_cert == NULL) {
> +        DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n");
> +        *cert = NULL;
> +        *token_name_out = NULL;
> +        ret = EOK;
> +        goto done;
> +    }
> +
> +    rv = CERT_VerifyCertificateNow(handle, found_cert, PR_TRUE,
> +                                   certificateUsageSSLClient, NULL, NULL);

Is the comment in cert_to_ssh_key() still valid since we run
CERT_VerifyCertificateNow here?

> +    if (rv != SECSuccess) {
> +        DEBUG(SSSDBG_OP_FAILURE,
> +              "CERT_VerifyCertificateNow failed [%d].\n",
> +              PR_GetError());
> +        ret = EIO;
> +        goto done;
> +    }
> +

[...]

> +int main(int argc, const char *argv[])
> +{
> +    int opt;
> +    poptContext pc;
> +    int debug_fd = -1;
> +    errno_t ret;
> +    TALLOC_CTX *main_ctx = NULL;
> +    char *cert;
> +    enum op_mode mode = OP_NONE;
> +    enum pin_mode pin_mode = PIN_NONE;
> +    char *pin = NULL;
> +    char *slot_name_in = NULL;
> +    char *token_name_out = NULL;
> +    char *nss_db = NULL;
> +
> +    struct poptOption long_options[] = {
> +        POPT_AUTOHELP
> +        {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0,
> +         _("Debug level"), NULL},
> +        {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0,
> +         _("Add debug timestamps"), NULL},
> +        {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0,
> +         _("Show timestamps with microseconds"), NULL},
> +        {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
> +         _("An open file descriptor for the debug logs"), NULL},
> +        {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN,
> +         &debug_to_stderr, 0,
> +         _("Send the debug output to stderr directly."), NULL },
> +        {"auth", 0, POPT_ARG_NONE, NULL, 'a', _("Run in auth mode"), NULL},
> +        {"pre", 0, POPT_ARG_NONE, NULL, 'p', _("Run in pre-auth mode"), NULL},
> +        {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL},
> +        {"keypad", 0, POPT_ARG_NONE, NULL, 'k', _("Expect PIN on keypad"),
> +         NULL},
> +        {"nssdb", 0, POPT_ARG_STRING, &nss_db, 0, _("NSS DB to use"),
> +         NULL},
> +        POPT_TABLEEND
> +    };
> +
> +    /* Set debug level to invalid value so we can decide if -d 0 was used. */
> +    debug_level = SSSDBG_INVALID;
> +
> +    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
> +    while((opt = poptGetNextOpt(pc)) != -1) {
           ~~
        Please put a space here.

> +        switch(opt) {
> +        case 'a':
> +            if (mode != OP_NONE) {
> +                fprintf(stderr,
> +                        "\n--auth and --pre are mutually exclusive and " \
> +                        "should be only used once.\n\n");
> +                poptPrintUsage(pc, stderr, 0);
> +                _exit(-1);
> +            }
> +            mode = OP_AUTH;
> +            break;

> From f004acdd79dfafb3c89a57e1b11950f2f5c3345e Mon Sep 17 00:00:00 2001
> From: Sumit Bose <sbose at redhat.com>
> Date: Fri, 26 Jun 2015 14:45:21 +0200
> Subject: [PATCH 3/7] pack_message_v3: allow empty name

ACK, we do the same for service already.



More information about the sssd-devel mailing list