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 <arpa/inet.h>
22 :
23 : #include "db/sysdb.h"
24 : #include "util/util.h"
25 : #include "util/crypto/sss_crypto.h"
26 : #include "util/sss_ssh.h"
27 :
28 : errno_t
29 0 : sss_ssh_make_ent(TALLOC_CTX *mem_ctx,
30 : struct ldb_message *msg,
31 : struct sss_ssh_ent **result)
32 : {
33 : TALLOC_CTX *tmp_ctx;
34 0 : struct sss_ssh_ent *res = NULL;
35 : errno_t ret;
36 : const char *name;
37 : struct ldb_message_element *el;
38 : unsigned int i;
39 :
40 0 : tmp_ctx = talloc_new(NULL);
41 0 : if (!tmp_ctx) {
42 0 : return ENOMEM;
43 : }
44 :
45 0 : name = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
46 0 : if (!name) {
47 0 : ret = EINVAL;
48 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Host is missing name attribute\n");
49 0 : goto done;
50 : }
51 :
52 0 : res = talloc_zero(tmp_ctx, struct sss_ssh_ent);
53 0 : if (!res) {
54 0 : ret = ENOMEM;
55 0 : goto done;
56 : }
57 :
58 0 : res->name = talloc_strdup(res, name);
59 0 : if (!res->name) {
60 0 : ret = ENOMEM;
61 0 : goto done;
62 : }
63 :
64 0 : el = ldb_msg_find_element(msg, SYSDB_SSH_PUBKEY);
65 0 : if (el) {
66 0 : res->num_pubkeys = el->num_values;
67 :
68 0 : res->pubkeys = talloc_array(res, struct sss_ssh_pubkey,
69 : res->num_pubkeys);
70 0 : if (!res->pubkeys) {
71 0 : ret = ENOMEM;
72 0 : goto done;
73 : }
74 :
75 0 : for (i = 0; i < el->num_values; i++) {
76 0 : res->pubkeys[i].data = sss_base64_decode(res->pubkeys,
77 0 : (char *)el->values[i].data, &res->pubkeys[i].data_len);
78 0 : if (!res->pubkeys[i].data) {
79 0 : ret = ENOMEM;
80 0 : goto done;
81 : }
82 : }
83 : }
84 :
85 0 : el = ldb_msg_find_element(msg, SYSDB_NAME_ALIAS);
86 0 : if (el) {
87 0 : res->num_aliases = el->num_values;
88 :
89 0 : res->aliases = talloc_array(res, char *, res->num_aliases);
90 0 : if (!res->aliases) {
91 0 : ret = ENOMEM;
92 0 : goto done;
93 : }
94 :
95 0 : for (i = 0; i < el->num_values; i++) {
96 0 : res->aliases[i] = talloc_strdup(res->aliases,
97 0 : (char *)el->values[i].data);
98 0 : if (!res->aliases[i]) {
99 0 : ret = ENOMEM;
100 0 : goto done;
101 : }
102 : }
103 : }
104 :
105 0 : *result = talloc_steal(mem_ctx, res);
106 0 : ret = EOK;
107 :
108 : done:
109 0 : talloc_free(tmp_ctx);
110 :
111 0 : return ret;
112 : }
113 :
114 : static errno_t
115 0 : sss_ssh_get_pubkey_algorithm(TALLOC_CTX *mem_ctx,
116 : struct sss_ssh_pubkey *pubkey,
117 : char **result)
118 : {
119 0 : size_t c = 0;
120 : uint32_t algo_len;
121 : char *algo;
122 :
123 0 : if (pubkey->data_len < 5) {
124 0 : return EINVAL;
125 : }
126 :
127 0 : SAFEALIGN_COPY_UINT32(&algo_len, pubkey->data, &c);
128 0 : algo_len = ntohl(algo_len);
129 0 : if (algo_len < 1 || algo_len > 64 || algo_len > pubkey->data_len - 4) {
130 : /* the maximum length of 64 is defined in RFC 4250 */
131 0 : return EINVAL;
132 : }
133 :
134 0 : algo = talloc_zero_array(mem_ctx, char, algo_len+1);
135 0 : if (!algo) {
136 0 : return ENOMEM;
137 : }
138 :
139 0 : memcpy(algo, pubkey->data+c, algo_len);
140 :
141 0 : *result = algo;
142 0 : return EOK;
143 : }
144 :
145 : errno_t
146 6 : sss_ssh_format_pubkey(TALLOC_CTX *mem_ctx,
147 : struct sss_ssh_pubkey *pubkey,
148 : char **result)
149 : {
150 : TALLOC_CTX *tmp_ctx;
151 : errno_t ret;
152 : char *blob;
153 : char *algo;
154 6 : char *out = NULL;
155 : size_t i, len;
156 :
157 6 : tmp_ctx = talloc_new(NULL);
158 6 : if (!tmp_ctx) {
159 0 : return ENOMEM;
160 : }
161 :
162 6 : if (pubkey->data_len > 4 && memcmp(pubkey->data, "\0\0\0", 3) == 0) {
163 : /* All valid public key blobs start with 3 null bytes (see RFC 4253
164 : * section 6.6, RFC 4251 section 5 and RFC 4250 section 4.6)
165 : */
166 0 : blob = sss_base64_encode(tmp_ctx, pubkey->data, pubkey->data_len);
167 0 : if (!blob) {
168 0 : ret = ENOMEM;
169 0 : goto done;
170 : }
171 :
172 0 : ret = sss_ssh_get_pubkey_algorithm(tmp_ctx, pubkey, &algo);
173 0 : if (ret != EOK) {
174 0 : goto done;
175 : }
176 :
177 0 : out = talloc_asprintf(mem_ctx, "%s %s", algo, blob);
178 0 : if (!out) {
179 0 : ret = ENOMEM;
180 0 : goto done;
181 : }
182 : } else {
183 : /* Not a valid public key blob, so this must be a textual public key */
184 2037 : for (i = 0; i < pubkey->data_len; i++) {
185 4069 : if (pubkey->data[i] == '\0' ||
186 4069 : (pubkey->data[i] == '\n' && i != pubkey->data_len - 1) ||
187 2033 : pubkey->data[i] == '\r') {
188 4 : ret = EINVAL;
189 4 : goto done;
190 : }
191 : }
192 :
193 2 : len = pubkey->data_len;
194 2 : if (pubkey->data[len - 1] == '\n') {
195 1 : len--;
196 : }
197 :
198 2 : out = talloc_array(mem_ctx, char, len + 1);
199 2 : if (out == NULL) {
200 0 : ret = ENOMEM;
201 0 : goto done;
202 : }
203 :
204 2 : memcpy(out, pubkey->data, len);
205 2 : out[len] = '\0';
206 : }
207 :
208 2 : *result = out;
209 2 : ret = EOK;
210 :
211 : done:
212 6 : talloc_free(tmp_ctx);
213 :
214 6 : return ret;
215 : }
|