xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_set_cred_option.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /*
2  * Copyright 2008-2010 by the Massachusetts Institute of Technology.
3  * All Rights Reserved.
4  *
5  * Export of this software from the United States of America may
6  *   require a specific license from the United States Government.
7  *   It is the responsibility of any person or organization contemplating
8  *   export to obtain such a license before exporting.
9  *
10  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
11  * distribute this software and its documentation for any purpose and
12  * without fee is hereby granted, provided that the above copyright
13  * notice appear in all copies and that both that copyright notice and
14  * this permission notice appear in supporting documentation, and that
15  * the name of M.I.T. not be used in advertising or publicity pertaining
16  * to distribution of the software without specific, written prior
17  * permission.  Furthermore if you modify this software you must label
18  * your software as modified software and not distribute it in such a
19  * fashion that it might be confused with the original M.I.T. software.
20  * M.I.T. makes no representations about the suitability of
21  * this software for any purpose.  It is provided "as is" without express
22  * or implied warranty.
23  */
24 
25 /* Glue routine for gssspi_set_cred_option */
26 
27 #include "mglueP.h"
28 #include <stdio.h>
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #include <string.h>
33 #include <time.h>
34 
35 static OM_uint32
alloc_union_cred(OM_uint32 * minor_status,gss_mechanism mech,gss_cred_id_t mech_cred,gss_union_cred_t * pcred)36 alloc_union_cred(OM_uint32 *minor_status,
37 		 gss_mechanism mech,
38 		 gss_cred_id_t mech_cred,
39 		 gss_union_cred_t *pcred)
40 {
41     OM_uint32		status;
42     OM_uint32		temp_minor_status;
43     gss_union_cred_t	cred = NULL;
44 
45     *pcred = NULL;
46 
47     status = GSS_S_FAILURE;
48 
49     cred = calloc(1, sizeof(*cred));
50     if (cred == NULL) {
51 	*minor_status = ENOMEM;
52 	goto cleanup;
53     }
54 
55     cred->loopback = cred;
56     cred->count = 1;
57 
58     cred->cred_array = calloc(cred->count, sizeof(gss_cred_id_t));
59     if (cred->cred_array == NULL) {
60 	*minor_status = ENOMEM;
61 	goto cleanup;
62     }
63     cred->cred_array[0] = mech_cred;
64 
65     status = generic_gss_copy_oid(minor_status,
66                                   &mech->mech_type,
67                                   &cred->mechs_array);
68     if (status != GSS_S_COMPLETE)
69         goto cleanup;
70 
71     status = GSS_S_COMPLETE;
72     *pcred = cred;
73 
74 cleanup:
75     if (status != GSS_S_COMPLETE)
76 	gss_release_cred(&temp_minor_status, (gss_cred_id_t *)&cred);
77 
78     return status;
79 }
80 
81 /*
82  * This differs from gssspi_set_cred_option() as shipped in 1.7, in that
83  * it can return a cred handle. To denote this change we have changed the
84  * name of the function from gssspi_set_cred_option() to gss_set_cred_option().
85  * However, the dlsym() entry point is still gssspi_set_cred_option(). This
86  * fixes a separate issue, namely that a dynamically loaded mechanism could
87  * not itself call set_cred_option() without calling its own implementation
88  * instead of the mechanism glue's. (This is useful where a mechanism wishes
89  * to export a mechanism-specific API that is a wrapper around this function.)
90  */
91 OM_uint32 KRB5_CALLCONV
gss_set_cred_option(OM_uint32 * minor_status,gss_cred_id_t * cred_handle,const gss_OID desired_object,const gss_buffer_t value)92 gss_set_cred_option(OM_uint32 *minor_status,
93 	            gss_cred_id_t *cred_handle,
94 	            const gss_OID desired_object,
95 	            const gss_buffer_t value)
96 {
97     gss_union_cred_t	union_cred;
98     gss_mechanism	mech;
99     int			i;
100     OM_uint32		status;
101     OM_uint32		mech_status;
102     OM_uint32		mech_minor_status;
103 
104     if (minor_status == NULL)
105 	return GSS_S_CALL_INACCESSIBLE_WRITE;
106     *minor_status = 0;
107 
108     if (cred_handle == NULL)
109 	return GSS_S_CALL_INACCESSIBLE_WRITE;
110 
111     status = GSS_S_UNAVAILABLE;
112 
113     if (*cred_handle == GSS_C_NO_CREDENTIAL) {
114 	gss_cred_id_t mech_cred = GSS_C_NO_CREDENTIAL;
115 
116 	/*
117 	 * We need to give a mechanism the opportunity to allocate a
118 	 * credentials handle. Unfortunately this does mean that only
119 	 * the default mechanism can allocate a credentials handle.
120 	 */
121         mech = gssint_get_mechanism(NULL);
122         if (mech == NULL)
123             return GSS_S_BAD_MECH;
124 
125 	if (mech->gssspi_set_cred_option == NULL)
126 	    return GSS_S_UNAVAILABLE;
127 
128 	status = mech->gssspi_set_cred_option(minor_status,
129 					      &mech_cred,
130 					      desired_object,
131 					      value);
132 	if (status != GSS_S_COMPLETE) {
133 	    map_error(minor_status, mech);
134 	    return status;
135 	}
136 
137 	if (mech_cred != GSS_C_NO_CREDENTIAL) {
138 	    status = alloc_union_cred(minor_status,
139 				      mech,
140 				      mech_cred,
141 				      &union_cred);
142 	    if (status != GSS_S_COMPLETE)
143 		return status;
144 	    *cred_handle = (gss_cred_id_t)union_cred;
145 	}
146     } else {
147 	union_cred = (gss_union_cred_t)*cred_handle;
148 
149 	for (i = 0; i < union_cred->count; i++) {
150 	    mech = gssint_get_mechanism(&union_cred->mechs_array[i]);
151 	    if (mech == NULL) {
152 		status = GSS_S_BAD_MECH;
153 		break;
154 	    }
155 
156 	    if (mech->gssspi_set_cred_option == NULL)
157 		continue;
158 
159 	    mech_status = mech->gssspi_set_cred_option(&mech_minor_status,
160 						       &union_cred->cred_array[i],
161 						       desired_object,
162 						       value);
163 	    if (mech_status == GSS_S_UNAVAILABLE)
164 		continue;
165 	    else {
166 		status = mech_status;
167 		*minor_status = mech_minor_status;
168 	    }
169 	    if (status != GSS_S_COMPLETE) {
170 		map_error(minor_status, mech);
171 		break;
172 	    }
173 	}
174     }
175 
176     return status;
177 }
178 
179 /*
180  * Provide this for backward ABI compatibility, but remove it from the
181  * header.
182  */
183 OM_uint32 KRB5_CALLCONV
184 gssspi_set_cred_option(OM_uint32 *minor_status,
185 	               gss_cred_id_t cred,
186 	               const gss_OID desired_object,
187 	               const gss_buffer_t value);
188 
189 OM_uint32 KRB5_CALLCONV
gssspi_set_cred_option(OM_uint32 * minor_status,gss_cred_id_t cred,const gss_OID desired_object,const gss_buffer_t value)190 gssspi_set_cred_option(OM_uint32 *minor_status,
191 	               gss_cred_id_t cred,
192 	               const gss_OID desired_object,
193 	               const gss_buffer_t value)
194 {
195     return gss_set_cred_option(minor_status, &cred,
196                                desired_object, value);
197 }
198