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 <talloc.h>
22 :
23 : #include "db/sysdb_ssh.h"
24 : #include "db/sysdb_private.h"
25 :
26 : static struct ldb_dn *
27 0 : sysdb_ssh_host_dn(TALLOC_CTX *mem_ctx,
28 : struct sss_domain_info *domain,
29 : const char *name)
30 : {
31 0 : return sysdb_custom_dn(mem_ctx, domain, name, SSH_HOSTS_SUBDIR);
32 : }
33 :
34 : static errno_t
35 2 : sysdb_update_ssh_host(struct sss_domain_info *domain,
36 : const char *name,
37 : struct sysdb_attrs *attrs)
38 : {
39 : errno_t ret;
40 :
41 2 : ret = sysdb_store_custom(domain, name, SSH_HOSTS_SUBDIR,
42 : attrs);
43 2 : if (ret != EOK) {
44 0 : DEBUG(SSSDBG_OP_FAILURE,
45 : "Error storing host %s [%d]: %s\n", name, ret, strerror(ret));
46 0 : return ret;
47 : }
48 :
49 2 : return EOK;
50 : }
51 :
52 : errno_t
53 2 : sysdb_store_ssh_host(struct sss_domain_info *domain,
54 : const char *name,
55 : const char *alias,
56 : int cache_timeout,
57 : time_t now,
58 : struct sysdb_attrs *attrs)
59 : {
60 : TALLOC_CTX *tmp_ctx;
61 : errno_t ret, sret;
62 2 : bool in_transaction = false;
63 2 : const char *search_attrs[] = { SYSDB_NAME_ALIAS, NULL };
64 : bool new_alias;
65 2 : struct ldb_message *host = NULL;
66 : struct ldb_message_element *el;
67 : unsigned int i;
68 :
69 2 : DEBUG(SSSDBG_TRACE_FUNC, "Storing host %s\n", name);
70 :
71 2 : tmp_ctx = talloc_new(NULL);
72 2 : if (!tmp_ctx) {
73 0 : return ENOMEM;
74 : }
75 :
76 2 : ret = sysdb_transaction_start(domain->sysdb);
77 2 : if (ret != EOK) {
78 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
79 0 : goto done;
80 : }
81 :
82 2 : in_transaction = true;
83 :
84 2 : ret = sysdb_get_ssh_host(tmp_ctx, domain, name, search_attrs, &host);
85 2 : if (ret != EOK && ret != ENOENT) {
86 0 : goto done;
87 : }
88 :
89 2 : ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, SYSDB_SSH_HOST_OC);
90 2 : if (ret != EOK) {
91 0 : DEBUG(SSSDBG_OP_FAILURE,
92 : "Could not set object class [%d]: %s\n", ret, strerror(ret));
93 0 : goto done;
94 : }
95 :
96 2 : ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, name);
97 2 : if (ret != EOK) {
98 0 : DEBUG(SSSDBG_OP_FAILURE,
99 : "Could not set name attribute [%d]: %s\n", ret, strerror(ret));
100 0 : goto done;
101 : }
102 :
103 2 : if (alias) {
104 0 : new_alias = true;
105 :
106 : /* copy aliases from the existing entry */
107 0 : if (host) {
108 0 : el = ldb_msg_find_element(host, SYSDB_NAME_ALIAS);
109 :
110 0 : if (el) {
111 0 : for (i = 0; i < el->num_values; i++) {
112 0 : if (strcmp((char *)el->values[i].data, alias) == 0) {
113 0 : new_alias = false;
114 : }
115 :
116 0 : ret = sysdb_attrs_add_val(attrs,
117 0 : SYSDB_NAME_ALIAS, &el->values[i]);
118 0 : if (ret != EOK) {
119 0 : DEBUG(SSSDBG_OP_FAILURE,
120 : "Could not add name alias %s [%d]: %s\n",
121 : el->values[i].data, ret, strerror(ret));
122 0 : goto done;
123 : }
124 : }
125 : }
126 : }
127 :
128 : /* add alias only if it is not already present */
129 0 : if (new_alias) {
130 0 : ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, alias);
131 0 : if (ret != EOK) {
132 0 : DEBUG(SSSDBG_OP_FAILURE,
133 : "Could not add name alias %s [%d]: %s\n",
134 : alias, ret, strerror(ret));
135 0 : goto done;
136 : }
137 : }
138 : }
139 :
140 : /* make sure sshPublicKey is present when modifying an existing host */
141 2 : if (host) {
142 0 : ret = sysdb_attrs_get_el(attrs, SYSDB_SSH_PUBKEY, &el);
143 0 : if (ret != EOK) {
144 0 : DEBUG(SSSDBG_OP_FAILURE,
145 : "Could not get sysdb sshPublicKey [%d]: %s\n",
146 : ret, strerror(ret));
147 0 : goto done;
148 : }
149 : }
150 :
151 2 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);
152 2 : if (ret != EOK) {
153 0 : DEBUG(SSSDBG_OP_FAILURE,
154 : "Could not set sysdb lastUpdate [%d]: %s\n",
155 : ret, strerror(ret));
156 0 : goto done;
157 : }
158 :
159 4 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,
160 2 : cache_timeout ? (now + cache_timeout) : 0);
161 2 : if (ret != EOK) {
162 0 : DEBUG(SSSDBG_OP_FAILURE, "Could not set sysdb cache expire [%d]: %s\n",
163 : ret, strerror(ret));
164 0 : goto done;
165 : }
166 :
167 2 : ret = sysdb_update_ssh_host(domain, name, attrs);
168 2 : if (ret != EOK) {
169 0 : goto done;
170 : }
171 :
172 2 : ret = sysdb_transaction_commit(domain->sysdb);
173 2 : if (ret != EOK) {
174 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
175 0 : goto done;
176 : }
177 :
178 2 : in_transaction = false;
179 :
180 2 : ret = EOK;
181 :
182 : done:
183 2 : if (in_transaction) {
184 0 : sret = sysdb_transaction_cancel(domain->sysdb);
185 0 : if (sret != EOK) {
186 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
187 : }
188 : }
189 :
190 2 : talloc_free(tmp_ctx);
191 :
192 2 : return ret;
193 : }
194 :
195 : errno_t
196 0 : sysdb_set_ssh_host_attr(struct sss_domain_info *domain,
197 : const char *name,
198 : struct sysdb_attrs *attrs,
199 : int mod_op)
200 : {
201 : errno_t ret;
202 : struct ldb_dn *dn;
203 : TALLOC_CTX *tmp_ctx;
204 :
205 0 : tmp_ctx = talloc_new(NULL);
206 0 : if (!tmp_ctx) {
207 0 : return ENOMEM;
208 : }
209 :
210 0 : dn = sysdb_ssh_host_dn(tmp_ctx, domain, name);
211 0 : if (!dn) {
212 0 : ret = ENOMEM;
213 0 : goto done;
214 : }
215 :
216 0 : ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op);
217 :
218 : done:
219 0 : talloc_free(tmp_ctx);
220 0 : return ret;
221 : }
222 :
223 : errno_t
224 0 : sysdb_update_ssh_known_host_expire(struct sss_domain_info *domain,
225 : const char *name,
226 : time_t now,
227 : int known_hosts_timeout)
228 : {
229 : TALLOC_CTX *tmp_ctx;
230 : errno_t ret;
231 : struct sysdb_attrs *attrs;
232 :
233 0 : DEBUG(SSSDBG_TRACE_FUNC,
234 : "Updating known_hosts expire time of host %s\n", name);
235 :
236 0 : tmp_ctx = talloc_new(NULL);
237 0 : if (!tmp_ctx) {
238 0 : return ENOMEM;
239 : }
240 :
241 0 : attrs = sysdb_new_attrs(tmp_ctx);
242 0 : if (!attrs) {
243 0 : ret = ENOMEM;
244 0 : goto done;
245 : }
246 :
247 0 : ret = sysdb_attrs_add_time_t(attrs, SYSDB_SSH_KNOWN_HOSTS_EXPIRE,
248 : now + known_hosts_timeout);
249 0 : if (ret != EOK) {
250 0 : DEBUG(SSSDBG_OP_FAILURE,
251 : "Could not set known_hosts expire time [%d]: %s\n",
252 : ret, strerror(ret));
253 0 : goto done;
254 : }
255 :
256 0 : ret = sysdb_update_ssh_host(domain, name, attrs);
257 0 : if (ret != EOK) {
258 0 : goto done;
259 : }
260 :
261 0 : ret = EOK;
262 :
263 : done:
264 0 : talloc_free(tmp_ctx);
265 :
266 0 : return ret;
267 : }
268 :
269 : errno_t
270 2 : sysdb_delete_ssh_host(struct sss_domain_info *domain,
271 : const char *name)
272 : {
273 2 : DEBUG(SSSDBG_TRACE_FUNC, "Deleting host %s\n", name);
274 2 : return sysdb_delete_custom(domain, name, SSH_HOSTS_SUBDIR);
275 : }
276 :
277 : errno_t
278 3 : sysdb_search_ssh_hosts(TALLOC_CTX *mem_ctx,
279 : struct sss_domain_info *domain,
280 : const char *filter,
281 : const char **attrs,
282 : size_t *num_hosts,
283 : struct ldb_message ***hosts)
284 : {
285 : errno_t ret;
286 : TALLOC_CTX *tmp_ctx;
287 : struct ldb_message **results;
288 : size_t num_results;
289 :
290 3 : tmp_ctx = talloc_new(NULL);
291 3 : if (!tmp_ctx) {
292 0 : return ENOMEM;
293 : }
294 :
295 3 : ret = sysdb_search_custom(tmp_ctx, domain, filter,
296 : SSH_HOSTS_SUBDIR, attrs,
297 : &num_results, &results);
298 3 : if (ret != EOK && ret != ENOENT) {
299 0 : DEBUG(SSSDBG_CRIT_FAILURE,
300 : "Error looking up host [%d]: %s\n",
301 : ret, strerror(ret));
302 0 : goto done;
303 3 : } if (ret == ENOENT) {
304 2 : DEBUG(SSSDBG_TRACE_FUNC, "No such host\n");
305 2 : *hosts = NULL;
306 2 : *num_hosts = 0;
307 2 : goto done;
308 : }
309 :
310 1 : *hosts = talloc_steal(mem_ctx, results);
311 1 : *num_hosts = num_results;
312 1 : ret = EOK;
313 :
314 : done:
315 3 : talloc_free(tmp_ctx);
316 :
317 3 : return ret;
318 : }
319 :
320 : errno_t
321 3 : sysdb_get_ssh_host(TALLOC_CTX *mem_ctx,
322 : struct sss_domain_info *domain,
323 : const char *name,
324 : const char **attrs,
325 : struct ldb_message **host)
326 : {
327 : TALLOC_CTX *tmp_ctx;
328 : errno_t ret;
329 : const char *filter;
330 : struct ldb_message **hosts;
331 : size_t num_hosts;
332 :
333 3 : tmp_ctx = talloc_new(NULL);
334 3 : if (!tmp_ctx) {
335 0 : return ENOMEM;
336 : }
337 :
338 3 : filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME, name);
339 3 : if (!filter) {
340 0 : ret = ENOMEM;
341 0 : goto done;
342 : }
343 :
344 3 : ret = sysdb_search_ssh_hosts(tmp_ctx, domain, filter, attrs,
345 : &num_hosts, &hosts);
346 3 : if (ret != EOK) {
347 2 : goto done;
348 : }
349 :
350 1 : if (num_hosts > 1) {
351 0 : ret = EINVAL;
352 0 : DEBUG(SSSDBG_CRIT_FAILURE,
353 : "Found more than one host with name %s\n", name);
354 0 : goto done;
355 : }
356 :
357 1 : *host = talloc_steal(mem_ctx, hosts[0]);
358 1 : ret = EOK;
359 :
360 : done:
361 3 : talloc_free(tmp_ctx);
362 :
363 3 : return ret;
364 : }
365 :
366 : errno_t
367 0 : sysdb_get_ssh_known_hosts(TALLOC_CTX *mem_ctx,
368 : struct sss_domain_info *domain,
369 : time_t now,
370 : const char **attrs,
371 : struct ldb_message ***hosts,
372 : size_t *num_hosts)
373 : {
374 : TALLOC_CTX *tmp_ctx;
375 : errno_t ret;
376 : const char *filter;
377 :
378 0 : tmp_ctx = talloc_new(NULL);
379 0 : if (!tmp_ctx) {
380 0 : return ENOMEM;
381 : }
382 :
383 0 : filter = talloc_asprintf(tmp_ctx,
384 : "(&(|(!(%s=*))(%s=0)(%s>=%lld))(%s>=%lld))",
385 : SYSDB_CACHE_EXPIRE,
386 : SYSDB_CACHE_EXPIRE,
387 : SYSDB_CACHE_EXPIRE, (long long)now + 1,
388 : SYSDB_SSH_KNOWN_HOSTS_EXPIRE, (long long)now + 1);
389 0 : if (!filter) {
390 0 : ret = ENOMEM;
391 0 : goto done;
392 : }
393 :
394 0 : ret = sysdb_search_ssh_hosts(mem_ctx, domain, filter, attrs,
395 : num_hosts, hosts);
396 :
397 : done:
398 0 : talloc_free(tmp_ctx);
399 :
400 0 : return ret;
401 : }
|