Commit Graph

2264 Commits

Author SHA1 Message Date
Alan Somers
ca2d3691c3 Fix several Coverity warnings in tftp
Some of the changes are in the libexec/tftpd directory, but to functions that
are only used by tftp(1) (they share some code).

* strcpy => strlcpy (1006793, 1006794, 1006796, 1006741)
* Unchecked return value and TOCTTOU (1009314)
* NULL pointer dereference (1018035, 1018036)

Reported by:	Coverity
CID:		1006793, 1006794, 1006796, 1006741, 1009314, 1018035
CID:		1018036
MFC after:	2 weeks
2018-07-22 17:10:12 +00:00
Alan Somers
3c0fa26534 Fix multiple Coverity warnings in tftpd(8)
* Initialize uninitialized variable (CID 1006502)
* strcpy => strlcpy (CID 1006792, 1006791, 1006790)
* Check function return values (CID 1009442, 1009441, 1009440)
* Delete dead code in receive_packet (not reported by Coverity)
* Remove redundant alarm(3) in receive_packet (not reported by Coverity)

Reported by:	Coverity
CID: 1006502, 1006792, 1006791, 1006790, 1009442, 1009441, 1009440
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D11287
2018-07-22 16:14:30 +00:00
Alan Somers
7378015b69 tftpd(8): when completing an WRQ, flush the file before acknowleding receipt
tftpd(8) should flush a newly written file to disk before ACKing the final DATA
packet.  Otherwise there is a narrow race window when a subsequent read may not
see the file.  This is somewhat related to r330710, but the race window is much
smaller.  Hopefully this will fix the intermittent tests in Jenkins.

Reported by:	Jenkins
MFC after:	2 weeks
2018-07-21 19:48:31 +00:00
Sean Eric Fagan
aad5531e71 This exposes ZFS user and group quotas via the normal
quatactl(2) mechanism.  (Read-only at this point, however.)
In particular, this is to allow rpc.rquotad query quotas
for NFS mounts, allowing users to see their quotas on the
hosts using the datasets.

The changes specifically:

* Add new RPC entry points for querying quotas.
* Changes the library routines to allow non-UFS quotas.
* Changes rquotad to check for quotas on mounted filesystems,
rather than being limited to entries in /etc/fstab
* Lastly, adds a VFS entry-point for ZFS to query quotas.

Note that this makes one unavoidable behavioural change: if quotas
are enabled, then they can be queried, as opposed to the current
method of checking for quotas being specified in fstab.  (With
ZFS, if there are user or group quotas, they're used, always.)

Reviewed by:	delphij, mav
Approved by:	mav
Sponsored by:	iXsystems Inc
Differential Revision:	https://reviews.freebsd.org/D15886
2018-07-05 22:56:13 +00:00
Konstantin Belousov
0725fca53d Make rtld use libc_nossp_pic.a. Remove SSP shims.
Submitted by:	Luis Pires
Reviewed by:	brooks
Differential revision:	https://reviews.freebsd.org/D15341
2018-05-09 10:30:56 +00:00
Alan Somers
ad5c8bd63a tftpd: misc Coverity cleanup in the tests
A bunch of unchecked return values from open(2) and read(2)

Reported by:	Coverity
CID:		1386900, 1386911, 1386926, 1386928, 1386932, 1386942
CID:		1386961, 1386979
MFC after:	8 days
X-MFC-With:	330696
2018-03-22 14:51:05 +00:00
Alan Somers
f270fabc2b tftpd: fix the build of tests on i386 after 330696
It's those darn printf format specifiers again

Reported by:	cy, kibab
MFC after:	20 days
X-MFC-With:	330696
2018-03-10 18:07:31 +00:00
Alan Somers
6301d64774 tftpd: reject unknown opcodes
If tftpd receives a command with an unknown opcode, it simply exits 1.  It
doesn't send an ERROR packet, and the client will hang waiting for one.  Fix
it.

PR:		226005
MFC after:	3 weeks
2018-03-10 01:50:43 +00:00
Alan Somers
b7da179e96 tftpd: Abort on an WRQ access violation
On a WRQ (write request) tftpd checks whether the client has access
permission for the file in question.  If not, then the write is prevented.
However, tftpd doesn't reply with an ERROR packet, nor does it abort.
Instead, it tries to receive the packet anyway.

The symptom is slightly different depending on the nature of the error.  If
the target file is nonexistent and tftpd lacks permission to create it, then
tftpd will willingly receive the file, but not write it anywhere.  If the
file exists but is not writable, then tftpd will fail to ACK to WRQ.

PR:		225996
MFC after:	3 weeks
2018-03-10 01:43:55 +00:00
Alan Somers
d89aca7618 tftpd: Verify world-writability for WRQ when using relative paths
tftpd(8) says that files may only be written if they already exist and are
publicly writable.  tftpd.c verifies that a file is publicly writable if it
uses an absolute pathname.  However, if the pathname is relative, that check
is skipped.  Fix it.

Note that this is not a security vulnerability, because the transfer
ultimately doesn't work unless the file already exists and is owned by user
nobody.  Also, this bug does not affect the default configuration, because
the default uses the "-s" option which makes all pathnames absolute.

PR:		226004
MFC after:	3 weeks
2018-03-10 01:35:26 +00:00
Alan Somers
d3953c1f47 tftpd: Flush files as soon as they are fully received
On an RRQ, tftpd doesn't exit as soon as it's finished receiving a file.
Instead, it waits five seconds just in case the client didn't receive the
server's last ACK and decides to resend the final DATA packet.
Unfortunately, this created a 5 second delay from when the client thinks
it's done sending the file, and when the file is available for other
processes.

Fix this bug by closing the file as soon as receipt is finished.

PR:			157700
Reported by:		Barry Mishler <barry_mishler@yahoo.com>
MFC after:		3 weeks
2018-03-09 23:25:18 +00:00
Alan Somers
888651fcd9 Add some functional tests for tftpd(8)
tftpd(8) is difficult to test in isolation due to its relationship with
inetd.  Create a test program that mimics the behavior of tftp(1) and
inetd(8) and verifies tftpd's response in several different scenarios.

These test cases cover all of the basic TFTP protocol, but not the optional
parts.

PR:		157700
PR:		225996
PR:		226004
PR:		226005
MFC after:	3 weeks
Differential Revision:	https://reviews.freebsd.org/D14310
2018-03-09 15:30:20 +00:00
Alan Somers
ea8727d50d rpc.sprayd: raise WARNS to 6
MFC after:	3 weeks
2018-03-05 16:11:07 +00:00
Edward Tomasz Napierala
7a467312ef .Xr pstat(8), so that people have a chance to learn how to get a list
of terminal devices using "pstat -t".

MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-03-02 14:16:19 +00:00
Michal Meloun
fad101b3f2 Make rtld_bind_start() debugger friendly.
Save link register and annotate call frame structure so debugger can unwind
call frame created by rtld_bind_start().

MFC after:	2 weeks
2018-02-27 15:35:11 +00:00
Edward Tomasz Napierala
fe3f4a580a Fix gettytab(5) to document f0, f1, and f2 as unsupported; they've been gone
since r131091.

PR:             184691 (partial)
Submitted by:   naddy@
MFC after:      2 weeks
Sponsored by:   The FreeBSD Foundation
2018-02-26 17:51:18 +00:00
Edward Tomasz Napierala
170430d505 Prevent getty(8) from looping indefinitely if the device node doesn't
exist. This behaviour makes no sense for eg USB serial adapters, or
USB device-side serial templates.

This mostly reverts to pre-r135941 behaviour.

Reviewed by:	imp@
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D14198
2018-02-25 20:15:06 +00:00
Edward Tomasz Napierala
18587b84c5 Build getty(8) with WARNS=6.
Reviewed by:	imp@
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D14197
2018-02-21 15:57:24 +00:00
Edward Tomasz Napierala
9c33cc93cd Sprinkle static; avoid nested externs.
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-02-04 19:05:13 +00:00
Edward Tomasz Napierala
1776dc9fd6 Add missing initializer.
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-02-04 18:40:36 +00:00
Edward Tomasz Napierala
9a9a988e26 Rename getty's getline() to get_line(), to avoid clash with getline(3).
Obtained from:	DragonFlyBSD
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-02-04 18:39:58 +00:00
Edward Tomasz Napierala
076ec4025d Don't cast away the const, it's not been needed since r92925.
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-02-04 18:36:24 +00:00
Edward Tomasz Napierala
2ba8065021 Initialize all the fields. This is one of the steps required to bump WARNS.
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-02-04 13:58:31 +00:00
Edward Tomasz Napierala
04688610ae Reduce code duplication; no functional changes.
Obtained from:	NetBSD
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-02-04 13:55:20 +00:00
Edward Tomasz Napierala
6b1b6a5e28 Remove unused variable.
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
2018-02-04 13:54:05 +00:00
Marius Strobl
41fc6f680b o Let rtld(1) set up psABI user trap handlers prior to executing the
objects' init functions instead of doing the setup via a constructor
  in libc as the init functions may already depend on these handlers
  to be in place. This gets us rid of:
  - the undefined order in which libc constructors as __guard_setup()
    and jemalloc_constructor() are executed WRT __sparc_utrap_setup(),
  - the requirement to link libc last so __sparc_utrap_setup() gets
    called prior to constructors in other libraries (see r122883).
  For static binaries, crt1.o still sets up the user trap handlers.
o Move misplaced prototypes for MD functions in to the MD prototype
  section of rtld.h.
o Sprinkle nitems().
2018-02-03 23:14:11 +00:00
Pedro F. Giffuni
5ab6bac110 rpc.sprayd: Remove 3rd and 4th clauses in christos' license.
Obtained from:	NetBSD
2017-12-28 17:51:53 +00:00
Pedro F. Giffuni
bec1dbb67b rpc.sprayd: Bring some changes from NetBSD.
Most notable, other than some style issues:
CVS 1.11:
  do not use LOG_CONS.
CVS 1.13:
  consistently use exit instead of return in main().
  use LOG_WARNING instead of LOG_ERR for non critical errors.

Obtained from:	NetBSD
MFC after:	2 weeks
2017-12-28 17:44:30 +00:00
Xin LI
a9a7c8c0a1 Replace send-mail with the more standarized sendmail, we do not create
links for send-mail in mailwrapper so it did not work anyway.

MFC after:	2 weeks
2017-12-27 06:23:50 +00:00
Xin LI
69097cd8da Use strlcpy().
MFC after:	2 weeks
2017-12-05 07:21:47 +00:00
Pedro F. Giffuni
e6209940de libexec: adoption of SPDX licensing ID tags.
Mainly focus on files that use BSD 2-Clause license, however the tool I
was using misidentified many licenses so this was mostly a manual - error
prone - task.

The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.

No functional change intended.
2017-11-27 15:25:02 +00:00
Pedro F. Giffuni
8a16b7a18f General further adoption of SPDX licensing ID tags.
Mainly focus on files that use BSD 3-Clause license.

The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.

Special thanks to Wind River for providing access to "The Duke of
Highlander" tool: an older (2014) run over FreeBSD tree was useful as a
starting point.
2017-11-20 19:49:47 +00:00
Pedro F. Giffuni
df57947f08 spdx: initial adoption of licensing ID tags.
The Software Package Data Exchange (SPDX) group provides a specification
to make it easier for automated tools to detect and summarize well known
opensource licenses. We are gradually adopting the specification, noting
that the tags are considered only advisory and do not, in any way,
superceed or replace the license texts.

Special thanks to Wind River for providing access to "The Duke of
Highlander" tool: an older (2014) run over FreeBSD tree was useful as a
starting point.

Initially, only tag files that use BSD 4-Clause "Original" license.

RelNotes:	yes
Differential Revision:	https://reviews.freebsd.org/D13133
2017-11-18 14:26:50 +00:00
Edward Tomasz Napierala
ef4968d9e7 Increase rtld initial memory pool size from 32kB to 128kB.
The old value was probably fine back in 1998, when that code was imported
(although the comments still mention VAX, which was quite obsolete by then);
now, however, it's too small to handle our libc, which results in some
additional calls to munmap/mmap later on.  Asking for more virtual address
space is virtually free, and syscalls are not, thus the change.

It was suggested by kib@ that this might be a symptom of a deeper problem.
It doesn't only affect libc, though - the change also improves rtld memory
management for eg KDE libraries.  I guess it's just a natural bloat.

MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D12834
2017-11-18 13:21:22 +00:00
John Baldwin
f2515b1cc1 Appease old GCC by disabling .cfi_sections for GCC 4.x. 2017-11-14 17:16:03 +00:00
John Baldwin
a264cb726b Some fixups to the CFI directives for PLT stub entry points.
The directives I added in r323466 and r323501 did not define a valid
CFA until several instructions into the associated functions.  This
triggers an assertion in GDB when generating a stack trace while
stopped at the first instruction of PLT stub entry point since there
is no valid CFA rule for the first instruction.

This is probably just wrong on my part as the non-simple .cfi_startproc
would have defined a valid CFA.  Instead, define a valid CFA as sp + 0
at the start of the functions and then use .cfa_def_offset to change the
offset when sp is adjusted later in the function.

Sponsored by:	DARPA / AFRL
2017-11-10 01:17:26 +00:00
John Baldwin
c3faeef12c Use NESTED() instead of LEAF() for rtld_start.
This is only cosmetic, but the entry point for rtld is not a leaf function,
and this avoids two .frame directives for rtld_start.

Sponsored by:	DARPA / AFRL
2017-11-10 01:13:45 +00:00
Bryan Drewery
ea825d0274 DIRDEPS_BUILD: Update dependencies.
Sponsored by:	Dell EMC Isilon
2017-10-31 00:07:04 +00:00
Bryan Drewery
04760bd70d These values already set by src.libnames.mk.
MFC after:	2 weeks
Sponsored by:	Dell EMC Isilon
2017-10-31 00:03:25 +00:00
Edward Tomasz Napierala
be8f91d3d0 Use MAP_PRIVATE instead of obsolete MAP_COPY. No functional changes.
MFC after:	2 weeks
2017-10-30 08:56:04 +00:00
Edward Tomasz Napierala
152036a0f7 Plug memory leak on error case.
Reported by:	Coverity
CID:		1382112
MFC after:	2 weeks
2017-10-29 12:07:27 +00:00
Edward Tomasz Napierala
b4ed9a87f9 Remove unneeded calls to access(2) from rtld(1); just call open(2) instead.
The result looks like this:

--- przed       2017-10-21 23:19:21.445034000 +0100
+++ po  2017-10-21 23:18:50.031865000 +0100
@@ -11,7 +11,6 @@ mmap(0x0,102,PROT_READ,MAP_PRIVATE,3,0x0)      = 343665418
 close(3)                                        = 0 (0x0)
 open("/usr/local/etc/libmap.d",O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC,0165) ERR#2 'No such file or directory'
 munmap(0x80067d000,102)                                 = 0 (0x0)
-access("/usr/local/lib/libintl.so.8",F_OK)      = 0 (0x0)
 openat(AT_FDCWD,"/usr/local/lib/libintl.so.8",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
 fstat(3,{ mode=-rw-r--r-- ,inode=642560,size=55188,blksize=32768 }) = 0 (0x0)
 mmap(0x0,4096,PROT_READ,MAP_PRIVATE|MAP_PREFAULT_READ,3,0x0) = 34366541824 (0x80067d000)
@@ -20,14 +19,13 @@ mmap(0x800877000,40960,PROT_READ|PROT_EXEC,MAP_PRIVATE
 mmap(0x800a81000,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED|MAP_PREFAULT_READ,3,0xa000) = 34370752512 (0x800a81000)
 munmap(0x80067d000,4096)                        = 0 (0x0)
 close(3)                                        = 0 (0x0)
-access("/usr/local/lib/libc.so.7",F_OK)                 ERR#2 'No such file or directory'
+openat(AT_FDCWD,"/usr/local/lib/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) ERR#2 'No such file or directory'
 openat(AT_FDCWD,"/var/run/ld-elf.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
 read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\M-2\0\0"...,128) = 128 (0x80)
 fstat(3,{ mode=-r--r--r-- ,inode=970684,size=306,blksize=32768 }) = 0 (0x0)
 lseek(3,0x80,SEEK_SET)                          = 128 (0x80)
 read(3,"/lib:/usr/lib:/usr/lib/compat:/u"...,178) = 178 (0xb2)
 close(3)                                        = 0 (0x0)
-access("/lib/libc.so.7",F_OK)                   = 0 (0x0)
 openat(AT_FDCWD,"/lib/libc.so.7",O_RDONLY|O_CLOEXEC|O_VERIFY,00) = 3 (0x3)
 fstat(3,{ mode=-r--r--r-- ,inode=1605239,size=1910320,blksize=32768 }) = 0 (0x0)
 mmap(0x0,4096,PROT_READ,MAP_PRIVATE|MAP_PREFAULT_READ,3,0x0) = 34366541824 (0x80067d000)

Reviewed by:	kib
MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D12766
2017-10-24 12:56:08 +00:00
Edward Tomasz Napierala
2fe071d971 Replace lseek(2)/read(2) pair with pread(2), removing yet another syscall
from the binary startup code.

MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
2017-10-24 12:04:07 +00:00
Edward Tomasz Napierala
1689a3c4ac Make find_library() conform to style(9). No functional changes.
Suggested by:	kib
MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
2017-10-24 11:24:54 +00:00
Edward Tomasz Napierala
e65ad973b2 Reword the conditional; it was ugly, and adding another parameter,
which I'm going to do in a subsequent commit, would make it even uglier.
No functional changes.

MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
2017-10-24 11:16:38 +00:00
Edward Tomasz Napierala
a8b31c14d2 Use xmalloc and read(2) instead of mmap(2) to read in libmap.conf(5).
This removes the need to call munmap(2) afterwards.

MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D12767
2017-10-24 10:48:26 +00:00
Edward Tomasz Napierala
6b61e3e47a Don't call realpath(3) from libmap rtld code. This gets rid of a few calls
to fstatat(2) at binary startup; the difference looks like this:

--- przed       2017-10-14 13:55:49.983528000 +0100
+++ po  2017-10-14 14:10:39.134343000 +0100
@@ -1,15 +1,10 @@
 mmap(0x0,32768,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34366173184 (0x800623000)
 issetugid()                                     = 0 (0x0)
-fstatat(AT_FDCWD,"/etc",{ mode=drwxr-xr-x ,inode=1364352,size=2560,blksize=32768 },AT_SYMLINK_NOFOLLOW) = 0 (0x0)
-fstatat(AT_FDCWD,"/etc/libmap.conf",{ mode=-rw-r--r-- ,inode=1373288,size=102,blksize=32768 },AT_SYMLINK_NOFOLLOW) = 0 (0x0)
 openat(AT_FDCWD,"/etc/libmap.conf",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
 fstat(3,{ mode=-rw-r--r-- ,inode=1373288,size=102,blksize=32768 }) = 0 (0x0)
 mmap(0x0,102,PROT_READ,MAP_PRIVATE,3,0x0)       = 34366205952 (0x80062b000)
 close(3)                                        = 0 (0x0)
-fstatat(AT_FDCWD,"/usr",{ mode=drwxr-xr-x ,inode=561792,size=512,blksize=32768 },AT_SYMLINK_NOFOLLOW) = 0 (0x0)
-fstatat(AT_FDCWD,"/usr/local",{ mode=drwxr-xr-x ,inode=561800,size=512,blksize=32768 },AT_SYMLINK_NOFOLLOW) = 0 (0x0)
-fstatat(AT_FDCWD,"/usr/local/etc",{ mode=drwxr-xr-x ,inode=653279,size=1536,blksize=32768 },AT_SYMLINK_NOFOLLOW) = 0 (0x0)
-fstatat(AT_FDCWD,"/usr/local/etc/libmap.d",0x7fffffffcf50,AT_SYMLINK_NOFOLLOW) ERR#2 'No such file or directory'
+open("/usr/local/etc/libmap.d",O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC,0165) ERR#2 'No such file or directory'
 munmap(0x80062b000,102)                                 = 0 (0x0)
 openat(AT_FDCWD,"/var/run/ld-elf.so.hints",O_RDONLY|O_CLOEXEC,00) = 3 (0x3)
 read(3,"Ehnt\^A\0\0\0\M^@\0\0\0\M-2\0\0"...,128) = 128 (0x80)

Reviewed by:	kib
MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D12741
2017-10-22 10:32:40 +00:00
Eugene Grosbein
de8d85c908 ftpd(8): fix user context handling.
Apply authenticated user context after update of wtmp(5) at start of session,
so that ftpd process is not killed by kernel with SIGXFSZ when user has
"filesize" limit lower than size of system wtmp file. Same applies
to session finalization: revert to super-user context before update of wtmp.

If ftpd hits limit while writing a file at user request,
do not get killed with SIGXFSZ instantly but apparently ignore the signal,
process error and report it to the user, and continue with the session.

PR:		143570
Approved by:	avg (mentor), mav (mentor)
MFC after:	1 week
2017-10-06 13:46:05 +00:00
Jeremie Le Hen
e415aa2846 Remove rcmds.
If they are still needed, you can find them in the net/bsdrcmds port.

This was proposed June, 20th and approved by various committers [1].
They have been marked as deprecated on CURRENT in r320644 [2] on July, 4th.
Both stable/11 and release/11.1 contain the deprecation notice (thanks to
allanjude@).

Note that ruptime(1)/rwho(1)/rwhod(8) were initially thought to be part of
rcmds but this was a mistake and those are therefore NOT removed.

[1] https://lists.freebsd.org/pipermail/freebsd-arch/2017-June/018239.html
[2] https://svnweb.freebsd.org/base?view=revision&revision=320644

Reviewed by:	bapt, brooks
Differential Revision:	https://reviews.freebsd.org/D12573
2017-10-06 08:43:14 +00:00
Gordon Tetlow
4572fb3faf Deorbit catman. The tradeoff of disk for performance has long since tipped
in favor of just rendering the manpage instead of relying on pre-formatted
catpages. Note, this does not impede the ability to use existing catpages,
it just removes the utility to generate them.

Reviewed by:	imp, allanjude
Approved by:	emaste (mentor)
Differential Revision:	https://reviews.freebsd.org/D12317
2017-09-13 16:35:16 +00:00