Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/rpc/svc.c
39536 views
1
/* @(#)svc.c 2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */
2
/*
3
* Copyright (c) 2010, Oracle America, Inc.
4
*
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
*
10
* * Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
13
* * Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in
15
* the documentation and/or other materials provided with the
16
* distribution.
17
*
18
* * Neither the name of the "Oracle America, Inc." nor the names of
19
* its contributors may be used to endorse or promote products
20
* derived from this software without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
23
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
28
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
*/
34
#if !defined(lint) && defined(SCCSIDS)
35
static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro";
36
#endif
37
38
/*
39
* svc.c, Server-side remote procedure call interface.
40
*
41
* There are two sets of procedures here. The xprt routines are
42
* for handling transport handles. The svc routines handle the
43
* list of service routines.
44
*/
45
46
#include "autoconf.h"
47
#if HAVE_SYS_PARAM_H
48
#include <sys/param.h>
49
#endif
50
#include <gssrpc/rpc.h>
51
#include <gssrpc/pmap_clnt.h>
52
#include <stdio.h>
53
#include <string.h>
54
#include <errno.h>
55
56
#ifdef FD_SETSIZE
57
static SVCXPRT **xports;
58
extern int gssrpc_svc_fdset_init;
59
#else
60
61
#ifdef NBBY
62
#define NOFILE (sizeof(int) * NBBY)
63
#else
64
#define NOFILE (sizeof(int) * 8)
65
#endif
66
67
static SVCXPRT *xports[NOFILE];
68
#endif /* def FD_SETSIZE */
69
70
#define NULL_SVC ((struct svc_callout *)0)
71
#define RQCRED_SIZE 1024 /* this size is excessive */
72
73
/*
74
* The services list
75
* Each entry represents a set of procedures (an rpc program).
76
* The dispatch routine takes request structs and runs the
77
* appropriate procedure.
78
*/
79
static struct svc_callout {
80
struct svc_callout *sc_next;
81
rpcprog_t sc_prog;
82
rpcprog_t sc_vers;
83
void (*sc_dispatch)(struct svc_req *, SVCXPRT *);
84
} *svc_head;
85
86
static struct svc_callout *svc_find(rpcprog_t, rpcvers_t,
87
struct svc_callout **);
88
89
static void svc_do_xprt(SVCXPRT *xprt);
90
91
/* *************** SVCXPRT related stuff **************** */
92
93
/*
94
* Activate a transport handle.
95
*/
96
void
97
xprt_register(SVCXPRT *xprt)
98
{
99
int sock = xprt->xp_sock;
100
101
#ifdef FD_SETSIZE
102
if (gssrpc_svc_fdset_init == 0) {
103
FD_ZERO(&svc_fdset);
104
gssrpc_svc_fdset_init++;
105
}
106
if (xports == NULL) {
107
xports = (SVCXPRT **)
108
mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
109
memset(xports, 0, FD_SETSIZE * sizeof(SVCXPRT *));
110
}
111
if (sock < FD_SETSIZE) {
112
xports[sock] = xprt;
113
FD_SET(sock, &svc_fdset);
114
if (sock > svc_maxfd)
115
svc_maxfd = sock;
116
}
117
#else
118
if (sock < NOFILE) {
119
xports[sock] = xprt;
120
svc_fds |= (1 << sock);
121
if (sock > svc_maxfd)
122
svc_maxfd = sock;
123
}
124
#endif /* def FD_SETSIZE */
125
}
126
127
/*
128
* De-activate a transport handle.
129
*/
130
void
131
xprt_unregister(SVCXPRT *xprt)
132
{
133
int sock = xprt->xp_sock;
134
135
#ifdef FD_SETSIZE
136
if ((sock < FD_SETSIZE) && (xports[sock] == xprt)) {
137
xports[sock] = (SVCXPRT *)0;
138
FD_CLR(sock, &svc_fdset);
139
}
140
#else
141
if ((sock < NOFILE) && (xports[sock] == xprt)) {
142
xports[sock] = (SVCXPRT *)0;
143
svc_fds &= ~(1 << sock);
144
}
145
#endif /* def FD_SETSIZE */
146
if (svc_maxfd <= sock) {
147
while ((svc_maxfd > 0) && xports[svc_maxfd] == 0)
148
svc_maxfd--;
149
}
150
}
151
152
153
/* ********************** CALLOUT list related stuff ************* */
154
155
/*
156
* Add a service program to the callout list.
157
* The dispatch routine will be called when a rpc request for this
158
* program number comes in.
159
*/
160
bool_t
161
svc_register(
162
SVCXPRT *xprt,
163
rpcprog_t prog,
164
rpcvers_t vers,
165
void (*dispatch)(struct svc_req *, SVCXPRT *),
166
int protocol)
167
{
168
struct svc_callout *prev;
169
struct svc_callout *s;
170
171
if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
172
if (s->sc_dispatch == dispatch)
173
goto pmap_it; /* he is registering another xptr */
174
return (FALSE);
175
}
176
s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
177
if (s == (struct svc_callout *)0) {
178
return (FALSE);
179
}
180
s->sc_prog = prog;
181
s->sc_vers = vers;
182
s->sc_dispatch = dispatch;
183
s->sc_next = svc_head;
184
svc_head = s;
185
pmap_it:
186
/* now register the information with the local binder service */
187
if (protocol) {
188
return (pmap_set(prog, vers, protocol, xprt->xp_port));
189
}
190
return (TRUE);
191
}
192
193
/*
194
* Remove a service program from the callout list.
195
*/
196
void
197
svc_unregister(
198
rpcprog_t prog,
199
rpcvers_t vers)
200
{
201
struct svc_callout *prev;
202
struct svc_callout *s;
203
204
if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
205
return;
206
if (prev == NULL_SVC) {
207
svc_head = s->sc_next;
208
} else {
209
prev->sc_next = s->sc_next;
210
}
211
s->sc_next = NULL_SVC;
212
mem_free((char *) s, (u_int) sizeof(struct svc_callout));
213
/* now unregister the information with the local binder service */
214
(void)pmap_unset(prog, vers);
215
}
216
217
/*
218
* Search the callout list for a program number, return the callout
219
* struct.
220
*/
221
static struct svc_callout *
222
svc_find(
223
rpcprog_t prog,
224
rpcvers_t vers,
225
struct svc_callout **prev)
226
{
227
struct svc_callout *s, *p;
228
229
p = NULL_SVC;
230
for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
231
if ((s->sc_prog == prog) && (s->sc_vers == vers))
232
goto done;
233
p = s;
234
}
235
done:
236
*prev = p;
237
return (s);
238
}
239
240
/* ******************* REPLY GENERATION ROUTINES ************ */
241
242
/*
243
* Send a reply to an rpc request
244
*/
245
bool_t
246
svc_sendreply(
247
SVCXPRT *xprt,
248
xdrproc_t xdr_results,
249
caddr_t xdr_location)
250
{
251
struct rpc_msg rply;
252
253
rply.rm_direction = REPLY;
254
rply.rm_reply.rp_stat = MSG_ACCEPTED;
255
rply.acpted_rply.ar_verf = xprt->xp_verf;
256
rply.acpted_rply.ar_stat = SUCCESS;
257
rply.acpted_rply.ar_results.where = xdr_location;
258
rply.acpted_rply.ar_results.proc = xdr_results;
259
return (SVC_REPLY(xprt, &rply));
260
}
261
262
/*
263
* No procedure error reply
264
*/
265
void
266
svcerr_noproc(SVCXPRT *xprt)
267
{
268
struct rpc_msg rply;
269
270
rply.rm_direction = REPLY;
271
rply.rm_reply.rp_stat = MSG_ACCEPTED;
272
rply.acpted_rply.ar_verf = xprt->xp_verf;
273
rply.acpted_rply.ar_stat = PROC_UNAVAIL;
274
SVC_REPLY(xprt, &rply);
275
}
276
277
/*
278
* Can't decode args error reply
279
*/
280
void
281
svcerr_decode(SVCXPRT *xprt)
282
{
283
struct rpc_msg rply;
284
285
rply.rm_direction = REPLY;
286
rply.rm_reply.rp_stat = MSG_ACCEPTED;
287
rply.acpted_rply.ar_verf = xprt->xp_verf;
288
rply.acpted_rply.ar_stat = GARBAGE_ARGS;
289
SVC_REPLY(xprt, &rply);
290
}
291
292
/*
293
* Some system error
294
*/
295
void
296
svcerr_systemerr(SVCXPRT *xprt)
297
{
298
struct rpc_msg rply;
299
300
rply.rm_direction = REPLY;
301
rply.rm_reply.rp_stat = MSG_ACCEPTED;
302
rply.acpted_rply.ar_verf = xprt->xp_verf;
303
rply.acpted_rply.ar_stat = SYSTEM_ERR;
304
SVC_REPLY(xprt, &rply);
305
}
306
307
/*
308
* Authentication error reply
309
*/
310
void
311
svcerr_auth(
312
SVCXPRT *xprt,
313
enum auth_stat why)
314
{
315
struct rpc_msg rply;
316
317
rply.rm_direction = REPLY;
318
rply.rm_reply.rp_stat = MSG_DENIED;
319
rply.rjcted_rply.rj_stat = AUTH_ERROR;
320
rply.rjcted_rply.rj_why = why;
321
SVC_REPLY(xprt, &rply);
322
}
323
324
/*
325
* Auth too weak error reply
326
*/
327
void
328
svcerr_weakauth(SVCXPRT *xprt)
329
{
330
331
svcerr_auth(xprt, AUTH_TOOWEAK);
332
}
333
334
/*
335
* Program unavailable error reply
336
*/
337
void
338
svcerr_noprog(SVCXPRT *xprt)
339
{
340
struct rpc_msg rply;
341
342
rply.rm_direction = REPLY;
343
rply.rm_reply.rp_stat = MSG_ACCEPTED;
344
rply.acpted_rply.ar_verf = xprt->xp_verf;
345
rply.acpted_rply.ar_stat = PROG_UNAVAIL;
346
SVC_REPLY(xprt, &rply);
347
}
348
349
/*
350
* Program version mismatch error reply
351
*/
352
void
353
svcerr_progvers(
354
SVCXPRT *xprt,
355
rpcvers_t low_vers,
356
rpcvers_t high_vers)
357
{
358
struct rpc_msg rply;
359
360
rply.rm_direction = REPLY;
361
rply.rm_reply.rp_stat = MSG_ACCEPTED;
362
rply.acpted_rply.ar_verf = xprt->xp_verf;
363
rply.acpted_rply.ar_stat = PROG_MISMATCH;
364
rply.acpted_rply.ar_vers.low = low_vers;
365
rply.acpted_rply.ar_vers.high = high_vers;
366
SVC_REPLY(xprt, &rply);
367
}
368
369
/* ******************* SERVER INPUT STUFF ******************* */
370
371
/*
372
* Get server side input from some transport.
373
*
374
* Statement of authentication parameters management:
375
* This function owns and manages all authentication parameters, specifically
376
* the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
377
* the "cooked" credentials (rqst->rq_clntcred).
378
* However, this function does not know the structure of the cooked
379
* credentials, so it make the following assumptions:
380
* a) the structure is contiguous (no pointers), and
381
* b) the cred structure size does not exceed RQCRED_SIZE bytes.
382
* In all events, all three parameters are freed upon exit from this routine.
383
* The storage is trivially management on the call stack in user land, but
384
* is mallocated in kernel land.
385
*/
386
387
void
388
svc_getreq(int rdfds)
389
{
390
#ifdef FD_SETSIZE
391
fd_set readfds;
392
int i, mask;
393
394
FD_ZERO(&readfds);
395
for (i=0, mask=1; rdfds; i++, mask <<=1) {
396
if (rdfds & mask)
397
FD_SET(i, &readfds);
398
rdfds &= ~mask;
399
}
400
svc_getreqset(&readfds);
401
#else
402
int readfds = rdfds & svc_fds;
403
404
svc_getreqset(&readfds);
405
#endif /* def FD_SETSIZE */
406
}
407
408
#ifdef FD_SETSIZE
409
#define FDSET_TYPE fd_set
410
#else
411
#define FDSET_TYPE int
412
#endif
413
414
void
415
svc_getreqset(FDSET_TYPE *readfds)
416
{
417
#ifndef FD_SETSIZE
418
int readfds_local = *readfds;
419
#endif
420
SVCXPRT *xprt;
421
int sock;
422
423
#ifdef FD_SETSIZE
424
for (sock = 0; sock <= svc_maxfd; sock++) {
425
if (!FD_ISSET(sock, readfds))
426
continue;
427
/* sock has input waiting */
428
xprt = xports[sock];
429
/* now receive msgs from xprtprt (support batch calls) */
430
svc_do_xprt(xprt);
431
}
432
#else
433
for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
434
if ((readfds_local & 1) == 0)
435
continue;
436
/* sock has input waiting */
437
xprt = xports[sock];
438
/* now receive msgs from xprtprt (support batch calls) */
439
svc_do_xprt(xprt);
440
}
441
#endif
442
}
443
444
extern struct svc_auth_ops svc_auth_gss_ops;
445
446
static void
447
svc_do_xprt(SVCXPRT *xprt)
448
{
449
caddr_t rawcred, rawverf, cookedcred;
450
struct rpc_msg msg;
451
struct svc_req r;
452
bool_t no_dispatch;
453
int prog_found;
454
rpcvers_t low_vers;
455
rpcvers_t high_vers;
456
enum xprt_stat stat;
457
458
rawcred = mem_alloc(MAX_AUTH_BYTES);
459
rawverf = mem_alloc(MAX_AUTH_BYTES);
460
cookedcred = mem_alloc(RQCRED_SIZE);
461
462
if (rawcred == NULL || rawverf == NULL || cookedcred == NULL)
463
return;
464
465
msg.rm_call.cb_cred.oa_base = rawcred;
466
msg.rm_call.cb_verf.oa_base = rawverf;
467
r.rq_clntcred = cookedcred;
468
469
do {
470
struct svc_callout *s;
471
enum auth_stat why;
472
473
if (!SVC_RECV(xprt, &msg))
474
goto call_done;
475
476
/* now find the exported program and call it */
477
478
r.rq_xprt = xprt;
479
r.rq_prog = msg.rm_call.cb_prog;
480
r.rq_vers = msg.rm_call.cb_vers;
481
r.rq_proc = msg.rm_call.cb_proc;
482
r.rq_cred = msg.rm_call.cb_cred;
483
484
no_dispatch = FALSE;
485
486
/* first authenticate the message */
487
why = gssrpc__authenticate(&r, &msg, &no_dispatch);
488
if (why != AUTH_OK) {
489
svcerr_auth(xprt, why);
490
goto call_done;
491
} else if (no_dispatch) {
492
goto call_done;
493
}
494
495
/* now match message with a registered service*/
496
prog_found = FALSE;
497
low_vers = (rpcvers_t) -1L;
498
high_vers = 0;
499
for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
500
if (s->sc_prog == r.rq_prog) {
501
if (s->sc_vers == r.rq_vers) {
502
(*s->sc_dispatch)(&r, xprt);
503
goto call_done;
504
} /* found correct version */
505
prog_found = TRUE;
506
if (s->sc_vers < low_vers)
507
low_vers = s->sc_vers;
508
if (s->sc_vers > high_vers)
509
high_vers = s->sc_vers;
510
} /* found correct program */
511
}
512
/*
513
* if we got here, the program or version
514
* is not served ...
515
*/
516
if (prog_found)
517
svcerr_progvers(xprt,
518
low_vers, high_vers);
519
else
520
svcerr_noprog(xprt);
521
/* Fall through to ... */
522
523
call_done:
524
if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
525
SVC_DESTROY(xprt);
526
break;
527
} else if ((xprt->xp_auth != NULL) &&
528
(xprt->xp_auth->svc_ah_ops != &svc_auth_gss_ops)) {
529
xprt->xp_auth = NULL;
530
}
531
} while (stat == XPRT_MOREREQS);
532
533
mem_free(rawcred, MAX_AUTH_BYTES);
534
mem_free(rawverf, MAX_AUTH_BYTES);
535
mem_free(cookedcred, RQCRED_SIZE);
536
}
537
538