summaryrefslogtreecommitdiffstats
path: root/lib/libaccess/nscert.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libaccess/nscert.cpp')
-rw-r--r--lib/libaccess/nscert.cpp963
1 files changed, 963 insertions, 0 deletions
diff --git a/lib/libaccess/nscert.cpp b/lib/libaccess/nscert.cpp
new file mode 100644
index 00000000..97939b24
--- /dev/null
+++ b/lib/libaccess/nscert.cpp
@@ -0,0 +1,963 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Description (nsadb.c)
+ *
+ * This module contains routines for accessing and storing information
+ * in a Netscape client certificate to username database. This
+ * database is used to associate a username with a client certificate
+ * that is presented to a server.
+ */
+
+#if defined(CLIENT_AUTH)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#include <base/fsmutex.h>
+#include <libaccess/nsdbmgmt.h>
+#define __PRIVATE_NSADB
+#include <libaccess/nsadb.h>
+#include <libaccess/nsamgmt.h>
+
+static FSMUTEX nscert_lock = 0;
+
+NSAPI_PUBLIC int nsadbCertInitialize(void)
+{
+#ifdef XP_UNIX
+ nscert_lock = fsmutex_init("NSCERTMAP", geteuid(),
+ FSMUTEX_VISIBLE|FSMUTEX_NEEDCRIT);
+#else /* XP_WIN32 */
+ char winuser[128];
+ DWORD wulength;
+ strcpy(winuser, "NSCERTMAP_");
+ wulength = 128 - 11;
+ GetUserName(winuser+10, &wulength);
+ nscert_lock = fsmutex_init(winuser, 0,
+ FSMUTEX_VISIBLE|FSMUTEX_NEEDCRIT);
+#endif
+ return (nscert_lock == 0) ? -1 : 0;
+}
+
+NSAPI_PUBLIC int nsadbDecodeCertRec(int reclen, char * recptr,
+ CertObj_t * coptr)
+{
+ ATR_t cp = (ATR_t)recptr; /* current pointer into record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+
+ /* Parse user DB record */
+ while ((cp - (ATR_t)recptr) < reclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case CAT_USERNAME: /* username associated with cert */
+ cp = NTSDECODE(cp, (NTS_t *)&coptr->co_username);
+ break;
+
+ case CAT_CERTID: /* certificate-to-user map id */
+ cp = USIDECODE(cp, &coptr->co_certid);
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Description (nsadbDecodeCertKey)
+ *
+ * This function decodes information from a certificate key.
+ * Currently a certificate key includes the DER encoding of the
+ * issuer and subject distinguished names. This is used to
+ * uniquely identify client certificates, even across certificate
+ * renewals. SECItems for the issuer and subject are provided
+ * by the caller. These are updated with the pointers and lengths
+ * of DER encodings, which can be decoded using nsadbDecodeCertName()
+ * into SECName structures. The returned SECItems refer to data
+ * in the provided key buffer.
+ *
+ * Arguments:
+ *
+ * keylen - length of the certificate key encoding
+ * keyptr - buffer containing certificate key encoding
+ * issuer - pointer to SECItem for returning issuer
+ * subject - pointer to SECItem for returning subject
+ *
+ * Returns:
+ *
+ * Zero is returned if no errors are encountered. Otherwise -1.
+ */
+
+NSAPI_PUBLIC int nsadbDecodeCertKey(int keylen, char * keyptr,
+ SECItem * issuer, SECItem * subject)
+{
+ ATR_t cp = (ATR_t)keyptr; /* current pointer into DB record */
+ USI_t len; /* attribute value encoding length */
+ USI_t tag; /* attribute tag */
+
+ /* Parse user DB record */
+ while ((cp - (ATR_t)keyptr) < keylen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case KAT_ISSUER: /* issuer DER encoding */
+ issuer->len = len;
+ issuer->data = cp;
+ cp += len;
+ break;
+
+ case KAT_SUBJECT: /* subject name DER encoding */
+ subject->len = len;
+ subject->data = cp;
+ cp += len;
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Description (nsadbEncodeCertKey)
+ *
+ * This function encodes information provided by the caller into
+ * a certificate key. The certificate key is returned in a
+ * buffer obtained from MALLOC().
+ *
+ * Arguments:
+ *
+ * issuer - pointer to SECItem for issuer DER
+ * subject - pointer to SECItem for subject DER
+ * keylen - returned length of certificate key
+ * keyptr - returned pointer to buffer containing
+ * certificate key encoding
+ *
+ * Returns:
+ *
+ * Zero is returned if no errors are encountered. Otherwise -1.
+ */
+
+NSAPI_PUBLIC int nsadbEncodeCertKey(SECItem * issuer, SECItem * subject,
+ int * keylen, char **keyptr)
+{
+ ATR_t cp; /* pointer into key buffer */
+ ATR_t kptr; /* pointer to key buffer */
+ int klen; /* length of key */
+ int rv = -1;
+
+ /* Compute length of key encoding */
+ klen = 1 + USILENGTH(issuer->len) + issuer->len +
+ 1 + USILENGTH(subject->len) + subject->len;
+
+ /* Allocate buffer to contain the key */
+ kptr = (ATR_t)MALLOC(klen);
+ if (kptr) {
+ /* Encode issuer and subject as attributes */
+ cp = kptr;
+ *cp++ = KAT_ISSUER;
+ cp = USIENCODE(cp, issuer->len);
+ memcpy(cp, issuer->data, issuer->len);
+ cp += issuer->len;
+ *cp++ = KAT_SUBJECT;
+ cp = USIENCODE(cp, subject->len);
+ memcpy(cp, subject->data, subject->len);
+ rv = 0;
+ }
+
+ /* Return length and buffer pointer */
+ if (keylen) *keylen = klen;
+ *keyptr = (char *)kptr;
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumCertsHelp)
+ *
+ * This is a local function that is called by NSDB during certificate
+ * to user database enumeration. It decodes certificate records into
+ * CertObj_t structures, and presents them to the caller of
+ * nsadbEnumerateCerts(), via the specified call-back function.
+ * The call-back function return value may be a negative error code,
+ * which will cause enumeration to stop, and the error code will be
+ * returned from nsadbEnumerateCerts(). If the return value of the
+ * call-back function is not negative, it can contain one or more of
+ * the following flags:
+ *
+ * ADBF_KEEPOBJ - do not free the CertObj_t structure
+ * that was passed to the call-back function
+ * ADBF_STOPENUM - stop the enumeration without an error
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to CertEnumArgs_t structure
+ * keylen - certificate record key length
+ * keyptr - certificate record key
+ * reclen - length of certificate record
+ * recptr - pointer to certificate record contents
+ *
+ * Returns:
+ *
+ * If the call-back returns a negative result, that value is
+ * returned. If the call-back returns ADBF_STOPENUM, then
+ * -1 is returned, causing the enumeration to stop. Otherwise
+ * the return value is zero.
+ */
+
+typedef struct CertEnumArgs_s CertEnumArgs_t;
+struct CertEnumArgs_s {
+ int rv; /* just a return value */
+ void * client; /* the current key for lookup */
+ void * authdb; /* the authentication data base */
+ CertEnumCallback func; /* client's callback function */
+};
+
+static int nsadbEnumCertsHelp(NSErr_t * errp, void * parg,
+ int keylen, char * keyptr,
+ int reclen, char * recptr)
+{
+ CertEnumArgs_t * ce = (CertEnumArgs_t *)parg;
+ CertObj_t * coptr;
+ int rv = NSAERRNOMEM;
+
+ /* Allocate a CertObj_t structure and initialize it */
+ coptr = (CertObj_t *)MALLOC(sizeof(CertObj_t));
+ if (coptr) {
+
+ coptr->co_issuer.data = 0;
+ coptr->co_subject.data = 0;
+ coptr->co_username = 0;
+ coptr->co_certid = 0;
+
+ /* Decode the certificate key */
+ rv = nsadbDecodeCertKey(keylen, keyptr,
+ &coptr->co_issuer, &coptr->co_subject);
+
+ /* Decode the certificate record */
+ rv = nsadbDecodeCertRec(reclen, recptr, coptr);
+
+ /* Pass the CertObj_t to the callback function */
+ rv = (*ce->func)(errp, ce->authdb, ce->client, coptr);
+ if (rv >= 0) {
+
+ /* Count the number of records seen */
+ ce->rv += 1;
+
+ /* Free the user object unless the call-back says not to */
+ if (!(rv & ADBF_KEEPOBJ)) {
+ nsadbFreeCertObj(coptr);
+ }
+ /* Return either 0 or -1, depending on ADBF_STOPENUM */
+ rv = (rv & ADBF_STOPENUM) ? -1 : 0;
+ }
+ else {
+ /* return the error code */
+ ce->rv = rv;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumerateClients)
+ *
+ * (See description for nsadbEnumerateUsers)
+ */
+
+NSAPI_PUBLIC int nsadbEnumerateCerts(NSErr_t * errp, void * authdb,
+ void * argp, CertEnumCallback func)
+{
+ AuthDB_t * adb = (AuthDB_t*)authdb;
+ CertEnumArgs_t helper_data;
+ int rv;
+
+ /* Open the certificate subdatabase for read access */
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv >= 0) {
+ helper_data.authdb = authdb;
+ helper_data.func = func;
+ helper_data.client = argp;
+ helper_data.rv = 0;
+
+ rv = ndbEnumerate(errp, adb->adb_certdb, NDBF_ENUMNORM,
+ (void*)&helper_data, nsadbEnumCertsHelp);
+ }
+
+ return (rv < 0) ? rv: helper_data.rv;
+}
+
+NSAPI_PUBLIC void nsadbFreeCertObj(CertObj_t * coptr)
+{
+ if (coptr) {
+ FREE(coptr->co_username);
+ FREE(coptr);
+ }
+}
+
+NSAPI_PUBLIC int nsadbGetCertById(NSErr_t * errp, void * authdb,
+ USI_t certid, CertObj_t **coptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ CertObj_t * cop = 0;
+ char * keyptr;
+ char * recptr;
+ int keylen;
+ int reclen;
+ int rv;
+
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+
+ /* Get the name corresponding to the id */
+ rv = ndbIdToName(errp, adb->adb_certdb, certid, &keylen, &keyptr);
+ if (rv < 0) goto punt;
+
+ rv = ndbFindName(errp, adb->adb_certdb,
+ keylen, keyptr, &reclen, &recptr);
+ if (rv < 0) goto punt;
+
+ /* Allocate a CertObj_t structure and initialize it */
+ cop = (CertObj_t *)MALLOC(sizeof(CertObj_t));
+ if (cop) {
+
+ cop->co_issuer.data = 0;
+ cop->co_subject.data = 0;
+ cop->co_username = 0;
+ cop->co_certid = 0;
+
+ /* Decode the certificate key */
+ rv = nsadbDecodeCertKey(keylen, keyptr,
+ &cop->co_issuer, &cop->co_subject);
+
+ /* Decode the certificate record */
+ rv = nsadbDecodeCertRec(reclen, recptr, cop);
+
+ }
+
+ punt:
+ if (coptr) *coptr = cop;
+ return rv;
+}
+
+/*
+ * Description (nsadbGetUserByCert)
+ *
+ * This function looks up a specified client certificate in the
+ * authentication database. It returns a pointer to the username
+ * associated with the client certificate, if any. The username
+ * buffer remains valid until the authentication database is
+ * closed.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * cert - pointer to client certificate
+ * username - pointer to returned user name (or null)
+ *
+ * Returns:
+ *
+ * The return value will be zero if the certificate is found. Also,
+ * *username will be set to the string value of the associated username
+ * iff username is not null.
+ */
+
+NSAPI_PUBLIC int nsadbGetUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert, char **username)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t cp; /* current pointer into DB record */
+ char * user = 0; /* pointer to username */
+ char * keyptr = 0; /* pointer to cert key */
+ char * recptr; /* pointer to cert db record */
+ int keylen; /* length of cert key */
+ int reclen; /* length of cert db record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+ int rv;
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&cert->derIssuer, &cert->derSubject,
+ &keylen, &keyptr);
+
+ if (adb->adb_certdb == NULL) {
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+ }
+
+ rv = ndbFindName(errp, adb->adb_certdb,
+ keylen, keyptr, &reclen, &recptr);
+ if (rv < 0) goto punt;
+
+ /* Parse cert DB record */
+ cp = (ATR_t)recptr;
+
+ while ((cp - (ATR_t)recptr) < reclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* We want the CAT_USERNAME attribute */
+ if (tag == CAT_USERNAME) {
+
+ /* Get the username associated with the cert */
+ user = (char *)cp;
+ break;
+ }
+
+ /* Just skip other attributes */
+ cp += len;
+ }
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ if (username) *username = user;
+ return rv;
+}
+
+/*
+ * Description (see description for nsadbOpenUsers)
+ */
+
+int nsadbOpenCerts(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t *adb = (AuthDB_t*)authdb;
+ char *dbname = NULL; /* user database name */
+ int dblen; /* strlen(adb_dbname) */
+ int version; /* database version */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ if (adb == NULL) goto err_inval;
+
+ /* Is the user database already open? */
+ if (adb->adb_certdb != 0) {
+
+ /* Yes, is it open for the desired access? */
+ if (adb->adb_flags & flags) {
+
+ /* Yes, that was easy */
+ return 0;
+ }
+ }
+ else {
+ /* Allocate space for the user database filename */
+ dblen = strlen(adb->adb_dbname);
+
+ dbname = (char *)MALLOC(dblen + strlen(ADBCERTDBNAME) + 2);
+ if (dbname == 0) goto err_nomem;
+
+ /* Construct user database name */
+ strcpy(dbname, adb->adb_dbname);
+
+ /* Put in a '/' (or '\') if it's not there */
+ if (dbname[dblen-1] != FILE_PATHSEP) {
+ dbname[dblen] = FILE_PATHSEP;
+ dbname[dblen+1] = 0;
+ ++dblen;
+ }
+
+ strcpy(&dbname[dblen], ADBCERTDBNAME);
+
+ if (nscert_lock == 0) {
+ rv = nsadbCertInitialize();
+ if (rv < 0) goto err_lock;
+ }
+ adb->adb_certlock = nscert_lock;
+ if (adb->adb_certlock == 0) goto punt;
+
+ fsmutex_lock((FSMUTEX)(adb->adb_certlock));
+
+ adb->adb_certdb = ndbOpen(errp,
+ dbname, 0, NDB_TYPE_CLIENTDB, &version);
+ if (adb->adb_certdb == 0) {
+ fsmutex_unlock((FSMUTEX)(adb->adb_certlock));
+ goto err_open;
+ }
+ }
+
+ /*
+ * We don't really reopen the database to get the desired
+ * access mode, since that is handled at the nsdb level.
+ * But we do update the flags, just for the record.
+ */
+ adb->adb_flags &= ~(ADBF_CREAD|ADBF_CWRITE);
+ if (flags & ADBF_CWRITE) adb->adb_flags |= ADBF_CWRITE;
+ else adb->adb_flags |= ADBF_CREAD;
+ rv = 0;
+
+ punt:
+ if (dbname != NULL) FREE(dbname);
+ return rv;
+
+ err_inval:
+ eid = NSAUERR3400;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ eid = NSAUERR3420;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_lock:
+ eid = NSAUERR3430;
+ rv = NSAERRLOCK;
+ goto err_ret;
+
+ err_open:
+ eid = NSAUERR3440;
+ rv = NSAERROPEN;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, dbname);
+ goto punt;
+
+}
+
+NSAPI_PUBLIC void nsadbCloseCerts(void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+
+ if (adb->adb_certnm != 0) {
+ /* Close the username-to-certid database */
+ nsadbCloseCertUsers(authdb, flags);
+ }
+
+ if (adb->adb_certdb != 0) {
+
+ ndbClose(adb->adb_certdb, 0);
+ adb->adb_certdb = 0;
+
+ /*
+ * A lock is held for the certificate map DB as long as it is
+ * open, so release the lock now.
+ */
+ fsmutex_unlock((FSMUTEX)(adb->adb_certlock));
+ }
+}
+
+/*
+ * Description (nsadbOpenCertUsers)
+ *
+ * This function opens a database that maps user names to client
+ * certificates. The database appears as "Certs.nm" in the
+ * authentication database directory. This function requires
+ * that the primary certificate database be opened (Certs.db)
+ * first, and will open it if necessary, acquiring a global
+ * lock in the process. The lock will not be released until
+ * nsadbCloseCerts() or nsadbClose() is called.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * flags - same as nsadbOpenCerts()
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful.
+ * Otherwise a negative error code is returned.
+ */
+
+NSAPI_PUBLIC int nsadbOpenCertUsers(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * dbname = 0;
+ int dblen;
+ int oflags = O_RDONLY; /* assume read-only access */
+ int eid;
+ int rv;
+
+ /* The primary certificate mapping database must be open first */
+ if (adb->adb_certdb != 0) {
+
+ /* It's open, but is it read-only when we need write? */
+ if (((flags & adb->adb_flags) == 0) && (flags & ADBF_CWRITE)) {
+
+ /* Yes, close it */
+ nsadbCloseCerts(authdb, 0);
+ }
+ }
+
+ /* Open it for the desired access if necessary */
+ if (adb->adb_certdb == 0) {
+ /*
+ * Open it for the desired access. Note that this acquires
+ * a global lock which is not released until nsadbClose() is
+ * called for the entire authentication database.
+ */
+ rv = nsadbOpenCerts(errp, authdb, flags);
+ if (rv < 0) {
+ /* Go no further if that failed */
+ return rv;
+ }
+ }
+
+ /* Now look at the username-to-certid database in particular */
+ if (adb->adb_certnm && (adb->adb_flags & flags)) {
+
+ /* The database is already open for the desired access */
+ return 0;
+ }
+
+ dblen = strlen(adb->adb_dbname);
+ dbname = (char *)MALLOC(dblen + strlen(ADBUMAPDBNAME) + 2);
+ strcpy(dbname, adb->adb_dbname);
+ if (dbname[dblen-1] != FILE_PATHSEP) {
+ dbname[dblen] = FILE_PATHSEP;
+ dbname[++dblen] = 0;
+ }
+ strcpy(&dbname[dblen], ADBUMAPDBNAME);
+
+ /* Check for write access and set open flags appropriately if so */
+ if (flags & ADBF_CWRITE) {
+ oflags = O_CREAT|O_RDWR;
+ }
+
+ /* Open the username-to-certid database */
+// adb->adb_certnm = dbopen(dbname, oflags, 0644, DB_HASH, 0);
+ adb->adb_certnm = 0;
+ if (adb->adb_certnm == 0) goto err_open;
+
+ punt:
+ FREE(dbname);
+
+ return rv;
+
+ err_open:
+ eid = NSAUERR3600;
+ rv = NSAERROPEN;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, dbname);
+ goto punt;
+}
+
+/*
+ * Description (nsadbFindCertUser)
+ *
+ * This function checks to see whether a client certificate is
+ * registered for a specified user name. If so, it returns the
+ * certificate mapping id (for use with nsadbGetCertById()).
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * username - pointer to user name string
+ * id - pointer to returned certificate mapping id
+ *
+ * Returns:
+ *
+ * If a certificate is registered for the specified user, the return
+ * value is zero and the certificate mapping id is returned via 'id'.
+ * Otherwise the return value is a negative error code (nsautherr.h)
+ * and an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbFindCertUser(NSErr_t * errp, void * authdb,
+ const char * username, USI_t * id)
+{
+ int eid;
+ int rv;
+ eid = NSAUERR3700;
+ rv = NSAERRNAME;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+/*
+ * Description (nsadbAddCertUser)
+ *
+ * This function adds an entry to the username-to-cert id database,
+ * with a given username and certificate mapping id.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * username - pointer to user name string
+ * id - certificate mapping id
+ *
+ * Returns:
+ *
+ * If the entry is added successfully, the return value is zero.
+ * Otherwise the return value is a negative error code (nsautherr.h)
+ * and an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbAddCertUser(NSErr_t * errp, void * authdb,
+ const char * username, USI_t id)
+{
+ /* Need to be ported on NSS 3.2 */
+ int eid;
+ int rv;
+
+ eid = NSAUERR3800;
+ rv = NSAERRPUT;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+NSAPI_PUBLIC int nsadbRemoveCertUser(NSErr_t * errp, void * authdb,
+ char * username)
+{
+ /* Need to be ported on NSS 3.2 */
+ int eid;
+ int rv;
+
+ eid = NSAUERR3800;
+ rv = NSAERRPUT;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+NSAPI_PUBLIC void nsadbCloseCertUsers(void * authdb, int flags)
+{
+ /* Need to be ported on NSS 3.2 */
+}
+
+/*
+ * Description (nsadbPutUserByCert)
+ *
+ * This function looks up a stores a client certificate mapping
+ * in the authentication database along with the associated username.
+ * It assumes that a record with the specified certificate key does
+ * not already exist, and will replace it if it does.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * certLen - length of the certificate key
+ * cert - certificate key pointer
+ * user - username to be associated with the
+ * certificate
+ *
+ * Returns:
+ *
+ */
+
+NSAPI_PUBLIC int nsadbPutUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert,
+ const char * username)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t cp; /* pointer into cert record contents */
+ char * keyptr = 0; /* pointer to cert record key */
+ char * recptr = 0; /* pointer to cert record contents */
+ int keylen; /* length of cert record key */
+ int reclen; /* length of cert record contents */
+ USI_t certid;
+ int usrlen;
+ int certidlen;
+ int eid;
+ int rv;
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&cert->derIssuer, &cert->derSubject,
+ &keylen, &keyptr);
+
+ /* Open the username-to-cert id database for write */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CWRITE);
+ if (rv) goto punt;
+
+ /* If the username is already mapped to a cert, it's an error */
+ certid = 0;
+ rv = nsadbFindCertUser(errp, authdb, username, &certid);
+ if (rv == 0) goto err_map;
+
+ /*
+ * Allocate a certificate id and write a record mapping this id
+ * to the specified certificate key.
+ */
+ certid = 0;
+ rv = ndbAllocId(errp, adb->adb_certdb, keylen, keyptr, &certid);
+ if (rv) goto punt;
+
+ /* Record the username as being mapped to the allocated cert id */
+ rv = nsadbAddCertUser(errp, authdb, username, certid);
+ if (rv < 0) goto punt;
+
+ nsadbCloseCertUsers(authdb, 0);
+
+ /*
+ * First we need to figure out how long the generated record will be.
+ * This doesn't have to be exact, but it must not be smaller than the
+ * actual record size.
+ */
+
+ /* CAT_USERNAME attribute: tag, length, NTS */
+ usrlen = NTSLENGTH(username);
+ if (usrlen > 127) goto err_user;
+ reclen = 2 + usrlen;
+
+ /* CAT_CERTID attribute: tag, length, USI */
+ certidlen = USILENGTH(certid);
+ reclen += 2 + certidlen;
+
+ /* Allocate the attribute record buffer */
+ recptr = (char *)MALLOC(reclen);
+ if (recptr) {
+
+ cp = (ATR_t)recptr;
+
+ /* Encode CAT_USERNAME attribute */
+ *cp++ = CAT_USERNAME;
+ *cp++ = usrlen;
+ cp = NTSENCODE(cp, (NTS_t)username);
+
+ /* Encode CAT_CERTID attribute */
+ *cp++ = CAT_CERTID;
+ *cp++ = certidlen;
+ cp = USIENCODE(cp, certid);
+ }
+
+ /* Store the record in the database under the certificate key */
+ rv = ndbStoreName(errp, adb->adb_certdb,
+ 0, keylen, keyptr, reclen, recptr);
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ if (recptr) {
+ FREE(recptr);
+ }
+
+ return rv;
+
+ err_user:
+ eid = NSAUERR3500;
+ rv = NSAERRINVAL;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adb->adb_dbname);
+ goto punt;
+
+ err_map:
+ eid = NSAUERR3520;
+ rv = NSAERRCMAP;
+ nsadbCloseCertUsers(authdb, 0);
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adb->adb_dbname);
+ goto punt;
+}
+
+NSAPI_PUBLIC int nsadbRemoveCert(NSErr_t * errp, void * authdb,
+ void * username, CertObj_t * coptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * keyptr = 0; /* pointer to cert record key */
+ int keylen; /* length of cert record key */
+ int rv;
+ int rv2;
+
+ /* If a username is specified, require it to match */
+ if (username && strcmp((char *)username, coptr->co_username)) {
+ return 0;
+ }
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&coptr->co_issuer, &coptr->co_subject,
+ &keylen, &keyptr);
+
+ if (adb->adb_certdb == NULL) {
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CWRITE);
+ if (rv < 0) goto punt;
+ }
+
+ /* Remove the username-to-cert id entry from Certs.nm */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CWRITE);
+ if (rv < 0) goto punt;
+ rv = nsadbRemoveCertUser(errp, authdb, coptr->co_username);
+ nsadbCloseCertUsers(authdb, 0);
+
+ /* Free the cert id value, if any */
+ rv = 0;
+ if (coptr->co_certid != 0) {
+ rv = ndbFreeId(errp, adb->adb_certdb,
+ keylen, keyptr, coptr->co_certid);
+ }
+
+ /* Delete the cert record */
+ rv2 = ndbDeleteName(errp, adb->adb_certdb, 0, keylen, keyptr);
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ return (rv) ? rv : rv2;
+}
+
+NSAPI_PUBLIC int nsadbRemoveUserCert(NSErr_t * errp,
+ void * authdb, char * username)
+{
+ CertObj_t * coptr = 0;
+ USI_t certid = 0;
+ int rv;
+
+ /*
+ * Open for read access at first. We don't want to create the
+ * database if it's not already there. This will do nothing
+ * if the database is already open for write, since that implies
+ * read access as well.
+ */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+
+ /* Find a certificate mapping id for the given username */
+ rv = nsadbFindCertUser(errp, authdb, username, &certid);
+ if (rv < 0) goto punt;
+
+ /* Look up the mapping from the mapping id */
+ rv = nsadbGetCertById(errp, authdb, certid, &coptr);
+ if (rv < 0) goto punt;
+
+ /* It's there, so remove it. This will re-open for write if needed. */
+ rv = nsadbRemoveCert(errp, authdb, (void *)username, coptr);
+
+ punt:
+
+ if (coptr != 0) {
+ nsadbFreeCertObj(coptr);
+ }
+
+ return rv;
+}
+
+#endif /* defined(CLIENT_AUTH) */