summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2012-02-03 22:52:08 +0100
committerJakub Hrozek <jhrozek@redhat.com>2012-02-07 00:26:57 +0100
commit347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5 (patch)
treea0867031e594fdb5e083be0f6afca3f27763783f
parente7311aec8d691e5427317442387af1bc8fff3742 (diff)
downloadsssd-347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5.tar.gz
sssd-347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5.tar.bz2
sssd-347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5.zip
SSH: Common client code
-rw-r--r--Makefile.am4
-rw-r--r--src/sss_client/common.c19
-rw-r--r--src/sss_client/ssh/sss_ssh.c284
-rw-r--r--src/sss_client/ssh/sss_ssh.h63
-rw-r--r--src/sss_client/sss_cli.h6
5 files changed, 375 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 644adcbe..1bc62092 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -384,7 +384,9 @@ dist_noinst_HEADERS = \
src/resolv/ares/ares_parse_srv_reply.h \
src/resolv/ares/ares_parse_txt_reply.h \
src/resolv/ares/ares_data.h \
- src/tests/common.h
+ src/tests/common.h \
+ src/sss_client/ssh/sss_ssh.h
+
if HAVE_NSS
dist_noinst_HEADERS += src/util/crypto/nss/nss_util.h
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
index 8fe8b44c..28adb442 100644
--- a/src/sss_client/common.c
+++ b/src/sss_client/common.c
@@ -381,6 +381,8 @@ static bool sss_cli_check_version(const char *socket_name)
expected_version = SSS_SUDO_PROTOCOL_VERSION;
} else if (strcmp(socket_name, SSS_AUTOFS_SOCKET_NAME) == 0) {
expected_version = SSS_AUTOFS_PROTOCOL_VERSION;
+ } else if (strcmp(socket_name, SSS_SSH_SOCKET_NAME) == 0) {
+ expected_version = SSS_SSH_PROTOCOL_VERSION;
} else {
return false;
}
@@ -849,6 +851,23 @@ int sss_autofs_make_request(enum sss_cli_command cmd,
return ret;
}
+int sss_ssh_make_request(enum sss_cli_command cmd,
+ struct sss_cli_req_data *rd,
+ uint8_t **repbuf, size_t *replen,
+ int *errnop)
+{
+ enum sss_status ret = SSS_STATUS_UNAVAIL;
+
+ ret = sss_cli_check_socket(errnop, SSS_SSH_SOCKET_NAME);
+ if (ret != SSS_STATUS_SUCCESS) {
+ return SSS_STATUS_UNAVAIL;
+ }
+
+ ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop);
+
+ return ret;
+}
+
const char *ssscli_err2string(int err)
{
diff --git a/src/sss_client/ssh/sss_ssh.c b/src/sss_client/ssh/sss_ssh.c
new file mode 100644
index 00000000..dbdbbeee
--- /dev/null
+++ b/src/sss_client/ssh/sss_ssh.c
@@ -0,0 +1,284 @@
+/*
+ Authors:
+ Jan Cholasta <jcholast@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <talloc.h>
+
+#include <popt.h>
+#include <locale.h>
+#include <libintl.h>
+
+#include "config.h"
+#include "util/crypto/sss_crypto.h"
+#include "sss_client/sss_cli.h"
+#include "sss_client/ssh/sss_ssh.h"
+
+/* FIXME - split from tools_util to create a common function */
+void usage(poptContext pc, const char *error)
+{
+ poptPrintUsage(pc, stderr, 0);
+ if (error) fprintf(stderr, "%s", error);
+}
+
+/* FIXME - split from tools_util to create a common function */
+int set_locale(void)
+{
+ char *c;
+
+ c = setlocale(LC_ALL, "");
+ if (c == NULL) {
+ return EIO;
+ }
+
+ errno = 0;
+ c = bindtextdomain(PACKAGE, LOCALEDIR);
+ if (c == NULL) {
+ return errno;
+ }
+
+ errno = 0;
+ c = textdomain(PACKAGE);
+ if (c == NULL) {
+ return errno;
+ }
+
+ return EOK;
+}
+
+errno_t
+sss_ssh_get_pubkeys(TALLOC_CTX *mem_ctx,
+ enum sss_cli_command command,
+ const char *name,
+ struct sss_ssh_pubkey **pubkeys,
+ size_t *pubkeys_len)
+{
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret = EOK;
+ uint32_t name_len;
+ size_t req_len;
+ uint8_t *req = NULL;
+ size_t c = 0;
+ struct sss_cli_req_data rd;
+ int req_ret, req_errno;
+ uint8_t *rep = NULL;
+ size_t rep_len;
+ uint32_t count, reserved, len, i;
+ struct sss_ssh_pubkey *result = NULL;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ /* build request */
+ name_len = strlen(name)+1;
+ req_len = 2*sizeof(uint32_t) + name_len;
+
+ req = talloc_array(tmp_ctx, uint8_t, req_len);
+ if (!req) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ SAFEALIGN_SET_UINT32(req+c, 0, &c);
+ SAFEALIGN_SET_UINT32(req+c, name_len, &c);
+ safealign_memcpy(req+c, name, name_len, &c);
+
+ /* send request */
+ rd.data = req;
+ rd.len = req_len;
+
+ req_ret = sss_ssh_make_request(command, &rd, &rep, &rep_len, &req_errno);
+ if (req_ret != SSS_STATUS_SUCCESS) {
+ ret = EFAULT;
+ goto done;
+ }
+ if (req_errno != EOK) {
+ ret = req_errno;
+ goto done;
+ }
+
+ /* parse reply */
+ c = 0;
+ if (rep_len-c < 2*sizeof(uint32_t)) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ SAFEALIGN_COPY_UINT32(&count, rep+c, &c);
+
+ SAFEALIGN_COPY_UINT32(&reserved, rep+c, &c);
+ if (reserved != 0) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ if (count > 0) {
+ result = talloc_zero_array(tmp_ctx, struct sss_ssh_pubkey, count);
+ if (!result) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ if (rep_len-c < 2*sizeof(uint32_t)) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ SAFEALIGN_COPY_UINT32(&result[i].flags, rep+c, &c);
+ if (result[i].flags != 0) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ SAFEALIGN_COPY_UINT32(&len, rep+c, &c);
+
+ if (rep_len-c < len + sizeof(uint32_t)) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ result[i].name = talloc_array(result, char, len);
+ if (!result[i].name) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ safealign_memcpy(result[i].name, rep+c, len, &c);
+ if (strnlen(result[i].name, len) != len-1) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ SAFEALIGN_COPY_UINT32(&len, rep+c, &c);
+
+ if (rep_len-c < len) {
+ ret = EINVAL;
+ goto done;
+ }
+
+ result[i].key = talloc_array(result, uint8_t, len);
+ if (!result[i].key) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ safealign_memcpy(result[i].key, rep+c, len, &c);
+ result[i].key_len = len;
+ }
+
+ *pubkeys = result ? talloc_steal(mem_ctx, result) : NULL;
+ *pubkeys_len = count;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
+
+char *
+sss_ssh_get_pubkey_algorithm(TALLOC_CTX *mem_ctx,
+ struct sss_ssh_pubkey *pubkey)
+{
+ size_t c = 0;
+ uint32_t algo_len;
+ char *algo;
+
+ SAFEALIGN_COPY_UINT32(&algo_len, pubkey->key, &c);
+ algo_len = ntohl(algo_len);
+
+ algo = talloc_zero_array(mem_ctx, char, algo_len+1);
+ if (!algo) {
+ return NULL;
+ }
+
+ memcpy(algo, pubkey->key+c, algo_len);
+
+ return algo;
+}
+
+errno_t
+sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx,
+ struct sss_ssh_pubkey *pubkey,
+ enum sss_ssh_pubkey_format format,
+ char **result)
+{
+ TALLOC_CTX *tmp_ctx;
+ errno_t ret = EOK;
+ char *pk;
+ char *algo;
+ char *out;
+
+ if (!pubkey) {
+ return EINVAL;
+ }
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ pk = sss_base64_encode(tmp_ctx, pubkey->key, pubkey->key_len);
+ if (!pk) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ switch (format) {
+ case SSS_SSH_FORMAT_RAW:
+ /* base64-encoded key blob */
+
+ out = talloc_steal(mem_ctx, pk);
+
+ break;
+
+ case SSS_SSH_FORMAT_OPENSSH:
+ /* OpenSSH authorized_keys/known_hosts format */
+
+ algo = sss_ssh_get_pubkey_algorithm(tmp_ctx, pubkey);
+ if (!algo) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ out = talloc_asprintf(tmp_ctx, "%s %s %s",
+ algo, pk, pubkey->name);
+ if (!out) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ talloc_steal(mem_ctx, out);
+
+ break;
+ }
+
+ *result = out;
+
+done:
+ talloc_free(tmp_ctx);
+
+ return ret;
+}
diff --git a/src/sss_client/ssh/sss_ssh.h b/src/sss_client/ssh/sss_ssh.h
new file mode 100644
index 00000000..633c3af7
--- /dev/null
+++ b/src/sss_client/ssh/sss_ssh.h
@@ -0,0 +1,63 @@
+/*
+ Authors:
+ Jan Cholasta <jcholast@redhat.com>
+
+ Copyright (C) 2012 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SSS_SSH_H_
+#define _SSS_SSH_H_
+
+void usage(poptContext pc, const char *error);
+int set_locale(void);
+
+#define BAD_POPT_PARAMS(pc, msg, val, label) do { \
+ usage(pc, msg); \
+ val = EXIT_FAILURE; \
+ goto label; \
+} while(0)
+
+struct sss_ssh_pubkey {
+ uint32_t flags;
+ char *name;
+
+ uint8_t *key;
+ size_t key_len;
+};
+
+errno_t
+sss_ssh_get_pubkeys(TALLOC_CTX *mem_ctx,
+ enum sss_cli_command command,
+ const char *name,
+ struct sss_ssh_pubkey **pubkeys,
+ size_t *pubkeys_len);
+
+char *
+sss_ssh_get_pubkey_algorithm(TALLOC_CTX *mem_ctx,
+ struct sss_ssh_pubkey *pubkey);
+
+enum sss_ssh_pubkey_format {
+ SSS_SSH_FORMAT_RAW,
+ SSS_SSH_FORMAT_OPENSSH
+};
+
+errno_t
+sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx,
+ struct sss_ssh_pubkey *pubkey,
+ enum sss_ssh_pubkey_format format,
+ char **result);
+
+#endif /* _SSS_SSH_H_ */
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
index 491af9ad..647d233f 100644
--- a/src/sss_client/sss_cli.h
+++ b/src/sss_client/sss_cli.h
@@ -46,6 +46,7 @@ typedef int errno_t;
#define SSS_PAM_PROTOCOL_VERSION 3
#define SSS_SUDO_PROTOCOL_VERSION 0
#define SSS_AUTOFS_PROTOCOL_VERSION 1
+#define SSS_SSH_PROTOCOL_VERSION 0
#ifdef LOGIN_NAME_MAX
#define SSS_NAME_MAX LOGIN_NAME_MAX
@@ -490,6 +491,11 @@ int sss_autofs_make_request(enum sss_cli_command cmd,
uint8_t **repbuf, size_t *replen,
int *errnop);
+int sss_ssh_make_request(enum sss_cli_command cmd,
+ struct sss_cli_req_data *rd,
+ uint8_t **repbuf, size_t *replen,
+ int *errnop);
+
#ifndef SAFEALIGN_COPY_UINT32
static inline void
safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter)