providers.c revision 677a31351c80453d9ce006481364399a96312052
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen/*
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen SSSD
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen Secrets Responder
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen Copyright (C) Simo Sorce <ssorce@redhat.com> 2016
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen This program is free software; you can redistribute it and/or modify
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen it under the terms of the GNU General Public License as published by
ed51404d355ae65d762cee68aefdbf900903a658Timo Sirainen the Free Software Foundation; either version 3 of the License, or
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen (at your option) any later version.
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen This program is distributed in the hope that it will be useful,
4afaedfcbd43896befbe1fd5c10eba42246f3fdeTimo Sirainen but WITHOUT ANY WARRANTY; without even the implied warranty of
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen GNU General Public License for more details.
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen You should have received a copy of the GNU General Public License
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen along with this program. If not, see <http://www.gnu.org/licenses/>.
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen*/
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen#include "responder/secrets/secsrv_private.h"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen#include "responder/secrets/secsrv_local.h"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen#include "responder/secrets/secsrv_proxy.h"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen#include "util/sss_iobuf.h"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen#include <jansson.h>
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainentypedef int (*url_mapper_fn)(struct sec_req_ctx *secreq,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen char **mapped_path);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainenstruct url_pfx_router {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen const char *prefix;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen url_mapper_fn mapper_fn;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen};
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainenstatic int sec_map_url_to_user_path(struct sec_req_ctx *secreq,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen char **mapped_path)
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen{
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen uid_t c_euid;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen c_euid = client_euid(secreq->cctx->creds);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen /* change path to be user specific */
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen *mapped_path =
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen talloc_asprintf(secreq, SEC_BASEPATH"users/%"SPRIuid"/%s",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen c_euid,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen &secreq->parsed_url.path[sizeof(SEC_BASEPATH) - 1]);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!*mapped_path) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Failed to map request to user specific url\n");
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen return ENOMEM;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
6454ff63651123d9f7e6ef6d84e69d60dbe29167Timo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_TRACE_LIBS,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "User-specific secrets path is [%s]\n", *mapped_path);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen return EOK;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen}
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainenstatic int kcm_map_url_to_path(struct sec_req_ctx *secreq,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen char **mapped_path)
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen{
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen uid_t c_euid;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen c_euid = client_euid(secreq->cctx->creds);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (c_euid != KCM_PEER_UID) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "UID %"SPRIuid" is not allowed to access "
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "the "SEC_KCM_BASEPATH" hive\n",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen c_euid);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return EPERM;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen *mapped_path = talloc_strdup(secreq, secreq->parsed_url.path );
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!*mapped_path) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Failed to map request to user specific url\n");
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen return ENOMEM;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen DEBUG(SSSDBG_TRACE_LIBS,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "User-specific KCM path is [%s]\n", *mapped_path);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen return EOK;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainenstatic struct url_pfx_router secrets_url_mapping[] = {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { SEC_BASEPATH, sec_map_url_to_user_path },
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen { SEC_KCM_BASEPATH, kcm_map_url_to_path },
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen { NULL, NULL },
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen};
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct provider_handle **handle)
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen{
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen struct sec_ctx *sctx;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen char **sections;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen char *def_provider;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen char *provider;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen int num_sections;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen int ret;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen url_mapper_fn mapper_fn = NULL;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sctx = talloc_get_type(secreq->cctx->rctx->pvt_ctx, struct sec_ctx);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen for (int i = 0; secrets_url_mapping[i].prefix != NULL; i++) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (strncasecmp(secreq->parsed_url.path,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen secrets_url_mapping[i].prefix,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen strlen(secrets_url_mapping[i].prefix)) == 0) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_TRACE_LIBS,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen "Mapping prefix %s\n", secrets_url_mapping[i].prefix);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen mapper_fn = secrets_url_mapping[i].mapper_fn;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen break;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (mapper_fn == NULL) {
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Path [%s] does not start with any allowed prefix\n",
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen secreq->parsed_url.path);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen return EPERM;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ret = mapper_fn(secreq, &secreq->mapped_path);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (ret != EOK) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_CRIT_FAILURE,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "Failed to map the user path [%d]: %s\n",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen ret, sss_strerror(ret));
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen return ret;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen /* source default provider */
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen ret = confdb_get_string(secreq->cctx->rctx->cdb, mem_ctx,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen CONFDB_SEC_CONF_ENTRY, "provider", "LOCAL",
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen &def_provider);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (ret) return EIO;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "The default provider is '%s'\n", def_provider);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen ret = confdb_get_sub_sections(mem_ctx, secreq->cctx->rctx->cdb,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen CONFDB_SEC_CONF_ENTRY, &sections,
f185133819c115c8cbc1c7e96804f237e23d255cTimo Sirainen &num_sections);
ed51404d355ae65d762cee68aefdbf900903a658Timo Sirainen if (ret != EOK) return ret;
ed51404d355ae65d762cee68aefdbf900903a658Timo Sirainen
ed51404d355ae65d762cee68aefdbf900903a658Timo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
f185133819c115c8cbc1c7e96804f237e23d255cTimo Sirainen "confdb section %s has %d sub-sections\n",
f185133819c115c8cbc1c7e96804f237e23d255cTimo Sirainen CONFDB_SEC_CONF_ENTRY, num_sections);
f185133819c115c8cbc1c7e96804f237e23d255cTimo Sirainen
f185133819c115c8cbc1c7e96804f237e23d255cTimo Sirainen provider = def_provider;
ed51404d355ae65d762cee68aefdbf900903a658Timo Sirainen
ed51404d355ae65d762cee68aefdbf900903a658Timo Sirainen // TODO order by length?
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen for (int i = 0; i < num_sections; i++) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen int slen;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen secreq->base_path = talloc_asprintf(secreq, SEC_BASEPATH"%s/", sections[i]);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!secreq->base_path) return ENOMEM;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen slen = strlen(secreq->base_path);
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "matching subsection [%s]\n", sections[i]);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (strncmp(secreq->base_path, secreq->mapped_path, slen) == 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen char *secname;
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen secname = talloc_asprintf(mem_ctx, CONFDB_SEC_CONF_ENTRY"/%s",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sections[i]);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!secname) return ENOMEM;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen provider = NULL;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen ret = confdb_get_string(secreq->cctx->rctx->cdb, mem_ctx,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen secname, "provider", def_provider,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen &provider);
f185133819c115c8cbc1c7e96804f237e23d255cTimo Sirainen if (ret || !provider) return EIO;
f185133819c115c8cbc1c7e96804f237e23d255cTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "matched subsection %s with provider %s\n",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen sections[i], provider);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen secreq->cfg_section = talloc_steal(secreq, secname);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!secreq->cfg_section) return ENOMEM;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen break;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen talloc_zfree(secreq->base_path);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!secreq->base_path) secreq->base_path = SEC_BASEPATH;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Request base path is [%s]\n", secreq->base_path);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "Request provider is [%s]\n", provider);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen ret = sec_get_provider(sctx, provider, handle);
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen if (ret == ENOENT) {
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen if (strcasecmp(provider, "LOCAL") == 0) {
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen ret = local_secrets_provider_handle(sctx, handle);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen } else if (strcasecmp(provider, "PROXY") == 0) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen ret = proxy_secrets_provider_handle(sctx, handle);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen } else {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_FATAL_FAILURE,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Unknown provider type: %s\n", provider);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen ret = EIO;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen if (ret == EOK) {
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen ret = sec_add_provider(sctx, *handle);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen }
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen return ret;
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen}
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainenint sec_provider_recv(struct tevent_req *req) {
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen TEVENT_REQ_RETURN_ON_ERROR(req);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_TRACE_INTERNAL, "Request finished\n");
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen return EOK;
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen}
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainenstatic struct sec_http_status_format_table {
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen int status;
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen const char *text;
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen const char *description;
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen} sec_http_status_format_table[] = {
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen { 200, "OK", "Success" },
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen { 400, "Bad Request",
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen "The request format is invalid." },
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen { 401, "Unauthorized",
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen "Access to the requested resource requires authentication." },
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen { 403, "Forbidden",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Access to the requested resource is forbidden." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { 404, "Not Found",
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "The requested resource was not found." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { 405, "Method Not Allowed",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Request method not allowed for this resource." },
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen { 406, "Not Acceptable",
2ef5254ab6b446b93ce7733bc96eeefa6f731ee4Timo Sirainen "The request cannot be accepted." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { 409, "Conflict",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "The requested resource already exists." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { 413, "Payload Too Large",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "The secret payload is too large." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { 500, "Internal Server Error",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "The server encountered an internal error." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { 504, "Gateway timeout",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "No response from a proxy server." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen { 507, "Insufficient Storage",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "The server is unable to store the resource needed to complete the request." },
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen};
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainenint sec_http_status_reply(TALLOC_CTX *mem_ctx, struct sec_data *reply,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen enum sec_http_status_codes code)
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen{
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen char *body = talloc_asprintf(mem_ctx,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "<html>\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "<head>\r\n<title>%d %s</title></head>\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "<body>\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "<h1>%s</h1>\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "<p>%s</p>\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "</body>",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].status,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].text,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].text,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].description);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!body) return ENOMEM;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen reply->data = talloc_asprintf(mem_ctx,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "HTTP/1.1 %d %s\r\n"
4afaedfcbd43896befbe1fd5c10eba42246f3fdeTimo Sirainen "Content-Length: %u\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "Content-Type: text/html\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "\r\n"
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "%s",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].status,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].text,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen (unsigned)strlen(body), body);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen talloc_free(body);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen if (!reply->data) return ENOMEM;
4afaedfcbd43896befbe1fd5c10eba42246f3fdeTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen reply->length = strlen(reply->data);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen DEBUG(SSSDBG_TRACE_LIBS,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen "HTTP reply %d: %s\n",
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].status,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen sec_http_status_format_table[code].text);
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen return EOK;
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen}
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainenint sec_http_reply_with_body(TALLOC_CTX *mem_ctx, struct sec_data *reply,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen enum sec_http_status_codes code,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen const char *content_type,
58c61ac5650583d21c891e61e051c614290d31fbTimo Sirainen struct sec_data *body)
{
int head_size;
reply->data = talloc_asprintf(mem_ctx,
"HTTP/1.1 %d %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %zu\r\n"
"\r\n",
sec_http_status_format_table[code].status,
sec_http_status_format_table[code].text,
content_type, body->length);
if (!reply->data) return ENOMEM;
head_size = strlen(reply->data);
reply->data = talloc_realloc(mem_ctx, reply->data, char,
head_size + body->length);
if (!reply->data) return ENOMEM;
memcpy(&reply->data[head_size], body->data, body->length);
reply->length = head_size + body->length;
DEBUG(SSSDBG_TRACE_LIBS,
"HTTP reply %d: %s\n",
sec_http_status_format_table[code].status,
sec_http_status_format_table[code].text);
return EOK;
}
int sec_http_append_header(TALLOC_CTX *mem_ctx, char **dest,
char *field, char *value)
{
if (*dest == NULL) {
*dest = talloc_asprintf(mem_ctx, "%s: %s\r\n", field, value);
} else {
*dest = talloc_asprintf_append_buffer(*dest, "%s: %s\r\n",
field, value);
}
if (!*dest) return ENOMEM;
return EOK;
}
int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply,
int status_code, const char *reason,
struct sec_kvp *headers, int num_headers,
struct sec_data *body)
{
const char *reason_phrase = reason ? reason : "";
bool add_content_length = true;
bool has_content_type = false;
int ret;
/* Status-Line */
reply->data = talloc_asprintf(mem_ctx, "HTTP/1.1 %d %s\r\n",
status_code, reason_phrase);
if (!reply->data) return ENOMEM;
DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d: %s\n", status_code, reason_phrase);
/* Headers */
for (int i = 0; i < num_headers; i++) {
if (strcasecmp(headers[i].name, "Content-Length") == 0) {
add_content_length = false;
} else if (strcasecmp(headers[i].name, "Content-Type") == 0) {
has_content_type = true;
}
ret = sec_http_append_header(mem_ctx, &reply->data,
headers[i].name, headers[i].value);
if (ret) return ret;
}
if (!has_content_type) {
DEBUG(SSSDBG_OP_FAILURE, "No Content-Type header\n");
return EINVAL;
}
if (add_content_length) {
reply->data = talloc_asprintf_append_buffer(reply->data,
"Content-Length: %u\r\n", (unsigned)body->length);
if (!reply->data) return ENOMEM;
}
/* CRLF separator before body */
reply->data = talloc_strdup_append_buffer(reply->data, "\r\n");
reply->length = strlen(reply->data);
/* Message-Body */
if (body && body->length) {
reply->data = talloc_realloc(mem_ctx, reply->data, char,
reply->length + body->length);
if (!reply->data) return ENOMEM;
memcpy(&reply->data[reply->length], body->data, body->length);
reply->length += body->length;
}
return EOK;
}
static errno_t
sec_http_iobuf_split(struct sss_iobuf *response,
const char **headers,
const char **body)
{
const char *data = (const char *)sss_iobuf_get_data(response);
char *delim;
/* The last header ends with \r\n and then comes \r\n again as a separator
* of body from headers. We can use this to find this point. */
delim = strstr(data, "\r\n\r\n");
if (delim == NULL) {
return EINVAL;
}
/* Skip to the body delimiter. */
delim = delim + sizeof("\r\n") - 1;
/* Replace \r\n with zeros turning data into:
* from HEADER\r\nBODY into HEADER\0\0BODY format. */
delim[0] = '\0';
delim[1] = '\0';
/* Split the buffer. */
*headers = data;
*body = delim + 2;
return 0;
}
static const char *
sec_http_iobuf_add_content_length(TALLOC_CTX *mem_ctx,
const char *headers,
size_t body_len)
{
/* If Content-Length is already present we do nothing. */
if (strstr(headers, "Content-Length:") != NULL) {
return headers;
}
return talloc_asprintf(mem_ctx, "%sContent-Length: %zu\r\n",
headers, body_len);
}
errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx,
struct sec_data *reply,
int response_code,
struct sss_iobuf *response)
{
const char *headers;
const char *body;
size_t body_len;
errno_t ret;
DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code);
ret = sec_http_iobuf_split(response, &headers, &body);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Unexpected HTTP reply, returning what we got from server\n");
reply->data = (char *)sss_iobuf_get_data(response);
reply->length = sss_iobuf_get_len(response);
return EOK;
}
/* Add Content-Length header if not present so client does not await
* not-existing incoming data. */
body_len = strlen(body);
headers = sec_http_iobuf_add_content_length(mem_ctx, headers, body_len);
if (headers == NULL) {
return ENOMEM;
}
reply->length = strlen(headers) + sizeof("\r\n") - 1 + body_len;
reply->data = talloc_asprintf(mem_ctx, "%s\r\n%s", headers, body);
if (reply->data == NULL) {
return ENOMEM;
}
return EOK;
}
enum sec_http_status_codes sec_errno_to_http_status(errno_t err)
{
DEBUG(SSSDBG_TRACE_LIBS, "Request errno: %d\n", err);
switch (err) {
case EOK:
return STATUS_200;
case EINVAL:
return STATUS_400;
case EACCES:
return STATUS_401;
case EPERM:
return STATUS_403;
case ENOENT:
return STATUS_404;
case EISDIR:
return STATUS_405;
case EMEDIUMTYPE:
case ERR_SEC_INVALID_CONTAINERS_NEST_LEVEL:
return STATUS_406;
case EEXIST:
return STATUS_409;
case ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE:
return STATUS_413;
case ERR_SEC_NO_PROXY:
return STATUS_504;
case ERR_SEC_INVALID_TOO_MANY_SECRETS:
return STATUS_507;
default:
return STATUS_500;
}
}
int sec_json_to_simple_secret(TALLOC_CTX *mem_ctx,
const char *input,
char **secret)
{
json_t *root;
json_t *element;
json_error_t error;
int ret;
root = json_loads(input, 0, &error);
if (!root) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to parse JSON payload on line %d: %s\n",
error.line, error.text);
return EINVAL;
}
if (!json_is_object(root)) {
DEBUG(SSSDBG_CRIT_FAILURE, "Json data is not an object.\n");
ret = EINVAL;
goto done;
}
element = json_object_get(root, "type");
if (!element) {
DEBUG(SSSDBG_CRIT_FAILURE, "Json data key 'type' not found.\n");
ret = EINVAL;
goto done;
}
if (!json_is_string(element)) {
DEBUG(SSSDBG_CRIT_FAILURE, "Json object 'type' is not a string.\n");
ret = EINVAL;
goto done;
}
if (strcmp(json_string_value(element), "simple") != 0) {
DEBUG(SSSDBG_CRIT_FAILURE, "Token type is not 'simple'.\n");
ret = EMEDIUMTYPE;
goto done;
}
element = json_object_get(root, "value");
if (!element) {
DEBUG(SSSDBG_CRIT_FAILURE, "Json key 'value' not found.\n");
ret = EINVAL;
goto done;
}
if (!json_is_string(element)) {
DEBUG(SSSDBG_CRIT_FAILURE, "Json object 'value' is not a string.\n");
ret = EINVAL;
goto done;
}
*secret = talloc_strdup(mem_ctx, json_string_value(element));
if (!*secret) {
ret = ENOMEM;
} else {
ret = EOK;
}
done:
json_decref(root);
return ret;
}
int sec_simple_secret_to_json(TALLOC_CTX *mem_ctx,
const char *secret,
char **output)
{
char *jsonized = NULL;
json_t *root;
int ret;
root = json_pack("{s:s, s:s}", "type", "simple", "value", secret);
if (!root) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to pack Json object\n");
return ENOMEM;
}
jsonized = json_dumps(root, JSON_INDENT(4));
if (!jsonized) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to dump Json object\n");
ret = ENOMEM;
goto done;
}
*output = talloc_strdup(mem_ctx, jsonized);
if (!*output) {
ret = ENOMEM;
goto done;
}
ret = EOK;
done:
json_decref(root);
free(jsonized);
return ret;
}
int sec_array_to_json(TALLOC_CTX *mem_ctx,
char **array, int count,
char **output)
{
char *jsonized = NULL;
json_t *root;
int ret;
root = json_array();
if (root == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to create Json array\n");
ret = ENOMEM;
goto done;
}
for (int i = 0; i < count; i++) {
// FIXME: json_string mem leak?
// FIXME: Error checking
json_array_append_new(root, json_string(array[i]));
}
jsonized = json_dumps(root, JSON_INDENT(4));
if (!jsonized) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to dump Json object\n");
ret = ENOMEM;
goto done;
}
*output = talloc_strdup(mem_ctx, jsonized);
if (!*output) {
ret = ENOMEM;
goto done;
}
ret = EOK;
done:
json_decref(root);
free(jsonized);
return ret;
}
int sec_get_provider(struct sec_ctx *sctx, const char *name,
struct provider_handle **out_handle)
{
struct provider_handle *handle;
for (int i = 0; sctx->providers && sctx->providers[i]; i++) {
handle = sctx->providers[i];
if (strcasecmp(handle->name, name) != 0) {
continue;
}
*out_handle = handle;
return EOK;
}
DEBUG(SSSDBG_MINOR_FAILURE, "No handle for provider %s\n", name);
return ENOENT;
}
int sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle)
{
int c;
for (c = 0; sctx->providers && sctx->providers[c]; c++)
continue;
sctx->providers = talloc_realloc(sctx, sctx->providers,
struct provider_handle *, c + 2);
if (!sctx->providers) return ENOMEM;
sctx->providers[c] = talloc_steal(sctx, handle);
sctx->providers[c + 1] = NULL;
return EOK;
}
bool sec_req_has_header(struct sec_req_ctx *req,
const char *name, const char *value)
{
for (int i = 0; i < req->num_headers; i++) {
if (strcasecmp(name, req->headers[i].name) == 0) {
if (value == NULL) return true;
return (strcasecmp(value, req->headers[i].value) == 0);
}
}
return false;
}