1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kdc/kdc_log.c - Logging functions for KDC requests */
3 /*
4 * Copyright 2008,2009 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "k5-int.h"
28 #include "kdc_util.h"
29 #include <syslog.h>
30 #include "adm_proto.h"
31
32 /*
33 * A note on KDC-status string format.
34 *
35 * - All letters in the status string should be capitalized;
36 * - the words in the status phrase are separated by underscores;
37 * - abbreviations should be avoided. Some acceptable "standard" acronyms
38 * are AS_REQ, TGS_REP etc.
39 * - since in almost all cases KDC status string is set on error, no need
40 * to state this fact as part of the status string;
41 * - KDC status string should be an imperative phrase.
42 *
43 * Example: "MAKE_RANDOM_KEY"
44 */
45
46 /* Main logging routines for ticket requests.
47
48 There are a few simple cases -- unparseable requests mainly --
49 where messages are logged otherwise, but once a ticket request can
50 be decoded in some basic way, these routines are used for logging
51 the details. */
52
53 /* "status" is null to indicate success. */
54 /* Someday, pass local address/port as well. */
55 /* Currently no info about name canonicalization is logged. */
56 void
log_as_req(krb5_context context,const krb5_fulladdr * local_addr,const krb5_fulladdr * remote_addr,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_db_entry * client,const char * cname,krb5_db_entry * server,const char * sname,krb5_timestamp authtime,const char * status,krb5_error_code errcode,const char * emsg)57 log_as_req(krb5_context context,
58 const krb5_fulladdr *local_addr,
59 const krb5_fulladdr *remote_addr,
60 krb5_kdc_req *request, krb5_kdc_rep *reply,
61 krb5_db_entry *client, const char *cname,
62 krb5_db_entry *server, const char *sname,
63 krb5_timestamp authtime,
64 const char *status, krb5_error_code errcode, const char *emsg)
65 {
66 const char *fromstring = 0;
67 char fromstringbuf[70];
68 char *ktypestr = NULL;
69 const char *cname2 = cname ? cname : "<unknown client>";
70 const char *sname2 = sname ? sname : "<unknown server>";
71
72 fromstring = inet_ntop(ADDRTYPE2FAMILY(remote_addr->address->addrtype),
73 remote_addr->address->contents,
74 fromstringbuf, sizeof(fromstringbuf));
75 if (!fromstring)
76 fromstring = "<unknown>";
77
78 ktypestr = ktypes2str(request->ktype, request->nktypes);
79
80 if (status == NULL) {
81 /* success */
82 char *rep_etypestr = rep_etypes2str(reply);
83 krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: ISSUE: authtime %u, %s, "
84 "%s for %s"),
85 ktypestr ? ktypestr : "", fromstring,
86 (unsigned int)authtime,
87 rep_etypestr ? rep_etypestr : "", cname2, sname2);
88 free(rep_etypestr);
89 } else {
90 /* fail */
91 krb5_klog_syslog(LOG_INFO, _("AS_REQ (%s) %s: %s: %s for %s%s%s"),
92 ktypestr ? ktypestr : "", fromstring, status, cname2,
93 sname2, emsg ? ", " : "", emsg ? emsg : "");
94 }
95 krb5_db_audit_as_req(context, request,
96 local_addr->address, remote_addr->address,
97 client, server, authtime, errcode);
98
99 free(ktypestr);
100 }
101
102 /*
103 * Unparse a principal for logging purposes and limit the string length.
104 * Ignore errors because the most likely errors are memory exhaustion, and many
105 * other things will fail in the logging functions in that case.
106 */
107 static void
unparse_and_limit(krb5_context ctx,krb5_principal princ,char ** str)108 unparse_and_limit(krb5_context ctx, krb5_principal princ, char **str)
109 {
110 /* Ignore errors */
111 krb5_unparse_name(ctx, princ, str);
112 limit_string(*str);
113 }
114
115 /* Here "status" must be non-null. Error code
116 KRB5KDC_ERR_SERVER_NOMATCH is handled specially.
117
118 Currently no info about name canonicalization is logged. */
119 void
log_tgs_req(krb5_context ctx,const krb5_fulladdr * from,krb5_kdc_req * request,krb5_kdc_rep * reply,krb5_principal cprinc,krb5_principal sprinc,krb5_principal altcprinc,krb5_timestamp authtime,unsigned int c_flags,const char * status,krb5_error_code errcode,const char * emsg)120 log_tgs_req(krb5_context ctx, const krb5_fulladdr *from,
121 krb5_kdc_req *request, krb5_kdc_rep *reply,
122 krb5_principal cprinc, krb5_principal sprinc,
123 krb5_principal altcprinc,
124 krb5_timestamp authtime,
125 unsigned int c_flags,
126 const char *status, krb5_error_code errcode, const char *emsg)
127 {
128 char *ktypestr = NULL, *rep_etypestr = NULL;
129 const char *fromstring = 0;
130 char fromstringbuf[70];
131 char *cname = NULL, *sname = NULL, *altcname = NULL;
132 char *logcname = NULL, *logsname = NULL, *logaltcname = NULL;
133
134 fromstring = inet_ntop(ADDRTYPE2FAMILY(from->address->addrtype),
135 from->address->contents,
136 fromstringbuf, sizeof(fromstringbuf));
137 if (!fromstring)
138 fromstring = "<unknown>";
139
140 unparse_and_limit(ctx, cprinc, &cname);
141 logcname = (cname != NULL) ? cname : "<unknown client>";
142 unparse_and_limit(ctx, sprinc, &sname);
143 logsname = (sname != NULL) ? sname : "<unknown server>";
144 unparse_and_limit(ctx, altcprinc, &altcname);
145 logaltcname = (altcname != NULL) ? altcname : "<unknown>";
146
147 /* Differences: server-nomatch message logs 2nd ticket's client
148 name (useful), and doesn't log ktypestr (probably not
149 important). */
150 if (errcode != KRB5KDC_ERR_SERVER_NOMATCH) {
151 ktypestr = ktypes2str(request->ktype, request->nktypes);
152 rep_etypestr = rep_etypes2str(reply);
153 krb5_klog_syslog(LOG_INFO, _("TGS_REQ (%s) %s: %s: authtime %u, %s%s "
154 "%s for %s%s%s"),
155 ktypestr ? ktypestr : "", fromstring, status,
156 (unsigned int)authtime,
157 rep_etypestr ? rep_etypestr : "",
158 !errcode ? "," : "", logcname, logsname,
159 errcode ? ", " : "", errcode ? emsg : "");
160 if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION))
161 krb5_klog_syslog(LOG_INFO,
162 _("... PROTOCOL-TRANSITION s4u-client=%s"),
163 logaltcname);
164 else if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION))
165 krb5_klog_syslog(LOG_INFO,
166 _("... CONSTRAINED-DELEGATION s4u-client=%s"),
167 logaltcname);
168
169 } else
170 krb5_klog_syslog(LOG_INFO, _("TGS_REQ %s: %s: authtime %u, %s for %s, "
171 "2nd tkt client %s"),
172 fromstring, status, (unsigned int)authtime,
173 logcname, logsname, logaltcname);
174
175 free(rep_etypestr);
176 free(ktypestr);
177 krb5_free_unparsed_name(ctx, cname);
178 krb5_free_unparsed_name(ctx, sname);
179 krb5_free_unparsed_name(ctx, altcname);
180 }
181
182 void
log_tgs_badtrans(krb5_context ctx,krb5_principal cprinc,krb5_principal sprinc,krb5_data * trcont,krb5_error_code errcode)183 log_tgs_badtrans(krb5_context ctx, krb5_principal cprinc,
184 krb5_principal sprinc, krb5_data *trcont,
185 krb5_error_code errcode)
186 {
187 unsigned int tlen;
188 char *tdots;
189 const char *emsg = NULL;
190 char *cname = NULL, *sname = NULL;
191 char *logcname = NULL, *logsname = NULL;
192
193 unparse_and_limit(ctx, cprinc, &cname);
194 logcname = (cname != NULL) ? cname : "<unknown client>";
195 unparse_and_limit(ctx, sprinc, &sname);
196 logsname = (sname != NULL) ? sname : "<unknown server>";
197
198 tlen = trcont->length;
199 tdots = tlen > 125 ? "..." : "";
200 tlen = tlen > 125 ? 125 : tlen;
201
202 if (errcode == KRB5KRB_AP_ERR_ILL_CR_TKT)
203 krb5_klog_syslog(LOG_INFO, _("bad realm transit path from '%s' "
204 "to '%s' via '%.*s%s'"),
205 logcname, logsname, tlen,
206 trcont->data, tdots);
207 else {
208 emsg = krb5_get_error_message(ctx, errcode);
209 krb5_klog_syslog(LOG_ERR, _("unexpected error checking transit "
210 "from '%s' to '%s' via '%.*s%s': %s"),
211 logcname, logsname, tlen,
212 trcont->data, tdots,
213 emsg);
214 krb5_free_error_message(ctx, emsg);
215 emsg = NULL;
216 }
217 krb5_free_unparsed_name(ctx, cname);
218 krb5_free_unparsed_name(ctx, sname);
219 }
220
221 void
log_tgs_alt_tgt(krb5_context context,krb5_principal p)222 log_tgs_alt_tgt(krb5_context context, krb5_principal p)
223 {
224 char *sname;
225 if (krb5_unparse_name(context, p, &sname)) {
226 krb5_klog_syslog(LOG_INFO,
227 _("TGS_REQ: issuing alternate <un-unparseable> TGT"));
228 } else {
229 limit_string(sname);
230 krb5_klog_syslog(LOG_INFO, _("TGS_REQ: issuing TGT %s"), sname);
231 free(sname);
232 }
233 /* OpenSolaris: audit_krb5kdc_tgs_req_alt_tgt(...) */
234 }
235