LCOV - code coverage report
Current view: top level - responder/ssh - sshsrv_cmd.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 481 0.0 %
Date: 2015-10-19 Functions: 0 22 0.0 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Jan Cholasta <jcholast@redhat.com>
       4             : 
       5             :     Copyright (C) 2012 Red Hat
       6             : 
       7             :     This program is free software; you can redistribute it and/or modify
       8             :     it under the terms of the GNU General Public License as published by
       9             :     the Free Software Foundation; either version 3 of the License, or
      10             :     (at your option) any later version.
      11             : 
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "config.h"
      22             : 
      23             : #include <talloc.h>
      24             : #include <string.h>
      25             : #include <netdb.h>
      26             : 
      27             : #include "util/util.h"
      28             : #include "util/crypto/sss_crypto.h"
      29             : #include "util/sss_ssh.h"
      30             : #include "util/cert.h"
      31             : #include "db/sysdb.h"
      32             : #include "db/sysdb_ssh.h"
      33             : #include "providers/data_provider.h"
      34             : #include "responder/common/responder.h"
      35             : #include "responder/common/responder_packet.h"
      36             : #include "responder/ssh/sshsrv_private.h"
      37             : 
      38             : static errno_t
      39             : ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx);
      40             : 
      41             : static errno_t
      42             : ssh_user_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx);
      43             : static errno_t
      44             : ssh_cmd_get_user_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx,
      45             :                               errno_t ret);
      46             : 
      47             : int
      48           0 : sss_ssh_cmd_get_user_pubkeys(struct cli_ctx *cctx)
      49             : {
      50             :     errno_t ret;
      51             :     struct ssh_cmd_ctx *cmd_ctx;
      52             : 
      53           0 :     cmd_ctx = talloc_zero(cctx, struct ssh_cmd_ctx);
      54           0 :     if (!cmd_ctx) {
      55           0 :         return ENOMEM;
      56             :     }
      57           0 :     cmd_ctx->cctx = cctx;
      58           0 :     cmd_ctx->is_user = true;
      59             : 
      60           0 :     ret = ssh_cmd_parse_request(cmd_ctx);
      61           0 :     if (ret != EOK) {
      62           0 :         goto done;
      63             :     }
      64             : 
      65           0 :     DEBUG(SSSDBG_TRACE_FUNC,
      66             :           "Requesting SSH user public keys for [%s] from [%s]\n",
      67             :            cmd_ctx->name, cmd_ctx->domname ? cmd_ctx->domname : "<ALL>");
      68             : 
      69           0 :     if (strcmp(cmd_ctx->name, "root") == 0) {
      70           0 :         ret = ENOENT;
      71           0 :         goto done;
      72             :     }
      73             : 
      74           0 :     if (cmd_ctx->domname) {
      75           0 :         cmd_ctx->domain = responder_get_domain(cctx->rctx, cmd_ctx->domname);
      76           0 :         if (!cmd_ctx->domain) {
      77           0 :             ret = ENOENT;
      78           0 :             goto done;
      79             :         }
      80             :     } else {
      81           0 :         cmd_ctx->domain = cctx->rctx->domains;
      82           0 :         cmd_ctx->check_next = true;
      83             :     }
      84             : 
      85           0 :     ret = ssh_user_pubkeys_search(cmd_ctx);
      86             : 
      87             : done:
      88           0 :     return ssh_cmd_get_user_pubkeys_done(cmd_ctx, ret);
      89             : }
      90             : 
      91             : static errno_t
      92             : ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx);
      93             : static errno_t
      94             : ssh_cmd_get_host_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx,
      95             :                               errno_t ret);
      96             : 
      97             : static int
      98           0 : sss_ssh_cmd_get_host_pubkeys(struct cli_ctx *cctx)
      99             : {
     100             :     errno_t ret;
     101             :     struct ssh_cmd_ctx *cmd_ctx;
     102             : 
     103           0 :     cmd_ctx = talloc_zero(cctx, struct ssh_cmd_ctx);
     104           0 :     if (!cmd_ctx) {
     105           0 :         return ENOMEM;
     106             :     }
     107           0 :     cmd_ctx->cctx = cctx;
     108           0 :     cmd_ctx->is_user = false;
     109             : 
     110           0 :     ret = ssh_cmd_parse_request(cmd_ctx);
     111           0 :     if (ret != EOK) {
     112           0 :         goto done;
     113             :     }
     114             : 
     115           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     116             :           "Requesting SSH host public keys for [%s][%s] from [%s]\n",
     117             :            cmd_ctx->name, cmd_ctx->alias ? cmd_ctx->alias : "",
     118             :            cmd_ctx->domname ? cmd_ctx->domname : "<ALL>");
     119             : 
     120           0 :     if (cmd_ctx->domname) {
     121           0 :         cmd_ctx->domain = responder_get_domain(cctx->rctx, cmd_ctx->domname);
     122           0 :         if (!cmd_ctx->domain) {
     123           0 :             ret = ENOENT;
     124           0 :             goto done;
     125             :         }
     126             :     } else {
     127           0 :         cmd_ctx->domain = cctx->rctx->domains;
     128           0 :         cmd_ctx->check_next = true;
     129             :     }
     130             : 
     131           0 :     ret = ssh_host_pubkeys_search(cmd_ctx);
     132             : 
     133             : done:
     134           0 :     return ssh_cmd_get_host_pubkeys_done(cmd_ctx, ret);
     135             : }
     136             : 
     137             : static void
     138           0 : ssh_dp_send_req_done(struct tevent_req *req)
     139             : {
     140           0 :     struct dp_callback_ctx *cb_ctx =
     141           0 :             tevent_req_callback_data(req, struct dp_callback_ctx);
     142             : 
     143             :     errno_t ret;
     144             :     dbus_uint16_t err_maj;
     145             :     dbus_uint32_t err_min;
     146             :     char *err_msg;
     147             : 
     148           0 :     ret = sss_dp_get_ssh_host_recv(cb_ctx->mem_ctx, req,
     149             :                                    &err_maj, &err_min,
     150             :                                    &err_msg);
     151           0 :     talloc_zfree(req);
     152           0 :     if (ret != EOK) {
     153           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     154             :               "Fatal error, killing connection!\n");
     155           0 :         talloc_free(cb_ctx->cctx);
     156           0 :         return;
     157             :     }
     158             : 
     159           0 :     cb_ctx->callback(err_maj, err_min, err_msg, cb_ctx->ptr);
     160             : }
     161             : 
     162             : static errno_t
     163             : ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx);
     164             : static void
     165             : ssh_user_pubkeys_search_dp_callback(uint16_t err_maj,
     166             :                                     uint32_t err_min,
     167             :                                     const char *err_msg,
     168             :                                     void *ptr);
     169             : 
     170             : static errno_t
     171           0 : ssh_user_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx)
     172             : {
     173             :     struct tevent_req *req;
     174             :     struct dp_callback_ctx *cb_ctx;
     175             : 
     176             :     /* if it is a domainless search, skip domains that require fully
     177             :      * qualified names instead */
     178           0 :     while (cmd_ctx->domain && cmd_ctx->check_next && cmd_ctx->domain->fqnames) {
     179           0 :         cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
     180             :     }
     181             : 
     182           0 :     if (!cmd_ctx->domain) {
     183           0 :         DEBUG(SSSDBG_OP_FAILURE,
     184             :               "No matching domain found for [%s], fail!\n", cmd_ctx->name);
     185           0 :         return ENOENT;
     186             :     }
     187             : 
     188             :     /* refresh the user's cache entry */
     189           0 :     if (NEED_CHECK_PROVIDER(cmd_ctx->domain->provider)) {
     190           0 :         req = sss_dp_get_account_send(cmd_ctx, cmd_ctx->cctx->rctx,
     191             :                                       cmd_ctx->domain, false, SSS_DP_USER,
     192           0 :                                       cmd_ctx->name, 0, NULL);
     193           0 :         if (!req) {
     194           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     195             :                   "Out of memory sending data provider request\n");
     196           0 :             return ENOMEM;
     197             :         }
     198             : 
     199           0 :         cb_ctx = talloc_zero(cmd_ctx, struct dp_callback_ctx);
     200           0 :         if (!cb_ctx) {
     201           0 :             talloc_zfree(req);
     202           0 :             return ENOMEM;
     203             :         }
     204             : 
     205           0 :         cb_ctx->callback = ssh_user_pubkeys_search_dp_callback;
     206           0 :         cb_ctx->ptr = cmd_ctx;
     207           0 :         cb_ctx->cctx = cmd_ctx->cctx;
     208           0 :         cb_ctx->mem_ctx = cmd_ctx;
     209             : 
     210           0 :         tevent_req_set_callback(req, ssh_dp_send_req_done, cb_ctx);
     211             : 
     212             :         /* tell caller we are in an async call */
     213           0 :         return EAGAIN;
     214             :     }
     215             : 
     216           0 :     return ssh_user_pubkeys_search_next(cmd_ctx);
     217             : }
     218             : 
     219             : static errno_t
     220           0 : ssh_user_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
     221             : {
     222             :     errno_t ret;
     223           0 :     const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, SYSDB_USER_CERT,
     224             :                             NULL };
     225             :     struct ldb_result *res;
     226             : 
     227           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     228             :           "Requesting SSH user public keys for [%s@%s]\n",
     229             :            cmd_ctx->name, cmd_ctx->domain->name);
     230             : 
     231           0 :     if (cmd_ctx->domain->sysdb == NULL) {
     232           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     233             :               "Fatal: Sysdb CTX not found for this domain!\n");
     234           0 :         return EFAULT;
     235             :     }
     236             : 
     237           0 :     ret = sysdb_get_user_attr_with_views(cmd_ctx, cmd_ctx->domain,
     238           0 :                                          cmd_ctx->name, attrs, &res);
     239           0 :     if (ret != EOK) {
     240           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     241             :               "Failed to make request to our cache!\n");
     242           0 :         return EIO;
     243             :     }
     244             : 
     245           0 :     if (res->count > 1) {
     246           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     247             :             "User search by name (%s) returned > 1 results!\n",
     248             :              cmd_ctx->name);
     249           0 :         return EINVAL;
     250             :     }
     251             : 
     252           0 :     if (!res->count) {
     253             :         /* if a multidomain search, try with next */
     254           0 :         if (cmd_ctx->check_next) {
     255           0 :             cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
     256           0 :             return ssh_user_pubkeys_search(cmd_ctx);
     257             :         }
     258             : 
     259           0 :         DEBUG(SSSDBG_OP_FAILURE,
     260             :               "No attributes for user [%s] found.\n", cmd_ctx->name);
     261             : 
     262           0 :         return ENOENT;
     263             :     }
     264             : 
     265           0 :     cmd_ctx->result = res->msgs[0];
     266             : 
     267             :     /* one result found */
     268           0 :     return EOK;
     269             : }
     270             : 
     271             : static void
     272           0 : ssh_user_pubkeys_search_dp_callback(uint16_t err_maj,
     273             :                                     uint32_t err_min,
     274             :                                     const char *err_msg,
     275             :                                     void *ptr)
     276             : {
     277           0 :     struct ssh_cmd_ctx *cmd_ctx = talloc_get_type(ptr, struct ssh_cmd_ctx);
     278             :     errno_t ret;
     279             : 
     280           0 :     if (err_maj) {
     281           0 :         DEBUG(SSSDBG_OP_FAILURE,
     282             :               "Unable to get information from Data Provider\n"
     283             :                "Error: %u, %u, %s\n",
     284             :                (unsigned int)err_maj, (unsigned int)err_min, err_msg);
     285             :     }
     286             : 
     287           0 :     ret = ssh_user_pubkeys_search_next(cmd_ctx);
     288           0 :     ssh_cmd_get_user_pubkeys_done(cmd_ctx, ret);
     289           0 : }
     290             : 
     291             : static errno_t
     292             : ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx);
     293             : static void
     294             : ssh_host_pubkeys_search_dp_callback(uint16_t err_maj,
     295             :                                     uint32_t err_min,
     296             :                                     const char *err_msg,
     297             :                                     void *ptr);
     298             : 
     299             : static errno_t
     300           0 : ssh_host_pubkeys_search(struct ssh_cmd_ctx *cmd_ctx)
     301             : {
     302             :     struct tevent_req *req;
     303             :     struct dp_callback_ctx *cb_ctx;
     304             : 
     305           0 :     if (!cmd_ctx->domain) {
     306           0 :         DEBUG(SSSDBG_OP_FAILURE,
     307             :               "No matching domain found for [%s], fail!\n", cmd_ctx->name);
     308           0 :         return ENOENT;
     309             :     }
     310             : 
     311             :     /* refresh the host's cache entry */
     312           0 :     if (NEED_CHECK_PROVIDER(cmd_ctx->domain->provider)) {
     313           0 :         req = sss_dp_get_ssh_host_send(cmd_ctx, cmd_ctx->cctx->rctx,
     314             :                                        cmd_ctx->domain, false,
     315           0 :                                        cmd_ctx->name, cmd_ctx->alias);
     316           0 :         if (!req) {
     317           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     318             :                   "Out of memory sending data provider request\n");
     319           0 :             return ENOMEM;
     320             :         }
     321             : 
     322           0 :         cb_ctx = talloc_zero(cmd_ctx, struct dp_callback_ctx);
     323           0 :         if (!cb_ctx) {
     324           0 :             talloc_zfree(req);
     325           0 :             return ENOMEM;
     326             :         }
     327             : 
     328           0 :         cb_ctx->callback = ssh_host_pubkeys_search_dp_callback;
     329           0 :         cb_ctx->ptr = cmd_ctx;
     330           0 :         cb_ctx->cctx = cmd_ctx->cctx;
     331           0 :         cb_ctx->mem_ctx = cmd_ctx;
     332             : 
     333           0 :         tevent_req_set_callback(req, ssh_dp_send_req_done, cb_ctx);
     334             : 
     335             :         /* tell caller we are in an async call */
     336           0 :         return EAGAIN;
     337             :     }
     338             : 
     339           0 :     return ssh_host_pubkeys_search_next(cmd_ctx);
     340             : }
     341             : 
     342             : static errno_t
     343           0 : ssh_host_pubkeys_search_next(struct ssh_cmd_ctx *cmd_ctx)
     344             : {
     345             :     errno_t ret;
     346             :     struct sysdb_ctx *sysdb;
     347           0 :     const char *attrs[] = { SYSDB_NAME, SYSDB_SSH_PUBKEY, NULL };
     348             : 
     349           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     350             :           "Requesting SSH host public keys for [%s@%s]\n",
     351             :            cmd_ctx->name, cmd_ctx->domain->name);
     352             : 
     353           0 :     sysdb = cmd_ctx->domain->sysdb;
     354           0 :     if (sysdb == NULL) {
     355           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     356             :               "Fatal: Sysdb CTX not found for this domain!\n");
     357           0 :         return EFAULT;
     358             :     }
     359             : 
     360           0 :     ret = sysdb_get_ssh_host(cmd_ctx, cmd_ctx->domain,
     361           0 :                              cmd_ctx->name, attrs, &cmd_ctx->result);
     362           0 :     if (ret != EOK && ret != ENOENT) {
     363           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     364             :               "Failed to make request to our cache!\n");
     365           0 :         return EIO;
     366             :     }
     367             : 
     368           0 :     if (ret == ENOENT) {
     369             :         /* if a multidomain search, try with next */
     370           0 :         if (cmd_ctx->check_next) {
     371           0 :             cmd_ctx->domain = get_next_domain(cmd_ctx->domain, false);
     372           0 :             return ssh_host_pubkeys_search(cmd_ctx);
     373             :         }
     374             : 
     375           0 :         DEBUG(SSSDBG_OP_FAILURE,
     376             :               "No attributes for host [%s] found.\n", cmd_ctx->name);
     377             : 
     378           0 :         return ENOENT;
     379             :     }
     380             : 
     381           0 :     return EOK;
     382             : }
     383             : 
     384             : static void
     385           0 : ssh_host_pubkeys_search_dp_callback(uint16_t err_maj,
     386             :                                     uint32_t err_min,
     387             :                                     const char *err_msg,
     388             :                                     void *ptr)
     389             : {
     390           0 :     struct ssh_cmd_ctx *cmd_ctx = talloc_get_type(ptr, struct ssh_cmd_ctx);
     391             :     errno_t ret;
     392             : 
     393           0 :     if (err_maj) {
     394           0 :         DEBUG(SSSDBG_OP_FAILURE,
     395             :               "Unable to get information from Data Provider\n"
     396             :                "Error: %u, %u, %s\n",
     397             :                (unsigned int)err_maj, (unsigned int)err_min, err_msg);
     398             :     }
     399             : 
     400           0 :     ret = ssh_host_pubkeys_search_next(cmd_ctx);
     401           0 :     ssh_cmd_get_host_pubkeys_done(cmd_ctx, ret);
     402           0 : }
     403             : 
     404             : static char *
     405           0 : ssh_host_pubkeys_format_known_host_plain(TALLOC_CTX *mem_ctx,
     406             :                                          struct sss_ssh_ent *ent)
     407             : {
     408             :     TALLOC_CTX *tmp_ctx;
     409             :     errno_t ret;
     410             :     char *name, *pubkey;
     411           0 :     char *result = NULL;
     412             :     size_t i;
     413             : 
     414           0 :     tmp_ctx = talloc_new(NULL);
     415           0 :     if (!tmp_ctx) {
     416           0 :         return NULL;
     417             :     }
     418             : 
     419           0 :     name = talloc_strdup(tmp_ctx, ent->name);
     420           0 :     if (!name) {
     421           0 :         goto done;
     422             :     }
     423             : 
     424           0 :     for (i = 0; i < ent->num_aliases; i++) {
     425           0 :         name = talloc_asprintf_append(name, ",%s", ent->aliases[i]);
     426           0 :         if (!name) {
     427           0 :             goto done;
     428             :         }
     429             :     }
     430             : 
     431           0 :     result = talloc_strdup(tmp_ctx, "");
     432           0 :     if (!result) {
     433           0 :         goto done;
     434             :     }
     435             : 
     436           0 :     for (i = 0; i < ent->num_pubkeys; i++) {
     437           0 :         ret = sss_ssh_format_pubkey(tmp_ctx, &ent->pubkeys[i], &pubkey);
     438           0 :         if (ret != EOK) {
     439           0 :             result = NULL;
     440           0 :             goto done;
     441             :         }
     442             : 
     443           0 :         result = talloc_asprintf_append(result, "%s %s\n", name, pubkey);
     444           0 :         if (!result) {
     445           0 :             goto done;
     446             :         }
     447             : 
     448           0 :         talloc_free(pubkey);
     449             :     }
     450             : 
     451           0 :     talloc_steal(mem_ctx, result);
     452             : 
     453             : done:
     454           0 :     talloc_free(tmp_ctx);
     455             : 
     456           0 :     return result;
     457             : }
     458             : 
     459             : static char *
     460           0 : ssh_host_pubkeys_format_known_host_hashed(TALLOC_CTX *mem_ctx,
     461             :                                           struct sss_ssh_ent *ent)
     462             : {
     463             :     TALLOC_CTX *tmp_ctx;
     464             :     errno_t ret;
     465             :     char *name, *pubkey, *saltstr, *hashstr, *result;
     466             :     unsigned char salt[SSS_SHA1_LENGTH], hash[SSS_SHA1_LENGTH];
     467             :     size_t i, j, k;
     468             : 
     469           0 :     tmp_ctx = talloc_new(NULL);
     470           0 :     if (!tmp_ctx) {
     471           0 :         return NULL;
     472             :     }
     473             : 
     474           0 :     result = talloc_strdup(tmp_ctx, "");
     475           0 :     if (!result) {
     476           0 :         goto done;
     477             :     }
     478             : 
     479           0 :     for (i = 0; i < ent->num_pubkeys; i++) {
     480           0 :         ret = sss_ssh_format_pubkey(tmp_ctx, &ent->pubkeys[i], &pubkey);
     481           0 :         if (ret != EOK) {
     482           0 :             result = NULL;
     483           0 :             goto done;
     484             :         }
     485             : 
     486           0 :         for (j = 0; j <= ent->num_aliases; j++) {
     487           0 :             name = (j == 0 ? ent->name : ent->aliases[j-1]);
     488             : 
     489           0 :             for (k = 0; k < SSS_SHA1_LENGTH; k++) {
     490           0 :                 salt[k] = rand();
     491             :             }
     492             : 
     493           0 :             ret = sss_hmac_sha1(salt, SSS_SHA1_LENGTH,
     494             :                                 (unsigned char *)name, strlen(name),
     495             :                                 hash);
     496           0 :             if (ret != EOK) {
     497           0 :                 DEBUG(SSSDBG_OP_FAILURE,
     498             :                       "sss_hmac_sha1() failed (%d): %s\n",
     499             :                        ret, strerror(ret));
     500           0 :                 result = NULL;
     501           0 :                 goto done;
     502             :             }
     503             : 
     504           0 :             saltstr = sss_base64_encode(tmp_ctx, salt, SSS_SHA1_LENGTH);
     505           0 :             if (!saltstr) {
     506           0 :                 result = NULL;
     507           0 :                 goto done;
     508             :             }
     509             : 
     510           0 :             hashstr = sss_base64_encode(tmp_ctx, hash, SSS_SHA1_LENGTH);
     511           0 :             if (!hashstr) {
     512           0 :                 result = NULL;
     513           0 :                 goto done;
     514             :             }
     515             : 
     516           0 :             result = talloc_asprintf_append(result, "|1|%s|%s %s\n",
     517             :                                             saltstr, hashstr, pubkey);
     518           0 :             if (!result) {
     519           0 :                 goto done;
     520             :             }
     521             : 
     522           0 :             talloc_free(saltstr);
     523           0 :             talloc_free(hashstr);
     524             :         }
     525             : 
     526           0 :         talloc_free(pubkey);
     527             :     }
     528             : 
     529           0 :     talloc_steal(mem_ctx, result);
     530             : 
     531             : done:
     532           0 :     talloc_free(tmp_ctx);
     533             : 
     534           0 :     return result;
     535             : }
     536             : 
     537             : static errno_t
     538           0 : ssh_host_pubkeys_update_known_hosts(struct ssh_cmd_ctx *cmd_ctx)
     539             : {
     540             :     TALLOC_CTX *tmp_ctx;
     541             :     errno_t ret;
     542           0 :     const char *attrs[] = {
     543             :         SYSDB_NAME,
     544             :         SYSDB_NAME_ALIAS,
     545             :         SYSDB_SSH_PUBKEY,
     546             :         NULL
     547             :     };
     548           0 :     struct cli_ctx *cctx = cmd_ctx->cctx;
     549           0 :     struct sss_domain_info *dom = cctx->rctx->domains;
     550           0 :     struct ssh_ctx *ssh_ctx = (struct ssh_ctx *)cctx->rctx->pvt_ctx;
     551             :     struct sysdb_ctx *sysdb;
     552           0 :     time_t now = time(NULL);
     553             :     struct ldb_message **hosts;
     554             :     size_t num_hosts, i;
     555             :     struct sss_ssh_ent *ent;
     556           0 :     int fd = -1;
     557           0 :     char *filename = NULL;
     558             :     char *entstr;
     559             :     ssize_t wret;
     560             : 
     561           0 :     tmp_ctx = talloc_new(NULL);
     562           0 :     if (!tmp_ctx) {
     563           0 :         return ENOMEM;
     564             :     }
     565             : 
     566           0 :     if (cmd_ctx->domain) {
     567           0 :         ret = sysdb_update_ssh_known_host_expire(cmd_ctx->domain,
     568           0 :                                                  cmd_ctx->name, now,
     569             :                                                  ssh_ctx->known_hosts_timeout);
     570           0 :         if (ret != EOK && ret != ENOENT) {
     571           0 :             goto done;
     572             :         }
     573             :     }
     574             : 
     575             :     /* write known_hosts file */
     576           0 :     filename = talloc_strdup(tmp_ctx, SSS_SSH_KNOWN_HOSTS_TEMP_TMPL);
     577           0 :     if (!filename) {
     578           0 :         ret = ENOMEM;
     579           0 :         goto done;
     580             :     }
     581             : 
     582           0 :     fd = sss_unique_file_ex(tmp_ctx, filename, 0133, &ret);
     583           0 :     if (fd == -1) {
     584           0 :         filename = NULL;
     585           0 :         goto done;
     586             :     }
     587             : 
     588           0 :     for (; dom; dom = get_next_domain(dom, false)) {
     589           0 :         sysdb = dom->sysdb;
     590           0 :         if (sysdb == NULL) {
     591           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     592             :                   "Fatal: Sysdb CTX not found for this domain!\n");
     593           0 :             ret = EFAULT;
     594           0 :             goto done;
     595             :         }
     596             : 
     597           0 :         ret = sysdb_get_ssh_known_hosts(tmp_ctx, dom, now, attrs,
     598             :                                         &hosts, &num_hosts);
     599           0 :         if (ret != EOK) {
     600           0 :             if (ret != ENOENT) {
     601           0 :                 DEBUG(SSSDBG_OP_FAILURE,
     602             :                       "Host search failed for domain [%s]\n", dom->name);
     603             :             }
     604           0 :             continue;
     605             :         }
     606             : 
     607           0 :         for (i = 0; i < num_hosts; i++) {
     608           0 :             ret = sss_ssh_make_ent(tmp_ctx, hosts[i], &ent);
     609           0 :             if (ret != EOK) {
     610           0 :                 DEBUG(SSSDBG_OP_FAILURE,
     611             :                       "Failed to get SSH host public keys\n");
     612           0 :                 continue;
     613             :             }
     614             : 
     615           0 :             if (ssh_ctx->hash_known_hosts) {
     616           0 :                 entstr = ssh_host_pubkeys_format_known_host_hashed(ent, ent);
     617             :             } else {
     618           0 :                 entstr = ssh_host_pubkeys_format_known_host_plain(ent, ent);
     619             :             }
     620           0 :             if (!entstr) {
     621           0 :                 DEBUG(SSSDBG_OP_FAILURE,
     622             :                       "Failed to format known_hosts data for [%s]\n",
     623             :                        ent->name);
     624           0 :                 continue;
     625             :             }
     626             : 
     627           0 :             wret = sss_atomic_write_s(fd, entstr, strlen(entstr));
     628           0 :             if (wret == -1) {
     629           0 :                 ret = errno;
     630           0 :                 goto done;
     631             :             }
     632             : 
     633           0 :             talloc_free(ent);
     634             :         }
     635             : 
     636           0 :         talloc_free(hosts);
     637             :     }
     638             : 
     639           0 :     ret = fchmod(fd, 0644);
     640           0 :     if (ret == -1) {
     641           0 :         ret = errno;
     642           0 :         goto done;
     643             :     }
     644             : 
     645           0 :     ret = rename(filename, SSS_SSH_KNOWN_HOSTS_PATH);
     646           0 :     if (ret == -1) {
     647           0 :         ret = errno;
     648           0 :         goto done;
     649             :     }
     650             : 
     651           0 :     ret = EOK;
     652             : 
     653             : done:
     654           0 :     if (fd != -1) {
     655           0 :         close(fd);
     656             :     }
     657           0 :     talloc_free(tmp_ctx);
     658             : 
     659           0 :     return ret;
     660             : }
     661             : 
     662             : static errno_t
     663           0 : ssh_cmd_parse_request(struct ssh_cmd_ctx *cmd_ctx)
     664             : {
     665           0 :     struct cli_ctx *cctx = cmd_ctx->cctx;
     666           0 :     struct ssh_ctx *ssh_ctx = talloc_get_type(cctx->rctx->pvt_ctx,
     667             :                                               struct ssh_ctx);
     668             :     errno_t ret;
     669             :     uint8_t *body;
     670             :     size_t body_len;
     671           0 :     size_t c = 0;
     672             :     uint32_t flags;
     673             :     uint32_t name_len;
     674             :     char *name;
     675             :     uint32_t alias_len;
     676           0 :     char *alias = NULL;
     677             :     uint32_t domain_len;
     678           0 :     char *domain = NULL;
     679             : 
     680           0 :     sss_packet_get_body(cctx->creq->in, &body, &body_len);
     681             : 
     682           0 :     SAFEALIGN_COPY_UINT32_CHECK(&flags, body+c, body_len, &c);
     683           0 :     if (flags & ~(uint32_t)SSS_SSH_REQ_MASK) {
     684           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid flags received [0x%x]\n", flags);
     685           0 :         return EINVAL;
     686             :     }
     687             : 
     688           0 :     SAFEALIGN_COPY_UINT32_CHECK(&name_len, body+c, body_len, &c);
     689           0 :     if (name_len == 0 || name_len > body_len - c) {
     690           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid name length\n");
     691           0 :         return EINVAL;
     692             :     }
     693             : 
     694           0 :     name = (char *)(body+c);
     695           0 :     if (!sss_utf8_check((const uint8_t *)name, name_len-1) ||
     696           0 :             name[name_len-1] != 0) {
     697           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Name is not valid UTF-8 string\n");
     698           0 :         return EINVAL;
     699             :     }
     700           0 :     c += name_len;
     701             : 
     702           0 :     if (flags & SSS_SSH_REQ_ALIAS) {
     703           0 :         SAFEALIGN_COPY_UINT32_CHECK(&alias_len, body+c, body_len, &c);
     704           0 :         if (alias_len == 0 || alias_len > body_len - c) {
     705           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Invalid alias length\n");
     706           0 :             return EINVAL;
     707             :         }
     708             : 
     709           0 :         alias = (char *)(body+c);
     710           0 :         if (!sss_utf8_check((const uint8_t *)alias, alias_len-1) ||
     711           0 :                 alias[alias_len-1] != 0) {
     712           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Alias is not valid UTF-8 string\n");
     713           0 :             return EINVAL;
     714             :         }
     715           0 :         c += alias_len;
     716             :     }
     717             : 
     718           0 :     if (flags & SSS_SSH_REQ_DOMAIN) {
     719           0 :         SAFEALIGN_COPY_UINT32_CHECK(&domain_len, body+c, body_len, &c);
     720           0 :         if (domain_len > 0) {
     721           0 :             if (domain_len > body_len - c) {
     722           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Invalid domain length\n");
     723           0 :                 return EINVAL;
     724             :             }
     725             : 
     726           0 :             domain = (char *)(body+c);
     727           0 :             if (!sss_utf8_check((const uint8_t *)domain, domain_len-1) ||
     728           0 :                     domain[domain_len-1] != 0) {
     729           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     730             :                       "Domain is not valid UTF-8 string\n");
     731           0 :                 return EINVAL;
     732             :             }
     733           0 :             c += domain_len;
     734             :         }
     735             : 
     736           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     737             :               "Requested domain [%s]\n", domain ? domain : "<ALL>");
     738             :     } else {
     739           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Splitting domain from name [%s]\n", name);
     740             : 
     741           0 :         ret = sss_parse_name(cmd_ctx, ssh_ctx->snctx, name,
     742             :                              &cmd_ctx->domname, &cmd_ctx->name);
     743           0 :         if (ret != EOK) {
     744           0 :             DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", name);
     745           0 :             return ENOENT;
     746             :         }
     747             : 
     748           0 :         name = cmd_ctx->name;
     749             :     }
     750             : 
     751           0 :     if (cmd_ctx->is_user && cmd_ctx->domname == NULL) {
     752           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     753             :               "Parsing name [%s][%s]\n", name, domain ? domain : "<ALL>");
     754             : 
     755           0 :         ret = sss_parse_name_for_domains(cmd_ctx, cctx->rctx->domains,
     756             :                                          domain, name,
     757             :                                          &cmd_ctx->domname,
     758             :                                          &cmd_ctx->name);
     759           0 :         if (ret != EOK) {
     760           0 :             DEBUG(SSSDBG_OP_FAILURE,
     761             :                   "Invalid name received [%s]\n", name);
     762           0 :             return ENOENT;
     763             :         }
     764             :     } else {
     765           0 :         if (cmd_ctx->name == NULL) {
     766           0 :             cmd_ctx->name = talloc_strdup(cmd_ctx, name);
     767           0 :             if (!cmd_ctx->name) return ENOMEM;
     768             :         }
     769             : 
     770           0 :         if (cmd_ctx->domname == NULL && domain != NULL) {
     771           0 :             cmd_ctx->domname = talloc_strdup(cmd_ctx, domain);
     772           0 :             if (!cmd_ctx->domname) return ENOMEM;
     773             :         }
     774             :     }
     775             : 
     776           0 :     if (alias != NULL && strcmp(cmd_ctx->name, alias) != 0) {
     777           0 :         cmd_ctx->alias = talloc_strdup(cmd_ctx, alias);
     778           0 :         if (!cmd_ctx->alias) return ENOMEM;
     779             :     }
     780             : 
     781           0 :     return EOK;
     782             : }
     783             : 
     784           0 : static errno_t decode_and_add_base64_data(struct ssh_cmd_ctx *cmd_ctx,
     785             :                                           struct ldb_message_element *el,
     786             :                                           bool cert_data,
     787             :                                           struct ssh_ctx *ssh_ctx,
     788             :                                           size_t fqname_len,
     789             :                                           const char *fqname,
     790             :                                           size_t *c)
     791             : {
     792           0 :     struct cli_ctx *cctx = cmd_ctx->cctx;
     793             :     uint8_t *key;
     794             :     size_t key_len;
     795             :     uint8_t *body;
     796             :     size_t body_len;
     797             :     int ret;
     798             :     size_t d;
     799             :     TALLOC_CTX *tmp_ctx;
     800             : 
     801           0 :     if (el == NULL) {
     802           0 :         DEBUG(SSSDBG_TRACE_ALL, "Mssing element, nothing to do.\n");
     803           0 :         return EOK;
     804             :     }
     805             : 
     806           0 :     tmp_ctx = talloc_new(NULL);
     807           0 :     if (tmp_ctx == NULL) {
     808           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
     809           0 :         return ENOMEM;
     810             :     }
     811             : 
     812           0 :     for (d = 0; d < el->num_values; d++) {
     813           0 :         if (cert_data) {
     814           0 :             ret = cert_to_ssh_key(tmp_ctx, ssh_ctx->ca_db,
     815           0 :                                   el->values[d].data, el->values[d].length,
     816             :                                   &key, &key_len);
     817           0 :             if (ret != EOK) {
     818           0 :                 DEBUG(SSSDBG_OP_FAILURE, "cert_to_ssh_key failed.\n");
     819           0 :                 return ret;
     820             :             }
     821             :         } else  {
     822           0 :             key = sss_base64_decode(tmp_ctx, (const char *) el->values[d].data,
     823             :                                     &key_len);
     824           0 :             if (key == NULL) {
     825           0 :                 DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n");
     826           0 :                 ret = ENOMEM;
     827           0 :                 goto done;
     828             :             }
     829             :         }
     830             : 
     831           0 :         ret = sss_packet_grow(cctx->creq->out,
     832           0 :                               3*sizeof(uint32_t) + key_len + fqname_len);
     833           0 :         if (ret != EOK) {
     834           0 :             DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n");
     835           0 :             goto done;
     836             :         }
     837           0 :         sss_packet_get_body(cctx->creq->out, &body, &body_len);
     838             : 
     839           0 :         SAFEALIGN_SET_UINT32(body+(*c), 0, c);
     840           0 :         SAFEALIGN_SET_UINT32(body+(*c), fqname_len, c);
     841           0 :         safealign_memcpy(body+(*c), fqname, fqname_len, c);
     842           0 :         SAFEALIGN_SET_UINT32(body+(*c), key_len, c);
     843           0 :         safealign_memcpy(body+(*c), key, key_len, c);
     844             : 
     845             :     }
     846             : 
     847           0 :     ret = EOK;
     848             : 
     849             : done:
     850           0 :     talloc_free(tmp_ctx);
     851             : 
     852           0 :     return ret;
     853             : }
     854             : 
     855             : static errno_t
     856           0 : ssh_cmd_build_reply(struct ssh_cmd_ctx *cmd_ctx)
     857             : {
     858           0 :     struct cli_ctx *cctx = cmd_ctx->cctx;
     859             :     errno_t ret;
     860             :     uint8_t *body;
     861             :     size_t body_len;
     862           0 :     size_t c = 0;
     863           0 :     struct ldb_message_element *el = NULL;
     864           0 :     struct ldb_message_element *el_override = NULL;
     865           0 :     struct ldb_message_element *el_orig = NULL;
     866           0 :     struct ldb_message_element *el_user_cert = NULL;
     867           0 :     uint32_t count = 0;
     868             :     const char *name;
     869             :     char *fqname;
     870             :     uint32_t fqname_len;
     871           0 :     struct ssh_ctx *ssh_ctx = talloc_get_type(cctx->rctx->pvt_ctx,
     872             :                                               struct ssh_ctx);
     873             : 
     874           0 :     ret = sss_packet_new(cctx->creq, 0,
     875           0 :                          sss_packet_get_cmd(cctx->creq->in),
     876           0 :                          &cctx->creq->out);
     877           0 :     if (ret != EOK) {
     878           0 :         return ret;
     879             :     }
     880             : 
     881           0 :     el = ldb_msg_find_element(cmd_ctx->result, SYSDB_SSH_PUBKEY);
     882           0 :     if (el) {
     883           0 :         count = el->num_values;
     884             :     }
     885             : 
     886           0 :     el_orig = ldb_msg_find_element(cmd_ctx->result,
     887             :                                   ORIGINALAD_PREFIX SYSDB_SSH_PUBKEY);
     888           0 :     if (el_orig) {
     889           0 :         count = el_orig->num_values;
     890             :     }
     891             : 
     892           0 :     if (DOM_HAS_VIEWS(cmd_ctx->domain)) {
     893           0 :         el_override = ldb_msg_find_element(cmd_ctx->result,
     894             :                                            OVERRIDE_PREFIX SYSDB_SSH_PUBKEY);
     895           0 :         if (el_override) {
     896           0 :             count += el_override->num_values;
     897             :         }
     898             :     }
     899             : 
     900           0 :     el_user_cert = ldb_msg_find_element(cmd_ctx->result, SYSDB_USER_CERT);
     901           0 :     if (el_user_cert) {
     902             :         /* TODO check if cert is valid */
     903           0 :         count += el_user_cert->num_values;
     904             :     }
     905             : 
     906           0 :     ret = sss_packet_grow(cctx->creq->out, 2*sizeof(uint32_t));
     907           0 :     if (ret != EOK) {
     908           0 :         return ret;
     909             :     }
     910           0 :     sss_packet_get_body(cctx->creq->out, &body, &body_len);
     911             : 
     912           0 :     SAFEALIGN_SET_UINT32(body+c, count, &c);
     913           0 :     SAFEALIGN_SET_UINT32(body+c, 0, &c);
     914             : 
     915           0 :     if (count == 0) {
     916           0 :         return EOK;
     917             :     }
     918             : 
     919           0 :     name = ldb_msg_find_attr_as_string(cmd_ctx->result, SYSDB_NAME, NULL);
     920           0 :     if (!name) {
     921           0 :         DEBUG(SSSDBG_OP_FAILURE,
     922             :               "Got unnamed result for [%s@%s]\n",
     923             :                cmd_ctx->name, cmd_ctx->domain->name);
     924           0 :         return ENOENT;
     925             :     }
     926             : 
     927           0 :     fqname = talloc_asprintf(cmd_ctx, "%s@%s",
     928           0 :                              name, cmd_ctx->domain->name);
     929           0 :     if (!fqname) {
     930           0 :         return ENOMEM;
     931             :     }
     932             : 
     933           0 :     fqname_len = strlen(fqname)+1;
     934             : 
     935           0 :     ret = decode_and_add_base64_data(cmd_ctx, el, false, ssh_ctx,
     936             :                                      fqname_len, fqname, &c);
     937           0 :     if (ret != EOK) {
     938           0 :         DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
     939           0 :         return ret;
     940             :     }
     941             : 
     942           0 :     ret = decode_and_add_base64_data(cmd_ctx, el_orig, false, ssh_ctx,
     943             :                                      fqname_len, fqname, &c);
     944           0 :     if (ret != EOK) {
     945           0 :         DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
     946           0 :         return ret;
     947             :     }
     948             : 
     949           0 :     ret = decode_and_add_base64_data(cmd_ctx, el_override, false, ssh_ctx,
     950             :                                      fqname_len, fqname, &c);
     951           0 :     if (ret != EOK) {
     952           0 :         DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
     953           0 :         return ret;
     954             :     }
     955             : 
     956           0 :     ret = decode_and_add_base64_data(cmd_ctx, el_user_cert, true, ssh_ctx,
     957             :                                      fqname_len, fqname, &c);
     958           0 :     if (ret != EOK) {
     959           0 :         DEBUG(SSSDBG_OP_FAILURE, "decode_and_add_base64_data failed.\n");
     960           0 :         return ret;
     961             :     }
     962             : 
     963           0 :     return EOK;
     964             : }
     965             : 
     966             : static errno_t
     967           0 : ssh_cmd_send_error(struct ssh_cmd_ctx *cmd_ctx,
     968             :                    errno_t error)
     969             : {
     970           0 :     struct cli_ctx *cctx = cmd_ctx->cctx;
     971             :     errno_t ret;
     972             : 
     973           0 :     ret = sss_cmd_send_error(cctx, error);
     974           0 :     if (ret != EOK) {
     975           0 :         return ret;
     976             :     }
     977             : 
     978           0 :     sss_cmd_done(cctx, cmd_ctx);
     979             : 
     980           0 :     return EOK;
     981             : }
     982             : 
     983             : static errno_t
     984           0 : ssh_cmd_send_reply(struct ssh_cmd_ctx *cmd_ctx)
     985             : {
     986           0 :     struct cli_ctx *cctx = cmd_ctx->cctx;
     987             :     errno_t ret;
     988             : 
     989             :     /* create response packet */
     990           0 :     ret = ssh_cmd_build_reply(cmd_ctx);
     991           0 :     if (ret != EOK) {
     992           0 :         return ret;
     993             :     }
     994             : 
     995           0 :     sss_packet_set_error(cctx->creq->out, EOK);
     996           0 :     sss_cmd_done(cctx, cmd_ctx);
     997             : 
     998           0 :     return EOK;
     999             : }
    1000             : 
    1001             : static errno_t
    1002           0 : ssh_cmd_done(struct ssh_cmd_ctx *cmd_ctx,
    1003             :              errno_t ret)
    1004             : {
    1005           0 :     switch (ret) {
    1006             :     case EOK:
    1007           0 :         ret = ssh_cmd_send_reply(cmd_ctx);
    1008           0 :         break;
    1009             : 
    1010             :     case EAGAIN:
    1011           0 :         return EOK;
    1012             : 
    1013             :     case EFAULT:
    1014           0 :         break;
    1015             : 
    1016             :     default:
    1017           0 :         ret = ssh_cmd_send_error(cmd_ctx, ret);
    1018           0 :         break;
    1019             :     }
    1020             : 
    1021           0 :     if (ret != EOK) {
    1022           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Fatal error, killing connection!\n");
    1023           0 :         talloc_free(cmd_ctx->cctx);
    1024           0 :         return EFAULT;
    1025             :     }
    1026             : 
    1027           0 :     return EOK;
    1028             : }
    1029             : 
    1030             : static errno_t
    1031           0 : ssh_cmd_get_user_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx,
    1032             :                               errno_t ret)
    1033             : {
    1034           0 :     return ssh_cmd_done(cmd_ctx, ret);
    1035             : }
    1036             : 
    1037             : static errno_t
    1038           0 : ssh_cmd_get_host_pubkeys_done(struct ssh_cmd_ctx *cmd_ctx,
    1039             :                               errno_t ret)
    1040             : {
    1041           0 :     if (ret == EOK || ret == ENOENT) {
    1042           0 :         ssh_host_pubkeys_update_known_hosts(cmd_ctx);
    1043             :     }
    1044             : 
    1045           0 :     return ssh_cmd_done(cmd_ctx, ret);
    1046             : }
    1047             : 
    1048           0 : struct cli_protocol_version *register_cli_protocol_version(void)
    1049             : {
    1050             :     static struct cli_protocol_version ssh_cli_protocol_version[] = {
    1051             :         {0, NULL, NULL}
    1052             :     };
    1053             : 
    1054           0 :     return ssh_cli_protocol_version;
    1055             : }
    1056             : 
    1057           0 : struct sss_cmd_table *get_ssh_cmds(void) {
    1058             :     static struct sss_cmd_table ssh_cmds[] = {
    1059             :         {SSS_GET_VERSION, sss_cmd_get_version},
    1060             :         {SSS_SSH_GET_USER_PUBKEYS, sss_ssh_cmd_get_user_pubkeys},
    1061             :         {SSS_SSH_GET_HOST_PUBKEYS, sss_ssh_cmd_get_host_pubkeys},
    1062             :         {SSS_CLI_NULL, NULL}
    1063             :     };
    1064             : 
    1065           0 :     return ssh_cmds;
    1066             : }

Generated by: LCOV version 1.10