1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
4 */
5
6 /*
7 * Copyright (C) 1998 by the FundsXpress, INC.
8 *
9 * All rights reserved.
10 *
11 * Export of this software from the United States of America may require
12 * a specific license from the United States Government. It is the
13 * responsibility of any person or organization contemplating export to
14 * obtain such a license before exporting.
15 *
16 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
17 * distribute this software and its documentation for any purpose and
18 * without fee is hereby granted, provided that the above copyright
19 * notice appear in all copies and that both that copyright notice and
20 * this permission notice appear in supporting documentation, and that
21 * the name of FundsXpress. not be used in advertising or publicity pertaining
22 * to distribution of the software without specific, written prior
23 * permission. FundsXpress makes no representations about the suitability of
24 * this software for any purpose. It is provided "as is" without express
25 * or implied warranty.
26 *
27 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
29 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 */
31
32 #include <k5-int.h>
33 #include <netdb.h>
34 #include <com_err.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <fake-addrinfo.h>
39 #include <krb5.h>
40
41 #include <kadm5/admin.h>
42 #include <kadm5/kadm_rpc.h>
43 #include "client_internal.h"
44 #include <iprop_hdr.h>
45 #include "iprop.h"
46
47 #include <gssrpc/rpc.h>
48 #include <gssapi/gssapi.h>
49 #include <gssapi/gssapi_krb5.h>
50 #include <gssrpc/auth_gssapi.h>
51
52 #define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX"
53
54 enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS, INIT_ANONYMOUS };
55
56 static kadm5_ret_t
57 init_any(krb5_context context, char *client_name, enum init_type init_type,
58 char *pass, krb5_ccache ccache_in, char *service_name,
59 kadm5_config_params *params, krb5_ui_4 struct_version,
60 krb5_ui_4 api_version, char **db_args, void **server_handle);
61
62 static kadm5_ret_t
63 get_init_creds(kadm5_server_handle_t handle, krb5_principal client,
64 enum init_type init_type, char *pass, krb5_ccache ccache_in,
65 char *svcname_in, char *realm, krb5_principal *server_out);
66
67 static kadm5_ret_t
68 gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
69 krb5_ccache ccache, krb5_principal client, char *pass,
70 char *svcname, char *realm, krb5_principal *server_out);
71
72 static kadm5_ret_t
73 connect_to_server(const char *hostname, int port, int *fd);
74
75 static kadm5_ret_t
76 setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
77 krb5_principal client, krb5_principal server);
78
79 static void
80 rpc_auth(kadm5_server_handle_t handle, kadm5_config_params *params_in,
81 gss_cred_id_t gss_client_creds, gss_name_t gss_target);
82
83 kadm5_ret_t
kadm5_init_with_creds(krb5_context context,char * client_name,krb5_ccache ccache,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)84 kadm5_init_with_creds(krb5_context context, char *client_name,
85 krb5_ccache ccache, char *service_name,
86 kadm5_config_params *params, krb5_ui_4 struct_version,
87 krb5_ui_4 api_version, char **db_args,
88 void **server_handle)
89 {
90 return init_any(context, client_name, INIT_CREDS, NULL, ccache,
91 service_name, params, struct_version, api_version, db_args,
92 server_handle);
93 }
94
95 kadm5_ret_t
kadm5_init_with_password(krb5_context context,char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)96 kadm5_init_with_password(krb5_context context, char *client_name,
97 char *pass, char *service_name,
98 kadm5_config_params *params, krb5_ui_4 struct_version,
99 krb5_ui_4 api_version, char **db_args,
100 void **server_handle)
101 {
102 return init_any(context, client_name, INIT_PASS, pass, NULL, service_name,
103 params, struct_version, api_version, db_args,
104 server_handle);
105 }
106
107 kadm5_ret_t
kadm5_init_anonymous(krb5_context context,char * client_name,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)108 kadm5_init_anonymous(krb5_context context, char *client_name,
109 char *service_name, kadm5_config_params *params,
110 krb5_ui_4 struct_version, krb5_ui_4 api_version,
111 char **db_args, void **server_handle)
112 {
113 return init_any(context, client_name, INIT_ANONYMOUS, NULL, NULL,
114 service_name, params, struct_version, api_version,
115 db_args, server_handle);
116 }
117
118 kadm5_ret_t
kadm5_init(krb5_context context,char * client_name,char * pass,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)119 kadm5_init(krb5_context context, char *client_name, char *pass,
120 char *service_name, kadm5_config_params *params,
121 krb5_ui_4 struct_version, krb5_ui_4 api_version, char **db_args,
122 void **server_handle)
123 {
124 return init_any(context, client_name, INIT_PASS, pass, NULL, service_name,
125 params, struct_version, api_version, db_args,
126 server_handle);
127 }
128
129 kadm5_ret_t
kadm5_init_with_skey(krb5_context context,char * client_name,char * keytab,char * service_name,kadm5_config_params * params,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)130 kadm5_init_with_skey(krb5_context context, char *client_name,
131 char *keytab, char *service_name,
132 kadm5_config_params *params, krb5_ui_4 struct_version,
133 krb5_ui_4 api_version, char **db_args,
134 void **server_handle)
135 {
136 return init_any(context, client_name, INIT_SKEY, keytab, NULL,
137 service_name, params, struct_version, api_version, db_args,
138 server_handle);
139 }
140
141 static kadm5_ret_t
init_any(krb5_context context,char * client_name,enum init_type init_type,char * pass,krb5_ccache ccache_in,char * service_name,kadm5_config_params * params_in,krb5_ui_4 struct_version,krb5_ui_4 api_version,char ** db_args,void ** server_handle)142 init_any(krb5_context context, char *client_name, enum init_type init_type,
143 char *pass, krb5_ccache ccache_in, char *service_name,
144 kadm5_config_params *params_in, krb5_ui_4 struct_version,
145 krb5_ui_4 api_version, char **db_args, void **server_handle)
146 {
147 int fd = -1;
148 OM_uint32 minor_stat;
149 krb5_boolean iprop_enable;
150 int port;
151 rpcprog_t rpc_prog;
152 rpcvers_t rpc_vers;
153 krb5_ccache ccache;
154 krb5_principal client = NULL, server = NULL;
155 struct timeval timeout;
156
157 kadm5_server_handle_t handle;
158 kadm5_config_params params_local;
159
160 int code = 0;
161 generic_ret r = { 0, 0 };
162
163 initialize_ovk_error_table();
164 initialize_ovku_error_table();
165
166 if (! server_handle) {
167 return EINVAL;
168 }
169
170 if (! (handle = malloc(sizeof(*handle)))) {
171 return ENOMEM;
172 }
173 memset(handle, 0, sizeof(*handle));
174 if (! (handle->lhandle = malloc(sizeof(*handle)))) {
175 free(handle);
176 return ENOMEM;
177 }
178
179 handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
180 handle->struct_version = struct_version;
181 handle->api_version = api_version;
182 handle->clnt = 0;
183 handle->client_socket = -1;
184 handle->cache_name = 0;
185 handle->destroy_cache = 0;
186 handle->context = 0;
187 handle->cred = GSS_C_NO_CREDENTIAL;
188 *handle->lhandle = *handle;
189 handle->lhandle->api_version = KADM5_API_VERSION_4;
190 handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
191 handle->lhandle->lhandle = handle->lhandle;
192
193 handle->context = context;
194
195 if(client_name == NULL) {
196 free(handle);
197 return EINVAL;
198 }
199
200 /*
201 * Verify the version numbers before proceeding; we can't use
202 * CHECK_HANDLE because not all fields are set yet.
203 */
204 GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION,
205 KADM5_NEW_LIB_API_VERSION);
206
207 memset(¶ms_local, 0, sizeof(params_local));
208
209 if ((code = kadm5_get_config_params(handle->context, 0,
210 params_in, &handle->params))) {
211 free(handle);
212 return(code);
213 }
214
215 #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \
216 KADM5_CONFIG_ADMIN_SERVER | \
217 KADM5_CONFIG_KADMIND_PORT)
218
219 if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
220 free(handle);
221 return KADM5_MISSING_KRB5_CONF_PARAMS;
222 }
223
224 code = krb5_parse_name(handle->context, client_name, &client);
225 if (code)
226 goto error;
227
228 /*
229 * Get credentials. Also does some fallbacks in case kadmin/fqdn
230 * principal doesn't exist.
231 */
232 code = get_init_creds(handle, client, init_type, pass, ccache_in,
233 service_name, handle->params.realm, &server);
234 if (code)
235 goto error;
236
237 /* If the service_name and client_name are iprop-centric, use the iprop
238 * port and RPC identifiers. */
239 iprop_enable = (service_name != NULL &&
240 strstr(service_name, KIPROP_SVC_NAME) != NULL &&
241 strstr(client_name, KIPROP_SVC_NAME) != NULL);
242 if (iprop_enable) {
243 port = handle->params.iprop_port;
244 rpc_prog = KRB5_IPROP_PROG;
245 rpc_vers = KRB5_IPROP_VERS;
246 } else {
247 port = handle->params.kadmind_port;
248 rpc_prog = KADM;
249 rpc_vers = KADMVERS;
250 }
251
252 code = connect_to_server(handle->params.admin_server, port, &fd);
253 if (code)
254 goto error;
255
256 handle->clnt = clnttcp_create(NULL, rpc_prog, rpc_vers, &fd, 0, 0);
257 if (handle->clnt == NULL) {
258 code = KADM5_RPC_ERROR;
259 #ifdef DEBUG
260 clnt_pcreateerror("clnttcp_create");
261 #endif
262 goto error;
263 }
264
265 /* Set a one-hour timeout. */
266 timeout.tv_sec = 3600;
267 timeout.tv_usec = 0;
268 (void)clnt_control(handle->clnt, CLSET_TIMEOUT, &timeout);
269
270 handle->client_socket = fd;
271 handle->lhandle->clnt = handle->clnt;
272 handle->lhandle->client_socket = fd;
273
274 /* now that handle->clnt is set, we can check the handle */
275 if ((code = _kadm5_check_handle((void *) handle)))
276 goto error;
277
278 /*
279 * The RPC connection is open; establish the GSS-API
280 * authentication context.
281 */
282 code = setup_gss(handle, params_in,
283 (init_type == INIT_CREDS) ? client : NULL, server);
284 if (code)
285 goto error;
286
287 /*
288 * Bypass the remainder of the code and return straight away
289 * if the gss service requested is kiprop
290 */
291 if (iprop_enable) {
292 code = 0;
293 *server_handle = (void *) handle;
294 goto cleanup;
295 }
296
297 if (init_2(&handle->api_version, &r, handle->clnt)) {
298 code = KADM5_RPC_ERROR;
299 #ifdef DEBUG
300 clnt_perror(handle->clnt, "init_2 null resp");
301 #endif
302 goto error;
303 }
304 /* Drop down to v3 wire protocol if server does not support v4 */
305 if (r.code == KADM5_NEW_SERVER_API_VERSION &&
306 handle->api_version == KADM5_API_VERSION_4) {
307 handle->api_version = KADM5_API_VERSION_3;
308 memset(&r, 0, sizeof(generic_ret));
309 if (init_2(&handle->api_version, &r, handle->clnt)) {
310 code = KADM5_RPC_ERROR;
311 goto error;
312 }
313 }
314 /* Drop down to v2 wire protocol if server does not support v3 */
315 if (r.code == KADM5_NEW_SERVER_API_VERSION &&
316 handle->api_version == KADM5_API_VERSION_3) {
317 handle->api_version = KADM5_API_VERSION_2;
318 memset(&r, 0, sizeof(generic_ret));
319 if (init_2(&handle->api_version, &r, handle->clnt)) {
320 code = KADM5_RPC_ERROR;
321 goto error;
322 }
323 }
324 if (r.code) {
325 code = r.code;
326 goto error;
327 }
328
329 *server_handle = (void *) handle;
330
331 goto cleanup;
332
333 error:
334 /*
335 * Note that it is illegal for this code to execute if "handle"
336 * has not been allocated and initialized. I.e., don't use "goto
337 * error" before the block of code at the top of the function
338 * that allocates and initializes "handle".
339 */
340 if (handle->destroy_cache && handle->cache_name) {
341 if (krb5_cc_resolve(handle->context,
342 handle->cache_name, &ccache) == 0)
343 (void) krb5_cc_destroy (handle->context, ccache);
344 }
345 if (handle->cache_name)
346 free(handle->cache_name);
347 (void)gss_release_cred(&minor_stat, &handle->cred);
348 if(handle->clnt && handle->clnt->cl_auth)
349 AUTH_DESTROY(handle->clnt->cl_auth);
350 if(handle->clnt)
351 clnt_destroy(handle->clnt);
352 if (fd != -1)
353 close(fd);
354 free(handle->lhandle);
355 kadm5_free_config_params(handle->context, &handle->params);
356
357 cleanup:
358 krb5_free_principal(handle->context, client);
359 krb5_free_principal(handle->context, server);
360 if (code)
361 free(handle);
362
363 return code;
364 }
365
366 /* Get initial credentials for authenticating to server. Perform fallback from
367 * kadmin/fqdn to kadmin/admin if svcname_in is NULL. */
368 static kadm5_ret_t
get_init_creds(kadm5_server_handle_t handle,krb5_principal client,enum init_type init_type,char * pass,krb5_ccache ccache_in,char * svcname_in,char * realm,krb5_principal * server_out)369 get_init_creds(kadm5_server_handle_t handle, krb5_principal client,
370 enum init_type init_type, char *pass, krb5_ccache ccache_in,
371 char *svcname_in, char *realm, krb5_principal *server_out)
372 {
373 kadm5_ret_t code;
374 krb5_ccache ccache = NULL;
375 char *svcname, svcbuf[BUFSIZ];
376
377 *server_out = NULL;
378
379 /*
380 * Acquire a service ticket for svcname@realm for client, using password
381 * pass (which could be NULL), and create a ccache to store them in. If
382 * INIT_CREDS, use the ccache we were provided instead.
383 */
384 if (init_type == INIT_CREDS) {
385 ccache = ccache_in;
386 if (asprintf(&handle->cache_name, "%s:%s",
387 krb5_cc_get_type(handle->context, ccache),
388 krb5_cc_get_name(handle->context, ccache)) < 0) {
389 handle->cache_name = NULL;
390 code = ENOMEM;
391 goto error;
392 }
393 } else {
394 static int counter = 0;
395
396 if (asprintf(&handle->cache_name, "MEMORY:kadm5_%u", counter++) < 0) {
397 handle->cache_name = NULL;
398 code = ENOMEM;
399 goto error;
400 }
401 code = krb5_cc_resolve(handle->context, handle->cache_name,
402 &ccache);
403 if (code)
404 goto error;
405
406 code = krb5_cc_initialize (handle->context, ccache, client);
407 if (code)
408 goto error;
409
410 handle->destroy_cache = 1;
411 }
412 handle->lhandle->cache_name = handle->cache_name;
413
414 svcname = (svcname_in != NULL) ? svcname_in : KADM5_ADMIN_SERVICE;
415 code = gic_iter(handle, init_type, ccache, client, pass, svcname, realm,
416 server_out);
417 if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
418 || code == KRB5_CC_NOTFOUND) && svcname_in == NULL) {
419 /* Retry with host-based service principal. */
420 code = kadm5_get_admin_service_name(handle->context,
421 handle->params.realm,
422 svcbuf, sizeof(svcbuf));
423 if (code)
424 goto error;
425 code = gic_iter(handle, init_type, ccache, client, pass, svcbuf, realm,
426 server_out);
427 }
428 /* Improved error messages */
429 if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD;
430 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN)
431 code = KADM5_SECURE_PRINC_MISSING;
432
433 error:
434 if (ccache != NULL && init_type != INIT_CREDS)
435 krb5_cc_close(handle->context, ccache);
436 return code;
437 }
438
439 /* Perform one iteration of attempting to get credentials. This includes
440 * searching existing ccache for requested service if INIT_CREDS. */
441 static kadm5_ret_t
gic_iter(kadm5_server_handle_t handle,enum init_type init_type,krb5_ccache ccache,krb5_principal client,char * pass,char * svcname,char * realm,krb5_principal * server_out)442 gic_iter(kadm5_server_handle_t handle, enum init_type init_type,
443 krb5_ccache ccache, krb5_principal client, char *pass, char *svcname,
444 char *realm, krb5_principal *server_out)
445 {
446 kadm5_ret_t code;
447 krb5_context ctx;
448 krb5_keytab kt;
449 krb5_get_init_creds_opt *opt = NULL;
450 krb5_creds mcreds, outcreds;
451
452 *server_out = NULL;
453 ctx = handle->context;
454 kt = NULL;
455 memset(&opt, 0, sizeof(opt));
456 memset(&mcreds, 0, sizeof(mcreds));
457 memset(&outcreds, 0, sizeof(outcreds));
458
459 /* Credentials for kadmin don't need to be forwardable or proxiable. */
460 if (init_type != INIT_CREDS) {
461 code = krb5_get_init_creds_opt_alloc(ctx, &opt);
462 if (code)
463 goto error;
464
465 krb5_get_init_creds_opt_set_forwardable(opt, 0);
466 krb5_get_init_creds_opt_set_proxiable(opt, 0);
467 krb5_get_init_creds_opt_set_out_ccache(ctx, opt, ccache);
468 if (init_type == INIT_ANONYMOUS)
469 krb5_get_init_creds_opt_set_anonymous(opt, 1);
470 }
471
472 if (init_type == INIT_PASS || init_type == INIT_ANONYMOUS) {
473 code = krb5_get_init_creds_password(ctx, &outcreds, client, pass,
474 krb5_prompter_posix,
475 NULL, 0, svcname, opt);
476 if (code)
477 goto error;
478 } else if (init_type == INIT_SKEY) {
479 if (pass) {
480 code = krb5_kt_resolve(ctx, pass, &kt);
481 if (code)
482 goto error;
483 }
484 code = krb5_get_init_creds_keytab(ctx, &outcreds, client, kt,
485 0, svcname, opt);
486 if (pass)
487 krb5_kt_close(ctx, kt);
488 if (code)
489 goto error;
490 } else if (init_type == INIT_CREDS) {
491 mcreds.client = client;
492 code = krb5_parse_name_flags(ctx, svcname,
493 KRB5_PRINCIPAL_PARSE_IGNORE_REALM,
494 &mcreds.server);
495 if (code)
496 goto error;
497 code = krb5_set_principal_realm(ctx, mcreds.server, realm);
498 if (code)
499 goto error;
500 code = krb5_cc_retrieve_cred(ctx, ccache, 0,
501 &mcreds, &outcreds);
502 krb5_free_principal(ctx, mcreds.server);
503 if (code)
504 goto error;
505 } else {
506 code = EINVAL;
507 goto error;
508 }
509
510 /* Steal the server principal of the creds we acquired and return it to the
511 * caller, which needs to knows what service to authenticate to. */
512 *server_out = outcreds.server;
513 outcreds.server = NULL;
514
515 error:
516 krb5_free_cred_contents(ctx, &outcreds);
517 if (opt)
518 krb5_get_init_creds_opt_free(ctx, opt);
519 return code;
520 }
521
522 /* Set *fd to a socket connected to hostname and port. */
523 static kadm5_ret_t
connect_to_server(const char * hostname,int port,int * fd)524 connect_to_server(const char *hostname, int port, int *fd)
525 {
526 struct addrinfo hint, *addrs, *a;
527 char portbuf[32];
528 int err, s;
529 kadm5_ret_t code;
530
531 /* Look up the server's addresses. */
532 (void) snprintf(portbuf, sizeof(portbuf), "%d", port);
533 memset(&hint, 0, sizeof(hint));
534 hint.ai_socktype = SOCK_STREAM;
535 hint.ai_flags = AI_ADDRCONFIG;
536 #ifdef AI_NUMERICSERV
537 hint.ai_flags |= AI_NUMERICSERV;
538 #endif
539 err = getaddrinfo(hostname, portbuf, &hint, &addrs);
540 if (err != 0)
541 return KADM5_CANT_RESOLVE;
542
543 /* Try to connect to each address until we succeed. */
544 for (a = addrs; a != NULL; a = a->ai_next) {
545 s = socket(a->ai_family, a->ai_socktype, 0);
546 if (s == -1) {
547 code = KADM5_FAILURE;
548 goto cleanup;
549 }
550 err = connect(s, a->ai_addr, a->ai_addrlen);
551 if (err == 0) {
552 *fd = s;
553 code = 0;
554 goto cleanup;
555 }
556 close(s);
557 }
558
559 /* We didn't succeed on any address. */
560 code = KADM5_RPC_ERROR;
561 cleanup:
562 freeaddrinfo(addrs);
563 return code;
564 }
565
566 /* Acquire GSSAPI credentials and set up RPC auth flavor. */
567 static kadm5_ret_t
setup_gss(kadm5_server_handle_t handle,kadm5_config_params * params_in,krb5_principal client,krb5_principal server)568 setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
569 krb5_principal client, krb5_principal server)
570 {
571 OM_uint32 gssstat, minor_stat;
572 gss_buffer_desc buf;
573 gss_name_t gss_client;
574 gss_name_t gss_target;
575 const char *c_ccname_orig;
576 char *ccname_orig;
577
578 ccname_orig = NULL;
579 gss_client = gss_target = GSS_C_NO_NAME;
580
581 /* Temporarily use the kadm5 cache. */
582 gssstat = gss_krb5_ccache_name(&minor_stat, handle->cache_name,
583 &c_ccname_orig);
584 if (gssstat != GSS_S_COMPLETE)
585 goto error;
586 if (c_ccname_orig)
587 ccname_orig = strdup(c_ccname_orig);
588 else
589 ccname_orig = 0;
590
591 buf.value = &server;
592 buf.length = sizeof(server);
593 gssstat = gss_import_name(&minor_stat, &buf,
594 (gss_OID)gss_nt_krb5_principal, &gss_target);
595 if (gssstat != GSS_S_COMPLETE)
596 goto error;
597
598 if (client != NULL) {
599 buf.value = &client;
600 buf.length = sizeof(client);
601 gssstat = gss_import_name(&minor_stat, &buf,
602 (gss_OID)gss_nt_krb5_principal, &gss_client);
603 } else gss_client = GSS_C_NO_NAME;
604
605 if (gssstat != GSS_S_COMPLETE)
606 goto error;
607
608 gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
609 GSS_C_NULL_OID_SET, GSS_C_INITIATE,
610 &handle->cred, NULL, NULL);
611 if (gssstat != GSS_S_COMPLETE)
612 goto error;
613
614 /*
615 * Do actual creation of RPC auth handle. Implements auth flavor
616 * fallback.
617 */
618 rpc_auth(handle, params_in, handle->cred, gss_target);
619
620 error:
621 if (gss_client)
622 gss_release_name(&minor_stat, &gss_client);
623 if (gss_target)
624 gss_release_name(&minor_stat, &gss_target);
625
626 /* Revert to prior gss_krb5 ccache. */
627 if (ccname_orig) {
628 gssstat = gss_krb5_ccache_name(&minor_stat, ccname_orig, NULL);
629 if (gssstat) {
630 return KADM5_GSS_ERROR;
631 }
632 free(ccname_orig);
633 } else {
634 gssstat = gss_krb5_ccache_name(&minor_stat, NULL, NULL);
635 if (gssstat) {
636 return KADM5_GSS_ERROR;
637 }
638 }
639
640 if (handle->clnt->cl_auth == NULL) {
641 return KADM5_GSS_ERROR;
642 }
643 return 0;
644 }
645
646 /* Create RPC auth handle. Do auth flavor fallback if needed. */
647 static void
rpc_auth(kadm5_server_handle_t handle,kadm5_config_params * params_in,gss_cred_id_t gss_client_creds,gss_name_t gss_target)648 rpc_auth(kadm5_server_handle_t handle, kadm5_config_params *params_in,
649 gss_cred_id_t gss_client_creds, gss_name_t gss_target)
650 {
651 OM_uint32 gssstat, minor_stat;
652 struct rpc_gss_sec sec;
653
654 /* Allow unauthenticated option for testing. */
655 if (params_in != NULL && (params_in->mask & KADM5_CONFIG_NO_AUTH))
656 return;
657
658 /* Use RPCSEC_GSS by default. */
659 if (params_in == NULL ||
660 !(params_in->mask & KADM5_CONFIG_OLD_AUTH_GSSAPI)) {
661 sec.mech = (gss_OID)gss_mech_krb5;
662 sec.qop = GSS_C_QOP_DEFAULT;
663 sec.svc = RPCSEC_GSS_SVC_PRIVACY;
664 sec.cred = gss_client_creds;
665 sec.req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
666
667 handle->clnt->cl_auth = authgss_create(handle->clnt,
668 gss_target, &sec);
669 if (handle->clnt->cl_auth != NULL)
670 return;
671 }
672
673 if (params_in != NULL && (params_in->mask & KADM5_CONFIG_AUTH_NOFALLBACK))
674 return;
675
676 /* Fall back to old AUTH_GSSAPI. */
677 handle->clnt->cl_auth = auth_gssapi_create(handle->clnt,
678 &gssstat,
679 &minor_stat,
680 gss_client_creds,
681 gss_target,
682 (gss_OID) gss_mech_krb5,
683 GSS_C_MUTUAL_FLAG
684 | GSS_C_REPLAY_FLAG,
685 0, NULL, NULL, NULL);
686 }
687
688 kadm5_ret_t
kadm5_destroy(void * server_handle)689 kadm5_destroy(void *server_handle)
690 {
691 OM_uint32 minor_stat;
692 krb5_ccache ccache = NULL;
693 int code = KADM5_OK;
694 kadm5_server_handle_t handle =
695 (kadm5_server_handle_t) server_handle;
696
697 CHECK_HANDLE(server_handle);
698
699 if (handle->destroy_cache && handle->cache_name) {
700 if ((code = krb5_cc_resolve(handle->context,
701 handle->cache_name, &ccache)) == 0)
702 code = krb5_cc_destroy (handle->context, ccache);
703 }
704 if (handle->cache_name)
705 free(handle->cache_name);
706 if (handle->cred)
707 (void)gss_release_cred(&minor_stat, &handle->cred);
708 if (handle->clnt && handle->clnt->cl_auth)
709 AUTH_DESTROY(handle->clnt->cl_auth);
710 if (handle->clnt)
711 clnt_destroy(handle->clnt);
712 if (handle->client_socket != -1)
713 close(handle->client_socket);
714 if (handle->lhandle)
715 free (handle->lhandle);
716
717 kadm5_free_config_params(handle->context, &handle->params);
718
719 handle->magic_number = 0;
720 free(handle);
721
722 return code;
723 }
724 /* not supported on client */
kadm5_lock(void * server_handle)725 kadm5_ret_t kadm5_lock(void *server_handle)
726 {
727 return EINVAL;
728 }
729
730 /* not supported on client */
kadm5_unlock(void * server_handle)731 kadm5_ret_t kadm5_unlock(void *server_handle)
732 {
733 return EINVAL;
734 }
735
kadm5_flush(void * server_handle)736 kadm5_ret_t kadm5_flush(void *server_handle)
737 {
738 return KADM5_OK;
739 }
740
_kadm5_check_handle(void * handle)741 int _kadm5_check_handle(void *handle)
742 {
743 CHECK_HANDLE(handle);
744 return 0;
745 }
746
kadm5_init_krb5_context(krb5_context * ctx)747 krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
748 {
749 return krb5_init_context(ctx);
750 }
751
752 /*
753 * Stub function for kadmin. It was created to eliminate the dependency on
754 * libkdb's ulog functions. The srv equivalent makes the actual calls.
755 */
756 krb5_error_code
kadm5_init_iprop(void * handle,char ** db_args)757 kadm5_init_iprop(void *handle, char **db_args)
758 {
759 return (0);
760 }
761