bpo-37363: Add audit events for a range of modules (GH-14301)

(cherry picked from commit 60419a7e96577cf783b3b45bf3984f9fb0d7ddff)

Co-authored-by: Steve Dower <steve.dower@python.org>
diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py
index 526dfd0..6f2569d 100644
--- a/Lib/ensurepip/__init__.py
+++ b/Lib/ensurepip/__init__.py
@@ -73,6 +73,8 @@
     if altinstall and default_pip:
         raise ValueError("Cannot use altinstall and default_pip together")
 
+    sys.audit("ensurepip.bootstrap", root)
+
     _disable_pip_configuration_settings()
 
     # By default, installing pip and setuptools installs all of the
diff --git a/Lib/ftplib.py b/Lib/ftplib.py
index a9b1aee..27bf6da 100644
--- a/Lib/ftplib.py
+++ b/Lib/ftplib.py
@@ -148,6 +148,7 @@
             self.timeout = timeout
         if source_address is not None:
             self.source_address = source_address
+        sys.audit("ftplib.FTP.connect", self, self.host, self.port)
         self.sock = socket.create_connection((self.host, self.port), self.timeout,
                                              source_address=self.source_address)
         self.af = self.sock.family
@@ -188,6 +189,7 @@
     def putline(self, line):
         if '\r' in line or '\n' in line:
             raise ValueError('an illegal newline character should not be contained')
+        sys.audit("ftplib.FTP.sendcmd", self, line)
         line = line + CRLF
         if self.debugging > 1:
             print('*put*', self.sanitize(line))
diff --git a/Lib/glob.py b/Lib/glob.py
index 002cd92..0b3fcc6 100644
--- a/Lib/glob.py
+++ b/Lib/glob.py
@@ -3,6 +3,7 @@
 import os
 import re
 import fnmatch
+import sys
 
 __all__ = ["glob", "iglob", "escape"]
 
@@ -37,6 +38,7 @@
     return it
 
 def _iglob(pathname, recursive, dironly):
+    sys.audit("glob.glob", pathname, recursive)
     dirname, basename = os.path.split(pathname)
     if not has_magic(pathname):
         assert not dironly
diff --git a/Lib/imaplib.py b/Lib/imaplib.py
index 341ee25..face45b 100644
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -289,6 +289,7 @@
         # (which is used by socket.create_connection()) expects None
         # as a default value for host.
         host = None if not self.host else self.host
+        sys.audit("imaplib.IMAP4.open", self, self.host, self.port)
         return socket.create_connection((host, self.port))
 
     def open(self, host = '', port = IMAP4_PORT):
@@ -318,6 +319,7 @@
 
     def send(self, data):
         """Send data to remote."""
+        sys.audit("imaplib.IMAP4.send", self, data)
         self.sock.sendall(data)
 
 
diff --git a/Lib/nntplib.py b/Lib/nntplib.py
index 5961a28..e7bbc85 100644
--- a/Lib/nntplib.py
+++ b/Lib/nntplib.py
@@ -68,6 +68,7 @@
 import collections
 import datetime
 import warnings
+import sys
 
 try:
     import ssl
@@ -413,6 +414,7 @@
     def _putline(self, line):
         """Internal: send one line to the server, appending CRLF.
         The `line` must be a bytes-like object."""
+        sys.audit("nntplib.NNTP.putline", self, line)
         line = line + _CRLF
         if self.debugging > 1: print('*put*', repr(line))
         self.file.write(line)
@@ -1040,6 +1042,7 @@
         """
         self.host = host
         self.port = port
+        sys.audit("nntplib.NNTP", self, host, port)
         self.sock = socket.create_connection((host, port), timeout)
         file = None
         try:
@@ -1071,6 +1074,7 @@
             """This works identically to NNTP.__init__, except for the change
             in default port and the `ssl_context` argument for SSL connections.
             """
+            sys.audit("nntplib.NNTP", self, host, port)
             self.sock = socket.create_connection((host, port), timeout)
             file = None
             try:
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 0e7609e..5e62f39 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -141,6 +141,7 @@
                  nosigint=False, readrc=True):
         bdb.Bdb.__init__(self, skip=skip)
         cmd.Cmd.__init__(self, completekey, stdin, stdout)
+        sys.audit("pdb.Pdb")
         if stdout:
             self.use_rawinput = 0
         self.prompt = '(Pdb) '
diff --git a/Lib/poplib.py b/Lib/poplib.py
index 9796f0d..ced0a2d 100644
--- a/Lib/poplib.py
+++ b/Lib/poplib.py
@@ -16,6 +16,7 @@
 import errno
 import re
 import socket
+import sys
 
 try:
     import ssl
@@ -99,6 +100,7 @@
         self.host = host
         self.port = port
         self._tls_established = False
+        sys.audit("poplib.POP3", self, host, port)
         self.sock = self._create_socket(timeout)
         self.file = self.sock.makefile('rb')
         self._debugging = 0
@@ -109,6 +111,7 @@
 
     def _putline(self, line):
         if self._debugging > 1: print('*put*', repr(line))
+        sys.audit("poplib.POP3.putline", self, line)
         self.sock.sendall(line + CRLF)
 
 
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 6486cd6..ab1a7d6 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -530,6 +530,7 @@
     function that supports the same signature (like copy()) can be used.
 
     """
+    sys.audit("shutil.copytree", src, dst)
     with os.scandir(src) as entries:
         return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks,
                          ignore=ignore, copy_function=copy_function,
@@ -640,6 +641,7 @@
     is false and onerror is None, an exception is raised.
 
     """
+    sys.audit("shutil.rmtree", path)
     if ignore_errors:
         def onerror(*args):
             pass
@@ -965,6 +967,7 @@
     'owner' and 'group' are used when creating a tar archive. By default,
     uses the current owner and group.
     """
+    sys.audit("shutil.make_archive", base_name, format, root_dir, base_dir)
     save_cwd = os.getcwd()
     if root_dir is not None:
         if logger is not None:
diff --git a/Lib/smtplib.py b/Lib/smtplib.py
index 3c5ac75..01f3d43 100755
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -335,6 +335,7 @@
             port = self.default_port
         if self.debuglevel > 0:
             self._print_debug('connect:', (host, port))
+        sys.audit("smtplib.SMTP.connect", self, host, port)
         self.sock = self._get_socket(host, port, self.timeout)
         self.file = None
         (code, msg) = self.getreply()
@@ -352,6 +353,7 @@
                 # should not be used, but 'data' needs to convert the string to
                 # binary itself anyway, so that's not a problem.
                 s = s.encode(self.command_encoding)
+            sys.audit("smtplib.SMTP.send", self, s)
             try:
                 self.sock.sendall(s)
             except OSError:
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index d34c578..c0bda96 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -1268,6 +1268,11 @@
                 comspec = os.environ.get("COMSPEC", "cmd.exe")
                 args = '{} /c "{}"'.format (comspec, args)
 
+            if cwd is not None:
+                cwd = os.fsdecode(cwd)
+
+            sys.audit("subprocess.Popen", executable, args, cwd, env)
+
             # Start the process
             try:
                 hp, ht, pid, tid = _winapi.CreateProcess(executable, args,
@@ -1276,7 +1281,7 @@
                                          int(not close_fds),
                                          creationflags,
                                          env,
-                                         os.fsdecode(cwd) if cwd is not None else None,
+                                         cwd,
                                          startupinfo)
             finally:
                 # Child is launched. Close the parent's copy of those pipe
@@ -1543,6 +1548,8 @@
             if executable is None:
                 executable = args[0]
 
+            sys.audit("subprocess.Popen", executable, args, cwd, env)
+
             if (_USE_POSIX_SPAWN
                     and os.path.dirname(executable)
                     and preexec_fn is None
diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py
index b9d45b4..8ce053e 100644
--- a/Lib/telnetlib.py
+++ b/Lib/telnetlib.py
@@ -231,6 +231,7 @@
         self.host = host
         self.port = port
         self.timeout = timeout
+        sys.audit("telnetlib.Telnet.open", self, host, port)
         self.sock = socket.create_connection((host, port), timeout)
 
     def __del__(self):
@@ -286,6 +287,7 @@
         """
         if IAC in buffer:
             buffer = buffer.replace(IAC, IAC+IAC)
+        sys.audit("telnetlib.Telnet.write", self, buffer)
         self.msg("send %r", buffer)
         self.sock.sendall(buffer)
 
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index e8b111e..45709cb 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -43,6 +43,7 @@
 import shutil as _shutil
 import errno as _errno
 from random import Random as _Random
+import sys as _sys
 import weakref as _weakref
 import _thread
 _allocate_lock = _thread.allocate_lock
@@ -244,6 +245,7 @@
     for seq in range(TMP_MAX):
         name = next(names)
         file = _os.path.join(dir, pre + name + suf)
+        _sys.audit("tempfile.mkstemp", file)
         try:
             fd = _os.open(file, flags, 0o600)
         except FileExistsError:
@@ -352,6 +354,7 @@
     for seq in range(TMP_MAX):
         name = next(names)
         file = _os.path.join(dir, prefix + name + suffix)
+        _sys.audit("tempfile.mkdtemp", file)
         try:
             _os.mkdir(file, 0o700)
         except FileExistsError:
@@ -546,7 +549,7 @@
         _os.close(fd)
         raise
 
-if _os.name != 'posix' or _os.sys.platform == 'cygwin':
+if _os.name != 'posix' or _sys.platform == 'cygwin':
     # On non-POSIX and Cygwin systems, assume that we cannot unlink a file
     # while it is open.
     TemporaryFile = NamedTemporaryFile
diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
index 82bff83..0af36c4 100755
--- a/Lib/webbrowser.py
+++ b/Lib/webbrowser.py
@@ -154,6 +154,7 @@
         self.basename = os.path.basename(self.name)
 
     def open(self, url, new=0, autoraise=True):
+        sys.audit("webbrowser.open", url)
         cmdline = [self.name] + [arg.replace("%s", url)
                                  for arg in self.args]
         try:
@@ -173,6 +174,7 @@
     def open(self, url, new=0, autoraise=True):
         cmdline = [self.name] + [arg.replace("%s", url)
                                  for arg in self.args]
+        sys.audit("webbrowser.open", url)
         try:
             if sys.platform[:3] == 'win':
                 p = subprocess.Popen(cmdline)
@@ -201,7 +203,7 @@
     remote_action_newwin = None
     remote_action_newtab = None
 
-    def _invoke(self, args, remote, autoraise):
+    def _invoke(self, args, remote, autoraise, url=None):
         raise_opt = []
         if remote and self.raise_opts:
             # use autoraise argument only for remote invocation
@@ -237,6 +239,7 @@
             return not p.wait()
 
     def open(self, url, new=0, autoraise=True):
+        sys.audit("webbrowser.open", url)
         if new == 0:
             action = self.remote_action
         elif new == 1:
@@ -253,7 +256,7 @@
         args = [arg.replace("%s", url).replace("%action", action)
                 for arg in self.remote_args]
         args = [arg for arg in args if arg]
-        success = self._invoke(args, True, autoraise)
+        success = self._invoke(args, True, autoraise, url)
         if not success:
             # remote invocation failed, try straight way
             args = [arg.replace("%s", url) for arg in self.args]
@@ -337,6 +340,7 @@
     """
 
     def open(self, url, new=0, autoraise=True):
+        sys.audit("webbrowser.open", url)
         # XXX Currently I know no way to prevent KFM from opening a new win.
         if new == 2:
             action = "newTab"
@@ -420,6 +424,7 @@
         return 1
 
     def open(self, url, new=0, autoraise=True):
+        sys.audit("webbrowser.open", url)
         if new:
             ok = self._remote("LOADNEW " + url)
         else:
@@ -577,6 +582,7 @@
 if sys.platform[:3] == "win":
     class WindowsDefault(BaseBrowser):
         def open(self, url, new=0, autoraise=True):
+            sys.audit("webbrowser.open", url)
             try:
                 os.startfile(url)
             except OSError:
@@ -606,6 +612,7 @@
             self.name = name
 
         def open(self, url, new=0, autoraise=True):
+            sys.audit("webbrowser.open", url)
             assert "'" not in url
             # hack for local urls
             if not ':' in url: