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 <errno.h>
24 : #include <stdlib.h>
25 : #include <stdio.h>
26 : #include <talloc.h>
27 :
28 : #include <popt.h>
29 : #include <locale.h>
30 : #include <libintl.h>
31 : #include <string.h>
32 :
33 : #include "util/util.h"
34 : #include "util/crypto/sss_crypto.h"
35 : #include "util/sss_ssh.h"
36 : #include "sss_client/sss_cli.h"
37 : #include "sss_client/ssh/sss_ssh_client.h"
38 :
39 : /* FIXME - split from tools_util to create a common function */
40 0 : void usage(poptContext pc, const char *error)
41 : {
42 0 : poptPrintUsage(pc, stderr, 0);
43 0 : if (error) fprintf(stderr, "%s", error);
44 0 : }
45 :
46 : /* FIXME - split from tools_util to create a common function */
47 0 : int set_locale(void)
48 : {
49 : char *c;
50 :
51 0 : c = setlocale(LC_ALL, "");
52 0 : if (c == NULL) {
53 0 : return EIO;
54 : }
55 :
56 0 : errno = 0;
57 0 : c = bindtextdomain(PACKAGE, LOCALEDIR);
58 0 : if (c == NULL) {
59 0 : return errno;
60 : }
61 :
62 0 : errno = 0;
63 0 : c = textdomain(PACKAGE);
64 0 : if (c == NULL) {
65 0 : return errno;
66 : }
67 :
68 0 : return EOK;
69 : }
70 :
71 : /* SSH public key request:
72 : *
73 : * header:
74 : * 0..3: flags (unsigned int, must be combination of SSS_SSH_REQ_* flags)
75 : * 4..7: name length (unsigned int)
76 : * 8..X: name (null-terminated UTF-8 string)
77 : * alias (only included if flags & SSS_SSH_REQ_ALIAS):
78 : * 0..3: alias length (unsigned int)
79 : * 4..X: alias (null-terminated UTF-8 string)
80 : * domain (ony included if flags & SSS_SSH_REQ_DOMAIN):
81 : * 0..3: domain length (unsigned int, 0 means default domain)
82 : * 4..X: domain (null-terminated UTF-8 string)
83 : *
84 : * SSH public key reply:
85 : *
86 : * header:
87 : * 0..3: number of results (unsigned int)
88 : * 4..7: reserved (unsigned int, must be 0)
89 : * results (repeated for each result):
90 : * 0..3: flags (unsigned int, must be 0)
91 : * 4..7: name length (unsigned int)
92 : * 8..(X-1): name (null-terminated UTF-8 string)
93 : * X..(X+3): key length (unsigned int)
94 : * (X+4)..Y: key (public key data)
95 : */
96 : errno_t
97 0 : sss_ssh_get_ent(TALLOC_CTX *mem_ctx,
98 : enum sss_cli_command command,
99 : const char *name,
100 : const char *domain,
101 : const char *alias,
102 : struct sss_ssh_ent **result)
103 : {
104 : TALLOC_CTX *tmp_ctx;
105 0 : struct sss_ssh_ent *res = NULL;
106 : errno_t ret;
107 : uint32_t flags;
108 : uint32_t name_len;
109 0 : uint32_t alias_len = 0;
110 : uint32_t domain_len;
111 : size_t req_len;
112 0 : uint8_t *req = NULL;
113 0 : size_t c = 0;
114 : struct sss_cli_req_data rd;
115 : int req_ret, req_errno;
116 0 : uint8_t *rep = NULL;
117 : size_t rep_len;
118 : uint32_t count, reserved, len, i;
119 :
120 0 : tmp_ctx = talloc_new(NULL);
121 0 : if (!tmp_ctx) {
122 0 : return ENOMEM;
123 : }
124 :
125 : /* build request */
126 0 : flags = 0;
127 0 : name_len = strlen(name)+1;
128 0 : req_len = 2*sizeof(uint32_t) + name_len;
129 :
130 0 : if (alias) {
131 0 : flags |= SSS_SSH_REQ_ALIAS;
132 0 : alias_len = strlen(alias)+1;
133 0 : req_len += sizeof(uint32_t) + alias_len;
134 : }
135 :
136 0 : flags |= SSS_SSH_REQ_DOMAIN;
137 0 : domain_len = domain ? (strlen(domain)+1) : 0;
138 0 : req_len += sizeof(uint32_t) + domain_len;
139 :
140 0 : req = talloc_array(tmp_ctx, uint8_t, req_len);
141 0 : if (!req) {
142 0 : ret = ENOMEM;
143 0 : goto done;
144 : }
145 :
146 0 : SAFEALIGN_SET_UINT32(req+c, flags, &c);
147 0 : SAFEALIGN_SET_UINT32(req+c, name_len, &c);
148 0 : safealign_memcpy(req+c, name, name_len, &c);
149 0 : if (alias) {
150 0 : SAFEALIGN_SET_UINT32(req+c, alias_len, &c);
151 0 : safealign_memcpy(req+c, alias, alias_len, &c);
152 : }
153 0 : SAFEALIGN_SET_UINT32(req+c, domain_len, &c);
154 0 : if (domain_len > 0) {
155 0 : safealign_memcpy(req+c, domain, domain_len, &c);
156 : }
157 :
158 : /* send request */
159 0 : rd.data = req;
160 0 : rd.len = req_len;
161 :
162 0 : req_ret = sss_ssh_make_request(command, &rd, &rep, &rep_len, &req_errno);
163 0 : if (req_errno != EOK) {
164 0 : ret = req_errno;
165 0 : goto done;
166 : }
167 0 : if (req_ret != SSS_STATUS_SUCCESS) {
168 0 : ret = EFAULT;
169 0 : goto done;
170 : }
171 :
172 : /* parse reply */
173 0 : c = 0;
174 0 : if (rep_len < c + 2*sizeof(uint32_t)) {
175 0 : ret = EINVAL;
176 0 : goto done;
177 : }
178 :
179 0 : SAFEALIGN_COPY_UINT32(&count, rep+c, &c);
180 :
181 0 : SAFEALIGN_COPY_UINT32(&reserved, rep+c, &c);
182 0 : if (reserved != 0) {
183 0 : ret = EINVAL;
184 0 : goto done;
185 : }
186 :
187 0 : res = talloc_zero(tmp_ctx, struct sss_ssh_ent);
188 0 : if (!res) {
189 0 : ret = ENOMEM;
190 0 : goto done;
191 : }
192 :
193 0 : if (count > 0) {
194 0 : res->pubkeys = talloc_zero_array(res, struct sss_ssh_pubkey, count);
195 0 : if (!res->pubkeys) {
196 0 : ret = ENOMEM;
197 0 : goto done;
198 : }
199 :
200 0 : res->num_pubkeys = count;
201 : }
202 :
203 0 : for (i = 0; i < count; i++) {
204 0 : if (rep_len-c < 2*sizeof(uint32_t)) {
205 0 : ret = EINVAL;
206 0 : goto done;
207 : }
208 :
209 0 : SAFEALIGN_COPY_UINT32(&flags, rep+c, &c);
210 0 : if (flags != 0) {
211 0 : ret = EINVAL;
212 0 : goto done;
213 : }
214 :
215 0 : SAFEALIGN_COPY_UINT32(&len, rep+c, &c);
216 :
217 0 : if (len > rep_len - c - sizeof(uint32_t)) {
218 0 : ret = EINVAL;
219 0 : goto done;
220 : }
221 :
222 0 : if (!res->name) {
223 0 : res->name = talloc_array(res, char, len);
224 0 : if (!res->name) {
225 0 : ret = ENOMEM;
226 0 : goto done;
227 : }
228 :
229 0 : safealign_memcpy(res->name, rep+c, len, &c);
230 0 : if (strnlen(res->name, len) != len-1) {
231 0 : ret = EINVAL;
232 0 : goto done;
233 : }
234 : } else {
235 0 : c += len;
236 : }
237 :
238 0 : SAFEALIGN_COPY_UINT32(&len, rep+c, &c);
239 :
240 0 : if (len > rep_len - c) {
241 0 : ret = EINVAL;
242 0 : goto done;
243 : }
244 :
245 0 : res->pubkeys[i].data = talloc_array(res, uint8_t, len);
246 0 : if (!res->pubkeys[i].data) {
247 0 : ret = ENOMEM;
248 0 : goto done;
249 : }
250 :
251 0 : safealign_memcpy(res->pubkeys[i].data, rep+c, len, &c);
252 0 : res->pubkeys[i].data_len = len;
253 : }
254 :
255 0 : *result = talloc_steal(mem_ctx, res);
256 0 : ret = EOK;
257 :
258 : done:
259 0 : talloc_free(tmp_ctx);
260 0 : free(rep);
261 :
262 0 : return ret;
263 : }
|