Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/rpc/key_call.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 2009, Sun Microsystems, Inc.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions are met:
9
* - Redistributions of source code must retain the above copyright notice,
10
* this list of conditions and the following disclaimer.
11
* - Redistributions in binary form must reproduce the above copyright notice,
12
* this list of conditions and the following disclaimer in the documentation
13
* and/or other materials provided with the distribution.
14
* - Neither the name of Sun Microsystems, Inc. nor the names of its
15
* contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
* POSSIBILITY OF SUCH DAMAGE.
29
*/
30
/*
31
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
32
*/
33
34
/*
35
* key_call.c, Interface to keyserver
36
*
37
* setsecretkey(key) - set your secret key
38
* encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent
39
* decryptsessionkey(agent, deskey) - decrypt ditto
40
* gendeskey(deskey) - generate a secure des key
41
*/
42
43
#include "namespace.h"
44
#include "reentrant.h"
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <unistd.h>
48
#include <errno.h>
49
#include <rpc/rpc.h>
50
#include <rpc/auth.h>
51
#include <rpc/auth_unix.h>
52
#include <rpc/key_prot.h>
53
#include <string.h>
54
#include <netconfig.h>
55
#include <sys/utsname.h>
56
#include <stdlib.h>
57
#include <signal.h>
58
#include <sys/wait.h>
59
#include <sys/fcntl.h>
60
#include "un-namespace.h"
61
#include "mt_misc.h"
62
63
64
#define KEY_TIMEOUT 5 /* per-try timeout in seconds */
65
#define KEY_NRETRY 12 /* number of retries */
66
67
#ifdef DEBUG
68
#define debug(msg) (void) fprintf(stderr, "%s\n", msg);
69
#else
70
#define debug(msg)
71
#endif /* DEBUG */
72
73
/*
74
* Hack to allow the keyserver to use AUTH_DES (for authenticated
75
* NIS+ calls, for example). The only functions that get called
76
* are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
77
*
78
* The approach is to have the keyserver fill in pointers to local
79
* implementations of these functions, and to call those in key_call().
80
*/
81
82
cryptkeyres *(*__key_encryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
83
cryptkeyres *(*__key_decryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
84
des_block *(*__key_gendes_LOCAL)(uid_t, void *) = 0;
85
86
static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *);
87
88
int
89
key_setsecret(const char *secretkey)
90
{
91
keystatus status;
92
93
if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf,
94
(void *)secretkey,
95
(xdrproc_t)xdr_keystatus, &status)) {
96
return (-1);
97
}
98
if (status != KEY_SUCCESS) {
99
debug("set status is nonzero");
100
return (-1);
101
}
102
return (0);
103
}
104
105
106
/* key_secretkey_is_set() returns 1 if the keyserver has a secret key
107
* stored for the caller's effective uid; it returns 0 otherwise
108
*
109
* N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
110
* be using it, because it allows them to get the user's secret key.
111
*/
112
113
int
114
key_secretkey_is_set(void)
115
{
116
struct key_netstres kres;
117
118
memset((void*)&kres, 0, sizeof (kres));
119
if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL,
120
(xdrproc_t)xdr_key_netstres, &kres) &&
121
(kres.status == KEY_SUCCESS) &&
122
(kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
123
/* avoid leaving secret key in memory */
124
memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
125
return (1);
126
}
127
return (0);
128
}
129
130
int
131
key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
132
{
133
cryptkeyarg2 arg;
134
cryptkeyres res;
135
136
arg.remotename = remotename;
137
arg.remotekey = *remotekey;
138
arg.deskey = *deskey;
139
if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
140
(xdrproc_t)xdr_cryptkeyres, &res)) {
141
return (-1);
142
}
143
if (res.status != KEY_SUCCESS) {
144
debug("encrypt status is nonzero");
145
return (-1);
146
}
147
*deskey = res.cryptkeyres_u.deskey;
148
return (0);
149
}
150
151
int
152
key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
153
{
154
cryptkeyarg2 arg;
155
cryptkeyres res;
156
157
arg.remotename = remotename;
158
arg.remotekey = *remotekey;
159
arg.deskey = *deskey;
160
if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
161
(xdrproc_t)xdr_cryptkeyres, &res)) {
162
return (-1);
163
}
164
if (res.status != KEY_SUCCESS) {
165
debug("decrypt status is nonzero");
166
return (-1);
167
}
168
*deskey = res.cryptkeyres_u.deskey;
169
return (0);
170
}
171
172
int
173
key_encryptsession(const char *remotename, des_block *deskey)
174
{
175
cryptkeyarg arg;
176
cryptkeyres res;
177
178
arg.remotename = (char *) remotename;
179
arg.deskey = *deskey;
180
if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
181
(xdrproc_t)xdr_cryptkeyres, &res)) {
182
return (-1);
183
}
184
if (res.status != KEY_SUCCESS) {
185
debug("encrypt status is nonzero");
186
return (-1);
187
}
188
*deskey = res.cryptkeyres_u.deskey;
189
return (0);
190
}
191
192
int
193
key_decryptsession(const char *remotename, des_block *deskey)
194
{
195
cryptkeyarg arg;
196
cryptkeyres res;
197
198
arg.remotename = (char *) remotename;
199
arg.deskey = *deskey;
200
if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
201
(xdrproc_t)xdr_cryptkeyres, &res)) {
202
return (-1);
203
}
204
if (res.status != KEY_SUCCESS) {
205
debug("decrypt status is nonzero");
206
return (-1);
207
}
208
*deskey = res.cryptkeyres_u.deskey;
209
return (0);
210
}
211
212
int
213
key_gendes(des_block *key)
214
{
215
if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL,
216
(xdrproc_t)xdr_des_block, key)) {
217
return (-1);
218
}
219
return (0);
220
}
221
222
int
223
key_setnet(struct key_netstarg *arg)
224
{
225
keystatus status;
226
227
228
if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg,
229
(xdrproc_t)xdr_keystatus, &status)){
230
return (-1);
231
}
232
233
if (status != KEY_SUCCESS) {
234
debug("key_setnet status is nonzero");
235
return (-1);
236
}
237
return (1);
238
}
239
240
241
int
242
key_get_conv(char *pkey, des_block *deskey)
243
{
244
cryptkeyres res;
245
246
if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey,
247
(xdrproc_t)xdr_cryptkeyres, &res)) {
248
return (-1);
249
}
250
if (res.status != KEY_SUCCESS) {
251
debug("get_conv status is nonzero");
252
return (-1);
253
}
254
*deskey = res.cryptkeyres_u.deskey;
255
return (0);
256
}
257
258
struct key_call_private {
259
CLIENT *client; /* Client handle */
260
pid_t pid; /* process-id at moment of creation */
261
uid_t uid; /* user-id at last authorization */
262
};
263
static struct key_call_private *key_call_private_main = NULL;
264
static thread_key_t key_call_key;
265
static once_t key_call_once = ONCE_INITIALIZER;
266
static int key_call_key_error;
267
268
static void
269
key_call_destroy(void *vp)
270
{
271
struct key_call_private *kcp = (struct key_call_private *)vp;
272
273
if (kcp) {
274
if (kcp->client)
275
clnt_destroy(kcp->client);
276
free(kcp);
277
}
278
}
279
280
static void
281
key_call_init(void)
282
{
283
284
key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy);
285
}
286
287
/*
288
* Keep the handle cached. This call may be made quite often.
289
*/
290
static CLIENT *
291
getkeyserv_handle(int vers)
292
{
293
void *localhandle;
294
struct netconfig *nconf;
295
struct netconfig *tpconf;
296
struct key_call_private *kcp;
297
struct timeval wait_time;
298
struct utsname u;
299
int main_thread;
300
int fd;
301
302
#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
303
#define TOTAL_TRIES 5 /* Number of tries */
304
305
if ((main_thread = thr_main())) {
306
kcp = key_call_private_main;
307
} else {
308
if (thr_once(&key_call_once, key_call_init) != 0 ||
309
key_call_key_error != 0)
310
return ((CLIENT *) NULL);
311
kcp = (struct key_call_private *)thr_getspecific(key_call_key);
312
}
313
if (kcp == (struct key_call_private *)NULL) {
314
kcp = (struct key_call_private *)malloc(sizeof (*kcp));
315
if (kcp == (struct key_call_private *)NULL) {
316
return ((CLIENT *) NULL);
317
}
318
if (main_thread)
319
key_call_private_main = kcp;
320
else
321
thr_setspecific(key_call_key, (void *) kcp);
322
kcp->client = NULL;
323
}
324
325
/* if pid has changed, destroy client and rebuild */
326
if (kcp->client != NULL && kcp->pid != getpid()) {
327
clnt_destroy(kcp->client);
328
kcp->client = NULL;
329
}
330
331
if (kcp->client != NULL) {
332
/* if uid has changed, build client handle again */
333
if (kcp->uid != geteuid()) {
334
kcp->uid = geteuid();
335
auth_destroy(kcp->client->cl_auth);
336
kcp->client->cl_auth =
337
authsys_create("", kcp->uid, 0, 0, NULL);
338
if (kcp->client->cl_auth == NULL) {
339
clnt_destroy(kcp->client);
340
kcp->client = NULL;
341
return ((CLIENT *) NULL);
342
}
343
}
344
/* Change the version number to the new one */
345
clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
346
return (kcp->client);
347
}
348
if (!(localhandle = setnetconfig())) {
349
return ((CLIENT *) NULL);
350
}
351
tpconf = NULL;
352
#if defined(__FreeBSD__)
353
if (uname(&u) == -1)
354
#else
355
#if defined(i386)
356
if (_nuname(&u) == -1)
357
#elif defined(sparc)
358
if (_uname(&u) == -1)
359
#else
360
#error Unknown architecture!
361
#endif
362
#endif
363
{
364
endnetconfig(localhandle);
365
return ((CLIENT *) NULL);
366
}
367
while ((nconf = getnetconfig(localhandle)) != NULL) {
368
if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
369
/*
370
* We use COTS_ORD here so that the caller can
371
* find out immediately if the server is dead.
372
*/
373
if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
374
kcp->client = clnt_tp_create(u.nodename,
375
KEY_PROG, vers, nconf);
376
if (kcp->client)
377
break;
378
} else {
379
tpconf = nconf;
380
}
381
}
382
}
383
if ((kcp->client == (CLIENT *) NULL) && (tpconf))
384
/* Now, try the CLTS or COTS loopback transport */
385
kcp->client = clnt_tp_create(u.nodename,
386
KEY_PROG, vers, tpconf);
387
endnetconfig(localhandle);
388
389
if (kcp->client == (CLIENT *) NULL) {
390
return ((CLIENT *) NULL);
391
}
392
kcp->uid = geteuid();
393
kcp->pid = getpid();
394
kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL);
395
if (kcp->client->cl_auth == NULL) {
396
clnt_destroy(kcp->client);
397
kcp->client = NULL;
398
return ((CLIENT *) NULL);
399
}
400
401
wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
402
wait_time.tv_usec = 0;
403
(void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT,
404
(char *)&wait_time);
405
if (clnt_control(kcp->client, CLGET_FD, (char *)&fd))
406
_fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
407
408
return (kcp->client);
409
}
410
411
/* returns 0 on failure, 1 on success */
412
413
static int
414
key_call(u_long proc, xdrproc_t xdr_arg, void *arg, xdrproc_t xdr_rslt,
415
void *rslt)
416
{
417
CLIENT *clnt;
418
struct timeval wait_time;
419
420
if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
421
cryptkeyres *res;
422
res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg);
423
*(cryptkeyres*)rslt = *res;
424
return (1);
425
} else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
426
cryptkeyres *res;
427
res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg);
428
*(cryptkeyres*)rslt = *res;
429
return (1);
430
} else if (proc == KEY_GEN && __key_gendes_LOCAL) {
431
des_block *res;
432
res = (*__key_gendes_LOCAL)(geteuid(), 0);
433
*(des_block*)rslt = *res;
434
return (1);
435
}
436
437
if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
438
(proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
439
(proc == KEY_GET_CONV))
440
clnt = getkeyserv_handle(2); /* talk to version 2 */
441
else
442
clnt = getkeyserv_handle(1); /* talk to version 1 */
443
444
if (clnt == NULL) {
445
return (0);
446
}
447
448
wait_time.tv_sec = TOTAL_TIMEOUT;
449
wait_time.tv_usec = 0;
450
451
if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
452
wait_time) == RPC_SUCCESS) {
453
return (1);
454
} else {
455
return (0);
456
}
457
}
458
459