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