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 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 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 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