-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstring_safe.c
249 lines (199 loc) · 5.52 KB
/
string_safe.c
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
/*
IIS LDAP Authentication Module
Copyright 2006 Inflection Technology, LLC
For more information, visit http://www.inflectiontech.com.
Released under LGPL terms.
Some portions Copyright Salvador Salanova Fortmann.
Some portions Copyright Microsoft Corporation.
File Name: string_safe.c
Abstract:
Visual Studio 2003 (or earlier) does not include new string
manipulation functions with maximum buffer sizes. This is
essential to avoiding buffer overflow issues.
VS 2005 includes strlcpy() and strlcat(). The function
strlreplace() is not included. To build with VS 2005,
simply uncomment the #define VS2005 in ldapauth.h.
--*/
#include <stdlib.h>
#include <string.h>
#include "string_safe.h"
#ifndef VS2005
size_t
strlcpy(
char *dst,
const char *src,
size_t size
)
{
size_t cpy_size = 0;
if ( size == 0 ) goto exception;
cpy_size = strlen( src );
if ( !(cpy_size < size) )
{
/*
Add +1 for terminating byte. Assuming size_t is
unsigned so -1 is safe.
*/
cpy_size = size - 1;
}
strncpy( dst, src, cpy_size );
/*
Terminate string. Size cpy_size is likely the same
length as the string, strncat() will not automatically
append a terminating byte if cpy_size = strlen().
Note cpy_size is actual characters copied and the buffer
is zero-index counted.
*/
dst[cpy_size] = 0;
exception:
return ( cpy_size );
}
size_t
strlcat(
char *dst,
const char *src,
size_t size
)
{
size_t src_size = 0;
size_t dst_size = 0;
size_t copy_size = 0;
src_size = strlen( src );
dst_size = strlen( dst );
if ( (src_size + dst_size) < size )
{
strncat( dst, src, src_size ); /* strncat() will terminate string */
copy_size = src_size;
}
/*
Total string size is too big. Only copy what will fit.
It *is* possible that dst_size >= size, so check first.
*/
else if ( dst_size < size )
{
copy_size = size - dst_size - 1; /* -1 for terminating byte */
if ( copy_size > 0 )
{
strncat( dst, src, copy_size );
}
}
return ( dst_size + copy_size );
}
#endif /* #ifndef VS2005 */
size_t
strlreplace(
char *dst,
char *search,
char *replace,
size_t size)
/*++
Routine Description:
Replaces all instances of a string inside a string with another
string.
This routine has several complicated issues. First, we cannot modify
the parameter dst unless we will succeed. Second, strcpy() cannot be
used to move parts of the same string around.
Arguments:
dst - destination string
search - search string
replace - replacement string
size - the maximum size of the dst string
Return Value:
The length of the dst string with replacements.
--*/
{
unsigned int dst_len = 0; /* length of the original dst parameter */
unsigned int cur_len = 0; /* current length of the dst with replacements */
unsigned int search_len = 0; /* length of the search string */
unsigned int replace_len = 0; /* length of the replacement string */
unsigned int cpy_len = 0; /* amount to copy */
unsigned int replace_count = 0; /* number of occurrances of search found */
char *dst_copy = NULL; /* memory buffer for a copy of dst */
char *dst_ptr = NULL; /* pointer to the current lcoation in dst */
char *dst_copy_ptr = NULL; /* pointer to the current location in dst_copy */
char *start_ptr = NULL; /* pointer to the start of the next occurrance of search */
if ( dst == NULL || search == NULL || replace == NULL || size == 0 )
{
/* Check for invalid parameters. */
goto exception;
}
dst_len = strlen( dst );
replace_len = strlen( replace );
search_len = strlen( search );
if ( replace_len >= size )
{
/* If replace_len is >= size, the operation can never work. */
goto exception;
}
cur_len = dst_len;
/* Make a working copy of the string. (+1 for terminator byte) */
dst_copy = malloc( dst_len + 1 );
if ( dst_copy == NULL )
{
goto exception;
}
/* strcpy() will not terminate string as dst_len is the string length */
strncpy( dst_copy, dst, dst_len );
dst_copy[dst_len] = 0;
/*
Step 1: Find out how many occurances are there.
*/
start_ptr = dst_copy;
while( (start_ptr = strstr(start_ptr, search)) != NULL )
{
replace_count++;
start_ptr += search_len;
}
/* Step 2: Check length of the new string with replacements. */
if ( (dst_len - (replace_count * search_len) + (replace_count * replace_len)) >= size )
{
/* too big? don't even bother... */
goto exception;
}
/* Start the replace operation */
dst_ptr = dst;
dst_copy_ptr = dst_copy;
start_ptr = strstr( dst_copy, search );
while( (cur_len + 1) < size && start_ptr != NULL )
{
/* Replace Step 1: Copy left size (from last occurrance to this one) */
cpy_len = start_ptr - dst_copy_ptr;
strncpy( dst_ptr, dst_copy_ptr, cpy_len );
/*
Move the indexes:
dst_copy --> point after search
*/
dst_ptr += cpy_len;
dst_copy_ptr += (cpy_len + search_len);
/*
Replace Step 2: Insert replace string.
*/
strncpy( dst_ptr, replace, replace_len );
/*
Move the indexes:
dst_ptr --> point after replace
*/
dst_ptr += replace_len;
cur_len = dst_ptr - dst;
/* Check for another pattern match */
start_ptr = (char *)strstr( dst_copy_ptr, search );
}
/*
Replace Final Step: Copy the rest of the string
after the last occurrance of search.
*/
cpy_len = dst_len - (dst_copy_ptr - dst_copy);
if ( cpy_len > 0 )
{
strncpy( dst_ptr, dst_copy_ptr, cpy_len );
cur_len += cpy_len;
}
/* Terminate */
dst[cur_len] = 0;
exception:
if ( dst_copy != NULL )
{
free( dst_copy );
}
return ( cur_len );
}