Subversion Repositories ALCASAR

Rev

Rev 2304 | Rev 3162 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log

Rev 2304 Rev 2596
1
#!/bin/bash
1
#!/bin/bash
2
#
2
#
3
# $Id: alcasar-letsencrypt.sh 2304 2017-06-26 12:56:14Z tom.houdayer $
3
# $Id: alcasar-letsencrypt.sh 2596 2018-08-19 23:28:45Z tom.houdayer $
4
#
4
#
5
# alcasar-letsencrypt.sh
5
# alcasar-letsencrypt.sh
6
# by Tom HOUDAYER
6
# by Tom HOUDAYER
7
#
7
#
8
# This script is distributed under the Gnu General Public License (GPL)
8
# This script is distributed under the Gnu General Public License (GPL)
9
#
9
#
10
# Manage Let's Encrypt for ALCASAR integration
10
# Manage Let's Encrypt for ALCASAR integration
11
 
11
 
12
CONF_FILE="/usr/local/etc/alcasar-letsencrypt"
12
CONF_FILE="/usr/local/etc/alcasar-letsencrypt"
13
 
13
 
14
ACCOUNT_EMAIL=""
14
ACCOUNT_EMAIL=""
15
DOMAIN=""
15
DOMAIN=""
16
DNS_API=""
16
DNS_API=""
17
 
17
 
18
DEBUG=false
18
DEBUG=false
19
STAGING_SERVER=""
19
STAGING_SERVER=""
20
FORCE=""
20
FORCE=""
21
OPT_PARAMS=""
21
OPT_PARAMS=""
22
 
22
 
23
ACMESH_HOME="/usr/local/etc/letsencrypt"
23
ACMESH_HOME="/usr/local/etc/letsencrypt"
24
ACMESH_BIN="/opt/acme.sh/acme.sh"
24
ACMESH_BIN="/opt/acme.sh/acme.sh"
25
 
25
 
26
usage="Usage: alcasar-letsencrypt.sh
26
usage="Usage: alcasar-letsencrypt.sh
27
       --issue -d alcasar.domain.tld --email alcasar@domain.tld [--dns-api dns_registrar] [--force] [--staging]
27
       --issue -d alcasar.domain.tld --email alcasar@domain.tld [--dns-api dns_registrar] [--force] [--staging]
28
       --renew [-d alcasar.domain.tld] [--force] [--staging]"
28
       --renew [-d alcasar.domain.tld] [--force] [--staging]"
29
 
29
 
30
 
30
 
31
################################################################################
31
################################################################################
32
#                                    ISSUE                                     #
32
#                                    ISSUE                                     #
33
################################################################################
33
################################################################################
34
issue() {
34
issue() {
35
	if [ ! -f $ACMESH_BIN ]; then
35
	if [ ! -f $ACMESH_BIN ]; then
36
		echo "The client does not seem to be installed."
36
		echo "The client does not seem to be installed."
37
		return 1
37
		return 1
38
	fi
38
	fi
39
 
39
 
40
	TMP_OUTPUT=$(mktemp --suffix=_ALCASAR-LE)
40
	TMP_OUTPUT=$(mktemp --suffix=_ALCASAR-LE)
41
 
41
 
42
	if [ ! -z $ACCOUNT_EMAIL ]; then
42
	if [ ! -z $ACCOUNT_EMAIL ]; then
43
		emailField=" --accountemail $ACCOUNT_EMAIL"
43
		emailField=" --accountemail $ACCOUNT_EMAIL"
44
		sed -i "s/^email=.*/email=$ACCOUNT_EMAIL/" $CONF_FILE
44
		sed -i "s/^email=.*/email=$ACCOUNT_EMAIL/" $CONF_FILE
45
	else
45
	else
46
		emailField=""
46
		emailField=""
47
	fi
47
	fi
48
 
48
 
49
	$DEBUG && debugOpt=" --debug" || debugOpt=""
49
	$DEBUG && debugOpt=" --debug" || debugOpt=""
-
 
50
	[ ! -z "$DNS_API" ] && dnsApiOpt="$DNS_API" || dnsApiOpt="--yes-I-know-dns-manual-mode-enough-go-ahead-please"
50
	$ACMESH_BIN --config-home $ACMESH_HOME/data \
51
	$ACMESH_BIN --config-home $ACMESH_HOME/data \
51
		$STAGING_SERVER $FORCE $debugOpt \
52
		$STAGING_SERVER $FORCE $debugOpt \
52
		$emailField \
53
		$emailField \
53
		--issue --dns $DNS_API -d $DOMAIN \
54
		--issue --dns $dnsApiOpt -d $DOMAIN \
54
		$OPT_PARAMS \
55
		$OPT_PARAMS \
55
		> $TMP_OUTPUT 2>&1
56
		> $TMP_OUTPUT 2>&1
56
	exitCode=$?
57
	exitCode=$?
57
 
58
 
58
	$DEBUG && cat $TMP_OUTPUT && echo -e "\n\n"
59
	$DEBUG && cat $TMP_OUTPUT && echo -e "\n\n"
59
 
60
 
60
	sed -i "s/^domainRequest=.*/domainRequest=$DOMAIN/" $CONF_FILE
61
	sed -i "s/^domainRequest=.*/domainRequest=$DOMAIN/" $CONF_FILE
61
	sed -i "s/^dateIssueRequest=.*/dateIssueRequest=$(date +%s)/" $CONF_FILE
62
	sed -i "s/^dateIssueRequest=.*/dateIssueRequest=$(date +%s)/" $CONF_FILE
62
	sed -i "s/^dnsapi=.*/dnsapi=${DNS_API:="dns"}/" $CONF_FILE
63
	sed -i "s/^dnsapi=.*/dnsapi=${DNS_API:="dns"}/" $CONF_FILE
63
 
64
 
64
	if ! _handle_client_response $TMP_OUTPUT; then
65
	if ! _handle_client_response $TMP_OUTPUT; then
65
		if [ $exitCode -ne 0 ]; then
66
		if [ $exitCode -ne 0 ]; then
66
			echo -e "Error!\n"
67
			echo -e "Error!\n"
67
			cat $TMP_OUTPUT
68
			cat $TMP_OUTPUT
68
			rm -f $TMP_OUTPUT
69
			rm -f $TMP_OUTPUT
69
			return 1
70
			return 1
70
		else
71
		else
71
			echo -e "Unknown state\n"
72
			echo -e "Unknown state\n"
72
			cat $TMP_OUTPUT
73
			cat $TMP_OUTPUT
73
		fi
74
		fi
74
	fi
75
	fi
75
 
76
 
76
	rm -f $TMP_OUTPUT
77
	rm -f $TMP_OUTPUT
77
}
78
}
78
 
79
 
79
 
80
 
80
################################################################################
81
################################################################################
81
#                                    RENEW                                     #
82
#                                    RENEW                                     #
82
################################################################################
83
################################################################################
83
renew() {
84
renew() {
84
	if [ ! -f $ACMESH_BIN ]; then
85
	if [ ! -f $ACMESH_BIN ]; then
85
		echo "The client does not seem to be installed."
86
		echo "The client does not seem to be installed."
86
		return 1
87
		return 1
87
	fi
88
	fi
88
 
89
 
89
	TMP_OUTPUT=$(mktemp --suffix=_ALCASAR-LE)
90
	TMP_OUTPUT=$(mktemp --suffix=_ALCASAR-LE)
90
 
91
 
91
	$DEBUG && debugOpt=" --debug" || debugOpt=""
92
	$DEBUG && debugOpt=" --debug" || debugOpt=""
-
 
93
	[ ! -z "$DNS_API" ] && dnsApiOpt="" || dnsApiOpt="--yes-I-know-dns-manual-mode-enough-go-ahead-please"
92
	$ACMESH_BIN --config-home $ACMESH_HOME/data \
94
	$ACMESH_BIN --config-home $ACMESH_HOME/data \
93
		$STAGING_SERVER $FORCE $debugOpt \
95
		$STAGING_SERVER $FORCE $debugOpt \
94
		--renew -d $DOMAIN \
96
		--renew -d $DOMAIN $dnsApiOpt \
95
		$OPT_PARAMS \
97
		$OPT_PARAMS \
96
		> $TMP_OUTPUT 2>&1
98
		> $TMP_OUTPUT 2>&1
97
	exitCode=$?
99
	exitCode=$?
98
 
100
 
99
	$DEBUG && cat $TMP_OUTPUT && echo -e "\n\n"
101
	$DEBUG && cat $TMP_OUTPUT && echo -e "\n\n"
100
 
102
 
101
	if ! _handle_client_response $TMP_OUTPUT; then
103
	if ! _handle_client_response $TMP_OUTPUT; then
102
		if [ $exitCode -ne 0 ]; then
104
		if [ $exitCode -ne 0 ]; then
103
			echo -e "Error!\n"
105
			echo -e "Error!\n"
104
			cat $TMP_OUTPUT
106
			cat $TMP_OUTPUT
105
			rm -f $TMP_OUTPUT
107
			rm -f $TMP_OUTPUT
106
			return 1
108
			return 1
107
		else
109
		else
108
			echo -e "Unknown state\n"
110
			echo -e "Unknown state\n"
109
			cat $TMP_OUTPUT
111
			cat $TMP_OUTPUT
110
		fi
112
		fi
111
	fi
113
	fi
112
 
114
 
113
	rm -f $TMP_OUTPUT
115
	rm -f $TMP_OUTPUT
114
}
116
}
115
 
117
 
116
 
118
 
117
################################################################################
119
################################################################################
118
#                                  CRON TASK                                   #
120
#                                  CRON TASK                                   #
119
################################################################################
121
################################################################################
120
cron_task() {
122
cron_task() {
121
	if [ $(grep '^dateNextRenewal=' $CONF_FILE | cut -d'=' -f2) -le $(date +%s) ]; then
123
	if [ $(grep '^dateNextRenewal=' $CONF_FILE | cut -d'=' -f2) -le $(date +%s) ]; then
122
		logger -t alcasar-letsencrypt "Launch CRON task."
124
		logger -t alcasar-letsencrypt "Launch CRON task."
123
		renew
125
		renew
124
	fi
126
	fi
125
}
127
}
126
 
128
 
127
 
129
 
128
################################################################################
130
################################################################################
129
#                            HANDLE CLIENT RESPONSE                            #
131
#                            HANDLE CLIENT RESPONSE                            #
130
################################################################################
132
################################################################################
131
_handle_client_response() {
133
_handle_client_response() {
132
	[ $# -lt 1 ] && return 1
134
	[ $# -lt 1 ] && return 1
133
	responseFile=$1
135
	responseFile=$1
134
 
136
 
135
	# issue / renew
137
	# issue / renew
136
	if [ $(cat $responseFile | grep "Add the following TXT record:" -c) -ne 0 ]; then
138
	if [ $(cat $responseFile | grep "Add the following TXT record:" -c) -ne 0 ]; then
137
		challenge=$(cat $responseFile | grep -E "TXT value: '[0-9a-zA-Z_-]+'" -o | cut -d"'" -f2)
139
		challenge=$(cat $responseFile | grep -E "TXT value: '[0-9a-zA-Z_-]+'" -o | cut -d"'" -f2)
138
		sed -i "s/^challenge=.*/challenge=$challenge/" $CONF_FILE
140
		sed -i "s/^challenge=.*/challenge=$challenge/" $CONF_FILE
139
 
141
 
140
		echo "Add the following TXT record:"
142
		echo "Add the following TXT record:"
141
		echo "Domain:    '_acme-challenge.$DOMAIN'"
143
		echo "Domain:    '_acme-challenge.$DOMAIN'"
142
		echo "TXT value: '$challenge'"
144
		echo "TXT value: '$challenge'"
143
	elif [ $(cat $responseFile | grep "Cert success." -c) -ne 0 ]; then
145
	elif [ $(cat $responseFile | grep "Cert success." -c) -ne 0 ]; then
144
		sed -i "s/^challenge=.*/challenge=/" $CONF_FILE
146
		sed -i "s/^challenge=.*/challenge=/" $CONF_FILE
145
		sed -i "s/^dateIssued=.*/dateIssued=$(date +%s)/" $CONF_FILE
147
		sed -i "s/^dateIssued=.*/dateIssued=$(date +%s)/" $CONF_FILE
146
		sed -i "s/^dateNextRenewal=.*/dateNextRenewal=$(date +%s -d '2 months - 3 days')/" $CONF_FILE
148
		sed -i "s/^dateNextRenewal=.*/dateNextRenewal=$(date +%s -d '2 months - 3 days')/" $CONF_FILE
147
 
149
 
148
		install_cert
150
		install_cert
149
		logger -t alcasar-letsencrypt "Certificate \"$DOMAIN\" imported."
151
		logger -t alcasar-letsencrypt "Certificate \"$DOMAIN\" imported."
150
		echo "Certificate imported."
152
		echo "Certificate imported."
151
		[ -z $DNS_API ] && echo "Note: you can delete the TXT record."
153
		[ -z $DNS_API ] && echo "Note: you can delete the TXT record."
152
	elif [ $(cat $responseFile | grep "Domains not changed." -c) -ne 0 ]; then
154
	elif [ $(cat $responseFile | grep "Domains not changed." -c) -ne 0 ]; then
153
		echo "Domain not changed"
155
		echo "Domain not changed"
154
	elif [ $(cat $responseFile | grep "$DOMAIN is already verified, skip dns-01." -c) -ne 0 ]; then
156
	elif [ $(cat $responseFile | grep "$DOMAIN is already verified, skip dns-01." -c) -ne 0 ]; then
155
		echo "Domain already verified"
157
		echo "Domain already verified"
156
	elif [ $(cat $responseFile | grep "Error add txt for domain:_acme-challenge.$DOMAIN" -c) -ne 0 ]; then
158
	elif [ $(cat $responseFile | grep "Error add txt for domain:_acme-challenge.$DOMAIN" -c) -ne 0 ]; then
157
		echo "Error add txt for domain:_acme-challenge.$DOMAIN"
159
		echo "Error add txt for domain:_acme-challenge.$DOMAIN"
158
	elif [ $(cat $responseFile | grep "Please add the TXT records to the domains, and retry again." -c) -ne 0 ]; then
160
	elif [ $(cat $responseFile | grep "Please add the TXT records to the domains, and retry again." -c) -ne 0 ]; then
159
		echo "Dns record not added yet, you need to add it manually and retry again."
161
		echo "Dns record not added yet, you need to add it manually and retry again."
160
	elif [ $(cat $responseFile | grep 'new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}' -c) -ne 0 ]; then
162
	elif [ $(cat $responseFile | grep 'new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}' -c) -ne 0 ]; then
161
		errorMsg=$(cat $responseFile | grep 'new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}' | sed 's/.*new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}.*/\1/')
163
		errorMsg=$(cat $responseFile | grep 'new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}' | sed 's/.*new-authz error: {"type":"urn:acme:error:malformed","detail":"Error creating new authz :: \(.*\)","status": 400}.*/\1/')
162
		echo "Incorrect domain name"
164
		echo "Incorrect domain name"
163
		echo "$errorMsg"
165
		echo "$errorMsg"
164
	elif [ $(cat $responseFile | grep "'$DOMAIN' is not a issued domain, skip." -c) -ne 0 ]; then
166
	elif [ $(cat $responseFile | grep "'$DOMAIN' is not a issued domain, skip." -c) -ne 0 ]; then
165
		echo "'$DOMAIN' is not a issued domain"
167
		echo "'$DOMAIN' is not a issued domain"
166
 
168
 
167
	# renew
169
	# renew
168
	elif [ $(cat $responseFile | grep "Skip, Next renewal time is: " -c) -ne 0 ]; then
170
	elif [ $(cat $responseFile | grep "Skip, Next renewal time is: " -c) -ne 0 ]; then
169
		nextRenewal=$(cat $responseFile | grep 'Skip, Next renewal time is: ' | sed 's/.*Skip, Next renewal time is: \(.*\)/\1/')
171
		nextRenewal=$(cat $responseFile | grep 'Skip, Next renewal time is: ' | sed 's/.*Skip, Next renewal time is: \(.*\)/\1/')
170
		echo "Skip, Next renewal time is: $nextRenewal"
172
		echo "Skip, Next renewal time is: $nextRenewal"
171
		echo "Add '--force' to force to renew."
173
		echo "Add '--force' to force to renew."
172
	elif [ $(cat $responseFile | grep "$DOMAIN:Verify error:Correct value not found for DNS challenge" -c) -ne 0 ]; then
174
	elif [ $(cat $responseFile | grep "$DOMAIN:Verify error:Correct value not found for DNS challenge" -c) -ne 0 ]; then
173
		echo "Correct value not found for DNS challenge"
175
		echo "Correct value not found for DNS challenge"
174
	elif [ $(cat $responseFile | grep "Unable to update challenge :: The challenge is not pending." -c) -ne 0 ]; then
176
	elif [ $(cat $responseFile | grep "Unable to update challenge :: The challenge is not pending." -c) -ne 0 ]; then
175
		echo "The challenge is not pending. You need to issue."
177
		echo "The challenge is not pending. You need to issue."
176
	else
178
	else
177
		return 2
179
		return 2
178
	fi
180
	fi
179
 
181
 
180
	return 0
182
	return 0
181
}
183
}
182
 
184
 
183
 
185
 
184
################################################################################
186
################################################################################
185
#                             INSTALL CERTIFICATE                              #
187
#                             INSTALL CERTIFICATE                              #
186
################################################################################
188
################################################################################
187
install_cert() {
189
install_cert() {
188
	echo "Importing certificate to ALCASAR..."
190
	echo "Importing certificate to ALCASAR..."
189
 
191
 
190
	if [ ! -f $ACMESH_HOME/certs/"$DOMAIN"/"$DOMAIN".cer ]; then
192
	if [ ! -f $ACMESH_HOME/certs/"$DOMAIN"/"$DOMAIN".cer ]; then
191
		echo "Certificate not found."
193
		echo "Certificate not found."
192
		return 1
194
		return 1
193
	fi
195
	fi
194
 
196
 
195
	/usr/local/bin/alcasar-importcert.sh \
197
	/usr/local/bin/alcasar-importcert.sh \
196
		-i $ACMESH_HOME/certs/"$DOMAIN"/"$DOMAIN".cer \
198
		-i $ACMESH_HOME/certs/"$DOMAIN"/"$DOMAIN".cer \
197
		-k $ACMESH_HOME/certs/"$DOMAIN"/"$DOMAIN".key \
199
		-k $ACMESH_HOME/certs/"$DOMAIN"/"$DOMAIN".key \
198
		-c $ACMESH_HOME/certs/"$DOMAIN"/fullchain.cer \
200
		-c $ACMESH_HOME/certs/"$DOMAIN"/fullchain.cer \
199
		> /dev/null 2>&1
201
		> /dev/null 2>&1
200
 
202
 
201
	if [ $? -ne 0 ]; then
203
	if [ $? -ne 0 ]; then
202
		echo "Error."
204
		echo "Error."
203
		return 1
205
		return 1
204
	fi
206
	fi
205
}
207
}
206
 
208
 
207
 
209
 
208
################################################################################
210
################################################################################
209
#                                     MAIN                                     #
211
#                                     MAIN                                     #
210
################################################################################
212
################################################################################
211
 
213
 
212
nb_args=$#
-
 
213
args=$1
-
 
214
 
-
 
215
if [ $nb_args -eq 0 ]; then
214
if [ $# -eq 0 ]; then
216
	echo "$usage"
215
	echo "$usage"
217
	exit 1
216
	exit 1
218
fi
217
fi
219
 
218
 
220
cmd=""
219
cmd=""
221
 
220
 
222
while [ $# -gt 0 ]; do
221
while [ $# -gt 0 ]; do
223
	case $1 in
222
	case $1 in
224
		-\? | -h | --help)
223
		-\? | -h | --help)
225
			echo "$usage"
224
			echo "$usage"
226
			exit 0
225
			exit 0
227
			;;
226
			;;
228
 
227
 
229
		--issue)
228
		--issue)
230
			cmd="issue"
229
			cmd="issue"
231
			shift 1
230
			shift 1
232
			;;
231
			;;
233
		--renew)
232
		--renew)
234
			cmd="renew"
233
			cmd="renew"
235
			shift 1
234
			shift 1
236
			;;
235
			;;
237
		--cron)
236
		--cron)
238
			cmd="cron"
237
			cmd="cron"
239
			shift 1
238
			shift 1
240
			;;
239
			;;
241
		--install-cert)
240
		--install-cert)
242
			cmd="install-cert"
241
			cmd="install-cert"
243
			shift 1
242
			shift 1
244
			;;
243
			;;
245
 
244
 
246
		--email)
245
		--email)
247
			ACCOUNT_EMAIL="$2"
246
			ACCOUNT_EMAIL="$2"
248
			shift 2
247
			shift 2
249
			;;
248
			;;
250
		--domain | -d)
249
		--domain | -d)
251
			DOMAIN="$2"
250
			DOMAIN="$2"
252
			shift 2
251
			shift 2
253
			;;
252
			;;
254
		--dns-api)
253
		--dns-api)
255
			DNS_API="$2"
254
			DNS_API="$2"
256
			shift 2
255
			shift 2
257
			;;
256
			;;
258
		--force)
257
		--force)
259
			FORCE="--force"
258
			FORCE="--force"
260
			shift 1
259
			shift 1
261
			;;
260
			;;
262
		--staging)
261
		--staging)
263
			STAGING_SERVER="--staging"
262
			STAGING_SERVER="--staging"
264
			shift 1
263
			shift 1
265
			;;
264
			;;
266
		--debug)
265
		--debug)
267
			DEBUG=true
266
			DEBUG=true
268
			shift 1
267
			shift 1
269
			;;
268
			;;
270
 
269
 
271
		*)
270
		*)
272
			found=false
271
			found=false
273
			for param in "--dnssleep"; do
272
			for param in "--dnssleep"; do
274
				if [ $1 == $param ]; then
273
				if [ $1 == $param ]; then
275
					OPT_PARAMS="$OPT_PARAMS $1 $2"
274
					OPT_PARAMS="$OPT_PARAMS $1 $2"
276
					shift 2
275
					shift 2
277
					found=true
276
					found=true
278
					break
277
					break
279
				fi
278
				fi
280
			done
279
			done
281
 
280
 
282
			if ! $found; then
281
			if ! $found; then
283
				echo "Unknown argument: $1"
282
				echo "Unknown argument: $1"
284
				echo "$usage"
283
				echo "$usage"
285
				exit 1
284
				exit 1
286
			fi
285
			fi
287
			;;
286
			;;
288
	esac
287
	esac
289
done
288
done
290
 
289
 
291
if [ -z $DOMAIN ]; then
290
if [ -z $DOMAIN ]; then
292
	if [ $(grep '^domainRequest=' $CONF_FILE | cut -d'=' -f2 | wc --chars) -gt 1 ]; then
291
	if [ $(grep '^domainRequest=' $CONF_FILE | cut -d'=' -f2 | wc --chars) -gt 1 ]; then
293
		DOMAIN="$(grep '^domainRequest=' $CONF_FILE | cut -d'=' -f2)"
292
		DOMAIN="$(grep '^domainRequest=' $CONF_FILE | cut -d'=' -f2)"
294
	else
293
	else
295
		DOMAIN="$(grep '^HOSTNAME=' /usr/local/etc/alcasar.conf | cut -d'=' -f2).$(grep '^DOMAIN=' /usr/local/etc/alcasar.conf | cut -d'=' -f2)"
294
		DOMAIN="$(grep '^HOSTNAME=' /usr/local/etc/alcasar.conf | cut -d'=' -f2).$(grep '^DOMAIN=' /usr/local/etc/alcasar.conf | cut -d'=' -f2)"
296
	fi
295
	fi
297
fi
296
fi
298
 
297
 
299
case $cmd in
298
case $cmd in
300
	issue)
299
	issue)
301
		issue
300
		issue
302
		;;
301
		;;
303
	renew)
302
	renew)
304
		renew
303
		renew
305
		;;
304
		;;
306
	cron)
305
	cron)
307
		cron_task
306
		cron_task
308
		;;
307
		;;
309
	install-cert)
308
	install-cert)
310
		install_cert
309
		install_cert
311
		;;
310
		;;
312
 
311
 
313
	*) exit 1 ;;
312
	*) exit 1 ;;
314
esac
313
esac
315
 
314