Browse Source

Initial commit

tags/1.0
Timo Röhling 11 years ago
commit
35ec3e10a8
13 changed files with 2231 additions and 0 deletions
  1. 1
    0
      .gitignore
  2. 25
    0
      CMakeLists.txt
  3. 339
    0
      LICENSE
  4. 52
    0
      README.md
  5. 8
    0
      main.cf.ex
  6. 11
    0
      makefile
  7. 35
    0
      postinstall.cmake.in
  8. 392
    0
      postsrsd.c
  9. 15
    0
      postsrsd.default
  10. 85
    0
      postsrsd.init.in
  11. 386
    0
      sha1.c
  12. 704
    0
      srs2.c
  13. 178
    0
      srs2.h

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
1
+build

+ 25
- 0
CMakeLists.txt View File

@@ -0,0 +1,25 @@
1
+cmake_minimum_required(VERSION 2.8)
2
+project(postsrsd C)
3
+
4
+find_program(HELP2MAN help2man DOC "path to help2man executable")
5
+find_program(DD dd DOC "path to dd executable")
6
+find_program(BASE64 base64 DOC "path to base64 executable")
7
+
8
+add_executable(${PROJECT_NAME} postsrsd.c sha1.c srs2.c)
9
+configure_file(${PROJECT_NAME}.init.in ${PROJECT_NAME}.init @ONLY)
10
+configure_file(postinstall.cmake.in postinstall.cmake @ONLY)
11
+
12
+if(HELP2MAN)
13
+add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
14
+	COMMAND ${HELP2MAN} ARGS -s8 -o${PROJECT_NAME}.8 -N -h-h -v-v ./${PROJECT_NAME}
15
+	VERBATIM
16
+)
17
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.8 DESTINATION "share/man/man8")
18
+endif()
19
+
20
+install(TARGETS ${PROJECT_NAME} DESTINATION "sbin")
21
+install(FILES README.md main.cf.ex DESTINATION "share/doc/${PROJECT_NAME}")
22
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.init DESTINATION "/etc/init.d" RENAME ${PROJECT_NAME})
23
+install(FILES ${PROJECT_NAME}.default DESTINATION "/etc/default" RENAME ${PROJECT_NAME})
24
+install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/postinstall.cmake")
25
+

+ 339
- 0
LICENSE View File

@@ -0,0 +1,339 @@
1
+                    GNU GENERAL PUBLIC LICENSE
2
+                       Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+                            Preamble
10
+
11
+  The licenses for most software are designed to take away your
12
+freedom to share and change it.  By contrast, the GNU General Public
13
+License is intended to guarantee your freedom to share and change free
14
+software--to make sure the software is free for all its users.  This
15
+General Public License applies to most of the Free Software
16
+Foundation's software and to any other program whose authors commit to
17
+using it.  (Some other Free Software Foundation software is covered by
18
+the GNU Lesser General Public License instead.)  You can apply it to
19
+your programs, too.
20
+
21
+  When we speak of free software, we are referring to freedom, not
22
+price.  Our General Public Licenses are designed to make sure that you
23
+have the freedom to distribute copies of free software (and charge for
24
+this service if you wish), that you receive source code or can get it
25
+if you want it, that you can change the software or use pieces of it
26
+in new free programs; and that you know you can do these things.
27
+
28
+  To protect your rights, we need to make restrictions that forbid
29
+anyone to deny you these rights or to ask you to surrender the rights.
30
+These restrictions translate to certain responsibilities for you if you
31
+distribute copies of the software, or if you modify it.
32
+
33
+  For example, if you distribute copies of such a program, whether
34
+gratis or for a fee, you must give the recipients all the rights that
35
+you have.  You must make sure that they, too, receive or can get the
36
+source code.  And you must show them these terms so they know their
37
+rights.
38
+
39
+  We protect your rights with two steps: (1) copyright the software, and
40
+(2) offer you this license which gives you legal permission to copy,
41
+distribute and/or modify the software.
42
+
43
+  Also, for each author's protection and ours, we want to make certain
44
+that everyone understands that there is no warranty for this free
45
+software.  If the software is modified by someone else and passed on, we
46
+want its recipients to know that what they have is not the original, so
47
+that any problems introduced by others will not reflect on the original
48
+authors' reputations.
49
+
50
+  Finally, any free program is threatened constantly by software
51
+patents.  We wish to avoid the danger that redistributors of a free
52
+program will individually obtain patent licenses, in effect making the
53
+program proprietary.  To prevent this, we have made it clear that any
54
+patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+  The precise terms and conditions for copying, distribution and
57
+modification follow.
58
+
59
+                    GNU GENERAL PUBLIC LICENSE
60
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+  0. This License applies to any program or other work which contains
63
+a notice placed by the copyright holder saying it may be distributed
64
+under the terms of this General Public License.  The "Program", below,
65
+refers to any such program or work, and a "work based on the Program"
66
+means either the Program or any derivative work under copyright law:
67
+that is to say, a work containing the Program or a portion of it,
68
+either verbatim or with modifications and/or translated into another
69
+language.  (Hereinafter, translation is included without limitation in
70
+the term "modification".)  Each licensee is addressed as "you".
71
+
72
+Activities other than copying, distribution and modification are not
73
+covered by this License; they are outside its scope.  The act of
74
+running the Program is not restricted, and the output from the Program
75
+is covered only if its contents constitute a work based on the
76
+Program (independent of having been made by running the Program).
77
+Whether that is true depends on what the Program does.
78
+
79
+  1. You may copy and distribute verbatim copies of the Program's
80
+source code as you receive it, in any medium, provided that you
81
+conspicuously and appropriately publish on each copy an appropriate
82
+copyright notice and disclaimer of warranty; keep intact all the
83
+notices that refer to this License and to the absence of any warranty;
84
+and give any other recipients of the Program a copy of this License
85
+along with the Program.
86
+
87
+You may charge a fee for the physical act of transferring a copy, and
88
+you may at your option offer warranty protection in exchange for a fee.
89
+
90
+  2. You may modify your copy or copies of the Program or any portion
91
+of it, thus forming a work based on the Program, and copy and
92
+distribute such modifications or work under the terms of Section 1
93
+above, provided that you also meet all of these conditions:
94
+
95
+    a) You must cause the modified files to carry prominent notices
96
+    stating that you changed the files and the date of any change.
97
+
98
+    b) You must cause any work that you distribute or publish, that in
99
+    whole or in part contains or is derived from the Program or any
100
+    part thereof, to be licensed as a whole at no charge to all third
101
+    parties under the terms of this License.
102
+
103
+    c) If the modified program normally reads commands interactively
104
+    when run, you must cause it, when started running for such
105
+    interactive use in the most ordinary way, to print or display an
106
+    announcement including an appropriate copyright notice and a
107
+    notice that there is no warranty (or else, saying that you provide
108
+    a warranty) and that users may redistribute the program under
109
+    these conditions, and telling the user how to view a copy of this
110
+    License.  (Exception: if the Program itself is interactive but
111
+    does not normally print such an announcement, your work based on
112
+    the Program is not required to print an announcement.)
113
+
114
+These requirements apply to the modified work as a whole.  If
115
+identifiable sections of that work are not derived from the Program,
116
+and can be reasonably considered independent and separate works in
117
+themselves, then this License, and its terms, do not apply to those
118
+sections when you distribute them as separate works.  But when you
119
+distribute the same sections as part of a whole which is a work based
120
+on the Program, the distribution of the whole must be on the terms of
121
+this License, whose permissions for other licensees extend to the
122
+entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+Thus, it is not the intent of this section to claim rights or contest
125
+your rights to work written entirely by you; rather, the intent is to
126
+exercise the right to control the distribution of derivative or
127
+collective works based on the Program.
128
+
129
+In addition, mere aggregation of another work not based on the Program
130
+with the Program (or with a work based on the Program) on a volume of
131
+a storage or distribution medium does not bring the other work under
132
+the scope of this License.
133
+
134
+  3. You may copy and distribute the Program (or a work based on it,
135
+under Section 2) in object code or executable form under the terms of
136
+Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+    a) Accompany it with the complete corresponding machine-readable
139
+    source code, which must be distributed under the terms of Sections
140
+    1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+    b) Accompany it with a written offer, valid for at least three
143
+    years, to give any third party, for a charge no more than your
144
+    cost of physically performing source distribution, a complete
145
+    machine-readable copy of the corresponding source code, to be
146
+    distributed under the terms of Sections 1 and 2 above on a medium
147
+    customarily used for software interchange; or,
148
+
149
+    c) Accompany it with the information you received as to the offer
150
+    to distribute corresponding source code.  (This alternative is
151
+    allowed only for noncommercial distribution and only if you
152
+    received the program in object code or executable form with such
153
+    an offer, in accord with Subsection b above.)
154
+
155
+The source code for a work means the preferred form of the work for
156
+making modifications to it.  For an executable work, complete source
157
+code means all the source code for all modules it contains, plus any
158
+associated interface definition files, plus the scripts used to
159
+control compilation and installation of the executable.  However, as a
160
+special exception, the source code distributed need not include
161
+anything that is normally distributed (in either source or binary
162
+form) with the major components (compiler, kernel, and so on) of the
163
+operating system on which the executable runs, unless that component
164
+itself accompanies the executable.
165
+
166
+If distribution of executable or object code is made by offering
167
+access to copy from a designated place, then offering equivalent
168
+access to copy the source code from the same place counts as
169
+distribution of the source code, even though third parties are not
170
+compelled to copy the source along with the object code.
171
+
172
+  4. You may not copy, modify, sublicense, or distribute the Program
173
+except as expressly provided under this License.  Any attempt
174
+otherwise to copy, modify, sublicense or distribute the Program is
175
+void, and will automatically terminate your rights under this License.
176
+However, parties who have received copies, or rights, from you under
177
+this License will not have their licenses terminated so long as such
178
+parties remain in full compliance.
179
+
180
+  5. You are not required to accept this License, since you have not
181
+signed it.  However, nothing else grants you permission to modify or
182
+distribute the Program or its derivative works.  These actions are
183
+prohibited by law if you do not accept this License.  Therefore, by
184
+modifying or distributing the Program (or any work based on the
185
+Program), you indicate your acceptance of this License to do so, and
186
+all its terms and conditions for copying, distributing or modifying
187
+the Program or works based on it.
188
+
189
+  6. Each time you redistribute the Program (or any work based on the
190
+Program), the recipient automatically receives a license from the
191
+original licensor to copy, distribute or modify the Program subject to
192
+these terms and conditions.  You may not impose any further
193
+restrictions on the recipients' exercise of the rights granted herein.
194
+You are not responsible for enforcing compliance by third parties to
195
+this License.
196
+
197
+  7. If, as a consequence of a court judgment or allegation of patent
198
+infringement or for any other reason (not limited to patent issues),
199
+conditions are imposed on you (whether by court order, agreement or
200
+otherwise) that contradict the conditions of this License, they do not
201
+excuse you from the conditions of this License.  If you cannot
202
+distribute so as to satisfy simultaneously your obligations under this
203
+License and any other pertinent obligations, then as a consequence you
204
+may not distribute the Program at all.  For example, if a patent
205
+license would not permit royalty-free redistribution of the Program by
206
+all those who receive copies directly or indirectly through you, then
207
+the only way you could satisfy both it and this License would be to
208
+refrain entirely from distribution of the Program.
209
+
210
+If any portion of this section is held invalid or unenforceable under
211
+any particular circumstance, the balance of the section is intended to
212
+apply and the section as a whole is intended to apply in other
213
+circumstances.
214
+
215
+It is not the purpose of this section to induce you to infringe any
216
+patents or other property right claims or to contest validity of any
217
+such claims; this section has the sole purpose of protecting the
218
+integrity of the free software distribution system, which is
219
+implemented by public license practices.  Many people have made
220
+generous contributions to the wide range of software distributed
221
+through that system in reliance on consistent application of that
222
+system; it is up to the author/donor to decide if he or she is willing
223
+to distribute software through any other system and a licensee cannot
224
+impose that choice.
225
+
226
+This section is intended to make thoroughly clear what is believed to
227
+be a consequence of the rest of this License.
228
+
229
+  8. If the distribution and/or use of the Program is restricted in
230
+certain countries either by patents or by copyrighted interfaces, the
231
+original copyright holder who places the Program under this License
232
+may add an explicit geographical distribution limitation excluding
233
+those countries, so that distribution is permitted only in or among
234
+countries not thus excluded.  In such case, this License incorporates
235
+the limitation as if written in the body of this License.
236
+
237
+  9. The Free Software Foundation may publish revised and/or new versions
238
+of the General Public License from time to time.  Such new versions will
239
+be similar in spirit to the present version, but may differ in detail to
240
+address new problems or concerns.
241
+
242
+Each version is given a distinguishing version number.  If the Program
243
+specifies a version number of this License which applies to it and "any
244
+later version", you have the option of following the terms and conditions
245
+either of that version or of any later version published by the Free
246
+Software Foundation.  If the Program does not specify a version number of
247
+this License, you may choose any version ever published by the Free Software
248
+Foundation.
249
+
250
+  10. If you wish to incorporate parts of the Program into other free
251
+programs whose distribution conditions are different, write to the author
252
+to ask for permission.  For software which is copyrighted by the Free
253
+Software Foundation, write to the Free Software Foundation; we sometimes
254
+make exceptions for this.  Our decision will be guided by the two goals
255
+of preserving the free status of all derivatives of our free software and
256
+of promoting the sharing and reuse of software generally.
257
+
258
+                            NO WARRANTY
259
+
260
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+REPAIR OR CORRECTION.
269
+
270
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+POSSIBILITY OF SUCH DAMAGES.
279
+
280
+                     END OF TERMS AND CONDITIONS
281
+
282
+            How to Apply These Terms to Your New Programs
283
+
284
+  If you develop a new program, and you want it to be of the greatest
285
+possible use to the public, the best way to achieve this is to make it
286
+free software which everyone can redistribute and change under these terms.
287
+
288
+  To do so, attach the following notices to the program.  It is safest
289
+to attach them to the start of each source file to most effectively
290
+convey the exclusion of warranty; and each file should have at least
291
+the "copyright" line and a pointer to where the full notice is found.
292
+
293
+    <one line to give the program's name and a brief idea of what it does.>
294
+    Copyright (C) <year>  <name of author>
295
+
296
+    This program is free software; you can redistribute it and/or modify
297
+    it under the terms of the GNU General Public License as published by
298
+    the Free Software Foundation; either version 2 of the License, or
299
+    (at your option) any later version.
300
+
301
+    This program is distributed in the hope that it will be useful,
302
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
+    GNU General Public License for more details.
305
+
306
+    You should have received a copy of the GNU General Public License along
307
+    with this program; if not, write to the Free Software Foundation, Inc.,
308
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+Also add information on how to contact you by electronic and paper mail.
311
+
312
+If the program is interactive, make it output a short notice like this
313
+when it starts in an interactive mode:
314
+
315
+    Gnomovision version 69, Copyright (C) year name of author
316
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+    This is free software, and you are welcome to redistribute it
318
+    under certain conditions; type `show c' for details.
319
+
320
+The hypothetical commands `show w' and `show c' should show the appropriate
321
+parts of the General Public License.  Of course, the commands you use may
322
+be called something other than `show w' and `show c'; they could even be
323
+mouse-clicks or menu items--whatever suits your program.
324
+
325
+You should also get your employer (if you work as a programmer) or your
326
+school, if any, to sign a "copyright disclaimer" for the program, if
327
+necessary.  Here is a sample; alter the names:
328
+
329
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+  <signature of Ty Coon>, 1 April 1989
333
+  Ty Coon, President of Vice
334
+
335
+This General Public License does not permit incorporating your program into
336
+proprietary programs.  If your program is a subroutine library, you may
337
+consider it more useful to permit linking proprietary applications with the
338
+library.  If this is what you want to do, use the GNU Lesser General
339
+Public License instead of this License.

+ 52
- 0
README.md View File

@@ -0,0 +1,52 @@
1
+About
2
+=====
3
+PostSRSd provides the Sender Rewriting Scheme (SRS) via TCP-based 
4
+lookup tables for Postfix. SRS is needed if your mail server acts
5
+as forwarder. 
6
+
7
+Imagine your server receives a mail from alice@example.com
8
+that is to be forwarded. If example.com uses the Sender Policy Framework 
9
+to indicate that all legit mails originate from their server, your 
10
+forwarded mail might be bounced, because you have no permission to send
11
+on behalf of example.com. The solution is that you map the address to
12
+your own domain, e.g. 
13
+SRS0+xxxx=yy=example.com=alice@yourdomain.org (forward SRS). If the
14
+mail is bounced later and a notification arrives, you can extract the
15
+original address from the rewritten one (revere SRS) and return the
16
+notification to the sender. You might notice that the reverse SRS can
17
+be abused to turn your server into an open relay. For this reason, xxxx
18
+and yy are a cryptographic signature and a time stamp. If the signature
19
+does not match, the address is forged and the mail can be discarded.
20
+
21
+Building
22
+========
23
+PostSRSd requires a POSIX compatible system and CMake to build. 
24
+Optionally, help2man is used to create a manual page.
25
+
26
+For convenience, a Makefile fragment is provided which calls CMake with
27
+the recommended command line options. Just run `make`.
28
+
29
+Installing
30
+==========
31
+Run `make install` as root to install the daemon and the configuration
32
+files.
33
+
34
+Configuration
35
+=============
36
+The configuration is located in `/etc/default/postsrsd`. You must store 
37
+a secret key in `/etc/postsrsd.secret`. The installer tries to generate 
38
+one from `/dev/urandom`. Be careful that no one can guess your secret,
39
+because anyone who knows it can use your mail server as open relay!
40
+
41
+PostSRSd exposes its functionality via two TCP lookup tables. The
42
+recommended Postfix configuration is to add the following fragment to
43
+your main.cf:
44
+
45
+    sender_canonical_maps = tcp:127.0.0.1:10001
46
+    sender_canonical_classes = envelope_sender
47
+    recipient_canonical_maps = tcp:127.0.0.1:10002
48
+    recipient_canonical_maps = envelope_recipient
49
+
50
+This will transparently rewrite incoming and outgoing envelope addresses.
51
+Run `service postsrsd start` and `postfix reload` as root, or reboot.
52
+

+ 8
- 0
main.cf.ex View File

@@ -0,0 +1,8 @@
1
+# Add this fragment to your main.cf
2
+
3
+sender_canonical_maps = tcp:127.0.0.1:10001
4
+sender_canonical_classes = envelope_sender
5
+recipient_canonical_maps = tcp:127.0.0.1:10002
6
+recipient_canonical_maps = envelope_recipient
7
+
8
+

+ 11
- 0
makefile View File

@@ -0,0 +1,11 @@
1
+all install: build/Makefile
2
+	$(MAKE) -C build $@
3
+
4
+clean distclean:
5
+	rm -rf build
6
+
7
+build/Makefile: CMakeLists.txt
8
+	mkdir -p build
9
+	cd build && cmake .. -DCMAKE_BUILD_TYPE=Release
10
+
11
+	

+ 35
- 0
postinstall.cmake.in View File

@@ -0,0 +1,35 @@
1
+message(STATUS "Updating RC: $ENV{DESTDIR}/etc/init.d/@PROJECT_NAME@")
2
+file(MAKE_DIRECTORY 
3
+	"$ENV{DESTDIR}/etc/rc0.d" 
4
+	"$ENV{DESTDIR}/etc/rc1.d" 
5
+	"$ENV{DESTDIR}/etc/rc2.d" 
6
+	"$ENV{DESTDIR}/etc/rc3.d" 
7
+	"$ENV{DESTDIR}/etc/rc4.d" 
8
+	"$ENV{DESTDIR}/etc/rc5.d" 
9
+	"$ENV{DESTDIR}/etc/rc6.d" 
10
+)
11
+execute_process(
12
+	COMMAND ln -sf ../init.d/@PROJECT_NAME@ rc0.d/K20@PROJECT_NAME@
13
+	COMMAND ln -sf ../init.d/@PROJECT_NAME@ rc1.d/K20@PROJECT_NAME@
14
+	COMMAND ln -sf ../init.d/@PROJECT_NAME@ rc2.d/S20@PROJECT_NAME@
15
+	COMMAND ln -sf ../init.d/@PROJECT_NAME@ rc3.d/S20@PROJECT_NAME@
16
+	COMMAND ln -sf ../init.d/@PROJECT_NAME@ rc4.d/S20@PROJECT_NAME@
17
+	COMMAND ln -sf ../init.d/@PROJECT_NAME@ rc5.d/S20@PROJECT_NAME@
18
+	COMMAND ln -sf ../init.d/@PROJECT_NAME@ rc6.d/K20@PROJECT_NAME@
19
+	WORKING_DIRECTORY "$ENV{DESTDIR}/etc"
20
+)
21
+set(SECRET_FILE "@PROJECT_NAME@.secret")
22
+set(DD "@DD@")
23
+set(BASE64 "@BASE64@")
24
+if(DD AND BASE64 AND EXISTS "/dev/urandom" AND NOT EXISTS "$ENV{DESTDIR}/etc/${SECRET_FILE}")
25
+	message(STATUS "Generating secret key")
26
+	execute_process(
27
+		COMMAND ${DD} if=/dev/urandom bs=18 count=1
28
+		COMMAND ${BASE64} -w0
29
+		OUTPUT_FILE "@CMAKE_CURRENT_BINARY_DIR@/${SECRET_FILE}"
30
+		ERROR_QUIET
31
+		OUTPUT_STRIP_TRAILING_WHITESPACE
32
+	)
33
+file(INSTALL "@CMAKE_CURRENT_BINARY_DIR@/${SECRET_FILE}" DESTINATION "/etc" FILE_PERMISSIONS OWNER_READ OWNER_WRITE)
34
+endif()
35
+

+ 392
- 0
postsrsd.c View File

@@ -0,0 +1,392 @@
1
+/* PostSRSd - Sender Rewriting Scheme daemon for Postfix
2
+ * Copyright (c) 2012 Timo Röhling <timo.roehling@gmx.de>
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation, either version 2 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+/* This program uses the libsrs2 library. The relevant source
19
+ * files have been added to this distribution. */
20
+
21
+#include "srs2.h"
22
+#include <sys/types.h>
23
+#include <sys/socket.h>
24
+#include <netdb.h>
25
+#include <errno.h>
26
+#include <unistd.h>
27
+#include <fcntl.h>
28
+#include <pwd.h>
29
+#include <string.h>
30
+#include <poll.h>
31
+#include <wait.h>
32
+
33
+#ifndef VERSION
34
+#define VERSION "1.0"
35
+#endif
36
+
37
+static char *self = NULL;
38
+
39
+static int bind_service (const char *service, int family)
40
+{
41
+  struct addrinfo *addr, *it;
42
+  struct addrinfo hints;
43
+  int err, sock, flags;
44
+  static const int one = 1;
45
+
46
+  memset (&hints, 0, sizeof(hints));
47
+  hints.ai_family = family;
48
+  hints.ai_socktype = SOCK_STREAM;
49
+  hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
50
+  err = getaddrinfo(NULL, service, &hints, &addr);
51
+  if (err != 0) {
52
+    fprintf(stderr, "%s: bind_service(%s): %s\n", self, service, gai_strerror(err));
53
+    return -1;
54
+  }
55
+  sock = -1;
56
+  for (it = addr; it; it = it->ai_next) {
57
+    sock = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
58
+    if (sock < 0) goto fail;
59
+    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) goto fail;
60
+    if (bind(sock, it->ai_addr, it->ai_addrlen) < 0) goto fail;
61
+    if (listen(sock, 10) < 0) goto fail;
62
+    flags = fcntl (sock, F_GETFL, 0);
63
+    if (flags < 0) goto fail;
64
+    if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) goto fail;
65
+    break;
66
+  fail:
67
+    err = errno;
68
+    if (sock >= 0) close (sock);
69
+    sock = -1;
70
+  }
71
+  freeaddrinfo (addr);
72
+  if (sock < 0)
73
+    fprintf (stderr, "%s: bind_service(%s): %s\n", self, service, strerror(err));
74
+  return sock;
75
+}
76
+
77
+static int is_hexdigit (char c)
78
+{
79
+  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
80
+}
81
+
82
+static char hex2num (char c)
83
+{
84
+  if (c >= '0' && c <= '9') return c - '0';
85
+  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
86
+  if (c >= 'A' && c <= 'F') return c - 'A' + 10;
87
+}
88
+
89
+static char num2hex (char c)
90
+{
91
+  if (c < 10) return '0' + c;
92
+  return 'a' + c - 10;
93
+}
94
+
95
+static char hex2char (const char *s)
96
+{
97
+  return 16 * hex2num(s[0]) + hex2num(s[1]);
98
+}
99
+
100
+static void char2hex (char c, char *buf)
101
+{
102
+  buf[0] = num2hex((c >> 4) & 0xf);
103
+  buf[1] = num2hex((c     ) & 0xf);
104
+}
105
+
106
+static char* url_decode (char *buf, size_t len, const char *input)
107
+{
108
+  char *output = buf;
109
+  if (!input || !output || len == 0) return NULL;
110
+
111
+  while (*input && --len) {
112
+    if (*input == '%' && is_hexdigit(input[1]) && is_hexdigit(input[2])) {
113
+      *output++ = hex2char(++input);
114
+      input += 2;
115
+    } else {
116
+      *output++ = *input++;
117
+    }
118
+  }
119
+  *output = 0;
120
+  return buf;
121
+}
122
+
123
+static char* url_encode (char* buf, size_t len, const char *input)
124
+{
125
+  char *output = buf;
126
+  if (!input || !output || len == 0) return NULL;
127
+  while (*input && --len) {
128
+    if (isspace(*input)) {
129
+      if (len <= 2) break;
130
+      *output++ = '%';
131
+      char2hex(*input, output);
132
+      output += 2; len -= 2;
133
+    } else {
134
+      *output++ = *input++;
135
+    }
136
+  }
137
+  *output = 0;
138
+  return buf;
139
+}
140
+
141
+static void handle_forward (srs_t *srs, FILE *fp, const char *address, const char *domain)
142
+{
143
+  int result;
144
+  char value[1024];
145
+  char outputbuf[1024], *output;
146
+
147
+  result = srs_forward(srs, value, sizeof(value), address, domain);
148
+  if (result == SRS_SUCCESS) {
149
+    output = url_encode(outputbuf, sizeof(outputbuf), value);
150
+    fprintf (fp, "200 %s\n", output);
151
+  } else {
152
+    fprintf (fp, "500 %s\n", srs_strerror(result));
153
+  }
154
+  fflush (fp);
155
+}
156
+
157
+static void handle_reverse (srs_t *srs, FILE *fp, const char *address, const char *domain)
158
+{
159
+  int result;
160
+  char value[1024];
161
+  char outputbuf[1024], *output;
162
+  result = srs_reverse(srs, value, sizeof(value), address);
163
+  if (result == SRS_SUCCESS) {
164
+    output = url_encode(outputbuf, sizeof(outputbuf), value);
165
+    fprintf (fp, "200 %s\n", output);
166
+  } else {
167
+    fprintf (fp, "500 %s\n", srs_strerror(result));
168
+  }
169
+  fflush (fp);
170
+}
171
+
172
+static void show_help ()
173
+{
174
+  fprintf (stdout,
175
+    "Sender Rewriting Scheme implementation for Postfix.\n\n"
176
+    "Implements two TCP lookup tables to rewrite mail addresses\n"
177
+    "as needed. The forward SRS is for sender envelope addresses\n"
178
+    "to prevent SPF-related bounces. The reverse SRS is for\n"
179
+    "recipient envelope addresses so that bounced mails can be\n"
180
+    "routed back to their original sender.\n"
181
+    "\n"
182
+    "Usage: %s -s<file> -d<domain> [other options]\n"
183
+    "Options:\n"
184
+    "   -s<file>       read secret from file (required)\n"
185
+    "   -d<domain>     set domain name for rewrite (required)\n"
186
+    "   -f<port>       set port for the forward SRS lookup (default: 10001)\n"
187
+    "   -r<port>       set port for the reverse SRS lookup (default: 10002)\n"
188
+    "   -p<pidfile>    write process ID to pidfile (default: none)\n"
189
+    "   -u<user>       switch user id after port bind (default: none)\n"
190
+    "   -t<seconds>    timeout for idle client connections (default: 1800)\n"
191
+    "   -D             fork into background\n"
192
+    "   -4             force IPv4 socket (default: any)\n"
193
+    "   -6             force IPv6 socket (default: any)\n"
194
+    "   -h             show this help\n"
195
+    "   -v             show version\n"
196
+    "\n",
197
+    self
198
+  );
199
+}
200
+
201
+typedef void(*handle_t)(srs_t*, FILE*, const char*, const char*);
202
+
203
+int main (int argc, char **argv)
204
+{
205
+  int opt, timeout = 1800, family = AF_UNSPEC;
206
+  int daemonize = FALSE;
207
+  char *forward_service = NULL, *reverse_service = NULL,
208
+       *user = NULL, *domain = NULL;
209
+  int forward_sock, reverse_sock;
210
+  char *secret_file = NULL, *pid_file = NULL;
211
+  FILE *pf = NULL;
212
+  char secret[1024];
213
+  char *tmp;
214
+  srs_t *srs;
215
+  struct pollfd fds[3];
216
+  handle_t handler[2] = { handle_forward, handle_reverse };
217
+
218
+  tmp = strrchr(argv[0], '/');
219
+  if (tmp) self = strdup(tmp + 1); else self = strdup(argv[0]);
220
+
221
+  while ((opt = getopt(argc, argv, "46d:f:r:s:u:t:p:Dhv")) != -1) {
222
+    switch (opt) {
223
+      case '?':
224
+        return EXIT_FAILURE;
225
+      case '4':
226
+        family = AF_INET;
227
+        break;
228
+      case '6':
229
+        family = AF_INET6;
230
+        break;
231
+      case 'd':
232
+        domain = strdup(optarg);
233
+        break;
234
+      case 'f':
235
+        forward_service = strdup(optarg);
236
+        break;
237
+      case 'r':
238
+        reverse_service = strdup(optarg);
239
+        break;
240
+      case 't':
241
+        timeout = atoi(optarg);
242
+        break;
243
+      case 's':
244
+        secret_file = strdup(optarg);
245
+        break;
246
+      case 'p':
247
+        pid_file = strdup(optarg);
248
+        break;
249
+      case 'u':
250
+        user = strdup(optarg);
251
+        break;
252
+      case 'D':
253
+        daemonize = TRUE;
254
+        break;
255
+      case 'h':
256
+	show_help();
257
+        return EXIT_SUCCESS;
258
+      case 'v':
259
+	fprintf (stdout, "%s\n", VERSION);
260
+	return EXIT_SUCCESS;
261
+    }
262
+  }
263
+  if (pid_file) {
264
+    pf = fopen (pid_file, "w");
265
+    if (pf == NULL) {
266
+      fprintf (stderr, "%s: Cannot write PID: %s\n\n", self, pid_file);
267
+      return EXIT_FAILURE;
268
+    }
269
+  }
270
+  if (domain == NULL) {
271
+    fprintf (stderr, "%s: You must set a home domain (-d)\n", self);
272
+    show_help();
273
+    return EXIT_FAILURE;
274
+  }
275
+  if (secret_file != NULL) {
276
+    size_t len;
277
+    FILE *fp = fopen(secret_file, "rb");
278
+    if (fp == NULL) {
279
+      fprintf (stderr, "%s: Cannot open file with secret: %s\n", self, secret_file);
280
+      return EXIT_FAILURE;
281
+    }
282
+    len = fread(secret, 1, sizeof(secret) - 1, fp);
283
+    if (len == 0 || len > sizeof(secret) - 1) {
284
+      fprintf (stderr, "%s: Cannot read secret from file: %s\n", self, secret_file);
285
+      return EXIT_FAILURE;
286
+    }
287
+    secret[len] = 0;
288
+    fclose (fp);
289
+  } else {
290
+    fprintf (stderr, "%s: You must set a secret (-s)\n", self);
291
+    show_help();
292
+    return EXIT_FAILURE;
293
+  }
294
+  if (forward_service != NULL) {
295
+    forward_sock = bind_service(forward_service, family);
296
+    free (forward_service);
297
+  } else {
298
+    forward_sock = bind_service("10001", family);
299
+  }
300
+  if (forward_sock < 0) return EXIT_FAILURE;
301
+  if (reverse_service != NULL) {
302
+    reverse_sock = bind_service(reverse_service, family);
303
+    free (reverse_service);
304
+  } else {
305
+    reverse_sock = bind_service("10002", family);
306
+  }
307
+  if (reverse_sock < 0) return EXIT_FAILURE;
308
+  if (user) {
309
+    struct passwd *pwd;
310
+    errno = 0;
311
+    pwd = getpwnam(user);
312
+    if (pwd == NULL) {
313
+      if (errno != 0)
314
+        fprintf (stderr, "%s: Failed to lookup user: %s\n", self, strerror(errno));
315
+      else
316
+        fprintf (stderr, "%s: No such user: %s\n", self, user);
317
+      return EXIT_FAILURE;
318
+    }
319
+    if (setuid(pwd->pw_uid) < 0) {
320
+      fprintf (stderr, "%s: Failed to switch user id: %s\n", self, strerror(errno));
321
+      return EXIT_FAILURE;
322
+    }
323
+  }
324
+  if (daemonize) {
325
+    close(0); close(1); close(2);
326
+    if (fork() != 0) return EXIT_SUCCESS;
327
+    setsid();
328
+    if (fork() != 0) return EXIT_SUCCESS;
329
+  }
330
+  if (pf) {
331
+    fprintf (pf, "%d", (int)getpid());
332
+    fclose (pf);
333
+  }
334
+
335
+  srs = srs_new();
336
+  srs_add_secret (srs, secret);
337
+  srs_set_separator (srs, '+');
338
+
339
+  fds[0].fd = forward_sock;
340
+  fds[0].events = POLLIN;
341
+  fds[1].fd = reverse_sock;
342
+  fds[1].events = POLLIN;
343
+
344
+  while(TRUE) {
345
+    int i, conn;
346
+    FILE *fp;
347
+    char linebuf[1024], *line;
348
+    char keybuf[1024], *key;
349
+
350
+    if (poll(fds, 2, 1000) < 0) {
351
+      if (!daemonize) fprintf (stderr, "%s: Poll failure: %s\n", self, strerror(errno));
352
+      return EXIT_FAILURE;
353
+    }
354
+    for (i = 0; i < 2; ++i) {
355
+      if (fds[i].revents) {
356
+        conn = accept(fds[i].fd, NULL, NULL);
357
+        if (conn < 0) continue;
358
+        if (fork() == 0) {
359
+          fp = fdopen(conn, "r+");
360
+          if (fp == NULL) exit(EXIT_FAILURE);
361
+          fds[2].fd = conn;
362
+          fds[2].events = POLLIN;
363
+          if (poll(&fds[2], 1, timeout * 1000) <= 0) return EXIT_FAILURE;
364
+          line = fgets(linebuf, sizeof(linebuf), fp);
365
+          while (line) {
366
+            char* token;
367
+            token = strtok(line, " \r\n");
368
+            if (token == NULL || strcmp(token, "get") != 0) {
369
+              fprintf (fp, "500 Invalid request\n");
370
+              return EXIT_FAILURE;
371
+            }
372
+            token = strtok(NULL, "\r\n");
373
+            if (!token) {
374
+              fprintf (fp, "500 Invalid request\n");
375
+              return EXIT_FAILURE;
376
+            }
377
+            key = url_decode(keybuf, sizeof(keybuf), token);
378
+            if (!key) break;
379
+            handler[i](srs, fp, key, domain);
380
+            if (poll(&fds[2], 1, timeout * 1000) <= 0) break;
381
+            line = fgets(linebuf, sizeof(linebuf), fp);
382
+          }
383
+          fclose (fp);
384
+          return EXIT_SUCCESS;
385
+        }
386
+        close (conn);
387
+      }
388
+    }
389
+    waitpid(-1, NULL, WNOHANG);
390
+  }
391
+  return EXIT_SUCCESS;
392
+}

+ 15
- 0
postsrsd.default View File

@@ -0,0 +1,15 @@
1
+# Default settings for postsrsd
2
+
3
+# Local domain name. Addresses are rewritten to originate from this domain
4
+#SRS_DOMAIN=example.com
5
+
6
+# The secret key to sign the addresses is stored in this file
7
+#SRS_SECRET=/etc/postsrsd.secret
8
+
9
+# These ports are used to bind the TCP list for postfix
10
+#SRS_FORWARD_PORT=10001
11
+#SRS_REVERSE_PORT=10002
12
+
13
+# Drop root privileges and run as this user after initialization.
14
+RUN_AS=nobody
15
+

+ 85
- 0
postsrsd.init.in View File

@@ -0,0 +1,85 @@
1
+#! /bin/sh
2
+#
3
+# @PROJECT_NAME@
4
+#               start/stop the @PROJECT_NAME@ daemon for Postfix
5
+#
6
+### BEGIN INIT INFO
7
+# Provides:          @PROJECT_NAME@
8
+# Required-Start:    $syslog, $local_fs
9
+# Required-Stop:     $syslog, $local_fs
10
+# Default-Start:     2 3 4 5
11
+# Default-Stop:      0 1 6
12
+# Short-Description: Start/stop the postsrs daemon
13
+### END INIT INFO
14
+
15
+set -e
16
+
17
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
18
+DAEMON=@CMAKE_INSTALL_PREFIX@/sbin/@PROJECT_NAME@
19
+NAME=@PROJECT_NAME@
20
+DESC="Postfix Sender Rewriting Scheme daemon"
21
+
22
+PIDFILE=/var/run/$NAME.pid
23
+SCRIPTNAME=/etc/init.d/$NAME
24
+
25
+# Gracefully exit if the package has been removed.
26
+test -x $DAEMON || exit 0
27
+
28
+. /lib/lsb/init-functions
29
+
30
+# Default configuration
31
+SRS_DOMAIN=`[ ! -r /etc/mailname ] || cat /etc/mailname | cut -d. -f2-`
32
+SRS_FORWARD_PORT=10001
33
+SRS_REVERSE_PORT=10002
34
+SRS_SECRET=/etc/@PROJECT_NAME@.secret
35
+RUN_AS=nobody
36
+
37
+# Read config file if it is present.
38
+if [ -r /etc/default/$NAME ]
39
+then
40
+    . /etc/default/$NAME
41
+fi
42
+
43
+POSTSRS_OPTS="-4 -f$SRS_FORWARD_PORT -r$SRS_REVERSE_PORT -d$SRS_DOMAIN -s$SRS_SECRET -u$RUN_AS -p$PIDFILE -D"
44
+
45
+test -r "$SRS_SECRET" || exit 0
46
+
47
+ret=0
48
+case "$1" in
49
+  start)
50
+	log_daemon_msg "Starting $DESC" "$NAME"
51
+	if start-stop-daemon --start --oknodo --quiet \
52
+		--pidfile $PIDFILE \
53
+		--name $NAME \
54
+		--startas $DAEMON -- $POSTSRS_OPTS
55
+	then
56
+	    log_end_msg 0
57
+	else
58
+	    ret=$?
59
+	    log_end_msg 1
60
+	fi
61
+	;;
62
+  stop)
63
+	log_daemon_msg "Stopping $DESC" "$NAME"
64
+	if start-stop-daemon --stop --oknodo --quiet \
65
+		--pidfile $PIDFILE --name $NAME
66
+	then
67
+	    log_end_msg 0
68
+	else
69
+	    ret=$?
70
+	    log_end_msg 1
71
+	fi
72
+        rm -f $PIDFILE
73
+	;;
74
+  reload|force-reload|restart)
75
+	$0 stop
76
+	$0 start
77
+	ret=$?
78
+	;;
79
+  *)
80
+	echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
81
+	exit 1
82
+	;;
83
+esac
84
+
85
+exit $ret

+ 386
- 0
sha1.c View File

@@ -0,0 +1,386 @@
1
+/* This file is copied from the libsrs2 sources */
2
+/* Modified by Timo Röhling <timo.roehling@gmx.de> */
3
+
4
+/* NIST Secure Hash Algorithm */
5
+/* Borrowed from SHA1.xs by Gisle Ass */
6
+/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */
7
+/* from Peter C. Gutmann's implementation as found in */
8
+/* Applied Cryptography by Bruce Schneier */
9
+/* Further modifications to include the "UNRAVEL" stuff, below */
10
+/* HMAC functions by Shevek <srs@anarres.org> for inclusion in
11
+ * libsrs2, under GPL-2 or BSD license. Combine this lot in any way
12
+ * you think will stand up in court. I hope my intent is clear. */
13
+
14
+/* This code is in the public domain */
15
+
16
+/* Useful defines & typedefs */
17
+
18
+#include <stdarg.h>
19
+#include <time.h>       /* time */
20
+#include <sys/types.h>  /* tyepdefs */
21
+#include <sys/time.h>   /* timeval / timezone struct */
22
+#include <string.h>		/* memcpy, strcpy, memset */
23
+
24
+#include "srs2.h"
25
+
26
+#ifdef SIZEOF_UNSIGNED_LONG
27
+#if SIZEOF_UNSIGNED_LONG < 4
28
+#error "SHA1 requires an unsigned long of at least 32 bits"
29
+#endif
30
+#endif
31
+
32
+#ifdef WORDS_BIGENDIAN
33
+#define BYTEORDER 0x4321
34
+#else
35
+#define BYTEORDER 0x1234
36
+#endif
37
+
38
+
39
+/* UNRAVEL should be fastest & biggest */
40
+/* UNROLL_LOOPS should be just as big, but slightly slower */
41
+/* both undefined should be smallest and slowest */
42
+
43
+#define SHA_VERSION 1
44
+#define UNRAVEL
45
+/* #define UNROLL_LOOPS */
46
+
47
+/* SHA f()-functions */
48
+#define f1(x,y,z)		((x & y) | (~x & z))
49
+#define f2(x,y,z)		(x ^ y ^ z)
50
+#define f3(x,y,z)		((x & y) | (x & z) | (y & z))
51
+#define f4(x,y,z)		(x ^ y ^ z)
52
+
53
+/* SHA constants */
54
+#define CONST1				0x5a827999L
55
+#define CONST2				0x6ed9eba1L
56
+#define CONST3				0x8f1bbcdcL
57
+#define CONST4				0xca62c1d6L
58
+
59
+/* truncate to 32 bits -- should be a null op on 32-bit machines */
60
+#define T32(x)		((x) & 0xffffffffL)
61
+
62
+/* 32-bit rotate */
63
+#define R32(x,n)		T32(((x << n) | (x >> (32 - n))))
64
+
65
+/* the generic case, for when the overall rotation is not unraveled */
66
+#define FG(n)		\
67
+	T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n);		\
68
+	E = D; D = C; C = R32(B,30); B = A; A = T
69
+
70
+/* specific cases, for when the overall rotation is unraveled */
71
+#define FA(n)		\
72
+	T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30)
73
+
74
+#define FB(n)		\
75
+	E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30)
76
+
77
+#define FC(n)		\
78
+	D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30)
79
+
80
+#define FD(n)		\
81
+	C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30)
82
+
83
+#define FE(n)		\
84
+	B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30)
85
+
86
+#define FT(n)		\
87
+	A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30)
88
+
89
+
90
+static void sha_transform(SHA_INFO *sha_info)
91
+{
92
+	int i;
93
+	sha_byte *dp;
94
+	ULONG T, A, B, C, D, E, W[80], *WP;
95
+
96
+	dp = sha_info->data;
97
+
98
+/*
99
+the following makes sure that at least one code block below is
100
+traversed or an error is reported, without the necessity for nested
101
+preprocessor if/else/endif blocks, which are a great pain in the
102
+nether regions of the anatomy...
103
+*/
104
+#undef SWAP_DONE
105
+
106
+#if BYTEORDER == 0x1234
107
+#define SWAP_DONE
108
+	/* assert(sizeof(ULONG) == 4); */
109
+	for (i = 0; i < 16; ++i) {
110
+		T = *((ULONG *) dp);
111
+		dp += 4;
112
+		W[i] =  ((T << 24) & 0xff000000) | ((T <<  8) & 0x00ff0000) |
113
+				((T >>  8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
114
+	}
115
+#endif
116
+
117
+#if BYTEORDER == 0x4321
118
+#define SWAP_DONE
119
+	/* assert(sizeof(ULONG) == 4); */
120
+	for (i = 0; i < 16; ++i) {
121
+		T = *((ULONG *) dp);
122
+		dp += 4;
123
+		W[i] = T32(T);
124
+	}
125
+#endif
126
+
127
+#if BYTEORDER == 0x12345678
128
+#define SWAP_DONE
129
+	/* assert(sizeof(ULONG) == 8); */
130
+	for (i = 0; i < 16; i += 2) {
131
+		T = *((ULONG *) dp);
132
+		dp += 8;
133
+		W[i] =  ((T << 24) & 0xff000000) | ((T <<  8) & 0x00ff0000) |
134
+				((T >>  8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
135
+		T >>= 32;
136
+		W[i+1] = ((T << 24) & 0xff000000) | ((T <<  8) & 0x00ff0000) |
137
+				 ((T >>  8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
138
+	}
139
+#endif
140
+
141
+#if BYTEORDER == 0x87654321
142
+#define SWAP_DONE
143
+	/* assert(sizeof(ULONG) == 8); */
144
+	for (i = 0; i < 16; i += 2) {
145
+		T = *((ULONG *) dp);
146
+		dp += 8;
147
+		W[i] = T32(T >> 32);
148
+		W[i+1] = T32(T);
149
+	}
150
+#endif
151
+
152
+#ifndef SWAP_DONE
153
+#error Unknown byte order -- you need to add code here
154
+#endif /* SWAP_DONE */
155
+
156
+	for (i = 16; i < 80; ++i) {
157
+		W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16];
158
+#if (SHA_VERSION == 1)
159
+		W[i] = R32(W[i], 1);
160
+#endif /* SHA_VERSION */
161
+	}
162
+	A = sha_info->digest[0];
163
+	B = sha_info->digest[1];
164
+	C = sha_info->digest[2];
165
+	D = sha_info->digest[3];
166
+	E = sha_info->digest[4];
167
+	WP = W;
168
+#ifdef UNRAVEL
169
+	FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1);
170
+	FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1);
171
+	FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2);
172
+	FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2);
173
+	FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3);
174
+	FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3);
175
+	FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4);
176
+	FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4);
177
+	sha_info->digest[0] = T32(sha_info->digest[0] + E);
178
+	sha_info->digest[1] = T32(sha_info->digest[1] + T);
179
+	sha_info->digest[2] = T32(sha_info->digest[2] + A);
180
+	sha_info->digest[3] = T32(sha_info->digest[3] + B);
181
+	sha_info->digest[4] = T32(sha_info->digest[4] + C);
182
+#else /* !UNRAVEL */
183
+#ifdef UNROLL_LOOPS
184
+	FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
185
+	FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1);
186
+	FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
187
+	FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2);
188
+	FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
189
+	FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3);
190
+	FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
191
+	FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4);
192
+#else /* !UNROLL_LOOPS */
193
+	for (i =  0; i < 20; ++i) { FG(1); }
194
+	for (i = 20; i < 40; ++i) { FG(2); }
195
+	for (i = 40; i < 60; ++i) { FG(3); }
196
+	for (i = 60; i < 80; ++i) { FG(4); }
197
+#endif /* !UNROLL_LOOPS */
198
+	sha_info->digest[0] = T32(sha_info->digest[0] + A);
199
+	sha_info->digest[1] = T32(sha_info->digest[1] + B);
200
+	sha_info->digest[2] = T32(sha_info->digest[2] + C);
201
+	sha_info->digest[3] = T32(sha_info->digest[3] + D);
202
+	sha_info->digest[4] = T32(sha_info->digest[4] + E);
203
+#endif /* !UNRAVEL */
204
+}
205
+
206
+/* initialize the SHA digest */
207
+
208
+static void
209
+sha_init(SHA_INFO *sha_info)
210
+{
211
+	sha_info->digest[0] = 0x67452301L;
212
+	sha_info->digest[1] = 0xefcdab89L;
213
+	sha_info->digest[2] = 0x98badcfeL;
214
+	sha_info->digest[3] = 0x10325476L;
215
+	sha_info->digest[4] = 0xc3d2e1f0L;
216
+	sha_info->count_lo = 0L;
217
+	sha_info->count_hi = 0L;
218
+	sha_info->local = 0;
219
+}
220
+
221
+/* update the SHA digest */
222
+
223
+static void
224
+sha_update(SHA_INFO *sha_info, sha_byte *buffer, int count)
225
+{
226
+	int i;
227
+	ULONG clo;
228
+
229
+	clo = T32(sha_info->count_lo + ((ULONG) count << 3));
230
+	if (clo < sha_info->count_lo) {
231
+		++sha_info->count_hi;
232
+	}
233
+	sha_info->count_lo = clo;
234
+	sha_info->count_hi += (ULONG) count >> 29;
235
+	if (sha_info->local) {
236
+		i = SHA_BLOCKSIZE - sha_info->local;
237
+		if (i > count) {
238
+			i = count;
239
+		}
240
+		memcpy(((sha_byte *) sha_info->data) + sha_info->local, buffer, i);
241
+		count -= i;
242
+		buffer += i;
243
+		sha_info->local += i;
244
+		if (sha_info->local == SHA_BLOCKSIZE) {
245
+			sha_transform(sha_info);
246
+		} else {
247
+			return;
248
+		}
249
+	}
250
+	while (count >= SHA_BLOCKSIZE) {
251
+		memcpy(sha_info->data, buffer, SHA_BLOCKSIZE);
252
+		buffer += SHA_BLOCKSIZE;
253
+		count -= SHA_BLOCKSIZE;
254
+		sha_transform(sha_info);
255
+	}
256
+	memcpy(sha_info->data, buffer, count);
257
+	sha_info->local = count;
258
+}
259
+
260
+
261
+static void
262
+sha_transform_and_copy(unsigned char digest[20], SHA_INFO *sha_info)
263
+{
264
+	sha_transform(sha_info);
265
+	digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff);
266
+	digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff);
267
+	digest[ 2] = (unsigned char) ((sha_info->digest[0] >>  8) & 0xff);
268
+	digest[ 3] = (unsigned char) ((sha_info->digest[0]      ) & 0xff);
269
+	digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff);
270
+	digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff);
271
+	digest[ 6] = (unsigned char) ((sha_info->digest[1] >>  8) & 0xff);
272
+	digest[ 7] = (unsigned char) ((sha_info->digest[1]      ) & 0xff);
273
+	digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff);
274
+	digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff);
275
+	digest[10] = (unsigned char) ((sha_info->digest[2] >>  8) & 0xff);
276
+	digest[11] = (unsigned char) ((sha_info->digest[2]      ) & 0xff);
277
+	digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff);
278
+	digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff);
279
+	digest[14] = (unsigned char) ((sha_info->digest[3] >>  8) & 0xff);
280
+	digest[15] = (unsigned char) ((sha_info->digest[3]      ) & 0xff);
281
+	digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff);
282
+	digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff);
283
+	digest[18] = (unsigned char) ((sha_info->digest[4] >>  8) & 0xff);
284
+	digest[19] = (unsigned char) ((sha_info->digest[4]      ) & 0xff);
285
+}
286
+
287
+/* finish computing the SHA digest */
288
+static void
289
+sha_final(unsigned char digest[20], SHA_INFO *sha_info)
290
+{
291
+	int count;
292
+	ULONG lo_bit_count, hi_bit_count;
293
+
294
+	lo_bit_count = sha_info->count_lo;
295
+	hi_bit_count = sha_info->count_hi;
296
+	count = (int) ((lo_bit_count >> 3) & 0x3f);
297
+	((sha_byte *) sha_info->data)[count++] = 0x80;
298
+	if (count > SHA_BLOCKSIZE - 8) {
299
+		memset(((sha_byte *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count);
300
+		sha_transform(sha_info);
301
+		memset((sha_byte *) sha_info->data, 0, SHA_BLOCKSIZE - 8);
302
+	} else {
303
+		memset(((sha_byte *) sha_info->data) + count, 0,
304
+			SHA_BLOCKSIZE - 8 - count);
305
+	}
306
+	sha_info->data[56] = (hi_bit_count >> 24) & 0xff;
307
+	sha_info->data[57] = (hi_bit_count >> 16) & 0xff;
308
+	sha_info->data[58] = (hi_bit_count >>  8) & 0xff;
309
+	sha_info->data[59] = (hi_bit_count >>  0) & 0xff;
310
+	sha_info->data[60] = (lo_bit_count >> 24) & 0xff;
311
+	sha_info->data[61] = (lo_bit_count >> 16) & 0xff;
312
+	sha_info->data[62] = (lo_bit_count >>  8) & 0xff;
313
+	sha_info->data[63] = (lo_bit_count >>  0) & 0xff;
314
+	sha_transform_and_copy(digest, sha_info);
315
+}
316
+
317
+
318
+
319
+/********************************************************************/
320
+
321
+/*
322
+		SHA_INFO ctx;
323
+		unsigned char *data;
324
+	STRLEN len;
325
+		unsigned char digeststr[20];
326
+
327
+		sha_init(&ctx);
328
+
329
+		for (i = 0; i < items; i++) {
330
+			data = (unsigned char *)(SvPVbyte(ST(i), len));
331
+			sha_update(&ctx, data, len);
332
+		}
333
+		sha_final(digeststr, &ctx);
334
+*/
335
+
336
+static void
337
+sha_digest(char *out, char *data, int len)
338
+{
339
+	SHA_INFO ctx;
340
+	sha_init(&ctx);
341
+	sha_update(&ctx, data, len);
342
+	sha_final(out, &ctx);
343
+}
344
+
345
+void
346
+srs_hmac_init(srs_hmac_ctx_t *ctx, char *secret, int len)
347
+{
348
+	char	 sbuf[SHA_BLOCKSIZE];
349
+	int		 i;
350
+
351
+	if (len > SHA_BLOCKSIZE) {
352
+		sha_digest(sbuf, secret, len);
353
+		secret = sbuf;
354
+		len = strlen(sbuf);	/* SHA_BLOCKSIZE? */
355
+	}
356
+
357
+	memset(ctx->ipad, 0x36, SHA_BLOCKSIZE);
358
+	memset(ctx->opad, 0x5c, SHA_BLOCKSIZE);
359
+	for (i = 0; i < len; i++) {
360
+		ctx->ipad[i] ^= secret[i];
361
+		ctx->opad[i] ^= secret[i];
362
+	}
363
+
364
+	memset(sbuf, 0, SHA_BLOCKSIZE);
365
+
366
+	sha_init(&ctx->sctx);
367
+	sha_update(&ctx->sctx, ctx->ipad, SHA_BLOCKSIZE);
368
+}
369
+
370
+void
371
+srs_hmac_update(srs_hmac_ctx_t *ctx, char *data, int len)
372
+{
373
+	sha_update(&ctx->sctx, data, len);
374
+}
375
+
376
+void
377
+srs_hmac_fini(srs_hmac_ctx_t *ctx, char *out)
378
+{
379
+	char	 buf[SHA_DIGESTSIZE + 1];
380
+
381
+	sha_final(buf, &ctx->sctx);
382
+	sha_init(&ctx->sctx);
383
+	sha_update(&ctx->sctx, ctx->opad, SHA_BLOCKSIZE);
384
+	sha_update(&ctx->sctx, buf, SHA_DIGESTSIZE);
385
+	sha_final(out, &ctx->sctx);
386
+}

+ 704
- 0
srs2.c View File

@@ -0,0 +1,704 @@
1
+/* This file is copied from the libsrs2 sources */
2
+/* Modified by Timo Röhling <timo.roehling@gmx.de> */
3
+
4
+/* Copyright (c) 2004 Shevek (srs@anarres.org)
5
+ * All rights reserved.
6
+ *
7
+ * This file is a part of libsrs2 from http://www.libsrs2.org/
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, under the terms of either the GNU General Public
11
+ * License version 2 or the BSD license, at the discretion of the
12
+ * user. Copies of these licenses have been included in the libsrs2
13
+ * distribution. See the the file called LICENSE for more
14
+ * information.
15
+ */
16
+
17
+#undef USE_OPENSSL
18
+
19
+#include <stdarg.h>
20
+#include <time.h>       /* time */
21
+#include <sys/types.h>  /* tyepdefs */
22
+#include <sys/time.h>   /* timeval / timezone struct */
23
+#include <string.h>		/* memcpy, strcpy, memset */
24
+#include <alloca.h>
25
+
26
+#ifdef USE_OPENSSL
27
+#include <openssl/hmac.h>
28
+#endif
29
+
30
+#include "srs2.h"
31
+
32
+
33
+#ifndef EVP_MAX_MD_SIZE
34
+#define EVP_MAX_MD_SIZE (16+20) /* The SSLv3 md5+sha1 type */
35
+#endif
36
+
37
+#ifndef HAVE_STRCASECMP
38
+# ifdef HAVE__STRICMP
39
+#  define strcasecmp _stricmp
40
+# endif
41
+#endif
42
+
43
+#ifndef HAVE_STRNCASECMP
44
+# ifdef HAVE__STRNICMP
45
+#  define strncasecmp _strnicmp
46
+# endif
47
+#endif
48
+
49
+	/* Use this */
50
+#define STRINGP(s) ((s != NULL) && (*(s) != '\0'))
51
+
52
+static const char *srs_separators = "=-+";
53
+
54
+static srs_malloc_t		srs_f_malloc	= malloc;
55
+static srs_realloc_t	srs_f_realloc	= realloc;
56
+static srs_free_t		srs_f_free		= free;
57
+
58
+int		
59
+srs_set_malloc(srs_malloc_t m, srs_realloc_t r, srs_free_t f)
60
+{
61
+	srs_f_malloc = m;
62
+	srs_f_realloc = r;
63
+	srs_f_free = f;
64
+	return SRS_SUCCESS;
65
+}
66
+
67
+const char *
68
+srs_strerror(int code)
69
+{
70
+	switch (code) {
71
+		/* Simple errors */
72
+		case SRS_SUCCESS:
73
+			return "Success";
74
+		case SRS_ENOTSRSADDRESS:
75
+			return "Not an SRS address.";
76
+
77
+		/* Config errors */
78
+		case SRS_ENOSECRETS:
79
+			return "No secrets in SRS configuration.";
80
+		case SRS_ESEPARATORINVALID:
81
+			return "Invalid separator suggested.";
82
+
83
+		/* Input errors */
84
+		case SRS_ENOSENDERATSIGN:
85
+			return "No at sign in sender address";
86
+		case SRS_EBUFTOOSMALL:
87
+			return "Buffer too small.";
88
+
89
+		/* Syntax errors */
90
+		case SRS_ENOSRS0HOST:
91
+			return "No host in SRS0 address.";
92
+		case SRS_ENOSRS0USER:
93
+			return "No user in SRS0 address.";
94
+		case SRS_ENOSRS0HASH:
95
+			return "No hash in SRS0 address.";
96
+		case SRS_ENOSRS0STAMP:
97
+			return "No timestamp in SRS0 address.";
98
+		case SRS_ENOSRS1HOST:
99
+			return "No host in SRS1 address.";
100
+		case SRS_ENOSRS1USER:
101
+			return "No user in SRS1 address.";
102
+		case SRS_ENOSRS1HASH:
103
+			return "No hash in SRS1 address.";
104
+		case SRS_EBADTIMESTAMPCHAR:
105
+			return "Bad base32 character in timestamp.";
106
+		case SRS_EHASHTOOSHORT:
107
+			return "Hash too short in SRS address.";
108
+
109
+		/* SRS errors */
110
+		case SRS_ETIMESTAMPOUTOFDATE:
111
+			return "Time stamp out of date.";
112
+		case SRS_EHASHINVALID:
113
+			return "Hash invalid in SRS address.";
114
+
115
+		default:
116
+			return "Unknown error in SRS library.";
117
+	}
118
+}
119
+
120
+srs_t *
121
+srs_new()
122
+{
123
+	srs_t	*srs = (srs_t *)srs_f_malloc(sizeof(srs_t));
124
+	srs_init(srs);
125
+	return srs;
126
+}
127
+
128
+void
129
+srs_init(srs_t *srs)
130
+{
131
+	memset(srs, 0, sizeof(srs_t));
132
+	srs->secrets = NULL;
133
+	srs->numsecrets = 0;
134
+	srs->separator = '=';
135
+	srs->maxage = 21;
136
+	srs->hashlength = 4;
137
+	srs->hashmin = srs->hashlength;
138
+	srs->alwaysrewrite = FALSE;
139
+}
140
+
141
+void
142
+srs_free(srs_t *srs)
143
+{
144
+	int	 i;
145
+	for (i = 0; i < srs->numsecrets; i++) {
146
+		memset(srs->secrets[i], 0, strlen(srs->secrets[i]));
147
+		srs_f_free(srs->secrets[i]);
148
+		srs->secrets[i] = '\0';
149
+	}
150
+	srs_f_free(srs);
151
+}
152
+
153
+int
154
+srs_add_secret(srs_t *srs, const char *secret)
155
+{
156
+	int		newlen = (srs->numsecrets + 1) * sizeof(char *);
157
+	srs->secrets = (char **)srs_f_realloc(srs->secrets, newlen);
158
+	srs->secrets[srs->numsecrets++] = strdup(secret);
159
+	return SRS_SUCCESS;
160
+}
161
+
162
+const char *
163
+srs_get_secret(srs_t *srs, int idx)
164
+{
165
+	if (idx < srs->numsecrets)
166
+		return srs->secrets[idx];
167
+	return NULL;
168
+}
169
+
170
+#define SRS_PARAM_DEFINE(n, t) \
171
+	int srs_set_ ## n (srs_t *srs, t value) { \
172
+		srs->n = value; \
173
+		return SRS_SUCCESS; \
174
+	} \
175
+	t srs_get_ ## n (srs_t *srs) { \
176
+		return srs->n; \
177
+	}
178
+
179
+int
180
+srs_set_separator(srs_t *srs, char value)
181
+{
182
+	if (strchr(srs_separators, value) == NULL)
183
+		return SRS_ESEPARATORINVALID;
184
+	srs->separator = value;
185
+	return SRS_SUCCESS;
186
+}
187
+
188
+char
189
+srs_get_separator(srs_t *srs)
190
+{
191
+	return srs->separator;
192
+}
193
+
194
+SRS_PARAM_DEFINE(maxage, int)
195
+	/* XXX Check hashlength >= hashmin */
196
+SRS_PARAM_DEFINE(hashlength, int)
197
+SRS_PARAM_DEFINE(hashmin, int)
198
+SRS_PARAM_DEFINE(alwaysrewrite, srs_bool)
199
+SRS_PARAM_DEFINE(noforward, srs_bool)
200
+SRS_PARAM_DEFINE(noreverse, srs_bool)
201
+
202
+/* Don't mess with these unless you know what you're doing well
203
+ * enough to rewrite the timestamp functions. These are based on
204
+ * a 2 character timestamp. Changing these in the wild is probably
205
+ * a bad idea. */
206
+#define SRS_TIME_PRECISION	(60 * 60 * 24)	/* One day */
207
+#define SRS_TIME_BASEBITS	5		/* 2^5 = 32 = strlen(CHARS) */
208
+/* This had better be a real variable since we do arithmethic
209
+ * with it. */
210
+const char *SRS_TIME_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
211
+#define SRS_TIME_SIZE		2
212
+#define SRS_TIME_SLOTS		(1<<(SRS_TIME_BASEBITS<<(SRS_TIME_SIZE-1)))
213
+
214
+int
215
+srs_timestamp_create(srs_t *srs, char *buf, time_t now)
216
+{
217
+	now = now / SRS_TIME_PRECISION;
218
+	buf[1] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
219
+	now = now >> SRS_TIME_BASEBITS;
220
+	buf[0] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
221
+	buf[2] = '\0';
222
+	return SRS_SUCCESS;
223
+}
224
+
225
+int
226
+srs_timestamp_check(srs_t *srs, const char *stamp)
227
+{
228
+	const char	*sp;
229
+	char		*bp;
230
+	int			 off;
231
+	time_t		 now;
232
+	time_t		 then;
233
+
234
+	/* We had better go around this loop exactly twice! */
235
+	then = 0;
236
+	for (sp = stamp; *sp; sp++) {
237
+		bp = strchr(SRS_TIME_BASECHARS, toupper(*sp));
238
+		if (bp == NULL)
239
+			return SRS_EBADTIMESTAMPCHAR;
240
+		off = bp - SRS_TIME_BASECHARS;
241
+		then = (then << SRS_TIME_BASEBITS) | off;
242
+	}
243
+
244
+	time(&now);
245
+	now = (now / SRS_TIME_PRECISION) % SRS_TIME_SLOTS;
246
+	while (now < then)
247
+		now = now + SRS_TIME_SLOTS;
248
+
249
+	if (now <= then + srs->maxage)
250
+		return SRS_SUCCESS;
251
+	return SRS_ETIMESTAMPOUTOFDATE;
252
+}
253
+
254
+const char *SRS_HASH_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
255
+								 "abcdefghijklmnopqrstuvwxyz"
256
+								 "0123456789+/";
257
+
258
+static void
259
+srs_hash_create_v(srs_t *srs, int idx, char *buf, int nargs, va_list ap)
260
+{
261
+#ifdef USE_OPENSSL
262
+	HMAC_CTX		 ctx;
263
+	int				 srshashlen;
264
+	char			 srshash[EVP_MAX_MD_SIZE + 1];
265
+#else
266
+	srs_hmac_ctx_t	 ctx;
267
+	char			 srshash[SHA_DIGESTSIZE + 1];
268
+#endif
269
+	char			*secret;
270
+	char			*data;
271
+	int				 len;
272
+	char			*lcdata;
273
+	unsigned char	*hp;
274
+	char			*bp;
275
+	int				 i;
276
+	int				 j;
277
+
278
+	secret = srs->secrets[idx];
279
+
280
+#ifdef USE_OPENSSL
281
+	HMAC_CTX_init(&ctx);
282
+	HMAC_Init(&ctx, secret, strlen(secret), EVP_sha1());
283
+#else
284
+	srs_hmac_init(&ctx, secret, strlen(secret));
285
+#endif
286
+
287
+	for (i = 0; i < nargs; i++) {
288
+		data = va_arg(ap, char *);
289
+		len = strlen(data);
290
+		lcdata = alloca(len + 1);
291
+		for (j = 0; j < len; j++) {
292
+			if (isupper(data[j]))
293
+				lcdata[j] = tolower(data[j]);
294
+			else
295
+				lcdata[j] = data[j];
296
+		}
297
+#ifdef USE_OPENSSL
298
+		HMAC_Update(&ctx, lcdata, len);
299
+#else
300
+		srs_hmac_update(&ctx, lcdata, len);
301
+#endif
302
+	}
303
+
304
+#ifdef USE_OPENSSL
305
+	HMAC_Final(&ctx, srshash, &srshashlen);
306
+	HMAC_CTX_cleanup(&ctx);
307
+	srshash[EVP_MAX_MD_SIZE] = '\0';
308
+#else
309
+	srs_hmac_fini(&ctx, srshash);
310
+	srshash[SHA_DIGESTSIZE] = '\0';
311
+#endif
312
+
313
+
314
+	/* A little base64 encoding. Just a little. */
315
+	hp = (unsigned char *)srshash;
316
+	bp = buf;
317
+	for (i = 0; i < srs->hashlength; i++) {
318
+		switch (i & 0x03) {
319
+			default:	/* NOTREACHED */
320
+			case 0:
321
+				j = (*hp >> 2);
322
+				break;
323
+			case 1:
324
+				j = ((*hp & 0x03) << 4) |
325
+						((*(hp + 1) & 0xF0) >> 4);
326
+				hp++;
327
+				break;
328
+			case 2:
329
+				j = ((*hp & 0x0F) << 2) |
330
+						((*(hp + 1) & 0xC0) >> 6);
331
+				hp++;
332
+				break;
333
+			case 3:
334
+				j = (*hp++ & 0x3F);
335
+				break;
336
+		}
337
+		*bp++ = SRS_HASH_BASECHARS[j];
338
+	}
339
+
340
+	*bp = '\0';
341
+	buf[srs->hashlength] = '\0';
342
+}
343
+
344
+int
345
+srs_hash_create(srs_t *srs, char *buf, int nargs, ...)
346
+{
347
+	va_list	 ap;
348
+
349
+	if (srs->numsecrets == 0)
350
+		return SRS_ENOSECRETS;
351
+	if (srs->secrets == NULL)
352
+		return SRS_ENOSECRETS;
353
+	if (srs->secrets[0] == NULL)
354
+		return SRS_ENOSECRETS;
355
+
356
+	va_start(ap, nargs);
357
+	srs_hash_create_v(srs, 0, buf, nargs, ap);
358
+	va_end(ap);
359
+
360
+	return SRS_SUCCESS;
361
+}
362
+
363
+int
364
+srs_hash_check(srs_t *srs, char *hash, int nargs, ...)
365
+{
366
+	va_list	ap;
367
+	char	*srshash;
368
+	char	*tmp;
369
+	int		 len;
370
+	int		 i;
371
+
372
+	len = strlen(hash);
373
+	if (len < srs->hashmin)
374
+		return SRS_EHASHTOOSHORT;
375
+	if (len < srs->hashlength) {
376
+		tmp = alloca(srs->hashlength + 1);
377
+		strncpy(tmp, hash, srs->hashlength);
378
+		tmp[srs->hashlength] = '\0';
379
+		hash = tmp;
380
+		len = srs->hashlength;
381
+	}
382
+
383
+	for (i = 0; i < srs->numsecrets; i++) {
384
+		va_start(ap, nargs);
385
+		srshash = alloca(srs->hashlength + 1);
386
+		srs_hash_create_v(srs, i, srshash, nargs, ap);
387
+		va_end(ap);
388
+		if (strncasecmp(hash, srshash, len) == 0)
389
+			return SRS_SUCCESS;
390
+	}
391
+
392
+	return SRS_EHASHINVALID;
393
+}
394
+
395
+int
396
+srs_compile_shortcut(srs_t *srs,
397
+				char *buf, int buflen,
398
+				char *sendhost, char *senduser,
399
+				const char *aliashost) {
400
+	char	*srshash;
401
+	char	 srsstamp[SRS_TIME_SIZE + 1];
402
+	int		 len;
403
+	int		 ret;
404
+
405
+	/* This never happens if we get called from guarded() */
406
+	if ((strncasecmp(senduser, SRS0TAG, 4) == 0) &&
407
+		(strchr(srs_separators, senduser[4]) != NULL)) {
408
+		sendhost = senduser + 5;
409
+		if (*sendhost == '\0')
410
+			return SRS_ENOSRS0HOST;
411
+		senduser = strchr(sendhost, SRSSEP);
412
+		if ((senduser == NULL) || (*senduser == '\0'))
413
+			return SRS_ENOSRS0USER;
414
+	}
415
+
416
+	len = strlen(SRS0TAG) + 1 +
417
+		srs->hashlength + 1 +
418
+			SRS_TIME_SIZE + 1 +
419
+				strlen(sendhost) + 1 + strlen(senduser)
420
+			+ 1 + strlen(aliashost);
421
+	if (len >= buflen)
422
+		return SRS_EBUFTOOSMALL;
423
+
424
+	ret = srs_timestamp_create(srs, srsstamp, time(NULL));
425
+	if (ret != SRS_SUCCESS)
426
+		return ret;
427
+	srshash = alloca(srs->hashlength + 1);
428
+	ret = srs_hash_create(srs, srshash,3, srsstamp, sendhost, senduser);
429
+	if (ret != SRS_SUCCESS)
430
+		return ret;
431
+
432
+	sprintf(buf, SRS0TAG "%c%s%c%s%c%s%c%s@%s", srs->separator,
433
+					srshash, SRSSEP, srsstamp, SRSSEP,
434
+						sendhost, SRSSEP, senduser,
435
+							aliashost);
436
+
437
+	return SRS_SUCCESS;
438
+}
439
+
440
+int
441
+srs_compile_guarded(srs_t *srs,
442
+				char *buf, int buflen,
443
+				char *sendhost, char *senduser,
444
+				const char *aliashost) {
445
+	char	*srshost;
446
+	char	*srsuser;
447
+	char	*srshash;
448
+	int		 len;
449
+	int		 ret;
450
+
451
+	if ((strncasecmp(senduser, SRS1TAG, 4) == 0) &&
452
+		(strchr(srs_separators, senduser[4]) != NULL)) {
453
+		/* Used as a temporary convenience var */
454
+		srshash = senduser + 5;
455
+		if (*srshash == '\0')
456
+			return SRS_ENOSRS1HASH;
457
+		/* Used as a temporary convenience var */
458
+		srshost = strchr(srshash, SRSSEP);
459
+		if (!STRINGP(srshost))
460
+			return SRS_ENOSRS1HOST;
461
+		*srshost++ = '\0';
462
+		srsuser = strchr(srshost, SRSSEP);
463
+		if (!STRINGP(srsuser))
464
+			return SRS_ENOSRS1USER;
465
+		*srsuser++ = '\0';
466
+		srshash = alloca(srs->hashlength + 1);
467
+		ret = srs_hash_create(srs, srshash, 2, srshost, srsuser);
468
+		if (ret != SRS_SUCCESS)
469
+			return ret;
470
+		len = strlen(SRS1TAG) + 1 +
471
+			srs->hashlength + 1 +
472
+				strlen(srshost) + 1 + strlen(srsuser)
473
+			+ 1 + strlen(aliashost);
474
+		if (len >= buflen)
475
+			return SRS_EBUFTOOSMALL;
476
+		sprintf(buf, SRS1TAG "%c%s%c%s%c%s@%s", srs->separator,
477
+						srshash, SRSSEP,
478
+							srshost, SRSSEP, srsuser,
479
+								aliashost);
480
+		return SRS_SUCCESS;
481
+	}
482
+	else if ((strncasecmp(senduser, SRS0TAG, 4) == 0) &&
483
+		(strchr(srs_separators, senduser[4]) != NULL)) {
484
+		srsuser = senduser + 4;
485
+		srshost = sendhost;
486
+		srshash = alloca(srs->hashlength + 1);
487
+		ret = srs_hash_create(srs, srshash, 2, srshost, srsuser);
488
+		if (ret != SRS_SUCCESS)
489
+			return ret;
490
+		len = strlen(SRS1TAG) + 1 +
491
+			srs->hashlength + 1 +
492
+				strlen(srshost) + 1 + strlen(srsuser)
493
+			+ 1 + strlen(aliashost);
494
+		if (len >= buflen)
495
+			return SRS_EBUFTOOSMALL;
496
+		sprintf(buf, SRS1TAG "%c%s%c%s%c%s@%s", srs->separator,
497
+						srshash, SRSSEP,
498
+							srshost, SRSSEP, srsuser,
499
+								aliashost);
500
+	}
501
+	else {
502
+		return srs_compile_shortcut(srs, buf, buflen,
503
+						sendhost, senduser, aliashost);
504
+	}
505
+
506
+	return SRS_SUCCESS;
507
+}
508
+
509
+int
510
+srs_parse_shortcut(srs_t *srs, char *buf, int buflen, char *senduser)
511
+{
512
+	char	*srshash;
513
+	char	*srsstamp;
514
+	char	*srshost;
515
+	char	*srsuser;
516
+	int		 ret;
517
+
518
+	if (strncasecmp(senduser, SRS0TAG, 4) == 0) {
519
+		srshash = senduser + 5;
520
+		if (!STRINGP(srshash))
521
+			return SRS_ENOSRS0HASH;
522
+		srsstamp = strchr(srshash, SRSSEP);
523
+		if (!STRINGP(srsstamp))
524
+			return SRS_ENOSRS0STAMP;
525
+		*srsstamp++ = '\0';
526
+		srshost = strchr(srsstamp, SRSSEP);
527
+		if (!STRINGP(srshost))
528
+			return SRS_ENOSRS0HOST;
529
+		*srshost++ = '\0';
530
+		srsuser = strchr(srshost, SRSSEP);
531
+		if (!STRINGP(srsuser))
532
+			return SRS_ENOSRS0USER;
533
+		*srsuser++ = '\0';
534
+		ret = srs_timestamp_check(srs, srsstamp);
535
+		if (ret != SRS_SUCCESS)
536
+			return ret;
537
+		ret = srs_hash_check(srs, srshash, 3, srsstamp,
538
+						srshost, srsuser);
539
+		if (ret != SRS_SUCCESS)
540
+			return ret;
541
+		sprintf(buf, "%s@%s", srsuser, srshost);
542
+		return SRS_SUCCESS;
543
+	}
544
+
545
+	return SRS_ENOTSRSADDRESS;
546
+}
547
+
548
+int
549
+srs_parse_guarded(srs_t *srs, char *buf, int buflen, char *senduser)
550
+{
551
+	char	*srshash;
552
+	char	*srshost;
553
+	char	*srsuser;
554
+	int		 ret;
555
+
556
+	if (strncasecmp(senduser, SRS1TAG, 4) == 0) {
557
+		srshash = senduser + 5;
558
+		if (!STRINGP(srshash))
559
+			return SRS_ENOSRS1HASH;
560
+		srshost = strchr(srshash, SRSSEP);
561
+		if (!STRINGP(srshost))
562
+			return SRS_ENOSRS1HOST;
563
+		*srshost++ = '\0';
564
+		srsuser = strchr(srshost, SRSSEP);
565
+		if (!STRINGP(srsuser))
566
+			return SRS_ENOSRS1USER;
567
+		*srsuser++ = '\0';
568
+		ret = srs_hash_check(srs, srshash, 2, srshost, srsuser);
569
+		if (ret != SRS_SUCCESS)
570
+			return ret;
571
+		sprintf(buf, SRS0TAG "%s@%s", srsuser, srshost);
572
+		return SRS_SUCCESS;
573
+	}
574
+	else {
575
+		return srs_parse_shortcut(srs, buf, buflen, senduser);
576
+	}
577
+}
578
+
579
+int
580
+srs_forward(srs_t *srs, char *buf, int buflen,
581
+				const char *sender, const char *alias)
582
+{
583
+	char	*senduser;
584
+	char	*sendhost;
585
+	char	*tmp;
586
+	int		 len;
587
+
588
+	if (srs->noforward)
589
+		return SRS_ENOTREWRITTEN;
590
+
591
+	/* This is allowed to be a plain domain */
592
+	while ((tmp = strchr(alias, '@')) != NULL)
593
+		alias = tmp + 1;
594
+
595
+	tmp = strchr(sender, '@');
596
+	if (tmp == NULL)
597
+		return SRS_ENOSENDERATSIGN;
598
+	sendhost = tmp + 1;
599
+
600
+	len = strlen(sender);
601
+
602
+	if (! srs->alwaysrewrite) {
603
+		if (strcasecmp(sendhost, alias) == 0) {
604
+			if (strlen(sender) >= buflen)
605
+				return SRS_EBUFTOOSMALL;
606
+			strcpy(buf, sender);
607
+			return SRS_SUCCESS;
608
+		}
609
+	}
610
+
611
+	/* Reconstruct the whole show into our alloca() buffer. */
612
+	senduser = alloca(len + 1);
613
+	strcpy(senduser, sender);
614
+	tmp = (senduser + (tmp - sender));
615
+	sendhost = tmp + 1;
616
+	*tmp = '\0';
617
+
618
+	return srs_compile_guarded(srs, buf, buflen,
619
+					sendhost, senduser, alias);
620
+}
621
+
622
+int		
623
+srs_forward_alloc(srs_t *srs, char **sptr,
624
+				const char *sender, const char *alias)
625
+{
626
+	char	*buf;
627
+	int		 slen;
628
+	int		 alen;
629
+	int		 len;
630
+	int		 ret;
631
+
632
+	if (srs->noforward)
633
+		return SRS_ENOTREWRITTEN;
634
+
635
+	slen = strlen(sender);
636
+	alen = strlen(alias);
637
+
638
+	/* strlen(SRSxTAG) + strlen("====+@") < 64 */
639
+	len = slen + alen + srs->hashlength + SRS_TIME_SIZE + 64;
640
+	buf = (char *)srs_f_malloc(len);
641
+
642
+	ret = srs_forward(srs, buf, len, sender, alias);
643
+
644
+	if (ret == SRS_SUCCESS)
645
+		*sptr = buf;
646
+	else
647
+		srs_f_free(buf);
648
+
649
+	return ret;
650
+}
651
+
652
+int
653
+srs_reverse(srs_t *srs, char *buf, int buflen, const char *sender)
654
+{
655
+	char	*senduser;
656
+	char	*tmp;
657
+	int		 len;
658
+
659
+	if (!SRS_IS_SRS_ADDRESS(sender))
660
+		return SRS_ENOTSRSADDRESS;
661
+
662
+	if (srs->noreverse)
663
+		return SRS_ENOTREWRITTEN;
664
+
665
+	len = strlen(sender);
666
+	if (len >= buflen)
667
+		return SRS_EBUFTOOSMALL;
668
+	senduser = alloca(len + 1);
669
+	strcpy(senduser, sender);
670
+
671
+	/* We don't really care about the host for reversal. */
672
+	tmp = strchr(senduser, '@');
673
+	if (tmp != NULL)
674
+		*tmp = '\0';
675
+	return srs_parse_guarded(srs, buf, buflen, senduser);
676
+}
677
+
678
+int
679
+srs_reverse_alloc(srs_t *srs, char **sptr, const char *sender)
680
+{
681
+	char	*buf;
682
+	int		 len;
683
+	int		 ret;
684
+
685
+	*sptr = NULL;
686
+
687
+	if (!SRS_IS_SRS_ADDRESS(sender))
688
+		return SRS_ENOTSRSADDRESS;
689
+
690
+	if (srs->noreverse)
691
+		return SRS_ENOTREWRITTEN;
692
+
693
+	len = strlen(sender) + 1;
694
+	buf = (char *)srs_f_malloc(len);
695
+
696
+	ret = srs_reverse(srs, buf, len, sender);
697
+
698
+	if (ret == SRS_SUCCESS)
699
+		*sptr = buf;
700
+	else
701
+		srs_f_free(buf);
702
+
703
+	return ret;
704
+}

+ 178
- 0
srs2.h View File

@@ -0,0 +1,178 @@
1
+/* This file is copied from the libsrs2 sources */
2
+/* Modified by Timo Röhling <timo.roehling@gmx.de> */
3
+
4
+/* Copyright (c) 2004 Shevek (srs@anarres.org)
5
+ * All rights reserved.
6
+ *
7
+ * This file is a part of libsrs2 from http://www.libsrs2.org/
8
+ *
9
+ * Redistribution and use in source and binary forms, with or without
10
+ * modification, under the terms of either the GNU General Public
11
+ * License version 2 or the BSD license, at the discretion of the
12
+ * user. Copies of these licenses have been included in the libsrs2
13
+ * distribution. See the the file called LICENSE for more
14
+ * information.
15
+ */
16
+
17
+#ifndef __SRS2_H__
18
+#define __SRS2_H__
19
+
20
+#include <stdio.h>
21
+#include <stdlib.h>
22
+#include <ctype.h>
23
+
24
+#ifndef __BEGIN_DECLS
25
+#define __BEGIN_DECLS
26
+#define __END_DECLS
27
+#endif
28
+
29
+__BEGIN_DECLS
30
+
31
+#define SRS_VERSION_MAJOR			1
32
+#define SRS_VERSION_MINOR			0
33
+#define SRS_VERSION_PATCHLEVEL		14
34
+#define SRS_VERSION_FROM(m, n, p)	(((m) << 16) + ((n) << 8) + (p))
35
+#define SRS_VERSION		SRS_VERSION_FROM(SRS_VERSION_MAJOR, \
36
+										SRS_VERSION_MINOR, \
37
+										SRS_VERSION_PATCHLEVEL)
38
+
39
+/* This is ugly, but reasonably safe. */
40
+#undef TRUE
41
+#define TRUE 1
42
+#undef FALSE
43
+#define FALSE 0
44
+
45
+#define SRSSEP	'='
46
+#define SRS0TAG	"SRS0"
47
+#define SRS1TAG	"SRS1"
48
+
49
+/* Error codes */
50
+
51
+#define SRS_ERRTYPE_MASK		0xF000
52
+#define SRS_ERRTYPE_NONE		0x0000
53
+#define SRS_ERRTYPE_CONFIG		0x1000
54
+#define SRS_ERRTYPE_INPUT		0x2000
55
+#define SRS_ERRTYPE_SYNTAX		0x4000
56
+#define SRS_ERRTYPE_SRS			0x8000
57
+
58
+#define SRS_SUCCESS				(0)
59
+#define SRS_ENOTSRSADDRESS		(1)
60
+#define SRS_ENOTREWRITTEN		(2)
61
+
62
+#define SRS_ENOSECRETS			(SRS_ERRTYPE_CONFIG | 1)
63
+#define SRS_ESEPARATORINVALID	(SRS_ERRTYPE_CONFIG | 2)
64
+
65
+#define SRS_ENOSENDERATSIGN		(SRS_ERRTYPE_INPUT | 1)
66
+#define SRS_EBUFTOOSMALL		(SRS_ERRTYPE_INPUT | 2)
67
+
68
+#define SRS_ENOSRS0HOST			(SRS_ERRTYPE_SYNTAX | 1)
69
+#define SRS_ENOSRS0USER			(SRS_ERRTYPE_SYNTAX | 2)
70
+#define SRS_ENOSRS0HASH			(SRS_ERRTYPE_SYNTAX | 3)
71
+#define SRS_ENOSRS0STAMP		(SRS_ERRTYPE_SYNTAX | 4)
72
+#define SRS_ENOSRS1HOST			(SRS_ERRTYPE_SYNTAX | 5)
73
+#define SRS_ENOSRS1USER			(SRS_ERRTYPE_SYNTAX | 6)
74
+#define SRS_ENOSRS1HASH			(SRS_ERRTYPE_SYNTAX | 7)
75
+#define	SRS_EBADTIMESTAMPCHAR	(SRS_ERRTYPE_SYNTAX | 8)
76
+#define SRS_EHASHTOOSHORT		(SRS_ERRTYPE_SYNTAX | 9)
77
+
78
+#define SRS_ETIMESTAMPOUTOFDATE	(SRS_ERRTYPE_SRS | 1)
79
+#define SRS_EHASHINVALID		(SRS_ERRTYPE_SRS | 2)
80
+
81
+#define SRS_ERROR_TYPE(x) ((x) & SRS_ERRTYPE_MASK)
82
+
83
+/* SRS implementation */
84
+
85
+#define SRS_IS_SRS_ADDRESS(x) ( \
86
+				(strncasecmp((x), "SRS", 3) == 0) && \
87
+				(strchr("01", (x)[3]) != NULL) && \
88
+				(strchr("-+=", (x)[4]) != NULL) \
89
+			)
90
+
91
+typedef void *(*srs_malloc_t)(size_t);
92
+typedef void *(*srs_realloc_t)(void *, size_t);
93
+typedef void (*srs_free_t)(void *);
94
+
95
+typedef int srs_bool;
96
+
97
+typedef
98
+struct _srs_t {
99
+	/* Rewriting parameters */
100
+	char	**secrets;
101
+	int		  numsecrets;
102
+	char	  separator;
103
+
104
+	/* Security parameters */
105
+	int		  maxage;			/* Maximum allowed age in seconds */
106
+	int		  hashlength;
107
+	int		  hashmin;
108
+
109
+	/* Behaviour parameters */
110
+	srs_bool  alwaysrewrite;	/* Rewrite even into same domain? */
111
+	srs_bool  noforward;		/* Never perform forwards rewriting */
112
+	srs_bool  noreverse;		/* Never perform reverse rewriting */
113
+	char	**neverrewrite;		/* A list of non-rewritten domains */
114
+} srs_t;
115
+
116
+/* Interface */
117
+int		 srs_set_malloc(srs_malloc_t m, srs_realloc_t r, srs_free_t f);
118
+srs_t	*srs_new();
119
+void	 srs_init(srs_t *srs);
120
+void	 srs_free(srs_t *srs);
121
+int		 srs_forward(srs_t *srs, char *buf, int buflen,
122
+				const char *sender, const char *alias);
123
+int		 srs_forward_alloc(srs_t *srs, char **sptr,
124
+				const char *sender, const char *alias);
125
+int		 srs_reverse(srs_t *srs, char *buf, int buflen,
126
+				const char *sender);
127
+int		 srs_reverse_alloc(srs_t *srs, char **sptr, const char *sender);
128
+const char *
129
+		 srs_strerror(int code);
130
+int		 srs_add_secret(srs_t *srs, const char *secret);
131
+const char *
132
+		 srs_get_secret(srs_t *srs, int idx);
133
+	/* You probably shouldn't call these. */
134
+int		 srs_timestamp_create(srs_t *srs, char *buf, time_t now);
135
+int		 srs_timestamp_check(srs_t *srs, const char *stamp);
136
+
137
+#define SRS_PARAM_DECLARE(n, t) \
138
+	int srs_set_ ## n (srs_t *srs, t value); \
139
+	t srs_get_ ## n (srs_t *srs);
140
+
141
+SRS_PARAM_DECLARE(alwaysrewrite, srs_bool)
142
+SRS_PARAM_DECLARE(separator, char)
143
+SRS_PARAM_DECLARE(maxage, int)
144
+SRS_PARAM_DECLARE(hashlength, int)
145
+SRS_PARAM_DECLARE(hashmin, int)
146
+SRS_PARAM_DECLARE(noforward, srs_bool)
147
+SRS_PARAM_DECLARE(noreverse, srs_bool)
148
+
149
+/* SHA1 implementation */
150
+
151
+typedef unsigned long	ULONG;	 /* 32-or-more-bit quantity */
152
+typedef unsigned char	sha_byte;
153
+
154
+#define SHA_BLOCKSIZE				64
155
+#define SHA_DIGESTSIZE				20
156
+
157
+typedef struct {
158
+	ULONG digest[5];				/* message digest */
159
+	ULONG count_lo, count_hi;		/* 64-bit bit count */
160
+	sha_byte data[SHA_BLOCKSIZE];		/* SHA data buffer */
161
+	int local;						/* unprocessed amount in data */
162
+} SHA_INFO;
163
+
164
+typedef
165
+struct _srs_hmac_ctx_t {
166
+	SHA_INFO	sctx;
167
+	char		ipad[SHA_BLOCKSIZE + 1];
168
+	char		opad[SHA_BLOCKSIZE + 1];
169
+} srs_hmac_ctx_t;
170
+
171
+void	 srs_hmac_init(srs_hmac_ctx_t *ctx, char *secret, int len);
172
+void	 srs_hmac_update(srs_hmac_ctx_t *ctx, char *data, int len);
173
+void	 srs_hmac_fini(srs_hmac_ctx_t *ctx, char *out);
174
+
175
+
176
+__END_DECLS
177
+
178
+#endif

Loading…
Cancel
Save