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