net: Use dom_sid_str_buf
[Samba.git] / auth / auth_log.c
blob2d4e33f53bf96be7824a01429c49528cd448f702
1 /*
3 Authentication and authorization logging
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * Debug log levels for authentication logging (these both map to
23 * LOG_NOTICE in syslog)
25 #define AUTH_FAILURE_LEVEL 2
26 #define AUTH_SUCCESS_LEVEL 3
27 #define AUTHZ_SUCCESS_LEVEL 4
29 /* 5 is used for both authentication and authorization */
30 #define AUTH_ANONYMOUS_LEVEL 5
31 #define AUTHZ_ANONYMOUS_LEVEL 5
33 #define AUTHZ_JSON_TYPE "Authorization"
34 #define AUTH_JSON_TYPE "Authentication"
37 * JSON message version numbers
39 * If adding a field increment the minor version
40 * If removing or changing the format/meaning of a field
41 * increment the major version.
43 #define AUTH_MAJOR 1
44 #define AUTH_MINOR 0
45 #define AUTHZ_MAJOR 1
46 #define AUTHZ_MINOR 1
48 #include "includes.h"
49 #include "../lib/tsocket/tsocket.h"
50 #include "common_auth.h"
51 #include "lib/util/util_str_escape.h"
52 #include "libcli/security/dom_sid.h"
53 #include "libcli/security/security_token.h"
54 #include "librpc/gen_ndr/server_id.h"
55 #include "source4/lib/messaging/messaging.h"
56 #include "source4/lib/messaging/irpc.h"
57 #include "lib/util/server_id_db.h"
58 #include "lib/param/param.h"
59 #include "librpc/ndr/libndr.h"
60 #include "lib/audit_logging/audit_logging.h"
63 * Determine the type of the password supplied for the
64 * authorisation attempt.
67 static const char* get_password_type(const struct auth_usersupplied_info *ui);
69 #ifdef HAVE_JANSSON
71 #include <jansson.h>
72 #include "system/time.h"
75 * Write the json object to the debug logs.
78 static void log_json(struct imessaging_context *msg_ctx,
79 struct loadparm_context *lp_ctx,
80 struct json_object *object,
81 const char *type,
82 int debug_class,
83 int debug_level)
85 audit_log_json(type, object, debug_class, debug_level);
86 if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
87 audit_message_send(msg_ctx,
88 AUTH_EVENT_NAME,
89 MSG_AUTH_LOG,
90 object);
95 * Write a machine parsable json formatted authentication log entry.
97 * IF removing or changing the format/meaning of a field please update the
98 * major version number AUTH_MAJOR
100 * IF adding a new field please update the minor version number AUTH_MINOR
102 * To process the resulting log lines from the commend line use jq to
103 * parse the json.
105 * grep "JSON Authentication" log file |
106 * sed 's;^[^{]*;;' |
107 * jq -rc '"\(.timestamp)\t\(.Authentication.status)\t
108 * \(.Authentication.clientDomain)\t
109 * \(.Authentication.clientAccount)
110 * \t\(.Authentication.workstation)
111 * \t\(.Authentication.remoteAddress)
112 * \t\(.Authentication.localAddress)"'
114 static void log_authentication_event_json(
115 struct imessaging_context *msg_ctx,
116 struct loadparm_context *lp_ctx,
117 const struct timeval *start_time,
118 const struct auth_usersupplied_info *ui,
119 NTSTATUS status,
120 const char *domain_name,
121 const char *account_name,
122 const char *unix_username,
123 struct dom_sid *sid,
124 int debug_level)
126 struct json_object wrapper = json_empty_object;
127 struct json_object authentication = json_empty_object;
128 char negotiate_flags[11];
129 int rc = 0;
131 authentication = json_new_object();
132 if (json_is_invalid(&authentication)) {
133 goto failure;
135 rc = json_add_version(&authentication, AUTH_MAJOR, AUTH_MINOR);
136 if (rc != 0) {
137 goto failure;
139 rc = json_add_string(&authentication, "status", nt_errstr(status));
140 if (rc != 0) {
141 goto failure;
143 rc = json_add_address(&authentication, "localAddress", ui->local_host);
144 if (rc != 0) {
145 goto failure;
147 rc =
148 json_add_address(&authentication, "remoteAddress", ui->remote_host);
149 if (rc != 0) {
150 goto failure;
152 rc = json_add_string(
153 &authentication, "serviceDescription", ui->service_description);
154 if (rc != 0) {
155 goto failure;
157 rc = json_add_string(
158 &authentication, "authDescription", ui->auth_description);
159 if (rc != 0) {
160 goto failure;
162 rc = json_add_string(
163 &authentication, "clientDomain", ui->client.domain_name);
164 if (rc != 0) {
165 goto failure;
167 rc = json_add_string(
168 &authentication, "clientAccount", ui->client.account_name);
169 if (rc != 0) {
170 goto failure;
172 rc = json_add_string(
173 &authentication, "workstation", ui->workstation_name);
174 if (rc != 0) {
175 goto failure;
177 rc = json_add_string(&authentication, "becameAccount", account_name);
178 if (rc != 0) {
179 goto failure;
181 rc = json_add_string(&authentication, "becameDomain", domain_name);
182 if (rc != 0) {
183 goto failure;
185 rc = json_add_sid(&authentication, "becameSid", sid);
186 if (rc != 0) {
187 goto failure;
189 rc = json_add_string(
190 &authentication, "mappedAccount", ui->mapped.account_name);
191 if (rc != 0) {
192 goto failure;
194 rc = json_add_string(
195 &authentication, "mappedDomain", ui->mapped.domain_name);
196 if (rc != 0) {
197 goto failure;
199 rc = json_add_string(&authentication,
200 "netlogonComputer",
201 ui->netlogon_trust_account.computer_name);
202 if (rc != 0) {
203 goto failure;
205 rc = json_add_string(&authentication,
206 "netlogonTrustAccount",
207 ui->netlogon_trust_account.account_name);
208 if (rc != 0) {
209 goto failure;
211 snprintf(negotiate_flags,
212 sizeof( negotiate_flags),
213 "0x%08X",
214 ui->netlogon_trust_account.negotiate_flags);
215 rc = json_add_string(
216 &authentication, "netlogonNegotiateFlags", negotiate_flags);
217 if (rc != 0) {
218 goto failure;
220 rc = json_add_int(&authentication,
221 "netlogonSecureChannelType",
222 ui->netlogon_trust_account.secure_channel_type);
223 if (rc != 0) {
224 goto failure;
226 rc = json_add_sid(&authentication,
227 "netlogonTrustAccountSid",
228 ui->netlogon_trust_account.sid);
229 if (rc != 0) {
230 goto failure;
232 rc = json_add_string(
233 &authentication, "passwordType", get_password_type(ui));
234 if (rc != 0) {
235 goto failure;
238 wrapper = json_new_object();
239 if (json_is_invalid(&wrapper)) {
240 goto failure;
242 rc = json_add_timestamp(&wrapper);
243 if (rc != 0) {
244 goto failure;
246 rc = json_add_string(&wrapper, "type", AUTH_JSON_TYPE);
247 if (rc != 0) {
248 goto failure;
250 rc = json_add_object(&wrapper, AUTH_JSON_TYPE, &authentication);
251 if (rc != 0) {
252 goto failure;
256 * While not a general-purpose profiling solution this will
257 * assist some to determine how long NTLM and KDC
258 * authentication takes once this process can handle it. This
259 * covers transactions elsewhere but not (eg) the delay while
260 * this is waiting unread on the input socket.
262 if (start_time != NULL) {
263 struct timeval current_time = timeval_current();
264 uint64_t duration = usec_time_diff(&current_time,
265 start_time);
266 rc = json_add_int(&authentication, "duration", duration);
267 if (rc != 0) {
268 goto failure;
272 log_json(msg_ctx,
273 lp_ctx,
274 &wrapper,
275 AUTH_JSON_TYPE,
276 DBGC_AUTH_AUDIT,
277 debug_level);
278 json_free(&wrapper);
279 return;
280 failure:
282 * On a failure authentication will not have been added to wrapper so it
283 * needs to be freed to avoid a leak.
286 json_free(&authentication);
287 json_free(&wrapper);
288 DBG_ERR("Failed to write authentication event JSON log message\n");
292 * Log details of a successful authorization to a service,
293 * in a machine parsable json format
295 * IF removing or changing the format/meaning of a field please update the
296 * major version number AUTHZ_MAJOR
298 * IF adding a new field please update the minor version number AUTHZ_MINOR
300 * To process the resulting log lines from the commend line use jq to
301 * parse the json.
303 * grep "JSON Authentication" log_file |\
304 * sed "s;^[^{]*;;" |\
305 * jq -rc '"\(.timestamp)\t
306 * \(.Authorization.domain)\t
307 * \(.Authorization.account)\t
308 * \(.Authorization.remoteAddress)"'
311 static void log_successful_authz_event_json(
312 struct imessaging_context *msg_ctx,
313 struct loadparm_context *lp_ctx,
314 const struct tsocket_address *remote,
315 const struct tsocket_address *local,
316 const char *service_description,
317 const char *auth_type,
318 const char *transport_protection,
319 struct auth_session_info *session_info,
320 int debug_level)
322 struct json_object wrapper = json_empty_object;
323 struct json_object authorization = json_empty_object;
324 char account_flags[11];
325 int rc = 0;
327 authorization = json_new_object();
328 if (json_is_invalid(&authorization)) {
329 goto failure;
331 rc = json_add_version(&authorization, AUTHZ_MAJOR, AUTHZ_MINOR);
332 if (rc != 0) {
333 goto failure;
335 rc = json_add_address(&authorization, "localAddress", local);
336 if (rc != 0) {
337 goto failure;
339 rc = json_add_address(&authorization, "remoteAddress", remote);
340 if (rc != 0) {
341 goto failure;
343 rc = json_add_string(
344 &authorization, "serviceDescription", service_description);
345 if (rc != 0) {
346 goto failure;
348 rc = json_add_string(&authorization, "authType", auth_type);
349 if (rc != 0) {
350 goto failure;
352 rc = json_add_string(
353 &authorization, "domain", session_info->info->domain_name);
354 if (rc != 0) {
355 goto failure;
357 rc = json_add_string(
358 &authorization, "account", session_info->info->account_name);
359 if (rc != 0) {
360 goto failure;
362 rc = json_add_sid(
363 &authorization, "sid", &session_info->security_token->sids[0]);
364 if (rc != 0) {
365 goto failure;
367 rc = json_add_guid(
368 &authorization, "sessionId", &session_info->unique_session_token);
369 if (rc != 0) {
370 goto failure;
372 rc = json_add_string(
373 &authorization, "logonServer", session_info->info->logon_server);
374 if (rc != 0) {
375 goto failure;
377 rc = json_add_string(
378 &authorization, "transportProtection", transport_protection);
379 if (rc != 0) {
380 goto failure;
383 snprintf(account_flags,
384 sizeof(account_flags),
385 "0x%08X",
386 session_info->info->acct_flags);
387 rc = json_add_string(&authorization, "accountFlags", account_flags);
388 if (rc != 0) {
389 goto failure;
392 wrapper = json_new_object();
393 if (json_is_invalid(&wrapper)) {
394 goto failure;
396 rc = json_add_timestamp(&wrapper);
397 if (rc != 0) {
398 goto failure;
400 rc = json_add_string(&wrapper, "type", AUTHZ_JSON_TYPE);
401 if (rc != 0) {
402 goto failure;
404 rc = json_add_object(&wrapper, AUTHZ_JSON_TYPE, &authorization);
405 if (rc != 0) {
406 goto failure;
409 log_json(msg_ctx,
410 lp_ctx,
411 &wrapper,
412 AUTHZ_JSON_TYPE,
413 DBGC_AUTH_AUDIT,
414 debug_level);
415 json_free(&wrapper);
416 return;
417 failure:
419 * On a failure authorization will not have been added to wrapper so it
420 * needs to be freed to avoid a leak.
423 json_free(&authorization);
424 json_free(&wrapper);
425 DBG_ERR("Unable to log Authentication event JSON audit message\n");
428 #else
430 static void log_no_json(struct imessaging_context *msg_ctx,
431 struct loadparm_context *lp_ctx)
433 if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
434 static bool auth_event_logged = false;
435 if (auth_event_logged == false) {
436 auth_event_logged = true;
437 DBG_ERR("auth event notification = true but Samba was "
438 "not compiled with jansson\n");
440 } else {
441 static bool json_logged = false;
442 if (json_logged == false) {
443 json_logged = true;
444 DBG_NOTICE("JSON auth logs not available unless "
445 "compiled with jansson\n");
449 return;
452 static void log_authentication_event_json(
453 struct imessaging_context *msg_ctx,
454 struct loadparm_context *lp_ctx,
455 const struct timeval *start_time,
456 const struct auth_usersupplied_info *ui,
457 NTSTATUS status,
458 const char *domain_name,
459 const char *account_name,
460 const char *unix_username,
461 struct dom_sid *sid,
462 int debug_level)
464 log_no_json(msg_ctx, lp_ctx);
465 return;
468 static void log_successful_authz_event_json(
469 struct imessaging_context *msg_ctx,
470 struct loadparm_context *lp_ctx,
471 const struct tsocket_address *remote,
472 const struct tsocket_address *local,
473 const char *service_description,
474 const char *auth_type,
475 const char *transport_protection,
476 struct auth_session_info *session_info,
477 int debug_level)
479 log_no_json(msg_ctx, lp_ctx);
480 return;
483 #endif
486 * Determine the type of the password supplied for the
487 * authorisation attempt.
490 static const char* get_password_type(const struct auth_usersupplied_info *ui)
493 const char *password_type = NULL;
495 if (ui->password_type != NULL) {
496 password_type = ui->password_type;
497 } else if (ui->auth_description != NULL &&
498 strncmp("ServerAuthenticate", ui->auth_description, 18) == 0)
500 if (ui->netlogon_trust_account.negotiate_flags
501 & NETLOGON_NEG_SUPPORTS_AES) {
502 password_type = "HMAC-SHA256";
503 } else if (ui->netlogon_trust_account.negotiate_flags
504 & NETLOGON_NEG_STRONG_KEYS) {
505 password_type = "HMAC-MD5";
506 } else {
507 password_type = "DES";
509 } else if (ui->password_state == AUTH_PASSWORD_RESPONSE &&
510 (ui->logon_parameters & MSV1_0_ALLOW_MSVCHAPV2) &&
511 ui->password.response.nt.length == 24) {
512 password_type = "MSCHAPv2";
513 } else if ((ui->logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED)
514 || (ui->password_state == AUTH_PASSWORD_PLAIN)) {
515 password_type = "Plaintext";
516 } else if (ui->password_state == AUTH_PASSWORD_HASH) {
517 password_type = "Supplied-NT-Hash";
518 } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
519 && ui->password.response.nt.length > 24) {
520 password_type = "NTLMv2";
521 } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
522 && ui->password.response.nt.length == 24) {
523 password_type = "NTLMv1";
524 } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
525 && ui->password.response.lanman.length == 24) {
526 password_type = "LANMan";
527 } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
528 && ui->password.response.nt.length == 0
529 && ui->password.response.lanman.length == 0) {
530 password_type = "No-Password";
532 return password_type;
536 * Write a human readable authentication log entry.
539 static void log_authentication_event_human_readable(
540 const struct auth_usersupplied_info *ui,
541 NTSTATUS status,
542 const char *domain_name,
543 const char *account_name,
544 const char *unix_username,
545 struct dom_sid *sid,
546 int debug_level)
548 TALLOC_CTX *frame = NULL;
550 const char *ts = NULL; /* formatted current time */
551 char *remote = NULL; /* formatted remote host */
552 char *local = NULL; /* formatted local host */
553 char *nl = NULL; /* NETLOGON details if present */
554 char *trust_computer_name = NULL;
555 char *trust_account_name = NULL;
556 char *logon_line = NULL;
557 const char *password_type = NULL;
559 frame = talloc_stackframe();
561 password_type = get_password_type(ui);
562 /* Get the current time */
563 ts = audit_get_timestamp(frame);
565 /* Only log the NETLOGON details if they are present */
566 if (ui->netlogon_trust_account.computer_name ||
567 ui->netlogon_trust_account.account_name) {
568 trust_computer_name = log_escape(frame,
569 ui->netlogon_trust_account.computer_name);
570 trust_account_name = log_escape(frame,
571 ui->netlogon_trust_account.account_name);
572 nl = talloc_asprintf(frame,
573 " NETLOGON computer [%s] trust account [%s]",
574 trust_computer_name, trust_account_name);
577 remote = tsocket_address_string(ui->remote_host, frame);
578 local = tsocket_address_string(ui->local_host, frame);
580 if (NT_STATUS_IS_OK(status)) {
581 struct dom_sid_buf sid_buf;
583 logon_line = talloc_asprintf(frame,
584 " became [%s]\\[%s] [%s].",
585 log_escape(frame, domain_name),
586 log_escape(frame, account_name),
587 dom_sid_str_buf(sid, &sid_buf));
588 } else {
589 logon_line = talloc_asprintf(
590 frame,
591 " mapped to [%s]\\[%s].",
592 log_escape(frame, ui->mapped.domain_name),
593 log_escape(frame, ui->mapped.account_name));
596 DEBUGC(DBGC_AUTH_AUDIT, debug_level,
597 ("Auth: [%s,%s] user [%s]\\[%s]"
598 " at [%s] with [%s] status [%s]"
599 " workstation [%s] remote host [%s]"
600 "%s local host [%s]"
601 " %s\n",
602 ui->service_description,
603 ui->auth_description,
604 log_escape(frame, ui->client.domain_name),
605 log_escape(frame, ui->client.account_name),
607 password_type,
608 nt_errstr(status),
609 log_escape(frame, ui->workstation_name),
610 remote,
611 logon_line,
612 local,
613 nl ? nl : ""
616 talloc_free(frame);
620 * Log details of an authentication attempt.
621 * Successful and unsuccessful attempts are logged.
623 * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
624 * authentication events over the message bus.
626 void log_authentication_event(
627 struct imessaging_context *msg_ctx,
628 struct loadparm_context *lp_ctx,
629 const struct timeval *start_time,
630 const struct auth_usersupplied_info *ui,
631 NTSTATUS status,
632 const char *domain_name,
633 const char *account_name,
634 const char *unix_username,
635 struct dom_sid *sid)
637 /* set the log level */
638 int debug_level = AUTH_FAILURE_LEVEL;
640 if (NT_STATUS_IS_OK(status)) {
641 debug_level = AUTH_SUCCESS_LEVEL;
642 if (dom_sid_equal(sid, &global_sid_Anonymous)) {
643 debug_level = AUTH_ANONYMOUS_LEVEL;
647 if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
648 log_authentication_event_human_readable(ui,
649 status,
650 domain_name,
651 account_name,
652 unix_username,
653 sid,
654 debug_level);
656 if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT_JSON, debug_level) ||
657 (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
658 log_authentication_event_json(msg_ctx,
659 lp_ctx,
660 start_time,
662 status,
663 domain_name,
664 account_name,
665 unix_username,
666 sid,
667 debug_level);
674 * Log details of a successful authorization to a service,
675 * in a human readable format.
678 static void log_successful_authz_event_human_readable(
679 const struct tsocket_address *remote,
680 const struct tsocket_address *local,
681 const char *service_description,
682 const char *auth_type,
683 const char *transport_protection,
684 struct auth_session_info *session_info,
685 int debug_level)
687 TALLOC_CTX *frame = NULL;
689 const char *ts = NULL; /* formatted current time */
690 char *remote_str = NULL; /* formatted remote host */
691 char *local_str = NULL; /* formatted local host */
692 struct dom_sid_buf sid_buf;
694 frame = talloc_stackframe();
696 /* Get the current time */
697 ts = audit_get_timestamp(frame);
699 remote_str = tsocket_address_string(remote, frame);
700 local_str = tsocket_address_string(local, frame);
702 DEBUGC(DBGC_AUTH_AUDIT, debug_level,
703 ("Successful AuthZ: [%s,%s] user [%s]\\[%s] [%s]"
704 " at [%s]"
705 " Remote host [%s]"
706 " local host [%s]\n",
707 service_description,
708 auth_type,
709 log_escape(frame, session_info->info->domain_name),
710 log_escape(frame, session_info->info->account_name),
711 dom_sid_str_buf(&session_info->security_token->sids[0],
712 &sid_buf),
714 remote_str,
715 local_str));
717 talloc_free(frame);
721 * Log details of a successful authorization to a service.
723 * Only successful authorizations are logged. For clarity:
724 * - NTLM bad passwords will be recorded by log_authentication_event
725 * - Kerberos decrypt failures need to be logged in gensec_gssapi et al
727 * The service may later refuse authorization due to an ACL.
729 * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
730 * authentication events over the message bus.
732 void log_successful_authz_event(
733 struct imessaging_context *msg_ctx,
734 struct loadparm_context *lp_ctx,
735 const struct tsocket_address *remote,
736 const struct tsocket_address *local,
737 const char *service_description,
738 const char *auth_type,
739 const char *transport_protection,
740 struct auth_session_info *session_info)
742 int debug_level = AUTHZ_SUCCESS_LEVEL;
744 /* set the log level */
745 if (security_token_is_anonymous(session_info->security_token)) {
746 debug_level = AUTH_ANONYMOUS_LEVEL;
749 if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
750 log_successful_authz_event_human_readable(remote,
751 local,
752 service_description,
753 auth_type,
754 transport_protection,
755 session_info,
756 debug_level);
758 if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT_JSON, debug_level) ||
759 (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
760 log_successful_authz_event_json(msg_ctx, lp_ctx,
761 remote,
762 local,
763 service_description,
764 auth_type,
765 transport_protection,
766 session_info,
767 debug_level);