Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/util/substitute.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
   Samba utility functions
4
   
5
   Copyright (C) Andrew Tridgell 1992-2001
6
   Copyright (C) Simo Sorce      2001-2002
7
   Copyright (C) Martin Pool     2003
8
   Copyright (C) James Peach   2005
9
   
10
   This program is free software; you can redistribute it and/or modify
11
   it under the terms of the GNU General Public License as published by
12
   the Free Software Foundation; either version 3 of the License, or
13
   (at your option) any later version.
14
   
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License for more details.
19
   
20
   You should have received a copy of the GNU General Public License
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
*/
23
24
#include "replace.h"
25
#include "debug.h"
26
#ifndef SAMBA_UTIL_CORE_ONLY
27
#include "charset/charset.h"
28
#else
29
#include "charset_compat.h"
30
#endif
31
#include "substitute.h"
32
33
/**
34
 * @file
35
 * @brief Substitute utilities.
36
 **/
37
38
/**
39
 Substitute a string for a pattern in another string. Make sure there is
40
 enough room!
41
42
 This routine looks for pattern in s and replaces it with
43
 insert. It may do multiple replacements or just one.
44
45
 Any of " ; ' $ or ` in the insert string are replaced with _
46
 if len==0 then the string cannot be extended. This is different from the old
47
 use of len==0 which was for no length checks to be done.
48
**/
49
50
static void string_sub2(char *s,const char *pattern, const char *insert, size_t len,
51
      bool remove_unsafe_characters, bool replace_once,
52
      bool allow_trailing_dollar)
53
2.10k
{
54
2.10k
  char *p;
55
2.10k
  size_t ls, lp, li, i;
56
57
2.10k
  if (!insert || !pattern || !*pattern || !s)
58
0
    return;
59
60
2.10k
  ls = strlen(s);
61
2.10k
  lp = strlen(pattern);
62
2.10k
  li = strlen(insert);
63
64
2.10k
  if (len == 0)
65
2.10k
    len = ls + 1; /* len is number of *bytes* */
66
67
23.4k
  while (lp <= ls && (p = strstr_m(s,pattern))) {
68
21.3k
    if (ls + li - lp >= len) {
69
0
      DBG_ERR("ERROR: string overflow by "
70
0
        "%zu in string_sub(%.50s, %zu)\n",
71
0
        ls + li - lp + 1 - len,
72
0
        pattern,
73
0
        len);
74
0
      break;
75
0
    }
76
21.3k
    if (li != lp) {
77
5.72k
      memmove(p+li,p+lp,strlen(p+lp)+1);
78
5.72k
    }
79
39.9k
    for (i=0;i<li;i++) {
80
18.5k
      switch (insert[i]) {
81
0
      case '$':
82
        /* allow a trailing $
83
         * (as in machine accounts) */
84
0
        if (allow_trailing_dollar && (i == li - 1 )) {
85
0
          p[i] = insert[i];
86
0
          break;
87
0
        }
88
0
        FALL_THROUGH;
89
0
      case '`':
90
0
      case '"':
91
0
      case '\'':
92
0
      case ';':
93
0
      case '%':
94
0
      case '\r':
95
0
      case '\n':
96
0
        if ( remove_unsafe_characters ) {
97
0
          p[i] = '_';
98
          /* yes this break should be here
99
           * since we want to fall throw if
100
           * not replacing unsafe chars */
101
0
          break;
102
0
        }
103
0
        FALL_THROUGH;
104
18.5k
      default:
105
18.5k
        p[i] = insert[i];
106
18.5k
      }
107
18.5k
    }
108
21.3k
    s = p + li;
109
21.3k
    ls = ls + li - lp;
110
111
21.3k
    if (replace_once)
112
0
      break;
113
21.3k
  }
114
2.10k
}
115
116
void string_sub(char *s,const char *pattern, const char *insert, size_t len)
117
2.10k
{
118
2.10k
  string_sub2( s, pattern, insert, len, true, false, false );
119
2.10k
}
120
121
/**
122
 Similar to string_sub() but allows for any character to be substituted. 
123
 Use with caution!
124
 if len==0 then the string cannot be extended. This is different from the old
125
 use of len==0 which was for no length checks to be done.
126
**/
127
128
_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
129
1.69k
{
130
1.69k
  char *p;
131
1.69k
  size_t ls,lp,li;
132
133
1.69k
  if (!insert || !pattern || !s)
134
0
    return;
135
136
1.69k
  ls = strlen(s);
137
1.69k
  lp = strlen(pattern);
138
1.69k
  li = strlen(insert);
139
140
1.69k
  if (!*pattern)
141
0
    return;
142
143
1.69k
  if (len == 0)
144
1.69k
    len = ls + 1; /* len is number of *bytes* */
145
146
20.4k
  while (lp <= ls && (p = strstr_m(s,pattern))) {
147
18.7k
    if (ls + li - lp >= len) {
148
0
      DBG_ERR("ERROR: string overflow by "
149
0
        "%zu in all_string_sub(%.50s, %zu)\n",
150
0
        ls + li - lp + 1 - len,
151
0
        pattern,
152
0
        len);
153
0
      break;
154
0
    }
155
18.7k
    if (li != lp) {
156
18.1k
      memmove(p+li,p+lp,strlen(p+lp)+1);
157
18.1k
    }
158
18.7k
    memcpy(p, insert, li);
159
18.7k
    s = p + li;
160
18.7k
    ls = ls + li - lp;
161
18.7k
  }
162
1.69k
}
163
164
/*
165
 * Internal guts of talloc_string_sub and talloc_all_string_sub.
166
 * talloc version of string_sub2.
167
 */
168
169
char *talloc_string_sub2(TALLOC_CTX *mem_ctx, const char *src,
170
      const char *pattern,
171
      const char *insert,
172
      bool remove_unsafe_characters,
173
      bool replace_once,
174
      bool allow_trailing_dollar)
175
0
{
176
0
  char *p, *in;
177
0
  char *s;
178
0
  char *string;
179
0
  ssize_t ls,lp,li,ld, i;
180
181
0
  if (!insert || !pattern || !*pattern || !src) {
182
0
    return NULL;
183
0
  }
184
185
0
  string = talloc_strdup(mem_ctx, src);
186
0
  if (string == NULL) {
187
0
    DEBUG(0, ("talloc_string_sub2: "
188
0
      "talloc_strdup failed\n"));
189
0
    return NULL;
190
0
  }
191
192
0
  s = string;
193
194
0
  in = talloc_strdup(mem_ctx, insert);
195
0
  if (!in) {
196
0
    DEBUG(0, ("talloc_string_sub2: ENOMEM\n"));
197
0
    talloc_free(string);
198
0
    return NULL;
199
0
  }
200
0
  ls = (ssize_t)strlen(s);
201
0
  lp = (ssize_t)strlen(pattern);
202
0
  li = (ssize_t)strlen(insert);
203
0
  ld = li - lp;
204
205
0
  for (i=0;i<li;i++) {
206
0
    switch (in[i]) {
207
0
      case '$':
208
        /* allow a trailing $
209
         * (as in machine accounts) */
210
0
        if (allow_trailing_dollar && (i == li - 1 )) {
211
0
          break;
212
0
        }
213
214
0
        FALL_THROUGH;
215
0
      case '`':
216
0
      case '"':
217
0
      case '\'':
218
0
      case ';':
219
0
      case '%':
220
0
      case '\r':
221
0
      case '\n':
222
0
        if (remove_unsafe_characters) {
223
0
          in[i] = '_';
224
0
          break;
225
0
        }
226
227
0
        FALL_THROUGH;
228
0
      default:
229
        /* ok */
230
0
        break;
231
0
    }
232
0
  }
233
234
0
  while ((p = strstr_m(s,pattern))) {
235
0
    if (ld > 0) {
236
0
      int offset = PTR_DIFF(s,string);
237
0
      string = (char *)talloc_realloc_size(mem_ctx, string,
238
0
              ls + ld + 1);
239
0
      if (!string) {
240
0
        DEBUG(0, ("talloc_string_sub: out of "
241
0
            "memory!\n"));
242
0
        TALLOC_FREE(in);
243
0
        return NULL;
244
0
      }
245
0
      p = string + offset + (p - s);
246
0
    }
247
0
    if (li != lp) {
248
0
      memmove(p+li,p+lp,strlen(p+lp)+1);
249
0
    }
250
0
    memcpy(p, in, li);
251
0
    s = p + li;
252
0
    ls += ld;
253
254
0
    if (replace_once) {
255
0
      break;
256
0
    }
257
0
  }
258
0
  TALLOC_FREE(in);
259
0
  return string;
260
0
}
261
262
/* Same as string_sub, but returns a talloc'ed string */
263
264
char *talloc_string_sub(TALLOC_CTX *mem_ctx,
265
      const char *src,
266
      const char *pattern,
267
      const char *insert)
268
0
{
269
0
  return talloc_string_sub2(mem_ctx, src, pattern, insert,
270
0
      true, false, false);
271
0
}
272
273
char *talloc_all_string_sub(TALLOC_CTX *ctx,
274
        const char *src,
275
        const char *pattern,
276
        const char *insert)
277
0
{
278
0
  return talloc_string_sub2(ctx, src, pattern, insert,
279
0
      false, false, false);
280
0
}