-
Notifications
You must be signed in to change notification settings - Fork 26
/
backup_samba4
executable file
·424 lines (391 loc) · 14.5 KB
/
backup_samba4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#!/bin/bash -e
#
# Copyright (C) Matthieu Patou <mat@matws.net> 2010-2011
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Revised 2013-09-25, Brian Martin, as follows:
# - Allow retention period ("DAYS") to be specified as a parameter.
# - Allow individual positional parameters to be left at the default
# by specifying "-"
# - Use IS0 8601 standard dates (yyyy-mm-dd instead of mmddyyyy).
# - Display tar exit codes when reporting errors.
# - Don't send error messages to /dev/null, so we know what failed.
# - Suppress useless tar "socket ignored" message.
# - Fix retention period bug when deleting old backups ($DAYS variable
# could be set, but was ignored).
#
# Revised 2015-10-25, Rowland Penny, as follows:
# - Added check to make sure being run by root.
# - Change Variable names to make them more obvious.
# - Removed option to change where to backup from.
# - Remove option to use arguments, this is a set & use script,
# and will not work with self compiled Samba without modification.
# - Backup acls & attrs if using GNU-tar version 1.27 up
# - Backup *.ldb & *.tdb files
# - Added debug option
#
# Revised 2015-12-08, Rowland Penny, as follows:
# - made to work with debian packages and self compiled installs
#
# Revised 2015-12-09, Louis van Belle, as follows:
# - corrected few echo's to $DEBUG
# - added the option for a full /etc backup also.
# - added the option to remove the backup files,
# but keep the 1e and 15e of the month
# - add ability to run the script multiple times per day
# without your files getting overridden (backups wil be numberd per run time)
#
# Revised 2015-12-11, Louis van Belle, as follows:
# - Script error when running from within cron.
# automatic put full paths in for the commands
# - changed shell from sh to bash, tested on debian wheezy
# Revised 2015-12-14, Louis van Belle, as follows:
# - Script error when running from within, missed a typo.
# - added file definitions by date/time standards
# Revised 2017-12-19, Louis van Belle:
# - exclude netlogon_creds_cli.tdb from the backups, its not needed,
# see: https://bugzilla.samba.org/show_bug.cgi?id=13088
# - make keep_day work, in test now.
# Revised 2017-12-19, Louis van Belle, Thanks Norbert Hanke.:
# - Fixed detection of samba/etc with a self compiled samba.
# Revised 2019-08-01, Louis van Belle, Thanks Norbert Hanke.:
# - Fixed detection of samba/etc with a self compiled samba.
# Revised 2019-08-01, Louis van Belle, Thanks jkirk.
# - Fixed backup folder rights.
# Revised 2019-10-02, Louis van Belle, Thanks t2semi.
# - Fixed tar paramater ordering.
# Revised 2019-10-02, Louis van Belle, re-style code.
##
# Used format in the backup file names.
# date format: ISO 8601 YYYY-MM-DD (extended format)
# time format: ISO 8601 24-hour clock system [hh][mm][ss] (basic format).
# where to store backups ( change this )
STOREDIR="/home/backups/$(hostname -s)"
# this creates an extra acl backup of sysvol with getfacl -R (yes/no)
BACKUP_SYSVOL_ACL="yes"
# Full /etc backup (yes/no)
BACKUP_ETC="yes"
# Number of days to keep the backup
DAYS=60
# KEEP_DAYS, for auto cleanup and extra safe backups.
# Keeps every date with ( defaults to ) 01e and 15e in the backup.
# Files are older then XX DAYS will be removed automaticly.
# If set to "yes" then any file with 01 or 15 in it will not be removed.
# default "yes" because its good the have backups even older then XX Days.
# If set to "no", any file older then XX Days wil be removed from the backup.
KEEP_DAYS="yes"
# The day numbers of the month to keep, only effective if KEEP_DAYS="yes" !
KEEP_DAY1="01"
KEEP_DAY2="15"
# the commando's this scripts need.
SCRIPT_COMMANDS="echo samba tdbbackup logger tar dirname cat grep awk sed date find rm getfacl tail cut wc awk sort"
# The location for the command file, make sure that folder exists.
SCRIPT_COMMANDS_FILE="/etc/samba/backup_samba4_commands"
# what to backup of samba, this should normaly not be needed to change.
DIRS="private sysvol samba"
#########################################################################
# DO NOT CHANGE ANYTHING BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING! #
# IF YOU BREAK IT, YOU FIX IT #
#########################################################################
if [ -n "$1" ] && [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
echo "This script will backup the Samba4 AD DC database files."
echo "It will backup your provision and archive it to $STOREDIR."
echo "The archived files will be stored for ${DAYS} days"
echo "usage:"
echo " '$0 --debug' will echo messages to screen,"
echo " usually used when initially testing."
echo " '$0 -h or --help' will print this message."
echo " '$0' by itself will log to syslog,"
echo " usually used when run from cron."
echo
exit 0
fi
# assign CMD_COMMAND variables
if [ ! -e ${SCRIPT_COMMANDS_FILE} ]
then
for COMMANDS in ${SCRIPT_COMMANDS}
do
# determin all command needed and add it the backup_samba4_commands file.
# This speeds up the second and all other backup runs.
EVAL_PROG="CMD_"
EVAL_PROG_DATA="${COMMANDS^^}"
EVAL_DATA="$(command -v "${COMMANDS}")"
eval "${EVAL_PROG}${EVAL_PROG_DATA}"="\"${EVAL_DATA}\""
EVAL_CHECK="${EVAL_PROG}${EVAL_PROG_DATA}"
if [ -z "${EVAL_CHECK}" ] || [ -z "${EVAL_DATA}" ]
then
echo "Error command ${EVAL_CHECK} is without data"
echo "Please adjust this value manualy in the file ${SCRIPT_COMMANDS_FILE}"
echo "${EVAL_CHECK}=\"${EVAL_DATA}\"" >> ${SCRIPT_COMMANDS_FILE}
else
echo "${EVAL_CHECK}=\"${EVAL_DATA}\"" >> ${SCRIPT_COMMANDS_FILE}
fi
done
echo "Exitting now...commands file created, please restart the script.."
exit 1
else
# Import the commands
source ${SCRIPT_COMMANDS_FILE}
# revalidate commands, check if variable are filled.
for COMMANDS in ${SCRIPT_COMMANDS}
do
EVAL2_PROG="CMD_"
EVAL2_PROG_DATA=${COMMANDS^^}
EVAL2_CHECK="${EVAL2_PROG}${EVAL2_PROG_DATA}"
if [ -z "${EVAL2_CHECK}" ]
then
echo "Error, ${EVAL2_CHECK} does not have a value"
echo "Please put the command in the file ${SCRIPT_COMMANDS_FILE}"
echo "Exitting now... "
exit 1
fi
if [ ! -e "${!EVAL2_CHECK}" ]
then
echo "Error, ${EVAL2_CHECK} is unset or set to the empty string"
echo "Please correct the command in the file ${SCRIPT_COMMANDS_FILE}"
echo "Exitting now... "
exit 1
fi
if [ "$1" = "--debug" ]
then
echo "Command checks : ${EVAL2_CHECK} contains : ${!EVAL2_CHECK}"
fi
done
fi
# Run with --debug for console output.
if [ -n "$1" ] && [ "$1" = "--debug" ]
then
DEBUG="${CMD_ECHO}"
else
# Else log it to syslog with logger
DEBUG="${CMD_LOGGER} -t $0"
fi
# make sure this is being run by root
USER=$(whoami)
if [ "$USER" != "root" ]
then
${DEBUG} "You must be root to run backup_samba4"
exit 1
fi
# Test if GNU tar is installed and is the required version or newer
TARVERSION="$(${CMD_TAR} --version | ${CMD_GREP} 'GNU tar' | ${CMD_AWK} '{print $NF}' | ${CMD_AWK} -F '.' '{print $2}')"
if [ -n "${TARVERSION}" ] && [ "${TARVERSION}" -ge "27" ]
then
TARARGS="-cj --acls --xattrs -f "
else
TARARGS="-cj -f "
fi
if [ ! -d "${STOREDIR}" ]
then
${DEBUG} "Missing backup directory $STOREDIR"
${DEBUG} "Will now create it."
install -d "${STOREDIR}" -o root -g staff -m 660
fi
# get where the directory that holds smb.conf is stored
CONFBASE="$(${CMD_SAMBA} -b | ${CMD_GREP} [C]ONFIGFILE | ${CMD_AWK} '{print $NF}' | ${CMD_AWK} -F '/' '{print $2}')"
if [ "${CONFBASE}" = "etc" ]
then
CONFDIR="/etc"
elif [ "${CONFBASE}" = "usr" ]
then
CONFDIR="/usr/local/samba/etc"
else
${DEBUG} "Cannot find Samba conf dir. ${CONFBASE}"
${DEBUG} "Cannot continue... Exiting."
exit 1
fi
${DEBUG} "Starting backup with $0"
# get the directory that holds the private dir
PRIVATEBASE="$(${CMD_DIRNAME} $(${CMD_SAMBA} -b | ${CMD_GREP} [P]RIVATE_DIR | ${CMD_AWK} '{print $NF}'))"
if [ ! -d "${PRIVATEBASE}" ]
then
${DEBUG} "Missing or wrong provision directory ${PRIVATEBASE}"
exit 1
fi
# get the directory that holds the sysvol dir
CONFILE="$(${CMD_SAMBA} -b | ${CMD_GREP} [C]ONFIGFILE | ${CMD_AWK} '{print $NF}')"
SYSVOLBASE="$(${CMD_CAT} ${CONFILE} | ${CMD_GREP} sysvol | ${CMD_GREP} scripts | ${CMD_AWK} '{print $NF}' | ${CMD_SED} 's/sysvol.*//')"
# backup .tdb & .ldb files
backup_file () {
FILE="${1}"
if [ -z "${FILE}" ]
then
${DEBUG} "Error: No file supplied - Cannot continue."
exit 1
fi
${CMD_TDBBACKUP} $1
Status=$?
if [ $Status -ne 0 ]
then
${DEBUG} "Error while backing up $1 - status $Status"
exit 1
fi
}
# check for existing backup files, if exist, create new files with following numbers.
check_backup_file () {
BACKUPDATE="$(${CMD_DATE} +%Y-%m-%d)" # ISO 8601 standard date.
${DEBUG} "Backupdate = $BACKUPDATE"
${DEBUG} "Message: checking for previous backups of this day : $d"
# determin last use counter nr
COUNTER="$(ls ${STOREDIR} | ${CMD_GREP} ${BACKUPDATE} | sort | ${CMD_GREP} $d | ${CMD_TAIL} -n1 | ${CMD_CUT} -d"-" -f5 | ${CMD_CUT} -d"." -f1)"
${DEBUG} "Counter = $COUNTER"
if [ -z "$COUNTER" ]
then
COUNTER=0
BACKUPDATE="${BACKUPDATE}-${COUNTER}"
else
COUNTER=$((COUNTER+1))
BACKUPDATE="${BACKUPDATE}-${COUNTER}"
fi
${DEBUG} "Message: setting date and counter : ${BACKUPDATE} for $d"
}
for d in $DIRS
do
if [ "$d" = "private" ]
then
check_backup_file
cd ${PRIVATEBASE}
relativedirname="$(${CMD_FIND} . -type d -name "$d" -prune)"
${CMD_FIND} $relativedirname -name "*.ldb.bak" -exec ${CMD_RM} {} \;
${CMD_FIND} $relativedirname -name "*.tdb.bak" -exec ${CMD_RM} {} \;
for ldb in $(${CMD_FIND} $relativedirname -name "*.ldb")
do
# backup .ldb files
backup_file $ldb
done
# exclude netlogon_creds_cli : https://bugzilla.samba.org/show_bug.cgi?id=13088
for tdb in $(${CMD_FIND} $d -name "*.tdb" -type f -print | xargs -0 | grep -v 'netlogon_creds_cli')
do
# backup .tdb files
backup_file $tdb
done
# Run the backup.
# --warning=no-file-ignored suppresses "socket ignored" messages.
# --warning=no-file-changed suppresses "file changed as we read it"
${CMD_TAR} ${TARARGS} ${STOREDIR}/${d}-${BACKUPDATE}.tar.bz2 \
--warning=no-file-ignored --warning=no-file-changed \
--transform 's/.ldb.bak/.ldb/' --transform 's/.tdb.bak/.tdb/' \
--exclude='*.ldb' --exclude='*.tdb' $relativedirname
Status=$?
if [ $Status -ne 0 -a $Status -ne 1 ]
then
# Ignore 1 - private dir is always changing.
${DEBUG} "Error archiving:"
${DEBUG} " ${STOREDIR}/${d}-${BACKUPDATE}.tar.bz2"
${DEBUG} " Status: $Status"
exit 1
else
${DEBUG} "Backup Status ${d}: ok"
fi
# delete any .bak files
${CMD_FIND} $relativedirname -name "*.ldb.bak" -exec ${CMD_RM} {} \;
${CMD_FIND} $relativedirname -name "*.tdb.bak" -exec ${CMD_RM} {} \;
elif [ "$d" = "sysvol" ]
then
check_backup_file
cd ${SYSVOLBASE}
relativedirname=$(${CMD_FIND} . -type d -name "$d" -prune)
# Run the backup.
# --warning=no-file-ignored suppresses "socket ignored" messages.
# --warning=no-file-changed suppresses "file changed as we read it"
${CMD_TAR} ${TARARGS} ${STOREDIR}/${d}-${BACKUPDATE}.tar.bz2 \
--warning=no-file-ignored --warning=no-file-changed $relativedirname
Status=$?
if [ $Status -ne 0 ]
then
${DEBUG} "Error archiving:"
${DEBUG} " ${STOREDIR}/${d}-${BACKUPDATE}.tar.bz2"
${DEBUG} "Status: $Status"
exit 1
else
${DEBUG} "Backup Status ${d}: ok"
fi
if [ ${BACKUP_SYSVOL_ACL} = "yes" ]
then
# ! Dont use sysvol here, it messes up the sysvol counter.
d=acl-sys_vol
check_backup_file
${DEBUG} "creating sysvol ACL file"
${CMD_GETFACL} -R sysvol > ${STOREDIR}/${d}.${BACKUPDATE}.acl
${CMD_TAR} ${TARARGS} ${STOREDIR}/${d}.${BACKUPDATE}.acl.tar.bz2 \
${STOREDIR}/${d}.${BACKUPDATE}.acl >/dev/null 2>&1
if [ $? -ne 0 ]
then
${DEBUG} "Error while archiving \
${STOREDIR}/sysvolacl.${BACKUPDATE}.tar.bz2"
exit 1
else
${DEBUG} "Backup Status sysvol acl: ok"
${CMD_RM} ${STOREDIR}/${d}.${BACKUPDATE}.acl
fi
#
fi
elif [ "$d" = "samba" ]
then
check_backup_file
cd ${CONFDIR}
if [ "${CONFILE}" = "/etc/samba/smb.conf" ]
then
relativedirname=$(${CMD_FIND} . -type d -name "$d" -prune)
else
relativedirname=$(${CMD_FIND} .. -type d -name "etc" -prune)
fi
# Run the backup.
# --warning=no-file-ignored suppresses "socket ignored" messages.
# --warning=no-file-changed suppresses "file changed as we read it"
${CMD_TAR} ${TARARGS} ${STOREDIR}/${d}-${BACKUPDATE}.tar.bz2 \
--warning=no-file-ignored --warning=no-file-changed $relativedirname
Status=$?
if [ $Status -ne 0 ]
then
${DEBUG} "Error archiving:"
${DEBUG} " ${STOREDIR}/${d}-${BACKUPDATE}.tar.bz2"
${DEBUG} "Status: $Status"
exit 1
else
${DEBUG} "Backup Status ${d}: ok"
fi
fi
done
# full backup of /etc
if [ ${BACKUP_ETC} = "yes" ]
then
d=etc
check_backup_file
${DEBUG} "creating full backup of /etc"
${CMD_TAR} ${TARARGS} ${STOREDIR}/etc-${BACKUPDATE}.tar.bz2 /etc >/dev/null 2>&1
Status=$?
if [ $Status -ne 0 ]
then
${DEBUG} "Error archiving:"
${DEBUG} " ${STOREDIR}/${d}-${BACKUPDATE}.tar.bz2"
${DEBUG} "Status: $Status"
exit 1
else
${DEBUG} "Backup Status /etc: ok"
fi
fi
# Remove any files over $DAYS days old from backup dir, keep the $KEEP_DAY1 and $KEEP_DAY2 of the month.
if [ ${KEEP_DAYS} = "yes" ]
then
${DEBUG} "Deleting any backup files over ${DAYS} days old, keeping date $KEEP_DAY1 and $KEEP_DAY2 of the month."
${CMD_FIND} ${STOREDIR} -name "*.bz2" -mtime +${DAYS} -type f -print | xargs -0 | egrep -v "\-${KEEP_DAY1}\-|\-${KEEP_DAY2}\-" | xargs ${CMD_RM} >/dev/null 2>&1
fi
if [ ${KEEP_DAYS} = "no" ]
then
${DEBUG} "Deleting any backup files over ${DAYS} days old."
${CMD_FIND} ${STOREDIR} -name "*.bz2" -mtime +${DAYS} -exec ${CMD_RM} {} \; >/dev/null 2>&1
fi
exit 0