2 * Copyright (c) 2005, PADL Software Pty Ltd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of PADL Software nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include "krb5_locl.h"
37 * Client library for Kerberos Credentials Manager (KCM) daemon
48 typedef struct krb5_kcmcache
{
50 struct sockaddr_un path
;
53 #define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data)
54 #define CACHENAME(X) (KCMCACHE(X)->name)
55 #define KCMCURSOR(C) (*(u_int32_t *)(C))
57 static krb5_error_code
58 kcm_send_request(krb5_context context
,
60 krb5_storage
*request
,
61 krb5_data
*response_data
)
64 krb5_data request_data
;
67 response_data
->data
= NULL
;
68 response_data
->length
= 0;
70 ret
= krb5_storage_to_data(request
, &request_data
);
77 for (i
= 0; i
< context
->max_retries
; i
++) {
80 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
84 if (connect(fd
, (struct sockaddr
*)&k
->path
, sizeof(k
->path
)) != 0) {
89 ret
= _krb5_send_and_recv_tcp(fd
, context
->kdc_timeout
,
90 &request_data
, response_data
);
92 if (ret
== 0 && response_data
->length
!= 0) {
97 krb5_data_free(&request_data
);
105 static krb5_error_code
106 kcm_storage_request(krb5_context context
,
107 kcm_operation opcode
,
108 krb5_storage
**storage_p
)
115 sp
= krb5_storage_emem();
117 krb5_set_error_string(context
, "malloc: out of memory");
118 return KRB5_CC_NOMEM
;
121 /* Send MAJOR | VERSION | OPCODE */
122 ret
= krb5_store_int8(sp
, KCM_PROTOCOL_VERSION_MAJOR
);
125 ret
= krb5_store_int8(sp
, KCM_PROTOCOL_VERSION_MINOR
);
128 ret
= krb5_store_int16(sp
, opcode
);
135 krb5_set_error_string(context
, "Failed to encode request");
136 krb5_storage_free(sp
);
142 static krb5_error_code
143 kcm_alloc(krb5_context context
, const char *name
, krb5_ccache
*id
)
147 k
= malloc(sizeof(*k
));
149 krb5_set_error_string(context
, "malloc: out of memory");
150 return KRB5_CC_NOMEM
;
154 k
->name
= strdup(name
);
155 if (k
->name
== NULL
) {
157 krb5_set_error_string(context
, "malloc: out of memory");
158 return KRB5_CC_NOMEM
;
163 k
->path
.sun_family
= AF_UNIX
;
164 strlcpy(k
->path
.sun_path
, _PATH_KCM_SOCKET
, sizeof(k
->path
.sun_path
));
166 (*id
)->data
.data
= k
;
167 (*id
)->data
.length
= sizeof(*k
);
172 static krb5_error_code
173 kcm_call(krb5_context context
,
175 krb5_storage
*request
,
176 krb5_storage
**response_p
,
177 krb5_data
*response_data_p
)
179 krb5_data response_data
;
180 krb5_error_code ret
, status
;
181 krb5_storage
*response
;
183 if (response_p
!= NULL
)
186 ret
= kcm_send_request(context
, k
, request
, &response_data
);
191 response
= krb5_storage_from_data(&response_data
);
192 if (response
== NULL
) {
193 krb5_data_free(&response_data
);
197 ret
= krb5_ret_int32(response
, &status
);
199 krb5_storage_free(response
);
200 krb5_data_free(&response_data
);
201 return KRB5_CC_FORMAT
;
205 krb5_storage_free(response
);
206 krb5_data_free(&response_data
);
210 if (response_p
!= NULL
) {
211 *response_data_p
= response_data
;
212 *response_p
= response
;
217 krb5_storage_free(response
);
218 krb5_data_free(&response_data
);
224 kcm_free(krb5_context context
, krb5_ccache
*id
)
226 krb5_kcmcache
*k
= KCMCACHE(*id
);
229 if (k
->name
!= NULL
) {
233 memset(k
, 0, sizeof(*k
));
234 krb5_data_free(&(*id
)->data
);
241 kcm_get_name(krb5_context context
,
244 return CACHENAME(id
);
247 static krb5_error_code
248 kcm_resolve(krb5_context context
, krb5_ccache
*id
, const char *res
)
250 return kcm_alloc(context
, res
, id
);
259 static krb5_error_code
260 kcm_gen_new(krb5_context context
, krb5_ccache
*id
)
264 krb5_storage
*request
, *response
;
265 krb5_data response_data
;
267 ret
= kcm_alloc(context
, NULL
, id
);
273 ret
= kcm_storage_request(context
, KCM_OP_GEN_NEW
, &request
);
275 kcm_free(context
, id
);
279 ret
= kcm_call(context
, k
, request
, &response
, &response_data
);
281 krb5_storage_free(request
);
282 kcm_free(context
, id
);
286 ret
= krb5_ret_stringz(response
, &k
->name
);
290 krb5_storage_free(request
);
291 krb5_storage_free(response
);
292 krb5_data_free(&response_data
);
295 kcm_free(context
, id
);
308 static krb5_error_code
309 kcm_initialize(krb5_context context
,
311 krb5_principal primary_principal
)
314 krb5_kcmcache
*k
= KCMCACHE(id
);
315 krb5_storage
*request
;
317 ret
= kcm_storage_request(context
, KCM_OP_INITIALIZE
, &request
);
321 ret
= krb5_store_stringz(request
, k
->name
);
323 krb5_storage_free(request
);
327 ret
= krb5_store_principal(request
, primary_principal
);
329 krb5_storage_free(request
);
333 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
335 krb5_storage_free(request
);
339 static krb5_error_code
340 kcm_close(krb5_context context
,
343 kcm_free(context
, &id
);
354 static krb5_error_code
355 kcm_destroy(krb5_context context
,
359 krb5_kcmcache
*k
= KCMCACHE(id
);
360 krb5_storage
*request
;
362 ret
= kcm_storage_request(context
, KCM_OP_DESTROY
, &request
);
366 ret
= krb5_store_stringz(request
, k
->name
);
368 krb5_storage_free(request
);
372 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
374 krb5_storage_free(request
);
386 static krb5_error_code
387 kcm_store_cred(krb5_context context
,
392 krb5_kcmcache
*k
= KCMCACHE(id
);
393 krb5_storage
*request
;
395 ret
= kcm_storage_request(context
, KCM_OP_STORE
, &request
);
399 ret
= krb5_store_stringz(request
, k
->name
);
401 krb5_storage_free(request
);
405 ret
= krb5_store_creds(request
, creds
);
407 krb5_storage_free(request
);
411 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
413 krb5_storage_free(request
);
427 static krb5_error_code
428 kcm_retrieve(krb5_context context
,
431 const krb5_creds
*mcred
,
435 krb5_kcmcache
*k
= KCMCACHE(id
);
436 krb5_storage
*request
, *response
;
437 krb5_data response_data
;
439 ret
= kcm_storage_request(context
, KCM_OP_RETRIEVE
, &request
);
443 ret
= krb5_store_stringz(request
, k
->name
);
445 krb5_storage_free(request
);
449 ret
= krb5_store_int32(request
, which
);
451 krb5_storage_free(request
);
455 ret
= krb5_store_creds_tag(request
, (krb5_creds
*)mcred
);
457 krb5_storage_free(request
);
461 ret
= kcm_call(context
, k
, request
, &response
, &response_data
);
463 krb5_storage_free(request
);
467 ret
= krb5_ret_creds(response
, creds
);
471 krb5_storage_free(request
);
472 krb5_storage_free(response
);
473 krb5_data_free(&response_data
);
485 static krb5_error_code
486 kcm_get_principal(krb5_context context
,
488 krb5_principal
*principal
)
491 krb5_kcmcache
*k
= KCMCACHE(id
);
492 krb5_storage
*request
, *response
;
493 krb5_data response_data
;
495 ret
= kcm_storage_request(context
, KCM_OP_GET_PRINCIPAL
, &request
);
499 ret
= krb5_store_stringz(request
, k
->name
);
501 krb5_storage_free(request
);
505 ret
= kcm_call(context
, k
, request
, &response
, &response_data
);
507 krb5_storage_free(request
);
511 ret
= krb5_ret_principal(response
, principal
);
515 krb5_storage_free(request
);
516 krb5_storage_free(response
);
517 krb5_data_free(&response_data
);
530 static krb5_error_code
531 kcm_get_first (krb5_context context
,
533 krb5_cc_cursor
*cursor
)
536 krb5_kcmcache
*k
= KCMCACHE(id
);
537 krb5_storage
*request
, *response
;
538 krb5_data response_data
;
541 ret
= kcm_storage_request(context
, KCM_OP_GET_FIRST
, &request
);
545 ret
= krb5_store_stringz(request
, k
->name
);
547 krb5_storage_free(request
);
551 ret
= kcm_call(context
, k
, request
, &response
, &response_data
);
553 krb5_storage_free(request
);
557 ret
= krb5_ret_int32(response
, &tmp
);
561 krb5_storage_free(request
);
562 krb5_storage_free(response
);
563 krb5_data_free(&response_data
);
568 *cursor
= malloc(sizeof(tmp
));
570 return KRB5_CC_NOMEM
;
572 KCMCURSOR(*cursor
) = tmp
;
585 static krb5_error_code
586 kcm_get_next (krb5_context context
,
588 krb5_cc_cursor
*cursor
,
592 krb5_kcmcache
*k
= KCMCACHE(id
);
593 krb5_storage
*request
, *response
;
594 krb5_data response_data
;
596 ret
= kcm_storage_request(context
, KCM_OP_GET_NEXT
, &request
);
600 ret
= krb5_store_stringz(request
, k
->name
);
602 krb5_storage_free(request
);
606 ret
= krb5_store_int32(request
, KCMCURSOR(*cursor
));
608 krb5_storage_free(request
);
612 ret
= kcm_call(context
, k
, request
, &response
, &response_data
);
614 krb5_storage_free(request
);
618 ret
= krb5_ret_creds(response
, creds
);
622 krb5_storage_free(request
);
623 krb5_storage_free(response
);
624 krb5_data_free(&response_data
);
637 static krb5_error_code
638 kcm_end_get (krb5_context context
,
640 krb5_cc_cursor
*cursor
)
643 krb5_kcmcache
*k
= KCMCACHE(id
);
644 krb5_storage
*request
;
646 ret
= kcm_storage_request(context
, KCM_OP_END_GET
, &request
);
650 ret
= krb5_store_stringz(request
, k
->name
);
652 krb5_storage_free(request
);
656 ret
= krb5_store_int32(request
, KCMCURSOR(*cursor
));
658 krb5_storage_free(request
);
662 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
664 krb5_storage_free(request
);
668 krb5_storage_free(request
);
670 KCMCURSOR(*cursor
) = 0;
686 static krb5_error_code
687 kcm_remove_cred(krb5_context context
,
693 krb5_kcmcache
*k
= KCMCACHE(id
);
694 krb5_storage
*request
;
696 ret
= kcm_storage_request(context
, KCM_OP_REMOVE_CRED
, &request
);
700 ret
= krb5_store_stringz(request
, k
->name
);
702 krb5_storage_free(request
);
706 ret
= krb5_store_int32(request
, which
);
708 krb5_storage_free(request
);
712 ret
= krb5_store_creds_tag(request
, cred
);
714 krb5_storage_free(request
);
718 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
720 krb5_storage_free(request
);
724 static krb5_error_code
725 kcm_set_flags(krb5_context context
,
730 krb5_kcmcache
*k
= KCMCACHE(id
);
731 krb5_storage
*request
;
733 ret
= kcm_storage_request(context
, KCM_OP_SET_FLAGS
, &request
);
737 ret
= krb5_store_stringz(request
, k
->name
);
739 krb5_storage_free(request
);
743 ret
= krb5_store_int32(request
, flags
);
745 krb5_storage_free(request
);
749 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
751 krb5_storage_free(request
);
755 static krb5_error_code
756 kcm_get_version(krb5_context context
,
762 const krb5_cc_ops krb5_kcm_ops
= {
782 _krb5_kcm_is_running(krb5_context context
)
785 krb5_ccache_data ccdata
;
786 krb5_ccache id
= &ccdata
;
787 krb5_boolean running
;
789 ret
= kcm_alloc(context
, NULL
, &id
);
793 running
= (_krb5_kcm_noop(context
, id
) == 0);
795 kcm_free(context
, &id
);
807 _krb5_kcm_noop(krb5_context context
,
811 krb5_kcmcache
*k
= KCMCACHE(id
);
812 krb5_storage
*request
;
814 ret
= kcm_storage_request(context
, KCM_OP_NOOP
, &request
);
818 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
820 krb5_storage_free(request
);
834 _krb5_kcm_chmod(krb5_context context
,
839 krb5_kcmcache
*k
= KCMCACHE(id
);
840 krb5_storage
*request
;
842 ret
= kcm_storage_request(context
, KCM_OP_CHMOD
, &request
);
846 ret
= krb5_store_stringz(request
, k
->name
);
848 krb5_storage_free(request
);
852 ret
= krb5_store_int16(request
, mode
);
854 krb5_storage_free(request
);
858 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
860 krb5_storage_free(request
);
875 _krb5_kcm_chown(krb5_context context
,
881 krb5_kcmcache
*k
= KCMCACHE(id
);
882 krb5_storage
*request
;
884 ret
= kcm_storage_request(context
, KCM_OP_CHOWN
, &request
);
888 ret
= krb5_store_stringz(request
, k
->name
);
890 krb5_storage_free(request
);
894 ret
= krb5_store_int32(request
, uid
);
896 krb5_storage_free(request
);
900 ret
= krb5_store_int32(request
, gid
);
902 krb5_storage_free(request
);
906 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
908 krb5_storage_free(request
);
916 * ServerPrincipalPresent
917 * ServerPrincipal OPTIONAL
924 _krb5_kcm_get_initial_ticket(krb5_context context
,
926 krb5_principal server
,
930 krb5_kcmcache
*k
= KCMCACHE(id
);
931 krb5_storage
*request
;
933 ret
= kcm_storage_request(context
, KCM_OP_GET_INITIAL_TICKET
, &request
);
937 ret
= krb5_store_stringz(request
, k
->name
);
939 krb5_storage_free(request
);
943 ret
= krb5_store_int8(request
, (server
== NULL
) ? 0 : 1);
945 krb5_storage_free(request
);
949 if (server
!= NULL
) {
950 ret
= krb5_store_principal(request
, server
);
952 krb5_storage_free(request
);
957 ret
= krb5_store_keyblock(request
, *key
);
959 krb5_storage_free(request
);
963 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
965 krb5_storage_free(request
);
981 _krb5_kcm_get_ticket(krb5_context context
,
983 krb5_kdc_flags flags
,
984 krb5_enctype enctype
,
985 krb5_principal server
)
988 krb5_kcmcache
*k
= KCMCACHE(id
);
989 krb5_storage
*request
;
991 ret
= kcm_storage_request(context
, KCM_OP_GET_TICKET
, &request
);
995 ret
= krb5_store_stringz(request
, k
->name
);
997 krb5_storage_free(request
);
1001 ret
= krb5_store_int32(request
, flags
.i
);
1003 krb5_storage_free(request
);
1007 ret
= krb5_store_int32(request
, enctype
);
1009 krb5_storage_free(request
);
1013 ret
= krb5_store_principal(request
, server
);
1015 krb5_storage_free(request
);
1019 ret
= kcm_call(context
, k
, request
, NULL
, NULL
);
1021 krb5_storage_free(request
);
1026 #endif /* HAVE_KCM */