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