forked from StephenHynes7/le_rsyslog
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlersyslog
1723 lines (1484 loc) · 65.8 KB
/
lersyslog
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
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python2
# coding: utf-8
# ------------------ Main import section -------------------
# Mandatory modules go here.
import ConfigParser
import getopt
import getpass
import hashlib
import httplib
import logging
import os
import platform
import socket
import subprocess
import sys
import re
import errno
import urllib
# ------------------- Constants section --------------------
# Application version
try:
from collections import OrderedDict
except ImportError:
from ordereddict import OrderedDict
LE_LERSYSLOG_NAME = 'lersyslog'
# This value should be replaced by version generator
LE_LERSYSLOG_VERSION = '1.0.9'
# Process exit codes
EXIT_OK = 0
EXIT_ERR = 1
# HTTP result codes
HTTP_OK = 200
HTTP_FORBIDDEN = 403
# Logger ID
LOG_LE_RSYSLOG = 'logentries.com'
# GUID regexp
LE_GUID_REGEXP = re.compile(
'[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}', re.IGNORECASE)
LE_EMAIL_REGEXP = re.compile(
'[0-9a-z#\{\}\[\]\.\{\}\&\!\^\'\`%\\+\-\|\~]+\@[0-9a-z\-]+\.[a-z]+', re.IGNORECASE)
# Paths
LE_LERSYSLOG_CONFIG_PATH = '/etc/logentries/rsyslog'
LE_LERSYSLOG_CONFIG_NAME = 'lersyslog.conf'
LE_LERSYSLOG_CERT_NAME = 'ca-certs.pem'
LE_RSYSLOG_CONFIG_FILE = LE_LERSYSLOG_CONFIG_PATH + \
'/' + LE_LERSYSLOG_CONFIG_NAME
RSYSLOG_CONF_FILE = '/etc/rsyslog.conf'
# Config sections and key names
CONF_MAIN_SECTION = 'Main'
CONF_HOST_KEY_PARAM = 'host-key'
CONF_ACOUNT_KEY_PARAM = 'account-key'
# Misc.
# Release information on LSB systems
LSB_RELEASE = '/etc/lsb-release'
# -------------------- Messages section --------------------
LOGGER_OBTAINING_ERROR = 'Cannot open log output'
APP_INTERRUPTED_MSG = '\nShutting down.'
USAGE_HELP_MESSAGE = """Logentries """ + LE_LERSYSLOG_NAME + """ version """ + str(LE_LERSYSLOG_VERSION) + """
Usage: lersyslog COMMAND [ARGS]
Where command is one of:
register Register this host
follow {file1, file2, ... ,fileN} Follow given files
help Show this message and exit
Where parameters are:
--version Show version number
--host-key= Set host key and exit
--account-key= Set account key and exit
--use-ca-provided Use internal bundled certificate
--force Force given operation
--debug Switch on debug messages
"""
PRIVILEGES_ERROR = LE_LERSYSLOG_NAME + ' must be invoked with elevated privileges. Please use command ' + \
'"sudo ./' + LE_LERSYSLOG_NAME + '"'
ACCOUNT_KEY_FORMAT_ERROR = 'Given account key does not look right.'
HOST_KEY_FORMAT_ERROR = 'Config check: given host key does not look right.'
KEYS_FORMAT_HELP = ' Key must be a valid GUID given in such form: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX ,' + \
' where X - a hexadecimal digit (0-9, a-f, A-F)'
UNKNOWN_PARAMETER_ERROR = 'Unknown parameter: '
CONFIG_PATH_CREATION_ERROR = 'Error while trying to create config dir (' + \
LE_LERSYSLOG_CONFIG_PATH + '): '
CONFIG_FILE_OPEN_ERROR = 'Error while creating/opening config file (' + \
LE_RSYSLOG_CONFIG_FILE + '): '
CONFIG_FILE_WRITE_ERROR = 'I/O error while saving config file (' + \
LE_RSYSLOG_CONFIG_FILE + '): '
CONFIG_FILE_READ_ERROR = 'I/O error while loading config file (' + \
LE_RSYSLOG_CONFIG_FILE + '): '
MALFORMED_KEY_FROM_CONFIG = 'It seems that value of \'%s\' parameter in ' + LE_RSYSLOG_CONFIG_FILE + ' file is ' + \
'malformed and cannot be used. Please run registration (./' + LE_LERSYSLOG_NAME + \
' register --account-key=... --host-key=... ) ' +\
'to reset %s value and supply both account and host keys from command line via ' + \
'--account-key and --host-key parameters.'
# -------------------- Dialog messages ---------------------
CREDENTIALS_DLG_HEADER = 'Please provide credentials that you have used\nduring registration on' + \
' Logentries service or hit ^C to quit.'
EMAIL_INPUT_MSG = 'E-Mail: '
PASSWORD_INPUT_MSG = 'Password: '
NO_ASSOC_ACCOUNTS = 'No accounts are associated with given credentials.'
ACCOUNT_CHOICE_DLG = 'Please, choose the account from the list:'
ACCOUNT_CHOICE_MSG = '\nChoose account by entering it\'s number in the list or press ^C to quit.\n' + \
'Your choice is: '
CREDENTIALS_INPUT_EMPTY_ERROR = 'E-mail or password is empty'
CERT_ERROR = 'Error: Cannot find suitable CA certificate.'
ERROR_ALREADY_REGISTERED = 'This host is already registered (host key in the config is %s). Use --force to override current registration.'
ERROR_NOT_REGISTERED = 'You have currently not registered this tool to your account. Please run' + \
' \'sudo lersyslog register\' or alternative \'sudo lersyslog register --account-key=...' + \
' --host-key=...\' before attempting to follow a file.'
# ----------------------- SSL certificate ------------------
authority_certificate = """-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID2TCCAsGgAwIBAgIDAjbQMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTAwMjE5MjIzOTI2WhcNMjAwMjE4MjIzOTI2WjBAMQswCQYDVQQG
EwJVUzEXMBUGA1UEChMOR2VvVHJ1c3QsIEluYy4xGDAWBgNVBAMTD0dlb1RydXN0
IFNTTCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJCzgMHk5Uat
cGA9uuUU3Z6KXot1WubKbUGlI+g5hSZ6p1V3mkihkn46HhrxJ6ujTDnMyz1Hr4Gu
FmpcN+9FQf37mpc8oEOdxt8XIdGKolbCA0mEEoE+yQpUYGa5jFTk+eb5lPHgX3UR
8im55IaisYmtph6DKWOy8FQchQt65+EuDa+kvc3nsVrXjAVaDktzKIt1XTTYdwvh
dGLicTBi2LyKBeUxY0pUiWozeKdOVSQdl+8a5BLGDzAYtDRN4dgjOyFbLTAZJQ50
96QhS6CkIMlszZhWwPKoXz4mdaAN+DaIiixafWcwqQ/RmXAueOFRJq9VeiS+jDkN
d53eAsMMvR8CAwEAAaOB2TCB1jAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFEJ5
VBthzVUrPmPVPEhX9Z/7Rc5KMB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4
ysxOMBIGA1UdEwEB/wQIMAYBAf8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDov
L2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYBBQUHAQEE
KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20wDQYJKoZI
hvcNAQEFBQADggEBANTvU4ToGr2hiwTAqfVfoRB4RV2yV2pOJMtlTjGXkZrUJPji
J2ZwMZzBYlQG55cdOprApClICq8kx6jEmlTBfEx4TCtoLF0XplR4TEbigMMfOHES
0tdT41SFULgCy+5jOvhWiU1Vuy7AyBh3hjELC3DwfjWDpCoTZFZnNF0WX3OsewYk
2k9QbSqr0E1TQcKOu3EDSSmGGM8hQkx0YlEVxW+o78Qn5Rsz3VqI138S0adhJR/V
4NwdzxoQ2KDLX4z6DOW/cf/lXUQdpj6HR/oaToODEj+IZpWYeZqF6wJHzSXj8gYE
TpnKXKBuervdo5AaRTPvvz7SBMS24CqFZUE+ENQ=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT
MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0
aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw
WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE
AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m
OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu
T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c
JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR
Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz
PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm
aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM
TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g
LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO
BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv
dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB
AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL
NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W
b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFSjCCBDKgAwIBAgIDBQMSMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQLExREb21haW4gVmFsaWRh
dGVkIFNTTDEbMBkGA1UEAxMSR2VvVHJ1c3QgRFYgU1NMIENBMB4XDTEyMDkxMDE5
NTI1N1oXDTE2MDkxMTIxMjgyOFowgcExKTAnBgNVBAUTIEpxd2ViV3RxdzZNblVM
ek1pSzNiL21hdktiWjd4bEdjMRMwEQYDVQQLEwpHVDAzOTM4NjcwMTEwLwYDVQQL
EyhTZWUgd3d3Lmdlb3RydXN0LmNvbS9yZXNvdXJjZXMvY3BzIChjKTEyMS8wLQYD
VQQLEyZEb21haW4gQ29udHJvbCBWYWxpZGF0ZWQgLSBRdWlja1NTTChSKTEbMBkG
A1UEAxMSYXBpLmxvZ2VudHJpZXMuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAxcmFqgE2p6+N9lM2GJhe8bNUO0qmcw8oHUVrsneeVA66hj+qKPoJ
AhGKxC0K9JFMyIzgPu6FvuVLahFZwv2wkbjXKZLIOAC4o6tuVb4oOOUBrmpvzGtL
kKVN+sip1U7tlInGjtCfTMWNiwC4G9+GvJ7xORgDpaAZJUmK+4pAfG8j6raWgPGl
JXo2hRtOUwmBBkCPqCZQ1mRETDT6tBuSAoLE1UMlxWvMtXCUzeV78H+2YrIDxn/W
xd+eEvGTSXRb/Q2YQBMqv8QpAlarcda3WMWj8pkS38awyBM47GddwVYBn5ZLEu/P
DiRQGSmLQyFuk5GUdApSyFETPL6p9MfV4wIDAQABo4IBqDCCAaQwHwYDVR0jBBgw
FoAUjPTZkwpHvACgSs5LdW6gtrCyfvwwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHREEFjAUghJhcGkubG9nZW50cmll
cy5jb20wQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2d0c3NsZHYtY3JsLmdlb3Ry
dXN0LmNvbS9jcmxzL2d0c3NsZHYuY3JsMB0GA1UdDgQWBBRaMeKDGSFaz8Kvj+To
j7eMOtT/zTAMBgNVHRMBAf8EAjAAMHUGCCsGAQUFBwEBBGkwZzAsBggrBgEFBQcw
AYYgaHR0cDovL2d0c3NsZHYtb2NzcC5nZW90cnVzdC5jb20wNwYIKwYBBQUHMAKG
K2h0dHA6Ly9ndHNzbGR2LWFpYS5nZW90cnVzdC5jb20vZ3Rzc2xkdi5jcnQwTAYD
VR0gBEUwQzBBBgpghkgBhvhFAQc2MDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cu
Z2VvdHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwDQYJKoZIhvcNAQEFBQADggEBAAo0
rOkIeIDrhDYN8o95+6Y0QhVCbcP2GcoeTWu+ejC6I9gVzPFcwdY6Dj+T8q9I1WeS
VeVMNtwJt26XXGAk1UY9QOklTH3koA99oNY3ARcpqG/QwYcwaLbFrB1/JkCGcK1+
Ag3GE3dIzAGfRXq8fC9SrKia+PCdDgNIAFqe+kpa685voTTJ9xXvNh7oDoVM2aip
v1xy+6OfZyGudXhXag82LOfiUgU7hp+RfyUG2KXhIRzhMtDOHpyBjGnVLB0bGYcC
566Nbe7Alh38TT7upl/O5lA29EoSkngtUWhUnzyqYmEMpay8yZIV4R9AuUk2Y4HB
kAuBvDPPm+C0/M4RLYs=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID+jCCAuKgAwIBAgIDAjbSMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTAwMjI2MjEzMjMxWhcNMjAwMjI1MjEzMjMxWjBhMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UECxMURG9tYWluIFZh
bGlkYXRlZCBTU0wxGzAZBgNVBAMTEkdlb1RydXN0IERWIFNTTCBDQTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKa7jnrNpJxiV9RRMEJ7ixqy0ogGrTs8
KRMMMbxp+Z9alNoGuqwkBJ7O1KrESGAA+DSuoZOv3gR+zfhcIlINVlPrqZTP+3RE
60OUpJd6QFc1tqRi2tVI+Hrx7JC1Xzn+Y3JwyBKF0KUuhhNAbOtsTdJU/V8+Jh9m
cajAuIWe9fV1j9qRTonjynh0MF8VCpmnyoM6djVI0NyLGiJOhaRO+kltK3C+jgwh
w2LMpNGtFmuae8tk/426QsMmqhV4aJzs9mvIDFcN5TgH02pXA50gDkvEe4GwKhz1
SupKmEn+Als9AxSQKH6a9HjQMYRX5Uw4ekIR4vUoUQNLIBW7Ihq28BUCAwEAAaOB
2TCB1jAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFIz02ZMKR7wAoErOS3VuoLaw
sn78MB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4ysxOMBIGA1UdEwEB/wQI
MAYBAf8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5j
b20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAB
hhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20wDQYJKoZIhvcNAQEFBQADggEBADOR
NxHbQPnejLICiHevYyHBrbAN+qB4VqOC/btJXxRtyNxflNoRZnwekcW22G1PqvK/
ISh+UqKSeAhhaSH+LeyCGIT0043FiruKzF3mo7bMbq1vsw5h7onOEzRPSVX1ObuZ
lvD16lo8nBa9AlPwKg5BbuvvnvdwNs2AKnbIh+PrI7OWLOYdlF8cpOLNJDErBjgy
YWE5XIlMSB1CyWee0r9Y9/k3MbBn3Y0mNhp4GgkZPJMHcCrhfCn13mZXCxJeFu1e
vTezMGnGkqX2Gdgd+DYSuUuVlZzQzmwwpxb79k1ktl8qFJymyFWOIPllByTMOAVM
IIi0tWeUz12OYjf+xLQ=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIF4TCCA8mgAwIBAgIJAMuLUWygLQmXMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYD
VQQGEwJJRTEQMA4GA1UECAwHSXJlbGFuZDEPMA0GA1UEBwwGRHVibGluMRgwFgYD
VQQKDA9KbGl6YXJkIExpbWl0ZWQxEzARBgNVBAMMCkxvZ2VudHJpZXMxJTAjBgkq
hkiG9w0BCQEWFnN1cHBvcnRAbG9nZW50cmllcy5jb20wHhcNMTQwMjI0MjA1MzQ2
WhcNMTkwMjIzMjA1MzQ2WjCBhjELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxh
bmQxDzANBgNVBAcMBkR1YmxpbjEYMBYGA1UECgwPSmxpemFyZCBMaW1pdGVkMRMw
EQYDVQQDDApMb2dlbnRyaWVzMSUwIwYJKoZIhvcNAQkBFhZzdXBwb3J0QGxvZ2Vu
dHJpZXMuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAymhjhWPh
gz7tuk5Jj+ohRfjUMNoUKCvTPVCl5LPon7seXmt+FC0Cyf68VoGY8m5fuahWseKr
uyw7Bk7Q18vFBvsGp38q7NvQYlcQ2pCj7Ln6AvSlYvoweS4pz1C9C479ODNj9U2I
RcqNxfZX2alxZGsoGg0u/KS3RbXFZzyMGPSXbugzMAYFyoIJM1U1iGhrjj8yAGes
pP1BeDwrK9qHOv2Uy3yF8UtNKRm+hYE0E+yv0+s8vQLYnHaaZFwt1hulo0CGDjpJ
vZtmR5U0qRjdFE6RZJsetfPNYeUYYeyG8qwEKMK86K3Jj8J9MR4l21Q+rIzK7JMm
4P3Rh/L4klWEKm48WhfAhlv43CSpt/6HWhBq3B400effQzudl2O6VfC1OIlKWQ3x
jmAKZToIlIVeF7X/5z04Azhy2SVpQ1DNVGShlKIiyTIA04ny3udMdDr0InvmXHtn
rQexpaw5uFYno2tmOSJiElx5c7fMQtOmXO6qd/s9TFsNH8hwJ9g+Vgof11gTOo6o
MEEgzeVfMOPd5JOtPXOD+S9X0Vt0dUlCD4xbjpwH1kJ5hfTcLtmANDOAIjF+P9pY
ajDLE9phYM9qydyRaTawyOS7GA7XaW/WPZzgbSZ3T9KNJIUU1c1OZd3JD4BsDOBD
ZTRxHxanHeg2pAAmiNX1rIBwz5O8Zm13rT8CAwEAAaNQME4wHQYDVR0OBBYEFDk6
qPSf6apMD0hAGrYutT+wdnqhMB8GA1UdIwQYMBaAFDk6qPSf6apMD0hAGrYutT+w
dnqhMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBADQg6tx70qwG74dj
af9QDXKHhGvp8SoGMNvioQGREhrAXb0JTFiEQAECJghiP8OH4PIOjsN/ON4YI+WW
ZPdGlcPkUgFQ/bdB7eEyKtGa7hDfH1PLL1FqVhZjoLC6poCJJVo/Q9J2dlkGaksK
/R6+QV4SYnzfPH4cKQoN4Q/F0VuzelonSVTk9BG72RsY1fQPrm6tA/sN5Nzl+a4W
d1UnK4KXajQH1Qsnv8VTXyBc+8wM3C12m/lsqc2npgIqU/xlQQXgDBR087+A/dX3
osXMzZfGhh6D/NyCKs7VuAsb7hRTPP/6WMgM3c9lSc05xZyXzEZ7FL4GYg3Gjsdg
PFQMkgfMyiECBPudVzU2RyWuXdId+i0ezl1mBSrowa+eNCx2pI5Er7OAjvEQOAlC
v50jvvwSU9dT39XkGNh+q5uxaFLxyr6WidT09xHi17RZhgcMzWkiShRRqum/rOfL
TUPMGFvOjLiMiRZvHYhB3XjPqO5z3DEWT6Ux8IUN0aqNWCSLV2DOc/2riflxtExc
V1XUj6wWPCNqNPvdXeuQl/yqOZM5ekBlPCpPyxztba8SrJZKVWRXJl3RxuKPuWIE
XI7Mr8xQHVr1HLt/SU+by7Y7im6nyZUfOzTNMkic0RXgI0fqztetDpfLedN8Xlwn
/1NE/L7egzmDtcwoSQYUTu8g5rI4
-----END CERTIFICATE-----
"""
# ------------------- Auxiliary routines -------------------
def report(message):
log.info(message)
def die(message):
log.fatal(message)
sys.exit(EXIT_ERR)
def app_quit():
sys.exit(EXIT_OK)
# --------------- Classes definition section ---------------
class Config:
def __init__(self):
self.debug = False
self.force = False
self.email = ''
self.password = ''
# Config-aware fields
self.account_key = ''
self.host_key = ''
# Miscellaneous
self.use_ssl = False
self.use_ca_provided = False
self.name = ''
self.host_name = ''
self.account_key_cmd_line_param = False
self.host_key_cmd_line_param = False
if not self.load():
self.save() # Create default config
def process_parameters(self, argv):
"""
Gets parameters from argv list and sets corresponding internal fields of
Config instance.
:param argv:
:return list(command):
"""
try:
optlist, args = getopt.gnu_getopt(argv, '',
'account-key= host-key= name= hostname= use-ca-provided force debug'.split())
except getopt.GetoptError, err:
die('Parameter error: ' + str(err))
for name, value in optlist:
if name == '--account-key':
self.account_key_cmd_line_param = True
if Config.verify_account_key(value):
self.account_key = value
else:
die(ACCOUNT_KEY_FORMAT_ERROR + KEYS_FORMAT_HELP)
elif name == '--host-key':
self.host_key_cmd_line_param = True
if Config.verify_host_key(value):
self.host_key = value
else:
die(HOST_KEY_FORMAT_ERROR + KEYS_FORMAT_HELP)
elif name == "--use-ca-provided":
self.use_ca_provided = True
elif name == '--name':
self.name = value
elif name == '--hostname':
self.host_name = value
elif name == '--force':
self.force = True
elif name == '--debug':
self.debug = True
else:
# Unknown parameter:
die(UNKNOWN_PARAMETER_ERROR + value)
if self.host_key_cmd_line_param and not self.account_key_cmd_line_param:
die('Please specify --host-key parameter only alongside with --account-key parameter!')
return args
def save(self):
"""
Saves all internal fields of Config instance to the config file.
:return:
"""
try:
log.debug(
'[DEBUG]: Saving config to file ' + LE_RSYSLOG_CONFIG_FILE)
conf = ConfigParser.SafeConfigParser()
Config.get_or_create_config_dir()
try:
conf_file = open(LE_RSYSLOG_CONFIG_FILE, 'wb+')
except Exception, e:
die(CONFIG_FILE_OPEN_ERROR)
# Populate config object
conf.add_section(CONF_MAIN_SECTION)
# Default values if instance values are not set
account_key = ''
host_key = ''
if not self.account_key is None:
account_key = self.account_key
if not self.host_key is None:
host_key = self.host_key
# Push values to config object
conf.set(CONF_MAIN_SECTION, CONF_ACOUNT_KEY_PARAM, account_key)
conf.set(CONF_MAIN_SECTION, CONF_HOST_KEY_PARAM, host_key)
conf.write(conf_file)
except IOError as e:
report(CONFIG_FILE_WRITE_ERROR)
die(e)
def load(self):
"""
Loads data from config file and initializes internal fields of config instance.
:return True if config is loaded and parsed successfully:
"""
try:
log.debug(
'[DEBUG]: Loading config from file ' + LE_RSYSLOG_CONFIG_FILE)
conf = ConfigParser.SafeConfigParser({
CONF_HOST_KEY_PARAM: '',
CONF_ACOUNT_KEY_PARAM: ''
})
conf.read(LE_RSYSLOG_CONFIG_FILE)
account_key = conf.get(CONF_MAIN_SECTION, CONF_ACOUNT_KEY_PARAM)
host_key = conf.get(CONF_MAIN_SECTION, CONF_HOST_KEY_PARAM)
if account_key != '':
if not Config.verify_account_key(account_key):
report(MALFORMED_KEY_FROM_CONFIG %
(CONF_ACOUNT_KEY_PARAM, CONF_ACOUNT_KEY_PARAM))
if host_key != '':
if not Config.verify_host_key(host_key):
report(MALFORMED_KEY_FROM_CONFIG %
(CONF_HOST_KEY_PARAM, CONF_HOST_KEY_PARAM))
# Corrupted config, but host still may be previously registered
if account_key == '' and host_key != '':
report('Warning! Account key parameter in the config is empty. It is recommended to ' +
'restore it either manually or using \"sudo lersyslog register ...\" command.')
self.account_key = account_key
self.host_key = host_key
except IOError as e:
report(CONFIG_FILE_READ_ERROR + e.message)
return False
except ConfigParser.NoSectionError as e:
report(e.message)
return False
except ConfigParser.NoOptionError as e:
report(e.message)
return False
else:
return True
def set_name(self):
"""
Sets host name if not set already. The new host name is
delivered from its hostname.
"""
if self.name is None or self.name == '':
self.name = self.set_hostname().split('.')[0]
return self.name
def set_hostname(self):
"""
Sets the hostname parameter based on server network name. If
the hostname is set already, it is kept untouched.
"""
host_name = socket.getfqdn()
if self.host_name is None or self.host_name == '':
self.host_name = host_name
return host_name
@staticmethod
def get_or_create_config_dir():
"""
Tries to create config directory. Returns it's path if succeeds.
:return str - Path to config directory:
"""
try:
os.makedirs(LE_LERSYSLOG_CONFIG_PATH)
except OSError as e:
if e.errno != errno.EEXIST:
die(CONFIG_PATH_CREATION_ERROR + e.message)
return LE_LERSYSLOG_CONFIG_PATH
@staticmethod
def verify_account_key(value):
"""
Checks given key to be a valid GUID.
:param value:
:return True if key is valid:
"""
return LE_GUID_REGEXP.match(value)
@staticmethod
def verify_host_key(value):
"""
Checks given key to be a valid GUID.
:param value:
:return True if key is valid:
"""
return LE_GUID_REGEXP.match(value)
@staticmethod
def validate_email(value):
return LE_EMAIL_REGEXP.match(value)
class ServerHTTPSConnection(httplib.HTTPSConnection):
"""
A slight modification of HTTPSConnection to verify the certificate
"""
def __init__(self, server, cert_file):
if not config.use_ssl:
httplib.HTTPSConnection.__init__(self, server)
else:
self.cert_file = cert_file
httplib.HTTPSConnection.__init__(self, server, cert_file=cert_file)
def wrap_socket(self, sock, certs=None, reqs=None):
if config.use_ssl:
return ssl.wrap_socket(sock, ca_certs=certs, cert_reqs=reqs)
else:
return sock
def connect(self):
if not config.use_ssl:
return httplib.HTTPSConnection.connect(self)
sock = ServerHTTPSConnection.create_connection(self.host, self.port)
try:
if self._tunnel_host:
self.sock = sock
self._tunnel()
except AttributeError:
pass
self.sock = self.wrap_socket(sock, self.cert_file, ssl.CERT_REQUIRED)
@staticmethod
def create_connection(host, port):
"""
A simplified version of socket.create_connection from Python 2.6.
"""
for addr_info in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
af, stype, proto, cn, sa = addr_info
soc = None
try:
soc = socket.socket(af, stype, proto)
soc.connect(sa)
return soc
except socket.error:
if socket:
soc.close()
raise socket.error, "Cannot make connection to %s:%s" % (host, port)
class API:
class Domain:
""" Logentries domains. """
# General domains
MAIN = 'logentries.com'
API = 'api.logentries.com'
DATA = 'data.logentries.com' # TODO
PULL = 'pull.logentries.com'
LE_SERVER_API = '/'
# Account-related addresses
ACCOUNT_KEYS_API = 'https://logentries.com/agent/account-keys/'
NON_SSL_PORT = 80
@staticmethod
def api_request(request, required=False, check_status=False, silent=False, die_on_error=True, method='POST'):
"""
Processes a request on the logentries domain.
"""
# Obtain response
if method == 'POST':
response, conn = API.get_response(method, API.Domain.LE_SERVER_API, urllib.urlencode(request),
silent=silent, die_on_error=die_on_error, domain=API.Domain.API)
else:
response, conn = API.get_response(method, urllib.quote('/' + config.account_key + '/' + request),
silent=silent, die_on_error=die_on_error, domain=API.Domain.API)
# Check the response
if not response:
if required:
die("Error: Cannot process LE request, no response")
if conn:
conn.close()
return None
if response.status != 200:
if required:
die("Error: Cannot process LE request: (%s)" % response.status)
conn.close()
return None
xresponse = response.read()
conn.close()
log.debug('[DEBUG]: Domain response: "%s"' % xresponse)
try:
d_response = json_loads(xresponse)
except ValueError:
error = 'Error: Invalid response, parse error.'
if die_on_error:
die(error)
else:
log.info(error)
d_response = None
if check_status and d_response['response'] != 'ok':
error = "Error: %s" % d_response['reason']
if die_on_error:
die(error)
else:
log.info(error)
d_response = None
return d_response
@staticmethod
def do_request(conn, operation, addr, data=None, headers={}):
log.debug('[DEBUG]: Domain request: %s %s %s %s' %
(operation, addr, data, headers))
if data:
conn.request(operation, addr, data, headers=headers)
else:
conn.request(operation, addr, headers=headers)
@staticmethod
def get_response(operation, addr, data=None, headers={}, silent=False, die_on_error=True, domain=Domain.API):
"""
Returns response from the domain or API server.
"""
response = None
conn = None
try:
conn = API.domain_connect(domain)
API.do_request(conn, operation, addr, data, headers)
response = conn.getresponse()
return response, conn
except socket.sslerror, msg: # Network error
if not silent:
log.info("[DEBUG]: SSL error: %s" % msg)
except socket.error, msg: # Network error
if not silent:
log.debug("[DEBUG]: Network error: %s" % msg)
except httplib.BadStatusLine as e:
error = "Internal error, bad status line in HTTP response: "
if die_on_error:
die(error + e.message)
else:
log.info(error)
return None, None
@staticmethod
def domain_connect(domain):
"""
Connects to the domain specified.
"""
# Find the correct server address
s = domain
log.debug('[DEBUG]: Connecting to %s', s)
# Pass the connection
if config.use_ssl:
return API.make_https_connection(s)
else:
return httplib.HTTPConnection(s)
@staticmethod
def make_https_connection(s):
"""
Makes HTTPS connection. Tried all available certificates.
"""
if not config.use_ca_provided:
# Try to connect with system certificate
try:
cert_file = SSL.system_cert_file()
if cert_file:
return ServerHTTPSConnection(s, cert_file)
except socket.error:
pass
# Try to connect with our default certificate
cert_file = SSL.default_cert_file()
if not cert_file:
die(CERT_ERROR)
return ServerHTTPSConnection(s, cert_file)
@staticmethod
def retrieve_account_keys():
"""
Retrieves account keys from the web server.
"""
username = config.email
password = config.password
try:
c = API.domain_connect(API.Domain.MAIN)
c.request('POST', API.Domain.ACCOUNT_KEYS_API,
urllib.urlencode(
{'username': username, 'password': password}),
{
'Referer': 'https://logentries.com/login/',
'Content-type': 'application/x-www-form-urlencoded',
})
response = c.getresponse()
if not response or response.status != HTTP_OK:
resp_val = 'err'
if response:
resp_val = response.status
if resp_val == HTTP_FORBIDDEN:
die('Error: Login failed. Invalid credentials.')
else:
report(
'Error: Unexpected login response from logentries: ')
die(resp_val)
else:
data = json_loads(response.read())
return data['accounts']
except socket.error as e:
die('Error: Cannot contact server ' + e.message)
except ValueError as e:
die('Error: Invalid response from the server (Parsing error ' +
e.message)
except KeyError:
die('Error: Invalid response from the server, user key not present.')
@staticmethod
def request_host_registration():
si = Misc.system_detect(True)
# Set or use predefined name and host name for the machine being
# registered
config.set_name()
config.set_hostname()
# Try to register this host - obtain host key for it.
request = {"request": "register",
'user_key': config.account_key,
'name': config.name,
'hostname': config.host_name,
'system': si['system'],
'distname': si['distname'],
'distver': si['distver']}
log.debug('[DEBUG]: Processing registration request:')
log.debug(request)
response = API.api_request(request, True, True)
config.host_key = response['host_key']
log.debug('[DEBUG]: Got host key: ' + config.host_key)
@staticmethod
def follow_file(file_path, name, type_opt):
"""
Creates a new log to follow the file given.
"""
request = {"request": "new_log",
"user_key": config.account_key,
"host_key": config.host_key,
"name": name,
"filename": file_path,
"type": type_opt,
"source": "token",
"follow": "true"}
API.api_request(request, True, True)
@staticmethod
def get_followed_logs():
host = API.api_request(
'hosts/%s/' % config.host_key, True, True, False, True, 'GET')
logs = host.get('list')
return logs
class Misc:
@staticmethod
def rfile(name):
"""
Returns content of the file, without trailing newline.
"""
x = open(name).read()
if len(x) != 0 and x[-1] == '\n':
x = x[0:len(x) - 1]
return x
@staticmethod
def call(command):
"""
Calls the given command in OS environment.
"""
x = subprocess.Popen(
command, stdout=subprocess.PIPE, shell=True).stdout.read()
if len(x) == 0:
return ''
if x[-1] == '\n':
x = x[0:len(x) - 1]
return x
@staticmethod
def release_test(filename, distname, system_info):
if os.path.isfile(filename):
system_info['distname'] = distname
system_info['distver'] = Misc.rfile(filename)
return True
return False
@staticmethod
def system_detect(details):
"""
Detects the current operating system. Returned information contains:
distname: distribution name
distver: distribution version
kernel: kernel type
system: system name
hostname: host name
"""
uname = platform.uname()
sys = uname[0]
system_info = dict(system=sys, hostname=socket.getfqdn(),
kernel='', distname='', distver='')
if not details:
return system_info
if sys == "SunOS":
pass
elif sys == "AIX":
system_info['distver'] = Misc.call("oslevel -r")
elif sys == "Darwin":
system_info['distname'] = Misc.call("sw_vers -productName")
system_info['distver'] = Misc.call("sw_vers -productVersion")
system_info['kernel'] = uname[2]
elif sys == "Linux":
system_info['kernel'] = uname[2]
# XXX CentOS?
releases = [
['/etc/debian_version', 'Debian'],
['/etc/UnitedLinux-release', 'United Linux'],
['/etc/annvix-release', 'Annvix'],
['/etc/arch-release', 'Arch Linux'],
['/etc/arklinux-release', 'Arklinux'],
['/etc/aurox-release', 'Aurox Linux'],
['/etc/blackcat-release', 'BlackCat'],
['/etc/cobalt-release', 'Cobalt'],
['/etc/conectiva-release', 'Conectiva'],
['/etc/fedora-release', 'Fedora Core'],
['/etc/gentoo-release', 'Gentoo Linux'],
['/etc/immunix-release', 'Immunix'],
['/etc/knoppix_version', 'Knoppix'],
['/etc/lfs-release', 'Linux-From-Scratch'],
['/etc/linuxppc-release', 'Linux-PPC'],
['/etc/mandriva-release', 'Mandriva Linux'],
['/etc/mandrake-release', 'Mandrake Linux'],
['/etc/mandakelinux-release', 'Mandrake Linux'],
['/etc/mklinux-release', 'MkLinux'],
['/etc/nld-release', 'Novell Linux Desktop'],
['/etc/pld-release', 'PLD Linux'],
['/etc/redhat-release', 'Red Hat'],
['/etc/slackware-version', 'Slackware'],
['/etc/e-smith-release', 'SME Server'],
['/etc/release', 'Solaris SPARC'],
['/etc/sun-release', 'Sun JDS'],
['/etc/SuSE-release', 'SuSE'],
['/etc/sles-release', 'SuSE Linux ES9'],
['/etc/tinysofa-release', 'Tiny Sofa'],
['/etc/turbolinux-release', 'TurboLinux'],
['/etc/ultrapenguin-release', 'UltraPenguin'],
['/etc/va-release', 'VA-Linux/RH-VALE'],
['/etc/yellowdog-release', 'Yellow Dog'],
]
# Check for known system IDs
for release in releases:
if Misc.release_test(release[0], release[1], system_info):
break
# Check for general LSB system
if os.path.isfile(LSB_RELEASE):
try:
fields = dict((a.split('=') for a in Misc.rfile(
LSB_RELEASE).split('\n') if len(a.split('=')) == 2))
system_info['distname'] = fields['DISTRIB_ID']
system_info['distver'] = fields['DISTRIB_RELEASE']
except ValueError:
pass
except KeyError:
pass
return system_info
class SSL:
authority_certificate = authority_certificate
authority_certificate_files = [ # Debian 5.x, 6.x, 7.x, Ubuntu 9.10, 10.4, 13.0
# Fedora 12, Fedora 13, CentOS 5
"/etc/ssl/certs/ca-certificates.crt",
# Amazon AMI
"/usr/share/purple/ca-certs/GeoTrust_Global_CA.pem",
"/etc/pki/tls/certs/ca-bundle.crt"]
@staticmethod
def get_cert():
if not config.use_ca_provided:
cert_name = SSL.system_cert_file()
if cert_name is None:
cert_name = SSL.default_cert_file()
else:
cert_name = SSL.default_cert_file()
if cert_name is None:
die('Cannot get default certificate file name to provide connection over SSL!')
@staticmethod
def default_cert_file_name():
return LE_LERSYSLOG_CONFIG_PATH + '/' + LE_LERSYSLOG_CERT_NAME
@staticmethod
def write_default_cert_file():
"""
Writes default certificate file in the configuration directory.
"""
Config.get_or_create_config_dir()
cert_filename = SSL.default_cert_file_name()
f = open(cert_filename, 'wb')
f.write(authority_certificate)
f.close()
@staticmethod
def default_cert_file():
"""
Returns location of the default certificate file or None. It tries to write the
certificate file if it is not there or it is outdated.
"""
cert_filename = SSL.default_cert_file_name()
try:
# If the certificate file is not there, create it
if not os.path.exists(cert_filename):
SSL.write_default_cert_file()
return cert_filename
# If it is there, check if it is outdated
curr_cert = Misc.rfile(cert_filename)
if curr_cert != authority_certificate:
SSL.write_default_cert_file()
except IOError:
# Cannot read/write certificate file, ignore
return None
return cert_filename
@staticmethod
def system_cert_file():
"""
Finds the location of our lovely site's certificate on the system or None.
"""
for f in SSL.authority_certificate_files:
if os.path.exists(f):
return f
return None
class Worker:
def __init__(self):
pass
@staticmethod
def write_rsyslog_conf(helper, filepath, token):
if filepath and token:
file_item = RSyslogHelper.RsyslogFollowedFileTemplate(
filepath, token, 'info', 'local7')
template = RSyslogHelper.RsyslogLogMsgTemplate(
file_item.tag, file_item.token)
routing_rule = RSyslogHelper.RoutingRuleTemplate(file_item.tag, template.name, API.Domain.DATA,