CVE-2022-38023 s3:rpc_server/netlogon: Avoid unnecessary loadparm_context allocations
[samba.git] / bootstrap / config.py
1 #!/usr/bin/env python3
2
3 # Copyright (C) Catalyst.Net Ltd 2019
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 """
19 Manage dependencies and bootstrap environments for Samba.
20
21 Config file for packages and templates.
22
23 Update the lists in this file to require new packages in the
24 container images used in GitLab CI
25
26 Author: Joe Guo <joeg@catalyst.net.nz>
27 """
28 import os
29 from os.path import abspath, dirname, join
30 HERE = abspath(dirname(__file__))
31 # output dir for rendered files
32 OUT = join(HERE, 'generated-dists')
33
34
35 # pkgs with same name in all packaging systems
36 COMMON = [
37     'acl',
38     'attr',
39     'autoconf',
40     'binutils',
41     'bison',
42     'ccache',
43     'curl',
44     'chrpath',
45     'flex',
46     'gcc',
47     'gdb',
48     'git',
49     'gzip',
50     'hostname',
51     'htop',
52     'lcov',
53     'make',
54     'patch',
55     'perl',
56     'psmisc',  # for pstree in test
57     'rng-tools',
58     'rsync',
59     'sed',
60     'sudo',  # docker images has no sudo by default
61     'tar',
62     'tree',
63     'wget',
64 ]
65
66
67 # define pkgs for all packaging systems in parallel
68 # make it easier to find missing ones
69 # use latest ubuntu and fedora as defaults
70 # deb, rpm, ...
71 PKGS = [
72     # NAME1-dev, NAME2-devel
73     ('lmdb-utils', 'lmdb'),
74     ('mingw-w64', 'mingw64-gcc'),
75     ('zlib1g-dev', 'zlib-devel'),
76     ('libbsd-dev', 'libbsd-devel'),
77     ('liburing-dev', 'liburing-devel'),
78     ('libarchive-dev', 'libarchive-devel'),
79     ('libblkid-dev', 'libblkid-devel'),
80     ('libcap-dev', 'libcap-devel'),
81     ('libacl1-dev', 'libacl-devel'),
82     ('libattr1-dev', 'libattr-devel'),
83
84     # libNAME1-dev, NAME2-devel
85     ('libpopt-dev', 'popt-devel'),
86     ('libreadline-dev', 'readline-devel'),
87     ('libjansson-dev', 'jansson-devel'),
88     ('liblmdb-dev', 'lmdb-devel'),
89     ('libncurses5-dev', 'ncurses-devel'),
90     # NOTE: Debian 7+ or Ubuntu 16.04+
91     ('libsystemd-dev', 'systemd-devel'),
92     ('libkrb5-dev', 'krb5-devel'),
93     ('libldap2-dev', 'openldap-devel'),
94     ('libcups2-dev', 'cups-devel'),
95     ('libpam0g-dev', 'pam-devel'),
96     ('libgpgme11-dev', 'gpgme-devel'),
97     # NOTE: Debian 8+ and Ubuntu 14.04+
98     ('libgnutls28-dev', 'gnutls-devel'),
99     ('libtasn1-bin', 'libtasn1-tools'),
100     ('libtasn1-dev', 'libtasn1-devel'),
101     ('', 'quota-devel'),
102     ('uuid-dev', 'libuuid-devel'),
103     ('libjs-jquery', ''),
104     ('libavahi-common-dev', 'avahi-devel'),
105     ('libdbus-1-dev', 'dbus-devel'),
106     ('libpcap-dev', 'libpcap-devel'),
107     ('libunwind-dev', 'libunwind-devel'),  # for back trace
108     ('libglib2.0-dev', 'glib2-devel'),
109     ('libicu-dev', 'libicu-devel'),
110     ('heimdal-multidev', ''),
111
112     # NAME1, NAME2
113     # for debian, locales provide locale support with language packs
114     # ubuntu split language packs to language-pack-xx
115     # for centos, glibc-common provide locale support with language packs
116     # fedora split language packs  to glibc-langpack-xx
117     ('locales', 'glibc-common'),  # required for locale
118     ('language-pack-en', 'glibc-langpack-en'),  # we need en_US.UTF-8
119     ('bind9utils', 'bind-utils'),
120     ('dnsutils', ''),
121     ('xsltproc', 'libxslt'),
122     ('krb5-user', 'krb5-workstation'),
123     ('krb5-config', ''),
124     ('krb5-kdc', 'krb5-server'),
125     ('apt-utils', 'yum-utils'),
126     ('pkg-config', 'pkgconfig'),
127     ('procps', 'procps-ng'),  # required for the free cmd in tests
128     ('lsb-release', 'lsb-release'),  # we need lsb_relase to show info
129     ('', 'rpcgen'),  # required for test
130     # refer: https://fedoraproject.org/wiki/Changes/SunRPCRemoval
131     ('', 'libtirpc-devel'),  # for <rpc/rpc.h> header on fedora
132     ('', 'rpcsvc-proto-devel'), # for <rpcsvc/rquota.h> header
133     ('mawk', 'gawk'),
134
135     ('python3', 'python3'),
136     ('python3-cryptography', 'python3-cryptography'), # for krb5 tests
137     ('python3-dev', 'python3-devel'),
138     ('python3-dbg', ''),
139     ('python3-iso8601', 'python3-iso8601'),
140     ('python3-gpg', 'python3-gpg'),  # defaults to ubuntu/fedora latest
141     ('python3-markdown', 'python3-markdown'),
142     ('python3-matplotlib', ''),
143     ('python3-dnspython', 'python3-dns'),
144     ('python3-pexpect', ''),  # for wintest only
145     ('python3-pyasn1', 'python3-pyasn1'), # for krb5 tests
146     ('python3-setproctitle', 'python3-setproctitle'),
147
148     ('', 'libsemanage-python'),
149     ('', 'policycoreutils-python'),
150
151     # perl
152     ('libparse-yapp-perl', 'perl-Parse-Yapp'),
153     ('libjson-perl', 'perl-JSON'),
154     ('', 'perl-JSON-Parse'),
155     ('perl-modules', ''),
156     ('', 'perl-FindBin'),
157     ('', 'perl-Archive-Tar'),
158     ('', 'perl-ExtUtils-MakeMaker'),
159     ('', 'perl-Test-Base'),
160     ('', 'perl-generators'),
161     ('', 'perl-interpreter'),
162
163     # fs
164     ('xfslibs-dev', 'xfsprogs-devel'), # for xfs quota support
165     ('', 'glusterfs-api-devel'),
166     ('glusterfs-common', 'glusterfs-devel'),
167     ('libcephfs-dev', 'libcephfs-devel'),
168
169     # spotlight
170     ('libtracker-sparql-2.0-dev', 'tracker-devel'),
171
172     # misc
173     # @ means group for rpm, use fedora as rpm default
174     ('build-essential', '@development-tools'),
175     ('debhelper', ''),
176     # rpm has no pkg for docbook-xml
177     ('docbook-xml', 'docbook-dtds'),
178     ('docbook-xsl', 'docbook-style-xsl'),
179     ('', 'keyutils-libs-devel'),
180     ('', 'which'),
181 ]
182
183
184 DEB_PKGS = COMMON + [pkg for pkg, _ in PKGS if pkg]
185 RPM_PKGS = COMMON + [pkg for _, pkg in PKGS if pkg]
186
187 GENERATED_MARKER = r"""
188 #
189 # This file is generated by 'bootstrap/template.py --render'
190 # See also bootstrap/config.py
191 #
192 """
193
194
195 APT_BOOTSTRAP = r"""
196 #!/bin/bash
197 {GENERATED_MARKER}
198 set -xueo pipefail
199
200 export DEBIAN_FRONTEND=noninteractive
201 apt-get -y update
202
203 apt-get -y install \
204     {pkgs}
205
206 apt-get -y autoremove
207 apt-get -y autoclean
208 apt-get -y clean
209 """
210
211
212 YUM_BOOTSTRAP = r"""
213 #!/bin/bash
214 {GENERATED_MARKER}
215 set -xueo pipefail
216
217 yum update -y
218 yum install -y epel-release
219 yum install -y yum-plugin-copr
220 yum copr enable -y sergiomb/SambaAD
221 yum update -y
222
223 yum install -y \
224     {pkgs}
225
226 yum clean all
227
228 if [ ! -f /usr/bin/python3 ]; then
229     ln -sf /usr/bin/python3.6 /usr/bin/python3
230 fi
231 """
232
233 CENTOS8S_YUM_BOOTSTRAP = r"""
234 #!/bin/bash
235 {GENERATED_MARKER}
236 set -xueo pipefail
237
238 yum update -y
239 yum install -y dnf-plugins-core
240 yum install -y epel-release
241
242 yum -v repolist all
243 yum config-manager --set-enabled powertools -y || \
244     yum config-manager --set-enabled powertools -y
245
246 yum update -y
247
248 yum install -y \
249     --setopt=install_weak_deps=False \
250     {pkgs}
251
252 yum clean all
253 """
254
255 DNF_BOOTSTRAP = r"""
256 #!/bin/bash
257 {GENERATED_MARKER}
258 set -xueo pipefail
259
260 dnf update -y
261
262 dnf install -y \
263     --setopt=install_weak_deps=False \
264     {pkgs}
265
266 dnf clean all
267 """
268
269 ZYPPER_BOOTSTRAP = r"""
270 #!/bin/bash
271 {GENERATED_MARKER}
272 set -xueo pipefail
273
274 zypper --non-interactive refresh
275 zypper --non-interactive update
276 zypper --non-interactive install \
277     --no-recommends \
278     system-user-nobody \
279     {pkgs}
280
281 zypper --non-interactive clean
282
283 if [ -f /usr/lib/mit/bin/krb5-config ]; then
284     ln -sf /usr/lib/mit/bin/krb5-config /usr/bin/krb5-config
285 fi
286 """
287
288 # A generic shell script to setup locale
289 LOCALE_SETUP = r"""
290 #!/bin/bash
291 {GENERATED_MARKER}
292 set -xueo pipefail
293
294 # refer to /usr/share/i18n/locales
295 INPUTFILE=en_US
296 # refer to /usr/share/i18n/charmaps
297 CHARMAP=UTF-8
298 # locale to generate in /usr/lib/locale
299 # glibc/localedef will normalize UTF-8 to utf8, follow the naming style
300 LOCALE=$INPUTFILE.utf8
301
302 # if locale is already correct, exit
303 ( locale | grep LC_ALL | grep -i $LOCALE ) && exit 0
304
305 # if locale not available, generate locale into /usr/lib/locale
306 if ! ( locale --all-locales | grep -i $LOCALE )
307 then
308     # no-archive means create its own dir
309     localedef --inputfile $INPUTFILE --charmap $CHARMAP --no-archive $LOCALE
310 fi
311
312 # update locale conf and global env file
313 # set both LC_ALL and LANG for safe
314
315 # update conf for Debian family
316 FILE=/etc/default/locale
317 if [ -f $FILE ]
318 then
319     echo LC_ALL="$LOCALE" > $FILE
320     echo LANG="$LOCALE" >> $FILE
321 fi
322
323 # update conf for RedHat family
324 FILE=/etc/locale.conf
325 if [ -f $FILE ]
326 then
327     # LC_ALL is not valid in this file, set LANG only
328     echo LANG="$LOCALE" > $FILE
329 fi
330
331 # update global env file
332 FILE=/etc/environment
333 if [ -f $FILE ]
334 then
335     # append LC_ALL if not exist
336     grep LC_ALL $FILE || echo LC_ALL="$LOCALE" >> $FILE
337     # append LANG if not exist
338     grep LANG $FILE || echo LANG="$LOCALE" >> $FILE
339 fi
340 """
341
342
343 DOCKERFILE = r"""
344 {GENERATED_MARKER}
345 FROM {docker_image}
346
347 # pass in with --build-arg while build
348 ARG SHA1SUM
349 RUN [ -n $SHA1SUM ] && echo $SHA1SUM > /sha1sum.txt
350
351 ADD *.sh /tmp/
352 # need root permission, do it before USER samba
353 RUN /tmp/bootstrap.sh && /tmp/locale.sh
354
355 # if ld.gold exists, force link it to ld
356 RUN set -x; LD=$(which ld); LD_GOLD=$(which ld.gold); test -x $LD_GOLD && ln -sf $LD_GOLD $LD && test -x $LD && echo "$LD is now $LD_GOLD"
357
358 # make test can not work with root, so we have to create a new user
359 RUN useradd -m -U -s /bin/bash samba && \
360     mkdir -p /etc/sudoers.d && \
361     echo "samba ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/samba
362
363 USER samba
364 WORKDIR /home/samba
365 # samba tests rely on this
366 ENV USER=samba LC_ALL=en_US.utf8 LANG=en_US.utf8
367 """
368
369 # Vagrantfile snippet for each dist
370 VAGRANTFILE_SNIPPET = r"""
371     config.vm.define "{name}" do |v|
372         v.vm.box = "{vagrant_box}"
373         v.vm.hostname = "{name}"
374         v.vm.provision :shell, path: "{name}/bootstrap.sh"
375         v.vm.provision :shell, path: "{name}/locale.sh"
376     end
377 """
378
379 # global Vagrantfile with snippets for all dists
380 VAGRANTFILE_GLOBAL = r"""
381 {GENERATED_MARKER}
382
383 Vagrant.configure("2") do |config|
384     config.ssh.insert_key = false
385
386 {vagrantfile_snippets}
387
388 end
389 """
390
391
392 DEB_DISTS = {
393     'debian10': {
394         'docker_image': 'debian:10',
395         'vagrant_box': 'debian/buster64',
396         'replace': {
397             'language-pack-en': '',   # included in locales
398             'liburing-dev': '',   # not available
399         }
400     },
401     'debian11': {
402         'docker_image': 'debian:11',
403         'vagrant_box': 'debian/bullseye64',
404         'replace': {
405             'language-pack-en': '',   # included in locales
406         }
407     },
408     'ubuntu1604': {
409         'docker_image': 'ubuntu:16.04',
410         'vagrant_box': 'ubuntu/xenial64',
411         'replace': {
412             'python3-gpg': 'python3-gpgme',
413             'glusterfs-common': '',
414             'libcephfs-dev': '',
415             'liburing-dev': '',   # not available
416             'libtracker-sparql-2.0-dev': '', # not available
417         }
418     },
419     'ubuntu1804': {
420         'docker_image': 'ubuntu:18.04',
421         'vagrant_box': 'ubuntu/bionic64',
422         'replace': {
423             'liburing-dev': '',   # not available
424         }
425     },
426     'ubuntu2004': {
427         'docker_image': 'ubuntu:20.04',
428         'vagrant_box': 'ubuntu/focal64',
429         'replace': {
430             'liburing-dev': '',   # not available
431         }
432     },
433 }
434
435
436 RPM_DISTS = {
437     'centos7': {
438         'docker_image': 'centos:7',
439         'vagrant_box': 'centos/7',
440         'bootstrap': YUM_BOOTSTRAP,
441         'replace': {
442             'lsb-release': 'redhat-lsb',
443             'python3': 'python36',
444             'python3-cryptography': 'python36-cryptography',
445             'python3-devel': 'python36-devel',
446             'python3-dns': 'python36-dns',
447             'python3-pyasn1': 'python36-pyasn1',
448             'python3-gpg': 'python36-gpg',
449             'python3-iso8601' : 'python36-iso8601',
450             'python3-markdown': 'python36-markdown',
451             # although python36-devel is available
452             # after epel-release installed
453             # however, all other python3 pkgs are still python36-ish
454             'python2-gpg': 'pygpgme',
455             'python3-gpg': '',  # no python3-gpg yet
456             '@development-tools': '"@Development Tools"',  # add quotes
457             'glibc-langpack-en': '',  # included in glibc-common
458             'glibc-locale-source': '',  # included in glibc-common
459             # update perl core modules on centos
460             # fix: Can't locate Archive/Tar.pm in @INC
461             'perl': 'perl-core',
462             'perl-FindBin': '',
463             'rpcsvc-proto-devel': '',
464             'glusterfs-api-devel': '',
465             'glusterfs-devel': '',
466             'libcephfs-devel': '',
467             'gnutls-devel': 'compat-gnutls34-devel',
468             'liburing-devel': '',   # not available
469             'python3-setproctitle': 'python36-setproctitle',
470             'tracker-devel': '', # do not install
471         }
472     },
473     'centos8s': {
474         'docker_image': 'quay.io/centos/centos:stream8',
475         'vagrant_box': 'centos/stream8',
476         'bootstrap': CENTOS8S_YUM_BOOTSTRAP,
477         'replace': {
478             'lsb-release': 'redhat-lsb',
479             '@development-tools': '"@Development Tools"',  # add quotes
480             'libsemanage-python': 'python3-libsemanage',
481             'lcov': '', # does not exist
482             'perl-JSON-Parse': '', # does not exist?
483             'perl-Test-Base': 'perl-Test-Simple',
484             'perl-FindBin': '',
485             'policycoreutils-python': 'python3-policycoreutils',
486             'liburing-devel': '', # not available yet, Add me back, once available!
487         }
488     },
489     'fedora33': {
490         'docker_image': 'fedora:33',
491         'vagrant_box': 'fedora/33-cloud-base',
492         'bootstrap': DNF_BOOTSTRAP,
493         'replace': {
494             'lsb-release': 'redhat-lsb',
495             'libsemanage-python': 'python3-libsemanage',
496             'policycoreutils-python': 'python3-policycoreutils',
497             'python3-iso8601': 'python3-dateutil',
498         }
499     },
500     'fedora34': {
501         'docker_image': 'fedora:34',
502         'vagrant_box': 'fedora/34-cloud-base',
503         'bootstrap': DNF_BOOTSTRAP,
504         'replace': {
505             'lsb-release': 'redhat-lsb',
506             'libsemanage-python': 'python3-libsemanage',
507             'policycoreutils-python': 'python3-policycoreutils',
508             'perl-FindBin': '',
509             'python3-iso8601': 'python3-dateutil',
510             'libtracker-sparql-2.0-dev': '', # only tracker 3.x is available
511         }
512     },
513     'opensuse151': {
514         'docker_image': 'opensuse/leap:15.1',
515         'vagrant_box': 'opensuse/openSUSE-15.1-x86_64',
516         'bootstrap': ZYPPER_BOOTSTRAP,
517         'replace': {
518             '@development-tools': '',
519             'dbus-devel': 'dbus-1-devel',
520             'docbook-style-xsl': 'docbook-xsl-stylesheets',
521             'glibc-common': 'glibc-locale',
522             'glibc-locale-source': 'glibc-i18ndata',
523             'glibc-langpack-en': '',
524             'jansson-devel': 'libjansson-devel',
525             'keyutils-libs-devel': 'keyutils-devel',
526             'krb5-workstation': 'krb5-client',
527             'libsemanage-python': 'python2-semanage',
528             'openldap-devel': 'openldap2-devel',
529             'perl-Archive-Tar': 'perl-Archive-Tar-Wrapper',
530             'perl-JSON-Parse': 'perl-JSON-XS',
531             'perl-generators': '',
532             'perl-interpreter': '',
533             'perl-FindBin': '',
534             'procps-ng': 'procps',
535             'python3-dns': 'python3-dnspython',
536             'python3-markdown': 'python3-Markdown',
537             'quota-devel': '',
538             'glusterfs-api-devel': '',
539             'libtasn1-tools': '', # asn1Parser is part of libtasn1
540             'mingw64-gcc': '', # doesn't exist
541             'liburing-devel': '',   # not available
542         }
543     },
544     'opensuse152': {
545         'docker_image': 'opensuse/leap:15.2',
546         'vagrant_box': 'opensuse/openSUSE-15.2-x86_64',
547         'bootstrap': ZYPPER_BOOTSTRAP,
548         'replace': {
549             '@development-tools': '',
550             'dbus-devel': 'dbus-1-devel',
551             'docbook-style-xsl': 'docbook-xsl-stylesheets',
552             'glibc-common': 'glibc-locale',
553             'glibc-locale-source': 'glibc-i18ndata',
554             'glibc-langpack-en': '',
555             'jansson-devel': 'libjansson-devel',
556             'keyutils-libs-devel': 'keyutils-devel',
557             'krb5-workstation': 'krb5-client',
558             'libsemanage-python': 'python2-semanage',
559             'openldap-devel': 'openldap2-devel',
560             'perl-Archive-Tar': 'perl-Archive-Tar-Wrapper',
561             'perl-JSON-Parse': 'perl-JSON-XS',
562             'perl-generators': '',
563             'perl-interpreter': '',
564             'perl-FindBin': '',
565             'procps-ng': 'procps',
566             'python3-iso8601': 'python3-python-dateutil',
567             'python3-dns': 'python3-dnspython',
568             'python3-markdown': 'python3-Markdown',
569             'quota-devel': '',
570             'glusterfs-api-devel': '',
571             'libtasn1-tools': '', # asn1Parser is part of libtasn1
572         }
573     }
574 }
575
576
577 DEB_FAMILY = {
578     'name': 'deb',
579     'pkgs': DEB_PKGS,
580     'bootstrap': APT_BOOTSTRAP,  # family default
581     'dists': DEB_DISTS,
582 }
583
584
585 RPM_FAMILY = {
586     'name': 'rpm',
587     'pkgs': RPM_PKGS,
588     'bootstrap': YUM_BOOTSTRAP,  # family default
589     'dists': RPM_DISTS,
590 }
591
592
593 YML_HEADER = r"""
594 ---
595 packages:
596 """
597
598
599 def expand_family_dists(family):
600     dists = {}
601     for name, config in family['dists'].items():
602         config = config.copy()
603         config['name'] = name
604         config['home'] = join(OUT, name)
605         config['family'] = family['name']
606         config['GENERATED_MARKER'] = GENERATED_MARKER
607
608         # replace dist specific pkgs
609         replace = config.get('replace', {})
610         pkgs = []
611         for pkg in family['pkgs']:
612             pkg = replace.get(pkg, pkg)  # replace if exists or get self
613             if pkg:
614                 pkgs.append(pkg)
615         pkgs.sort()
616
617         lines = ['  - {}'.format(pkg) for pkg in pkgs]
618         config['packages.yml'] = YML_HEADER.lstrip() + os.linesep.join(lines)
619
620         sep = ' \\' + os.linesep + '    '
621         config['pkgs'] = sep.join(pkgs)
622
623         # get dist bootstrap template or fall back to family default
624         bootstrap_template = config.get('bootstrap', family['bootstrap'])
625         config['bootstrap.sh'] = bootstrap_template.format(**config).strip()
626         config['locale.sh'] = LOCALE_SETUP.format(**config).strip()
627
628         config['Dockerfile'] = DOCKERFILE.format(**config).strip()
629         # keep the indent, no strip
630         config['vagrantfile_snippet'] = VAGRANTFILE_SNIPPET.format(**config)
631
632         dists[name] = config
633     return dists
634
635
636 # expanded config for dists
637 DEB_DISTS_EXP = expand_family_dists(DEB_FAMILY)
638 RPM_DISTS_EXP = expand_family_dists(RPM_FAMILY)
639
640 # assemble all together
641 DISTS = {}
642 DISTS.update(DEB_DISTS_EXP)
643 DISTS.update(RPM_DISTS_EXP)
644
645
646 def render_vagrantfile(dists):
647     """
648     Render all snippets for each dist into global Vagrantfile.
649
650     Vagrant supports multiple vms in one Vagrantfile.
651     This make it easier to manage the fleet, e.g:
652
653     start all: vagrant up
654     start one: vagrant up ubuntu1804
655
656     All other commands apply to above syntax, e.g.: status, destroy, provision
657     """
658     # sort dists by name and put all vagrantfile snippets together
659     snippets = [
660         dists[dist]['vagrantfile_snippet']
661         for dist in sorted(dists.keys())]
662
663     return VAGRANTFILE_GLOBAL.format(
664             vagrantfile_snippets=''.join(snippets),
665             GENERATED_MARKER=GENERATED_MARKER
666             )
667
668
669 VAGRANTFILE = render_vagrantfile(DISTS)
670
671
672 # data we need to expose
673 __all__ = ['DISTS', 'VAGRANTFILE', 'OUT']