Move /var/svc/log to /var/log/svc
[unleashed/lotheac.git] / usr / src / cmd / gss / gssd / gssd_proc.c
blobc6a51aa34a9785fb2c6d8ce7da7550bfed7fec03
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2017 Joyent Inc
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
27 * RPC server procedures for the gssapi usermode daemon gssd.
30 #include <stdio.h>
31 #include <stdio_ext.h>
32 #include <unistd.h>
33 #include <pwd.h>
34 #include <grp.h>
35 #include <strings.h>
36 #include <limits.h>
37 #include <sys/param.h>
38 #include <mechglueP.h>
39 #include "gssd.h"
40 #include <gssapi/gssapi.h>
41 #include <rpc/rpc.h>
42 #include <stdlib.h>
43 #include <syslog.h>
44 #include <sys/resource.h>
45 #include <sys/debug.h>
47 #define SRVTAB ""
48 #define FDCACHE_PERCENTAGE .75 /* Percentage of total FD limit */
49 #define FDCACHE_DEFAULT 16 /* Default LRU cache size */
50 #define GSSD_FD_LIMIT 255 /* Increase number of fds allowed */
52 extern int gssd_debug; /* declared in gssd.c */
53 static OM_uint32 gssd_time_verf; /* verifies same gssd */
54 static OM_uint32 context_verf; /* context sequence numbers */
56 struct gssd_ctx_slot {
57 struct gssd_ctx_slot *lru_next;
58 struct gssd_ctx_slot *lru_prev;
59 bool_t inuse;
60 OM_uint32 create_time;
61 OM_uint32 verf;
62 gss_ctx_id_t ctx;
63 gss_ctx_id_t rpcctx;
66 struct gssd_ctx_slot *gssd_ctx_slot_tbl;
67 struct gssd_ctx_slot *gssd_lru_head;
69 static int max_contexts;
71 static int checkfrom(struct svc_req *, uid_t *);
72 extern void set_gssd_uid(uid_t);
73 extern int __rpc_get_local_uid(SVCXPRT *, uid_t *);
76 * Syslog (and output to stderr if debug set) the GSSAPI major
77 * and minor numbers.
79 static void
80 syslog_gss_error(OM_uint32 maj_stat, OM_uint32 min_stat, char *errstr)
82 OM_uint32 gmaj_stat, gmin_stat;
83 gss_buffer_desc msg;
84 OM_uint32 msg_ctx = 0;
87 if (gssd_debug)
88 fprintf(stderr,
89 "gssd: syslog_gss_err: called from %s: maj=%d min=%d\n",
90 errstr ? errstr : "<null>", maj_stat, min_stat);
92 /* Print the major status error from the mech. */
93 /* msg_ctx - skip the check for it as is probably unnecesary */
94 gmaj_stat = gss_display_status(&gmin_stat, maj_stat,
95 GSS_C_GSS_CODE,
96 GSS_C_NULL_OID, &msg_ctx, &msg);
97 if ((gmaj_stat == GSS_S_COMPLETE)||
98 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
99 syslog(LOG_DAEMON|LOG_NOTICE,
100 "GSSAPI error major: %s", (char *)msg.value);
101 if (gssd_debug)
102 (void) fprintf(stderr,
103 "gssd: GSSAPI error major: %s\n",
104 (char *)msg.value);
106 (void) gss_release_buffer(&gmin_stat, &msg);
109 /* Print the minor status error from the mech. */
110 msg_ctx = 0;
111 /* msg_ctx - skip the check for it as is probably unnecesary */
112 gmaj_stat = gss_display_status(&gmin_stat, min_stat,
113 GSS_C_MECH_CODE,
114 GSS_C_NULL_OID,
115 &msg_ctx, &msg);
116 if ((gmaj_stat == GSS_S_COMPLETE)||
117 (gmaj_stat == GSS_S_CONTINUE_NEEDED)) {
118 syslog(LOG_DAEMON|LOG_NOTICE,
119 "GSSAPI error minor: %s",
120 (char *)msg.value);
121 if (gssd_debug)
122 (void) fprintf(stderr,
123 "gssd: GSSAPI error minor: %s\n",
124 (char *)msg.value);
125 (void) gss_release_buffer(&gmin_stat, &msg);
129 void
130 gssd_setup(char *arg)
132 int i;
133 struct rlimit rl;
134 hrtime_t high_res_time;
136 gssd_time_verf = (OM_uint32)time(NULL);
137 max_contexts = FDCACHE_DEFAULT;
140 * Use low order bits of high resolution time to get a reasonably
141 * random number to start the context sequencing. This alternative
142 * to using a time value avoid clock resets via NTP or ntpdate.
144 high_res_time = gethrtime();
145 context_verf = (OM_uint32)high_res_time;
148 * Increase resource limit of FDs in case we get alot accept/init_
149 * sec_context calls before we're able to export them. This can
150 * happen in very heavily load environments where gssd doesn't get
151 * much time to work on its backlog.
153 if ((getrlimit(RLIMIT_NOFILE, &rl)) == 0) {
154 rl.rlim_cur = (rl.rlim_max >= GSSD_FD_LIMIT) ?
155 GSSD_FD_LIMIT : rl.rlim_max;
156 if ((setrlimit(RLIMIT_NOFILE, &rl)) == 0)
157 max_contexts = rl.rlim_cur * FDCACHE_PERCENTAGE;
158 (void) enable_extended_FILE_stdio(-1, -1);
161 gssd_ctx_slot_tbl = (struct gssd_ctx_slot *)
162 malloc(sizeof (struct gssd_ctx_slot) * max_contexts);
164 if (gssd_ctx_slot_tbl == NULL) {
165 (void) fprintf(stderr,
166 gettext("[%s] could not allocate %d byte context table"
167 "\n"), arg,
168 (sizeof (struct gssd_ctx_slot) * max_contexts));
169 exit(1);
172 for (i = 1; i < max_contexts; i++) {
173 gssd_ctx_slot_tbl[i-1].lru_next = &gssd_ctx_slot_tbl[i];
174 gssd_ctx_slot_tbl[i].lru_prev = &gssd_ctx_slot_tbl[i-1];
175 gssd_ctx_slot_tbl[i].inuse = FALSE;
176 gssd_ctx_slot_tbl[i].verf = 0;
177 gssd_ctx_slot_tbl[i].create_time = 0;
178 gssd_ctx_slot_tbl[i].rpcctx = (gss_ctx_id_t)(i + 1);
181 gssd_ctx_slot_tbl[max_contexts - 1].lru_next = &gssd_ctx_slot_tbl[0];
182 gssd_ctx_slot_tbl[0].lru_prev = &gssd_ctx_slot_tbl[max_contexts - 1];
183 gssd_ctx_slot_tbl[0].inuse = FALSE;
184 gssd_ctx_slot_tbl[0].verf = 0;
185 gssd_ctx_slot_tbl[0].create_time = 0;
186 gssd_ctx_slot_tbl[0].rpcctx = (gss_ctx_id_t)1;
188 gssd_lru_head = &gssd_ctx_slot_tbl[0];
191 static OM_uint32 syslog_interval = 60;
193 static struct gssd_ctx_slot *
194 gssd_alloc_slot(gss_ctx_id_t ctx)
196 struct gssd_ctx_slot *lru;
197 OM_uint32 current_time;
198 static OM_uint32 last_syslog = 0;
199 static bool_t first_take = TRUE;
200 static int tooks;
201 OM_uint32 minor_status;
203 lru = gssd_lru_head;
204 gssd_lru_head = lru->lru_next;
206 current_time = (OM_uint32) time(NULL);
208 if (last_syslog == 0)
209 last_syslog = current_time; /* Save 1st alloc time */
211 if (lru->inuse) {
212 if (lru->ctx != GSS_C_NO_CONTEXT)
213 (void) gss_delete_sec_context(&minor_status,
214 &lru->ctx, NULL);
215 tooks++;
217 if (((current_time - last_syslog) > syslog_interval) ||
218 first_take) {
219 syslog(LOG_WARNING, gettext("re-used an existing "
220 "context slot of age %u seconds (%d slots re-"
221 "used during last %u seconds)"),
222 current_time - lru->create_time, tooks,
223 current_time - last_syslog);
225 last_syslog = current_time;
226 tooks = 0;
227 first_take = FALSE;
232 * Assign the next context verifier to the context (avoiding zero).
234 context_verf++;
235 if (context_verf == 0)
236 context_verf = 1;
237 lru->verf = context_verf;
239 lru->create_time = current_time;
240 lru->ctx = ctx;
241 lru->inuse = TRUE;
242 return (lru);
246 * We always add 1 because we don't want slot 0 to be confused
247 * with GSS_C_NO_CONTEXT.
250 static struct gssd_ctx_slot *
251 gssd_handle_to_slot(GSS_CTX_ID_T *h)
253 intptr_t i;
255 if (h->GSS_CTX_ID_T_len == 0) {
256 return (NULL);
258 if (h->GSS_CTX_ID_T_len != sizeof (i))
259 return (NULL);
261 i = (*(intptr_t *)(h->GSS_CTX_ID_T_val)) - 1;
263 if (i < 0 || i >= max_contexts)
264 return (NULL);
266 return (&gssd_ctx_slot_tbl[i]);
269 static void
270 gssd_rel_slot(struct gssd_ctx_slot *lru)
272 struct gssd_ctx_slot *prev, *next;
274 if (lru == NULL)
275 return;
277 lru->inuse = FALSE;
280 * Remove entry from its current location in list
282 prev = lru->lru_prev;
283 next = lru->lru_next;
284 prev->lru_next = next;
285 next->lru_prev = prev;
288 * Since it is no longer in use, it is the least recently
289 * used.
291 prev = gssd_lru_head->lru_prev;
292 next = gssd_lru_head;
294 prev->lru_next = lru;
295 lru->lru_prev = prev;
297 next->lru_prev = lru;
298 lru->lru_next = next;
300 gssd_lru_head = lru;
303 static void
304 gssd_convert_context_handle(GSS_CTX_ID_T *h,
305 gss_ctx_id_t *context_handle,
306 OM_uint32 verf,
307 bool_t *context_verf_ok,
308 struct gssd_ctx_slot **slotp)
310 struct gssd_ctx_slot *slot;
312 *context_verf_ok = FALSE;
313 *context_handle = (gss_ctx_id_t)1;
314 if (slotp != NULL)
315 *slotp = NULL;
317 if (h->GSS_CTX_ID_T_len == 0) {
318 *context_handle = GSS_C_NO_CONTEXT;
319 *context_verf_ok = TRUE;
320 return;
323 slot = gssd_handle_to_slot(h);
325 if (slot == NULL)
326 return;
328 if (verf != slot->verf)
329 return;
331 *context_verf_ok = TRUE;
332 *context_handle = slot->ctx;
333 if (slotp != NULL)
334 *slotp = slot;
337 bool_t
338 gss_acquire_cred_1_svc(argp, res, rqstp)
339 gss_acquire_cred_arg *argp;
340 gss_acquire_cred_res *res;
341 struct svc_req *rqstp;
343 OM_uint32 minor_status;
344 gss_name_t desired_name;
345 gss_OID_desc name_type_desc;
346 gss_OID name_type = &name_type_desc;
347 OM_uint32 time_req;
348 gss_OID_set_desc desired_mechs_desc;
349 gss_OID_set desired_mechs;
350 int cred_usage;
351 gss_cred_id_t output_cred_handle;
352 gss_OID_set actual_mechs;
353 gss_buffer_desc external_name;
354 uid_t uid;
355 int i, j;
357 if (gssd_debug)
358 fprintf(stderr, gettext("gss_acquire_cred\n"));
360 memset(res, 0, sizeof (*res));
363 * if the request isn't from root, null out the result pointer
364 * entries, so the next time through xdr_free won't try to
365 * free unmalloc'd memory and then return NULL
368 if (checkfrom(rqstp, &uid) == 0) {
369 res->output_cred_handle.GSS_CRED_ID_T_val = NULL;
370 res->actual_mechs.GSS_OID_SET_val = NULL;
371 return (FALSE);
374 /* set the uid sent as the RPC argument */
376 uid = argp->uid;
377 set_gssd_uid(uid);
379 /* convert the desired name from external to internal format */
381 external_name.length = argp->desired_name.GSS_BUFFER_T_len;
382 external_name.value = (void *)malloc(external_name.length);
383 if (!external_name.value)
384 return (GSS_S_FAILURE);
385 memcpy(external_name.value, argp->desired_name.GSS_BUFFER_T_val,
386 external_name.length);
388 if (argp->name_type.GSS_OID_len == 0) {
389 name_type = GSS_C_NULL_OID;
390 } else {
391 name_type->length = argp->name_type.GSS_OID_len;
392 name_type->elements = (void *)malloc(name_type->length);
393 if (!name_type->elements) {
394 free(external_name.value);
395 return (GSS_S_FAILURE);
397 memcpy(name_type->elements, argp->name_type.GSS_OID_val,
398 name_type->length);
401 if (gss_import_name(&minor_status, &external_name, name_type,
402 &desired_name) != GSS_S_COMPLETE) {
404 res->status = (OM_uint32) GSS_S_FAILURE;
405 res->minor_status = minor_status;
407 free(external_name.value);
408 if (name_type != GSS_C_NULL_OID)
409 free(name_type->elements);
411 return (TRUE);
415 * copy the XDR structured arguments into their corresponding local GSSAPI
416 * variables.
419 cred_usage = argp->cred_usage;
420 time_req = argp->time_req;
422 if (argp->desired_mechs.GSS_OID_SET_len != 0) {
423 desired_mechs = &desired_mechs_desc;
424 desired_mechs->count =
425 (int)argp->desired_mechs.GSS_OID_SET_len;
426 desired_mechs->elements = (gss_OID)
427 malloc(sizeof (gss_OID_desc) * desired_mechs->count);
428 if (!desired_mechs->elements) {
429 free(external_name.value);
430 free(name_type->elements);
431 return (GSS_S_FAILURE);
433 for (i = 0; i < desired_mechs->count; i++) {
434 desired_mechs->elements[i].length =
435 (OM_uint32)argp->desired_mechs.
436 GSS_OID_SET_val[i].GSS_OID_len;
437 desired_mechs->elements[i].elements =
438 (void *)malloc(desired_mechs->elements[i].
439 length);
440 if (!desired_mechs->elements[i].elements) {
441 free(external_name.value);
442 free(name_type->elements);
443 for (j = 0; j < (i -1); j++) {
444 free
445 (desired_mechs->elements[j].elements);
447 free(desired_mechs->elements);
448 return (GSS_S_FAILURE);
450 memcpy(desired_mechs->elements[i].elements,
451 argp->desired_mechs.GSS_OID_SET_val[i].
452 GSS_OID_val,
453 desired_mechs->elements[i].length);
455 } else
456 desired_mechs = GSS_C_NULL_OID_SET;
458 /* call the gssapi routine */
460 res->status = (OM_uint32)gss_acquire_cred(&res->minor_status,
461 desired_name,
462 time_req,
463 desired_mechs,
464 cred_usage,
465 &output_cred_handle,
466 &actual_mechs,
467 &res->time_rec);
470 * convert the output args from the parameter given in the call to the
471 * variable in the XDR result
474 res->output_cred_handle.GSS_CRED_ID_T_len = sizeof (gss_cred_id_t);
475 res->output_cred_handle.GSS_CRED_ID_T_val =
476 (void *)malloc(sizeof (gss_cred_id_t));
477 if (!res->output_cred_handle.GSS_CRED_ID_T_val) {
478 free(external_name.value);
479 free(name_type->elements);
480 for (i = 0; i < desired_mechs->count; i++) {
481 free(desired_mechs->elements[i].elements);
483 free(desired_mechs->elements);
484 return (GSS_S_FAILURE);
486 memcpy(res->output_cred_handle.GSS_CRED_ID_T_val, &output_cred_handle,
487 sizeof (gss_cred_id_t));
489 if (actual_mechs != GSS_C_NULL_OID_SET) {
490 res->actual_mechs.GSS_OID_SET_len =
491 (uint_t)actual_mechs->count;
492 res->actual_mechs.GSS_OID_SET_val = (GSS_OID *)
493 malloc(sizeof (GSS_OID) * actual_mechs->count);
494 if (!res->actual_mechs.GSS_OID_SET_val) {
495 free(external_name.value);
496 free(name_type->elements);
497 for (i = 0; i < desired_mechs->count; i++) {
498 free(desired_mechs->elements[i].elements);
500 free(desired_mechs->elements);
501 free(res->output_cred_handle.GSS_CRED_ID_T_val);
502 return (GSS_S_FAILURE);
504 for (i = 0; i < actual_mechs->count; i++) {
505 res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len =
506 (uint_t)actual_mechs->elements[i].length;
507 res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val =
508 (char *)malloc(actual_mechs->elements[i].
509 length);
510 if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) {
511 free(external_name.value);
512 free(name_type->elements);
513 free(desired_mechs->elements);
514 for (j = 0; j < desired_mechs->count; j++) {
515 free
516 (desired_mechs->elements[i].elements);
518 free(res->actual_mechs.GSS_OID_SET_val);
519 for (j = 0; j < (i - 1); j++) {
520 free
521 (res->actual_mechs.
522 GSS_OID_SET_val[j].GSS_OID_val);
524 return (GSS_S_FAILURE);
526 memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
527 actual_mechs->elements[i].elements,
528 actual_mechs->elements[i].length);
530 } else
531 res->actual_mechs.GSS_OID_SET_len = 0;
534 * set the time verifier for credential handle. To ensure that the
535 * timestamp is not the same as previous gssd process, verify that
536 * time is not the same as set earlier at start of process. If it
537 * is, sleep one second and reset. (due to one second granularity)
540 if (res->status == GSS_S_COMPLETE) {
541 res->gssd_cred_verifier = (OM_uint32)time(NULL);
542 if (res->gssd_cred_verifier == gssd_time_verf) {
543 sleep(1);
544 gssd_time_verf = (OM_uint32)time(NULL);
546 res->gssd_cred_verifier = gssd_time_verf;
547 } else
548 syslog_gss_error(res->status, res->minor_status,
549 "acquire_cred");
552 * now release the space allocated by the underlying gssapi mechanism
553 * library for actual_mechs as well as by this routine for
554 * external_name, name_type and desired_name
557 free(external_name.value);
558 if (name_type != GSS_C_NULL_OID)
559 free(name_type->elements);
560 gss_release_name(&minor_status, &desired_name);
562 if (actual_mechs != GSS_C_NULL_OID_SET) {
563 for (i = 0; i < actual_mechs->count; i++)
564 free(actual_mechs->elements[i].elements);
565 free(actual_mechs->elements);
566 free(actual_mechs);
569 if (desired_mechs != GSS_C_NULL_OID_SET) {
570 for (i = 0; i < desired_mechs->count; i++)
571 free(desired_mechs->elements[i].elements);
572 free(desired_mechs->elements);
576 /* return to caller */
578 return (TRUE);
581 bool_t
582 gss_add_cred_1_svc(argp, res, rqstp)
583 gss_add_cred_arg *argp;
584 gss_add_cred_res *res;
585 struct svc_req *rqstp;
588 OM_uint32 minor_status;
589 gss_name_t desired_name;
590 gss_OID_desc name_type_desc;
591 gss_OID name_type = &name_type_desc;
592 gss_OID_desc desired_mech_type_desc;
593 gss_OID desired_mech_type = &desired_mech_type_desc;
594 int cred_usage;
595 gss_cred_id_t input_cred_handle;
596 gss_OID_set actual_mechs;
597 gss_buffer_desc external_name;
598 uid_t uid;
599 int i, j;
601 if (gssd_debug)
602 fprintf(stderr, gettext("gss_add_cred\n"));
604 if (argp->gssd_cred_verifier != gssd_time_verf) {
605 res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
606 res->minor_status = 0;
607 res->actual_mechs.GSS_OID_SET_len = 0;
608 res->actual_mechs.GSS_OID_SET_val = NULL;
609 res->initiator_time_rec = 0;
610 res->acceptor_time_rec = 0;
611 fprintf(stderr, gettext("gss_add_cred defective cred\n"));
612 return (TRUE);
614 memset(res, 0, sizeof (*res));
617 * if the request isn't from root, null out the result pointer
618 * entries, so the next time through xdr_free won't try to
619 * free unmalloc'd memory and then return NULL
622 if (checkfrom(rqstp, &uid) == 0) {
623 return (FALSE);
626 /* set the uid sent as the RPC argument */
628 uid = argp->uid;
629 set_gssd_uid(uid);
631 /* convert the desired name from external to internal format */
633 external_name.length = argp->desired_name.GSS_BUFFER_T_len;
634 external_name.value = (void *)argp->desired_name.GSS_BUFFER_T_val;
635 name_type->length = argp->name_type.GSS_OID_len;
636 name_type->elements = (void *)argp->name_type.GSS_OID_val;
638 if (gss_import_name(&minor_status, &external_name, name_type,
639 &desired_name) != GSS_S_COMPLETE) {
641 if (gssd_debug)
642 fprintf(stderr,
643 gettext("gss_add_cred:import name"),
644 gettext(" failed status %d \n"),
645 res->status);
646 res->status = (OM_uint32)GSS_S_FAILURE;
647 res->minor_status = minor_status;
648 return (TRUE);
652 * copy the XDR structured arguments into their corresponding local GSSAPI
653 * variables.
656 cred_usage = argp->cred_usage;
657 if (argp->desired_mech_type.GSS_OID_len == 0)
658 desired_mech_type = GSS_C_NULL_OID;
659 else {
660 desired_mech_type->length =
661 (OM_uint32)argp->desired_mech_type.GSS_OID_len;
662 desired_mech_type->elements =
663 (void *)malloc(desired_mech_type->length);
664 if (!desired_mech_type->elements) {
665 return (GSS_S_FAILURE);
667 memcpy(desired_mech_type->elements,
668 argp->desired_mech_type.GSS_OID_val,
669 desired_mech_type->length);
671 input_cred_handle =
672 (argp->input_cred_handle.GSS_CRED_ID_T_len == 0 ?
673 GSS_C_NO_CREDENTIAL :
674 /*LINTED*/
675 *((gss_cred_id_t *)argp->input_cred_handle.
676 GSS_CRED_ID_T_val));
678 if (input_cred_handle != GSS_C_NO_CREDENTIAL)
679 /* verify the input_cred_handle */
680 if (argp->gssd_cred_verifier != gssd_time_verf) {
681 res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
682 res->minor_status = 0;
683 return (TRUE);
686 /* call the gssapi routine */
688 res->status = (OM_uint32)gss_add_cred(&res->minor_status,
689 input_cred_handle,
690 desired_name,
691 desired_mech_type,
692 cred_usage,
693 argp->initiator_time_req,
694 argp->acceptor_time_req,
695 NULL,
696 &actual_mechs,
697 &res->initiator_time_rec,
698 &res->acceptor_time_rec);
700 if ((res->status != GSS_S_COMPLETE) &&
701 (res->status != GSS_S_DUPLICATE_ELEMENT))
702 syslog_gss_error(res->status, res->minor_status, "add_cred");
705 * convert the output args from the parameter given in the call to the
706 * variable in the XDR result
708 if (actual_mechs != GSS_C_NULL_OID_SET) {
709 res->actual_mechs.GSS_OID_SET_len =
710 (uint_t)actual_mechs->count;
711 res->actual_mechs.GSS_OID_SET_val = (GSS_OID *)
712 malloc(sizeof (GSS_OID) * actual_mechs->count);
713 if (!res->actual_mechs.GSS_OID_SET_val) {
714 free(desired_mech_type->elements);
715 free(desired_mech_type);
716 return (GSS_S_FAILURE);
718 for (i = 0; i < actual_mechs->count; i++) {
719 res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len =
720 (uint_t)actual_mechs->elements[i].length;
721 res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val =
722 (char *)malloc(actual_mechs->elements[i].
723 length);
724 if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) {
725 free(desired_mech_type->elements);
726 free(desired_mech_type);
727 free(res->actual_mechs.GSS_OID_SET_val);
728 for (j = 0; j < (i - 1); j++) {
729 free
730 (res->actual_mechs.
731 GSS_OID_SET_val[j].GSS_OID_val);
733 return (GSS_S_FAILURE);
735 memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
736 actual_mechs->elements[i].elements,
737 actual_mechs->elements[i].length);
739 } else
740 res->actual_mechs.GSS_OID_SET_len = 0;
743 * now release the space allocated for
744 * desired_name and desired_mech_type
747 gss_release_name(&minor_status, &desired_name);
748 free(desired_mech_type->elements);
749 gss_release_oid_set(&minor_status, &actual_mechs);
751 * if (actual_mechs != GSS_C_NULL_OID_SET) {
752 * for (i = 0; i < actual_mechs->count; i++)
753 * free(actual_mechs->elements[i].elements);
754 * free(actual_mechs->elements);
755 * free(actual_mechs);
760 /* return to caller */
762 return (TRUE);
765 bool_t
766 gss_release_cred_1_svc(argp, res, rqstp)
767 gss_release_cred_arg *argp;
768 gss_release_cred_res *res;
769 struct svc_req *rqstp;
772 uid_t uid;
773 gss_cred_id_t cred_handle;
775 memset(res, 0, sizeof (*res));
777 if (gssd_debug)
778 fprintf(stderr, gettext("gss_release_cred\n"));
780 if (checkfrom(rqstp, &uid) == 0)
781 return (FALSE);
783 /* set the uid sent as the RPC argument */
785 uid = argp->uid;
786 set_gssd_uid(uid);
789 * if the cred_handle verifier is not correct,
790 * set status to GSS_S_DEFECTIVE_CREDENTIAL and return
793 if (argp->gssd_cred_verifier != gssd_time_verf) {
794 res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
795 return (TRUE);
799 * if the cred_handle length is 0
800 * set cred_handle argument to GSS_S_NO_CREDENTIAL
803 if (argp->cred_handle.GSS_CRED_ID_T_len == 0)
804 cred_handle = GSS_C_NO_CREDENTIAL;
805 else
806 cred_handle =
807 (gss_cred_id_t)argp->cred_handle.GSS_CRED_ID_T_val;
809 /* call the gssapi routine */
811 res->status = (OM_uint32)gss_release_cred(&res->minor_status,
812 &cred_handle);
814 /* return to caller */
816 return (TRUE);
819 bool_t
820 gss_init_sec_context_1_svc(argp, res, rqstp)
821 gss_init_sec_context_arg *argp;
822 gss_init_sec_context_res *res;
823 struct svc_req *rqstp;
826 OM_uint32 minor_status;
827 gss_ctx_id_t context_handle;
828 bool_t context_verf_ok;
829 gss_cred_id_t claimant_cred_handle;
830 gss_buffer_desc external_name;
831 gss_OID_desc name_type_desc;
832 gss_OID name_type = &name_type_desc;
833 gss_name_t internal_name;
835 gss_OID_desc mech_type_desc;
836 gss_OID mech_type = &mech_type_desc;
837 struct gss_channel_bindings_struct
838 input_chan_bindings;
839 gss_channel_bindings_t input_chan_bindings_ptr;
840 gss_buffer_desc input_token;
841 gss_buffer_desc output_token;
842 gss_buffer_t input_token_ptr;
843 gss_OID actual_mech_type;
844 struct gssd_ctx_slot *slot = NULL;
846 uid_t uid;
848 memset(res, 0, sizeof (*res));
850 if (gssd_debug)
851 fprintf(stderr, gettext("gss_init_sec_context\n"));
854 * if the request isn't from root, null out the result pointer
855 * entries, so the next time through xdr_free won't try to
856 * free unmalloc'd memory and then return NULL
859 if (checkfrom(rqstp, &uid) == 0) {
860 res->context_handle.GSS_CTX_ID_T_val = NULL;
861 res->actual_mech_type.GSS_OID_val = NULL;
862 res->output_token.GSS_BUFFER_T_val = NULL;
863 return (FALSE);
866 /* set the uid sent as the RPC argument */
868 uid = argp->uid;
869 set_gssd_uid(uid);
872 * copy the supplied context handle into the local context handle, so it
873 * can be supplied to the gss_init_sec_context call
876 gssd_convert_context_handle(&argp->context_handle, &context_handle,
877 argp->gssd_context_verifier, &context_verf_ok, &slot);
879 claimant_cred_handle =
880 (argp->claimant_cred_handle.GSS_CRED_ID_T_len == 0 ?
881 GSS_C_NO_CREDENTIAL :
882 /*LINTED*/
883 *((gss_cred_id_t *)argp->claimant_cred_handle.
884 GSS_CRED_ID_T_val));
886 if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
887 /* verify the verifier_cred_handle */
888 if (argp->gssd_cred_verifier != gssd_time_verf) {
889 res->context_handle.GSS_CTX_ID_T_val = NULL;
890 res->output_token.GSS_BUFFER_T_val = NULL;
891 res->actual_mech_type.GSS_OID_val = NULL;
892 res->context_handle.GSS_CTX_ID_T_len = 0;
893 res->output_token.GSS_BUFFER_T_len = 0;
894 res->actual_mech_type.GSS_OID_len = 0;
895 res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
896 res->minor_status = 0;
897 return (TRUE);
901 if (context_handle != GSS_C_NO_CONTEXT) {
902 /* verify the verifier_context_handle */
904 if (!context_verf_ok) {
905 res->context_handle.GSS_CTX_ID_T_val = NULL;
906 res->output_token.GSS_BUFFER_T_val = NULL;
907 res->actual_mech_type.GSS_OID_val = NULL;
908 res->context_handle.GSS_CTX_ID_T_len = 0;
909 res->output_token.GSS_BUFFER_T_len = 0;
910 res->actual_mech_type.GSS_OID_len = 0;
911 res->status = (OM_uint32)GSS_S_NO_CONTEXT;
912 res->minor_status = 0;
913 return (TRUE);
917 /* convert the target name from external to internal format */
919 external_name.length = argp->target_name.GSS_BUFFER_T_len;
920 external_name.value = (void *)argp->target_name.GSS_BUFFER_T_val;
922 if (argp->name_type.GSS_OID_len == 0) {
923 name_type = GSS_C_NULL_OID;
924 } else {
925 name_type->length = argp->name_type.GSS_OID_len;
926 name_type->elements = (void *)malloc(name_type->length);
927 if (!name_type->elements)
928 return (GSS_S_FAILURE);
929 memcpy(name_type->elements, argp->name_type.GSS_OID_val,
930 name_type->length);
933 if (argp->mech_type.GSS_OID_len == 0)
934 mech_type = GSS_C_NULL_OID;
935 else {
936 mech_type->length = (OM_uint32)argp->mech_type.GSS_OID_len;
937 mech_type->elements = (void *)argp->mech_type.GSS_OID_val;
940 if (gss_import_name(&minor_status, &external_name, name_type,
941 &internal_name) != GSS_S_COMPLETE) {
943 if (name_type != GSS_C_NULL_OID)
944 free(name_type->elements);
945 res->status = (OM_uint32)GSS_S_FAILURE;
946 res->minor_status = minor_status;
948 return (TRUE);
951 * copy the XDR structured arguments into their corresponding local GSSAPI
952 * variables.
955 if (argp->input_chan_bindings.present == YES) {
956 input_chan_bindings_ptr = &input_chan_bindings;
957 input_chan_bindings.initiator_addrtype =
958 (OM_uint32)argp->input_chan_bindings.
959 initiator_addrtype;
960 input_chan_bindings.initiator_address.length =
961 (uint_t)argp->input_chan_bindings.initiator_address.
962 GSS_BUFFER_T_len;
963 input_chan_bindings.initiator_address.value =
964 (void *)argp->input_chan_bindings.initiator_address.
965 GSS_BUFFER_T_val;
966 input_chan_bindings.acceptor_addrtype =
967 (OM_uint32)argp->input_chan_bindings.acceptor_addrtype;
968 input_chan_bindings.acceptor_address.length =
969 (uint_t)argp->input_chan_bindings.acceptor_address.
970 GSS_BUFFER_T_len;
971 input_chan_bindings.acceptor_address.value =
972 (void *)argp->input_chan_bindings.acceptor_address.
973 GSS_BUFFER_T_val;
974 input_chan_bindings.application_data.length =
975 (uint_t)argp->input_chan_bindings.application_data.
976 GSS_BUFFER_T_len;
977 input_chan_bindings.application_data.value =
978 (void *)argp->input_chan_bindings.application_data.
979 GSS_BUFFER_T_val;
980 } else {
981 input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS;
982 input_chan_bindings.initiator_addrtype = 0;
983 input_chan_bindings.initiator_address.length = 0;
984 input_chan_bindings.initiator_address.value = 0;
985 input_chan_bindings.acceptor_addrtype = 0;
986 input_chan_bindings.acceptor_address.length = 0;
987 input_chan_bindings.acceptor_address.value = 0;
988 input_chan_bindings.application_data.length = 0;
989 input_chan_bindings.application_data.value = 0;
992 if (argp->input_token.GSS_BUFFER_T_len == 0) {
993 input_token_ptr = GSS_C_NO_BUFFER;
994 } else {
995 input_token_ptr = &input_token;
996 input_token.length = (size_t)
997 argp->input_token.GSS_BUFFER_T_len;
998 input_token.value = (void *)argp->input_token.GSS_BUFFER_T_val;
1001 /* call the gssapi routine */
1003 res->status = (OM_uint32)gss_init_sec_context(&res->minor_status,
1004 (gss_cred_id_t)argp->claimant_cred_handle.
1005 GSS_CRED_ID_T_val,
1006 &context_handle,
1007 internal_name,
1008 mech_type,
1009 argp->req_flags,
1010 argp->time_req,
1011 input_chan_bindings_ptr,
1012 input_token_ptr,
1013 &actual_mech_type,
1014 &output_token,
1015 &res->ret_flags,
1016 &res->time_rec);
1019 * convert the output args from the parameter given in the call to the
1020 * variable in the XDR result
1023 if (res->status == (OM_uint32)GSS_S_COMPLETE ||
1024 res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1026 if (slot == NULL || slot->ctx != context_handle) {
1028 * Note that gssd_alloc_slot() will delete ctx's as long
1029 * as we don't call gssd_rel_slot().
1031 slot = gssd_alloc_slot(context_handle);
1034 res->gssd_context_verifier = slot->verf;
1036 res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1037 res->context_handle.GSS_CTX_ID_T_val =
1038 (void *)malloc(sizeof (gss_ctx_id_t));
1039 if (!res->context_handle.GSS_CTX_ID_T_val) {
1040 free(name_type->elements);
1041 return (GSS_S_FAILURE);
1044 memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1045 sizeof (gss_ctx_id_t));
1047 res->output_token.GSS_BUFFER_T_len =
1048 (uint_t)output_token.length;
1049 res->output_token.GSS_BUFFER_T_val =
1050 (char *)output_token.value;
1053 * the actual mech type parameter
1054 * is ready only upon GSS_S_COMPLETE
1056 if (res->status == GSS_S_COMPLETE) {
1057 res->actual_mech_type.GSS_OID_len =
1058 (uint_t)actual_mech_type->length;
1059 res->actual_mech_type.GSS_OID_val =
1060 (void *)malloc(actual_mech_type->length);
1061 if (!res->actual_mech_type.GSS_OID_val) {
1062 free(name_type->elements);
1063 free(res->context_handle.GSS_CTX_ID_T_val);
1064 return (GSS_S_FAILURE);
1066 memcpy(res->actual_mech_type.GSS_OID_val,
1067 (char *)actual_mech_type->elements,
1068 actual_mech_type->length);
1069 } else
1070 res->actual_mech_type.GSS_OID_len = 0;
1071 } else {
1072 syslog_gss_error(res->status, res->minor_status,
1073 "init_sec_context");
1074 if (context_handle != GSS_C_NO_CONTEXT) {
1075 (void) gss_delete_sec_context(&minor_status,
1076 &context_handle, NULL);
1078 res->context_handle.GSS_CTX_ID_T_len = 0;
1079 res->actual_mech_type.GSS_OID_len = 0;
1080 res->output_token.GSS_BUFFER_T_len = 0;
1084 * now release the space allocated by the underlying gssapi mechanism
1085 * library for internal_name and for the name_type.
1088 gss_release_name(&minor_status, &internal_name);
1089 if (name_type != GSS_C_NULL_OID)
1090 free(name_type->elements);
1093 /* return to caller */
1094 return (TRUE);
1097 bool_t
1098 gss_accept_sec_context_1_svc(argp, res, rqstp)
1099 gss_accept_sec_context_arg *argp;
1100 gss_accept_sec_context_res *res;
1101 struct svc_req *rqstp;
1103 uid_t uid;
1104 OM_uint32 minor_status;
1105 gss_ctx_id_t context_handle = NULL;
1106 gss_cred_id_t verifier_cred_handle;
1107 gss_buffer_desc external_name;
1108 gss_name_t internal_name = NULL;
1110 gss_buffer_desc input_token_buffer;
1111 gss_buffer_t input_token_buffer_ptr;
1112 struct gss_channel_bindings_struct
1113 input_chan_bindings;
1114 gss_channel_bindings_t input_chan_bindings_ptr;
1115 gss_OID mech_type;
1116 gss_buffer_desc output_token;
1117 gss_cred_id_t delegated_cred_handle;
1118 bool_t context_verf_ok;
1119 struct gssd_ctx_slot *slot = NULL;
1121 memset(res, 0, sizeof (*res));
1123 if (gssd_debug)
1124 fprintf(stderr, gettext("gss_accept_sec_context\n"));
1127 * if the request isn't from root, null out the result pointer
1128 * entries, so the next time through xdr_free won't try to
1129 * free unmalloc'd memory and then return NULL
1132 if (checkfrom(rqstp, &uid) == 0) {
1133 res->context_handle.GSS_CTX_ID_T_val = NULL;
1134 res->src_name.GSS_BUFFER_T_val = NULL;
1135 res->mech_type.GSS_OID_val = NULL;
1136 res->output_token.GSS_BUFFER_T_val = NULL;
1137 res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
1138 return (FALSE);
1141 /* set the uid sent as the RPC argument */
1143 uid = argp->uid;
1144 set_gssd_uid(uid);
1147 * copy the supplied context handle into the local context handle, so
1148 * it can be supplied to the gss_accept_sec_context call
1151 gssd_convert_context_handle(&argp->context_handle, &context_handle,
1152 argp->gssd_context_verifier, &context_verf_ok, &slot);
1154 if (context_handle != GSS_C_NO_CONTEXT)
1155 /* verify the context_handle */
1156 if (!context_verf_ok) {
1157 res->context_handle.GSS_CTX_ID_T_val = NULL;
1158 res->src_name.GSS_BUFFER_T_val = NULL;
1159 res->mech_type.GSS_OID_val = NULL;
1160 res->output_token.GSS_BUFFER_T_val = NULL;
1161 res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
1162 res->src_name.GSS_BUFFER_T_len = 0;
1163 res->context_handle.GSS_CTX_ID_T_len = 0;
1164 res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1165 res->output_token.GSS_BUFFER_T_len = 0;
1166 res->mech_type.GSS_OID_len = 0;
1167 res->status = (OM_uint32)GSS_S_NO_CONTEXT;
1168 res->minor_status = 0;
1169 return (TRUE);
1173 * copy the XDR structured arguments into their corresponding local
1174 * GSSAPI variable equivalents.
1178 verifier_cred_handle =
1179 (argp->verifier_cred_handle.GSS_CRED_ID_T_len == 0 ?
1180 GSS_C_NO_CREDENTIAL :
1181 /*LINTED*/
1182 *((gss_cred_id_t *)argp->verifier_cred_handle.
1183 GSS_CRED_ID_T_val));
1185 if (verifier_cred_handle != GSS_C_NO_CREDENTIAL)
1186 /* verify the verifier_cred_handle */
1187 if (argp->gssd_cred_verifier != gssd_time_verf) {
1188 res->context_handle.GSS_CTX_ID_T_val = NULL;
1189 res->src_name.GSS_BUFFER_T_val = NULL;
1190 res->mech_type.GSS_OID_val = NULL;
1191 res->output_token.GSS_BUFFER_T_val = NULL;
1192 res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
1193 res->src_name.GSS_BUFFER_T_len = 0;
1194 res->context_handle.GSS_CTX_ID_T_len = 0;
1195 res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1196 res->output_token.GSS_BUFFER_T_len = 0;
1197 res->mech_type.GSS_OID_len = 0;
1198 res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
1199 res->minor_status = 0;
1200 return (TRUE);
1203 input_token_buffer_ptr = &input_token_buffer;
1204 input_token_buffer.length = (size_t)argp->input_token_buffer.
1205 GSS_BUFFER_T_len;
1206 input_token_buffer.value = (void *)argp->input_token_buffer.
1207 GSS_BUFFER_T_val;
1209 if (argp->input_chan_bindings.present == YES) {
1210 input_chan_bindings_ptr = &input_chan_bindings;
1211 input_chan_bindings.initiator_addrtype =
1212 (OM_uint32)argp->input_chan_bindings.
1213 initiator_addrtype;
1214 input_chan_bindings.initiator_address.length =
1215 (uint_t)argp->input_chan_bindings.initiator_address.
1216 GSS_BUFFER_T_len;
1217 input_chan_bindings.initiator_address.value =
1218 (void *)argp->input_chan_bindings.initiator_address.
1219 GSS_BUFFER_T_val;
1220 input_chan_bindings.acceptor_addrtype =
1221 (OM_uint32)argp->input_chan_bindings.
1222 acceptor_addrtype;
1223 input_chan_bindings.acceptor_address.length =
1224 (uint_t)argp->input_chan_bindings.acceptor_address.
1225 GSS_BUFFER_T_len;
1226 input_chan_bindings.acceptor_address.value =
1227 (void *)argp->input_chan_bindings.acceptor_address.
1228 GSS_BUFFER_T_val;
1229 input_chan_bindings.application_data.length =
1230 (uint_t)argp->input_chan_bindings.application_data.
1231 GSS_BUFFER_T_len;
1232 input_chan_bindings.application_data.value =
1233 (void *)argp->input_chan_bindings.application_data.
1234 GSS_BUFFER_T_val;
1235 } else {
1236 input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS;
1237 input_chan_bindings.initiator_addrtype = 0;
1238 input_chan_bindings.initiator_address.length = 0;
1239 input_chan_bindings.initiator_address.value = 0;
1240 input_chan_bindings.acceptor_addrtype = 0;
1241 input_chan_bindings.acceptor_address.length = 0;
1242 input_chan_bindings.acceptor_address.value = 0;
1243 input_chan_bindings.application_data.length = 0;
1244 input_chan_bindings.application_data.value = 0;
1248 /* call the gssapi routine */
1250 res->status = (OM_uint32)gss_accept_sec_context(&res->minor_status,
1251 &context_handle,
1252 verifier_cred_handle,
1253 input_token_buffer_ptr,
1254 input_chan_bindings_ptr,
1255 &internal_name,
1256 &mech_type,
1257 &output_token,
1258 &res->ret_flags,
1259 &res->time_rec,
1260 &delegated_cred_handle);
1262 /* convert the src name from internal to external format */
1264 if (res->status == (OM_uint32)GSS_S_COMPLETE ||
1265 res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
1268 * upon GSS_S_CONTINUE_NEEDED only the following
1269 * parameters are ready: minor, ctxt, and output token
1271 res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1272 res->context_handle.GSS_CTX_ID_T_val =
1273 (void *)malloc(sizeof (gss_ctx_id_t));
1274 if (!res->context_handle.GSS_CTX_ID_T_val) {
1275 res->status = (OM_uint32)GSS_S_FAILURE;
1276 res->minor_status = 0;
1277 return (TRUE);
1280 if (slot == NULL || slot->ctx != context_handle) {
1282 * Note that gssd_alloc_slot() will delete ctx's as long
1283 * as we don't call gssd_rel_slot().
1285 slot = gssd_alloc_slot(context_handle);
1288 memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1289 sizeof (gss_ctx_id_t));
1290 res->gssd_context_verifier = slot->verf;
1292 res->output_token.GSS_BUFFER_T_len =
1293 (uint_t)output_token.length;
1294 res->output_token.GSS_BUFFER_T_val =
1295 (char *)output_token.value;
1297 if (res->status == GSS_S_COMPLETE) {
1298 if (gss_export_name(&minor_status, internal_name,
1299 &external_name)
1300 != GSS_S_COMPLETE) {
1302 res->status = (OM_uint32)GSS_S_FAILURE;
1303 res->minor_status = minor_status;
1304 gss_release_name(&minor_status, &internal_name);
1305 gss_delete_sec_context(&minor_status,
1306 &context_handle, NULL);
1307 free(res->context_handle.GSS_CTX_ID_T_val);
1308 res->context_handle.GSS_CTX_ID_T_val = NULL;
1309 res->context_handle.GSS_CTX_ID_T_len = 0;
1310 gss_release_buffer(&minor_status,
1311 &output_token);
1312 res->output_token.GSS_BUFFER_T_len = 0;
1313 res->output_token.GSS_BUFFER_T_val = NULL;
1314 return (TRUE);
1316 res->src_name.GSS_BUFFER_T_len =
1317 (uint_t)external_name.length;
1318 res->src_name.GSS_BUFFER_T_val =
1319 (void *)external_name.value;
1321 res->delegated_cred_handle.GSS_CRED_ID_T_len =
1322 sizeof (gss_cred_id_t);
1323 res->delegated_cred_handle.GSS_CRED_ID_T_val =
1324 (void *)malloc(sizeof (gss_cred_id_t));
1325 if (!res->delegated_cred_handle.GSS_CRED_ID_T_val) {
1326 free(res->context_handle.GSS_CTX_ID_T_val);
1327 gss_release_name(&minor_status, &internal_name);
1328 gss_delete_sec_context(&minor_status,
1329 &context_handle, NULL);
1330 gss_release_buffer(&minor_status,
1331 &external_name);
1332 res->status = (OM_uint32)GSS_S_FAILURE;
1333 res->minor_status = 0;
1334 return (TRUE);
1336 memcpy(res->delegated_cred_handle.GSS_CRED_ID_T_val,
1337 &delegated_cred_handle,
1338 sizeof (gss_cred_id_t));
1340 res->mech_type.GSS_OID_len = (uint_t)mech_type->length;
1341 res->mech_type.GSS_OID_val =
1342 (void *)malloc(mech_type->length);
1343 if (!res->mech_type.GSS_OID_val) {
1344 free(res->context_handle.GSS_CTX_ID_T_val);
1345 free(res->delegated_cred_handle.GSS_CRED_ID_T_val);
1346 gss_release_name(&minor_status, &internal_name);
1347 gss_delete_sec_context(&minor_status,
1348 &context_handle, NULL);
1349 gss_release_buffer(&minor_status, &external_name);
1350 res->status = (OM_uint32)GSS_S_FAILURE;
1351 res->minor_status = 0;
1352 return (TRUE);
1354 memcpy(res->mech_type.GSS_OID_val, mech_type->elements,
1355 mech_type->length);
1357 /* release the space allocated for internal_name */
1358 gss_release_name(&minor_status, &internal_name);
1360 } else { /* GSS_S_CONTINUE_NEEDED */
1361 res->src_name.GSS_BUFFER_T_len = 0;
1362 res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1363 res->mech_type.GSS_OID_len = 0;
1365 } else {
1366 syslog_gss_error(res->status, res->minor_status,
1367 "accept_sec_context");
1369 if (context_handle != GSS_C_NO_CONTEXT) {
1370 (void) gss_delete_sec_context(&minor_status,
1371 &context_handle, NULL);
1373 res->src_name.GSS_BUFFER_T_len = 0;
1374 res->context_handle.GSS_CTX_ID_T_len = 0;
1375 res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
1376 res->output_token.GSS_BUFFER_T_len =
1377 (uint_t)output_token.length;
1378 res->output_token.GSS_BUFFER_T_val =
1379 (char *)output_token.value;
1381 res->mech_type.GSS_OID_len = 0;
1384 /* return to caller */
1386 return (TRUE);
1389 bool_t
1390 gss_process_context_token_1_svc(argp, res, rqstp)
1391 gss_process_context_token_arg *argp;
1392 gss_process_context_token_res *res;
1393 struct svc_req *rqstp;
1396 uid_t uid;
1397 gss_buffer_desc token_buffer;
1398 gss_ctx_id_t context_handle;
1399 bool_t context_verf_ok;
1401 memset(res, 0, sizeof (*res));
1403 if (gssd_debug)
1404 fprintf(stderr, gettext("gss_process_context_token\n"));
1406 if (checkfrom(rqstp, &uid) == 0)
1407 return (FALSE);
1409 gssd_convert_context_handle(&argp->context_handle, &context_handle,
1410 argp->gssd_context_verifier, &context_verf_ok, NULL);
1412 /* verify the context_handle */
1414 if (!context_verf_ok) {
1415 res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1416 res->minor_status = 0;
1417 return (TRUE);
1420 /* set the uid sent as the RPC argument */
1422 uid = argp->uid;
1423 set_gssd_uid(uid);
1426 * copy the XDR structured arguments into their corresponding local
1427 * GSSAPI variable equivalents.
1430 token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len;
1431 token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val;
1434 /* call the gssapi routine */
1436 res->status = (OM_uint32)gss_process_context_token(&res->minor_status,
1437 context_handle,
1438 &token_buffer);
1440 if (GSS_ERROR(res->status))
1441 syslog_gss_error(res->status, res->minor_status,
1442 "process_context_token");
1444 /* return to caller */
1446 return (TRUE);
1449 bool_t
1450 gss_delete_sec_context_1_svc(argp, res, rqstp)
1451 gss_delete_sec_context_arg *argp;
1452 gss_delete_sec_context_res *res;
1453 struct svc_req *rqstp;
1455 uid_t uid;
1456 gss_ctx_id_t context_handle;
1457 gss_buffer_desc output_token;
1458 bool_t context_verf_ok;
1459 struct gssd_ctx_slot *slot = NULL;
1461 memset(res, 0, sizeof (*res));
1463 if (gssd_debug)
1464 fprintf(stderr, gettext("gss_delete_sec_context\n"));
1468 * copy the supplied context handle into the local context handle, so it
1469 * can be supplied to the gss_delete_sec_context call
1471 gssd_convert_context_handle(&argp->context_handle, &context_handle,
1472 argp->gssd_context_verifier, &context_verf_ok, &slot);
1474 /* verify the context_handle */
1475 if (!context_verf_ok) {
1476 res->context_handle.GSS_CTX_ID_T_val = NULL;
1477 res->context_handle.GSS_CTX_ID_T_len = 0;
1478 res->output_token.GSS_BUFFER_T_val = NULL;
1479 res->output_token.GSS_BUFFER_T_len = 0;
1480 res->status = (OM_uint32)GSS_S_NO_CONTEXT;
1481 res->minor_status = 0;
1482 return (TRUE);
1486 * if the request isn't from root, null out the result pointer
1487 * entries, so the next time through xdr_free won't try to
1488 * free unmalloc'd memory and then return NULL
1491 if (checkfrom(rqstp, &uid) == 0) {
1492 res->context_handle.GSS_CTX_ID_T_val = NULL;
1493 res->output_token.GSS_BUFFER_T_val = NULL;
1494 return (FALSE);
1497 /* call the gssapi routine */
1499 res->status = (OM_uint32)gss_delete_sec_context(&res->minor_status,
1500 &context_handle,
1501 &output_token);
1504 * convert the output args from the parameter given in the call to the
1505 * variable in the XDR result. If the delete succeeded, return a zero
1506 * context handle.
1509 if (res->status == GSS_S_COMPLETE) {
1510 if (context_handle != GSS_C_NO_CONTEXT)
1511 return (GSS_S_FAILURE);
1512 res->context_handle.GSS_CTX_ID_T_len = 0;
1513 res->context_handle.GSS_CTX_ID_T_val = NULL;
1514 res->output_token.GSS_BUFFER_T_len =
1515 (uint_t)output_token.length;
1516 res->output_token.GSS_BUFFER_T_val =
1517 (char *)output_token.value;
1519 if (slot != NULL) {
1521 * gss_delete_sec_context deletes the context if it
1522 * succeeds so clear slot->ctx to avoid a dangling
1523 * reference.
1525 slot->ctx = GSS_C_NO_CONTEXT;
1526 gssd_rel_slot(slot);
1528 } else {
1529 res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1530 res->context_handle.GSS_CTX_ID_T_val =
1531 (void *)malloc(sizeof (gss_ctx_id_t));
1532 if (!res->context_handle.GSS_CTX_ID_T_val) {
1533 return (GSS_S_FAILURE);
1536 if (slot == NULL || slot->ctx != context_handle) {
1538 * Note that gssd_alloc_slot() will delete ctx's as long
1539 * as we don't call gssd_rel_slot().
1541 slot = gssd_alloc_slot(context_handle);
1543 * Note that no verifier is returned in the .x
1544 * protocol. So if the context changes, we won't
1545 * be able to release it now. So it will have to
1546 * be LRUed out.
1550 memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1551 sizeof (gss_ctx_id_t));
1553 res->output_token.GSS_BUFFER_T_len = 0;
1554 res->output_token.GSS_BUFFER_T_val = NULL;
1557 /* return to caller */
1560 return (TRUE);
1564 bool_t
1565 gss_export_sec_context_1_svc(argp, res, rqstp)
1566 gss_export_sec_context_arg *argp;
1567 gss_export_sec_context_res *res;
1568 struct svc_req *rqstp;
1571 uid_t uid;
1572 gss_ctx_id_t context_handle;
1573 gss_buffer_desc output_token;
1574 bool_t context_verf_ok;
1575 struct gssd_ctx_slot *slot = NULL;
1577 memset(res, 0, sizeof (*res));
1579 if (gssd_debug)
1580 fprintf(stderr, "gss_export_sec_context\n");
1583 * if the request isn't from root, null out the result pointer
1584 * entries, so the next time through xdr_free won't try to
1585 * free unmalloc'd memory and then return NULL
1588 if (checkfrom(rqstp, &uid) == 0) {
1589 res->context_handle.GSS_CTX_ID_T_val = NULL;
1590 res->output_token.GSS_BUFFER_T_val = NULL;
1591 return (FALSE);
1595 * copy the supplied context handle into the local context handle, so it
1596 * can be supplied to the gss_export_sec_context call
1599 gssd_convert_context_handle(&argp->context_handle, &context_handle,
1600 argp->gssd_context_verifier, &context_verf_ok, &slot);
1602 /* verify the context_handle */
1604 if (!context_verf_ok) {
1605 res->status = (OM_uint32)GSS_S_NO_CONTEXT;
1606 /* the rest of "res" was cleared by a previous memset() */
1607 return (TRUE);
1610 /* call the gssapi routine */
1612 res->status = (OM_uint32)gss_export_sec_context(&res->minor_status,
1613 &context_handle,
1614 &output_token);
1617 * convert the output args from the parameter given in the call to the
1618 * variable in the XDR result. If the delete succeeded, return a zero context
1619 * handle.
1621 if (res->status == GSS_S_COMPLETE) {
1622 if (context_handle != GSS_C_NO_CONTEXT)
1623 return (GSS_S_FAILURE);
1624 res->context_handle.GSS_CTX_ID_T_len = 0;
1625 res->context_handle.GSS_CTX_ID_T_val = NULL;
1626 res->output_token.GSS_BUFFER_T_len =
1627 (uint_t)output_token.length;
1628 res->output_token.GSS_BUFFER_T_val =
1629 (char *)output_token.value;
1631 if (slot != NULL) {
1633 * gss_export_sec_context deletes the context if it
1634 * succeeds so set slot->ctx to avoid a dangling
1635 * reference.
1637 slot->ctx = GSS_C_NO_CONTEXT;
1638 gssd_rel_slot(slot);
1640 } else {
1641 res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1642 res->context_handle.GSS_CTX_ID_T_val =
1643 (void *)malloc(sizeof (gss_ctx_id_t));
1645 if (slot == NULL || slot->ctx != context_handle) {
1647 * Note that gssd_alloc_slot() will delete ctx's as long
1648 * as we don't call gssd_rel_slot().
1650 slot = gssd_alloc_slot(context_handle);
1652 * Note that no verifier is returned in the .x
1653 * protocol. So if the context changes, we won't
1654 * be able to release it now. So it will have to
1655 * be LRUed out.
1659 memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
1660 sizeof (gss_ctx_id_t));
1661 res->output_token.GSS_BUFFER_T_len = 0;
1662 res->output_token.GSS_BUFFER_T_val = NULL;
1666 /* return to caller */
1668 return (TRUE);
1672 * This routine doesn't appear to ever be called.
1674 bool_t
1675 gss_import_sec_context_1_svc(argp, res, rqstp)
1676 gss_import_sec_context_arg *argp;
1677 gss_import_sec_context_res *res;
1678 struct svc_req *rqstp;
1681 uid_t uid;
1682 gss_ctx_id_t context_handle;
1683 gss_buffer_desc input_token;
1684 gss_buffer_t input_token_ptr;
1686 memset(res, 0, sizeof (*res));
1688 if (gssd_debug)
1689 fprintf(stderr, "gss_export_sec_context\n");
1692 * if the request isn't from root, null out the result pointer
1693 * entries, so the next time through xdr_free won't try to
1694 * free unmalloc'd memory and then return NULL
1697 if (checkfrom(rqstp, &uid) == 0) {
1698 res->context_handle.GSS_CTX_ID_T_val = NULL;
1699 return (FALSE);
1703 if (argp->input_token.GSS_BUFFER_T_len == 0) {
1704 input_token_ptr = GSS_C_NO_BUFFER;
1705 } else {
1706 input_token_ptr = &input_token;
1707 input_token.length = (size_t)
1708 argp->input_token.GSS_BUFFER_T_len;
1709 input_token.value = (void *) argp->input_token.GSS_BUFFER_T_val;
1713 /* call the gssapi routine */
1715 res->status = (OM_uint32) gss_import_sec_context(&res->minor_status,
1716 input_token_ptr,
1717 &context_handle);
1720 * convert the output args from the parameter given in the call to the
1721 * variable in the XDR result. If the delete succeeded, return a zero context
1722 * handle.
1724 if (res->status == GSS_S_COMPLETE) {
1725 res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
1726 res->context_handle.GSS_CTX_ID_T_val =
1727 (void *) malloc(sizeof (gss_ctx_id_t));
1728 memcpy(res->context_handle.GSS_CTX_ID_T_val, &context_handle,
1729 sizeof (gss_ctx_id_t));
1730 } else {
1731 res->context_handle.GSS_CTX_ID_T_len = 0;
1732 res->context_handle.GSS_CTX_ID_T_val = NULL;
1736 /* return to caller */
1738 return (TRUE);
1741 bool_t
1742 gss_context_time_1_svc(argp, res, rqstp)
1743 gss_context_time_arg *argp;
1744 gss_context_time_res *res;
1745 struct svc_req *rqstp;
1747 uid_t uid;
1749 memset(res, 0, sizeof (*res));
1751 if (gssd_debug)
1752 fprintf(stderr, gettext("gss_context_time\n"));
1755 * if the request isn't from root, null out the result pointer
1756 * entries, so the next time through xdr_free won't try to
1757 * free unmalloc'd memory and then return NULL
1760 if (checkfrom(rqstp, &uid) == 0)
1761 return (FALSE);
1763 /* set the uid sent as the RPC argument */
1765 uid = argp->uid;
1766 set_gssd_uid(uid);
1768 /* Semantics go here */
1770 return (TRUE);
1773 bool_t
1774 gss_sign_1_svc(argp, res, rqstp)
1775 gss_sign_arg *argp;
1776 gss_sign_res *res;
1777 struct svc_req *rqstp;
1780 uid_t uid;
1782 gss_buffer_desc message_buffer;
1783 gss_buffer_desc msg_token;
1784 gss_ctx_id_t context_handle;
1785 bool_t context_verf_ok;
1787 memset(res, 0, sizeof (*res));
1789 if (gssd_debug)
1790 fprintf(stderr, gettext("gss_sign\n"));
1792 gssd_convert_context_handle(&argp->context_handle, &context_handle,
1793 argp->gssd_context_verifier, &context_verf_ok, NULL);
1795 /* verify the context_handle */
1796 if (!context_verf_ok) {
1797 res->msg_token.GSS_BUFFER_T_val = NULL;
1798 res->msg_token.GSS_BUFFER_T_len = 0;
1799 res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1800 res->minor_status = 0;
1801 return (TRUE);
1806 * if the request isn't from root, null out the result pointer
1807 * entries, so the next time through xdr_free won't try to
1808 * free unmalloc'd memory and then return NULL
1811 if (checkfrom(rqstp, &uid) == 0) {
1812 res->msg_token.GSS_BUFFER_T_val = NULL;
1813 return (FALSE);
1817 * copy the XDR structured arguments into their corresponding local
1818 * GSSAPI variable equivalents.
1821 message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len;
1822 message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val;
1824 /* call the gssapi routine */
1826 res->status = (OM_uint32)gss_sign(&res->minor_status,
1827 context_handle,
1828 argp->qop_req,
1829 (gss_buffer_t)&message_buffer,
1830 (gss_buffer_t)&msg_token);
1832 * convert the output args from the parameter given in the call to
1833 * the variable in the XDR result
1836 if (res->status == GSS_S_COMPLETE) {
1837 res->msg_token.GSS_BUFFER_T_len = (uint_t)msg_token.length;
1838 res->msg_token.GSS_BUFFER_T_val = (char *)msg_token.value;
1839 } else
1840 syslog_gss_error(res->status, res->minor_status, "sign");
1842 /* return to caller */
1844 return (TRUE);
1847 bool_t
1848 gss_verify_1_svc(argp, res, rqstp)
1849 gss_verify_arg *argp;
1850 gss_verify_res *res;
1851 struct svc_req *rqstp;
1854 uid_t uid;
1856 gss_buffer_desc message_buffer;
1857 gss_buffer_desc token_buffer;
1858 gss_ctx_id_t context_handle;
1859 bool_t context_verf_ok;
1861 memset(res, 0, sizeof (*res));
1863 if (gssd_debug)
1864 fprintf(stderr, gettext("gss_verify\n"));
1866 gssd_convert_context_handle(&argp->context_handle, &context_handle,
1867 argp->gssd_context_verifier, &context_verf_ok, NULL);
1869 /* verify the context_handle */
1870 if (!context_verf_ok) {
1871 res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1872 res->minor_status = 0;
1873 return (TRUE);
1877 * if the request isn't from root, null out the result pointer
1878 * entries, so the next time through xdr_free won't try to
1879 * free unmalloc'd memory and then return NULL
1882 if (checkfrom(rqstp, &uid) == 0)
1883 return (FALSE);
1886 * copy the XDR structured arguments into their corresponding local
1887 * GSSAPI variable equivalents.
1890 message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len;
1891 message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val;
1893 token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len;
1894 token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val;
1896 /* call the gssapi routine */
1898 res->status = (OM_uint32)gss_verify(&res->minor_status,
1899 context_handle,
1900 &message_buffer,
1901 &token_buffer,
1902 &res->qop_state);
1904 if (GSS_ERROR(res->status))
1905 syslog_gss_error(res->status, res->minor_status, "verify");
1907 /* return to caller */
1908 return (TRUE);
1911 bool_t
1912 gss_seal_1_svc(argp, res, rqstp)
1913 gss_seal_arg *argp;
1914 gss_seal_res *res;
1915 struct svc_req *rqstp;
1917 uid_t uid;
1919 gss_buffer_desc input_message_buffer;
1920 gss_buffer_desc output_message_buffer;
1921 gss_ctx_id_t context_handle;
1922 bool_t context_verf_ok;
1924 memset(res, 0, sizeof (*res));
1926 if (gssd_debug)
1927 fprintf(stderr, gettext("gss_seal\n"));
1929 gssd_convert_context_handle(&argp->context_handle, &context_handle,
1930 argp->gssd_context_verifier, &context_verf_ok, NULL);
1932 /* verify the context_handle */
1934 if (!context_verf_ok) {
1935 res->output_message_buffer.GSS_BUFFER_T_val = NULL;
1936 res->output_message_buffer.GSS_BUFFER_T_len = 0;
1937 res->status = (OM_uint32) GSS_S_NO_CONTEXT;
1938 res->minor_status = 0;
1939 return (TRUE);
1943 * if the request isn't from root, null out the result pointer
1944 * entries, so the next time through xdr_free won't try to
1945 * free unmalloc'd memory and then return NULL
1948 if (checkfrom(rqstp, &uid) == 0) {
1949 res->output_message_buffer.GSS_BUFFER_T_val = NULL;
1950 return (FALSE);
1956 * copy the XDR structured arguments into their corresponding local
1957 * GSSAPI variable equivalents.
1960 input_message_buffer.length = (size_t)argp->input_message_buffer.
1961 GSS_BUFFER_T_len;
1962 input_message_buffer.value = (void *)argp->input_message_buffer.
1963 GSS_BUFFER_T_val;
1966 /* call the gssapi routine */
1968 res->status = (OM_uint32)gss_seal(&res->minor_status,
1969 context_handle,
1970 argp->conf_req_flag,
1971 argp->qop_req,
1972 &input_message_buffer,
1973 &res->conf_state,
1974 &output_message_buffer);
1976 * convert the output args from the parameter given in the call to the
1977 * variable in the XDR result
1980 if (res->status == GSS_S_COMPLETE) {
1981 res->output_message_buffer.GSS_BUFFER_T_len =
1982 (uint_t)output_message_buffer.length;
1983 res->output_message_buffer.GSS_BUFFER_T_val =
1984 (char *)output_message_buffer.value;
1985 } else
1986 syslog_gss_error(res->status, res->minor_status, "seal");
1988 /* return to caller */
1990 return (TRUE);
1993 bool_t
1994 gss_unseal_1_svc(argp, res, rqstp)
1995 gss_unseal_arg *argp;
1996 gss_unseal_res *res;
1997 struct svc_req *rqstp;
2000 uid_t uid;
2002 gss_buffer_desc input_message_buffer;
2003 gss_buffer_desc output_message_buffer;
2004 gss_ctx_id_t context_handle;
2005 bool_t context_verf_ok;
2007 memset(res, 0, sizeof (*res));
2009 if (gssd_debug)
2010 fprintf(stderr, gettext("gss_unseal\n"));
2012 /* verify the context_handle */
2013 gssd_convert_context_handle(&argp->context_handle, &context_handle,
2014 argp->gssd_context_verifier, &context_verf_ok, NULL);
2016 /* verify the context_handle */
2017 if (!context_verf_ok) {
2018 res->output_message_buffer.GSS_BUFFER_T_val = NULL;
2019 res->output_message_buffer.GSS_BUFFER_T_len = 0;
2020 res->status = (OM_uint32)GSS_S_NO_CONTEXT;
2021 res->minor_status = 0;
2022 return (TRUE);
2026 * if the request isn't from root, null out the result pointer
2027 * entries, so the next time through xdr_free won't try to
2028 * free unmalloc'd memory and then return NULL
2031 if (checkfrom(rqstp, &uid) == 0) {
2032 res->output_message_buffer.GSS_BUFFER_T_val = NULL;
2033 return (FALSE);
2038 * copy the XDR structured arguments into their corresponding local
2039 * GSSAPI variable equivalents.
2042 input_message_buffer.length = (size_t)argp->input_message_buffer.
2043 GSS_BUFFER_T_len;
2044 input_message_buffer.value = (void *)argp->input_message_buffer.
2045 GSS_BUFFER_T_val;
2047 /* call the gssapi routine */
2049 res->status = (OM_uint32)gss_unseal(&res->minor_status,
2050 context_handle,
2051 &input_message_buffer,
2052 &output_message_buffer,
2053 &res->conf_state,
2054 &res->qop_state);
2057 * convert the output args from the parameter given in the call to the
2058 * variable in the XDR result
2061 if (res->status == GSS_S_COMPLETE) {
2062 res->output_message_buffer.GSS_BUFFER_T_len =
2063 (uint_t)output_message_buffer.length;
2064 res->output_message_buffer.GSS_BUFFER_T_val =
2065 (char *)output_message_buffer.value;
2066 } else
2067 syslog_gss_error(res->status, res->minor_status, "unseal");
2070 /* return to caller */
2072 return (TRUE);
2075 bool_t
2076 gss_display_status_1_svc(argp, res, rqstp)
2077 gss_display_status_arg *argp;
2078 gss_display_status_res *res;
2079 struct svc_req *rqstp;
2081 uid_t uid;
2082 gss_OID mech_type;
2083 gss_OID_desc mech_type_desc;
2084 gss_buffer_desc status_string;
2086 memset(res, 0, sizeof (*res));
2088 if (gssd_debug)
2089 fprintf(stderr, gettext("gss_display_status\n"));
2092 * if the request isn't from root, null out the result pointer
2093 * entries, so the next time through xdr_free won't try to
2094 * free unmalloc'd memory and then return NULL
2097 if (checkfrom(rqstp, &uid) == 0) {
2098 res->status_string.GSS_BUFFER_T_val = NULL;
2099 return (FALSE);
2102 /* set the uid sent as the RPC argument */
2104 uid = argp->uid;
2105 set_gssd_uid(uid);
2108 * copy the XDR structured arguments into their corresponding local
2109 * GSSAPI variables.
2112 if (argp->mech_type.GSS_OID_len == 0)
2113 mech_type = GSS_C_NULL_OID;
2114 else {
2115 mech_type = &mech_type_desc;
2116 mech_type_desc.length = (OM_uint32) argp->mech_type.GSS_OID_len;
2117 mech_type_desc.elements = (void *) argp->mech_type.GSS_OID_val;
2121 /* call the gssapi routine */
2123 res->status = (OM_uint32) gss_display_status(&res->minor_status,
2124 argp->status_value,
2125 argp->status_type,
2126 mech_type,
2127 (OM_uint32 *)&res->message_context,
2128 &status_string);
2131 * convert the output args from the parameter given in the call to the
2132 * variable in the XDR result
2135 if (res->status == GSS_S_COMPLETE) {
2136 res->status_string.GSS_BUFFER_T_len =
2137 (uint_t)status_string.length;
2138 res->status_string.GSS_BUFFER_T_val =
2139 (char *)status_string.value;
2142 return (TRUE);
2146 /*ARGSUSED*/
2147 bool_t
2148 gss_indicate_mechs_1_svc(argp, res, rqstp)
2149 void *argp;
2150 gss_indicate_mechs_res *res;
2151 struct svc_req *rqstp;
2153 gss_OID_set oid_set;
2154 uid_t uid;
2156 memset(res, 0, sizeof (*res));
2158 if (gssd_debug)
2159 fprintf(stderr, gettext("gss_indicate_mechs\n"));
2161 res->mech_set.GSS_OID_SET_val = NULL;
2164 * if the request isn't from root, null out the result pointer
2165 * entries, so the next time through xdr_free won't try to
2166 * free unmalloc'd memory and then return NULL
2169 if (checkfrom(rqstp, &uid) == 0) {
2170 return (FALSE);
2173 res->status = gss_indicate_mechs(&res->minor_status, &oid_set);
2175 if (res->status == GSS_S_COMPLETE) {
2176 int i, j;
2178 res->mech_set.GSS_OID_SET_len = oid_set->count;
2179 res->mech_set.GSS_OID_SET_val = (void *)
2180 malloc(oid_set->count * sizeof (GSS_OID));
2181 if (!res->mech_set.GSS_OID_SET_val) {
2182 return (GSS_S_FAILURE);
2184 for (i = 0; i < oid_set->count; i++) {
2185 res->mech_set.GSS_OID_SET_val[i].GSS_OID_len =
2186 oid_set->elements[i].length;
2187 res->mech_set.GSS_OID_SET_val[i].GSS_OID_val =
2188 (char *)malloc(oid_set->elements[i].length);
2189 if (!res->mech_set.GSS_OID_SET_val[i].GSS_OID_val) {
2190 for (j = 0; j < (i -1); j++) {
2191 free
2192 (res->mech_set.GSS_OID_SET_val[i].GSS_OID_val);
2194 free(res->mech_set.GSS_OID_SET_val);
2195 return (GSS_S_FAILURE);
2197 memcpy(res->mech_set.GSS_OID_SET_val[i].GSS_OID_val,
2198 oid_set->elements[i].elements,
2199 oid_set->elements[i].length);
2203 return (TRUE);
2206 bool_t
2207 gss_inquire_cred_1_svc(argp, res, rqstp)
2208 gss_inquire_cred_arg *argp;
2209 gss_inquire_cred_res *res;
2210 struct svc_req *rqstp;
2213 uid_t uid;
2215 OM_uint32 minor_status;
2216 gss_cred_id_t cred_handle;
2217 gss_buffer_desc external_name;
2218 gss_OID name_type;
2219 gss_name_t internal_name;
2220 gss_OID_set mechanisms;
2221 int i, j;
2223 memset(res, 0, sizeof (*res));
2225 if (gssd_debug)
2226 fprintf(stderr, gettext("gss_inquire_cred\n"));
2228 /* verify the verifier_cred_handle */
2230 if (argp->gssd_cred_verifier != gssd_time_verf) {
2231 res->name.GSS_BUFFER_T_val = NULL;
2232 res->name_type.GSS_OID_val = NULL;
2233 res->mechanisms.GSS_OID_SET_val = NULL;
2234 res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL;
2235 res->minor_status = 0;
2236 return (TRUE);
2240 * if the request isn't from root, null out the result pointer
2241 * entries, so the next time through xdr_free won't try to
2242 * free unmalloc'd memory and then return NULL
2245 if (checkfrom(rqstp, &uid) == 0) {
2246 res->name.GSS_BUFFER_T_val = NULL;
2247 res->name_type.GSS_OID_val = NULL;
2248 res->mechanisms.GSS_OID_SET_val = NULL;
2249 return (FALSE);
2252 /* set the uid sent as the RPC argument */
2254 uid = argp->uid;
2255 set_gssd_uid(uid);
2257 cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ?
2258 GSS_C_NO_CREDENTIAL :
2259 /*LINTED*/
2260 *((gss_cred_id_t *)argp->cred_handle.
2261 GSS_CRED_ID_T_val));
2263 /* call the gssapi routine */
2265 res->status = (OM_uint32)gss_inquire_cred(&res->minor_status,
2266 cred_handle,
2267 &internal_name,
2268 &res->lifetime,
2269 &res->cred_usage,
2270 &mechanisms);
2272 if (res->status != GSS_S_COMPLETE) {
2273 syslog_gss_error(res->status, res->minor_status,
2274 "inquire_cred");
2275 return (TRUE);
2278 /* convert the returned name from internal to external format */
2280 if (gss_display_name(&minor_status, internal_name,
2281 &external_name, &name_type)
2282 != GSS_S_COMPLETE) {
2284 res->status = (OM_uint32)GSS_S_FAILURE;
2285 res->minor_status = minor_status;
2287 gss_release_name(&minor_status, &internal_name);
2289 if (mechanisms != GSS_C_NULL_OID_SET) {
2290 for (i = 0; i < mechanisms->count; i++)
2291 free(mechanisms->elements[i].elements);
2292 free(mechanisms->elements);
2293 free(mechanisms);
2296 return (TRUE);
2300 * convert the output args from the parameter given in the call to the
2301 * variable in the XDR result
2305 res->name.GSS_BUFFER_T_len = (uint_t)external_name.length;
2306 res->name.GSS_BUFFER_T_val = (void *)external_name.value;
2309 * we have to allocate storage for name_type here, since the value
2310 * returned from gss_display_name points to the underlying mechanism
2311 * static storage. If we didn't allocate storage, the next time
2312 * through this routine, the xdr_free() call at the beginning would
2313 * try to free up that static storage.
2316 res->name_type.GSS_OID_len = (uint_t)name_type->length;
2317 res->name_type.GSS_OID_val = (void *)malloc(name_type->length);
2318 if (!res->name_type.GSS_OID_val) {
2319 return (GSS_S_FAILURE);
2321 memcpy(res->name_type.GSS_OID_val, name_type->elements,
2322 name_type->length);
2324 if (mechanisms != GSS_C_NULL_OID_SET) {
2325 res->mechanisms.GSS_OID_SET_len =
2326 (uint_t)mechanisms->count;
2327 res->mechanisms.GSS_OID_SET_val = (GSS_OID *)
2328 malloc(sizeof (GSS_OID) * mechanisms->count);
2329 if (!res->mechanisms.GSS_OID_SET_val) {
2330 free(res->name_type.GSS_OID_val);
2331 return (GSS_S_FAILURE);
2333 for (i = 0; i < mechanisms->count; i++) {
2334 res->mechanisms.GSS_OID_SET_val[i].GSS_OID_len =
2335 (uint_t)mechanisms->elements[i].length;
2336 res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val =
2337 (char *)malloc(mechanisms->elements[i].
2338 length);
2339 if (!res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val) {
2340 free(res->name_type.GSS_OID_val);
2341 for (j = 0; j < i; j++) {
2342 free(res->mechanisms.
2343 GSS_OID_SET_val[i].GSS_OID_val);
2345 free(res->mechanisms.GSS_OID_SET_val);
2346 return (GSS_S_FAILURE);
2348 memcpy(res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val,
2349 mechanisms->elements[i].elements,
2350 mechanisms->elements[i].length);
2352 } else
2353 res->mechanisms.GSS_OID_SET_len = 0;
2355 /* release the space allocated for internal_name and mechanisms */
2356 gss_release_name(&minor_status, &internal_name);
2358 if (mechanisms != GSS_C_NULL_OID_SET) {
2359 for (i = 0; i < mechanisms->count; i++)
2360 free(mechanisms->elements[i].elements);
2361 free(mechanisms->elements);
2362 free(mechanisms);
2365 /* return to caller */
2366 return (TRUE);
2370 bool_t
2371 gss_inquire_cred_by_mech_1_svc(argp, res, rqstp)
2372 gss_inquire_cred_by_mech_arg *argp;
2373 gss_inquire_cred_by_mech_res *res;
2374 struct svc_req *rqstp;
2377 uid_t uid;
2379 gss_cred_id_t cred_handle;
2380 gss_OID_desc mech_type_desc;
2381 gss_OID mech_type = &mech_type_desc;
2383 memset(res, 0, sizeof (*res));
2385 if (gssd_debug)
2386 fprintf(stderr, gettext("gss_inquire_cred\n"));
2388 /* verify the verifier_cred_handle */
2390 if (argp->gssd_cred_verifier != gssd_time_verf) {
2391 res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL;
2392 res->minor_status = 0;
2393 return (TRUE);
2397 * if the request isn't from root, null out the result pointer
2398 * entries, so the next time through xdr_free won't try to
2399 * free unmalloc'd memory and then return NULL
2402 if (checkfrom(rqstp, &uid) == 0) {
2403 return (FALSE);
2406 /* set the uid sent as the RPC argument */
2408 uid = argp->uid;
2409 set_gssd_uid(uid);
2411 cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ?
2412 GSS_C_NO_CREDENTIAL :
2413 /*LINTED*/
2414 *((gss_cred_id_t *)argp->cred_handle.
2415 GSS_CRED_ID_T_val));
2417 /* call the gssapi routine */
2419 if (argp->mech_type.GSS_OID_len == 0)
2420 mech_type = GSS_C_NULL_OID;
2421 else {
2422 mech_type->length =
2423 (OM_uint32)argp->mech_type.GSS_OID_len;
2424 mech_type->elements =
2425 (void *)malloc(mech_type->length);
2426 if (!mech_type->elements) {
2427 return (GSS_S_FAILURE);
2429 memcpy(mech_type->elements,
2430 argp->mech_type.GSS_OID_val,
2431 mech_type->length);
2433 res->status = (OM_uint32)gss_inquire_cred_by_mech(
2434 &res->minor_status, cred_handle,
2435 mech_type, NULL, NULL,
2436 NULL, NULL);
2438 /* return to caller */
2439 return (TRUE);
2443 bool_t
2444 gsscred_name_to_unix_cred_1_svc(argsp, res, rqstp)
2445 gsscred_name_to_unix_cred_arg *argsp;
2446 gsscred_name_to_unix_cred_res *res;
2447 struct svc_req *rqstp;
2449 uid_t uid;
2450 gss_OID_desc oid;
2451 gss_name_t gssName;
2452 gss_buffer_desc gssBuf = GSS_C_EMPTY_BUFFER;
2453 OM_uint32 minor;
2454 int gidsLen;
2455 gid_t *gids, gidOut;
2457 if (gssd_debug)
2458 fprintf(stderr, gettext("gsscred_name_to_unix_cred\n"));
2460 memset(res, 0, sizeof (*res));
2463 * check the request originator
2465 if (checkfrom(rqstp, &uid) == 0)
2466 return (FALSE);
2468 /* set the uid from the rpc request */
2469 uid = argsp->uid;
2470 set_gssd_uid(uid);
2473 * convert the principal name to gss internal format
2474 * need not malloc the input parameters
2476 gssBuf.length = argsp->pname.GSS_BUFFER_T_len;
2477 gssBuf.value = (void*)argsp->pname.GSS_BUFFER_T_val;
2478 oid.length = argsp->name_type.GSS_OID_len;
2479 oid.elements = (void*)argsp->name_type.GSS_OID_val;
2481 res->major = gss_import_name(&minor, &gssBuf, &oid, &gssName);
2482 if (res->major != GSS_S_COMPLETE)
2483 return (TRUE);
2485 /* retrieve the mechanism type from the arguments */
2486 oid.length = argsp->mech_type.GSS_OID_len;
2487 oid.elements = (void*)argsp->mech_type.GSS_OID_val;
2489 /* call the gss extensions to map the principal name to unix creds */
2490 res->major = gsscred_name_to_unix_cred(gssName, &oid, &uid, &gidOut,
2491 &gids, &gidsLen);
2492 gss_release_name(&minor, &gssName);
2494 if (res->major == GSS_S_COMPLETE) {
2495 res->uid = uid;
2496 res->gid = gidOut;
2497 res->gids.GSSCRED_GIDS_val = gids;
2498 res->gids.GSSCRED_GIDS_len = gidsLen;
2501 return (TRUE);
2502 } /* gsscred_name_to_unix_cred_svc_1 */
2504 bool_t
2505 gsscred_expname_to_unix_cred_1_svc(argsp, res, rqstp)
2506 gsscred_expname_to_unix_cred_arg *argsp;
2507 gsscred_expname_to_unix_cred_res *res;
2508 struct svc_req *rqstp;
2510 uid_t uid;
2511 gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
2512 int gidsLen;
2513 gid_t *gids, gidOut;
2515 if (gssd_debug)
2516 fprintf(stderr, gettext("gsscred_expname_to_unix_cred\n"));
2518 memset(res, 0, sizeof (*res));
2521 * check the request originator
2523 if (checkfrom(rqstp, &uid) == 0)
2524 return (FALSE);
2526 /* set the uid from the rpc request */
2527 uid = argsp->uid;
2528 set_gssd_uid(uid);
2531 * extract the export name from arguments
2532 * need not malloc the input parameters
2534 expName.length = argsp->expname.GSS_BUFFER_T_len;
2535 expName.value = (void*)argsp->expname.GSS_BUFFER_T_val;
2537 res->major = gsscred_expname_to_unix_cred(&expName, &uid,
2538 &gidOut, &gids, &gidsLen);
2540 if (res->major == GSS_S_COMPLETE) {
2541 res->uid = uid;
2542 res->gid = gidOut;
2543 res->gids.GSSCRED_GIDS_val = gids;
2544 res->gids.GSSCRED_GIDS_len = gidsLen;
2547 return (TRUE);
2548 } /* gsscred_expname_to_unix_cred_1_svc */
2550 bool_t
2551 gss_get_group_info_1_svc(argsp, res, rqstp)
2552 gss_get_group_info_arg *argsp;
2553 gss_get_group_info_res *res;
2554 struct svc_req *rqstp;
2556 uid_t uid;
2557 int gidsLen;
2558 gid_t *gids, gidOut;
2560 if (gssd_debug)
2561 fprintf(stderr, gettext("gss_get_group_info\n"));
2563 memset(res, 0, sizeof (*res));
2566 * check the request originator
2568 if (checkfrom(rqstp, &uid) == 0)
2569 return (FALSE);
2571 /* set the uid from the rpc request */
2572 uid = argsp->uid;
2573 set_gssd_uid(uid);
2576 * extract the uid from the arguments
2578 uid = argsp->puid;
2579 res->major = gss_get_group_info(uid, &gidOut, &gids, &gidsLen);
2580 if (res->major == GSS_S_COMPLETE) {
2581 res->gid = gidOut;
2582 res->gids.GSSCRED_GIDS_val = gids;
2583 res->gids.GSSCRED_GIDS_len = gidsLen;
2586 return (TRUE);
2587 } /* gss_get_group_info_1_svc */
2589 /*ARGSUSED*/
2590 bool_t
2591 gss_get_kmod_1_svc(argsp, res, rqstp)
2592 gss_get_kmod_arg *argsp;
2593 gss_get_kmod_res *res;
2594 struct svc_req *rqstp;
2596 gss_OID_desc oid;
2597 char *kmodName;
2599 if (gssd_debug)
2600 fprintf(stderr, gettext("gss_get_kmod\n"));
2602 res->module_follow = FALSE;
2603 oid.length = argsp->mech_oid.GSS_OID_len;
2604 oid.elements = (void *)argsp->mech_oid.GSS_OID_val;
2605 kmodName = __gss_get_kmodName(&oid);
2607 if (kmodName != NULL) {
2608 res->module_follow = TRUE;
2609 res->gss_get_kmod_res_u.modname = kmodName;
2612 return (TRUE);
2616 * Returns 1 if caller is ok, else 0.
2617 * If caller ok, the uid is returned in uidp.
2619 static int
2620 checkfrom(rqstp, uidp)
2621 struct svc_req *rqstp;
2622 uid_t *uidp;
2624 SVCXPRT *xprt = rqstp->rq_xprt;
2625 struct authunix_parms *aup;
2626 uid_t uid;
2628 /* check client agent uid to ensure it is privileged */
2629 if (__rpc_get_local_uid(xprt, &uid) < 0) {
2630 syslog(LOG_ERR, gettext("__rpc_get_local_uid failed %s %s"),
2631 xprt->xp_netid, xprt->xp_tp);
2632 goto weakauth;
2634 if (gssd_debug)
2635 fprintf(stderr, gettext("checkfrom: local_uid %d\n"), uid);
2636 if (uid != 0) {
2637 syslog(LOG_ERR,
2638 gettext("checkfrom: caller (uid %d) not privileged"),
2639 uid);
2640 goto weakauth;
2644 * Request came from local privileged process.
2645 * Proceed to get uid of client if needed by caller.
2647 if (uidp) {
2648 if (rqstp->rq_cred.oa_flavor != AUTH_SYS) {
2649 syslog(LOG_ERR, gettext("checkfrom: not UNIX credentials"));
2650 goto weakauth;
2652 CTASSERT(sizeof (struct authunix_parms) <= RQCRED_SIZE);
2653 /*LINTED*/
2654 aup = (struct authunix_parms *)rqstp->rq_clntcred;
2655 *uidp = aup->aup_uid;
2656 if (gssd_debug) {
2657 fprintf(stderr,
2658 gettext("checkfrom: caller's uid %d\n"), *uidp);
2661 return (1);
2663 weakauth:
2664 svcerr_weakauth(xprt);
2665 return (0);