1 /* krb5/cred.c --- Kerberos 5 GSS-API credential management functions.
2  * Copyright (C) 2003-2014 Simon Josefsson
3  *
4  * This file is part of the Generic Security Service (GSS).
5  *
6  * GSS is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSS is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14  * License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSS; if not, see http://www.gnu.org/licenses or write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19  * Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /* Get specification. */
24 #include "k5internal.h"
25 
26 static OM_uint32
acquire_cred1(OM_uint32 * minor_status,const gss_name_t desired_name,OM_uint32 time_req,const gss_OID_set desired_mechs,gss_cred_usage_t cred_usage,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * time_rec)27 acquire_cred1 (OM_uint32 * minor_status,
28 	       const gss_name_t desired_name,
29 	       OM_uint32 time_req,
30 	       const gss_OID_set desired_mechs,
31 	       gss_cred_usage_t cred_usage,
32 	       gss_cred_id_t * output_cred_handle,
33 	       gss_OID_set * actual_mechs, OM_uint32 * time_rec)
34 {
35   gss_name_t name = desired_name;
36   _gss_krb5_cred_t k5 = (*output_cred_handle)->krb5;
37   OM_uint32 maj_stat;
38 
39   if (desired_name == GSS_C_NO_NAME)
40     {
41       gss_buffer_desc buf = { 4, (char *) "host" };
42 
43       maj_stat = gss_import_name (minor_status, &buf,
44 				  GSS_C_NT_HOSTBASED_SERVICE, &name);
45       if (GSS_ERROR (maj_stat))
46 	return maj_stat;
47     }
48 
49   maj_stat = gss_krb5_canonicalize_name (minor_status, name,
50 					 GSS_KRB5, &k5->peerptr);
51   if (GSS_ERROR (maj_stat))
52     return maj_stat;
53 
54   if (k5->peerptr == GSS_C_NO_NAME)
55     {
56       maj_stat = gss_release_name (minor_status, &name);
57       if (GSS_ERROR (maj_stat))
58 	return maj_stat;
59       return GSS_S_BAD_NAME;
60     }
61 
62   if (shishi_init_server (&k5->sh) != SHISHI_OK)
63     return GSS_S_FAILURE;
64 
65   {
66     char *p;
67 
68     p = malloc (k5->peerptr->length + 1);
69     if (!p)
70       {
71 	if (minor_status)
72 	  *minor_status = ENOMEM;
73 	return GSS_S_FAILURE;
74       }
75     memcpy (p, k5->peerptr->value, k5->peerptr->length);
76     p[k5->peerptr->length] = 0;
77 
78     k5->key = shishi_hostkeys_for_serverrealm (k5->sh, p, NULL);
79 
80     free (p);
81   }
82 
83   if (!k5->key)
84     {
85       if (minor_status)
86 	*minor_status = GSS_KRB5_S_KG_KEYTAB_NOMATCH;
87       return GSS_S_NO_CRED;
88     }
89 
90   if (time_rec)
91     *time_rec = GSS_C_INDEFINITE;
92 
93   return GSS_S_COMPLETE;
94 }
95 
96 OM_uint32
gss_krb5_acquire_cred(OM_uint32 * minor_status,const gss_name_t desired_name,OM_uint32 time_req,const gss_OID_set desired_mechs,gss_cred_usage_t cred_usage,gss_cred_id_t * output_cred_handle,gss_OID_set * actual_mechs,OM_uint32 * time_rec)97 gss_krb5_acquire_cred (OM_uint32 * minor_status,
98 		       const gss_name_t desired_name,
99 		       OM_uint32 time_req,
100 		       const gss_OID_set desired_mechs,
101 		       gss_cred_usage_t cred_usage,
102 		       gss_cred_id_t * output_cred_handle,
103 		       gss_OID_set * actual_mechs, OM_uint32 * time_rec)
104 {
105   OM_uint32 maj_stat;
106   gss_cred_id_t p = *output_cred_handle;
107 
108   p->krb5 = calloc (sizeof (*p->krb5), 1);
109   if (!p->krb5)
110     {
111       if (minor_status)
112 	*minor_status = ENOMEM;
113       return GSS_S_FAILURE;
114     }
115 
116   if (actual_mechs)
117     {
118       maj_stat = gss_create_empty_oid_set (minor_status, actual_mechs);
119       if (GSS_ERROR (maj_stat))
120 	{
121 	  free (p->krb5);
122 	  return maj_stat;
123 	}
124       maj_stat = gss_add_oid_set_member (minor_status, GSS_KRB5,
125 					 actual_mechs);
126       if (GSS_ERROR (maj_stat))
127 	{
128 	  free (p->krb5);
129 	  return maj_stat;
130 	}
131     }
132 
133   maj_stat = acquire_cred1 (minor_status, desired_name, time_req,
134 			    desired_mechs, cred_usage,
135 			    &p, actual_mechs, time_rec);
136   if (GSS_ERROR (maj_stat))
137     {
138       if (actual_mechs)
139 	gss_release_oid_set (NULL, actual_mechs);
140       free (p->krb5);
141 
142       return maj_stat;
143     }
144 
145   if (minor_status)
146     *minor_status = 0;
147   return GSS_S_COMPLETE;
148 }
149 
150 static OM_uint32
inquire_cred(OM_uint32 * minor_status,const gss_cred_id_t cred_handle,gss_name_t * name,OM_uint32 * lifetime,gss_cred_usage_t * cred_usage,gss_OID_set * mechanisms)151 inquire_cred (OM_uint32 * minor_status,
152 	      const gss_cred_id_t cred_handle,
153 	      gss_name_t * name,
154 	      OM_uint32 * lifetime,
155 	      gss_cred_usage_t * cred_usage, gss_OID_set * mechanisms)
156 {
157   OM_uint32 maj_stat;
158 
159   if (cred_handle == GSS_C_NO_CREDENTIAL)
160     return GSS_S_NO_CRED;
161 
162   if (mechanisms)
163     {
164       maj_stat = gss_create_empty_oid_set (minor_status, mechanisms);
165       if (GSS_ERROR (maj_stat))
166 	return maj_stat;
167       maj_stat = gss_add_oid_set_member (minor_status, GSS_KRB5, mechanisms);
168       if (GSS_ERROR (maj_stat))
169 	return maj_stat;
170     }
171 
172   if (name)
173     {
174       maj_stat = gss_duplicate_name (minor_status, cred_handle->krb5->peerptr,
175 				     name);
176       if (GSS_ERROR (maj_stat))
177 	return maj_stat;
178     }
179 
180   if (cred_usage)
181     *cred_usage = GSS_C_BOTH;
182 
183   if (lifetime)
184     *lifetime = GSS_C_INDEFINITE;
185 
186   if (minor_status)
187     *minor_status = 0;
188   return GSS_S_COMPLETE;
189 }
190 
191 OM_uint32
gss_krb5_inquire_cred(OM_uint32 * minor_status,const gss_cred_id_t cred_handle,gss_name_t * name,OM_uint32 * lifetime,gss_cred_usage_t * cred_usage,gss_OID_set * mechanisms)192 gss_krb5_inquire_cred (OM_uint32 * minor_status,
193 		       const gss_cred_id_t cred_handle,
194 		       gss_name_t * name,
195 		       OM_uint32 * lifetime,
196 		       gss_cred_usage_t * cred_usage,
197 		       gss_OID_set * mechanisms)
198 {
199   return inquire_cred (minor_status, cred_handle, name, lifetime,
200 		       cred_usage, mechanisms);
201 }
202 
203 OM_uint32
gss_krb5_inquire_cred_by_mech(OM_uint32 * minor_status,const gss_cred_id_t cred_handle,const gss_OID mech_type,gss_name_t * name,OM_uint32 * initiator_lifetime,OM_uint32 * acceptor_lifetime,gss_cred_usage_t * cred_usage)204 gss_krb5_inquire_cred_by_mech (OM_uint32 * minor_status,
205 			       const gss_cred_id_t cred_handle,
206 			       const gss_OID mech_type,
207 			       gss_name_t * name,
208 			       OM_uint32 * initiator_lifetime,
209 			       OM_uint32 * acceptor_lifetime,
210 			       gss_cred_usage_t * cred_usage)
211 {
212   OM_uint32 maj_stat;
213 
214   maj_stat = inquire_cred (minor_status, cred_handle, name,
215 			   initiator_lifetime, cred_usage, NULL);
216 
217   if (acceptor_lifetime)
218     *acceptor_lifetime = *initiator_lifetime;
219 
220   return maj_stat;
221 }
222 
223 OM_uint32
gss_krb5_release_cred(OM_uint32 * minor_status,gss_cred_id_t * cred_handle)224 gss_krb5_release_cred (OM_uint32 * minor_status, gss_cred_id_t * cred_handle)
225 {
226   _gss_krb5_cred_t k5 = (*cred_handle)->krb5;
227 
228   if (k5->peerptr != GSS_C_NO_NAME)
229     gss_release_name (NULL, &k5->peerptr);
230 
231   shishi_key_done (k5->key);
232   shishi_done (k5->sh);
233   free (k5);
234 
235   if (minor_status)
236     *minor_status = 0;
237   return GSS_S_COMPLETE;
238 }
239