403bcad166f52d29223ab93fa8321461fa16ab06
[metze/samba/wip.git] / auth / auth_log.c
1 /*
2
3    Authentication and authorization logging
4
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
6
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.
11
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.
16
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/>.
19 */
20
21 /*
22  * Debug log levels for authentication logging (these both map to
23  * LOG_NOTICE in syslog)
24  */
25 #define AUTH_FAILURE_LEVEL 2
26 #define AUTH_SUCCESS_LEVEL 3
27 #define AUTHZ_SUCCESS_LEVEL 4
28
29 /* 5 is used for both authentication and authorization */
30 #define AUTH_ANONYMOUS_LEVEL 5
31 #define AUTHZ_ANONYMOUS_LEVEL 5
32
33 #define AUTHZ_JSON_TYPE "Authorization"
34 #define AUTH_JSON_TYPE  "Authentication"
35
36 /*
37  * JSON message version numbers
38  *
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.
42  */
43 #define AUTH_MAJOR 1
44 #define AUTH_MINOR 0
45 #define AUTHZ_MAJOR 1
46 #define AUTHZ_MINOR 1
47
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"
61
62 /*
63  * Determine the type of the password supplied for the
64  * authorisation attempt.
65  *
66  */
67 static const char* get_password_type(const struct auth_usersupplied_info *ui);
68
69 #ifdef HAVE_JANSSON
70
71 #include <jansson.h>
72 #include "system/time.h"
73
74 /*
75  * Write the json object to the debug logs.
76  *
77  */
78 static void log_json(struct imessaging_context *msg_ctx,
79                      struct loadparm_context *lp_ctx,
80                      struct json_object *context,
81                      const char *type,
82                      int debug_class,
83                      int debug_level)
84 {
85         char* json = NULL;
86
87         if (context->error) {
88                 return;
89         }
90
91         json = json_dumps(context->root, 0);
92         if (json == NULL) {
93                 DBG_ERR("Unable to convert JSON object to string\n");
94                 context->error = true;
95                 return;
96         }
97
98         DEBUGC(debug_class, debug_level, ("JSON %s: %s\n", type, json));
99         if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
100                 audit_message_send(msg_ctx,
101                                    AUTH_EVENT_NAME,
102                                    MSG_AUTH_LOG,
103                                    json);
104         }
105
106         if (json) {
107                 free(json);
108         }
109
110 }
111
112 /*
113  * Write a machine parsable json formatted authentication log entry.
114  *
115  * IF removing or changing the format/meaning of a field please update the
116  *    major version number AUTH_MAJOR
117  *
118  * IF adding a new field please update the minor version number AUTH_MINOR
119  *
120  *  To process the resulting log lines from the commend line use jq to
121  *  parse the json.
122  *
123  *  grep "JSON Authentication" log file |
124  *  sed 's;^[^{]*;;' |
125  * jq -rc  '"\(.timestamp)\t\(.Authentication.status)\t
126  *           \(.Authentication.clientDomain)\t
127  *           \(.Authentication.clientAccount)
128  *           \t\(.Authentication.workstation)
129  *           \t\(.Authentication.remoteAddress)
130  *           \t\(.Authentication.localAddress)"'
131  */
132 static void log_authentication_event_json(
133         struct imessaging_context *msg_ctx,
134         struct loadparm_context *lp_ctx,
135         const struct auth_usersupplied_info *ui,
136         NTSTATUS status,
137         const char *domain_name,
138         const char *account_name,
139         const char *unix_username,
140         struct dom_sid *sid,
141         int debug_level)
142 {
143         struct json_object context = json_new_object();
144         struct json_object authentication;
145         char negotiate_flags[11];
146
147         json_add_timestamp(&context);
148         json_add_string(&context, "type", AUTH_JSON_TYPE);
149
150         authentication = json_new_object();
151         json_add_version(&authentication, AUTH_MAJOR, AUTH_MINOR);
152         json_add_string(&authentication, "status", nt_errstr(status));
153         json_add_address(&authentication, "localAddress", ui->local_host);
154         json_add_address(&authentication, "remoteAddress", ui->remote_host);
155         json_add_string(&authentication,
156                         "serviceDescription",
157                         ui->service_description);
158         json_add_string(&authentication,
159                         "authDescription",
160                         ui->auth_description);
161         json_add_string(&authentication,
162                         "clientDomain",
163                         ui->client.domain_name);
164         json_add_string(&authentication,
165                         "clientAccount",
166                         ui->client.account_name);
167         json_add_string(&authentication,
168                         "workstation",
169                         ui->workstation_name);
170         json_add_string(&authentication, "becameAccount", account_name);
171         json_add_string(&authentication, "becameDomain", domain_name);
172         json_add_sid(&authentication, "becameSid", sid);
173         json_add_string(&authentication,
174                         "mappedAccount",
175                         ui->mapped.account_name);
176         json_add_string(&authentication,
177                         "mappedDomain",
178                         ui->mapped.domain_name);
179         json_add_string(&authentication,
180                         "netlogonComputer",
181                         ui->netlogon_trust_account.computer_name);
182         json_add_string(&authentication,
183                         "netlogonTrustAccount",
184                         ui->netlogon_trust_account.account_name);
185         snprintf(negotiate_flags,
186                  sizeof( negotiate_flags),
187                  "0x%08X",
188                  ui->netlogon_trust_account.negotiate_flags);
189         json_add_string(&authentication,
190                         "netlogonNegotiateFlags",
191                         negotiate_flags);
192         json_add_int(&authentication,
193                      "netlogonSecureChannelType",
194                      ui->netlogon_trust_account.secure_channel_type);
195         json_add_sid(&authentication,
196                      "netlogonTrustAccountSid",
197                      ui->netlogon_trust_account.sid);
198         json_add_string(&authentication, "passwordType", get_password_type(ui));
199         json_add_object(&context,AUTH_JSON_TYPE, &authentication);
200
201         log_json(msg_ctx,
202                  lp_ctx,
203                  &context,
204                  AUTH_JSON_TYPE,
205                  DBGC_AUTH_AUDIT,
206                  debug_level);
207         json_free(&context);
208 }
209
210 /*
211  * Log details of a successful authorization to a service,
212  * in a machine parsable json format
213  *
214  * IF removing or changing the format/meaning of a field please update the
215  *    major version number AUTHZ_MAJOR
216  *
217  * IF adding a new field please update the minor version number AUTHZ_MINOR
218  *
219  *  To process the resulting log lines from the commend line use jq to
220  *  parse the json.
221  *
222  *  grep "JSON Authentication" log_file |\
223  *  sed "s;^[^{]*;;" |\
224  *  jq -rc '"\(.timestamp)\t
225  *           \(.Authorization.domain)\t
226  *           \(.Authorization.account)\t
227  *           \(.Authorization.remoteAddress)"'
228  *
229  */
230 static void log_successful_authz_event_json(
231         struct imessaging_context *msg_ctx,
232         struct loadparm_context *lp_ctx,
233         const struct tsocket_address *remote,
234         const struct tsocket_address *local,
235         const char *service_description,
236         const char *auth_type,
237         const char *transport_protection,
238         struct auth_session_info *session_info,
239         int debug_level)
240 {
241         struct json_object context = json_new_object();
242         struct json_object authorization;
243         char account_flags[11];
244
245         json_add_timestamp(&context);
246         json_add_string(&context, "type", AUTHZ_JSON_TYPE);
247         authorization = json_new_object();
248         json_add_version(&authorization, AUTHZ_MAJOR, AUTHZ_MINOR);
249         json_add_address(&authorization, "localAddress", local);
250         json_add_address(&authorization, "remoteAddress", remote);
251         json_add_string(&authorization,
252                         "serviceDescription",
253                         service_description);
254         json_add_string(&authorization, "authType", auth_type);
255         json_add_string(&authorization,
256                         "domain",
257                         session_info->info->domain_name);
258         json_add_string(&authorization,
259                         "account",
260                         session_info->info->account_name);
261         json_add_sid(&authorization,
262                      "sid",
263                      &session_info->security_token->sids[0]);
264         json_add_guid(&authorization,
265                       "sessionId",
266                       &session_info->unique_session_token);
267         json_add_string(&authorization,
268                         "logonServer",
269                         session_info->info->logon_server);
270         json_add_string(&authorization,
271                         "transportProtection",
272                         transport_protection);
273
274         snprintf(account_flags,
275                  sizeof(account_flags),
276                  "0x%08X",
277                  session_info->info->acct_flags);
278         json_add_string(&authorization, "accountFlags", account_flags);
279         json_add_object(&context, AUTHZ_JSON_TYPE, &authorization);
280
281         log_json(msg_ctx,
282                  lp_ctx,
283                  &context,
284                  AUTHZ_JSON_TYPE,
285                  DBGC_AUTH_AUDIT,
286                  debug_level);
287         json_free(&context);
288 }
289
290 #else
291
292 static void log_no_json(struct imessaging_context *msg_ctx,
293                         struct loadparm_context *lp_ctx)
294 {
295         if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
296                 static bool auth_event_logged = false;
297                 if (auth_event_logged == false) {
298                         auth_event_logged = true;
299                         DBG_ERR("auth event notification = true but Samba was "
300                                 "not compiled with jansson\n");
301                 }
302         } else {
303                 static bool json_logged = false;
304                 if (json_logged == false) {
305                         json_logged = true;
306                         DBG_NOTICE("JSON auth logs not available unless "
307                                    "compiled with jansson\n");
308                 }
309         }
310
311         return;
312 }
313
314 static void log_authentication_event_json(
315         struct imessaging_context *msg_ctx,
316         struct loadparm_context *lp_ctx,
317         const struct auth_usersupplied_info *ui,
318         NTSTATUS status,
319         const char *domain_name,
320         const char *account_name,
321         const char *unix_username,
322         struct dom_sid *sid,
323         int debug_level)
324 {
325         log_no_json(msg_ctx, lp_ctx);
326         return;
327 }
328
329 static void log_successful_authz_event_json(
330         struct imessaging_context *msg_ctx,
331         struct loadparm_context *lp_ctx,
332         const struct tsocket_address *remote,
333         const struct tsocket_address *local,
334         const char *service_description,
335         const char *auth_type,
336         const char *transport_protection,
337         struct auth_session_info *session_info,
338         int debug_level)
339 {
340         log_no_json(msg_ctx, lp_ctx);
341         return;
342 }
343
344 #endif
345
346 /*
347  * Determine the type of the password supplied for the
348  * authorisation attempt.
349  *
350  */
351 static const char* get_password_type(const struct auth_usersupplied_info *ui)
352 {
353
354         const char *password_type = NULL;
355
356         if (ui->password_type != NULL) {
357                 password_type = ui->password_type;
358         } else if (ui->auth_description != NULL &&
359                    strncmp("ServerAuthenticate", ui->auth_description, 18) == 0)
360         {
361                 if (ui->netlogon_trust_account.negotiate_flags
362                     & NETLOGON_NEG_SUPPORTS_AES) {
363                         password_type = "HMAC-SHA256";
364                 } else if (ui->netlogon_trust_account.negotiate_flags
365                            & NETLOGON_NEG_STRONG_KEYS) {
366                         password_type = "HMAC-MD5";
367                 } else {
368                         password_type = "DES";
369                 }
370         } else if (ui->password_state == AUTH_PASSWORD_RESPONSE &&
371                    (ui->logon_parameters & MSV1_0_ALLOW_MSVCHAPV2) &&
372                    ui->password.response.nt.length == 24) {
373                 password_type = "MSCHAPv2";
374         } else if ((ui->logon_parameters & MSV1_0_CLEARTEXT_PASSWORD_SUPPLIED)
375                    || (ui->password_state == AUTH_PASSWORD_PLAIN)) {
376                 password_type = "Plaintext";
377         } else if (ui->password_state == AUTH_PASSWORD_HASH) {
378                 password_type = "Supplied-NT-Hash";
379         } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
380                    && ui->password.response.nt.length > 24) {
381                 password_type = "NTLMv2";
382         } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
383                    && ui->password.response.nt.length == 24) {
384                 password_type = "NTLMv1";
385         } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
386                    && ui->password.response.lanman.length == 24) {
387                 password_type = "LANMan";
388         } else if (ui->password_state == AUTH_PASSWORD_RESPONSE
389                    && ui->password.response.nt.length == 0
390                    && ui->password.response.lanman.length == 0) {
391                 password_type = "No-Password";
392         }
393         return password_type;
394 }
395
396 /*
397  * Write a human readable authentication log entry.
398  *
399  */
400 static void log_authentication_event_human_readable(
401         const struct auth_usersupplied_info *ui,
402         NTSTATUS status,
403         const char *domain_name,
404         const char *account_name,
405         const char *unix_username,
406         struct dom_sid *sid,
407         int debug_level)
408 {
409         TALLOC_CTX *frame = NULL;
410
411         const char *ts = NULL;             /* formatted current time      */
412         char *remote = NULL;               /* formatted remote host       */
413         char *local = NULL;                /* formatted local host        */
414         char *nl = NULL;                   /* NETLOGON details if present */
415         char *trust_computer_name = NULL;
416         char *trust_account_name = NULL;
417         char *logon_line = NULL;
418         const char *password_type = NULL;
419
420         frame = talloc_stackframe();
421
422         password_type = get_password_type(ui);
423         /* Get the current time */
424         ts = audit_get_timestamp(frame);
425
426         /* Only log the NETLOGON details if they are present */
427         if (ui->netlogon_trust_account.computer_name ||
428             ui->netlogon_trust_account.account_name) {
429                 trust_computer_name = log_escape(frame,
430                         ui->netlogon_trust_account.computer_name);
431                 trust_account_name  = log_escape(frame,
432                         ui->netlogon_trust_account.account_name);
433                 nl = talloc_asprintf(frame,
434                         " NETLOGON computer [%s] trust account [%s]",
435                         trust_computer_name, trust_account_name);
436         }
437
438         remote = tsocket_address_string(ui->remote_host, frame);
439         local = tsocket_address_string(ui->local_host, frame);
440
441         if (NT_STATUS_IS_OK(status)) {
442                 char sid_buf[DOM_SID_STR_BUFLEN];
443
444                 dom_sid_string_buf(sid, sid_buf, sizeof(sid_buf));
445                 logon_line = talloc_asprintf(frame,
446                                              " became [%s]\\[%s] [%s].",
447                                              log_escape(frame, domain_name),
448                                              log_escape(frame, account_name),
449                                              sid_buf);
450         } else {
451                 logon_line = talloc_asprintf(
452                                 frame,
453                                 " mapped to [%s]\\[%s].",
454                                 log_escape(frame, ui->mapped.domain_name),
455                                 log_escape(frame, ui->mapped.account_name));
456         }
457
458         DEBUGC(DBGC_AUTH_AUDIT, debug_level,
459                ("Auth: [%s,%s] user [%s]\\[%s]"
460                 " at [%s] with [%s] status [%s]"
461                 " workstation [%s] remote host [%s]"
462                 "%s local host [%s]"
463                 " %s\n",
464                 ui->service_description,
465                 ui->auth_description,
466                 log_escape(frame, ui->client.domain_name),
467                 log_escape(frame, ui->client.account_name),
468                 ts,
469                 password_type,
470                 nt_errstr(status),
471                 log_escape(frame, ui->workstation_name),
472                 remote,
473                 logon_line,
474                 local,
475                 nl ? nl : ""
476         ));
477
478         talloc_free(frame);
479 }
480
481 /*
482  * Log details of an authentication attempt.
483  * Successful and unsuccessful attempts are logged.
484  *
485  * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
486  * authentication events over the message bus.
487  */
488 void log_authentication_event(
489         struct imessaging_context *msg_ctx,
490         struct loadparm_context *lp_ctx,
491         const struct auth_usersupplied_info *ui,
492         NTSTATUS status,
493         const char *domain_name,
494         const char *account_name,
495         const char *unix_username,
496         struct dom_sid *sid)
497 {
498         /* set the log level */
499         int debug_level = AUTH_FAILURE_LEVEL;
500
501         if (NT_STATUS_IS_OK(status)) {
502                 debug_level = AUTH_SUCCESS_LEVEL;
503                 if (dom_sid_equal(sid, &global_sid_Anonymous)) {
504                         debug_level = AUTH_ANONYMOUS_LEVEL;
505                 }
506         }
507
508         if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
509                 log_authentication_event_human_readable(ui,
510                                                         status,
511                                                         domain_name,
512                                                         account_name,
513                                                         unix_username,
514                                                         sid,
515                                                         debug_level);
516         }
517         if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT_JSON, debug_level) ||
518             (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
519                 log_authentication_event_json(msg_ctx, lp_ctx,
520                                               ui,
521                                               status,
522                                               domain_name,
523                                               account_name,
524                                               unix_username,
525                                               sid,
526                                               debug_level);
527         }
528 }
529
530
531
532 /*
533  * Log details of a successful authorization to a service,
534  * in a human readable format.
535  *
536  */
537 static void log_successful_authz_event_human_readable(
538         const struct tsocket_address *remote,
539         const struct tsocket_address *local,
540         const char *service_description,
541         const char *auth_type,
542         const char *transport_protection,
543         struct auth_session_info *session_info,
544         int debug_level)
545 {
546         TALLOC_CTX *frame = NULL;
547
548         const char *ts = NULL;       /* formatted current time      */
549         char *remote_str = NULL;     /* formatted remote host       */
550         char *local_str = NULL;      /* formatted local host        */
551         char sid_buf[DOM_SID_STR_BUFLEN];
552
553         frame = talloc_stackframe();
554
555         /* Get the current time */
556         ts = audit_get_timestamp(frame);
557
558         remote_str = tsocket_address_string(remote, frame);
559         local_str = tsocket_address_string(local, frame);
560
561         dom_sid_string_buf(&session_info->security_token->sids[0],
562                            sid_buf,
563                            sizeof(sid_buf));
564
565         DEBUGC(DBGC_AUTH_AUDIT, debug_level,
566                ("Successful AuthZ: [%s,%s] user [%s]\\[%s] [%s]"
567                 " at [%s]"
568                 " Remote host [%s]"
569                 " local host [%s]\n",
570                 service_description,
571                 auth_type,
572                 log_escape(frame, session_info->info->domain_name),
573                 log_escape(frame, session_info->info->account_name),
574                 sid_buf,
575                 ts,
576                 remote_str,
577                 local_str));
578
579         talloc_free(frame);
580 }
581
582 /*
583  * Log details of a successful authorization to a service.
584  *
585  * Only successful authorizations are logged.  For clarity:
586  * - NTLM bad passwords will be recorded by log_authentication_event
587  * - Kerberos decrypt failures need to be logged in gensec_gssapi et al
588  *
589  * The service may later refuse authorization due to an ACL.
590  *
591  * NOTE: msg_ctx and lp_ctx is optional, but when supplied allows streaming the
592  * authentication events over the message bus.
593  */
594 void log_successful_authz_event(
595         struct imessaging_context *msg_ctx,
596         struct loadparm_context *lp_ctx,
597         const struct tsocket_address *remote,
598         const struct tsocket_address *local,
599         const char *service_description,
600         const char *auth_type,
601         const char *transport_protection,
602         struct auth_session_info *session_info)
603 {
604         int debug_level = AUTHZ_SUCCESS_LEVEL;
605
606         /* set the log level */
607         if (security_token_is_anonymous(session_info->security_token)) {
608                 debug_level = AUTH_ANONYMOUS_LEVEL;
609         }
610
611         if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT, debug_level)) {
612                 log_successful_authz_event_human_readable(remote,
613                                                           local,
614                                                           service_description,
615                                                           auth_type,
616                                                           transport_protection,
617                                                           session_info,
618                                                           debug_level);
619         }
620         if (CHECK_DEBUGLVLC(DBGC_AUTH_AUDIT_JSON, debug_level) ||
621             (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx))) {
622                 log_successful_authz_event_json(msg_ctx, lp_ctx,
623                                                 remote,
624                                                 local,
625                                                 service_description,
626                                                 auth_type,
627                                                 transport_protection,
628                                                 session_info,
629                                                 debug_level);
630         }
631 }