/* certificates.c -- Certificate management * * GPLv2 only - Copyright (C) 2008 - 2010 * David Sommerseth * * 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; version 2 * of the License. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ /** * @file sqlite/administration/certificates.c * @author David Sommerseth * @date 2009-09-13 * * @brief Certificate management functions * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef DRIVER_MODE #define DRIVER_MODE #endif #include #include "../sqlite.h" #define FMAP_CERTS /**< fieldmapping.h: Include declaration of tbl_sqlite_certs */ #include "../fieldmapping.h" /** * Internal function. Retrieves info about one or more certificates * * @param ctx eurephiaCTX * @param srch_map eDBfieldMap defining the query * @param sortkeys String containing the sort order of the fields * * @return Returns a valid xmlDoc containing the query, * or a eurephia XML document with an error message. */ static xmlDoc *certificate_list(eurephiaCTX *ctx, eDBfieldMap *srch_map, const char *sortkeys) { xmlDoc *certlist = NULL; xmlNode *cert_n = NULL, *tmp_n = NULL; eDBfieldMap *ptr = NULL; dbresult *res = NULL; xmlChar tmp[2050]; int i; DEBUG(ctx, 21, "Function call: certificates_list(ctx, fieldMap, '%s')", sortkeys); assert( (ctx != NULL) && (srch_map != NULL) ); // Replace spaces with underscore in common name and // in organisation fields, to comply with OpenVPN standards for( ptr = srch_map; ptr != NULL; ptr = ptr->next ) { if( ptr->field_id & (FIELD_CNAME | FIELD_ORG) ) { xmlReplaceChars((xmlChar *) ptr->value, ' ', '_'); } } res = sqlite_query_mapped(ctx, SQL_SELECT, "SELECT depth, lower(digest), common_name, organisation, email, " " registered, certid" " FROM openvpn_certificates", NULL, srch_map, sortkeys); if( res == NULL ) { eurephia_log(ctx, LOG_ERROR, 0, "Could not query the certificate table"); return eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Could not query the database for certificate info"); } memset(&tmp, 0, 2050); eurephiaXML_CreateDoc(ctx, 1, "certificates", &certlist, &cert_n); xmlStrPrintf(tmp, 64, (xmlChar *) "%i", sqlite_get_numtuples(res)); xmlNewProp(cert_n, (xmlChar *) "certificates", (xmlChar *) tmp); for( i = 0; i < sqlite_get_numtuples(res); i++ ) { tmp_n = xmlNewChild(cert_n, NULL, (xmlChar *) "certificate", NULL); sqlite_xml_value(tmp_n, XML_ATTR, "certid", res, i, 6); sqlite_xml_value(tmp_n, XML_ATTR, "depth", res, i, 0); sqlite_xml_value(tmp_n, XML_ATTR, "registered", res, i, 5); sqlite_xml_value(tmp_n, XML_NODE, "digest", res, i, 1); xmlStrPrintf(tmp, 2048, (xmlChar *) "%.2048s", sqlite_get_value(res, i, 2)); xmlReplaceChars(tmp, '_', ' '); xmlNewChild(tmp_n, NULL, (xmlChar *) "common_name", tmp); xmlStrPrintf(tmp, 2048, (xmlChar *) "%.2048s", sqlite_get_value(res, i, 3)); xmlReplaceChars(tmp, '_', ' '); xmlNewChild(tmp_n, NULL, (xmlChar *) "organisation", tmp); sqlite_xml_value(tmp_n, XML_NODE, "email", res, i, 4); } sqlite_free_results(res); return certlist; } /** * Internal function. Registers a new certificate and saves it in the database * * @param ctx eurephiaCTX * @param crtinf_map eDBfieldMap containing certificate info to be registered * * @return Returns an eurephia ResultMsg XML document with a result string. On fatal errors, * NULL is returned */ static xmlDoc *certificate_add(eurephiaCTX *ctx, eDBfieldMap *crtinf_map) { xmlDoc *res_d = NULL; xmlNode *info_n = NULL; eDBfieldMap *ptr = NULL; dbresult *res = NULL; DEBUG(ctx, 21, "Function call: certificate_add(ctx, xmlDoc)"); assert( (ctx != NULL) && (crtinf_map != NULL) ); if( (ctx->context_type != ECTX_ADMIN_CONSOLE) && (ctx->context_type != ECTX_ADMIN_WEB) ) { eurephia_log(ctx, LOG_CRITICAL, 0, "eurephia admin function call attempted with wrong context type"); return NULL; } // Replace spaces with underscore in common name and // in organisation fields, to comply with OpenVPN standards for( ptr = crtinf_map; ptr != NULL; ptr = ptr->next ) { if( ptr->field_id & (FIELD_CNAME | FIELD_ORG) ) { xmlReplaceChars((xmlChar *) ptr->value, ' ', '_'); } } // Register the certificate res = sqlite_query_mapped(ctx, SQL_INSERT, "INSERT INTO openvpn_certificates", crtinf_map, NULL, NULL); if( res == NULL ) { eurephia_log(ctx, LOG_FATAL, 0, "Could not register the certificate"); res_d = eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Could not register the certificate"); } else { xmlChar *certid = malloc_nullsafe(ctx, 34); assert( certid != NULL ); // Prepare an information tag/node with the certid value xmlStrPrintf(certid, 32, (xmlChar *) "%ld", res->last_insert_id); info_n = xmlNewNode(NULL, (xmlChar *)"certificate"); xmlNewProp(info_n, (xmlChar *) "certid", certid); res_d = eurephiaXML_ResultMsg(ctx, exmlRESULT, info_n, "Certificate registered (certid %ld)", res->last_insert_id); xmlFreeNode(info_n); } sqlite_free_results(res); return res_d; } /** * Internal function. Deletes one or more certificates from the database * * @param ctx eurephiaCTX * @param crtinf_map eDBfieldMap with information about certificate(s) to delete * * @return Returns an eurephia ResultMsg XML document with a result string. On fatal errors, * NULL is returned */ static xmlDoc *certificate_delete(eurephiaCTX *ctx, eDBfieldMap *crtinf_map) { xmlDoc *res_d = NULL; eDBfieldMap *ptr = NULL; dbresult *res = NULL; DEBUG(ctx, 21, "Function call: certificate_delete(ctx, xmlDoc)"); assert( (ctx != NULL) && (crtinf_map != NULL) ); if( (ctx->context_type != ECTX_ADMIN_CONSOLE) && (ctx->context_type != ECTX_ADMIN_WEB) ) { eurephia_log(ctx, LOG_CRITICAL, 0, "eurephia admin function call attempted with wrong context type"); return NULL; } // Replace spaces with underscore in common name and // in organisation fields, to comply with OpenVPN standards for( ptr = crtinf_map; ptr != NULL; ptr = ptr->next ) { if( ptr->field_id & (FIELD_CNAME | FIELD_ORG) ) { xmlReplaceChars((xmlChar *) ptr->value, ' ', '_'); } } // Register the certificate res = sqlite_query_mapped(ctx, SQL_DELETE, "DELETE FROM openvpn_certificates", NULL, crtinf_map, NULL); if( res == NULL ) { eurephia_log(ctx, LOG_FATAL, 0, "Could not complete the delete certificate request"); res_d = eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Could not delete the certificate(s)"); } else { res_d = eurephiaXML_ResultMsg(ctx, exmlRESULT, NULL, "%i %s deleted", sqlite_get_affected_rows(res), (sqlite_get_affected_rows(res) != 1 ? "certificates":"certificate") ); } sqlite_free_results(res); return res_d; } /** * @copydoc eDBadminCertificate() */ xmlDoc *eDBadminCertificate(eurephiaCTX *ctx, xmlDoc *qryxml) { eDBfieldMap *fmap = NULL; char *mode = NULL; xmlDoc *resxml = NULL; xmlNode *root_n = NULL, *fieldmap_n = NULL; DEBUG(ctx, 20, "Function call: eDBadminCertificate(ctx, {xmlDoc})"); assert( (ctx != NULL) && (qryxml != NULL) ); if( (ctx->context_type != ECTX_ADMIN_CONSOLE) && (ctx->context_type != ECTX_ADMIN_WEB) ) { eurephia_log(ctx, LOG_CRITICAL, 0, "eurephia admin function call attempted with wrong context type"); return NULL; } root_n = eurephiaXML_getRoot(ctx, qryxml, "certificates", 1); if( root_n == NULL ) { eurephia_log(ctx, LOG_CRITICAL, 0, "Invalid XML input."); return NULL; } mode = xmlGetAttrValue(root_n->properties, "mode"); if( mode == NULL ) { eurephia_log(ctx, LOG_ERROR, 0, "Missing mode attribute"); return NULL; } fieldmap_n = xmlFindNode(root_n, "fieldMapping"); if( fieldmap_n == NULL ) { eurephia_log(ctx, LOG_ERROR, 0, "Missing fieldMapping"); return NULL; } fmap = eDBxmlMapping(ctx, tbl_sqlite_certs, NULL, fieldmap_n); if( strcmp(mode, "list") == 0 ) { char *sortkeys = xmlGetNodeContent(root_n, "sortkeys"); resxml = certificate_list(ctx, fmap, eDBmkSortKeyString(fmap, sortkeys)); } else if( strcmp(mode, "register") == 0 ) { resxml = certificate_add(ctx, fmap); } else if( strcmp(mode, "delete") == 0 ) { resxml = certificate_delete(ctx, fmap); } else { eurephia_log(ctx, LOG_ERROR, 0, "Certificates - Unknown mode: '%s'", mode); resxml = eurephiaXML_ResultMsg(ctx, exmlERROR, NULL, "Unknown mode '%s'", mode); } eDBfreeMapping(fmap); return resxml; }