source: rtems-libbsd/freebsd/lib/libc/rpc/key_call.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 60b1d40, checked in by Sebastian Huber <sebastian.huber@…>, on 06/09/16 at 08:23:57

RPC(3): Import from FreeBSD

  • Property mode set to 100644
File size: 12.0 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
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#ident  "@(#)key_call.c 1.25    94/04/24 SMI"
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38/*
39 * key_call.c, Interface to keyserver
40 *
41 * setsecretkey(key) - set your secret key
42 * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent
43 * decryptsessionkey(agent, deskey) - decrypt ditto
44 * gendeskey(deskey) - generate a secure des key
45 */
46
47#include "namespace.h"
48#include "reentrant.h"
49#include <stdio.h>
50#include <stdlib.h>
51#include <unistd.h>
52#include <errno.h>
53#include <rpc/rpc.h>
54#include <rpc/auth.h>
55#include <rpc/auth_unix.h>
56#include <rpc/key_prot.h>
57#include <string.h>
58#include <netconfig.h>
59#include <sys/utsname.h>
60#include <stdlib.h>
61#include <signal.h>
62#include <sys/wait.h>
63#include <sys/fcntl.h>
64#include "un-namespace.h"
65#include "mt_misc.h"
66
67
68#define KEY_TIMEOUT     5       /* per-try timeout in seconds */
69#define KEY_NRETRY      12      /* number of retries */
70
71#ifdef DEBUG
72#define debug(msg)      (void) fprintf(stderr, "%s\n", msg);
73#else
74#define debug(msg)
75#endif /* DEBUG */
76
77/*
78 * Hack to allow the keyserver to use AUTH_DES (for authenticated
79 * NIS+ calls, for example).  The only functions that get called
80 * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
81 *
82 * The approach is to have the keyserver fill in pointers to local
83 * implementations of these functions, and to call those in key_call().
84 */
85
86cryptkeyres *(*__key_encryptsession_pk_LOCAL)() = 0;
87cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0;
88des_block *(*__key_gendes_LOCAL)() = 0;
89
90static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *);
91
92int
93key_setsecret(secretkey)
94        const char *secretkey;
95{
96        keystatus status;
97
98        if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf,
99                        (void *)secretkey,
100                        (xdrproc_t)xdr_keystatus, &status)) {
101                return (-1);
102        }
103        if (status != KEY_SUCCESS) {
104                debug("set status is nonzero");
105                return (-1);
106        }
107        return (0);
108}
109
110
111/* key_secretkey_is_set() returns 1 if the keyserver has a secret key
112 * stored for the caller's effective uid; it returns 0 otherwise
113 *
114 * N.B.:  The KEY_NET_GET key call is undocumented.  Applications shouldn't
115 * be using it, because it allows them to get the user's secret key.
116 */
117
118int
119key_secretkey_is_set(void)
120{
121        struct key_netstres     kres;
122
123        memset((void*)&kres, 0, sizeof (kres));
124        if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL,
125                        (xdrproc_t)xdr_key_netstres, &kres) &&
126            (kres.status == KEY_SUCCESS) &&
127            (kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
128                /* avoid leaving secret key in memory */
129                memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
130                return (1);
131        }
132        return (0);
133}
134
135int
136key_encryptsession_pk(remotename, remotekey, deskey)
137        char *remotename;
138        netobj *remotekey;
139        des_block *deskey;
140{
141        cryptkeyarg2 arg;
142        cryptkeyres res;
143
144        arg.remotename = remotename;
145        arg.remotekey = *remotekey;
146        arg.deskey = *deskey;
147        if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
148                        (xdrproc_t)xdr_cryptkeyres, &res)) {
149                return (-1);
150        }
151        if (res.status != KEY_SUCCESS) {
152                debug("encrypt status is nonzero");
153                return (-1);
154        }
155        *deskey = res.cryptkeyres_u.deskey;
156        return (0);
157}
158
159int
160key_decryptsession_pk(remotename, remotekey, deskey)
161        char *remotename;
162        netobj *remotekey;
163        des_block *deskey;
164{
165        cryptkeyarg2 arg;
166        cryptkeyres res;
167
168        arg.remotename = remotename;
169        arg.remotekey = *remotekey;
170        arg.deskey = *deskey;
171        if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
172                        (xdrproc_t)xdr_cryptkeyres, &res)) {
173                return (-1);
174        }
175        if (res.status != KEY_SUCCESS) {
176                debug("decrypt status is nonzero");
177                return (-1);
178        }
179        *deskey = res.cryptkeyres_u.deskey;
180        return (0);
181}
182
183int
184key_encryptsession(remotename, deskey)
185        const char *remotename;
186        des_block *deskey;
187{
188        cryptkeyarg arg;
189        cryptkeyres res;
190
191        arg.remotename = (char *) remotename;
192        arg.deskey = *deskey;
193        if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
194                        (xdrproc_t)xdr_cryptkeyres, &res)) {
195                return (-1);
196        }
197        if (res.status != KEY_SUCCESS) {
198                debug("encrypt status is nonzero");
199                return (-1);
200        }
201        *deskey = res.cryptkeyres_u.deskey;
202        return (0);
203}
204
205int
206key_decryptsession(remotename, deskey)
207        const char *remotename;
208        des_block *deskey;
209{
210        cryptkeyarg arg;
211        cryptkeyres res;
212
213        arg.remotename = (char *) remotename;
214        arg.deskey = *deskey;
215        if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
216                        (xdrproc_t)xdr_cryptkeyres, &res)) {
217                return (-1);
218        }
219        if (res.status != KEY_SUCCESS) {
220                debug("decrypt status is nonzero");
221                return (-1);
222        }
223        *deskey = res.cryptkeyres_u.deskey;
224        return (0);
225}
226
227int
228key_gendes(key)
229        des_block *key;
230{
231        if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL,
232                        (xdrproc_t)xdr_des_block, key)) {
233                return (-1);
234        }
235        return (0);
236}
237
238int
239key_setnet(arg)
240struct key_netstarg *arg;
241{
242        keystatus status;
243
244
245        if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg,
246                        (xdrproc_t)xdr_keystatus, &status)){
247                return (-1);
248        }
249
250        if (status != KEY_SUCCESS) {
251                debug("key_setnet status is nonzero");
252                return (-1);
253        }
254        return (1);
255}
256
257
258int
259key_get_conv(pkey, deskey)
260        char *pkey;
261        des_block *deskey;
262{
263        cryptkeyres res;
264
265        if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey,
266                        (xdrproc_t)xdr_cryptkeyres, &res)) {
267                return (-1);
268        }
269        if (res.status != KEY_SUCCESS) {
270                debug("get_conv status is nonzero");
271                return (-1);
272        }
273        *deskey = res.cryptkeyres_u.deskey;
274        return (0);
275}
276
277struct  key_call_private {
278        CLIENT  *client;        /* Client handle */
279        pid_t   pid;            /* process-id at moment of creation */
280        uid_t   uid;            /* user-id at last authorization */
281};
282static struct key_call_private *key_call_private_main = NULL;
283static thread_key_t key_call_key;
284static once_t key_call_once = ONCE_INITIALIZER;
285static int key_call_key_error;
286
287static void
288key_call_destroy(void *vp)
289{
290        struct key_call_private *kcp = (struct key_call_private *)vp;
291
292        if (kcp) {
293                if (kcp->client)
294                        clnt_destroy(kcp->client);
295                free(kcp);
296        }
297}
298
299static void
300key_call_init(void)
301{
302
303        key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy);
304}
305
306/*
307 * Keep the handle cached.  This call may be made quite often.
308 */
309static CLIENT *
310getkeyserv_handle(vers)
311int     vers;
312{
313        void *localhandle;
314        struct netconfig *nconf;
315        struct netconfig *tpconf;
316        struct key_call_private *kcp;
317        struct timeval wait_time;
318        struct utsname u;
319        int main_thread;
320        int fd;
321
322#define TOTAL_TIMEOUT   30      /* total timeout talking to keyserver */
323#define TOTAL_TRIES     5       /* Number of tries */
324
325        if ((main_thread = thr_main())) {
326                kcp = key_call_private_main;
327        } else {
328                if (thr_once(&key_call_once, key_call_init) != 0 ||
329                    key_call_key_error != 0)
330                        return ((CLIENT *) NULL);
331                kcp = (struct key_call_private *)thr_getspecific(key_call_key);
332        }       
333        if (kcp == (struct key_call_private *)NULL) {
334                kcp = (struct key_call_private *)malloc(sizeof (*kcp));
335                if (kcp == (struct key_call_private *)NULL) {
336                        return ((CLIENT *) NULL);
337                }
338                if (main_thread)
339                        key_call_private_main = kcp;
340                else
341                        thr_setspecific(key_call_key, (void *) kcp);
342                kcp->client = NULL;
343        }
344
345        /* if pid has changed, destroy client and rebuild */
346        if (kcp->client != NULL && kcp->pid != getpid()) {
347                clnt_destroy(kcp->client);
348                kcp->client = NULL;
349        }
350
351        if (kcp->client != NULL) {
352                /* if uid has changed, build client handle again */
353                if (kcp->uid != geteuid()) {
354                        kcp->uid = geteuid();
355                        auth_destroy(kcp->client->cl_auth);
356                        kcp->client->cl_auth =
357                                authsys_create("", kcp->uid, 0, 0, NULL);
358                        if (kcp->client->cl_auth == NULL) {
359                                clnt_destroy(kcp->client);
360                                kcp->client = NULL;
361                                return ((CLIENT *) NULL);
362                        }
363                }
364                /* Change the version number to the new one */
365                clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
366                return (kcp->client);
367        }
368        if (!(localhandle = setnetconfig())) {
369                return ((CLIENT *) NULL);
370        }
371        tpconf = NULL;
372#if defined(__FreeBSD__)
373        if (uname(&u) == -1)
374#else
375#if defined(i386)
376        if (_nuname(&u) == -1)
377#elif defined(sparc)
378        if (_uname(&u) == -1)
379#else
380#error Unknown architecture!
381#endif
382#endif
383        {
384                endnetconfig(localhandle);
385                return ((CLIENT *) NULL);
386        }
387        while ((nconf = getnetconfig(localhandle)) != NULL) {
388                if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
389                        /*
390                         * We use COTS_ORD here so that the caller can
391                         * find out immediately if the server is dead.
392                         */
393                        if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
394                                kcp->client = clnt_tp_create(u.nodename,
395                                        KEY_PROG, vers, nconf);
396                                if (kcp->client)
397                                        break;
398                        } else {
399                                tpconf = nconf;
400                        }
401                }
402        }
403        if ((kcp->client == (CLIENT *) NULL) && (tpconf))
404                /* Now, try the CLTS or COTS loopback transport */
405                kcp->client = clnt_tp_create(u.nodename,
406                        KEY_PROG, vers, tpconf);
407        endnetconfig(localhandle);
408
409        if (kcp->client == (CLIENT *) NULL) {
410                return ((CLIENT *) NULL);
411        }
412        kcp->uid = geteuid();
413        kcp->pid = getpid();
414        kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL);
415        if (kcp->client->cl_auth == NULL) {
416                clnt_destroy(kcp->client);
417                kcp->client = NULL;
418                return ((CLIENT *) NULL);
419        }
420
421        wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
422        wait_time.tv_usec = 0;
423        (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT,
424                (char *)&wait_time);
425        if (clnt_control(kcp->client, CLGET_FD, (char *)&fd))
426                _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
427
428        return (kcp->client);
429}
430
431/* returns  0 on failure, 1 on success */
432
433static int
434key_call(proc, xdr_arg, arg, xdr_rslt, rslt)
435        u_long proc;
436        xdrproc_t xdr_arg;
437        void *arg;
438        xdrproc_t xdr_rslt;
439        void *rslt;
440{
441        CLIENT *clnt;
442        struct timeval wait_time;
443
444        if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
445                cryptkeyres *res;
446                res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg);
447                *(cryptkeyres*)rslt = *res;
448                return (1);
449        } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
450                cryptkeyres *res;
451                res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg);
452                *(cryptkeyres*)rslt = *res;
453                return (1);
454        } else if (proc == KEY_GEN && __key_gendes_LOCAL) {
455                des_block *res;
456                res = (*__key_gendes_LOCAL)(geteuid(), 0);
457                *(des_block*)rslt = *res;
458                return (1);
459        }
460
461        if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
462            (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
463            (proc == KEY_GET_CONV))
464                clnt = getkeyserv_handle(2); /* talk to version 2 */
465        else
466                clnt = getkeyserv_handle(1); /* talk to version 1 */
467
468        if (clnt == NULL) {
469                return (0);
470        }
471
472        wait_time.tv_sec = TOTAL_TIMEOUT;
473        wait_time.tv_usec = 0;
474
475        if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
476                wait_time) == RPC_SUCCESS) {
477                return (1);
478        } else {
479                return (0);
480        }
481}
Note: See TracBrowser for help on using the repository browser.