xref: /freebsd/crypto/krb5/src/kadmin/server/kadm_rpc_svc.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-file-style: "bsd"; indent-tabs-mode: t -*- */
2 /*
3  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
4  *
5  */
6 
7 #include <k5-int.h>
8 #include <gssrpc/rpc.h>
9 #include <gssapi/gssapi_krb5.h> /* for gss_nt_krb5_name */
10 #include <syslog.h>
11 #include <kadm5/kadm_rpc.h>
12 #include <krb5.h>
13 #include <kadm5/admin.h>
14 #include <adm_proto.h>
15 #include "misc.h"
16 #include "kadm5/server_internal.h"
17 
18 extern void *global_server_handle;
19 
20 static int check_rpcsec_auth(struct svc_req *);
21 
22 /*
23  * Function: kadm_1
24  *
25  * Purpose: RPC processing procedure.
26  *	    originally generated from rpcgen
27  *
28  * Arguments:
29  *	rqstp		    (input) rpc request structure
30  *	transp		    (input) rpc transport structure
31  *	(input/output)
32  *	<return value>
33  *
34  * Requires:
35  * Effects:
36  * Modifies:
37  */
38 
kadm_1(rqstp,transp)39 void kadm_1(rqstp, transp)
40    struct svc_req *rqstp;
41    SVCXPRT *transp;
42 {
43      union {
44 	  cprinc_arg create_principal_2_arg;
45 	  dprinc_arg delete_principal_2_arg;
46 	  mprinc_arg modify_principal_2_arg;
47 	  rprinc_arg rename_principal_2_arg;
48 	  gprinc_arg get_principal_2_arg;
49 	  chpass_arg chpass_principal_2_arg;
50 	  chrand_arg chrand_principal_2_arg;
51 	  cpol_arg create_policy_2_arg;
52 	  dpol_arg delete_policy_2_arg;
53 	  mpol_arg modify_policy_2_arg;
54 	  gpol_arg get_policy_2_arg;
55 	  setkey_arg setkey_principal_2_arg;
56 	  cprinc3_arg create_principal3_2_arg;
57 	  chpass3_arg chpass_principal3_2_arg;
58 	  chrand3_arg chrand_principal3_2_arg;
59 	  setkey3_arg setkey_principal3_2_arg;
60 	  setkey4_arg setkey_principal4_2_arg;
61 	  getpkeys_arg get_principal_keys_2_arg;
62      } argument;
63      union {
64 	  generic_ret gen_ret;
65 	  gprinc_ret get_principal_2_ret;
66 	  chrand_ret chrand_principal_2_ret;
67 	  gpol_ret get_policy_2_ret;
68 	  getprivs_ret get_privs_2_ret;
69 	  gprincs_ret get_princs_2_ret;
70 	  gpols_ret get_pols_2_ret;
71 	  chrand_ret chrand_principal3_2_ret;
72 	  gstrings_ret get_string_2_ret;
73 	  getpkeys_ret get_principal_keys_ret;
74      } result;
75      bool_t retval;
76      bool_t (*xdr_argument)(), (*xdr_result)();
77      bool_t (*local)();
78 
79      if (rqstp->rq_cred.oa_flavor != AUTH_GSSAPI &&
80 	 !check_rpcsec_auth(rqstp)) {
81 	  krb5_klog_syslog(LOG_ERR, "Authentication attempt failed: %s, "
82 			   "RPC authentication flavor %d",
83 			   client_addr(rqstp->rq_xprt),
84 			   rqstp->rq_cred.oa_flavor);
85 	  svcerr_weakauth(transp);
86 	  return;
87      }
88 
89      switch (rqstp->rq_proc) {
90      case NULLPROC:
91 	  (void) svc_sendreply(transp, xdr_void, (char *)NULL);
92 	  return;
93 
94      case CREATE_PRINCIPAL:
95 	  xdr_argument = xdr_cprinc_arg;
96 	  xdr_result = xdr_generic_ret;
97 	  local = (bool_t (*)()) create_principal_2_svc;
98 	  break;
99 
100      case DELETE_PRINCIPAL:
101 	  xdr_argument = xdr_dprinc_arg;
102 	  xdr_result = xdr_generic_ret;
103 	  local = (bool_t (*)()) delete_principal_2_svc;
104 	  break;
105 
106      case MODIFY_PRINCIPAL:
107 	  xdr_argument = xdr_mprinc_arg;
108 	  xdr_result = xdr_generic_ret;
109 	  local = (bool_t (*)()) modify_principal_2_svc;
110 	  break;
111 
112      case RENAME_PRINCIPAL:
113 	  xdr_argument = xdr_rprinc_arg;
114 	  xdr_result = xdr_generic_ret;
115 	  local = (bool_t (*)()) rename_principal_2_svc;
116 	  break;
117 
118      case GET_PRINCIPAL:
119 	  xdr_argument = xdr_gprinc_arg;
120 	  xdr_result = xdr_gprinc_ret;
121 	  local = (bool_t (*)()) get_principal_2_svc;
122 	  break;
123 
124      case GET_PRINCS:
125 	  xdr_argument = xdr_gprincs_arg;
126 	  xdr_result = xdr_gprincs_ret;
127 	  local = (bool_t (*)()) get_princs_2_svc;
128 	  break;
129 
130      case CHPASS_PRINCIPAL:
131 	  xdr_argument = xdr_chpass_arg;
132 	  xdr_result = xdr_generic_ret;
133 	  local = (bool_t (*)()) chpass_principal_2_svc;
134 	  break;
135 
136      case SETKEY_PRINCIPAL:
137 	  xdr_argument = xdr_setkey_arg;
138 	  xdr_result = xdr_generic_ret;
139 	  local = (bool_t (*)()) setkey_principal_2_svc;
140 	  break;
141 
142      case CHRAND_PRINCIPAL:
143 	  xdr_argument = xdr_chrand_arg;
144 	  xdr_result = xdr_chrand_ret;
145 	  local = (bool_t (*)()) chrand_principal_2_svc;
146 	  break;
147 
148      case CREATE_POLICY:
149 	  xdr_argument = xdr_cpol_arg;
150 	  xdr_result = xdr_generic_ret;
151 	  local = (bool_t (*)()) create_policy_2_svc;
152 	  break;
153 
154      case DELETE_POLICY:
155 	  xdr_argument = xdr_dpol_arg;
156 	  xdr_result = xdr_generic_ret;
157 	  local = (bool_t (*)()) delete_policy_2_svc;
158 	  break;
159 
160      case MODIFY_POLICY:
161 	  xdr_argument = xdr_mpol_arg;
162 	  xdr_result = xdr_generic_ret;
163 	  local = (bool_t (*)()) modify_policy_2_svc;
164 	  break;
165 
166      case GET_POLICY:
167 	  xdr_argument = xdr_gpol_arg;
168 	  xdr_result = xdr_gpol_ret;
169 	  local = (bool_t (*)()) get_policy_2_svc;
170 	  break;
171 
172      case GET_POLS:
173 	  xdr_argument = xdr_gpols_arg;
174 	  xdr_result = xdr_gpols_ret;
175 	  local = (bool_t (*)()) get_pols_2_svc;
176 	  break;
177 
178      case GET_PRIVS:
179 	  xdr_argument = xdr_u_int32;
180 	  xdr_result = xdr_getprivs_ret;
181 	  local = (bool_t (*)()) get_privs_2_svc;
182 	  break;
183 
184      case INIT:
185 	  xdr_argument = xdr_u_int32;
186 	  xdr_result = xdr_generic_ret;
187 	  local = (bool_t (*)()) init_2_svc;
188 	  break;
189 
190      case CREATE_PRINCIPAL3:
191 	  xdr_argument = xdr_cprinc3_arg;
192 	  xdr_result = xdr_generic_ret;
193 	  local = (bool_t (*)()) create_principal3_2_svc;
194 	  break;
195 
196      case CHPASS_PRINCIPAL3:
197 	  xdr_argument = xdr_chpass3_arg;
198 	  xdr_result = xdr_generic_ret;
199 	  local = (bool_t (*)()) chpass_principal3_2_svc;
200 	  break;
201 
202      case CHRAND_PRINCIPAL3:
203 	  xdr_argument = xdr_chrand3_arg;
204 	  xdr_result = xdr_chrand_ret;
205 	  local = (bool_t (*)()) chrand_principal3_2_svc;
206 	  break;
207 
208      case SETKEY_PRINCIPAL3:
209 	  xdr_argument = xdr_setkey3_arg;
210 	  xdr_result = xdr_generic_ret;
211 	  local = (bool_t (*)()) setkey_principal3_2_svc;
212 	  break;
213 
214      case PURGEKEYS:
215 	  xdr_argument = xdr_purgekeys_arg;
216 	  xdr_result = xdr_generic_ret;
217 	  local = (bool_t (*)()) purgekeys_2_svc;
218 	  break;
219 
220      case GET_STRINGS:
221 	  xdr_argument = xdr_gstrings_arg;
222 	  xdr_result = xdr_gstrings_ret;
223 	  local = (bool_t (*)()) get_strings_2_svc;
224 	  break;
225 
226      case SET_STRING:
227 	  xdr_argument = xdr_sstring_arg;
228 	  xdr_result = xdr_generic_ret;
229 	  local = (bool_t (*)()) set_string_2_svc;
230 	  break;
231 
232      case SETKEY_PRINCIPAL4:
233 	  xdr_argument = xdr_setkey4_arg;
234 	  xdr_result = xdr_generic_ret;
235 	  local = (bool_t (*)()) setkey_principal4_2_svc;
236 	  break;
237 
238      case EXTRACT_KEYS:
239 	  xdr_argument = xdr_getpkeys_arg;
240 	  xdr_result = xdr_getpkeys_ret;
241 	  local = (bool_t (*)()) get_principal_keys_2_svc;
242 	  break;
243 
244      default:
245 	  krb5_klog_syslog(LOG_ERR, "Invalid KADM5 procedure number: %s, %d",
246 			   client_addr(rqstp->rq_xprt), rqstp->rq_proc);
247 	  svcerr_noproc(transp);
248 	  return;
249      }
250      memset(&argument, 0, sizeof(argument));
251      if (!svc_getargs(transp, xdr_argument, &argument)) {
252 	  svcerr_decode(transp);
253 	  return;
254      }
255      memset(&result, 0, sizeof(result));
256      retval = (*local)(&argument, &result, rqstp);
257      if (retval && !svc_sendreply(transp, xdr_result, (void *)&result)) {
258 	  krb5_klog_syslog(LOG_ERR, "WARNING! Unable to send function results, "
259 		 "continuing.");
260 	  svcerr_systemerr(transp);
261      }
262      if (!svc_freeargs(transp, xdr_argument, &argument)) {
263 	  krb5_klog_syslog(LOG_ERR, "WARNING! Unable to free arguments, "
264 		 "continuing.");
265      }
266      if (!svc_freeargs(transp, xdr_result, &result)) {
267 	  krb5_klog_syslog(LOG_ERR, "WARNING! Unable to free results, "
268 		 "continuing.");
269      }
270      return;
271 }
272 
273 static int
check_rpcsec_auth(struct svc_req * rqstp)274 check_rpcsec_auth(struct svc_req *rqstp)
275 {
276      gss_ctx_id_t ctx;
277      krb5_context kctx;
278      OM_uint32 maj_stat, min_stat;
279      gss_name_t name;
280      krb5_principal princ;
281      int ret, success;
282      krb5_data *c1, *c2, *realm;
283      gss_buffer_desc gss_str;
284      kadm5_server_handle_t handle;
285      size_t slen;
286      char *sdots;
287 
288      success = 0;
289      handle = (kadm5_server_handle_t)global_server_handle;
290 
291      if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS)
292 	  return 0;
293 
294      ctx = rqstp->rq_svccred;
295 
296      maj_stat = gss_inquire_context(&min_stat, ctx, NULL, &name,
297 				    NULL, NULL, NULL, NULL, NULL);
298      if (maj_stat != GSS_S_COMPLETE) {
299 	  krb5_klog_syslog(LOG_ERR, _("check_rpcsec_auth: failed "
300 				      "inquire_context, stat=%u"), maj_stat);
301 	  log_badauth(maj_stat, min_stat, rqstp->rq_xprt, NULL);
302 	  goto fail_name;
303      }
304 
305      kctx = handle->context;
306      ret = gss_to_krb5_name_1(rqstp, kctx, name, &princ, &gss_str);
307      if (ret == 0)
308 	  goto fail_name;
309 
310      slen = gss_str.length;
311      trunc_name(&slen, &sdots);
312      /*
313       * Since we accept with GSS_C_NO_NAME, the client can authenticate
314       * against the entire kdb.  Therefore, ensure that the service
315       * name is something reasonable.
316       */
317      if (krb5_princ_size(kctx, princ) != 2)
318 	  goto fail_princ;
319 
320      c1 = krb5_princ_component(kctx, princ, 0);
321      c2 = krb5_princ_component(kctx, princ, 1);
322      realm = krb5_princ_realm(kctx, princ);
323      success = data_eq_string(*realm, handle->params.realm) &&
324 	     data_eq_string(*c1, "kadmin") && !data_eq_string(*c2, "history");
325 
326 fail_princ:
327      if (!success) {
328 	 krb5_klog_syslog(LOG_ERR, _("bad service principal %.*s%s"),
329 			  (int) slen, (char *) gss_str.value, sdots);
330      }
331      gss_release_buffer(&min_stat, &gss_str);
332      krb5_free_principal(kctx, princ);
333 fail_name:
334      gss_release_name(&min_stat, &name);
335      return success;
336 }
337 
338 int
gss_to_krb5_name_1(struct svc_req * rqstp,krb5_context ctx,gss_name_t gss_name,krb5_principal * princ,gss_buffer_t gss_str)339 gss_to_krb5_name_1(struct svc_req *rqstp, krb5_context ctx, gss_name_t gss_name,
340 		   krb5_principal *princ, gss_buffer_t gss_str)
341 {
342      OM_uint32 status, minor_stat;
343      gss_OID gss_type;
344      char *str;
345      int success;
346 
347      status = gss_display_name(&minor_stat, gss_name, gss_str, &gss_type);
348      if ((status != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name)) {
349 	  krb5_klog_syslog(LOG_ERR, _("gss_to_krb5_name: failed display_name "
350 				      "status %d"), status);
351 	  log_badauth(status, minor_stat, rqstp->rq_xprt, NULL);
352 	  return 0;
353      }
354      str = malloc(gss_str->length +1);
355      if (str == NULL)
356 	  return 0;
357      *str = '\0';
358 
359      strncat(str, gss_str->value, gss_str->length);
360      success = (krb5_parse_name(ctx, str, princ) == 0);
361      free(str);
362      return success;
363 }
364