xref: /freebsd/contrib/pam-krb5/portable/krb5-extra.c (revision ee3960cba1068e12fb032a68c46d74841d9edab3)
1 /*
2  * Portability glue functions for Kerberos.
3  *
4  * This file provides definitions of the interfaces that portable/krb5.h
5  * ensures exist if the function wasn't available in the Kerberos libraries.
6  * Everything in this file will be protected by #ifndef.  If the native
7  * Kerberos libraries are fully capable, this file will be skipped.
8  *
9  * The canonical version of this file is maintained in the rra-c-util package,
10  * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
11  *
12  * Written by Russ Allbery <eagle@eyrie.org>
13  * Copyright 2015-2016, 2018 Russ Allbery <eagle@eyrie.org>
14  * Copyright 2010-2012, 2014
15  *     The Board of Trustees of the Leland Stanford Junior University
16  *
17  * Copying and distribution of this file, with or without modification, are
18  * permitted in any medium without royalty provided the copyright notice and
19  * this notice are preserved.  This file is offered as-is, without any
20  * warranty.
21  *
22  * SPDX-License-Identifier: FSFAP
23  */
24 
25 #include <config.h>
26 #include <portable/krb5.h>
27 #include <portable/macros.h>
28 #include <portable/system.h>
29 
30 #include <errno.h>
31 
32 /* Figure out what header files to include for error reporting. */
33 #if !defined(HAVE_KRB5_GET_ERROR_MESSAGE) && !defined(HAVE_KRB5_GET_ERR_TEXT)
34 #    if !defined(HAVE_KRB5_GET_ERROR_STRING)
35 #        if defined(HAVE_IBM_SVC_KRB5_SVC_H)
36 #            include <ibm_svc/krb5_svc.h>
37 #        elif defined(HAVE_ET_COM_ERR_H)
38 #            include <et/com_err.h>
39 #        elif defined(HAVE_KERBEROSV5_COM_ERR_H)
40 #            include <kerberosv5/com_err.h>
41 #        else
42 #            include <com_err.h>
43 #        endif
44 #    endif
45 #endif
46 
47 /* Used for unused parameters to silence gcc warnings. */
48 #define UNUSED __attribute__((__unused__))
49 
50 /*
51  * This string is returned for unknown error messages.  We use a static
52  * variable so that we can be sure not to free it.
53  */
54 #if !defined(HAVE_KRB5_GET_ERROR_MESSAGE) \
55     || !defined(HAVE_KRB5_FREE_ERROR_MESSAGE)
56 static const char error_unknown[] = "unknown error";
57 #endif
58 
59 
60 #ifndef HAVE_KRB5_CC_GET_FULL_NAME
61 /*
62  * Given a Kerberos ticket cache, return the full name (TYPE:name) in
63  * newly-allocated memory.  Returns an error code.  Avoid asprintf and
64  * snprintf here in case someone wants to use this code without the rest of
65  * the portability layer.
66  */
67 krb5_error_code
68 krb5_cc_get_full_name(krb5_context ctx, krb5_ccache ccache, char **out)
69 {
70     const char *type, *name;
71     size_t length;
72 
73     type = krb5_cc_get_type(ctx, ccache);
74     if (type == NULL)
75         type = "FILE";
76     name = krb5_cc_get_name(ctx, ccache);
77     if (name == NULL)
78         return EINVAL;
79     length = strlen(type) + 1 + strlen(name) + 1;
80     *out = malloc(length);
81     if (*out == NULL)
82         return errno;
83     sprintf(*out, "%s:%s", type, name);
84     return 0;
85 }
86 #endif /* !HAVE_KRB5_CC_GET_FULL_NAME */
87 
88 
89 #ifndef HAVE_KRB5_GET_ERROR_MESSAGE
90 /*
91  * Given a Kerberos error code, return the corresponding error.  Prefer the
92  * Kerberos interface if available since it will provide context-specific
93  * error information, whereas the error_message() call will only provide a
94  * fixed message.
95  */
96 const char *
97 krb5_get_error_message(krb5_context ctx UNUSED, krb5_error_code code UNUSED)
98 {
99     const char *msg;
100 
101 #    if defined(HAVE_KRB5_GET_ERROR_STRING)
102     msg = krb5_get_error_string(ctx);
103 #    elif defined(HAVE_KRB5_GET_ERR_TEXT)
104     msg = krb5_get_err_text(ctx, code);
105 #    elif defined(HAVE_KRB5_SVC_GET_MSG)
106     krb5_svc_get_msg(code, (char **) &msg);
107 #    else
108     msg = error_message(code);
109 #    endif
110     if (msg == NULL)
111         return error_unknown;
112     else
113         return msg;
114 }
115 #endif /* !HAVE_KRB5_GET_ERROR_MESSAGE */
116 
117 
118 #ifndef HAVE_KRB5_FREE_ERROR_MESSAGE
119 /*
120  * Free an error string if necessary.  If we returned a static string, make
121  * sure we don't free it.
122  *
123  * This code assumes that the set of implementations that have
124  * krb5_free_error_message is a subset of those with krb5_get_error_message.
125  * If this assumption ever breaks, we may call the wrong free function.
126  */
127 void
128 krb5_free_error_message(krb5_context ctx UNUSED, const char *msg)
129 {
130     if (msg == error_unknown)
131         return;
132 #    if defined(HAVE_KRB5_GET_ERROR_STRING)
133     krb5_free_error_string(ctx, (char *) msg);
134 #    elif defined(HAVE_KRB5_SVC_GET_MSG)
135     krb5_free_string(ctx, (char *) msg);
136 #    endif
137 }
138 #endif /* !HAVE_KRB5_FREE_ERROR_MESSAGE */
139 
140 
141 #ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
142 /*
143  * Allocate and initialize a krb5_get_init_creds_opt struct.  This code
144  * assumes that an all-zero bit pattern will create a NULL pointer.
145  */
146 krb5_error_code
147 krb5_get_init_creds_opt_alloc(krb5_context ctx UNUSED,
148                               krb5_get_init_creds_opt **opts)
149 {
150     *opts = calloc(1, sizeof(krb5_get_init_creds_opt));
151     if (*opts == NULL)
152         return errno;
153     krb5_get_init_creds_opt_init(*opts);
154     return 0;
155 }
156 #endif /* !HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC */
157 
158 
159 #ifndef HAVE_KRB5_PRINCIPAL_GET_REALM
160 /*
161  * Return the realm of a principal as a const char *.
162  */
163 const char *
164 krb5_principal_get_realm(krb5_context ctx UNUSED, krb5_const_principal princ)
165 {
166     const krb5_data *data;
167 
168     data = krb5_princ_realm(ctx, princ);
169     if (data == NULL || data->data == NULL)
170         return NULL;
171     return data->data;
172 }
173 #endif /* !HAVE_KRB5_PRINCIPAL_GET_REALM */
174 
175 
176 #ifndef HAVE_KRB5_VERIFY_INIT_CREDS_OPT_INIT
177 /*
178  * Initialize the option struct for krb5_verify_init_creds.
179  */
180 void
181 krb5_verify_init_creds_opt_init(krb5_verify_init_creds_opt *opt)
182 {
183     opt->flags = 0;
184     opt->ap_req_nofail = 0;
185 }
186 #endif
187